git-workflow

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Git Workflow

Git 工作流

Conventional Commit Format

规范提交格式

<type>(<scope>): <description>

[optional body]

[optional footer(s)]
<type>(<scope>): <description>

[可选正文]

[可选页脚]

Commit Types

提交类型

TypePurposeExample
feat
New feature for the user
feat(auth): add OAuth2 login flow
fix
Bug fix for the user
fix(cart): correct quantity calculation
refactor
Code change that neither fixes nor adds
refactor(api): simplify request middleware
docs
Documentation only changes
docs(readme): add setup instructions
test
Adding or correcting tests
test(auth): add login failure scenarios
chore
Maintenance tasks, dependencies
chore(deps): upgrade lodash to 4.17.21
perf
Performance improvement
perf(query): add index for user lookup
style
Formatting, whitespace, semicolons
style(lint): fix indentation in models
ci
CI configuration and scripts
ci(actions): add Node 20 to test matrix
revert
Reverts a previous commit
revert: revert feat(auth) commit abc123
类型用途示例
feat
为用户添加新功能
feat(auth): add OAuth2 login flow
fix
修复用户侧的Bug
fix(cart): correct quantity calculation
refactor
既不修复Bug也不添加新功能的代码变更
refactor(api): simplify request middleware
docs
仅修改文档
docs(readme): add setup instructions
test
添加或修正测试用例
test(auth): add login failure scenarios
chore
维护任务、依赖更新
chore(deps): upgrade lodash to 4.17.21
perf
性能优化
perf(query): add index for user lookup
style
格式调整、空格、分号修改
style(lint): fix indentation in models
ci
CI配置和脚本修改
ci(actions): add Node 20 to test matrix
revert
回滚之前的提交
revert: revert feat(auth) commit abc123

Commit Message Rules

提交消息规则

  • Subject line: max 72 characters, imperative mood, no trailing period
  • Body: wrap at 80 characters, explain what and why (not how)
  • Footer: reference issues with
    Closes #123
    or
    Refs #456
  • Breaking changes: add
    BREAKING CHANGE:
    in the footer or
    !
    after type
feat(api)!: change authentication endpoint response shape

The /auth/login endpoint now returns a nested token object instead
of a flat structure. This aligns with our OAuth2 token standard.

BREAKING CHANGE: response.token is now response.auth.access_token
Closes #892
  • 主题行:最多72个字符,使用祈使语气,末尾无句号
  • 正文:每行不超过80个字符,说明做了什么以及为什么(而非怎么做)
  • 页脚:用
    Closes #123
    Refs #456
    关联议题
  • 破坏性变更:在页脚添加
    BREAKING CHANGE:
    ,或在类型后加
    !
feat(api)!: change authentication endpoint response shape

The /auth/login endpoint now returns a nested token object instead
of a flat structure. This aligns with our OAuth2 token standard.

BREAKING CHANGE: response.token is now response.auth.access_token
Closes #892

Commit Atomicity

提交原子性

Each commit must represent exactly one logical change.
  • Address a single concern (one bug fix, one feature slice, one refactor)
  • Leave the codebase in a working state (tests pass, code compiles)
  • Be revertable without side effects on unrelated code
  • Include related test changes alongside the code change
  • Never mix formatting with logic changes
  • Never bundle unrelated bug fixes together
bash
undefined
每个提交必须恰好代表一个逻辑变更。
  • 解决单一关注点(一个Bug修复、一个功能片段、一次重构)
  • 提交后代码库处于可工作状态(测试通过、代码可编译)
  • 可回滚且不会对无关代码产生副作用
  • 代码变更时同步包含相关测试修改
  • 永远不要将格式调整与逻辑变更混合
  • 永远不要将无关的Bug修复捆绑在一起
bash
undefined

Stage specific hunks, specific files, then verify

暂存特定代码块、特定文件,然后验证

git add -p git add src/auth/login.ts src/auth/login.test.ts git diff --cached
undefined
git add -p git add src/auth/login.ts src/auth/login.test.ts git diff --cached
undefined

Interactive Rebase

交互式变基

bash
git rebase -i HEAD~5      # Rebase last N commits
git rebase -i main        # Rebase onto a branch
bash
git rebase -i HEAD~5      # 变基最近N个提交
git rebase -i main        # 变基到指定分支

Rebase Commands

变基命令

CommandShortEffect
pick
p
Keep the commit as-is
reword
r
Keep the commit but edit the message
edit
e
Pause to amend the commit (add files, split)
squash
s
Merge into the previous commit, keep message
fixup
f
Merge into previous commit, discard message
drop
d
Remove the commit entirely
Squash WIP commits:
pick   a1b2c3d feat(auth): add login endpoint
fixup  e4f5g6h wip
fixup  i7j8k9l fix tests
Fixup a commit further back:
bash
git commit --fixup=<target-sha>
git rebase -i --autosquash main
Split a commit (mark as "edit"):
bash
git reset HEAD~1
git add src/models/user.ts
git commit -m "refactor(models): extract user validation"
git add src/routes/auth.ts
git commit -m "feat(auth): add login route"
git rebase --continue
命令缩写效果
pick
p
保留提交原样
reword
r
保留提交但修改提交消息
edit
e
暂停以修改提交(添加文件、拆分)
squash
s
合并到前一个提交,保留提交消息
fixup
f
合并到前一个提交,丢弃提交消息
drop
d
完全移除提交
合并WIP提交:
pick   a1b2c3d feat(auth): add login endpoint
fixup  e4f5g6h wip
fixup  i7j8k9l fix tests
修复更早的提交:
bash
git commit --fixup=<target-sha>
git rebase -i --autosquash main
拆分提交(标记为"edit"):
bash
git reset HEAD~1
git add src/models/user.ts
git commit -m "refactor(models): extract user validation"
git add src/routes/auth.ts
git commit -m "feat(auth): add login route"
git rebase --continue

Merge vs Rebase

合并 vs 变基

Use RebaseUse Merge
Updating feature branch from mainIntegrating feature branch into main (
--no-ff
)
Cleaning up local commits before pushingShared branches others have based work on
Maintaining linear history on personal branchPreserving context of parallel development
  • Never rebase commits pushed to a shared branch
  • Always rebase local work before pushing
  • Use
    git pull --rebase
    to avoid unnecessary merge commits
bash
git checkout feature/login && git rebase main          # Update feature
git checkout main && git merge --no-ff feature/login   # Merge feature
使用变基的场景使用合并的场景
从主分支更新功能分支将功能分支合并到主分支(
--no-ff
推送前清理本地提交其他开发者已基于此分支开展工作的共享分支
在个人分支上维护线性提交历史保留并行开发的上下文
  • 永远不要对推送到共享分支的提交执行变基
  • 推送前务必对本地工作执行变基
  • 使用
    git pull --rebase
    避免不必要的合并提交
bash
git checkout feature/login && git rebase main          # 更新功能分支
git checkout main && git merge --no-ff feature/login   # 合并功能分支

Conflict Resolution

冲突解决

  1. Identify:
    git status
    -- look for "both modified" entries
  2. Understand both sides:
    bash
    git show :1:path/to/file    # base version
    git show :2:path/to/file    # ours (current branch)
    git show :3:path/to/file    # theirs (incoming branch)
  3. Resolve each conflict block, then mark resolved:
    bash
    git add path/to/file
    git rebase --continue    # or git merge --continue
StrategyWhen to Use
Accept oursTheir change is outdated or wrong
Accept theirsOur change was superseded
Manual mergeBoth changes are needed, combine them
Re-implementBoth sides diverged too far, rewrite the block
Abort with:
git merge --abort
or
git rebase --abort
  1. 识别冲突:
    git status
    -- 查找"both modified"条目
  2. 理解双方变更:
    bash
    git show :1:path/to/file    # 基础版本
    git show :2:path/to/file    # 我方(当前分支)
    git show :3:path/to/file    # 对方(待合并分支)
  3. 解决每个冲突块,然后标记为已解决:
    bash
    git add path/to/file
    git rebase --continue    # 或 git merge --continue
策略使用场景
接受我方变更对方变更已过时或不正确
接受对方变更我方变更已被替代
手动合并双方变更都需要,需合并两者
重新实现双方差异过大,重写代码块
终止操作:
git merge --abort
git rebase --abort

.gitignore Patterns

.gitignore 规则

gitignore
undefined
gitignore
undefined

Node.js # Python # Java / Kotlin

Node.js # Python # Java / Kotlin

node_modules/ pycache/ *.class dist/ *.py[cod] target/ *.log .venv/ build/ coverage/ *.egg-info/ .gradle/
node_modules/ pycache/ *.class dist/ *.py[cod] target/ *.log .venv/ build/ coverage/ *.egg-info/ .gradle/

IDE and OS # Secrets (always ignore)

IDE 和 系统文件 # 敏感信息(务必忽略)

.idea/ *.pem .vscode/ .key .DS_Store .env Thumbs.db !.env.example

| Pattern         | Matches                              |
|-----------------|--------------------------------------|
| `*.log`         | All .log files in any directory      |
| `/build`        | build directory in repo root only    |
| `build/`        | build directory anywhere             |
| `**/logs`       | logs directory at any depth          |
| `!important`    | Negate a previous ignore rule        |
| `doc/**/*.txt`  | txt files anywhere under doc/        |
.idea/ *.pem .vscode/ .key .DS_Store .env Thumbs.db !.env.example

| 规则         | 匹配对象                              |
|-----------------|--------------------------------------|
| `*.log`         | 所有目录下的.log文件      |
| `/build`        | 仅仓库根目录下的build目录    |
| `build/`        | 任意位置的build目录             |
| `**/logs`       | 任意层级下的logs目录          |
| `!important`    | 取消之前的忽略规则        |
| `doc/**/*.txt`  | doc目录下任意位置的txt文件        |

Git Hooks

Git 钩子

HookTriggerCommon Use
pre-commit
Before commit is createdLint, format, run fast tests
commit-msg
After message is writtenValidate conventional commit format
pre-push
Before push to remoteRun full test suite
prepare-commit-msg
Before editor opensAdd branch name or ticket number
bash
#!/usr/bin/env bash
钩子触发时机常见用途
pre-commit
提交创建前代码检查、格式化、运行快速测试
commit-msg
提交消息编写后验证提交消息是否符合规范格式
pre-push
推送到远程仓库前运行完整测试套件
prepare-commit-msg
编辑器打开前添加分支名或工单编号
bash
#!/usr/bin/env bash

.git/hooks/commit-msg

.git/hooks/commit-msg

commit_msg=$(cat "$1") pattern='^(feat|fix|refactor|docs|test|chore|perf|style|ci|revert)((.+))?(!)?: .{1,72}' if ! echo "$commit_msg" | grep -qE "$pattern"; then echo "ERROR: Commit message does not follow conventional format." exit 1 fi
undefined
commit_msg=$(cat "$1") pattern='^(feat|fix|refactor|docs|test|chore|perf|style|ci|revert)((.+))?(!)?: .{1,72}' if ! echo "$commit_msg" | grep -qE "$pattern"; then echo "ERROR: Commit message does not follow conventional format." exit 1 fi
undefined

Stashing

暂存操作

bash
git stash push -m "wip: login form validation"   # Save with message
git stash list                                     # List all stashes
git stash apply                                    # Apply most recent (keep in list)
git stash pop                                      # Apply and remove most recent
git stash apply stash@{2}                          # Apply specific stash
git stash drop stash@{0}                           # Drop specific stash
git stash clear                                    # Clear all stashes
git stash push -u -m "include new files"           # Include untracked files
git stash branch feature/from-stash stash@{0}      # Create branch from stash
bash
git stash push -m "wip: login form validation"   # 带消息保存暂存
git stash list                                     # 列出所有暂存
git stash apply                                    # 应用最近的暂存(保留在列表中)
git stash pop                                      # 应用并移除最近的暂存
git stash apply stash@{2}                          # 应用指定暂存
git stash drop stash@{0}                           # 删除指定暂存
git stash clear                                    # 清空所有暂存
git stash push -u -m "include new files"           # 包含未跟踪文件
git stash branch feature/from-stash stash@{0}      # 从暂存创建分支

Cherry-Picking

樱桃拣选(Cherry-Pick)

bash
git cherry-pick -x abc123              # Always use -x to record source
git cherry-pick abc123..def456         # Cherry-pick a range
git cherry-pick --no-commit abc123     # Stage only, do not commit
git cherry-pick --abort                # Abort a conflicted cherry-pick
The
-x
flag appends
(cherry picked from commit ...)
for traceability.
bash
git cherry-pick -x abc123              # 始终使用-x记录来源
git cherry-pick abc123..def456         # 拣选一系列提交
git cherry-pick --no-commit abc123     # 仅暂存,不提交
git cherry-pick --abort                # 终止冲突中的拣选操作
-x
参数会追加
(cherry picked from commit ...)
以保证可追溯性。

Git Bisect

Git 二分查找

bash
git bisect start
git bisect bad                         # Mark current state as bad
git bisect good v2.1.0                 # Mark a known good commit
bash
git bisect start
git bisect bad                         # 将当前状态标记为有问题
git bisect good v2.1.0                 # 标记已知正常的提交

Test each checkout, then: git bisect good / git bisect bad

测试每个检出版本,然后执行:git bisect good / git bisect bad

git bisect start HEAD v2.1.0 # Automate with a test script git bisect run npm test git bisect reset # When done, return to original state
undefined
git bisect start HEAD v2.1.0 # 使用测试脚本自动化执行 git bisect run npm test git bisect reset # 完成后返回原状态
undefined

Amending Commits Safely

安全地修改提交

bash
git commit --amend -m "fix(auth): correct token expiry check"
git add forgotten-file.ts && git commit --amend --no-edit
git commit --amend --author="Name <email@example.com>"
bash
git commit --amend -m "fix(auth): correct token expiry check"
git add forgotten-file.ts && git commit --amend --no-edit
git commit --amend --author="Name <email@example.com>"

Safety Checklist

安全检查清单

  • The commit has NOT been pushed to a shared branch
  • No one else has based work on this commit
  • Never amend commits on main, master, develop, or release branches
  • Use
    --force-with-lease
    instead of
    --force
    when pushing amended commits
  • 该提交尚未推送到共享分支
  • 没有其他人基于此提交开展工作
  • 永远不要修改main、master、develop或release分支上的提交
  • 推送修改后的提交时,使用
    --force-with-lease
    而非
    --force

Daily Workflow

日常工作流

bash
git checkout main && git pull --rebase
git checkout -b feature/ticket-123-description
git add -p && git commit -m "feat(module): add feature description"
git fetch origin && git rebase origin/main
git rebase -i origin/main              # Clean up before review
git push -u origin feature/ticket-123-description
bash
git checkout main && git pull --rebase
git checkout -b feature/ticket-123-description
git add -p && git commit -m "feat(module): add feature description"
git fetch origin && git rebase origin/main
git rebase -i origin/main              # 代码审查前清理提交
git push -u origin feature/ticket-123-description