Estaba trabajando con un amigo en un proyecto, y él editó un montón de archivos que no deberían haberse editado. De alguna manera fusioné su trabajo con el mío, ya sea cuando lo saqué o cuando traté de elegir los archivos específicos que quería. He estado buscando y jugando durante mucho tiempo, tratando de descubrir cómo eliminar las confirmaciones que contienen las ediciones de esos archivos, parece ser un cambio entre revertir y rebase, y no hay ejemplos directos, y el los documentos suponen que sé más que yo.
Así que aquí hay una versión simplificada de la pregunta:
Dado el siguiente escenario, ¿cómo elimino commit 2?
$ mkdir git_revert_test && cd git_revert_test
$ git init
Initialized empty Git repository in /Users/josh/deleteme/git_revert_test/.git/
$ echo "line 1" > myfile
$ git add -A
$ git commit -m "commit 1"
[master (root-commit) 8230fa3] commit 1
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 myfile
$ echo "line 2" >> myfile
$ git commit -am "commit 2"
[master 342f9bb] commit 2
1 files changed, 1 insertions(+), 0 deletions(-)
$ echo "line 3" >> myfile
$ git commit -am "commit 3"
[master 1bcb872] commit 3
1 files changed, 1 insertions(+), 0 deletions(-)
El resultado esperado es
$ cat myfile
line 1
line 3
Aquí hay un ejemplo de cómo he estado tratando de revertir
$ git revert 342f9bb
Automatic revert failed. After resolving the conflicts,
mark the corrected paths with 'git add <paths>' or 'git rm <paths>'
and commit the result.
git
commit
revert
cherry-pick
Joshua Cheek
fuente
fuente
Respuestas:
El algoritmo que utiliza Git al calcular las diferencias para revertir requiere que
La definición de "adyacente" se basa en el número predeterminado de líneas de una diferencia de contexto, que es 3. Entonces, si 'myfile' se construyó así:
Entonces todo funciona como se esperaba.
La segunda respuesta fue muy interesante. Hay una característica que aún no se ha lanzado oficialmente (aunque está disponible en Git v1.7.2-rc2) llamada Estrategia de reversión. Puedes invocar a git de esta manera:
y debería hacer un mejor trabajo descifrando lo que querías decir. No sé cuál es la lista de estrategias disponibles, ni sé la definición de ninguna estrategia.
fuente
perl -p
es útil para escribir programas muy cortos (una línea) que repiten y pasan su entrada a la salida, de forma similar a sed.perl -i
se usa para editar archivos en su lugar .perl -e
es cómo enviar el código para ser evaluado .Hay cuatro formas de hacerlo:
Forma limpia, revertiendo pero mantener en el registro la reversión:
De manera difícil, elimine por completo solo la última confirmación:
Nota: Evite
git reset --hard
ya que también descartará todos los cambios en los archivos desde la última confirmación. Si--soft
no funciona, mejor prueba--mixed
o--keep
.Rebase (muestre el registro de los últimos 5 commits y elimine las líneas que no desea, o reordene, o aplaste múltiples commits en uno, o haga lo que quiera, esta es una herramienta muy versátil):
Y si se comete un error:
Rebase rápida: elimine solo una confirmación específica utilizando su id:
Alternativas: también puedes probar:
Otra alternativa más:
Como último recurso, si necesita una libertad total de edición de historial (por ejemplo, porque git no le permite editar lo que desea), puede usar esta aplicación de código abierto muy rápida : reposurgeon .
Nota: por supuesto, todos estos cambios se realizan localmente,
git push
luego debe aplicar los cambios al control remoto. Y en caso de que su repositorio no quiera eliminar la confirmación ("no se permite el avance rápido", lo que sucede cuando desea eliminar una confirmación que ya presionó), puede usargit push -f
para forzar los cambios.Nota 2: si trabaja en una rama y necesita forzar el empuje, debe evitarlo
git push --force
porque puede sobrescribir otras ramas (si ha realizado cambios en ellas, incluso si su pago actual está en otra rama). Prefieren especificar siempre la rama remota cuando fuerza de empuje :git push --force origin your_branch
.fuente
git rebase -i HEAD~5
trabajó para mi. Luego eliminé los commits que no necesitaba y pude resolver el problema en menos de 30 segundos. Gracias.Aquí hay una solución fácil:
(Nota:
x
es el número de confirmaciones)al ejecutar el archivo de bloc de notas se abrirá. Ingrese
drop
además de su compromiso.Si no conoce Vim, simplemente haga clic en cada selección de palabras que desea editar y luego presione la tecla "I" (para el modo de inserción). Una vez que haya terminado de escribir, presione la tecla "esc" para salir del modo de inserción.
y listo, ya está ... Simplemente sincronice el panel de control de git y los cambios se enviarán al control remoto.
Si la confirmación que suelta ya estaba en el control remoto, tendrá que forzar la inserción. Dado que --force se considera dañino , use
git push --force-with-lease
.fuente
Tu elección es entre
Debe elegir (1) si el cambio erróneo ha sido detectado por otra persona y (2) si el error se limita a una rama privada no empujada.
Git revert es una herramienta automatizada para hacer (1), crea una nueva confirmación deshaciendo algunas confirmaciones anteriores. Verá el error y la eliminación en el historial del proyecto, pero las personas que extraen de su repositorio no tendrán problemas cuando actualicen. No está funcionando de manera automatizada en su ejemplo, por lo que debe editar 'myfile' (para eliminar la línea 2), hacer
git add myfile
ygit commit
lidiar con el conflicto. Luego terminarás con cuatro commits en tu historial, con commit 4 revertiendo commit 2.Si a nadie le importa que su historial cambie, puede volver a escribirlo y eliminar commit 2 (opción 2). La manera fácil de hacer esto es usarlo
git rebase -i 8230fa3
. Esto lo colocará en un editor y puede elegir no incluir el compromiso erróneo eliminando el compromiso (y manteniendo la "selección" al lado de los otros mensajes de confirmación. Lea sobre las consecuencias de hacerlo .fuente
Aproximación 1
Primero obtenga el hash de confirmación (ej .: 1406cd61) que necesita revertir. la solución simple estará debajo del comando,
si ha confirmado más cambios relacionados con los archivos 1406cd61 después de la confirmación 1406cd61, el comando anterior simple no funcionará. Luego tienes que hacer los pasos a continuación, que es recoger cerezas.
Aproximacion 2
Siga las siguientes acciones, ya que estamos usando --force necesita tener derechos de administrador sobre el repositorio de git para hacer esto.
Paso 1: busque el compromiso antes del compromiso que desea eliminar
git log
Paso 2: Revisa ese commit
git checkout <commit hash>
Paso 3: Crea una nueva sucursal usando tu confirmación de pago actual
git checkout -b <new branch>
Paso 4: ahora debe agregar la confirmación después de la confirmación eliminada
git cherry-pick <commit hash>
Paso 5: Ahora repita el Paso 4 para todas las demás confirmaciones que desea mantener.
Paso 6: Una vez que todas las confirmaciones se han agregado a su nueva sucursal y se han confirmado. Verifique que todo esté en el estado correcto y funcione según lo previsto. Verifique que todo se haya comprometido:
git status
Paso 7: cambia a tu rama rota
git checkout <broken branch>
Paso 8: Ahora realice un restablecimiento completo en la rama rota a la confirmación antes de la que desea eliminar
git reset --hard <commit hash>
Paso 9: combine su rama fija en esta rama
git merge <branch name>
Paso 10: Empuje los cambios combinados nuevamente al origen. ADVERTENCIA: ¡Esto sobrescribirá el repositorio remoto!
git push --force origin <branch name>
Puede hacer el proceso sin crear una nueva rama reemplazando los pasos 2 y 3 con el paso 8 y luego no llevar a cabo los pasos 7 y 9.
fuente
Puede eliminar confirmaciones no deseadas con
git rebase
. Supongamos que incluyó algunas confirmaciones de la rama de tema de un compañero de trabajo en su rama de tema, pero luego decida que no desea esas confirmaciones.En este punto, su editor de texto abrirá la vista interactiva de rebase. Por ejemplo
Si el rebase no tuvo éxito, elimine la rama temporal e intente otra estrategia. De lo contrario, continúe con las siguientes instrucciones.
Si está empujando su rama de tema a un control remoto, es posible que deba forzar el empuje ya que el historial de confirmación ha cambiado. Si otros están trabajando en la misma rama, avíseles.
fuente
De otras respuestas aquí, estaba un poco confundido con cómo
git rebase -i
podría usarse para eliminar una confirmación, así que espero que esté bien anotar mi caso de prueba aquí (muy similar al OP).Aquí hay un
bash
script que puede pegar para crear un repositorio de prueba en la/tmp
carpeta:En este punto, tenemos una
file.txt
con estos contenidos:En este punto, HEAD está en la 5ª confirmación, HEAD ~ 1 sería la 4ª y HEAD ~ 4 sería la primera confirmación (por lo que HEAD ~ 5 no existiría). Digamos que queremos eliminar la tercera confirmación: podemos emitir este comando en el
myrepo_git
directorio:( Tenga en cuenta que los
git rebase -i HEAD~5
resultados con "fatal: se necesitaba una única revisión; HEAD ~ 5" no válido. ) Se abrirá un editor de texto (ver captura de pantalla en la respuesta de @Dennis ) con estos contenidos:Entonces obtenemos todos los commits desde (pero sin incluir ) nuestro HEAD ~ 4 solicitado. Elimine la línea
pick 448c212 3rd git commit
y guarde el archivo; obtendrá esta respuesta degit rebase
:En este punto, abra myrepo_git /
folder/file.txt
en un editor de texto; verá que ha sido modificado:Básicamente,
git
ve que cuando HEAD llegó a la segunda confirmación, había contenido deaaaa
+bbbb
; y luego tiene un parche decccc
+ agregadodddd
que no sabe cómo agregar al contenido existente.Entonces, aquí
git
no puede decidir por usted, es usted quien tiene que tomar una decisión: al eliminar la tercera confirmación, mantiene los cambios introducidos por ella (aquí, la líneacccc
), o no lo hace. Si no lo hace, simplemente elimine las líneas adicionales, incluida lacccc
,folder/file.txt
usando un editor de texto, para que se vea así:... y luego guardar
folder/file.txt
. Ahora puede emitir los siguientes comandos en elmyrepo_git
directorio:Ah, entonces para marcar que hemos resuelto el conflicto, debemos hacer
git add
lo siguientefolder/file.txt
antes de hacergit rebase --continue
:Aquí se abre nuevamente un editor de texto, que muestra la línea
4th git commit
; aquí tenemos la oportunidad de cambiar el mensaje de confirmación (que en este caso podría cambiarse significativamente4th (and removed 3rd) commit
o similar). Digamos que no quiere, así que salga del editor de texto sin guardar; una vez que hagas eso, obtendrás:En este punto, ahora tiene un historial como este (que también podría inspeccionar con say
gitk .
u otras herramientas) del contenido defolder/file.txt
(con, aparentemente, marcas de tiempo sin cambios de los commits originales):Y si anteriormente, decidimos mantener la línea
cccc
(el contenido del tercer git commit que eliminamos), habríamos tenido:Bueno, este era el tipo de lectura que esperaba haber encontrado, para comenzar a entender cómo
git rebase
funciona en términos de eliminar commits / revisiones; así que espero que pueda ayudar a otros también ...fuente
Por lo tanto, parece que la confirmación incorrecta se incorporó en una confirmación de fusión en algún momento. ¿Ya se ha retirado su compromiso de fusión? Si es así, entonces querrás usar
git revert
; Tendrás que apretar los dientes y superar los conflictos. Si no, entonces posiblemente podría volver a crear un rebase o revertir, pero puede hacerlo antes de la confirmación de fusión y luego rehacer la fusión.Realmente no hay mucha ayuda que podamos brindarle para el primer caso. Después de intentar la reversión y descubrir que la automática falló, debe examinar los conflictos y solucionarlos adecuadamente. Este es exactamente el mismo proceso que arreglar conflictos de fusión; puede usar
git status
para ver dónde están los conflictos, editar los archivos no fusionados, encontrar los trozos en conflicto, descubrir cómo resolverlos, agregar los archivos en conflicto y finalmente confirmar. Si lo usagit commit
solo (no-m <message>
), el mensaje que aparece en su editor debe ser el mensaje de plantilla creado porgit revert
; puede agregar una nota sobre cómo solucionó los conflictos, luego guardar y salir para confirmar.Para el segundo caso, solucionar el problema antes de la fusión, hay dos subcajas, dependiendo de si ha trabajado más desde la fusión. Si no lo ha hecho, puede simplemente
git reset --hard HEAD^
eliminar la fusión, hacer la reversión y luego rehacer la fusión. Pero supongo que sí. Entonces, terminarás haciendo algo como esto:git rebase -i <something before the bad commit> <temporary branch>
para eliminar la mala confirmación)git rebase --onto <temporary branch> <old merge commit> <real branch>
fuente
Así que hiciste un trabajo y lo empujaste, llamémosles commits A y B. Tu compañero de trabajo también hizo algo de trabajo, comete C y D. Fusionaste a tus compañeros de trabajo con los tuyos (fusionar commit E), luego continuaste trabajando, comprometiste eso, también (cometer F), y descubrió que su compañero de trabajo cambió algunas cosas que no debería haber cambiado.
Entonces su historial de confirmación se ve así:
Realmente quieres deshacerte de C, D y D '. Como usted dice que fusionó el trabajo de sus compañeros de trabajo con los suyos, estos commits ya están "ahí fuera", por lo que eliminar los commits utilizando, por ejemplo, git rebase es un no-no. Créeme, lo he intentado.
Ahora, veo dos salidas:
si aún no ha presionado E y F a su compañero de trabajo ni a ninguna otra persona (generalmente su servidor "de origen"), aún podría eliminarlos del historial por el momento. Este es tu trabajo que quieres guardar. Esto se puede hacer con un
(reemplace D 'con el hash de confirmación real que puede obtener de un
git log
En este punto, las confirmaciones E y F han desaparecido y los cambios son cambios no confirmados en su espacio de trabajo local nuevamente. En este punto, los movería a una rama o los convertiría en un parche y los guardaría para más adelante. Ahora, revierta el trabajo de su compañero de trabajo, ya sea automáticamente con un
git revert
o manualmente. Cuando hayas hecho eso, repite tu trabajo además de eso. Es posible que tenga conflictos de fusión, pero al menos estarán en el código que escribió, en lugar del código de su compañero de trabajo.Si ya ha presionado el trabajo que hizo después de las confirmaciones de su compañero de trabajo, aún puede intentar obtener un "parche inverso" ya sea manualmente o usando
git revert
, pero dado que su trabajo está "en el camino", por así decirlo, probablemente obtendrá más conflictos de fusión y más confusos. Parece que eso es en lo que terminaste ...fuente
git revert --strategy resolve si commit es una fusión: usa git revert --strategy resolve -m 1
fuente