Como mesclar arquivos específicos das ramificações do Git

179

Eu tenho 2 ramos git branch1 e branch2 e quero mesclar file.py no branch2 em file.py no branch1 e apenas esse arquivo.

Em essência, eu só quero trabalhar no file.py no branch1, mas quero aproveitar o comando de mesclagem. Qual é a melhor maneira de fazer isso?

rwolst
fonte

Respostas:

207

Quando o conteúdo é file.pyda filial2 que não se aplica mais à filial1 , é necessário escolher algumas alterações e deixar outras. Para controle total, faça uma mesclagem interativa usando o --patchswitch:

$ git checkout --patch branch2 file.py

A seção do modo interativo na página de manual git-add(1)explica as chaves que devem ser usadas:

y - stage this hunk
n - do not stage this hunk
q - quit; do not stage this hunk nor any of the remaining ones
a - stage this hunk and all later hunks in the file
d - do not stage this hunk nor any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help

O comando split é particularmente útil.

pdp
fonte
3
Como podemos usar o patch e ao mesmo tempo usar uma ferramenta de mesclagem? em vez das coisas mais importantes
Gabriel
@ Gabriel Eu usei o Git mesmo com arquivos de patch e tarballs porque é muito fácil criar um repo ( git init <dir>) e finalmente jogá-lo fora ( rm -r <dir>).
pdp 27/01
105

Embora não seja uma mesclagem em si, às vezes é necessário todo o conteúdo de outro arquivo em outra ramificação. A postagem no blog de Jason Rudolph fornece uma maneira simples de copiar arquivos de um ramo para outro. Aplique a técnica da seguinte maneira:

$ git checkout branch1 # ensure in branch1 is checked out and active
$ git checkout branch2 file.py

Agora file.pyestá agora no ramo1 .

Мати Тернер
fonte
91
Fácil, mas isso não é realmente uma fusão . Ele só substitui file.pycom o que está no ramo 2.
Greg Hewgill
E se você mesclar novamente o arquivo do ramo1 para o ramo2? Você terá conflito!
Amir
Isso mantém o histórico de confirmação?
C2H50H
18

Nenhuma das outras respostas atuais realmente "mesclará" os arquivos, como se você estivesse usando o comando mesclar. (Na melhor das hipóteses, eles exigirão que você escolha manualmente as diferenças.) Se você realmente deseja tirar vantagem da fusão usando as informações de um ancestral comum, pode seguir um procedimento baseado no encontrado na seção "Mesclagem avançada" do git Manual de referencia.

Para este protocolo, suponho que você queira mesclar o arquivo 'caminho / para / arquivo.txt' da origem / mestre no HEAD - modifique conforme apropriado. (Você não precisa estar no diretório superior do seu repositório, mas ajuda.)

# Find the merge base SHA1 (the common ancestor) for the two commits:
git merge-base HEAD origin/master

# Get the contents of the files at each stage
git show <merge-base SHA1>:path/to/file.txt > ./file.common.txt
git show HEAD:path/to/file.txt > ./file.ours.txt
git show origin/master:path/to/file.txt > ./file.theirs.txt

# You can pre-edit any of the files (e.g. run a formatter on it), if you want.

# Merge the files
git merge-file -p ./file.ours.txt ./file.common.txt ./file.theirs.txt > ./file.merged.txt

# Resolve merge conflicts in ./file.merged.txt
# Copy the merged version to the destination
# Clean up the intermediate files

O arquivo de mesclagem git deve usar todas as suas configurações de mesclagem padrão para formatação e similares.

Observe também que se o "nosso" é a versão da cópia de trabalho e você não deseja ser excessivamente cauteloso, pode operar diretamente no arquivo:

git merge-base HEAD origin/master
git show <merge-base SHA1>:path/to/file.txt > ./file.common.txt
git show origin/master:path/to/file.txt > ./file.theirs.txt
git merge-file path/to/file.txt ./file.common.txt ./file.theirs.txt
RM
fonte
15

São todas as modificações file.pyem branch2em suas próprias commits, separado de modificações para outros arquivos? Nesse caso, você pode simplesmente fazer cherry-pickas alterações:

git checkout branch1
git cherry-pick <commit-with-changes-to-file.py>

Caso contrário, mergenão funciona caminhos ao longo individuais ... você pode muito bem criar um git diffpedaço de file.pyalterações de branch2e git apply-lhes branch1:

git checkout branch2
git diff <base-commit-before-changes-to-file.py> -- file.py > my.patch
git checkout branch1
git apply my.patch

fonte
8

Você pode stashe stash popo arquivo:

git checkout branch1
git checkout branch2 file.py
git stash
git checkout branch1
git stash pop
Martin G
fonte
Isso substitui branch1 / file.py pelo conteúdo de branch2 / file.py em vez de uma mesclagem que deve gerar um conflito de mesclagem a ser resolvido.
plumSemPy
2

Para mesclar apenas as alterações dos branch2 file.py, faça as outras alterações desaparecerem.

git checkout -B wip branch2
git read-tree branch1
git checkout branch2 file.py
git commit -m'merging only file.py history from branch2 into branch1'
git checkout branch1
git merge wip

A mesclagem nunca examinará nenhum outro arquivo. Pode ser necessário '-f' os checkout se as árvores forem diferentes o suficiente.

Observe que isso deixará o branch1 parecendo que tudo no histórico do branch2 até esse ponto foi mesclado, o que pode não ser o que você deseja. Uma versão melhor do primeiro checkout acima provavelmente é

git checkout -B wip `git merge-base branch1 branch2`

Nesse caso, a mensagem de confirmação provavelmente também deve ser

git commit -m"merging only $(git rev-parse branch2):file.py into branch1"
jthill
fonte
0

Estou na mesma situação, quero mesclar um arquivo de um ramo que tenha muitos commits nele no 2 ramo. Eu tentei várias maneiras acima e outras que encontrei na internet e todas falharam (porque o histórico de commit é complexo), por isso decido fazer o meu caminho (do jeito louco).

git merge <other-branch>
cp file-to-merge file-to-merge.example
git reset --hard HEAD (or HEAD^1 if no conflicts happen)
cp file-to-merge.example file-to-merge
Trac Nguyen
fonte
0

O que eu fiz é um pouco manual, mas eu:

  1. Mesclou as filiais normalmente; Reverteu a mesclagem com revert;
  2. Verifiquei todos os meus arquivos para HEAD~1, ou seja, seu estado no commit de mesclagem;
  3. Rebased meus commits para ocultar esse hackery do histórico de commit.

Feio? Sim. Fácil de lembrar? Também sim.

Lucas Lima
fonte