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