Come aggiungere un file modificato a un commit precedente (non ultimo) in Git


461

Ho cambiato diverse cose nell'ultima ora e le ho impegnate passo dopo passo, ma mi sono appena reso conto di aver dimenticato di aggiungere un file modificato alcuni commit fa.

Il registro è simile al seguente:

    GIT TidyUpRequests u:1 d:0> git log 
    commit fc6734b6351f6c36a587dba6dbd9d5efa30c09ce 
    Author: David Klein <> 
    Date:   Tue Apr 27 09:43:55 2010 +0200

        The Main program now tests both Webservices at once

    commit 8a2c6014c2b035e37aebd310a6393a1ecb39f463 
    Author: David Klein <>
    Date:   Tue Apr 27 09:43:27 2010 +0200

        ISBNDBQueryHandler now uses the XPath functions from XPath.fs too

    commit 06a504e277fd98d97eed4dad22dfa5933d81451f 
    Author: David Klein <> 
    Date:   Tue Apr 27 09:30:34 2010 +0200

        AmazonQueryHandler now uses the XPath Helper functions defined in XPath.fs

    commit a0865e28be35a3011d0b6091819ec32922dd2dd8 <--- changed file should go here
    Author: David Klein <> 
    Date:   Tue Apr 27 09:29:53 2010 +0200

        Factored out some common XPath Operations

Qualche idea?


Risposte:


694

Usa git rebase. In particolare:

  1. Utilizzare git stashper memorizzare le modifiche che si desidera aggiungere.
  2. Usa git rebase -i HEAD~10(o comunque molti commit che vuoi vedere).
  3. Contrassegna il commit in questione ( a0865...) per la modifica cambiando la parola pickall'inizio della riga in edit. Non eliminare le altre righe in quanto ciò eliminerebbe i commit. [^ Vimnote]
  4. Salvare il file rebase e git tornerà alla shell e aspetterà che tu ripari quel commit.
  5. Pop la scorta usando git stash pop
  6. Aggiungi il tuo file con git add <file>.
  7. Modifica il commit con git commit --amend --no-edit.
  8. Fai una git rebase --continuecosa che riscriverà il resto dei tuoi impegni contro quello nuovo.
  9. Ripeti dal passaggio 2 in poi se hai contrassegnato più di un commit per la modifica.

[^ vimnote]: se lo stai utilizzando, vimdovrai premere il Inserttasto per modificarlo, quindi Escdigitare e :wqper salvare il file, chiudere l'editor e applicare le modifiche. In alternativa, puoi configurare un editor di commit git di facile utilizzo con git config --global core.editor "nano".


23
Cosa succede se si hanno modifiche non messe in scena che si desidera aggiungere alla modifica? Se li nascondessi, non potrei git add.
Sam,

15
Sam, puoi semplicemente annullare le modifiche mentre sul commit in questione, funzionerà bene.
omnikron,

17
Nota: quando si contrassegna il commit con edit, NON ELIMINARE gli altri commit elencati nel file. In tal caso, i commit verranno eliminati e dovrai seguire questi passaggi per ripristinarli.
David Tuite,

2
Per quanto riguarda ciò che ha detto @DavidTuite, una mia abitudine quando faccio cose su Git che non sono sicuro di come andrà a finire è la creazione di un ramo "branchname-ref" per salvare lo stato attuale della sequenza temporale nel caso in cui rovini le cose. Quando ho finito, lo cancello.
Raffaello,

1
Nel passaggio 6, includere il. (punto) nel comando. Comando corretto:git add .
Tom

323

Per "correggere" un vecchio commit con una piccola modifica, senza cambiare il messaggio di commit del vecchio commit, dove OLDCOMMITè qualcosa di simile 091b73a:

git add <my fixed files>
git commit --fixup=OLDCOMMIT
git rebase --interactive --autosquash OLDCOMMIT^

È inoltre possibile utilizzare git commit --squash=OLDCOMMITper modificare il vecchio messaggio di commit durante rebase.


  • git rebase --interactivemostrerà un editor di testo (che può essere configurato ) per confermare (o modificare) la sequenza di istruzioni rebase . Ci sono informazioni per le modifiche all'istruzione rebase nel file; basta salvare e chiudere l'editor ( :wqinvim ) per continuare con la rebase.
  • --autosquashinserirà automaticamente tutti i --fixup=OLDCOMMITcommit nell'ordine desiderato. Si noti che --autosquashè valido solo quando --interactivesi utilizza l' opzione.
  • L' ^in OLDCOMMIT^significa che è un riferimento per il commit poco prima OLDCOMMIT.

I passaggi precedenti sono utili per la verifica e / o la modifica della sequenza di istruzioni rebase , ma è anche possibile saltare / automatizzare l'editor di testo rebase interattivo:

Vedi git commit e git rebase . Come sempre, quando riscrivi la cronologia di Git , dovresti solo risolvere i problemi di correzione o di compressione che non hai ancora pubblicato per nessun altro (inclusi utenti Internet casuali e server di build).


18
Molto più chiaro delle altre opzioni, e ha funzionato come un incantesimo
Chris Mitchelmore,

5
@Jonah: l'editor non è aperto per modificare il messaggio di commit , ma per confermare (o modificare) i passaggi di rebase . Non può essere evitato; --autosquashè valido solo quando --interactiveviene utilizzata l' opzione .
Joel Purra,

5
Usando questa soluzione sono bloccato git mostrando VIM. Il mio problema è che non so usare VIM. Come diamine posso uscirne, come posso controllare questa cosa, così confusa.
Neon Warge,

2
@NeonWarge: l'editor di scelta è configurabile usando ad esempio git config --global core.editor "pico". Esistono molti altri modi per configurare git e / o modificare l'editor predefinito ecc. Del sistema .
Joel Purra,

2
una bella riga qui
idanp

61

con git 1.7, c'è un modo davvero semplice usando git rebase:

mettere in scena i tuoi file:

git add $files

creare un nuovo commit e riutilizzare il messaggio di commit del commit "non funzionante"

git commit -c master~4

anteponi fixup!nella riga dell'oggetto (o squash!se desideri modificare il commit (messaggio)):

fixup! Factored out some common XPath Operations

utilizzare git rebase -i --autosquashper correggere il commit


2
+1. Uso bello della nuova direttiva correzione (1.7+): stackoverflow.com/questions/2302736/trimming-git-checkins/...
VonC

@knittl Stavo provando il tuo metodo per aggiungere un altro file a un mio vecchio commit (non spinto), ma quando lo ribasso ottengo You asked me to rebase without telling me which branch you want to rebase against, and 'branch.master.merge'e se poi uso git rebase -i --autosquashottengo solo una noopriga dell'oggetto, riordinando il commit su se stesso. Hai idea di cosa faccio di sbagliato?
Oschrenk,

7
@oschrenk: è necessario fornire un commit a cui si desidera git rebase -i --autosquash HEAD~10
reimpostare

1
Buona risposta, ma ho anche bisogno di aggiungere un commit contro il quale ribadire. Sarebbe bello se potessi aggiornarlo.
Paul Odeon,

@PaulOdeon: non capisco la tua domanda. Cosa stai cercando di fare e dove stai riscontrando problemi?
Knittl

8

Puoi provare una rebase --interactivesessione per modificare il tuo vecchio commit (a condizione che tu non abbia già trasferito tali commit in un altro repository).

A volte la cosa risolta in b.2. non può essere modificato al commit non del tutto perfetto che risolve, poiché il commit è sepolto profondamente in una serie di patch .
Questo è esattamente lo scopo del rebase interattivo: usalo dopo un sacco di "a" se "b", riorganizzando e modificando i commit e comprimendo più commit in uno.

Inizia con l'ultimo commit che vuoi conservare così com'è:

git rebase -i <after-this-commit>

Un editor verrà attivato con tutti i commit nel tuo ramo corrente (ignorando i commit di unione), che vengono dopo il commit dato.
Puoi riordinare gli commit in questo elenco in base al contenuto del tuo cuore e puoi rimuoverli. L'elenco è più o meno così:

pick deadbee The oneline of this commit
pick fa1afe1 The oneline of the next commit
...

Le descrizioni on-line sono puramente per il tuo piacere; git rebase non li guarderà ma i nomi di commit ("deadbee" e "fa1afe1" in questo esempio), quindi non cancellare o modificare i nomi.

Sostituendo il comando "pick" con il comando "edit", puoi dire a git rebase di fermarsi dopo aver applicato quel commit, in modo da poter modificare i file e / o il messaggio di commit, modificare il commit e continuare a riformulare .

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.