[インデックス 17255] ファイルの概要
このコミットは、cmd/go
ツールにおける Git リポジトリのクローンに関する問題を修正するものです。具体的には、go get
コマンドが古い Go バージョン(Go 1.2より前)で Git リポジトリをクローンした際に発生する「detached HEAD」状態を検出し、master
ブランチに切り替えることで、リポジトリが通常の Git 操作で利用可能になるように修復します。これにより、go get
がダウンロードしたリポジトリが、その後の開発作業で問題なく扱えるようになります。
コミット
commit 80ca8c5d0449d7c6a2b881aa3c05d3706575e628
Author: David Symonds <dsymonds@golang.org>
Date: Thu Aug 15 09:44:23 2013 +1000
cmd/go: fix detached heads that are remnants of bad git clones.
Fixes #6042.
R=adg
CC=golang-dev
https://golang.org/cl/12923043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/80ca8c5d0449d7c6a2b881aa3c05d3706575e628
元コミット内容
cmd/go
: 不適切な Git クローンの残骸である detached HEAD を修正。
Issue #6042 を修正。
変更の背景
この変更は、Go の go get
コマンドが Git リポジトリをクローンする際に発生していた特定の問題に対処するために導入されました。Go 1.2 より前のバージョンでは、go get
が Git リポジトリをダウンロードする方法に問題があり、結果としてクローンされたリポジトリが「detached HEAD」状態になってしまうことがありました。
「detached HEAD」状態のリポジトリは、特定のコミットを直接指しているため、ブランチに紐付けられていません。この状態では、通常の Git 操作(例えば、新しいコミットのプルやブランチの切り替えなど)が期待通りに機能しないか、非常に扱いにくくなります。特に、go get
がダウンロードしたリポジトリは、ユーザーがその後の開発で利用することを想定しているため、このような不安定な状態は大きな問題でした。
このコミットは、go get
がリポジトリをダウンロードした直後に、そのリポジトリが detached HEAD 状態であるかどうかをチェックし、もしそうであれば、自動的に master
ブランチに切り替えることで、この問題を修正します。これにより、go get
によって取得された Git リポジトリが、すぐに通常の開発ワークフローで使用できるようになります。
関連する Issue #6042 は、まさにこの「go get
で取得したリポジトリが detached HEAD になり、git pull
ができない」というユーザーからの報告に対応するものです。
前提知識の解説
Git の "detached HEAD"
Git における "HEAD" は、現在チェックアウトされているコミットを指すポインタです。通常、HEAD はブランチ(例: master
や main
)を指しており、そのブランチが最新のコミットを指しています。この状態では、新しいコミットを作成すると、ブランチのポインタも自動的に進みます。
しかし、「detached HEAD」状態とは、HEAD が直接特定のコミットを指している状態を指します。これは、ブランチを介さずにコミットハッシュで直接チェックアウトした場合や、タグをチェックアウトした場合などに発生します。この状態では、新しいコミットを作成しても、どのブランチにも属さない「孤立した」コミットが作成されてしまい、そのコミットに到達するためのブランチ参照がなくなってしまいます。そのため、detached HEAD 状態での作業は、一時的な実験や過去のコミットの調査には便利ですが、通常の開発フローには不向きです。
git symbolic-ref HEAD
コマンド
git symbolic-ref HEAD
コマンドは、HEAD がシンボリック参照(つまりブランチ)を指しているかどうかを確認するために使用されます。
- HEAD がブランチを指している場合(通常のブランチにいる場合)、このコマンドは
refs/heads/ブランチ名
のような出力を返します。 - HEAD が直接コミットを指している場合(detached HEAD 状態の場合)、このコマンドはエラーを返します。このエラーの有無を利用して、現在のリポジトリが detached HEAD 状態であるかをプログラム的に判断できます。
git checkout master
コマンド
git checkout master
コマンドは、リポジトリの master
ブランチに切り替えるために使用されます。もし master
ブランチが存在しない場合は、エラーになるか、あるいは設定によっては新しいブランチを作成しようとします。このコミットの文脈では、detached HEAD 状態から通常のブランチ状態に戻すために、最も一般的なデフォルトブランチである master
への切り替えを試みています。
go get
と VCS (Version Control System)
go get
コマンドは、Go パッケージとその依存関係をダウンロードし、インストールするために使用されます。このコマンドは、指定されたインポートパスに基づいて、適切なバージョン管理システム(Git, Mercurial, Subversionなど)を自動的に判断し、リポジトリをクローンまたは更新します。go get
は内部的に、各VCSに対応するコマンド(例: git clone
, git pull
)を呼び出して、ソースコードを取得します。
技術的詳細
このコミットは、src/cmd/go/vcs.go
ファイルに fixDetachedHead
という新しいメソッドを追加し、既存の download
メソッドからそれを呼び出すように変更しています。
fixDetachedHead
メソッドのロジックは以下の通りです。
- VCS の種類チェック: まず、現在の VCS が Git (
vcsGit
) であるかどうかを確認します。この修正は Git に特化したものであるため、Git 以外の場合は何もしません。 - detached HEAD の検出:
git symbolic-ref HEAD
コマンドをrunVerboseOnly
で実行します。- このコマンドが成功した場合(エラーが返されない場合)、それは HEAD がシンボリック参照(つまりブランチ)を指していることを意味し、detached HEAD 状態ではないため、処理を終了します。
- このコマンドがエラーを返した場合、それはリポジトリが detached HEAD 状態であることを意味します。
- detached HEAD の修復: detached HEAD 状態が検出された場合、
git checkout master
コマンドを実行してmaster
ブランチに切り替えます。これにより、リポジトリは通常のブランチ状態に戻り、その後の Git 操作が可能になります。 - ログ出力: 詳細ビルド (
buildV
が true) の場合、detached HEAD が検出され修復される際に、どのディレクトリが修復されたかを示すログメッセージが出力されます。
この fixDetachedHead
メソッドは、vcsCmd
構造体の download
メソッドの冒頭で呼び出されます。これにより、go get
がリポジトリの新しい変更をダウンロードする前に、まずそのリポジトリが detached HEAD 状態でないことを確認し、必要であれば修復するようになります。
コメントには「Go versions before 1.2 downloaded Git repositories in an unfortunate way that resulted in the working tree state being on a detached head.」とあり、Go 1.2 でこの問題が修正されたことが示唆されています。しかし、既に detached HEAD 状態になっている既存のリポジトリに対して go get
が git pull
を実行しようとすると問題が発生するため、この fixDetachedHead
が必要とされました。また、「TODO(dsymonds): Consider removing this for Go 1.3.」というコメントは、将来的にこの修正が不要になる可能性を示唆しています。これは、Go 1.2 以降では新規のクローンで detached HEAD が発生しないため、既存の古いクローンが十分に更新されれば、この修復ロジック自体が不要になるという考えに基づいています。
コアとなるコードの変更箇所
src/cmd/go/vcs.go
ファイルの download
関数に fixDetachedHead
の呼び出しが追加され、fixDetachedHead
関数自体が新しく定義されています。
diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go
index d857c14462..ec5dc17c5f 100644
--- a/src/cmd/go/vcs.go
+++ b/src/cmd/go/vcs.go
@@ -223,9 +223,36 @@ func (v *vcsCmd) create(dir, repo string) error {
// download downloads any new changes for the repo in dir.
func (v *vcsCmd) download(dir string) error {
+ if err := v.fixDetachedHead(dir); err != nil {
+ return err
+ }
return v.run(dir, v.downloadCmd)
}
+// fixDetachedHead switches a Git repository in dir from a detached head to the master branch.
+// Go versions before 1.2 downloaded Git repositories in an unfortunate way
+// that resulted in the working tree state being on a detached head.
+// That meant the repository was not usable for normal Git operations.
+// Go 1.2 fixed that, but we can't pull into a detached head, so if this is
+// a Git repository we check for being on a detached head and switch to the
+// real branch, almost always called "master".
+// TODO(dsymonds): Consider removing this for Go 1.3.
+func (v *vcsCmd) fixDetachedHead(dir string) error {
+ if v != vcsGit {
+ return nil
+ }
+
+ // "git symbolic-ref HEAD" succeeds iff we are not on a detached head.
+ if err := v.runVerboseOnly(dir, "symbolic-ref HEAD"); err == nil {
+ // not on a detached head
+ return nil
+ }
+ if buildV {
+ log.Printf("%s on detached head; repairing", dir)
+ }
+ return v.run(dir, "checkout master")
+}
+
// tags returns the list of available tags for the repo in dir.
func (v *vcsCmd) tags(dir string) ([]string, error) {
var tags []string
コアとなるコードの解説
func (v *vcsCmd) download(dir string) error
この関数は、指定されたディレクトリ (dir
) にあるリポジトリの新しい変更をダウンロードする役割を担っています。
func (v *vcsCmd) download(dir string) error {
if err := v.fixDetachedHead(dir); err != nil {
return err
}
return v.run(dir, v.downloadCmd)
}
if err := v.fixDetachedHead(dir); err != nil { return err }
:v.fixDetachedHead(dir)
を呼び出し、dir
で指定されたリポジトリが detached HEAD 状態であれば修復を試みます。- もし
fixDetachedHead
がエラーを返した場合(例えば、Git コマンドの実行に失敗した場合など)、そのエラーを呼び出し元に返して処理を中断します。 - この行が追加されたことで、実際のリポジトリのダウンロード処理 (
v.run(dir, v.downloadCmd)
) の前に、リポジトリの状態が正常であることが保証されるようになりました。
return v.run(dir, v.downloadCmd)
:fixDetachedHead
が成功または何もする必要がなかった場合、通常のダウンロードコマンド (v.downloadCmd
はgit pull
などに相当) を実行します。
func (v *vcsCmd) fixDetachedHead(dir string) error
この新しい関数は、Git リポジトリが detached HEAD 状態である場合に、それを master
ブランチに切り替えることで修復します。
func (v *vcsCmd) fixDetachedHead(dir string) error {
if v != vcsGit {
return nil
}
if v != vcsGit { return nil }
:- 現在の
vcsCmd
オブジェクト (v
) が Git (vcsGit
) ではない場合、この関数は何もせずnil
(エラーなし) を返して終了します。これは、この修正が Git に特化しているためです。
- 現在の
// "git symbolic-ref HEAD" succeeds iff we are not on a detached head.
if err := v.runVerboseOnly(dir, "symbolic-ref HEAD"); err == nil {
// not on a detached head
return nil
}
if err := v.runVerboseOnly(dir, "symbolic-ref HEAD"); err == nil
:v.runVerboseOnly(dir, "symbolic-ref HEAD")
を実行します。これは、指定されたディレクトリ (dir
) でgit symbolic-ref HEAD
コマンドを実行します。- このコマンドは、HEAD がブランチを指している場合(つまり、detached HEAD ではない場合)は成功し、エラーを返しません。
err == nil
は、コマンドが成功したことを意味します。この場合、リポジトリは detached HEAD ではないため、nil
を返して関数を終了します。
if buildV {
log.Printf("%s on detached head; repairing", dir)
}
return v.run(dir, "checkout master")
}
if buildV { log.Printf("%s on detached head; repairing", dir) }
:buildV
は、go get -v
のように詳細出力モードが有効になっている場合にtrue
になるグローバル変数です。buildV
がtrue
の場合、log.Printf
を使って、どのディレクトリが detached HEAD 状態であり、修復中であるかを示すメッセージを出力します。
return v.run(dir, "checkout master")
:- ここに至るということは、
git symbolic-ref HEAD
がエラーを返した、つまりリポジトリが detached HEAD 状態であることを意味します。 v.run(dir, "checkout master")
を実行し、指定されたディレクトリでgit checkout master
コマンドを実行します。これにより、リポジトリの HEAD がmaster
ブランチに切り替わり、通常のブランチ状態に戻ります。このコマンドの実行結果(成功またはエラー)が関数の戻り値となります。
- ここに至るということは、
関連リンク
- Go Issue 6042: https://code.google.com/p/go/issues/detail?id=6042 (古い Go Issue Tracker のリンクですが、GitHub に移行されている可能性があります)
- Go CL 12923043: https://golang.org/cl/12923043 (Go の Gerrit コードレビューシステムへのリンク)
参考にした情報源リンク
- Git - HEAD とは何か
- Git - symbolic-ref
- Git - checkout
- Go Command - go get
- golang/go issue 6042 on GitHub (Go Issue Tracker が GitHub に移行された後のリンク)# [インデックス 17255] ファイルの概要
このコミットは、cmd/go
ツールにおける Git リポジトリのクローンに関する問題を修正するものです。具体的には、go get
コマンドが古い Go バージョン(Go 1.2より前)で Git リポジトリをクローンした際に発生する「detached HEAD」状態を検出し、master
ブランチに切り替えることで、リポジトリが通常の Git 操作で利用可能になるように修復します。これにより、go get
がダウンロードしたリポジトリが、その後の開発作業で問題なく扱えるようになります。
コミット
commit 80ca8c5d0449d7c6a2b881aa3c05d3706575e628
Author: David Symonds <dsymonds@golang.org>
Date: Thu Aug 15 09:44:23 2013 +1000
cmd/go: fix detached heads that are remnants of bad git clones.
Fixes #6042.
R=adg
CC=golang-dev
https://golang.org/cl/12923043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/80ca8c5d0449d7c6a2b881aa3c05d3706575e628
元コミット内容
cmd/go
: 不適切な Git クローンの残骸である detached HEAD を修正。
Issue #6042 を修正。
変更の背景
この変更は、Go の go get
コマンドが Git リポジトリをクローンする際に発生していた特定の問題に対処するために導入されました。Go 1.2 より前のバージョンでは、go get
が Git リポジトリをダウンロードする方法に問題があり、結果としてクローンされたリポジリが「detached HEAD」状態になってしまうことがありました。
「detached HEAD」状態のリポジトリは、特定のコミットを直接指しているため、ブランチに紐付けられていません。この状態では、通常の Git 操作(例えば、新しいコミットのプルやブランチの切り替えなど)が期待通りに機能しないか、非常に扱いにくくなります。特に、go get
がダウンロードしたリポジトリは、ユーザーがその後の開発で利用することを想定しているため、このような不安定な状態は大きな問題でした。
このコミットは、go get
がリポジトリをダウンロードした直後に、そのリポジトリが detached HEAD 状態であるかどうかをチェックし、もしそうであれば、自動的に master
ブランチに切り替えることで、この問題を修正します。これにより、go get
によって取得された Git リポジリが、すぐに通常の開発ワークフローで使用できるようになります。
関連する Issue #6042 は、まさにこの「go get
で取得したリポジトリが detached HEAD になり、git pull
ができない」というユーザーからの報告に対応するものです。
前提知識の解説
Git の "detached HEAD"
Git における "HEAD" は、現在チェックアウトされているコミットを指すポインタです。通常、HEAD はブランチ(例: master
や main
)を指しており、そのブランチが最新のコミットを指しています。この状態では、新しいコミットを作成すると、ブランチのポインタも自動的に進みます。
しかし、「detached HEAD」状態とは、HEAD が直接特定のコミットを指している状態を指します。これは、ブランチを介さずにコミットハッシュで直接チェックアウトした場合や、タグをチェックアウトした場合などに発生します。この状態では、新しいコミットを作成しても、どのブランチにも属さない「孤立した」コミットが作成されてしまい、そのコミットに到達するためのブランチ参照がなくなってしまいます。そのため、detached HEAD 状態での作業は、一時的な実験や過去のコミットの調査には便利ですが、通常の開発フローには不向きです。
git symbolic-ref HEAD
コマンド
git symbolic-ref HEAD
コマンドは、HEAD がシンボリック参照(つまりブランチ)を指しているかどうかを確認するために使用されます。
- HEAD がブランチを指している場合(通常のブランチにいる場合)、このコマンドは
refs/heads/ブランチ名
のような出力を返します。 - HEAD が直接コミットを指している場合(detached HEAD 状態の場合)、このコマンドはエラーを返します。このエラーの有無を利用して、現在のリポジトリが detached HEAD 状態であるかをプログラム的に判断できます。
git checkout master
コマンド
git checkout master
コマンドは、リポジトリの master
ブランチに切り替えるために使用されます。もし master
ブランチが存在しない場合は、エラーになるか、あるいは設定によっては新しいブランチを作成しようとします。このコミットの文脈では、detached HEAD 状態から通常のブランチ状態に戻すために、最も一般的なデフォルトブランチである master
への切り替えを試みています。
go get
と VCS (Version Control System)
go get
コマンドは、Go パッケージとその依存関係をダウンロードし、インストールするために使用されます。このコマンドは、指定されたインポートパスに基づいて、適切なバージョン管理システム(Git, Mercurial, Subversionなど)を自動的に判断し、リポジトリをクローンまたは更新します。go get
は内部的に、各VCSに対応するコマンド(例: git clone
, git pull
)を呼び出して、ソースコードを取得します。
技術的詳細
このコミットは、src/cmd/go/vcs.go
ファイルに fixDetachedHead
という新しいメソッドを追加し、既存の download
メソッドからそれを呼び出すように変更しています。
fixDetachedHead
メソッドのロジックは以下の通りです。
- VCS の種類チェック: まず、現在の VCS が Git (
vcsGit
) であるかどうかを確認します。この修正は Git に特化したものであるため、Git 以外の場合は何もしません。 - detached HEAD の検出:
git symbolic-ref HEAD
コマンドをrunVerboseOnly
で実行します。- このコマンドが成功した場合(エラーが返されない場合)、それは HEAD がシンボリック参照(つまりブランチ)を指していることを意味し、detached HEAD 状態ではないため、処理を終了します。
- このコマンドがエラーを返した場合、それはリポジトリが detached HEAD 状態であることを意味します。
- detached HEAD の修復: detached HEAD 状態が検出された場合、
git checkout master
コマンドを実行してmaster
ブランチに切り替えます。これにより、リポジトリは通常のブランチ状態に戻り、その後の Git 操作が可能になります。 - ログ出力: 詳細ビルド (
buildV
が true) の場合、detached HEAD が検出され修復される際に、どのディレクトリが修復されたかを示すログメッセージが出力されます。
この fixDetachedHead
メソッドは、vcsCmd
構造体の download
メソッドの冒頭で呼び出されます。これにより、go get
がリポジトリの新しい変更をダウンロードする前に、まずそのリポジトリが detached HEAD 状態でないことを確認し、必要であれば修復するようになります。
コメントには「Go versions before 1.2 downloaded Git repositories in an unfortunate way that resulted in the working tree state being on a detached head.」とあり、Go 1.2 でこの問題が修正されたことが示唆されています。しかし、既に detached HEAD 状態になっている既存のリポジトリに対して go get
が git pull
を実行しようとすると問題が発生するため、この fixDetachedHead
が必要とされました。また、「TODO(dsymonds): Consider removing this for Go 1.3.」というコメントは、将来的にこの修正が不要になる可能性を示唆しています。これは、Go 1.2 以降では新規のクローンで detached HEAD が発生しないため、既存の古いクローンが十分に更新されれば、この修復ロジック自体が不要になるという考えに基づいています。
コアとなるコードの変更箇所
src/cmd/go/vcs.go
ファイルの download
関数に fixDetachedHead
の呼び出しが追加され、fixDetachedHead
関数自体が新しく定義されています。
diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go
index d857c14462..ec5dc17c5f 100644
--- a/src/cmd/go/vcs.go
+++ b/src/cmd/go/vcs.go
@@ -223,9 +223,36 @@ func (v *vcsCmd) create(dir, repo string) error {
// download downloads any new changes for the repo in dir.
func (v *vcsCmd) download(dir string) error {
+ if err := v.fixDetachedHead(dir); err != nil {
+ return err
+ }
return v.run(dir, v.downloadCmd)
}
+// fixDetachedHead switches a Git repository in dir from a detached head to the master branch.
+// Go versions before 1.2 downloaded Git repositories in an unfortunate way
+// that resulted in the working tree state being on a detached head.
+// That meant the repository was not usable for normal Git operations.
+// Go 1.2 fixed that, but we can't pull into a detached head, so if this is
+// a Git repository we check for being on a detached head and switch to the
+// real branch, almost always called "master".
+// TODO(dsymonds): Consider removing this for Go 1.3.
+func (v *vcsCmd) fixDetachedHead(dir string) error {
+ if v != vcsGit {
+ return nil
+ }
+
+ // "git symbolic-ref HEAD" succeeds iff we are not on a detached head.
+ if err := v.runVerboseOnly(dir, "symbolic-ref HEAD"); err == nil {
+ // not on a detached head
+ return nil
+ }
+ if buildV {
+ log.Printf("%s on detached head; repairing", dir)
+ }
+ return v.run(dir, "checkout master")
+}
+
// tags returns the list of available tags for the repo in dir.
func (v *vcsCmd) tags(dir string) ([]string, error) {
var tags []string
コアとなるコードの解説
func (v *vcsCmd) download(dir string) error
この関数は、指定されたディレクトリ (dir
) にあるリポジトリの新しい変更をダウンロードする役割を担っています。
func (v *vcsCmd) download(dir string) error {
if err := v.fixDetachedHead(dir); err != nil {
return err
}
return v.run(dir, v.downloadCmd)
}
if err := v.fixDetachedHead(dir); err != nil { return err }
:v.fixDetachedHead(dir)
を呼び出し、dir
で指定されたリポジトリが detached HEAD 状態であれば修復を試みます。- もし
fixDetachedHead
がエラーを返した場合(例えば、Git コマンドの実行に失敗した場合など)、そのエラーを呼び出し元に返して処理を中断します。 - この行が追加されたことで、実際のリポジトリのダウンロード処理 (
v.run(dir, v.downloadCmd)
) の前に、リポジトリの状態が正常であることが保証されるようになりました。
return v.run(dir, v.downloadCmd)
:fixDetachedHead
が成功または何もする必要がなかった場合、通常のダウンロードコマンド (v.downloadCmd
はgit pull
などに相当) を実行します。
func (v *vcsCmd) fixDetachedHead(dir string) error
この新しい関数は、Git リポジトリが detached HEAD 状態である場合に、それを master
ブランチに切り替えることで修復します。
func (v *vcsCmd) fixDetachedHead(dir string) error {
if v != vcsGit {
return nil
}
if v != vcsGit { return nil }
:- 現在の
vcsCmd
オブジェクト (v
) が Git (vcsGit
) ではない場合、この関数は何もせずnil
(エラーなし) を返して終了します。これは、この修正が Git に特化しているためです。
- 現在の
// "git symbolic-ref HEAD" succeeds iff we are not on a detached head.
if err := v.runVerboseOnly(dir, "symbolic-ref HEAD"); err == nil {
// not on a detached head
return nil
}
if err := v.runVerboseOnly(dir, "symbolic-ref HEAD"); err == nil
:v.runVerboseOnly(dir, "symbolic-ref HEAD")
を実行します。これは、指定されたディレクトリ (dir
) でgit symbolic-ref HEAD
コマンドを実行します。- このコマンドは、HEAD がブランチを指している場合(つまり、detached HEAD ではない場合)は成功し、エラーを返しません。
err == nil
は、コマンドが成功したことを意味します。この場合、リポジトリは detached HEAD ではないため、nil
を返して関数を終了します。
if buildV {
log.Printf("%s on detached head; repairing", dir)
}
return v.run(dir, "checkout master")
}
if buildV { log.Printf("%s on detached head; repairing", dir) }
:buildV
は、go get -v
のように詳細出力モードが有効になっている場合にtrue
になるグローバル変数です。buildV
がtrue
の場合、log.Printf
を使って、どのディレクトリが detached HEAD 状態であり、修復中であるかを示すメッセージを出力します。
return v.run(dir, "checkout master")
:- ここに至るということは、
git symbolic-ref HEAD
がエラーを返した、つまりリポジトリが detached HEAD 状態であることを意味します。 v.run(dir, "checkout master")
を実行し、指定されたディレクトリでgit checkout master
コマンドを実行します。これにより、リポジトリの HEAD がmaster
ブランチに切り替わり、通常のブランチ状態に戻ります。このコマンドの実行結果(成功またはエラー)が関数の戻り値となります。
- ここに至るということは、
関連リンク
- Go Issue 6042: https://code.google.com/p/go/issues/detail?id=6042 (古い Go Issue Tracker のリンクですが、GitHub に移行されている可能性があります)
- Go CL 12923043: https://golang.org/cl/12923043 (Go の Gerrit コードレビューシステムへのリンク)
参考にした情報源リンク
- Git - HEAD とは何か
- Git - symbolic-ref
- Git - checkout
- Go Command - go get
- golang/go issue 6042 on GitHub (Go Issue Tracker が GitHub に移行された後のリンク)