{"thread":{"id":"18988","subject":"How to merge from newer branch to older branches?","startedAt":"2009-04-21T19:24:26Z","lastAt":"2009-04-22T21:17:10Z","messageCount":9,"participants":["skillzero@gmail.com","Jeff King","John M. Dlugosz","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"111899","messageId":"2729632a0904211224x6e2621caxf6c169d90b760530@mail.gmail.com","threadId":"18988","inReplyTo":null,"subject":"How to merge from newer branch to older branches?","fromName":"","fromEmail":"skillzero@gmail.com","sentAt":"2009-04-21T19:24:26Z","receivedAt":"2009-04-21T19:24:26Z","isPatch":false,"sender":{"key":"skillzero@gmail.com","avatar":null},"body":"I'm not sure how to merge a topic branch onto multiple branches\nwithout conflicts or unwanted changes. My workflow probably isn't\nideal, but I often run into cases like this and wondered if there's a\nway to solve it with git.\n\nWe have a \"future\" branch for new development. I wanted to add a new\nfeature so I branched from \"future\" to create a branch named\n\"feature\". I completed the work, but now they've decided they need\nthat on two older branches. It looks like this:\n\nfuture o-o-o-o-o-o-o\n        \\   \\       \\\n1.2          o-o-o   \\\n          \\           \\\n1.1        o-o-o       \\\n                        \\\nfeature                  o-o-o\n                         a b c\n\nI've read I should have started from the oldest common denominator\nbranch that I might ever want, but at the time I created the branch,\n\"future\" was it because we thought 1.1 and 1.2 were locked down and\nnot going to add new features. But things change and I need to roll my\nfeature into 1.1 and 1.2.\n\nWhat's the best way to merge changes on the \"feature\" branch into the\n1.1 and 1.2 branches? If I try to checkout 1.1 then 'git merge\nfeature', it (obviously) merges in a bunch of changes from \"future\"\nthat I don't want (and has a bunch of conflicts). I also tried just\ncherry-picking commits a, b, and c from the \"feature\" branch. That\nmostly worked, but there were some surprising conflicts. Text that had\nbeen inserted into a couple files (which had been untouched in 1.1 and\n1.2) caused a conflict when it seemed like it should have just added\nthe lines without conflict. I realize it's difficult to know why it\nconflicted without seeing the changes, but I'm just asking in a more\ngeneral way how I should be doing merges like this.\n\nIs cherry-picking the best way? It seems pretty tedious because I have\nto do each commit in reverse order (although I could script it). I was\nhoping there was a way to say \"apply all the changes from when\n\"feature\" branched up to its tip\". I would also like to preserve the\ncommit history rather than just making making one big commit of all\nthe changes.\n"},{"id":"111901","messageId":"20090421193615.GB7832@coredump.intra.peff.net","threadId":"18988","inReplyTo":"2729632a0904211224x6e2621caxf6c169d90b760530@mail.gmail.com","subject":"Re: How to merge from newer branch to older branches?","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-04-21T19:36:15Z","receivedAt":"2009-04-21T19:36:15Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Apr 21, 2009 at 12:24:26PM -0700, skillzero@gmail.com wrote:\n\n> We have a \"future\" branch for new development. I wanted to add a new\n> feature so I branched from \"future\" to create a branch named\n> \"feature\". I completed the work, but now they've decided they need\n> that on two older branches. It looks like this:\n> [...]\n> I've read I should have started from the oldest common denominator\n> branch that I might ever want, but at the time I created the branch,\n\nRight. Junio branches all topics in git from \"master\", but then merges\npromising ones into \"next\". When the topic is ready for master, he can\nthen just merge the topic branch, pulling in that topic but not the rest\nof next.\n\n> \"future\" was it because we thought 1.1 and 1.2 were locked down and\n> not going to add new features. But things change and I need to roll my\n> feature into 1.1 and 1.2.\n\nYep. Advanced planning is not always possible. :)\n\n> What's the best way to merge changes on the \"feature\" branch into the\n> 1.1 and 1.2 branches? If I try to checkout 1.1 then 'git merge\n\nIf it is just one or two commits, you probably just want to \"git\ncherry-pick\" them onto your older branches.\n\nIf it is a larger series, or one which might see more development, you\nmight want to use \"git rebase\" to rewrite the branch as if it were based\non 1.1, and then merge that into 1.1, 1.2, and feature.\n\n> feature', it (obviously) merges in a bunch of changes from \"future\"\n> that I don't want (and has a bunch of conflicts). I also tried just\n> cherry-picking commits a, b, and c from the \"feature\" branch. That\n> mostly worked, but there were some surprising conflicts. Text that had\n> been inserted into a couple files (which had been untouched in 1.1 and\n> 1.2) caused a conflict when it seemed like it should have just added\n> the lines without conflict. I realize it's difficult to know why it\n> conflicted without seeing the changes, but I'm just asking in a more\n> general way how I should be doing merges like this.\n\nYes, without seeing the conflicts it's hard to say. But presumably the\nadded lines provide context, so git was having a hard time trying to\nfigure out where in the old file your changes would go (you can think of\ncherry-pick as the moral equivalent of \"git show $COMMIT | git apply\";\nso you are basically applying a patch on top of something that it is\nnot quite the same).\n\nIf you are having trouble resolving conflicts, you might try using \"git\nmergetool\" to fire up an external resolver that may provide a richer\ninterface (I use xxdiff with mergetool, myself).\n\n> Is cherry-picking the best way? It seems pretty tedious because I have\n> to do each commit in reverse order (although I could script it). I was\n> hoping there was a way to say \"apply all the changes from when\n> \"feature\" branched up to its tip\". I would also like to preserve the\n> commit history rather than just making making one big commit of all\n> the changes.\n\nIn its simplest form, rebase is basically cherry-picking a series of\ncommits. So that would make things a bit less tedious for you, but you\nwill probably still end up with the same set of conflicts.\n\n-Peff\n"},{"id":"111917","messageId":"gsm7fm$q31$1@ger.gmane.org","threadId":"18988","inReplyTo":"2729632a0904211224x6e2621caxf6c169d90b760530@mail.gmail.com","subject":"Re: How to merge from newer branch to older branches?","fromName":"John M. Dlugosz","fromEmail":"ngnr63q02@sneakemail.com","sentAt":"2009-04-22T04:46:32Z","receivedAt":"2009-04-22T04:46:32Z","isPatch":false,"sender":{"key":"ngnr63q02@sneakemail.com","avatar":null},"body":"skillzero@gmail.com wrote:\n> \n> future o-o-o-o-o-o-o\n>         \\   \\       \\\n> 1.2          o-o-o   \\\n>           \\           \\\n> 1.1        o-o-o       \\\n>                         \\\n> feature                  o-o-o\n>                          a b c\n> \n> Is cherry-picking the best way? It seems pretty tedious because I have\n> to do each commit in reverse order (although I could script it). I was\n> hoping there was a way to say \"apply all the changes from when\n> \"feature\" branched up to its tip\". I would also like to preserve the\n> commit history rather than just making making one big commit of all\n> the changes.\n\nI think any other command that \"just\" moves those deltas would be the exact equivalent of \ncherry picking in terms of the conflicts it sees.\n\nYou can, however, collapse a,b,c into one commit and pick that into each place it is \nneeded, calling it a good comment for the whole feature.  That might be more difficult to \nmerge than doing one at a time, but if not, and the whole string is tedious (i.e. 50 \ninstead of 3, mostly incremental typo fixes and stuff) I can see the benefit of making it \na gestalt.\n\nFurthermore... (thinking out loud)... the conflicts are caused by things after the other \nbranches, right?  After you do the resolving for (say) 1.2, then instead of picking a,b,c \nagain (with the same merge issues), pick the one you put onto 1.2 already.  Work your way \nthat way from branches that came off nearest to the original feature, back down toward the \n  root.  Each time pick the one you just planted, because it already contains merges part \nway down.  Then you only have to deal with the changes between those two branches.\n\nSo that's what I'd do:  pick a, b, and c onto the most recient other branch (1.2 in your \ndrawing), fixing merge as I go.  Then reset mixed back to the original tip before the \npicks, and commit everything with a good name for the feature.  Then, pick that onto the \nnext newest branch (1,1 in your drawing), etc.\n\n--John\n"},{"id":"111922","messageId":"7vmya946fg.fsf@gitster.siamese.dyndns.org","threadId":"18988","inReplyTo":"20090421193615.GB7832@coredump.intra.peff.net","subject":"Re: How to merge from newer branch to older branches?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-04-22T05:13:23Z","receivedAt":"2009-04-22T05:13:23Z","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> On Tue, Apr 21, 2009 at 12:24:26PM -0700, skillzero@gmail.com wrote:\n>\n>> We have a \"future\" branch for new development. I wanted to add a new\n>> feature so I branched from \"future\" to create a branch named\n>> \"feature\". I completed the work, but now they've decided they need\n>> that on two older branches. It looks like this:\n>> [...]\n>> I've read I should have started from the oldest common denominator\n>> branch that I might ever want, but at the time I created the branch,\n>\n> Right. Junio branches all topics in git from \"master\", but then merges\n> promising ones into \"next\". When the topic is ready for master, he can\n> then just merge the topic branch, pulling in that topic but not the rest\n> of next.\n\nNo, I don't.\n\nI often branch from somewhere older than 'master', often tip from 'maint'\nsometimes even older.  And that is not necessarily because I am better\nthan other people in planning ahead.  There are branches that forked from\nolder series (like 1.6.0.X) that are merged to next and then master,\nwithout ever getting merged to produce 1.6.0.(X+1).\n\n> Yep. Advanced planning is not always possible. :)\n>\n>> What's the best way to merge changes on the \"feature\" branch into the\n>> 1.1 and 1.2 branches? If I try to checkout 1.1 then 'git merge\n>\n> If it is just one or two commits, you probably just want to \"git\n> cherry-pick\" them onto your older branches.\n\nI would suggest against it.  Just like you did not manage to plan in\nadvance for these two patches to fork from older branches, you will regret\nlater that these two were still full of bugs and need to be fixed up with\nmore patches on top.  Even if they are only a few right now, keeping a\ncleaned up series that applies to the oldest would be easier to manage in\nthe long run.\n\nI.e., rebase feature onto somewhere older (like 1.1):\n\n\tgit rebase --onto v1.1 feature~2 feature\n\nthen let q&a people merge that to v1.1 and v1.2, while keeping the tip of\nthe feature still open.  You will queue further fix-ups on that branch and\ntell q&a people to merge again to get the fixed to the feature.\n"},{"id":"111945","messageId":"20090422133434.GA11530@coredump.intra.peff.net","threadId":"18988","inReplyTo":"7vmya946fg.fsf@gitster.siamese.dyndns.org","subject":"Re: How to merge from newer branch to older branches?","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-04-22T13:34:35Z","receivedAt":"2009-04-22T13:34:35Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Apr 21, 2009 at 10:13:23PM -0700, Junio C Hamano wrote:\n\n> > Right. Junio branches all topics in git from \"master\", but then merges\n> > promising ones into \"next\". When the topic is ready for master, he can\n> > then just merge the topic branch, pulling in that topic but not the rest\n> > of next.\n> \n> No, I don't.\n> \n> I often branch from somewhere older than 'master', often tip from 'maint'\n> sometimes even older.  And that is not necessarily because I am better\n> than other people in planning ahead.  There are branches that forked from\n> older series (like 1.6.0.X) that are merged to next and then master,\n> without ever getting merged to produce 1.6.0.(X+1).\n\nSure, but I assumed a new topic that came in would get branched from\n'master', since that is presumably what the person developing it based\nit on. Is that not true?\n\nThat is also what is in Documentation/howto/maintain-git.txt:\n\n   - Anything unobvious that is applicable to 'master' (in other\n     words, does not depend on anything that is still in 'next'\n     and not in 'master') is applied to a new topic branch that\n     is forked from the tip of 'master'.  This includes both\n     enhancements and unobvious fixes to 'master'.  A topic\n     branch is named as ai/topic where \"ai\" is typically\n     author's initial and \"topic\" is a descriptive name of the\n     topic (in other words, \"what's the series is about\").\n\n   - An unobvious fix meant for 'maint' is applied to a new\n     topic branch that is forked from the tip of 'maint'.  The\n     topic is named as ai/maint-topic.\n\n-Peff\n"},{"id":"111970","messageId":"2729632a0904221044q20e6cabau7dd06b3020a8ce49@mail.gmail.com","threadId":"18988","inReplyTo":"7vmya946fg.fsf@gitster.siamese.dyndns.org","subject":"Re: How to merge from newer branch to older branches?","fromName":"","fromEmail":"skillzero@gmail.com","sentAt":"2009-04-22T17:44:06Z","receivedAt":"2009-04-22T17:44:06Z","isPatch":false,"sender":{"key":"skillzero@gmail.com","avatar":null},"body":"Based on the help from this discussion and the rebase documenation,\nwhat I ended up doing that seemed to require the fewest conflicts is\nto use git merge-base to find the merge-base of master and 1.1 (the\noldest branch I wanted the feature) then I found the commit\nimmediately before the first commit on the feature branch (feature~3\nin this case or commit a^). Then I rebased feature:\n\ngit rebase --onto merge-base-of-1.1-and-master feature-before-first feature\n\nTurning this (hopefully not mangled by gmail):\n\nfuture o-o-o-o-o-o-o\n        \\   \\       \\\n1.2      \\   o-o-o   \\\n          \\           \\\n1.1        o-o-o       \\\n                        \\\nfeature                  o-o-o\n                         a b c\n\ninto this:\n\nfuture  o-o-o-o-o-o-o\n        |\\   \\\n1.2     | \\   o-o-o\n        |  \\\n1.1     |   o-o-o\n         \\\nfeature   o-o-o\n          a b c\n\nI can merge 'feature' into 1.1, 1.2, etc. then theoretically, I should\nbe able to apply bug fixes to 'feature' later and re-merge into 1.1,\n1.2, etc. to pick up just the bug fixes, right?\n\nWhen I merged 'feature' into 'v1.1', it resulted in the same conflicts\nI originally ran into when cherry-picking, but when I looked at it, I\nrealized this was because I had manually integrated some changes into\n1.1 from master (I'm trying to move our tree from CVS to git so I had\nto manually move in some stuff from CVS instead of doing a proper git\nmerge).\n\nIt seems like this merge conflict is going to cause problems if I try\nto re-merge to pick up a bug fix to 'feature' in the future. Looking\nat the documentation, it sounds like 'git rerere' can help by\nre-applying the manual conflict resolution I did?\n\nBTW...Is there a way to find the first commit of a branch? I had to\njust look at the log manually to see what I remembered to be the first\ncommit.\n"},{"id":"111999","messageId":"20090422201541.GC14146@coredump.intra.peff.net","threadId":"18988","inReplyTo":"2729632a0904221044q20e6cabau7dd06b3020a8ce49@mail.gmail.com","subject":"Re: How to merge from newer branch to older branches?","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-04-22T20:15:41Z","receivedAt":"2009-04-22T20:15:41Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Apr 22, 2009 at 10:44:06AM -0700, skillzero@gmail.com wrote:\n\n> Then I rebased feature:\n> \n> git rebase --onto merge-base-of-1.1-and-master feature-before-first feature\n>\n> [...]\n> \n> I can merge 'feature' into 1.1, 1.2, etc. then theoretically, I should\n> be able to apply bug fixes to 'feature' later and re-merge into 1.1,\n> 1.2, etc. to pick up just the bug fixes, right?\n\nExactly.\n\n> It seems like this merge conflict is going to cause problems if I try\n> to re-merge to pick up a bug fix to 'feature' in the future. Looking\n> at the documentation, it sounds like 'git rerere' can help by\n> re-applying the manual conflict resolution I did?\n\nIt shouldn't. Remember that your merges into 1.1, 1.2, etc, created a\nnew merge base. So when you have bug fixes to make to this topic, you\ndon't put them on the \"feature\" branch, but onto this topic branch. Then\nyou re-merge the topic branch into 1.1., 1.2, feature, etc, and it will\nlook only at the new bugfix.\n\n> BTW...Is there a way to find the first commit of a branch? I had to\n> just look at the log manually to see what I remembered to be the first\n> commit.\n\nSort of. Branches in git are really just refs pointing to the tip of the\nbranch. So once the tip advances, the ref no longer remembers \"oh, this\nis where I branched from\". If there are other commits along the thing\nyou branched off of, you can calculate the merge-base of the thing you\nbranched from, and your branch.\n\nHowever, the first entry in the reflog for that branch ref should\nindicate branch creation (unless it is so old that it has expired).\nSomething like:\n\n  $ git branch foo origin/master\n  $ git reflog show foo\n  0be9bc0 foo@{0}: branch: Created from origin/master\n\nSo 0be9bc0 would be the creation point in this case. But you might have\ntotally rewritten the branch after that point, so 0be9bc0 might not be a\nuseful value anymore.\n\n-Peff\n"},{"id":"112008","messageId":"2729632a0904221401u43af69a5ncec0f3f274ad648f@mail.gmail.com","threadId":"18988","inReplyTo":"20090422201541.GC14146@coredump.intra.peff.net","subject":"Re: How to merge from newer branch to older branches?","fromName":"","fromEmail":"skillzero@gmail.com","sentAt":"2009-04-22T21:01:01Z","receivedAt":"2009-04-22T21:01:01Z","isPatch":false,"sender":{"key":"skillzero@gmail.com","avatar":null},"body":"On Wed, Apr 22, 2009 at 1:15 PM, Jeff King <peff@peff.net> wrote:\n>\n> On Wed, Apr 22, 2009 at 10:44:06AM -0700, skillzero@gmail.com wrote:\n>\n>> It seems like this merge conflict is going to cause problems if I try\n>> to re-merge to pick up a bug fix to 'feature' in the future. Looking\n>> at the documentation, it sounds like 'git rerere' can help by\n>> re-applying the manual conflict resolution I did?\n>\n> It shouldn't. Remember that your merges into 1.1, 1.2, etc, created a\n> new merge base. So when you have bug fixes to make to this topic, you\n> don't put them on the \"feature\" branch, but onto this topic branch. Then\n> you re-merge the topic branch into 1.1., 1.2, feature, etc, and it will\n> look only at the new bugfix.\n\nI'm not sure I understand. When I did the original rebase of \"feature\"\nonto the merge-base of all the branches I wanted to merge to (v1.1 and\nv1.2 in this case), the end result was that \"feature\" is now based on\nthe merge-base. When I merged \"feature\" into 1.1, I had to fix some\nconflicts so in the log I see my conflict fix commit then a merge\ncommit, but \"feature\" wasn't changed (only v1.1 was).\n\nI was thinking that if I find a bug in my original \"feature\" branch, I\nwould commit the fix to the \"feature\" branch then merge that into\nv1.1, v1.2, master, etc. But I was thinking that when I tried to merge\n\"feature\" into v1.1 (which previously needed a commit to fix\nconflicts), I'd need to re-fix those same conflicts.\n\nWhen I look at the log for v1.1 though, maybe I just misunderstood the\nway the conflicts are resolved in git? I was thinking the conflicting\nmerge would end up as one big commit that's a combination of the\n\"feature\"'s commits and my conflict fixes.\n\nBut in the log for v1.1, it looks like my conflict fixing commit may\nhave just \"fixed\" the v1.1 branch such that it could accept a\n\"feature\" merge without conflict. If that's true then a future merge\nof \"feature\" containing new commits should just merge without\nconflict. That would be awesome if that's the way conflicting\nresolving in git works.\n\n> However, the first entry in the reflog for that branch ref should\n> indicate branch creation (unless it is so old that it has expired).\n> Something like:\n>\n>  $ git branch foo origin/master\n>  $ git reflog show foo\n>  0be9bc0 foo@{0}: branch: Created from origin/master\n>\n> So 0be9bc0 would be the creation point in this case. But you might have\n> totally rewritten the branch after that point, so 0be9bc0 might not be a\n> useful value anymore.\n\nThanks, that shows what I need. For my case, it happened to be @{58}.\nIs there a way to reverse the order or a special syntax to say \"0 from\nthe end\"? Trying --reverse said \"cannot combine --reverse with\n--walk-reflogs\" and trying @{-1} show me something else.\n"},{"id":"112013","messageId":"20090422211710.GA16096@coredump.intra.peff.net","threadId":"18988","inReplyTo":"2729632a0904221401u43af69a5ncec0f3f274ad648f@mail.gmail.com","subject":"Re: How to merge from newer branch to older branches?","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-04-22T21:17:10Z","receivedAt":"2009-04-22T21:17:10Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Apr 22, 2009 at 02:01:01PM -0700, skillzero@gmail.com wrote:\n\n> I'm not sure I understand. When I did the original rebase of \"feature\"\n> onto the merge-base of all the branches I wanted to merge to (v1.1 and\n> v1.2 in this case), the end result was that \"feature\" is now based on\n\nErr, sorry, I was confusing your \"future\" branch and your \"feature\"\nbranch. Wherever I said \"feature\", I meant \"future\", and \"topic\" I meant\n\"feature\". Yikes.\n\nSo you would make bug-fixes on \"feature\", and then just re-merge it to\n1.1, 1.2, and future.\n\n> the merge-base. When I merged \"feature\" into 1.1, I had to fix some\n> conflicts so in the log I see my conflict fix commit then a merge\n> commit, but \"feature\" wasn't changed (only v1.1 was).\n\nRight. So now the merge-base between feature and 1.1 is the new merge\ncommit. And when you re-merge them, you will only look at things that\nhappened on the feature branch since that merge-base.\n\n> I was thinking that if I find a bug in my original \"feature\" branch, I\n> would commit the fix to the \"feature\" branch then merge that into\n> v1.1, v1.2, master, etc. But I was thinking that when I tried to merge\n> \"feature\" into v1.1 (which previously needed a commit to fix\n> conflicts), I'd need to re-fix those same conflicts.\n\nNope, because the merge commit already records the state of the tree\nonce those conflicts are fixed. Now it's possible that the _bugfix_ may\nhave its own conflicts. But you shouldn't see the same conflicts again.\n\n> When I look at the log for v1.1 though, maybe I just misunderstood the\n> way the conflicts are resolved in git? I was thinking the conflicting\n> merge would end up as one big commit that's a combination of the\n> \"feature\"'s commits and my conflict fixes.\n\nSort of.  It is a new commit with two parents: the previous tip of v1.1,\nand the tip of \"feature\". But its tree contains the state with all of\nv1.1, all of feature's commits, and your fixes.\n\n-Peff\n"}]}