Reputation: 325
Given a Git repository and a committed file a
.
I remove the file with an O/S command: $ rm a
Calling git status
returns:
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
deleted: a
no changes added to commit (use "git add" and/or "git commit -a")
Next, I'm calling git rm
followed by git status
which yields:
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: a
Git's man pages description of the command git rm
:
Remove files from the index, or from the working tree and the index.
From my understanding, what happened in the above command sequence is that git rm
put the change of deleting the file into the staging area (which I'm using synonymously with index), instead of removing something from it.
What is my misconception here?
Upvotes: 1
Views: 841
Reputation: 4250
In order to understand the man page of git rm
you need to understand how the staging area (i.e. index) and git status
work.
You can think of working tree, staging area and commit referenced by head as three folders with the same content in a clean situation (i.e. git status
shows no diff):
Working Staging HEAD
--------- --------- ------
a a a
The question is how git status
detect changes?:
When you execute rm a
, you are removing a only from the working copy, obtainin this:
Working Staging HEAD
--------- --------- ------
- a a
git status
detect one unstaged change because there is a difference between working and staging, and no staged changes since there is no difference between staging and HEAD
When you execute git rm a
, as the documentation states, a
is removed also from the staging area, resulting in:
Working Staging HEAD
--------- --------- ------
- - a
Which allows git status
to detect one staged change and no unstaged changes.
Following this way of thinking you can understand some other commands suggested by git status itself:
git add <file>...
- to update what will be committed, i.e. copy file from working to staginggit-commit
- Record changes to the repository, i.e. copy every file from staging to HEAD (also creates a new commit and moves HEAD)git checkout -- <file>...
to discard changes in working directory, i.e. copy from staging to working copygit reset HEAD <file>
to unstage, i.e. copy from HEAD to stagingAs a side note, git rm --cached a
will result in this:
Working Staging HEAD
--------- --------- ------
a - a
Git status will show the removal of a
as staged for commit, since there is a difference between staging and head, but also a
as untracked: there is a difference between working and staging, but since the file is missing from the staging area, git status detects it as untracked file instead of unstaged change
Upvotes: 1
Reputation: 45649
The index is not a list of changes. Go clone a repo containing a sizable project. Don't change anything, don't stage anything.
ls -l .git/index
Why is it so big? Isn't the index empty? Well, no. Because the index is not a list of changes.
The index contains a representation of a snapshot of the project. (Or, during a merge, multiple such representations.) A commit also is a snapshot of the project.
Many commands, such as status
, interpret one state of the project (in this case the one that's staged) in terms of the difference from another version (in this case, the HEAD
commit).
If I create a new repo, checked out at master
, create file1
and file2
, and commit these, then the new commit contains two files and so does the index.
As the documentation accurately states, git rm file1
would then remove file1
from the index. git status
would then compare the index to the existing commit, and seeing that file1
was in the latter but not the former, it will say that "delete file1
" is a change staged for commit.
Upvotes: 2
Reputation: 387667
What git rm
does is add the change to the index to remove a file from the working directory. So you are staging the removal of a file. This may sound a bit weird but this is the clearest way you can think of it.
A commit contains changes, changes you have previously staged. Usual changes include new files and file changes, but also file removals. So the removal of a file is considered a change, and by calling git rm
you are adding that change to the index.
This is btw. the reason why you can use things like git add -u
to add all pending changes and also have file removals included: The file removal is a pending change, so when you add it, you are adding the change to remove the file.
In addition, what git rm
also does it physically remove the file from the working directory. So if you did not delete the file using rm
first, Git would have deleted it from the working directory as well. If the file is already removed, then Git will only stage the removal change. Related to this is git rm --cached
which will also stage the removal of the file but will not physically remove the file from the working directory. So this will only stage the change to remove the file (although that change hasn’t been physically executed).
Upvotes: 5
Reputation: 1
actually git rm
deletes files from your local directory and the changes will be pushed to your repository within the next commit. So the deleted file can't be seen in your repository anymore. While using rm
the file will only be deleted from your local repository and the changes won't be written to your origin repo. Therefore, you don't have to use rm
before git rm
.
Upvotes: 0