Escolha a estratégia de mesclagem do Git para arquivos específicos ("nosso", "meu", "deles")

207

Estou no meio de rebarbas depois de um git pull --rebase. Eu tenho alguns arquivos que possuem conflitos de mesclagem. Como posso aceitar as alterações "deles" ou "minhas" para arquivos específicos?

$ git status
# Not currently on any branch.
# You are currently rebasing.
#   (fix conflicts and then run "git rebase --continue")
#   (use "git rebase --skip" to skip this patch)
#   (use "git rebase --abort" to check out the original branch)
#
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:  CorrectlyMergedFile
#
# Unmerged paths:
#   (use "git reset HEAD <file>..." to unstage)
#   (use "git add <file>..." to mark resolution)
#
#       both modified: FileWhereIWantToAcceptTheirChanges
#       both modified: FileWhereIWantToAcceptMyChanges

Normalmente, basta abrir o arquivo ou uma ferramenta de mesclagem e aceitar manualmente todas as alterações "deles" ou "minhas". No entanto, suspeito que esteja faltando um comando git conveniente.

Além disso, observe que só poderei escolher uma estratégia de mesclagem para cada arquivo quando vir quais arquivos atingem conflitos e possivelmente quais são os conflitos.

Steven Wexler
fonte
@AbeVoelker Não acho que isso resolva meu problema. Desejo selecionar uma estratégia de mesclagem para arquivos específicos. Além disso, observe que só vou saber qual estratégia de mesclagem usar quando estiver na minha nova base e ver quais arquivos atingiram conflitos e quais são os conflitos.
Steven Wexler
Editei esta pergunta para ser mais genérica: stackoverflow.com/questions/278081/… . Talvez possamos fechar esta pergunta como uma duplicata disso? Isso é apropriado?
@ TheShadow Isso me parece razoável.
Steven Wexler
Eu não tinha certeza se era apropriado alterar o título da outra pergunta para o que fiz, porque retirei a parte sobre a resolução de arquivos binários. Eu restaurei a outra pergunta para o que era anteriormente, então essa pergunta atual ainda agrega valor.

Respostas:

251

Para cada arquivo em conflito que você obtém, você pode especificar

git checkout --ours -- <paths>
# or
git checkout --theirs -- <paths>

Dos git checkoutdocumentos

git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...

--ours
--theirs
Ao fazer o check-out de caminhos do índice, verifique o estágio # 2 ( ours) ou # 3 ( theirs) quanto a caminhos não imersos.

O índice pode conter entradas não mescladas devido a uma falha na mesclagem anterior. Por padrão, se você tentar fazer check-out dessa entrada no índice, a operação de check-out falhará e nada será retirado. O uso -fignorará essas entradas não imersas. O conteúdo de um lado específico da mesclagem pode ser retirado do índice usando --oursou --theirs. Com -m, as alterações feitas no arquivo da árvore de trabalho podem ser descartadas para recriar o resultado da mesclagem em conflito original.


fonte
9
É possível aceitá-los para todos os arquivos deixados em aberto?
aslakjo
41
@aslakjo git rebase -s recursive -X <ours/theirs>ou git merge -s recursive -X <ours/theirs>. Lembre-se de que, para uma rebase, "nossos" e "deles" são revertidos do que são durante uma mesclagem. Você provavelmente também pode usar um arquivo / shell glob também, como git checkout --theirs -- *.txt.
2
Muito obrigado, @Cupcake, a reversão inesperada do ours/theirsrebase estava me deixando louco !! (Faz sentido agora que eu penso sobre como um rebase realmente funciona, mas não em todos intuitiva.)
Dan Lenski
2
O @DanLenski rebase em geral é apenas uma ferramenta realmente complicada para as pessoas entenderem primeiro, mas depois que você entende como funciona, você pode fazer todo tipo de coisa realmente poderosa.
1
@VincentSels, na verdade, você precisa mascarar o caractere *; caso contrário, o shell tentará expandi-lo. então, no seu caso git checkout --outs -- "**/*.csproj", fará o que você quer dizer. O mesmo é verdade, por exemplo, para git lfs track "*.jpg". Se você tiver alguns arquivos jpg no seu CWD, sem as aspas, somente esses serão rastreados.
eFloh
117

Mesmo que essa pergunta seja respondida, fornecendo um exemplo do que "deles" e "nosso" significa no caso de git rebase vs merge. Veja este link

Git Rebase
theirs é na verdade o ramo atual no caso de rebase . Portanto, o conjunto de comandos abaixo está realmente aceitando as alterações de sua ramificação atual na ramificação remota.

# see current branch
$ git branch
... 
* branch-a
# rebase preferring current branch changes during conflicts
$ git rebase -X theirs branch-b

Git Merge
Para mesclar , o significado de theirse oursé revertido. Portanto, para obter o mesmo efeito durante uma mesclagem , ou seja, mantenha as alterações atuais do seu ramo ( ours) sobre o ramo remoto que está sendo mesclado ( theirs).

# assuming branch-a is our current version
$ git merge -X ours branch-b  # <- ours: branch-a, theirs: branch-b
Abe
fonte
2
bem, esta é uma distinção muito importante! Obrigado por esclarecer.
Verboze 7/11
26

Note que git checkout --ours|--theirsirá substituir os arquivos totalmente , escolhendo uma das duas theirsou oursversão, que pode ser ou pode não ser o que você quer fazer (se você tiver quaisquer alterações não-conflitantes que vêm do outro lado, eles serão perdidos).

Se em vez você quer executar uma mala de três vias no arquivo, e só resolver os pedaços em conflito usando --ours|--theirs, ao mesmo tempo mantendo pedaços não-conflitantes de ambos os lados no lugar, você pode querer recorrer a git merge-file; veja detalhes nesta resposta .

jakub.g
fonte
1
Em relação às "alterações não conflitantes" que serão perdidas - refere-se apenas aos arquivos em que há alterações não conflitantes em linhas específicas, ou no mesmo arquivo ou a todas as alterações de todos os arquivos em históricos alinhados?
precisa saber é o seguinte
2
@ktamlyn por "alterações sem conflito", eu quis dizer alterações no mesmo arquivo. Por exemplo, existem dois pedaços alterado (em partes) example.txtem oursversão, um está em conflito (também alterados na theirsrevisão), a outra é não-conflito. Se você o fizer git checkout --theirs example.txt, apenas lerá cegamente o arquivo inteiro na theirsrevisão e a parte não conflituosa do diff será perdida.
jakub.g
1
Obrigado! Este foi um esclarecimento necessário para mim, embora "alterações no mesmo arquivo" façam mais sentido nesse contexto.
precisa saber é o seguinte
Essa deve ser a resposta aceita, bem, embora não dê realmente uma resposta, mas aponta uma questão importante na outra solução proposta.
tomasyany
1
Se você quiser voltar ao arquivo em conflito original, poderá executar git checkout --merge <path>.
Andrew Keeton