Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 20 additions & 7 deletions Documentation/git-history.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,26 @@ at once.
LIMITATIONS
-----------

This command does not (yet) work with histories that contain merges. You
should use linkgit:git-rebase[1] with the `--rebase-merges` flag instead.

Furthermore, the command does not support operations that can result in merge
conflicts. This limitation is by design as history rewrites are not intended to
be stateful operations. The limitation can be lifted once (if) Git learns about
first-class conflicts.
This command supports two-parent merge commits in the rewrite path:
the auto-remerged tree of the original parents, the merge commit
itself, and the auto-merged tree of the rewritten parents are
combined so that the user's manual conflict resolution (textual or
semantic) is preserved through the replay. Octopus merges (more than
two parents) are not supported and are rejected with an error.

The replay propagates the textual diffs the user actually made in
the merge commit. It does _not_ extrapolate symbol-level intent: if
rewriting the parents pulls in genuinely new content (for example, a
new caller of a function that the merge renamed), that new content
is _not_ rewritten by the replay and may need a follow-up edit.
Symbol-aware refactoring is out of scope here, just as it is for
plain rebase.

The command does not support operations that can result in merge
conflicts on the replayed merge itself. This limitation is by design
as history rewrites are not intended to be stateful operations. Use
linkgit:git-rebase[1] with the `--rebase-merges` flag when the
rewrite is expected to require interactive conflict resolution.

COMMANDS
--------
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,7 @@ TEST_BUILTINS_OBJS += test-hash-speed.o
TEST_BUILTINS_OBJS += test-hash.o
TEST_BUILTINS_OBJS += test-hashmap.o
TEST_BUILTINS_OBJS += test-hexdump.o
TEST_BUILTINS_OBJS += test-historian.o
TEST_BUILTINS_OBJS += test-json-writer.o
TEST_BUILTINS_OBJS += test-lazy-init-name-hash.o
TEST_BUILTINS_OBJS += test-match-trees.o
Expand Down
16 changes: 11 additions & 5 deletions builtin/history.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,15 +195,15 @@ static int parse_ref_action(const struct option *opt, const char *value, int uns
return 0;
}

static int revwalk_contains_merges(struct repository *repo,
const struct strvec *revwalk_args)
static int revwalk_contains_octopus_merges(struct repository *repo,
const struct strvec *revwalk_args)
{
struct strvec args = STRVEC_INIT;
struct rev_info revs;
int ret;

strvec_pushv(&args, revwalk_args->v);
strvec_push(&args, "--min-parents=2");
strvec_push(&args, "--min-parents=3");

repo_init_revisions(repo, &revs, NULL);

Expand All @@ -217,7 +217,7 @@ static int revwalk_contains_merges(struct repository *repo,
}

if (get_revision(&revs)) {
ret = error(_("replaying merge commits is not supported yet!"));
ret = error(_("replaying octopus merges is not supported"));
goto out;
}

Expand Down Expand Up @@ -289,7 +289,7 @@ static int setup_revwalk(struct repository *repo,
strvec_push(&args, "HEAD");
}

ret = revwalk_contains_merges(repo, &args);
ret = revwalk_contains_octopus_merges(repo, &args);
if (ret < 0)
goto out;

Expand Down Expand Up @@ -482,6 +482,9 @@ static int cmd_history_reword(int argc,
if (ret < 0) {
ret = error(_("failed replaying descendants"));
goto out;
} else if (ret) {
ret = error(_("conflict during replay; some descendants were not rewritten"));
goto out;
}

ret = 0;
Expand Down Expand Up @@ -721,6 +724,9 @@ static int cmd_history_split(int argc,
if (ret < 0) {
ret = error(_("failed replaying descendants"));
goto out;
} else if (ret) {
ret = error(_("conflict during replay; some descendants were not rewritten"));
goto out;
}

ret = 0;
Expand Down
Loading
Loading