Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Being an Effective Git (User)

Being an Effective Git (User)

Making the Jump From Subversion.

Talk given at GroupSpaces HQ on 9th December 2010

Dave Ingram

March 23, 2012
Tweet

More Decks by Dave Ingram

Other Decks in Programming

Transcript

  1. Git is not Subversion • The two are very different

    • Not just in operation, but in the way you must think
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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
  9. Checking status $ git status # On branch branch #

    Changed but not updated: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: app/models/Comment.php # modified: app/views/CommentView.php # # Untracked files: # (use "git add <file>..." 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
  10. 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 @@ <?php require once('app/models/Article.php'); +require once('app/models/CommentThread.php'); class Comment extends Model { @@ -16,5 +17,75 @@ clone branch edit status diff stage check commit merge/push
  11. 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
  12. 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
  13. 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
  14. 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
  15. 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
  16. 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
  17. 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)
  18. 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
  19. 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 ...
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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)
  25. 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
  26. 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
  27. Subversion branching A few commits later on all branches, you

    decide to merge mybranch back into trunk trunk mybranch yourbranch
  28. 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
  29. Subversion branching At any given time, these commits are on

    their branch and only ever on that branch trunk mybranch yourbranch
  30. 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
  31. 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
  32. 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*
  33. 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
  34. 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
  35. 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
  36. Git branching A few commits later, you’re ready to merge

    mybranch back into trunk trunk mybranch yourbranch
  37. Git branching To merge, change to trunk (git checkout trunk)

    and import the changes by running git merge mybranch trunk mybranch yourbranch
  38. 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
  39. 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
  40. Long-lived feature branch After your big-feature branch has been running

    for a while, you need something from trunk trunk big-feature
  41. Long-lived feature branch A few commits later, there is a

    fix on trunk that you also need. . . trunk big-feature
  42. Long-lived feature branch Just merge again from trunk to big-feature,

    and git will work out what to do trunk big-feature
  43. Long-lived feature branch Eventually you’re at the stage where you’re

    ready to merge big-feature back into trunk trunk big-feature
  44. 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
  45. 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
  46. 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
  47. 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
  48. 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
  49. 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
  50. 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
  51. 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
  52. 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
  53. 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.
  54. 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.
  55. 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.
  56. 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.
  57. 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
  58. 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.
  59. git bisect We now continue marking commits as “good” or

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

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

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

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

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

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

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

    “bad”, and git immediately chooses a next possibility. . .
  67. 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.
  68. 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
  69. 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!
  70. 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 ...