Merge branch 'js/patch-mode-in-others-in-c'

The effort to move "git-add--interactive" to C continues.

* js/patch-mode-in-others-in-c:
  commit --interactive: make it work with the built-in `add -i`
  built-in add -p: implement the "worktree" patch modes
  built-in add -p: implement the "checkout" patch modes
  built-in stash: use the built-in `git add -p` if so configured
  legacy stash -p: respect the add.interactive.usebuiltin setting
  built-in add -p: implement the "stash" and "reset" patch modes
  built-in add -p: prepare for patch modes other than "stage"
This commit is contained in:
Junio C Hamano 2020-02-05 14:34:58 -08:00
Родитель 381e8e9de1 c480eeb574
Коммит 9a5315edfd
7 изменённых файлов: 390 добавлений и 50 удалений

Просмотреть файл

@ -927,7 +927,7 @@ static int run_patch(struct add_i_state *s, const struct pathspec *ps,
parse_pathspec(&ps_selected, parse_pathspec(&ps_selected,
PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL, PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
PATHSPEC_LITERAL_PATH, "", args.argv); PATHSPEC_LITERAL_PATH, "", args.argv);
res = run_add_p(s->r, &ps_selected); res = run_add_p(s->r, ADD_P_ADD, NULL, &ps_selected);
argv_array_clear(&args); argv_array_clear(&args);
clear_pathspec(&ps_selected); clear_pathspec(&ps_selected);
} }

Просмотреть файл

@ -22,6 +22,16 @@ void init_add_i_state(struct add_i_state *s, struct repository *r);
struct repository; struct repository;
struct pathspec; struct pathspec;
int run_add_i(struct repository *r, const struct pathspec *ps); int run_add_i(struct repository *r, const struct pathspec *ps);
int run_add_p(struct repository *r, const struct pathspec *ps);
enum add_p_mode {
ADD_P_ADD,
ADD_P_STASH,
ADD_P_RESET,
ADD_P_CHECKOUT,
ADD_P_WORKTREE,
};
int run_add_p(struct repository *r, enum add_p_mode mode,
const char *revision, const struct pathspec *ps);
#endif #endif

Просмотреть файл

@ -8,13 +8,215 @@
#include "diff.h" #include "diff.h"
enum prompt_mode_type { enum prompt_mode_type {
PROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_HUNK PROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_HUNK,
PROMPT_MODE_MAX, /* must be last */
}; };
static const char *prompt_mode[] = { struct patch_mode {
N_("Stage mode change [y,n,a,q,d%s,?]? "), /*
N_("Stage deletion [y,n,a,q,d%s,?]? "), * The magic constant 4 is chosen such that all patch modes
N_("Stage this hunk [y,n,a,q,d%s,?]? ") * provide enough space for three command-line arguments followed by a
* trailing `NULL`.
*/
const char *diff_cmd[4], *apply_args[4], *apply_check_args[4];
unsigned is_reverse:1, index_only:1, apply_for_checkout:1;
const char *prompt_mode[PROMPT_MODE_MAX];
const char *edit_hunk_hint, *help_patch_text;
};
static struct patch_mode patch_mode_add = {
.diff_cmd = { "diff-files", NULL },
.apply_args = { "--cached", NULL },
.apply_check_args = { "--cached", NULL },
.prompt_mode = {
N_("Stage mode change [y,n,q,a,d%s,?]? "),
N_("Stage deletion [y,n,q,a,d%s,?]? "),
N_("Stage this hunk [y,n,q,a,d%s,?]? ")
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
"will immediately be marked for staging."),
.help_patch_text =
N_("y - stage this hunk\n"
"n - do not stage this hunk\n"
"q - quit; do not stage this hunk or any of the remaining "
"ones\n"
"a - stage this hunk and all later hunks in the file\n"
"d - do not stage this hunk or any of the later hunks in "
"the file\n")
};
static struct patch_mode patch_mode_stash = {
.diff_cmd = { "diff-index", "HEAD", NULL },
.apply_args = { "--cached", NULL },
.apply_check_args = { "--cached", NULL },
.prompt_mode = {
N_("Stash mode change [y,n,q,a,d%s,?]? "),
N_("Stash deletion [y,n,q,a,d%s,?]? "),
N_("Stash this hunk [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
"will immediately be marked for stashing."),
.help_patch_text =
N_("y - stash this hunk\n"
"n - do not stash this hunk\n"
"q - quit; do not stash this hunk or any of the remaining "
"ones\n"
"a - stash this hunk and all later hunks in the file\n"
"d - do not stash this hunk or any of the later hunks in "
"the file\n"),
};
static struct patch_mode patch_mode_reset_head = {
.diff_cmd = { "diff-index", "--cached", NULL },
.apply_args = { "-R", "--cached", NULL },
.apply_check_args = { "-R", "--cached", NULL },
.is_reverse = 1,
.index_only = 1,
.prompt_mode = {
N_("Unstage mode change [y,n,q,a,d%s,?]? "),
N_("Unstage deletion [y,n,q,a,d%s,?]? "),
N_("Unstage this hunk [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
"will immediately be marked for unstaging."),
.help_patch_text =
N_("y - unstage this hunk\n"
"n - do not unstage this hunk\n"
"q - quit; do not unstage this hunk or any of the remaining "
"ones\n"
"a - unstage this hunk and all later hunks in the file\n"
"d - do not unstage this hunk or any of the later hunks in "
"the file\n"),
};
static struct patch_mode patch_mode_reset_nothead = {
.diff_cmd = { "diff-index", "-R", "--cached", NULL },
.apply_args = { "--cached", NULL },
.apply_check_args = { "--cached", NULL },
.index_only = 1,
.prompt_mode = {
N_("Apply mode change to index [y,n,q,a,d%s,?]? "),
N_("Apply deletion to index [y,n,q,a,d%s,?]? "),
N_("Apply this hunk to index [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
"will immediately be marked for applying."),
.help_patch_text =
N_("y - apply this hunk to index\n"
"n - do not apply this hunk to index\n"
"q - quit; do not apply this hunk or any of the remaining "
"ones\n"
"a - apply this hunk and all later hunks in the file\n"
"d - do not apply this hunk or any of the later hunks in "
"the file\n"),
};
static struct patch_mode patch_mode_checkout_index = {
.diff_cmd = { "diff-files", NULL },
.apply_args = { "-R", NULL },
.apply_check_args = { "-R", NULL },
.is_reverse = 1,
.prompt_mode = {
N_("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
N_("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
N_("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
"will immediately be marked for discarding."),
.help_patch_text =
N_("y - discard this hunk from worktree\n"
"n - do not discard this hunk from worktree\n"
"q - quit; do not discard this hunk or any of the remaining "
"ones\n"
"a - discard this hunk and all later hunks in the file\n"
"d - do not discard this hunk or any of the later hunks in "
"the file\n"),
};
static struct patch_mode patch_mode_checkout_head = {
.diff_cmd = { "diff-index", NULL },
.apply_for_checkout = 1,
.apply_check_args = { "-R", NULL },
.is_reverse = 1,
.prompt_mode = {
N_("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
N_("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
N_("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
"will immediately be marked for discarding."),
.help_patch_text =
N_("y - discard this hunk from index and worktree\n"
"n - do not discard this hunk from index and worktree\n"
"q - quit; do not discard this hunk or any of the remaining "
"ones\n"
"a - discard this hunk and all later hunks in the file\n"
"d - do not discard this hunk or any of the later hunks in "
"the file\n"),
};
static struct patch_mode patch_mode_checkout_nothead = {
.diff_cmd = { "diff-index", "-R", NULL },
.apply_for_checkout = 1,
.apply_check_args = { NULL },
.prompt_mode = {
N_("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
N_("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
N_("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
"will immediately be marked for applying."),
.help_patch_text =
N_("y - apply this hunk to index and worktree\n"
"n - do not apply this hunk to index and worktree\n"
"q - quit; do not apply this hunk or any of the remaining "
"ones\n"
"a - apply this hunk and all later hunks in the file\n"
"d - do not apply this hunk or any of the later hunks in "
"the file\n"),
};
static struct patch_mode patch_mode_worktree_head = {
.diff_cmd = { "diff-index", NULL },
.apply_args = { "-R", NULL },
.apply_check_args = { "-R", NULL },
.is_reverse = 1,
.prompt_mode = {
N_("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
N_("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
N_("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
"will immediately be marked for discarding."),
.help_patch_text =
N_("y - discard this hunk from worktree\n"
"n - do not discard this hunk from worktree\n"
"q - quit; do not discard this hunk or any of the remaining "
"ones\n"
"a - discard this hunk and all later hunks in the file\n"
"d - do not discard this hunk or any of the later hunks in "
"the file\n"),
};
static struct patch_mode patch_mode_worktree_nothead = {
.diff_cmd = { "diff-index", "-R", NULL },
.apply_args = { NULL },
.apply_check_args = { NULL },
.prompt_mode = {
N_("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
N_("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
N_("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
},
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
"will immediately be marked for applying."),
.help_patch_text =
N_("y - apply this hunk to worktree\n"
"n - do not apply this hunk to worktree\n"
"q - quit; do not apply this hunk or any of the remaining "
"ones\n"
"a - apply this hunk and all later hunks in the file\n"
"d - do not apply this hunk or any of the later hunks in "
"the file\n"),
}; };
struct hunk_header { struct hunk_header {
@ -47,6 +249,10 @@ struct add_p_state {
unsigned deleted:1, mode_change:1,binary:1; unsigned deleted:1, mode_change:1,binary:1;
} *file_diff; } *file_diff;
size_t file_diff_nr; size_t file_diff_nr;
/* patch mode */
struct patch_mode *mode;
const char *revision;
}; };
static void err(struct add_p_state *s, const char *fmt, ...) static void err(struct add_p_state *s, const char *fmt, ...)
@ -162,9 +368,18 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
struct hunk *hunk = NULL; struct hunk *hunk = NULL;
int res; int res;
argv_array_pushv(&args, s->mode->diff_cmd);
if (s->revision) {
struct object_id oid;
argv_array_push(&args,
/* could be on an unborn branch */
!strcmp("HEAD", s->revision) &&
get_oid("HEAD", &oid) ?
empty_tree_oid_hex() : s->revision);
}
color_arg_index = args.argc;
/* Use `--no-color` explicitly, just in case `diff.color = always`. */ /* Use `--no-color` explicitly, just in case `diff.color = always`. */
argv_array_pushl(&args, "diff-files", "-p", "--no-color", "--", NULL); argv_array_pushl(&args, "--no-color", "-p", "--", NULL);
color_arg_index = args.argc - 2;
for (i = 0; i < ps->nr; i++) for (i = 0; i < ps->nr; i++)
argv_array_push(&args, ps->items[i].original); argv_array_push(&args, ps->items[i].original);
@ -382,7 +597,10 @@ static void render_hunk(struct add_p_state *s, struct hunk *hunk,
- header->colored_extra_start; - header->colored_extra_start;
} }
new_offset += delta; if (s->mode->is_reverse)
old_offset -= delta;
else
new_offset += delta;
strbuf_addf(out, "@@ -%lu,%lu +%lu,%lu @@", strbuf_addf(out, "@@ -%lu,%lu +%lu,%lu @@",
old_offset, header->old_count, old_offset, header->old_count,
@ -805,11 +1023,10 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
"(context).\n" "(context).\n"
"To remove '%c' lines, delete them.\n" "To remove '%c' lines, delete them.\n"
"Lines starting with %c will be removed.\n"), "Lines starting with %c will be removed.\n"),
'-', '+', comment_line_char); s->mode->is_reverse ? '+' : '-',
strbuf_commented_addf(&s->buf, s->mode->is_reverse ? '-' : '+',
_("If the patch applies cleanly, the edited hunk " comment_line_char);
"will immediately be\n" strbuf_commented_addf(&s->buf, "%s", _(s->mode->edit_hunk_hint));
"marked for staging.\n"));
/* /*
* TRANSLATORS: 'it' refers to the patch mentioned in the previous * TRANSLATORS: 'it' refers to the patch mentioned in the previous
* messages. * messages.
@ -890,7 +1107,8 @@ static int run_apply_check(struct add_p_state *s,
reassemble_patch(s, file_diff, 1, &s->buf); reassemble_patch(s, file_diff, 1, &s->buf);
setup_child_process(s, &cp, setup_child_process(s, &cp,
"apply", "--cached", "--check", NULL); "apply", "--check", NULL);
argv_array_pushv(&cp.args, s->mode->apply_check_args);
if (pipe_command(&cp, s->buf.buf, s->buf.len, NULL, 0, NULL, 0)) if (pipe_command(&cp, s->buf.buf, s->buf.len, NULL, 0, NULL, 0))
return error(_("'git apply --cached' failed")); return error(_("'git apply --cached' failed"));
@ -957,6 +1175,57 @@ static int edit_hunk_loop(struct add_p_state *s,
} }
} }
static int apply_for_checkout(struct add_p_state *s, struct strbuf *diff,
int is_reverse)
{
const char *reverse = is_reverse ? "-R" : NULL;
struct child_process check_index = CHILD_PROCESS_INIT;
struct child_process check_worktree = CHILD_PROCESS_INIT;
struct child_process apply_index = CHILD_PROCESS_INIT;
struct child_process apply_worktree = CHILD_PROCESS_INIT;
int applies_index, applies_worktree;
setup_child_process(s, &check_index,
"apply", "--cached", "--check", reverse, NULL);
applies_index = !pipe_command(&check_index, diff->buf, diff->len,
NULL, 0, NULL, 0);
setup_child_process(s, &check_worktree,
"apply", "--check", reverse, NULL);
applies_worktree = !pipe_command(&check_worktree, diff->buf, diff->len,
NULL, 0, NULL, 0);
if (applies_worktree && applies_index) {
setup_child_process(s, &apply_index,
"apply", "--cached", reverse, NULL);
pipe_command(&apply_index, diff->buf, diff->len,
NULL, 0, NULL, 0);
setup_child_process(s, &apply_worktree,
"apply", reverse, NULL);
pipe_command(&apply_worktree, diff->buf, diff->len,
NULL, 0, NULL, 0);
return 1;
}
if (!applies_index) {
err(s, _("The selected hunks do not apply to the index!"));
if (prompt_yesno(s, _("Apply them to the worktree "
"anyway? ")) > 0) {
setup_child_process(s, &apply_worktree,
"apply", reverse, NULL);
return pipe_command(&apply_worktree, diff->buf,
diff->len, NULL, 0, NULL, 0);
}
err(s, _("Nothing was applied.\n"));
} else
/* As a last resort, show the diff to the user */
fwrite(diff->buf, diff->len, 1, stderr);
return 0;
}
#define SUMMARY_HEADER_WIDTH 20 #define SUMMARY_HEADER_WIDTH 20
#define SUMMARY_LINE_WIDTH 80 #define SUMMARY_LINE_WIDTH 80
static void summarize_hunk(struct add_p_state *s, struct hunk *hunk, static void summarize_hunk(struct add_p_state *s, struct hunk *hunk,
@ -1005,13 +1274,6 @@ static size_t display_hunks(struct add_p_state *s,
return end_index; return end_index;
} }
static const char help_patch_text[] =
N_("y - stage this hunk\n"
"n - do not stage this hunk\n"
"q - quit; do not stage this hunk or any of the remaining ones\n"
"a - stage this and all the remaining hunks\n"
"d - do not stage this hunk nor any of the remaining hunks\n");
static const char help_patch_remainder[] = static const char help_patch_remainder[] =
N_("j - leave this hunk undecided, see next undecided hunk\n" N_("j - leave this hunk undecided, see next undecided hunk\n"
"J - leave this hunk undecided, see next hunk\n" "J - leave this hunk undecided, see next hunk\n"
@ -1097,7 +1359,8 @@ static int patch_update_file(struct add_p_state *s,
(uintmax_t)hunk_index + 1, (uintmax_t)hunk_index + 1,
(uintmax_t)file_diff->hunk_nr); (uintmax_t)file_diff->hunk_nr);
color_fprintf(stdout, s->s.prompt_color, color_fprintf(stdout, s->s.prompt_color,
_(prompt_mode[prompt_mode_type]), s->buf.buf); _(s->mode->prompt_mode[prompt_mode_type]),
s->buf.buf);
fflush(stdout); fflush(stdout);
if (strbuf_getline(&s->answer, stdin) == EOF) if (strbuf_getline(&s->answer, stdin) == EOF)
break; break;
@ -1254,7 +1517,7 @@ soft_increment:
const char *p = _(help_patch_remainder), *eol = p; const char *p = _(help_patch_remainder), *eol = p;
color_fprintf(stdout, s->s.help_color, "%s", color_fprintf(stdout, s->s.help_color, "%s",
_(help_patch_text)); _(s->mode->help_patch_text));
/* /*
* Show only those lines of the remainder that are * Show only those lines of the remainder that are
@ -1288,10 +1551,16 @@ soft_increment:
reassemble_patch(s, file_diff, 0, &s->buf); reassemble_patch(s, file_diff, 0, &s->buf);
discard_index(s->s.r->index); discard_index(s->s.r->index);
setup_child_process(s, &cp, "apply", "--cached", NULL); if (s->mode->apply_for_checkout)
if (pipe_command(&cp, s->buf.buf, s->buf.len, apply_for_checkout(s, &s->buf,
NULL, 0, NULL, 0)) s->mode->is_reverse);
error(_("'git apply --cached' failed")); else {
setup_child_process(s, &cp, "apply", NULL);
argv_array_pushv(&cp.args, s->mode->apply_args);
if (pipe_command(&cp, s->buf.buf, s->buf.len,
NULL, 0, NULL, 0))
error(_("'git apply' failed"));
}
if (!repo_read_index(s->s.r)) if (!repo_read_index(s->s.r))
repo_refresh_and_write_index(s->s.r, REFRESH_QUIET, 0, repo_refresh_and_write_index(s->s.r, REFRESH_QUIET, 0,
1, NULL, NULL, NULL); 1, NULL, NULL, NULL);
@ -1301,7 +1570,8 @@ soft_increment:
return quit; return quit;
} }
int run_add_p(struct repository *r, const struct pathspec *ps) int run_add_p(struct repository *r, enum add_p_mode mode,
const char *revision, const struct pathspec *ps)
{ {
struct add_p_state s = { struct add_p_state s = {
{ r }, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT { r }, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
@ -1310,9 +1580,35 @@ int run_add_p(struct repository *r, const struct pathspec *ps)
init_add_i_state(&s.s, r); init_add_i_state(&s.s, r);
if (mode == ADD_P_STASH)
s.mode = &patch_mode_stash;
else if (mode == ADD_P_RESET) {
if (!revision || !strcmp(revision, "HEAD"))
s.mode = &patch_mode_reset_head;
else
s.mode = &patch_mode_reset_nothead;
} else if (mode == ADD_P_CHECKOUT) {
if (!revision)
s.mode = &patch_mode_checkout_index;
else if (!strcmp(revision, "HEAD"))
s.mode = &patch_mode_checkout_head;
else
s.mode = &patch_mode_checkout_nothead;
} else if (mode == ADD_P_WORKTREE) {
if (!revision)
s.mode = &patch_mode_checkout_index;
else if (!strcmp(revision, "HEAD"))
s.mode = &patch_mode_worktree_head;
else
s.mode = &patch_mode_worktree_nothead;
} else
s.mode = &patch_mode_add;
s.revision = revision;
if (discard_index(r->index) < 0 || repo_read_index(r) < 0 || if (discard_index(r->index) < 0 || repo_read_index(r) < 0 ||
repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1, (!s.mode->index_only &&
NULL, NULL, NULL) < 0 || repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1,
NULL, NULL, NULL) < 0) ||
parse_diff(&s, ps) < 0) { parse_diff(&s, ps) < 0) {
strbuf_release(&s.plain); strbuf_release(&s.plain);
strbuf_release(&s.colored); strbuf_release(&s.colored);

Просмотреть файл

@ -31,6 +31,7 @@ static int take_worktree_changes;
static int add_renormalize; static int add_renormalize;
static int pathspec_file_nul; static int pathspec_file_nul;
static const char *pathspec_from_file; static const char *pathspec_from_file;
static int legacy_stash_p; /* support for the scripted `git stash` */
struct update_callback_data { struct update_callback_data {
int flags; int flags;
@ -196,12 +197,25 @@ int run_add_interactive(const char *revision, const char *patch_mode,
&use_builtin_add_i); &use_builtin_add_i);
if (use_builtin_add_i == 1) { if (use_builtin_add_i == 1) {
enum add_p_mode mode;
if (!patch_mode) if (!patch_mode)
return !!run_add_i(the_repository, pathspec); return !!run_add_i(the_repository, pathspec);
if (strcmp(patch_mode, "--patch"))
die("'%s' not yet supported in the built-in add -p", if (!strcmp(patch_mode, "--patch"))
patch_mode); mode = ADD_P_ADD;
return !!run_add_p(the_repository, pathspec); else if (!strcmp(patch_mode, "--patch=stash"))
mode = ADD_P_STASH;
else if (!strcmp(patch_mode, "--patch=reset"))
mode = ADD_P_RESET;
else if (!strcmp(patch_mode, "--patch=checkout"))
mode = ADD_P_CHECKOUT;
else if (!strcmp(patch_mode, "--patch=worktree"))
mode = ADD_P_WORKTREE;
else
die("'%s' not supported", patch_mode);
return !!run_add_p(the_repository, mode, revision, pathspec);
} }
argv_array_push(&argv, "add--interactive"); argv_array_push(&argv, "add--interactive");
@ -327,6 +341,8 @@ static struct option builtin_add_options[] = {
N_("override the executable bit of the listed files")), N_("override the executable bit of the listed files")),
OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo, OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo,
N_("warn when adding an embedded repository")), N_("warn when adding an embedded repository")),
OPT_HIDDEN_BOOL(0, "legacy-stash-p", &legacy_stash_p,
N_("backend for `git stash -p`")),
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file), OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul), OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
OPT_END(), OPT_END(),
@ -428,6 +444,17 @@ int cmd_add(int argc, const char **argv, const char *prefix)
die(_("--pathspec-from-file is incompatible with --interactive/--patch")); die(_("--pathspec-from-file is incompatible with --interactive/--patch"));
exit(interactive_add(argc - 1, argv + 1, prefix, patch_interactive)); exit(interactive_add(argc - 1, argv + 1, prefix, patch_interactive));
} }
if (legacy_stash_p) {
struct pathspec pathspec;
parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_FULL |
PATHSPEC_SYMLINK_LEADING_PATH |
PATHSPEC_PREFIX_ORIGIN,
prefix, argv);
return run_add_interactive(NULL, "--patch=stash", &pathspec);
}
if (edit_interactive) { if (edit_interactive) {
if (pathspec_from_file) if (pathspec_from_file)

Просмотреть файл

@ -367,7 +367,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
die(_("index file corrupt")); die(_("index file corrupt"));
if (interactive) { if (interactive) {
char *old_index_env = NULL; char *old_index_env = NULL, *old_repo_index_file;
hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR); hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
refresh_cache_or_die(refresh_flags); refresh_cache_or_die(refresh_flags);
@ -375,12 +375,16 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
if (write_locked_index(&the_index, &index_lock, 0)) if (write_locked_index(&the_index, &index_lock, 0))
die(_("unable to create temporary index")); die(_("unable to create temporary index"));
old_repo_index_file = the_repository->index_file;
the_repository->index_file =
(char *)get_lock_file_path(&index_lock);
old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT)); old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT));
setenv(INDEX_ENVIRONMENT, get_lock_file_path(&index_lock), 1); setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1);
if (interactive_add(argc, argv, prefix, patch_interactive) != 0) if (interactive_add(argc, argv, prefix, patch_interactive) != 0)
die(_("interactive add failed")); die(_("interactive add failed"));
the_repository->index_file = old_repo_index_file;
if (old_index_env && *old_index_env) if (old_index_env && *old_index_env)
setenv(INDEX_ENVIRONMENT, old_index_env, 1); setenv(INDEX_ENVIRONMENT, old_index_env, 1);
else else

Просмотреть файл

@ -998,9 +998,9 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
{ {
int ret = 0; int ret = 0;
struct child_process cp_read_tree = CHILD_PROCESS_INIT; struct child_process cp_read_tree = CHILD_PROCESS_INIT;
struct child_process cp_add_i = CHILD_PROCESS_INIT;
struct child_process cp_diff_tree = CHILD_PROCESS_INIT; struct child_process cp_diff_tree = CHILD_PROCESS_INIT;
struct index_state istate = { NULL }; struct index_state istate = { NULL };
char *old_index_env = NULL, *old_repo_index_file;
remove_path(stash_index_path.buf); remove_path(stash_index_path.buf);
@ -1014,16 +1014,19 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
} }
/* Find out what the user wants. */ /* Find out what the user wants. */
cp_add_i.git_cmd = 1; old_repo_index_file = the_repository->index_file;
argv_array_pushl(&cp_add_i.args, "add--interactive", "--patch=stash", the_repository->index_file = stash_index_path.buf;
"--", NULL); old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT));
add_pathspecs(&cp_add_i.args, ps); setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1);
argv_array_pushf(&cp_add_i.env_array, "GIT_INDEX_FILE=%s",
stash_index_path.buf); ret = run_add_interactive(NULL, "--patch=stash", ps);
if (run_command(&cp_add_i)) {
ret = -1; the_repository->index_file = old_repo_index_file;
goto done; if (old_index_env && *old_index_env)
} setenv(INDEX_ENVIRONMENT, old_index_env, 1);
else
unsetenv(INDEX_ENVIRONMENT);
FREE_AND_NULL(old_index_env);
/* State of the working tree. */ /* State of the working tree. */
if (write_index_as_tree(&info->w_tree, &istate, stash_index_path.buf, 0, if (write_index_as_tree(&info->w_tree, &istate, stash_index_path.buf, 0,

Просмотреть файл

@ -207,7 +207,7 @@ create_stash () {
# find out what the user wants # find out what the user wants
GIT_INDEX_FILE="$TMP-index" \ GIT_INDEX_FILE="$TMP-index" \
git add--interactive --patch=stash -- "$@" && git add --legacy-stash-p -- "$@" &&
# state of the working tree # state of the working tree
w_tree=$(GIT_INDEX_FILE="$TMP-index" git write-tree) || w_tree=$(GIT_INDEX_FILE="$TMP-index" git write-tree) ||