-
1. Primeiros Passos
- 1.1 Sobre Controle de Versão
- 1.2 Uma Breve História do Git
- 1.3 O que é Git?
- 1.4 A Linha de Comando
- 1.5 Instalando o Git
- 1.6 Configuração inicial do Git
- 1.7 Obtendo Ajuda
- 1.8 Resumo
-
2. Fundamentos do Git
-
3. Ramificação (Branching) no Git
-
4. Git no Servidor
- 4.1 Os Protocolos
- 4.2 Colocando o Git em um Servidor
- 4.3 Gerando a sua Chave Pública SSH
- 4.4 Configurando o Servidor
- 4.5 Git Daemon
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Opções de Hospedagem de Terceiros
- 4.10 Resumo
-
5. Git Distribuído
-
6. GitHub
-
7. Ferramentas do Git
- 7.1 Seleção de Revisão
- 7.2 Área de Stage Interativa
- 7.3 Fazendo Stash e Limpando
- 7.4 Assinando Seu Trabalho
- 7.5 Pesquisando (Searching)
- 7.6 Reescrevendo o Histórico
- 7.7 Reset Desmistificado
- 7.8 Merging Avançado
- 7.9 Rerere
- 7.10 Depurando com Git
- 7.11 Submódulos
- 7.12 Empacotando (Bundling)
- 7.13 Substituir (Replace)
- 7.14 Armazenamento de Credenciais
- 7.15 Resumo
-
8. Customizando o Git
- 8.1 Configuração do Git
- 8.2 Atributos do Git
- 8.3 Hooks do Git
- 8.4 Uma Política de Exemplo Imposta pelo Git
- 8.5 Resumo
-
9. Git e Outros Sistemas
- 9.1 Git como Cliente
- 9.2 Migrando para o Git
- 9.3 Resumo
-
10. Git Internals (Por Dentro do Git)
- 10.1 Encanamento e Porcelana (Plumbing and Porcelain)
- 10.2 Objetos do Git
- 10.3 Referências do Git
- 10.4 Arquivos de pacote (Packfiles)
- 10.5 Refspec
- 10.6 Protocolos de Transferência
- 10.7 Manutenção e Recuperação de Dados
- 10.8 Variáveis de Ambiente
- 10.9 Resumo
-
A1. Appendix A: O Git em Outros Ambientes
- A1.1 Interfaces Gráficas
- A1.2 Git no Visual Studio
- A1.3 Git no Visual Studio Code
- A1.4 Git no IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine
- A1.5 Git no Sublime Text
- A1.6 Git no Bash
- A1.7 Git no Zsh
- A1.8 Git no PowerShell
- A1.9 Resumo
-
A2. Appendix B: Incorporando o Git nos seus Aplicativos
- A2.1 Linha de Comando do Git
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
A3. Appendix C: Comandos do Git
- A3.1 Configuração e Ajustes
- A3.2 Obtendo e Criando Projetos
- A3.3 Snapshots Básicos
- A3.4 Branches e Merges
- A3.5 Compartilhando e Atualizando Projetos
- A3.6 Inspeção e Comparação
- A3.7 Depuração
- A3.8 Patches
- A3.9 E-mail
- A3.10 Sistemas Externos
- A3.11 Administração
- A3.12 Comandos de Encanamento
5.3 Git Distribuído - Mantendo um Projeto
Mantendo um Projeto
Além de saber como contribuir efetivamente para um projeto, você provavelmente precisará saber como manter um.
Isso pode consistir em aceitar e aplicar patches gerados via format-patch e enviados por e-mail para você, ou integrar alterações em branches remotos de repositórios que você adicionou como remotos ao seu projeto.
Quer você mantenha um repositório canônico ou queira ajudar verificando ou aprovando patches, você precisa saber como aceitar o trabalho de uma forma que seja mais clara para outros contribuidores e sustentável para você a longo prazo.
Trabalhando em Branches de Tópicos
Quando você estiver pensando em integrar um novo trabalho, geralmente é uma boa ideia testá-lo em um branch de tópico (topic branch) — um branch temporário feito especificamente para testar esse novo trabalho.
Dessa forma, é fácil ajustar um patch individualmente e deixá-lo se não estiver funcionando até que você tenha tempo de voltar a ele.
Se você criar um nome de branch simples com base no tema do trabalho que vai testar, como ruby_client ou algo similarmente descritivo, poderá se lembrar dele facilmente caso precise abandoná-lo por um tempo e voltar mais tarde.
O mantenedor do projeto Git também tende a colocar esses branches em namespaces — como sc/ruby_client, onde sc é a abreviação da pessoa que contribuiu com o trabalho.
Como você deve se lembrar, você pode criar o branch com base no seu branch master assim:
$ git branch sc/ruby_client master
Ou, se você também quiser mudar para ele imediatamente, pode usar a opção checkout -b:
$ git checkout -b sc/ruby_client master
Agora você está pronto para adicionar o trabalho contribuído que você recebeu a este branch de tópico e determinar se deseja mesclá-lo (merge) em seus branches de longo prazo.
Aplicando Patches a partir de E-mail
Se você receber um patch por e-mail que precisa integrar ao seu projeto, você precisa aplicar o patch no seu branch de tópico para avaliá-lo.
Existem duas maneiras de aplicar um patch enviado por e-mail: com git apply ou com git am.
Aplicando um Patch com apply
Se você recebeu o patch de alguém que o gerou com git diff ou alguma variação do comando diff do Unix (o que não é recomendado; veja a próxima seção), você pode aplicá-lo com o comando git apply.
Supondo que você tenha salvo o patch em /tmp/patch-ruby-client.patch, você pode aplicar o patch assim:
$ git apply /tmp/patch-ruby-client.patch
Isso modifica os arquivos no seu diretório de trabalho.
É quase idêntico a executar um comando patch -p1 para aplicar o patch, embora seja mais paranoico e aceite menos correspondências difusas (fuzzy matches) do que o patch.
Ele também lida com adições, exclusões e renomeações de arquivos se estiverem descritos no formato git diff, o que o patch não faz.
Finalmente, o git apply é um modelo de “aplique tudo ou aborte tudo” (apply all or abort all) onde tudo é aplicado ou nada é, enquanto o patch pode aplicar os arquivos de patch parcialmente, deixando o seu diretório de trabalho num estado estranho.
O git apply é, no geral, muito mais conservador do que o patch.
Ele não criará um commit para você — após executá-lo, você deve preparar (stage) e fazer o commit das alterações introduzidas manualmente.
Você também pode usar git apply para ver se um patch se aplica de forma limpa antes de tentar aplicá-lo de fato — você pode rodar git apply --check com o patch:
$ git apply --check 0001-see-if-this-helps-the-gem.patch
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Se não houver saída, então o patch deve se aplicar de forma limpa. Esse comando também sai com um status diferente de zero se a verificação falhar, então você pode usá-lo em scripts se quiser.
Aplicando um Patch com am
Se o contribuidor for um usuário do Git e foi bom o suficiente para usar o comando format-patch para gerar o patch dele, então o seu trabalho é mais fácil porque o patch contém as informações do autor e uma mensagem de commit para você.
Se você puder, encoraje os seus contribuidores a usar o format-patch em vez do diff para gerar patches para você.
Você só deveria ter que usar o git apply para patches legados e coisas desse tipo.
Para aplicar um patch gerado pelo format-patch, você usa o git am (o comando é chamado de am porque é usado para "aplicar uma série de patches de uma caixa de correio").
Tecnicamente, o git am foi construído para ler um arquivo mbox, que é um formato simples de texto puro (plain-text) para armazenar uma ou mais mensagens de e-mail em um único arquivo de texto.
Fica parecido com isso:
From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith <jessica@example.com>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] Add limit to log function
Limit log functionality to the first 20
Este é o começo da saída do comando git format-patch que você viu na seção anterior; ele também representa um formato de e-mail mbox válido.
Se alguém lhe enviou o patch de forma adequada por e-mail usando git send-email, e você fez o download dele no formato mbox, você pode apontar o git am para esse arquivo mbox, e ele começará a aplicar todos os patches que encontrar.
Se você executa um cliente de e-mail que pode salvar vários e-mails no formato mbox, pode salvar uma série inteira de patches num arquivo e então usar o git am para aplicá-los um de cada vez.
No entanto, se alguém fez upload de um arquivo de patch gerado via git format-patch em um sistema de tickets ou algo semelhante, você pode salvar o arquivo localmente e depois passar esse arquivo salvo no seu disco para o git am aplicá-lo:
$ git am 0001-limit-log-function.patch
Applying: Add limit to log function
Você pode ver que ele foi aplicado de forma limpa e automaticamente criou o novo commit para você.
As informações do autor são retiradas dos cabeçalhos From e Date do e-mail, e a mensagem do commit é retirada do Subject e do corpo (antes do patch) do e-mail.
Por exemplo, se esse patch foi aplicado a partir do exemplo de mbox acima, o commit gerado se pareceria com isso:
$ git log --pretty=fuller -1
commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
Author: Jessica Smith <jessica@example.com>
AuthorDate: Sun Apr 6 10:17:23 2008 -0700
Commit: Scott Chacon <schacon@gmail.com>
CommitDate: Thu Apr 9 09:19:06 2009 -0700
Add limit to log function
Limit log functionality to the first 20
A informação Commit indica a pessoa que aplicou o patch e a hora em que foi aplicado.
A informação Author (Autor) é o indivíduo que originalmente criou o patch e quando ele foi originalmente criado.
Mas é possível que o patch não seja aplicado de forma limpa.
Talvez o seu branch principal tenha divergido muito do branch a partir do qual o patch foi construído, ou o patch depende de outro patch que você ainda não aplicou.
Nesse caso, o processo git am falhará e perguntará o que você deseja fazer:
$ git am 0001-see-if-this-helps-the-gem.patch
Applying: See if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Patch failed at 0001.
When you have resolved this problem run "git am --resolved".
If you would prefer to skip this patch, instead run "git am --skip".
To restore the original branch and stop patching run "git am --abort".
Este comando coloca marcadores de conflito em quaisquer arquivos com os quais tenha problemas, muito parecido com uma operação de merge ou rebase em conflito.
Você resolve esse problema da mesma maneira — edite o arquivo para resolver o conflito, prepare (stage) o novo arquivo, e então execute git am --resolved para continuar com o próximo patch:
$ (fix the file)
$ git add ticgit.gemspec
$ git am --resolved
Applying: See if this helps the gem
Se você quiser que o Git tente resolver o conflito de forma um pouco mais inteligente, você pode passar uma opção -3 para ele, o que faz com que o Git tente um merge de três vias (three-way merge).
Essa opção não está ativada por padrão porque ela não funciona se o commit no qual o patch diz que foi baseado não estiver no seu repositório.
Se você tiver esse commit — se o patch for baseado em um commit público — então a opção -3 é geralmente muito mais inteligente para aplicar um patch conflitante:
$ git am -3 0001-see-if-this-helps-the-gem.patch
Applying: See if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
No changes -- Patch already applied.
Neste caso, sem a opção -3, o patch teria sido considerado como um conflito.
Como a opção -3 foi usada, o patch foi aplicado de forma limpa.
Se você estiver aplicando vários patches a partir de um mbox, você também pode executar o comando am no modo interativo, que para em cada patch que encontra e pergunta se você deseja aplicá-lo:
$ git am -3 -i mbox
Commit Body is:
--------------------------
See if this helps the gem
--------------------------
Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all
Isso é bom se você tiver vários patches salvos, porque você pode visualizar o patch primeiro se não se lembrar do que se trata, ou não aplicar o patch se já o tiver feito.
Quando todos os patches para o seu tópico forem aplicados e tiverem sido confirmados (committed) no seu branch, você pode escolher se e como integrá-los em um branch de longa duração.
Fazendo Checkout de Branches Remotos
Se a sua contribuição veio de um usuário do Git que configurou seu próprio repositório, fez o push de várias alterações para ele e depois lhe enviou a URL do repositório e o nome do branch remoto onde as alterações estão, você pode adicioná-lo como remoto e fazer os merges localmente.
Por exemplo, se Jessica lhe enviar um e-mail dizendo que ela tem um ótimo novo recurso no branch ruby-client de seu repositório, você pode testá-lo adicionando o remoto e fazendo checkout desse branch localmente:
$ git remote add jessica https://github.com/jessica/myproject.git
$ git fetch jessica
$ git checkout -b rubyclient jessica/ruby-client
Se ela lhe enviar um e-mail novamente mais tarde com outro branch contendo outro ótimo recurso, você poderia fazer um fetch e checkout diretamente porque já tem a configuração do remoto.
Isso é mais útil se você estiver trabalhando com uma pessoa de forma consistente. Se alguém tiver apenas um único patch para contribuir de vez em quando, então aceitá-lo por e-mail pode consumir menos tempo do que exigir que todos executem seus próprios servidores e ter que adicionar e remover remotos continuamente para obter alguns patches. Também é improvável que você queira ter centenas de remotos, cada um para alguém que contribui com apenas um ou dois patches. No entanto, scripts e serviços hospedados podem facilitar isso — depende muito de como você desenvolve e como os seus contribuidores desenvolvem.
A outra vantagem dessa abordagem é que você também obtém o histórico dos commits.
Embora você possa ter problemas de merge legítimos, você sabe em que ponto da sua história o trabalho deles se baseia; um merge de três vias adequado é o padrão em vez de ter que fornecer um -3 e torcer para que o patch tenha sido gerado a partir de um commit público ao qual você tem acesso.
Se você não estiver trabalhando com uma pessoa consistentemente, mas ainda assim quiser fazer um pull dela dessa maneira, pode fornecer a URL do repositório remoto ao comando git pull.
Isso faz um pull único e não salva a URL como uma referência de remoto:
$ git pull https://github.com/onetimeguy/project
From https://github.com/onetimeguy/project
* branch HEAD -> FETCH_HEAD
Merge made by the 'recursive' strategy.
Determinando o Que é Introduzido
Agora você tem um branch de tópico que contém o trabalho contribuído. Neste ponto, você pode determinar o que gostaria de fazer com ele. Esta seção revisita alguns comandos para que você possa ver como pode usá-los para revisar exatamente o que você introduzirá se fizer o merge disto no seu branch principal.
Muitas vezes é útil obter uma revisão de todos os commits que estão neste branch mas que não estão no seu branch master.
Você pode excluir os commits no branch master adicionando a opção --not antes do nome do branch.
Isso faz a mesma coisa que o formato master..contrib que usamos anteriormente.
Por exemplo, se o seu contribuidor lhe enviar dois patches e você criar um branch chamado contrib e aplicou esses patches lá, você pode executar isto:
$ git log contrib --not master
commit 5b6235bd297351589efc4d73316f0a68d484f118
Author: Scott Chacon <schacon@gmail.com>
Date: Fri Oct 24 09:53:59 2008 -0700
See if this helps the gem
commit 7482e0d16d04bea79d0dba8988cc78df655f16a0
Author: Scott Chacon <schacon@gmail.com>
Date: Mon Oct 22 19:38:36 2008 -0700
Update gemspec to hopefully work better
Para ver as alterações que cada commit introduz, lembre-se de que você pode passar a opção -p para o git log e ele anexará o diff introduzido a cada commit.
Para ver um diff completo do que aconteceria se você fosse mesclar esse branch de tópico com outro branch, você pode ter que usar um truque estranho para obter os resultados corretos. Você pode pensar em executar isso:
$ git diff master
Este comando fornece um diff, mas pode ser enganoso.
Se o seu branch master avançou desde que você criou o branch de tópico a partir dele, então você obterá resultados aparentemente estranhos.
Isso acontece porque o Git compara diretamente os snapshots do último commit do branch de tópico em que você está e o snapshot do último commit no branch master.
Por exemplo, se você adicionou uma linha num arquivo no branch master, uma comparação direta dos snapshots fará parecer que o branch de tópico vai remover essa linha.
Se o master for um ancestral direto do seu branch de tópico, isso não é um problema; mas se as duas histórias tiverem divergido, o diff fará parecer que você está adicionando todas as coisas novas no seu branch de tópico e removendo tudo o que é exclusivo do branch master.
O que você realmente quer ver são as alterações adicionadas ao branch de tópico — o trabalho que você introduzirá se mesclar esse branch com o master.
Você faz isso fazendo com que o Git compare o último commit no seu branch de tópico com o primeiro ancestral comum que ele tem com o branch master.
Tecnicamente, você pode fazer isso descobrindo explicitamente o ancestral comum e então rodando o seu diff sobre ele:
$ git merge-base contrib master
36c7dba2c95e6bbb78dfa822519ecfec6e1ca649
$ git diff 36c7db
ou, de forma mais concisa:
$ git diff $(git merge-base contrib master)
No entanto, nenhum desses é particularmente conveniente, então o Git fornece outra abreviação (shorthand) para fazer a mesma coisa: a sintaxe de três pontos (triple-dot syntax).
No contexto do comando git diff, você pode colocar três pontos após outro branch para fazer um diff entre o último commit do branch em que você está e o seu ancestral comum com o outro branch:
$ git diff master...contrib
Esse comando mostra apenas o trabalho que o seu atual branch de tópico introduziu desde o seu ancestral comum com o master.
Essa é uma sintaxe muito útil para se lembrar.
Integrando o Trabalho Contribuído
Quando todo o trabalho no seu branch de tópico estiver pronto para ser integrado a um branch de linha principal (mainline branch), a questão é como fazê-lo. Além disso, qual fluxo de trabalho geral você deseja usar para manter o seu projeto? Você tem várias opções, então abordaremos algumas delas.
Fluxos de Trabalho de Merge
Um fluxo de trabalho básico é simplesmente mesclar todo esse trabalho diretamente no seu branch master.
Neste cenário, você tem um branch master que contém código basicamente estável.
Quando você tem trabalho num branch de tópico que você acha que concluiu, ou trabalho com o qual outra pessoa contribuiu e você verificou, você o mescla no seu branch master, exclui o branch de tópico recém-mesclado e repete.
Por exemplo, se temos um repositório com trabalho em dois branches chamados ruby_client e php_client que se parece com Histórico com vários branches de tópicos, e mesclamos ruby_client seguido de php_client, o seu histórico acabará ficando parecido com Após um merge de branch de tópico.
Esse é provavelmente o fluxo de trabalho mais simples, mas pode possivelmente ser problemático se você estiver lidando com projetos maiores ou mais estáveis, onde você quer ser muito cuidadoso com o que introduz.
Se você tem um projeto mais importante, talvez queira usar um ciclo de merge de duas fases.
Neste cenário, você tem dois branches de longa duração, master e develop, em que você determina que o master é atualizado apenas quando uma versão (release) muito estável é criada, e todo o novo código é integrado ao branch develop.
Você faz regularmente o push de ambos os branches para o repositório público.
Toda vez que você tem um novo branch de tópico para mesclar (Antes de um merge de branch de tópico), você o mescla em develop (Após um merge de branch de tópico); em seguida, quando você cria uma tag de um lançamento, você faz um fast-forward do master para onde quer que o agora estável branch develop esteja (Após um lançamento (release) do projeto).
Desta forma, quando as pessoas clonarem o repositório do seu projeto, elas podem fazer o checkout do master para construir a versão estável mais recente e manter-se atualizadas com facilidade, ou podem fazer o checkout do develop, que é o conteúdo mais inovador (cutting-edge).
Você também pode estender esse conceito tendo um branch integrate onde todo o trabalho é mesclado.
Então, quando a base de código nesse branch estiver estável e passar nos testes, você o mescla em um branch develop; e quando ele provar estar estável por um tempo, você faz um fast-forward no seu branch master.
Fluxos de Trabalho de Mesclagem em Grande Escala
O projeto Git tem quatro branches de longa duração: master, next, e seen (antigamente 'pu' — proposed updates, ou atualizações propostas) para trabalhos novos, e maint para backports de manutenção.
Quando um novo trabalho é introduzido por contribuidores, ele é coletado em branches de tópicos no repositório do mantenedor de uma maneira semelhante à que descrevemos (veja Gerenciando uma série complexa de branches de tópicos contribuídos paralelamente).
Neste ponto, os tópicos são avaliados para determinar se eles são seguros e estão prontos para consumo ou se precisam de mais trabalho.
Se forem seguros, eles são mesclados em next, e esse branch recebe um push para que todos possam testar os tópicos integrados juntos.
Se os tópicos ainda precisarem de trabalho, eles são mesclados em seen.
Quando for determinado que eles estão totalmente estáveis, os tópicos são mesclados novamente em master.
Os branches next e seen são então reconstruídos a partir de master.
Isso significa que o master quase sempre se move para frente, o next sofre rebase ocasionalmente e o seen sofre rebase ainda com mais frequência:
Quando um branch de tópico finalmente é mesclado no master, ele é removido do repositório.
O projeto Git também tem um branch maint originado a partir do fork do último lançamento, a fim de fornecer patches de backport caso um lançamento de manutenção seja necessário.
Assim, quando você clona o repositório Git, você tem quatro branches nos quais pode fazer checkout para avaliar o projeto em diferentes estágios de desenvolvimento, dependendo do quão inovador você deseja ser ou de como deseja contribuir; e o mantenedor tem um fluxo de trabalho estruturado para ajudá-lo a examinar (vet) novas contribuições.
O fluxo de trabalho do projeto Git é especializado.
Para entender claramente isso, você poderia conferir o Guia do Mantenedor do Git.
Fluxos de Trabalho de Rebase e Cherry-Pick
Outros mantenedores preferem fazer rebase ou cherry-pick do trabalho contribuído no topo do seu branch master, em vez de fazer o merge dele, para manter um histórico majoritariamente linear.
Quando você tem trabalho em um branch de tópico e determina que deseja integrá-lo, você se move para esse branch e executa o comando rebase para reconstruir as alterações no topo do seu branch master (ou develop, e assim por diante) atual.
Se isso funcionar bem, você pode fazer um fast-forward no seu branch master, e acabará com um histórico de projeto linear.
A outra maneira de mover o trabalho introduzido de um branch para outro é fazer o cherry-pick dele. Um cherry-pick no Git é como um rebase para um único commit. Ele pega o patch que foi introduzido em um commit e tenta reaplicá-lo no branch em que você está no momento. Isso é útil se você tem vários commits num branch de tópico e quer integrar apenas um deles, ou se tem apenas um commit num branch de tópico e prefere fazer o cherry-pick em vez de executar o rebase. Por exemplo, suponha que você tenha um projeto parecido com este:
Se você quiser puxar (pull) o commit e43a6 para o seu branch master, você pode executar:
$ git cherry-pick e43a6
Finished one cherry-pick.
[master]: created a0a41a9: "More friendly message when locking the index fails."
3 files changed, 17 insertions(+), 3 deletions(-)
Isso puxa a mesma alteração introduzida em e43a6, mas você obtém um novo valor SHA-1 de commit, porque a data de aplicação é diferente.
Agora o seu histórico se parece com isso:
Agora você pode remover o seu branch de tópico e descartar os commits que você não quis puxar.
Rerere
Se você está fazendo muitos merges e rebases, ou está mantendo um branch de tópico de longa vida, o Git tem um recurso chamado “rerere” que pode ajudar.
Rerere significa “reuse recorded resolution” (reutilizar resolução registrada) — é uma forma de atalhar a resolução manual de conflitos. Quando o rerere está ativado, o Git mantém um conjunto de pré e pós-imagens de merges bem-sucedidos e, se perceber que há um conflito exatamente igual a um que você já corrigiu, ele usará a correção da última vez, sem incomodá-lo com isso.
Esse recurso vem em duas partes: uma configuração e um comando.
A configuração é rerere.enabled, e é útil o suficiente para ser colocada em sua configuração global:
$ git config --global rerere.enabled true
Agora, sempre que você fizer um merge que resolva conflitos, a resolução será registrada no cache, caso você precise dela no futuro.
Se precisar, você pode interagir com o cache do rerere usando o comando git rerere.
Quando é invocado sozinho, o Git verifica seu banco de dados de resoluções e tenta encontrar uma correspondência com quaisquer conflitos de merge atuais e resolvê-los (embora isso seja feito automaticamente se rerere.enabled estiver definido como true).
Existem também subcomandos para ver o que será registrado, para apagar resoluções específicas do cache e para limpar todo o cache.
Cobriremos o rerere em mais detalhes em Rerere.
Adicionando Tags aos Seus Lançamentos
Quando você tiver decidido cortar um lançamento (release), provavelmente desejará atribuir uma tag para poder recriar esse lançamento em qualquer momento no futuro. Você pode criar uma nova tag conforme discutido em Fundamentos do Git. Se você decidir assinar a tag como mantenedor, a marcação com tag pode se parecer com isso:
$ git tag -s v1.5 -m 'my signed 1.5 tag'
You need a passphrase to unlock the secret key for
user: "Scott Chacon <schacon@gmail.com>"
1024-bit DSA key, ID F721C45A, created 2009-02-09
Se você realmente assinar as suas tags, pode ter o problema de distribuir a chave pública PGP usada para assinar as suas tags.
O mantenedor do projeto Git resolveu esse problema incluindo a sua chave pública como um blob no repositório e então adicionando uma tag que aponta diretamente para esse conteúdo.
Para fazer isso, você pode descobrir qual chave deseja executando gpg --list-keys:
$ gpg --list-keys
/Users/schacon/.gnupg/pubring.gpg
---------------------------------
pub 1024D/F721C45A 2009-02-09 [expires: 2010-02-09]
uid Scott Chacon <schacon@gmail.com>
sub 2048g/45D02282 2009-02-09 [expires: 2010-02-09]
Em seguida, você pode importar diretamente a chave para o banco de dados do Git, exportando-a e passando o resultado via pipe pelo git hash-object, que grava um novo blob com esse conteúdo no Git e retorna o SHA-1 do blob para você:
$ gpg -a --export F721C45A | git hash-object -w --stdin
659ef797d181633c87ec71ac3f9ba29fe5775b92
Agora que você tem o conteúdo de sua chave no Git, pode criar uma tag que aponte diretamente para ele, especificando o novo valor SHA-1 que o comando hash-object lhe deu:
$ git tag -a maintainer-pgp-pub 659ef797d181633c87ec71ac3f9ba29fe5775b92
Se você rodar git push --tags, a tag maintainer-pgp-pub será compartilhada com todos.
Se alguém quiser verificar uma tag, eles podem importar diretamente a sua chave PGP, retirando o blob diretamente do banco de dados e importando-o para o GPG:
$ git show maintainer-pgp-pub | gpg --import
Eles podem usar essa chave para verificar todas as suas tags assinadas.
Além disso, se você incluir instruções na mensagem da tag, rodar git show <tag> permitirá que você dê ao usuário final instruções mais específicas sobre a verificação de tags.
Gerando um Número de Build
Como o Git não possui números monotonicamente crescentes como 'v123' ou o equivalente para acompanhar cada commit, se você deseja ter um nome legível por humanos para acompanhar um commit, você pode rodar o git describe nesse commit.
Em resposta, o Git gera uma string que consiste no nome da tag mais recente anterior a esse commit, seguida pelo número de commits desde essa tag e, finalmente, por um valor SHA-1 parcial do commit que está sendo descrito (prefixado com a letra "g" que significa Git):
$ git describe master
v1.6.2-rc1-20-g8c5b85c
Dessa forma, você pode exportar um snapshot ou build e nomeá-lo com algo compreensível para as pessoas.
Na verdade, se você compilar o Git a partir do código-fonte clonado do repositório Git, o git --version lhe dará algo que se parece com isto.
Se você estiver descrevendo um commit que marcou diretamente com uma tag, ele lhe dará simplesmente o nome da tag.
Por padrão, o comando git describe requer tags anotadas (tags criadas com a flag -a ou -s); se você quiser aproveitar também as tags leves (lightweight tags, não anotadas), adicione a opção --tags ao comando.
Você também pode usar essa string como o alvo de um comando git checkout ou git show, embora ele dependa do valor SHA-1 abreviado no final, portanto pode não ser válido para sempre.
Por exemplo, o kernel do Linux pulou recentemente de 8 para 10 caracteres para garantir a exclusividade do objeto SHA-1, portanto, nomes de saída mais antigos do git describe foram invalidados.
Preparando um Lançamento (Release)
Agora você quer lançar (release) um build.
Uma das coisas que você vai querer fazer é criar um arquivo compactado (archive) do snapshot mais recente do seu código para aquelas pobres almas que não usam o Git.
O comando para fazer isso é git archive:
$ git archive master --prefix='project/' | gzip > `git describe master`.tar.gz
$ ls *.tar.gz
v1.6.2-rc1-20-g8c5b85c.tar.gz
Se alguém abrir esse tarball, obterá o snapshot mais recente do seu projeto dentro de um diretório project.
Você também pode criar um arquivo zip da mesma maneira, mas passando a opção --format=zip para o git archive:
$ git archive master --prefix='project/' --format=zip > `git describe master`.zip
Agora você tem um belo tarball e um arquivo zip do lançamento do seu projeto que você pode fazer upload para o seu site ou enviar por e-mail para as pessoas.
O Shortlog
É hora de enviar um e-mail para a sua lista de discussão de pessoas que querem saber o que está acontecendo no seu projeto.
Uma maneira legal de obter rapidamente uma espécie de changelog do que foi adicionado ao seu projeto desde o seu último lançamento ou e-mail é usar o comando git shortlog.
Ele resume todos os commits no intervalo que você fornece; por exemplo, o seguinte lhe dá um resumo de todos os commits desde o seu último lançamento, se o seu último lançamento se chamasse v1.0.1:
$ git shortlog --no-merges master --not v1.0.1
Chris Wanstrath (6):
Add support for annotated tags to Grit::Tag
Add packed-refs annotated tag support.
Add Grit::Commit#to_patch
Update version and History.txt
Remove stray `puts`
Make ls_tree ignore nils
Tom Preston-Werner (4):
fix dates in history
dynamic version method
Version bump to 1.0.2
Regenerated gemspec for version 1.0.2
Você obtém um resumo limpo de todos os commits desde a v1.0.1, agrupados por autor, que você pode enviar por e-mail para a sua lista.