Impossible with Git. And you have a mindset not matching that of required to use Git sensbibly.
First, note that you're talking about some sort of central repository without even mentioning that fact. But Git is not a centralized system -- quite contrary, it's a distributed system where each developer has its *own* repository and has total control over its contents. I mean, whatever imaginary restrictions you would like to
set up (we'll return to them shortly), they have no meaning at all in the repositories in which actual developers do their actual work.
Second, Git does not track directories. This might sound weird (to someone coming from, say, subversion) but it's true nevertheless --
the fact Git knows something about directories does not imply it actually pays any attention to them; Git indeed has the concept of "trees", which resembles directories, in its repository format, but this is just a byproduct of the fact filesystems on popular OSes Git runs on are also hierarchical. When you rename a file or directory in a Git repository, and commit this change, no information is recorded to explicitly mention this fact; to give you an example, the
git mv command which "renames" a file (possibly across directories) is just a shortcut for "delete and untrack the file then move it physically in the work tree then start tracking it at its new location".
Now let's get back to your centralized workflow. I infer from your question that you have one central ("master", "blessed", "reference" or whatever) repository everyone clones from and pushes to, and you want fine-grained control over who pushes what. Now, since Git supports so-called "hooks" -- scripts which run at key moments of the repository updates, including pushes -- you're in theory are able to write a post-receive hook which would traverse over each of the updated "refs" (branches, tags etc), then for each ref traverse the new line of commits that ref points to, and inspect it to see if the commit touches any paths you want / do not want, and fail the hook, if needed, to make the whole operation abort. You can see that this is doable but hard to get right.
Now let's try to reconsider your approach to this problem. "The Git way" in a case like this is just to not let every single developer to commit to that reference repo. Instead, have one or two designated "integrators" who will be responsible for taking changes from individual developers, *verify these changes* and, if they are okay, integrate them and push the resulting commit(s) to the main repo. If needed, your individual developers might have their own "central" repositories, serving as backups of their local ones and/or for means of easier visibility of the stuff those developers are working on. Or each developer might have their personal set of branches in the single central repository.
The de-facto standard tool to implement per-repository and per-branch read/write (or more fine-grained) access for the case of accessing the server via SSH with virtual Git users is gitolite . This tool also
makes possible to have per-developer repositories (it calls them "wild" repositories").
The proposed workflow is like this:
- Each individual developer either
Has their local repo accessible directly from their workstation (it's not hard to implement, really, -- one should stop thinking that VCS requires a server to operate) or
- Has their personal central mirror for their local repository.
- has their personal set of branches in the single central repository.
In either case each developer either works in their local repo, and integrators pull from it, or they occasionally push their work either to their personal central mirror or use their personal branches in
a central repo; in this case the integrators pull their work from there.
Integrators do actual integration and update the central repo.
No one except those folks is able to commit there, only fetch.
Of course, this approach requires certain mind bending. Linus Torvalds gave a good and lengthy explanations of this alternative mindset while helping KDE folks migrate from their CVCS to Git .