00385 Git 命令行完全教程


Git 命令行完全教程

目标:从零开始,用纯命令行完成 VS Code 可视化 Git 的所有常用操作。


目录

  1. 初始化仓库
  2. 提交代码
  3. 查看提交记录
  4. Tag 标签管理
  5. Worktree 多分支并行开发
  6. 打包特定版本为 zip
  7. 版本回退
  8. 查看特定记录的代码
  9. Merge 合并
  10. 解决合并冲突
  11. 附:常用命令速查表

1. 初始化仓库

1.1 全新项目

# 创建项目目录并进入
mkdir my-project
cd my-project

# 初始化 git 仓库
git init

# 查看仓库状态
git status

执行后会在当前目录生成 .git 隐藏目录,这就是 git 的”数据库”。

1.2 配置用户信息(首次使用必做)

git config --global user.name  "你的名字"
git config --global user.email "your@email.com"

# 查看配置
git config --list

1.3 忽略不需要跟踪的文件

创建 .gitignore 文件:

cat > .gitignore << 'EOF'
# 编译产物
*.o
*.class
*.pyc
__pycache__/

# 依赖
node_modules/
vendor/

# 系统文件
.DS_Store
Thumbs.db

# IDE
.vscode/
.idea/

# 敏感文件
.env
*.key
*.pem
EOF

1.4 克隆已有仓库

# 通过 SSH(推荐)
git clone git@github.com:user/repo.git

# 通过 HTTPS
git clone https://github.com/user/repo.git

# 克隆到指定目录
git clone git@github.com:user/repo.git my-folder

2. 提交代码

2.1 基本工作流

# 第一步:查看当前状态(看看改了哪些文件)
git status

# 第二步:添加文件到暂存区
git add 文件名              # 添加单个文件
git add file1.txt file2.py  # 添加多个文件
git add src/                # 添加整个目录
git add .                   # 添加当前目录所有改动

# 第三步:提交到本地仓库
git commit -m "feat: 添加登录功能"

# 一步到位:添加所有已跟踪文件的改动并提交
git commit -am "fix: 修复分页bug"
# 注意:-a 只对已跟踪的文件生效,新文件仍需先 git add

2.2 提交信息规范

# 推荐格式:类型: 简短描述
git commit -m "feat: 新增用户管理模块"
git commit -m "fix: 修复登录超时问题"
git commit -m "docs: 更新API文档"
git commit -m "refactor: 重构数据库连接层"
git commit -m "perf: 优化列表查询性能"

2.3 修改最近一次提交

# 漏了文件,想追加到上一次提交
git add 漏掉的文件
git commit --amend --no-edit

# 想改上次的提交信息
git commit --amend -m "新的提交信息"

2.4 实操演示

# 模拟一次完整提交
echo "print('hello')" > main.py
git status                              # 看到 main.py 是未跟踪的(红色)
git add main.py                         # 加入暂存区
git status                              # 看到 main.py 变绿色
git commit -m "feat: 添加main.py入口"    # 提交!

echo "print('world')" >> main.py
git status                              # 看到 main.py 被修改
git diff                                # 看看具体改了什么
git commit -am "feat: main.py增加输出"   # 一步到位提交

git log --oneline                       # 查看提交历史

3. 查看提交记录

这是 VS Code 可视化最核心的替代功能。

3.1 基本查看

# 完整日志(按j/k上下翻页,按q退出)
git log

# 简洁模式(一行一条)
git log --oneline

# 最近 N 条
git log -5
git log --oneline -10

3.2 图形化分支图(最接近 VS Code 的视图)

# 最推荐:带分支图的简洁日志
git log --oneline --graph --all

# 更详细的分支图
git log --graph --all --decorate --format='%C(auto)%h %C(blue)%an %C(green)%ad %C(reset)%s' --date=short

# 建议设置别名,方便反复使用
git config --global alias.tree "log --oneline --graph --all"
git tree   # 以后直接打这个就行

3.3 查看每次提交的具体改动

# 查看某次提交改了哪些内容
git show <commit-hash>

# 只看某个文件在两次提交间的变化
git log -p 文件名

# 查看每一行的最后修改者和修改时间
git blame 文件名
git blame -L 10,20 文件名   # 只看第10到20行

3.4 搜索提交记录

# 按提交信息关键词搜索
git log --oneline --grep="登录"

# 按代码改动的关键词搜索
git log --oneline -S "functionName"

# 按作者搜索
git log --oneline --author="张三"

# 按时间范围
git log --oneline --since="2025-01-01" --until="2025-12-31"

# 查看某个文件的所有提交历史
git log --oneline -- 文件名

3.5 查看改了什么(类似 VS Code 的对比视图)

# 工作区 vs 暂存区(还没 git add 的改动)
git diff

# 暂存区 vs 最新提交(已经 git add 了但没 commit)
git diff --cached
# 或
git diff --staged

# 工作区 vs 最新提交(所有未提交的改动)
git diff HEAD

# 比较两个提交
git diff commit1 commit2
git diff abc123..def456

# 比较两个分支
git diff main..feature-login

# 只看某个文件的差异
git diff -- 文件名

4. Tag 标签管理

Tag 就是给某个 commit 打上版本号标记,比如 v1.0.0,方便以后快速定位。

4.1 创建 Tag

# 轻量标签(不推荐,信息太少)
git tag v1.0.0

# 附注标签(推荐,带说明信息)
git tag -a v1.0.0 -m "正式发布 1.0.0 版本"

# 给之前的某个提交打标签
git tag -a v0.9.0 -m "测试版" <commit-hash>

# 查看某个标签的详情
git show v1.0.0

4.2 查看 Tag

# 列出所有标签
git tag

# 按模式过滤
git tag -l "v1.*"

# 按时间排序查看
git tag --sort=-creatordate | head -10
git tag --sort=-v:refname           # 按版本号排序

4.3 推送 Tag 到远程

# 推送单个标签
git push origin v1.0.0

# 推送所有标签
git push origin --tags

# 默认 git push 不会推送标签,需要显式指定

4.4 删除 Tag

# 删除本地标签
git tag -d v1.0.0

# 删除远程标签
git push origin --delete v1.0.0
# 或
git push origin :refs/tags/v1.0.0

4.5 切换到某个 Tag 的代码

# 只读查看
git checkout v1.0.0

# 基于 Tag 创建新分支(推荐方式,可以在上面改代码)
git checkout -b hotfix-from-v1 v1.0.0

5. Worktree 多分支并行开发

Worktree 让你在同一个仓库里同时检出多个分支到不同目录,互不干扰。

典型场景

  • 正在 feature-A 分支开发,突然要修 main 分支的紧急 bug
  • 不用 stash 当前工作,直接开个新 worktree 修 bug

5.1 创建 Worktree

# 语法
git worktree add <目录路径> <分支名>

# 示例:在隔壁目录检出 main 分支修 bug
git worktree add ../my-project-hotfix main

# 基于某个提交创建新分支并检出
git worktree add -b feature-payment ../my-project-payment main

5.2 查看所有 Worktree

git worktree list
# 输出示例:
# /home/user/my-project        abc1234 [main]
# /home/user/my-project-hotfix def5678 [main]

5.3 删除 Worktree

# 到那个 worktree 目录下正常删除文件后
git worktree remove ../my-project-hotfix

# 或先清理,再删除
git worktree prune
rm -rf ../my-project-hotfix

5.4 完整实战:用 Worktree 修紧急 Bug

cd /home/user/my-project          # 当前在 main 分支开发功能

git worktree list                  # 看看有哪些 worktree

# 开新 worktree 修 bug
git worktree add ../my-project-hotfix main

# 进新目录修 bug
cd ../my-project-hotfix
# ... 修改代码 ...
git commit -am "hotfix: 修复支付回调空指针"
git push

# 回到原目录继续开发
cd /home/user/my-project
# 新目录和原目录完全独立,各干各的

# 修完后清理 worktree
git worktree remove ../my-project-hotfix

5.5 Worktree 中的合并操作

Worktree 本质上是共享同一个 .git 仓库的不同工作目录,所以合并命令和普通方式完全一样。关键在于搞清楚”你在哪个目录、要合并谁”。

场景A:在 Worktree 里开发完,合并回主分支

# 假设目录结构:
# /home/user/my-project         → main 分支
# /home/user/my-project-feature → feature-login 分支(worktree)

# 在 feature worktree 里开发并提交
cd /home/user/my-project-feature
# ... 开发 ...
git add .
git commit -m "feat: 登录功能完成"

# 然后回到主目录,把 feature 分支合并进来
cd /home/user/my-project
git merge feature-login
# 或者
git merge --no-ff feature-login -m "merge: 合并登录功能"

场景B:主分支有新提交,同步到 Worktree

# main 分支有人提交了新代码(不管是在哪个 worktree 提交的)
# 在 feature worktree 里把最新 main 合并进来

cd /home/user/my-project-feature   # 进入 feature worktree
git merge main                      # 把 main 的最新代码合并到当前分支

# 如果有冲突,在当前目录正常解决即可
# ... 解决冲突 ...
git add .
git commit -m "merge: 同步 main 最新代码"

场景C:一个 Worktree 一个任务,互不阻塞

# Terminal 1:在 feature 目录开发新功能
cd /home/user/my-project-feature
git checkout feature-login
# ... 正常开发、提交 ...

# Terminal 2:在 hotfix 目录修紧急 bug
cd /home/user/my-project-hotfix
git checkout hotfix-urgent
# ... 修 bug、提交 ...

# Terminal 3:在 main 目录做发布
cd /home/user/my-project
git merge feature-login      # 合并功能
git merge hotfix-urgent      # 合并热修复
git tag -a v2.0.0 -m "发布"   # 打版本

场景D:Worktree 间交叉合并(不推荐,但可行)

# 直接在 feature worktree 目录执行 merge
cd /home/user/my-project-feature
git merge hotfix-urgent       # 此时会报错!

# 错误原因:hotfix-urgent 分支被另一个 worktree 检出了
# Git 不允许同一个分支同时被两个 worktree 检出

# 解决方案:先让 hotfix worktree 切换到别的分支
cd /home/user/my-project-hotfix
git checkout main             # 或直接 git switch main
# 现在 hotfix-urgent 没人占用了

cd /home/user/my-project-feature
git merge hotfix-urgent       # 可以了

5.6 Worktree + Merge 完整实战:并行开发两个功能,最后一起合并

# 初始状态:只有 main 分支
cd /home/user/my-project
git branch
# * main

# 创建两个 worktree,分别开发两个独立功能
git worktree add -b feature-payment ../my-project-payment main
git worktree add -b feature-report  ../my-project-report  main

# 开发 payment 功能
cd ../my-project-payment
echo "payment module" > payment.py
git add payment.py
git commit -m "feat: 支付模块"

# 开发 report 功能(payment 还在开发中,互不干扰!)
cd ../my-project-report
echo "report module" > report.py
git add report.py
git commit -m "feat: 报表模块"

# payment 继续开发
cd ../my-project-payment
echo "alipay support" >> payment.py
git commit -am "feat: 支持支付宝"

# 回到主目录,逐个合并
cd /home/user/my-project

# 先合并 payment
git merge --no-ff feature-payment -m "merge: 合并支付模块"

# 再合并 report(可能需要解决冲突)
git merge --no-ff feature-report -m "merge: 合并报表模块"

# 发布
git tag -a v1.0.0 -m "第一个正式版"
git archive -o ../myproject-v1.0.0.zip v1.0.0

# 清理 worktree
git worktree remove ../my-project-payment
git worktree remove ../my-project-report

# 查看最终的分支图
git log --oneline --graph --all

5.7 Worktree 注意事项

# 1. 同一个分支不能被两个 worktree 同时检出
git worktree list
# 确保没有分支名重复出现在不同目录

# 2. worktree 里删除分支前,先切换到其他分支
git switch main
git branch -d feature-old

# 3. 主仓库删了分支,worktree 引用会失效,记得 prune
git worktree prune

# 4. Worktree 共享 .git,所以 git log / git stash 等操作数据互通
#    在一个 worktree 里 git stash,在另一个 worktree 里 git stash list 能看到

6. 打包特定版本为 zip

git archive 可以直接导出任意版本为 zip/tar.gz,不包含 .git 目录,适合交付。

6.1 打包当前版本

# 当前 HEAD 版本打包为 zip
git archive -o ../output.zip HEAD

# 打包为 tar.gz
git archive -o ../output.tar.gz HEAD

6.2 打包指定版本

# 按 Tag 打包
git archive -o ../v1.0.0.zip v1.0.0

# 按分支打包
git archive -o ../develop.zip develop

# 按 commit hash 打包
git archive -o ../snapshot.zip abc1234

# 只打包某个子目录
git archive -o ../src.zip HEAD src/

# 排除某些文件
git archive -o ../no-test.zip HEAD -- ':!test'

6.3 实用脚本:一键打包发布

#!/bin/bash
# 保存为 release.sh

VERSION=${1:-"v1.0.0"}
git archive -o "../myproject-${VERSION}.zip" "$VERSION"
echo "已生成: myproject-${VERSION}.zip"
ls -lh "../myproject-${VERSION}.zip"

用法:

chmod +x release.sh
./release.sh v2.0.0

6.4 打包带 .git 的完整仓库(迁移到另一台机器继续开发)

git archive 不含 .git,如果你要把整个仓库(含提交历史、分支、标签)搬到内网服务器继续开发,用下面三种方式。

方式一:直接打包整个目录(最简单)

# 打包为 zip(含 .git)
zip -r ../myproject-full.zip .

# 打包为 tar.gz(推荐,压缩比更高且保留权限)
tar -czf ../myproject-full.tar.gz .

# 到目标机器解压
unzip myproject-full.zip -d /path/to/new-project/
# 或
tar -xzf myproject-full.tar.gz -C /path/to/new-project/

方式二:git bundle 打包(最 Git 原生,推荐)

git bundle 把整个仓库(所有分支、标签、历史)打包成一个文件,无需解压,直接当远程仓库用。

# 打包:导出所有分支和标签
git bundle create ../myproject.bundle --all

# 查看 bundle 里有什么
git bundle list-heads ../myproject.bundle
# 输出示例:
# abc1234 refs/heads/main
# def5678 refs/heads/develop
# 1112222 refs/tags/v1.0.0

# 也可以只打包某个分支及其历史
git bundle create ../myproject.bundle main develop

# 也可以打包某个范围(比如只导出 v1.0.0 之后的内容)
git bundle create ../myproject.bundle v1.0.0..main

到目标机器恢复:

# 在目标机器上,像克隆远程仓库一样从 bundle 文件恢复
git clone /path/to/myproject.bundle /path/to/new-project/

# 克隆完就是一个完整的 git 仓库,历史、分支、标签全在
cd /path/to/new-project/
git log --oneline --graph --all   # 一切都在
git branch -a                      # 所有分支都在
git tag                            # 所有标签都在

方式三:U 盘 / SCP 拷贝(物理隔离环境)

# 源机器:直接复制整个项目目录(.git 自然在里面)
scp -r /home/user/my-project user@目标IP:/home/user/

# 或者先 tar 再传
tar -czf myproject.tar.gz my-project/
scp myproject.tar.gz user@目标IP:/home/user/

# 到目标机器解压即用
ssh user@目标IP
cd /home/user
tar -xzf myproject.tar.gz
cd my-project
git log --oneline    # 历史完整保留

三种方式对比

方式 包含 .git 尊重 .gitignore 文件大小 适用场景
git archive 不含 是(只导出已跟踪文件) 最小 交付给客户/生产部署
git bundle 完整历史 是(只打包 Git 对象) 比 archive 大 跨机器迁移开发(推荐)
zip -r / tar 完整历史 (无差别打包整个目录) 最大,含 node_modules 等 快速完整备份

7. 版本回退

7.1 先理解三个区域

工作区          暂存区         本地仓库          远程仓库
(Working)  →   (Stage)   →   (Local)    →    (Remote)
  |              |              |               |
git add      git commit     git push
  |              |              |               |
 ← git restore ← git restore  ← git reset      ← git revert
                  --staged    ← git revert

7.2 回退方法对比

命令 效果 适合场景
git restore 文件 撤销工作区改动 还没 add
git restore --staged 文件 移出暂存区 已经 add 但没 commit
git reset --soft HEAD~1 撤销 commit,改动保留在暂存区 commit 错了,想重写
git reset --mixed HEAD~1 撤销 commit 和 add,改动保留在工作区 commit 错了,从头来
git reset --hard HEAD~1 彻底丢弃最近一次提交的所有改动 确定不要了
git revert HEAD 创建一次新提交来”反向”抵消 已推送到远程

7.3 实战:各种回退场景

# 场景1:改乱了工作区,想恢复到上次 commit 的状态
git restore 文件名
git restore .                          # 恢复所有文件

# 场景2:git add 错了,想取消暂存
git restore --staged 文件名

# 场景3:刚 commit 了,但发现漏改东西
git reset --soft HEAD~1                # 回到 commit 前,改动还在暂存区
# ... 补改 ...
git commit -m "修正后的提交"

# 场景4:这次 commit 完全不想要了,回到干净状态
git reset --hard HEAD~1

# 场景5:回退到指定版本(回退 N 个 commit)
git reset --hard HEAD~3                # 回退 3 次提交

# 场景6:回退到指定 commit hash
git log --oneline                      # 先找到目标 commit
git reset --hard abc1234               # 回退到该 commit
# 警告:abc1234 之后的提交会全部丢失!

# 场景7:已经 push 到远程了,用 revert(安全)
git revert HEAD                        # 创建新 commit 撤销最近一次
git revert abc1234                     # 撤销指定 commit
git push origin main

# 场景8:回退后又后悔了
git reflog                             # 查看所有 HEAD 的移动记录
git reset --hard HEAD@{1}              # 回到回退前的状态

7.4 reset vs revert 关键区别

# reset:真删了,不留痕(像时光倒流)
git reset --hard HEAD~1

# revert:创建反向 commit,历史可追溯(像打补丁)
git revert HEAD

简单规则:已 push 到远程,用 revert;还在本地,用 reset。


8. 查看特定记录的代码

8.1 查看某次提交的完整改动(等效 GitHub 的 commit 详情页)

git show 输出内容就是 GitHub 上点开某个 commit 看到的信息:作者、时间、提交信息、文件 diff,完全对应。

基础用法

git show abc1234                    # 看完整 diff(等效 GitHub commit 详情)
git show abc1234 --stat             # 只看改了哪些文件(等效 GitHub "Files changed" 概览)
git show abc1234 --stat -p          # 文件统计 + diff 一次看完
git show abc1234 -- 文件名           # 只看某个文件的改动
git show HEAD~3                     # 看 3 次提交之前的改动

注意: git show <hash> 展示的是这一次提交的改动。而 git diff <hash> / git difftool <hash> 展示的是该提交到当前状态之间所有的累积差异,完全不一样。要用 difftool 只看一次提交,必须加 ^!

git show abc1234                      # ✅ 只看这一次提交

git difftool --tool=icdiff abc1234    # ❌ 从那次提交到现在的所有差异
git difftool --tool=icdiff abc1234^!  # ✅ 只看这一次提交
git difftool --tool=icdiff abc1234~..abc1234  # 等价写法

彩色单词级对比(更像 GitHub 的高亮效果)

# GitHub 默认是单词级高亮,命令行加 --color-words 达到同样效果
git show abc1234 --color-words

# 设置别名,以后直接用
git config --global alias.showw 'show --color-words'
git showw abc1234

连续查看最近 N 次提交各自的 diff

# 最近 5 次提交,每次都有完整 diff(等效 GitHub Commits 列表逐个点开看)
git log -p -5

# 最近 5 次,只显示文件概览不展开 diff
git log --stat -5

# 最近 5 次 + 单词级高亮
git log -p -5 --color-words

左右分屏对比(等效 GitHub 的 Split 视图)

GitHub 默认是左旧右新的分屏 diff。终端下有几种方式实现同样效果。

方案一:vimdiff(零依赖,内置)

vimdiff 是 Vim 自带的分屏对比工具,所有 Linux 都内置:

# 查看某次提交的左右分屏对比
git difftool --tool=vimdiff abc1234

# 对比两个提交
git difftool --tool=vimdiff abc1234..def5678

# 对比某个文件的两版本
git difftool --tool=vimdiff abc1234 -- src/main.py

# 设为默认 difftool,以后直接 git difftool
git config --global diff.tool vimdiff
git config --global difftool.prompt false   # 不弹出确认提示
git difftool abc1234

vimdiff 打开后:

  • 左边是旧版本,右边是新版本
  • Ctrl+W + 左右箭头 切换窗口
  • :qa 退出所有窗口,进入下一个文件
  • 红色高亮 = 差异行

方案二:delta(最像 GitHub,强烈推荐)

delta 是一个 Rust 写的 diff 美化工具,支持左右分屏,效果跟 GitHub 几乎一样:

# 安装(CentOS 可能需要先装 cargo 或下载二进制)
# 方式A:用 cargo
cargo install git-delta
# 方式B:直接从 GitHub Release 下载二进制
# wget https://github.com/dandavison/delta/releases/latest/download/delta-*.tar.gz

# 配置 git 使用 delta
git config --global core.pager delta
git config --global interactive.diffFilter 'delta --color-only'
git config --global delta.side-by-side true          # 开启左右分屏!
git config --global delta.line-numbers true           # 显示行号
git config --global delta.navigate true               # 用 n/N 跳转到下一个/上一个差异块

# 配置完后,git diff / git show 自动变成左右分屏
git show abc1234
git diff
git log -p

效果演示:

 src/main.py
──────────────────────────────────────────────────────────────────
  34  def login(user, pwd):    │  34  def login(user, pwd, method='password'):
  35      return api.login()   │  35      return api.authenticate(user, pwd, method)
                               │  36
                               │  37  def logout():
                               │  38      session.clear()

方案三:icdiff(轻量 Python 方案)

如果装不了 Rust,用 Python 的 icdiff。注意 icdiff 不是 Git 内置工具,需要先安装再注册:

# 1. 安装 icdiff
pip install icdiff

# 2. 注册为 Git 自定义 difftool(关键一步!否则报 Unknown merge tool)
git config --global difftool.icdiff.cmd 'icdiff --line-numbers --no-bold "$LOCAL" "$REMOTE"'
git config --global difftool.prompt false

# 3. 使用
git difftool --tool=icdiff abc1234

# 设为默认
git config --global diff.tool icdiff
git difftool abc1234

三种方案对比

方案 安装 效果 适用场景
vimdiff 零依赖,系统自带 功能全但颜值一般 临时用、不想装东西
delta 需下载二进制 最像 GitHub,真分屏 日常使用(推荐)
icdiff pip install 轻量分屏 Python 环境已有

### 8.2 查看某个文件在某个版本时的内容

```bash
# 查看文件在特定 commit 时的内容(不修改工作区)
git show abc1234:路径/文件名

# 示例
git show abc1234:src/main.py
git show v1.0.0:README.md
git show HEAD~5:config/db.conf

8.3 比较文件在不同版本间的差异

# 同一个文件在两个版本间的差异
git diff abc1234..def5678 -- 文件名

# 文件在两次提交间的变化
git diff HEAD~3..HEAD -- src/main.py

# 文件名在两处不一样怎么办,看下一节

8.4 临时切换到某个版本(仅查看,不改代码)

# 切换到某个 commit(detached HEAD 状态)
git checkout abc1234
# ... 看完代码 ...
git switch main   # 或 git checkout main  回到正常分支

# 切换到某个 tag
git checkout v1.0.0

8.5 实用对比脚本

# 查看一个文件从一开始到现在的所有版本
git log --oneline --follow -- 文件名
# --follow 会追踪文件重命名

# 查看某次提交前后10行上下文
git show abc1234 -U10

9. Merge 合并

9.1 基本合并流程

# 场景:把 feature-login 分支的代码合并到 main

# Step 1: 切换到目标分支
git checkout main
# 或
git switch main

# Step 2: 确保目标分支是最新的
git pull origin main

# Step 3: 合并
git merge feature-login

# Step 4: (如果没问题)推送到远程
git push origin main

9.2 合并策略

# 默认合并(可能产生 merge commit)
git merge feature-login

# Fast-Forward 合并:如果 main 没有新 commit,直接把 main 指针移过去
# 等同于 --ff,这是默认行为
git merge --ff feature-login

# 禁止 Fast-Forward:强制生成一个 merge commit
# 好处:分支历史清晰可见
git merge --no-ff feature-login -m "merge: 合并登录功能"

# Squash 合并:把 feature 分支的所有 commit 压成一个 commit
# 好处:main 分支历史干净
git merge --squash feature-login
git commit -m "feat: 登录功能(含10次提交)"

9.3 三种合并方式对比

--ff (Fast-Forward)
main:    A---B
feature:     \---C---D
结果:    A---B---C---D    (线性,看不出分支的存在)

--no-ff
main:    A---B
feature:     \---C---D
结果:    A---B-------M    (M 是 merge commit,保留分支结构)
               \---C---D

--squash
main:    A---B
feature:     \---C---D
结果:    A---B---S        (S 包含了 C+D 的全部改动,只有一次 commit)

9.4 合并前先预演

# 合并前看看有没有冲突,不真正执行
git merge --no-commit --no-ff feature-login
# 检查完没问题的话:
git commit -m "merge: 合并 feature-login"
# 如果不想合并了:
git merge --abort

9.5 中断合并

# 合并到一半发现有冲突不想解决了
git merge --abort
# 回到合并前状态,干干净净

10. 解决合并冲突

当两个分支改了同一个文件的同一行,git 无法自动判断用哪个版本,就会产生冲突。

10.1 冲突的样子

<<<<<<< HEAD                    # 这是当前分支(main)的内容
def login(user, pwd):
    return api.login(user, pwd)
=======                         # 这是要合并进来的分支(feature)的内容
def login(user, pwd, method='password'):
    return api.authenticate(user, pwd, method)
>>>>>>> feature-login

10.2 解决冲突三步法

# Step 1: 找到冲突
git merge feature-login
# 输出:CONFLICT (content): Merge conflict in src/auth.py

git status                       # 看到 both modified: src/auth.py

# Step 2: 手动编辑文件,删除冲突标记
# 打开 src/auth.py,看到 <<<<<<< ======= >>>>>>> 标记
# 决定保留哪个版本(或两个版本融合),删掉标记

# Step 3: 标记已解决并提交
git add src/auth.py
git commit -m "merge: 合并 feature-login(已解决冲突)"

10.3 冲突解决示例

# 原始文件有冲突:
# <<<<<<< HEAD
# def login(user, pwd):
# =======
# def login(user, pwd, method='password'):
# >>>>>>> feature-login

# 手动编辑,保留你的选择,比如:
def login(user, pwd, method='password'):
    return api.authenticate(user, pwd, method)

# 保存后:
git add src/auth.py
# 所有冲突都解决后:
git commit
# 默认会打开编辑器让你确认 merge 信息,保存退出即可

10.4 冲突时的常用操作

# 查看哪些文件有冲突
git diff --name-only --diff-filter=U

# 全部接受当前分支(ours)的版本
git checkout --ours 文件名
git add 文件名

# 全部接受合并分支(theirs)的版本
git checkout --theirs 文件名
git add 文件名

# 使用可视化 diff 工具(如果服务器装了)
git mergetool

# 放弃合并
git merge --abort

# 查看冲突的具体差异
git diff 文件名

10.5 查看合并历史

# 查看哪些分支已合并、未合并
git branch --merged
git branch --no-merged

# 查看合并日志
git log --merges --oneline

# 查看某次合并引入了哪些改动
git log --first-parent main

附:常用命令速查表

最常用(每天都会用)

git status                           # 查看状态
git log --oneline --graph --all      # 查看历史图
git diff                             # 看工作区改动
git add . && git commit -m "..."    # 提交
git push origin main                 # 推送到远程
git pull                             # 拉取远程更新

实用别名配置(建议加到 ~/.bashrc 或 ~/.gitconfig)

# 简洁状态
git config --global alias.st status

# 上次提交的改动
git config --global alias.last 'log -1 --stat'

# 漂亮的分支图
git config --global alias.tree 'log --oneline --graph --all --decorate'

# 漂亮日志
git config --global alias.lg "log --graph --format='%C(auto)%h %C(blue)%an %C(green)%ad %C(reset)%s' --date=short"

# 搜索提交信息
git config --global alias.find 'log --oneline --grep'

# 配置完成后:
git st       # git status
git last     # 查看最近一次提交
git tree     # 查看分支图
git lg       # 漂亮的提交日志
git find "关键词"  # 搜索提交

紧急情况速查

# 改坏了,回到上次 commit
git restore .

# 刚 commit 了想反悔
git reset --soft HEAD~1

# 刚 push 了想反悔
git revert HEAD && git push

# 合并乱了想重来
git merge --abort

# 误删了 commit 想找回
git reflog && git reset --hard HEAD@{n}

# 查看某次提交的文件内容
git show abc1234:path/to/file

结语:命令行 vs VS Code 操作对照

操作 VS Code 方式 命令行方式
看改了什么 左侧文件颜色 git status + git diff
看提交历史 GitLens / 时间线 git log --oneline --graph --all
看单次提交 点击 commit 条目 git show <hash>
提交代码 Ctrl+Enter git add + git commit -m "..."
看文件历史 GitLens blame git blame 文件名
分支合并 右键菜单 git merge 分支名
解决冲突 内嵌编辑器 手动编辑 → git addgit commit
版本回退 右键 revert git reset / git revert
打标签 右键创建 tag git tag -a v1.0 -m "..."
打包发布 手动压缩 git archive -o v1.0.zip v1.0

命令行一开始可能不习惯,但一旦熟练,效率远高于鼠标点击。多练习,两周就能肌肉记忆。

结语

第三百八十五篇博文写完,开心!!!!

今天,也是充满希望的一天。


文章作者: LuYF-Lemon-love
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 LuYF-Lemon-love !
  目录