Gitについての備忘録


先日サブモジュールを扱って色々躓いたので、これを機にgitについて勉強してみました。何番煎じか分からない備忘録です。
※[Pro Git](http://git-scm.com/book/ja/v1)の内容を自分向けに整理したものです。

# 概要

- gitはsvnのような差分管理ではなく、ファイル単位で管理されている。
- git cloneは最新のコミットのみではなく、過去のコミットを含む全てをクローンする（一部のフックなどを除く）。
- ファイルの状態には、大別して、gitの管理状態を意味するtrackedファイルと管理外のuntrackedファイルがある。
- trackedファイルの状態には,unmodified, staging, modifiedがある。
- stagingのファイルがコミット対象になる。

# 基本

## ファイルを追跡対象にしたりstaging状態にする

例１

```bash
git add a.c # そのファイルをstaging状態にする。

git add . # dir(この場合./)を指定するとそのディレクトリを再帰的に追加する。
```

```bash
git add a.c # a.cをstaging状態にする。
vim a.c # 何か編集する。 a.cはmodified状態になる。
        # この時点でcommitしても、staging状態がコミットされる。
git add a.c # a.cがstaging状態になる。
git commit -a # 未stagingをstaging状態にして、commitする。通常はこちら
```

## staging状態をmodified状態に戻す

```bash
git reset HEAD filename
```

## 変更した内容を直近のコミットの内容に戻す

```bash
git checkout -- filename
```


## 差分を表示する

```bash
git diff # 作業ディレクトリの内容とstaging状態の差を表示する。
git diff --staged # staging状態と直近のコミットとの差を表示する。
git diff --check で空白等の余計な文字を(X)で教えてくれる。
```

## コミットする

```bash

git commit # -mを指定しない場合、環境変数$EDITORで登録された
           # エディタが起動され、コメント入力できる。

git commit --amend # 直近のコミットに対して上書きする。
                   # 直近のコミットにコメントを上書きしたり、変更を追加できたりする。
```

## ファイルを削除する

```bash
git rm file
```

## ファイルを移動する

```bash
git mv from to
#上記は、以下のショートカット
mv from to
git rm from
git add to
```

## 作業状態を一時的に隠す

```bash
git stash # 現在の作業ファイル等をスタックに記録し、直近のコミット状態に戻す。

git stash list # 一覧の表示

git stash apply # 直近のstash状態を復元する.ただしstagin状態は戻らない.
                # stackの内容は消えない。
git stash apply --index # sgit stash applyに加えtaging状態も戻す。

git stash drop # 直近のスタックを削除する。

git stash pop # 直近のstash状態を復元して、スタックから削除する.

git stash show -p | git apply -R # 直近のstash applyを戻す。
# git config --global alias.stash-unapply '!git stash show -p | git apply -R'しておくと良い。

git stash branch branch-name # stashで隠した作業ディレクトリから新しいブランチを作成する。
```


# リモート操作

```bash
git remote # リモート名の一覧を確認できる。
git remote -v # 名前に対応するURLも表示する。


git remote add remote-name repository-url # リモートリポジトリ追加

git remote show remote-name # リモートの詳細表示

git fetch remote-name # リモートリポジトリの情報を取得するのみで、ローカルリポジトリの内容は変更されない。

git pull # リモートの状態を取得して、ローカルリポジトリにマージする。

git push remote-name repository-url # リモートへローカルリポジトリの内容を更新する。

git remote rm remote-name # リモートの設定を削除する
```


# タグ

```bash
git tag # 一覧表示
git tag -l 'v1.*' # 検索

git show tag-text # タグの詳細を表示する

git tag -a tag-text -m "comment" # 注釈付き(現在のスナップショットの複製を作る)

git tag version # 軽量タグ(branchを作る)
```

## リリース用のタグ付け

```
git tag -s v1.5 -m "comment"

git describe # ビルド番号を自動生成する.

git archive master --prefix=my_project/ # アーカイブファイルを生成する。
```

# ブランチ

- HEADポインタは、参照しているコミットのスナップショットを指す。

## ブランチの作成

```bash
git branch branchname# 作成するだけ。切り替えない。
```

## ブランチの一覧表示

```bash
git branch
git branch -v # 直近のコミットログを確認
git branch --merged # マージされたブランチの一覧を確認する。
git branch --no-merged # 未マージの一覧を確認する。
```

## ブランチを切り替える

- ブランチの変更は、作業中のファイルやstaginファイルがある場合できない。

```
git checkout branch-name # HEADをbranch-nameを差し替えて、作業ディレクトリをそのブランチのスナップ状態に戻す。

git checkout -b new-branch-name # 新しいブランチを作成して、HEADをそれに切り替える。
```

## ブランチのマージ

- マージ元が直接マージ先に到達できるときは、fast-forwardといい、HEADのの位置を差し替えるだけ.
- 複数のブランチがマージされる場合、自動的に新しいスナップショットを作成して、コミットする。

```bash
git merge branch-name # 現在のブランチにbranch-nameのブランチ内容をマージする。
```

## ブランチの削除

```bash
git brach -d branch-name
```

## コンフリクトした場合

```bash
git status # コンフリクトしたファイルの確認。解決していないファイルは、unmanagedとして表示される。
vim filename # コンフリクトしたファイルを編集する。
             #<<<<<<<<< ======== >>>>>>>のコンフリクト部分を編集して、望むの状態にする。
git add filename # コンフリクトの解決済みにする。
git commit
```

```bash
git mergetool # 外部のマージツールでマージ作業を行う
```

# リモートブランチ

- ブランチ名は、remote-name/branch-name。

## リモートブランチの情報を取得する
```bash
git fetch origin # リモートブランチの情報をローカルに取得する。（取得するだけ）
```

## リモートブランチへ変更を通知する

```bash
git push # git push remote-name from-branchname:to-branchnameの省略計
```

## リモートブランチをチェックアウトする

```sh
git checkout -b local-branch-name remote-name/branch-name # ローカル名local-branch-nameでリモートのブランチをチェックアウトする。
```

## リモートブランチを削除する

```bash
git push remote-name :bracn-name
```

# マージ(rebase/merge)

- 公開リポジトリにpushしたブランチへのrebaseはダメ。

## 基本形

```bash
git checkout branch_b
git rebase master # branch_bの内容がmasterにマージされて、branch_bのスナップショットは、masterのリビジョンに移動する。
                  # ただしbranchはbranch_bのまま。

git checkout master
git merge branch_b # これでmasterにbranch_bの内容を反映する。
```
## --onto

```bash
git rebase --onto master branch_a branch_b # branch_bの変更と、branch_bに関連するbranch_aの変更をmasterに反映して、branch_bのmaster上に移動する。
      #ただしbranchはbranch_bのまま

git checkout master
git merge branch_b # これでmasterにbranch_bの内容を反映する。
```

```bash
git log --no-merges remote-name/branch-name ^local-branch # masterからlocal-branchの間に、マージが必要なブランチを表示する
```

# 分散作業

## プルリクエスト

```bash
git request-pull remote-name/branch-name local-branch-name # プルリクエストする
```

## 複数のコミットを１つにしてマージ.

例

```bash
git checkout -b ver2 origin/master
git merge --no-commit --squash local_branch
git commit
git push origin master 
```

## パッチの作成

- diff形式とmbox形式の二つある

```bash
git format-patch # mbox形式のパッチが作成できる。
```

## メールの送信

- gitのconfigファイルでメールの設定が行える。

```bash
git send-email *.patch
```

## パッチの適用

```bash
git apply difffile # git diffからマージする
git apply --check difffile マージできるか確認する。

git am patchfile # format-patch形式のパッチを適用する。
git am -3 patchfile # 3方向マージを行う
git am -i -3 atchfile # 対話的にパッチを行える。
```

## cherry-pick

```bash
git cherry-pick commit-ssh # 特定のコミットを現在のブランチにマージする
```

# コミットの範囲指定

```bash
git log master..my-branch # my-branchから辿れて、masterからは辿れないブランチのログを表示する。

git log origin/master..HEAD # プッシュしようとしているコミットを表示する。
```


```bash
# 次の３つは同じ意味
git log refA..refB
git log ^refA refB
git log revB --not refA
```

```bash
git log master...experiment # どちらからか辿れるコミットが表示される

git log -left-right masterc..branch_name # どちら向きのコミットかを表示する
```

# 歴史の改編

※　あまり使わない事を期待して。

- ログを変えるだけなら git commit --amend
- コミットした内容を消したり、変更するにはgit rebase -i HEAD-3みたいな感じ。

# [サブモジュール](http://git-scm.com/book/ja/v1/Git-のさまざまなツール-サブモジュール)

## サブモジュールの追加

- submodule addすると、.gitmodulesファイルという設定ファイルが作られる。

```bash
git submodule add other-repository # リポジトリ配下に別のリポジトリを含める

git commit # submoduleがaddしたことをコミットする。

```

## サブモジュールを含むリポジトリをcloneする

```bash
git clone repository
git submodule init
git submodule update
```

## サブモジュールの内容をリモートからマージする更新する

- git submodule updateを行うと、サブモジュールに変更がなくても、ローカルの変更を断りなく変更する。
- サブモジュールを親プロジェクトから編集する場合は、git checkout -b tempなど別のブランチを作成した方が変更が失われなくて良い。
- 親プロジェクト内のファイルをサブモジュール化するには、手順が必要。

```bash
git merge origin/master #submoduleのHEADポインタは変わるけど、ファイルは更新されていない。
git submodule update # これでマージされる。	
```

(※ 作成中)

# 便利

## 自動補完

contrib/completionディレクトリにある.git-completion.bashを~/に
コピーすると、少し幸せになれる。

```bash
git config --global alias.co checkout # gitの操作にaliasを作成できる。
git config --global alias.xxx '!git xxx' # !で始めると、外部のコマンドを指定できる。
```

# その他

```bash
git clone url dir # dirにリポジトリをcloneする
```