卒論生のためのGit

# はじめに
研究室に配属されるとほぼ間違いなく「絶対にオンラインストレージなどにファイルのバックアップを取っておけ」と言われる．
提出間近になってPCが壊れたために，とんでもないことになるという被害が後を絶たないからである．
Wordで卒論を書く際はOneDriveやGoogle Driveなどのストレージを活用すれば困ることはほぼないだろう．
ところが，理系ではTeXを使用して論文を執筆するケースも多い（TeXしか認めない研究室も少なくないとか）．更にプログラムを用いて数値実験を行うケースもある．
その場合でもOneDrive等を用いることが最適な選択肢なのだろうか．
勿論誤った選択肢とは言えない．ところがソースコードの管理においてはGit，GitHubという便利なツールがあるため，これを用いた方がなにかと便利である．
しかし大学の講義では教わらないケースが多く，殆どの学生が使えないどころか，存在すら知らないというのが現実である．（尤も大学が実用性のあるものばかり教えるのもちょっと変な話ではあるが）
とはいえ，知っておくとかなり便利である．ここでは卒論生にとって是非覚えておきたいGit，並びにGitHubの使い方を紹介する．
Gitの概要やコマンドも紹介するが，すべて紹介するには余白が狭すぎる．Gitに関する説明に関する記事や書籍は多く出回っているため，これらを参考にしつつこの記事を読んでいただければより理解が深まるかと思う．（オススメは[コレ](https://mixi-developers.mixi.co.jp/22-technical-training-gw-b42d06431004#b274)）

続編→ https://qiita.com/a_uchida/items/82a9cd571998e812388e


# 何のためにGitやGitHubを使うのか
Gitとは一言でいうとバージョン管理ツールである．
わざわざこんなことをする理由は，万が一最新版が誤っていた際やグダってしまった際に戻すことができるからである．
（チームプロジェクトでは連携しやすくなるというメリットもある）
バージョン管理というとよくこのようなケースを見かける．
```
├── 卒論
│   └── 概要
│       ├── 概要_20221201.tex
│       ├── 概要_20221203.tex
│       └── 概要_20221204.tex
│       └── 概要_20221207.tex
│   └── 本文
│       ├── 本文_20221201.tex
│       ├── 本文_20221203.tex
│       └── 本文_20221204.tex
│       └── 本文_20221207.tex
```
PDFやWordファイルに関しては致し方ない部分もある．
ところがプログラムにおいてこのような管理手法はハッキリ言って最悪である．理由は言うまでもない．
こんな手法で何とかなるのであれば，世のエンジニアはわざわざGitなんて使わない．
Gitを知らなければこのように管理するしかないかもしれないが，Gitを使うことができれば一つのファイルに対して複数のバージョンを保持できるようになるのである．
さらにこれをリモートでも管理できるようにしたものがGitHubである．
チームプロジェクトでの作業でも力を発揮するGitHubであるが，Gitのオンラインストレージという使い方もできるのである．

# 環境構築
## Gitのインストール
### Mac
ターミナルを開き，以下のコマンドを入力する．
```
$ git --version
```
以下のような表示が出ていれば，既にGitがインストールされている（細かいバージョンは異なるかもしれない．気に入らなければ自分で改めてインストールしよう）．
```
git version 2.25.1
```
コマンドライン・デベロッパーツールをインストールするように通知が出る場合もあるのでその場合はインストールしよう．
Gitがインストールされておらず，このような通知も出ない場合は自分でインストールする必要がある．Homebrewを用いると良い．
```
$ brew update
$ brew install git
```
入れたはずのバージョンが反映されていない場合，パスの設定を見直すこと．

### Windows(WSL)
Ubuntuを用いていることを想定する．
```
$ sudo apt update
$ sudo apt install git
```
確認方法はMacと同様．

## GitHubのアカウント作成
ファイルをサーバー上にアップするためGitHubの登録もしておこう．
Sign Upというボタンから画面に従うだけ．
https://github.com/

## GitHub Educationに申請
登録しておくと，プライベートリポジトリ数の制限などの制約から解放される．
是非申請しておこう．
https://education.github.com/

## GitHub CLI
無くても全然問題はないが，せっかくなので入れておこう．（この記事ではGitHub CLIを使用することを前提にする）
### Mac
```
$ brew install gh
```
### WSL
```
$ sudo apt update
$ sudo apt install gh
```
インストールしたら，以下のコマンドを入力してターミナル上でもGitHubにログインしよう．
```
$ gh auth login
```
画面の指示に従えばOK．

# Gitの基本的な概念
## コミット
編集履歴とイメージしていただければ問題ない．具体的には，ファイルに対する変更・状態を記録する．
あるコマンドを打つだけで履歴を保存することができる．
まずは，対象ファイルをステージングエリアと呼ばれる領域に追加する必要がある．これは，コミット1つ1つに意味を持たせるためである．
例えば，実験記録を修正すると同時に論文の本文も編集していたとしよう．一気に2つ以上のタスクをこなすことは決して悪いことではないが，もしこれらを同時にコミットしてしまうとどうなるだろうか．後から見返したときに何をやったのかがわかりにくくなってしまう．
まず予め，片方のファイルのみステージングエリアに追加して，一旦コミットすることによりこのような状態を回避することが可能になる．
## リポジトリ
コミットされたデータを記録するものである．厳密にはディレクトリとは異なることに注意されたい．
その中でもGitHubのようにリモート上に保管するものをリモートリポジトリとよび，ローカル上で管理するものをローカルリポジトリと呼ぶ．

## ブランチ
時々複数のタスクを行いたい場合もある．粒度が大きくない場合はコミットを分ければいいだけだが，複数回コミットする方が望ましいケースもある．ましてこれを複数人でやる場合はコミットの順番が大変なことになってしまう．このとき活躍するのがブランチである．
ブランチ（branch）という名前の通り，作業を分岐させることができる（下図参照）．
![git_branch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855517/12a255ca-3d0b-8db7-8851-e3c0dbdda8c7.png)

勿論適宜複数のブランチを切り替えたり（チェックアウト），分岐元のブランチへ併合（マージ）することもできる．


# ユースケース
## 既存のディレクトリをGitの監視下に置きたい
これをしなければGitの恩恵を受けられない．
該当するディレクトリに移動した状態で以下のコマンドを入力する．
```
$ git init
```
以下のように表示されればOK．
```
Initialized empty Git repository in <ディレクトリ名>
```

## 編集内容をGitに反映させたい
編集したファイル（ここでは`main.tex`, `abst.tex`とする）をまずはステージングエリアに追加し，コミット対象にする．
```
$ git add main.tex abst.tex
```
また，編集したファイルを全部コミット対象にしたい！という場合は以下のようにしてもOK．
```
$ git add -A
```

コミット対象にした後，Gitにコミットする．
```
$ git commit -m "何かメッセージを入力"
```
メッセージには何をやったかを記載しておくと良い．

## 履歴を見たい
ログを出力させれば良い．
```
$ git log
```

## どこを弄ったのか分からなくなってしまった
該当ファイル（ここでは`a.txt`とする）がステージングエリアに追加されていない場合は追加しておくこと．
該当ファイルすらわからない場合は，全ファイルをステージングエリアに追加すれば良い．
その上で以下のコマンドを入力する．
```
$ git diff
```
以下のように表示され，編集内容が一目でわかる．
```
diff --git a/a.txt b/a.txt
index 980a0d5..1ce3f81 100644
--- a/a.txt
+++ b/a.txt
@@ -1 +1 @@
-Hello World!
+Goodbye World!
```

## 誤ってコミットしてしまった
熟練のエンジニアでも結構やってしまいがちである．
この場合，コミット後の編集内容は保持しておきたいケースが多い．
以下のコマンドでリセット可能．
```
$ git reset
```
また，指定したコミットまで遡りたい場合は，resetの後にコミットIDを指定すればよい．（IDはログから確認可能）

## 弄ったはいいけど元に戻したい
これも結構あるあるなケースである．
`hard`オプションをつける．（コミット後の編集内容は全て飛ぶので注意！！）
```
$ git reset --hard
```

## 複数のパターンを試したい
ファイルを編集していると，複数のパターンが思い浮かぶこともあるが，いちいちCtrl+Zを繰り返してはまた編集して気に入らなければまた戻すといったことをしがちである．
このようなケースでもGitの恩恵を受けられる．ブランチ機能を使うと管理しやすくなる．
ここでは2つのケースを試したいと仮定しよう．まずはそれぞれブランチを作成する．ブランチ名はわかりやすい名前を付けておくと良い．
```
$ git branch <ブランチ名>
```
`git branch`と打つと，ブランチ一覧が出力される．ブランチを切り替えたい場合は以下のコマンドを入力．
```
$ git checkout <ブランチ名>
```
両方のパターンが落ち着いたら，それらをメインのブランチにも反映させよう．（必要に応じて片方だけのパターンもあるだろう）
まずはメインのブランチに切り替えた上で，マージしたいブランチに対して以下のコマンドを入力．
```
$ git merge <ブランチ名>
```
編集箇所によってはコンフリクトが起こる場合があるのでその場合は解消すること．（手動で一部弄る必要がある場合もある）

## 別ブランチの特定のコミットだけ反映させたい
大分ピンポイントなユースケースであるが，複数のブランチを管理していると意外とあるあるなケースである．
マージはしたくないけど一部だけというイメージである．
この場合は`cherry-pick`を用いる．
```
$ git cherry-pick <コミットID>
```

## あれ？なんか知らない間に動かなくなった
誰しも一度は経験のあるケースである．ひどい時は発狂したくなる．
ややマニアックな機能である`bisect`を用いると，どのコミットで悪さをしているかの特定が簡単になる．
流石に全部修正してくれるといった夢のような機能ではないが，知っておくとバグの特定が幾分か楽になる．使い方は2通りに分かれる．
### テスト用スクリプトを用いる場合
終了コードが0であればgood，1であればbadとして扱われる．その場に応じて適切な言語を用いて実装すると良い．（ここでは`test.sh`とする）
以下のコマンドを入力すれば，初めてバグが混入したコミットにチェックアウトされる．
```
$ git bisect run ./test.sh
```

### 手動でテストする場合
バグが混入していないことが確実なコミットIDを予め調べておこう．その上で，まずは
```
$ git bisect bad
```
で現在のコミットでは正常に動作しないと記録する．次に，
```
$ git bisect <正常に動作するコミットID> good
```
で調べたコミットでは正常に動作すると記録する．するとgoodとbadの中間のコミットにチェックアウトされるので正常に動作するかを確認する．
正常に動作した場合は`git bisect good`，正常に動作しない場合は`git bisect bad`を実行．これを終了するまで繰り返す．終了時には，動かなくなり始めたコミットがチェックアウトされているはずである．
途中でやめたくなった場合は，
```
$ git bisect reset
```
終了後に細心のコミットに戻る際も上記のコマンドを実行すれば良い．
コミット数$N$に対し，テスト回数は高々$\log N$回程度なので，手動でもさほど大変ではないはず．

## コミットした内容をGitHubに反映させる
まずはローカルのディレクトリとGitHub上のリポジトリと紐づける必要がある．
リポジトリをまだ作成していない場合は，以下のコマンドを入力し，出力される指示に従って情報を入力しよう．
```
$ gh repo create
```
すでにリポジトリが作成されている場合，`.git`で終わるURLをあらかじめGitHubから取得し，以下のコマンドを入力すればよい．
```
$ git add remote origin https://github.com/<user-name>/<repository-name>.git
```

編集内容をGitHubに反映させるには`push`コマンドを使う．
```
$ git push origin <ブランチ名>
```
コミットしただけでは反映されない点に注意！！

## 別PCで作業したい
研究室で作業をした後，家のPCで続きの作業をしたいというケースも多い．
その場合，当然GitHub上とローカル環境では差分が生じている．
以下のコマンドで差分をなくそう．
```
# 最新状態を取得
$ git fetch
# 取得した状態を反映させる
$ git pull origin <ブランチ名>
```
そもそもディレクトリがない場合は，以下のコマンドで引っ張ってくることが可能．

```
$ gh repo clone <user-name>/<repository-name>
```

# 参考文献
エンジニアのためのGitの教科書 実践で使える！バージョン管理とチーム開発手法，株式会社リクルートテクノロジーズ，翔泳社，2016