These are my expanded notes form Peter Bell’s git class at Gilt Group on 3/27/2014. The below should be true for git versions 1.7.9 to 1.9.*. I’d estimate myself as mid-level or beginning-of-mid-level git user. I’ve cloned, I’ve pulled, I’ve pushed, I’ve branched, but I haven’t gone much farther then what I used to do with SVN. I’ve had this lingering feeling like I have a brand new (insert cool sports car here), but I’ve just been driving it at 15 miles an hour on residential roads. Below are some of the things I found particularly useful or interesting in no particular order.
A Metaphor for the Add, Commit, Push Process
When I first moved to git from svn I remember one of the trickier parts to wrap my head around was the need for the three step add, commit, push process. They have this cutesy shopping metaphor, where
git add is like putting something in your shopping bag, then
git commit is going to the register. I don’t think Peter said this, but my mind couldn’t help but fill in the blank and say
git push is when you take it home.
Add and commit both happen locally on your machine. In a perfect world you’d be committing on every significant change and making a log message to reflect that. Pushing is the only time something is truly backed up outside your computer. You should probably be committing 20+ times a day, but pushing something closer to 4.
When and Why To Branch
A branch should be made for solving/updating anything on your project. And what is being solved on that branch should never take longer then a week or two. Think of a branch like you would a ticket in an issue tracker. It’s a solve for a single serving problem. Your master branch should always be fully functional and ready to go to production. Any branch you make should be rebased or merged with all of the conflicts resolved before merging back into master.
I’ve been annoyed for a while that git commands often weren’t terse enough. If I’d thought about it for two minutes I’d probably of realized there’s a way around it, but I hadn’t really given it any thought. You can make your own custom aliases with
git config --global alias.<alias for command> "<command to be aliased>". The most obtuse and probably most interesting one provided us at the lecture gives you a much more exciting log readout with some ascii art branch illustrations
git config --global alias.lg "log --oneline --decorate --all --graph". After this run
git lg and watch as your co-workers look on with jealous eyes.
git add . vs
git add -A.
git add . is a standard add all command.
git add -A or
git add --all does a smart add all. It uses an algorithm to guess things you might of done and account for them. The easiest example of this is if you renamed a file without using the proper git command. Suppose in your editor you just right clicked “index.html” and renamed it “home.htm”. A normal
git add . would think you deleted a file and created a new one, but this command is smart enough to infer what happened.
Undo an Add
Git provides the less-then-intuitive
git reset HEAD <filename> to un-stage if you added something by accident.
The Proper Way to Rename a File
git mv <original file name> <new file name>. This is pretty much the same way you’d do it on the mac command line, just throw git infront. The advantage of this is your logs will show what happened.
git branch will output all your branches and highlight where you’re at.
git checkout <branch name> will move you to another existing branch.
Create a new branch and switch over to it all in one command with
git checkout -b <branch name>.
Once you’ve added and committed some things to a new branch and it’s time to push, you need to use
git push -u origin <new branch name> to properly push it the first time. After this you can push in the normal fashion.
Rebase VS. Merge
Rebase more or less is a merge, so why use it? The key difference is that rebase brings the head of your branch to the head of the master branch and applies all the edits you have made after the head of the master branch. In a way you are re-writing history. Merge is what I think most of us are used to where the two histories remain intact and the merge edits occur in a historically accurate way.
This being the internet there’s a lot of disagreement on if rebase should be used or not. The argument for it is that rebase is a good way to prepare your branch before you merge it into master because it will bring you up to date with any edits that have occurred in master while you were focusing on your feature. It is also useful if you’re working on a branch for an extended period of time and you know other branches have been committed in the mean-time. It can sort of keep you up to date.
This is obviously a dense enough topic to be its own blog post. This guy goes into way more detail.
To rebase your branch, make sure you are on your branch, then run
git rebase master. If there are no conflicts you’ll get a message with something like “First, rewinding head to replay your work on top of it…”, followed by some statements that start with “Applying: …”. Poof, rebase done. Most likely there will be merge conflicts though, and don’t worry git will make you acutely aware. Resolve these same as you normally would. Either open in vim/your-text-editor and hand edit, or (my preferred) run
git mergetool and it will open the conflicts up on your local diff software. Once conflicts are resolved be sure to run
git rebase --continue to finish the job.
This rebase is lovin’ life.
Manage a “.gitignore” file on the root of your project to specify files that should never be pushed. This is just a nice simple text list of files and folders, with a new line to seperate each entry. I think most people already got this part, but if you don’t some great first candidates are the mac system file “.DS_Store” and if your using grunt or node your “node_modules” folder. There’s a bunch of starter files here.
.DS_Store dist/ignore node_modules src/libs
A More Terse Status Output
git status -s
git diff shows you un-staged changes.
git diff --staged shows you staged changes.
git diff HEAD shows you both of the above. Maybe it’s time for an alias?
This is the cryptographic code generated by git to represent each commit you do. If you use
git log --oneline this is the alphanumeric string output before the commit message on each line. These are useful when reverting your work.
Useless info: SHA-1 hashes were developed by the NSA.
Reverting Git Commits
Revert to any previous commit with
git revert <SHA-1 hash>.This is the safest way of rolling back revisions. It will take you back to the SHA-1 hash you provide, however it will make it part of history. Instead of erasing what was done you are adding the revision to history.
In git 1.0 the default behavior for
git push is to push all of your local branches. This default behavior is known as a “matching” push. Because of this, in the past I’ve usually specified which branch to push
git push origin <branch_name>. In git 2.0 the default push is going to be updated to what they call a “simple” push. This means that running
git push will only push the branch you are currently working on. You can configure your default push to simple now with the
git config --global push.default simple command.
Color in the Command Line
The below commands will make your git output display in color. Some installs may automatically be set to color. If you want to get rid of color output just change true to false.
git config --global color.diff true
git config --global color.ui true
Use Git to Tell a Story
Think of git as a story telling device. In two weeks when you go urban exploring and fall off a building, what would it be nice for the next developer to know? It’s a log of your trials and tribulation with whatever code base so try to give enough information that someone else could follow. Commits like “new css” don’t give the reader much to work with.