Comment puis-je écraser mes dernières validations X ensemble en une seule validation en utilisant Git?
git
rebase
squash
git-squash
markdorison
la source
la source
Réponses:
Utilisez
git rebase -i <after-this-commit>
et remplacez "pick" sur le second commit et les suivants par "squash" ou "fixup", comme décrit dans le manuel .Dans cet exemple, il
<after-this-commit>
s'agit du hachage SHA1 ou de l'emplacement relatif de la tête de la branche actuelle à partir de laquelle les validations sont analysées pour la commande de rebase. Par exemple, si l'utilisateur souhaite afficher 5 validations à partir de la tête courante dans le passé, la commande estgit rebase -i HEAD~5
.la source
<after-this-commit>
?<after-this-commit>
est commit X + 1, c'est-à-dire le parent du commit le plus ancien que vous souhaitez écraser.rebase -i
approche etreset --soft
is,rebase -i
me permet de conserver l'auteur du commit, tout enreset --soft
me permettant de recommencer. Parfois, j'ai besoin d'écraser les commits de demandes de tirage tout en conservant les informations sur l'auteur. Parfois, je dois réinitialiser le soft sur mes propres commits. Upvotes aux deux grandes réponses de toute façon.Vous pouvez le faire assez facilement sans
git rebase
ougit merge --squash
. Dans cet exemple, nous écraserons les 3 derniers commits.Si vous souhaitez écrire le nouveau message de commit à partir de zéro, cela suffit:
Si vous souhaitez commencer à éditer le nouveau message de validation avec une concaténation des messages de validation existants (c'est-à-dire semblable à ce qu'une
git rebase -i
liste d'instructions pick / squash / squash /… / squash vous lancerait), alors vous devez extraire ces messages et passer àgit commit
:Ces deux méthodes écrasent les trois dernières validations en une seule nouvelle validation de la même manière. La réinitialisation logicielle redirige simplement HEAD vers le dernier commit que vous ne voulez pas écraser. Ni l'index ni l'arborescence de travail ne sont touchés par la réinitialisation logicielle, laissant l'index dans l'état souhaité pour votre nouveau commit (c'est-à-dire qu'il a déjà toutes les modifications des commits que vous êtes sur le point de «jeter»).
la source
git rebase --squash-recent
- être , ou mêmegit commit --amend-many
.branch@{upstream}
(ou juste@{upstream}
pour la branche actuelle; dans les deux cas, la dernière partie peut être abrégée en@{u}
; voir gitrevisions ). Cela peut différer de votre «dernier commit poussé» (par exemple, si quelqu'un d'autre a poussé quelque chose qui a construit au-dessus de votre dernier push et que vous l'avez récupéré), mais il semble que cela pourrait être proche de ce que vous voulez.push -f
mais sinon c'était charmant, merci.git push --force
ensuite pour que ça prenne le commitVous pouvez utiliser
git merge --squash
pour cela, qui est légèrement plus élégant quegit rebase -i
. Supposons que vous soyez maître et que vous vouliez écraser les 12 derniers commits en un seul.AVERTISSEMENT: assurez-vous d'abord de valider votre travail - vérifiez qu'il
git status
est propre (cargit reset --hard
il supprimera les modifications par étapes et non par étapes)Alors:
La documentation de
git merge
décrit l'--squash
option plus en détail.Mise à jour: le seul véritable avantage de cette méthode par rapport à la plus simple
git reset --soft HEAD~12 && git commit
suggérée par Chris Johnsen dans sa réponse est que vous obtenez le message de validation pré-rempli avec chaque message de validation que vous écrasez.la source
git rebase -i
, mais vous n'en donnez pas la raison. Provisoirement -1, car il me semble qu'en fait le contraire est vrai et c'est un hack; N'exécutez-vous pas plus de commandes que nécessaire juste pour forcergit merge
à faire l'une des chosesgit rebase
spécifiquement conçues pour?git merge --squash
est également plus facile à utiliser dans un script. Essentiellement, le raisonnement était que vous n'avez pas besoin du tout d '"interactivité"git rebase -i
pour cela.git merge --squash
est moins susceptible de produire des conflits de fusion face aux mouvements / suppressions / renommages par rapport au rebasage, surtout si vous fusionnez à partir d'une branche locale. (Avertissement: basé sur une seule expérience, corrigez-moi si ce n'est pas vrai dans le cas général!)HEAD@{1}
juste du bon côté, par exemple lorsque votre flux de travail est interrompu pendant une heure par une panne de courant, etc.Je recommande d'éviter
git reset
autant que possible - en particulier pour les novices Git. À moins que vous n'ayez vraiment besoin d'automatiser un processus basé sur un certain nombre de validations, il existe une méthode moins exotique ...git merge --squash (working branch name)
git commit
Le message de validation sera prérempli en fonction du squash.
la source
gitk
pour étiqueter la ligne de code que vous écrasez et étiqueter également la base sur laquelle écraser. Dans le cas normal, ces deux étiquettes existent déjà, donc l'étape (1) peut être ignorée.git branch your-feature && git reset --hard HEAD~N
le moyen le plus pratique. Cependant, cela implique à nouveau git reset, ce que cette réponse a tenté d'éviter.Sur la base de la réponse de Chris Johnsen ,
Ajouter un alias global "squash" depuis bash: (ou Git Bash sous Windows)
... ou à l'aide de l'invite de commandes de Windows:
Votre
~/.gitconfig
devrait maintenant contenir cet alias:Usage:
... qui écrase automatiquement les derniers
N
commits, inclus.Remarque: Le message de validation résultant est une combinaison de toutes les validations écrasées, dans l'ordre. Si vous n'êtes pas satisfait de cela, vous pouvez toujours
git commit --amend
le modifier manuellement. (Ou, modifiez l'alias en fonction de vos goûts.)la source
git squash -m "New summary."
etN
déterminer automatiquement le nombre de commits non poussés.git commit --amend
pour modifier davantage le message, mais cet alias vous permet de prendre un bon départ sur ce qui devrait être dans le message de validation.Grâce à ce billet de blog pratique, j'ai trouvé que vous pouvez utiliser cette commande pour écraser les 3 derniers commits:
C'est pratique car cela fonctionne même lorsque vous êtes sur une succursale locale sans informations de suivi / repo à distance.
La commande ouvrira l'éditeur de rebase interactif qui vous permettra ensuite de réorganiser, écraser, reformuler, etc. comme d'habitude.
Utilisation de l'éditeur de rebase interactif:
L'éditeur de rebase interactif affiche les trois derniers commits. Cette contrainte a été déterminée par l'
HEAD~3
exécution de la commandegit rebase -i HEAD~3
.Le commit le plus récent,,
HEAD
est affiché en premier sur la ligne 1. Les lignes commençant par a#
sont des commentaires / documentation.La documentation affichée est assez claire. Sur une ligne donnée, vous pouvez changer la commande de
pick
en une commande de votre choix.Je préfère utiliser la commande
fixup
car cela "écrase" les modifications du commit dans le commit sur la ligne ci-dessus et rejette le message du commit.Comme le commit sur la ligne 1 est
HEAD
, dans la plupart des cas, vous laisseriez cela commepick
. Vous ne pouvez pas utilisersquash
oufixup
car il n'y a pas d'autre commit pour écraser le commit.Vous pouvez également modifier l'ordre des validations. Cela vous permet d'annuler ou de corriger les commits qui ne sont pas adjacents chronologiquement.
Un exemple pratique au quotidien
J'ai récemment validé une nouvelle fonctionnalité. Depuis lors, j'ai commis deux corrections de bugs. Mais maintenant, j'ai découvert un bug (ou peut-être juste une faute d'orthographe) dans la nouvelle fonctionnalité que j'ai validée. Comme c'est ennuyeux! Je ne veux pas qu'un nouveau commit pollue mon historique de commit!
La première chose que je fais est de corriger l'erreur et de faire un nouveau commit avec le commentaire
squash this into my new feature!
.Je lance ensuite
git log
ougitk
et j'obtiens le commit SHA de la nouvelle fonctionnalité (dans ce cas1ff9460
).Ensuite, je lance l'éditeur de rebase interactif avec
git rebase -i 1ff9460~
. le~
après la validation SHA indique l'éditeur d'inclure cette validation dans l'éditeur.Ensuite, je déplace la validation contenant le correctif (
fe7f1e0
) sous la validation de la fonctionnalité et je changepick
enfixup
.À la fermeture de l'éditeur, le correctif sera écrasé dans la validation de la fonctionnalité et mon historique de validation sera joli et propre!
Cela fonctionne bien lorsque toutes les validations sont locales, mais si vous essayez de modifier les validations déjà poussées vers la télécommande, vous pouvez vraiment causer des problèmes aux autres développeurs qui ont extrait la même branche!
la source
pick
en ligne 1. Si vous choisissezsquash
oufixup
pour le commit sur la ligne 1, git affichera un message disant "erreur: ne peut pas" réparer "sans un commit précédent". Ensuite, il vous donnera la possibilité de le corriger: "Vous pouvez résoudre ce problème avec 'git rebase --edit-todo' puis exécuter 'git rebase --continue'." ou vous pouvez simplement abandonner et recommencer: "Ou vous pouvez abandonner le rebase avec 'git rebase --abort'.".Si vous utilisez TortoiseGit, vous pouvez la fonction
Combine to one commit
:Show Log
Combine to one commit
dans le menu contextuelCette fonction exécute automatiquement toutes les étapes git simples nécessaires. Malheureusement, uniquement disponible pour Windows.
la source
Pour ce faire, vous pouvez utiliser la commande git suivante.
n (= 4 ici) est le numéro du dernier commit. Ensuite, vous avez les options suivantes,
Mettre à jour comme ci-dessous
pick
un commit etsquash
les autres dans le plus récent,Pour plus de détails, cliquez sur le lien
la source
Basé sur cet article j'ai trouvé cette méthode plus facile pour mon cas d'utilisation.
Ma branche «dev» devançait «origin / dev» de 96 commits (donc ces commits n'étaient pas encore poussés vers la télécommande).
Je voulais écraser ces commits en un seul avant de pousser le changement. Je préfère réinitialiser la branche à l'état «origine / dev» (cela laissera toutes les modifications des 96 validations non mises en scène), puis valider les modifications à la fois:
la source
Dans la branche sur laquelle vous souhaitez combiner les validations, exécutez:
exemple:
Cela ouvrira l'éditeur de texte et vous devez changer le 'pick' devant chaque commit avec 'squash' si vous souhaitez que ces commits soient fusionnés ensemble. De la documentation:
p, pick = utiliser commit
s, squash = utiliser la validation, mais fusionner avec la validation précédente
Par exemple, si vous cherchez à fusionner toutes les validations en une seule, la «sélection» est la première validation que vous avez effectuée et toutes les futures (placées sous la première) doivent être définies sur «squash». Si vous utilisez vim, utilisez : x en mode insertion pour enregistrer et quitter l'éditeur.
Puis pour continuer le rebase:
Pour en savoir plus à ce sujet et sur d'autres façons de réécrire votre historique de validation, consultez cet article utile
la source
--continue
et vim:x
.git add
la bonne configuration dans vos fichiers que vous utilisezgit rebase --continue
pour passer à la prochaine validation et commencer à fusionner.:x
est une commande qui enregistrera les modifications du fichier lors de l'utilisation de vim voir ceciAnomies réponse est bonne, mais je ne me sentais pas en sécurité à ce sujet, j'ai donc décidé d'ajouter quelques captures d'écran.
Étape 0: journal git
Voyez où vous en êtes
git log
. Plus important encore, trouvez le hachage de validation du premier commit que vous ne voulez pas écraser. Donc seulement:Étape 1: git rebase
Exécutez
git rebase -i [your hash]
, dans mon cas:Étape 2: choisissez / écrasez ce que vous voulez
Dans mon cas, je veux tout écraser sur le commit qui était le premier dans le temps. L'ordre est du premier au dernier, donc exactement dans l'autre sens que dans
git log
. Dans mon cas, je veux:Étape 3: ajuster le (s) message (s)
Si vous avez sélectionné un seul commit et écrasé le reste, vous pouvez ajuster un message de commit:
C'est ça. Une fois que vous avez enregistré ceci (
:wq
), vous avez terminé. Jetez-y un œil avecgit log
.la source
git log
Procédure 1
1) Identifier le hachage court de validation
Ici même
git log --oneline
pouvez également utiliser pour obtenir un hachage court.2) Si vous voulez écraser (fusionner) les deux derniers commit
3) Cela ouvre un
nano
éditeur pour la fusion. Et ça ressemble à ci-dessous4) renommer le mot
pick
poursquash
lequel est présent avantabcd1234
. Après avoir renommé, il devrait être comme ci-dessous.5) Maintenant, enregistrez et fermez l'
nano
éditeur. Appuyez surctrl + o
et appuyez surEnter
pour enregistrer. Et puis appuyez surctrl + x
pour quitter l'éditeur.6) Ensuite
nano
éditeur s'ouvre à nouveau pour mettre à jour les commentaires, si nécessaire, mettez-le à jour.7) Maintenant, il est écrasé avec succès, vous pouvez le vérifier en vérifiant les journaux.
8) Maintenant, poussez pour repo. Remarque pour ajouter un
+
signe avant le nom de la branche. Cela signifie une poussée forcée.Remarque: Ceci est basé sur l'utilisation de git sur
ubuntu
shell. Si vous utilisez différents systèmes d'exploitation (Windows
ouMac
), les commandes ci-dessus sont les mêmes, sauf l'éditeur. Vous pourriez obtenir un éditeur différent.Procédure 2
--fixup
option et leOLDCOMMIT
devrait être sur lequel nous devons fusionner (écraser) ce commit.Maintenant, cela crée un nouveau commit au-dessus de HEAD avec
fixup1 <OLDCOMMIT_MSG>
.OLDCOMMIT
.Ici
^
signifie le précédent commitOLDCOMMIT
. Cetterebase
commande ouvre une fenêtre interactive sur un éditeur (vim ou nano) sur lequel nous n'avons pas besoin de faire quoi que ce soit juste enregistrer et sortir est suffisant. Parce que l'option transmise à ceci déplacera automatiquement le dernier commit à côté de l'ancien commit et changera l'opération enfixup
(équivalent à squash). Ensuite, le rebase continue et se termine.Procédure 3
--amend
peuvent être utilisés avecgit-commit
.--amend
Fusionne ici les nouvelles modifications au dernier commitcdababcd
et génère un nouvel ID de commit1d4ab2e1
Conclusion
la source
Pour écraser les 10 derniers commits en 1 seul commit:
Si vous souhaitez également mettre à jour la branche distante avec la validation écrasée:
la source
Si vous êtes sur une branche distante (appelée
feature-branch
) clonée à partir d'un référentiel doré (golden_repo_name
), voici la technique pour écraser vos commits en une seule:Commander le repo doré
Créez-en une nouvelle branche (repo doré) comme suit
Fusion de squash avec votre succursale locale que vous avez déjà
Validez vos modifications (ce sera la seule validation qui va dans dev-branch)
Poussez la branche vers votre référentiel local
la source
Ce qui peut être vraiment pratique:
trouvez le hachage de validation que vous souhaitez écraser, par exemple
d43e15
.Maintenant, utilisez
la source
C'est super bavard, mais d'une manière plutôt cool, donc je vais juste le jeter dans le ring:
Traduction: fournir un nouvel "éditeur" pour git qui, si le nom de fichier à éditer est
git-rebase-todo
(l'invite de rebase interactive) change tout sauf le premier "pick" en "squash", et génère autrement vim - de sorte que lorsque vous y êtes invité pour modifier le message de validation écrasé, vous obtenez vim. (Et évidemment, j'écrasais les cinq derniers commits sur branch foo, mais vous pouvez changer cela comme bon vous semble.)Je ferais probablement ce que Mark Longair a suggéré .
la source
Si vous voulez écraser chaque commit en un seul commit (par exemple lorsque vous publiez un projet publiquement pour la première fois), essayez:
la source
2020 Solution simple sans rebase:
git reset --soft HEAD~2
git commit -m "new commit message"
git push --force
2 signifie que les deux derniers commits seront écrasés. Vous pouvez le remplacer par n'importe quel numéro
la source
Je pense que la façon la plus simple de le faire est de créer une nouvelle branche hors de master et de faire une fusion - squash de la branche de fonctionnalité.
Ensuite, vous avez toutes les modifications prêtes à être validées.
la source
One-liner simple qui fonctionne toujours, étant donné que vous êtes actuellement sur la branche que vous souhaitez écraser, master est la branche dont il est issu et le dernier commit contient le message de commit et l'auteur que vous souhaitez utiliser:
la source
si par exemple vous voulez écraser les 3 dernières validations en une seule validation dans une branche (référentiel distant) dans par exemple: https://bitbucket.org
Ce que j'ai fait c'est
la source
⚠️ AVERTISSEMENT: «Mon dernier X valide» peut être ambigu.
Dans cette histoire très abrégée du référentiel https://github.com/fleetwood-mac/band-history , vous avez ouvert une pull request pour fusionner le Bill Clinton commit dans l'original (
MASTER
commit Fleetwood Mac ).Vous avez ouvert une demande de pull et sur GitHub vous voyez ceci:
Quatre commits:
Penser que personne ne se soucierait jamais de lire l'historique complet du référentiel. (Il y a en fait un dépôt, cliquez sur le lien ci-dessus!) Vous décidez d'écraser ces commits. Alors tu vas courir
git reset --soft HEAD~4 && git commit
. Alors vousgit push --force
sur GitHub pour nettoyer votre PR.Et que se passe-t-il? Vous venez de faire un seul commit qui va de Fritz à Bill Clinton. Parce que vous avez oublié qu'hier vous travailliez sur la version Buckingham Nicks de ce projet. Et
git log
ne correspond pas à ce que vous voyez sur GitHub.🐻 MORALE DE L'HISTOIRE
git checkout
lesgit reset --soft
quegit commit
que funes directement à partir du de la àla source
Si vous ne vous souciez pas des messages de validation des validations intermédiaires, vous pouvez utiliser
la source
Si vous travaillez avec GitLab, vous pouvez simplement cliquer sur l'option Squash dans la demande de fusion comme indiqué ci-dessous. Le message de validation sera le titre de la demande de fusion.
la source
où le nombre de ^ est X
(dans ce cas, écrasez les deux derniers commits)
la source
En plus d'autres excellentes réponses, j'aimerais ajouter comment
git rebase -i
me confond toujours avec l'ordre de validation - du plus ancien au plus récent ou vice versa? Voici donc mon workflow:git rebase -i HEAD~[N]
, où N est le nombre de validations que je veux rejoindre, en commençant par la plus récente . Celagit rebase -i HEAD~5
signifierait donc "écraser les 5 derniers commits en un nouveau";Sources et lectures supplémentaires: # 1 , # 2 .
la source
Qu'en est-il d'une réponse à la question liée à un flux de travail comme celui-ci?
merge --squash
après le PR, mais l'équipe a pensé que cela ralentirait le processus.)Je n'ai pas vu de flux de travail comme celui-ci sur cette page. (Cela peut être mes yeux.) Si je comprends
rebase
bien, plusieurs fusions nécessiteraient plusieurs résolutions de conflits . Je ne veux même pas y penser!Donc, cela semble fonctionner pour nous.
git pull master
git checkout -b new-branch
git checkout -b new-branch-temp
git checkout new-branch
git merge --squash new-branch-temp
// met tous les changements en scènegit commit 'one message to rule them all'
git push
la source
Je trouve qu'une solution plus générique ne consiste pas à spécifier les «N» commits, mais plutôt la branche / commit-id que vous souhaitez écraser au-dessus. C'est moins sujet aux erreurs que de compter les validations jusqu'à une validation spécifique - spécifiez simplement la balise directement, ou si vous voulez vraiment compter, vous pouvez spécifier HEAD ~ N.
Dans mon flux de travail, je démarre une branche, et mon premier commit sur cette branche résume l'objectif (c'est-à-dire que c'est généralement ce que je vais pousser comme message «final» pour la fonctionnalité dans le référentiel public.) Donc, quand j'ai terminé, tout Je veux faire est
git squash master
revenir au premier message et puis je suis prêt à pousser.J'utilise l'alias:
Cela videra l'historique écrasé avant de le faire - cela vous donne une chance de récupérer en récupérant un ancien ID de validation de la console si vous souhaitez revenir. (Les utilisateurs de Solaris notent qu'il utilise l'
-i
option sed GNU , les utilisateurs Mac et Linux devraient être d'accord avec cela.)la source
git squash master
lorsque nous sommes contrôlés sur l'esclave. que se passera-t-il? cacherons-nous le conflit?En question, il pourrait être ambigu ce que l'on entend par «dernier».
par exemple,
git log --graph
sort les éléments suivants (simplifiés):Les dernières validations par le temps sont H0, merge, B0. Pour les écraser, vous devrez rebaser votre branche fusionnée lors de la validation H1.
Le problème est que H0 contient H1 et H2 (et généralement plus de validations avant fusion et après branchement) tandis que B0 n'en contient pas. Vous devez donc gérer les modifications de H0, fusion, H1, H2, B0 au moins.
Il est possible d'utiliser rebase mais de manière différente, puis dans d'autres réponses mentionnées:
rebase -i HEAD~2
Cela vous montrera les options de choix (comme mentionné dans d'autres réponses):
Mettez la courge au lieu de choisir H0:
Après la sauvegarde et la sortie, le rebase appliquera les commits à son tour après H1. Cela signifie qu'il vous demandera de résoudre à nouveau les conflits (où HEAD sera H1 dans un premier temps, puis accumulera les validations au fur et à mesure de leur application).
Une fois le rebase terminé, vous pouvez choisir le message pour H0 et B0 écrasés:
PS Si vous faites juste une réinitialisation sur BO: (par exemple, l'utilisation
reset --mixed
est expliquée plus en détail ici https://stackoverflow.com/a/18690845/2405850 ):puis vous vous écrasez dans les changements B0 de H0, H1, H2 (perdre complètement valide les changements après la ramification et avant la fusion.
la source
1) git reset --soft HEAD ~ n
n - Numéro du commit, besoin de squash
2) git commit -m "nouveau message de commit"
3) git push origin nom_branche --force
la source