招聘时间

咳咳,在进入正题之前,发一个团队的招聘小广告:

想要参与万亿级别的项目吗?想要跟来自海内外大厂、顶尖高校的大佬们做同事吗?想要和字节一同跳动吗?

欢迎加入抖音电商前端团队,在这里你能够接触到业内前沿的前端技术,找到自己感兴趣的方向进行深研,和公司、团队一同生长。

假设感兴趣的话,欢迎点击岗位信息 进行投递~

等待你的加入~

一、背景

git 是一个分布式版别控制软件,开始由林纳斯托瓦兹创造,于 2005 年以 GPL 发布。开始意图是为更好地办理 Linux 内核开发而规划。

Git 有许多优势,现在是许多团队(当然也包括作者的团队)仅有运用的代码版别控制软件,为了让大家更加方便、标准地运用 Git,本文收拾了作者的团队的 Git 标准、常见场景实践、留意事项、常见问题。

二、强制标准

My-Git Flow 工作流

  1. 有且仅有 master 分支用于出产环境的布置,一切布置出产环境的 SCM 包分支来历必须是 master
  1. master 是受维护的分支,任何人都不能推送代码至 master
  1. 任何新改动都需求从 master 派生出一个分支,并且为其起一个描绘新改动内容的姓名:比方 feat/2198234-add-error-boundary
  1. 在本地提交该新分支改动,并且应常常性的向服务器端该同名分支推送改动
  1. 在新分支能够兼并(即需求完成测试即将上线)的时分,新建一个 merge request
  1. 只有在其他人 review 通过之后,新分支才允许兼并到 master 分支

分支办理

分支命名

分支命名应该遵从尽量语义化,假设有相关的 meego,尽量在分支命名中体现出来。

// Good cases
feat/2198234-add-error-boundary
fix/api-error-message
// Bad cases
text
hotfix-xiaowang
dev-xiaowang

Commit 标准

Commit Message

Commit Message 应遵从 Conventional commits 标准。

团队的项目中应该接入 Commitizen Commitlint 来对 commit message 进行标准和校验。

<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

全体格式阐明:

  1. Commit message 都包括三个部分:Header,Body 和 Footer。
  1. 其间,Header 是必需的,Body 和 Footer 能够省略
  1. Header,Body 和 Footer 之前用空行分隔。
  1. 每一行内容长度都不能超越100个字符
# header: <type>(<scope>): <subject>,100-character line
# - type: feat, fix, docs, style, refactor, test, chore
# - scope: can be empty (eg. if the change is a global or difficult to assign to a single component)
# - subject: start with verb (such as 'change')
#
# body: 100-character wrapped. This should answer:
# * Why was this change necessary?
# * How does it address the problem?
# * Are there any side effects?
#
# footer: reserved field
# - BREAKING CHANGE: description
# - Closes #123, #245, #992
type(必需)

type 用来阐明 commit 的类别,只允许运用下面的标识:

Changelog 装备参阅:假设 typefeatfix ,则该 commit 信息将必定呈现在 change log 之中。其他情况(docschorestylerefactortest)再定,主张是不要。

feat: A new feature
fix: A bug fix(code、UI)
docs: Documentation only changes
perf: A code change that improves performance
refactor: A code change that neither fixes a bug nor adds a feature
style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
test: Adding missing tests or correcting existing tests
build: Changes that affect the build system or external dependencies
ci: Changes to our CI configuration files and scripts
chore : Other changes that don't modify src or test files
revert: Reverts a previous commit. If the commit reverts a previous commit, it should begin with revert: , followed by the header of the reverted commit. In the body it should say: This reverts commit <hash>., where the hash is the SHA of the commit being reverted.
scope(可选)

scope 用于阐明 commit 影响的规模,比方影响哪个模块或者功用等。推荐按功用描绘。

subject(必需)

subject 是关于 commit 信息的简略描绘。

Commit message 示例
// good case
feat(页面A): 新增 B 模块
- 添加一致的面包屑布局
- 抽象公共 ProTable 组件,封装了挑选栏、分页器、数据获取
- 晋级 antd 组件库版别号至 2.9.0
// bad case
fix: xiaowang
chore: 修正案牍
fix: 修正线上问题

Commit 原子性

倡议最小粒度 commit 准则,准则上每个独立的改动对应一个 commit。

为了更好的盯梢提交前史以及回溯,要保证 commit 的“原子性”,每个 commit 要以适当的粒度包括且仅包括“单项”改动,防止过多的暂时 commit;提交代码时应该让每个 commit 都更具有意义,而不是散乱随意的 commit。

判别准则参阅:commit 粒度尽量小,且只提交该单个 commit 时功用能够正常运转。

Squash Commits

基于 commit 原子性准则,应防止将过于零星的 commit 提交兼并到骨干分支。对于需求或者功用的 commit,尤其是在协作开发时,假设 commit 过于暂时或零星,应整组成一个 commit 再提交到骨干保证骨干前史简练有用

squash commits 能有用削减 rebase 方法兼并时的抵触,能简化处理抵触的过程;频繁暂时的 commit 导致多个无意义提交,简略引起他人困惑。

留意:现已兼并到骨干的 commit,不能进行 squash,改动骨干(协作)分支前史会导致其他人无法正常同步。

暂时 commits 的处理方案

假设你的工作常常被打断,导致呈现许多暂时的 commits,那么你或许需求善用 git stash 技巧。

三、操作主张

Rebase vs Merge

关于 Rebase 和 Merge 的评论,能够参阅这篇文章。

异同总结

  • Rebase 和 Merge 都能够用来兼并不同分支的 commits
  • Merge 能够坚持修正内容的前史记载,可是前史记载会很杂乱,关注点在于实在的操作记载
  • Rebase 前史记载简略(线性),是在原有提交的基础大将差异内容反映进去
Merge Rebase
Git 实践规范分享
Git 实践规范分享

推荐操作

  • 兼并 master 分支的最新代码至本地分支,请运用 git rebase master
  • 将本地代码合入公共分支,请运用 merge(提交 merge request)

四、Git 装备及东西

必要的大局装备

  • git config --global user.name [YOUR_NAME]
  • git config --global user.email [YOUR_EMAIL]
  • git config --global core.ignorecase false

依照自己的习气和喜爱的装备

  • git config --global push.default current
  • git config --global alias.co checkout
  • git config --global alias.ci commit
  • git config --global alias.br branch
  • git config --global alias.rb rebase
  • git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

设置 Git 的 SSH-Keys

  1. 访问个人主页的 SSH Keys 设置页面
  1. 在本地生成 SSH 公钥

    1. 先承认是否已有 SSH 公钥(默许情况下,用户的 SSH 密钥存储在其 ~/.ssh 目录下。 进入该目录并列出其间内容,你便能够快速承认自己是否已具有密钥)
    2. ls ~/.ssh
      // 假设有 id_rsa、id_rsa.pub 这两个文件,则已存在 SSH 公钥,将 id_rsa.pub 的内容拷贝至 SSH Keys 设置页面即可
      // windows 上是 id_ecdsa 和 id_ecdsa.pub 文件
      
    3. 假设上一步没找到 SSH 公钥,则手动生成
    4. ssh-keygen
      // 这个指令会问询生成的位置、密钥口令等,直接默许就行
      // windows 上:ssh-keygen -t ecdsa -C "xxxxxx@bytedance.com"
      
    5. 拷贝公钥至 SSH Keys 的设置页面
    6. cat ~/.ssh/id_rsa.pub
      // 形如下:
      ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU
      GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3
      Pbv7kOdJMTasjhfashjfgasjhfgahsjfgashjfgahjsgashjfgahjsfgaahfjsasfhj=@mylaptop.local
      

装置 Git Commit 指令行东西 —— Commitizen

yarn global add commitizen cz-conventional-changelog
echo '{ "path": "cz-conventional-changelog" }' > ~/.czrc

运用效果

Git 实践规范分享

VSCode 插件

GitLens —— 检查 Git 提交记载,找到代码的提交者

Git 可视化东西

  • SourceTree

直接用指令行检查 git 的 diff 是非常高效的,并且也非常契合高端程序员的气质,可是需求记住的指令也是非常多。作为一个懒惰的程序员,咱们就需求一些可视化东西来辅佐咱们检查 diff 和处理抵触。SourceTree 是一个界面美丽、功用强大且免费的东西。请留意,SourceTree 应该是一个辅佐东西,它协助咱们更方便检查代码,咱们不应该依靠它去提交代码。

  • VSCode 内置东西
  • Git-Fork
  • Gitkraken
  • Tower

五、常见场景

接下来,让咱们看一些工作中运用 Git 常见的场景。

基本场景:

新拉取项目

git clone git@code.byted.org:XXX/XXXX.git

新建分支

// 从当时分支新建
git checkout -b NEW_BRANCH_NAME
// 基于远端分支新建分支
git checkout -b NEW_BRANCH_NAME origin/REMOTE_BRANCH_NAME(长途分支称号)

推送代码至远端分支

git push origin REMOTE_BRANCH_NAME

拉取远端改动

// 拉取远端一切改动
git fetch
// 把长途分支上的内容都拉取到本地
git pull origin REMOTE_BRANCH_NAME [--rebase]

兼并长途分支到本地

常见于长途的 master 或其他分支有改动,并且这部分改动需求合入当时分支。(此处以 master 为例)

git checkout master
git pull --rebase
git checkout YOUR_BRANCH
git rebase master (此处也能够运用 merge)
// rebase 之后,将代码 push 到远端,因为此处改动了当时分支的提交前史,因此或许需求 --force-with-lease
git push origin YOUR_BRANCH --force-with-lease

兼并分支到 master

  1. 在 gitlab 上手动提交 MergeRequest

  2. 在他人 Approve 之后,点击 merge 合入 master(主张勾选 「Squash commits」)

Git 实践规范分享

暂存及康复修正(stash)

常见于暂时切换分支,且不想放弃或提交当时的修正。

// 将当时修正放入暂存区,能够在 save 之后加入暂存的信息
git stash [save][message] 
// 检查当时暂存区清单
git stash list
// 康复暂存区的修正,仅运用"git stash pop" 将康复到最新的操作。指定stash ID (如:stash@{1} ),则能够康复特定的操作。
git stash pop [ID]
// 删去暂存的操作, 假设运用 "git stash drop",会删去最新的操作。指定stash ID (如:stash@{1} ),则能够删去特定的操作。
git stash drop [ID]

装备长途目录

git remote add origin git@code.byted.org:xxx/XXX.git

新建项目

// 1. 新建 .git 文件
git init
// 2. 装备长途目录
git remote add origin git@code.byted.org:xxx/XXX.git
// 3. 推送文件至远端的 master 分支(完成后需求去远端设置 master 为受维护分支)
git push -u origin master

\

杂乱场景

紧缩(兼并)提交

常见于本地分支有多次 commits,其间全部或部分 commits 能够兼并为一次有语义的 commit

// 1. 利用 rebase -i 兼并 commits,其间的 COMMIT_HASH 是需求兼并的 commits 的鸿沟(不包括)
git rebase -i COMMIT_HASH
// 2. 在 vim 界面修正需求保存和 squash 的 commits,能够紧缩修正成 s

紧缩前的 git log 信息:

Git 实践规范分享

假设咱们想兼并 e75a64c ~ cc21dbe 这部分提交:

git rebase -i 2701084

修正需求保存的 commit 信息

Git 实践规范分享

兼并后的 git log 信息

Git 实践规范分享

处理抵触

处理抵触常见于在本地 rebase 或 merge master 的改动,此处以 rebase master 为例:

// 为了削减处理抵触的次数,主张本地先 squash commits(通过上面的兼并提交)
git rebase -i COMMIT_HASH
// rebase master 的改动
git rebase master
// 手动处理抵触
// 处理完抵触之后,继续 rebase
git add .
git rebase --continue

留意:处理抵触遇到困难时(比方不知道该选用谁的提交),主张直接找到代码的提交者,当面处理。

// 暂停当时的兼并操作
git rebase --abort

Revert 代码

通常情况下,代码合入 master 分支的时机是在上线前。因为误操作、提早合入后被告知无法发布等原因导致代码被误合入 master,为了防止影响后续上线同学和线上环境,咱们或许需求及时 revert 现已合入 master 的代码。

Revert 的原理就是提交一个逆向 commit,对之前的 commits 进行 undo 操作,而不是抹除之前的 commits 在 git 中的记载

  1. 进入需求 revert 的 merge request 链接,直接点击 Revert 按钮。

Git 实践规范分享

  1. 如平常提交 Merge Request 相同,在这里提交 revert 信息

Git 实践规范分享

刚刚的 revert 操作帮咱们做了三件事:

  • 生成新分支:revert-COMMIT_HASH
  • 提交 undo 的 commit 「fix: revert “Merge branch ‘chore/competitor-shop’ into ‘master'”」
  • 提交 merge request
  1. 咱们能够在新生成的 revert-COMMIT_HASH 上进行修正操作,也能够在他人 Approve 之后将 merge request 合入 master,合入 master 之后,本次 revert 操作就大功告成了。
  1. 康复 revert:通过上面的操作后,咱们的代码现已从 master 分支上消失了,可是咱们的提交记载还在 master 分支上。假设此刻再从本来的分支提交 merge request,你会发现 「0 file changed」。假设想从头找回之前修正的代码,此刻需求对 revert 进行 revert, 原因见这篇文章。步骤同上。

吊销提交

// 吊销最近一次提交,并保存代码,吊销 add 的状态
git reset --mixed HEAD~1
// 吊销最近一次提交,并保存代码,保存 add 的状态
git reset --soft HEAD~1
// 吊销最近一次提交,并删去代码
git reset --hard HEAD~1

修正提交

景象一:重写最近的提交音讯
git commit --amend
景象二:修正旧提交或者多个提交的音讯,运用 rebase -i(类似于兼并提交)
git rebase -i COMMIT_HASH

此列表将类似于以下内容:

pick e499d89 Delete CNAME
pick 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.
# Rebase 9fdb3bd..f7fde4a onto 9fdb3bd
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

在要更改的每个提交音讯的前面,用 reword 替换 pick

pick e499d89 chore: Delete CNAME
reword 0c39034 fix: Better README
reword f7fde4a feat: Change the commit message but push the same commit.

多人协作

假设有一个功用需求多个人协同开发,请运用一个约好的公共分支随时同步你们的代码,以免抵触并且方便联调。且应该像对待 master 相同对待你们的公共分支(即不能直接推送代码至公共分支)。假设有 A,B 两个人一同开发一个新功用叫 achievement

初始化本地分支

在 A 的电脑上:

git checkout master
git pull --rebase
git checkout -b feat/achievement
git push
git checkout -b feat/achievement-a

在 B 的电脑上:

git fetch
git checkout feat/achievement
git checkout -b feat/achievement-b
A 和 B 需求常常更新代码至远端,并合入公共分支

在 A 这边:

// on branch feat/achievement-a
git checkout feat/achievement
git pull --rebase
git checkout feat/achievement-a
git rebase feat/achievement // 或许要处理抵触
git push
// 提交 merge request,将 feat/achievement-a 的提交合入公共分支

在 B 这边:

// on branch feat/achievement-b
git checkout feat/achievement
git pull --rebase
git checkout feat/achievement-b
git rebase feat/achievement //或许要处理抵触
git push
// 提交 merge request,将 feat/achievement-b 的提交合入公共分支

协作开发的时分抵触是非常常见的。不要惧怕抵触,应该尽早处理抵触。养成频繁 rebase ,频繁更新公共分支的习气。

六、留意事项

切换 git 账号的 SSH-Key

实现方法参阅这篇文章。

在公司电脑上进行这样的操作非常危险,强烈主张不要在公司的电脑上进行自己的 github 开发!!!

七、常见问题

此处收拾一些运用 Git 时的常见问题:

未初始化 git

场景复原:fatal: not a git repository (or any of the parent directories): .git

报错原因:未初始化 git(没有 .git 目录)

处理方案:git init

未相关长途分支

场景复原:git push 时报错——fatal: The current branch xxx has no upstream branch.

报错原因:未相关长途分支

处理方案:git push --set-upstream origin xxx

落后长途分支

场景复原:git push 时报错——pdates were rejected because the tip of your current branch is behind its remote counterpart

报错原因:当时分支落后于长途分支

处理方案:需求先拉取远端的更新,再进行 push

git pull --rebase origin YOUR_BRANCH
git push origin YOUR_BRANCH

附:

Git 学习东西:learngitbranching.js.org/?locale=zh_…