283 votes

Comment séparer le dernier commit en deux dans Git

J'ai deux branches qui fonctionnent, maître et forum et j'ai juste fait quelques modifications dans forum que j'aimerais transformer en maître . Mais malheureusement, le commit que je veux sélectionner contient aussi des modifications que je ne veux pas.

La solution serait probablement de supprimer d'une manière ou d'une autre le mauvais commit et de le remplacer par deux commits distincts, l'un avec les changements que je veux prendre dans master, et l'autre qui n'y a pas sa place.

J'ai essayé de faire

git reset --hard HEAD^

qui a supprimé tous les changements, donc j'ai dû revenir en arrière avec

git reset ORIG_HEAD

Donc ma question est, quelle est la meilleure façon de divisé le dernier commit en deux commits séparés ?

339voto

hcs42 Points 5407

Vous devez utiliser l'index. Après avoir effectué une réinitialisation mixte (" git reset HEAD^"), ajoutez la première série de changements dans l'index, puis les commiter. Ensuite, livrez le le reste.

Vous pouvez utiliser " git add "pour placer toutes les modifications apportées à un fichier dans l'index. Si vous ne voulez pas mettre en scène toutes les modifications faites dans un fichier, seulement certaines d'entre elles, vous vous pouvez utiliser "git add -p".

Voyons un exemple. Supposons que j'ai un fichier appelé monfichier, qui contient le texte suivant :

something
something else
something again

Je l'ai modifié dans mon dernier commit pour qu'il ressemble maintenant à ceci :

1
something
something else
something again
2

Maintenant je décide que je veux le diviser en deux, et je veux que l'insertion de la première ligne soit dans le premier commit, et que l'insertion de la dernière ligne soit dans le second commit.

D'abord je retourne au parent de HEAD, mais je veux garder les modifications dans le système de fichiers, donc j'utilise "git reset" sans argument (ce qui fera une réinitialisation dite "mixte"). mixte) :

$ git reset HEAD^
myfile: locally modified
$ cat myfile
1
something
something else
something again
2

Maintenant, j'utilise "git add -p" pour ajouter les changements que je veux commiter à l'index (=J'ai les mettre en scène). "git add -p" est un outil interactif qui vous demande quelles sont les modifications du fichier qu'il doit ajouter à l'index.

$ git add -p myfile
diff --git a/myfile b/myfile
index 93db4cb..2f113ce 100644
--- a/myfile
+++ b/myfile
@@ -1,3 +1,5 @@
+1
 something
 something else
 something again
+2
Stage this hunk [y,n,a,d,/,s,e,?]? s    # split this section into two!
Split into 2 hunks.
@@ -1,3 +1,4 @@
+1
 something
 something else
 something again
Stage this hunk [y,n,a,d,/,j,J,g,e,?]? y  # yes, I want to stage this
@@ -1,3 +2,4 @@
 something
 something else
 something again
+2
Stage this hunk [y,n,a,d,/,K,g,e,?]? n   # no, I don't want to stage this

Ensuite, j'effectue ce premier changement :

$ git commit -m "Added first line"
[master cef3d4e] Added first line
 1 files changed, 1 insertions(+), 0 deletions(-)

Maintenant je peux valider tous les autres changements (notamment le chiffre "2" mis dans la dernière ligne) :

$ git commit -am "Added last line"
[master 5e284e6] Added last line
 1 files changed, 1 insertions(+), 0 deletions(-)

Vérifions le journal pour voir quels commits nous avons :

$ git log -p -n2 | cat
Commit 5e284e652f5e05a47ad8883d9f59ed9817be59d8
Author: ...
Date: ...

    Added last line

Diff --git a/myfile b/myfile
Index f9e1a67..2f113ce 100644
--- a/myfile
+++ b/myfile
@@ -2,3 +2,4 @@
 something
 something else
 something again
+2

Commit cef3d4e0298dd5d279a911440bb72d39410e7898
Author: ...
Date: ...

    Added first line

Diff --git a/myfile b/myfile
Index 93db4cb..f9e1a67 100644
--- a/myfile
+++ b/myfile
@@ -1,3 +1,4 @@
+1
 something
 something else
 something again

1 votes

Je me suis lentement habitué à git à partir de Mercurial au cours de la dernière semaine et demie, et il existe une commande de raccourci pratique git reset [--patch|-p] <commit> que vous pouvez utiliser pour vous épargner la peine d'avoir à git add -p après la réinitialisation. Est-ce que j'ai raison ? J'utilise git 1.7.9.5.

2 votes

Voici un peu plus de détails sur cette technique, y compris le rebasage si c'était un ancien commit, ou si vous devez changer N commits en M commits : emmanuelbernard.com/blog/2014/04/14/ .

85voto

spazm Points 1545

Les objectifs : Je veux diviser un commit passé en deux. Je veux maintenir le message du commit.

Plan : rebasement interactif d'un avant splitme. éditer splitme. Réinitialiser les fichiers à diviser dans un second commit. Modifier le commit, maintenir le message, modifier si nécessaire. Réintroduire les fichiers séparés dans le premier commit. Faire un nouveau commit avec un nouveau message. Continuer le rebasement. Les étapes de rebasement peuvent être sautées si le splitme est le commit le plus récent.

git rebase -i splitme^
# mark splitme commit with 'e'
git reset HEAD^ -- $files
git commit --amend
git add $files
git commit -m "commit with just some files"
git rebase --continue

Si je voulais que les fichiers fractionnés soient livrés en premier, je rebase -i à nouveau et je change l'ordre.

git rebase -i splitme^
# swap order of splitme and 'just some files'

1 votes

git reset HEAD^ était la pièce manquante du puzzle. Fonctionne bien avec -p aussi. Merci.

10 votes

Il est important de noter que le -- $files argument pour git reset . Avec des chemins passés, git reset restaure ces fichiers à l'état du commit référencé mais ne change aucun commit. Si vous omettez les chemins, alors vous "perdez" le commit que vous voulez modifier à l'étape suivante.

2 votes

Cette méthode vous évite de devoir copier et coller à nouveau votre premier message de validation, par rapport à la réponse acceptée.

52voto

Charles Bailey Points 244082

Pour changer le commit actuel en deux commits, vous pouvez faire quelque chose comme ce qui suit.

Soit :

git reset --soft HEAD^

Cela annule le dernier commit mais laisse tout en place. Vous pouvez alors dé-stager certains fichiers :

git reset -- file.file

En option, restocker des parties de ces fichiers :

git add -p file.file

Faites un nouveau premier commit :

git commit

L'étape et commettre le reste des changements dans un deuxième commit :

git commit -a

Ou :

Défaire et annuler toutes les modifications de la dernière livraison :

git reset HEAD^

Mettez en scène de manière sélective la première série de changements :

git add -p

Engagez-vous :

git commit

Valider le reste des changements :

git commit -a

(Dans l'une ou l'autre des étapes, si vous annulez un commit qui a ajouté un tout nouveau fichier et que vous voulez l'ajouter au second commit, vous devrez l'ajouter manuellement en tant que commit -a ne met en scène que les modifications apportées aux fichiers déjà suivis).

22voto

Exécuter git gui sélectionnez le bouton d'option "Modifier la dernière livraison", et déstockez (Commit > Unstage From Commit, ou Ctrl - U ) les changements que vous ne voulez pas faire dans le premier commit. Je pense que c'est la façon la plus simple de procéder.

Une autre chose que vous pouvez faire est de sélectionner les changements sans les valider ( git cherry-pick -n ) et ensuite, soit manuellement, soit avec git gui sélectionnez les modifications souhaitées avant de les valider.

15voto

semanticart Points 2773
git reset HEAD^

le --dur est ce qui tue vos changements.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X