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
branchexample_branch
was created;branch_commit
was commited toexample_branch
, firstgit log
display exactly this state of the repository;Then
example_branch
was merged tomaster
- ongit log
it just desplayed asmaster
moved to same commit asexample_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
intomaster
;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 createdexample branch
commit of whichfile
hascontent for example branch
;The
master
branch continues it’s way with a commit which hasfile
withcontent for example branch
;The first
git log
output shows the state of the repository at this step, so for now we have two branches wherefile
has different contents;Tried to merge
example_branch
into themaster
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 inmaster
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
fortest_file1
and the version fromexample_branch
fortest_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