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

1 messages from 2025-02-27 to 2025-02-27. Participants: Nikita Leshenko.
Thread: https://gitlist.dev/t/63012

## Nikita Leshenko, 2025-02-27 09:51

Subject: git-am doesn't compute intermediate hashes when patch applies cleanly
Message-ID: <CAEXts1sWBK0HY9PdvsGqq-nxbi0qdkodBV3CNEZ567ji02ZojA@mail.gmail.com>
URL: https://gitlist.dev/e/CAEXts1sWBK0HY9PdvsGqq-nxbi0qdkodBV3CNEZ567ji02ZojA%40mail.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 ----

```
