{"thread":{"id":"21488","subject":"Preserving branches after merging on ancestor","startedAt":"2009-11-05T18:30:24Z","lastAt":"2009-11-07T13:31:01Z","messageCount":12,"participants":["Richard Lee","Eric Raible","Jonathan Nieder","Björn Steinbrink","rhlee","Dilip M"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"126909","messageId":"26217077.post@talk.nabble.com","threadId":"21488","inReplyTo":null,"subject":"Preserving branches after merging on ancestor","fromName":"Richard Lee","fromEmail":"richard@webdezign.co.uk","sentAt":"2009-11-05T18:30:24Z","receivedAt":"2009-11-05T18:30:24Z","isPatch":false,"sender":{"key":"richard@webdezign.co.uk","avatar":"https://gravatar.com/avatar/36c0bc285b2d30baa54ed2e1488161fd27a4a4a8128836a673b66204ab08c9b7?d=mp&s=160"},"body":"\nHello gits,\n\nI've been using various version control systems for several years now before\ncoming to git two months ago. So far I've been just doing linear commits\nwithout any branches on my source code so that I end up with a linear\nhistory. This makes it very hard to see where you started and stopped\nworking on something on the git graph.\n\nSo I tried using branches for features today. Most of the time I'm the only\nperson working on a project. So when I've finished working on a feature\nbranch and ready to merge it back into the master branch, the master head IS\nthe common ancestor of the two branches. As shown below\n\n* b6d75f1 [feature] stuff on feature branch\n* 43dba08 stuff on feature branch\n* ab7efdd [master] init\n\nWhen I merge the graph looks likes this:\n\n* b6d75f1 [master] [feature] stuff on feature branch\n* 43dba08 stuff on feature branch\n* ab7efdd init\n\nNow I lose the start point of where I satrted on the feature branch. And if\nI decided to reuse the name of the branch 'feature' to work on it again by\nresetting it to somewhere else, I loose to finish point. (Should I be using\ngit-reset like this?)\n\nOne way of getting round this problem is to use empty commits on the master\nbranch, as shown below.\n\n*   6fc04b5 Merge branch 'feature2'\n|\\\n| * 07a117b stuff on feature2\n* | 52f5ba1 Empty commit\n|/\n*   5deaa93 Merge branch 'feature1'\n|\\\n| * b163b17 stuff on feature1\n| * 53bb820 stuff on feature1\n| * c9ef14c stuff on feature1\n* | 34227a3 Empty commit\n|/\n* e88d332 Init\n\nBut is this correct? It seems rather hackish to create empty commits on the\nmaster branch just to historically preserve commits on a seperate branch.\nShould I be using feature branches in git like this or another way? For\nexample more informative commit messages. \n\nI cannot imagine using this empty commits fix in other VCS if they don't\nallow empty commits like svn or hg.\n\n\nCheers,\n\nRichard\n-- \nView this message in context: http://old.nabble.com/Preserving-branches-after-merging-on-ancestor-tp26217077p26217077.html\nSent from the git mailing list archive at Nabble.com.\n"},{"id":"126911","messageId":"loom.20091105T193641-910@post.gmane.org","threadId":"21488","inReplyTo":"26217077.post@talk.nabble.com","subject":"Re: Preserving branches after merging on ancestor","fromName":"Eric Raible","fromEmail":"raible@gmail.com","sentAt":"2009-11-05T18:38:03Z","receivedAt":"2009-11-05T18:38:03Z","isPatch":false,"sender":{"key":"raible@gmail.com","avatar":null},"body":"Richard Lee <richard <at> webdezign.co.uk> writes:\n\n> So I tried using branches for features today. Most of the time I'm the only\n> person working on a project. So when I've finished working on a feature\n> branch and ready to merge it back into the master branch, the master head IS\n> the common ancestor of the two branches. As shown below\n> \n> * b6d75f1 [feature] stuff on feature branch\n> * 43dba08 stuff on feature branch\n> * ab7efdd [master] init\n> \n> When I merge the graph looks likes this:\n> \n> * b6d75f1 [master] [feature] stuff on feature branch\n> * 43dba08 stuff on feature branch\n> * ab7efdd init\n\nYou're getting a so-called \"fast-forward\" merge,\nwhich is the default.  Turn it off with:\n\ngit merge --no-ff\n"},{"id":"126928","messageId":"20091105223004.GA3224@progeny.tock","threadId":"21488","inReplyTo":"26217077.post@talk.nabble.com","subject":"Re: Preserving branches after merging on ancestor","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2009-11-05T22:30:04Z","receivedAt":"2009-11-05T22:30:04Z","isPatch":false,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi Richard,\n\nRichard Lee wrote:\n \n> One way of getting round this problem is to use empty commits on the master\n> branch, as shown below.\n> \n> *   6fc04b5 Merge branch 'feature2'\n> |\\\n> | * 07a117b stuff on feature2\n> * | 52f5ba1 Empty commit\n> |/\n> *   5deaa93 Merge branch 'feature1'\n> |\\\n> | * b163b17 stuff on feature1\n> | * 53bb820 stuff on feature1\n> | * c9ef14c stuff on feature1\n> * | 34227a3 Empty commit\n> |/\n> * e88d332 Init\n> \n> But is this correct? It seems rather hackish to create empty commits on the\n> master branch just to historically preserve commits on a seperate branch.\n> Should I be using feature branches in git like this or another way? For\n> example more informative commit messages. \n\nAs Eric said, you can avoid the empty commits by passing 'git merge'\nthe --no-ff option, which would give the history I think you intend:\n\n*   26749ab Merge branch 'feature2'\n|\\\n| * b9cd8ff stuff on feature2\n|/\n*   829ba2c Merge branch 'feature1'\n|\\\n| * b163b17 stuff on feature1\n| * 53bb820 stuff on feature1\n| * c9ef14c stuff on feature1\n|/\n* e88d332 Init\n\nBut doing this misses some of the main benefits of feature branches\nimho.\n\nIf you base each feature branch on the stable release or features it\ndepends on instead, this gives you the freedom to merge one feature without\nthe others to another branch.  For example:\n\n# wouldn’t feature1 be neat? let me try it.\ngit checkout -b feature1 v1.0\nhack hack hack\n# looks good.\ngit commit -a\n\n# how about an unrelated feature2?\ngit checkout -b feature2 v1.0\nhack hack hack\n# looks good.\ngit commit -a\n\n# but do they work?\ngit checkout v1.0; # detach head for testing [1]\ngit merge feature1 feature2\nmake check\n# hmm, these don’t seem to work well together\n... (investigating some more)\n\n# looks like feature1 is not ready for prime time\n# so let’s just use feature2 for now.\ngit checkout master\ngit merge feature2\ngit branch -d feature2\nmake check\n# looks good; better publish it.\ngit push origin master\n\nv1.0 --- feature1\n    \\\n     \\-- feature2 [master]\n\nAs a nice side-effect, if you work this way then you can develop\nfeature2 without being distracted by new bugs introduced by feature1.\n\nWith many features built this way, the revision graph starts to give\nsome hints about relationships between features developed around the\nsame time.  For example, with the history\n\nv1.0 --- feature1 --- feature2 -- feature4 -- feature6 - v1.1\n                               \\                        /\n                                -- feature5 ------------\n\nfeature4 and feature5 are not likely to be closely related, but\nfeature4 and feature6 might be.  The exact history of merges is less\nimportant than the general \"shape\" of the graph.\n\nThanks for the food for thought.\n\nHope that helps,\nJonathan\n\n[1] See <http://www.kernel.org/pub/software/scm/git/docs/git-checkout.html#_detached_head>.\n"},{"id":"126930","messageId":"20091105232848.GA1939@atjola.homenet","threadId":"21488","inReplyTo":"20091105223004.GA3224@progeny.tock","subject":"Re: Preserving branches after merging on ancestor","fromName":"Björn Steinbrink","fromEmail":"b.steinbrink@gmx.de","sentAt":"2009-11-05T23:28:48Z","receivedAt":"2009-11-05T23:28:48Z","isPatch":false,"sender":{"key":"b.steinbrink@gmx.de","avatar":"https://avatars.githubusercontent.com/u/230962?v=4"},"body":"On 2009.11.05 16:30:04 -0600, Jonathan Nieder wrote:\n> But doing this misses some of the main benefits of feature branches\n> imho.\n> \n> If you base each feature branch on the stable release or features it\n> depends on instead, this gives you the freedom to merge one feature without\n> the others to another branch.\n\nI guess Richard took the \"branch topic1, merge topic1, branch topic2,\nmerge topic2\" thing just as an example because that ends up with two\nfast-forwards. And your example _still_ has such a fast-forward.\n\n> For example:\n> \n> # wouldn’t feature1 be neat? let me try it.\n> git checkout -b feature1 v1.0\n> hack hack hack\n> # looks good.\n> git commit -a\n> \n> # how about an unrelated feature2?\n> git checkout -b feature2 v1.0\n> hack hack hack\n> # looks good.\n> git commit -a\n> \n> # but do they work?\n> git checkout v1.0; # detach head for testing [1]\n> git merge feature1 feature2\n> make check\n> # hmm, these don’t seem to work well together\n> ... (investigating some more)\n> \n> # looks like feature1 is not ready for prime time\n> # so let’s just use feature2 for now.\n> git checkout master\n> git merge feature2\n> git branch -d feature2\n> make check\n> # looks good; better publish it.\n> git push origin master\n> \n> v1.0 --- feature1\n>     \\\n>      \\-- feature2 [master]\n\nAnd here you got a fast-forward of master to feature2, i.e. linear\nhistory, which is what Richard was trying to avoid.\n\nInstead of:\n\nA---B---C---D---E (topic2) (master)\n     \\\n      F---G---H (topic1)\n\nHe wants:\n\n      F---G---H (topic1)\n     /\nA---B-----------M (master)\n     \\         /\n      C---D---E (topic2)\n\nSo he can see at which point topic2 got merged. This allows to ask \"which\ncommits got merged here\" (and for a merge-once topic branch this means:\nWhich commits are related to that topic), by using for example:\n\ngit log M^1..M^2 # Will show C, D and E\n\nIn the fast-forward case, there's no way to get that without manually\nfiguring out where the topic branch started.\n\nBjörn\n"},{"id":"126942","messageId":"20091106010947.GB4425@progeny.tock","threadId":"21488","inReplyTo":"20091105232848.GA1939@atjola.homenet","subject":"Re: Preserving branches after merging on ancestor","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2009-11-06T01:09:48Z","receivedAt":"2009-11-06T01:09:48Z","isPatch":false,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Björn Steinbrink wrote:\n\n> I guess Richard took the \"branch topic1, merge topic1, branch topic2,\n> merge topic2\" thing just as an example because that ends up with two\n> fast-forwards.\n\nHmm, I found Richard’s example pretty realistic.  I used to work like\nthat, and I don’t think I am the only one.\n\n> And your example _still_ has such a fast-forward.\n\nYep, if you really want to avoid fast-forwards, please use \"--no-ff\"!\n\nBut what I was trying to make clear was that in some workflows, the\nfast-forwards are not so harmful.  They even make the history a little\ncleaner (easier to read and understand).\n\n> Instead of:\n> \n> A---B---C---D---E (topic2) (master)\n>      \\\n>       F---G---H (topic1)\n> \n> He wants:\n> \n>       F---G---H (topic1)\n>      /\n> A---B-----------M (master)\n>      \\         /\n>       C---D---E (topic2)\n> \n> So he can see at which point topic2 got merged. This allows to ask \"which\n> commits got merged here\" (and for a merge-once topic branch this means:\n> Which commits are related to that topic), by using for example:\n> \n> git log M^1..M^2 # Will show C, D and E\n\nYou can get the same information locally even with a fast-forward:\n\ngit log master@{1}..master\n\nBut to someone reading the published history, it is not available.\nDepending on your way of working, this may or may not be reasonable.\n\nPerhaps your merge commit messages contain important information about\nthe branch’s overall purpose and provenance, which would be impossible\nif there is no merge commit.\n\nOn the other hand, if the goal is just to present the fact of a merge,\nto explain where a patch falls in the larger scheme of things, then\nhow large a chunk of changes I decided to call a feature does not seem\ntoo important.\n\nImagine a patch series, cleaning up some ugly code that has been\nbothering me for a while:\n\n base [master] --- A --- B --- C [cleanup]\n\nIt looks good, so I merge to master with --no-ff.\n\n base --------- D [master]\n     \\         /\n      A---B---C [cleanup]\n\nLooking at that code inspires me to build a new feature that is much\neasier with the cleaned up version.  So I fork a branch from cleanup\n(Or master?  Their content is the same, but somehow I choose one) and\nwrite some patches for the new feature.\n\n base --------- D [master]\n     \\         /\n      A---B---C [cleanup] --- E --- F --- G\n\nIt looks good, so I merge.\n\n base --------- D --------- H [master]\n     \\         /           /\n      A---B---C---E---F---G\n\nIs this really any easier to read than base---A---B---C---E---F---G?\nIn hindsight, was this logically really two series, or is the D commit\nextra cruft?\n\nAlmost always, a fast-forward comes from a continuation of this kind,\nsince that is what it means for a commit to be the logical commit to\nfork from.\n\nOf course, these things are a matter of taste.  I just wanted to\nexplain why a fast-forward could at least sometimes be the right\nresult from merging a topic branch (and why, in practice, some people\nnever end up needing to use --no-ff).\n\nRegards,\nJonathan\n"},{"id":"126946","messageId":"20091106021038.GA27206@atjola.homenet","threadId":"21488","inReplyTo":"20091106010947.GB4425@progeny.tock","subject":"Re: Preserving branches after merging on ancestor","fromName":"Björn Steinbrink","fromEmail":"b.steinbrink@gmx.de","sentAt":"2009-11-06T02:10:38Z","receivedAt":"2009-11-06T02:10:38Z","isPatch":false,"sender":{"key":"b.steinbrink@gmx.de","avatar":"https://avatars.githubusercontent.com/u/230962?v=4"},"body":"On 2009.11.05 19:09:48 -0600, Jonathan Nieder wrote:\n> Björn Steinbrink wrote:\n> \n> > I guess Richard took the \"branch topic1, merge topic1, branch topic2,\n> > merge topic2\" thing just as an example because that ends up with two\n> > fast-forwards.\n> \n> Hmm, I found Richard’s example pretty realistic.  I used to work like\n> that, and I don’t think I am the only one.\n> \n> > And your example _still_ has such a fast-forward.\n> \n> Yep, if you really want to avoid fast-forwards, please use \"--no-ff\"!\n> \n> But what I was trying to make clear was that in some workflows, the\n> fast-forwards are not so harmful.  They even make the history a little\n> cleaner (easier to read and understand).\n> \n> > Instead of:\n> > \n> > A---B---C---D---E (topic2) (master)\n> >      \\\n> >       F---G---H (topic1)\n> > \n> > He wants:\n> > \n> >       F---G---H (topic1)\n> >      /\n> > A---B-----------M (master)\n> >      \\         /\n> >       C---D---E (topic2)\n> > \n> > So he can see at which point topic2 got merged. This allows to ask \"which\n> > commits got merged here\" (and for a merge-once topic branch this means:\n> > Which commits are related to that topic), by using for example:\n> > \n> > git log M^1..M^2 # Will show C, D and E\n> \n> You can get the same information locally even with a fast-forward:\n> \n> git log master@{1}..master\n\nAnd after two weeks, you'll dig through the reflog to find the right\nentries? Come on... And (as you said yourself below) everyone else\n(including yourself in a different clone of that repo) doesn't have that\nreflog entry anyway.\n\n> But to someone reading the published history, it is not available.\n> Depending on your way of working, this may or may not be reasonable.\n> \n> Perhaps your merge commit messages contain important information about\n> the branch’s overall purpose and provenance, which would be impossible\n> if there is no merge commit.\n\nThe actual commits that make up the topic should have descriptive enough\ncommit messages to make extra \"why merge this\" messages shouldn't be\nrequired. But merge commits provide a way of giving a high-level\noverview of the history of a project.\n\n> On the other hand, if the goal is just to present the fact of a merge,\n> to explain where a patch falls in the larger scheme of things, then\n> how large a chunk of changes I decided to call a feature does not seem\n> too important.\n\nFor example in git.git, I can do \"git log --first-parent\n..origin/master\" to get a high-level log of what happened. And then I\nmight see commit b7eb912b0, which is \"Merge branch ja/fetch-doc\". So I\nknow \"OK, there were some doc updates\", without having to crawl through\nthe individual commits.\n\nAnd if I decide that for _this_ topic, I care to see what got merged, I\ncan do: git log b7eb912b0^1..b7eb912b0^2\n\nHad this been a fast-forward, even the --first-parent history would\nthrow the individual commits at me, giving me less of a high-level\noverview.\n\n> Imagine a patch series, cleaning up some ugly code that has been\n> bothering me for a while:\n> \n>  base [master] --- A --- B --- C [cleanup]\n> \n> It looks good, so I merge to master with --no-ff.\n> \n>  base --------- D [master]\n>      \\         /\n>       A---B---C [cleanup]\n> \n> Looking at that code inspires me to build a new feature that is much\n> easier with the cleaned up version.  So I fork a branch from cleanup\n> (Or master?  Their content is the same, but somehow I choose one) and\n> write some patches for the new feature.\n> \n>  base --------- D [master]\n>      \\         /\n>       A---B---C [cleanup] --- E --- F --- G\n> \n> It looks good, so I merge.\n> \n>  base --------- D --------- H [master]\n>      \\         /           /\n>       A---B---C---E---F---G\n> \n> Is this really any easier to read than base---A---B---C---E---F---G?\n> In hindsight, was this logically really two series, or is the D commit\n> extra cruft?\n\nChoosing \"cleanup\" as the starting point for an unrelated topic branch\n(after all \"cleanup\" was already merged, so there's absolutely no reason\nto base a new topic on it) is wrong. That history looks as if E,F,G was\na second part of the same topic branch.\n\nI'd have done:\n\n              E---F---G (topic2)\n             /         \\\n0-----------D-----------H (master)\n \\         /\n  A---B---C (cleanup)\n\nAnd then I could do \"git log --first-parent master\" to see H and D\n(high-level view), and \"git log H^1..H^2\" or \"git log D^1..D^2\" to get a\nlow-level view at the merged topics.\n\nNeither of which I could do with \"0---A---B---C---E---F---G\". With that,\nI'd have to manually looking up the start/end points of each topic.\n\n> Almost always, a fast-forward comes from a continuation of this kind,\n> since that is what it means for a commit to be the logical commit to\n> fork from.\n\nHm? I don't get that one. The \"continuation\" would be that you started\nthe second topic branch from the first topic branch, right? And that\ncaused the merge to \"master\" _not_ to be a fast-forward. So I'm somewhat\nconfused there.\n\n> Of course, these things are a matter of taste.  I just wanted to\n> explain why a fast-forward could at least sometimes be the right\n> result from merging a topic branch (and why, in practice, some people\n> never end up needing to use --no-ff).\n\nSure, fast-forwards can be the right thing, e.g. when you have a\n(possibly useless) branch head \"master\" that you update by pulling. In\nsuch a case merge commits would only lead to useless clutter. But\nRichard wants to see where topic branches got merged (to be still able\nto see what got merged in the future), and yeah, that's a matter of\ntaste. But you argued that using --no-ff would \"[miss] some of the main\nbenefits of feature branches\", which is simply not true.\n\nBjörn\n"},{"id":"126948","messageId":"20091106050353.GA8824@progeny.tock","threadId":"21488","inReplyTo":"20091106021038.GA27206@atjola.homenet","subject":"Re: Preserving branches after merging on ancestor","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2009-11-06T05:03:53Z","receivedAt":"2009-11-06T05:03:53Z","isPatch":false,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Björn Steinbrink wrote:\n\n> For example in git.git, I can do \"git log --first-parent\n> ..origin/master\" to get a high-level log of what happened. And then I\n> might see commit b7eb912b0, which is \"Merge branch ja/fetch-doc\". So I\n> know \"OK, there were some doc updates\", without having to crawl through\n> the individual commits.\n\nYep, fast-forward merges do ruin the --first-parent log.  Thanks for\nthe reminder.\n\n>> Of course, these things are a matter of taste.  I just wanted to\n>> explain why a fast-forward could at least sometimes be the right\n>> result from merging a topic branch (and why, in practice, some people\n>> never end up needing to use --no-ff).\n> \n> Sure, fast-forwards can be the right thing, e.g. when you have a\n> (possibly useless) branch head \"master\" that you update by pulling. In\n> such a case merge commits would only lead to useless clutter.\n\nI hope this use case becomes less important as git’s UI improves.  To\ntrack unmodified upstream sources, a simple 'git checkout' to get\nup-to-date is much simpler, except that \"git branch\" does not display\nthe current branch any more.  Using 'git pull' for the daily update\nmakes for a distractingly merge-heavy history once one has commits of\none’s own.\n\nA similar use case won’t disappear: asking someone else to resolve a\nmerge for you and pulling the result.\n\nFor both these tasks, --ff-only might give better behavior.\n\nIn other cases, I would guess some people would always want --no-ff\nand others never.  Apparently, there is a configuration option to\nsupport this: add a line \"mergeoptions = --no-ff\" (or \"mergeoptions =\n--ff\") to a [branch \"master\"] section in .git/config or ~/.gitconfig.\n\n> But\n> Richard wants to see where topic branches got merged (to be still able\n> to see what got merged in the future), and yeah, that's a matter of\n> taste. But you argued that using --no-ff would \"[miss] some of the main\n> benefits of feature branches\", which is simply not true.\n\nI spoke imprecisely; I should have said that if most merges are\ncandidates for fast-forwarding, this suggests feature branches are not\nbeing used in the best way, and --no-ff just makes that situation more\ntolerable.\n\nThen your response pushed me towards the question of whether --no-ff\nis a good idea in general, and I got distracted. :)  Sorry for the\nconfusion, and thanks for the insights.\n\nRegards,\nJonathan\n"},{"id":"126985","messageId":"1257520877359-3959325.post@n2.nabble.com","threadId":"21488","inReplyTo":"20091106050353.GA8824@progeny.tock","subject":"Re: Preserving branches after merging on ancestor","fromName":"rhlee","fromEmail":"richard@webdezign.co.uk","sentAt":"2009-11-06T15:21:17Z","receivedAt":"2009-11-06T15:21:17Z","isPatch":false,"sender":{"key":"richard@webdezign.co.uk","avatar":"https://gravatar.com/avatar/36c0bc285b2d30baa54ed2e1488161fd27a4a4a8128836a673b66204ab08c9b7?d=mp&s=160"},"body":"\nHi John, Björn and Eric,\n\nThank you very much for your replies from which I gained a lot insight about\ngit merging and different workflows.\n\nYes, I have tried out --no-ff and it does the job for me. (Incidentally,\ndoing that take it look neater in git gui as all the master nodes appear on\ntop of each other. Using empty commits, the merged branches appear on top\nthe master nodes in the graph.)\n\n\nJonathan Nieder-2 wrote:\n> \n> Then your response pushed me towards the question of whether --no-ff is a\n> good idea in general\n> \n\nJohn, I get the feeling from what you say in general that fast forwards are\ndefault behaviour for merges for a reason and by using the --no-ff option I\nam making my workflow and git history uncessesarily awkward and working\nagainst best practices?\n\n\nJonathan Nieder-2 wrote:\n> \n>> I guess Richard took the \"branch topic1, merge topic1, branch topic2, \n>> merge topic2\" thing just as an example because that ends up with two \n>> fast-forwards.\n> \n> Hmm, I found Richard’s example pretty realistic.  I used to work like\n> that, and I don’t think I am the only one.\n> \n\nI'm not saying there is any one \"right\" workflow. But is there a more\nsuitable workflow than than \"branch topic1, merge topic1, branch topic2,\nmerge topic2\"?\n\nThanks,\nRichard\n-- \nView this message in context: http://n2.nabble.com/Preserving-branches-after-merging-on-ancestor-tp3954131p3959325.html\nSent from the git mailing list archive at Nabble.com.\n"},{"id":"127005","messageId":"20091106225250.GA14642@progeny.tock","threadId":"21488","inReplyTo":"1257520877359-3959325.post@n2.nabble.com","subject":"Re: Preserving branches after merging on ancestor","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2009-11-06T22:52:50Z","receivedAt":"2009-11-06T22:52:50Z","isPatch":false,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Richard Lee wrote:\n> Jonathan Nieder wrote:\n\n>> Then your response pushed me towards the question of whether --no-ff is a\n>> good idea in general\n>> \n> \n> John, I get the feeling from what you say in general that fast forwards are\n> default behaviour for merges for a reason and by using the --no-ff option I\n> am making my workflow and git history uncessesarily awkward and working\n> against best practices?\n\nWell, no.  Some of us (read: I) just haven’t figured out yet how to fit the\n--no-ff option into a broader workflow yet.  It is only two years old. :)\n\nThere are pros and cons to using --no-ff to merge topic branches.  Pros:\n\n * 'git log --first-parent' will give the list of topics now.\n * The beginning and end of each topic is not forgotten by a clone any\n   more.\n\nCons:\n\n * The perceived beginning and end of a topic might be irrelevant or\n   misleading.\n * Every topic needs a good name. :)\n * More commits for a person looking through the history to deal with.\n   A merge commit from a would-be fast-forward records content identical\n   to its second parent, and it is not necessary as glue to tie the\n   content-changing commits together any more.\n\nAfter thinking about it a little, the pros seem to far outweight the cons.\n\n>> Björn Steinbrink wrote:\n>>\n>>> I guess Richard took the \"branch topic1, merge topic1, branch topic2, \n>>> merge topic2\" thing just as an example because that ends up with two \n>>> fast-forwards.\n>> \n>> Hmm, I found Richard’s example pretty realistic.  I used to work like\n>> that, and I don’t think I am the only one.\n>> \n> \n> I'm not saying there is any one \"right\" workflow. But is there a more\n> suitable workflow than than \"branch topic1, merge topic1, branch topic2,\n> merge topic2\"?\n\nYes, in my opinion.  I prefer to branch topic1, branch topic2, ...\nand only later (after some time to reflect) decide which topics to\nmerge.  For this to work, each topic should not have all previous\ntopics as ancestors, or there is no way to postpone merging any one.\n\nThis is especially nice when a topic turns into a long-term project.\nBy not merging in the partial work, I keep the code in the master\nbranch a little cleaner, but more importantly, bugs in the partial\nwork do not interfere with work on other topics.  Once it is finally\ntime to merge the topic back to master, it is in one clean merge, and\nall the commits are together for someone looking at the history.\n\n“What about testing?” one might ask.  “How can I tell when it is safe\nto merge the topic to master, when the topic and other features since\nthen might work well separately but not together?”  The “Throw-away\nintegration” section in gitworkflows(7) [1] discusses how to deal with\nthis.\n\nTaking the idea of forking from the oldest relevant commit to an\nextreme in a single-person project, you can end up with history like\nthis:\n\ninitial---------------final\n       \\             /|\n        \\---A-------/ |\n         \\         / /|\n          \\---B---/ / |\n           \\       /  |\n            \\---C--   |\n             \\       /\n              \\--D---\n               \\\n                -E- ...\n\ni.e., full of octopus merges and basically unreadable in gitk.\nArguably, this is at least partially a gitk bug.  [Aside: a dream\nfeature for gitk would be to give the --first-parent history at first\nand then fill in topics when the user requests them.  That is, in this\nexample, it would show\n\n  initial---final\n\nbut after a click on the parent A, it would show\n\n  initial---final\n         \\ /\n          A\n\nand so on.]  To avoid this, it is best not defer merging topics into\nthe mainline for too long, and to base each topic branch not on the\noldest relevant commit but on the tip of the oldest branch it might be\nmerged to (which in the simplest case is usually the mainline).\n\nA single person has a lot of control over the shape of the history,\nso that it is easy to make it totally linear or sequence of enormous\noctopuses.  The nicest history for others to read, I think, is that\nmost like one created by many people in a healthy project.  But that’s\na hard ideal to achieve, and more important than crafting well shaped\nhistory is to write good code, so it is not worth obsessing over.\n\nI hope that is a little clearer.\n\nRegards,\nJonathan\n\n[1] http://www.kernel.org/pub/software/scm/git/docs/gitworkflows.html#_throw_away_integration\n"},{"id":"127031","messageId":"c94f8e120911061941l1fb62d84g9a5ba3f1a00d9156@mail.gmail.com","threadId":"21488","inReplyTo":"1257520877359-3959325.post@n2.nabble.com","subject":"Re: Preserving branches after merging on ancestor","fromName":"Dilip M","fromEmail":"dilipm79@gmail.com","sentAt":"2009-11-07T03:41:11Z","receivedAt":"2009-11-07T03:41:11Z","isPatch":false,"sender":{"key":"dilipm79@gmail.com","avatar":"https://gravatar.com/avatar/9417e308513ce9251de2802a026c72eb164e6c9b9d7143a3ee13f6ed0c4d1bd5?d=mp&s=160"},"body":"On Fri, Nov 6, 2009 at 8:51 PM, rhlee <richard@webdezign.co.uk> wrote:\n\n> Hi John, Björn and Eric,\n>\n> Thank you very much for your replies from which I gained a lot insight about\n> git merging and different workflows.\n>\n> Yes, I have tried out --no-ff and it does the job for me. (Incidentally, doing\n> that take it look neater in git gui as all the master nodes appear on top of\n> each other. Using empty commits, the merged branches appear on top the master\n> nodes in the graph.)\n\nThanks to Richard, John, Björn, and Eric.\n\nI had a similar _confusion_ looking looking at graph. I always use \"log --graph\n--pretty=oneline\". Now I have _opted_ to pull/merge with '--no-ff', to keep the\ngraph plain and simple for non-power users :)\n\n\n\n-- Dilip\n"},{"id":"127040","messageId":"20091107132840.GA9303@atjola.homenet","threadId":"21488","inReplyTo":"1257520877359-3959325.post@n2.nabble.com","subject":"Re: Preserving branches after merging on ancestor","fromName":"Björn Steinbrink","fromEmail":"b.steinbrink@gmx.de","sentAt":"2009-11-07T13:28:40Z","receivedAt":"2009-11-07T13:28:40Z","isPatch":false,"sender":{"key":"b.steinbrink@gmx.de","avatar":"https://avatars.githubusercontent.com/u/230962?v=4"},"body":"On 2009.11.06 07:21:17 -0800, rhlee wrote:\n> Jonathan Nieder-2 wrote:\n> > \n> > Then your response pushed me towards the question of whether --no-ff is a\n> > good idea in general\n> > \n> \n> John, I get the feeling from what you say in general that fast forwards are\n> default behaviour for merges for a reason and by using the --no-ff option I\n> am making my workflow and git history uncessesarily awkward and working\n> against best practices?\n\nAs Jonathan already said, there are pros and cons when the merge is\nabout merging topic branches to some \"main\" branch. In addition to that,\nworking with git often also involves other merges. For example, you\nmight have your private topic branch, on which you work on two different\nboxes. So you push your topic branch to some private bare repo, fetch it\nfrom the other box, work there, and push the result back to the bare\nrepo. And then, in the \"original\" repo, you of course want to update\nyour local branch head to reflect the new changes. So you fetch and\nmerge, but you really don't want a merge commit in that case, but the\ndefault fast-forward behaviour. In some sense, that kind of \"merge\", is\nmore like an \"update\", for which the fast-forward behaviour is simply\nbetter.\n\n> Jonathan Nieder-2 wrote:\n> > \n> >> I guess Richard took the \"branch topic1, merge topic1, branch topic2, \n> >> merge topic2\" thing just as an example because that ends up with two \n> >> fast-forwards.\n> > \n> > Hmm, I found Richard’s example pretty realistic.  I used to work like\n> > that, and I don’t think I am the only one.\n> > \n> \n> I'm not saying there is any one \"right\" workflow. But is there a more\n> suitable workflow than than \"branch topic1, merge topic1, branch topic2,\n> merge topic2\"?\n\nThat order of commands looks like a strict \"Start a topic, finish a\ntopic, merge it, start next topic, ...\" workflow. And that severely\nlimits what you can do, as you're forced to work on only one thing and\nto finish it first before starting something else. Such a strict\nworkflow basically makes branching pointless. I often do things like:\n\ngit checkout -b new_feature master\n*work & commit*\n\n*get a bug report about the stable version*\ngit checkout -b bug_fix_foo maint\n*work & commit*\n\n*get a report about a trivial bug on master*\ngit checkout master\n*fix bug & commit* # Yes, directly on master\ngit push\n\ngit checkout bug_fix_foo\n*finish the bug_fix*\ngit checkout maint\ngit merge bug_fix_foo # Merge the bugfix to the oldest branch it applies to\ngit checkout master\ngit merge maint # Merge bugfixes forward to the more recent branches\ngit push\n\ngit checkout new_feature\n*finish feature*\ngit checkout master\ngit merge new_feature\ngit push\n\nSo I could work on multiple things at the same time, and even merged\nthem in reverse order, compared to the order in which I started the\nbranches. It's just the strict \"start, finish, merge, start next, ...\"\norder that looks suspicious, but that's totally unrelated to the --no-ff\nthing. Even when working on multiple branches and merging them in a\nrandom order, you can hit a fast-forward for the \"first\" merge.\n\nBjörn\n"},{"id":"127042","messageId":"20091107133101.GB9303@atjola.homenet","threadId":"21488","inReplyTo":"c94f8e120911061941l1fb62d84g9a5ba3f1a00d9156@mail.gmail.com","subject":"Re: Preserving branches after merging on ancestor","fromName":"Björn Steinbrink","fromEmail":"b.steinbrink@gmx.de","sentAt":"2009-11-07T13:31:01Z","receivedAt":"2009-11-07T13:31:01Z","isPatch":false,"sender":{"key":"b.steinbrink@gmx.de","avatar":"https://avatars.githubusercontent.com/u/230962?v=4"},"body":"On 2009.11.07 09:11:11 +0530, Dilip M wrote:\n> On Fri, Nov 6, 2009 at 8:51 PM, rhlee <richard@webdezign.co.uk> wrote:\n> \n> > Hi John, Björn and Eric,\n> >\n> > Thank you very much for your replies from which I gained a lot\n> > insight about git merging and different workflows.\n> >\n> > Yes, I have tried out --no-ff and it does the job for me.\n> > (Incidentally, doing that take it look neater in git gui as all the\n> > master nodes appear on top of each other. Using empty commits, the\n> > merged branches appear on top the master nodes in the graph.)\n> \n> Thanks to Richard, John, Björn, and Eric.\n> \n> I had a similar _confusion_ looking looking at graph. I always use\n> \"log --graph --pretty=oneline\". Now I have _opted_ to pull/merge with\n> '--no-ff', to keep the graph plain and simple for non-power users :)\n\nJust be careful with that. There are situations in which you clearly\ndon't want --no-ff, see the \"working on a topic branch on multiple\nboxes\" example I gave in the mail I sent a minute ago. ;-)\n\nBjörn\n"}]}