Can a file be both staged and unstaged in Git?
Actually the state you see is very easily to reproduce:
git init
touch test
git add test #1
echo 42 > test #2
git status #3
in #1 we stage the empty test file. #2 changes the contents of the file. These changes will no be staged (since you need to explicitly stage changes using git add
). The output of git status
in #3 tells you exactly that.
To see which changes have been staged, run git diff --cached
. To see which changes to your working copy files have not been staged, run git diff
.
In your question you state that you ran git commit
. From your git status
output it seems as if the commit was not created, probably because you did not enter a commit message. Check the output of git commit
, git probably told you what went wrong when trying to create the commit!
Where in .git could I look to see the authoritative state of this file?
Use git diff
:
git diff -- yourFile
will give you the changes not yet staged (not yet added to the index)git diff --cached -- yourFile
will give you the changes already added to the index.
See more at "Changes, not files":
Most version control systems work with files. You add the file to source control and the system tracks changes from that moment on.
Git concentrates on the changes to a file, not the file itself.
Agit add file
command does not tell git to add the file to the repository, but to note the current state of the file for it to be committed later.
See also "git add -p
: The most powerful git feature you're not using yet"
Note that git status -v -v will soon (Git 2.3.4, Q2 2015) shows you both diffs (staged and unstaged), possible listing different diffs for the same file.
See "Show both staged & working tree in git diff?".
Answer to "Does this make sense?"
It only makes sense if you understand that git does not store differences it stores snapshots.
In the example you describe there are two versions of README.md in your changes. The staged one is the version that you're currently happy with and will end up being the latest snapshot of the file if you choose to commit it. The unstaged version is is a potential snapshot that will replace the currently staged version if you choose to stage it.
Read the section 'Snapshots, Not Differences' in the following link for more understanding on how git works:
http://git-scm.com/book/en/Getting-Started-Git-Basics
Also look at the following link for a further explanation of the scenario that you've included in your question (in particular the section 'Staging Modified Files'):
http://git-scm.com/book/en/Git-Basics-Recording-Changes-to-the-Repository
This means part of the changes you made are staged for commit and parts are not.
You can check what is staged if you run
git diff --staged -- README.md
and check for what is unstaged by running
git diff -- README.md
Most version control systems generally only store the changes between two states. The way git works, while you make multiple changes to a file, you will have to add/mark each of them to be part of one set of changes a.k.a a commit. When you use git add
this is done automatically.
However it is not the only way you add can all your individual changes(hunks) to your "index". You can for example make multiple changes to the same file and commit them in different commits or add only specific changes to a commit. E.g. to explicitly add some changes to your "index" but not others, you can do so by using git add -p
to add only some "hunks" (groups) of the changes instead of the whole list of changes itself.
What has happened here is that the changes you made to README.md
before staging ( git add
) will show in staged and any changes you made after staging README.md
will show as unstaged as you have got above.