Używam poddrzewa Git z kilkoma projektami, nad którymi pracuję, aby udostępnić między nimi kod podstawowy. Kod podstawowy jest często aktualizowany, a aktualizacje mogą mieć miejsce w każdym z projektów, ostatecznie wszystkie z nich zostaną zaktualizowane.
Napotkałem problem polegający na tym, że git zgłasza, że moje poddrzewo jest aktualne, ale wypychanie zostaje odrzucone. Na przykład:
#! git subtree pull --prefix=public/shared project-shared master
From github.com:****
* branch master -> FETCH_HEAD
Already up-to-date.
Jeśli nacisnę, powinienem otrzymać wiadomość, że nie ma co naciskać ... Tak? DOBRZE? :(
#! git subtree push --prefix=public/shared project-shared master
git push using: project-shared master
To [email protected]:***
! [rejected] 72a6157733c4e0bf22f72b443e4ad3be0bc555ce -> master (non-fast-forward)
error: failed to push some refs to '[email protected]:***'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Co mogłoby być tego przyczyną? Dlaczego pchanie zawodzi?
git
git-subtree
mateusz
źródło
źródło
--rejoin
do przyspieszania wypychania poddrzewa. Kiedy ręcznie przechodzę przez wypychanie poddrzewa, działającsubtree split --rejoin
, podzielona gałąź poddrzewa ma tylko historię z powrotem do ostatniego połączenia, kiedy zwykle zawiera całą historię poddrzewa. Dla mnie jest to bezpośrednia przyczyna błędu braku przewijania do przodu. Nadal nie jestem pewien, dlaczego podział poddrzewa generuje skróconą historię.Odpowiedzi:
Znalazłem odpowiedź w tym komentarzu na blogu https://coderwall.com/p/ssxp5q
źródło
error: unknown option 'prefix'
heroku
i jakipythonapp
mam w odpowiedzi. Tłumaczenie tego z języka specyficznego dlagit push <your subtree's origin> `git subtree split --prefix=Path/to/subtree master`:master --force
W systemie Windows zagnieżdżone polecenie nie działa:
Możesz po prostu najpierw uruchomić zagnieżdżony bit:
To (po wielu liczbach) zwróci token, np
Użyj tego w poleceniu zawierającym, np:
źródło
git subtree
nie jest to polecenie. Po użyciu twojego rozwiązania udało mi się wdrożyć folder na heroku zamiast całego mojego repozytoriumUżyj
--onto
flagi:[EDYCJA: niestety
subtree push
nie przesyła dalej--onto
do bazowegosplit
, więc operację należy wykonać w dwóch poleceniach! Po wykonaniu tej czynności widzę, że moje polecenia są identyczne z tymi w jednej z pozostałych odpowiedzi, ale wyjaśnienie jest inne, więc i tak zostawię je tutaj.]Lub jeśli nie używasz basha:
Spędziłem godziny, przeglądając źródło poddrzewa git, aby znaleźć to rozwiązanie, więc mam nadzieję, że to docenisz;)
subtree push
zaczyna się od uruchomieniasubtree split
, które przepisuje historię zmian do formatu, który powinien być gotowy do wysłania. Sposób, w jaki to robi, polega na odcięciupublic/shared/
początku każdej ścieżki, która go zawiera, i usunięciu wszelkich informacji o plikach, które go nie mają. Oznacza to, że nawet jeśli wyciągniesz niezgniecione, wszystkie zatwierdzenia z repozytorium wyższego szczebla zostaną zignorowane, ponieważ nazywają pliki według ich gołych ścieżek. (Zatwierdzenia, które nie dotykają żadnych plików wpublic/shared/
lub zatwierdzenia scalające, które są identyczne z rodzicami, również są zwinięte. [EDYCJA: Poza tym, od tamtej pory znalazłem wykrywanie squasha, więc teraz myślę, że to tylko wtedy, gdy wyciągnąłeś niezgnieciony, a następnie uproszczone zwijanie zatwierdzenia scalającego opisane w kolejnej odpowiedzi pozwala wybrać niezgniecioną ścieżkę i odrzucić zgniecioną ścieżkę.]) Rezultat jest taki, że rzeczy, które próbuje wypchnąć, kończą się zawieraniem pracy, którą ktoś poświęcił na bieżące repozytorium hosta, z którego wypychasz, ale nie pracy osób zaangażowanych bezpośrednio do repozytorium podrzędnego lub za pośrednictwem innego hosta magazyn.Jeśli jednak użyjesz
--onto
, wszystkie zatwierdzone zmiany są rejestrowane jako OK, aby używać ich dosłownie, więc gdy proces przepisywania napotka je jako jeden z rodziców scalania, chce je przepisać, zachowa je zamiast próbować je przepisać w zwykły sposób.źródło
git remote -v
.--onto
opcja pomaga gitowi zidentyfikować zatwierdzenia, które są już w repozytorium podrzędnym.W przypadku aplikacji typu „Strony GitHub”, w której wdrażasz poddrzewo „dist” w gałęzi gh-pages, rozwiązanie może wyglądać mniej więcej tak
Wspominam o tym, ponieważ wygląda to nieco inaczej niż przykłady heroku podane powyżej. Widzisz, że mój folder „dist” istnieje w głównej gałęzi mojego repozytorium, a następnie przesyłam go jako poddrzewo do gałęzi gh-pages, która również znajduje się w źródle.
źródło
Z tym problemem spotkałem się już wcześniej i oto jak go rozwiązałem.
Dowiedziałem się, że mam oddział, który nie był dołączony do lokalnego oddziału głównego. Ta gałąź istnieje i po prostu wisi w próżni. W twoim przypadku prawdopodobnie nazywa się
project-shared
. Zakładając, że tak jest i kiedy robisz agit branch
, możesz zobaczyć lokalnyproject-shared
oddział, możesz `` dołączyć '' nowe zatwierdzenia do istniejącegoproject-shared
oddziału, wykonując:git subtree split --prefix=public/shared --onto public-shared --branch public-shared
Zrozumiałem,
git subtree
że zacznę tworzenie nowego oddziału--onto
, w tym przypadku jest topublic-shared
oddział lokalny . Wówczas gałąź oznacza utworzenie gałęzi, która po prostu zastępuje starąpublic-shared
gałąź.Pozwoli to zachować wszystkie poprzednie SHA
public-shared
gałęzi. Wreszcie możesz zrobićgit push project-shared project-shared:master
Zakładając, że masz również
project-shared
pilota; spowoduje to przesunięcie lokalnego wiszącego w pustejproject-shared
gałęzi domaster
gałęzi pilotaproject-shared
.źródło
Wynika to z ograniczeń oryginalnego algorytmu. Podczas obsługi zatwierdzeń scalających oryginalny algorytm używa uproszczonych kryteriów odcinania niepowiązanych rodziców. W szczególności sprawdza, czy istnieje rodzic, który ma to samo drzewo. Gdyby taki rodzic znalazł, zwinąłby zatwierdzenie scalające i zamiast tego użyłby zatwierdzenia rodzica, zakładając, że inni rodzice mają zmiany niezwiązane z poddrzewem. W niektórych przypadkach spowodowałoby to porzucenie części historii, która ma rzeczywiste zmiany w poddrzewie. W szczególności porzuciłby sekwencje zatwierdzeń, które dotknęłyby poddrzewa, ale skutkowałyby tą samą wartością poddrzewa.
Zobaczmy przykład (który możesz łatwo odtworzyć), aby lepiej zrozumieć, jak to działa. Weź pod uwagę następującą historię (format linii to: zatwierdzenie [drzewo] temat):
W tym przykładzie dzielimy się dalej
dir
. ZatwierdzaD
iE
ma to samo drzewoz
, ponieważ mamy zatwierdzenieC
, które cofnęło zatwierdzenieB
, więcB-C
sekwencja nie robi nic,dir
mimo że ma w niej zmiany.Teraz zróbmy podział. Najpierw podzieliliśmy się po zatwierdzeniu
C
.Następnie podzieliliśmy się po zatwierdzeniu
E
.Tak, straciliśmy dwa zatwierdzenia. Powoduje to błąd podczas próby wypchnięcia drugiego podziału, ponieważ nie ma on tych dwóch zatwierdzeń, które już dotarły do źródła.
Zwykle możesz tolerować ten błąd używając
push --force
, ponieważ porzucone zatwierdzenia generalnie nie zawierają krytycznych informacji. Na dłuższą metę błąd musi zostać naprawiony, więc historia splitu faktycznie zawierałaby wszystkie zatwierdzenia, które dotykajądir
, zgodnie z oczekiwaniami. Spodziewałbym się, że poprawka obejmie głębszą analizę zatwierdzeń rodzica dla ukrytych zależności.Dla odniesienia, oto część oryginalnego kodu odpowiedzialna za zachowanie.
copy_or_skip() ... for parent in $newparents; do ptree=$(toptree_for_commit $parent) || exit $? [ -z "$ptree" ] && continue if [ "$ptree" = "$tree" ]; then # an identical parent could be used in place of this rev. identical="$parent" else nonidentical="$parent" fi ... if [ -n "$identical" ]; then echo $identical else copy_commit $rev $tree "$p" || exit $? fi
źródło
Odpowiedź Erica Woodruffa mi nie pomogła, ale następujące:
Zwykle używam opcji „git subtree pull” z opcją „--squash”. Wygląda na to, że utrudniło to pogodzenie sprawy, więc musiałem tym razem wyciągnąć poddrzewo bez zgniatania, rozwiązać niektóre konflikty, a następnie naciskać.
Muszę dodać, że zgniecione szarpnięcie nie ujawniło żadnych konfliktów, powiedziało mi, że wszystko w porządku.
źródło
Innym [prostszym] rozwiązaniem jest przesunięcie głowy pilota poprzez wykonanie kolejnego zatwierdzenia, jeśli możesz. Po wciągnięciu tej zaawansowanej głowy do lokalnego poddrzewa będziesz mógł ponownie z niej wypchnąć.
źródło
Możesz wymusić wypychanie lokalnych zmian do zdalnego repozytorium poddrzewa
źródło
Szybka powłoka PowerShell dla użytkowników systemu Windows oparta na rozwiązaniu Chrisa Jordana
źródło
Oto, co napisałem na podstawie tego, co powiedział @entheh.
źródło
Miałem też ten problem. Oto, co zrobiłem na podstawie najlepszych odpowiedzi:
Dany:
Wpisz to:
Zwróć uwagę, że token wyprowadzany przez „git subtree push” jest używany w „git push”.
źródło