りんごとバナナとエンジニア

エンジニア修行の記録

Gitリポジトリ移行時にgit remote rm -> addとすべきでない理由

先日、とあるリポジトリをBitbucketからGitHubに移行させた。念のためプッシュしていない変更がない状態にしておき、リモートリポジトリを無事に移した。あとはローカルリポジトリで指定しているremoteを更新するだけだったのだが、その時以下のようにやってしまった。

$ git remote rm origin
$ git remote add origin <移行先のリモートリポジトリのURL>

その場は何事もなかったが、その後しばらく開発作業を進めていると問題に直面した。 git pull でリモートの変更を取り込もうとすると、以下のエラーが出て失敗するようになってしまった。

$ git pull
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details

    git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream-to=origin/<branch> master

この原因は、remoteを消してまた作り直したことにある。 git pull は引数なしで実行すると、カレントブランチが追跡しているリモートブランチの変更を取ってくる。このとき、remoteの名前が origin であれば、ローカルの .git/refs/remotes/origin 以下に、各ブランチの最新のコミットを示すコミットオブジェクトが保存される。これが「リモート追跡ブランチ」と言われるものの実体である。
しかし今回、 git remote rm origin をしたことで、 .git/refs/remotes/origin 以下を消してしまった。これにより、リモート追跡ブランチも全て消えてしまい、ローカルブランチがリモートのどのブランチを追跡しているかわからなくなってしまったのだ。現に git branch -vv で確認すると、移行前まではローカルブランチは同名のリモートブランチを追跡していたのだが、移行後はその紐付きが全てなくなっていた。

もちろん git branch -u origin/<リモートブランチ名> とすれば再び紐付けることができるが、各ブランチでそれをやるのは面倒くさい。最も楽な方法は、移行するときに以下のようにすることだ。

git remote set-url origin <移行先のリモートリポジトリのURL>

こうすればURLが変わるだけであり .git/refs/remotes/origin は消えないので、移行後も問題なくリモートと通信することができる。