My Profile Photo

AndrewCz


Using liberty-minded opensource tools, and using them well


Shared Git Working Directory




THIS IS A REALLY BAD IDEA(TM)

THIS IS A VERY BAD IDEA - git is not meant to work like this.

Imagine a scenario in which there is a service account (godlike) with the proverbial “(ssh) keys to the kingdom”. It therefore makes sense that all work is done using this user, as just the ease of access alone is a big draw. Additionally, there is one server where the private keys are stored in order for this service account to make all of its connections. Just as likely you might see that the sysadmins would use that server to develop and test their scripts. And not only that, but the environment setup is such that the automation engine is only able to work in one of the directories, and all development is concurrently done by the various sysadmins within that directory.

Therefore, with the sysadmins all using that one directory on that one server to develop their scripts:

  • There is no ability to use branches
  • There must be some kind of special setup to specify Author and Commiter for Git
  • The users must be authenticated as themselves to push up to the remote repo
  • They must be notified if there are changed files in the local repo that have not been pushed after they had been changed.

Shared Working Directory

First off, we must realize that since git changes the files on disk every time a new branch is created, we don’t have the ability to use branches. In the event that both Bob and Alice are logged in, if Bob does a git checkout bob, and subsequently Alice does a git checkout alice, then Bob will be working on the alice branch, since the files were changed on disk, and it had nothing to do with their separate sessions.

The result of this is that all work is done on a specific branch. For the time being, this will be on master. However, I could envision a scenario in which the branch that is being developed and tested on by the sysadmins in their day to day operations is separate from the branch that is used to be pulled down for all automation workflows. There also could be some type of weekly or semi-weekly pull request that gets reviewed and approved based off of the first branch into the second. However, that is not what we’re aiming for yet.

Permissions

Permissions of the files need to be set up properly in order to allow anyone from the various groups to edit and commit them, as well as the god-like service account. This has to be done when we initialize the repository.

$ git init --shared=group
$ chown -R :godlike "$PWD"
$ chmod -R g+swX "$PWD"

This does a couple things. First, it allows anyone to use the repo who is in the repo’s group: --shared=group. However, it doesn’t specify the group. We have to do that with regular unix permissions. So first we chown the files to the group in question: godlike, and then we add the sticky bit to all of the files and directories for the group (making all new files created having the same permissions and ownership) and give those files and directories write access by the group: godlike. This ensures that regardless of whoever creates or modifies any files, the files will still have the correct permissions, and be owned by the godlike group.

Commits

Commits are a little bit trickier. Commits are subject to several different environment variables:

  • GIT_COMMITTER_NAME
  • GIT_COMMITTER_EMAIL
  • GIT_AUTHOR_NAME
  • GIT_AUTHOR_EMAIL

These variables should be set every time a user tries to make a commit. So, in order to do that, we set an alias that sets these (if they are not already set) before each and every git command:

git() {
  if [ -z "$GIT_COMMITTER_NAME" ]; then
    read -p "Git User: " UNAME
    if /usr/bin/su $UNAME -c exit; then
      GIT_COMMITTER_NAME=$UNAME
      export GIT_COMMITTER_NAME
      GIT_COMMITTER_EMAIL=$UNAME@oclc.org
      export GIT_COMMITTER_EMAIL
      GIT_AUTHOR_NAME=$GIT_COMMITTER_NAME
      export GIT_AUTHOR_NAME
      GIT_AUTHOR_EMAIL=$GIT_COMMITTER_EMAIL
      export GIT_AUTHOR_EMAIL
      echo "  using git user: $GIT_AUTHOR_NAME / $GIT_AUTHOR_EMAIL"
      /usr/bin/git "$@"
    else
      echo "Please try again..."
    fi
  else
    echo "  using git user: $GIT_AUTHOR_NAME / $GIT_AUTHOR_EMAIL"
    /usr/bin/git "$@"
  fi
}

There is of course room for authentication in this after prompting for the user’s name, but we’ll bypass that for the time being, and just prompt them for the user that we are supposed to be committing as.

Staging

Here’s a neat little puzzle. How do people remember which files they edited? It’s all well and good to hack away at whatever files are needed to be changed, but when the setup is complete and the changes have to be committed, how can a user tell which files are the ones that they edited, versus ones that a concurrently logged-in user edited? For this, there doesn’t seem to be any good answer.

Remember what files you edited. Stage only those files. Sorry.

Pushes

Pushes can be authenticated as any user. However, that user has to provide their own credentials and user at the time of push. This is simply by making sure that the remote url is set without a user. If it is, then it will always prompt for some username and its corresponding password.

Notification

The notification is going to be a bit trickier, and is as follows:

$ if [[ ! -z $(cd ${GIT REPO} && git status -s) ]]; then mail -s 'Uncommitted git files in "$PWD"' user@domain <<< $(git status); fi ]]

Or something to that effect.


References: