[Notes] A Tale of Three Trees by @chacon


Here’s some more Strange Loop 2011 material–this time about a talk on git given by Scott Chacon (@chacon)!

In his talk, Scott focuses on demystifying git’s reset command through an explanation of git’s three trees: HEAD, index, and the working tree. Toward the end of the talk, he also includes some of Git’s plumbing goodies that can be useful in local scripts for automatic backup, cleaning past commits, and so forth.

Hope you enjoy the notes. As always, I typed quickly and so guarantee absolutely no accuracy. You might reference these notes with his slides (warning: PDF).


  • Head
    • Indirect pointer to the last commit
    • Points to a tree
  • Index
  • Working Directory
  • Tree Roles
    • Last commit, next parent
    • Index proposed next commit
      • Could git add everything, rm all files, and git commit would still work just fine
    • Work Dir sandbox
  • git status tells you the diff of the three trees

git reset

  • A tool to manipulate these three trees
    • Path Form: git reset [file]
      • Opposite of git add [file]
      • Takes entry from HEAD and make index look like that
      • Lets you manipulate your index without touching your working directory.
    • Commit form: git reset [commit]
      • Does three things in order. The option determines where in this process it stops.
      • --soft: move HEAD to target
        • Moving the branch to somewhere else. Does not change index or working directory; just changes where the branch points.
        • git reset --soft HEAD~
          • HEAD~: parent of HEAD
          • Undoes results of last commit.
      • [--mixed]: then copy to index
        • Takes what HEAD is pointing at and makes your index look like that.
      • --hard – then copy to work dir
        • Touches your working directory
  • Can use this to squash the last two commits into one
    • git reset --soft HEAD~2; git commit
      • Moves HEAD back tw ocommits, keep index
    • Awesome for staging your work in progress and then making one nice, beautiful commit
  • git checkout
    • git checkout [commit] [path]
    • git checkout [commit]
    • If you’re in a dev branch and have made some commits:
      • git reset master will move your index to where the branch started
      • git checkout master will move HEAD to point to master
    • reset vs. checkout
  • Patchy work
    • git add --patch [file]
    • git reset --patch (commit) [file]
    • git checkout --patch (commit) [file]
      • Revert parts of a file for commit


  • git add -p
    • Uses the index tree as a staging area for partial addition
  • git commit --amend == git reset --soft HEAD~; git commit ...
  • git log --stat (branch)

The Plumbing Commands

  • A summary of the below commands
  • rev-parse
    • Take any string you give it and tell you its SHA. E.g., git rev-parse origin/master
    • git rev-parse master~163^2~3^2 – walks backwards, does some cool stuff. Figures out its SHA.
    • Can do ranges: git rev-parse master~163^2~3^2..origin/master
  • hash-object
    • Use git as a raw key-value store
    • git hash-object -w ~/.sshid_rsa.pub
    • echo 'my awesome value' | git hash-object -w --stdin
      • Will return SHA and write into database
  • ls-files
    • git ls-files -s: shows you your staging area
  • read-tree
    • Reads a tree value into your index at a raw value git ls-files -s # show index git ls-files -r HEAD # show index git read-tree HEAD~2 # basically same as git reset
  • write-tree
    • Takes whatever your index looks like and writes it out as a tree object.
    • git write-tree: tells you the tree that a commit would make if you commited it.
    • Does not commit.
  • commit-tree
    • echo 'my commit message' | git commit-tree
    • Commits without git commit
  • update-ref
    • Part of git branch mechanism
    • Updates your reflog as well
    • git update-ref refs/heads/newbranch
  • symbolic-ref
    • Update HEAD itself
    • git symbolic-ref HEAD refs/heads/newbranch
  • Example usage
    • Could make an auto-backup system for your working directory
    • Publish documentation to another branch
  • These are all under the rules that you shouldn’t mess with history if you’ve already pushed that to people.
    • So, use this stuff locally.
← all posts

michael schade

I built out engineering and operations teams at Stripe as employee #20 from 2012 to 2019; now I'm working on something new. I like helping people, photography, reading, gym, traveling, and learning new things. Say hi! 🏳️‍🌈