Skip to content

Commit d2a233c

Browse files
dschogitster
authored andcommitted
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 <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 2e40831 commit d2a233c

File tree

4 files changed

+85
-30
lines changed

4 files changed

+85
-30
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_ADD, 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_ADD,
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: 69 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,41 @@
88
#include "diff.h"
99

1010
enum prompt_mode_type {
11-
PROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_HUNK
11+
PROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_HUNK,
12+
PROMPT_MODE_MAX, /* must be last */
1213
};
1314

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,?]? ")
15+
struct patch_mode {
16+
/*
17+
* The magic constant 4 is chosen such that all patch modes
18+
* provide enough space for three command-line arguments followed by a
19+
* trailing `NULL`.
20+
*/
21+
const char *diff_cmd[4], *apply_args[4], *apply_check_args[4];
22+
unsigned is_reverse:1, apply_for_checkout:1;
23+
const char *prompt_mode[PROMPT_MODE_MAX];
24+
const char *edit_hunk_hint, *help_patch_text;
25+
};
26+
27+
static struct patch_mode patch_mode_add = {
28+
.diff_cmd = { "diff-files", NULL },
29+
.apply_args = { "--cached", NULL },
30+
.apply_check_args = { "--cached", NULL },
31+
.prompt_mode = {
32+
N_("Stage mode change [y,n,q,a,d%s,?]? "),
33+
N_("Stage deletion [y,n,q,a,d%s,?]? "),
34+
N_("Stage this hunk [y,n,q,a,d%s,?]? ")
35+
},
36+
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
37+
"will immediately be marked for staging."),
38+
.help_patch_text =
39+
N_("y - stage this hunk\n"
40+
"n - do not stage this hunk\n"
41+
"q - quit; do not stage this hunk or any of the remaining "
42+
"ones\n"
43+
"a - stage this hunk and all later hunks in the file\n"
44+
"d - do not stage this hunk or any of the later hunks in "
45+
"the file\n")
1846
};
1947

2048
struct hunk_header {
@@ -47,6 +75,10 @@ struct add_p_state {
4775
unsigned deleted:1, mode_change:1,binary:1;
4876
} *file_diff;
4977
size_t file_diff_nr;
78+
79+
/* patch mode */
80+
struct patch_mode *mode;
81+
const char *revision;
5082
};
5183

5284
static void err(struct add_p_state *s, const char *fmt, ...)
@@ -162,9 +194,18 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
162194
struct hunk *hunk = NULL;
163195
int res;
164196

197+
argv_array_pushv(&args, s->mode->diff_cmd);
198+
if (s->revision) {
199+
struct object_id oid;
200+
argv_array_push(&args,
201+
/* could be on an unborn branch */
202+
!strcmp("HEAD", s->revision) &&
203+
get_oid("HEAD", &oid) ?
204+
empty_tree_oid_hex() : s->revision);
205+
}
206+
color_arg_index = args.argc;
165207
/* 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;
208+
argv_array_pushl(&args, "--no-color", "-p", "--", NULL);
168209
for (i = 0; i < ps->nr; i++)
169210
argv_array_push(&args, ps->items[i].original);
170211

@@ -382,7 +423,10 @@ static void render_hunk(struct add_p_state *s, struct hunk *hunk,
382423
- header->colored_extra_start;
383424
}
384425

385-
new_offset += delta;
426+
if (s->mode->is_reverse)
427+
old_offset -= delta;
428+
else
429+
new_offset += delta;
386430

387431
strbuf_addf(out, "@@ -%lu,%lu +%lu,%lu @@",
388432
old_offset, header->old_count,
@@ -805,11 +849,10 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
805849
"(context).\n"
806850
"To remove '%c' lines, delete them.\n"
807851
"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"));
852+
s->mode->is_reverse ? '+' : '-',
853+
s->mode->is_reverse ? '-' : '+',
854+
comment_line_char);
855+
strbuf_commented_addf(&s->buf, "%s", _(s->mode->edit_hunk_hint));
813856
/*
814857
* TRANSLATORS: 'it' refers to the patch mentioned in the previous
815858
* messages.
@@ -890,7 +933,8 @@ static int run_apply_check(struct add_p_state *s,
890933
reassemble_patch(s, file_diff, 1, &s->buf);
891934

892935
setup_child_process(s, &cp,
893-
"apply", "--cached", "--check", NULL);
936+
"apply", "--check", NULL);
937+
argv_array_pushv(&cp.args, s->mode->apply_check_args);
894938
if (pipe_command(&cp, s->buf.buf, s->buf.len, NULL, 0, NULL, 0))
895939
return error(_("'git apply --cached' failed"));
896940

@@ -1005,13 +1049,6 @@ static size_t display_hunks(struct add_p_state *s,
10051049
return end_index;
10061050
}
10071051

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-
10151052
static const char help_patch_remainder[] =
10161053
N_("j - leave this hunk undecided, see next undecided hunk\n"
10171054
"J - leave this hunk undecided, see next hunk\n"
@@ -1097,7 +1134,8 @@ static int patch_update_file(struct add_p_state *s,
10971134
(uintmax_t)hunk_index + 1,
10981135
(uintmax_t)file_diff->hunk_nr);
10991136
color_fprintf(stdout, s->s.prompt_color,
1100-
_(prompt_mode[prompt_mode_type]), s->buf.buf);
1137+
_(s->mode->prompt_mode[prompt_mode_type]),
1138+
s->buf.buf);
11011139
fflush(stdout);
11021140
if (strbuf_getline(&s->answer, stdin) == EOF)
11031141
break;
@@ -1254,7 +1292,7 @@ static int patch_update_file(struct add_p_state *s,
12541292
const char *p = _(help_patch_remainder), *eol = p;
12551293

12561294
color_fprintf(stdout, s->s.help_color, "%s",
1257-
_(help_patch_text));
1295+
_(s->mode->help_patch_text));
12581296

12591297
/*
12601298
* Show only those lines of the remainder that are
@@ -1288,10 +1326,11 @@ static int patch_update_file(struct add_p_state *s,
12881326
reassemble_patch(s, file_diff, 0, &s->buf);
12891327

12901328
discard_index(s->s.r->index);
1291-
setup_child_process(s, &cp, "apply", "--cached", NULL);
1329+
setup_child_process(s, &cp, "apply", NULL);
1330+
argv_array_pushv(&cp.args, s->mode->apply_args);
12921331
if (pipe_command(&cp, s->buf.buf, s->buf.len,
12931332
NULL, 0, NULL, 0))
1294-
error(_("'git apply --cached' failed"));
1333+
error(_("'git apply' failed"));
12951334
if (!repo_read_index(s->s.r))
12961335
repo_refresh_and_write_index(s->s.r, REFRESH_QUIET, 0,
12971336
1, NULL, NULL, NULL);
@@ -1301,7 +1340,8 @@ static int patch_update_file(struct add_p_state *s,
13011340
return quit;
13021341
}
13031342

1304-
int run_add_p(struct repository *r, const struct pathspec *ps)
1343+
int run_add_p(struct repository *r, enum add_p_mode mode,
1344+
const char *revision, const struct pathspec *ps)
13051345
{
13061346
struct add_p_state s = {
13071347
{ r }, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
@@ -1310,6 +1350,9 @@ int run_add_p(struct repository *r, const struct pathspec *ps)
13101350

13111351
init_add_i_state(&s.s, r);
13121352

1353+
s.mode = &patch_mode_add;
1354+
s.revision = revision;
1355+
13131356
if (discard_index(r->index) < 0 || repo_read_index(r) < 0 ||
13141357
repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1,
13151358
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_ADD;
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)