{"thread":{"id":"30156","subject":"Interleaved remote branch update problems","startedAt":"2012-04-05T21:49:14Z","lastAt":"2012-04-06T06:09:47Z","messageCount":4,"participants":["Martin Fick","Jeff King"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"188597","messageId":"201204051549.14397.mfick@codeaurora.org","threadId":"30156","inReplyTo":null,"subject":"Interleaved remote branch update problems","fromName":"Martin Fick","fromEmail":"mfick@codeaurora.org","sentAt":"2012-04-05T21:49:14Z","receivedAt":"2012-04-05T21:49:14Z","isPatch":false,"sender":{"key":"mfick@codeaurora.org","avatar":null},"body":"I have noticed that git push --force does not reliably force \na push to remote branches.  In particular, it will not \nupdate a remote branch if that branch has been updated since \nthe beginning of the push.  Is this normal, is this \nexpected?  It also fails to fast forward in a similar \nsituation without the -f flag.  This seems counter intuitive \nfrom the perspective of a git push user.  Are there good \nreasons for this?\n\n-Martin\n\n(Using git 1.7.8 or 1.7.10-rc3)\n\n-- \nEmployee of Qualcomm Innovation Center, Inc. which is a \nmember of Code Aurora Forum\n"},{"id":"188610","messageId":"20120406003710.GC14224@sigill.intra.peff.net","threadId":"30156","inReplyTo":"201204051549.14397.mfick@codeaurora.org","subject":"Re: Interleaved remote branch update problems","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-04-06T00:37:10Z","receivedAt":"2012-04-06T00:37:10Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Apr 05, 2012 at 03:49:14PM -0600, Martin Fick wrote:\n\n> I have noticed that git push --force does not reliably force \n> a push to remote branches.  In particular, it will not \n> update a remote branch if that branch has been updated since \n> the beginning of the push.  Is this normal, is this \n> expected?\n\nYes, that's expected. --force means \"it's OK to push something that will\nrewind history\", not \"it's OK to clobber somebody else who is pushing at\nthe same time\". The determination for the former happens on the client\nside, and for the latter on the server side.\n\nIf you want the latter, you would need a protocol extension, I think;\nI'm pretty sure the client doesn't transmit the force flag at all to the\nserver (and I don't think this should be tied to the force flag\nautomatically; they are two different cases, and you may be in a\nsituation where it is safe to do the former but not necessarily the\nlatter).\n\n-Peff\n"},{"id":"188630","messageId":"9a97881f-a49e-47b2-9c14-b067bc7a525c@email.android.com","threadId":"30156","inReplyTo":"20120406003710.GC14224@sigill.intra.peff.net","subject":"Re: Interleaved remote branch update problems","fromName":"Martin Fick","fromEmail":"mfick@codeaurora.org","sentAt":"2012-04-06T05:32:40Z","receivedAt":"2012-04-06T05:32:40Z","isPatch":false,"sender":{"key":"mfick@codeaurora.org","avatar":null},"body":"\n\nJeff King <peff@peff.net> wrote:\n>On Thu, Apr 05, 2012 at 03:49:14PM -0600, Martin Fick wrote:\n>\n>> I have noticed that git push --force does not reliably force \n>> a push to remote branches.  In particular, it will not \n>> update a remote branch if that branch has been updated since \n>> the beginning of the push.  Is this normal, is this \n>> expected?\n>\n>Yes, that's expected. --force means \"it's OK to push something that\n> will rewind history\", not \"it's OK to clobber somebody else who is\n> pushing at the same time\".\n\nBut why is it ok to clobber somebody else right after they pushed, this seems like splitting hairs?  Why force me to wait to clobber?  Afterall, git goes through great pains to only lock a ref for the small duration of time when it is updated.  But this behavior means that it effectively is actually locked for the entire duration of a push except that it teases a client into thinking it is not locked until then end of a potential costly transfer.\n\nAnd what about the fast forward case?  If client A is pushing change a and then client B starts pushing b which depends on a, why shouldn't B succeed as long as A succeeds first, even without the force flag?  But it does not work this way even with the force flag.\n\n\n> The determination for the former happens on the client\n>side, and for the latter on the server side.\n>\n>If you want the latter, you would need a protocol extension, I think;\n>I'm pretty sure the client doesn't transmit the force flag at all to\n>the\n>server (and I don't think this should be tied to the force flag\n>automatically; they are two different cases, and you may be in a\n>situation where it is safe to do the former but not necessarily the\n>latter).\n\nI think this use case distinction is irrelevant to users on a shared server unless you could somehow tell git to \"only clobber the branch if it currently points to shax\".  Which is sort of what git is pretending to do, but it isn't really since the user isn't specifying shax, it is determined when the push starts and is inherently subject to a race.  It's not like the user can safely determine what the remote branch points to before they update it to see if it is ok to clobber it.\n\nJust a user's perspective...\n\n-Martin\n\nEmployee of Qualcomm Innovation Center,Inc. which is a member of Code Aurora Forum\n"},{"id":"188632","messageId":"20120406060947.GB25301@sigill.intra.peff.net","threadId":"30156","inReplyTo":"9a97881f-a49e-47b2-9c14-b067bc7a525c@email.android.com","subject":"Re: Interleaved remote branch update problems","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-04-06T06:09:47Z","receivedAt":"2012-04-06T06:09:47Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Apr 05, 2012 at 11:32:40PM -0600, Martin Fick wrote:\n\n> >Yes, that's expected. --force means \"it's OK to push something that\n> > will rewind history\", not \"it's OK to clobber somebody else who is\n> > pushing at the same time\".\n> \n> But why is it ok to clobber somebody else right after they pushed,\n> this seems like splitting hairs?  Why force me to wait to clobber?\n\nBecause it gives you a chance to take it back. You have told git \"it is\nOK to move from A to B, even if that is a rewind\". You did not tell it\n\"it is OK to move C to B\". Imagine your workflow is:\n\n  1. Try to push B, and see that the remote is at A; your push is\n     rejected.\n\n  2. Examine \"git log --graph A...B\" and see that yes, your B is an\n     amendment over A, and so it is OK to push. Or maybe you just happen\n     to know what B and A are, because you just pushed a broken A and\n     are amending it, in which case you can skip the log. But the point\n     is that the user makes a decision about the case.\n\n  3. Do \"git push -f\" to approve writing B over A.\n\nIf somebody else has built C on top of A, and pushed it during (3), then\nyou don't necessarily want to clobber it; you should repeat your\nanalysis from (2) and make a new decision.\n\nThe astute reader will notice that somebody might have pushed C between\nsteps (1) and (3), and therefore the second \"push -f\" may overwrite\ntheir C, even though that was not what was intended by the user. The git\nprotocol already says \"I am expecting to move ref R from A to B\". The\nproblem is that the interface is mis-designed for this workflow. The\nfirst push should note \"A\" somewhere on disk, and the second \"git push\n-f\" should really be \"git push --retry-with-force\", and check to make\nsure that our starting point really is \"A\".\n\nI suspect nobody has complained so far because it is a race condition\nthat just doesn't come up unless you have an extremely busy repository\nwith lots of force pushes.\n\n> And what about the fast forward case?  If client A is pushing change a\n> and then client B starts pushing b which depends on a, why shouldn't B\n> succeed as long as A succeeds first, even without the force flag?  But\n> it does not work this way even with the force flag.\n\nRight. Because the force flag is about history rewinds, not about\nclobbering simultaneous pushes.\n\nDon't get me wrong; I can see the use for an option to clobber a\nsimultaneous push in some workflows. I just think that there is value in\ndistinguishing it from what \"force\" does now.\n\n> I think this use case distinction is irrelevant to users on a shared\n> server unless you could somehow tell git to \"only clobber the branch\n> if it currently points to shax\".  Which is sort of what git is\n> pretending to do, but it isn't really since the user isn't specifying\n> shax, it is determined when the push starts and is inherently subject\n> to a race.  It's not like the user can safely determine what the\n> remote branch points to before they update it to see if it is ok to\n> clobber it.\n\nRight. And I think that is a bug (or an interface misdesign), albeit one\nthat doesn't come up much. But I'd rather not make it worse by losing\nwhat safety we have.\n\n-Peff\n"}]}