Git fork

add-patch: add diff.context command line overrides

This patch compliments the previous commit, where builtins that use
add-patch infrastructure now respect diff.context and
diff.interHunkContext file configurations.

In particular, this patch helps users who don't want to set persistent
context configurations or just want a way to override them on a one-time
basis, by allowing the relevant builtins to accept corresponding command
line options that override the file configurations.

This mimics commands such as diff and log, which allow for both context
file configuration and command line overrides.

Signed-off-by: Leon Michalak <leonmichalak6@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

Leon Michalak and committed by
Junio C Hamano
2b3ae040 2b0a2db2

+241 -35
+10
Documentation/diff-context-options.adoc
··· 1 + `-U<n>`:: 2 + `--unified=<n>`:: 3 + Generate diffs with _<n>_ lines of context. Defaults to `diff.context` 4 + or 3 if the config option is unset. 5 + 6 + `--inter-hunk-context=<n>`:: 7 + Show the context between diff hunks, up to the specified _<number>_ 8 + of lines, thereby fusing hunks that are close to each other. 9 + Defaults to `diff.interHunkContext` or 0 if the config option 10 + is unset.
+2
Documentation/git-add.adoc
··· 104 104 initial command menu and directly jumps to the `patch` subcommand. 105 105 See ``Interactive mode'' for details. 106 106 107 + include::diff-context-options.adoc[] 108 + 107 109 `-e`:: 108 110 `--edit`:: 109 111 Open the diff vs. the index in an editor and let the user
+2
Documentation/git-checkout.adoc
··· 289 289 Note that this option uses the no overlay mode by default (see also 290 290 `--overlay`), and currently doesn't support overlay mode. 291 291 292 + include::diff-context-options.adoc[] 293 + 292 294 `--ignore-other-worktrees`:: 293 295 `git checkout` refuses when the wanted branch is already checked 294 296 out or otherwise in use by another worktree. This option makes
+2
Documentation/git-commit.adoc
··· 76 76 which changes to commit. See linkgit:git-add[1] for 77 77 details. 78 78 79 + include::diff-context-options.adoc[] 80 + 79 81 `-C <commit>`:: 80 82 `--reuse-message=<commit>`:: 81 83 Take an existing _<commit>_ object, and reuse the log message
+2
Documentation/git-reset.adoc
··· 125 125 separated with _NUL_ character and all other characters are taken 126 126 literally (including newlines and quotes). 127 127 128 + include::diff-context-options.adoc[] 129 + 128 130 `--`:: 129 131 Do not interpret any more arguments as options. 130 132
+2
Documentation/git-restore.adoc
··· 52 52 Mode" section of linkgit:git-add[1] to learn how to operate 53 53 the `--patch` mode. 54 54 55 + include::diff-context-options.adoc[] 56 + 55 57 `-W`:: 56 58 `--worktree`:: 57 59 `-S`::
+2
Documentation/git-stash.adoc
··· 208 208 The `--patch` option implies `--keep-index`. You can use 209 209 `--no-keep-index` to override this. 210 210 211 + include::diff-context-options.adoc[] 212 + 211 213 -S:: 212 214 --staged:: 213 215 This option is only valid for `push` and `save` commands.
+28 -8
add-interactive.c
··· 36 36 free(key); 37 37 } 38 38 39 - void init_add_i_state(struct add_i_state *s, struct repository *r) 39 + void init_add_i_state(struct add_i_state *s, struct repository *r, 40 + struct add_p_opt *add_p_opt) 40 41 { 41 42 const char *value; 42 43 ··· 90 91 repo_config_get_bool(r, "interactive.singlekey", &s->use_single_key); 91 92 if (s->use_single_key) 92 93 setbuf(stdin, NULL); 94 + 95 + if (add_p_opt->context != -1) { 96 + if (add_p_opt->context < 0) 97 + die(_("%s cannot be negative"), "--unified"); 98 + s->context = add_p_opt->context; 99 + } 100 + if (add_p_opt->interhunkcontext != -1) { 101 + if (add_p_opt->interhunkcontext < 0) 102 + die(_("%s cannot be negative"), "--inter-hunk-context"); 103 + s->interhunkcontext = add_p_opt->interhunkcontext; 104 + } 93 105 } 94 106 95 107 void clear_add_i_state(struct add_i_state *s) ··· 978 990 opts->prompt = N_("Patch update"); 979 991 count = list_and_choose(s, files, opts); 980 992 if (count > 0) { 993 + struct add_p_opt add_p_opt = { 994 + .context = s->context, 995 + .interhunkcontext = s->interhunkcontext, 996 + }; 981 997 struct strvec args = STRVEC_INIT; 982 998 struct pathspec ps_selected = { 0 }; 983 999 ··· 988 1004 parse_pathspec(&ps_selected, 989 1005 PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL, 990 1006 PATHSPEC_LITERAL_PATH, "", args.v); 991 - res = run_add_p(s->r, ADD_P_ADD, NULL, &ps_selected); 1007 + res = run_add_p(s->r, ADD_P_ADD, &add_p_opt, NULL, &ps_selected); 992 1008 strvec_clear(&args); 993 1009 clear_pathspec(&ps_selected); 994 1010 } ··· 1023 1039 if (count > 0) { 1024 1040 struct child_process cmd = CHILD_PROCESS_INIT; 1025 1041 1026 - strvec_pushl(&cmd.args, "git", "diff", "-p", "--cached", 1027 - oid_to_hex(!is_initial ? &oid : 1028 - s->r->hash_algo->empty_tree), 1029 - "--", NULL); 1042 + strvec_pushl(&cmd.args, "git", "diff", "-p", "--cached", NULL); 1043 + if (s->context != -1) 1044 + strvec_pushf(&cmd.args, "--unified=%i", s->context); 1045 + if (s->interhunkcontext != -1) 1046 + strvec_pushf(&cmd.args, "--inter-hunk-context=%i", s->interhunkcontext); 1047 + strvec_pushl(&cmd.args, oid_to_hex(!is_initial ? &oid : 1048 + s->r->hash_algo->empty_tree), "--", NULL); 1030 1049 for (i = 0; i < files->items.nr; i++) 1031 1050 if (files->selected[i]) 1032 1051 strvec_push(&cmd.args, ··· 1119 1138 _("(empty) select nothing")); 1120 1139 } 1121 1140 1122 - int run_add_i(struct repository *r, const struct pathspec *ps) 1141 + int run_add_i(struct repository *r, const struct pathspec *ps, 1142 + struct add_p_opt *add_p_opt) 1123 1143 { 1124 1144 struct add_i_state s = { NULL }; 1125 1145 struct print_command_item_data data = { "[", "]" }; ··· 1162 1182 ->util = util; 1163 1183 } 1164 1184 1165 - init_add_i_state(&s, r); 1185 + init_add_i_state(&s, r, add_p_opt); 1166 1186 1167 1187 /* 1168 1188 * When color was asked for, use the prompt color for
+13 -3
add-interactive.h
··· 3 3 4 4 #include "color.h" 5 5 6 + struct add_p_opt { 7 + int context; 8 + int interhunkcontext; 9 + }; 10 + 11 + #define ADD_P_OPT_INIT { .context = -1, .interhunkcontext = -1 } 12 + 6 13 struct add_i_state { 7 14 struct repository *r; 8 15 int use_color; ··· 21 28 int context, interhunkcontext; 22 29 }; 23 30 24 - void init_add_i_state(struct add_i_state *s, struct repository *r); 31 + void init_add_i_state(struct add_i_state *s, struct repository *r, 32 + struct add_p_opt *add_p_opt); 25 33 void clear_add_i_state(struct add_i_state *s); 26 34 27 35 struct repository; 28 36 struct pathspec; 29 - int run_add_i(struct repository *r, const struct pathspec *ps); 37 + int run_add_i(struct repository *r, const struct pathspec *ps, 38 + struct add_p_opt *add_p_opt); 30 39 31 40 enum add_p_mode { 32 41 ADD_P_ADD, ··· 37 46 }; 38 47 39 48 int run_add_p(struct repository *r, enum add_p_mode mode, 40 - const char *revision, const struct pathspec *ps); 49 + struct add_p_opt *o, const char *revision, 50 + const struct pathspec *ps); 41 51 42 52 #endif
+3 -2
add-patch.c
··· 1763 1763 } 1764 1764 1765 1765 int run_add_p(struct repository *r, enum add_p_mode mode, 1766 - const char *revision, const struct pathspec *ps) 1766 + struct add_p_opt *o, const char *revision, 1767 + const struct pathspec *ps) 1767 1768 { 1768 1769 struct add_p_state s = { 1769 1770 { r }, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT 1770 1771 }; 1771 1772 size_t i, binary_count = 0; 1772 1773 1773 - init_add_i_state(&s.s, r); 1774 + init_add_i_state(&s.s, r, o); 1774 1775 1775 1776 if (mode == ADD_P_STASH) 1776 1777 s.mode = &patch_mode_stash;
+17 -4
builtin/add.c
··· 29 29 NULL 30 30 }; 31 31 static int patch_interactive, add_interactive, edit_interactive; 32 + static struct add_p_opt add_p_opt = ADD_P_OPT_INIT; 32 33 static int take_worktree_changes; 33 34 static int add_renormalize; 34 35 static int pathspec_file_nul; ··· 157 158 int interactive_add(struct repository *repo, 158 159 const char **argv, 159 160 const char *prefix, 160 - int patch) 161 + int patch, struct add_p_opt *add_p_opt) 161 162 { 162 163 struct pathspec pathspec; 163 164 int ret; ··· 169 170 prefix, argv); 170 171 171 172 if (patch) 172 - ret = !!run_add_p(repo, ADD_P_ADD, NULL, &pathspec); 173 + ret = !!run_add_p(repo, ADD_P_ADD, add_p_opt, NULL, &pathspec); 173 174 else 174 - ret = !!run_add_i(repo, &pathspec); 175 + ret = !!run_add_i(repo, &pathspec, add_p_opt); 175 176 176 177 clear_pathspec(&pathspec); 177 178 return ret; ··· 253 254 OPT_GROUP(""), 254 255 OPT_BOOL('i', "interactive", &add_interactive, N_("interactive picking")), 255 256 OPT_BOOL('p', "patch", &patch_interactive, N_("select hunks interactively")), 257 + OPT_DIFF_UNIFIED(&add_p_opt.context), 258 + OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext), 256 259 OPT_BOOL('e', "edit", &edit_interactive, N_("edit current diff and apply")), 257 260 OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files"), 0), 258 261 OPT_BOOL('u', "update", &take_worktree_changes, N_("update tracked files")), ··· 394 397 prepare_repo_settings(repo); 395 398 repo->settings.command_requires_full_index = 0; 396 399 400 + if (add_p_opt.context < -1) 401 + die(_("'%s' cannot be negative"), "--unified"); 402 + if (add_p_opt.interhunkcontext < -1) 403 + die(_("'%s' cannot be negative"), "--inter-hunk-context"); 404 + 397 405 if (patch_interactive) 398 406 add_interactive = 1; 399 407 if (add_interactive) { ··· 401 409 die(_("options '%s' and '%s' cannot be used together"), "--dry-run", "--interactive/--patch"); 402 410 if (pathspec_from_file) 403 411 die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--interactive/--patch"); 404 - exit(interactive_add(repo, argv + 1, prefix, patch_interactive)); 412 + exit(interactive_add(repo, argv + 1, prefix, patch_interactive, &add_p_opt)); 413 + } else { 414 + if (add_p_opt.context != -1) 415 + die(_("the option '%s' requires '%s'"), "--unified", "--interactive/--patch"); 416 + if (add_p_opt.interhunkcontext != -1) 417 + die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--interactive/--patch"); 405 418 } 406 419 407 420 if (edit_interactive) {
+28 -3
builtin/checkout.c
··· 61 61 62 62 struct checkout_opts { 63 63 int patch_mode; 64 + int patch_context; 65 + int patch_interhunk_context; 64 66 int quiet; 65 67 int merge; 66 68 int force; ··· 104 106 struct tree *source_tree; 105 107 }; 106 108 107 - #define CHECKOUT_OPTS_INIT { .conflict_style = -1, .merge = -1 } 109 + #define CHECKOUT_OPTS_INIT { \ 110 + .conflict_style = -1, \ 111 + .merge = -1, \ 112 + .patch_context = -1, \ 113 + .patch_interhunk_context = -1, \ 114 + } 108 115 109 116 struct branch_info { 110 117 char *name; /* The short name used */ ··· 539 546 540 547 if (opts->patch_mode) { 541 548 enum add_p_mode patch_mode; 549 + struct add_p_opt add_p_opt = { 550 + .context = opts->patch_context, 551 + .interhunkcontext = opts->patch_interhunk_context, 552 + }; 542 553 const char *rev = new_branch_info->name; 543 554 char rev_oid[GIT_MAX_HEXSZ + 1]; 544 555 ··· 564 575 else 565 576 BUG("either flag must have been set, worktree=%d, index=%d", 566 577 opts->checkout_worktree, opts->checkout_index); 567 - return !!run_add_p(the_repository, patch_mode, rev, 568 - &opts->pathspec); 578 + return !!run_add_p(the_repository, patch_mode, &add_p_opt, 579 + rev, &opts->pathspec); 569 580 } 570 581 571 582 repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR); ··· 1738 1749 N_("checkout their version for unmerged files"), 1739 1750 3, PARSE_OPT_NONEG), 1740 1751 OPT_BOOL('p', "patch", &opts->patch_mode, N_("select hunks interactively")), 1752 + OPT_DIFF_UNIFIED(&opts->patch_context), 1753 + OPT_DIFF_INTERHUNK_CONTEXT(&opts->patch_interhunk_context), 1741 1754 OPT_BOOL(0, "ignore-skip-worktree-bits", &opts->ignore_skipworktree, 1742 1755 N_("do not limit pathspecs to sparse entries only")), 1743 1756 OPT_PATHSPEC_FROM_FILE(&opts->pathspec_from_file), ··· 1779 1792 1780 1793 argc = parse_options(argc, argv, prefix, options, 1781 1794 usagestr, parseopt_flags); 1795 + 1796 + if (opts->patch_context < -1) 1797 + die(_("'%s' cannot be negative"), "--unified"); 1798 + if (opts->patch_interhunk_context < -1) 1799 + die(_("'%s' cannot be negative"), "--inter-hunk-context"); 1800 + 1801 + if (!opts->patch_mode) { 1802 + if (opts->patch_context != -1) 1803 + die(_("the option '%s' requires '%s'"), "--unified", "--patch"); 1804 + if (opts->patch_interhunk_context != -1) 1805 + die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--patch"); 1806 + } 1782 1807 1783 1808 if (opts->show_progress < 0) { 1784 1809 if (opts->quiet)
+15 -1
builtin/commit.c
··· 19 19 #include "environment.h" 20 20 #include "diff.h" 21 21 #include "commit.h" 22 + #include "add-interactive.h" 22 23 #include "gettext.h" 23 24 #include "revision.h" 24 25 #include "wt-status.h" ··· 122 123 static char *fixup_message, *fixup_commit, *squash_message; 123 124 static const char *fixup_prefix; 124 125 static int all, also, interactive, patch_interactive, only, amend, signoff; 126 + static struct add_p_opt add_p_opt = ADD_P_OPT_INIT; 125 127 static int edit_flag = -1; /* unspecified */ 126 128 static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship; 127 129 static int config_commit_verbose = -1; /* unspecified */ ··· 354 356 const char *ret; 355 357 char *path = NULL; 356 358 359 + if (add_p_opt.context < -1) 360 + die(_("'%s' cannot be negative"), "--unified"); 361 + if (add_p_opt.interhunkcontext < -1) 362 + die(_("'%s' cannot be negative"), "--inter-hunk-context"); 363 + 357 364 if (is_status) 358 365 refresh_flags |= REFRESH_UNMERGED; 359 366 parse_pathspec(&pathspec, 0, ··· 400 407 old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT)); 401 408 setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1); 402 409 403 - if (interactive_add(the_repository, argv, prefix, patch_interactive) != 0) 410 + if (interactive_add(the_repository, argv, prefix, patch_interactive, &add_p_opt) != 0) 404 411 die(_("interactive add failed")); 405 412 406 413 the_repository->index_file = old_repo_index_file; ··· 424 431 commit_style = COMMIT_NORMAL; 425 432 ret = get_lock_file_path(&index_lock); 426 433 goto out; 434 + } else { 435 + if (add_p_opt.context != -1) 436 + die(_("the option '%s' requires '%s'"), "--unified", "--interactive/--patch"); 437 + if (add_p_opt.interhunkcontext != -1) 438 + die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--interactive/--patch"); 427 439 } 428 440 429 441 /* ··· 1722 1734 OPT_BOOL('i', "include", &also, N_("add specified files to index for commit")), 1723 1735 OPT_BOOL(0, "interactive", &interactive, N_("interactively add files")), 1724 1736 OPT_BOOL('p', "patch", &patch_interactive, N_("interactively add changes")), 1737 + OPT_DIFF_UNIFIED(&add_p_opt.context), 1738 + OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext), 1725 1739 OPT_BOOL('o', "only", &only, N_("commit only specified files")), 1726 1740 OPT_BOOL('n', "no-verify", &no_verify, N_("bypass pre-commit and commit-msg hooks")), 1727 1741 OPT_BOOL(0, "dry-run", &dry_run, N_("show what would be committed")),
+15 -2
builtin/reset.c
··· 346 346 struct object_id oid; 347 347 struct pathspec pathspec; 348 348 int intent_to_add = 0; 349 + struct add_p_opt add_p_opt = ADD_P_OPT_INIT; 349 350 const struct option options[] = { 350 351 OPT__QUIET(&quiet, N_("be quiet, only report errors")), 351 352 OPT_BOOL(0, "no-refresh", &no_refresh, ··· 370 371 PARSE_OPT_OPTARG, 371 372 option_parse_recurse_submodules_worktree_updater), 372 373 OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")), 374 + OPT_DIFF_UNIFIED(&add_p_opt.context), 375 + OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext), 373 376 OPT_BOOL('N', "intent-to-add", &intent_to_add, 374 377 N_("record only the fact that removed paths will be added later")), 375 378 OPT_PATHSPEC_FROM_FILE(&pathspec_from_file), ··· 420 423 oidcpy(&oid, &tree->object.oid); 421 424 } 422 425 426 + if (add_p_opt.context < -1) 427 + die(_("'%s' cannot be negative"), "--unified"); 428 + if (add_p_opt.interhunkcontext < -1) 429 + die(_("'%s' cannot be negative"), "--inter-hunk-context"); 430 + 423 431 prepare_repo_settings(the_repository); 424 432 the_repository->settings.command_requires_full_index = 0; 425 433 ··· 427 435 if (reset_type != NONE) 428 436 die(_("options '%s' and '%s' cannot be used together"), "--patch", "--{hard,mixed,soft}"); 429 437 trace2_cmd_mode("patch-interactive"); 430 - update_ref_status = !!run_add_p(the_repository, ADD_P_RESET, rev, 431 - &pathspec); 438 + update_ref_status = !!run_add_p(the_repository, ADD_P_RESET, 439 + &add_p_opt, rev, &pathspec); 432 440 goto cleanup; 441 + } else { 442 + if (add_p_opt.context != -1) 443 + die(_("the option '%s' requires '%s'"), "--unified", "--patch"); 444 + if (add_p_opt.interhunkcontext != -1) 445 + die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--patch"); 433 446 } 434 447 435 448 /* git reset tree [--] paths... can be used to
+45 -11
builtin/stash.c
··· 1242 1242 } 1243 1243 1244 1244 static int stash_patch(struct stash_info *info, const struct pathspec *ps, 1245 - struct strbuf *out_patch, int quiet) 1245 + struct strbuf *out_patch, int quiet, 1246 + struct add_p_opt *add_p_opt) 1246 1247 { 1247 1248 int ret = 0; 1248 1249 struct child_process cp_read_tree = CHILD_PROCESS_INIT; ··· 1267 1268 old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT)); 1268 1269 setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1); 1269 1270 1270 - ret = !!run_add_p(the_repository, ADD_P_STASH, NULL, ps); 1271 + ret = !!run_add_p(the_repository, ADD_P_STASH, add_p_opt, NULL, ps); 1271 1272 1272 1273 the_repository->index_file = old_repo_index_file; 1273 1274 if (old_index_env && *old_index_env) ··· 1362 1363 } 1363 1364 1364 1365 static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_buf, 1365 - int include_untracked, int patch_mode, int only_staged, 1366 - struct stash_info *info, struct strbuf *patch, 1366 + int include_untracked, int patch_mode, struct add_p_opt *add_p_opt, 1367 + int only_staged, struct stash_info *info, struct strbuf *patch, 1367 1368 int quiet) 1368 1369 { 1369 1370 int ret = 0; ··· 1439 1440 untracked_commit_option = 1; 1440 1441 } 1441 1442 if (patch_mode) { 1442 - ret = stash_patch(info, ps, patch, quiet); 1443 + ret = stash_patch(info, ps, patch, quiet, add_p_opt); 1443 1444 if (ret < 0) { 1444 1445 if (!quiet) 1445 1446 fprintf_ln(stderr, _("Cannot save the current " ··· 1513 1514 if (!check_changes_tracked_files(&ps)) 1514 1515 return 0; 1515 1516 1516 - ret = do_create_stash(&ps, &stash_msg_buf, 0, 0, 0, &info, 1517 + ret = do_create_stash(&ps, &stash_msg_buf, 0, 0, NULL, 0, &info, 1517 1518 NULL, 0); 1518 1519 if (!ret) 1519 1520 printf_ln("%s", oid_to_hex(&info.w_commit)); ··· 1524 1525 } 1525 1526 1526 1527 static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int quiet, 1527 - int keep_index, int patch_mode, int include_untracked, int only_staged) 1528 + int keep_index, int patch_mode, struct add_p_opt *add_p_opt, 1529 + int include_untracked, int only_staged) 1528 1530 { 1529 1531 int ret = 0; 1530 1532 struct stash_info info = STASH_INFO_INIT; ··· 1594 1596 1595 1597 if (stash_msg) 1596 1598 strbuf_addstr(&stash_msg_buf, stash_msg); 1597 - if (do_create_stash(ps, &stash_msg_buf, include_untracked, patch_mode, only_staged, 1598 - &info, &patch, quiet)) { 1599 + if (do_create_stash(ps, &stash_msg_buf, include_untracked, patch_mode, 1600 + add_p_opt, only_staged, &info, &patch, quiet)) { 1599 1601 ret = -1; 1600 1602 goto done; 1601 1603 } ··· 1768 1770 const char *stash_msg = NULL; 1769 1771 char *pathspec_from_file = NULL; 1770 1772 struct pathspec ps; 1773 + struct add_p_opt add_p_opt = ADD_P_OPT_INIT; 1771 1774 struct option options[] = { 1772 1775 OPT_BOOL('k', "keep-index", &keep_index, 1773 1776 N_("keep index")), ··· 1775 1778 N_("stash staged changes only")), 1776 1779 OPT_BOOL('p', "patch", &patch_mode, 1777 1780 N_("stash in patch mode")), 1781 + OPT_DIFF_UNIFIED(&add_p_opt.context), 1782 + OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext), 1778 1783 OPT__QUIET(&quiet, N_("quiet mode")), 1779 1784 OPT_BOOL('u', "include-untracked", &include_untracked, 1780 1785 N_("include untracked files in stash")), ··· 1826 1831 die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file"); 1827 1832 } 1828 1833 1834 + if (!patch_mode) { 1835 + if (add_p_opt.context != -1) 1836 + die(_("the option '%s' requires '%s'"), "--unified", "--patch"); 1837 + if (add_p_opt.interhunkcontext != -1) 1838 + die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--patch"); 1839 + } 1840 + 1841 + if (add_p_opt.context < -1) 1842 + die(_("'%s' cannot be negative"), "--unified"); 1843 + if (add_p_opt.interhunkcontext < -1) 1844 + die(_("'%s' cannot be negative"), "--inter-hunk-context"); 1845 + 1829 1846 ret = do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode, 1830 - include_untracked, only_staged); 1847 + &add_p_opt, include_untracked, only_staged); 1831 1848 1832 1849 clear_pathspec(&ps); 1833 1850 free(pathspec_from_file); ··· 1852 1869 const char *stash_msg = NULL; 1853 1870 struct pathspec ps; 1854 1871 struct strbuf stash_msg_buf = STRBUF_INIT; 1872 + struct add_p_opt add_p_opt = ADD_P_OPT_INIT; 1855 1873 struct option options[] = { 1856 1874 OPT_BOOL('k', "keep-index", &keep_index, 1857 1875 N_("keep index")), ··· 1859 1877 N_("stash staged changes only")), 1860 1878 OPT_BOOL('p', "patch", &patch_mode, 1861 1879 N_("stash in patch mode")), 1880 + OPT_DIFF_UNIFIED(&add_p_opt.context), 1881 + OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext), 1862 1882 OPT__QUIET(&quiet, N_("quiet mode")), 1863 1883 OPT_BOOL('u', "include-untracked", &include_untracked, 1864 1884 N_("include untracked files in stash")), ··· 1877 1897 stash_msg = strbuf_join_argv(&stash_msg_buf, argc, argv, ' '); 1878 1898 1879 1899 memset(&ps, 0, sizeof(ps)); 1900 + 1901 + if (add_p_opt.context < -1) 1902 + die(_("'%s' cannot be negative"), "--unified"); 1903 + if (add_p_opt.interhunkcontext < -1) 1904 + die(_("'%s' cannot be negative"), "--inter-hunk-context"); 1905 + 1906 + if (!patch_mode) { 1907 + if (add_p_opt.context != -1) 1908 + die(_("the option '%s' requires '%s'"), "--unified", "--patch"); 1909 + if (add_p_opt.interhunkcontext != -1) 1910 + die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--patch"); 1911 + } 1912 + 1880 1913 ret = do_push_stash(&ps, stash_msg, quiet, keep_index, 1881 - patch_mode, include_untracked, only_staged); 1914 + patch_mode, &add_p_opt, include_untracked, 1915 + only_staged); 1882 1916 1883 1917 strbuf_release(&stash_msg_buf); 1884 1918 return ret;
+2 -1
commit.h
··· 2 2 #define COMMIT_H 3 3 4 4 #include "object.h" 5 + #include "add-interactive.h" 5 6 6 7 struct signature_check; 7 8 struct strbuf; ··· 257 258 int interactive_add(struct repository *repo, 258 259 const char **argv, 259 260 const char *prefix, 260 - int patch); 261 + int patch, struct add_p_opt *add_p_opt); 261 262 262 263 struct commit_extra_header { 263 264 struct commit_extra_header *next;
+2
parse-options.h
··· 616 616 #define OPT_PATHSPEC_FROM_FILE(v) OPT_FILENAME(0, "pathspec-from-file", v, N_("read pathspec from file")) 617 617 #define OPT_PATHSPEC_FILE_NUL(v) OPT_BOOL(0, "pathspec-file-nul", v, N_("with --pathspec-from-file, pathspec elements are separated with NUL character")) 618 618 #define OPT_AUTOSTASH(v) OPT_BOOL(0, "autostash", v, N_("automatically stash/stash pop before and after")) 619 + #define OPT_DIFF_UNIFIED(v) OPT_INTEGER_F('U', "unified", v, N_("generate diffs with <n> lines context"), PARSE_OPT_NONEG) 620 + #define OPT_DIFF_INTERHUNK_CONTEXT(v) OPT_INTEGER_F(0, "inter-hunk-context", v, N_("show context between diff hunks up to the specified number of lines"), PARSE_OPT_NONEG) 619 621 620 622 #define OPT_IPVERSION(v) \ 621 623 OPT_SET_INT_F('4', "ipv4", (v), N_("use IPv4 addresses only"), \
+49
t/t3701-add-interactive.sh
··· 1252 1252 test_grep "diff.context cannot be negative" output 1253 1253 ' 1254 1254 1255 + for cmd in add checkout restore 'commit -m file' 1256 + do 1257 + test_expect_success "${cmd%% *} accepts -U and --inter-hunk-context" ' 1258 + test_write_lines a b c d e f g h i j k l m n o p q r s t u v >file && 1259 + git add file && 1260 + test_write_lines a b c d e F g h i j k l m n o p Q r s t u v >file && 1261 + echo y | git -c diff.context=5 -c diff.interhunkcontext=1 \ 1262 + $cmd -p -U 4 --inter-hunk-context 2 >actual && 1263 + test_grep "@@ -2,20 +2,20 @@" actual 1264 + ' 1265 + done 1266 + 1267 + test_expect_success 'reset accepts -U and --inter-hunk-context' ' 1268 + test_write_lines a b c d e f g h i j k l m n o p q r s t u v >file && 1269 + git commit -m file file && 1270 + test_write_lines a b c d e F g h i j k l m n o p Q r s t u v >file && 1271 + git add file && 1272 + echo y | git -c diff.context=5 -c diff.interhunkcontext=1 \ 1273 + reset -p -U 4 --inter-hunk-context 2 >actual && 1274 + test_grep "@@ -2,20 +2,20 @@" actual 1275 + ' 1276 + 1277 + test_expect_success 'stash accepts -U and --inter-hunk-context' ' 1278 + test_write_lines a b c d e F g h i j k l m n o p Q r s t u v >file && 1279 + git commit -m file file && 1280 + test_write_lines a b c d e f g h i j k l m n o p q r s t u v >file && 1281 + echo y | git -c diff.context=5 -c diff.interhunkcontext=1 \ 1282 + stash -p -U 4 --inter-hunk-context 2 >actual && 1283 + test_grep "@@ -2,20 +2,20 @@" actual 1284 + ' 1285 + 1286 + for cmd in add checkout commit reset restore "stash save" "stash push" 1287 + do 1288 + test_expect_success "$cmd rejects invalid context options" ' 1289 + test_must_fail git $cmd -p -U -3 2>actual && 1290 + cat actual | echo && 1291 + test_grep -e ".--unified. cannot be negative" actual && 1292 + 1293 + test_must_fail git $cmd -p --inter-hunk-context -3 2>actual && 1294 + test_grep -e ".--inter-hunk-context. cannot be negative" actual && 1295 + 1296 + test_must_fail git $cmd -U 7 2>actual && 1297 + test_grep -E ".--unified. requires .(--interactive/)?--patch." actual && 1298 + 1299 + test_must_fail git $cmd --inter-hunk-context 2 2>actual && 1300 + test_grep -E ".--inter-hunk-context. requires .(--interactive/)?--patch." actual 1301 + ' 1302 + done 1303 + 1255 1304 test_done
+2
t/t9902-completion.sh
··· 2596 2596 --merge Z 2597 2597 --conflict=Z 2598 2598 --patch Z 2599 + --unified=Z 2600 + --inter-hunk-context=Z 2599 2601 --ignore-skip-worktree-bits Z 2600 2602 --ignore-other-worktrees Z 2601 2603 --recurse-submodules Z