Myślę, że Twoim podstawowym problemem jest to, że źle interpretujesz i / lub nie rozumiesz, co robi git i dlaczego to robi.
Kiedy klonujesz inne repozytorium, git tworzy kopię tego, co jest „tam”. Bierze ona także „ich” oddział etykiety, takie jak master
, i tworzy kopię tej etykiecie którego „imię i nazwisko” w swoim drzewie git jest (zazwyczaj) remotes/origin/master
(ale w twoim przypadku remotes/upstream/master
). W większości przypadków możesz również pominąć remotes/
część, więc możesz odnieść się do tej oryginalnej kopii jako upstream/master
.
Jeśli teraz dokonasz i zatwierdzisz jakieś zmiany w jakimś pliku (plikach), jesteś jedyną osobą z tymi zmianami. W międzyczasie inne osoby mogą używać oryginalnego repozytorium (z którego utworzyłeś swój klon), aby tworzyć inne klony i zmieniać te klony. Oczywiście tylko oni mają swoje zmiany. Ostatecznie jednak ktoś może mieć zmiany, które odsyła do pierwotnego właściciela (przez „wypychanie”, poprawki lub cokolwiek innego).
git pull
Komenda jest przeważnie tylko skrótem git fetch
następuje git merge
. Jest to ważne, ponieważ oznacza, że musisz zrozumieć, co faktycznie robią te dwie operacje.
git fetch
Komenda mówi wrócić do gdziekolwiek sklonowany z (lub inaczej skonfigurować jako miejsce do pobrania z) i znaleźć „nowe rzeczy ktoś jeszcze dodane lub zmienione lub usunięte”. Te zmiany są kopiowane i stosowane do kopii tego, co otrzymałeś wcześniej . Są one nie stosuje się do swojej pracy, tylko do nich.
git merge
Polecenie jest bardziej skomplikowane i gdzie idziesz krzywo. To, co robi, nieco uproszczone, to porównanie „tego, co zmieniłeś w swojej kopii”, z „zmianami, które pobrałeś od kogoś innego, a tym samym dodano do Twojej kopii-cudzej-pracy”. Jeśli twoje zmiany i ich zmiany nie wydają się ze sobą kolidować, merge
operacja łączy je razem i daje ci "zobowiązanie scalające", które wiąże twój rozwój i ich rozwój razem (chociaż istnieje bardzo powszechny "łatwy" przypadek, w którym nie masz zmienia się i pojawia się „szybkie przewijanie do przodu”).
Sytuacja, z którą się teraz spotykasz, to taka, w której dokonałeś zmian i zobowiązałeś się do ich wykonania - w rzeczywistości dziewięć razy, stąd „naprzód 9” - i nie dokonali żadnych zmian. Więc fetch
posłusznie nic nie pobiera, a potem merge
bierze ich brak zmian i również nic nie robi.
To, czego chcesz, to przyjrzeć się, a może nawet „zresetować”, „ich” wersję kodu.
Jeśli chcesz tylko na to spojrzeć, możesz po prostu sprawdzić tę wersję:
git checkout upstream/master
To mówi gitowi, że chcesz przenieść bieżący katalog do gałęzi, której pełna nazwa to faktycznie remotes/upstream/master
. Zobaczysz ich kod od czasu ostatniego uruchomienia git fetch
i uzyskania najnowszego kodu.
Jeśli chcesz zrezygnować ze wszystkich własnych zmian, to co musisz zrobić, to zmienić pomysł gita na to, którą wersję master
powinna nazwać Twoja etykieta . Obecnie nazywa twoje ostatnie zatwierdzenie. Jeśli wrócisz do tej gałęzi:
git checkout master
to git reset
polecenie pozwoli ci „przenieść etykietę”, tak jak było. Jedynym pozostałym problemem (zakładając, że naprawdę jesteś gotowy porzucić wszystko, co zrobiłeś) jest znalezienie miejsca, w którym powinna wskazywać etykieta.
git log
pozwoli ci znaleźć nazwy numeryczne - takie jak 7cfcb29
- które są trwałe (nigdy się nie zmieniają), i istnieje absurdalna liczba innych sposobów ich nazwania, ale w tym przypadku potrzebujesz tylko nazwy upstream/master
.
Aby przenieść etykietę, wycierając swoje własne zmiany (dowolny, które zostały popełnione w rzeczywistości odzyskania przez jakiś czas, ale jest to o wiele trudniejsze po to więc być bardzo pewny):
git reset --hard upstream/master
--hard
Opowiada git wymazać tego, co robiłeś, przesunąć bieżącą etykietę gałęzi, a następnie sprawdzić dany popełnić.
To nie jest zbyt częste, aby naprawdę chcieć git reset --hard
i zniszczyć mnóstwo pracy. Bezpieczniejszą metodą (co znacznie ułatwia odzyskanie tej pracy, jeśli zdecydujesz, że część z nich była jednak warta zachodu) jest zmiana nazwy istniejącej gałęzi:
git branch -m master bunchofhacks
a następnie utwórz nową lokalną gałąź o nazwie master
„ścieżki” (nie podoba mi się ten termin, ponieważ wydaje mi się, że dezorientuje ludzi, ale to jest termin git :-)) wzorzec pochodzenia (lub nadrzędnego):
git branch -t master upstream/master
z którym możesz się potem zabrać:
git checkout master
To, co robią ostatnie trzy polecenia (są skróty, które sprawiają, że są to tylko dwa polecenia), to zmiana nazwy wklejonej na istniejącej etykiecie, a następnie utworzenie nowej etykiety, a następnie przełączenie się na nią:
zanim cokolwiek zrobisz:
C0 - "remotes/upstream/master"
\
\- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9 "master"
po git branch -m
:
C0 - "remotes/upstream/master"
\
\- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9 "bunchofhacks"
po git branch -t master upstream/master
:
C0 - "remotes/upstream/master", "master"
\
\- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9 "bunchofhacks"
Oto C0
najnowsze zatwierdzenie (pełne drzewo źródeł), które otrzymałeś, kiedy po raz pierwszy wykonałeś swoje git clone
. Twoje zatwierdzenia od C1 do C9.
Zwróć uwagę, że gdybyś to zrobił, git checkout bunchofhacks
a git reset --hard HEAD^^
to zmieniłoby ostatnie zdjęcie na:
C0 - "remotes/upstream/master", "master"
\
\- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 - "bunchofhacks"
\
\- C8 --- C9
Powodem jest to, że HEAD^^
nazywa wersję drugą w górę od nagłówka bieżącej gałęzi (która byłaby tuż przed resetowaniem bunchofhacks
), a reset --hard
następnie przenosi etykietę. Commity C8 i C9 są teraz w większości niewidoczne (możesz użyć takich rzeczy jak reflog i git fsck
je znaleźć, ale nie jest to już trywialne). Twoje etykiety mogą się poruszać, jak chcesz. fetch
Komenda dba o tych, które zaczynają remotes/
. Konwencjonalne jest dopasowanie „twoje” do „ich” (więc jeśli oni mają remotes/origin/mauve
, nazwałbyś mauve
też swoje ), ale możesz wpisać „ich”, kiedy chcesz nazwać / zobaczyć zmiany, które otrzymałeś „od nich”. (Pamiętaj, że „jedno zatwierdzenie” to całe drzewo źródłowe. Możesz wybrać jeden konkretny plik z jednego zatwierdzenia, git show
na przykład