¿Cómo avanzo y retrocedo entre confirmaciones en git?


104

Estoy haciendo un git bisecty después de llegar al compromiso problemático, ahora estoy tratando de dar un paso adelante / atrás para asegurarme de que estoy en el correcto.

yo se de HEAD^ que retrocedemos en la historia, pero ¿hay otro atajo para avanzar (hacia un compromiso específico en el futuro) así:

A - B - C(HEAD) - D - E - F

Sé que mi objetivo es F y quiero pasar de C a D .


NOTA: esto no es un duplicado de Git: cómo moverse hacia adelante y hacia atrás entre confirmaciones , mi pregunta es ligeramente diferente y no se responde allí



git checkout -b new_branch HEAD~4para retroceder 4 confirmaciones de HEAD como en stackoverflow.com/a/4940090/911945
Anton Tarasenko

Respuestas:


57

He experimentado un poco y esto parece ser el truco para navegar hacia adelante ( editar : funciona bien solo cuando tiene un historial lineal sin fusiones confirmadas):

git checkout $(git rev-list --topo-order HEAD..towards | tail -1)

donde towardses un SHA1 de la confirmación o una etiqueta.

Explicación:

  • el comando dentro $()significa: obtenga todas las confirmaciones entre la actual HEADy la towardsconfirmación (excluyendo HEAD), y ordénelas en el orden de precedencia (como en el git logpredeterminado, en lugar del orden cronológico que es extrañamente el predeterminado rev-list), y luego tome el último (tail ), es decir, al que queremos ir.
  • esto se evalúa en la subcapa y se pasa a git checkoutpara realizar un pago.

Puede definir una función accesible como un alias de espera de parámetros en su .profilearchivo para navegar hacia la confirmación en particular:

# Go forward in Git commit hierarchy, towards particular commit 
# Usage:
#  gofwd v1.2.7
# Does nothing when the parameter is not specified.
gofwd() {
  git checkout $(git rev-list --topo-order HEAD.."$*" | tail -1)
}

# Go back in Git commit hierarchy
# Usage: 
#  goback
alias goback='git checkout HEAD~'

2
Avanzar funciona bien en partes rectas del historial, pero entra en bucles cuando se encuentra una fusión.
Kostas

Sí, en realidad no lo he probado en fusiones. Intentaré echar un vistazo en el tiempo libre, pero tengo pocos incentivos temporalmente, ya que hemos acordado tener una historia estrictamente lineal en nuestro proyecto;)
jakub.g

2
¡Gran respuesta! Modificado para especificar automáticamente la rama actual: stackoverflow.com/a/23172256/480608
Raine Revere

Esto es incorrecto. git logmuestra las confirmaciones en orden cronológico, por defecto, igual que rev-list, excepto cuando se usa la --graphbandera.
papiro

Evidencia bastante convincente de que git es demasiado complejo. Para algo que suele ser tan simple como Deshacer o Rehacer, aquí tenemos una lista loca de respuestas conflictivas. Y ni siquiera he entrado en ninguna de las respuestas vinculadas. FWIW, probé una versión de esto con un conjunto lineal simple de confirmaciones y finalmente me di por vencido.
Snowcrash

49

Todo lo que necesita para obtener un estado de cabeza claro, no separado, es reiniciar, no pagar.

git reset HEAD@{1}

5
o git reset "HEAD@{1}"en ciertas conchas como fish y powershell ... git reflogtambién puede ser útil para encontrar la confirmación correcta.
Steve Cook

1
Utilice siempre comillas simples en los comandos de shell a menos que desee explícitamente que el shell intente interpretar / expandir el contenido. Esto es especialmente importante en casos como este, donde el objetivo es evitar que el shell interprete caracteres especiales. De esa manera, no necesita saber si la cadena contiene algo que sea problemático.
Chris Page

Hice eso para mirar atrás en el tiempo, luego lo hice git reset HEADpara volver a donde estaba ... ahora no tengo idea de en qué estado se encuentra mi repositorio y todo da miedo. ¿Qué debería hacer ahora?
theonlygusti

47

Creo que puedes hacer:

git reset HEAD@{1}

Para avanzar un compromiso en el tiempo. Para avanzar en varias confirmaciones, use HEAD @ {2}, HEAD @ {3}, etc.


20

Esto es lo que estoy usando para navegar hacia adelante y hacia atrás.

pasar a la siguiente confirmación

function n() {
    git log --reverse --pretty=%H master | grep -A 1 $(git rev-parse HEAD) | tail -n1 | xargs git checkout
}

pasando a la confirmación anterior

function p() {
    git checkout HEAD^1
}

¡Gracias! ¡Estoy usando esto ahora! Notas para otros principiantes como yo : para volver a adjuntar HEAD, git checkout <current branch>adjunta a la última confirmación. git checkout -b <new-branch-name>de la confirmación actual permite cambios en la nueva rama. git rebase -itambién funciona. Además , nombré mi n()función nx()para evitar conflictos con el administrador de versiones del nodo "n". ¡Asegúrate de comprobar los alias!
Steven Choi

function () {...} es para crear un archivo de scripting bash Unix / Linux, vengo de Windows, un poco difícil de entender para mí en primer lugar
IcyBrk

9

Digamos que F es la última confirmación en trunk(inserte su propio nombre de rama aquí) ... puede referirse a él como trunk~0(o simplemente trunk), E como trunk~1, D como, trunk~2etc.

Eche un vistazo a su reflog para ver más formas de nombrar las confirmaciones.


1
~ retrocede, no avanza, tronco ~ 2 es A
EmmanuelMess

Si. Esta respuesta supone que tiene una rama llamada troncal apuntando a F, y que sabe en qué parte del historial de esa rama desea moverse. No está tratando de avanzar en relación con HEAD, sino menos atrás en relación con el tronco.
Inútil

@EmmanuelMess ¿cómo es trunk~2A?
theonlygusti

@theonlygusti Te alejas de HEAD dos veces.
EmmanuelMess

Todavía está asumiendo que la rama trunky su corriente HEADson idénticas, lo que no se muestra en la pregunta, lo que he dicho que no es lo que estoy asumiendo, y que es muy poco probable a la mitad de unbisect
Inútil

3

Atravesar hacia atrás es trivial ya que estás bajando por el árbol y siempre hay un camino por recorrer

  function git_down
        git checkout HEAD^
  end

Al atravesar hacia adelante, se está moviendo hacia arriba en el árbol, por lo que debe ser explícito a qué rama se dirige:

  function git_up 
        git log --reverse --pretty=%H $argv | grep -A 1 (git rev-parse HEAD) | tail -n1 | xargs git checkout
  end

Uso: git down,git up <branch-name>


Ir hacia atrás tampoco es del todo único, cuando se trata de fusiones. Aunque HEAD^suele ser un valor predeterminado razonable.
kdb

2

Si quieres ver el futuro, puedes hacer este truco, ya que Git no tiene un comando estricto para ello.

git log --reverse COMMIT_HASH..

Ejemplo

Lista de hashes del historial de registros:

A
B
C -> put this
D

con el comando git log --reverse C.., en la salida verá B y A .


1

Probablemente no sea la forma más agradable, pero puede usar git logpara ver la lista de confirmaciones y luego usar git checkout [sha1 of D]para pasar a D.


6
No lo entiendo, si está en C, entonces git log solo le mostrará C, B y A.
Bilthon

Ok, lo tengo, pero tendrás que hacer un git-log complicado como se indica en el enlace proporcionado por VonC
Bilthon

1

Acabo de hacer una prueba sobre esto. digamos, por ejemplo, que está en la rama maestra. Entonces haga:

git checkout HEAD@{3}

Entonces, la cabeza se desprende, y luego puede intentarlo nuevamente para ir a cualquier otra confirmación:

git checkout HEAD@{4}

Una vez que haya terminado de mirar a su alrededor, puede volver a su estado original simplemente revisando esa sucursal. En mi ejemplo: rama maestra

git checkout master

Si no desea ir al estado original y desea mantener una de las confirmaciones como su cabeza y continuar desde allí, entonces debe ramificarse desde allí. por ejemplo, después de "git checkout HEAD @ {4}", puede emitir

git checkout -b MyNewBranch

0

Como solución alternativa, puede volver a HEAD con

git checkout <branch>

Y luego pasa al compromiso que te gustaría, con

git checkout HEAD~<offset>

0

Si está utilizando vs code, Git history es un complemento increíble donde puede ver las confirmaciones de manera eficiente y verificar su contenido en el propio editor. mira el enlace


0
branchName=master; commitInOrder=1; git checkout $(git log --pretty=%H "${branchName}" | tac | head -n "${commitInOrder}" | tail -n 1)

dónde:

branchName es igual al nombre de la rama

commitInOrder es igual a una confirmación en orden desde la primera confirmación en la rama seleccionada (por lo que 1 es la primera confirmación, 2 es la segunda confirmación en la rama, etc.)

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.