Posso dividere un pezzo già diviso con git?


205

Di recente ho scoperto l' patchopzione git per il addcomando e devo dire che è davvero una funzionalità fantastica. Ho anche scoperto che un grosso pezzo poteva essere diviso in piccoli pezzi premendo la schiave, il che aumenta la precisione del commit. E se volessi una precisione ancora maggiore, se il pezzo diviso non fosse abbastanza piccolo?

Ad esempio, considera questo pezzo già diviso:

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

Come posso aggiungere la rimozione dei commenti CSS solo al prossimo commit? L' sopzione non è più disponibile!

Risposte:


254

Se stai usando git add -pe anche dopo aver diviso s, non hai una modifica abbastanza piccola, puoi usare eper modificare direttamente la patch.

Questo può essere un po 'confuso, ma se segui attentamente le istruzioni nella finestra dell'editor che verrà aperta dopo aver premuto, eallora andrà bene. Nel caso in cui hai citato, vorrai sostituire il -con uno spazio all'inizio di queste righe:

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

... ed elimina la seguente riga, ovvero quella che inizia con +. Se poi salvi ed esci dal tuo editor, verrà messa in scena solo la rimozione del commento CSS.


9
Soluzione fantastica! L'ho visto ma frainteso ... Pensavo che i cambiamenti sarebbero stati rimossi anche dall'albero di lavoro.
greg0ire,

7
In effetti, non è molto evidente dal testo di aiuto. Mi trovo a usarlo molto, in realtà, poiché penso che git ti incoraggi davvero a rendere ogni impegno il più preciso e bello possibile :)
Mark Longair,

27
Nota che devi davvero sostituirlo con uno spazio . L'ho provato pensando di poter semplicemente eliminare i -personaggi e Git si è lamentato del fatto che la mia patch non fosse applicabile.
Ryan Lundy,

3
Sto indovinando il motivo per cui elimini le linee con '-' e sostituisci '+' con uno spazio è che stai formando una patch in cui quelle linee con '-' sono già state rimosse e le linee con ' I + sono già stati aggiunti (nell'occhio della patch). O un altro modo di vederlo, è effettivamente compiere l'azione che quei personaggi (-, +) rappresentano (aggiungendo una linea o rimuovendola). Solo le righe rimanenti con '-'s e' + 'vengono registrate come modifiche e il resto è "proprio come è il file".
Atomictom,

3
@Filype: non so perché ciò sarebbe accaduto, temo - se tu stessi correndo git add -pe modificando un pezzo con equesto dovrebbe influenzare solo ciò che è in scena, non il tuo albero di lavoro.
Mark Longair,

60

Supponiamo che example.cssassomigli a questo:

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

Ora cambiamo i selettori di stile nel blocco centrale e, mentre ci siamo, eliminiamo qualche vecchio stile commentato che non ci serve più.

.classname {
  width: 440px;
}

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

.another {
  width: 420px;
}

È stato facile, ora impegniamoci. Ma aspetta, voglio mantenere la separazione logica delle modifiche nel controllo della versione per una semplice revisione del codice passo-passo e in modo che io e il mio team possiamo facilmente cercare nella cronologia di commit specifiche.

L'eliminazione del vecchio codice è logicamente separata dall'altra modifica del selettore di stile. Avremo bisogno di due commit distinti, quindi aggiungiamo hunk per una 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,?]?

Spiacenti, sembra che i cambiamenti siano troppo vicini, quindi Git li ha raggruppati insieme.

Anche provare a dividerlo premendo sha lo stesso risultato perché la divisione non è abbastanza granulare per le nostre modifiche di precisione. Sono necessarie linee invariate tra le linee modificate per consentire a git di dividere automaticamente la patch.

Quindi, cerchiamo di manualmente modificare premendoe

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

git aprirà la patch nel nostro editor preferito.

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

Rivediamo l'obiettivo:

Come posso aggiungere la rimozione dei commenti CSS solo al prossimo commit?

Vogliamo dividerlo in due commit:

  1. Il primo commit comporta l'eliminazione di alcune righe (rimozione dei commenti).

    Per rimuovere le righe commentate, lasciarle da sole, sono già contrassegnate per tenere traccia delle eliminazioni nel controllo versione proprio come vogliamo.

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

  2. Il secondo commit è una modifica, che viene tracciata registrando sia le eliminazioni che le aggiunte:

    • Eliminazioni (vecchie righe di selezione rimosse)

      Per mantenere le vecchie linee di selezione (non cancellarle durante questo commit), vogliamo ...

      Per rimuovere le righe "-", crearle ""

      ... che significa letteralmente sostituire i -segni meno con un carattere spaziale .

      Quindi queste tre linee ...

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

      ... diventerà ( notare il singolo spazio nella prima di tutte e 3 le righe):


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

    • Aggiunte (aggiunta nuova linea di selezione)

      Per non prestare attenzione alla nuova linea di selezione aggiunta durante questo commit, vogliamo ...

      Per rimuovere le righe "+", eliminale.

      ... che significa letteralmente eliminare l'intera riga:

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

      (Bonus: se ti capita di usare vim come editor, premi ddper eliminare una riga. Gli utenti Nano premono Ctrl+ K)

Il tuo editor dovrebbe apparire così quando salvi:

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

Ora impegniamoci.

git commit -m "remove old code"

E solo per essere sicuri, vediamo le modifiche dall'ultimo commit.

git show
commit 572ecbc7beecca495c8965ce54fbccabdd085112
Author: Jeff Puckett <jeff@jeffpuckett.com>
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 {

Perfetto: puoi vedere che solo le eliminazioni sono state incluse in quel commit atomico. Ora finiamo il lavoro e impegniamo il resto.

git add .
git commit -m "change selectors"
git show
commit 83ec3c16b73bca799e4ed525148cf303e0bd39f9
Author: Jeff Puckett <jeff@jeffpuckett.com>
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;
 }

Finalmente puoi vedere che l'ultimo commit include solo le modifiche al selettore.


1
Bonus n. 2: se ti capita di usare VIM come editor, devi premere due volte "d" sulla tastiera per eliminare una riga: D
Alexxus

3
Inoltre, invece di rimuovere le linee aggiunte che non si desidera aggiungere, è possibile sostituire +con #. Il risultato è lo stesso, ma forse ti senti a disagio con l'eliminazione (e non riesci a ripristinare) o vuoi sperimentare prima di salvare.
ob-ivan,

E quello, perché Vim è r #oltre il plus xD
aksh1618

L'obiettivo è "Come posso aggiungere la rimozione dei commenti CSS solo al prossimo commit?", Ma i passaggi sono davvero confusi su ciò che sta realizzando. (vogliamo "aggiungere" solo la "rimozione" delle poche righe al prossimo commit.) Quindi dire semplicemente rimuovere o aggiungere è molto confuso. Dichiarare ciò che è stato realizzato in ogni fase aiuterebbe a chiarire.
ahnbizcad,

9

Se puoi usare git gui, ti consente di mettere in scena i cambiamenti riga per riga. Sfortunatamente, non so come farlo dalla riga di comando - o anche se è possibile.

Un'altra opzione che ho usato in passato è il rollback di parte della modifica (tenere aperto l'editor), eseguire il commit dei bit desiderati, annullare e salvare nuovamente dall'editor. Non molto elegante, ma fa il suo lavoro. :)


EDIT (utilizzo di git-gui):

Non sono sicuro che git-gui sia lo stesso nelle versioni msysgit e linux, ho usato solo quello msysgit. Ma supponendo che sia lo stesso, quando lo esegui, ci sono quattro riquadri: il riquadro in alto a sinistra indica le modifiche alla directory di lavoro, in basso a sinistra le modifiche alle fasi, in alto a destra è il diff per il file selezionato (sia che funzioni o in scena), e in basso a destra è per la descrizione del commit (sospetto che non ne avrai bisogno). Quando fai clic su un file in quello in alto a destra, vedrai il diff. Se fai clic con il tasto destro su una linea diff, vedrai un menu contestuale. Le due opzioni da notare sono "stage hunk for commit" e "stage line for commit". Continui a selezionare "stage line for commit" sulle righe che vuoi impegnare e il gioco è fatto. Puoi anche selezionare più linee e metterle in scena se vuoi.

Per quanto riguarda il commit, puoi usare lo strumento gui o la riga di comando.


La tua seconda proposta è abbastanza evidente, ma la prima è interessante, potresti approfondire un po 'di più? Ho installato git-guima non ho idea di come ottenere ciò che stai descrivendo.
greg0ire,

grazie mille! Questo funziona! Sono stato anche in grado di selezionare le linee che volevo mettere in scena e indicizzarle con un clic.
greg0ire,

0

Un modo per farlo è saltare il pezzo, git addqualunque altra cosa ti serva, e poi correre di git addnuovo. Se questo è l'unico pezzo, sarai in grado di dividerlo.

Se sei preoccupato per l'ordine dei commit, basta usare git rebase -i.


Questo è quello che ho provato, e il pezzo nella mia domanda è l'unico quando corro di git add -pnuovo, ma non riesco a dividerlo. Ho capito: Stage this hunk [y,n,q,a,d,/,e,?]?e poi colpire 's' stampa l'aiuto. A proposito, intendevi add patchno patch add? O c'è un git patchplugin che dovrei installare?
greg0ire,

Hai commesso gli hunk in scena prima di eseguirlo di nuovo? E no, Mercurial ha plugin, Git no.
Abizern,

No non l'ho fatto, voglio che facciano lo stesso commit (ma immagino che se la tua soluzione funziona, posso usare - aggiustare per raggiungere questo obiettivo). Lo proverò.
greg0ire,

Come diceva la mia risposta → git rebase -i. Che è più flessibile dicommit --amend
Abizern l'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.