Well so far we have created a branch to test out some new code, then merged that branch with our master branch. We thoroughly tested everything. We thought QA went well and were sure there were no bugs – but alas! we have royally screwed ourselves… or have we? Git provides some pretty quick and easy commands for fixing mistakes. Let’s dive into them.
Undoing Changes to your Working Directory
git checkout [name_of_file_or_branch]
- Go into the repository and get [name_of_file_or_branch] and replace the version that I have in my working directory. The checkout command is used to retrieve both branches and files.
git checkout -- [name_of_file]
--tells git that you are checking out a file from the current branch. Because the checkout command is used for both branches and files, including the — is considered a best practice when checking out files (though it isn’t required).
Undoing Changes to your Staging Directory
git reset HEAD [name_of_file]
- Go look at the HEAD pointer, which points to the last commit at the tip of the current branch, and reset [name_of_file] to be the same.
Note: only the most recent commit can be edited in Git without a record of its change being recorded. This is because Git retains a parent/child relationship of every commit ever made. Each new commit is established as the parent of the previous commit. So, the reason why you can only edit the most recent commit (without that change being retained in Git) is because that commit has no parent ~ a subsequent commit has not yet been made to establish that association.
Digging deeper… When you make a commit, Git’s algorithm generates a unique 40-character value called a “SHA-1 hash” to identify the commit. When a subsequent commit is made, it establishes itself as the parent of the previous commit by chaining itself to the hash value of the previous commit. So, the reason that you cannot edit a commit when subsquent commits have been made is because it would change the hash, thereby breaking the chain of dependencies. In order for a commit to be edited or “amended”, it cannot have parent – it has to be the most recent commit because editing anything, even the commit message, will change the hash value.
git commit --amend -m "my commit message"
- Edit the most recent commit to contain all the files that have been added to staging and update the commit message to read “my commit message”. Note: if no files have been added to staging, Git will simply edit the commit message. In fact, the
--amendcommand is frequently used to do just that.
Reverting to a Previous Commit
git checkout [hash_value] -- [name_of_file]
- Go look up the file named [name_of_file] from the commit with the hash value of [hash_value] and put that file in my staging directory. Note: the
--tells git that you are not checking out a branch. Also note: checking out files from a previous commit moves them to staging (not the working directory). If you just want to do a straight up revert, you could simply commit those changes. However, if you want to move those files back to your working directory, you will need to reset the HEAD (shown in a previous command). Lastly, when reverting to files from a previous commit, it is advisable to place part of the hash value of the commit that you are reverting to in the commit message for the new commit.
git revert [hash_value]
- Completely undo the changes made in commit [hash_value]. Remove everything that was added and add everything that was removed, then make a new commit.
git revert [hash_value] -n
- Same as the previous command except that instead of making a new commit, just add the files to the staging directory. Note: this gives you the opportunity to write your own commit message and also make any other modifications prior to making the commit.