Digamos que tengo el siguiente repositorio local con un árbol de confirmación como este:
master --> a
\
\
develop c --> d
\
\
feature f --> g --> h
masteres mi este es el último código de lanzamiento estable , developes mi este es el "próximo" código de lanzamiento y featurees una nueva característica que se está preparandodevelop .
Lo que quiero poder hacer en mi repositorio remoto usando ganchos es featurerechazar los empujes a menos que commit fsea un descendiente directo de developHEAD. es decir, el árbol de confirmación se ve así porque la función ha estado git rebaseactivada 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
fes descendiente?
A partir de ahí, verificaría qué HEAD de la rama principal es, y vería si el fpredecesor 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
bazse basa en (una versión anterior de)bar? ¿Pero qué pasa si borramosbar?Ahora parece que
bazse basa enfoo. Pero la ascendencia debazno cambió, simplemente eliminamos una etiqueta (y la confirmación pendiente resultante). ¿Y si agregamos una nueva etiqueta en4?Ahora parece que
bazse basa enquux. Aún así, la ascendencia no cambió, solo cambiaron las etiquetas.Sin embargo, si estuviéramos preguntando "¿es commit
6un descendiente de commit3?" (suponiendo3y6son nombres de confirmación SHA-1 completos), la respuesta sería "sí", independientemente de si las etiquetasbaryquuxestá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
HySaceptando al mismo tiempoH',J,K, oN, pero sería también aceptarLyP(que implican fusiones, pero no fusionar la punta del desarrollo ).También a rechazar
LyP, 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á
developsi lo ejecutas desde H ymastersi lo ejecutas desde I.El código está disponible como una esencia
fuente
cannot handle more than 25 refsackque no está disponible en Mac (alguien sugirió reemplazarackcongrep)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-decorationdonde--graphes opcionalgit log --graph --decorate --simplify-by-decoration --onelinegit parent
Puedes simplemente ejecutar el comando
git parentpara 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\.gitconfigAgregue 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 refsexcepción.Tengo una solución a su problema general (determine si
featuredesciende de la punta dedevelop), pero no funciona utilizando el método que describió.Puede usar
git branch --containspara enumerar todas las ramas que descienden de la punta dedevelop, luego usegreppara asegurarse de quefeatureesté 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 logargumentosA 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 rebaseen 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
rebasefrecuencia (y las fusiones sefast-forwardeditan 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 8Una solución
La solución basada en
git show-branchno funcionó para mí (ver más abajo), así que la combiné con la que estaba basadagit logy terminé con esto:Limitaciones y advertencias
logcomandomasterydevelopresultados (en su mayoría) en<SHA> Initial commitLos resultados
A pesar de la existencia de una sucursal local (por ejemplo, solo
origin/topicestá presente desde que elOSHA desprotegió la confirmación directamente), el script debe imprimirse de la siguiente manera:G,H,I(ramahotfix) →masterM,N,O(ramafeature/a) →developS,T,U(ramafeature/c) →developP,Q,R(ramafeature/b) →feature/aJ,K,L(ramadevelop) →<sha> Initial commit*B,D,E,F(ramamaster) →<sha> Initial commit* - o
mastersideveloplos 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-branchdemostró ser poco confiable para mí en las siguientes situaciones:grep '\*' \por 'grep'! \ - y eso es solo el comienzo de todos los problemasmasterydevelopresultados endevelopy `` respectivamentemasterrama (hotfix/ramas) terminan con eldevelopcomo padre ya que sumasterpadre 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 lafeaturerama y la lista dedevelopramas,/refs/heads/developSi los dos commits coinciden con la identificación, está listo (eso significaría que la
featurerama 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_branchen 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
awkcomando 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
sedcomandos.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 -1Obtenga 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