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ści refs/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 z fatal: ref HEAD is not a symbolic ref
git rev-parse HEAD
feds 17a02998078923f2d62811326d130de991d1a95a
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:
git branch temp
git checkout temp
(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ć:
git log --graph --decorate --pretty=oneline --abbrev-commit master origin/master temp
git diff master temp
git diff origin/master temp
(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ć:
git branch -f master temp
git checkout master
(te dwa polecenia mogą być skrócone jako git checkout -B master temp
)
Następnie możesz usunąć gałąź tymczasową:
git branch -d temp
Wreszcie, prawdopodobnie będziesz chciał przeforsować przywróconą historię:
git push origin master
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).