De hecho, podría utilizar el filtro de subdirectorio seguido de un filtro de índice para volver a poner el contenido en un subdirectorio, pero ¿por qué molestarse, cuando podría simplemente usar el filtro de índice por sí mismo?
He aquí un ejemplo de la página man:
git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
Esto sólo elimina un nombre de archivo; lo que quiere hacer es eliminar todo menos un subdirectorio determinado. Si quieres ser cauteloso, usted podría enumerar explícitamente cada ruta a eliminar, pero si sólo quiere ir all-in, sólo puede hacer algo como esto:
git filter-branch --index-filter 'git ls-tree -z --name-only --full-tree $GIT_COMMIT | grep -zv "^directory-to-keep$" | xargs -0 git rm --cached -r' -- --all
espero es probable que haya una forma más elegante ; si alguien tiene algo, por favor sugiéralo!
Algunas notas sobre ese comando:
- filter-branch establece internamente GIT_COMMIT a la corriente cometer SHA1
- yo no habría esperado
--full-tree
ser necesario, pero al parecer filter-branch corre el índice -filtro del directorio .git-rewrite/t
en lugar del nivel superior del repositorio.
- grep es probablemente exagerado, pero no creo que sea un problema de velocidad.
--all
aplica esto a todas las referencias; Me imagino que realmente quieres eso. (--
lo separa de las opciones de la rama de filtro)
-z
y -0
indique a ls-tree, grep y xargs que usen la terminación NUL para manejar espacios en nombres de archivo.
Editar, mucho después: Thomas amablemente sugirió una forma de eliminar las confirmaciones ahora vacías, pero ahora está desactualizada. Mirar el historial de edición si tienes una versión antigua de git, pero con git moderna, todo lo que necesita hacer es añadir esta opción:
--prune-empty
Eso va a quitar todos los envíos que están vacías después de la aplicación del filtro de índice.
Aparte de las comillas simples anidadas (que me tomé la libertad de reemplazar), esto funcionó casi a la perfección. El único problema era que los commits vacíos para los directorios ahora inexistentes permanecían en el registro. Eliminé estos usando 'git filter-branch -f --commit-filter 'si [z $ 1 = z \' git rev-parse $ 3^{tree} \ ']; luego skip_commit "$ @"; else git commit-tree "$ @"; fi '"$ @" 'que encontré en http://github.com/jwiegley/git-scripts/blob/master/git-remove-empty-commits – Thomas
@Thomas: ¡Gracias por arreglar mi descuidado error! Además, debería poder usar el filtro de compromiso en el mismo comando que el filtro de índice. Los filtros se ejecutan en el orden que se muestra en la documentación; commit-filter es, naturalmente, después de los filtros que modifican el contenido de la confirmación. Probablemente también desee usar '--remap-to-ancestor', lo que hará que los refs que apuntan a commits omitidos se muevan al ancestro más cercano en lugar de excluirlos. – Cascabel
@Jefromi: el argumento 'index-filter' debería ser más fácil de expresar como 'git rm -r -f --cached --ignore-unmatch $ (ls! (Directory-to-keep))', vea mis respuestas http : //stackoverflow.com/a/8079852/396967 y http://stackoverflow.com/a/7849648/396967 – kynan