有没有办法检查 git 标签是否与相应提交的内容匹配?

发布于 2024-12-20 04:12:01 字数 348 浏览 2 评论 0原文

在我工作的公司中,某些项目有一个 project.info 文件,其中包含程序/库/其他内容的当前版本。

实际上,当有人想要标记一个版本时,他必须首先确保 project.info 文件(已版本化)是最新的,并且包含与他所标记的名称相同的版本。即将创建。不用说这很容易出错。

我们致力于 git 的客户端-服务器工作流程(所有提交都转到同一个中央存储库),所以我想知道:有没有一种方法(也许是一个钩子?)使这个中央存储库拒绝 project.info 的标签 匹配?

我应该注意什么才能开始?

非常感谢。

In the company I work for, some projects have an project.info file which contains the current version of the program/library/whatever.

Actually, when someone wants to tag a version, he must first ensure that the project.info file (which is versionned) is up-to-date and contains the same version than the name of the tag he is about to create. No need to say that this is error prone.

We work on a clients-server workflow for git (all commits go to the same central repository) so I wonder: is there a way (a hook perhaps ?) to make this central repository refuse tags for which the project.info does not match ?

What should I look for to get started ?

Thank you very much.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一刻暧昧 2024-12-27 04:12:02

感谢这里所有的建议,我成功了。

这是我的最终 update 钩子脚本:

#!/bin/sh
#
# An example hook script to blocks unannotated tags from entering.
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
#
# To enable this hook, rename this file to "update".
#
# Config
# ------
# hooks.allowunannotated
#   This boolean sets whether unannotated tags will be allowed into the
#   repository.  By default they won't be.
# hooks.allowdeletetag
#   This boolean sets whether deleting tags will be allowed in the
#   repository.  By default they won't be.
# hooks.allowmodifytag
#   This boolean sets whether a tag may be modified after creation. By default
#   it won't be.
# hooks.allowdeletebranch
#   This boolean sets whether deleting branches will be allowed in the
#   repository.  By default they won't be.
# hooks.denycreatebranch
#   This boolean sets whether remotely creating branches will be denied
#   in the repository.  By default this is allowed.
#

# --- 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

# --- Config
allowunannotated=$(git config --bool hooks.allowunannotated)
allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
denycreatebranch=$(git config --bool hooks.denycreatebranch)
allowdeletetag=$(git config --bool hooks.allowdeletetag)
allowmodifytag=$(git config --bool hooks.allowmodifytag)
allowwildtag=$(git config --bool hooks.allowwildtag)
allowunmatchedtag=$(git config --bool hooks.allowunmatchedtag)

# check for no description
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
case "$projectdesc" in
"Unnamed repository"* | "")
    echo "*** Project description file hasn't been set" >&2
    exit 1
    ;;
esac

# --- 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
        short_refname=${refname##refs/tags/}
        if [ "$allowunannotated" != "true" ]; then
            echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
            echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
            exit 1
        fi
        ;;
    refs/tags/*,delete)
        # delete tag
        if [ "$allowdeletetag" != "true" ]; then
            echo "*** Deleting a tag is not allowed in this repository" >&2
            exit 1
        fi
        ;;
    refs/tags/*,tag)
        # annotated tag
        if [ "$allowwildtag" != "true" ] && ./hooks/check_tag -r $refname > /dev/null 2>&1
        then
            echo "*** Tag '$refname' does not match the naming constraints." >&2
            echo "*** Tags must follow the 'x.y-z' pattern, where x, y, and z are numeric characters." >&2
            exit 1
        fi
        if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
        then
            echo "*** Tag '$refname' already exists." >&2
            echo "*** Modifying a tag is not allowed in this repository." >&2
            exit 1
        fi
        if [ "$allowunmatchedtag" != "true" ] 
        then
            project_version=`./hooks/extract_project_version $newrev 2>/dev/null`

            if [ "$project_version" == "" ]
            then
                # We dont output anything in case of success
                #echo "*** Project does not contain a project.info file. No tag match performed."
                :
            elif [ "$project_version" == "error" ]
            then
                # The project contains an invalid project.info: we accept the tag but warn about it.
                echo "*** Project contains an invalid project.info file. No tag match performed."
            else
                tag_version=${refname##refs/tags/}

                if [ "$project_version" != "$tag_version" ]
                then
                    echo "*** Tag and project version do not match: $tag_version != $project_version"
                    echo "*** Please check your project.info file."
                    exit 1
                fi
            fi
        fi
        ;;
    refs/heads/*,commit)
        # branch
        if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
            echo "*** Creating a branch is not allowed in this repository" >&2
            exit 1
        fi
        ;;
    refs/heads/*,delete)
        # delete branch
        if [ "$allowdeletebranch" != "true" ]; then
            echo "*** Deleting a branch is not allowed in this repository" >&2
            exit 1
        fi
        ;;
    refs/remotes/*,commit)
        # tracking branch
        ;;
    refs/remotes/*,delete)
        # delete tracking branch
        if [ "$allowdeletebranch" != "true" ]; then
            echo "*** Deleting a tracking branch is not allowed in this repository" >&2
            exit 1
        fi
        ;;
    *)
        # Anything else (is there anything else?)
        echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
        exit 1
        ;;
esac

# --- Finished
exit 0

这是我的 extract_project_version 脚本:

#!/bin/bash

rev=$1

if [ "$rev" == "" ]
then
    echo "Missing revision parameter." >&2
    exit 1
fi

tmpdir=/tmp/$.extract_project_version

mkdir -p $tmpdir
git archive $rev | tar -x -C $tmpdir

if [ -e "$tmpdir/project.info" ]
then
    echo $tmpdir/project.info
fi

rm -rf $tmpdir

现在它完美运行:)

Thanks to all the advices here, I succeeded.

Here is my final update hook script:

#!/bin/sh
#
# An example hook script to blocks unannotated tags from entering.
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
#
# To enable this hook, rename this file to "update".
#
# Config
# ------
# hooks.allowunannotated
#   This boolean sets whether unannotated tags will be allowed into the
#   repository.  By default they won't be.
# hooks.allowdeletetag
#   This boolean sets whether deleting tags will be allowed in the
#   repository.  By default they won't be.
# hooks.allowmodifytag
#   This boolean sets whether a tag may be modified after creation. By default
#   it won't be.
# hooks.allowdeletebranch
#   This boolean sets whether deleting branches will be allowed in the
#   repository.  By default they won't be.
# hooks.denycreatebranch
#   This boolean sets whether remotely creating branches will be denied
#   in the repository.  By default this is allowed.
#

# --- 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

# --- Config
allowunannotated=$(git config --bool hooks.allowunannotated)
allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
denycreatebranch=$(git config --bool hooks.denycreatebranch)
allowdeletetag=$(git config --bool hooks.allowdeletetag)
allowmodifytag=$(git config --bool hooks.allowmodifytag)
allowwildtag=$(git config --bool hooks.allowwildtag)
allowunmatchedtag=$(git config --bool hooks.allowunmatchedtag)

# check for no description
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
case "$projectdesc" in
"Unnamed repository"* | "")
    echo "*** Project description file hasn't been set" >&2
    exit 1
    ;;
esac

# --- 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
        short_refname=${refname##refs/tags/}
        if [ "$allowunannotated" != "true" ]; then
            echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
            echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
            exit 1
        fi
        ;;
    refs/tags/*,delete)
        # delete tag
        if [ "$allowdeletetag" != "true" ]; then
            echo "*** Deleting a tag is not allowed in this repository" >&2
            exit 1
        fi
        ;;
    refs/tags/*,tag)
        # annotated tag
        if [ "$allowwildtag" != "true" ] && ./hooks/check_tag -r $refname > /dev/null 2>&1
        then
            echo "*** Tag '$refname' does not match the naming constraints." >&2
            echo "*** Tags must follow the 'x.y-z' pattern, where x, y, and z are numeric characters." >&2
            exit 1
        fi
        if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
        then
            echo "*** Tag '$refname' already exists." >&2
            echo "*** Modifying a tag is not allowed in this repository." >&2
            exit 1
        fi
        if [ "$allowunmatchedtag" != "true" ] 
        then
            project_version=`./hooks/extract_project_version $newrev 2>/dev/null`

            if [ "$project_version" == "" ]
            then
                # We dont output anything in case of success
                #echo "*** Project does not contain a project.info file. No tag match performed."
                :
            elif [ "$project_version" == "error" ]
            then
                # The project contains an invalid project.info: we accept the tag but warn about it.
                echo "*** Project contains an invalid project.info file. No tag match performed."
            else
                tag_version=${refname##refs/tags/}

                if [ "$project_version" != "$tag_version" ]
                then
                    echo "*** Tag and project version do not match: $tag_version != $project_version"
                    echo "*** Please check your project.info file."
                    exit 1
                fi
            fi
        fi
        ;;
    refs/heads/*,commit)
        # branch
        if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
            echo "*** Creating a branch is not allowed in this repository" >&2
            exit 1
        fi
        ;;
    refs/heads/*,delete)
        # delete branch
        if [ "$allowdeletebranch" != "true" ]; then
            echo "*** Deleting a branch is not allowed in this repository" >&2
            exit 1
        fi
        ;;
    refs/remotes/*,commit)
        # tracking branch
        ;;
    refs/remotes/*,delete)
        # delete tracking branch
        if [ "$allowdeletebranch" != "true" ]; then
            echo "*** Deleting a tracking branch is not allowed in this repository" >&2
            exit 1
        fi
        ;;
    *)
        # Anything else (is there anything else?)
        echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
        exit 1
        ;;
esac

# --- Finished
exit 0

And here is my extract_project_version script:

#!/bin/bash

rev=$1

if [ "$rev" == "" ]
then
    echo "Missing revision parameter." >&2
    exit 1
fi

tmpdir=/tmp/$.extract_project_version

mkdir -p $tmpdir
git archive $rev | tar -x -C $tmpdir

if [ -e "$tmpdir/project.info" ]
then
    echo $tmpdir/project.info
fi

rm -rf $tmpdir

And now it works perfectly :)

九局 2024-12-27 04:12:02

服务器端

如果您计划使用挂钩,接收后挂钩(服务器引用已更新)可以在 project.info 如果它已被忘记,但初始标记提交在文件中不会有正确的信息...

如果您想在更新引用之前验证这一点,问题在于预接收/更新挂钩< /strong> 实际上没有所需的信息检查 project.info 的有效性(它们获取正在更新的 ref 的名称、存储在 ref 中的旧对象名称以及要存储在 ref 中的新对象名称)。

您可以在此处找到一些挂钩示例那里有一些信息

关于此主题的其他一些 Stack Overflow 主题:

客户端

这不能确保任何事情,因为客户端可能决定不应用正确的方法。尽管如此,提交后挂钩也许可以解决这个问题。

Server-side

If you plan on using hooks, a post-receive hook (server refs updated) could create a commit with a change on project.info if it has been forgotten, but the initial tagging commit would not have the right information in the file...

If you want to validate this before updating the refs, the problem is that pre-receive/update hooks do not actually have the information required to check the validity of project.info (they get the name of the ref being updated, the old object name stored in the ref and the new objectname to be stored in the ref).

You can find some examples of hooks here and some information there.

Some other Stack Overflow topics on this subject :

Client-side

This would not ensure anything since clients could decide not to apply the proper method. Still, a post-commit hook could probably do the trick.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文