Lo que desea hacer es altamente perjudicial si ha publicado el historial a otros desarrolladores. Consulte "Recuperación de la base de datos ascendente" en la git rebase
documentación para conocer los pasos necesarios después de reparar su historial.
Tiene al menos dos opciones: git filter-branch
y un rebase interactivo, ambos explicados a continuación.
Utilizando git filter-branch
Tuve un problema similar con los datos de prueba binarios voluminosos de una importación de Subversion y escribí sobre la eliminación de datos de un repositorio git .
Digamos que tu historial de git es:
$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A login.html
* cb14efd Remove DVD-rip
| D oops.iso
* ce36c98 Careless
| A oops.iso
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
Tenga en cuenta que git lola
es un alias no estándar pero muy útil. Con el --name-status
interruptor, podemos ver las modificaciones del árbol asociadas con cada confirmación.
En el commit "Descuidado" (cuyo nombre de objeto SHA1 es ce36c98) el archivo oops.iso
es el DVD-rip agregado por accidente y eliminado en el siguiente commit, cb14efd. Usando la técnica descrita en la publicación de blog mencionada anteriormente, el comando para ejecutar es:
git filter-branch --prune-empty -d /dev/shm/scratch \
--index-filter "git rm --cached -f --ignore-unmatch oops.iso" \
--tag-name-filter cat -- --all
Opciones:
--prune-empty
elimina las confirmaciones que se vuelven vacías ( es decir , no cambian el árbol) como resultado de la operación de filtro. En el caso típico, esta opción produce un historial más limpio.
-d
nombra un directorio temporal que aún no existe para usar para construir el historial filtrado. Si está ejecutando en una distribución moderna de Linux, la especificación de un árbol /dev/shm
dará como resultado una ejecución más rápida .
--index-filter
es el evento principal y se ejecuta contra el índice en cada paso de la historia. Desea eliminar oops.iso
donde se encuentre, pero no está presente en todas las confirmaciones. El comando git rm --cached -f --ignore-unmatch oops.iso
elimina el DVD-rip cuando está presente y no falla de lo contrario.
--tag-name-filter
describe cómo reescribir nombres de etiquetas. Un filtro de cat
es la operación de identidad. Es posible que su repositorio, como el ejemplo anterior, no tenga etiquetas, pero incluí esta opción para una generalidad completa.
--
especifica el final de las opciones para git filter-branch
--all
Lo siguiente --
es una abreviatura para todas las referencias. Su repositorio, como el ejemplo anterior, puede tener solo una referencia (maestra), pero incluí esta opción para una generalidad completa.
Después de algunos cambios, la historia es ahora:
$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A login.html
* e45ac59 Careless
| A other.html
|
| * f772d66 (refs/original/refs/heads/master) Login page
| | A login.html
| * cb14efd Remove DVD-rip
| | D oops.iso
| * ce36c98 Careless
|/ A oops.iso
| A other.html
|
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
Tenga en cuenta que la nueva confirmación "Descuidado" solo agrega other.html
y que la confirmación "Eliminar DVD-rip" ya no está en la rama maestra. La rama etiquetada refs/original/refs/heads/master
contiene sus confirmaciones originales en caso de que haya cometido un error. Para eliminarlo, siga los pasos en "Lista de verificación para reducir un repositorio".
$ git update-ref -d refs/original/refs/heads/master
$ git reflog expire --expire=now --all
$ git gc --prune=now
Para una alternativa más simple, clone el repositorio para descartar los bits no deseados.
$ cd ~/src
$ mv repo repo.old
$ git clone file:///home/user/src/repo.old repo
El uso de una file:///...
URL de clonación copia objetos en lugar de crear solo enlaces duros.
Ahora tu historia es:
$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A login.html
* e45ac59 Careless
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
Los nombres de objeto SHA1 para las dos primeras confirmaciones ("Índice" y "Página de administración") permanecieron iguales porque la operación de filtro no modificó esas confirmaciones. “Descuidado” perdido oops.iso
y “página de inicio de sesión” consiguieron un nuevo padre, por lo que sus SHA1s hicieron el cambio.
Rebase interactivo
Con una historia de:
$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A login.html
* cb14efd Remove DVD-rip
| D oops.iso
* ce36c98 Careless
| A oops.iso
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
desea eliminar oops.iso
de "Descuidado" como si nunca lo hubiera agregado, y luego "Eliminar DVD-rip" es inútil para usted. Por lo tanto, nuestro plan para crear una nueva versión interactiva es mantener la "Página de administración", editar "Descuidado" y descartar "Eliminar DVD-rip".
La ejecución $ git rebase -i 5af4522
inicia un editor con los siguientes contenidos.
pick ce36c98 Careless
pick cb14efd Remove DVD-rip
pick f772d66 Login page
# Rebase 5af4522..f772d66 onto 5af4522
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
Al ejecutar nuestro plan, lo modificamos a
edit ce36c98 Careless
pick f772d66 Login page
# Rebase 5af4522..f772d66 onto 5af4522
# ...
Es decir, eliminamos la línea con "Eliminar DVD-rip" y cambiamos la operación en "Descuidado" para que sea en edit
lugar de pick
.
Guardar-salir del editor nos deja en el símbolo del sistema con el siguiente mensaje.
Stopped at ce36c98... Careless
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
Como nos dice el mensaje, estamos en el compromiso "Descuidado" que queremos editar, por lo que ejecutamos dos comandos.
$ git rm --cached oops.iso
$ git commit --amend -C HEAD
$ git rebase --continue
El primero elimina el archivo ofensivo del índice. El segundo modifica o modifica "Descuidado" para que sea el índice actualizado e -C HEAD
indica a git que reutilice el antiguo mensaje de confirmación. Finalmente, git rebase --continue
continúa con el resto de la operación de rebase.
Esto da una historia de:
$ git lola --name-status
* 93174be (HEAD, master) Login page
| A login.html
* a570198 Careless
| A other.html
* 5af4522 Admin page
| A admin.html
* e738b63 Index
A index.html
que es lo que quieres