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

git-am doesn't compute intermediate hashes when patch applies cleanly

From
NLNikita Leshenko <nikita@island.io>
Date
Feb 27, 2025, 09:51 UTC
Message-ID
<CAEXts1sWBK0HY9PdvsGqq-nxbi0qdkodBV3CNEZ567ji02ZojA@mail.gmail.com>
Hi,
(Git 2.48.1)
Imagine this scenario:
* I have a patch file with two commit, A and B that both touch the same file F.
* The patch file has hashes on the files (for --3way)
* I apply the patches with --3way
* A applies cleanly (even though the file is different)
* B requires a 3way merge

Now, because A applies cleanly, no fake ancestor was created for F. Then, when B fails to apply cleanly, the patch file for F contains unknown sha1 hash and the 3way merge fails. In other words, because Git didn't build fake ancestors for A it lost the opportunity to learn about hashes that are relevant for B.

Is there a way to "force" using a 3-way merge for all commits, even when a patch applies cleanly?

Here's a bash script to reproduce the issue:

---- START OF SCRIPT ---- #!/bin/bash

set -e

echo echo ==================================== echo "GENERATE PATCH" echo ==================================== echo

rm -rf src_repo git -c init.defaultBranch=bug init src_repo cd src_repo

printf "1\n2\n3\n4\n5\n6\n7\n8\n9" > file git add file git commit -m base

printf "11\n2\n3\n4\n5\n6\n7\n8\n9" > file git commit -am first printf "11\n2\n3\n4\n5\n66\n7\n8\n9" > file git commit -am second

git format-patch -2 --stdout > test.patch cd ..

echo echo ==================================== echo "SANITY TEST" echo " - apply to indentical file in another repository" echo ==================================== echo

rm -rf sanity_repo git -c init.defaultBranch=bug init sanity_repo cd sanity_repo

printf "1\n2\n3\n4\n5\n6\n7\n8\n9" > file git add file git commit -m "identical content"

git am --3way --keep-cr ../src_repo/test.patch cd ..

echo echo ==================================== echo "GOOD 3-WAY TEST" echo " - apply to modified file in another repository" echo " - have the original file in the repository as well, so that sha1 is present" echo " - change the file so that the first commit fails to apply cleanly" echo " - this will force a 3-way merge and the intermediate sha1 will be created" echo " - the second commit will fail to apply cleanly" echo " - this will force a 3-way merge and the intermediate sha1 will be used to create an ancestor" echo ==================================== echo

rm -rf good_repo git -c init.defaultBranch=bug init good_repo cd good_repo

printf "1\n2\n3\n4\n5\n6\n7\n8\n9" > file git add file git commit -m "identical content"

printf "1\n2\n3\n4XXX\n5\n6\n7\n8\n9" > file git commit -am "change in hunk"

git am --3way --keep-cr ../src_repo/test.patch cd ..

echo echo ==================================== echo "BAD 3-WAY TEST" echo " - apply to modified file in another repository" echo " - have the original file in the repository as well, so that sha1 is present" echo " - change the file so that the first commit does apply cleanly but the hashes are different now" echo " - no 3-way merge was performed so the intermediate sha1 is missing" echo " - the second commit will fail to apply cleanly" echo " - this will force a 3-way merge and the git will complain about intermediate sha1 error" echo ==================================== echo

rm -rf bad_repo git -c init.defaultBranch=bug init bad_repo cd bad_repo

printf "1\n2\n3\n4\n5\n6\n7\n8\n9" > file git add file git commit -m "identical content"

printf "1\n2\n3\n4\n5\n6\n7\n8\n9XXX" > file git commit -am "change outside of hunk"

git am --3way --keep-cr ../src_repo/test.patch || echo FAILED!!!
cd ..

echo echo ==================================== echo "WORKAROUND 3-WAY ISSUE" echo " - demonstrate the patch can in theory be applied" echo " - start with the same report as bad_repo" echo " - first apply the patch to the original commit to reconstruct intermediate hashes" echo " - then apply to the latest commit, now it succeeds" echo ==================================== echo

rm -rf workaround_repo git -c init.defaultBranch=bug init workaround_repo cd workaround_repo

printf "1\n2\n3\n4\n5\n6\n7\n8\n9" > file git add file git commit -m "identical content"

printf "1\n2\n3\n4\n5\n6\n7\n8\n9XXX" > file git commit -am "change outside of hunk"

git checkout @~ git am --3way --keep-cr ../src_repo/test.patch git checkout bug

git am --3way --keep-cr ../src_repo/test.patch
cd ..
---- END OF SCRIPT ----
Message 1 of 1 in “git-am doesn't compute intermediate hashes when patch applies cleanly”
  1. Nikita LeshenkoFeb 27, 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.