---
# System prepended metadata

title: Git Flow
tags: [' Roles', Git, ' Git Flow']

---

---
slideOptions:
  transition: slide
  theme: night
tags: Git, Git Flow, Roles
type: 
title: Git Flow
---
<style>
    .reveal section img {
        background: transparent!important;
        border: none!important;
        box-shadow: none!important;
    }
</style>

# Git flow
## Tổ chức repository

* Một repo chỉ nên có 2 branch chính:
* <b><u>Master</u></b> : 
	* Là nhánh sẽ chứa code được release đầy đủ nhất với chất lượng tốt nhất đã được thông qua đầy đủ các bước về kiểm định. Nhánh này sẽ là sản phẩm được triển khai lên DC/DR
	* Setting permission ở nhánh này:
		* Allow to merge: <b>No one</b>
		* Allow to push: <b>No one</b>
		* Default branch: <b>False</b>
* <b><u>Development</u></b> : 
	* Là nhánh chứa code được merge từ <i>local dev</i>. Đây cũng là nhánh sẽ sử dụng chung cho toàn bộ các dev trong suốt quá trình phát triển sản phẩm.
	* Code ở nhánh này sẽ phải được review về style programming; các thuật toán cũng như kỹ thuật sử dụng trong code
	* Là nhánh sẽ được triển khai lên môi trường staging
	* Code sau khi đã pass qua Stress test, IT test sẽ được merge lên nhánh <b>Maste</b> khi được sự đồng ý của <b><i>PM</i></b>
	* Setting permission ở nhánh này:
		* Allow to merge: <b>Maintainer</b>
		* Allow to push: <b>No one</b>
		* Default branch: <b>True</b>
----

## Nguyên tắc
* Sử dụng ssh và cli để đạt được hiệu quả tốt nhất khi làm việc với repository
* Mỗi pull-request tương ứng với một ticket.
* Mỗi một pull-request không hạn chế số lượng commit
* Pull-request title phải đặt sao cho tương ứng với title của task với format `refs [Loại ticket] #[ticket_Số ticket] [Nội dung ticket]` （Ví dụ: `refs bug #ticket_1234 Sửa lỗi cache`）.
* Đối với commit title, trong trường hợp pull-request đó chỉ có 1 commit thì có thể đặt commit title tương tự như trên là `refs [Loại ticket] #[ticket_Số ticket] [Nội dung ticket]` （Ví dụ: `refs bug #ticket_1234 Sửa lỗi cache`）.\
  Tuy nhiên với trường hợp 1 ppull-request có chứa nhiêù commit thì cần phải ghi rõ trong nội dung commit title là trong commit đó xử lý đối ứng vấn đề gì.
  * Ví dụ:
      1. Pull-request title: `refs bug #ticket_1234 Sửa lỗi cache`
      2. Trong trường hợp pull-request có 2 commit thì nội dung commit title của 2 commit sẽ tương ứng như sau
        - `Tạo method thực hiện việc clear cache trong Model`
        - `Tại controller gọi method ở Model để thực hiện việc clear cache`
- Gitflow đến thời điểm 2018/03/28 có quy định là 1 pull-request chỉ một commit sẽ không còn hiệu lực nữa. Tuy nhiên với các dự án mà teamsize lớn hơn 10 người thì để nhằm mục đích cho thuận tiện cho việc confirm thì khuyến khích dùng squash and merge .
- Ngoài ra thì với gitflow trước đây ( trước thời điểm 2018/03/28) thì có cho phép dùng force push, tuy nhiên do khi sử dụng force push sẽ xoá hết lịch sử thay đổi do vậy gitlow hiện tại không khuyến khích sử dụng force push. Trong trường hợp cần sử dụng force push thì cần có sự đồng thuận từ team.
- Tại môi trường local(trên máy lập trình viên), tuyệt đối không được thay đổi code khi ở branch master.Nhất định phải thao tác trên branch khởi tạo để làm task.

## Quy định về cách đánh mã remote/task-branch trên local dev
- Nên đặt tên remote của repository là tên dự án hoặc tên công ty. Khuyến cáo không nên để tên mặc định <b>`origin`</b>
- <b><u>[TaskType]/[Ticket_TicketNumber]</u></b>: trong đó
  * <b>TaskType</b>: Là <b><i>feature</i></b> hoặc <b><i>bug</i></b> (phụ thuộc vào kiểu task được break trên JIRA)
  * <b>Ticket_TicketNumber</b>: Là mã ticket trên JIRA tương ứng với mỗi task
  * Example: <i>feature/ticket_01</i>: Nghĩa là đây là branch thực hiện chức năng(<i>feature</i>) tích hợp login SSO(<i>ticket 01</i> trên JIRA) của dự án DPA(<i>Ký hiệu</i> của dự án)
----

## Quy định đánh tag version
- Tag là chức năng đặt tên một cách đơn giản của Git, nó cho phép ta xác định một cách rõ ràng các phiên bản mã nguồn (code) của dự án. Ta có thể coi tag như một branch không thay đổi được. Một khi nó được tạo (gắn với 1 commit cụ thể) thì ta không thể thay đổi lịch sử commit ấy được nữa.
- Sử dụng `Annotated tag` để có thể mô tả thông tin chi tiết hơn
- Chỉ nên sử dụng tag khi Release
- Khi đánh tag phải nhập đầy đủ thông tin về <b>version(-a)</b>, <b>message(-m)</b>, <b>author(-s)</b>
	- Version: v.x.x.x
	- Message: Thông tin mô tả các điểm nổi bật trong version được release
	- Author: Người trực tiếp release và thực hiện đánh tag (Không cần thiết nếu người đánh tag là người trực tiếp thao tác vì git sẽ lấy từ config của account hiện tại tại thời điểm đánh tag)
	- ex:
	```ssh
	$ git tag -a v1.0.0 -m "Release 1.0.0"
	```
	- Sau khi thực hiện đánh tag tại local thì sẽ thực hiện công khai tag trên repository:
	```ssh
	$ git push --tags # <---- Đẩy toàn bộ tag từ local lên repository
	$ git push [remote_name] <tag_identifier> # <---- Đẩy một tag từ local lên repository
	```
Sau khi đã đánh tag các version code(commit) thì ta có thể thực hiện release để sử dụng giữa các team trong công ty hoặc đối tác
## Quy trình

### Chuẩn bị

1. Trên SCM (Source control manager), fork Central Repository về tài khoản của mình（repository ở tài khoản của mình sẽ được gọi là Forked Repository）.
2. Tạo thư mục chứa source code của dự án và truy cập vào thư mục đã được tạo.
	```sh
	$ mkdir [Thư mục dự án]
	$ cd [Thư mục dự án]
	```
3. Fetch code từ Repository về local dev
	```sh
	$ git init
	$ git remote add [remote_name] [URL của Repository]
	$ git fetch [remote_name]
	```
----

### Đối với dự án áp dụng quy định tương ứng với 1 pull-request chỉ cho phép nhiều commit

Từ đây, Central Repository và Forked Repository sẽ được gọi lần lượt là `[remote_name]` và `origin`.

1. Đồng bộ hóa branch development tại local với `[remote_name]`.
    ```sh
    $ git checkout development
    $ git pull -r [remote_name] development
    ```

2. Tạo branch để làm task từ branch development ở local. Tên branch là số ticket của task（Ví dụ: `feature/ticket_1234`）.
    ```sh
    $ git checkout development # <--- Không cần thiết nếu đang ở trên branch development
    $ git checkout -b feature/ticket_1234
    ```

3. Tiến hành làm task（Có thể commit bao nhiêu tùy ý）.

4. Push code lên remote repository.

    ```sh
    $ git push -u [remote_name] feature/ticket_1234
    ```

5. Tại `[remote_name]` trên Git, từ branch `feature/ticket_1234` đã được push lên hãy gửi pull-request đối với branch development của `[remote_name]`.

6. Hãy gửi link URL của trang pull-request cho reviewer trên chatwork để tiến hành review code.

    6.1. Trong trường hợp reviewer có yêu cầu sửa chữa, hãy thực hiện các bước 3. 〜 5..
    6.2. Tiếp tục gửi lại URL cho reviewer trên chatwork để tiến hành việc review code.

7. Nếu trên 2 người reviewer đồng ý với pull-request, người reviewer cuối cùng sẽ thực hiện việc merge pull-request.
   Revewer xác nhận sự đồng ý bằng comment LGTM.
   
8. Quay trở lại 1.
----

### Đối với dự án áp dụng quy định tương ứng với 1 pull-request chỉ cho phép 1 commit

Từ đây, Central Repository và Forked Repository sẽ được gọi lần lượt là `[remote_name]` và `origin`.

1. Đồng bộ hóa branch development tại local với `[remote_name]`.
    ```sh
    $ git checkout development
    $ git pull -r [remote_name] development
    ```

2. Tạo branch để làm task từ branch development ở local. Tên branch là số ticket của task（Ví dụ: `feature/ticket_1234`）.
    ```sh
    $ git checkout development # <--- Không cần thiết nếu đang ở trên branch development
    $ git checkout -b feature/ticket_1234
    ```

3. Tiến hành làm task（Có thể commit bao nhiêu tùy ý）.

4. Trường hợp đã tạo nhiều commit trong quá trình làm task, tại 5. trước khi push phải dùng rebase -i để hợp các commit lại thành 1 commit duy nhất.
    ```sh
    $ git rebase -i [Giá trị hash của commit trước commit đầu tiên trong quá trình làm task]
    ```

5. Quay trở về branch development ở local và lấy code mới nhất về

    ```sh
    $ git checkout development
    $ git pull -r [remote_name] development
    ```

6. Quay trở lại branch làm task, sau đó rebase với branch development.

    ```sh
    $ git checkout feature/ticket_1234
    $ git rebase development
    ```
    **Trường hợp xảy ra conflict trong quá trình rebase、hãy thực hiện các thao tác của mục「Khi xảy ra conflict trong quá trình rebase」.**

7. Push code lên `[remote_name]`.

    ```sh
    $ git push -u [remote_name] task/1234
    ```

8. Tại `[remote_name]` trên Git, từ branch `feature/ticket_1234` đã được push lên hãy gửi pull-request đối với branch development của `[remote_name]`.

9. Hãy gửi link URL của trang pull-request cho reviewer trên chatwork để tiến hành review code.

    9.1. Trong trường hợp reviewer có yêu cầu sửa chữa, hãy thực hiện các bước 3. 〜 6.

    9.2 push -f (push đè hoàn toàn lên code cũ) đối với `[remote_name]` làm task.
    ```sh
    $ git push [remote_name] feature/ticket_1234 -f
    ```

    9.3 Tiếp tục gửi lại URL cho reviewer trên chatwork để tiến hành việc review code.

10. Nếu trên 2 người reviewer đồng ý với pull-request, người reviewer cuối cùng sẽ thực hiện việc merge pull-request.
    Revewer xác nhận sự đồng ý bằng comment LGTM.

11. Quay trở lại 1.
----

#### Khi xảy ra conflict trong quá trình rebase

Khi xảy ra conflict trong quá trình rebase, sẽ có hiển thị như dưới đây (tại thời điểm này sẽ bị tự động chuyển về một branch vô danh)
```sh
$ git rebase development
First, rewinding head to replay your work on top of it...
Applying: refs #1234 Sửa lỗi cache
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merging path/to/conflicting/file
CONFLICT (add/add): Merge conflict in path/to/conflicting/file
Failed to merge in the changes.
Patch failed at 0001 refs #1234 Sửa lỗi cache
The copy of the patch that failed is found in:
    /path/to/working/dir/.git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".
```

1. Hãy thực hiện fix lỗi conflict thủ công（những phần được bao bởi <<< và >>> ）.
Trong trường hợp muốn dừng việc rebase lại, hãy dùng lệnh `git rebase --abort`.

2. Khi đã giải quyết được tất cả các conflict, tiếp tục thực hiện việc rebase bằng:

    ```sh
    $ git add .
    $ git rebase --continue
    ```