{"thread":{"id":"7470","subject":"[PATCH 0/3] Somebody updated my branch tip underneath me.","startedAt":"2007-03-29T08:23:10Z","lastAt":"2007-03-31T21:39:20Z","messageCount":5,"participants":["Junio C Hamano","Sergio Callegari"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"38294","messageId":"7vslbo4fwx.fsf@assigned-by-dhcp.cox.net","threadId":"7470","inReplyTo":null,"subject":"[PATCH 0/3] Somebody updated my branch tip underneath me.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-29T08:23:10Z","receivedAt":"2007-03-29T08:23:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"With this series, I am taking hints from Linus and trying to\nillustrate a problem, show an approach to its solution and code\nminimally to get others interested enough to follow through.\n\n[PATCH 1/3] Add BASE index extension.\n[PATCH 2/3] update-index --{set,get}-base\n[PATCH 3/3] Use BASE index extension in git-commit and git-merge.\n\nThe problem description and the strategy to solve it are in the\ncommit log message of [PATCH 3/3].  There I only talk about\ngit-push from elsewhere while we are looking the other way, but\nthe same situation can also happen when you use a lightweight\nshared working tree (i.e. Julian phillips's git-new-workdir) and\nmake a commit on a branch in one working tree while the other\nworking tree has a checkout of the same branch.\n\nLet's see who are motivated enough to bite.\n"},{"id":"38308","messageId":"loom.20070329T133700-713@post.gmane.org","threadId":"7470","inReplyTo":"7vslbo4fwx.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 0/3] Somebody updated my branch tip underneath me.","fromName":"Sergio Callegari","fromEmail":"scallegari@arces.unibo.it","sentAt":"2007-03-29T11:55:36Z","receivedAt":"2007-03-29T11:55:36Z","isPatch":true,"sender":{"key":"scallegari@arces.unibo.it","avatar":null},"body":"Junio C Hamano <junkio <at> cox.net> writes:\n\n> \n> With this series, I am taking hints from Linus and trying to\n> illustrate a problem, show an approach to its solution and code\n> minimally to get others interested enough to follow through.\n> \n> [PATCH 1/3] Add BASE index extension.\n> [PATCH 2/3] update-index --{set,get}-base\n> [PATCH 3/3] Use BASE index extension in git-commit and git-merge.\n> \n> The problem description and the strategy to solve it are in the\n> commit log message of [PATCH 3/3].  There I only talk about\n> git-push from elsewhere while we are looking the other way, but\n> the same situation can also happen when you use a lightweight\n> shared working tree (i.e. Julian phillips's git-new-workdir) and\n> make a commit on a branch in one working tree while the other\n> working tree has a checkout of the same branch.\n> \n> Let's see who are motivated enough to bite.\n> \n> \n\nThis seems very nice, not just because of under-the-hood pushes, but also wrt\nthe contrib/workdir thing: good to solve two slightly different problems in a\nsingle consistent way.\n\nJust a minor question:\n\nFrom, your comments to patch 3/3 it looks like when a \"commit\" or \"status\" (or\nwhatever command) catches the mismatch in the head from the index-commit, it\nonly exits with a notice.  And you also mention that recovery then happens via\nhead detaching (that in your example is done manually)...\n\nIf (as I am guessing) head detaching is the /only/ possible path to recovery,\nwouldn't it make sense to do it automatically, storing somewhere the latest\nbranch one was on (e.g. to be used for subsequent merge)?\n\nAlso, in general: whenever head gets detached (e.g. by a checkout) would it make\nsense to \"by default\" store somewhere the previous branch name? (e.g. to gain a\nshorthand command to get back to the former branch)?\n\nThanks,\n\nSergio\n"},{"id":"38346","messageId":"7vwt0z3ipb.fsf@assigned-by-dhcp.cox.net","threadId":"7470","inReplyTo":"loom.20070329T133700-713@post.gmane.org","subject":"Re: [PATCH 0/3] Somebody updated my branch tip underneath me.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-29T20:20:32Z","receivedAt":"2007-03-29T20:20:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sergio Callegari <scallegari@arces.unibo.it> writes:\n\n> Junio C Hamano <junkio <at> cox.net> writes:\n>\n>> With this series, I am taking hints from Linus and trying to\n>> illustrate a problem, show an approach to its solution and code\n>> minimally to get others interested enough to follow through.\n>> \n>> [PATCH 1/3] Add BASE index extension.\n>> [PATCH 2/3] update-index --{set,get}-base\n>> [PATCH 3/3] Use BASE index extension in git-commit and git-merge.\n>> \n>> The problem description and the strategy to solve it are in the\n>> commit log message of [PATCH 3/3].  There I only talk about\n>> git-push from elsewhere while we are looking the other way, but\n>> the same situation can also happen when you use a lightweight\n>> shared working tree (i.e. Julian phillips's git-new-workdir) and\n>> make a commit on a branch in one working tree while the other\n>> working tree has a checkout of the same branch.\n>> \n>> Let's see who are motivated enough to bite.\n>> ...\n> If (as I am guessing) head detaching is the /only/ possible\n> path to recovery, wouldn't it make sense to do it\n> automatically, storing somewhere the latest branch one was on\n> (e.g. to be used for subsequent merge)?\n\nAnswering that is part of \"let's see who are motivated enough\"\narea ;-).  Are you?\n"},{"id":"38431","messageId":"loom.20070331T144714-311@post.gmane.org","threadId":"7470","inReplyTo":"7vwt0z3ipb.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 0/3] Somebody updated my branch tip underneath me.","fromName":"Sergio Callegari","fromEmail":"scallegari@arces.unibo.it","sentAt":"2007-03-31T12:50:42Z","receivedAt":"2007-03-31T12:50:42Z","isPatch":true,"sender":{"key":"scallegari@arces.unibo.it","avatar":null},"body":"Junio C Hamano <junkio <at> cox.net> writes:\n\n> \n> Answering that is part of \"let's see who are motivated enough\"\n> area .  Are you?\n> \n> \n\nTouché! :-)\n\nSergio\n"},{"id":"38450","messageId":"7vvegh6qk7.fsf@assigned-by-dhcp.cox.net","threadId":"7470","inReplyTo":"loom.20070331T144714-311@post.gmane.org","subject":"Re: [PATCH 0/3] Somebody updated my branch tip underneath me.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-31T21:39:20Z","receivedAt":"2007-03-31T21:39:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sergio Callegari <scallegari@arces.unibo.it> writes:\n\n> Junio C Hamano <junkio <at> cox.net> writes:\n>\n>> \n>> Answering that is part of \"let's see who are motivated enough\"\n>> area .  Are you?\n>\n> Touché! :-)\n\nHaving said that...\n\n       If we allowed a commit to be created in such a case, your next\n       commit will have B as the parent, with the tree state you wanted\n       to have in X.  The graph becomes like this:\n\n                 x---x---B\n                /          \\\n        ---o---A            X (New HEAD)\n\n       The commit essentially reverts what happened in 'x' and 'B',\n       which is quite bad.\n\n       What you want to happen in this case is to make a graph like\n       this:\n\n                 x---x---B branch tip\n                /\n        ---o---A-------X (your work is still based on A)\n\n       and then perhaps merge B's work, after making sure B is a\n       fast-forward of A and doing other sanity checks:\n\n                 x---x---B\n                /         \\\n        ---o---A-------X---M the final branch tip\n\nI did not code the patch to detach the HEAD at the same time,\nbecause I was not convinced that \"What you want to happen\" part\nis the *only* sane resolution of the situation.\n\nDepending on who created the chain that leads to B, I suspect\nthe desired outcome to resolve this situation would be\ndifferent.  If it was yourself working in another repository\n(either working in a separate repository on the same machine,\nand then pushed to update the branch tip from there, or working\nin a separate working tree that shares the .git/refs with this\nrepository created with Julian Phillips's workdir script to\ndirectly update the branch tip), then you might want to rebase\nthe branch tip on top of your commit 'X', resulting in a picture\nlike this instead:\n\n                         x'--x'--B' branch tip\n                        /\n        ---o---A-------X (your work is still based on A)\n\nBoth of these workflows would require you to detach your HEAD to\nA.\n\nBut it is conceivable that you might want to do an equivalent of\n\"switching branches while merging the local changes\" (aka \"git\ncheckout -m other-branch\") without making a commit, to result\nin:\n\n                 x---x---B.......X' (your work is now based on B)\n                /        tip\n        ---o---A\n\nThis is especially true when the chain leading to B is somebody\nelse's work, which potentially is already published elsewhere.\nYou do not want to rebase that (although it is perfectly fine to\nmerge with it, so the solution I suggested in the original\nmessage is Ok).\n\nThe difference in the end result is your commit will come after\nB, not before it, and in this case you do not need to detach the\nHEAD.  For this, you would need to perform the same operation as\n\"# Match the index to the working tree, and do a three-way\" part\nof git-checkout.sh:\n\n\tgit update-index --refresh >/dev/null\n\n\tnew=`git rev-parse --verify HEAD` ;# updated head at B\n\told=`git update-index --get-base` ;# base of the working tree at A\n\n\t# prepare $work tree that represents what you would have\n        # committed if you did \"git commit -a\"\n    \tgit diff-files --name-only | git update-index --remove --stdin &&\n\twork=`git write-tree` &&\n\tgit read-tree --reset -u $new || exit\n\n        # Three-way merge to transplant A..X change on top of B\n\teval GITHEAD_$new='${new_name:-${branch:-$new}}' &&\n\teval GITHEAD_$work=local &&\n\texport GITHEAD_$new GITHEAD_$work &&\n\tgit merge-recursive $old -- $new $work\n\n\t# Do not register the cleanly merged paths in the index yet.\n\t# this is not a real merge before committing, but just carrying\n\t# the working tree changes along.\n\tunmerged=`git ls-files -u`\n\tgit read-tree --reset $new\t;# index has B's tree now\n\tcase \"$unmerged\" in\n\t'')\t;;\n\t*)\n\t\t# ... except we carry the conflicted paths along\n\t\t(\n\t\t\tz40=0000000000000000000000000000000000000000\n\t\t\techo \"$unmerged\" |\n\t\t\tsed -e 's/^[0-7]* [0-9a-f]* /'\"0 $z40 /\"\n\t\t\techo \"$unmerged\"\n\t\t) | git update-index --index-info\n\t\t;;\n\tesac\n\n\nWhere you should detach your head to (if you choose to do so) is\nalready recorded in the index and \"git update-index --get-base\"\nwould give that to you if you need it, but once we detach the\nHEAD, we would not know on which branch we were, and we need to\nkeep that information while detaching the HEAD.  If there is a\nsane resolution that does not require detaching the HEAD (such\nas the above example), there is no point to do so, so I left\nthat policy decision to later steps.\n"}]}