Git 工程指引(命令+问题) - 指南
Git 工程常用指令
- Git Bash
- 重要的参数
- 辨析
- Fast-forward only
- 附录:常用命令速查表
- 问题记录
- 特殊场景
Git Bash
git客户端升级至2.26及以上版本
git流程

文件的三种状态
- Untracked files 未跟踪
- Changes not staged for commit 未提交的更改
- Changes to be committed 提交的更改
到底哪些操作会导致Git合并冲突呢
不同分支修改了同一文件的同一行代码才会产生冲突,但是有一个例外:不同分支修改的是同一文件的相邻行
或者
多个分支修改了同一个文件的名称,如果两个分支中分别修改了不同文件中的部分,是不会产生冲突,直接合并即可
有些相邻甚远的地方,git是可以smart merge
但是
有的还得自己做决定ing:
<<<<<<<=======>>>>>>>

<<<<<<<和====== 之间的所有内容都是你的本地修改。 这些修改还没有在远程版本库中 =======和>>>>>>>之间的所有行都是来自远程版本库或另一个分支的修改。现在你需要研究这两个部分并做出决定。
重要的参数
HEAD、head和master
本地分支最新提交的快照
HEAD在 Git 中表示当前 活动分支 的最新提交- 每个分支(如
main、feature等)在 Git 中本质上是一个指向特定 提交 的引用,而HEAD则指向当前活动的分支例如: - 如果你在
main分支上工作,HEAD就指向main分支的最新提交。 - 如果你在
feature分支上工作,HEAD就指向feature分支的最新提交 - 有的时候HEAD会指向一个没有分支名字的修订版本,这种情况叫”detached HEAD“
- head(小写)是commit对象的引用,每个head都有一个名字(分支名字或者标签名字等等),但是默认情况下,每个叫master的repository都会有一个head, 一个repository可以包含任意数量的head。在任何时候,只要这个head被选择成为”current head“,那么这个head就成了HEAD,总是大写
本地的父提交
小技巧:
HEAD~1= 上一步- HEAD~1 == HEAD^ == HEAD^1
HEAD~2= 上两步HEAD^2= 第二个父节点(复杂合并时用)
| 写法 | 含义 | 备注 |
|---|---|---|
HEAD~1 | 第一个祖先(前一个 commit) | 推荐,通用 |
HEAD^ | 第一个父节点(前一个 commit) | 等同于 HEAD~1 |
HEAD^2 | 第二个父节点(比如合并了两个分支) | 仅用于 merge commit |
对于普通提交,HEAD~1 和 HEAD^ 完全一样;
对于 merge commit,HEAD^1 和 HEAD^2 分别表示两个父分支
✅ 举个完整例子
A --- B --- C --- D (main)
\
E --- F (feature)
# 执行 git merge feature on main,生成 G
G 是 merge commit,有两个父:D 和 F
现在 HEAD 指向 G:
| 命令 | 结果 |
|---|---|
HEAD^1 | D(main 分支的最新提交) |
HEAD^2 | F(feature 分支的最新提交) |
HEAD~1 | D(等同于 HEAD^1) |
HEAD~2 | B(D 的父提交) |
✅ 关键点:
HEAD^2指的是“另一个分支”的提交(F)HEAD~2指的是“连续两个步骤”的祖先(B)
| 错误做法 | 正确做法 | 原因 |
|---|---|---|
git reset --hard HEAD^2 | git reset --hard HEAD~2 | HEAD^2 只能用于 merge commit,否则报错 |
git revert HEAD^2 | git revert HEAD~2 | revert 不能作用于 parent,只能作用于 commit hash |
混淆 HEAD^2 和 HEAD~2 | 区分清楚 | 一个是“第2个父”,一个是“往上走2步” |
远程在 本地缓存 的引用
origin/master 是远程仓库(origin)的master分支在本地缓存的引用,通过git fetch更新
- 与本地
HEAD的关联:git merge origin/master:合并远程分支到当前分支,可能产生分叉历史。git rebase origin/master:将本地提交线性追加到远程分支后,保持历史整洁
commit
commit规范
- feat: 新功能
- fix: 修复问题
- docs: 修改文档
- style: 修改代码格式,不影响代码逻辑
- refactor: 重构代码,理论上不影响现有功能
- perf: 提升性能
- test: 增加修改测试用例
- chore: 修改工具相关(包括但不限于文档、代码生成等)
- deps: 升级依赖
–amend --no-edit
git commit --amend:会打开编辑器让您修改提交信息git commit --amend --no-edit:保持提交信息不变,仅修改提交内容(git commit --amend:- 使用
git commit --amend来覆盖修正上一次的提交,相当于上次提交错误的信息被覆盖了,在gitk图形化界面和git log上都看不到之前的信息 - 在
git commit时绑定了错误的icafe或者commit信息需要修改时,如果还没有push到远端,可直接使用git commit --amend --message="修改后的message"来修改提交信息
- 使用
-v
-v 显示的差异是工作区与暂存区的比较(即 git diff --staged 的结果)git commit -v 会在编辑器底部追加一个差异对比(类似 git diff 的输出),帮助你更清晰地核对改动。
合并提交(Merge Commit)
- 如果你执行了一个 git merge,比如把 feature 合并到 main,那么生成的这个新 commit(merge commit)有两个父节点:
- 一个是 main 的最后一个 commit
- 一个是 feature 的最后一个 commit
对于普通提交,HEAD~1 和 HEAD^ 完全一样;
对于 merge commit,HEAD^1 和 HEAD^2 分别表示两个父分支
对比cherry-pick
cherry-pick到底应该怎么翻译?——优选
把某次 commit 应用到另一个分支
pull + push
相同的才会覆盖,不同的直接新建了
完整命令
- 完整的推——拉命令
git push origin 本地分支:远程分支
git pull origin 远程分支:本地分支
- 缺省参数
git push origin master
如果远程分支被省略,如上则表示将本地分支
git push origin master:refs/for/master
是将本地的master分支推送到远程主机origin上的对应master分支
git push origin HEAD:refs/for/master
HEAD: 是一个特别的指针,它是一个指向你正在工作的本地分支的指针
“refs” 并非是缩写,它代表 “references”(引用)的意思。在 Git 里,引用是指向提交对象的指针,比如远程分支 origin/master 的完整引用路径是 refs/remotes/origin/master
所以 其实两个都是代表的指针了!!!
gitpgitp配置为git push origin HEAD:refs/for/master 的别名
- 打开你的终端。
- 输入命令
git config --list来列出所有配置的别名。 - 在输出的列表中查找
gitp相关的配置。
辨析
git add . git add -A,git add -u区别
git add .添加当前目录下所有新文件、修改过的文件(包括未跟踪的文件)不包含被删除的文件- 类比:
git add *会忽略隐藏文件,.gitignore文件也不会被加进去 git add -A添加/移除/修改的所有内容 ,是git add .和git add -u的合集,既包括新增文件,也包括被删除的文件- 如果之前删掉了文件,只用
git add .不会把这个删除动作记入暂存区 git add -u只添加 已跟踪文件的更改(modified + deleted)- 忽略未跟踪文件三种情况
- 新建立的文件
- 或者 git aad . 之后 用git rm --cache从暂存区的new file变成 未跟踪
- .gitignore文件中的
✅ 举例说明:
# 假设你做了以下操作: touch new_file.txt # 新建了一个文件 echo "hello" > main.py # 修改了 main.py rm old_file.txt # 删除了一个文件 git add . → 只加 main.py 和 new_file.txt(不加删除) git add -A → 加 main.py, new_file.txt, 删除 old_file.txt git add -u → 加 main.py 和 删除 old_file.txt(不加 new_file.txt)
| 命令 | 跟踪文件 | 未跟踪文件 | 删除文件 |
|---|---|---|---|
git add . | ✅ | ✅ | ❌ |
git add -A | ✅ | ✅ | ✅ |
git add -u | ✅ | ❌ | ✅ |
⚠️ 建议:日常使用推荐
git add -A或git add .,除非特别需要控制范围。
merge 和 rebase 区别

| 特性 | git merge | git rebase |
|---|---|---|
| 合并方式 | 产生一个“合并 commit” | 把你的 commit“挪到”目标分支后面 |
| 历史是否干净 | ❌ 有多个分支线 | ✅ 更线性、清晰 |
| 是否修改历史 | ❌ 不改 | ✅ 会改(需谨慎) |
A---B---C (main)
\
D---E (feature)
git merge feature → 产生 F(合并)
git rebase main → D', E' 在 C 后面,变成直线
✅ git merge 示例(标准流程)
git checkout feature
git merge main # 合并 main 分支到 feature
- 生成一个“合并提交”
- 历史像一棵树
✅ git rebase 示例(重构历史)
git checkout feature
git rebase main
- 把
feature上的所有 commit 都“重新建立”在main的最新基础上 - 像一条直线
pull 和 fetch 区别
git fetch 不指定分支,默认是fetch所有分支
| 命令 | 行为 | 是否自动合并 |
|---|---|---|
git fetch | 拉取远程分支信息,不改变本地分支 | ❌ |
git pull | fetch + merge,自动合并 | ✅ |
✅ 推荐先用
fetch,再手动merge或rebase,避免意外冲突
推荐流程:
git fetch origin # 获取远程最新状态
git checkout main
git rebase origin/main # 把本地分支基于远程更新
回退到某个版本revert和reset区别
这是最常见的误区!
| 操作 | 是否重建历史 | 影响哪些人 | 使用场景 |
|---|---|---|---|
git reset --hard <commit> | ✅ 暴力的,破坏性的 | 所有人受影响 | 本地开发,误提交 |
git revert <commit> | ❌ 安全 | 所有人都能拉取 | 修复线上 bug |
✅ 1. git reset --hard <commit>
git reset --hard b3a8f2d5
- 把当前分支指针指向
b3a8f2d5 - 所有后面的 commit 都被物理删除
- 工作区和暂存区也同步更改
- ✅ 适用于本地开发,没 push 时
✅ 2. git revert <commit>
git revert b3a8f2d5
- 在当前分支的前面创建一个新的 commit,内容是“反向应用 b3a8f2d5”
- 安全!不会破坏历史
- ✅ 用于生产环境修复错误
git restore vs git reset vs git revert
| 命令 | 用途 | 作用对象 | 是否改历史 |
|---|---|---|---|
git restore | 恢复文件到某个状态(工作区或暂存区) | 单个文件或目录 | ❌ 不改历史 |
git reset | 移动分支指针,更改当前分支的提交历史 | 整个分支/HEAD | ✅ 改历史 |
git revert | 创建一个“反向”的新 commit,撤销之前的提交 | 特定 commit | ❌ 不改历史 |
✅ 总结:
- 想恢复某文件 →
restore- 想删除最近一次 commit →
reset- 想安全地撤销已发布的 commit →
revert
1. git restore —— ❤️❤️
# 从暂存区移除文件,相当于 左边的Unstage changes
git restore --staged <file>
# 放弃文件修改,相当于 左边的 Discard changes
git restore <file>
# 把某个文件恢复到之前的版本
git restore --source=<commit> <file>
✅ 作用:
将文件从 暂存区(index)或历史版本 恢复到工作区(working directory)
注意:
- 只影响文件,不影响提交历史
- 适用于:误删、误加、修改后想回滚
常见用法:
A. 把工作区文件还原为上一版本(未 add)
git restore file.txt
- 将
file.txt恢复到最后一次 commit 的内容(忽略所有未暂存的更改)
B. 把文件从暂存区移除(unstage)
git restore --staged file.txt
- 等价于
git reset HEAD file.txt,但语法更清晰
C. 恢复特定 commit 中的文件
git restore --source=HEAD~1 file.txt
- 把
file.txt恢复成HEAD~1那个版本的内容
推荐:Git ≥ 2.23 支持
restore,是现代首选。
2. git reset —— 移动分支指针(可破坏历史)
✅ 作用:
将当前分支的 HEAD 指针指向另一个 commit,从而改变历史。
⚠️ 危险!⚠️
- 如果已经 push 到远程,请慎用(可能造成冲突)
三个模式(参数):
| 模式 | 作用 | 行为 |
|---|---|---|
--soft | 只移动 HEAD,不改变索引和工作区 | 所有更改仍在暂存区 |
--mixed(默认) | 移动 HEAD,清空暂存区 | 工作区不变,暂存区清空 |
--hard | 移动 HEAD,清空暂存区和工作区 | 所有更改丢失 |
示例说明:
假设当前状态:
A (origin/main) ← B (main) ← C (feature)
1. git reset --soft HEAD~1
git reset --soft HEAD~1
- 把
main指针移到B(即取消最后一次提交 C) - ✅ 所有更改还在暂存区,可以重新提交
- ✅ 适合:你要重新组织 commit
2. git reset --mixed HEAD~1
git reset --mixed HEAD~1
- 把
main指针移到B - ❗ 暂存区清空,但工作区保留代码
- ✅ 适合:放弃提交,但保留代码继续改
3. git reset --hard HEAD~1
git reset --hard HEAD~1
- 把
main指针移到B - ❌ 工作区也清空,C 的所有改动全部丢失
- ⚠️ 谨慎!只能用于本地开发
3. git revert —— 安全地撤销
✅ 作用:
创建一个新的 commit,其内容是“反向”应用某个旧 commit
不会破坏历史,可以安全地 push 给团队
举例:
# 提交历史:
A → B → C → D
你想撤销 B 这次提交:
git revert B
结果变成:
A → B → C → D → B_revert
- 新建了一个 commit,叫做
B_revert - 里面包含“把 B 的改动都去掉”的操作
✅ 优点:安全,不会重写历史
✅ 适用场景:线上环境修复 bug
对比总结:
| 命令 | 修改历史? | 适用场景 |
|---|---|---|
git reset | ✅ 是(危险) | 本地开发,想丢弃提交 |
git revert | ❌ 否(安全) | 公开分支,修复错误 |
git restore | ❌ 否 | 文件级恢复,误操作 |
Fast-forward only
什么是 Fast-forward?
一种特殊的
git merge方式,当目标分支没有新提交时,落后并且之前都是线性,直接把当前分支快进过去
如果存在分叉,会拒绝合并
场景示例:
main: A → B
feature: A → B → C
如果 main 没有新提交,执行:
git checkout main
git merge feature
→ Git 会直接把 main 指针指向 C,不需要创建新的 merge commit
这就是 Fast-forward merge
为什么叫 “only”?
“Fast-forward only” 是说:只允许 fast-forward 类型的合并,不允许创建 merge commit
通常用在:
- 保护主干分支(如
main/develop) - 保证历史线性(避免无意义的 merge commit)
Fast-forward vs Merge vs Rebase
| 特性 | Fast-forward | Merge | Rebase |
|---|---|---|---|
| 是否产生新 commit? | ❌ 否 | ✅ 是(合并 commit) | ❌ 否(本质是重写) |
| 历史是否干净? | ✅ 干净(线性) | ❌ 有分叉 | ✅ 干净(线性) |
| 是否改历史? | ❌ 否 | ❌ 否 | ✅ 是(会改) |
| 适用人群 | 团队协作 | 团队协作 | 个人项目 |
| 优点 | 简单、无污染 | 安全 | 历史整洁 |
| 缺点 | 限制条件多 | 历史混乱 | 有风险 |
实际例子对比:
main: A → B
feature: A → C → D
1. git merge feature(普通 merge)
main: A → B → C → D → M (M 是 merge commit)
- 产生合并节点,历史有分叉
2. git merge --ff-only feature
- ✅ 成功(因为主干没变),变成:
main: A → B → C → D
- ❌ 失败(如果主干有变动)
3. git rebase main
git checkout feature
git rebase main
- 把
C、D重新放在B后面:
feature: A → B → C' → D'
C'、D'是新 hash(因为改变了时间顺序)
注意:
rebase会改变 commit ID!
git cherry-pick 是什么?和 Fast-forward 的区别
✅ 作用:
把某个 commit 的内容复制到当前分支,而不是合并整个分支,常用于 拿过来别人写好的补丁
示例:
# 你知道 commit C 是好代码
A → B → C (good) → D (bad)
你想把这个 C 应用到另一个分支(比如 hotfix):
git checkout hotfix
git cherry-pick C
结果:
hotfix: ... → C_new
- 新建一个 commit,内容完全一样,但 hash 不同
✅ 用途:把别人写的 fix 拿过来,不用拉整个 branch
和 Fast-forward 的区别:
| 特性 | cherry-pick | Fast-forward |
|---|---|---|
| 是否复制单个 commit | ✅ 是 | ❌ 否 |
| 是否改变历史 | ✅ 是(生成新 commit) | ❌ 否(只是指针移动) |
| 适用场景 | 引入特定补丁 | 合并完整分支 |
| 是否需要指定 commit | ✅ 必须 | ❌ 自动匹配 |
附录:常用命令速查表
| 命令 | 功能 |
|---|---|
git reset --soft HEAD~1 | 取消最近一次提交,保留更改 |
git reset --mixed HEAD~1 | 取消提交,清除暂存区 |
git reset --hard HEAD~1 | 取消提交,清空工作区(危险!) |
git restore --staged file | 从暂存区移除文件 |
git restore file.txt | 恢复文件到最新 commit |
git revert HEAD | 撤销最后一次提交 |
git cherry-pick b3a8f2d | 复制某个 commit 到当前分支 |
git rebase main | 把当前分支基于 main 重排 |
git merge --ff-only feature | 只允许快进合并 |
git status——❤️

提供以下关键信息:
当前分支信息:
git status会显示当前所处的分支名称。与远程分支的差异
已暂存的更改(Changes to be committed)
需要unstage——stage,可以直接 可视化的 - + 去操作
# 查看暂存区的修改内容
git diff --staged <file>
# 如果需要取消暂存(回到未暂存状态)——三种方法
git restore --staged <file>
git rm --cached <file>
git reset HEAD <file>
# 注意,下边的会把工作区 的文件彻底删除!!!
git rm --force <file>
- 未暂存的更改(Changes not staged for commit)
# 查看具体修改内容
git diff <file>
# 添加到暂存区准备提交
git add <file>
# 或放弃修改(恢复到上次提交的状态)
git restore <file>
- 未跟踪的文件(Untracked files)
Your branch and ‘origin/master’ have diverged

git pull
Your branch is up to date with ‘origin/master’
- 打开 左侧的 源代码管理可以 - + 可以右键 copy,create
- git status 确定修改的状态
- git status只会查看你的本地origin/master引用,会存在消息不准确不及时,及不等于与上游的最新实时状态保持最新状态
- origin/master”指的是指向“origin/master”分支的 HEAD 提交的引用。引用是 Git 对象(通常是提交对象)的易于理解的别名。“origin/master”引用只有在您git push访问远程仓库时才会更新
- 因为Git的设计理念是尽可能避免不必要的网络操作,存放的,比较的是引用,并不是最新的
- 解决办法一:替换为
git remote show origin再检查一遍 - 解决办法二:
git fetch之后再次git status,
git pull- 点击终端的文件,一个个右上角确定了修改是正确的。看一个添加一个
- 可以先 本地git add,git commit 存一下,防止丢了只有push了才会经历评审的环节
git tag -a “” -m
Git 标签(Tag)用于给仓库中的特定提交点加上标记,通常用于发布版本(如 v1.0, v2.0)
执行 git log --decorate 查看标签
推送标签到远程仓库
默认情况下,git push 不会推送标签,你需要显式地推送标签
git push origin
推送所有标签:
git push origin --tags
删除轻量标签
本地删除:
git tag -d
远程删除:
git push origin --delete
问题记录
push时候:invalid change-id
第一步:安装hook
// 方法一
curl -s http://icode.baidu.com/tools/hooks/commit-msg > $(git rev-parse --git-dir)/hooks/commit-msg && chmod u+x $(git rev-parse --git-dir)/hooks/commit-msg
// 方法二
mkdir -p $(git rev-parse --git-dir)/hooks && curl -s http://icode.baidu.com/tools/hooks/commit-msg > $(git rev-parse --git-dir)/hooks/commit-msg && chmod u+x $(git rev-parse --git-dir)/hooks/commit-msg
第二步:
git commit --amend --no-edit
若依然无法push,请尝试git reset --soft origin/[branchname]后重新commit
git reset --soft origin/master
--soft:只移动 HEAD 指针,暂存区和工作区不变origin/master:远程分支的最新 commit- 把当前分支的 HEAD 指针移到
origin/master - 所有本地更改仍然在暂存区或工作区(你还能重新提交)
pull时候:You have divergent branches and need to specify how to reconcile them
// ------使用合并
# 设置默认使用合并
git config pull.rebase false
git pull
# 或直接执行:
git pull --no-rebase
# 如果有冲突,解决冲突后提交
git add .
git commit -m "合并远程更新"
// ------使用变基
git config pull.rebase true
git pull
# 或直接执行:
git pull --rebase
# 如果有冲突,解决每个冲突后:
git add .
git rebase --continue
pull 时候,error: cannot pull with rebase: You have unstaged changes,Please commit or stash them.
// 方法一:
# 首先 ,手动把unstaged changes里面的文件,存到另外 文本文件里面去
# 把unstaged changes 回滚到之前的版本
git restore
# 再次执行
git pull
# 最后手动把 文本文件 里面的内容复制过来
// 方法二
# 临时保存未提交的更改 到堆栈
git stash
git pull
git stash pop
# 或者 apply,堆栈的内容还在,只是应用了一下
特殊场景
两类Git 使用的方式,根据分支来看
Gerrit的那种评审分支——❤️
# 第一次提交 CR
git add .
git commit -m "feedas-123"
git push origin HEAD:refs/for/master
# 第二次提交 CR
git add .
git commit --amend --no-edit
// git commit --amend -m "修改的信息"
git push origin HEAD:refs/for/master
git工作流gitflow的那种多分支开发
① 切换主开发分支(假设名称是develop),拉取最新代码
git checkout develop
git pull
② 切换个人开发分支(假设名称是feat_gcx),合并最新代码
git checkout feat_gcx
git branch (这步可有可无,确认一下是否切过来了)
git merge develop
③ 若没有冲突,可以直接推到远程仓库
git push
④ 若有冲突,则先把冲突部分删除,再进行提交
git add -A
git commit -a -m “XXX”
git push
⑤ 开启劳累的一天
⑥ 提交代码,和4步骤一模一样。
精准分享关键代码
#L行号
#L开始行号-L结束行号
撤销操作——❤️
都可以用git restore!!!
取消本次暂存区的文件
# 三种方法
git restore --staged <file>
git rm --cached <file> # 由modified:变成deleted: 的记录,所以会被一起提交上去。由new file:变到了Untracked files:
git reset HEAD <file> # HEAD 可以理解为当前分支了,而不是提交的快照了
放弃文件修改
都是使用restore和checkout 两种
还在本次暂存区,未提交的
# 两种方法
git restore <file>
git checkout -- example.txt # --表示“选项结束”,为了明确分隔命令参数与文件路径
已经提交了(回到过去提交的状态)
# Git 的 commit ID 是 SHA-1 哈希值(40 位十六进制)
# 你可以用 前7~10 位 作为缩写(只要唯一即可)
git log
git checkout
# 然后add,重新push,这个文件的更改
git add <这个 file>
git commit --amend --no-edit
git push origin HEAD:refs/for/master
| 命令 | 功能 | 特点 |
|---|---|---|
git checkout <commit> <file> | 把某个文件恢复到之前的版本 | 旧版语法,仍在支持 |
git restore --source=<commit> <file> | 同上,更现代 | 推荐! |
常用高级命令
| 命令 | 用途 | 示例 |
|---|---|---|
git log --oneline --graph | 查看带图的提交历史 | git log --oneline --graph |
git reflog | 查看所有 HEAD 变化(可找回被 reset 的 commit) | git reflog |
git cherry-pick <commit> | 把某次 commit 应用到另一个分支 | git cherry-pick abcdef |
git stash | 临时保存未提交的更改 | git stash / git stash pop |
git branch -D <name> | 强行删除分支(含未合并的) | git branch -D feature |
git tag v1.0 | 给某个 commit 打标签 | git tag v1.0 |
| git resert | 回退到前一个提交 | git reset --hard HEAD~1 或 git reset --hard HEAD^ |
| git show | 查看合并提交的父节点 | git show HEAD^1 / git show HEAD^2 |
git reset --soft HEAD~1 | 丢弃最近一次提交 | 保留代码,重新提交 |
git restore file.txt | 回滚工作区文件 | 安全,不改历史 |
git revert <commit> | 撤销已发布的 commit | 安全,推给团队 |
git rebase main | 想要线性历史 | 重构历史,但小心 |
git cherry-pick abcdef | 从别人分支拿一个 fix | 复制单个 commit |
git merge --ff-only feature | 合并分支(无冲突) | 保持线性 |
git merge feature | 想自动合并 | 自动创建 merge commit |
浙公网安备 33010602011771号