Saturday 24 March 2018

Git fundido por estratégia recursiva


Gent fundir por estratégia recursiva
O mecanismo de mesclagem (git misge e git pull commands) permite que as "estratégias de mesclagem" do backend sejam escolhidas com a opção - s. Algumas estratégias também podem tomar suas próprias opções, que podem ser aprovadas ao dar - X & lt; option & gt; argumentos para combinar e / ou git pull.
Isso só pode resolver duas cabeças (ou seja, o ramo atual e outro ramo que você retirou) usando um algoritmo de mesclagem de 3 vias. Ele tenta detectar cuidadosamente as ambiguidades de mesclagem cruzada e é considerado geralmente seguro e rápido.
Isso só pode resolver duas cabeças usando um algoritmo de mesclagem de 3 vias. Quando há mais de um antepassado comum que pode ser usado para a mesclagem de 3 vias, ele cria uma árvore mesclada dos antepassados ​​comuns e usa isso como a árvore de referência para a mesclagem de 3 vias. Isso foi relatado como resultado de menos conflitos de fusão sem causar mismerges por testes feitos em compromissos de fusão reais tirados do histórico de desenvolvimento do kernel do Linux 2.6. Além disso, isso pode detectar e manipular fusões envolvendo renomeações. Esta é a estratégia de mesclagem padrão ao puxar ou mesclar um ramo.
A estratégia "recursiva" pode ter as seguintes opções:
Esta opção força os tipos de conflitos a serem automaticamente resolvidos, favorecendo a "nossa" versão. As mudanças da outra árvore que não estão em conflito com o nosso lado são refletidas no resultado de mesclagem. Para um arquivo binário, todo o conteúdo é retirado do nosso lado.
Isso não deve ser confundido com a estratégia de "nossa", que nem sequer olha o que a outra árvore contém. Ele descarta tudo o que a outra árvore fez, declarando que "nossa" história contém tudo o que aconteceu nele.
Este é o oposto do "nosso"; note que, ao contrário do "nosso", não há "deles" mescla a estratégia para confundir esta opção de fusão.
Com esta opção, "merge-recursive" gasta um pouco de tempo extra para evitar mismerges que às vezes ocorrem devido a linhas de correspondência sem importância (por exemplo, chaves de funções distintas). Use isso quando os ramos a serem fundidos divergiram de forma selvagem. Veja também git-diff [1] - paciência.
Diz a "fusão-recursiva" para usar um algoritmo de diferença diferente, o que pode ajudar a evitar mismerges que ocorrem devido a linhas de correspondência sem importância (como aparelhos de diferentes funções). Veja também git-diff [1] --diff-algorithm.
ignore-space-change ignore-all-space ignore-space-at-eol ignore-cr-at-eol.
Trata as linhas com o tipo de mudança de espaço indicado como inalterada por causa de uma fusão de três vias. As mudanças de espaço em branco misturadas com outras alterações em uma linha não são ignoradas. Veja também git-diff [1] - b, - w, --ignore-space-at-eol e --ignore-cr-at-eol.
Se a "sua" versão apenas introduzir mudanças de espaço em branco para uma linha, a "nossa" versão é usada;
Se a nossa versão introduzir mudanças no espaço em branco, a versão '' deles '' inclui uma alteração substancial, a 'sua' versão é usada;
Caso contrário, a fusão prossegue da maneira usual.
Isso executa um check-out virtual e check-in de todos os três estágios de um arquivo ao resolver uma mesclagem de três vias. Esta opção destina-se a ser usada quando mesclar ramos com diferentes filtros limpos ou regras de normalização de fim de linha. Consulte "Mesclando ramos com diferentes atributos check-in / checkout" em gitattributes [5] para detalhes.
Desativa a opção renormalize. Isso substitui a variável de configuração fusionar.
Desative a detecção de renomeação. Veja também git-diff [1] --no-renomeação.
Ativar a detecção de renomeação, opcionalmente, definir o limite de similaridade. Este é o padrão. Veja também git-diff [1] --find-renames.
Sinônimo desaprovado para find-renames = & lt; n & gt; .
Esta opção é uma forma mais avançada de estratégia "subárvore", onde a estratégia adivinha a forma como duas árvores devem ser deslocadas para combinar uma com a outra quando se fundem. Em vez disso, o caminho especificado é prefixado (ou despojado desde o início) para tornar a forma de duas árvores coincidir.
Isso resolve casos com mais de duas cabeças, mas se recusa a fazer uma fusão complexa que precisa de resolução manual. É principalmente destinado a ser usado para agrupar as cabeças de tópicos. Essa é a estratégia de mesclagem padrão ao puxar ou juntar mais de uma ramificação.
Isso resolve qualquer número de cabeças, mas a árvore resultante da mesclagem é sempre a da cabeça atual do ramo, ignorando efetivamente todas as mudanças de todos os outros ramos. É destinado a substituir o antigo histórico de desenvolvimento de filiais laterais. Observe que isso é diferente da opção - Xours para a estratégia de intercalação "recursiva".
Esta é uma estratégia recursiva modificada. Ao mesclar as árvores A e B, se B corresponde a uma subárvore de A, B é primeiro ajustado para coincidir com a estrutura em árvore de A, em vez de ler as árvores no mesmo nível. Este ajuste também é feito para a árvore-antepassada comum.
Com as estratégias que utilizam a fusão de 3 vias (incluindo o padrão, 'recursivo'), se uma alteração for feita em ambos os ramos, mas mais tarde será revertida em um dos ramos, essa mudança estará presente no resultado mesclado; Algumas pessoas acham esse comportamento confuso. Ocorre porque apenas as cabeças e a base de mesclagem são consideradas ao realizar uma mesclagem, e não o indivíduo comete. O algoritmo de mesclagem considera, portanto, a alteração revertida como nenhuma alteração, e substitui a versão alterada.

Blog da AlBlue & rsquo; s.
Macs, Modularidade e Mais.
Git Dica da Semana: Fusion Revisited.
A Dica Git da semana da semana é sobre a fusão. Você pode se inscrever no feed se quiser receber novas parcelas automaticamente.
Anteriormente, analisamos a fusão em abril, mas abordamos o índice na semana passada e os números de índice (ou estágio), que fazem parte das fusões. Esta semana, vamos ver o que isso significa com diferentes tipos de fusões. Se você não é familliar com fusões, dê uma olhada na publicação anterior primeiro.
A mesclagem permite reunir dois (ou mais) compromissos em um único commit de mesclagem, ao mesmo tempo que reúne todos os diferentes arquivos combinados nos dois. Se houver conflitos de mesclagem, estes devem ser resolvidos individualmente. Fósforos em que um dos commit é um antepassado do compromisso atual são referidos como fusões de avanço rápido e não resultam em um compromisso de mesclagem sendo criado. Quando você puxa de uma fonte remota, você está realmente fazendo uma busca e uma mesclagem em um passo e ndash; embora geralmente, você pode avançar rapidamente quando você faz.
Para os propósitos deste post, vou criar três ramos chamados & lsquo; Alex & rsquo ;, & lsquo; Bob & rsquo; e & lsquo; master & rsquo ;, em homenagem a Alice e Bob. Cada ramo terá um arquivo chamado Hello que conterá o texto & ldquo; Olá, meu nome é Alex & rdquo; (c. f. Bob), bem como um AlexsFile, BobsFile etc.
Quando você cria uma mesclagem, você tem a opção de dizer como a mesclagem será processada. A estratégia usual é recursiva. Isso significa que o Git irá caminhar para cada diretório (árvore) e descobrir quais arquivos têm diferenças em comparação com a revisão básica e, em seguida, usar aquele com alterações. (Se ambos tiverem alterações, o conteúdo do novo arquivo é mesclado textualmente, e se houver um problema com isso, um conflito se segue.) É por isso que você vê a mensagem & ldquo; Merge feita por recursive & rdquo; depois de fazer a operação:
O commit d612aa & hellip; é um nó de mesclagem em que traz dois ramos separados juntos. Uma vez que nenhum deles é um antepassado do outro, eles não podem ser encaminhados rapidamente e, como tal, o nó de mesclagem é criado. Podemos determinar os pais cometidos com HEAD ^ 1 e HEAD ^ 2:
É ainda mais fácil quando não há alterações a serem mescladas:
O avanço rápido aqui indica que o mestre está atrás de Bob, e então podemos simplesmente mover o ponteiro para a frente & ndash; Como resultado, não precisamos criar um nó de mesclagem.
Então, duas estratégias que o Git usa são fazer um avanço rápido ou uma fusão feita por recursiva. Isso cobre 99% das fusões que você precisará fazer; Mas vale a pena notar que a Git tem mais alguns truques é a manga, que pode ajudar em determinadas situações.
Os exemplos acima têm um ou dois pais. No entanto, um nó de mesclagem Git é capaz de representar mais de duas cabeças em uma mesclagem e usa uma estratégia chamada polvo. Isso é selecionado por padrão quando você mescla mais de dois ramos:
Nesse caso, temos três compromissos unindo o nó da mesclagem. o mestre (que tinha divergido), e os ramos de Alex e Bob de antes. Uma vez que nosso nó de mesclagem agora tem três pais, podemos usar git rev-parse para converter a HEAD ^ 1/2/3 na primeira, segunda e terceira cabeças.
E se os arquivos estiverem em conflito?
Podemos lançar uma ferramenta de três vias com git mergetool:
Observe que a mesclagem Octopus não manipula conflitos de mais de 2 arquivos. Se você fizer isso, você acabará com uma mensagem de erro diferente:
Finalmente, a última estratégia que vale a pena conhecer é a nossa estratégia. Isso leva qualquer número de cabeças e cria um nó de mesclagem, mas sem realmente fazer alterações. Em outras palavras, um HEIT ^ 1 de Shit Git sempre retornará vazio para uma estratégia do nosso:
Podemos verificar que estes são idênticos, uma vez que a árvore apontada por HEAD é a mesma que a árvore apontada pela HEAD ^ 1 (ou seja, o pai). O sufixo ^ é usado para mostrar a árvore associada ao commit.
O argumento --decorate to git log adiciona os nomes das ramificações à saída, o que pode ser útil para mostrar de onde as fusões vieram. O argumento --graph é principalmente usado com o argumento --online; embora você possa executar um git --graph, as mensagens de confirmação completas tendem a ocultar a estrutura do gráfico.
A nossa estratégia só é realmente útil se você deseja codificar um conjunto de compromissos anteriores, mas não os afeta no mestre atual (por exemplo, porque você escolheu alguns dos conteúdos e não quer levar outras peças, mas preservar eles na história, como é de alguma forma).
Mensagem de mesclagem e avanço rápido.
A mensagem de mesclagem será criada automaticamente, com base nos nomes das filiais que você está mesclando. No entanto, é possível passar uma opção - m, como com git commit, para fornecer uma mensagem adicional. Isso pode ser útil se a mensagem de mesclagem precisar de informações adicionais codificadas (como, por exemplo, quais bug (s) foram corrigidos).
Também é possível forçar uma fusão, mesmo que não seja necessário. Se você tem filiais baseados em tópicos, pode ser útil denotar que o trabalho foi realizado em um ramo separado antes de ser incorporado de novo ao mestre. Execução da mesclagem de git --no-ff criará um nó de mesclagem, seja ou não o ramo pode ser encaminhado ou não. Uma vez que o commit de mesclagem tem o nome do ramo que você está mesclando como parte do commit, você pode terminar com nomes descritivos para mostrar o recurso que foi concluído:
Ser capaz de mesclar com um --no-ff pode ser útil ao usar alguns tipos de fluxos de trabalho de confirmação, onde muitos ramos são usados ​​para desenvolver recursos individuais e depois trazidos para um ramo principal posteriormente. Também vale a pena notar o argumento --merges permite filtrar apenas as fusões em um repositório:
Da próxima vez, veremos o que podemos fazer com os diferentes fluxos de trabalho do Git usando a mesclagem --no-ff.
Volte a próxima semana para outra parcela na série Git Tip of the Week.
Postagens recentes.
StackOverflow.
Em Delicious.
GitHub Repos.
Atualização do status. @alblue no GitHub.
Direitos autorais e cópia; 2017 - Alex Blewitt - Powered by Octopress.

O blog de mrkrstphr.
Pare de mesclar o mestrado.
Postado em 12 de fevereiro de 2018.
Eu provavelmente incomodo meus colegas de trabalho constantemente reclamando sobre eles mesclando mestre. Não penso que qualquer um deles entenda o que eu estou falando. Provavelmente porque eu apenas gritei e nunca expliquei.
Então, vamos caminhar através de um pequeno cenário que explica por que o mestre em fusão é estúpido.
Deixe-nos criar um novo repositório e faça alguns compromissos:
Agora, vamos e crie um novo ramo para fazer algum trabalho separado em:
Se estamos trabalhando com outras pessoas, ou talvez trabalhando separadamente, o mestre pode mudar enquanto estamos trabalhando neste ramo foo:
Uma vez que nós divergimos do mestre, é bem possível - e bastante comum - que possamos trazer essas mudanças no mestre para o nosso ramo para que possamos usá-los ou incorporá-los.
A sabedoria convencional e comum diz que mesclar essas mudanças em:
Ótimo trabalho, droga. Agora, veja seu histórico de confirmação:
Nós mangamos nossa história de compromisso, de modo que parece que 21edb08 aconteceu antes de f25c8a8, e isso será verdade quando você inevitavelmente juntar isso em mestre. Agora as coisas estão fora de ordem.
E pior ainda, você introduziu uma ebde5b muda e inútil.
Vamos desatar sua bagunça:
Agora, em vez de fundir, vamos rebase nosso ramo em cima do mestre:
Ei, olhe isso: nossa história de compromisso é bonita. É na ordem correta que aconteceu, e não temos um compromisso de fusão sem sentido.
Então, o que está rebaixando?
Quando você cria um ramo, você diverge da linha principal:
A1, A2 e A3 se comprometem a dominar. Na A3, você cria um novo ramo e faz um commit, que se torna B1.
A base do seu novo ramo é A3, como aquilo de onde você criou.
Quando mais comete acontecer ao mestre, você fica para trás:
Quando você rebase, você está movendo a base do seu ramo para a frente. Git essencialmente re-runs your branch & # 39; s comete no topo do mestre:
A base do seu ramo é agora A5, e seus compromissos, B1 e B2 foram reescritos em cima da A5. Nós os chamamos de C1 e C2, pois são totalmente novos comprometem-se com diferentes mudanças e alvos de referência.
Para saber mais sobre rebasing, com gráficos melhores, check-out Git Branching - Rebase.
Quando Rebase.
Então, quando faz sentido rebase? Sempre? Definitivamente não.
Rebase faz mais sentido quando você tenta incorporar outras mudanças em seu ramo não-mestre. Como parte de fazer o seu trabalho fora do mestre, você não quer afetar a ordem em que as coisas aconteceram no mestre, que a fusão pode fazer. Você quer construir seu trabalho em cima do mestre.
Quase sempre faz sentido rebase seu ramo com o mestre e nunca mesclar o mestre em seu ramo.
Isso também oferece o benefício adicional de resolver conflitos em seu ramo antes de mestre, em vez de resolver conflitos no mestre.
Quando combinar.
O inverso disso é que você nunca deve rebase seu ramo em mestre, pois reescreve a história do mestre. Em vez disso, seu ramo deve sempre ser incorporado ao mestre.
Existe uma maneira de mesclar no mestre sem gerar um commit de mesclagem fedorento, e isso é para usar a opção --ff-only ao mesclar. O avanço rápido apenas evita que uma fusão ocorra, e só puxará suas mudanças se puder simplesmente mover o ponteiro da CABEÇA do ramo para o ponteiro CABO do ramo que você está fundindo.
Se puder, não irá falhar. Quando não pode avançar, é quase sempre porque o ramo que você está tentando mesclar um ramo que não foi rebased com o mestre. Se a base do ramo não for a CABEÇA do mestre, ele simplesmente não pode simplesmente soltar os compromissos do seu ramo no topo do mestre.
Para resolver isso, apenas certifique-se de rebase seu ramo com o mestre:
Isso parece muito trabalho, mas veja quão bonito e fácil seguir seu histórico de compromissos é!
Lidar com o GitHub.
Se você estiver usando o GitHub, ou algum outro sistema inferior, você não tem controle sobre os pedidos de puxar são mesclados. O GitHub não vai fazer um rebase e depois uma fusão para você, eles simplesmente irão gerar um compromisso de mesclagem.
Há uma maneira de contornar isso, mas é pior do que a dança rebase-merge: você pode lidar com a mesclagem na linha de comando e empurrar manualmente para dominar.
Ain, ninguém tem tempo para isso. Neste ponto, provavelmente é mais fácil lidar com os poucos compromissos de mesclagem gerados por pedidos de tração. É ainda menos compromissos de fusão do que aqueles gerados pela mesclagem do mestre o tempo todo.
Cuidado com o histórico de reescrita.
Rebase é essencialmente reescrevendo o histórico, mesmo se você acabar com o mesmo número de compromissos na mesma ordem. Lembre-se, rebasing gera novos compromissos com novos hashes de referência. Por que isso importa?
Se alguém mais tiver aqueles cometidos em sua história - digamos que você empurre sua filial para o GitHub para que outro desenvolvedor possa trabalhar nela - eles vão ter um mau momento.
Você está essencialmente destruindo sua história. Na próxima vez que tentarem retirar as atualizações da sua filial, não funcionará de forma limpa (a menos que eles usem um git pull --rebase, o que realmente deveriam fazer de qualquer maneira).
Se eles tentam empurrar para o seu ramo, eles não podem. A menos que forçam, o que nesse momento irá apagar suas mudanças. Eles primeiro terão que usar giro --rebase.
Isso torna as coisas mais difíceis. Trabalhável, com comunicação adequada, mas difícil.
Nunca deves rebase dentro do mestre. Se você fizer isso, você está pedindo que o fogo do inferno choque sobre você.
Lidar com Conflitos.
A desvantagem de rebasing é conflitos. Os conflitos podem ser gerados quando você mescla ou rebase, mas eles podem se tornar muito mais difíceis ao rebaixar.
Ao combinar com conflitos, você resolve todos os conflitos de uma só vez, em uma única empresa gigante.
Lembre-se de que, quando renunciamos, cada confirmação é reaplicada no topo do mestre (ou qualquer ramo em que você reasignar). Assim, cada confirmação de reaplicação tem a possibilidade de gerar conflitos.
Isso significa que se você tiver 25 compromissos em sua filial e você está reasignando com o mestre, as 25 oportunidades para gerar conflitos. Você pode ter que resolver conflitos similares várias vezes com o git rebase suas alterações.
Esse tipo de suga no início. Rebasin & # 39; Não é fácil, mas parece certo. E uma vez que você se acostume com isso, nunca mais vai querer voltar.
A arquitetura limpa em PHP.
Escrevi um livro sobre a Arquitetura Limpa no PHP, que cobre como organizar e desacoplar seu código de forma limpa de forma a que ele o prepare para sobreviver e ser fácil de manter a longo prazo.

git-merge (1) Manual Page.
git-merge - Junte-se a duas ou mais histórias de desenvolvimento.
DESCRIÇÃO.
Incorpora as mudanças dos compromissos nomeados (desde o tempo em que suas histórias divergiram do ramo atual) no ramo atual. Este comando é usado pelo git pull para incorporar mudanças de outro repositório e pode ser usado manualmente para mesclar as mudanças de um ramo para outro.
Suponha que o seguinte histórico exista e o ramo atual seja "mestre":
Então, "git merge topic" irá reproduzir as mudanças feitas no tópico, uma vez que divergiu do mestre (ou seja, E) até a confirmação atual (C) no topo do mestre e gravar o resultado em um novo commit junto com os nomes de os dois controladores de pai e uma mensagem de log do usuário que descreve as alterações.
A segunda sintaxe (& lt; msg & gt; HEAD & lt; commit & gt; & # 8230;) é suportada por motivos históricos. Não use isso na linha de comando ou em novos scripts. É o mesmo que git merge - m & lt; msg & gt; & lt; commit & gt; & # 8230; .
A terceira sintaxe ("git merge --abort") só pode ser executada após a fusão resultou em conflitos. git merge --abort interromperá o processo de mesclagem e tentará reconstruir o estado de pré-mesclagem. No entanto, se houve alterações não confirmadas quando a mesclagem foi iniciada (e especialmente se essas alterações foram modificadas após a fusão ter sido iniciada), git merge - infelizmente, em alguns casos, não será possível reconstruir as alterações originais (pré-mesclagem). Assim sendo:
Aviso: executar desencadear git com mudanças não comprometidas é desencorajado: quando possível, ele deixa você em um estado que é difícil de recuar no caso de um conflito.
Execute a mesclagem e cometer o resultado. Esta opção pode ser usada para substituir --no-commit.
Com --no-commit, execute a mesclagem, mas fingir que a fusão falhou e não autenticar, para dar ao usuário a chance de inspecionar e ajustar mais o resultado de mesclagem antes de cometer.
Não gere um commit de mesclagem se a mesclagem for resolvida como uma avanço rápido, apenas atualize o ponteiro do ramo. Este é o comportamento padrão do git-merge.
Com --no-ff, gere uma confusão de mesclagem, mesmo que a mesclagem seja resolvida como um avanço rápido.
Além dos nomes das filiais, preencha a mensagem de log com descrições de uma linha de no máximo & lt; n & gt; Compromissos reais que estão sendo mesclados. Veja também git-fmt-merge-msg (1).
Com --no-log não lista descrições de uma linha dos compromissos reais que estão sendo mesclados.
Mostre um diffstat no final da mesclagem. O diffstat também é controlado pela opção de configuração merge. stat.
Com - n ou --no-stat não mostre um diffstat no final da mesclagem.
Produza a árvore de trabalho e o estado do índice como se uma fusão real acontecesse (exceto para as informações de mesclagem), mas na verdade não faça uma confirmação ou mova a CABEÇA, nem registre $ GIT_DIR / MERGE_HEAD para causar o próximo comando de confirmação de git para criar uma mesclagem cometer. Isso permite que você crie um único commit no topo do ramo atual, cujo efeito é o mesmo que mesclar outro ramo (ou mais no caso de um polvo).
Com --no-squash, execute a mesclagem e comente o resultado. Esta opção pode ser usada para substituir --squash.
Recuse-se a mesclar e sair com um status diferente de zero, a menos que o HEAD atual já esteja atualizado ou a mesclagem pode ser resolvida como um avanço rápido.
-s & lt; strategy & gt; --strategy = & lt; strategy & gt;
Use a estratégia de mesclagem fornecida; podem ser fornecidos mais de uma vez para especificá-los na ordem em que devem ser testados. Se não houver nenhuma opção - s, uma lista integrada de estratégias é usada em vez disso (git merge-recursive ao mesclar uma única cabeça, git merge-octopus caso contrário).
-X & lt; option & gt; --strategy-option = & lt; opção & gt;
Passe a opção de estratégia de mesclagem específica até a estratégia de mesclagem.
Sinônimos para - marcar e - não estar estatístico; Estes são obsoletos e serão removidos no futuro.
Operar silenciosamente. Implica - não há progresso.
Ativar / desativar o progresso explicitamente. Se nenhum dos dois for especificado, o progresso é mostrado se o erro padrão estiver conectado a um terminal. Observe que nem todas as estratégias de mesclagem podem suportar relatórios de progresso.
Defina a mensagem de confirmação a ser usada para a confirmação de mesclagem (no caso de uma delas ser criada).
Se --log for especificado, um shortlog dos compromissos que estão sendo mesclados será anexado à mensagem especificada.
O comando git fmt-merge-msg pode ser usado para dar um bom padrão para invocações automatizadas de mesclagem de git.
Permita que o mecanismo rerere atualize o índice com o resultado da resolução de conflito automático, se possível.
Aborte o processo atual de resolução de conflitos e tente reconstruir o estado de pré-mesclagem.
Se houvesse mudanças de trabalho não comprometidas presentes quando a mesclagem começasse, git merge - infeliz, em alguns casos, não conseguirá reconstruir essas alterações. Portanto, é recomendável sempre comprometer ou armazenar as alterações antes de executar a fusão.
git merge --abort é equivalente a git reset - imergem quando MERGE_HEAD está presente.
Compromete, geralmente outras cabeças de filial, a fundir-se em nosso ramo. Especificar mais de um commit criará uma mesclagem com mais de dois pais (chamada carinhosamente chamada de Octopus Merge).
Se nenhum commit for fornecido a partir da linha de comando e se a variável de configuração Merge. defaultToUpstream estiver definida, mescla os ramos de rastreamento remoto que o ramo atual está configurado para usar como a montante. Veja também a seção de configuração desta página do manual.
CHECKS PRÉ-MERGE.
Antes de aplicar mudanças externas, você deve obter seu próprio trabalho em boa forma e comprometido localmente, portanto, não será bloqueado se houver conflitos. Veja também git-stash (1). git pull e git merge pararão sem fazer nada quando mudanças locais não comprometidas se sobrepõem com os arquivos que git pull / git merge pode precisar atualizar.
Para evitar a gravação de alterações não relacionadas no commit de mesclagem, git pull e git merge também abortar se houver alterações registradas no índice relativo ao commit HEAD. (Uma exceção é quando as entradas de índice alteradas estão no estado que resultaria da fusão já.)
Se todos os compromissos com nome já são ancestrais de HEAD, a fusão git irá sair cedo com a mensagem "Já está atualizada".
MERGE FAST-FORWARD.
Muitas vezes, o chefe de ramo atual é um antepassado do commit nomeado. Este é o caso mais comum especialmente quando invocado a partir de git pull: você está rastreando um repositório upstream, você não cometeu alterações locais e agora deseja atualizar para uma revisão upstream mais recente. Nesse caso, um novo commit não é necessário para armazenar o histórico combinado; Em vez disso, o HEAD (juntamente com o índice) é atualizado para apontar o commit nomeado, sem criar um commit adicional de mesclagem.
Esse comportamento pode ser suprimido com a opção --no-ff.
MERGE VERDADEIRO.
Exceto em uma fusão de avanço rápido (veja acima), os ramos a serem mesclados devem ser vinculados por um compromisso de mesclagem que tem ambos como seus pais.
Uma versão combinada que concilie as mudanças de todos os ramos a serem mesclados é comprometida e sua HEAD, índice e árvore de trabalho são atualizadas para isso. É possível ter modificações na árvore de trabalho, desde que não se sobreponham; A atualização os preservará.
Quando não é óbvio como conciliar as mudanças, acontece o seguinte:
O ponteiro HEAD permanece o mesmo.
O MERGE_HEAD ref está configurado para apontar para o outro cabeçalho.
Os caminhos que se fundiram de forma limpa são atualizados no arquivo de índice e na sua árvore de trabalho.
Para caminhos conflitantes, o arquivo de índice grava até três versões: o estágio 1 armazena a versão do antepassado comum, o estágio 2 da HEAD e o estágio 3 do MERGE_HEAD (você pode inspecionar os estágios com git ls-files - u). Os arquivos da árvore de trabalho contêm o resultado do programa "mesclagem"; ou seja, resultados de fusão de 3 vias com marcadores de conflito familiares e lt; & lt; & lt; === & gt; & gt; & gt; .
Nenhuma outra alteração é feita. Em particular, as modificações locais que você teve antes de iniciar a mesclagem permanecerão iguais e as entradas de índice para elas permanecerão como estavam, ou seja, CHAVE correspondente.
Se você tentou uma fusão que resultou em conflitos complexos e deseja começar de novo, você pode recuperar com git merge - abortar.
COMO OS CONFLITOS SÃO APRESENTADOS.
Durante uma mesclagem, os arquivos da árvore de trabalho são atualizados para refletir o resultado da mesclagem. Entre as mudanças feitas na versão do antepassado comum, as que não se sobrepõem (ou seja, você mudou uma área do arquivo, enquanto o outro lado deixou essa área intacta, ou vice-versa) são incorporados no resultado final, literalmente. Quando ambos os lados fizeram mudanças na mesma área, no entanto, git não pode escolher aleatoriamente um lado sobre o outro e pede que você o resolva deixando o que os dois lados fizeram nessa área.
Por padrão, o git usa o mesmo estilo que é usado pelo programa "mesclagem" do conjunto RCS para apresentar um tipo de conflito, como este:
A área onde um par de mudanças conflitantes aconteceu foi marcada com marcadores & lt; & lt; & lt; & lt; & lt; & lt; =======, e & gt; & gt; & gt; & gt; & gt; & gt; & gt; & gt; & gt; & gt; & gt; & gt; & gt; & gt; & gt; & gt; . A parte antes do ======= é tipicamente seu lado, e a parte mais tarde é normalmente o lado deles.
O formato padrão não mostra o que o original disse na área conflitante. Você não pode dizer quantas linhas são excluídas e substituídas pela observação da Barbie & # 8217; do seu lado. A única coisa que você pode dizer é que seu lado quer dizer que é difícil e prefere ir às compras, enquanto o outro lado quer dizer que é fácil.
Um estilo alternativo pode ser usado definindo a variável de configuração "merge. conflictstyle" para "diff3". No estilo "diff3", o conflito acima pode parecer assim:
Em adição ao & lt; & gt; lt; & lt; & lt; & lt; =======, e & gt; & gt; & gt; & gt; & gt; & gt; & gt; & gt; & gt; & gt; & gt; & gt; & gt; & gt; & gt; & gt; marcadores, usa outro ||||||| marcador que é seguido pelo texto original. Você pode dizer que o original apenas declarou um fato, e seu lado simplesmente cedeu a essa declaração e desistiu, enquanto o outro lado tentou ter uma atitude mais positiva. Às vezes, você pode encontrar uma melhor resolução ao visualizar o original.
COMO RESOLVER CONFLITOS.
Depois de ver um conflito, você pode fazer duas coisas:
Decida não se fundir. As únicas limpezas que você precisa são para redefinir o arquivo de índice para a confirmação HEAD para inverter 2. e para limpar as mudanças na árvore de trabalho feitas em 2. e 3; git merge - abort pode ser usado para isso.
Resolva os conflitos. Git marcará os conflitos na árvore de trabalho. Edite os arquivos em forma e git adicione-os ao índice. Use git commit para selar o negócio.
Você pode trabalhar com o conflito com várias ferramentas:
Use um mergethool. git mergetool para lançar um mergethool gráfico que irá ajudá-lo através da fusão.
Olhe para os diffs. Git diff mostrará um diferencial de três vias, destacando as mudanças nas versões HEAD e MERGE_HEAD.
Olhe os diffs de cada ramo. git log --merge - p & lt; path & gt; mostrará diffs primeiro para a versão HEAD e depois a versão MERGE_HEAD.
Veja os originais. git show: 1: o nome do arquivo mostra o antepassado comum, git show: 2: o nome do arquivo mostra a versão HEAD e o show git: 3: o nome do arquivo mostra a versão MERGE_HEAD.
Misture correções de ramos e aprimoramentos em cima do ramo atual, fazendo uma mesclagem de polvo:
Junte o ramo obsoleto no ramo atual, usando a nossa estratégia de fusão:
Junte o maint do ramo no ramo atual, mas não faça um novo commit automaticamente:
Isso pode ser usado quando você deseja incluir mais mudanças na mesclagem ou deseja escrever sua própria mensagem de confirmação de mesclagem.
Você deve abster-se de abusar dessa opção para esconder mudanças substanciais em uma comissão de mesclagem. Pequenos arranjos, como tropeçar o nome da versão / versão, seriam aceitáveis.
MERGE ESTRATÉGIAS.
O mecanismo de mesclagem (comandos git-merge e git-pull) permite que as estratégias de mesclagem do backend sejam escolhidas com a opção - s. Algumas estratégias também podem tomar suas próprias opções, que podem ser aprovadas ao dar - X & lt; option & gt; argumentos para git-merge e / ou git-pull.
Isso só pode resolver duas cabeças (ou seja, o ramo atual e outro ramo que você retirou) usando um algoritmo de mesclagem de 3 vias. Ele tenta detectar cuidadosamente as ambiguidades de mesclagem cruzada e é considerado geralmente seguro e rápido.
Isso só pode resolver duas cabeças usando um algoritmo de mesclagem de 3 vias. Quando há mais de um antepassado comum que pode ser usado para a mesclagem de 3 vias, ele cria uma árvore mesclada dos antepassados ​​comuns e usa isso como a árvore de referência para a mesclagem de 3 vias. Isso foi relatado como resultado de menos conflitos de mesclagem sem causar mis-merges por testes feitos em compromissos de fusão reais tirados do histórico de desenvolvimento do kernel do Linux 2.6. Além disso, isso pode detectar e manipular fusões envolvendo renomeações. Esta é a estratégia de mesclagem padrão ao puxar ou mesclar um ramo.
A estratégia recursiva pode levar as seguintes opções:
Esta opção força os tipos de conflitos a serem resolvidos automaticamente, favorecendo nossa versão. As mudanças da outra árvore que não estão em conflito com o nosso lado são refletidas no resultado de mesclagem.
Isso não deve ser confundido com a nossa estratégia de fusão, que nem sequer olha o que a outra árvore contém. Ele descarta tudo o que a outra árvore fez, declarando que nossa história contém tudo o que aconteceu nele.
Isso é oposto ao nosso.
Com esta opção, a fusão-recursiva gasta um pouco de tempo extra para evitar mismerges que às vezes ocorrem devido a linhas de correspondência sem importância (por exemplo, chaves de funções distintas). Use isso quando os ramos a serem fundidos divergiram de forma selvagem. Veja também git-diff (1) - paciência.
ignore-space-change ignore-all-space ignore-space-at-eol.
Trata as linhas com o tipo de mudança de espaço indicado como inalterada por causa de uma fusão de três vias. As mudanças de espaço em branco misturadas com outras alterações em uma linha não são ignoradas. Veja também git-diff (1) - b, - w e --ignore-space-at-eol.
Se sua versão apenas introduzir mudanças de espaço em uma linha, nossa versão é usada;
Se a nossa versão introduzir mudanças no espaço em branco, mas a sua versão inclui uma alteração substancial, sua versão é usada;
Caso contrário, a fusão prossegue da maneira usual.
Isso executa um check-out virtual e check-in de todos os três estágios de um arquivo ao resolver uma mesclagem de três vias. This option is meant to be used when merging branches with different clean filters or end-of-line normalization rules. See "Merging branches with differing checkin/checkout attributes" in gitattributes(5) for details.
Disables the renormalize option. This overrides the merge. renormalize configuration variable.
Controls the similarity threshold used for rename detection. See also git-diff(1) - M .
This option is a more advanced form of subtree strategy, where the strategy makes a guess on how two trees must be shifted to match with each other when merging. Instead, the specified path is prefixed (or stripped from the beginning) to make the shape of two trees to match.
This resolves cases with more than two heads, but refuses to do a complex merge that needs manual resolution. It is primarily meant to be used for bundling topic branch heads together. This is the default merge strategy when pulling or merging more than one branch.
This resolves any number of heads, but the resulting tree of the merge is always that of the current branch head, effectively ignoring all changes from all other branches. It is meant to be used to supersede old development history of side branches. Note that this is different from the - Xours option to the recursive merge strategy.
This is a modified recursive strategy. When merging trees A and B, if B corresponds to a subtree of A, B is first adjusted to match the tree structure of A, instead of reading the trees at the same level. This adjustment is also done to the common ancestor tree.
CONFIGURATION.
Specify the style in which conflicted hunks are written out to working tree files upon merge. The default is "merge", which shows a <<<<<<< conflict marker, changes made by one side, a ======= marker, changes made by the other side, and then a >>>>>>> marker. An alternate style, "diff3", adds a ||||||| marker and the original text before the ======= marker.
If merge is called without any commit argument, merge the upstream branches configured for the current branch by using their last observed values stored in their remote tracking branches. The values of the branch.<current branch>.merge that name the branches at the remote named by branch.<current branch>.remote are consulted, and then they are mapped via remote.<remote>.fetch to their corresponding remote tracking branches, and the tips of these tracking branches are merged.
By default, git does not create an extra merge commit when merging a commit that is a descendant of the current commit. Instead, the tip of the current branch is fast-forwarded. When set to false , this variable tells git to create an extra merge commit in such a case (equivalent to giving the --no-ff option from the command line). When set to only , only such fast-forward merges are allowed (equivalent to giving the --ff-only option from the command line).
In addition to branch names, populate the log message with at most the specified number of one-line descriptions from the actual commits that are being merged. Defaults to false, and true is a synonym for 20.
The number of files to consider when performing rename detection during a merge; if not specified, defaults to the value of diff. renameLimit.
Tell git that canonical representation of files in the repository has changed over time (e. g. earlier commits record text files with CRLF line endings, but recent ones use LF line endings). In such a repository, git can convert the data recorded in commits to a canonical form before performing a merge to reduce unnecessary conflicts. For more information, see section "Merging branches with differing checkin/checkout attributes" in gitattributes(5).
Whether to print the diffstat between ORIG_HEAD and the merge result at the end of the merge. True by default.
Controls which merge resolution program is used by git-mergetool(1). Valid built-in values are: "araxis", "bc3", "diffuse", "ecmerge", "emerge", "gvimdiff", "kdiff3", "meld", "opendiff", "p4merge", "tkdiff", "tortoisemerge", "vimdiff" and "xxdiff". Any other value is treated is custom merge tool and there must be a corresponding mergetool.<tool>.cmd option.
Controls the amount of output shown by the recursive merge strategy. Level 0 outputs nothing except a final error message if conflicts were detected. Level 1 outputs only conflicts, 2 outputs conflicts and file changes. Level 5 and above outputs debugging information. The default is level 2. Can be overridden by the GIT_MERGE_VERBOSITY environment variable.
Defines a human-readable name for a custom low-level merge driver. See gitattributes(5) for details.
Defines the command that implements a custom low-level merge driver. See gitattributes(5) for details.
Names a low-level merge driver to be used when performing an internal merge between common ancestors. See gitattributes(5) for details.
Sets default options for merging into branch <name>. The syntax and supported options are the same as those of git merge , but option values containing whitespace characters are currently not supported.

Chapter 7. Merging.
Merging is the process of combining the recent changes from several branches into a single new commit that is on all those branches. Most often there are only two branches involved, but in fact, there can be any number; if there are more than two, it is called an “octopus merge.” When there are only two branches, the current branch is called “our” side of the merge, while the other branch is called “their” side. Since the octopus merge is unusual, we will generally assume a two-branch merge in this discussion.
We described how Git may start a merge for you as part of git pull (see “Pulling”), but you can also perform merges explicitly. Here’s a typical scenario: you’re working on a software project, and you have an idea for a new feature, but you don’t want your experimental work on that feature to disturb your main development. So you create a branch named feature to contain the work:
When you need to go back to work on the main part of your project, you commit your work on the feature branch and switch back to master (or whichever branch you need to work on):
You continue like this for some time. Eventually, if you decide you don’t like your feature idea, you can discard the work by deleting the branch with git branch - D feature . If you decide to keep it, however, at some point you’ll want to incorporate it into the main project code, and you do this with a merge:
It’s best to have all your work committed before running git merge ; that is, git status should show no outstanding changes or untracked files. Backing out of a merge to your initial state may prove difficult otherwise. You can use git stash as a quick way to save working changes and restore them later (see “git stash”).
This merge was simple. You had added the files effulgent. c and epiphany. h on the feature branch, and they did not exist on master , so Git just added them. You had made minor changes to main. c on both branches, but those changes did not conflict, so Git combined them automatically and committed its merged version. The ASCII graph with filenames on the left is called a “diffstat”; it is a summary of the changes made by this commit. The lines of plus and minus signs represent the relative number of line additions (“insertions”) and deletions made in the corresponding file.
Both aspects of merging have occurred here: content and structure. First, Git combined the content of both branches by adding and merging changes to files; then, it recorded the fact of the merge structurally by creating a merge commit tying both branches together in the commit graph. This indicates in the history those commits whose contents were combined to produce the new one, by making them its parents. A “merge commit” is defined simply as a commit having more than one parent.
You can continue this process as long as you like, working on the feature branch separately and periodically merging its work into master . If you do, you will probably also need to merge the other way as well, updating the feature branch with the latest work on master , so that you’re not working on outdated code; for this, just do the reverse: switch to feature and run git merge master .
When your new feature is fully incorporated into the main development, and you no longer need to work on it separately, you can delete the feature branch with git branch - d feature ; as discussed in “Deleting a Branch”, Git will complain if you haven’t fully merged feature into master , to prevent you from accidentally losing work. Deleting feature doesn’t delete any of its content or history; it just removes the name “feature” as a reference point, a place at which you intend to add independent commits later on—since you no longer need it. You can reuse “feature” as a branch name in the future if you want, and there will be no collision with the earlier usage; in fact, aside from possibly in commit messages or reflogs, once you delete a branch, there is no record in the repository proper that it ever existed! Branch names serve to indicate what parts of the object database are still of interest, and where development is still occurring; if a branch’s content is merged into other branches, and you no longer need a line of development with that name, then you can just delete it, and reuse the name later for something else if you like. Similarly, looking back in the commit graph, it is not possible to know on which branch name a particular commit was made; even in a linear history, the current branch name might have been changed at some point in the past. It might be interesting or useful to know this in some situations, but Git just doesn’t keep this information. Git branches are ephemeral in a sense, just tools for building the commit graph, which is what matters.
Merge Conflicts.
The merge above went smoothly, but what if you had made changes in the two branches that Git could not combine on its own? These are called “merge conflicts,” and Git would stop and ask you to resolve them before committing. This process can range from simple to very complex, depending on the content and changes involved; fortunately, there are tools available to help, both in Git itself and with which Git can work. Let’s walk through a simple example. Suppose you have a file moebius with the following contents :
…and you make commits on branches chandra and floyd changing it thus:
You have changed the same two lines on each side in different ways, and Git’s line-oriented merge approach will not attempt to guess at your intent or combine the lines (e. g., form a single line dolphin monoliths , interesting as those might be); it will signal a merge conflict :
The phrase CONFLICT (content) indicates that the conflict is due to irreconcilable content changes in this file. Git might indicate other reasons as well, such as an add/add conflict, in which the same filename is added to both branches but with different contents.
If you start a merge and then want to cancel it — perhaps you weren’t expecting so many conflicts and you don’t have time to deal with them now — just use git merge --abort .
To get an overview of the merge state, use git status . Any changes Git resolved on its own will be shown as already staged for commit, and there is a separate section at the end for merge conflicts :
Unmerged paths are files with conflicts Git could not resolve. To find out what went wrong in detail, use git diff . This command not only shows the differences between various combinations of working tree, index, and commits; it also has a special mode for helping with merge conflicts :
This display shows the alternative versions of the section in conflict, separated by ======= and marked with the corresponding branch: ours (the current branch) and theirs (in this case floyd , the branch we are merging into ours). As usual, git diff shows differences between the working tree and the index, which in this case are the conflicts yet to be resolved; changes already made and staged are not shown. You can use git diff --staged to see those; add --stat for an overview. You’ll find that Git has updated the working file with similar markup:
Once you’ve edited the file to resolve the conflict, use git add to stage your fixed version for commit and remove it from the list of conflicted paths (if the resolution is actually to delete the file, use git rm ). Once you’ve addressed all the conflicts and git status no longer reports any unmerged paths, you can use git commit to complete the merge. Git will present a commit message containing details about this merge including its branches and conflicts, which you can edit as you see fit; in this case :
…and you can see you’ve created a “merge commit” having more than one parent:
The other branch, floyd , has stayed where it was, while the current branch chandra has advanced one commit from e355785d to aeba9d85 , and that last commit unifies the two branches. A new commit on floyd will cause them to diverge again, and you can merge again in the future if you need to (in either direction). Note that at this point, a simple git log will show commits from both branches, not just those made while on chandra :
You might have expected to see only commits aeba9d85, e355785d, and 50769fc9. This presentation may seem odd at first, but it’s just a different way of looking at the notion of “branch.” A Git branch is defined as the set of all commits reachable in the commit graph from the branch tip; think of it as all commits that contributed content to the tip commit (which, after a merge, includes all commits prior to that one on both branches).
In simple cases, you may get what you think of as the history of “this branch” with git log --first-parent , which just follows the first parent of merge commits rather than all of them. However, this isn’t guaranteed, and in more complex histories it won’t mean much. Since Git allows nonlinear history, a simple list of commits is often not very useful, and you need visualization tools to help you interpret it (see “Visual Tools”).
Resolving Merge Conflicts.
Git doesn’t have built-in tools to interactively address merge conflicts directly; that’s what external merge tools are for, which we’ll consider shortly in “Merge Tools”. However, here are some tips for use in simple cases.
git log - p --merge shows all commits containing changes relevant to any unmerged files, on either branch, together with their diffs. This can help you identify the changes in the history that led to the conflicts. If you want to discard all the changes from one side of the merge, use git checkout -- file to update the working file with the copy from the current or other branch, followed by git add file to stage the change and mark the conflict as resolved. Having done that, if you would like to apply some of the changes from the opposite side, use git checkout - p branch file . This starts an interactive loop that allows you to selectively apply or edit differing sections (see the “patch” item in the “Interactive Mode” section of git-add(1) for details).
In our example, if you decided to keep your version as a default, but selectively apply changes from the other branch, you could do:
If the current branch is already contained in the other (that is, HEAD is an ancestor of the other branch tip), then git merge will just move the current branch up to meet the other in a “fast-forward” update, and not make a new commit at all. You can force a merge commit anyway with git merge --no-ff (“no fast-forward”), if you have some reason to do so. If the converse is true, and the other branch is already contained in this one, then Git will simply say that the current branch is “already is up-to-date,” and do nothing. The goal of the merge is to incorporate into the current branch any changes on the other branch since the two diverged—but they haven’t diverged. If you want to use Git’s content-merging and conflict-resolution machinery, but do not want to create a merge commit, use git merge --squash . This operates like a normal merge with regard to content, but the commit it creates is just on the current branch (that is, has a single parent and does not connect to the other branch in the commit graph). You can use git merge - m to specify a commit message just as with git commit , although remember that Git provides useful information in its supplied message, which you may prefer to start with and edit instead (which happens by default ). Use git merge --no-commit to stop Git from committing when an automatic merge succeeds, in case you want to have a look first. This isn’t strictly necessary, since you could always abort the commit by giving a blank commit message, or make any changes you want afterward and use git commit --amend . Git records that a merge is in progress by setting the ref MERGE_HEAD to point to the other branch; this is how it knows to make a merge commit (as opposed to a simple commit on the current branch) even when there are intervening commands while you resolve conflicts.
Details on Merging.
When merging, Git considers the changes that have occurred on the branches in question since they last diverged. In the example above, the branches chandra and floyd last diverged at commit 50769fc9, so the changes to be reconciled were those in commits e355785d and a5374035. These branches might have diverged and been merged several times previously, but you will only be asked to deal with new changes since that last happened. Some other version control systems do not have this feature, so that merging branches repeatedly is a problem: you end up resolving the same conflicts over and over.
More precisely, when merging several branches, Git seeks a “merge base”: a recent common ancestor of all the branch tips, to use as a reference point for arbitrating changes. Although in complicated situations there might be multiple possibilities for a merge base (see git-merge-base(1) ), in the common case of our example, there is a single obvious choice, which Git finds automatically. Since our merge now involves three commits—two branch tips and the merge base—it is called a “three-way merge.”
Recall that git status showed our conflicts, the “unmerged paths.” Where does it keep this information? There are conflict markers in the working files, but it would be slow to read all the files for this purpose, and in any case that wouldn’t help for a modify/delete conflict. The answer demonstrates yet again the usefulness of the index. When there is a merge conflict for a file, Git simply stores not one version of the file in the index, but three: those belonging to the merge base and to the current and “other” branches, numbered 1, 2, and 3, respectively. The number is called the “stage” of the file and is a distinct property of an index entry along with the filename, mode bits, and so on. In fact, there is a third stage, 0, which is the usual state of an entry that has no associated merge conflict. We can see this using git ls-files , which shows the contents of the index. Prior to the merge, we see :
The fields here are the mode bits, ID of the blob object holding the file’s contents, the stage number, and the filename. After running git merge floyd and getting a conflict for this file, we see something very different (using - u instead of - s would show only unmerged paths; here we have only one file anyway) :
Note that the ID of stage 2 matches what was previously stage 0 above, since stage 2 is the version on the current branch. You can use git cat-file to see the contents of the different stages, here the stage 1 merge-base version:
You can refer to a specific stage of a file with the syntax :n:path ; so git show :1:moebius is an easier equivalent for this.
Git merges the three commits into the index in this way at the start of the merge. It then follows a set of simple rules to quickly resolve the easy cases; por exemplo:
If all three stages match, reduce to a single stage 0. If stage 1 matches stage 2, then reduce to a single stage 0 matching stage 3 (or vice versa): one side made a change while the other did nothing. If stage 1 matches stage 2, but there is no stage 3, then remove the file: we made no change, while the other branch deleted it, so accept the other branch’s change. If stages 1 and 2 differ, and there is no stage 3, then report a “modify/delete” conflict: we changed the file, while the other branch deleted it; the user must decide what to do.
…and so forth. Note that for matching, Git doesn’t need to fetch the actual files; it can just compare the blob object IDs already in the index, since they are hashes of the files’ contents. This is very fast; content-based addressing wins again. You can read about this process in more detail in git-read-tree(1) . Any files that can’t be easily resolved this way must then actually be examined to attempt merging their contents.
Merge Tools.
Merging can be complex job, with you staring at scores of conflicting sections of source code changes from yourself and other people, and trying to combine them into a single working whole. There are tools available that go far beyond the simple text output of git diff in helping you to visualize and resolve such conflicts. Git integrates smoothly with these external “merge tools,” to help you get the job done more easily. Git supports over a dozen free and commercial merge tools out of the box, including araxis, emerge, opendiff, kdiff3, and gvimdiff . It also defines an interface with which you can use most any such tool, usually requiring only a simple wrapper script to connect it to Git.
We can’t delve into the details of the individual merge tools; many of them are complex programs in their own right and would require another small book each to describe. Here, we’ll just describe how they work with Git generally.
The driver for using a merge tool is git mergetool . Once invoked, this command runs over all the files with merge conflicts, asking for each if you want to invoke the selected merge tool on the file. The default merge tool is opendiff , but you can set a different default with the merge. tool Git configuration variable. The tool will usually present you with a view of the “ours” and “theirs” versions of the file, along with the merge base, and provide ways to move from one change or conflict to the next, select which side’s change to use (or combine them), etc. When you quit the merge tool indicating success, Git will add your merged version to the index (thus marking this conflict as resolved), and go on to the next unmerged file.
The - y switch to git mergetool tells it to run the tool on all unmerged files, without pausing to prompt yes or no for each one. git mergetool leaves a backup foo. orig for each file foo it processes, since you might have modified it yourself before running the merge tool. You can set mergetool. keepBackup no to turn off this feature. Actually, Git still makes the backup; it just deletes it when the merge tool exits successfully, so that the backup is still there in case the tool were to crash.
If a merge tool exits unexpectedly or doesn’t work properly, you may see files like these left behind (for the file main. c ):
These are the temporary files that Git uses to pass the various file versions to the merge tool.
Custom Merge Tools.
If you want to use a merge tool not directly supported by Git, it need only obey some simple conventions; usually, you’ll write a glue script to accommodate them. Git passes four filenames to the tool as environment variables :
The tool should exit with a code of zero to indicate that the user is happy with the merged version, saved to the filename in the MERGED environment variable. A nonzero exit code means that Git should ignore that file and not mark this conflict resolved. To define a new Git merge tool named “foo” with your own program named newtool :
This shows the files being passed on the command line to newtool ; if your program reads the environment variables itself, then of course that’s not required. The trustExitCode setting means that Git will interpret the tool’s exit code as previously described; if this setting is false, Git will prompt the user for what to do anyway.
Merge Strategies.
Git has a number of approaches it can take to automatically merge files that have been changed by both sides of a merge; that is to say, exactly what it does in analyzing text to determine the boundaries of changed blocks, when blocks have been moved, when changes can be safely merged, and when they should be punted to the user. These approaches are called “merge strategies,” and each may in turn have various options; Git can even be extended with new strategies by writing custom “merge drivers,” without having to touch Git proper.
The built-in merge strategies are described in git-merge(1) . The many options are quite technical and involved, and Git’s default choice of strategy is usually sufficient; we will not cover them in depth here. However, here are a few tips involving merge strategies that are generally useful:
Why the Octopus?
An octopus merge is generally used to tie together several topic branches with the master branch in preparation for a new release of a project, bringing in all their separate contributions. The individual branches should already have been reconciled with the master and have no conflicts amongst them, or else as mentioned, the octopus merge will not work. The octopus merge does not have any inherent advantage over simply merging all the topic branches into the master pairwise and reconciling the conflicts there; it accomplishes the same goal and incorporates the same history. However, with a large number of branches, it can make for a cleaner and more easily understood commit graph, and so some people prefer it. See Figure 7-1.
Reusing Previous Merge Decisions.
Git can remember merge conflict resolutions you made in the past, and reuse them automatically if you run into similar conflicts later. This feature goes by the name git rerere , for “reuse recorded resolution.” This is useful if you’re working on a particularly difficult merge. You may abort a merge and retry it in various ways, but having resolved some conflicts in the meantime, this feature can remember and reapply those decisions. It can also be helpful if you’re rewriting repository history, or in maintaining branches on which you end up resolving the same conflicts repeatedly until the branch’s content can finally be merged appropriately.

No comments:

Post a Comment