Przesuń wskaźnik gałęzi do innego zatwierdzenia bez kasy

759

Aby przesunąć wskaźnik gałęzi pobranej gałęzi, można użyć git reset --hardpolecenia. Ale jak przesunąć wskaźnik gałęzi niezarejestrowanej gałęzi, aby wskazywał na inne zatwierdzenie (zachowując wszystkie inne rzeczy, takie jak śledzona gałąź zdalna)?

Mot
źródło
11
Wygląda na to, że wszystko, co chciałeś zrobić, to gałąź innego zatwierdzenia niż ta, którą teraz utworzono. Jeśli moje rozumowanie jest poprawne, to dlaczego po prostu nie utworzysz nowej gałęzi z zatwierdzenia, które chcesz utworzyć przy użyciu git branch <branch-name> <SHA-1-of-the-commit>i zrzucisz starą gałąź?
yasouser
6
@yasouser - Nie jestem pewien, czy jakakolwiek gałąź „master” dumpingowa jest dobrym pomysłem.
Bulwersator

Odpowiedzi:

578

Możesz to zrobić dla dowolnych referencji. Oto jak przenieść wskaźnik gałęzi:

git update-ref -m "reset: Reset <branch> to <new commit>" refs/heads/<branch> <commit>

Ogólna forma:

git update-ref -m "reset: Reset <branch> to <new commit>" <ref> <commit>

Jeśli chcesz, możesz wybrać gnidy dotyczące komunikatu o ponownym logowaniu - uważam, że branch -ften różni się od reset --hardjednego i nie jest to dokładnie żaden z nich.

Adam A.
źródło
39
Gdzie jest dobre przesłanie? Gdzie jest przechowywany i jak go później przeczytać?
Mot
4
UWAGA: To nie działa na nagich repozytoriach. W czystych repozytoriach musisz użyć „git branch -f master <commit>”, aby zaktualizować gałąź (patrz odpowiedź poniżej).
Czerwiec Rodos
37
Jeśli, podobnie jak ja, przypadkowo użyjesz <branch> zamiast refs / heads / <branch>, skończysz z nowym plikiem w katalogu .git na .git / <branch> i otrzymasz wiadomości takie jak „zmiana nazwy„ master ”jest dwuznaczna, gdy próbujesz z nim pracować. Możesz usunąć plik z katalogu .git, aby to naprawić.
David Minor
34
Nie wyjaśniono z satysfakcją, dlaczego jest to lepsze niż git branch -f. Mówiąc ściślej, wydaje się, że ta metoda jest: (A) trudniejsza w użyciu (B) trudniejsza do zapamiętania i (C) bardziej niebezpieczna
Steven Lu
10
„co dokładnie oznaczają arbitralne referencje” - Oddziały nie są jedynym rodzajem referencji, który wskazuje na zatwierdzenie. Istnieją tagi, a także możesz sam tworzyć referencje stylów ref / whatevs / myref, które nie są rozgałęzieniami ani tagami. Uważam, że to również odpowiada na pytanie Stevena Lu o to, co może być „lepsze”. Zgadzam się, gałąź -f jest najprostsza, jeśli pracujesz z gałęziami.
Adam
962
git branch -f <branch-name> <new-tip-commit>
Chris Johnsen
źródło
24
Lub dowolnych pozycjach piśmiennictwa, git update-ref -m "reset: Reset <branch> to <new commit>" <branch> <commit>. (Jeśli chcesz, możesz wybrać gnidy na temat komunikatu o ponownym logowaniu - uważam, że branch -ften różni się od reset --hardjednego, i to nie jest dokładnie żaden z nich.)
Cascabel
4
Jefromi, proszę napisać osobną odpowiedź, aby uzyskać głosy. :)
Mot
16
To lepsza odpowiedź, ponieważ obsługuje 99% przypadków i faktycznie jest zgodna z dokumentacją. git help branchmówi „-f, --force Zresetuj <nazwazgałęzienia> do <startpoint>, jeśli <nazwazgałęzienia> już istnieje. Bez -f gałąź git odmawia zmiany istniejącej gałęzi.”
AlexChaffee
12
Robię git branch -f master <hash>i to mówi mi fatal: Cannot force update the current branch.Ummmm, co muszę teraz zrobić, sprawdź jakąś inną losową gałąź, zanim będę mógł używać tego polecenia?
Qwertie,
20
To nie zadziała, jeśli gałąź, którą próbujesz przenieść, jest bieżącą gałęzią ( HEADwskazuje na nią).
Vladimir Panteleev
135

Możesz także przekazać git reset --hardodwołanie do zatwierdzenia.

Na przykład:

git checkout branch-name
git reset --hard new-tip-commit

Odkryłem, że robię coś takiego częściowo:

Zakładając tę ​​historię

$ git log --decorate --oneline --graph
* 3daed46 (HEAD, master) New thing I shouldn't have committed to master
* a0d9687 This is the commit that I actually want to be master

# Backup my latest commit to a wip branch
$ git branch wip_doing_stuff

# Ditch that commit on this branch
$ git reset --hard HEAD^

# Now my changes are in a new branch
$ git log --decorate --oneline --graph
* 3daed46 (wip_doing_stuff) New thing I shouldn't have committed to master
* a0d9687 (HEAD, master) This is the commit that I actually want to be master
Amiel Martin
źródło
Ma to największy sens, ponieważ zwykle używa się HEAD lub HEAD ^, aby cofnąć końcówkę gałęzi w czasie. Jest to zatem spójne z określeniem wcześniejszego zatwierdzenia.
justingordon
11
To dobrze, jeśli twoje drzewo robocze jest czyste. Jeśli masz wiele etapowych lub nieetapowych zmian, prawdopodobnie lepiej zrobić to tak, git update-refjak opisano powyżej.
płatny frajer
16
Czy zauważyłeś, że twoja „odpowiedź” nie dodaje niczego, co nie jest już częścią pytania? - OP powiedział: jeśli jest wyrejestrowany ... możesz użyć git reset --hard ...Nie musisz go tutaj powtarzać! :-(
Robert Siemer,
6
@Robert: Nie zgadzam się. Pytanie nie mówiło, jak go używać i tak jest. Miło było nie musieć tak szukać.
Wilson F
7
@WilsonF, może miło było znaleźć to tutaj, ale w ogóle nie odpowiada na pytanie. Być może jest to odpowiedź na inne pytanie, ale tutaj jest źle .
Robert Siemer,
52

Aby wzbogacić dyskusję, jeśli chcesz przenieść myBranchgałąź do bieżącego zatwierdzenia, po prostu pomiń drugi argument po-f

Przykład:

git branch -f myBranch


Generalnie robię to, gdy jestem rebasew stanie Odłączony HEAD :)

Matheus Felipe
źródło
13

W gitk --all:

  • kliknij prawym przyciskiem myszy żądany zatwierdzenie
  • -> utwórz nowy oddział
  • wprowadź nazwę istniejącego oddziału
  • naciśnij klawisz Return w oknie dialogowym, które potwierdza zastąpienie starej gałęzi o tej nazwie .

Uwaga: ponowne utworzenie zamiast modyfikacji istniejącej gałęzi spowoduje utratę informacji o gałęzi śledzenia . (Zasadniczo nie stanowi to problemu w prostych przypadkach użycia, w których jest tylko jeden pilot, a lokalny oddział ma taką samą nazwę jak odpowiadająca gałąź w pilocie. Zobacz komentarze, aby uzyskać więcej informacji, dzięki @mbdevpl za zwrócenie uwagi na ten minus.

Byłoby fajnie, gdyby gitkmiał funkcję, w której okno dialogowe zawierało 3 opcje: nadpisywanie, modyfikowanie istniejących lub anulowanie.


Nawet jeśli zwykle jesteś ćpunem z wiersza poleceń, takim jak ja, git guii gitkjesteś całkiem ładnie zaprojektowany dla podzbioru użycia git, na który pozwalają. Gorąco polecam używanie ich do tego, w czym są dobrzy (tj. Wybiórcze umieszczanie przystawek do / z indeksu w git gui, a także po prostu zatwierdzanie. (Ctrl-s, aby dodać podpisany: wiersz, ctrl-enter, aby zatwierdzić .)

gitk jest świetny do śledzenia kilku gałęzi podczas sortowania zmian w ładną serię łatek do przesłania w górę lub w cokolwiek innego, w którym musisz śledzić to, co znajdujesz się w środku z wieloma gałęziami.

Nie mam nawet otwartej graficznej przeglądarki plików, ale uwielbiam gitk / git gui.

Peter Cordes
źródło
1
Tak łatwo! Być może właśnie przekonwertowałem z gitg na gitk.
Michael Cole
W ten sposób informacje gałęzi śledzenia są tracone.
mbdevpl,
@mbdevpl: Nie jestem naprawdę ekspertem od gitów. Myślę, że rozumiem, co masz na myśli, ale nie implikacje. Używałem tego dość często i nadal byłem w stanie zepchnąć te gałęzie do gałęzi o tej samej nazwie na pilocie. Jakie są dla Ciebie powiązania między oddziałem a jego oddziałem zdalnego śledzenia?
Peter Cordes
@mbdevpl: czy ma to znaczenie tylko wtedy , gdy lokalny oddział ma inną nazwę niż zdalny oddział, który śledzi ?
Peter Cordes
1
@PeterCordes Ineed, gdy nazwy oddziałów nie pasują, ma to znaczenie. Również gdy jest więcej niż jeden pilot. Również gdy używasz git zachęty do wyświetlania statusu gałęzi, pokaże ona odległość zatwierdzenia do gałęzi śledzenia (jeśli jest ustawiona). Wpływa to również na git statuswydajność. Dodatkowo, w niektórych przypadkach git fetchi git pushnie będzie działać bez określania zdalnego wyraźnie, jeśli nie ustawić oddział śledzenia. Nie znam wszystkich przypadków, ale dla mnie ogólna zasada jest taka, że ​​dla wygody i szybkości pracy lepiej jest mieć gałęzie śledzące w kolejności.
mbdevpl,
7

Zalecanym rozwiązaniemgit branch -f branch-pointer-to-move new-pointer w TortoiseGit :

  • „Dziennik Git Show”
  • Zaznacz „Wszystkie gałęzie”
  • W linii, do której chcesz przenieść wskaźnik gałęzi (wskaźnik nowej):
    • Kliknij prawym przyciskiem myszy „Utwórz oddział w tej wersji”
    • Obok „Oddziału” wpisz nazwę oddziału do przeniesienia (wskaźnik oddziału do ruchu)
    • W obszarze „Podstawowy” sprawdź, czy nowy wskaźnik jest poprawny
    • Zaznacz „Siła”
    • Ok

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

topór.
źródło
4

Szczerze mówiąc, jestem zaskoczony, jak nikt nie pomyślał o git pushpoleceniu:

git push -f . <destination>:<branch>

Kropka (.) Oznacza lokalne repozytorium i może być potrzebna opcja -f, ponieważ miejsce docelowe może znajdować się „za swoim zdalnym odpowiednikiem” .

Chociaż to polecenie służy do zapisywania zmian na serwerze, wynik jest dokładnie taki sam, jak w przypadku przeniesienia gałęzi zdalnej ( <branch>) do tego samego zatwierdzenia, co gałąź lokalna ( <destination>)

Adrian
źródło
Możesz to również zrobić bez -funikania blokowania czegokolwiek lokalnego; na przykład git fetch origin && git push . origin/develop:developjest to szybka i niezawodna wersja bez git checkout develop && git pull --ff-only
czeków
1

Otwórz plik .git/refs/heads/<your_branch_name>i zmień przechowywany tam skrót na taki, w którym chcesz przenieść głowę oddziału. Po prostu edytuj i zapisz plik w dowolnym edytorze tekstu. Upewnij się tylko, że gałąź do modyfikacji nie jest aktualnie aktywna.

Oświadczenie: Prawdopodobnie nie jest to zalecany sposób, ale wykonuje zadanie.

Guillermo Gutiérrez
źródło
1
Nie jestem pewien, czy jest to chaotyczny czy zły sposób na zrobienie tego. 🤔 😉
Keith Russell
@KeithRussell może być zarówno: P
Guillermo Gutiérrez
0

W przypadku, gdy zatwierdzenie, które chcesz wskazać, znajduje się przed bieżącą gałęzią (tak powinno być, chyba że chcesz cofnąć ostatnie zatwierdzenia bieżącej gałęzi), możesz po prostu zrobić:

git merge <commit>
Jean Paul
źródło
Pytanie zadawane o to, co zrobić, jeśli oddział nie jest wyewidencjonowany.
Keith Russell
Ups, przegapiłem ten punkt. W takim przypadku możesz zrobić git push . <commit>:<branch>tak , jak już sugerowano.
Jean Paul