Mercurial:最後のコミットを修正するには?


211

git commit --amendMercurialで対応するもの、つまり作業コピーがリンクされているコミットを変更する方法を探しています。私は最後のコミットのみに関心があり、任意の以前のコミットには関心がありません。

この修正手順の要件は次のとおりです。

  • 可能であれば、拡張機能は必要ありません。これは、必要があり、デフォルト以外の拡張子を必要としない、公式Mercurialのインストールが付属していません、すなわち拡張を。

  • 修正のコミットが現在のブランチの1つのヘッドである場合、新しいヘッドを作成しないでください。コミットがヘッドでない場合、新しいヘッドが作成されることがあります。

  • 手順は、何らかの理由で修正が失敗した場合に、修正前と同じ作業コピーとリポジトリの状態を復元したいという意味で安全でなければなりません。つまり、修正自体が失敗する可能性がある場合は、作業コピーとリポジトリの状態を復元するためのフェイルセーフ手順が必要です。私は、修正手順の性質にある「障害」(たとえば、競合など)に言及しています。ファイルシステム関連の問題(アクセス制限、書き込み用にファイルをロックできないなど)には言及していません... )

アップデート(1):

  • 手順は自動化可能でなければならないため、ユーザーの介入を必要とせずにGUIクライアントで実行できます。

アップデート(2):

  • 作業ディレクトリ内のファイルは変更しないでください(特定の変更されたファイルにファイルシステムロックが存在する場合があります)。これは特に、可能なアプローチがクリーンな作業ディレクトリを必要としない場合があることを意味します。

回答:


289

Mercurial 2.2のリリースでは、--amendオプションを使用hg commitして、現在の作業ディレクトリで最後のコミットを更新できます。

以下からのコマンドラインリファレンス

--amendフラグを使用すると、hgステータスによって現在報告されている変更に加えて、親の変更を含む新しいコミットを含む新しいコミットで作業ディレクトリの親を修正できます。古いコミットは、.hg / strip-backupのバックアップバンドルに保存されます(復元方法については、hg help bundleおよびhg help unbundleを参照してください)。

特に指定のない限り、メッセージ、ユーザー、日付は修正されたコミットから取得されます。コマンドラインでメッセージが指定されていない場合、エディターは修正されたコミットのメッセージで開きます。

すばらしいのは、このメカニズムが「安全」であることです。これは、比較的新しい「フェーズ」機能に依存して、ローカルリポジトリの外部ですでに利用可能になっている履歴を変更する更新を防ぐためです。


2
いい答えだ!試験的な進化の拡張機能により、ヘッド以外のコミットを安全に修正できます。古いコミットは廃止とマークされ、非表示になります。非公開サーバーを使用すると、変更セットをプッシュした後で安全にこれを行うこともできます。
Martin Geisler、2014

5
最後のコミットでメッセージを更新するには:hg commit --amend -m "this is my new message"
Jay Sheth

52

Mercurialでコミットを編集するには、3つのオプションがあります。

  1. hg strip --keep --rev -1最後の(1)回のコミットを取り消すと、もう一度実行できます(詳細については、この回答を参照してください)。

  2. Mercurialに同梱されているMQ拡張機能の使用

  3. Mercurialに同梱されていない場合でも、Histedit拡張機能は言及する価値があります

Mercurial wikiのEditing Historyページでも見ることができます。

つまり、履歴の編集は非常に難しく、推奨されません。すでに変更をプッシュしている場合、他のすべてのクローンを完全に制御できる場合を除いて、実行できることはほとんどありません。

私はgit commit --amendコマンドに慣れていませんが、AFAIK、Histeditが最も近いアプローチのようですが、残念ながらMercurialには同梱されていません。MQの使い方は本当に複雑ですが、MQを使用すればほとんど何でもできます。


1
なぜロールバックに失敗したのかはわかりませんが、(ほとんど)希望どおりの動作をしているようです。唯一の問題は、元のコミットでファイルが削除され、修正されたコミットで復活した場合です。ロールバック前にバージョンが解除され、ロールバック後、削除がスケジュールされます(ただし、ファイルは引き続き存在します)作業ディレクトリ)
mstrap '18年

@Marc私はあなたの問題を理解しているとは思いませんが、forgetコマンドを見てください、それがあなたが探しているものだと思います。
krtek、

ここでは「忘れる」は役に立たないと思います。問題の詳細は次のとおりです。(1)リビジョン2にいます(2)「ファイル」を削除し、その他の変更を加えます(3)変更をコミットし、リビジョン3になります(4)次に、考えを変えて決定します「ファイル」はコミットから削除すべきではないので、リビジョン3を修正したいと思います。したがって、バージョン管理されていない「ファイル」を再度追加します(5)ロールバックを実行します。これにより、dirstateがリセットされ、「ファイル」が削除されました。(6)「hg commit」を再度実行すると、「file」は削除されたままになりますが、削除する必要はありません。そのための自動修正はどのようになりますか?
mstrap

1
自動化された部分についてはわかりませんが、hg revert myfile削除を元に戻すことができます。たぶん動作したhg add後、ファイルを追加し直すかもしれませんrollback
krtek

3
公開された変更の履歴の編集は避けるべきであることに同意しますが、私のローカル履歴の編集はDVCSのハイライトの1つです。qimportを備えたMQは、純粋な履歴編集、AFAICTです。
mstrap

38

対応するGUI hg commit --amend

これはTortoiseHGのGUIからも機能します(私はv2.5を使用しています):

「コミット」ビューに切り替えるか、ワークベンチビューで「作業ディレクトリ」エントリを選択します。[コミット]ボタンには、[現在のリビジョンを修正]というオプションがあります(ボタンのドロップダウン矢印をクリックしてそれを見つけます)。

ここに画像の説明を入力してください

          ||
          ||
          \/

ここに画像の説明を入力してください

警告の先制者

この追加オプションは、Mercurialのバージョンが2.2.0以上で、現在のリビジョンが公開されておらず、パッチではなく、子がない場合にのみ有効になります。[...]

ボタンをクリックすると、「commit --amend」を呼び出してリビジョンを「修正」します。

これについての詳細は、THG開発チャネルで


とても助かります、ありがとう。THGは、コミット(修正)メッセージを前のコミットからのメッセージにデフォルト設定するのに十分スマートです-まさに私が欲しかったものです。
UuDdLrLrSs 2016年

7

私はkrtekが書いたものにチューニングしています。より具体的には、ソリューション1:

仮定:

  • 1つ(!)のチェンジセットをコミットしましたが、まだプッシュしていません
  • このチェンジセットを変更したい(ファイルやコミットメッセージの追加、削除、変更など)

解決:

  • hg rollback最後のコミットを元に戻すために使用します
  • 新しい変更を適用して再度コミットします

ロールバックは実際に最後の操作を取り消します。その動作方法は非常に単純です。HGでの通常の操作はファイルにのみ追加されます。これにはコミットが含まれます。Mercurialは最後のトランザクションのファイル長を追跡しているため、ファイルを元の長さに戻すことにより、1つのステップを完全に元に戻すことができます。


1
ソリューションをチューニングしていただきありがとうございます(1)。ロールバックで小さな問題が残っています。krtekのソリューションで私のコメントを参照してください。
mstrap

8
ロールバックを強調することの1つは、人を引き付けるので、ロールバックされるのは最後のコミットではなく、リポジトリの最後のトランザクションであることです。そのため、何かがリポジトリへの書き込みを引き起こした場合、ロールバックは役に立ちません。これは、微妙ですが重要なことです。MQとhisteditは、ロールバックウィンドウが閉じられても、特定の時点までしか役に立ちません。
ポールS

7

まだ変更を反映していないと想定すると、次のことができます。

  • .hgrcに追加:

    [extensions]
    mq =
    
  • リポジトリで:

    hg qimport -r0:tip
    hg qpop -a
    

    もちろん、リビジョン0から始めたり、すべてのパッチをポップしたりする必要はありません。最後の1つだけポップ(hg qpop)で十分です(以下を参照)。

  • .hg/patches/seriesファイルの最後のエントリ、または不要なパッチを削除します。再注文も可能です。

  • hg qpush -a; hg qfinish -a
  • .diff.hg / patches内のファイル(未適用のパッチ)を削除します(あなたの場合は1つでなければなりません)。

あなたがいる場合したくないために、すべて取り戻すあなたのパッチを、あなたが使用してそれを編集することができますhg qimport -r0:tip(または類似)、その後、編集スタッフと利用hg qrefreshあなたのスタックの最上位のパッチに変更をマージします。をお読みくださいhg help qrefresh

を編集.hg/patches/seriesすることで、いくつかのパッチを削除したり、一部を並べ替えたりすることもできます。最新のリビジョンが99の場合、そのまま使用できますhg qimport -r98:tip; hg qpop; [edit series file]; hg qpush -a; hg qfinish -a

もちろん、この手順は推奨されておらず、リスクも伴います。これを行う前に、すべてのバックアップを作成してください

余談ですが、私はそれをプライベートのみのリポジトリで何十億回も実行しました。


私はmq-extensionの使用も検討しましたが、非常に多くの操作が必要なため、一部の操作が失敗する可能性があります(たとえば、バイナリファイルが含まれている場合)。さらに、この手順はGUIクライアント内で使用する必要があるため、.hg / patch / seriesを編集する必要はありません(上記の要件を更新しました)
mstrap

うーん、これはあなたには役に立たないでしょう、プライベートリポジトリでは本当にお尻を蹴ります hg qfold、btw を使用してローカルの変更をプッシュする前にパッチを1つに結合するのは非常にクールです
hochl

MQを使用するための+1、しかし私はあなたが行き過ぎたと思います。彼は最後のコミットを修正することについてのみ尋ねています。また、そのインポートは、マージにヒットするとすぐにキールオーバーします。'qimport -rヒント; <ものを編集>; qrefresh -e; qfin -a 'はジョブを実行します(-eはコミットメッセージを編集します)
Paul S

確かに、マージは問題hg import -r<prev>:tipです。通常、パッチを1つポップして使用します。欠点は、サブバージョンのように、以前のバージョンへのショートカットがないことです。
hochl

2

Mercurialの最近のバージョンにevolveは、hg amendコマンドを提供する拡張機能が含まれています。これにより、バージョン管理の修正前の履歴を失うことなく、コミットを修正できます。

hg amend [オプション] ... [ファイル] ...

エイリアス:更新

チェンジセットをアップデートと組み合わせ、新しいものと交換する

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).

拡張機能の詳細については、https://www.mercurial-scm.org/doc/evolution/user-guide.html#example-3-amend-a-changeset-with-evolveを参照してくださいevolve


同じコミットメッセージを再利用することは素晴らしい機能です!
mpen

1

元の質問のすべての問題を解決できるわけではありませんが、これは水銀が以前のコミットをどのように修正できるかについての事実上の投稿のようですので、2セント相当の情報を追加します。

あなたが私のようなものであり、ファイルを追加せずに以前のコミットメッセージ(タイプミスの修正など)のみを変更したい場合、これは機能します

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

包含または除外パターンhg commitがない場合、デフォルトでは作業ディレクトリ内のすべてのファイルが含まれます。パターン-X 'glob:**'を適用すると、すべての可能なファイルが除外され、コミットメッセージの変更のみが可能になります。

機能的にはgit commit --amend、インデックス/ステージにファイルがない場合と同じです。


0

別の解決策は、uncommitコマンドを使用して現在のコミットから特定のファイルを除外することです。

hg uncommit [file/directory]

これは、現在のコミットを維持し、一部のファイルをコミットから選択解除する場合に非常に役立ちます(特にfiles/directories削除された場合に役立ちます)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.