{"thread":{"id":"63297","subject":"git merge bug report","startedAt":"2025-04-15T12:23:44Z","lastAt":"2025-04-15T16:20:58Z","messageCount":4,"participants":["mu gsh","Junio C Hamano","Lucas Seiki Oshiro"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"516192","messageId":"CAE8aReXOwM8ByyObxrb8NhRMYfK1OB_6B9eOO07mYXMkp_E8EA@mail.gmail.com","threadId":"63297","inReplyTo":null,"subject":"git merge bug report","fromName":"mu gsh","fromEmail":"yue937@gmail.com","sentAt":"2025-04-15T12:23:30Z","receivedAt":"2025-04-15T12:23:44Z","isPatch":false,"sender":{"key":"yue937@gmail.com","avatar":null},"body":"Dear Git Maintainers,\n\nI would like to report a bug I encountered in Git during a merge\noperation. The method from one branch was merged into the wrong class,\ndespite there being no reported conflict.\n\nGit Version: git version 2.49.0\nOperating System: Arch Linux\n\nDescription:\nWhen merging two commits involving changes to the same file, Git does\nnot report a conflict, but the resulting merged file places a method\nin an unexpected class. This seems like a mismerge.\n\n\nSteps to Reproduce\nYou can reproduce the issue using the following shell script:\n```\n#!/bin/bash\n\nset -e\n\n# init in /tmp dir\nrm -rf /tmp/git-merge-bug\nmkdir -p /tmp/git-merge-bug && cd /tmp/git-merge-bug\ngit init\ncat > models.py <<EOF\nclass User:\n    name = \"str\"\n\n\nclass Product:\n    id = 0\nEOF\ngit add models.py\ngit commit -m \"initial: User and Product class\"\n\n# feature1\ngit checkout -b feature\ncat > models.py <<EOF\nclass User:\n    name = \"str\"\n\n    def user_method(self):\n        return\n\n\nclass Product:\n    id = 0\nEOF\ngit commit -am \"feature: add method to User\"\n\n# feature 2\ngit checkout master\ncat > models.py <<EOF\nclass User:\n    name = \"str\"\n    bugger = \"fix me\"\n\n\nclass NoMethod:\n    pass\n\n\nclass Product:\n    id = 0\nEOF\ngit commit -am \"master: add field to User and new class\"\n\ngit merge feature\necho\necho \"==== merged, user_method into NoMethod class  ====\"\ncat models.py\n```\n\nActual Result\n\nAfter the merge, the user_method ends up inside the NoMethod class,\nwhich is incorrect and unexpected.\n\n\nPlease let me know if any additional information is needed. Thank you\nfor your time and help.\n\n\nBest regards,\n\ngshmu\n"},{"id":"516196","messageId":"xmqqtt6po7lj.fsf@gitster.g","threadId":"63297","inReplyTo":"CAE8aReXOwM8ByyObxrb8NhRMYfK1OB_6B9eOO07mYXMkp_E8EA@mail.gmail.com","subject":"Re: git merge bug report","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-04-15T13:52:08Z","receivedAt":"2025-04-15T13:52:10Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"mu gsh <yue937@gmail.com> writes:\n\n> cat > models.py <<EOF\n> class User:\n>     name = \"str\"\n>\n>\n> class Product:\n>     id = 0\n> EOF\n> git add models.py\n> git commit -m \"initial: User and Product class\"\n>\n> # feature1\n> git checkout -b feature\n> cat > models.py <<EOF\n> class User:\n>     name = \"str\"\n>\n>     def user_method(self):\n>         return\n>\n>\n> class Product:\n>     id = 0\n> EOF\n> git commit -am \"feature: add method to User\"\n>\n> # feature 2\n> git checkout master\n> cat > models.py <<EOF\n> class User:\n>     name = \"str\"\n>     bugger = \"fix me\"\n>\n>\n> class NoMethod:\n>     pass\n>\n>\n> class Product:\n>     id = 0\n> EOF\n> git commit -am \"master: add field to User and new class\"\n>\n> git merge feature\n> echo\n> echo \"==== merged, user_method into NoMethod class  ====\"\n> cat models.py\n> ```\n>\n> Actual Result\n>\n> After the merge, the user_method ends up inside the NoMethod class,\n> which is incorrect and unexpected.\n>\n>\n> Please let me know if any additional information is needed. Thank you\n> for your time and help.\n\nI think this is very much expected, unfortunately.  Git is language\nagnostic in the sense that it does not know the meaning of the\ncontents of the file it is thrown at.  With the merge, what it was\nasked to do is:\n\n - The other branch, \"feature1\", added three lines, an empty\n   user_method() definition and a blank line around it, before\n   lines that have 'class product:' and '  id = 0' (or after lines\n   that have 'class User:' and '  name = str' followed by a blank\n   line).\n\n - In the meantime, you added some stuff in feature2.\n\n - Please replay what the other branch did on top of what we have.\n\nBut after your feature2, the precontext lines that it can use as an\nanchor no longer exist (the blank line after 'class User:' and '\nname = str' is gone). while the post context lines (\"blank followed\nby 'class Product: followed by 'id = 0'\") are still intact.\nWiggling the added three lines there would be a more natural choice\nthan having to deal with \"bugger = 'fix me'\" whose disposition is\ntotally unclear to unthinking non-mind that is a mechanical merge\nmachinery in Git.\n\n"},{"id":"516197","messageId":"39551FA4-855C-4E55-BC2B-F77D9BBCCF6A@gmail.com","threadId":"63297","inReplyTo":"CAE8aReXOwM8ByyObxrb8NhRMYfK1OB_6B9eOO07mYXMkp_E8EA@mail.gmail.com","subject":"Re: git merge bug report","fromName":"Lucas Seiki Oshiro","fromEmail":"lucasseikioshiro@gmail.com","sentAt":"2025-04-15T14:13:35Z","receivedAt":"2025-04-15T14:13:52Z","isPatch":false,"sender":{"key":"lucasseikioshiro@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12701580?v=4"},"body":"Hi!\n\n> I would like to report a bug I encountered in Git during a merge\n> operation. The method from one branch was merged into the wrong class,\n> despite there being no reported conflict.\n\nThanks for your script! I could reproduce this here!\n\nWhen two branches changes the same plaintext file, Git tries to merge\nthem based on their contents without taking into account the syntax.\nIt is done using diff algorithms, which you can change using\n`-X diff-algorithm=<algorithm>`.\n\nI tried the four algorithms available (minimal, histogram, myers and\npatience) and all of them produced the same result.\n\nSadly, they are not infallible and those mistakes may happen. There\nare other cases where it can happen. For example, imagine a Python\nclass with only two methods and each branch deletes one of them.\nAfter merging, it will leave an empty class definition, which is not\nallowed in Python (unless you use `pass`). These algorithms are not\naware of that, and they'll leave an invalid Python file.\n\nAlso note that they are not exactly wrong. They only do their work\nnaively based on the information they have.\n\nThis way, it's always a good idea to check if the merge went well.\n"},{"id":"516208","messageId":"CAE8aReUm2rCR76L2T175Ng5Pir+-G_a4whxiOPhfvNzXSV_d2Q@mail.gmail.com","threadId":"63297","inReplyTo":"39551FA4-855C-4E55-BC2B-F77D9BBCCF6A@gmail.com","subject":"Re: git merge bug report","fromName":"mu gsh","fromEmail":"yue937@gmail.com","sentAt":"2025-04-15T16:20:46Z","receivedAt":"2025-04-15T16:20:58Z","isPatch":false,"sender":{"key":"yue937@gmail.com","avatar":null},"body":"Hi!\n\nfocus on the feature 2, the two double empty lines, which one is the new one?\n```\n    bugger = \"fix: the empty lines blow not the new added lines\"\n\n\nclass NoMethod:\n    pass\n\n\nclass Product\n```\n\nShould the second one be newly added? instead of the first\n\nOn Tue, 15 Apr 2025 at 22:13, Lucas Seiki Oshiro\n<lucasseikioshiro@gmail.com> wrote:\n>\n> Hi!\n>\n> > I would like to report a bug I encountered in Git during a merge\n> > operation. The method from one branch was merged into the wrong class,\n> > despite there being no reported conflict.\n>\n> Thanks for your script! I could reproduce this here!\n>\n> When two branches changes the same plaintext file, Git tries to merge\n> them based on their contents without taking into account the syntax.\n> It is done using diff algorithms, which you can change using\n> `-X diff-algorithm=<algorithm>`.\n>\n> I tried the four algorithms available (minimal, histogram, myers and\n> patience) and all of them produced the same result.\n>\n> Sadly, they are not infallible and those mistakes may happen. There\n> are other cases where it can happen. For example, imagine a Python\n> class with only two methods and each branch deletes one of them.\n> After merging, it will leave an empty class definition, which is not\n> allowed in Python (unless you use `pass`). These algorithms are not\n> aware of that, and they'll leave an invalid Python file.\n>\n> Also note that they are not exactly wrong. They only do their work\n> naively based on the information they have.\n>\n> This way, it's always a good idea to check if the merge went well.\n"}]}