{"thread":{"id":"11057","subject":"Re: can't commit files that have been git add'ed because \"fatal: you need to resolve your current index first\"","startedAt":"2007-11-29T04:10:46Z","lastAt":"2007-11-29T04:10:46Z","messageCount":1,"participants":["Bill Priest"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"61363","messageId":"88849.40139.qm@web55011.mail.re4.yahoo.com","threadId":"11057","inReplyTo":null,"subject":"Re: can't commit files that have been git add'ed because \"fatal: you need to resolve your current index first\"","fromName":"Bill Priest","fromEmail":"priestwilliaml@yahoo.com","sentAt":"2007-11-29T04:10:46Z","receivedAt":"2007-11-29T04:10:46Z","isPatch":false,"sender":{"key":"priestwilliaml@yahoo.com","avatar":null},"body":"On Wed, 28 Nov 2007 12:08:40 -0800\nJunio C Hamano <gitster@pobox.com> wrote:\n\n> Bill Priest <priestwilliaml@yahoo.com> writes:\n> \n> >   I merged from one branch to another and had lots\nof\n> > conflicts.  I've resolved a set of files from the\n> > conflicts (in a directory) and did a git-add on\nthis\n> > set of files.  I wasn't able to commit these\nfiles. \n> > On IRC I was told that all files must be resolved\n> > before I can commit any of them.  This seems\npretty\n> > limiting.\n> \n> You have two parallel development lines that lead to\nA and B and trying\n> to come up with a \"merge\" M:\n> \n>          o---o---A\n>         /         \\\n>     ---o---o---B---M\n> \n> What property should the merge commit \"M\" have?  It\nmust keep the\n> changes made on the upper line to make it better\nthan B, and it must\n> keep the changes made on the lower line to make it\nbetter than A.\n\nOk.  One thing I probably wasn't clear on is these are\ntwo distinct\nproduct lines that share a great amount of code;\nhowever, much of the\ncode is \"incompatible\".  The two branches will never\nbe \"merged\" into\none \"mainline\" as the underlying hardware is by\ndefinition\nincompatible.  In theory I could use a bunch of\nconditional compilation\nto unify the two lines; however, this means that every\ntime I make a\nchange to one branch I have to make sure that it\ndoesn't break the\nother one.  It would have been better if the code was\nmodularized\nbetter to just include different files for the two\nversions;\nunfortunately this is easier said than done.  I guess\nyou could think\nof it line a 2.4 kernel vs. a 2.6 kernel; but in the\nsame repository.\nSo to sum it up there are changes in branch A that\nwill never go into\nbranch B (and vice versa); however, there are a number\nof changes that\nneed to go into both.  Unfortunately the rest of my\nteam uses\nsubversion and isn't even aware that I am using git\n(we recently switch\nto subversion from cvs, so it is a hard sell to\nmanagement to switch\nagain).  I'm responsible for keeping bug fixes and new\nfeatures in both\nproduct lines and I found subversion's merging to be\nutterly useless. \n> Let's say both upper and lower lines of development\ntouched files frotz\n> and xyzzy in overlapping, different ways.  You try\nto merge A while you\n> are at B and see conflicts in these two files.\n> \n> Let's say you resolved frotz; the contents in frotz\nis in a desired\n> shape, i.e you have the changes you want from the\nline led to A and the\n> other line led to B.  But you haven't resolved xyzzy\nyet.\n> \n> You seem to want to make this half-resolved state as\na commit.  First\n> question: what contents would you want to commit for\nxyzzy?\n\nAs an example there is a directory in the tree that is\na program that\nruns on a PC (vs. the other stuff that runs on\nembedded processors) it\nshares a handful of include files w/ the embedded side\nfor packet\ndefinition but it is otherwise completely separate\nfrom the programs\nthat run on the embedded processors.  Once I complete\nmerging of this\ndirectory and it builds it is ready to go.  The\nremaining merges have\nno effect on this PC based program.  I'm not sure if\nit is possible or\nnot but if I could merge this directory and below\n(does git support\nthis??) it might be one way of handling it or if I\ncherry-pick'ed it\nthat could also work.  This isn't always feasible as\nthe other users\noften check in wholesale changes into subversion as\none change set\n(remember that these are former cvs users that have\nlots of bad habits\nto lose).  It would be great if branches were created\nfor each\n\"logical\" change and checked in in one changeset; this\nseems to be what\ngit is expecting (in a perfect world this would always\nbe the case).\n\n> \n> If you commit the contents from B (because you\nstarted from it), then it\n> should not be recorded as a proper merge.  If you\ndid so, merging that\n> back to A would obliterate all the work done up to A\nto file xyzzy:\n> \n>          o---o---A...X\n>         /         \\ .\n>     ---o---o---B---*\n>  \n> because merge base of A and * (I am marking it\ndifferently because such\n> an incomplete merge should not be made) is A, so the\nresult (X) will be\n> the half-merge * itself (fast forward).  That's not\na merge as it is not\n> better than A -- you discarded improvements made to\nxyzzy by people who\n> built up to A.\n> \n> This is inherent to what a merge is.  With proper\nunderstanding of what\n> a merge is, you would not feel this limiting at all.\n\nI've used clearcase in the past and although there\nwere many things I\ndidn't like about it (big, slow, costs $$$$, network\npig, needs a super\nserver, etc.) it did allow commits of files at any\ntime and tracked the\nfiles that were merged independently.  I know that git\ntracks changes\nand not files; but in the end you have to pick file(s)\nor pieces of\nthem to be committed; having the tool restrict me from\ncommitting files\nbecause of the way it tracks merges IS limiting IMHO. \nI guess the big\ndifference is that in kernel land you can reject\npatches until they are\nbroken up into \"atomic\" pieces (I don't really have\nthe option of\nreversing the subversion commit and turning it into\n\"atomic\" commits).\n\n> Having said that, I think something like the\nfollowing _could_ be done,\n> although I do not know if it makes much sense.\n> \n> (1) Try merge, see it conflict, resolve only a part\nof it, and record\n>     the result as \"WIP to merge in A\".  Do not\nrecord it as a merge, as\n>     it is not.  diff between B and M will contain a\nsquash merge of A on\n>     top of B minus the changes to the path xyzzy.\n> \n>          o---o---A\n>         /         \n>     ---o---o---B---M\n> \n> (2) Fix up the conflicts in xyzzy to resolve the\nconflicts fully, and\n>     record the result as \"Final merge of A into B\". \nThis should be\n>     recorded as a merge, as the result is \"keeping\nchanges done on both\n>     branches to come up with something better than\neither of them.\"\n> \n>          o---o---A---,\n>         /             \\\n>     ---o---o---B---M---N\n> \n> If you look at the topology a bit differently, the\nabove actually makes\n> some sense:\n> \n>          .---o---o---A\n>         /             \\\n>     ---o---o---B---M---N\n> \n> That is, instead of merging A into B, you made\n\"preparatory changes\" to\n> branch B in order to make it easier to merge A. \nThat's what the commit\n> M is about.\n> \n> Then you merge A on top of M.  In reality, because\nthe difference\n> between B to M contains most of the squash merge of\nA into B, such a\n> merge N will contain many accidental clean merges. \nBut in git,\n> accidental clean merges are not a problem (people\ncan apply the same\n> patch to their trees and later their branches can be\nmerged).\n> \n> But \"git commit\" after a conflicted merge will\nalways create a merge,\n> and there is no canned option to do multi-step merge\nlike the above.\n> \n> You can still do that by hand, by doing something\nlike:\n> \n> \t$ git merge --squash A\n>         $ resolve only partly\n>         $ git commit -m 'Prepare to merge A'\n>         $ git reset --hard\n>         $ git merge A\n> \t$ resolve the rest\n>         $ git commit -m 'Fully merged A'\n\nOk.  I did a git merge --squash.  So I should be able\nto try this.\nAfter I resolve only partly; I'm assuming that I git\ncheckout HEAD any\nfiles that I don't want yet and then do the commit? \nAssuming that I\ncommit the partial after throwing away any merges that\nI wasn't ready\nto do (via git checkout HEAD); what does the \"git\nreset --hard\" do? \n> For such a multi-step merge to make sense, the\nchange between B---M\n> should make sense by itself for people who have to\nread such a history\n> later.  Such a half-a-squash-merge may probably not\nmake sense by itself\n> in most cases, so I suspect the above workflow would\nnot be useful in\n> general.\n\nI would agree for the case where in the end you really\nonly have one\nproduct; but again think like you have a 2.4 kernel\nand a 2.6 kernel in\nthe same repository.  For most embedded development\n(I've been doing it\nfor 20+ years) there is always newer hardware that\nchanges processors,\nadd features, gets all the new development while the\n\"old\" production\nboard is still shipping and in customers hands and\nneeds bug fixes and\nthe occassional new feature.  It doesn't make sense to\nhave two\nseparate repositories when much of the code is the\nsame and is likely\nto need the same fixes.\n\nJunio,\n\tThanks for your time and insight; git has already\nsaved me\ncountless hours and has certainly come a long way in a\nvery short\ntime.  I'll give your multi-step merge a shot and see\nhow well it works\nfor my code base.  I'm sure there are better ways to\nstructure my code\nbase to get what I am looking for; but as is usually\nthe case the rules\nof the game have changed as I have been playing it\n(the old hardware\nwas supposed to die and never be touched again; HA\nHA).\n\nRegards,\n\nBill\n\n\n\n\n      ____________________________________________________________________________________\nBe a better pen pal. \nText or chat with friends inside Yahoo! Mail. See how.  http://overview.mail.yahoo.com/\n"}]}