Czy mogę „zatwierdzić” plik i zignorować zmiany jego zawartości?

355

Każdy programista w moim zespole ma własną konfigurację lokalną. Te informacje o konfiguracji są przechowywane w pliku o nazwie, devtargets.rbktóry jest używany w naszych zadaniach kompilacji prowizji. Nie chcę jednak, aby programiści blokowali nawzajem swój plik devtargets.

Moją pierwszą myślą było umieszczenie tego pliku na .gitignoreliście, aby nie był zaangażowany w git.

Potem zacząłem się zastanawiać: czy można zatwierdzić plik, ale zignorować zmiany w pliku? Zatwierdziłbym więc domyślną wersję pliku, a następnie gdy programista zmieniłby ją na swoim komputerze lokalnym, git zignorowałby zmiany i nie pojawiłby się na liście zmienionych plików, gdy wykonujesz status git lub git commit .

Czy to jest możliwe? Na pewno byłaby to miła funkcja ...

Derick Bailey
źródło

Odpowiedzi:

458

Jasne, robię to od czasu do czasu za pomocą

git update-index --assume-unchanged [<file> ...]

Aby cofnąć i ponownie rozpocząć śledzenie (jeśli zapomniałeś, które pliki nie były śledzone, zobacz to pytanie ):

git update-index --no-assume-unchanged [<file> ...]

Odpowiednia dokumentacja :

- [no-] zakłada-niezmieniona
Po określeniu tej flagi nazwy obiektów zarejestrowane dla ścieżek nie są aktualizowane. Zamiast tego ta opcja ustawia / wyłącza bit „zakładaj niezmieniony” dla ścieżek. Gdy bit „zakładaj niezmieniony” jest włączony, użytkownik obiecuje nie zmieniać pliku i pozwala Gitowi założyć, że działający plik drzewa odpowiada temu, co jest zapisane w indeksie. Jeśli chcesz zmienić działający plik drzewa, musisz odznaczyć bit, aby powiedzieć Gitowi. Czasami jest to pomocne podczas pracy z dużym projektem w systemie plików, który ma bardzo wolne lstat(2)wywołanie systemowe (np. Cifs).

Git zawiedzie (z gracją) na wypadek, gdyby musiał zmodyfikować ten plik w indeksie, np. Podczas scalania w zatwierdzeniu; dlatego w przypadku zmiany założonego pliku, który nie został wyśledzony, należy ręcznie obsłużyć sytuację.

Niepowodzenie z wdziękiem w tym przypadku oznacza, że ​​jeśli są jakieś zmiany w górę do tego pliku (uzasadnione zmiany itp.), Gdy wykonasz ściąganie, powie:

$ git pull
…
From https://github.com/x/y
   72a914a..106a261  master     -> origin/master
Updating 72a914a..106a261
error: Your local changes to the following files would be overwritten by merge:
                filename.ext

i odmówi połączenia.

W tym momencie możesz temu zaradzić, cofając lokalne zmiany, oto jeden ze sposobów:

 $ git checkout filename.ext

następnie pociągnij ponownie i ponownie zmodyfikuj plik lokalny lub –no-assume-unchangedmożesz ustawić, a następnie możesz wykonać normalne ukrywanie i scalanie itp.

Rob Wilkerson
źródło
10
czy to polecenie działa lokalnie w folderze .git? Mam na myśli, że jeśli uruchomię tę komendę dla pliku config.php, czy ta propagacja zostanie rozpowszechniona wśród innych użytkowników korzystających z repo?
Mag
16
@Magus: Nie. To będzie działać tylko dla ciebie.
Rob Wilkerson
3
Niedługo potem będziesz chciał wiedzieć, jak ustalić, czy plik jest przyjęty jako niezmieniony: stackoverflow.com/questions/2363197/...
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功
10
Zignorowane w ten sposób zmiany plików zostaną utracone, gdy zostanie użyta opcja „git stash”. Czy jest na to jakiś sposób?
Alexis,
5
Po to nie git update-index --assume-unchangedjest. public-inbox.org/git/…
jsageryd
97

Preferowanym sposobem na to jest użycie git update-index --skip-worktree <file>, jak wyjaśniono w tej odpowiedzi :

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, że ​​pliki odpowiadające tej części indeksu nie zostały zmodyfikowane w kopii roboczej. Pozwala to uniknąć bałaganu wywołania statystyk. 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 wymaga modyfikacji przez reset - twardy lub podobny), będzie udawał, że tak nie było, używając zamiast tego wersji z indeksu. Trwa to do momentu odrzucenia indeksu.

Aby cofnąć to, użyj git update-index --no-skip-worktree <file>

Od wersji git 2.25.1 nie jest to już zalecany sposób, cytując:

Użytkownicy często próbują użyć bitów „zakładaj niezmienione” i „pomiń”, aby 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.

1615903
źródło
Czy działa to u wszystkich użytkowników, którzy pobierają repozytorium? Czy otrzymają określone pliki, ale nie będą już w stanie dodawać zmian przez pomyłkę, chyba że wyraźnie to powiedzą?
mmm
2
@ momomo flaga jest przechowywana w indeksie, więc nie, tylko dla jednego użytkownika. Zobacz odpowiedź erjiang na coś, co działa u wszystkich użytkowników.
1615903
Próbuję ustalić, jaka powinna być zawartość pliku. Skomentowałem odpowiedź, o której wspomniałeś, ale nie otrzymałem odpowiedzi. Gdzie ma się znajdować i jaka jest jego zawartość? Czy wiesz?
mmm
Nie śledzę. Polecenie służy do zignorowania jednego określonego pliku określonego w poleceniu. Zawartość tego pliku nie jest istotna.
1615903
1
Dokumentacja Git wyraźnie mówi, że nie należy używać git update-index --skip-worktreedo tego celu.
bk2204
43

Wydaje się, że powszechną praktyką jest tworzenie devtargets.default.rbi zatwierdzanie go, a następnie instruowanie każdego użytkownika, aby skopiował ten plik devtargets.rb(który znajduje się na liście .gitignore). Na przykład CakePHP robi to samo dla pliku konfiguracyjnego bazy danych, który naturalnie zmienia się z maszyny na maszynę.

erjiang
źródło
6
Nie można .gitignore śledzonego pliku. .gitignore działa tylko na pliki, których nie ma w indeksie.
CB Bailey,
1
starałem się tego uniknąć, ale tak naprawdę nie mam dobrego powodu. robimy to teraz i wydaje mi się, że pamiętam, że muszę stworzyć własną wersję bez nazwy „.default”.
Derick Bailey,
11
@DerickBailey Ale szczerze mówiąc, łatwiej jest pamiętać o skopiowaniu pliku, niż pamiętać o użyciu --assume-unchangedopcji dla wszystkich, którzy klonują repozytorium.
Dan
1
@DerickBailey możesz również ustawić domyślną wersję rake, devtargets.default.rbjeśli devtargets.rbnie istnieje.
Łukasza
@erjang co jest w tym pliku devtargets.default.rb? Przykład?
mmm
2

Dla użytkowników IntelliJ IDEA: jeśli chcesz zignorować zmiany pliku (lub plików), możesz przenieść je do innego Change Set.

  • Udaj się do Local Changes( Cmd + 9)
  • Wybierz pliki, które chcesz zignorować
  • F6 aby przenieść je do innego Change Set
Eugene
źródło