Featured image of post Teamwork Using Git

Teamwork Using Git

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:

  1. Guest: can only view repository contents, but cannot perform write operations;

  2. Reporter: can view and clone repositories, but cannot perform write operations;

  3. Developer: can perform write operations, but cannot manage project settings;

  4. Maintainer: can manage project settings and members;

  5. 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:

  1. Project Manager: Owner
  2. Developer #1: Maintainer (responsible for developing and reviewing code)
  3. Developer #2: Developer
  4. Developer #3: Developer (joined midway)
  5. 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.

  1. The project manager creates a repository, submits the requirements document, and adds team members as Developers

The initial submission is as follows:

1
2
3
4
5
6
git init .
touch README.md #This article briefly introduces the project background and function
git add README.md #Add README.md to the staging area
git commit -m "first commit"
git remote add origin https://<host>:<port>/path/to/xxx.git #Add a remote library, change it to your own remote library here
git push -u origin master

Next, submit the requirements documents.

1
2
mkdir docs  #创建docs目录,在该目录下添加需求文档
touch docs/requirements.md  #采用markdown格式记录需求文档

Open the docs/requirements.md file and complete the requirements document. After writing it, do the following:

1
2
3
git add docs/requirements.md #Add the requirements document to the staging area
git commit -m "[docs] Add requirements document"
git push origin master
  1. Developer #1 submits technical documents and creates dev branch

Submitting technical documents is as follows:

1
2
3
git remote add origin https://<host>:<port>/path/to/xxx.git #Add remote library, change it to your own remote library
git fetch origin -a #Get all branches of remote library
touch docs/technical.md #Record technical documents in markdown format

Open the docs/technical.md file and complete the writing of the technical document. After that, do the following:

1
2
3
4
5
6
git add docs/technical.md #Add the technical document to the staging area
git commit -m "[docs]Add technical document"
git push origin master

git checkout -b dev #Create and switch to the dev branch
git push origin dev

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:

  1. Developer #1 submits an issue according to the document of the dev branch. Developer #1 creates a new branch feat_xxx based on the dev branch in the issue and notifies Developer #2 to develop the function

  2. Developer #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:

1
2
git fetch origin -a #Get all branches of the remote library
git checkout -b feat_xxx origin/feat_xxx #Create a feat_xxx branch locally based on the remote feat_xxx branch and switch to it

If feat_xxx branch already exists, execute the following command:

1
2
git checkout feat_xxx #No need for the -base parameter, because the local feat_xxx branch already exists
git pull origin feat_xxx:feat_xxx #Pull the remote feat_xxx branch to the local feat_xxx branch
  1. Developer #2 develops on feat_xxx and pushes it to the remote library after development is completed
1
2
3
git add <files>
git commit -m "[feat] Add xxx function" #"[feat]" indicates that this is a new function
git push origin feat_xxx

Note: If the modification of feat_xxx is a new function, the comment of the commit record should be prefixed with “[feat]”.

  1. Developer #2 has not submitted an MR before, so he creates an MR request to merge feat_xxx into the dev 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.

  1. 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

  1. If the review passes, Developer #1 will create a sub-item Issue in the Issue, create a test_xxx branch based on the feat_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;

  1. The tester pulls the test branch code, writes the test case and submits it to the test_xxx branch
1
2
3
4
5
6
7
#If the test_xxx branch already exists, execute the following command
git checkout test_xxx #Execute for the first pull: git checkout -b test_xxx origin/test_xxx
touch test/test_xxx #Write a test script
#Write a script for test cases written in other languages
git add test/test_xxx
git commit -m "[test] Test xxx function" #Commit the "[test]" annotation of the record, indicating that it has modified the test code
git push origin test_xxx

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.

  1. If the tester has not proposed an MR before, then create an MR request to merge test_xxx into the feat_xxx branch. The Issue and the corresponding MR need to be associated

  2. Developer #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

  1. Developer #1 and Developer #2 update feat_xxx. They can first test locally. If there are problems, return to step (3)
1
2
3
git fetch origin feat_xxx
git checkout feat_xxx #Switch to the local branch to be merged
git merge origin/feat_xxx #Merge the remote library into the current branch
  1. If all test cases pass, Developer #1 confirms that the MR has passed and merges feat_xxx into the dev 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:

  1. 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:

1
2
3
git checkout dev
git tag release-x.x.x #Switch to the dev branch and create the current branch as a release version
git push origin release-x.x.x #Push the version to the remote

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:

1
2
3
4
5
git fetch origin -a
git checkout -b test-release-x.x.x origin/release-x.x.x #Create a test branch based on the remote release version
#Test, if there is a problem that must be found, submit the corresponding test case. The following operations are required
git commit -m "[test] Test release version x.x.x"
git push origin test-release-x.x.x
  1. 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 problematic dev branch and assigns it to developer 2

  2. Developer 2 needs to modify and submit the code on fix_xxx2

The submission record here is annotated as [fix] Fix xxx problem

  1. Developer 2 performs the same operation as the tester. If the problem still occurs, return to step (3)

  2. Developer 2 submits a MR request to merge fix_xxx2 into the dev branch, and associates the MR with the corresponding fix issue

  3. Tester 2 pulls fix_xxx2 for testing. If there is no problem, it passes, but it will not be merged into the dev branch

  4. Developer 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:

1
2
3
git clone https://<host>:<port>/path/to/repo-xxx.git #Clone the forked repository to the local
cd repo-xxx
git remote add upstream https://<host>:<port>/path/to/repo-xxx.git #Add the forked repository as the upstream repository

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:

1
2
git fetch upstream feat_xxx #Get the feat_xxx branch of the upstream repository
git checkout -b feat_xxx upstream/feat_xxx

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 branch

  • Developer 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

1
2
3
4
git fetch -p #-p is the abbreviation of --prune
git checkout dev #If you are currently on the feat_xxx branch
git branch -d feat_xxx #Delete the local feat_xxx branch
git branch -D feat_xxx #Note: This means that the local branch has not been merged and will be forcibly deleted

There is a big problem with a certain release version. How to delete the deleted remote library tag stored locally

1
git fetch -P #-P is the abbreviation of --prune-tags

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

1
2
3
4
5
6
7
8
git fetch upstream -a #Get changes in the upstream warehouse
git merge upstream/dev dev #Synchronize the upstream warehouse to the local dev branch
#or git pull upstream dev:dev #Replace the above 2 lines of instructions
git push origin dev #Synchronize local changes to the fork warehouse

git checkout dev #If you are currently in the fix_xxx branch
git branch -d fix_xxx #Delete the local fix_xxx branch
git fetch -p #Delete the deleted fix_xxx branch stored locally

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:

1
type_subject
  • 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:

1
2
3
4
feat_support_eth #Support network port
refactor_cmd_resp #Refactor command reply prompt information
style_format_code #Format source code
test_cmd_resp #Test command reply prompt information

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:

1
Format: [type]msg

Where type values ​​and their meanings are as follows:

typeMeaningExample
featNew feature (feature)[feat] Add health check
fixFix bug (fix bug)[fix] Fix health check relocation problem
docDocumentation changes (documentation)[doc] Improve technical documentation
styleCode formatting[style] Format non-generated source code
refactorRefactor code[refactor] Refactor command reply prompt
testAdd or modify tests[test] Test health check
choreCommit without modifying source code or test files[chore] Improve .gitignore
perfChanges to improve performance[perf] Improve sliding average performance
ciChanges related to continuous integration[ci] Automatically generate and publish hex and bin files
buildChanges to build system or external dependencies[build] Improve CMakelists.xt configuration
revertUndo 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:

1
2
3
4
5
6
git clone https://<host>:<port>/path/to/repo_xxx.git
cd repo_xxx.git

touch .git/hooks/pre-commit #Create a pre_commit text file in the .git/hooks directory
#Edit pre-commit content
chmod +x .git/hooks/pre_commit #Modify the pre-commit attribute to be executable

The content of pre-commit is as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/sh
# Find all C source files and header files
files=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(c|h)$')
# If there are no files to format, exit
[ -z "$files" ] && exit 0
# Run clang-format on each file with the specified .clang-format file
echo "$files" | xargs clang-format -i --style=file
# Add the formatted files back to the staging area
echo "$files" | xargs git add
exit 0

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.

Reference

  1. https://www.cnblogs.com/xiaoqi/p/gitlab-flow.html

  2. https://www.atlassian.com/git/tutorials

  3. https://git-scm.com/book/

  4. https://docs.github.com/zh/get-started/start-your-journey/about-github-and-git

Licensed under CC BY-NC-SA 4.0
Last updated on Dec 08, 2024 15:41 +0800