4

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

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

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

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

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

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

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

4

1 回答 1

3

此脚本并排打开文件的最后 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 风格来说,脚本已经变得太大了,但它现在已经非常安全了——但对于有经验的人来说足够简单。

于 2012-07-31T07:17:04.593 回答