* show all merge conflicts @ 2017-01-27 16:56 Michael Spiegel 2017-01-27 17:51 ` Jeff King 0 siblings, 1 reply; 9+ messages in thread From: Michael Spiegel @ 2017-01-27 16:56 UTC (permalink / raw) To: git Hi folks, I'm trying to determine whether a merge required a conflict to resolve after the merge has occurred. The git book has some advice (https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging) to use `git show` on the merge commit or use `git log --cc -p -1`. These strategies work when the merge conflict was resolved with a change that is different from either parent. When the conflict is resolved with a change that is the same as one of the parents, then these commands are indistinguishable from a merge that did not conflict. Is it possible to distinguish between a conflict-free merge and a merge conflict that is resolved by with the changes from one the parents? Thanks, --Michael ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: show all merge conflicts 2017-01-27 16:56 show all merge conflicts Michael Spiegel @ 2017-01-27 17:51 ` Jeff King 2017-01-28 5:42 ` G. Sylvie Davies 0 siblings, 1 reply; 9+ messages in thread From: Jeff King @ 2017-01-27 17:51 UTC (permalink / raw) To: Michael Spiegel; +Cc: git On Fri, Jan 27, 2017 at 11:56:08AM -0500, Michael Spiegel wrote: > I'm trying to determine whether a merge required a conflict to resolve > after the merge has occurred. The git book has some advice > (https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging) to use > `git show` on the merge commit or use `git log --cc -p -1`. These > strategies work when the merge conflict was resolved with a change > that is different from either parent. When the conflict is resolved > with a change that is the same as one of the parents, then these > commands are indistinguishable from a merge that did not conflict. Is > it possible to distinguish between a conflict-free merge and a merge > conflict that is resolved by with the changes from one the parents? No. You'd have to replay the merge to know if it would have had conflicts. There was a patch series a few years ago that added a new diff-mode to do exactly that, and show the diff against what was resolved. It had a few issues (I don't remember exactly what) and never got merged. Certainly one complication is that you don't know exactly _how_ the merge was done in the first place (e.g., which merge strategy, which custom merge drivers were in effect, etc). But in general, replaying with a standard merge-recursive would get you most of what you want to know. I've done this manually sometimes when digging into erroneous merges (e.g., somebody accidentally runs "git reset -- <paths>" in the middle of a merge and throws away some changes. You should be able to do: git checkout $merge^1 git merge $merge^2 git diff -R $merge to see what the original resolution did. -Peff ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: show all merge conflicts 2017-01-27 17:51 ` Jeff King @ 2017-01-28 5:42 ` G. Sylvie Davies 2017-01-28 13:43 ` Philip Oakley 2017-01-28 14:28 ` Jeff King 0 siblings, 2 replies; 9+ messages in thread From: G. Sylvie Davies @ 2017-01-28 5:42 UTC (permalink / raw) To: Jeff King; +Cc: Michael Spiegel, git On Fri, Jan 27, 2017 at 9:51 AM, Jeff King <peff@peff.net> wrote: > On Fri, Jan 27, 2017 at 11:56:08AM -0500, Michael Spiegel wrote: > >> I'm trying to determine whether a merge required a conflict to resolve >> after the merge has occurred. The git book has some advice >> (https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging) to use >> `git show` on the merge commit or use `git log --cc -p -1`. These >> strategies work when the merge conflict was resolved with a change >> that is different from either parent. When the conflict is resolved >> with a change that is the same as one of the parents, then these >> commands are indistinguishable from a merge that did not conflict. Is >> it possible to distinguish between a conflict-free merge and a merge >> conflict that is resolved by with the changes from one the parents? > > No. You'd have to replay the merge to know if it would have had > conflicts. > Aside from the usual "git log -cc", I think this should work (replace HEAD with whichever commit you are analyzing): git diff --name-only HEAD^2...HEAD^1 > m1 git diff --name-only HEAD^1...HEAD^2 > b1 git diff --name-only HEAD^1..HEAD > m2 git diff --name-only HEAD^2..HEAD > b2 If files listed between m1 and b2 differ, then the merge is dirty. Similarly for m2 and b1. More information here: http://stackoverflow.com/questions/27683077/how-do-you-detect-an-evil-merge-in-git/41356308#41356308 - Sylvie > There was a patch series a few years ago that added a new diff-mode to > do exactly that, and show the diff against what was resolved. It had a > few issues (I don't remember exactly what) and never got merged. > > Certainly one complication is that you don't know exactly _how_ the > merge was done in the first place (e.g., which merge strategy, which > custom merge drivers were in effect, etc). But in general, replaying > with a standard merge-recursive would get you most of what you want to > know. > > I've done this manually sometimes when digging into erroneous merges > (e.g., somebody accidentally runs "git reset -- <paths>" in the middle > of a merge and throws away some changes. > > You should be able to do: > > git checkout $merge^1 > git merge $merge^2 > git diff -R $merge > > to see what the original resolution did. > > -Peff ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: show all merge conflicts 2017-01-28 5:42 ` G. Sylvie Davies @ 2017-01-28 13:43 ` Philip Oakley 2017-01-28 14:28 ` Jeff King 1 sibling, 0 replies; 9+ messages in thread From: Philip Oakley @ 2017-01-28 13:43 UTC (permalink / raw) To: G. Sylvie Davies, Jeff King; +Cc: Michael Spiegel, git From: "G. Sylvie Davies" <sylvie@bit-booster.com> > On Fri, Jan 27, 2017 at 9:51 AM, Jeff King <peff@peff.net> wrote: >> On Fri, Jan 27, 2017 at 11:56:08AM -0500, Michael Spiegel wrote: >> >>> I'm trying to determine whether a merge required a conflict to resolve >>> after the merge has occurred. The git book has some advice >>> (https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging) to use >>> `git show` on the merge commit or use `git log --cc -p -1`. These >>> strategies work when the merge conflict was resolved with a change >>> that is different from either parent. When the conflict is resolved >>> with a change that is the same as one of the parents, then these >>> commands are indistinguishable from a merge that did not conflict. Is >>> it possible to distinguish between a conflict-free merge and a merge >>> conflict that is resolved by with the changes from one the parents? >> >> No. You'd have to replay the merge to know if it would have had >> conflicts. >> > > > Aside from the usual "git log -cc", I think this should work (replace > HEAD with whichever commit you are analyzing): > > git diff --name-only HEAD^2...HEAD^1 > m1 > git diff --name-only HEAD^1...HEAD^2 > b1 > git diff --name-only HEAD^1..HEAD > m2 > git diff --name-only HEAD^2..HEAD > b2 > > If files listed between m1 and b2 differ, then the merge is dirty. > Similarly for m2 and b1. > > More information here: > > http://stackoverflow.com/questions/27683077/how-do-you-detect-an-evil-merge-in-git/41356308#41356308 > > > - Sylvie This feels as though there ought to be some sort of --left-right option to get an indication of which side various changes came from > >> There was a patch series a few years ago that added a new diff-mode to >> do exactly that, and show the diff against what was resolved. It had a >> few issues (I don't remember exactly what) and never got merged. >> >> Certainly one complication is that you don't know exactly _how_ the >> merge was done in the first place (e.g., which merge strategy, which >> custom merge drivers were in effect, etc). But in general, replaying >> with a standard merge-recursive would get you most of what you want to >> know. >> >> I've done this manually sometimes when digging into erroneous merges >> (e.g., somebody accidentally runs "git reset -- <paths>" in the middle >> of a merge and throws away some changes. >> >> You should be able to do: >> >> git checkout $merge^1 >> git merge $merge^2 >> git diff -R $merge >> >> to see what the original resolution did. >> >> -Peff > ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: show all merge conflicts 2017-01-28 5:42 ` G. Sylvie Davies 2017-01-28 13:43 ` Philip Oakley @ 2017-01-28 14:28 ` Jeff King 2017-01-29 6:45 ` G. Sylvie Davies 1 sibling, 1 reply; 9+ messages in thread From: Jeff King @ 2017-01-28 14:28 UTC (permalink / raw) To: G. Sylvie Davies; +Cc: Michael Spiegel, git On Fri, Jan 27, 2017 at 09:42:41PM -0800, G. Sylvie Davies wrote: > Aside from the usual "git log -cc", I think this should work (replace > HEAD with whichever commit you are analyzing): > > git diff --name-only HEAD^2...HEAD^1 > m1 > git diff --name-only HEAD^1...HEAD^2 > b1 > git diff --name-only HEAD^1..HEAD > m2 > git diff --name-only HEAD^2..HEAD > b2 > > If files listed between m1 and b2 differ, then the merge is dirty. > Similarly for m2 and b1. > > More information here: > > http://stackoverflow.com/questions/27683077/how-do-you-detect-an-evil-merge-in-git/41356308#41356308 I don't think that can reliably find evil merges, since it looks at the file level. If you had one hunk resolved for "theirs" and one hunk for "ours" in a given file, then the file will be listed in each diff, whether it has evil hunks or not. I don't think this is just about evil merges, though. For instance, try: seq 1 10 >file git add file git commit -m base sed s/4/master/ <file >tmp && mv tmp file git commit -am master git checkout -b other HEAD^ sed s/4/other/ <file >tmp && mv tmp file git commit -am other git merge master git checkout --ours file git commit -am merged merge=$(git rev-parse HEAD) The question is: were there conflicts in $merge, and how were they resolved? That isn't an evil merge, but there's still something interesting to show that "git log --cc" won't display. Replaying the merge like: git checkout $merge^1 git merge $merge^2 git diff -R $merge shows you the patch to go from the conflict state to the final one. -Peff ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: show all merge conflicts 2017-01-28 14:28 ` Jeff King @ 2017-01-29 6:45 ` G. Sylvie Davies 2017-02-27 14:28 ` Michael J Gruber 0 siblings, 1 reply; 9+ messages in thread From: G. Sylvie Davies @ 2017-01-29 6:45 UTC (permalink / raw) To: Jeff King; +Cc: G. Sylvie Davies, Michael Spiegel, git On Sat, Jan 28, 2017 at 6:28 AM, Jeff King <peff@peff.net> wrote: > On Fri, Jan 27, 2017 at 09:42:41PM -0800, G. Sylvie Davies wrote: > >> Aside from the usual "git log -cc", I think this should work (replace >> HEAD with whichever commit you are analyzing): >> >> git diff --name-only HEAD^2...HEAD^1 > m1 >> git diff --name-only HEAD^1...HEAD^2 > b1 >> git diff --name-only HEAD^1..HEAD > m2 >> git diff --name-only HEAD^2..HEAD > b2 >> >> If files listed between m1 and b2 differ, then the merge is dirty. >> Similarly for m2 and b1. >> >> More information here: >> >> http://stackoverflow.com/questions/27683077/how-do-you-detect-an-evil-merge-in-git/41356308#41356308 > > I don't think that can reliably find evil merges, since it looks at the > file level. If you had one hunk resolved for "theirs" and one hunk for > "ours" in a given file, then the file will be listed in each diff, > whether it has evil hunks or not. > Well, you have to do both. Do "git show -c" to catch that one ("theirs" for one hunk, "ours" for the other, same file). And then do that sequence of the 4 "git diff" commands to identify dirty merges where "theirs" or "ours" was applied to entire files, and thus not showing up in the "git show -c". > I don't think this is just about evil merges, though. For instance, > try: > > seq 1 10 >file > git add file > git commit -m base > > sed s/4/master/ <file >tmp && mv tmp file > git commit -am master > > git checkout -b other HEAD^ > sed s/4/other/ <file >tmp && mv tmp file > git commit -am other > > git merge master > git checkout --ours file > git commit -am merged > > merge=$(git rev-parse HEAD) > > The question is: were there conflicts in $merge, and how were they > resolved? > > That isn't an evil merge, but there's still something interesting to > show that "git log --cc" won't display. > > Replaying the merge like: > > git checkout $merge^1 > git merge $merge^2 > git diff -R $merge > > shows you the patch to go from the conflict state to the final one. > I know the stackoverflow question asks "how to detect evil merges", and I go along with that in my answer. But honestly I prefer to call them dirty rather than evil, and by "dirty" I just mean merges that did not resolve cleanly via "git merge", and had some form of user intervention, be it conflict resolution, or other strange things. The trick I propose with the sequence of 4 "git diff" commands identifies that merge from your example as dirty: $ cat b1 m2 file $ cat b2 m1 file file The trick doesn't really tell you much except that the merge is dirty. If you notice that the "m2" file is empty, I think that's one way to realize that master's edit was dropped, and therefore "other" won. Maybe it even merged cleanly but someone did a "git commit --amend" to make it the merge dirty after the fact. I do like your approach, it's very simple and reliable. But in my situation I'm writing pre-receive hooks for bare repos, so I don't think I can actually do "git merge"! I think my suggestion would work for OP, as long as they also run "git show -c" alongside it. (And your suggestion would work, too, of course). - Sylvie ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: show all merge conflicts 2017-01-29 6:45 ` G. Sylvie Davies @ 2017-02-27 14:28 ` Michael J Gruber 2017-02-27 19:45 ` Junio C Hamano 0 siblings, 1 reply; 9+ messages in thread From: Michael J Gruber @ 2017-02-27 14:28 UTC (permalink / raw) To: G. Sylvie Davies, Jeff King; +Cc: Michael Spiegel, git G. Sylvie Davies venit, vidit, dixit 29.01.2017 07:45: > On Sat, Jan 28, 2017 at 6:28 AM, Jeff King <peff@peff.net> wrote: >> On Fri, Jan 27, 2017 at 09:42:41PM -0800, G. Sylvie Davies wrote: >> >>> Aside from the usual "git log -cc", I think this should work (replace >>> HEAD with whichever commit you are analyzing): >>> >>> git diff --name-only HEAD^2...HEAD^1 > m1 >>> git diff --name-only HEAD^1...HEAD^2 > b1 >>> git diff --name-only HEAD^1..HEAD > m2 >>> git diff --name-only HEAD^2..HEAD > b2 >>> >>> If files listed between m1 and b2 differ, then the merge is dirty. >>> Similarly for m2 and b1. >>> >>> More information here: >>> >>> http://stackoverflow.com/questions/27683077/how-do-you-detect-an-evil-merge-in-git/41356308#41356308 >> >> I don't think that can reliably find evil merges, since it looks at the >> file level. If you had one hunk resolved for "theirs" and one hunk for >> "ours" in a given file, then the file will be listed in each diff, >> whether it has evil hunks or not. >> > > Well, you have to do both. Do "git show -c" to catch that one > ("theirs" for one hunk, "ours" for the other, same file). > > And then do that sequence of the 4 "git diff" commands to identify > dirty merges where "theirs" or "ours" was applied to entire files, and > thus not showing up in the "git show -c". > >> I don't think this is just about evil merges, though. For instance, >> try: >> >> seq 1 10 >file >> git add file >> git commit -m base >> >> sed s/4/master/ <file >tmp && mv tmp file >> git commit -am master >> >> git checkout -b other HEAD^ >> sed s/4/other/ <file >tmp && mv tmp file >> git commit -am other >> >> git merge master >> git checkout --ours file >> git commit -am merged >> >> merge=$(git rev-parse HEAD) >> >> The question is: were there conflicts in $merge, and how were they >> resolved? >> >> That isn't an evil merge, but there's still something interesting to >> show that "git log --cc" won't display. >> >> Replaying the merge like: >> >> git checkout $merge^1 >> git merge $merge^2 >> git diff -R $merge >> >> shows you the patch to go from the conflict state to the final one. >> > > I know the stackoverflow question asks "how to detect evil merges", > and I go along with that in my answer. But honestly I prefer to call > them dirty rather than evil, and by "dirty" I just mean merges that > did not resolve cleanly via "git merge", and had some form of user > intervention, be it conflict resolution, or other strange things. > > The trick I propose with the sequence of 4 "git diff" commands > identifies that merge from your example as dirty: > > $ cat b1 m2 > file > > $ cat b2 m1 > file > file > > The trick doesn't really tell you much except that the merge is dirty. > If you notice that the "m2" file is empty, I think that's one way to > realize that master's edit was dropped, and therefore "other" won. > > Maybe it even merged cleanly but someone did a "git commit --amend" to > make it the merge dirty after the fact. > > I do like your approach, it's very simple and reliable. But in my > situation I'm writing pre-receive hooks for bare repos, so I don't > think I can actually do "git merge"! > > I think my suggestion would work for OP, as long as they also run "git > show -c" alongside it. (And your suggestion would work, too, of > course). If you're curious, I kept rebasing Thomas' remerge-diff (on top of our next) so far. You can find it at https://github.com/mjg/git/tree/remerge-diff if you're interested. I don't know what problems were found back then, or what it would take to get this in-tree now. Michael ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: show all merge conflicts 2017-02-27 14:28 ` Michael J Gruber @ 2017-02-27 19:45 ` Junio C Hamano 2017-02-27 20:45 ` Jeff King 0 siblings, 1 reply; 9+ messages in thread From: Junio C Hamano @ 2017-02-27 19:45 UTC (permalink / raw) To: Michael J Gruber; +Cc: G. Sylvie Davies, Jeff King, Michael Spiegel, git Michael J Gruber <git@drmicha.warpmail.net> writes: > If you're curious, I kept rebasing Thomas' remerge-diff (on top of our > next) so far. You can find it at > > https://github.com/mjg/git/tree/remerge-diff ;-). Yes, this was a good one. > if you're interested. I don't know what problems were found back then, > or what it would take to get this in-tree now. If I recall correctly, everybody was in favor of what it does (or at least attempted to do), but was leaky and not ready for "log -p" to be used on a long stretch of history or something? ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: show all merge conflicts 2017-02-27 19:45 ` Junio C Hamano @ 2017-02-27 20:45 ` Jeff King 0 siblings, 0 replies; 9+ messages in thread From: Jeff King @ 2017-02-27 20:45 UTC (permalink / raw) To: Junio C Hamano; +Cc: Michael J Gruber, G. Sylvie Davies, Michael Spiegel, git On Mon, Feb 27, 2017 at 11:45:31AM -0800, Junio C Hamano wrote: > Michael J Gruber <git@drmicha.warpmail.net> writes: > > > If you're curious, I kept rebasing Thomas' remerge-diff (on top of our > > next) so far. You can find it at > > > > https://github.com/mjg/git/tree/remerge-diff > > ;-). > Yes, this was a good one. FWIW, I have also been carrying it forward. It's not a tool I reach for often, but a couple of times it has come in very handy (mostly helping somebody to track down a mistake that somebody made in a merge, like accidentally using "checkout --ours" on top of a conflict). > > if you're interested. I don't know what problems were found back then, > > or what it would take to get this in-tree now. > > If I recall correctly, everybody was in favor of what it does (or at > least attempted to do), but was leaky and not ready for "log -p" to > be used on a long stretch of history or something? The last round was at: http://public-inbox.org/git/cover.1409860234.git.tr@thomasrast.ch/ I think. I think the leakiness was dealt with by rebasing onto the name_hash refactoring. But it looks like there are a lot of little issues, and maybe one bigger one: it turns "log" from a read-only operation into that writes into the object database. -Peff ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2017-02-27 21:13 UTC | newest] Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2017-01-27 16:56 show all merge conflicts Michael Spiegel 2017-01-27 17:51 ` Jeff King 2017-01-28 5:42 ` G. Sylvie Davies 2017-01-28 13:43 ` Philip Oakley 2017-01-28 14:28 ` Jeff King 2017-01-29 6:45 ` G. Sylvie Davies 2017-02-27 14:28 ` Michael J Gruber 2017-02-27 19:45 ` Junio C Hamano 2017-02-27 20:45 ` Jeff King
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).