The source of this article is the public number: Programmer successfully
This article introduces the git practical ability that architects need to master from the perspective of front-end engineering, team collaboration, and production deployment.
Outline preview
The content presented in this article includes the following aspects:
- Branch management strategy
- commit specification and commit validation
- Misuse of the withdrawal plan
- Tag and production environment
- Permanently eliminate 443 Timeout
- Hook to achieve deployment?
- Ultimate Application: CI/CD
Branch management strategy
Git branches are powerful and flexible at the same time. If there is no good branch management strategy, team members will merge and push at will, which will cause branch confusion, various coverage, conflicts, loss and other problems.
At present, the most popular branch management strategy, also known as workflow (Workflow), mainly includes three types:
- Git Flow
- GitHub Flow
- GitLab Flow
Our front-end team has formulated its own set of branch management strategies based on the actual situation.
We divide branches into 4 broad categories:
- dev-*
- develop
- staging
- release
dev-*
is a collective name for a group of development branches, including personal branches, module branches, fix branches, etc., on which team developers develop.
Before development, merge the latest code of the develop branch through merge
; after the development is completed, it must be merged back to the develop
branch through cherry-pick
.
develop
is a separate branch, corresponding to the development environment, keeping the latest and complete development code. It only accepts merges of cherry-pick
, merges are not allowed.
staging
branch corresponds to the test environment. When the develop branch is updated and ready to be released for testing, staging merges the develop branch via rebase
, and then publishes the latest code to the test server for testers to test.
After the test finds the problem, go through the process of dev-* -> develop -> staging until the test passes.
release
is the production environment. The latest commits of the release branch are always kept in sync with the live production code, that is, the release branch is ready to be released at any time.
When the staging tests pass, the release
branch merges with the staging branch through rebase
, and then publishes the latest code to the production server.
To summarize the merge rules:
- develop -> (merge) -> dev-*
- dev-* -> (cherry-pick) -> develop
- develop -> (rebase) -> staging
- staging -> (rebase) -> release
Why must cherry-pick be used to merge into develop?
Use merge to merge, if there is a conflict, a fork will occur; dev-*
many and complicated branches, and direct merge to develop will produce intricate forks, making it difficult to sort out the progress of the submission.
And cherry-pick only merges the required commits into the develop branch, and does not generate forks, so that the git commit graph (git graph) will always maintain a straight line.
In addition, after the module development branch is completed, multiple commits need to be combined into one commit, and then merged into the develop branch to avoid redundant commits, which is one of the reasons for not using merge.
Why must rebase be used to merge into staging/release?
Release is translated into rebase, and merge also does not produce forks. When develop has updated many features to be merged into staging tests, it is impossible to merge commits one by one with cherry-pick. Therefore, it needs to be merged at one time through rebase, and it is guaranteed that staging and develop are completely synchronized.
The same is true for release. After the test is passed, use rebase to merge staging at one time, which also ensures that staging and release are completely synchronized.
commit specification and commit validation
The commit specification refers to the description information filled in when git commit, which must conform to the unified specification.
Just imagine, if the commits of team members are filled in at will, when collaboratively developing and reviewing the code, other people have no idea what functions the commit has completed or what bugs have been fixed, and it is difficult to control the progress.
In order to visually see the updated content of commits, the developer community has created a specification that divides commits according to their functions and adds some fixed prefixes, such as fix:
and feat:
, to mark what the commit mainly does.
The current mainstream prefixes include the following parts:
build
: Indicates build, release version is available with thisci
: Update automation configuration like CI/CDchore
: Miscellaneous, other changesdocs
: Updated documentationfeat
: Commonly used, indicating new functionsfix
: Commonly used: Indicates bug fixesperf
: Performance optimizationrefactor
: Refactoringrevert
: code rollbackstyle
: style changestest
: Unit test changes
These prefixes have to be written every time they are submitted, and many people still can't remember them at the beginning. A very useful tool is recommended here, which can automatically generate prefixes. The address is at here
First install globally:
npm install -g commitizen cz-conventional-changelog
Create a ~/.czrc
file and write the following content:
{ "path": "cz-conventional-changelog" }
Now you can use the git cz
command instead of git commit
command, the effect is as follows:
Then arrow up and down to select the prefix, and you can easily create a submission that conforms to the specification according to the prompts.
After the specification is in place, it is not enough to rely on people's conscious compliance, and the submitted information must be verified in the process.
At this time, we need to use a new thing - git hook
, which is the git hook.
The role of a git hook is to trigger custom scripts before and after a git action occurs. These actions include committing, merging, pushing, etc. We can use these hooks to implement our own business logic in all aspects of the git process.
Git hooks are divided into client-side hooks and server-side hooks.
There are four main client hooks:
pre-commit
: run before submitting information to check the code in the staging areaprepare-commit-msg
: not commonly usedcommit-msg
: Very important, use this hook to check commit informationpost-commit
: run after commit is complete
Server-side hooks include:
pre-receive
: Very important, various checks before push are herepost-receive
: not commonly usedupdate
: not commonly used
Most teams verify on the client side, so we use the commit-msg
hook to verify the commit information on the client side.
Fortunately, we do not need to manually write the verification logic, the community has a mature solution: husky + commitlint
husky is an artifact for creating git client hooks, and commitlint is to verify whether the commit information conforms to the above specifications. The combination of the two can prevent the creation of commits that do not conform to the commit specification, and guarantee the commit specification from the source.
For the specific usage of husky + commitlint, please see here
Misuse of the withdrawal plan
Frequent use of git to pull and push code in development will inevitably lead to misoperation. Don't panic at this time, git supports the withdrawal scheme of most scenarios, let's summarize.
The withdrawal is mainly two orders: reset
and revert
git reset
The principle of the reset command is to restore the version according to commitId
. Because each commit generates a commitId, reset can help you revert to any version in history.
The version and commit here are the same, a commitId is a version
The format of the reset command is as follows:
$ git reset [option] [commitId]
For example, to withdraw to a commit, the command would be:
$ git reset --hard cc7b5be
In the above command, how is the commitId obtained? It's very simple. Use the git log
command to view the commit record, and you can see the commitId value. This value is very long. We can take the first 7 digits.
The option here is --hard
. In fact, there are 3 values. The specific meanings are as follows:
--hard
: undo commit, undo add, delete workspace change code--mixed
: Default parameter. Revoke commit, revoke add, restore workspace change code--soft
: revoke commit, do not revoke add, restore the code changed in the workspace
Pay special attention to --hard
here, restoring with this parameter will delete the workspace code. That is to say, if there is uncommitted code in your project, using this parameter will delete it directly, it cannot be restored, be careful!
In addition to reverting with commitId, git reset also provides a shortcut to revert to the last commit:
$ git reset --soft HEAD^
HEAD^
means the previous commit, can be used multiple times.
In fact, the most common misoperation in daily development is this: just after submitting, suddenly found a problem, such as the submission information is not written well, or the code change is missing, then you need to withdraw to the last submission, modify the code, and then resubmit.
The process is roughly like this:
# 1. 回退到上次提交
$ git reset HEAD^
# 2. 修改代码...
...
# 3. 加入暂存
$ git add .
# 4. 重新提交
$ git commit -m 'fix: ***'
For this process, git also provides a more convenient method:
$ git commit --amend
This command will directly modify the current commit information. If the code is changed, execute git add
first, and then execute this command, which is faster and more convenient than the above process.
There is also a very important feature of reset, that is, is a true backward version of .
What does that mean? For example, the current commit, you have pushed to the remote warehouse; now you use reset to withdraw a commit, at this time the local git warehouse is one version behind the remote warehouse. At this point, if you push again, the remote repository will refuse and ask you to pull first.
If you need the remote warehouse to also roll back the version, you need -f
parameter to force the push, and the local code will overwrite the remote code.
Note, the -f
parameter is very dangerous! If you are not very familiar with git principle and command line, remember not to use this parameter.
How can it be safer to revoke the code of the previous version and synchronize it to the remote?
The solution is the second command to be said below: git revert
git revert
The role of revert and reset is the same as restoring the version, but they are implemented in different ways.
To put it simply, reset directly restores to the previous commit, and the workspace code is naturally the code of the previous commit; while revert is to add a new commit, but this commit uses the code of the previous commit.
Therefore, the two restored codes are the same, the difference is a new commit (revert) and a rollback commit (reset).
Because revert is always adding new submissions, the local warehouse version can never be behind the remote warehouse, and can be pushed directly to the remote warehouse, thus solving the problem of adding -f
parameters to push after reset, and improving security.
After talking about the principle, let's take a look at how to use it:
$ git revert -n [commitId]
It is very simple to use after mastering the principle, as long as one commitId is enough.
Tag and production environment
Git supports tagging a commit in history, which is often used to identify important version updates.
The current common practice is to use tags to represent the version of the production environment. When the latest commit passes the tests and is ready for release, we can create a tag representing the production version to release.
For example, I want to send a version of v1.2.4
:
$ git tag -a v1.2.4 -m "my version 1.2.4"
Then you can view:
$ git show v1.2.4
> tag v1.2.4
Tagger: ruims <2218466341@qq.com>
Date: Sun Sep 26 10:24:30 2021 +0800
my version 1.2.4
Finally push the tag to the remote with git push:
$ git push origin v1.2.4
Note here : the tag has nothing to do with which branch it was created in, the tag is just the alias of the commit. Therefore, the ability tag of commit can be used, such as the git reset
and git revert
commands mentioned above.
When there is a problem in the production environment and a version rollback is required, you can do this:
$ git revert [pre-tag]
# 若上一个版本是 v1.2.3,则:
$ git revert v1.2.3
In a warehouse with frequent updates and a large number of commits, using tags to identify versions is obviously cleaner and more readable.
Think about the usefulness of tags from another angle.
As mentioned in the branch management strategy section above, the release branch is synchronized with the production code. In the CI/CD (discussed below) continuous deployment process, we listen to the release branch for pushes and trigger automatic builds.
Is it possible to listen to the tag push and then trigger the automatic build, so that the intuitiveness of the version update is better?
There are many uses to be considered.
Permanently eliminate 443 Timeout
The code repository within our team is GitHub. For well-known reasons, GitHub pulls and pushes very slowly, and even reports an error: 443 Timeout.
The plan we started was to turn on VPN for all staff. Although the speed is good most of the time, there are occasional hours or even a day when the code cannot be pushed up, which seriously affects the development progress.
Later, I suddenly thought that the slow time-out was due to the wall, for example, the GitHub homepage could not be opened. Looking at the root cause, the wall is the http or https protocol when accessing the website, so other protocols will not have a wall?
Do it when you think of it. We found that GitHub supports the https
protocol in addition to the default ssh
protocol. So ready to try cloning the code using the ssh protocol.
One of the more troublesome things about using the ssh protocol is to configure password-free login, otherwise, you need to enter the account password every time you pull/push.
The official documentation for configuring SSH on GitHub is at here
Students who are struggling with English can read here
In short, after generating the public key, open the GitHub homepage, click Account -> Settings -> SSH and GPG keys -> Add SSH key , and then paste the public key into it.
Now, we clone the code with the ssh protocol, the example is as follows:
$ git clone git@github.com:[organi-name]/[project-name]
Found that it was cloned in an instant! Test pull/push several times, and the speed will fly!
No matter which code management platform you use, if you encounter the 443 Timeout problem, please try the ssh protocol!
Hook to achieve deployment?
Using git hook to implement deployment should be an advanced application of hook.
Now there are many tools, such as GitHub and GitLab, which provide continuous integration functions, that is, monitor the push of a certain branch, and then trigger automatic builds and automatic deployments.
In fact, no matter how many tricks these tools have, the core functions (listening and building) are still provided by git. It's just that the core functions are better integrated with its own platform.
Today, we will put aside these tools, trace the source, and use pure git to realize the automatic deployment of a react project. Mastering this core logic makes continuous deployment on any other platform less mysterious.
Since this part has a lot of content, an article is removed separately, and the address is as follows:
Pure Git implements front-end CI/CD
Ultimate Application: CI/CD
Some of the above places also mentioned continuous integration and continuous deployment. Now, the protagonist has officially debuted!
It can be said that all the specification rules written above are for better design and implementation of this protagonist --- CI/CD.
First of all, what is CI/CD?
The core concept, CI (Continuous Integration) is translated into continuous integration, CD includes two parts, continuous delivery (Continuous Delivery) and continuous deployment (Continuous Deployment)
Looking at the , CI/CD is a method of frequently applications to customers by automating the process. This process runs through the entire lifecycle of an application's integration, testing, delivery, and deployment, and is collectively referred to as the "CI/CD pipeline".
Although both are automated pipelines like assembly lines, CI and CD have their own divisions of labor.
Continuous integration is the frequent integration of code into the trunk branch. When new code is submitted, build and test will be automatically executed, and if the test passes, it will be automatically merged into the main branch, which realizes rapid product iteration while maintaining high quality.
Continuous Delivery is the frequent delivery of new versions of software to the quality team or users for review. After the review is passed, the production environment can be released. Continuous Delivery requires code (the latest commit on a branch) to be in a release-ready state.
Continuous deployment is the automatic deployment to the production environment after the code passes the review. Continuous deployment requires code (the latest commit on a branch) to be ready to deploy.
The only difference between continuous deployment and continuous delivery is the step of deploying to the production environment, whether is automated .
Deployment automation may seem like a small step, but in practice you will find that it is the most difficult part of the CI/CD pipeline to implement.
Why? First, from continuous integration to continuous delivery, these links are all implemented by the development team. We collaborated within the team to produce a new version of the application to be released.
However, deploying the application to the server is the job of the operations team. If we want to implement deployment, we must communicate with the operation and maintenance team. However, the development students do not understand the server, and the operation and maintenance students do not understand the code, so communication is difficult.
In addition, operation and maintenance is manual deployment. If we want to achieve automatic deployment, we must have server permissions and interact with the server. This is also a big problem, because the ops team must be concerned about security issues, so the promotion is hindered.
At present, there are many mature CI/CD solutions in the community, such as the old jenkins , the circleci 162438d7f7611f used by react, and the GitHub that I think is the best use of the system among.
This article is already quite long, so let's end it here. Next, I will publish a detailed CI/CD practice for react front-end projects based on GitHub Action. Remember to pay attention to my column.
Wonderful past
This column will output long-term articles on front-end engineering and architecture, which have been published as follows:
- Pure Git implements front-end CI/CD
- Front-end architect magic skills, three-stroke unified code style
If you like my article, please like and support me! Also welcome to follow my column, thanks 🙏🙏
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。