X-Git-Url: http://git.cascardo.eti.br/?p=cursogit.git;a=blobdiff_plain;f=Colaborando_com_Git.mdwn;h=373ff00385af2f62374779cc216503deb4b7b097;hp=cb498cd85d059588814347e77c9715abd9264655;hb=HEAD;hpb=81bb518f8fc4ef898ac8c777072c33b2cb635ce3 diff --git a/Colaborando_com_Git.mdwn b/Colaborando_com_Git.mdwn index cb498cd..373ff00 100644 --- a/Colaborando_com_Git.mdwn +++ b/Colaborando_com_Git.mdwn @@ -99,4 +99,206 @@ renomear, o subcomando rename. ## Fazendo atualizações +Após adicionar um remoto, queremos fazer o download dos branches e +commits remotos. Um dos comandos que pode ser utilizado é git fetch. + + ~/project$ git fetch alice + From git://alice.example.com/project.git/ + * [new branch] master -> alice/master + * [new branch] shell -> alice/shell + ~/project$ git branch -r + alice/master + alice/shell + origin/HEAD -> origin/master + origin/devel + origin/master + ~/project$ + +Note que ao realizar o fetch, diferente do clone, não é criada uma +referência ao HEAD do repositório remoto. Tampouco, é criado um branch +local, ou feito um checkout. As referências, no entanto, são escritas +localmente, de tal forma que é possível investigar os commits dos +branches remotos sem novo acesso à rede. + +Como o acesso à rede não é feito a cada comando, novas atualizações +precisam ser feitas quando o repositório remoto é atualizado e deseja-se +investigar novos branches ou novos commits. Além de git fetch, pode ser +utilizado git remote update. + + ~/project$ git remote update + Fetching origin + Fetching alice + From git://alice.example.com/project.git/ + * [new branch] devel -> alice/devel + ~/project$ + +Veja que um novo branch foi atualizado. + +## Branches remotos + +Agora que temos uma lista de branches remotos, podemos manipulá-los como +branches locais, usando git log, git diff, entre outros comandos. +Podemos fazer um checkout de um branch remoto, criando um branch local. + + ~/project$ git checkout -b shell alice/shell + Branch shell set up to track remote branch shell from alice. + Switched to a new branch 'shell' + ~/project$ git branch -vv + master 033d4b8 [origin/master] Acrescenta lista de arquivos a serem ignorados. + * shell a5cb5bb [alice/shell] Implementação de hello em shell script. + ~/project$ + +A opção -vv de git branch mostra o commit ID, o sumário do commit, e o +branch remoto que é rastreado pelo branch local. O rastreamento de um +branch local é importante para comandos como git push e git pull, que +veremos logo mais. + +## Atualizando repositórios remotos + +Após clonar ou adicionar um repositório remoto com uma URL que permite +escrita, poderemos atualizá-lo através do comando git push. + +O comportamento de git push sofreu alterações ao longo das versões de +Git. Veremos alguns destes comportamentos padrões, e como utilizar +parâmetros explícitos para evitar surpresas. + + ~/project$ git add hello.c + ~/project$ git commit -m "Utiliza world sem capitalização" + [master 18c7b69] Utiliza world sem capitalização + 1 file changed, 1 insertion(+), 1 deletion(-) + ~/project$ git push origin master:master + Counting objects: 3, done. + Delta compression using up to 4 threads. + Compressing objects: 100% (3/3), done. + Writing objects: 100% (3/3), 321 bytes | 0 bytes/s, done. + Total 3 (delta 2), reused 0 (delta 0) + To /home/user2/project + 033d4b8..18c7b69 master -> master + ~/project$ + +Adicionamos um novo commit ao nosso histórico, e fazemos uma atualização +no repositório remoto origin. O primeiro parâmetro é o repositório +remoto que queremos atualizar. O segundo parâmetro, chamado refspec, +especifica o branch local e o branch remoto que serão sincronizados. + +No exemplo acima, o branch local master foi utilizado para atualizar o +branch remoto master. Objetos são escritos no repositório remoto, e a +referência atualizada. + +Note que o branch de origem deve conter todos os commits no branch de +destino a ser atualizado. Caso contrário, o push não avançará o branch +remoto, o que chamamos de fast-forward. Veremos mais à frente as +condições para termos uma situação de fast-forward. + +Tanto o remoto quanto o refspec podem ser omitidos. O padrão em versões +anteriores à versão 2.0.0 do Git era fazer o push de todos os branches +com nomes iguais ao repositório remoto especificado explicitamente ou +implicitamente. Se o remoto não é especificado, é assumido o remoto que +o branch corrente rastreia. + +No exemplo sobre Branches remotos acima, o branch local shell rastreia o +branch remoto alice/shell. Caso este branch seja o branch corrente, git +push utilizaria por padrão o repositório remoto alice. O refspec +matching, como é chamado o padrão utilizado em versões anteriores à Git +2.0.0, atualizaria todos os branches no remoto alice que tivessem um +branch local com o mesmo nome. Ou seja, se alice tivesse branches +master, devel e shell, e estes mesmos branches existissem localmente, +todos seriam atualizados. Ainda que o branch local master rastreasse o +branch remoto origin/master, alice/master seria atualizado neste caso +específico. Se o branch corrente fosse master, que rastreasse +origin/master, o repositório remoto origin seria atualizado no lugar do +repositório remoto alice. + +O novo padrão, a partir da versão 2.0.0, se chama simple. Ele atualiza +apenas o branch atual, apenas se o branch remoto rastreado tiver o mesmo +nome. + +As outras opções, sendo todas elas configuráveis globalmente ou por +repositório, através da opção push.default, são upstream, current e +nothing. A opção nothing exige que o refspec esteja explícito na linha +de comando. A opção current atualiza no remoto especificado ou ímplicito +o branch com o mesmo nome que o branch local corrente. E a opção +upstream atualiza o branch remoto rastreado pelo branch corrente. + +## Repositórios bare + +É importante mencionar que ao realizar push em um repositório com um +diretório de trabalho, o diretório de trabalho e o índice não são +atualizados, mesmo que o branch corrente seja o branch atualizado. Isto +pode causar problemas, caso o diretório de trabalho seja atualizado. +Portanto, o padrão em versões desde 1.7.0 é impedir que tal branch seja +atualizado, a não ser que a opção de configuração +receive.denyCurrentBranch utilize os valores warn, false ou ignore. + +Anteriormente à versão 1.7.0, o diretório de trabalho era atualizado +quando um push era feito. Isso poderia ser perigoso, pois o diretório de +trabalho poderia conter alterações que não foram gravadas, causando a +perda de dados. + +Mas existe um tipo de repositório que não possui diretório de trabalho, +e pode evitar problemas como esses. Este tipo de repositório é conhecido +como repositório bare. Ele pode ser criado com a opção --bare de git +init ou de git clone. Geralmente, por convenção, tais repositórios têm a +URL terminada em .git. + + $ git clone --bare project/ project.git/ + Cloning into bare repository 'project.git'... + done. + $ + ## Publicando um repositório + +Vimos como trabalhar com um repositório remoto, obtendo seus commits +para trablharmos localmente. No entanto, o caminho reverso é necessário +para publicarmos os commits locais para que outros possam trabalhar com +eles. + +Há várias formas de fazê-lo. Veremos aqui algumas delas, utilizando um +host próprio, que seja acessível ao público alvo, através de SSH, HTTP +ou git daemon. + +### SSH + +Publicar através de SSH é simples de ser feito, mas tem algumas +implicações. Entre elas é o acesso exigido a um shell no host para os +usuários, dificultando acesso anônimo e criando um novo problema de +segurança a ser resolvido. A outra implicação é que o acesso por +múltiplos usuários a um mesmo repositório exige um cuidado especial para +evitar problemas de permissão quando um usuário publica novos commits e +outros objetos. Há algumas soluções que resolvem alguns desses +problemas, criando um shell e um usuário especial para uso dedicado a +repositórios Git. Veremos, no entanto, apenas a solução mais comum, que +não exige outro software instalado no host, além de Git. + +Uma excelente forma de utilizar a publicação via SSH é disponibilizá-la +de forma somente leitura através de outros métodos, e ter um único +usuário que possa atualizá-lo, o que resolve vários dos problemas já +mencionados. + +Há duas formas simples para publicar um repositório via SSH. Uma delas é +criar um bare clone do repositório e fazer a cópia para o host remoto, +através do método de preferência. Uma opção é scp. + + $ git clone --bare project/ + Cloning into bare repository 'project.git'... + done. + $ scp -rq project.git/ git.example.com:/srv/git/alice/ + $ + +A outra opção é criar um repositório bare no host remoto, e fazer o +primeiro push. + + alice@git.example.com $ mkdir project.git + alice@git.example.com $ cd project.git + alice@git.example.com project.git$ git init --bare + Initialized empty Git repository in /srv/git/alice/project.git/ + alice@git.example.com project.git$ + + ~/project$ git remote add origin git.example.com:/srv/git/alice/project.git/ + ~/project$ git push origin master:master + Counting objects: 3, done. + Writing objects: 100% (3/3), 229 bytes, done. + Total 3 (delta 0), reused 0 (delta 0) + To git.example.com:/srv/git/alice/project.git/ + * [new branch] master -> master + ~/project$