【问题标题】:How can I prevent non-fastforward pushes to selected branch(es) in git?如何在 git 中防止非快进推送到选定的分支)?
【发布时间】:2012-07-15 00:51:30
【问题描述】:

我想保护我的 git 存储库,以便只覆盖非主分支。有没有办法只保护选定的分支?

【问题讨论】:

    标签: git git-push fast-forward


    【解决方案1】:

    This SO answer 将为您提供所需的内容。只需编辑它以应用于主分支:

    #!/bin/sh
    # lock the master branch for pushing
    refname="$1"
    
    if [ "$refname" = "refs/heads/master" ]
    then
        echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
        echo "You cannot push to the master branch."
        echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
        exit 1
    fi
    exit 0
    

    更新:
    这将阻止所有推送到主分支,包括快进。

    【讨论】:

    【解决方案2】:

    您可以通过配置denyNonFastForwards来防止非快进更新

    git config --system receive.denyNonFastForwards true
    

    但它适用于所有分支。 更多信息请参考ProGit

    【讨论】:

      【解决方案3】:

      您可以使用GitEnterprise 设置每个分支权限(管理员),以使用细粒度访问权限阻止非快进推送。

      如果您需要阻止所有分支的历史更改,git config --system receive.denyNonFastForwards true 将简单地完成这项工作。

      【讨论】:

      • denyNonFastForwards 不是您应该使用的“分辨率”。设置一个 git 钩子来拒绝强制推送...这是正确的方法。
      • @Eric 拒绝非快进推送实际上是 GitHub/BitBucket 的方式。没有发明新的自行车。
      • 如果您拒绝每个分支上的所有非快进,那么您将如何合并您的功能分支?
      • @Eric 这只发生在你的本地仓库中。如果您现在将这个重新定位的分支合并回 master 并将其推送到远程仓库,这将是一个安全的快进推送,具有清晰的历史记录。
      • 好吧,我想我理解应该应用“重写提交是一个坏主意”的上下文。这不是“所有重写提交都是不好的”的全面覆盖。相反,只重写远程上的提交。我认识到,之前我被告知应该避免“所有重写提交”。当他们最初误解了为什么重写提交是不好的。只是一种不同的阅读方式!谢谢!!
      【解决方案4】:

      我认为这取决于您在服务器端使用什么来访问您的存储库。有一些服务器应用程序支持每个分支的权限,例如 GerritGitlab(但是,我不确定 Gitlab 是否支持您的用例)。 Gerrit 支持它,因为我在公司使用类似的工作流程。

      也许Gitolite 也支持它(这是 Gitlab 在后台使用的),它更易于设置,但没有 Gerrit 或 Gitlab 之类的 Web 界面。

      补充说明:建议的 GitEnterprise 也是一个很好的解决方案,不过我的建议是合适的,如果您有自己的服务器(这在许多公司中很常见)。

      【讨论】:

        【解决方案5】:

        这是我为自己使用而编写的更新挂钩(复制到挂钩/更新)。默认情况下,此脚本拒绝所有非快进更新,但允许它们用于显式配置的分支。反转它应该很容易,以便除 master 分支之外的所有分支都允许非快进更新。

        #!/bin/sh
        #
        # A hook script to block non-fast-forward updates for branches that haven't
        # been explicitly configured to allow it. Based on update.sample.
        # Called by "git receive-pack" with arguments: refname sha1-old sha1-new
        #
        # Config
        # ------
        # hooks.branch.<name>.allownonfastforward
        #   This boolean sets whether non-fast-forward updates will be allowed for
        #   branch <name>. By default they won't be.
        
        # --- Command line
        refname="$1"
        oldrev="$2"
        newrev="$3"
        
        # --- Safety check
        if [ -z "$GIT_DIR" ]; then
                echo "Don't run this script from the command line." >&2
                echo " (if you want, you could supply GIT_DIR then run" >&2
                echo "  $0 <ref> <oldrev> <newrev>)" >&2
                exit 1
        fi
        
        if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
                echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
                exit 1
        fi
        
        # --- Check types
        # if $newrev is 0000...0000, it's a commit to delete a ref.
        zero="0000000000000000000000000000000000000000"
        if [ "$newrev" = "$zero" ]; then
                newrev_type=delete
        else
                newrev_type=$(git cat-file -t $newrev)
        fi
        
        case "$refname","$newrev_type" in
                refs/tags/*,commit)
                        # un-annotated tag
                        ;;
                refs/tags/*,delete)
                        # delete tag
                        ;;
                refs/tags/*,tag)
                        # annotated tag
                        ;;
                refs/heads/*,commit)
                        # branch
                        # git rev-list doesn't print anything on fast-forward updates
                        if test $(git rev-list "$newrev".."$oldrev"); then
                                branch=${refname##refs/heads/}
                                nonfastforwardallowed=$(git config --bool hooks.branch."$branch".allownonfastforward)
        
                                if [ "$nonfastforwardallowed" != "true" ]; then
                                        echo "hooks/update: Non-fast-forward updates are not allowed for branch $branch"
                                        exit 1
                                fi
                        fi
                        ;;
                refs/heads/*,delete)
                        # delete branch
                        ;;
                refs/remotes/*,commit)
                        # tracking branch
                        ;;
                refs/remotes/*,delete)
                        # delete tracking branch
                        ;;
                *)
                        # Anything else (is there anything else?)
                        echo "hooks/update: Unknown type of update to ref $refname of type $newrev_type" >&2
                        exit 1
                        ;;
        esac
        
        # --- Finished
        exit 0
        

        【讨论】:

        • 如果您可以修改脚本以便除 master 分支之外的所有分支都允许非快进更新,那将会很有用
        • 查看我下面的帖子,对这个脚本进行轻微修改,允许对允许的分支进行通配符
        【解决方案6】:

        如果您被允许修改您的服务器,那么这将在服务器上启用快速转发。

        ssh ip 'echo $"[receive]
            denyDeletes = false
            denyNonFastForwards = false" >> /path/to/repo/config'
        #then git push -f origin master
        

        【讨论】:

          【解决方案7】:

          这是对Tanu Kaskinen 脚本的修改,以允许对分支名称进行通配符。我们使用名称以“d/”开头的分支来指定“开发”分支。我想要一种方法来允许这些 d/ 分支的非快进更新:

             refs/heads/*,commit)
                      # branch
                      # git rev-list doesn't print anything on fast-forward updates
          
                      if [[ $(git rev-list "$newrev".."$oldrev") ]]; then
                              branch=${refname##refs/heads/}
                              if [[ "$branch" =~ ^d/ ]] ; then
                                echo "Non-fast-forward update allowed on d/ branch"
                                nonfastforwardallowed="true";
                              else
                                #look for a specific config setting
                                nonfastforwardallowed=$(git config --bool  hooks.branch."$branch".allownonfastforward)
                              fi
          
          
                              if [ "$nonfastforwardallowed" != "true" ]; then
                                      echo "hooks/update: Non-fast-forward updates are not allowed for branch $branch"
                                      exit 1
                              fi
                      fi
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-08-13
            • 2013-12-26
            • 2013-10-09
            • 2012-11-03
            • 2016-06-06
            • 2019-03-28
            • 2016-07-13
            • 2020-12-31
            相关资源
            最近更新 更多