Jak mogę cofnąć ostatnie zatwierdzenie w repozytorium git bare?

94

Biorąc pod uwagę, że istnieje kilka poleceń git, które nie mają sensu w czystym repozytorium (ponieważ gołe repozytoria nie używają indeksów i nie mają katalogu roboczego),

git reset --hard HEAD^ 

nie jest rozwiązaniem pozwalającym cofnąć zatwierdzenie ostatniej zmiany w takim repozytorium.

Przeszukiwaniu internetu, można znaleźć wszystko, co związane z tematem jest ten , w którym ja przedstawił trzy sposoby w ten sposób:
1. „ręcznie zaktualizować ref (co wiąże się hydrauliką)”;
2. „ git push -fz nieoczyszczonego repozytorium”;
3. „ git branch -f this $that”.

Które rozwiązanie Twoim zdaniem jest bardziej odpowiednie lub jakie są inne sposoby, aby to zrobić? Niestety, znaleziona przeze mnie dokumentacja dotycząca repozytoriów git bare jest dość uboga.

Lavinia-Gabriela Dobrovolschi
źródło
8
@ Lavinia-Garbriela Dobrovol Nie używaj skomplikowanych rzeczy poniżej. Próbujesz przenieść HEAD do innego zatwierdzenia i do tego służy reset git, nawet w przypadku samego repozytorium. Zgodnie z moją odpowiedzią poniżej, użyj: git reset --soft <commit> Z --soft nie próbujesz zmieniać działającego drzewa i indeksu, które nie istnieją, więc git pozwala ci zresetować bez problemu.
Hazok

Odpowiedzi:

133

Możesz użyć git update-refpolecenia. Aby usunąć ostatnie zatwierdzenie, użyłbyś:

$ git update-ref HEAD HEAD^

Lub jeśli nie jesteś w gałęzi, z której nie możesz usunąć ostatniego zatwierdzenia:

$ git update-ref refs/heads/branch-name branch-name^

Możesz również przekazać sha1, jeśli chcesz:

$ git update-ref refs/heads/branch-name a12d48e2

Zobacz dokumentację polecenia git-update-ref .

Sylvain Defresne
źródło
@ Lavinia-Gabriela Dobrovolschi: tak, nie znałem dokładnej składni.
VonC,
@VonC Możesz określić, że <ref> in git update-ref <ref> <newvalue>będzie właściwą gałęzią, na przykład „refs / heads / master” zamiast HEAD. Mam nadzieję, że nie zrozumiałem źle twojego pytania.
Lavinia-Gabriela Dobrovolschi
@Sylvain: +1 dobra edycja. @ Lavinia-Gabriela Dobrovolschi dziękuję za precyzję. Jest to o wiele bardziej praktyczne (zakładam, że jeśli masz bezpośredni dostęp do zdalnego serwera).
VonC,
3
Przykłady są mylące, jeśli chodzi o branch-nameargumentację. Używając update-refz „gałęzią”, absolutnie musisz podać pełną nazwę referencyjną gałęzi (tj. Przed refs/heads/zwykłą krótką nazwą gałęzi). Jeśli użyjesz tylko krótkiej nazwy, $GIT_DIR/branch-namezamiast tego utworzysz / zaktualizujesz $GIT_DIR/refs/heads/branch-name. Istnienie obu branch-namei refs/heads/branch-namespowoduje ostrzeżenia „refname… jest niejednoznaczne”.
Chris Johnsen
Ta odpowiedź jest znacznie bardziej skomplikowana niż to, co zaproponował Zach. A jego rozwiązanie działa dobrze.
Krystian,
32

Jeśli używasz następujących w gołym repozytorium:

git reset --soft <commit>

wtedy nie napotkasz problemów, których używasz, --hardi --mixedopcji w gołym repozytorium, ponieważ nie próbujesz zmienić czegoś, czego nie ma (tj. drzewo robocze i indeks). W twoim przypadku chciałbyś użyć (z samego repozytorium):

git reset --soft HEAD^

Aby przełączyć gałęzie w zdalnym repozytorium, wykonaj:

git symbolic-ref HEAD refs/heads/<branch_name>

Aby zobaczyć aktualnie wybrany oddział użyj:

git symbolic-ref HEAD

https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-symbolic-ref.html

Hazok
źródło
3
Jak wybierasz oddział, który chcesz przenieść? Twój przykład działa dobrze na master, ale git checkout other_branchnie działa w nagim.
Gauthier
1
Hmmm ... Zastanawiam się, kto mnie za to zagłosował. Pytanie nie dotyczyło przełączania gałęzi w zdalnym repozytorium, ale dotyczyło resetowania w gołym repo. Aby zmienić domyślną gałąź w zdalnym repozytorium, użyj git symbolic-ref HEAD refs / heads / <branch_name>.
Hazok
7

git push -fPowinno zadziałać:
jeśli sklonować tę gołą repo, usunąć ostatni commit ( git reset --hard HEAD^tak jak wspomniałeś, ale w lokalnym zakaz nagiej repo) i przesunąć do tyłu ( -f):

  • nie zmieniasz żadnego SHA1 dla innych zatwierdzeń poprzedzających ten, który usuwasz.
  • jesteś pewien, że odsunąłeś dokładną zawartość samego repozytorium minus dodatkowe zatwierdzenie (ponieważ najpierw je sklonowałeś).
VonC
źródło
@ VonC Cześć Von, widziałem, jak dużo odpowiadałeś na Git, więc chciałem cię zapytać ... Byłem ciekawy, dlaczego, git reset --soft <sha1>jak pokazano w mojej odpowiedzi poniżej, nie byłby zalecaną praktyką przenoszenia HEAD na gołym repozytorium?
Hazok
Myślę, że innym powodem, o który pytam, jest to, że używanie miękkiego resetowania dla gołych repozytoriów nie jest informacjami, które są łatwo dostępne, a wiele forów wydaje się mieć niepotrzebnie złożone obejścia, gdy wydaje się, że miękki reset jest najlepszą praktyką ze względu na najmniejszą ilość wpisywania i najmniejszą szansę za błąd.
Hazok
2
@Zach: a reset --softpowinno działać, gdy jest wykonywane bezpośrednio na gołym repozytorium. Podejrzewam, że jest to rzadko wykonywane, ponieważ nagie repozytorium jest generalnie repozytorium upstream (tj. Repozytorium, do którego wysyłasz dane) i przez większość czasu nie masz do niego bezpośredniego dostępu lokalnego. Ale jeśli tak, to z pewnością jest to kolejny dobry przykład reset --softużycia " " (jak w stackoverflow.com/questions/5203535/ ... ) Więc +1 do twojej odpowiedzi.
VonC
2

Możesz także użyć notacji git refspec i zrobić coś takiego:

git push -f origin +<commit you want to revert to>:<destination_head | branch_name>

Wymusza to aktualizację gałęzi docelowej (jak oznaczono przez ref) do zatwierdzenia źródłowego, zgodnie z oznaczeniem +<object ref>części.

alup
źródło
2
z wyjątkiem sytuacji, gdy istnieje lista ACL na gałęzi - co zwykle ma miejsce, jeśli „musisz to zrobić na samym repozytorium” ...
David Schmitt