Reputation: 237
I think my master and release branches somehow diverged and I'm wondering what the best way to bring them back in sync is.
I have a master
branch which is supposed to be used for development, but then I'll merge this master
branch into a release
branch to create final builds that can be deployed. It was working fine, but as of a week ago, whenever I try to create a pull request merging from master
into release
, I get a list of commits that should've already been in release
. I'll merge the PR, but this keeps happening with every new PR trying to merge from master
to release
.
I tried looking at changes to make sure both branches are identical
git diff upstream/master..upstream/release
gives me no diffs.
git diff upstream/release..upstream/master
also gives me no diffs.
However git diff upstream/master...upstream/release
gives me the changes from all the commits since the one that probably diverged my two branches.
I think what might be happening is that my two branches are identical in raw code, but they have different commits? I'm still taking classes on git and how to use it more effectively so any help would be greatly appreciated!
Upvotes: 0
Views: 2033
Reputation: 489083
I think what might be happening is that my two branches are identical in raw code, but they have different commits?
Yes, that is the correct diagnosis, although you can confirm this with:
git log --left-right --boundary --decorate --oneline --graph
upstream/master...upstream/release
(all as one one, broken up into several for posting purposes).
Remember, Git is about commits. Branch names like master
and release
, and remote-tracking names like upstream/master
and upstream/release
, identify some particular commit. We say that these names point to those commits.
Commits also point to other commits: in particular, each commit points to its immediate parent.
When you have a simple linear sequence of such commits, each with its own hash ID, ending in some final hash ID we can call H
, we can draw that like this:
... <-F <-G <-H <-- master
The name master
holds the right hash ID: it lets you (or Git, at least) easily find the correct hash H
for the last commit in the chain. In other words, master
points to H
. Commit H
itself contains the snapshot—all of your files, frozen in time—and also the raw hash ID of previous ("parent") commit G
, so H
points to G
. The hash lets Git find G
. Commit G
contains a snapshot and another parent-hash, F
, which lets Git find F
, and so on.
In this case, you have a situation like this:
I--J <-- upstream/master
/
...--G--H
\
K--L <-- upstream/release
For whatever reason,1 the snapshots in J
and L
match, so comparing upstream/master
(commit J
) to upstream/release
(commit L
) shows no difference, regardless of which direction you use for the comparison.
Here, it's helpful to know that:
git diff A..B
just means:
git diff A B
That is, Git finds the two hash IDs in question, extracts the two frozen snapshots, and compares (diffs) them. You see information telling you what is needed to change the snapshot that is in A
into the snapshot in B
,
But:
git diff A...B
does not mean compare A to B, but rather find a merge base between A and B, and compare that merge base snapshot to B. In this case, given the drawing I made—which probably does not quite match the actual set of commits you have—the merge base of upstream/master
and upstream/release
is commit H
, which as you can see, is in both histories: you will find commit H
if you start at J
and work backwards, and you will also find commit H
if you start at L
and work backwards.
So here, this would diff the snapshot in H
against the snapshot in whichever commit is pointed-to by the name you put on the right. Since the snapshots in J
and L
match, you'll see the same diff regardless of which way you run it:
git diff upstream/master...upstream/release
compares H
vs L
, while:
git diff upstream/release...upstream/master
compares H
vs J
, but they both produce the same diff.
If you want the histories to match up—the history is the set of commits found by starting at the name, then working backwards—you must:
upstream/release
, orupstream/master
, oradd a new merge commit and move both, as illustrated by:
I--J
/ \
...--G--H M <-- upstream/release, upstream/master
\ /
K--L
for instance. But all of this is complicated by the fact that these two names are remote-tracking names. They are not branch names.
These remote-tracking names are yours, so you can move them—but your Git automatically moves them, to match the hash IDs stored in some other Git repository's branch names. That other Git repository is the one your Git calls upstream
, and it has branch names master
and release
. You run:
git fetch upstream
and your Git calls up their Git, finds any new commits they have that you don't (that you'll need), gets those commits, and then updates your upstream/*
remote-tracking names to store the same hash IDs that their branch names hold.
Hence, to get your remote-tracking names updated, the right way to do that is to convince them to get their branch names updated. Then you just run git fetch upstream
to update yours to match.
1The most likely reason to have these commits matching like this, without a merge commit in place, is for someone to have used git merge --squash
, or perhaps a clicky GitHub web page button labeled "squash and merge".
Upvotes: 0
Reputation: 51988
TIL : git diff
has a different interpretation of ..
and ...
from git log
.
git diff a..b
(two dots) is the same as git diff a b
git diff a...b
(three dots) compares the merge base of a
and b
to b
See the docs, the "Description" section.
Run : git log --oneline --graph upstream/master upstream/release
, you will view how the commits are laid out.
Your two dots diff command indeed shows you that the two branches have the same content.
The "merge base" is the forking point between the two branches, what you see in your three dots diff is the diff between that commit and the head commit of the branch.
Upvotes: 0
Reputation: 30277
I bet that if you run git diff upstream/release...upstream/master
you will get the same output as the 3rd command you posted there... and yes, the branches have diverged, but they have the same content, that's why you have no diff with 2 dots but you get output with 3 dots.
That still doesn't answer your question. It really depends on what you call "bring them in sync".
have the same content
: they already doget the branch histories together
, you might try merging them.get one branch to have the exact same history as the other
, that implies resetting --hard (therefore rewriting history) and some force-pushing.Upvotes: 1