有没有git log技巧 - 关注已重命名的目录?

时间:2016-08-10 10:32:56

标签: git

git命令有一个有用的命令,可以在重命名后跟踪文件,如git log --follow path/to/some/file中所示。不幸的是,它仅适用于单个文件。我希望能够做到等同于git log --follow some/directory

这样做的一种方法可能是按下git ls-tree的输出并在循环中执行此操作,但问题就变成了影响多个文件的提交不会“合并”到一个提交中。 / p>

有更好的方法吗?注意:使用git 2.7.4

2 个答案:

答案 0 :(得分:4)

没有

Git不存储目录,只存储文件。当您使用任何路径名来查看整个提交的git loggit diff之类的命令时,Git实际上会说“从整个提交开始,然后将其缩小到匹配该路径的文件”。这里的目录只是最终选择目录中的每个文件。

--follow选项只能跟随一个文件。因此,如果您能够以某种方式设法将其应用于目录,Git会首先将目录转换为一组文件,然后选择其中一个文件并按照该文件。

(实际的--follow代码是非常hacky。它利用了重命名检测代码,但只有在以较新到旧的顺序比较提交时才有效:如果添加--reverse--follow永远不会工作。可能整个事情需要被抛弃并重新编码。也许通过重新编码,你可以让它处理多个文件名,甚至是满是文件的目录。)

答案 1 :(得分:0)

似乎没有内置的方法来做到这一点。

可以使用脚本并遵循一个简单的算法来做到这一点:

  • 为每个文件生成与其关联的提交列表
  • 合并所有列表并对它们进行稳定排序(这很棘手,因为确定提交的顺序并不简单)。
  • 为每个提交迭代执行git log并通过less
  • 管道

这是使用python 3和sh模块执行此操作的一种hacky方式,由于各种原因无法在Windows上运行。

#!/usr/bin/env python3

import os
import shlex
import sys
import tempfile

import sh

def _get_commits(fname):
    # Ask for the commit and the timestamp
    # .. the timestamp doesn't guarantee ordering, but good enough
    for c in sh.git('log', '--follow', '--pretty=%ct %h', fname,
                   _tty_out=False, _iter=True):
        c = c.strip().split()
        yield int(c[0]), c[1]

def git_log_follow_multi(filenames):
    if len(filenames) == 0:
        print("Specify at least one file to log")
    elif len(filenames) <= 1:
        os.system('git log --follow -p %s' % filenames[0])
    else:
        # Use git log to generate lists of commits for each file, sort
        commits = []
        for fname in filenames:
            commits += _get_commits(fname)

        # Sort the lists (python's sort is stable)
        commits.sort(reverse=True)

        # Uniquify (http://www.peterbe.com/plog/uniqifiers-benchmark)
        seen = set()
        seen_add = seen.add
        commits = [c for c in commits if not (c in seen or seen_add(c))]

        # Finally, display them
        tname = None

        try:
            file_list = ' '.join(shlex.quote(fname) for fname in filenames)

            with tempfile.NamedTemporaryFile(mode='w', delete=False) as fp:
                tname = fp.name
                for _, commit in commits:
                    fp.write('git log -p -1 --color %s %s\n' % (commit, file_list))

            # Use os.system to make our lives easier
            os.system('bash %s | less -FRX' % tname)
        finally:
            if tname:
                os.unlink(tname)


if __name__ == '__main__':
    git_log_follow_multi(sys.argv[1:])

现在,这个脚本并不能完全满足您的需求,因为它需要一个文件列表,但您可以使用glob执行它,它会执行您正在寻找的内容。

./script.py src/*