繁体   English   中英

查看单个文件历史记录的“x”提交的完整文件差异(在git中托管)

[英]View full file diff of `x` commits of a single file's history (that's hosted in git)

假设我在git中有一个名为filex.code的文件,我希望看到该文件的最后x版本的完整代码每个更改的部分都突出显示 - 全部在一个地方。 因此,一个x -paned犯下的历史filex.code ,仿佛我正在做一个x -paned差异,但观察历史版本而不是从不同的分支合并。

x越大越好。 Crossplatform会很棒,但三巨头中的任何一个都可以。 能够编辑最新版本也很棒,但只读可视化很多。

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

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

我也不是在考虑设置difftool ,我不这么认为。 我想要将历史编辑的x次迭代可视化为单个文件,而不是区分文件的两个已知版本。

问太多了? 这是一个WTFA(写出“神奇”App [你自己])的情况吗?

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

此脚本并排打开文件的最后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风格,但它现在非常防弹 - 但足够简单,经验丰富的眼睛。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM