Understanding Git Merges
I know this solution is somewhere, but I am having a hard time understanding git.
I am a single developer and there are often no changes on other branches as long as I use git.
Here's what I often do:
git branch changes
git checkout -b changes
/* changes occur */
git commit -m "Changes Occured"
/* Changes occur */
git commit -m "More Changes"
After that, I have the following visualization in my head:
:
| c2
| |
| c1
| /
master
However git gui shows this visualization
:
c2 changes
|
c1
|
master
Then I merge my changes with master like so:
git checkout -b master
git merge changes
I have the following visualization:
:
| master, changes
|
| \
| c2
| |
| c1
| /
master
However, the git gui shows:
:
| master, changes
c2
|
c1
|
master
Is this the expected behavior? Or am I doing something wrong?
source to share
Your visualization suggests there are master
more commits on top :
c3 (master)
|
| c2 (changes)
| |
| c1
| /
c0
:
Or, equivalently, branch names have some kind of permanent meaning (they are not in Git: in Git, only commit matter; branch names are mostly just silly things that accommodate common people, except for some special roles. which they have are kept alive and help send them back and forth between different Gits).
Note also that I've also moved the branch labels to point to the newest commit (only). This is how shortcut labels work in Git: they point to a single commit and therefore identify the commit of the branch tip.
If commit c3
doesn't already exist, Git notices that you have this convention:
c2 (changes)
|
c1
|
c0 (master)
:
in which the commit c0
which is the end master
is also available from c2
which is the end changes
. This means that the commit c0
is on both branches (note that this reachability property is true even if it master
points to some commit c3
, as in the top diagram). Because you have such a layout, Git can "push the name master
forward quickly" up the downlinks from c2
to c1
and back to c0
. It is this thing, which is not a merge at all, is the default action git merge
whenever possible. If master
already pointed to a new commitc3
, that would not be possible, and Git would have to do and do a "real merge" (perform a merge action and perform a merge commit c4
).
To get Git to do the merge - the action, merge-as-a-verb, is still completely unnecessary, and Git doesn't bother - you can use git merge --no-ff
. This will make a new merge commit c3
and move the label master
up to indicate the merge commit :
c3 (HEAD -> master)
|\
| c2 (changes)
| |
| c1
| /
c0
:
Note that only the current branch name is moved, i.e. label master
. To mark which label is current, let's add a name HEAD
.
source to share
Branches in git are nothing more than a history of their commitments. They are not written themselves, but simply point to the last of those commits.
That's why
:
c2 changes
|
c1
|
master
looks like it is displayed. There are only two commits, c1 and c2, and it changes
points to the second one and master
has no history recorded.
After the merge, I master
also wrote down the commits c1
and c2
. Since there were no commits exclusively to master before the merge took place, master
and changes
practically do not match, i.e. Record the same commit history because from both perspectives the same commits happened in the same order. This is ( c1
, c2
) since the merge was done using fast forward.
source to share