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ť.

Riešenie

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áva refs/heads/master Vetva s názvom "master" je odškrtnutá.
  • git rev-parse refs/heads/master yield 17a02998078923f2d62811326d130de991d1a95a Táto revízia je aktuálny tip alebo "hlava" vetvy master.
  • Výsledkom 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 HEADrefs/heads/master17a02998078923f2d62811326d130de991d1a95a

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ím fatal: ref HEAD is not a symbolic ref
  • Výsledkom git rev-parse HEAD je 17a02998078923f2d62811326d130de991d1a95a Keďže nejde o symbolický ref, musí ukazovať priamo na samotnú revíziu.

Máme HEAD17a02998078923f2d62811326d130de991d1a95a

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:

git branch temp
git checkout temp

(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ť:

git log --graph --decorate --pretty=oneline --abbrev-commit master origin/master temp
git diff master temp
git diff origin/master temp

(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:

git branch -f master temp
git checkout master

(tieto dva príkazy možno skrátiť ako git checkout -B master temp)

Potom môžete dočasnú vetvu odstrániť:

git branch -d temp

Nakoniec budete pravdepodobne chcieť poslať obnovenú históriu:

git push origin master

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žili git 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).

Komentáre (22)

Základné vysvetlenie odpojenej hlavy nájdete tu:

http://git-scm.com/docs/git-checkout.

Príkazový riadok na vizualizáciu:

git branch

alebo

git branch -a

dostanete výstup ako je uvedený nižšie:

* (no branch)
master
branch1

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:

Ste v stave 'detached HEAD'. Ste môžete sa rozhliadnuť, urobiť experimentálne zmeny a odovzdať ich a môžete zahodiť všetky revízie, ktoré ste v tomto stave bez toho, aby ste ovplyvnili akékoľvek vetvy vykonaním ďalšieho checkoutu.

Ak chcete vytvoriť novú vetvu zachovať vytvorené revízie, môžete to urobiť tak (teraz alebo neskôr) pomocou príkazu -b s príponou príkazom checkout znova. Príklad:

git checkout -b new_branch_name

Nynie, ako ich dostať na master:

Vykonajte git reflog alebo dokonca len git log a zaznamenajte svoje revízie. Teraz git checkout master a git merge revízie.

git merge HEAD@{1}

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íkaz git rebase --continue na pokračovanie. To by zabezpečilo, že by ste nikdy neprišli k odpojenému HEAD.

Komentáre (2)

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 teraz HEAD na tejto novej vetve.

Komentáre (2)