【问题标题】:View full file diff of `x` commits of a single file's history (that's hosted in git)查看单个文件历史的“x”提交的完整文件差异(托管在 git 中)
【发布时间】:2012-07-28 09:29:02
【问题描述】:

假设我在 git 中有一个名为 filex.code 的文件,我想查看该文件的最后一个 x 版本的完整代码,并突出显示每个更改的部分 em> -- 都在一个地方。所以x-paned 提交历史是filex.code,几乎就像我在做一个x-paned 差异,但查看历史版本而不是从不同的分支合并。

x 越大越好。跨平台会很棒,但是三巨头中的任何一个都可以。能够编辑最新版本也很棒,但只读可视化就足够了。

请注意,这与提交文件的simple history 不同,因此其他精彩的gitk path/to/file(或SourceTree 或您喜欢的任何可视化git 客户端)不是我想要的。 git log -p 也很接近,它的输出诱人地包含了我想要的所有信息,只是它都是线性的,几乎是“程序化”的输出格式,而不是像你最喜欢的三个那样好的、相对非分层的、视觉的-paned GUI 的合并工具。

编辑:另一个非常酷的选项,最终仍然遇到仅显示每行的最新源和线性输出的缺点是git blame,但它很酷。)

所以我也不是在寻找setting up difftool,我不认为。我不想区分文件的两个已知版本,而是想将 x 历史编辑迭代可视化到单个文件。

要求太多?这是 WTFA([自己] 编写“神奇”应用程序)的情况吗?

较小的选择:是否有一个三窗格的合并工具,我可以欺骗它来显示单个文件的最后三个提交?

【问题讨论】:

    标签: git git-diff git-log difftool mergetool


    【解决方案1】:

    此脚本并排打开文件的最后 N 个修订版。

    #!/usr/bin/env python
    import os, sys, tempfile
    from shutil import rmtree
    from subprocess import call, Popen, PIPE
    from optparse import OptionParser
    from traceback import print_exc
    
    COMMAND = 'vim -d'
    
    def vcall(cmd, **kwargs):
        if options.verbose:
            print ' '.join(cmd)
        return call(' '.join(cmd) if sys.platform == 'darwin' else cmd, 
                    **kwargs)
    
    parser = OptionParser('usage: %s [-n <number of revisions>] filename' % 
                          sys.argv[0])
    parser.add_option('-n', '--num', dest='N', type='int', 
                      help='number of revisions', default=3)
    parser.add_option('-v', '--verbose', dest='verbose',
                      help='be verbose', default=False, action='store_true')
    (options, args) = parser.parse_args()
    if len(args) != 1:
        parser.error('incorrect number of arguments')
    filename = args[0]
    
    if vcall('git rev-parse'.split()) != 0:
        sys.exit(1)
    
    try:
        cmd = 'git rev-list HEAD --'.split() + [filename]
        if options.verbose:
            print ' '.join(cmd)
        pipe = Popen(' '.join(cmd) if sys.platform == 'darwin' else cmd, 
                     stdout=PIPE).stdout
        revs = []
        for i, line in enumerate(pipe):
            if i == options.N:
                break
            revs.append(line.rstrip())
    except:
        print_exc()
    
    N = len(revs)
    if N == 0:
        sys.exit('fatal: ambiguous argument %s: path not in the working tree' % 
                 filename)
    elif N < options.N:
        sys.stderr.write('%s has only %d revision%s' % 
                         (filename, N, 's' if N > 1 else ''))
    
    tempdir = ''
    try:
        tempdir = tempfile.mkdtemp()
        head, tail = os.path.split(filename)
        tempfiles = []
        for i in xrange(N):
            tempfiles.append(tail + ('.%d' % i if i else ''))
        for i, f in enumerate(tempfiles):
            with open(os.sep.join((tempdir, f)), 'w') as fout:
                vcall(['git', 'show', '%s:./%s' % (revs[i], filename)], stdout=fout)
        vcall(COMMAND.split() + list(reversed(tempfiles)), shell=True, cwd=tempdir)
    except:
        print_exc()
    finally:
        try:
            if tempdir and os.path.isdir(tempdir):
                rmtree(tempdir)
        except:
            print_exc()
    

    注意事项:

    1. Vimdiff 有一个限制,即仅在 4 个(第一个)缓冲区中突出显示差异,但对于并排显示 - 显示所有文件修订版(例如 N=20 效果很好)。为避免 N>4 的警告,请使用 COMMAND = 'vim -O' 并排查看版本,完全没有任何差异。

    2. 对于 SO 风格来说,脚本已经变得太大了,但它现在已经非常安全了 - 但对于有经验的人来说足够简单。

    【讨论】:

    • 我进行了编辑,修复了在 OS X 10.7.4 的股票 python 上工作的问题。 cwd 正在工作,但对 vimdiff 的调用没有。不知道为什么不。代码here,以防编辑因任何原因被拒绝。谢谢。 真的好东西。要去清理 cmets。
    • 至于通过一个字符串将参数提供给call而不是列表:“如果为args指定了一个字符串,它将用作要执行的程序的名称或路径;这将只有在没有给程序提供参数的情况下才有效。”似乎 OS X 的实现有点不标准。
    • 我已经接受了你的补丁的修改版本,请再试一次。奇怪的是,此脚本中的其他 call 实例在 OS X 下似乎运行良好。vimgit 有不同的类型吗?
    • 效果很好——去看看吧。在您的补丁程序版本中进行了更清晰的修复。再次感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-24
    • 2014-11-25
    • 2012-08-10
    • 2021-12-07
    • 2012-12-21
    • 1970-01-01
    • 2018-12-02
    相关资源
    最近更新 更多