Mercurial ~ 間違ったら

前置き

間違っても元に戻せることがSCMツールを使う最大の理由でしょう。なので、戻す方法を知っておくことは重要です。しかし実際に使用する頻度が少ないせいか、addやcommitに比べると定着しにくいのも事実ですね。バックアップソフトを買って自動バックアップしてるけどリストアの経験は無い、というのと似てるような…。

ここでは、戻す方法を重点的に説明します。

本文

準備

まずは、ひと通り(個人で)で使ったサンプルプロジェクトのタグVERSION1.0をクローン化して、そこから作業を開始しましょう。

~/sandbox/proj1 $ cd ..
~/sandbox $ hg clone -r VERSION1.0 proj1 proj1.mistake
全チェンジセットを取得中
チェンジセットを追加中
マニフェストを追加中
ファイルの変更を追加中
10 のチェンジセット(10 の変更を 4 ファイルに適用)を追加
ブランチ default へ更新中
ファイル状態: 更新数 2、マージ数 0、削除数 0、衝突未解決数 0
~/sandbox $ ls
proj1  proj1.mistake
~/sandbox $ cd proj1.mistake/
~/sandbox/proj1.mistake $ ls -a
.  ..  .hg  foo  sub
~/sandbox/proj1.mistake $ hg log -l 2
チェンジセット:   9:50f3095c9a73
タグ:             tip
ユーザ:           maru
日付:             Tue Apr 19 18:46:29 2011 +0900
要約:             remove barrr

チェンジセット:   8:b63d3a430609
ユーザ:           maru
日付:             Tue Apr 19 18:44:31 2011 +0900
要約:             edit barrr(d)

作業ディレクトリを特定のリビジョンで置き換える(親を変える)

適当にファイル削除や編集を行ったあとで、元に戻してみます。

~/sandbox/proj1.mistake $ rm foo
~/sandbox/proj1.mistake $ cd sub
~/sandbox/proj1.mistake/sub $ echo mistake >>buz
~/sandbox/proj1.mistake/sub $ hg sta
M sub/buz
! foo
~/sandbox/proj1.mistake/sub $ hg update -C     # 作業ディレクトリを強制的にティップで置き換え。
ファイル状態: 更新数 2、マージ数 0、削除数 0、衝突未解決数 0
~/sandbox/proj1.mistake/sub $ hg sta
~/sandbox/proj1.mistake/sub $ cat buz
a
~/sandbox/proj1.mistake/sub $ cd ..
~/sandbox/proj1.mistake $ ls
foo  sub

このように、-Cオプション付きのupdateを行うと、作業ディレクトリを強制的に特定のリビジョンで置き換えることができます。

親を変えずに、ファイル単位で元に戻す

作業ディレクトリ全体ではなく、ファイル単位で元に戻してみます。

~/sandbox/proj1.mistake $ hg update -r 6          # R6を親とする。
ファイル状態: 更新数 1、マージ数 0、削除数 0、衝突未解決数 0
~/sandbox/proj1.mistake $ hg parents
チェンジセット:   6:ea4917b81d35
ユーザ:           maru
日付:             Tue Apr 19 18:43:49 2011 +0900
要約:             edit bar(c)

~/sandbox/proj1.mistake $ rm foo
~/sandbox/proj1.mistake $ echo mistake >>bar
~/sandbox/proj1.mistake $ hg sta
M bar
! foo
~/sandbox/proj1.mistake $ cat bar
a
b
c
mistake
~/sandbox/proj1.mistake $ hg revert bar           # barを親リビジョン版に戻す。
~/sandbox/proj1.mistake $ cat bar
a
b
c
~/sandbox/proj1.mistake $ hg parents
チェンジセット:   6:ea4917b81d35
ユーザ:           maru
日付:             Tue Apr 19 18:43:49 2011 +0900
要約:             edit bar(c)

~/sandbox/proj1.mistake $ hg revert -r 5 bar      # barを親とは違うリビジョンに戻す。
~/sandbox/proj1.mistake $ cat bar
a
b
~/sandbox/proj1.mistake $ hg parents              # それでも親は変わらない。
チェンジセット:   6:ea4917b81d35
ユーザ:           maru
日付:             Tue Apr 19 18:43:49 2011 +0900
要約:             edit bar(c)

~/sandbox/proj1.mistake $ hg sta                  # barの状態がMになっている(親リビジョン版と差異があるので)。
M bar
! foo
? bar.orig
~/sandbox/proj1.mistake $ hg revert -a            # 全ファイルをrevertする。
bar の復旧中
foo の復旧中
~/sandbox/proj1.mistake $ ls -a                   # revert前のファイルがbar.origとして残る。
.  ..  .hg  bar  bar.orig  foo  sub

updateと異なり、revertならファイル単位で任意のリビジョンへ戻すことができます。revertしても作業ディレクトリの親リビジョンは変わらない、という点に注意して下さい(これもupdateと異なる点です)。

Mercurialは、(revertに限らず)作業ディレクトリ上の未コミットファイルを上書きするとき、自動的にバックアップファイル(*.orig)を残すようになっています。*.origファイルはバージョン管理対象から外したいですよね。こういう場合は、.hgignoreという管理ファイルを作っておくことにより、hgに無視させることができます。.hgignoreファイルは、プロジェクトのトップディレクトリに作ります。

~/sandbox/proj1.mistake $ hg sta
? bar.orig
~/sandbox/proj1.mistake $ hg update -C     # 一旦、ティップへ戻す。
ファイル状態: 更新数 0、マージ数 0、削除数 1、衝突未解決数 0
~/sandbox/proj1.mistake $ hg sta
? bar.orig
~/sandbox/proj1.mistake $ echo syntax: glob >.hgignore
~/sandbox/proj1.mistake $ echo '*.orig' >>.hgignore
~/sandbox/proj1.mistake $ cat .hgignore
syntax: glob
*.orig
~/sandbox/proj1.mistake $ hg sta           # bar.origが無視されるようになった。
? .hgignore
~/sandbox/proj1.mistake $ hg add           # .hgignore自体はバージョン管理対象とする。
.hgignore を追加登録中
~/sandbox/proj1.mistake $ hg com -m "add .hgignore"
~/sandbox/proj1.mistake $ hg log -l 2
チェンジセット:   10:6c7e534eeb52
タグ:             tip
ユーザ:           maru
日付:             Tue Apr 19 19:53:46 2011 +0900
要約:             add .hgignore

チェンジセット:   9:50f3095c9a73
ユーザ:           maru
日付:             Tue Apr 19 18:46:29 2011 +0900
要約:             remove barrr

コミットを取り消す

コミットを「なかったことにする」ことができます。ただし、1世代のみです。

~/sandbox/proj1.mistake $ hg remove foo
~/sandbox/proj1.mistake $ hg sta
R foo
~/sandbox/proj1.mistake $ hg com -m "remove foo"
~/sandbox/proj1.mistake $ hg log -l 2
チェンジセット:   11:ab8a5f57937f
タグ:             tip
ユーザ:           maru
日付:             Tue Apr 19 19:56:22 2011 +0900
要約:             remove foo

チェンジセット:   10:6c7e534eeb52
ユーザ:           maru
日付:             Tue Apr 19 19:53:46 2011 +0900
要約:             add .hgignore

~/sandbox/proj1.mistake $ hg rollback            # 直前のコミットを取り消す。
最新のトランザクションをロールバックしています
~/sandbox/proj1.mistake $ hg log -l 2            # R11が消えた。
チェンジセット:   10:6c7e534eeb52
タグ:             tip
ユーザ:           maru
日付:             Tue Apr 19 19:53:46 2011 +0900
要約:             add .hgignore

チェンジセット:   9:50f3095c9a73
ユーザ:           maru
日付:             Tue Apr 19 18:46:29 2011 +0900
要約:             remove barrr

~/sandbox/proj1.mistake $ cat foo                # コミット前の状態に戻るだけ。
cat: foo: そのようなファイルやディレクトリはありません
~/sandbox/proj1.mistake $ hg sta
R foo
~/sandbox/proj1.mistake $ hg rollback            # 2世代以上戻ることはできない。
利用可能なロールバック情報がありません

rollbackは、直前のコミットを取り消して、作業ディレクトリをコミット前の状態に戻します。あくまでも「コミット前の状態」に戻すだけで、前のリビジョンに戻すわけではありません。上記の例で言えば、rollbackしても、fooをremoveした操作はundoされません。fooをrevertすれば、fooが戻ります。

Last modified:2011/04/19 18:17:05
Keyword(s):
References:[Mercurial(分散SCM)]
This page is frozen.