488 votes

Comment trouver le parent le plus proche d'une branche Git ?

Disons que j'ai le dépôt local suivant avec un arbre de commit comme ceci :

master --> a
            \
             \
      develop c --> d
               \
                \
         feature f --> g --> h

master est mon il s'agit du dernier code de la version stable , develop est mon il s'agit du code de la "prochaine" version y feature es une nouvelle fonctionnalité en préparation pour develop .

En utilisant des crochets, je veux être capable de refuser les poussées pour feature à mon référentiel distant, à moins que le commit f est un descendant direct de develop HEAD. C'est à dire que l'arbre de commit ressemble à ceci, parce que la fonctionnalité a été git rebase en d .

master --> a
            \
             \
      develop c --> d
                     \
                      \
               feature f --> g --> h

Alors, est-il possible de :

  • Identifiez la branche mère de feature ?
  • Identifiez le commit de la branche mère qui f est un descendant de ?

A partir de là, je vérifierais quel est le HEAD de la branche mère, et voir si f Le prédécesseur correspond à la branche parent HEAD, pour déterminer si la fonctionnalité doit être rebasée.

0 votes

Cette question devrait être reformulée pour trouver le parent d'un parent.

51voto

Murali Points 298

Cela fonctionne bien pour moi :

git show-branch | grep '*' | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'

Commentaire de courtoisie et réponses de droidbot et @Jistanidiot.

1 votes

Oui, mais parfois ça donne "broken pipe" de grep.

2 votes

* n'est pas une expression rationnelle à passer à grep. Il faut utiliser grep -F '*' o grep '\*' à la place. Bonne solution sinon.

1 votes

Je n'ai pas de résultat.

14voto

Matt Stuvysant Points 39

Une solution

La solution sur la base de git show-branch n'a pas tout à fait fonctionné pour moi (voir ci-dessous), donc je l'ai combiné avec celui de sur la base de git log et je me suis retrouvé avec ça :

git log --decorate --simplify-by-decoration --oneline \ # selects only commits with a branch or tag
      | grep -v "(HEAD" \                               # removes current head (and branch)
      | head -n1 \                                      # selects only the closest decoration
      | sed 's/.* (\(.*\)) .*/\1/' \                    # filters out everything but decorations
      | sed 's/\(.*\), .*/\1/' \                        # picks only the first decoration
      | sed 's/origin\///'                              # strips "origin/" from the decoration

Limites et mises en garde

  • HEAD peut être détaché (de nombreux outils CI le font pour s'assurer qu'ils construisent le bon commit dans une branche donnée), mais branche d'origine et branche locale doivent être à la fois à parité ou "au-dessus" le HEAD actuel.
  • Il doit y avoir pas d'étiquettes de la manière (je présume ; je n'ai pas testé le script sur les commits avec une balise entre la branche enfant et la branche parent)
  • le script s'appuie sur le fait que "HEAD" est toujours répertorié comme la première décoration par le log commande
  • en cours d'exécution le script sur master y develop résulte (principalement) en <SHA> Initial commit

Les résultats

 A---B---D---E---F <-origin/master, master
      \      \
       \      \
        \      G---H---I <- origin/hotfix, hotfix
         \
          \
           J---K---L <-origin/develop, develop
                \
                 \
                  M---N---O <-origin/feature/a, feature/a
                       \   \
                        \   \
                         \   P---Q---R <-origin/feature/b, feature/b
                          \
                           \
                            S---T---U <-origin/feature/c, feature/c

Malgré l'existence de branches locales (par exemple, seulement origin/topic est présent depuis le commit O a été extrait par directement par son SHA), le script devrait s'imprimer comme suit :

  • Pour les commits G , H , I (branche hotfix ) master
  • Pour les commits M , N , O (branche feature/a ) develop
  • Pour les commits S , T , U (branche feature/c ) develop
  • Pour les commits P , Q , R (branche feature/b ) feature/a
  • Pour les commits J , K , L (branche develop ) <sha> Initial commit *
  • Pour les commits B , D , E , F (branche master ) <sha> Initial commit

* - ou master si develop Les commits de master sont au dessus du HEAD de master (~ le master serait en avance rapide pour développer)


Pourquoi show-branch n'a pas fonctionné pour moi

La solution sur la base de git show-branch s'est avéré peu fiable pour moi dans les situations suivantes :

  • HEAD détaché - y compris les moyens de remplacement du boîtier de tête détaché grep '\*' \ pour `grep '!' \ - et ce n'est que le début de tous les problèmes
  • en cours d'exécution le script sur master y develop résulte en develop et `` respectivement
  • branches sur master branche ( hotfix/ branches) se retrouvent avec le develop en tant que parent depuis leur plus proche master La branche parentale a été marquée avec ! au lieu de * pour une raison.

2 votes

La seule réponse qui a fonctionné - comme un alias git : "!git log --decorate --simplify-by-decoration --oneline | grep -v '(HEAD' | head -n1 | sed 's/.* (\\(.*\\)) .*/\\1/' | sed 's/\\(.*\\), .*/\\1/' | sed 's/origin\\///'"

0 votes

Cette commande a fonctionné pour moi git log --decorate --simplify-by-decoration --oneline | grep -v "(HEAD" | head -n1 | sed 's/.* ((.*). | head -n1 | sed 's/.* ((.*)) .*/ \1 /' | sed 's/(.*), .*/ \1 /' | sed 's/origin\///'

13voto

ilius Points 1291

Puisqu'aucune des réponses précédentes n'a fonctionné sur notre dépôt, je veux partager ma propre façon de faire, en utilisant les dernières fusions dans la base de données. git log :

#!/bin/bash
git log --oneline --merges "$@" | grep into | sed 's/.* into //g' | uniq --count | head -n 10

Mettez-le dans un script nommé git-last-merges qui accepte également un nom de branche comme argument (au lieu de la branche courante) ainsi que d'autres éléments git log arguments.

À partir de la sortie, nous pouvons détecter manuellement la ou les branches parentes sur la base de nos propres conventions de branchement et du nombre de fusions de chaque branche.

Si vous utilisez git rebase sur les branches enfant souvent (et les fusions sont souvent accélérées pour qu'il n'y ait pas trop de commits de fusion), cette réponse ne fonctionnera pas bien, donc j'ai écrit un script pour compter les commits en avance (normal et fusion), et les commits en retard (il ne devrait pas y avoir de commits en retard de fusion dans la branche parent) sur toutes les branches en comparaison avec la branche courante.

#!/bin/bash
HEAD="`git rev-parse --abbrev-ref HEAD`"
echo "Comparing to $HEAD"
printf "%12s  %12s   %10s     %s\n" "Behind" "BehindMerge" "Ahead" "Branch"
git branch | grep -v '^*' | sed 's/^\* //g' | while read branch ; do
    ahead_merge_count=`git log --oneline --merges $branch ^$HEAD | wc -l`
    if [[ $ahead_merge_count != 0 ]] ; then
        continue
    fi
    ahead_count=`git log --oneline --no-merges $branch ^$HEAD | wc -l`
    behind_count=`git log --oneline --no-merges ^$branch $HEAD | wc -l`
    behind_merge_count=`git log --oneline --merges ^$branch $HEAD | wc -l`
    behind="-$behind_count"
    behind_merge="-M$behind_merge_count"
    ahead="+$ahead_count"
    printf "%12s  %12s   %10s     %s\n" "$behind" "$behind_merge" "$ahead" "$branch"
done | sort -n

0 votes

Merci. Bien que cela puisse ne pas fonctionner très bien si vous utilisez rebase souvent (et les fusions sont fast-forward souvent). Je modifierai ma réponse si je trouve une meilleure solution.

1 votes

La seule ? réponse jusqu'à présent qui a fonctionné raisonnablement pour moi dans le cas où la branche courante est master. La plupart des autres solutions donnent un résultat aléatoire (et clairement incorrect) dans ce cas limite où il n'y a pas de branches parentes.

1 votes

C'est la seule réponse qui a fonctionné pour moi. Pour obtenir le premier parent au lieu d'une liste des 10 premiers, vous pouvez utiliser ceci : git log --oneline --merges "$@" | grep into | sed 's/.* into //g' | uniq --count | head -n 1 | cut -d ' ' -f 8

8voto

Ivan Kuznetsov Points 51
git log -2 --pretty=format:'%d' --abbrev-commit | tail -n 1 | sed 's/\\s(//g; s/,/\\n/g';

(origine/nom-parent, nom-parent)

git log -2 --pretty=format:'%d' --abbrev-commit | tail -n 1 | sed 's/\\s(//g; s/,/\\n/g';

origine/nom-parent

git log -2 --pretty=format:'%d' --abbrev-commit | tail -n 1 | sed 's/(.\*,//g; s/)//';

Nom du parent

0 votes

Cela a marché pour moi.

7voto

VonC Points 414372

Rappelez-vous que, comme décrit dans "Git : Trouver de quelle branche provient un commit " vous ne pouvez pas facilement déterminer la branche dans laquelle ce commit a été effectué (les branches peuvent être renommées, déplacées, supprimées...), même si la fonction git branch --contains <commit> est un début.

  • Vous pouvez revenir en arrière de commit en commit jusqu'à ce que git branch --contains <commit> ne liste pas les feature branche et liste develop branche,
  • comparez ce commit SHA1 à /refs/heads/develop

Si les deux commits id correspondent, vous êtes prêt à partir (ce qui signifie que le feature La branche a son origine à l'HEAD de develop ).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X