Commette solo una parte di un file in Git


2765

Quando apporto modifiche a un file in Git, come posso eseguire il commit solo di alcune modifiche?

Ad esempio, come è possibile eseguire il commit di solo 15 righe su 30 righe modificate in un file?


3
stackoverflow.com/q/34609924/52074 correlati : se è necessario dividere un pezzo in blocchi più piccoli.
Trevor Boyd Smith,

Riepilogo: in termini di capacità: git gui= git add -e> git add -i -p; in termini di convenienza: git gui> git add -i -p> git add -e. Quindi: scegli git guiquando hai accesso a X. scegli git add -i -pcose semplici e quando non hai o non vuoi usare X. git add -eper la messa in scena complessa senza X.
Penghe Geng

Risposte:


3688

Puoi usare git add --patch <filename>(o -pin breve), e git inizierà a scomporre il tuo file in quelli che ritiene siano "hunk" sensati (parti del file). Ti verrà quindi richiesto con questa domanda:

Stage this hunk [y,n,q,a,d,/,j,J,g,s,e,?]?

Ecco una descrizione di ciascuna opzione:

  • y mettere in scena questo pezzo per il prossimo commit
  • n non mettere in scena questo pezzo per il prossimo commit
  • qsmettere; non mettere in scena questo pezzo o nessuno dei pezzi rimanenti
  • a mettere in scena questo pezzo e tutti gli hunk successivi nel file
  • d non mettere in scena questo hunk o uno qualsiasi degli hunk successivi nel file
  • g seleziona un pezzo per andare a
  • / cerca un hunk corrispondente alla regex data
  • j lascia questo pezzo indeciso, vedi il prossimo pezzo indeciso
  • J lascia questo pezzo indeciso, vedi pezzo successivo
  • k lascia questo pezzo indeciso, vedi il pezzo precedente indeciso
  • K lascia questo pezzo indeciso, vedi pezzo precedente
  • s dividere il pezzo corrente in blocchi più piccoli
  • e modifica manualmente il pezzo corrente
  • ? aiuto stampa hunk

Se il file non è ancora nel repository, è possibile innanzitutto farlo git add -N <filename>. Successivamente puoi continuare con git add -p <filename>.

Successivamente, puoi utilizzare:

  • git diff --staged per verificare di aver messo in scena le modifiche corrette
  • git reset -p per mettere in scena pezzi aggiunti erroneamente
  • git commit -v per visualizzare il commit mentre si modifica il messaggio di commit.

Nota che questo è molto diverso dal git format-patchcomando, il cui scopo è analizzare i dati di commit in un .patchfile.

Riferimento per il futuro: Git Tools - Staging interattivo


83
Potrebbe essere utile notare che si -p/--patchtratta di una scorciatoia per l'azione patch all'interno del -i/--interactivecomando che avvia l'utile modalità interattiva .
tutuDajuju,

5
> Cosa succede se quel file è già in scena? Mostrerà solo le modifiche non messe in scena. Come git difffa.
Eugen Konkov,

3
Come posso modificare manualmente il pezzo corrente? Non so cosa fare dopo aver digitato e.
Hunsu,

23
Dopo aver premuto e, puoi modificare il pezzo manualmente sostituendo +o -by#
veksen il

1
questo è fantastico ma ora come lo spingo davvero? se lo faccio git pushdice già aggiornato. e se lo git diffvedo vedo i pezzi a cui ho detto n. se git diff --stagedvedo il commit voglio spingere. Supponendo di poter eseguire il commit, come posso eliminare i blocchi a cui ho detto no?
amante

250

È possibile utilizzare git add --interactiveo , quindi ( non ); vedere la modalità interattiva nella manpage git-add o semplicemente seguire le istruzioni.git add -p <file>git commit git commit -a

Modern Git ha anche git commit --interactive(e git commit --patch, che è un collegamento all'opzione patch nel commit interattivo).

Se preferisci farlo dalla GUI, puoi usare git-gui . Puoi semplicemente contrassegnare i pezzi che vuoi includere nel commit. Personalmente lo trovo più facile dell'uso git add -i. Anche altre GUI git, come QGit o GitX, potrebbero avere questa funzionalità.


1
È interessante notare che windows.github.com ha supportato il commit parziale dei file, ma sembra averlo abbandonato di recente ..
Juri,

1
@Juri Penso che il supporto per il commit dei file parziali sia tornato.
Ela782

@Juri Prego. In realtà non ho mai notato che era stato lì prima, l'ho visto la scorsa settimana e ho pensato "oh, che nuova straordinaria funzionalità"! :-)
Ela782,

1
Oggigiorno windows.github.com reindirizza al rinominato GitHub Desktop che è più bello della Git GUI e supporta commit parziali ... ma non supporta la firma del commit. Sospiro.

147

git gui fornisce questa funzionalità nella vista diff. Fai clic con il pulsante destro del mouse sulla linea o sulle linee che ti interessano e dovresti visualizzare una voce di menu "metti in scena questa linea per eseguire il commit".


13
per patch complesse questo è di solito l'approccio più veloce per me.
hochl,

7
Questo è un modo molto efficiente e intuitivo per aggiungere modifiche all'area di stadiazione in modo fine. Inoltre, è possibile selezionare più righe e verranno aggiunte tutte le modifiche all'interno di tale selezione.
jox,

Nota che non gitklo è, ma è incluso in Git Bash per Windows; dovresti avere una voce di menu di avvio per esso o puoi avviarlo con il comando git gui. C'è anche quello stage this hunkche è probabilmente più utile di stage this line. Potrebbe essere nuovo da quando questa risposta è stata creata 10 anni fa.
Chris,

82

Credo che git add -e myfilesia il modo più semplice (almeno la mia preferenza) poiché apre semplicemente un editor di testo e ti consente di scegliere quale linea vuoi mettere in scena e quale linea non lo fai. Per quanto riguarda i comandi di modifica:

contenuto aggiunto:

Il contenuto aggiunto è rappresentato da righe che iniziano con "+". È possibile impedire la messa in scena di eventuali linee di addizione eliminandole.

contenuto rimosso:

Il contenuto rimosso è rappresentato da linee che iniziano con "-". È possibile impedire la loro rimozione temporanea convertendo "-" in "" (spazio).

contenuto modificato:

Il contenuto modificato è rappresentato dalle righe "-" (rimuovendo il vecchio contenuto) seguito dalle righe "+" (aggiungendo il contenuto sostitutivo). È possibile impedire la modifica temporanea della conversione convertendo "-" righe in "" e rimuovendo le righe "+". Attenzione che la modifica di solo metà della coppia potrebbe introdurre cambiamenti confusi nell'indice.

Tutti i dettagli git addsono disponibili sugit --help add


7
Ciò sarebbe più utile se ci fosse una spiegazione chiara da qualche parte su come scegliere effettivamente quelle linee (cioè i comandi effettivi da inserire). Non ne ho trovato uno nella documentazione. Potresti aggiungere un riferimento?
Alex,

4
Per chi non ama le opzioni stenografiche, lo -eè --edit.
Kolyunya,

2
@Alex Le citazioni di riferimento aggiunte daFreedomBanana provengono dalla sezione MODIFICA PATCH ingit --help add
Randall

8
Questa è l'unica risposta (che richiede solo git) che risolve il problema di aggiungere / rimuovere una linea saggia quando non è possibile ridurre gli hunk sin modalità patch interattiva.
cdosborn,

3
Potrebbe essere utile capire che questo comando ( git add -e) * non * cambia il contenuto del file sul disco. Sposta solo parte delle modifiche da non in scena a in scena (indice).
Penghe Geng,

44

Se stai usando vim, potresti provare l'ottimo plugin chiamato fuggitivo .

Puoi vedere il diff di un file tra la copia di lavoro e l'indice con :Gdiff, e quindi aggiungere linee o blocchi all'indice usando i classici comandi vim diff come dp. Salvare le modifiche nell'indice e confermare con :Gcommit, e il gioco è fatto.

Molto interessanti screencast introduttivi qui (vedi esp. Parte 2 ).


Grazie mille per questo link. Esattamente lo stesso di cui ho bisogno. Soprattutto :diffget/:diffputin modalità visiva, dove posso scegliere linee specifiche, che voglio ripristinare / eseguire il commit. Quindi, assicurati di nuovo: vim è fantastico.
goodniceweb,

30

Consiglio vivamente di utilizzare SourceTree di Atlassian. (È gratuito.) Lo rende banale. Puoi mettere in scena singole parti di codice o singole righe di codice in modo rapido e semplice.

inserisci qui la descrizione dell'immagine


1
Sono d'accordo che SourceTree è un buon strumento per questo scopo, perché ti dà un controllo più preciso di quanto sia possibile attraverso la riga di comando.

19
@cupcake Direi il contrario, visto che SourceTree probabilmente usa quegli eseguibili git a linea di comando, intrinsecamente sarà sempre possibile fare le stesse (o più) azioni a grana fine tramite la "linea di comando".
tutuDajuju,

2
Indipendentemente dall'argomentazione fine che consiglio vivamente a SourceTree, poiché gli hunk di messa in scena e le singole linee sono super facili: i.imgur.com/85bNu4C.png
Mars Robertson,

1
@tutuDajuju In questo caso, non sono sicuro che sia vero. SourceTree ha la capacità di scegliere quali porzioni mettere in scena riga per riga . Non devi mettere in scena un intero pezzo; puoi mettere in scena 2 linee nel mezzo di un pezzo. Non ho idea di come ci riesca, però. (Al momento, sto cercando di aggirare l'incapacità di SourceTree di mettere in scena linee particolari per un file non tracciato. Sono atterrato qui alla ricerca di una soluzione alternativa, solo per scoprire che apparentemente Git sembra non offrire l'abilità line-by-line affatto. Almeno non in modo semplice.)
jpmc26

1
@Sun puoi fare clic sulla riga 50 e spostare + fare clic sulla riga 100, quindi in scena. Puoi facilmente mettere in scena la linea 50-100 in Sourcetree :)
ryan123 il

26

Vale la pena notare che per utilizzare git add --patchun nuovo file è necessario innanzitutto aggiungere il file da indicizzare con git add --intent-to-add:

git add -N file
git add -p file

23

Quando ho molte modifiche e finirò per creare qualche commit dalle modifiche, allora voglio salvare temporaneamente il mio punto di partenza prima di mettere in scena le cose.

Come questo:

$ git stash -u
Saved working directory and index state WIP on master: 47a1413 ...
$ git checkout -p stash
... step through patch hunks
$ git commit -m "message for 1st commit"
$ git checkout -p stash
... step through patch hunks
$ git commit -m "message for 2nd commit"
$ git stash pop

La risposta di Whymarrh è ciò che faccio di solito, tranne che a volte ci sono molti cambiamenti e posso dire che potrei fare un errore durante la messa in scena delle cose, e voglio uno stato impegnato su cui posso ricorrere per un secondo passaggio.


12

Se usi emacs, dai un'occhiata a Magit , che fornisce un'interfaccia git per emacs. Supporta abbastanza bene gli hunk di gestione temporanea (parti di file).


Spesso inciampo su un comando git che vuole aprire un editor, quando l'ho eseguito da una finestra della shell Mx. Magit intercetta questa follia e apre solo un nuovo buffer per quello? (per favore, nessun suggerimento daemon-emacs-demone; grazie comunque ma la vita è troppo breve).
user2066657,

No, per quanto ne so non lo intercetta. Ma non limitarti a crederci perché (1) non uso quasi mai la finestra della shell in Emacs e (2) normalmente utilizzo emacsclient. Detto questo, se emacsclient è un'opzione per te, ciò ha impedito almeno l'apertura di una finestra aggiuntiva con emacs e il buffer "COMMIT_EDITMSG" è stato aperto nella mia finestra Emacs esistente.
Mark van Lent,


9

Per coloro che usano le estensioni Git :

Nella finestra Commit, seleziona il file che desideri eseguire parzialmente il commit, quindi seleziona il testo che desideri impegnare nel riquadro a destra, quindi fai clic con il pulsante destro del mouse sulla selezione e scegli "Metti in scena le linee selezionate" dal menu di scelta rapida.


2
La scorciatoia da tastiera in Git Extensions per 'Stage linee selezionate' è s- molto utile per mettere in scena rapidamente parti di file per un commit.
Alchemistmatt,

8

Proprio come la risposta di jdsumsion, puoi anche nascondere il tuo lavoro attuale ma poi usare un difftool come la fusione per estrarre le modifiche selezionate dalla scorta. In questo modo puoi anche modificare gli hunk manualmente molto facilmente, il che è un po 'una seccatura quando in git add -p:

$ git stash -u
$ git difftool -d -t meld stash
$ git commit -a -m "some message"
$ git stash pop

L'uso del metodo stash ti dà l'opportunità di testare, se il tuo codice funziona ancora, prima di impegnarlo.


funziona bene, ma se lo usi git commit --amendsembra che dopo non riesci a far apparire lo stash o c'è un modo per farlo?
Segna il

7

Aggiungendo una risposta precedente, se si preferisce utilizzare la riga di comando, l'immissione git add -e myfileconsente di scegliere riga per riga ciò che si desidera eseguire, poiché questo comando aprirà un editor con le differenze, in questo modo:

inserisci qui la descrizione dell'immagine

Come +saprai, le linee che iniziano con -sono aggiunte, le linee che iniziano con sono cancellazioni. Così:

  • Per non mettere in scena un'aggiunta basta eliminare quella riga.
  • Per non mettere in scena una cancellazione basta sostituire -con spazio .

Questo è ciò che git add -hdice sull'aggiunta di file in questo modo (patch file):

contenuto aggiunto Il contenuto aggiunto è rappresentato da righe che iniziano con "+". È possibile impedire la messa in scena di eventuali linee di addizione eliminandole.

contenuto rimosso: il contenuto rimosso è rappresentato da linee che iniziano con "-". È possibile impedire la loro rimozione temporanea convertendo "-" in "" (spazio).

contenuto modificato: il contenuto modificato è rappresentato dalle righe "-" (rimuovendo il vecchio contenuto) seguito dalle righe "+" (aggiungendo il contenuto sostitutivo). È possibile impedire la modifica temporanea della conversione convertendo "-" righe in "" e rimuovendo le righe "+". Attenzione che la modifica di solo metà della coppia potrebbe introdurre cambiamenti confusi nell'indice.

Attenzione: non modificare il contenuto del file, questo non è un buon posto per farlo. Basta cambiare gli operatori delle righe cancellate o aggiunte.


Quale risposta precedente? Le risposte sono memorizzate in base al numero di punti che hanno. Quindi la tua risposta è in un posto diverso ora rispetto a quando l'hai scritta rispetto ad altre risposte.
KulaGGin

Credo che la risposta citata sia di @theFreedomBanana
K. Symbol

6

Il plugin vim-gitgutter può mettere in scena hunk senza uscire dall'editor vim

:GitGutterStageHunk

Oltre a ciò, offre altre interessanti funzioni come una colonna di segno diff come in alcuni IDE moderni

Se solo una parte del pezzo dovesse essere messa in scena vim-fuggitivo

:Gdiff

consente quindi la selezione della gamma visiva :'<,'>diffputo :'<,'>diffgetdi mettere in scena / ripristinare i cambi di linea individuali.



4

Con TortoiseGit:

fare clic con il tasto destro sul file e utilizzare Context Menu → Restore after commit. Questo creerà una copia del file così com'è. Quindi è possibile modificare il file, ad esempio in TortoiseGitMerge e annullare tutte le modifiche che non si desidera eseguire il commit. Dopo aver salvato tali modifiche è possibile eseguire il commit del file.


4

Sono passati 10 anni da quando questa domanda è stata posta. E spero che questa risposta sia utile a qualcuno. Come menzionato nella risposta qui , dove la GUI non è un'opzione, l' estensione crecord di Andrew Shadura aiuta a portare una finestra ncurses in cui possiamo selezionare le linee da impegnare.

Imposta l'estensione come segue:

git clone https://github.com/andrewshadura/git-crecord
cd git-crecord
./setup.py install
ln -s $PWD/git-crecord ~/.local/bin/git-crecord

cd al tuo repository git e invocalo come segue:

git crecord

Ciò farebbe apparire l'interfaccia ncurses che può essere utilizzata come mostrato di seguito. Premendo i seguenti tasti nella finestra di ncurses verranno eseguite alcune azioni:

f       hunk toggle fold (arrow keys can also be used)
space   toggle hunk selection
a       toggle commit or amend
c       confirm and open commit window

Screencast che mostra un esempio di utilizzoEsempio


3

Per gli utenti Atom , il pacchetto github include la gestione temporanea interattiva, nello stile di git gui. Per i collegamenti consultare la documentazione del pacchetto .

L'uso di Atom consente di lavorare con un tema con sfondo scuro (per impostazione predefinita, git guiha uno sfondo bianco).



2

git-meld-index - citando dal sito Web:

git-meld-index esegue la fusione - o qualsiasi altro git difftool (kdiff3, diffuse, ecc.) - per consentire all'utente di mettere in scena interattivamente le modifiche all'indice git (noto anche come area di staging git).

Questo è simile alla funzionalità di git add -p e git add --interactive. In alcuni casi la fusione è più facile / più veloce da usare rispetto a git add -p. Questo perché la fusione ti consente, ad esempio, di:

  • vedi più contesto
  • vedere le differenze interne alla linea
  • modifica a mano e vedi gli aggiornamenti diff 'live' (aggiornati dopo ogni pressione di un tasto)
  • passare a una modifica senza dire 'n' a ogni modifica che si desidera saltare

uso

In un repository git, eseguire:

git meld-index

Vedrai meld (o il tuo git difftool configurato) apparire con:

SINISTRA : directory temporanea contenente file copiati dall'albero di lavoro

A DESTRA : directory temporanea con i contenuti dell'indice. Ciò include anche i file che non sono ancora nell'indice ma che sono modificati o non tracciati nella copia di lavoro - in questo caso vedrai il contenuto del file da HEAD.

Modifica l'indice (lato destro) fino a quando felice. Ricorda di salvare quando necessario.

Al termine, close meld e git-meld-index aggiorneranno l'indice in modo che corrisponda al contenuto della directory temporanea sul lato destro della combinazione appena modificata.


2

Se è su Windowspiattaforma, secondo me git guiè un ottimo strumento per stage/ commitpoche righe dal unstagedfile

1. Hunk saggio:

  • Seleziona il file dalla unstagged Changessezione
  • Fare clic con il tasto destro del mouse sul codice che deve essere messo in scena
  • Selezionare Stage Hunk for commit

2. Linea saggia:

  • Seleziona il file dalla unstagged Changessezione
  • Seleziona la linea / le linee da mettere in scena
  • Fare clic con il tasto destro e selezionare Stage Lines for commit

3. Se si desidera mettere in scena il file completo tranne un paio di righe:

  • Seleziona il file dalla unstagged Changessezione
  • stampa Ctrl+T (Stage file to commit)
  • Il file selezionato ora passa alla Staged Changessezione
  • Seleziona la linea / le linee da mettere in scena
  • Fare clic con il tasto destro e selezionare UnStage Lines for commit

1

Come mostra una risposta sopra, puoi usare git add --patch filename.txt

o la forma abbreviata git add -p filename.txt

... ma per i file già presenti nel tuo repository, in s è molto meglio usare --patch flag direttamente sul comando commit (se stai usando una versione abbastanza recente di git): git commit --patch filename.txt

... o, ancora, la forma abbreviata git commit -p filename.txt

... e quindi usando i tasti menzionati, (y / n ecc.), per scegliere le righe da includere nel commit.


Che cosa ti dà " git add -p filename.txt" oltre a meno spazio per l'errore? Se sbagli la modifica del file parziale, annullare un'aggiunta è meglio che annullare un commit.
CTMacUser,

Non so perché, ma quando dico 'n' la linea viene inclusa .... e quando dico 'y' sul secondo pezzo, viene inclusa anche.
amorevole

1

git-cola è un'ottima interfaccia grafica e ha anche questa funzione integrata. Basta selezionare le linee per mettere in scena e premere S. Se non viene effettuata alcuna selezione, viene messo in scena l'intero blocco.

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.