Skip to content

Commit 5ac62a9

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 e6b1b18 commit 5ac62a9

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
@@ -839,7 +839,7 @@ static int run_patch(struct add_i_state *s, const struct pathspec *ps,
839839
parse_pathspec(&ps_selected,
840840
PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
841841
PATHSPEC_LITERAL_PATH, "", args.argv);
842-
res = run_add_p(s->r, &ps_selected);
842+
res = run_add_p(s->r, ADD_P_STAGE, NULL, &ps_selected);
843843
argv_array_clear(&args);
844844
clear_pathspec(&ps_selected);
845845
}

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, ...)
@@ -158,9 +185,18 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
158185
struct hunk *hunk = NULL;
159186
int res;
160187

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

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

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

@@ -952,13 +988,6 @@ static size_t display_hunks(struct add_p_state *s,
952988
return end_index;
953989
}
954990

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

10421071
color_fprintf(stdout, s->s.prompt_color,
1043-
_(prompt_mode[prompt_mode_type]), s->buf.buf);
1072+
_(s->mode->prompt_mode[prompt_mode_type]),
1073+
s->buf.buf);
10441074
fflush(stdout);
10451075
if (strbuf_getline(&s->answer, stdin) == EOF)
10461076
break;
@@ -1197,7 +1227,7 @@ static int patch_update_file(struct add_p_state *s,
11971227
const char *p = _(help_patch_remainder), *eol = p;
11981228

11991229
color_fprintf(stdout, s->s.help_color, "%s",
1200-
_(help_patch_text));
1230+
_(s->mode->help_patch_text));
12011231

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

1233-
setup_child_process(&cp, s, "apply", "--cached", NULL);
1263+
setup_child_process(&cp, s, "apply", NULL);
1264+
argv_array_pushv(&cp.args, s->mode->apply);
12341265
if (pipe_command(&cp, s->buf.buf, s->buf.len,
12351266
NULL, 0, NULL, 0))
1236-
error(_("'git apply --cached' failed"));
1267+
error(_("'git apply' failed"));
12371268
repo_refresh_and_write_index(s->s.r, REFRESH_QUIET, 0);
12381269
}
12391270

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

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

1286+
s.mode = &patch_mode_stage;
1287+
s.revision = revision;
1288+
12541289
if (repo_refresh_and_write_index(r, REFRESH_QUIET, 0) < 0 ||
12551290
parse_diff(&s, ps) < 0) {
12561291
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)