Posso usar o git diff em arquivos não rastreados?


270

É possível pedir ao git diff que inclua arquivos não rastreados em sua saída diff? Ou é minha melhor aposta para o git adicionar os novos arquivos que eu criei e os arquivos existentes que eu editei e use

git diff --cached

?

Respostas:


267

Nas versões recentes do git, é possível git add -No arquivo (ou --intent-to-add), que adiciona um blob de tamanho zero ao índice nesse local. O resultado é que seu arquivo "não rastreado" agora se torna uma modificação para adicionar todo o conteúdo a esse arquivo de tamanho zero, e isso aparece na saída "git diff".

git diff

echo "this is a new file" > new.txt
git diff

git add -N new.txt
git diff
diff --git a/new.txt b/new.txt
index e69de29..3b2aed8 100644
--- a/new.txt
+++ b/new.txt
@@ -0,0 +1 @@
+this is a new file

Infelizmente, como apontado, você não pode git stashenquanto tiver um --intent-to-addarquivo pendente como este. Embora, se você precisar ocultar, adicione os novos arquivos e os oculte. Ou você pode usar a solução alternativa da emulação:

git update-index --add --cacheinfo \
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 new.txt

(configurar um apelido é seu amigo aqui).


Acontece que minha cópia do Git não é recente o suficiente para adicionar -N, mas isso responde à minha pergunta.
Andrew Grimm

1
Você pode emular "git add -N new.txt" com "git update-index --add --cacheinfo 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 new.txt" (como consegui colocar isso na resposta errada?)
araqnid


1
e se você tiver muitos arquivos novos, existe uma maneira fácil de adicionar todos eles e depois diferenciá-los?
Vic

1
@Vicgit add -N .
Nathan

92

Eu acredito que você pode diferenciar os arquivos no seu índice e nos arquivos não rastreados, simplesmente fornecendo o caminho para os dois arquivos.

git diff --no-index tracked_file untracked_file

3
Isso funciona se você tiver mais de um arquivo não rastreado que você criou desde o último commit?
Andrew Grimm

12
Sim, resposta perfeita! Posso então usar git diff --no-index untracked_file_1 untracked_file_2para obter git diffcores de sintaxe etc. em diffs ... lindas.
Colin D Bennett

40
Não entendo por que você está comparando um arquivo rastreado com um arquivo não rastreado não relacionado. Se você só queria chegar diff saída para o arquivo untracked, você pode apenas usar /dev/nullem vez disso: git diff --no-index -- /dev/null <untracked_file>.

4
Ou apenas cat untracked_file_1, ou talvez printf '\e[1;32m%s\e[0m\n' "$(cat untracked_file_1)"se você realmente precisa de uma saída verde. :) (Embora em uma observação mais séria, observe que a substituição de comandos removerá as novas linhas à direita do seu arquivo.) #
Wildcard

8
Essa deve ser a resposta aceita - não requer alteração do índice do git; que, como o autor original diz, tem seu lado negativo
DIMMSum

38

Para as minhas tarefas interativas do dia-a-dia (onde eu difuso a árvore de trabalho em relação ao HEAD o tempo todo e gostaria de incluir arquivos não rastreados incluídos no diff), add -N/--intent-to-addé inutilizável, porque ele quebra git stash .

Então aqui está o meu git diffsubstituto. Não é uma solução particularmente limpa, mas como eu realmente a uso apenas de maneira interativa, estou bem com um hack:

d() {
    if test "$#" = 0; then
        (
            git diff --color
            git ls-files --others --exclude-standard |
                while read -r i; do git diff --color -- /dev/null "$i"; done
        ) | `git config --get core.pager`
    else
        git diff "$@"
    fi
}

Digitar apenas dincluirá arquivos não rastreados no diff (que é o que mais me interessa no meu fluxo de trabalho) e d args...se comportará como normal git diff.

Notas:

  • Estamos usando aqui o fato de que git diffapenas diferenças individuais são concatenadas, portanto não é possível diferenciar a dsaída de uma "diferença real" - exceto pelo fato de que todos os arquivos não rastreados são classificados por último.
  • O único problema com essa função é que a saída é colorida mesmo quando redirecionada; mas não posso me incomodar em adicionar lógica para isso.
  • Não consegui encontrar nenhuma maneira de incluir arquivos não rastreados apenas montando uma lista de argumentos para git diff. Se alguém descobrir como fazer isso ou se algum recurso for adicionado gitem algum momento no futuro, deixe uma nota aqui!

4
Ironicamente, a minha git update-index --add --cacheinfo 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 new.txtsolução que eu sugeri para gits mais velhos faz o trabalho com git stash, supondo que você já tem e69de29bb na sua db, por exemplo, ao tentar usar add -Nanteriormente. Então, aparentemente, não é exatamente equivalente de git add -Nalguma forma: tbh não sei como.
Araqnid

2
Você está realizando comparação de cadeias em vez de verificação de igualdade numérica com seu testcomando, a propósito. Não deve afetar nada, mas test "$#" -eq 0é mais precisamente o que se pretende.
Curinga

1
Sim, ainda parece que você precisa fazê-lo aos pares ... mas pode falsificá-lo em um, lesspara que você não precise pressionar qpara cada arquivo e pareça exatamente como git diff, removendo a paginação por arquivo ( -P), adicionando-a novamente depois ( | less), preservando a cor ( --color=always) e interpretando-a como cor ( less -rou less -R). Então por completo é:do git -P diff --color=always -- /dev/null "$i"; done | less -r
hyperpallium

Caso você deseje ser incomodado no futuro test -t 1(por exemplo, if [ -t 1 ]; then color_arg=--color; fialgo assim), é uma maneira de o shell verificar se sua saída é um terminal, o que é uma maneira útil de decidir sobre a coloração. E xargspode dar um jeito de se livrar do loop while. Você ainda precisará -n 1disso, por isso ainda lançará o git várias vezes e ainda precisará ser pareado dessa maneira, mas ... ele se livra whilee read, então talvez seja melhor?!? Deixo isso para o leitor.
lindes 12/02

28

Não 100% ao ponto, mas se por algum motivo você não quiser adicionar seus arquivos ao índice, conforme sugerido pela resposta aceita, aqui está outra opção:

Se os arquivos não forem rastreados, obviamente o diff é o arquivo inteiro, então você pode visualizá-los com menos:

less $(git ls-files --others --exclude-standard)

Navegue entre eles com :ne :ppara o próximo e o anterior.

Atualização a partir dos comentários: Se você precisar de um formato de patch, também poderá combiná-lo com git diff:

git ls-files --others --exclude-standard | xargs -n 1 git --no-pager diff /dev/null | less

Você também pode redirecionar a saída para um arquivo ou usar outro comando diff nesse caso.


6
você também pode executar git diff /dev/null <untracked_tile>e obter o patch no formato de remendo, em vez de "apenas" um arquivo
SimSimY

2
esta resposta combinada com o git diff é a solução perfeita.
Iwind 12/04/19

22
git add -A
git diff HEAD

Gere o patch, se necessário, e depois:

git reset HEAD

Isso tem o potencial de perder (antes) trabalho anterior, adicionando tudo. Especialmente no caso de se fazer uso com git add -pmuita frequência (o que eu geralmente recomendo, a propósito) ... Isso dá uma maneira de fazer a coisa básica, apenas ... deve-se notar que ele tem o potencial para o lado indesejado efeitos
lindes 12/02

13

isso funciona para mim:

git add my_file.txt
git diff --cached my_file.txt
git reset my_file.txt

O último passo é opcional, ele deixará o arquivo no estado anterior (não rastreado)

útil se você estiver criando um patch também:

  git diff --cached my_file.txt > my_file-patch.patch

A especificidade desse par de adição / redefinição é um bom contraste com a abordagem da espingarda de stackoverflow.com/a/50486906/313756 ... obrigado por isso.
lindes 12/02

9

As alterações funcionam quando preparadas e não preparadas com este comando. Novos arquivos funcionam quando testados:

$ git diff HEAD

Se eles não forem testados, você verá apenas diferenças de arquivo.


26
HEADé o valor padrão , portanto, é o mesmo git diffque não resolve o problema.
Iulian Onofrei

4
Isso exige git addde cada arquivo não monitorado
SilvioQ

Se você editar esta resposta para incluir o git addque é o mais simples , se seu caso de uso é verificar o que você acabou de adicionar / deseja adicionar
KCD

8

Para um arquivo:

git diff --no-index /dev/null new_file

Para todos os novos arquivos:

for next in $( git ls-files --others --exclude-standard ) ; do git --no-pager diff --no-index /dev/null $next; done;

Como alias:

alias gdnew="for next in \$( git ls-files --others --exclude-standard ) ; do git --no-pager diff --no-index /dev/null \$next; done;"

Para todos os arquivos modificados e novos combinados como um comando:

{ git --no-pager diff; gdnew }

2

Normalmente, quando eu trabalho com equipes de localização remota, é importante para mim que eu tenha conhecimento prévio de quais alterações foram feitas por outras equipes no mesmo arquivo, antes de seguir as etapas git untrack -> staged -> commit para isso, escrevi um script bash que ajude-me a evitar conflitos desnecessários de mesclagem com a equipe remota ou criar uma nova filial local e comparar e mesclar na filial principal

#set -x 
branchname=`git branch | grep -F '*' |  awk '{print $2}'`
echo $branchname
git fetch origin ${branchname}
for file in `git status | grep "modified" | awk "{print $2}" `
do
echo "PLEASE CHECK OUT GIT DIFF FOR "$file 
git difftool FETCH_HEAD $file ;
done

no script acima eu busco o branch principal remoto (não é necessário o branch master) para FETCH_HEAD, faça uma lista apenas do meu arquivo modificado e compare os arquivos modificados com o git difftool

aqui muitos difftool suportados pelo git, eu configuro o 'Meld Diff Viewer' para uma boa comparação da GUI.


-9

Supondo que você não tenha confirmações locais,

git diff origin/master

8
A pergunta pede um git diffcomando que inclua arquivos não rastreados. Este comando não os inclui. Além disso, a existência ou não de confirmações locais não tem absolutamente nada a ver com a questão.
toon81

JFTR, eu git merge --squash mybranche git diff mastermostrei as alterações nos arquivos não rastreados.
Muammar

2
Isso é impossível. Você parece estar confuso sobre o que "não rastreado" significa. Não rastreado não significa que um arquivo é rastreado em uma ramificação e não em outra, significa que não está "no Git" em lugar algum. Quer você esmague ou não, não faz diferença. git diffnão mostra diferenças nos arquivos não rastreados: como eles não são rastreados, nunca há diferenças a serem mostradas, por definição. É assim que o Git funciona. :)
toon81 17/01
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.