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?

+3


source to share


3 answers


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

.

+4


source


If there are no other commits in the main branch, git will offer fast forward instead of merging. If you don't like this behavior (many, like me, do not) and want to keep branch history, you can merge with git merge _branch_ --no-ff

to force git to do the merge.



+1


source


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.

+1


source







All Articles