Skip to content

Commit 009eb82

Browse files
committed
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 drop the commit instead of creating an empty commit. This matches the behavior of "git rebase --reapply-cherry-pick --empty=drop" and "git cherry-pick --empty-drop".
1 parent b00f91d commit 009eb82

File tree

2 files changed

+32
-3
lines changed

2 files changed

+32
-3
lines changed

replay.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "commit.h"
55
#include "environment.h"
66
#include "gettext.h"
7+
#include "hex.h"
78
#include "ident.h"
89
#include "object.h"
910
#include "object-name.h"
@@ -88,12 +89,12 @@ struct commit *replay_pick_regular_commit(struct repository *repo,
8889
struct merge_result *result)
8990
{
9091
struct commit *base, *replayed_base;
91-
struct tree *pickme_tree, *base_tree;
92+
struct tree *pickme_tree, *base_tree, *replayed_base_tree;
9293

9394
base = pickme->parents->item;
9495
replayed_base = mapped_commit(replayed_commits, base, onto);
9596

96-
result->tree = repo_get_commit_tree(repo, replayed_base);
97+
replayed_base_tree = repo_get_commit_tree(repo, replayed_base);
9798
pickme_tree = repo_get_commit_tree(repo, pickme);
9899
base_tree = repo_get_commit_tree(repo, base);
99100

@@ -103,13 +104,17 @@ struct commit *replay_pick_regular_commit(struct repository *repo,
103104

104105
merge_incore_nonrecursive(merge_opt,
105106
base_tree,
106-
result->tree,
107+
replayed_base_tree,
107108
pickme_tree,
108109
result);
109110

110111
free((char*)merge_opt->ancestor);
111112
merge_opt->ancestor = NULL;
112113
if (!result->clean)
113114
return NULL;
115+
/* Drop commits that become empty */
116+
if (oideq(&replayed_base_tree->object.oid, &result->tree->object.oid) &&
117+
!oideq(&pickme_tree->object.oid, &base_tree->object.oid))
118+
return replayed_base;
114119
return replay_create_commit(repo, result->tree, pickme, replayed_base);
115120
}

t/t3650-replay-basics.sh

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ test_expect_success 'setup' '
2525
git switch -c topic3 &&
2626
test_commit G &&
2727
test_commit H &&
28+
git switch -c empty &&
29+
git commit --allow-empty --only -m empty &&
2830
git switch -c topic4 main &&
2931
test_commit I &&
3032
test_commit J &&
@@ -106,6 +108,28 @@ test_expect_success 'using replay on bare repo to perform basic cherry-pick' '
106108
test_cmp expect result-bare
107109
'
108110

111+
test_expect_success 'commits that become empty are dropped' '
112+
git replay --ref-action=print --advance main topic1^! >result &&
113+
ONTO=$(cut -f 3 -d " " result) &&
114+
git replay --ref-action=print --onto $ONTO \
115+
--branches --ancestry-path=empty ^A >result &&
116+
# Write the new value of refs/heads/empty to "new-empty" and
117+
# generate a sed script that annotates the output of
118+
# `git log --format="%H %s"` with the updated branches
119+
SCRIPT="$(sed -e "
120+
/empty/{
121+
h
122+
s|^.*empty \([^ ]*\) .*|\1|wnew-empty
123+
g
124+
}
125+
s|^.*/\([^/ ]*\) \([^ ]*\).*|/\2/s/\\\$/ (\1)/|
126+
\$s|\$|;s/^[^ ]* //|" result)" &&
127+
git log --format="%H %s" --stdin <new-empty >actual.raw &&
128+
sed -e "$SCRIPT" actual.raw >actual &&
129+
test_write_lines "empty (empty)" "H (topic3)" G "C (topic1)" F M L B A >expect &&
130+
test_cmp expect actual
131+
'
132+
109133
test_expect_success 'replay on bare repo fails with both --advance and --onto' '
110134
test_must_fail git -C bare replay --advance main --onto main topic1..topic2 >result-bare
111135
'

0 commit comments

Comments
 (0)