La respuesta aceptada no "hace que Git " se olvide " de un archivo ..." (históricamente). Solo hace que git ignore el archivo en el presente / futuro.
Este método hace que git olvide por completo los archivos ignorados ( pasado / presente / futuro), pero no elimina nada del directorio de trabajo (incluso cuando se vuelve a extraer desde el control remoto).
Este método requiere el uso de /.git/info/exclude
(preferido) O un preexistente .gitignore
en todas las confirmaciones que tienen archivos que deben ignorarse / olvidarse. 1
Todos los métodos para hacer cumplir git ignoran el comportamiento después de los hechos reescriben el historial de manera efectiva y, por lo tanto, tienen ramificaciones significativas para cualquier repositorio público / compartido / colaborativo que pueda retirarse después de este proceso. 2
Consejo general: comience con un repositorio limpio : todo está comprometido, nada pendiente en el directorio o índice de trabajo, ¡ y haga una copia de seguridad !
Además, el historial de comentarios / revisiones de esta respuesta ( y el historial de revisiones de de esta pregunta ) pueden ser útiles / esclarecedores.
#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
Finalmente, sigue el resto de esta guía de GitHub (comenzando en el paso 6) que incluye advertencias / información importante sobre los comandos a continuación .
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
Otros desarrolladores que extraen del repositorio remoto ahora modificado deben hacer una copia de seguridad y luego:
#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
Notas al pie
1 Debido a que /.git/info/exclude
se puede aplicar a todas las confirmaciones históricas utilizando las instrucciones anteriores, quizás los detalles sobre cómo obtener un .gitignore
archivo en las confirmaciones históricas que lo necesitan están fuera del alcance de esta respuesta. Quería un apropiado .gitignore
para estar en el commit raíz, como si fuera lo primero que hiciera. Es posible que a otros no les importe, ya que /.git/info/exclude
pueden lograr lo mismo independientemente de dónde.gitignore
exista en el historial de confirmaciones, y claramente reescribir el historial es un tema muy delicado, incluso cuando se tiene conocimiento de las ramificaciones .
FWIW, los métodos potenciales pueden incluir git rebase
o un git filter-branch
que copia un externo .gitignore
en cada confirmación, como las respuestas a esta pregunta
2 Hacer cumplir el comportamiento de git ignore después de los hechos mediante la confirmación de los resultados de un git rm --cached
comando independiente puede dar como resultado la eliminación de archivos recientemente ignorados en futuros tirones del control remoto forzado. El --prune-empty
indicador en el siguiente git filter-branch
comando evita este problema al eliminar automáticamente la confirmación de solo índice anterior "eliminar todos los archivos ignorados". Reescribir el historial de git también cambia los hash de confirmación, lo que causará estragos en futuros tirones de repositorios públicos / compartidos / colaborativos. Por favor, comprenda las ramificaciones completamente antes de hacer esto a dicho repositorio. Esta guía de GitHub especifica lo siguiente:
Dígale a sus colaboradores que modifiquen , no fusionen, las ramas que crearon a partir de su historial de repositorio antiguo (contaminado). Una confirmación de fusión podría reintroducir parte o la totalidad de la historia contaminada que acaba de tomarse la molestia de purgar.
Las soluciones alternativas que no afectan al repositorio remoto son git update-index --assume-unchanged </path/file>
o git update-index --skip-worktree <file>
, ejemplos de las cuales se pueden encontrar aquí .
git clean -X
Suena similar, pero no se aplica en esta situación (cuando Git sigue rastreando los archivos). Estoy escribiendo esto para cualquiera que busque una solución para no seguir la ruta incorrecta.