¿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í

Kostas
fuente
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~'
jakub.g
fuente
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}
d3day
fuente
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.

w0utert
fuente
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
}
MK
fuente
¡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.

Inútil
fuente
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>

Dziamid
fuente
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 .

dimpiax
fuente
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.

generación bb
fuente
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
usuario1322977
fuente
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>
Patrizio Bertoni
fuente
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

Rahil Ahmad
fuente
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.)

invitado
fuente