name: inverse layout: true class: center, middle, inverse
Licensed under CC BY 4.0. Code examples: OSI-approved MIT license.
layout: false
- In most cases a
git merge
runs smooth and automatic - Then a merge commit appears (unless fast-forward) without you even noticing
- Git is very good at resolving modifications when merging branches
- You can merge more than one branch (octopus merges)
- But sometimes the same line is modified on two branches and Git issues a conflict
- Then you need to tell Git which version to keep
- There are several ways to do that as we will see
- We will work with a primitive example: the same file on two branches
billy jean is not my lover
he is just a boy who
says that i am the one
but the kid is not my daughter
- As you can hopefully see the lyrics is not quite right
billy jean is not my lover
he is just a boy who
says that i am the one
but the kid is not my daughter
- Alice works on branch
alice
and corrects some errors
billy jean is not my lover
*she is just a girl who # modified by Alice
says that i am the one
*but the kid is not my son # modified by Alice
- Bob works on branch
bob
and corrects some errors
billy jean is not my lover
*he is just a girl who # modified by Bob
says that i am the one
but the kid is not my daughter
- Bob decides to merge branch
alice
$ git merge alice
- What will happen?
- Bob decides to merge branch
alice
$ git merge alice
Auto-merging lyrics
CONFLICT (content): Merge conflict in lyrics
Automatic merge failed; fix conflicts and then commit the result.
- Without conflict Git would have automatically created a merge commit, but since there is a conflict, Git did not commit
$ git status
# On branch bob
# You have unmerged paths.
# (fix conflicts and run "git commit")
#
# Unmerged paths:
# (use "git add <file>..." to mark resolution)
#
# both modified: lyrics
- Let us inspect file
lyrics
billy jean is not my lover
*<<<<<<< HEAD
*he is just a girl who
*=======
*she is just a girl who
*>>>>>>> alice
says that i am the one
but the kid is not my son
- Git inserted resolution markers (the
<<<<<<<
,>>>>>>>
, and=======
) - Try also
git diff
git diff
now only shows the conflicting part, nothing else- We have to mark resolution for file
lyrics
- We will discuss 3 different ways to do this
<<<<<<< HEAD
he is just a girl who
=======
she is just a girl who
>>>>>>> alice
- Manual resolution means that you have to edit the code/text between the resolution markers
- Git stages all files without conflicts and leaves the files with conflicts unstaged
- Decide what you keep (the one, the other, or both or something else)
- Then remove the resolution markers
- Tell Git that you have resolved the conflict with
git add lyrics
- Then verify with
git status
# On branch bob
# All conflicts fixed but you are still merging.
# (use "git commit" to conclude merge)
#
# Changes to be committed:
#
# modified: lyrics
- Now commit the merge; this opens up a prepared commit message that you can keep or modify
- It is good practice to keep the information that there was a conflict in the commit message
$ git mergetool lyrics
- Your current branch is left, the branch you merge is right, result is in the middle
- After you are done, close and commit,
git add
is not needed when usinggit mergetool
- Sometimes you know that you want to keep "our" version (version on this branch) or "theirs" (version on the merged branch)
- Then you do not have to resolve conflicts manually
$ git checkout --theirs lyrics # keep theirs (alice)
# alternative would be --ours (bob)
$ git add lyrics # tell Git that you have resolved it
$ git commit
- Imagine it is Friday evening, you try to merge but have conflicts all over the place
- You do not feel like resolving it now and want to undo the half-finished merge
- Or it is a conflict that you cannot resolve and only your colleague knows which version is the one to keep
- What to do?
- Imagine it is Friday evening, you try to merge but have conflicts all over the place
- You do not feel like resolving it now and want to undo the half-finished merge
- Or it is a conflict that you cannot resolve and only your colleague knows which version is the one to keep
- There is no reason to delete the whole repository
- Simply reset the repository to
HEAD
(last committed state)
$ git reset --hard HEAD # throws away everything that is not in HEAD
- The repository looks exactly as it was before the merge
- Conflicts can be avoided if you think and talk with your colleagues before committing
- Think and plan to which branch you will commit to
- Fortran people: modifying common blocks often causes conflicts
- Modifying global data often causes conflicts
- Monolithic entangled spaghetti-code maximizes risk of conflicts
- Modular programing minimizes risk of conflicts
- Ball-of-mud branches for "everything" maximize risk of conflicts
- One branch for one task only
- Resolve conflicts early
- If the branch affects code that is likely to be modified by others, the branch should be short-lived and/or merge often to the main development line
- If the branch affects code that is likely to be modified by others, the branch should merge the main development line often to stay up-to-date
- You create a branch for your new feature that you are working on
- While working on your feature you discover a defect or bug that has nothing to do with your new feature
- Or you see some ugly code and want to clean it up
- You are a responsible developer and you do not want to leave this defect
- You decide to fix this defect right on your new branch "while at it"
- This is a bad idea - why?
- Reasoning
- If you fix it on your branch other people will not see it
- You may want to merge it to
master
but you cannot since your new feature is not ready yet - Perhaps somebody else will fix it on master in a different way and then it will conflict with your new feature
- Before you commit a change, think: "who needs this change?"
- Based on the answer select the appropriate branch
- Develop separate features on separate branches and be very strict and disciplined with this
- Better solution
- Fix it on
master
, so other developers can see it - Than merge it to your development/topic branch
- Fix it on
- Developing separate features on separate branches minimizes conflicts
- It makes branches shorter-lived
- This again minimizes conflicts
- OK I made a commit to the "wrong" branch
- And it is a public branch, what now?
git cherry-pick
the commit to the "right" branch
- You made few commits to the
master
branch - You then realize that it broke some tests but you have no time now to fix them
- So you wish you had committed them to an experimental branch instead
- You want to move last three commits to a separate branch
- First make sure that your working directory and index are empty
- Then create a new branch (e.g.
feature
)
- Now just reset
master
back three commits
$ git checkout master
$ git branch feature # create feature branch but stay on master
$ git reset --hard c2 # on master
- Another job well done
- However this should not be done if the commits have already been shared with others
-
Feature branch merges to
master
typically once (at the end of its lifetime) -
But there may be good reasons for merging branch to
master
more often (release branch) -
Never merge a feature branch into another feature branch (branch pollution; discuss why)
-
For modular projects with write-protected
master
and code review and very high discipline- You typically should not merge
master
except the occasionalgit cherry-pick
- You typically should not merge
-
For entangled projects where most of the development happens directly on
master
- It is good to merge
master
to your topic branch often to stay in sync with main development line - Merge
master
to your branch ideally should never conflict - But it will sometimes, resolve conflicts early
- It is good to merge