git missing work tree

2019-04-14 02:12发布

问题:

I am receiving the "[remote rejected] master branch is currently checked out" error - essentially the same problem as the OP at this post (Git push error '[remote rejected] master -> master (branch is currently checked out)'), and following is what I have done so far to fix it, but now it seems I have a choice between having the above-stated problem or a new one - the "missing work-tree" error, and as explained below, this is where I am currently stuck.

Please also note that I have a different requirement than the other question. I do NOT want two repos, one bare and one non-bare - just the single repo (origin/remote), from which the local machines will be pulling/pushing code - and which is a live web server. The other post did not specify any requirement along these lines (and this option was not addressed there), but my needs are very specific, hence this question.

Also note that it is unavoidable that sometimes there may be direct edits to this directory's files on the server (albeit still using Git), rather than being pushed from a local workstation to the server (remote).

First I reset the repo, setting it to to bare (the developer who originally set Git up on the server only used the git init command when he set up the repo):

    git init --bare    

Then, because all my server files were already present (it is not an empty directory), I did an initial commit, by this method (the usual):

    git add .
    git commit -m "initial commit"

Then I edited the .git/config file thusly:

    git config receive.denyCurrentBranch ignore    

My current server .git/config file looks like this:

[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true

[receive]
        denyCurrentBranch = false

I am able to push commits successfully, BUT if I try to then apply this:

    git checkout -f

as suggested above (presumably to accept all the commits and reset the HEAD to include all my changes?), I receive the following fatal error:

    fatal: This operation must be run in a work tree

Do I need to set the worktree to this directory? If so, how do I do that? And if I do that, will the result still be in keeping with my stated goal (again, no separate bare and non-bare repos - just the single directory, which is ALSO serving a live web site and is located in the web root)?

Is there anything else I need to do that I am missing?

I have read widely on stackoverflow on this topic, including: Git init --bare - Not Working on working tree fatal: This operation must be run in a work tree Difference between HEAD / Working Tree / Index in Git The Pro-Git book (esp here: http://git-scm.com/book/ch2-2.html) Git-Flow (nvie): http://nvie.com/posts/a-successful-git-branching-model/

All help and comments greatly appreciated. Thank you!

回答1:

You've created a bare git repository (which does not by itself have a working tree). A bare git repository is the recommended way to go when you want to push changes.

And from your question, I understand that you have some sort of server setup, and everytime you do a git push, you want the files on the server to be updated to reflect the newly pushed changes.

Yes it is do-able, but you need to separate the bare repo and work-tree. The work-tree location should correspond to the location where your files need to be deployed on the server. Let's just assume it is /foor/bar. By setting up a post-receive hook, you can deploy the new files to this worktree location, after every push automatically.

These are the steps for this setup:

  1. Create the work-tree directory if it does not exist already.

    mkdir -p /foo/bar
    
  2. Create the following script and copy it in as bare-repo's hooks/post-receive

    #! /bin/sh
    GIT_WORK_TREE=/foo/bar git checkout -f
    
  3. Mark this script as executable:

    chmod +x hooks/post-receive
    

That's all that will be required. Now try a git push and your new changes will be automatically deployed onto /foo/bar location.

A note of caution: git checkout -f clobbers all local changes in any of the tracked files and any such changes in /foo/bar will be lost on a new checkout -f. Any files that are not tracked in git but created/generated under /foo/bar, should not be affected.

Also I would suggest to get rid of the changes you've made in the .git/config, especially for receive.denyCurrentBranch.

Your config should look like this IMO:

[core]
    repositoryformatversion = 0
    filemode = true
    bare = true
    logallrefupdates = true


标签: git workflow