【編集中】初学者向けGitLabを使った開発の流れ

# 備忘録：GitLabを使った開発の流れ
GitLabを使った開発を行った際に覚えたことをメモしておきます。
本内容はGit初学者を対象としています。ぜひ、GitLabを使ったチームでの開発を行う際に参考にしていただければと思います。
## ポイント：Gitはまずはこれだけ覚えよう
- コミット、プッシュ、マージができれば基本的な作業が可能
- IDEやGUIのツールからも使えますが、覚えるまではまずはコマンドラインでの実行がオススメ

## GitLabを使った開発の流れ

本記事では、GitLabを使った開発において、よくあるユースケースを説明します。前提および取り上げるユースケースは以下になります。
> ＜前提＞
・プロジェクトは作成済み
・main/developブランチに開発していくファイル・プログラム等はそろっている
・Gitでバージョン管理を行う
・GitのコマンドはGitBashにて実行する
　https://gitforwindows.org/
＜対象ユースケース＞
・main/developブランチにあるプログラムを改修する(バグFIX、機能追加など)


GitLab上で、チーム全体で共有しているプログラムに、新たに機能を追加したりバグを修正したりする場合、以下の手順で作業を行います。
1. イシューを立てる
1. 作業用ブランチを切る(必要に応じて)
1. 作業用のブランチに移動する
1. 作業用のブランチにてプログラムを改修等を行う
1. 変更したプログラムおよび変更内容を確認する
1. 改修したプログラムをコミットする
1. コミット内容をプッシュする
1. マージする

それでは実際にやってみます。
### 0.準備 ローカル環境にgitのリモートリポジトリからソースを取得

```terminal:コマンド
git clone [clone_url]
cd [cloneして生成されたディレクトリ]
```

clone_urlはGitLabの以下画面から"clone"をクリックし、SSHもしくはHTTPS通信用のURLをコピーしてください。
`git clone [clone_url]`実行すると、アクセスキーまたはアクセストークンでの認証を要求される場合があります。
上記認証を求められた際は以下を参照してください。
・SSHでのcloneを行う場合
　https://qiita.com/altblanc/items/2ddcfa68ece7a68aff3d
・HTTPSでのcloneを行う場合←オススメ
　https://www.insight-tec.com/tech-blog/api/20210705_gitlab/
これでgit/gitlab上で管理されているソースコード等をローカルリポジトリに持ってくることが出来ます。

### 1.イシューを立てる
GitLab上で改修内容をチーム全体に伝えます。このためにイシューを立てるという作業を行います。
以下画面のtitle、description欄に、改修内容がチームメンバが分かるように(※)記載してください。(←言うは易し生むは難し)
イシューを立てると自動で通し番号が振り分けられます。(例：#6)
(※)イシューの書き方は、部内・チーム内等で定めた書き方にしてください。
![new_issue.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335185/1b5dadee-8ce8-22c0-ab62-2d0d13205bf6.jpeg)


### 2.ブランチを切る(ブランチを作る)
そもそもなんでブランチなんてものが必要なのか。
作業用のブランチを切って作業すると、以下メリットがあります。
>・統合(本番)用ブランチに直接変更を加えず、プログラム改修等の作業を行える
・チーム内で別々の人が同時に作業できる
・プログラム改修等の作業後のソースコードの差分を追える


まずは、現時点で存在するブランチを確認してみます。
```shell:コマンド
git branch
```

```shell:例
git branch

# ブランチの一覧が表示される
# *がついているブランチが今いるブランチ
    develop
    feature
  * main
```

それでは作業するためのブランチを切っていきます。
ブランチの命名規則についてはチームで決めたルールに沿っていただくのがよいです。
今回は1ブランチ1イシューの方針より、ブランチ名にイシューの通し番号をつけておきます。(例：#1)
※この例ではmainからブランチを切っていますが、どのブランチから開発ブランチを切るかは、チーム開発の場合はルールを決めて行うのが一般的です。

```shell:コマンド
git branch xxxx
```
```xxxx```は任意の内容を記載すればよいが、文字列によってはブランチ名として認識できない場合があるため、```"xxxx"```のようにダブルクォーテーションで囲んで記載することを推奨します。

```shell:例
git branch feature/#1
git branch     #  ブランチが作成されたか確認のため実施
    develop
    feature
  * main
    feature/#1 #　ブランチが作成されていることが確認できる

```

### 3.作業用のブランチに移動する

```shell:コマンド
git checkout xxx
```

```shell:例
git checkout feature/#1
    Switched to branch 'feature/#1'

git branch # branch移動できたか確認のため実施
    develop
    feature
    main
  * feature/#1 #　現在のブランチが作成したブランチになっていることを確認
```

##### Tips
`xxx`にはブランチ名だけでなく、コミット(後述)IDを指定することで、コミット時の変更履歴を参照することが出来ます。

### 4.作業用のブランチにてプログラムを改修等を行う :pencil:
イシューを解決するようにソースコード等の改修を行う。

### 5.変更したプログラムおよび変更内容を確認する
##### 変更したプログラムの一覧を確認
```shell:コマンド
git status
```

```shell:例
git status
    On branch feature/#1
    Changes not staged for commit:
    (use "git add/rm <file>..." to update what will be committed)
    (use "git checkout -- <file>..." to discard changes in working    directory)

	modified:   app/index.html
	modified:   app/scripts/ :innocent: app.js
	deleted:    app/scripts/controllers/detail.jsbk
	modified:   app/scripts/controllers/searchctrl.js

    Untracked files:
    (use "git add <file>..." to include in what will be committed)

	app/scripts/controllers/kakugenctrl.js
	app/views/kakugen.html

    no changes added to commit (use "git add" and/or "git commit -a")
```

直前のコミットからの変更があったファイルが表示されます
・modified:修正したファイル
・deleted:削除したファイル
・Untracked files:ステージングされていない(※)ファイル
(※)gitのバージョン管理対象外

##### 変更したファイルのソースコードを確認

```shell:コマンド
git diff
```
```shell:例
git diff
diff --git a/work/mymath.py b/work/mymath.py
index f2839a5..054a215 100644
--- a/work/mymath.py
+++ b/work/mymath.py
@@ -25,8 +25,16 @@ def fib_m(n, memo=None):
         memo[n] = fib_m(n - 2, memo) + fib_m(n - 1, memo)
     return memo[n]

-def nijyo(n):
-    return n^2
+def kaijyo(n):
+    if n ==0:
+        result = 0
+    else:
+        for i in range(n-1):
+            if i==0:
+                result = 1
+            else:
+                result = result*(i+1)
+    return result

 def multiplication(a, b):
     return (a+1)*(b+1)
```
ファイルの変更点(削除した箇所/追加された箇所)が行ごとに表示されます。
-：削除した行
+：追加した行
##### Tips
`git diff`だけを実行すると、当該ブランチの直前のコミット内容との差分を表示します。
`git diff xxx`と実行することで(`xxx`はコミットID)、指定のコミット時の内容との差分を表示できます。
例えば、ブランチ作成時の履歴と現在のソースコードを比較したい場合は、
`git cat-file -p HEAD`を活用して、ブランチ作成時のコミットIDを取得し、`git diff`の引数とします。

### 6.改修したプログラムをコミットする

コミットとは変更内容(差分)を記録することです。
コミットの流れは以下の2ステップです。

1. コミットしたいファイルを選択
2. コミット

##### 1.コミットしたいファイルを選択

```shell:コマンド
git add xxx
```

```shell:例
git add app/scripts/controllers/kakugenctrl.js

# 消す対象のファイルをコミット対象とする時
git rm app/scripts/controllers/detail.jsbk

# ディレクトリ単位でコミットしたい時は以下のようにディレクトリ指定も可能
# git add ./ 
```

##### コミット対象を確認する

```
git status
    On branch feature/#1
    Changes to be committed:`
  	modified:   app/index.html
  	modified:   app/scripts/app.js
  	deleted:    app/scripts/controllers/detail.jsbk
  	new file:   app/scripts/controllers/kakugenctrl.js
  	modified:   app/scripts/controllers/searchctrl.js
  	new file:   app/views/kakugen.html
```

##### 2.コミットする

```shell:コマンド
git commit
# m オプションを使用するとコメントを同時にセットできる
# git commit -m"feature/#1 ○○の計算が正しい計算になるように修正"
```

```shell:例
git commit -m"feature/#1 ○○の計算が正しい計算になるように修正"
    [feature/#1 a566530] feature/#1
     6 files changed, 17 insertions(+), 90 deletions(-)
     delete mode 100644 app/scripts/controllers/detail.jsbk
     create mode 100644 app/scripts/controllers/kakugenctrl.js
     create mode 100644 app/views/kakugen.html
```

##### コミットログを確認する

```shell:コマンド
git log
```

```shell:例
git log
    commit 37a5410e951ffaf1bdde556f94db804c12b81fcf (HEAD -> revision/math_function_1/#1)
    Author: shimizume <○○××@gmail.com>
    Date:   Mon May 8 11:35:41 2023 +0900

    feature/#1 ○○の計算が正しい計算になるように修正

```

### 7.コミット内容をプッシュする
```shell:コマンド
git push origin xxx
```

```shell:例
git push origin feature/#1`
  	Counting objects: 11, done.
  	Delta compression using up to 4 threads.
  	Compressing objects: 100% (10/10), done.
  	Writing objects: 100% (11/11), 1.22 KiB | 0 bytes/s, done.
  	Total 11 (delta 5), reused 0 (delta 0)
  	To https://github.com/ikouya/dailyweb.git
   	* [new branch]      feature/#1 -> feature/#1
```
### 8.マージする
マージする方法は大きく二種類あります。
　① プログラムの改修を行っていた本人がマージする
　② その他のチームメンバにマージリクエストしてマージする
##### ① プログラムの改修を行っていた本人がマージする
mainブランチに作業用ブランチの変更点をマージする。
```shell:コマンド
# mainブランチに移動
git checkout main
    Switched to branch 'main'
    Your branch is up-to-date with 'origin/main'.

# mainブランチにfeatureブランチをマージします
git merge feature/#1`
  
    Updating e070127..a566530
    Fast-forward
     app/scripts/controllers/detail.jsbk    | 82 ----------------------------------------------------------
     app/scripts/controllers/kakugenctrl.js |  7 +++++++
     2 files changed, 17 insertions(+), 90 deletions(-)
     delete mode 100644 app/scripts/controllers/detail.jsbk
     create mode 100644 app/scripts/controllers/kakugenctrl.js
    yukiyoshimura /Applications/develop/GitHub/dailyweb $ git push origin main
    Total 0 (delta 0), reused 0 (delta 0)
    To https://github.com/ikouya/dailyweb.git
       e070127..a566530  main -> main

# リモートブランチを更新
git push origin main
```
マージ時に以下の様なメッセージが出力される場合があります。
これは現在いるブランチとマージする(変更点を取り込む)ブランチの変更点が競合していることを示しています。この場合、基本的には競合した箇所を手動で修正し、修正したファイルをaddし、commitします。
```shell:マージするファイルと競合が発生した場合
$ git merge feature/#2
Auto-merging work/mymath.py
CONFLICT (content): Merge conflict in work/mymath.py
Automatic merge failed; fix conflicts and then commit the result.
```
競合発生時のステータスは以下のように表示されます。ここではmymath.pyで競合が起きているため、Unmerged paths内に`both modified:   mymath.py`と表示されています。
```shell:競合発生時の変更ファイルの確認
git status
On branch add+1/multiplication/#2
Your branch is ahead of 'origin/#2_add+1_multiplication' by 1 commit.
  (use "git push" to publish your local commits)

You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Changes to be committed:

        modified:   main.py

Unmerged paths:
  (use "git add <file>..." to mark resolution)

        both modified:   mymath.py
```
競合が発生しているファイルの該当箇所を確認すると、以下の様に元のブランチの変更点とマージするブランチの変更点が両方記載されています。ここから残したい変更点を手動で修正することになります。
```python:マージ時の競合箇所
def multiplication(a, b):
<<<<<<< HEAD # Current Change
    return (a+1)*(b+1)
=======
    return a*b, a, b # Incoming Change
>>>>>>> #2_multiplication
```
##### ② その他のチームメンバにマージリクエストしてマージする
本マージ方法は、作業用ブランチで修正した内容をクロスレビューしてからマージすることを想定しております。大きな変更を伴う場合は、本マージ方法をとることが多いと思います。これもまたチームでのルール次第ですが、
GitLabの画面に戻ります。画面の右タブにあるMerge Requestをクリックすると以下のような画面になります。(バージョンによって異なるかもしれません。)
初めに元のブランチとマージするブランチを選択します。
(私だけかもしれませんが笑)表記が分かりづらいので以下に対応表を記載しておきます。
Source branch：`git merge ×××`の`×××`にあたるブランチ
Target branch：`git merge ×××`をする時に現在いるブランチ(`git checkout 〇〇〇`の`〇〇〇`にあたるブランチ)
＃私はここがコマンドラインで指定する時と直感が合わなくて混乱しました。
|  GitLab |  Git command  |
| ---- | ---- |
|  Source branch  |  `git merge ×××`の`×××`にあたるブランチ  |
|  Target branch  |  `git merge ×××`をする時に現在いるブランチ(`git checkout 〇〇〇`の`〇〇〇`にあたるブランチ  |

![new_merge_request_branch.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335185/dd67b9cd-c73e-7bbd-0778-2ea14e7c08c0.jpeg)

続いて、リクエスト時のタイトル・メッセージ等を記載します。
その他にもAssignee(最終承認者)、Reviewerなど選択できます。
書き方・記載範囲等はチームの運用に従ってください。
![new_merge_request_title.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335185/9bc7d218-ad1e-9aae-346e-edc2d3d0f810.jpeg)


①②どちらのマージ方法においても、マージ後の変更履歴は以下のようになります。
本手順のような開発・運用を行うことで、保守性やトレーサビリティを考慮したプログラム開発を行うことが出来ます。
一連の流れ
![image.png]()