Rompere un commit precedente in più commit

Senza creare una succursale e svolgere una serie di lavori funky su un nuovo ramo, è ansible rompere un singolo commit in un paio di commit diversi dopo che è stato eseguito il commit nel repository locale?

git rebase -i lo farà.

Innanzitutto, inizia con una directory di lavoro pulita: lo git status dovrebbe mostrare modifiche, eliminazioni o aggiunte in sospeso.

Per dividere il tuo commit più recente, prima:

 $ git reset HEAD~ 

Ora impegna i pezzi individualmente nel solito modo, producendo il numero di commit di cui hai bisogno.

Se fosse più indietro nell’albero, allora

 $ git rebase -i HEAD~3 

dove 3 è il numero di commit che è.

Se fosse più indietro nell’albero di quanto tu voglia contare, allora

 $ git rebase -i 123abcd~ 

dove 123abcd è lo SHA1 del commit che vuoi dividere.

Quando ottieni la schermata di modifica di rebase, trova il commit che vuoi separare. All’inizio di questa riga, sostituisci pick con edit ( e in breve). Salva il buffer ed esci. Ora Rebase si fermerà subito dopo il commit che vuoi modificare. Poi:

 $ git reset HEAD~ 

Impegna i pezzi singolarmente nel solito modo, producendo il numero di commit di cui hai bisogno, quindi

 $ git rebase --continue 

Manuale di git-rebase (sezione SPLITTING COMMITS)

In modalità intertriggers, puoi contrassegnare i commit con l’azione “modifica”. Tuttavia, questo non significa necessariamente che git rebase si aspetta che il risultato di questa modifica sia esattamente un commit. In effetti, è ansible annullare il commit o aggiungere altri commit. Questo può essere usato per dividere un commit in due:

  • Avvia un rebase interattivo con git rebase -i ^ , dove è il commit che vuoi dividere. In effetti, qualsiasi intervallo di commit lo farà, purché contenga quel commit.

  • Segna il commit che vuoi dividere con l’azione “modifica”.

  • Quando si tratta di modificare quel commit, eseguire git reset HEAD^ . L’effetto è che l’HEAD viene riavvolto di uno, e l’indice segue l’esempio. Tuttavia, l’albero di lavoro rimane lo stesso.

  • Ora aggiungi le modifiche all’indice che vuoi avere nel primo commit. Puoi usare git add (possibilmente in modo interattivo) o git gui (o entrambi) per farlo.

  • Impegna l’indice corrente attuale con qualsiasi messaggio di commit appropriato ora.

  • Ripeti gli ultimi due passaggi finché l’albero di lavoro non è pulito.

  • Continua il rebase con git rebase --continue .

Usa git rebase --interactive per modificare quello precedentemente commit, esegui git reset HEAD~ , quindi git add -p per aggiungerne un po ‘, poi fai un commit, poi aggiungi un altro e fai un altro commit, tutte le volte che vuoi. Quando hai finito, esegui git rebase --continue , e avrai tutti i commit divisi in precedenza nello stack.

Importante : tieni presente che puoi giocare e apportare tutte le modifiche che desideri e non devi preoccuparti di perdere le vecchie modifiche, perché puoi sempre eseguire git reflog per trovare il punto nel tuo progetto che contiene le modifiche che vuoi, (chiamiamo a8c4ab ), quindi git reset a8c4ab .

Ecco una serie di comandi per mostrare come funziona:

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

ora aggiungi un file A

vi A

aggiungi questa linea:

one

git commit -am one

quindi aggiungi questa linea a A:

two

git commit -am two

quindi aggiungi questa linea a A:

three

git commit -am three

ora il file A assomiglia a questo:

 one two three 

e il nostro git log è simile al seguente (beh, io uso 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 

Diciamo che vogliamo dividere il secondo commit, two .

git rebase --interactive HEAD~2

Questo fa apparire un messaggio simile al seguente:

 pick 2b613bc two pick bfb8e46 three 

Cambia la prima pick in una e per modificare quel commit.

git reset HEAD~

git diff ci mostra che abbiamo appena distriggersto il commit che abbiamo fatto per il secondo commit:

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

Mettiamo in scena quel cambiamento e aggiungiamo “e un terzo” a quella riga nel file A

git add .

Questo è solitamente il punto durante un rebase interattivo in cui dovremmo eseguire git rebase --continue , perché di solito vogliamo semplicemente tornare indietro nel nostro stack di commit per modificare un commit precedente. Ma questa volta, vogliamo creare un nuovo commit. Quindi eseguiremo git commit -am 'two and a third' . Ora modifichiamo il file A e aggiungiamo la linea two and two thirds .

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

Abbiamo un conflitto con il nostro commit, three , quindi risolviamolo:

Cambiamo

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

a

 one two and a third two and two thirds three 

git add .; git rebase --continue

Ora il nostro git log -p questo aspetto:

 commit e59ca35bae8360439823d66d459238779e5b4892 Author: Rose Perrone  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  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  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  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 

Le risposte precedenti hanno coperto l’uso di git rebase -i per modificare il commit che si desidera dividere e impegnarlo in parti.

Funziona bene quando si suddividono i file in commit diversi, ma se si desidera rompere le modifiche ai singoli file, è necessario saperne di più.

Avendo ottenuto il commit che vuoi dividere, usando rebase -i e contrassegnandolo per la edit , hai due opzioni.

  1. Dopo aver usato git reset HEAD~ , passa attraverso i patch individualmente usando git add -p per selezionare quelli che vuoi in ogni commit

  2. Modifica la copia di lavoro per rimuovere le modifiche che non desideri; commettere quello stato provvisorio; e quindi ritirare il commit completo per il prossimo round.

L’opzione 2 è utile se stai dividendo un grosso commit, in quanto ti consente di controllare che le versioni provvisorie vengano compilate ed eseguite correttamente come parte dell’unione. Questo procede come segue.

Dopo aver usato rebase -i e edit il commit, usa

 git reset --soft HEAD~ 

per annullare il commit, ma lasciare i file impegnati nell’indice. Puoi anche eseguire un reset misto omettendo –soft, a seconda di quanto vicino al risultato finale sarà il tuo commit iniziale. L’unica differenza è se inizi con tutte le modifiche messe in scena o con tutte quelle non triggerste.

Ora vai e modifica il codice. Puoi rimuovere le modifiche, eliminare i file aggiunti e fare tutto ciò che vuoi per build il primo commit della serie che stai cercando. Puoi anche crearlo, eseguirlo e confermare di disporre di un insieme coerente di fonti.

Una volta che sei felice, metti in scena / metti in pausa i file secondo necessità (mi piace usare git gui per questo) e commetti le modifiche attraverso l’interfaccia utente o la riga di comando

 git commit 

Questo è il primo impegno fatto. Ora vuoi ripristinare la tua copia di lavoro allo stato che aveva dopo il commit che stai dividendo, in modo da poter prendere più modifiche per il prossimo commit. Per trovare lo sha1 del commit che stai modificando, usa git status . Nelle prime righe dello stato vedrai il comando rebase attualmente in esecuzione, in cui puoi trovare lo sha1 del tuo commit originale:

 $ 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) ... 

In questo caso, il commit che sto modificando ha sha1 65dfb6a . Sapendo questo, posso controllare il contenuto di quel commit sulla mia directory di lavoro usando il modulo di git checkout che prende sia un commit che un percorso di file. Qui io uso . come posizione del file per sostituire l’intera copia di lavoro:

 git checkout 65dfb6a . 

Non perdere il punto alla fine!

Questo controllerà e metterà in scena i file così come erano dopo il commit che stai modificando, ma in relazione al commit precedente che hai fatto, quindi tutte le modifiche già commesse non faranno parte del commit.

Ora puoi andare avanti e commetterlo così com’è per finire lo split, o andare di nuovo in giro, cancellando alcune parti del commit prima di fare un altro commit temporaneo.

Se si desidera riutilizzare il messaggio di commit originale per uno o più commit, è ansible utilizzarlo direttamente dai file di lavoro di rebase:

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

Infine, una volta che hai effettuato tutte le modifiche,

 git rebase --continue 

proseguirà e completerà l’operazione di rebase.

git rebase --interactive può essere usato per dividere un commit in commit più piccoli. I documenti Git su rebase hanno una concisa procedura dettagliata del processo: Splitting Commits :

In modalità intertriggers, puoi contrassegnare i commit con l’azione “modifica”. Tuttavia, questo non significa necessariamente che git rebase aspetta che il risultato di questa modifica sia esattamente un commit. In effetti, è ansible annullare il commit o aggiungere altri commit. Questo può essere usato per dividere un commit in due:

  • Avvia un rebase interattivo con git rebase -i ^ , dove è il commit che vuoi dividere. In effetti, qualsiasi intervallo di commit lo farà, purché contenga quel commit.

  • Segna il commit che vuoi dividere con l’azione “modifica”.

  • Quando si tratta di modificare quel commit, eseguire git reset HEAD^ . L’effetto è che l’HEAD viene riavvolto di uno, e l’indice segue l’esempio. Tuttavia, l’albero di lavoro rimane lo stesso.

  • Ora aggiungi le modifiche all’indice che vuoi avere nel primo commit. Puoi usare git add (possibilmente in modo interattivo) o git gui (o entrambi) per farlo.

  • Impegna l’indice corrente attuale con qualsiasi messaggio di commit appropriato ora.

  • Ripeti gli ultimi due passaggi finché l’albero di lavoro non è pulito.

  • Continua il rebase con git rebase --continue .

Se non sei assolutamente sicuro che le revisioni intermedie siano coerenti (compilano, passano testuite, ecc.) Dovresti usare git stash per ripulire le modifiche non ancora commesse dopo ogni commit, test e modifica del commit se le correzioni sono necessari

Puoi eseguire rebase git rebase -i interattivo git rebase -i . La pagina man ha esattamente quello che vuoi:

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

Nota che c’è anche git reset --soft HEAD^ . È simile a git reset (che è --mixed su --mixed ) ma mantiene il contenuto dell’indice. In modo che se hai aggiunto / rimosso i file, li hai già nell’indice.

Risulta molto utile in caso di commit giganti.

Ora nell’ultimo TortoiseGit su Windows puoi farlo molto facilmente.

Apri la finestra di dialogo di rebase, configurala e procedi come segue.

  • Fai clic con il tasto destro sul commit che vuoi dividere e seleziona ” Edit ” (tra scelta, squash, cancella …).
  • Fai clic su ” Start ” per iniziare il rebasing.
  • Una volta arrivato al commit da dividere, seleziona il pulsante ” Edit/Split ” e fai clic su ” Amend ” direttamente. Si apre la finestra di commit.
    Modifica / Dividi commit
  • Deseleziona i file che vuoi mettere su un commit separato.
  • Modifica il messaggio di commit, quindi fai clic su ” commit “.
  • Fino a quando non ci sono file da impegnare, la finestra di commit si aprirà ancora e ancora. Quando non ci sono più file da impegnare, ti verrà chiesto se vuoi aggiungere ancora un commit.

Molto utile, grazie TortoiseGit!

Penso che il modo migliore di usare git rebase -i . Ho creato un video per mostrare i passaggi per dividere un commit: https://www.youtube.com/watch?v=3EzOz7e1ADI

La cosa più semplice da fare senza un rebase interattivo è (probabilmente) per fare un nuovo ramo che inizia dal commit prima di quello che vuoi dividere, cherry-pick -n il commit, resettare, stash, commit il file move, riapplicare lo stash e commetti le modifiche e poi unisci con il precedente ramo o seleziona i commit che seguono. (Quindi cambia il nome dell’ex ramo nella testa corrente.) (Probabilmente è meglio seguire i consigli degli MBO e fare un rebase interattivo).

Se hai questo:

 A - B <- mybranch 

Dove hai impegnato del contenuto nel commit B:

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

Ma tu vuoi dividere B in C - D e ottenere questo risultato:

 A - C - D <-mybranch 

Puoi dividere il contenuto come questo ad esempio (contenuto da diverse directory in commit differenti) ...

Reimposta il ramo sul commit prima di dividerlo:

 git checkout mybranch git reset --hard A 

Crea il primo commit (C):

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

Crea secondo commit (D):

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