Estou tentando uma manobra de fusão de git bastante robusta agora. Um problema que me deparo é que fiz algumas alterações em algum código da minha ramificação, mas meu colega mudou esse código para um novo arquivo em sua ramificação. Então, quando o fiz git merge my_branch his_branch
, o git não percebeu que o código no novo arquivo era o mesmo que o antigo e, portanto, nenhuma das minhas alterações está lá.
Qual é a maneira mais fácil de aplicar minhas alterações novamente ao código nos novos arquivos. Não terei muitos problemas para descobrir quais confirmações precisam ser reaplicadas (posso apenas usar git log --stat
). Mas até onde eu sei, não há como o git reaplicar as alterações nos novos arquivos. A coisa mais fácil que estou vendo agora é reaplicar manualmente as alterações, o que não parece uma boa ideia.
Eu sei que o git reconhece blobs, não arquivos, então certamente deve haver uma maneira de dizer a ele: "aplique essa alteração exata no código desse commit, exceto não onde estava, mas onde está agora neste novo arquivo".
--rename-threshold
opção para ajustar a quantidade de semelhança necessária.Respostas:
Eu tive um problema semelhante e resolvi-o reorganizando meu trabalho para corresponder à organização do arquivo de destino.
Diga que você modificou
original.txt
em seu ramo (olocal
ramo), mas no ramo mestre,original.txt
foi copiado para outro, digamoscopy.txt
. Esta cópia foi feita em um commit que chamamos de commitCP
.Você deseja aplicar todas as alterações locais, confirmações
A
eB
abaixo feitas nooriginal.txt
novo arquivocopy.txt
.Crie um ramo descartável
move
no ponto inicial de suas alterações comgit branch move X
. Ou seja, coloque omove
branch em commitX
, aquele antes dos commit que você deseja mesclar; provavelmente, esse é o commit do qual você se ramificou para implementar suas alterações. Como o usuário @digory doo escreveu abaixo, você pode fazer ogit merge-base master local
para encontrarX
.Nesta ramificação, emita o seguinte comando de renomeação:
Isso renomeia o arquivo. Observe que
copy.txt
ainda não existia na sua árvore neste momento.Confirme sua alteração (chamamos de confirmação
MV
).Agora você pode refazer o seu trabalho sobre
move
:Isso deve funcionar sem problemas, e suas alterações são aplicadas
copy.txt
na sua filial local.Agora, você não necessariamente deseja ou precisa ter confirmação
MV
no histórico da ramificação principal, porque a operação de movimentação pode levar a um conflito com a operação de cópia em commitCP
na ramificação principal.Você só precisa refazer seu trabalho novamente, descartando a operação de movimentação, da seguinte maneira:
... onde
CP
está o commit ondecopy.txt
foi introduzido no outro ramo. Isso refaz todas as alterações nacopy.txt
parte superior daCP
confirmação. Agora, seulocal
ramo é exatamente como se você sempre modificassecopy.txt
e nãooriginal.txt
, e você pode continuar se fundindo com os outros.É importante que as mudanças sejam aplicadas
CP
oucopy.txt
não existiriam e as mudanças seriam aplicadas novamenteoriginal.txt
.Espero que isso esteja claro. Essa resposta chega tarde, mas pode ser útil para outra pessoa.
fonte
patch
(o que também envolve potencialmente muito trabalho), e é por isso que pensei que poderia ser interessante mostrá-lo. Além disso, observe que levei mais tempo para escrever a resposta do que realmente aplicar as alterações, no meu caso. Em qual etapa você recomendaria usando uma mesclagem? e porque? A única diferença que vejo é que, ao rebater, faço um commit temporário que é descartado posteriormente (commitMV
), o que não é possível apenas com mesclagens.Você sempre pode usar
git diff
(ougit format-patch
) para gerar o patch, editar manualmente os nomes dos arquivos no patch e aplicá-lo comgit apply
(ougit am
).Além disso, a única maneira de funcionar automaticamente é se a detecção de renomeação do git puder descobrir que os arquivos novos e antigos são a mesma coisa - o que parece que eles não estão realmente no seu caso, apenas uma parte deles. É verdade que o git usa blobs, não arquivos, mas um blob é apenas o conteúdo de um arquivo inteiro, sem o nome do arquivo e os metadados anexados. Portanto, se você tiver um pedaço de código movido entre dois arquivos, eles não são realmente o mesmo blob - o restante do conteúdo do blob é diferente, apenas o pedaço em comum.
fonte
git format-patch
trabalho para um commit. Se assim forgit format-patch SHA1
, ele gera um monte de arquivos de correção para todo o histórico. Mas acho quegit show SHA1 > diff.patch
também funcionará.-1
opção O modo normal de operação para o formato de patch é um intervalo de revisões, assimorigin/master..master
, você pode preparar facilmente uma série de patches.git apply
egit am
são muito exigentes, porque desejam os mesmos números de linha. Mas atualmente estou obtendo sucesso com opatch
comando UNIX .Aqui está uma solução de mesclagem de encontrar um conflito de mesclagem com renomear e editar e resolvê-lo com o mergetool, reconhecendo os 3 arquivos de origem de mesclagem corretos.
Após uma mesclagem falhar devido ao 'arquivo excluído' que você percebe que foi renomeado e editado:
Passo a passo:
Crie um arquivo.txt:
Crie uma ramificação onde você editará mais tarde:
Crie a renomeação e edite no mestre:
Troque para ramificar e edite também:
Tentativa de mesclar mestre:
Observe que o conflito é difícil de resolver - e que os arquivos foram renomeados. Abortar, imite o renomear:
Tente mesclar novamente:
Ótimo! A mesclagem resulta em um conflito 'normal' que pode ser resolvido com o mergetool:
fonte
B.txt -> C.txt
eA.txt -> B.txt
com o git mv, e o git não pôde combinar automaticamente os conflitos de mesclagem corretamente (estava obtendo conflitos de mesclagem entre o antigoB.txt
e o novoB.txt
). Usando esse método, os conflitos de mesclagem estão agora entre os arquivos corretos.