Como preparar apenas parte de um novo arquivo com o git?

222

Eu amo o git add --interactive . Agora faz parte do meu fluxo de trabalho diário.

O problema parece que não funciona com arquivos não rastreados. O que eu quero fazer é rastrear um novo arquivo, mas apenas adicionar parte dele, ou seja, algumas partes desse novo arquivo ainda não estão prontas para serem preparadas.

Por exemplo, com o git add -i, eu posso escolher a opção de patch e até editar blocos individuais, a fim de preparar partes do novo código, deixando os comentários do código de depuração em estágios. Adoro trabalhar dessa maneira, porque torna óbvio em que locais do mega patch em que estou trabalhando ainda precisam de trabalho.

Infelizmente, parece que não consigo fazer o mesmo com um arquivo não rastreado. Ou eu preparo o arquivo inteiro, ou nada. A solução alternativa que estou usando é a preparação ou até a confirmação de um novo arquivo quando ele estiver vazio e, em seguida, a realização de alterações individuais da maneira usual. Mas essa solução parece um truque sujo e, quando esqueço, ou mudo de idéia, cria mais problemas do que deveria.

Portanto, a pergunta é: como preparar apenas parte de um novo arquivo, para que esse novo arquivo seja rastreado, mas deixando o todo ou parte do seu conteúdo sem palco?

agosto
fonte

Respostas:

415

Whoa, tudo isso update-indexe os hash-objectnegócios parecem excessivamente complicados. Que tal isso:

git add -N new_file
git add -i

De git help add:

-N, --intent-to-add
    Record only the fact that the path will be added later.  An entry
    for the path is placed in the index with no content.  This is useful
    for, among other things, showing the unstaged content of such files
    with git diff and committing them with git commit -a.
Richard Hansen
fonte
9
++ 1! crédito devido. Eu confio um pouco demais que eu sei que estes manpages por agora ....</shame>
sehe
1
Bem encontrado. Eu deveria ter rolado a página de manual um pouco mais. Talvez eu devesse devolver o crachá do Git Pro.
dave1010
3
Pergunto-me por que o git-gui não usa isso internamente para conseguir criar linhas de um novo arquivo.
Deiwin #
6
-NDescoberta maravilhosa , obrigado! Embora eu prefira combiná-lo -pnesse caso. gid add -N the_file& git add -p. Deve-se acrescentar que -Ntambém funciona com-A
Cyril CHAPON 25/08/2015
@Deiwin - você pode adicionar um [guitool] ao seu .gitconfig para fazer um "git add -N $ FILENAME": [guitool "Adicionar com intenção"] cmd = "git add -N $ FILENAME" needsfile = yes noconsole = yes
Steve Folly
7

A maneira mais fácil de fazer isso (e imho teste interativo em geral) é git gui. Ele vem com o git e deve funcionar em quase todas as plataformas suportadas pelo git.

Basta executar git guie uma interface gráfica do usuário será aberta, permitindo blocos de teste e de teste e até linhas únicas de arquivos rastreados e não rastreados.

Captura de tela de Git Gui

Chronial
fonte
Essa é uma resposta criativa e, às vezes, é muito, muito útil.
Pablo Olmos de Aguilera C.
3
Apenas uma observação que nem todas as distribuições git incluem git gui. No Debian, por exemplo, ele está em um pacote separado chamado 'git-gui'.
Cristoper
Foram à procura (o suficiente para não dura) para esse recurso há anos, este é um trocador de vida
austinmarton
2
Para mim, a preparação de linhas únicas de arquivos não rastreados git guinunca funcionou. Na verdade, desativa essas opções de menu .
Deiwin
2
@Deiwin Devo ter esquecido isso na pergunta - minha captura de tela mostra um arquivo já rastreado. Se você deseja usar git guipara um novo arquivo, é necessário executar git add -N new_fileprimeiro - consulte a resposta de Richard Hansen.
Cronial
6
git update-index --add --cacheinfo 100644 $(git hash-object -w /dev/null) newfile
git add --interactive newfile

Demonstração simples:

mkdir /tmp/demo
cd /tmp/demo
git init .

echo hello > newfile
git update-index --add --cacheinfo 100644 $(git hash-object -w /dev/null) newfile
  • Dica Se você tem certeza de que o blob 'vazio' já existe no seu banco de dados de objetos git, você pode codificar o hash e69de29bb2d1d6434b8b29ae775ad8c2e48c5391. Eu não recomendo fazer isso_
  • Dica Se você estiver no Windows, provavelmente poderá usar apenas em NUL:vez de /dev/null. Caso contrário, use algo comoecho -n '' | git hash-object --stdin -w

Agora, o índice conterá newfilecomo o blob vazio e o blob vazio foi inserido no banco de dados do objeto se ainda não existia:

$ find .git/objects/ -type f 
.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391

$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#   new file:   newfile
#
# 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:   newfile
#

$ git diff
diff --git a/newfile b/newfile
index e69de29..ce01362 100644
--- a/newfile
+++ b/newfile
@@ -0,0 +1 @@
+hello

Isso deve ser exatamente o que você deseja. Também posso recomendar o plugin fugitivo vim para gerenciamento de índice muito inteligente (consulte Better git add -p? )

ver
fonte
1
Isso parece funcionar bem. Eu o aliei para "arquivo vazio de palco", pois é um pouco complexo de se lembrar.
dave1010
@ dave1010: Fico feliz que ajudou! Sim, pensei em adicionar um alias, mas não sabia como você esperaria lidar, por exemplo, caracteres curinga ou vários argumentos de nome de arquivo em geral. Então optei por não ver
sehe,
2

Edit: isso não parece estar funcionando agora. Tenho certeza de que era antes (no git 1.7.1). Caso isso não funcione, sugiro a preparação, /dev/nullcomo sugere acima:

git update-index --add --cacheinfo 100644 $(git hash-object -w /dev/null) newfile

Se você estiver no Windows (sem /dev/null), poderá substituí-lo pelo caminho para um arquivo vazio.

Resposta original

Você quer

git add -p # (or --patch)

Isso adiciona arquivos não rastreados para mim. Na página do manual:

Escolha interativamente pedaços de patch entre o índice e a árvore de trabalho e adicione-os ao índice. Isso permite ao usuário revisar a diferença antes de adicionar conteúdo modificado ao índice.

Isso efetivamente executa add --interactive, mas ignora o menu de comando inicial e salta diretamente para o subcomando do patch. Consulte "Modo interativo" para obter detalhes.

dave1010
fonte
2
Por mais interessante que isso não funcione para mim (git 1.7.4); git add -p newfilenão funciona (efeito nu) e git add --interactive'[a] dd untracked' tem o efeito que git add newfiletem; Editar também verificado com git 1.7.5.3; Não há dados
sehe
Boa dica para o Windows, dicas adicionadas para isso na minha resposta. Thx
consulte
-2

Só para registrar uma outra possibilidade: eu uso

git add -N file
git add -p file

E então você pode montar pedaços ou editá-los no lugar.

Pedro Adame Vergara
fonte
1
Esta resposta diz o mesmo que a resposta aceita, que remonta a 2011. Voto a favor.
Stanislav Pankevich
A resposta aceita combina add -Ncom add -i. Acabei de adicionar isso em add -pvez de add -ifuncionar também.
Pedro Adame Vergara