初心者向けGit操作FAQ


# はじめに
次の操作はなんとなくできるけど、その他が分からない人向けのFAQです。
このあたりが怪しい人は、次の[おすすめの教材は？](#reccomend)で基本を確認してください。

* はじめに`git clone`して、`git pull`, `git add`, `git commit`, `git push`する
* `git branch`, `git checkout`でブランチを操作する
* `git log`, `git status`で状態を確認する

# <span id="reccomend">0. おすすめの教材は？</span>
いろいろありますが、無料でわかりやすい次のサイトがおすすめです。

* [サルでもわかるGit入門](http://www.backlog.jp/git-guide/)
* [Git の基本](https://www.atlassian.com/ja/git/tutorial/git-basics)

次をみるとよく使うものは大体調べられます。

[サルでもわかるGit入門 逆引きGit](http://www.backlog.jp/git-guide/reference/)

# 1. Gitをはじめたばかりの初心者からよく聞かれる質問

## pullできない
よくあるのは、pullしたときに次のメッセージがでる場合です。

```
Please, commit your changes or stash them before you can merge.
```

pullはリモートリポジトリからコードをダウンロード(fetch)して、自分のコードとマージ(merge)する行為です。

```
pull = fetch + merge origin/master
```

commitしていないというのは作業中ということなので、このような操作をすることは本来ありえないはずです。
そのため、gitではcommitしていない状態でpullするとエラーになります。
commitしてからpullしましょう。
commitをしたくないという場合は[stash](#stash)で一時退避すればpullできます。

## マージしていいの？
どこからどこにマージするかが重要です。
masterへのマージは、ローカルで実施しないルールがよくあります。
例えば、[GitLab Flow](https://about.gitlab.com/2014/09/29/gitlab-flow/)の場合、masterへのマージは[マージリクエスト](http://doc.gitlab.com/ce/workflow/merge_requests.html#sts=Merge Requests)で実施します。
その場合は、ローカルで自分のブランチをmasterにマージしてはいけません。

まずは自分がどのブランチいるかを確認しましょう。

```
git status
```

`On branch foo`と表示されれば、fooブランチにいることになります。
この状態で、barをマージしたいのであれば、次のコマンドを実行します。

```
git merge bar
```

## <span id="conflict">競合を解消したい</span>
pullしたときなどに、次のようなメッセージがでているときは、他の人の変更と競合が発生しています。

```
CONFLICT (content): Merge conflict in <file>
Automatic merge failed; fix conflicts and then commit the result.
```

競合しているファイル（<file>部分）を開くと次のように競合している箇所がマーキングされています。

```
<<<<<<< HEAD
## gitlesson1
=======
## lesson1
>>>>>>> 9cb71b3e2bfa1be8b2f5a85d360ffe215a46235b
```

`=======`の上が自分、下が他の人の変更です。
`HEAD`は自分が今使っているブランチの先頭で、`9cb71b3e2bfa1be8b2f5a85d360ffe215a46235b`は他の人の変更のcommit IDです。
この部分を適切に修正して、commitすれば競合が解消されます。
例えば、自分の変更を正とする場合であれば、次のとおりに変更します。

```
## gitlesson1
```

その後、commitします。

```
git commit -m "XXのため発生した競合をYYで解消"
```

# 2. 少し慣れてきた初心者からよく聞かれる質問

## <span id="reload">元に戻したい</span>
### 全体を元に戻したい
全体を元に戻したいときは次のようにします。
※`--hard`は自分の作業領域まで元に戻すオプションで、`--soft`は、作業領域は戻さずにローカルリポジトリだけ元に戻します（[commitを消したい](#delCommit)参照）。

```
git reset --hard
```

特定のcommitポイントまで戻したいときは次のようにします。

```
git reset --hard <commit ID>
```

commit IDは`git log`で確認します。

### 特定のファイルを元に戻したい
あるファイルだけ、直前のcommitまで戻したいときは次のようにします。

```
git checkout <file>
```

特定のcommitポイントまで戻したいときは次のようにします。

```
git checkout <commit ID> <file>
```

<commit ID>は`git log`で確認します。

## 作成済みのブランチを引き継ぎたい
例えば、他の人が作業しているブランチを途中で引き継いで作業する場合には、リモートリポジトリのブランチをローカルリポジトリに持ってくる必要があります。
その場合は、次のようにブランチを作成します。

```
git checkout -b feature/#99 origin/feature/#99
```

`origin/feature/#99`というのが他の人が作成してリモートリポジトリに存在するブランチです。
（originというのがリモートリポジトリを表していますあるのがポイントです。）
ローカルリポジトリに`feature/#99`を作成して、`origin/feature/#99`とひも付けています。

## タグをつけたい
特定のcommitにタグをつける場合は次のようにします。

```
git tag <tag name>
git push --tags
```

タグをつけたところに戻す場合は、次のようにします。

```
git reset --hard <tag name>
```

## 変更を比較したい
直前のcommitと比較する場合は次のようにします。

```
git diff HEAD
```

特定のcommitポイントと比較するときは次のようにします。

```
git diff <commit ID>
```

commit IDは`git log`で確認します。

## <span id="stash">作成中のコードを避難したい</span>
作業中のコードを一時的に避難するときは次のようにします。
messageは省略できます。

```
git stash save "<message>"
```

避難したものを確認するときは次のようにします。

```
git stash list
```

避難したものを復元する場合は次のようにします。
nはstashしたときの番号です。
`stash@{n}`部分を省略すると最新のものが復元されます。

```
git stash pop stash@{n}
```

避難したものを削除する場合は次のようにします。
nはstashしたときの番号です。
`stash@{n}`部分を省略すると最新のものが削除されます。

```
git stash drop stash@{n}
```

避難したもの全てを削除する場合は次のようにします。

```
git stash clear
```

# 3. 初心者から聞かれるとうれしい質問

## commitログをキレイにしたい
ローカルで作業するときに、細かくcommitするのはよい習慣ですが、リモートにpushするときにはトレースしやすいようにキレイに整理したいものです。
なお、リモートにpushしてしまったものは変更できないので注意してください。
（つまり、commitログはpushする前にキレイにしなければならない。）

### <span id="delCommit">commitを消したい</span>
直前のcommitを消したいときは次のようにします。
※`--soft`は作業領域は戻さずにローカルリポジトリだけ元に戻すオプションで、`--hard`は自分の作業領域まで元に戻します（[元に戻したい](#reload)参照）。

```
git reset --soft HEAD^
```

特定のcommitポイントまで消したいときは次のようにします。

```
git reset --soft <commit ID>
```

commit IDは`git log`で確認します。

### commitをまとめたい
あるcommitだけを残して、それまでのcommitは履歴から消したいときは次のようにします。
（commit IDを省略すると、pushしていない最も古いcommitまでを編集できます。）

```
git rebase -i <commit ID>
```

ここで、編集画面がでてきます。

```
pick 6d614bd a
pick 10f8cbb b
pick 53ae876 c

# Rebase b03024d..53ae876 onto b03024d (3 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
```

`pick`の部分をコメントの説明のとおりに編集します。
例えば、aとbを消してしまって、cだけを残したい場合は次のようにして保存します。

```
d 6d614bd a
d 10f8cbb b
pick 53ae876 c
```

ここで、競合が発生することがあるので、注意してください。
aとbのcommitを削除するだけなのに、なぜ競合が発生するのかと思うかもしれませんが、rebaseは新たなコミットを生成して、そこに移動するコマンドです。
そのため、競合が発生することがあります。
ともかく、メッセージをよくみて、競合が発生していたら、通常どおりに[競合を解消](#conflict)してください。

最後に、rebaseを完了させるコマンドを実行します。

```
git rebase --continue
```

もし、rebaseをやめる場合は次のようにします。

```
git rebase --abort
```