[インデックス 16641] ファイルの概要
このコミットは、Goプロジェクトのコードレビューシステムで使用されるcodereview.py
スクリプトに対する変更です。具体的には、Mercurial (Hg) リポジトリの同期処理(hg sync
)における挙動を改善し、ユーザーが常に最新の状態に更新されるように強制するものです。
コミット
commit 75aab1374196f454c9fa579863eaadbae2ac17c3
Author: Russ Cox <rsc@golang.org>
Date: Tue Jun 25 17:23:21 2013 -0400
codereview: force hg update after hg pull -u during hg sync
If you hg update your client to an earlier CL, then
hg sync will move you back to tip if it pulls anything in,
but it will leave you where you are if it doesn't pull anything in.
That's confusing: make hg sync always update to tip.
R=golang-dev, bradfitz, r, dsymonds
CC=golang-dev
https://golang.org/cl/10456044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/75aab1374196f454c9fa579863eaadbae2ac17c3
元コミット内容
codereview: force hg update after hg pull -u during hg sync
If you hg update your client to an earlier CL, then
hg sync will move you back to tip if it pulls anything in,
but it will leave you where you are if it doesn't pull anything in.
That's confusing: make hg sync always update to tip.
R=golang-dev, bradfitz, r, dsymonds
CC=golang-dev
https://golang.org/cl/10456044
変更の背景
この変更の背景には、Mercurial (Hg) を利用したGoプロジェクトのコードレビューワークフローにおける、hg sync
コマンドの挙動に関する混乱がありました。
従来のhg sync
コマンドは、リモートリポジトリから新しい変更セット(コミット)をプルした場合(hg pull -u
)、自動的にローカルリポジトリの作業コピーを最新の状態("tip")に更新していました。しかし、もしリモートに新しい変更がなかった場合、hg sync
は何もプルせず、結果としてローカルの作業コピーはユーザーが以前にhg update
でチェックアウトしていた古い変更セットのままになっていました。
この挙動は、特に開発者が意図的に古い変更セットにhg update
で戻っていた場合に問題となりました。開発者はhg sync
を実行することで常に最新の状態に同期されることを期待するにもかかわらず、新しい変更がない場合は古い状態に留まってしまうため、混乱を招いていました。
このコミットは、このような混乱を解消し、hg sync
コマンドが常にローカルの作業コピーをリポジトリの最新の状態("tip")に更新するように強制することを目的としています。これにより、開発者はhg sync
を実行すれば、常に最新のコードベースで作業できるという一貫した期待を持つことができるようになります。
前提知識の解説
このコミットを理解するためには、以下の概念について理解しておく必要があります。
Mercurial (Hg)
Mercurialは、Gitと同様の分散型バージョン管理システム(DVCS)です。Goプロジェクトは初期にMercurialを使用していましたが、後にGitに移行しました。しかし、このコミットが作成された2013年時点では、Mercurialが主要なバージョン管理システムとして利用されていました。
Mercurialの基本的なコマンドと概念は以下の通りです。
- リポジトリ (Repository): プロジェクトのすべてのファイルと変更履歴が保存されている場所。
- 変更セット (Changeset): Gitにおけるコミットに相当し、一連の変更をまとめた単位。
- ヘッド (Head): 特定のブランチにおける最新の変更セット。
- tip: リポジトリ全体で最も新しい変更セット。
- 作業コピー (Working Copy): リポジトリからチェックアウトされ、実際にファイルを編集する場所。
Mercurialの主要コマンド
hg pull
: リモートリポジトリから新しい変更セットをローカルリポジトリにダウンロードします。このコマンドだけでは作業コピーは更新されません。hg update
: ローカルリポジトリ内の特定の変更セットに作業コピーを更新します。引数なしで実行すると、通常はローカルリポジトリのtip
に更新されます。hg pull -u
:hg pull
を実行した後、自動的に作業コピーをプルした最新の変更セットに更新します。hg incoming
: リモートリポジトリに、ローカルリポジトリにはまだ存在しない変更セットがあるかどうかを確認します。hg sync
: Goプロジェクトのコードレビューツールで使用されるカスタムコマンドで、hg pull
とhg update
を組み合わせたような動作をします。このコミットの変更対象です。
Goのコードレビューシステム
Goプロジェクトは、独自のコードレビューシステムを使用していました。これは、Gerritのようなツールに似ていますが、Mercurialと密接に統合されていました。codereview.py
スクリプトは、このシステムの一部であり、Mercurialの操作をラップして、コードレビューワークフローを円滑に進めるためのユーティリティ機能を提供していました。
codereview.py
このPythonスクリプトは、GoプロジェクトのMercurialベースのコードレビューシステムの中核をなすものでした。Mercurialコマンドのラッパーや、コードレビューに関連する様々なヘルパー機能を提供していました。このコミットでは、特にsync
関数が変更されています。
技術的詳細
このコミットの技術的な核心は、lib/codereview/codereview.py
ファイルのsync
関数における条件分岐の変更です。
変更前は、sync
関数内でリモートからの変更をプルする際に、hg_pull(ui, repo, update=True)
が直接呼び出されていました。このupdate=True
は、hg pull -u
に相当し、プルが成功すれば作業コピーも更新されることを意味します。
しかし、前述の背景で説明したように、hg pull
で新しい変更が何もプルされなかった場合、hg pull -u
は実質的に何もせず、作業コピーは古い変更セットのままになっていました。
このコミットでは、この挙動を修正するために、sync
関数内に以下のロジックが追加されました。
hg_incoming(ui, repo)
の呼び出し: まず、hg_incoming
関数を呼び出して、リモートリポジトリにローカルにはまだない新しい変更セットがあるかどうかを確認します。- 条件分岐:
- もし新しい変更セットがある場合(
hg_incoming
がTrueを返す場合)、これまで通りhg_pull(ui, repo, update=True)
を実行します。これにより、新しい変更がプルされ、作業コピーも最新に更新されます。 - もし新しい変更セットがない場合(
hg_incoming
がFalseを返す場合)、hg_update(ui, repo)
を呼び出します。このhg_update
は、新しく追加されたヘルパー関数で、引数なしのhg update
に相当し、ローカルリポジトリのtip
に作業コピーを強制的に更新します。
- もし新しい変更セットがある場合(
この変更により、hg sync
は常に以下のいずれかの方法で作業コピーを最新の状態に保つことが保証されます。
- 新しい変更をプルして更新する。
- 新しい変更がない場合でも、明示的に
hg update
を実行して最新の状態に更新する。
コミットメッセージにある「It is important not to do both hg pull -u and hg update in the same command, because the hg update will end up marking resolve conflicts from the hg pull -u as resolved, causing files with <<< >>> markers to not show up in hg resolve -l. Yay Mercurial.」というコメントは、Mercurialの挙動に関する注意点を示しています。hg pull -u
とhg update
を連続して実行すると、hg pull -u
によって発生したマージコンフリクトが、その後のhg update
によって誤って解決済みとマークされてしまう可能性があるため、これを避けるために条件分岐でどちらか一方のみを実行するようにしている、という非常に具体的なMercurialの癖への対応が示されています。これは、Mercurialの内部動作を深く理解している開発者ならではの配慮と言えます。
また、このコミットでは、hg_update
という新しいヘルパー関数がcodereview.py
に追加されています。この関数は、hg_commands.update
をラップし、hg_pull
と同様に、Mercurialの出力からノイズを除去し、ユーザーにとって分かりやすい形式で表示する役割を担っています。
コアとなるコードの変更箇所
lib/codereview/codereview.py
ファイルのsync
関数と、新しく追加されたhg_update
関数が主な変更箇所です。
--- a/lib/codereview/codereview.py
+++ b/lib/codereview/codereview.py
@@ -1168,6 +1168,25 @@ def hg_pull(ui, repo, **opts):\
ui.write(line + '\n')
return err
+def hg_update(ui, repo, **opts):\
+ w = uiwrap(ui)
+ ui.quiet = False
+ ui.verbose = True # for file list
+ err = hg_commands.update(ui, repo, **opts)
+ for line in w.output().split('\n'):
+ if isNoise(line):
+ continue
+ if line.startswith('moving '):
+ line = 'mv ' + line[len('moving '):]
+ if line.startswith('getting ') and line.find(' to ') >= 0:
+ line = 'mv ' + line[len('getting '):]
+ if line.startswith('getting '):
+ line = '+ ' + line[len('getting '):]
+ if line.startswith('removing '):
+ line = '- ' + line[len('removing '):]
+ ui.write(line + '\n')
+ return err
+
def hg_push(ui, repo, **opts):\
w = uiwrap(ui)
ui.quiet = False
@@ -2019,7 +2038,19 @@ def sync(ui, repo, **opts):\
raise hg_util.Abort(codereview_disabled)\
if not opts["local"]:\
- err = hg_pull(ui, repo, update=True)\
+ # If there are incoming CLs, pull -u will do the update.
+ # If there are no incoming CLs, do hg update to make sure
+ # that an update always happens regardless. This is less
+ # surprising than update depending on incoming CLs.
+ # It is important not to do both hg pull -u and hg update
+ # in the same command, because the hg update will end
+ # up marking resolve conflicts from the hg pull -u as resolved,
+ # causing files with <<< >>> markers to not show up in
+ # hg resolve -l. Yay Mercurial.
+ if hg_incoming(ui, repo):
+ err = hg_pull(ui, repo, update=True)
+ else:
+ err = hg_update(ui, repo)
if err:
return err
sync_changes(ui, repo)
コアとなるコードの解説
hg_update
関数の追加
このコミットで新しく追加されたhg_update
関数は、Mercurialのupdate
コマンドをラップしています。
w = uiwrap(ui)
:uiwrap
は、MercurialのUIオブジェクトをラップし、コマンドの出力をキャプチャするためのユーティリティです。ui.quiet = False
とui.verbose = True
: Mercurialコマンドの出力を詳細にする設定です。err = hg_commands.update(ui, repo, **opts)
: 実際のMercurialのupdate
コマンドを実行します。for line in w.output().split('\n'):
:update
コマンドの出力を1行ずつ処理します。if isNoise(line): continue
: 不要な出力(ノイズ)をスキップします。if line.startswith('moving '): line = 'mv ' + line[len('moving '):]
:moving
で始まる行をmv
に変換し、より一般的なファイル移動の表示に合わせます。if line.startswith('getting ') and line.find(' to ') >= 0: line = 'mv ' + line[len('getting '):]
:getting ... to ...
のような行もmv
に変換します。if line.startswith('getting '): line = '+ ' + line[len('getting '):]
:getting
で始まる行を+
に変換し、ファイル追加の表示に合わせます。if line.startswith('removing '): line = '- ' + line[len('removing '):]
:removing
で始まる行を-
に変換し、ファイル削除の表示に合わせます。ui.write(line + '\n')
: 処理された行をUIに出力します。
このhg_update
関数は、hg_pull
関数と同様に、Mercurialの生出力をよりユーザーフレンドリーな形式に整形する役割を担っています。
sync
関数の変更
sync
関数内の変更は、以下の条件分岐が追加された部分です。
if hg_incoming(ui, repo):
err = hg_pull(ui, repo, update=True)
else:
err = hg_update(ui, repo)
if hg_incoming(ui, repo):
: リモートリポジトリに新しい変更セットがあるかどうかをhg_incoming
関数で確認します。hg_incoming
は、Mercurialのincoming
コマンドをラップしたもので、新しい変更がある場合にTrueを返します。
err = hg_pull(ui, repo, update=True)
: 新しい変更がある場合、これまで通りhg pull -u
に相当するhg_pull
を呼び出します。これにより、新しい変更がプルされ、作業コピーも最新に更新されます。else:
: 新しい変更がない場合。err = hg_update(ui, repo)
: 新しい変更がない場合でも、新しく追加されたhg_update
関数を呼び出し、作業コピーをローカルリポジトリのtip
に強制的に更新します。
このロジックにより、hg sync
は常に作業コピーを最新の状態に保つことが保証され、ユーザーの混乱が解消されます。また、Mercurialの特定の挙動(hg pull -u
とhg update
の連続実行によるコンフリクト解決の誤認識)を回避するためのコメントも非常に重要で、当時のMercurialの利用における深い知見を示しています。
関連リンク
- Goプロジェクトのコードレビューシステムに関する情報(当時のもの):https://golang.org/doc/contribute.html (現在はGitベースのGerritに移行しているため、当時のMercurialベースのシステムに関する直接的なドキュメントは少ないかもしれません。)
- Mercurial公式サイト: https://www.mercurial-scm.org/
参考にした情報源リンク
- Mercurial公式ドキュメント
- GoプロジェクトのGitHubリポジトリのコミット履歴
- Goプロジェクトのメーリングリストや開発者フォーラム(当時の議論を追う場合)
- https://golang.org/cl/10456044 (Goのコードレビューシステムにおける変更リストのURL)
- Mercurialの
pull
,update
,incoming
コマンドに関する一般的な情報