3302 Stimmen

Wie kann ich eine bestimmte Übertragung ändern?

Normalerweise reiche ich eine Liste von Übertragungen zur Überprüfung ein. Wenn ich die folgenden Commits habe:

  1. HEAD
  2. Commit3
  3. Commit2
  4. Commit1

...Ich weiß, dass ich Head Commit ändern kann mit git commit --amend . Aber wie kann ich die Commit1 da es sich nicht um die HEAD verpflichten?

52 Stimmen

Eine alternative Antwort finden Sie hier: stackoverflow.com/a/18150592/520567 Die von Ihnen akzeptierte Antwort ist eigentlich eine exakte Antwort auf Ihre Frage, aber wenn Sie Ihren neuen Commit schon fertig haben, bevor Sie sich entschlossen haben, edit zu verwenden, dann wäre diese Antwort einfacher. Es kann auch mit mehreren Commits funktionieren, die Sie zusammen mit einem älteren Commit zusammenführen/verschmelzen wollen.

7 Stimmen

Sie können auch einfach sehen Aufteilen einer Übertragung en Git-Tools - Geschichte neu schreiben für weitere Informationen.

1 Stimmen

47voto

Dethariel Punkte 3037

Vollständig nicht interaktiver Befehl (1)

Ich dachte nur, ich teile einen Alias, den ich dafür verwende. Er basiert auf nicht interaktiv interaktive Rebase. Um es zu Ihrem Git hinzuzufügen, führen Sie diesen Befehl aus (Erklärung siehe unten):

git config --global alias.amend-to '!f() { SHA=`git rev-parse "$1"`; git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"; }; f'

Oder eine Version, die auch mit ungespeicherten Dateien umgehen kann (indem sie diese zwischenlagert und dann wieder entlagert):

git config --global alias.amend-to '!f() { SHA=`git rev-parse "$1"`; git stash -k && git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^" && git stash pop; }; f'

Der größte Vorteil dieses Befehls ist die Tatsache, dass er wimmelbild .


(1) vorausgesetzt, es gibt keine Konflikte während der Umbasierung, natürlich

Verwendung

git amend-to <REV> # e.g.
git amend-to HEAD~1
git amend-to aaaa1111

Der Name amend-to erscheint IMHO angemessen. Vergleichen Sie den Fluss mit --amend :

git add . && git commit --amend --no-edit
# vs
git add . && git amend-to <REV>

Erläuterung

  • git config --global alias.<NAME> '!<COMMAND>' - erstellt einen globalen Git-Alias namens <NAME> die einen Nicht-Git-Befehl ausführen wird <COMMAND>
  • f() { <BODY> }; f - eine "anonyme" Bash-Funktion.
  • SHA=`git rev-parse "$1"`; - konvertiert das Argument in eine Git-Revision und weist das Ergebnis der Variablen SHA
  • git commit --fixup "$SHA" - fixup-commit für SHA . Siehe git-commit docs
  • GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
    • git rebase --interactive "$SHA^" Dieser Teil wurde bereits in anderen Antworten behandelt.
    • --autosquash ist das, was in Verbindung mit git commit --fixup siehe git-rebase docs für weitere Informationen
    • GIT_SEQUENCE_EDITOR=true ist das, was das Ganze nicht interaktiv macht. Diesen Hack habe ich gelernt aus diesem Blogbeitrag .

1 Stimmen

Man kann auch amend-to mit nicht bereitgestellten Dateien umgehen: git config --global alias.amend-to '!f() { SHA= git rev-parse "$1" ; git stash -k && git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^" && git stash pop; }; f'

3 Stimmen

Ein Problem bei dieser Methode ist, dass sie nicht zusammenhängende Korrekturen vornehmen könnte.

0 Stimmen

Geht es bei der Frage nicht darum, die Commit-Nachricht zu ändern? Denn diese Antwort geht nicht darauf ein, zumindest nicht direkt.

27voto

FeepingCreature Punkte 3493

Wenn Sie aus irgendeinem Grund keine interaktiven Editoren mögen, können Sie git rebase --onto .

Angenommen, Sie möchten Folgendes ändern Commit1 . Verzweigen Sie zunächst von avant Commit1 :

git checkout -b amending [commit before Commit1]

Zweitens: Greifen Sie Commit1 con cherry-pick :

git cherry-pick Commit1

Ändern Sie nun Ihre Änderungen und erstellen Sie Commit1' :

git add ...
git commit --amend -m "new message for Commit1"

Und schließlich, nachdem Sie alle anderen Änderungen versteckt haben, transplantieren Sie den Rest Ihrer Übertragungen bis zu master auf der Spitze Ihres neuen Commit:

git rebase --onto amending Commit1 master

Lies: "rebase, auf den Zweig amending alle Übertragungen zwischen Commit1 (nicht inbegriffen) und master (einschließlich)". Das heißt, Commit2 und Commit3, wobei das alte Commit1 ganz weggelassen wird. Sie könnten sie auch einfach herauspicken, aber dieser Weg ist einfacher.

Denken Sie daran, Ihre Äste aufzuräumen!

git branch -d amending

4 Stimmen

Können Sie git checkout -b amending Commit1~1 um die vorherige Übertragung zu erhalten

0 Stimmen

Sind die ersten beiden Schritte gleichbedeutend mit git checkout -b amending Commit1 ?

0 Stimmen

Dies ist eine großartige Antwort für Leute, die Angst vor interaktiven Rebase haben. Mein einziger Kritikpunkt ist, dass es unnötig ist, mit einem früheren Commit zu beginnen und den aktuellen Commit auszuwählen, den man ändern möchte. Man kann einfach von dem gegebenen Commit abzweigen und ihn wie gezeigt ändern, ohne den Cherrypick-Schritt zu machen. Tatsächlich wird die Verzweigung durch das Cherrypicking nur um einen Commit vorverlegt, so als ob Sie direkt von diesem Commit verzweigen würden.

20voto

git stash + rebase Automatisierung

Für den Fall, dass ich einen alten Commit häufig für Gerrit-Reviews ändern muss, habe ich das getan:

git-amend-old() (
  # Stash, apply to past commit, and rebase the current branch on to of the result.
  current_branch="$(git rev-parse --abbrev-ref HEAD)"
  apply_to="$1"
  git stash
  git checkout "$apply_to"
  git stash apply
  git add -u
  git commit --amend --no-edit
  new_sha="$(git log --format="%H" -n 1)"
  git checkout "$current_branch"
  git rebase --onto "$new_sha" "$apply_to"
)

GitHub vorgelagert .

Verwendung:

  • Quelldatei ändern, kein Bedarf an git add wenn bereits im Repo
  • git-amend-old $old_sha

Ich mag das über --autosquash da sie andere, nicht miteinander verbundene Korrekturen nicht verdrängt.

2 Stimmen

Sehr nette Abhilfe, dies sollte eine Standardoption sein für git amend um Änderungen an einem bestimmten Commit unter Verwendung des aktuellen Stash zu übernehmen, sehr clever!

13voto

DINA TAKLIT Punkte 4596

Die beste Option ist die Verwendung von "Interaktiver Befehl rebase" .

Le site git rebase Befehl ist unglaublich leistungsfähig. Er erlaubt Ihnen die Bearbeitung Commit-Meldungen , Commits kombinieren, neu anordnen usw.

Jedes Mal, wenn Sie einen Commit zurückbasen, wird ein neuer SHA für jeden Commit erstellt, unabhängig davon, ob der Inhalt geändert wird oder nicht! Sie sollten vorsichtig sein, wenn Sie diesen Befehl verwenden, denn er kann drastische Auswirkungen haben kann, besonders wenn Sie mit anderen Entwicklern zusammen Entwicklern zusammenarbeiten. Sie könnten anfangen, mit Ihrem Commit zu arbeiten, während Sie rebasieren. Nachdem Sie den Push der Commits erzwungen haben, sind sie nicht mehr synchronisiert und Sie können später eine unangenehme Situation herausfinden. Seien Sie also vorsichtig!

Es wird empfohlen, eine backup Zweig vor dem Umbasieren so wenn Sie feststellen, dass die Dinge außer Kontrolle geraten sind, können Sie zum vorherigen Zustand zurückkehren.

Wie wird dieser Befehl nun verwendet?

git rebase -i <base> 

-i stehen für "interaktiv" . Beachten Sie, dass Sie eine Umbasierung im nicht-interaktiven Modus durchführen können, z. B:

#interactivly rebase the n commits from the current position, n is a given number(2,3 ...etc)
git rebase -i HEAD~n 

HEAD gibt Ihren aktuellen Standort an (kann auch der Name der Verzweigung oder der Commit SHA sein). Die ~n bedeutet "n voré, also HEAD~n ist die Liste der "n" Commits vor dem aktuellen Commit.

git rebase hat verschiedene Befehle wie:

  • p o pick die Verpflichtung so beizubehalten, wie sie ist.
  • r o reword : um den Inhalt des Commits beizubehalten, aber die Commit-Nachricht zu ändern.
  • s o squash : um die Änderungen dieses Commits mit dem vorhergehenden Commit (dem in der Liste darüber) zu kombinieren.
  • ... usw.

    Hinweis: Es ist besser, Git mit Ihrem Code-Editor zu verwenden, um die Dinge zu vereinfachen. Wenn Sie zum Beispiel Visual Code verwenden, können Sie Folgendes hinzufügen git config --global core.editor "code --wait" . Oder Sie können in Google suchen, wie Sie Ihren bevorzugten Code-Editor mit GIT verknüpfen können.

Beispiel für git rebase

Ich wollte die letzten 2 Commits, die ich gemacht habe, so ändern, dass ich wie folgt vorgehe:

  1. Zeigt die aktuellen Übertragungen an:

    #This to show all the commits on one line
    $git log --oneline
    4f3d0c8 (HEAD -> documentation) docs: Add project description and included files"
    4d95e08 docs: Add created date and project title"
    eaf7978 (origin/master , origin/HEAD, master) Inital commit
    46a5819 Create README.md
  2. Jetzt benutze ich git rebase um die 2 letzten Commit-Meldungen zu ändern: $git rebase -i HEAD~2 Es öffnet den Code-Editor und zeigt dies an:

    pick 4d95e08 docs: Add created date and project title
    pick 4f3d0c8 docs: Add project description and included files
    
    # Rebase eaf7978..4f3d0c8 onto eaf7978 (2 commands)
    #
    # Commands:
    # p, pick <commit> = use commit
    # r, reword <commit> = use commit, but edit the commit message
    ...

    Da ich die Commit-Nachricht für diese 2 Commits ändern möchte. Ich werde also eingeben r o reword anstelle von pick . Speichern Sie dann die Datei und schließen Sie die Registerkarte. Beachten Sie, dass rebase wird in einem mehrstufigen Prozess ausgeführt, so dass der nächste Schritt die Aktualisierung der Nachrichten ist. Beachten Sie auch, dass die Commits in umgekehrter chronologischer Reihenfolge angezeigt werden, d.h. der letzte Commit wird in dieser Zeile angezeigt und der erste Commit in der ersten Zeile und so weiter.

  3. Aktualisieren Sie die Nachrichten: Aktualisieren Sie die erste Nachricht:

    docs: Add created date and project title to the documentation "README.md"
    
    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    ...

    speichern und schließen Bearbeiten Sie die zweite Nachricht

    docs: Add project description and included files to the documentation "README.md"
    
    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    ...

    speichern und schließen.

  4. Am Ende des Umbaus erhalten Sie eine Meldung wie diese: Successfully rebased and updated refs/heads/documentation was bedeutet, dass Sie Erfolg haben. Sie können die Änderungen anzeigen:

    5dff827 (HEAD -> documentation) docs: Add project description and included files to the documentation "README.md"
    4585c68 docs: Add created date and project title to the documentation "README.md"
    eaf7978 (origin/master, origin/HEAD, master) Inital commit
    46a5819 Create README.md

    Ich wünsche mir, dass dies den neuen Benutzern hilft :).

13voto

Tom Hale Punkte 32065

Automatisierter interaktiver Rebase-Edit, gefolgt von einem Commit Revert, bereit für einen Do-over

Ich habe eine frühere Übergabe so oft korrigiert, dass ich ein Skript dafür geschrieben habe.

Hier ist der Arbeitsablauf:

  1. git commit-edit <commit-hash>

    Dadurch gelangen Sie zu der Übergabe, die Sie bearbeiten möchten.

  2. Reparieren Sie die Übergabe so, wie Sie es sich wünschen.

    (Möglicherweise möchten Sie die git stash save um alle Dateien aufzubewahren, die Sie nicht übertragen wollen)

  3. Wiederholen Sie die Übergabe mit --amend , z.B.:

    git commit --amend
  4. Schließen Sie die Umbasierung ab:

    git rebase --continue

Damit dies funktioniert, fügen Sie das folgende Skript in eine ausführbare Datei namens git-commit-edit irgendwo in Ihrem $PATH :

#!/bin/bash

set -euo pipefail

script_name=${0##*/}

warn () { printf '%s: %s\n' "$script_name" "$*" >&2; }
die () { warn "$@"; exit 1; }

[[ $# -ge 2 ]] && die "Expected single commit to edit. Defaults to HEAD~"

# Default to editing the parent of the most recent commit
# The most recent commit can be edited with `git commit --amend`
commit=$(git rev-parse --short "${1:-HEAD~}")
message=$(git log -1 --format='%h %s' "$commit")

if [[ $OSTYPE =~ ^darwin ]]; then
  sed_inplace=(sed -Ei "")
else
  sed_inplace=(sed -Ei)
fi

export GIT_SEQUENCE_EDITOR="${sed_inplace[*]} "' "s/^pick ('"$commit"' .*)/edit \\1/"'
git rebase --quiet --interactive --autostash --autosquash "$commit"~
git reset --quiet @~ "$(git rev-parse --show-toplevel)"  # Reset the cache of the toplevel directory to the previous commit
git commit --quiet --amend --no-edit --allow-empty  #  Commit an empty commit so that that cache diffs are un-reversed

echo
echo "Editing commit: $message" >&2
echo

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X