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

419

Disons que j'ai le référentiel local suivant avec une arborescence de validation comme celle-ci:

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

masterest mon c'est le dernier code de version stable , developest mon ceci est le «prochain» code de version , et featureest une nouvelle fonctionnalité en cours de préparationdevelop .

Ce que je veux pouvoir faire sur mon référentiel distant en utilisant des hooks, c'est que les poussées featuresoient refusées à moins que commit ne fsoit un descendant direct de developHEAD. c'est-à-dire que l'arborescence de validation ressemble à ceci parce que la fonctionnalité a été git rebaseactivée d.

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

Est-il donc possible de:

  • Identifiez la branche parente de feature?
  • Identifiez le commit dans la branche parent qui fest un descendant de?

À partir de là, je vérifierais ce qu'est le HEAD de la branche parent et je verrais si le fprédécesseur correspond au HEAD de la branche parent, pour déterminer si la fonctionnalité doit être rebasée.

Peter Farmer
la source
cette question devrait être reformulée pour trouver le parent d'un parent.
Tim Boland

Réponses:

348

En supposant que le référentiel distant possède une copie du développement branche de (votre description initiale la décrit dans un référentiel local, mais il semble qu'elle existe également dans la télécommande), vous devriez être en mesure de réaliser ce que je pense que vous voulez, mais l'approche est un peu différent de ce que vous avez imaginé.

L'histoire de Git est basée sur un DAG de commits. Les branches (et les «refs» en général) ne sont que des étiquettes transitoires qui pointent vers des validations spécifiques dans le DAG de validation en constante augmentation. En tant que tel, la relation entre les branches peut varier dans le temps, mais pas la relation entre les validations.

    ---o---1                foo
            \
             2---3---o      bar
                  \
                   4
                    \
                     5---6  baz

Il semble être bazbasé sur (une ancienne version de) bar? Mais que se passe-t-il si nous supprimons bar?

    ---o---1                foo
            \
             2---3
                  \
                   4
                    \
                     5---6  baz

Maintenant, on dirait qu'il bazest basé sur foo. Mais l'ascendance de bazn'a pas changé, nous venons de supprimer une étiquette (et la validation qui en résulte). Et si nous ajoutons une nouvelle étiquette à 4?

    ---o---1                foo
            \
             2---3
                  \
                   4        quux
                    \
                     5---6  baz

Maintenant, on dirait qu'il bazest basé sur quux. Pourtant, l'ascendance n'a pas changé, seules les étiquettes ont changé.

Si, cependant, nous demandions "est-ce que commettre est 6un descendant de commit 3?" (en supposant 3et 6sont des noms de validation SHA-1 complets), la réponse serait «oui», que les étiquettes baret quuxsoient présentes ou non.

Ainsi, vous pouvez poser des questions comme «la validation poussée est-elle un descendant de la pointe actuelle de la branche de développement ?», Mais vous ne pouvez pas poser de manière fiable «quelle est la branche parente de la validation poussée?».

Une question principalement fiable qui semble se rapprocher de ce que vous voulez est:

Pour tous les ancêtres du commit poussé (à l'exception de la pointe actuelle de develop et de ses ancêtres), qui ont la pointe actuelle de develop comme parent:

  • existe-t-il au moins un tel commit?
  • y a-t-il des commits monoparentaux?

Qui pourrait être implémenté comme:

pushedrev=...
basename=develop
if ! baserev="$(git rev-parse --verify refs/heads/"$basename" 2>/dev/null)"; then
    echo "'$basename' is missing, call for help!"
    exit 1
fi
parents_of_children_of_base="$(
  git rev-list --pretty=tformat:%P "$pushedrev" --not "$baserev" |
  grep -F "$baserev"
)"
case ",$parents_of_children_of_base" in
    ,)     echo "must descend from tip of '$basename'"
           exit 1 ;;
    ,*\ *) echo "must not merge tip of '$basename' (rebase instead)"
           exit 1 ;;
    ,*)    exit 0 ;;
esac

Cela couvrira une partie de ce que vous souhaitez restreindre, mais peut-être pas tout.

Pour référence, voici un exemple d'historique étendu:

    A                                   master
     \
      \                    o-----J
       \                  /       \
        \                | o---K---L
         \               |/
          C--------------D              develop
           \             |\
            F---G---H    | F'--G'--H'
                    |    |\
                    |    | o---o---o---N
                     \   \      \       \
                      \   \      o---o---P
                       \   \   
                        R---S

Le code ci - dessus peut être utilisé pour rejeter Het Stout en acceptant H', J, Kou N, mais il serait aussi accepter Let P(ils impliquent des fusions, mais ils ne se confondent pas la pointe de développer ).

Pour refuser également Let P, vous pouvez modifier la question et demander

Pour tous les ancêtres du commit poussé (à l'exception de la pointe actuelle de develop et de ses ancêtres):

  • y a-t-il des engagements avec deux parents?
  • sinon, au moins un de ces commit a-t-il la pointe actuelle de développer son (seul) parent?
pushedrev=...
basename=develop
if ! baserev="$(git rev-parse --verify refs/heads/"$basename" 2>/dev/null)"; then
    echo "'$basename' is missing, call for help!"
    exit 1
fi
parents_of_commits_beyond_base="$(
  git rev-list --pretty=tformat:%P "$pushedrev" --not "$baserev" |
  grep -v '^commit '
)"
case "$parents_of_commits_beyond_base" in
    *\ *)          echo "must not push merge commits (rebase instead)"
                   exit 1 ;;
    *"$baserev"*)  exit 0 ;;
    *)             echo "must descend from tip of '$basename'"
                   exit 1 ;;
esac
Chris Johnsen
la source
J'obtiens ceci: git: fatal: argument ambigu '...': révision et nom de fichier. quelle est l'intention des points triple?
Jack Ukleja
1
@Schneider Je suis sûr que le '...' est destiné à être un espace réservé dans cet exemple: si vous le remplacez par le SHA du commit, vous essayez d'effectuer cette vérification (par exemple, le HEAD de la branche vous êtes actuellement sur), tout fonctionne très bien.
Daniel Brady
Merci pour cette réponse élaborée! C'est super utile. Je veux faire un crochet similaire, mais je ne veux pas coder en dur le nom de la branche de développement. Ce qui signifie que je veux un crochet pour empêcher le rebasage vers une branche autre que la branche parent. Si je comprends bien votre réponse (je suis nouveau sur bash et tout ça), cela n'est pas couvert dans votre réponse, non? Y a-t-il un moyen de faire cela?
Kemeia
Êtes-vous prêt à répondre à une question connexe? Je n'ai pas pu faire fonctionner votre code sur un référentiel REMOTE. Voici le lien vers la question de suivi sur la façon d'adapter votre approche pour travailler avec un référentiel REMOTE: stackoverflow.com/questions/49619492/…
CodeMed
Cela ne fonctionnait pas pour moi quand j'en avais develop > release > feature, je récupèrerais et cela nécessite de connaître le parent. La solution à mon problème était stackoverflow.com/a/56673640/2366390
verdverm
241

Une reformulation

Une autre façon de formuler la question est: "Quel est le commit le plus proche qui réside sur une branche autre que la branche actuelle, et quelle branche est-ce?"

Une solution

Vous pouvez le trouver avec un peu de magie en ligne de commande

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

Avec awk :

git show-branch -a \
| grep '\*' \
| grep -v `git rev-parse --abbrev-ref HEAD` \
| head -n1 \
| sed 's/[^\[]*//' \
| awk 'match($0, /\[[a-zA-Z0-9\/-]+\]/) { print substr( $0, RSTART+1, RLENGTH-2 )}'

Voici comment ça fonctionne:

  1. Affichez un historique textuel de toutes les validations, y compris les branches distantes.
  2. Les ancêtres du commit actuel sont indiqués par une étoile. Filtrez tout le reste.
  3. Ignorez tous les commits de la branche courante.
  4. Le premier résultat sera la branche ancêtre la plus proche. Ignorez les autres résultats.
  5. Les noms des succursales sont affichés [entre parenthèses]. Ignorez tout ce qui se trouve en dehors des crochets et des crochets.
  6. Parfois, le nom de la branche comprend un ~ # ou ^ # pour indiquer le nombre de validations entre la validation référencée et la pointe de la branche. On s'en fout. Ignore les.

Et le résultat

Exécution du code ci-dessus sur

 A---B---D <-master
      \
       \
        C---E---I <-develop
             \
              \
               F---G---H <-topic

Vous donnera developsi vous l'exécutez à partir de H et mastersi vous l'exécutez à partir de I.

Le code est disponible sous forme de résumé

Joe Chrysler
la source
24
Suppression d'un backtick final qui a provoqué une erreur. Cependant, lors de l'exécution de cette commande, je reçois une grande quantité d'avertissements, me plaignant de chaque branche disantcannot handle more than 25 refs
Jon L.
1
@JoeChrysler pensez-vous que vous pouvez en faire une ligne au lieu de 2, et éventuellement le faire fonctionner sur Mac car il ackn'est pas disponible sur Mac (quelqu'un a suggéré de le remplacer ackpar grep)
nonopolarity
53
Désolé, c'est un mauvais. Voici le bon qui a fonctionné pour moi:git show-branch | grep '*' | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'
droidbot
15
@droidbot Nice, mais nécessite une réorganisation de la tuyauterie pour éviter la suppression des références lorsque grep -v capture le message de validation ou que votre nom de branche fait partie d'un autre nom de branche. git show-branch | sed "s/].*//" | grep "\*" | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed "s/^.*\[//"
gaal
3
@OlegAbrazhaev Je ne sais pas si vous avez déjà obtenu une réponse à votre question. en utilisant l'alias git de: parent = "!git show-branch | grep '*' | grep -v \"$(git rev-parse --abbrev-ref HEAD)\" | head -n1 | sed 's/.*\\[\\(.*\\)\\].*/\\1/' | sed 's/[\\^~].*//' #"works for me
mduttondev
111

Vous pouvez également essayer:

git log --graph --decorate
rcde0
la source
5
git log --graph --decorate --simplify-by-decoration--graphest facultatif.
Na13-c
1
git log --graph --decorate --simplify-by-decoration --oneline
anishtain4
106

git parent

Vous pouvez simplement exécuter la commande

git parent

pour trouver le parent de la branche, si vous ajoutez le @ Joe Chrysler réponse de comme alias git . Cela simplifiera l'utilisation.

Ouvrez le fichier gitconfig situé à l' "~/.gitconfig"aide de n'importe quel éditeur de texte. (Pour linux). Et pour Windows, le chemin ".gitconfig" se trouve généralement àc:\users\your-user\.gitconfig

vim  ~/.gitconfig

Ajoutez la commande d'alias suivante dans le fichier:

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

Enregistrez et quittez l'éditeur.

Exécutez la commande git parent

C'est ça!

NIKHIL CM
la source
5
C'est une excellente solution. Il serait utile d'ajouter également un échantillon de sortie pour être sûr des résultats attendus. Lorsque je l'ai exécuté, j'ai reçu quelques avertissements avant la toute dernière ligne qui, je crois, était le nom de la branche parent.
ttemple
4
Fonctionne comme un charme! Pour les utilisateurs de Windows, le .gitconfig est généralement situé dans c: \ users \ your-user \ .gitconfig
zion
12
Obtenir l' cannot handle more than 25 refsexception.
shajin
quelqu'un peut-il modifier cela pour gérer l'avertissement? @ttemple, pouvez-vous?
NIKHIL CM
@NIKHILCM fonctionne comme un champion. Mais j'ai une question ici si le parent indique d'où la branche a créé ou autre chose?
Hariprasath
52

J'ai une solution à votre problème global (déterminez si elle featuredescend de la pointe de develop), mais cela ne fonctionne pas en utilisant la méthode que vous avez décrite.

Vous pouvez utiliser git branch --containspour lister toutes les branches descendantes de la pointe dedevelop , puis utiliser greppour vous assurer featurequ'elles figurent parmi celles-ci.

git branch --contains develop | grep "^ *feature$"

S'il en fait partie, il imprimera " feature"sur la sortie standard et aura un code retour de 0. Sinon, il n'imprimera rien et aura un code retour de 1.

Daniel Stutzbach
la source
1
Cela fonctionne mais il convient de noter que cela peut prendre beaucoup de temps sur un référentiel qui a beaucoup de références. Cela le rend un peu moins idéal pour exécuter, par exemple, un crochet de pré-réception.
Ebneter
Je cherchais la branche, nous l'appellerons <branch>, où j'ai joué: à git checkout -b <branch-2>partir de ... CECI est la réponse! Pas besoin de grep, vraiment. git branch --contains <branch>
Poopy McFartnoise
44

Cela fonctionne bien pour moi.

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

Réponses de courtoisie de: @droidbot et @Jistanidiot

Murali Mopuru
la source
Ouais, mais parfois ça vous fait "pipe cassée" de grep.
Vladislav Rastrusny
1
*n'est pas une expression rationnelle appropriée pour passer à grep. Devrait utiliser grep -F '*'ou à la grep '\*'place. Bonne solution sinon.
arielf
Je n'ai eu aucune sortie.
Sandip Subedi
fonctionne pour moi ....
roottraveller
11

Étant donné qu'aucune des réponses ci-dessus n'a fonctionné sur notre référentiel, je souhaite partager ma propre manière, en utilisant les dernières fusions dans 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 actuelle) ainsi que d'autresgit log arguments

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

EDIT: Si vous utilisezgit rebase souvent des branches enfants (et que les fusions sont souvent avancées rapidement donc il n'y a pas trop de validations de fusion), cette réponse ne fonctionnera pas bien, j'ai donc écrit un script pour compter les validations anticipées (normal et fusion) , et derrière les validations (il ne devrait pas y avoir de fusion derrière dans la branche parent) sur toutes les branches par rapport à la branche actuelle. Exécutez simplement ce script et faites-moi savoir si cela fonctionne pour vous ou non

#!/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
saeedgnu
la source
Merci. Bien que cela puisse ne pas fonctionner très bien si vous utilisez rebasesouvent (et les fusions sont fast-forwardsouvent éditées). Je modifierai ma réponse si j'ai trouvé une meilleure solution.
saeedgnu
1
Le seul? réponse jusqu'à présent qui a fonctionné sensiblement pour moi dans le cas où la branche actuelle est maître. La plupart des autres solutions ont donné un résultat aléatoire (et manifestement incorrect) dans ce cas avéré où il n'y a pas de branches parentales réelles.
arielf
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
lots0logs
10

Une solution

La solution basée surgit show-branch ne fonctionnait pas tout à fait pour moi (voir ci-dessous), donc je l'ai combinée avec celle basée surgit log et je me suis retrouvée avec ceci:

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

Limitations et mises en garde

  • HEAD peut être détaché (de nombreux outils CI le font pour s'assurer qu'ils génèrent une validation correcte dans une branche donnée), mais la branche d'origine et la branche locale doivent être à la fois égales ou "supérieures" à la HEAD actuelle.
  • Il ne doit pas y avoir de balises sur le chemin (je présume; je n'ai pas testé le script sur les validations avec une balise entre la branche enfant et la branche parent)
  • le script repose sur le fait que "HEAD" est toujours répertorié comme le premier décor par la logcommande
  • en cours d' exécution du script sur masteretdevelop les résultats ( la plupart du temps) en<SHA> Initial commit

Les resultats

 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 d'une branche locale (par exemple, seule origin/topicest présente puisque la validation a Oété extraite directement par son SHA), le script doit s'afficher comme suit:

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

* - ou mastersi developles commits étaient au-dessus de la tête du maître (~ le maître serait rapidement transmissible à développer)


Pourquoi n'a-t-il pas travaillé pour moi?

La solution basée surgit show-branch s'est révélée peu fiable pour moi dans les situations suivantes:

  • TÊTE détachée - y compris le boîtier de tête détachée signifie remplacer grep '\*' \pour `grep '! \ - et ce n'est que le début de tous les ennuis
  • en cours d' exécution du script sur masteretdevelop les résultats dans developet respectivement ``
  • les branches sur lamaster branche ( hotfix/branches) se retrouvent avec developcomme parent puisque leur parent de masterbranche le plus proche a été marqué avec !au lieu de *pour une raison.
Matt Stuvysant
la source
2
Seule réponse qui a fonctionné - en tant qu'alias git:"!git log --decorate --simplify-by-decoration --oneline | grep -v '(HEAD' | head -n1 | sed 's/.* (\\(.*\\)) .*/\\1/' | sed 's/\\(.*\\), .*/\\1/' | sed 's/origin\\///'"
Ian Kemp
8

N'oubliez pas que, comme décrit dans "Git: Trouver de quelle branche provient une validation" , vous ne pouvez pas facilement localiser la branche où cette validation a été effectuée (les branches peuvent être renommées, déplacées, supprimées ...), même si git branch --contains <commit>c'est un début.

  • Vous pouvez revenir de commit à commit jusqu'à ce git branch --contains <commit>que ne répertorie pas la featurebranche et la listedevelop ,
  • comparer ce commit SHA1 à /refs/heads/develop

Si les deux commits correspondent, vous êtes prêt à partir (cela signifierait que la featurebranche a son origine à la tête de develop).

VonC
la source
6

La magie de la ligne de commande de JoeChrysler peut être simplifiée. Voici la logique de Joe - par souci de concision, j'ai introduit un paramètre nommé cur_branchà la place de la substitution de commande `git rev-parse --abbrev-ref HEAD`dans les deux versions; qui peut être initialisé comme ceci:

cur_branch=$(git rev-parse --abbrev-ref HEAD)

Ensuite, voici le pipeline de Joe:

git show-branch -a           |
  grep '\*'                  | # we want only lines that contain an asterisk
  grep -v "$cur_branch"      | # but also don't contain the current branch
  head -n1                   | # and only the first such line
  sed 's/.*\[\(.*\)\].*/\1/' | # really, just the part of the line between []
  sed 's/[\^~].*//'            # and with any relative refs (^, ~n) removed

Nous pouvons accomplir la même chose que les cinq de ces filtres de commande individuels dans une awkcommande relativement simple :

git show-branch -a |
  awk -F'[]^~[]' '/\*/ && !/'"$cur_branch"'/ {print $2;exit}'  

Cela se décompose comme ceci:

-F'[]^~[]' 

diviser la ligne en champs à ], ^, ~et [caractères.

/\*/                      

Rechercher des lignes contenant un astérisque

&& !/'"$cur_branch"'/

... mais pas le nom de la branche actuelle

{ print $2;               

Lorsque vous trouvez une telle ligne, imprimez son deuxième champ (c'est-à-dire la partie entre les première et deuxième occurrences de nos caractères de séparation de champ). Pour les noms de branche simples, ce sera juste ce qu'il y a entre les crochets; pour les références avec des sauts relatifs, ce sera juste le nom sans le modificateur. Notre ensemble de séparateurs de champs gère donc l'intention des deux sedcommandes.

  exit }

Quittez ensuite immédiatement. Cela signifie qu'il ne traite que la première ligne correspondante, nous n'avons donc pas besoin de diriger la sortie head -n 1.

Mark Reed
la source
3
Notez que certaines branches peuvent manquer dans la sortie en raison d'un trop grand nombre de références. Ils sont plutôt affichés comme des avertissements sur stderr.
Zitrax
5

Voici une implémentation PowerShell de la solution de Mark Reed:

git show-branch -a | where-object { $_.Contains('*') -eq $true} | Where-object {$_.Contains($branchName) -ne $true } | select -first 1 | % {$_ -replace('.*\[(.*)\].*','$1')} | % { $_ -replace('[\^~].*','') }
chrisevett
la source
5

Je ne dis pas que c'est un bon moyen de résoudre ce problème, mais cela semble fonctionner pour moi.

git branch --contains $(cat .git/ORIG_HEAD) Le problème étant que cat'inguer un fichier jette un coup d'œil dans le fonctionnement interne de git, ce n'est donc pas nécessairement compatible (ou rétrocompatible).

user1529413
la source
3

Implémentation multiplateforme avec Ant

    <exec executable="git" outputproperty="currentBranch">
        <arg value="rev-parse" />  
        <arg value="--abbrev-ref" />  
        <arg value="HEAD" />  
    </exec>

    <exec executable="git" outputproperty="showBranchOutput">
        <arg value="show-branch" />  
        <arg value="-a" />  
    </exec>

    <loadresource property="baseBranch">
      <propertyresource name="showBranchOutput"/>
          <filterchain>
            <linecontains>
              <contains value="*"/>
            </linecontains>
            <linecontains negate="true">
              <contains value="${currentBranch}"/>
            </linecontains>
            <headfilter lines="1"/>
            <tokenfilter>
                <replaceregex pattern=".*\[(.*)\].*" replace="\1"/>
                <replaceregex pattern="[\^~].*" replace=""/>
            </tokenfilter>
          </filterchain>
    </loadresource>

    <echo message="${currentBranch} ${baseBranch}" />
ENargit
la source
2

@Mark Reed: Vous devez ajouter que la ligne de validation ne doit pas seulement contenir un astérisque, mais commencer par un astérisque! Sinon, les messages de validation contenant un astérisque sont également inclus dans les lignes correspondantes. Il devrait donc être:

git show-branch -a | awk -F'[]^~[]' '/^\*/ && !/'"$current_branch"'/ {print $2;exit}'

ou la version longue:

git show-branch -a           |
  awk '^\*'                  | # we want only lines that contain an asterisk
  awk -v "$current_branch"   | # but also don't contain the current branch
  head -n1                   | # and only the first such line
  sed 's/.*\[\(.*\)\].*/\1/' | # really, just the part of the line between []
  sed 's/[\^~].*//'            # and with any relative refs (^, ~n) removed`
ladiko
la source
2
vbc=$(git rev-parse --abbrev-ref HEAD)
vbc_col=$(( $(git show-branch | grep '^[^\[]*\*' | head -1 | cut -d* -f1 | wc -c) - 1 )) 
swimming_lane_start_row=$(( $(git show-branch | grep -n "^[\-]*$" | cut -d: -f1) + 1 )) 
git show-branch | tail -n +$swimming_lane_start_row | grep -v "^[^\[]*\[$vbc" | grep "^.\{$vbc_col\}[^ ]" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'

Atteint les mêmes fins que la réponse de Mark Reed, mais utilise une approche beaucoup plus sûre qui ne se comporte pas mal dans un certain nombre de scénarios:

  1. Le dernier commit de la branche parent est une fusion, ce qui rend la colonne - non visible*
  2. Le message de validation contient le nom de la branche
  3. Le message de validation contient *
Haoyang Feng
la source
0

Quiconque le souhaite ces jours-ci - L'application SourceTree d'Atlassian vous montre une excellente représentation visuelle de la façon dont vos branches sont liées les unes aux autres, c'est-à-dire où elles ont commencé et où elles se trouvent actuellement dans l'ordre de validation (par exemple HEAD ou 4 commits derrière, etc.) .

jake
la source
0

Si vous utilisez Source Tree regardez vos détails de commit> Parents> alors vous verrez les numéros de commit soulignés (liens)

Mike6679
la source
0

Une alternative: git rev-list master | grep "$(git rev-list HEAD)" | head -1

Obtenez le dernier commit que c'est à la fois ma branche et master(ou la branche que vous souhaitez spécifier)

Alexander Woods
la source
0

Cela n'a pas fonctionné pour moi quand j'avais fait quelque chose comme develop > release-v1.0.0 > feature-foo ça, cela remonterait au développement, notez qu'il y avait un rebase impliqué, je ne sais pas si cela aggrave mon problème ...

Ce qui suit a donné le hachage de validation correct pour moi

git log --decorate \
  | grep 'commit' \
  | grep 'origin/' \
  | head -n 2 \
  | tail -n 1 \
  | awk '{ print $2 }' \
  | tr -d "\n"
verdverm
la source