memo

2011-01-23

python + dulwich で git-show 的なこと

dulwich-0.7.0 で入った dulwich.diff_tree の使い方を確認するために、 git-show 的なスクリプトを書いてみた。

ついでに format も使いまくってみているので python-2.6 以上じゃないと動かん。

#!/usr/bin/python

import datetime
import difflib
import dulwich
import re
import sys

repo = dulwich.repo.Repo('.')

if len(sys.argv) > 1:
    commit_sha = sys.argv[1]
else:
    commit_sha = repo.head()

commit = repo.get_object(commit_sha)

date = datetime.datetime.fromtimestamp(commit.commit_time)
message = re.compile('^', re.MULTILINE).sub('    ', commit.message)

print '''commit {commit_sha}
Author: {commit.author}
Date:   {date:%c}

{message}
'''.format(**locals()),


parent = repo.get_object(commit.parents[0])

for change in dulwich.diff_tree.tree_changes(repo.object_store, parent.tree, commit.tree):
    if change.type == 'modify':
        print 'diff --git a/{0} b/{1}'.format(change.old.path, change.new.path)
        # TODO: if mode changed
        print 'index {0:.7}..{1:.7} {2:o}'.format(change.old.sha, change.new.sha, change.new.mode)
        for line in difflib.unified_diff(repo.get_object(change.old.sha).data.splitlines(True),
                                         repo.get_object(change.new.sha).data.splitlines(True),
                                         'a/' + change.old.path,
                                         'b/' + change.new.path):
            print line,

    elif change.type == 'add':
        print 'diff --git a/{0} b/{0}'.format(change.new.path)
        print 'new file mode {0:o}'.format(change.new.mode)
        print 'index {0:.7}..{1:.7}'.format('0'*40, change.new.sha)
        for line in difflib.unified_diff([],
                                         repo.get_object(change.new.sha).data.splitlines(True),
                                         '/dev/null',
                                         'b/' + change.new.path):
            print line,

    elif change.type == 'delete':
        print 'diff --git a/{0} b/{0}'.format(change.old.path)
        print 'deleted file mode {0:o}'.format(change.old.mode)
        print 'index {0:.7}..{1:.7}'.format(change.old.sha, '0'*40)
        for line in difflib.unified_diff(repo.get_object(change.old.sha).data.splitlines(True),
                                         [],
                                         'a/' + change.old.path,
                                         '/dev/null'):
            print line,
    else:
        # TODO: implement 'copy', 'rename', 'unchanged'
        print change