Migrando repositorio Git
Tags: git, tutorial, devops, braziliandevs
Published: 2023-03-22 11:26:21

Com as constantes aquisições de empresas no mercado de TI é bem comum ter que migrar o repositório de código que estava em um repositório remoto para outro, às vezes em produtos diferentes. 

Pensando no cenário de migração de repositório remoto de soluções diferentes, do GitHub para o Azure Devops, por exemplo, a migração pode se tornar um pouco mais complexa. Veja, você precisa migrar o histórico do projeto por completo com branchs, tags e notes. 

Primeiro, crie o repositório de destino para nossa migração, vamos utilizar ele no script. 

Para isso criei um pequeno script bash na qual vou explicar aqui linha a linha antes de mostrar por completo, vejamos:

```bash
set -eufo pipefail
```

O comando "set -eufo pipefail" é um conjunto de opções que pode ser usado em scripts de shell, como o Bash, para modificar o comportamento padrão do ambiente do shell.

Uma explicação mais detalhada de cada uma das opções incluídas no comando:

* "set -e": Encerra o script imediatamente caso um comando falhe ou retorne um status diferente de zero. Isso ajuda a evitar que erros passem despercebidos e ajuda a garantir que o script pare em caso de falha.
* "set -u": Faz com que o shell gere um erro caso uma variável não definida seja referenciada. Isso pode ajudar a evitar erros que possam ocorrer quando uma variável é usada sem ter sido previamente inicializada.
* "set -f": Desativa a expansão de nomes de arquivos com caracteres curinga (como * e ?), o que pode ser útil em scripts que lidam com arquivos com nomes não convencionais ou que podem conter espaços ou outros caracteres especiais.
* "set -o pipefail": Faz com que um pipeline (comando composto por vários comandos conectados com o operador |) retorne o status de saída do último comando que falhou, em vez de retornar o status de saída do último comando executado com sucesso. Isso pode ser útil em pipelines complexos, onde é importante detectar falhas em qualquer ponto do pipeline.

O comando "set -eufo pipefail" ajuda a garantir que o script seja executado de forma confiável e consistente, evitando erros comuns que podem levar a falhas ou a comportamentos inesperados. Ele é especialmente útil em scripts que executam tarefas críticas ou lidam com dados sensíveis, onde a confiabilidade é essencial.

```bash
SOURCE_URL=https://repositorio_git_origem.git
TARGET_URL=https://repositorio_git_alvo.git
```

SOURCE_URL será a URL Git do repositório que queremos copiar
TARGET_URL será a URL Git do repositório alvo que queremos que fique igual ao repositório da SOURCE_URL

```bash
WORKDIR=./repos
```

Apenas para organização criei um diretório de trabalho local.

```bash
echo "Cloning from ${SOURCE_URL} into ${WORKDIR}..."
git init --bare "${WORKDIR}"
cd "${WORKDIR}"
```

O –bare cria um repositório vazio. Se GIT_DIRo ambiente não estiver definido, ele será definido no diretório de trabalho atual. Ao incializar um repositório como bare não será permitido editar arquivos (git add) e commitar mudanças (git commit), já que o mesmo não possui uma working tree.

Utilizo o –bare para garantir que não tenha nenhuma mudança no meio do processo de migração. 

```bash
git config remote.origin.url "${SOURCE_URL}"
```

Esse comando é utilizado para definir a URL de um repositório Git remoto

```bash
git config --add remote.origin.fetch '+refs/heads/*:refs/heads/*'
```

O comando git config --add remote.origin.fetch adicionam uma nova configuração no git para o repositório atual.

O parâmetro --add diz ao git para adicionar essa configuração em vez de substituir configurações existentes.

remote.origin.fetch define o nome da configuração que está sendo adicionada. Essa configuração especifica como o Git deve buscar as alterações dos ramos do repositório remoto (chamado de "origin").

O valor '+refs/heads/:refs/heads/' é uma expressão que especifica que o git deve buscar todas as branches (ramificações) do repositório remoto. O primeiro * representa todas as branches no repositório remoto, e o segundo * representa todas as branches locais no repositório local. O sinal de + antes de refs/heads/* indica que, além de buscar os branches existentes, também deve-se adicionar novos branches que possam ser criados no repositório remoto.

Essa configuração diz ao git para buscar todas as branches do repositório remoto chamado "origin" e adicioná-las ao repositório local.

```bash
git config --add remote.origin.fetch '+refs/tags/*:refs/tags/*'
```

O sinal de + antes de refs/tags/* indica que, além de buscar as tags existentes, também deve-se adicionar novas tags que possam ser criadas no repositório remoto.

Essa configuração diz ao git para buscar todas as tags do repositório remoto chamado "origin" e adicioná-las ao repositório local.

```bash
git config --add remote.origin.fetch '+refs/notes/*:refs/notes/*'
```

O sinal de + antes de refs/notes/* indica que, além de buscar as notas existentes, também deve-se adicionar novas notas que possam ser criadas no repositório remoto.

Essa configuração diz ao git para buscar todas as notas do repositório remoto chamado "origin" e adicioná-las ao repositório local.

```bash
git config remote.origin.mirror true
```

A opção mirror é usada para especificar se o repositório local deve espelhar todos os dados do repositório remoto. Quando essa opção é definida como true, isso indica que todas as alterações feitas no repositório remoto devem ser automaticamente sincronizadas com o repositório local.

Quando essa opção está ativada, todas as operações de push, fetch e pull serão direcionadas ao repositório remoto origin, e o repositório local será atualizado automaticamente para refletir todas as alterações no repositório remoto, ou seja, define que o repositório remoto origin deve ser espelhado no repositório local e que todas as alterações no repositório remoto devem ser automaticamente sincronizadas com o repositório local.

```bash
git fetch --all
```

Este comando é usado para atualizar todas as referências de um repositório local com as alterações mais recentes do repositório remoto.

O parâmetro --all indica que o comando deve buscar atualizações para todas as branches (ramificações), tags e notas no repositório remoto.

Quando executado, o comando git fetch --all irá buscar todas as alterações no repositório remoto, mas não as mesclar automaticamente com a branch atual. Em vez disso, ele atualizará as referências locais para refletir as alterações mais recentes no repositório remoto.

Isso é útil quando você deseja verificar o estado atual do repositório remoto sem mesclar as alterações com seu repositório local.

```bash
echo ""
echo "Cloned to ${WORKDIR}; pushing to ${TARGET_URL}"
```

Apenas um print para deixar tudo mais visual 

```bash
git push --mirror "${TARGET_URL}"
```

Ao executar o comando git push --mirror "${TARGET_URL}", o Git irá enviar todas as alterações do repositório local para o repositório remoto especificado, sobrescrevendo quaisquer alterações existentes e excluindo referências que não existem mais no repositório local.

```bash
echo ""
echo "Cleaning up temporary directory ${WORKDIR}..."
```

Mais anotações para deixar visível a conclusão da execução. 

```bash
rm -rf "${WORKDIR}"
```

Remoção do diretorio de trabalho. 

Com isso passamos por todos os comandos do script e seu repositório foi migrado na íntegra =D

Abaixo o script completo. 

```bash
echo "Done."

bla bla bla
#!/bin/sh

set -eufo pipefail

SOURCE_URL=https://repositorio_git_origem.git
TARGET_URL=https://repositorio_git_alvo.git
WORKDIR=./repos

echo "Cloning from ${SOURCE_URL} into ${WORKDIR}..."

git init --bare "${WORKDIR}"
cd "${WORKDIR}"

git config remote.origin.url "${SOURCE_URL}"
git config --add remote.origin.fetch '+refs/heads/*:refs/heads/*'
git config --add remote.origin.fetch '+refs/tags/*:refs/tags/*'
git config --add remote.origin.fetch '+refs/notes/*:refs/notes/*'
git config remote.origin.mirror true
git fetch --all

echo ""
echo "Cloned to ${WORKDIR}; pushing to ${TARGET_URL}"

git push --mirror "${TARGET_URL}"

echo ""
echo "Cleaning up temporary directory ${WORKDIR}..."

rm -rf "${WORKDIR}"

echo "Done."
```