{"thread":{"id":"48041","subject":"How to debug a \"git merge\"?","startedAt":"2018-03-14T16:56:14Z","lastAt":"2018-03-20T01:32:57Z","messageCount":8,"participants":["Lars Schneider","Derrick Stolee","Jeff King","Elijah Newren"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"341640","messageId":"7895279B-9FB6-471B-A8BA-53315B265A51@gmail.com","threadId":"48041","inReplyTo":null,"subject":"How to debug a \"git merge\"?","fromName":"Lars Schneider","fromEmail":"larsxschneider@gmail.com","sentAt":"2018-03-14T16:56:04Z","receivedAt":"2018-03-14T16:56:14Z","isPatch":false,"sender":{"key":"larsxschneider@gmail.com","avatar":"https://avatars.githubusercontent.com/u/477434?v=4"},"body":"Hi,\n\nI am investigating a Git merge (a86dd40fe) in which an older version of \na file won over the newer version. I try to understand why this is the \ncase. I can reproduce the merge with the following commands:\n$ git checkout -b test a02fa3303\n$ GIT_MERGE_VERBOSITY=5 git merge --verbose c1b82995c\n\nThe merge actually generates a merge conflict but not for my\nproblematic file. The common ancestor of the two parents (merge base) \nis b91161554.\n\nThe merge graph is not pretty (the committers don't have a clean \nbranching scheme) but I cannot spot a problem between the merge commit\nand the common ancestor:\n$ git log --graph --oneline a86dd40fe\n\nCan you give me a hint how to debug this merge further? How can I \nunderstand why Git picked a certain version of a file in a merge?\n\nI am using Git 2.16.2 on Linux.\n\nThanks,\nLars\n"},{"id":"341642","messageId":"ddde09e9-0524-23f8-3585-ac00c2ec7f45@gmail.com","threadId":"48041","inReplyTo":"7895279B-9FB6-471B-A8BA-53315B265A51@gmail.com","subject":"Re: How to debug a \"git merge\"?","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2018-03-14T17:02:21Z","receivedAt":"2018-03-14T17:02:53Z","isPatch":false,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 3/14/2018 12:56 PM, Lars Schneider wrote:\n> Hi,\n>\n> I am investigating a Git merge (a86dd40fe) in which an older version of\n> a file won over the newer version. I try to understand why this is the\n> case. I can reproduce the merge with the following commands:\n> $ git checkout -b test a02fa3303\n> $ GIT_MERGE_VERBOSITY=5 git merge --verbose c1b82995c\n>\n> The merge actually generates a merge conflict but not for my\n> problematic file. The common ancestor of the two parents (merge base)\n> is b91161554.\n>\n> The merge graph is not pretty (the committers don't have a clean\n> branching scheme) but I cannot spot a problem between the merge commit\n> and the common ancestor:\n> $ git log --graph --oneline a86dd40fe\n\nHave you tried `git log --graph --oneline --simplify-merges -- path` to \nsee what changes and merges involved the file? I find that view to be \nvery helpful (while the default history simplification can hide things). \nIn particular, if there was a change that was reverted in one side and \nnot another, we could find out.\n\nYou could also use the \"A...B\" to check your two commits for merging, \nand maybe add \"--boundary\".\n\n>\n> Can you give me a hint how to debug this merge further? How can I\n> understand why Git picked a certain version of a file in a merge?\n>\n> I am using Git 2.16.2 on Linux.\n>\n> Thanks,\n> Lars\n\n"},{"id":"341710","messageId":"77D50EDA-6262-4288-B6E7-87BE63EFB54F@gmail.com","threadId":"48041","inReplyTo":"ddde09e9-0524-23f8-3585-ac00c2ec7f45@gmail.com","subject":"Re: How to debug a \"git merge\"?","fromName":"Lars Schneider","fromEmail":"larsxschneider@gmail.com","sentAt":"2018-03-14T20:53:31Z","receivedAt":"2018-03-14T20:53:41Z","isPatch":false,"sender":{"key":"larsxschneider@gmail.com","avatar":"https://avatars.githubusercontent.com/u/477434?v=4"},"body":"\n> On 14 Mar 2018, at 18:02, Derrick Stolee <stolee@gmail.com> wrote:\n> \n> On 3/14/2018 12:56 PM, Lars Schneider wrote:\n>> Hi,\n>> \n>> I am investigating a Git merge (a86dd40fe) in which an older version of\n>> a file won over the newer version. I try to understand why this is the\n>> case. I can reproduce the merge with the following commands:\n>> $ git checkout -b test a02fa3303\n>> $ GIT_MERGE_VERBOSITY=5 git merge --verbose c1b82995c\n>> \n>> The merge actually generates a merge conflict but not for my\n>> problematic file. The common ancestor of the two parents (merge base)\n>> is b91161554.\n>> \n>> The merge graph is not pretty (the committers don't have a clean\n>> branching scheme) but I cannot spot a problem between the merge commit\n>> and the common ancestor:\n>> $ git log --graph --oneline a86dd40fe\n> \n> Have you tried `git log --graph --oneline --simplify-merges -- path` to see what changes and merges involved the file? I find that view to be very helpful (while the default history simplification can hide things). In particular, if there was a change that was reverted in one side and not another, we could find out.\n\nThanks for this tip! Unfortunately, this only confirms my current view:\n\n### First parent\n$ git log --graph --oneline --simplify-merges a02fa3303 -- path/to/problem\n* 4e47a10c7 <-- old version\n* 01f01f61c \n\n### Second parent\n$ git log --graph --oneline --simplify-merges c1b82995c -- path/to/problem\n* 590e52ed1 <-- new version\n* 8e598828d \n* ad4e9034b \n* 4e47a10c7 \n* 01f01f61c \n\n### Merge\n$ git log --graph --oneline --simplify-merges a86dd40fe -- path/to/problem\n*   a86dd40fe <-- old version ?!?! That's the problem!\n|\\\n| * 590e52ed1 <-- new version\n| * 8e598828d\n| * ad4e9034b\n|/\n* 4e47a10c7 <-- old version\n* 01f01f61c\n\n\n> You could also use the \"A...B\" to check your two commits for merging, and maybe add \"--boundary\".\n\n$ git diff --boundary a02fa3303...c1b82995c -- path/to/problem\n\nThis looks like the correct diff. The \"new version\" is mark as +/add/green in the diff.\n\nDoes this make any sense to you?\n\nThank you,\nLars"},{"id":"341723","messageId":"20180314222028.GA20977@sigill.intra.peff.net","threadId":"48041","inReplyTo":"7895279B-9FB6-471B-A8BA-53315B265A51@gmail.com","subject":"Re: How to debug a \"git merge\"?","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-03-14T22:20:29Z","receivedAt":"2018-03-14T22:20:35Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Mar 14, 2018 at 05:56:04PM +0100, Lars Schneider wrote:\n\n> I am investigating a Git merge (a86dd40fe) in which an older version of \n> a file won over the newer version. I try to understand why this is the \n> case. I can reproduce the merge with the following commands:\n> $ git checkout -b test a02fa3303\n> $ GIT_MERGE_VERBOSITY=5 git merge --verbose c1b82995c\n> \n> The merge actually generates a merge conflict but not for my\n> problematic file. The common ancestor of the two parents (merge base) \n> is b91161554.\n> \n> The merge graph is not pretty (the committers don't have a clean \n> branching scheme) but I cannot spot a problem between the merge commit\n> and the common ancestor:\n> $ git log --graph --oneline a86dd40fe\n> \n> Can you give me a hint how to debug this merge further? How can I \n> understand why Git picked a certain version of a file in a merge?\n\nMaybe a stupid question, but: did you make sure that the merge does\nindeed pick the wrong version of the file? The other option is that\nsomebody mistakenly did a \"checkout --ours\" or similar while resolving\nthe conflict.\n\nIf the wrong file is indeed picked by the merge, then you may want to\ntry switching merge drivers. E.g., \"-s resolve\" is a bit simpler and\nstupider than the default merge-recursive. If the problem goes away,\nthen we know it's a possible bug in merge-recursive (or maybe a\nconfusing implication of its strategy). If the problem is still there\nwith \"resolve\", then at least it may be easier to debug. ;)\n\n-Peff\n"},{"id":"341739","messageId":"1632E897-B434-4ECC-A236-49C03398DF55@gmail.com","threadId":"48041","inReplyTo":"20180314222028.GA20977@sigill.intra.peff.net","subject":"Re: How to debug a \"git merge\"?","fromName":"Lars Schneider","fromEmail":"larsxschneider@gmail.com","sentAt":"2018-03-15T09:51:27Z","receivedAt":"2018-03-15T09:51:37Z","isPatch":false,"sender":{"key":"larsxschneider@gmail.com","avatar":"https://avatars.githubusercontent.com/u/477434?v=4"},"body":"\n> On 14 Mar 2018, at 23:20, Jeff King <peff@peff.net> wrote:\n> \n> On Wed, Mar 14, 2018 at 05:56:04PM +0100, Lars Schneider wrote:\n> \n>> I am investigating a Git merge (a86dd40fe) in which an older version of \n>> a file won over the newer version. I try to understand why this is the \n>> case. I can reproduce the merge with the following commands:\n>> $ git checkout -b test a02fa3303\n>> $ GIT_MERGE_VERBOSITY=5 git merge --verbose c1b82995c\n>> \n>> The merge actually generates a merge conflict but not for my\n>> problematic file. The common ancestor of the two parents (merge base) \n>> is b91161554.\n>> \n>> The merge graph is not pretty (the committers don't have a clean \n>> branching scheme) but I cannot spot a problem between the merge commit\n>> and the common ancestor:\n>> $ git log --graph --oneline a86dd40fe\n>> \n>> Can you give me a hint how to debug this merge further? How can I \n>> understand why Git picked a certain version of a file in a merge?\n> \n> Maybe a stupid question, but: did you make sure that the merge does\n> indeed pick the wrong version of the file? The other option is that\n> somebody mistakenly did a \"checkout --ours\" or similar while resolving\n> the conflict.\n\nNo stupid question at all. That's exactly what they did and I did not\nrealize it! Thank you!\n\nNext time I won't stumble over this. I wonder if this is a common enough\nproblem to do something about it? For instance what if `git log` (or just\n`git show`) has an option `--verify-merges` or `--reenact-merges` or \nsomething? This option would perform a \"default recursive merge\" and \nshow the diff between the actual merge and the default merge?\n\nIn the most common case there is no diff. If there are merge conflicts\nthen we would just show the conflicting files. If there is no merge\nconflict for a file *but* a difference then we would show it. I think\nthis would have helped me to realize this kind of problem earlier.\n\nWould that option make sense to you?\n\nThanks,\nLars\n"},{"id":"341746","messageId":"20180315140921.GA27748@sigill.intra.peff.net","threadId":"48041","inReplyTo":"1632E897-B434-4ECC-A236-49C03398DF55@gmail.com","subject":"Re: How to debug a \"git merge\"?","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-03-15T14:09:21Z","receivedAt":"2018-03-15T14:09:30Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Mar 15, 2018 at 10:51:27AM +0100, Lars Schneider wrote:\n\n> > Maybe a stupid question, but: did you make sure that the merge does\n> > indeed pick the wrong version of the file? The other option is that\n> > somebody mistakenly did a \"checkout --ours\" or similar while resolving\n> > the conflict.\n> \n> No stupid question at all. That's exactly what they did and I did not\n> realize it! Thank you!\n\nOh good. :) I have run across this same situation before myself, which\nis why I thought to ask about it.\n\n> Next time I won't stumble over this. I wonder if this is a common enough\n> problem to do something about it? For instance what if `git log` (or just\n> `git show`) has an option `--verify-merges` or `--reenact-merges` or \n> something? This option would perform a \"default recursive merge\" and \n> show the diff between the actual merge and the default merge?\n> \n> In the most common case there is no diff. If there are merge conflicts\n> then we would just show the conflicting files. If there is no merge\n> conflict for a file *but* a difference then we would show it. I think\n> this would have helped me to realize this kind of problem earlier.\n> \n> Would that option make sense to you?\n\nYes, it's absolutely a good idea, and a frequent wish-list item. The\nproblem is that it's tricky to implement. The only working patches I\nknow of were Thomas Rast's \"--remerge-diff\" from 2014:\n\n  https://public-inbox.org/git/cover.1409860234.git.tr@thomasrast.ch/\n\nThe tricky thing is that you have to actually re-run the diff, and we\ndon't know what options were used for the original diff (e.g., what\nstrategy). And also, merge-recursive really wants to have a valid\nworking tree (though I think maybe that has gotten better over the\nyears).\n\nBut even with those warts, I still found it useful in many cases.\n\n-Peff\n"},{"id":"341754","messageId":"CABPp-BEsTOZ-tCvG1y5a0qPB8xJLLa0obyTU===mBgXC1jXgFA@mail.gmail.com","threadId":"48041","inReplyTo":"20180315140921.GA27748@sigill.intra.peff.net","subject":"Re: How to debug a \"git merge\"?","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-03-15T15:51:43Z","receivedAt":"2018-03-15T15:51:50Z","isPatch":false,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Thu, Mar 15, 2018 at 7:09 AM, Jeff King <peff@peff.net> wrote:\n> On Thu, Mar 15, 2018 at 10:51:27AM +0100, Lars Schneider wrote:\n>> Next time I won't stumble over this. I wonder if this is a common enough\n>> problem to do something about it? For instance what if `git log` (or just\n>> `git show`) has an option `--verify-merges` or `--reenact-merges` or\n>> something? This option would perform a \"default recursive merge\" and\n>> show the diff between the actual merge and the default merge?\n>>\n>> In the most common case there is no diff. If there are merge conflicts\n>> then we would just show the conflicting files. If there is no merge\n>> conflict for a file *but* a difference then we would show it. I think\n>> this would have helped me to realize this kind of problem earlier.\n>>\n>> Would that option make sense to you?\n>\n> Yes, it's absolutely a good idea, and a frequent wish-list item. The\n> problem is that it's tricky to implement. The only working patches I\n> know of were Thomas Rast's \"--remerge-diff\" from 2014:\n>\n>   https://public-inbox.org/git/cover.1409860234.git.tr@thomasrast.ch/\n>\n> The tricky thing is that you have to actually re-run the diff, and we\n> don't know what options were used for the original diff (e.g., what\n> strategy). And also, merge-recursive really wants to have a valid\n> working tree (though I think maybe that has gotten better over the\n> years).\n\nmerge-recursive's working tree reliance has gotten better, though work\nremains.  I'll get back to it, eventually.  :-)\n\nThere's also a third issue which I think makes this feature difficult\n(though not intractable): some conflict types might be difficult to\nrepresent in such a diff.  For those interested in the details\n\nIn particular, at the basic level I'm thinking of conflict types such\nas modify/delete, rename/rename(1to2), and directory/file conflicts.\nIt appears Thomas Rast's series would resolve all of these by doing a\ntwo-way diff against /dev/null for each un-paired but conflicted path.\nPerhaps that's good enough, but it does lose a lot of semantic content\n(is this conflict because this was an add/add conflict where one side\nwas an empty file, or did one side of history delete the path, or did\nthe other side of history rename the path elsewhere, or did one side\nhave a directory in the way?).  This semantic content isn't stored\nanywhere in merge-recursive; it's simply printed with a \"CONFLICT\"\nmessage to the screen when it runs across the path, so there'd be a\nlittle work involved in re-plumbing that.  Also, directory rename\ndetection adds implicit renames that add a few more conflict types\nthat could fall in this set (\"Existing file/dir in the way of implicit\nrename for path\", and \"Cannot map more than one path to %s from\nimplicit renames\").  There's also one it adds that maybe could map to\nthis type of solution but it'd take some work (\"directory rename\nsplit\").\n\nTo make matters worse, there are also multiply-conflicted types that\nare possible that may make matters even more difficult for a --remerge\ndiff.  For example, the files involved in a rename/rename(2to1) could\nalso be involved in a rename/delete.  Another that came up on the list\nyesterday is that both rename/add and rename/delete conflicts can\nhappen on the same pair.  I think merge-recursive doesn't even detect\nthese and mis-handles both in the normal case, the --remerge-diff\nwould just be even more tricky.  There are also a couple new\nmultiple-conflict-types that are handled fine for the normal merge\ncase but might make a remerge-diff more complex.  Two examples I can\nthink of are (1) if a path is involved in a rename/delete, and the\nrenamed side should get a transitive renaming due to the directory it\ngetting renamed into having been renamed on the other side of history,\nbut there's a path in the way of the implicit rename, or (2) if a path\nis involved in a modify/delete and should be implicitly renamed due to\na directory rename but there are several paths that need to be\nimplicitly renamed to the same location.\n\nHowever, to end on a bit of good news, this week's decision to make\nrename/rename(2to1) and rename/add both behave more like add/add will\nsimplify matters for implementing --remerge-diff.\n"},{"id":"342270","messageId":"b852dc0d-f601-f36a-c996-b3395a3cb3fd@gmail.com","threadId":"48041","inReplyTo":"77D50EDA-6262-4288-B6E7-87BE63EFB54F@gmail.com","subject":"Re: How to debug a \"git merge\"?","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2018-03-20T01:32:36Z","receivedAt":"2018-03-20T01:32:57Z","isPatch":false,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 3/14/2018 4:53 PM, Lars Schneider wrote:\n>> On 14 Mar 2018, at 18:02, Derrick Stolee <stolee@gmail.com> wrote:\n>>\n>> On 3/14/2018 12:56 PM, Lars Schneider wrote:\n>>> Hi,\n>>>\n>>> I am investigating a Git merge (a86dd40fe) in which an older version of\n>>> a file won over the newer version. I try to understand why this is the\n>>> case. I can reproduce the merge with the following commands:\n>>> $ git checkout -b test a02fa3303\n>>> $ GIT_MERGE_VERBOSITY=5 git merge --verbose c1b82995c\n>>>\n>>> The merge actually generates a merge conflict but not for my\n>>> problematic file. The common ancestor of the two parents (merge base)\n>>> is b91161554.\n>>>\n>>> The merge graph is not pretty (the committers don't have a clean\n>>> branching scheme) but I cannot spot a problem between the merge commit\n>>> and the common ancestor:\n>>> $ git log --graph --oneline a86dd40fe\n>> Have you tried `git log --graph --oneline --simplify-merges -- path` to see what changes and merges involved the file? I find that view to be very helpful (while the default history simplification can hide things). In particular, if there was a change that was reverted in one side and not another, we could find out.\n> Thanks for this tip! Unfortunately, this only confirms my current view:\n>\n> ### First parent\n> $ git log --graph --oneline --simplify-merges a02fa3303 -- path/to/problem\n> * 4e47a10c7 <-- old version\n> * 01f01f61c\n>\n> ### Second parent\n> $ git log --graph --oneline --simplify-merges c1b82995c -- path/to/problem\n> * 590e52ed1 <-- new version\n> * 8e598828d\n> * ad4e9034b\n> * 4e47a10c7\n> * 01f01f61c\n>\n> ### Merge\n> $ git log --graph --oneline --simplify-merges a86dd40fe -- path/to/problem\n> *   a86dd40fe <-- old version ?!?! That's the problem!\n> |\\\n> | * 590e52ed1 <-- new version\n> | * 8e598828d\n> | * ad4e9034b\n> |/\n> * 4e47a10c7 <-- old version\n> * 01f01f61c\n>\n>\n>> You could also use the \"A...B\" to check your two commits for merging, and maybe add \"--boundary\".\n> $ git diff --boundary a02fa3303...c1b82995c -- path/to/problem\n>\n> This looks like the correct diff. The \"new version\" is mark as +/add/green in the diff.\n>\n> Does this make any sense to you?\n>\n> Thank you,\n> Lars\n\nI'm sorry for the delay on this, but in my experience in helping \ncustomers saying \"why doesn't my commit/change appear in the history of \na file?\" is because someone resolved merge conflicts by just taking one \nside instead of doing a real merge (such as using -Xours). The only \nsolution is to re-apply the original change again and talk to the user \nwho incorrectly merged, to prevent future occurrences. These things \nrarely happen to teams who use pull requests that require review, since \nthe diff would be problematic. There are still a lot of teams that push \ndirectly to master, though.\n\nThanks,\n-Stolee\n"}]}