Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding Git Merges

Tags:

git

I know this solution is somewhere, but I am having trouble understanding git.

I am a single developer and there are often no changes on other branches while I am using git.

Here is often what I do:

git branch changes
git checkout -b changes
/* changes occur */
git commit -m "Changes Occured"
/* Changes occur */
git commit -m "More Changes"

After this, i have the following visualization in my head:

  :
  | c2
  | |
  | c1
  | /
master

However, git gui shows this visualization

    :
    c2 changes
    |
    c1
    |
  master

I then 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, git gui shows:

:
| master, changes
c2
|
c1
|

master

Is this the expected behavior? Or am i doing something wrong?

like image 244
S. Walker Avatar asked Aug 15 '26 14:08

S. Walker


2 Answers

Your visualization presupposes that there are more commits atop branch master:

c3 (master)
|
| c2 (changes)
| |
| c1
| /
c0
:

Or, equivalently, that branch names have some sort of permanent significance (they don't in Git: in Git, only commits matter; branch names are largely just silly things to accomodate mere humans, except for some special roles they have in keeping commits alive and helping to send them back and forth between different Gits).

Note also that I have also moved the branch labels to point to the newest commit (only). This is how branch labels work in Git: they point to a single commit, and hence identify the tip commit of the branch.

If commit c3 does not yet exist, Git notices that you have this arrangement:

c2 (changes)
|
c1
|
c0 (master)
:

in which commit c0, which is the tip of master, is also reachable from c2, which is the tip of changes. This means that commit c0 is on both branches (note that this is reachability thing is true even if master points to some commit c3, as in the top diagram). Since you do have this arrangement, Git can "slide the name master forward in a fast-forward fashion", up the downward links that go from c2 to c1 and back to c0. This—this thing that is not actually a merge at all—is the default action for git merge whenever it is possible. If master already pointed to new commit c3, that would be impossible, and Git would have to do, and make, a "real merge" (do the merging action, and make a merge commit c4).

To force Git to make a merge commit—the action, the merge-as-a-verb, is still entirely unnecessary and Git doesn't bother—you can use git merge --no-ff. This will make a new merge commit c3 and move the master label up to point to that merge commit:

c3 (HEAD -> master)
|\
| c2 (changes)
| |
| c1
| /
c0
:

Note that only the current branch name, i.e., the label master, moves. To note which label is current, we add the HEAD name.

like image 188
torek Avatar answered Aug 17 '26 05:08

torek


If there are no other commits on the main branch, git will opt to fast forward instead of making a merge commit. If you don't like this behavior (many, like me, don't) and want to keep the branch history, you can merge with git merge _branch_ --no-ff to force git to make a merge commit.

like image 45
GameKyuubi Avatar answered Aug 17 '26 05:08

GameKyuubi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!