Merge#

Branches merge is opertion that allows you to get changes from intependend branches in one common commit. The git merge command is crucial for this page.

To merge branches you need to git checkout to brunch to which we merge all the changes, and execute command git merge <branch to be merged>.

To ancestor{#sec-to_ancestor}#

The simplest case is when you create a branch, make a few commits, and want to add those changes from an ancestor branch that hasn’t changed.

Simply put, you just tell the parent branch to just start referencing the last commit of the branch you want to merge into the parent branch.

In the next cell:

  • Created repository where there is basic commit;

  • From basic commit branch example_branch was created;

  • branch_commit was commited to example_branch, first git log display exactly this state of the repository;

  • Then example_branch was merged to master - on git log it just desplayed as master moved to same commit as example_branch.

%%bash
mkdir merge_example
cd merge_example
git init &> /dev/null

echo "content" > test_file
git add --all
git commit -m "basic commit" &> /dev/null

echo
echo "=====creating branch====="
git checkout -b example_branch 2>&1
echo "content2" > test_file
git commit -am "branch commit" &> /dev/null
git log --decorate --graph

echo
echo "=====merging to master====="
git checkout master 2>&1

echo "-----git merge-----"
git merge example_branch
echo "-----git log-----"
git log --decorate --graph

cd ..
rm -r merge_example
=====creating branch=====
Switched to a new branch 'example_branch'
* commit bbd3463120a7fc513429a75ca2ebfff325571f84 (HEAD -> example_branch)
| Author: Dranikf <kobfedsur@gmail.com>
| Date:   Sun Sep 10 16:20:47 2023 +0300
| 
|     branch commit
| 
* commit c42d7deed4d71b0f5c9036816fe65e7295a5e227 (master)
  Author: Dranikf <kobfedsur@gmail.com>
  Date:   Sun Sep 10 16:20:47 2023 +0300
  
      basic commit

=====merging to master=====
Switched to branch 'master'
-----git merge-----
Updating c42d7de..bbd3463
Fast-forward
 test_file | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
-----git log-----
* commit bbd3463120a7fc513429a75ca2ebfff325571f84 (HEAD -> master, example_branch)
| Author: Dranikf <kobfedsur@gmail.com>
| Date:   Sun Sep 10 16:20:47 2023 +0300
| 
|     branch commit
| 
* commit c42d7deed4d71b0f5c9036816fe65e7295a5e227
  Author: Dranikf <kobfedsur@gmail.com>
  Date:   Sun Sep 10 16:20:47 2023 +0300
  
      basic commit

Basic case{#sec-basic_case}#

Here I’ll play with the case when you have to branches but one doesn’t refer to any ancestor of other (like it was in To ancestor) section, so we have two separate branches.

Note in this example I don’t pay any attention ot conflicts, the example is made in such a way as to avoid conflicts.

In the example:

  • I created a repository where there are two branches that have independent commits in them, this is shown in the first git log output;

  • Then I merge example_branch into master;

  • In the final git log output:

    • There is a new commit where the two branches merge;

    • The message of the commit is Merge branch 'example_branch' - automatically generated by git, in practice you’ll be able to set the message you want.

%%bash
mkdir merge_example
cd merge_example
git init &> /dev/null

echo "content" > file
git add --all
git commit -m "basic commit" &> /dev/null

git checkout -b example_branch &> /dev/null
echo "content" > branch_file
git add --all
git commit -m "branch commit" &> /dev/null

git checkout master &> /dev/null
echo "master content" > file
git commit -am "master commit" &> /dev/null

echo
echo "=====log====="
git log --decorate --graph --all

echo
echo "=====merge====="
git merge example_branch

echo
echo "=====log====="
git log --decorate --graph --all

cd ..
rm -r merge_example
=====log=====
* commit 6ea69b66f6c2a49ea60a3a6b5b3de66181274234 (example_branch)
| Author: Fedor Kobak <kobfedsur@gmail.com>
| Date:   Sun Sep 10 13:00:54 2023 +0300
| 
|     branch commit
|   
| * commit 8b9f875b80b9d44020dedf40a39b1894f4a406d6 (HEAD -> master)
|/  Author: Fedor Kobak <kobfedsur@gmail.com>
|   Date:   Sun Sep 10 13:00:54 2023 +0300
|   
|       master commit
| 
* commit 15149be74a6d219dac74624c94bd7aeda0691e9d
  Author: Fedor Kobak <kobfedsur@gmail.com>
  Date:   Sun Sep 10 13:00:54 2023 +0300
  
      basic commit

=====merge=====
Merge made by the 'ort' strategy.
 branch_file | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 branch_file

=====log=====
*   commit 96f925a2adbada606ba4678c71460cf697fd8590 (HEAD -> master)
|\  Merge: 8b9f875 6ea69b6
| | Author: Fedor Kobak <kobfedsur@gmail.com>
| | Date:   Sun Sep 10 13:00:54 2023 +0300
| | 
| |     Merge branch 'example_branch'
| | 
| * commit 6ea69b66f6c2a49ea60a3a6b5b3de66181274234 (example_branch)
| | Author: Fedor Kobak <kobfedsur@gmail.com>
| | Date:   Sun Sep 10 13:00:54 2023 +0300
| | 
| |     branch commit
| | 
* | commit 8b9f875b80b9d44020dedf40a39b1894f4a406d6
|/  Author: Fedor Kobak <kobfedsur@gmail.com>
|   Date:   Sun Sep 10 13:00:54 2023 +0300
|   
|       master commit
| 
* commit 15149be74a6d219dac74624c94bd7aeda0691e9d
  Author: Fedor Kobak <kobfedsur@gmail.com>
  Date:   Sun Sep 10 13:00:54 2023 +0300
  
      basic commit

Solve conflict#

In the section basic case the example shows the case where the brances to be merged modify different files. But how does git deal with the case where branches being merged have changes in the same files?

Git will enter a special state - a merge conflict. It will be necessary to edit the files that caused the conflict, add changes to the stage, and commit the changes.

When there is a conflict, git will make some changes to the conflicting files. It will record where there is a conflict:

<<<<<<< HEAD
<content of the branch we are merging into>
===========
<content of the branch we merge into another>
>>>>>>> <branch ot be merged name>

Manual example#

We can put any content there: we can put content from one of the branches, or we can put completely different content.

So in the following example

  • Create a repository;

  • Commit with the message basic commit;

  • From basic commit commit created example branch commit of which file has content for example branch;

  • The master branch continues it’s way with a commit which has file with content for example branch;

  • The first git log output shows the state of the repository at this step, so for now we have two branches where file has different contents;

  • Tried to merge example_branch into the master branch and got a message that there was a merge conflict;

  • Shows what the git status of the repository looks like in this state:

    • Prints possible solutions;

    • Prints the files that caused the merge conflict;

  • Suppose we want to fix a conflict. Our actions are to write into the conflict files how they should be fixed as a result, add them to the stage, and then commit;

  • Interestingly, git will overwrite the files involved in the conflict. The example shows what our file will look like, see =====conflict file=====;

  • I set the file to after merge content and just commit the changes - this commit will become the merge point for the conflicting branches.

%%bash
mkdir merge_example
cd merge_example
git init &> /dev/null

echo "content for basic commit" > file
git add --all
git commit -m "basic commit" &> /dev/null

git checkout -b example_branch &> /dev/null
echo "content for example branch" > file
git commit -am "commit in example_branch" &> /dev/null

git checkout master &> /dev/null
echo "content for master branch" > file
git commit -am "commit in master" &> /dev/null

echo "=====git log====="
git log --decorate --graph --all

echo
echo "=====merge try====="
git merge example_branch
echo
echo "=====git status====="
git status
echo
echo "=====conflict file====="
cat file

echo "after merge content" > file
git add file
git commit -am "my after merge commit" &> /dev/null

echo
echo "=====git log====="
git log --all --decorate --graph


cd ..
rm -r merge_example
=====git log=====
* commit 69a666cd3dc1c3f0b436a1ecbeb58ea32eb080c1 (example_branch)
| Author: Dranikf <kobfedsur@gmail.com>
| Date:   Sun Sep 10 16:43:44 2023 +0300
| 
|     commit in example_branch
|   
| * commit 51377f0e8c2f305bfcab9c4a97a6a36d8e44c99f (HEAD -> master)
|/  Author: Dranikf <kobfedsur@gmail.com>
|   Date:   Sun Sep 10 16:43:44 2023 +0300
|   
|       commit in master
| 
* commit 7307ad26c4cc29bbb0eac4b9ad2420aeab716f0b
  Author: Dranikf <kobfedsur@gmail.com>
  Date:   Sun Sep 10 16:43:44 2023 +0300
  
      basic commit

=====merge try=====
Auto-merging file
CONFLICT (content): Merge conflict in file
Automatic merge failed; fix conflicts and then commit the result.

=====git status=====
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
	both modified:   file

no changes added to commit (use "git add" and/or "git commit -a")

=====conflict file=====
<<<<<<< HEAD
content for master branch
=======
content for example branch
>>>>>>> example_branch

=====git log=====
*   commit acb33c07dd270ac0ff04f29c37303d10ecb2ed0c (HEAD -> master)
|\  Merge: 51377f0 69a666c
| | Author: Dranikf <kobfedsur@gmail.com>
| | Date:   Sun Sep 10 16:43:44 2023 +0300
| | 
| |     my after merge commit
| | 
| * commit 69a666cd3dc1c3f0b436a1ecbeb58ea32eb080c1 (example_branch)
| | Author: Dranikf <kobfedsur@gmail.com>
| | Date:   Sun Sep 10 16:43:44 2023 +0300
| | 
| |     commit in example_branch
| | 
* | commit 51377f0e8c2f305bfcab9c4a97a6a36d8e44c99f
|/  Author: Dranikf <kobfedsur@gmail.com>
|   Date:   Sun Sep 10 16:43:44 2023 +0300
|   
|       commit in master
| 
* commit 7307ad26c4cc29bbb0eac4b9ad2420aeab716f0b
  Author: Dranikf <kobfedsur@gmail.com>
  Date:   Sun Sep 10 16:43:44 2023 +0300
  
      basic commit

Select version#

Sometimes files can differ significantly between branches, so it can be difficult to edit files in all the difference entries. You may want to consider specifying which branch file should be taken for the merge commit.

You can do this with the syntax git checkout --theirs/ours <list of files>. If you use ours it will take the version of the file from the current branch, if you use theirs it will take the version from the merging branch.

The following example shows the difference:

  • There are two files added to the git repository;

  • In new_branch the files change one way in master the other, so you’ll have conflicts when merging;

  • Use git checkout to resolve the conflict:

    • For test_file1 we use the --ours option;

    • For test_file2 we use the --theirs option;

  • As a result we have the version from master for test_file1 and the version from example_branch for test_file2;

%%bash
mkdir merge_example
cd merge_example
git init &> /dev/null

echo -e "version\n"\
"of the test_file1\n"\
"from initian commit"\
> test_file1
echo -e "version\n"\
"of the test_file2\n"\
"from initian commit"\
> test_file2

git add --all
git commit -m "initial commit" &> /dev/null

git checkout -b new_branch &> /dev/null
echo -e "version\n"\
"of the test_file1\n"\
"from new_branch"\
> test_file1
echo -e "version\n"\
"of the test_file2\n"\
"from new_branch"\
> test_file2
git commit -am "commit from new_branch" &> /dev/null

git checkout master &> /dev/null
echo -e "version\n"\
"of the test_file1\n"\
"from master"\
> test_file1
echo -e "version\n"\
"of the test_file2\n"\
"from master"\
> test_file2
git commit -am "commit from master" &> /dev/null

git log --graph --decorate --all

git merge new_branch &> /dev/null

echo
echo
echo "=====Files before checkout====="
echo "-----test_file1-----"
cat test_file1
echo "-----test_file2-----"
cat test_file2


echo
echo "=====Files after checkout====="
git checkout --ours test_file1 &> /dev/null
git checkout --theirs test_file2 &> /dev/null
echo "-----test_file1-----"
cat test_file1
echo "-----test_file1-----"
cat test_file2

cd ..
rm -r merge_example
* commit 7d17539a009082402162cd98502bc9e3e0032aca (HEAD -> master)
| Author: Fedor Kobak <kobfedsur@gmail.com>
| Date:   Mon Oct 30 15:50:33 2023 +0300
| 
|     commit from master
|   
| * commit 40934888b03ac7bb5e4d2df298f6eb294a881cce (new_branch)
|/  Author: Fedor Kobak <kobfedsur@gmail.com>
|   Date:   Mon Oct 30 15:50:33 2023 +0300
|   
|       commit from new_branch
| 
* commit c830f9d4e47bb64137721c148926432b922365ed
  Author: Fedor Kobak <kobfedsur@gmail.com>
  Date:   Mon Oct 30 15:50:33 2023 +0300
  
      initial commit


=====Files for merge=====
-----test_file1-----
version
of the test_file1
<<<<<<< HEAD
from master
=======
from new_branch
>>>>>>> new_branch
-----test_file2-----
version
of the test_file2
<<<<<<< HEAD
from master
=======
from new_branch
>>>>>>> new_branch

=====Files before checkout=====
-----test_file1-----
version
of the test_file1
from master
-----test_file1-----
version
of the test_file2
from new_branch