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

£可爱£侵袭症+ 提交于 2019-12-07 10:03:53

问题


Say I have a file in git called filex.code, and I want to see the full code of the last x versions of that file with each changed section highlighted -- all in one place. So an x-paned commit history of filex.code, almost as if I were doing an x-paned diff, but viewing historical versions rather than merging from different branches.

The greater x, the better. Crossplatform would be great, but any of the Big Three works. Being able to edit the latest version would also be great, but read-only visualization is plenty.

Note that this is different from a simple history of commits to a file, so the otherwise wonderful gitk path/to/file (or SourceTree or whatever visual git client you love) isn't what I'm looking for. git log -p also comes close, and its output tantalizingly includes all the information I'd want, just that it's all in a linear, almost "procedural" output format rather than a good, relatively non-hierarchical, visual one like your favorite three-paned GUI'd mergetool's.

(Edit: Another really cool option that ultimately still experiences the shortcomings of only showing each line's latest source & a linear output is git blame, but it's cool.)

So I'm not precisely looking for setting up difftool either, I don't think. Rather than diffing two known versions of a file, I want to visualize x iterations of historical edits to a single file.

Asking too much? Is this a WTFA (Write The "Fantastic" App [yourself]) situation?

Lesser alternative: Is there a three-paned mergetool that I can trick into displaying the last three commits of a single file?


回答1:


This script opens last N revisions of the file side-by-side.

#!/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()

Notes:

  1. Vimdiff has a limitation of highlighting diffs in only 4 (first) buffers, but as for showing side-by-side - all file revisions are shown (eg N=20 works great). To avoid the warning for N>4 use COMMAND = 'vim -O' to see versions side-by-side without any diffs at all.

  2. The script has grown to be too large for SO style, but it is quite bullet-proof now - yet simple enough for an experienced eye.



来源:https://stackoverflow.com/questions/11726144/view-full-file-diff-of-x-commits-of-a-single-files-history-thats-hosted-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!