Git 工程指引(命令+问题) - 指南

Git 工程常用指令

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 中表示当前 活动分支 的最新提交
  • 每个分支(如 mainfeature 等)在 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~1HEAD^ 完全一样;
对于 merge commit,HEAD^1HEAD^2 分别表示两个父分支

✅ 举个完整例子
A --- B --- C --- D   (main)
             \
              E --- F   (feature)
# 执行 git merge feature on main,生成 G
G 是 merge commit,有两个父:D 和 F

现在 HEAD 指向 G

命令结果
HEAD^1D(main 分支的最新提交)
HEAD^2F(feature 分支的最新提交)
HEAD~1D(等同于 HEAD^1
HEAD~2B(D 的父提交)

✅ 关键点:

  • HEAD^2 指的是“另一个分支”的提交(F
  • HEAD~2 指的是“连续两个步骤”的祖先(B
错误做法正确做法原因
git reset --hard HEAD^2git reset --hard HEAD~2HEAD^2 只能用于 merge commit,否则报错
git revert HEAD^2git revert HEAD~2revert 不能作用于 parent,只能作用于 commit hash
混淆 HEAD^2HEAD~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~1HEAD^ 完全一样;
对于 merge commit,HEAD^1HEAD^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
所以 其实两个都是代表的指针了!!!

gitp
gitp配置为git push origin HEAD:refs/for/master 的别名

  1. 打开你的终端。
  2. 输入命令git config --list来列出所有配置的别名。
  3. 在输出的列表中查找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 -Agit add .,除非特别需要控制范围。

merge 和 rebase 区别

在这里插入图片描述

特性git mergegit 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 pullfetch + merge,自动合并

✅ 推荐先用 fetch,再手动 mergerebase,避免意外冲突

推荐流程:

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-forwardMergeRebase
是否产生新 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
  • CD 重新放在 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-pickFast-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’

  1. 打开 左侧的 源代码管理可以 - + 可以右键 copy,create
  2. git status 确定修改的状态
  3. git status只会查看你的本地origin/master引用,会存在消息不准确不及时,及不等于与上游的最新实时状态保持最新状态
  4. git pull
  5. 点击终端的文件,一个个右上角确定了修改是正确的。看一个添加一个
  6. 可以先 本地git add,git commit 存一下,防止丢了只有push了才会经历评审的环节

git tag -a “” -m

Git 标签(Tag)用于给仓库中的特定提交点加上标记,通常用于发布版本(如 v1.0, v2.0)
执行 git log --decorate 查看标签

打标签的操作发生在我们commit修改到本地仓库之后

推送标签到远程仓库

默认情况下,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~1git 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
posted on 2026-01-21 11:29  ljbguanli  阅读(0)  评论(0)    收藏  举报