I must admit I don’t fully understand the explanation in Pro Git, so I would like to know two things:
- Why does Git duplicate the commits in this PR while rebasing?
- How can I fix the mess am in now?
Kind help please!
I must admit I don’t fully understand the explanation in Pro Git, so I would like to know two things:
Kind help please!
@jwnasambu Each commit hash in Git is based on a number of factors, one of which is the hash of the commit that comes before it.
If you reorder commits you will change commit hashes; rebasing (when it does something) will change commit hashes. With that, the result of running git rebase master dev
, where dev
is out of sync with master
, will create new commits (and thus hashes) with the same content as those on dev
but with the commits on master
inserted before them.
I follow a somewhat repetitive workflow but it helps;
$ git pull --rebase upstream master
#—On local master branch to pull changes from upstream.`
$ git checkout -b TRUNK-123 master
-b [optional flag / applies to creating a new branch]
$ git rebase -i master
-i [optional for interactive rebase]
If you are on branch X and you do git rebase -i master, it changes branch X, not master, so you would have to push branch X.
Conclusion: Pull upstream changes to the local master branch, then check out your branch and rebase when required (You would have to commit any local changes to that branch first).
You can also rebase on branches you don’t have checked out, e.g.,
git fetch upstream master
git rebase -i upstream/master
Should do the same thing.
@jwnasambu Don’t worry too much about what commits show up in the commits tab on GitHub… This tends to happen when you mix two methods of keeping a branch up to date, e.g., both doing a git merge
of master
and then a git rebase
. Generally, you shouldn’t mix both merges
and rebases
on a single branch because it gets messy.
If you want to clean things up, then the thing to do is a git rebase --interactive
and remove the merge commits. A Git UI can be helpful here…
Merging and rebasing are two mechanisms for keeping a branch in sync with an upstream branch. A merge
applies the updates from the upstream branch by creating a new commit (the merge commit) in the current branch that contains the changes and, in the case of conflicts, any changes you’ve made to address those conflicts.
Rebasing applied a different strategy: it takes the point where the two branches (upstream and current) diverge, resets to that point, applies the changes from upstream and then the changes from the current branch. That’s what this diagram is getting at:
C4’ is the same diff as C4, but it’s now applied after C3 instead of C2. With a merge you end up with this:
Where C6 adds C3 and C5 to the master
branch plus the merge commit which includes any conflict resolutions that need to be applied.
Thanks so so much for the clear explanation. I now understand where the mess originated from and I now know how to go about it. I was really scared but now I can move with confidence. Once again thanks @ibacher.