mercurial

  • git のような分散バージョン管理ツール
  • git でできることは大抵できる
  • 過去改変が git より面倒 (コミットメッセージの変更も含む)
  • テキストデータだけでなく、バイナリファイル管理にも向いている (容量的に)
  • add の挙動が異なり、一度 add すると、ずっと管理していてくれる (コミットの度に add しなくて済む)
  • 個人的には git より、扱いが管理が簡単な気がする
  • リビジョンをハッシュの他に、コミット番号でも管理するため、リビジョン指定がシンプル
$ sudo apt install mercurial
$ sudo -H pip3 install mercurial
  • 最新版がインストールされる。
  • libbz2-devlibffi-dev が必要。
  1. 設定
    • ホームディレクトリに .hgrc を作成して編集する
      [ui]
      username = ユーザ名 <メールアドレス>
  • ホームディレクトリに .hgrc として作成、編集する
  • 基本としては「[]」で囲まれた項目と、「設定名 = 設定値」で構成される
項目 設定名 設定値
uiusernameユーザ名 <メールアドレス>
mergeマージする際に差分を表示する外部ツール (diff3 あたりを書いておけば良さそう)
ignoreすべてのリポジトリに共通な無視リストのファイルパス
aliasエイリアス名mercurialのコマンド (例: ci = commit)
extentionsエクステンション名なし(詳しくは エクステンションに記述)

基本的には git と同じ

  1. リポジトリを作成 (hg init)
  2. 管理ファイルを追加 (hg add)
  3. コミット (hg commit)

以降は、2を必要に応じて行いつつ、3を繰り返す

$ hg init
$ hg add [ファイル]
  • ファイルやディレクトリを指定しない場合、すべてのファイルが add される (ディレクトリもあれば再帰的に追加される)
  • 管理ファイルの取り消し
    $ hg revert [取り消したいファイル]
$ hg status
  • statusst でも可
  • ファイルの状態
    • ?: 管理下にないファイル (add されていないファイル)
    • A: 次回コミット時に追加されるファイル (add 済みのファイル)
    • M: 既に管理下にあり、変更されたファイル
    • R: 削除されたファイル (hg rm で削除したファイル)
    • !: 存在しないファイル (hg rm をしないで削除されたファイル; mercurial 上では削除されていないファイル)

管理しないファイルを無視する場合

  • エディタが出力するバックアップファイルやロックファイルなど、管理する予定もないファイルが状態に表示されると、非常に見づらくなる
  • その場合は無視リスト (リポジトリのトップに .hgignore) を作成して対応する
    • 1行目はリストをワイルドカードか、正規表現か、どちらの表記で書くかを指定する
      • glob: ワイルドカード
      • re あるいは regexp: Perl や Python の正規表現
    • 2行目以降にワイルドカードか正規表現で示されたファイルのリストを書いていく

  • syntax: regexp
    \/?\.\~lock\..+
    \/?\~\$.+
    \.zip$
    • ~lock. で始まるファイルを無視
    • ~$ で始まるファイルを無視
    • .zip ファイルを無視
  • 実ファイルを削除せずに管理から外す (次回コミット時から管理しない)
    $ hg forget <ファイル>
  • 実ファイルを削除して管理から外す (次回コミット時から管理しない)
    $ hg rm <ファイル>
    • rmremove でも可
$ hg cp <コピー元> <コピー先>
  • ただし、コピー元の履歴まで引き継がれるわけではないので注意
  • cpcopy でも可
$ hg mv <ファイル> <変更後の名前>
  • 実体は copy+remove なので、元ファイルの履歴は消える
  • mvrename でも可
  • コミットメッセージを後から編集するコミット
    $ hg commit
    • 実行すると端末上でエディタが開かれるので、そこにコミットメッセージを入力する
  • コミットメッセージとともにコミット
    $ hg commit -m <コミットメッセージ>
  • コミットメッセージを書いたファイルを指定してコミット
    $ hg commit -l <コミットメッセージファイル
  • 特定のファイルのみコミット
    $ hg commit <コミットしたいファイル>
$ hg rollback
  • 直前のcommit, pull, import, unbundle を 1 回だけ取り消す
  • 作業領域は変更しない
  • mercurial では、一度 add したものは removeforget するまで常にトラッキングされる。
  • 特定のファイルのみのコミットの場合、コミットの章で触れたように、hg commit FILE としてファイルを指定する。
  • 指定を忘れて誤って全体をコミットしてしまった場合に戻す方法は rollback 以外では以下の通りである (事前に MQ エクステンションを有効にしておく必要あり)。
    $ hg qimport -r REV_ID
    $ hg qrefresh FILE
    $ hg qfinish -a
    • REV_ID: 修正したいリビジョン番号
    • FILE: 本来コミットするはずだったファイル群
    • これで特定のファイルのみのコミットの修正される。
    • qimport -r の後に、hg qseries -shg qdiff などで誤ったリビジョンの確認をすると確実。
  • リビジョン(履歴)を表示する
    $ hg log [オプション]
  • オプション
    • -r: リビジョンを指定
    • -l: リビジョンの表示数 (指定がない場合は、すべて表示する)
    • -v: コミットメッセージ全文を表示する
  • 表示例:
    changeset:   1:96a83a913743    <- 2回目のコミットの「リビジョン番号:ハッシュ」
    tag:         tip               <- タグ
    user:        hoge <hoge@example.com>    <- コミットしたユーザ
    date:        Wed May 18 10:16:22 2016 +0900    <- コミット日時
    summary:     2nd commit    <- コミットメッセージのタイトル(1行目の内容)
    
    changeset:   0:0ed873115825    <- 1回目のコミットの「リビジョン番号:ハッシュ」
    user:        hoge <hoge@example.com>    <- コミットしたユーザ
    date:        Wed May 18 10:15:11 2016 +0900    <- コミット日時
    summary:     1st commit    <- コミットメッセージのタイトル(1行目の内容)
  • 特定のリビジョンのコミット状態に戻す
    $ hg update [オプション] <リビジョン>
    • -C をつけると作業領域の変更を破棄する
    • updatecheckout でも可
  • 特定のファイルのみ特定のリビジョンのコミット状態に戻す
    $ hg revert [オプション] <ファイル>
    • -r <リビジョン>: 特定のリビジョンのコミット状態に戻す (このオプションを付けない場合、直前のリビジョンに戻す)
  • 特定のリビジョンにおけるファイルを別名で保存する
    $ hg cat -r <リビジョン> -o <別名> <ファイル>
$ hg strip <リビジョン>
  • 実行後、バックアップが取られる
  • 誤って削除したリビジョンを戻す
    $ hg unbundle .hg/strip-backup/<ハッシュ>.hg
    • ハッシュは、strip した直後にバックアップしたメッセージに表示されている
    • メッセージを忘れた場合は、.hg/strip-backup 内にファイルがあるので、そこから探すしかない…。
  • ブランチの新規作成
    $ hg branch <ブランチ名>
    • ブランチ作成すると、自動的に作成したブランチに移動する
    • 作成したブランチからコミット前に別のブランチに移動すると、ブランチが削除される
  • 現在のブランチ表示
    $ hg branch
  • ブランチ一覧表示
    $ hg branches
  • ブランチ間の移動
    $ hg checkout <ブランチ名>
  • ブランチのマージ
    $ hg merge <マージしたいブランチ>
    • マージする際は取り込み後に残るブランチにいる必要がある
  • ブランチの削除
    $ hg strip <削除したいブランチ>
  • rebase 拡張が必要なので、.hgrc の [extensions] 以下に追記
    rebase =
    $ hg update <リビジョンの移動先ブランチ>
    $ hg rebase --source revision_s --dest revision_d --keep
    • revision_s: 移動させたいリビジョンの開始番号 (指定した番号以降のリビジョンも一緒に移動する)
    • revision_d: 移動先のリビジョン番号 (指定されたリビジョンの後に、移動指定したリビジョンが取り付けられる)
    • –keep: デフォルトでは、リビジョン移動後に移動元のブランチが消されるため、このオプションを付けて消さないようにする
  • 特定のリビジョンの状態を USB メモリや Web 上で配布する場合に、.hg や .hgignore ファイルはつけたくない
  • その場合、以下のコマンドを使う
    $ hg archive [オプション] -r <リビジョン> <出力名>
    • -X 除外ファイル: 除外ファイルを指定する
      • 例: -X .hg* (.hg や .hgignore を除外する)
    • 出力名は名前だけだと、出力名のフォルダを新たに作成してその下にコピーするが、.zip や .tgz などの拡張子をつけると圧縮形式で出力してくれる
  • エクステンションの histedit を使うので、使える状態にする
  • ここではリビジョンの 1 と 2 を変更する例を紹介します
  • 初期リポジトリ (例)
    @  changeset:   3:c56f122d5366
    |  tag:         tip
    |  user:        mumeiyamibito
    |  date:        Fri Oct 28 09:52:22 2016 +0900
    |  summary:     4th commit
    |
    o  changeset:   2:315becd9db3f
    |  user:        mumeiyamibito
    |  date:        Fri Oct 28 09:52:12 2016 +0900
    |  summary:     3rd commit
    |
    o  changeset:   1:88774b2a3443
    |  user:        mumeiyamibito
    |  date:        Fri Oct 28 09:52:06 2016 +0900
    |  summary:     2nd commit
    |
    o  changeset:   0:93daa7d382ae
       user:        mumeiyamibito
       date:        Fri Oct 28 09:52:00 2016 +0900
       summary:     1st commit
  1. histedit の実行
    $ hg histedit <リビジョン>
    $ hg histedit 1
    • エディタが立ち上がり、pick <リビジョンのハッシュ> <リビジョン番号> <コミットメッセージ> のリストが表示される
      pick 88774b2a3443 1 2nd commit                                                                                                                                                                                                                
      pick 315becd9db3f 2 3rd commit
      pick c56f122d5366 3 4th commit
       
      # Edit history between 88774b2a3443 and c56f122d5366
      #
      # Commits are listed from least to most recent
      #
      # Commands:
      #
      #  e, edit = use commit, but stop for amending
      #  m, mess = edit commit message without changing commit content
      #  p, pick = use commit
      #  d, drop = remove commit from history
      #  f, fold = use commit, but combine it with the one above
      #  r, roll = like fold, but discard this commit's description
      #
  2. 編集したいリビジョンの pickedit あるいは e に変更する
    edit 88774b2a3443 1 2nd commit                                                                                                                                                                                                                
    edit 315becd9db3f 2 3rd commit
    pick c56f122d5366 3 4th commit
           
    # Edit history between 88774b2a3443 and c56f122d5366
    #   
    # Commits are listed from least to most recent
    #   
    # Commands:
    #   
    #  e, edit = use commit, but stop for amending
    #  m, mess = edit commit message without changing commit content
    #  p, pick = use commit
    #  d, drop = remove commit from history
    #  f, fold = use commit, but combine it with the one above
    #  r, roll = like fold, but discard this commit's description
    #   
  3. リビジョン 1 のコミットメッセージを変更する
    $ hg histedit --continue
    • いつものコミット時のエディタが起動するので、リビジョン 1 に付ける新しいコミットメッセージを記入する
  4. リビジョン 2 のコミットメッセージを変更する
    $ hg histedit --continue
    • いつものコミット時のエディタが起動するので、リビジョン 2 に付ける新しいコミットメッセージを記入する
  • 複数の別々のリポジトリで管理していたファイルを、それぞれの履歴を残しつつ、マージする方法
    $ hg pull -f /path/to/repository
    $ hg merge
    $ hg commit
    • /path/to/repository: 統合したい別のリポジトリのパス
    • pull を使っているが、ローカルのリポジトリでも問題ない
    • 実行すると、別リポジトリがブランチとして履歴に加わり、統合される (デフォルトのタイムラインに追加されるわけではない)
  • 参考サイト
  • 上記の複数リポジトリの統一とは逆に、特定ファイルのみの別リポジトリにして管理する方法
    $ hg convert /path/to/original_repository /path/to/new_repository --filemap map.txt
    • /path/to/original_repository: コピー元のリポジトリのパス
    • /path/to/new_repository: 新たに作成する特定ファイルのみの別リポジトリのパス
    • map.txt: フィルタ条件を書き込んだファイル
      map.txt
      include INCLUDE_FILE_PATH
      exclude EXCLUDE_FILE_PATH
      rename ORIGINAL_PATH RENAMED_PATH
      • INCLUDE_FILE_PATH: リポジトリコピーの際に、コピーするファイルのパス (リポジトリのトップパスがベース)
      • EXCLUDE_FILE_PATH: リポジトリコピーの際に、外したいファイルのパス (リポジトリのトップパスがベース)
      • ORIGINAL_PATH: リポジトリコピーの際に、名前を変更したいファイルのパス (リポジトリのトップパスがベース)
      • RENAMED_PATH: リポジトリコピーの際に、名前変更後のパス (リポジトリのトップパスがベース)
      • includeexclude も指定していない場合、すべてのファイルがコピーされる。
      • rename は事前に include しておく必要あり (rename だけではコピーされない)
      • これらの指定は 1 ファイルにつき、1 行使う (includeexclude の後に、ファイルのパスを続けて指定するとエラーが出る。)
      • 例: リポジトリ内の class/class1.pyclass/class2.py のみのリポジトリを作成する (class1.py はリポジトリのトップに class_main.py として配置する)
        include class/class1.py
        include class/class2.py
        rename class/class1.py class_main.py 
  • 事前にエクステンションを有効化する必要があるため、.hgrc[extensions] 以下に追記する。
    [extensions]
    convert=
  • 参考サイト:
  • 何らかの処理によって、mercurial の管理ディレクトリ内のデータが破損した場合、mercurial の操作をしようとすると abort: data/FILE.i@XXXXXXXXXXXX: no match found! というエラーが現れることがある (FILE はその名前のファイルのトラッキングデータ)。
  • 修復するには以下のコマンドを実行すると復旧できる可能性がある
    $ hg convert --config convert.hg.ignoreerrors=True SOURCE_REPO DEST_REPO
    • SOURCE_REPO: 修復したいリポジトリ (mercurial で管理しているディレクトリ)
    • DEST_REPO: 修復後のリポジトリの出力先
  • mercurial のサーバ構築のサイトの多くは Apache を使った方法を紹介しているが、ただバージョン管理のストレージとして使いたい場合には大掛かり過ぎる気がする (Apache を設定すれば、ウェブ上で公開することが可能である)。ここでは、バージョン管理のストレージとして使う場合を想定して紹介する。
  • サーバ構築
    • SSH サーバ + mercurial がインストールされている環境を構築すれば良い (構築方法は他のサイトを参照)。
  • クライアント側の設定 (オプション)
    • SSH を公開鍵設定やポート変更をしている場合、~/.hgrc[ui] に SSH の設定を追記することで利用できる。
      [ui]
      ssh = ssh -i PRIVATE_KEY -p PORT
      • PRIVATE_KEY: 秘密鍵のパス
      • PORT: ポート番号
  • 使い方 (クライアント側)
    • リモートサーバにリポジトリを作成
      $ hg clone . ssh://USER_NAME@SERVER_NAME/path/to/new_repository
      • USER_NAME: SSH のユーザ名
      • SERVER_NAME: SSH のサーバ名 (IP アドレス)
      • path/to/new_repository: サーバ内のパス (USER_NAME が指定されているのであれば、/home/USER_NAME が起点になる)
    • プッシュ
      $ hg push ssh://USER_NAME@SERVER_NAME/path/to/repository
      • USER_NAME: SSH のユーザ名
      • SERVER_NAME: SSH のサーバ名 (IP アドレス)
      • path/to/repository: サーバ内のパス (USER_NAME が指定されているのであれば、/home/USER_NAME が起点になる)
    • クローン
      $ hg clone ssh://USER_NAME@SERVER_NAME/path/to/repository
      • USER_NAME: SSH のユーザ名
      • SERVER_NAME: SSH のサーバ名 (IP アドレス)
      • path/to/repository: サーバ内のパス (USER_NAME が指定されているのであれば、/home/USER_NAME が起点になる)
    • プル
      $ hg pull ssh://USER_NAME@SERVER_NAME/path/to/repository
      • USER_NAME: SSH のユーザ名
      • SERVER_NAME: SSH のサーバ名 (IP アドレス)
      • path/to/repository: サーバ内のパス (USER_NAME が指定されているのであれば、/home/USER_NAME が起点になる)
  • mercurial を快適に使うための拡張パック
  • 大抵はインストールされているものの、有効になっていない
  • 有効にするには .hgrc の [extentions] 以下にエクステンション名を入れる
    [extentions]
    エクステンション名 = 
    エクステンション名 = エクステンションのパス
    • 外部エクステンションの場合、エクステンションのパスが必要
  • 無銘闇人が導入しているエクステンション
    • graphlog: リビジョン一覧表示の際に、左端にリビジョンのツリー構造(ブランチの分かれ具合など)をアスキーアートで表示
      • 使う場合は、hg log と同様の感覚で、hg glog
      • エイリアスで log を glog に置き換えてもいいかもしれない
    • mq: 変更内容をパッチ化する (過去改変などで使う)
    • convert: git など他の分散バージョン管理システムのリポジトリを mercurial 用に変換する
      $ hg convert <GITリポジトリ> <新リポジトリ>
    • color: diff や status に色を付けて表示
      • [color]mode = auto
    • shelve: 作業領域を一時的に退避する (git の stash)
    • eol: 改行コードの管理
    • progress: コミット時に進捗状況を表示
      • [progress]deley = 1.5
    • histedit
      • 過去のコミットメッセージを変更するなど過去改変をする拡張機能
      • 多くのサイトで、hg clone で導入して、.hgrc に histedit = /path/to/histedit/hg_histedit.pyと記述する方法が書かれているが、Ver. 2.3 以降はデフォルトでインストールされている (ちなみに Ubuntu 16.04 相当では、Ver. 3.7.3 なので mercurial インストールするだけでこのエクステンションはインストールされている)
        • Ver. 2.3 以降は histedit = を .hgrc の [extensions] 以下に記述するだけで良い
    • zipdoc: docx などの XML 形式の Word を管理する場合、バージョン管理用のフォルダの肥大化を抑制
      • Word の docx は XML を zip で固めたものであり、mercurial ではバイナリとして認識されるため、差分ではなく、zip を保存することでバージョン管理している。このエクステンションは docx などをコミット・チェックアウトする際に展開・圧縮して差分で管理するようにする。
      • 標準ではインストールされていないので、 ここ から入手する
      • .hgrc
  1. 変換プログラムをダウンロードする。
    $ git clone http://repo.or.cz/r/fast-export.git fast-export
  2. 転送先の git リポジトリ (空) NEW_GIT_REPO を作成する。
    $ mkdir NEW_GIT_REPO
    $ cd NEW_GIT_REPO
    $ git init 
  3. 変換する。
    $ ../fast-export/hg-fast-export.sh -r HG_REPO_PATH
    • HG_REPO_PATH: 変換したい mercurial のリポジトリパス
  • hg statushg log などの結果はデフォルトでは、less コマンド (pager) のように表示される。
  • これらの結果をプロンプトに反映させたい場合や、端末上にその結果を残したい (pager は q キーを押すと、結果が消える) 場合は、設定ファイル $HOME/.hgrc に以下を追記すると良い。
    [pager]
    ignore = SUBCOMMAND [, SUBCOMMND, ...]
    • SUBCOMMAND: pager を無効化したいサブコマンド (logstatus など hg の後に付けるキーワード)
    • 複数ある場合は、カンマで区切る
  • 一時的に無効化したい場合は、–pager false を各コマンドの後ろにでも付けておけば良い。
    • 例:
      $ hg log --pager false
  • ツール/mercurial.txt
  • 最終更新: 2020/10/12 10:17
  • by mumeiyamibito