Git - Differenza tra 'assume-immutato' e 'skip-worktree'


450

Ho delle modifiche locali a un file che non voglio impegnare nel mio repository. È un file di configurazione per la creazione dell'applicazione su un server, ma voglio creare localmente con impostazioni diverse. Naturalmente, il file viene sempre visualizzato quando faccio "git status" come qualcosa da mettere in scena. Vorrei nascondere questo particolare cambiamento e non impegnarlo. Non apporterò altre modifiche al file.

Dopo un po 'di ricerche, vedo 2 opzioni:' assume-immutato 'e' skip-worktree '. Una domanda precedente qui ne parla ma non spiega davvero le loro differenze. La mia domanda è questa: in che modo i due comandi sono diversi? Perché qualcuno dovrebbe usare l'uno o l'altro?


1
Di solito lo sto usando .gitignoreper scopi simili. Questa soluzione funzionerebbe per te?
samuil,

45
samuil, .gitignore ignora l'aggiunta, non il cambiamento. Quando il file è già in git verrà monitorato l'evento se è elencato in .gitignore
Grigory

ma non si può rimuovere tutto e aggiungere tutto per "aggiornare" come spiegato qui? stackoverflow.com/questions/7075923/... @Grigory
Daniel Springer

2
Il file non dovrebbe essere ignorato, se ottengo correttamente l'intenzione di OP. Il file deve essere nel repository, ma queste modifiche molto specifiche che ha apportato non dovrebbero essere impegnate - almeno ora.
Simone,

Risposte:


666

Tu vuoi skip-worktree.

assume-unchangedè progettato per i casi in cui è costoso verificare se un gruppo di file è stato modificato; quando si imposta il bit, git(ovviamente) si presuppone che i file corrispondenti a quella parte dell'indice non siano stati modificati nella copia di lavoro. Quindi evita un pasticcio di statchiamate. Questo bit viene perso ogni volta che cambia la voce del file nell'indice (quindi, quando il file viene modificato a monte).

skip-worktreeè più di questo: anche quando git sa che il file è stato modificato (o deve essere modificato da uno reset --hardo simili), farà finta di non esserlo, usando invece la versione dall'indice. Ciò persiste fino a quando l'indice viene scartato.

C'è un buon riassunto delle ramificazioni di questa differenza e dei casi d'uso tipici qui: http://fallengamer.livejournal.com/93321.html .

Da quell'articolo:

  • --assume-unchangedpresume che uno sviluppatore non debba modificare un file. Questo flag ha lo scopo di migliorare le prestazioni per le cartelle che non cambiano come SDK.
  • --skip-worktreeè utile quando si ordina a git di non toccare un file specifico perché gli sviluppatori dovrebbero modificarlo. Ad esempio, se il repository principale a monte ospita alcuni file di configurazione pronti per la produzione e non si desidera eseguire il commit accidentale di modifiche a tali file, --skip-worktreeè esattamente ciò che si desidera.

3
Questo ha senso. skip-worktree sembra davvero essere la strada da percorrere. Grazie!
ckb,

100
Una piccola nota per risparmiare pochi secondi nella ricerca e nella lettura. Per annullare gli --skip-worktreeeffetti e disinserire il flag c'è --no-skip-worktreeun'opzione. Funziona esattamente allo stesso modo. Ciò è utile nel caso in cui una mano fosse scivolata e i file sbagliati fossero contrassegnati, o se le circostanze fossero cambiate e i file precedentemente ignorati non dovrebbero più essere ignorati.
drdaeman,

18
Per rispondere alla mia domanda sopra, la differenza tra l'utilizzo --skip-worktreee il .git/info/excludefile è che il primo funzionerà anche per i file attualmente tracciati. .git/info/exclude, come .gitignore, impedirà solo l'aggiunta accidentale di file non tracciati all'indice, ma non apportare modifiche ai file già tracciati.
Linus R

13
Questo può essere spinto sul telecomando ed essere preservato da tutti i cloni?
CMCDragonkai

4
Solo l'uso , signora:git update-index --skip-worktree <file_name>
ruffin

108

Nota: fallengamer ha fatto alcuni test nel 2011 (quindi potrebbero essere obsoleti), e qui ci sono i suoi risultati :

operazioni

  • Il file viene modificato sia nel repository locale che upstream
    git pull:
    Git conserva comunque le modifiche locali.
    In questo modo non perderesti accidentalmente i dati che hai contrassegnato con una delle bandiere.
    • File con assume-unchangedflag: Git non sovrascriverà il file locale. Invece genererebbe conflitti e consigli su come risolverli
    • File con skip-worktreeflag: Git non sovrascriverà il file locale. Invece genererebbe conflitti e consigli su come risolverli

  • Il file viene modificato sia nel repository locale sia a monte, provando comunque a estrarre Usando i risultati in qualche lavoro manuale aggiuntivo ma almeno non perderesti alcun dato se avessi delle modifiche locali.
    git stash
    git pull
    skip-worktree
    • File con assume-unchangedflag: ignora tutte le modifiche locali senza possibilità di ripristinarle. L'effetto è come ' git reset --hard'. ' git pull' la chiamata avrà esito positivo
    • File con skip-worktreeflag: Stash non funzionerebbe sui skip-worktreefile. ' git pull' fallirà con lo stesso errore di cui sopra. Lo sviluppatore è costretto a reimpostare manualmente il skip-worktreeflag per poter riporre e completare l'errore pull.

  • Nessuna modifica locale, il file upstream è cambiato Entrambi i flag non ti impedirebbero di ottenere modifiche upstream. Git rileva che hai rotto la promessa e sceglie di riflettere la realtà ripristinando la bandiera.
    git pull
    assume-unchanged
    • File con assume-unchangedflag: il contenuto viene aggiornato, il flag viene perso.
      ' git ls-files -v' mostrerebbe che il flag è modificato in H(da h).
    • File con skip-worktreeflag: il contenuto viene aggiornato, il flag viene conservato.
      ' git ls-files -v' mostrerebbe la stessa Sbandiera di prima del pull.

  • Con il file locale modificato Git non tocca il file e riflette la realtà (il file promesso di essere invariato è stato effettivamente modificato) per il file.
    git reset --hard
    skip-worktreeassume-unchanged
    • File con assume-unchangedflag: il contenuto del file viene ripristinato. Il flag viene ripristinato su H(da h).
    • File con skip-worktreeflag: il contenuto del file è intatto. La bandiera rimane la stessa.

Aggiunge la seguente analisi:

  • Sembra che si skip-worktreestia impegnando molto per preservare i dati locali . Ma non ti impedisce di ottenere modifiche a monte se è sicuro. Inoltre git non resetta il flag pull.
    Ignorare il reset --hardcomando " " potrebbe diventare una brutta sorpresa per uno sviluppatore.

  • Assume-unchangedflag potrebbe essere perso durante l' pulloperazione e le modifiche locali all'interno di tali file non sembrano essere importanti per git.

Vedere:

Conclude:

In realtà nessuna delle bandiere è abbastanza intuitiva .

  • assume-unchangedpresume che uno sviluppatore non debba modificare un file. Se un file è stato modificato, tale modifica non è importante. Questo flag ha lo scopo di migliorare le prestazioni per le cartelle che non cambiano come SDK.
    Ma se la promessa viene meno e un file viene effettivamente modificato, git ripristina la bandiera per riflettere la realtà. Probabilmente va bene avere alcuni flag incoerenti in cartelle generalmente non pensate per essere cambiate.

  • D'altra parte skip-worktreeè utile quando si impone a git di non toccare mai un file specifico. Ciò è utile per un file di configurazione già tracciato.
    Il repository principale a monte ospita alcune configurazioni pronte per la produzione, ma si desidera modificare alcune impostazioni nella configurazione per poter eseguire alcuni test locali. E non si desidera controllare accidentalmente le modifiche in tale file per influire sulla configurazione di produzione. In quel caso skip-worktreerende la scena perfetta.


Con Git 2.25.1 (febbraio 2020), "In realtà nessuna delle bandiere è abbastanza intuitiva" di cui sopra è ulteriormente chiarito:

Vedi commit 7a2dc95 , commit 1b13e90 (22 gennaio 2020) di brian m. Carlson ( bk2204) .
(Unita da Junio ​​C Hamano - gitster- in commit 53a8329 , 30 gennaio 2020)
( Git Mailing list )

doc: dissuadere gli utenti dal tentativo di ignorare i file tracciati

Firmato-fuori: Jeff King
Firmato-fuori: brian m. Carlson

È abbastanza comune per gli utenti voler ignorare le modifiche a un file che Git tiene traccia.

Gli scenari comuni per questo caso sono le impostazioni IDE e i file di configurazione, che generalmente non dovrebbero essere tracciati e possibilmente generati da file tracciati usando un meccanismo di template.

Tuttavia, gli utenti imparano a conoscere i bit invariati e skip-worktree e provano comunque a usarli per farlo.

Questo è problematico, perché quando questi bit sono impostati, molte operazioni si comportano come previsto dall'utente, ma di solito non aiutano quando è git checkoutnecessario sostituire un file.

Non esiste un comportamento ragionevole in questo caso, perché a volte i dati sono preziosi, come alcuni file di configurazione, e talvolta sono dati irrilevanti che l'utente sarebbe felice di scartare.

Poiché questa non è una configurazione supportata e gli utenti sono inclini a utilizzare in modo improprio le funzionalità esistenti per scopi non intenzionali, causando tristezza e confusione generali , documentiamo il comportamento esistente e le insidie ​​nella documentazione in git update-indexmodo che gli utenti sappiano che dovrebbero esplorare soluzioni alternative.

Inoltre, forniamo una soluzione consigliata per gestire il caso comune dei file di configurazione, poiché esistono molti approcci noti utilizzati con successo in molti ambienti.

La git update-indexpagina man ora include:

Gli utenti spesso provano a usare i bit assume-unchangede skip-worktreeper dire a Git di ignorare le modifiche ai file tracciati. Questo non funziona come previsto, poiché Git può comunque verificare i file dell'albero di lavoro rispetto all'indice durante l'esecuzione di determinate operazioni. In generale, Git non fornisce un modo per ignorare le modifiche ai file tracciati, quindi sono consigliate soluzioni alternative.

Ad esempio, se il file che si desidera modificare è una sorta di file di configurazione, il repository può includere un file di configurazione di esempio che può quindi essere copiato nel nome ignorato e modificato. Il repository può anche includere uno script per trattare il file di esempio come modello, modificandolo e copiandolo automaticamente.

L'ultima parte è ciò che descrivo un tipico driver del filtro contenuto basato su smudge / clean script .


7
Se si ha skip-worktree su un file e le modifiche a monte, si ottiene "si prega di eseguire il commit o lo stash" quando si tenta di estrarre, anche se lo stato git non segnala il file come modificato. Come è possibile evitarlo, in modo che i cambiamenti locali possano persistere mentre le persone si agitano con le impostazioni di produzione sull'origine?
GreenAsJade,

3
Sì, posso confermare che lo fai. Significa che è ancora molto difficile avere un file locale che vuoi semplicemente mantenere diversamente dall'origine.
GreenAsJade,

1
@GreenAsJade di quanto sembri antico. Qualche possibilità che tu possa testarlo con un 2.2.x?
VonC,

1
@VonC, Il link al "commento di Junio" non è nella cronologia delle revisioni. È questo a cui ti riferivi?
Michael - Dov'è Clay Shirky il

1
@Michael Buona cattura, grazie. Ho rimesso quel link nella risposta.
VonC,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.