This is kind of a weird one, and I apologize in advance if it doesn't have much application outside of my specific circumstances. I am using git to manage my deployment packages by committing and tagging a set of generated files relating to the deployment and a submodule which points to the release code. I am attempting to do a git checkout of this deployment tag from a bare repo on each machine into a different, empty directory. The output I get indicates that it has deleted the files it should have created, and the work-tree directory remains empty afterward.
$ ls -al /var/www/test/
total 0
$ git --bare --work-tree=/var/www/test/ checkout my_tag
D .gitmodules
D generated.tgz
D release
D signatures.md5
HEAD is now at 8946ff5... Generated contents of deployment package.
$ ls -al /var/www/test/
total 0
I should state that both the commit referenced by my_tag and the tip of master have the same 4 files (though with different contents). Which makes it all the stranger that the following procedure gets me 75% of the way there:
$ git --bare --work-tree=/var/www/test/ checkout master
D .gitmodules
Previous HEAD position was 8946ff5... Generated contents of deployment package.
Switched to branch 'master'
$ ls -al /var/www/test/
total 4
-rw-r--r-- 1 root root 0 Oct 17 17:00 generated.tgz
drwxr-xr-x 2 root root 4096 Oct 17 17:00 release
-rw-r--r-- 1 root root 0 Oct 17 17:00 signatures.md5
$ git --bare --work-tree=/var/www/test/ checkout my_tag
D .gitmodules
(---- git's warning about detached HEAD state cut ----)
HEAD is now at 8946ff5... Generated contents of deployment package
$ ls -al /var/www/test/
total 4624
-rw-r--r-- 1 root root 2103765 Oct 17 17:02 generated.tgz
drwxr-xr-x 2 root root 4096 Oct 17 17:00 release
-rw-r--r-- 1 root root 2614883 Oct 17 17:02 signatures.md5
The thing is, "release" is a git submodule, and I can't init or update it without .gitmodules, so 75% of the way there still isn't good enough.
One solution to this problem would be to simply clone the repo anew every time I deploy, and maybe I'll go that way if nobody can suggest a better solution. But ideally I'd like to keep one bare repo on each machine and checkout from that to a new work-tree each time. Can anybody tell me what's going on here?
For reference, I'm using Git 1.8.2.1.
The basic problem is that checkout
is comparing the desired revision (my_tag
, master
) against what's in HEAD
in the --bare
repo. (And the --bare
argument is doing nothing.) So with my_tag
, it says you're already in detached HEAD
mode and on the desired rev—i.e., it should not change HEAD
—and looks into the target directory, /var/www/test/
, and sees that the files have been removed and gives you the D
status for each. It assumes they were there because of the index (see below).
When you switch to checkout master
, it figures: OK, you're moving from this detached-HEAD
to master
, it updates HEAD
and checks out the changed files. But .gitmodules
is the same in my_tag
and head
, so that one remains D
eleted.
If you use checkout -f
, it will assume it should replace the missing files.
Git also has the bad habit :-) of using $GIT_DIR/index
to record what it is doing with the checkout, as well as $GIT_DIR/HEAD
. This leads to left-behind files when files are removed from the thing you're trying to deploy. If the target directory is emptied out before doing a checkout -f
that should be OK though. (Alternatively, set GIT_INDEX_FILE
in the environment, naming a file you keep along with each unique deployment. I have not experimented with this but it should work well.)