Jestem nowy w gałęziach Git. Zawsze pracuję nad jednym oddziałem i zatwierdzam zmiany, a następnie okresowo wypycham do mojego zdalnego źródła.
Gdzieś ostatnio zrobiłem reset niektórych plików, aby pozbyć się ich ze stopniowania zmian, a później rebase -i
pozbyłem się kilku ostatnich lokalnych zatwierdzeń. Teraz jestem w stanie, którego nie do końca rozumiem.
W moim obszarze roboczym git log
pokazuje dokładnie to, czego się spodziewałem - jadę właściwym pociągiem z zobowiązaniami, których nie chciałem odejść, i nowymi, itp.
Ale właśnie przepchnąłem do zdalnego repozytorium, a co jest inne - kilka zmian, które zabiłem w bazie, zostało wypchniętych, a nowych popełnionych lokalnie nie ma.
Myślę, że „master / origin” jest odłączony od HEAD, ale nie jestem w 100% jasny, co to znaczy, jak wizualizować go za pomocą narzędzi wiersza poleceń i jak to naprawić.
I did a reset of some files to get them out of commit staging
częściowo zrobiłeś ? przepraszam za pytania :)Odpowiedzi:
Najpierw wyjaśnijmy, czym jest HEAD i co to znaczy, kiedy jest odłączony.
HEAD to symboliczna nazwa aktualnie wyrejestrowanego zatwierdzenia. Kiedy HEAD nie jest odłączony ( sytuacja „normalna” 1 : masz gałąź wyewidencjonowaną), HEAD faktycznie wskazuje na „ref” gałęzi, a gałąź wskazuje na zatwierdzenie. HEAD jest więc „przymocowany” do gałęzi. Po dokonaniu nowego zatwierdzenia gałąź, na którą wskazuje HEAD, jest aktualizowana, aby wskazywała na nowe zatwierdzenie. HEAD podąża automatycznie, ponieważ wskazuje tylko gałąź.
git symbolic-ref HEAD
wydajnościrefs/heads/master
Oddział o nazwie „master” jest wyewidencjonowany.
git rev-parse refs/heads/master
wydajność17a02998078923f2d62811326d130de991d1a95a
Zatwierdzenie to bieżąca wskazówka lub „głowa” gałęzi master.
git rev-parse HEAD
przynosi również17a02998078923f2d62811326d130de991d1a95a
To właśnie oznacza być „symbolicznym ref”. Wskazuje obiekt poprzez inne odniesienie.
(Symboliczne odwołania zostały pierwotnie zaimplementowane jako dowiązania symboliczne, ale później zmieniono je na zwykłe pliki z dodatkową interpretacją, aby mogły być używane na platformach, które nie mają dowiązań symbolicznych).
Mamy
HEAD
→refs/heads/master
→17a02998078923f2d62811326d130de991d1a95a
Kiedy HEAD jest odłączony, wskazuje bezpośrednio na zatwierdzenie - zamiast pośrednio wskazywać na jeden poprzez gałąź. Możesz myśleć o odłączonej GŁOWIE jako o nienazwanej gałęzi.
git symbolic-ref HEAD
nie działa zfatal: ref HEAD is not a symbolic ref
git rev-parse HEAD
feds17a02998078923f2d62811326d130de991d1a95a
Ponieważ nie jest to symboliczny odnośnik, musi wskazywać bezpośrednio na samo zatwierdzenie.
Mamy
HEAD
→17a02998078923f2d62811326d130de991d1a95a
Ważną rzeczą, o której należy pamiętać przy odłączonym HEAD jest to, że jeśli zatwierdzenie, na które wskazuje, jest w inny sposób niepowiązane (żaden inny odnośnik nie może do niego dotrzeć), wtedy stanie się „wiszące”, kiedy kasujesz jakieś inne zatwierdzenie. W końcu takie zwisające zatwierdzenia zostaną przycięte w procesie wyrzucania elementów bezużytecznych (domyślnie są one przechowywane przez co najmniej 2 tygodnie i mogą być przechowywane dłużej przez odwołanie się do reflog HEAD).
1 Wykonywanie „normalnej” pracy z odłączoną GŁOWĄ jest całkowicie w porządku, wystarczy śledzić to, co robisz, aby uniknąć wyrzucania historii z rejestru.
Pośrednie etapy interaktywnego rebase są wykonywane z odłączonym HEAD (częściowo, aby uniknąć zanieczyszczenia reflogu aktywnej gałęzi). Jeśli zakończysz operację pełnego bazowania, zaktualizuje ona twoją oryginalną gałąź o skumulowany wynik operacji bazowania i ponownie przyłączy HEAD do oryginalnej gałęzi. Domyślam się, że nigdy nie ukończyłeś w pełni procesu rebase; pozostawi to odłączony HEAD wskazujący na zatwierdzenie, które zostało ostatnio przetworzone przez operację rebase.
Aby wyjść z tej sytuacji, powinieneś utworzyć gałąź, która wskazuje na zatwierdzenie aktualnie wskazywane przez odłączony HEAD:
(te dwa polecenia mogą być skrócone jako
git checkout -b temp
)Spowoduje to ponowne podłączenie HEAD do nowego
temp
oddziału.Następnie powinieneś porównać bieżące zatwierdzenie (i jego historię) z normalną gałęzią, nad którą miałeś pracować:
(Prawdopodobnie będziesz chciał poeksperymentować z opcjami dziennika: dodaj
-p
, odłóż,--pretty=…
aby zobaczyć cały komunikat dziennika itp.)Jeśli Twój nowy
temp
oddział wygląda dobrze, możesz zaktualizować (np.),master
Aby go wskazać:(te dwa polecenia mogą być skrócone jako
git checkout -B master temp
)Następnie możesz usunąć gałąź tymczasową:
Wreszcie, prawdopodobnie będziesz chciał przeforsować przywróconą historię:
Konieczne może być dodanie
--force
na końcu tego polecenia, aby wypchnąć, jeśli zdalna gałąź nie może być „szybko przekazana” do nowego zatwierdzenia (tj. Upuściłeś lub przepisałeś istniejące zatwierdzenie lub w inny sposób przepisałem trochę historii).Jeśli byłeś w trakcie operacji rebase, prawdopodobnie powinieneś to wyczyścić. Możesz sprawdzić, czy trwa proces rebase, szukając katalogu
.git/rebase-merge/
. Możesz ręcznie wyczyścić trwający rebase, po prostu usuwając ten katalog (np. Jeśli nie pamiętasz już celu i kontekstu aktywnej operacji rebase). Zwykle byś użyłgit rebase --abort
, ale to powoduje dodatkowe resetowanie, którego prawdopodobnie chcesz uniknąć (przenosi HEAD z powrotem do oryginalnej gałęzi i resetuje go z powrotem do pierwotnego zatwierdzenia, co cofnie część pracy, którą wykonaliśmy powyżej).źródło
man git-symbolic-ref
: „W przeszłości.git/HEAD
było dowiązanie symbolicznerefs/heads/master
. Kiedy chcieliśmy przejść do innej gałęzi, zrobiliśmy toln -sf refs/heads/newbranch .git/HEAD
, a kiedy chcieliśmy dowiedzieć się, na której gałęzi się znajdujemy, zrobiliśmy toreadlink .git/HEAD
. Ale dowiązania symboliczne nie są w pełni przenośne , więc są teraz przestarzałe, a odniesienia symboliczne (jak opisano powyżej) są domyślnie używane ”.git branch -f master HEAD && git checkout master
wystarczy - zakładając, że Twoim celem jest utrzymanie obecnej głowy, ale wyznaczenie jej jakomaster
. Inne cele również mają sens i wymagają innych przepisów.Po prostu zrób to:
Lub, jeśli masz zmiany, które chcesz zachować, wykonaj następujące czynności:
źródło
git reset
powinien zawierać ostrzeżenie „Jeśli nie masz pojęcia, co robisz, przestań”. Właśnie wyzdrowiałem z godziny terroru, myśląc, że straciłem ostatni tydzień pracy. Dzięki!Natknąłem się na ten problem i kiedy przeczytałem w głosowanej odpowiedzi:
Pomyślałem: Ah-ha! Jeśli
HEAD
jest symboliczną nazwą aktualnego zatwierdzenia kasy, mogę ją pogodzić,master
zmieniając ją namaster
:To polecenie:
master
HEAD
powrotem do punktuHEAD
odbiegającegomaster
master
Rezultatem końcowym jest to, że wszystkie zatwierdzenia, które były w,
HEAD
ale niemaster
były, również są wmaster
.master
pozostaje sprawdzone.W odniesieniu do pilota:
Historia zdalna nie może być już przewijana do przodu przy użyciu historii lokalnej. Będziesz musiał użyć force-push (
git push -f
), aby zastąpić zdalną historię. Jeśli masz współpracowników, zwykle warto z nimi skoordynować, aby wszyscy byli na tej samej stronie.Po
master
przekazaniu do zdalnegoorigin
gałąź zdalnego śledzeniaorigin/master
zostanie zaktualizowana, aby wskazywała to samo zatwierdzenie, comaster
.źródło
Spójrz tutaj na podstawowe wyjaśnienie odłączonej głowy:
http://git-scm.com/docs/git-checkout
Linia poleceń do wizualizacji:
lub
otrzymasz wynik jak poniżej:
Te
* (no branch)
pokazy jesteś w jednorodzinnym głowy.Mogłeś dojść do tego stanu, wykonując
git checkout somecommit
itp., I ostrzegłoby Cię to:Teraz, aby doprowadzić ich do mistrza:
Zrób
git reflog
lub nawet po prostugit log
zanotuj swoje zobowiązania. Terazgit checkout master
igit merge
zobowiązania.Edytować:
Aby dodać, użyj
git rebase -i
nie tylko do usuwania / zabijania niepotrzebnych zmian, ale także do ich edycji. Po prostu wspomnij „edytuj” na liście zatwierdzeń, a będziesz mógł zmienić swoje zatwierdzenie, a następnie wydać polecenie,git rebase --continue
aby kontynuować. Zapewniłoby to, że nigdy nie pojawiłeś się w ODŁĄCZONEJ GŁOWIE.źródło
Pobierz odłączony zatwierdzenie do własnego oddziału
Po prostu biegnij
git checkout -b mynewbranch
.Następnie uruchom
git log
, a zobaczysz, że zatwierdzenie jest terazHEAD
w tej nowej gałęzi.źródło
mynewbranch
coś się do mnie przyłączy?jeśli masz tylko gałąź master i chcesz wrócić do „rozwoju” lub funkcji, wykonaj następujące czynności:
Uwaga: sprawdzanie pochodzenia / rozwoju .
Jesteś w stanie odłączonym HEAD . Możesz się rozejrzeć, wprowadzić eksperymentalne zmiany i zatwierdzić je, a także możesz odrzucić wszelkie zatwierdzenia dokonane w tym stanie bez wpływu na oddziały, wykonując kolejną kasę ...
następnie
To działa :)
źródło
Jeśli chcesz wypchnąć bieżącą odłączoną GŁOWĘ (sprawdź
git log
wcześniej), spróbuj:aby wysłać odłączony HEAD do gałęzi master w miejscu pochodzenia. Jeśli twoje wypychanie zostanie odrzucone, spróbuj
git pull origin master
najpierw uzyskać zmiany od pochodzenia. Jeśli nie przejmujesz się zmianami pochodzącymi z pierwotnego źródła i został on odrzucony, ponieważ zrobiłeś celową zmianę bazy i chcesz zastąpić origin / master swoją obecnie odłączoną gałęzią - możesz to wymusić (-f
). Jeśli straciłeś dostęp do poprzednich zatwierdzeń, zawsze możesz uruchomić,git reflog
aby zobaczyć historię ze wszystkich oddziałów.Aby wrócić do gałęzi master, zachowując zmiany, wypróbuj następujące polecenia:
Zobacz: Git: „Obecnie nie w żadnym oddziale”. Czy istnieje prosty sposób na powrót do oddziału przy zachowaniu zmian?
źródło
Znalazłem to pytanie podczas wyszukiwania
You are in 'detached HEAD' state.
Po przeanalizowaniu tego, co zrobiłem, aby się tu dostać, w porównaniu z tym, co zrobiłem w przeszłości, odkryłem, że popełniłem błąd.
Mój normalny przepływ to:
Tym razem zrobiłem:
Problem polega na tym, że przypadkowo:
Zamiast:
Naprawą (w mojej sytuacji) było po prostu uruchomienie powyższej komendy, a następnie kontynuowanie przepływu:
źródło
Poniższe działało dla mnie (używając tylko głównego oddziału):
Pierwszy wypycha odłączoną GŁOWĘ do zdalnego źródła.
Drugi przechodzi do głównego oddziału.
Trzeci odzyskuje HEAD, który przywiązuje się do mistrza oddziału.
Problemy mogą pojawić się przy pierwszym poleceniu, jeśli push zostanie odrzucony. Ale nie byłby to już problem odłączonej głowy, ale chodzi o to, że odłączony HEAD nie jest świadomy niektórych zdalnych zmian.
źródło
Właśnie natrafiłem dziś na ten problem i jestem pewien, że rozwiązałem go, wykonując:
Byłem na komputerze służbowym, kiedy wymyśliłem, jak to zrobić, a teraz mam ten sam problem na moim komputerze osobistym. Będę musiał poczekać do poniedziałku, kiedy wrócę do komputera roboczego, aby zobaczyć dokładnie, jak to zrobiłem.
źródło
Jeśli masz całkowitą pewność, że HEAD jest dobrym stanem:
Prawdopodobnie nie możesz naciskać na pochodzenie, ponieważ twój mistrz odszedł od pochodzenia. Jeśli masz pewność, że nikt inny nie korzysta z repozytorium, możesz wymusić:
Najbardziej przydatne, jeśli jesteś w gałęzi funkcji, której nikt inny nie używa.
źródło
Wszystko, co musisz zrobić, to „git checkout [nazwa-gałęzi]”, gdzie [nazwa-gałęzi] to nazwa oryginalnej gałęzi, z której przeszedłeś w stan odłączonej głowy. (Odłączony od asdfasdf) zniknie.
Na przykład w oddziale „dev” kasujesz zatwierdzenie asdfasd14314 ->
jesteś teraz w stanie odłączonej głowy
„gałąź git” wyświetli coś w stylu ->
ale aby wyjść z odłączonego stanu głowy i wrócić do dev ->
a następnie „gałąź git” wyświetli ->
ale dzieje się tak oczywiście, jeśli nie masz zamiaru utrzymywać żadnych zmian w stanie odłączonej głowy, ale często robię to, nie zamierzając wprowadzać żadnych zmian, ale tylko spojrzeć na poprzednie zatwierdzenie
źródło
Jak zauważył Chris, miałem następującą sytuację
git symbolic-ref HEAD
nie działa zfatal: ref HEAD is not a symbolic ref
Jednak
git rev-parse refs/heads/master
wskazywał na dobry popełnić skąd mogę odzyskać (w moim przypadku ostatniego zatwierdzenia i widać, że zobowiązują się za pomocągit show [SHA]
Potem zrobiłem wiele nieporządnych rzeczy, ale wydaje się, że to naprawiłem,
git symbolic-ref HEAD refs/heads/master
I głowa jest przywiązana!
źródło
Zamiast robić
git checkout origin/master
po prostu zrób
git checkout master
następnie
git branch
potwierdzi swój oddział.źródło
Miałem ten problem dzisiaj, kiedy zaktualizowałem submoduł, ale nie było go w żadnej gałęzi. Już się popełniłem, więc ukrywanie, kasa, rozpakowywanie nie działało. Skończyło się na tym, że wybrałem zatwierdzenie odłączonej głowy. Więc natychmiast po tym, jak popełniłem (gdy wypychanie nie powiodło się), zrobiłem:
Myślałem: jestem na oderwanej głowie, ale chcę być mistrzem. Zakładając, że mój stan odłączenia nie różni się bardzo od master, gdybym mógł zastosować moje zatwierdzenie do master, byłbym ustawiony. Właśnie to robi cherry-pick.
źródło
Jeśli zrobiłeś kilka zatwierdzeń na masterie i po prostu chcesz
master
tam „scalić wstecz” (tzn. Chceszmaster
wskazaćHEAD
), linijka będzie:master
, nawet jeśli już istnieje (która jest jak przeprowadzkamaster
i tego właśnie chcemy).HEAD
, gdzie jesteś.master
.Uznałem to za szczególnie przydatne w przypadku sub-repozytoriów, które również często znajdują się w stanie odłączonym.
źródło
Miałem ten sam problem i rozwiązałem go, wykonując następujące kroki.
Jeśli chcesz zachować zmiany
git checkout master
polecenie, aby wrócić do gałęzi master.git checkout -b changes
igit checkout -B master changes
Jeśli nie potrzebujesz zmian
Aby usunąć wszystkie nieśledzone pliki ze swojego oddziału, uruchom
git clean -df
.Następnie musisz usunąć wszystkie niestabilne zmiany w repozytorium. Aby to zrobić, musisz biec
git checkout --
Na koniec musisz przywrócić gałąź do gałęzi głównej za pomocą
git checkout master
polecenia.źródło
Dla mnie było to tak proste, jak ponowne usunięcie lokalnego oddziału, ponieważ nie miałem żadnych lokalnych zatwierdzeń, które chciałbym wcisnąć:
Więc zrobiłem:
A następnie ponownie sprawdzając oddział:
źródło
Kiedy osobiście znajduję się w sytuacji, gdy okazuje się, że dokonałem pewnych zmian, gdy nie jestem w
master
(tj.HEAD
Jest odłączony tuż nadmaster
i nie ma żadnych pośrodku między nimi) ukrywanie może pomóc:źródło
Krótko mówiąc, odłączony stan HEAD oznacza, że nie jesteś wyewidencjonowany w HEAD (lub tip) dowolnej gałęzi .
Zrozum z przykładem
Gałąź w większości przypadków jest sekwencją wielu zatwierdzeń, takich jak:
Zatwierdzenie 1: master -> branch_HEAD (123be6a76168aca712aea16076e971c23835f8ca)
Zatwierdź 2: master -> 123be6a76168aca712aea16076e971c23835f8ca -> branch_HEAD (100644a76168aca712aea16076e971c23835f8ca)
Jak widać powyżej w przypadku sekwencji zatwierdzeń, twoja gałąź wskazuje na twoje ostatnie zatwierdzenie. W takim przypadku, jeśli wykonasz transakcję w celu zatwierdzenia 123be6a76168aca712aea16076e971c23835f8ca, to będziesz w stanie odłączonej głowy, ponieważ HEAD twojego oddziału wskazuje na 100644a76168aca712aea16076e971c23835f8ca i technicznie jesteś wyewidencjonowany w HEAD żadnego oddziału. W związku z tym jesteś w stanie odłączonym HEAD.
Wyjaśnienie teoretyczne
Na tym blogu wyraźnie stwierdzono, że repozytorium Git jest drzewem zatwierdzeń, z każdym zatwierdzeniem wskazującym na jego przodka, przy czym każdy wskaźnik zatwierdzenia jest aktualizowany, a te wskaźniki do każdej gałęzi są przechowywane w podkatalogach .git / refs. Tagi są przechowywane w .git / refs / tags, a gałęzie są przechowywane w .git / refs / heads. Jeśli spojrzysz na któryś z plików, zobaczysz, że każdy znacznik odpowiada jednemu plikowi z 40-znakowym hashem zatwierdzenia i jak wyjaśniono powyżej przez @Chris Johnsen i @Yaroslav Nikitenko, możesz sprawdzić te referencje.
źródło
Wpadłem w naprawdę głupi stan, wątpię, czy ktokolwiek uzna to za przydatne ... ale na wszelki wypadek
które ostatecznie naprawiłem
źródło
To działało dla mnie idealnie:
1.
git stash
aby zapisać lokalne modyfikacjeJeśli chcesz odrzucić zmiany,
git clean -df
git checkout -- .
git clean usuwa wszystkie nieśledzone pliki (ostrzeżenie: chociaż nie usuwa zignorowanych plików wymienionych bezpośrednio w .gitignore, może usuwać zignorowane pliki znajdujące się w folderach), a git checkout usuwa wszystkie nieustawione zmiany.
2.
git checkout master
aby przejść do głównej gałęzi (Zakładając, że chcesz użyć master)3.
git pull
wyciągnąć ostatnie zatwierdzenie z gałęzi master4.
git status
aby sprawdzić, czy wszystko wygląda świetnieźródło
W moim przypadku uruchomiłem
git status
i zobaczyłem, że mam kilka nieśledzonych plików w moim katalogu roboczym.Aby rebase działał, musiałem je tylko wyczyścić (ponieważ ich nie potrzebowałem).
źródło
Jeśli używasz EGit w Eclipse: załóż, że twój master jest główną gałęzią programistyczną
Po tym powinieneś być w stanie ponownie dołączyć do master-origin.
źródło
Miałem ten sam problem. Przechowuję swoje zmiany za pomocą
git stash
i mocno resetuję gałąź lokalnie do poprzedniego zatwierdzenia (myślałem, że to spowodowało), a następnie zrobiłemgit pull
i nie dostaję teraz tej głowy. Nie zapomnijgit stash apply
ponownie wprowadzić zmian.źródło
źródło