Re:ゼロから始めるGit生活

#はじめに
いつもどおり自分用のメモです。
Gitのことあまり理解してないのでそんな人にはいいかもしれない。

#Gitについて
バージョン管理システム。ソフトウェア構成管理や、ソースコード管理を行うソフトウェアのこと。
SVNと違ってGitはリポジトリを維持するサーバーは必須ではない。
つまりローカルな環境でローカルなファイルのみを使って管理をすることが可能。



Gitにはリポジトリーと作業コピーとの間に、
**インデックス**
変更したファイルやディレクトリを登録するところ
**ステージ**
特定の変更内容をindexに登録し、次回のコミットに含めるようGitに指示するところ
**キャッシュ**
と呼ばれる中間的な層が存在する。

↓追記：訂正
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a href="https://twitter.com/CST_negi">@CST_negi</a> うーんと、インデックスとステージとキャッシュは基本的に全部同じ物をさしてます。この辺の用語が混乱してるのは実際イマイチなんだけど……。 staging area = index ≒ staged (files) ≒ cached (files) なのでご注意を</p>&mdash; ぐる (たまご) (@gull08) <a href="https://twitter.com/gull08/status/725612993652772865">2016年4月28日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
#プロジェクトの基本的な流れ
↓以上をふまえて基本的な初期の流れ
**1.リポジトリーの初期化**
git config で自分の名前とかメールアドレスとかを設定しておく。
リポジトリにしたいディレクトリを作ってgit initする。
**2.コミット対象のファイルを追加**
git add ファイル名
これによってGitの対象になるので、UntrackedFileには出てこなくなる。
**3.変更の確定**
git commit -m "Init Commit"のような感じでメッセージ付きでコミットする。
**あとは2,3の繰り返し…**




#Gitコマンドラインインタフェース(初期) 
**git config：**
コマンド環境設定
**git init:**
リポジトリの初期化
→最初にやること
**git add:**
インデックスへの追加
→git add .とかする。
**git commit:**
インデックスへのコミット
→git commit -m ""でメッセージを付加する。
**git log:**
リポジトリーの変更ログの表示→これまでのコミットログが見られる。
**git diff:**
特定のリビジョンとの差分の表示
**git status:**
状態の確認→UntrackedFileとかあったら表示される。

#Gitの管理対象から外したいファイルの指定：.gitignore
Unityの.unityとか、Temp/とかいろいろ管理したくない場合あると思います。
この場合例えば

```(ex).gitignore
#Sceneファイル
*.unity
#Tempフォルダ
Temp/
```
みたいな感じで書いておけばOK。Unity用.gitignoreに関して詳しくは以下
参考： http://qiita.com/nariya/items/97afba6b7b448920cdf0

#取り消し・リセット
##check out
`git checkout test.txt`のように使う
開発を進めていく過程で元の状態に戻りたい場合とか出てくるかも…

コミット後にファイルを引き出して作業ツリーに展開するコマンド
→コミットされた最新の状態からやり直すことを意味する。
（AddもCommitもしていなければCheckoutで戻せる）



##commit --amend
`git commit --amend -a -m "changed Message"`
のように使う。
働きとしては直前のコミットを置き換えるというもの

##reset
**通常Reset**
コミット情報を削除するが、作業ツリーは維持される。
`git reset HEAD-2`
のように使う（2つ前のコミットにリセットするという意味）
**HardReset**
コミット情報を削除して、作業ツリーもその状態に合わせる。基本的にこっちのがResetって感じがする。
`git reset --hard HEAD^^`
のように使う(2つ前のコミットにリセットしてその当時の作業ツリーにする。)

reset --hardは環境が壊れたとか、今やってる作業いらんなってなった時に使う感じがする。

##blame/revert
Resetと異なり、コミットの履歴自体を削除することはない。
その代わり、特定のコミットで行われた変更をなかったコトにするために役立つやつ。

git blameは以下のように、それぞれの行がどのコミットによって作られたかを調べる便利コマンド

```(ex).gitblame
[root@localhost myproject]# git blame test.txt
^4e911e6 (negipoyoc 2016-04-28 15:52:00 +0900  1) Hello Git.
394a53db (negipoyoc 2016-04-28 15:58:25 +0900  2) test
92982477 (negipoyoc 2016-04-28 16:04:18 +0900  3) commit

```

こうして得たハッシュ値を元に
`git revert 394a53db`のように使う。
(基本的にコンフリクトが発生するけど、発生しない場合は指定したコミットが取り消された状態でコミットを行う。)

コンフリクトが発生するとコミットには至らず、自力でコンフリクトを解消しに行くことになる。

**rebase(難しい)**
コミット履歴を編集するもの
・順番の変更
・コミットメッセージの変更
・コミットの圧縮
・コミットの分割
などいろいろできる。


コミットメッセージの変更を例にやってみる。
まず`git log`でコミット番号を得る。

```(ex).gitlog
[root@localhost myproject]# git log
commit dc2730f6cb677f4fcba602b6b3ba14a777785970
Author: negipoyoc <negi@poyoc.jp>
Date:   Thu Apr 28 16:16:06 2016 +0900

    modify at master

commit 6fddf88e6dbf47a84bb8fbbafe84609e53f96614
Author: negipoyoc <negi@poyoc.jp>
Date:   Thu Apr 28 16:14:06 2016 +0900

    3files add

```

次に変更したいCommitMessageの値をコピーして
`git rebase -i 6fddf88e6dbf47a84bb8fbbafe84609e53f96614`する。(-iはインタラクティブに行うオプション)

するとエディターが起動して、「pick ~~」と書いてあるファイルが開かれるので、
例えばpickをrewordに変更して保存終了する。

すると指定したコミットがHEADBOARDになった無名ブランチ上での作業となる。（重要）
これを利用して

```(ex).gitrebase
git commit --amend -m "rebase Tester"
git rebase --continue
```
とすると、編集画面に戻る。（仮にrewordをrewardのように綴りが間違っていても、`git rebase --edit-todo`すれば前の編集画面に戻ってまた編集できるようになるので心配なし）

その編集画面を終了して`git log`すると…


```(ex).gitlog
commit 851c475ec17395f377b3b455bb80a33d452f5a97
Author: negipoyoc <negi@poyoc.jp>
Date:   Thu Apr 28 16:16:06 2016 +0900

    modify at master

commit 2fe5c0f5ac20fac5cb6b3654c91778bcbfb322a5
Author: negipoyoc <negi@poyoc.jp>
Date:   Thu Apr 28 16:14:06 2016 +0900

    rebase Tester

```

となって、無事メッセージを変更できたことがわかる。


##tag
`git tag tagName`のように使う。（これは現時点でのコミットに対するタグの定義なる。）

例えば`git reset --hard HEAD^^^`したい時に、予め3つ前のコミットに対して"vol.03"というタグをつけておけば`git reset --hard vol.03`というようになる。

必須でにはないけど単純に便利ということ。


#ブランチ
Gitではデフォルトでmasterというブランチ上で作業を行っている。また、別のブランチを作れる。それの説明。

##ブランチの作成
ブランチを作成するには、branchコマンドを使用する。

```(ex).gitbranch
$git branch testBranch

$git branch
  testBranch
 *master
```
→現在の作業ブランチがmasterであることを示している。

##作業ブランチの切り替え
切り替えには、git checkoutを行う。

```(ex).gitbranch
$git checkout testBranch

$git branch
 *testBranch
  master
```

ちなみに、ブランチを切り替えてコミットしても別のブランチには反映されない。(当たり前)

##マージ
masterとtestBranchでお互いいろいろな変更をしました。
その上でtestBranchでの変更をmasterにマージするには`git merge`をする。

```(ex).gitmerge
$git checkout master 
(↑まずmasterに行く)

$git merge experimental
(↑で、マージが完了する。)

```
このマージについては、ブランチが持つ履歴もマージされる。
このマージを取り消すには`git reset --hard HEAD^`すればおｋ


#コンフリクト
Gitで一番めんどくさいと思ってるコンフリクトについて

マージが問題なく動作するのは変更にコンフリクトが無いため。例えば同一のオブジェクトに対して異なる変更を加えた場合コンフリクトが発生する。
※予め言っておくとコンフリクトの解消を誰がどのように行うかは、そのプロジェクトによる。



`git checkout master`
`git merge testBranch`後にコンフリクトが起きると下のような画面に成る

```(ex).conflict
[root@localhost myproject]# git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add <file>..." to mark resolution)

	both modified:   test.txt

```

肝心のtest.txtの中身というと

```(ex).confilict
[root@localhost myproject]# cat test.txt 
Hello Git.
<<<<<<< HEAD
modify #1
test
=======
>>>>>>> parent of 6ae3fba... modified MessageV
```
のようになっている。

これは
masterでは
「modify #1
test」
と書いてあったものをtestBranchでは削除している様子である。
(=======で区切られている。)


これをエディタなどを使って直して解消を完了させる。(ここは手動です。)


最後に

```(ex).conflict
$ git add .
$ git commit -m "resolve conflict"
```
として、コミットしてコンフリクトを解消するという流れ。
コンフリクトを理解しておくと怖さが減って良いね。