Git tutorial for humans
From branch to branch Stanislav Komorovský and Elena Malkin (and Radovan Bast) Centre for Theoretical and Computational Chemistry Department of Chemistry, University of Tromsø N-9037 Tromsø, Norway
Git tutorial
Part 2 - From branch to branch
1/56
Why to use branches?
we could work on the main line (master) all the time but this would be neither practical nor efficient this is because everybody would be exposed to new bugs immediately when we develop, we introduce bugs and errors (this is normal) but when using branches, this is not a problem it is a very good practice to use branches develop independent features on separate branches in this part we will learn how to use branches in Git
Git tutorial
Part 2 - From branch to branch
2/56
Git and branches
branches are the true power of Git it is easy to create branches Git also makes it easy to merge branches in Git branches are embarrassingly lightweight (they are just pointers) it costs nothing to create new branches don’t fear the branches!
Git tutorial
Part 2 - From branch to branch
3/56
What is a commit?
commit hash: ffa109c956a01cf28a80c0... author: Stano email:
[email protected] date: Oct 8, 2013 18:16 tree: g98dm764skm9dmv6a0c0...
In this presentation we will label commits as a1, a2, ..., b1, b2, ... In reality the unique identifier of a commit is hash
Git tutorial
Part 2 - From branch to branch
4/56
What is branch?
branches are pointers branch master points to commit c2 try this: cat .git/refs/heads/master d8247aa7a003786df7ef0acd3665842d6d57adcd That’s it! Branch master is simply a hash to a commit HEAD points to where we are (currently master)
Git tutorial
Part 2 - From branch to branch
5/56
What is branch?
to see where we are (where HEAD points to) use git branch git branch * master there is only master and HEAD points to master (star)
Git tutorial
Part 2 - From branch to branch
6/56
How to create branch
let us create a new branch called "devel" git branch devel a new pointer appeared but we are still on master (HEAD did not move) git branch devel * master
Git tutorial
Part 2 - From branch to branch
7/56
How to switch between branches
with git checkout we can switch between branches git checkout devel we switched to devel git branch * devel master Git tutorial
Part 2 - From branch to branch
8/56
Work on a branch do not effect other branches
we do some work, make few commits on devel as we commit, the branch pointer as well as HEAD move master does not move perhaps we committed some bugs, but master is not affected
Git tutorial
Part 2 - From branch to branch
9/56
let us switch back to master git checkout master pointer HEAD is relocated and points now to master
Git tutorial
Part 2 - From branch to branch
10/56
Master is just another branch
we do some work on master, independent of devel as we commit, the master pointer as well as HEAD move master is also just a branch we consider it the main development line but it is a pointer, just like devel
Git tutorial
Part 2 - From branch to branch
11/56
How to merge branches
imagine that master has received some important bugfixes and devel needs them let us merge these commits to devel git merge master we merge master into devel git merge master means: merge commits from master to where you are Git automatically creates a merge commit (unless it is a fast-forward merge or unless there is a conflict; we will come back to these later) Git tutorial
Part 2 - From branch to branch
12/56
let us do more work on devel . . .
Git tutorial
Part 2 - From branch to branch
13/56
having committed some work to devel, let us switch back to master git checkout master
Git tutorial
Part 2 - From branch to branch
14/56
let us do more work on master . . . again the pointers move as we commit consider now that all bugs are fixed on devel and devel is ready to merge to master
Git tutorial
Part 2 - From branch to branch
15/56
merge from devel to here (master) git merge devel again a merge commit appears
Git tutorial
Part 2 - From branch to branch
16/56
How to delete branch
we can imagine that all the work on devel is completed this work has been integrated to master we can now delete the branch git branch -d devel as you see only the pointer disappeared, not the commits
Git tutorial
Part 2 - From branch to branch
17/56
How to force the deletion of a branch HEAD master c1
c2
c3
c4
c5
c6
c7
m2
b1
b2
b3
m1
b4
b5
we have done more work on devel but we decided not to merge it git branch -d devel will not work Git will not let you delete a branch which has not been reintegrated to delete devel anyway you must force Git to do it git branch -D devel only the pointer was deleted it is possible to revive commit b5 later Git will keep it next 30 days Git tutorial
Part 2 - From branch to branch
18/56
summary
let us pause for a moment and recapitulate what we have just learned cat .git/refs/heads/master git git git git git
branch branch checkout merge branch -d
# # # # #
see where we are create branch switch to branch merge branch (to current branch) delete branch
since the following command combo is so frequent: git branch git checkout
# create branch # switch to branch
there is a shortcut for it: git checkout -b
Git tutorial
# create branch and switch to it
Part 2 - From branch to branch
19/56
Two typical workflows develop a new cool feature on a branch: git checkout -b new-feature git commit
git checkout master git merge new-feature git branch -d new-feature
# # # # # # #
create branch, switch to it work, work, work, ... test feature is ready switch to master merge work to master remove branch
search for some really nasty bug: git checkout -b debug-cool-feature # debug, debug, arrrrghh, debug, ... # uff git checkout master git branch -D debug-cool-feature
# fix the bug on master # remove all testing code with one command # -D because we never merged back
advantage: we worked on a branch, branch is deleted, master is clean
Git tutorial
Part 2 - From branch to branch
20/56
Browsing history we don’t have to branch from the tip of the branch (HEAD) we can branch from arbitrary (earlier) hash git checkout -b this is the recommended mechanism to inspect old code (hash of commit c4 is abc123): HEAD master
old-code
c1
c2
c3
git checkout -b old-code abc123 # # # git checkout master # git branch -d old-code
c4
c5
c6
c7
create branch called old-code from hash abc123 do some archeology ... "what was I thinking back then!?" after you are done switch back to master
branches help us to keep the repository organized Git tutorial
c8
Part 2 - From branch to branch
21/56
fast-forward vs. non-fast-forward merges to clarify what is meant by "fast-forward" imagine that you are on master and want to merge devel
if you now type git merge devel Git will recognize that it can simply move the master pointer to b3 without creating a merge commit this is behavior is called fast-forward merge the default in Git is to fast-forward merge when possible
Git tutorial
Part 2 - From branch to branch
22/56
How to forbid fast-forward merges
you can tell git to always merge with no fast-forward:
git merge devel
git merge --no-ff devel
both is fine, the resulting code is the same, not the history it is a matter of taste
Git tutorial
Part 2 - From branch to branch
23/56
Merging vs. rebasing
to illustrate rebasing we consider the following situation
we want to merge master now you know how to do it: git merge master but there is an alternative
Git tutorial
Part 2 - From branch to branch
24/56
Merging vs. rebasing
git merge master
git rebase master
git rebase replays the branch commits b1–b3 on top of master as if they were committed after c5 it changes history (notice that the commits b1–b3 have been replaced by b1*–b3*) git rebase makes "merges" producing a linear history when working with others do not rebase commits that you have made public (history has changed)
Git tutorial
Part 2 - From branch to branch
25/56
Remote repositories
you know how to create a git repository with git init and how to work with it on your local machine
working with other people on a Git project typically starts by cloning the project you clone from another machine via ssh (or via other protocols: git, http, ...) user@host2> git clone ssh://user@host1/path/to/repo [/path/to/clone] think of git clone as a scp -r "plus" we will see what the "plus" means
Git tutorial
Part 2 - From branch to branch
26/56
imagine there is a central repository on host1 we are ready to clone the repository
Git tutorial
Part 2 - From branch to branch
27/56
git clone
user@host2> git clone ssh://user@host1/path/to/repo [/path/to/clone] we clone the entire history, all branches, all commits git clone creates pointers origin/master and origin/devel origin refers to where we cloned from, it is a shortcut for ssh://user@host1/path/to/repo Git tutorial
Part 2 - From branch to branch
28/56
git clone
origin/master and origin/devel are read-only branches they only move during git pull or git fetch or git push only git pull or git fetch or git push require network all other operations are local operations Git tutorial
Part 2 - From branch to branch
29/56
Commit arrives on remote repository
remote repository receives new commit pointer is moved (pushed) by someone else nothing changes on the local repository until we git pull or git fetch Git tutorial
Part 2 - From branch to branch
30/56
git fetch
git fetch git fetch updates origin/master and origin/devel all your local branches remain unchanged git fetch can never conflict because origin/master and origin/devel are read-only =⇒ you can’t checkout and work on origin/branch Git tutorial
Part 2 - From branch to branch
31/56
git pull
git merge origin/master the second step merges origin/master in this case it is fast-forward merge git pull is combo for git fetch followed by git merge with the usual setting, git pull will merge into current branch Git tutorial
Part 2 - From branch to branch
32/56
Work a bit on local repository
git commit git commit we can commit locally these commits are not visible to others until we git push observe that master , origin/master , and master on remote repository are 3 different pointers Git tutorial
Part 2 - From branch to branch
33/56
git push
git push origin master only now the remote master as well as origin/master move WARNING: without specifying remote repository and branch Git will push all branches on origin! use git config –global push.default current to set default behavior for git push Git tutorial
Part 2 - From branch to branch
34/56
Conflicts between remote and local repository
we commit "d7" and in the meantime remote receives commit "c7" from someone else what happens if we git pull
Git tutorial
Part 2 - From branch to branch
35/56
git pull
git pull origin master first we fetched (origin/master moved) then we merged origin/master to master (master moved) local master and remote master are two different branches if they diverge, Git will merge them during git pull Git tutorial
Part 2 - From branch to branch
36/56
git pull --rebase
git pull origin master --rebase you can avoid merge commit using --rebase this will replay your unpublished local master commits at the end of origin/master note how "d7" changed to "d7*" WARNING: if conflict appears ... uff ... =⇒ use google ;) Git tutorial
Part 2 - From branch to branch
37/56
Checkout remote branch devel
git checkout -b devel origin/devel we create and switch to local branch devel tracking origin/devel
Git tutorial
Part 2 - From branch to branch
38/56
Do some work
git commit as we commit to devel the pointer moves while origin/devel does not
Git tutorial
Part 2 - From branch to branch
39/56
Make public your development on devel branch
git push origin devel we have pushed origin/devel forward
Git tutorial
Part 2 - From branch to branch
40/56
How to make public new local branch?
push it upstream git checkout -b mynewbranch git commit
# create and switch to mynewbranch # work and commit
git push --set-upstream origin mynewbranch:mynewbranch
--set-upstream will set default behavior for git push and git pull when HEAD is on branch mynewbranch git pull will merge remote changes from origin/mynewbranch to mynewbranch git push will push local changes only to origin/mynewbranch
Git tutorial
Part 2 - From branch to branch
41/56
Conflict resolution
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
Git tutorial
Part 2 - From branch to branch
42/56
Example: create master branch for maximum clarity we will work with a primitive example: two branches, two files go to a safe place and create a new repository mkdir /tmp/merge-test cd /tmp/merge-test git init create a file called file1 that contains the following 5 lines: line line line line line
1 2 3 4 5 copy file1 to file2, add both and commit:
cp file1 file2 git add file1 file2 git commit -a -m "adding file1 and file2 on master"
Git tutorial
Part 2 - From branch to branch
43/56
Example: create devel branch and modify master
git branch devel but we stay on master; verify with git status and/or git branch now we modify both files inserting line "foo" line foo line line line line
1 2 3 4 5
cp file1 file2 and again we commit both files git commit -a -m "modify file1 and file2 on master"
Git tutorial
Part 2 - From branch to branch
44/56
Example: switch to devel branch
git checkout devel verify that on devel branch both files are in their initial form we have modified them on master, not here on devel cat file1 cat file2
Git tutorial
Part 2 - From branch to branch
45/56
Example: modify files on devel branch in file1 we insert a "bar": line line line line bar line
1 2 3 4 5 in file2 we insert two lines:
line bar line line line bar line
1 2 3 4 5 we commit our changes
git commit -a -m "modify file1 and file2 on devel" Git tutorial
Part 2 - From branch to branch
46/56
situation before git merge devel file1 master
file1 devel
line foo line line line line
line line line line bar line
1 2 3 4 5
1 2 3 4
c1
5
file2 devel
line foo line line line line
line bar line line line bar line
2 3 4 5
Git tutorial
c2 b1
file2 master 1
master
1
devel
2 3 4
HEAD
5
Part 2 - From branch to branch
47/56
merge devel to master HEAD we are ready to merge the two branches
master
we anticipate that file1 will merge automatically while file2 will conflict before the merge we switch to master, then we merge devel to master
c1
c2 b1
git checkout master git merge devel indeed Git issues a merge conflict in file2
devel
Auto-merging file1 Auto-merging file2 CONFLICT (content): Merge conflict in file2 Automatic merge failed; fix conflicts and then commit the result.
Git tutorial
Part 2 - From branch to branch
48/56
Situation after git merge devel file1 master
merge
file1 devel
line foo line line line line
line foo line line line bar line
line line line line bar line
1 2 3 4 5
1 2 3 4
1 2 3 4 5
5
file2 master
conflict
file2 devel
line foo line line line line
line 1 > devel line 2 line 3 line 4 bar line 5
line bar line line line bar line
1 2 3 4 5
Git tutorial
Part 2 - From branch to branch
1 2 3 4 5
49/56
Check status without conflict Git would have automatically created a merge commit but since there is a conflict, Git did not commit as always we inspect the situation with git status git status # On branch master # Changes to be committed: # # modified: file1 # # Unmerged paths: # (use "git add/rm ..." as appropriate to mark resolution) # # both modified: file2 #
we have to mark resolution for file2 we will discuss 3 different ways to do this
Git tutorial
Part 2 - From branch to branch
50/56
Inspect the situation let us inspect file2 cat file2 line 1 > devel line 2 line 3 line 4 bar line 5 Git inserted resolution markers (the , and =======) try also git diff git diff now only shows the conflicting part, nothing else
Git tutorial
Part 2 - From branch to branch
51/56
Manual resolution > devel manual resolution means that you have to edit the code/text between the resolution markers decide what you keep ("foo" or "bar" or both or something else) then remove the resolution markers tell Git that you have resolved the conflict with git add file2 then commit the merge vi file2 git add file2 git status git commit
Git tutorial
# resolve conflict # observe how the conflicting file2 moved up
Part 2 - From branch to branch
52/56
Resolution using mergetool to undo the manual merge (move repository back to HEAD minus one) use git reset --hard HEAD~1 now merge again, again the same conflict git merge devel git status now try git mergetool
this opens up a nice graphical overview (in this case meld tool is used) your current branch is left, the branch you merge is right, result is in the middle conflicts are in red, automatic merges are in green; resolve conflicts in the middle window after you are done, close and commit, git add is not needed when using git mergetool Git tutorial
Part 2 - From branch to branch
53/56
Using "ours" or "theirs" strategy
again let us undo the merge, and merge again to reproduce the conflict git reset --hard HEAD~1 git merge devel git status
Git tutorial
Part 2 - From branch to branch
54/56
Using "ours" or "theirs" strategy
sometimes you know that you want to keep "our" version (version on this branch) or "their" version (version on the merged branch) then you don’t have to resolve conflicts manually git checkout --ours file2 git add file2 git commit Git tutorial
# keep ours (master) # alternative would be --theirs (devel) # tell Git that you have resolved it Part 2 - From branch to branch
55/56
Aborting conflicting merge
imagine it’s Friday evening, you try to merge but have conflicts all over the place you don’t feel like resolving it now and want to undo the half-finished merge there is no reason to delete the whole repository simply reset the repository to HEAD (last committed state) git reset --hard HEAD the repository looks exactly as it was before the merge
Git tutorial
Part 2 - From branch to branch
56/56