#topicpath
----

http://kray.jp/blog/git-why-explanation/
http://www.backlog.jp/git-guide/stepup/stepup2_1.html

#contents

Gitは ローカルでのコミットやリモートへのプッシュ・プル、ブランチのマージやナントカカントカなどいろいろとややこしい仕組みがあります。とりあえず自分の理解のために、まずはリモートを使わないローカルでの操作を整理してみました。おもにリポジトリの作成からコミット、マージまでを整理しました。



** Gitを始める [#qac54eb8]
$ mkdir tutorial && cd $_
$ git init
Initialized empty Git repository in /Users/masatomix/git/tutorial/.git/
$ echo "master added" >> file1.txt
$ cat file1.txt
master added
$ git add file1.txt
$ git commit -m "master commit"
[master (root-commit) 25c2961] master commit
 1 file changed, 1 insertion(+)
 create mode 100644 file1.txt
$ echo "2 master added" >> file1.txt
$ cat file1.txt
master added
2 master addedgit 
$ git add file1.txt
$ git commit -m "2 master commit"
[master ad0dac1] 2 master commit
 1 file changed, 1 insertion(+)
 $ mkdir tutorial && cd $_
 $ git init
 Initialized empty Git repository in /Users/masatomix/git/tutorial/.git/

 $ echo "master added" >> file1.txt
 $ cat file1.txt
 master added
 $ git add file1.txt
 $ git commit -m "master commit"
 [master (root-commit) 25c2961] master commit
  1 file changed, 1 insertion(+)
  create mode 100644 file1.txt

 $ echo "2 master added" >> file1.txt
 $ cat file1.txt
 master added
 2 master addedgit 
 $ git add file1.txt
 $ git commit -m "2 master commit"
 [master ad0dac1] 2 master commit
  1 file changed, 1 insertion(+)

addしてcommitの繰り返しです。コミットまでできました。



** ブランチを作成する [#s0954705]
ブランチを作成します
$ git checkout  -b dev   ←作成と移動。作成だけなら git branch dev でいい
Switched to a new branch 'dev'
$ git branch
* dev [#h881c414]
  master
 $ git checkout  -b dev   ←作成と移動。作成だけなら git branch dev でいい
 Switched to a new branch 'dev'
 $ git branch
 * dev [#h881c414]
   master

ローカルのワーキングツリーがdevになりました。この時点で、masterとdev それぞれはおなじリビジョンにいることになります。

01.png
#ref(01.png)

devに存在するファイルを修正して、コミットします。

$ echo "dev modified" >> file1.txt
$ git add file1.txt
$ git commit -m "dev commit"
[dev 3f7af4f] dev commit
 1 file changed, 1 insertion(+)
$
 $ echo "dev modified" >> file1.txt  && git add file1.txt && git commit -m "dev commit"
 [dev 3f7af4f] dev commit
  1 file changed, 1 insertion(+)

02.png
#ref(02.png)

画面イメージを見て分かるとおり、devだけひとつリビジョンが進んでいますね。
上記のキャプチャを見て分かるとおり、devだけひとつリビジョンが進んでいますね。


** ブランチのマージ [#c7877d94]
さて、devで修正した内容をmasterにマージします。マージとはようするに、ローカルのワーキングツリー上のブランチに、他のブランチの修正を反映させることです。
修正反映させたいブランチへ移動して、他のブランチを指定して下記コマンドを実行します。
さて、devで修正した内容をmasterにマージします。マージとは、ローカルのワーキングツリー上のブランチに他のブランチの修正を反映させることです。
修正を反映させたいブランチへ移動して、他のブランチを指定してマージのコマンドを実行します。

$ git checkout master
Switched to branch 'master'
$ git merge dev
Updating ad0dac1..3f7af4f
Fast-forward
 file1.txt | 1 +
 1 file changed, 1 insertion(+)
$ git branch
  dev
* master [#fbf5598a]
 $ git checkout master
 Switched to branch 'master'
 $ git merge dev
 Updating ad0dac1..3f7af4f
 Fast-forward
  file1.txt | 1 +
  1 file changed, 1 insertion(+)
 $ git branch
   dev
 * master [#fbf5598a]

今回は masterブランチにdevブランチをマージしました。ただmasterはなにもコミットがされていなかったので、ただ単に、masterブランチのリビジョンがdevに進んだだけのようですね。(Fast-forwardという)
03.png
今回は masterブランチにdevブランチをマージしました。ただmasterについてはdevを作成後、コミットがされていなかったので、ただ単にmasterブランチのリビジョンがdevのリビジョンに進んだだけのようですね。これを早送りするって意味でFast-forwardなマージというようです。

#ref(03.png)

** Fast-forwardでないマージ [#nc334ab4]
masterブランチからdevブランチを作成後、masterが別のブランチをマージしたことで先に進んで場合を考えます。この場合はdevブランチの修正はをmasterにマージする際、単純なFast-forwardにすることはできないはずですね。
masterからdevを作成後、たとえばmasterが別のブランチをマージして先に進んでいる場合を考えます。この場合はdevの修正をmasterにマージする際、単純なFast-forwardにすることはできないはずですよね。どうなるかやってみます。

 $ git checkout -b dev2
 Switched to a new branch 'dev2'
 $ echo "dev2 added " >> file2.txt && git add file2.txt && git commit -m "dev2 commit"
 [dev2 134e253] dev2 commit
  1 file changed, 1 insertion(+)
  create mode 100644 file2.txt

$ git checkout -b dev2
Switched to a new branch 'dev2'
$ echo "dev2 added " >> file2.txt
$ git add file2.txt
$ git commit -m "dev2 commit"
[dev2 134e253] dev2 commit
 1 file changed, 1 insertion(+)
 create mode 100644 file2.txt
$ git checkout master
Switched to branch 'master'
$ git merge dev2
Updating 3f7af4f..134e253
Fast-forward
 file2.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 file2.txt
 $ git checkout master
 Switched to branch 'master'
 $ git merge dev2
 Updating 3f7af4f..134e253
 Fast-forward
  file2.txt | 1 +
  1 file changed, 1 insertion(+)
  create mode 100644 file2.txt
 
さあdev2を使って、masterのリビジョンを少し進めました。

masterを少し進めました。
#ref(04.png)

04.png
続いて、devも独自にリビジョンをすこしだけ進めておきます。

さあ、dev2でコミットしたファイルをマージしたmasterに対して、devの修正を反映してみます。
 $ git checkout dev
 $ echo "dev added " >> file1.txt  && git add file1.txt && git commit -m "2 dev commit"
 [dev 3f7a1ef] 2 dev commit
  1 file changed, 1 insertion(+)

$ echo "dev added " >> file1.txt  && git add file1.txt && git commit -m "2 dev commit"
[dev 3f7a1ef] 2 dev commit
 1 file changed, 1 insertion(+)
#ref(05.png)

05.png
上記キャプチャで分かるとおり、masterとdev2はおなじ場所にいます。dev はmasterの一個前(?)から派生していて、独自の進化をしています。さあ派生したdevの修正をmasterに反映してみます。

いきます
 $ git checkout  master
 Switched to branch 'master'
 $ git merge dev
 Merge made by the 'recursive' strategy.
  file1.txt | 1 +
  1 file changed, 1 insertion(+)

$ git checkout  master
Switched to branch 'master'
$ git merge dev
Merge made by the 'recursive' strategy.
 file1.txt | 1 +
 1 file changed, 1 insertion(+)
#ref(06.png)

06.png
新しいコミットがひとつ実行され、Fast-forwardでないやり方で、ファイルがマージされました((今回devでのコミットは一回でしたが、複数回の場合も、それらをまとめた一つのコミットが実行されます))。

今回はFast-forwardではないのでコミットメッセージを入れるダイアログが出たと思いますが、
  $ git merge dev -m "Merge branch dev" 
などとすればメッセージは表示されません。。

新しいコミットが実行され、Fast-forwardでないやり方で、ファイルがマージされました。
最後にdevをmasterまで進めて、完了です。

 $ git checkout dev
 $ git merge master
 Updating 3f7a1ef..56f88d1
 Fast-forward
  file2.txt | 1 +
  1 file changed, 1 insertion(+)
  create mode 100644 file2.txt

masterとdevはおなじ状態になりました。

#ref(07.png)

**まとめ [#g81261ad]
このように、あるブランチの修正をマージする場合、そのまま直列に後ろにつなげばよい場合は、Fast-forwardというやり方でブランチの内容が反映されることが分かりました((というか自分がただ進むだけということでしょうか))。また自分が別のコミットやマージによって、単純に早送りするだけではダメな場合、他ブランチの修正を反映させたコミットを新たに作成することで、マージ処理が行われることが分かりました。

最後にdevをmasterまで進めて、完了です。
それらの修正がコンフリクトしない場合、gitが正しくマージ処理をしてくれます。かしこいです。おなじファイルをいじっているなど、単純なマージで廃家内場合は人間が競合を取り除くコミットを手動で行うことで、マージ処理を行います。それについてはこちらに詳しく書いてありますのでそちらをご参照のこと。

$ git checkout dev
$ git merge master
Updating 3f7a1ef..56f88d1
Fast-forward
 file2.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 file2.txt
[[6. マージでの衝突を解決する>http://www.backlog.jp/git-guide/stepup/stepup2_7.html]]

masterとdevはおなじ状態になりました。
** さいごに、リベースってなんだ [#zb00c773]
別のブランチの修正をマージするにあたって
 $ git checkout dev
 $ git merge  master
とやることで、devブランチにmasterブランチの修正を反映させることができるのでした。便宜上、マージがさっきの逆のパタンになっているのはご愛敬。。

07.png
#ref(08.png)

さてgit には リベースという概念があります。これはマージが「いまのdevの状態に対して、masterのコミットをまとめた内容をコミットすることで反映する」のに対して「いまのdevの状態(コミット履歴)を待避しておいて、枝分かれしたところへ戻りそこからmasterの修正内容をdevに反映し、そのあと待避していたコミット履歴を新たにコミットする」機能のようです。

 $ git checkout dev
 $ git rebase master
 First, rewinding head to replay your work on top of it...
 Applying: dev commit     <- 3fc335e として新たにコミットされてる!
 Applying: dev commit     <- 9210c21 として新たにコミットされてる!
 Applying: dev commit     <- 09a6a5a として新たにコミットされてる!

#ref(09.png)

このように、devのコミットがいったん待避されて((rewinding。巻き戻し))、masterの修正がdevに反映され((そして、これはきっとFast-forward))、んで「あらたな」コミットとして、待避していた内容がコミットされることが分かりました。

画面キャプチャからもわかるとおり、修正履歴が一直線となり見やすくなるにはなるのですが。。ココではリモートへのpushの件は出てきませんが、リモートへpush済みのブランチを、それより前のリビジョンからrebaseした場合、巻き戻し&再コミットによってリモートとの不整合が発生するので、そんなケースではやってはいけないようです。

[[こわくない Git>http://www.slideshare.net/kotas/git-15276118]]のP.143 に詳しく書いてあります。




**関連リンク [#z8b7d3a5]
-[[Git初心者に捧ぐ!Gitの「これなんで?」を解説します。 | KRAY Inc>http://kray.jp/blog/git-why-explanation/]]
-[[サルでもわかるGit入門 〜バージョン管理を使いこなそう〜>http://www.backlog.jp/git-guide/stepup/stepup2_1.html]]

-[[Git の疑問。トピックブランチで作業中に、master ブランチで重要な変更が加えられた。どうすればよい?>http://blog.inouetakuya.info/entry/20130602/1370173582]] ココのSlideShare めちゃくちゃわかりやすい。必読。


----
この記事は
#vote(おもしろかった,そうでもない)

#comment

#topicpath

SIZE(10){現在のアクセス:&counter;}


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS