Git:在pre-push hook中,忽略已经在远程任何分支上的提交

时间:2014-12-10 01:58:06

标签: git version-control githooks

我有一个预推钩(非常类似于git附带的示例预推送提交),它会检查提交消息中的特定字符串,如果找到则不会推送。

如果我创建一个新的分支(让我说我从master分支,并调用它的功能),做一些提交(不包含我想避免推送的字符串)并尝试将其推送到远程,它将如果此分支的古代历史中的某些提交包含该字符串,则会失败。

我怎样才能让git只考虑不在任何远程分支中的提交?有没有办法在不检查每个远程分支的每次提交的可达性的情况下执行此操作?

可能有效的一种方法是从分支的尖端退回一次一次提交并检查是否有指向它的远程分支,并且一旦找到,就截断正在考虑的范围这里。我是沿着正确的路线,还是有更好的方法?

以下是钩子。

#!/bin/sh

# This hook is called with the following parameters:
#
# $1 -- Name of the remote to which the push is being done
# $2 -- URL to which the push is being done
#
# If pushing without using a named remote those arguments will be equal.
#
# Information about the commits which are being pushed is supplied as lines to
# the standard input in the form:
#
#   <local ref> <local sha1> <remote ref> <remote sha1>

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
        exit 0
    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 bad commit message
        commit=`git rev-list -n 1 --grep '\bbad string\b' "$range"`
        if [ -n "$commit" ]
        then
            echo "Found commit with bad string in $local_ref, not pushing"
            exit 1
        fi
    fi
done

exit 0

2 个答案:

答案 0 :(得分:1)

这将列出$ branch上不在任何$ remote分支中的所有提交:

git fetch $remote
git rev-list $branch $(    # or git log --oneline
        git for-each-ref --format='  ^%(refname)  ' refs/remotes/$remote
)

虽然为此可以不使用git fetch。所以在哪里设置range替换

range="$local_sha $(
        git for-each-ref --format='^%(refname)' refs/remotes/$remote
)"

并且不要在命令行中引用它 - shell会将这些单词拆分得很好,每个格式化的引用都将从搜索中排除。

有一件事:那里的顶部有一个IFS=' '。更改shell的场间分隔符是一种特殊用途的东西,很少需要。那个会让它认为标签和换行不是字段分隔符,而不是你在命令输出中进行修改时想要的。

脚本的工作版本:

#!/bin/sh

# This hook is called with the following parameters:
#
# $1 -- Name of the remote to which the push is being done
# $2 -- URL to which the push is being done
#
# If pushing without using a named remote those arguments will be equal.
#
# Information about the commits which are being pushed is supplied as lines to
# the standard input in the form:
#
#   <local ref> <local sha1> <remote ref> <remote sha1>

remote="$1"
url="$2"

z40=0000000000000000000000000000000000000000

while read local_ref local_sha remote_ref remote_sha
do
    if [ "$local_sha" = $z40 ]
    then
        # Handle delete
        exit 0
    else
        if [ "$remote_sha" = $z40 ]
        then
            # New branch, examine all commits not on any remote branch
            range="$local_sha $(
                    git for-each-ref --format='^%(refname)' refs/remotes/$remote
            )"
        else
            # Update to existing branch, examine new commits
            range="$remote_sha..$local_sha"
        fi

        # Check for bad commit message
        commit=`git rev-list -n 1 --grep '\bbad string\b' $range`
        if [ -n "$commit" ]
        then
            echo "Found commit with bad string in $local_ref, not pushing"
            exit 1
        fi
    fi
done

exit 0

答案 1 :(得分:-1)

首先,您可以创建仅包含提交编号和提交消息的提交列表:

$ git log --pretty=oneline

此命令将为您提供如下所示的输出:

ca82a6dff817ec66f44342007202690a93763949 changed the version number
085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary test
a11bef06a3f659402fe7563abf99ad00de2209e6 first commit

(此示例输出是从http://git-scm.com/book/en/v2/Git-Basics-Viewing-the-Commit-History复制的)

您可以按如下方式获取最后12个提交(将12替换为您想要的提交数):

$ git log --pretty=oneline -12

您还可以过滤所需的提交号码,但不包含字符串:

$ git log --pretty=oneline -12 | grep -v "the unwanted string" | awk '{print "git cherry-pick "$1;} > cherrypick.sh

($ grep -v过滤掉不包含下一个参数的行.awk命令打印第一个标记。)

然后您可以按如下方式创建一个新分支:

$ git checkout -b new_branch_name

你将进入新的分支机构。在新分支上,您可以在第一个删除之前重置回提交(让我们调用此提交a11bef):

$ git reset --hard a11bef

然后你可以挑选你想要的提交:

$ chmod u+x cherrypick.sh
$ ./cherrypick.sh

瞧!只有您想要的提交的分支。

CAVEAT:执行此操作可能会遇到合并冲突。