Dlaczego Git mówi, że moja gałąź główna jest „już aktualna”, mimo że tak nie jest?

118

Podstawowy problem

Właśnie usunąłem CAŁY kod z pliku w moim projekcie i zatwierdziłem zmianę w moim lokalnym gicie (celowo). Zrobiłem

git pull upstream master

aby pobrać i scalić z upstream (więc teoretycznie ten usunięty kod powinien wrócić).

Git mówi mi, że wszystko jest aktualne.

Wszystko zdecydowanie NIE jest aktualne - cały ten usunięty kod jest nadal usuwany.

Inne istotne informacje

Mam tylko jedną gałąź zwaną „master”.

Niedawno skonfigurowałem „master”, aby śledzić nadawanie w następujący sposób:

Branch master skonfigurowany do śledzenia zdalnego branch mastera z upstream.

Polecenie git branch -vvdaje:

* master 7cfcb29 [upstream/master: ahead 9] deletion test

Dlaczego dlaczego tak się dzieje? Jestem bliski wysłania e-mailem do mojego kierownika projektu wszelkich zmian, które wprowadzę w naszym kodzie.

Aktualizacja

Myślałem, że to oczywiste, ale taki jest mój cel:

Pobierz najnowszy kod w moim systemie.

Przepraszam za moją złość, ale dlaczego tak proste zadanie musi być takie trudne?

user1971506
źródło
1
Jest oczywiste, że jeśli usuniesz źródło, spróbuj wyciągnąć za pomocą prostego „wyciągnięcia”, że git nie nadpisuje twoich lokalnych zmian (w tym przypadku twoich usunięć) bez upewnienia się, że naprawdę chcesz nadpisać lokalne zmiany. Pierwsza odpowiedź wydaje się dokładnie wyjaśniać, jak możesz się do tego zabrać.
CashCow

Odpowiedzi:

209

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 pullKomenda jest przeważnie tylko skrótem git fetchnastępuje git merge. Jest to ważne, ponieważ oznacza, że ​​musisz zrozumieć, co faktycznie robią te dwie operacje.

git fetchKomenda 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 mergePolecenie 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ć, mergeoperacja łą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 fetchposłusznie nic nie pobiera, a potem mergebierze 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 fetchi 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ę masterpowinna nazwać Twoja etykieta . Obecnie nazywa twoje ostatnie zatwierdzenie. Jeśli wrócisz do tej gałęzi:

git checkout master

to git resetpolecenie 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 logpozwoli 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

--hardOpowiada 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 --hardi 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 C0najnowsze 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 bunchofhacksa 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 --hardnastępnie przenosi etykietę. Commity C8 i C9 są teraz w większości niewidoczne (możesz użyć takich rzeczy jak reflog i git fsckje znaleźć, ale nie jest to już trywialne). Twoje etykiety mogą się poruszać, jak chcesz. fetchKomenda dba o tych, które zaczynają remotes/. Konwencjonalne jest dopasowanie „twoje” do „ich” (więc jeśli oni mają remotes/origin/mauve, nazwałbyś mauveteż 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 showna przykład

torek
źródło
12
Wiele się nauczyłem z twojej doskonałej odpowiedzi. Ale nadal nie wiem, dlaczego otrzymuję komunikat o statusie git: „Twoja gałąź jest aktualna z 'origin / master'”, kiedy repozytorium upstream jest kilka zatwierdzeń przed moim obecnym repozytorium. Mogę być na bieżąco z git pull, ale skąd mam wiedzieć, że muszę to zrobić, jeśli komunikat mówi, że jestem na bieżąco?
Christopher Werby
@ChristopherWerby: brzmi to tak, jakbyś działał git mergejako polecenie wiersza poleceń (co robię sam, to rozsądna metoda). Zwróć jednak uwagę, że git pullzaczyna się to od pierwszego uruchomienia git fetch, a następnie uruchomienia git merge(lub git rebasejeśli zamiast tego powiesz mu, aby to zrobił). Jest to krok pobierania, który faktycznie przenosi nowe zatwierdzenia do scalenia (lub tylko do zmiany bazy).
torek
@torek Czy jest jakieś polecenie inne niż git status, którego mogę użyć, aby sprawdzić, czy repozytorium nadrzędne wyprzedza moje obecne repozytorium? Komunikat, który otrzymuję git status, mówiący, że „Twoja gałąź jest aktualna pod względem„ pochodzenia / wzorca ””, myli mnie, myśląc, że mam najnowsze zmiany, podczas gdy nie mam. Czasami dostaję komunikat, który mówi coś w rodzaju „origin / master to 5 commits before your branch” (parafrazując). Ale to nie jest spójne.
Christopher Werby
1
To wciąż nie git statuswyjaśnia, dlaczego mówi "Twoja gałąź jest aktualna", gdy natychmiast git fetchpotem ściąga ponad sto obiektów i rozwiązuje prawie sto delt, wymienia kilka nowych gałęzi i kilka nowych tagów i zmienia główny (zdalny tracking), zatwierdzenie nagłówka gałęzi - a potem kolejny status gita wesoło i nieszczerze, wciąż mówi „Twoja gałąź jest aktualna”. Najwyraźniej wiele spadło z pochodzenia, ale branża była „na bieżąco z pochodzeniem” zarówno przed, jak i po?
NeilG,
1
git pulluruchamia się wtedy jako git fetchpierwsza git merge(lub inne wybrane polecenie). git fetchKrok aktualizuje swojej pamięci git dotyczącą ich stanu git'S, wywołując ich Git i uzyskanie od nich czegoś nowego. Twój git statustylko sprawdza pamięci git za ich Git.
torek
18

Miałem ten sam problem co Ty.

Zrobiłem to git status git fetch git pull, ale moja gałąź wciąż była w tyle. Miałem foldery i pliki przesłane do zdalnego komputera i widziałem pliki w Internecie, ale w moim lokalnym ich brakowało.

Na koniec te polecenia zaktualizowały wszystkie pliki i foldery w moim lokalnym:

git fetch --all
git reset --hard origin/master 

lub jeśli chcesz oddział

git checkout your_branch_name_here
git reset --hard origin/your_branch_name_here
jturi
źródło
1
dzięki! to faktycznie zadziałało. Pamiętaj, że nazwy gałęzi uwzględniają wielkość liter!
André Ramon
4

Wszelkie zatwierdzone zmiany, takie jak usunięcie wszystkich plików projektu, będą nadal obowiązywać po ściągnięciu. Wszystko, co robi pull, to scalenie najnowszych zmian z innego miejsca do własnej gałęzi, a jeśli twoja gałąź usunęła wszystko, to w najlepszym przypadku wystąpią konflikty scalania, gdy zmiany zewnętrzne wpłyną na pliki, które usunąłeś. Krótko mówiąc, tak, wszystko jest aktualne.

Jeśli opiszesz, jaki wynik chciałbyś, aby zamiast „wszystkie pliki zostały usunięte”, może ktoś zasugeruje odpowiednie postępowanie.

Aktualizacja:

POBIERZ NAJNOWSZY KOD W MOIM SYSTEMIE

Wydaje się, że nie rozumiesz, że masz już najnowszy kod, który należy do Ciebie. Jeśli naprawdę chcesz zobaczyć najnowszą pracę innej osoby znajdującą się w gałęzi głównej, po prostu zrób:

git fetch upstream
git checkout upstream/master

Należy pamiętać, że nie pozostawi to możliwości natychmiastowego (ponownego) rozpoczęcia własnej pracy. Jeśli chcesz wiedzieć, jak cofnąć coś, co zrobiłeś lub w inny sposób cofnąć zmiany wprowadzone przez Ciebie lub kogoś innego, podaj szczegóły. Zastanów się również nad tym, do czego służy kontrola wersji, ponieważ wydaje się, że nie rozumiesz jej podstawowego celu.

Ryan Stewart
źródło
W rzeczywistości chcę mieć najnowszą wersję kodu innej osoby w moim systemie. Jednak te dwie komendy tego nie zrobiły. Wszystko, co otrzymuję, to „już na gałęzi master”. Kod w moich plikach nie odzwierciedla kodu drugiej osoby.
user1971506
Przepraszam, powinienem upstream/master. Zaktualizowałem moją odpowiedź.
Ryan Stewart
3

Jak mówią inni plakaty, pull scala zmiany z górnego źródła do repozytorium. Jeśli chcesz zastąpić to, co jest w twoim repozytorium, tym, co jest w źródle, masz kilka opcji. Bez mankietu, pójdę z

git checkout HEAD^1  # Get off your repo's master.. doesn't matter where you go, so just go back one commit
git branch -d master  # Delete your repo's master branch
git checkout -t upstream/master  # Check out upstream's master into a local tracking branch of the same name
Paweł
źródło
1

Najlepsza odpowiedź jest znacznie lepsza pod względem zakresu i szczegółowości podanych informacji, ale wydaje się, że gdybyś chciał rozwiązać swój problem niemal natychmiast i nie przeszkadzało ci sięganie po niektóre z podstawowych zasad kontroli wersji, możesz ...

  1. Przełącz na master

    $ git checkout upstream master
    
  2. Usuń niechcianą gałąź. (Uwaga: musi mieć opcję -D, zamiast zwykłej flagi -d, ponieważ twoja gałąź ma wiele zatwierdzeń przed masterem.)

    $ git branch -d <branch_name>
    
  3. Utwórz nowy oddział

    $ git checkout -b <new_branch_name>
    
Bracie Donkey
źródło
1

Chociaż żadna z tych odpowiedzi nie zadziałała dla mnie, udało mi się rozwiązać problem za pomocą następującego polecenia.

git fetch origin

To dla mnie sztuczka.

Doctiger
źródło
0

Przypominamy, jeśli masz pliki lokalnie, które nie są jeszcze w github i swój git statusmówi

Twój oddział jest aktualny pod względem „pochodzenia / mistrza”. nic do popełnienia, czyste drzewo robocze

Może się to zdarzyć, jeśli pliki są w formacie .gitignore

Spróbuj biegać

cat .gitignore 

i sprawdzanie, czy te pliki się tam pojawiają. To by wyjaśniało, dlaczego git nie chce ich przenosić na pilota.

stevec
źródło