Wie man prüft, ob ein Git-Commit vom HEAD aus erreichbar ist

GitGitBeginner
Jetzt üben

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

In diesem Lab lernen Sie, wie Sie feststellen können, ob ein bestimmter Git-Commit (Git-Commit) vom aktuellen HEAD aus erreichbar ist. Dies ist eine grundlegende Fähigkeit, um die Historie Ihres Repositorys zu verstehen und Commits zu identifizieren, die Teil der aktiven Entwicklungslinie sind.

Wir werden zwei primäre Methoden untersuchen: die Verwendung des Befehls git log --ancestry-path, um die Commit-Hierarchie zwischen zwei Punkten zu visualisieren, und die Anwendung des Befehls git merge-base --is-ancestor für eine direkte Prüfung der Abstammung. Sie werden diese Techniken üben, indem Sie ein Beispiel-Repository mit mehreren Zweigen (branches) und Commits einrichten, darunter einige, die absichtlich vom HEAD aus nicht erreichbar gemacht werden, damit Sie Ihr Verständnis testen und bestätigen können.


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{{"Wie man prüft, ob ein Git-Commit vom HEAD aus erreichbar ist"}} git/add -.-> lab-560063{{"Wie man prüft, ob ein Git-Commit vom HEAD aus erreichbar ist"}} git/commit -.-> lab-560063{{"Wie man prüft, ob ein Git-Commit vom HEAD aus erreichbar ist"}} git/branch -.-> lab-560063{{"Wie man prüft, ob ein Git-Commit vom HEAD aus erreichbar ist"}} git/checkout -.-> lab-560063{{"Wie man prüft, ob ein Git-Commit vom HEAD aus erreichbar ist"}} git/merge -.-> lab-560063{{"Wie man prüft, ob ein Git-Commit vom HEAD aus erreichbar ist"}} git/log -.-> lab-560063{{"Wie man prüft, ob ein Git-Commit vom HEAD aus erreichbar ist"}} git/reflog -.-> lab-560063{{"Wie man prüft, ob ein Git-Commit vom HEAD aus erreichbar ist"}} git/rebase -.-> lab-560063{{"Wie man prüft, ob ein Git-Commit vom HEAD aus erreichbar ist"}} end

Verwenden von git log --ancestry-path

In diesem Schritt werden wir untersuchen, wie man den Befehl git log --ancestry-path verwendet. Dieser Befehl ist nützlich, um die Commit-Historie entlang eines bestimmten Pfads zwischen zwei Commits anzuzeigen. Er hilft Ihnen, die Abstammungslinie der Änderungen zu verstehen.

Zunächst erstellen wir ein einfaches Git-Repository und machen ein paar Commits, um ein Szenario für die Verwendung von --ancestry-path einzurichten.

Navigieren Sie in Ihr Projektverzeichnis:

cd ~/project

Erstellen Sie ein neues Verzeichnis für dieses Lab und initialisieren Sie ein Git-Repository:

mkdir ancestry-lab
cd ancestry-lab
git init

Sie sollten eine Ausgabe sehen, die anzeigt, dass ein leeres Git-Repository initialisiert wurde:

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

Jetzt erstellen wir eine Datei und machen den ersten Commit:

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

Sie werden eine Ausgabe sehen, die den Commit bestätigt:

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

Als Nächstes machen wir einen weiteren Commit:

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

Sie werden eine Ausgabe für den zweiten Commit sehen:

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

Jetzt erstellen wir einen neuen Zweig (branch) und machen einen Commit auf diesem Zweig:

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

Sie werden eine Ausgabe für das Erstellen des Zweigs, das Umschalten auf ihn und den neuen Commit sehen:

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

Gehen wir zurück zum master-Zweig und machen einen weiteren Commit:

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

Sie werden eine Ausgabe für das Umschalten der Zweige und den neuen Commit sehen:

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

Jetzt haben wir eine Commit-Historie mit einem Zweig. Verwenden wir git log, um die vollständige Historie anzuzeigen:

git log --all --decorate --oneline

Sie werden ein Log ähnlich diesem sehen (Commit-Hashes und Reihenfolge können variieren):

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

Jetzt verwenden wir git log --ancestry-path. Dieser Befehl erfordert zwei Commit-Referenzen. Er zeigt die Commits an, die Vorfahren des zweiten Commits und Nachfahren des ersten Commits sind.

Finden wir die Commit-Hashes für "Initial commit" und "More master content". Sie können diese aus der Ausgabe von git log --all --decorate --oneline erhalten. Ersetzen Sie <initial-commit-hash> und <master-commit-hash> durch die tatsächlichen Hashes aus Ihrer Ausgabe.

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

Dieser Befehl zeigt die Commits auf dem Pfad vom ersten Commit bis zum neuesten Commit auf dem master-Zweig an. Sie sollten die Commits "Initial commit", "Add more content" und "More master content" sehen.

Die Option --ancestry-path ist nützlich, um die direkte Entwicklungslinie zwischen zwei Punkten in Ihrer Historie zu verstehen und Commits von anderen Zweigen zu ignorieren, die später möglicherweise zusammengeführt wurden.

Ausführen von git merge-base --is-ancestor

In diesem Schritt lernen wir etwas über git merge-base --is-ancestor. Dieser Befehl wird verwendet, um zu prüfen, ob ein Commit ein Vorfahr eines anderen Commits ist. Es handelt sich um eine einfache Prüfung, die einen Statuscode zurückgibt (0 für wahr, 1 für falsch), anstatt Commit-Informationen auszugeben. Dies ist besonders nützlich in Skripten oder für schnelle Prüfungen.

Wir werden weiterhin das ancestry-lab-Repository verwenden, das wir im vorherigen Schritt erstellt haben. Stellen Sie sicher, dass Sie sich im richtigen Verzeichnis befinden:

cd ~/project/ancestry-lab

Denken Sie an die Commit-Historie aus dem vorherigen Schritt. Wir haben Commits sowohl auf dem master- als auch auf dem feature-Zweig (branch).

Finden wir die Commit-Hashes für den "Initial commit" und den neuesten Commit auf dem master-Zweig ("More master content"). Sie können git log --oneline verwenden, um die letzten Commits anzuzeigen.

git log --oneline

Die Ausgabe wird ähnlich wie folgt aussehen:

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

Jetzt verwenden wir git merge-base --is-ancestor, um zu prüfen, ob der "Initial commit" ein Vorfahr des neuesten Commits auf master ist. Ersetzen Sie <initial-commit-hash> und <master-commit-hash> durch die tatsächlichen Hashes.

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

Der Befehl echo $? gibt den Exit-Status des vorherigen Befehls aus. Wenn der erste Commit ein Vorfahr des zweiten ist, wird der Exit-Status 0 sein. Andernfalls wird er 1 sein.

Da der "Initial commit" tatsächlich ein Vorfahr des neuesten Commits auf master ist, sollte die Ausgabe von echo $? 0 sein.

Jetzt prüfen wir, ob der "Initial commit" ein Vorfahr des neuesten Commits auf dem feature-Zweig ist. Zunächst finden wir den Commit-Hash für den "Add feature file"-Commit.

git log --all --decorate --oneline

Die Ausgabe wird ähnlich wie folgt aussehen:

<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

Jetzt verwenden wir git merge-base --is-ancestor, um zu prüfen, ob der "Initial commit" ein Vorfahr des "Add feature file"-Commits ist. Ersetzen Sie <initial-commit-hash> und <feature-commit-hash> durch die tatsächlichen Hashes.

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

Wieder sollte die Ausgabe von echo $? 0 sein, da der "Initial commit" der Ausgangspunkt für beide Zweige ist.

Schließlich prüfen wir, ob der neueste Commit auf feature ein Vorfahr des neuesten Commits auf master ist. Ersetzen Sie <feature-commit-hash> und <master-commit-hash> durch die tatsächlichen Hashes.

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

In diesem Fall ist der neueste Commit auf feature kein Vorfahr des neuesten Commits auf master (sie befinden sich nach der anfänglichen Aufspaltung auf verschiedenen Zweigen). Daher sollte die Ausgabe von echo $? 1 sein.

Das Verständnis der Vorfahrbeziehung zwischen Commits ist grundlegend für das Verständnis, wie Git die Historie verfolgt und wie Operationen wie Merging und Rebasing funktionieren. Die Option --is-ancestor bietet eine einfache Möglichkeit, diese Beziehung zu prüfen.

Testen von unerreichbaren Commits

In diesem Schritt werden wir das Konzept von "unerreichbaren" Commits in Git untersuchen. Ein unerreichbarer Commit ist ein Commit, der von keinem Zweig (branch), Tag oder anderen Verweis aus erreicht werden kann. Diese Commits sind nicht Teil Ihrer aktuellen Projektgeschichte, wie sie von Standardbefehlen wie git log angezeigt wird.

Wir werden weiterhin das ancestry-lab-Repository verwenden. Stellen Sie sicher, dass Sie sich im richtigen Verzeichnis befinden:

cd ~/project/ancestry-lab

Derzeit sind alle unsere Commits entweder vom master- oder vom feature-Zweig aus erreichbar. Erstellen wir ein Szenario, in dem ein Commit unerreichbar wird.

Zunächst machen wir einen neuen Commit auf dem master-Zweig:

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

Sie werden eine Ausgabe für diesen neuen Commit sehen:

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

Jetzt setzen wir den master-Zweig auf den vorherigen Commit zurück. Dadurch wird der "Temporary commit" vom master-Zweig aus unerreichbar. Wir verwenden git reset --hard HEAD~1. HEAD~1 bezieht sich auf den Commit direkt vor dem aktuellen HEAD.

Seien Sie vorsichtig mit git reset --hard, da es Änderungen verwirft! In diesem Fall verwerfen wir absichtlich den "Temporary commit" aus der Geschichte des master-Zweigs.

git reset --hard HEAD~1

Sie werden eine Ausgabe sehen, die anzeigt, dass der HEAD jetzt beim vorherigen Commit ist:

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

Jetzt schauen wir uns das Standard-git log an:

git log --oneline

Sie werden feststellen, dass der "Temporary commit" nicht mehr in der Log-Ausgabe für den master-Zweig enthalten ist.

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

Der "Temporary commit" existiert immer noch in der Git-Datenbank, wird jedoch von keinem Zweig oder Tag referenziert. Er ist jetzt ein "unerreichbarer" Commit.

Wie können wir unerreichbare Commits sehen? Git hat eine spezielle Referenz namens reflog, die Aktualisierungen der Spitze von Zweigen und anderen Referenzen aufzeichnet. Wir können git log mit der Option --walk-reflogs oder einfach git reflog verwenden, um diese Commits anzuzeigen.

Verwenden wir git reflog:

git reflog

Sie werden ein Log der ausgeführten Aktionen sehen, einschließlich des Commits, den wir gerade gemacht und dann zurückgesetzt haben:

<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

Beachten Sie den Eintrag für "Temporary commit". Er ist über master@{1} im reflog erreichbar. Er ist jedoch vom aktuellen HEAD oder von keiner Zweigspitze aus erreichbar.

Unerreichbare Commits werden schließlich von Git's Garbage Collection (git gc) bereinigt, bleiben aber standardmäßig für einen bestimmten Zeitraum (normalerweise 30 oder 90 Tage) über das reflog zugänglich. Dies kann ein Lebensretter sein, wenn Sie versehentlich Commits zurücksetzen oder löschen.

Das Verständnis von unerreichbaren Commits hilft Ihnen, den Unterschied zwischen Git's internen Objektdatenbank und den Referenzen (Zweige, Tags, HEAD) zu verstehen, die auf Commits in dieser Datenbank verweisen.

Zusammenfassung

In diesem Lab haben wir gelernt, wie man mithilfe von zwei Hauptmethoden prüft, ob ein Git-Commit vom HEAD aus erreichbar ist. Zunächst haben wir uns den Befehl git log --ancestry-path angeschaut, der es uns ermöglicht, die Commit-Historie entlang des Pfads zwischen zwei angegebenen Commits zu visualisieren. Wir haben ein einfaches Repository mit mehreren Zweigen (branches) und Commits eingerichtet, um zu zeigen, wie dieser Befehl hilft, die Abstammung zu verstehen und zu erkennen, ob ein Commit ein Vorfahr eines anderen ist.

Zweitens werden wir lernen, wie man den Befehl git merge-base --is-ancestor verwendet, der eine direktere und programmierbare Möglichkeit bietet, zu bestimmen, ob ein Commit ein Vorfahr eines anderen ist. Schließlich werden wir diese Methoden mit unerreichbaren Commits testen, um unser Verständnis davon zu festigen, wie man die Erreichbarkeit innerhalb eines Git-Repositories überprüft.