Les différentes méthodes ci-dessous sont des méthodes pragmatiques, utiles et efficaces pour déduire une réponse probable , mais notons que dans git, la question elle-même est un malentendu, les commits ne viennent pas des branches. Les succursales vont et viennent, elles bougent, seuls les commits représentent la véritable histoire du repo. Là encore, ce n'est pas une façon de dire que les solutions ci-dessous sont mauvaises. Sachez simplement qu'aucun d'eux ne donne une réponse entièrement fiable, ce qui est impossible par conception dans git. (Un cas simple est celui des branches supprimées: je branche, je commets deux fois, je fusionne dans une autre branche, je supprime la première branche. D'où le commit "vient"?
RomainValeri
1
J'ai un cas où je tire explicitement un clone peu profond de profondeur 1 d'une balise. C'est bon marché et facile et efficace ... et jusqu'à présent, j'ai fait tout ce que je voulais magnifiquement. Maintenant que j'aimerais savoir sur quelle branche se trouvait la balise, je me suis fait arroser, du moins pour ce détail. Vous ne pouvez pas toujours rentrer à la maison, lol
Paul Hodges
Réponses:
865
Bien que Dav ait raison de dire que les informations ne sont pas directement stockées, cela ne signifie pas que vous ne pourrez jamais le découvrir. Voici quelques choses que vous pouvez faire.
Rechercher les branches sur lesquelles le commit est activé
git branch -a --contains <commit>
Cela vous indiquera toutes les branches qui ont le commit donné dans leur histoire. Évidemment, cela est moins utile si la validation a déjà été fusionnée.
Rechercher les reflogs
Si vous travaillez dans le référentiel dans lequel la validation a été effectuée, vous pouvez rechercher les reflogs pour la ligne de cette validation. Les reflogs de plus de 90 jours sont élagués par git-gc, donc si le commit est trop ancien, vous ne le trouverez pas. Cela dit, vous pouvez le faire:
git reflog show --all | grep a871742
pour trouver le commit a871742. Notez que vous DEVEZ utiliser les 7 premiers chiffres abrégés du commit. La sortie devrait ressembler à ceci:
a871742 refs/heads/completion@{0}: commit (amend): mpc-completion: total rewrite
indiquant que la validation a été effectuée sur la branche "achèvement". La sortie par défaut affiche des hachages de validation abrégés, alors assurez-vous de ne pas rechercher le hachage complet ou vous ne trouverez rien.
git reflog show est en fait juste un alias pour git log -g --abbrev-commit --pretty=oneline , donc si vous voulez jouer avec le format de sortie pour rendre différentes choses disponibles pour grep, c'est votre point de départ!
Si vous ne travaillez pas dans le référentiel où la validation a été effectuée, le mieux que vous puissiez faire dans ce cas est d'examiner les reflogs et de trouver quand la validation a été introduite pour la première fois dans votre référentiel; avec un peu de chance, vous êtes allé chercher la branche dans laquelle il s'était engagé. C'est un peu plus complexe, car vous ne pouvez pas parcourir à la fois l'arbre de validation et les reflogs. Vous souhaitez analyser la sortie reflog, en examinant chaque hachage pour voir s'il contient le commit souhaité ou non.
Rechercher un commit de fusion ultérieur
Cela dépend du flux de travail, mais avec de bons flux de travail, les validations sont effectuées sur les branches de développement qui sont ensuite fusionnées. Vous pouvez le faire:
git log --merges <commit>..
pour voir les validations de fusion qui ont le commit donné comme ancêtre. (Si la validation n'a été fusionnée qu'une seule fois, la première devrait être la fusion que vous recherchez; sinon, vous devrez en examiner quelques-unes, je suppose.) Le message de validation de la fusion doit contenir le nom de la branche qui a été fusionnée.
Si vous voulez pouvoir compter sur cela, vous pouvez utiliser l' --no-ffoption git mergepour forcer la création de commit de fusion même dans le cas d'avance rapide. (Ne soyez pas trop impatient, cependant. Cela pourrait devenir obscurcissant s'il est surutilisé.) La réponse de VonC à une question connexe développe utilement ce sujet.
+1. L'absence totale d'informations sur ce problème particulier vous fait vous demander s'il s'agit réellement d'un problème? Les succursales peuvent changer, être renommées ou supprimées à tout moment. Cela peut git describesuffire, car les balises (annotées) peuvent être considérées comme plus importantes que les branches.
VonC
9
Je suis tout à fait d'accord - les branches sont conçues pour être légères et flexibles. Si vous adoptez un flux de travail dans lequel ces informations deviennent importantes, vous pouvez utiliser l' --no-ffoption pour vous assurer qu'il y a toujours un commit de fusion, afin que vous puissiez toujours tracer le chemin d'un commit donné lors de sa fusion vers master.
Cascabel
32
Pour info, si vous voulez trouver des validations qui n'existent que sur la télécommande, ajoutez le -adrapeau à la première commande, par exemplegit branch -a --contains <commit>
Jonathan Day
8
@JonathanDay: Non, cela trouvera des commits sur n'importe quelle branche. Si vous ne souhaitez en utiliser que sur la télécommande, utilisez -r.
Cascabel
7
@SimonTewsi Comme je l'ai dit, si c'est vraiment un problème, utilisez merge --no-ffpour enregistrer de manière fiable le nom de la branche lorsque vous fusionnez. Mais sinon, considérez les noms de branche comme des étiquettes courtes temporaires et validez les descriptions comme permanentes. "Par quel nom abrégé avons-nous fait référence à cela pendant le développement?" ne devrait vraiment pas être une question aussi importante que "que fait cet engagement?"
Cascabel
156
Cette commande simple fonctionne comme un charme:
git name-rev <SHA>
Par exemple (où test-branch est le nom de la branche):
Tu m'as sauvé la journée. C'est la solution parfaite.
Taco
8
Et il n'a fallu que 8 ans pour cette solution parfaite. Merci!
S1J0
6
J'ai trouvé git name-rev --name-only <SHA>plus utile pour obtenir uniquement le nom de la branche. Ma question ... Peut-elle retourner plus d'une succursale en toute circonstance?
git-what-branch(Script Perl, voir ci-dessous) ne semble plus être maintenu.
git-when-mergedest une alternative écrite en Python qui fonctionne très bien pour moi.
Trouvez quand un commit a été fusionné dans une ou plusieurs branches.
Recherchez le commit de fusion qui a été introduit COMMITdans les BRANCHs spécifiés.
Plus précisément, recherchez le commit le plus ancien dans l'historique du premier parent BRANCHqui contient le COMMITcomme ancêtre.
Indiquez-nous (par défaut) le chemin causal le plus ancien des validations et des fusions pour que la validation demandée atteigne une branche nommée. Si une validation a été effectuée directement sur une branche nommée, c'est évidemment le premier chemin.
Par chemin causal le plus ancien, nous entendons le chemin qui a fusionné en une branche nommée le plus tôt, par temps de validation (sauf si --topo-orderspécifié).
PERFORMANCE
Si de nombreuses branches (par exemple des centaines) contiennent la validation, le système peut prendre beaucoup de temps (pour une validation particulière dans l'arborescence Linux, il a fallu 8 secondes pour explorer une branche, mais il y avait plus de 200 branches candidates) pour suivre le chemin à chaque validation.
Sélection d'un particulier--reference-branch --reference tag à examiner sera des centaines de fois plus rapide (si vous avez des centaines de branches candidates).
EXEMPLES
# git-what-branch --all 1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4
1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4 first merged onto master using the following minimal temporal path:
v2.6.12-rc3-450-g1f9c381 merged up at v2.6.12-rc3-590-gbfd4bda (Thu May 5 08:59:37 2005)
v2.6.12-rc3-590-gbfd4bda merged up at v2.6.12-rc3-461-g84e48b6 (Tue May 3 18:27:24 2005)
v2.6.12-rc3-461-g84e48b6 is on master
v2.6.12-rc3-461-g84e48b6 is on v2.6.12-n
[...]
Ce programme ne prend pas en compte les effets de la sélection à la volée de l'engagement d'intérêt, mais uniquement des opérations de fusion.
git-what-branchne semble plus se maintenir. git-when-merged est une alternative écrite en Python qui fonctionne très bien pour moi.
sschuberth
@sschuberth merci pour cette mise à jour. J'ai inclus votre commentaire dans la réponse pour plus de visibilité.
VonC
37
Par exemple, pour trouver que la c0118favalidation est venue de redesign_interactions:
* ccfd449 (HEAD -> develop) Require to return undef if no digits found
* 93dd5ff Merge pull request #4 from KES777/clean_api
|\
| * 39d82d1 Fix tc0118faests for debugging debugger internals
| * ed67179 Move &push_frame out of core
| * 2fd84b5 Do not lose info about call point
| * 3ab09a2 Improve debugger output: Show info about emitted events
| * a435005 Merge branch 'redesign_interactions' into clean_api
| |\
| | * a06cc29 Code comments
| | * d5d6266 Remove copy/paste code
| | * c0118fa Allow command to choose how continue interaction
| | * 19cb534 Emit &interact event
Vous devez exécuter:
git log c0118fa..HEAD --ancestry-path --merges
Faites défiler vers le bas pour trouver la dernière validation de fusion . Lequel est:
commit a435005445a6752dfe788b8d994e155b3cd9778f
Merge: 0953cac a06cc29
Author: Eugen Konkov
Date: Sat Oct 1 00:54:18 2016 +0300
Merge branch 'redesign_interactions' into clean_api
C'était la seule solution qui m'a donné le résultat souhaité. J'ai essayé le reste.
artisan
Notez que cela ne fonctionne que si les résumés de validation de fusion contiennent les noms de branche utilisés dans les fusions, ce qu'ils font généralement par défaut. Cependant git merge -m"Any String Here", les informations sur les branches source et cible seront masquées.
qneill
@qneill: Non, la fusion a toujours plus sur les branches fusionnées: Merge: f6b70fa d58bdcb. Vous pouvez nommer votre commit de fusion comme vous. Je n'aurai pas d'importance
Eugen Konkov
1
@EugenKonkov une fois que les branches ont traversé la fusion, l'historique du chemin dans le graphique d'où elles proviennent est laissé dans le reflog, mais pas dans la base de données d'objets git. J'ai posté une réponse en essayant d'expliquer ce que je dis
qneill
La version UPD fonctionne pour moi, une commande simple qui trouve le commit d'origine
vpalmu
9
git branch --contains <ref>est la commande "porcelaine" la plus évidente pour ce faire. Si vous voulez faire quelque chose de similaire avec seulement des commandes "plomberie":
COMMIT=$(git rev-parse <ref>) # expands hash if needed
for BRANCH in $(git for-each-ref --format "%(refname)" refs/heads); do
if $(git rev-list $BRANCH | fgrep -q $COMMIT); then
echo $BRANCH
fi
done
Quelque chose semble manquer dans la deuxième phrase.
Peter Mortensen
J'ai mis à jour la description. Merci pour la rétroaction.
phyatt
4
L'option d'un pauvre est d'utiliser l'outil tig1 sur HEAD, recherchez le commettras, puis suivre visuellement la ligne de ce commit arrière jusqu'à une fusion validation est vu. Le message de fusion par défaut doit spécifier quelle branche est fusionnée à où :)
1 Tig est une interface en mode texte basée sur ncurses pour Git. Il fonctionne principalement comme un navigateur de référentiel Git, mais il peut également aider à organiser les modifications pour la validation au niveau du bloc et agir comme un pager pour la sortie de diverses commandes Git.
À titre expérimental, j'ai créé un hook post-commit qui stocke des informations sur la branche actuellement extraite dans les métadonnées de commit. J'ai également légèrement modifié gitk pour afficher ces informations.
Pour être honnête, je ne savais pas que des notes git existaient lorsque j'ai écrit cela. Oui, utiliser git notes pour réaliser la même chose est probablement une meilleure idée.
pajp
3
Je fais face au même problème ( Jenkins multibranch pipeline) - n'avoir que des informations de commit et essayer de trouver un nom de branche d'où ce commit est originaire. Il doit fonctionner pour les succursales distantes, les copies locales ne sont pas disponibles.
Voici ce avec quoi je travaille:
git rev-parse HEAD | xargs git name-rev
En option, vous pouvez supprimer la sortie:
git rev-parse HEAD | xargs git name-rev | cut -d' ' -f2 | sed 's/remotes\/origin\///g'
Si l'OP essaie de déterminer l' historique qui a été traversé par une branche lors de la création d'un commit particulier ("découvrez de quelle branche provient un commit en fonction de sa valeur de hachage SHA-1"), alors sans le reflog il n'y a pas de enregistrements dans la base de données d'objets Git qui montre quelle branche nommée était liée à quel historique de validation.
(J'ai posté cela comme réponse en réponse à un commentaire.)
Et quelle est la sortie de git log 80c10e5..HEAD --ancestry-path --merges --oneline --color | tail -n 1et les git log 086c9ce..HEAD --ancestry-path --merges --oneline --color | tail -n 1commandes pour les deux cas?
Eugen Konkov
Les SHA changent bien sûr à chaque fois que les commandes sont exécutées, pour répéter vos commandes, j'ai utilisé HEAD ^ 1 et HEAD ^ 2 lors d'une nouvelle exécution. Les commandes et la sortie sont: $ git log HEAD^1..HEAD --ancestry-path --merges --oneline --color | tail -n 1qui donne 376142d merge brancheset $ git log HEAD^2..HEAD --ancestry-path --merges --oneline --color | tail -n 1qui donne 376142d merge branches - qui montre le résumé de la validation de la fusion, qui (comme je l'ai affirmé) peut être écrasé lors de la création de la fusion, masquant éventuellement l'historique des branches de la fusion.
qneill
0
TL; DR:
Utilisez ce qui suit si vous vous souciez des états de sortie du shell:
branch-current - le nom de la branche actuelle
branch-names - noms de branche propres (un par ligne)
branch-name - Assurez-vous qu'une seule branche est renvoyée de branch-names
Les deux branch-nameet branch-namesacceptent un commettras comme argument, et par défaut à HEADsi aucune est donnée.
En raison du statut de sortie, ceux-ci peuvent être construits en toute sécurité. Par exemple, pour obtenir la télécommande utilisée pour la récupération:
Je ne veux pas vraiment déprécier cela, car à proprement parler, il est vrai que git ne stocke pas en permanence ces informations, mais il est très souvent possible de le savoir néanmoins. Voir ma réponse.
Réponses:
Bien que Dav ait raison de dire que les informations ne sont pas directement stockées, cela ne signifie pas que vous ne pourrez jamais le découvrir. Voici quelques choses que vous pouvez faire.
Rechercher les branches sur lesquelles le commit est activé
Cela vous indiquera toutes les branches qui ont le commit donné dans leur histoire. Évidemment, cela est moins utile si la validation a déjà été fusionnée.
Rechercher les reflogs
Si vous travaillez dans le référentiel dans lequel la validation a été effectuée, vous pouvez rechercher les reflogs pour la ligne de cette validation. Les reflogs de plus de 90 jours sont élagués par git-gc, donc si le commit est trop ancien, vous ne le trouverez pas. Cela dit, vous pouvez le faire:
pour trouver le commit a871742. Notez que vous DEVEZ utiliser les 7 premiers chiffres abrégés du commit. La sortie devrait ressembler à ceci:
indiquant que la validation a été effectuée sur la branche "achèvement". La sortie par défaut affiche des hachages de validation abrégés, alors assurez-vous de ne pas rechercher le hachage complet ou vous ne trouverez rien.
git reflog show
est en fait juste un alias pourgit log -g --abbrev-commit --pretty=oneline
, donc si vous voulez jouer avec le format de sortie pour rendre différentes choses disponibles pour grep, c'est votre point de départ!Si vous ne travaillez pas dans le référentiel où la validation a été effectuée, le mieux que vous puissiez faire dans ce cas est d'examiner les reflogs et de trouver quand la validation a été introduite pour la première fois dans votre référentiel; avec un peu de chance, vous êtes allé chercher la branche dans laquelle il s'était engagé. C'est un peu plus complexe, car vous ne pouvez pas parcourir à la fois l'arbre de validation et les reflogs. Vous souhaitez analyser la sortie reflog, en examinant chaque hachage pour voir s'il contient le commit souhaité ou non.
Rechercher un commit de fusion ultérieur
Cela dépend du flux de travail, mais avec de bons flux de travail, les validations sont effectuées sur les branches de développement qui sont ensuite fusionnées. Vous pouvez le faire:
pour voir les validations de fusion qui ont le commit donné comme ancêtre. (Si la validation n'a été fusionnée qu'une seule fois, la première devrait être la fusion que vous recherchez; sinon, vous devrez en examiner quelques-unes, je suppose.) Le message de validation de la fusion doit contenir le nom de la branche qui a été fusionnée.
Si vous voulez pouvoir compter sur cela, vous pouvez utiliser l'
--no-ff
optiongit merge
pour forcer la création de commit de fusion même dans le cas d'avance rapide. (Ne soyez pas trop impatient, cependant. Cela pourrait devenir obscurcissant s'il est surutilisé.) La réponse de VonC à une question connexe développe utilement ce sujet.la source
git describe
suffire, car les balises (annotées) peuvent être considérées comme plus importantes que les branches.--no-ff
option pour vous assurer qu'il y a toujours un commit de fusion, afin que vous puissiez toujours tracer le chemin d'un commit donné lors de sa fusion vers master.-a
drapeau à la première commande, par exemplegit branch -a --contains <commit>
-r
.merge --no-ff
pour enregistrer de manière fiable le nom de la branche lorsque vous fusionnez. Mais sinon, considérez les noms de branche comme des étiquettes courtes temporaires et validez les descriptions comme permanentes. "Par quel nom abrégé avons-nous fait référence à cela pendant le développement?" ne devrait vraiment pas être une question aussi importante que "que fait cet engagement?"Cette commande simple fonctionne comme un charme:
git name-rev <SHA>
Par exemple (où test-branch est le nom de la branche):
Même cela fonctionne pour des scénarios complexes, comme:
Ici,
git name-rev commit<SHA2>
renvoie branchB .la source
git name-rev --name-only <SHA>
plus utile pour obtenir uniquement le nom de la branche. Ma question ... Peut-elle retourner plus d'une succursale en toute circonstance?Mise à jour de décembre 2013:
Commentaires de sschuberth
Il est basé sur " Rechercher un commit de fusion qui inclut un commit spécifique ".
Réponse originale septembre 2010:
Sébastien Douche vient de twitter (16 minutes avant cette réponse SO):
Voici un script Perl de Seth Robertson qui semble très intéressant:
la source
git-what-branch
ne semble plus se maintenir. git-when-merged est une alternative écrite en Python qui fonctionne très bien pour moi.Par exemple, pour trouver que la
c0118fa
validation est venue deredesign_interactions
:Vous devez exécuter:
Faites défiler vers le bas pour trouver la dernière validation de fusion . Lequel est:
Mise à jour
Ou juste une commande:
la source
git merge -m"Any String Here"
, les informations sur les branches source et cible seront masquées.Merge: f6b70fa d58bdcb
. Vous pouvez nommer votre commit de fusion comme vous. Je n'aurai pas d'importancegit branch --contains <ref>
est la commande "porcelaine" la plus évidente pour ce faire. Si vous voulez faire quelque chose de similaire avec seulement des commandes "plomberie":(crosspost de cette réponse SO )
la source
khichar.anil a couvert la plupart de cela dans sa réponse.
J'ajoute juste le drapeau qui supprimera les balises de la liste des noms de révision. Cela nous donne:
la source
L'option d'un pauvre est d'utiliser l'outil
tig
1 surHEAD
, recherchez le commettras, puis suivre visuellement la ligne de ce commit arrière jusqu'à une fusion validation est vu. Le message de fusion par défaut doit spécifier quelle branche est fusionnée à où :)la source
À titre expérimental, j'ai créé un hook post-commit qui stocke des informations sur la branche actuellement extraite dans les métadonnées de commit. J'ai également légèrement modifié gitk pour afficher ces informations.
Vous pouvez le vérifier ici: https://github.com/pajp/branch-info-commits
la source
Je fais face au même problème ( Jenkins multibranch pipeline) - n'avoir que des informations de commit et essayer de trouver un nom de branche d'où ce commit est originaire. Il doit fonctionner pour les succursales distantes, les copies locales ne sont pas disponibles.
Voici ce avec quoi je travaille:
En option, vous pouvez supprimer la sortie:
la source
Je pense que quelqu'un devrait faire face au même problème qui ne peut pas trouver la branche, bien qu'il existe en fait dans une branche.
Vous feriez mieux de tirer tout d'abord:
Effectuez ensuite la recherche de branche:
ou:
la source
Si l'OP essaie de déterminer l' historique qui a été traversé par une branche lors de la création d'un commit particulier ("découvrez de quelle branche provient un commit en fonction de sa valeur de hachage SHA-1"), alors sans le reflog il n'y a pas de enregistrements dans la base de données d'objets Git qui montre quelle branche nommée était liée à quel historique de validation.
(J'ai posté cela comme réponse en réponse à un commentaire.)
J'espère que ce script illustre mon point:
La sortie montre l'absence de tout moyen de savoir si la validation avec 'Add f1' provenait de la branche b1 ou b2 du clone / tmp / r2 distant.
(Dernières lignes de la sortie ici)
la source
git log 80c10e5..HEAD --ancestry-path --merges --oneline --color | tail -n 1
et lesgit log 086c9ce..HEAD --ancestry-path --merges --oneline --color | tail -n 1
commandes pour les deux cas?$ git log HEAD^1..HEAD --ancestry-path --merges --oneline --color | tail -n 1
qui donne376142d merge branches
et$ git log HEAD^2..HEAD --ancestry-path --merges --oneline --color | tail -n 1
qui donne376142d merge branches
- qui montre le résumé de la validation de la fusion, qui (comme je l'ai affirmé) peut être écrasé lors de la création de la fusion, masquant éventuellement l'historique des branches de la fusion.TL; DR:
Utilisez ce qui suit si vous vous souciez des états de sortie du shell:
branch-current
- le nom de la branche actuellebranch-names
- noms de branche propres (un par ligne)branch-name
- Assurez-vous qu'une seule branche est renvoyée debranch-names
Les deux
branch-name
etbranch-names
acceptent un commettras comme argument, et par défaut àHEAD
si aucune est donnée.Alias utiles dans les scripts
Valider uniquement accessible à partir d'une seule branche
0
.Commit accessible depuis plusieurs succursales
1
.En raison du statut de sortie, ceux-ci peuvent être construits en toute sécurité. Par exemple, pour obtenir la télécommande utilisée pour la récupération:
la source
Pour trouver la succursale locale:
Pour trouver la branche distante:
la source
Mis à part la recherche dans tout l'arbre jusqu'à ce que vous trouviez un hachage correspondant, non.
la source