Confirmar apenas parte de um arquivo no Git

2765

Quando faço alterações em um arquivo no Git, como posso confirmar apenas algumas delas?

Por exemplo, como eu poderia confirmar apenas 15 das 30 linhas que foram alteradas em um arquivo?

freddiefujiwara
fonte
3
stackoverflow.com/q/34609924/52074 relacionado : se você precisar dividir um pedaço em pedaços menores.
Trevor Boyd Smith
Resumo: em termos de capacidade: git gui= git add -e> git add -i -p; em termos de conveniência: git gui> git add -i -p> git add -e. Assim: escolher git guiquando você tem acesso a X. escolher git add -i -ppara coisas simples e quando você não tem ou quer usar X. git add -epara estadiamento complexo sem X.
Penghe Geng

Respostas:

3688

Você pode usar git add --patch <filename>(ou -pabreviar), e o git começará a dividir seu arquivo no que ele considera sensatos "pedaços" (partes do arquivo). Em seguida, ele será solicitado com esta pergunta:

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

Aqui está uma descrição de cada opção:

  • y encenar esse pedaço para o próximo commit
  • n não prepare esse pedaço para o próximo commit
  • qSair; não encene este pedaço ou qualquer um dos pedaços restantes
  • a encenar este pedaço e tudo mais tarde pedaços no arquivo
  • d não encene este pedaço ou qualquer um dos pedaços posteriores no arquivo
  • g selecione um pedaço para ir para
  • / procure um pedaço que corresponda ao regex especificado
  • j deixe esse pedaço indeciso, veja o próximo pedaço indeciso
  • J deixe esse pedaço indeciso, veja o próximo pedaço
  • k deixe esse pedaço indeciso, veja o pedaço indeciso anterior
  • K deixe esse pedaço indeciso, veja o pedaço anterior
  • s dividir o pedaço atual em pedaços menores
  • e editar manualmente o pedaço atual
  • ? ajuda do pedaço de impressão

Se o arquivo ainda não estiver no repositório, você poderá fazê-lo git add -N <filename>. Depois você pode continuar git add -p <filename>.

Depois, você pode usar:

  • git diff --staged para verificar se você efetuou as alterações corretas
  • git reset -p para desfilar porções adicionadas por engano
  • git commit -v para visualizar sua confirmação enquanto você edita a mensagem de confirmação.

Observe que isso é muito diferente do git format-patchcomando, cujo objetivo é analisar dados de confirmação em .patcharquivos.

Referência para o futuro: Git Tools - Interativo

mac
fonte
83
Pode ser útil observar que -p/--patché um atalho para a ação do patch dentro do -i/--interactivecomando que inicia o modo interativo útil .
TutuDajuju
5
> O que acontece se esse arquivo já estiver preparado? Ele mostrará apenas alterações não estágios. O mesmo que git difffaz.
Eugen Konkov 3/15
3
Como posso editar o pedaço atual manualmente? Não sei o que fazer depois de digitar e.
Hunsu
23
Depois de pressionar e, você pode editar o galã manualmente, substituindo +ou -por#
veksen
1
isso é ótimo, mas agora como faço para empurrá-lo? se eu fizer git pushisso já está atualizado. e se git diffeu vejo os pedaços que eu disse n. se git diff --stagedeu vejo o commit que quero enviar. Supondo que eu possa enviar por push o commit, como excluo os pedaços que eu disse no?
Chovy
250

Você pode usar git add --interactiveor , e então ( not ); consulte Modo interativo na página de manual git-add , ou simplesmente siga as instruções.git add -p <file>git commit git commit -a

O Modern Git também possui git commit --interactive(e git commit --patch, que é um atalho para corrigir a opção no commit interativo).

Se você preferir fazê-lo a partir da GUI, pode usar o git-gui . Você pode simplesmente marcar os pedaços que deseja incluir no commit. Pessoalmente, acho mais fácil do que usar git add -i. Outras GUIs do git, como QGit ou GitX, também podem ter essa funcionalidade.

Jakub Narębski
fonte
1
Curiosamente, windows.github.com apoio tinha de commits arquivo parcial, mas parece ter caído recentemente ..
Juri
1
@Juri Eu acho que o suporte para commits arquivo parcial está de volta.
Ela782
@Juri De nada. Na verdade, eu nunca notei que ele estava lá antes - eu o vi na semana passada e pensei "oh, que novo recurso incrível"! :-)
Ela782
1
Atualmente, o windows.github.com redireciona para o GitHub Desktop renomeado, que é mais agradável que a GUI do Git e suporta confirmações parciais ... mas não suporta assinatura de confirmação. Suspiro.
147

O git gui fornece essa funcionalidade sob a visualização diff. Basta clicar com o botão direito do mouse nas linhas em que você está interessado e você verá um item de menu "encene esta linha para confirmar".

Ionuț G. Stan
fonte
13
para patches complexos, essa geralmente é a abordagem mais rápida para mim.
hochl
7
Essa é uma maneira muito eficiente e intuitiva de adicionar alterações na área de preparação de maneira minuciosa. Também várias linhas podem ser selecionadas e todas as alterações nessa seleção serão adicionadas.
jox
Observe que não gitk, mas ele está incluído no Git Bash for Windows; você deve ter uma entrada de menu Iniciar para ele ou pode iniciá-lo com o comando git gui. Há também o stage this hunkque provavelmente é mais útil que stage this line. Pode ser novo, já que esta resposta foi criada há 10 anos.
26419 Chris
82

Acredito que essa git add -e myfileé a maneira mais fácil (pelo menos de minha preferência), pois ela simplesmente abre um editor de texto e permite que você escolha qual linha deseja exibir e qual não deseja. Em relação aos comandos de edição:

conteúdo adicionado:

O conteúdo adicionado é representado por linhas começando com "+". Você pode impedir o preparo de qualquer linha de adição excluindo-as.

conteúdo removido:

O conteúdo removido é representado por linhas que começam com "-". Você pode impedir a preparação da remoção convertendo o "-" para um "" (espaço).

conteúdo modificado:

O conteúdo modificado é representado pelas linhas "-" (removendo o conteúdo antigo), seguidas pelas linhas "+" (adicionando o conteúdo de substituição). Você pode impedir o preparo da modificação convertendo as linhas "-" para "" e removendo as linhas "+". Lembre-se de que modificar apenas metade do par provavelmente introduzirá mudanças confusas no índice.

Todos os detalhes sobre git addestão disponíveis emgit --help add

theFreedomBanana
fonte
7
Isso seria mais útil se houvesse uma explicação clara em algum lugar sobre como realmente escolher essas linhas (ou seja, os comandos reais a serem inseridos). Não consegui encontrar um na documentação. Você poderia adicionar uma referência?
Alex
4
Para quem não gosta de opções de taquigrafia, -eé --edit.
Kolyunya
2
@Alex As citações de referência adicionadas por theFreedomBanana são da seção EDITANDO PATCHES ingit --help add
Randall
8
Esta é a única resposta (exigindo apenas o git) que resolve o problema de adicionar / remover linhas de maneira sábia quando você não pode reduzir os pedaços com o smodo de patch interativo.
precisa saber é o seguinte
3
Pode ser útil entender que este comando ( git add -e) * não * altera o conteúdo do arquivo no disco. Ele apenas move parte das alterações de não faseado para faseado (índice).
Penghe Geng 5/07/19
44

Se você estiver usando o vim, experimente o excelente plugin chamado fugitivo .

Você pode ver o diff de um arquivo entre a cópia de trabalho e o índice com :Gdiffe, em seguida, adicionar linhas ou blocos ao índice usando comandos clássicos do vim diff como dp. Salve as modificações no índice e confirme :Gcommit, e pronto.

Muito bons screencasts introdutórios aqui (ver esp. Parte 2 ).

François
fonte
Muito obrigado por esses links. Exatamente o mesmo que eu preciso. Especialmente :diffget/:diffputno modo visual, onde posso escolher linhas específicas, as quais quero redefinir / confirmar. Portanto, verifique novamente: o vim é incrível.
28615 goodniceweb
30

Eu recomendaria fortemente o uso do SourceTree da Atlassian. (É grátis.) Isso é trivial. Você pode organizar blocos de código individuais ou linhas de código individuais de maneira rápida e fácil.

insira a descrição da imagem aqui

Bob Stein
fonte
1
Concordo que o SourceTree é uma boa ferramenta para esse fim, porque oferece um controle mais refinado do que é possível através da linha de comando.
19
@cupcake Eu diria o contrário, visto que o SourceTree provavelmente usa os executáveis ​​git da linha de comando; por natureza, sempre será possível fazer as mesmas (ou mais) ações refinadas através da "linha de comando".
tutuDajuju
2
Independentemente do granulado-fino argumento Eu recomendo SourceTree como pedaços de paragem e linhas individuais é super fácil: i.imgur.com/85bNu4C.png
Mars Robertson
1
@tutuDajuju Nesse caso, não tenho certeza se isso é verdade. O SourceTree tem a capacidade de escolher quais partes o estágio será linha por linha . Você não precisa montar um pedaço inteiro; você pode colocar 2 linhas no meio de um pedaço. Eu não tenho idéia de como isso acontece, no entanto. (No momento, estou tentando solucionar a incapacidade do SourceTree de preparar linhas específicas para um arquivo não rastreado. Cheguei aqui procurando uma solução alternativa, apenas para descobrir que o git aparentemente não parece oferecer a capacidade linha por linha . Pelo menos não de uma maneira direta.)
jpmc26 11/11/2015
1
@ Sun, você pode clicar na linha 50 e deslocar + clique na linha 100 e depois no estágio. Você pode facilmente Stage Line 50-100 em Sourcetree :)
ryan123
26

Vale ressaltar que, para usar git add --patchem um novo arquivo, você precisa primeiro adicionar o arquivo ao índice com git add --intent-to-add:

git add -N file
git add -p file
user1338062
fonte
23

Quando tenho muitas alterações e acabo criando algumas confirmações, quero salvar meu ponto de partida temporariamente antes de preparar as coisas.

Como isso:

$ 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

A resposta de Whymarrh é o que eu costumo fazer, exceto que às vezes há muitas mudanças e posso dizer que posso cometer um erro ao encenar as coisas, e quero um estado comprometido no qual possa recorrer para uma segunda passagem.

jdsumsion
fonte
12

Se você usa o emacs, dê uma olhada no Magit , que fornece uma interface git para o emacs. Ele suporta blocos de teste (partes de arquivos) muito bem.

Mark van Lent
fonte
Frequentemente tropeço em um comando git que deseja abrir um editor, quando o executo a partir de uma janela shell do Mx. O magit intercepta essa loucura e abre apenas um novo buffer para isso? (por favor, não há dicas de background-emacs-daemon; obrigado de qualquer maneira, mas a vida é muito curta).
User2066657
Não, até onde sei, não intercepta isso. Mas não aceite minha palavra porque (1) quase nunca uso a janela do shell no Emacs e (2) normalmente uso o emacsclient. Dito isto, se o emacsclient é uma opção para você, isso impediu pelo menos uma janela adicional com o emacs e o buffer "COMMIT_EDITMSG" foi aberto na minha janela existente do Emacs.
Mark van Lent
10

A Intellij IDEA (e acho que todos os outros produtos da série) tem suporte para confirmações parciais desde a v2018.1

insira a descrição da imagem aqui

Holger Brandl
fonte
9

Para quem usa extensões Git :

Na janela Confirmar, selecione o arquivo que deseja confirmar parcialmente, depois selecione o texto que deseja confirmar no painel direito, clique com o botão direito do mouse na seleção e escolha 'Preparar linhas selecionadas' no menu de contexto.

srgstm
fonte
2
O atalho de teclado no Git Extensions para 'Stage selected lines' é s- muito útil para preparar rapidamente partes de arquivos para uma confirmação.
Alchemistmatt
8

Muito parecido com a resposta da jdsumsion, você também pode esconder seu trabalho atual, mas depois usar um difftool como meld para extrair as alterações selecionadas do esconderijo. Dessa forma, você pode editar os blocos manualmente muito facilmente, o que é um pouco trabalhoso quando git add -p:

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

O uso do método stash oferece a você a oportunidade de testar, se seu código ainda funcionar, antes de enviá-lo.

derhoch
fonte
isso funciona bem, mas se você usar git commit --amend, parece que não poderá colocar o estoque posteriormente ou existe uma maneira de fazer isso?
Mark
7

Adicionando uma resposta anterior, se você preferir usar a linha de comando, digitar git add -e myfileoferece a opção de escolher linha por linha o que você deseja confirmar, porque esse comando abrirá um editor com as diferenças, assim:

insira a descrição da imagem aqui

Como você pode saber, as linhas que começam com +são adições, as linhas que começam com -são exclusões. Assim:

  • Para não encenar uma adição, exclua essa linha.
  • Para não realizar uma exclusão, basta substituir -por espaço .

É o que git add -hdiz sobre a adição de arquivos desta maneira (patching files):

conteúdo adicionado O conteúdo adicionado é representado por linhas começando com "+". Você pode impedir o preparo de qualquer linha de adição excluindo-as.

conteúdo removido: o conteúdo removido é representado por linhas que começam com "-". Você pode impedir a preparação da remoção convertendo o "-" para um "" (espaço).

conteúdo modificado: o conteúdo modificado é representado por linhas "-" (removendo o conteúdo antigo) seguido por linhas "+" (adicionando o conteúdo de substituição). Você pode impedir o preparo da modificação convertendo as linhas "-" para "" e removendo as linhas "+". Lembre-se de que modificar apenas metade do par provavelmente introduzirá mudanças confusas no índice.

Cuidado: não altere o conteúdo do arquivo, este não é um bom lugar para fazê-lo. Basta alterar os operadores de linhas excluídas ou adicionadas.

Beto Aveiga
fonte
Qual resposta anterior? As respostas são armazenadas com base no número de pontos que eles têm. Portanto, sua resposta está em um lugar diferente agora do que quando você a escreveu, em comparação com outras respostas.
KulaGGin 5/01
Eu acredito que a resposta referenciada é de @theFreedomBanana
K. Symbol
6

O plugin vim-gitgutter pode encenar pedaços sem sair do editor vim usando

:GitGutterStageHunk

Além disso, ele fornece outros recursos interessantes, como uma coluna de sinal diff, como em alguns IDEs modernos

Se apenas parte do pedaço deve ser encenada por vim-fugitivo

:Gdiff

permite a seleção visual da faixa :'<,'>diffputou :'<,'>diffgetpara preparar / reverter as alterações de linha individuais.

c0ffeeartc
fonte
4

Com o TortoiseGit:

clique com o botão direito do mouse no arquivo e use-o Context Menu → Restore after commit. Isso criará uma cópia do arquivo como está. Depois, você pode editar o arquivo, por exemplo, no TortoiseGitMerge e desfazer todas as alterações que você não deseja confirmar. Depois de salvar essas alterações, você pode confirmar o arquivo.

Fr0sT
fonte
4

Faz dez anos desde que essa pergunta foi feita. E espero que esta resposta seja útil para alguém. Como mencionado na resposta aqui , onde a GUI não é uma opção, a extensão de crecord de Andrew Shadura ajuda a trazer uma janela ncurses na qual podemos selecionar as linhas a serem confirmadas.

Configure a extensão da seguinte maneira:

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

cd ao seu repositório git e invoque-o da seguinte maneira:

git crecord

Isso abriria a interface ncurses, que pode ser usada como mostrado abaixo. Pressionar as seguintes teclas na janela ncurses executará determinadas ações:

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 mostrando um exemplo de usoExemplo

Uma corrida
fonte
3

Para usuários Atom , o pacote github inclui teste interativo, no estilo de git gui. Para atalhos, consulte a documentação do pacote .

O uso do Atom permite trabalhar com um tema com fundo escuro (por padrão, git guicom fundo branco).

Ioannis Filippidis
fonte
2

git-meld-index - citando no site:

O git-meld-index executa o meld - ou qualquer outro gto difftool (kdiff3, difuso etc.) - para permitir a interação interativa de alterações no índice git (também conhecido como área de preparação do git).

Isso é semelhante à funcionalidade do git add -p e git add --interactive. Em alguns casos, o meld é mais fácil / rápido de usar do que o git add -p. Isso porque o meld permite, por exemplo:

  • veja mais contexto
  • veja diferenças intra-linha
  • edite manualmente e veja as atualizações de diferenças 'ao vivo' (atualizadas após cada pressionamento de tecla)
  • navegue até uma alteração sem dizer 'n' a cada alteração que você deseja pular

Uso

Em um repositório git, execute:

git meld-index

Você verá o meld (ou o seu git difftool configurado) aparecer com:

ESQUERDA : arquivos temporários de continuação de diretório copiados da sua árvore de trabalho

DIREITO : diretório temporário com o conteúdo do índice. Isso também inclui arquivos que ainda não estão no índice, mas são modificados ou não rastreados na cópia de trabalho - nesse caso, você verá o conteúdo do arquivo HEAD.

Edite o índice (lado direito) até ficar feliz. Lembre-se de salvar quando necessário.

Quando terminar, feche o meld e o git-meld-index atualizará o índice para corresponder ao conteúdo do diretório temporário no lado direito do meld que você acabou de editar.

Croad Langshan
fonte
2

Se estiver na Windowsplataforma, na minha opinião git guié uma ferramenta muito boa para stage/ commitpoucas linhas do unstagedarquivo

1. Hunk wise:

  • Selecione o arquivo da unstagged Changesseção
  • Clique com o botão direito do mouse em um pedaço de código que precisa ser preparado
  • Selecione Stage Hunk for commit

2. Linha sábia:

  • Selecione o arquivo da unstagged Changesseção
  • Selecione a linha / linhas a serem preparadas
  • Clique com o botão direito e selecione Stage Lines for commit

3. Se você deseja preparar o arquivo completo, exceto algumas linhas:

  • Selecione o arquivo da unstagged Changesseção
  • pressione Ctrl+T (Stage file to commit)
  • O arquivo selecionado agora se move para a Staged ChangesSeção
  • Selecione a linha / linhas a serem preparadas
  • Clique com o botão direito e selecione UnStage Lines for commit
Anvesh Yalamarthy
fonte
1

Como mostra uma resposta acima, você pode usar git add --patch filename.txt

ou a forma abreviada git add -p filename.txt

... mas para os arquivos que já estão no seu repositório, é muito melhor usar s - usando o sinalizador --patch no comando commit diretamente (se você estiver usando uma versão recente do git): git commit --patch filename.txt

... ou, novamente, a forma abreviada git commit -p filename.txt

... e, em seguida, usando as chaves mencionadas (y / n etc), para escolher as linhas a serem incluídas no commit.

Samuel Lampa
fonte
O que isso lhe dá além de " git add -p filename.txt" menos espaço para erro? Se você estragar a alteração parcial do arquivo, desfazer uma adição é melhor do que desfazer uma confirmação.
precisa saber é o seguinte
Não sei por que, mas quando digo 'n' a linha é incluída ... e quando digo 'y' no segundo pedaço, ela também é incluída.
Chovy
1

O git-cola é uma ótima interface gráfica e também possui esse recurso. Basta selecionar as linhas para encenar e pressionar S. Se nenhuma seleção for feita, o pedaço completo é preparado.

AndiDog
fonte