Realmente não relacionado a esta resposta, mas eu abandonaria git pull
, o que apenas é executado git fetch
seguido por git merge
. Você está fazendo três mesclagens, o que fará seu Git executar três operações de busca, quando uma busca é tudo que você precisa. Conseqüentemente:
git fetch origin # update all our origin/* remote-tracking branches
git checkout demo # if needed -- your example assumes you're on it
git merge origin/demo # if needed -- see below
git checkout master
git merge origin/master
git merge -X theirs demo # but see below
git push origin master # again, see below
Controlando a mesclagem mais complicada
A parte mais interessante aqui é git merge -X theirs
. Como root545 observou , as -X
opções são passadas para a estratégia de mesclagem, e tanto a recursive
estratégia padrão quanto a alternativa resolve
tomam -X ours
ou -X theirs
(uma ou outra, mas não ambas). Para entender o que eles fazem, no entanto, você precisa saber como o Git encontra e trata os conflitos de mesclagem .
Um conflito de mesclagem pode ocorrer dentro de algum arquivo 1 quando a versão base difere da versão atual (também chamada local, HEAD ou --ours
) e da outra versão (também chamada remota ou --theirs
) desse mesmo arquivo. Ou seja, a fusão identificou três revisões (três commits): base, nossa e deles. A versão "base" é a partir da base de mesclagem entre nosso commit e seu commit, conforme encontrado no gráfico de commit (para muito mais sobre isso, veja outras postagens do StackOverflow). O Git então encontrou dois conjuntos de mudanças: "o que fizemos" e "o que eles fizeram". Essas alterações são (em geral) encontradas linha a linha, puramente textuaisbase. Git não tem uma compreensão real do conteúdo do arquivo; é apenas comparar cada linha do texto.
Essas mudanças são o que você vê na git diff
saída e, como sempre, elas também têm contexto . É possível que as coisas que mudamos estejam em linhas diferentes das coisas que eles mudaram, de modo que as mudanças parecem que não iriam colidir, mas o contexto também mudou (por exemplo, devido à nossa mudança estar perto da parte superior ou inferior do arquivo, para que o arquivo se esgote na nossa versão, mas na deles, eles também adicionaram mais texto na parte superior ou inferior).
Se as mudanças acontecerem em linhas diferentes - por exemplo, mudamos color
para colour
a linha 17 e eles mudam fred
para barney
a linha 71 - então não há conflito: o Git simplesmente aceita as duas mudanças. Se as mudanças acontecem nas mesmas linhas, mas são mudanças idênticas , o Git pega uma cópia da mudança. Somente se as mudanças estiverem nas mesmas linhas, mas forem mudanças diferentes, ou aquele caso especial de contexto interferente, você obterá um conflito de modificar / modificar.
As opções -X ours
e -X theirs
informam ao Git como resolver esse conflito, escolhendo apenas uma das duas alterações: a nossa ou a deles. Como você disse que está mesclando os demo
(deles) com os master
(os nossos) e deseja as alterações de demo
, é o que você deseja -X theirs
.
Aplicar às cegas -X
, entretanto, é perigoso. Só porque nossas mudanças não entraram em conflito linha por linha não significa que elas não entrem em conflito! Um exemplo clássico ocorre em linguagens com declarações de variáveis. A versão base pode declarar uma variável não utilizada:
int i;
Em nossa versão, excluímos a variável não usada para fazer um aviso do compilador desaparecer - e em sua versão, eles adicionam um loop algumas linhas depois, usando i
como contador de loop. Se combinarmos as duas alterações, o código resultante não será mais compilado. A -X
opção não ajuda aqui, pois as alterações são em linhas diferentes .
Se você tiver um conjunto de testes automatizado, a coisa mais importante a fazer é executar os testes após a fusão. Você pode fazer isso após a confirmação e consertar as coisas mais tarde, se necessário; ou você pode fazer isso antes de confirmar, adicionando --no-commit
ao git merge
comando. Vamos deixar os detalhes de tudo isso para outras postagens.
1 Você também pode obter conflitos em relação às operações de "todo o arquivo", por exemplo, talvez consertemos a grafia de uma palavra em um arquivo (para que tenhamos uma mudança), e eles apaguem o arquivo inteiro (para que tenham um excluir). O Git não resolverá esses conflitos por conta própria, independentemente dos -X
argumentos.
Fazer menos mesclagens e / ou mesclagens mais inteligentes e / ou usar rebase
Existem três fusões em ambas as nossas sequências de comando. A primeira é trazer origin/demo
para o local demo
(o seu uso git pull
que, se o Git for muito antigo, não será atualizado, origin/demo
mas produzirá o mesmo resultado final). O segundo é trazer para origin/master
dentro master
.
Não está claro para mim quem está atualizando demo
e / ou master
. Se você escreve seu próprio código em seu próprio demo
branch, e outros estão escrevendo código e empurrando-o para o demo
branch origin
, então esta fusão de primeira etapa pode ter conflitos ou produzir uma fusão real. Na maioria das vezes, é melhor usar rebase, em vez de mesclar, para combinar trabalho (reconhecidamente, isso é uma questão de gosto e opinião). Em caso afirmativo, você pode querer usar git rebase
. Por outro lado, se você nunca faz nenhum de seus próprios commits demo
, você nem mesmo precisa de umdemo
branch. Alternativamente, se você deseja automatizar muito isso, mas ser capaz de verificar cuidadosamente quando há commits que você e outros fizeram, você pode querer usargit merge --ff-only origin/demo
: isso irá acelerar o seu, se possível, e simplesmente falhará completamente se não (nesse ponto você pode inspecionar os dois conjuntos de alterações e escolher uma fusão real ou um rebase, conforme apropriado).demo
para corresponder ao atualizado,origin/demo
Esta mesma lógica se aplica master
, embora você está fazendo a fusão em master
, então você definitivamente precisa de um master
. No entanto, é ainda mais provável que você deseje que a mesclagem falhe se não puder ser feita como uma não mesclagem de avanço rápido, então isso provavelmente também deveria ser git merge --ff-only origin/master
.
Digamos que você nunca faça seus próprios commits no demo
. Neste caso, podemos descartar o nome demo
inteiramente:
git fetch origin # update origin/*
git checkout master
git merge --ff-only origin/master || die "cannot fast-forward our master"
git merge -X theirs origin/demo || die "complex merge conflict"
git push origin master
Se você está fazendo seus próprios demo
commits de branch, isso não é útil; você também pode manter a fusão existente (mas talvez adicionar --ff-only
dependendo do comportamento que você deseja), ou alternar para fazer um rebase. Observe que todos os três métodos podem falhar: mesclar pode falhar com um conflito, mesclar com --ff-only
pode não ser capaz de avançar e rebase pode falhar com um conflito (rebase funciona, em essência, com commits seletivamente, que usa a fusão máquinas e, portanto, pode obter um conflito de fusão).
git push -f origin master