I have a feature branch, and a master branch.
Master branch has evolved and I mean to have those updates to diverging as little as possible from master branch.
So I git pull
in both branches, git checkout feature/branch
and finally git rebase master
.
Now here I either expect everything to work smoothly or conflicts showing up that I need to resolve before continuing rebase until all master commits are re-applied successfully on feature branch.
Now what really happened in my case is something I do not understand:
$>git rebase master First, rewinding head to replay your work on top of it... Applying: myFirstCommitDoneOnTheBranch Applying: myOtherCommitDoneOnTheBranch $>git status On branch feature/branch Your branch and 'origin/feature/feature' have diverged, and have 27 and 2 different commits each, respectively. (use "git pull" to merge the remote branch into yours) nothing to commit, working tree clean $>git pull *load of conflicts*
Now, as much as I can understand he load of conflicts after the pull; I do not understand the need for a pull. Logically, it should rollback to master when it got branched, save the commits made on the branch, forward to latest commit on master and then apply the saved commits.
I do not understand to what the Applying
message refers to: what is applying the commits on which version?
There is no need to do a git pull after you have rebased your feature branch on top of master . With your current workflow, the reason why git status is telling you this: Your branch and 'origin/feature' have diverged, and have 27 and 2 different commits each, respectively.
It is best practice to always rebase your local commits when you pull before pushing them. As nobody knows your commits yet, nobody will be confused when they are rebased but the additional commit of a merge would be unnecessarily confusing.
If you're working on your own branch, always push immediately after rebasing. and assuming that they should git pull --rebase , which in this case is exactly what you don't want.
tl;dr You should update both master
and feature
with git pull
and git pull --rebase
before rebasing feature
on top of master
. There is no need to do a git pull
after you have rebased your feature
branch on top of master
.
With your current workflow, the reason why git status
is telling you this:
Your branch and 'origin/feature' have diverged, and have 27 and 2 different commits each, respectively.
is because your rebased feature
branch now has 25 new commits that aren't reachable from origin/feature
(since they came from the rebase on master
) plus 2 commits that are reachable from origin/feature
but have different commit IDs. Those commits contain the same changes (i.e. they're patch equivalent) but they have different SHA-1 hashes because they are based off of a different commit in origin/feature
than the one you rebased them on in your local repository.
Here's an example. Let's assume that this is your history before doing git pull
on master
:
A - B - C (master) \ D - E (feature)
After git pull
, master
got commit F
:
A - B - C - F (master, origin/master) \ D - E (feature)
At that point, you rebase feature
on top of master
, which applies D
and E
:
A - B - C - F (master, origin/master) \ D - E (feature)
In the meantime, the remote branch origin/feature
is still based off commit C
:
A - B - C - F (master, origin/master) \ \ \ D' - E' (feature) \ D - E (origin/feature)
If you do a git status
on feature
, Git will tell you that your feature
branch has diverged from origin/feature
with 3 (F
, D'
, E'
) and 2 (D
, E
) commits, respectively.
Note that
D'
andE'
contain the same changes asD
andE
but have different commit IDs because they have been rebased on top ofF
.
The solution is to do git pull
on both master
and feature
before rebasing feature
on master
. However, since you may have commits on feature
that you haven't yet pushed to origin
, you would want to do:
git checkout feature && git pull --rebase
to avoid creating a merge commit between origin/feature
and your local feature
.
In light of this comment, I expanded on the diverging branches. The reason why git status
reports that feature
and origin/feature
diverge after the rebase is due to the fact that rebasing brings in new commits to feature
, plus it rewrites the commits that were previously pushed to origin/feature
.
Consider the situation after the pull but before the rebase:
A - B - C - F (master) \ D - E (feature, origin/feature)
At this point, feature
and origin/feature
point to the same commit E
—in other words, they're in "sync". After rebasing feature
on top of master
, history will look like this:
A - B - C - F (master) \ \ \ D' - E' (feature) \ D - E (origin/feature)
As you can see, feature
and origin/feature
have diverged, their common ancestor being commit C
. This is because feature
now contains the new commit F
from master
plus D'
and E'
(read as "D prime" and "E prime") which are commits D
and E
applied on top of F
. Even though they contain the same changes, Git considers them to be different because they have different commit IDs. Meanwhile, origin/feature
still references D
and E
.
At this point, you've rewritten history: you've modified existing commits by virtue of rebasing them, effectively creating "new" ones.
Now, if you were to run git pull
on feature
this is what would happen:
A - B - C - F (master) \ \ \ D' - E'- M (feature) \ / D - E - (origin/feature)
Since git pull
does git fetch
+ git merge
, this would result in the creation of the merge commit M
, whose parents are E'
and E
.
If, instead, you ran git pull --rebase
(that is, git fetch
+ git rebase
) then Git would:
feature
to commit C
(the common ancestor of feature
and origin/feature
)D
and E
from origin/feature
F
, D'
and E'
However, noticing that D'
and E'
contain the same changes as D
and E
, Git would just discard them, resulting in a history looking like this:
A - B - C - F (master) \ D - E - F' (feature) ^ (origin/feature)
Notice how commit F
, previously reachable from feature
, got applied on top of origin/feature
resulting in F'
. At this point, git status
would tell you this:
Your branch is ahead of 'origin/feature' by 1 commit.
That commit being, of course, F'
.
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