git: Merge Branches but Keep Commit History
branch, git, history, rebase, version-control
Solution
Answer
Here is a workflow that you can use that does just what you need it to do.
git checkout master
git pull --rebase (1)
git checkout new_feature
<do a bunch of commits>
git rebase master (2)
git checkout master
git merge new_feature (3)
git branch -D new_feature (4)
Explanation
(1) `git pull --rebase` will first fetch `origin/master` and then replay your local `master` on top of it. Note in the example log that your local commits are on top of your "local remote HEAD pointer."
> git log --oneline --all -10 --decorate
d34d34c (HEAD, master) Local commit message.
d3434r2 Local commit message.
d234d4c Local commit message.
er3ede3 (origin/master, origin/HEAD) Remote commit message.
sfe3fd3 Remote commit message.
You can now `checkout` and work on your `new_feature` branch for a while. When you're done...
(2) `git rebase master` will replay `new_feature` on top of `master`. Again, your local commits remain on top of your "local remote HEAD pointer."
> git log --oneline --all -10 --decorate
fc5773d (new_feature) Local new_feature commit.
9282838 Local new_feature commit.
d34d34c (HEAD, master) Local commit.
d3434r2 Local commit.
d234d4c Local commit.
er3ede3 (origin/master, origin/HEAD) Remote commit.
sfe3fd3 Remote commit.
The `rebase` command just put `new_feature` ahead of master, and to align them you need to run...
(3) `git merge new_feature`, which will do a fast-forward merge. Now `HEAD`, `new_feature`, and `master` all point to the same commit.
> git log --oneline --all -10 --decorate
fc5773d (HEAD, new_feature, master) Local new_feature commit.
9282838 Local new_feature commit.
d34d34c Local commit.
d3434r2 Local commit.
d234d4c Local commit.
er3ede3 (origin/master, origin/HEAD) Remote commit.
sfe3fd3 Remote commit.
(4) After that, you can safely delete the `new_feature` branch. Your final log before pushing will look like this:
> git log --oneline --all -10 --decorate
fc5773d (HEAD, master) Local new_feature commit 2
9282838 Local new_feature commit.
d34d34c Local commit.
d3434r2 Local commit.
d234d4c Local commit.
er3ede3 (origin/master, origin/HEAD) Remote commit.
sfe3fd3 Remote commit.
Problem
In my git workflow we have one main repository and one branch, master. Everyone pulls from remote master and everyone pushes to remote master. I want to work in my own branch while I prepare a feature. So far my history is something like this: ``` git pull --rebase git checkout -b new_feature <make some commits> git checkout master git pull --rebase ``` Now I want to merge the branch and here's what I need: - No merge commits in my local master branch. - All commits made into my new_feature branch merged into master as if I had made them in master. - All merged commits to be merged somewhere on top of my local remote head pointer. My biggest concern is item 3, when is needed so that I can safely push the changes. If the merged commits are intertwined with commits before head then I will have problems pushing, see related problem I had: git: Pushing Single Commits, Reordering with rebase, Duplicate Commits. I've read the following: - http://mettadore.com/2011/05/06/a-simple-git-rebase-workflow-explained/ - Keep commits history after a 'git merge' - How do you rebase the current branch's changes on top of changes being merged in? And I think I need to do: ``` git checkout master git pull --rebase git checkout new_feature git rebase master git checkout master git rebase new_feature git push ``` My understanding is that ``` git checkout new_feature git rebase master ``` will make new_feature appear as if it was branched off from the new current head. Is that true? And that ``` git checkout master git rebase new_feature ``` will place new_feature on top of master. Is that correct? If so, this is the main point of my confusion. If "git rebase master" places master commits at the bottom of new_feature, then why does "git rebase new_feature" place new_feature commits at the top of master, i.e. why doesn't it do the opposite?