smuge滤波器中“ git Decord”的评估时间



在将旧的SVN存储库成功转换为git之后,使用svn2git,我的任务是重现$Revision$关键字扩展(或关闭近似值(。

>

所以我...

  • 为SVN的 Rev0

  • 添加了svn-r注释标签
  • .git/attributes中添加

    * filter=revsion
    
  • .git/configure中添加

    [filter "revsion"]
        smudge = /bin/sed -e 's/\$Revision\$/$Revision: '$(GIT_EXEC_PATH=/usr/lib/git-core/ /usr/bin/git describe --match svn-r)'$/g'
        clean = /bin/sed -e 's/\$Revision: [^$]*\$/$Revision$/g'
    

...而且它有效,但是正在做错误 thing。

每当我进行结帐时,它都会扩展上一个 HEADgit describe(结帐(。这样,当我在 master 〜1 上进行 git checkout master时。我得到了 master〜1 的扩展,而不是 master

只是为了确保早期评估不是.git/config$(...)的错

因此,我的问题是:是否有一种方法可以使git describe由A smudge filter 运行在结帐之后描述commit /p>

tl; dr:a(测试(解决方案

尝试此后检查挂钩(尽管已测试,尽管很轻微;我也将其放在GitHub上的脚本存储库中(:

#! /usr/bin/env python
"""
post-checkout hook to re-smudge files
"""
from __future__ import print_function
import collections
import os
import subprocess
import sys
def run(cmd):
    """
    Run command and collect its stdout.  If it produces any stderr
    or exits nonzero, die a la subprocess.check_call().
    """
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    stdout, _ = proc.communicate()
    status = proc.wait()
    if status != 0:
        raise subprocess.CalledProcessError(status, cmd)
    return stdout
def git_ls_files(*args):
    """
    Run git ls-files with given arguments, plus -z; break up
    returned byte string into list of files.  Note, in Py3k this
    will be a list of byte-strings!
    """
    output = run(['git', 'ls-files', '-z'] + list(args))
    # -z produces NUL termination, not NUL separation: discard last entry
    return output.split(b'')[:-1]
def recheckout(files):
    """
    Force Git to re-extract the given files from the index.
    Since Git insists on doing nothing when the files exist
    in the work-tree, we first *remove* them.
    To avoid blowing up on very long argument lists, do these
    1000 files at a time or up to 10k bytes of argument at a
    time, whichever occurs first.  Note that we may go over
    the 10k limit by the length of whatever file is long, so
    it's a sloppy limit and we don't need to be very accurate.
    """
    files = collections.deque(files)
    while files:
        todo = [b'git', b'checkout', b'--']
        # should add 1 to account for b'' between arguments in os exec:
        # argbytes = reduce(lambda x, y: x + len(y) + 1, todo, 0)
        # but let's just be very sloppy here
        argbytes = 0
        while files and len(todo) < 1000 and argbytes < 10000:
            path = files.popleft()
            todo.append(path)
            argbytes += len(path) + 1
            os.remove(path)
        # files is now empty, or todo has reached its limit:
        # run the git checkout command
        run(todo)
def warn_about(files):
    """
    Make a note to the user that some file(s) have not been
    re-checked-out as they are modified in the work-tree.
    """
    if len(files) == 0:
        return
    print("Note: the following files have been carried over and may")
    print("not match what you would expect for a clean checkout:")
    # If this is py3k, each path is a bytes and we need a string.
    if type(b'') == type(''):
        printable = lambda path: path
    else:
        printable = lambda path: path.decode('unicode_escape')
    for path in files:
        print('t{}n'.format(printable(path)))
def main():
    """
    Run, as called by git post-checkout hook.  We get three arguments
    that are very simple, so no need for argparse.
    We only want to do something when:
     - the flag argument, arg 3, is 1
     - the two other arguments differ
    What we do is re-checkout the *unmodified* files, to
    force them to re-run through any defined .gitattributes
    filter.
    """
    argv = sys.argv[1:]
    if len(argv) != 3:
        return 'error: hook must be called with three arguments'
    if argv[2] != '1':
        return 0
    if argv[0] == argv[1]:
        return 0
    allfiles = git_ls_files()
    modfiles = git_ls_files('-m')
    unmodified = set(allfiles) - set(modfiles)
    recheckout(unmodified)
    warn_about(modfiles)
    return 0
if __name__ == '__main__':
    try:
        sys.exit(main())
    except KeyboardInterrupt:
        sys.exit('nInterrupted')

要提高性能,您可以将其修改以仅在可能使用$Revision$的文件上操作(您的属性将其定义为"所有文件",所以我在此处使用它(。

我今天早上考虑了这个问题。正如您所观察到的,仅仅是git checkout在更改提交时填充索引和工作树时尚未更新HEAD参考。最终,尝试计算git checkout即将设置HEAD to 的CC_16似乎太烦人了。相反,您可以使用检查后的挂钩

尚不清楚是否应该使用而不是 the污迹过滤器,还是在中加上 the the the the the the the the the the the the the the the the the the the the the the the the the the the the smudge filter> 是正确的。您几乎可以肯定仍然希望干净的过滤器照常运行。

无论如何,检查后的挂钩获取:

...三个参数:上一个头部的参考,新头的参考(可能已更改或可能没有更改(,以及指示结帐是否为分支结帐的标志(更改分支,flag = 1(或文件结帐(从索引中检索文件,flag = 0(。此钩子不能影响 git结帐

的结果

(git checkout和/或这里的文档中存在错误。最后一句话说"不影响"结果",但这在两种方面都不是正确的:

  • 挂钩的退出状态成为git checkout的退出状态。如果挂钩的退出状态非零。
  • 钩子可以覆盖工作树。

这是我打算在这里使用的最后一个。(

也可以按照 git克隆运行,除非使用-no-no-no-no-na(选项。给出的挂钩的第一个参数是null-ref,第二个参数始终为1。/p>

此挂钩可用于执行存储库有效性检查,如果不同的头部不同或设置工作的dir metadata属性。

您的目标是在更新HEAD时使污迹过滤器运行。查看内置/Checkout.c的源代码,我们发现"更改consits"的源代码。情况,git checkout首先填充索引和工作树,然后更新HEAD REF(第一个突出显示行(,然后使用两个哈希ID运行post-checkout挂钩(在某些情况下,第一个是特殊的Null-Hash(和标志设置为1。

文件结帐(根据定义不更改consits(将标志设置为0。两个哈希ID将始终匹配,这就是为什么标志测试几乎不需要的原因。

进行文件结帐将重新运行污迹过滤器。由于HEAD现在已更新,$Revision$将以您想要的方式展开。显而易见的是,每个工作树文件必须更新两次!还有另一个问题,上面的python代码通过删除 所谓的未移交文件,迫使 git checkout将其从索引中重新提取到工作树。

最新更新