{"thread":{"id":"29867","subject":"who's on first? - following first parent and merge-management","startedAt":"2012-03-07T05:36:06Z","lastAt":"2012-03-09T16:26:33Z","messageCount":13,"participants":["Neal Kreitzinger","Junio C Hamano","Jeff King","Jonathan Nieder","Johannes Sixt","Holger Hellmuth"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"186288","messageId":"jj6s47$m98$1@dough.gmane.org","threadId":"29867","inReplyTo":null,"subject":"who's on first? - following first parent and merge-management","fromName":"Neal Kreitzinger","fromEmail":"nkreitzinger@gmail.com","sentAt":"2012-03-07T05:36:06Z","receivedAt":"2012-03-07T05:36:06Z","isPatch":false,"sender":{"key":"nkreitzinger@gmail.com","avatar":null},"body":"\"first parent\" and \"follow first parent\" are mentioned frequently in git \ndocumentation.  This seems to imply that its pretty important.  That \nwould imply it should be intentional (planned).  Who is \"first parent\"? \n  Who is \"first parent\" _meant_ to be?  What is \"follow first parent\" \n_meant_ to show?\n\n(I've been on the rebase track until now so I'm \"new\" to git-merge's.) \nSymptomatically, I think \"first parent\" is the branch you were on when \nyou did the merge.  That would mean the first parent can change \ndepending on your merge-management practices.  This affects the results \nthat \"follow first parent\" produces.  For example:\n\n$ git log --first-parent --oneline origin/master\ndeadbee some commit x\n\nScenario A: \"First-Parent Flip-Flop\" (some users are doing this)\n\n(1) I commit on local master.  USER=foo\n$ git checkout master && hack && git commit -a -m \"foo commit 1\"\n$ git log --first-parent --oneline master\nfoo1111 foo commit 1\ndeadbee some commit x\n\n(2) You push to canonical master.  USER=bar\n$ git checkout master && hack && git commit -a -m \"bar commit 1\"\n$ git log --first-parent --oneline master\nbar1111 bar commit 1\ndeadbee some commit x\n$ git push origin HEAD && git fetch origin\n$ git log --first-parent --oneline origin/master\nbar1111 bar commit 1\ndeadbee some commit x\n\n(3) I merge canonical master w/my master and push.  USER=foo\n$ git checkout master && git pull origin\n$ git log --first-parent --oneline master\nmrg1111 Merge branch 'master' of file:///root/BARE\nfoo1111 foo commit 1\ndeadbee some commit x\n$ git push origin HEAD && git fetch origin\n$ git log --first-parent --oneline origin/master\nmrg1111 Merge branch 'master' of file:///root/BARE\nfoo1111 foo commit 1\ndeadbee some commit x\n\n(4) You merge canonical master w/your master and push.  USER=bar\n$ git checkout master && hack && git commit -a -m \"bar commit 2\"\n$ git log --first-parent --oneline master\nbar2222 bar commit 2\nbar1111 bar commit 1\ndeadbee some commit x\n$ git pull origin\n$ git log --first-parent --oneline master\nmrg2222 Merge branch 'master' of file:///root/BARE\nbar2222 bar commit 2\nbar1111 bar commit 1\ndeadbee some commit x\n$ git push origin HEAD && git fetch origin\n$ git log --first-parent --oneline origin/master\nmrg2222 Merge branch 'master' of file:///root/BARE\nbar2222 bar commit 2\nbar1111 bar commit 1\ndeadbee some commit x\n\nThis \"flip-flop\" practice does not seem right to me.  Please comment.\n\nScenario B: \"First-Parent Consistency\"\n(1) I commit on local master.  USER=foo\n$ git checkout -b foo-topic master && hack && git commit -a -m \"foo \ncommit 1\"\n$ git log --first-parent --oneline foo-topic\nfoo1111 foo commit 1\ndeadbee some commit x\n\n(2) You push to canonical master.  USER=bar\n$ git checkout -b bar-topic master && hack && git commit -a -m \"bar \ncommit 1\"\n$ git log --first-parent --oneline bar-topic\nbar1111 bar commit 1\ndeadbee some commit x\n$ git checkout master && git merge bar-topic && git push origin HEAD && \ngit fetch origin\n$ git log --first-parent --oneline origin/master\nbar1111 bar commit 1\ndeadbee some commit x\n\n(3) I merge --no-ff into master and push.  USER=foo\n$ git checkout master && git pull --ff-only origin\n$ git log --first-parent --oneline master\nbar1111 bar commit 1\ndeadbee some commit x\n$ git-merge foo-topic\n$ git log --first-parent --oneline master\nmrg1111 Merge branch 'foo-topic'\nbar1111 bar commit 1\ndeadbee some commit x\n$ git push origin HEAD && git fetch origin\n$ git log --first-parent --oneline origin/master\nmrg1111 Merge branch 'foo-topic'\nbar1111 bar commit 1\ndeadbee some commit x\n\n(4) You merge --no-ff into master and push.  USER=bar\n$ git checkout bar-topic && hack && git commit -a -m \"bar commit 2\"\n$ git log --first-parent --oneline bar-topic\nbar2222 bar commit 2\nbar1111 bar commit 1\ndeadbee some commit x\n$ git checkout origin && git pull --ff-only origin\n$ git log --first-parent --oneline master\nmrg1111 Merge branch 'foo-topic'\nbar1111 bar commit 1\ndeadbee some commit x\n$ git merge bar-topic\n$ git log --first-parent --oneline master\nmrg2222 Merge branch 'bar-topic'\nmrg1111 Merge branch 'foo-topic'\nbar1111 bar commit 1\ndeadbee some commit x\n$ git push origin HEAD && git fetch origin\n$ git log --first-parent --oneline origin/master\nmrg2222 Merge branch 'bar-topic'\nmrg1111 Merge branch 'foo-topic'\nbar1111 bar commit 1\ndeadbee some commit x\n\nThis \"consistency\" scenario seems better, but I'm not sure if its right. \n  Git seems to \"like it\" in that the merge messages make more sense. \nPlease comment.\n\nPlease advise on \"first parent\" intent, best-practices, and pitfalls, or \ndocumentation that explains it.  (I haven't found documentation that \ndirectly explains \"first parent theory and practice\".  I've seen many \nreferences to \"first parent\" and its implied meaning that I'm supposed \nto \"just know\" or deduce).\n\nThanks in advance for any pointers.\n\nv/r,\nneal\n"},{"id":"186291","messageId":"7vwr6woo8p.fsf@alter.siamese.dyndns.org","threadId":"29867","inReplyTo":"jj6s47$m98$1@dough.gmane.org","subject":"Re: who's on first? - following first parent and merge-management","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-07T07:37:42Z","receivedAt":"2012-03-07T07:37:42Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neal Kreitzinger <nkreitzinger@gmail.com> writes:\n\n> Please advise on \"first parent\" intent, best-practices, and pitfalls,\n> or documentation that explains it.  (I haven't found documentation\n> that directly explains \"first parent theory and practice\".  I've seen\n> many references to \"first parent\" and its implied meaning that I'm\n> supposed to \"just know\" or deduce).\n\nA short conclusion: if you take \"first parentness\" very seriously,\nneither of your two approaches are optimal, but that does not make\nyou a bad person. It is just that \"log --first-parent\" is not the\nbest way to get an overview of the history for your workflow.\n\nThe mechanical definition of \"first parent\" is that:\n\n - A merge is a commit with more than one parent.\n\n - When you run \"merge\", you are on one commit, HEAD, taking changes\n   made by \"other branches\" you are merging into \"your history\"\n   (whose definition is \"the commit-dag leading to your HEAD\n   commit\"), and record the resulting tree as a new commit.\n\n - This new commit records all its parents, one of them being your\n   old \"HEAD\" and the rest being \"other branches\" you merged into\n   \"your history\".  They are recorded in that order in the resulting\n   commit (\"git cat-file commit HEAD\" after a merge to see them).\n\nHence, the first parent of a merge is the HEAD the committer was at\nwhen s/he ran \"git merge\".\n\nIt's late so I won't go into the details of what the implications of\nthis is in this message.  Perhaps tomorrow when/if I have time.\n"},{"id":"186377","messageId":"7vty1zfwmd.fsf@alter.siamese.dyndns.org","threadId":"29867","inReplyTo":"7vwr6woo8p.fsf@alter.siamese.dyndns.org","subject":"Re: who's on first? - following first parent and merge-management","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-08T06:13:46Z","receivedAt":"2012-03-08T06:13:46Z","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> The mechanical definition of \"first parent\" is that:\n>\n>  - A merge is a commit with more than one parent.\n>\n>  - When you run \"merge\", you are on one commit, HEAD, taking changes\n>    made by \"other branches\" you are merging into \"your history\"\n>    (whose definition is \"the commit-dag leading to your HEAD\n>    commit\"), and record the resulting tree as a new commit.\n>\n>  - This new commit records all its parents, one of them being your\n>    old \"HEAD\" and the rest being \"other branches\" you merged into\n>    \"your history\".  They are recorded in that order in the resulting\n>    commit (\"git cat-file commit HEAD\" after a merge to see them).\n>\n> Hence, the first parent of a merge is the HEAD the committer was at\n> when s/he ran \"git merge\".\n\nGiven the above definition, the first thing to realize is that \"the\nfirst parent\" is primarily a local concept.  If you are looking at\none commit on a run of \"a single strand of pearls\", it only has one\nparent (i.e. its first parent), and it is the state the committer\nwas on when he made the commit.  If you are looking at a merge, its\nfirst parent is the commit the person who made that merge was on.\n\nBecause of this local nature of first-parenthood, depending on the\nway how your project works, following the first parent chain all the\nway down to the root, i.e. \"git log --first-parent\", may or may not\ngive an output that makes sense.  \"git show HEAD~250\" has the same\nissue.\n\nAn extreme example is where Git is used merely as a better CVS,\nwhere everybody works on his own \"master\", e.g.\n\n    $ git clone $central mine && cd mine\n    ... begin repeating from here ...\n    $ git pull ;# this may get \"already up-to-date\" or create a merge\n    $ work; work; work; git commit\n    $ work; work; work; git commit\n    $ git pull ;# this may create a merge or get \"already up-to-date\"\n    ... optionally ...\n    $ git push\n    ... go back and repeat ...\n\nImagine many people are doing the above simultaneously against the\nsame shared central repository.\n\nBecause everybody can create a \"merge\" when he is on his latest\ncommit that may not even yet be ready for other's use, the first\nparent of a merge has no significance in the history of the overall\nproject. The first parents of merges in such a project are \"points\nat which random members of the project happened to be immediately\nbefore s/he pulled from the shared central repository\".  When you\nwant a birds-eye view of changes between two versions of a project,\n\"git log --first-parent v1.0..v2.0\" gives no useful information in\nsuch a project.  \"git log --no-merges\" or even \"git shortlog\" over\nthe same range would generally work better.\n\nInsisting on \"git pull --no-ff\" in such a workflow makes things even\nworse for \"first-parent summary\".  If everybody else were active\nwhile you were sleeping, and if you were up-to-date before going to\nbed, \"git pull --no-ff\" you do as the first thing in the morning\nfrom a habit will record a useless merge commit, and the _only_ two\nthings such a commit records are (1) where the tip of the shared\ncentral repository was before you went to bed, and (2) where the tip\nof the shared central repository was when you came back to work.\nNeither is worth recording as part of the overall project history,\nobviously.\n\nThere is the other end of extreme that first-parent summary works\nwell. When there is a clear pecking order among project members,\ni.e. there is the central integrator \"My history is the official\none, yours are forks of it and I may merge them back to my history\nfrom time to time\".  Unless there is a fast-forward merge, in such a\nsetting, \"git log --first-parent\" going all the way down to the root\nshows the way the history grew from the integrator's point of view,\nand use of \"git pull --no-ff\" by the integrator is one way to make\nsure that all merge commits yield this consistent view.  He may have\nmade individual commits (i.e. a single strand of pearls) on the\nmainline of the history, and they are shown as individual commits.\nHe may have merged from a branch of his own or somebody else into\nthe mainline of the history, and such a merge is shown as a single\nevent that pulls all the commits from the side branch (and this is\nwhere \"git merge --summary\" becomes useful).\n\nIt is no accident that we encourage users to focus the work made on\na single branch (either his own or a remote) to a single topic---by\ndoing so, it makes more sense to treat a merge of such a branch into\nthe mainline as a single event that adds a feature (or fixes a bug,\nor whatever the topic of the branch wanted to achieve), relative to\nthe state of the project immediately before the merge (i.e. \"the\nfirst parent\" of the merge).  And \"log --first-parent\" is a way to\nsummarize the history by culling the details of \"side branches\" and\nletting only the merge commits talk about what these side branches\ndid to the history.\n\nIt also is not an accident that \"--first-parent\" is a much later\ninvention than \"log\" and \"shortlog\".  Only after people got used to\nworking with Git, they discovered the usefulness of the topic branch\nworkflow, which is the key ingredient for any history that the first\nparenthood can giving a birds-eye view.\n\nEven if your project is using a central shared repository, you can\ntake advantage of \"first parent\" summary by making sure you merge\nyour work into the shared history, not the other way around like the\nworkflow illustrated earlier in this message (or your \"Flip-flop\").\n\nYou would work like this:\n\n    $ git clone $central mine && cd mine\n    $ git checkout -b mywork\n    ... begin repeating from here ...\n    $ git checkout work ;# make sure you do not work on 'master'\n    $ work; work; work; git commit\n    $ work; work; work; git commit\n    ... when you are done working on one logical topic ...\n    $ git checkout master\n    $ git pull --ff-only ;# the tip of shared history\n    $ git merge mywork ;# note the first parent is the shared history\n    $ test\n    $ git push\n    ... go back and repeat ...\n\nThe resulting history may look like this:\n\n                  \\\n    ---A---B---C---D---M\n        \\             /\n         O---O---O---O      mywork\n\nwhere A, B, C, D are the commits others made and published to the\ncentral shared repository (i.e. the shared project history).  A is\nwhere the 'master' of the shared central repository was when you\ncloned and forked your \"mywork\" branch at.  O are commits you made\non your \"side branch\".\n\nBy checking out your \"master\" and runnig \"pull --ff-only\", you would\nbe checking out D to your working tree, and merging your work on the\nside branch to record M, which is what you publish and what becomes\nthe tip of the shared history.  By following the first parent chain\nstarting at M, you can see that a single unit of your work (the goal\nyou wanted to achieve on your \"mywork\" branch), which consists of 4\ncommits, was merged into the shared history at M, and before that,\nsomebody else integrated his work at D, and so on.\n\nNote that the last push may race with other people and fail due to\nnon fast-forward.  In such a case, you have two possibilities.  An\neasier way that violates the \"first parent\" principle for a short\nwhile is to do this:\n\n    $ git pull ;# may conflict and need resolution\n    $ test\n    $ git push\n\nThe resulting history may look like this:\n\n                     E---F\n                  \\ /     \\\n    ---A---B---C---D---M---X\n        \\             /\n         O---O---O---O      mywork\n\nwhere E and F happened at the shared central repository while you\nwere resolving merge M and testing the result.  You pulled these\nchanges and integrated into your history to create X, so the first\nparent of X becomes M and you would end up treating E and F as if\nthey happened on a side branch, even though they are what people may\nconsider the \"mainline\" of the the shared project history.\n\nIf you are a purist, you could instead do this when \"git push\" is\nrejected in the original sequence:\n\n    $ git reset --hard HEAD^ ;# cancel the merge of mywork\n    $ git pull --ff-only ;# get the updated tip of shared history\n    $ git merge mywork\n    $ test\n    $ git push\n\nwhich will result in a history like this:\n\n                     E---F---M'\n                  \\ /       /\n    ---A---B---C---D---M   /\n        \\             /   / \n         O---O---O---O---   mywork\n\nYou abandon merge M (\"reset --hard HEAD^\" would take you back to D),\nupdate from the central repository again to be at F, and then merge\nyour work (the same O--O--O--O) into it to create a new merge M',\nand make that the tip of the shared history by pushing it.  Again,\nfollowing the first parent chain starting from M', the history can\nbe summarized as a series of merges of completed topics into the\nshared history.  It is a judgement call if this is worth it (I\npersonally do not think it is, but others may disagree).\n"},{"id":"186384","messageId":"20120308071403.GE7643@sigill.intra.peff.net","threadId":"29867","inReplyTo":"7vty1zfwmd.fsf@alter.siamese.dyndns.org","subject":"Re: who's on first? - following first parent and merge-management","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-03-08T07:14:03Z","receivedAt":"2012-03-08T07:14:03Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Mar 07, 2012 at 10:13:46PM -0800, Junio C Hamano wrote:\n\n> If you are a purist, you could instead do this when \"git push\" is\n> rejected in the original sequence:\n> \n>     $ git reset --hard HEAD^ ;# cancel the merge of mywork\n>     $ git pull --ff-only ;# get the updated tip of shared history\n>     $ git merge mywork\n>     $ test\n>     $ git push\n\nThis gave me an idea that I think is probably crazy, but that I hadn't\nseen mentioned before.\n\nWhat if the user could specify a partial ordering of refs, and we used\nthat order when listing merge parents in the resulting commit. So for\nexample, if you said that:\n\n  refs/remotes/origin/master > refs/heads/master\n\nthen doing:\n\n  $ git checkout master\n  $ git pull origin master\n\nwould result in a \"flipped\" merge commit, with origin/master as the\nfirst parent, and master as the second. That makes the CVS-style\ncentral workflow (i.e. \"oops, somebody else pushed, I'll just pull &&\npush\") follow the first-parent flow that people expect.\n\nYou could extend it to topic branches, too (\"refs/heads/master >\nrefs/heads/jk/*\"). Of course, depending on your workflow, you might\n_want_ to have them flipped. I.e., when it is not just laziness or lack\nof understanding, and you really are making a merge commit to say \"topic\nXYZ depends on something that is now in master, so let's merge that in\nbefore continuing topic development\".\n\nSo I think the primary audience would be people doing clueless\ncentralized-repo development. Of course you'd perhaps want to flip the\nmerge message, too. And I do think people are overly-interested in\n--first-parent in the first place, so the effort of specifying the\nparent ordering like this is probably not worth it.\n\nI think when people ask about --first-parent, what they really want to\nsay is \"what happened on branch X, and what happened on this other\nbranch\". I wonder if we would do better to annotate the ref name of each\nside of the merge, and then people could follow a particular ref through\nhistory if they felt like it. That feels very un-git, as the DAG\nfundamentally does not care about the ref names. On the other hand,\npeople do care, and we actually do have that information already in our\nstock merge commit messages\n\nWhat if we had something like \"git log --follow-branch=master\", and it\nwas implemented something like:\n\n  if commit has no parents\n    add nothing to traversal\n  else if commit has one parent\n    consider parent for traversal (subject to usual UNINTERESTING, etc)\n  else\n    match commit message against /Merge branch '(.*)'( into (.*))?/\n    if $2 is empty, then set $2 to 'master'\n    if $1 is 'master', add parent 2 to traversal\n    if $2 is 'master', add parent 1 to traversal\n\nIOW, mine the commit messages to make a guess about the original state.\nI wonder how well it would work in practice. Git lets you do funny\nthings like merge on a detached HEAD and assign the result to a ref.\nThat may give you an odd merge message, but that's OK, because nothing\nis parsing it. But it would break a traversal like this.\n\nLike I said, I think these probably crazy ideas, but they were\ninteresting enough to me to think through. Maybe they will inspire\nsomething not-crazy from somebody else. :)\n\n-Peff\n"},{"id":"186387","messageId":"7v8vjbfspu.fsf@alter.siamese.dyndns.org","threadId":"29867","inReplyTo":"20120308071403.GE7643@sigill.intra.peff.net","subject":"Re: who's on first? - following first parent and merge-management","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-08T07:38:05Z","receivedAt":"2012-03-08T07:38:05Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> This gave me an idea that I think is probably crazy, but that I hadn't\n> seen mentioned before.\n> ...\n> You could extend it to topic branches, too (\"refs/heads/master >\n> refs/heads/jk/*\"). Of course, depending on your workflow, you might\n> _want_ to have them flipped. I.e., when it is not just laziness or lack\n> of understanding, and you really are making a merge commit to say \"topic\n> XYZ depends on something that is now in master, so let's merge that in\n> before continuing topic development\".\n\nIt certainly is *fun* to think about, and in a way it is sort-of in\nline at least in spirit with the -m option to the \"revert\" command\nto give the user run-time control over the order of the parents when\ncreating a new merge commit object.\n\nBut I agree that people are overly and needlessly interested in\nfirst parenthood.\n\n> So I think the primary audience would be people doing clueless\n> centralized-repo development. Of course you'd perhaps want to flip the\n> merge message, too. And I do think people are overly-interested in\n> --first-parent in the first place, so the effort of specifying the\n> parent ordering like this is probably not worth it.\n\nAs I already said in my first message in this thread, using shared\ncentral repository workflow does not make one a bad person, let\nalone clueless.  It just means that the first parenthood is not a\nsuitable tool for summarlizing their histories, and there are more\nsuitable ones such as shortlog that would apply equally well to all\nworkflows regardless of the parent order.\n"},{"id":"186388","messageId":"20120308074911.GA23712@burratino","threadId":"29867","inReplyTo":"7vty1zfwmd.fsf@alter.siamese.dyndns.org","subject":"Re: who's on first? - following first parent and merge-management","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2012-03-08T07:49:11Z","receivedAt":"2012-03-08T07:49:11Z","isPatch":false,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi all,\n\nJunio C Hamano wrote:\n\n> Given the above definition, the first thing to realize is that \"the\n> first parent\" is primarily a local concept.\n[... and much nice explanation ...]\n\nWould you mind including this explanation as a new file with some name\nlike <Documentation/howto/using-first-parent.txt>?  I think the quoted\nexplanation is very clear and I have not come up with any obvious\ntweaks to make to it, which is why I am simply suggesting this instead\nof sending a patch that would repeat the same text.\n\nStrawman abstract:\n\n| From: Junio C Hamano <gitster@pobox.com>\n| Date: Wed, 07 Mar 2012 22:13:46 -0800\n| Subject: who's on first? - following first parent and merge-management\n| Abstract: In this article, JC describes the \"log --first-parent\" and\n|  \"merge --no-ff\" options and what kind of history makes them useful.\n\nHm?\nJonathan\n"},{"id":"186389","messageId":"4F5867D4.1010904@viscovery.net","threadId":"29867","inReplyTo":"20120308071403.GE7643@sigill.intra.peff.net","subject":"Re: who's on first? - following first parent and merge-management","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2012-03-08T08:03:32Z","receivedAt":"2012-03-08T08:03:32Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 3/8/2012 8:14, schrieb Jeff King:\n> What if the user could specify a partial ordering of refs, and we used\n> that order when listing merge parents in the resulting commit. So for\n> example, if you said that:\n> \n>   refs/remotes/origin/master > refs/heads/master\n> \n> then doing:\n> \n>   $ git checkout master\n>   $ git pull origin master\n> \n> would result in a \"flipped\" merge commit, with origin/master as the\n> first parent, and master as the second.\n\nI have wished for such a thing several times already.\n\nIt happens when I have a topic with changes that trigger a complete\nrebuild of the project. When I merge it to master, I have to\n\n   # on topic\n   git checkout master   #1\n   git merge topic       #2\n\n#1 triggers a rebuild, but I don't do a build. Then #2 again triggers a\nrebuild, but in reality the only changes since the last build are those\nfrom master since the topic forked (no, I can't use ccache).\n\nTo avoid the situation, I jump through hoops by preparing an index and\nworktree with the merge result while I am on topic:\n\n   # on topic\n   git checkout --detach\n   git merge master      # triggers rebuild of only master's changes\n   # merge result ready; carry it over to master and repeat the merge\n   git reset --soft master\n   git checkout master\n   git merge topic       # fails if content merge is necessary\n   git checkout master -- file/needing/content/merge # (*)\n   git merge topic       # now succeeds\n\nThis would not be necessary if the order of the merge parents could be\nspecified, e.g.:\n\n   # on topic\n   git merge --into master\n\n(*) Jumping through these hoops make sense only if\nfile/needing/content/merge is _not_ the one that triggers the complete\nrebuild.\n\n-- Hannes\n"},{"id":"186465","messageId":"7vpqcndmpa.fsf@alter.siamese.dyndns.org","threadId":"29867","inReplyTo":"4F5867D4.1010904@viscovery.net","subject":"Re: who's on first? - following first parent and merge-management","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-08T17:30:57Z","receivedAt":"2012-03-08T17:30:57Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j.sixt@viscovery.net> writes:\n\n> I have wished for such a thing several times already.\n>\n> It happens when I have a topic with changes that trigger a complete\n> rebuild of the project. When I merge it to master, I have to\n>\n>    # on topic\n>    git checkout master   #1\n>    git merge topic       #2\n>\n> #1 triggers a rebuild, but I don't do a build. Then #2 again triggers a\n> rebuild, but in reality the only changes since the last build are those\n> from master since the topic forked (no, I can't use ccache).\n>\n> To avoid the situation,...\n> This would not be necessary if the order of the merge parents could be\n> specified, e.g.:\n>\n>    # on topic\n>    git merge --into master\n\nI think the underlying mechanism needed to implement the above\nshares a lot with what Jeff called \"crazy idea\", but where you would\nwant to be after such a merge may be different in these two cases.\n\nWith the \"crazy idea\", you merge the other branch that happened to\nbe the mainline into your work in reverse. You would explain such a\nmerge as \"I am merging early part of my topic that will eventually\ndo X to mainline now, to make later conflict resolution easier, even\nthough it is not yet complete\" or something like that, and you will\ncontinue working on your topic starting from the resulting merge.\nThe real project mainline will not be updated with this merge until\nthe topic is complete (in other words, you do not push).\n\nI have a feeling that your \"git merge-to master\" may be different.\nYou may explain the resulting commit as \"This topic is complete for\nnow and is ready for master\", and the master gets updated with the\nresult, but you may want to keep \"topic\" free of unrelated random\nother development that happened on \"master\" since they diverged.\nThat way, \"topic\" can further be polished and you will leave the\ndoor open to merge it down to even older releases than \"master\".\n"},{"id":"186508","messageId":"7vaa3qbt9e.fsf@alter.siamese.dyndns.org","threadId":"29867","inReplyTo":"20120308074911.GA23712@burratino","subject":"Re: who's on first? - following first parent and merge-management","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-08T22:52:13Z","receivedAt":"2012-03-08T22:52:13Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n> Junio C Hamano wrote:\n>\n>> Given the above definition, the first thing to realize is that \"the\n>> first parent\" is primarily a local concept.\n> [... and much nice explanation ...]\n>\n> Would you mind including this explanation as a new file with some name\n> like <Documentation/howto/using-first-parent.txt>?  I think the quoted\n> explanation is very clear and I have not come up with any obvious\n> tweaks to make to it, which is why I am simply suggesting this instead\n> of sending a patch that would repeat the same text.\n>\n> Strawman abstract:\n>\n> | From: Junio C Hamano <gitster@pobox.com>\n> | Date: Wed, 07 Mar 2012 22:13:46 -0800\n> | Subject: who's on first? - following first parent and merge-management\n> | Abstract: In this article, JC describes the \"log --first-parent\" and\n> |  \"merge --no-ff\" options and what kind of history makes them useful.\n\nEverything I write here is open source, so in that sense I wouldn't\nmind, but I have a suspicion that building on existing gitworkflows\ndocument might be more appropriate, as opposed to a self-contained\nstandalone document that has to be read by readers in addition to\nthe other existing documents.  The current gitworkflows document is\ndetailed in describing how the history is built, but is fairly\nlacking in description on how the resulting history can be studied.\n"},{"id":"186558","messageId":"4F59F212.6030701@ira.uka.de","threadId":"29867","inReplyTo":"7vpqcndmpa.fsf@alter.siamese.dyndns.org","subject":"Re: who's on first? - following first parent and merge-management","fromName":"Holger Hellmuth","fromEmail":"hellmuth@ira.uka.de","sentAt":"2012-03-09T12:05:38Z","receivedAt":"2012-03-09T12:05:38Z","isPatch":false,"sender":{"key":"hellmuth@ira.uka.de","avatar":null},"body":"On 08.03.2012 18:30, Junio C Hamano wrote:\n> Johannes Sixt<j.sixt@viscovery.net>  writes:\n>> To avoid the situation,...\n>> This would not be necessary if the order of the merge parents could be\n>> specified, e.g.:\n>>\n>>     # on topic\n>>     git merge --into master\n>\n> I think the underlying mechanism needed to implement the above\n> shares a lot with what Jeff called \"crazy idea\", but where you would\n> want to be after such a merge may be different in these two cases.\n\nI don't think there is much question that you should still be in the \nsame branch. Not because you necessarily want to be in that branch. But \nbecause it would be surprising if git-merge changed your branch \nsometimes and most times not.\n"},{"id":"186560","messageId":"4F59F7A2.3030606@viscovery.net","threadId":"29867","inReplyTo":"4F59F212.6030701@ira.uka.de","subject":"Re: who's on first? - following first parent and merge-management","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2012-03-09T12:29:22Z","receivedAt":"2012-03-09T12:29:22Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 3/9/2012 13:05, schrieb Holger Hellmuth:\n> On 08.03.2012 18:30, Junio C Hamano wrote:\n>> Johannes Sixt<j.sixt@viscovery.net>  writes:\n>>> To avoid the situation,...\n>>> This would not be necessary if the order of the merge parents could be\n>>> specified, e.g.:\n>>>\n>>>     # on topic\n>>>     git merge --into master\n>>\n>> I think the underlying mechanism needed to implement the above\n>> shares a lot with what Jeff called \"crazy idea\", but where you would\n>> want to be after such a merge may be different in these two cases.\n> \n> I don't think there is much question that you should still be in the same\n> branch. Not because you necessarily want to be in that branch. But because\n> it would be surprising if git-merge changed your branch sometimes and most\n> times not.\n\nI don't think that it is so clear-cut. And for this reason, I would even\ngo as far as to suggest that you should end up with a detached HEAD.\n\nBefore the merge we have this situation:\n\n--o--o--o--o      <- master\n   \\\n    o--o--o--X    <- topic\n\nThe result of 'git merge --into master' must advance branch master by the\nmerge commit (I think there is no doubt about this):\n\n--o--o--o--o---M  <- master\n   \\          /\n    o--o--o--X    <- topic\n\nAlso, the index and worktree must match M (no doubt, either, IMO). But\nwhat does HEAD refer to? I see three possibilities:\n\n1. master; as you say, this may be surprising if we were on topic before\nthe branch.\n\n2. topic; but then the index would be dirty because it does not match X.\n\n3. M, i.e. a detached HEAD; this is just a compromise and a fat warning at\nthe end of the merge output would be necessary that instructs the user to\ncheckout a suitable branch.\n\nNow that I have tossed around these ideas, there's another caveat: What if\nthe merge fails due to a conflict? After the conflicts were resolved, 'git\ncommit' is needed to complete the merge. But this would create the commit\nwhere HEAD points to. IOW, we have to chose option 1 so that the merge\ncommit advances master.\n\nWould this be less surprising if the option were named --checkout-into?\n\n-- Hannes\n"},{"id":"186562","messageId":"4F5A04BA.8030401@ira.uka.de","threadId":"29867","inReplyTo":"4F59F7A2.3030606@viscovery.net","subject":"Re: who's on first? - following first parent and merge-management","fromName":"Holger Hellmuth","fromEmail":"hellmuth@ira.uka.de","sentAt":"2012-03-09T13:25:14Z","receivedAt":"2012-03-09T13:25:14Z","isPatch":false,"sender":{"key":"hellmuth@ira.uka.de","avatar":null},"body":"On 09.03.2012 13:29, Johannes Sixt wrote:\n> Am 3/9/2012 13:05, schrieb Holger Hellmuth:\n>> On 08.03.2012 18:30, Junio C Hamano wrote:\n>>> Johannes Sixt<j.sixt@viscovery.net>   writes:\n>>>> To avoid the situation,...\n>>>> This would not be necessary if the order of the merge parents could be\n>>>> specified, e.g.:\n>>>>\n>>>>      # on topic\n>>>>      git merge --into master\n>>>\n>>> I think the underlying mechanism needed to implement the above\n>>> shares a lot with what Jeff called \"crazy idea\", but where you would\n>>> want to be after such a merge may be different in these two cases.\n>>\n>> I don't think there is much question that you should still be in the same\n>> branch. Not because you necessarily want to be in that branch. But because\n>> it would be surprising if git-merge changed your branch sometimes and most\n>> times not.\n>\n> I don't think that it is so clear-cut. And for this reason, I would even\n> go as far as to suggest that you should end up with a detached HEAD.\n>\n> Before the merge we have this situation:\n>\n> --o--o--o--o<- master\n>     \\\n>      o--o--o--X<- topic\n>\n> The result of 'git merge --into master' must advance branch master by the\n> merge commit (I think there is no doubt about this):\n>\n> --o--o--o--o---M<- master\n>     \\          /\n>      o--o--o--X<- topic\n>\n> Also, the index and worktree must match M (no doubt, either, IMO). But\n> what does HEAD refer to? I see three possibilities:\n\nI see we have different ideas. I envisioned --into to be the equivalent of\ngit checkout master\ngit merge topic\ngit checkout topic\n\nand in that case index and worktree would be topic naturally.\n\nBut your caveat below would be even more problematic in this case.\n\n> 1. master; as you say, this may be surprising if we were on topic before\n> the branch.\n>\n> 2. topic; but then the index would be dirty because it does not match X.\n>\n> 3. M, i.e. a detached HEAD; this is just a compromise and a fat warning at\n> the end of the merge output would be necessary that instructs the user to\n> checkout a suitable branch.\n>\n> Now that I have tossed around these ideas, there's another caveat: What if\n> the merge fails due to a conflict? After the conflicts were resolved, 'git\n> commit' is needed to complete the merge. But this would create the commit\n> where HEAD points to. IOW, we have to chose option 1 so that the merge\n> commit advances master.\n>\n> Would this be less surprising if the option were named --checkout-into?\n\nDon't think so. It would make it clear where you end up but it would \nmuddle/hide the original purpose of the parameter. \"git merge --into \nxxx\" sounds like a real sentence (Larry Wall would approve ;-).\n\nGuess we would have to rely on the documentation to make it clear that a \nbranch switch happens. And a message \"Changing to branch xxx\" on STDOUT \nwouldn't hurt either.\n"},{"id":"186571","messageId":"7vfwdh7nba.fsf@alter.siamese.dyndns.org","threadId":"29867","inReplyTo":"4F5A04BA.8030401@ira.uka.de","subject":"Re: who's on first? - following first parent and merge-management","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-09T16:26:33Z","receivedAt":"2012-03-09T16:26:33Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Holger Hellmuth <hellmuth@ira.uka.de> writes:\n\n> On 09.03.2012 13:29, Johannes Sixt wrote:\n>> Am 3/9/2012 13:05, schrieb Holger Hellmuth:\n>>> On 08.03.2012 18:30, Junio C Hamano wrote:\n>>>> Johannes Sixt<j.sixt@viscovery.net>   writes:\n>>>> ...\n>>>> I think the underlying mechanism needed to implement the above\n>>>> shares a lot with what Jeff called \"crazy idea\", but where you would\n>>>> want to be after such a merge may be different in these two cases.\n>>>\n>>> I don't think there is much question that you should still be in the same\n>>> branch. Not because you necessarily want to be in that branch. But because\n>>> it would be surprising if git-merge changed your branch sometimes and most\n>>> times not.\n>>\n>> I don't think that it is so clear-cut.\n>> ...\n> I see we have different ideas. I envisioned --into to be the equivalent of\n> git checkout master\n> git merge topic\n> git checkout topic\n>\n> and in that case index and worktree would be topic naturally.\n\nThat is why I rewrote it to \"git merge-to master\" in my response,\nand said that there are two slightly different workflow ingredients\nthat can be implemented with a similar mechanism.\n"}]}