Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent git committers from creating certain directories

Tags:

git

Is there a way to prevent git committers from creating a directory in the repository.

We have some developers who keep misplacing files in a directory structure. Files that should be in

 a/b/c/file

End up in

 a/a/b/c/file

I simply want to prevent the creation of

 a/a/*

It needs to happen suitably obviously, so that they know their files weren't committed... thus, simply ignoring a/a/* isn't enough.

Is there a way to do this?

EDIT

A few people have pointed out that committers should be 'trained' to not do this. There are a few flaws there:

  • Committers are human and make mistakes; training won't prevent this from happening
  • This is not the kind of information that would stick in the head of a new hire during training (waaay to fine a detail)
  • Mostly, this occurs during merges from one branch to another, so the files are not being manually created, rather they are pulled over in a larger changeset.

Thus, the need for an automated approach.

like image 624
Dancrumb Avatar asked Dec 26 '22 01:12

Dancrumb


2 Answers

User education with a 2x4 clue-stick should be the first choice. For a technological solution you could prevent them from making such commits locally with a suitable commit hook. However, they probably would fail to install the hook as well. So you are left with implementing a hook that rejects their pushes. You can do this with an update hook which can reject commits before they get written into the central repository. Here is such a hook script:

#!/bin/sh
#
# update hook - args: refname sha1-old sha1-new

ref="$1"
old="$2"
new="$3"
if [ -z "$ref" -o -z "$old" -o -z "$new" ]; then
  echo >&2 "usage: $0 <ref> <oldrev> <newrev>"
  exit 1
fi

for badpath in a/a a/z/x; do
  if git ls-tree $new:$badpath >/dev/null; then
    bogus=$(git ls-tree -r --name-only $new $badpath)
    echo >&2 "REJECTED DUE TO BOGUS PATH \"$bogus\""
    exit 1
  fi
done

exit 0

If we create a simple bare repository and add this as hooks/update and make it executable (on windows, we don't need to do that - hooks are executed anyway). Then clone the repository and add a banned path (like a/b/c/file as in your example). This is what I get when I push this commit:

C:\Users\Pat\AppData\Local\Temp\x\L>git push origin master
Counting objects: 9, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (7/7), 423 bytes | 0 bytes/s, done.
Total 7 (delta 0), reused 0 (delta 0)
remote: REJECTED DUE TO BOGUS PATH "a/a/b/c/file"
remote: error: hook declined to update refs/heads/master
To C:/Users/Pat/AppData/Local/Temp/x/R
 ! [remote rejected] master -> master (hook declined)
error: failed to push some refs to 'C:/Users/Pat/AppData/Local/Temp/x/R'

This illustrates two things. Firstly, these hook scripts are actually very simple to create and to test in some temporary repository. Anything you echo to stderr or stdout gets copied to the pushing user. Second - this all works on windows too (when using Git for Windows at least).

A commit hook works on the users local repository and would be less obnoxious but you then have the problem of ensuring that all local clones have the correct hooks in place. This is much simpler to handle on the server end.

like image 175
patthoyts Avatar answered Jan 17 '23 14:01

patthoyts


This would accomplish preventing creation of a subdirectory a, but it's not ideal, and the better answer is probably training:

ln -s . a
git add a
git commit -m "Create top-level self-referential symlink to stifle subdirectory creation"
like image 36
twalberg Avatar answered Jan 17 '23 13:01

twalberg