Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between git rm cached and git reset HEAD

I am confused with git rm --cached I guess.
I have a repository and a file committed. I modify the file and I do: git add myfile
The file is now staged.
When I do git status:

# On branch master   
# Changes to be committed:  
#   (use "git reset HEAD <file>..." to unstage)  
#  
#       modified:   com/main/StringMain.java  
#  

Now the file is a modified tracked file. So I assume that is in the staging area. So I can't understand what is the meaning of the recommendation (use "git reset HEAD <file>..." to unstage). So I did: git rm --cached instead followed by a git commit. But this seems to removed my file from being tracked and made it untracked.
If I do git status:

# On branch master  
# Untracked files:  
#   (use "git add <file>..." to include in what will be committed)  
#  
#       com/  
nothing added to commit but untracked files present (use "git add" to track)  

So what has happened?

like image 318
Cratylus Avatar asked Jun 15 '13 10:06

Cratylus


People also ask

What is git rm cached?

git rm --cached command remove files from your local git repository. The --cached flag deletes the file from your git repository, it becomes an untracked file in your project folder. Note you have to commit the changes.

What does git reset head do?

The git reset HEAD~2 command moves the current branch backward by two commits, effectively removing the two snapshots we just created from the project history. Remember that this kind of reset should only be used on unpublished commits.

Does git rm -- cached delete the file?

By default, the git rm command deletes files both from the Git repository as well as the filesystem. Using the --cached flag, the actual file on disk will not be deleted.


2 Answers

Here is one way to think about it:

git rm --cached [file]

This simply removes a file from being tracked (the state a file is in after it is added - i.e. git add [file])

git reset HEAD [file]

This simply continues to keep tracking changes to the file, but will place it back into the 'unstaged' area.

Here is an example.

First, I created 4 untracked files:

$ for i in {A..D}; do touch $i; echo "First line" > $i; done
$ ls
A   B   C   D
$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)

    A
    B
    C
    D

nothing added to commit but untracked files present (use "git add" to track)

Next, I track them using git add, then I will commit the changes:

$ git add .

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   A
    new file:   B
    new file:   C
    new file:   D

$ git commit -m "First Commit"
[master 6e8d625] First Commit
 4 files changed, 4 insertions(+)
 create mode 100644 A
 create mode 100644 B
 create mode 100644 C
 create mode 100644 D

$ git status
On branch master
nothing to commit, working directory clean

Now I will modify file A so git picks up the change, then I will add the changed file to the staging area:

$ echo "First line of file A" > A

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   A

no changes added to commit (use "git add" and/or "git commit -a")

$ git add A

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   A

Now this is where the differences matter.

The first example that I will give you is what happens when you use git rm --cached :

$ git rm --cached A
rm 'A'

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    deleted:    A

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    A

Notice how file A is now untracked, much like how it was prior to adding it into git in the very beginning (when "git add ." was used).

Now, the second example is if I were to use git reset HEAD instead:

$ git reset HEAD A
Unstaged changes after reset:
M   A

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   A

no changes added to commit (use "git add" and/or "git commit -a")

Here you will notice that it resets the status of file A back to an unstaged state, but still continues to track the changes of it.

like image 167
Ethan Bannister Avatar answered Oct 24 '22 06:10

Ethan Bannister


git rm --cached removes the file from the index.

git reset HEAD resets the index version of the file back to its state in the HEAD commit.

So the difference is that the first removes the file, while the second reverts it to the last committed version.


To verify this, you can use git diff to compare the working tree to the index, and git diff --cached to compare the index to the head commit.

When you run git rm --cached, the modified file is removed entirely from the index. It is still present in the working directory and the last commit. If you compare the index with the last commit:

git diff --cached modified_file

You'll see that the modified file is not present in the index. This is confirmed by:

git status

Which will show the file as being scheduled for deletion on commit. Your working directory was not affected by git rm --cached, because --cached works directly in the index.

like image 33
Andomar Avatar answered Oct 24 '22 07:10

Andomar