I’ve learned a lot about git, usually in a hurry after I mess up and have to fix it. Here are some basic techniques I’ve learned that may help a git beginner.
Fixing your ungood code
Let’s say you’re a clerk working for an Orwellian Ministry of Truth and you find out the new chocolate ration is 20 grams. You look at tonight’s newscast transcript, newscast.txt, which says:
...and in other news, the Ministry of Plenty has announced that chocolate rations will be held steady at 40 grams for the forthcoming quarter...
Well, that won’t do. We modify the transcript newscast to say:
...and in other news, the Ministry of Plenty has announced that chocolate rations will be cut to 20 grams for the forthcoming quarter...
And we commit:
$ git add newscast.txt $ git commit -m "Fixed chocolate ration" [master 9772a49] Fixed chocolate ration 1 files changed, 1 insertions(+), 1 deletions(-)
As you’re about to push, your supervisor, who has been hovering, shrieks: “Do you want to be an unperson? Don’t say they’ve lowered a ration!”
So, we’ll modify the file again:
...and in other news, the Ministry of Plenty has announced that chocolate rations will be raised to 20 grams for the forthcoming quarter...
Now we’ll add this change, as though we were going to make a new commit:
$ git add newscast.txt $ git status # On branch master # Changes to be committed: # (use "git reset HEAD ..." to unstage) # # modified: newscast.txt #
git commit --amend sweeps everything in our staging area into the last commit:
$ # this opens your text editor, in case you want to change the message $ git commit --amend [master 04ce65d] Fixed chocolate ration 1 files changed, 1 insertions(+), 1 deletions(-)
Now you just have one commit with the “correct” changes.
We have always been at war with Eastasia
Sometimes you have a mistake so severe that you don’t even want it to exist in the repository’s history anymore. If you haven’t pushed yet, you can use
git reset to unwrite any history that happened after a given commit.
Let’s say we messed something up and we want to get back to 72ecbbda47c0712846312849bab1fb458cd9fffb:
$ git reset --hard 72ecbbda47c0712846312849bab1fb458cd9fffb
And you’re back to 72ecbbda47c0712846312849bab1fb458cd9fffb, like whatever happened never actually happened.
git reset isn’t just good for revisionist history, it’s also nice when you have a merge conflict, some deleted files, a strange thing with branches, and you don’t even know what’s going on: you just want to go home. A hard reset can get you out of almost any problem.
However, once you’ve pushed, resetting isn’t an option. If you reset a public repo on a “real” project, you’ll be unpersoned so fast your head will spin.
When you’ve already pushed a crimethink
Let’s say you made a mistake (as above), but have already pushed to a remote repository. Now you have to either fix the commit or remove it.
In the example above, it’s easy enough to fix: change “cut the chocolate ration” to “raised the chocolate ration” and you’re done, so you might as well just push a new commit with the fix.
However, sometimes a fix will take longer (e.g., you need research a plausible story to explain away inconsistencies). You don’t want anyone getting confused in the meantime, so if you cannot immediately correct history, you should politely back it out. This is where
git revert comes in.
First, look up the hash of the commit you want to undo.
$ git log -1 # -1 means only show the latest 1 commit commit 72ecbbda47c0712846312849bab1fb458cd9fffb Author: Kristina Date: Thu Feb 23 09:07:58 2012 -0500 Airplane was now invented by the Party
Now, revert that hash:
$ git revert 72ecbbda47c0712846312849bab1fb458cd9fffb
git revert will pop up your editor and you can mess with the revert message, if you want.
Changing airplane's invention date is going to take more work than anticipated This reverts commit 72ecbbda47c0712846312849bab1fb458cd9fffb. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # On branch master # Changes to be committed: # (use "git reset HEAD ..." to unstage) # # modified: newscast.txt #
Save, exit, and push to the remote repo.
$ git revert 72ecbbda47c0712846312849bab1fb458cd9fffb [master 84e6f13] Changing airplane's invention date is going to take more work than anticipated 1 files changed, 0 insertions(+), 1 deletions(-)
You can revert any commit from any time in history. Note that this creates a “uncommit” in addition to the original commit: it’s essentially creating an “opposite diff” to cancel out the original commit. So the original commit is still there.
Ignorance is strength, but just in case…
Some resources you may find helpful, when learning git:
git gui: invaluable for staging commits
gitk: easier to read than
git logwhen examining commit history
- GitReady: most useful site I’ve found for recipes of common tasks.
And remember, use a full sentence describing your change in commit messages. Big Brother is watching.
8 thoughts on “git-oh-$#!†”
Thanks, this was awesome. I’ve learned most of these already but the “1984” examples make it very memorable.
Thank you! I felt a little silly posting it because it is such basic stuff, but hopefully it’ll be useful to beginners.
This is so helpful! I get in so much trouble with git I’m going to use this later!
Thanks! Glad it’s helpful!
Use as many full sentences as your commit warrants, but only *after* a single-line commit summary less than 80 characters followed by two newlines. 🙂
Good point! I didn’t mean people should limit themselves to one sentence, but our codebase tends towards commit messages like “fixed bug,” “whoops,” and worse.
Git supports aliases.
And you can make long boring ones like “uncommit” or set them up like I did: http://floatboth.com/where-i-set-up-my-git-and-hg-aliases-like-a-boss/ Basically, like vim commands 🙂
Cool! I love git aliases, thanks for sharing!