Mercurial钩子不允许提交大型二进制文件

Mercurial钩子不允许提交大型二进制文件,mercurial,hook,pre-commit-hook,mercurial-hook,Mercurial,Hook,Pre Commit Hook,Mercurial Hook,我想要一个Mercurial钩子,它将在提交一个事务之前运行,如果提交的二进制文件大于1兆字节,该事务将中止该事务。我发现下面的代码除了一个问题外运行良好。如果我的变更集涉及删除一个文件,这个钩子将抛出一个异常 钩子(我使用的是pretxncommit=python:checksize.newbinsize): 例外情况: $ hg commit -m 'commit message' error: pretxncommit hook raised an exception: apps/he

我想要一个Mercurial钩子,它将在提交一个事务之前运行,如果提交的二进制文件大于1兆字节,该事务将中止该事务。我发现下面的代码除了一个问题外运行良好。如果我的变更集涉及删除一个文件,这个钩子将抛出一个异常

钩子(我使用的是
pretxncommit=python:checksize.newbinsize
):

例外情况:

$  hg commit -m 'commit message'
error: pretxncommit hook raised an exception: apps/helpers/templatetags/include_extends.py@bced6272d8f4: not found in manifest
transaction abort!
rollback completed
abort: apps/helpers/templatetags/include_extends.py@bced6272d8f4: not found in manifest!
我不熟悉编写Mercurial hooks,所以我很困惑到底发生了什么。如果hg已经知道文件被删除了,为什么钩子会关心它呢?有没有办法固定这个钩子,让它一直工作

更新(已解决): 我修改了钩子以过滤掉变更集中删除的文件。

对于ctx中的f.files()
将包括删除的文件,您需要过滤掉这些文件

(您可以将范围内的版本(ctx.rev(),tip+1)的
替换为范围内的版本(ctx.rev(),len(repo)):
,然后删除
tip=…


如果您使用的是现代hg,那么您不会使用
ctx=context.changectx(repo,node)
,而是
ctx=repo[node]

在最近的Mercurial中,这在shell钩子中非常容易做到:

if hg locate -r tip "set:(added() or modified()) and binary() and size('>100k')"; then
  echo "bad files!"
  exit 1
else
  exit 0
fi

这是怎么回事?首先,我们有一个文件集来查找所有有问题的更改文件(请参阅HG1.9中的“hg帮助文件集”)。“locate”命令与status类似,只是它只列出文件,如果找到任何文件,则返回0。我们指定'-r tip'来查看挂起的提交。

如何从ctx.files()中筛选删除的文件?捕获异常就足够了;)
def newbinsize(ui, repo, node=None, **kwargs):
    '''forbid to add binary files over a given size'''
    forbid = False
    # default limit is 10 MB
    limit = int(ui.config('limits', 'maxnewbinsize', 10000000))
    ctx = repo[node]
    for rev in xrange(ctx.rev(), len(repo)):
        ctx = context.changectx(repo, rev)

        # do not check the size of files that have been removed
        # files that have been removed do not have filecontexts
        # to test for whether a file was removed, test for the existence of a filecontext
        filecontexts = list(ctx)
        def file_was_removed(f):
            """Returns True if the file was removed"""
            if f not in filecontexts:
                return True
            else:
                return False

        for f in itertools.ifilterfalse(file_was_removed, ctx.files()):
            fctx = ctx.filectx(f)
            filecontent = fctx.data()
            # check only for new files
            if not fctx.parents():
                if len(filecontent) > limit and util.binary(filecontent):
                    msg = 'new binary file %s of %s is too large: %ld > %ld\n'
                    hname = dpynode.short(ctx.node())
                    ui.write(_(msg) % (f, hname, len(filecontent), limit))
                    forbid = True
    return forbid
if hg locate -r tip "set:(added() or modified()) and binary() and size('>100k')"; then
  echo "bad files!"
  exit 1
else
  exit 0
fi