Skip to content

Commit 30e47c1

Browse files
committed
built-in add -p: prepare for patch modes other than "stage"
The Perl script backing `git add -p` is used not only for that command, but also for `git stash -p`, `git reset -p` and `git checkout -p`. In preparation for teaching the C version of `git add -p` to support also the latter commands, let's abstract away what is "stage" specific into a dedicated data structure describing the differences between the patch modes. As we prepare for calling the built-in `git add -p` in `run_add_interactive()` via code paths that have not let `add_config()` do its work, we have to make sure to re-parse the config using that function in those cases. Finally, please note that the Perl version tries to make sure that the diffs are only generated for the modified files. This is not actually necessary, as the calls to Git's diff machinery already perform that work, and perform it well. This makes it unnecessary to port the `FILTER` field of the `%patch_modes` struct, as well as the `get_diff_reference()` function. Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 2890041 commit 30e47c1

File tree

4 files changed

+77
-28
lines changed

4 files changed

+77
-28
lines changed

add-interactive.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@ static int run_patch(struct add_i_state *s, const struct pathspec *ps,
846846
parse_pathspec(&ps_selected,
847847
PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
848848
PATHSPEC_LITERAL_PATH, "", args.argv);
849-
res = run_add_p(s->r, &ps_selected);
849+
res = run_add_p(s->r, ADD_P_STAGE, NULL, &ps_selected);
850850
argv_array_clear(&args);
851851
clear_pathspec(&ps_selected);
852852
}

add-interactive.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ const char *get_add_i_color(enum color_add_i ix);
3131
struct repository;
3232
struct pathspec;
3333
int run_add_i(struct repository *r, const struct pathspec *ps);
34-
int run_add_p(struct repository *r, const struct pathspec *ps);
34+
35+
enum add_p_mode {
36+
ADD_P_STAGE,
37+
};
38+
39+
int run_add_p(struct repository *r, enum add_p_mode mode,
40+
const char *revision, const struct pathspec *ps);
3541

3642
#endif

add-patch.c

Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,33 @@ enum prompt_mode_type {
1111
PROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_HUNK
1212
};
1313

14-
static const char *prompt_mode[] = {
15-
N_("Stage mode change [y,n,a,q,d%s,?]? "),
16-
N_("Stage deletion [y,n,a,q,d%s,?]? "),
17-
N_("Stage this hunk [y,n,a,q,d%s,?]? ")
14+
struct patch_mode {
15+
const char *diff[4], *apply[4], *apply_check[4];
16+
unsigned is_reverse:1, apply_for_checkout:1;
17+
const char *prompt_mode[PROMPT_HUNK + 1];
18+
const char *edit_hunk_hint, *help_patch_text;
19+
};
20+
21+
static struct patch_mode patch_mode_stage = {
22+
.diff = { "diff-files", NULL },
23+
.apply = { "--cached", NULL },
24+
.apply_check = { "--cached", NULL },
25+
.is_reverse = 0,
26+
.prompt_mode = {
27+
N_("Stage mode change [y,n,q,a,d%s,?]? "),
28+
N_("Stage deletion [y,n,q,a,d%s,?]? "),
29+
N_("Stage this hunk [y,n,q,a,d%s,?]? ")
30+
},
31+
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
32+
"will immediately be marked for staging."),
33+
.help_patch_text =
34+
N_("y - stage this hunk\n"
35+
"n - do not stage this hunk\n"
36+
"q - quit; do not stage this hunk or any of the remaining "
37+
"ones\n"
38+
"a - stage this hunk and all later hunks in the file\n"
39+
"d - do not stage this hunk or any of the later hunks in "
40+
"the file\n")
1841
};
1942

2043
struct hunk_header {
@@ -47,6 +70,10 @@ struct add_p_state {
4770
unsigned deleted:1, mode_change:1,binary:1;
4871
} *file_diff;
4972
size_t file_diff_nr;
73+
74+
/* patch mode */
75+
struct patch_mode *mode;
76+
const char *revision;
5077
};
5178

5279
static void err(struct add_p_state *s, const char *fmt, ...)
@@ -159,9 +186,18 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
159186
struct hunk *hunk = NULL;
160187
int res;
161188

189+
argv_array_pushv(&args, s->mode->diff);
190+
if (s->revision) {
191+
struct object_id oid;
192+
argv_array_push(&args,
193+
/* could be on an unborn branch */
194+
!strcmp("HEAD", s->revision) &&
195+
get_oid("HEAD", &oid) ?
196+
empty_tree_oid_hex() : s->revision);
197+
}
198+
color_arg_index = args.argc;
162199
/* Use `--no-color` explicitly, just in case `diff.color = always`. */
163-
argv_array_pushl(&args, "diff-files", "-p", "--no-color", "--", NULL);
164-
color_arg_index = args.argc - 2;
200+
argv_array_pushl(&args, "--no-color", "-p", "--", NULL);
165201
for (i = 0; i < ps->nr; i++)
166202
argv_array_push(&args, ps->items[i].original);
167203

@@ -738,11 +774,10 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
738774
"(context).\n"
739775
"To remove '%c' lines, delete them.\n"
740776
"Lines starting with %c will be removed.\n"),
741-
'-', '+', comment_line_char);
742-
strbuf_commented_addf(&buf,
743-
_("If the patch applies cleanly, the edited hunk "
744-
"will immediately be\n"
745-
"marked for staging.\n"));
777+
s->mode->is_reverse ? '+' : '-',
778+
s->mode->is_reverse ? '-' : '+',
779+
comment_line_char);
780+
strbuf_commented_addf(&buf, "%s", _(s->mode->edit_hunk_hint));
746781
/*
747782
* TRANSLATORS: 'it' refers to the patch mentioned in the previous
748783
* messages.
@@ -838,7 +873,8 @@ static int run_apply_check(struct add_p_state *s,
838873
reassemble_patch(s, file_diff, 1, &s->buf);
839874

840875
setup_child_process(&cp, s,
841-
"apply", "--cached", "--check", NULL);
876+
"apply", "--check", NULL);
877+
argv_array_pushv(&cp.args, s->mode->apply_check);
842878
if (pipe_command(&cp, s->buf.buf, s->buf.len, NULL, 0, NULL, 0))
843879
return error(_("'git apply --cached' failed"));
844880

@@ -953,13 +989,6 @@ static size_t display_hunks(struct add_p_state *s,
953989
return end_index;
954990
}
955991

956-
static const char help_patch_text[] =
957-
N_("y - stage this hunk\n"
958-
"n - do not stage this hunk\n"
959-
"q - quit; do not stage this hunk or any of the remaining ones\n"
960-
"a - stage this and all the remaining hunks\n"
961-
"d - do not stage this hunk nor any of the remaining hunks\n");
962-
963992
static const char help_patch_remainder[] =
964993
N_("j - leave this hunk undecided, see next undecided hunk\n"
965994
"J - leave this hunk undecided, see next hunk\n"
@@ -1041,7 +1070,8 @@ static int patch_update_file(struct add_p_state *s,
10411070
prompt_mode_type = PROMPT_HUNK;
10421071

10431072
color_fprintf(stdout, s->s.prompt_color,
1044-
_(prompt_mode[prompt_mode_type]), s->buf.buf);
1073+
_(s->mode->prompt_mode[prompt_mode_type]),
1074+
s->buf.buf);
10451075
fflush(stdout);
10461076
if (strbuf_getline(&s->answer, stdin) == EOF)
10471077
break;
@@ -1198,7 +1228,7 @@ static int patch_update_file(struct add_p_state *s,
11981228
const char *p = _(help_patch_remainder), *eol = p;
11991229

12001230
color_fprintf(stdout, s->s.help_color, "%s",
1201-
_(help_patch_text));
1231+
_(s->mode->help_patch_text));
12021232

12031233
/*
12041234
* Show only those lines of the remainder that are
@@ -1231,18 +1261,20 @@ static int patch_update_file(struct add_p_state *s,
12311261
strbuf_reset(&s->buf);
12321262
reassemble_patch(s, file_diff, 0, &s->buf);
12331263

1234-
setup_child_process(&cp, s, "apply", "--cached", NULL);
1264+
setup_child_process(&cp, s, "apply", NULL);
1265+
argv_array_pushv(&cp.args, s->mode->apply);
12351266
if (pipe_command(&cp, s->buf.buf, s->buf.len,
12361267
NULL, 0, NULL, 0))
1237-
error(_("'git apply --cached' failed"));
1268+
error(_("'git apply' failed"));
12381269
repo_refresh_and_write_index(s->s.r, REFRESH_QUIET, 0);
12391270
}
12401271

12411272
putchar('\n');
12421273
return quit;
12431274
}
12441275

1245-
int run_add_p(struct repository *r, const struct pathspec *ps)
1276+
int run_add_p(struct repository *r, enum add_p_mode mode,
1277+
const char *revision, const struct pathspec *ps)
12461278
{
12471279
struct add_p_state s = {
12481280
{ r }, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
@@ -1252,6 +1284,9 @@ int run_add_p(struct repository *r, const struct pathspec *ps)
12521284
if (init_add_i_state(r, &s.s))
12531285
return error("Could not read `add -i` config");
12541286

1287+
s.mode = &patch_mode_stage;
1288+
s.revision = revision;
1289+
12551290
if (repo_refresh_and_write_index(r, REFRESH_QUIET, 0) < 0 ||
12561291
parse_diff(&s, ps) < 0) {
12571292
strbuf_release(&s.plain);

builtin/add.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ static void refresh(int verbose, const struct pathspec *pathspec)
181181
free(seen);
182182
}
183183

184+
static int add_config(const char *var, const char *value, void *cb);
185+
184186
int run_add_interactive(const char *revision, const char *patch_mode,
185187
const struct pathspec *pathspec)
186188
{
@@ -193,12 +195,18 @@ int run_add_interactive(const char *revision, const char *patch_mode,
193195
&use_builtin_add_i);
194196

195197
if (use_builtin_add_i == 1) {
198+
enum add_p_mode mode;
199+
196200
if (!patch_mode)
197201
return !!run_add_i(the_repository, pathspec);
198-
if (strcmp(patch_mode, "--patch"))
202+
203+
if (!strcmp(patch_mode, "--patch"))
204+
mode = ADD_P_STAGE;
205+
else
199206
die("'%s' not yet supported in the built-in add -p",
200207
patch_mode);
201-
return !!run_add_p(the_repository, pathspec);
208+
209+
return !!run_add_p(the_repository, mode, revision, pathspec);
202210
}
203211

204212
argv_array_push(&argv, "add--interactive");

0 commit comments

Comments
 (0)