git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH v2] replay: drop commits that become empty

From
PWPhillip Wood <phillip.wood123@gmail.com>
Date
Dec 16, 2025, 14:19 UTC
Message-ID
<80477d23-eed3-4a99-be97-f692bc36095e@gmail.com>
In-Reply-To
<xmqqpl8f719x.fsf@gitster.g>
On 15/12/2025 23:50, Junio C Hamano wrote:
Show 14 quoted lines
> Phillip Wood <phillip.wood123@gmail.com> writes:
> 
>> From: Phillip Wood <phillip.wood@dunelm.org.uk>
>>
>> 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".
> 
> OK.  Maybe it is just me but "onto then" -> "onto," would flow the
> sentence better?

I agree it reads better with a comma here and in the second paragraph, I'll re-roll

Thanks
Phillip
Show 103 quoted lines
>> 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
> 
> If one thinks about it, it is the only natural behaviour to use the
> last surviving commit to point the branch at.  Thanks for spelling
> it out so clearly.
> 
> BTW, "can been seen" -> "can be seen" (will amend locally).
> 
>> 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.
> 
> Again maybe it is just me, but I'd prefer to see a comma after "a
> breaking change" to flow the sentence better.
> 
>> Helped-by: Elijah Newren <newren@gmail.com>
>> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
>> ---
>> ...
>> diff --git a/Documentation/git-replay.adoc b/Documentation/git-replay.adoc
>> index dcb26e8a8e8..96a3a557bf3 100644
>> --- a/Documentation/git-replay.adoc
>> +++ b/Documentation/git-replay.adoc
>> @@ -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.
> 
> OK.
> 
>> diff --git a/replay.c b/replay.c
>> index 13983dbc566..2864c213993 100644
>> --- a/replay.c
>> +++ b/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,13 +103,17 @@ struct commit *replay_pick_regular_commit(struct repository *repo,
>>   
>>   	merge_incore_nonrecursive(merge_opt,
>>   				  base_tree,
>> -				  result->tree,
>> +				  replayed_base_tree,
>>   				  pickme_tree,
>>   				  result);
>>   
>>   	free((char*)merge_opt->ancestor);
>>   	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);
>>   }
> 
> OK, that is straight-forward.  Instead of overriding the
> result->tree upfront, we try the same using a temporary
> replayed_base_tree, and that allows us to see if the resulting tree
> computed by merge_incore matches.  Only when it made a non-empty
> change, we proceed to create a new commit.
> 
>> diff --git a/t/t3650-replay-basics.sh b/t/t3650-replay-basics.sh
>> index cf3aacf3551..9d4b0dd1a77 100755
>> --- a/t/t3650-replay-basics.sh
>> +++ b/t/t3650-replay-basics.sh
>> @@ -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 &&
> 
> The use of "--only" here is a bit curious.  As there is no change
> between the index and the commit our "empty" branch points at,
> wouldn't it be unnecessary?  The option, together with --allow-empty,
> would only matter if you did
> 
> 	git switch -c empty &&
> 	modify blah &&
> 	git add blah &&
> 	git commit --allow-empty --only -m empty
> 
> because without --only, the changes to blah will be taken.
Previous: Junio C HamanoNext: Phillip Wood
Message 8 of 16 in “replay: drop commits that become empty”
  1. replay: drop commits that become emptyPhillip Wood, Nov 27, 2025
  2. Junio C HamanoNov 28, 2025
  3. Phillip WoodDec 4, 2025
  4. Elijah NewrenNov 28, 2025
  5. Phillip WoodDec 4, 2025
  6. replay: drop commits that become emptyPhillip Wood, Dec 15, 2025
  7. Junio C HamanoDec 15, 2025
  8. Phillip WoodDec 16, 2025
  9. Phillip WoodDec 17, 2025
  10. Junio C HamanoDec 17, 2025
  11. Elijah NewrenDec 16, 2025
  12. replay: drop commits that become emptyPhillip Wood, Dec 16, 2025
  13. Elijah NewrenDec 16, 2025
  14. Phillip WoodDec 17, 2025
  15. replay: drop commits that become emptyPhillip Wood, Dec 18, 2025
  16. Junio C HamanoDec 19, 2025

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.