认识工作区、暂存区和版本库

  1. 理解下 Git 工作区、暂存区和版本库概念
    1. 工作区:就是你在电脑里能看到的目录;
    2. 暂存区:英文叫 stageindex,一般存放在 .git 目录下的 index 文件 (.git/index) 中,所以把暂存区有时也叫作索引 (index)
    3. 版本库:工作区有一个隐藏目录 .git,这个不算工作区,而是 Git 的版本库;
  2. git 操作

Git 安装 + 完整配置

  1. 全平台安装

    1. WindowsGit 官网 下载,一路默认;
    2. Macbrew install git
    3. Linuxsudo apt-get install git
  2. 全局 / 本地 / 系统三级配置:

    # 1. 全局配置(所有仓库生效,第一次必配)
    git config --global user.name "你的名字"
    git config --global user.email "你的邮箱"
    git config --global core.editor "code --wait"  # 默认编辑器 VS Code
    git config --global core.autocrlf true  # Windows 换行符
    git config --global core.autocrlf input # Mac/Linux 换行符
    
    # 2. 本地配置(仅当前仓库生效,优先级最高)
    git config --local user.name "项目专用名"
    
    # 3. 查看所有配置
    git config --list --show-origin
    
  3. SSH 免密配置 (告别每次输密码)

    # 1. 生成 SSH 密钥
    ssh-keygen -t ed25519 -C "你的邮箱"
    
    # 2. 复制公钥
    # Windows:clip < ~/.ssh/id_ed25519.pub
    # Mac:pbcopy < ~/.ssh/id_ed25519.pub
    
    # 3. 粘贴到 GitHub/GitLab -> Settings -> SSH keys
    # 4. 测试
    ssh -T git@github.com
    

Git 完整命令手册

仓库初始化与克隆

# 初始化本地仓库(生成 .git 文件夹)
git init

# 克隆远程仓库(完整复制所有版本历史)
git clone 仓库地址

# 浅克隆(只克隆最新版本,体积小)
git clone --depth=1 仓库地址

文件操作 (工作区 → 暂存区 → 本地仓库)

# 查看文件状态(最常用,红色=工作区,绿色=暂存区)
git status

# 查看修改内容(工作区 vs 暂存区)
git diff
# 查看暂存区 vs 本地仓库
git diff --staged

# 添加到暂存区
git add 文件名       # 单个文件
git add 文件夹/*     # 文件夹
git add .            # 所有修改(推荐)
git add -u           # 仅更新已跟踪文件

# 提交到本地仓库
git commit -m "提交说明"        # 标准提交
git commit -am "说明"           # 跳过 add,直接提交已跟踪文件
git commit --amend -m "新说明"  # 修改上一次提交(未推送)
git commit --amend --no-edit    # 补充修改到上一次提交,不改说明

# 查看提交历史
git log                  # 完整历史
git log --oneline        # 简洁版
git log --graph          # 图形化分支
git log --stat           # 查看文件修改统计
git reflog               # 查看所有操作记录(找回丢失提交)

远程仓库操作 (本地 ↔ 云端)

# 查看远程仓库
git remote -v

# 关联远程仓库
git remote add origin 仓库地址

# 修改远程仓库地址
git remote set-url origin 新地址

# 拉取远程代码(推荐,不会自动合并)
git fetch origin 分支名
# 拉取并合并(等于 fetch + merge)
git pull origin 分支名

# 推送到远程
git push origin 分支名
git push -u origin main  # 第一次推送,绑定上游分支
git push -f              # 强制推送(谨慎用!)

分支操作 (Git 最强大功能)

# 查看分支
git branch           # 本地分支
git branch -r        # 远程分支
git branch -a        # 所有分支

# 创建分支
git branch 分支名

# 切换分支
git checkout 分支名   # 旧命令
git switch 分支名     # 新命令(推荐)

# 创建并切换分支
git checkout -b 分支名
git switch -c 分支名

# 重命名分支
git branch -m 旧名 新名

# 删除分支
git branch -d 分支名  # 安全删除(已合并)
git branch -D 分支名  # 强制删除(未合并)

# 推送本地分支到远程
git push origin 分支名

# 删除远程分支
git push origin --delete 分支名

标签 (发布版本用)

# 查看标签
git tag

# 创建轻量标签
git tag v1.0

# 创建附注标签(推荐)
git tag -a v1.0 -m "版本说明"

# 推送标签到远程
git push origin v1.0
git push origin --tags  # 推送所有标签

# 删除标签
git tag -d v1.0
git push origin --delete tag v1.0

Git 冲突完全解决方案

  1. 冲突产生原因:多人修改同一文件同一行,或一人删除文件、一人修改文件,Git 无法自动合并;

  2. 冲突标记格式:

    <<<<<<< HEAD        # 当前分支代码
    你的代码
    =======             # 分隔线
    别人的代码
    >>>>>>> 分支名      # 合并分支代码
    
  3. 解决步骤:

    • 打开冲突文件,手动删除标记,保留正确代码;
    • git add . 标记冲突已解决;
    • git commit -m "解决冲突" 完成合并;
    • git push 推送;
  4. 冲突中止 (不想解决了)

    git merge --abort
    git rebase --abort
    

企业级 Git 工作流

  1. Git Flow (大型项目,最严谨)

    • main:生产环境,永远稳定;
    • develop:开发主分支;
    • feature/*:功能开发分支;
    • release/*:预发布分支;
    • hotfix/*:线上紧急 bug 修复;
  2. GitHub Flow (中小型项目,简单高效)

    • 只有 main 主分支 + 功能分支;
    • 功能完成 → 提 PR → 代码审查 → 合并到 main → 自动部署;
  3. GitLab Flow (最佳实践,兼顾灵活与安全)

    • 分支对应环境:developmenttestproduction
    • 严格上游分支合并,避免混乱;

进阶操作

git reset 操作

  1. 原理:

    • git resetGit 中回退版本、撤销提交最核心的命令,简单说:它能把当前分支的 HEAD 指针,移动到指定的提交节点,同时控制工作区、暂存区的文件状态;
    • git reset --hard 目标版本 => 回到目标版本,把目标版本之后的一切全部删掉;
  2. git reset 三种模式:

    模式 命令写法 作用 工作区 暂存区
    软回退 –soft 仅移动 HEAD,不改动文件 保留修改 保留修改
    默认模式 –mixed 移动 HEAD + 重置暂存区 保留修改 清空修改
    硬回退 –hard 彻底重置,删除所有修改 清空修改 清空修改
  3. 高频实用场景:

    • 场景 1:回退到当前分支的最新提交
      • 清空工作区所有未提交的修改
      • 清空暂存区所有 git add 的内容
      • 不改变版本历史 (不删除任何 commit)
    git reset --hard
    # 等价于 git reset --hard HEAD
    
    • 场景 2:撤销最后一次提交 (重新提交)
    git reset --soft HEAD~1
    
    # 修改文件后重新提交
    git commit -m "正确的提交信息"
    
    • 场景 3:撤销 git add (取消暂存)
    # 等价于 git reset --mixed (默认模式)
    git reset
    
    • 场景 4:放弃所有本地修改,回到远程最新版
    # 先拉取远程最新代码
    git fetch origin
    
    # 硬回退到远程主分支
    git reset --hard origin/main
    
    • 场景 5:回退后后悔了,想恢复版本 (git reset 不是 “不可逆”!用 git reflog 找回丢失的提交)
    # 查看所有操作历史(包含被删除的提交)
    git reflog
    
    # 找到误删前的哈希值,硬回退回去
    git reset --hard 丢失的哈希值
    
  4. 注意:

    1. ⚠️ 绝对不要在公共分支用 git reset --hard,多人协作,回退版本会覆盖别人的代码,导致冲突灾难,请使用 git revert
    2. ⚠️ –hard 会永久删除未提交的修改,未提交的文件、git add 过的文件,都会被直接删除,无法通过普通方式恢复
    3. ⚠️ 回退后,远程分支需要强制推送 (仅在私人分支使用)
    4. ⚠️ 软回退 / 默认回退,文件不会丢,都是安全操作,放心用;
    5. ⚠️ HEAD~1 等价于 HEAD^ (回退 1 个版本:HEAD~1 = HEAD^,回退 2 个版本:HEAD~2)

git revert 操作

  1. 原理:

    1. git revertGit 中安全撤销历史提交的核心命令,它不会删除 / 改写已提交的历史记录,而是通过新建一个 「反向提交」,抵消掉目标提交的所有修改,完美保留项目完整提交历史;
    2. 简单理解:你提交了一个错误代码 (commit A)git revert A 会生成一个新提交 (commit A’),让代码回到 A 之前的状态,AA’ 都会保留在历史里;
  2. 高频使用案例:

    • 场景 1:撤销「最近一次提交」
    # 提交记录 e4f5g6h -> a1b2c3d (HEAD -> main)
    git revert a1b2c3d
    # 代码自动回到 e4f5g6h 的状态!
    
    • 场景 2:撤销「历史中某一个旧提交」 (3 天前的一个提交引入了 bug,后面又提交了 5 次,只想撤销那一个错误提交)
    # 直接指定那个旧的 commit 哈希即可
    git revert 8f9a7b1
    
    • 场景 3:撤销「连续的多个提交」
    # # 撤销连续的多个提交(左开右闭:不包含 start,包含 end)
    git revert 3d4e5f6..7a8b9c0
    
    • 场景 4:撤销「合并提交(merge)」 (把 dev 分支合并到了 main,发现有问题,要撤销这次合并)
    # 找到 merge 提交哈希,必须加 -m 1(1 代表保留主分支,丢弃合并进来的代码)
    git revert -m 1 9s2k7d2
    
    • 场景 5:撤销后不自动提交 (可以手动修改代码后再提交)
    git revert -n a1b2c3d
    # 手动修改代码
    git add .
    git commit -m "手动撤销错误提交"
    
    • 场景 6:撤销错了,恢复回去 (revert 你的 revert 提交)
    # 提交记录:a1b2c34 -> 9999999 Revert "a1b2c32"   ← 这就是要 revert 的目标
    git revert 9999999
    
    • 场景 7:冲突了,继续撤销/不继续撤销 (要撤销的旧代码,和后来新写的代码重叠了,Git 不知道怎么自动处理)
    ┌─────────────────────────────────┐
    │      Git Revert 冲突处理图       │
    ├─────────────────────────────────┤
    │ 1. 看到 CONFLICT → 打开文件      │
    │ 2. 删除 <<<<<<< ======= >>>>>>> │
    │ 3. git add .                    │
    │ 4. git revert --continue        │
    │ 5. 保存提交 → 完成               │
    ├─────────────────────────────────┤
    │ 放弃撤销:git revert --abort     │
    └─────────────────────────────────┘
    
  3. 注意:

    1. 不要用 revert 撤销根提交(第一次提交),因为没有父提交了,无法生成反向提交;
      • 整个项目会被清空;
      • 冲突爆炸,极难修复;
    2. revert 后不能再把原来的提交 cherry-pick 回来,想恢复必须:
      • 要么 revert 那个撤销提交;
      • 要么用 git cherry-pick -f 强制;

git rebase 操作

  1. git rebaseGit 中重构提交历史的核心命令,核心作用是:把一段提交记录「剪切」下来,「粘贴」到另一个分支的最新提交后面,让分支历史变成一条干净、线性、无分叉的直线,变基 = 给你的功能分支换一个 “最新的地基”,对于其他分支是没有改动的

    1. merge:保留所有分支历史,生成新的「合并提交」,历史会分叉;
    2. rebase:重写提交历史,抹平分支分叉,历史是一条直线;
  2. 常用使用场景:

    1. 场景 1:把主干最新代码同步到自己的功能分支 (最常用)
      • 你的功能分支开发时,主干 (main/master) 有别人更新的代码,你要把最新代码同步过来,同时保持历史干净、无线性分叉,初始状态如下;
        main:    A -- B -- C (最新)
                       \
        feature:        D -- E -- F (你的功能分支)
        
      • git checkout feature 切换到你的功能分支 feature,要对 feature 分支变基,不能在 main 上操作;
      • git fetch origin 拉取远程主干最新代码,不执行这步,你变基的是旧版 main,同步无效 (git fetch origin 会把远程所有分支的最新代码下载到本地,不合并、不冲突)
      • git rebase origin/main 执行变基 (核心命令),这一步 Git 内部做了 4 件事;
        1. 找到 feature 和 main 的公共祖先 B
        2. 把 feature 上 B 之后的提交 D E F 暂存
        3. 把 feature 指向 origin/main 的最新位置 C
        4. 把 D E F 一个个重新应用到 C 后面
        
        main:    A -- B -- C
                            \
        feature:              D' -- E' -- F'
        
      • 如果发生冲突 (一定会遇到)Git 会暂停变基,并提示:
        Auto-merging xxx.js
        CONFLICT (content): Merge conflict in xxx.js
        error: could not apply...
        
      • 打开文件,手动解决冲突;
      • 冲突解决后,继续变基,❌ 绝对不要执行 git commit! 否则会破坏变基流程;
        git add .               # 只 add,不要 commit!
        git rebase --continue   # 继续执行剩下的提交
        
        # 如果想放弃变基,恢复到开始之前
        git rebase --abort
        
      • 变基完成后推送到远程,因为 feature 历史被改写,必须强制推送,自己的功能分支放心 push -f,不会影响别人 (main)
        git push -f origin feature
        
    2. 场景 2:合并本地多个零散提交 (美化历史)
      • git log --oneline 查看最近要合并的提交;
        f7a392d 调试按钮
        36bd283 修改样式
        1a2b3c6 完成登录功能
        
      • git rebase -i HEAD~3 执行交互式变基;
        • HEAD~3 = 合并最近 3 个提交;
        • -i = interactive 交互式模式;
      • 进入编辑界面(关键)
        pick 1a2b3c 完成登录功能
        pick 36bd28 修改样式
        pick f7a392 调试按钮
        
      • 把后面的提交改成 pick = 保留提交s / squash = 合并进前一个提交
        pick 1a2b3c 完成登录功能
        s 36bd28 修改样式
        s f7a392 调试按钮
        
      • Vim 编辑器:esc → :wq 保存退出;
      • 编辑最终的提交信息 (Git 会让你输入合并后的提交描述,删掉无用信息,写一句清晰的)
  3. 注意:

    1. 只在自己的功能分支用 rebase (公共分支被多人使用,rebase 会改写提交历史,其他人拉代码会出现大量冲突、提交丢失,直接导致协作崩溃)
    2. 永远不要对 main/master 等公共分支执行 rebase
    3. 解决冲突时只 addcommit
    4. 变基后必须 git push -f 强制推送;

git stash 操作

  1. git stash (Git 储藏 / 暂存)Git 最实用的「紧急救火」命令,核心作用:在不提交当前代码的情况下,临时保存工作区和暂存区的修改,让你的工作目录回到干净状态 (简单说:你写了一半的代码不想提交,但必须先切走处理别的事,用它就对了)

    1. 保存对象:只保存工作区 (未提交的修改) + 暂存区 (git add 过的文件),不包含未跟踪的新文件 (比如新建的、从未 add 过的文件)
    2. 存储位置:修改会被打包成一个储藏栈 (stash stack),遵循后进先出规则,最新的储藏永远在最上面;
    3. 恢复方式:可以随时把储藏的代码恢复到当前分支,也能恢复到其他分支;
    4. 状态变化:执行后,git status 会显示工作目录干净 (working tree clean)
  2. 最常用核心命令:

    命令 作用
    git stash 快速保存修改 (默认备注:WIP on 分支名…)
    git stash save "备注信息" 带备注保存 (推荐,方便查找)
    git stash list 查看所有储藏列表
    git stash pop 恢复最新的储藏,并删除该储藏记录
    git stash apply 恢复最新的储藏,保留该储藏记录
    git stash drop 删除最新的储藏记录
    git stash clear 清空所有储藏记录 (谨慎使用)
  3. 完整实战案例:

    • 场景 1:开发到一半,需要切分支修紧急 bug
    # 1. 查看当前修改(工作区有未提交代码)
    git status
    
    # 2. 临时保存代码,带备注方便识别
    git stash save "开发用户登录功能-写到一半"
    
    # 3. 此时工作区变干净,可以放心切分支
    git checkout main
    
    # 4. 修完bug,切回原分支
    git checkout dev
    
    # 5. 恢复刚才的代码(自动删除储藏记录)
    git stash pop
    
    • 场景 2:保存多个储藏,指定恢复某一个
    # 1. 查看所有储藏(stash@{0}是最新的)
    git stash list
    # 输出示例:
    # stash@{0}: On dev: 修复登录bug
    # stash@{1}: On dev: 开发用户列表功能
    
    # 2. 恢复指定储藏(保留记录)
    git stash apply stash@{1}
    
    # 3. 删除指定储藏
    git stash drop stash@{1}
    
    • 场景 3:保存新建的未跟踪文件 (默认不保存从未 git add 过的文件)
    # 保存所有修改(包含未跟踪的新文件)
    git stash -u
    # 等价命令
    git stash --include-untracked
    
    • 场景 4:只保存部分文件 (不想保存所有修改)
    git stash push -m "只保存login.js" src/login.js
    
    • 场景 5:查看储藏的内容 (不恢复)
    # 查看最新储藏的修改详情
    git stash show -p
    
    # 查看指定储藏的详情
    git stash show -p stash@{1}
    
  4. 注意:

    1. 储藏不是提交,不要长期依赖;
    2. 储藏记录不会同步到远程仓库,换电脑就找不到了;
    3. git stash clear 会永久删除所有储藏,无法恢复!

git cherry-pick 操作

  1. git cherry-pickGit 中精准提取某一个 / 几个提交 (commit),并复制到当前分支的命令 (不合并整个分支,只把指定的单次提交 “搬” 到当前分支)

  2. 基础语法:

    # 单个提交
    git cherry-pick <commit-hash>
    
    # 多个离散提交
    git cherry-pick <commit1> <commit2> <commit3>
    
    # 连续多个提交(左开右闭:包含commit2,不包含commit1)
    git cherry-pick <commit1>..<commit2>
    
    # 连续提交(包含起始和结束)
    git cherry-pick <commit1>^..<commit2>
    
    # 保留原提交的作者信息(推荐)
    git cherry-pick -x <commit-hash>
    
  3. 常用案例:

    • 场景 1:dev 分支修复 bug,同步到 master 上线;
    # 切到 master
    git checkout master
    # picked dev 那个修复 commit
    git cherry-pick -x a1b2c3
    
    • 场景 2:feature 分支只想要某一个功能,不合并整个分支 (在 feature/user 写了很多功能,但只想把提交 9f8e7d 这个工具函数拿到 develop)
    git checkout develop
    git cherry-pick 9f8e7d
    

    场景 3:不小心 reset 丢了提交,用 cherry-pick 找回 (误删了一个提交,幸好之前在另一个分支上 cherry-pick 过这个提交,现在可以从那个分支再 cherry-pick 一次回来)

    • 场景 4:只应用代码,不自动提交 (手动修改后再提交)
    git cherry-pick -n a1b2c3
    
    # 修改完后:
    git add .
    git commit
    
    • 场景 5:picked 时顺便改 commit 信息
    git cherry-pick -e a1b2c3
    
    • 场景 6:冲突时的标准处理案例
    # 手动改文件解决冲突
    git add .
    
    # 继续 cherry-pick 流程
    git cherry-pick --continue
    
    # 想放弃这次 cherry-pick
    git cherry-pick --abort
    
    • 场景 7:picked 一个 merge 提交 (合并节点),普通 cherry-pick 不能直接 picked merge 是因为 Git 不知道你要复制哪条分支的代码;
    # -m 1:代表主干分支(被合并到的那个分支)
    # -m 2:代表被合并进来的分支
    git cherry-pick -m 1 8a7s6d
    
  4. 注意:

    1. 不要在公共分支上随意使用,cherry-pick 会生成新提交,如果在多人共用的分支上操作,会导致提交历史混乱;
    2. 不要重复搬运同一个提交,同一个提交如果被搬运两次,会出现重复代码 / 冲突,可以用 git branch --contains <commit> 查看该提交已经在哪些分支存在;
    3. 推荐加 -x 参数,加 -x 会在提交信息中记录 (cherry picked from commit a1b2c3)
    4. 不要用它替代正常合并,cherry-pick 只适合小提交、小修复;
    5. 搬运前确保工作区干净,操作前最好 git stashgit commit,避免代码混乱;

面试题

git 与 svn 的区别在哪里?

  1. gitsvn 最大的区别在于 git 是分布式的,而 svn 是集中式的。因此我们不能再离线的情况下使用 svn,如果服务器出现问题,我们就没有办法使用 svn 来提交我们的代码。

  2. svn 中的分支是整个版本库的复制的一份完整目录,而 git 的分支是指针指向某次提交,因此 git 的分支创建更加开销更小并且分支上的变化不会影响到其他人,svn 的分支变化会影响到所有的人;

  3. svn 的指令相对于 git 来说要简单一些,比 git 更容易上手;

git pull 和 git fetch 的区别

  1. git fetch 只是将远程仓库的变化下载下来,并没有和本地分支合并;

  2. git pull 会将远程仓库的变化下载下来,并和当前分支合并;

git rebase 和 git merge 的区别

  1. git mergegit rebase 都是用于分支合并,关键在 commit 记录的处理上不同;

  2. git merge 会新建一个新的 commit 对象,然后两个分支以前的 commit 记录都指向这个新 commit 记录。这种方法会保留之前每个分支的 commit 历史;

  3. git rebase 会先找到两个分支的第一个共同的 commit 祖先记录,然后将提取当前分支这之后的所有 commit 记录,然后将这个 commit 记录添加到目标分支的最新提交后面;经过这个合并后,两个分支合并后的 commit 记录就变为了线性的记录了;

打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

你好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 认识工作区、暂存区和版本库
  2. 2. Git 安装 + 完整配置
  3. 3. Git 完整命令手册
    1. 3.1. 仓库初始化与克隆
    2. 3.2. 文件操作 (工作区 → 暂存区 → 本地仓库)
    3. 3.3. 远程仓库操作 (本地 ↔ 云端)
    4. 3.4. 分支操作 (Git 最强大功能)
    5. 3.5. 标签 (发布版本用)
  4. 4. Git 冲突完全解决方案
  5. 5. 企业级 Git 工作流
  6. 6. 进阶操作
    1. 6.1. git reset 操作
    2. 6.2. git revert 操作
    3. 6.3. git rebase 操作
    4. 6.4. git stash 操作
    5. 6.5. git cherry-pick 操作
  7. 7. 面试题
    1. 7.1. git 与 svn 的区别在哪里?
    2. 7.2. git pull 和 git fetch 的区别
    3. 7.3. git rebase 和 git merge 的区别