Gitfence

How to Give Contractors Access to Part of a GitHub Repo

GitHub grants access per repository, not per folder. Here are the real options for giving a contractor part of a repo, with commands and tradeoffs.

Gitfence team7 min read

Short answer: GitHub can't do this natively. Repository roles (Read, Triage, Write, Maintain, Admin) apply to the whole repository, so a contractor who can read one folder can read every folder and the full history. To give someone only part of a repo, you either move that part into its own repository, publish a filtered copy, or put a path-aware layer in front of GitHub.

This guide covers each option, what it costs you, and where it leaks.

Why GitHub permissions stop at the repository

GitHub's repository roles are assigned per repository. Custom repository roles on GitHub Enterprise Cloud let you mix permissions differently, but they are still scoped to a repository, not to paths inside it. The same applies to outside collaborators, teams and fine-grained tokens.

The deeper reason is Git itself. A clone contains every commit, and every commit points to a tree that covers the whole project. Git's own documentation is direct about this in gitnamespaces: "The fetch and push protocols are not designed to prevent one side from stealing data from the other repository that was not intended to be shared. If you have private data that you need to protect from a malicious peer, your best option is to store it in another repository."

There's a long-open GitHub community request for folder-level access control, and the answers there point to the same workarounds below. See Can you restrict access to folders in a GitHub repository? for the platform-by-platform detail.

Option 1: Split the code they need into its own repository

This is the standard advice and the only one that uses GitHub's own access model.

# Extract src/widgets with its history into a new repo
git clone [email protected]:acme/app.git widgets-split
cd widgets-split
git filter-repo --subdirectory-filter src/widgets
git remote add origin [email protected]:acme/widgets.git
git push -u origin main

git filter-repo is a separate tool you install; the older git filter-branch does the same job more slowly.

Works well when the contractor's work is genuinely separable: a design system, an SDK, a mobile client that talks to an API.

Costs:

  • The rest of the code now has to consume the split repo as a package or submodule, and your team changes how it works.
  • Cross-cutting changes become multi-repo pull requests.
  • If the contractor's code imports anything from the private part, they can't build or test it. You end up publishing internal packages or writing mocks.

Option 2: Git submodules

Submodules keep a separate repository as a subdirectory of another. Put the sensitive code in a private submodule the contractor can't access; they clone the parent and simply don't get that folder.

git submodule add [email protected]:acme/pricing-core.git core/pricing
git commit -m "Move pricing into a private submodule"

A contractor without access to acme/pricing-core sees a failed submodule update and an empty directory. That is real access control, because it's a separate repository.

Costs: submodules are notorious for friction. Pro Git itself warns about detached HEADs, forgotten submodule pushes and the need for git clone --recurse-submodules. And as with splitting, the contractor can't compile against code that isn't there.

Option 3: Publish a filtered copy (Copybara, filter-repo, scripts)

Keep the real repo private and generate a second repo containing only the allowed paths. Copybara is built for exactly this ("transforming and moving code between repositories"), and a scheduled git filter-repo job works for small teams.

Works well when the contractor mostly reads, or contributes rarely.

Costs:

  • Their changes land in the copy. You have to move them back, usually by hand or with a reverse transformation you maintain.
  • Filtered history is rewritten, so commit hashes differ between the two repos. Reviewing "the same" change in two places is confusing.
  • It's another pipeline to keep running, and it breaks when someone renames a folder.

Option 4: Give full access, then restrict writes

Some teams accept that the contractor will see everything and only control what they can change:

  • CODEOWNERS plus "Require review from Code Owners" on the default branch means changes to core/ need a core owner's approval.
  • Push rulesets can "prevent commits that include changes in specified file paths from being pushed" for private and internal repositories.

This protects the integrity of core/, not its confidentiality. The contractor can still clone and read every line. See CODEOWNERS is not access control for why this distinction catches people out.

Option 5: Sparse checkout (not an option, but often suggested)

git sparse-checkout set src/widgets makes the contractor's working tree smaller. It doesn't change what they can fetch: the history still contains every file, and git sparse-checkout disable brings everything back. It's a performance feature. We cover this in Git sparse checkout vs real access control.

Comparing the options

Approach Hides code from the contractor They can build against hidden code Core team changes workflow Contractor work returns as a normal PR
Split repo Yes No Yes Only in the split repo
Submodules Yes No Yes Yes, but in two repos
Filtered copy Yes No Some No, manual sync
CODEOWNERS / push rules No Yes No Yes
Sparse checkout No Yes No Yes
Path-aware proxy (Gitfence) Yes Yes, with Types only No Yes

Option 6: A path-aware view in front of GitHub (how Gitfence does it)

Gitfence sits in front of GitHub and gives each person and AI agent their own view of the repository. You set access per folder or file, and the contractor clones a URL that only contains what they're allowed to see. Your core team keeps working in GitHub exactly as before.

Each path gets one of four levels:

  • No access: the path is absent from every commit in their clone.
  • Types only: they get generated TypeScript declarations, with literal values redacted, so code that imports the hidden module still type-checks.
  • Can read: source, read-only.
  • Can edit: full access.

For a contractor building checkout UI against your pricing engine, that might look like src/ = Can edit, core/pricing/ = Types only, infra/ and .env* = No access.

The contractor uses plain git:

git clone https://gitfence.dev/acme/app.git
git checkout -b alice/checkout
# ...edit, commit...
git push -u origin alice/checkout

Gitfence checks every changed path against their permissions, applies the change onto the full upstream tree, and opens an ordinary GitHub pull request. Pushes to the default branch are rejected. Your reviewers see a normal PR, and your CI, review bots and branch protection still apply.

A few details that matter for contractors:

  • Hidden objects are never in their repo. The view repository is built by fetching filtered commits, so hidden blobs don't exist there. Our security tests check clones over protocol v0 and v2, --depth 1, --filter=blob:none, --filter=tree:0 and --mirror, and direct fetches of hidden object IDs.
  • Tests against the real code. Since core/ isn't in their clone, they can't run the full suite locally. Fenced CI runs the tests on the real code in a sandbox with no network access and redacts hidden source from the output. For people you trust less, summary mode returns only pass or fail.
  • NDA before code. Invitations can require signing an NDA or other document before the first clone. See NDAs for developers before code access.
  • Exceptions and requests. You can grant one person an exception to a group's rules, and contractors (or their AI agents) can request access to a path, which an admin approves or denies.

Limits you should know

  • Gitfence controls what a contractor can see from the moment it's in place. It can't take back code they already cloned before.
  • Commits that change both hidden and visible files keep their message, so don't put secrets in commit messages.
  • Fenced CI redaction catches verbatim and lightly reformatted source, not encoded output such as base64. Use summary mode for untrusted people.
  • Today Gitfence supports GitHub only, and Types only mode supports TypeScript.

Pricing is per restricted person: full-access teammates are free. Details are on pricing, and the contractor workflow is described on Gitfence for contractors.

Which option should you pick?

  • One-off, self-contained job: split the code into its own repository.
  • Long-running contractor who needs the rest of the codebase to compile: a filtered view with Types only for the parts they call.
  • You trust them with all source and only care about changes: CODEOWNERS plus branch protection or push rulesets.
  • Never: sparse checkout as a security measure.

If the contractor works with an AI coding agent, the same scoping applies to the agent; see protecting source code from AI coding agents and contractors. The same approach also works for onboarding new developers without full codebase access.

FAQ

Can I give a GitHub collaborator access to just one folder?

No. Collaborator and team permissions on GitHub apply to the whole repository. To limit someone to a folder you need a separate repository, a filtered copy, or a proxy such as Gitfence.

Can a contractor with Read access clone a private repository?

Yes. Read access lets someone clone the repository, including its full history. Read is a repository-wide permission, not a folder-level one.

Does disabling forking stop a contractor from copying the code?

No. The forking policy controls whether a private repository can be forked on GitHub. It doesn't stop someone with read access from cloning and pushing the code somewhere else.

How do I revoke a contractor's access when the contract ends?

On GitHub, remove them from the repository or organization and revoke any deploy keys or tokens they had. In Gitfence, remove the membership or let the access end date pass; their clone URL stops working. In both cases, they keep whatever they already downloaded.

Do contractors need a GitHub account to use Gitfence?

They use Sign in with GitHub to accept an invitation, but they never receive GitHub access to your repository. They clone and push through Gitfence, and their pushes arrive in GitHub as pull requests.

Fence your first repository in minutes

Free for one repository and your own team. Add a restricted person and Pro is free for 14 days, no card.