【Gitサーバー】サーバーにGitを入れてGitサーバー構築してみた【GitWeb】

# Gitって難しいよね

こんにちは @ykhirao です！！フリーランスエンジニア初めて2週間立ちましたが、案件に入って初めてやったことは開発ではなくGit/GitHubを導入でした。いまWinSCP/TeraTermからGitベースのデプロイ環境を構築しようと思って、改めてGitに関して調べ直していました。

その知見を書いていく。

基本的にはここ [https://git-scm.com/book/ja/v2/Gitサーバー-プロトコル](https://git-scm.com/book/ja/v2/Git%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC-%E3%83%97%E3%83%AD%E3%83%88%E3%82%B3%E3%83%AB) の4章の内容を中心に書いていこうかと思います。

> Git標準でついているGitWebを立ち上げてみたり

<img width="1680" alt="スクリーンショット 2020-07-10 23.46.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112929/2c37c5bb-23df-483c-22bd-56294e48e1e7.png">

> GitHubとか使うんではなくてbareレポジトリというものをGCPのVPSに置いてみたり

そんな感じのQiitaです。暇があったらGitサーバーってなんじゃらほいって自分でも調べてみてください。私にはよくわからなかったです。たぶんGitのbareレポジトリ(つまり.git/ディレクトリ)をホストしているだけのサーバーのこと…


## 最初Gitサーバーって何言ってるのかと思った

Gitサーバーって何？パルプンテ状態でした。


```
Git on the Server
```

って書かれているので、サーバーにGit入れる話で、誤訳なのかなって思ったけど

https://git-scm.com/book/en/v2/Git-on-the-Server-Generating-Your-SSH-Public-Key

で

```
Many Git servers ... 
```

って書かれているので、誤訳じゃなくて普通に使われている言葉っぽいなあと思い、一旦言葉じりについては納得した。

```bash
yk@yk ~ % git --version
git version 2.25.0
```

## Gitって川の流れに例えるとわかりやすいよね（異論は受け付ける）


Gitのプロトコルには主に

1. Local プロトコル
2. HTTP/S プロトコル 
3. SSH プロトコル 

があるみたい。この中のLocalプロトコルは使ったことなかったのでとても新鮮味を感じた。

> 適当なレポジトリをダウンロードしてくる

とりあえず https://github.com/explore から自分にあったいい感じの軽そうなレポジトリを取ってくる。

https://github.com/denoland が 出てきたので一番コミット数少なそうな https://github.com/denoland/ninja_gn_binaries を選んで見る。

```bash
# GitHubから適当なレポジトリをクローンしてくる
$ git clone https://github.com/denoland/ninja_gn_binaries

Cloning into 'ninja_gn_binaries'...
(ry)


# プロジェクト名.git というフォルダ名をつけて bareレポジトリというのを作成する
$ git clone --bare ninja_gn_binaries ninja_gn_binaries.git

# bareレポジトリに移動
$ cd ninja_gn_binaries.git

# git操作に反応するhooksをサンプルを使用できる形に
$ mv hooks/post-update.sample hooks/post-update

# 全ユーザーに実行権限付与
$ chmod a+x hooks/post-update
```

いい感じにローカルプロトコルの準備ができました。
今回は普通の場所 `/Users/yk/workspace/ninja_gn_binaries.git` に作りましたが、同じネットワーク内の共有ファイルシステム内においたりすると、ネットワーク内からpull/pushなどのアクセスができるっぽいです。

```bash
$ pwd
/Users/yk/workspace/ninja_gn_binaries

# remoteの設定をしよう
$ git remote add local /Users/yk/workspace/ninja_gn_binaries.git

# この場合
# git push local master
# みたいにアクセスできるようになる
```


`vim .git/config`

```config
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
        ignorecase = true
        precomposeunicode = true
[remote "origin"]
        url = https://github.com/denoland/ninja_gn_binaries
        fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
        remote = origin
        merge = refs/heads/master
[remote "local"]
        url = /Users/yk/workspace/ninja_gn_binaries.git
        fetch = +refs/heads/*:refs/remotes/local/*
```

いい感じに設定できてますね。 `origin` は `https://github.com/denoland/ninja_gn_binaries` に設定されているので `git push origin master` は他人のレポジトリなので権限的にエラーがでると思います。 `git push local master` なら自分のPC内なのでいい感じにpushできるはず。


```bash
$ pwd
/Users/yk/workspace/ninja_gn_binaries

$ touch README.md
$ git add .
$ git commit -m "Create readme"
[master db503c6] Create readme
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README.md

$ git log
commit db503c617db3b9f8ce88c8c1f6afc9a71d4675f8 (HEAD -> master, local/master)
Author: Yuki <yuki@example.com>
Date:   Thu Jul 9 00:31:45 2020 +0900

    Create readme

commit 50abf78bdabe66518865e3b9fdfaaade87bcfded (tag: 20200506, origin/master, origin/HEAD)
Author: Bert Belder <bertbelder@gmail.com>
Date:   Wed May 6 01:41:43 2020 +0200

    Update gn to git revision 5ed3c9cc
```

いい感じに `local/master` にpushできました！
このremoteのブランチを別のファイルにcloneしてきましょう！

```bash
$ pwd
/Users/yk/workspace

$ git clone /Users/yk/workspace/ninja_gn_binaries.git second-clone-sample
Cloning into 'second-clone-sample'...
done.

$ ll | grep second-clone-sample
drwxr-xr-x   7 yk  staff   224  7  9 00:37 second-clone-sample

$ cd second-clone-sample

$ git log
commit db503c617db3b9f8ce88c8c1f6afc9a71d4675f8 (HEAD -> master, origin/master, origin/HEAD)
Author: Yuki <yuki@example.com>
Date:   Thu Jul 9 00:31:45 2020 +0900

    Create readme

commit 50abf78bdabe66518865e3b9fdfaaade87bcfded (tag: 20200506)
Author: Bert Belder <bertbelder@gmail.com>
Date:   Wed May 6 01:41:43 2020 +0200

    Update gn to git revision 5ed3c9cc

```

別のフォルダにcloneしてくることができました。 :clap: 


1. Local プロトコル

の話が終わったのですが、

2. HTTP/S プロトコル
3. SSH プロトコル

は簡単で

```bash
# HTTP/S プロトコル
git clone https://github.com/denoland/ninja_gn_binaries.git
# 仮にプライベートレポジトリの場合、この段階でID/Passwordが聞かれる


# SSH プロトコル
git@github.com:denoland/ninja_gn_binaries.git
# 公開鍵を登録していると使えて
# プライベートレポジトリでもID/Passの入力なしで使える
```

いつも見ているあれです！GitHubのここ

<img width="1352" alt="スクリーンショット 2020-07-09 0.40.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112929/dfc87db6-82d6-36b5-6212-01f497a351c2.png">

bareレポジトリの本質的なものは、 `git init` したときに作られる `.git` フォルダだけを管理しているレポジトリみたいです。[https://git-scm.com/book/ja/v2/Gitサーバー-サーバー用の-Git-の取得]

```
$ mkdir sample

$ cd sample

$ ls

$ ll
total 0
drwxr-xr-x   2 yk  staff   64  7  9 00:49 .
drwxr-xr-x  10 yk  staff  320  7  9 00:49 ..

$ git init
Initialized empty Git repository in /Users/yk/workspace/sample/.git/

$ ll
total 0
drwxr-xr-x   3 yk  staff   96  7  9 00:49 .
drwxr-xr-x  10 yk  staff  320  7  9 00:49 ..
drwxr-xr-x   9 yk  staff  288  7  9 00:49 .git
```

このlocalプロトコルを作成したときの bare というファイルの実態を持たないものがいわゆる世間で言われる `Gitサーバー` で、世の中にGitサーバーを構築してGit管理したいって思っている人たちの選択肢は次の3つくらいだと思っている。

1. GitHub/GitLab/その他ホスティングサービスを使う
1. 同じサーバー上の別の階層にbareレポジトリを置く
1. 別のサーバー上にbareレポジトリを置く


特に「社内でセキュリティが…」って理由がない限りは「マイクロソフトが買収した設計図サイトです！」と上司を説得してGitHubをbareレポジトリの代わりにする方向が一番きれいかなと思いました。イシュートラッカーとかカンバンとかプルリクエストとか使えるし、便利かなと


## ついに始まるサーバにGit入れてみるサーバー構築編

ここみてGCPの無料VPSをたちあげた
https://22musyoku.tokyo/gce-always-free/

公開鍵を登録したら、こんな感じでSSHできる。

```
yk@yk sample % ssh 3X.1XX.XX.45

(yes)

Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-1019-gcp x86_64)

(ryaku)

yk@lwaysfree-micro:~$
```

GCP-Ubuntu20.04だとgitが入ってなかったので適当にいれる。

```
$ git
-bash: git: command not found
$ sudo apt update
$ sudo apt upgrade
$ git --version
git version 2.25.1
```

projectのbareレポを作る

```
$ sudo mkdir /opt/git
$ sudo mkdir /opt/git/project.git
$ cd /opt/git/project.git
$ sudo git init --bare
Initialized empty Git repository in /opt/git/project.git/
```

ローカルPCでいろいろごりごり

```
$ git status
On branch master

No commits yet

nothing to commit (create/copy files and use "git add" to track)
$ touch README.md
$ git add .
$ git commit -m "INIT"
[master (root-commit) 909289c] INIT
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README.md
$

# リモートの設定する
# ykとIPアドレスの部分は適宜変えて
$ git remote add origin yk@34.105.XX.XX:/opt/git/project.git
$ git push origin master
```



```
% git push origin master

Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 213 bytes | 213.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
error: remote unpack failed: unable to create temporary object directory
To 34.105.93.45:/opt/git/project.git
 ! [remote rejected] master -> master (unpacker error)
error: failed to push some refs to 'yk@34.105.93.45:/opt/git/project.git'
```

書き込みのエラーが出たので一旦ユーザー所有者にする

```bash
yk@lwaysfree-micro:/opt/git$ sudo chown yk project.git/ -R
yk@lwaysfree-micro:/opt/git$ ll
total 12
drwxr-xr-x 3 root root 4096 Jul  8 16:11 ./
drwxr-xr-x 3 root root 4096 Jul  8 16:10 ../
drwxr-xr-x 7 yk   root 4096 Jul  8 16:34 project.git/
```

OKそう。push成功！

```bash
% git push origin master

Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 213 bytes | 213.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To 34.105.93.45:/opt/git/project.git
 * [new branch]      master -> master
```

localにクローンしてくることもできます！いい感じですね。
これが噂のGit用だけのGitサーバーか…

```bash
$ git clone yk@34.105.XX.XX:/opt/git/project.git sample-clone
Cloning into 'sample-clone'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (3/3), done.

$ cd sample-clone

y$ git log
commit 909289c7a8057ec6fcb207da70684e9daa81e39e (HEAD -> master, origin/master, origin/HEAD)
Author: Yuki <yuki@example.com>
Date:   Thu Jul 9 01:22:46 2020 +0900
```

`4.10 Gitサーバー - まとめ` に書かれていますが


> 自前でサーバーを構築すれば、多くのことを制御できるようになり、ファイアウォールの内側でもサーバーを実行することができます。 しかし、サーバーを構築して運用するにはそれなりの手間がかかります。ホスティングサービスを使えば、サーバーの準備や保守は簡単になります。 しかし、他人のサーバー上に自分のコードを置き続けなければなりません。組織によってはそんなことを許可していないかもしれません。


可能ならGitHubとか使いましょう〜


## GitWeb立ち上げてみる

`4.7 Gitサーバー - GitWeb`

簡単にGitのなにそれをWebで見えるいい感じのサーバーが立ち上げられます。(macだとrubyが入っているので)

```bash
yk@yk workspace % mkdir sample
yk@yk workspace % cd sample 
yk@yk sample % git init 
Initialized empty Git repository in /Users/yk/workspace/sample/.git/
yk@yk sample % touch README.md
yk@yk sample % git add README.md 
yk@yk sample % git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
	new file:   README.md

yk@yk sample % git commit -m "INIT"
[master (root-commit) 290565d] INIT
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README.md
yk@yk sample % git instaweb --httpd=webrick --stop
yk@yk sample % git instaweb --httpd=webrick       
yk@yk sample % 

# http://127.0.0.1:1234/ が立ち上がります！！！！！

# 必要なくなったら落とす
yk@yk sample % git instaweb --httpd=webrick --stop
```

<img width="1680" alt="スクリーンショット 2020-07-10 23.46.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112929/2c37c5bb-23df-483c-22bd-56294e48e1e7.png">

これでSource Treeとか必要ないですね！！！！！（極論）

正直TIGとかのほうが好きだと思ってしまったのはここだけの話。

`4.8 Gitサーバー - GitLab` でGitWeb使うくらいならGitLab使おうぜ…OSSだし。みたいな雰囲気が醸し出されています。

## 結論Gitサーバーって何?

調べてもよくわからなかった。

Gitだけのために用意している、踏み台サーバー的な存在のことを `Gitサーバー` って呼んでいるのかと思った。
bareレポジトリをホストするだけならわざわざサーバーを建てずに、プロジェクトと同じサーバーの別の階層におけばいいのでは、と思いました。（感想）


.