GIT- Cleaning up. The basics of undoing.

Brief

Version control is a must-have when you are developing software or writing a document that will change over time. This helps us to keep track of every change that has been made on the files of a project along with valuable information as when a change was done, who did it, what was done as part of the change, a message provided by the editor along with other important information; it even allows us to compare two different versions of a file and pick whatever we need from one version and merge it into the current file version.

However, making mistakes is not unexpected, that’s why here it is the basic but at the same time. Powerful list commands you have to know in order to fix mistakes while using git.

 

Note: This article is dedicated to those who want to know what exactly happens behind the scene while using visual tools like source tree or embedded tools on your favorite code/text editor, which means we will be relying only on the terminal to explain the commands.


Amend changes to existing commits

git commit --amend (Adding more changes on the latest commit)

This is not exactly an undo command but as its name says, it’s a way to fix a commit before we have to undo something, to be more specific, it allows us to include more changes onto a commit or edit the commit message itself without leaving traces on the repository history.

 

How it works:

1. Make some changes on any file whether it’s existent or new on a git repository.

2. Stage the changes.

a. git add

3. Commit your changes with a message.

a. $ git commit -m 'initial commit'

4. Make more changes that should have belonged to the same commit, it can be changed on one or more files or even adding or deleting files.

5. Stage the changes.

a. git add

6. Commit your changes without modifying the message within the same existing commit.

a. $ git commit --amend

7. You’ll be presented with an editor to modify the commit message, type :x once you are happy with the commit message and hit enter to save your changes, this will take you back to the previous screen:

a.

8. Now your commit will be replaced by a new one a new message without leaving traces on the repository history.

 

Also, you can tell git to leave your commit message as is in case you don’t want to edit it and only want to add the new changes to the current commit. To achieve this, just add -no-edit as follows git commit --amend -no-edit, this will include your latest changes without opening the commit editor screen shown above in 7.a.

 

Exclude specific files (.gitignore)

 

Before undoing we should know how to prevent undesired files from getting tracked, all we have to do is create a file named .gitignore at the root of our repository and know the name and/or location of the files. Each line of the .gitignore file specifies a pattern, here is the pattern format that can be used:

– A blank line matches no files, so it can serve as a separator for readability.

– A line starting with # serves as a comment. Put a backslash (“\“) in front of the first hash for patterns that begin with a hash.

– Trailing spaces are ignored unless they are quoted with backslash (“\“).

– An optional prefix “!” which negates the pattern; any matching file excluded by a previous pattern will become included again.

– If there is a separator at the beginning or middle (or both) of the pattern, then the pattern is relative to the directory level of the particular .gitignore file itself. Otherwise, the pattern may also match at any level below the .gitignore level.

– If there is a separator at the end of the pattern then the pattern will only match directories. Otherwise, the pattern can match both files and directories.

– An asterisk “*” matches anything except a slash. The character “?” matches any one character except “/“.

– The range notation, e.g. [a-zA-Z], can be used to match one of the characters in a range. 

– Two consecutive asterisks (“**“) in patterns matched against full pathname may have special meaning:

– A leading “**” followed by a slash means a match in all directories. For example, “**/foo” matches file or directory “foo” anywhere, the same as pattern “foo“. “**/foo/bar” matches file or directory “bar” anywhere that is directly under directory “foo“.

– A trailing “/**” matches everything inside. For example, “abc/**” matches all files inside directory “abc“, relative to the location of the .gitignore file, with infinite depth.

– A slash followed by two consecutive asterisks then a slash matches zero or more directories. For example, “a/**/b” matches “a/b“, “a/x/b“, “a/x/y/b” and so on.

– Other consecutive asterisks are considered regular asterisks and will match according to the previous rules.

 

Unstaging a staged file.

Sometimes there are auto-generated files with unpredictable names that should not be committed to the repository, however, if you were not careful enough and staged any of those files, there is a way to undo it.

1. After staging your changes enter the following command to know what was changed

a. git status

2. Use git reset HEAD <filename> to unstage a file.

3. Use git clean -df to clean up the repository by removing all unnecessary unstaged files like auto-generated files.

4. You can proceed to commit your changes.

Now let’s say you already committed some undesired files/changes and want to undo it without undoing the whole commit.

1. Use git reset HEAD^ <filename> remove a file from the commit.

2. Whether the file was already part of the repository or it is a brand new file that is not supposed to be part of the commit and you just want to revert your latest changes, use git checkout -- <filename> to undo all changes on a file or git checkout . to undo all changes on all uncommitted files.

Note: You have to be careful with this command since it will revert all uncommitted changes on all uncommitted files. Use it only if you are sure that you want to revert everything uncommitted.

3. Use git commit --amend -no-edit to tell git that you want the reverted files to remain reverted in the commit.

4. At this point git status will only tell you about pushing without any details of what exactly is going to be pushed to the repository, if you want to know, you can refer to the --amend section above, it will open the commit editor screen where you can see all the changes to be included in the commit.

What if you want to thoroughly revert your changes to a specific commit? For this, we can simply do git checkout <sha1> where sha1 is the specific commit id, use git log in order to list the previous commits with the required ID.

There is more, what if you want to utterly undo your current changes and match your repository state to the latest commit in origin? For this, use git reset --hard origin/<branch_name> to destroy all local modifications and get the latest commit of a specific origin branch, you can also replace origin/<branch_name> by a specific commit ID of any branch different from yours, this will destroy your local changes too and apply the specific commit on top of your current branch.

Note: This is a dangerous option that has to be used if and only if you are sure that you want to revert your branch to the latest origin state since all your changes will be lost even if you already did git commit but didn’t do git push.

More dangerous options related to git reset –hard:

To remove the last commit from git, you can simply run git resethard HEAD^ If you are removing multiple commits from the top, you can run git resethard HEAD~2 to remove the last two commits. You can increase the number to remove even more commits.

 

Stash.

There are also situations when you don’t want to lose some changes but also don’t want to include them on the commit or just want to put them apart for a while and come back to them later. Let me explain with an example, picture a situation where you have already made some progress on a new feature, and out of nowhere you’re asked to do an urgent fix that has nothing to do with your current progress on the feature, you obviously don’t want to lose your changes, but cannot include them as part of the fix since it is not completed yet, that’s when stash comes in handy.

There are some stash basic options you have to know:

git stash saves your local modifications away and reverts the working directory to match the HEAD commit.

git stash list List the stash entries that you currently have. 

git stash show Show the changes recorded in the stash entry as a diff between the stashed contents and the commit back when the stash entry was first created.

git stash pop Remove a single stashed state from the stash list and apply it on top of the current working tree state.

Note: Please refer to https://git-scm.com/docs/git-stash for more stash details and options.

 

References.

Git. (n.d.). Retrieved December 26, 2019, from https://git-scm.com