Impegna solo una parte di un file in Git

Quando apporto le modifiche a un file in Git, come posso impegnare solo alcune delle modifiche?

Ad esempio, come posso impegnare solo 15 righe su 30 righe che sono state modificate in un file?

Puoi usare git add --patch (o -p in breve), e git inizierà a scomporre il tuo file in ciò che pensa siano “hunk” sensibili (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 stage questo hunk per il prossimo commit
  • n non mettere in scena questo pezzo per il prossimo commit
  • q esci; non mettere in scena questo pezzo o uno qualsiasi dei pezzi restanti
  • uno stage questo pezzo e tutti gli hunk successivi nel file
  • d non mettere in scena questo hunk o uno dei pezzi successivi nel file
  • g seleziona un pezzo per andare a
  • / cerca un hunk che corrisponda alla regex data
  • Lascia questo pezzo indeciso, guarda il prossimo pezzo indeciso
  • Lascia questo pezzo indeciso, guarda il prossimo pezzo
  • Lascia questo pezzo indeciso, vedi il pezzo indeciso precedente
  • K lascia questo pezzo indeciso, guarda il pezzo precedente
  • s divide il pezzo attuale in pezzi più piccoli
  • e modifica manualmente il pezzo corrente
  • ? stampare aiuto per i fusti

Se il file non è ancora nel repository, puoi prima fare git add -N . Successivamente puoi continuare con git add -p .

Successivamente, puoi usare:
git diff --staged per verificare di aver messo in scena le modifiche corrette
git reset -p per sottrarre gli hunk aggiunti erroneamente
git commit -v per visualizzare il commit mentre si modifica il messaggio di commit.

Nota che questo è molto diverso dal comando git format-patch , il cui scopo è quello di analizzare i dati di commit in un file .patch .

Riferimento per il futuro: https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging

Puoi usare git add --interactive o git add -p < file > e poi git commit ( non git commit -a ); vedi la modalità intertriggers nella manpage git-add , o semplicemente segui le istruzioni.

Modern Git ha anche git commit --interactive (e git commit --patch , che è l’opzione shortcut to patch nel commit interattivo).

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

git gui fornisce questa funzionalità sotto la vista del diff. Basta fare clic con il tasto destro del mouse sulla / e linea / e a cui sei interessato e dovresti vedere una voce di menu “stage this line to commit”.

Credo che git add -e myfile sia il modo più semplice (almeno la mia preferenza) poiché apre semplicemente un editor di testo e ti permette 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 linee che iniziano con “+”. È ansible impedire la messa in scena di eventuali linee di aggiunta eliminandole.

contenuto rimosso:

Il contenuto rimosso è rappresentato da linee che iniziano con “-“. Puoi impedire la messa in scena della loro rimozione convertendo “-” in “” (spazio).

contenuto modificato:

Il contenuto modificato è rappresentato da linee “-” (rimozione del vecchio contenuto) seguito da linee “+” (aggiunta del contenuto sostitutivo). È ansible impedire la gestione temporanea della modifica convertendo “-” linee in “” e rimuovendo le linee “+”. Attenzione che modificare solo la metà della coppia è probabile che introduca cambiamenti confusi all’indice.

Tutti i dettagli su git add sono disponibili su git --help add

Se stai usando vim, potresti provare l’eccellente plugin chiamato fuggitivo .

Puoi vedere il diff di un file tra copia di lavoro e indice con :Gdiff , quindi aggiungi linee o hunk all’indice usando i classici comandi diff di vim come dp . Salva le modifiche nell’indice e :Gcommit commit con :Gcommit e il gioco è fatto.

Screencast introduttivi molto buoni qui (vedi anche parte 2 ).

Consiglio vivamente di utilizzare SourceTree di Atlassian. (È gratuito). Rende questo banale. È ansible mettere in scena singoli pezzi di codice o singole righe di codice in modo rapido e semplice.

inserisci la descrizione dell'immagine qui

Vale la pena notare che per usare git add --patch per un nuovo file è necessario prima aggiungere il file all’indice con git add --intent-to-add :

 git add -N file git add -p file 

Quando ho molte modifiche e finirò per creare alcuni commit dalle modifiche, quindi 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 commettere un errore mentre sto organizzando delle cose, e voglio uno stato impegnato su cui posso ricorrere per un secondo passaggio.

Se si utilizza emacs, dare un’occhiata a Magit , che fornisce un’interfaccia git per emacs. Supporta abbastanza bene gli hunks di staging (parti di file).

Proprio come la risposta di jdsumsion, puoi anche riporre il tuo lavoro corrente, ma poi usare una combinazione di difftool come per estrarre le modifiche selezionate dalla scorta. In questo modo puoi anche modificare manualmente gli hunk in modo molto semplice, il che è un po ‘fastidioso quando in git add -p :

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

L’utilizzo del metodo stash ti dà l’opportunità di testare, se il tuo codice funziona ancora, prima di eseguirlo.

Per coloro che usano Git Extensions :

Nella finestra Commit, seleziona il file che vuoi parzialmente salvare, quindi seleziona il testo che vuoi impegnare nel pannello di destra, quindi fai clic con il pulsante destro del mouse sulla selezione e scegli “Stage selected lines” dal menu di scelta rapida.

Intellij IDEA (e credo che tutti gli altri prodotti della serie) abbiano costruito il supporto per i commit parziali dalla v2018.1

inserisci la descrizione dell'immagine qui

Il plugin vim-gitgutter può mettere in scena gli hunk senza lasciare l’editor di Vim

 :GitGutterStageHunk 

Oltre a questo, fornisce altre interessanti funzionalità come una colonna di segno diff come in alcuni IDE moderni

Se solo una parte del pezzo dovrebbe essere messa in scena vim-fugitive

 :Gdiff 

consente la selezione dell’intervallo visivo, quindi :'<,'>diffput o :'<,'>diffget allo stadio / ripristina le singole variazioni di riga.

Ho provato git add -p filename.x , ma su un mac, ho trovato gitx ( http://gitx.frim.nl/ o https://github.com/pieter/gitx ) per essere molto più facile da impegnare esattamente linee che volevo.

Con TortoiseGit:

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

Per emacs c’è anche gitsum

git-meld-index – quoting dal sito web:

git-meld-index esegue meld – o qualsiasi altro git difftool (kdiff3, diffuse, ecc.) – per consentire di mettere in scena in modo interattivo 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 combinazione è più facile / più rapida da usare rispetto a git add -p. Questo perché la combinazione consente, ad esempio, di:

  • vedere più contesto
  • vedere le differenze intra-line
  • modificare a mano e vedere gli aggiornamenti diff ‘in diretta’ (aggiornati dopo ogni pressione di un tasto)
  • passare a una modifica senza dire “n” ad ogni modifica che si desidera saltare

uso

In un repository git, esegui:

 git meld-index 

Visualizzerai meld (o il tuo gto difftool configurato) con:

A SINISTRA : directory temporanea che conserva i file copiati dal tuo albero di lavoro

A DESTRA : directory temporanea con i contenuti dell’indice. Questo include anche i file che non sono ancora nell’indice ma 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 non è felice. Ricorda di salvare quando necessario.

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

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

o il git add -p filename.txt forma breve git add -p filename.txt

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

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

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

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

L’utilizzo di Atom consente di lavorare con un tema con uno sfondo scuro (per impostazione predefinita, git gui ha uno sfondo bianco).

Aggiungendo una risposta precedente, se preferisci usare la riga di comando, inserire git add -e myfile ti dà la possibilità di scegliere riga per riga ciò che vuoi impegnare perché questo comando aprirà un editor con le differenze, in questo modo:

inserisci la descrizione dell'immagine qui

Come puoi sapere, le righe che iniziano con + sono aggiunte, le righe che iniziano con - sono cancellazioni. Così:

  • Per non aggiungere un’aggiunta basta eliminare quella linea.
  • Per non mettere in scena una cancellazione basta sostituire - con lo spazio .

Questo è ciò che git add -h dice sull’aggiunta di file in questo modo (patching dei file):

contenuto aggiunto Il contenuto aggiunto è rappresentato da linee che iniziano con “+”. È ansible impedire la messa in scena di eventuali linee di aggiunta eliminandole.

contenuto rimosso: il contenuto rimosso è rappresentato da linee che iniziano con “-“. Puoi impedire la messa in scena della loro rimozione convertendo “-” in “” (spazio).

contenuto modificato: il contenuto modificato è rappresentato da linee “-” (rimozione del vecchio contenuto) seguito da linee “+” (aggiunta del contenuto sostitutivo). È ansible impedire la gestione temporanea della modifica convertendo “-” linee in “” e rimuovendo le linee “+”. Attenzione che modificare solo la metà della coppia è probabile che introduca cambiamenti confusi all’indice.

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

Se è su piattaforma Windows , a mio parere git gui è lo strumento migliore per stage in stage / commit poche righe dal file unstaged

1. Hunk wise:

  • Seleziona il file dalla sezione unstagged Changes
  • Pezzo di codice con il tasto destro del mouse che deve essere messo in scena
  • Seleziona Stage Hunk for commit

2. Linea saggio:

  • Seleziona il file dalla sezione unstagged Changes
  • Seleziona la linea / le linee da organizzare
  • Seleziona Stage Lines for commit

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

  • Seleziona il file dalla sezione unstagged Changes
  • Premi Ctrl+T (Stage file to commit)
  • Il file selezionato ora passa alla sezione Staged Changes sistematiche
  • Seleziona la linea / le linee da organizzare
  • Seleziona UnStage Lines for commit

git-cola è una grande interfaccia grafica e ha anche questa funzionalità integrata. Basta selezionare le linee da palcoscenico e premere S. Se non viene effettuata alcuna selezione, viene eseguito il blocco completo.