Skip to content

Commit 7ff2683

Browse files
pyokagangitster
authored andcommitted
builtin-am: implement -i/--interactive
Since d1c5f2a (Add git-am, applymbox replacement., 2005-10-07), git-am.sh supported the --interactive mode. After parsing the patch mail and extracting the patch, commit message and authorship info, an interactive session will begin that allows the user to choose between: * applying the patch * applying the patch and all subsequent patches (by disabling interactive mode in subsequent patches) * skipping the patch * editing the commit message Since f89ad67 (Add [v]iew patch in git-am interactive., 2005-10-25), git-am.sh --interactive also supported viewing the patch to be applied. When --resolved-ing in --interactive mode, we need to take care to update the patch with the contents of the index, such that the correct patch will be displayed when the patch is viewed in interactive mode. Re-implement the above in builtin/am.c Signed-off-by: Paul Tan <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 94cd175 commit 7ff2683

File tree

1 file changed

+104
-1
lines changed

1 file changed

+104
-1
lines changed

builtin/am.c

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "log-tree.h"
2626
#include "notes-utils.h"
2727
#include "rerere.h"
28+
#include "prompt.h"
2829

2930
/**
3031
* Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -119,6 +120,7 @@ struct am_state {
119120
int prec;
120121

121122
/* various operating modes and command line options */
123+
int interactive;
122124
int threeway;
123125
int quiet;
124126
int signoff;
@@ -1171,7 +1173,7 @@ static void NORETURN die_user_resolve(const struct am_state *state)
11711173
if (state->resolvemsg) {
11721174
printf_ln("%s", state->resolvemsg);
11731175
} else {
1174-
const char *cmdline = "git am";
1176+
const char *cmdline = state->interactive ? "git am -i" : "git am";
11751177

11761178
printf_ln(_("When you have resolved this problem, run \"%s --continue\"."), cmdline);
11771179
printf_ln(_("If you prefer to skip this patch, run \"%s --skip\" instead."), cmdline);
@@ -1403,6 +1405,36 @@ static void write_commit_patch(const struct am_state *state, struct commit *comm
14031405
log_tree_commit(&rev_info, commit);
14041406
}
14051407

1408+
/**
1409+
* Writes the diff of the index against HEAD as a patch to the state
1410+
* directory's "patch" file.
1411+
*/
1412+
static void write_index_patch(const struct am_state *state)
1413+
{
1414+
struct tree *tree;
1415+
unsigned char head[GIT_SHA1_RAWSZ];
1416+
struct rev_info rev_info;
1417+
FILE *fp;
1418+
1419+
if (!get_sha1_tree("HEAD", head))
1420+
tree = lookup_tree(head);
1421+
else
1422+
tree = lookup_tree(EMPTY_TREE_SHA1_BIN);
1423+
1424+
fp = xfopen(am_path(state, "patch"), "w");
1425+
init_revisions(&rev_info, NULL);
1426+
rev_info.diff = 1;
1427+
rev_info.disable_stdin = 1;
1428+
rev_info.no_commit_id = 1;
1429+
rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;
1430+
rev_info.diffopt.use_color = 0;
1431+
rev_info.diffopt.file = fp;
1432+
rev_info.diffopt.close_file = 1;
1433+
add_pending_object(&rev_info, &tree->object, "");
1434+
diff_setup_done(&rev_info.diffopt);
1435+
run_diff_index(&rev_info, 1);
1436+
}
1437+
14061438
/**
14071439
* Like parse_mail(), but parses the mail by looking up its commit ID
14081440
* directly. This is used in --rebasing mode to bypass git-mailinfo's munging
@@ -1654,6 +1686,65 @@ static void validate_resume_state(const struct am_state *state)
16541686
am_path(state, "author-script"));
16551687
}
16561688

1689+
/**
1690+
* Interactively prompt the user on whether the current patch should be
1691+
* applied.
1692+
*
1693+
* Returns 0 if the user chooses to apply the patch, 1 if the user chooses to
1694+
* skip it.
1695+
*/
1696+
static int do_interactive(struct am_state *state)
1697+
{
1698+
assert(state->msg);
1699+
1700+
if (!isatty(0))
1701+
die(_("cannot be interactive without stdin connected to a terminal."));
1702+
1703+
for (;;) {
1704+
const char *reply;
1705+
1706+
puts(_("Commit Body is:"));
1707+
puts("--------------------------");
1708+
printf("%s", state->msg);
1709+
puts("--------------------------");
1710+
1711+
/*
1712+
* TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]
1713+
* in your translation. The program will only accept English
1714+
* input at this point.
1715+
*/
1716+
reply = git_prompt(_("Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: "), PROMPT_ECHO);
1717+
1718+
if (!reply) {
1719+
continue;
1720+
} else if (*reply == 'y' || *reply == 'Y') {
1721+
return 0;
1722+
} else if (*reply == 'a' || *reply == 'A') {
1723+
state->interactive = 0;
1724+
return 0;
1725+
} else if (*reply == 'n' || *reply == 'N') {
1726+
return 1;
1727+
} else if (*reply == 'e' || *reply == 'E') {
1728+
struct strbuf msg = STRBUF_INIT;
1729+
1730+
if (!launch_editor(am_path(state, "final-commit"), &msg, NULL)) {
1731+
free(state->msg);
1732+
state->msg = strbuf_detach(&msg, &state->msg_len);
1733+
}
1734+
strbuf_release(&msg);
1735+
} else if (*reply == 'v' || *reply == 'V') {
1736+
const char *pager = git_pager(1);
1737+
struct child_process cp = CHILD_PROCESS_INIT;
1738+
1739+
if (!pager)
1740+
pager = "cat";
1741+
argv_array_push(&cp.args, pager);
1742+
argv_array_push(&cp.args, am_path(state, "patch"));
1743+
run_command(&cp);
1744+
}
1745+
}
1746+
}
1747+
16571748
/**
16581749
* Applies all queued mail.
16591750
*
@@ -1702,6 +1793,9 @@ static void am_run(struct am_state *state, int resume)
17021793
write_commit_msg(state);
17031794
}
17041795

1796+
if (state->interactive && do_interactive(state))
1797+
goto next;
1798+
17051799
if (run_applypatch_msg_hook(state))
17061800
exit(1);
17071801

@@ -1787,10 +1881,17 @@ static void am_resolve(struct am_state *state)
17871881
die_user_resolve(state);
17881882
}
17891883

1884+
if (state->interactive) {
1885+
write_index_patch(state);
1886+
if (do_interactive(state))
1887+
goto next;
1888+
}
1889+
17901890
rerere(0);
17911891

17921892
do_commit(state);
17931893

1894+
next:
17941895
am_next(state);
17951896
am_run(state, 0);
17961897
}
@@ -2036,6 +2137,8 @@ int cmd_am(int argc, const char **argv, const char *prefix)
20362137
};
20372138

20382139
struct option options[] = {
2140+
OPT_BOOL('i', "interactive", &state.interactive,
2141+
N_("run interactively")),
20392142
OPT_BOOL('3', "3way", &state.threeway,
20402143
N_("allow fall back on 3way merging if needed")),
20412144
OPT__QUIET(&state.quiet, N_("be quiet")),

0 commit comments

Comments
 (0)