Skip to content

Commit 6530ccd

Browse files
committed
Merge branch 'pw/replay-drop-empty' into seen
"git replay" is taught to drop commits that become empty (not the ones that are empty in the original). * pw/replay-drop-empty: replay: drop commits that become empty
2 parents 708bf14 + 2f8b312 commit 6530ccd

File tree

3 files changed

+31
-4
lines changed

3 files changed

+31
-4
lines changed

Documentation/git-replay.adoc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ The default mode can be configured via the `replay.refAction` configuration vari
6262
Range of commits to replay; see "Specifying Ranges" in
6363
linkgit:git-rev-parse[1]. In `--advance <branch>` mode, the
6464
range should have a single tip, so that it's clear to which tip the
65-
advanced <branch> should point.
65+
advanced <branch> should point. Any commits in the range whose
66+
changes are already present in the branch the commits are being
67+
replayed onto will be dropped.
6668

6769
include::rev-list-options.adoc[]
6870

replay.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,12 +211,12 @@ static struct commit *pick_regular_commit(struct repository *repo,
211211
struct merge_result *result)
212212
{
213213
struct commit *base, *replayed_base;
214-
struct tree *pickme_tree, *base_tree;
214+
struct tree *pickme_tree, *base_tree, *replayed_base_tree;
215215

216216
base = pickme->parents->item;
217217
replayed_base = mapped_commit(replayed_commits, base, onto);
218218

219-
result->tree = repo_get_commit_tree(repo, replayed_base);
219+
replayed_base_tree = repo_get_commit_tree(repo, replayed_base);
220220
pickme_tree = repo_get_commit_tree(repo, pickme);
221221
base_tree = repo_get_commit_tree(repo, base);
222222

@@ -226,14 +226,18 @@ static struct commit *pick_regular_commit(struct repository *repo,
226226

227227
merge_incore_nonrecursive(merge_opt,
228228
base_tree,
229-
result->tree,
229+
replayed_base_tree,
230230
pickme_tree,
231231
result);
232232

233233
free((char*)merge_opt->ancestor);
234234
merge_opt->ancestor = NULL;
235235
if (!result->clean)
236236
return NULL;
237+
/* Drop commits that become empty */
238+
if (oideq(&replayed_base_tree->object.oid, &result->tree->object.oid) &&
239+
!oideq(&pickme_tree->object.oid, &base_tree->object.oid))
240+
return replayed_base;
237241
return create_commit(repo, result->tree, pickme, replayed_base);
238242
}
239243

t/t3650-replay-basics.sh

Lines changed: 21 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 -m empty &&
2830
git switch -c topic4 main &&
2931
test_commit I &&
3032
test_commit J &&
@@ -160,6 +162,25 @@ test_expect_success 'using replay on bare repo to perform basic cherry-pick' '
160162
test_cmp expect result-bare
161163
'
162164

165+
test_expect_success 'commits that become empty are dropped' '
166+
# Save original branches
167+
git for-each-ref --format="update %(refname) %(objectname)" \
168+
refs/heads/ >original-branches &&
169+
test_when_finished "git update-ref --stdin <original-branches &&
170+
rm original-branches" &&
171+
# Cherry-pick tip of topic1 ("F"), from the middle of A..empty, to main
172+
git replay --advance main topic1^! &&
173+
174+
# Replay all of A..empty onto main (which includes topic1 & thus F
175+
# in the middle)
176+
git replay --onto main --branches --ancestry-path=empty ^A \
177+
>result &&
178+
git log --format="%s%d" L..empty >actual &&
179+
test_write_lines >expect \
180+
"empty (empty)" "H (topic3)" G "C (topic1)" "F (main)" "M (tag: M)" &&
181+
test_cmp expect actual
182+
'
183+
163184
test_expect_success 'replay on bare repo fails with both --advance and --onto' '
164185
test_must_fail git -C bare replay --advance main --onto main topic1..topic2 >result-bare
165186
'

0 commit comments

Comments
 (0)