Thursday, August 14, 2008

My Git Cheatsheet

You scraped along on CVS. Subversion seemed to bring you a cleaner world, but you still had to admit to yourself you dreaded branching. You had to find a better way. Along came Git and the world of SCM was like crawling through the Wardrobe. You downloaded Git. You Google'd for more information and found this cheatsheet. The answer to your prayers? No. You should already know some Git already. But you found My Git Cheatsheet anyway. So just hold on tight.

Setting Up Git

You can figure out how to install it yourself. Once you have, run the following:
git config --global user.name "Joe Smith"
git config --global user.email "joe@smith.com"
git config --global color.diff auto
git config --global color.status auto
git config --global color.branch auto
Did you use your own name and email? If not, just stop reading now. The color commands will make your day brighter when you run many of the status commands. You only need to do this once no matter how many repositories you make.

Creating Your Repository

There are two ways to start a repository. You can either create your own directory, anywhere you want, and:
git init
Or you can start from an existing, public repository and:
git clone git://git.assembla.com/my-whatever-project.git
You will use your own private repository and deliver your work to the public one(s). Having the private repository allows you to make changes you've never imagined, like blowing away commits and deleting branches endlessly. Congratulations, you are on Git. Now what can you do with it? A lot of stuff, some of it common, some of it not. We'll start with the common. Away we go.

The Basics

Add some files and commit:
vi MyNewClass.as (add some content)
git add MyNewClass.as (add change to your index)
git commit (commit index to repository)
Or another way:
vi MyNewClass.as
git commit MyNewClass.as (with file args, commit implicitly calls add)
If you edit more than one file:
vi MyNewClass.as
vi MyOtherNewClass.as
git add . (. recurses directories)
git commit
Or another way:
vi MyNewClass.as
vi MyOtherNewClass.as
git commit -a (-a implicitly calls add as well)
Note that files go from your workspace, to your index, and then are committed to the repository. Think of an index as a changeset in Perforce -- it's what will be committed. Even though you can easily skip the index step, the concept is used in other operations. Wanna confirm that last commit, or see the last commit in general? Try:
git show
But oh man! You messed up that commit. You broke something! You need to back it out, but how?
git revert HEAD
This adds a new commit that does the reverse of the last set of changes. They don't go back into your workspace, though. But, you can access the original changes in the repository because they weren't destroyed, just reversed. HEAD is a revision symbol. It means "the latest." If you wanted to, say, revert a change from two commits ago, do:
git revert HEAD^
So, in order, you'd have the original commit, the next commit, and a reversion of the original commit. Cool! HEAD^ might be arbitrary, but the power of reverting a commit undeniable. You can specify any commit anyway. Look at your history:
git log
See those 40-character ID's? You can revert any of them:
git revert f728 (just the first few characters is all you likely need if they are unique)
To remove a file:
git rm MyClass.as
git commit
Note that removals go right into your index. Now, how do you check the status of your workspace? Check with this:
git status
If you want information on changes you've made to a file, use:
git diff MyClass.as
And remember, if you add a changed file to your index, then make more changes to it, you're gonna have to add the file again otherwise only your first set of changes will go in. The index represents the change, not the files themselves. In effect, an index is your "change order."

Tagging

You know what this is. Tag a specific point in time. Maybe you sent your client v1.0 of your application and you want to be able to reference back to what you gave them in the future. Tag it:
git tag v1.0
Nah, that's a stupid name. Forget it. Get rid of it:
git tag -d v1.0
It's gone right? Check the list of tags:
git tag -l
Remake the tag as FIRST_RELEASE:
git tag FIRST_RELEASE
Oh, wait! You need to make one more change! Add and commit. Now, remake the tag again:
git tag -f FIRST_RELEASE (-f replaces the tag)
The tag moves to the new HEAD. You can use tags just like commit points or branches:
git checkout FIRST_RELEASE
You can't revert it, though. It's not a commit, it's a point in time. Remember?

Fixing Mistakes

Say you've made some changes to your code, but decide they are crap. Clean up your index and workspace with:
git reset --hard HEAD (resets to last commit)
Say you realized your code was crap AFTER you commit. You can throw away the last commit by resetting to the commit before it with the extremely dangerous:
git reset --hard HEAD^ (BUT BE CAREFUL - I WARNED YOU!)
I say to be careful because blowing away commits is extremely insane. Flirt with this command and make a mistake, and you're royally screwed. You'll learn later, though, that it's only half decent because your repository is completely private. You would NEVER do this in a public repository. So don't. Here's a nicer way:
git reset --soft HEAD^ (--soft will put the changes in your workspace and index)
The big difference here is that the changes aren't thrown away, but rather placed in your workspace for additional editing. Excellent. Additionally, when you want to commit using this method, use:
git commit -c
That gives you your old commit message back. You probably typed a really good commit message and you wouldn't want to redo it. Your new message will likely be similar. If you want to avoid even that, there's one more way. This is most useful when you make a commit and then decide you wanted to add more to the commit, or less. Just make the additional changes and:
git commit --ammend
This just incorporates your new changes into the last commit. This is so much better than having three commits represent one change like I do all the time in Subversion. Git loves you. You may also have a problem with just a single file and maybe don't want to blow away ALL your changes. If you have changed a file and added it to the index, or removed a file you no longer want to remove, do:
git reset HEAD FILE (pulls FILE from index)
git checkout FILE (reverts FILE)

Stashing

This feature is what you have always wanted and never knew it. Let's assume you have received CR239; damn, some dude found a bug. You need to fix it, but you're working on something else. Damn. Now you gotta copy those files to some other location and then reset your workspace so you can fix the problem and then bring back your changes and pray to God there isn't a conflict, right? Wrong. Stash your existing changes:
git stash "Localization Work" (describe what you were doing well)
YOUR FILES ARE GONE! No they're not. You stashed them. Check your stashes:
git stash list
See, there it is. Your workspace is clean now. Don't worry if your changes were in the index or not, they are all saved. Now fix CR239 and come back when here when you're done. Done? Good. You're fast. I assume you've checked in your changes, too. Good. Now, let's bring your work back:
git stash pop
Or, if you want to be more explicit:
git stash apply stash@{0} (use the right stash name)
git stash drop stash@{0}
Coolest thing ever, right? If you stash too much and don't clean up after yourself, the stash can get kinda crowded. Use that drop command to get rid of them individually. If you ever want to clean it all up in one shot, do:
git stash clear
Ah, that's better. Hope you didn't need that code.

Branching

Don't worry. It sucked before. Now it's cool and insanely easy. Let's pretend another bug was reported: CR833. You want to fix the problem on a different branch, so you can keep your main development separate from the bug fix. So, first, you might stash your current changes, if you have any:
git stash "What I was working on before freakin' Eric reported CR833."
OK, now, start working on a new branch:
git checkout -b CR833 (the -b creates the branch, checkout switches you to it)
Check it out, you have a new branch:
git branch
The asterisk (*) means you're using that branch. Easy, right? OK, fix the problem and then come back. Damn, you're good. Checked in? Good. Let's go back to the master:
git checkout master (no need for -b, the branch already exists)
And now you need to merge.

Merging

At some point you'll want to bring those changes into the master. Otherwise, they will stay on the branch and you're likely doing your official builds off master. So, we need to merge them:
git merge CR833 (you run this from the branch you want to merge into, usually master)
Done -- unless there are conflicts. If there are, make you changes and add and commit until it's all good. Don't worry, the merge will be clean because the file will be specially marked as merges. If you're done with that branch now, feel free to remove it (but you don't have to):
git branch -d CR833
We can delete the branches because we are using private repositories. See how cool that is? Keeps things clean. I told you branching was easy.

Rebasing

Now, let's assume CR833 was a real pain and took you a whole month to fix. Or maybe you just suck and took a long time. Along the way, new stuff was being checked into master and you want to keep up to date with things -- especially that fix Sean put in that stopped the program from crashing so much. Sweet. Rebasing is like changing when you branched. If you branched a week ago, and you rebase now, it will make it seem like you just branched now when you're done. You aren't merging the master in to your work, you're actually scrapping all your work (including commits), updating from master (or whatever), and then reapplying all your work again (including commits). Freakin' sweet. So, from the branch you want to rebase (which is generally, quite literally, the branch):
git rebase master (or whatever branch you're rebasing from)
If you haven't been branched very long, this will likely work right away. Sometimes, though, you may have conflicts because some other yutz was changing the files in master that you've been changing in the branch. You'll have to resolve the conflicts. Do it. Then:
git rebase --continue (--continue because you're still doing the original rebase)
Continue until the rebase completes. If things get too messy, perhaps you want to cancel the rebase. Do:
git rebase --abort
All your changes return and you're right back where you started. Wuss.

Pushing to a Repository

Git is designed to go places. Developers can share changes with developers. You can have more than one repository (by cloning multiple times) and push and pull changes between them. If you're confused, realize that your repository is private. It's just for you and no one else. Now re-read the paragraph. INSPIRED! Pushing changes adds what you've done to another repository. The best example is when you have a public repository that everyone refers to and where official builds are made. You push your work to the repository to get it "in the public record." This might sound weird. With Subversion, there is only one repository, and your workspace is on its own. You can only commit to that repository. That's simpler, but branching sucked. Now you have simple branching. So, now you have more than one repository. Deal. But, it's also cool. Let's assume you created your own repository and bought some Git space on Assembla.com (or Unfuddle, or GitHub). Go setup an account if you don't have one. It's cool. If not, just use your imagination. So, let's take our repository and send it to Assembla:
git remote add assembla git://git.assembla.com/my-whatever-project.git
git push assembla master
Or more explicitly:
git remote add assembla git://git.assembla.com/my-whatever-project.git
git push assembla CR833:master
Use this last syntax if you want to push a branch to a master. Probably not very common. Now your changes are in that repository. That's cool, but I said this was a good feature and it just feels like an extra step. Well, yeah. But, remember, you can send your stuff to whoever you want. Maybe your work buddy. Keep it secure, no one has to know.

Pulling from a Repository

Pulling lets you get changes from somewhere else:
git pull assembla master
Now you have their changes, including a list of branches available to use as well.

Cleanup

Git might get a little fragmented at times. Remember your hard drive in the 1990's? Every so often, give these a run:
git gc (gs is garbage collection)
git fsck
You're done. Now git.

Feedback

Help me keep this cheatsheet current, correct, and useful. Am I missing some common operations? Wrote something wrong (hardly likely)? Be a decent human being. Leave feedback.

11 comments:

Matthew McCullough said...

Nice job. Enjoyed the sheet. Will definitely be a link I share with co-workers starting to learn GIT.

Thanks,
Matthew McCullough

Виталий said...

this is great, thank you, bookmarked.

Arthur said...

I wrote a blog entry a while ago which shows some useful configuration options for Git, like setting up svn-like shortcuts for often-used commands. So that I don't have to write "git checkout ..." just "git co".

Saves a little typing if you come from a CVS/SVN background and already know the commands.

Thought you might be interested: http://bit.ly/4UUZv

Erik I said...

Nice! Thanks!

Now, if somebody could make this kind of documentation for every tool I use.. :)

kaoru said...

無修正 指マン 四つん這い メス豚 クリ舐め バスガイド トイレ盗撮サイト 正上位 くすぐりフェチ 局部 裸エプロン 洋ピン バニーガール 裏本 レオタード メイド ボンデージ 無修正動画ねたまん デリヘルR 長身女性 アダルト アニメ 家庭教師エッチ 熟女 動画 ルーズソックス 監禁恥育 おいかわなお あかねほたる しらいしひより つかもとゆき もんぶらん みやしたあんな あさかわ らん ひめかわれい むらさきあやの つつみさやか いいじまなつき ふじいあや

mamoru said...

lenovo イチゴ 消防署 会津若松 中央線 額縁 伊香保 tudorbingo 小笠原 プラセンタ 人口 ズーラシア 高校生 キャンプ ポストカード ライセンス お絵かき にんにく 洋菓子 塗り絵 クロサギ サウナ 陣痛 新横浜 テント ダリ 子宮 ハイビスカス くま 写真家 換気扇 ステーキ サッカリン プリメーラ 西暦 プレハブ 明太子 学習院 スラッガー 数珠 オリーブ アフリカ ノキア アルツハイマー らんま マスプロ 北斗星 治験

huyuni said...

if you or your friend want to China Wholesaleplease cheack you can buy buy products wholesale here from wholesale from china ,the China Wholesalers on China Wholesale wholesale from china buy products wholesale China Wholesalers

huyuni said...

quelle chaussures pumapaire de chaussures pour hommes choisir?!? La réponse est toute simple:chaussures nike une paire de baskets en partie vernies. du 17ème au 5ème rang, qui lui offre une place dans un top 5 largement tn requindominé par les sites de vente de produits high-tech. Le site de réservation d'hôtels Bookings.com gagne pour sa part 47 places et atteint le 8ème rang.

huyuni said...

Charlestoncheap columbia jackets. turned a pair of double plays to do the trick. spyder jacketsThe had at least one runner on in every inning but the first and outhit the RiverDogs by a 12-6 margin Lawal should be a focal point of the Yellow cheap polo shirts along with highly touted newcomer, 6-9 Derrick Favors, rated as the No. 1 power forward on the ESPNU 100. The Yellow Jackets

huyuni said...

Cheap Brand Jeans ShopMen Jeans - True Religion Jeans, burberry polo shirtsGUCCI Jeans, Levi's Jeans, D&G Jeans, RED MONKEY Jeans, Cheap JeansArmani Jeans, Diesel Jeans, Ed hardy Jeans, Evisu Jeans, Women JeansJack&Jones Jeans...Lacoste Polo Shirts, , Burberry Polo Shirts.wholesale Lacoste polo shirts and cheap polo shirtswith great price. clothingol.com offers lot of 10 lacoste polo shirts and lot of 20 cheap polo shirts. clothingol.com offers classic fit polo shirts. polo clothing

huyuni said...

nike shoes & Puma Shoes Online- tn nike,puma shoes,puma cat, baskets cheap nike shox, air max.cheap nike shox r4 torch, cheap nike air, nike running shoes air max, puma speed and more. Paypal payment.nike running shoes Enjoy your shopping experience on Nike & Puma Shoes Online Store.