{"thread":{"id":"7296","subject":"git push to a non-bare repository","startedAt":"2007-03-18T17:31:21Z","lastAt":"2007-03-21T17:20:38Z","messageCount":27,"participants":["Matthieu Moy","Junio C Hamano","Sam Vilain","Jakub Narebski","Theodore Tso","Shawn O. Pearce","Nicolas Pitre","Sergio Callegari","Neil Schemenauer"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"37385","messageId":"vpq648ye9w6.fsf@olympe.imag.fr","threadId":"7296","inReplyTo":null,"subject":"git push to a non-bare repository","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@imag.fr","sentAt":"2007-03-18T17:31:21Z","receivedAt":"2007-03-18T17:31:21Z","isPatch":false,"sender":{"key":"git@matthieu-moy.fr","avatar":"https://avatars.githubusercontent.com/u/14709?v=4"},"body":"Hi,\n\nI have a repository with a working tree on a machine A, did a clone to\nanother machine B and commited there locally.\n\nI want my changes to get back into the first repository, so I did a\n\"push\". The new commit is in the history, I can see it with \"git log\",\nbut the modifications are not in the working tree.\n\nThis time, it's OK: I didn't have any uncommited modifications on A,\nso I just did a \"git reset --hard HEAD\" there.\n\nBut if I had some uncommited changes, \"git reset --hard HEAD\" means\ndata loss, which is precisely what I want to avoid by using a VCS. It\nseems a solution is to do:\n\n$ git reset --soft <commit-id-before-the-push>\n$ git merge <commit-id-after-the-push>\n\nBut it means I have to remember <commit-id-before-the-push>.\n\n\nI don't understand the design choice here: git had two options to\navoid this scenario:\n\n1) update the working tree while doing the push. That's feasible with\n   good performance since git is present on the server, but leaves the\n   problem of possible conflicts.\n\n2) let git remember what the local tree points to (not just the branch\n   name, but the commit id itself, stored in a place that \"git push\"\n   won't modify). Then, provide me a way to \"update\" to the latest\n   revision.\n\nFyi, bzr does this. Indeed, in bzr, a branch (let's say \"repository\"\nin the git vocabulary) with a working tree just means a working tree\n(AKA lightweight checkout) located in the same directory as a branch.\nThe working tree knows which revision it corresponds to, and where to\nfind its branch. There's a \"bzr update\" command to get my working tree\nto the head of the branch, keeping the uncommited changes.\n\nI believe this idea is very much linked to the \"Lightweight Checkout\"\nidea (listed on the SoC ideas), since, in the case of multiple working\ndirectories sharing the same .git, you don't want a commit in one tree\nto affect the others.\n\nSo, did I miss something? Is there anything on the todo-list?\n\nThanks,\n\n-- \nMatthieu\n"},{"id":"37392","messageId":"7vr6rml4fb.fsf@assigned-by-dhcp.cox.net","threadId":"7296","inReplyTo":"vpq648ye9w6.fsf@olympe.imag.fr","subject":"Re: git push to a non-bare repository","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-18T19:47:36Z","receivedAt":"2007-03-18T19:47:36Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Matthieu Moy <Matthieu.Moy@imag.fr> writes:\n\n> I don't understand the design choice here: git had two options to\n> avoid this scenario:\n\nActually, there are no such \"design choices\".  That's entirely\nup to the repository owners to arrange post-update hook, to\nallow you to do anything you want.  \n\nThe default is not to encourage people (who do not know what\nthey are doing anyway) to push into non-bare repository.\n"},{"id":"37407","messageId":"45FDB447.5070507@vilain.net","threadId":"7296","inReplyTo":"7vr6rml4fb.fsf@assigned-by-dhcp.cox.net","subject":"Re: git push to a non-bare repository","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2007-03-18T21:51:03Z","receivedAt":"2007-03-18T21:51:03Z","isPatch":false,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"Junio C Hamano wrote:\n>> I don't understand the design choice here: git had two options to\n>> avoid this scenario:\n>>     \n>\n> Actually, there are no such \"design choices\".  That's entirely\n> up to the repository owners to arrange post-update hook, to\n> allow you to do anything you want.  \n>\n> The default is not to encourage people (who do not know what\n> they are doing anyway) to push into non-bare repository.\n>   \n\nMaybe it's worth making it an error (that can be forced) if you're\npushing to the head that's checked out in a non-bare repository ?\n\nIt's pretty nasty behaviour for people used to darcs / bzr et al.\n\nSam.\n"},{"id":"37409","messageId":"etkcrn$e9a$1@sea.gmane.org","threadId":"7296","inReplyTo":"45FDB447.5070507@vilain.net","subject":"Re: git push to a non-bare repository","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-03-18T22:01:28Z","receivedAt":"2007-03-18T22:01:28Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Sam Vilain wrote:\n\n> Junio C Hamano wrote:\n\n>>> I don't understand the design choice here: git had two options to\n>>> avoid this scenario:\n>>\n>> Actually, there are no such \"design choices\".  That's entirely\n>> up to the repository owners to arrange post-update hook, to\n>> allow you to do anything you want.  \n>>\n>> The default is not to encourage people (who do not know what\n>> they are doing anyway) to push into non-bare repository.\n>>   \n> \n> Maybe it's worth making it an error (that can be forced) if you're\n> pushing to the head that's checked out in a non-bare repository ?\n> \n> It's pretty nasty behaviour for people used to darcs / bzr et al.\n\nPerhaps it would be for the best.\n\nBUT unless you arrange some fancy post-update hook you have two\nsane choices:\n * push to bare repository, with 1:1 refs mapping\n * push to non-bare repository, but with mapping pushed refs on\n   pushee to remotes refs (remote / tracking branches) on remote\n   side.\n\nIn all other choices there madness lies... ;-)\n\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"37416","messageId":"7vabyanqjz.fsf@assigned-by-dhcp.cox.net","threadId":"7296","inReplyTo":"45FDB447.5070507@vilain.net","subject":"Re: git push to a non-bare repository","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-18T22:18:56Z","receivedAt":"2007-03-18T22:18:56Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sam Vilain <sam@vilain.net> writes:\n\n> Junio C Hamano wrote:\n> ...\n> Maybe it's worth making it an error (that can be forced) if you're\n> pushing to the head that's checked out in a non-bare repository ?\n\nWe talked about that in the past on the list.  No.\n"},{"id":"37439","messageId":"7vr6rmm1y9.fsf@assigned-by-dhcp.cox.net","threadId":"7296","inReplyTo":"20070319020053.GA11371@thunk.org","subject":"Re: git push to a non-bare repository","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-19T01:55:42Z","receivedAt":"2007-03-19T01:55:42Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Theodore Tso <tytso@mit.edu> writes:\n\n> Is it at all possible to figure out <commit-id-before-the-push>?  It\n> seems the answer is no, and I suspect that's a bug.\n\nDoesn't update hook get pre- and post- commit object name?\n"},{"id":"37438","messageId":"20070319020053.GA11371@thunk.org","threadId":"7296","inReplyTo":"vpq648ye9w6.fsf@olympe.imag.fr","subject":"Re: git push to a non-bare repository","fromName":"Theodore Tso","fromEmail":"tytso@mit.edu","sentAt":"2007-03-19T02:00:54Z","receivedAt":"2007-03-19T02:00:54Z","isPatch":false,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Sun, Mar 18, 2007 at 06:31:21PM +0100, Matthieu Moy wrote:\n> I have a repository with a working tree on a machine A, did a clone to\n> another machine B and commited there locally.\n> \n> I want my changes to get back into the first repository, so I did a\n> \"push\". The new commit is in the history, I can see it with \"git log\",\n> but the modifications are not in the working tree.\n\nThe general answer (which you've already received) is to tell folks is\nto simply don't use \"git push\" to remote trees; basically, if you ever\nhave a non-bare repository, it doesn't do what you expect, and it will\nleave the novice user horribly confused.  A much better answer is to\nsimply go back to machine A, and pull from machine B.\n\nI was exploring though to see if there was anything we could do\nbetter, and so I used my standard test repository of the GNU Hello,\nworld program, and did the following:\n\n\tgit clone hello r1\n\tgit clone r1 r2\n\tcd r1\n\t<edit hello.c's headers to be GPL v2 only>\n\tgit commit -a -m \"GPL v2 only\"\n\tcd ../r2\n\t<edit hello.c so that the message printed is \"Hello, world!\" \n\t\tinstead of \"hello, world\">\n\tcd ..\n\nOK, so this sets up the standard test setup of repositories r1 and r2.\nr1 contains a committed change so that hello.c is GPLv2 only.  r2\ncontains an uncommitted change to the actual text printed by hello.c.\nThe changes are nicely seprated in distaince by over 100 lines, so\nthere should be no problems with merges.  Let's play...\n\nExperiment #1.  Let's try pushing from r1 to r2.\n\n\tcd r1\n\tgit push ../r2\n\nThis pushes the change GPLv2 change from r1 to r2.  However, it leaves\nthe working tree and the index untouched, which leads to some very\nunexpected and surprising behavior:\n\n  a) If you do a \"git commit\" you will commit the current contents of\n     the index, which is usually the contents of the head of r2 before \n     the push.\n  b) If you do a \"git commit -a\" you will commit the modified changes to \n     the working directory --- based off of the state of r2 before the\n     push.  What will therefore show up in the revision log is something\n     which appears to be based off of the more recent change in r1, but \n     which is really based off of the old history as of r2 before the push.\n\nAll of this is bad, which is why \"git push\" to a non-bare repository\nis extremely surprising.  (As an aside, what Bitkeeper would do is to\nupdate the working tree, but it added the constraint that it would\nonly allow the \"bk push\" if the push resulted in a fast-forward merge,\nthus guaranteeing no conflicts, and if the none of the files that\nwould need to be updated in the working tree had been locally\nmodified; if either constraint were modified, the push would be\naborted, and the remote repository not modified at all.  It would be\nnice if we could enforce these constraints using the appropriate\nhooks, but from what I can tell the hooks aren't in the right place\nfor us to be able to do that, or to be able to undo or recover from a\nbad push.  More on that in a bit.)\n\nOK, so suppose we do the push anyway.  As you suggested, one possible\nsolution is:\n\n> $ git reset --soft <commit-id-before-the-push>\n> $ git merge <commit-id-after-the-push>\n> \n> But it means I have to remember <commit-id-before-the-push>.\n\nIs it at all possible to figure out <commit-id-before-the-push>?  It\nseems the answer is no, and I suspect that's a bug.  Maybe it doesn't\nmake sense to save the original HEAD in ORIG_HEAD in r2, but surely\nthe original HEAD should be saved in the reflog, right?  Well, at the\nmoment it saves it in neither case.\n\nThe problem is without doing this, it is as far as I can tell\nimpossible to determine what revision the index is currently\ncorresponding to, and without this information, it's very limited in\nwhat you can do.\n\nWhat possible solution which you *can* do is:\n\n\tgit diff > /tmp/stage-patch\n\tgit reset --hard\n\tpatch -p1 < /tmp/stage-patch\n\nBut that seems a bit manual and somewhat kludgy.  If we had the\nrevision of r2 before the push, it would be possible to do a 3-way\nmerge, which in some cases might result in a cleaner merge of the\nmodified files in the working tree.\n\nExperiment #2.  Let's try pulling from r2 to r1\n\nSo this is what we tell people they should do; so how well does it\nwork in this case?\n\n\t<do the above experimental setup>\n\tcd r2\n\tgit pull ../r1\n\nWhat do we get?\n\n\tUpdating f2e3cc0..37508dc\n\thello.c: needs update\n\tfatal: Entry 'hello.c' not uptodate. Cannot merge.\n\t hello.c |    7 +++----\n\t 1 files changed, 3 insertions(+), 4 deletions(-)\n\nOh, dear.  Since hello.c was locally modified, git-merge refused to do\na 3-way merge to the local file.  That's unfortunate, since if it had,\nit would have succeeded, and in this case it would have done the right\nthing.  git-checkout will do something similar, but it at has an -m\noption which will do a 3-way merge to update the local working file.\nUnfortunately git-merge and git-pull do not have such an option.\n'twould be nice if it did, but that's going to have to wait someone\nwanting to scratch that particular itch...\n\nThe failure leaves the index and the working tree in the same confused\nstate as the \"git push\" scenario, though --- the index is still\nreferring to original state of the tree before the pull, but the HEAD\nhas been updated to after the pull, so \"git commit\" will lead to the\nsame confusing behavior.  Fortunately, though, when we do a pull,\nORIG_HEAD and the reflog are updated, so we can get back to our\noriginal state via a command like this:\n\n\tgit update-ref HEAD ORIG_HEAD\n\nSo ok, let's break down the git pull into its two constiuent parts.\nThe git-fetch and the git-merge.  \n\n\tgit fetch\n\tgit merge FETCH_HEAD\n\nThis fails in the same way:\n\n   Updating f2e3cc0..37508dc\n   hello.c: needs update\n   fatal: Entry 'hello.c' not uptodate. Cannot merge.\n    hello.c |    7 +++----\n    1 files changed, 3 insertions(+), 4 deletions(-)\n\nAnd just as before, it leaves HEAD updated to FETCH_HEAD, even though\nit failed.  So it's consistent, but that's not what the documentation\nfor git-merge states:\n\n      You  may  have  local modifications in the working tree files. In other\n      words, git-diff is allowed to report changes. However, the  merge  uses\n      your  working  tree  as  the  working area, and in order to prevent the\n      merge operation from losing such changes, it makes sure  that  they  do\n      not  interfere  with the merge. Those complex tables in read-tree docu-\n      mentation define what it means  for  a  path  to  \"interfere  with  the\n      merge\".  And  if  your  local  modifications  interfere with the merge,\n      again, it stops before touching anything.\n             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWell, it certainly stops before touching any local files, but it has\nalready updated HEAD, which leaves things in a very confusion\nsituation.  Maybe it would be better if git-merge atomically failed\nand left HEAD back pointing at the original revision?   \n\n\t\t\t\t\t\t- Ted\n"},{"id":"37442","messageId":"20070319022143.GF20658@spearce.org","threadId":"7296","inReplyTo":"7vr6rmm1y9.fsf@assigned-by-dhcp.cox.net","subject":"Re: git push to a non-bare repository","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-03-19T02:21:43Z","receivedAt":"2007-03-19T02:21:43Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Junio C Hamano <junkio@cox.net> wrote:\n> Theodore Tso <tytso@mit.edu> writes:\n> \n> > Is it at all possible to figure out <commit-id-before-the-push>?  It\n> > seems the answer is no, and I suspect that's a bug.\n> \n> Doesn't update hook get pre- and post- commit object name?\n\nYes, and the same is true in the new post-receive hook.\n\n-- \nShawn.\n"},{"id":"37444","messageId":"20070319024744.GD11371@thunk.org","threadId":"7296","inReplyTo":"20070319022143.GF20658@spearce.org","subject":"Re: git push to a non-bare repository","fromName":"Theodore Tso","fromEmail":"tytso@mit.edu","sentAt":"2007-03-19T02:47:44Z","receivedAt":"2007-03-19T02:47:44Z","isPatch":false,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Sun, Mar 18, 2007 at 10:21:43PM -0400, Shawn O. Pearce wrote:\n> Junio C Hamano <junkio@cox.net> wrote:\n> > Theodore Tso <tytso@mit.edu> writes:\n> > \n> > > Is it at all possible to figure out <commit-id-before-the-push>?  It\n> > > seems the answer is no, and I suspect that's a bug.\n> > \n> > Doesn't update hook get pre- and post- commit object name?\n> \n> Yes, and the same is true in the new post-receive hook.\n\nIn my comments, I was observing that *after* the push had succeeded,\nthere was no way to find the commit-id-before-the-push, since neither\nthe reflog nor ORIG_HEAD is getting updated.  Is there a good reason\nwhy not?  Would you accept a patch which caused the reflog and\npossibly ORIG_HEAD to be updated on the remote side of the push?\n\n\nWhen I was talking about a hook to enforce the BitKeeper semantics,\nthe question is whether we have enough to enforce the following:\n\n\t* Only accept the push if it will result in a fast-forward\n\t\tmerge (and if not, tell the user to do a git pull, merge\n\t\tlocally, and then redo the git push)\n\t* Only accept the push if there are no locally modified files\n\t\tthat would be affected when the working directory is\n\t\tupdated to reflect the new HEAD\n\nI don't think there's any easy way to determine if these two criteria\nwould be met besides trying to actually do the merge, and if it fails\natomically back out to the original starting point, right?  Or am I\nmissing something painfully obvious?\n\nSince one of the applications where I might want to do something like\nthis is a push a web site being maintained by git (where I don't want\nany the result of the interim attempted to merge to accidentally get\nseen by the web server), probably in order to do this right I'd have\nto have the hook script do a cp -rl of the repository+working tree to\nsome scratch space, try to do the merge and update of the working\ntree, and if it succeeds, allow it to happen for real in the \"live\"\ntree, and if not, fail the merge.  This seems awfully kludgy; is there\nsome other way?\n\n\t\t\t\t\t\t- Ted\n"},{"id":"37445","messageId":"20070319025603.GG20658@spearce.org","threadId":"7296","inReplyTo":"20070319024744.GD11371@thunk.org","subject":"Re: git push to a non-bare repository","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-03-19T02:56:03Z","receivedAt":"2007-03-19T02:56:03Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Theodore Tso <tytso@mit.edu> wrote:\n> On Sun, Mar 18, 2007 at 10:21:43PM -0400, Shawn O. Pearce wrote:\n> > Junio C Hamano <junkio@cox.net> wrote:\n> > > Theodore Tso <tytso@mit.edu> writes:\n> > > \n> > > > Is it at all possible to figure out <commit-id-before-the-push>?  It\n> > > > seems the answer is no, and I suspect that's a bug.\n> > > \n> > > Doesn't update hook get pre- and post- commit object name?\n> > \n> > Yes, and the same is true in the new post-receive hook.\n> \n> In my comments, I was observing that *after* the push had succeeded,\n> there was no way to find the commit-id-before-the-push, since neither\n> the reflog nor ORIG_HEAD is getting updated.  Is there a good reason\n> why not?  Would you accept a patch which caused the reflog and\n> possibly ORIG_HEAD to be updated on the remote side of the push?\n\nThe reflog does update if the log file exists during a push (err,\nactually during receive-pack).  Or if core.logAllRefUpdates is set\nto true.  Now this isn't the default in a bare repository, but it\nshould be the default in a repository with a working directory.\nSo the case we are talking about should be seeing the reflog update.\n \n> When I was talking about a hook to enforce the BitKeeper semantics,\n> the question is whether we have enough to enforce the following:\n> \n> \t* Only accept the push if it will result in a fast-forward\n> \t\tmerge (and if not, tell the user to do a git pull, merge\n> \t\tlocally, and then redo the git push)\n\nYes, the update hook can detect this.  Actually receive-pack by\ndefault rejects *all* non-fast-forward pushes, even if the client\nside uses --force.\n\n> \t* Only accept the push if there are no locally modified files\n> \t\tthat would be affected when the working directory is\n> \t\tupdated to reflect the new HEAD\n\nThe update hook could also perform this check; test if the ref\nbeing updated is the current branch, and if so, verify the index and\nworking directory is clean.  That's a simple run of git-symbolic-ref\n(to get the current branch) and git-runstatus (to check the index\nand working directory), is it not?\n\nIf git-runstatus exits to indicate the tree is clean (nothing to\ncommit) then a simple `read-tree -m -u HEAD $new` should update\nthe working directory and index, right?\n\n-- \nShawn.\n"},{"id":"37454","messageId":"20070319032130.GF11371@thunk.org","threadId":"7296","inReplyTo":"20070319025603.GG20658@spearce.org","subject":"Re: git push to a non-bare repository","fromName":"Theodore Tso","fromEmail":"tytso@mit.edu","sentAt":"2007-03-19T03:21:30Z","receivedAt":"2007-03-19T03:21:30Z","isPatch":false,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Sun, Mar 18, 2007 at 10:56:03PM -0400, Shawn O. Pearce wrote:\n> The reflog does update if the log file exists during a push (err,\n> actually during receive-pack).  Or if core.logAllRefUpdates is set\n> to true.  Now this isn't the default in a bare repository, but it\n> should be the default in a repository with a working directory.\n> So the case we are talking about should be seeing the reflog update.\n\nSo I dug a little more deeply, and the problem is that the reflog for\nmaster was getting updated, but not the reflog for HEAD, and that's\nwhat \"git reflog\" was showing --- hence my confusion.\n\nWhat are the rules for when HEAD's reflog should get updated, and is\nthis documented anywhere in the man pages?\n\n\t\t\t\t\t\t- Ted\n\nScript started on Sun 18 Mar 2007 11:11:59 PM EDT\nTop-level shell (parent script)\nUsing ssh-agent pid 7679\n<tytso@candygram> {/home/tytso/talks/dscm/git}  \n1% cp -r test1 test2 ; cd test2\n<tytso@candygram> {/home/tytso/talks/dscm/git/test2}  \n2% (cd r2; git-config core.logallrefupdates)\ntrue\n<tytso@candygram> {/home/tytso/talks/dscm/git/test2}  \n3% cat r2/.git/refs/heads/master\nf2e3cc0bb64c8c94b89ba07bfbdd1653584586f2\n<tytso@candygram> {/home/tytso/talks/dscm/git/test2}  \n4% cat r2/.git/logs/HEAD\n0000000000000000000000000000000000000000 f2e3cc0bb64c8c94b89ba07bfbdd1653584586f2 Theodore Ts'o <tytso@mit.edu> 1174266825 -0400\n<tytso@candygram> {/home/tytso/talks/dscm/git/test2}  \n5% cat r2/.git/logs/refs/heads/master\n0000000000000000000000000000000000000000 f2e3cc0bb64c8c94b89ba07bfbdd1653584586f2 Theodore Ts'o <tytso@mit.edu> 1174266825 -0400\n<tytso@candygram> {/home/tytso/talks/dscm/git/test2}  \n6% (cd r1 ; git push ../r2)\nupdating 'refs/heads/master'\n  from f2e3cc0bb64c8c94b89ba07bfbdd1653584586f2\n  to   37508dc11dbe274d021124057fd2d027f6ce9d17\nGenerating pack...\nDone counting 5 objects.\nResult has 3 objects.\nDeltifying 3 objects.\n 100% (3/3) done\nWriting 3 objects.\n 100% (3/3) done\nTotal 3 (delta 2), reused 0 (delta 0)\nUnpacking 3 objects\n  100% (3/3) done\nrefs/heads/master: f2e3cc0bb64c8c94b89ba07bfbdd1653584586f2 -> 37508dc11dbe274d021124057fd2d027f6ce9d17\n<tytso@candygram> {/home/tytso/talks/dscm/git/test2}  \n7% cd r2\n<tytso@candygram> {/home/tytso/talks/dscm/git/test2/r2}  [master]\n8% cat .git/refs/heads/master\n37508dc11dbe274d021124057fd2d027f6ce9d17\n<tytso@candygram> {/home/tytso/talks/dscm/git/test2/r2}  [master]\n9% cat .git/logs/HEAD\n0000000000000000000000000000000000000000 f2e3cc0bb64c8c94b89ba07bfbdd1653584586f2 Theodore Ts'o <tytso@mit.edu> 1174266825 -0400\n<tytso@candygram> {/home/tytso/talks/dscm/git/test2/r2}  [master]\n10% cat .git/logs/refs/heads/master\n0000000000000000000000000000000000000000 f2e3cc0bb64c8c94b89ba07bfbdd1653584586f2 Theodore Ts'o <tytso@mit.edu> 1174266825 -0400\nf2e3cc0bb64c8c94b89ba07bfbdd1653584586f2 37508dc11dbe274d021124057fd2d027f6ce9d17 Theodore Ts'o <tytso@mit.edu> 1174274004 -0400\tpush\n<tytso@candygram> {/home/tytso/talks/dscm/git/test2/r2}  [master]\n11% git reflog\n37508dc... HEAD@{0}: \n<tytso@candygram> {/home/tytso/talks/dscm/git/test2/r2}  [master]\n13% git version\ngit version 1.5.0.5.425.g9cec6-dirty\n<tytso@candygram> {/home/tytso/talks/dscm/git/test2/r2}  [master]\n14% exit\n\nScript done on Sun 18 Mar 2007 11:14:28 PM EDT\n"},{"id":"37455","messageId":"20070319033340.GG11371@thunk.org","threadId":"7296","inReplyTo":"20070319025603.GG20658@spearce.org","subject":"Re: git push to a non-bare repository","fromName":"Theodore Tso","fromEmail":"tytso@mit.edu","sentAt":"2007-03-19T03:33:40Z","receivedAt":"2007-03-19T03:33:40Z","isPatch":false,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Sun, Mar 18, 2007 at 10:56:03PM -0400, Shawn O. Pearce wrote:\n> > When I was talking about a hook to enforce the BitKeeper semantics,\n> > the question is whether we have enough to enforce the following:\n> > \n> > \t* Only accept the push if it will result in a fast-forward\n> > \t\tmerge (and if not, tell the user to do a git pull, merge\n> > \t\tlocally, and then redo the git push)\n> \n> Yes, the update hook can detect this.  Actually receive-pack by\n> default rejects *all* non-fast-forward pushes, even if the client\n> side uses --force.\n\nAh, so that's controlled by receive.denyNonFastForwards, right?  Cool,\nI missed that.  Thanks!!\n\nDocumentation/config.txt doesn't say it defaults to true, but from\nyour comments that is the default?\n\n> > \t* Only accept the push if there are no locally modified files\n> > \t\tthat would be affected when the working directory is\n> > \t\tupdated to reflect the new HEAD\n> \n> The update hook could also perform this check; test if the ref\n> being updated is the current branch, and if so, verify the index and\n> working directory is clean.  That's a simple run of git-symbolic-ref\n> (to get the current branch) and git-runstatus (to check the index\n> and working directory), is it not?\n> \n> If git-runstatus exits to indicate the tree is clean (nothing to\n> commit) then a simple `read-tree -m -u HEAD $new` should update\n> the working directory and index, right?\n\nWhat git-runstatus will allow me to do is to abort if there are any\nlocal modifications, regardless of whether or not they would conflict\nwith the working tree update.  The key phrase in my criteria was no\nlocally modified files \"THAT WOULD BE AFFECTED\".\n\nWhat I could do with BitKeeper is that I could modify some file like\nschedule.html on my webserver, and then push a changeset from my\nlaptop to would update sermons.html, and it would allow the push ---\nsince it would change the file sermons.html, and not touch\nschedule.html.\n\nBut if I modified schedule.html on my laptop and then committed it,\nand *then* try to push that changeset to the webserver, it would abort\nsince in order to accept the changeset, it would have to update the\nworking tree, and that would clash with the locally modified\nschedule.html file.  At thta point I'd have to login to the webserver,\nrevert the local modification and bring it back down my laptop and\ninclude it in a proper changeset.\n\nYeah, I probably shouldn't have ever modified the file locally on the\nwebserver, but that would sometimes happen when I was in a rush, and\nit was nice when it Just Worked.\n\n\t\t\t\t\t\t- Ted\n"},{"id":"37458","messageId":"20070319034755.GH20658@spearce.org","threadId":"7296","inReplyTo":"20070319033340.GG11371@thunk.org","subject":"Re: git push to a non-bare repository","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-03-19T03:47:55Z","receivedAt":"2007-03-19T03:47:55Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Theodore Tso <tytso@mit.edu> wrote:\n> Ah, so that's controlled by receive.denyNonFastForwards, right?  Cool,\n> I missed that.  Thanks!!\n> \n> Documentation/config.txt doesn't say it defaults to true, but from\n> your comments that is the default?\n\nAh, my bad, it defaults to false:\n\n  static int deny_non_fast_forwards = 0;\n\nI should have known better, as I run a 1.5.x (aka 'next') server\nfor a workgroup and I never have that set, but use instead a complex\nupdate hook that decides if a fast-forward is required or not.\n \n> > > \t* Only accept the push if there are no locally modified files\n> > > \t\tthat would be affected when the working directory is\n> > > \t\tupdated to reflect the new HEAD\n> > \n> > If git-runstatus exits to indicate the tree is clean (nothing to\n> > commit) then a simple `read-tree -m -u HEAD $new` should update\n> > the working directory and index, right?\n> \n> What git-runstatus will allow me to do is to abort if there are any\n> local modifications, regardless of whether or not they would conflict\n> with the working tree update.  The key phrase in my criteria was no\n> locally modified files \"THAT WOULD BE AFFECTED\".\n\n  git-diff $old $new | git-apply --index ?\n\nIf the patch does not apply, nothing gets updated.  If it does apply,\nthe index is also updated and stat data updated.\n\nOK, it doesn't quite handle every case, as sometimes a patch will\nreject but the internal 3-way merge from xdiff that is called by\nmerge-recursive will succeed, but this does protect your working\ntree and doesn't require making a temporary copy.\n\n\nOf course another possible approach is to stuff the entire working\ndirectory into a temporary tree, and then merge.  If the merge\ndoesn't work, you can reset to the temporary tree.  Unfortunately the\nworking directory is \"in flux\" during that process... its not atomic.\n\n-- \nShawn.\n"},{"id":"37459","messageId":"20070319035351.GI20658@spearce.org","threadId":"7296","inReplyTo":"20070319032130.GF11371@thunk.org","subject":"Re: git push to a non-bare repository","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-03-19T03:53:51Z","receivedAt":"2007-03-19T03:53:51Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Theodore Tso <tytso@mit.edu> wrote:\n> So I dug a little more deeply, and the problem is that the reflog for\n> master was getting updated, but not the reflog for HEAD, and that's\n> what \"git reflog\" was showing --- hence my confusion.\n> \n> What are the rules for when HEAD's reflog should get updated, and is\n> this documented anywhere in the man pages?\n\nIt is buried down in write_ref_sha1 (in refs.c).  The rule is if the\nname of the ref given to us for update does not match the actual\nref we are about to change, we log to both the original ref name\ngiven and the actual ref name.\n\nThis handles the case of HEAD being a symref to some actual branch;\nwe update the HEAD reflog and the actual branch reflog whenever\nsomeone updates HEAD.  Which is what we are usually doing from\ntools like git-checkout.\n\nreceive-pack isn't updating the HEAD reflog as its updating the\nactual branch, not HEAD.  If you pushed instead to HEAD you should\nsee the HEAD reflog entry too.\n\nIts a little ugly here as I'm not sure we should always update\nHEAD's reflog if HEAD points at a branch we are actually updating.\nMaybe we should though in receive-pack ?\n\n-- \nShawn.\n"},{"id":"37461","messageId":"alpine.LFD.0.83.0703182355570.18328@xanadu.home","threadId":"7296","inReplyTo":"20070319035351.GI20658@spearce.org","subject":"Re: git push to a non-bare repository","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2007-03-19T04:08:47Z","receivedAt":"2007-03-19T04:08:47Z","isPatch":false,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"On Sun, 18 Mar 2007, Shawn O. Pearce wrote:\n\n> Theodore Tso <tytso@mit.edu> wrote:\n> > So I dug a little more deeply, and the problem is that the reflog for\n> > master was getting updated, but not the reflog for HEAD, and that's\n> > what \"git reflog\" was showing --- hence my confusion.\n> > \n> > What are the rules for when HEAD's reflog should get updated, and is\n> > this documented anywhere in the man pages?\n> \n> It is buried down in write_ref_sha1 (in refs.c).  The rule is if the\n> name of the ref given to us for update does not match the actual\n> ref we are about to change, we log to both the original ref name\n> given and the actual ref name.\n> \n> This handles the case of HEAD being a symref to some actual branch;\n> we update the HEAD reflog and the actual branch reflog whenever\n> someone updates HEAD.  Which is what we are usually doing from\n> tools like git-checkout.\n> \n> receive-pack isn't updating the HEAD reflog as its updating the\n> actual branch, not HEAD.  If you pushed instead to HEAD you should\n> see the HEAD reflog entry too.\n\nThis is indeed a corner case.  And it was never considered before as \ngreat care was made at the time to be sure pushes wouldn't create any \nreflogs on the remote side, which is effectively done by not \nautomatically enabling reflogs on bare repos.\n\n> Its a little ugly here as I'm not sure we should always update\n> HEAD's reflog if HEAD points at a branch we are actually updating.\n> Maybe we should though in receive-pack ?\n\nIf the meaning of HEAD changed (although indirectly) because HEAD \nhappens to point to the branch that just got updated then logically the \nHEAD reflog should be updated too.  On the other hand the HEAD reflog \nshould reflect operations performed on HEAD.  Since the push updates the \nbranch directly it is not exactly performing some operation on HEAD \nsince HEAD could point anywhere and that wouldn't change the push at \nall.\n\nMeaning that for the discussion of pushing to a non-bare repository with \na dirty working tree... If the branch being pushed into is not pointed \nto by HEAD then no consideration what so ever about the working tree \nshould be made, and no update to the HEAD reflog made of course.\n\n\nNicolas\n"},{"id":"37463","messageId":"7vejnlna2z.fsf@assigned-by-dhcp.cox.net","threadId":"7296","inReplyTo":"20070319034755.GH20658@spearce.org","subject":"Re: git push to a non-bare repository","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-19T04:14:44Z","receivedAt":"2007-03-19T04:14:44Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Shawn O. Pearce\" <spearce@spearce.org> writes:\n\n>   git-diff $old $new | git-apply --index ?\n>\n> If the patch does not apply, nothing gets updated.  If it does apply,\n> the index is also updated and stat data updated.\n\nAnd if you are only checking then perhaps instead of --index\nuse --check, so that the actual updates are deferred?\n"},{"id":"37473","messageId":"20070319062525.GH11371@thunk.org","threadId":"7296","inReplyTo":"alpine.LFD.0.83.0703182355570.18328@xanadu.home","subject":"Re: git push to a non-bare repository","fromName":"Theodore Tso","fromEmail":"tytso@mit.edu","sentAt":"2007-03-19T06:25:25Z","receivedAt":"2007-03-19T06:25:25Z","isPatch":false,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Mon, Mar 19, 2007 at 12:08:47AM -0400, Nicolas Pitre wrote:\n> > Its a little ugly here as I'm not sure we should always update\n> > HEAD's reflog if HEAD points at a branch we are actually updating.\n> > Maybe we should though in receive-pack ?\n> \n> If the meaning of HEAD changed (although indirectly) because HEAD \n> happens to point to the branch that just got updated then logically the \n> HEAD reflog should be updated too.  On the other hand the HEAD reflog \n> should reflect operations performed on HEAD.  Since the push updates the \n> branch directly it is not exactly performing some operation on HEAD \n> since HEAD could point anywhere and that wouldn't change the push at \n> all.\n> \n> Meaning that for the discussion of pushing to a non-bare repository with \n> a dirty working tree... If the branch being pushed into is not pointed \n> to by HEAD then no consideration what so ever about the working tree \n> should be made, and no update to the HEAD reflog made of course.\n\nRight, but if the branch being pointed to is pointed to by HEAD I\nwould argue that the reflog for HEAD should be updated, since\noperations that reference HEAD will see a new commit, and and it will\nbe confusing when \"git reflog\" shows no hint of the change.\n\nOf couse, if the branch being pushed to isn't one which is pointed by\nHEAD, of course HEAD's reflog shouldn't be updated.\n\n\t\t\t\t\t\t- Ted\n"},{"id":"37475","messageId":"7vzm69ivfg.fsf@assigned-by-dhcp.cox.net","threadId":"7296","inReplyTo":"20070319062525.GH11371@thunk.org","subject":"Re: git push to a non-bare repository","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-19T06:44:51Z","receivedAt":"2007-03-19T06:44:51Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Theodore Tso <tytso@mit.edu> writes:\n\n> Right, but if the branch being pointed to is pointed to by HEAD I\n> would argue that the reflog for HEAD should be updated, since\n> operations that reference HEAD will see a new commit, and and it will\n> be confusing when \"git reflog\" shows no hint of the change.\n>\n> Of couse, if the branch being pushed to isn't one which is pointed by\n> HEAD, of course HEAD's reflog shouldn't be updated.\n\nIf we were to do this properly, we probably would need to\nrestructure the reflog update code for the HEAD in a major way.\n\"git-update-ref refs/heads/foo $newvalue\" when HEAD points at\nbranch 'foo' currently does not update HEAD reflog because the\ncurrent definition of HEAD reflog is (as Nico mentioned) log of\nchanges made through HEAD symref.  Instead, we would need a\nreverse lookup every time any ref is updated to see if that ref\nis pointed by any symbolics ref and update the reflogs of those\nsymbolic refs.  This is expensive to do in general, though,\nbecause there is no backpointer to list of symbolic refs that\npoint at a non-symbolic ref.\n"},{"id":"37480","messageId":"vpq8xdtpp3g.fsf@olympe.imag.fr","threadId":"7296","inReplyTo":"20070319020053.GA11371@thunk.org","subject":"Re: git push to a non-bare repository","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@imag.fr","sentAt":"2007-03-19T09:19:47Z","receivedAt":"2007-03-19T09:19:47Z","isPatch":false,"sender":{"key":"git@matthieu-moy.fr","avatar":"https://avatars.githubusercontent.com/u/14709?v=4"},"body":"Theodore Tso <tytso@mit.edu> writes:\n\n> On Sun, Mar 18, 2007 at 06:31:21PM +0100, Matthieu Moy wrote:\n>> I have a repository with a working tree on a machine A, did a clone to\n>> another machine B and commited there locally.\n>> \n>> I want my changes to get back into the first repository, so I did a\n>> \"push\". The new commit is in the history, I can see it with \"git log\",\n>> but the modifications are not in the working tree.\n>\n> The general answer (which you've already received) is to tell folks is\n> to simply don't use \"git push\" to remote trees; basically, if you ever\n> have a non-bare repository, it doesn't do what you expect, and it will\n> leave the novice user horribly confused.  A much better answer is to\n> simply go back to machine A, and pull from machine B.\n\nIt's not really an option in my case. A is a fixe-IP/fixe-DNS machine,\nwhile B is my home machine, behind a NAT modem-router. So, I'd have to\nfigure out my home IP, port-forward the ssh port from the modem to my\nmachine, ...\n\nIf I understand correctly the other answers, I have two options:\n\n* Git doesn't manage this case, and doesn't care about me loosing data\n  if they're not commited, I'll have to do it myself with hooks.\n\n* Create a bare repository on machine A, and clone it to a non-bare\n  repo on which I'll work. But that means duplicating the repository\n  on the same filesystem of the same machine. Not really satisfactory\n  either. The \"light checkout\" feature would make it better, but I'm\n  still worried about what will happen to my light checkout when\n  someone pushes to the repository.\n\n-- \nMatthieu\n"},{"id":"37482","messageId":"etlmro$l1s$1@sea.gmane.org","threadId":"7296","inReplyTo":"vpq8xdtpp3g.fsf@olympe.imag.fr","subject":"Re: git push to a non-bare repository","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-03-19T10:01:09Z","receivedAt":"2007-03-19T10:01:09Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Matthieu Moy wrote:\n\n> * Create a bare repository on machine A, and clone it to a non-bare\n>   repo on which I'll work. But that means duplicating the repository\n>   on the same filesystem of the same machine. Not really satisfactory\n>   either. The \"light checkout\" feature would make it better, but I'm\n>   still worried about what will happen to my light checkout when\n>   someone pushes to the repository.\n\nYou can share repository object database using alternates.\n\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"37490","messageId":"loom.20070319T124736-893@post.gmane.org","threadId":"7296","inReplyTo":"vpq648ye9w6.fsf@olympe.imag.fr","subject":"Re: git push to a non-bare repository","fromName":"Sergio Callegari","fromEmail":"scallegari@arces.unibo.it","sentAt":"2007-03-19T12:44:42Z","receivedAt":"2007-03-19T12:44:42Z","isPatch":false,"sender":{"key":"scallegari@arces.unibo.it","avatar":null},"body":"Hi,\n\nMatthieu Moy <Matthieu.Moy <at> imag.fr> writes:\n\n> \n> Hi,\n> \n> I have a repository with a working tree on a machine A, did a clone to\n> another machine B and commited there locally.\n> \n> I want my changes to get back into the first repository, so I did a\n> \"push\". The new commit is in the history, I can see it with \"git log\",\n> but the modifications are not in the working tree.\n> \n> This time, it's OK: I didn't have any uncommited modifications on A,\n> so I just did a \"git reset --hard HEAD\" there.\n\nAt times I have a similar scenario, working with both an office-pc (attached to\nthe internet with a public static address) and a laptop (either detached from\nthe internet or attached to it under a dynamic address and NAT) \n\n> But if I had some uncommited changes, \"git reset --hard HEAD\" means\n> data loss, which is precisely what I want to avoid by using a VCS. It\n> seems a solution is to do:\n> \n> $ git reset --soft <commit-id-before-the-push>\n> $ git merge <commit-id-after-the-push>\n\nI think that there might also be another option...\nperhaps in some cases you might want to commit the local changes by branching\nat <commit-id-before-the-push>...\n\nFor instance:\n* you work on the office-pc: work work work (you do not commit yet, as you\nexpect you will be able to finish your stuff and commit after that)\n* but for some reason you do not finish, you go away and you start working on\nthe laptop...\n* you cannot pull the changes from the office-pc (as they are not committed)\nand assume you cannot or don't want to retrieve them otherwise... so you start\nworking on what you have... work work work ... commit. You do not branch before\ncommitting as this is a finished thing and you now believe it deserves going on\nyour current branch... (or you just have forgotten about the hanging stuff on\nthe office-pc)...\n* As soon as you can, you push to the office-pc\n* Since the local changes on the office-pc are relative to something that has\nsuddendly got older than the current branch-tip, you might want to merge, but\nyou also might not want to... you might prefer to complete the thing and first\ntest it as is... in this case you might want to branch, rather than merging.\n\nSo when you push to a non-bare repo, it might probably be nice to be able to\nselect between different behaviors:\nA) Try to auto merge and refuse the push if merging is impossible (as it is\ncurrently suggested)\nB) Accept the push anyway (in the end if one machine is under NAT, pushing is\nthe only way to propagate changes), update the branch, loose the head and store\nsomewhere some information like \"I used to be in branch so and so, but I am not\nanymore at the branch tip since that has been changed, local changes are against\ncommit ...\"  In this way the non-bare repo can start working as if it has become\na headless checkout with local changes, explaining the situation and suggesting\nappropriate action (either merging or branching) to the user...\nsomething like:\ngit status (or git commit)\nNo current branch since the repository has been changed from outside this\nworking tree... Cannot commit... Your last branch was ...\nPossible options\n< suggestion for merging >\n< suggestion for branching >\n\nI do not know if this makes any sense at all, since my usage of git is somehow\nlimited and atypical (e.g. due to the 2 machines) and I might be missing many\nmany implications...\n\nHowever B looks like a behavior that could be applied also in the case of\nmultiple working trees insisting on a single repo, like in Junio's recen post\nwhere he wrote:\n\n > These days I use a few working trees that are connected to my\n> primary repository (which also has a working tree).  The primary\n> repository is in /src/git, and other ones look like this:\n> \n> : gitster git.wk0; ls -l .git/\n> total 120\n> drwxrwsr-x  3 junio src  4096 Mar  5 16:22 ./\n> drwxrwsr-x 15 junio src 16384 Mar  5 16:23 ../\n> -rw-rw-r--  1 junio src    41 Mar  5 16:22 HEAD\n> lrwxrwxrwx  1 junio src    27 Mar  3 22:53 config -> /src/git/.git/config\n> lrwxrwxrwx  1 junio src    26 Mar  3 22:53 hooks -> /src/git/.git/hooks/\n> -rw-rw-r--  1 junio src 82455 Mar  5 16:22 index\n> lrwxrwxrwx  1 junio src    25 Mar  3 22:53 info -> /src/git/.git/info/\n> drwxrwsr-x  3 junio src  4096 Mar  3 22:59 logs/\n> lrwxrwxrwx  1 junio src    28 Mar  3 22:53 objects -> /src/git/.git/objects/\n> lrwxrwxrwx  1 junio src    32 Mar  3 22:53 packed-refs ->\n/src/git/.git/packed-refs\n> lrwxrwxrwx  1 junio src    25 Mar  3 22:53 refs -> /src/git/.git/refs/\n> lrwxrwxrwx  1 junio src    28 Mar  3 22:53 remotes -> /src/git/.git/remotes/\n> lrwxrwxrwx  1 junio src    29 Mar  3 22:53 rr-cache -> /src/git/.git/rr-cache/\n> \n> It shares everything other than HEAD and the index (the reflog\n> for branches are also shared by a symlink .git/logs/refs\n> pointing at the one in the primary repository).\n> \n> This risks confusion for an uninitiated if you update a ref that\n> is checked out in another working tree, but modulo that caveat\n> it works reasonably well.\n> \n> We might want to add an option to 'git-clone' to create\n> something like this, but I am somewhat worried about the newbie\n> confusion factor.  Perhaps...\n> \n> $ git clone --i-know-what-i-am-doing-give-me-an-alternate-working-tree \\\n>   /src/git /src/git.wk0\n\n\nSo, did I miss something?\n \nMany thanks,\n\nSergio\n"},{"id":"37504","messageId":"alpine.LFD.0.83.0703191115180.18328@xanadu.home","threadId":"7296","inReplyTo":"20070319062525.GH11371@thunk.org","subject":"Re: git push to a non-bare repository","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2007-03-19T15:16:11Z","receivedAt":"2007-03-19T15:16:11Z","isPatch":false,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"On Mon, 19 Mar 2007, Theodore Tso wrote:\n\n> On Mon, Mar 19, 2007 at 12:08:47AM -0400, Nicolas Pitre wrote:\n> > If the meaning of HEAD changed (although indirectly) because HEAD \n> > happens to point to the branch that just got updated then logically the \n> > HEAD reflog should be updated too.  On the other hand the HEAD reflog \n> > should reflect operations performed on HEAD.  Since the push updates the \n> > branch directly it is not exactly performing some operation on HEAD \n> > since HEAD could point anywhere and that wouldn't change the push at \n> > all.\n> > \n> > Meaning that for the discussion of pushing to a non-bare repository with \n> > a dirty working tree... If the branch being pushed into is not pointed \n> > to by HEAD then no consideration what so ever about the working tree \n> > should be made, and no update to the HEAD reflog made of course.\n> \n> Right, but if the branch being pointed to is pointed to by HEAD I\n> would argue that the reflog for HEAD should be updated, since\n> operations that reference HEAD will see a new commit, and and it will\n> be confusing when \"git reflog\" shows no hint of the change.\n> \n> Of couse, if the branch being pushed to isn't one which is pointed by\n> HEAD, of course HEAD's reflog shouldn't be updated.\n\nI think we're saying the exact same thing.\n\n\nNicolas\n"},{"id":"37505","messageId":"alpine.LFD.0.83.0703191116181.18328@xanadu.home","threadId":"7296","inReplyTo":"7vzm69ivfg.fsf@assigned-by-dhcp.cox.net","subject":"Re: git push to a non-bare repository","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2007-03-19T15:20:36Z","receivedAt":"2007-03-19T15:20:36Z","isPatch":false,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"On Sun, 18 Mar 2007, Junio C Hamano wrote:\n\n> Theodore Tso <tytso@mit.edu> writes:\n> \n> > Right, but if the branch being pointed to is pointed to by HEAD I\n> > would argue that the reflog for HEAD should be updated, since\n> > operations that reference HEAD will see a new commit, and and it will\n> > be confusing when \"git reflog\" shows no hint of the change.\n> >\n> > Of couse, if the branch being pushed to isn't one which is pointed by\n> > HEAD, of course HEAD's reflog shouldn't be updated.\n> \n> If we were to do this properly, we probably would need to\n> restructure the reflog update code for the HEAD in a major way.\n> \"git-update-ref refs/heads/foo $newvalue\" when HEAD points at\n> branch 'foo' currently does not update HEAD reflog because the\n> current definition of HEAD reflog is (as Nico mentioned) log of\n> changes made through HEAD symref.  Instead, we would need a\n> reverse lookup every time any ref is updated to see if that ref\n> is pointed by any symbolics ref and update the reflogs of those\n> symbolic refs.  This is expensive to do in general, though,\n> because there is no backpointer to list of symbolic refs that\n> point at a non-symbolic ref.\n\nBut practically speaking... is there that many cases where a branch is \nupdated directly instead of the operation performed through HEAD?\n\nWe identified one case which is a push to a non bare repo.\n\nIf those cases are very few (and they _should_ be very few) then we \nmight simply cheat a little and update HEAD separately in those cases.\n\n\nNicolas\n"},{"id":"37563","messageId":"45FF2393.6070700@vilain.net","threadId":"7296","inReplyTo":"20070319035351.GI20658@spearce.org","subject":"Re: git push to a non-bare repository","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2007-03-19T23:58:11Z","receivedAt":"2007-03-19T23:58:11Z","isPatch":false,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"Shawn O. Pearce wrote:\n> receive-pack isn't updating the HEAD reflog as its updating the\n> actual branch, not HEAD.  If you pushed instead to HEAD you should\n> see the HEAD reflog entry too.\n>   \n\nWhat about splitting HEAD when you push to the underlying branch, and\nmaking HEAD a non-symref?\n\nSam.\n"},{"id":"37564","messageId":"7vodmod9id.fsf@assigned-by-dhcp.cox.net","threadId":"7296","inReplyTo":"45FF2393.6070700@vilain.net","subject":"Re: git push to a non-bare repository","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-20T00:49:30Z","receivedAt":"2007-03-20T00:49:30Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sam Vilain <sam@vilain.net> writes:\n\n> Shawn O. Pearce wrote:\n>> receive-pack isn't updating the HEAD reflog as its updating the\n>> actual branch, not HEAD.  If you pushed instead to HEAD you should\n>> see the HEAD reflog entry too.\n>\n> What about splitting HEAD when you push to the underlying branch, and\n> making HEAD a non-symref?\n\nI do not think any of the complication is needed, and I think\nsomebody mentioned a good example, which is a firewalled host\nthat can only be pushed into.  In that example, even though he\nknows he could fetch in reverse direction in the ideal world,\nthe network configuration does not let him do so, hence need for\na push.\n\nTo deal with that sanely, people who push between non bare\nrepositories can just forget about pushing into branch heads.\n\nInstead, they can arrange their pushes to be a true mirror image\nof their fetch that they wish could do.  To illustrate:\n\nOn repo A that can only be pushed into, if you _could_ fetch\nfrom repo B, you would:\n\n\t$ git fetch B\n\nwith something like this:\n\n\t[remote \"B\"] fetch = refs/heads/*:refs/remotes/B/*\n\nBut unfortunately because you can only push into A from B, you would\nrun this on B instead:\n\n\t$ git push A\n\nwith:\n\n\t[remote \"A\"] push = refs/heads/*:refs/remotes/B/*\n\nAnd after you perform your push, you come to the machine with\nrepo A on it, and remembering that what you did was a mirror\nimage of \"git fetch B\", you would:\n\n\t$ git merge remotes/B/master\n\nand you are done.\n\nIn other words, don't think of refs/remotes/B as something that\nis for the use of \"git fetch\".  Its purpose is to track the\nremote repository B's heads.  You maintain that hierarchy by\nissuing fetch in repository A.  You can issue push in repository\nB to do so as well.\n\nI push into a live repository almost every day.  My typical day\nconcludes like this:\n\n\tgitster$ git push kernel-org-private\n        gitster$ ssh kernel.org\n        kernel.org$ git merge origin\n        kernel.org$ Meta/Doit -pedantic &\n        kernel.org$ exit\n        ... go drink my tea ...\n\nwhere\n\n (1) gitster is my private development machine\n (2) kernel.org is a machine made available to me by friendly\n     k.org folks\n (3) Meta is a checkout of my 'todo' branch and \n (4) Doit is a script to build all four public branches.\n\nI always leave 'master' checked out on my kernel.org repository,\nand the push from my private machine is done with (I still use\nthe non separate-remote layout):\n\n\tPush: refs/heads/master:refs/heads/origin\n\tPush: refs/heads/next:refs/heads/next\n\tPush: +refs/heads/pu:refs/heads/pu\n\tPush: refs/heads/maint:refs/heads/maint\n\nSo the first thing I do after logging in to kernel.org machine\nis to run \"git merge origin\" to bring the 'master' up-to-date.\nIf you think of 'push' being mirror image of 'fetch' you would\nunderstand why.  It is like issuing \"git fetch\" on kernel.org\nmachine to retrive the hot-off-the-press from my private machine\nand then \"git merge\" it (usually \"git pull\" would do that as a\nsingle step).\n\nHowever, sometimes I accidentally leave 'next' checked out.  If\nI find out that I left non 'master' checked out, I would do \"git\nreset --hard HEAD\" before doing anything else, and I do not want\nmy push to sometimes result in detached HEAD and sometimes not.\nI do not want to lose the information which branch I was on last\n(because the next thing I would do is on which branch Meta/Doit\nfailed).  If I _were_ annoyed enough by sometimes mistakenly\npushing into the live branch, I would switch to separate remote\nlayout and push into remotes/origin/* hierarchy, and there will\nbe truly nothing to worry about after that point.\n"},{"id":"37565","messageId":"7vk5xcd9au.fsf@assigned-by-dhcp.cox.net","threadId":"7296","inReplyTo":"7vodmod9id.fsf@assigned-by-dhcp.cox.net","subject":"Re: git push to a non-bare repository","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-20T00:54:01Z","receivedAt":"2007-03-20T00:54:01Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> However, sometimes I accidentally leave 'next' checked out.  If\n> I find out that I left non 'master' checked out, I would do \"git\n> reset --hard HEAD\" before doing anything else, and I do not want\n> my push to sometimes result in detached HEAD and sometimes not.\n> I do not want to lose the information which branch I was on last\n> (because the next thing I would do is on which branch Meta/Doit\n\ns/do is on/do is to find out on/;\n\n> failed).  If I _were_ annoyed enough by sometimes mistakenly\n> pushing into the live branch, I would switch to separate remote\n> layout and push into remotes/origin/* hierarchy, and there will\n> be truly nothing to worry about after that point.\n"},{"id":"37688","messageId":"etrph6$dt3$1@sea.gmane.org","threadId":"7296","inReplyTo":"vpq8xdtpp3g.fsf@olympe.imag.fr","subject":"Re: git push to a non-bare repository","fromName":"Neil Schemenauer","fromEmail":"nas@arctrix.com","sentAt":"2007-03-21T17:20:38Z","receivedAt":"2007-03-21T17:20:38Z","isPatch":false,"sender":{"key":"nas@arctrix.com","avatar":null},"body":"Matthieu Moy <Matthieu.Moy@imag.fr> wrote:\n> It's not really an option in my case. A is a fixe-IP/fixe-DNS machine,\n> while B is my home machine, behind a NAT modem-router. So, I'd have to\n> figure out my home IP, port-forward the ssh port from the modem to my\n> machine, ...\n\nI think this is a pretty common scenario.  I have a central server\nthat I would like to push to and a bunch of other machines behind\nfirewalls.  Pulling from the central machine is not practical.\n\n  Neil\n"}]}