OK here is a less constroversal attempt to add new trailers. Instead of changing the default behavior (which could be done incrementally later), this patch simply adds a new option --append-trailer to revert and cherry-pick. Both will show either Reverts: <commit>[~<num>] or Cherry-picked-from: <commit>[~<num>] --append-trailer could be added to more commands (e.g. merge) that generate commit messages if they have something for machine consumption. After this, perhaps we could have a config key to turn this on by default (for revert; for cherry-pick it will turn off "-x" too). Then after a couple releases, the we got good reception, we'll make it default? No tests, no proper commit message since I think we're still going to discuss a bit more before settling down. PS. maybe --append-trailer is too generic? We have --signoff which is also a trailer. But that one carries more weights than just "machine generated tags". Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- Documentation/git-cherry-pick.txt | 6 +++++ Documentation/git-revert.txt | 6 +++++ builtin/revert.c | 7 ++++++ sequencer.c | 39 +++++++++++++++++++++++++++---- sequencer.h | 1 + 5 files changed, 55 insertions(+), 4 deletions(-) diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt index d35d771fc8..b5dff29ead 100644 --- a/Documentation/git-cherry-pick.txt +++ b/Documentation/git-cherry-pick.txt @@ -102,6 +102,12 @@ effect to your index in a row. Add Signed-off-by line at the end of the commit message. See the signoff option in linkgit:git-commit[1] for more information. +--append-trailer:: + When recording a commit, append a "Cherry-picked-from:" line + with object name of the cherry-picked commit. If a merge is + cherry-picked with `-m`, the extended SHA-1 syntax is used + to indicate the side of the merge to be cherry-picked. + -S[<keyid>]:: --gpg-sign[=<keyid>]:: GPG-sign commits. The `keyid` argument is optional and diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt index 837707a8fd..e08010b200 100644 --- a/Documentation/git-revert.txt +++ b/Documentation/git-revert.txt @@ -91,6 +91,12 @@ effect to your index in a row. Add Signed-off-by line at the end of the commit message. See the signoff option in linkgit:git-commit[1] for more information. +--append-trailer:: + When recording a commit, append a "Cherry-picked-from:" line + with object name of the cherry-picked commit. If a merge is + cherry-picked with `-m`, the extended SHA-1 syntax is used + to indicate the side of the merge to be cherry-picked. + --strategy=<strategy>:: Use the given merge strategy. Should only be used once. See the MERGE STRATEGIES section in linkgit:git-merge[1] diff --git a/builtin/revert.c b/builtin/revert.c index c93393c89b..3bd8f57b90 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -119,6 +119,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts) if (opts->action == REPLAY_PICK) { struct option cp_extra[] = { OPT_BOOL('x', NULL, &opts->record_origin, N_("append commit name")), + OPT_BOOL(0, "append-trailer", &opts->append_trailer, N_("record cherry picked commit as trailer")), OPT_BOOL(0, "ff", &opts->allow_ff, N_("allow fast-forward")), OPT_BOOL(0, "allow-empty", &opts->allow_empty, N_("preserve initially empty commits")), OPT_BOOL(0, "allow-empty-message", &opts->allow_empty_message, N_("allow commits with empty messages")), @@ -126,6 +127,12 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts) OPT_END(), }; options = parse_options_concat(options, cp_extra); + } else if (opts->action == REPLAY_REVERT) { + struct option cp_extra[] = { + OPT_BOOL(0, "append-trailer", &opts->append_trailer, N_("record reverted commit as trailer")), + OPT_END(), + }; + options = parse_options_concat(options, cp_extra); } argc = parse_options(argc, argv, NULL, options, usage_str, diff --git a/sequencer.c b/sequencer.c index 9e1ab3a2a7..e8fa307109 100644 --- a/sequencer.c +++ b/sequencer.c @@ -911,7 +911,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, if ((flags & EDIT_MSG)) argv_array_push(&cmd.args, "-e"); else if (!(flags & CLEANUP_MSG) && - !opts->signoff && !opts->record_origin && + !opts->signoff && !opts->record_origin && !opts->append_trailer && git_config_get_value("commit.cleanup", &value)) argv_array_push(&cmd.args, "--cleanup=verbatim"); @@ -1669,7 +1669,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, char *author = NULL; struct commit_message msg = { NULL, NULL, NULL, NULL }; struct strbuf msgbuf = STRBUF_INIT; - int res, unborn = 0, allow; + int res, unborn = 0, allow, parent_id = -1; if (opts->no_commit) { /* @@ -1716,6 +1716,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, return error(_("commit %s does not have parent %d"), oid_to_hex(&commit->object.oid), opts->mainline); parent = p->item; + parent_id = cnt; } else if (0 < opts->mainline) return error(_("mainline was specified but commit %s is not a merge."), oid_to_hex(&commit->object.oid)); @@ -1768,6 +1769,17 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, strbuf_addstr(&msgbuf, oid_to_hex(&parent->object.oid)); } strbuf_addstr(&msgbuf, ".\n"); + + if (opts->append_trailer) { + strbuf_addstr(&msgbuf, "\n"); + if (parent_id != -1) + strbuf_addf(&msgbuf, "Reverts: %s~%d\n", + oid_to_hex(&commit->object.oid), + parent_id); + else + strbuf_addf(&msgbuf, "Reverts: %s\n", + oid_to_hex(&commit->object.oid)); + } } else { const char *p; @@ -1780,14 +1792,28 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, if (find_commit_subject(msg.message, &p)) strbuf_addstr(&msgbuf, p); - if (opts->record_origin) { + if (opts->record_origin || opts->append_trailer) { strbuf_complete_line(&msgbuf); if (!has_conforming_footer(&msgbuf, NULL, 0)) strbuf_addch(&msgbuf, '\n'); + } + + if (opts->record_origin) { strbuf_addstr(&msgbuf, cherry_picked_prefix); strbuf_addstr(&msgbuf, oid_to_hex(&commit->object.oid)); strbuf_addstr(&msgbuf, ")\n"); } + if (opts->append_trailer) { + if (opts->record_origin) + strbuf_addstr(&msgbuf, "\n"); + if (parent_id != -1) + strbuf_addf(&msgbuf, "Cherry-picked-from: %s~%d\n", + oid_to_hex(&commit->object.oid), + parent_id); + else + strbuf_addf(&msgbuf, "Cherry-picked-from: %s\n", + oid_to_hex(&commit->object.oid)); + } if (!is_fixup(command)) author = get_author(msg.message); } @@ -2227,6 +2253,8 @@ static int populate_opts_cb(const char *key, const char *value, void *data) opts->signoff = git_config_bool_or_int(key, value, &error_flag); else if (!strcmp(key, "options.record-origin")) opts->record_origin = git_config_bool_or_int(key, value, &error_flag); + else if (!strcmp(key, "options.append-trailer")) + opts->append_trailer = git_config_bool_or_int(key, value, &error_flag); else if (!strcmp(key, "options.allow-ff")) opts->allow_ff = git_config_bool_or_int(key, value, &error_flag); else if (!strcmp(key, "options.mainline")) @@ -2618,6 +2646,8 @@ static int save_opts(struct replay_opts *opts) res |= git_config_set_in_file_gently(opts_file, "options.signoff", "true"); if (opts->record_origin) res |= git_config_set_in_file_gently(opts_file, "options.record-origin", "true"); + if (opts->append_trailer) + res |= git_config_set_in_file_gently(opts_file, "options.append-trailer", "true"); if (opts->allow_ff) res |= git_config_set_in_file_gently(opts_file, "options.allow-ff", "true"); if (opts->mainline) { @@ -3432,7 +3462,8 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts) setenv(GIT_REFLOG_ACTION, action_name(opts), 0); if (opts->allow_ff) assert(!(opts->signoff || opts->no_commit || - opts->record_origin || opts->edit)); + opts->record_origin || opts->append_trailer || + opts->edit)); if (read_and_refresh_cache(opts)) return -1; diff --git a/sequencer.h b/sequencer.h index 660cff5050..7d7c1fe6b4 100644 --- a/sequencer.h +++ b/sequencer.h @@ -31,6 +31,7 @@ struct replay_opts { /* Boolean options */ int edit; int record_origin; + int append_trailer; int no_commit; int signoff; int allow_ff; -- 2.19.1.1005.gac84295441