2013-07-30 11 views
7

Powiedz, że mam repozytorium, które ma numer wersji A. I chciałbym zaktualizować go do wersji B, podczas gdy ostatnia wersja to C. (wersja A jest wcześniejsza niż B, i B jest wcześniejsze niż C). Jestem nowym do git więc zrobiłem kilka badań i stwierdzili, this, który inspiruje mnie rozwiązanie:Git: zaktualizuj repozytorium do pewnej wersji

git pull # update from A to the latest revision C 
git reset --hard B 

To działa. Ale ponieważ nie mogę git reset --hard B od A bezpośrednio, precedensowa aktualizacja do najnowszej jest nadal zbyt ciężka, zastanawiam się, może być jakieś jedno-wierszowe polecenie, aby dopasować moje potrzeby. Wszelkie wskazówki proszę?

Odpowiedz

14

Nie ma "aktualizacji repozytorium dla określonej wersji". Repozytorium ma wszystkie wersje, to właśnie robi.

Jeśli chcesz umieścić konkretną wersję repo w twoim bieżącym drzewie pracy, możesz to zrobić na kilka sposobów. Najbliżej pytania brzmi:

zmiana lokalnego repozytorium:

git fetch origin 

utworzyć nowy oddział (oddział niezależnie od aktualnie jesteś, będziemy ciężko zresetować później, więc nie ma znaczenia):

git branch yourbranchname 
git checkout yourbranchname 

powyższe 2 operacje mogą być skrócone do jednego (strumienia szczytowego przyjmuje się jako źródło gałęzi)

git checkout -b yourbranchname 

następnie umieść wskaźnik tego oddziału do popełnienia trzeba (B):

git reset --hard sha1-of-B 

git zresetować --hard zawsze będzie działać, to nie zależy od historii swojego oddziału, jedyny warunek na to, aby praca polega na tym, że zatwierdzenie B jest w twojej lokalnej bazie obiektów (np B musi istnieć i musiało zostać pobrane z odległego repozytorium, ponieważ nie jest to twoja praca).

Jak @Hasturkun zwraca uwagę, można również rozgałęziać bezpośrednio z dowolnej hash z dodatkowym argumentem:

git checkout -b yourbranchname SHA-1 
+4

Naprawdę nie trzeba resetować gałęzi, ponieważ można ją po prostu utworzyć, gdy punkt początkowy jest tam, gdzie chcesz, tj.'git branch newbranch SHA1-of-B' lub' git checkout -b newbranch SHA1-of-B' – Hasturkun

+0

@ Sébastien Dzięki za przedstawienie mi podstawowych pojęć. –

+0

@Hasturkun Twoja odpowiedź działa idealnie dla mnie, dzięki. –

5

Do tego celu należy użyć git checkout. Wystarczy zrobić:

git checkout B

i trzeba tę zmianę.

+0

Dzięki, ale dostałem błąd przy użyciu 'git checkout':' referencja nie jest drzewem'. –

+0

Myślę, że komentarz Hasturkuna w odpowiedzi Sébastiena Dawana rozwiąże ten problem. – jbr

1

Twoje podejście jest całkowicie błędne. Modyfikujesz coś, czego nie chcesz modyfikować: Twoją bieżącą gałąź (prawdopodobnie master).

Prosty, liniowy repozytorium git jest łańcuchem zobowiązuje się ten

*---A---*---*---B---*---*---C 
    ^     ^
    |      | 
    master    origin/master 
    ^
    | 
    HEAD 

To jest stan repozytorium po nazwali git fetch. Zauważ, że cała historia wraz ze wszystkimi pośrednimi krokami znajduje się właśnie na twoim lokalnym dysku twardym. Trzeba tylko sprawdzić stan zatwierdzenia A (HEAD punktów na master, który wskazuje na A), więc pliki, które widzisz, należą do tego stanu.

Teraz, jeśli chcesz spojrzeć na stan, który został zatwierdzony jako B, możesz po prostu sprawdzić, czy zatwierdzić z git checkout B. To aktualizuje pliki, które widzisz na stan B i wskazuje HEAD na które popełnić:

*---A---*---*---B---*---*---C 
    ^  ^  ^
    |   |   | 
    master  HEAD origin/master 

HEAD zawsze odwołuje się do popełniania/gałąź git myśli jesteś, i do którego będzie porównać swój katalog roboczy po wywołaniu git status.

Wystarczy prosty git checkout B, jeśli po prostu chcesz przejrzeć to zatwierdzenie. Jeśli rzeczywiście chcesz wprowadzić zmiany, które zatwierdzasz i chcesz zachować, powinieneś wprowadzić nowy oddział, aby zapisać te zmiany. Osiąga się to przez proste git checkout -b newBranch po git checkout B. To daje stan

*---A---*---*---B---*---*---C 
    ^  ^  ^
    |   |   | 
    master newBranch origin/master 
       ^
       | 
       HEAD 

to po prostu daje nazwę popełnienia B innej niż jego wartość hash. Po jakichś bardziej zobowiązuje, Twój stan będzie wyglądać następująco:

*---A---*---*---B---*---*---C 
    ^   |   ^
    |   |   | 
    master   \ origin/master 
        \ 
        *---*---D 
          ^
          | 
         newBranch 
          ^
          | 
          HEAD 

Chodzi o to, że po sprawdzeniu innego oddziału/commit z git checkout ..., zawsze można łatwo powrócić do popełnienia D wywołując git checkout newBranch oraz stałe przystanki referencyjne git z zatwierdzenia usuwania śmieci D.


Dlaczego teraz używasz git reset --hard? Po pierwsze, blokuje wszystkie lokalne zmiany, które nie zostały jeszcze zatwierdzone bez powiadomienia. Po drugie, może stracić historię, jeśli nie będziesz z nią ostrożny.

Rozważmy na przykład przypadek, w którym wprowadzono pewne zmiany po ostatnim przekazaniu do repozytorium wyższego szczebla i chcemy przyjrzeć się historycznemu zatwierdzeniu B. (. Nieco przeciwieństwem sprawy w swoje pytanie) Historia wygląda następująco:

*---A---*---*---B---*---*---C 
    ^     ^
     |      | 
origin/master    master 
          ^
           | 
          HEAD 

Z git reset --hard B, masz ten stan:

*---A---*---*---B-(-*---*---C) 
    ^  ^
     |   | 
origin/master master 
       ^
        | 
       HEAD 

W commity w nawiasach nie są odniesione bezpośrednio lub pośrednio przez jakikolwiek oddział i mogą być w dowolnym momencie zbierane śmieci. git może nie być bardzo agresywny w przypadku zbierania śmieci, , ale jeśli nie będzie zbierać śmieci, gdy jesteś w tym stanie, nie ma możliwości, aby uzyskać zatwierdzenie C z powrotem, będzie utracone na zawsze. Nie chcesz, aby tak się stało, więc nie jest dobrym pomysłem, aby nabrać zwyczaju używania lekko git reset --hard.

Gdyby użyto git checkout zamiast oddział master nadal będzie wskazujące na C, i nadal będzie w stanie wrócić do niego za pomocą prostego git checkout master.

Powiązane problemy