Fusionner (avec squash) toutes les modifications d'une autre branche en un seul commit

479

Dans Git, existe-t-il un moyen de fusionner toutes les modifications d'une branche dans une autre, mais de squash en un seul commit en même temps?

Je travaille souvent sur une nouvelle fonctionnalité dans une branche distincte et j'engage / pousse régulièrement - principalement pour la sauvegarde ou pour transférer ce que je travaille sur une autre machine. La plupart du temps, ces commits disent «Feature xxx WIP» ou quelque chose de redondant.

Une fois que le travail est terminé et que je veux fusionner la branche WIP en maître, je voudrais ignorer toutes ces validations intermédiaires, et juste avoir une seule validation propre.

Y a-t-il un moyen facile de faire ceci?

Sinon, que diriez-vous d'une commande qui écrase toutes les validations sur une branche depuis le point où elle a été branchée?

Brad Robinson
la source

Réponses:

601

Une autre option est git merge --squash <feature branch>alors enfin de faire un git commit.

De la fusion Git

--squash

--no-squash

Produisez l'arborescence de travail et l'état d'index comme si une fusion réelle s'était produite (à l'exception des informations de fusion), mais ne faites pas de validation ni ne déplacez le HEAD, ni d'enregistrement $GIT_DIR/MERGE_HEADpour que la git commitcommande suivante crée une validation de fusion. Cela vous permet de créer un seul commit au-dessus de la branche actuelle dont l'effet est identique à la fusion d'une autre branche (ou plus dans le cas d'une pieuvre).

fseto
la source
1
Fonction cool! J'adore git. Bien que je vais certainement l'utiliser à l'avenir maintenant, je recommanderais toujours de vous familiariser avec rebase -i. C'est une bonne compétence à avoir, juste au cas où vous voudriez vraiment leur faire plus d'un seul commit.
Will Buck
4
Un mot d'avertissement: cela fonctionne, mais le message de validation par défaut inclut le journal de la branche en cours de fusion. Le problème est qu'il ressemble au format que vous voyez normalement où tout le texte affiché ne fait pas réellement partie du message de validation, mais dans ce cas, il le fait. Donc, si vous ne voulez pas tout cela, vous devez supprimer tout cela manuellement de votre message de validation. J'aurais dû tester cela avant de l'utiliser ...
still_dreaming_1
23
Cela, et soyez averti que la succursale ne sera pas considérée comme fusionnée. stackoverflow.com/questions/19308790/…
Ryan
3
À mon humble avis, cela aurait dû être appelérebase --squash
Andy
donc (car il ne fusionne pas vraiment la branche de fonctionnalité), cela serait approprié si vous deviez supprimer la branche de fonctionnalité après validation. Est-ce exact? (Je ne suis pas un expert git)
Andrew Spencer
214

Je l'ai trouvé! La commande de fusion a une --squashoption

git checkout master
git merge --squash WIP

à ce stade, tout est fusionné, peut-être en conflit, mais pas engagé. Je peux donc maintenant:

git add .
git commit -m "Merged WIP"
Brad Robinson
la source
2
que fait- git add .il?
Michael Potter
1
@MichaelPotter Il ajoute tous les fichiers et modifications
Daksh Shah
2
git add .ajoute tous les fichiers non ignorés dans le répertoire courant, je me méfierais de ramasser des fichiers involontaires de cette façon.
Jake Cobb
7
Comme alternative à git add .vous pouvez utiliser git add -upour ajouter uniquement des fichiers qui ont déjà été ajoutés à l'arborescence.
Brandon Ogle
19
Suggérant qu'un "git add." faire aussi est déroutant. Quand je fais le "git merge --squash WIP", il a déjà les changements écrasés dans l'index. Il suffit de les engager. Faire un "git add". ajoutera les modifications qui se trouvent dans le répertoire de travail, mais qui ne faisaient pas partie de la branche de fonctionnalité. La question était de savoir comment valider les modifications dans la branche de fonctionnalité en une seule validation.
John Pankowicz
30

Essayez git rebase -i mastervotre branche de fonctionnalités. Vous pouvez ensuite changer tous les "sauf" en "squash" pour combiner les commits. Voir les validations de squashing avec rebase

Enfin, vous pouvez ensuite effectuer la fusion à partir de la branche principale.

fseto
la source
8
Oui, cela fonctionne, mais je ne veux pas les tracas du rebase interactif. Je veux juste tout depuis que la branche s'est aplatie.
Brad Robinson
2
+1 Cela fait une histoire propre. Il est beaucoup plus facile d'identifier et de gérer les commits sous forme de patchs individuels, de cartes, d'histoires, etc.
Ryan
2

Utilisation git merge --squash <feature branch>comme réponse acceptée suggère la fait l'affaire, mais elle ne montrera pas la branche fusionnée comme réellement fusionnée.

Une meilleure solution consiste donc à:

  • Créer une nouvelle branche à partir du dernier maître
  • Fusionner <feature branch> dans ce qui précède en utilisantgit merge --squash
  • Fusionner la branche nouvellement créée en maître

Ce wiki explique la procédure en détail.

raratiru
la source
0

J'ai créé mon propre alias git pour faire exactement cela. Je l'appelle git freebase! Il prendra votre branche de fonctionnalité désordonnée et non rebasable existante et la recréera afin qu'elle devienne une nouvelle branche avec le même nom avec ses validations écrasées en une seule validation et rebasées sur la branche que vous spécifiez (master par défaut). À la toute fin, il vous permettra d'utiliser le message de validation que vous souhaitez pour votre nouvelle branche "freebased".

Installez-le en plaçant l'alias suivant dans votre .gitconfig:

[alias]
  freebase = "!f() { \
    TOPIC="$(git branch | grep '\\*' | cut -d ' ' -f2)"; \
    NEWBASE="${1:-master}"; \
    PREVSHA1="$(git rev-parse HEAD)"; \
    echo "Freebaseing $TOPIC onto $NEWBASE, previous sha1 was $PREVSHA1"; \
    echo "---"; \
    git reset --hard "$NEWBASE"; \
    git merge --squash "$PREVSHA1"; \
    git commit; \
  }; f"

Utilisez-le à partir de votre branche de fonctionnalités en exécutant: git freebase <new-base>

Je ne l'ai testé que quelques fois, alors lisez-le d'abord et assurez-vous que vous voulez l'exécuter. Par mesure de sécurité, il imprime le sha1 de départ, vous devriez donc pouvoir restaurer votre ancienne branche en cas de problème.

Je vais le maintenir dans mon référentiel dotfiles sur github: https://github.com/stevecrozz/dotfiles/blob/master/.gitconfig

Stephen Crosby
la source
travaillé comme un bonheur! vous pourriez aussi bien jeter un œil à evernote.com/shard/s52/sh/7f8f4ff1-9a68-413f-9225-c49e3ee2fafd/…
Ilya Sheershoff
-1

git merge --squash <feature branch> est une bonne option. Le "git commit" vous indique tous les messages de validation de branche de fonctionnalité avec votre choix de le garder.

Pour moins de validation, fusionnez.

git merge do x times --git reset HEAD ^ --soft puis git commit.

Risque - les fichiers supprimés peuvent revenir.

Arjun Mullick
la source
-5

Vous pouvez le faire avec la commande "rebase". Appelons les branches «principales» et «fonctionnelles»:

git checkout feature
git rebase main

La commande rebase rejouera toutes les validations sur "feature" comme une validation avec un parent égal à "main".

Vous voudrez peut-être exécuter git merge mainavant git rebase mainsi "main" a changé depuis la création de "feature" (ou depuis la fusion la plus récente). De cette façon, vous avez toujours votre historique complet au cas où vous auriez un conflit de fusion.

Après le rebase, vous pouvez fusionner votre branche en main, ce qui devrait entraîner une fusion rapide:

git checkout main
git merge feature

Voir la page de rebase de Understanding Git Conceptually pour une bonne vue d'ensemble

NamshubWriter
la source
Ça n'a pas marché pour moi. Je viens de créer un simple repo de test, avec une branche WIP et j'ai essayé ce qui précède et j'ai obtenu des conflits de fusion (même si je n'avais fait aucune modification sur le maître).
Brad Robinson
Si la fonctionnalité a été créée à partir de main (git checkout -b feature main) et que vous avez récemment fusionné à partir de main, vous ne devriez pas avoir de conflits avec la rebase
NamshubWriter
OK, réessayé. N'a pas eu de conflits cette fois, mais l'histoire n'a pas été écrasée.
Brad Robinson
En jetant un autre coup d'œil à la documentation de git-merge, vous avez raison, certains des commits resteront. Si vous avez effectué des fusions précédentes de "principal" vers "fonctionnalité", alors le rebase supprimera certains d'entre eux, mais pas tous.
NamshubWriter
N'oubliez pas que le rebasage peut être assez dangereux si la branche de fonctionnalité a déjà été publiée. Plus d'informations sur cette question SO .
Robert Rossmann