Kann ich ein bereits geteiltes Stück mit Git teilen?

204

Ich habe kürzlich die patchOption von git für den addBefehl entdeckt, und ich muss sagen, dass es wirklich eine fantastische Funktion ist. Ich entdeckte auch, dass ein großer Teil durch Drücken der sTaste in kleinere Teile aufgeteilt werden kann , was die Genauigkeit des Festschreibens erhöht. Aber was ist, wenn ich noch mehr Präzision will, wenn das geteilte Stück nicht klein genug ist?

Betrachten Sie zum Beispiel dieses bereits geteilte Stück:

@@ -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;
 }

Wie kann ich das Entfernen von CSS-Kommentaren nur zum nächsten Commit hinzufügen? Die sOption ist nicht mehr verfügbar!

greg0ire
quelle

Antworten:

253

Wenn Sie verwenden git add -pund auch nach dem Teilen mit snicht genügend Änderungen vorgenommen haben, können Sie eden Patch direkt bearbeiten.

Dies kann etwas verwirrend sein, aber wenn Sie die Anweisungen im Editorfenster, das nach dem Drücken geöffnet wird, sorgfältig befolgen, eist alles in Ordnung. In dem von Ihnen angegebenen Fall möchten Sie das -durch ein Leerzeichen am Anfang dieser Zeilen ersetzen :

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

... und löschen Sie die folgende Zeile, dh die, die mit beginnt +. Wenn Sie dann Ihren Editor speichern und beenden, wird nur das Entfernen des CSS-Kommentars bereitgestellt.

Mark Longair
quelle
9
Coole Lösung! Ich habe das gesehen, aber missverstanden ... Ich dachte, die Änderungen würden auch aus dem Arbeitsbaum entfernt.
Greg0ire
7
In der Tat ist es aus dem Hilfetext nicht sehr offensichtlich. Ich benutze das eigentlich sehr oft, da ich denke, dass Git dich wirklich ermutigt, jedes Commit so präzise und schön wie möglich zu gestalten :)
Mark Longair
27
Beachten Sie, dass Sie es wirklich durch ein Leerzeichen ersetzen müssen . Ich habe versucht, herauszufinden, dass ich die -Zeichen einfach löschen kann , und Git hat sich beschwert, dass mein Patch nicht angewendet wurde.
Ryan Lundy
3
Ich vermute, der Grund, warum Sie die Zeilen mit dem '-' löschen und '+' durch ein Leerzeichen ersetzen, ist, dass Sie dann einen Patch bilden, in dem diese Zeilen mit dem '-' bereits entfernt wurden und die Zeilen mit dem '-'. + wurden bereits hinzugefügt (in den Augen des Patches). Oder eine andere Sichtweise ist, dass Sie tatsächlich die Aktion ausführen, die diese Zeichen (-, +) darstellen (Hinzufügen einer Linie oder Entfernen). Nur die verbleibenden Zeilen mit '-'s und' + 'werden als Änderungen aufgezeichnet und der Rest ist "wie die Datei ist".
Atomiktom
3
@Filype: Ich weiß leider nicht, warum das passiert wäre - wenn Sie ein Stück damit ausgeführt git add -pund bearbeitet hätten e, hätte dies nur Auswirkungen auf die Inszenierung, nicht auf Ihren Arbeitsbaum.
Mark Longair
60

Nehmen wir an, Sie sehen so example.cssaus:

.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;
}

Lassen Sie uns nun die Stilauswahl im mittleren Block ändern und, während wir gerade dabei sind, einen alten auskommentierten Stil löschen, den wir nicht mehr benötigen.

.classname {
  width: 440px;
}

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

.another {
  width: 420px;
}

Das war einfach, jetzt legen wir fest. Aber warten Sie, ich möchte die logische Trennung der Änderungen in der Versionskontrolle für eine einfache schrittweise Codeüberprüfung beibehalten, damit mein Team und ich den Commit-Verlauf problemlos nach Einzelheiten durchsuchen können.

Das Löschen von altem Code ist logisch von der anderen Änderung der Stilauswahl getrennt. Wir werden zwei unterschiedliche Commits benötigen, also fügen wir Hunks für einen Patch hinzu.

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,?]?

Hoppla, es sieht so aus, als wären die Änderungen zu eng, also hat git sie zusammengeschmissen.

Selbst der Versuch, es durch Drücken zu teilen , shat das gleiche Ergebnis, da die Teilung für unsere Präzisionsänderungen nicht detailliert genug ist. Unveränderte Zeilen sind zwischen geänderten Zeilen erforderlich, damit Git den Patch automatisch aufteilen kann.

Lassen Sie es uns also manuell bearbeiten , indem Sie auf drückene

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

git öffnet den Patch in unserem Editor Ihrer Wahl.

# 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.

Lassen Sie uns das Ziel überprüfen:

Wie kann ich das Entfernen von CSS-Kommentaren nur zum nächsten Commit hinzufügen?

Wir wollen dies in zwei Commits aufteilen:

  1. Beim ersten Festschreiben werden einige Zeilen gelöscht (Entfernen von Kommentaren).

    Um die kommentierten Zeilen zu entfernen, lassen Sie sie einfach in Ruhe. Sie sind bereits markiert, um die Löschungen in der Versionskontrolle genau so zu verfolgen, wie wir es möchten.

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

  2. Das zweite Commit ist eine Änderung, die durch Aufzeichnen von Löschungen und Hinzufügungen verfolgt wird:

    • Löschungen (alte Auswahlzeilen entfernt)

      Um die alten Auswahlzeilen beizubehalten (löschen Sie sie während dieses Commits nicht), möchten wir ...

      Um '-' Linien zu entfernen, machen Sie sie ''

      ... das bedeutet wörtlich die minus ersetzen -Zeichen mit einem Leerzeichen Charakter.

      Also diese drei Zeilen ...

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

      ... wird ( beachten Sie das einzelne Leerzeichen in der ersten von allen 3 Zeilen):


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

    • Ergänzungen (neue Auswahlzeile hinzugefügt)

      Um nicht auf die neue Auswahlzeile zu achten, die während dieses Commits hinzugefügt wurde, möchten wir ...

      Um '+' Zeilen zu entfernen, löschen Sie sie.

      ... was wörtlich bedeutet, die ganze Zeile zu löschen:

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

      (Bonus: Wenn Sie zufällig vim als Editor verwenden, drücken Sie dd, um eine Zeile zu löschen. Nano- Benutzer drücken Ctrl+ K)

Ihr Editor sollte beim Speichern folgendermaßen aussehen:

# 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.

Jetzt legen wir fest.

git commit -m "remove old code"

Und um sicherzugehen, sehen wir uns die Änderungen seit dem letzten Commit an.

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 {

Perfekt - Sie können sehen, dass nur die Löschungen in diesem atomaren Commit enthalten waren. Jetzt beenden wir den Job und legen den Rest fest.

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;
 }

Schließlich können Sie sehen, dass das letzte Commit nur die Selektoränderungen enthält.

Jeff Puckett
quelle
1
Bonus # 2: Wenn Sie zufällig VIM als Editor verwenden, müssen Sie zweimal "d" auf Ihrer Tastatur drücken, um eine Zeile zu löschen: D
Alexxus
3
Auch anstelle die zusätzlichen Linien zu entfernen , die Sie nicht hinzufügen möchten, können Sie ersetzen +mit #. Das Ergebnis ist das gleiche, aber möglicherweise ist das Löschen (und das Zurücksetzen) unangenehm oder Sie möchten experimentieren, bevor Sie speichern.
Ob-Ivan
Und das, denn vim ist r #vorbei plus xD
aksh1618
Das Ziel ist "Wie kann ich das Entfernen von CSS-Kommentaren nur zum nächsten Commit hinzufügen?", Aber die Schritte sind wirklich verwirrend, was damit erreicht wird. (Wir möchten nur das "Entfernen" der wenigen Zeilen zum nächsten Commit "hinzufügen".) Es ist also sehr verwirrend, einfach "Entfernen" oder "Hinzufügen" zu sagen. Die Angabe, was bei jedem Schritt erreicht wurde, würde zur Klärung beitragen.
Ahnbizcad
9

Wenn Sie Git Gui verwenden können, können Sie Änderungen zeilenweise durchführen. Leider weiß ich nicht, wie ich es über die Kommandozeile machen soll - oder auch wenn es möglich ist.

Eine andere Option, die ich in der Vergangenheit verwendet habe, besteht darin, einen Teil der Änderung zurückzusetzen (den Editor offen zu halten), die gewünschten Bits festzuschreiben, rückgängig zu machen und im Editor erneut zu speichern. Nicht sehr elegant, erledigt aber die Arbeit. :) :)


EDIT (Git-GUI-Verwendung):

Ich bin nicht sicher, ob die Git-GUI in msysgit- und Linux-Versionen identisch ist. Ich habe nur die msysgit-Version verwendet. Unter der Annahme, dass es dasselbe ist, gibt es beim Ausführen vier Bereiche: Im oberen linken Bereich werden die Änderungen Ihres Arbeitsverzeichnisses vorgenommen, unten links werden die Änderungen Ihrer Stufen vorgenommen, oben rechts wird der Unterschied für die ausgewählte Datei angezeigt (sei es das Arbeitsverzeichnis) oder inszeniert), und unten rechts finden Sie eine Beschreibung des Commits (ich vermute, Sie werden es nicht benötigen). Wenn Sie oben rechts auf eine Datei klicken, wird der Unterschied angezeigt. Wenn Sie mit der rechten Maustaste auf eine Diff-Linie klicken, wird ein Kontextmenü angezeigt. Die beiden zu beachtenden Optionen sind "Stage Hunk for Commit" und "Stage Line for Commit". Sie wählen in den Zeilen, die Sie festschreiben möchten, weiterhin "Stage Line for Commit" und sind fertig. Sie können sogar mehrere Linien auswählen und sie inszenieren, wenn Sie möchten.

Zum Festschreiben können Sie entweder das GUI-Tool oder die Befehlszeile verwenden.

vhallac
quelle
Ihr zweiter Satz ist ziemlich offensichtlich, aber der erste ist interessant. Könnten Sie etwas mehr Details angeben? Ich habe installiert, git-guiaber ich habe keine Ahnung, wie ich das erreichen kann, was Sie beschreiben.
Greg0ire
vielen Dank! Das funktioniert! Ich konnte sogar die Linien auswählen, die ich inszenieren wollte, und sie mit einem Klick indizieren.
Greg0ire
0

Eine Möglichkeit, dies zu tun, besteht darin, den Block zu überspringen, git addwas auch immer Sie sonst noch benötigen, und ihn dann git adderneut auszuführen . Wenn dies der einzige Block ist, können Sie ihn aufteilen.

Wenn Sie sich Sorgen über die Reihenfolge der Commits machen, verwenden Sie einfach git rebase -i.

Abizern
quelle
Dies ist, was ich versucht habe, und das Stück in meiner Frage ist das einzige, wenn ich git add -pwieder renne , aber ich kann es nicht teilen. Ich verstehe das: Stage this hunk [y,n,q,a,d,/,e,?]?und wenn ich dann auf 's' drücke, wird die Hilfe gedruckt. Übrigens, meintest du add patchnicht patch add? Oder gibt es ein git patchPlugin, das ich installieren sollte?
Greg0ire
Haben Sie die inszenierten Hunks festgeschrieben, bevor Sie dies erneut ausgeführt haben? Und nein, Mercurial hat Plugins, Git nicht.
Abizern
Nein, habe ich nicht, ich möchte, dass sie sich im selben Commit befinden (aber ich denke, wenn Ihre Lösung funktioniert, kann ich - amend verwenden, um dies zu erreichen). Ich werde es versuchen.
Greg0ire
Wie meine Antwort sagte → git rebase -i. Welches ist flexibler alscommit --amend
Abizern