開発者が直接masterリポジトリを参照できない！そんな閉じた環境でもストレスフリーなgit運用をしよう

## はじめに

通常gitを使って開発を行う場合、このような形が一般的だと思います。

- 各自ローカル環境にmasterリポジトリをcloneして作業
- 最新環境は常にpullすれば利用出来る
- 修正はmasterリポジトリへ直接push。push先は
    - masterリポジトリにブランチを切ってmerge request, or
    - 直接masterブランチへpush (レビューをローカルで)

しかし、会社によっては、**特別なサーバーPC以外は開発用PCと外部ネットワークの通信が出来ない**という環境もそこそこあると思います。私もそんな環境で開発をしていました。
そんな時に構築したgit環境の運用が想像以上に良かったので、整理もかねて紹介したいと思います。

## 単純な構成

基本はgitの特性を活かしてサーバーPCに社内用リポジトリを設け、社内リポジトリとmasterリポジトリを同期させる運用になると思います。
以下のような状態ですね。
<img width="800" alt="localnetwork.png" src="https://qiita-image-store.s3.amazonaws.com/0/252277/5a86ef8f-8e67-edd9-9730-7ecaecb2ca58.png">

この構成を作るだけなら、サーバー上で以下コマンドを叩き、ローカルネットワークからSSHなりでアクセス出来るようにすればOKです。

```
git clone --bare URL
```

しかし、これだけでルールを決めずに運用すると、以下の両方を同時に満たすことは出来ません。

1. **conflict防止⇒push/pullを高頻度で行う必要がある。**
2. **品質担保⇒pushは十分テストしてからにしたい**

特に私のケースだと**git pushは常にリリースとして扱う**といった契約条件がついていたため2の比重が大きく、しっかり結合試験をした上でpushをする必要がありました。
なので、自社内のコードをしばらくpushしなくてもconflictが発生しないような工夫が必要でした。

## 最初の考え: 自社用ブランチを作成してもらう

上記1の解決策として、**社内開発用のブランチをmasterとして開発を行う**ということを考えました。
masterはまっさらな状態なままでpullを定期的に行い、社内開発用ブランチにrebase。社内開発用ブランチを常に最新コード+自社コードの状態になるよう保ち、**conflictが発生しても社内開発者がすぐに気付いて対応できる**形です。

<img width="800" alt="middle_normal.png" src="https://qiita-image-store.s3.amazonaws.com/0/252277/7aa4d7e6-33d6-b415-19d1-1fd4b2173f72.png">

構想を考えていた時は、社内・顧客ともにgitlabを利用していたので、ブランチにリリース⇒merge requestでレビューという運用がしたいと考えていました。githubへpull requestを出すのと同じ構図ですね。
しかしこの運用だと顧客側の運用も変えないといけないので断念。

## 実際の運用: 社内リポジトリに自社用ブランチを作成する

最終的な構成がこちら。リリース時にmasterへのmergeする手番を加え、**こちらの作業ブランチが顧客に全く見えないようにしました**。
このようにして構築したローカル環境でのgit運用、想像以上にストレスフリーで、というかいい点の多い構成になりました。

<img width="800" alt="middle_freedom.png" src="https://qiita-image-store.s3.amazonaws.com/0/252277/2ac11d4e-ab93-6c07-4ecb-5a4aedb79fce.png">

以下は何が良かったのかの解説です。

### ローカル環境でも常に最新コードで開発が可能

最初の構想と同じメリットですが、開発者が常に最新コードで開発が出来るため、「顧客側の修正が見えないのでconflictが発生した！」といったトラブルもなくスムーズに開発が出来ました。顧客もガンガン開発するような環境でしたが、1時間に1度のpull⇒rebase実施で十分でした。

### 顧客を気にせず自由に運用出来るので楽しい

顧客とこちらの環境が切り離されているので、やってみたいことがあれば自由に試すことが可能でした。
**顧客を気にせず好きなことが出来るのですごく楽しい！**
merge requestを採用したり、派生させたリポジトリを作って遊んだりと色々試していました。

(本当は顧客も含めプロジェクト全体で色々試してみることが出来れば最高だと思います)

### 定期更新・リリースどちらもスクリプトで簡略化が出来る

顧客側のリポジトリと社内リポジトリを同期するための全ての作業がgitコマンドで実施可能なので、スクリプト化により人の手を煩わせない作業が可能でした。例えばこんな感じ(記憶を掘り起こして記載してるので、コマンドの細かい所が違ってたらすいません

**構成**

```構成
PATH
 |
 +-- bare_repos.git
 |
 +-- repos_for_rebase (bare_reposをclone)
 |     branch: master, develop(自社開発用ブランチ)
 |
 `-- release_dir (リリース用空ディレクトリ。なんでもいいです)
```

**定期更新**

```shell:pull_rebase.sh
#顧客リポジトリとmasterブランチを同期
cd ${PATH}/bare_repos.git
git fetch origin "refs/heads/master:refs/heads/master"

#自社開発用ブランチへマージ
cd ${PATH}/repos_for_rebase
git checkout master
git pull
git rebase master develop
#エラーになったらメール通知とかしてrebase --abortを実行
git push origin develop
```

**リリース**

```shell:release.sh
#tmpリポジトリを作成
cd ${PATH}/release_dir
rm -rf bare_repos
git clone ${PATH}/bare_repos.git
#tmpリポジトリのmasterブランチにdevelopブランチをマージ
cd bare_repos
#git branch develop origin/developがいるかも
git merge develop

#remote addしてpush
git remote add release 顧客のリポジトリURL
git push release master
```

### **顧客に影響しない構成なので、git未導入で苦労している環境へも適用可能**

本当はgitを導入したいんだけど、顧客都合で導入できず大変な思いをしてマージ・リリースをしている。
そんな状況の方がいらっしゃったら、この構成はうまくハマるかもです。

流石にgit pull, git pushの部分は使えませんが、最新コードを取り込んでmasterに反映させる手番さえ踏めば、社内の開発者は自由にgitで開発が出来ます。

<img width="800" alt="other_repos.png" src="https://qiita-image-store.s3.amazonaws.com/0/252277/7f83d37e-c19d-ae43-c5bf-c821c03660a9.png">

gitのbareリポジトリは以下で作成でき、後は作ったbareリポジトリをcloneして最新コードをcommit、pushすれば環境構築終了！導入も簡単です。

```shell:
cd ディレクトリ名
git init --bare
```

なんなら共同で弄るコードを共有しにくい状況が少しでもあるなら、上記構成を自分のPCに作るだけでもかなりメリットがあると思っています。
全員に「gitを使いましょう！」と先導するのは凄くパワーがいるので、こうやってローカルから徐々に「これは便利だね！」という流れを作るのもいいかもしれませんね。

## 余談

ちなみにこの環境を構築して知ったのですが、gitlabのリポジトリ管理は
`gitホームディレクトリ/repository(repositoriesかも)/ユーザーorグループ名/git bareリポジトリ`
というディレクトリ構成になっていました。このリポジトリを差し替えたり、hookスクリプトを修正したりすれば、UI操作なしでも自由にリポジトリを弄ることが出来ます。
(トップから見えるcommit数等、業務に支障のないレベルの細かい箇所がうまく動作しなかったりしますが)

今回体験した環境下ではgitlabサーバーをローカルネットワーク内に置く必要があったため、この仕組みは大いに利用させてもらいました。

## **素材**
素材: いらすとや