Jak ustawia się origin / HEAD?

144

Mam gałąź skonfigurowaną do śledzenia pochodzenia referencji. git checkout <branchname>przełącza się na tę gałąź, a a git statuspokaże mi, jak daleko przed lub za moją gałęzią jest od początku, ale jestem zaskoczony, że origin/HEADnadal wskazuje na origin/master, a nieorigin/<branchname>

Więc moje pytanie brzmi, w jakich okolicznościach pochodzenie / HEAD zostaje przeniesione?

EDYTOWAĆ:

Doceniam odpowiedzi o tym, jak przenieść pochodzenie / HEAD, ale interesuje mnie to, co „organicznie” go porusza, poza mną wyraźnie mówiąc mu, żeby to zrobił.

Na przykład, kiedy zmieniam gałęzie, git wskazuje HEAD na gałąź, którą sprawdzam, więc jestem zaskoczony, że origin / HEAD nie porusza się w ten sam sposób.

ecoffey
źródło
Zauważ, że to pytanie dotyczy lokalnych symbolicznych odniesień do pilotów, takich jak refs/origin/HEAD. Nie chodzi o to, jak HEADustawia się własne symboliczne odniesienie repozytorium .
clacke

Odpowiedzi:

173

Najpierw zwróć uwagę, że Twoje pytanie zawiera pewne nieporozumienie. origin / HEAD reprezentuje domyślną gałąź na pilocie , tj. HEAD znajdujący się w tym zdalnym repozytorium, które nazywasz origin. Kiedy zmieniasz gałęzie w repozytorium, nie masz na to wpływu. To samo dotyczy zdalnych oddziałów; możesz mieć masteriw origin/masterswoim repozytorium, gdzie origin/masterreprezentuje lokalną kopię masteroddziału w zdalnym repozytorium.

origin's HEAD zmieni się tylko wtedy, gdy ty lub ktoś inny faktycznie zmieni go w zdalnym repozytorium , co w zasadzie nigdy nie powinno się zdarzyć - chcesz, aby domyślna gałąź repozytorium publicznego pozostała stała, na stabilnej gałęzi (prawdopodobnie master). origin / HEAD to lokalny odnośnik reprezentujący lokalną kopię HEAD w zdalnym repozytorium. (Jego pełna nazwa to refs / remotes / origin / HEAD.)

Myślę, że powyższe odpowiedzi są odpowiedzią na to, co tak naprawdę chciałeś wiedzieć, ale aby odpowiedzieć na pytanie, które wprost zadałeś ... pochodzenie / HEAD jest ustawiane automatycznie, gdy klonujesz repozytorium i to wszystko. Dziwne, że nie jest to ustawiane za pomocą poleceń takich jak git remote update- wierzę, że jedyny sposób, w jaki to się zmieni, to ręczna zmiana. (Przez zmianę rozumiem wskazanie innej gałęzi; oczywiście zatwierdzenie wskazuje na zmiany, jeśli ta gałąź się zmieni, co może się zdarzyć podczas pobierania / ściągania / zdalnej aktualizacji.)


Edycja : problem omówiony poniżej został poprawiony w Git 1.8.4.3 ; zobacz tę aktualizację .


Jest jednak małe zastrzeżenie. HEAD jest symbolicznym odnośnikiem, wskazującym na gałąź zamiast bezpośrednio do zatwierdzenia, ale protokoły zdalnego transferu git raportują tylko zatwierdzenia dla referencji. Więc Git zna SHA1 zatwierdzenia wskazanego przez HEAD i wszystkie inne referencje; następnie musi wydedukować wartość HEAD, znajdując gałąź, która wskazuje na to samo zatwierdzenie. Oznacza to, że jeśli dwie gałęzie wskazują na to, jest to niejednoznaczne. (Uważam, że jeśli to możliwe, wybiera mastera, a następnie wraca do pierwszego w kolejności alfabetycznej.) Zobaczysz to zgłoszone w wyniku git remote show origin:

$ git remote show origin
* remote origin
  Fetch URL: ...
  Push  URL: ...
  HEAD branch (remote HEAD is ambiguous, may be one of the following):
    foo
    master

Co dziwne, chociaż pojęcie HEAD wydrukowane w ten sposób zmieni się, jeśli coś się zmieni na pilocie (np. Jeśli zostanie usunięte foo), w rzeczywistości nie aktualizuje się refs/remotes/origin/HEAD. Może to prowadzić do naprawdę dziwnych sytuacji. Powiedzmy, że w powyższym przykładzie origin / HEAD faktycznie wskazywał na foo, a gałąź foo pochodzenia została usunięta. Następnie możemy to zrobić:

$ git remote show origin
...
HEAD branch: master
$ git symbolic-ref refs/remotes/origin/HEAD
refs/remotes/origin/foo
$ git remote update --prune origin
Fetching origin
 x [deleted]         (none)     -> origin/foo
   (refs/remotes/origin/HEAD has become dangling)

Więc chociaż zdalny program wie, że HEAD jest mistrzem, niczego nie aktualizuje. Nieaktualna gałąź foo jest poprawnie przycinana, a HEAD zwisa (wskazując na nieistniejącą gałąź) i nadal nie aktualizuje jej, aby wskazywała na master. Jeśli chcesz to naprawić, użyj git remote set-head origin -a, który automatycznie określa HEAD źródła, jak powyżej, a następnie faktycznie ustawia początek / HEAD, aby wskazywały na odpowiednią gałąź zdalną.

Cascabel
źródło
@jefromi Niesamowita odpowiedź! Tylko uwaga: piszesz, że HEAD jest symbolicznym odniesieniem, wskazującym na gałąź zamiast bezpośrednio do zatwierdzenia [...] , ale warto wspomnieć o „odłączonym stanie HEAD”, dla kompletności.
jub0bs
2
@Jubobs Thanks! Jeśli moja odpowiedź wymaga aktualizacji, możesz ją po prostu edytować - z pewnością zaoszczędzi to ludziom czasu na przeczytanie krótkiego podsumowania tego, jak to naprawdę działa, zamiast konieczności sortowania tego, co było prawdą dwa lata temu, a co jest prawdą teraz .
Cascabel
przeczytałem to co najmniej 5 razy i nadal nic z tego nie rozumiem
krb686
7
git remote set-head origin -awykonał robotę za mnie
Shujito
75

To jest twoje ustawienie jako właściciela lokalnego repozytorium. Zmień to w ten sposób:

git remote set-head origin some_branch

Pochodzenie / HEAD wskaże twoją gałąź zamiast master. Będzie to dotyczyło tylko Twojego repozytorium, a nie innych. Domyślnie będzie wskazywać master, chyba że coś innego zostało skonfigurowane w zdalnym repozytorium.

Ręczne wprowadzanie ustawień zdalnej głowicy dostarcza dobrych informacji na ten temat.

Edycja: podkreślenie: bez twojego polecenia, jedynym sposobem, w jaki by się „przesunął”, byłaby zmiana nazwy gałęzi master , która nie uważam za „organiczną”. Więc powiedziałbym, że organicznie się nie porusza.

eis
źródło
1
Nacisk na edycję nie jest tutaj całkowicie poprawny. Może się również zmienić, jeśli sklonujesz z kopii lokalnej, która nie znajduje się w gałęzi głównej.
mphair
Nie uważam klona za „ruszającego się”, ale myślę, że możemy się nie zgodzić :)
eis
24

Co porusza pochodzenie / GŁOWĘ „organicznie”?

  • git clone ustawia go raz w miejscu, w którym HEAD jest na początku
    • służy jako domyślna gałąź do wyewidencjonowania po sklonowaniu z git clone

Co oznacza HEAD on origin?

  • na samych repozytoriach (często repozytoria „na serwerach”) służy jako znacznik dla gałęzi domyślnej, ponieważ git cloneużywa go w taki sposób
  • w repozytoriach non-bare (lokalnych lub zdalnych) odzwierciedla bieżące pobranie repozytorium

Co ustawia pochodzenie / GŁOWA?

  • git clone pobiera i ustawia go
  • miałoby sens, gdyby git fetchzaktualizował je tak, jak inne odniesienia, ale tak nie jest
  • git remote set-head origin -a pobiera i ustawia go
    • przydatne do aktualizacji lokalnej wiedzy o tym, co zdalne uważa za „domyślną gałąź”

Drobnostki

  • origin/HEAD można również ustawić dowolną inną wartość bez kontaktowania się z pilotem: git remote set-head origin <branch>
    • Nie widzę żadnego zastosowania tego, z wyjątkiem testów
  • niestety nic nie jest w stanie ustawić HEAD na pilocie
  • starsze wersje gita nie wiedziały, na którą gałąź HEAD wskazuje na pilocie, tylko, który skrót zatwierdzenia ostatecznie ma: więc miejmy nadzieję, że wybrał nazwę gałęzi wskazującą na ten sam skrót
Robert Siemer
źródło
Straciłem odniesienie do, origin/HEADa twoje rozwiązanie pomogło. Dzięki!
java_dude
Nie zgadzam się z git fetchaktualizacją, ponieważ pozwala skonfigurować (lokalny) skrót. Cytując dokument: „Posiadanie domyślnej gałęzi dla pilota nie jest wymagane, ale pozwala na określenie nazwy pilota zamiast określonej gałęzi”. Byłoby dziwne, gdyby zdalna zmiana spowodowała zaktualizowanie lokalnie skonfigurowanych skrótów.
Micha Wiedenmann
@MichaWiedenmann Dlaczego miałby to być skrót skonfigurowany lokalnie? Lokalnie skonfigurowany skrót origin/HEADto zła nazwa. I że git cloneużywa zdalnej nazwy jako domyślnej dla „lokalnie skonfigurowanej gałęzi” również temu zaprzecza. W nie-gołych repozytoriach nie ma nawet sensu używanie prądu zdalnego HEAD.
Robert Siemer
10

Zastrzeżenie : to aktualizacja odpowiedzi Jefromi , którą piszę, aby zaoszczędzić trochę czasu ciekawskim.

Na próżno próbowałem odtworzyć (w Git 2.0.1) remote HEAD is ambiguouswiadomość, o której wspomina Jefromi w swojej odpowiedzi; więc trochę poszperałem (klonując https://github.com/git/git i przeszukując dziennik). Kiedyś tak było

Determining HEAD is ambiguous since it is done by comparing SHA1s.

In the case of multiple matches we return refs/heads/master if it
matches, else we return the first match we encounter. builtin-remote
needs all matches returned to it, so add a flag for it to request such.

(Commit 4229f1fa325870d6b24fe2a4c7d2ed5f14c6f771, z dnia 27 lutego 2009 r., Znaleziony razem z git log --reverse --grep="HEAD is ambiguous")

Jednak ta dwuznaczność została już zniesiona :

One long-standing flaw in the pack transfer protocol used by "git
clone" was that there was no way to tell the other end which branch
"HEAD" points at, and the receiving end needed to guess.  A new
capability has been defined in the pack protocol to convey this
information so that cloning from a repository with more than one
branches pointing at the same commit where the HEAD is at now
reliably sets the initial branch in the resulting repository.

(Commit 9196a2f8bd46d36a285bdfa03b4540ed3f01f671, datowany na 8 listopada 2013, znaleziony razem z git log --grep="ambiguous" --grep="HEAD" --all-match)

Edytuj (dzięki torek ):

$ git name-rev --name-only 9196a2f8bd46d36a285bdfa03b4540ed3f01f671
tags/v1.8.4.3~3

Oznacza to, że jeśli używasz Git w wersji 1.8.4.3 lub nowszej , nie powinieneś napotkać żadnego problemu z niejednoznacznym zdalnym HEAD.

jub0bs
źródło
1
Na podstawie tagów w źródle git ta poprawka dotyczy git w wersji 1.8.4.3 i nowszych.
torek
@RobertSiemer Nie jestem pewien, ale myślę, że tak.
jub0bs
8

Pamiętaj, że mówimy o dwóch niezależnych repozytoriach git. Twoje lokalne repozytorium z kodem i zdalnym uruchomionym gdzie indziej.

Masz rację, kiedy zmieniasz gałąź, HEAD wskazuje na Twoją obecną gałąź. Wszystko to dzieje się w lokalnym repozytorium Git. Nie zdalne repozytorium, które może być własnością innego programisty, lub umieszczenie na serwerze w twoim biurze, github, lub innym katalogu w systemie plików itp.

Twój komputer (lokalne repozytorium) nie ma żadnego interesu w zmianie wskaźnika HEAD na zdalnym repozytorium git. Może być na przykład własnością innego programisty.

Jeszcze jedno, to, co twój komputer nazywa origin / XXX, to zrozumienie przez komputer stanu pilota w momencie ostatniego pobrania.

Więc co „organicznie” zaktualizowałoby pochodzenie / HEAD? Byłaby to aktywność na zdalnym repozytorium git. Nie twoje lokalne repozytorium.

Ludzie wspominali

git symbolic-ref HEAD refs / head / my_other_branch

Zwykle jest to używane, gdy na serwerze znajduje się udostępnione centralne repozytorium git do użytku przez zespół programistów. Byłoby to polecenie wykonane na komputerze zdalnym. Możesz to zobaczyć jako aktywność w zdalnym repozytorium git.

Pablo Maurin
źródło
1
Przepraszam, jeśli trochę się powtarzam. Chcę tylko zwrócić uwagę na fakt, że git jest rozproszonym systemem kontroli wersji i jako takie dwa repozytoria są niezależne.
Pablo Maurin
3

Uruchom następujące polecenia z git CLI:

# move to the wanted commit
git reset --hard <commit-hash> 

# update remote
git push --force origin <branch-name> 
Yakir GIladi Edry
źródło
1
Świetnie, to mi pomogło!
Shay Zambrovski,