Skip to content

Commit

Permalink
rebase -i: support --ignore-date
Browse files Browse the repository at this point in the history
rebase am already has this flag to "lie" about the author date
by changing it to the committer (current) 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 Nov 2, 2019
1 parent 0185c68 commit 08187b4
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 11 deletions.
6 changes: 3 additions & 3 deletions Documentation/git-rebase.txt
Expand Up @@ -391,8 +391,8 @@ See also INCOMPATIBLE OPTIONS below.
as the committer date. This implies --force-rebase.

--ignore-date::
This flag is passed to 'git am' to change the author date
of each rebased commit (see linkgit:git-am[1]).
Instead of using the given author date, reset it to the
current time. This implies --force-rebase.
+
See also INCOMPATIBLE OPTIONS below.

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

The following options:

* --ignore-date
* --whitespace
* -C

Expand All @@ -555,6 +554,7 @@ In addition, the following pairs of options are incompatible:
* --preserve-merges and --rebase-merges
* --preserve-merges and --ignore-whitespace
* --preserve-merges and --committer-date-is-author-date
* --preserve-merges and --ignore-date
* --rebase-merges and --strategy
* --rebase-merges and --strategy-option

Expand Down
14 changes: 9 additions & 5 deletions builtin/rebase.c
Expand Up @@ -83,6 +83,7 @@ struct rebase_options {
char *gpg_sign_opt;
int autostash;
int committer_date_is_author_date;
int ignore_date;
char *cmd;
int allow_empty_message;
int rebase_merges, rebase_cousins;
Expand Down Expand Up @@ -117,6 +118,7 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
replay.reschedule_failed_exec = opts->reschedule_failed_exec;
replay.committer_date_is_author_date =
opts->committer_date_is_author_date;
replay.ignore_date = opts->ignore_date;
replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
replay.strategy = opts->strategy;

Expand Down Expand Up @@ -981,6 +983,8 @@ static int run_am(struct rebase_options *opts)
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->ignore_date)
argv_array_push(&opts->git_am_opts, "--ignore-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 @@ -1432,8 +1436,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
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_BOOL(0, "ignore-date", &options.ignore_date,
"ignore author date and use current date"),
OPT_PASSTHRU_ARGV('C', NULL, &options.git_am_opts, N_("n"),
N_("passed to 'git apply'"), 0),
OPT_BOOL(0, "ignore-whitespace", &options.ignore_whitespace,
Expand Down Expand Up @@ -1706,13 +1710,13 @@ 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)
if (options.committer_date_is_author_date ||
options.ignore_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, "--ignore-date") ||
!strcmp(option, "--whitespace=fix") ||
if (!strcmp(option, "--whitespace=fix") ||
!strcmp(option, "--whitespace=strip"))
options.flags |= REBASE_FORCE;
else if (skip_prefix(option, "-C", &p)) {
Expand Down
60 changes: 57 additions & 3 deletions sequencer.c
Expand Up @@ -148,6 +148,7 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, "rebase-merge/refs-to-delete")
*/
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_ignore_date, "rebase-merge/ignore_date")
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 @@ -891,6 +892,36 @@ static char *read_author_date_or_null(void)
return date;
}

/* Construct a free()able author string with current time as the author date */
static char *ignore_author_date(const char *author)
{
int len = strlen(author);
struct ident_split ident;
struct strbuf new_author = STRBUF_INIT;

if (split_ident_line(&ident, author, len) < 0) {
error(_("malformed ident line"));
return NULL;
}
len = ident.mail_end - ident.name_begin + 1;

strbuf_addf(&new_author, "%.*s ", len, ident.name_begin);
datestamp(&new_author);
return strbuf_detach(&new_author, NULL);
}

static void push_dates(struct child_process *child, int change_committer_date)
{
time_t now = time(NULL);
struct strbuf date = STRBUF_INIT;

strbuf_addf(&date, "@%"PRIuMAX, (uintmax_t)now);
argv_array_pushf(&child->env_array, "GIT_AUTHOR_DATE=%s", date.buf);
if (change_committer_date)
argv_array_pushf(&child->env_array, "GIT_COMMITTER_DATE=%s", date.buf);
strbuf_release(&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 @@ -959,7 +990,8 @@ static int run_git_commit(struct repository *r,
return -1;

strbuf_addf(&datebuf, "@%s", date);
res = setenv("GIT_COMMITTER_DATE", datebuf.buf, 1);
res = setenv("GIT_COMMITTER_DATE",
opts->ignore_date ? "" : datebuf.buf, 1);

strbuf_release(&datebuf);
free(date);
Expand All @@ -983,6 +1015,8 @@ static int run_git_commit(struct repository *r,
argv_array_push(&cmd.args, "--amend");
if (opts->gpg_sign)
argv_array_pushf(&cmd.args, "-S%s", opts->gpg_sign);
if (opts->ignore_date)
push_dates(&cmd, opts->committer_date_is_author_date);
if (defmsg)
argv_array_pushl(&cmd.args, "-F", defmsg, NULL);
else if (!(flags & EDIT_MSG))
Expand Down Expand Up @@ -1405,7 +1439,8 @@ static int try_to_commit(struct repository *r,
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);
res = setenv("GIT_COMMITTER_DATE",
opts->ignore_date ? "" : date.buf, 1);
strbuf_release(&date);

if (res)
Expand Down Expand Up @@ -1455,6 +1490,15 @@ static int try_to_commit(struct repository *r,

reset_ident_date();

if (opts->ignore_date) {
author = ignore_author_date(author);
if (!author) {
res = -1;
goto out;
}
free(author_to_free);
author_to_free = (char *)author;
}
if (commit_tree_extended(msg->buf, msg->len, &tree, parents,
oid, author, opts->gpg_sign, extra)) {
res = error(_("failed to write commit object"));
Expand Down Expand Up @@ -2538,6 +2582,11 @@ static int read_populate_opts(struct replay_opts *opts)
opts->committer_date_is_author_date = 1;
}

if (file_exists(rebase_path_ignore_date())) {
opts->allow_ff = 0;
opts->ignore_date = 1;
}

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

Expand Down Expand Up @@ -2622,6 +2671,8 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,
write_file(rebase_path_signoff(), "--signoff\n");
if (opts->committer_date_is_author_date)
write_file(rebase_path_cdate_is_adate(), "%s", "");
if (opts->ignore_date)
write_file(rebase_path_ignore_date(), "%s", "");
if (opts->reschedule_failed_exec)
write_file(rebase_path_reschedule_failed_exec(), "%s", "");

Expand Down Expand Up @@ -3439,6 +3490,8 @@ static int do_merge(struct repository *r,
argv_array_push(&cmd.args, git_path_merge_msg(r));
if (opts->gpg_sign)
argv_array_push(&cmd.args, opts->gpg_sign);
if (opts->ignore_date)
push_dates(&cmd, opts->committer_date_is_author_date);

/* Add the tips to be merged */
for (j = to_merge; j; j = j->next)
Expand Down Expand Up @@ -3711,7 +3764,8 @@ static int pick_commits(struct repository *r,
if (opts->allow_ff)
assert(!(opts->signoff || opts->no_commit ||
opts->record_origin || opts->edit ||
opts->committer_date_is_author_date));
opts->committer_date_is_author_date ||
opts->ignore_date));
if (read_and_refresh_cache(r, opts))
return -1;

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

int mainline;

Expand Down
29 changes: 29 additions & 0 deletions t/t3433-rebase-options-compatibility.sh
Expand Up @@ -99,4 +99,33 @@ test_expect_success '--committer-date-is-author-date works with rebase -r' '
done <rev_list
'

# Checking for +0000 in author time is enough since default
# timezone is UTC, but the timezone used while committing
# sets to +0530.
test_expect_success '--ignore-date works with am backend' '
git commit --amend --date="$GIT_AUTHOR_DATE" &&
git rebase --ignore-date HEAD^ &&
git show HEAD --pretty="format:%ai" >authortime &&
grep "+0000" authortime
'

test_expect_success '--ignore-date works with interactive backend' '
git commit --amend --date="$GIT_AUTHOR_DATE" &&
git rebase --ignore-date -i HEAD^ &&
git show HEAD --pretty="format:%ai" >authortime &&
grep "+0000" authortime
'

test_expect_success '--ignore-date works with rebase -r' '
git checkout side &&
git merge --no-ff commit3 &&
git rebase -r --root --ignore-date &&
git rev-list HEAD >rev_list &&
while read HASH
do
git show $HASH --pretty="format:%ai" >authortime
grep "+0000" authortime
done <rev_list
'

test_done

0 comments on commit 08187b4

Please sign in to comment.