阻止 git 分支被推送

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6644329/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-19 05:40:46  来源:igfitidea点击:

Block a git branch from being pushed

gitbranchprivate

提问by houbysoft

Here's the situation:

这是情况:

I have a public repository for my open-source app on github.com. However, now I'd like to write some specific code that will not be public (I might use it in a commercial version of my application).

我在 github.com 上有一个用于我的开源应用程序的公共存储库。但是,现在我想编写一些不会公开的特定代码(我可能会在我的应用程序的商业版本中使用它)。

I figured I could use the same repository, and I'd create a "private" branch in my git repository that I wouldn't push.

我想我可以使用相同的存储库,并且我会在我的 git 存储库中创建一个我不会推送的“私有”分支。

But, mistakes happen. Is there some way to forbid git from ever pushing a branch to remote servers?

但是,错误时有发生。有什么方法可以禁止 git 将分支推送到远程服务器吗?

If there's a better way to handle this situation, I would of course welcome any suggestions.

如果有更好的方法来处理这种情况,我当然欢迎任何建议。

采纳答案by hammar

A slightly hackish solution: Make a dummy branch on GitHub with the same name as your real branch, and make sure it would not be a fast forward merge. That way, the push operation will fail.

一个稍微有点骇人听闻的解决方案:在 GitHub 上创建一个与真实分支同名的虚拟分支,并确保它不会是快进合并。这样,推送操作就会失败。

Here's an example.

这是一个例子。

$ git clone [email protected]: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

Now that the dummy branch is set up, we can recreate it locally to diverge from the one on GitHub.

现在虚拟分支已经建立,我们可以在本地重新创建它以与 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"

Now if we accidentally try to push, it will fail with a non-fast forward merge error:

现在,如果我们不小心尝试推送,它将因非快进合并错误而失败:

$ git push origin secret
To [email protected]:user/repo.git
! [rejected]        secret -> secret (non-fast forward)
error: failed to push some refs to ‘[email protected]:user/repo.git'

回答by Steve Bennett

Here's how the pre-pushhook approach works, with a branch called dontpushthis.

这是pre-push钩子方法的工作原理,有一个名为dontpushthis.

Create this file as .git/hooks/pre-push:

创建此文件为.git/hooks/pre-push

if [[ `grep 'dontpushthis'` ]]; then 
  echo "You really don't want to push this branch. Aborting."
  exit 1
fi

This works because the list of refs being pushed is passed on standard input. So this will also catch git push --all.

这是有效的,因为被推送的引用列表是在标准输入上传递的。所以这也会赶上git push --all

Make it executable.

使其可执行。

Do this in every local repository.

在每个本地存储库中执行此操作。

When you try to push to that branch, you'll see:

当您尝试推送到该分支时,您会看到:

$ 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'

Obviously this is as simple as it looks, and only prevents pushing the branch named "dontpushthis". So it's useful if you're trying to avoid directly pushing to an important branch, such as master.

显然,这看起来很简单,并且只会阻止推送名为“dontpushthis”的分支。因此,如果您试图避免直接推送到重要分支,例如master.

If you're trying to solve the problem of preventing confidential information leaking, it might not be sufficient. For example, if you created a sub-branch from dontpushthis, that branch would not be detected. You'd need more sophisticated detection - you could look to see whether any of the commits on the "dontpushthis" branch were present on the current branch, for instance.

如果您想解决防止机密信息泄露的问题,这可能还不够。例如,如果您从 中创建了一个子分支dontpushthis,则不会检测到该分支。您需要更复杂的检测 - 例如,您可以查看当前分支上是否存在“dontpushthis”分支上的任何提交。

A safer solution

更安全的解决方案

Looking at the question again, I think a better solution in this case would be:

再次看这个问题,我认为在这种情况下更好的解决方案是:

  1. Have one repo which is public
  2. Clone that to a new working directory which is private
  3. Remove the remote (git remote rm origin) from that working directory.
  4. To merge public changes, just do git pull https://github.com/myproj/mypublicrepo
  1. 有一个公开的回购
  2. 将其克隆到一个新的私有工作目录
  3. git remote rm origin从该工作目录中删除远程 ( )。
  4. 要合并公共更改,只需执行 git pull https://github.com/myproj/mypublicrepo

This way, the private repo working directory never has anywhere it could push to. You essentially have a one-way valve of public information to private, but not back.

这样,私有仓库工作目录永远不会有任何可以推送到的地方。你本质上有一个公开信息的单向阀,但不能返回。

回答by Lungang Fang

A touch up of the .git/hooks/pre-push script from @steve-bennett

对@steve-bennett 的 .git/hooks/pre-push 脚本的修改

    #!/usr/bin/bash

    branch_blocked=mine

    if grep -q "$branch_blocked"; then
        echo "Branch '$branch_blocked' is blocked by yourself." >&2
        exit 1
    fi

回答by Aquadarius

Why not simply use the example of pre-push provided with current git version?

为什么不简单地使用当前 git 版本提供的 pre-push 示例?

The idea is to begin the commit message of the first commit of your private branch with the word PRIVATE:.

这个想法是用这个词开始你的私有分支的第一次提交的提交消息PRIVATE:

After setting the pre-push script, for every push it checks the commit messages of all the log of pushed refs. If they start with PRIVATE:, the push will be blocked.

设置 pre-push 脚本后,对于每次推送,它都会检查所有推送的 refs 日志的提交消息。如果它们以 PRIVATE: 开头,则推送将被阻止。

Here are the steps:

以下是步骤:

  • Create a file in .git/hooks/pre-push
  • Give it execution rights
  • Past the following script in it

    #!/bin/sh
    
    remote=""
    url=""
    
    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=""
    url=""
    
  • 在里面创建一个文件 .git/hooks/pre-push
  • 赋予它执行权
  • 在其中传递以下脚本

    #!/bin/sh
    
    remote=""
    url=""
    
    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=""
    url=""
    

Example of failure

失败的例子

$ 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'

To make the branch pushable again, you can either remove the hook or, better, modify the commit message to remove the forbidden word.

要使分支再次可推送,您可以删除钩子,或者更好地修改提交消息以删除禁用词。

This script can be modified to only consider one forbidden remote by checking remote_ref. But in that case, do not forget to copy this hook in all the repos allowed to receive this branch.

这个脚本可以通过检查修改为只考虑一个被禁止的远程remote_ref。但在这种情况下,不要忘记在所有允许接收此分支的存储库中复制此钩子。

回答by Tadeck

You can create a branch that does not exist in your remote repository.

您可以创建远程存储库中不存在的分支。

That way if you just do:

这样,如果你只是这样做:

git push origin

it will push only branches that exist on the remote repository.

它只会推送远程存储库中存在的分支。

Also look into .git/config(within the local repository directory) file after creating the branch - you will see that every local branch can have different remote repository assigned. You can take advantage of that by assigning this branch to separate (private) repository, but the is not the universal solution (the branch still can be pushed to origin remote, if explicitly ordered to, or by command git push origin).

.git/config创建分支后还要查看(在本地存储库目录中)文件 - 您将看到每个本地分支都可以分配不同的远程存储库。您可以通过将此分支分配给单独的(私有)存储库来利用这一点,但这不是通用解决方案(如果明确命令或通过命令,分支仍然可以推送到远程源git push origin)。

回答by Ulrich Dangel

There are multiple solutions:

有多种解决方案:

  1. Non technical, just adjust the license to a commercial one for your branch
  2. Make a private repository on github which contains your fork
  3. Make a git-hook on the server (afaik not possible with github)
  4. Write an wrapper for git-pushto prevent the push with git push
  1. 非技术性,只需将许可证调整为您分支机构的商业许可证
  2. 在 github 上创建一个包含你的 fork 的私有仓库
  3. 在服务器上做一个 git-hook (afaik 不能用 github)
  4. 编写一个包装器git-push以防止使用 git push 推送

回答by asmeurer

If you use GitHub, you can create a branch on GitHub with the same name as your branch. There is no need to push any commits to it, just make an empty branch off master or whatever (you can do it in the GitHub interface by typing the branch in the "branch" popdown and clicking create branch <branch-name>).

如果您使用 GitHub,您可以在 GitHub 上创建一个与您的分支同名的分支。无需向其推送任何提交,只需从 master 或其他任何内容创建一个空分支(您可以在 GitHub 界面中通过在“分支”弹出窗口中键入分支并单击 来完成此操作create branch <branch-name>)。

Then, go to the branch settings for the repository (e.g., https://github.com/<user>/<repo>/settings/branches/<branch-name>) and enable branch protection for your branch. Be sure to check all the boxes, particularly, the require reviews or status checks boxes, which disallows the branch from being pushed to directly (it would have to be pushed from a pull request), and also be sure to check the box to include administrators.

然后,转到存储库的分支设置(例如,https://github.com/<user>/<repo>/settings/branches/<branch-name>)并为您的分支启用分支保护。确保选中所有框,特别是需要评论或状态复选框,这不允许将分支直接推送到(它必须从拉取请求中推送),并确保选中该框以包括管理员。

Then GitHub will not allow you to push to the branch, even if you use -f. You'll get a message like

那么 GitHub 将不允许你推送到分支,即使你使用-f. 你会收到类似的消息

$ 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 '[email protected]:<user>/<repo>.git'