I set up a new Git repository using the following commands:
mkdir plans-for-world-domination
cd plans-for-world-domination
git init
echo "MWA HA HA HA HA!" > plans.txt
git add .
git commit -m "Beginning my plans..."
Then I made a clone of this repository, made some changes, committed them, and then tried to push:
cd ..
git clone plans-for-world-domination clone
cd clone
echo "Step 1: set up super secret spy base in Cleveland, Ohio" >> plans.txt
git commit -am "Update plans"
git push origin master
When I cd
back into the plans-for-world-domination
repository though, there are changes staged in the staging-area/index that are the reverse of the changes that I just pushed:
$ cd ../plans-for-world-domination
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: plans.txt
$ git diff --staged
diff --git a/plans.txt b/plans.txt
index febb495..ce01362 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1,2 +1 @@
MWA HA HA HA HA!
-Step 1: set up super secret spy base in Cleveland, Ohio
Why does my first repo have these unstaged changes that are the reverse of what I just pushed, and how can I fix this?
Pushes don't update the working-copy and staging-area in non-bare repositories
The staging area in the first repository appears to contain the reverse of the changes that were just pushed because it's a non-bare repository, meaning that it contains a working copy, which is also frequently referred to as a working (directory) tree in the Git documentation. Bare repositories, on the other hand, don't have a working copy directory.
Since the repository is non-bare, when you push to it, the push only updates branch references, and the symbolic
HEAD
reference, becausegit push
doesn't operate on the working-copy and staging area that are present in non-bare repos.As a consequence of this, the working-copy and staging-area of the non-bare repo are still left on the same state of the repository that was present before the push that updated
HEAD
. In other words, the actual state of the working-copy and staging-area do not match the state of the commit pointed to byHEAD
. This is why those differences between the two states show up whengit status
andgit diff
are run:(Sub-optimal) solution: hard reset
Since the working-copy and staging-area are out of sync with
HEAD
, a solution to get them to match again is to simply useto reset the working-coy and staging-area to the commit pointed to by
HEAD
.However, this is not the ideal solution...
Ideal solution: push to bare repositories instead
You're not really supposed to push to non-bare repositories, because of this exact issue of their working-copies and staging-areas de-syncing with the repository references. Instead, unless you have an unusual reason to push to a non-bare repository, you really ought to push to bare repositories instead, which don't have a working copy.
To create a bare repository, simply use the
--bare
flag:Pushing to non-bare repositories is denied by default since Git 1.6.2
Note that since Git version 1.6.2, pushing to non-bare repositories has been denied by default:
In fact, when you try to push to a non-bare repo with current versions of Git, you're push should be denied with the following error message (slightly modified for brevity):
As the error message above explains, you can disable the safety checks that prevent you from pushing into a non-bare repo by disabling the
receive.denyCurrentBranch
config setting in the remote non-bare repo: