{"thread":{"id":"42675","subject":"Fast-forward able commit, otherwise fail","startedAt":"2016-06-21T03:59:25Z","lastAt":"2016-07-20T21:01:06Z","messageCount":9,"participants":["David Lightle","Junio C Hamano","Jacob Keller","Stefan Haller","Philip Oakley"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"289721","messageId":"CAP4gbxqjHzqHhPuNK8UOwPMa46g2=vcNSk1AvGjxN8s+ou-0Dw@mail.gmail.com","threadId":"42675","inReplyTo":null,"subject":"Fast-forward able commit, otherwise fail","fromName":"David Lightle","fromEmail":"dlightle@gmail.com","sentAt":"2016-06-21T03:58:20Z","receivedAt":"2016-06-21T03:59:25Z","isPatch":false,"sender":{"key":"dlightle@gmail.com","avatar":null},"body":"Hello,\n\nI am trying to build a git workflow in our enterprise and am almost\nevenly torn between a \"rebase workflow\" and git-flow (which uses merge\ninstead of rebase, obviously).  We are using Bitbucket for pull\nrequests as code reviews (right or wrong).\n\nI apologize if my inexperience with git shows through, but I'm wanting\nto achieve the following --\n\nMaintain two long-running branches (develop as a stable pre-release,\nmaster as a deployed version), with short-term feature branches off of\ndevelop and short-term release branches that are based on develop and\nmerge into master eventually (ie. a lightweight git-flow).\n\nHowever, as part of this, I would prefer to require/ensure that each\nfeature branch is up-to-date and otherwise able to be fast-forwarded;\nwe currently have this with the bitbucket server setting requiring\n--ff-only.\n\nThe other half of what I would prefer is to still perform the merge\ncommit, though, to ensure separate tracking of the feature branches\n(ie. --no-ff).\n\nI know that I have read that --ff-only and --no-ff are contradictory,\nbut I believe that is somewhat ambiguously correct -- I believe the\ntwo flags contradict in the sense of \"what to do with the merge\ncommit\", but not necessarily on the \"when it can be done\".\n\nI read an ancient post about on this list (which predates the\ntri-state of fast-forward) that I believe could have allowed this to\nwork.\n\nI have also read a few articles and posts that achieve this more as a\nmatter of practice than a workflow enforcement via git flags; for this\nto be something to potentially get absorbed into a Bitbucket workflow,\nI suspect it would need to a git flag (they now support merging via\n--ff, --no-ff, --ff-only, --squash, and --squash-ff-only for their\nhosted solution, for example).\n\nHere are a few articles that say they prefer this approach (rebase and\nthen merge --no-ff):\nhttps://walkingthestack.blogspot.com/2012/05/why-you-should-use-git-merge-no-ff-when.html\nhttp://blog.differential.com/best-way-to-merge-a-github-pull-request/\nhttp://victorlin.me/tags/rebase\n\nCan anyone share their thoughts on workflows that might achieve what\nI'm looking at here or opinions on adding the functionality I'm\ndescribing?\n\nThanks!\n"},{"id":"289722","messageId":"xmqqh9cnrvp2.fsf@gitster.mtv.corp.google.com","threadId":"42675","inReplyTo":"CAP4gbxqjHzqHhPuNK8UOwPMa46g2=vcNSk1AvGjxN8s+ou-0Dw@mail.gmail.com","subject":"Re: Fast-forward able commit, otherwise fail","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-06-21T04:51:21Z","receivedAt":"2016-06-21T04:53:27Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"David Lightle <dlightle@gmail.com> writes:\n\n> I know that I have read that --ff-only and --no-ff are contradictory,\n> but I believe that is somewhat ambiguously correct -- I believe the\n> two flags contradict in the sense of \"what to do with the merge\n> commit\", but not necessarily on the \"when it can be done\".\n\nTraditionally we have mildly suggested against making otherwise\nneedless merge commit with \"--no-ff\".  We also have suggested\nagainst keeping the history too linear, not because linear history\nis bad, but because it will require rebasing soon before pushing out\nyour changes [*1*].\n\nI personally would feel that what you seem to be aiming for is the\nworst of both worlds in the sense that contributors are still forced\nto rebase immediately before pushing out, which leads to\ninsufficiently tested version landing on truck, and at the same time\nforcing the resulting history to have otherwise needless merges (the\nlatter is probably a much lessor of the two sins).\n\nHowever, Git as a tool is not opinionated strongly enough to make it\nhard to do these two things (independently).  I do not think it is\nunreasonable to add a new mode of \"merge\" that rejects a resulting\nhistory that is not shaped the way you like.  So far the command\nrejected --ff-only and --no-ff given together, so if an updated Git\nstarts taking them together and creating a needless real merge and\nfailing only when the first parent does not fast-forward to the\nsecond parent, nobody's existing workflow would be broken.\n\nHaving said that, you need to think things through.  Sample\nquestions you would want to be asking yourself are (not exhaustive):\n\n - What is your plan to _enforce_ your project participants to use\n   this new mode of operation?\n\n - Do you _require_ your project participants to always pass a new\n   option to \"git merge\" or \"git pull\"?\n\n - Do you force them to set some new configuration variables?  \n\n - Do you trust them once you tell them what to do?  \n\n - How will your project's trunk get their changes?\n\n - How you prevent some participants who misunderstood your\n   instructions from pushing an incorrectly shaped history to your\n   project?\n\nIf they are eventually pushing the result to a central repository\nand that is how the project's overall history advances, then the\nmost reliable mechanism that is least limiting to your users is\npre-receive hook at that central repository that ensures the shape\nof the history being pushed to update the branches.  You walk the\nfirst-parent chain of the commits and ensure all the commits are\nmerges, and for each of these merges, its second parent is a\ndescendant of its first parent.  Otherwise you reject their push.\n\nThat way, your users can make normal merges while trying their\nchanges locally all they want without straightjacket.  Only when\nthey prepare the final history to be placed at the tip of the\nproject's official history, they need to make sure that the history\nis shaped as you specified.\n\n\n[Footnote]\n\n*1* Your changes before rebasing may have seen enough\ntesting in one context (i.e. built on older base), but \"rebase\nimmediately before push to ensure fast-forward\" will force you to\npublish a version that by definition will have little or no testing,\nwhich may or may not work well with a different context.\n"},{"id":"289936","messageId":"xmqqr3bokeib.fsf@gitster.mtv.corp.google.com","threadId":"42675","inReplyTo":"xmqqh9cnrvp2.fsf@gitster.mtv.corp.google.com","subject":"Re: Fast-forward able commit, otherwise fail","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-06-22T23:09:00Z","receivedAt":"2016-06-22T23:09:20Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> However, Git as a tool is not opinionated strongly enough to make it\n> hard to do these two things (independently).  I do not think it is\n> unreasonable to add a new mode of \"merge\" that rejects a resulting\n> history that is not shaped the way you like.  So far the command\n> rejected --ff-only and --no-ff given together, so if an updated Git\n> starts taking them together and creating a needless real merge and\n> failing only when the first parent does not fast-forward to the\n> second parent, nobody's existing workflow would be broken.\n>\n> Having said that, you need to think things through.  Sample\n> questions you would want to be asking yourself are (not exhaustive):\n>\n>  - What is your plan to _enforce_ your project participants to use\n>    this new mode of operation?\n>\n>  - Do you _require_ your project participants to always pass a new\n>    option to \"git merge\" or \"git pull\"?\n>\n>  - Do you force them to set some new configuration variables?  \n>\n>  - Do you trust them once you tell them what to do?  \n>\n>  - How will your project's trunk get their changes?\n>\n>  - How you prevent some participants who misunderstood your\n>    instructions from pushing an incorrectly shaped history to your\n>    project?\n\nAnother thing to consider is that the proposed workflow would not\nscale if your team becomes larger.  Requiring each and every commit\non the trunk to be a merge commit, whose second parent (i.e. the tip\nof the feature branch) fast-forwards to the first parent of the\nmerge (i.e. you require the feature to be up-to-date), would mean\nthat Alice and Bob collaborating on this project would end up\nworking like this:\n\n A:    git pull --ff-only origin ;# starts working\n A:    git checkout -b topic-a\n A:    git commit; git commit; git commit\n B:    git pull --ff-only origin ;# starts working\n B:    git checkout -b topic-b\n B:    git commit; git commit\n\n A:    git checkout master && git merge --ff-only --no-ff topic-a\n A:    git push origin ;# happy\n\n B:    git checkout master && git merge --ff-only --no-ff topic-b\n B:    git push origin ;# fails!\n\n B:    git fetch origin ;# starts recovering\n B:    git reset --hard origin/master\n B:    git merge --ff-only --no-ff topic-b ;# fails!\n B:    git rebase origin/master topic-b\n B:    git checkout master && git merge --ff-only --no-ff topic-b\n B:    git push origin ;# hopefully nobody pushed in the meantime\n\nThe first push by Bob fails because his 'master', even though it is\na merge between the once-at-the-tip-of-public-master and topic-b\nwhich was forked from that once-at-the-tip, it no longer fast-forwards\nbecause Alice pushed her changes to the upstream.\n\nAnd it is not sufficient to redo the previous merge after fetching\nthe updated upstream, because your additional \"feature branch must\nbe up-to-date\" requirement is now broken for topic-b.  Bob needs to\nrebuild it on top of the latest, which includes what Alice pushed,\nusing rebase, do that merge again, and hope that nobody else pushed\nto update the upstream in the meantime.  As you have more people\nworking simultanously on more features, Bob will have to spend more\ntime doing steps between \"starts recovering\" and \"hopefully nobody\npushed in the meantime\", because the probability is higher that\nsomebody other than Alice has pushed while Bob is trying to recover.\n\nThe time spend on recovery is not particularly productive, and this\nworkflow gives him a (wrong) incentive to do that recovery procedure\nquickly to beat the other participants to become the first to push.\n\nThe workflow should instead be designed to incentivise participant\nto spend more time to carefully inspect the result of his rebasing\nto make sure that his changes still make sense in the context of the\nupdated codebase that contains changes from others since he forked\ntopic-b from the upstream, in order to ensure quality.\n\nThis \"push quickly immediately after rebasing without carefully\nchecking the result of rebase\" pressure is shared by a workflow that\nrequires a completely linear history, and not unique to your\nproposed workflow, but because you also require a --no-ff merge to\nthe updated upstream, robbing even more time from the project\nparticipants, it aggravates the problem.\n"},{"id":"291053","messageId":"CAP4gbxp6qKntysrkyTSWxkQNpqPzf2gHLiKpJzA-TmqO71sHyg@mail.gmail.com","threadId":"42675","inReplyTo":"xmqqr3bokeib.fsf@gitster.mtv.corp.google.com","subject":"Re: Fast-forward able commit, otherwise fail","fromName":"David Lightle","fromEmail":"dlightle@gmail.com","sentAt":"2016-07-08T19:28:02Z","receivedAt":"2016-07-08T19:28:10Z","isPatch":false,"sender":{"key":"dlightle@gmail.com","avatar":null},"body":"I've been trying to think of just what to say in response, so it has\ntaken me some time as well as I've been experimenting with our\nworkflow to try some alternate approaches while we still can.\n\nIn your above scenario with Alice & Bob, wouldn't that same issue come\nup in _any_ rebase workflow (--ff-only)?  From what I've read this is\na typical consequence of requiring fast-forward merges; to be\neffective, the rebase step must  be more likely to succeed in a time\nwindow than for someone to have pushed additional changes (otherwise\nyou end up in a loop like above).  But I don't believe that's\ninherently any worse with the change I'm asking about which  would\nonly take that existing flag (--ff-only) and additionally create an\nactual merge commit when those conditions are present.\n\nWe were previously using the fast-forward-only approach and it worked\nmoderately well, but there is a learning curve to it more (rebase vs\nmerge).  However, because we want to follow a gitflow workflow, where\ntopic branches are created from develop and merged back into develop,\nwe want to ensure that is an actual merge commit to identify the\nchanges that occurred on that topic branch (with --ff-only it becomes\nhard to distinguish changes from one topic branch to the next).\n\nWe will still be using develop as an integration branch which will\nreceive testing as well, so the rebased version will still be tested\nbefore it gets released in our scenario.  But again that is a\nrebase-workflow issue more than a rebase+merge commit issue, right?\n\nAlso GitLab already has introduced a \"rebase before merging\" automated\ntool in their product, and BitBucket has a similar request oustanding,\nand both (plus GitHub) allow squashing commits as part of the merge.\nIn fact, I just noticed that GitLab has built in the functionality I'm\nlooking for even, which is what they call \"Merge commit with\nsemi-linear history\" but I'm asking whether direct support for this\napproach would be reasonable.  These approaches can all produce the\n\"untested merged product\", but they support the way the users want to\nuse the system as well.  I'm not saying any approach is right or wrong\nas I'm not qualified enough to say.\n\nOn Wed, Jun 22, 2016 at 6:09 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> However, Git as a tool is not opinionated strongly enough to make it\n>> hard to do these two things (independently).  I do not think it is\n>> unreasonable to add a new mode of \"merge\" that rejects a resulting\n>> history that is not shaped the way you like.  So far the command\n>> rejected --ff-only and --no-ff given together, so if an updated Git\n>> starts taking them together and creating a needless real merge and\n>> failing only when the first parent does not fast-forward to the\n>> second parent, nobody's existing workflow would be broken.\n>>\n>> Having said that, you need to think things through.  Sample\n>> questions you would want to be asking yourself are (not exhaustive):\n>>\n>>  - What is your plan to _enforce_ your project participants to use\n>>    this new mode of operation?\n>>\n>>  - Do you _require_ your project participants to always pass a new\n>>    option to \"git merge\" or \"git pull\"?\n>>\n>>  - Do you force them to set some new configuration variables?\n>>\n>>  - Do you trust them once you tell them what to do?\n>>\n>>  - How will your project's trunk get their changes?\n>>\n>>  - How you prevent some participants who misunderstood your\n>>    instructions from pushing an incorrectly shaped history to your\n>>    project?\n>\n> Another thing to consider is that the proposed workflow would not\n> scale if your team becomes larger.  Requiring each and every commit\n> on the trunk to be a merge commit, whose second parent (i.e. the tip\n> of the feature branch) fast-forwards to the first parent of the\n> merge (i.e. you require the feature to be up-to-date), would mean\n> that Alice and Bob collaborating on this project would end up\n> working like this:\n>\n>  A:    git pull --ff-only origin ;# starts working\n>  A:    git checkout -b topic-a\n>  A:    git commit; git commit; git commit\n>  B:    git pull --ff-only origin ;# starts working\n>  B:    git checkout -b topic-b\n>  B:    git commit; git commit\n>\n>  A:    git checkout master && git merge --ff-only --no-ff topic-a\n>  A:    git push origin ;# happy\n>\n>  B:    git checkout master && git merge --ff-only --no-ff topic-b\n>  B:    git push origin ;# fails!\n>\n>  B:    git fetch origin ;# starts recovering\n>  B:    git reset --hard origin/master\n>  B:    git merge --ff-only --no-ff topic-b ;# fails!\n>  B:    git rebase origin/master topic-b\n>  B:    git checkout master && git merge --ff-only --no-ff topic-b\n>  B:    git push origin ;# hopefully nobody pushed in the meantime\n>\n> The first push by Bob fails because his 'master', even though it is\n> a merge between the once-at-the-tip-of-public-master and topic-b\n> which was forked from that once-at-the-tip, it no longer fast-forwards\n> because Alice pushed her changes to the upstream.\n>\n> And it is not sufficient to redo the previous merge after fetching\n> the updated upstream, because your additional \"feature branch must\n> be up-to-date\" requirement is now broken for topic-b.  Bob needs to\n> rebuild it on top of the latest, which includes what Alice pushed,\n> using rebase, do that merge again, and hope that nobody else pushed\n> to update the upstream in the meantime.  As you have more people\n> working simultanously on more features, Bob will have to spend more\n> time doing steps between \"starts recovering\" and \"hopefully nobody\n> pushed in the meantime\", because the probability is higher that\n> somebody other than Alice has pushed while Bob is trying to recover.\n>\n> The time spend on recovery is not particularly productive, and this\n> workflow gives him a (wrong) incentive to do that recovery procedure\n> quickly to beat the other participants to become the first to push.\n>\n> The workflow should instead be designed to incentivise participant\n> to spend more time to carefully inspect the result of his rebasing\n> to make sure that his changes still make sense in the context of the\n> updated codebase that contains changes from others since he forked\n> topic-b from the upstream, in order to ensure quality.\n>\n> This \"push quickly immediately after rebasing without carefully\n> checking the result of rebase\" pressure is shared by a workflow that\n> requires a completely linear history, and not unique to your\n> proposed workflow, but because you also require a --no-ff merge to\n> the updated upstream, robbing even more time from the project\n> participants, it aggravates the problem.\n"},{"id":"291062","messageId":"xmqqbn27lqm0.fsf@gitster.mtv.corp.google.com","threadId":"42675","inReplyTo":"CAP4gbxp6qKntysrkyTSWxkQNpqPzf2gHLiKpJzA-TmqO71sHyg@mail.gmail.com","subject":"Re: Fast-forward able commit, otherwise fail","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-07-08T22:19:51Z","receivedAt":"2016-07-08T22:19:59Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"David Lightle <dlightle@gmail.com> writes:\n\n> In your above scenario with Alice & Bob, wouldn't that same issue come\n> up in _any_ rebase workflow (--ff-only)?  From what I've read this is\n> a typical consequence of requiring fast-forward merges; to be\n> effective, the rebase step must  be more likely to succeed in a time\n> window than for someone to have pushed additional changes (otherwise\n> you end up in a loop like above).  But I don't believe that's\n> inherently any worse with the change I'm asking about which  would\n> only take that existing flag (--ff-only) and additionally create an\n> actual merge commit when those conditions are present.\n\nTrue, but that does not change the fact that you would be adding\n_more_ code to support a workflow that we know to be bad.\n\n> In fact, I just noticed that GitLab has built in the functionality I'm\n> looking for even, which is what they call \"Merge commit with\n> semi-linear history\" but I'm asking whether direct support for this\n> approach would be reasonable.  These approaches can all produce the\n> \"untested merged product\", but they support the way the users want to\n> use the system as well.  I'm not saying any approach is right or wrong\n> as I'm not qualified enough to say.\n\nWe, not being a for-profit entity, do not have a strong incentive to\nadd features that encourages bad workflow to the users.  Of course,\nwe also do not necessarily stop them if users really want to shoot\nthemselves in the foot ;-), but such a change would inevitably be of\nlower priority to us.\n\n"},{"id":"291080","messageId":"CA+P7+xroUpQDX1hV=s7Qcp_yyt8A1dXuZS4+gwXgqOGy_+QC5w@mail.gmail.com","threadId":"42675","inReplyTo":"xmqqbn27lqm0.fsf@gitster.mtv.corp.google.com","subject":"Re: Fast-forward able commit, otherwise fail","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2016-07-09T02:10:25Z","receivedAt":"2016-07-09T02:10:50Z","isPatch":false,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"On Fri, Jul 8, 2016 at 3:19 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> David Lightle <dlightle@gmail.com> writes:\n>> In fact, I just noticed that GitLab has built in the functionality I'm\n>> looking for even, which is what they call \"Merge commit with\n>> semi-linear history\" but I'm asking whether direct support for this\n>> approach would be reasonable.  These approaches can all produce the\n>> \"untested merged product\", but they support the way the users want to\n>> use the system as well.  I'm not saying any approach is right or wrong\n>> as I'm not qualified enough to say.\n>\n> We, not being a for-profit entity, do not have a strong incentive to\n> add features that encourages bad workflow to the users.  Of course,\n> we also do not necessarily stop them if users really want to shoot\n> themselves in the foot ;-), but such a change would inevitably be of\n> lower priority to us.\n>\n\nI would add that after using a linear history at $dayjob a lot, i've\nfound the biggest reasoning for a linear history is that non-linear\nhistory confuses the users. I'd rather advocate for learning how to\nhandle the more complex history than trying to force users into\nquickly rebasing code which can lead to the issues Junio mentioned\nabove.\n\nThanks,\nJake\n"},{"id":"291254","messageId":"1mqa4a5.1ykwh5b8vc9q7M%lists@haller-berlin.de","threadId":"42675","inReplyTo":"xmqqr3bokeib.fsf@gitster.mtv.corp.google.com","subject":"Re: Fast-forward able commit, otherwise fail","fromName":"Stefan Haller","fromEmail":"lists@haller-berlin.de","sentAt":"2016-07-12T13:24:48Z","receivedAt":"2016-07-12T13:32:47Z","isPatch":false,"sender":{"key":"lists@haller-berlin.de","avatar":null},"body":"Junio C Hamano <gitster@pobox.com> wrote:\n\n> Another thing to consider is that the proposed workflow would not\n> scale if your team becomes larger.  Requiring each and every commit\n> on the trunk to be a merge commit, whose second parent (i.e. the tip\n> of the feature branch) fast-forwards to the first parent of the\n> merge (i.e. you require the feature to be up-to-date), would mean\n> that Alice and Bob collaborating on this project would end up\n> working like this:\n> \n>  A:    git pull --ff-only origin ;# starts working\n>  A:    git checkout -b topic-a\n>  A:    git commit; git commit; git commit\n>  B:    git pull --ff-only origin ;# starts working\n>  B:    git checkout -b topic-b\n>  B:    git commit; git commit\n> \n>  A:    git checkout master && git merge --ff-only --no-ff topic-a\n>  A:    git push origin ;# happy\n> \n>  B:    git checkout master && git merge --ff-only --no-ff topic-b\n>  B:    git push origin ;# fails!\n> \n>  B:    git fetch origin ;# starts recovering\n>  B:    git reset --hard origin/master\n>  B:    git merge --ff-only --no-ff topic-b ;# fails!\n>  B:    git rebase origin/master topic-b\n>  B:    git checkout master && git merge --ff-only --no-ff topic-b\n>  B:    git push origin ;# hopefully nobody pushed in the meantime\n> \n> The first push by Bob fails because his 'master', even though it is\n> a merge between the once-at-the-tip-of-public-master and topic-b\n> which was forked from that once-at-the-tip, it no longer fast-forwards\n> because Alice pushed her changes to the upstream.\n> \n> And it is not sufficient to redo the previous merge after fetching\n> the updated upstream, because your additional \"feature branch must\n> be up-to-date\" requirement is now broken for topic-b.  Bob needs to\n> rebuild it on top of the latest, which includes what Alice pushed,\n> using rebase, do that merge again, and hope that nobody else pushed\n> to update the upstream in the meantime.  As you have more people\n> working simultanously on more features, Bob will have to spend more\n> time doing steps between \"starts recovering\" and \"hopefully nobody\n> pushed in the meantime\", because the probability is higher that\n> somebody other than Alice has pushed while Bob is trying to recover.\n> \n> The time spend on recovery is not particularly productive, and this\n> workflow gives him a (wrong) incentive to do that recovery procedure\n> quickly to beat the other participants to become the first to push.\n\nI have read and re-read this thread a hundred times now, but I still\ndon't understand why it makes much of a difference whether or not Bob\nrebases his branch onto master before pushing his merge. In both cases,\nAlice and Bob have this race as to whose push succeeds, and in both\ncases you end up with merge commits on master that are not well tested.\n\nFirst of all, let me say that at my company we do use the workflow that\nDavid suggests; we rebase topic branches onto master before merging them\n(with --no-ff), and we like the resulting shape of the history. Even the\nmore experienced git users like it for its simplicity; it simply saves\nus time and mental energy when digging through the history.\n\nSecond, we did indeed run into the scalability problems that you\ndescribe [*1*]. However, we ran into this way before starting to require\nthe rebase-before-merge; in my experience, rebasing or not makes no\ndifference here. After all, the resulting tree state of the merge commit\nis identical in both cases; it's just the individual commits on the\nmerged topic branch that have not been tested in the rebased case. But\nif the merge commit is green, it is pretty unlikely in my experience\nthat one of the individual commits is not. It's theoretically possible\nof course, just very, very unlikely.\n\nSo what am I missing?\n\n\n[Footnote]\n*1* These problems were so annoying for us that we invented technical\nmeasures to solve them. We now have a web interface where developers can\ngrab a lock on the repo, or put themselves into a queue for the lock\nwhen it's taken. There's a push hook that only allows pushing when you\nhold the lock. This solves it nicely, because once you have the lock,\nyou can take all the time you need to make sure your merge compiles, and\nrun the test suite locally.\n"},{"id":"291270","messageId":"xmqqeg6y7t62.fsf@gitster.mtv.corp.google.com","threadId":"42675","inReplyTo":"1mqa4a5.1ykwh5b8vc9q7M%lists@haller-berlin.de","subject":"Re: Fast-forward able commit, otherwise fail","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-07-12T15:49:41Z","receivedAt":"2016-07-12T15:49:49Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"lists@haller-berlin.de (Stefan Haller) writes:\n\n> I have read and re-read this thread a hundred times now, but I still\n> don't understand why it makes much of a difference whether or not Bob\n> rebases his branch onto master before pushing his merge. In both cases,\n> Alice and Bob have this race as to whose push succeeds, and in both\n> cases you end up with merge commits on master that are not well tested.\n\nOne crucial difference is that at least you _know_ that $tip^2 has\nbeen well tested, when you do not rebase, and you can check out\n$tip^2 to study and understand how it was supposed to work, when the\nmerge of the topic into an updated mainline is found to be faulty.\nThat knowledge helps you to go forward--you'd need to adjust some\nuntold assumption $tip^2 made, which was broken somewhere between\n$tip^2..$tip^1 on the mainline, to an updated reality.\n\nOnce you rebase, you end up with \"This series of changes once was\nworking well, and during the rebase somewhere it stopped working\",\nunless you say something like \"these 7 changes were originally\ndeveloped and tested on commit X\" in the rebased commit.\n\n"},{"id":"291862","messageId":"D239BC78A8EB47DD8397F93ABB3D35B0@PhilipOakley","threadId":"42675","inReplyTo":"1mqa4a5.1ykwh5b8vc9q7M%lists@haller-berlin.de","subject":"Re: Fast-forward able commit, otherwise fail","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2016-07-20T16:47:56Z","receivedAt":"2016-07-20T21:01:06Z","isPatch":false,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Stefan Haller\" <lists@haller-berlin.de>\n> Junio C Hamano <gitster@pobox.com> wrote:\n>\n>> Another thing to consider is that the proposed workflow would not\n>> scale if your team becomes larger.  Requiring each and every commit\n>> on the trunk to be a merge commit, whose second parent (i.e. the tip\n>> of the feature branch) fast-forwards to the first parent of the\n>> merge (i.e. you require the feature to be up-to-date), would mean\n>> that Alice and Bob collaborating on this project would end up\n>> working like this:\n>>\n>>  A:    git pull --ff-only origin ;# starts working\n>>  A:    git checkout -b topic-a\n>>  A:    git commit; git commit; git commit\n>>  B:    git pull --ff-only origin ;# starts working\n>>  B:    git checkout -b topic-b\n>>  B:    git commit; git commit\n>>\n>>  A:    git checkout master && git merge --ff-only --no-ff topic-a\n>>  A:    git push origin ;# happy\n>>\n>>  B:    git checkout master && git merge --ff-only --no-ff topic-b\n>>  B:    git push origin ;# fails!\n>>\n>>  B:    git fetch origin ;# starts recovering\n>>  B:    git reset --hard origin/master\n>>  B:    git merge --ff-only --no-ff topic-b ;# fails!\n>>  B:    git rebase origin/master topic-b\n>>  B:    git checkout master && git merge --ff-only --no-ff topic-b\n>>  B:    git push origin ;# hopefully nobody pushed in the meantime\n>>\n>> The first push by Bob fails because his 'master', even though it is\n>> a merge between the once-at-the-tip-of-public-master and topic-b\n>> which was forked from that once-at-the-tip, it no longer fast-forwards\n>> because Alice pushed her changes to the upstream.\n>>\n>> And it is not sufficient to redo the previous merge after fetching\n>> the updated upstream, because your additional \"feature branch must\n>> be up-to-date\" requirement is now broken for topic-b.  Bob needs to\n>> rebuild it on top of the latest, which includes what Alice pushed,\n>> using rebase, do that merge again, and hope that nobody else pushed\n>> to update the upstream in the meantime.  As you have more people\n>> working simultanously on more features, Bob will have to spend more\n>> time doing steps between \"starts recovering\" and \"hopefully nobody\n>> pushed in the meantime\", because the probability is higher that\n>> somebody other than Alice has pushed while Bob is trying to recover.\n>>\n>> The time spend on recovery is not particularly productive, and this\n>> workflow gives him a (wrong) incentive to do that recovery procedure\n>> quickly to beat the other participants to become the first to push.\n>\n> I have read and re-read this thread a hundred times now, but I still\n> don't understand why it makes much of a difference whether or not Bob\n> rebases his branch onto master before pushing his merge. In both cases,\n> Alice and Bob have this race as to whose push succeeds, and in both\n> cases you end up with merge commits on master that are not well tested.\n\nI'd like to put in comment from a different perspective.\n\nYou didn't say how often you expected these merge commits to be made \n(daily/hourly/2-minutes), and also didn't mention how long it's taking to do \nthe tests - 5-mins/one hour/3 hours/all day, and in particular the values \nfor the difficult cases.\n\nFor example it maybe: team size means typical small feature merge commits \nare ~twice/day, needing only 30 mins test time, however there are difficult \n(big feature) commits are every 1-3 weeks, and take all day (or more) to \ntest, leaving an open window for small feature merges to sneak in and break \nthe 'clean-test' process.\n\nIn the above case you have a management issue, where someone needs to \n(actively) manage the process so that there are no commits to master during \nthat window, and rather they are put to 'next' (using Git' branch \nconvention) and once the big feature has landed the 'next-features' can be \nrebased & tested and added on top of master.\n\nShould the case be more that there is just some occasional overlaps from the \n30mins test, during the two per day window, then that should be more \nmanageable by social and procedural convention.\n\nThe thing to notice is that the upstream is always good and well formed \n(because it rejects, or should reject, commits that \naren't --ff-only --no-ff). So before any merge (either way) [i.e. just after \nrebase & test] master should be pulled to be locally up to date.\n\nIf there were no extra commits on top, then a quick --ff-only --no-ff merge \nand push, taking only a few seconds, will complete the feature. Otherwise, \nif there were extra commits on top, then it's a moderately quick rebase & \nre-test (an annoyance but handleable because its infrequent) should mean the \nupdated commit will now pass the 'pull master' check cleanly - remember the \ncommit/push rate means it's unlikely that a second clash happens, otherwise \nits back to the 'management' approach.\n\n\n>\n> First of all, let me say that at my company we do use the workflow that\n> David suggests; we rebase topic branches onto master before merging them\n> (with --no-ff), and we like the resulting shape of the history. Even the\n> more experienced git users like it for its simplicity; it simply saves\n> us time and mental energy when digging through the history.\n>\n> Second, we did indeed run into the scalability problems that you\n> describe [*1*]. However, we ran into this way before starting to require\n> the rebase-before-merge; in my experience, rebasing or not makes no\n> difference here. After all, the resulting tree state of the merge commit\n> is identical in both cases; it's just the individual commits on the\n> merged topic branch that have not been tested in the rebased case. But\n> if the merge commit is green, it is pretty unlikely in my experience\n> that one of the individual commits is not. It's theoretically possible\n> of course, just very, very unlikely.\n>\n> So what am I missing?\n>\n>\n> [Footnote]\n> *1* These problems were so annoying for us that we invented technical\n> measures to solve them. We now have a web interface where developers can\n> grab a lock on the repo, or put themselves into a queue for the lock\n> when it's taken. There's a push hook that only allows pushing when you\n> hold the lock. This solves it nicely, because once you have the lock,\n> you can take all the time you need to make sure your merge compiles, and\n> run the test suite locally.\n> --\n\nPhilip \n\n"}]}