Puis-je diviser un morceau déjà divisé avec git?

205

J'ai récemment découvert l' patchoption de git pour la addcommande, et je dois dire que c'est vraiment une fonctionnalité fantastique. J'ai également découvert qu'un gros morceau pouvait être divisé en plus petits morceaux en appuyant sur la stouche, ce qui ajoute à la précision du commit. Mais que se passe-t-il si je veux encore plus de précision, si le morceau divisé n'est pas assez petit?

Par exemple, considérez ce morceau déjà divisé:

@@ -34,12 +34,7 @@
   width: 440px;
 }

-/*#field_teacher_id {
-  display: block;
-} */
-
-form.table-form #field_teacher + label,
-form.table-form #field_producer_distributor + label {
+#user-register form.table-form .field-type-checkbox label {
   width: 300px;
 }

Comment puis-je ajouter la suppression des commentaires CSS uniquement au prochain commit? L' soption n'est plus disponible!

greg0ire
la source

Réponses:

254

Si vous utilisez git add -pet même après avoir fractionné avec s, vous n'avez pas un assez petit changement, vous pouvez utiliser epour modifier le patch directement.

Cela peut être un peu déroutant, mais si vous suivez attentivement les instructions de la fenêtre de l'éditeur qui s'ouvrira après avoir appuyé sur, tout eira bien. Dans le cas où vous avez cité, vous voudriez remplacer le -par un espace au début de ces lignes:

-
-form.table-form #field_teacher + label,
-form.table-form #field_producer_distributor + label {

... et supprimez la ligne suivante, c'est-à-dire celle qui commence par +. Si vous enregistrez puis quittez votre éditeur, seule la suppression du commentaire CSS sera mise en scène.

Mark Longair
la source
9
Solution cool! J'ai vu cela mais j'ai mal compris ... Je pensais que les modifications seraient également supprimées de l'arbre de travail.
greg0ire
7
En effet, ce n'est pas très évident d'après le texte d'aide. En fait, je me retrouve beaucoup à l'utiliser, car je pense que git vous encourage vraiment à rendre chaque commit aussi précis et beau que possible :)
Mark Longair
27
Notez que vous devez vraiment le remplacer par un espace . Je l'ai essayé en pensant que je pouvais simplement supprimer les -caractères, et Git s'est plaint que mon patch ne s'appliquait pas.
Ryan Lundy
3
Je suppose que la raison pour laquelle vous supprimez les lignes avec le '-' et remplacez les '+' par un espace est que vous formez alors un patch où ces lignes avec le '-' ont déjà été supprimées et les lignes avec le ' Les + ont déjà été ajoutés (dans l'œil du patch). Ou une autre façon de voir les choses, c'est que vous effectuez réellement l'action que ces caractères (-, +) représentent (en ajoutant une ligne ou en la supprimant). Seules les lignes restantes avec des «-» et des «+» sont enregistrées en tant que modifications et le reste est «exactement comme le fichier est».
atomictom
3
@Filype: Je ne sais pas pourquoi cela se serait produit, je le crains - si vous exécutiez et éditiez git add -pun morceau avec ecela ne devrait affecter que ce qui est organisé, pas votre arbre de travail.
Mark Longair
60

Disons que votre example.cssapparence ressemble à ceci:

.classname {
  width: 440px;
}

/*#field_teacher_id {
  display: block;
} */

form.table-form #field_teacher + label,
form.table-form #field_producer_distributor + label {
  width: 300px;
}

.another {
  width: 420px;
}

Maintenant, changeons les sélecteurs de style dans le bloc du milieu, et pendant que nous y sommes, supprimons un ancien style commenté dont nous n'avons plus besoin.

.classname {
  width: 440px;
}

#user-register form.table-form .field-type-checkbox label {
  width: 300px;
}

.another {
  width: 420px;
}

C'était facile, maintenant engageons-nous. Mais attendez, je veux maintenir une séparation logique des changements dans le contrôle de version pour une révision simple du code par étapes, et pour que mon équipe et moi puissions facilement rechercher dans l'historique des validations des détails.

La suppression de l'ancien code est logiquement distincte de l'autre changement de sélecteur de style. Nous allons avoir besoin de deux validations distinctes, alors ajoutons des morceaux pour un patch.

git add --patch
diff --git a/example.css b/example.css
index 426449d..50ecff9 100644
--- a/example.css
+++ b/example.css
@@ -2,12 +2,7 @@
   width: 440px;
 }

-/*#field_teacher_id {
-  display: block;
-} */
-
-form.table-form #field_teacher + label,
-form.table-form #field_producer_distributor + label {
+#user-register form.table-form .field-type-checkbox label {
   width: 300px;
 }

Stage this hunk [y,n,q,a,d,/,e,?]?

Oups, on dirait que les changements sont trop proches, donc git les a regroupés.

Même essayer de le diviser en appuyant sur sa le même résultat car le fractionnement n'est pas assez granulaire pour nos changements de précision. Des lignes inchangées sont requises entre les lignes modifiées pour que git puisse diviser automatiquement le patch.

Donc, nous allons manuellement modifier en appuyant sure

Stage this hunk [y,n,q,a,d,/,e,?]? e

git ouvrira le patch dans notre éditeur de choix.

# Manual hunk edit mode -- see bottom for a quick guide
@@ -2,12 +2,7 @@
   width: 440px;
 }

-/*#field_teacher_id {
-  display: block;
-} */
-
-form.table-form #field_teacher + label,
-form.table-form #field_producer_distributor + label {
+#user-register form.table-form .field-type-checkbox label {
   width: 300px;
 }

# ---
# To remove '-' lines, make them ' ' lines (context).
# To remove '+' lines, delete them.
# Lines starting with # will be removed.
#
# If the patch applies cleanly, the edited hunk will immediately be
# marked for staging. If it does not apply cleanly, you will be given
# an opportunity to edit again. If all lines of the hunk are removed,
# then the edit is aborted and the hunk is left unchanged.

Passons en revue l'objectif:

Comment puis-je ajouter la suppression des commentaires CSS uniquement au prochain commit?

Nous voulons diviser cela en deux commits:

  1. Le premier commit implique la suppression de certaines lignes (suppression des commentaires).

    Pour supprimer les lignes commentées, laissez-les simplement, elles sont déjà marquées pour suivre les suppressions dans le contrôle de version comme nous le voulons.

    -/*#field_teacher_id {
    - display: block;
    -} */

  2. Le deuxième commit est un changement, qui est suivi en enregistrant à la fois les suppressions et les ajouts:

    • Suppressions (anciennes lignes de sélection supprimées)

      Pour conserver les anciennes lignes de sélection (ne les supprimez pas lors de cette validation), nous voulons ...

      Pour supprimer les lignes '-', faites-les ''

      ... ce qui signifie littéralement remplacer les -signes moins par un caractère espace .

      Donc, ces trois lignes ...

      -
      -form.table-form #field_teacher + label,
      -form.table-form #field_producer_distributor + label {

      ... deviendra ( remarquez l'espace unique à la première des 3 lignes):


      form.table-form #field_teacher + label,
      form.table-form #field_producer_distributor + label {

    • Ajouts (nouvelle ligne de sélection ajoutée)

      Pour ne pas faire attention à la nouvelle ligne de sélecteur ajoutée lors de ce commit, nous voulons ...

      Pour supprimer les lignes «+», supprimez-les.

      ... ce qui signifie littéralement supprimer toute la ligne:

      +#user-register form.table-form .field-type-checkbox label {

      (Bonus: si vous utilisez vim comme éditeur, appuyez sur ddpour supprimer une ligne. Les utilisateurs de Nano appuyez sur Ctrl+ K)

Votre éditeur devrait ressembler à ceci lorsque vous enregistrez:

# Manual hunk edit mode -- see bottom for a quick guide
@@ -2,12 +2,7 @@
   width: 440px;
 }

-/*#field_teacher_id {
-  display: block;
-} */

 form.table-form #field_teacher + label,
 form.table-form #field_producer_distributor + label {
   width: 300px;
 }

# ---
# To remove '-' lines, make them ' ' lines (context).
# To remove '+' lines, delete them.
# Lines starting with # will be removed.
#
# If the patch applies cleanly, the edited hunk will immediately be
# marked for staging. If it does not apply cleanly, you will be given
# an opportunity to edit again. If all lines of the hunk are removed,
# then the edit is aborted and the hunk is left unchanged.

Maintenant, engageons-nous.

git commit -m "remove old code"

Et juste pour être sûr, voyons les changements du dernier commit.

git show
commit 572ecbc7beecca495c8965ce54fbccabdd085112
Author: Jeff Puckett <[email protected]>
Date:   Sat Jun 11 17:06:48 2016 -0500

    remove old code

diff --git a/example.css b/example.css
index 426449d..d04c832 100644
--- a/example.css
+++ b/example.css
@@ -2,9 +2,6 @@
   width: 440px;
 }

-/*#field_teacher_id {
-  display: block;
-} */

 form.table-form #field_teacher + label,
 form.table-form #field_producer_distributor + label {

Parfait - vous pouvez voir que seules les suppressions ont été incluses dans ce commit atomique. Maintenant, terminons le travail et engageons le reste.

git add .
git commit -m "change selectors"
git show
commit 83ec3c16b73bca799e4ed525148cf303e0bd39f9
Author: Jeff Puckett <[email protected]>
Date:   Sat Jun 11 17:09:12 2016 -0500

    change selectors

diff --git a/example.css b/example.css
index d04c832..50ecff9 100644
--- a/example.css
+++ b/example.css
@@ -2,9 +2,7 @@
   width: 440px;
 }

-
-form.table-form #field_teacher + label,
-form.table-form #field_producer_distributor + label {
+#user-register form.table-form .field-type-checkbox label {
   width: 300px;
 }

Enfin, vous pouvez voir que le dernier commit inclut uniquement les modifications du sélecteur.

Jeff Puckett
la source
1
Bonus # 2: Si vous utilisez VIM comme éditeur, vous devez appuyer deux fois sur "d" sur votre clavier pour supprimer une ligne: D
Alexxus
3
De plus, au lieu de supprimer les lignes ajoutées que vous ne souhaitez pas ajouter, vous pouvez les remplacer +par #. Le résultat est le même, mais peut-être que vous n'êtes pas à l'aise avec la suppression (et que vous ne pouvez pas revenir en arrière) ou que vous souhaitez tester avant d'enregistrer.
ob-ivan
Et cela, car vim est r #au - dessus du plus xD
aksh1618
L'objectif est "Comment puis-je ajouter la suppression des commentaires CSS uniquement au prochain commit?", Mais les étapes sont vraiment confuses quant à ce qu'elle accomplit. (nous voulons "ajouter" uniquement la "suppression" des quelques lignes au prochain commit.) Donc, dire simplement supprimer ou ajouter est très déroutant. Énoncer ce qui a été accompli à chaque étape aiderait à clarifier.
ahnbizcad
9

Si vous pouvez utiliser git gui, cela vous permet de mettre en scène les changements ligne par ligne. Malheureusement, je ne sais pas comment le faire à partir de la ligne de commande - ou même si c'est possible.

Une autre option que j'ai utilisée dans le passé consiste à annuler une partie du changement (garder l'éditeur ouvert), valider les bits que je veux, annuler et ré-enregistrer à partir de l'éditeur. Pas très élégant, mais fait le travail. :)


EDIT (utilisation de git-gui):

Je ne sais pas si le git-gui est le même dans les versions msysgit et linux, je n'ai utilisé que le msysgit. Mais en supposant que c'est la même chose, lorsque vous l'exécutez, il y a quatre volets: le volet supérieur gauche est votre répertoire de travail change, en bas à gauche est votre étape change, en haut à droite est le diff pour le fichier sélectionné (que ce soit dir de travail ou mise en scène), et en bas à droite est pour la description du commit (je suppose que vous n'en aurez pas besoin). Lorsque vous cliquez sur un fichier en haut à droite, vous verrez le diff. Si vous cliquez avec le bouton droit sur une ligne de diff, vous verrez un menu contextuel. Les deux options à noter sont "morceau de scène pour commit" et "ligne de scène pour commit". Vous continuez à sélectionner «étape de la ligne de validation» sur les lignes que vous souhaitez valider, et vous avez terminé. Vous pouvez même sélectionner plusieurs lignes et les mettre en scène si vous le souhaitez.

En ce qui concerne la validation, vous pouvez utiliser l'outil gui ou la ligne de commande.

vhallac
la source
Votre deuxième proposition est assez évidente, mais la première est intéressante, pourriez-vous détailler un peu plus? J'ai installé git-guimais je n'ai aucune idée de comment réaliser ce que vous décrivez.
greg0ire
Merci beaucoup! Cela marche! J'ai même pu sélectionner les lignes que je voulais mettre en scène et les indexer en un seul clic.
greg0ire
0

Une façon de le faire est de sauter le morceau, git addtout ce dont vous avez besoin, puis d'exécutergit add recommencer. Si c'est le seul morceau, vous pourrez le diviser.

Si vous vous inquiétez de l'ordre des validations, utilisez simplement git rebase -i.

Abizern
la source
C'est ce que j'ai essayé, et le morceau dans ma question est le seul quand je cours à git add -pnouveau, mais je ne peux pas le diviser. J'obtiens ceci: Stage this hunk [y,n,q,a,d,/,e,?]?puis appuyer sur 's' affiche l'aide. BTW, tu voulais dire add patch, non patch add? Ou existe-t-il un git patchplugin que je devrais installer?
greg0ire
Avez-vous validé les mecs mis en scène avant de recommencer? Et non, Mercurial a des plugins, pas Git.
Abizern
Non, je ne veux pas qu'ils soient dans le même commit (mais je suppose que si votre solution fonctionne, je peux utiliser --amend pour y parvenir). Je vais essayer.
greg0ire
Comme ma réponse l'a dit → git rebase -i. Ce qui est plus flexible quecommit --amend
Abizern