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

Getting more from Git

Getting more from Git

I gave this talk at #FFconf in Brighton in November 2019.
This talk covers:
- What is "good" for Git?
- Why are we not very good at Git?
- A bit of history about Git. Who is she? Where did she come from?
- Some tips for using Git - --patch adding, --amending, using reset and rebase.

Alice Bartlett

November 08, 2019
Tweet

More Decks by Alice Bartlett

Other Decks in Technology

Transcript

  1. @alicebartlett 1. Let’s all get a bit better at Git

    2. Let’s have an interesting 40 minutes
  2. @alicebartlett I think we could all do better with our

    Git mastery. To understand what “bad” looks like, I have found someone to make an example of
  3. @alicebartlett This is the codebase for the FT’s web app.

    It is 9 years old, and still going strong.
  4. @alicebartlett Update link style User research showed that many people

    did not spot links in the copy. This commit updates the link style to the new underlined style which performed better.
  5. @alicebartlett // Scannable summary // Body that // explains //

    *why* Update link style User research showed that many people did not spot links in the copy. This commit updates the link style to the new underlined style which performed better.
  6. @alicebartlett Fix background download There is a bug in the

    window.history.pushState implementation in Android Honeycomb so always use the location hash instead until that is fixed.
  7. 2. What is Git 3. Tips for rewriting your Git

    history 1. Why should you care
  8. 2. What is Git 3. Tips for rewriting your Git

    history 1. Why should you care
  9. @alicebartlett None of these things are necessary to ship a

    feature. But they are necessary for helping other people understand our code and maintain it.
  10. @alicebartlett Your commits, if you do them well, offer unique

    benefits over other ways of explaining your code:
  11. @alicebartlett 1. They never change 2. They live alongside your

    code 3. They’re searchable with Git grep
  12. @alicebartlett 1. They never change 2. They live alongside your

    code 3. They’re searchable with Git grep 4. They allow you to document your change at the time that you made it
  13. @alicebartlett 1. They never change 2. They live alongside your

    code 3. They’re searchable with Git grep 4. They allow you to document your change at the time that you made it 5. They are hosting independent
  14. @alicebartlett My second reason you should care about writing good

    commits is: it will make you a better software developer
  15. @alicebartlett Secondly, in order to write down why you introduced

    a change to a codebase, you have to actually understand why you introduced a change
  16. @alicebartlett Explaining why is an important thing to do as

    an engineer — it forces you to understand things you could otherwise have gotten away with not understanding
  17. @alicebartlett One of the reasons little baby me found writing

    good commits hard was that when I started writing code, a lot of my process was “try things until it works”
  18. @alicebartlett This meant it took me a lot longer to

    gain a deeper understanding of how things work
  19. 1. Why should you care? • The code is better

    - which is better for you because you have to maintain it • It makes you smarter
  20. 2. What is Git 3. Tips for rewriting your Git

    history 1. Why should you care
  21. @alicebartlett He is known for emails to the Linux mailing

    list containing comments that I don’t want to repeat here but they are very very unpleasant
  22. @alicebartlett When he created Git, it was described as a

    tool expressly designed to make you feel less intelligent than you thought you were
  23. @alicebartlett Up until 2005, Linux development had used a version

    control system called BitKeeper, and prior to that, they just emailed tarballs around
  24. @alicebartlett One of the Linux contributors, Andrew Tridgell, decided to

    create an open source BitKeeper client as he didn’t think it was right to use a closed source client to work on an open source project
  25. @alicebartlett Which meant development on the Linux kernel had to

    pause while a new version control system was found
  26. @alicebartlett So Linus creates Git - he knows a lot

    about file system performance so he’s able to make it about an order of magnitude faster than its competitors across lots of operations — reading, committing and diffing
  27. @alicebartlett Let’s take a quick look at some of the

    ways Git was really different from CVS and Subversion, two popular alternatives back In 2005
  28. @alicebartlett One of the design choices for Git which is

    very different to its major competitors is that it is distributed
  29. @alicebartlett • No network connection needed • Common operations like

    committing are quicker • You can try things in private
  30. @alicebartlett • No network connection needed • Common operations like

    committing are quicker • You can try things in private • There is no single point of failure because there’s no central server
  31. @alicebartlett • No network connection needed • Common operations like

    committing are quicker • You can try things in private • There is no single point of failure because there’s no central server • Much easier to give people access to noodle around
  32. @alicebartlett In 2007, Linus gave a talk at Google about

    Git and the benefits of distributed version control and he got about three questions that were all variations of…
  33. @alicebartlett All branches existed in a global namespace, you couldn’t

    have a little private branch to do your experiments on
  34. @alicebartlett Branches were considered a really advanced technique in CVS

    and SVN, so most people just didn’t use them.
  35. @alicebartlett If you’re not using branches though revising your history

    becomes super annoying for your colleagues who will already have your first set of changes
  36. @alicebartlett If you're not using branches, and you only have

    a central repository, committing becomes really difficult because all the tests have to pass, and the commit must make sense in isolation
  37. @alicebartlett OK so — we agree: 1. Doing version control

    properly is important 2. Git is really good, actually.
  38. @alicebartlett So to figure this stuff out you have to

    go read the manual. But the manual is also really confusing!
  39. @alicebartlett This is why we’re so bad at Git. Because

    its user interface is badly designed.
  40. 2. What is Git? • A version control system created

    to manage the Linux kernel • Radically different to pre-existing version control systems • Bad user interface
  41. 2. What is Git? 3. Tips for rewriting your Git

    history 1. Why should you care
  42. @alicebartlett Before you can commit something, you have to add

    it to the list of things you want to commit.
  43. @alicebartlett When you have some lines in your file that

    you want to commit but some that you don’t — use git add --patch
  44. @alicebartlett Using git add --patch means that even if you’ve

    failed to work atomically, ie you have ended up with multiple changes in the same file, you can still commit atomically
  45. @alicebartlett git add --patch will ask you which bits of

    a file you want to add. It calls these “bits” hunks.
  46. $ git add --patch diff --git a/config/playlist.js b/config/playlist.js index 7e54d1a..eba4bf5

    100644 --- a/config/playlist.js +++ b/config/playlist.js @@ -28,14 +28,6 @@ const playlistConfigs = { videos: byDuration }) }, - popular: { - query: queries['popular-videos'], - dataReader: ({ data: { video: { popular = []}} = {}} = {}) => ({ - videos: popular - }) - }, section: { query: queries['section-videos'], dataReader: ({ data: { section = {}} = {}} = {}) => { Stage this hunk [y,n,q,s,e,?]?
  47. $ git add --patch diff --git a/config/playlist.js b/config/playlist.js index 7e54d1a..eba4bf5

    100644 --- a/config/playlist.js +++ b/config/playlist.js @@ -28,14 +28,6 @@ const playlistConfigs = { videos: byDuration }) }, - popular: { - query: queries['popular-videos'], - dataReader: ({ data: { video: { popular = []}} = {}} = {}) => ({ - videos: popular - }) - }, section: { query: queries['section-videos'], dataReader: ({ data: { section = {}} = {}} = {}) => { Stage this hunk [y,n,q,s,e,?]? Nice diff of your changes
  48. $ git add --patch diff --git a/config/playlist.js b/config/playlist.js index 7e54d1a..eba4bf5

    100644 --- a/config/playlist.js +++ b/config/playlist.js @@ -28,14 +28,6 @@ const playlistConfigs = { videos: byDuration }) }, - popular: { - query: queries['popular-videos'], - dataReader: ({ data: { video: { popular = []}} = {}} = {}) => ({ - videos: popular - }) - }, section: { query: queries['section-videos'], dataReader: ({ data: { section = {}} = {}} = {}) => { Stage this hunk [y,n,q,s,e,?]?
  49. @alicebartlett Stage this hunk [y,n,q,s,e,?]? y: yes add this to

    the things I want to commit n: no, leave this hunk alone q: quit s: split this hunk into smaller hunks e: manually edit the hunk ?: tell me about these options
  50. @alicebartlett Stage this hunk [y,n,q,s,e,?]? y: yes add this to

    the things I want to commit n: no, leave this hunk alone q: quit s: split this hunk into smaller hunks e: manually edit the hunk ?: tell me about these options
  51. @alicebartlett So git commit is something you’ll have used many

    times if you’ve used git. git commit --amend lets you amend your last commit.
  52. @alicebartlett When you use git commit --amend you completely replace

    the last commit with a new one and it will commit everything that’s currently staged.
  53. 377dfcd00dd057542b112cf13be6cf1380b292ad 20-05-2016: Fix broken sign up buttno CSS $ git

    commit --amend 439301fe69e8f875c049ad0718386516b4878e22 20-05-2016: Fix broken sign up button CSS
  54. @alicebartlett git reset moves changes back through these structures What

    gets moved depends on the arguments you call reset with
  55. @alicebartlett Calling git reset with no additional arguments moves any

    changes on the Staging Index back to the Working Directory. Nothing happens to the commit history. git reset
  56. @alicebartlett Calling git reset <sha> will move all changes from

    any commit after the id you’ve given it back to the Working Directory git reset <sha>
  57. @alicebartlett Calling git reset <sha> will move all changes from

    any commit after the id you’ve given it back to the Working Directory git reset <sha> Commit <sha>
  58. @alicebartlett You can also call git reset with the --hard

    option. This will reset the pointers to commit <sha> and DELETE the contents of you working Directory. Any uncommitted changes in your working directory or staging index are lost git reset <sha> --hard
  59. @alicebartlett You can also call git reset with the --hard

    option. This will reset the pointers to commit <sha> and DELETE the contents of you working Directory. Any uncommitted changes in your working directory or staging index are lost git reset <sha> --hard Gone!
  60. @alicebartlett 1. git add and git add --patch to selectively

    move changes from Working Directory to Staging 2. git commit --amend to quickly change commit messages 3. git reset to move work backwards in workflow
  61. @alicebartlett Start End Start End In the last bit we

    covered making and undoing commits, now we’re going to look at changing larger bits of your commit history
  62. @alicebartlett git rebase allows you to literally rewrite your history.

    This is very useful as often, through making changes, new or better ways of doing things or ordering changes reveal themselves
  63. @alicebartlett Rebasing replays your changes over a branch. You take

    the patch of one commit and apply it to a different commit
  64. @alicebartlett feature branch master Rebasing is changing the base of

    your branch from one commit to another, making it look as if you had created a branch from a different commit HEAD
  65. @alicebartlett feature branch If you're working on a feature and

    want to bring in changes from master that happen in the interim, rebasing stops you from having lots of merge commits merge commit
  66. @alicebartlett Rebasing on it’s own is kind of interesting, but

    the really useful stuff happens with git rebase --interactive
  67. @alicebartlett On the feature branch and we run: git rebase

    --interactive origin/master feature branch master
  68. @alicebartlett pick a8f83c27 Remove CommentFactory documentation pick cf19c147 Whitespace changes

    pick 637bf758 Add commentwer mock pick fb274f86 Whitespace # Rebase 66d43b29..fb274f86 onto 66d43b29 (5 commands) # # Commands: # p, pick <commit> = use commit # r, reword <commit> = use commit, but edit the commit message # e, edit <commit> = use commit, but stop for amending # s, squash <commit> = use commit, but meld into previous commit # f, fixup <commit> = like "squash", but discard this commit's log message # x, exec <command> = run command (the rest of the line) using shell # d, drop <commit> = remove commit # l, label <label> = label current HEAD with a name # t, reset <label> = reset HEAD to a label # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>] # # [… etc… ]
  69. @alicebartlett A list of commits pick a8f83c27 Remove CommentFactory documentation

    pick cf19c147 Whitespace changes pick 637bf758 Add commentwer mock pick fb274f86 Whitespace # Rebase 66d43b29..fb274f86 onto 66d43b29 (5 commands) # # Commands: # p, pick <commit> = use commit # r, reword <commit> = use commit, but edit the commit message # e, edit <commit> = use commit, but stop for amending # s, squash <commit> = use commit, but meld into previous commit # f, fixup <commit> = like "squash", but discard this commit's log message # x, exec <command> = run command (the rest of the line) using shell # d, drop <commit> = remove commit # l, label <label> = label current HEAD with a name # t, reset <label> = reset HEAD to a label # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>] # # [… etc… ]
  70. @alicebartlett A list of commands pick a8f83c27 Remove CommentFactory documentation

    pick cf19c147 Whitespace changes pick 637bf758 Add commentwer mock pick fb274f86 Whitespace # Rebase 66d43b29..fb274f86 onto 66d43b29 (5 commands) # # Commands: # p, pick <commit> = use commit # r, reword <commit> = use commit, but edit the commit message # e, edit <commit> = use commit, but stop for amending # s, squash <commit> = use commit, but meld into previous commit # f, fixup <commit> = like "squash", but discard this commit's log message # x, exec <command> = run command (the rest of the line) using shell # d, drop <commit> = remove commit # l, label <label> = label current HEAD with a name # t, reset <label> = reset HEAD to a label # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>] # # [… etc… ]
  71. @alicebartlett pick a8f83c27 Remove CommentFactory documentation pick cf19c147 Whitespace changes

    pick 637bf758 Add commentwer mock pick fb274f86 Whitespace Lets merge these two commits as they’re both just whitespace changes
  72. @alicebartlett pick a8f83c27 Remove CommentFactory documentation pick cf19c147 Whitespace changes

    squash fb274f86 Whitespace pick 637bf758 Add commentwer mock We can use “squash” to do that
  73. @alicebartlett pick a8f83c27 Remove CommentFactory documentation pick cf19c147 Whitespace changes

    squash fb274f86 Whitespace pick 637bf758 Add commentwer mock Let’s also fix this typo using the re-word option
  74. @alicebartlett pick a8f83c27 Remove CommentFactory documentation pick cf19c147 Whitespace changes

    squash fb274f86 Whitespace reword 637bf758 Add commentwer mock Let’s also fix this typo using the re-word option
  75. @alicebartlett Once you close that rebase file Git will step

    you through each of the commands from top to bottom, stopping when your input is required
  76. @alicebartlett feature HEAD pick a8f83c27 Remove CommentFactory documentation pick cf19c147

    Whitespace changes squash fb274f86 Whitespace reword 637bf758 Add commentwer mock
  77. @alicebartlett pick a8f83c27 Remove CommentFactory documentation pick cf19c147 Whitespace changes

    squash fb274f86 Whitespace reword 637bf758 Add commentwer mock pick feature HEAD
  78. @alicebartlett pick a8f83c27 Remove CommentFactory documentation pick cf19c147 Whitespace changes

    squash fb274f86 Whitespace reword 637bf758 Add commentwer mock pick feature HEAD
  79. @alicebartlett pick a8f83c27 Remove CommentFactory documentation pick cf19c147 Whitespace changes

    squash fb274f86 Whitespace reword 637bf758 Add commentwer mock squash feature HEAD
  80. @alicebartlett pick a8f83c27 Remove CommentFactory documentation pick cf19c147 Whitespace changes

    squash fb274f86 Whitespace reword 637bf758 Add commentwer mock reword feature HEAD
  81. @alicebartlett feature HEAD pick a8f83c27 Remove CommentFactory documentation pick cf19c147

    Whitespace changes squash fb274f86 Whitespace reword 637bf758 Add commenter mock
  82. @alicebartlett Old Mac Donald had a farm eee-eye-eee-eye-oh and on

    that farm he had some cows eee-eye-eee-eye-oh! With a moo moo here! and a moo moo there! here a moo! there a moo! everywhere a moo moo! Old Mac Donald had a farm eee-eye-eee-eye-oh
  83. @alicebartlett Old Mac Donald had a farm eee-eye-eee-eye-oh and on

    that farm he had some cows eee-eye-eee-eye-oh! With a moo moo here! and a moo moo there! here a moo! there a moo! everywhere a moo moo! Old Mac Donald had a farm eee-eye-eee-eye-oh Initial commit
  84. @alicebartlett Old Mac Donald had a farm eee-eye-eee-eye-oh and on

    that farm she had some cows eee-eye-eee-eye-oh! With a moo moo here! and a moo moo there! here a moo! there a moo! everywhere a moo moo! Old Mac Donald had a farm eee-eye-eee-eye-oh Initial commit Change gender"
  85. @alicebartlett Old Mac Donald had a farm eee-eye-eee-eye-oh and on

    that farm she had some wheat eee-eye-eee-eye-oh! With a swish swish here! and a swish swish there! here a swish! there a swish! everywhere a swish swish! Old Mac Donald had a farm eee-eye-eee-eye-oh Initial commit Change gender" Farm wheat
  86. @alicebartlett Old Mac Donald had a farm eee-eye-eee-eye-oh and on

    that farm they had some wheat eee-eye-eee-eye-oh! With a swish swish here! and a swish swish there! here a swish! there a swish! everywhere a swish swish! Old Mac Donald had a farm eee-eye-eee-eye-oh Initial commit Change gender" Farm wheat Use singular they
  87. @alicebartlett Initial commit Change gender" Farm wheat Use singular they

    Let’s delete this from commit. We don't need it, it doesn’t help tell the story of our project
  88. @alicebartlett pick a Initial commit pick b Change gender "

    pick c Farm wheat pick d Use singular they Initial commit Change gender" Farm wheat Use singular they
  89. @alicebartlett Initial commit Change gender" Farm wheat Use singular they

    pick a Initial commit pick c Farm wheat pick d Use singular they
  90. @alicebartlett Auto-merging old-mac-donald.txt CONFLICT (content): Merge conflict in old-mac-donald.txt error:

    could not apply C... Farm wheat Resolve all conflicts manually, mark them as resolved with "git add/rm <conflicted_files>", then run "git rebase --continue". You can instead skip this commit: run "git rebase --skip". To abort and get back to the state before "git rebase", run "git rebase --abort". Could not apply C... Farm wheat
  91. @alicebartlett Auto-merging old-mac-donald.txt CONFLICT (content): Merge conflict in old-mac- donald.txt

    error: could not apply C... Farm wheat Resolve all conflicts manually, mark them as resolved with "git add/rm <conflicted_files>", then run "git rebase --continue". You can instead skip this commit: run "git rebase --skip". To abort and get back to the state before "git rebase", run "git rebase --abort". Could not apply C... Farm wheat Initial commit Change gender" Farm wheat Use singular they
  92. @alicebartlett $ git show b commit b [...] eee-eye-eee-eye-oh -and

    on that farm he had some cows +and on that farm she had some cows eee-eye-eee-eye-oh! [...]
  93. @alicebartlett $ git show c commit c [...] eee-eye-eee-eye-oh -and

    on that farm she had some cows +and on that farm she had some wheat eee-eye-eee-eye-oh! [...]
  94. @alicebartlett eee-eye-eee-eye-oh <<<<<<< HEAD and on that farm he had

    some cows ======= and on that farm she had some wheat >>>>>>> c... Switch to wheat eee-eye-eee-eye-oh!
  95. @alicebartlett eee-eye-eee-eye-oh and on that farm he had some wheat

    eee-eye-eee-eye-oh! And now we’re good to go — we can add that change and continue run git rebase --continue
  96. @alicebartlett And you have single handedly saved the planet and

    destroyed the gender binary in a two commit messages while also overcoming a merge conflict and maintaining a clean Git history. Not bad. Initial commit Farm wheat Use singular they
  97. @alicebartlett 1. git rebase to pull in any changes from

    another branch for a neater history without any merge commits 2. git rebase --interactive to edit and restructure multiple commits before you push them
  98. 3. Tips for Git history management • Use git add

    --patch to help iron out your messy working process from the history • Gateway drug: git commit --amend • Use git reset to undo things in the history • Use git rebase for redo things in the history
  99. 2. What is Git 3. Tips for rewriting your Git

    history 1. Why should you care
  100. @alicebartlett 1. Noun Project Faces by Sarah Rudkin: https:// thenounproject.com/sarahdrudkin/collection/faces/

    2. Linus Torvalds at Google 2007: https://www.youtube.com/ watch?v=4XpnKHJAok8 3. Tekin Süleyman’s A Branch In Time: https:// www.youtube.com/watch?v=1NoNTqank_U 4. Git man page generator: https://git-man-page- generator.lokaltog.net/