{"thread":{"id":"21934","subject":"How to selectively recreate merge state?","startedAt":"2009-12-10T23:56:05Z","lastAt":"2009-12-11T23:46:33Z","messageCount":18,"participants":["Jay Soffian","Junio C Hamano","Jakub Narebski","Michael J Gruber","Björn Steinbrink","Thomas Rast","Paolo Bonzini"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"129722","messageId":"76718490912101556o3e2911e8t32b48c0b735fd98c@mail.gmail.com","threadId":"21934","inReplyTo":null,"subject":"How to selectively recreate merge state?","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-12-10T23:56:05Z","receivedAt":"2009-12-10T23:56:05Z","isPatch":false,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"Let's say you initiate a merge:\n\n$ git merge topic\n\nAnd this merge results in conflicts in two files, foo and bar. You\nresolve the conflicts in both files, but then decide you don't like\nhow you resolved bar.\n\nHow do you set the index and working-copy back to the state it was\nimmediately after doing the merge for bar, while leaving the merge\nresolution alone for foo?\n\nj.\n"},{"id":"129723","messageId":"7v8wda8jg3.fsf@alter.siamese.dyndns.org","threadId":"21934","inReplyTo":"76718490912101556o3e2911e8t32b48c0b735fd98c@mail.gmail.com","subject":"Re: How to selectively recreate merge state?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-12-11T00:04:28Z","receivedAt":"2009-12-11T00:04:28Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jay Soffian <jaysoffian@gmail.com> writes:\n\n> Let's say you initiate a merge:\n>\n> $ git merge topic\n>\n> And this merge results in conflicts in two files, foo and bar. You\n> resolve the conflicts in both files, but then decide you don't like\n> how you resolved bar.\n>\n> How do you set the index and working-copy back to the state it was\n> immediately after doing the merge for bar, while leaving the merge\n> resolution alone for foo?\n\nBefore you \"git add bar\", you can say \"git checkout --conflict=merge bar\"\n(or --conflict=diff3).\n\nAfter \"git add bar\", you can't.  Save what you have resolved so far in a\nseparate file (e.g. \"cp foo foo.resolved\"), reset to the previous state\nand redo the merge.\n"},{"id":"129724","messageId":"m38wdae4k4.fsf@localhost.localdomain","threadId":"21934","inReplyTo":"7v8wda8jg3.fsf@alter.siamese.dyndns.org","subject":"Re: How to selectively recreate merge state?","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2009-12-11T00:28:50Z","receivedAt":"2009-12-11T00:28:50Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Jay Soffian <jaysoffian@gmail.com> writes:\n> \n> > Let's say you initiate a merge:\n> >\n> > $ git merge topic\n> >\n> > And this merge results in conflicts in two files, foo and bar. You\n> > resolve the conflicts in both files, but then decide you don't like\n> > how you resolved bar.\n> >\n> > How do you set the index and working-copy back to the state it was\n> > immediately after doing the merge for bar, while leaving the merge\n> > resolution alone for foo?\n> \n> Before you \"git add bar\", you can say \"git checkout --conflict=merge bar\"\n> (or --conflict=diff3).\n\nOr (if I understand manpage correctly) just \"git checkout --conflict bar\".\n \n> After \"git add bar\", you can't.  Save what you have resolved so far in a\n> separate file (e.g. \"cp foo foo.resolved\"), reset to the previous state\n> and redo the merge.\n\nHmmm... isn't it what \"git update-index --unresolve bar\" is for?\n\n  --unresolve::\n        Restores the 'unmerged' or 'needs updating' state of a\n        file during a merge if it was cleared by accident.\n\nUnless \"git add foo\" not only adds current contents of foo at stage 0,\nbut also removes higher stages from index...\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"129727","messageId":"7vzl5q71rp.fsf@alter.siamese.dyndns.org","threadId":"21934","inReplyTo":"m38wdae4k4.fsf@localhost.localdomain","subject":"Re: How to selectively recreate merge state?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-12-11T01:11:38Z","receivedAt":"2009-12-11T01:11:38Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narebski <jnareb@gmail.com> writes:\n\n>   --unresolve::\n>         Restores the 'unmerged' or 'needs updating' state of a\n>         file during a merge if it was cleared by accident.\n>\n> Unless \"git add foo\" not only adds current contents of foo at stage 0,\n> but also removes higher stages from index...\n\nBy definition, adding anything at stage #0 is to remove higher stages.\n"},{"id":"129728","messageId":"200912110233.18756.jnareb@gmail.com","threadId":"21934","inReplyTo":"7vzl5q71rp.fsf@alter.siamese.dyndns.org","subject":"Re: How to selectively recreate merge state?","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2009-12-11T01:33:18Z","receivedAt":"2009-12-11T01:33:18Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Dnia piątek 11. grudnia 2009 02:11, Junio C Hamano napisał:\n> Jakub Narebski <jnareb@gmail.com> writes:\n> \n> >   --unresolve::\n> >         Restores the 'unmerged' or 'needs updating' state of a\n> >         file during a merge if it was cleared by accident.\n> >\n> > Unless \"git add foo\" not only adds current contents of foo at stage 0,\n> > but also removes higher stages from index...\n> \n> By definition, adding anything at stage #0 is to remove higher stages.\n\nHmmm... let's test it:\n\n $ git merge side-branch \n Auto-merging foo\n CONFLICT (content): Merge conflict in foo\n Automatic merge failed; fix conflicts and then commit the result.\n $ git ls-files --stage\n 100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 1       foo\n 100644 3bd1f0e29744a1f32b08d5650e62e2e62afb177c 2       foo\n 100644 469a41eda5c8b45503a3bfc32ad6b5decc658132 3       foo\n $ <edit foo>\n $ git add foo\n $ git ls-files --stage\n 100644 a1b58d38ffa61e8e99b7cb95cdf540aedf2a96b3 0       foo\n\nNow let's test '--unresolve' option of git-update-index:\n\n $ git update-index --unresolve foo\n $ git ls-files --stage foo\n 100644 3bd1f0e29744a1f32b08d5650e62e2e62afb177c 2       foo\n 100644 469a41eda5c8b45503a3bfc32ad6b5decc658132 3       foo\n\nWTF? What happened to stage 1 (ancestor)?\n\n\n $ git checkout --conflict=merge foo\n error: path 'foo' does not have all three versions\n\nLet's recover it by hand:\n\n $ echo -e \"100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 1\\tfoo\" | \n   git update-index --index-info\n $ git ls-files --stage foo\n 100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 1       foo\n 100644 3bd1f0e29744a1f32b08d5650e62e2e62afb177c 2       foo\n 100644 469a41eda5c8b45503a3bfc32ad6b5decc658132 3       foo\n $ git checkout --conflict=merge foo\n\n-- \nJakub Narebski\nPoland\n"},{"id":"129739","messageId":"4B222289.6000004@drmicha.warpmail.net","threadId":"21934","inReplyTo":"200912110233.18756.jnareb@gmail.com","subject":"Re: How to selectively recreate merge state?","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2009-12-11T10:44:25Z","receivedAt":"2009-12-11T10:44:25Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Jakub Narebski venit, vidit, dixit 11.12.2009 02:33:\n> Dnia piątek 11. grudnia 2009 02:11, Junio C Hamano napisał:\n>> Jakub Narebski <jnareb@gmail.com> writes:\n>>\n>>>   --unresolve::\n>>>         Restores the 'unmerged' or 'needs updating' state of a\n>>>         file during a merge if it was cleared by accident.\n>>>\n>>> Unless \"git add foo\" not only adds current contents of foo at stage 0,\n>>> but also removes higher stages from index...\n>>\n>> By definition, adding anything at stage #0 is to remove higher stages.\n> \n> Hmmm... let's test it:\n> \n>  $ git merge side-branch \n>  Auto-merging foo\n>  CONFLICT (content): Merge conflict in foo\n>  Automatic merge failed; fix conflicts and then commit the result.\n>  $ git ls-files --stage\n>  100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 1       foo\n>  100644 3bd1f0e29744a1f32b08d5650e62e2e62afb177c 2       foo\n>  100644 469a41eda5c8b45503a3bfc32ad6b5decc658132 3       foo\n>  $ <edit foo>\n>  $ git add foo\n>  $ git ls-files --stage\n>  100644 a1b58d38ffa61e8e99b7cb95cdf540aedf2a96b3 0       foo\n> \n> Now let's test '--unresolve' option of git-update-index:\n> \n>  $ git update-index --unresolve foo\n>  $ git ls-files --stage foo\n>  100644 3bd1f0e29744a1f32b08d5650e62e2e62afb177c 2       foo\n>  100644 469a41eda5c8b45503a3bfc32ad6b5decc658132 3       foo\n> \n> WTF? What happened to stage 1 (ancestor)?\n\n2 and 3 are easy (cheap) to recreate from HEAD and MERGE_HEAD, 1 is not.\nI guess that's why --unresolve doesn't even attempt to do anything with 1.\n\n> \n>  $ git checkout --conflict=merge foo\n>  error: path 'foo' does not have all three versions\n> \n> Let's recover it by hand:\n> \n>  $ echo -e \"100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 1\\tfoo\" | \n>    git update-index --index-info\n>  $ git ls-files --stage foo\n>  100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 1       foo\n>  100644 3bd1f0e29744a1f32b08d5650e62e2e62afb177c 2       foo\n>  100644 469a41eda5c8b45503a3bfc32ad6b5decc658132 3       foo\n>  $ git checkout --conflict=merge foo\n\nYeah, if we knew that sha1...\n"},{"id":"129742","messageId":"20091211110944.GB19232@atjola.homenet","threadId":"21934","inReplyTo":"4B222289.6000004@drmicha.warpmail.net","subject":"Re: How to selectively recreate merge state?","fromName":"Björn Steinbrink","fromEmail":"b.steinbrink@gmx.de","sentAt":"2009-12-11T11:09:44Z","receivedAt":"2009-12-11T11:09:44Z","isPatch":false,"sender":{"key":"b.steinbrink@gmx.de","avatar":"https://avatars.githubusercontent.com/u/230962?v=4"},"body":"On 2009.12.11 11:44:25 +0100, Michael J Gruber wrote:\n> Jakub Narebski venit, vidit, dixit 11.12.2009 02:33:\n> >  $ git checkout --conflict=merge foo\n> >  error: path 'foo' does not have all three versions\n> > \n> > Let's recover it by hand:\n> > \n> >  $ echo -e \"100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 1\\tfoo\" | \n> >    git update-index --index-info\n> >  $ git ls-files --stage foo\n> >  100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 1       foo\n> >  100644 3bd1f0e29744a1f32b08d5650e62e2e62afb177c 2       foo\n> >  100644 469a41eda5c8b45503a3bfc32ad6b5decc658132 3       foo\n> >  $ git checkout --conflict=merge foo\n> \n> Yeah, if we knew that sha1...\n\nHm, isn't that \"$(git merge-base HEAD MERGE_HEAD):foo\"?\n\nBjörn\n"},{"id":"129743","messageId":"200912111220.40844.jnareb@gmail.com","threadId":"21934","inReplyTo":"4B222289.6000004@drmicha.warpmail.net","subject":"Re: How to selectively recreate merge state?","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2009-12-11T11:20:40Z","receivedAt":"2009-12-11T11:20:40Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Dnia piątek 11. grudnia 2009 11:44, Michael J Gruber napisał:\n> Jakub Narebski venit, vidit, dixit 11.12.2009 02:33:\n>> Dnia piątek 11. grudnia 2009 02:11, Junio C Hamano napisał:\n>>> Jakub Narebski <jnareb@gmail.com> writes:\n>>>\n>>>>   --unresolve::\n>>>>         Restores the 'unmerged' or 'needs updating' state of a\n>>>>         file during a merge if it was cleared by accident.\n>>>>\n>>>> Unless \"git add foo\" not only adds current contents of foo at stage 0,\n>>>> but also removes higher stages from index...\n>>>\n>>> By definition, adding anything at stage #0 is to remove higher stages.\n>> \n>> Hmmm... let's test it:\n>> \n>>  $ git merge side-branch \n>>  Auto-merging foo\n>>  CONFLICT (content): Merge conflict in foo\n>>  Automatic merge failed; fix conflicts and then commit the result.\n>>  $ git ls-files --stage\n>>  100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 1       foo\n>>  100644 3bd1f0e29744a1f32b08d5650e62e2e62afb177c 2       foo\n>>  100644 469a41eda5c8b45503a3bfc32ad6b5decc658132 3       foo\n>>  $ <edit foo>\n>>  $ git add foo\n>>  $ git ls-files --stage\n>>  100644 a1b58d38ffa61e8e99b7cb95cdf540aedf2a96b3 0       foo\n\nI thought that \"git add foo\" only adds current contents of foo in stage 0,\nand does not delete other stages.\n \nUnless \"git add foo\" does more than \"git update-index foo\" does here.\n\n>> Now let's test '--unresolve' option of git-update-index:\n>> \n>>  $ git update-index --unresolve foo\n>>  $ git ls-files --stage foo\n>>  100644 3bd1f0e29744a1f32b08d5650e62e2e62afb177c 2       foo\n>>  100644 469a41eda5c8b45503a3bfc32ad6b5decc658132 3       foo\n>> \n>> WTF? What happened to stage 1 (ancestor)?\n> \n> 2 and 3 are easy (cheap) to recreate from HEAD and MERGE_HEAD, 1 is not.\n> I guess that's why --unresolve doesn't even attempt to do anything with 1.\n\nBut then \"git update-index --unresolve <file>\" is next to useless.\n\n>> \n>>  $ git checkout --conflict=merge foo\n>>  error: path 'foo' does not have all three versions\n>> \n>> Let's recover it by hand:\n>> \n>>  $ echo -e \"100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 1\\tfoo\" | \n>>    git update-index --index-info\n>>  $ git ls-files --stage foo\n>>  100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 1       foo\n>>  100644 3bd1f0e29744a1f32b08d5650e62e2e62afb177c 2       foo\n>>  100644 469a41eda5c8b45503a3bfc32ad6b5decc658132 3       foo\n>>  $ git checkout --conflict=merge foo\n> \n> Yeah, if we knew that sha1...\n\nIsn't it:\n\n  $ git ls-tree $(git merge-base HEAD MERGE_HEAD) -- foo\n\nor\n\n  $ git rev-parse \"$(git merge-base HEAD MERGE_HEAD):foo\"\n\n-- \nJakub Narebski\nPoland\n"},{"id":"129745","messageId":"4B223C1E.6010403@drmicha.warpmail.net","threadId":"21934","inReplyTo":"200912111220.40844.jnareb@gmail.com","subject":"Re: How to selectively recreate merge state?","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2009-12-11T12:33:34Z","receivedAt":"2009-12-11T12:33:34Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Jakub Narebski venit, vidit, dixit 11.12.2009 12:20:\n> Dnia piątek 11. grudnia 2009 11:44, Michael J Gruber napisał:\n>> Jakub Narebski venit, vidit, dixit 11.12.2009 02:33:\n>>> Dnia piątek 11. grudnia 2009 02:11, Junio C Hamano napisał:\n>>>> Jakub Narebski <jnareb@gmail.com> writes:\n>>>>\n>>>>>   --unresolve::\n>>>>>         Restores the 'unmerged' or 'needs updating' state of a\n>>>>>         file during a merge if it was cleared by accident.\n>>>>>\n>>>>> Unless \"git add foo\" not only adds current contents of foo at stage 0,\n>>>>> but also removes higher stages from index...\n>>>>\n>>>> By definition, adding anything at stage #0 is to remove higher stages.\n>>>\n>>> Hmmm... let's test it:\n>>>\n>>>  $ git merge side-branch \n>>>  Auto-merging foo\n>>>  CONFLICT (content): Merge conflict in foo\n>>>  Automatic merge failed; fix conflicts and then commit the result.\n>>>  $ git ls-files --stage\n>>>  100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 1       foo\n>>>  100644 3bd1f0e29744a1f32b08d5650e62e2e62afb177c 2       foo\n>>>  100644 469a41eda5c8b45503a3bfc32ad6b5decc658132 3       foo\n>>>  $ <edit foo>\n>>>  $ git add foo\n>>>  $ git ls-files --stage\n>>>  100644 a1b58d38ffa61e8e99b7cb95cdf540aedf2a96b3 0       foo\n> \n> I thought that \"git add foo\" only adds current contents of foo in stage 0,\n> and does not delete other stages.\n>  \n> Unless \"git add foo\" does more than \"git update-index foo\" does here.\n\nQuoting Junio:\n\nBy definition, adding anything at stage #0 is to remove higher stages.\n\nCould one leave 1 alone but still mark the conflict resolved?\n\n>>> Now let's test '--unresolve' option of git-update-index:\n>>>\n>>>  $ git update-index --unresolve foo\n>>>  $ git ls-files --stage foo\n>>>  100644 3bd1f0e29744a1f32b08d5650e62e2e62afb177c 2       foo\n>>>  100644 469a41eda5c8b45503a3bfc32ad6b5decc658132 3       foo\n>>>\n>>> WTF? What happened to stage 1 (ancestor)?\n>>\n>> 2 and 3 are easy (cheap) to recreate from HEAD and MERGE_HEAD, 1 is not.\n>> I guess that's why --unresolve doesn't even attempt to do anything with 1.\n> \n> But then \"git update-index --unresolve <file>\" is next to useless.\n\nWell, I'm not defending current behaviour, just describing its\nimplementation.\n\n> \n>>>\n>>>  $ git checkout --conflict=merge foo\n>>>  error: path 'foo' does not have all three versions\n>>>\n>>> Let's recover it by hand:\n>>>\n>>>  $ echo -e \"100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 1\\tfoo\" | \n>>>    git update-index --index-info\n>>>  $ git ls-files --stage foo\n>>>  100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 1       foo\n>>>  100644 3bd1f0e29744a1f32b08d5650e62e2e62afb177c 2       foo\n>>>  100644 469a41eda5c8b45503a3bfc32ad6b5decc658132 3       foo\n>>>  $ git checkout --conflict=merge foo\n>>\n>> Yeah, if we knew that sha1...\n> \n> Isn't it:\n> \n>   $ git ls-tree $(git merge-base HEAD MERGE_HEAD) -- foo\n> \n> or\n> \n>   $ git rev-parse \"$(git merge-base HEAD MERGE_HEAD):foo\"\n\nYes, sure. That's why I wrote \"cheap\": --unresolve simply reads HEAD and\nMERGE_HEAD. Resetting 1 requires (re)calculation of the merge base.\n\nMichael\n"},{"id":"129748","messageId":"200912111351.38695.trast@student.ethz.ch","threadId":"21934","inReplyTo":"20091211110944.GB19232@atjola.homenet","subject":"Re: How to selectively recreate merge state?","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-12-11T12:51:37Z","receivedAt":"2009-12-11T12:51:37Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Björn Steinbrink wrote:\n> On 2009.12.11 11:44:25 +0100, Michael J Gruber wrote:\n> > Jakub Narebski venit, vidit, dixit 11.12.2009 02:33:\n> > >  $ echo -e \"100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 1\\tfoo\" | \n> > >    git update-index --index-info\n> > \n> > Yeah, if we knew that sha1...\n> \n> Hm, isn't that \"$(git merge-base HEAD MERGE_HEAD):foo\"?\n\nNot if the merge-base isn't unique and you're using the recursive\nstrategy, IIUC.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"129750","messageId":"200912111500.51982.jnareb@gmail.com","threadId":"21934","inReplyTo":"4B223C1E.6010403@drmicha.warpmail.net","subject":"Re: How to selectively recreate merge state?","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2009-12-11T14:00:50Z","receivedAt":"2009-12-11T14:00:50Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Dnia piątek 11. grudnia 2009 13:33, Michael J Gruber napisał:\n> Jakub Narebski venit, vidit, dixit 11.12.2009 12:20:\n>> Dnia piątek 11. grudnia 2009 11:44, Michael J Gruber napisał:\n>>> Jakub Narebski venit, vidit, dixit 11.12.2009 02:33:\n>>>> Dnia piątek 11. grudnia 2009 02:11, Junio C Hamano napisał:\n>>>>> Jakub Narebski <jnareb@gmail.com> writes:\n>>>>>\n>>>>>>   --unresolve::\n>>>>>>         Restores the 'unmerged' or 'needs updating' state of a\n>>>>>>         file during a merge if it was cleared by accident.\n>>>>>>\n>>>>>> Unless \"git add foo\" not only adds current contents of foo at stage 0,\n>>>>>> but also removes higher stages from index...\n>>>>>\n>>>>> By definition, adding anything at stage #0 is to remove higher stages.\n>>>>\n>>>> Hmmm... let's test it:\n>>>>\n>>>>  $ git merge side-branch \n>>>>  Auto-merging foo\n>>>>  CONFLICT (content): Merge conflict in foo\n>>>>  Automatic merge failed; fix conflicts and then commit the result.\n>>>>  $ git ls-files --stage\n>>>>  100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 1       foo\n>>>>  100644 3bd1f0e29744a1f32b08d5650e62e2e62afb177c 2       foo\n>>>>  100644 469a41eda5c8b45503a3bfc32ad6b5decc658132 3       foo\n>>>>  $ <edit foo>\n>>>>  $ git add foo\n>>>>  $ git ls-files --stage\n>>>>  100644 a1b58d38ffa61e8e99b7cb95cdf540aedf2a96b3 0       foo\n>> \n>> I thought that \"git add foo\" only adds current contents of foo in stage 0,\n>> and does not delete other stages.\n>>  \n>> Unless \"git add foo\" does more than \"git update-index foo\" does here.\n> \n> Quoting Junio:\n> \n> By definition, adding anything at stage #0 is to remove higher stages.\n> \n> Could one leave 1 alone but still mark the conflict resolved?\n\nI have thought that if there exist stage #0 in index, git simply _ignores_\nhigher stages, so git-add simply adds stage #0 and does not delete higher\nstages.\n\nBut I see that \"git update-index --unresolve\" (and its predecessor \n\"git-unresolve\") simply recreate stages #2 and #3.\n\n\nThe documentation of \"git update-index --unresolve\" lacks this info,\nand it doesn't tell one what it is for (see commit message for commit\nec16779 (Add git-unresolve <paths>..., 2006-04-19)).\n\n-- \nJakub Narebski\nPoland\n"},{"id":"129753","messageId":"4B225DC0.4020603@drmicha.warpmail.net","threadId":"21934","inReplyTo":"200912111500.51982.jnareb@gmail.com","subject":"Re: How to selectively recreate merge state?","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2009-12-11T14:57:04Z","receivedAt":"2009-12-11T14:57:04Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Jakub Narebski venit, vidit, dixit 11.12.2009 15:00:\n> Dnia piątek 11. grudnia 2009 13:33, Michael J Gruber napisał:\n>> Jakub Narebski venit, vidit, dixit 11.12.2009 12:20:\n>>> Dnia piątek 11. grudnia 2009 11:44, Michael J Gruber napisał:\n>>>> Jakub Narebski venit, vidit, dixit 11.12.2009 02:33:\n>>>>> Dnia piątek 11. grudnia 2009 02:11, Junio C Hamano napisał:\n>>>>>> Jakub Narebski <jnareb@gmail.com> writes:\n>>>>>>\n>>>>>>>   --unresolve::\n>>>>>>>         Restores the 'unmerged' or 'needs updating' state of a\n>>>>>>>         file during a merge if it was cleared by accident.\n>>>>>>>\n>>>>>>> Unless \"git add foo\" not only adds current contents of foo at stage 0,\n>>>>>>> but also removes higher stages from index...\n>>>>>>\n>>>>>> By definition, adding anything at stage #0 is to remove higher stages.\n>>>>>\n>>>>> Hmmm... let's test it:\n>>>>>\n>>>>>  $ git merge side-branch \n>>>>>  Auto-merging foo\n>>>>>  CONFLICT (content): Merge conflict in foo\n>>>>>  Automatic merge failed; fix conflicts and then commit the result.\n>>>>>  $ git ls-files --stage\n>>>>>  100644 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 1       foo\n>>>>>  100644 3bd1f0e29744a1f32b08d5650e62e2e62afb177c 2       foo\n>>>>>  100644 469a41eda5c8b45503a3bfc32ad6b5decc658132 3       foo\n>>>>>  $ <edit foo>\n>>>>>  $ git add foo\n>>>>>  $ git ls-files --stage\n>>>>>  100644 a1b58d38ffa61e8e99b7cb95cdf540aedf2a96b3 0       foo\n>>>\n>>> I thought that \"git add foo\" only adds current contents of foo in stage 0,\n>>> and does not delete other stages.\n>>>  \n>>> Unless \"git add foo\" does more than \"git update-index foo\" does here.\n>>\n>> Quoting Junio:\n>>\n>> By definition, adding anything at stage #0 is to remove higher stages.\n>>\n>> Could one leave 1 alone but still mark the conflict resolved?\n> \n> I have thought that if there exist stage #0 in index, git simply _ignores_\n> higher stages, so git-add simply adds stage #0 and does not delete higher\n> stages.\n> \n> But I see that \"git update-index --unresolve\" (and its predecessor \n> \"git-unresolve\") simply recreate stages #2 and #3.\n> \n> \n> The documentation of \"git update-index --unresolve\" lacks this info,\n> and it doesn't tell one what it is for (see commit message for commit\n> ec16779 (Add git-unresolve <paths>..., 2006-04-19)).\n> \n\nOh yes, one should always read the classics ;) [Really nice commit\nmessage, that is.]\n\nMichael\n"},{"id":"129754","messageId":"7vaaxp5xr4.fsf@alter.siamese.dyndns.org","threadId":"21934","inReplyTo":"4B225DC0.4020603@drmicha.warpmail.net","subject":"Re: How to selectively recreate merge state?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-12-11T15:35:59Z","receivedAt":"2009-12-11T15:35:59Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael J Gruber <git@drmicha.warpmail.net> writes:\n\n>> The documentation of \"git update-index --unresolve\" lacks this info,\n>> and it doesn't tell one what it is for (see commit message for commit\n>> ec16779 (Add git-unresolve <paths>..., 2006-04-19)).\n>\n> Oh yes, one should always read the classics ;) [Really nice commit\n> message, that is.]\n\nThanks.\n\nThis is exactly why I often give _explanation_ of the current behaviour\nbased on history, without defending it is good nor claiming it is bad.\nKnowing how things came about gives us better perspective to decide where\nto go next.\n"},{"id":"129764","messageId":"7v3a3h48lz.fsf@alter.siamese.dyndns.org","threadId":"21934","inReplyTo":"200912111500.51982.jnareb@gmail.com","subject":"Re: How to selectively recreate merge state?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-12-11T19:24:24Z","receivedAt":"2009-12-11T19:24:24Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narebski <jnareb@gmail.com> writes:\n\n> I have thought that if there exist stage #0 in index, git simply _ignores_\n> higher stages, so git-add simply adds stage #0 and does not delete higher\n> stages.\n\nThen you thought wrong ;-).\n\nLeaving resolved cruft in the main index (aka active_cache[]) will make\nall the normal operation codepath unnecessarily complex.  They rely on \"if\nI see stage #0, there is no higher stages for the same path\".  And extra\nchecks will slow things down.\n\nBut that does not necessarily mean the index is a wrong place to save away\npre-resolution information on resolved paths (read on).\n\nBefore suggesting a possible next move, there are a few things we should\nnotice while reading ec16779 (Add git-unresolve <paths>..., 2006-04-19):\n\n - This was done about only one year after git was born.  You should not\n   take it granted that the workflow it wanted to support makes sense.\n\n   Considering that using \"git add\" to mark the resolution is to declare\n   that you are _finished_ with that path, using it for other purposes\n   (e.g. leaving a note that says \"I've looked at and have one possible\n   resolution in the file in the work tree, but I haven't verified the\n   result yet\", which is what the commit talks about) is simply an\n   (ab|mis)use of the index.  Lossage of higher stage information by this\n   misuse is user's problem, and there is this thing called pen & pencil\n   the user can use for taking notes if s/he does not want to lose the\n   original conflict information from the index.\n\n - Even if we for a moment consider that the workflow made some sense, the\n   particular implementation is not suitable anymore for today's git.\n\n   Again, this was done only one year after git was born, and back then\n   \"pull/merge\" were the only things that left conflicts in every day\n   operations by end users, and not many people didn't expect git to merge\n   across renames.  It was sufficient to read the path the end user asked\n   for from HEAD and MERGE_HEAD and pretend we \"unresolved\" in such a\n   simpler world.\n\n   But \"merge\" is not the primary thing that gives you conflicts anymore.\n   \"rebase\", \"cherry-pick\", \"stash apply\" are much more widely used by\n   ordinary users these days than back then, and reading from MERGE_HEAD\n   wouldn't do any good for recreating what these operations did.  Even\n   with \"merge\", stages #2 and #3 can come from a totally different path\n   when using recursive and subtree strategies, so reading from\n   HEAD/MERGE_HEAD is not as useful as it used to be.\n\nIn fact, considering that there are many ways conflicts can be left in the\nindex and there are only two ways that they are resolved in the index by\nthe user (and both eventually uses a single function to do so), it would\nmake perfect sense to do the following:\n\n - Define a new index extension section to record \"unresolve\"\n   information.\n\n - Every time add_index_entry_with_check() in read-cache.c records a stage\n   0 entry while dropping higher stage entries for the same path, record\n   these higher stage entries to the \"unresolve\" section.\n\n - An \"update-index --unresolve\" will use the information from this\n   \"unresolve\" extension to recreate the unmerged state.\n\n - \"rerere forget\" that we earlier talked about in a separate thread will\n   use exactly the same mechanism to get back the unmerged state to\n   recompute the conflict identifier (this is why J6t is addded to the Cc:\n   list).\n\n - \"checkout --conflict\" _might_ want to also consider unresolving the\n   path first using this information, if it finds the path user asked to\n   re-checkout with conflict markers has already been resolved.\n\nIt is important to think through to decide when we purge the \"unresolve\"\nsection.\n\nIf you run \"read-tree\", \"checkout\" to switch branches, or \"reset\" (any\noption other than \"--soft\" which does not even touch the index), it is a\ngood sign that the information in the \"unresolve\" extension section is no\nlonger needed, so you can drop the section in these operations.\n\nOptionally, write_index() could notice if there is no unmerged entries and\nthe cache_tree is fully valid---that is an indication that a tree object\nhas been written out of the now resolved index, and may (or may not) imply\nthat the \"unresolve\" information is no longer needed.  But I haven't\nthought this last one through.  You could wish to unresolve even after you\ncommitted your merge (you _could_ wish for anything after all), but I do\nnot yet know if granting that wish makes much sense.\n\nThere may be other cases we _must_ drop \"unresolve\".\n"},{"id":"129766","messageId":"hfuakf$fnd$1@ger.gmane.org","threadId":"21934","inReplyTo":"200912111220.40844.jnareb@gmail.com","subject":"Re: How to selectively recreate merge state?","fromName":"Paolo Bonzini","fromEmail":"bonzini@gnu.org","sentAt":"2009-12-11T20:38:39Z","receivedAt":"2009-12-11T20:38:39Z","isPatch":false,"sender":{"key":"bonzini@gnu.org","avatar":"https://avatars.githubusercontent.com/u/42082?v=4"},"body":"On 12/11/2009 12:20 PM, Jakub Narebski wrote:\n>> >  2 and 3 are easy (cheap) to recreate from HEAD and MERGE_HEAD, 1 is not.\n>> >  I guess that's why --unresolve doesn't even attempt to do anything with 1.\n> But then \"git update-index --unresolve<file>\" is next to useless.\n\nOnly \"next to\".  It can still be useful if you added a file before \nediting it, so you left in the conflict markers.\n\nPaolo\n"},{"id":"129767","messageId":"7vtyvx1ad3.fsf@alter.siamese.dyndns.org","threadId":"21934","inReplyTo":"hfuakf$fnd$1@ger.gmane.org","subject":"Re: How to selectively recreate merge state?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-12-11T21:14:48Z","receivedAt":"2009-12-11T21:14:48Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Paolo Bonzini <bonzini@gnu.org> writes:\n\n> On 12/11/2009 12:20 PM, Jakub Narebski wrote:\n>>> >  2 and 3 are easy (cheap) to recreate from HEAD and MERGE_HEAD, 1 is not.\n>>> >  I guess that's why --unresolve doesn't even attempt to do anything with 1.\n>> But then \"git update-index --unresolve<file>\" is next to useless.\n>\n> Only \"next to\".  It can still be useful if you added a file before\n> editing it, so you left in the conflict markers.\n\nTo be fair, these need to be judged within their context, and then get\nupdated to today's reality.\n\n\"diff --cc\" was merely a relatively new curiosity that allows a different\nview into a conflicted merge (it was still cooking in 'next').  The\nprimary ways to inspect a conflict were \"diff --theirs\" and \"diff --ours\";\nrepopulating stages #2 and #3 was sufficient for them.\n"},{"id":"129768","messageId":"76718490912111418i6b59056eq69671979613749f7@mail.gmail.com","threadId":"21934","inReplyTo":"7v3a3h48lz.fsf@alter.siamese.dyndns.org","subject":"Re: How to selectively recreate merge state?","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-12-11T22:18:32Z","receivedAt":"2009-12-11T22:18:32Z","isPatch":false,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"On Fri, Dec 11, 2009 at 2:24 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>  - This was done about only one year after git was born.  You should not\n>   take it granted that the workflow it wanted to support makes sense.\n>\n>   Considering that using \"git add\" to mark the resolution is to declare\n>   that you are _finished_ with that path, using it for other purposes\n>   (e.g. leaving a note that says \"I've looked at and have one possible\n>   resolution in the file in the work tree, but I haven't verified the\n>   result yet\", which is what the commit talks about) is simply an\n>   (ab|mis)use of the index.  Lossage of higher stage information by this\n>   misuse is user's problem, and there is this thing called pen & pencil\n>   the user can use for taking notes if s/he does not want to lose the\n>   original conflict information from the index.\n\nJust a little more data. What happened in my case was that I was using\na visual merge tool and accidentally saved instead of canceled, so git\nmergetool automagically added my results. I had resolved about 15\nfiles, and made a mistake with only one, so I was sad when I couldn't\ndetermine how to unresolve that one file (at which point I saved off\nthe other 14 resolutions, reset, re-did the merge).\n\nMy intuition led me to try \"git reset <path>\" since that's how one\nnormally unstages additions to the index. But of course that didn't\nwork, where \"of course\" only makes sense if you know how the index is\nused during a merge.\n\n> In fact, considering that there are many ways conflicts can be left in the\n> index and there are only two ways that they are resolved in the index by\n> the user (and both eventually uses a single function to do so), it would\n> make perfect sense to do the following:\n>\n> [...excellent list of suggestions elided...]\n\nAlso, I think we could improve the output of \"git status\" during merge\nresolution, both before and after conflicts have been resolved in a\nfile. Immediately after a conflict, the conflicted files are shown as\n\"unmerged\":\n\n$ git status\nfoo: needs merge\n# On branch master\n# Changed but not updated:\n#   (use \"git add <file>...\" to update what will be committed)\n#   (use \"git checkout -- <file>...\" to discard changes in working directory)\n#\n#\tunmerged:   foo\n#\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n\n\"unmerged\" is good. But the instruction to use \"git checkout --\n<file>\" to discard changes is wrong in this context:\n\n$ git checkout -- foo\nerror: path 'foo' is unmerged\n\nThen, after resolving foo and adding it:\n\n$ git status\n# On branch master\n# Changes to be committed:\n#   (use \"git reset HEAD <file>...\" to unstage)\n#\n#\tmodified:   foo\n#\n\nWell, yes, I can use git reset, but that just keeps my side of the merge.\n\nSo I think with your suggested changes to the index, we can do better\nwith the status output during a merge.\n\nj.\n"},{"id":"129770","messageId":"7vk4wtysyu.fsf@alter.siamese.dyndns.org","threadId":"21934","inReplyTo":"76718490912111418i6b59056eq69671979613749f7@mail.gmail.com","subject":"Re: How to selectively recreate merge state?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-12-11T23:46:33Z","receivedAt":"2009-12-11T23:46:33Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jay Soffian <jaysoffian@gmail.com> writes:\n\n> Also, I think we could improve the output of \"git status\" during merge\n> resolution, both before and after conflicts have been resolved in a\n> file.\n\nI think you are talking about something that is largely unrelated, even\nthough they would be a pair of good issues to discuss.  The solution to\nthem does not have much to do with what we have been discussing so far in\nthis thread, and actually should be much simpler, which is a good news\n;-).\n\n> $ git status\n> foo: needs merge\n> # On branch master\n> # Changed but not updated:\n> #   (use \"git add <file>...\" to update what will be committed)\n> #   (use \"git checkout -- <file>...\" to discard changes in working directory)\n> #\n> #\tunmerged:   foo\n> #\n> no changes added to commit (use \"git add\" and/or \"git commit -a\")\n>\n> \"unmerged\" is good. But the instruction to use \"git checkout --\n> <file>\" to discard changes is wrong in this context:\n\nYou should be able to change this without any \"unresolve\" index extension\nadded to the index.  Just notice an unmerged entry in the index and reword\nthe message accordingly.\n\nMore importantly, note that \"git status\" lists \"unmerged\" entries in a\nseparate section in its output in 1.6.6 (and has been so on 'master' for\nsome time) and your problem report needs to be adjusted for a more recent\nreality.  Here is what you would get:\n\n        $ git status\n        # On branch pu\n        # Changes to be committed:\n        #   (use \"git reset HEAD <file>...\" to unstage)\n        #\n        #       modified:   builtin-send-pack.c\n        #       modified:   remote.c\n        #       modified:   remote.h\n        #       modified:   transport.c\n        #\n        # Unmerged paths:\n        #   (use \"git reset HEAD <file>...\" to unstage)\n        #   (use \"git add <file>...\" to mark resolution)\n        #\n        #       both modified:      transport-helper.c\n        #\n\nOne problem we can see is that 'use \"git reset HEAD <file>...\" to unstage'\nis an invalid advice if we are in the middle of a merge, but is perfectly\nvalid if this were during \"rebase\", \"am -3\", \"cherry-pick\" and \"revert\".\n\nThe solution to this issue is exactly the same as the next one.\n\n> $ git status\n> # On branch master\n> # Changes to be committed:\n> #   (use \"git reset HEAD <file>...\" to unstage)\n> #\n> #\tmodified:   foo\n> #\n>\n> Well, yes, I can use git reset, but that just keeps my side of the merge.\n\nIf the conflict was coming from \"rebase\", \"cherry-pick\", etc., there is\nnothing but one side, as there is no merge going on, and what \"git reset\"\ndoes is exactly what the message tells you---to unstage.\n\nI think \"git status\" should notice that the next commit you would make\nfrom this state will be a merge commit, and remove these \"reset HEAD\"\nlines.  Once you \"git add\" to resolve, it makes _no_ sense to reset to\nHEAD, if you are concluding a merge.  Until \"update-index --unresolve\" is\nrevived as a modern version (and I suspect that a more logical Porcelain\ninterface would be a new option \"reset --unmerge <paths>...\"), we should\nsimply drop \"reset HEAD\" advice when we are in a merge.\n\nNote that the \"unresolve\" index extension will not help you at all in\norder for you to decide if you are going to make a merge commit.  You\nshould instead ask \"does .git/MERGE_HEAD exist?\", and it is something you\nshould be able to implement directly on top of upcoming 1.6.6 release.\n"}]}