From branch to branch

Git tutorial for humans From branch to branch Stanislav Komorovský and Elena Malkin (and Radovan Bast) Centre for Theoretical and Computational Chemi...
Author: Nicholas Watson
3 downloads 1 Views 2MB Size
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