Wie ändere ich ein bestimmtes Commit?


2233

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

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

... Ich weiß, dass ich Head Commit mit ändern kann git commit --amend. Aber wie kann ich Änderungen vornehmen Commit1, da es sich nicht um das HEADCommit handelt?


31
Eine alternative Antwort finden Sie hier: stackoverflow.com/a/18150592/520567 Ihre akzeptierte Antwort ist wirklich eine genaue Antwort auf Ihre Frage. Wenn Sie jedoch Ihr neues Commit bereit haben, bevor Sie sich für die Verwendung von edit entschieden haben, ist diese Antwort einfacher. Es kann auch mit mehreren Commits arbeiten, die Sie zusammen mit einem älteren zusammenführen / quetschen möchten.
Akostadinov

6
Weitere Informationen finden Sie unter Aufteilen eines Commits in Git Tools - Umschreiben des Verlaufs .
hakre

Antworten:


2955

Sie können Git Rebase verwenden . Wenn Sie beispielsweise das Commit ändern möchten bbc643cd, führen Sie es aus

$ git rebase --interactive 'bbc643cd^'

Bitte beachten Sie das Caret ^am Ende des Befehls, da Sie tatsächlich auf das Commit zurückgreifen müssen , bevor Sie es ändern möchten .

Im Standard - Editor, ändern , pickum editin der Linie zu erwähnen ‚bbc643cd‘.

Speichern Sie die Datei und beenden Sie: git interpretiert die Befehle in der Datei und führt sie automatisch aus. Sie befinden sich in der vorherigen Situation, in der Sie gerade ein Commit erstellt haben bbc643cd.

An diesem Punkt bbc643cdist Ihr letztes Commit und Sie können es leicht ändern : Nehmen Sie Ihre Änderungen vor und schreiben Sie sie dann mit dem Befehl fest:

$ git commit --all --amend --no-edit

Geben Sie danach Folgendes ein:

$ git rebase --continue

um zum vorherigen HEAD-Commit zurückzukehren.

WARNUNG : Beachten Sie, dass dies den SHA-1 dieses Commits sowie alle untergeordneten Elemente ändert. Mit anderen Worten, dies schreibt den Verlauf von diesem Punkt an neu. Sie können Repos dabei unterbrechen, wenn Sie mit dem Befehl drückengit push --force


125
Eine weitere interessante Option in diesem Ablauf besteht darin, dass Sie das Commit möglicherweise in zwei verschiedene Commits aufteilen, nachdem Sie zu dem Commit gewechselt sind, das Sie ändern möchten, anstatt Dateien zu ändern und über das Commit oben (das, das Sie bearbeiten) zu übertragen (oder noch mehr). In diesem Fall kehren Sie zum Bearbeiten zum Festschreiben zurück und führen Sie "git reset HEAD ^" aus. Dadurch werden die geänderten Dateien dieses Commits auf die Bühne gebracht. Wählen Sie nun alle gewünschten Dateien aus und legen Sie sie fest. Dieser Ablauf wird in der Manpage "git-rebase" recht gut erklärt. Siehe Abschnitt "Aufteilen von Commits". bit.ly/d50w1M
Diego Pino

200
In Git 1.6.6 und höher können Sie die rewordAktion in git rebase -ianstelle von verwenden edit(sie öffnet automatisch den Editor und fährt mit den restlichen Rebase-Schritten fort; dies vermeidet die Verwendung von git commit --ammendund git rebase --continuewenn Sie nur die Commit-Nachricht und nicht den Inhalt ändern müssen ).
Chris Johnsen

108
Es ist erwähnenswert, dass Sie möglicherweise git stashvorher git rebaseund git stash popnachher ausführen müssen , wenn Änderungen anstehen.
user123444555621

3
Gibt es einen Shortucut-Befehl zum Bearbeiten eines bestimmten Commits in der interaktiven Rebase, ohne den Editor zu öffnen, das Commit zu finden, es als Bearbeiten zu markieren und dann zur Befehlszeile zurückzukehren?
sstur

15
Beachten Sie, dass es mit neuerem Git klüger wäre, sofortige Anweisungen zu befolgen, anstatt sie git commit --all --amend --no-edithier blind zu verwenden . Alles was ich danach tun musste git rebase -i ...war dann git commit --amendnormal zu sein git rebase --continue.
Eric Chen

453

Verwenden Sie die fantastische interaktive Rebase:

git rebase -i @~9   # Show the last 9 commits in a text editor

Suchen Sie das gewünschte Commit, ändern Sie es pickin e( edit) und speichern und schließen Sie die Datei. Git wird zu diesem Commit zurückspulen, sodass Sie entweder:

  • verwenden git commit --amend, um Änderungen vorzunehmen, oder
  • Verwenden Sie git reset @~diese Option, um das letzte Commit zu verwerfen, jedoch nicht die Änderungen an den Dateien (dh, Sie gelangen zu dem Punkt, an dem Sie die Dateien bearbeitet, aber noch nicht festgeschrieben hatten).

Letzteres ist nützlich, um komplexere Aufgaben wie das Aufteilen in mehrere Commits auszuführen.

Führen Sie dann aus git rebase --continue, und Git spielt die nachfolgenden Änderungen zusätzlich zu Ihrem geänderten Commit erneut ab. Möglicherweise werden Sie aufgefordert, einige Zusammenführungskonflikte zu beheben.

Hinweis: @ist eine Abkürzung für HEADund ~ist das Commit vor dem angegebenen Commit.

Weitere Informationen zum Umschreiben des Verlaufs finden Sie in den Git-Dokumenten.


Hab keine Angst, dich zu erholen

ProTip ™: Haben Sie keine Angst, mit "gefährlichen" Befehlen zu experimentieren, die den Verlauf neu schreiben. * - Git löscht Ihre Commits standardmäßig 90 Tage lang nicht. Sie finden sie im Reflog:

$ git reset @~3   # go back 3 commits
$ git reflog
c4f708b HEAD@{0}: reset: moving to @~3
2c52489 HEAD@{1}: commit: more changes
4a5246d HEAD@{2}: commit: make important changes
e8571e4 HEAD@{3}: commit: make some changes
... earlier commits ...
$ git reset 2c52489
... and you're back where you started

* Achten Sie auf Optionen wie --hardund --forceobwohl - sie können Daten verwerfen.
* Schreiben Sie den Verlauf auch nicht in Zweigen neu, in denen Sie zusammenarbeiten.



Auf vielen Systemen git rebase -iwird Vim standardmäßig geöffnet. Vim funktioniert nicht wie die meisten modernen Texteditoren. Sehen Sie sich also an, wie Sie mit Vim die Basis neu erstellen können . Wenn Sie lieber einen anderen Editor verwenden möchten, ändern Sie ihn mit git config --global core.editor your-favorite-text-editor.


29
Die Mitte Ihrer Antwort ist ein seltsamer Ort, um das zu platzieren, was ich nur als Möbelwerbung für VIM bezeichnen kann. Es ist für die Frage irrelevant und bringt Ihre Antwort nur durcheinander.
Absichten

21
@Intentss: Ah, ich kann sehen, warum das komisch aussah. Der Grund dafür war, dass Vim auf vielen Systemen der Standard-Texteditor ist. Die erste Erfahrung vieler Menschen mit interaktiver Neugründung ist ein Bildschirm, auf dem der Cursor durch Tippen überall herumfliegt. Dann wechseln sie ihren Editor zu etwas anderem, und ihre zweite Erfahrung mit interaktiver Neugründung ist ziemlich normal, lässt sie jedoch fragen, warum eine Textdatei anstelle einer GUI verwendet wird. Um einen Flow mit Rebasing zu erreichen, benötigen Sie etwas wie Vim oder den Rebase-Modus von Emacs.
Zaz

9
Okay. Da so viele Leute diesen Teil für irrelevant halten, habe ich ihn auf drei Zeilen reduziert und auch erklärt, wie man den Editor bei Bedarf ändert.
Zaz

17
Genial! Ich wusste nicht, dass Sie @als Abkürzung für verwenden können HEAD. Vielen Dank für die Veröffentlichung.
James Ko

3
git reset @~genau das, was ich tun wollte, nachdem ich mich für Commit entschieden hatte git rebase .... Du bist mein Held)
18augst

79

Interaktives Rebase mit --autosquashist etwas, das ich häufig verwende, wenn ich frühere Commits tiefer im Verlauf korrigieren muss. Dies beschleunigt im Wesentlichen den Prozess, den die Antwort von ZelluX veranschaulicht, und ist besonders praktisch, wenn Sie mehr als ein Commit bearbeiten müssen.

Aus der Dokumentation:

--autosquash

Wenn die Commit-Protokollnachricht mit "squash! ..." (oder "fixup! ...") beginnt und ein Commit vorliegt, dessen Titel mit demselben beginnt, ändern Sie automatisch die Aufgabenliste von rebase -i, sodass das Commit ausgeführt wird Das zum Quetschen markierte wird direkt nach dem zu ändernden Commit angezeigt

Angenommen, Sie haben eine Geschichte, die so aussieht:

$ git log --graph --oneline
* b42d293 Commit3
* e8adec4 Commit2
* faaf19f Commit1

und Sie haben Änderungen, die Sie an Commit2 ändern möchten, und übernehmen dann Ihre Änderungen mit

$ git commit -m "fixup! Commit2"

Alternativ können Sie das Commit-sha anstelle der Commit-Nachricht verwenden, "fixup! e8adec4oder sogar nur ein Präfix der Commit-Nachricht.

Starten Sie dann zuvor eine interaktive Rebase für das Commit

$ git rebase e8adec4^ -i --autosquash

Ihr Editor wird mit den bereits korrekt bestellten Commits geöffnet

pick e8adec4 Commit2
fixup 54e1a99 fixup! Commit2
pick b42d293 Commit3

Sie müssen lediglich speichern und beenden


21
Sie können auch git commit --fixup=@~anstelle von verwenden git commit -m "fixup! Commit2". Dies ist besonders nützlich, wenn Ihre Commit-Nachrichten länger sind und es schwierig wäre, das Ganze abzutippen.
Zaz

42

Lauf:

$ git rebase --interactive commit_hash^

Jedes ^gibt an, wie viele Commits Sie zurück bearbeiten möchten. Wenn es nur eines ist (der von Ihnen angegebene Commit-Hash), fügen Sie einfach einen hinzu^ .

Mit Vim Sie die Wörter ändern , pickum rewordfür die Commits Sie ändern möchten, zu speichern und beenden ( :wq). Dann fordert git Sie bei jedem Commit auf, das Sie als Reword markiert haben, damit Sie die Commit-Nachricht ändern können.

Jede Festschreibungsnachricht müssen Sie speichern und beenden ( :wq), um zur nächsten Festschreibungsnachricht zu gelangen

Wenn Sie beenden möchten, ohne die Änderungen zu übernehmen, drücken Sie :q!

BEARBEITEN : Um darin zu navigieren , gehen vimSie jnach oben, knach unten, hnach links und lnach rechts (alles im NORMALModus, drücken Sie ESC, um in den NORMALModus zu wechseln). Um einen Text zu bearbeiten, drücken iSie, um in den INSERTModus zu gelangen, in dem Sie Text einfügen. Drücken Sie ESC, um zum NORMALModus zurückzukehren :)

UPDATE : Hier ist ein großartiger Link aus der Github-Liste. Wie man (fast) alles mit Git rückgängig macht


4
Hat perfekt für mich funktioniert. Erwähnenswert git push --force?
u01jmg3

Was git push --forceüberschreibt, ist das Überschreiben der Remote-Commits mit Ihren lokalen Commits. Das ist nicht der Fall bei diesem Thema :)
Betoharres

@BetuUuUu Natürlich, wenn Ihre Commits auf Remote übertragen werden und Sie die Commit-Nachricht lokal geändert haben, möchten Sie Push auf Remote erzwingen, nicht wahr?
Sudip Bhandari

@ SudipBhandari Das ist das Gefühl, das ich bekomme. Ich habe nicht erzwungen, und jetzt habe ich einen zusätzlichen Zweig, der alle Commits auf den zurückspiegelt, dessen Nachricht ich geändert habe, was super hässlich ist.
Ruffin

2
@greenhouse Wenn Sie Änderungen vornehmen und Push erzwingen, werden andere Teammitglieder höchstwahrscheinlich auf Zusammenführungskonflikte stoßen. Sie sollten also generell sehr vorsichtig sein. Aber wenn Sie etwas ändern, das noch niemand abgerufen hat, sollte es in Ordnung sein (das wird es nicht bemerken). Daher würde ich --force als letzten Ausweg betrachten und immer den Stand des Repos mit anderen Mitgliedern konsultieren.
Tomasz Kaczmarzyk

18

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

Angenommen, Sie möchten Änderungen vornehmen Commit1. Verzweigen Sie zuerst von vor Commit1 :

git checkout -b amending [commit before Commit1]

Zweitens greifen Commit1mit 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 gespeichert haben, übertragen Sie den Rest Ihrer Commits zusätzlich zu masterIhrem neuen Commit:

git rebase --onto amending Commit1 master

Lesen Sie: "Rebase auf den Zweig amending, alle Commits zwischen Commit1(nicht inklusive) und master(inklusive)". Das heißt, Commit2 und Commit3 schneiden das alte Commit1 vollständig aus. Sie könnten sie einfach pflücken, aber dieser Weg ist einfacher.

Denken Sie daran, Ihre Zweige aufzuräumen!

git branch -d amending

4
Sie können verwenden git checkout -b amending Commit1~1, um das vorherige Commit zu erhalten
Arin Taylor

Entsprechen die ersten beiden Schritte git checkout -b amending Commit1?
Haoshu

16

Basierend auf Dokumentation

Ändern der Nachricht älterer oder mehrerer Festschreibungsnachrichten

git rebase -i HEAD~3 

Oben wird eine Liste der letzten 3 Commits für den aktuellen Zweig angezeigt. Ändern Sie 3 in etwas anderes, wenn Sie mehr möchten. Die Liste sieht folgendermaßen aus:

pick e499d89 Delete CNAME
pick 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.

Ersetzen Sie pick durch reword vor jeder Commit-Nachricht, die Sie ändern möchten. Angenommen, Sie ändern das zweite Commit in der Liste. Ihre Datei sieht folgendermaßen aus:

pick e499d89 Delete CNAME
reword 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.

Speichern und schließen Sie die Festschreibungslistendatei. Daraufhin wird ein neuer Editor angezeigt, mit dem Sie Ihre Festschreibungsnachricht ändern, die Festschreibungsnachricht ändern und speichern können.

Finaly Force-Push die geänderten Commits.

git push --force

Ich erhalte folgenden Fehler: Fehler: Es gab ein Problem mit dem Editor 'vi'. Bitte geben Sie die Nachricht entweder mit der Option -m oder -F ein.
Erick Maynard

12

Vollständig nicht interaktiver Befehl (1)

Ich dachte nur, ich würde einen Alias ​​teilen, den ich dafür verwende. Es basiert auf einer nicht interaktiven interaktiven Basis. Führen Sie diesen Befehl aus, um es Ihrem Git hinzuzufügen (Erklärung 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'

Der größte Vorteil dieses Befehls ist die Tatsache, dass es kein Vim ist .


(1) da es natürlich keine Konflikte während der Rebase gibt

Verwendungszweck

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

Der Name amend-toscheint meiner Meinung nach 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 ​​mit dem Namen <NAME>, der einen Nicht-Git-Befehl ausführt<COMMAND>
  • f() { <BODY> }; f - eine "anonyme" Bash-Funktion.
  • SHA=`git rev-parse "$1"`; - konvertiert das Argument in eine Git-Revision und weist das Ergebnis einer Variablen zu SHA
  • git commit --fixup "$SHA"- Fixup-Commit für SHA. Siehe git-commitDokumente
  • GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
    • git rebase --interactive "$SHA^" Teil wurde durch andere Antworten abgedeckt.
    • --autosquashwird in Verbindung mit verwendet git commit --fixup. Weitere Informationen finden Sie in den git-rebaseDokumenten
    • GIT_SEQUENCE_EDITOR=truemacht das Ganze nicht interaktiv. Diesen Hack habe ich aus diesem Blogbeitrag gelernt .

1
Man kann auch nicht amend-tobereitgestellte Dateien verarbeiten: 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'
Dethariel

2
Ein Problem bei dieser Methode ist, dass nicht verwandte Korrekturen angewendet werden können.
Ciro Santilli 3 病毒 审查 六四 事件 法轮功

Ist es nicht der Sinn der Frage, die Festschreibungsnachricht zu ändern? Weil diese Antwort das nicht oder zumindest nicht direkt anspricht.
Wytten

@wytten die Frage fragt nicht nach dem Ändern der Commit-Nachricht, es geht darum, das Commit zu ändern, das nicht HEAD ist. Eine Antwort auf Ihre Frage wäre also "Nein, es ist nicht der Punkt der Frage"
Dethariel

Ich bin verwirrt. Wie ändern wir die Commit-Nachricht?
ggb667

8

Automatisierte interaktive Rebase-Bearbeitung, gefolgt von Commit-Revert, bereit für eine Überarbeitung

Ich habe festgestellt, dass ich ein Commit in der Vergangenheit häufig genug repariert habe, dass ich ein Skript dafür geschrieben habe.

Hier ist der Workflow:

  1. git commit-edit <commit-hash>
    

    Dadurch werden Sie an dem Commit abgelegt, den Sie bearbeiten möchten.

  2. Korrigieren und inszenieren Sie das Commit so, wie Sie es sich gewünscht haben.

    (Möglicherweise möchten git stash saveSie Dateien behalten, die Sie nicht festschreiben.)

  3. Wiederholen Sie das Commit mit --amendz.

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

    git rebase --continue
    

Damit das oben genannte funktioniert, fügen Sie das folgende Skript in eine ausführbare Datei ein, die git-commit-editirgendwo in Ihrem Verzeichnis aufgerufen wird $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

7

Kam zu diesem Ansatz (und es ist wahrscheinlich genau das gleiche wie die Verwendung von interaktiver Rebase), aber für mich ist es ziemlich einfach.

Hinweis: Ich präsentiere diesen Ansatz, um zu veranschaulichen, was Sie tun können, anstatt eine alltägliche Alternative zu sein. Da es viele Schritte hat (und möglicherweise einige Einschränkungen.)

Angenommen, Sie möchten das Commit ändern 0und sind gerade aktivfeature-branch

some-commit---0---1---2---(feature-branch)HEAD

Kasse zu diesem Commit und erstelle ein quick-branch. Sie können Ihren Feature-Zweig auch als Wiederherstellungspunkt klonen (bevor Sie beginnen).

?(git checkout -b feature-branch-backup)
git checkout 0
git checkout -b quick-branch

Sie werden jetzt so etwas haben:

0(quick-branch)HEAD---1---2---(feature-branch)

Bühnenwechsel, alles andere verstauen.

git add ./example.txt
git stash

Übernehmen Sie die Änderungen und checken Sie zurück zu feature-branch

git commit --amend
git checkout feature-branch

Sie werden jetzt so etwas haben:

some-commit---0---1---2---(feature-branch)HEAD
           \
             ---0'(quick-branch)

Rebase feature-branchauf quick-branch(lösen Konflikte auf dem Weg). Stash auftragen und entfernen quick-branch.

git rebase quick-branch
git stash pop
git branch -D quick-branch

Und am Ende haben Sie:

some-commit---0'---1'---2'---HEAD(feature-branch)

Git wird die 0-Festschreibung beim erneuten Basieren nicht duplizieren (obwohl ich nicht wirklich sagen kann, inwieweit).

Hinweis: Alle Commit-Hashes werden ab dem Commit geändert, den wir ursprünglich ändern wollten.


6

Um einen nicht interaktiven Befehl zu erhalten, fügen Sie ein Skript mit diesem Inhalt in Ihren PFAD ein:

#!/bin/sh
#
# git-fixup
# Use staged changes to modify a specified commit
set -e
cmt=$(git rev-parse $1)
git commit --fixup="$cmt"
GIT_EDITOR=true git rebase -i --autosquash "$cmt~1"

Verwenden Sie es, indem Sie Ihre Änderungen (mit git add) bereitstellen und dann ausführen git fixup <commit-to-modify>. Natürlich bleibt es interaktiv, wenn Konflikte auftreten.


1
Das funktioniert gut. Ich habe einige zusätzliche Funktionen hinzugefügt, um stückweise Korrekturen eines schmutzigen Baums durchzuführen, um ein Commit-Set zu perfektionieren. `dirtydiff = $ (git diff); if ["$ {dirtydiff}"! = ""]; dann Echo "Stashing schmutziger Baum"> & 2; Git Stash; fi;
Simon Feltman

6

git stash+ rebaseAutomatisierung

Wenn ich ein altes Commit für Gerrit-Überprüfungen häufig ändern muss, habe ich Folgendes 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 stromaufwärts .

Verwendungszweck:

  • Quelldatei ändern, keine Notwendigkeit, git addwenn bereits im Repo
  • git-amend-old $old_sha

Ich mag das vorbei, --autosquashda es andere nicht verwandte Fixups nicht zerquetscht.


Sehr gute Problemumgehung, dies sollte eine Standardoption sein git amend, um Änderungen an einem bestimmten Commit mit dem aktuellen Stash anzuwenden, sehr clever!
Caiohamamura

5

Ich habe das gelöst,

1) durch Erstellen eines neuen Commits mit Änderungen, die ich möchte.

r8gs4r commit 0

2) Ich weiß, welches Commit ich brauche, um es zusammenzuführen. Das ist Commit 3.

Daher steht git rebase -i HEAD~4# 4 für das Commit der letzten 4 (hier steht Commit 3 auf dem 4. Platz).

3) In der interaktiven Rebase befindet sich das letzte Commit unten. es wird gleich aussehen,

pick q6ade6 commit 3
pick vr43de commit 2
pick ac123d commit 1
pick r8gs4r commit 0

4) Hier müssen wir das Commit neu anordnen, wenn Sie mit einem bestimmten zusammenführen möchten. es sollte so sein,

parent
|_child

pick q6ade6 commit 3
f r8gs4r commit 0
pick vr43de commit 2
pick ac123d commit 1

Nach der Neuanordnung müssen Sie ersetzen p pickdurch f( Fixup wird ohne Festschreibungsnachricht zusammengeführt) oder s( Squash- Zusammenführung mit Festschreibungsnachricht kann sich zur Laufzeit ändern)

und dann rette deinen Baum.

Jetzt mit vorhandenem Commit zusammenführen.

Hinweis: Dies ist keine vorzuziehende Methode, es sei denn, Sie warten alleine. Wenn Sie eine große Teamgröße haben, ist es keine akzeptable Methode, den Git-Baum neu zu schreiben. Dies führt zu Konflikten, von denen Sie wissen, dass andere dies nicht tun. Wenn Sie Ihren Baum mit weniger Commits sauber halten möchten, können Sie dies versuchen und wenn sein kleines Team sonst nicht vorzuziehen ist .....


Dies ist eine gute Lösung, wenn Sie während einer interaktiven Rebase keine Live-Änderungen vornehmen möchten.
Dunatotatos

4

Die beste Option ist die Verwendung des Befehls "Interaktiver Rebase" .

Der git rebaseBefehl ist unglaublich mächtig. Sie können Commit-Nachrichten bearbeiten , Commits kombinieren, neu anordnen ... usw.

Jedes Mal, wenn Sie ein Commit neu starten, wird für jedes Commit ein neuer SHA erstellt, unabhängig davon, ob der Inhalt geändert wird oder nicht! Sie sollten vorsichtig sein, wenn Sie diesen Befehl verwenden, da er drastische Auswirkungen haben kann, insbesondere wenn Sie mit anderen Entwicklern zusammenarbeiten. Möglicherweise arbeiten sie mit Ihrem Commit, während Sie einige neu festlegen. Nachdem Sie die Commits erzwungen haben, sind sie nicht mehr synchron und können dies später in einer unordentlichen Situation herausfinden. Also sei vorsichtig!

Es wird empfohlen, backupvor dem erneuten Basieren einen Zweig zu erstellen, damit Sie immer dann zum vorherigen Status zurückkehren können, wenn Sie außer Kontrolle geraten.

Wie benutzt man nun diesen Befehl?

git rebase -i <base> 

-istehen für "interaktiv" . Beachten Sie, dass Sie eine Rebase im nicht interaktiven Modus durchführen können. Ex:

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

HEADGibt Ihren aktuellen Standort an (kann auch Filialname oder Commit-SHA sein). Das~n bedeutet "n beforeé", also HEAD~ndie Liste der "n" Commits vor dem, auf dem Sie sich gerade befinden.

git rebase hat andere Befehle wie:

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

    Hinweis: Es ist besser, Git mit Ihrem Code-Editor zum Laufen zu bringen, um die Arbeit zu vereinfachen. Wenn Sie beispielsweise visuellen Code verwenden, können Sie diesen 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 von git rebase

Ich wollte die letzten 2 Commits ändern, die ich gemacht habe, also verarbeite ich so:

  1. Zeigen Sie die aktuellen Commits 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 git rebaseändere ich die 2 letzten Commit-Nachrichten: $git rebase -i HEAD~2 Es öffnet den Code-Editor und zeigt Folgendes:

    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 möchte ich die Commit-Nachricht für diese 2 Commits ändern. Also werde ich tippen roder rewordanstelle von pick. Speichern Sie dann die Datei und schließen Sie die Registerkarte. Beachten Sie, dass dies rebasein einem mehrstufigen Prozess ausgeführt wird. Der nächste Schritt besteht darin, die Nachrichten zu aktualisieren. Beachten Sie auch, dass die Festschreibungen in umgekehrter chronologischer Reihenfolge angezeigt werden, sodass die letzte Festschreibung in dieser und die erste Festschreibung in der ersten Zeile usw. angezeigt wird.

  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 der Rebase erhalten Sie eine solche Nachricht: Dies Successfully rebased and updated refs/heads/documentationbedeutet, dass Sie erfolgreich sind. 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ünschte, das könnte den neuen Benutzern helfen :).


2

Für mich war es das Entfernen einiger Anmeldeinformationen aus einem Repo. Ich habe versucht, neu zu gründen, und bin dabei auf eine Menge scheinbar nicht zusammenhängender Konflikte gestoßen, als ich versucht habe, neu zu gründen - weiterzumachen. Versuchen Sie nicht, sich neu zu gründen, sondern verwenden Sie das Tool BFG (Brew Install Bfg) auf dem Mac.


0

Wenn Sie die Commits noch nicht gepusht haben, können Sie mit zu einem vorherigen Commit zurückkehren git reset HEAD^[1,2,3,4...]

Zum Beispiel

git commit <file1> -m "Updated files 1 and 2"
git commit <file3> -m "Updated file 3"

Hoppla, ich habe vergessen, file2 zum ersten Commit hinzuzufügen ...

git reset HEAD^1 // because I only need to go back 1 commit

git add <file2>

Dadurch wird Datei2 zum ersten Commit hinzugefügt.


0

Nun, diese Lösung mag sehr albern klingen, kann Sie aber unter bestimmten Bedingungen retten.

Ein Freund von mir hat gerade versehentlich einige sehr große Dateien festgeschrieben (vier automatisch generierte Dateien zwischen 3 GB und 5 GB) und dann einige zusätzliche Code-Commits durchgeführt, bevor er das Problem erkannte, das git pushnicht mehr funktionierte!

Die Dateien wurden aufgelistet, .gitignoreaber nach dem Umbenennen des Containerordners wurden sie verfügbar gemacht und festgeschrieben! Und jetzt gab es noch ein paar weitere Commits des Codes, die jedoch pushfür immer ausgeführt wurden (beim Versuch, GB Daten hochzuladen!) Und schließlich aufgrund der Dateigrößenbeschränkungen von Github fehlschlagen würden .

Das Problem mit interaktiver Rebase oder Ähnlichem war, dass sie sich mit dem Stöbern in diesen riesigen Dateien befassen und ewig brauchen würden, um etwas zu tun. Trotzdem waren wir uns nach fast einer Stunde in der CLI nicht sicher, ob die Dateien (und Deltas) tatsächlich aus dem Verlauf entfernt oder einfach nicht in den aktuellen Commits enthalten sind. Der Push funktionierte auch nicht und mein Freund steckte wirklich fest.

Die Lösung, die ich gefunden habe, war:

  1. Benennen Sie den aktuellen Git-Ordner in um ~/Project-old .
  2. Klonen Sie den Git-Ordner erneut von Github (bis ~/Project ).
  3. Kasse zur gleichen Filiale.
  4. Manuell cp -rdie Dateien von ~/Project-oldOrdner zu~/Project .
  5. Stellen Sie sicher, dass die massiven Dateien, die nicht eingecheckt werden müssen, mvbearbeitet und enthalten sind.gitignore ordnungsgemäß enthalten sind.
  6. Stellen Sie außerdem sicher, dass Sie den .gitOrdner im kürzlich geklonten Ordner nicht überschreiben~/Project von dem alten . Hier leben die Protokolle der problematischen Geschichte!
  7. Überprüfen Sie nun die Änderungen. Es sollte die Vereinigung aller jüngsten Commits sein, mit Ausnahme der problematischen Dateien.
  8. Übernehmen Sie schließlich die Änderungen, und es ist gut, bearbeitet zu werden push.

Das größte Problem bei dieser Lösung besteht darin, dass einige Dateien manuell kopiert werden und alle kürzlich durchgeführten Commits zu einem zusammengeführt werden (offensichtlich mit einem neuen Commit-Hash). B.

Die großen Vorteile sind, dass es in jedem Schritt sehr klar ist, sowohl für große als auch für sensible Dateien hervorragend geeignet ist und keine Spuren in der Geschichte hinterlässt!

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.