[インデックス 16713] ファイルの概要
このコミットは、Go言語のコマンドラインツール cmd/go
における、Gitリポジトリに対する go get -u
コマンドの挙動修正に関するものです。具体的には、go get -u
がGitリポジトリを更新する際に、git fetch
ではなく git pull --ff-only
を使用するように変更することで、ユーザーのローカル変更を誤って上書きすることなく、より安全かつ確実に最新のコードを取得できるようにします。
コミット
commit 8b16a8bbc10c9cfc07123311e1cc05263c7beec9
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Sun Jul 7 23:06:30 2013 +0800
cmd/go: fix "go get -u" for git repositories.
CL 10869046 changed cmd/go to checkout master branch, so
for "go get -u" to work, it must "git pull" instead of
"git fetch". Added "--ff-only" so that it won't accidentally
overwrite user changes.
R=dsymonds
CC=golang-dev
https://golang.org/cl/10907043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/8b16a8bbc10c9cfc07123311e1cc05263c7beec9
元コミット内容
cmd/go: fix "go get -u" for git repositories.
CL 10869046 changed cmd/go to checkout master branch, so
for "go get -u" to work, it must "git pull" instead of
"git fetch". Added "--ff-only" so that it won't accidentally
overwrite user changes.
R=dsymonds
CC=golang-dev
https://golang.org/cl/10907043
変更の背景
この変更の背景には、以前のコミット CL 10869046
があります。CL 10869046
は、cmd/go
がGitリポジトリを扱う際に、デフォルトで master
ブランチをチェックアウトするように変更しました。この変更以前は、go get -u
は単にリモートの変更をフェッチ(git fetch
)するだけで、ローカルブランチにマージする操作は行っていませんでした。
master
ブランチをチェックアウトするようになったことで、go get -u
が期待通りに最新のコードを反映するためには、フェッチした変更をローカルの master
ブランチに統合する必要が生じました。しかし、単に git fetch
を実行するだけでは、リモートの変更がローカルの作業コピーに反映されません。そのため、git pull
のようなマージ操作が必要となりました。
また、go get -u
はユーザーがローカルで行った変更を上書きすべきではありません。もしユーザーがローカルで作業中のリポジトリに対して go get -u
を実行した場合、その変更が失われることは望ましくありません。この問題を解決するために、git pull
に --ff-only
オプションを追加することが決定されました。
前提知識の解説
このコミットを理解するためには、以下のGitコマンドとGoの go get
コマンドに関する基本的な知識が必要です。
-
git fetch
: リモートリポジトリから最新の変更(コミット、ブランチ、タグなど)をローカルリポジトリにダウンロードしますが、ローカルのブランチにはマージしません。リモートの変更をローカルで確認したいが、現在の作業を中断したくない場合などに使用します。ダウンロードされた変更は、通常origin/master
のようなリモート追跡ブランチに保存されます。 -
git pull
:git fetch
とgit merge
の2つの操作を組み合わせたものです。リモートリポジトリから最新の変更をダウンロードし(fetch
)、その後、現在のローカルブランチにその変更をマージします。これにより、ローカルの作業コピーがリモートの最新状態に更新されます。 -
git pull --ff-only
:git pull
に--ff-only
オプションを付けたものです。このオプションは、マージが「fast-forward」(早送り)マージである場合にのみ実行を許可します。fast-forwardマージとは、ローカルブランチがリモートブランチの直接の祖先である場合に発生するマージで、単にローカルブランチのポインタをリモートブランチの最新コミットに移動させるだけで完了します。 もしfast-forwardマージが不可能な場合(つまり、ローカルブランチにリモートにはないコミットがある場合、またはマージコンフリクトが発生する可能性がある場合)、--ff-only
オプションが指定されているとgit pull
は失敗し、マージは実行されません。これにより、ユーザーのローカル変更が意図せず上書きされたり、複雑なマージコンフリクトが自動的に解決されたりするのを防ぎます。 -
go get
: Go言語のパッケージ管理コマンドの一つです。指定されたパッケージとその依存関係をダウンロードし、インストールします。go get -u
:-u
オプションは「update」を意味し、指定されたパッケージとその依存関係を最新バージョンに更新します。既にローカルに存在するパッケージの場合、リモートリポジトリから最新の変更を取得し、ローカルのコピーを更新しようとします。
技術的詳細
このコミットの技術的な核心は、cmd/go
がGitリポジトリを更新する際の内部的な挙動を変更した点にあります。
以前の go get -u
は、Gitリポジトリに対して git fetch
コマンドを実行していました。git fetch
はリモートの変更をローカルに取得するものの、ローカルの作業ブランチ(例: master
)には自動的にマージしません。これは、ユーザーが手動でマージを行うことを想定しているか、あるいは go get
が単にリモートの最新状態をローカルにキャッシュするだけで十分だと考えられていたためかもしれません。
しかし、CL 10869046
によって cmd/go
が master
ブランチをチェックアウトするようになったため、go get -u
が実際にローカルの master
ブランチを最新の状態に「更新」するためには、フェッチした変更をマージする必要が生じました。
そこで、git pull
コマンドが導入されました。git pull
は git fetch
と git merge
を組み合わせたものであり、リモートの変更を取得し、それを現在のブランチにマージします。これにより、go get -u
が実行された際に、ローカルのGitリポジトリがリモートの最新状態に同期されるようになります。
さらに重要なのは、--ff-only
オプションの追加です。このオプションは、git pull
がfast-forwardマージのみを実行することを強制します。
- fast-forwardマージが可能な場合: ローカルブランチにリモートにはないコミットがなく、単にリモートの最新コミットまでポインタを進めるだけで済む場合、
git pull --ff-only
は成功し、ローカルリポジトリはスムーズに更新されます。これは、ユーザーがローカルで変更を加えていない、または変更をコミットしていない場合に典型的です。 - fast-forwardマージが不可能な場合: ローカルブランチにリモートにはないコミットがある場合(つまり、ユーザーがローカルで作業を進めている場合)、
git pull --ff-only
は失敗します。これにより、go get -u
はユーザーの未コミットの変更や、リモートと競合する可能性のあるローカルコミットを自動的に上書きしたり、複雑なマージを試みたりすることなく、安全に処理を停止します。ユーザーはその後、手動でマージを行うか、変更をコミット/スタッシュするなどの対応を取ることができます。
この変更により、go get -u
はGitリポジトリに対してより堅牢で安全な更新メカニズムを提供するようになりました。
コアとなるコードの変更箇所
変更は src/cmd/go/vcs.go
ファイルの vcsGit
構造体内の downloadCmd
フィールドにあります。
--- a/src/cmd/go/vcs.go
+++ b/src/cmd/go/vcs.go
@@ -91,7 +91,7 @@ var vcsGit = &vcsCmd{
cmd: "git",
createCmd: "clone {repo} {dir}",
- downloadCmd: "fetch",
+ downloadCmd: "pull --ff-only",
tagCmd: []tagCmd{
// tags/xxx matches a git tag named xxx
コアとなるコードの解説
src/cmd/go/vcs.go
ファイルは、Goの cmd/go
ツールが様々なバージョン管理システム(VCS)とどのように連携するかを定義しています。このファイルには、Git、Mercurial (hg)、Subversion (svn)、Bazaar (bzr) などのVCSごとのコマンド定義が含まれています。
vcsGit
構造体は、Gitリポジトリを操作するためのコマンドを定義しています。
cmd: "git"
: Gitコマンドの実行ファイル名を指定します。createCmd: "clone {repo} {dir}"
: 新しいリポジトリを作成(クローン)する際に実行されるコマンドです。{repo}
はリモートリポジトリのURL、{dir}
はローカルのディレクトリパスに置き換えられます。downloadCmd: "fetch"
からdownloadCmd: "pull --ff-only"
への変更がこのコミットの核心です。- 変更前は、
downloadCmd
はfetch
でした。これは、go get -u
がリポジトリを更新する際に、単にgit fetch
を実行していたことを意味します。 - 変更後は、
downloadCmd
がpull --ff-only
になりました。これにより、go get -u
はgit pull --ff-only
を実行するようになり、リモートの変更をフェッチし、fast-forwardマージが可能な場合にのみローカルブランチにマージするようになりました。
- 変更前は、
この変更により、go get -u
はGitリポジトリの更新において、より安全で意図した通りの挙動を示すようになりました。
関連リンク
- Go言語の公式ドキュメント: https://golang.org/
- Goの
go get
コマンドに関するドキュメント: https://golang.org/cmd/go/#hdr-Download_and_install_packages_and_dependencies - Git公式ドキュメント: https://git-scm.com/doc
参考にした情報源リンク
- GitHub上のコミットページ: https://github.com/golang/go/commit/8b16a8bbc10c9cfc07123311e1cc05263c7beec9
- Go CL 10907043: https://golang.org/cl/10907043
- Gitの
pull
コマンドに関するドキュメント: https://git-scm.com/docs/git-pull - Gitの
fetch
コマンドに関するドキュメント: https://git-scm.com/docs/git-fetch - Gitの fast-forward マージに関する情報 (一般的なGitの概念): https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging (Git公式ブックの関連セクション)