Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/mercurial/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Version control 预先提交mercurial钩子以停止对错误分支的提交_Version Control_Mercurial_Mercurial Hook - Fatal编程技术网

Version control 预先提交mercurial钩子以停止对错误分支的提交

Version control 预先提交mercurial钩子以停止对错误分支的提交,version-control,mercurial,mercurial-hook,Version Control,Mercurial,Mercurial Hook,我在Mercurial存储库中有一个软件 我正在将我的软件项目打包为Debian包。 这似乎是一个标准的方法来做到这一点是有一个 Debian包文件的单独分支, 它们位于debian子目录中 我一直存在的一个问题是,我忘记了我是哪个分支 打开并意外地提交到错误的分支。这种情况会发生 经常,而且真的很烦人。当这种情况发生时,我通常 在意识到问题之前,按遥控器,然后 要手动修复本地和远程存储库 疼痛 我能想到的唯一选择是有一个预提交钩子 如果我试图对错误的分支进行提交,该操作将中止 具体来说,假设主

我在Mercurial存储库中有一个软件

我正在将我的软件项目打包为Debian包。 这似乎是一个标准的方法来做到这一点是有一个 Debian包文件的单独分支, 它们位于
debian
子目录中

我一直存在的一个问题是,我忘记了我是哪个分支 打开并意外地提交到错误的分支。这种情况会发生 经常,而且真的很烦人。当这种情况发生时,我通常 在意识到问题之前,按遥控器,然后 要手动修复本地和远程存储库 疼痛

我能想到的唯一选择是有一个预提交钩子 如果我试图对错误的分支进行提交,该操作将中止

具体来说,假设主分支称为
default
,而 包含Debian文件的称为
Debian
。然后我希望提交到
默认值
仅当提交中没有任何文件来自
debian
目录我希望只有在所有 提交中的文件位于
debian
目录中

我花了一些时间阅读Mercurial Hooks一章,并浏览了一些示例 在Hg的书中,但仍然不知道如何去做这件事。我确实得到了强烈的印象 对于这样的东西,我应该调用一个外部Python脚本,可能是这样
.hg/
中,是的,
预提交
钩子可以做到这一点。如果您想在bash中执行此操作,您可以使用以下内容:

#!/bin/bash
revs=$(hg log -r "$HG_NODE:tip" --template '{rev} ') #Intentional space after {rev}
rc=0
for rev in $revs
do
    files=$(hg log -r $rev --template '{files}')
    #Above will include discards. So you cannot 'hg cat' them all. So you may want
    #  files=$(hg log -r $rev --template '{file_mods} {file_adds}')
    branch=$(hg log -r $rev --template '{branch}')
    for file in $files
    do
        if [ branch == "debian" ] &&  [ "$(echo $file | grep -v "debian")" != "" ] ; then
          echo "ERROR: Non debian file in debian branch."
          exit 1
        fi
        if [ branch != "debian" ] &&  [ "$(echo $file | grep "debian")" != "" ] ; then
          echo "ERROR: debian file in non-debian branch."
          exit 1
        fi
    done
done
exit $rc

那些if/grep行几乎肯定是错误的,但你明白了。

使用@Ry4an的解决方案作为起点,我使用新的API编写了以下脚本


下面的代码是使用进程内钩子的方法。这些 函数可以在Mercurial存储库的
.hgrc
中使用,如下所示

pretxncommit.foo = python:mercurial_hooks.abort_commit_to_wrong_branch
pre-qfinish.bar = python:mercurial_hooks.qfinish_abort_commit_to_wrong_branch
中止提交到错误分支
不允许正常提交到错误分支 分支,但允许MQ提交<代码>qfinish\u abort\u commit\u到错误的分支 停止qfinish将错误分支上的MQ提交转换为 定期提交

我在上使用了函数
finish
供参考

def abort_commit_to_wrong_branch(ui, repo, **kwargs):
    """
    Don't allow commits to 'debian' branch including files not
    contained in the 'debian/' directory. Also don't allow commits to
    non-'debian' branches including files contained in the 'debian/'
    directory. Don't restrict MQ commits.
    """
    # If repo has '_committingpatch' attribute, then it is an mq
    # commit in progress, so return 'False'
    import os
    ctx = repo[kwargs['node']]
    files = ctx.files()
    branch = ctx.branch()
    if hasattr(repo, "_committingpatch"):
        for f in files:
            d = os.path.dirname(f)
            if branch == "debian" and d != "debian":
                ui.warn("Warning: committing %s (file not in 'debian' directory) to 'debian' branch. Allowed since this ia an MQ commit.\n"%f)
            if branch != "debian" and d == "debian":
                ui.warn("Warning: committing %s (file in 'debian' directory) to non 'debian' branch. Allowed since this ia an MQ commit.\n"%f)
        return False
    for f in files:
        d = os.path.dirname(f)
        if branch == "debian" and d != "debian":
            ui.warn("Error: cannot commit %s (file not in 'debian' directory) to 'debian' branch\n"%f)
            return True
        if branch != "debian" and d == "debian":
            ui.warn("Error: cannot commit %s (file in 'debian' directory) to non 'debian' branch\n"%f)
            return True

def qfinish_abort_commit_to_wrong_branch(ui, repo, **kwargs):
    """
    Don't allow qfinish on 'debian' branch including files not
    contained in the 'debian/' directory. Also don't allow qfinish on
    non-'debian' branches including files contained in the 'debian/'
    directory. Don't restrict MQ commits.
    """
    from mercurial import scmutil
    import os
    if not repo.mq.applied:
        ui.status(('no patches applied\n'))
        return True
    opts = kwargs['opts']
    # case corresponding to `-a`. no revisions specified.
    if opts.get('applied'):
        revrange = ('qbase::qtip',)
    # case where revision(s) specified
    revrange = kwargs['pats']
    revs = scmutil.revrange(repo, revrange)
    # loop over revisions
    for rev in revs:
        ctx = repo[rev]
        files = ctx.files()
        branch = ctx.branch()
        for f in files:
            d = os.path.dirname(f)
            if branch == "debian" and d != "debian":
                ui.warn("Error: cannot commit %s (file not in 'debian' directory) to 'debian' branch\n"%f)
                return True
            if branch != "debian" and d == "debian":
                ui.warn("Error: cannot commit %s (file in 'debian' directory) to non 'debian' branch\n"%f)
                return True

谢谢Ryan,这非常有帮助。使用shell而不是Python有什么好处吗?Python是在过程中运行的,因此效率更高,但您将学习一种新的api,而不是在提交中获取当前分支名称和文件列表,而您可能已经知道如何在bash中实现这一点。最后,可能更多的是关于您和您的团队以后会发现更容易定制的内容。这里可以找到一些例子:Hi Ryan。不知道你说的不是api是什么意思。你是说Mercurial没有固定的“官方”API吗?官方API是命令行。Matt Mackall非常重视命令行向后兼容性,但是内部构件,比如“repo”对象上的函数名随时可能发生更改。实际上,它们不会有太大的变化,但未来的Mercurial升级可能会破坏python钩子,而保证不会破坏bash钩子。
def abort_commit_to_wrong_branch(ui, repo, **kwargs):
    """
    Don't allow commits to 'debian' branch including files not
    contained in the 'debian/' directory. Also don't allow commits to
    non-'debian' branches including files contained in the 'debian/'
    directory. Don't restrict MQ commits.
    """
    # If repo has '_committingpatch' attribute, then it is an mq
    # commit in progress, so return 'False'
    import os
    ctx = repo[kwargs['node']]
    files = ctx.files()
    branch = ctx.branch()
    if hasattr(repo, "_committingpatch"):
        for f in files:
            d = os.path.dirname(f)
            if branch == "debian" and d != "debian":
                ui.warn("Warning: committing %s (file not in 'debian' directory) to 'debian' branch. Allowed since this ia an MQ commit.\n"%f)
            if branch != "debian" and d == "debian":
                ui.warn("Warning: committing %s (file in 'debian' directory) to non 'debian' branch. Allowed since this ia an MQ commit.\n"%f)
        return False
    for f in files:
        d = os.path.dirname(f)
        if branch == "debian" and d != "debian":
            ui.warn("Error: cannot commit %s (file not in 'debian' directory) to 'debian' branch\n"%f)
            return True
        if branch != "debian" and d == "debian":
            ui.warn("Error: cannot commit %s (file in 'debian' directory) to non 'debian' branch\n"%f)
            return True

def qfinish_abort_commit_to_wrong_branch(ui, repo, **kwargs):
    """
    Don't allow qfinish on 'debian' branch including files not
    contained in the 'debian/' directory. Also don't allow qfinish on
    non-'debian' branches including files contained in the 'debian/'
    directory. Don't restrict MQ commits.
    """
    from mercurial import scmutil
    import os
    if not repo.mq.applied:
        ui.status(('no patches applied\n'))
        return True
    opts = kwargs['opts']
    # case corresponding to `-a`. no revisions specified.
    if opts.get('applied'):
        revrange = ('qbase::qtip',)
    # case where revision(s) specified
    revrange = kwargs['pats']
    revs = scmutil.revrange(repo, revrange)
    # loop over revisions
    for rev in revs:
        ctx = repo[rev]
        files = ctx.files()
        branch = ctx.branch()
        for f in files:
            d = os.path.dirname(f)
            if branch == "debian" and d != "debian":
                ui.warn("Error: cannot commit %s (file not in 'debian' directory) to 'debian' branch\n"%f)
                return True
            if branch != "debian" and d == "debian":
                ui.warn("Error: cannot commit %s (file in 'debian' directory) to non 'debian' branch\n"%f)
                return True