Git: Comment écraser tous les commits sur une branche

315

Je crée une nouvelle branche masteravec:

git checkout -b testbranch

J'y fais 20 commits.

Maintenant, je veux écraser ces 20 commits. Je fais ça avec:

git rebase -i HEAD~20

Et si je ne sais pas combien de commits? Existe-t-il un moyen de faire quelque chose comme:

git rebase -i all on this branch
user3803850
la source
6
Vous pouvez faire ce git rebase -i 58333012713fc168bd70ad00d191b3bdc601fa2dqui fera un rebase interactif où le numéro de commit est le dernier commit qui reste inchangé
denns
@denns En utilisant cette méthode avec le dernier commit de la branche, vous rebasiez de fantastique. Merci beaucoup!
Joshua Pinter

Réponses:

395

Une autre façon d'écraser tous vos commits est de réinitialiser l'index à master:

 git checkout yourBranch
 git reset $(git merge-base master yourBranch)
 git add -A
 git commit -m "one commit on yourBranch"

Ce n'est pas parfait car cela implique que vous savez de quelle branche "yourBranch" vient.
Remarque: trouver que la branche d'origine n'est pas facile / possible avec Git (la voie visuelle est souvent la plus simple , comme on le voit ici ).


EDIT: vous devrez utiliser git push --force


Karlotcha Hoa ajoute dans les commentaires :

Pour la réinitialisation, vous pouvez faire

git reset $(git merge-base master $(git rev-parse --abbrev-ref HEAD)) 

[Cela] utilise automatiquement la branche sur laquelle vous vous trouvez actuellement.
Et si vous utilisez cela, vous pouvez également utiliser un alias, car la commande ne dépend pas du nom de la branche .

VonC
la source
2
Mieux vaut payer pour valider où se trouve YourBranchactuellement. Cela restera YourBranchintact lorsque vous le ferezreset
Eugen Konkov
1
@Abdurrahim Ou ouvrez un git bash, et vous pouvez copier-coller ces commandes!
VonC
3
Pour la réinitialisation, vous pouvez git reset $(git merge-base master $(git rev-parse --abbrev-ref HEAD))utiliser automatiquement la branche sur laquelle vous vous trouvez. Et si vous utilisez cela, vous pouvez également utiliser un alias, car la commande ne dépend pas du nom de la branche.
Karlotcha Hoa
1
@Druska Pour les cas de branchement simlpe, non, cela devrait fonctionner correctement.
VonC
1
@Shimmy oui, à condition de forcer la poussée après la réinitialisation: git push --force(et prévenez vos collègues si vous êtes plusieurs personnes travaillant sur cette branche)
VonC
112

Extraire la branche pour laquelle vous souhaitez écraser toutes les validations en une seule validation. Disons que son appelé, feature_branch.

git checkout feature_branch

Étape 1:

Effectuez une réinitialisation logicielle de votre origin/feature_branchavec votre mastersuccursale locale (selon vos besoins, vous pouvez également réinitialiser avec origine / maître). Cela réinitialisera tous les commits supplémentaires dans votre feature_branch, mais sans modifier localement les modifications de votre fichier.

git reset --soft master

Étape 2:

Ajoutez toutes les modifications dans votre répertoire git repo, au nouveau commit qui va être créé. Et engagez la même chose avec un message.

git add -A && git commit -m "commit message goes here"

shanky
la source
6
C'était la solution la plus fiable pour moi - ne provoquant aucune erreur de rebase ni conflit de fusion.
ANTARA
1
Attention: le git add -A ajoute TOUT ce que vous avez dans le dossier local - à la branche.
David H
j'adore cette solution! c'est exactement ce que je voulais!
jacoballenwood
1
La meilleure solution pour un noob - un moment non destructif et uniquement oops peut être en train d'enregistrer trop de secrets d'application, etc., ce qui ne devrait pas avoir d'importance si vous avez un bon fichier
gitignore
@NSduToit Réponse courte: Non, vous n'êtes pas obligé. Après avoir fait les étapes mentionnées ci-dessus dans ma réponse, vous vous retrouverez avec un commit avec quelques modifications de code. Vous pouvez le considérer comme n'importe quel autre commit avec quelques modifications de code. Vous pouvez pousser cela vers votre succursale distante sans le -fdrapeau.
Shank
110

Ce que vous faites est assez sujet aux erreurs. Faites juste:

git rebase -i master

qui ne rebase automatiquement que les validations de votre branche sur le dernier master actuel.

Évoli
la source
5
merci, j'ai compris, mais pourquoi mon système est-il sujet aux erreurs
user3803850
10
Probablement parce qu'il est facile de se tromper de chiffre?
Daniel Scott
13
D'accord, c'est votre meilleure solution. mais suivez ce lien car il explique mieux ce que vous devez faire.
Christo
3
Au lieu d'écraser les validations, vous pouvez fusionner la branche vers master et effectuer une réinitialisation de git sur origin / master pour annuler toutes les validations. Cela vous permettrait de valider votre code non organisé existant aveccommit -am "the whole thing!"
nurettin
2
@nurettin Je pense que la reset origin/masterméthode est vraiment mauvaise car c'est la même chose que de faire des commits directement sur master - il n'y a pas d'historique de 'fusion de branche', pas d'option de pull request. La réponse de @WaZaA est beaucoup plus conforme au workflow git normal, je pense
Drenai
79

Une autre façon simple de le faire: allez sur la branche d'origine et faites a merge --squash. Cette commande ne fait pas le commit "écrasé". lorsque vous le faites, tous les messages de validation de yourBranch sont rassemblés.

$ git checkout master
$ git merge --squash yourBranch
$ git commit # all commit messages of yourBranch in one, really useful
 > [status 5007e77] Squashed commit of the following: ...
WaZaA
la source
1
Vrai. J'ai mentionné la différence entre fusion --squash et rebase -i dans stackoverflow.com/a/2427520/6309
VonC
1
Cela fonctionne si vous ne voulez pas vous écraser dans la branche parent, il suffit de créer et de basculer vers une nouvelle branche basée sur la branche parent et de faire la fusion de squash dans celle-ci.
Charlotte
Cheers mate, super astuce!
Nestor Milyaev le
agréable! je crée une branche "temp" hors de "master" d'abord pour écraser "yourBranch", puis fusionne "temp" dans "master".
lazieburd
34

En supposant que vous vous dériviez du maître, vous n'avez pas besoin d'entrer yourBranchtout le temps dans l'étape de réinitialisation:

git checkout yourBranch
git reset --soft HEAD~$(git rev-list --count HEAD ^master)
git add -A
git commit -m "one commit on yourBranch"

Explication :

  • git rev-list --count HEAD ^mastercompte les validations depuis que vous avez créé votre branche de fonctionnalité à partir du maître, f.ex. 20.
  • git reset --soft HEAD~20effectuera une réinitialisation logicielle des 20 derniers commits. Cela laisse vos modifications dans les fichiers, mais supprime les validations.

Utilisation :

Dans mon .bash_profile, j'ai ajouté un alias pour gisquashle faire avec une seule commande:

# squash all commits into one
alias gisquash='git reset --soft HEAD~$(git rev-list --count HEAD ^master)'

Après avoir réinitialisé et validé, vous devez faire a git push --force.

Indice :

Si vous utilisez Gitlab> = 11.0, vous n'avez plus besoin de le faire car il a une option de compression lors de la fusion des branches. Option de squashing Gitlab

mles
la source
15

Sur la base de la lecture de plusieurs questions et réponses Stackoverflow sur le squashing, je pense que c'est une bonne doublure pour écraser tous les commits sur une branche:

git reset --soft $(git merge-base master YOUR_BRANCH) && git commit -am "YOUR COMMIT MESSAGE" && git rebase -i master

Cela suppose que master est la branche de base.

Travis Reeder
la source
1
Merci beaucoup, la société a beaucoup de restrictions en place et n'a pas pu rebaser la manière habituelle avec un éditeur car elle n'était pas à haute voix pour enregistrer. Impossible également d'utiliser la fonction de squash et de fusion dans git car cette branche va à Lead dev pour la fusion et il n'aime pas ça. Ce 1 paquebot a fonctionné et a sauvé des maux de tête. Emploi super.
L1ghtk3ira
10

Solution pour les personnes qui préfèrent cliquer:

  1. Installez sourcetree (c'est gratuit)

  2. Vérifiez à quoi ressemblent vos commits. Vous avez probablement quelque chose de similaire à cela entrez la description de l'image ici

  3. Cliquez avec le bouton droit sur la validation parent . Dans notre cas, c'est la branche maître.

entrez la description de l'image ici

  1. Vous pouvez écraser le commit avec le précédent en cliquant sur un bouton. Dans notre cas, nous devons cliquer 2 fois. Vous pouvez également modifier le message de validation entrez la description de l'image ici

  2. Les résultats sont impressionnants et nous sommes prêts à pousser! entrez la description de l'image ici

Note latérale: Si vous poussiez vos validations partielles vers la télécommande, vous devez utiliser la poussée forcée après le squash

Marcin Szymczak
la source
Merci pour cela!
Crystal
0

Une autre solution consisterait à enregistrer tous les journaux de validation dans un fichier

git log> branch.log

Maintenant, branch.log aura tous les identifiants de commit depuis le début .. faites défiler vers le bas et prenez le premier commit (ce sera difficile dans le terminal) en utilisant le premier commit

git reset --soft

tous les commits seront écrasés

pranav
la source
0

La réinitialisation de Git, comme mentionné dans de nombreuses réponses, est de loin le moyen le plus simple et le plus simple de réaliser ce que vous voulez. Je l'utilise dans le workflow suivant:

(sur la branche développement)

git fetch
git merge origin/master  #so development branch has all current changes from master
git reset origin/master  #will show all changes from development branch to master as unstaged
git gui # do a final review, stage all changes you really want
git commit # all changes in a single commit
git branch -f master #update local master branch
git push origin master #push it
Marcus
la source
0

Tout ce git reset, dur, doux, et tout le reste mentionné ici fonctionne probablement (ce n'était pas le cas pour moi) si vous faites les étapes correctement et une sorte de génie.
Si vous êtes le Joe Smo moyen, essayez ceci:
Comment utiliser git merge --squash?


Ça m'a sauvé la vie, et ce sera mon coup de cœur pour le squash, je l'utilise 4 fois depuis que je l'ai découvert. Simple, propre et fondamentalement 1 comamnd. En bref:


si vous êtes sur une branche, appelez-la "my_new_feature" off develop et votre pull request a 35 commits (ou quelque soit le nombre) et vous voulez que ce soit 1.

A. Assurez-vous que votre branche est à jour, continuez développer, obtenir les dernières informations et fusionner et résoudre tous les conflits avec "my_new_feature"
(cette étape, vous devez vraiment la faire dès que vous le pouvez)

B. Obtenir la dernière de développer et de se lancer à un nouvel appel de la branche , il « my_new_feature_squashed »

C. la magie est là.
Vous voulez prendre votre travail de « my_new_feature » à « my_new_feature_squashed »
Bougez donc (tout sur votre nouvelle branche sur laquelle nous développons créé off):
fusion git --squash my_new_feature

Toutes vos modifications seront désormais sur votre nouvelle branche, n'hésitez pas à la tester, puis faites votre 1 commit, push, nouveau PR de cette branche - et attendez la répétition le lendemain.
N'aimez-vous pas le codage? :)

ItaiRoded
la source