mirror of
https://github.com/git/git.git
synced 2025-12-12 20:36:24 +01:00
replay: drop commits that become empty
If the changes in a commit being replayed are already in the branch that the commits are being replayed onto then "git replay" creates an empty commit. This is confusing because the commit message no longer matches the contents of the commit. Drop the commit instead. Commits that start off empty are not dropped. This matches the behavior of "git rebase --reapply-cherry-pick --empty=drop" and "git cherry-pick --empty-drop". If a branch points to a commit that is dropped it will be updated to point to the last commit that was not dropped. This can been seen in the new test where "topic1" is updated to point to the rebased "C" as "F" is dropped because it is already upstream. While this is a breaking change "git replay" is marked as experimental to allow improvements like this that change the behavior. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
committed by
Junio C Hamano
parent
bdddf4b651
commit
ad020dae7d
@@ -59,7 +59,9 @@ The default mode can be configured via the `replay.refAction` configuration vari
|
||||
be passed, but in `--advance <branch>` mode, they should have
|
||||
a single tip, so that it's clear where <branch> should point
|
||||
to. See "Specifying Ranges" in linkgit:git-rev-parse[1] and the
|
||||
"Commit Limiting" options below.
|
||||
"Commit Limiting" options below. Any commits in the range whose
|
||||
changes are already present in the branch the commits are being
|
||||
replayed onto will be dropped.
|
||||
|
||||
include::rev-list-options.adoc[]
|
||||
|
||||
|
||||
10
replay.c
10
replay.c
@@ -88,12 +88,12 @@ struct commit *replay_pick_regular_commit(struct repository *repo,
|
||||
struct merge_result *result)
|
||||
{
|
||||
struct commit *base, *replayed_base;
|
||||
struct tree *pickme_tree, *base_tree;
|
||||
struct tree *pickme_tree, *base_tree, *replayed_base_tree;
|
||||
|
||||
base = pickme->parents->item;
|
||||
replayed_base = mapped_commit(replayed_commits, base, onto);
|
||||
|
||||
result->tree = repo_get_commit_tree(repo, replayed_base);
|
||||
replayed_base_tree = repo_get_commit_tree(repo, replayed_base);
|
||||
pickme_tree = repo_get_commit_tree(repo, pickme);
|
||||
base_tree = repo_get_commit_tree(repo, base);
|
||||
|
||||
@@ -103,7 +103,7 @@ struct commit *replay_pick_regular_commit(struct repository *repo,
|
||||
|
||||
merge_incore_nonrecursive(merge_opt,
|
||||
base_tree,
|
||||
result->tree,
|
||||
replayed_base_tree,
|
||||
pickme_tree,
|
||||
result);
|
||||
|
||||
@@ -111,5 +111,9 @@ struct commit *replay_pick_regular_commit(struct repository *repo,
|
||||
merge_opt->ancestor = NULL;
|
||||
if (!result->clean)
|
||||
return NULL;
|
||||
/* Drop commits that become empty */
|
||||
if (oideq(&replayed_base_tree->object.oid, &result->tree->object.oid) &&
|
||||
!oideq(&pickme_tree->object.oid, &base_tree->object.oid))
|
||||
return replayed_base;
|
||||
return replay_create_commit(repo, result->tree, pickme, replayed_base);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ test_expect_success 'setup' '
|
||||
git switch -c topic3 &&
|
||||
test_commit G &&
|
||||
test_commit H &&
|
||||
git switch -c empty &&
|
||||
git commit --allow-empty --only -m empty &&
|
||||
git switch -c topic4 main &&
|
||||
test_commit I &&
|
||||
test_commit J &&
|
||||
@@ -106,6 +108,29 @@ test_expect_success 'using replay on bare repo to perform basic cherry-pick' '
|
||||
test_cmp expect result-bare
|
||||
'
|
||||
|
||||
test_expect_success 'commits that become empty are dropped' '
|
||||
git replay --ref-action=print --advance main topic1^! >result &&
|
||||
ONTO=$(cut -f 3 -d " " result) &&
|
||||
git replay --ref-action=print --onto $ONTO \
|
||||
--branches --ancestry-path=empty ^A >result &&
|
||||
# Write the new value of refs/heads/empty to "new-empty" and
|
||||
# generate a sed script that annotates the output of
|
||||
# `git log --format="%H %s"` with the updated branches
|
||||
SCRIPT="$(sed -e "
|
||||
/empty/{
|
||||
h
|
||||
s|^.*empty \([^ ]*\) .*|\1|wnew-empty
|
||||
g
|
||||
}
|
||||
s|^.*/\([^/ ]*\) \([^ ]*\).*|/^\2/s/\\\$/ (\1)/|
|
||||
\$s|\$|;s/^[^ ]* //|" result)" &&
|
||||
git log --format="%H %s" --stdin <new-empty >actual.raw &&
|
||||
sed -e "$SCRIPT" actual.raw >actual &&
|
||||
test_write_lines >expect \
|
||||
"empty (empty)" "H (topic3)" G "C (topic1)" F M L B A &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'replay on bare repo fails with both --advance and --onto' '
|
||||
test_must_fail git -C bare replay --advance main --onto main topic1..topic2 >result-bare
|
||||
'
|
||||
|
||||
Reference in New Issue
Block a user