Skip to content

Git 常用的命令

常见分支

  • main 分支是“生产环境”分支,永远保持稳定、可发布。
  • develop 分支是“集成分支”,所有新功能开发完成后会合并到这里。
  • feature/xxx 分支是“功能开发分支”,每个新需求或任务都从 develop 创建新分支进行开发。
  • 开发完成后,通过 Pull Request (或 Merge Request) 合并回 develop。

日常开发高频命令

  1. 初始化与拉取项目
    • git clone [repository_url]: 首次加入项目时,将远程仓库完整地克隆到本地。这是你参与协作的第一步。
    • git pull origin develop: 在开始新任务前,务必从远程 develop 分支拉取最新的代码,确保你的工作是基于团队的最新进展。
  2. 创建和切换分支
    • git checkout develop: 切换到 develop 分支,准备创建新的功能分支。
    • git checkout -b feature/user-login: 从当前分支(应该是最新的 develop)创建并立即切换到一个名为 feature/user-login 的新分支。这是你独立工作的开始,所有新代码都应该在这个分支上,以避免污染 develop 分支。
    • git branch: 查看本地所有分支,并确认当前所在分支(会用 * 标记)。
  3. 本地开发与提交
    • 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 和版本管理。
  4. 推送到远程仓库
    • 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,将这个技术完美地应用在你的病人身上。你只拿了你想要的,其他一概不碰。

实际操作场景:

  1. 定位 Commit:首先,你要去 develop 分支上找到那个修复 Bug 的提交的唯一 ID(commit hash)。

    bash
    git checkout develop
    git log --oneline
    # 假设你找到的commit是: a8e3b8d fix: correct critical payment bug
  2. 切换回你的分支:回到你的功能分支。

    bash
    git checkout feature/new-payment
  3. 执行"摘樱桃"

    bash
    git cherry-pick a8e3b8d

结果a8e3b8d这个提交所包含的所有代码改动,现在已经被应用到了你的feature/new-payment分支上,并产生了一个新的 commit(hash 不同,但内容和提交信息一样)。

Leader 建议cherry-pick 是一个非常有用的“战术性”工具,尤其适合在多个长期维护的分支间同步关键修复。但不要滥用它来替代常规的 mergerebase 流程。


2. git rebase -i:你的提交历史“精装编辑部”

想象你是一位作家,正在写一本书的一个章节(你的feature分支)。在写作过程中,你可能会有很多草稿性质的保存动作:

  • commit 1: "写了第一段"
  • commit 2: "修正了错别字"
  • commit 3: "啊啊啊忘了保存"
  • commit 4: "补充了一句话"
  • commit 5: "删掉刚才那句废话"

在你把这个章节交给编辑(提交 Pull Request)之前,你肯定不希望编辑看到这么凌乱的修改记录。你希望把这些零碎的修改,整理成一个或两个逻辑清晰、意义完整的提交,比如:

  • feat: 完成用户认证模块的核心逻辑
  • refactor: 优化认证流程的错误处理

git rebase -ii代表 interactive,交互式)就是你的“精装编辑部”。

它的作用是:

提供一个交互式的界面,让你在推送之前,对你自己本地的一系列提交进行重新排序、合并、修改或删除。

实际操作场景:

假设你想整理最近的 5 个提交。

  1. 启动交互式变基

    bash
    # HEAD~5 的意思是,从当前提交(HEAD)往前数5个
    git rebase -i HEAD~5
  2. 进入编辑界面: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
    # ... 其他命令 ...

    注意:提交是倒序排列的,最旧的在最下面。

  3. 编辑指令:你只需要修改每行前面的 pick 关键字,来告诉 Git 你想做什么。比如,我们想把这 5 个合并成 1 个:

    pick 3a4b5c6 写了第一段
    s 8e7d6c5 修正了错别字     # s 代表 squash (压扁/合并)
    s 5c6a7b8 啊啊啊忘了保存
    s 9f2d8e7 补充了一句话
    s 1a3b4c5 删掉刚才那句废话

    squash的意思是:把这个提交和它前一个提交合并。

  4. 保存并退出:保存并关闭编辑器后,Git 会把这 5 个提交合并,然后弹出另一个编辑器,让你为这个合并后的新提交写一个新的、有意义的 commit message。

结果:你原本乱糟糟的 5 个提交,现在变成了一个干净、清晰的提交。你的 Git 历史看起来非常专业,同事在 Code Review 时也会感谢你。

Leader 建议:这是提交 PR 前的黄金准则!它可以极大地提升代码库历史的可读性。但请严格遵守永远不要对已经推送到公共分支(如 develop, main)的提交使用交互式变基,因为它会改写历史,会给其他协作者带来灾难。


3. git reset --soft vs --mixed:时光倒流的不同方式

想象一下你的工作流程有三个区域:

  1. 工作区 (Working Directory):你正在编辑的文件,就像你书桌上摊开的稿纸。
  2. 暂存区 (Staging Area):你执行 git add 后的文件,就像你把写好的稿纸放进一个“待归档”的文件夹里。
  3. 本地仓库 (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 的创建和审查。