2013-10-03 10 views
7

Biorąc pod uwagę repozytorium git, muszę wygenerować słownik daty ostatniej modyfikacji kontrolowanej przez każdą z wersji jako unikalny znacznik czasu odwzorowany na ścieżkę do pliku. Potrzebuję daty ostatniej modyfikacji, jeśli chodzi o git - nie systemu plików.Git: jak wyświetlić listę wszystkich plików objętych kontrolą wersji wraz z datą ich autora?

Aby to zrobić, chciałbym uzyskać polecenie git wyświetlające listę wszystkich plików objętych kontrolą wersji wraz z datą autora każdego pliku. Dane wyjściowe z git ls-files lub git ls-tree -r master byłyby idealne, gdyby ich dane wyjściowe zawierały sygnatury czasowe w każdym wierszu.

Czy istnieje sposób na uzyskanie tego wyniku z git?

Aktualizacja więcej kontekstu: mam aktualną implementację, która składa się z skrypt Pythona, który dokonuje iteracji każdego pliku źródłowego i pod kontrolą robi git log na każdej z nich, ale mam znalezieniem że nie skaluje się dobrze . Im więcej plików w repozytorium, tym więcej wywoła git log połączeń. Więc to doprowadziło mnie do poszukiwania sposobu na zebranie informacji z git przy mniejszej liczbie połączeń (najlepiej 1).

+1

@derekvanvivliet Co masz na myśli przez autora pliku? Może być wielu ludzi, którzy dokonali zatwierdzeń do pliku. –

+0

Niestety git nie ma "winy na drzewie", tj. "' Git winnie '" aby uzyskać dane wyjściowe jak w np. Widok drzewa GitHub. Możesz uzyskać dane dla każdego pojedynczego pliku za pomocą 'git log -1 --tformat = ... --follow = ' z niestandardowym formatem, iterując po 'git ls-tree --names-only -r HEAD', ale to nie będzie szybki. –

+0

@ ansh0l nie plik autor, data autora. Mam na myśli datę ostatniej modyfikacji pliku w kontroli źródła – derekvanvliet

Odpowiedz

1

lista wszystkich plików pod kontrolą wersji wraz z datą autora każdego pliku,

skalowanie nie jest problemem, z tego:

#!/bin/sh 
temp="${TMPDIR:-/tmp}/@@@[email protected]@@$$" 
trap "rm '$temp'" 0 1 2 3 15 
git log --pretty=format:"%H%x09%at" --topo-order --reverse "[email protected]" >"$temp" 
cut -f1 "$temp" \ 
| git diff-tree -r --root --name-status --stdin \ 
| awk ' 
     BEGIN {FS="\t"; OFS="\t"} 
     FNR==1{++f} 
     f==1 {at[$1]=$2; next} 
     NF==1 {commit=$1; next} 
     $1=="D"{$1=""; delete last[$0]; next} # comment to also show deleted files 
       {did=$1;$1=""; last[$0]=at[commit]"\t"did} 
     END {for (f in last) print last[f]f} 
' "$temp" - \ 
| sort -t"`printf '\t'`" -k3 
+0

który działa naprawdę dobrze. Czy możesz wyjaśnić, co robisz z 'git log' i' git diff-tree'? Chciałbym zaimplementować go w pythonie, gdyby działał równie dobrze w pobliżu. – derekvanvliet

+0

Zasadniczo cała efektywność tutaj polega na manipulowaniu dużymi różnicami w drzewach, jeśli python utrzymuje pamięć podręczną obiektów, może to również zrobić.Dziennik zrzuca autora SHA + data w formacie unix-timestamp autora z katalogu głównego do przodu, tak że najnowszy-faktycznie zatwierdzony% at jest zarejestrowany, a następnie cut | diff-tree pluje dla każdej linii SHA, a następnie par nazwy-nazwy w awk, który ładuje najpierw pary sha/timestamp, a następnie ładuje nazwę name-> timestamp-via-commit-SHA + tabelę statusu i zrzuca tabelę na końcu. Najlepszym sposobem sprawdzenia, co się dzieje, jest samodzielne uruchamianie komend w repozytorium zabawek. – jthill

0

Napisałem poniższy skrypt, aby wypisać dla każdego pliku ścieżkę, krótki hashtag i datę.

#!/usr/bin/env python3 
# -*- coding: utf-8 -*- 
# 
# Author: R.F. Smith <[email protected]> 
# $Date: 2013-03-23 01:09:59 +0100 $ 
# 
# 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.""" 

import os 
import sys 
import subprocess 
import time 
from multiprocessing import Pool 

# Suppres terminal windows on MS windows. 
startupinfo = None 
if os.name == 'nt': 
    startupinfo = subprocess.STARTUPINFO() 
    startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW 

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. 
    """ 
    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 (fname[2:], '', time.gmtime(0.0)) 
    return out 

def main(): 
    """Main program.""" 
    # Get a list of all files 
    allfiles = [] 
    # Get a list of excluded files. 
    exargs = ['git', 'ls-files', '-i', '-o', '--exclude-standard'] 
    exc = subprocess.check_output(exargs).split() 
    if not '.git' in os.listdir('.'): 
     print('This directory is not managed by git.') 
     sys.exit(0) 
    for root, dirs, files in os.walk('.'): 
     if '.git' in dirs: 
      dirs.remove('.git') 
     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 = [] 
    for res in p.imap_unordered(filecheck, allfiles): 
     filedata.append(res) 
    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))) 


if __name__ == '__main__': 
    main() 
+0

Dzięki @RolandSmith. Tak naprawdę używam obecnie skryptu podobnego do tego. Miałem nadzieję, że istnieje sposób na uzyskanie tych informacji (nazw plików związanych z ich datą ostatniej modyfikacji) z git przy mniejszej liczbie połączeń do 'git log' lub najlepiej jednego połączenia. – derekvanvliet

0

Co chciałbym zrobić to uruchomić git ls-files i dodać je wszystkie do tablicy, a następnie uruchomić git log $date_args --name-only, a następnie zanalizować tę moc i usunąć te pliki z tablicy podczas dodawania informacji o dacie do słownika i zatrzymać przetwarzanie po pustej tablicy.

0

Proszę bardzo:

git ls-files -z | xargs -0 -n1 -I{} -- git log -1 --format='%at {}' {} 

To działa na bash i prawdopodobnie sh.

Powiązane problemy