Git: assume-unchanged czy skip-worktree? Ignoruj lokalne zmiany w śledzonym pliku

Plik jest w repozytorium, a Ty zmieniasz go tylko u siebie: port w docker-compose.yml, adres bazy w pliku konfiguracyjnym. .gitignore nie pomoże, bo plik jest już śledzony. Są dwie flagi w git update-index, które ukrywają taki plik w git status. Różnią się tym, co się stanie z Twoimi zmianami przy reset --hard albo checkout 🙈

Krótko: do lokalnych zmian używaj --skip-worktree. --assume-unchanged został zrobiony do czegoś innego i potrafi po cichu skasować Twoją wersję pliku.

skip-worktree: ukryj plik i zachowaj zmiany

# ustaw
git update-index --skip-worktree docker-compose.yml

# lista plików z flagą (S = skip-worktree, h = assume-unchanged)
git ls-files -v | grep -E '^(h|S)'

# cofnij
git update-index --no-skip-worktree docker-compose.yml

assume-unchanged: to samo, ale bez ochrony

# ustaw
git update-index --assume-unchanged docker-compose.yml

# lista plików z flagą
git ls-files -v | grep '^h'

# cofnij
git update-index --no-assume-unchanged docker-compose.yml

Dokumentacja Gita opisuje tę flagę jako sposób na pominięcie sprawdzania zmian na wolnych systemach plików. Git zakłada, że plik się nie zmienił, więc Twoja lokalna wersja nie ma żadnej ochrony.

Test: co się dzieje z lokalną zmianą

Plik z lokalną zmianą (port: 8080 zamiast port: 80), flaga ustawiona, jedno polecenie na świeżym repozytorium:

Polecenieassume-unchangedskip-worktree
git reset --hardzmiana skasowanazmiana zostaje
git restore plikzmiana skasowanabłąd, zmiana zostaje
git checkout .zmiana skasowanabłąd, zmiana zostaje
git stashnie zapisuje zmianynie zapisuje zmiany
git pull (ktoś zmienił ten plik)przerywa z błędemprzerywa z błędem

Przy assume-unchanged jedno git reset --hard wraca do wersji z repozytorium, bez ostrzeżenia. Przy skip-worktree Git omija plik.

Kiedy ktoś zmieni plik w repozytorium

Obie flagi kończą git pull błędem Your local changes ... would be overwritten. Wyjście:

  1. Cofnij flagę: git update-index --no-skip-worktree docker-compose.yml
  2. Schowaj zmianę: git stash
  3. Pobierz zmiany: git pull
  4. Przywróć zmianę: git stash pop, a potem ustaw flagę ponownie

Gdy zmiany dotyczą różnych linii, Git scala je sam. Gdy tych samych albo sąsiednich, stash pop zgłasza konflikt, który rozwiązujesz ręcznie. Flagę ustawisz dopiero po jego rozwiązaniu, bo przy konflikcie update-index zwraca błąd.

Uwagi

  • Dokumentacja Gita pisze, że skip-worktree powstał głównie dla sparse checkout i nie każde polecenie go respektuje. Przy konflikcie (merge, rebase) Git i tak może zapisać taki plik
  • Flaga żyje w indeksie Twojego klona. Inni jej nie dostaną, a nowy klon zaczyna bez niej
  • Dla docker-compose.yml lepszy jest osobny plik docker-compose.override.yml w .gitignore: Docker Compose łączy go z głównym plikiem automatycznie i nic nie trzeba odpinać

Masz plik, który zmieniasz tylko lokalnie? Sprawdź git ls-files -v | grep -E '^(h|S)' i zostaw w komentarzu, ile flag znalazłeś w swoich repozytoriach 👏

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Wymagane pola są oznaczone *