Comment vérifier si un commit Git est accessible depuis le HEAD

GitGitBeginner
Pratiquer maintenant

💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici

Introduction

Dans ce laboratoire (lab), vous apprendrez à déterminer si un commit Git spécifique est accessible depuis le HEAD actuel. Il s'agit d'une compétence fondamentale pour comprendre l'historique de votre dépôt (repository) et identifier les commits qui font partie de la ligne de développement active.

Nous allons explorer deux méthodes principales : utiliser la commande git log --ancestry-path pour visualiser la lignée des commits entre deux points, et employer la commande git merge-base --is-ancestor pour vérifier directement l'ascendance. Vous allez pratiquer ces techniques en configurant un dépôt d'exemple (sample repository) avec plusieurs branches et commits, y compris certains qui sont intentionnellement rendus inaccessibles depuis le HEAD, vous permettant ainsi de tester et de confirmer votre compréhension.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL git(("Git")) -.-> git/SetupandConfigGroup(["Setup and Config"]) git(("Git")) -.-> git/BasicOperationsGroup(["Basic Operations"]) git(("Git")) -.-> git/BranchManagementGroup(["Branch Management"]) git/SetupandConfigGroup -.-> git/init("Initialize Repo") git/BasicOperationsGroup -.-> git/add("Stage Files") git/BasicOperationsGroup -.-> git/commit("Create Commit") git/BranchManagementGroup -.-> git/branch("Handle Branches") git/BranchManagementGroup -.-> git/checkout("Switch Branches") git/BranchManagementGroup -.-> git/merge("Merge Histories") git/BranchManagementGroup -.-> git/log("Show Commits") git/BranchManagementGroup -.-> git/reflog("Log Ref Changes") git/BranchManagementGroup -.-> git/rebase("Reapply Commits") subgraph Lab Skills git/init -.-> lab-560063{{"Comment vérifier si un commit Git est accessible depuis le HEAD"}} git/add -.-> lab-560063{{"Comment vérifier si un commit Git est accessible depuis le HEAD"}} git/commit -.-> lab-560063{{"Comment vérifier si un commit Git est accessible depuis le HEAD"}} git/branch -.-> lab-560063{{"Comment vérifier si un commit Git est accessible depuis le HEAD"}} git/checkout -.-> lab-560063{{"Comment vérifier si un commit Git est accessible depuis le HEAD"}} git/merge -.-> lab-560063{{"Comment vérifier si un commit Git est accessible depuis le HEAD"}} git/log -.-> lab-560063{{"Comment vérifier si un commit Git est accessible depuis le HEAD"}} git/reflog -.-> lab-560063{{"Comment vérifier si un commit Git est accessible depuis le HEAD"}} git/rebase -.-> lab-560063{{"Comment vérifier si un commit Git est accessible depuis le HEAD"}} end

Utiliser git log --ancestry-path

Dans cette étape, nous allons explorer comment utiliser la commande git log --ancestry-path. Cette commande est utile pour visualiser l'historique des commits le long d'un chemin spécifique entre deux commits. Elle vous aide à comprendre la lignée des modifications.

Tout d'abord, créons un simple dépôt Git (repository) et effectuons quelques commits pour configurer un scénario d'utilisation de --ancestry-path.

Accédez au répertoire de votre projet :

cd ~/project

Créez un nouveau répertoire pour ce laboratoire (lab) et initialisez un dépôt Git :

mkdir ancestry-lab
cd ancestry-lab
git init

Vous devriez voir un message indiquant qu'un dépôt Git vide a été initialisé :

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

Maintenant, créons un fichier et effectuons le premier commit :

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

Vous verrez un message confirmant le commit :

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

Ensuite, effectuons un autre commit :

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

Vous verrez un message pour le deuxième commit :

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

Maintenant, créons une nouvelle branche (branch) et effectuons un commit sur cette branche :

git branch feature
git checkout feature
echo "Feature work" > file2.txt
git add file2.txt
git commit -m "Add feature file"

Vous verrez un message pour la création de la branche, le passage à celle-ci et le nouveau commit :

Switched to a new branch 'feature'
[feature <commit-hash>] Add feature file
 1 file changed, 1 insertion(+)
 create mode 100644 file2.txt

Revenons à la branche master et effectuons un autre commit :

git checkout master
echo "More master work" >> file1.txt
git add file1.txt
git commit -m "More master content"

Vous verrez un message pour le changement de branche et le nouveau commit :

Switched to branch 'master'
[master <commit-hash>] More master content
 1 file changed, 1 insertion(+)

Maintenant, nous avons un historique de commits avec une branche. Utilisons git log pour voir l'historique complet :

git log --all --decorate --oneline

Vous verrez un historique similaire à celui-ci (les hachages de commit et l'ordre peuvent varier) :

<commit-hash> (HEAD -> master) More master content
<commit-hash> Add more content
<commit-hash> (feature) Add feature file
<commit-hash> Initial commit

Maintenant, utilisons git log --ancestry-path. Cette commande nécessite deux références de commit. Elle affichera les commits qui sont les ancêtres du deuxième commit et les descendants du premier commit.

Trouvons le hachage du commit pour "Initial commit" et "More master content". Vous pouvez obtenir ces hachages à partir de la sortie de git log --all --decorate --oneline. Remplacez <initial-commit-hash> et <master-commit-hash> par les hachages réels de votre sortie.

git log --ancestry-path <initial-commit-hash> <master-commit-hash> --oneline

Cette commande affichera les commits sur le chemin du commit initial au dernier commit sur la branche master. Vous devriez voir les commits "Initial commit", "Add more content" et "More master content".

L'option --ancestry-path est utile pour comprendre la ligne directe de développement entre deux points de votre historique, en ignorant les commits d'autres branches qui pourraient avoir été fusionnés plus tard.

Exécuter git merge-base --is-ancestor

Dans cette étape, nous allons apprendre à utiliser git merge-base --is-ancestor. Cette commande est utilisée pour vérifier si un commit est l'ancêtre d'un autre commit. C'est une vérification simple qui renvoie un code de statut (0 pour vrai, 1 pour faux) plutôt que d'afficher des informations sur les commits. Cela est particulièrement utile dans les scripts ou pour des vérifications rapides.

Nous allons continuer à utiliser le dépôt (repository) ancestry-lab que nous avons créé à l'étape précédente. Assurez-vous d'être dans le bon répertoire :

cd ~/project/ancestry-lab

Rappelons l'historique des commits de l'étape précédente. Nous avons des commits sur les branches master et feature.

Trouvons les hachages des commits pour le "Initial commit" et le dernier commit sur la branche master ("More master content"). Vous pouvez utiliser git log --oneline pour voir les commits récents.

git log --oneline

La sortie sera similaire à :

<master-commit-hash> (HEAD -> master) More master content
<commit-hash> Add more content
<initial-commit-hash> Initial commit

Maintenant, utilisons git merge-base --is-ancestor pour vérifier si le "Initial commit" est l'ancêtre du dernier commit sur master. Remplacez <initial-commit-hash> et <master-commit-hash> par les hachages réels.

git merge-base --is-ancestor <initial-commit-hash> <master-commit-hash>
echo $?

La commande echo $? affiche le code de sortie de la commande précédente. Si le premier commit est l'ancêtre du deuxième, le code de sortie sera 0. Sinon, ce sera 1.

Étant donné que le "Initial commit" est effectivement l'ancêtre du dernier commit sur master, la sortie de echo $? devrait être 0.

Maintenant, vérifions si le "Initial commit" est l'ancêtre du dernier commit sur la branche feature. Tout d'abord, trouvez le hachage du commit pour le "Add feature file" commit.

git log --all --decorate --oneline

La sortie sera similaire à :

<master-commit-hash> (HEAD -> master) More master content
<commit-hash> Add more content
<feature-commit-hash> (feature) Add feature file
<initial-commit-hash> Initial commit

Maintenant, utilisez git merge-base --is-ancestor pour vérifier si le "Initial commit" est l'ancêtre du commit "Add feature file". Remplacez <initial-commit-hash> et <feature-commit-hash> par les hachages réels.

git merge-base --is-ancestor <initial-commit-hash> <feature-commit-hash>
echo $?

Encore une fois, la sortie de echo $? devrait être 0 car le "Initial commit" est le point de départ de toutes les deux branches.

Enfin, vérifions si le dernier commit sur feature est l'ancêtre du dernier commit sur master. Remplacez <feature-commit-hash> et <master-commit-hash> par les hachages réels.

git merge-base --is-ancestor <feature-commit-hash> <master-commit-hash>
echo $?

Dans ce cas, le dernier commit sur feature n'est pas l'ancêtre du dernier commit sur master (ils se trouvent sur des branches différentes après la séparation initiale). Donc, la sortie de echo $? devrait être 1.

Comprendre la relation d'ascendance entre les commits est fondamental pour comprendre comment Git suit l'historique et comment des opérations telles que la fusion (merge) et le rebasage (rebase) fonctionnent. Le drapeau --is-ancestor offre un moyen simple de vérifier cette relation.

Tester les commits inaccessibles

Dans cette étape, nous allons explorer le concept de commits "inaccessibles" (unreachable) dans Git. Un commit inaccessible est un commit qui ne peut être atteint depuis aucune branche (branch), étiquette (tag) ou autre référence. Ces commits ne font pas partie de l'historique actuel de votre projet tel qu'il est affiché par des commandes standard comme git log.

Nous allons continuer à utiliser le dépôt (repository) ancestry-lab. Assurez-vous d'être dans le bon répertoire :

cd ~/project/ancestry-lab

Actuellement, tous nos commits sont accessibles depuis la branche master ou la branche feature. Créons un scénario où un commit devient inaccessible.

Tout d'abord, effectuons un nouveau commit sur la branche master :

echo "Temporary commit" >> file1.txt
git add file1.txt
git commit -m "Temporary commit"

Vous verrez un message pour ce nouveau commit :

[master <commit-hash>] Temporary commit
 1 file changed, 1 insertion(+)

Maintenant, réinitialisons (reset) la branche master au commit précédent. Cela rendra le "Temporary commit" inaccessible depuis la branche master. Nous allons utiliser git reset --hard HEAD~1. HEAD~1 fait référence au commit directement avant le HEAD actuel.

Attention avec git reset --hard car cela supprime les modifications ! Dans ce cas, nous supprimons intentionnellement le "Temporary commit" de l'historique de la branche master.

git reset --hard HEAD~1

Vous verrez un message indiquant que le HEAD est maintenant au commit précédent :

HEAD is now at <previous-commit-hash> More master content

Maintenant, regardons le résultat standard de git log :

git log --oneline

Vous verrez que le "Temporary commit" n'est plus affiché dans le résultat du log pour la branche master.

<previous-commit-hash> (HEAD -> master) More master content
<commit-hash> Add more content
<initial-commit-hash> Initial commit

Le "Temporary commit" existe toujours dans la base de données Git, mais il n'est référencé par aucune branche ou étiquette. Il est maintenant un commit "inaccessible".

Comment pouvons-nous voir les commits inaccessibles ? Git a une référence spéciale appelée reflog qui enregistre les mises à jour de la tête des branches et d'autres références. Nous pouvons utiliser git log avec l'option --walk-reflogs ou simplement git reflog pour voir ces commits.

Utilisons git reflog :

git reflog

Vous verrez un historique des actions effectuées, y compris le commit que nous venons de faire puis de réinitialiser :

<master-commit-hash> (HEAD -> master) master@{0}: reset: moving to HEAD~1
<temporary-commit-hash> master@{1}: commit: Temporary commit
<previous-commit-hash> master@{2}: commit: More master content
<commit-hash> master@{3}: commit: Add more content
<initial-commit-hash> master@{4}: commit (initial): Initial commit

Remarquez l'entrée pour le "Temporary commit". Il est accessible via master@{1} dans le reflog. Cependant, il n'est pas accessible depuis le HEAD actuel ou la tête de toute branche.

Les commits inaccessibles sont éventuellement nettoyés par la collecte de déchets (garbage collection) de Git (git gc), mais ils restent accessibles via le reflog pendant une période par défaut (généralement 30 ou 90 jours). Cela peut être un vrai sauveur si vous réinitialisez ou supprimez accidentellement des commits.

Comprendre les commits inaccessibles vous aide à saisir la différence entre la base de données d'objets interne de Git et les références (branches, étiquettes, HEAD) qui pointent vers les commits dans cette base de données.

Résumé

Dans ce laboratoire (lab), nous avons appris à vérifier si un commit Git est accessible depuis le HEAD en utilisant deux méthodes principales. Tout d'abord, nous avons exploré la commande git log --ancestry-path, qui nous permet de visualiser l'historique des commits le long du chemin entre deux commits spécifiés. Nous avons créé un dépôt (repository) simple avec plusieurs branches (branches) et commits pour démontrer comment cette commande aide à comprendre la lignée et à identifier si un commit est l'ancêtre d'un autre.

Deuxièmement, nous allons apprendre à utiliser la commande git merge-base --is-ancestor, qui offre un moyen plus direct et programmatique de déterminer si un commit est l'ancêtre d'un autre. Enfin, nous allons tester ces méthodes avec des commits inaccessibles (unreachable) pour consolider notre compréhension de la vérification de l'accessibilité au sein d'un dépôt Git.