155 votes

Trouver une branche Git contenant des modifications sur un fichier donné

J'ai 57 succursales locales. Je sais que j'ai apporté une modification à un fichier spécifique dans l'une d'entre elles, mais je ne suis pas sûr laquelle. Y a-t-il une sorte de commande que je peux exécuter pour trouver quelles succursales contiennent des modifications à un certain fichier?

135voto

Seth Robertson Points 13276

Trouver toutes les branches qui contiennent un changement de NOM_FICHIER (même si c'est avant le point de branchement (non enregistré))

NOM_FICHIER=""
git log --all --format=%H $NOM_FICHIER | while read f; do git branch --contains $f; done | sort -u

Inspecter manuellement :

gitk --all --date-order -- $NOM_FICHIER

Trouver tous les changements de NOM_FICHIER non fusionnés dans master :

git for-each-ref --format="%(refname:short)" refs/heads | grep -v master | while read br; do git cherry master $br | while read x h; do if [ "`git log -n 1 --format=%H $h -- $NOM_FICHIER`" = "$h" ]; then echo $br; fi; done; done | sort -u

1 votes

Est-ce que je dois remplacer quelque chose dans cette commande en dehors de FILENAME? Cela renvoie tous les 57 noms de branches.

0 votes

@Dustin: Si les 57 branches contiennent ce nom de fichier, alors les 57 branches contiennent un changement qui inclut ce nom de fichier. Les branches commencent à partir de la révision la plus ancienne accessible sur cette branche, même si cette révision existait avant que vous ne créiez la branche (la branche est créée rétroactivement). Je pense que vous devez mieux définir votre problème. Savez-vous quel est le changement? Pourriez-vous utiliser git log -Schange … ou git log --grep LOGMESSAGE … (avec … représentant le reste de la commande que j'ai mentionné).

3 votes

@Dustin: Une autre option est d'utiliser gitk --all -- filename qui vous montrera graphiquement toutes les modifications apportées à ce fichier. Si vous pouvez identifier le commit en question, alors vous pouvez utiliser git branch --contains pour voir à quelles branches le commit a migré. Si vous voulez voir sur quelle branche le commit en question a été originellement créé, alors recherchez git-what-branch, mais soyez conscient que les fusions fast-forward peuvent obscurcir cette information.

81voto

Adam Dymitruk Points 34999

Tout ce dont vous avez besoin, c'est

git log --all -- chemin/vers/fichier/nomdefichier

Si vous voulez connaître la branche immédiatement, vous pouvez également utiliser :

git log --all --format=%S -- chemin/vers/fichier/nomdefichier | xargs -I{} -n 1 echo {} trouvé dans && git branch --contains {}

En outre, si vous avez apporté des modifications de nom, vous voudrez peut-être inclure --follow pour la commande Git log.

22 votes

Cela affichera les commits, mais il a demandé quelle branche. Ajoutez un --source là-dessus et vous êtes bon.

0 votes

Merci, mais je ne pense pas que cela montre toutes les branches pour chaque commit. Mais cela serait utile.

1 votes

Vrai, mais dans ce cas particulier, il n'en cherchait qu'un seul.

21voto

Simpleton Points 421

Il semble que ce soit toujours un problème sans solution appropriée. Je n'ai pas assez de crédits pour commenter, alors voici ma petite contribution.

La 1ère solution de Seth Robertson a plutôt bien fonctionné pour moi, mais ne m'a donné que des branches locales, parmi lesquelles figuraient de nombreux faux positifs, probablement en raison des fusions de la branche stable.

La 2ème solution d'Adam Dymitruk n'a pas du tout fonctionné pour moi. Tout d'abord, qu'est-ce que --format=%5 ? Ce n'est pas reconnu par git, je n'ai rien trouvé à ce sujet et je n'ai pas réussi à le faire fonctionner avec d'autres options de format.

Mais sa 1ère solution combinée avec l'option --source et avec un simple grep s'est révélée utile :

git log --all --source --  | grep -o "refs/.*" | sort -u

Cela me donne un certain nombre de tags et branches distants et une branche locale, où j'ai apporté les dernières modifications au fichier. Je ne suis pas sûr de la complétude de cette méthode.

MISE À JOUR comme demandé par @nealmcb, tri des branches par changement le plus récent :

Tout d'abord, vous pourriez changer le grep en "refs/heads/.*", ce qui vous donnera uniquement les branches locales. S'il n'y a que quelques branches, vous pourriez examiner le dernier commit de chacune de cette façon :

git log -1  -- 

S'il y a plus de branches et que vous voulez vraiment automatiser cela, vous pouvez combiner les deux commandes en utilisant xargs, le formatage du git log et un autre tri dans cette commande en une ligne :

git log --all --source --  | grep -o "refs/heads/.*" | sort -u | xargs -I '{}' git log -1 --format=%aI%x20%S '{}' --  | sort -r

Cela donnera un résultat de la forme :

2020-05-07T15:10:59+02:00 refs/heads/branch1
2020-05-05T16:11:52+02:00 refs/heads/branch3
2020-03-27T11:45:48+00:00 refs/heads/branch2

0 votes

Super - merci. Et maintenant, que diriez-vous de trier par modification la plus récente ?

0 votes

L'utilité de cette dernière longue commande est OMGWTFBBQ niveau INCROYABLE. Absolument magnifique. Ne laissez pas les votes sur les autres réponses d'une avance de huit ans vous tromper. C'est de l'or, Jerry! (sauf que cette fois, c'est vrai)

7voto

Marcin Raczkowski Points 515

Je sais que cette question est ancienne, mais j'ai continué à y revenir avant de développer ma propre solution. Je trouve qu'elle est plus élégante et grâce à l'utilisation de la base de fusion, elle élimine les branches non désirées.

#!/bin/bash

fichier=$1
base=${2:-master}

b=$(tput bold) # Joli affichage
n=$(tput sgr0)

echo "Recherche des branches avec des modifications sur $fichier liées à la branche $base"

# Nous parcourons toutes les branches locales en utilisant la plomberie
for branche in $(git for-each-ref --format='%(refname:short)' refs/heads/); do
  # Nous établissons un ancêtre commun entre la base et la branche, pour ne trouver que les modifications ultérieures.  
  base_fusion=$(git merge-base $base $branche)
  # Vérifier s'il y a des modifications dans un chemin donné.
  modifications=$(git diff $base_fusion..$branche --stat -- $fichier)

  if [[ ! -z $modifications ]]; then
    echo "Branche: ${b}$branche${n} | Base de fusion: $base_fusion"
    # Afficher les statistiques des modifications joliment formatées
    git diff $base_fusion..$branche --stat -- $fichier
  fi
done

Si vous le placez dans le PATH en tant que git-find-changes (avec des permissions d'exécution) - vous pouvez alors l'appeler avec git find-changes /chemin

Exemple de sortie pour git find-changes app/models/

Branche: update_callbacks | Base de fusion : db07d23b5d9600d88ba0864aca8fe79aad14e55b
 app/models/api/callback_config.rb | 28 ++++++++++++++++++++++++++++
 1 fichier modifié, 28 insertions(+)
Branche: repackaging | Base de fusion : 76578b9b7ee373fbe541a9e39cf93cf5ff150c73
 app/models/order.rb                 | 38 ++++++++++++++++++++++++++++++++++++++
 1 fichier modifié, 38 insertions(+)

1 votes

Script très intéressant. Upvoted. Est-il show-changes ou find-changes?

0 votes

@VonC merci, usage corrigé, devrait être trouvé partout

0 votes

Merci beaucoup pour cela - cela m'a vraiment aidé aujourd'hui. Une petite modification - l'utilisation devrait être git-trouver-changements une fois que vous l'avez ajouté à votre chemin. Vous avez oublié le trait d'union entre git et trouver.

0voto

whiteinge Points 59

Voici une méthode brutale et peu élégante, mais je m'attends à ce qu'elle fonctionne. Assurez-vous d'avoir mis de côté tous les changements non validés au préalable car cela changera la branche sur laquelle vous vous trouvez actuellement.

for branch in $(git for-each-ref --format="%(refname:short)" refs/heads); do
    git checkout $branch && git grep QUELQUECHOSE
done

1 votes

Parce que si vous connaissez le changement, vous pouvez utiliser git log -S

0 votes

Quel shell supposez-vous? Bash?

0 votes

Pas de bashismes, cela devrait fonctionner sur POSIX. Je ne suis pas sûr que for-each-ref respecte toujours ce drapeau short cependant. Cela dit, ignorez ma réponse; les autres réponses sont meilleures.

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