Slide 1

Slide 1 text

Being an Effective Git (User) Making the jump from Subversion Dave Ingram @dmi March 23, 2012

Slide 2

Slide 2 text

Git is not Subversion • The two are very different • Not just in operation, but in the way you must think

Slide 3

Slide 3 text

Git is not Subversion • The two are very different • Not just in operation, but in the way you must think • Subversion commit: A snapshot in time • Git commit: A set of changes; a diff

Slide 4

Slide 4 text

Git is not Subversion • The two are very different • Not just in operation, but in the way you must think • Subversion commit: A snapshot in time • Git commit: A set of changes; a diff • Subversion branch: A cheap copy of the tree • Git branch: A convenient, changable identifier for a commit and its ancestors

Slide 5

Slide 5 text

How do I use it?

Slide 6

Slide 6 text

Basic commands • Basic git commands are quite similar to subversion • Both use subcommands of a master program, e.g. git status and svn status • Git has man pages for each command: git command --help • Most commands are (more or less) identical • Be warned: there are some differences

Slide 7

Slide 7 text

Basic commands Subversion Git svn checkout git clone svn status git status svn diff git diff svn update git pull∗ svn commit git commit -a && git push svn switch branch URL git checkout branch name svn revert path git checkout -- path svn log git log svn merge git merge or git cherry-pick ∗Not really identical

Slide 8

Slide 8 text

Setting user info • Git needs to know who you are! • The very first git commands you should run: • git config --global user.name ' your name ' • git config --global user.email email • This information will identify your commits

Slide 9

Slide 9 text

Workflow Walkthrough

Slide 10

Slide 10 text

Overview clone branch edit status diff stage check commit merge/ push

Slide 11

Slide 11 text

Setting up your working copy Start off by getting a copy of the repository: $ git clone url dir Initialized empty Git repository in dir /.git/ remote: Counting objects: 77, done. remote: Compressing objects: 100% (76/76), done. remote: Total 77 (delta 49), reused 0 (delta 0) Receiving objects: 100% (77/77), 1.97 MiB | 1.26 MiB/s, done. Resolving deltas: 100% (49/49), done. $ cd dir clone branch edit status diff stage check commit merge/push

Slide 12

Slide 12 text

Starting work on a feature A newly-cloned repository will start with the master branch checked out. It’s a good idea to put every feature in its own branch, unless it’s a trivial bugfix: $ git co -b branch This will create the branch branch, and switch to it. Now you can actually start to edit files. clone branch edit status diff stage check commit merge/push

Slide 13

Slide 13 text

Checking status $ git status # On branch branch # Changed but not updated: # (use "git add ..." to update what will be committed) # (use "git checkout -- ..." to discard changes in working directory) # # modified: app/models/Comment.php # modified: app/views/CommentView.php # # Untracked files: # (use "git add ..." to include in what will be committed) # # app/models/CommentThread.php # www/comments/threads/ no changes added to commit (use "git add" and/or "git commit -a") clone branch edit status diff stage check commit merge/push

Slide 14

Slide 14 text

Seeing what has changed To see details of what has changed, use: $ git diff diff --git a/app/models/Comment.php b/app/models/Comment.php index 07ac8b3..627b51b 100644 --- a/app/models/Comment.php +++ b/app/models/Comment.php @@ -1,4 +1,5 @@

Slide 15

Slide 15 text

Preparing a commit With git, you must “stage” changes to be committed. This gives you full control and helps ensure that you don’t commit anything you don’t intend. $ git add app/models/Comment*.php $ git add app/views/CommentView.php $ git add www/comments/threads If you want to stage everything, you could also do: $ git add . clone branch edit status diff stage check commit merge/push

Slide 16

Slide 16 text

Seeing what will be committed To see details of what will be committed, like git diff, use: $ git status -v This will show you every change waiting to be committed, in the same style as git diff. clone branch edit status diff stage check commit merge/push

Slide 17

Slide 17 text

Making a commit Actually making a commit is very simple: $ git commit -m message If you want to provide a longer commit message, you can use your editor by running: $ git commit Note that the first line of a commit message should be a short summary, and the second line must be blank. Any further lines can contain more details about the commit. clone branch edit status diff stage check commit merge/push

Slide 18

Slide 18 text

Merging your branch back After the feature is finished, the branch needs to be merged back. First, change to master: $ git checkout master Next, pull any recent changes from the central repository: $ git pull Then merge in the branch and push it back to the main repository: $ git merge branch $ git push clone branch edit status diff stage check commit merge/push

Slide 19

Slide 19 text

Basic workflow summary $ git clone url dir $ cd dir $ git co -b branch edit files... $ git status $ git diff $ git add . $ git status -v $ git commit -m message $ git checkout master $ git pull $ git merge branch $ git push Feature loop Commit loop

Slide 20

Slide 20 text

Remember! • Git is not Subversion • All commits are local until you push them! • Make sure you push branches regularly (e.g. daily) • If your machine dies, unpushed commits will be lost • Git commands work on the whole repository, not just the current directory and those below • Git works best when you frequently make many small commits

Slide 21

Slide 21 text

Other useful commands There are two other commands that are useful to know, although you may not use them every day: • git stash — “stash” and restore your changes to the working copy, if you need it to be clean • git bisect — quickly narrow down the commit which introduced a bug (to be covered later)

Slide 22

Slide 22 text

git stash • You may find you need to interrupt what you’re doing in order to fix a bug, without wanting to commit • Although it’s possible to go back and edit commits that haven’t been pushed, it can be troublesome • git stash will save the current state of your working copy to a stack, then reset it to being clean • You can switch branches or do whatever is necessary to fix the immediate issue • When you’re done, switch back to the branch you were on and run git stash pop to return to where you last were

Slide 23

Slide 23 text

git stash ...work work work need to fix an urgent bug! $ git stash your working copy is now clean, with no uncommitted changes $ git checkout master $ git pull do emergency fix $ git add . $ git commit -m 'Emergency fix for bug' $ git push $ git stash list stash@{0}: On mybranch: Added threading stash@{1}: On other-branch: Fixed widget $ git checkout mybranch $ git stash pop work work work ...

Slide 24

Slide 24 text

Branching and Merging

Slide 25

Slide 25 text

History Styles • History in Subversion is mostly linear: • Monotonically increasing global revision IDs • Branching can be expensive, slow, and inconvenient • Branches are often only made for large features

Slide 26

Slide 26 text

History Styles • History in Subversion is mostly linear: • Monotonically increasing global revision IDs • Branching can be expensive, slow, and inconvenient • Branches are often only made for large features • In git, history tends to be very branchy: • No sequential revision IDs • Branching is easy, fast, and convenient • Tend to create tiny branches for each individual feature

Slide 27

Slide 27 text

Subversion branching • In Subversion, a branch is a cheap copy of trunk (or another branch) • Once you commit to a branch, that commit always belongs to that branch

Slide 28

Slide 28 text

Subversion branching • In Subversion, a branch is a cheap copy of trunk (or another branch) • Once you commit to a branch, that commit always belongs to that branch • Branches can be deleted without being merged, but are still recoverable by traversing history

Slide 29

Slide 29 text

Subversion branching • In Subversion, a branch is a cheap copy of trunk (or another branch) • Once you commit to a branch, that commit always belongs to that branch • Branches can be deleted without being merged, but are still recoverable by traversing history • Merging or cherry-picking loses information about where the changes came from (unless mentioned in the commit message)

Slide 30

Slide 30 text

Subversion branching • In Subversion, a branch is a cheap copy of trunk (or another branch) • Once you commit to a branch, that commit always belongs to that branch • Branches can be deleted without being merged, but are still recoverable by traversing history • Merging or cherry-picking loses information about where the changes came from (unless mentioned in the commit message) • Merging also squashes an entire branch worth of changes into a single commit

Slide 31

Slide 31 text

Subversion branching • In Subversion, a branch is a cheap copy of trunk (or another branch) • Once you commit to a branch, that commit always belongs to that branch • Branches can be deleted without being merged, but are still recoverable by traversing history • Merging or cherry-picking loses information about where the changes came from (unless mentioned in the commit message) • Merging also squashes an entire branch worth of changes into a single commit • A bit like copying an entire directory with cp -r

Slide 32

Slide 32 text

Subversion branching You start out with commits on trunk trunk

Slide 33

Slide 33 text

Subversion branching You then create mybranch via svn cp trunk mybranch

Slide 34

Slide 34 text

Subversion branching One commit later on trunk. . . trunk mybranch

Slide 35

Slide 35 text

Subversion branching You create yourbranch via svn cp trunk mybranch yourbranch

Slide 36

Slide 36 text

Subversion branching A few commits later on all branches, you decide to merge mybranch back into trunk trunk mybranch yourbranch

Slide 37

Slide 37 text

Subversion branching You change to trunk and run svn merge .../mybranch with the right revision range to import the changes, and commit trunk mybranch yourbranch

Slide 38

Slide 38 text

Subversion branching At any given time, these commits are on their branch and only ever on that branch trunk mybranch yourbranch

Slide 39

Slide 39 text

Subversion branching Notice that this commit is on trunk and embodies all the changes from mybranch, but Subversion does not remember where it came from – it looks like a normal commit

Slide 40

Slide 40 text

Git branching • In Git, a branch is a convenient non-permanent name for a commit • The branch a commit belongs to is any branch it is reachable from • This means that if you trace a path back from a branch to the root, all of the commits you pass through are reachable from that branch

Slide 41

Slide 41 text

Git branching • In Git, a branch is a convenient non-permanent name for a commit • The branch a commit belongs to is any branch it is reachable from • This means that if you trace a path back from a branch to the root, all of the commits you pass through are reachable from that branch • If an unmerged, unpushed branch is deleted, it is gone*

Slide 42

Slide 42 text

Git branching • In Git, a branch is a convenient non-permanent name for a commit • The branch a commit belongs to is any branch it is reachable from • This means that if you trace a path back from a branch to the root, all of the commits you pass through are reachable from that branch • If an unmerged, unpushed branch is deleted, it is gone* • Cherry-picking loses ancestry by default, but can be easily changed

Slide 43

Slide 43 text

Git branching • In Git, a branch is a convenient non-permanent name for a commit • The branch a commit belongs to is any branch it is reachable from • This means that if you trace a path back from a branch to the root, all of the commits you pass through are reachable from that branch • If an unmerged, unpushed branch is deleted, it is gone* • Cherry-picking loses ancestry by default, but can be easily changed • Merging keeps the branch, but loses the name attached to it

Slide 44

Slide 44 text

Git branching • In Git, a branch is a convenient non-permanent name for a commit • The branch a commit belongs to is any branch it is reachable from • This means that if you trace a path back from a branch to the root, all of the commits you pass through are reachable from that branch • If an unmerged, unpushed branch is deleted, it is gone* • Cherry-picking loses ancestry by default, but can be easily changed • Merging keeps the branch, but loses the name attached to it • A bit like creating a symlink with ln -s

Slide 45

Slide 45 text

Git branching You start out with commits on trunk trunk

Slide 46

Slide 46 text

Git branching You then create mybranch via git br, which is not a commit trunk mybranch

Slide 47

Slide 47 text

Git branching One commit later on trunk. . . trunk mybranch

Slide 48

Slide 48 text

Git branching You create yourbranch via git br trunk mybranch yourbranch

Slide 49

Slide 49 text

Git branching As you commit to each branch, their pointers move trunk mybranch yourbranch

Slide 50

Slide 50 text

Git branching A few commits later, you’re ready to merge mybranch back into trunk trunk mybranch yourbranch

Slide 51

Slide 51 text

Git branching To merge, change to trunk (git checkout trunk) and import the changes by running git merge mybranch trunk mybranch yourbranch

Slide 52

Slide 52 text

Git branching Notice that this commit is on trunk, and all of mybranch is reachable from it. If you delete mybranch, then its history remains. trunk mybranch yourbranch

Slide 53

Slide 53 text

That’s great and all, but. . . • . . . what are the advantages? • Git’s branch tracking lets you do complicated merges really easily • Long-lived feature branches are trivial • Branching and merging is no longer something to fear! • Let’s see an example

Slide 54

Slide 54 text

Long-lived feature branch After your big-feature branch has been running for a while, you need something from trunk trunk big-feature

Slide 55

Slide 55 text

Long-lived feature branch Simply merge the commits from trunk and carry on trunk big-feature

Slide 56

Slide 56 text

Long-lived feature branch A few commits later, there is a fix on trunk that you also need. . . trunk big-feature

Slide 57

Slide 57 text

Long-lived feature branch Just merge again from trunk to big-feature, and git will work out what to do trunk big-feature

Slide 58

Slide 58 text

Long-lived feature branch Eventually you’re at the stage where you’re ready to merge big-feature back into trunk trunk big-feature

Slide 59

Slide 59 text

Long-lived feature branch Change to trunk, run git merge big-feature and git will merge back with few or no problems trunk big-feature

Slide 60

Slide 60 text

Release management qa live master 20101204-163152 20101211-145819

Slide 61

Slide 61 text

Release management qa live master 20101204-163152 20101211-145819 All development happens around the master branch

Slide 62

Slide 62 text

Release management qa live master 20101204-163152 20101211-145819 Prepare to deploy by merging from master to qa

Slide 63

Slide 63 text

Release management qa live master 20101204-163152 20101211-145819 All fixes happen on master so qa is kept merge-only

Slide 64

Slide 64 text

Release management qa live master 20101204-163152 20101211-145819 A deploy is simply a merge from qa to live plus a tag

Slide 65

Slide 65 text

Release management qa live master 20101204-163152 20101211-145819 Hotfixes happen on live and get merged back to master

Slide 66

Slide 66 text

Things to remember • Git has very powerful merge tracking

Slide 67

Slide 67 text

Things to remember • Git has very powerful merge tracking • Because it tracks content, it can even handle changes to a file that has been renamed in another branch

Slide 68

Slide 68 text

Things to remember • Git has very powerful merge tracking • Because it tracks content, it can even handle changes to a file that has been renamed in another branch • Problems are only likely to come up if: • the same part of a file is edited in both branches and git can’t work out a resolution

Slide 69

Slide 69 text

Things to remember • Git has very powerful merge tracking • Because it tracks content, it can even handle changes to a file that has been renamed in another branch • Problems are only likely to come up if: • the same part of a file is edited in both branches and git can’t work out a resolution • a file is deleted (not moved) in one branch and edited in another

Slide 70

Slide 70 text

Things to remember • Git has very powerful merge tracking • Because it tracks content, it can even handle changes to a file that has been renamed in another branch • Problems are only likely to come up if: • the same part of a file is edited in both branches and git can’t work out a resolution • a file is deleted (not moved) in one branch and edited in another • two files are created with the same path in each branch

Slide 71

Slide 71 text

Tracking down bugs

Slide 72

Slide 72 text

Final bit of git magic (for now) • Sometimes a bug is found that has probably existed for a long time, as an unexpected side-effect of an earlier change • If you know that it used to work, then tracking down the commit which actually caused the bug can be a big task • This is where git bisect comes in useful

Slide 73

Slide 73 text

git bisect • git bisect allows you to do a binary search on commits to find the one that caused the bug • You could manually jump between revisions, but that’s very time-consuming • With git bisect you must still find a good commit, but you can just keep jumping back in history to find it • Just tell git whether a commit is good or bad, and it does the rest • Note: needs a clean working copy when you begin

Slide 74

Slide 74 text

git bisect We know that the current commit is bad and contains a bug that wasn’t there before, but we don’t know when it was introduced. We start git bisect, (using git stash to save changes from our working copy if necessary): $ git bisect start

Slide 75

Slide 75 text

git bisect We know that the current commit is bad and contains a bug that wasn’t there before, but we don’t know when it was introduced. We start git bisect, (using git stash to save changes from our working copy if necessary): $ git bisect start We now mark the current commit as being “bad” (i.e. it has the bug) $ git bisect bad

Slide 76

Slide 76 text

git bisect We then jump back in history (say fifteen commits at a time) until we find a commit without the bug. $ git checkout HEAD~15 Note: To better illustrate what git checkout is doing, the animation goes back 5 commits at a time.

Slide 77

Slide 77 text

git bisect We then jump back in history (say fifteen commits at a time) until we find a commit without the bug. $ git checkout HEAD~15 Note: To better illustrate what git checkout is doing, the animation goes back 5 commits at a time.

Slide 78

Slide 78 text

git bisect We then jump back in history (say fifteen commits at a time) until we find a commit without the bug. $ git checkout HEAD~15 Note: To better illustrate what git checkout is doing, the animation goes back 5 commits at a time.

Slide 79

Slide 79 text

git bisect We then jump back in history (say fifteen commits at a time) until we find a commit without the bug. $ git checkout HEAD~15 Note: To better illustrate what git checkout is doing, the animation goes back 5 commits at a time.

Slide 80

Slide 80 text

git bisect This commit doesn’t have the bug, so we mark it as “good” (i.e. the bug isn’t there). $ git bisect good

Slide 81

Slide 81 text

git bisect This commit doesn’t have the bug, so we mark it as “good” (i.e. the bug isn’t there). $ git bisect good As soon as we do this, git automatically checks out the next com- mit we should test.

Slide 82

Slide 82 text

git bisect We now continue marking commits as “good” or “bad”, and git immediately chooses a next possibility. . .

Slide 83

Slide 83 text

git bisect We now continue marking commits as “good” or “bad”, and git immediately chooses a next possibility. . .

Slide 84

Slide 84 text

git bisect We now continue marking commits as “good” or “bad”, and git immediately chooses a next possibility. . .

Slide 85

Slide 85 text

git bisect We now continue marking commits as “good” or “bad”, and git immediately chooses a next possibility. . .

Slide 86

Slide 86 text

git bisect We now continue marking commits as “good” or “bad”, and git immediately chooses a next possibility. . .

Slide 87

Slide 87 text

git bisect We now continue marking commits as “good” or “bad”, and git immediately chooses a next possibility. . .

Slide 88

Slide 88 text

git bisect We now continue marking commits as “good” or “bad”, and git immediately chooses a next possibility. . .

Slide 89

Slide 89 text

git bisect We now continue marking commits as “good” or “bad”, and git immediately chooses a next possibility. . .

Slide 90

Slide 90 text

git bisect git now reports that this commit is one that introduced the bug, and so it can be examined to find the source of the bug.

Slide 91

Slide 91 text

git bisect After noting down the commit ID for later examination, you need to go back to where you started to carry on working. All you need to do is finish git bisect and perhaps run git stash pop if we had any stashed changes from before. $ git bisect reset

Slide 92

Slide 92 text

git bisect After noting down the commit ID for later examination, you need to go back to where you started to carry on working. All you need to do is finish git bisect and perhaps run git stash pop if we had any stashed changes from before. $ git bisect reset Done!

Slide 93

Slide 93 text

git bisect summary $ git bisect start The current commit has the bug $ git bisect bad Jump back 10 commits (repeat until good commit found) $ git checkout HEAD~10 When this commit does not have the bug. .. $ git bisect good Git automatically checks out commits to test – decide if pass/fail $ git bisect good|bad Eventually git tells you which commit is bad Investigate... $ git bisect reset Back where you started work work work ...

Slide 94

Slide 94 text

Questions?