Wie man eine Git Cherry-Pick-Operation rückgängig macht

GitGitBeginner
Jetzt üben

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

Einführung

Die Cherry-Pick-Funktion von Git ermöglicht es Ihnen, bestimmte Commits von einem Branch auf einen anderen anzuwenden. Obwohl sie leistungsstark ist, kann es vorkommen, dass Sie einen Cherry-Pick-Vorgang aufgrund von Fehlern oder Konflikten rückgängig machen müssen. In diesem Lab lernen Sie, wie Sie einen Cherry-Pick durchführen und anschließend verschiedene Methoden anwenden, um ihn bei Bedarf zu widerrufen. Am Ende verfügen Sie über praktische Erfahrung mit Cherry-Pick-Operationen und die Fähigkeiten, sich von häufigen Problemen zu erholen.

Einrichten eines Test-Repositorys

In diesem Schritt erstellen wir ein Test-Git-Repository, um Cherry-Pick-Operationen zu üben. Dies bietet eine sichere Umgebung, um mit verschiedenen Git-Befehlen zu experimentieren.

Erstellen eines neuen Git-Repositorys

Beginnen wir damit, ein neues Verzeichnis für unser Test-Repository zu erstellen und es als Git-Repository zu initialisieren:

mkdir -p ~/project/cherry-pick-lab
cd ~/project/cherry-pick-lab
git init

Sie sollten eine ähnliche Ausgabe sehen:

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

Einrichten der Git-Benutzerkonfiguration

Bevor wir Commits durchführen können, müssen wir einen Benutzernamen und eine E-Mail-Adresse für Git einrichten:

git config --local user.name "LabEx User"
git config --local user.email "[email protected]"

Erstellen von initialen Commits auf dem Main-Branch

Erstellen wir einige initiale Commits auf dem Main-Branch:

## Create and commit the first file
echo "## Cherry Pick Lab" > README.md
git add README.md
git commit -m "Initial commit with README"

## Create and commit a second file
echo "console.log('Hello, world!');" > app.js
git add app.js
git commit -m "Add main application file"

Anzeigen des Commit-Verlaufs

Überprüfen wir unseren Commit-Verlauf, um sicherzustellen, dass alles korrekt eingerichtet ist:

git log --oneline

Sie sollten eine ähnliche Ausgabe sehen:

abcd123 (HEAD -> main) Add main application file
efgh456 Initial commit with README

Die tatsächlichen Commit-Hashes unterscheiden sich auf Ihrem System. Notieren Sie sich den Commit-Hash für "Add main application file", da wir ihn später verwenden werden.

Erstellen eines Feature-Branches

Erstellen wir nun einen Feature-Branch, in dem wir einige zusätzliche Änderungen vornehmen:

git checkout -b feature-branch

Sie sollten eine ähnliche Ausgabe sehen:

Switched to a new branch 'feature-branch'

Fügen wir nun einige Commits zu diesem Feature-Branch hinzu:

## Create and commit a new feature file
echo "function newFeature() { return 'awesome'; }" > feature.js
git add feature.js
git commit -m "Add new feature function"

## Modify the README file
echo -e "## Cherry Pick Lab\n\nThis repo demonstrates git cherry-pick operations." > README.md
git add README.md
git commit -m "Update README with project description"

Jetzt haben wir einen Main-Branch mit zwei Commits und einen Feature-Branch mit zwei zusätzlichen Commits. Im nächsten Schritt verwenden wir Cherry-Pick, um einen der Feature-Branch-Commits auf den Main-Branch anzuwenden.

Durchführen einer Cherry-Pick-Operation

In diesem Schritt lernen wir, wie man den Befehl cherry-pick verwendet, um einen bestimmten Commit von einem Branch auf einen anderen anzuwenden. Dies ist nützlich, wenn Sie Änderungen selektiv von einem Branch in einen anderen übernehmen möchten.

Verstehen von Cherry-Pick

Cherry-Picking in Git ermöglicht es Ihnen, einen bestimmten Commit von einem Branch auszuwählen und auf einen anderen Branch anzuwenden. Im Gegensatz zu Merging oder Rebasing, die typischerweise mehrere Commits anwenden, wendet Cherry-Picking jeweils nur einen Commit an.

Zurück zum Main-Branch wechseln

Zuerst wechseln wir zurück zum Main-Branch, auf dem wir einen Commit vom Feature-Branch anwenden möchten:

git checkout main

Sie sollten eine Ausgabe sehen, die den Wechsel bestätigt:

Switched to branch 'main'

Anzeigen der Feature-Branch-Commits

Bevor wir Cherry-Picking durchführen, untersuchen wir die Commits im Feature-Branch, die wir möglicherweise auf Main anwenden möchten:

git log feature-branch --oneline

Dies zeigt alle Commits im Feature-Branch, einschließlich derer, die mit dem Main-Branch geteilt werden. Sie sehen eine ähnliche Ausgabe:

1234abc Update README with project description
5678def Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README

Notieren Sie sich den Commit-Hash für "Add new feature function" (in diesem Beispiel ist es 5678def). Wir werden diesen Hash im nächsten Schritt verwenden.

Cherry-Picking eines Commits

Nun wollen wir den Commit "Add new feature function" vom Feature-Branch in unseren Main-Branch cherry-picken:

git cherry-pick [COMMIT_HASH]

Ersetzen Sie [COMMIT_HASH] durch den tatsächlichen Hash, den Sie sich zuvor notiert haben. Zum Beispiel:

git cherry-pick 5678def

Wenn das Cherry-Pick erfolgreich ist, sehen Sie eine ähnliche Ausgabe:

[main 98765ab] Add new feature function
 1 file changed, 1 insertion(+)
 create mode 100644 feature.js

Überprüfen des Cherry-Pick

Bestätigen wir, dass das Cherry-Pick wie erwartet funktioniert hat:

git log --oneline

Sie sollten jetzt den cherry-gepickten Commit in der History Ihres Main-Branches sehen:

98765ab (HEAD -> main) Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README

Sie können auch überprüfen, ob die Datei existiert:

ls -la

Sie sollten feature.js in der Ausgabe sehen:

total 16
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 .
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 ..
drwxr-xr-x 8 labex labex 4096 Jan 1 00:00 .git
-rw-r--r-- 1 labex labex   29 Jan 1 00:00 app.js
-rw-r--r-- 1 labex labex   42 Jan 1 00:00 feature.js
-rw-r--r-- 1 labex labex   16 Jan 1 00:00 README.md

Die Cherry-Pick-Operation hat den Commit vom Feature-Branch erfolgreich auf den Main-Branch angewendet. Im nächsten Schritt erfahren wir, wie wir dieses Cherry-Pick bei Bedarf rückgängig machen können.

Rückgängigmachen eines Cherry-Pick mit Git Reset

Nachdem wir erfolgreich einen Commit cherry-gepickt haben, lernen wir nun, wie man diese Operation rückgängig macht. In diesem Schritt verwenden wir den Befehl git reset, der der direkteste Weg ist, um ein kürzlich durchgeführtes Cherry-Pick rückgängig zu machen.

Verstehen von Git Reset

Der Befehl git reset verschiebt den aktuellen Branch-Zeiger auf einen angegebenen Commit und macht somit effektiv alle Commits, die nach diesem Punkt kamen, "ungültig". Es gibt drei Hauptmodi von Git Reset:

  • --soft: Verschiebt den Branch-Zeiger, lässt aber Änderungen gestaged
  • --mixed (Standard): Verschiebt den Branch-Zeiger und entfernt Änderungen aus dem Staging-Bereich
  • --hard: Verschiebt den Branch-Zeiger und verwirft alle Änderungen

Um ein Cherry-Pick rückgängig zu machen, verwenden wir die Option --hard, um den cherry-gepickten Commit und seine Änderungen vollständig zu entfernen.

Überprüfen des aktuellen Status

Zuerst überprüfen wir unseren aktuellen Status, um zu bestätigen, dass wir uns auf dem Main-Branch mit dem cherry-gepickten Commit befinden:

git log --oneline -n 3

Sie sollten eine ähnliche Ausgabe sehen:

98765ab (HEAD -> main) Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README

Rückgängigmachen des Cherry-Pick mit Git Reset

Um die Cherry-Pick-Operation rückgängig zu machen, verwenden wir git reset mit der Option --hard, um den Branch-Zeiger einen Commit zurückzusetzen:

git reset --hard HEAD~1

Dieser Befehl weist Git an, den Branch auf den Commit vor dem aktuellen HEAD zurückzusetzen (der Teil ~1 bedeutet "ein Commit zuvor").

Sie sollten eine ähnliche Ausgabe sehen:

HEAD is now at abcd123 Add main application file

Überprüfen des Reset

Überprüfen wir, ob das Cherry-Pick rückgängig gemacht wurde:

git log --oneline

Sie sollten sehen, dass der cherry-gepickte Commit nicht mehr in der History enthalten ist:

abcd123 (HEAD -> main) Add main application file
efgh456 Initial commit with README

Überprüfen wir auch, ob die Datei feature.js entfernt wurde:

ls -la

Die Ausgabe sollte feature.js nicht enthalten:

total 12
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 .
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 ..
drwxr-xr-x 8 labex labex 4096 Jan 1 00:00 .git
-rw-r--r-- 1 labex labex   29 Jan 1 00:00 app.js
-rw-r--r-- 1 labex labex   16 Jan 1 00:00 README.md

Herzlichen Glückwunsch! Sie haben erfolgreich eine Cherry-Pick-Operation mit git reset rückgängig gemacht. Diese Methode ist sauber und einfach, aber sie schreibt die History neu, daher sollte sie nur für lokale Änderungen verwendet werden, die noch nicht in ein gemeinsames Repository gepusht wurden.

Rückgängigmachen eines Cherry-Pick mit Git Revert

Im vorherigen Schritt haben wir git reset verwendet, um ein Cherry-Pick rückgängig zu machen. Allerdings schreibt git reset die History neu, was problematisch sein kann, wenn Sie Ihre Änderungen bereits in ein gemeinsames Repository gepusht haben. In diesem Schritt lernen wir, wie man git revert verwendet, um ein Cherry-Pick sicher rückgängig zu machen, ohne die History neu zu schreiben.

Verstehen von Git Revert

Der Befehl git revert erstellt einen neuen Commit, der die Änderungen, die durch einen vorherigen Commit eingeführt wurden, rückgängig macht. Im Gegensatz zu git reset, das Commits aus der History entfernt, fügt git revert einen neuen Commit hinzu, der den Änderungen entgegenwirkt und die Commit-History beibehält.

Erneutes Durchführen eines Cherry-Pick

Zuerst cherry-picken wir den Commit erneut, damit wir etwas zum Revertieren haben:

## Get the commit hash from the feature branch
FEATURE_HASH=$(git log feature-branch --oneline | grep "new feature" | cut -d ' ' -f 1)

## Cherry-pick the commit
git cherry-pick $FEATURE_HASH

Sie sollten eine ähnliche Ausgabe sehen:

[main 98765ab] Add new feature function
 1 file changed, 1 insertion(+)
 create mode 100644 feature.js

Überprüfen des aktuellen Status

Bestätigen wir, dass das Cherry-Pick erfolgreich war:

git log --oneline -n 3
ls -la

Sie sollten den cherry-gepickten Commit in der History und die Datei feature.js in der Verzeichnisliste sehen.

Revertieren des Cherry-Pick

Nun verwenden wir git revert, um das Cherry-Pick rückgängig zu machen und gleichzeitig die History zu erhalten:

git revert HEAD --no-edit

Das Flag --no-edit weist Git an, die Standard-Commit-Nachricht zu verwenden, ohne einen Editor zu öffnen.

Sie sollten eine ähnliche Ausgabe sehen:

[main abc9876] Revert "Add new feature function"
 1 file changed, 1 deletion(-)
 delete mode 100644 feature.js

Überprüfen des Revert

Überprüfen wir die Commit-History:

git log --oneline -n 4

Sie sollten sowohl den cherry-gepickten Commit als auch den Revert-Commit sehen:

abc9876 (HEAD -> main) Revert "Add new feature function"
98765ab Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README

Nun überprüfen wir, ob die Datei feature.js entfernt wurde:

ls -la

Die Ausgabe sollte feature.js nicht enthalten:

total 12
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 .
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 ..
drwxr-xr-x 8 labex labex 4096 Jan 1 00:00 .git
-rw-r--r-- 1 labex labex   29 Jan 1 00:00 app.js
-rw-r--r-- 1 labex labex   16 Jan 1 00:00 README.md

Obwohl sowohl git reset als auch git revert das gleiche Endergebnis erzielen (Entfernen der durch das Cherry-Pick eingeführten Änderungen), tun sie dies auf unterschiedliche Weise:

  • git reset entfernt den Commit aus der History, was Probleme verursachen kann, wenn der Commit mit anderen geteilt wurde.
  • git revert fügt einen neuen Commit hinzu, der die Änderungen rückgängig macht und die Commit-History beibehält, was für gemeinsame Repositories sicherer ist.

Die Wahl zwischen diesen Methoden hängt von Ihrer spezifischen Situation ab:

  • Verwenden Sie git reset für lokale Änderungen, die noch nicht geteilt wurden
  • Verwenden Sie git revert für Änderungen, die in ein gemeinsames Repository gepusht wurden

Umgang mit Cherry-Pick-Konflikten

Manchmal, wenn Sie einen Commit cherry-picken, kann Git auf Konflikte stoßen, wenn die Änderungen in dem Commit mit Änderungen in Ihrem aktuellen Branch kollidieren. In diesem Schritt lernen wir, wie man Cherry-Pick-Konflikte behandelt und wie man eine Cherry-Pick-Operation abbricht.

Erstellen eines Szenarios mit potenziellen Konflikten

Zuerst erstellen wir ein Szenario, das zu einem Cherry-Pick-Konflikt führt:

## Switch to main branch and modify README.md
git checkout main
echo -e "## Cherry Pick Lab\n\nThis is the main branch README." > README.md
git commit -am "Update README in main branch"

## Switch to feature branch and make a conflicting change to README.md
git checkout feature-branch
echo -e "## Cherry Pick Lab\n\nThis README has been updated in the feature branch." > README.md
git commit -am "Update README in feature branch"

Versuch eines Cherry-Pick mit Konflikten

Nun wechseln wir zurück zum Main-Branch und versuchen, den Commit vom Feature-Branch zu cherry-picken:

git checkout main
CONFLICT_HASH=$(git log feature-branch --oneline | grep "Update README in feature" | cut -d ' ' -f 1)
git cherry-pick $CONFLICT_HASH

Da beide Branches dieselben Zeilen in README.md geändert haben, sollten Sie einen Konflikt sehen:

error: could not apply a1b2c3d... Update README in feature branch
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'

Anzeigen des Konflikts

Untersuchen wir den Konflikt:

git status

Sie sollten eine Ausgabe sehen, die einen Konflikt in README.md anzeigt:

On branch main
You are currently cherry-picking commit a1b2c3d.
  (fix conflicts and run "git cherry-pick --continue")
  (use "git cherry-pick --abort" to cancel the cherry-pick operation)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
  both modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")

Sehen wir uns den Inhalt der konfliktbehafteten Datei an:

cat README.md

Sie sollten so etwas sehen:

## Cherry Pick Lab

<<<<<<< HEAD
This is the main branch README.
=======
This README has been updated in the feature branch.
>>>>>>> a1b2c3d... Update README in feature branch

Auflösen des Konflikts

Um den Konflikt zu lösen, müssen wir die Datei bearbeiten und entscheiden, welche Änderungen beibehalten werden sollen. Ändern wir README.md, um beide Änderungen einzubeziehen:

echo -e "## Cherry Pick Lab\n\nThis is the main branch README.\n\nThis README has also been updated with content from the feature branch." > README.md

Nun markieren wir den Konflikt als gelöst und setzen das Cherry-Pick fort:

git add README.md
git cherry-pick --continue

Git öffnet einen Editor mit einer Standard-Commit-Nachricht. Speichern und schließen Sie den Editor, um das Cherry-Pick abzuschließen.

Abbrechen eines Cherry-Pick

Manchmal entscheiden Sie sich möglicherweise, die Konflikte nicht zu lösen und möchten stattdessen die Cherry-Pick-Operation abbrechen. Erstellen wir einen weiteren Konflikt und brechen dann das Cherry-Pick ab:

## Create another conflicting commit in feature branch
git checkout feature-branch
echo "// This will conflict with app.js in main" > app.js
git commit -am "Modify app.js in feature branch"

## Try to cherry-pick this commit to main
git checkout main
ANOTHER_CONFLICT=$(git log feature-branch --oneline | grep "Modify app.js" | cut -d ' ' -f 1)
git cherry-pick $ANOTHER_CONFLICT

Sie sollten einen weiteren Konflikt sehen. Diesmal brechen wir das Cherry-Pick ab:

git cherry-pick --abort

Sie sollten sehen, dass die Cherry-Pick-Operation abgebrochen wurde und Ihr Arbeitsverzeichnis in seinen vorherigen Zustand zurückversetzt wurde:

git status

Ausgabe:

On branch main
nothing to commit, working tree clean

Der Umgang mit Konflikten während Cherry-Pick-Operationen ist eine wesentliche Fähigkeit für Git-Benutzer. Sie haben drei Optionen, wenn Sie auf einen Konflikt stoßen:

  1. Lösen Sie den Konflikt manuell und verwenden Sie dann git add und git cherry-pick --continue
  2. Überspringen Sie den konfliktbehafteten Commit mit git cherry-pick --skip
  3. Brechen Sie die gesamte Cherry-Pick-Operation mit git cherry-pick --abort ab

Der beste Ansatz hängt von der spezifischen Situation und Ihren Projektanforderungen ab.

Zusammenfassung

In diesem Lab haben Sie praktische Erfahrung mit der Cherry-Pick-Funktion von Git gesammelt und mehrere Möglichkeiten kennengelernt, Cherry-Pick-Operationen rückgängig zu machen:

  1. Sie haben ein Test-Repository mit mehreren Branches und Commits erstellt, um damit zu üben.
  2. Sie haben eine Cherry-Pick-Operation durchgeführt, um einen bestimmten Commit von einem Branch auf einen anderen anzuwenden.
  3. Sie haben gelernt, wie man ein Cherry-Pick mit git reset rückgängig macht, was für lokale Änderungen geeignet ist.
  4. Sie haben untersucht, wie man ein Cherry-Pick sicher mit git revert rückgängig macht, was die History erhält.
  5. Sie haben das Behandeln von Cherry-Pick-Konflikten geübt und gelernt, wie man eine Cherry-Pick-Operation abbricht.

Diese Fähigkeiten sind von unschätzbarem Wert, wenn Sie in realen Projekten mit Git arbeiten. Cherry-Picking ermöglicht es Ihnen, Änderungen selektiv über Branches hinweg anzuwenden, während das Wissen, wie man Cherry-Picks rückgängig macht, Ihnen hilft, sich von Fehlern zu erholen und eine saubere Git-History zu erhalten.

Denken Sie daran, dass verschiedene Methoden zum Rückgängigmachen unterschiedlichen Zwecken dienen:

  • Verwenden Sie git reset für lokale Änderungen, die noch nicht geteilt wurden.
  • Verwenden Sie git revert für Änderungen, die in ein gemeinsames Repository gepusht wurden.
  • Verwenden Sie git cherry-pick --abort, um eine laufende Cherry-Pick-Operation abzubrechen.

Durch das Verständnis dieser Optionen können Sie die am besten geeignete Methode für Ihre spezifische Situation auswählen.