first-contributions 进阶指南:从修改提交到解决冲突的完整 Git 实战手册
【免费下载链接】first-contributions🚀✨ Help beginners to contribute to open source projects项目地址: https://gitcode.com/gh_mirrors/fi/first-contributions
导读
完成 first-contributions 主教程的首次 Pull Request 之后,你已经掌握了 fork、clone、branch、commit、push 与 PR 的基础闭环。但真实的开源协作远不止于此:提交信息写错了怎么办?Fork 落后于上游仓库怎么办?两个分支同时改了同一行代码怎么办?本篇文章以仓库 孟加拉语补充材料索引 为骨架,系统展开其引用的全部 13 个进阶 Git 主题,覆盖提交修正、历史重写、分支治理、冲突处理与凭据管理五大场景,让你在参与开源项目时不再畏惧任何一次"意外"。
前置说明:这份补充材料是什么
仓库中每一份补充文档都默认读者已经完成了 primary tutorial(fork 上游 → clone 到本地 → 新建<add-your-name>分支 → 提交 → 发起 Pull Request)。因此,下文涉及的所有操作都发生在真实开源协作的上下文里:你的仓库同时存在origin(自己的 GitHub Fork)与upstream(原项目公共仓库)两个远程,以及本地、Fork、上游三方协作的"三角工作流"。
原索引以 additional-material.be.md 收录了 10 篇 git_workflow_scenarios 下的操作文档,外加 .gitignore、凭据存储与实用链接共 13 个主题。下文逐一展开,每节都给出可直接复制的命令与关键注意点。
一、修改提交:git commit --amend
对应文档:amending-a-commit.md
场景一:提交推送到远程后发现提交信息有拼写错误,或发现自己漏改了一行。你不需要新建一个"补救提交",只需修改最近一次提交。
修改最近一次提交的信息
git commit --amend -m "新的提交信息" git push origin <branch-name>- 不加
-m直接运行git commit --amend,Git 会打开默认文本编辑器,等你修改提交信息后保存退出; - 加上
-m标志则跳过编辑器,直接以新信息替换原信息。
把漏改的内容并入上一次提交
假设你的提交历史如下:
g56123f create file botfile a2235d updated contributor.md a5da0d modified botfile你发现a5da0d里漏写了一个单词。两种做法:一是新建一条独立提交;二是把新改动并入a5da0d,让改动保持"一个提交一个主题"。后一种对小型修正更干净,操作如下:
# 1. 修改文件(把遗漏的单词补上) # 2. 加入暂存区 git add <filename> # 3. 修改上一次提交(会打开编辑器,可保留或改写原信息) git commit --amend # 4. 推送 git push origin <branch-name>修改已推送到远程的提交
一旦提交已经推送到远程,git commit --amend本质上是用一个新提交替换旧提交,本地历史将与远程历史分叉。要让远程也更新,必须强制推送覆盖远程分支历史:
git add <your changed files> git commit --amend -m "followed by your new commit message" git push --force⚠️ 警告:
git push --force会直接覆盖远程分支、丢弃远程上已有的改动——包括其他协作者在此期间推送的内容。 更安全的替代方案是git push --force-with-lease:推送前 Git 会先核对远程分支是否仍是你上次拉取时的状态,若是,则拒绝推送并提醒你,避免误伤他人的提交。在你无意覆盖别人改动时,应优先使用它。
二、配置 Git 身份与更多选项
对应文档:configuring-git.md
第一次运行git commit时,你可能会看到这样的提示:
$ git commit *** Please tell me who you are. Run git config --global user.email "you@example.com" git config --global user.name "Your Name" to set your account's default identity. Omit --global to set the identity only in this repository.Git 要求每次提交都绑定名字与邮箱,这是协作的基础:只有这样才能知道"谁在什么时候改了什么"。向 Git 提供身份有三种作用域,优先级从高到低为:命令行级 > 仓库级 > 全局级。
全局配置(Global)
存入全局配置后,本机所有仓库都会生效,适用于大多数场景:
git config --global user.email "you@example.com" git config --global user.name "Your Name"通用语法:git config --global <变量名> <值>。
仓库配置(Repository)
省略--global,配置只作用于当前仓库。典型场景:工作项目用公司邮箱、个人项目用私人邮箱:
git config user.email "you@alternate.com" git config user.name "Your Name"通用语法:git config <变量名> <值>。
命令行配置(Command-line)
仅对单条命令生效。所有 Git 命令都支持在动作动词之前用-c传入临时配置:
git -c user.name='Your Name' -c user.email='you@example.com' commit -m "Your commit message"通用语法:git -c <变量-1>=<值> -c <变量-2>=<值> <command>。
优先级说明
三种方式的生效优先级是命令行级 > 仓库级 > 全局级。例如某个变量同时在命令行和全局配置中出现,本次操作使用命令行中的值。
身份之外的其他配置项
core.editor—— 指定编写提交信息等场景使用的编辑器名称;commit.template—— 指定系统上一个文件作为初始提交信息模板;color.ui—— 布尔值,控制 Git 输出是否使用颜色。
三、保持 Fork 与上游仓库同步
对应文档:keeping-your-fork-synced-with-this-repository.md
开源协作的典型结构是"三角工作流":上游公共仓库(upstream)→ 你的 GitHub Fork(origin)→ 本地仓库,一共三个仓库。Pull Request 只能从你的 Fork 发起,所以同步的次序是:先让本地与上游同步,再让本地推送到 Fork。GitHub 提示"你落后 N 个提交"时,就该执行下面的流程。
完整同步流程
# 1. 确认当前在 main 分支(git status 的第一行会显示当前分支) git status # 如果不在 main: git checkout main # 2. 添加上游远程(只需做一次),命名为 upstream git remote add upstream https://github.com/firstcontributions/first-contributions.git # 3. 拉取上游最新内容 git fetch upstream # 4. 把上游 main 变基/合并进本地 main git rebase upstream/main # 5. 推送到你的 GitHub Fork(origin) git push origin main一步到位的快捷方式
如果只想一次性拉取并合并上游main到当前本地分支:
git pull upstream main此后本地、Fork、上游三方保持一致。建议每次看到 GitHub 提示落后时都执行一遍同步,再做新功能开发,可大幅减少后续的合并冲突。
四、把提交移动到正确的分支
对应文档:moving-a-commit-to-a-different-branch.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会丢弃未提交的改动。执行前确认没有未保存的工作。
五、从 Git 仓库移除文件
对应文档:removing-a-file.md
有时你想让 Git 停止跟踪某个文件,但文件本身还要留在电脑上(例如误提交的配置文件)。核心命令:
git rm <file> --cached原理说明
加上--cached后,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六、删除本地与远程分支
对应文档:removing-branch-from-your-repository.md
按主教程做完贡献后,<add-your-name>分支已完成了它的使命,可以清理掉。先把它合并进main,再删除本地分支:
git checkout main git merge <add-your-name> main git branch -d <add-your-name>删除远程分支(GitHub Fork 上的<add-your-name>)则需要谨慎:在维护者尚未合并你的 Pull Request 之前,千万不要删除它。只有确认 PR 已合并后,才执行:
git push origin --delete <add-your-name>这样本地与远程的分支都保持整洁。时间一长上游仓库会积累大量新提交,记得回到第三节的同步流程保持三方一致。
七、解决合并冲突
对应文档:resolving-merge-conflicts.md
什么是合并冲突
当不同分支的改动相互冲突、Git 无法自动合并时就会产生冲突。常见场景:
- 两个贡献者修改了同一文件的同一行;
- 一个贡献者删除了另一个贡献者正在修改的文件;
- 两个分支把同一文件重命名成了不同名字。
此时 Git 会暂停合并,把冲突文件标记出来等待人工处理。本教程聚焦命令行解法。
五步解决流程
1. 找出冲突文件。合并失败后运行:
git status在 "Unmerged paths" 下查找冲突文件列表。
2. 打开冲突文件查看标记。Git 用冲突标记标出边界:
<<<<<<< HEAD 你的改动 ======= 传入的改动 >>>>>>> branch-name<<<<<<< HEAD以下是当前分支的改动;=======分隔双方改动;>>>>>>> branch-name以下是另一分支传入的改动。
3. 手动解决冲突。三种选择:保留你的改动、接受传入的改动、或把两者有意义地合并。编辑完成后,务必删除<<<<<<<、=======、>>>>>>>这些冲突标记。
4. 标记为已解决:
git add <filename>对每个冲突文件重复此步骤。
5. 提交合并:
git commit -m "Resolved merge conflicts"至此合并流程收尾。
辅助工具
# 启动可视化合并工具(需先安装 Meld、KDiff3、Beyond Compare 等) git mergetool # 想放弃本次合并时 git merge --abort减少冲突的最佳实践
- 经常从主分支拉取更新:
git pull origin main; - 每个功能/修复使用独立分支:
git checkout -b feature-branch。
八、还原提交:git revert
对应文档:reverting-a-commit.md
git revert相当于 Git 世界的 "Ctrl+Z":它新建一条提交来撤销另一条提交的所有改动,历史保持线性增长,非常适合已经推送到远程的提交。每个提交都有唯一的 SHA(Secure Hash Algorithm)标识,只要能拿到 SHA 就能还原它,但要注意按顺序还原以免搞乱仓库。
步骤
# 1. 查看提交历史(--oneline 以一行简洁形式显示,每行开头是 7 位短 SHA) git log --oneline示例输出:
389004d added spacing in title c1b9fc1 Merge branch 'master' into tutorials 77eaafd added tutorial for reverting a commit# 2. 复制目标提交的 SHA(如 389004d) git revert 389004dGit 会打开文本编辑器让你编辑提交信息,可以保留默认以Revert开头的消息,也可以自定义。
# 3. 保存并关闭编辑器 # 4. 推送 git push origin <branch-name>完成。本例中仓库将回到c1b9fc1时的状态。
九、压缩提交:git rebase -i
对应文档:squashing-commits.md
什么是 Squash
Squash 即重写提交历史,把多个提交合并成一个带有完整描述的提交。开源项目经常要求这样做:分支上大量的过程性提交只对作者本人有意义,合并成一个提交后,改动描述更清晰、日后也更容易整体还原。
操作步骤
先查看要合并的提交:
git log会看到类似:
commit blablabla Author: omguhh Date: 10/10/20 Commit message 1 commit blablabla2 Author: omguhh Date: 10/10/20 Commit message 2进入交互式 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 # # 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把第二条的pick改为squash,使其并入上一条:
pick blablabla Changing test01.txt file squash blablabla2 Adding dummy01.txt file保存退出后,Git 会打开提交信息编辑器,展示两条提交信息的组合:
# This is a combination of 2 commits. # The first commit's message is: commit message 1 # This is the 2nd commit message: commit message 2自由修改后保存退出。再次运行git log,两个提交已合并为一个。
十、撤销本地提交:git reset
对应文档:undoing-a-commit.md
git reset系列用于撤销尚未推送的本地提交。三种模式各有用途。
软撤销:仅重置暂存区
git reset把暂存区重置到最近一次提交,工作目录的改动保留,可以重新提交。若只想把某个文件移出暂存区:
git reset <file>经典用法——把误合在一起的改动拆成两条提交:
# 修改 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模式告诉 Git 连工作目录的改动一起丢弃,只有在确定要放弃全部本地开发时才使用。
# 开始了一次疯狂的实验 # 新建 crazy.php 并写入代码 $ git add crazy.php $ git commit -m "Started a crazy dev" # 再次修改 crazy.php 以及大量其他文件 $ git add . $ git commit -m "Continued dev" # 测试后局面失控,决定整体回退 $ git reset --hard HEAD~2git reset --hard HEAD~2把当前分支回退 2 个提交点,同时丢弃这两次提交产生的所有改动快照。
⚠️ 记住:如果提交已经推送到共享仓库,永远不要执行
git reset --hard,否则会给仓库中所有协作者带来麻烦。此时应改用第八节的git revert。
十一、创建 .gitignore 文件
对应文档:creating-a-gitignore-file.md
为什么需要 .gitignore
.gitignore是 Git 工作流的关键组件,告诉 Git 忽略哪些文件与目录,防止不必要或敏感的数据被纳入版本控制。以下几类文件不应入库:
- 临时或系统生成的文件(缓存、构建产物、日志);
- 可重新安装的大型依赖(如
node_modules); - 个人或敏感配置(API 密钥、环境变量);
- IDE/编辑器专属文件(如
.vscode/、.idea/)。
忽略它们能让仓库保持干净、减少冲突、避免安全风险。
创建方法
- 在项目根目录新建名为
.gitignore的文本文件; - 每行列出一个要忽略的文件或目录;
- 保存。
基本语法
*—— 通配符,匹配多个文件;/—— 指定相对.gitignore的路径;#—— 注释。
示例文件
# 忽略 Mac 系统文件 .DS_Store # 忽略依赖目录 node_modules/ venv/ # 忽略日志与缓存文件 *.log .cache/ # 忽略环境变量文件 .env # 忽略所有文本文件 *.txt全局 .gitignore
对所有仓库生效的全局忽略文件:
git config --global core.excludesfile ~/.gitignore_global然后像编辑本地.gitignore一样编辑~/.gitignore_global。
取消已跟踪文件的跟踪
文件在加入.gitignore之前若已被提交,需要先从跟踪中移除:
# 取消跟踪单个文件(保留在本地) git rm --cached filename # 取消跟踪所有被忽略的文件(-- 之后是路径,. 表示当前目录) git rm -r --cached . git add . git commit -m "Updated .gitignore"撤销git rm --cached只需:git add filename。
十二、存储凭据:git credential cache
对应文档:storing-credentials.md
每次访问远程仓库都要输入用户名密码确实影响效率,Git 提供了凭据缓存机制来解决。
⚠️ 安全提示:请务必遵守你工作/学习场所的安全策略。注意,
credential.helper cache方式以明文把凭据保存在本机磁盘上,同一台电脑上的其他用户(例如恶意 NPM 模块)都可能读取到它。
全局凭据缓存(所有仓库)
git config --global credential.helper cache仓库级凭据缓存
git config credential.helper cache设置缓存超时
不指定时长时凭据可能被长期保留;用--timeout控制保存在内存中的时间:
git config credential.helper 'cache --timeout=<timeout>'使用该 helper 时凭据不会落盘,超时后自动清除。默认值是 900 秒(15 分钟)。
十三、进一步学习资源索引
对应文档:Useful-links-for-further-learning.md
该文档是一份面向初学者与进阶者的学习资源索引,收录了 GitHub 官方文档、交互式 Git 练习工具、视频课程、命令速查表、合并冲突专题、rebase 图解、提交信息书写规范、开源贡献入门指南、版本控制课程以及编辑器内置 Git 功能说明等多类资料。当你完成本文全部练习后,可以继续翻阅这份清单:把交互式教程当作日常练习场,把速查表贴在案头,把提交信息规范应用到每一次git commit中,就能逐步形成更专业的协作习惯。
总结:把这些技巧串进真实的贡献流程
把本文的 13 个技巧放回 first-contributions 的真实贡献场景,你会看到一条完整的能力链路:
- 开发前先按第三节同步 fork,避免"落后 N 个提交";
- 提交后若发现信息有误或漏改,用第一节
git commit --amend修正; - 若提交到了错误分支,用第四节移动到正确分支;
- 若误提交了不该入库的文件,用第五节或第十一节从跟踪中移除;
- PR 合并后,用第六节清理本地与远程的临时分支;
- 若 PR 评审要求合并提交历史,用第九节 squash;
- 若遭遇冲突,按第七节逐文件解决;
- 若推错了提交,用第八节 revert(已推送)或第十节 reset(未推送);
- 最后用第十二节配置凭据缓存,避免频繁输入密码。
这些文档全部收录在 git_workflow_scenarios 目录下,除英文原版外,多数主题还提供了中文(如 amending-a-commit.zh-cn.md)、孟加拉语(additional-material.be.md)等多语言版本,可对照阅读。掌握这 13 个主题,你在任何开源项目中的协作都会更加从容。
【免费下载链接】first-contributions🚀✨ Help beginners to contribute to open source projects项目地址: https://gitcode.com/gh_mirrors/fi/first-contributions
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考