En términos sencillos, ¿qué hace "git reset"?

Resuelto Bite code asked hace 14 años • 7 respuestas

He visto publicaciones interesantes que explican sutilezas sobre git reset.

Desafortunadamente, cuanto más leo sobre esto, más parece que no lo entiendo completamente. Vengo de una experiencia en SVN y Git es un paradigma completamente nuevo. Me volví voluble fácilmente, pero Git es mucho más técnico.

Creo git resetque está cerca hg revert, pero parece que hay diferencias.

Entonces, ¿qué hace exactamente git reset? Incluya explicaciones detalladas sobre:

  • las opciones --hard, --softy --merge;
  • la extraña notación que usas con HEADtales como HEAD^y HEAD~1;
  • casos de uso concretos y flujos de trabajo;
  • consecuencias en la copia de trabajo, el HEADy su nivel de estrés global.
Bite code avatar Mar 27 '10 23:03 Bite code
Aceptado

En general, git resetla función de es tomar la rama actual y restablecerla para que apunte a otro lugar, y posiblemente traer consigo el índice y el árbol de trabajo. Más concretamente, si su rama maestra (actualmente desprotegida) es así:

- A - B - C (HEAD, master)

y te das cuenta de que quieres que master apunte a B, no a C, usarás git reset Bpara moverlo allí:

- A - B (HEAD, master)      # - C is still here, but there's no branch pointing to it anymore

Digresión: Esto es diferente de una compra. Si ejecutaras git checkout B, obtendrías esto:

- A - B (HEAD) - C (master)

Has terminado en un estado HEAD desapegado. HEAD, árbol de trabajo, índice todo coincide B, pero la rama maestra quedó atrás en C. Si realiza una nueva confirmación Den este punto, obtendrá esto, que probablemente no sea lo que desea:

- A - B - C (master)
       \
        D (HEAD)

Recuerde, restablecer no realiza confirmaciones, simplemente actualiza una rama (que es un puntero a una confirmación) para que apunte a una confirmación diferente. El resto son sólo detalles de lo que sucede con su índice y árbol de trabajo.

Casos de uso

Cubro muchos de los principales casos de uso en git resetmis descripciones de las distintas opciones en la siguiente sección. Realmente se puede utilizar para una amplia variedad de cosas; el hilo común es que todos ellos implican restablecer la rama, el índice y/o el árbol de trabajo para que apunte o coincida con una confirmación determinada.

Cosas con las que tener cuidado

  • --hardpuede hacer que usted realmente pierda el trabajo. Modifica tu árbol de trabajo.

  • git reset [options] commitpuede hacer que (en cierto modo) pierda confirmaciones. En el ejemplo del juguete anterior, perdimos el compromiso C. Todavía está en el repositorio y puede encontrarlo mirando git reflog show HEADo git reflog show master, pero ya no se puede acceder a él desde ninguna sucursal.

  • Git elimina permanentemente dichas confirmaciones después de 30 días, pero hasta entonces puedes recuperar C apuntando una rama hacia él nuevamente ( git checkout C; git branch <new branch name>).

Argumentos

Parafraseando la página de manual, el uso más común es el del formulario git reset [<commit>] [paths...], que restablecerá las rutas dadas a su estado desde la confirmación dada. Si no se proporcionan las rutas, se restablece todo el árbol y, si no se proporciona la confirmación, se considera HEAD (la confirmación actual). Este es un patrón común en los comandos de git (por ejemplo, checkout, diff, log, aunque la semántica exacta varía), por lo que no debería sorprender demasiado.

Por ejemplo, git reset other-branch path/to/foorestablece todo en la ruta/a/foo a su estado en otra rama, git reset -- .restablece el directorio actual a su estado en HEAD y simplemente git resetrestablece todo a su estado en HEAD.

El árbol de trabajo principal y las opciones de índice.

Hay cuatro opciones principales para controlar lo que sucede con su árbol de trabajo y su índice durante el reinicio.

Recuerde, el índice es el "área de preparación" de git: es donde van las cosas cuando dice prepararse git addpara comprometerse.

  • --hardhace que todo coincida con el compromiso que has restablecido. Probablemente esto sea lo más fácil de entender. Todos sus cambios locales se ven afectados. Un uso principal es eliminar su trabajo pero no cambiar las confirmaciones: git reset --hardsignifica git reset --hard HEAD, es decir, no cambiar la rama pero deshacerse de todos los cambios locales. El otro es simplemente mover una rama de un lugar a otro y mantener sincronizado el índice/árbol de trabajo. Este es el que realmente te puede hacer perder trabajo, porque modifica tu árbol de trabajo. Asegúrese de desechar el trabajo local antes de ejecutar cualquiera reset --hard.

  • --mixedes el valor predeterminado, es decir, git resetsignifica git reset --mixed. Restablece el índice, pero no el árbol de trabajo. Esto significa que todos sus archivos están intactos, pero cualquier diferencia entre la confirmación original y la que restableció se mostrará como modificaciones locales (o archivos sin seguimiento) con estado git. Utilízalo cuando te des cuenta de que has realizado algunas confirmaciones incorrectas, pero quieres conservar todo el trabajo que has realizado para poder arreglarlo y volver a confirmarlo. Para confirmar, deberá agregar archivos al índice nuevamente ( git add ...).

  • --softno toca el índice ni el árbol de trabajo. Todos sus archivos están intactos como con --mixed, pero todos los cambios se muestran como changes to be committedcon el estado de git (es decir, registrados en preparación para la confirmación). Use esto cuando se dé cuenta de que ha realizado algunas confirmaciones incorrectas, pero todo el trabajo está bien; todo lo que necesita hacer es volver a confirmarlo de manera diferente. El índice no se modifica, por lo que puede confirmar inmediatamente si lo desea; la confirmación resultante tendrá el mismo contenido que tenía antes de restablecer.

  • --mergese agregó recientemente y está destinado a ayudarlo a cancelar una combinación fallida. Esto es necesario porque git mergeen realidad le permitirá intentar una fusión con un árbol de trabajo sucio (uno con modificaciones locales) siempre que esas modificaciones estén en archivos que no se vean afectados por la fusión. git reset --mergerestablece el índice (como --mixed: todos los cambios se muestran como modificaciones locales) y restablece los archivos afectados por la fusión, pero deja los demás en paz. Con suerte, esto restaurará todo a como estaba antes de la mala fusión. Generalmente lo usarás como git reset --merge(es decir git reset --merge HEAD) porque solo deseas restablecer la fusión, no mover la rama. ( HEADaún no se ha actualizado porque falló la fusión)

    Para ser más concreto, supongamos que ha modificado los archivos A y B e intenta fusionarlos en una rama que modificó los archivos C y D. La fusión falla por algún motivo y decide abortarla. Tu usas git reset --merge. Devuelve C y D a cómo estaban en HEAD, pero deja las modificaciones a A y B solas, ya que no formaban parte del intento de fusión.

¿Quiere saber más?

Creo que man git resetes bastante bueno para esto; aunque tal vez necesites un poco de idea de cómo funciona git para que realmente lo entiendas. En particular, si se toma el tiempo para leerlas detenidamente, esas tablas que detallan los estados de los archivos en el índice y el árbol de trabajo para las distintas opciones y casos son muy, muy útiles. (Pero sí, son muy densos: transmiten una gran cantidad de la información anterior de una forma muy concisa).

Notación extraña

La "notación extraña" ( HEAD^y HEAD~1) que mencionas es simplemente una abreviatura para especificar confirmaciones, sin tener que usar un nombre hash como 3ebe3f6. Está completamente documentado en la sección "especificar revisiones" de la página de manual de git-rev-parse, con muchos ejemplos y sintaxis relacionada. El signo de intercalación y la tilde en realidad significan cosas diferentes :

  • HEAD~es la abreviatura de HEAD~1y significa el primer padre de la confirmación. HEAD~2significa el primer padre del compromiso. Piense en HEAD~n"n confirmaciones antes de HEAD" o "el ancestro de enésima generación de HEAD".
  • HEAD^(o HEAD^1) también significa el primer padre de la confirmación. HEAD^2significa el segundo padre de la confirmación. Recuerde, una confirmación de fusión normal tiene dos padres: el primer padre es la confirmación fusionada y el segundo padre es la confirmación que se fusionó. En general, las fusiones pueden tener muchos padres arbitrariamente (fusiones de pulpo).
  • Los operadores ^y ~se pueden encadenar, como en HEAD~3^2, el segundo padre del antepasado de tercera generación de HEAD, HEAD^^2, el segundo padre del primer padre de HEAD, o incluso HEAD^^^, lo que equivale a HEAD~3.

signo de intercalación y tilde

Cascabel avatar Mar 27 '2010 16:03 Cascabel

Recuerda que en gittienes:

  • el HEADpuntero , que te indica en qué compromiso estás trabajando
  • el árbol de trabajo , que representa el estado de los archivos en su sistema
  • el área de preparación (también llamada índice ), que "etapa" los cambios para que luego puedan confirmarse juntos

Incluya explicaciones detalladas sobre:

--hard, --softy --merge;

En orden creciente de peligrosidad:

  • --softse mueve HEADpero no toca el área de preparación ni el árbol de trabajo.
  • --mixedmueve HEADy actualiza el área de preparación, pero no el árbol de trabajo.
  • --mergemueve HEAD, restablece el área de preparación e intenta mover todos los cambios en su árbol de trabajo al nuevo árbol de trabajo.
  • --hardMueve HEAD y ajusta tu área de preparación y árbol de trabajo al nuevo HEAD, tirando todo a la basura.

casos de uso y flujos de trabajo concretos;

  • Úselo --softcuando desee pasar a otra confirmación y arreglar las cosas sin "perder su lugar". Es bastante raro que necesites esto.

--

# git reset --soft example
touch foo                            // Add a file, make some changes.
git add foo                          // 
git commit -m "bad commit message"   // Commit... D'oh, that was a mistake!
git reset --soft HEAD^               // Go back one commit and fix things.
git commit -m "good commit"          // There, now it's right.

--

  • Úselo --mixed(que es el valor predeterminado) cuando quiera ver cómo se ven las cosas en otra confirmación, pero no quiera perder ningún cambio que ya tenga.

  • Úselo --mergecuando desee mudarse a un nuevo lugar pero incorpore los cambios que ya tiene en el árbol de trabajo.

  • Úselo --hardpara borrar todo y comenzar de nuevo en la nueva confirmación.

John Feminella avatar Mar 27 '2010 17:03 John Feminella

La publicación Reset Demystified en el blog Pro Git ofrece una explicación muy obvia sobre git resety git checkout.

Después de toda la útil discusión al principio de esa publicación, el autor reduce las reglas a los siguientes tres simples pasos:

Básicamente eso es todo. El resetcomando sobrescribe estos tres árboles en un orden específico y se detiene cuando usted se lo indica.

  1. Mueva cualquier rama a la que apunte HEAD (deténgase si --soft)
  2. ENTONCES, haga que el Índice se vea así (deténgase aquí a menos que --hard)
  3. ENTONCES, haga que el Directorio de Trabajo se vea así

--mergeTambién hay --keepopciones, pero prefiero mantener las cosas más simples por ahora; eso será para otro artículo.

Daniel Hershcovich avatar Jul 19 '2011 14:07 Daniel Hershcovich

TL;DR

git resetrestablece Staging a la última confirmación. Úselo --hardpara restablecer también los archivos en su directorio de trabajo a la última confirmación.

VERSIÓN MÁS LARGA

Pero eso es obviamente simplista, de ahí las muchas respuestas bastante detalladas. Para mí tenía más sentido leer git reseten el contexto de deshacer cambios. Por ejemplo, vea esto:

Si git revert es una forma "segura" de deshacer cambios, puedes pensar en git reset como un método peligroso. Cuando deshaces con git reset (y ninguna referencia o reflog ya no hace referencia a las confirmaciones), no hay forma de recuperar la copia original; es una deshacer permanente. Se debe tener cuidado al utilizar esta herramienta, ya que es uno de los únicos comandos de Git que tiene el potencial de perder su trabajo.

Desde https://www.atlassian.com/git/tutorials/undoing-changes/git-reset

y esto

En el nivel de confirmación, restablecer es una forma de mover la punta de una rama a una confirmación diferente. Esto se puede utilizar para eliminar confirmaciones de la rama actual.

From https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting/commit-level-operations

Snowcrash avatar Jul 13 '2015 17:07 Snowcrash