Briser une précédente livraison en plusieurs commits
Sans la création d'une branche et de faire un tas de funky travailler sur une nouvelle branche, est-il possible de rompre un seul s'engager dans un certain nombre de différents s'engage après avoir été commis dans le dépôt local?
- Une bonne source pour l'apprentissage de la façon de le faire est de Pro Git §6.4 Git Outils de Réécriture de l'Histoire, dans le "Fractionnement d'un Commit" section.
- La documentation liée à l'observation ci-dessus sont excellents, et expliqué que les réponses ci-dessous.
- Je suggère l'utilisation de cet alias stackoverflow.com/a/19267103/301717. Il permet de diviser une validation à l'aide de
git autorebase split COMMIT_ID
- Chose la plus facile à faire sans un rebase interactif est (probablement) pour créer une nouvelle branche de départ à la validation avant celui que vous voulez diviser, cherry-pick -n de la validation, de réinitialisation, de cachette, de commettre le déplacement de fichiers, réappliquer la cachette et de valider les modifications, puis fusion avec l'ancienne direction générale ou de choisir les commits qui ont suivi. (Puis passer l'ancien nom de la branche de l'actuel chef.) (C'est probablement mieux de suivre Mbo conseils et faire un rebase interactif.) (Copié à partir de 2010 réponse ci-dessous)
- J'ai rencontré ce problème une fois j'ai accidentellement écrasé deux s'engage pendant un rebase dans un précédent commit. Ma façon de le fixer, il était à la caisse de la prévenue s'engager,
git reset HEAD~
,git stash
, puisgit cherry-pick
le premier commit à l'intérieur de la courge, puisgit stash pop
. Mon cherry-pick cas est tout à fait spécifique ici, maisgit stash
etgit stash pop
est assez pratique pour les autres.
Vous devez vous connecter pour publier un commentaire.
git rebase -i
va le faire.Tout d'abord, commencez avec un répertoire de travail est propre:
git status
ne doivent présenter ni dans l'attente des modifications, des suppressions ou des ajouts.Maintenant, vous devez décider qui commit(s) que vous voulez diviser.
A) le Fractionnement de la plus récente s'engager
À se séparer de votre plus récente s'engager, d'abord:
Maintenant commettre les pièces individuellement de la manière habituelle, la production comme de nombreux engage que vous en avez besoin.
B) Fractionnement d'un commit plus loin en arrière
Cela nécessite rebasage, qui est, la réécriture de l'histoire. Pour trouver la bonne engager, vous avez plusieurs choix:
Si c'était à trois s'engage en retour, puis
où
3
est combien s'engage en retour c'est.Si elle a été plus loin en arrière dans l'arbre que vous souhaitez compter, puis
où
123abcd
est le SHA1 de la validation que vous souhaitez diviser.Si vous êtes sur une autre branche (par exemple, une branche) que vous avez l'intention de fusionner en master:
Lorsque vous obtenez le rebase écran de modification, de trouver le commit que vous voulez rompre. Au début de cette ligne, remplacer
pick
avecedit
(e
pour faire court). Économiser de la mémoire tampon et de sortie. Cela va maintenant s'arrêter juste après le commit que vous voulez modifier. Alors: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
, j'ai effectivement eu àgit add (files to be added)
,git commit
, puisgit stash
(pour les fichiers restants). Aprèsgit rebase --continue
, j'ai utiliségit checkout stash .
pour obtenir les fichiers restantsgit add -p
pour ajouter uniquement les sections partielles de fichiers, éventuellement avec l'e
option pour modifier les diffs à seulement consacrer une partie d'un morceau.git stash
est également utile si vous souhaitez effectuer certains travaux, mais le supprimer à partir du courant de commettre.massive_branch
pas seulement dans les petits s'engage, mais divisée en deux branches distinctes. J'ai enregistrer manuellement le SHA de certains s'engage, puis créer une nouvelle branche et à la cerise choisir leur plus quand je suis fait avec le rebase de lamassive_branch
. Une meilleure façon de faire cela? Comme, comme vous le changement d'année de base et la création de nouveaux commits, le marquage s'engage à se déplacer à une branche distincte?git rebase -i HEAD^3
de commande. De cette façon, si la scission va mal, vous n'avez pas à défaire tout à fait aussi beaucoup de travail.git add -p
estgit add -i
, mais il semble être moins connus.^
dansgit rebase -i 123abcd^
?~
sans nombre, qui signifie "premier ancêtre." Si les chiffres donnés, par exemple^2
ou~2
, alors ils ne sont pas nécessairement équivalents. Je vais modifier la réponse de la rendre plus cohérente.git reset HEAD~
va perdre des fichiers ajoutés récemment.git reset
ne dangereux choses. Cela dit, je vous recommande de commencer cette séquence avec un chiffon propre arbre.git reset HEAD~
au cours de rebase sera, comme son nom l'indique, réinitialisation de l'arbre de la précédente livraison, c'est à dire. sans les fichiers introduite par le commmit.git reset HEAD~
. Ils ne sont pas perdus.error: failed to push some refs to 'https://github.com/MyRepo/repo.git' hint: Updates were rejected because the tip of your current branch is behind
à repousser les modifications après que les modifications ci-dessus.pull
avantpush
résolu le problème.De git-git rebase manuel (FRACTIONNEMENT s'ENGAGE section)
~
au lieu de^
.reset
ting la validation, après tout, le message d'inclus. La prudence chose à faire, si vous savez que vous allez être le fractionnement d'un commit, mais souhaitez conserver certains/tous les de son message, est de prendre une copie de ce message. Donc,git show
la validation avant derebase
ing, ou si vous oubliez ou vous préférez ce: revenez-y plus tard via lereflog
. Rien de tout cela ne fait "perdu" jusqu'à ce que le garbage collector de suite dans 2 semaines ou quoi que ce soit.~
et^
sont des choses différentes, même sur Windows. Vous voulez toujours le signe^
, de sorte que vous aurez juste besoin d'échapper en fonction de votre shell. Dans PowerShell, c'estHEAD`^
. Avec cmd.exe vous pouvez double-il à fuir comme laHEAD^^
. Dans la plupart (tous?) les coquilles, vous pouvez les entourer de guillemets comme"HEAD^"
.git reflog
);git log <sha>
git commit --reuse-message=abcd123
. L'option courte car c'est-C
.Utilisation
git rebase --interactive
afin de le modifier plus tôt s'engager, exécutezgit reset HEAD~
, puisgit add -p
pour en ajouter, puis faire un commit, puis ajouter un peu plus et de faire un autre commit, autant de fois que vous le souhaitez. Lorsque vous avez terminé, exécutezgit rebase --continue
, et vous aurez tout le split s'engage plus tôt dans votre pile.Important: Notez que vous pouvez jouer et de faire tous les changements que vous voulez, et ne pas avoir à vous soucier de perdre des vieux changements, parce que vous pouvez toujours exécuter le
git reflog
pour trouver le point dans votre projet qui contient les modifications que vous souhaitez, (appelons-laa8c4ab
), puisgit reset a8c4ab
.Voici une série de commandes pour montrer comment cela fonctionne:
mkdir git-test; cd git-test; git init
maintenant ajouter un fichier
A
vi A
ajouter cette ligne:
one
git commit -am one
puis ajoutez cette ligne à Un:
two
git commit -am two
puis ajoutez cette ligne à Un:
three
git commit -am three
maintenant le fichier ressemble à ceci:
et notre
git log
se présente comme suit (eh bien, j'utilisegit log --pretty=oneline --pretty="%h %cn %cr ---- %s"
Disons que nous voulons diviser le deuxième s'engager,
two
.git rebase --interactive HEAD~2
Cela apporte un message qui ressemble à ceci:
Modifier le premier
pick
à une
l'édition de commettre.git reset HEAD~
git diff
nous montre que nous venons de unstaged la validation nous avons fait pour la deuxième commit:Laisser la scène de ce changement, et d'ajouter "et un troisième" cette ligne dans le fichier
A
.git add .
C'est généralement le moment au cours d'un rebase interactif où nous
git rebase --continue
, parce qu'en général nous voulons juste revenir dans notre pile de s'engage à modifier plus tôt s'engager. Mais cette fois, nous voulons créer un nouveau commit. Donc, nous allons exécutergit commit -am 'two and a third'
. Maintenant, nous allons éditer le fichier deA
et ajoutez la lignetwo 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
à
git add .; git rebase --continue
Maintenant notre
git log -p
ressemble à ceci:Réponses précédentes ont porté sur l'utilisation de
git rebase -i
pour modifier le commit que vous voulez couper, et de s'engager dans les pièces.Cela fonctionne bien quand fractionner les fichiers dans différents commits, mais si vous voulez vous séparer des changements à des fichiers individuels, il n'y a plus que vous devez savoir.
Ayant obtenu la validation que vous voulez couper, à l'aide de
rebase -i
et le marquer pouredit
, vous avez deux options.Après l'utilisation de
git reset HEAD~
, aller à travers les patchs individuellement à l'aide degit add -p
de sélectionner celles que vous voulez dans chaque commitModifier la copie de travail pour supprimer les modifications que vous ne voulez pas; s'engager que les intermédiaires de l'état; et puis tirez pleinement s'engager pour le prochain tour.
L'Option 2 est utile si vous êtes à la division d'un grand engageons, il vous permet de vérifier que les versions provisoires de construire et d'exécuter correctement dans le cadre de la fusion. Cela se déroule comme suit.
Après l'utilisation de
rebase -i
etedit
ing de la validation, l'utilisationpour annuler la livraison, mais laisser les fichiers validés dans l'index. Vous pouvez également faire un mixte de réinitialisation en omettant --soft, selon le résultat final de votre premier commit va être. La seule différence est que vous commencez avec tous les changements mis en scène ou avec eux tous les unstaged.
Maintenant, allez et modifier le code. Vous pouvez supprimer les modifications, supprimer les fichiers ajoutés, et faire ce que vous voulez construire le premier commit de la série que vous cherchez. Vous pouvez également construire, exécuter, et de confirmer que vous avez un ensemble cohérent de source.
Une fois que vous êtes heureux, le stade/unstage les fichiers nécessaires (j'aime utiliser
git gui
pour cela), et de valider les modifications apportées par le biais de l'INTERFACE utilisateur ou de la ligne de commandeC'est le premier commit fait. 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. Afin de trouver le sha1 de la validation du montage, de l'utilisation
git status
. Dans les premières lignes de l'état, vous verrez la commande rebase qui est actuellement en cours d'exécution, dans lequel vous pouvez trouver le sha1 de l'original de votre commit:Dans ce cas, la validation, je suis en train de monter a sha1
65dfb6a
. Sachant cela, je peux voir le contenu de ce commit sur mon répertoire de travail en utilisant le formulaire degit checkout
qui prend à la fois une validation et un emplacement de fichier. J'utilise ici.
comme l'emplacement du fichier à remplacer l'ensemble de la copie de travail:Ne manquez pas le point sur la fin!
Cela permettra de vérifier, et le stade, les fichiers qu'ils l'étaient après la validation du montage, mais par rapport à la précédente livraison vous faites, de sorte que toutes les modifications que vous avez déjà commis, ne feront pas partie de la livraison.
Vous pouvez soit aller de l'avant maintenant et de s'engager comme-est à la fin de la scission, ou aller autour de nouveau, la suppression de certaines parties de la livraison avant de faire un autre intermédiaire commettre.
Si vous souhaitez réutiliser l'original message de commit pour un ou plusieurs commits, vous pouvez l'utiliser directement à partir de la rebase de fichiers de travail:
Enfin, une fois que vous avez commis toutes les modifications,
permettra de poursuivre et de compléter le rebase opération.
git rebase --interactive
peuvent être utilisés pour diviser une livraison dans les plus petits s'engage. Le Git docs sur rebase ont une forme concise, la procédure pas à pas du processus de Fractionnement s'Engage:^
est un caractère d'échappement pour la ligne de commande: il devrait être doublé. Par exemple, la questiongit reset HEAD^^
au lieu degit reset HEAD^
.^
deux fois réinitialise deux s'engage au-dessus de la TÊTE actuelle."HEAD^"
dans cmd.exe ou PowerShell,HEAD^^
dans cmd.exe,HEAD`^
en PowerShell. Il est utile d'en apprendre davantage sur la façon de coquillages — et votre shell de travail (c'est à dire, comment une commande se transforme en pièces individuelles qui se passait au programme), de sorte que vous pouvez adapter les commandes en ligne dans le droit de caractères de votre shell. (Pas spécifique à Windows.)Vous pouvez faire rebase interactif
git rebase -i
. Page de manuel a exactement ce que vous voulez:http://git-scm.com/docs/git-rebase#_splitting_commits
Maintenant dans la dernière TortoiseGit sur Windows, vous pouvez le faire très facilement.
Ouvrir le rebase dialogue, configurer, et de suivre les étapes suivantes.
Edit
" (parmi les choisir, squash, suppression,...).Start
" pour démarrer la conversion.Edit/Split
" bouton etcliquez sur "
Amend
" directement. La boîte de dialogue de validation s'ouvre.commit
".Très utile, merci TortoiseGit !
Veuillez noter qu'il est également
git reset --soft HEAD^
. Il est similaire à lagit reset
(qui par défaut est--mixed
), mais il conserve l'index de contenu. De sorte que si vous avez ajouté ou supprimé des fichiers, vous les avez dans l'index.S'avère être très utile en cas de géant s'engage.
Chose la plus facile à faire sans un rebase interactif est (probablement) pour créer une nouvelle branche de départ à la validation avant celui que vous voulez diviser, cherry-pick -n de la validation, de réinitialisation, de cachette, de commettre le déplacement de fichiers, réappliquer la cachette et de valider les modifications, puis fusion avec l'ancienne direction générale ou de choisir les commits qui ont suivi. (Puis passer l'ancien nom de la branche de l'actuel chef.) (C'est probablement mieux de suivre Mbo conseils et faire un rebase interactif.)
rebase -i
suggestions. Je pense que cela n'a pas eu beaucoup d'attention en raison de l'absence de toute mise en forme, cependant. Peut-être que vous pourriez revoir, maintenant que vous avez 126k points et savez probablement comment DONC. 😉Je pense que la meilleure façon d'utiliser
git rebase -i
. J'ai créé une vidéo pour montrer les étapes de fractionnement d'un commit: https://www.youtube.com/watch?v=3EzOz7e1ADISi vous avez ceci:
Où vous avez commis une teneur en commettre B:
Mais vous voulez diviser B en C - D, et d'obtenir ce résultat:
Vous pouvez diviser le contenu comme ceci par exemple (contenu à partir de différents répertoires dans les différents commits)...
Réinitialiser la branche de retour à la validation avant de l'un à split:
De créer un premier commit (C):
Créer de la deuxième commit (D):
Cela fait plus de 8 ans, mais peut-être que quelqu'un va trouver utile de toute façon.
J'ai été en mesure de faire le tour sans
rebase -i
.L'idée est de mener git dans le même état qu'il était avant que vous ne
git commit
:Après cela, vous verrez ce brillant
Unstaged changes after reset:
et votre repo est dans un état comme vous êtes sur le point de commettre tous ces fichiers. À partir de maintenant, vous pouvez facilement s'engager à nouveau comme vous le faites habituellement. Espérons que cela aide.Ici est de savoir comment diviser un commit dans IntelliJ IDEA, PyCharm, PhpStorm etc
Dans le Contrôle de Version du journal de la fenêtre, sélectionnez la validation que vous souhaitez
split, droit de la souris et sélectionnez la
Interactively Rebase from
Here
marque de celui que vous souhaitez diviser comme
edit
, cliquez surStart
Rebasing
Vous devriez voir une étiquette jaune est placé ce sens que la TÊTE
à qui s'engagent. Clic-droit sur le commettre, sélectionnez
Undo Commit
Maintenant ces commits sont de retour à la zone de mise en attente, vous pouvez ensuite valider
séparément. Après tout, le changement a été commise, l'ancien commit
devient inactif.