Mercurialはmercurialでpush済みの名前付きブランチをリネームする三つの方法の記事にあるように一度作成したものはすべて記録するという設計なので、確かにGitのように表題のAPIは提供されていません。
しかし、本質的には単純にファイルを書き換えているだけなので、pushしていないローカルの環境では、ブランチ名を変更したりブランチを削除することは簡単にできます。
MQ拡張によりパッチ化することでこれらを実現していきます。
$ hg branch cursed-branch # :p
よくあることです。
人間誰しもtypoします。落ち着きましょう。大丈夫です。Merucurialは寛大なので落ち着いて作業すれば問題ありません。hg branch
のhelpを確認すれば何か手があるはずです。
$ hg help branch
hg branch [-fC] [NAME]
...
オプション:
-f --force 同名既存ブランチが存在する場合でもブランチ作成を実施
-C --clean ブランチ名設定を解消し、 親リビジョンのブランチに戻る
--mq パッチ管理リポジトリへの操作
が、何度読み返してもブランチ名を変更するオプションは見当たりません。どうしたらいいのでしょうか?
.hg/をのぞいてみましょう。
$ ls .hg/
00changelog.i branch dirstate last-message.txt requires strip-backup undo.branch undo.dirstate
bookmarks cache hgrc patches store undo.bookmarks undo.desc
$ file .hg/branch
.hg/branch: ASCII text
$ cat .hg/branch
cursed-branch
テキストファイルである’branch’ファイルが怪しそうです。中を確認すると、’cursed-branch’という間違ったブランチ名が記述されていますね。
間違ったブランチ名を削除して正しいブランチ名に編集してみましょう。これでブランチ名を変更できます。
$ vim .hg/branch
$ cat .hg/branch
blessed-branch
$ hg branch
blessed-branch
また、作成した直後であればhg update default
などして他のブランチ移動すると作成したブランチはなくなるので、再度作成しなおすこともできます。
追記:hg branch [name]
は何度でも可能なので、上記のような手順は踏まなくてよいです。単純に正しい名前で再度branchコマンドを実行するだけでよくなります。
ブランチを作った直後であれば、先程のようにファイルを書き換えるだけでよいですが、作ったブランチにコミットを築いてしまうとファイルを変更するだけではうまくいきません。
なぜならそれぞれのコミットにブランチの情報が含まれてしまっているからです。
では、どうやってブランチ名を変更すればいいのでしょうか?
変更したいブランチのコミットをパッチ化してbranchファイルを書きかえることで変更できます。
次のようなコミットを重ねていたとしましょう。
$ hg glog
@ チェンジセット: 4:9775fad84de8
| ブランチ: topic
| タグ: tip
| 親: 2:e938e86a55c4
| ユーザ: yoppi
| 日付: Sat Mar 26 12:25:10 2011 +0900
| 要約: added foo
|
| o チェンジセット: 3:ae8709c095fd
| | 親: 1:a7338d78342d
| | ユーザ: yoppi
| | 日付: Sat Mar 26 12:24:45 2011 +0900
| | 要約: added hoge
| |
o | チェンジセット: 2:e938e86a55c4
|/ ブランチ: topic
| ユーザ: yoppi
| 日付: Sat Mar 26 12:24:30 2011 +0900
| 要約: added foo.txt
|
o チェンジセット: 1:a7338d78342d
| ユーザ: yoppi
| 日付: Sat Mar 26 12:23:55 2011 +0900
| 要約: added hoge
|
o チェンジセット: 0:1b3a9c75737d
ユーザ: yoppi
日付: Sat Mar 26 12:23:36 2011 +0900
要約: initial commit
リビジョン2でtopicブランチを切って機能を開発しています。
そしてリビジョン4のコミットの時点でこのブランチ名をfeatureにしたほうが良かったと思いブランチ名を変更しようとしましょう。
このtopicブランチのコミットをパッチ化します。
$ hg qimport -r "branch(topic)"
$ hg qseries
2.diff
4.diff
この時点では、最後のコミットであるリビジョン4のパッチが適用されている状態です。
topicブランチの一番元になるコミットに移動しましょう。
$ hg qgoto 2
4.diff の適用解除
適用中の最上位パッチは 2.diff です
$ hg glog
o チェンジセット: 3:ae8709c095fd
| タグ: tip
| 親: 1:a7338d78342d
| ユーザ: yoppi
| 日付: Sat Mar 26 12:24:45 2011 +0900
| 要約: added hoge
|
| @ チェンジセット: 2:e938e86a55c4
|/ ブランチ: topic
| タグ: 2.diff
| タグ: qbase
| タグ: qtip
| ユーザ: yoppi
| 日付: Sat Mar 26 12:24:30 2011 +0900
| 要約: added foo.txt
|
o チェンジセット: 1:a7338d78342d
| タグ: qparent
| ユーザ: yoppi
| 日付: Sat Mar 26 12:23:55 2011 +0900
| 要約: added hoge
|
o チェンジセット: 0:1b3a9c75737d
ユーザ: yoppi
日付: Sat Mar 26 12:23:36 2011 +0900
要約: initial commit
これで、branchを切った直後と同じ状態です。正確にはパッチが一つ適用されて状態ですが。
つまり、.hg/branchを編集すればブランチ名を変更できるわけです。
ただし、変更しただけでは有効になりません。パッチをrefreshすることで初めて変更が反映されます。
$ hg qrefresh
$ hg glog
@ チェンジセット: 3:16e6dd2ef5bb
| ブランチ: feature
| タグ: 2.diff
| タグ: qbase
| タグ: qtip
| タグ: tip
| 親: 1:a7338d78342d
| ユーザ: yoppi
| 日付: Sat Mar 26 12:24:30 2011 +0900
| 要約: added foo.txt
|
| o チェンジセット: 2:ae8709c095fd
|/ ユーザ: yoppi
| 日付: Sat Mar 26 12:24:45 2011 +0900
| 要約: added hoge
|
o チェンジセット: 1:a7338d78342d
| タグ: qparent
| ユーザ: yoppi
| 日付: Sat Mar 26 12:23:55 2011 +0900
| 要約: added hoge
|
o チェンジセット: 0:1b3a9c75737d
ユーザ: yoppi
日付: Sat Mar 26 12:23:36 2011 +0900
要約: initial commit
これでブランチ名をtopicからfeatureへ変更できました。あとは、残りのパッチも適用してパッチの編集を終了しましょう。
$ hg qpush 2.diff
$ hg glog
@ チェンジセット: 4:999a9a5dcf51
| ブランチ: feature
| タグ: 4.diff
| タグ: qtip
| タグ: tip
| ユーザ: yoppi
| 日付: Sat Mar 26 12:25:10 2011 +0900
| 要約: added foo
|
o チェンジセット: 3:16e6dd2ef5bb
| ブランチ: feature
| タグ: 2.diff
| タグ: qbase
| 親: 1:a7338d78342d
| ユーザ: yoppi
| 日付: Sat Mar 26 12:24:30 2011 +0900
| 要約: added foo.txt
|
| o チェンジセット: 2:ae8709c095fd
|/ ユーザ: yoppi
| 日付: Sat Mar 26 12:24:45 2011 +0900
| 要約: added hoge
|
o チェンジセット: 1:a7338d78342d
| タグ: qparent
| ユーザ: yoppi
| 日付: Sat Mar 26 12:23:55 2011 +0900
| 要約: added hoge
|
o チェンジセット: 0:1b3a9c75737d
ユーザ: yoppi
日付: Sat Mar 26 12:23:36 2011 +0900
要約: initial commit
$ hg qfinish -a
$ hg glog
@ チェンジセット: 4:999a9a5dcf51
| ブランチ: feature
| タグ: tip
| ユーザ: yoppi
| 日付: Sat Mar 26 12:25:10 2011 +0900
| 要約: added foo
|
o チェンジセット: 3:16e6dd2ef5bb
| ブランチ: feature
| 親: 1:a7338d78342d
| ユーザ: yoppi
| 日付: Sat Mar 26 12:24:30 2011 +0900
| 要約: added foo.txt
|
| o チェンジセット: 2:ae8709c095fd
|/ ユーザ: yoppi
| 日付: Sat Mar 26 12:24:45 2011 +0900
| 要約: added hoge
|
o チェンジセット: 1:a7338d78342d
| ユーザ: yoppi
| 日付: Sat Mar 26 12:23:55 2011 +0900
| 要約: added hoge
|
o チェンジセット: 0:1b3a9c75737d
ユーザ: yoppi
日付: Sat Mar 26 12:23:36 2011 +0900
要約: initial commit
ブランチのルートのチェンジセットでブランチ名を変更することで、それ以降のチェンジセットも一度に変更されることになります。
ブランチを切ったけどいらなくなってしまうことはしばしばあります。
削除せずに残しておくと、pushする時点で--new-branch
を付けろと警告がでて、泣く泣く-bオプションでpushするブランチを指定するか、もしくは、closeしてpushするという方針しかとれないのでしょうか?
ローカルのブランチは削除できます。
ここでも、MQ拡張を使って削除したいブランチのコミットをパッチ化して実現します。
さきほどの’ブランチでコミットをいくつかしたけどブランチ名かえたくなった’で例としてとりあげているtopicブランチを削除したいとしましょう。qimport
でパッチ化したところまで手順は同じです。
$ hg glog
@ チェンジセット: 4:bd0a69adeed9
| ブランチ: topic
| タグ: tip
| 親: 2:8e372b859477
| ユーザ: yoppi
| 日付: Sat Apr 02 21:55:25 2011 +0900
| 要約: modified foo
|
| o チェンジセット: 3:65d7581c136f
| | 親: 1:a65859ffe351
| | ユーザ: yoppi
| | 日付: Sat Apr 02 21:55:06 2011 +0900
| | 要約: modified hoge
| |
o | チェンジセット: 2:8e372b859477
|/ ブランチ: topic
| ユーザ: yoppi
| 日付: Sat Apr 02 21:54:48 2011 +0900
| 要約: added foo.txt
|
o チェンジセット: 1:a65859ffe351
| ユーザ: yoppi
| 日付: Sat Apr 02 21:54:19 2011 +0900
| 要約: modified hoge
|
o チェンジセット: 0:014088fbb922
ユーザ: yoppi
日付: Sat Apr 02 21:53:53 2011 +0900
要約: initial commit
$ hg qimport -r 2 -r 4
この時点では、作成したパッチが全てパッチキュー上に適用されています。
これらのパッチを全て取り除きましょう。
$ hg qpop -a
4.diff の適用解除
2.diff の適用解除
全てのパッチの適用が解除されました
$ hg glog
o チェンジセット: 2:65d7581c136f
| タグ: tip
| ユーザ: yoppi
| 日付: Sat Apr 02 21:55:06 2011 +0900
| 要約: modified hoge
|
@ チェンジセット: 1:a65859ffe351
| ユーザ: yoppi
| 日付: Sat Apr 02 21:54:19 2011 +0900
| 要約: modified hoge
|
o チェンジセット: 0:014088fbb922
ユーザ: yoppi
日付: Sat Apr 02 21:53:53 2011 +0900
要約: initial commit
歴史からコミットが失くなったと同時にブランチもなくなったことがわかります。
さて、最後にパッチが必要ならtransplantで他のブランチに移植したり、必要ないなら削除しましょう。
$ hg qseries | while read patch
do
hg qdelete $patch
done
これで完全にブランチを削除したことになります。