0

My problems refers to the situation described in this post. In a nutshell, there is a remote bare and a non-bare repo. According to the plan few people (including me) should be able to push their changes to the bare repo. The hooks/post-receive file makes it possible that those changes are automatically pulled into the non-bare repo at the server. This is the contents of the file:

!/bin/sh
cd /data/11_prywatne/14_Pawel/repo_pawel_non_bare/deploy || exit
unset GIT_DIR
git pull origin master

`chmod g+rwx -R /data/11_prywatne/14_Pawel/repo_pawel_non_bare/deploy/ &> /dev/null`

All has been going well while I was the only person pushing and pulling to the non-bare repo. However, once another person git push origin master some problems occured. For instance, while trying to git pull origin master at the remote non-bare repo (I know it's not necessary since there's hooks/post-receive) I got this error:

fatal: Couldn't find remote ref master
fatal: The remote end hung up unexpectedly

I tried checking with git log (at the remote non-bare) what the history of commits is and got this error:

error: Could not read <hash of the commit made by the other person>
fatal: Failed to traverse parents of commit 68e6227f4c4f84843ed7dd4fc03a159

git status (at the remote non-bare) returns the following output:

# On branch master
error: Could not read <hash of the commit made by the other person>
error: Could not read <hash of the commit made by the other person>
fatal: Failed to traverse parents of commit 68e6227f4c4f84843ed7dd4fc03a15967051a97f

git push origin master (at the remote non-bare) returns:

error: Could not read <hash of the commit made by the other person>
fatal: Failed to traverse parents of commit 68e6227f4c4f84843ed7dd4fc03a15967051a97f
error: pack-objects died with strange error

(Still at the remote non-bare) then I decided to git reset --hard and everything seemed normal, but git push origin master gets me:

error: unable to resolve reference refs/heads/master: Permission denied
remote: error: failed to lock refs/heads/master
To /data/11_prywatne/14_Pawel/gole.git/
 ! [remote rejected] master -> master (failed to lock)
error: failed to push some refs to '/data/11_prywatne/14_Pawel/gole.git/'
[user@server deploy]$ git pull origin master
fatal: git upload-pack: cannot find object <hash of the commit made by the other person>:
fatal: The remote end hung up unexpectedly

I switched to my local repo and tried to push. I got the same errors which indicated the problem is caused by Permission denied. I asked the other person to set group permissions for the file that resides in the bare repo refs/heads/master. The problem was seemingly solved, but another one occurred while trying to git push origin master:

error: Ref refs/heads/master is at <hash of the commit made by the other person> but expected 0000000000000000000000000000000000000000
remote: error: failed to lock refs/heads/master
To server_ip:/data/11_prywatne/14_Pawel/gole.git/
 ! [remote rejected] master -> master (failed to lock)
error: failed to push some refs to 'user@server_ip:/data/11_prywatne/14_Pawel/gole.git/'

While trying to git pull origin master I get:

fatal: git upload-pack: cannot find object <hash of the commit made by the other person>:
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

Just for clarification. This is the content of .git/config at my local machine:

[core]
        repositoryformatversion = 0
        filemode = false
        bare = false
        logallrefupdates = true
        symlinks = false
        ignorecase = true
[remote "origin"]
        url = user@server_ip:/data/11_prywatne/14_Pawel/gole.git/
        fetch = +refs/heads/*:refs/remotes/origin/*

The .git/config file on the other person's machine differs only when it comes to the url it points to (user2@server:/data/11_prywatne/14_Pawel/gole.git/).

The same file but in the non-bare repo at the server:

[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
[remote "origin"]
        fetch = +refs/heads/*:refs/remotes/origin/*
        url = /data/11_prywatne/14_Pawel/gole.git/
[branch "master"]
        remote = origin
        merge = refs/heads/master

Probably I missed some steps while creating a non-bare repo. Should I consider some internal git options that enable creating shared non-bare repos? Does my use of chmod indicate that I've made a mistake? How can I solve the problem with ?

balkon16
  • 1,338
  • 4
  • 20
  • 40

1 Answers1

2

This is a problem with filesystem permissions, probably caused because the people pushing to the bare repository do so using different system accounts. You have to remember that the hook scripts runs under the same account. If any of the permissions in both the bare and the non-bare repository are too limited, it will be impossible for user A to go through this fully after user B has also pushed - some files and internal Git subdirectories will be owned by A and some by B.

For this reason, it is critical that both repos are initialized using the --shared option. You can configure this after the fact, too, but then you have to manually fix the filesystem permissions for everything that already exists and it's error-prone. It might be easier to just re-create the non-bare repo from scratch.

However, this is still not sufficient, because --shared only affects Git's own metadata and not the working tree. Your pull can still fail due to being unable to actually check out the files. Each time a pull operation creates new directories, the permissions on them will potentially be too strict.

Fixing this is outside the scope of Git - you might want to look into:

  • Having all of the users change their default umask in their accounts on that machine;
  • Setting a common primary user group for all of these users (not always feasible) OR
  • Using POSIX ACLs (which, admittedly, can be quite confusing).

If you want to sidestep these issues, another option is updating the non-bare repo in a frequently-running cronjob, so that you can be sure it is run by the same user every time.

Jan Krüger
  • 17,870
  • 3
  • 59
  • 51
  • Thank you for your comment. It clarifies what my next steps should be. Is it possible to implement one of the solutions in the `post-receive` file? I believe that all the users who push/pull from the bare repo are in the same group. – balkon16 Feb 22 '19 at 13:40
  • 1
    @balkon16 if all of the interaction with the non-bare repo happens through the `post-receive` hook, then yes, something like `chmod -f -R g+w .; chgrp -f -R .` (after pulling) could work. The second part is optional if the group in question is the primary group for all the users. Also keep in mind that this only works if the `post-receive` hook is the only way the users ever interact with the non-bare repo. – Jan Krüger Feb 22 '19 at 18:39