# Merge Branches permitem experimentar com o repositório, e separar o desenvolvimento de novas funcionalidades e correções. Também permite que várias pessoas trabalhem no mesmo projeto, através de branches remotos. Em algum momento, os vários branches devem ser reunidos em uma nova versão. Há várias formas de fazê-lo. Uma das ferramentas que o permite é o merge. Mas antes, revisaremos e veremos alguns conceitos. ## Branches Discutimos como criar branches na seção [[Branches]] e como obter branches remotos na seção [[Remotes]]. Vejamos, no entanto, porque levam esse nome. A imagem abaixo mostra um repositório com poucos commits. Com exceção do primeiro commit, todos os commits em Git possuem um ou mais genitores. Isso faz com que a relação entre os commits constitua um grafo acíclico dirigido, uma estrutura similar àquela associada a uma árvore genealógica. O exemplo abaixo mostra commits com apenas um genitor. Note, no entanto, que há um ramo, representado pelo branch devel. Isto é o que chamamos de histórico não-linear. Há formas de linearizar históricos e veremos mais adiante as razões para fazê-lo, quando não fazê-lo, e como fazê-lo. [[!img branches.png]] ## Commit IDs Vimos em [[Git_log]] que um commit é identificado por um ID. Este ID é um hash SHA-1 do objeto do commit. O objeto é composto pelo log, autor, data, a árvore de arquivos, outros metadados, e a lista de genitores. Dada a natureza de um hash criptográfico como SHA-1, pequenas mudanças no commit, seja no sumário, em algum arquivo, genitor, ou outros, causa uma mudança no commit ID. Vejamos como alterar um commit usando a opção --amend do comando git commit. Para tanto, criaremos um novo branch a partir do master e alteraremos nosso novo HEAD. ~/project$ git checkout -b amend master Switched to a new branch 'amend' ~/project$ Veja como fica o nosso grafo após o novo branch ser criado na imagem abaixo. Note que o grafo continua o mesmo e o branch amend é apenas uma referência ao mesmo commit ao qual o branch master se refere. [[!img branch.png]] Neste exemplo, alteramos apenas a mensagem de log, usando a opção --amend. ~/project$ git commit --amend [amend 571a638] Acrescenta lista de arquivos a serem ignorados. 1 file changed, 2 insertions(+) create mode 100644 .gitignore ~/project$ Note o resultado na figura abaixo. O commit foi alterado, mudando seu ID. Ele ainda aponta para o mesmo genitor, mas é um commit diferente daquele referenciado pelo branch master. [[!img amend.png]] ## Histórico A sequência de commits que vemos em um branch é também chamada de histórico. Como é utilizado um hash criptográfico e um link entre os commits utilizando o ID, e esse faz parte do conteúdo criptografado, não é possível alterar este histórico. Quando alteramos um commit, como feito acima, o histórico original é mantido enquanto ainda existir alguma referência a ele, através de branches, por exemplo. Se algum commit tiver o commit alterado como seu genitor, sua referência ainda será ao commit genitor original, não à nova versão do commit. Sendo assim, para aproveitar os commits já realizados, é necessário reescrevê-los para que apontem, em cadeia, às novas versões dos commits reescritos. Isso se chama reescrevendo a história, e pode ser feito com o comando git rebase, entre outros comandos. Veremos mais logo quando e como reescrever a história. Agora, veremos quando não se deve reescrevê-la. ## Fast-foward ## Merge Integração de código e histórico. ~/project$ git merge devel Faz o merge de testes. Merge made by the 'recursive' strategy. Makefile | 3 +++ 1 file changed, 3 insertions(+) ~/project$ [[!img merge.png]]