Skip to content

Commit 9c31b19

Browse files
committed
Merge branch 'pw/rebase-i-more-options'
"git rebase -i" learns a bit more options. * pw/rebase-i-more-options: t3436: do not run git-merge-recursive in dashed form rebase: add --reset-author-date rebase -i: support --ignore-date rebase -i: support --committer-date-is-author-date am: stop exporting GIT_COMMITTER_DATE rebase -i: add --ignore-whitespace flag
2 parents e197136 + 6160b2e commit 9c31b19

File tree

11 files changed

+423
-49
lines changed

11 files changed

+423
-49
lines changed

Documentation/git-rebase.txt

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -459,17 +459,38 @@ with `--keep-base` in order to drop those commits from your branch.
459459
See also INCOMPATIBLE OPTIONS below.
460460

461461
--ignore-whitespace::
462+
Ignore whitespace differences when trying to reconcile
463+
differences. Currently, each backend implements an approximation of
464+
this behavior:
465+
+
466+
apply backend: When applying a patch, ignore changes in whitespace in
467+
context lines. Unfortunately, this means that if the "old" lines being
468+
replaced by the patch differ only in whitespace from the existing
469+
file, you will get a merge conflict instead of a successful patch
470+
application.
471+
+
472+
merge backend: Treat lines with only whitespace changes as unchanged
473+
when merging. Unfortunately, this means that any patch hunks that were
474+
intended to modify whitespace and nothing else will be dropped, even
475+
if the other side had no changes that conflicted.
476+
462477
--whitespace=<option>::
463-
These flags are passed to the 'git apply' program
478+
This flag is passed to the 'git apply' program
464479
(see linkgit:git-apply[1]) that applies the patch.
465480
Implies --apply.
466481
+
467482
See also INCOMPATIBLE OPTIONS below.
468483

469484
--committer-date-is-author-date::
485+
Instead of using the current time as the committer date, use
486+
the author date of the commit being rebased as the committer
487+
date. This option implies `--force-rebase`.
488+
470489
--ignore-date::
471-
These flags are passed to 'git am' to easily change the dates
472-
of the rebased commits (see linkgit:git-am[1]).
490+
--reset-author-date::
491+
Instead of using the author date of the original commit, use
492+
the current time as the author date of the rebased commit. This
493+
option implies `--force-rebase`.
473494
+
474495
See also INCOMPATIBLE OPTIONS below.
475496

@@ -607,9 +628,6 @@ INCOMPATIBLE OPTIONS
607628
The following options:
608629

609630
* --apply
610-
* --committer-date-is-author-date
611-
* --ignore-date
612-
* --ignore-whitespace
613631
* --whitespace
614632
* -C
615633

@@ -636,6 +654,9 @@ In addition, the following pairs of options are incompatible:
636654
* --preserve-merges and --signoff
637655
* --preserve-merges and --rebase-merges
638656
* --preserve-merges and --empty=
657+
* --preserve-merges and --ignore-whitespace
658+
* --preserve-merges and --committer-date-is-author-date
659+
* --preserve-merges and --ignore-date
639660
* --keep-base and --onto
640661
* --keep-base and --root
641662
* --fork-point and --root

builtin/am.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ struct am_state {
9898
char *author_name;
9999
char *author_email;
100100
char *author_date;
101+
char *committer_name;
102+
char *committer_email;
101103
char *msg;
102104
size_t msg_len;
103105

@@ -130,6 +132,8 @@ struct am_state {
130132
*/
131133
static void am_state_init(struct am_state *state)
132134
{
135+
const char *committer;
136+
struct ident_split id;
133137
int gpgsign;
134138

135139
memset(state, 0, sizeof(*state));
@@ -150,6 +154,14 @@ static void am_state_init(struct am_state *state)
150154

151155
if (!git_config_get_bool("commit.gpgsign", &gpgsign))
152156
state->sign_commit = gpgsign ? "" : NULL;
157+
158+
committer = git_committer_info(IDENT_STRICT);
159+
if (split_ident_line(&id, committer, strlen(committer)) < 0)
160+
die(_("invalid committer: %s"), committer);
161+
state->committer_name =
162+
xmemdupz(id.name_begin, id.name_end - id.name_begin);
163+
state->committer_email =
164+
xmemdupz(id.mail_begin, id.mail_end - id.mail_end);
153165
}
154166

155167
/**
@@ -161,6 +173,8 @@ static void am_state_release(struct am_state *state)
161173
free(state->author_name);
162174
free(state->author_email);
163175
free(state->author_date);
176+
free(state->committer_name);
177+
free(state->committer_email);
164178
free(state->msg);
165179
strvec_clear(&state->git_apply_opts);
166180
}
@@ -1556,7 +1570,7 @@ static void do_commit(const struct am_state *state)
15561570
struct object_id tree, parent, commit;
15571571
const struct object_id *old_oid;
15581572
struct commit_list *parents = NULL;
1559-
const char *reflog_msg, *author;
1573+
const char *reflog_msg, *author, *committer = NULL;
15601574
struct strbuf sb = STRBUF_INIT;
15611575

15621576
if (run_hook_le(NULL, "pre-applypatch", NULL))
@@ -1580,11 +1594,15 @@ static void do_commit(const struct am_state *state)
15801594
IDENT_STRICT);
15811595

15821596
if (state->committer_date_is_author_date)
1583-
setenv("GIT_COMMITTER_DATE",
1584-
state->ignore_date ? "" : state->author_date, 1);
1585-
1586-
if (commit_tree(state->msg, state->msg_len, &tree, parents, &commit,
1587-
author, state->sign_commit))
1597+
committer = fmt_ident(state->committer_name,
1598+
state->author_email, WANT_COMMITTER_IDENT,
1599+
state->ignore_date ? NULL
1600+
: state->author_date,
1601+
IDENT_STRICT);
1602+
1603+
if (commit_tree_extended(state->msg, state->msg_len, &tree, parents,
1604+
&commit, author, committer, state->sign_commit,
1605+
NULL))
15881606
die(_("failed to write commit object"));
15891607

15901608
reflog_msg = getenv("GIT_REFLOG_ACTION");

builtin/commit.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,8 +1672,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
16721672
}
16731673

16741674
if (commit_tree_extended(sb.buf, sb.len, &active_cache_tree->oid,
1675-
parents, &oid, author_ident.buf, sign_commit,
1676-
extra)) {
1675+
parents, &oid, author_ident.buf, NULL,
1676+
sign_commit, extra)) {
16771677
rollback_index_files();
16781678
die(_("failed to write commit object"));
16791679
}

builtin/rebase.c

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ struct rebase_options {
9292
int autosquash;
9393
char *gpg_sign_opt;
9494
int autostash;
95+
int committer_date_is_author_date;
96+
int ignore_date;
9597
char *cmd;
9698
int allow_empty_message;
9799
int rebase_merges, rebase_cousins;
@@ -130,8 +132,12 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
130132
replay.quiet = !(opts->flags & REBASE_NO_QUIET);
131133
replay.verbose = opts->flags & REBASE_VERBOSE;
132134
replay.reschedule_failed_exec = opts->reschedule_failed_exec;
135+
replay.committer_date_is_author_date =
136+
opts->committer_date_is_author_date;
137+
replay.ignore_date = opts->ignore_date;
133138
replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
134139
replay.strategy = opts->strategy;
140+
135141
if (opts->strategy_opts)
136142
parse_strategy_opts(&replay, opts->strategy_opts);
137143

@@ -1289,6 +1295,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
12891295
struct strbuf revisions = STRBUF_INIT;
12901296
struct strbuf buf = STRBUF_INIT;
12911297
struct object_id merge_base;
1298+
int ignore_whitespace = 0;
12921299
enum action action = ACTION_NONE;
12931300
const char *gpg_sign = NULL;
12941301
struct string_list exec = STRING_LIST_INIT_NODUP;
@@ -1318,16 +1325,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
13181325
PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
13191326
OPT_BOOL(0, "signoff", &options.signoff,
13201327
N_("add a Signed-off-by: line to each commit")),
1321-
OPT_PASSTHRU_ARGV(0, "ignore-whitespace", &options.git_am_opts,
1322-
NULL, N_("passed to 'git am'"),
1323-
PARSE_OPT_NOARG),
1324-
OPT_PASSTHRU_ARGV(0, "committer-date-is-author-date",
1325-
&options.git_am_opts, NULL,
1326-
N_("passed to 'git am'"), PARSE_OPT_NOARG),
1327-
OPT_PASSTHRU_ARGV(0, "ignore-date", &options.git_am_opts, NULL,
1328-
N_("passed to 'git am'"), PARSE_OPT_NOARG),
1328+
OPT_BOOL(0, "committer-date-is-author-date",
1329+
&options.committer_date_is_author_date,
1330+
N_("make committer date match author date")),
1331+
OPT_BOOL(0, "reset-author-date", &options.ignore_date,
1332+
N_("ignore author date and use current date")),
1333+
OPT_HIDDEN_BOOL(0, "ignore-date", &options.ignore_date,
1334+
N_("synonym of --reset-author-date")),
13291335
OPT_PASSTHRU_ARGV('C', NULL, &options.git_am_opts, N_("n"),
13301336
N_("passed to 'git apply'"), 0),
1337+
OPT_BOOL(0, "ignore-whitespace", &ignore_whitespace,
1338+
N_("ignore changes in whitespace")),
13311339
OPT_PASSTHRU_ARGV(0, "whitespace", &options.git_am_opts,
13321340
N_("action"), N_("passed to 'git apply'"), 0),
13331341
OPT_BIT('f', "force-rebase", &options.flags,
@@ -1624,12 +1632,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
16241632
options.autosquash) {
16251633
allow_preemptive_ff = 0;
16261634
}
1635+
if (options.committer_date_is_author_date || options.ignore_date)
1636+
options.flags |= REBASE_FORCE;
16271637

16281638
for (i = 0; i < options.git_am_opts.nr; i++) {
16291639
const char *option = options.git_am_opts.v[i], *p;
1630-
if (!strcmp(option, "--committer-date-is-author-date") ||
1631-
!strcmp(option, "--ignore-date") ||
1632-
!strcmp(option, "--whitespace=fix") ||
1640+
if (!strcmp(option, "--whitespace=fix") ||
16331641
!strcmp(option, "--whitespace=strip"))
16341642
allow_preemptive_ff = 0;
16351643
else if (skip_prefix(option, "-C", &p)) {
@@ -1682,6 +1690,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
16821690
imply_merge(&options, "--rebase-merges");
16831691
}
16841692

1693+
if (options.type == REBASE_APPLY) {
1694+
if (ignore_whitespace)
1695+
strvec_push(&options.git_am_opts,
1696+
"--ignore-whitespace");
1697+
if (options.committer_date_is_author_date)
1698+
strvec_push(&options.git_am_opts,
1699+
"--committer-date-is-author-date");
1700+
if (options.ignore_date)
1701+
strvec_push(&options.git_am_opts, "--ignore-date");
1702+
} else {
1703+
/* REBASE_MERGE and PRESERVE_MERGES */
1704+
if (ignore_whitespace) {
1705+
string_list_append(&strategy_options,
1706+
"ignore-space-change");
1707+
}
1708+
}
1709+
16851710
if (strategy_options.nr) {
16861711
int i;
16871712

commit.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,8 +1316,8 @@ int commit_tree(const char *msg, size_t msg_len, const struct object_id *tree,
13161316
int result;
13171317

13181318
append_merge_tag_headers(parents, &tail);
1319-
result = commit_tree_extended(msg, msg_len, tree, parents, ret,
1320-
author, sign_commit, extra);
1319+
result = commit_tree_extended(msg, msg_len, tree, parents, ret, author,
1320+
NULL, sign_commit, extra);
13211321
free_commit_extra_headers(extra);
13221322
return result;
13231323
}
@@ -1440,7 +1440,8 @@ N_("Warning: commit message did not conform to UTF-8.\n"
14401440
int commit_tree_extended(const char *msg, size_t msg_len,
14411441
const struct object_id *tree,
14421442
struct commit_list *parents, struct object_id *ret,
1443-
const char *author, const char *sign_commit,
1443+
const char *author, const char *committer,
1444+
const char *sign_commit,
14441445
struct commit_extra_header *extra)
14451446
{
14461447
int result;
@@ -1473,7 +1474,9 @@ int commit_tree_extended(const char *msg, size_t msg_len,
14731474
if (!author)
14741475
author = git_author_info(IDENT_STRICT);
14751476
strbuf_addf(&buffer, "author %s\n", author);
1476-
strbuf_addf(&buffer, "committer %s\n", git_committer_info(IDENT_STRICT));
1477+
if (!committer)
1478+
committer = git_committer_info(IDENT_STRICT);
1479+
strbuf_addf(&buffer, "committer %s\n", committer);
14771480
if (!encoding_is_utf8)
14781481
strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding);
14791482

commit.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -270,10 +270,9 @@ int commit_tree(const char *msg, size_t msg_len,
270270

271271
int commit_tree_extended(const char *msg, size_t msg_len,
272272
const struct object_id *tree,
273-
struct commit_list *parents,
274-
struct object_id *ret, const char *author,
275-
const char *sign_commit,
276-
struct commit_extra_header *);
273+
struct commit_list *parents, struct object_id *ret,
274+
const char *author, const char *committer,
275+
const char *sign_commit, struct commit_extra_header *);
277276

278277
struct commit_extra_header *read_commit_extra_headers(struct commit *, const char **);
279278

ident.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -375,11 +375,15 @@ static void ident_env_hint(enum want_ident whose_ident)
375375
const char *fmt_ident(const char *name, const char *email,
376376
enum want_ident whose_ident, const char *date_str, int flag)
377377
{
378-
static struct strbuf ident = STRBUF_INIT;
378+
static int index;
379+
static struct strbuf ident_pool[2] = { STRBUF_INIT, STRBUF_INIT };
379380
int strict = (flag & IDENT_STRICT);
380381
int want_date = !(flag & IDENT_NO_DATE);
381382
int want_name = !(flag & IDENT_NO_NAME);
382383

384+
struct strbuf *ident = &ident_pool[index];
385+
index = (index + 1) % ARRAY_SIZE(ident_pool);
386+
383387
if (!email) {
384388
if (whose_ident == WANT_AUTHOR_IDENT && git_author_email.len)
385389
email = git_author_email.buf;
@@ -435,25 +439,25 @@ const char *fmt_ident(const char *name, const char *email,
435439
die(_("name consists only of disallowed characters: %s"), name);
436440
}
437441

438-
strbuf_reset(&ident);
442+
strbuf_reset(ident);
439443
if (want_name) {
440-
strbuf_addstr_without_crud(&ident, name);
441-
strbuf_addstr(&ident, " <");
444+
strbuf_addstr_without_crud(ident, name);
445+
strbuf_addstr(ident, " <");
442446
}
443-
strbuf_addstr_without_crud(&ident, email);
447+
strbuf_addstr_without_crud(ident, email);
444448
if (want_name)
445-
strbuf_addch(&ident, '>');
449+
strbuf_addch(ident, '>');
446450
if (want_date) {
447-
strbuf_addch(&ident, ' ');
451+
strbuf_addch(ident, ' ');
448452
if (date_str && date_str[0]) {
449-
if (parse_date(date_str, &ident) < 0)
453+
if (parse_date(date_str, ident) < 0)
450454
die(_("invalid date format: %s"), date_str);
451455
}
452456
else
453-
strbuf_addstr(&ident, ident_default_date());
457+
strbuf_addstr(ident, ident_default_date());
454458
}
455459

456-
return ident.buf;
460+
return ident->buf;
457461
}
458462

459463
const char *fmt_name(enum want_ident whose_ident)

0 commit comments

Comments
 (0)