Git 实用操作指南
2026/8/7 14:43:15 网站建设 项目流程

Git 实用操作全指南:从基础到进阶

学习 Git 最权威的资料是其官方文档,推荐优先查阅:Git 官方文档(中文版)。本文整理了日常开发中高频使用的 Git 命令,按核心场景分类,方便我快速查阅和使用。

一、Git 核心概念:工作区、暂存区与仓库

Git 工作流程围绕三个核心区域展开,理解它们的关系是熟练使用 Git 的基础。

  1. 工作区:本地电脑中实际编辑文件的目录,即日常写代码的地方。
  2. 暂存区(索引):临时存放修改的区域,用于确认哪些修改需要提交到仓库。
  3. 本地仓库:存储所有提交历史的数据库,记录了项目的完整版本变化。
  4. 远程仓库:托管在服务器上的仓库(如 GitHub、GitLab),用于团队协作和代码备份。

核心流程:工作区 →(git add)→ 暂存区 →(git commit)→ 本地仓库 →(git push)→ 远程仓库

二、基础操作:仓库初始化与文件管理

这部分包含从创建 / 克隆仓库到跟踪、提交文件的基础命令,是日常开发的高频操作。

1. 仓库创建与克隆

  • git init:在当前目录初始化一个新的 Git 仓库。
  • git clone <URL>:从指定 URL 克隆远程仓库到本地。
  • git clone --depth 1 <URL> <目录名>:只克隆最近 1 次提交历史,减少下载体积,并指定本地目录。
  • git clone -b <分支名> <URL>:克隆远程仓库的指定分支。

2. 文件跟踪与删除(git add / rm)

  • git add <文件名>:将工作区的文件添加到暂存区,开始跟踪该文件。
  • git add [dir]:添加指定目录到暂存区,包括子目录。
  • git add -u:将正在跟踪的被修改过的工作区文件添加到暂存区。
  • git add .:将当前目录所有文件添加到暂存区。
  • git rm <文件名>:删除被 Git 跟踪的文件(同时删除工作区文件)。
  • git rm --cache <文件名>:从暂存区移除文件,不再跟踪,但保留工作区文件。

3. 文件移动与重命名(git mv)

  • git mv <原文件名> <新文件名>:重命名一个已被 Git 跟踪的文件。
  • git mv <原目录/文件名> <新目录/文件名>:将文件移动到新目录并重命名。
  • 注意:此命令能保留文件的提交历史。你用git status查看会发现renamed: playbooks/networking/wifi_ap.md -> playbooks/wifi/wifi_access_point.md这样的log。如果直接使用操作系统的mvrename命令移动文件,Git 会将其视为“删除原文件”和“添加新文件”两个独立操作,会丢失修改的关联性。使用git mv可以避免这个问题。

3. 提交修改

先检查配置gitconfig--globaluser.name# 查询全局user.namegitconfig--globaluser.email# 查询全局user.emailgitconfig--global--list# 查询全局配置gitconfig--globaluser.name"xxx"# 配置全局user.namegitconfig--globaluser.email"xxx"# 配置全局user.email
  • git commit -m "提交说明":将暂存区的修改提交到本地仓库,并添加说明。
  • git commit -s -m "提交说明":添加签名。
  • git commit -s 后回车:添加签名,Git 会打开默认编辑器(如vimnano)(git config --global core.editor vim命令可将git默认编辑器调整为vim)
  • git commit -am "提交说明":直接将已跟踪文件的修改(未暂存)添加到暂存区并提交。(省去了git add ,太着急了吧)

4. 查看历史提交(git log)

  • git status:查看文件状态(未暂存文件红色,暂存文件绿色,提交后无显示)。
  • git log:查看提交历史,按时间倒序排列。
  • git log -n 2:查看最近两次的提交历史,按时间倒序排列。
  • git log da35b6 -n 2:查看da35b6在内最近两次的提交历史,按时间倒序排列。
  • git log -p -2:查看最近 2 次提交的具体修改内容(对比差异)。
  • git log --pretty=oneline:将每条提交记录压缩为一行显示,简洁高效。
  • git log --pretty=format:"%h 【%an】 %ar :《%s》":自定义提交记录格式,包含简化哈希(% h)、作者(% an)、距今时间(% ar)、提交说明(% s)。
  • git log --graph:以图形化形式展示提交历史,清晰查看分支合并关系。
  • git log -- <文件名>:查看对指定文件的所有提交
  • git log -S "function":看哪些提交改了function这个字符串
  • git log -p -S "function":在上一个基础上看修改function这个字符串的具体内容
  • git log -p -S "function"– driver/your_driver.c :在上一个基础上缩小查找范围
  • git log -L :函数名:文件名:通过-L选项指定函数范围,直接定位修改过该函数的所有提交
  • git log branch1..branch2 --oneline:查看branch2在branch1基础上还有哪些提交

三、差异对比(diff):工作区、暂存区与仓库的差异

通过git diff命令查看不同区域的文件差异,是定位修改内容的关键操作。

命令对比范围用途
git diff工作区 vs 暂存区(git add)查看未暂存的修改
git diff HEAD <文件名>工作区 vs 本地仓库(当前 HEAD)查看工作区与最新提交的差异
git diff --cached <文件名>暂存区(git add) vs 本地仓库(当前 HEAD)查看已暂存但未提交的修改
git diff refs/remotes/origin/master工作区 vs 远程 master 分支查看本地与远程分支的差异
git diff <旧提交ID1> <新提交ID2> --stat两次提交之间查看两次提交的文件修改统计(如修改行数)
git diff <旧提交ID1> <新提交ID2> <文件名>两次提交的指定文件查看具体文件在两次提交间的差异

四、远程仓库操作:连接与同步

团队协作中需频繁与远程仓库交互,包括连接、推送、拉取等操作。

1. 远程仓库管理

  • git remote -v:查看已配置的远程仓库 URL(-v表示显示详细信息)。
  • git remote add <远程名> <URL>:添加远程仓库,通常远程名设为origin
  • git remote rm <远程名>:删除指定的远程仓库配置。
  • git remote rename <旧名> <新名>:修改远程仓库的名称。

2. 推送与拉取

  • git push <远程仓库> <本地分支名>:<远程分支名>:将特定本地分支推送到远程仓库,若远程分支不存在则自动创建。
  • git push <远程仓库> <远程分支名>:简化写法,将本地master分支推送到origin远程的master分支。
  • git push -u <远程仓库> <远程分支名>:推送分支并建立 “跟踪关系”,后续推送直接用git push
  • git push <远程仓库> --delete <分支名>删除 指定的 远程仓库 中的 指定分支
  • git fetch <远程仓库>:拉取远程仓库的所有分支更新到本地(不合并到当前分支),若不指定分支则拉取所有分支。
  • git fetch --prune:拉取远程更新的同时,删除本地存在但远程已删除的分支,保持同步。

3. 远程分支查看删除等

  • git branch -r:只查看本地缓存的远程分支(如origin/master)。
  • git branch -a:查看所有分支(本地分支白色,当前分支绿色,远程分支红色)。
  • git branch -vv:查看本地分支与远程分支的关联关系,以及最近一次提交信息。
  • git remote show <远程名>:展示本地分支与远程分支的详细关联情况,包括更新状态。

五、分支操作:创建、切换与合并

分支是 Git 核心功能,用于并行开发、修复 bug 等场景,避免影响主分支。

1. 分支创建与切换

  • git branch <分支名>:创建新分支(如git branch Lyrix)。
  • git checkout <分支名>git switch <分支名>:切换到指定分支(两者功能一致)。
  • git checkout -b <新分支名>:创建新分支并立即切换到该分支。
  • git checkout -b <本地分支名> <远程名>/<远程分支名>:基于远程分支创建本地分支,并建立跟踪关系。
  • git checkout .:放弃工作区所有未暂存的修改,恢复到最近一次提交状态。

2. 分支合并

  • git merge <待合并分支名>:将指定分支的内容合并到当前分支(如在master分支执行git merge Lyrix,将Lyrix合并到master)。
  • 合并冲突处理:合并时若出现冲突,先用git status查看冲突文件,用编辑器修改冲突内容(保留需要的代码,删除冲突标记<<<<<<<=======>>>>>>>,),再执行git addgit commit完成合并。

3. 分支删除

  • git branch -d <分支名>:删除已合并到其他分支的本地分支(若分支未合并,会提示报错)。
  • git branch -D <分支名>:强制删除未合并的本地分支(谨慎使用,避免丢失代码)。
  • git push <远程名> -d <远程分支名>:删除远程仓库的指定分支(如git push origin -d Lyrix)。

4. 摘樱桃 cherry-pick

  • git cherry-pick <提交ID1> <提交ID2> <提交ID3>:将其他分支的某个特定提交 “复制” 到当前分支,适用于只需要单个提交、不需要整分支合并的场景(俗称 “摘樱桃”)。可以一次摘很多,用空格分隔,但注意他们是。

5. 分支重命名

  • git branch -m <new_branch_name>:重命名当前所在分支。

六、进阶操作:储藏、补丁与版本回退,子模块

这部分包含应对临时需求、代码复用、版本修正的进阶命令,解决开发中的特殊场景。

1. 工作区储藏(Stash)

当需要临时切换分支,但当前工作区修改未完成、不便提交时,用stash保存工作区状态。

  • git stash:将工作区和暂存区的修改保存到 “储藏栈”,工作区恢复干净状态。
  • git stash save "储藏说明":保存储藏时添加说明,方便后续识别。
  • git stash pop:应用储藏栈中最近的一次储藏,并删除该储藏记录(只能用一次)。
  • git stash apply:应用指定的储藏(如git stash apply stash@{1}),且不删除储藏记录(可多次应用)。
  • git stash list:查看所有储藏记录。
  • git stash drop <储藏ID>:删除指定的储藏记录(如git stash drop stash@{0})。
  • git stash show:查看储藏内容中哪些文件有修改。
  • git stash show -p:查看储藏内容的具体修改差异。

2. 补丁操作(Patch)

通过补丁文件分享代码修改,适用于未通过远程仓库协作的场景(如邮件发送修改)。

(1)生成补丁(git diffgit format-patch)
  • git diff <文件名> > <补丁名>.patch:生成单个文件的修改补丁(如git diff Test.java > test.patch)。
  • git diff > <补丁名>.patch:生成所有修改文件的补丁。
  • git format-patch <提交ID1>..<提交ID2> --stdout > <补丁名>.patch:生成两个提交间所有修改的补丁(不包含提交ID1)。
  • git format-patch -1 <提交ID> --stdout > <补丁名>.patch:生成单个提交的补丁。
  • git format-patch HEAD~3 --stdout > <补丁名>.patch:生成最近 3 次提交的补丁。
(2)应用补丁
  • git apply <补丁名>.patch:应用git diff生成的补丁,需手动执行git addgit commit
  • git am <补丁名>.patch:应用git format-patch生成的补丁,自动包含提交信息,无需手动提交。
  • git apply --check <补丁名>.patch:检查补丁是否可正常应用(无输出则表示无冲突)。
  • git apply -R <补丁名>.patch:撤销已应用的补丁。

3. 版本回退与修改

(1)版本回退(reset)

修改 HEAD 指针位置,回退到历史版本,适用于需要彻底删除后续提交的场景(谨慎使用,避免丢失代码)。

  • git reflog:查看所有历史版本的操作记录,获取需要回退的提交 ID。(如果之前rebase啥的把有用从commit给误删了,需要用这条命令查看之前 HEAD 指针的记录)
  • git reset --hard <提交ID>:强制回退到指定版本,工作区、暂存区均同步修改(会覆盖本地未提交的代码,需提前备份)。
  • git reset --soft <提交ID>:回退到指定版本,暂存区和工作区的修改保留(未提交状态)。
  • git reset --mixed <提交ID>:回退到指定版本,暂存区修改清空,工作区修改保留(默认模式)。
  • 远程版本回退:若已推送到远程仓库,需执行git push -f <远程名> <分支名>强制覆盖远程分支(团队协作中需提前沟通,避免影响他人)。
(2)反做(revert)

撤销某个历史提交的修改,但保留该提交之后的所有版本,适用于需要 “取消旧修改” 但不删除后续提交的场景(比reset更安全,推荐优先使用)。

  • git revert -n <提交ID>:反做指定提交的修改(-n表示不自动提交)。
  • 修改冲突文件(若有),执行git addgit commit -m "撤销XXX提交",再用git push推送到远程。
(3)修改提交历史(rebase)

用于 ①合并多个提交、②提交顺序调整、③提交说明修改、④适用于提交历史混乱时整理记录(仅整理本地未推送的提交,已推送的提交禁止使用)。

  • git rebase -i HEAD~2:交互式修改最近 2 次提交(HEAD~2表示最近 2 次,可替换为具体提交 ID)。
  • git rebase -i <commit_id>:修改指定的<commit_id>只有的提交
  • git rebase -i --root:从最初的 commit 之前开始修改。
  • 执行命令后会弹出编辑界面,按提示修改提交(如将pick改为squash合并提交,删除行则删除提交)具体步骤参考我的博客:【git rebase操作】.

4. git 子模块(git submodule)

在大型项目、开源项目或者包含第三方依赖库的代码仓库中经常用到。简单来说,Git 允许你把另一个独立的 Git 仓库,当作当前仓库的一个“子文件夹”来引用。
比如,你的项目依赖了一个第三方的开源库,你不想把它的代码直接复制粘贴到你的项目里(这样不好同步更新),于是你选择把它作为一个“子模块”挂载进来。
当你拉取包含git子模块的项目时你只需要执行

# 初始化并递归更新当前仓库中所有的 Git 子模块(Submodule)gitsubmodule update--init--recursive

如果你作为大型项目开发这个,如何第三方开源仓库的指定 commit 作为子模块挂载到你的工程呢?

  1. 第一步:添加子模块:

    # 语法:git submodule add <第三方仓库地址> <你希望存放的子模块目录名>gitsubmoduleaddhttps://github.com/username/repo.git path/to/submodule

    执行完这条命令后,Git 会自动把这个仓库克隆到你指定的目录下,并且会在你的项目根目录生成一个.gitmodules文件(用来记录子模块的仓库地址和路径)。

  2. 进入子模块,切换到指定的 Commit

    刚添加完时,子模块默认会停留在第三方仓库的默认分支(比如main)的最新提交上。我们需要把它切换到你想要的那个“指定 commit”。

    # 1. 进入子模块的目录cdpath/to/submodule# 2. 检出(checkout)你指定的 commit ID(或者 tag 标签)gitcheckout abc123456789# 3. 退出子模块目录,回到主仓库根目录cd../..
  3. 第三步:在主仓库中提交“版本锁定”记录(最关键的一步)

    把这个“子模块指向了 abc1234 版本”的信息,记录到主仓库的提交历史中。

    # 1. 将子模块目录的变更添加到暂存区(注意:这里 add 的是子模块的文件夹路径,不要带尾部斜杠)gitaddpath/to/submodule# 2. 提交到主仓库,并写上清晰的日志gitcommit-m"添加第三方库 xxx 作为子模块,并锁定到指定版本 abc1234"
  4. 第四步:推送到远程仓库

    最后,把你的主仓库(包含.gitmodules文件和子模块的 commit 指针)推送到远程:

    gitpush origin main

七、标签操作(tag):版本标记与发布

通过标签(Tag)标记重要版本(如发布版本v1.0),方便后续快速定位和回滚。

  • git tag <标签名>:在当前提交创建标签(如git tag v1.0)。
  • git tag:查看所有本地标签。
  • git tag -d <标签名>:删除本地标签。
  • git push <远程名> <标签名>:将指定标签推送到远程仓库(如git push origin v1.0)。
  • git push <远程名> --tags:将所有本地标签推送到远程仓库。
  • git checkout <标签名>:切换到指定标签对应的版本(少用)(处于 “分离头指针” 状态,修改需创建新分支)。

[!WARNING]

git checkout <标签名>使用注意,如果当前暂存区有来自不同仓库的同名tag, 则该命令可能会不如你意。这样操作:

  1. 获取远程仓库 tag 对应的 commit ID
gitls-remote repoA tags/<tag_name>
  1. 基于 commit ID 切换到目标版本
gitcheckout a1b2c3d4e5f6abcdef1234567890abcd12345678

八、常见问题与补充说明

如何查看当前所在分支?

执行git statusgit loggit branch --list,当前分支会用*标记或显示为绿色。

合并分支时必须切换到目标分支吗?

是的。例如要将Lyrix合并到master,必须先切换到master分支,再执行git merge Lyrix

本地分支与远程分支如何同步?

  1. 执行git fetch <远程名>拉取远程最新更新;
  2. 执行git merge <远程名>/<远程分支名>将远程更新合并到本地分支(如git merge origin/master)。

Fast Forward Merge 与 3-Way Merge 的区别?

  • Fast Forward Merge:目标分支(如master)没有新提交,直接将目标分支指针指向待合并分支(如Lyrix),无合并记录。
  • 3-Way Merge:目标分支有新提交,需基于两者的共同祖先创建新的合并提交,保留合并记录。

日常开发分支管理思路

你的思路本质上是通过分支隔离 “有效成果” 和 “临时调试”,这是合理的,但可以进一步优化分支策略,让流程更清晰、协作更顺畅(即使是个人开发)。以下是具体建议:

一、你的方案的合理性与可优化点

合理性

  • 用两个分支隔离 “干净的有效补丁” 和 “杂乱的调试过程”,避免有效代码被临时调试代码污染,方便后续整理和合并。

可优化点

  • 若仅用两个分支,长期开发可能导致 “有效分支” 堆积过多补丁,难以追溯每个功能的来源;“调试分支” 过于杂乱,回头看时可能分不清哪些调试是针对哪个问题的。

二、更推荐的分支管理策略(适合个人开发)

核心思路:按 “功能 / 任务” 拆分短期分支,用一个 “主开发分支” 整合有效成果,用 “临时调试分支” 做尝试,形成 “短期尝试→验证有效→合并到主开发分支” 的闭环。

具体分支结构建议:

分支类型命名示例用途生命周期
主开发分支devdevelop存放经过验证的、可整合的有效代码(类似你的 “有效 patch 分支”)长期存在,持续更新
功能 / 任务分支feature/xxx针对单个功能或任务(如 “修复 XXbug”“实现 XX 功能”)创建的短期分支功能完成并合并后删除
调试 / 实验分支debug/xxx-issue记录针对某个问题的调试过程(带临时日志、调试代码)问题解决后可删除或归档
稳定版本分支release/v1.0(可选)dev分支拉出,用于发布或测试的稳定版本长期保留,仅修复 bug

三、日常开发流程(按步骤说明)

从主分支创建功能分支

每次开始一个明确的任务(如 “开发 A 功能”“修复 B bug”),从dev分支创建一个功能分支:

gitcheckout devgitpull# 确保主分支最新gitcheckout-bfeature/implement-A# 功能分支

这个分支只专注于该任务,提交记录尽量清晰(如 “完成 A 功能的核心逻辑”“修复 A 功能的边界条件”)。

用调试分支做 “脏实验”

若开发中需要做大量尝试性调试(如 “测试某个猜想”“临时加日志排查问题”),从当前功能分支创建调试分支:

gitcheckout feature/implement-Agitcheckout-bdebug/test-A-logic# 调试分支

这里可以随意提交临时代码(甚至带printk、注释掉部分逻辑),不用担心污染功能分支。

验证有效后合并到功能分支

调试出有效结论后(如 “这个思路可行”“这段代码能修复问题”),将调试分支中的有效代码整理后合并到功能分支:

# 切换到功能分支gitcheckout feature/implement-A# 合并调试分支的有效代码(可选 rebase 让提交更整洁)gitmerge--squashdebug/test-A-logic# 把调试分支的提交压缩成一个gitcommit-m"完成A功能的XX逻辑(解决了XX问题)"# 若提交描述信息拼写错误、不准确时重新编辑描述。修改最近一次提交的描述(未推送时使用)gitcommit--amend# 如果修改历史提交信息,需要git rebase, 修改pick为reword(只改提交描述),如果已经推送到远端想想强推则git push --force-with# 调试分支完成使命,可删除gitbranch-ddebug/test-A-logic

功能完成后合并到主开发分支

当功能分支的代码经过充分验证(如自测通过、无调试残留),合并到dev分支:

gitcheckout devgitmerge feature/implement-Agitpush origin dev# 功能分支可删除(或保留以备后续修改)gitbranch-dfeature/implement-A

四、关键技巧:让分支管理更高效

提交记录 “原子化”

每个提交只做一件事(如 “修复 XX 函数的参数错误”“添加 XX 功能的配置项”),避免一个提交包含多个不相关修改。这样后续回滚或查找问题时更方便。

善用git stash临时保存工作区

若调试到一半需要切换分支(如突然要改另一个 bug),可用git stash保存当前未提交的修改,切换分支处理完后再git stash pop恢复,避免频繁创建临时分支。

定期 “清理” 无用分支

功能分支和调试分支完成后及时删除,避免本地分支列表过于臃肿(可用git branch -vv查看已合并的分支,放心删除)。

必要时 “归档” 调试过程

  1. 若某些调试过程有参考价值(如 “解决了一个罕见 bug 的思路”),可以不删除调试分支,而是用标签(git tag debug/20241028-xxx-issue)标记,方便后续查阅。

五、为什么这样更有效?

  • 聚焦性:功能分支只对应一个任务,提交记录清晰,方便追溯;调试分支隔离临时操作,不影响核心代码。
  • 灵活性:即使调试分支搞乱了,也不会影响功能分支和主分支,大不了删掉调试分支重新来。
  • 可扩展性:若后续需要多人协作,这种结构能无缝衔接(每人在自己的功能分支开发,通过dev分支整合)。

简单说,核心就是 “按任务拆分,按有效性分层”:用功能分支保证代码的 “可追溯性”,用调试分支承担 “试错成本”,用主分支沉淀 “有效成果”。比单纯两个分支更有条理,长期开发会更省力。

六、如何将测试分支高效合并到功能分支

关键原则:减少 “调试提交” 的杂乱度

与其事后整理,不如在调试时养成习惯,减少后续工作量:

  1. 调试代码单独标记:在调试语句前统一标记(如// DEBUG_LYRIX:),方便后续全局搜索删除;
  2. 避免 “为调试而提交”:非必要不提交纯调试代码(可用git stash临时保存),只在有有效进展时提交;
  3. 小步提交有效代码:调试中一旦有明确的有效修改(如修复一个逻辑错误),立即提交并写清楚注释(如 “修复 XX 条件判断错误”),避免有效代码和调试代码混在一起
切换到调试分支,基于功能分支的最新状态做 “交互式变基”
git cherry-pick精准提取有效提交

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询