Merging

File renaming problems

If, while merging, you encounter the following scary message:

  warning: too many files, skipping inexact rename detection

You'll get a whole lot of merge conflicts which one would imagine git could have taken care of. The problem, at least in my case, is that because detecting file name changes is currently an O(n^2) operation for git, which may take a long time--especially when you take into account the number of files in our repository. As such, git defines an upper limit on the search, so that it will stop after m iterations. This limit defaults to 1, but can be set by changing the value of diff.renamelimit to something higher. A value of 400, in my case, seemed to do the trick.

insufficient permission for adding an object

If, while pushing to the repo in AFS, you encounter one of the following error messages:

  insufficient permission for adding an object to repository database

  error: unable to create temporary sha1 filename ./objects/fb: Permission denied

Something like git-gc must have run recently, and so directories in 'objects' need to be recreated. Git would do that as needed, but it doesn't know anything about AFS ACLs and is confused by the unix permissions it sees in our repo. The following bash shell commands may be used to rectify the situation:

cd /afs/cs.wisc.edu/p/condor/repository/CONDOR_SRC.git/objects
for i in `seq 0 255`; do dir=`printf "%02x" $i`; mkdir -p $dir; done

The version of git installed under /unsup/git on the CS dept AFS server includes a patch to avoid this problem.

Details

Whenever git creates a directory under .git, it also sets the directory permissions, including the S_ISGID bit. This bit isn't supported under AFS, and the chmod() will fail with errno EACCES. This causes git to abort the entire push. Git uses S_ISGID to ensure all files have the same group, and not whatever primary group each committer has when they push. Explanation from a git maintainer:

We fix directory permissions after creating any directory under .git
with the same code, so that in a repository shared by group, new
subdirectories created by a random somebody who belongs to that
group will belong to that group (we also chmod to g+wx in case such
a random somebody has overly strict umask).  Instead of running
chown(2) on every new file created by us, we let the filesystem to
take care of it by telling the directories we create that new files
in them should inherit their group ownership.

What we were worried about back when we decided to use S_ISGID was a
scenario like this:

* A repository is shared by group "src".

* A user belongs to the group "src".  That group may or may not be
  his primary group (i.e. "mkdir foo" done at random place by him
  may not belong to the "src" group).

* The user attempts to create a new branch "foo/bar" by pushing
  from outside.  There is no other branch whose name is
  "foo/anything" when this happens.

* An equivalent of "mkdir -p .git/refs/heads/foo" needs to be done
  before an equivalent of "echo $sha >.git/refs/heads/foo/bar"
  happens to accept this push.  We want "foo" and "bar" to belong
  to "src" group and they get appropriate permission bits suitable
  to be accessed by the members of the "src" group.

The story is the same for loose objects and their fan-out directory.
Storing a commit object fb/012345... may need to create the leading
fan-out ".git/objects/fb" and we want that directory and any future
files created in it to belong to the "src" group.

Any alternative implementation that achieves the same result that
works on AFS can be substituted with the current code, or made
conditionally activated on AFS.