Git 常用的命令
常见分支
- main 分支是“生产环境”分支,永远保持稳定、可发布。
- develop 分支是“集成分支”,所有新功能开发完成后会合并到这里。
- feature/xxx 分支是“功能开发分支”,每个新需求或任务都从 develop 创建新分支进行开发。
- 开发完成后,通过 Pull Request (或 Merge Request) 合并回 develop。
日常开发高频命令
- 初始化与拉取项目
- git clone [repository_url]: 首次加入项目时,将远程仓库完整地克隆到本地。这是你参与协作的第一步。
- git pull origin develop: 在开始新任务前,务必从远程 develop 分支拉取最新的代码,确保你的工作是基于团队的最新进展。
- 创建和切换分支
- git checkout develop: 切换到 develop 分支,准备创建新的功能分支。
- git checkout -b feature/user-login: 从当前分支(应该是最新的 develop)创建并立即切换到一个名为 feature/user-login 的新分支。这是你独立工作的开始,所有新代码都应该在这个分支上,以避免污染 develop 分支。
- git branch: 查看本地所有分支,并确认当前所在分支(会用 * 标记)。
- 本地开发与提交
- git status: 时刻检查你当前工作区的状态,看哪些文件被修改、新增或删除了。这是一个“安全感”命令。
- git add . 或 git add [file_path]: 将你的修改“暂存”起来,准备提交。我更推荐使用 git add [file_path],更精确地控制本次提交包含哪些内容,养成 小步、原子化提交 的好习惯。
- git commit -m "feat: implement user login form": 将暂存区的修改正式提交到你的本地仓库。 建议:我们团队强制要求遵循 Conventional Commits 规范(如 feat:, fix:, docs:, style:, refactor: 等),这不仅仅是为了好看,更是为了自动化生成 CHANGELOG 和版本管理。
- 推送到远程仓库
- git push origin feature/user-login: 将你本地的 feature/user-login 分支以及其上的所有提交,推送到远程仓库。这样你的代码就备份到了云端,并且你的同事可以通过 Pull Request 看到你的工作。
团队协作与代码同步
- git fetch origin: 从远程仓库下载最新的对象和引用(比如分支、标签信息),但 不会 自动合并到你的本地分支。这是一个更安全的数据同步方式。
- git rebase origin/develop: 这是我们团队推荐的、保持 Git 历史线性整洁的关键命令。当你自己的 feature/user-login 分支开发了一段时间后,develop 分支可能已经有了其他同事提交的新代码。此时,在你自己的分支上执行此命令,可以将你的分支“变基”到最新的 develop 之上。 为什么用 rebase 而不是 merge? rebase 可以让你的提交历史变成一条直线,非常清晰。而 merge 会在历史中产生一个分叉再合并的“气泡”,当多人协作时,这会让 develop 的历史图变得难以阅读。 黄金法则:永远不要对一个已经被推送到远程并被多人使用的公共分支(如 develop, main)进行 rebase。只在你自己的、私有的功能分支上使用它。
- git log --oneline --graph: 在 rebase 或 merge 前后,用这个命令可以清晰地看到分支的提交历史图,帮助你理解发生了什么。
"后悔药"与代码修复
- git commit --amend: 当你刚刚的 commit 消息写错了,或者漏掉了一两个文件的修改,可以用这个命令来“修补”上一次提交,而不是产生一个新的、多余的 commit。
- git reset [commit_hash]: 回滚代码。在个人分支上非常有用。 --soft: 仅仅移动 HEAD 指针,你的代码和暂存区都不变。可以用来重新组织提交。 --mixed (默认): 移动 HEAD,并重置暂存区。你的工作区代码不变。 --hard: (危险!) 彻底丢弃指定 commit 之后的所有修改。使用前请三思。
- git revert [commit_hash]: 当一个错误的提交已经被推送到了公共分支(如 develop),你不应该使用 git reset 去修改历史。正确的做法是使用 revert,它会创建一个新的提交,内容是指定 commit 的逆向操作。这保留了完整的历史记录,对团队协作是安全的。
- git stash: 临时保存你的工作。当你正在一个分支上开发,突然需要切换到另一个分支改一个紧急的 Bug 时,可以用 git stash 将当前未提交的修改(包括暂存和未暂存的)“藏”起来。处理完后,再用 git stash pop 恢复。
高级但非常有用的命令
git cherry-pick [commit_hash]: "摘樱桃"。可以从另一个分支上“摘取”某一个特定的提交,并应用到当前分支上。比如,你需要将 develop 分支上的一个紧急修复,也应用到你正在开发的某个长期特性分支上。
git rebase -i [base_commit]: 交互式 rebase。这是一个强大的工具,可以让你在推送前,对你的提交历史进行编辑,比如合并(squash)、修改(reword)、删除(drop)多个 commits,让你的 PR 提交历史非常干净、有条理。
1. git cherry-pick
:精确移植手术
想象一下,你正在两个并行的手术室里工作。
- 手术室 A (
develop
分支):正在进行一项常规的大手术,进展顺利。 - 手术室 B (
feature/new-payment
分支):你正在进行一项复杂、长期的创新手术,可能还需要好几天才能完成。
突然,手术室 A 的医生(你的同事)发明了一种新的、绝妙的缝合技术(一个commit
),并且已经应用在了develop
分支上,修复了一个紧急的出血点(一个 Bug)。
你现在在手术室 B,也遇到了同样的出血点!你非常需要那个新的缝合技术,但是你不能把手术室 A 的所有进展(整个develop
分支)都合并过来,因为那会把你的创新手术搞得一团糟。
这时,git cherry-pick
就派上用场了。
它的作用是:
“从别的分支上,把某一个特定的提交(commit)拿过来,在我的当前分支上重放一遍。”
就像一名外科医生,你走进手术室 A,精确地学习并复制了那个“新的缝合技术”(那个commit
),然后回到手术室 B,将这个技术完美地应用在你的病人身上。你只拿了你想要的,其他一概不碰。
实际操作场景:
定位 Commit:首先,你要去
develop
分支上找到那个修复 Bug 的提交的唯一 ID(commit hash)。bashgit checkout develop git log --oneline # 假设你找到的commit是: a8e3b8d fix: correct critical payment bug
切换回你的分支:回到你的功能分支。
bashgit checkout feature/new-payment
执行"摘樱桃":
bashgit cherry-pick a8e3b8d
结果:a8e3b8d
这个提交所包含的所有代码改动,现在已经被应用到了你的feature/new-payment
分支上,并产生了一个新的 commit(hash 不同,但内容和提交信息一样)。
Leader 建议:cherry-pick
是一个非常有用的“战术性”工具,尤其适合在多个长期维护的分支间同步关键修复。但不要滥用它来替代常规的 merge
或 rebase
流程。
2. git rebase -i
:你的提交历史“精装编辑部”
想象你是一位作家,正在写一本书的一个章节(你的feature
分支)。在写作过程中,你可能会有很多草稿性质的保存动作:
commit 1: "写了第一段"
commit 2: "修正了错别字"
commit 3: "啊啊啊忘了保存"
commit 4: "补充了一句话"
commit 5: "删掉刚才那句废话"
在你把这个章节交给编辑(提交 Pull Request)之前,你肯定不希望编辑看到这么凌乱的修改记录。你希望把这些零碎的修改,整理成一个或两个逻辑清晰、意义完整的提交,比如:
feat: 完成用户认证模块的核心逻辑
refactor: 优化认证流程的错误处理
git rebase -i
(i
代表 interactive,交互式)就是你的“精装编辑部”。
它的作用是:
提供一个交互式的界面,让你在推送之前,对你自己本地的一系列提交进行重新排序、合并、修改或删除。
实际操作场景:
假设你想整理最近的 5 个提交。
启动交互式变基:
bash# HEAD~5 的意思是,从当前提交(HEAD)往前数5个 git rebase -i HEAD~5
进入编辑界面:Git 会打开一个文本编辑器,里面列出了你指定的 5 个提交,像这样:
pick 1a3b4c5 删掉刚才那句废话 pick 9f2d8e7 补充了一句话 pick 5c6a7b8 啊啊啊忘了保存 pick 8e7d6c5 修正了错别字 pick 3a4b5c6 写了第一段 # Commands: # p, pick = use commit # s, squash = use commit, but meld into previous commit # ... 其他命令 ...
注意:提交是倒序排列的,最旧的在最下面。
编辑指令:你只需要修改每行前面的
pick
关键字,来告诉 Git 你想做什么。比如,我们想把这 5 个合并成 1 个:pick 3a4b5c6 写了第一段 s 8e7d6c5 修正了错别字 # s 代表 squash (压扁/合并) s 5c6a7b8 啊啊啊忘了保存 s 9f2d8e7 补充了一句话 s 1a3b4c5 删掉刚才那句废话
squash
的意思是:把这个提交和它前一个提交合并。保存并退出:保存并关闭编辑器后,Git 会把这 5 个提交合并,然后弹出另一个编辑器,让你为这个合并后的新提交写一个新的、有意义的 commit message。
结果:你原本乱糟糟的 5 个提交,现在变成了一个干净、清晰的提交。你的 Git 历史看起来非常专业,同事在 Code Review 时也会感谢你。
Leader 建议:这是提交 PR 前的黄金准则!它可以极大地提升代码库历史的可读性。但请严格遵守:永远不要对已经推送到公共分支(如 develop, main)的提交使用交互式变基,因为它会改写历史,会给其他协作者带来灾难。
3. git reset --soft
vs --mixed
:时光倒流的不同方式
想象一下你的工作流程有三个区域:
- 工作区 (Working Directory):你正在编辑的文件,就像你书桌上摊开的稿纸。
- 暂存区 (Staging Area):你执行
git add
后的文件,就像你把写好的稿纸放进一个“待归档”的文件夹里。 - 本地仓库 (Local Repository):你执行
git commit
后的地方,就像你把“待归档”文件夹正式盖章存入了档案柜。
git reset
就是一部时光机,让你回到过去的某个commit
状态。--soft
和--mixed
是两种不同的倒流模式。
git reset --soft HEAD~1
(温柔的后悔)
- 发生了什么:时光机只把**档案柜(本地仓库)**里的最新档案拿了出来,撤销了
commit
这个动作。 - 状态:
- 本地仓库 (Local Repo):回到了上一个版本。
- 暂存区 (Staging Area):保持不变。那个“待归档”文件夹还好好的在那里,里面的内容就是你刚刚撤销的那个 commit 的内容。
- 工作区 (Working Directory):保持不变。你桌上的稿纸也完全没动。
- 适用场景:“我只是对刚才的提交信息不满意,或者想再加点小修改一起提交。” 因为所有改动都还在暂存区,你可以直接执行
git commit -m "一个更好的提交信息"
来创建一个新的、正确的提交。
git reset --mixed HEAD~1
(标准的后悔,也是默认模式)
- 发生了什么:时光机不仅拿出了档案柜的档案(撤销 commit),还把“待归档”文件夹(暂存区)里的稿纸也拿了出来,扔回了你的书桌上。
- 状态:
- 本地仓库 (Local Repo):回到了上一个版本。
- 暂存区 (Staging Area):被清空了。
- 工作区 (Working Directory):保持不变。所有被撤销的改动,现在都以“未暂存的修改”状态出现在你的工作区。
- 适用场景:“我上一次提交的内容有点问题,我想重新整理一下,决定哪些需要提交,哪些不需要。” 因为所有改动都回到了工作区,你可以重新使用
git add
来一块一块地挑选你真正想要提交的内容,实现更精细的控制。
命令 | 本地仓库 (Commit) | 暂存区 (Staging) | 工作区 (Working Dir) | 比喻 |
---|---|---|---|---|
reset --soft | 回滚 | 保留 | 不变 | 只撤销了“归档”这个动作 |
reset --mixed | 回滚 | 回滚 | 不变 | 撤销了“归档”和“放入待归档文件夹” |
总结
- 保持沟通:在做任何可能影响他人的操作(如 force push)前,一定要通知相关同事。
- 提交清晰:遵循 commit message 规范,让每一次提交都言之有物。
- 分支整洁:多用 rebase 保持主干历史的线性,用 cherry-pick 按需择取,用 stash 灵活切换。
- 安全第一:区分 reset 和 revert 的使用场景,保护公共分支的历史。
- 拥抱 PR:Pull Request 是代码审查、知识分享和保证质量的核心阵地,认真对待每一次 PR 的创建和审查。