Git: pago a 2 confirmaciones después de una label

Conocer el siguiente esquema: enter image description here

La línea amarilla es la twig Maestra. La línea roja es twig Desarrollo.

Estoy en Master en la label 6.2.1. Mi necesidad sería get automáticamente el sha1 de la confirmación con un círculo en azul, revisando este sha1 y creando mi twig desde este sha1. Este compromiso no es el último compromiso de desarrollo.

Lo que hay que hacer podría consistir en:

  • obteniendo el sha1 de la label 6.2.1: git log --oneline | head -1 | cut -d ' ' -f1 git log --oneline | head -1 | cut -d ' ' -f1
  • obteniendo el padre de la label 6.2.1: llamado commit 'P'
  • obteniendo el siguiente commit de 'P' llamado commit 'C1' que debería estar en desarrollo
  • get la siguiente confirmación de 'C1' llamada 'C2' también en desarrollo.

Actualmente tengo que ir manualmente a Gitlab, get el sha1 relacionado antes de pagar y luego crear mi sucursal.

Hay una manera, pero hay un problema potencial.

Un nombre de label identifica una confirmación.

Más específicamente y precisamente, un nombre de label como v2.1 es la versión corta del nombre de reference totalmente calificado refs/tags/v2.1 , y cualquier reference de Git identifica algún object de Git. Todos los nombres de las sucursales , como el master que es la abreviatura de refs/heads/master , están obligados a identificar solo un object commit. Los nombres de label usualmente identifican un object de compromiso (Git llama a esto una label liviana) o un object de label anotado , que luego identifica el compromiso. En cualquier caso, el name ^{commit} syntax especial de gitrevisions name ^{commit} refiere a la confirmación específica, si es necesario (normalmente no se sabe), Git se da count de que, por ejemplo, git checkout necesita una confirmación y agrega el ^{commit} automáticamente )

El problema es que no quieres la confirmación identificada por la label. Quieres un compromiso cercano . Dijiste "dos commits after " y esto es un problema: no hay tal cosa como commit después de otro commit. Solo hay commits antes de otro commit.

Objeción, tu honor!

¿Cómo no puede haber una confirmación después de una confirmación si hay una confirmación antes de una confirmación? Por ejemplo, anotemos cuatro commits en una fila:

 A <- B <- C <- D 

En Git, commit D almacena el ID de su confirmación principal , que es commit C Entonces, dado D , es muy fácil retroceder a C Del mismo modo, la identificación B la tienda C , y B almacena la ' A '. (Si A es el primer compromiso de todos los times, no hay padre: no puede retroceder, y A es un compromiso raíz . Un compromiso raíz es aquel que no tiene padre).

El problema aquí es que puede haber más de una confirmación antes de una confirmación, o después de una confirmación, para ese asunto. En lugar de solo lo anterior, considere este fragment de gráfico:

 A--B--C--D---H <-- master \ / E--F--G <-- feature 

Commit H , que es la punta del branch master , es un commit de fusión . Tiene dos padres: D y G Cuando examinamos el compromiso H vemos algo como esto (con diferentes numbers):

 $ git show master commit 3e5c63943d35be1804d302c0393affc4916c3dc3 Merge: c13c783 20690b2 

Esto significa que tiene dos padres, c13c783... y 20690b2... ¿Cuál es la confirmación antes de confirmar H ?

Entonces, la respuesta a la objeción es que no hay una confirmación antes de una confirmación, posiblemente hay muchas (a menudo 1, a veces 2, más raro pero ocasionalmente cero, o tres o más) confirmaciones antes de otra confirmación. Del mismo modo, puede haber ninguno, o dos o más, se compromete después de otro compromiso.

Para encontrar los compromisos que desea , necesita más información.

Más información

En general, retroceder es fácil. El primer (y, a menudo, el único ) padre de una confirmación suele ser el interesante, ya que es la confirmación que estaba en la twig antes de que esa confirmación se agregara a esa twig. Es decir, mientras que el compromiso H tiene a D y G como padres, si el master solía apuntar a D y ahora apunta a H , es el primer padre de H que queremos.

Gitrevisions tiene una syntax rápida y fácil para seguir a los primeros padres: simplemente agrega un carácter tilde ~ y un recuento de cuántos primos padres darán un paso atrás. Así que para ir dos pasos atrás de la v2.1 , siguiendo solo a los primeros padres, simplemente escriba v2.1~2 :

 git checkout -b newbranch v2.1~2 

y tu estas listo.

Avanzar es más difícil. Git solo almacena enlaces al revés, por lo que lo que debes hacer es proporcionar un nombre o identidad de un compromiso posterior , desde el cual Git puede funcionar al revés para alcanzar tu confirmación conocida (labelda). Por ejemplo, si tenemos una label que apunta a cometer C y queremos avanzar dos pasos (hacia D y luego hacia H ), le daríamos a Git dos bits de información:

  1. por favor termine en v2.1
  2. y comienza desde el master

y haga que enumere todas las confirmaciones entre esos dos puntos, y luego elija uno de los dos pasos "más cerca de master " que el final en v2.1 . Digamos en este punto que hay aún más confirmaciones en el master ahora, por lo que el dibujo se ve así:

  tag:v2.1 | v A--B--C--D---H--I <-- master \ / E--F--G <-- feature 

Para encontrar H esta manera, usamos git rev-list y aún más syntax de gitrevisions . (Por ahora, debería ser obvio que aprender la syntax de gitrevisions es fundamental para usar Git ).

 git rev-list v2.1..master 

La syntax de dos puntos aquí significa " no include v2.1 sí", por lo que se enumerarán las confirmaciones comenzando desde el maestro y volviendo a la confirmación después de la v2.1 :

 0fbc341... # id of I a9315c3... # id of H 9911231... # id of D 

Tomamos los dos últimos ID, a9315c3 el último de estos ID y obtenemos un a9315c3 , que es el ID de H

Pero todavía hay un problema potencial

¿Qué pasa si el gráfico se parece más a esto?

  tag:v2.1 | v A--B--C--D---------H--I <-- master \ / E--F--G <-- feature 

Notamos antes que usar la notación ~ usa el primer padre. Podemos hacer eso aquí, usando git rev-list --first-parent v2.1..master . Eso evitará que Git GFE , lo que asegurará que encontremos H lugar de E

También es una buena idea agregar --topo-order al command rev-list, ya que de lo contrario estos commits se enumeran en el order de date de confirmación, y si la date / las horas alguna vez se estropearon en una de las computadoras involucradas en hacer el repository, las confirmaciones pueden enumerarse en el order incorrecto.

También existe la opción --ancestry-path , que es útil en algunos casos (tal vez no aplicable a su caso): se asegura de que git rev-list enumere solo commits que sean descendientes del lado izquierdo de la operación .. . Usted usaría esto donde el primer --first-parent no es deseado, por ejemplo:

 ...--o--*--A--B--C \ \ \ D--E--F--G--H <-- branch 

Si queremos que el compromiso "tres pasos" después de labeldo commit * , que podría ser C o G Usando git rev-list tag..branch se imprimirá todo de A a H (en algún order). Agregar --first-parent cortará G o C solo uno de esos dos puede ser el primer padre de H – y si desea ver ambos no puede usar --first-parent . Agregar --ancestry-path hará que git rev-list omita DEF ; el rest saldrá, en algún order. Agregar --topo-order garantizará que B salga penúltimo y A salga último (recuerde, Git está trabajando hacia atrás), con C y G en cualquier order antes que ellos, y H primero.

Esa no es una solución completa, pero no hay una solución completa, si tienes un gráfico de ramificación y fusión como este.

De todos modos, elija algún subset de estas opciones. Si sabe que sus charts son los primeros para padres, entonces, por ejemplo:

git rev-list --topo-order --first-parent tag .. branchname | tail -2 | head -1

te dará el hash que quieras

(Para otro truco ligeramente sutil, agregue --reverse para invertir el order de printing de git rev-list y luego use sed -n -e 2p para imprimir la segunda línea. Tenga en count, sin embargo, que no puede usar git rev-list 's -n Indica aquí, ya que count y se detiene desde la list no revertida , y no sabemos cuántos commits habrá, queremos el segundo de abajo, independientemente de cuántos.

Abra git bash, vaya al directory seleccionado y luego ejecute los siguientes commands. Para get el command de ejecución SHA1

 git log branchname --oneline 

Tendrá el sha1 junto al post de confirmación

enter image description here

 git branch branchname <sha1-of-commit>