{"thread":{"id":"64133","subject":"[BUG] git apply misplaces patch when similar code fragments exist in the same file","startedAt":"2025-09-12T13:33:22Z","lastAt":"2025-09-13T07:29:34Z","messageCount":3,"participants":["Guo Tingsheng","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"526185","messageId":"SN6PR03MB428591529FBE9413B427B030AE08A@SN6PR03MB4285.namprd03.prod.outlook.com","threadId":"64133","inReplyTo":null,"subject":"[BUG] git apply misplaces patch when similar code fragments exist in the same file","fromName":"Guo Tingsheng","fromEmail":"coricraft16@outlook.com","sentAt":"2025-09-12T13:33:20Z","receivedAt":"2025-09-12T13:33:22Z","isPatch":false,"sender":{"key":"coricraft16@outlook.com","avatar":null},"body":"Hello Git developers,\n\nI would like to report a potential issue in Git's patch application mechanism, where a patch can be incorrectly applied to a similar but unintended code location if line numbers have shifted.\n\nEnvironment:\n- git version: 2.43.0\n- OS: Ubuntu 24.04 LTS\n\nSteps to reproduce:\n1. Start from Commit_1, containing the following file:\n\n   function HeaderComponent() {\n       return `\n           <div class=\"layout-section\">\n               <button>Click Me</button>\n           </div>\n       `;\n   }\n\n   function FooterComponent() {\n       return `\n           <div class=\"layout-section\">\n               <button>Click Me</button>\n           </div>\n       `;\n   }\n\n2. In another branch, Commit_2 introduces additional import statements before HeaderComponent, shifting its return statement further down (around line 10).  \n   In Commit_2, the button text in HeaderComponent is modified as follows:\n\n   @@ -10,6 +10,6 @@\n        return `\n            <div class=\"layout-section\">\n   -            <button>Click Me</button>\n   +            <button>点击</button>\n            </div>\n        `;\n    }\n\n3. Generate a patch from Commit_2.\n\n4. Apply this patch on top of Commit_1 using:\n   git apply commit2.patch\n\nExpected result:\n- The patch should apply the change to HeaderComponent, modifying its button text.\n\nActual result:\n- The patch is incorrectly applied to FooterComponent instead, producing:\n\n   function HeaderComponent() {\n       return `\n           <div class=\"layout-section\">\n               <button>Click Me</button>\n           </div>\n       `;\n   }\n\n   function FooterComponent() {\n       return `\n           <div class=\"layout-section\">\n               <button>点击</button>\n           </div>\n       `;\n   }\n\nAdditional information:\n- This issue occurs when a file contains multiple similar code fragments, and the patch context fails to match due to line number shifts between commits.\n- As a result, git apply may incorrectly match against the wrong occurrence of the repeated code, introducing unintended changes.\n- This can potentially lead to subtle bugs in real-world projects (e.g., configuration files, HTML/JS components).\n\nThanks,  \nCori\n"},{"id":"526208","messageId":"xmqqfrcrmxan.fsf@gitster.g","threadId":"64133","inReplyTo":"SN6PR03MB428591529FBE9413B427B030AE08A@SN6PR03MB4285.namprd03.prod.outlook.com","subject":"Re: [BUG] git apply misplaces patch when similar code fragments exist in the same file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-09-12T16:48:48Z","receivedAt":"2025-09-12T16:48:51Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Guo Tingsheng <CoriCraft16@outlook.com> writes:\n\n> 2. In another branch, Commit_2 introduces additional import statements before HeaderComponent, shifting its return statement further down (around line 10).  \n>    In Commit_2, the button text in HeaderComponent is modified as follows:\n>\n>    @@ -10,6 +10,6 @@\n>         return `\n>             <div class=\"layout-section\">\n>    -            <button>Click Me</button>\n>    +            <button>点击</button>\n>             </div>\n>         `;\n>     }\n\nThis hunk shown here may be a fabrication (it only has two\npre-context but three post-context lines, which is unusual unless\nthe shorter one is at the end of the file), but in any case, a patch\nhunk above is applied to a location that has exactly these lines:\n\n        return `\n            <div class=\"layout-section\">\n                <button>Click Me</button>\n            </div>\n        `;\n    }\n\nthat is the closest to line #10.\n\nIf there are more than one places in the target file that the\npreimage (i.e. the context lines that are shown with \" \" at the\nbeginning, and the preimage lines that are shown with \"-\" at the\nbeginning) would match, the patch is ambiguous.\n\nIt is very much expected, depending on what other changes have\nhappened to the target file since they diverged to make the matching\nplaces move from the original place, it would be applied to a\n\"wrong\" place by chance, as the preimage does not uniquely identify\nwhere the patch hunk should to be applied in such a situation.\n\nYou can generate a patch with wider context if you can _anticipate_\nthe issue (for example, you may _know_ that commit-1 already had\nmultiple lines that match the preimage in the hunk before running\n\"git diff\" or \"git format-patch\") to give it a better chance to be\nunambiguous, e.g. \"git diff -U8\".  But in general it is impossible\nto guarantee that your preimage in the hunk will be and stay to be\nunambiguous.  After all, the receiving end can make independent\nchanges that happen to match the preimage the patch is looking for,\nno matter how wide the context you pick when you generate your\npatch.\n\nIt might be a good starter project for aspiring Git developers to\nteach \"git apply\" to notice this situation and warn about it.  The\ntool cannot by definition to always pick the right place to patch,\nbut the tool should be able to recognise a situation where a patch\nhunk is ambiguous and can apply to multiple places in the target and\nlet you know about it.\n\n"},{"id":"526240","messageId":"BYAPR03MB4280844D32D821EFF98AE9A6AE0BA@BYAPR03MB4280.namprd03.prod.outlook.com","threadId":"64133","inReplyTo":"xmqqfrcrmxan.fsf@gitster.g","subject":"回复: [BUG] git apply misplaces patch when similar code fragments exist in the same file","fromName":"Guo Tingsheng","fromEmail":"coricraft16@outlook.com","sentAt":"2025-09-13T07:29:31Z","receivedAt":"2025-09-13T07:29:34Z","isPatch":false,"sender":{"key":"coricraft16@outlook.com","avatar":null},"body":"Hi Junio,\n\n> This hunk shown here may be a fabrication (it only has two\n> pre-context but three post-context lines, which is unusual unless\n> the shorter one is at the end of the file),\n\nYes, you are right. The example I showed earlier was man-made, in order to illustrate the issue more clearly. The real case is longer, and I will show it at the end of this mail.\n\nThe scenario where I observed this bug is as follows:  \nI pick two adjacent commits A (earlier) and B (later) from Git history. Using A as the base, I extract the changes introduced by B into a patch. Then I split this patch into two smaller patches by dividing hunks randomly, and apply them separately onto A to create two branches. Finally, I merge these two branches, and compare the merged result against commit B to verify merge correctness.\n\nIn this process, each branch’s patch is directly cut from B’s patch. The line numbers in each hunk still describe the positions relative to B vs. A. However, since each branch only carries a subset of B’s hunks, the line numbers may no longer correspond exactly to the right positions. As a result, Git falls back to fuzzy matching, and in cases where there are similar code fragments, the patch may be applied to the wrong location.\n\n> After all, the receiving end can make independent\n> changes that happen to match the preimage the patch is looking for,\n> no matter how wide the context you pick when you generate your\n> patch.\n\nI fully agree with your point: no matter how much context we include, we cannot absolutely guarantee precise matching, because the branches may have independent changes. Therefore, I think your suggestion of emitting warnings in potentially ambiguous situations would be very helpful.\n\nBelow is a real example I observed:\n\nBranch 1 change:\n@@ -131,7 +145,7 @@ public class ExcelWriter {\n     }\n \n     /**\n-     * Write data to a sheet\n+     * Write data(List<List<String>>) to a sheet\n      * @param data  Data to be written\n      * @param sheet Write to this sheet\n      * @param table Write to this table\n\nBranch 2 change:\n@@ -156,7 +170,7 @@ public class ExcelWriter {\n     }\n \n     /**\n-     * Write data to a sheet\n+     * Write data(List<List<Object>>) to a sheet\n      * @param data  Data to be written\n      * @param sheet Write to this sheet\n      * @param table Write to this table\n\nMerging these two branches and comparing the result with commit B using `git diff` gives:\n\ndiff --git a/src/main/java/com/alibaba/excel/ExcelWriter.java b/src/main/java/com/alibaba/excel/ExcelWriter.java\nindex e4061e0e..91c34a63 100644\n--- a/src/main/java/com/alibaba/excel/ExcelWriter.java\n+++ b/src/main/java/com/alibaba/excel/ExcelWriter.java\n@@ -145,7 +145,7 @@ public class ExcelWriter {\n     }\n \n     /**\n-     * Write data(List<List<String>>) to a sheet\n+     * Write data(List<List<Object>>) to a sheet\n      * @param data  Data to be written\n      * @param sheet Write to this sheet\n      * @param table Write to this table\n@@ -170,7 +170,7 @@ public class ExcelWriter {\n     }\n \n     /**\n-     * Write data(List<List<Object>>) to a sheet\n+     * Write data(List<List<String>>) to a sheet\n      * @param data  Data to be written\n      * @param sheet Write to this sheet\n      * @param table Write to this table\n\nAs shown, the comment intended for line 145 (`List<List<String>>`) was incorrectly applied at line 170, and the one intended for line 170 (`List<List<Object>>`) was misplaced at line 145. This demonstrates how fuzzy matching can misapply patches when similar fragments exist.\n\nThanks,\nCori\n________________________________________\n发件人: Junio C Hamano <gitster@pobox.com>\n发送时间: 2025年9月13日 0:48\n收件人: Guo Tingsheng <CoriCraft16@outlook.com>\n抄送: git@vger.kernel.org <git@vger.kernel.org>\n主题: Re: [BUG] git apply misplaces patch when similar code fragments exist in the same file\n \nGuo Tingsheng <CoriCraft16@outlook.com> writes:\n\n> 2. In another branch, Commit_2 introduces additional import statements before HeaderComponent, shifting its return statement further down (around line 10). \n>    In Commit_2, the button text in HeaderComponent is modified as follows:\n>\n>    @@ -10,6 +10,6 @@\n>         return `\n>             <div class=\"layout-section\">\n>    -            <button>Click Me</button>\n>    +            <button>点击</button>\n>             </div>\n>         `;\n>     }\n\nThis hunk shown here may be a fabrication (it only has two\npre-context but three post-context lines, which is unusual unless\nthe shorter one is at the end of the file), but in any case, a patch\nhunk above is applied to a location that has exactly these lines:\n\n        return `\n            <div class=\"layout-section\">\n                <button>Click Me</button>\n            </div>\n        `;\n    }\n\nthat is the closest to line #10.\n\nIf there are more than one places in the target file that the\npreimage (i.e. the context lines that are shown with \" \" at the\nbeginning, and the preimage lines that are shown with \"-\" at the\nbeginning) would match, the patch is ambiguous.\n\nIt is very much expected, depending on what other changes have\nhappened to the target file since they diverged to make the matching\nplaces move from the original place, it would be applied to a\n\"wrong\" place by chance, as the preimage does not uniquely identify\nwhere the patch hunk should to be applied in such a situation.\n\nYou can generate a patch with wider context if you can _anticipate_\nthe issue (for example, you may _know_ that commit-1 already had\nmultiple lines that match the preimage in the hunk before running\n\"git diff\" or \"git format-patch\") to give it a better chance to be\nunambiguous, e.g. \"git diff -U8\".  But in general it is impossible\nto guarantee that your preimage in the hunk will be and stay to be\nunambiguous.  After all, the receiving end can make independent\nchanges that happen to match the preimage the patch is looking for,\nno matter how wide the context you pick when you generate your\npatch.\n\nIt might be a good starter project for aspiring Git developers to\nteach \"git apply\" to notice this situation and warn about it.  The\ntool cannot by definition to always pick the right place to patch,\nbut the tool should be able to recognise a situation where a patch\nhunk is ambiguous and can apply to multiple places in the target and\nlet you know about it.\n"}]}