- Traveling back in time
- Revert files back to a previous state
- Revert the entire project back to a previous state
- Compare changes over time
- See who last modified something that might be causing a problem
- Who introduced an issue and when
- Paralelizing your work
- Solving multiple issues separately
- Make a quick fix in the midst developing a feature
Version Control Systems (VCS)
Frequently making a backup
The caveman solution
Muggles still use this use this everyday
- Pretty straightforward
- Hard to manage over time
- Hard to collaborate
- Single point of failure
- CVS, Subversion, Perforce
- Standard solution for many years and still used by many
- Easier to collaborate
- Not too hard to understand
- Easier to administer a CVCS than it is to deal with local databases on every client
- Single point of failure
- Hard to work without access to the server
- Git, Mercurial, Bazaar
- Clients fully mirror the repository
- No single point of failure
- Best for collaboration - Multiple remotes
- Designed for:
- Simple Design
- Non-linear development (thousands of parallel branches)
- Fully distributed
- Scale - Able to handle large projects like the Linux kernel efficiently (speed and data size)
- While other VCSs represent commits as file based changes, git takes snapshots of the files. Snapshots, not differences
- Git stores data as snapshots of the project over time
- Nearly every operation is local
- Local history
- Database is replicated when cloning
- You can commit without network connection
- Integrity is built-in
O rly? Who is using dat?
If you don't use Git, you better have a damn good reason not to.
Why you should NOT use a GUI for Git
- Git is NOT famous for its interface
- It is really HARD to change #1. It is a very likely unreliable abstraction.
- You're a programmer, not a manager or tech dude
- GUIs are slow
C:\Documents and Settings\$USER\.gitconfig
git config --global user.name "John Doe" git config --global user.email firstname.lastname@example.org
git config --global core.editor vim
Merge tool -- don't change this if you're not sure
gif config --global merge.tool vimdiff
Check current settings
git config --list # show all config values, last ones have priority git config user.name # show config value
git help <verb> git <verb> --help man git-<verb>
git help config
IRC - irc.freenode.net
The 3 states for tracked files
- Commited The data is safely stored in the database.
- Modified Changed, but not commited.
- Staged Marked modified file in its current version to go into the next commit
The 3 sections
- Git directory Where Git stores the metadata and object database. This is what is copied when a project is cloned
- Working directory A single checkout of one version of the project, pulled from the database to use or modify.
- Staging area - aka index A file contained in the Git directory that stores information about the next commit
Initializing a repository in an existing directory
Cloning an existing repository
git clone <repo>
Checking the status of your files
Start tracking new files or staging modified files
git add <filename> # interactive git add -i <filename>
A file is staged in its current version. If you make changes to a file after you staging it, the new changes will not go into the new commit unless you stage the file again before commiting.
See what is changed
See what is staged
git diff --cached
git commit git commit -m 'Add speech module #432' # Thor-style commits git commit -a -m 'fix stuff'
Preferably, commit messages:
- Are in the present tense
- Start with a capitalized letter
- Have a subject that does not exceed 50 chars
- Have a thourough message body that explains in detail what was changed and why. This message is linewrapped at 72 chars.
Change last commit message
git commit --amend
git rm <filename> git rm <filename> --cached
Git accepts file-glob patterns
git add test/\*.js
Because bash does its own globbing,
* is escaped.
mv <old> <new> git rm <old> git add <new> # or git mv <old> <new>
View the commit history
Removing file form staging area
git reset <filename>
Undo file changes
git checkout <filename>
git tag <tagname> # simple git tag -a <tagname> # annotated
git remote -v
Add a remote
git remote add <name> <url>
Fetch remote database
git fetch <remote>
Does not change any of your own branches nor your working copy.
Fetch + merge with current branch
git pull <remote> master
git push <remote> master
Branching means diverging the from the current line of development.
To understand branching, you need to understand how commits are stored. A commit consists of:
- pointer to a tree (snapshot), identified by its checksum
- pointer to previous commits
What are branches:
- A branch in Git is simply a lightweight movable pointer to one of these commits.
- When you commit, the branch moves forward, pointing to the new commit.
- A branch in Git is in actuality a simple file that contains the 40 character SHA–1 checksum of the commit it points to
- Branching is inexpensive.
- Creating a new branch is just creating another pointer!
- Creating a new branch is as quick and simple as writing 41 bytes to a file (40 characters and a newline).
- Branching is a LOCAL operation, no server communication is needed
- Switching branches changes the files in the working directory
- A special pointer called
HEADalways points to the current branch.
Create a branch
git branch <branch_name>
Move to another branch
git checkout <branch_name>
Create a branch, and switch to it
git checkout -b <branch_name>
* charater prefixes the current branch (
See the last commit on each branch
git branch -v
Delete a branch:
git branch -d <branch_name>
You should branch everytime you do something new. Branch for:
If for some reason you do not care about versions.
- Keep master stable
If you want to have releases with specific versions.
- Develop on master
- Branch to stable release versions
- Fix bugs on release versions branches and merge onto master
- Never merge master onto release version branches
- Keep master stable
- Have a branch for each brand
- Merge features onto master, and only then, merge master onto the branded branches
References to the state of branches on remote repositories. They're local branches (pointers, remember!) that you can't move (directly).
Push a branch
git push <remote> <branch> # or git push <remote> <local_branch>:<remote_branch>
Checkout a remote branch
git checkout -b serverfix origin/serverfix
Setup a pre-existing branch to track an existing server branch
git checkout <local_branch> git checkout --track <remote>/<remote_branch>
Delete a remote branch
git push <remote> :<remote_branch>
<branch> into HEAD
git merge <branch>
Fast forward merges
When the commit on the branch you’re on isn’t a direct ancestor of the branch you’re merging in, or, in other words, when you try to merge one commit with a commit that can be reached by following the first commit’s history, Git simplifies things by moving the pointer forward because there is no divergent work to merge together — this is called a “fast forward”.
Three-way (or n-way)
Otherwise, Git does a simple three-way merge. Git identifies the common ancestor and uses as a base for the 3-way merge. A new snapshot is created that results from this three-way merge and automatically, a new commit is created that points to it.
A merge conflict can happen in three-way merges when the same part of a file is changed by both branches being merged. Git pauses the merge process until the conflics are resolved.
See which files are unmerged
<<<<<<< HEAD:index.html <div id="container">Awesome!</div> ======= <div id="container"> Wunderbar! </div> >>>>>>> my-other-branch:index.html
HEAD is was what you had checked out when you ran your merge command
Mark file as resolved
git add <filename>
Use the configured graphical tool to resolve the issues
Continue the merge after all conflicts have been resolved
By default, the commit on a merge will be
'Merge branch <branch>'
See which branches haven't yet been merged
git branch --no-merged
Reapplying a diverging branch onto another.
git checkout <diverging_branch> git rebase master
After rebasing, a merge of master with diverging_branch will fast-forward master.
How it works: Git …
- finds the common ancestor of the two branches (base)
- gets the diff of each commit of the branch you’re on, from the base
- saves those diffs to temporary files
- resets the current branch to the same commit as the branch you are rebasing onto
- applies each change (diff) in turn
Rebasing replays changes from one line of work onto another in the order they were introduced, whereas merging takes the endpoints and merges them together.
The only difference between merging and rebasing is the resulting history.
!! Do not rebase pushed commits !!
- Everyone can commit
- The first to push feels less pain
- The second developer must merge/rebase before pushing
- Common in centralized version control systems (CVCS)
- Very basic, very common
Integration manager workflow
- 1 maintainer
- Everyone pulls from the maintainer
- Contributions are made through pull requests
- Maintainer pulls contributions from the colaborators' repos and merges them
Dictator and Lieutenants workflow
- Good for big projects
- Dictator owns the main repo
- Lieutenants are responsible for components of the whole solution
- Lieutenants integrate contributions from contributors
- Dictator integrate pulling from his trusted Lieutenants
git config --global color.ui true
git config --global alias.l log --color --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%aN>%Creset'
git config --global alias.s status -s
Stage parts of a file
git add -i <filename>
Also, use bash alias'es.
Use a bash prompt that tells you which branch you're currently on.
# Append this to .bash_profile export PS1="\W\$(git branch 2> /dev/null | grep -e '\* ' | sed 's/^..\(.*\)/[\1]/')$ "
For another day
- Cherry picking
- Commit squashing
- Changing history
- merge strategies
- whitespace settings