Posso obter uma saída compatível com patches do git-diff?

160

Estou fazendo algo muito simples errado. Estou tentando preparar um arquivo de patch comum, para poder aplicar novamente algumas alterações:

$ git diff > before
$ git diff something_here > save.patch
$ git checkout . 
$ patch < save.patch
$ git diff > after
$ diff before after
$

Com o something_here espaço em branco , quase funciona, mas os nomes dos arquivos não estão corretos. Acho que estou perdendo alguma opção.

Na vida real, vou fazer uma mesclagem após o checkout, para que o patch possa falhar por lá, mas você vê no que estou entrando.

Edite Minha falha aqui por fazer a pergunta errada. A questão real é: eu quero salvar minhas alterações, fazer uma mesclagem e reaplicar as alterações, se possível? Perguntei da maneira errada, porque estou acostumado a usar o patch para resolver esse tipo de problema e git diffparecia que era isso que eu queria que eu fizesse.

Comentário de Charles Bailey teve a resposta certa. Para mim, o git-apply é a coisa certa a fazer (o git-stash parece mais pesado do que eu preciso, o rebasing e os pacotes estão definitivamente além do meu nível de habilidade atual.) Vou aceitar a resposta que Charles deu (porque você não pode aceitar um comentário). Obrigado por todas as sugestões.

Editar, 6 anos depois Como qualquer pessoa familiarizada com o assunto sabe, eu superestimei a dificuldade de git stash. Quase todos os dias, usarei a seguinte sequência:

$ git stash
$ git merge
$ git stash pop
Malvolio
fonte
8
Existe algum motivo que você deseja usar especificamente, em patchvez degit apply ?
perfil completo de CB Bailey
3
E mesmo assim, você realmente precisa de patches em vez de algo como git stashou outras ferramentas git?
CB Bailey
3
Após a edição, acho que git stashé a solução mais fácil para o que você está tentando fazer, mas existem muitas abordagens que funcionam.
CB Bailey
1
@ Malvolio: Na verdade, você nem precisa pensar em um nome de arquivo temporário para armazenar seu patch.
CB Bailey
4
@Charlse, às vezes você precisa enviar um patch para alguém sem todo o repositório git. Por exemplo, se estiver usando git-svn.
Elazar Leibovich 29/03

Respostas:

139

Se você quiser usar o patch, precisará remover os a/ b/prefixos que o git usa por padrão. Você pode fazer isso com a --no-prefixopção (você também pode fazer isso com a -popção do patch ):

git diff --no-prefix [<other git-diff arguments>]

Geralmente, porém, é mais fácil usar o straight git diffe depois usar a saída para alimentar git apply.

Na maioria das vezes, tento evitar o uso de patches de texto. Geralmente, uma ou mais confirmações temporárias combinadas com rebase git stashe pacotes são mais fáceis de gerenciar.

Para o seu caso de uso, acho que stashé o mais apropriado.

# save uncommitted changes
git stash

# do a merge or some other operation
git merge some-branch

# re-apply changes, removing stash if successful
# (you may be asked to resolve conflicts).
git stash pop
CB Bailey
fonte
7
git diff --no-prefix master > diff.patche depoisgit checkout master patch -p0 < diff.patch
Natim
1
@ Natim Para segurança máxima, eu recomendaria o uso patch --dry-run < diff.patchantes de emitir o último comando.
ᴠɪɴᴄᴇɴᴛ
1
@ ᴠɪɴᴄᴇɴᴛ qual seria o benefício de fazer isso? Já que estamos usando o git, é improvável que percam alguma coisa, não é?
Natim
1
@ Natim Como eu disse, apenas para segurança máxima, não há necessidade de desfazer nada em caso de erro. Eu também estava pensando em pessoas que leem isso e desejam usar patchfora do git (talvez usando um arquivo de correção gerado por diff) em um caso de uso mais geral.
ᴠɪɴᴄᴇɴᴛ
Para incluir novos arquivos no seu patch, você precisa incluir também "git diff --no-prefix --cached" no patch. Talvez haja uma maneira melhor?
Jamshid
219

Basta usar -p1: você precisará usar -p0o --no-prefixcaso de qualquer maneira, para que você possa deixar de fora o --no-prefixe usar -p1:

$ git diff > save.patch
$ patch -p1 < save.patch

$ git diff --no-prefix > save.patch
$ patch -p0 < save.patch
ndim
fonte
1
Se você está se perguntando o porquê, o homem resume tudo bem - fonte .
TutuDajuju
3
Isso não funcionará com renomeações; git diffgera uma linha que patchignora. git applyé o caminho a percorrer.
Hraban
17

As diferenças do git têm um segmento de caminho extra anexado aos caminhos do arquivo. Você pode remover esta entrada no caminho especificando -p1 com patch, assim:

patch -p1 < save.patch
Henrik Gustafsson
fonte
10
  1. Eu salvo o diff do diretório atual (incluindo arquivos não confirmados) no HEAD atual.
  2. Em seguida, você pode transportar o save.patcharquivo para qualquer lugar (incluindo arquivos binários).
  3. Na máquina de destino, aplique o patch usando git apply <file>

Nota: também são os arquivos faseados no momento.

$ git diff --binary --staged HEAD > save.patch
$ git reset --hard
$ <transport it>
$ git apply save.patch
Matej
fonte
Hahaha Isso é engraçado. Fiz essa pergunta há quase quatro anos e a maneira como venho fazendo isso evoluiu, mas se você tivesse me perguntado ontem como fazê-lo, eu teria dado sua resposta e dito que obtive de respostas a essa pergunta. (Na verdade, eu provavelmente usaria um bare git diff > save.patche em git checkout .vez de um reset, mas sim ...
Malvolio
Oh não percebeu seus 4 anos de idade: P. Aliás, a redefinição é apenas para demonstrar que funciona. Também não vejo ninguém usando git applyou tornando o diff relevante para o seu estado e o ponteiro para o último commit disponível. Fazer simplesmente git diffnão fez nada
Matej 5/09
Sim, agora eu me pergunto como eu descobri git apply. A coisa com git diffé (eu acho) de usar git reset- as relações entre os repo, o índice, ea área de trabalho são o problema.
Malvolio
8

Um truque útil para evitar a criação de arquivos de patch temporários:

git diff | patch -p1 -d [dst-dir]
slowstart
fonte
Exatamente o que eu queria. Também funciona perfeitamente com esconderijos! git stash show -p stash@{3} | patch -p1 -d [dst-dir]
precisa saber é o seguinte