Briser un précédent commit en commits multiples

sans créer une branche et sans faire un tas de travail funky sur une nouvelle branche, est-il possible de casser une seule propagation en quelques propagation différentes après qu'elle ait été engagée dans le dépôt local?

864
git
demandé sur Jakuje 2011-06-02 20:11:12

11 réponses

git rebase -i je le ferai.

tout d'abord, commencez par un répertoire de travail propre: git status ne doit pas afficher de modifications, suppressions ou ajouts en attente.

pour séparer votre plus récent commit, d'abord:

$ git reset HEAD~

maintenant, commettez les pièces individuellement de la manière habituelle, en produisant autant de commits que vous avez besoin.

S'il était plus loin dans l'arbre, puis

$ git rebase -i HEAD~3

3 est combien de commit back il est.

S'il était plus loin dans l'arbre que vous voulez compter, alors

$ git rebase -i 123abcd~

123abcd est la SHA1 de la commission que vous voulez diviser.

lorsque vous obtenez l'écran rebase edit, trouvez la propagation que vous voulez séparer. Au début de cette ligne, remplacer pick avec edit ( e ). Économiser de la mémoire tampon et de sortie. Rebase va maintenant s'arrêter juste après la propagation que vous voulez éditer. Puis:

$ git reset HEAD~

Commettre les pièces individuellement de la manière habituelle, la production comme de nombreux engage que vous en avez besoin, puis

$ git rebase --continue
1325
répondu Wayne Conrad 2018-03-05 18:40:49

From git-rebase manual (SPLITTING COMMITS section)

en mode interactif, vous pouvez marquer des commits avec l'action"edit". Cependant, cela ne signifie pas nécessairement que git rebase s'attend à ce que le résultat de cette édition soit exactement une propagation. En effet, vous pouvez annuler la livraison, ou vous pouvez ajouter d'autres validations. Cela peut être utilisé pour diviser un commit en deux:

  • Démarrer une rebase interactive avec git rebase -i <commit>^ , où <commit> est le commit que vous voulez partager. En fait, n'importe quelle plage de propagation fera l'affaire, tant qu'elle contient cette propagation.

  • marquez le commit que vous voulez partager avec l'action"edit".

  • quand il s'agit d'éditer ce commit, exécutez git reset HEAD^ . L'effet est que la tête est rebondie par un, et l'indice suit la même. Cependant, l'arbre de travail reste le même.

  • ajoutez maintenant les modifications à l'index que vous voulez avoir dans la première propagation. Vous pouvez utiliser git add (peut-être de façon interactive) ou git gui (ou les deux) pour faire cela.

  • Commettre l'indice actuel avec ce message de commit est approprié maintenant.

  • répétez les deux dernières étapes jusqu'à ce que votre arbre de travail soit propre.

  • continuer le rebase avec git rebase --continue .

252
répondu MBO 2014-10-07 17:53:38

utilisez git rebase --interactive pour éditer ce commit, Lancez git reset HEAD~ , puis git add -p pour en ajouter, puis faites un commit, puis ajoutez un autre et faites un autre commit, autant de fois que vous le souhaitez. Quand vous aurez terminé, lancez git rebase --continue , et vous aurez toutes les Split commits plus tôt dans votre pile.

Important : notez que vous pouvez jouer et faire tous les changements que vous voulez, et ne pas avoir à vous soucier de la perte de vieux changements, parce que vous pouvez toujours exécuter git reflog pour trouver le point votre projet qui contient les modifications que vous souhaitez, (appelons-le a8c4ab ), puis git reset a8c4ab .

Voici une série de commandes pour montrer comment ça marche:

mkdir git-test; cd git-test; git init

maintenant ajouter un fichier A

vi A

ajouter cette ligne:

one

git commit -am one

puis ajouter cette ligne à A:

two

git commit -am two

puis ajouter cette ligne à A:

three

git commit -am three

maintenant le fichier a ressemble à ceci:

one
two
three

et notre git log ressemble à ce qui suit (bien, j'utilise git log --pretty=oneline --pretty="%h %cn %cr ---- %s"

bfb8e46 Rose Perrone 4 seconds ago ---- three
2b613bc Rose Perrone 14 seconds ago ---- two
9aac58f Rose Perrone 24 seconds ago ---- one

disons que nous voulons diviser la Deuxième Commission, two .

git rebase --interactive HEAD~2

ceci amène un message qui ressemble à ceci:

pick 2b613bc two
pick bfb8e46 three

Modifier le premier pick à une e pour modifier les commettre.

git reset HEAD~

git diff s'engager:

diff --git a/A b/A
index 5626abf..814f4a4 100644
--- a/A
+++ b/A
@@ -1 +1,2 @@
 one
+two

mettons en scène ce changement, et ajoutez" et un tiers "à cette ligne dans le fichier A .

git add .

c'est habituellement le point lors d'un rebase interactif où nous exécutons git rebase --continue , parce que nous voulons simplement retourner dans notre pile de propagations pour éditer une propagation antérieure. Mais cette fois, nous voulons créer un nouveau commit. Donc on va lancer git commit -am 'two and a third' . Maintenant, nous éditons le fichier A et ajouter la ligne two and two thirds .

git add . git commit -am 'two and two thirds' git rebase --continue

Nous avons un conflit avec notre engagement, three , donc, nous allons le résoudre:

Nous allons changer

one
<<<<<<< HEAD
two and a third
two and two thirds
=======
two
three
>>>>>>> bfb8e46... three

à

one
two and a third
two and two thirds
three

git add .; git rebase --continue

maintenant notre git log -p ressemble à ceci:

commit e59ca35bae8360439823d66d459238779e5b4892
Author: Rose Perrone <roseperrone@fake.com>
Date:   Sun Jul 7 13:57:00 2013 -0700

    three

diff --git a/A b/A
index 5aef867..dd8fb63 100644
--- a/A
+++ b/A
@@ -1,3 +1,4 @@
 one
 two and a third
 two and two thirds
+three

commit 4a283ba9bf83ef664541b467acdd0bb4d770ab8e
Author: Rose Perrone <roseperrone@fake.com>
Date:   Sun Jul 7 14:07:07 2013 -0700

    two and two thirds

diff --git a/A b/A
index 575010a..5aef867 100644
--- a/A
+++ b/A
@@ -1,2 +1,3 @@
 one
 two and a third
+two and two thirds

commit 704d323ca1bc7c45ed8b1714d924adcdc83dfa44
Author: Rose Perrone <roseperrone@fake.com>
Date:   Sun Jul 7 14:06:40 2013 -0700

    two and a third

diff --git a/A b/A
index 5626abf..575010a 100644
--- a/A
+++ b/A
@@ -1 +1,2 @@
 one
+two and a third

commit 9aac58f3893488ec643fecab3c85f5a2f481586f
Author: Rose Perrone <roseperrone@fake.com>
Date:   Sun Jul 7 13:56:40 2013 -0700

    one

diff --git a/A b/A
new file mode 100644
index 0000000..5626abf
--- /dev/null
+++ b/A
@@ -0,0 +1 @@
+one
36
répondu Rose Perrone 2013-07-08 15:28:58

les réponses précédentes ont couvert l'utilisation de git rebase -i pour éditer la propagation que vous voulez diviser, et la propager en plusieurs parties.

cela fonctionne bien lors de la division des fichiers en différentes propagations, mais si vous voulez séparer les modifications des fichiers individuels, il y a plus que vous devez savoir.

ayant obtenu le commit que vous voulez partager, en utilisant rebase -i et en le marquant pour edit , vous avez deux options.

  1. après avoir utilisé git reset HEAD~ , passez en revue les patches individuellement en utilisant git add -p pour sélectionner ceux que vous voulez dans chaque propagation

  2. éditez la copie de travail pour supprimer les changements que vous ne voulez pas; commit cet état provisoire; et puis retirez le commit complet pour le tour suivant.

L'Option 2 est utile si vous divisez un grand commit, car elle vous permet de vérifier que les versions intermédiaires se construisent et fonctionnent correctement dans le cadre de la fusion. Cela se déroule comme suit.

après rebase -i et edit dans la commande, Utiliser

git reset --soft HEAD~

pour annuler la propagation, mais laisser les fichiers engagés dans l'index. Vous pouvez également effectuer une réinitialisation mixte en omettant --soft, en fonction de la proximité du résultat final de votre commit initial. La seule différence est si vous commencez avec tous les changements mis en place ou avec eux tous les unstaged.

allez maintenant éditer le code. Vous pouvez supprimer des modifications, supprimer des fichiers ajoutés, et faire tout ce que vous voulez pour construire la première propagation de la série que vous recherchez. Vous pouvez aussi le construire, l'exécuter et confirmer que vous avez un ensemble cohérent de sources.

une fois que vous êtes heureux, étape/décompactage des fichiers au besoin (j'aime utiliser git gui pour cela), et commit les modifications à travers L'UI ou la ligne de commande

git commit

C'est la première fois. Maintenant, vous voulez restaurer votre copie de travail à l'état qu'il avait après la validation, vous êtes fractionnement, de sorte que vous pouvez prendre plus de changements pour votre prochain commit. Pour trouver le sha1 de la propagation que vous éditez, utilisez git status . Dans les premières lignes de l'état, vous verrez la commande rebase qui est en cours d'exécution, dans laquelle vous pouvez trouver le sha1 de votre commit original:

$ git status
interactive rebase in progress; onto be83b41
Last commands done (3 commands done):
   pick 4847406 US135756: add debugging to the file download code
   e 65dfb6a US135756: write data and download from remote
  (see more in file .git/rebase-merge/done)
...

dans ce cas, le comit que je suis en train d'éditer a sha1 65dfb6a . Sachant cela, je peux vérifier le contenu de cette propagation sur mon répertoire de travail en utilisant la forme git checkout qui prend à la fois une propagation et une localisation de fichier. Ici j'utilise . comme emplacement du fichier pour remplacer toute la copie de travail:

git checkout 65dfb6a .

ne manquez pas le point à la fin!

cela vérifiera, et mettra en scène, les fichiers comme ils étaient après la propagation que vous éditez, mais relatif à la propagation précédente que vous avez faite, de sorte que les changements que vous avez déjà commis ne feront pas partie de la propagation.

vous pouvez soit aller de l'avant maintenant et le commettre comme-est pour terminer la scission, ou aller autour de nouveau, en supprimant certaines parties de la commit avant de faire une autre commit intérimaire.

si vous voulez réutiliser le message de propagation original pour une ou plusieurs propagations, vous pouvez l'utiliser directement à partir des fichiers de travail de la base de données:

git commit --file .git/rebase-merge/message

Enfin, une fois que vous avez engagé tous les changements,

git rebase --continue

va poursuivre et compléter l'opération rebase.

20
répondu Andy Mortimer 2018-06-08 11:33:13

git rebase --interactive peut être utilisé pour diviser un commit en commits plus petits. Le Git docs sur rebase ont un aperçu concis du processus-fractionnement Commits :

en mode interactif, vous pouvez marquer commits avec l'action"edit". Cependant, cela ne signifie pas nécessairement que git rebase s'attend à ce que le résultat de cette édition soit exactement une propagation. En effet, vous pouvez annuler la livraison, ou vous pouvez ajouter d'autres validations. Cela peut être utilisé pour diviser un commit en deux:

  • lancez un rebase interactif avec git rebase -i <commit>^ , où <commit> est le commit que vous voulez partager. En fait, n'importe quelle plage de propagation fera l'affaire, tant qu'elle contient cette propagation.

  • Marquez l'engagement que vous voulez partager avec l'action "edit".

  • quand il s'agit d'éditer ce commit, exécutez git reset HEAD^ . L'effet est que la tête est rebondie par un, et l'indice suit la même. Cependant, l'arbre de travail reste la même.

  • Maintenant, ajoutez les modifications à l'index que vous voulez avoir dans la première propagation. Vous pouvez utiliser git add (peut-être de façon interactive) ou git gui (ou les deux) pour faire cela.

  • Commettre l'indice actuel avec ce message de commit est approprié maintenant.

  • répétez les deux dernières étapes jusqu'à ce que votre arbre de travail soit propre.

  • Continue le rebase avec git rebase --continue .

si vous n'êtes pas absolument sûr que les révisions intermédiaires sont cohérentes (elles compilent, passent le test, etc.) vous devez utiliser git stash pour cacher les changements non-encore engagés après chaque propagation, test, et modifier la propagation si les corrections sont nécessaire.

17
répondu 2013-07-14 22:25:14

vous pouvez faire le rebase interactif git rebase -i . Page de manuel a exactement ce que vous voulez:

http://git-scm.com/docs/git-rebase#_splitting_commits

10
répondu manojlds 2013-07-14 22:22:07

veuillez noter qu'il y a aussi git reset --soft HEAD^ . Il est similaire à git reset (qui par défaut à --mixed ) mais il conserve le contenu de l'index. De sorte que si vous avez ajouté ou supprimé des fichiers, vous les avez dans l'index.

S'avère très utile en cas de propagation géante.

7
répondu lethalman 2014-11-27 15:23:41

maintenant dans le dernier TortoiseGit sur Windows, vous pouvez le faire très facilement.

ouvrez la boîte de dialogue rebase, configurez-la , et faites les étapes suivantes.

  • faites un clic droit sur le commit que vous voulez partager et sélectionnez" Edit " (au choix, au hasard, supprimer)...).
  • , Cliquez sur Start " pour démarrer l'année de référence.
  • une fois qu'il arrive à la commit to split, vérifiez le " "151920920 le bouton" " et cliquez sur " Amend " directement. Le dialogue de propagation s'ouvre.

    Edit/Split commit
  • Désélectionner les fichiers que vous voulez mettre sur une autre validation.
  • édite le message de propagation, puis clique sur " commit ".
  • Jusqu'à ce qu'il y ait des fichiers à propager, le dialogue de propagation s'ouvrira encore et encore. Quand il n'y a plus de fichier à propager, il vous demander si vous voulez ajouter un plus commettre.

très utile, merci TortoiseGit !

7
répondu Mikaël Mayer 2016-04-22 10:32:46

je pense que la meilleure façon que j'utilise git rebase -i . J'ai créé une vidéo pour montrer les étapes pour partager un commit: https://www.youtube.com/watch?v=3EzOz7e1ADI

1
répondu Nguyen Sy Thanh Son 2016-07-25 11:47:20

la chose la plus facile à faire sans un rebase interactif est (probablement) de faire une nouvelle branche à partir de la propagation avant celle que vous voulez diviser, cherry-pick-n la propagation, reset, stash, commit le mouvement de fichier, reapply la propagation et commit les changements, et puis soit fusionner avec l'ancienne branche ou cherry-pick les commits qui ont suivi. (Puis changer le nom de l'ancienne branche à la tête courante.) (Il est probablement préférable de suivre les conseils de MBOs et de faire un rebase interactif.)

0
répondu William Pursell 2010-01-22 17:04:50

si vous avez ceci:

A - B <- mybranch

où vous avez commis un contenu en commit B:

/modules/a/file1
/modules/a/file2
/modules/b/file3
/modules/b/file4

mais vous voulez diviser B en C-D, et obtenir ce résultat:

A - C - D <-mybranch

vous pouvez diviser le contenu comme ceci par exemple (contenu de différents répertoires dans différentes propagations)...

réinitialiser la branche de nouveau à la commit avant celle à split:

git checkout mybranch
git reset --hard A

Créer le premier commit (C):

git checkout B /modules/a
git add -u
git commit -m "content of /modules/a"

Créer un deuxième commit (D):

git checkout B /modules/b
git add -u
git commit -m "content of /modules/b"
0
répondu Martin G 2017-02-08 17:44:48