Adicione apenas alterações que não sejam de espaço em branco

343

Eu tenho meu editor de texto para aparar automaticamente os espaços em branco finais ao salvar um arquivo e estou contribuindo para um projeto de código aberto que tem sérios problemas com os espaços em branco finais.

Sempre que tento enviar um patch, devo primeiro ignorar todas as alterações somente de espaço em branco manualmente, para escolher apenas as informações relevantes. Não apenas isso, mas quando corro git rebase, geralmente encontro vários problemas por causa deles.

Como tal, eu gostaria de poder adicionar ao índice apenas alterações que não sejam espaços em branco, de uma maneira semelhante a git add -pisso, mas sem ter que escolher todas as alterações sozinho.

Alguém sabe como fazer isso?

Edição: Eu não posso mudar a maneira como o projeto funciona, e eles decidiram, depois de discuti-lo na lista de discussão, ignorar isso.

Edu Felipe
fonte

Respostas:

395

A solução @Frew não era exatamente o que eu precisava, então esse é o alias que fiz para o mesmo problema:

alias.addnw=!sh -c 'git diff -U0 -w --no-color "$@" | git apply --cached --ignore-whitespace --unidiff-zero -'

Ou você pode simplesmente executar:

git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero -

Atualizar

Foram adicionadas opções -U0e, --unidiff-zerorespectivamente, para solucionar problemas de correspondência de contexto, de acordo com este comentário .

Basicamente, ele aplica o patch que seria aplicado addsem alterações de espaço em branco. Você notará que, depois de uma git addnw your/filemudança ainda em etapas, ainda restam os espaços em branco.

O --no-color não é obrigatório, mas como tenho cores definidas para sempre, tenho que usá-lo. Enfim, é melhor prevenir do que remediar.

Colin Hebert
fonte
7
Isso funcionou bem para mim, no entanto, tive que usar git apply --ignore-whitespacecaso contrário, o patch não se aplicaria por razões óbvias.
jupp0r
106
Realmente deveria haver uma opção para o git add, assim git add -wfez isso.
21414 Jarl
7
Isso me dá problemas patch does not applye error while searching for... Alguma idéia?
DTI-Matt
18
não funcionou para mim. Ocorreu um patch does not applyerro.
Jerry Saravia
13
Se você está recebendo 'remendo falhou' devido ao espaço em branco no contexto como pontos @bronson, este comando funciona revisto (Gera um patch sem contexto): git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero. Isso não é arriscado, porque o índice já está o mais atualizado possível, por isso é uma base confiável para o patch.
void.pointer
36

Isso funciona para mim:

Se você quiser manter um estoque, isso funciona

git stash && git stash apply && git diff -w > foo.patch && git checkout . && git apply foo.patch && rm foo.patch

Eu não gosto do esconderijos, mas eu correr em um bug no git + cygwin onde eu perder as alterações, de modo a certificar-se de que o material foi para a reflog pelo menos eu configurar o seguinte:

git add . && git commit -am 'tmp' && git reset HEAD^ && git diff -w > foo.patch && git checkout . && git apply foo.patch && rm foo.patch

Basicamente, criamos um diff que não inclui as alterações de espaço, revertemos todas as alterações e depois aplicamos o diff.

Frew Schmidt
fonte
11
+1. Você pode fazer um git stashcheck-out em vez de fazer um backup das suas alterações, pelo menos até que sejam testadas.
Paŭlo Ebermann
11
Você vai acabar com muitos esconderijos e basicamente não precisa fazer tudo isso. Ele funciona, mas eu acho que é um pouco confuso
Colin Hebert
3
Eu concordo com o Colin. Se o script funcionar, não será necessário criar uma ocultação. O que pode ser bom considerar, porém, seria executar o stash e, em seguida, o stash pop. Os stashes popped podem ser recuperados, se necessário, mas você não terá muitos stashes caso contrário. Isso também deixa um arquivo extra em torno de mentir
Casebash
Que tal pular arquivos binários? Ao tentar aplicar o trecho acima, recebo erros que o patch não pode ser aplicado sem a linha de índice completa! O que me impressiona é que nem sequer toquei nesses arquivos / binários!
precisa saber é o seguinte
11
Eu acho que no final do primeiro comando "git rm foo.patch" deveria ser apenas "rm foo.patch". Caso contrário, muito útil obrigado.
Jack Casey
33

Crie um arquivo de correção contendo apenas as alterações reais (excluindo linhas com apenas alterações de espaço em branco), limpe sua área de trabalho e aplique esse arquivo de correção:

git diff> backup
git diff -w> altera
git reset --hard
patch <alterações

Avaliar as diferenças remanescentes, em seguida, adde commitcomo normal.

O equivalente ao Mercurial é fazer o seguinte:

hg diff> backup
hg diff -w> altera o
hg revert --todos
hg import --não confirma alterações

Steve Pitchers
fonte
O que é uma pergunta "protegida"? e eu também responde. Eu não acho que isso ainda se qualifica como uma me muito resposta, porque parece que a questão foi puxado fora do ar ...
JWW
4
@jww O núcleo da pergunta do pôster original é "como evitar cometer alterações de espaço em branco apenas no controle de origem". Por acaso, o OP está usando o Git, mas isso também se aplica a todos os sistemas de controle de origem que já usei. Esta resposta mostra o procedimento correto se alguém estiver usando o Mercurial. Eu poderia imaginar alguém pode também contribuir com uma solução para as pessoas usando Sublesion, etc.
Steve jarros
11
@jww e @ pagid: editei minha resposta para abordar especificamente o Git, usando a mesma abordagem da minha solução para o Mercurial. Na minha opinião, o StackOverflow é mais do que apenas outro fórum de perguntas e respostas - ele também tem um papel como repositório de conhecimento. Pessoas que não sejam o pôster original podem se beneficiar das respostas dadas, e suas circunstâncias variam. É por isso que acredito que as respostas que transmitem um princípio geral são válidas, em vez de direcionar apenas uma única situação específica.
Steve jarros
@Steve - " Editei minha resposta para abordar especificamente o Git ..." - por que você não fez uma nova pergunta no contexto mercurial e depois adicionou sua própria resposta à nova pergunta ???
jww 24/07
8
Esta é realmente a mais limpa, mais compreensível e mais inquebrável das abordagens que já vi.
Kzqai
12

A resposta mais votada não funciona em todos os casos, devido ao espaço em branco no contexto do patch, de acordo com os usuários nos comentários.

Revisei o comando da seguinte maneira:

$ git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero

Isso gera um patch sem contexto. Não deve ser um problema, pois o patch tem vida curta.

Alias ​​correspondente, novamente uma revisão do que já foi fornecido por outros usuários:

addw = !sh -c 'git diff -U0 -w --no-color "$@" | git apply --cached --ignore-whitespace --unidiff-zero' -
void.pointer
fonte
Para ignorar apenas as alterações de recuo, tive que usar em --ignore-space-changevez de -w. git diff -U0 --ignore-space-change --no-color | git apply --cached --unidiff-zero
21716 Andy
Uma palavra de advertência para não usar esse adorável truque sem contexto; caso --ignore-blank-linescontrário, você encontrará trechos de diferenças sendo corrigidos com deslocamentos incorretos se parte do 'espaço em branco' que você deseja ignorar for remoções / adições de linhas vazias.
Elbeardmorez
12

Adicione o seguinte ao seu .gitconfig:

anw = !git diff -U0 -w --no-color -- \"$@\" | git apply --cached --ignore-whitespace --unidiff-zero "#"

Obrigado à resposta de @Colin Herbert pela inspiração.

Explicação da sintaxe

A final #deve ser citada para que não seja tratada como um comentário dentro do .gitconfig, mas é repassada e tratada como um comentário dentro do shell - ela é inserida entre o final dos git applyargumentos fornecidos pelo usuário e os que são gitcolocados automaticamente no final da linha de comando. Esses argumentos não são desejados aqui - não queremos git applyconsumi-los, portanto, o caractere de comentário anterior. Você pode querer executar este comando GIT_TRACE=1 git anwpara ver isso em ação.

O --sinal termina nos argumentos e permite que você tenha um arquivo nomeado -wou algo que se pareça com uma opção para git diff.

Aspas duplas escapadas $@são necessárias para preservar todos os argumentos citados fornecidos pelo usuário. Se o "personagem não for escapado, ele será consumido pelo .gitconfiganalisador e não alcançará o shell.

Nota: .gitconfigapelido de análise não reconhece aspas simples como nada de especial - seus apenas caracteres especiais são ", \, \n, e ;(fora de uma "corda -quoted). É por isso que um "sempre deve ser escapado, mesmo que pareça estar dentro de uma string de aspas simples (sobre a qual o git é completamente independente).

Isso é importante, por exemplo. se você tiver um alias útil para executar um bashcomando na raiz da árvore de trabalho. A formulação incorreta é:

sh = !bash -c '"$@"' -

Enquanto o correto é:

sh = !bash -c '\"$@\"' -
Tom Hale
fonte
Excelente. Isso me permitiu adicionar um arquivo por vez. Além de adicionar um diretório raiz para um argumento, existe uma maneira de fazer isso funcionar como 'git add -A'?
Chucky
7

Que tal o seguinte:

git add `git diff -w --ignore-submodules |grep "^[+][+][+]" |cut -c7-`

O comando dentro de aspas recebe os nomes dos arquivos que possuem alterações que não são de espaço em branco.

karmakaze
fonte
2
ou apenas git add `git diff -w |grep '^+++' |cut -c7-`se submódulos não utilizado
karmakaze
-1

Você deve primeiro considerar se o espaço em branco à direita é intencional. Muitos projetos, incluindo o kernel do Linux, Mozilla, Drupal e Kerberos (para citar alguns da página da Wikipedia em grande estilo) proíbem o espaço em branco à direita. Na documentação do kernel do Linux:

Obtenha um editor decente e não deixe espaços em branco no final das linhas.

No seu caso, o problema é o contrário: confirmações anteriores (e talvez atuais) não seguiram essa diretriz.

Aposto que ninguém realmente quer o espaço em branco à direita, e corrigir o problema pode ser uma mudança bem-vinda. Outros usuários também podem estar enfrentando o mesmo problema que você. Também é provável que os colaboradores que estão adicionando espaço em branco à direita não tenham consciência de que estão fazendo isso.

Em vez de tentar reconfigurar o git para ignorar o problema ou desativar a funcionalidade desejável no seu editor, eu começaria com uma postagem na lista de discussão do projeto que explica o problema. Muitos editores (e o próprio git) podem ser configurados para lidar com o espaço em branco à direita.

Kevin Vermeer
fonte
16
Não é intencional, mas não posso mudar a maneira como pensam mais de 100 pessoas que contribuem com o projeto. Eles não se importam e não aceitam patches com mais de 1000 alterações, que tratam apenas do espaço em branco à direita. Eles conhecem o problema e decidiram ignorá-lo. Essa discussão já aconteceu na lista e foi encerrada. Nesse caso, sou eu quem precisa se adaptar a eles.
Edu Felipe
19
Em seguida, configure seu editor de forma que não apare os espaços em branco finais ao trabalhar no código deste projeto.
jamessan
-2

Encontrei um gancho de pré-confirmação do git que remove os espaços em branco à direita . No entanto, se você não conseguir que outras pessoas usem isso, talvez não seja uma solução válida.

  #!/bin/sh

  if git-rev-parse --verify HEAD >/dev/null 2>&1 ; then
     against=HEAD
  else
     # Initial commit: diff against an empty tree object
     against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
  fi
  # Find files with trailing whitespace
  for FILE in `exec git diff-index --check --cached $against -- | sed '/^[+-]/d' | sed -r 's/:[0-9]+:.*//' | uniq` ; do
     # Fix them!
     sed -i 's/[[:space:]]*$//' "$FILE"
  done
  exit
cmcginty
fonte
4
Esta pergunta está perguntando como preservar o espaço em branco à direita.
Douglas
@Douglas: um provavelmente poderia usar esta resposta para criar um commit em uma filial temporária, comprometer o patch real lá e cereja-escolher o diff única no ramo trabalhando de alguma forma ...
Tobias KIENZLER