Skip to content

Commit 8f6139f

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. 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 2e40831 commit 8f6139f

File tree

4 files changed

+79
-29
lines changed

4 files changed

+79
-29
lines changed

add-interactive.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,7 @@ static int run_patch(struct add_i_state *s, const struct pathspec *ps,
924924
parse_pathspec(&ps_selected,
925925
PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
926926
PATHSPEC_LITERAL_PATH, "", args.argv);
927-
res = run_add_p(s->r, &ps_selected);
927+
res = run_add_p(s->r, ADD_P_STAGE, NULL, &ps_selected);
928928
argv_array_clear(&args);
929929
clear_pathspec(&ps_selected);
930930
}

add-interactive.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ void init_add_i_state(struct add_i_state *s, struct repository *r);
2222
struct repository;
2323
struct pathspec;
2424
int run_add_i(struct repository *r, const struct pathspec *ps);
25-
int run_add_p(struct repository *r, const struct pathspec *ps);
25+
26+
enum add_p_mode {
27+
ADD_P_STAGE,
28+
};
29+
30+
int run_add_p(struct repository *r, enum add_p_mode mode,
31+
const char *revision, const struct pathspec *ps);
2632

2733
#endif

add-patch.c

Lines changed: 63 additions & 25 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, ...)
@@ -162,9 +189,18 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
162189
struct hunk *hunk = NULL;
163190
int res;
164191

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

@@ -382,7 +418,10 @@ static void render_hunk(struct add_p_state *s, struct hunk *hunk,
382418
- header->colored_extra_start;
383419
}
384420

385-
new_offset += delta;
421+
if (s->mode->is_reverse)
422+
old_offset -= delta;
423+
else
424+
new_offset += delta;
386425

387426
strbuf_addf(out, "@@ -%lu,%lu +%lu,%lu @@",
388427
old_offset, header->old_count,
@@ -805,11 +844,10 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
805844
"(context).\n"
806845
"To remove '%c' lines, delete them.\n"
807846
"Lines starting with %c will be removed.\n"),
808-
'-', '+', comment_line_char);
809-
strbuf_commented_addf(&s->buf,
810-
_("If the patch applies cleanly, the edited hunk "
811-
"will immediately be\n"
812-
"marked for staging.\n"));
847+
s->mode->is_reverse ? '+' : '-',
848+
s->mode->is_reverse ? '-' : '+',
849+
comment_line_char);
850+
strbuf_commented_addf(&s->buf, "%s", _(s->mode->edit_hunk_hint));
813851
/*
814852
* TRANSLATORS: 'it' refers to the patch mentioned in the previous
815853
* messages.
@@ -890,7 +928,8 @@ static int run_apply_check(struct add_p_state *s,
890928
reassemble_patch(s, file_diff, 1, &s->buf);
891929

892930
setup_child_process(s, &cp,
893-
"apply", "--cached", "--check", NULL);
931+
"apply", "--check", NULL);
932+
argv_array_pushv(&cp.args, s->mode->apply_check);
894933
if (pipe_command(&cp, s->buf.buf, s->buf.len, NULL, 0, NULL, 0))
895934
return error(_("'git apply --cached' failed"));
896935

@@ -1005,13 +1044,6 @@ static size_t display_hunks(struct add_p_state *s,
10051044
return end_index;
10061045
}
10071046

1008-
static const char help_patch_text[] =
1009-
N_("y - stage this hunk\n"
1010-
"n - do not stage this hunk\n"
1011-
"q - quit; do not stage this hunk or any of the remaining ones\n"
1012-
"a - stage this and all the remaining hunks\n"
1013-
"d - do not stage this hunk nor any of the remaining hunks\n");
1014-
10151047
static const char help_patch_remainder[] =
10161048
N_("j - leave this hunk undecided, see next undecided hunk\n"
10171049
"J - leave this hunk undecided, see next hunk\n"
@@ -1097,7 +1129,8 @@ static int patch_update_file(struct add_p_state *s,
10971129
(uintmax_t)hunk_index + 1,
10981130
(uintmax_t)file_diff->hunk_nr);
10991131
color_fprintf(stdout, s->s.prompt_color,
1100-
_(prompt_mode[prompt_mode_type]), s->buf.buf);
1132+
_(s->mode->prompt_mode[prompt_mode_type]),
1133+
s->buf.buf);
11011134
fflush(stdout);
11021135
if (strbuf_getline(&s->answer, stdin) == EOF)
11031136
break;
@@ -1254,7 +1287,7 @@ static int patch_update_file(struct add_p_state *s,
12541287
const char *p = _(help_patch_remainder), *eol = p;
12551288

12561289
color_fprintf(stdout, s->s.help_color, "%s",
1257-
_(help_patch_text));
1290+
_(s->mode->help_patch_text));
12581291

12591292
/*
12601293
* Show only those lines of the remainder that are
@@ -1288,10 +1321,11 @@ static int patch_update_file(struct add_p_state *s,
12881321
reassemble_patch(s, file_diff, 0, &s->buf);
12891322

12901323
discard_index(s->s.r->index);
1291-
setup_child_process(s, &cp, "apply", "--cached", NULL);
1324+
setup_child_process(s, &cp, "apply", NULL);
1325+
argv_array_pushv(&cp.args, s->mode->apply);
12921326
if (pipe_command(&cp, s->buf.buf, s->buf.len,
12931327
NULL, 0, NULL, 0))
1294-
error(_("'git apply --cached' failed"));
1328+
error(_("'git apply' failed"));
12951329
if (!repo_read_index(s->s.r))
12961330
repo_refresh_and_write_index(s->s.r, REFRESH_QUIET, 0,
12971331
1, NULL, NULL, NULL);
@@ -1301,7 +1335,8 @@ static int patch_update_file(struct add_p_state *s,
13011335
return quit;
13021336
}
13031337

1304-
int run_add_p(struct repository *r, const struct pathspec *ps)
1338+
int run_add_p(struct repository *r, enum add_p_mode mode,
1339+
const char *revision, const struct pathspec *ps)
13051340
{
13061341
struct add_p_state s = {
13071342
{ r }, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
@@ -1310,6 +1345,9 @@ int run_add_p(struct repository *r, const struct pathspec *ps)
13101345

13111346
init_add_i_state(&s.s, r);
13121347

1348+
s.mode = &patch_mode_stage;
1349+
s.revision = revision;
1350+
13131351
if (discard_index(r->index) < 0 || repo_read_index(r) < 0 ||
13141352
repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1,
13151353
NULL, NULL, NULL) < 0 ||

builtin/add.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,12 +194,18 @@ int run_add_interactive(const char *revision, const char *patch_mode,
194194
&use_builtin_add_i);
195195

196196
if (use_builtin_add_i == 1) {
197+
enum add_p_mode mode;
198+
197199
if (!patch_mode)
198200
return !!run_add_i(the_repository, pathspec);
199-
if (strcmp(patch_mode, "--patch"))
201+
202+
if (!strcmp(patch_mode, "--patch"))
203+
mode = ADD_P_STAGE;
204+
else
200205
die("'%s' not yet supported in the built-in add -p",
201206
patch_mode);
202-
return !!run_add_p(the_repository, pathspec);
207+
208+
return !!run_add_p(the_repository, mode, revision, pathspec);
203209
}
204210

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

0 commit comments

Comments
 (0)