{"thread":{"id":"63012","subject":"git-am doesn't compute intermediate hashes when patch applies cleanly","startedAt":"2025-02-27T09:51:31Z","lastAt":"2025-02-27T09:51:31Z","messageCount":1,"participants":["Nikita Leshenko"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"513139","messageId":"CAEXts1sWBK0HY9PdvsGqq-nxbi0qdkodBV3CNEZ567ji02ZojA@mail.gmail.com","threadId":"63012","inReplyTo":null,"subject":"git-am doesn't compute intermediate hashes when patch applies cleanly","fromName":"Nikita Leshenko","fromEmail":"nikita@island.io","sentAt":"2025-02-27T09:51:17Z","receivedAt":"2025-02-27T09:51:31Z","isPatch":false,"sender":{"key":"nikita@island.io","avatar":null},"body":"Hi,\n(Git 2.48.1)\nImagine this scenario:\n* I have a patch file with two commit, A and B that both touch the same file F.\n* The patch file has hashes on the files (for --3way)\n* I apply the patches with --3way\n* A applies cleanly (even though the file is different)\n* B requires a 3way merge\n\nNow, because A applies cleanly, no fake ancestor was created for F.\nThen, when B fails to apply cleanly, the patch file for F contains\nunknown sha1 hash and the 3way merge fails.\nIn other words, because Git didn't build fake ancestors for A it lost\nthe opportunity to learn about hashes that are relevant for B.\n\nIs there a way to \"force\" using a 3-way merge for all commits, even\nwhen a patch applies cleanly?\n\nHere's a bash script to reproduce the issue:\n\n---- START OF SCRIPT ----\n#!/bin/bash\n\nset -e\n\necho\necho ====================================\necho \"GENERATE PATCH\"\necho ====================================\necho\n\nrm -rf src_repo\ngit -c init.defaultBranch=bug init src_repo\ncd src_repo\n\nprintf \"1\\n2\\n3\\n4\\n5\\n6\\n7\\n8\\n9\" > file\ngit add file\ngit commit -m base\n\nprintf \"11\\n2\\n3\\n4\\n5\\n6\\n7\\n8\\n9\" > file\ngit commit -am first\nprintf \"11\\n2\\n3\\n4\\n5\\n66\\n7\\n8\\n9\" > file\ngit commit -am second\n\ngit format-patch -2 --stdout > test.patch\ncd ..\n\necho\necho ====================================\necho \"SANITY TEST\"\necho \" - apply to indentical file in another repository\"\necho ====================================\necho\n\nrm -rf sanity_repo\ngit -c init.defaultBranch=bug init sanity_repo\ncd sanity_repo\n\nprintf \"1\\n2\\n3\\n4\\n5\\n6\\n7\\n8\\n9\" > file\ngit add file\ngit commit -m \"identical content\"\n\ngit am --3way --keep-cr ../src_repo/test.patch\ncd ..\n\necho\necho ====================================\necho \"GOOD 3-WAY TEST\"\necho \" - apply to modified file in another repository\"\necho \" - have the original file in the repository as well, so that\nsha1 is present\"\necho \" - change the file so that the first commit fails to apply cleanly\"\necho \" - this will force a 3-way merge and the intermediate sha1 will\nbe created\"\necho \" - the second commit will fail to apply cleanly\"\necho \" - this will force a 3-way merge and the intermediate sha1 will\nbe used to create an ancestor\"\necho ====================================\necho\n\nrm -rf good_repo\ngit -c init.defaultBranch=bug init good_repo\ncd good_repo\n\nprintf \"1\\n2\\n3\\n4\\n5\\n6\\n7\\n8\\n9\" > file\ngit add file\ngit commit -m \"identical content\"\n\nprintf \"1\\n2\\n3\\n4XXX\\n5\\n6\\n7\\n8\\n9\" > file\ngit commit -am \"change in hunk\"\n\ngit am --3way --keep-cr ../src_repo/test.patch\ncd ..\n\necho\necho ====================================\necho \"BAD 3-WAY TEST\"\necho \" - apply to modified file in another repository\"\necho \" - have the original file in the repository as well, so that\nsha1 is present\"\necho \" - change the file so that the first commit does apply cleanly\nbut the hashes are different now\"\necho \" - no 3-way merge was performed so the intermediate sha1 is missing\"\necho \" - the second commit will fail to apply cleanly\"\necho \" - this will force a 3-way merge and the git will complain about\nintermediate sha1 error\"\necho ====================================\necho\n\nrm -rf bad_repo\ngit -c init.defaultBranch=bug init bad_repo\ncd bad_repo\n\nprintf \"1\\n2\\n3\\n4\\n5\\n6\\n7\\n8\\n9\" > file\ngit add file\ngit commit -m \"identical content\"\n\nprintf \"1\\n2\\n3\\n4\\n5\\n6\\n7\\n8\\n9XXX\" > file\ngit commit -am \"change outside of hunk\"\n\ngit am --3way --keep-cr ../src_repo/test.patch || echo FAILED!!!\n\ncd ..\n\necho\necho ====================================\necho \"WORKAROUND 3-WAY ISSUE\"\necho \" - demonstrate the patch can in theory be applied\"\necho \" - start with the same report as bad_repo\"\necho \" - first apply the patch to the original commit to reconstruct\nintermediate hashes\"\necho \" - then apply to the latest commit, now it succeeds\"\necho ====================================\necho\n\nrm -rf workaround_repo\ngit -c init.defaultBranch=bug init workaround_repo\ncd workaround_repo\n\nprintf \"1\\n2\\n3\\n4\\n5\\n6\\n7\\n8\\n9\" > file\ngit add file\ngit commit -m \"identical content\"\n\nprintf \"1\\n2\\n3\\n4\\n5\\n6\\n7\\n8\\n9XXX\" > file\ngit commit -am \"change outside of hunk\"\n\ngit checkout @~\ngit am --3way --keep-cr ../src_repo/test.patch\ngit checkout bug\n\ngit am --3way --keep-cr ../src_repo/test.patch\n\ncd ..\n\n---- END OF SCRIPT ----\n"}]}