3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

git merge やり方 | HEAD | Learn Git Branching

Last updated at Posted at 2023-08-19

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

image.png

用語

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代前の親)を指します。
コミットハッシュを書くよりずっと簡単。
image.png

bugFixの親コミットをチェックアウトするには

git checkout bugFix^

2."~" 演算子
コミットツリーの中で複数の段階上へ移動したいときに使う。チルダ演算子のあとには、上へ移動したい親コミットの数を表す数字もオプションでつけられます。

git checkout HEAD~4

image.png

ブランチの強制

相対リファレンスのよくある使い方としてあるのは、ブランチの移動です。-fオプションを使ってブランチを直接コミットに関連付けられます。次のようになります

git branch -f main HEAD~3

mainブランチを(強制的に)HEADより親三代前へと移動します。
image.png
image.png

git branch main C6
git checkout HEAD~1
git branch -f bugFix HEAD~1
   or
git branch -f bugFix C0

image.png

変更を元に戻す 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)の下に一連のコミットをコピーしたいという意を単純に表す方法です。
image.png
image.png

Git インタラクティブrebase

どのコミットを操りたいかがわからない時はgitのインタラクティブrebaseを使えます。rebaseしたい一連のコミットを一括で見るベストな方法です。

インタラクティブrebaseとは単に、rebaseコマンドに-iオプションを合わせて使うことです。

このオプションをつければ、gitがインタフェースを開き、どのコミットがrebase対象の下にコピーされるかを確認できます。それらのコミットのハッシュやメッセージも表示され、rebaseの概要を一眼で見るのに便利です。

インタラクティブrebaseダイアログが開くと、3つの操作から選べます:

  • UIウィンドウのなかで順番を調整するだけでコミットの順番を変えられます(こちらのダイアログでは、マウスでドラッグアンドドロップで操作します)。
  • 特定のコミットを丸ごと除くこともできます。除きたいコミットを指定するにはpickをオフにします。
  • 最後に、コミットを組み合わせられます。技術的に制限があり再現できないのでその詳細な説明を省きますが、短く言いますと、複数のコミットを一つにまとめることができる機能です。
git rebase -i HEAD~4

image.png
image.png
image.png


image.png
image.png

ローカルに積み上がったコミット

実際の開発ではこういうケースがよくあります:「バグの原因調査を試みているがバグの再現性がかなり低い。調査の補助のために、いくつかのデバッグ用の命令やprint文を差し込んでいる。」

これらのデバッグ用のコードはバグ修正用のブランチにコミットされています。そしてついにバグの原因を突き止めて、修正した!やった!

あとはbugFixブランチをmainブランチに統合できればOK。そこで単純にmainをfast-forwardすればよいかというと、それではmainブランチの中にデバッグ用のコードも混入してしまいます。
こでGitの魔法が力を発揮します。解決のためにはいくつかの方法がありますが、最も素直な解決方法は2つあって:

git rebase -i
git cherry-pick

インタラクティブモードの(-iオプションつきの)rebaseによって、保持したいコミットと破棄したいコミットを選り分けることができます。コミットの順序を変更することも可能です。この方法は、一部の変更をどこかへやってしまいたい時に便利です。

もう一方のcherry-pickを使うと、持っていきたいコミットを選んでHEADの先にストンと落とすことができます。
image.png

git rebase -i main 

git rebase -i main コマンドは、Gitリポジトリ内で使用されるコマンドであり、特定のブランチ(ここでは main ブランチ)のコミット履歴をインタラクティブな方法で再構築・編集するために使用されます。このコマンドは「インタラクティブなリベース」を実行するためのものです。

image.png

git rebase bugFix main

git rebase bugFix main コマンドは、Gitリポジトリ内で使用されるコマンドであり、特定のブランチ(ここでは bugFix ブランチ)のコミット履歴を別のブランチ(ここでは main ブランチ)の上に再適用(リベース)するために使用されます。

具体的には、bugFix ブランチ上のコミット履歴を、main ブランチ上の最新のコミットに基づいて再適用することを意味します。これにより、bugFix ブランチの変更内容が最新の main ブランチの変更と統合され、クリーンなコミット履歴が保たれます。

image.png

コミットをやりくりする

開発中に頻繁に起こるケースをもう1つ考えます。ある変更(newImage)とまた別の変更(caption)があって、それらに依存関係があるとします。この一連の変更が一列に積み重なっているとします。

ここでトリッキーなのは、以前のコミットに対して微修正をかけなければならないケースがあるということです。今回の教材でも、過去のコミットであるにも関わらずnewImageブランチに僅かな修正を加えるような設計の修正が入ったとしましょう。
この困難な状況を、以下の手順で克服することを考えます:

  • git rebase -iを使って順番を変更する。これで、変更をかけたいコミットを一番先頭に持ってくる。
  • git commit --amendコマンドで僅かな変更を行う
  • git rebase -iコマンドを再度使って、先頭に持ってきていたコミットを元に戻す
  • 最後に、レベルクリアのためにmainブランチを先頭に持ってくる

image.png

git rebase -i HEAD~2

image.png
image.png

git commit --amend

image.png

git rebase -i HEAD~2

image.png

git rebase caption main

image.png

コミットをやりくりする その2

前回見てきたように、コミット順序の変更のために、私たちはrebase -iコマンドを利用しました。ツリーの先頭に変更対象のコミットがあれば、--amendオプションを使うことで容易に変更を書きかえて、元の順序に戻すことができます。

この場合に心配なことが一つだけあって、それは複数回の順序の変更が行われるので、rebaseのコンフリクト(衝突)が起こりうることです。こういうケースへの対策として、git cherry-pickを使った別の解決法について考えてみましょう。
image.png
image.png

[練習]
image.png

git checkout main
git cherry-pick C2

image.png

git commit --amend

image.png

git cherry-pick C3

image.png

Gitのタグ

ブランチのように参照でき、「マイルストーン(標識)」のような確かで永久的な印をコミットにつけます。
重要なことは、コミットを新たに作ってもタグは動かないということです。あなたは、タグにチェックアウトしてそのタグで作業を完了させるということはできません -- タグは、コミットツリーの特定の地点を指定する錨のようなものとして機能します。
image.png
image.png

[練習]
image.png

git tag v1 side~1

image.png

git tag v0 main~2

image.png

git checkout v1

image.png

Git Describe

タグは、ソースリストの優秀な「アンカー(標識)」として作用するので、Gitには最も近く関係のある「アンカー」(タグの別名)を記述するためのコマンドがあります。そして、そのコマンドはgit describeと呼ばれています!

Gitのdescribeは、あなたが大量のコミットの中を移動するとき、今どこにいるかを知るのを助けてくれます(このような状況は、例えばあなたがデバッグ検索コマンドの一つgit bisectを走らせ終わった後や、同僚が休暇から帰ってきて自分の席に座るときに起こります)。

Gitのdescribeは、以下の形式をとります:

git describe <参照>

<参照>には、Gitが解釈可能なコミットの参照表現(ブランチやタグの指定、コミットハッシュなど)をいれます。もし、何も入力しなかった場合、Gitは現在の位置のコミット(HEAD)を使います。

コマンドの結果は以下のようになります:

<タグ>_<コミット数>_g<ハッシュ>

<タグ>には履歴の一番最新のタグ名が、<コミット数>にはそのタグから幾つのコミットがあったか、<ハッシュ>はそのコミットのハッシュがそれぞれ入ります。
image.png

image.png

[ 練習 ]

image.png

git commit

image.png

複数のブランチをリベースする

いくつものブランチが出てきます。このブランチたち全てをmainブランチにリベースしましょう。

おエライさん方が今回の仕事を少しトリッキーにしてくれました -- コミットはすべて一列の連続した状態にしてほしいそうです。つまり私たちが作るリポジトリの最終的なツリーの状態は、C7'が最後に来て、C6'がその一つ上に来て、、と順に積み重なるイメージです。
image.png

git rebase main bugFix

image.png

git rebase bugFix side

image.png

git rebase side another

image.png

git rebase another main

image.png

親の指定

~修飾子と同じように、^修飾子も後に任意の番号を置くことができます。

指定した数だけ遡る(これは~の場合の機能)のではなく、^はマージコミットからどの親を選択するかを指定できます。マージコミットは複数の親で構成されるので、選択する経路が曖昧であることを覚えておいてください。

Gitは通常、マージコミットから「一つ目」の親、マージされた側のブランチの親を選びます。しかし、^で数を指定することでこのデフォルトの動作を変えることができます。
image.png
image.png

二つ目の親を指定(C2に移動)
image.png
image.png

image.png
一つ上がって、C5の親に行き、二つさかのぼる
image.png

image.png
image.png

[練習]
image.png

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つ前のコミットの内容がコピーされた状態で開始されることになります。通常、このような操作は、バグ修正などの作業を別のブランチで行う際に使用されます。

image.png

ブランチスパゲッティ

image.png

git checkout one

image.png

git cherry-pick C4 C3 C2

image.png

git checkout two

image.png

git cherry-pick C5 C4 C3 C2

image.png

git branch -f three C2

git branch: これは、ブランチの作成、表示、切り替えなどを行うコマンドです。

-f: これは「force」の略で、このオプションを使うとブランチを強制的に指定したコミットに移動させることができます。通常、ブランチを移動させる際には、コミットの履歴を壊さないように注意が必要ですが、このオプションを使用すると強制的に移動させることができます。

three: これは移動させたいブランチの名前です。ここでは、three ブランチを指定しています。

C2: これは移動先となるコミットのハッシュ値またはコミット名です。ここでは、C2 というコミットを指定しています。

つまり、git branch -f three C2 コマンドは、以下の操作を行います:

既存の three ブランチを、指定したコミット C2 に強制的に移動させます。この操作により、three ブランチは指定したコミットに関する履歴を持つようになります。コミットの履歴が変更されるため、他の人と共有している場合は慎重に使用する必要があります。通常は、コミット履歴を壊さずにブランチを移動させる方法を検討する方が良いですが、特定の状況下でこのコマンドを使用することがあります。
image.png

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?