Git - różnica między „zakładaniem niezmienionym” a „pomijaniem”

450

Mam lokalne zmiany w pliku, których nie chcę zatwierdzać w moim repozytorium. Jest to plik konfiguracyjny do budowy aplikacji na serwerze, ale chcę budować lokalnie z różnymi ustawieniami. Oczywiście plik zawsze pojawia się, gdy robię „status git” jako coś, co można inscenizować. Chciałbym ukryć tę konkretną zmianę i jej nie zatwierdzać. Nie wprowadzę żadnych innych zmian w pliku.

Po krótkich poszukiwaniach widzę 2 opcje: „zakładaj bez zmian” i „pomiń”. Poprzednie pytanie tutaj mówi o nich, ale tak naprawdę nie wyjaśnia ich różnic. Moje pytanie brzmi: czym różnią się te dwa polecenia? Dlaczego ktoś miałby korzystać z jednego lub drugiego?

ckb
źródło
1
Zwykle używam .gitignoredo podobnych celów. Czy to rozwiązanie działałoby dla Ciebie?
samuil
45
samuil, .gitignore ignoruje dodawanie, a nie zmianę. Gdy plik jest już w git, będzie śledzony, jeśli jest wymieniony w .gitignore
Grigory,
ale czy nie można usunąć wszystkich i dodać wszystkich, aby „odświeżyć”, jak wyjaśniono tutaj? stackoverflow.com/questions/7075923/… @Grigory
Daniel Springer
2
Plik nie powinien być ignorowany, jeśli poprawnie otrzymam zamiar OP. Plik musi znajdować się w repozytorium, ale te bardzo specyficzne zmiany, które wprowadził, nie powinny zostać zatwierdzone - przynajmniej nie teraz.
Simone

Odpowiedzi:

666

Chcesz skip-worktree.

assume-unchangedjest przeznaczony do przypadków, w których sprawdzenie, czy grupa plików została zmodyfikowana, jest kosztowne; po ustawieniu bitu git(oczywiście) zakłada się, że pliki odpowiadające tej części indeksu nie zostały zmodyfikowane w kopii roboczej. Pozwala to uniknąć bałaganu statpołączeń. Ten bit jest tracony za każdym razem, gdy zmienia się pozycja pliku w indeksie (więc gdy plik jest zmieniany w górę).

skip-worktreeto coś więcej: nawet jeśli git wie, że plik został zmodyfikowany (lub musi zostać zmodyfikowany przez a reset --hardlub podobny), będzie udawał, że tak nie było, używając zamiast tego wersji z indeksu. Trwa to do momentu odrzucenia indeksu.

Istnieje dobre podsumowanie konsekwencji tej różnicy i typowych przypadków użycia tutaj: http://fallengamer.livejournal.com/93321.html .

Z tego artykułu:

  • --assume-unchangedzakłada, że ​​programista nie powinien zmieniać pliku. Ta flaga służy do poprawy wydajności niezmienionych folderów, takich jak zestawy SDK.
  • --skip-worktreejest przydatny, gdy instruujesz git, aby nie dotykał określonego pliku, ponieważ programiści powinni go zmienić. Na przykład, jeśli w głównym repozytorium nadrzędnym znajdują się niektóre gotowe do produkcji pliki konfiguracyjne i nie chcesz przypadkowo zatwierdzać zmian w tych plikach, --skip-worktreeto dokładnie to, czego chcesz.
Borealid
źródło
3
To ma sens. wydaje się, że to droga do pracy. Dzięki!
ckb
100
Mała notatka, aby zaoszczędzić kilka sekund na wyszukiwaniu i czytaniu. Aby anulować --skip-worktreeefekty i rozbroić flagę, dostępna jest --no-skip-worktreeopcja. Działa dokładnie w ten sam sposób. Jest to przydatne w przypadku, gdy ręka się poślizgnęła i niewłaściwe pliki zostały oflagowane, lub jeśli okoliczności się zmieniły i wcześniej pomijane pliki nie powinny być dłużej ignorowane.
drdaeman,
18
Aby odpowiedzieć na moje pytanie powyżej, różnica między używaniem --skip-worktreea .git/info/excludeplikiem polega na tym, że ten pierwszy będzie działał nawet dla plików, które są obecnie śledzone. .git/info/exclude, na przykład .gitignore, zapobiegnie tylko przypadkowemu dodaniu nieśledzonych plików do indeksu, ale nie spowoduje zmian w plikach, które są już śledzone.
LinusR
13
Czy można to zepchnąć na odległość i zachować dla wszystkich klonów?
CMCDragonkai
4
Tylko użycie , proszę pani:git update-index --skip-worktree <file_name>
ruffin
108

Uwaga: fallengamer przeprowadził kilka testów w 2011 roku (więc mogą być nieaktualne), a oto jego ustalenia :

Operacje

  • Plik jest zmieniany zarówno w lokalnym repozytorium, jak i wcześniej
    git pull:
    Git i tak zachowuje lokalne zmiany.
    W ten sposób nie stracisz przypadkowo żadnych danych oznaczonych dowolną z flag.
    • Plik z assume-unchangedflagą: Git nie nadpisuje lokalnego pliku. Zamiast tego generowałby konflikty i doradzał, jak je rozwiązać
    • Plik z skip-worktreeflagą: Git nie nadpisuje lokalnego pliku. Zamiast tego generowałby konflikty i doradzał, jak je rozwiązać

  • Plik jest zmieniany zarówno w lokalnym repozytorium, jak i w górę, próbując i tak wyciągnąć. Wykorzystuje wyniki w dodatkowej pracy ręcznej, ale przynajmniej nie straciłbyś żadnych danych, gdybyś miał jakieś lokalne zmiany.
    git stash
    git pull
    skip-worktree
    • Plik z assume-unchangedflagą: odrzuca wszystkie lokalne zmiany bez możliwości ich przywrócenia. Efekt jest jak „ git reset --hard”. ' git pull' połączenie się powiedzie
    • Plik z skip-worktreeflagą: Skrytka nie działa na skip-worktreeplikach. „ git pull” zakończy się niepowodzeniem z takim samym błędem jak powyżej. Deweloper jest zmuszony ręcznie zresetować skip-worktreeflagę, aby móc ukryć i zakończyć awarię pull.

  • Bez zmian lokalnych, zmieniono plik nadrzędny Obie flagi nie uniemożliwiłyby uzyskania zmian nadrzędnych. Git wykrywa, że ​​złamałeś obietnicę i postanawia odzwierciedlić rzeczywistość, resetując flagę.
    git pull
    assume-unchanged
    • Plik z assume-unchangedflagą: treść jest aktualizowana, flaga została utracona.
      git ls-files -v” pokazuje, że flaga jest zmodyfikowana na H(z h).
    • Plik z skip-worktreeflagą: treść jest aktualizowana, flaga zostaje zachowana.
      git ls-files -v” Pokaże taką samą Sflagę jak przed pull.

  • Po zmianie pliku lokalnego Git nie dotyka pliku i odzwierciedla rzeczywistość (plik, który obiecał pozostać niezmieniony, został zmieniony) dla pliku.
    git reset --hard
    skip-worktreeassume-unchanged
    • Plik z assume-unchangedflagą: zawartość pliku jest cofana. Flaga jest resetowana do H(z h).
    • Plik z skip-worktreeflagą: zawartość pliku jest nienaruszona. Flaga pozostaje taka sama.

Dodaje następującą analizę:

  • Wygląda na skip-worktreeto, że bardzo się starasz zachować swoje lokalne dane . Ale to nie zapobiega otrzymywaniu zmian, jeśli jest to bezpieczne. Plus git nie resetuje flagi pull.
    Ale zignorowanie polecenia „ reset --hard” może stać się przykrą niespodzianką dla programisty.

  • Assume-unchangedFlaga może zostać utracona podczas pulloperacji, a lokalne zmiany w takich plikach nie wydają się być ważne dla git.

Widzieć:

Podsumowuje:

W rzeczywistości żadna z flag nie jest wystarczająco intuicyjna .

  • assume-unchangedzakłada, że ​​programista nie powinien zmieniać pliku. Jeśli plik został zmieniony - zmiana ta nie jest ważna. Ta flaga służy do poprawy wydajności niezmienionych folderów, takich jak zestawy SDK.
    Ale jeśli obietnica zostanie złamana, a plik faktycznie zmieniony, git cofa flagę, aby odzwierciedlić rzeczywistość. Prawdopodobnie dobrze jest mieć niespójne flagi w folderach, których nie można zmienić.

  • Z drugiej strony skip-worktreejest przydatny, gdy instruujesz git, aby nigdy nie dotykał określonego pliku. Jest to przydatne w przypadku już śledzonego pliku konfiguracyjnego.
    W głównym repozytorium nadrzędnym znajduje się konfiguracja gotowa do produkcji, ale chcesz zmienić niektóre ustawienia w konfiguracji, aby móc przeprowadzić lokalne testy. I nie chcesz przypadkowo sprawdzać zmian w takim pliku, aby wpłynąć na konfigurację produkcyjną. W takim przypadku skip-worktreetworzy idealną scenę.


W Git 2.25.1 (luty 2020 r.) Wspomniane powyżej „Właściwie żadna z flag nie jest wystarczająco intuicyjna” zostało wyjaśnione:

Zobacz zatwierdzenie 7a2dc95 , zatwierdzenie 1b13e90 (22 stycznia 2020 r.) Autor: brian m. carlson ( bk2204) .
(Scalony przez Junio ​​C Hamano - gitster- w commit 53a8329 , 30 stycznia 2020)
( Git Mailing list )

doc: zniechęcaj użytkowników do ignorowania śledzonych plików

Podpisano: Jeff King
Podpisano: brian m. Carlson

Użytkownicy często ignorują zmiany w pliku, który śledzi Git.

Typowymi scenariuszami w tym przypadku są ustawienia IDE i pliki konfiguracyjne, które zasadniczo nie powinny być śledzone i prawdopodobnie generowane z plików śledzonych przy użyciu mechanizmu szablonów.

Jednak użytkownicy dowiadują się o bitach „zakładaj niezmienione” i „pomiń”, i i tak próbuj ich użyć.

Jest to problematyczne, ponieważ po ustawieniu tych bitów wiele operacji zachowuje się zgodnie z oczekiwaniami użytkownika, ale zwykle nie pomaga, gdy git checkouttrzeba wymienić plik.

W tym przypadku nie ma rozsądnego zachowania, ponieważ czasami dane są cenne, takie jak niektóre pliki konfiguracyjne, a czasem nieistotne dane, które użytkownik chętnie odrzuci.

Ponieważ nie jest to obsługiwana konfiguracja, a użytkownicy są skłonni do niewłaściwego wykorzystywania istniejących funkcji do niezamierzonych celów, powodując ogólny smutek i zamieszanie , udokumentujmy istniejące zachowanie i pułapki w dokumentacji git update-index, aby użytkownicy wiedzieli, że powinni zbadać alternatywne rozwiązania.

Ponadto zapewnijmy zalecane rozwiązanie radzenia sobie ze zwykłym przypadkiem plików konfiguracyjnych, ponieważ istnieją dobrze znane podejścia stosowane z powodzeniem w wielu środowiskach.

git update-indexStrona podręcznika zawiera teraz:

Użytkownicy często próbują użyć bitów assume-unchangedi, skip-worktreeaby powiedzieć Gitowi, aby ignorował zmiany w śledzonych plikach. Nie działa to zgodnie z oczekiwaniami, ponieważ Git może nadal sprawdzać działające pliki drzewa pod kątem indeksu podczas wykonywania niektórych operacji. Ogólnie rzecz biorąc, Git nie umożliwia ignorowania zmian w śledzonych plikach, dlatego zalecane są alternatywne rozwiązania.

Na przykład, jeśli plik, który chcesz zmienić, jest jakimś plikiem konfiguracyjnym, repozytorium może zawierać przykładowy plik konfiguracyjny, który można następnie skopiować do zignorowanej nazwy i zmodyfikować. Repozytorium może nawet zawierać skrypt traktujący przykładowy plik jako szablon, automatycznie go modyfikując i kopiując.

Ta ostatnia część jest tym, co opisuję typowym sterownikiem filtru treści opartym na smudge / clean scripts .

VonC
źródło
8
Jeśli masz plik pomijania-pracy dla pliku i zmiany w górę, otrzymujesz „proszę zatwierdzić lub ukryć” przy próbie ściągnięcia, nawet jeśli status git nie zgłasza pliku jako zmienionego. Jak można tego uniknąć, aby lokalne zmiany mogły się utrzymywać, gdy ludzie bawią się przy ustawieniach produkcji w miejscu pochodzenia?
GreenAsJade,
3
Tak, mogę to potwierdzić. Oznacza to, że nadal bardzo trudno jest mieć plik lokalny, który po prostu chcesz zachować inaczej niż plik źródłowy.
GreenAsJade,
1
@GreenAsJade niż wydaje się starożytny. Czy jest szansa, że ​​mógłbyś przetestować to w wersji 2.2.x?
VonC
1
@VonC, Link do „komentarza Junio” nie znajduje się w historii wersji. Czy o to ci chodziło?
Michael - Where's Clay Shirky
1
@Michael Dobry połów, dziękuję. Ponownie umieściłem ten link w odpowiedzi.
VonC