Teamwork Using Git
It’s been a long time since the last update of the blog. This time, the content of the update is about how to use Git for teamwork. This article mainly introduces the workflow of teamwork.
Basic Tutorial
This article assumes that you have a basic understanding of Git. If you are not familiar with Git, you can refer to some basic tutorials about Git first such as Liao Xuefeng’s Git Tutorial.
If you are not used to Chinese, it’s recommended to read the official Git documentation: Git Documentation.
If you have basic Git skills, you can continue to read this article to learn how to use Git for teamwork. Before reading this article, you can also read Pro Git. Fortunately, the book is free to read online and available in many languages.
Then, let me introduce the workflow of teamwork using Git.
Teamwork Workflow
I introduce the workflow mainly based on Gitlab.
In GitLab, there are 5 roles for repository members:
Guest: can only view repository contents, but cannot perform write operations;
Reporter: can view and clone repositories, but cannot perform write operations;
Developer: can perform write operations, but cannot manage project settings;
Maintainer: can manage project settings and members;
Owner: has all permissions, including deleting projects.
Suppose there is a project with 5 team members including project manager (1 person), developers (3 people, 1 of whom joined midway), tester (1 person);
The roles and responsibilities of these 5 people are as follows:
- Project Manager: Owner
- Developer #1: Maintainer (responsible for developing and reviewing code)
- Developer #2: Developer
- Developer #3: Developer (joined midway)
- Tester: Reporter
Before Developer #3 joined, the project development was all done collaboratively within the team, and the code should be submitted to a repository.
After Developer #3 joins, the project involves cross-team development. Developer #3 should fork the repository. If using GitLab, merge the code into the upstream repository (the upstream repository is the forked repository) through Merge Request (MR for short).
The following is the workflow description of GitLab Flow.
- The project manager creates a repository, submits the requirements document, and adds team members as Developers
The initial submission is as follows:
|
|
Next, submit the requirements documents.
|
|
Open the docs/requirements.md
file and complete the requirements document. After writing it, do the following:
|
|
- Developer #1 submits technical documents and creates dev branch
Submitting technical documents is as follows:
|
|
Open the docs/technical.md
file and complete the writing of the technical document. After that, do the following:
|
|
Internal team collaboration
When collaborating internally, Developer #1, Developer #2, and Tester are all in the same team. They are all members of the project and can directly submit code to the same repository;
Next, two application scenarios are explained according to the GitLab Flow
workflow.
Develop new features
Development and testing of new features cannot be modified on one branch, but a new branch should be created, named feat_xxx
to represent the development of xxx feature.
Next, Developer #1 raises an issue and creates two new branches in the issue named feat_xxx
and test_xxx
, which are used by Developer #2 to submit feature code to the feat_xxx
branch and testers to submit test case code to the test_xxx
branch.
Among them, the feat_xxx
branch is based on the latest dev
branch, and the test_xxx
branch is based on the feat_xxx
branch. The workflow is as follows:
Developer #1 submits an issue according to the document of the dev branch. Developer #1 creates a new branch
feat_xxx
based on thedev
branch in the issue and notifies Developer #2 to develop the functionDeveloper #2 obtains and checks out to the
feat_xxx
branch
If the feat_xxx
branch does not exist, you need to create and switch to a new branch. Execute the following instructions:
|
|
If feat_xxx
branch already exists, execute the following command:
|
|
- Developer #2 develops on
feat_xxx
and pushes it to the remote library after development is completed
|
|
Note: If the modification of feat_xxx is a new function, the comment of the commit record should be prefixed with “[feat]”.
- Developer #2 has not submitted an MR before, so he creates an MR request to merge
feat_xxx
into thedev
branch, and the Issue needs to be associated with the MR.
After the Developer #2 completes the new function, he needs to associate the MR in the Issue, through the !<MR_number>
method. Assuming that the serial number of the MR is 9, the comment See merge request !9
should be added to the Issue;
Also, add a comment in Merge Request to indicate which Issue this corresponds to, through the #<Issue_number
method. Assuming that the Issue corresponding to the MR is 5, the comment See issue #5
should be added.
- Developer #1 reviews the code. If the review fails, he/she will state the improvement suggestions in the MR and return to step (3)
The comment of the submission record here should still be [perf] Improve xxx
, where “[perf]” is the improvement made for xxx
- If the review passes, Developer #1 will create a sub-item Issue in the Issue, create a
test_xxx
branch based on thefeat_xxx
branch, and assign the Issue to the tester
Note: Developer #1 should not pass the MR after the review passes. The tester needs to submit the test case and pass the test. Then the tester needs to submit an MR request to merge the test_xxx
branch into the feat_xxx
branch. Only then can Developer #1 confirm the MR and feat_xxx
will be deleted;
- The tester pulls the test branch code, writes the test case and submits it to the
test_xxx
branch
|
|
Whether the test case is correct or not, the test case program should be submitted, and the submission record prefix should be “[test]”, indicating that this is a test case.
If the tester has not proposed an MR before, then create an MR request to merge
test_xxx
into thefeat_xxx
branch. The Issue and the corresponding MR need to be associatedDeveloper #2 reviews the tester’s MR. If it does not pass, return to step (10). Otherwise, it will be submitted to Developer #1 for review. If Developer #1 passes the review, the merge is allowed
Developer #1 allows the merge, which will delete the test_xxx
branch, and then the MR will be closed. Developer #1 is also required to mark the test issue as completed
- Developer #1 and Developer #2 update
feat_xxx
. They can first test locally. If there are problems, return to step (3)
|
|
- If all test cases pass, Developer #1 confirms that the MR has passed and merges
feat_xxx
into thedev
branch.
Dealing with integration issues
When testing a function alone, everything works fine, but there is a problem when integrating it. The following example is used to introduce it.
Assume that the requirements have not changed significantly, the original function feat_xxx1 (no problem), add a new function feat_xxx2, and there is no problem when testing feat_xxx2 alone, but a problem occurs after the integration test. The tester needs to raise an issue first, and other members should actively discuss and locate the problem;
Here, there is no need to go back to the feat_xxx2 branch to fix the problem (maybe the problem of feat_xxx1 was not exposed in the previous integration test), but to create a new branch on the integrated dev
branch to fix the integration problem.
The specific workflow is as follows:
- The tester tests based on the
dev
branch, and raises an issue if a problem is found, explaining the phenomenon of the problem and what operations were performed
If the problem occurs in a certain test case, the test case program should be submitted and then an MR should be submitted to request to merge test_dev
into the dev
branch, and then the MR and the corresponding issue should be associated in the issue
If other members discuss and confirm that there is a problem, after Developer 1 and Developer 2 pass the tester’s MR, Developer 1 confirms the merge, and the test_dev
branch will be deleted
Note:
Feat_xxx3 and feat_xxx4 may be developed at the same time. Each function is fine when tested separately, but problems occur after integration. They are merged into the dev
branch without conflict. The tester should create two new branches locally for these two integrations. For the commits of feat_xxx3 merged into dev, create a test_dev
branch, and for the commits of feat_xxx4 merged into dev, create a test_dev1
branch. Branch naming is analogous.
If you merge into the dev
branch multiple times in a row, including adding new functions and fixing problems with old functions, you should create a tag through the following command:
|
|
Generally, the tester tests the code on the branch of release-x.x.x
. If there is a problem, create a test-release-x.x.x
branch locally for testing. The operation is as follows:
|
|
After locating the problem (assuming that the problem occurs in feat_xxx2 developed by developer 2), developer 1 creates a
fix_xxx2
branch in the Issue based on the problematicdev
branch and assigns it to developer 2Developer 2 needs to modify and submit the code on
fix_xxx2
The submission record here is annotated as [fix] Fix xxx problem
Developer 2 performs the same operation as the tester. If the problem still occurs, return to step (3)
Developer 2 submits a MR request to merge
fix_xxx2
into thedev
branch, and associates the MR with the corresponding fix issueTester 2 pulls
fix_xxx2
for testing. If there is no problem, it passes, but it will not be merged into thedev
branchDeveloper 1 observes the bug fix, and finally passes the merge, and the
fix_xxx2
branch will be deleted
Cross-team development workflow
After developer 3 joins, the code submitted by developer 3 may affect existing functions due to lack of precautions. Therefore, developer 3 should fork the upstream repository for development, and other members should continue to develop in the original way.
Developer 3 should do the following:
|
|
Assuming that the project is urgent and the function that should have been implemented by Developer 2 is handed over to Developer 3 for development, Developer 1 should raise an Issue in the upstream repository and create a feat_xxx
branch based on the dev
branch. When Developer 3 receives the notification, he should do the following:
|
|
The subsequent operations are similar to the development workflow within the team.
Note:
If developer 3 needs to submit an MR, he should create an MR in his forked repository;
If developer 3 receives an assignment, he should pull the corresponding branch from the upstream repository
upstream
to the local, and then modify and submit the code on the branchDeveloper 3 cannot push directly to the upstream repository, but should push to the forked repository, and then create an MR request to merge it into the corresponding branch of the upstream repository. The MR needs to be associated with the corresponding issue in the upstream repository.
Supplement
The remote library branch is deleted after MR, how to delete the remote library fetched locally
After developer 1 confirms MR, the remote library’s feat_xxx
branch is deleted, but the local feat_xxx
still exists
|
|
There is a big problem with a certain release version. How to delete the deleted remote library tag stored locally
|
|
In cross-team collaboration, after the upstream warehouse MR, how to synchronize the forked remote library with its upstream warehouse
Assuming that your MR requests to merge fix_xxx
into the dev
branch of the upstream warehouse, after developer 1 confirms the merge, the operation is as follows
|
|
How to name a new branch
For example, to add a new feature Add query temperature function, you should create a new branch named feat_query_temp
in the current branch (usually dev branch) (where feat is the abbreviation of feature);
The naming format of the new branch is as follows:
|
|
Submission type (type): including
feat
(new feature),fix
(fix problem),doc
(document change),refactor
(code refactoring, not new feature, not bug fix),test
(add or modify test),chore
(other submissions that do not modify source code or test cases),style
(code format, does not affect code operation);Short description (subject): Use underscores
_
to separate words, and be concise and clear.
The naming rule example is as follows:
|
|
How to write commit comments
Commit comments should be as concise and clear as possible, and directly reflect the changes in the submitted code;
New features and bug fixes should also be submitted in two batches, and other types of submissions should be submitted in the same way;
You can submit to the local library through the git commit -m <message>
command, where the description of <message>
is as follows:
|
|
Where type values and their meanings are as follows:
type | Meaning | Example |
---|---|---|
feat | New feature (feature) | [feat] Add health check |
fix | Fix bug (fix bug) | [fix] Fix health check relocation problem |
doc | Documentation changes (documentation) | [doc] Improve technical documentation |
style | Code formatting | [style] Format non-generated source code |
refactor | Refactor code | [refactor] Refactor command reply prompt |
test | Add or modify tests | [test] Test health check |
chore | Commit without modifying source code or test files | [chore] Improve .gitignore |
perf | Changes to improve performance | [perf] Improve sliding average performance |
ci | Changes related to continuous integration | [ci] Automatically generate and publish hex and bin files |
build | Changes to build system or external dependencies | [build] Improve CMakelists.xt configuration |
revert | Undo previous submission | [revert] Rollback scheduled tasks |
How to automatically perform specific operations for each submission
If you need to format the code before each submission, you should normally perform specific operations actively, but you can configure .git/hooks/pre-commit
to perform the desired operations. The example is as follows:
|
|
The content of pre-commit is as follows:
|
|
After the above configuration, each time git commit
is executed, it will filter “.c” and “.h” files in the modified files, and then format the files through clang-format
according to the “.clang-format” configuration file in the root directory.