Comment «git montrer» un commit de fusion avec une sortie de diff combinée même lorsque chaque fichier modifié est d'accord avec l'un des parents?

186

Après avoir effectué une fusion "simple" (une sans conflit), git showne montre généralement que quelque chose comme

commit 0e1329e551a5700614a2a34d8101e92fd9f2cad6 (HEAD, master)
Merge: fc17405 ee2de56
Author: Tilman Vogel <email@email>
Date:   Tue Feb 22 00:27:17 2011 +0100

Merge branch 'testing' into master

Cela est dû au fait que, pour les fusions, git showutilise le format de diff combiné qui omet les fichiers qui correspondent à l'une des versions parentes.

Existe-t-il un moyen de forcer git à toujours afficher toutes les différences en mode diff combiné?

Faire git show -maffichera les différences (en utilisant des différences par paires entre la nouvelle et toutes les versions parentes respectivement) mais je préférerais avoir cela avec les différences marquées par +/- dans les colonnes respectives comme en mode combiné.

Tilman Vogel
la source
1
@ Tilman Vogel: veuillez revoir la réponse acceptée - On dirait qu'il y a de meilleures réponses
Jayan
1
@Jayan Bien que les autres réponses soient plus populaires car elles contiennent des conseils utiles, elles ne se rapprochent en fait pas de mon problème en faisant simplement des différences bidirectionnelles. Je cherchais un différentiel à trois voies.
Tilman Vogel

Réponses:

-3

Non, il n'y a aucun moyen de faire cela avec git show. Mais ce serait certainement bien parfois, et ce serait probablement relativement facile à implémenter dans le code source de git (après tout, il suffit de lui dire de ne pas supprimer ce qu'il pense être une sortie étrangère), donc le patch pour le faire serait probablement accepté par les responsables de git.

Faites attention à ce que vous souhaitez, cependant; fusionner une branche avec un changement d'une ligne qui a été fourché il y a trois mois aura toujours un énorme diff par rapport à la ligne principale, et donc un tel diff complet serait presque totalement inutile. C'est pourquoi git ne le montre pas.

Apenwarr
la source
12
Veuillez ne pas dire «pas moyen de faire cela» aussi clairement que possible - voir d'autres réponses. C'est très trompeur à dire.
kgadek
1
git show HEAD ^ ... HEAD; # par la solution de @ hesham_EE.
Michael Dimmitt
git show HEAD ~ 1 ... HEAD ~ 0 --name-only; # meilleure syntaxe. Pour itérer les pr.
Michael Dimmitt
256

Regardez le message de validation:

commit 0e1329e551a5700614a2a34d8101e92fd9f2cad6 (HEAD, master)
Merge: fc17405 ee2de56
Author: Tilman Vogel <email@email>
Date:   Tue Feb 22 00:27:17 2011 +0100

Merge branch 'testing' into master

remarquez la ligne:

Merge: fc17405 ee2de56

prenez ces deux identifiants de validation et inversez-les. donc pour obtenir le diff que vous voulez, vous feriez:

git diff ee2de56..fc17405

pour afficher uniquement les noms des fichiers modifiés:

git diff --name-only ee2de56..fc17405

et pour les extraire, vous pouvez ajouter ceci à votre gitconfig:

exportfiles = !sh -c 'git diff $0 --name-only | "while read files; do mkdir -p \"$1/$(dirname $files)\"; cp -vf $files $1/$(dirname $files); done"'

puis utilisez-le en faisant:

git exportfiles ee2de56..fc17405 /c/temp/myproject
rip747
la source
Merci pour la suggestion mais je pense que cela ne résout pas mon problème. En raison du balisage et de la mise en forme des commentaires limités, j'ai ajouté mon commentaire à votre réponse. Désolé! Doit être évalué par les pairs jusqu'à ce qu'il soit visible.
Tilman Vogel
6
Il semble que ma modification a été refusée. En résumé: votre diff ne montre pas quels ajouts proviennent de quelle branche. Et vous ne pouvez pas distinguer si des modifications ont été ajoutées dans la seconde ou supprimées dans la première branche.
Tilman Vogel
45
Une meilleure solution est git diff fc17405...ee2de56- cela montrera tous les changements sur ee2de56 qui sont accessibles à partir de commits sur fc17405, ce que je crois est ce que vous voulez. Notez les 3 points au lieu de deux.
Kris Nuttycombe
1
@KrisNuttycombe 3 points et l'ordre. Et votre commentaire correspond à ce que je recherchais, ce qui, je pense, correspond davantage à ce que voulait l'OP.
Izkata
@KrisNuttycombe Cela ne fonctionne pas d'une manière ou d'une autre avec git log, qui montre toujours tous les commits, comme la ..variante. ..et ...faites de même pour log, mais pour diffils sont différents !? Comment obtenir une liste des commits qui ont été fusionnés dans cette branche?
Rudie
77

Une meilleure solution (mentionnée par @KrisNuttycombe):

git diff fc17405...ee2de56

pour le commit de fusion:

commit 0e1329e551a5700614a2a34d8101e92fd9f2cad6 (HEAD, master)
Merge: fc17405 ee2de56
Author: Tilman Vogel <email@email>
Date:   Tue Feb 22 00:27:17 2011 +0100

pour afficher toutes les modifications ee2de56qui sont accessibles à partir des validations fc17405. Notez l'ordre des hachages de validation - c'est le même que celui indiqué dans les informations de fusion:Merge: fc17405 ee2de56

Notez également les 3 points ...au lieu de deux !

Pour une liste des fichiers modifiés, vous pouvez utiliser:

git diff fc17405...ee2de56 --name-only
CodeManX
la source
C'est exactement ce que j'étais après +1.
geedoubleya
Cela montre en fait le résultat d'un conflit de fusion, contrairement à l'autre réponse.
Pod
12

Vous pouvez créer une branche avec HEAD défini sur un commit avant la fusion. Ensuite, vous pouvez faire:

git merge --squash testing

Cela fusionnera, mais ne validera pas. Ensuite:

git diff
side2k
la source
5

On dirait une réponse ici: https://public-inbox.org/git/[email protected]/

Donc, d'une manière similaire, courir

$ git diff --cc $ M $ M ^ 1 $ M ^ 2 $ (git merge-base $ M ^ 1 $ M ^ 2)

devrait afficher un patch combiné qui explique l'état à $ M par rapport aux états enregistrés dans ses parents et la base de fusion.

max630
la source
savez-vous si un outil peut être configuré pour afficher un tel diff de manière côte à côte, potentiellement dans quelques colonnes (comme dans la fenêtre de résolution des conflits de fusion IntelliJ)? Votre réponse est précisément ce que je cherchais
Max
@Max Non, j'ai bien peur que non. Googler "n-way visual diff" fournit des liens, donc je les ai essayés.
max630 le
4

Je pense que vous avez juste besoin de 'git show -c $ ref'. Essayer cela sur le référentiel git sur a8e4a59 montre un diff combiné (caractères plus / moins dans l'une des 2 colonnes). Comme le mentionne le manuel de git-show, il délègue à peu près «git diff-tree», donc ces options semblent utiles.

patthoyts
la source
3
Non, pour une fusion "simple", git show -c $refaffiche le même résultat que celui que j'ai cité, c'est-à-dire aucune différence. -csélectionne un mode de diff combiné très similaire au mode par défaut pour les validations de fusion qui est «--cc», voir git help showet git help diff-tree. Les deux omettent complètement les fichiers qui correspondent à l'une des versions parentes de ce fichier.
Tilman Vogel
a8e4a59en effet, ne rentre pas dans la catégorie des commits de fusion, je veux dire. Ce commit de fusion contient en effet un fichier qui diffère de ses deux versions parentes. Documentation/git-fast-import.txta des choses ajoutées d'un parent et d'autres de l'autre. Cela entraîne une sortie non vide de git diff-tree --cc. Cependant, seuls les changements dans ce cas «conflictuel» sont affichés. Tous les résultats de fusion "propres", regardez git show -m a8e4a59, ne sont pas affichés du tout.
Tilman Vogel
1
@TilmanVogel: Merci d'avoir signalé que les fusions de fichiers "sans intérêt" sont laissées en dehors de la git show -csortie. ( man git-diff-treedit "En outre, il ne répertorie que les fichiers qui ont été modifiés par tous les parents." mais pour ma part, je n'avais certainement pas repéré cela.)
Paul Whittaker
3

dans votre cas, il vous suffit de

git diff HEAD^ HEAD^2

ou simplement hacher pour vous commit:

git diff 0e1329e55^ 0e1329e55^2
gurugray
la source
4
Non, cela ne fait qu'un simple différentiel bidirectionnel entre les deux parents. Ce que je demandais, c'était un mode qui montre simultanément la différence entre git merge-base HEAD^ HEAD^2et HEAD^et HEAD^2dans le même style que pour les fichiers qui ont été fusionnés avec des conflits.
Tilman Vogel
3

Si votre validation de fusion est la validation 0e1329e5, comme ci-dessus, vous pouvez obtenir le diff contenu dans cette fusion en:

git diff 0e1329e5^..0e1329e5

J'espère que ça aide!

hesham_EE
la source
3

Si vous êtes assis à la validation de fusion, cela montre les différences:

git diff HEAD~1..HEAD

Si vous n'êtes pas à la validation de fusion, remplacez simplement HEAD par la validation de fusion. Cette méthode semble la plus simple et la plus intuitive.

Bruce Dawson
la source
1
Ce n'est pas une sortie "diff combiné". Obtenir des différences entre chaque paire de parents et HEAD n'est pas un problème ici.
Tilman Vogel
2

Vous pouvez utiliser la commande diff-tree avec l'indicateur -c. Cette commande vous montre quels fichiers ont été modifiés lors de la validation de fusion.

git diff-tree -c {merged_commit_sha}

J'ai obtenu la description de l'indicateur -c de Git-Scm :

Cet indicateur change la façon dont un commit de fusion est affiché (ce qui signifie qu'il n'est utile que lorsque la commande en reçoit un, ou --stdin). Il montre les différences entre chacun des parents et le résultat de la fusion simultanément au lieu de montrer les différences par paires entre un parent et le résultat un par un (ce que fait l'option -m). De plus, il ne répertorie que les fichiers modifiés par tous les parents.

Ehsan Mirsaeedi
la source
2
On dirait un bon article sur ce sujet: haacked.com/archive/2014/02/21/reviewing-merge-commits et peut-être cela aussi: longair.net/blog/2009/04/16/git-fetch-and-merge
Devin G Rhode
1

J'ai construit une approche polyvalente pour effectuer diverses opérations sur les commits d'une fusion.

Première étape : ajoutez un alias à git en éditant ~/.gitconfig:

[alias]
  range = "!. ~/.githelpers && run_on_merge_range"

Deuxième étape : dans ~/.githelpers, définissez une fonction bash:

run_on_merge_range() {
  cmd=$1; shift
  commit=$1; shift
  range=$(git show $commit | grep Merge: | awk '{print $2 "..." $3}')
  echo "git $cmd $range $@"
  if [ -z $range ]; then
    echo "No merge detected"
    exit 1
  fi
  git $cmd $range $@
}

Troisième étape : profitez!

git range log <merge SHA> --oneline
git range diff <merge SHA> --reverse -p
git range diff <merge SHA> --name-only

Il y a probablement BEAUCOUP de marge d'amélioration ici, je viens de fouetter cela ensemble pour surmonter une situation ennuyeuse. N'hésitez pas à vous moquer de ma syntaxe et / ou de ma logique bash.

Nerdmaster
la source
Notez que vous voudrez peut-être changer "..." en ".." dans le bit "awk", selon ce dont vous avez besoin et la commande que vous exécutez: stackoverflow.com/questions/462974
...