git mergeコマンドを使って、bugFixブランチをmainブランチへとマージするまでの流れ
bugFixという名前で新しいブランチを切る
git branch bugFix
git checkout bugFixコマンドでbugFixブランチに切り替える
git checkout bugFix
一回だけコミット
git commit
git checkoutでmainへ戻る
git checkout main
もう1回コミットする
git commit
git mergeコマンドを使って、bugFixブランチをmainブランチへとマージする
git merge bugFix
用語
HEAD
HEADとは現在チェックアウトされているコミットを指す単語です。要するに今作業中のコミットを表します。
HEADはいつも、作業中のツリーに反映されている最新のコミットを指します。作業ツリーへ変更を加える多くのgitコマンドはまずHEADから処理を始めます。
HEADは普段、ブランチ名(例えば、bugFixなど)を指します。コミットすれば、bugFixの状態が変更され、その変更がHEADから確認できるようになります
HEADの分離(detached HEAD)とは単に、ブランチではなく特定のコミットにHEADを紐づけることです。特定のコミットに紐づけるにはコミットをハッシュで指定します。ハッシュを見るにはgit logを使う。
例えば、fed2da64c0efc5293610bdd892f82a58e8cbc5d8
手短くコミットを指定する方法があります。ユニークな存在だと確認できるだけのハッシュの字数を入力すれば良いです -- 上記の長い文字列の代わりにfed2を入力するだけで済みます。
相対リファレンス
相対リファレンスを使うことで、覚えやすい位置(例えばbugFixブランチやHEAD)から始め、そのところから相対的な位置を指定できます。
[やり方]
1.一つずつ上へ移動させる^(カレット)
リファレンス名にカレットを追加すると、指定コミットの親コミットを見つけるようにとgitに命令を出しています。
なので main^と記述すれば、"mainの一個上の親"、という意味になります。
そしてmain^^とはその親の一つの上のコミット(2代前の親)を指します。
コミットハッシュを書くよりずっと簡単。
bugFixの親コミットをチェックアウトするには
git checkout bugFix^
2."~" 演算子
コミットツリーの中で複数の段階上へ移動したいときに使う。チルダ演算子のあとには、上へ移動したい親コミットの数を表す数字もオプションでつけられます。
git checkout HEAD~4
ブランチの強制
相対リファレンスのよくある使い方としてあるのは、ブランチの移動です。-fオプションを使ってブランチを直接コミットに関連付けられます。次のようになります
git branch -f main HEAD~3
mainブランチを(強制的に)HEADより親三代前へと移動します。
git branch main C6
git checkout HEAD~1
git branch -f bugFix HEAD~1
or
git branch -f bugFix C0
変更を元に戻す git reset | git Revert
git reset HEAD~1
git resetはブランチのポインタを後方に移動することで変更のキャンセルを実現します。履歴を上書きするような動作だと思うと良いでしょう
git revert HEAD
変更を巻き戻して他の人とそれを共有するためには、git revertを使う必要があります。
コードの移動 git cherry-pick
git cherry-pick <Commit1> <Commit2> <...>
git cherry-pick C2 C4
現在の位置(HEAD)の下に一連のコミットをコピーしたいという意を単純に表す方法です。
Git インタラクティブrebase
どのコミットを操りたいかがわからない時はgitのインタラクティブrebaseを使えます。rebaseしたい一連のコミットを一括で見るベストな方法です。
インタラクティブrebaseとは単に、rebaseコマンドに-iオプションを合わせて使うことです。
このオプションをつければ、gitがインタフェースを開き、どのコミットがrebase対象の下にコピーされるかを確認できます。それらのコミットのハッシュやメッセージも表示され、rebaseの概要を一眼で見るのに便利です。
インタラクティブrebaseダイアログが開くと、3つの操作から選べます:
- UIウィンドウのなかで順番を調整するだけでコミットの順番を変えられます(こちらのダイアログでは、マウスでドラッグアンドドロップで操作します)。
- 特定のコミットを丸ごと除くこともできます。除きたいコミットを指定するにはpickをオフにします。
- 最後に、コミットを組み合わせられます。技術的に制限があり再現できないのでその詳細な説明を省きますが、短く言いますと、複数のコミットを一つにまとめることができる機能です。
git rebase -i HEAD~4
ローカルに積み上がったコミット
実際の開発ではこういうケースがよくあります:「バグの原因調査を試みているがバグの再現性がかなり低い。調査の補助のために、いくつかのデバッグ用の命令やprint文を差し込んでいる。」
これらのデバッグ用のコードはバグ修正用のブランチにコミットされています。そしてついにバグの原因を突き止めて、修正した!やった!
あとはbugFixブランチをmainブランチに統合できればOK。そこで単純にmainをfast-forwardすればよいかというと、それではmainブランチの中にデバッグ用のコードも混入してしまいます。
こでGitの魔法が力を発揮します。解決のためにはいくつかの方法がありますが、最も素直な解決方法は2つあって:
git rebase -i
git cherry-pick
インタラクティブモードの(-iオプションつきの)rebaseによって、保持したいコミットと破棄したいコミットを選り分けることができます。コミットの順序を変更することも可能です。この方法は、一部の変更をどこかへやってしまいたい時に便利です。
もう一方のcherry-pickを使うと、持っていきたいコミットを選んでHEADの先にストンと落とすことができます。
git rebase -i main
git rebase -i main コマンドは、Gitリポジトリ内で使用されるコマンドであり、特定のブランチ(ここでは main ブランチ)のコミット履歴をインタラクティブな方法で再構築・編集するために使用されます。このコマンドは「インタラクティブなリベース」を実行するためのものです。
git rebase bugFix main
git rebase bugFix main コマンドは、Gitリポジトリ内で使用されるコマンドであり、特定のブランチ(ここでは bugFix ブランチ)のコミット履歴を別のブランチ(ここでは main ブランチ)の上に再適用(リベース)するために使用されます。
具体的には、bugFix ブランチ上のコミット履歴を、main ブランチ上の最新のコミットに基づいて再適用することを意味します。これにより、bugFix ブランチの変更内容が最新の main ブランチの変更と統合され、クリーンなコミット履歴が保たれます。
コミットをやりくりする
開発中に頻繁に起こるケースをもう1つ考えます。ある変更(newImage)とまた別の変更(caption)があって、それらに依存関係があるとします。この一連の変更が一列に積み重なっているとします。
ここでトリッキーなのは、以前のコミットに対して微修正をかけなければならないケースがあるということです。今回の教材でも、過去のコミットであるにも関わらずnewImageブランチに僅かな修正を加えるような設計の修正が入ったとしましょう。
この困難な状況を、以下の手順で克服することを考えます:
- git rebase -iを使って順番を変更する。これで、変更をかけたいコミットを一番先頭に持ってくる。
- git commit --amendコマンドで僅かな変更を行う
- git rebase -iコマンドを再度使って、先頭に持ってきていたコミットを元に戻す
- 最後に、レベルクリアのためにmainブランチを先頭に持ってくる
git rebase -i HEAD~2
git commit --amend
git rebase -i HEAD~2
git rebase caption main
コミットをやりくりする その2
前回見てきたように、コミット順序の変更のために、私たちはrebase -iコマンドを利用しました。ツリーの先頭に変更対象のコミットがあれば、--amendオプションを使うことで容易に変更を書きかえて、元の順序に戻すことができます。
この場合に心配なことが一つだけあって、それは複数回の順序の変更が行われるので、rebaseのコンフリクト(衝突)が起こりうることです。こういうケースへの対策として、git cherry-pickを使った別の解決法について考えてみましょう。
git checkout main
git cherry-pick C2
git commit --amend
git cherry-pick C3
Gitのタグ
ブランチのように参照でき、「マイルストーン(標識)」のような確かで永久的な印をコミットにつけます。
重要なことは、コミットを新たに作ってもタグは動かないということです。あなたは、タグにチェックアウトしてそのタグで作業を完了させるということはできません -- タグは、コミットツリーの特定の地点を指定する錨のようなものとして機能します。
git tag v1 side~1
git tag v0 main~2
git checkout v1
Git Describe
タグは、ソースリストの優秀な「アンカー(標識)」として作用するので、Gitには最も近く関係のある「アンカー」(タグの別名)を記述するためのコマンドがあります。そして、そのコマンドはgit describeと呼ばれています!
Gitのdescribeは、あなたが大量のコミットの中を移動するとき、今どこにいるかを知るのを助けてくれます(このような状況は、例えばあなたがデバッグ検索コマンドの一つgit bisectを走らせ終わった後や、同僚が休暇から帰ってきて自分の席に座るときに起こります)。
Gitのdescribeは、以下の形式をとります:
git describe <参照>
<参照>には、Gitが解釈可能なコミットの参照表現(ブランチやタグの指定、コミットハッシュなど)をいれます。もし、何も入力しなかった場合、Gitは現在の位置のコミット(HEAD)を使います。
コマンドの結果は以下のようになります:
<タグ>_<コミット数>_g<ハッシュ>
<タグ>には履歴の一番最新のタグ名が、<コミット数>にはそのタグから幾つのコミットがあったか、<ハッシュ>はそのコミットのハッシュがそれぞれ入ります。
[ 練習 ]
git commit
複数のブランチをリベースする
いくつものブランチが出てきます。このブランチたち全てをmainブランチにリベースしましょう。
おエライさん方が今回の仕事を少しトリッキーにしてくれました -- コミットはすべて一列の連続した状態にしてほしいそうです。つまり私たちが作るリポジトリの最終的なツリーの状態は、C7'が最後に来て、C6'がその一つ上に来て、、と順に積み重なるイメージです。
git rebase main bugFix
git rebase bugFix side
git rebase side another
git rebase another main
親の指定
~修飾子と同じように、^修飾子も後に任意の番号を置くことができます。
指定した数だけ遡る(これは~の場合の機能)のではなく、^はマージコミットからどの親を選択するかを指定できます。マージコミットは複数の親で構成されるので、選択する経路が曖昧であることを覚えておいてください。
Gitは通常、マージコミットから「一つ目」の親、マージされた側のブランチの親を選びます。しかし、^で数を指定することでこのデフォルトの動作を変えることができます。
git branch bugWork main^^2^
git branch: これは、ブランチの作成、表示、切り替えなどを行うコマンドです。
bugWork: これは新しく作成されるブランチの名前です。bugWorkという名前のブランチが作成されることを意味します。
main^^2^: これはコミットの指定方法です。ここでは「main」ブランチの指定コミットに対する相対的な位置を示しています。
main ブランチの最新のコミットを main^ と表現します。つまり、1つ前のコミットを指します。
main^2 は、main ブランチの1つ前のコミットの親コミットを指します。つまり、2つ前のコミットを示します。
つまり、main ブランチの2つ前のコミットの親コミットを指定しています。
したがって、git branch bugWork main^^2^ コマンドは、以下の操作を行います:
main ブランチの2つ前のコミット(main^^2^)を基にして、新しいブランチ bugWork を作成します。新しいブランチには、2つ前のコミットの変更内容が含まれます。
これにより、新しい bugWork ブランチが作成され、そのブランチには main ブランチの2つ前のコミットの内容がコピーされた状態で開始されることになります。通常、このような操作は、バグ修正などの作業を別のブランチで行う際に使用されます。
ブランチスパゲッティ
git checkout one
git cherry-pick C4 C3 C2
git checkout two
git cherry-pick C5 C4 C3 C2
git branch -f three C2
git branch: これは、ブランチの作成、表示、切り替えなどを行うコマンドです。
-f: これは「force」の略で、このオプションを使うとブランチを強制的に指定したコミットに移動させることができます。通常、ブランチを移動させる際には、コミットの履歴を壊さないように注意が必要ですが、このオプションを使用すると強制的に移動させることができます。
three: これは移動させたいブランチの名前です。ここでは、three ブランチを指定しています。
C2: これは移動先となるコミットのハッシュ値またはコミット名です。ここでは、C2 というコミットを指定しています。
つまり、git branch -f three C2 コマンドは、以下の操作を行います:
既存の three ブランチを、指定したコミット C2 に強制的に移動させます。この操作により、three ブランチは指定したコミットに関する履歴を持つようになります。コミットの履歴が変更されるため、他の人と共有している場合は慎重に使用する必要があります。通常は、コミット履歴を壊さずにブランチを移動させる方法を検討する方が良いですが、特定の状況下でこのコマンドを使用することがあります。