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

rebase -i: support --ignore-date

Rebase is implemented with two different backends - 'apply' and 'merge' each of which support a different set of options. In particular the apply backend supports a number of options implemented by 'git am' that are not implemented in the merge backend. This means that the available options are different depending on which backend is used which is confusing. This patch adds support for the --ignore-date option to the merge backend. This option uses the current time as the author date rather than reusing the original author date when rewriting commits. We take care to handle the combination of --ignore-date and --committer-date-is-author-date in the same way as the apply backend. Original-patch-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Phillip Wood committed Aug 17, 2020 at 18:40 UTC a3894aad67df655a9c7f3b511093f681d3a01fb7
5 files changed +123 -20
Documentation/git-rebase.txt
+4 -3
@@ -450,8 +450,9 @@ See also INCOMPATIBLE OPTIONS below.
450 date. This option implies `--force-rebase`.
451
452 --ignore-date::
453 - This flag is passed to 'git am' to change the author date
454 - of each rebased commit (see linkgit:git-am[1]).
453 + Instead of using the author date of the original commit, use
454 + the current time as the author date of the rebased commit. This
455 + option implies `--force-rebase`.
456 +
457 See also INCOMPATIBLE OPTIONS below.
458
@@ -589,7 +590,6 @@ INCOMPATIBLE OPTIONS
590 The following options:
591
592 * --apply
592 - * --ignore-date
593 * --whitespace
594 * -C
595
@@ -617,6 +617,7 @@ In addition, the following pairs of options are incompatible:
617 * --preserve-merges and --empty=
618 * --preserve-merges and --ignore-whitespace
619 * --preserve-merges and --committer-date-is-author-date
620 + * --preserve-merges and --ignore-date
621 * --keep-base and --onto
622 * --keep-base and --root
623
builtin/rebase.c
+8 -5
@@ -89,6 +89,7 @@ struct rebase_options {
89 char *gpg_sign_opt;
90 int autostash;
91 int committer_date_is_author_date;
92 + int ignore_date;
93 char *cmd;
94 int allow_empty_message;
95 int rebase_merges, rebase_cousins;
@@ -127,6 +128,7 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
128 replay.reschedule_failed_exec = opts->reschedule_failed_exec;
129 replay.committer_date_is_author_date =
130 opts->committer_date_is_author_date;
131 + replay.ignore_date = opts->ignore_date;
132 replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
133 replay.strategy = opts->strategy;
134
@@ -1503,8 +1505,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
1505 OPT_BOOL(0, "committer-date-is-author-date",
1506 &options.committer_date_is_author_date,
1507 N_("make committer date match author date")),
1506 - OPT_PASSTHRU_ARGV(0, "ignore-date", &options.git_am_opts, NULL,
1507 - N_("passed to 'git am'"), PARSE_OPT_NOARG),
1508 + OPT_BOOL(0, "ignore-date", &options.ignore_date,
1509 + N_("ignore author date and use current date")),
1510 OPT_PASSTHRU_ARGV('C', NULL, &options.git_am_opts, N_("n"),
1511 N_("passed to 'git apply'"), 0),
1512 OPT_BOOL(0, "ignore-whitespace", &ignore_whitespace,
@@ -1797,13 +1799,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
1799 options.autosquash) {
1800 allow_preemptive_ff = 0;
1801 }
1800 - if (options.committer_date_is_author_date)
1802 + if (options.committer_date_is_author_date || options.ignore_date)
1803 options.flags |= REBASE_FORCE;
1804
1805 for (i = 0; i < options.git_am_opts.argc; i++) {
1806 const char *option = options.git_am_opts.argv[i], *p;
1805 - if (!strcmp(option, "--ignore-date") ||
1806 - !strcmp(option, "--whitespace=fix") ||
1807 + if (!strcmp(option, "--whitespace=fix") ||
1808 !strcmp(option, "--whitespace=strip"))
1809 allow_preemptive_ff = 0;
1810 else if (skip_prefix(option, "-C", &p)) {
@@ -1862,6 +1863,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
1863 if (options.committer_date_is_author_date)
1864 argv_array_push(&options.git_am_opts,
1865 "--committer-date-is-author-date");
1866 + if (options.ignore_date)
1867 + argv_array_push(&options.git_am_opts, "--ignore-date");
1868 } else {
1869 /* REBASE_MERGE and PRESERVE_MERGES */
1870 if (ignore_whitespace) {
sequencer.c
+54 -12
@@ -150,6 +150,7 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, "rebase-merge/refs-to-delete")
150 */
151 static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt")
152 static GIT_PATH_FUNC(rebase_path_cdate_is_adate, "rebase-merge/cdate_is_adate")
153 +static GIT_PATH_FUNC(rebase_path_ignore_date, "rebase-merge/ignore_date")
154 static GIT_PATH_FUNC(rebase_path_orig_head, "rebase-merge/orig-head")
155 static GIT_PATH_FUNC(rebase_path_verbose, "rebase-merge/verbose")
156 static GIT_PATH_FUNC(rebase_path_quiet, "rebase-merge/quiet")
@@ -959,7 +960,11 @@ static int run_git_commit(struct repository *r,
960
961 if (opts->committer_date_is_author_date)
962 argv_array_pushf(&cmd.env_array, "GIT_COMMITTER_DATE=%s",
963 + opts->ignore_date ?
964 + "" :
965 author_date_from_env_array(&cmd.env_array));
966 + if (opts->ignore_date)
967 + argv_array_push(&cmd.env_array, "GIT_AUTHOR_DATE=");
968
969 argv_array_push(&cmd.args, "commit");
970
@@ -1434,26 +1439,51 @@ static int try_to_commit(struct repository *r,
1439 struct ident_split id;
1440 struct strbuf date = STRBUF_INIT;
1441
1437 - if (split_ident_line(&id, author, (int)strlen(author)) < 0) {
1438 - res = error(_("invalid author identity '%s'"), author);
1439 - goto out;
1440 - }
1441 - if (!id.date_begin) {
1442 - res = error(_("corrupt author: missing date information"));
1443 - goto out;
1442 + if (!opts->ignore_date) {
1443 + if (split_ident_line(&id, author, (int)strlen(author)) < 0) {
1444 + res = error(_("invalid author identity '%s'"),
1445 + author);
1446 + goto out;
1447 + }
1448 + if (!id.date_begin) {
1449 + res = error(_(
1450 + "corrupt author: missing date information"));
1451 + goto out;
1452 + }
1453 + strbuf_addf(&date, "@%.*s %.*s",
1454 + (int)(id.date_end - id.date_begin),
1455 + id.date_begin,
1456 + (int)(id.tz_end - id.tz_begin),
1457 + id.tz_begin);
1458 + } else {
1459 + reset_ident_date();
1460 }
1445 - strbuf_addf(&date, "@%.*s %.*s",
1446 - (int)(id.date_end - id.date_begin), id.date_begin,
1447 - (int)(id.tz_end - id.tz_begin), id.tz_begin);
1461 committer = fmt_ident(opts->committer_name,
1462 opts->committer_email,
1450 - WANT_COMMITTER_IDENT, date.buf,
1463 + WANT_COMMITTER_IDENT,
1464 + opts->ignore_date ? NULL : date.buf,
1465 IDENT_STRICT);
1466 strbuf_release(&date);
1467 } else {
1468 reset_ident_date();
1469 }
1470
1471 + if (opts->ignore_date) {
1472 + struct ident_split id;
1473 + char *name, *email;
1474 +
1475 + if (split_ident_line(&id, author, strlen(author)) < 0) {
1476 + error(_("invalid author identity '%s'"), author);
1477 + goto out;
1478 + }
1479 + name = xmemdupz(id.name_begin, id.name_end - id.name_begin);
1480 + email = xmemdupz(id.mail_begin, id.mail_end - id.mail_begin);
1481 + author = fmt_ident(name, email, WANT_AUTHOR_IDENT, NULL,
1482 + IDENT_STRICT);
1483 + free(name);
1484 + free(email);
1485 + }
1486 +
1487 if (commit_tree_extended(msg->buf, msg->len, &tree, parents, oid,
1488 author, committer, opts->gpg_sign, extra)) {
1489 res = error(_("failed to write commit object"));
@@ -2583,6 +2613,11 @@ static int read_populate_opts(struct replay_opts *opts)
2613 opts->committer_date_is_author_date = 1;
2614 }
2615
2616 + if (file_exists(rebase_path_ignore_date())) {
2617 + opts->allow_ff = 0;
2618 + opts->ignore_date = 1;
2619 + }
2620 +
2621 if (file_exists(rebase_path_reschedule_failed_exec()))
2622 opts->reschedule_failed_exec = 1;
2623
@@ -2675,6 +2710,8 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,
2710 write_file(rebase_path_keep_redundant_commits(), "%s", "");
2711 if (opts->committer_date_is_author_date)
2712 write_file(rebase_path_cdate_is_adate(), "%s", "");
2713 + if (opts->ignore_date)
2714 + write_file(rebase_path_ignore_date(), "%s", "");
2715 if (opts->reschedule_failed_exec)
2716 write_file(rebase_path_reschedule_failed_exec(), "%s", "");
2717
@@ -3597,7 +3634,11 @@ static int do_merge(struct repository *r,
3634
3635 if (opts->committer_date_is_author_date)
3636 argv_array_pushf(&cmd.env_array, "GIT_COMMITTER_DATE=%s",
3637 + opts->ignore_date ?
3638 + "" :
3639 author_date_from_env_array(&cmd.env_array));
3640 + if (opts->ignore_date)
3641 + argv_array_push(&cmd.env_array, "GIT_AUTHOR_DATE=");
3642
3643 cmd.git_cmd = 1;
3644 argv_array_push(&cmd.args, "merge");
@@ -3877,7 +3918,8 @@ static int pick_commits(struct repository *r,
3918 if (opts->allow_ff)
3919 assert(!(opts->signoff || opts->no_commit ||
3920 opts->record_origin || opts->edit ||
3880 - opts->committer_date_is_author_date));
3921 + opts->committer_date_is_author_date ||
3922 + opts->ignore_date));
3923 if (read_and_refresh_cache(r, opts))
3924 return -1;
3925
sequencer.h
+1
@@ -46,6 +46,7 @@ struct replay_opts {
46 int quiet;
47 int reschedule_failed_exec;
48 int committer_date_is_author_date;
49 + int ignore_date;
50
51 int mainline;
52
t/t3436-rebase-more-options.sh
+56
@@ -108,6 +108,62 @@ test_expect_success '--committer-date-is-author-date works when committing confl
108 test_ctime_is_atime -1
109 '
110
111 +# Checking for +0000 in the author date is sufficient since the
112 +# default timezone is UTC but the timezone used while committing is
113 +# +0530. The inverted logic in the grep is necessary to check all the
114 +# author dates in the file.
115 +test_atime_is_ignored () {
116 + git log $1 --format=%ai >authortime &&
117 + ! grep -v +0000 authortime
118 +}
119 +
120 +test_expect_success '--ignore-date works with apply backend' '
121 + git commit --amend --date="$GIT_AUTHOR_DATE" &&
122 + git rebase --apply --ignore-date HEAD^ &&
123 + test_atime_is_ignored -1
124 +'
125 +
126 +test_expect_success '--ignore-date works with merge backend' '
127 + git commit --amend --date="$GIT_AUTHOR_DATE" &&
128 + git rebase --ignore-date -m HEAD^ &&
129 + test_atime_is_ignored -1
130 +'
131 +
132 +test_expect_success '--ignore-date works after conflict resolution' '
133 + test_must_fail git rebase --ignore-date -m \
134 + --onto commit2^^ commit2^ commit2 &&
135 + echo resolved >foo &&
136 + git add foo &&
137 + git rebase --continue &&
138 + test_atime_is_ignored -1
139 +'
140 +
141 +test_expect_success '--ignore-date works with rebase -r' '
142 + git checkout side &&
143 + git merge --no-ff commit3 &&
144 + git rebase -r --root --ignore-date &&
145 + test_atime_is_ignored
146 +'
147 +
148 +test_expect_success '--ignore-date with --committer-date-is-author-date works' '
149 + test_must_fail git rebase -m --committer-date-is-author-date \
150 + --ignore-date --onto commit2^^ commit2^ commit3 &&
151 + git checkout --theirs foo &&
152 + git add foo &&
153 + git rebase --continue &&
154 + test_ctime_is_atime -2 &&
155 + test_atime_is_ignored -2
156 +'
157 +
158 +test_expect_success '--ignore-date --committer-date-is-author-date works when forking merge' '
159 + GIT_SEQUENCE_EDITOR="echo \"merge -C $(git rev-parse HEAD) commit3\">" \
160 + PATH="./test-bin:$PATH" git rebase -i --strategy=test \
161 + --ignore-date --committer-date-is-author-date \
162 + side side &&
163 + test_ctime_is_atime -1 &&
164 + test_atime_is_ignored -1
165 + '
166 +
167 # This must be the last test in this file
168 test_expect_success '$EDITOR and friends are unchanged' '
169 test_editor_unchanged