La risposta accettata non "fa dimenticare a Git " un file ... "(storicamente). Fa solo in modo che git ignori il file nel presente / futuro.
Questo metodo fa in modo che git dimentichi completamente i file ignorati ( passati / presenti / futuri), ma non elimina nulla dalla directory di lavoro (anche quando viene estratto nuovamente da remoto).
Questo metodo richiede l'utilizzo di /.git/info/exclude
(preferito) O un preesistente .gitignore
in tutti i commit che hanno file da ignorare / dimenticare. 1
Tutti i metodi per applicare git ignorano il comportamento dopo il fatto riscrivendo efficacemente la storia e quindi hanno conseguenze significative per qualsiasi repository pubblico / condiviso / collaborativo che potrebbe essere tirato dopo questo processo. 2
Consiglio generale: inizia con un repository pulito - tutto impegnato, nulla in sospeso nella directory o nell'indice di lavoro ed esegui un backup !
Inoltre, i commenti / la cronologia delle revisioni di questa risposta ( e la cronologia delle revisioni di questa domanda ) possono essere utili / illuminanti.
#commit up-to-date .gitignore (if not already existing)
#this command must be run on each branch
git add .gitignore
git commit -m "Create .gitignore"
#apply standard git ignore behavior only to current index, not working directory (--cached)
#if this command returns nothing, ensure /.git/info/exclude AND/OR .gitignore exist
#this command must be run on each branch
git ls-files -z --ignored --exclude-standard | xargs -0 git rm --cached
#Commit to prevent working directory data loss!
#this commit will be automatically deleted by the --prune-empty flag in the following command
#this command must be run on each branch
git commit -m "ignored index"
#Apply standard git ignore behavior RETROACTIVELY to all commits from all branches (--all)
#This step WILL delete ignored files from working directory UNLESS they have been dereferenced from the index by the commit above
#This step will also delete any "empty" commits. If deliberate "empty" commits should be kept, remove --prune-empty and instead run git reset HEAD^ immediately after this command
git filter-branch --tree-filter 'git ls-files -z --ignored --exclude-standard | xargs -0 git rm -f --ignore-unmatch' --prune-empty --tag-name-filter cat -- --all
#List all still-existing files that are now ignored properly
#if this command returns nothing, it's time to restore from backup and start over
#this command must be run on each branch
git ls-files --other --ignored --exclude-standard
Infine, segui il resto di questa guida di GitHub (a partire dal passaggio 6) che include importanti avvertenze / informazioni sui comandi seguenti .
git push origin --force --all
git push origin --force --tags
git for-each-ref --format="delete %(refname)" refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --prune=now
Altri sviluppatori che eseguono il pull dal repository remoto ora modificato dovrebbero eseguire un backup e quindi:
#fetch modified remote
git fetch --all
#"Pull" changes WITHOUT deleting newly-ignored files from working directory
#This will overwrite local tracked files with remote - ensure any local modifications are backed-up/stashed
git reset FETCH_HEAD
Le note
1 Poiché /.git/info/exclude
può essere applicato a tutti i commit storici usando le istruzioni sopra, forse i dettagli su come ottenere un .gitignore
file nei commit storici che ne hanno bisogno vanno oltre lo scopo di questa risposta. Volevo un vero .gitignore
essere nel root commit, come se fosse la prima cosa che ho fatto. Ad altri potrebbe non interessarsi poiché /.git/info/exclude
può realizzare la stessa cosa indipendentemente da dove .gitignore
esiste nella cronologia del commit, e riscrivere chiaramente la storia è un argomento molto delicato, anche se consapevole delle conseguenze .
FWIW, i potenziali metodi possono includere git rebase
o un git filter-branch
copia di un esterno .gitignore
in ciascun commit, come le risposte a questa domanda
2 L'applicazione forzata di git ignora il comportamento dopo aver eseguito il commit dei risultati di un git rm --cached
comando autonomo può comportare la cancellazione di file appena ignorata nei pull futuri dal telecomando forzato. Il --prune-empty
flag nel git filter-branch
comando seguente evita questo problema rimuovendo automaticamente il precedente commit solo indice "elimina tutti i file ignorati". Riscrivere la storia di Git cambia anche gli hash di commit, che causeranno il caos su futuri pull da repository pubblici / condivisi / collaborativi. Si prega di comprendere appieno le ramificazioni prima di fare questo a tale repo. Questa guida di GitHub specifica quanto segue:
Di 'ai tuoi collaboratori di rifare , non unire, tutti i rami che hanno creato dalla tua vecchia storia (contaminata) del repository. Un commit di merge potrebbe reintrodurre una parte o tutta la storia contaminata che hai appena avuto il disturbo di eliminare.
Soluzioni alternative che non influiscono sul repository remoto sono git update-index --assume-unchanged </path/file>
o git update-index --skip-worktree <file>
, esempi dei quali sono disponibili qui .
git clean -X
sembra simile, ma non si applica in questa situazione (quando i file sono ancora tracciati da Git). Sto scrivendo questo per chiunque cerchi una soluzione per non seguire la strada sbagliata.