@matheusbsbs / matheus-bagliano / commits / cbd8db17ac
Fork 0

rebase -i: support --committer-date-is-author-date

rebase am already has this flag to "lie" about the committer date by changing it to the author date. Let's add the same for interactive machinery. Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Rohit Ashiwal committed Nov 1, 2019 at 19:30 UTC cbd8db17acb77ea646c739bf96c31fe7484bc491
6 files changed +120 -11
Documentation/git-rebase.txt
+7 -3
@@ -386,9 +386,13 @@ unchanged for the sake of a three-way merge.
386 See also INCOMPATIBLE OPTIONS below.
387
388 --committer-date-is-author-date::
389 + Instead of recording the time the rebased commits are
390 + created as the committer date, reuse the author date
391 + as the committer date. This implies --force-rebase.
392 +
393 --ignore-date::
390 - These flags are passed to 'git am' to easily change the dates
391 - of the rebased commits (see linkgit:git-am[1]).
394 + This flag is passed to 'git am' to change the author date
395 + of each rebased commit (see linkgit:git-am[1]).
396 +
397 See also INCOMPATIBLE OPTIONS below.
398
@@ -525,7 +529,6 @@ INCOMPATIBLE OPTIONS
529
530 The following options:
531
528 - * --committer-date-is-author-date
532 * --ignore-date
533 * --whitespace
534 * -C
@@ -551,6 +554,7 @@ In addition, the following pairs of options are incompatible:
554 * --preserve-merges and --signoff
555 * --preserve-merges and --rebase-merges
556 * --preserve-merges and --ignore-whitespace
557 + * --preserve-merges and --committer-date-is-author-date
558 * --rebase-merges and --strategy
559 * --rebase-merges and --strategy-option
560
builtin/rebase.c
+12 -5
@@ -82,6 +82,7 @@ struct rebase_options {
82 int ignore_whitespace;
83 char *gpg_sign_opt;
84 int autostash;
85 + int committer_date_is_author_date;
86 char *cmd;
87 int allow_empty_message;
88 int rebase_merges, rebase_cousins;
@@ -114,6 +115,8 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
115 replay.allow_empty_message = opts->allow_empty_message;
116 replay.verbose = opts->flags & REBASE_VERBOSE;
117 replay.reschedule_failed_exec = opts->reschedule_failed_exec;
118 + replay.committer_date_is_author_date =
119 + opts->committer_date_is_author_date;
120 replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
121 replay.strategy = opts->strategy;
122
@@ -976,6 +979,8 @@ static int run_am(struct rebase_options *opts)
979
980 if (opts->ignore_whitespace)
981 argv_array_push(&am.args, "--ignore-whitespace");
982 + if (opts->committer_date_is_author_date)
983 + argv_array_push(&opts->git_am_opts, "--committer-date-is-author-date");
984 if (opts->action && !strcmp("continue", opts->action)) {
985 argv_array_push(&am.args, "--resolved");
986 argv_array_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
@@ -1424,9 +1429,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
1429 PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
1430 OPT_BOOL(0, "signoff", &options.signoff,
1431 N_("add a Signed-off-by: line to each commit")),
1427 - OPT_PASSTHRU_ARGV(0, "committer-date-is-author-date",
1428 - &options.git_am_opts, NULL,
1429 - N_("passed to 'git am'"), PARSE_OPT_NOARG),
1432 + OPT_BOOL(0, "committer-date-is-author-date",
1433 + &options.committer_date_is_author_date,
1434 + N_("make committer date match author date")),
1435 OPT_PASSTHRU_ARGV(0, "ignore-date", &options.git_am_opts, NULL,
1436 N_("passed to 'git am'"), PARSE_OPT_NOARG),
1437 OPT_PASSTHRU_ARGV('C', NULL, &options.git_am_opts, N_("n"),
@@ -1701,10 +1706,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
1706 state_dir_base, cmd_live_rebase, buf.buf);
1707 }
1708
1709 + if (options.committer_date_is_author_date)
1710 + options.flags |= REBASE_FORCE;
1711 +
1712 for (i = 0; i < options.git_am_opts.argc; i++) {
1713 const char *option = options.git_am_opts.argv[i], *p;
1706 - if (!strcmp(option, "--committer-date-is-author-date") ||
1707 - !strcmp(option, "--ignore-date") ||
1714 + if (!strcmp(option, "--ignore-date") ||
1715 !strcmp(option, "--whitespace=fix") ||
1716 !strcmp(option, "--whitespace=strip"))
1717 options.flags |= REBASE_FORCE;
sequencer.c
+63 -2
@@ -147,6 +147,7 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, "rebase-merge/refs-to-delete")
147 * command-line.
148 */
149 static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt")
150 +static GIT_PATH_FUNC(rebase_path_cdate_is_adate, "rebase-merge/cdate_is_adate")
151 static GIT_PATH_FUNC(rebase_path_orig_head, "rebase-merge/orig-head")
152 static GIT_PATH_FUNC(rebase_path_verbose, "rebase-merge/verbose")
153 static GIT_PATH_FUNC(rebase_path_quiet, "rebase-merge/quiet")
@@ -879,6 +880,17 @@ static char *get_author(const char *message)
880 return NULL;
881 }
882
883 +/* Returns a "date" string that needs to be free()'d by the caller */
884 +static char *read_author_date_or_null(void)
885 +{
886 + char *date;
887 +
888 + if (read_author_script(rebase_path_author_script(),
889 + NULL, NULL, &date, 0))
890 + return NULL;
891 + return date;
892 +}
893 +
894 static const char staged_changes_advice[] =
895 N_("you have staged changes in your working tree\n"
896 "If these changes are meant to be squashed into the previous commit, run:\n"
@@ -938,6 +950,24 @@ static int run_git_commit(struct repository *r,
950
951 cmd.git_cmd = 1;
952
953 + if (opts->committer_date_is_author_date) {
954 + int res = -1;
955 + struct strbuf datebuf = STRBUF_INIT;
956 + char *date = read_author_date_or_null();
957 +
958 + if (!date)
959 + return -1;
960 +
961 + strbuf_addf(&datebuf, "@%s", date);
962 + res = setenv("GIT_COMMITTER_DATE", datebuf.buf, 1);
963 +
964 + strbuf_release(&datebuf);
965 + free(date);
966 +
967 + if (res)
968 + return -1;
969 + }
970 +
971 if (is_rebase_i(opts) && read_env_script(&cmd.env_array)) {
972 const char *gpg_opt = gpg_sign_opt_quoted(opts);
973
@@ -1331,7 +1361,6 @@ static int try_to_commit(struct repository *r,
1361
1362 if (parse_head(r, &current_head))
1363 return -1;
1334 -
1364 if (flags & AMEND_MSG) {
1365 const char *exclude_gpgsig[] = { "gpgsig", NULL };
1366 const char *out_enc = get_commit_output_encoding();
@@ -1359,6 +1388,30 @@ static int try_to_commit(struct repository *r,
1388 commit_list_insert(current_head, &parents);
1389 }
1390
1391 + if (opts->committer_date_is_author_date) {
1392 + int len = strlen(author);
1393 + struct ident_split ident;
1394 + struct strbuf date = STRBUF_INIT;
1395 +
1396 + if (split_ident_line(&ident, author, len) < 0) {
1397 + res = error(_("malformed ident line"));
1398 + goto out;
1399 + }
1400 + if (!ident.date_begin) {
1401 + res = error(_("corrupted author without date information"));
1402 + goto out;
1403 + }
1404 +
1405 + strbuf_addf(&date, "@%.*s %.*s",
1406 + (int)(ident.date_end - ident.date_begin), ident.date_begin,
1407 + (int)(ident.tz_end - ident.tz_begin), ident.tz_begin);
1408 + res = setenv("GIT_COMMITTER_DATE", date.buf, 1);
1409 + strbuf_release(&date);
1410 +
1411 + if (res)
1412 + goto out;
1413 + }
1414 +
1415 if (write_index_as_tree(&tree, r->index, r->index_file, 0, NULL)) {
1416 res = error(_("git write-tree failed to write a tree"));
1417 goto out;
@@ -2480,6 +2533,11 @@ static int read_populate_opts(struct replay_opts *opts)
2533 opts->signoff = 1;
2534 }
2535
2536 + if (file_exists(rebase_path_cdate_is_adate())) {
2537 + opts->allow_ff = 0;
2538 + opts->committer_date_is_author_date = 1;
2539 + }
2540 +
2541 if (file_exists(rebase_path_reschedule_failed_exec()))
2542 opts->reschedule_failed_exec = 1;
2543
@@ -2562,6 +2620,8 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,
2620 write_file(rebase_path_gpg_sign_opt(), "-S%s\n", opts->gpg_sign);
2621 if (opts->signoff)
2622 write_file(rebase_path_signoff(), "--signoff\n");
2623 + if (opts->committer_date_is_author_date)
2624 + write_file(rebase_path_cdate_is_adate(), "%s", "");
2625 if (opts->reschedule_failed_exec)
2626 write_file(rebase_path_reschedule_failed_exec(), "%s", "");
2627
@@ -3650,7 +3710,8 @@ static int pick_commits(struct repository *r,
3710 setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
3711 if (opts->allow_ff)
3712 assert(!(opts->signoff || opts->no_commit ||
3653 - opts->record_origin || opts->edit));
3713 + opts->record_origin || opts->edit ||
3714 + opts->committer_date_is_author_date));
3715 if (read_and_refresh_cache(r, opts))
3716 return -1;
3717
sequencer.h
+1
@@ -43,6 +43,7 @@ struct replay_opts {
43 int verbose;
44 int quiet;
45 int reschedule_failed_exec;
46 + int committer_date_is_author_date;
47
48 int mainline;
49
t/t3422-rebase-incompatible-options.sh
-1
@@ -61,7 +61,6 @@ test_rebase_am_only () {
61 }
62
63 test_rebase_am_only --whitespace=fix
64 -test_rebase_am_only --committer-date-is-author-date
64 test_rebase_am_only -C4
65
66 test_expect_success REBASE_P '--preserve-merges incompatible with --signoff' '
t/t3433-rebase-options-compatibility.sh
+37
@@ -7,6 +7,9 @@ test_description='tests to ensure compatibility between am and interactive backe
7
8 . ./test-lib.sh
9
10 +GIT_AUTHOR_DATE="1999-04-02T08:03:20+05:30"
11 +export GIT_AUTHOR_DATE
12 +
13 # This is a special case in which both am and interactive backends
14 # provide the same output. It was done intentionally because
15 # both the backends fall short of optimal behaviour.
@@ -26,8 +29,13 @@ test_expect_success 'setup' '
29 EOF
30 git commit -am "update file" &&
31 git tag side &&
32 + test_commit commit1 foo foo1 &&
33 + test_commit commit2 foo foo2 &&
34 + test_commit commit3 foo foo3 &&
35
36 git checkout --orphan master &&
37 + git rm --cached foo &&
38 + rm foo &&
39 sed -e "s/^|//" >file <<-\EOF &&
40 |line 1
41 | line 2
@@ -62,4 +70,33 @@ test_expect_success '--ignore-whitespace works with interactive backend' '
70 test_cmp expect file
71 '
72
73 +test_expect_success '--committer-date-is-author-date works with am backend' '
74 + git commit --amend &&
75 + git rebase --committer-date-is-author-date HEAD^ &&
76 + git show HEAD --pretty="format:%ai" >authortime &&
77 + git show HEAD --pretty="format:%ci" >committertime &&
78 + test_cmp authortime committertime
79 +'
80 +
81 +test_expect_success '--committer-date-is-author-date works with interactive backend' '
82 + git commit --amend &&
83 + git rebase -i --committer-date-is-author-date HEAD^ &&
84 + git show HEAD --pretty="format:%ai" >authortime &&
85 + git show HEAD --pretty="format:%ci" >committertime &&
86 + test_cmp authortime committertime
87 +'
88 +
89 +test_expect_success '--committer-date-is-author-date works with rebase -r' '
90 + git checkout side &&
91 + git merge --no-ff commit3 &&
92 + git rebase -r --root --committer-date-is-author-date &&
93 + git rev-list HEAD >rev_list &&
94 + while read HASH
95 + do
96 + git show $HASH --pretty="format:%ai" >authortime
97 + git show $HASH --pretty="format:%ci" >committertime
98 + test_cmp authortime committertime
99 + done <rev_list
100 +'
101 +
102 test_done