网淘吧来吧,欢迎您!

返回首页 微信
微信
手机版
手机版

Git Workflows技能使用说明

2026-03-26 新闻来源:网淘吧 围观:87
电脑广告
手机广告

Git 工作流

适用于实际开发的高级 Git 操作。涵盖交互式变基、二分查找、工作树、引用日志恢复、子树、子模块、稀疏检出、冲突解决和单体仓库模式。

何时使用

  • 在合并前清理提交历史(交互式变基)
  • 查找哪个提交引入了错误(二分查找)
  • 同时处理多个分支(工作树)
  • 恢复丢失的提交或撤销错误操作(引用日志)
  • 跨仓库管理共享代码(子树/子模块)
  • 解决复杂的合并冲突
  • 跨分支或派生仓库挑选提交
  • 处理大型单体仓库(稀疏检出)

交互式变基

压缩、重新排序、编辑提交

# 交互式变基最近 5 个提交
git rebase -i HEAD~5

# 变基到 main 分支上(自分支分叉以来的所有提交)
git rebase -i main

编辑器会打开一个选择列表:

pick a1b2c3d 添加用户模型
pick e4f5g6h 修复用户模型中的拼写错误
pick i7j8k9l 添加用户控制器
pick m0n1o2p 添加用户路由
pick q3r4s5t 修复控制器中的导入

可用命令:

pick   = 原样使用提交
reword = 使用提交但编辑提交信息
edit   = 在此提交后暂停以修改它
squash = 合并到前一个提交中(保留两条提交信息)
fixup  = 合并到前一个提交中(丢弃此条提交信息)
drop   = 完全移除该提交

常见模式

# 将修复提交压缩到其父提交中
# 将修复提交的 "pick" 改为 "fixup":
pick a1b2c3d 添加用户模型
fixup e4f5g6h 修复用户模型中的拼写错误
pick i7j8k9l 添加用户控制器
fixup q3r4s5t 修复控制器中的导入
pick m0n1o2p 添加用户路由

# 重新排序提交(只需移动行)
pick i7j8k9l 添加用户控制器
pick m0n1o2p 添加用户路由
pick a1b2c3d 添加用户模型

# 将一个提交拆分为两个
# 标记为 "edit",然后在它暂停时:
git reset HEAD~
git add src/model.ts
git commit -m "添加用户模型"
git add src/controller.ts
git commit -m "添加用户控制器"
git rebase --continue

自动压缩(自动排列提交信息)

# 提交修复时,引用要压缩到的提交
git commit --fixup=a1b2c3d -m "修复拼写错误"
# 或者
git commit --squash=a1b2c3d -m "附加更改"

# 之后,使用自动压缩进行变基
git rebase -i --autosquash main
# fixup/squash 提交会自动放置在其目标提交之后

中止或继续

git rebase --abort      # 取消并恢复原始状态
git rebase --continue   # 在解决冲突或编辑后继续
git rebase --skip       # 跳过当前提交并继续

二分查找(定位 Bug)

通过提交记录进行二分查找

# 开始二分查找
git bisect start

# 将当前提交标记为有问题的(包含 Bug)
git bisect bad

# 标记一个已知良好的提交(在 Bug 出现之前)
git bisect good v1.2.0
# 或者:git bisect good abc123

# Git 会检出中间的一个提交。测试后,执行:
git bisect good   # 如果此提交没有 Bug
git bisect bad    # 如果此提交有 Bug

# 重复直到 Git 识别出具体的提交
# "abc123 是第一个有问题的提交"

# 完成 — 返回原始分支
git bisect reset

自动化二分查找(使用测试脚本)

# 全自动:Git 在每个提交上运行脚本
# 脚本必须返回 0 表示良好,1 表示有问题
git bisect start HEAD v1.2.0
git bisect run ./test-for-bug.sh

# 示例测试脚本
cat > /tmp/test-for-bug.sh << 'EOF'
#!/bin/bash
# 如果 Bug 不存在返回 0,如果存在返回 1
npm test -- --grep "login should redirect" 2>/dev/null
EOF
chmod +x /tmp/test-for-bug.sh
git bisect run /tmp/test-for-bug.sh

处理构建失败的二分查找

# 如果某个提交无法编译,跳过它
git bisect skip

# 跳过一个已知有问题的提交范围
git bisect skip v1.3.0..v1.3.5

工作树(并行分支)

同时处理多个分支

# 为其他分支添加工作树
git worktree add ../myproject-hotfix hotfix/urgent-fix
# 创建一个新目录并检出该分支

# 添加一个带有新分支的工作树
git worktree add ../myproject-feature -b feature/new-thing

# 列出所有工作树
git worktree list

# 完成后移除工作树
git worktree remove ../myproject-hotfix

# 清理过时的工作树引用
git worktree prune

使用场景

# 在不影响当前工作的情况下审查 PR
git worktree add ../review-pr-123 origin/pr-123

# 在功能分支上开发的同时在 main 分支上运行测试
git worktree add ../main-tests main
cd ../main-tests && npm test

# 并排比较不同分支的行为
git worktree add ../compare-old release/v1.0
git worktree add ../compare-new release/v2.0

恢复日志(Recovery)

查看Git记住的所有内容

# 显示恢复日志(所有HEAD移动记录)
git reflog
# 输出示例:
# abc123 HEAD@{0}: commit: 添加功能
# def456 HEAD@{1}: rebase: 移动到主分支
# ghi789 HEAD@{2}: checkout: 从功能分支切换到主分支

# 显示特定分支的恢复日志
git reflog show feature/my-branch

# 显示带时间戳的恢复日志
git reflog --date=relative

从错误中恢复

# 撤销错误的重设基底操作(在恢复日志中找到重设基底前的提交)
git reflog
# 找到:"ghi789 HEAD@{5}: checkout: 从功能分支切换到主分支"(重设基底前)
git reset --hard ghi789

# 恢复已删除的分支
git reflog
# 找到该分支上的最后一次提交
git branch recovered-branch abc123

# 在reset --hard操作后恢复
git reflog
git reset --hard HEAD@{2}   # 回退到恢复日志中的前两个条目

# 恢复已丢弃的暂存
git fsck --unreachable | grep commit
# 或
git stash list  # 如果它还存在
git log --walk-reflogs --all -- stash  # 查找已丢弃的暂存提交

拣选提交(Cherry-Pick)

将特定提交复制到另一个分支

# 拣选单个提交
git cherry-pick abc123

# 拣选多个提交
git cherry-pick abc123 def456 ghi789

# 拣选一个范围(起始提交不包含,结束提交包含)
git cherry-pick abc123..ghi789

# 拣选但不提交(仅暂存更改)
git cherry-pick --no-commit abc123

# 从其他远程仓库/分支拣选提交
git remote add upstream https://github.com/other/repo.git
git fetch upstream
git cherry-pick upstream/main~3   # 从上游主分支的第3个提交开始拣选

处理拣选过程中的冲突

# 如果出现冲突:
# 1. 在文件中解决冲突
# 2. 暂存已解决的文件
git add resolved-file.ts
# 3. 继续操作
git cherry-pick --continue

# 或中止操作
git cherry-pick --abort

子树和子模块

子树(更简单——将代码复制到你的仓库中)

# 添加子树
git subtree add --prefix=lib/shared https://github.com/org/shared-lib.git main --squash

# 从上游拉取更新
git subtree pull --prefix=lib/shared https://github.com/org/shared-lib.git main --squash

# 将本地更改推送回上游
git subtree push --prefix=lib/shared https://github.com/org/shared-lib.git main

# 将子树拆分为独立分支(用于提取)
git subtree split --prefix=lib/shared -b shared-lib-standalone

子模块(指向特定提交的另一个仓库指针)

# 添加子模块
git submodule add https://github.com/org/shared-lib.git lib/shared

# 克隆包含子模块的仓库
git clone --recurse-submodules https://github.com/org/main-repo.git

# 克隆后初始化子模块(如果忘记使用 --recurse 参数)
git submodule update --init --recursive

# 更新子模块至最新版本
git submodule update --remote

# 移除子模块
git rm lib/shared
rm -rf .git/modules/lib/shared
# 如果 .gitmodules 中仍有记录,请手动删除

使用场景对比

子树:更简单,克隆者无需特殊命令,代码直接存在于主仓库。
       适用场景:共享库、供应商代码、上游更新不频繁的情况。

子模块:指向精确提交,仓库体积更小,分离清晰。
         适用场景:大型依赖项、独立发布周期、多贡献者协作。

稀疏检出(Monorepo 单仓库模式)

仅检出所需目录

# 启用稀疏检出
git sparse-checkout init --cone

# 选择目录
git sparse-checkout set packages/my-app packages/shared-lib

# 添加其他目录
git sparse-checkout add packages/another-lib

# 列出已检出内容
git sparse-checkout list

# 禁用(恢复完整检出)
git sparse-checkout disable

使用稀疏检出克隆(大型单仓库)

# 部分克隆 + 稀疏检出(适用于巨型仓库的最快方式)
git clone --filter=blob:none --sparse https://github.com/org/monorepo.git
cd monorepo
git sparse-checkout set packages/my-service

# 无检出克隆(仅获取元数据)
git clone --no-checkout https://github.com/org/monorepo.git
cd monorepo
git sparse-checkout set packages/my-service
git checkout main

冲突解决

理解冲突标记

<<<<<<< HEAD(或"我方")
当前分支上的修改内容
=======
来自合并分支的修改内容
>>>>>>> feature-branch(或"对方")

解决策略

# 接受我们所有的更改(当前分支胜出)
git checkout --ours path/to/file.ts
git add path/to/file.ts

# 接受他们所有的更改(传入分支胜出)
git checkout --theirs path/to/file.ts
git add path/to/file.ts

# 为所有文件接受我们的更改
git checkout --ours .
git add .

# 使用合并工具
git mergetool

# 查看三方差异(基础版本、我们的版本、他们的版本)
git diff --cc path/to/file.ts

# 显示共同祖先版本
git show :1:path/to/file.ts   # 基础版本(共同祖先)
git show :2:path/to/file.ts   # 我们的版本
git show :3:path/to/file.ts   # 他们的版本

变基冲突工作流

# 在变基过程中,冲突一次一个提交地出现
# 1. 在文件中修复冲突
# 2. 暂存修复
git add fixed-file.ts
# 3. 继续到下一个提交
git rebase --continue
# 4. 重复直到完成

# 如果某个提交在解决冲突后变为空
git rebase --skip

Rerere(复用记录的解决方案)

# 全局启用 rerere
git config --global rerere.enabled true

# Git 会记住你如何解决冲突
# 下次出现相同冲突时,它会自动解决

# 查看记录的解决方案
ls .git/rr-cache/

# 忘记一个错误的解决方案
git rerere forget path/to/file.ts

储藏模式

# 附带消息储藏
git stash push -m "WIP: 重构认证流程"

# 储藏特定文件
git stash push -m "部分储藏" -- src/auth.ts src/login.ts

# 储藏包括未跟踪的文件
git stash push -u -m "包含未跟踪文件"

# 列出储藏
git stash list

# 应用最近的储藏(保留在储藏列表中)
git stash apply

# 应用并从储藏列表中移除
git stash pop

# 应用特定的储藏
git stash apply stash@{2}

# 显示储藏中的内容
git stash show -p stash@{0}

# 从储藏创建分支
git stash branch new-feature stash@{0}

# 丢弃特定的储藏
git stash drop stash@{1}

# 清除所有储藏
git stash clear

追溯和日志考古

# 谁更改了每一行(附带日期)
git blame src/auth.ts

# 追溯特定的行范围
git blame -L 50,70 src/auth.ts

# 在追溯中忽略空白更改
git blame -w src/auth.ts

# 查找某行何时被删除(搜索所有历史)
git log -S "function oldName" --oneline

# 查找何时添加/移除了正则表达式模式
git log -G "TODO.*hack" --oneline

# 跟踪文件的重命名历史
git log --follow --oneline -- src/new-name.ts

# 显示最后触及每一行的提交,忽略移动
git blame -M src/auth.ts

# 显示包含文件更改的日志
git log --stat --oneline -20

# 显示影响特定文件的所有提交
git log --oneline -- src/auth.ts

# 显示特定提交的差异
git show abc123

标签和发布

# 创建带注释的标签(推荐用于发布)
git tag -a v1.2.0 -m "发布 1.2.0:添加认证模块"

# 创建轻量标签
git tag v1.2.0

# 为过去的提交打标签
git tag -a v1.1.0 abc123 -m "为发布 1.1.0 补打标签"

# 列出标签
git tag -l
git tag -l "v1.*"

# 推送标签
git push origin v1.2.0      # 单个标签
git push origin --tags       # 所有标签

# 删除标签
git tag -d v1.2.0            # 本地
git push origin --delete v1.2.0  # 远程

提示

  • git rebase -i是最有用的高级 Git 命令。首先学习它。
  • 切勿对已推送到共享分支的提交进行变基。只对本地/功能分支的工作进行变基。
  • git reflog是你的安全网。如果你丢失了提交,它们几乎总是可以在90天内恢复。
  • git bisect run配合自动化测试比手动二分查找更快,并能消除人为错误。
  • 工作树比多个克隆更节省成本——它们共享.git存储。
  • 优先选择git subtree而不是git submodule除非有特定原因。对于协作者来说,子树更简单。
  • 全局启用rerere。它会记住冲突解决方案,所以你永远不会重复解决同一个冲突。
  • git stash push -m "描述"比单纯的git stash要好得多。当你有5个储藏时,你会感谢自己的。
  • git log -S "字符串"(镐)是查找函数或变量何时添加或删除的最快方法。

天猫隐藏优惠券

网淘吧

免责申明
部分文章来自各大搜索引擎,如有侵权,请与我联系删除。
打赏
文章底部电脑广告
手机广告位-内容正文底部

相关文章

您是本站第281428名访客 今日有104篇新文章/评论