Mercurial: Wie kann das letzte Commit geändert werden?

211

Ich suche nach einem Gegenstück zu git commit --amendMercurial, dh nach einer Möglichkeit, das Commit zu ändern, mit dem meine Arbeitskopie verknüpft ist. Ich interessiere mich nur für das letzte Commit, nicht für ein willkürliches früheres Commit.

Die Anforderungen für dieses Änderungsverfahren sind:

  • Wenn möglich, sollten keine Erweiterungen erforderlich sein. Es dürfen keine nicht standardmäßigen Erweiterungen erforderlich sein , dh Erweiterungen, die nicht mit einer offiziellen Mercurial-Installation geliefert werden.

  • Wenn die Änderungsverpflichtung ein Leiter meiner aktuellen Niederlassung ist, sollte kein neuer Leiter erstellt werden. Wenn das Commit kein Kopf ist, kann ein neuer Kopf erstellt werden.

  • Das Verfahren sollte so sicher sein , dass ich, wenn die Änderung aus irgendeinem Grund fehlschlägt, die gleiche Arbeitskopie und den gleichen Repository-Status wie vor der Änderung wiederherstellen möchte. Mit anderen Worten, wenn die Änderung selbst fehlschlagen kann, sollte es eine ausfallsichere Prozedur geben, um die Arbeitskopie und den Repository-Status wiederherzustellen. Ich beziehe mich auf "Fehler", die in der Art des Änderungsverfahrens liegen (wie z. B. Konflikte), nicht auf Probleme im Zusammenhang mit dem Dateisystem (wie Zugriffsbeschränkungen, das Nicht-Sperren einer Datei zum Schreiben, ... )

Update (1):

  • Die Prozedur muss automatisierbar sein , damit sie von einem GUI-Client ausgeführt werden kann, ohne dass eine Benutzerinteraktion erforderlich ist.

Update (2):

  • Dateien im Arbeitsverzeichnis dürfen nicht berührt werden (möglicherweise gibt es Dateisystemsperren für bestimmte geänderte Dateien). Dies bedeutet insbesondere, dass ein möglicher Ansatz zu keinem Zeitpunkt ein sauberes Arbeitsverzeichnis erfordern kann.
mstrap
quelle

Antworten:

289

Mit der Version von Mercurial 2.2 können Sie die --amendOption mit verwenden hg commit, um das letzte Commit mit dem aktuellen Arbeitsverzeichnis zu aktualisieren

Aus der Befehlszeilenreferenz :

Das Flag --amend kann verwendet werden, um das übergeordnete Element des Arbeitsverzeichnisses durch ein neues Commit zu ändern, das die Änderungen im übergeordneten Verzeichnis zusätzlich zu den Änderungen enthält, die derzeit vom hg-Status gemeldet werden, sofern vorhanden. Das alte Commit wird in einem Sicherungspaket in .hg / strip-backup gespeichert (siehe hg help bundle und hg help entbündeln, wie es wiederhergestellt werden kann).

Nachricht, Benutzer und Datum stammen aus dem geänderten Commit, sofern nicht anders angegeben. Wenn in der Befehlszeile keine Nachricht angegeben ist, wird der Editor mit der Nachricht des geänderten Commits geöffnet.

Das Tolle ist, dass dieser Mechanismus "sicher" ist, da er auf der relativ neuen Funktion "Phasen" basiert, um Aktualisierungen zu verhindern, die den Verlauf ändern würden, der bereits außerhalb des lokalen Repositorys verfügbar gemacht wurde.

Chris Phillips
quelle
2
Gute Antwort! Mit der experimentellen Evolve-Erweiterung können Sie Nicht-Head- Commits sicher ändern . Das alte Commit wird als veraltet und ausgeblendet markiert. Mit einem Nicht-Publishing-Server können Sie dies sogar sicher tun, nachdem Sie die Änderungssätze verschoben haben.
Martin Geisler
5
Um nur die Nachricht beim letzten Commit zu aktualisieren: hg commit --amend -m "Dies ist meine neue Nachricht"
Jay Sheth
52

Sie haben 3 Möglichkeiten, Commits in Mercurial zu bearbeiten:

  1. hg strip --keep --rev -1Machen Sie die letzten (1) Commits rückgängig, damit Sie sie erneut ausführen können ( weitere Informationen finden Sie in dieser Antwort ).

  2. Verwendung der MQ-Erweiterung , die im Lieferumfang von Mercurial enthalten ist

  3. Auch wenn es nicht mit Mercurial geliefert wird , ist die Histedit- Erweiterung erwähnenswert

Sie können auch einen Blick auf die Seite Bearbeitungsverlauf des Mercurial-Wikis werfen .

Kurz gesagt, die Bearbeitung des Verlaufs ist sehr schwierig und entmutigend . Und wenn Sie Ihre Änderungen bereits vorgenommen haben, können Sie kaum etwas tun, außer wenn Sie die vollständige Kontrolle über alle anderen Klone haben.

Ich bin mit dem git commit --amendBefehl nicht wirklich vertraut , aber AFAIK, Histedit scheint der naheliegendste Ansatz zu sein, aber leider wird er nicht mit Mercurial ausgeliefert. Die Verwendung von MQ ist sehr kompliziert, aber Sie können fast alles damit machen.

krtek
quelle
1
Ich bin mir nicht sicher, warum ich das Rollback verpasst habe, aber es scheint (fast) das zu tun, was ich will. Das einzige Problem besteht darin, dass eine Datei, die für mein ursprüngliches Commit entfernt und für mein geändertes Commit wiederbelebt wurde, vor dem Rollback nicht mehr konvertiert wird. Nach dem Rollback wird die Entfernung geplant (die Datei ist jedoch noch in vorhanden das Arbeitsverzeichnis)
mstrap
@Marc Ich bin mir nicht sicher, ob ich Ihr Problem verstehe, aber schauen Sie sich den Befehl zum Vergessen an. Ich denke, es ist das, wonach Sie suchen.
krtek
Ich denke nicht, dass "Vergessen" hier hilfreich sein wird. Hier ist das Problem im Detail: (1) Ich bin bei Revision 2 (2) Entfernen Sie "Datei" und haben Sie einige andere Änderungen. (3) Übernehmen Sie Änderungen, was zu Revision 3 führt. (4) Jetzt werde ich meine Meinung ändern und entscheiden "Datei" sollte nicht aus dem Commit entfernt werden, daher möchte ich Revision 3 ändern. Daher füge ich erneut "Datei" hinzu, die jetzt nicht mehr konvertiert ist. (5) Jetzt führe ich einen Rollback durch: Der Dirstate wird zurückgesetzt und markiert. " Datei "wie entfernt. (6) Wenn Sie "hg commit" jetzt erneut ausführen, bleibt "file" entfernt, sollte es aber nicht mehr sein. Wie könnte eine automatisierte Lösung dafür aussehen?
Mstrap
1
Für den automatisierten Teil weiß ich nicht, aber Sie können hg revert myfiledas Löschen rückgängig machen. Möglicherweise wird hg adddie Datei erneut hinzugefügt, nachdem dies rollbackebenfalls funktioniert hat.
krtek
3
Ich bin damit einverstanden, dass die Bearbeitung des Verlaufs veröffentlichter Änderungen vermieden werden sollte, aber die Bearbeitung meines lokalen Verlaufs ist einer der Höhepunkte eines DVCS. MQ mit seinem qimport ist AFAICT.
Mstrap
38

GUI-Äquivalent für hg commit --amend:

Dies funktioniert auch über die GUI von TortoiseHG (ich verwende v2.5):

Wechseln Sie in die Ansicht "Commit" oder wählen Sie in der Workbench-Ansicht den Eintrag "Arbeitsverzeichnis". Die Schaltfläche "Festschreiben" enthält die Option "Aktuelle Version ändern" (klicken Sie auf den Dropdown-Pfeil der Schaltfläche, um sie zu finden).

Geben Sie hier die Bildbeschreibung ein

          ||
          ||
          \/

Geben Sie hier die Bildbeschreibung ein

Vorbehalt :

Diese zusätzliche Option wird nur aktiviert, wenn die Mercurial-Version mindestens 2.2.0 ist und wenn die aktuelle Version nicht öffentlich ist, kein Patch ist und keine untergeordneten Elemente enthält. [...]

Wenn Sie auf die Schaltfläche klicken, wird "commit --amend" aufgerufen, um die Revision zu "ändern".

Weitere Infos dazu auf dem THG Dev Channel

Cristian Diaconescu
quelle
Sehr hilfreich, danke. THG ist intelligent genug, um die Commit- (Änderungs-) Nachricht standardmäßig auf die Nachricht aus dem vorherigen Commit zu übertragen - genau das, was ich wollte.
UuDdLrLrSs
7

Ich stimme auf das ein, was krtek geschrieben hat. Genauer gesagt Lösung 1:

Annahmen:

  • Sie haben einen (!) Änderungssatz festgeschrieben, ihn aber noch nicht gepusht
  • Sie möchten diesen Änderungssatz ändern (z. B. Dateien hinzufügen, entfernen oder ändern und / oder die Festschreibungsnachricht).

Lösung:

  • Verwenden Sie hg rollbackdiese Option, um das letzte Commit rückgängig zu machen
  • Mit den neuen Änderungen erneut festschreiben

Der Rollback macht den letzten Vorgang wirklich rückgängig. Die Arbeitsweise ist recht einfach: Bei normalen Vorgängen in HG werden nur Dateien angehängt. Dies beinhaltet ein Commit. Mercurial verfolgt die Dateilängen der letzten Transaktion und kann daher einen Schritt vollständig rückgängig machen, indem die Dateien auf ihre alten Längen zurückgeschnitten werden.

Lucero
quelle
1
Vielen Dank für die Tuning-Lösung (1); Es gibt nur noch ein kleines Problem mit dem Rollback. Bitte beachten Sie meinen Kommentar zur Lösung von krtek.
Mstrap
8
Eine Sache, die beim Rollback hervorgehoben werden sollte, weil sie die Leute auffängt, ist, dass es die letzte Transaktion auf dem Repo ist, die zurückgesetzt wird, nicht das letzte Commit. Wenn also etwas anderes ein Schreiben in das Repo verursacht hat, hilft ein Rollback nicht. Es ist eine subtile, aber wichtige Sache, an die man sich erinnert. MQ und histedit können helfen, sobald das Rollback-Fenster geschlossen wurde, aber immer noch nur bis zu einem bestimmten Punkt.
Paul S
7

Angenommen, Sie haben Ihre Änderungen noch nicht weitergegeben, können Sie Folgendes tun.

  • Fügen Sie Ihrer .hgrc hinzu:

    [extensions]
    mq =
    
  • In Ihrem Repository:

    hg qimport -r0:tip
    hg qpop -a
    

    Natürlich müssen Sie nicht mit Revision Null beginnen oder alle Patches platzen lassen, denn für das letzte hg qpopgenügt nur ein Pop ( ) (siehe unten).

  • Entfernen Sie den letzten Eintrag in der .hg/patches/seriesDatei oder die Patches, die Sie nicht mögen. Nachbestellungen sind ebenfalls möglich.

  • hg qpush -a; hg qfinish -a
  • Entfernen Sie die .diffDateien (nicht angewendete Patches), die sich noch in .hg / patches befinden (sollte in Ihrem Fall eine sein).

Wenn Sie nicht wollen , um alle zurücknehmen Ihren Patch, können Sie es durch die Verwendung bearbeiten hg qimport -r0:tip(oder ähnlich), dann bearbeiten Sachen und Verwendung hg qrefreshdie Änderungen in die oberste Patch auf Ihrem Stapel zu verschmelzen. Lesen Sie hg help qrefresh.

Durch Bearbeiten .hg/patches/serieskönnen Sie sogar mehrere Patches entfernen oder einige neu anordnen. Wenn Ihre letzte Revision 99 ist, können Sie nur verwenden hg qimport -r98:tip; hg qpop; [edit series file]; hg qpush -a; hg qfinish -a.

Natürlich ist dieses Verfahren sehr entmutigt und riskant . Machen Sie eine Sicherungskopie von allem, bevor Sie dies tun!

Als Nebenbemerkung habe ich es zig Mal in privaten Repositories gemacht.

hochl
quelle
Ich hatte auch überlegt, mq-extension zu verwenden, erfordert jedoch ziemlich viele Operationen, für die einige von ihnen möglicherweise fehlschlagen (z. B. wenn Binärdateien beteiligt sind). Darüber hinaus ist es nicht akzeptabel, .hg / patch / series bearbeiten zu müssen, da dieses Verfahren in einem GUI-Client verwendet werden sollte (ich habe die Anforderungen oben aktualisiert)
mstrap
Hmmm, tut mir leid, dass das nichts für dich ist, in einem privaten Repository ist das wirklich ein Knaller (mit Backups - ich habe bereits einen Repräsentanten mit Fatfinger zerstört ^^). Es ist ziemlich cool, Patches zu einem zu kombinieren, bevor die lokalen Änderungen mit hg qfoldbtw
hochl
+1 für die Verwendung von MQ, aber ich denke, Sie sind über Bord gegangen. Er fragt nur nach einer Änderung des letzten Commits. Auch dieser Import wird umkippen, sobald er zusammengeführt wird. 'qimport -r tip; <Sachen bearbeiten>; qrefresh -e; qfin -a 'erledigt den Job (-e, um die Festschreibungsnachricht zu bearbeiten)
Paul S
Richtig, Zusammenführungen sind ein Problem. Normalerweise platziere ich nur einen Patch und verwende ihn hg import -r<prev>:tip. Schade, dass es für die vorherige Version keine Abkürzung gibt, wie bei Subversion.
hochl
2

Neuere Versionen von Mercurial enthalten die evolveErweiterung, die den hg amendBefehl bereitstellt . Auf diese Weise können Sie ein Commit ändern, ohne den Verlauf der Vorabänderung in Ihrer Versionskontrolle zu verlieren.

hg ändere [OPTION] ... [DATEI] ...

Aliase: aktualisieren

Kombinieren Sie ein Änderungsset mit Updates und ersetzen Sie es durch ein neues

Commits a new changeset incorporating both the changes to the given files
and all the changes from the current parent changeset into the repository.

See 'hg commit' for details about committing changes.

If you don't specify -m, the parent's message will be reused.

Behind the scenes, Mercurial first commits the update as a regular child
of the current parent. Then it creates a new commit on the parent's
parents with the updated contents. Then it changes the working copy parent
to this new combined changeset. Finally, the old changeset and its update
are hidden from 'hg log' (unless you use --hidden with log).

Eine vollständige Beschreibung der Erweiterung finden Sie unter https://www.mercurial-scm.org/doc/evolution/user-guide.html#example-3-amend-a-changeset-with-evolveevolve .

Karl Bartel
quelle
Die Wiederverwendung derselben Commit-Nachricht ist eine nette Funktion!
Mpen
1

Könnte nicht alle Probleme in der ursprünglichen Frage lösen, aber da dies der De-facto-Beitrag darüber zu sein scheint, wie Quecksilber das vorherige Commit ändern kann, werde ich meine Informationen im Wert von 2 Cent hinzufügen.

Wenn Sie wie ich sind und nur die vorherige Festschreibungsnachricht ändern möchten (Tippfehler beheben usw.), ohne Dateien hinzuzufügen, funktioniert dies

hg commit -X 'glob:**' --amend

Ohne Einschluss- oder Ausschlussmuster hg commitwerden standardmäßig alle Dateien im Arbeitsverzeichnis eingeschlossen. Durch das Anwenden eines Musters -X 'glob:**'werden alle möglichen Dateien ausgeschlossen, sodass nur die Festschreibungsnachricht geändert werden kann.

Funktionell ist es dasselbe, als git commit --amendob sich keine Dateien in Index / Stage befinden.

kaskelotti
quelle
0

Eine andere Lösung könnte darin bestehen, mit dem uncommitBefehl eine bestimmte Datei vom aktuellen Commit auszuschließen.

hg uncommit [file/directory]

Dies ist sehr hilfreich, wenn Sie das aktuelle Commit beibehalten und einige Dateien vom Commit abwählen möchten (besonders hilfreich, files/directorieswenn sie gelöscht wurden).

Sam Liao
quelle