2

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

我将我的软件项目打包为 Debian 包。执行此操作的标准方法似乎是为 Debian 软件包文件创建一个单独的分支,这些文件位于debian子目录中。

我一直遇到的一个问题是我忘记了我在哪个分支上并且不小心提交到了错误的分支。这种情况经常发生,真的很烦人。发生这种情况时,我通常会在意识到问题之前推送到远程,然后必须手动修复本地和远程存储库,这很痛苦。

我能想到的唯一选择是有一个预提交钩子,如果我试图提交到错误的分支,它会中止。

具体来说,假设调用了主分支,调用default了包含 Debian 文件的分支debian。然后,我希望default 仅当提交中的所有文件都不来自debian 目录时,才能成功提交分支。我希望debian仅当提交中的所有文件都在目录中时,才能成功提交debian目录。

我花了一些时间阅读有关 Mercurial Hooks 的章节并浏览了 Hg Book 中的示例,但仍然不知道如何去做。我确实得到了强烈的印象,对于这样的事情,我应该调用一个外部 Python 脚本,可能在.hg/.

4

3 回答 3

3

是的,你知道precommit钩子可以做到这一点。如果您想在 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 行几乎肯定是错误的,但你明白了。

于 2013-10-08T00:45:27.887 回答
0

使用进程内挂钩的方法是以下代码。这些函数可以.hgrc像这样在 Mercurial 存储库中使用。

pretxncommit.foo = python:mercurial_hooks.abort_commit_to_wrong_branch
pre-qfinish.bar = python:mercurial_hooks.qfinish_abort_commit_to_wrong_branch

abort_commit_to_wrong_branch不允许正常提交到错误的分支,但允许 MQ 提交。qfinish_abort_commit_to_wrong_branch 阻止 qfinish 将错误分支上的 MQ 提交转换为常规提交。

finishhttps://bitbucket.org/mirror/mercurial/src/tip/hgext/mq.py?at=default#cl-3034中使用了该功能以 供参考。

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
于 2013-10-13T20:00:16.943 回答
0

以@Ry4an 的解决方案为起点,我使用新的hglib API 提出了以下脚本。

#!/usr/bin/python                                                                                                                                                         

# Abort commit to the debian branch if it is not contained in a debian                                                                                                    
# subdirectory                                                                                                                                                            

# Similary abort commit to non-debian branches if it is contained in a                                                                                                    
# debian subdirectory                                                                                                                                                     

import hglib, os, sys
client = hglib.open("/home/faheem/hooktest")
ctx = client['tip']
files = ctx.files()  
branch = ctx.branch()

for f in files:
    d = os.path.dirname(f)
    if branch == "debian" and d != "debian":
        sys.exit("cannot commit %s (file not in 'debian' directory) to 'debian' branch"%f)
    if branch != "debian" and d == "debian":
        sys.exit("cannot commit %s (file in 'debian' directory) to non 'debian' branch"%f)
于 2013-10-10T19:59:03.740 回答