Digamos que tengo el siguiente repositorio local con un árbol de confirmación como este:
master --> a
\
\
develop c --> d
\
\
feature f --> g --> h
master
es mi este es el último código de lanzamiento estable , develop
es mi este es el "próximo" código de lanzamiento y feature
es una nueva característica que se está preparandodevelop
.
Lo que quiero poder hacer en mi repositorio remoto usando ganchos es feature
rechazar los empujes a menos que commit f
sea un descendiente directo de develop
HEAD. es decir, el árbol de confirmación se ve así porque la función ha estado git rebase
activada d
.
master --> a
\
\
develop c --> d
\
\
feature f --> g --> h
Entonces, ¿es posible:
- Identificar la rama principal de
feature
? - Identifique la confirmación en la rama principal de la que
f
es descendiente?
A partir de ahí, verificaría qué HEAD de la rama principal es, y vería si el f
predecesor coincide con el HEAD de la rama principal, para determinar si la característica necesita ser modificada.
Respuestas:
Suponiendo que el repositorio remoto tiene una copia de la rama de desarrollo (su descripción inicial lo describe en un repositorio local, pero parece que también existe en el remoto), debería poder lograr lo que creo que quiere, pero el enfoque es un poco diferente de lo que has imaginado.
La historia de Git se basa en un DAG de commits. Las ramas (y las "referencias" en general) son solo etiquetas transitorias que apuntan a compromisos específicos en el DAG de compromiso en continuo crecimiento. Como tal, la relación entre ramas puede variar con el tiempo, pero la relación entre confirmaciones no lo hace.
Parece que
baz
se basa en (una versión anterior de)bar
? ¿Pero qué pasa si borramosbar
?Ahora parece que
baz
se basa enfoo
. Pero la ascendencia debaz
no cambió, simplemente eliminamos una etiqueta (y la confirmación pendiente resultante). ¿Y si agregamos una nueva etiqueta en4
?Ahora parece que
baz
se basa enquux
. Aún así, la ascendencia no cambió, solo cambiaron las etiquetas.Sin embargo, si estuviéramos preguntando "¿es commit
6
un descendiente de commit3
?" (suponiendo3
y6
son nombres de confirmación SHA-1 completos), la respuesta sería "sí", independientemente de si las etiquetasbar
yquux
están presentes o no.Por lo tanto, puede hacer preguntas como "¿el commit forzado es descendiente de la punta actual de la rama de desarrollo ?", Pero no puede preguntar de manera confiable "¿cuál es la rama padre del commit forzado?".
Una pregunta en su mayoría confiable que parece acercarse a lo que quieres es:
Que podría implementarse como:
Esto cubrirá algo de lo que desea restringir, pero tal vez no todo.
Como referencia, aquí hay un historial de ejemplo extendido:
El código anterior podría ser utilizado para rechazar
H
yS
aceptando al mismo tiempoH'
,J
,K
, oN
, pero sería también aceptarL
yP
(que implican fusiones, pero no fusionar la punta del desarrollo ).También a rechazar
L
yP
, puede cambiar la pregunta y pedirfuente
develop > release > feature
, volvería a desarrollar y requiere conocer a los padres. La solución a mi problema fue stackoverflow.com/a/56673640/2366390Una reformulación
Otra forma de formular la pregunta es "¿Cuál es la confirmación más cercana que reside en una rama distinta de la rama actual, y qué rama es esa?"
Una solución
Puedes encontrarlo con un poco de magia de línea de comando
Con awk :
Así es como funciona:
Y el resultado
Ejecutando el código anterior en
Te dará
develop
si lo ejecutas desde H ymaster
si lo ejecutas desde I.El código está disponible como una esencia
fuente
cannot handle more than 25 refs
ack
que no está disponible en Mac (alguien sugirió reemplazarack
congrep
)git show-branch | grep '*' | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'
git show-branch | sed "s/].*//" | grep "\*" | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed "s/^.*\[//"
parent = "!git show-branch | grep '*' | grep -v \"$(git rev-parse --abbrev-ref HEAD)\" | head -n1 | sed 's/.*\\[\\(.*\\)\\].*/\\1/' | sed 's/[\\^~].*//' #"
funciona para míTambién puedes probar:
fuente
git log --graph --decorate --simplify-by-decoration
donde--graph
es opcionalgit log --graph --decorate --simplify-by-decoration --oneline
git parent
Puedes simplemente ejecutar el comando
git parent
para encontrar el padre de la rama, si agrega la respuesta de @Joe Chrysler como un alias git . Simplificará el uso.
Abra el archivo gitconfig ubicado en
"~/.gitconfig"
cualquier editor de texto. (Para linux). Y para Windows, la ruta ".gitconfig" generalmente se encuentra enc:\users\your-user\.gitconfig
Agregue el siguiente comando de alias en el archivo:
Guarde y salga del editor.
Ejecuta el comando
git parent
¡Eso es!
fuente
cannot handle more than 25 refs
excepción.Tengo una solución a su problema general (determine si
feature
desciende de la punta dedevelop
), pero no funciona utilizando el método que describió.Puede usar
git branch --contains
para enumerar todas las ramas que descienden de la punta dedevelop
, luego usegrep
para asegurarse de quefeature
esté entre ellas.Si está entre ellos, imprimirá
" feature"
a la salida estándar y tendrá un código de retorno de 0. De lo contrario, no imprimirá nada y tendrá un código de retorno de 1.fuente
<branch>
, donde realicé:git checkout -b <branch-2>
desde ... ¡ESTA es la respuesta! No hay necesidad de grep, de verdad.git branch --contains <branch>
Esto funciona bien para mí.
Respuestas de cortesía de: @droidbot y @Jistanidiot
fuente
*
no es una expresión regular adecuada para pasar a grep. Debería usargrep -F '*'
o en sugrep '\*'
lugar. Buena solución de lo contrario.Como ninguna de las respuestas anteriores funcionó en nuestro repositorio, quiero compartir mi propio camino, utilizando las últimas fusiones en
git log
:Póngalo en un script llamado
git-last-merges
, que también acepta un nombre de rama como argumento (en lugar de la rama actual), así como otrosgit log
argumentosA partir de la salida, podemos detectar manualmente la (s) rama (s) principal (es) en función de las convenciones de ramificación propias y el número de fusiones de cada rama.
EDITAR: si usa
git rebase
en ramas secundarias a menudo (y las fusiones se reenvían rápidamente a menudo para que no haya demasiados commits de fusión), esta respuesta no funcionará bien, así que escribí un script para contar los commits por adelantado (normal y merge) , y detrás de confirmaciones (no debería haber ninguna fusión posterior en la rama principal) en todas las ramas en comparación con la rama actual. Simplemente ejecute este script y avíseme si funciona para usted o nofuente
rebase
frecuencia (y las fusiones sefast-forward
editan con frecuencia). Editaré mi respuesta si encuentro una mejor solución.git log --oneline --merges "$@" | grep into | sed 's/.* into //g' | uniq --count | head -n 1 | cut -d ' ' -f 8
Una solución
La solución basada en
git show-branch
no funcionó para mí (ver más abajo), así que la combiné con la que estaba basadagit log
y terminé con esto:Limitaciones y advertencias
log
comandomaster
ydevelop
resultados (en su mayoría) en<SHA> Initial commit
Los resultados
A pesar de la existencia de una sucursal local (por ejemplo, solo
origin/topic
está presente desde que elO
SHA desprotegió la confirmación directamente), el script debe imprimirse de la siguiente manera:G
,H
,I
(ramahotfix
) →master
M
,N
,O
(ramafeature/a
) →develop
S
,T
,U
(ramafeature/c
) →develop
P
,Q
,R
(ramafeature/b
) →feature/a
J
,K
,L
(ramadevelop
) →<sha> Initial commit
*B
,D
,E
,F
(ramamaster
) →<sha> Initial commit
* - o
master
sidevelop
los commits estuvieran encima del HEAD del master (~ el master sería rápido de desarrollar)¿Por qué no me funcionó la sucursal?
La solución basada en
git show-branch
demostró ser poco confiable para mí en las siguientes situaciones:grep '\*' \
por 'grep'! \ - y eso es solo el comienzo de todos los problemasmaster
ydevelop
resultados endevelop
y `` respectivamentemaster
rama (hotfix/
ramas) terminan con eldevelop
como padre ya que sumaster
padre de rama más cercano se marcó con en!
lugar de*
por una razón.fuente
"!git log --decorate --simplify-by-decoration --oneline | grep -v '(HEAD' | head -n1 | sed 's/.* (\\(.*\\)) .*/\\1/' | sed 's/\\(.*\\), .*/\\1/' | sed 's/origin\\///'"
Recuerde que, como se describe en "Git: Encontrar de qué rama proviene un commit" , no puede identificar fácilmente la rama donde se realizó ese commit (las ramas se pueden renombrar, mover, eliminar ...), aunque
git branch --contains <commit>
sea un comienzo.git branch --contains <commit>
que no enumere lafeature
rama y la lista dedevelop
ramas,/refs/heads/develop
Si los dos commits coinciden con la identificación, está listo (eso significaría que la
feature
rama tiene su origen en HEAD ofdevelop
).fuente
La magia de la línea de comandos de JoeChrysler se puede simplificar. Aquí está la lógica de Joe: por brevedad, he introducido un parámetro nombrado
cur_branch
en lugar de la sustitución del comando`git rev-parse --abbrev-ref HEAD`
en ambas versiones; que se puede inicializar así:Entonces, aquí está la tubería de Joe:
Podemos lograr lo mismo que los cinco filtros de comandos individuales en un
awk
comando relativamente simple :Eso se descompone así:
dividir la línea en los campos de
]
,^
,~
, y[
caracteres.Encuentra líneas que contienen un asterisco
... pero no el nombre de la sucursal actual
Cuando encuentre dicha línea, imprima su segundo campo (es decir, la parte entre la primera y la segunda aparición de nuestros caracteres separadores de campo). Para nombres de rama simples, eso será justo lo que está entre los corchetes; para referencias con saltos relativos, será solo el nombre sin el modificador. Entonces, nuestro conjunto de separadores de campo maneja la intención de ambos
sed
comandos.Luego salga de inmediato. Esto significa que solo procesa la primera línea coincidente, por lo que no necesitamos canalizar la salida
head -n 1
.fuente
Aquí hay una implementación de PowerShell de la solución de Mark Reed:
fuente
No digo que esta sea una buena manera de resolver este problema, sin embargo, esto parece funcionar para mí.
git branch --contains $(cat .git/ORIG_HEAD)
El problema es que la captura de un archivo se asoma al funcionamiento interno de git, por lo que esto no es necesariamente compatible con versiones anteriores (o compatibles con versiones anteriores).fuente
Implementación multiplataforma con Ant
fuente
@ Mark Reed: ¡Debe agregar que la línea de confirmación no solo debe contener un asterisco, sino que debe comenzar con un asterisco! De lo contrario, los mensajes de confirmación que contienen un asterisco también se incluyen en las líneas coincidentes. Entonces debería ser:
git show-branch -a | awk -F'[]^~[]' '/^\*/ && !/'"$current_branch"'/ {print $2;exit}'
o la versión larga:
fuente
Logra los mismos fines que la respuesta de Mark Reed, pero utiliza un enfoque mucho más seguro que no se comporta mal en una serie de escenarios:
-
no*
*
fuente
Cualquiera que quiera hacer esto en estos días: la aplicación SourceTree de Atlassian le muestra una excelente representación visual de cómo sus ramas se relacionan entre sí, es decir, dónde comenzaron y dónde se encuentran actualmente en el orden de compromiso (por ejemplo, HEAD o 4 commits detrás, etc.) .
fuente
Si utiliza el Árbol de fuentes, consulte los detalles de confirmación> Padres> y verá los números de confirmación subrayados (enlaces)
fuente
Una alternativa:
git rev-list master | grep "$(git rev-list HEAD)" | head -1
Obtenga la última confirmación de que es mi rama y
master
(o cualquier rama que desee especificar)fuente
Esto no funcionó para mí cuando había hecho algo como
develop > release-v1.0.0 > feature-foo
, volvería a desarrollarse, tenga en cuenta que hubo un rebase involucrado, no estoy seguro de si eso está agravando mi problema ...Lo siguiente dio el hash de confirmación correcto para mí
fuente