|
25 | 25 | #include "log-tree.h"
|
26 | 26 | #include "notes-utils.h"
|
27 | 27 | #include "rerere.h"
|
| 28 | +#include "prompt.h" |
28 | 29 |
|
29 | 30 | /**
|
30 | 31 | * Returns 1 if the file is empty or does not exist, 0 otherwise.
|
@@ -119,6 +120,7 @@ struct am_state {
|
119 | 120 | int prec;
|
120 | 121 |
|
121 | 122 | /* various operating modes and command line options */
|
| 123 | + int interactive; |
122 | 124 | int threeway;
|
123 | 125 | int quiet;
|
124 | 126 | int signoff;
|
@@ -1171,7 +1173,7 @@ static void NORETURN die_user_resolve(const struct am_state *state)
|
1171 | 1173 | if (state->resolvemsg) {
|
1172 | 1174 | printf_ln("%s", state->resolvemsg);
|
1173 | 1175 | } else {
|
1174 |
| - const char *cmdline = "git am"; |
| 1176 | + const char *cmdline = state->interactive ? "git am -i" : "git am"; |
1175 | 1177 |
|
1176 | 1178 | printf_ln(_("When you have resolved this problem, run \"%s --continue\"."), cmdline);
|
1177 | 1179 | 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
|
1403 | 1405 | log_tree_commit(&rev_info, commit);
|
1404 | 1406 | }
|
1405 | 1407 |
|
| 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 | + |
1406 | 1438 | /**
|
1407 | 1439 | * Like parse_mail(), but parses the mail by looking up its commit ID
|
1408 | 1440 | * 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)
|
1654 | 1686 | am_path(state, "author-script"));
|
1655 | 1687 | }
|
1656 | 1688 |
|
| 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 | + |
1657 | 1748 | /**
|
1658 | 1749 | * Applies all queued mail.
|
1659 | 1750 | *
|
@@ -1702,6 +1793,9 @@ static void am_run(struct am_state *state, int resume)
|
1702 | 1793 | write_commit_msg(state);
|
1703 | 1794 | }
|
1704 | 1795 |
|
| 1796 | + if (state->interactive && do_interactive(state)) |
| 1797 | + goto next; |
| 1798 | + |
1705 | 1799 | if (run_applypatch_msg_hook(state))
|
1706 | 1800 | exit(1);
|
1707 | 1801 |
|
@@ -1787,10 +1881,17 @@ static void am_resolve(struct am_state *state)
|
1787 | 1881 | die_user_resolve(state);
|
1788 | 1882 | }
|
1789 | 1883 |
|
| 1884 | + if (state->interactive) { |
| 1885 | + write_index_patch(state); |
| 1886 | + if (do_interactive(state)) |
| 1887 | + goto next; |
| 1888 | + } |
| 1889 | + |
1790 | 1890 | rerere(0);
|
1791 | 1891 |
|
1792 | 1892 | do_commit(state);
|
1793 | 1893 |
|
| 1894 | +next: |
1794 | 1895 | am_next(state);
|
1795 | 1896 | am_run(state, 0);
|
1796 | 1897 | }
|
@@ -2036,6 +2137,8 @@ int cmd_am(int argc, const char **argv, const char *prefix)
|
2036 | 2137 | };
|
2037 | 2138 |
|
2038 | 2139 | struct option options[] = {
|
| 2140 | + OPT_BOOL('i', "interactive", &state.interactive, |
| 2141 | + N_("run interactively")), |
2039 | 2142 | OPT_BOOL('3', "3way", &state.threeway,
|
2040 | 2143 | N_("allow fall back on 3way merging if needed")),
|
2041 | 2144 | OPT__QUIET(&state.quiet, N_("be quiet")),
|
|
0 commit comments