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:
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:
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?
Merging. When you run git merge , your HEAD branch will generate a new commit, preserving the ancestry of each commit history.
So, instead of merging you first execute the following while on branch-b, git rebase master . This creates new commits that are copies of the old commits, i.e., the same change-set, author information and message, but new committer information and parent history.
Rebase is one of two Git utilities that specializes in integrating changes from one branch onto another. The other change integration utility is git merge . Merge is always a forward moving change record. Alternatively, rebase has powerful history rewriting features.
When you perform a merge, you effectively merge one branch into another—typically a feature branch or bug fix branch into a main branch such as master or develop. Not only will the code changes get merged in, but also all the commits that went into the feature branch.
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)
(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.
It's unnecessary to run git rebase new_feature
on the master branch after you've run git rebase master
on the new_feature branch. After you've run git rebase master
on the new_feature branch, you can then merge new_feature into master - it will be a fast-forward merge and won't introduce a merge commit.
The reason why git rebase new-feature
isn't playing all the new-feature commits on top of master is because git recognizes master already is at the base of new feature - we performed that step with git rebase master
- and that it would just be rebasing on itself. So instead it just fast-forwards to new-feature.
Also, you don't need to worry about pushing commits that reside below your remote/master tip -- the remote will reject your push should you try (unless you provide the -f option, which, don't). And, if your local master is tracking your remote master, git status
will tell if your local has diverged from you remote branch.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With