カルテット開発チームではバージョン管理でgitを使用しています。 使い始めた頃は何回も操作を間違って(今もですが)、gitからソースファイルを復旧するためだけに何時間も費やしてしまいました。今回は、うっかり備忘録としてありがちな間違いと解決用のコマンドをご紹介します。
記事を書くにあたり以下のサイトを参考にさせていただきました。
http://qiita.com/yaotti/items/0d5364eae36ad1bb8e01
ブランチを切り忘れてmasterでコミットしてしまった
新しいプロジェクトを作って作業を始めたとき、ブランチを切り忘れたうっかりさんの対応です。新しいブランチを作れば大丈夫です。
[bash]
$git checkout -b bugfix
$git checkout master
$git reset –hard HEAD^
[/bash]
<コマンドの説明>
その時点でブランチbugfixを作成(-b:チェックアウトと同時に移動)
masterブランチを選択
コミットを1つ消す(–hard:物理ファイルもリセット)
ブランチを移動し忘れてコミットしてしまった
修正を加えた後で「ブランチを移動し忘れた!!」といううっかりさんはcherry-pickを使いましょう。cherry-pickは別ブランチにあるコミットを取り込みます。コミットの識別番号が変わるので取り込み済のコミットはresetで消しておいたほうがスッキリすると思います。
[bash]
$git checkout bugfix
$git cherry-pick master
$git checkout master
$git reset –hard HEAD^^
[/bash]
<コマンドの説明>
bugfixブランチを選択
masterのコミットを持ってくる(もしくはcherry-pick C2 C3でコミットを指定)
masterブランチを選択
取り込み済のコミット2つを消す
間違ったコミットをpushしてしまった
masterから分岐したはずのbugfixでコミットがひとつ欠けている、しかもmasterはすでにpushしてしまった…という残念なうっかりさんの対応です。以前この泥沼にはまってほぼ1日を費やしました。
pushしてしまったコミットはresetで取り消すとさらに泥沼になるのでrevertで打ち消ししましょう。その後でmergeやcherry-pickなどを使って正しいコミットをmasterに取り込みします。
[bash]
$git checkout master
$git revert C2
…(merge,cherry-pickなど)
$git push
[/bash]
<コマンドの説明>
masterブランチを選択
C2のコミットを打ち消し
merge,cherry-pickなどを使って正しいコミットを持ってくる
もう一度push一人だけで作業しているプロジェクトならgit push -fでリモートのコミットを書き換えるという反則技もありますが、訳が分かっていない最初の頃ほど使わないほうが良い気がします。もう少しgitに慣れて、泥沼にはまった原因とrevertの使い方を理解した上で最終手段として使うほうがいいかな、と思います。
間違ってreset –hardして必要なコミットを消した
gitは現在位置HEADからの相対位置でコミットを指定できるのでとても便利ですね。 1つ前のコミット HEAD^ または HEAD~1
2つ前のコミット HEAD^^ または HEAD~2
便利な反面、簡単にコミットが取り消しできるので相対位置を間違えて過去に戻りすぎることもありますよね?そんなうっかりさんはreflogを確認してresetする前の状態に戻りましょう。
[bash]
$git reflog
1fff20 HEAD@{0}: head~3
3f03c5 HEAD@{1}: commit "xxx修正"
5350ca HEAD@{2}: commit "yyy修正"
$git reset –hard HEAD@{1}
[/bash]
<コマンドの説明>
reflogでブランチに対して行った操作のログを見る
戻したいコミットを指定(–hardで物理ファイルごと戻しましょう)
mergeとrebaseの違い
mergeとrebaseはどちらも2つのブランチのコミットを合体させるコマンドです。どのようなうっかり対策になるか分かりませんが、混乱しやすいこのコマンドをおさらいしておきましょう。
[merge]
[bash]
$git checkout master
$git merge bugfix
[/bash]
<コマンドの説明>
bugfixの修正をmasterに取り込みします。
masterからbugfixが分岐したそのままの形が残ります。
[rebase]
[bash]
$git checkout bugfix
$git rebase master
[/bash]
<コマンドの説明>
bugfixをmasterに統合して一本化します。
bugfixのコミットは改変されます。どちらも物理的なファイルの状態が同じになるのでややこしいですね。
一般的には統合ブランチ(分岐元のmaster)、トピックブランチ(分岐したbugfix)どちらにコミットを取り込むかによって使い分けるようです。masterにbugfixを取り込む→merge
bugfixにmasterを取り込む(分岐元に統合させる)→rebase実際のプロジェクトではmasterからいくつもブランチが分岐しているので、bugfixを一度masterにrebaseする事により、他のブランチの修正も反映され分岐の流れもスッキリするのかなと理解しています。
ツリー表示
全てのブランチのコミットをツリー表示してくれるコマンドがないかなあと探したら、ありました。git –graphにオプションを追加して見やすくしたものです。長いので.gitconfigにエイリアスを作っておくと便利です。
.gitconfig
[bash]
[alias]
graph=$ git log –graph –date-order -C -M –pretty=format:\"<%h> %ad [%an] %Cgreen%d%Creset %s\" –all –date=short
[/bash]
ツリー表示を見たい時はgit graphと入力します。
おわり
普段作業しているプロジェクトをgit graphで表示してみたら、ツリー表示の便利さが微塵も感じられないほどのスパゲティ状態でした。ブランチをきれいに管理するには、まだまだ程遠い道のりがありそうです…。