Jak zmusić git pull do zastąpienia wszystkiego przy każdym ściągnięciu?

203

Mam CENTRALNE repozytorium z trzema repozytoriami deweloperów, które normalnie go pobierają i wypychają.

Mam również dwa inne repozytoria, które pobierają z CENTRAL-ego repozytorium: jedno jest serwerem na żywo, a drugie serwerem testowym / etapowym - każde pobiera z własnej gałęzi.

Scenariusz jest następujący: mam post-updateskrypt przechwytujący na repozytorium CENTRAL, który automatycznie uzyskuje dostęp do repozytoriów testowych i na żywo i uruchamia polecenie pull na każdym z nich. To aktualizuje zarówno serwery testowe, jak i aktywne, wszystko w zależności od tego, który oddział ma nowe zatwierdzenia. To wszystko działa świetnie.

Problem polega na tym, że mogą wystąpić sytuacje, w których pliki mogą być aktualizowane bezpośrednio na serwerze (przez ftp lub cokolwiek innego), a skrypt CENTRAL po aktualizacji zawiedzie, ponieważ wystąpią konflikty scalania / nadpisywania. Nie da się uniknąć tego scenariusza i jest to nieuniknione.

Chciałbym, aby tak się stało: chcę, aby ściąganie z witryn na żywo i testowych zawsze nadpisywało / scalało podczas ściągania. Zawsze. Te repozytoria będą dostępne tylko w wersji „pull”, ponieważ nie są przeznaczone do opracowywania.

We wszystkich moich badaniach nie mogę znaleźć dobrego rozwiązania, aby ciąg zawsze wymuszał zastąpienie plików lokalnych. Czy to w ogóle możliwe? Jeśli tak, byłby to świetny scenariusz rozwoju.

bmilesp
źródło
1
Chociaż głosowałem za odpowiedzią „zresetuj to, co właśnie ściągnąłeś” poniżej, myślę, że rozwiązaniem twojego prawdziwego problemu jest nie wprowadzanie zmian poza pasmem. Modyfikacje, bez względu na to, jak pilne, powinny zawsze przechodzić kontrolę wersji. Nikt oprócz operatorów nie powinien mieć bezpośredniego dostępu do działających witryn (np. Nie programistów). Konsekwentne stosowanie kontroli wersji oznacza, że ​​masz zapis, kiedy wprowadzono zmiany, kto je wprowadził, oraz lepsze narzędzia do pracy z nimi. Po co go obalać, bez żadnej realnej korzyści?
Phil Miller,
1
@Novelocrat racja, rozumiem co mówisz. Niestety istnieje wiele scenariuszy, w których ktoś może przesłać plik bezpośrednio na serwer. W takim przypadku musiałbym uruchomić szereg poleceń, aby ponownie zsynchronizować repozytorium. Wcześniej używaliśmy skryptu FTP do przenoszenia plików z repozytorium na serwer. Powyższa metoda po prostu wyeliminowałaby krok FTP, który w przeszłości działał bardzo dobrze.
bmilesp
3
Nie pozwól więc, aby ludzie mieli bezpośredni dostęp do serwera. Zablokuj dostęp FTP i SSH lub powiedz, że zostaną zwolnieni za wprowadzanie niemożliwych do rozliczenia zmian. Pozwolenie na kontynuowanie tego rodzaju ćwiczeń tylko na dłuższą metę boli ciebie i twoją drużynę.
Phil Miller,

Odpowiedzi:

510

Naprawdę idealnym sposobem na to jest w ogóle nie używanie pull, ale zamiast tego fetchi reset:

git fetch origin master
git reset --hard FETCH_HEAD
git clean -df

(Zmiana masterna gałąź, którą chcesz śledzić.)

pull jest zaprojektowany wokół łączenia w pewien sposób zmian, podczas gdy reset po prostu dopasować lokalną kopię do określonego zatwierdzenia.

Możesz rozważyć nieco inne opcje w cleanzależności od potrzeb twojego systemu.

Bursztyn
źródło
3
@ user730569 reset --hard to polecenie, które służy do wymuszenia stanu katalogu roboczego (i bieżącej gałęzi) do stanu pasującego do stanu określonego zatwierdzenia.
Amber
25
FETCH_HEADjest referencją, która jest automatycznie tworzona przez w fetchcelu reprezentowania pobranego ref. Nie jest scalony, po prostu nadpisywany przy każdym pobieraniu. cleanto polecenie, które usuwa pliki, które nie są śledzone git, -dfflagi nakazują usunąć katalogi ( -d) i faktycznie usunąć ( -f).
Amber
4
dlaczego nie ma tego słowa kluczowego? Potrzebuję tego znacznie częściej niż ciągnąć.
Wolfgang Fahl
14
Możesz użyć git clean -dnprzed użyciem, git clean -dfaby zobaczyć, które pliki / foldery zostaną usunięte. git clean -dfmożna cofnąć tylko, jeśli miałeś kopię zapasową
Ibrahim Lawal
1
@NickMiddleweek Martwiłem się, git clean -dfże usunę również pliki gitignored, ale okazuje się, że nie. git clean --helpmówi „Zwykle usuwane są tylko pliki nieznane Gitowi, ale jeśli podano opcję -x, usuwane są również pliki ignorowane. Może to na przykład być przydatne do usunięcia wszystkich produktów kompilacji”.
nickang
6

Nie jestem pewien, jak to zrobić za pomocą jednego polecenia, ale możesz zrobić coś takiego:

git reset --hard
git pull

lub nawet

git stash
git pull
Matt Wolfe
źródło
Aby uruchomić w jednym poleceniem: git reset --hard && git pull. Alternatywnie, ale nie lepiej git reset --hard; git pull. Użycie &&spowoduje uruchomienie drugiego polecenia tylko wtedy, gdy pierwsze polecenie zakończyło się powodzeniem. ;uruchomi go niezależnie od kodu wyjścia pierwszego polecenia.
mazunki
5

Aby pobrać kopię gałęzi i wymusić zastąpienie plików lokalnych od źródła:

git reset --hard origin/current_branch

Cała bieżąca praca zostanie utracona, a wtedy będzie taka sama jak gałąź początkowa

Andrew Atkinson
źródło
5
git reset --hard HEAD
git fetch --all
git reset --hard origin/your_branch
Dzmitry
źródło
2

Możesz zmienić zaczep, aby wyczyścić wszystko w czystości.

# Danger! Wipes local data!

# Remove all local changes to tracked files
git reset --hard HEAD

# Remove all untracked files and directories
git clean -dfx

git pull ...
Dietrich Epp
źródło
2
co robi x? proszę wyjaśnić przełączniki
Steve K
2
Myślę, że x ma usunąć wszystkie nieśledzone pliki. Trudno powiedzieć na stronie podręcznika, dlatego mamy SO.
JosephK
2
@JosephK: To nieprawda. Podstawowym celem git cleanjest już „Usuń nieśledzone pliki z drzewa roboczego” (u góry strony). Zwykle nie obejmuje to plików ignorowanych, ale -xnakazuje git cleantakże dołączanie plików ignorowanych (z wyjątkiem tego, że nie wpływa to na pliki ignorowane przez -eopcję).
Dietrich Epp
2

Jeśli nie zatwierdziłeś jeszcze zmian lokalnych od czasu ostatniego pobrania / klonowania, możesz użyć:

git checkout *
git pull

checkoutusunie twoje lokalne zmiany przy ostatnim zatwierdzeniu lokalnym i pullsinkronizuje je do zdalnego repozytorium

Maviles
źródło