git add --interactive “Seu hunk editado não se aplica”

85

Estou tentando git add --interactiveadicionar seletivamente algumas alterações ao meu índice, mas recebo continuamente a mensagem "Seu trecho editado não se aplica. Editar novamente ...". Eu recebo esta mensagem mesmo se eu escolher a opção e, e imediatamente salvo / fecho meu editor. Em outras palavras, sem editar o pedaço, o patch não se aplica.

Aqui está o exemplo exato que estou usando (estou tentando montar uma pequena demonstração):

Arquivo original:

first change
second change off branch
third change off branch
second change
third change
fourth change

Novo arquivo:

Change supporting feature 1
first change
second change off branch
third change off branch
second change
third change
fourth change
bug fix 1
change supporting feature 1

Estou tentando mostrar como usar git add --interactivepara adicionar apenas a linha "bug fix 1" ao índice. Executando um suplemento interativo no arquivo, eu escolho o modo de patch. Me apresenta com

diff --git a/newfile b/newfile
index 6d501a3..8b81ae9 100644
--- a/newfile
+++ b/newfile
@@ -1,6 +1,9 @@
+Change supporting feature 1
 first change
 second change off branch
 third change off branch
 second change
 third change
 fourth change
+bug fix 1
+change supporting feature 1

Eu respondo com divisão, seguido de "não" para aplicar o primeiro pedaço. O segundo pedaço, tento editar. Originalmente, tentei excluir o resultado final - não funcionou. Deixar o pedaço sozinho também não funciona, e não consigo descobrir por quê.

Josh
fonte
Uma boa coisa a ter certeza aqui é que você não está adicionando -'s no início das linhas que não existem no arquivo para começar; é um diff e não pode deletar linhas que ainda não estejam lá. Então, se uma linha no diff começar com +e você alterá-la para -git, passa para WTF? porque agora a linha marcada para remoção não existe para começar (em vez disso, essa linha foi marcada para adição, e quando uma linha marcada para adição está marcada para remoção git não pode remover uma linha que ainda não esteja no arquivo) .
final de
1
Verifique também as terminações de linha (LF, CRLF) no meu caso não se aplica a um LF em vez de CRLF!
Alberto Rivelli

Respostas:

37

Para este exemplo específico, você precisa ajustar os números das linhas no pedaço. Mude a linha:

@@ -1,6 +2,8 @@

para que em vez disso leia:

@@ -2,7 +2,8 @@
William Pursell
fonte
16
Depois de pesquisar um pouco, descobri que essas linhas estão mostrando o "intervalo de arquivo" e "intervalo de arquivo". Eu realmente não entendo a lógica por trás da mudança de 1 para 2. Eu tentei e funciona, mas não entendo por que o "intervalo de arquivo" muda. O arquivo original é o mesmo, quer eu esteja aplicando todo o patch ou apenas o pedaço editado. Você pode esclarecer melhor ou apontar-me uma referência de descida no formato diff unificado. Não tive sucesso em encontrar um.
Josh
9
@Josh: stackoverflow.com/questions/2529441/… pode ajudar, mesmo se eu não obtiver inteiramente os pedaços do formato Unificado. @William +1
VonC
5
@Josh: Olhando para ele, parece que pode ser um bug. Depois de editar o hunk, o git tenta verificar o patch verificando se todos os pedaços serão aplicados (pode ser excessivo). Infelizmente, neste caso, isso significa que o pedaço anterior (que você não está aplicando) está sendo verificado, e há alguma sobreposição que faz com que git apply --check falhe. Não conheço uma solução elegante; git pode estar fazendo a coisa certa por ser excessivamente cauteloso aqui.
William Pursell
22
Mais informações sobre como alterar os números das linhas, por favor? Por que temos que fazer isso? E como? O que cada número significa?
Bill
4
@WilliamPursell quais versões do git? Mudei para um novo computador e executei git v2.17.0 e de repente minhas edições de patch não são mais válidas.
Dennis
105

É como nesta postagem git-add ?

Editar manualmente o pedaço é imensamente poderoso, mas também um pouco complicado se você nunca fez isso antes.
O mais importante a se ter em mente: o diff é sempre recuado com um caractere além de qualquer outro recuo que estiver lá.
O personagem pode ser:

  • um espaço (indica uma linha inalterada),
  • um -indicando que a linha foi removida,
  • ou um +indicando que a linha foi adicionada.

Nada mais. Deve ser um espaço, um - ou um +. Qualquer outra coisa e você obterá erros
(não há caractere para uma linha alterada, uma vez que eles são tratados removendo a linha antiga e adicionando a alterada como nova).

Já que você tem o diff aberto em seu editor de texto favorito (você configurou o Git para usar seu editor de texto favorito, certo?), Você pode fazer o que quiser - desde que tenha certeza de que o diff resultante se aplica perfeitamente.

E aí está o truque. Se você nunca fez isso antes, o Git dirá "Seu hunk editado não se aplica. Editar novamente?" com frequência, você começará a se odiar por sua incapacidade de descobrir isso , mesmo que pareça tão fácil (ou Git porque não consegue descobrir o que você quer).

Uma coisa que me fazia tropeçar com frequência era que eu esquecia o recuo de um caractere.
Eu marcaria uma linha com um - para ser removido, mas na maioria dos editores de texto que insere um -, isso não sobrescreve o espaço que estava lá antes. Isso significa que você está adicionando um espaço adicional a toda a linha, o que por sua vez significa que o algoritmo diff não pode encontrar / combinar a linha no arquivo original, o que significa que o Git gritará com você .

A outra coisa é que o diff ainda precisa fazer sentido. "Sentido" significa que pode ser aplicado de forma limpa. Exatamente como você cria um diff sensível parece um pouco uma arte sombria (pelo menos para mim agora), mas você deve sempre ter em mente a aparência do arquivo original e então planejar seus -s e + s de acordo. Se você editar seus pedaços com bastante frequência, eventualmente pegará o jeito.

Veja também este commit em git add -p .

A resposta de Ortomala Lokni refere-se à postagem do blog de Joaquín Windmüller " Selecione seletivamente as alterações para fazer commit com git (ou Imma edite seu pedaço) "

Em vez de contar linhas, o que o Git gostaria de fazer é unir pedaços sobrepostos (quando um é editado) antes de aplicar o referido pedaço editado.
Isso foi discutido em meados de 2018 e evitaria cenários como:

se você dividir um hunk, edite o primeiro subhunk, transformando uma linha de contexto final em uma exclusão, então, se você tentar preparar o segundo subhunk, ele falhará.

VonC
fonte
5
Obrigado pelo link, mas eu já tinha visto isso. Eu não estava adicionando / deixando uma linha adicional. O problema estava nos números das linhas, mas ainda não entendi a correção.
Josh
9
Eu não estava substituindo um '-' excluído por um espaço em branco - bagunçando o recuo. THX!!
pedorro
Apenas certifique-se de não entender mal a parte do espaço em branco. Achei que todas as linhas inalteradas deveriam ser apenas uma linha com um preto - em vez de meramente o caractere de recuo ... Tive uma hora de "o pedaço editado não se aplica" até que entendi o porquê: - /
oligofren
@oligofren Não tenho certeza se entendi você: o que você teve que fazer para aplicar o seu pedaço editado?
VonC
1
@VonC: Primeiro pensei que deveria mudar - foo para `` (apenas um espaço em branco, não "um espaço em branco e a linha inteira"). Levei um tempo para entender que deveria ser `foo`.
oligofren
48

É claro que estou atrasado para isso, mas mesmo assim gostaria de mencionar para registro que esse problema foi discutido no ano passado na lista de e- mails do git e parece que não mudou muito desde então.

Este problema particular decorre da divisão e tentativa de editar o mesmo pedaço. A análise, conforme postado originalmente por Jeff King, do problema subjacente é essencialmente:

Hm. OK eu vejo. A verificação de feeds de "esta diferença se aplica" ambas as partes do patch dividido para o git-apply. Mas é claro que a segunda parte nunca se aplicará corretamente, porque seu contexto se sobrepõe à primeira parte, mas não leva isso em consideração.

Fazendo a verificação com apenas o patch editado funcionaria. Mas isso não leva em consideração que o patch editado potencialmente não será aplicado no longo prazo, dependendo de você aceitar ou não a outra metade do patch dividido. E não podemos saber disso ainda, porque o usuário pode não ter nos contado (ele poderia ter pulado a primeira metade e voltar a ela depois da etapa de edição).

Jeff conclui sua postagem com uma solução alternativa muito pragmática que sempre tem êxito e, portanto, é altamente recomendada:

Então, em geral, acho que dividir e editar o mesmo pedaço é inerentemente perigoso e vai levar a esses tipos de problemas. E como a edição fornece um superconjunto da funcionalidade, acho que você deve apenas editar e permitir que a primeira parte do pedaço seja aplicada ou não, dependendo de sua preferência.

Ao escolher editar apenas um pedaço não dividido anteriormente, você não terá que lidar com os números das linhas.

Niels Ganser
fonte
6
Obrigado, isso é realmente muito mais fácil do que brincar com os números das linhas.
Michiakig
3
Esse era o meu problema. Precisava que meu pedaço fosse menor. Realizou uma divisão em modo interativo. A divisão não era o que eu queria, então decidi tentar editar manualmente. Continuei recebendo o erro. Recomeçou, funcionou na primeira tentativa.
Kyle é
Esta é a melhor resposta neste tópico. Não divida e edite. Apenas edite.
Dr_Zaszuś
No meu caso, um problema extra estava vindo das terminações de linha do Windows mostradas ^Mno arquivo diff. Depois de salvar o arquivo com terminações CR, o patch de edição interativa foi aprovado!
Dr_Zaszuś
Obrigado, isso funcionou para mim. Eu tive que trabalhar em um pedaço enorme, então eu dividi e tudo quebrou. Mantê-lo não dividido fez tudo funcionar bem.
Matthias Fischer
16

Quando você não deseja excluir uma linha que foi preparada para exclusão, como em

 first line
-second line
 third line

onde você deseja manter a segunda linha, certifique-se de substituir o -por um espaço, em vez de excluir a linha inteira (como faria para se livrar de uma linha adicionada). O Git usará a linha para o contexto.

Rose Perrone
fonte
1
Isso não ficou claro para mim, pensei que Git estava me dizendo para tornar a linha um único espaço.
JackHasaKeyboard
15

É importante também modificar corretamente o cabeçalho do pedaço (por exemplo @@ -1,6 +1,9 @@). Joaquin Windmuller revela o segredo da edição de cabeçalhos em uma de suas postagens de blog .

Os segredos da edição de pedaços

Editar os pedaços pode ser confuso no início, as instruções que o git lhe dá ajuda, mas não são suficientes para começar.

# —||

# To remove ‘-’ lines, make them ’ ’ lines (context).

# To remove ‘+’ lines, delete them.

# Lines starting with # will be removed.

#

# If the patch applies cleanly, the edited hunk will immediately be

# marked for staging. If it does not apply cleanly, you will be given

# an opportunity to edit again. If all lines of the hunk are removed,

# then the edit is aborted and the hunk is left unchanged.

O molho secreto é ... contar linhas:

  • Se você remover uma linha que começa com +, subtraia um para a nova contagem de linha (último dígito do cabeçalho do pedaço) .
  • Se você remover uma linha que começa com - então adicione um à nova contagem de linha (último dígito do cabeçalho do pedaço) .
  • Não remova as outras linhas (linhas de referência).

Isso deve permitir que você modifique rapidamente os pedaços para selecionar as partes que deseja.

Ortomala Lokni
fonte
1
Existe uma maneira de automatizar a edição do cabeçalho do hunk ou configurar o git para determinar as contagens de linha apropriadas?
Dennis
Você provavelmente pode criar um script de seu editor favorito para automatizar isso. Talvez já haja alguns plugins para isso, mas isso depende do editor.
Ortomala Lokni
14

Recentemente, ao ler este tópico, descobri como fazer a edição manual.

O truque que usei foi se eu tivesse uma diferença como:

+ Line to add
+ Line to add
+ Line I dont want to include
+ Line I dont want to include

O truque é remover completamente as duas linhas que não quero, fazendo com que a diferença resultante pareça:

+ Line to add
+ Line to add

Embora isso seja provavelmente óbvio para a maioria das pessoas, não era para mim até hoje e achei que deveria apenas compartilhar minha experiência. Por favor, diga-me se existe algum perigo para este método.

Sedrik
fonte
2
Eu não posso agradecer o suficiente! Eu estava tentando mudar o +para ' 'por pelo menos uma hora.
soumer
Você sabe, loucura é fazer a mesma coisa e esperar um resultado diferente. Venho dizendo isso para mim mesmo há 20 minutos antes de descobrir que só precisava excluir :)
solidak
Esta deve ser a resposta. Bom e simples, obrigado!
xPeaWhyTee
7

Você pode editar manualmente os números das linhas, o que é definitivamente útil em alguns casos. No entanto, você provavelmente poderia ter evitado esse problema específico NÃO primeiro dividindo o pedaço.

Se você perceber que provavelmente precisará editar algo mais tarde no pedaço que o Git escolheu automaticamente, é melhor apenas editar o pedaço inteiro em vez de dividir, preparar metade e editar a outra metade. Git fará um trabalho melhor descobrindo isso.

Michael Hines
fonte
6

Cheguei a esta questão procurando uma solução para o mesmo problema, e não consegui descobrir como alterar os números das linhas (como sugerido acima) no pedaço para fazer com que o git o aceite no meu caso. Eu encontrei uma maneira muito melhor de fazer isso usando git gui. Lá você pode selecionar as linhas no diff que deseja encenar, então clicar com o botão direito e escolher "Linhas de fase do commit". Lembro-me que o git-cola também tem a mesma funcionalidade.

Jayesh
fonte
Essa realmente deveria ser a resposta. git-colaparece funcionar em Linux, Windows e MacOS.
leeand00
5

Um problema adicional que tive quando recebi esse erro foi que as terminações de linha mudaram quando salvei o arquivo de edição.

Eu estava usando o Windows e o Bloco de notas para minhas edições (salva apenas com terminações de linha do Windows). Meu código foi escrito em Notepad ++ e eu o configurei para ter terminações de linha no estilo Unix / Linux.

Quando mudei minhas configurações para ter o Notepad ++ como o editor git padrão, fui capaz de fazer minhas edições no pedaço.

git config --global core.editor "notepad++"
KLee1
fonte
1
Isso funcionou para mim. Mas eu precisava do caminho completo para o notepad ++ e demorou um pouco para acertar: git config --global core.editor '"C:/Program\ Files\ \(x86\)/Notepad++/notepad++.exe"' (adapte de acordo com o local onde o notepad ++ está instalado no seu PC)
Annabel
1
Exatamente o mesmo problema para mim. Era o Bloco de notas que estava causando problemas. Assim que mudei meu editor padrão para o Notepad ++, tudo começou a funcionar novamente.
Johnny Oshika
4

Um motivo para mensagens estranhas "Seu pedaço editado não se aplica" (provavelmente acompanhado de algo como "erro: fragmento de patch sem cabeçalho na linha ...") pode ser seu editor se ele estiver configurado para remover espaços em branco à direita. Obviamente, isso causaria grandes problemas, pois os patches codificam linhas vazias, já que as linhas com um espaço, qualquer pedaço contendo linhas vazias não seria aplicado se fosse salvo com tal editor. Portanto, na verdade, qualquer pedaço contendo quaisquer linhas vazias inalteradas deixaria de ser aplicado após a edição com se a remoção do espaço em branco final estiver ativada.

Timo
fonte
0

Para sua informação, estava recebendo um erro ligeiramente relacionado ... quando adicionei o patch seguindo a instrução sugerida acima ... Não estava apresentando nenhum erro, no entanto. Eu estava recebendo repetidamente me pedindo para encenar o mesmo pedaço ... Eu percebi que estava executando uma versão mais antiga do Vim 7.4 ... Eu atualizei o vim e está funcionando como esperado agora. Espero que isso ajude alguém ..

Mantisimo
fonte