web-dev-qa-db-fra.com

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

J'essaie de fusionner 2 commits en 1, alors j'ai suivi "écraser commets avec rebase" de git ready .

J'ai couru

git rebase --interactive HEAD~2

Dans l'éditeur résultant, je remplace pick par squash, puis enregistrez-quit, mais la base est défaillante avec l'erreur

Impossible de 'squash' sans un commit précédent

Maintenant que mon arbre de travail a atteint cet état, je ne parviens pas à récupérer. La commande git rebase --interactive HEAD~2 échoue avec

Rebase interactive déjà commencé

et git rebase --continue échoue avec

Impossible de 'squash' sans un commit précédent

1101
michael

Sommaire

Le message d'erreur

Impossible de 'squash' sans un commit précédent

Git écrase toujours un nouveau commit dans un commit plus ancien ou "vers le haut" tel qu'il est affiché dans la liste de tâches interactive de base , c’est-à-dire un commit sur une ligne précédente. Changer la commande de la toute première ligne de votre liste de tâches en squash produira toujours cette erreur car il n’ya rien dans le premier commit à écraser.

Le correctif

D'abord, retournez à votre point de départ

$ git rebase --abort

Dis que ton histoire est

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

C'est-à-dire que a était le premier commit, puis b et enfin c. Après avoir commis c, nous décidons d’écraser b et c ensemble:

(Remarque: l'exécution de git log transfère sa sortie dans un pager, less par défaut sur la plupart des plates-formes. Pour quitter le pageur et revenir à l'invite de commande, appuyez sur la touche Touche q.)

Lancer 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 de la sortie de git log.)

Si vous changez pick de b en squash, vous obtiendrez l’erreur que vous avez constatée, mais si vous écrasez c en b (nouvelle commande plus ancienne ou plus ancienne) en modifiant la liste de tâches en

pick   b76d157 b
squash a931ac7 c

et en quittant votre éditeur, vous aurez 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 un message de validation du nouveau commit combiné:

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

Note sur la réécriture de l'historique

Rebase interactive réécrit l'histoire. Toute tentative d'envoi à une télécommande qui contient l'ancien historique échouera car il ne s'agit pas d'une avance rapide.

Si la branche que vous rebasez est une branche de sujet ou de fonctionnalité dans laquelle vous travaillez seul , ce n'est pas grave. Pousser vers un autre référentiel nécessitera l’option --force, ou vous pourrez éventuellement, en fonction des autorisations du référentiel distant, supprimer d’abord l’ancienne branche puis Transférer la version rebasée. Des exemples de commandes susceptibles de détruire du travail n'entrent pas dans le cadre de cette réponse.

Réécrire l’historique déjà publié sur une branche dans laquelle vous travaillez avec d’autres personnes sans de très bonnes raisons, telles que la divulgation d’un mot de passe ou d’autres données confidentielles, obligent ainsi vos collaborateurs à travailler de manière antisociale. va déranger les autres développeurs. La section "Récupération à partir d'une base amont" dans la documentation git rebase explique, avec une emphase supplémentaire.

Redéfinir la base (ou toute autre forme de réécriture) d'une branche sur laquelle d'autres ont travaillé est une mauvaise idée: toute personne en aval de celle-ci est obligée 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 rebasonner l'upstream en premier lieu.

1675
Greg Bacon

S'il existe plusieurs validations, vous pouvez utiliser git rebase -i pour réduire deux validations en une seule.

S'il n'y a que deux commits que vous souhaitez fusionner et qu'il s'agit des "deux plus récents", vous pouvez utiliser les commandes suivantes pour combiner les deux commits en un:

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

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 combinez simplement plusieurs commits récents en un mais n'avez pas besoin de drop, reword et d'autres travaux de rebase.

vous pouvez simplement faire:

git reset --soft "HEAD~n"
  • En supposant que ~n soit le nombre de commits pour annuler la validation doucement (c.-à-d. ~1, ~2, ...)

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

git commit --amend

ce qui est à peu près la même chose qu'une longue plage de squash et un pick.

Et cela fonctionne pour n commits mais pas seulement deux commits, comme indiqué ci-dessus.

89
pambda

Tout d’abord, vous devriez vérifier le nombre de commits que vous avez:

git log

Il y a deux statut:

Le premier est qu’il n’ya que deux commits:

Par exemple:

commit A
commit B

(Dans ce cas, vous ne pouvez pas utiliser git rebase à faire), vous devez suivre les instructions suivantes.

$ git reset --soft HEAD^1

$ git commit --amend

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

Par exemple:

commit A
commit B
commit C
commit D

(dans 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 le savez toujours pas, veuillez lire http://zerodie.github.io/blog/2012/01/19/git-rebase-i/

52
Haimei

En supposant que vous êtes dans votre propre branche de sujet. Si vous souhaitez fusionner les 2 derniers commits en un et ressembler à un héros, déconnectez-vous du commit juste avant de faire les deux derniers commits.

git checkout -b temp_branch HEAD^2

Ensuite, squash engage l’autre branche de cette nouvelle branche:

git merge branch_with_two_commits --squash

Cela apportera les changements mais ne les engagera 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.

28
Homan

vous pouvez annuler la rebase avec

git rebase --abort

et lorsque vous exécutez à nouveau la commande interactive rebase, le 'squash'; commit doit être inférieur au pick commit dans la liste

22
Leom Burke

J'utilise souvent git reset --mixed pour rétablir une version de base avant plusieurs validations que vous souhaitez fusionner, puis je fais une nouvelle validation, de cette façon, vous pouvez laisser votre commit le plus récent, assurez-vous que votre version est HEAD après avoir poussé vers le serveur.

commit ac72a4308ba70cc42aace47509a5e
Author: <[email protected]>
Date:   Tue Jun 11 10:23:07 2013 +0500

    Added algorithms for Cosine-similarity

commit 77df2a40e53136c7a2d58fd847372
Author: <[email protected]>
Date:   Tue Jun 11 13:02:14 2013 -0700

    Set stage for similar objects

commit 249cf9392da197573a17c8426c282
Author: Ralph <[email protected]>
Date:   Thu Jun 13 16:44:12 2013 -0700

    Fixed a bug in space world automation

Si je veux fusionner deux commits en un, j'utilise d'abord:

git reset --mixed 249cf9392da197573a17c8426c282

"249cf9392da197573a17c8426c282" était la troisième version, c'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.
16
VinceStyling

$ git rebase --abort

Exécutez ce code à tout moment si vous voulez annuler la rebase git

$ git rebase -i HEAD~2

Réappliquer les deux derniers commits. La commande ci-dessus ouvrira un éditeur de code

  • [Le dernier commit sera en bas]. Changez le dernier commit en squash (s). Depuis squash va se fondre avec le commit précédent.
  • Appuyez ensuite sur la touche echap et tapez: wq pour sauvegarder et fermer

Après: wq vous serez en mode rebase actif

Remarque : Vous aurez un autre éditeur si aucun message d'avertissement/d'erreur ne s'affiche, S'il y a une erreur ou si un autre éditeur est averti pas montré, vous pouvez abandonner en exécutant $ 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, sauvegardez et quittez [: wq]

Remarque 2: Vous devrez peut-être forcer la transmission de vos modifications au référentiel distant si vous exécutez la commande rebase.

$ git Push -f

$ git Push -f Origin master

11
Gnanasekar S

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

Étant donné que j’ai branchX vérifié et qu’il y a deux commits, dont je veux créer un, 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 le côté négatif de cette méthode), je dois aussi:

git checkout branchX
git reset --hard <the_new_commit>
2
Martin G

Si vous souhaitez combiner les deux derniers commits et utiliser simplement le message de l'ancien, vous pouvez automatiser le processus à l'aide de expect .

Je suppose:

  • Vous utilisez vi comme éditeur
  • Vos commits sont d'une ligne chacun

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
1
erwaman

Si votre branche principale git log ressemble à ce qui suit:

commit ac72a4308ba70cc42aace47509a5e
Author: <[email protected]>
Date:   Tue Jun 11 10:23:07 2013 +0500

    Added algorithms for Cosine-similarity

commit 77df2a40e53136c7a2d58fd847372
Author: <[email protected]>
Date:   Tue Jun 11 13:02:14 2013 -0700

    Set stage for similar objects

commit 249cf9392da197573a17c8426c282
Author: Ralph <[email protected]>
Date:   Thu Jun 13 16:44:12 2013 -0700

    Fixed a bug in space world automation

et vous voulez fusionner les deux commits les plus importants, procédez comme suit:

  1. Le premier à être placé en toute sécurité lors du dernier avant-dernier dans une branche distincte. Vous pouvez nommer n'importe quelle branche. git checkout 77df2a40e53136c7a2d58fd847372 -b merged-commits
  2. Maintenant, sélectionnez simplement vos modifications du dernier commit dans cette nouvelle branche en tant que: git cherry-pick -n -x ac72a4308ba70cc42aace47509a5e. (Résoudre les conflits s'il en survient)
  3. Alors maintenant, vos modifications dans le dernier commit sont là dans votre avant dernier commit. Mais vous devez toujours vous engager, alors ajoutez d'abord les modifications que vous venez de sélectionner, puis exécutez git commit --amend.

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

En outre, vous pouvez maintenant ignorer les deux commits consécutifs dans votre branche principale. Il suffit de mettre à 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
Usman