数千のファイルを含む Git リポジトリがあり、個々のファイルごとに最後のコミットの日時を取得したいと考えています。これは Python を使用して (たとえば、 のようなものを使用してos.path.getmtime(path)
) 実行できますか?
質問する
8326 次
4 に答える
4
興味深い質問です。以下は、簡単で汚い実装です。multiprocessing.Pool.imap()
便利なので、以前はサブプロセスを開始していました。
#!/usr/bin/env python
# vim:fileencoding=utf-8:ft=python
#
# Author: R.F. Smith <rsmith@xs4all.nl>
# Last modified: 2015-05-24 12:28:45 +0200
#
# To the extent possible under law, Roland Smith has waived all
# copyright and related or neighboring rights to gitdates.py. This
# work is published from the Netherlands. See
# http://creativecommons.org/publicdomain/zero/1.0/
"""For each file in a directory managed by git, get the short hash and
data of the most recent commit of that file."""
from __future__ import print_function
from multiprocessing import Pool
import os
import subprocess
import sys
import time
# Suppres annoying command prompts on ms-windows.
startupinfo = None
if os.name == 'nt':
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
def main():
"""
Entry point for gitdates.
"""
checkfor(['git', '--version'])
# Get a list of all files
allfiles = []
# Get a list of excluded files.
if '.git' not in os.listdir('.'):
print('This directory is not managed by git.')
sys.exit(0)
exargs = ['git', 'ls-files', '-i', '-o', '--exclude-standard']
exc = subprocess.check_output(exargs, startupinfo=startupinfo).split()
for root, dirs, files in os.walk('.'):
for d in ['.git', '__pycache__']:
try:
dirs.remove(d)
except ValueError:
pass
tmp = [os.path.join(root, f) for f in files if f not in exc]
allfiles += tmp
# Gather the files' data using a Pool.
p = Pool()
filedata = [res for res in p.imap_unordered(filecheck, allfiles)
if res is not None]
p.close()
# Sort the data (latest modified first) and print it
filedata.sort(key=lambda a: a[2], reverse=True)
dfmt = '%Y-%m-%d %H:%M:%S %Z'
for name, tag, date in filedata:
print('{}|{}|{}'.format(name, tag, time.strftime(dfmt, date)))
def checkfor(args, rv=0):
"""
Make sure that a program necessary for using this script is available.
Calls sys.exit when this is not the case.
Arguments:
args: String or list of strings of commands. A single string may
not contain spaces.
rv: Expected return value from evoking the command.
"""
if isinstance(args, str):
if ' ' in args:
raise ValueError('no spaces in single command allowed')
args = [args]
try:
with open(os.devnull, 'w') as bb:
rc = subprocess.call(args, stdout=bb, stderr=bb,
startupinfo=startupinfo)
if rc != rv:
raise OSError
except OSError as oops:
outs = "Required program '{}' not found: {}."
print(outs.format(args[0], oops.strerror))
sys.exit(1)
def filecheck(fname):
"""
Start a git process to get file info. Return a string containing the
filename, the abbreviated commit hash and the author date in ISO 8601
format.
Arguments:
fname: Name of the file to check.
Returns:
A 3-tuple containing the file name, latest short hash and latest
commit date.
"""
args = ['git', '--no-pager', 'log', '-1', '--format=%h|%at', fname]
try:
b = subprocess.check_output(args, startupinfo=startupinfo)
data = b.decode()[:-1]
h, t = data.split('|')
out = (fname[2:], h, time.gmtime(float(t)))
except (subprocess.CalledProcessError, ValueError):
return None
return out
if __name__ == '__main__':
main()
出力例:
serve-git|8d92934|2012-08-31 21:21:38 +0200
setres|8d92934|2012-08-31 21:21:38 +0200
mydec|e711e27|2008-04-09 21:26:05 +0200
sync-iaudio|8d92934|2012-08-31 21:21:38 +0200
tarenc|8d92934|2012-08-31 21:21:38 +0200
keypress.sh|a5c0fb5|2009-09-29 00:00:51 +0200
tolower|8d92934|2012-08-31 21:21:38 +0200
編集os.devnull
:の代わりに (ms-windows でも動作する)を使用するように更新されました/dev/null
。
Edit2 : startupinfo
ms-windows でポップアップするコマンド プロンプトを抑制するために使用されます。
Edit3 :__future__
これを Python 2 および 3 の両方と互換性を持たせるために使用されます。2.7.9 および 3.4.3 でテスト済み。githubでも利用できるようになりました。
于 2012-10-28T13:30:34.623 に答える
0
GitPythonライブラリを使用できます。
于 2012-10-27T21:53:46.513 に答える