The art of version control

Jeff Schomay

  • programmer
  • game designer
  • screenwriter
  • git fan

Appreciating your tools

Software development is organic.

We need a tool for non-linear development.

"Git is the magic sauce that bridges the linear process of writing code in the text editor, with the organic process of software development."

1. History

A good git history tells the story of how ideas turned into software.

2. Parallel development

Explore many solutions to the same problem.  Work on multiple things at once.

3. Collaboration

The closest thing to a "hive mind"

Making git in the command line better


Git-fu discipline #1: Git forensics

git forensics: comparisons


Option 1: use external software like SourceTree or Tower

Option 2: `gitk`

Option 3 (the cool way): `git log --graph --all --oneline --decorate` 
(you might want an alias)

Bonus: try adding `--simplify-by-decoration` to the above

Tip: add `-- path/to/file.ext` to any git log command to only see commits that changed that file (even if the file isn't in your working tree!)

Understanding Branches

Q: Which colour line represents the "dev" branch?

A: Trick question!  Branches are pointers to a single commit only.


Git graphs aren't trees, they are more like linked-lists.

Branches are merely references to the "loose ends."

The correct question is: "Which commits are down-stream from the commit referenced by the dev branch?"

(A: ALL of them, except fix_hook and forgery)

git forensics: comparisons

Comparing commits (.. vs ...)

`git log` = "What commits are unique to dev?" 
"What commits are reachable from dev, but not from master?"

`git log featureA...featureB` = "What commits are reachable from either featureA or featureB, but not both?"

* Use `--left-right with` ...
* Use `-p` or `--stat` to see changes by commit
* Use `git merge-base A B` to find the common commit between branches
* Use `..remote-name/branch-name` to compare to remotes
* Leave out either side of the ... to mean "use HEAD"
* Use `branchX..abc123` to find out if a branch has a specific commit in it (an empty result means it does, otherwise it doesn't)

Gotcha: git diff is different (see next slide)

git forensics: comparisons

Comparing code

`git diff A B` (or `git diff A..B`) to diff revisions

`git diff A...B` to see only diffs added by B

`git diff` to see diffs between working directory and index

`git diff --cached` to see diffs between staged files and index

Tip: use `git diff` and `git diff --cached` before a git commit

Tip: git pipes its output through less, so you can search with `/pattern<enter>` and use `n/N` for next/previous.

git forensics: searching

grep in git!

`git log --grep pattern` to search commit messages

`git grep -n pattern` to search index
Bonus: `git grep --help` for advanced searching

`git log -Spattern` to search diffs (see when you made changes to 'pattern')

git forensics: searching

Tracking down where things went wrong

git bisect to the rescue!

`git bisect --help`

git forensics: searching

git knows what you've done

Have you ever lost your commits after a rebase, reset, stash, etc?

The good news: No, you have not.

`git reflog`

There they are :)

Git-fu discipline #2: Manipulating state

manipulating state: changing code

You can change the state of your code in 2 ways:
1. Move yourself to the code
2. Bring the code to you

Move yourself to the code:
* `git checkout branchName`
Tip: relative refs are useful.
* `git reset HEAD~3` to go back 3 commits (brings your working directory with you unless you add `--hard`)


​Bring the code to you:
* `git merge branchName` (add `--no-commit` to make edits first)
Tip: `git add -i` or `git add -i` for partial committing.
Tip: `git mergetool` makes resolving merge conflicts much more fun.
Tip: Remember you can grab code from different remotes too.
* `git checkout abc123 -- path/to/file.ext` (add `-p` for super fine control extra awesomeness)

manipulating state: changing history

Why change history?  To clarify your story of development.
* Clarify commits
* Clarify messy branches

Warning!  Do not change history of public commits.

* `git commit src/fileIForgotToAdd.js --amend` (plus you can edit the commit message)
* `git reset HEAD~`, then `git add -i` if you commit too much
* `git reset ref` to change where your branch references (like resetting your messed up local branch to the version on the remote)

And of course, our good friend, Mr. Rebase!  (He's not so scary)

manipulating state: changing code

(maybe a little scary)

manipulating state: changing history

Rebasing: moving branches around

Who cares?: I do!!
Why?: They keep the history nice and flat:
* Avoid unintentional and unnecessary merge commits
* Correct haphazard branching-off points

Simply defined: `git rebase master feature` = "Remake all of the commits in `git log master..feature`, in order, one by one, off of the tip of master."

(Remember the warning: no rebasing public commits)

manipulating state: changing code

Neat Rebase tricks

* `git rebase --onto X A B` to rebase A..B onto X instead of the tip of A.  This is useful if you branched a feature off of a feature and want to move it to the main trunk (`git rebase --onto master featureA featureB`).

* Add `-i` for interactive rebasing (you get a chance to massage each commit before it gets remade).  Great for commits like "wip", "oops, forgot to update README" and "spelling fix."
But also: `git rebase HEAD~5 -i` to clean up the last 5 commits.

* `git pull --rebase` instead of git pull if your local branch has diverged from its upstream tracking branch.  Instead of creating a "merge origin/dev" commit, it will pull in the remote branch and rebase your local commits onto the tip of it.

Git resources

Review: git is awesome!


  • Why use git?  It helps us develop organically
  • Understanding branches is the path to mastering git
  • 2 disciplines of git-fu: git forensics & changing code state
  • Git is powerful, learn it, use it (`git command --help`)


Thank you



By Jeff Schomay