Let's say that I am on a local repo and its branch is my_name/branch_A
When I do git rebase <branch_B>
, I sometimes get many conflicts in the files that I did not modify.
Why does this happen?
I like to just get the HEAD of all the files from branch_B
except for the ones I modified in my_name/branch_A
. How can this be done without manually resolving these conflicts that I did not introduce myself.
Rebase copies commits (and then abandons the originals). This is the root of the problem.
Let's look at an example. First, note that I'm drawing commit graphs with older commits towards the left, and newer commits towards the right. The commits have single-letter names here, instead of Git's true 40-character hash names like
f1c93ab7...
. Branch names appear on the right, with an arrow pointing to the tip commit of that branch, because that is how Git actually stores these things.Your current branch name is
my_name/branch_A
, and you have a branch namedbranch_B
as well. There are some commits on each branch that are not on the other branch, and some commits that are on both branches. Meanwhile your branch,my_name/branch_A
, forks off from some third point—so there are commits on your branch that are not onbranch_B
, but are not "your commits":You made commits
I
andJ
and now you would like to have those two commits come after commitH
, i.e., to rework your commits to be "after" the tip ofbranch_B
.In other words, you did not make commits
C--D--E
. Nonetheless, these commits are on your branch. In fact, commitsA
andB
are on your branch too: those two commits are on all the branches.If you now run
git rebase branch_B
(while you're still on your branch), Git has to figure out two things:The name
branch_B
tells Git both of these things. The commits to be copied are "those that are onmy_name/branch_A
but not onbranch_B
. That'sC-D-E-I-J
. The place to put them is "after the tip commit ofbranch_B
, i.e., after commitH
.If this all succeeds, Git would set your branch name to point to the new copies:
The names with the "prime" marks (
C'
and so on) are the copies.(You can view the commits that
git rebase
would/will copy withgit log <upstream>..HEAD
, which in this case isgit log branch_B..HEAD
. I would add--oneline
here in most cases to get a one-line log message per commit.)Well, if that's the problem, what should you do? The obvious answer is: tell Git not to copy
C-D-E
. You want this result instead:That is, Git should copy only those commits "between" (after, really) the tip of
branch_uhoh
and your branch, so as to get commitsI
andJ
; but it should copy them to (again, after, really) the tip ofbranch_B
. The way to do that is to write:In other words, tell rebase both things, instead of telling it one thing and letting it figure out the two from that.
(But how do you find
branch_uhoh
? Well, the "right" way is usually to remember it, but you can just rungit log --graph --decorate --oneline
and find the cutoff commit by its ID or any name that shows up. Instead ofbranch_uhoh
you can cut-and-paste the hash ID of the actual cutoff commit. Most often, you can have Git itself remember the "upstream" name for you, and you rebase only within and onto the upstream and you need no arguments: you just rungit rebase
and it does all the work. But there are special cases where you need to transplant commits, where this is not sufficient; then you needgit rebase --onto
.)