Question Comment puis-je fusionner deux commits en un si j'ai déjà commencé à rebaser?


J'essaie de fusionner 2 commits en 1, donc j'ai suivi "Squashing commits avec rebase" de git prêt.

Iran

git rebase --interactive HEAD~2

Dans l'éditeur résultant, je change pick à squash et puis arrêtez-le, mais le rebase échoue avec l'erreur

Impossible de "squasher" sans un commit précédent

Maintenant que mon arbre de travail a atteint cet état, j'ai de la difficulté à récupérer. La commande git rebase --interactive HEAD~2 échoue avec

Rebase interactive déjà démarrée

et git rebase --continue échoue avec

Impossible de "squasher" sans un commit précédent


989
2018-04-01 20:56


origine


Réponses:


Résumé

Le message d'erreur

Impossible de "squasher" sans un commit précédent

signifie que vous avez probablement tenté de "écraser vers le bas". Git écrase toujours un nouveau commit dans un commit plus ancien ou "vers le haut" tel que vu sur la liste de tâches de rebasage interactif, c'est-à-dire dans un commit sur une ligne précédente. Changer la commande sur la toute première ligne de votre liste de tâches squash produira toujours cette erreur car il n'y a rien pour le premier commit à écraser.

Le correctif

D'abord revenir à l'endroit où vous avez commencé

$ git rebase --abort

Dites que votre histoire est

$ git log --pretty=oneline
a931ac7c808e2471b22b5bd20f0cad046b1c5d0d c
b76d157d507e819d7511132bdb5a80dd421d854f b
df239176e1a2ffac927d8b496ea00d5488481db5 a

Autrement dit, a était le premier commit, puis b, et enfin c. Après avoir commis c, nous décidons d'écraser b et c ensemble:

(Note: En cours d'exécution git log canalise sa sortie dans un pager, less par défaut sur la plupart des plates-formes. Pour quitter le pager et revenir à votre invite de commande, appuyez sur q clé.)

Fonctionnement git rebase --interactive HEAD~2 vous donne un éditeur avec

pick b76d157 b
pick a931ac7 c

# Rebase df23917..a931ac7 onto df23917
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

(Notez que cette liste de tâches est dans l'ordre inverse par rapport à la sortie de git log.)

Changer de b pick à squash se traduira par l'erreur que vous avez vu, mais si à la place vous écrasez c dans b (plus récent commit dans l'ancien ou "écraser vers le haut") en changeant la liste de todo à

pick   b76d157 b
squash a931ac7 c

et sauvegarder-quitter votre éditeur, vous obtiendrez un autre éditeur dont le contenu est

# This is a combination of 2 commits.
# The first commit's message is:

b

# This is the 2nd commit message:

c

Lorsque vous enregistrez et quittez, le contenu du fichier modifié devient le message de validation du nouveau commit combiné:

$ git log --pretty=oneline
18fd73d3ce748f2a58d1b566c03dd9dafe0b6b4f b and c
df239176e1a2ffac927d8b496ea00d5488481db5 a

Remarque sur l'historique de la réécriture

La rebase interactive réécrit l'histoire. Tenter de pousser vers une télécommande qui contient l'ancien historique échouera parce que ce n'est pas un fast-forward.

Si la branche que vous avez rebasée est une branche de rubrique ou de fonctionnalité dans lequel vous travaillez par vous-même, pas de gros problème. Pousser vers un autre référentiel nécessitera --force Vous pouvez également, en fonction des autorisations du référentiel distant, supprimer l'ancienne branche, puis appuyer sur la version rebasée. Des exemples de ces commandes susceptibles de détruire le travail sont en dehors de la portée de cette réponse.

Réécrire l'histoire déjà publiée sur une branche dans laquelle vous travaillez avec d'autres personnes sans très Une bonne raison, telle que la fuite d'un mot de passe ou d'autres détails sensibles, force le travail sur vos collaborateurs et est antisociale et agace les autres développeurs. le La section «Récupération d'une base de rebuts en amont» dans le git rebase Documentation explique, avec un accent supplémentaire.

Rebaser (ou toute autre forme de réécriture) une branche sur laquelle d'autres ont travaillé est une mauvaise idée: quiconque en aval est obligé de corriger manuellement son historique. Cette section explique comment effectuer le correctif du point de vue de l'aval. La vraie solution, cependant, serait d'éviter de rebaser l'amont en premier lieu. ...


1533
2018-04-02 19:04



S'il y a plusieurs validations, vous pouvez utiliser git rebase -i pour écraser deux commits en un.

S'il y a seulement deux commits que vous voulez fusionner, et ils sont les "deux plus récents", les commandes suivantes peuvent être utilisées pour combiner les deux commits en un:

git reset --soft "HEAD^"
git commit --amend

335
2017-07-11 05:31



D'abord vous devriez vérifier combien de commits vous avez:

git log

Il y a deux statuts:

L'un est qu'il y a seulement deux commits:

Par exemple:

commit A
commit B

(Dans ce cas, vous ne pouvez pas utiliser git rebase pour faire), vous devez faire suite.

$ git reset --soft HEAD^1

$ git commit --amend

Un autre est qu'il y a plus de deux commits; vous voulez fusionner le commit C et D.

Par exemple:

commit A
commit B
commit C
commit D

(sous cette condition, vous pouvez utiliser git rebase)

git rebase -i B

Et que d'utiliser "squash" à faire. Le reste est très facile. Si vous ne savez toujours pas, veuillez lire http://zerodie.github.io/blog/2012/01/19/git-rebase-i/ 


50
2018-05-27 19:01



Rebase: Vous n'en aurez pas besoin:

Un moyen plus simple pour le scénario le plus fréquent.

Dans la plupart des cas:

En fait, si tout ce que vous voulez est juste fusionner simplement plusieurs commits récents en un seul  mais n'a pas besoin drop, reword et d'autres travaux de rebase.

vous pouvez simplement faire:

git reset --soft "HEAD~n"
  • En supposant ~n est le nombre de commits à délier doucement (c.-à-d. ~1, ~2, ...)

Ensuite, utilisez la commande suivante pour modifier le message de validation.

git commit --amend

ce qui est plutôt la même chose qu'une longue squash et une pick.

Et cela fonctionne pour n commits mais pas seulement deux commits comme la réponse ci-dessus a incité.


49
2018-04-26 09:15



En supposant que vous étiez dans votre propre branche de sujet. Si vous voulez fusionner les deux derniers commits en un et ressembler à un héros, bifurquez le commit juste avant de faire les deux derniers commits.

git checkout -b temp_branch HEAD^2

Ensuite, le squash commet l'autre branche dans cette nouvelle branche:

git merge branch_with_two_commits --squash

Cela apportera les changements mais ne les commettra pas. Alors, engagez-les et vous avez terminé.

git commit -m "my message"

Vous pouvez maintenant fusionner cette nouvelle branche de sujet dans votre branche principale.


26
2017-10-23 23:44



vous pouvez annuler le rebase avec

git rebase --abort

et quand vous exécutez la commande interactive rebase à nouveau le 'squash; commit doit être en dessous du commit commit dans la liste


22
2018-04-01 20:59



J'utilise souvent git reset - mixé pour rétablir une version de base avant que plusieurs commits que vous voulez fusionner, alors je fais un nouveau commit, de cette façon pourrait laisser votre commit le plus récent, assurer que votre version est HEAD après que vous ayez poussé vers le serveur.

commit ac72a4308ba70cc42aace47509a5e
Author: <me@me.com>
Date:   Tue Jun 11 10:23:07 2013 +0500

    Added algorithms for Cosine-similarity

commit 77df2a40e53136c7a2d58fd847372
Author: <me@me.com>
Date:   Tue Jun 11 13:02:14 2013 -0700

    Set stage for similar objects

commit 249cf9392da197573a17c8426c282
Author: Ralph <ralph@me.com>
Date:   Thu Jun 13 16:44:12 2013 -0700

    Fixed a bug in space world automation

Si je veux fusionner la tête de deux commits en un, d'abord j'utilise:

git reset --mixed 249cf9392da197573a17c8426c282

"249cf9392da197573a17c8426c282" était la troisième version, est aussi votre version de base avant de fusionner, après cela, je fais un nouveau commit:

git add .
git commit -m 'some commit message'

C'est tout, l'espoir est un autre moyen pour tout le monde.

FYI, de git reset --help:

 --mixed
     Resets the index but not the working tree (i.e., the changed files are
     preserved but not marked for commit) and reports what has not been
     updated. This is the default action.

13
2017-09-09 02:48



$ git rebase --abort

Exécutez ce code à tout moment si vous souhaitez annuler le rebas git

$ git rebase -i HEAD~2

Pour réappliquer les deux derniers validations. La commande ci-dessus va ouvrir un éditeur de code

  • [ Le dernier commit sera au fond ] Changer le dernier commettre à squash (s). Puisque le squash va fusionner avec le commit précédent.
  • Puis appuyez sur la touche Echap et tapez: wq pour enregistrer et fermer

Après: wq vous serez en mode de rebasement actif

Remarque: Vous obtiendrez un autre éditeur si aucun message d'avertissement / erreur, S'il y a une erreur ou un avertissement un autre éditeur ne s'affichera pas, vous pouvez annuler par runnning $ git rebase --abort si vous voyez une erreur ou un avertissement, continuez simplement en exécutant $ git rebase --continue

Vous verrez votre message 2 commit. Choisissez-en un ou écrivez votre propre message de validation, enregistrez et quittez [: wq]

Note 2: Vous devrez peut-être forcer de pousser vos modifications vers le repo distant si vous exécutez la commande rebase

$ git push -f

$ git push -f origin master


10
2018-02-20 21:49



Si votre branche maîtresse git log ressemble à quelque chose comme suit:

commit ac72a4308ba70cc42aace47509a5e
Author: <me@me.com>
Date:   Tue Jun 11 10:23:07 2013 +0500

    Added algorithms for Cosine-similarity

commit 77df2a40e53136c7a2d58fd847372
Author: <me@me.com>
Date:   Tue Jun 11 13:02:14 2013 -0700

    Set stage for similar objects

commit 249cf9392da197573a17c8426c282
Author: Ralph <ralph@me.com>
Date:   Thu Jun 13 16:44:12 2013 -0700

    Fixed a bug in space world automation

et vous voulez fusionner les deux meilleurs commits juste faire des étapes faciles:

  1. D'abord être sur le côté sûr de la caisse le deuxième dernier commit dans une branche distincte. Vous pouvez nommer la branche n'importe quoi. git checkout 77df2a40e53136c7a2d58fd847372 -b merged-commits
  2. Maintenant, choisissez juste vos changements du dernier commit dans cette nouvelle branche comme: git cherry-pick -n -x ac72a4308ba70cc42aace47509a5e. (Résolvez les conflits si cela se produit)
  3. Alors maintenant, vos changements dans le dernier commit sont là dans votre deuxième commit précédent. Mais vous devez encore vous engager, alors ajoutez d'abord les changements que vous venez de sélectionner, puis exécutez git commit --amend.

C'est tout. Vous pouvez pousser cette version fusionnée dans la branche "fusionné-commits" si vous le souhaitez.

En outre, vous pouvez ignorer les deux validations consécutives dans votre branche principale maintenant. Mettez à jour votre branche principale en tant que:

git checkout master
git reset --hard origin/master (CAUTION: This command will remove any local changes to your master branch)
git pull

1
2018-06-16 15:57



Depuis que j'utilise git cherry-pick pour à peu près tout, pour moi, il est naturel de le faire même ici.

Étant donné que j'ai branchX vérifié et il y a deux commits à la pointe de celui-ci, dont je veux créer un commit en combinant leur contenu, je fais ceci:

git checkout HEAD^ // Checkout the privious commit
git cherry-pick --no-commit branchX // Cherry pick the content of the second commit
git commit --amend // Create a new commit with their combined content

Si je veux mettre à jour branchX aussi (et je suppose que c'est l'inconvénient de cette méthode), je dois aussi:

git checkout branchX
git reset --hard <the_new_commit>

1
2017-11-26 10:52



Si vous souhaitez combiner les deux derniers validations et utiliser le message de validation plus ancien, vous pouvez automatiser le processus en utilisant expect.

Je suppose:

  • Vous utilisez vi comme éditeur
  • Vos commissions sont d'une ligne chacune

J'ai testé avec git version 2.14.3 (Apple Git-98).


#!/usr/bin/env expect
spawn git rebase -i HEAD~2

# down, delete word, insert 's' (for squash), Escape, save and quit
send "jdwis \033:wq\r"

expect "# This is a"

# down 4, delete 3 lines, save and quit
send "4j3d\r:wq\r"

interact

0
2018-02-06 04:45