¿Cómo pagar en Git por fecha?

314

Estoy trabajando en una regresión en el código fuente. Me gustaría decirle a Git: "verifique la fuente en función de una fecha / hora parametrizada". es posible?

También he realizado cambios en mi vista actual que no quiero perder. Idealmente, me gustaría alternar entre la fuente actual y alguna versión que me interese en base a una fecha anterior.

Amir Afghani
fuente
99
En caso de que no lo sepas, git bisect es bastante bueno para encontrar regresiones. Yo diría que use la sintaxis {hace 1 año}, como dijo Andy, para encontrar una confirmación buena y conocida, y luego úsela como git bisect goodpunto inicial .
MatrixFrog
Siento que este es un buen caso de uso tags.
Jess

Respuestas:

365

Para mantener sus cambios actuales

Puede mantener su trabajo escondido, sin comprometerlo, con git stash . Lo usarías git stash poppara recuperarlo. O puede (como dijo carleeto ) git commiten una rama separada.

Pago por fecha usando rev-parse

Puedes pagar un commit antes de una fecha específica usando rev-parse esto:

git checkout 'master@{1979-02-26 18:30:00}'

Puede encontrar más detalles sobre las opciones disponibles en el git-rev-parse .

Como se señaló en los comentarios, este método utiliza el registro de registros para encontrar la confirmación en su historial. Por defecto estas entradas caducan después de 90 días . Aunque la sintaxis para usar el reflog es menos detallada, solo puede retroceder 90 días.

Salida por fecha usando rev-list

La otra opción, que no usa el reflog, es usar rev-list para obtener el commit en un momento particular con:

git checkout `git rev-list -n 1 --first-parent --before="2009-07-27 13:37" master`

Tenga en cuenta --first-parent si solo desea su historial y no las versiones introducidas por una fusión. Eso es lo que generalmente quieres.

Andy
fuente
2
@Rocky ¿Puedes darnos más detalles Rocky? ¿Qué está ingresando en la línea de comando y por qué dice que no funciona? ¿Está recibiendo un mensaje de error?
Andy
8
@Rocky: El problema es que el parámetro debe estar entre comillas, de lo contrario bash separa los argumentos en los espacios. Tratar git co 'master@{2 days ago}'.
Mark Wilden
13
Nota: dependiendo de qué tan lejos retroceda, esto puede no funcionar porque utiliza el registro (que caduca después de un tiempo). Verá 'advertencia: el registro de' maestro 'solo vuelve a ...'. La solución de Rocky funcionará siempre. git checkoutgit rev-list -n 1 --before="2009-07-27 13:37" master
Mark Nadig
3
Edité su respuesta porque los backticks están en desuso y son difíciles de leer. $(...)Se prefieren las subcapas .
Amedee Van Gasse
1
@Andy ¡Feliz 40 cumpleaños, Andy! (suponiendo que eso sea lo que significa 1979-02-26 :))
David Blevins
123

La solución de Andy no me funciona. Aquí encontré otra forma:

git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`

Git: pago por fecha

Rocoso
fuente
3
Cuando ejecuto el comando anterior, ¿tengo error: unknown switch `n'alguna idea de cómo solucionar esto?
Tim
15

Parece que necesitas algo similar a esto: pago Git basado en la fecha

En otras palabras, usas rev-list para encontrar el commit y luego usas checkout para obtenerlo.

Si no desea perder sus cambios por etapas, lo más fácil sería crear una nueva rama y confirmarlos en esa rama. Siempre puede alternar entre las ramas.

Editar: el enlace está inactivo, así que aquí está el comando:

git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`
Carl
fuente
2
Gran enlace! Así que git checkout branch@{date}deja de funcionar cuando expira el reflog, pero puedes usarlo git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`.
cdunn2001
10

Para aquellos que prefieren una tubería para ordenar la sustitución

git rev-list -n1 --before=2013-7-4 master | xargs git checkout
Steven Penny
fuente
9

En mi caso, la -n 1opción no funciona. En Windows, descubrí que la siguiente secuencia de comandos funciona bien:

git rev-list -1 --before="2012-01-15 12:00" master

Esto devuelve el SHA del commit apropiado para la fecha dada y luego:

git checkout SHA
BartoszKP
fuente
4

La git rev-parsesolución propuesta por @Andy funciona bien si la fecha que le interesa es la fecha de confirmación . Sin embargo, si desea realizar el pago en función de la fecha del autor , rev-parseno funcionará, ya que no ofrece una opción para usar esa fecha para seleccionar las confirmaciones. En su lugar, puede usar lo siguiente.

git checkout $(
  git log --reverse --author-date-order --pretty=format:'%ai %H' master |
  awk '{hash = $4} $1 >= "2016-04-12" {print hash; exit 0 }
)

(Si también desea especificar el tiempo de uso $1 >= "2016-04-12" && $2 >= "11:37"en el predicado awk ).

Diomidis Spinellis
fuente
3

Yendo más allá con la rev-listopción, si desea encontrar la confirmación de fusión más reciente de su rama maestra en su rama de producción (como un ejemplo puramente hipotético):

git checkout `git rev-list -n 1 --merges --first-parent --before="2012-01-01" production`

Necesitaba encontrar el código que estaba en los servidores de producción a partir de una fecha determinada. Esto lo encontré para mí.

Egerlach
fuente
2

Si desea poder volver a la versión precisa del repositorio en el momento en que realiza una compilación, es mejor etiquetar la confirmación desde la que realiza la compilación.

Las otras respuestas proporcionan técnicas para devolver el repositorio a la confirmación más reciente en una rama en un momento determinado, pero puede que no siempre sean suficientes. Por ejemplo, si construye desde una rama, y ​​luego elimina la rama, o construye desde una rama que luego se reescribe, la confirmación desde la que construyó puede volverse "inalcanzable" en git desde cualquier rama actual. Los objetos inalcanzables en git pueden eventualmente eliminarse cuando se compacta el repositorio.

Poner una etiqueta en el commit significa que nunca se volverá inalcanzable, sin importar lo que hagas con las ramas después (salvo quitar la etiqueta).

Antlersoft
fuente
Aunque esto no me da la respuesta que busco, merece una buena mención para señalar un aspecto no mencionado hasta ahora. Esta podría ser la fuente de problemas que le impiden llegar a la versión correcta.
manuelvigarcia
1
git rev-list -n 1 --before="2009-07-27 13:37" origin/master

tome la cadena impresa (por ejemplo XXXX) y haga:

git checkout XXXX
Luca C.
fuente
2
¿No es este un duplicado de la respuesta @bartoszkp? simplemente agregando la referencia al origen, debería haber un comentario sobre la otra respuesta ...
manuelvigarcia
sí, de hecho casi, solo aclarando qué copiar para quién no sabe qué es SHA (como yo), en mi caso ese texto no era claro y este es mi código después de encontrar la solución, no copiado, de hecho puedes ver las opciones son muy diferentes también
Luca C.