Como Verificar se um Commit Git é Ancestral de Outro

GitBeginner
Pratique Agora

Introdução

Neste laboratório, você aprenderá como determinar se um commit Git é um ancestral de outro. Compreender as relações ancestrais entre commits é crucial para navegar e compreender o histórico do seu projeto.

Exploraremos o comando git merge-base --is-ancestor, uma ferramenta poderosa para este propósito. Adicionalmente, utilizaremos o git log para visualizar o histórico de commits e rastrear a ancestralidade, e testaremos o comando com commits não ancestrais para solidificar sua compreensão. Ao final deste laboratório, você estará proficiente em identificar relações ancestrais dentro do seu repositório Git.

Usar git merge-base --is-ancestor

Nesta etapa, aprenderemos como usar o comando git merge-base --is-ancestor para determinar se um commit é um ancestral de outro. Este é um conceito fundamental para entender o histórico e as relações entre diferentes versões do seu projeto no Git.

Primeiramente, vamos criar um repositório Git simples e fazer alguns commits para estabelecer um histórico. Navegue até o diretório do seu projeto, caso ainda não esteja lá:

cd ~/project

Agora, crie um novo diretório para este laboratório e inicialize um repositório Git dentro dele:

mkdir git-ancestor-lab
cd git-ancestor-lab
git init

Você deve ver uma saída semelhante a esta:

Initialized empty Git repository in /home/labex/project/git-ancestor-lab/.git/

Em seguida, vamos criar nosso primeiro arquivo e fazer o commit:

echo "Initial content" > file1.txt
git add file1.txt
git commit -m "Add file1 with initial content"

Você verá uma saída confirmando o commit:

[master (root-commit) <commit-hash>] Add file1 with initial content
 1 file changed, 1 insertion(+)
 create mode 100644 file1.txt

Agora, vamos fazer outro commit. Modifique o arquivo e faça o commit das alterações:

echo "More content" >> file1.txt
git add file1.txt
git commit -m "Add more content to file1"

Você verá uma saída confirmando o segundo commit:

[master <commit-hash>] Add more content to file1
 1 file changed, 1 insertion(+)

Agora temos um histórico simples com dois commits. Vamos visualizar o log para ver os hashes dos commits:

git log --oneline

A saída será algo parecido com isto (seus hashes de commit serão diferentes):

<commit-hash-2> (HEAD -> master) Add more content to file1
<commit-hash-1> Add file1 with initial content

Nesta saída, <commit-hash-1> é o hash do primeiro commit, e <commit-hash-2> é o hash do segundo commit. O segundo commit é um descendente direto do primeiro commit. Isso significa que o primeiro commit é um ancestral do segundo commit.

O comando git merge-base --is-ancestor <ancestor-commit> <descendant-commit> verifica se o primeiro commit é um ancestral do segundo commit. Se for, o comando sai com um status de 0 (sucesso). Se não for, ele sai com um status de 1 (falha).

Vamos testar isso. Substitua <commit-hash-1> e <commit-hash-2> pelos hashes reais da sua saída git log --oneline.

git merge-base --is-ancestor <commit-hash-1> <commit-hash-2>
echo $?

O comando echo $? imprime o status de saída do comando anterior. Como <commit-hash-1> é um ancestral de <commit-hash-2>, o comando git merge-base deve ter sucesso, e a saída de echo $? deve ser 0.

Compreender a ancestralidade é crucial para muitas operações Git, como merging (fusão) e rebasing (rebase), pois ajuda o Git a determinar o histórico comum entre diferentes branches (ramificações) ou commits.

Executar git log para Rastrear a Ancestralidade

Nesta etapa, usaremos o comando git log para visualizar o histórico de commits e entender o conceito de ancestralidade de forma mais clara. O comando git log é uma ferramenta poderosa para explorar o histórico do seu repositório.

Navegue até o diretório do seu repositório, caso ainda não esteja lá:

cd ~/project/git-ancestor-lab

Já temos dois commits em nosso repositório. Vamos visualizar o log novamente, desta vez usando o formato padrão:

git log

A saída mostrará os detalhes de cada commit, incluindo o hash do commit, autor, data e mensagem do commit. Os commits são listados em ordem cronológica inversa (do mais recente para o mais antigo).

commit <commit-hash-2> (HEAD -> master)
Author: Jane Doe <jane.doe@example.com>
Date:   <Date and Time>

    Add more content to file1

commit <commit-hash-1>
Author: Jane Doe <jane.doe@example.com>
Date:   <Date and Time>

    Add file1 with initial content

Nesta saída, você pode ver que o segundo commit (<commit-hash-2>) aponta para o primeiro commit (<commit-hash-1>). É assim que o Git rastreia o histórico. Cada commit (exceto o inicial) tem um commit pai, e essa relação pai-filho define a ancestralidade.

O comando git log essencialmente percorre para trás através desta cadeia de pais, começando pelo commit atual (indicado por HEAD -> master).

Vamos adicionar outro commit para tornar o histórico um pouco mais longo:

echo "Final content" >> file1.txt
git add file1.txt
git commit -m "Add final content to file1"

Agora, execute git log --oneline novamente para ver o histórico atualizado:

git log --oneline

A saída mostrará três commits:

<commit-hash-3> (HEAD -> master) Add final content to file1
<commit-hash-2> Add more content to file1
<commit-hash-1> Add file1 with initial content

Aqui, <commit-hash-3> é o commit mais recente, <commit-hash-2> é seu pai, e <commit-hash-1> é o pai de <commit-hash-2>. Isso significa que <commit-hash-1> é um ancestral de <commit-hash-2> e <commit-hash-3>. Da mesma forma, <commit-hash-2> é um ancestral de <commit-hash-3>.

Podemos usar git merge-base --is-ancestor para verificar essas relações. Substitua os espaços reservados pelos seus hashes de commit reais.

git merge-base --is-ancestor <commit-hash-1> <commit-hash-3>
echo $?

Isso deve gerar 0 porque o primeiro commit é um ancestral do terceiro commit.

git merge-base --is-ancestor <commit-hash-2> <commit-hash-3>
echo $?

Isso também deve gerar 0 porque o segundo commit é um ancestral do terceiro commit.

Usar git log ajuda você a visualizar o gráfico de commits e entender as relações pai-filho, que se relaciona diretamente com o conceito de ancestralidade que git merge-base --is-ancestor verifica.

Testar Commits Não Ancestrais

Nas etapas anteriores, usamos git merge-base --is-ancestor para confirmar que commits anteriores eram ancestrais de commits posteriores na mesma branch. Agora, vamos explorar o que acontece quando testamos commits que não são ancestrais um do outro.

Navegue até o diretório do seu repositório:

cd ~/project/git-ancestor-lab

Atualmente, temos uma única branch (master) com três commits. Para testar relações não-ancestrais, precisamos criar uma nova branch e fazer um commit nessa branch. Isso criará um histórico divergente.

Primeiro, vamos criar uma nova branch chamada feature:

git branch feature

Este comando cria um novo ponteiro de branch chamado feature que aponta para o mesmo commit que master (nosso último commit, <commit-hash-3>).

Agora, vamos mudar para a branch feature:

git checkout feature

Você deve ver uma saída indicando que você mudou de branch:

Switched to branch 'feature'

Agora estamos na branch feature. Vamos fazer um novo commit nesta branch. Crie um novo arquivo:

echo "Feature content" > file2.txt
git add file2.txt
git commit -m "Add file2 on feature branch"

Você verá uma saída confirmando o commit na branch feature:

[feature <commit-hash-4>] Add file2 on feature branch
 1 file changed, 1 insertion(+)
 create mode 100644 file2.txt

Agora, vamos olhar para o histórico usando git log --oneline --all --graph. A flag --all mostra commits de todas as branches, e --graph desenha uma representação baseada em texto do histórico de commits.

git log --oneline --all --graph

A saída mostrará um histórico de ramificação. Pode parecer algo assim (os hashes de commit variarão):

* <commit-hash-4> (HEAD -> feature) Add file2 on feature branch
* <commit-hash-3> (master) Add final content to file1
* <commit-hash-2> Add more content to file1
* <commit-hash-1> Add file1 with initial content

Neste gráfico, <commit-hash-4> é o commit mais recente na branch feature, e <commit-hash-3> é o commit mais recente na branch master. Esses dois commits não são ancestrais um do outro. Eles compartilham um ancestral comum, que é <commit-hash-3> (o commit onde a branch feature foi criada).

Vamos usar git merge-base --is-ancestor para testar a relação entre <commit-hash-4> e <commit-hash-3>. Substitua os espaços reservados pelos seus hashes de commit reais.

git merge-base --is-ancestor <commit-hash-4> <commit-hash-3>
echo $?

Este comando verifica se <commit-hash-4> é um ancestral de <commit-hash-3>. Com base em nosso gráfico, não é. Portanto, o comando deve sair com um status de 1.

Agora, vamos testar o outro lado: <commit-hash-3> é um ancestral de <commit-hash-4>?

git merge-base --is-ancestor <commit-hash-3> <commit-hash-4>
echo $?

Este comando verifica se <commit-hash-3> é um ancestral de <commit-hash-4>. Olhando para o gráfico, o pai de <commit-hash-4> é <commit-hash-3>. Então, <commit-hash-3> é um ancestral de <commit-hash-4>. O comando deve sair com um status de 0.

Isso demonstra como git merge-base --is-ancestor pode ser usado para verificar programaticamente a relação entre quaisquer dois commits no histórico do seu repositório, mesmo em diferentes branches.

Resumo

Neste laboratório, aprendemos como usar o comando git merge-base --is-ancestor para verificar se um commit Git é um ancestral de outro. Começamos criando um repositório Git simples e fazendo alguns commits para estabelecer um histórico. Em seguida, usamos git log --oneline para visualizar o histórico de commits e identificar os hashes dos commits. Esta etapa fundamental é crucial para entender as relações entre diferentes versões de um projeto no Git.