Following up on Git: rebase onto development branch from upstream, basically the same ask as:
I have local
masteranddevelopbranches. I do all my work ondevelopand then merge them intomasterfor releases. There is a remote branch,upstream/masterwhich has changes I want, but I want to rebase my changes indevelop(which shares a common ancestor) on top of its changes and put them back intodevelop. I've already donegit fetch upstream.
Here is the (a bit more complicated/advanced) situation I'm facing with, starting from scratch.
- I forked an upstream, and made my own changes from its development branches (
dev/br-1), in my own new branch (dev/br-2), andgit pushto my own repo. - Now, upstream has advanced, both in its
masteranddevelopbranches. - The way upstream advanced its
developbranch is viarebase, i.e., all its own changes are put back on top after rebase. - My local repo is gone with my old machine, and I need to pick-up/git-clone from my own repo to continue with my customization.
- I want to rebase my changes in my
dev/br-2branch (which shares a common ancestor) on top of all the upstream changes. - I've already done
git fetch upstreamand was able to rebase mymasterwith upstream's. - It is how to rebase my current
dev/br-1from upstream, thendev/br-2fromdev/br-1branch that makes my head spinning nonstop.
Although it looks like a very specific case, but the principle of how to do git branching and rebasing still applies, and the answer would be very educational to the general public. Please help.
UPDATE: So I looked at @torek suggested git rebase --onto command, like How to git rebase a branch with the onto command?, and all their refed docs, and think my problem is still one or two levels up than what I've read (because there are two repos and 5 branches involved). Here is the summary:
Situation at point#1:
A---B---C---D master (upstream) \ E---F---G dev/br-1 (upstream) \ H---I---J dev/br-2 (myown) Situation at point#2&3:
A---B---C---D master (upstream) \ E'---F'---G' dev/br-1 (upstream) And I don't even know where should I draw my myown branch. Here is my current situation (which may have already been messed up, as I see HEAD might be in a weird place):
$ git log --all --decorate --oneline --graph * 7aec18c (upstream/dev/br-1) more updates * b83c3f8 more updates * 4cf241f update file-a * 200959c update file-a from main * dc45a94 (upstream/master, master) update file-a from main | * ce2a804 (origin/dev/br-2) update file-a | * 0006c5e (HEAD -> dev/br-1, origin/dev/br-1) more updates | * cdee8bb more updates | * 85afa56 update file-a |/ * 2f5eaaf (origin/master, origin/HEAD) add file-a The ultimate goal is to place myown
H---I---J dev/br-2
branch on top of the newly rebased G', in my own repo, after catching up with upstream. I.e., in my own repo, in the end, it should look like this:
A---B---C---D rebased master (upstream) \ E'---F'---G' rebased dev/br-1 (upstream) \ H'---I'---J' rebased dev/br-2 How to do that?
More explain by command:
cd /tmp mkdir upstream cd upstream # prepare its `master` and `dev/br-1` branches cd /tmp git clone upstream myfork # prepare my own changes based on the `dev/br-1` branch into `dev/br-2` cd /tmp/upstream # advance its `master` . . . # and its`dev/br-1` branches git checkout dev/br-1 git rebase -X theirs master dev/br-1 . . . Now upstream has advanced, both in its master and its develop branches (via rebase), and I need to pick-up from my own repo to continue with my customization.
cd /tmp mv myfork myfork0 git clone myfork0 myfork1 cd myfork1 git remote -v git remote add upstream /tmp/upstream git remote -v git fetch upstream git rebase upstream/master git checkout --track origin/dev/br-1 $ git remote -v origin /tmp/myfork0 (fetch) origin /tmp/myfork0 (push) upstream /tmp/upstream (fetch) upstream /tmp/upstream (push) $ git branch -avv * dev/br-1 0006c5e [origin/dev/br-1] more updates master dc45a94 [origin/master: ahead 1] update file-a from main remotes/origin/HEAD -> origin/master remotes/origin/dev/br-1 0006c5e more updates remotes/origin/dev/br-2 ce2a804 update file-a remotes/origin/master 2f5eaaf add file-a remotes/upstream/dev/br-1 7aec18c more updates remotes/upstream/master dc45a94 update file-a from main $ git log --all --decorate --oneline --graph * 7aec18c (upstream/dev/br-1) more updates * b83c3f8 more updates * 4cf241f update file-a * 200959c update file-a from main * dc45a94 (upstream/master, master) update file-a from main | * ce2a804 (origin/dev/br-2) update file-a | * 0006c5e (HEAD -> dev/br-1, origin/dev/br-1) more updates | * cdee8bb more updates | * 85afa56 update file-a |/ * 2f5eaaf (origin/master, origin/HEAD) add file-a UPDATE2:
With above status, when I tried --rebase-merges as suggested by @VonC, I'm getting:
$ git rebase --rebase-merges --onto master $(git merge-base dev/br-2 master) dev/br2 fatal: Not a valid object name dev/br-2 fatal: invalid upstream 'dev/br2' $ git checkout --track origin/dev/br-2 Branch 'dev/br-2' set up to track remote branch 'dev/br-2' from 'origin' by rebasing. Switched to a new branch 'dev/br-2' $ git rebase --rebase-merges --onto master $(git merge-base dev/br-2 master) dev/br-2 Successfully rebased and updated refs/heads/dev/br-2. $ git log --all --decorate --oneline --graph * 344418c (HEAD -> dev/br-2) update file-a * 4de3dec more updates * 81af2ac more updates * 1e3f9fb update file-a | * 7aec18c (upstream/dev/br-1) more updates | * b83c3f8 more updates | * 4cf241f update file-a | * 200959c update file-a from main |/ * dc45a94 (upstream/master, master) update file-a from main | * ce2a804 (origin/dev/br-2) update file-a | * 0006c5e (origin/dev/br-1, dev/br-1) more updates | * cdee8bb more updates | * 85afa56 update file-a |/ * 2f5eaaf (origin/master, origin/HEAD) add file-a Here, how to rebase my current dev/br-1 from upstream, then dev/br-2 from dev/br-1 branch please (detailed preparation can be found at https://pastebin.com/Df8VbCp2, if necessary).
git log --all --decorate --oneline --graphdo it, or see Pretty Git branch graphs etc.). This graph shows the commits that you have now. Then draw a graph of the commits you'd like to have, i.e., the same set of commits except that some have been copied to "new and improved" commits that have different parents.git rebase --ontowill do what you need, even if it takes severalgit rebase --ontocommands. Note that I generally like to use single uppercase letters for the existing commits, and then add a "prime" tick (commitC'is a copy of commitCfor instance, exceptC'comes afterEinstead of afterB) for the copies.git rebase --rebase-merges --onto master $(git merge-base dev/br-2 master) dev/br2to see if br-1 is rebased alongside br2? More on--rebase-mergeshere.git merge-base dev/br-2 masterwork first: the goal is to get the commit from master, from which br1 then br2 were created.