tag comandos git git-revert

comandos - git rebase



Revertir una serie de fusiones y confirmaciones en Git(sin reescribir el historial) (4)

Contexto

Uno de mis compañeros de equipo empujó por error algunos compromisos a nuestra rama de desarrollo principal. Somos un equipo pequeño, colocado. Nuestro repositorio remoto está alojado en un servidor interno.

Aquí está la parte superior de nuestro registro de confirmación (todas estas confirmaciones ya se han enviado):

$ git log develop -6 --pretty=oneline --abbrev-commit faada93 Merge branch ''develop'' of <our_repo_path>.git 244d174 Support classes again a97a877 Pruned all unused references (again). 8c29252 Merge branch ''develop'' of <our_repo_path>.git a78b993 Support models & methods - product types & categories da8b496 Resolved JIRA issue PPF-182

da8b496 es el último compromiso que queríamos mantener en nuestra rama de develop , por lo que necesitamos revertir los 5 últimos compromisos. Creamos una nueva rama desde 8c29252 para continuar trabajando en una "rama de características".

Intenté muchas cosas, guiado por esta respuesta y este post de Linus , y terminé haciendo lo que puedes ver en mi historial de terminales a continuación. Pero no estoy seguro de si lo que terminé haciendo es "la forma correcta". La información que encontré era compleja; No pude discernir una "mejor solución" para este problema en particular.

Pregunta

¿Fue el enfoque que elegí (ver detalles a continuación) una buena manera de revertir esos 5 compromisos, sin dañar nuestra historia? ¿Hay una manera más fácil o "más correcta" de lograr lo mismo?

Entre otras cosas, consideré crear una nueva rama desde da8b496 ( git checkout -b new-develop da8b496 ) y abandonar nuestra rama de develop actual, pero eso no me pareció correcto.

Lo que acabé haciendo (detalles)

Primero, creé una nueva sucursal para los confirmaciones a78b993 y 8c29252 , porque estas confirmaciones contienen el trabajo que queremos mantener y eventualmente se fusionan con nuestra principal sucursal de desarrollo.

$ git checkout -b new-feature-brach 8c29252

Entonces comencé a revertir los compromisos ofensivos en nuestra rama de desarrollo.

Intenté esto primero, pero no funcionó (probablemente porque algunas de las confirmaciones se fusionan):

$ git revert a78b993..HEAD error: a cherry-pick or revert is already in progress hint: try "git cherry-pick (--continue | --quit | --abort)" fatal: revert failed

Así que ... Revertí manualmente cada compromiso en su lugar; uno a uno:

$ git revert -m 1 faada93 [develop 40965a5] Revert "Merge branch ''develop'' of <our_repo_path>.git" 8 files changed, 167 insertions(+), 3 deletions(-) $ git revert 244d174 [develop 3cebd68] Revert "Support classes again" 45 files changed, 557 insertions(+), 1572 deletions(-) (list of affected files) $ git revert a97a877 error: could not revert a97a877... Pruned all unused references (again). hint: after resolving the conflicts, mark the corrected paths hint: with ''git add <paths>'' or ''git rm <paths>'' hint: and commit the result with ''git commit'' $ git mergetool Merging: exampleFile1.cs exampleFile2.cs Deleted merge conflict for ''exampleFile1.cs'': {local}: deleted {remote}: modified file Use (m)odified or (d)eleted file, or (a)bort? m Deleted merge conflict for ''exampleFile2.cs'': {local}: deleted {remote}: modified file Use (m)odified or (d)eleted file, or (a)bort? m $ git commit -m "Adding files to be reverted along with the next commit." [develop 15bc02b] Adding files to be able to revert the next commit in line. 2 files changed, 239 insertions(+) (list of affected files here) $ git revert -m 1 8c29252 # On branch develop # Your branch is ahead of ''origin/develop'' by 3 commits. # (use "git push" to publish your local commits) # # Untracked files: # (use "git add <file>..." to include in what will be committed) # # exampleFile1.cs.orig # exampleFile2.cs.orig nothing added to commit but untracked files present (use "git add" to track) $ git revert a78b993 [develop 841e77c] Revert "Support models & methods - product types & categories" 2 files changed, 239 deletions(-) (list of affected files here)

Confirmar registro después de que se hicieron todos los revertidos:

$ git log develop -10 --pretty=oneline --abbrev-commit 841e77c Revert "Support models & methods - product types & categories" 15bc02b Adding files to be able to revert the next commit in line. 3cebd68 Revert "Support classes again" 40965a5 Revert "Merge branch ''develop'' of <our_repo_path>.git" faada93 Merge branch ''develop'' of <our_repo_path>.git 244d174 Support classes again a97a877 Pruned all unused references (again). 8c29252 Merge branch ''develop'' of <our_repo_path>.git a78b993 Support models & methods - product types & categories da8b496 Resolved JIRA issue PPF-182

Gráfico después de revertir:

$ git log --graph --oneline -8 develop * 841e77c Revert "Support models & methods - product types & categories" * 15bc02b Adding files to be able to revert the next commit in line. * 3cebd68 Revert "Support classes again" * 40965a5 Revert "Merge branch ''develop'' of <our_repo_path>.git" * faada93 Merge branch ''develop'' of <our_repo_path>.git |/ | * a97a877 Pruned all unused references (again). | * 8c29252 Merge branch ''develop'' of <our_repo_path>.git | |/ | | * da8b496 Resolved JIRA issue PPF-182

Me parece correcto. Por último, elimino algunos archivos de copia de seguridad que no deseo conservar:

$ git clean -fd (list of affected files here)

El estado actual es limpio:

$ git status # On branch develop # Your branch is ahead of ''origin/develop'' by 4 commits. # (use "git push" to publish your local commits) # nothing to commit, working directory clean

Y luego empujo todo de nuevo al mando a distancia:

git push origin develop


A pesar de que su historial ha cambiado, puede crear ramas que le permitan retroceder y experimentar. Git significa nunca tener que decir "deberías haberlo hecho". Si convergen en una realidad que le guste más, entonces hágalo. De lo contrario, tíralo.

Los siguientes ejemplos crearán nuevas sucursales que dejarán todo lo demás en su repositorio solo.

Alternativa 1: git revertir

Primero crea una rama de rasguño en el punto donde comenzaste tu aventura.

$ git checkout -b tmp-revert faada93

Al especificar un rango de confirmación, git revert deshará múltiples confirmaciones.

$ git revert da8b496..faada93

Alternativa 2: git commit-tree

Considere el diagrama a continuación de Git Internals - Git Objects , sección 10.2 en la segunda edición de Pro Git por Scott Chacon y Ben Straub. La confirmación superior ("tercera confirmación") tiene un hash SHA1 que comienza en 1a410e . En el contexto de esta historia, 1a410e^{tree} se resolvería en 3c4e9c , es decir, el objeto de árbol inmediatamente a la derecha del tercer commit.

Figura 151 de Pro Git , 2ª ed.

Estudia este modelo para entender cómo git rastrea el contenido . Crear una cuarta cuarta confirmación cuyo árbol sea idéntico a la segunda confirmación (es decir, 0155eb ) agregaría un nuevo objeto de confirmación que compartiría o "señalaría" el árbol y las manchas existentes en lugar de agregar nuevos objetos duplicados.

Siga leyendo para aprender cómo realizar esta costura de bajo nivel con git commit-tree .

Comience por crear otra rama temporal para trabajar.

$ git checkout -b tmp-ctree faada93

En este punto, desea crear una nueva confirmación donde su árbol (es decir, el código confirmado) es idéntico al de da8b496 , la última confirmación que desea mantener. Este árbol es direccionable directamente en git: da8b496^{tree} .

git commit-tree es "fontanería", un comando de bajo nivel en git, a diferencia de "porcelana". Puede parecer incómodo o desconocido de usar, pero en este caso brinda un control preciso del resultado que desea.

Cree un nuevo compromiso sin da8b496 cuyo árbol sea el mismo que el de da8b496 y cuyo padre ( -p ) sea la punta de la rama actual, faada93 en su caso. Tenga en cuenta que git commit-tree lee el mensaje de confirmación de la nueva confirmación en la entrada estándar, que el comando a continuación suministra con el comando echo .

$ echo Revert back to da8b496 | / git commit-tree da8b496^{tree} -p $(git rev-parse tmp-ctree) new-commit-sha1

La parte en cursiva de arriba no es parte del comando. Indica que git commit-tree genera el hash SHA1 del commit recién creado. Al conocer el nuevo SHA1 de confirmación, puede mover la rama a ese punto, por ejemplo ,

$ git merge new-commit-sha1

En el comando anterior, reemplace new-commit-sha1 con la salida de git commit-tree . (Podría hacer lo mismo con git reset --hard new-commit-sha1 , pero el hard reset es una herramienta git reset --hard new-commit-sha1 donde se evita el uso casual).

Podría rodar todo lo anterior en un solo comando compuesto.

$ git merge --ff-only $(echo Revert back to da8b496 | / git commit-tree da8b496^{tree} -p $(git rev-parse tmp-ctree))

El cambio --ff-only a git merge está pensado para evitar sorpresas. Su intención es que el nuevo compromiso sea un avance rápido o un descendiente del actual jefe de rama: ¡su hijo inmediato, de hecho!

Limpiar

Para eliminar las ramas temporales de arriba, cambie a otra y dispare, Sr. McManus. Tus otras ramas serán como las dejaste.

$ git checkout develop $ git branch -D tmp-revert tmp-ctree

Los dos deben ser idénticos, como se puede verificar con

$ git diff tmp-revert tmp-ctree

Para mantener uno, fusionalo en tu rama de develop .

$ git checkout develop $ git merge --ff-only tmp-ctree $ git push origin develop


Lo que estás tratando de hacer es muy arriesgado.

de hecho, puede revertir y eliminar las confirmaciones que ya ha enviado al repositorio, pero si alguien ya ha realizado los cambios y tiene el commitId que va a eliminar, el repositorio puede volverse "inestable" y git no podrá hacerlo. maneja el tirón y los empujes desde que eliminaste la confirmación que ahora se elimina del historial.

Haga esto (revertir y eliminar la confirmación) solo y solo si nadie ha tirado todavía de esta confirmación.


Puedo sugerir que esto se pueda considerar un duplicado de esta respuesta: haga de la rama git actual una rama maestra

La excelente solución de Jefromi fue:

[git branch better_branch <last good commit>] git checkout better_branch git merge --strategy=ours master # keep the content of this branch, but record a merge git checkout master git merge better_branch # fast-forward master up to the merge


Usted tiene un pequeño equipo de ubicación conjunta, por lo que la comunicación no es un problema. Haga que el historial de confirmaciones se vea como debería haber sido:

git branch -f develop dab4896 git branch newfeature 8c29252 git push -f origin develop newfeature

y que todos recojan. Has terminado

Este tipo de error es una de las razones para reescribir.