Existe-t-il un moyen de savoir de quelle branche provient un commit étant donné son SHA-1 valeur de hachage ?
Des points bonus si vous pouvez me dire comment accomplir cela en utilisant Ruby Grit.
Existe-t-il un moyen de savoir de quelle branche provient un commit étant donné son SHA-1 valeur de hachage ?
Des points bonus si vous pouvez me dire comment accomplir cela en utilisant Ruby Grit.
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.
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.
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.
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-ff
option git 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.
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):
git name-rev 651ad3a
251ad3a remotes/origin/test-branch
Même cela fonctionne pour des scénarios complexes, comme:
origin/branchA/
/branchB
/commit<SHA1>
/commit<SHA2>
Ici, git name-rev commit<SHA2>
renvoie branchB .
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:
git-what-branch
(Script Perl, voir ci-dessous) ne semble plus être maintenu.git-when-merged
est une alternative écrite en Python qui fonctionne très bien pour moi.
Il est basé sur " Rechercher un commit de fusion qui inclut un commit spécifique ".
git when-merged [OPTIONS] COMMIT [BRANCH...]
Trouvez quand un commit a été fusionné dans une ou plusieurs branches.
Recherchez le commit de fusion qui a été introduitCOMMIT
dans les BRANCHs spécifiés.Plus précisément, recherchez le commit le plus ancien dans l'historique du premier parent
BRANCH
qui contient leCOMMIT
comme ancêtre.
Réponse originale septembre 2010:
Sébastien Douche vient de twitter (16 minutes avant cette réponse SO):
git-what-branch : Découvrez sur quelle branche se trouve un commit, ou comment il est arrivé à une branche nommée
Voici un script Perl de Seth Robertson qui semble très intéressant:
SYNOPSIS
git-what-branch [--allref] [--all] [--topo-order | --date-order ]
[--quiet] [--reference-branch=branchname] [--reference=reference]
<commit-hash/tag>...
APERÇU
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-order
spé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-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 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
Mise à jour
Ou juste une commande:
git log c0118fa..HEAD --ancestry-path --merges --oneline --color | tail -n 1
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'importance
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
(crosspost de cette réponse SO )
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:
git name-rev --name-only --exclude=tags/* $SHA
L'option d'un pauvre est d'utiliser l'outil tig
1 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.
Vous pouvez le vérifier ici: https://github.com/pajp/branch-info-commits
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'
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:
git pull --all
Effectuez ensuite la recherche de branche:
git name-rev <SHA>
ou:
git branch --contains <SHA>
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:
rm -rf /tmp/r1 /tmp/r2; mkdir /tmp/r1; cd /tmp/r1
git init; git config user.name n; git config user.email e@x.io
git commit -m"empty" --allow-empty; git branch -m b1; git branch b2
git checkout b1; touch f1; git add f1; git commit -m"Add f1"
git checkout b2; touch f2; git add f2; git commit -m"Add f2"
git merge -m"merge branches" b1; git checkout b1; git merge b2
git clone /tmp/r1 /tmp/r2; cd /tmp/r2; git fetch origin b2:b2
set -x;
cd /tmp/r1; git log --oneline --graph --decorate; git reflog b1; git reflog b2;
cd /tmp/r2; git log --oneline --graph --decorate; git reflog b1; git reflog b2;
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)
+ cd /tmp/r1
+ git log --oneline --graph --decorate
* f0c707d (HEAD, b2, b1) merge branches
|\
| * 086c9ce Add f1
* | 80c10e5 Add f2
|/
* 18feb84 empty
+ git reflog b1
f0c707d b1@{0}: merge b2: Fast-forward
086c9ce b1@{1}: commit: Add f1
18feb84 b1@{2}: Branch: renamed refs/heads/master to refs/heads/b1
18feb84 b1@{3}: commit (initial): empty
+ git reflog b2
f0c707d b2@{0}: merge b1: Merge made by the 'recursive' strategy.
80c10e5 b2@{1}: commit: Add f2
18feb84 b2@{2}: branch: Created from b1
+ cd /tmp/r2
+ git log --oneline --graph --decorate
* f0c707d (HEAD, origin/b2, origin/b1, origin/HEAD, b2, b1) merge branches
|\
| * 086c9ce Add f1
* | 80c10e5 Add f2
|/
* 18feb84 empty
+ git reflog b1
f0c707d b1@{0}: clone: from /tmp/r1
+ git reflog b2
f0c707d b2@{0}: fetch origin b2:b2: storing head
git log 80c10e5..HEAD --ancestry-path --merges --oneline --color | tail -n 1
et les git 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 donne 376142d merge branches
et $ git log HEAD^2..HEAD --ancestry-path --merges --oneline --color | tail -n 1
qui 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.
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 de branch-names
Les deux branch-name
et branch-names
acceptent un commettras comme argument, et par défaut à HEAD
si aucune est donnée.
branch-current = "symbolic-ref --short HEAD" # https://stackoverflow.com/a/19585361/5353461
branch-names = !"[ -z \"$1\" ] && git branch-current 2>/dev/null || git branch --format='%(refname:short)' --contains \"${1:-HEAD}\" #" # https://stackoverflow.com/a/19585361/5353461
branch-name = !"br=$(git branch-names \"$1\") && case \"$br\" in *$'\\n'*) printf \"Multiple branches:\\n%s\" \"$br\">&2; exit 1;; esac; echo \"$br\" #"
% git branch-name eae13ea
master
% echo $?
0
0
.% git branch-name 4bc6188
Multiple branches:
attempt-extract
master%
% echo $?
1
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:
remote-fetch = !"branch=$(git branch-name \"$1\") && git config branch.\"$branch\".remote || echo origin #"
Pour trouver la succursale locale:
grep -lR YOUR_COMMIT .git/refs/heads | sed 's/.git\/refs\/heads\///g'
Pour trouver la branche distante:
grep -lR $commit .git/refs/remotes | sed 's/.git\/refs\/remotes\///g'
Mis à part la recherche dans tout l'arbre jusqu'à ce que vous trouviez un hachage correspondant, non.