阻止用户推送已删除的分支

时间:2015-01-21 18:23:34

标签: git

考虑这个测试脚本。

#!/bin/sh -x

rm -rf test clone*

# create a test repo containing one branch called "branch"
git init test
cd test
echo foo > foo
git add foo
git commit -am "initial commit"
git branch branch

# create three clones of the repo
cd ..
git clone test clone1
git clone test clone2
git clone test clone3

# push a commit on the branch in clone1
cd clone1
git checkout branch
echo bar > foo
git commit -am "bar"
git push origin branch

# from clone2, delete the branch in the origin
cd ../clone2
git push --delete origin branch

# from clone3, push a commit on the branch
cd ../clone3
git checkout branch
echo baz > foo
git commit -am "baz"
git push origin branch

此脚本创建一个包含三个克隆的测试仓库。克隆1在分支上推送提交;克隆2推送删除分支;克隆3在分支的陈旧版本上推送提交。

如果Clone 2没有删除分支,那么克隆3在尝试推送分支时会出错。例如如果您注释掉“clone2”行,则克隆3的推送被正确拒绝。

但是在Clone 2删除分支之后,没有什么能阻止Clone 3推送分支的陈旧副本;克隆3用户可能甚至不知道该分支曾被删除,或者该分支根本就是陈旧的。

我理解为什么会这样:删除git branches从历史记录中删除它们。从git的角度来看,Clone 3正在创建一个新的新分支,恰好不包括Clone 1的已删除提交。

但这不是我想要的。我想让Clone 3在尝试推送到已删除的分支时收到某种错误或警告消息,这句话说:“嘿,伙计!那个分支被删除了!你需要 - 强制推送如果你想重新创造它。“

这可能吗?

1 个答案:

答案 0 :(得分:3)

您无法获得--force+标记,但可以拥有pre-receiveupdate个标记在完成推送的裸存储库中。

在任何一种脚本中,您都会被告知要更新哪些参考。分支只是一个引用,其全名以refs/heads/开头(名称的其余部分是分支名称,可能包含更多斜杠)。您可以检查这是否在"禁止"如果是,请拒绝推送。

(其他名称以refs/tags/开头,如果是标签,refs/notes/,如果它们是注释,依此类推。)

pre-receiveupdate挂钩之间的主要区别在于,前者在其标准输入上同时给出了所有建议的参考更新列表,而后者则一次一个地给出建议的参考更新。要么可以说"允许"或"拒绝",但因为pre-receive挂钩只运行一次所有更新,其允许/拒绝是全有或全无:您检查所有更新一次并确定当时是否允许他们都是。 update挂钩每个引用运行一次,并且可以拒绝某些单独更新,同时允许其他更新。

两个钩子每次更新都会收到三个项目:名称,前一个(又称旧)SHA-1和建议的新SHA-1。在这两种情况下,如果旧的SHA-1是全零,则创建引用名称;如果新的SHA-1是全零,它将被删除;它存在,但如果两个SHA-1都不是特殊的全零,则从一个提交 1 移动到另一个提交。

两个钩子都没有得到任何关于这是否是强制推动的迹象。这意味着如果你想允许一些故意重新创建这些禁止分支的方法,你必须想出一些替代方案。

一种可能性就是拥有一定的祝福"用户:那些(至少在理论上)知道他们正在做什么的人被允许重新创建这样的分支。 (我相信这通常是首选解决方案。)

另一种(相当hacky)方法是使用多个钩子。在预接收挂钩中,如果要更新的引用之一具有一些特殊名称(例如," refs / force"),则允许重新创建分支;然后,在更新挂钩中,拒绝该特定的特殊名称,或使用post-receive挂钩删除" force"参考文献

可以让pre-receive hook允许all,然后更新钩子拒绝一些:结果只是允许那些没有被单独拒绝的人。用户看到的输出可能有点可怕/令人困惑,但是:他们会收到拒绝消息,并且必须意识到它仅适用于某些特定的 ref更新,而不是作为一个整体的推动。

您必须存储"已删除"的列表。某处的分支(可能在由钩子维护的文件中,并在删除分支时更新)。

请注意,如果你使用gitolite,它内置了很多这种控件。它接管了一些钩子,并要求每个人都按特定用户推送,所以它的运行方式有点不同于只是按照我上面描述的方式使用原始钩子。


1 或标记或其他对象,但分支名称应始终指向提交。标记名称通常指向提交(轻量级标记)或标记对象(带注释的标记)。可以直接在blob或tree对象上有一个引用点,但分支和标记名称都不应该这样做。

相关问题