情况如下:
我在github.com上有一个公共仓库,用于我的开源应用程序。然而,现在我想编写一些特定的代码,这些代码将不会公开(我可能会在商业版应用程序中使用它)。
我想使用同一个仓库,在我的git仓库中创建一个"私有"分支,我不会进行推送。
但是,错误难免会发生。有没有办法禁止git将分支推送到远程服务器上?
如果有更好的处理这种情况的方法,我当然欢迎任何建议。
pre-push
钩子方法,主要用于与名为dontpushthis
的分支一起使用。请按照以下步骤创建.git/hooks/pre-push
文件:#!/usr/bin/bash
if [[ `grep 'dontpushthis'` ]]; then
echo "You really don't want to push this branch. Aborting."
exit 1
fi
这能生效是因为推送的参考列表被传递到标准输入流中。所以这也会捕获 git push --all
。
将其设为可执行文件。
在每个本地仓库中操作此步骤。
当你尝试将其推送到该分支时,你将看到:
$ git checkout dontpushthis
$ git push
You really don't want to push this branch. Aborting.
error: failed to push some refs to 'https://github.com/stevage/test.git'
master
),则非常有用。dontpushthis
创建了一个子分支,则无法检测到该分支。您需要更复杂的检测 - 您可以查看当前分支上是否存在“dontpushthis”分支上的任何提交,例如。git remote rm origin
)
4. 要合并公共更改,只需执行git pull https://github.com/myproj/mypublicrepo
这样,私有存储库工作目录永远没有可以推送的地方。实际上,您拥有一个公共信息到私有信息的单向阀门,但不能返回。一个有点hack的解决方案:在GitHub上创建一个与你的真正分支同名的虚拟分支,并确保它不会是快进合并(fast forward merge)。这样,推送操作将失败。
以下是一个例子。
$ git clone git@github.com:user/repo.git
$ cd repo
$ git checkout -b secret
$ echo "This is just a dummy to prevent fast-forward merges" > dummy.txt
$ git add .
$ git commit -m "Dummy"
$ git push origin secret
现在虚拟分支已经设置好了,我们可以在本地重新创建它以与GitHub上的分支产生分歧。
$ git checkout master
$ git branch -D secret
$ git checkout -b secret
$ echo "This diverges from the GitHub branch" > new-stuff.txt
$ git add .
$ git commit -m "New stuff"
现在,如果我们不小心尝试进行push操作,它将会因为无法进行快速向前合并而失败:
$ git push origin secret
To git@github.com:user/repo.git
! [rejected] secret -> secret (non-fast forward)
error: failed to push some refs to ‘git@github.com:user/repo.git’
pre-push
钩子并将其包含在本地存储库中,但该脚本需要放置在每个具有分支访问权限和推送能力的存储库中。 - Dan Hunsaker#!/usr/bin/bash
branch_blocked=mine
if grep -q "$branch_blocked"; then
echo "Branch '$branch_blocked' is blocked by yourself." >&2
exit 1
fi
为什么不直接使用当前git版本提供的pre-push示例呢?
这个想法是在你的私有分支的第一次提交的提交消息中使用单词PRIVATE:
。
设置pre-push脚本后,每次推送时,它会检查所有已推送ref的日志的提交消息。如果它们以PRIVATE:开头,则会阻止推送。
以下是步骤:
.git/hooks/pre-push
Past the following script in it
#!/bin/sh
remote="$1"
url="$2"
z40=0000000000000000000000000000000000000000
IFS=' '
while read local_ref local_sha remote_ref remote_sha
do
if [ "$local_sha" = $z40 ]
then
# Handle delete
:
else
if [ "$remote_sha" = $z40 ]
then
# New branch, examine all commits
range="$local_sha"
else
# Update to existing branch, examine new commits
range="$remote_sha..$local_sha"
fi
# Check for WIP commit
commit=`git rev-list -n 1 --grep '^PRIVATE:' "$range"`
if [ -n "$commit" ]
then
echo "Error: Found PRIVATE commit in $local_ref."
echo "The commit is in the range $range."
echo "NOT pushing!"
exit 1
fi
fi
done
exit 0
remote="$1"
url="$2"
失败示例
$ git push origin private/old-kalman-filter
Found PRIVATE commit in refs/heads/myforbiddenbranch, the commit is in the range
a15c7948676af80c95b96430e4240d53ff783455. NOT PUSHING!
error: failed to push some refs to 'remote:/path/to/remote/repo'
如果要使分支能够再次推送,可以删除挂钩或者更改提交消息以删除被禁止的词。
通过检查remote_ref
,可以修改此脚本以仅考虑一个被禁止的远程。但在这种情况下,请不要忘记将此挂钩复制到允许接收此分支的所有存储库中。
$ git push -f origin private
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 981 bytes | 981.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
remote: error: GH006: Protected branch update failed for refs/heads/private.
remote: error: At least 1 approving review is required by reviewers with write access.
To github.com:<user>/<repo>.git
! [remote rejected] private -> private (protected branch hook declined)
error: failed to push some refs to 'git@github.com:<user>/<repo>.git'
有多种解决方案:
git push origin
它只会推送在远程仓库上存在的分支。
创建分支后,请查看本地仓库目录中的.git/config
文件 - 您将看到每个本地分支都可以分配不同的远程仓库。您可以通过将此分支分配给单独的(私有)仓库来利用它,但这并非普遍解决方案(如果明确命令或使用git push origin
命令,则仍然可以将分支推送到源远程)。
git push remote branch
的方式,这会使你所提到的两个if条件无效。 - manojldsgit push origin my_private_branch
),为什么您认为git不应该这样做?实际上,我认识的大多数人都只使用git push
(或git push [remote]
),如果有多个分支、远程和编写git push origin my_private_branch
似乎要写100次,这样效率会低得多。 - Tadeck
#!/bin/sh if [[ `grep -e develop -e master` ]]; then echo "请不要直接推送到develop或master分支" exit 1 fi
- Jacob Evans