Git: Commands you need to know when you are messed upšŸ˜Ø! [Part-1]

Skrew Everything
From The Scratch
Published in
12 min readMar 1, 2020

First things first, this is not an another ā€œKNOW THESE GIT COMMANDS TO BE MORE PRODUCTIVE!ā€ or ā€œGIT COMMANDS LIST THAT EVERY DEVELOPER MUST KNOW!ā€

Readers on Medium

We got enough of those in the internet. What we donā€™t have is: ā€œCOMMANDS YOU NEED TO KNOW WHEN YOU ARE MESSED UP!ā€šŸ˜‡

If anyone say they never messed up in Git, Donā€™t trust them! Unless itā€™s Linus Torvalds or Jeff Dean.

Git is every junior developerā€™s nightmare when they are working in a group. Especially with the people who are experienced and know their shit. Because,

  1. If you make some mistake, you canā€™t just delete .git from the root folder and pretend everything is ok. (Ohhhhhā€¦ Iā€™m guilty of doing thisšŸ¤«. I hope my boss doesnā€™t read this articlešŸ˜°)
  2. When they see your mess, they might not think you are dumb or inept of doing work but your conscious will think about it constantly. For people like me, the brain suddenly remembers all the embarrassing things even done during the childhood at 2 A.M.
Yeah, thatā€™s me most of the time

The above two points makes everyone nervous before making every commit and pushing to the remote.

But sometimes, that extra care we take wonā€™t even save us and sooner or later we do something stupid, which we want to hide desperately from our peers and manager. So, obviously we turn to Google, frantically searching for some commands for hours to bury the body and pretend everything is normal.

Ok. Ok. FinešŸ˜‘. Iā€™m gonna stop blabbering and get to the stuff you are here for before you feel sleepyšŸ„± and leave šŸƒšŸ»ā€ā™€ļøšŸ’Ø.(Sometimes, I get distracted šŸ˜…. Iā€™m known to talk about ā€¦ā€¦ā€¦ā€¦.. See, Iā€™m again getting distracted šŸ¤¦šŸ»šŸ¤·šŸ¼)

Actually, itā€™s a two part series. I donā€™t want to fry your brains with too much information in one day(Yes, I do care for youšŸ„ŗ). So, this part mainly concentrates on commands which has effects on your local working directory. The next part will be on remote repo like on reverting, deleting, editing commits etc. which requires more of your attention while learning.

Whatā€™s in this?

  1. Accidentally staged files for commit?
  2. Accidentally tracking files or donā€™t want to track a file anymore?
  3. Want to delete untracked and ignored files?
  4. Want to revert un-committed changes?

So, letā€™s see some of the things we can mess up and how to clean it without jeopardizing our whole work.

Accidentally staged files for commit?

Have you ever executed the below command and wanted to undo?

git add .git add *git add -Agit add -u

(Yes, there are 4 variations! Checkout this SO post to know everything about them)

Now, you got multiple commands to do that

  1. git reset <filename> or git reset HEAD <filename>
  2. git rm --cached <filename>
  3. git restore --staged <filename> ā€” Added in Git v2.23 (August 2019)

Actually, these three commands will be recommended to you by the Git itself when you add the files to index or to staging area. If you are using Git v2.23+ then you will be suggested git restore --staged <filename> instead of git reset HEAD <filename>

There is never really only one way to do anything in git. That is the beauty of it :)

I guess the new command git restore --staged <filename> is self explanatory. Let me explain the other two commands.

git reset HEAD <filename> : reset command resets the INDEX or STAGING AREA to previous commit i.e., the position of the HEAD in the Git.

git rm --cached <filename> : removes the files from the INDEX or STAGING AREA completely. If you deleted a file which is already in the repo and run this command, the file will be removed from the INDEX or STAGING AREA and also from the repo in the next commit. That said, if you used git rm --cached on a new file that is staged, it would basically look like you had just un-staged it since it had never been committed before.

Now, why does Git suggest two different commands?

For git reset HEAD <filename> or git restore --staged <filename> to work, there should be at least 1 commit in the repo. Because git reset HEAD command is saying to reset the files to the HEAD but HEAD is not created until the first commit is made.

Because HEAD is created only when first commit is made

But you can still run it by excluding Head option and it works perfectly

Now you donā€™t have any error

WHYšŸ¤”?

In old versions of Git, the above commands are equivalent to git reset HEAD <file> and git reset HEAD respectively, and will fail if HEAD is undefined (because you haven't yet made any commits in your repository) or ambiguous (because you created a branch called HEAD, which is a stupid thing that you shouldn't do). This was changed in Git 1.8.2, though, so in modern versions of Git you can use the commands above even prior to making your first commit:

ā€œgit resetā€ (without options or parameters) used to error out when you do not have any commits in your history, but it now gives you an empty index (to match non-existent commit you are not even on).

Note: I will use git revert instead of git revert Head in the following article.

You can read more about git revert vs git revert HEAD in the below SO posts

So, if you observe next time, Git suggests git rm --cached <filename> when you donā€™t have initial commit and when you have at least one commit, Git suggests git reset HEAD or git restore --staged

Now, you might be scratching your head thinking: ā€œI understand everything but still I donā€™t understand anything and how to use itā€. Donā€™t worry, been there, done that. So, how about we look at those commands from a different perspective with a mess up to understand it actually.

git reset

git reset HEAD <filename> : You are lazy and you commit only at the end of the day by staging files and committing multiple times to organise the work.(Yeahā€¦ Sometimes I do this toošŸ˜‘)

Entire day you have added/edited many different files like above. Now you want to group server config files in one commit and database config files in one commit. But accidentally you have executed git add .

Now, you see that and want to remove the db config files and any other files to commit only server config files

Now, you can commit server config files and then commit db config files in separate commits.

Doing this doesnā€™t delete anything from your local working directory.

git rm ā€” cached

git rm --cached : Now you see why Git suggests this only when there are no commits. Tip: Donā€™t use this to unstage files without knowing completely about this!

I repeat! The behaviour of git rm --cached and git reset is same when there are no commits!

First, letā€™s see what is the output when we run git rm --cached with at least one commit

Can you comprehend what happened by just looking at the above image? If not, donā€™t worry. Thatā€™s why everyone is here. Nobody is gonna judge you.

git rm --cached deletes the file from the INDEX or STAGING AREA but you still have the file in your filesystem with all itā€™s content and also Git removes it from itā€™s tracking.

In simple terms, git rm --cached makes it look like you copied a new file into your folder.

Another effect is, this command removes the file from the repo. If anyone pulls the code after you have run git rm --cached <file> && git push , then that <file> will also be deleted from their local filesystem. Because it only exists in your local filesystem as an untracked file.

Iā€™m gonna give you an embarrassing mess once I made so that you can get an intuition when to use this.

Story Time: Once, I initialised my node project and forgot to add .gitignore and ran my alias to add everything and push it to the remote server.(Yeah I know how dumb it is and my brain is known to glitch out sometimes) Doing that pushed my entire node_modules to the remote server. So, what can I do?

  1. Add .gitignore, run rm -r node_modules && git add . && git commit && git push && npm install OR
  2. Add .gitignore, run git rm --cached -r node_modules && git commit && git push

The second option is more nice and short. When you run git rm --cached -r ( -r stands for recursive)it removes the node_modules from the INDEX or STAGING AREA and also removes it from itā€™s tracking files but it is not removed from your local file system. So, you donā€™t have to install it again like in first option. Now, whenever you run git add . , it checks .gitignore and you wonā€™t see node_modules in your git status as untracked files.

Doing this doesnā€™t delete anything from your local working directory.

Summary:

Always use git reset <filename> to unstage some files or git reset . to unstage all files. This works even if there was no prior commit in the repo.

Use git rm --cached only when you want to remove the file from the repo but keep a local copy in your local file system. Donā€™t use it interchangeably with git reset !

If you want to know from more why there are two ways, checkout this SO post:

Accidentally tracking files or donā€™t want to track a file anymore?

This is where git rm --cached is useful actually.

Like I said before, (read the Story Time above if you skipped it to understand)

Ok Fine. Iā€™m gonna say it again in a summary what it does for some lazy people.

git rm --cached command actually removes it from the INDEX or STAGING AREA and also deletes it from the repo. So, git push actually removes the file from the repo and any subsequent git pull by others will also delete that file from their local file systems(not yours. You actually have your copy).

To remove/untrack everything: git rm --cached .

To remove/untrack one file: git rm --cached <filename>

To remove/untrack a directory: git rm --cached -r <directoryname>

Doing this doesnā€™t delete anything from your local working directory.

Note: git rm is not same as git rm --cached . git rm actually deletes the file from your local file system, repo, and others file system. So, be careful not to forget ā€” -cachedoption!

Want to delete untracked and ignored files?

Suppose you added some new files to the working folder and later decided to remove those. There are too many files to run rm file1 file2 file3 .... .

Another scenario is, you want to delete the temporary files which are mentioned in .gitignore

Doing this deletes from your local working directory.

Be careful!

You can run git clean

From man pages:

Cleans the working tree by recursively removing files that are not under version control, starting from the current directory.

Normally, only files unknown to Git are removed, but if the -x option is specified, ignored files are also removed. This can, for example, be useful to
remove all build products.

As said, it removes recursively from current directory(where you run that command). So, to remove all untracked and/or ignored files/directories, run it from the root of the project directory.

To remove untracked files: git clean -f

To remove untracked and ignored files: git clean -xf

To remove untracked directories and files: git clean -fd

To remove untracked and ignored directories and files: git clean -xfd

Why -f, --force?

If the Git configuration variable clean.requireForce is not set to false, git clean will refuse to delete files or directories unless given -f, -n or
-i. Git will refuse to delete directories with .git sub directory or file unless a second -f is given.

This command actually deletes files and directories physically. So, you might be intimidated by running this command and hope you are not doing wrong by deleting ā€œnot-to-deleteā€ files/directories.

If you are scared(like me), you can use this command in ā€œInteractive Modeā€ by running git clean -fi

You can select option 4 and Git asks whether to remove it or not for every file.

From man pages:

git clean ā€” help

Want to revert un-committed changes?

You have run git commit and later edited some files in the project. After hours of work, you want to delete the changes or un-edit those files to previous staging version.

You can use: git checkout

Yeah. You heard that right. The innocent git checkout which we often use to change branches can actually cause some destruction if used improperly.

Doing this deletes the work from your local working directory up until previous commit.

Be careful!

From man pages:

git-checkout ā€” Switch branches or restore working tree files

Updates files in the working tree to match the version in the index or the specified tree. If no paths are given, git checkout will also update HEAD to set
the specified branch as the current branch.

Just a side note: You might have seen git restore <filename> as a suggestion by Git in the above image(that might be because Iā€™m using latest version v2.25.0). Donā€™t use that because it is experimental as it is mentioned in the man pages

git restore ā€” help

Moving on ā€¦.

git checkout . can only revert any modified file to previous staging version but not to previous commit!

In the above image, the previous staging version of somedbconfigfile1 is empty. So doing git checkout . reverted the contents First message to commit to empty.

But you might think ā€œIn the above image, git checkout .reverted to previous commit right?ā€

Now, letā€™s see another example to really understand what reverting to previous staging version means.

Git doesnā€™t keep history of INDEX or STAGING AREA. It only has two states.

  1. Whatā€™s there in INDEX
  2. Whatā€™s not there in INDEX

If you run git add , Git replaces/adds itā€™s ā€œWhatā€™s there in INDEXā€ with new ā€œWhatā€™s not there in INDEXā€ data. So, you cannot iterate over your INDEX history like with your COMMIT history and restore.

So, as there are no INDEX versions left, Git gets the copy from previous commit which is somedbconfigfile1 is empty.

git checkout <filename> command can only be run on un-staged files. Thatā€™s the reason I have used git reset . to unstage the file in the above image.

I know thatā€™s a lot of things to absorb about the innocent git checkout .

I think itā€™s enough for today. Donā€™t forget to comeback to check the part 2! If your memory is as bad as mine, Hit that FOLLOW šŸ˜‰

Other useful articles

If you still got some energy to burn, then read this one about git reset. It is a must! Complete guide for git reset : https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified

If anyone finds another way to do the same things with different commands, Congratulations! Do share and enlighten our fellow developers! If you donā€™t know then yes, we can do same thing using different commands in Git. Donā€™t trust me? Look šŸ‘‡šŸ»šŸ‘‡šŸ»šŸ‘‡šŸ»

https://stackoverflow.com/a/6919749/4859791

Disclaimer: Before anyone calls me out for not giving credits for memes, I have a dope stash of them saved on my phone from all over the internet since the ā€œdot com bubbleā€. So, if you need some, mail mešŸ™‚

Liked it? Then šŸ‘šŸ»šŸ‘šŸ»šŸ‘šŸ» it and share it!

--

--

Skrew Everything

A wannabe artist šŸ‘Øā€šŸŽØ, but canā€™t draw šŸ˜«. A wannabe athlete šŸƒā€ā™‚ļø,but canā€™t run šŸ„µ.Found my peace with coding šŸ‘Øā€šŸ’» and writing āœļø. Twitter.com/SkrewEverything