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:
| Polecenie | assume-unchanged | skip-worktree |
|---|---|---|
git reset --hard | zmiana skasowana | zmiana zostaje |
git restore plik | zmiana skasowana | błąd, zmiana zostaje |
git checkout . | zmiana skasowana | błąd, zmiana zostaje |
git stash | nie zapisuje zmiany | nie zapisuje zmiany |
git pull (ktoś zmienił ten plik) | przerywa z błędem | przerywa 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:
- Cofnij flagę:
git update-index --no-skip-worktree docker-compose.yml - Schowaj zmianę:
git stash - Pobierz zmiany:
git pull - 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-worktreepowstał 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.ymllepszy jest osobny plikdocker-compose.override.ymlw.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 👏