Annulla parte delle modifiche non messe in scena in git


158

Come posso annullare parti delle mie modifiche non messe in scena in Git ma mantenere il resto come non messo in scena? Il modo in cui ho capito è:

git commit --interactive
# Choose the parts I want to delete
# Commit the changes
git stash
git rebase -i master # (I am an ancestor of master)
# Delete the line of the most recent commit
git stash apply

Funziona, ma sarebbe bello se ci fosse qualcosa di simile git commit --interactivesolo per ripristinare le modifiche. Qualche metodo migliore?

Risposte:


265

È possibile utilizzare git checkout -p, che consente di scegliere singoli hunk dal diff tra la copia di lavoro e l'indice da ripristinare. Allo stesso modo, git add -pti consente di scegliere gli hunk da aggiungere all'indice e git reset -pti consente di scegliere singoli hunk dal diff tra l'indice e HEAD per uscire dall'indice.

$ git checkout -p file/to/partially/revert
# or ...
$ git checkout -p .

Se desideri effettuare un'istantanea del tuo repository git in anticipo per preservare queste modifiche prima di ripristinarle, mi piace fare:

$ git stash; git stash apply

Se lo usi spesso, potresti volerlo alias:

[alias]
    checkpoint = !git stash; git stash apply

Il ripristino di singoli hunk o linee può essere ancora più semplice se si utilizza una buona modalità editor o plug-in, che può fornire supporto per la selezione diretta delle linee da ripristinare, poiché a volte -ppuò essere un po 'goffo. Uso Magit , una modalità Emacs che è molto utile per lavorare con Git. In Magit, puoi correre magit-status, trovare le differenze per le modifiche che vuoi ripristinare, selezionare le linee che desideri ripristinare (o semplicemente posizionare il cursore su blocchi che desideri ripristinare se vuoi ripristinare un pezzo alla volta anziché una riga alla volta) e premere kper ripristinare quelle righe specifiche. Consiglio vivamente Magit se usi Emacs.


Penso che sia complessa quanto la soluzione che mi è venuta in origine, ma penso che la mia soluzione originale abbia il vantaggio di salvare le linee rimosse per 30 giorni perché sono impegnate. Penso che forse sarebbe bello avere uno script shell scritto attorno ad esso, però.
asmeurer

1
Mi dispiace, ho appena realizzato che git checkoutha anche una -pbandiera, che fa esattamente quello che stavi chiedendo in un singolo comando. Scuse per il precedente complesso set di passaggi; puoi semplicemente usare git checkout -p. Per quanto riguarda il salvataggio di cose, prima di fare qualcosa di potenzialmente distruttivo faccio spesso un git stash; git stash apply(o creo un alias che lo fa come git checkpointo qualcosa del genere) per registrare l'albero corrente in uno stash in modo da poter tornare indietro se qualcosa va storto.
Brian Campbell,

Ecco qua, questa è la soluzione! Per quanto riguarda l'alias, sto pensando che qualcosa del genere git commit -a -m "Backup Commit" --edit; git reset HEAD^ sarebbe meglio, perché non sporcherebbe il mio stato di stash, che potrei usare per qualcos'altro. Quindi, finché hai SHA1, puoi sceglierlo entro i prossimi 30 giorni. --Edit ti consente di aggiungere informazioni al messaggio di commit per aiutarti a trovare SHA1 in seguito, se lo desideri. D'altra parte, questo sporcherebbe il reflog di git, quindi immagino che sia un compromesso basato su quello che fai.
asmeurer,

L'alias del checkpoint non funziona per me: viene eseguito solo il primo comando, non il secondo. È triste, perché mi sarebbe piaciuto. Sto usando git versione 1.7.10.4.
Fabien,

C'è un modo per git checkout -pnon applicare le patch all'indice ma solo per metterle in scena?
Geremia,

28
git diff > patchfile

Quindi modifica il file di patch e rimuovi le parti che non desideri annullare, quindi:

patch -R < patchfile

6
Tuttavia, questa risposta è particolarmente ammirevole per la sua semplicità e facilità d'uso. +1
tholy

Il generato patchfilesembra fantastico in vim e aiuta davvero!
Bily,

Perfetto. Posso confermare che funziona anche con Windows con Cygwin e Ubuntu Bash per Windows.
Checo R,

1
Nota che puoi anche usare git apply -Rinvece di patch(solo per rimanere nei regni di git, o nell'evento diverso che patchnon è disponibile)
user1556435

patch: **** malformed patch at line 41: @@ -428,9 +443,9 @@ you should place your code here."
HappyFace,

5

Si potrebbe fare

git checkout master -- path/to/file

Per ogni file che si desidera ripristinare.


Oppure usa HEAD al posto del master se lavori su un ramo. Come indicato nel rapporto "stato git" (almeno nelle versioni recenti).
Jonathan Leffler,

1

Che ne dite di

  1. Eseguire il backup dei file interessati con le modifiche dall'indice
  2. utilizzare git add -psolo per aggiungere nuovamente le modifiche che si desidera all'indice.

1

Quando eseguo 'git status', dice:

$ git status
# On branch fr/fr.002
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   makefile
#
no changes added to commit (use "git add" and/or "git commit -a")
$

Quindi, per annullare le modifiche non messe in scena, mi dice di eseguire:

git checkout -- makefile

3
Penso che si stesse chiedendo come ripristinare singoli hunk, non un intero file alla volta. Questa è, ovviamente, la soluzione se devi solo annullare tutte le modifiche in un file.
Brian Campbell,

Sì, sospetto che tu abbia ragione. Le opzioni 'git checkout -p' e 'git add -p' sembrano essere probabilmente ciò che si desidera - come hai detto.
Jonathan Leffler,

1

La risposta di Brian Campbell fa crashare il mio git, versione 1.9.2.msysgit.0, per ragioni sconosciute, quindi il mio approccio è mettere in scena pezzi che voglio conservare, scartare le modifiche nella copia di lavoro, quindi mettere in scena.

$ git add -p
   ... select the hunks to keep
$ git checkout -- .
$ git reset HEAD .

1
C'è anche git stash -p. Si potrebbe fare git stash -p; git reset --hard; git stash pop. Questo è effettivamente lo stesso di quello che stai facendo, tranne per il fatto che non devi scrivere un messaggio di commit.
asmeurer,

@asmeurer evviva. Il mio non richiede un messaggio di commit, ma probabilmente ha più senso usare lo stash che l'indice per questo.
G-Wiz,

0

puoi fare git checkoute assegnargli i nomi delle parti che vuoi annullare.

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.