Ako môžem zosúladiť oddelený HEAD s master/origin?
Som nováčikom v zložitosti vetvenia systému Git. Vždy pracujem na jednej vetve a odovzdávam zmeny a potom ich pravidelne posielam do svojho vzdialeného pôvodu.
Niekde som nedávno urobil reset niektorých súborov, aby som ich dostal z commit staging, a neskôr som urobil rebase -i
, aby som sa zbavil niekoľkých nedávnych lokálnych revízií. Teraz som v stave, ktorému celkom nerozumiem.
V pracovnej oblasti mi git log
ukazuje presne to, čo by som očakával - som v správnom vlaku s commitmi, ktoré som nechcel odstrániť, a novými, ktoré tam sú, atď.
Ale práve som tlačil do vzdialeného repozitára a to, čo tam je, je iné -- pár revízií, ktoré som zabil v rebase, sa tlačilo a nové, ktoré som commitoval lokálne, tam nie sú.
Myslím, že "master/origin" je oddelený od HEAD, ale nie je mi na 100 % jasné, čo to znamená, ako to vizualizovať pomocou nástrojov príkazového riadku a ako to opraviť.
Najprv si objasnime, čo je HEAD a čo znamená, keď je odpojený.
HEAD je symbolický názov pre aktuálne skontrolovanú revíziu. Keď HEAD nie je odpojené ("normálna" 1 situácia: máte odkontrolovanú vetvu), HEAD v skutočnosti ukazuje na "ref" vetvy a vetva ukazuje na revíziu. HEAD je teda "pripojený" k vetve. Keď vykonáte novú revíziu, vetva, na ktorú HEAD ukazuje, sa aktualizuje tak, aby ukazovala na novú revíziu. HEAD nasleduje automaticky, pretože práve ukazuje na vetvu.
git symbolic-ref HEAD
dávarefs/heads/master
Vetva s názvom "master" je odškrtnutá.git rev-parse refs/heads/master
yield17a02998078923f2d62811326d130de991d1a95a
Táto revízia je aktuálny tip alebo "hlava" vetvy master.git rev-parse HEAD
je tiež17a02998078923f2d62811326d130de991d1a95a
Toto je to, čo znamená byť "symbolickým ref". Ukazuje na objekt prostredníctvom nejakého iného odkazu.(Symbolické odkazy boli pôvodne implementované ako symbolické odkazy, ale neskôr sa zmenili na obyčajné súbory s dodatočnou interpretáciou, aby sa mohli používať na platformách, ktoré nemajú symbolické odkazy).
Máme
HEAD
→refs/heads/master
→17a02998078923f2d62811326d130de991d1a95a
Keď je HEAD oddelené, ukazuje priamo na revíziu - namiesto toho, aby na ňu ukazovalo nepriamo cez vetvu. Odpojený HEAD si môžete predstaviť ako nepomenovanú vetvu.
git symbolic-ref HEAD
zlyhá s hlásenímfatal: ref HEAD is not a symbolic ref
git rev-parse HEAD
je17a02998078923f2d62811326d130de991d1a95a
Keďže nejde o symbolický ref, musí ukazovať priamo na samotnú revíziu.Máme
HEAD
→17a02998078923f2d62811326d130de991d1a95a
Dôležitá vec, ktorú si treba zapamätať pri odpojenom HEAD, je, že ak je revízia, na ktorú ukazuje, inak neodkazovaná (žiadny iný ref sa na ňu nedostane), potom sa stane "visiacou", keď odhlásite nejakú inú revíziu. Nakoniec budú takéto visiace revízie vyradené z procesu zberu odpadu (štandardne sa uchovávajú aspoň 2 týždne a môžu sa uchovávať dlhšie, ak sa na ne odkazuje v reflogu HEAD).
1 Je úplne v poriadku vykonávať "normálnu" prácu s odpojeným HEAD, len musíte sledovať, čo robíte, aby ste nemuseli loviť zahodenú históriu z reflogu.
Medzikroky interaktívneho rebase sa vykonávajú s oddeleným HEAD (čiastočne preto, aby sa zabránilo znečisteniu reflogu aktívnej vetvy). Ak dokončíte celú operáciu rebase, aktualizuje sa pôvodná vetva kumulatívnym výsledkom operácie rebase a HEAD sa znovu pripojí k pôvodnej vetve. Predpokladám, že ste proces rebase nikdy úplne nedokončili; zostane vám tak odpojený HEAD ukazujúci na revíziu, ktorá bola naposledy spracovaná operáciou rebase.
Aby ste sa z tejto situácie dostali, mali by ste vytvoriť vetvu, ktorá bude ukazovať na revíziu, na ktorú v súčasnosti ukazuje váš odpojený HEAD:
(tieto dva príkazy možno skrátiť ako
git checkout -b temp
)Týmto sa váš HEAD znovu pripojí k novej vetve
temp
.Potom by ste mali porovnať aktuálnu revíziu (a jej históriu) s normálnou vetvou, na ktorej ste očakávali, že budete pracovať:
(Pravdepodobne budete chcieť experimentovať s možnosťami denníka: pridať
-p
, vynechať--pretty=...
, aby ste videli celú správu denníka, atď.)Ak vaša nová vetva
temp
vyzerá dobre, možno budete chcieť aktualizovať (napr.)master
, aby na ňu ukazoval:(tieto dva príkazy možno skrátiť ako
git checkout -B master temp
)Potom môžete dočasnú vetvu odstrániť:
Nakoniec budete pravdepodobne chcieť poslať obnovenú históriu:
Možno budete musieť pridať
--force
na koniec tohto príkazu na push, ak vzdialená vetva nemôže byť "rýchlo preklopená" na novú revíziu (t.j. upustili ste, alebo prepísali nejakú existujúcu revíziu, alebo inak prepísali nejaký kúsok histórie).Ak ste boli uprostred operácie rebase, mali by ste ju pravdepodobne vyčistiť. To, či prebiehala rebaze, môžete skontrolovať vyhľadaním adresára
.git/rebase-merge/
. Prebiehajúcu rebase môžete ručne vyčistiť tak, že tento adresár jednoducho odstránite (napr. ak si už nepamätáte účel a kontext aktívnej operácie rebase). Zvyčajne by ste použiligit rebase --abort
, ale to robí nejaké dodatočné resetovanie, ktorému sa pravdepodobne chcete vyhnúť (presúva HEAD späť do pôvodnej vetvy a resetuje ju späť na pôvodnú revíziu, čo zruší časť práce, ktorú sme vykonali vyššie).Základné vysvetlenie odpojenej hlavy nájdete tu:
http://git-scm.com/docs/git-checkout.
Príkazový riadok na vizualizáciu:
alebo
dostanete výstup ako je uvedený nižšie:
Znak
* (bez vetvy)
ukazuje, že ste v oddelenej hlave.Do tohto stavu ste sa mohli dostať vykonaním príkazu
git checkout somecommit
atď. a upozornilo by vás to nasledujúcim spôsobom:Nynie, ako ich dostať na master:
Vykonajte
git reflog
alebo dokonca lengit log
a zaznamenajte svoje revízie. Terazgit checkout master
agit merge
revízie.Upravte:
Na doplnenie, použite
git rebase -i
nielen na odstránenie/zabitie revízií, ktoré nepotrebujete, ale aj na ich úpravu. Stačí v zozname revízií uviesť "editovať" a budete môcť zmeniť svoju revíziu a potom vydať príkazgit rebase --continue
na pokračovanie. To by zabezpečilo, že by ste nikdy neprišli k odpojenému HEAD.Dostaňte svoju oddelenú revíziu do vlastnej vetvy
Jednoducho spustite
git checkout -b mynewbranch
.Potom spustite
git log
a uvidíte, že revízia je terazHEAD
na tejto novej vetve.