One of the greatest aspects about Git is that you can undo almost anything. In the end, this means that you actually can't mess up: Git always provides a safety net for you.
Fixing the Last Commit
No matter how carefully you craft your commits, sooner or later you'll forget to add a change or mistype the commit's message. That's when Git's "amend" feature comes in handy: it allows you to change the very last commit really easily.
To amend a commit in Tower, simply make sure to check the "Amend" option in the commit area. As soon as you do, the last commit's message is prefilled into the textfields. You can then either change the message or/and stage changes just like you're used to.
The Golden Rules of Version Control
No. 5: Never Amend Published Commits
Using the "amend" option is a great little helper that you'll come to appreciate yourself very quickly. However, you'll need to keep the following things in mind when using it:
- (a) It can only be used to fix the very last commit. Older commits can't be modified with "amend".
- (b) You should never "amend" a commit that has already been published / pushed to a remote repository! This is because "amend" effectively produces a completely new commit object in the background that replaces the old one. If you're the only person who had this commit, doing this is safe. However, after publishing the original commit on a remote, other people might already have based new work on this commit. Replacing it with an amended version will cause problems.
Undoing Local Changes
Changes are called "local" when they haven't been committed, yet: all the modifications that are currently present in your working directory are "local", uncommitted changes.
Sometimes, you'll produce code that... well... is worse than what you had before. These are the times when you want to discard these changes and start fresh with the last committed version.
Tower allows you to undo local changes in different granularity:
- Discard all changes in a file
by choosing "Discard Local Changes" from the right-click menu
- Discard a chunk (an area of changes) in a file
by clicking the "Discard Chunk" button in the file's diff view
- Discard individual changed lines in a file
by selecting the corresponding line(s) and clicking "Discard Lines" in the file's diff view
If you need to discard all current changes in your working copy and want to restore the last committed version of your complete project, right-click the "Working Copy" item in the sidebar and select "Discard All Local Changes...".
This tells Git to replace the files in your working copy with the "HEAD" revision (which is the last committed version), discarding all local changes.
Discarding uncommitted changes cannot be undone. This is because they have never been saved in your repository. Therefore, Git has no chance to restore this kind of changes. Always keep this in mind when discarding local changes.
Undoing Committed Changes
Sometimes you'll want to undo a certain commit. E.g. when you notice that your changes were wrong, when you introduced a bug, or simply when the customer has decided he doesn't want this anymore.
Undo Using "Revert"
Using Git's "revert" command is one possibility to undo a previous commit. Note that the command doesn't delete any commits: instead, it reverts the effects of a certain commit, effectively undoing it. It does this by producing a new commit with changes that revert each of the changes in that unwanted commit. For example, if your original commit added a word in a certain place, the reverting commit will remove exactly this word, again.
Undo Using "Reset"
Another tool to "undo" commits is the "reset" command. It neither produces any new commits nor does it delete any old ones. It works by resetting your current HEAD branch to an older revision (also called "rolling back" to that older revision). The commits that came after this revision are effectively undone and are no longer visible in the history of this branch.
When resetting to an older revision, you can choose to either keep or discard changes:
- Keeping changes will leave both current local changes as well as the changes from the rolled back commits in your working copy.
- Discarding changes will fully restore the project as it was in that past revision - which will also discard any current local changes.
Just like "revert", the "reset" command also doesn't delete any commits. It just makes it look as if they hadn't existed and removes them from the history. However, they are still stored in Git's database for at least 30 days. So if you should ever notice you accidentally removed commits you still need, one of your Git expert colleagues will still be able to restore them for you.
Using Revert & Reset in Tower
Both commands - revert and reset - can be used in Tower. Don't forget, however, that reset can only be performed on the HEAD branch. Therefore, make sure that the correct branch is checked out and select it in the sidebar. Then, simply right-click the commit you want to reset or revert and choose the corresponding option from the menu.