Exercício – Colaborar com outras pessoas usando um repositório compartilhado
O pull direto do repositório de outra pessoa funciona, desde que você esteja na mesma rede. Mas é um processo complicado, e a maioria dos colaboradores não está na mesma rede. É melhor configurar um repositório central em que todos os colaboradores possam efetuar push e pull.
Quando você conta sobre seu projeto ao seu amigo desenvolvedor Pedro e ele pede para participar, isso é exatamente o que você decide fazer: configurar um repositório central, que também é chamado de repositório simples.
Criar um repositório simples
O que você precisa é de um repositório que não tenha uma árvore de trabalho. Um repositório simples tem várias vantagens em relação a uma árvore de trabalho:
- Sem uma árvore de trabalho, todos podem efetuar push das alterações sem se preocupar com o check-out do branch.
- É fácil para o Git detectar quando outro usuário enviou por push as alterações que podem entrar em conflito com as suas.
- Um repositório compartilhado é dimensionado para qualquer número de desenvolvedores. Com um repositório simples, você precisa saber apenas sobre o repositório compartilhado, não sobre todos os outros colaboradores dos quais você pode precisar efetuar pull.
- Ao colocar o repositório compartilhado em um servidor que todos vocês podem acessar, você não precisará se preocupar com firewalls e permissões.
- Você não precisa ter contas separadas no servidor, pois o Git controla quem fez cada commit. (O GitHub tem milhões de usuários, todos compartilhando a conta
git
. Todos usam o protocolo de rede de criptografia SSH (Secure Shell), e os usuários são diferenciados pelas respectivas chaves públicas.)
É fácil criar um repositório simples para compartilhamento:
Crie um diretório chamado Shared.git no mesmo nível dos diretórios Alice e Cats para manter o repositório simples:
cd .. mkdir Shared.git cd Shared.git
O nome do diretório não é importante, mas nós nos referiremos a ele como o diretório Shared.git ou apenas o diretório compartilhado nestes exercícios.
A nomeação do diretório Shared.git segue a longa tradição de atribuição de um nome que termina com
.git
aos repositórios simples para distingui-los das árvores de trabalho. É uma convenção, mas não um requisito.Agora, use o seguinte comando para criar um repositório simples no diretório compartilhado:
git init --bare
Quando um repositório ainda é simples, o comando
git checkout
não pode ser usado para definir o nome do branch padrão. Para realizar essa tarefa, você pode alterar o branchHEAD
para que ele aponte para outro branch; nesse caso, o branchmain
:git symbolic-ref HEAD refs/heads/main
A próxima etapa é inserir o conteúdo do seu repositório no repositório compartilhado. Use estes comandos para retornar ao diretório do projeto, em que o repositório está armazenado, configurar um repositório remoto
origin
e executar um push inicial:cd ../Cats git remote add origin ../Shared.git git push origin main
Verifique a saída. A saída indicará o sucesso:
Counting objects: 12, done. Delta compression using up to 2 threads. Compressing objects: 100% (8/8), done. Writing objects: 100% (12/12), 1.07 KiB | 0 bytes/s, done. Total 12 (delta 1), reused 0 (delta 0) To ../Shared.git * [new branch] main -> main
Você deseja que
push
epull
usem o branchmain
deorigin
por padrão, como se você tivesse criado seu repositório clonando-o em primeiro lugar. Para fazer isso, você precisará informar ao Git qual branch ele deverá controlar.git branch --set-upstream-to origin/main
Verifique esta saída:
Branch main set up to track remote branch main from origin.
O Git indicará um problema se você tentar executar esse comando antes do push inicial, porque o novo repositório não tinha branches. O Git não pode controlar um branch que não existe. Tudo o que o Git faz nos bastidores é procurar em
.git/refs/remotes/origin
um arquivo chamado trunk.
Configuração para colaboradores
A próxima etapa é que Pedro clonará o repositório simples e que Alice definirá a origem no repositório dela para ser direcionada ao repositório compartilhado para pushes e pulls.
Crie um diretório chamado Pedro que seja irmão do diretório do projeto e altere para o diretório Pedro:
cd .. mkdir Bob cd Bob
Agora, clone o repositório compartilhado (inclua o ponto no final do comando):
git clone ../Shared.git .
Atualmente, o repositório de Alice está configurado para efetuar push e pull do repositório dela. Use os seguintes comandos para alterar para o diretório Alice e alterar
origin
para que ele aponte para o repositório compartilhado:cd ../Alice git remote set-url origin ../Shared.git
Começar a colaboração
Agora que Pedro está configurado para trabalhar no site, ele decide adicionar um rodapé à parte inferior da página. Vamos usar a persona de Pedro e Alice por alguns instantes e aprender os conceitos básicos da colaboração.
Comece acessando o diretório Pedro e trabalhando como ele:
cd ../Bob git config user.name Bob git config user.email bob@contoso.com
Abra index.html e substitua o elemento
<hr>
por esta linha (encontrada no final do elemento<body>
):<footer><hr>Copyright (c) 2021 Contoso Cats</footer>
Depois, salve o arquivo e feche o editor.
Confirme as alterações e efetue push para a origem remota:
git commit -a -m "Put a footer at the bottom of the page" git push
Verifique a saída. Se um aviso como o exemplo a seguir for exibido, não se preocupe. Esse aviso só informa os usuários de uma alteração nos comportamentos padrão do Git. Caso deseje ter certeza de que não verá esse aviso novamente, execute
git config --global push.default simple
.warning: push.default is unset; its implicit value has changed in Git 2.0 from 'matching' to 'simple'. To squelch this message and maintain the traditional behavior, use: git config --global push.default matching To squelch this message and adopt the new behavior now, use: git config --global push.default simple When push.default is set to 'matching', git will push local branches to the remote branches that already exist with the same name. Since Git 2.0, Git defaults to the more conservative 'simple' behavior, which only pushes the current branch to the corresponding remote branch that 'git pull' uses to update the current branch. See 'git help config' and search for 'push.default' for further information. (the 'simple' mode was introduced in Git 1.7.11. Use the similar mode 'current' instead of 'simple' if you sometimes use older versions of Git)
Embora Pedro esteja editando o site, Alice também está. Ela decide adicionar uma barra de navegação à página. Essa adição exige que ela modifique dois arquivos: index.html e site.css. Comece retornando ao diretório Alice:
cd ../Alice
Agora, abra index.html e insira a seguinte linha logo após a marca
<body>
na linha 8:<nav><a href="./index.html">home</a></nav>
Depois, salve o arquivo e feche o editor.
Em seguida, abra site.css na pasta CSS e adicione a seguinte linha na parte inferior:
nav { background-color: #C0D8DF; }
Salve o arquivo e feche o editor.
Agora, vamos supor que Alice receba um email de Pedro informando que ele fez alterações no site. Ela decide efetuar pull das alterações dele antes de fazer commit de suas próprias alterações. (Se Alice já tiver confirmado as alterações dela, ela terá um problema diferente, que será abordado em outro módulo.) Alice executa este comando:
git pull
Verifique a saída. Na saída, parece que o Git impediu um problema:
remote: Counting objects: 3, done. remote: Compressing objects: 100% (3/3), done. remote: Total 3 (delta 2), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. From ../Shared 843d142..2cf6cbf main -> origin/main Updating 843d142..2cf6cbf error: Your local changes to the following files would be overwritten by merge: index.html Please commit your changes or stash them before you can merge. Aborting
O Git avisa que o pull substituirá a versão de Alice de index.html e as alterações dela serão perdidas. Isso porque Pedro modificou index.html também. Se Alice não tivesse alterado index.html, o Git teria feito commit da mesclagem.
Use um comando
git diff
para ver as alterações que Pedro fez em index.html:git diff origin -- index.html
Verifique a saída. Na saída, fica evidente que as alterações de Alice e as alterações de Pedro não se sobrepõem. Agora, Alice pode armazenar em stash as alterações dela.
git stash
salva o estado da árvore de trabalho e do índice fazendo alguns commits temporários. Considere o stash como uma maneira de salvar seu trabalho atual enquanto você faz alguma outra coisa, sem fazer um commit "real" nem afetar o histórico do repositório.Na realidade, Alice deveria ter armazenado em stash as alterações ou feito commit delas antes de tentar efetuar pull. O pull para uma árvore de trabalho "suja" é arriscado, pois pode executar ações das quais você não poderá recuperar com facilidade.
Use o seguinte comando para aplicar stash às alterações de Alice:
git stash
Verifique a saída. Ele será semelhante a este exemplo:
Saved working directory and index state WIP on main: 95bbc3b Change background color to light blue HEAD is now at 95bbc3b Change background color to light blue
Agora, é seguro para Alice efetuar pull e, depois disso, remover o stash mais recente da pilha, que é organizado como uma pilha. (Na realidade,
git stash
é abreviatura degit stash push
. Isso é muito parecido com a pilha em que você coloca as faturas que você ainda não pagou.) Execute estes comandos:git pull git stash pop
A remoção do stash mais recente da pilha mescla as alterações. Se as alterações se sobrepuserem, poderá haver um conflito. Saiba como resolver essas situações em um módulo mais avançado do Git no Microsoft Learn.
Verifique a saída. Alice verá esta saída, que informa que a mesclagem foi bem-sucedida e que as alterações estão de volta, mas que ainda não foram preparadas para commit:
Auto-merging index.html On branch main Your branch is up-to-date with 'origin/main'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: CSS/site.css modified: index.html no changes added to commit (use "git add" and/or "git commit -a") Dropped refs/stash@{0} (0cfb7b75d56611d9fc6a6ab660a51f5582b8d9c5)
Neste ponto, ela pode continuar trabalhando ou apenas fazer commit e efetuar push das alterações. Vamos fazer outra alteração como Alice, atribuindo rodapés no mesmo estilo das barras de navegação.
Abra site.css na pasta CSS e substitua a terceira linha, aquela que define o estilo de elementos
<nav>
, por esta regra CSS compartilhada. Em seguida, como de costume, salve as alterações e feche o editor.nav, footer { background-color: #C0D8DF; }
Agora, faça commit das alterações e efetue push delas para o repositório compartilhado:
git commit -a -m "Stylize the nav bar" git push
O site atualizado agora está no repositório compartilhado.
Conclua retornando ao diretório do projeto e efetuando um pull:
cd ../Cats git pull
Abra index.html (aquele no diretório do projeto) para confirmar se as alterações feitas por Pedro e Alice estão presentes no repositório local. Verifique se index.html tem o código mais atualizado:
<!DOCTYPE html> <html> <head> <meta charset='UTF-8'> <title>Our Feline Friends</title> <link rel="stylesheet" href="CSS/site.css"> </head> <body> <nav><a href="./index.html">home</a></nav> <h1>Our Feline Friends</h1> <p>Eventually we will put cat pictures here.</p> <footer><hr>Copyright (c) 2021 Contoso Cats</footer> </body> </html>
No momento, seu repositório e o repositório de Alice estão sincronizados, mas o de Pedro não. Conclua atualizando Pedro também:
cd ../Bob git pull
Os três repositórios estão agora em alinhamento. O repositório compartilhado é a única fonte de verdade para todos os usuários, e todos os pushes e pulls são direcionados para o repositório compartilhado.
Caso você esteja curioso sobre a aparência do site, esta é uma visualização:
Se desejar, baixe seus arquivos para visualizá-los localmente:
Compacte a pasta Cats:
cd .. zip -r Cats.zip Cats
Baixe o arquivo compactado:
download Cats.zip
Agora, descompacte-o no computador local e abra index.html para vê-lo.