2011-10-15 23 views
8

Mam a) katalog roboczy bez katalogu .git i b) repozytorium. a to jakaś wersja w środku historii b.Znajdź wersję Git katalogu roboczego Brakuje katalogu .git

Jak mogę się dowiedzieć, która wersja a odpowiada w b?

Pomyślałem o skorupie robiącym diff z katalogu roboczego do wszystkich wersji i wybrałem tę z najmniejszymi (mam nadzieję, że 0) różnicami.

To byłoby trochę surowe (i nie jestem pewien jak to zrobić), czy jest łatwiejszy sposób?

Odpowiedz

4

Można napisać skrypt, aby uruchomić diff gitdir workdir | wc -c dla każdego zatwierdzenia. Następnie możesz zestawić wyniki i powiedzieć, że zatwierdzenie, które ma najmniejszą różnicę (mierzoną przez wc -c), jest najbliższym zatwierdzeniem do działającego reż.

Oto, co to może wyglądać w Pythonie:

find_closest_sha1.py:

#!/usr/bin/env python 
import subprocess 
import shlex 
import sys 
import os 
import operator 

gitdir,workdir=map(os.path.realpath,sys.argv[1:3]) 
os.chdir(gitdir) 
proc=subprocess.Popen(shlex.split('git rev-list --all'),stdout=subprocess.PIPE) 
shas,err=proc.communicate() 
shas=shas.split() 
head=shas[0] 
data={} 
for sha1 in shas: 
    subprocess.Popen(shlex.split('git checkout {s}'.format(s=sha1)), 
          stderr=open('/dev/null')).wait() 
    proc=subprocess.Popen(shlex.split('diff {g} {w}'.format(g=gitdir,w=workdir)), 
          stdout=subprocess.PIPE) 
    out,err=proc.communicate() 
    distance=len(out) 
    data[sha1]=distance 
answer=min(data.items(),key=operator.itemgetter(1))[0] 
print('closest match: {s}'.format(s=answer)) 
subprocess.Popen(shlex.split('git checkout {h}'.format(h=head)), 
       stderr=open('/dev/null')).wait() 

Przykład:

% rsync -a gitdir/ workdir/ 
% cd workdir 
% git checkout HEAD~10 
HEAD is now at b9fcebf... fix foo 

% cd .. 
% /bin/rm -rf workdir/.git 
% find_closest_sha1.py gitdir workdir 
closest match: b9fcebfb170785c19390ebb4a9076d11350ade79 
+0

Skrypt Pythona całkowicie zawiedzie, gdy go przetestowałem. Wydaje zatwierdzenie, które było całkowicie błędne. –

1

Możesz zmniejszyć liczbę wersji, które musisz sprawdzić przy pomocy pickaxe. Porównaj swój katalog roboczy z najnowszą wersją i wybierz inną linię, która wygląda tak rzadko, jak to tylko możliwe. Powiedzmy, że twoja ostatnia wersja ma linię zawierającą foobar, ale twój katalog roboczy jej nie zawiera; uruchom git log -Sfoobar, który wyprowadza wszystkie zatwierdzenia dodając lub usuwając foobar. Możesz teraz przenieść swoje repozytorium z powrotem do pierwszej (najnowszej) wersji na tej liście, ponieważ wszystkie wersje po niej będą inne od twojego katalogu roboczego. Powtarzaj z inną różnicą, dopóki nie znajdziesz poprawnej wersji.

1

Ponieważ git używa magazynu plików z adresami do zawartości, powinno być możliwe znalezienie gdzieś tam dowolnego drzewa, ale nie znam szczegółów. Zgaduję, że mógłbyś skopiować pliki z odłączonego katalogu roboczego do katalogu roboczego repozytorium, a następnie zatwierdzić wszystko, w jakiś sposób znaleźć skrót obiektu drzewa utworzonego przez commit i przeszukać istniejące zatwierdzenia dla tego, które odwołuje się do tego samego drzewa. .

Aby to zadziałało, drzewo będzie oczywiście musiało idealnie pasować, więc nie możesz dostać żadnych nieprzenośnych plików do zatwierdzenia (takich jak pliki obiektów, kopie redaktorów itp.).

Edycja: Właśnie wypróbowałem to na jednym repozytorium (z git cat-file commit HEAD, aby pokazać obiekt drzewa w HEAD, i przeszukując wynik git log --pretty=raw dla tego hasha drzewa), i to nie działało (nie znalazłem hasha w historii). Dostałem kilka ostrzeżeń o konwersji CRLF, kiedy wykonałem commit, więc to mógł być problem, tzn. Prawdopodobnie masz różne hashe dla tego samego drzewa, w zależności od tego, jak twój git jest skonfigurowany do łączenia plików tekstowych. Zaznaczam tę wiki społeczności, jeśli ktoś wie, jak to zrobić w sposób niezawodny.

0

Zakładając, że w drzewo i b/.git ustawienia ignorowania są takie same, jak podczas tworzenia i że w drzewie roboczym nie ma żadnych niezignorowanych nieśledzonych plików, powinieneś móc uruchomić coś takiego.

Strategia polega na odtworzeniu identyfikatora git drzewa roboczego, a następnie wyszukaniu dowolnego zatwierdzenia zawierającego to drzewo.

# work from detached working tree 
cd a 

# Use existing repository and a temporary index file 
GIT_DIR=b/.git 
GIT_INDEX_FILE=/tmp/tmp-index 
export GIT_DIR GIT_INDEX_FILE 

# find out the id of the current working tree 
git add . && 
tree_id=$(git write-tree) && 
rm /tmp/tmp-index 

# find a commit that matches the tree 
for commit in $(git rev-list --all) 
do 
    if test "$tree_id" = "$(git rev-parse ${commit}^{tree})"; then 
     git show "$commit" 
     break 
    fi 
done 

unset GIT_DIR 
unset GIT_INDEX_FILE