first-contributions 附加资料:Git 进阶操作与协作工作流实战指南
【免费下载链接】first-contributions🚀✨ Help beginners to contribute to open source projects项目地址: https://gitcode.com/gh_mirrors/fi/first-contributions
本指南是 first-contributions 项目为已完成基础入门教程的贡献者准备的进阶资料,系统覆盖 Git 日常协作中最常遇到的十类高阶操作:配置身份、同步分叉、修改/回滚/恢复提交、解决合并冲突、挤压提交、移动提交、删除文件与分支等。读完本文,你将掌握一套可立即投入开源协作的 Git 进阶工具箱,知道每种操作适用的场景、背后的原理以及安全边界。
前置说明:本文档的定位
本指南对应的源文档位于 docs/additional-material/translations/Chinese/additional-material.zh-cn.md,其英文原版见 docs/additional-material/git_workflow_scenarios/additional-material.md。文档明确假定:你来到这里之前已经完成 first-contributions 的基础教学,即已经掌握了 fork、clone、创建分支、提交、发起 Pull Request 的完整流程。本文在此基础上展开进阶内容,因此不重复讲解 fork/clone 等基础步骤。
仓库中每个进阶主题都有独立成篇的教程文件(含多语言翻译),本文将各主题的要点整合为一份连贯指南,并提供对应的仓库内原文路径,方便你按需深入阅读。建议按顺序通读一遍,再在实际协作中按需查阅对应小节。
配置 Git:三种作用域与优先级
首次提交时,Git 会因为不知道你的身份而拒绝创建提交,并给出如下提示:
$ git commit *** 请告诉我你是谁。 运行 git config --global user.email "you@example.com" git config --global user.name "Your Name" 来设置你账户的默认身份。 如果只想在当前仓库设置身份,省略 --global。Git 在设计上要求每个提交都绑定一个名字和邮箱,这正是协作项目能够追溯"谁在何时改动了哪部分"的基础。配置身份有四种方式,按作用域从小到大依次为:
全局配置(--global)
$ git config --global user.email "you@example.com" $ git config --global user.name "Your Name"存储在全局配置中的内容对系统上所有仓库生效,适用于大多数个人开发场景,是官方推荐的首选方式。
仓库配置(省略 --global)
$ git config user.email "you@alternate.com" $ git config user.name "Your Name"省略--global后,配置仅写入当前仓库。典型场景是:日常提交使用个人邮箱,而在某个公司项目中提交时使用公司邮箱。
命令行配置(-c 参数)
git -c user.name='Your Name' -c user.email='you@example.com' commit -m "Your commit message"-c参数在命令动词之前传入,配置只对当前这一条命令生效,不写入任何配置文件。适合单次临时提交(如代为提交某次变更)或脚本化场景。
配置优先级
三种方式的优先级为:命令行配置 > 仓库配置 > 全局配置。即同一变量若在命令行与全局均被配置,本次操作采用命令行的值。理解这一优先级,可以在不污染全局环境的前提下为特定仓库或特定命令做精细化覆盖。
用户信息之外的常用配置
git config不仅能配置身份,还支持大量其他选项,常见的有:
core.editor—— 指定编写提交消息等场景使用的编辑器名称;commit.template—— 指定系统上某个文件作为初始提交模板;color.ui—— 布尔值,控制 Git 输出是否使用颜色。
配置完成后,可以在 docs/additional-material/translations/Chinese/configuring-git.zh-cn.md 查看中文完整教程,英文原版见 docs/additional-material/git_workflow_scenarios/configuring-git.md。
保持分叉与上游仓库同步:三角工作流
在 first-contributions 的协作模型中,始终存在三个仓库:上游公共仓库(first-contributions.git)、你在 GitHub 上的分叉、以及你本地机器上的克隆。这种"上游 → 本地 → 分叉"的协作结构在开源项目中非常典型,被称为Triangle Workflows(三角工作流)。
只有通过自己的分叉才能发起 Pull Request,因此分叉必须最后更新;同步的正确顺序是:先把上游仓库拉到本地合并,再把本地推送到分叉。完整步骤如下:
- 确保在主分支上(用
git status第一行查看当前分支;不在则执行git checkout main); - 添加上游远程仓库并命名为
upstream:
git remote add upstream https://github.com/firstcontributions/first-contributions.git- 拉取上游最新版本:
git fetch upstream- 将上游主分支合并进本地主分支:
git rebase upstream/main- 推送本地主分支到自己的分叉(远程名
origin):
git push origin main如果想一步完成"拉取并合并",可以合并第 3、4 步为:
git pull upstream main完成以上操作后,三个仓库即全部同步。每当 GitHub 提示你的分叉落后上游若干提交时,都应重复这一流程——这正是多人协作项目中保持提交基线干净的关键习惯。中文教程见 docs/additional-material/translations/Chinese/keeping-your-fork-synced-with-this-repository.zh-cn.md,英文原版见 docs/additional-material/git_workflow_scenarios/keeping-your-fork-synced-with-this-repository.md。
修改最近一次提交:git commit --amend
当你把提交推送到远端后才发现提交消息有拼写错误,或漏改了文件中的一行内容,该怎么办?git commit --amend正是为此设计——它允许你修改当前分支最近一次提交(在推送到远端之前可以反复修改)。
仅修改提交消息
不打开文件、直接替换提交消息:
git commit --amend -m "你的新提交消息" git push origin <分支名>注意:如果只输入git commit --amend而不带-m,Git 会打开文本编辑器让你修改提交消息;加上-m标志可以跳过编辑器交互。
把遗漏的改动并入最近提交
假设你的提交历史如下,且发现botfile中漏掉了一个单词:
g56123f create file botfile a2235d updated contributor.md a5da0d modified botfile有两种处理方式:新增一个独立提交(历史会多出b0ca8f added single word to botfile);或者把改动 amend 进a5da0d,使两次改动合并为一个提交。对于微小修正,后者显然更干净:
# 修改文件后,加入暂存区 git add <文件名> # 不新建提交,而是并入最近一次提交 git commit --amend此时文本编辑器会打开,你可以保留或修改原有提交消息;退出编辑器后执行git push origin <分支名>即可。两条改动最终落在同一个提交里。
修改已推送的远端提交
如果目标提交已经推送到远端,amend 会创建一个新提交并替换原提交,导致本地历史与远端分叉。要改写远端历史,必须用强制推送覆盖:
git add <你的改动文件> git commit --amend -m "你的新提交消息" git push --force警告:强制推送会覆盖(并丢弃)远端上的既有内容,包括其他协作者在此期间推送的变更,务必谨慎使用。相对更安全的选择是
git push --force-with-lease,它会在远端有他人新提交时拒绝推送,避免误伤他人工作。
完整教程见 docs/additional-material/translations/Chinese/amending-a-commit.zh-cn.md(英文原版:docs/additional-material/git_workflow_scenarios/amending-a-commit.md)。
回滚已推送的提交:git revert
git revert相当于 Git 世界里的"Ctrl+Z":它会创建一个全新的提交,用来撤销某个旧提交的全部改动。由于每个提交都带有唯一的 SHA(Secure Hash Algorithm)标识,只要拥有目标提交的 SHA,就能精确回滚任意历史提交——前提是按顺序逆向处理,避免把仓库弄乱。
先用简洁格式查看提交历史与 SHA:
git log --oneline输出中每行开头的 7 位字符就是缩写提交哈希,例如:
389004d added spacing in title c1b9fc1 Merge branch 'master' into tutorials 77eaafd added tutorial for reverting a commit假设要撤销389004d("added spacing in title"):
git revert 389004d命令会打开文本编辑器让你确认提交消息——可以保留默认的以Revert开头的消息,也可以自定义。保存退出后推送:
git push origin <分支名>完成推送后,仓库即恢复到撤销该提交之前的状态。与reset不同,revert不改写历史,而是新增一个反向提交,因此适用于已经推送到共享仓库的提交,不会给协作者带来历史分叉问题。中文教程见 docs/additional-material/translations/Chinese/reverting-a-commit.zh-cn.md,英文原版见 docs/additional-material/git_workflow_scenarios/reverting-a-commit.md。
恢复本地提交:git reset
与revert针对远端不同,git reset用于恢复本地提交,适合"把本地仓库搞砸了想重置"的场景。
取消暂存但不丢改动
git reset将暂存区重置到最近一次提交,工作目录中的改动原样保留,之后仍可重新提交。只针对单个文件:
git reset <file>典型用法是"先把两个文件都git add,再决定分开提交":
# 在 index.php 和 tutorial.php 中做了修改 $ git add . # 意识到两个文件应分开提交,先取消暂存 tutorial.php $ git reset tutorial.php # 先提交 index.php $ git commit -m "Changed index.php" # 再提交 tutorial.php $ git add tutorial.php $ git commit -m "Changed tutorial.php"彻底放弃本地改动
git reset --hard--hard模式不仅重置暂存区,还会把工作目录中的所有改动还原到最近一次提交,未提交的修改将全部丢失。例如:
# 开始一个疯狂实验,新建并提交 crazy.php $ git add crazy.php $ git commit -m "Started a crazy dev" # 继续大量修改并提交 $ git add . $ git commit -m "Continued dev" # 测试失控,决定整体回退 $ git reset --hard HEAD~2git reset --hard HEAD~2把当前分支向后移动 2 个提交,同时撤销这期间的所有改动,并将这 2 个快照从项目历史中移除。
重要提醒:永远不要在提交已推送到共享仓库后执行
git reset --hard——这会重写共享历史,给仓库中的所有人带来麻烦。本地未推送的提交可以放心使用 reset,已推送的内容请改用git revert。
中文教程见 docs/additional-material/translations/Chinese/undoing-a-commit.zh-cn.md,英文原版见 docs/additional-material/git_workflow_scenarios/undoing-a-commit.md。
解决合并冲突
合并冲突发生在不同分支的改动相互冲突、Git 无法自动合并时。常见触发场景包括:
- 两位贡献者修改了同一文件的同一行;
- 一位贡献者删除了另一位已修改的文件;
- 不同分支上对同一文件进行了不同的重命名。
冲突解决五步法
- 识别冲突文件:合并后执行
git status,查看 "Unmerged paths"(未合并路径)下列出的文件; - 打开并检查冲突文件:Git 用如下标记标出冲突区域:
<<<<<<< HEAD 你的改动 ======= 传入的改动 >>>>>>> branch-name其中<<<<<<< HEAD代表当前分支的改动,=======分隔双方冲突内容,>>>>>>> branch-name代表另一分支传入的改动; 3.解决冲突:决定保留自己的改动、接受传入的改动、或将两者合理合并,然后删除所有冲突标记(<<<<<<<、=======、>>>>>>>); 4.标记为已解决:对每个冲突文件执行git add <文件名>; 5.提交合并:
git commit -m "Resolved merge conflicts"提交完成后,整个合并流程即告终结。
辅助工具与兜底手段
git mergetool:启动可视化合并工具辅助解决冲突(需预先安装 Meld、KDiff3、Beyond Compare 等工具);git merge --abort:想放弃本次合并时,用它安全取消合并流程,回到合并前状态。
预防冲突的最佳实践
- 经常拉取:
git pull origin main及时同步主分支的最新改动; - 使用功能分支:
git checkout -b feature-branch为每个功能或修复单独开分支,减少并行改动相互碰撞的概率。
中文教程见 docs/additional-material/translations/Chinese/resolving-merge-conflicts.zh-cn.md,英文原版见 docs/additional-material/git_workflow_scenarios/resolving-merge-conflicts.md。
挤压提交:git rebase -i
Squashing(挤压)指重写提交历史,把多个提交合并为一个,并用一条信息描述全部改动。在开源项目中这很常见——分支上的大量中间提交往往只对开发者本人有意义,挤压后既能更简洁地描述变更,也便于必要时整体回滚。
操作步骤
先查看要合并的提交:
git log确认目标后,进入交互式 rebase 模式,并指定回溯深度:
git rebase -i HEAD~2编辑器会打开类似如下的清单:
pick blablabla Changing test01.txt file pick blablabla2 Adding dummy01.txt file # 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要将blablabla2并入blablabla,把第二行的pick改为squash:
pick blablabla Changing test01.txt file squash blablabla2 Adding dummy01.txt file保存退出后,编辑器会显示合并后的提交消息草稿(两个提交消息的组合),你可以自由修改,然后再次保存退出。此时再执行git log,两个提交已合并为一个,并带有你最终确认的提交消息。
提示:
fixup与squash类似,但会直接丢弃被合并提交的消息,适合不需要保留多条消息的场合。清单中的注释还提醒:删除某一行意味着该提交将被永久丢失;若把所有行都删除,rebase 会被中止。
中文教程见 docs/additional-material/translations/Chinese/squashing-commits.zh-cn.md,英文原版见 docs/additional-material/git_workflow_scenarios/squashing-commits.md。当开源项目的维护者要求你"把若干提交挤压成一个提交并附上有信息量的提交消息"时,本节就是标准答案。
移动提交到另一个分支
不小心把改动提交到了错误的分支?有两种修复路径。
移动到已存在的分支
git reset HEAD~ --soft # 撤销最近一次提交,但保留改动 git stash # 暂存当前工作目录状态 git checkout name-of-the-correct-branch # 切换到目标分支 git stash pop # 恢复暂存的状态 git add . # 也可以逐个添加文件 git commit -m "your message here"完成上述操作后,改动就出现在正确的分支上了。
移动到新建的分支
git branch newbranch # 创建新分支,保留所有提交 git reset --hard HEAD~# # 当前分支回退 # 个提交(这些提交将从当前分支消失) git checkout newbranch # 切到新分支,它拥有全部提交警告:后一种方式中,任何未提交的改动都会丢失;
git reset --hard前务必确认工作目录干净。
中文教程见 docs/additional-material/translations/Chinese/moving-a-commit-to-a-different-branch.zh-cn.md,英文原版见 docs/additional-material/git_workflow_scenarios/moving-a-commit-to-a-different-branch.md。
删除文件:git rm --cached
有时你想让 Git 停止跟踪某个文件,但不删除电脑上的文件:
git rm <file> --cached执行后,Git 不再跟踪该文件的改动——对 Git 而言如同文件已被删除,但文件系统上文件依然存在。关键在于--cached标志:如果没有它,Git 会同时把文件从仓库和本地文件系统中一并删除。
随后提交并推送,远端仓库即会移除该文件:
git commit -m "Remove file1.js" git push origin main # 或你正在工作的分支进阶用法:
- 一次删除多个文件:
git rm file1.js file2.js file3.js --cached; - 使用通配符批量删除同类文件,例如移除所有
.txt文件:git rm *.txt --cached。
中文教程见 docs/additional-material/translations/Chinese/removing-a-file.zh-cn.md,英文原版见 docs/additional-material/git_workflow_scenarios/removing-a-file.md。
删除分支:本地与远端
在 first-contributions 的基础流程中,你创建了<add-your-name>分支并提交了 Pull Request。合并完成后,这个临时分支就完成了使命,可以清理了。
先回到主分支并合并,再删除本地分支:
git checkout main git merge <add-your-name> main git branch -d <add-your-name>此时 GitHub 分叉上仍保留<add-your-name>远端分支。在维护者合并你的 Pull Request 之前,切勿删除该远端分支;确认合并后,删除远端分支:
git push origin --delete <add-your-name>清理完分支后,本地与分叉都会恢复整洁。中文教程见 docs/additional-material/translations/Chinese/removing-branch-from-your-repository.zh-cn.md,英文原版见 docs/additional-material/git_workflow_scenarios/removing-branch-from-your-repository.md。
延伸资料:.gitignore、凭证存储与学习链接
除上述主题外,仓库还收录了若干高价值延伸资料:
- 创建 .gitignore 文件:解释
.gitignore的作用、使用原因与创建方法。该文件几乎出现在所有 Git 项目中,帮助只把必要的文件提交进 Git,避免构建产物、本地配置等无关内容污染仓库; - 存储凭证:说明如何为仓库存储认证凭证。文档特别提醒:凭证存储涉及安全问题,请务必遵循所在工作单位或学校的相关安全策略;
- 好用的链接索引:汇集了大量博文、网站、提示与技巧,面向开源新手和希望深入学习的人,充当继续学习的一站式索引(英文原版见 docs/additional-material/git_workflow_scenarios/Useful-links-for-further-learning.md)。
结语:把进阶操作纳入日常协作
本文覆盖的操作构成了开源贡献者日常协作的完整工具箱:用config管理身份,用"上游 → 本地 → 分叉"的三角工作流保持同步,用amend/rebase -i打磨提交历史,用revert/reset安全回退,用git rm --cached管理文件跟踪,用分支清理保持仓库整洁。实践中的两条铁律请务必牢记:已推送到共享仓库的提交用revert而不是reset --hard;强制推送优先选择--force-with-lease。掌握这些操作后,配合 first-contributions 的主教程,你就能在任何开源项目中自信、安全地完成从首次提交到长期协作的全流程。
【免费下载链接】first-contributions🚀✨ Help beginners to contribute to open source projects项目地址: https://gitcode.com/gh_mirrors/fi/first-contributions
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考