Skip to content

Commit

Permalink
rebase -i: support --committer-date-is-author-date
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
r1walz authored and gitster committed Sep 9, 2019
1 parent 7c5b2e1 commit ccafcb3
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 11 deletions.
10 changes: 7 additions & 3 deletions Documentation/git-rebase.txt
Expand Up @@ -386,9 +386,13 @@ unchanged for the sake of a three-way merge.
See also INCOMPATIBLE OPTIONS below.

--committer-date-is-author-date::
Instead of recording the time the rebased commits are
created as the committer date, reuse the author date
as the committer date. This implies --force-rebase.

--ignore-date::
These flags are passed to 'git am' to easily change the dates
of the rebased commits (see linkgit:git-am[1]).
This flag is passed to 'git am' to change the author date
of each rebased commit (see linkgit:git-am[1]).
+
See also INCOMPATIBLE OPTIONS below.

Expand Down Expand Up @@ -525,7 +529,6 @@ INCOMPATIBLE OPTIONS

The following options:

* --committer-date-is-author-date
* --ignore-date
* --whitespace
* -C
Expand All @@ -551,6 +554,7 @@ In addition, the following pairs of options are incompatible:
* --preserve-merges and --signoff
* --preserve-merges and --rebase-merges
* --preserve-merges and --ignore-whitespace
* --preserve-merges and --committer-date-is-author-date
* --rebase-merges and --ignore-whitespace
* --rebase-merges and --strategy
* --rebase-merges and --strategy-option
Expand Down
17 changes: 12 additions & 5 deletions builtin/rebase.c
Expand Up @@ -82,6 +82,7 @@ struct rebase_options {
int ignore_whitespace;
char *gpg_sign_opt;
int autostash;
int committer_date_is_author_date;
char *cmd;
int allow_empty_message;
int rebase_merges, rebase_cousins;
Expand Down Expand Up @@ -114,6 +115,8 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
replay.allow_empty_message = opts->allow_empty_message;
replay.verbose = opts->flags & REBASE_VERBOSE;
replay.reschedule_failed_exec = opts->reschedule_failed_exec;
replay.committer_date_is_author_date =
opts->committer_date_is_author_date;
replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
replay.strategy = opts->strategy;

Expand Down Expand Up @@ -976,6 +979,8 @@ static int run_am(struct rebase_options *opts)

if (opts->ignore_whitespace)
argv_array_push(&am.args, "--ignore-whitespace");
if (opts->committer_date_is_author_date)
argv_array_push(&opts->git_am_opts, "--committer-date-is-author-date");
if (opts->action && !strcmp("continue", opts->action)) {
argv_array_push(&am.args, "--resolved");
argv_array_pushf(&am.args, "--resolvemsg=%s", resolvemsg);
Expand Down Expand Up @@ -1424,9 +1429,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
OPT_BOOL(0, "signoff", &options.signoff,
N_("add a Signed-off-by: line to each commit")),
OPT_PASSTHRU_ARGV(0, "committer-date-is-author-date",
&options.git_am_opts, NULL,
N_("passed to 'git am'"), PARSE_OPT_NOARG),
OPT_BOOL(0, "committer-date-is-author-date",
&options.committer_date_is_author_date,
N_("make committer date match author date")),
OPT_PASSTHRU_ARGV(0, "ignore-date", &options.git_am_opts, NULL,
N_("passed to 'git am'"), PARSE_OPT_NOARG),
OPT_PASSTHRU_ARGV('C', NULL, &options.git_am_opts, N_("n"),
Expand Down Expand Up @@ -1701,10 +1706,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
state_dir_base, cmd_live_rebase, buf.buf);
}

if (options.committer_date_is_author_date)
options.flags |= REBASE_FORCE;

for (i = 0; i < options.git_am_opts.argc; i++) {
const char *option = options.git_am_opts.argv[i], *p;
if (!strcmp(option, "--committer-date-is-author-date") ||
!strcmp(option, "--ignore-date") ||
if (!strcmp(option, "--ignore-date") ||
!strcmp(option, "--whitespace=fix") ||
!strcmp(option, "--whitespace=strip"))
options.flags |= REBASE_FORCE;
Expand Down
61 changes: 59 additions & 2 deletions sequencer.c
Expand Up @@ -147,6 +147,7 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, "rebase-merge/refs-to-delete")
* command-line.
*/
static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt")
static GIT_PATH_FUNC(rebase_path_cdate_is_adate, "rebase-merge/cdate_is_adate")
static GIT_PATH_FUNC(rebase_path_orig_head, "rebase-merge/orig-head")
static GIT_PATH_FUNC(rebase_path_verbose, "rebase-merge/verbose")
static GIT_PATH_FUNC(rebase_path_quiet, "rebase-merge/quiet")
Expand Down Expand Up @@ -879,6 +880,17 @@ static char *get_author(const char *message)
return NULL;
}

/* Returns a "date" string that needs to be free()'d by the caller */
static char *read_author_date_or_null(void)
{
char *date;

if (read_author_script(rebase_path_author_script(),
NULL, NULL, &date, 0))
return NULL;
return date;
}

static const char staged_changes_advice[] =
N_("you have staged changes in your working tree\n"
"If these changes are meant to be squashed into the previous commit, run:\n"
Expand Down Expand Up @@ -938,6 +950,24 @@ static int run_git_commit(struct repository *r,

cmd.git_cmd = 1;

if (opts->committer_date_is_author_date) {
int res = -1;
struct strbuf datebuf = STRBUF_INIT;
char *date = read_author_date_or_null();

if (!date)
return -1;

strbuf_addf(&datebuf, "@%s", date);
res = setenv("GIT_COMMITTER_DATE", datebuf.buf, 1);

strbuf_release(&datebuf);
free(date);

if (res)
return -1;
}

if (is_rebase_i(opts) && read_env_script(&cmd.env_array)) {
const char *gpg_opt = gpg_sign_opt_quoted(opts);

Expand Down Expand Up @@ -1331,7 +1361,6 @@ static int try_to_commit(struct repository *r,

if (parse_head(r, &current_head))
return -1;

if (flags & AMEND_MSG) {
const char *exclude_gpgsig[] = { "gpgsig", NULL };
const char *out_enc = get_commit_output_encoding();
Expand Down Expand Up @@ -1359,6 +1388,26 @@ static int try_to_commit(struct repository *r,
commit_list_insert(current_head, &parents);
}

if (opts->committer_date_is_author_date) {
int len = strlen(author);
struct ident_split ident;
struct strbuf date = STRBUF_INIT;

if (split_ident_line(&ident, author, len) < 0)
return error(_("malformed ident line"));
if (!ident.date_begin)
return error(_("corrupted author without date information"));

strbuf_addf(&date, "@%.*s %.*s",
(int)(ident.date_end - ident.date_begin), ident.date_begin,
(int)(ident.tz_end - ident.tz_begin), ident.tz_begin);
res = setenv("GIT_COMMITTER_DATE", date.buf, 1);
strbuf_release(&date);

if (res)
goto out;
}

if (write_index_as_tree(&tree, r->index, r->index_file, 0, NULL)) {
res = error(_("git write-tree failed to write a tree"));
goto out;
Expand Down Expand Up @@ -2480,6 +2529,11 @@ static int read_populate_opts(struct replay_opts *opts)
opts->signoff = 1;
}

if (file_exists(rebase_path_cdate_is_adate())) {
opts->allow_ff = 0;
opts->committer_date_is_author_date = 1;
}

if (file_exists(rebase_path_reschedule_failed_exec()))
opts->reschedule_failed_exec = 1;

Expand Down Expand Up @@ -2562,6 +2616,8 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,
write_file(rebase_path_gpg_sign_opt(), "-S%s\n", opts->gpg_sign);
if (opts->signoff)
write_file(rebase_path_signoff(), "--signoff\n");
if (opts->committer_date_is_author_date)
write_file(rebase_path_cdate_is_adate(), "%s", "");
if (opts->reschedule_failed_exec)
write_file(rebase_path_reschedule_failed_exec(), "%s", "");

Expand Down Expand Up @@ -3650,7 +3706,8 @@ static int pick_commits(struct repository *r,
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->edit ||
opts->committer_date_is_author_date));
if (read_and_refresh_cache(r, opts))
return -1;

Expand Down
1 change: 1 addition & 0 deletions sequencer.h
Expand Up @@ -43,6 +43,7 @@ struct replay_opts {
int verbose;
int quiet;
int reschedule_failed_exec;
int committer_date_is_author_date;

int mainline;

Expand Down
1 change: 0 additions & 1 deletion t/t3422-rebase-incompatible-options.sh
Expand Up @@ -61,7 +61,6 @@ test_rebase_am_only () {
}

test_rebase_am_only --whitespace=fix
test_rebase_am_only --committer-date-is-author-date
test_rebase_am_only -C4

test_expect_success REBASE_P '--preserve-merges incompatible with --signoff' '
Expand Down
37 changes: 37 additions & 0 deletions t/t3433-rebase-options-compatibility.sh
Expand Up @@ -7,6 +7,9 @@ test_description='tests to ensure compatibility between am and interactive backe

. ./test-lib.sh

GIT_AUTHOR_DATE="1999-04-02T08:03:20+05:30"
export GIT_AUTHOR_DATE

# This is a special case in which both am and interactive backends
# provide the same output. It was done intentionally because
# both the backends fall short of optimal behaviour.
Expand All @@ -26,8 +29,13 @@ test_expect_success 'setup' '
EOF
git commit -am "update file" &&
git tag side &&
test_commit commit1 foo foo1 &&
test_commit commit2 foo foo2 &&
test_commit commit3 foo foo3 &&
git checkout --orphan master &&
git rm --cached foo &&
rm foo &&
sed -e "s/^|//" >file <<-\EOF &&
|line 1
| line 2
Expand Down Expand Up @@ -62,4 +70,33 @@ test_expect_success '--ignore-whitespace works with interactive backend' '
test_cmp expect file
'

test_expect_success '--committer-date-is-author-date works with am backend' '
git commit --amend &&
git rebase --committer-date-is-author-date HEAD^ &&
git show HEAD --pretty="format:%ai" >authortime &&
git show HEAD --pretty="format:%ci" >committertime &&
test_cmp authortime committertime
'

test_expect_success '--committer-date-is-author-date works with interactive backend' '
git commit --amend &&
git rebase -i --committer-date-is-author-date HEAD^ &&
git show HEAD --pretty="format:%ai" >authortime &&
git show HEAD --pretty="format:%ci" >committertime &&
test_cmp authortime committertime
'

test_expect_success '--committer-date-is-author-date works with rebase -r' '
git checkout side &&
git merge commit3 &&
git rebase -r --root --committer-date-is-author-date &&
git rev-list HEAD >rev_list &&
while read HASH
do
git show $HASH --pretty="format:%ai" >authortime
git show $HASH --pretty="format:%ci" >committertime
test_cmp authortime committertime
done <rev_list
'

test_done

0 comments on commit ccafcb3

Please sign in to comment.