我们可以只在Git 仓库中设置一个分支的可访问权限吗?

Can we set the permission of accessible to a branch only in a Git repository?

我们想与我们的合作伙伴共享一个特定的分支。假设我们在 Git 存储库上有一个项目,它有一个 masterdevelop 和几个 feature/* 分支。

现在,我们从 develop 分支分支出一个 feature/prepare_shared_code 分支,并删除一些专有代码。并从 feature/prepare_shared_code 分支分支一个 feature/work_phase_I 分支。

我们能否将权限设置为特定用户只能访问此 feature/work_phase_I 分支?也就是说,用户只能从该分支查看(日志)、读取(克隆)、写入(推送)和创建(分支)。无法查看developmasterfeature/prepare_shared_code等特性分支,无法获取源代码的专有部分。

我们只是在Windows服务器上使用Apache+Git解决方案,这不容易为git用户设置权限.然而,我们已经尝试转移到 GitBlit,它可能是 Windows OS 上最强大的 Java-stack Git 服务器。虽然可以管理用户的权限,但仅限于per repository,还有一些branch protection,比如合并前的review check,不允许强制push。

TL;DR: 不,你不能直接授予用户对分支的访问权限,同时还阻止他们查看分支的整个历史记录。

为什么?

每个 Git 提交都包含一个指向上一个提交的指针。因此,如果您的历史看起来像这样:

* ffffff [feature/prepare_shared_code] some private commit
| * eeeeee [feature/work_phase_I] some public commit
| * dddddd some public commit
|/
* cccccc remove credentials
* bbbbbb some private commit
* aaaaaa some private commit

然后通过授予用户对 feature/work_phase_I 的访问权限,您不仅授予他们提交 eeeeeedddddd 的权限,而且还授予他们提交 aaaaaabbbbbb,和 cccccc(以及 aaaaaa 中的任何 parents)。

这不是可以在不重写历史记录的情况下修复的问题 server-side,因为之前的提交包含在用于生成提交哈希的数据中。 (理论上,某些 Web 服务可以隐藏特定用户的特定提交,但我认为这不是您要问的。)

解决方法

这里有两种可能的解决方法。

第一个是更好的 long-term 选项:重新组织您的代码库,这样您的专有代码就不会与更多 public 代码混在一起。根据您的技术堆栈和您对 "proprietary codes" 的定义,这可能意味着创建库/包、将凭据移动到 .gitignored 配置文件、将代码移动到子模块等。

第二个选项可以在不重组代码库的情况下完成。您可以使用孤立分支和压缩合并来维护与专有代码 none 的单独历史记录。

创建一个孤立分支:

git checkout --orphan partner_code some_public_branch
git commit -m "Initial public commit"

然后每当你想用新的更改更新分支时,执行:

git checkout partner_code
git merge --squash feature/work_phase_I

--squash 标志将阻止 feature/work_phase_I 的整个历史记录包含在 partner_code 中。

Re-integrating 变化

你在问题中没有提到合作伙伴分支上的更改是否需要合并到主线分支中,但是既然你提到了功能分支,我认为是这样。

在我的测试中,从孤立分支到您的私有分支执行正常的 git merge 操作可能会导致无关的合并冲突。我找到了两个解决方法。

Cherry-pick

如果只有几个提交,您可以 git cherry-pick 从孤立分支到您的私有分支的每个提交。

变基

如果孤儿分支上有大量提交,您可以使用临时分支和git rebase来自动化该过程。

git checkout -b temp partner_code
git rebase --onto feature/work_phase_I abcdef12 temp

其中 abcdef12partner_code 分支上的最后一次提交 您需要的提交之前。

这会将 partner_code 分支上的任何新提交复制到基于 feature/work_phase_I 的名为 temp 的分支,因此您现在可以根据需要将其与您的私有分支合并.

Server-side支持

我的回答集中在如何创建一个不包含历史上任何专有代码的分支。完成此操作后,使用例如限制用户对 server-side 上的那个分支的访问应该很简单。 Gitolite。此设置的 Gitolite 规则可能如下所示:

repo myrepo
  RW+              = @devs
  RW partner_code$ = @partners

这将允许 devs 组中的任何人都具有完全访问权限,并且 partners 组中的任何人都可以读取和(fast-forward)写入 partner_code分支.