Git命令详解
前言:Git 作为目前最主流的分布式版本控制系统,是程序员日常开发的必备工具,也是面试中的高频考察点。本文将从「核心命令实战使用」和「面试常见问题」两大模块,帮你系统梳理 Git 相关知识,无论是日常开发避坑还是面试备考,都能直接参考。
一、Git 核心命令详细使用
本节按「基础配置 → 仓库操作 → 暂存与提交 → 分支管理 → 远程协作 → 版本回退 → 高级技巧」的逻辑梳理,每个命令包含「功能说明 + 语法 + 实战场景」,兼顾新手入门和老手回顾。
1. 基础配置:首次使用必做
Git 首次安装后,需要配置用户信息,否则无法提交代码(提交记录会关联用户名和邮箱)。
# 配置全局用户名(提交记录显示的名称)
git config --global user.name "你的用户名"
# 配置全局邮箱(建议与代码托管平台账号邮箱一致)
git config --global user.email "你的邮箱地址"
# 查看全局配置信息
git config --global --list
# 配置默认文本编辑器(如vscode,需先将vscode添加到环境变量)
git config --global core.editor "code --wait"
# 配置差异对比工具
git config --global diff.tool vscode
git config --global difftool.vscode.cmd "code --wait --diff $LOCAL $REMOTE"
✨ 注意:如果需要为单个项目配置不同的用户名/邮箱,去掉 --global 参数,在项目根目录执行命令即可。
2. 仓库操作:本地与远程仓库搭建
2.1 本地仓库初始化
# 在当前目录初始化Git仓库(生成.git隐藏文件夹)
git init
# 初始化时指定仓库名称(会创建一个名为repo-name的文件夹,再在其中初始化仓库)
git init repo-name
2.2 关联远程仓库
# 克隆远程仓库到本地(完整复制远程仓库的所有内容,包括历史记录)
git clone <远程仓库地址> # 例:git clone https://github.com/username/repo.git
# 本地已有仓库,关联远程仓库(命名为origin,origin是默认的远程仓库别名)
git remote add origin <远程仓库地址>
# 查看已关联的远程仓库信息
git remote -v
# 移除关联的远程仓库
git remote remove origin
# 重命名远程仓库别名(如将origin改为github)
git remote rename origin github
3. 暂存与提交:核心工作流
Git 工作流核心:工作区 → 暂存区(index/stage) → 本地仓库 → 远程仓库
# 查看文件状态(已修改/未暂存/已暂存/未跟踪)
git status # 详细输出
git status -s # 简洁输出(A:新增,M:修改,D:删除,??:未跟踪)
# 将工作区文件添加到暂存区
git add <文件名> # 添加单个文件
git add <目录名> # 添加整个目录
git add . # 添加当前目录下所有修改(包括新增、修改,不包括删除)
git add -u # 添加已跟踪文件的修改和删除(不包括新增)
git add -A # 添加所有修改(新增、修改、删除,等同于git add . + git add -u)
# 从暂存区移除文件(工作区文件保留)
git rm --cached <文件名> # 仅移除暂存区,工作区文件不变
git rm <文件名> # 同时删除工作区和暂存区的文件
# 提交暂存区文件到本地仓库
git commit -m "提交说明" # 简洁提交,说明写在-m后
git commit # 打开默认编辑器,编写详细提交说明(推荐复杂提交时使用)
git commit -a # 跳过暂存区,直接将已跟踪文件的修改提交(相当于git add -u + git commit)
git commit --amend # 追加提交(修改最近一次提交的说明,或补充未提交的修改到最近一次提交)
✨ 实战技巧:提交说明建议遵循「类型: 描述」格式,如 feat: 新增用户登录功能、fix: 修复首页轮播图切换bug,类型包括 feat(新功能)、fix(修复)、docs(文档)、style(格式)、refactor(重构)等。
4. 分支管理:多人协作核心
分支作用:隔离开发环境,避免不同功能/修复的代码相互干扰(如master/main为生产分支,dev为开发分支,feature/*为功能分支,bugfix/*为修复分支)。
# 查看分支(当前分支前有*)
git branch # 查看本地分支
git branch -r # 查看远程分支
git branch -a # 查看所有分支(本地+远程)
# 创建分支
git branch <分支名> # 基于当前分支创建新分支(仅创建,不切换)
# 切换分支
git checkout <分支名> # 切换到指定分支
git checkout -b <分支名> # 创建并切换到新分支(常用)
# Git 2.23+ 版本新增switch命令,更直观
git switch <分支名> # 切换分支
git switch -c <分支名> # 创建并切换分支
# 合并分支(将指定分支合并到当前分支)
git merge <待合并分支名> # 如在dev分支,执行git merge feature/login,将登录功能合并到dev
# 解决合并冲突:当两个分支修改同一文件同一行时,合并会触发冲突
# 1. 冲突发生后,Git会在文件中标记冲突内容(<<<<<<< HEAD 到 ======= 是当前分支内容,======= 到 >>>>>>> 分支名是待合并分支内容)
# 2. 手动编辑文件,删除冲突标记,保留正确内容
# 3. 编辑完成后,执行git add <冲突文件> 和 git commit 完成合并
# 删除分支
git branch -d <分支名> # 删除本地分支(需确保分支已合并,否则提示)
git branch -D <分支名> # 强制删除本地分支(未合并也可删除)
git push origin --delete <分支名> # 删除远程分支
# 拉取远程分支到本地(远程分支已存在,本地没有)
git checkout -b <本地分支名> origin/<远程分支名>
git switch -c <本地分支名> origin/<远程分支名>
5. 远程协作:多人开发必备
# 拉取远程仓库最新代码到本地(并合并到当前分支)
git pull origin <远程分支名> # 如git pull origin dev(拉取远程dev分支并合并到本地当前分支)
git pull # 若本地分支已与远程分支关联,可省略origin和分支名
# 推送本地代码到远程仓库
git push origin <本地分支名>:<远程分支名> # 如git push origin dev:dev(将本地dev推到远程dev)
git push # 关联后可省略
git push -u origin <本地分支名> # 首次推送时,-u建立本地与远程分支的关联(后续可直接git push)
# 拉取远程仓库最新代码,但不合并(如需手动合并,避免自动合并冲突)
git fetch origin <远程分支名>
git fetch # 拉取所有远程分支的最新代码
# 查看远程分支与本地分支的差异
git diff origin/<远程分支名> <本地分支名>
✨ 协作流程建议:1. 拉取远程最新代码(git pull)→ 2. 本地开发并提交(git add + git commit)→ 3. 推送至远程(git push),避免因本地代码过时导致冲突。
6. 版本回退:纠正错误提交
首先需要查看提交记录,找到需要回退的版本号(版本号是一串哈希值,可简写前6-8位)。
# 查看提交记录
git log # 详细显示所有提交记录(作者、时间、提交说明、版本号)
git log --oneline # 简洁显示(版本号前7位 + 提交说明)
git log --graph # 图形化显示分支合并历史
git log -n <数字> # 显示最近n条提交记录
# 版本回退核心命令:git reset
# 1. 软回退(git reset --soft):回退到指定版本,暂存区和工作区不变(保留修改,可重新提交)
git reset --soft <版本号> # 如git reset --soft a1b2c3d
# 2. 混合回退(git reset --mixed,默认):回退到指定版本,暂存区清空,工作区保留修改(需要重新git add)
git reset <版本号> # 等同于git reset --mixed <版本号>
# 3. 硬回退(git reset --hard):回退到指定版本,暂存区和工作区全部清空(修改全部丢失,慎用!)
git reset --hard <版本号>
# 回退远程仓库版本(若已推送错误版本到远程,需强制推送)
git push origin <分支名> --force # 或 -f(谨慎使用,多人协作时可能覆盖他人代码)
# 备选方案:git revert(安全回退,推荐多人协作时使用)
# 原理:创建一个新的提交,抵消指定版本的修改,不会改变历史记录
git revert <版本号> # 回退指定版本的修改
git revert -n <版本号> # 不自动提交,需手动git commit(处理多个版本回退时使用)
✨ 区别:git reset 会修改提交历史,适合本地未推送的错误;git revert 不修改历史,适合已推送的错误(避免影响他人)。
7. 高级技巧:提升效率
# 1. 暂存工作区修改(临时切换分支时使用)
git stash # 将当前工作区未提交的修改暂存起来(工作区变干净)
git stash save "暂存说明" # 带说明的暂存(方便区分)
git stash list # 查看所有暂存记录
git stash apply # 应用最近一次暂存的修改(暂存记录保留)
git stash apply stash@{n} # 应用第n条暂存记录(n从0开始)
git stash pop # 应用最近一次暂存的修改,并删除该暂存记录
git stash drop stash@{n} # 删除第n条暂存记录
git stash clear # 清空所有暂存记录
# 2. 查看文件修改内容
git diff # 查看工作区与暂存区的差异
git diff --cached # 查看暂存区与本地仓库的差异
git diff <版本号1> <版本号2> # 查看两个版本之间的差异
git diff <分支1> <分支2> # 查看两个分支之间的差异
git diff <版本号> <文件名> # 查看指定版本中该文件的修改
# 3. 查看指定文件的提交历史
git blame <文件名> # 显示文件每一行的最后修改人、版本号和时间(定位谁写的代码)
# 4. 忽略文件(不希望被Git跟踪的文件,如日志、缓存、IDE配置文件)
# 在项目根目录创建.gitignore文件,写入需要忽略的文件/目录,例:
# node_modules/ # 忽略node_modules目录
# *.log # 忽略所有.log后缀的文件
# .idea/ # 忽略IDEA的配置目录
# 注意:.gitignore只对未跟踪的文件有效,已跟踪的文件需要先执行git rm --cached <文件名> 解除跟踪
二、Git 面试常见问题汇总
本节整理了面试中高频出现的 Git 问题,包括基础概念、核心原理、实战场景等,每个问题附详细解答。
1. 基础概念类
Q1:Git 和 SVN 的区别?
核心区别:Git 是分布式版本控制系统,SVN 是集中式版本控制系统。
- 集中式(SVN):有一个中央服务器,所有代码都存储在中央服务器,开发者需要先从服务器拉取代码,开发完成后再推送到服务器;缺点是依赖网络,断网无法工作,中央服务器故障时无法协作。
- 分布式(Git):每个开发者的本地都是一个完整的仓库(包含所有历史记录),无需依赖中央服务器即可完成提交、分支等操作;仅在需要协作时(拉取/推送)与远程仓库交互;优点是断网可工作,容错性高(单个仓库故障不影响整体),分支操作高效。
Q2:Git 的工作区、暂存区、本地仓库、远程仓库分别是什么?
- 工作区(Working Directory):就是你本地电脑上看到的项目文件夹,是你正在编辑的代码目录。
- 暂存区(Stage/Index):介于工作区和本地仓库之间的缓存区域,用于临时存放你想要提交的修改;通过 git add 命令将工作区的修改添加到暂存区。
- 本地仓库(Local Repository):位于项目目录下的 .git 隐藏文件夹,存储了所有版本的历史记录和元数据;通过 git commit 命令将暂存区的修改提交到本地仓库。
- 远程仓库(Remote Repository):位于服务器上的仓库(如GitHub、GitLab),用于多人协作时共享代码;通过 git pull/push 命令与本地仓库交互。
Q3:Git 中的 HEAD 是什么?
HEAD 是一个指针,指向当前所在的分支的最新提交记录。可以把它理解为「当前工作位置」的标记:
- 当切换分支时,HEAD 会跟着切换到新分支的最新提交。
- 当进行版本回退时,HEAD 会指向回退的目标版本。
- 可以通过 git rev-parse HEAD 查看当前 HEAD 指向的版本号。
2. 核心操作类
Q1:git pull 和 git fetch 的区别?
两者都是从远程仓库获取最新代码,但核心区别在于「是否自动合并」:
- git fetch:仅从远程拉取最新代码到本地的远程跟踪分支(如 origin/dev),不会合并到本地当前分支;需要手动执行 git merge 进行合并,适合需要先查看差异再决定是否合并的场景。
- git pull:等价于 git fetch + git merge;拉取远程代码后自动合并到本地当前分支;优点是简单高效,缺点是可能自动合并产生冲突,不易控制。
✨ 建议:多人协作时,优先使用 git fetch + git merge,避免自动合并冲突。
Q2:git reset 和 git revert 的区别?如何选择?
两者都是用于版本回退,但原理和使用场景完全不同:
- git reset:通过移动 HEAD 指针来回退版本,会直接修改提交历史;分为 soft、mixed、hard 三种模式。
- git revert:通过创建一个新的提交来抵消指定版本的修改,不会修改历史记录。
选择原则:
- 如果修改仅在本地,未推送到远程仓库:使用 git reset(灵活,可根据需要选择模式)。
- 如果修改已推送到远程仓库,多人协作场景:使用 git revert(安全,不会破坏他人的提交历史,避免覆盖他人代码)。
Q3:如何解决 Git 合并冲突?
合并冲突产生的原因:两个分支修改了同一文件的同一部分内容,Git 无法自动判断保留哪部分,需要手动解决。
解决步骤:
- 当执行 git merge 出现冲突时,Git 会提示哪些文件冲突,同时文件中会出现冲突标记:
- 打开冲突文件,手动编辑:删除冲突标记(<<<<<<<、=======、>>>>>>>),保留正确的代码内容。
- 编辑完成后,执行 git add <冲突文件>(将解决后的文件添加到暂存区)。
- 执行 git commit 完成合并(此时无需加 -m,Git 会自动生成合并提交说明)。
✨ 技巧:可以使用 VS Code、WebStorm 等 IDE 的可视化工具辅助解决冲突,更直观。
Q4:git stash 的使用场景和常用命令?
使用场景:当你正在一个分支开发,但需要临时切换到另一个分支(如修复紧急 bug),而当前分支的修改还未完成,不想提交(提交不完整的代码会污染提交历史),此时可以用 git stash 将当前修改暂存起来,待后续恢复。
常用命令:参考第一部分「高级技巧」中的 stash 相关命令(stash、stash list、stash apply、stash pop、stash drop、stash clear)。
3. 分支与协作类
Q1:Git 分支的作用是什么?常见的分支策略有哪些?
分支的核心作用:隔离开发环境,避免不同功能/修复的代码相互干扰,提高协作效率。
常见分支策略:Git Flow(经典)、GitHub Flow(简洁)。
-
Git Flow 分支模型:
- master/main:生产分支,存放可部署的稳定代码,不直接开发。
- develop:开发分支,从 master 分支创建,用于集成各个功能分支的代码。
- feature/*:功能分支,从 develop 分支创建,开发完成后合并回 develop。
- bugfix/*:修复分支,从 develop 分支创建,修复开发中的 bug 后合并回 develop。
- release/*:发布分支,从 develop 分支创建,用于发布前的准备(如小修复),完成后合并到 master 和 develop。
- hotfix/*:紧急修复分支,从 master 分支创建,修复生产环境的紧急 bug,完成后合并到 master 和 develop。
-
GitHub Flow 分支模型(适合持续部署场景):
- master/main:主分支,始终保持可部署状态。
- feature/*:功能分支,从 master 创建,开发完成后提交 PR(Pull Request),审核通过后合并回 master,合并后自动部署。
Q2:如何将一个分支的特定提交合并到另一个分支?( cherry-pick 用法)
使用 git cherry-pick 命令,可以将一个分支的单个或多个指定提交,复制到当前分支(无需合并整个分支)。
使用场景:比如在 feature 分支有一个 bug 修复的提交,需要同步到 develop 分支,但 feature 分支其他功能还未完成,不能合并整个分支,此时可以用 cherry-pick 只复制这个修复提交。
# 1. 先在源分支(如feature分支)查看需要复制的提交版本号(通过git log --oneline)
# 2. 切换到目标分支(如develop分支)
git checkout develop
# 3. 执行cherry-pick,复制指定提交
git cherry-pick <提交版本号>
# 4. 若出现冲突,解决冲突后执行:
git add <冲突文件>
git cherry-pick --continue # 继续完成cherry-pick
# 若想放弃cherry-pick,执行:
git cherry-pick --abort
Q3:什么是 Pull Request(PR)?它的作用是什么?
Pull Request(简称 PR)是 GitHub、GitLab 等代码托管平台提供的一种协作功能,用于将一个分支的代码合并到另一个分支前,发起的「代码审核请求」。
作用:
- 代码审核:发起 PR 后,团队成员可以查看修改内容,提出意见,确保代码质量。
- 协作沟通:在 PR 评论区可以讨论代码问题,无需线下沟通。
- 自动化集成:可以配置 CI/CD 流程(如自动测试、编译),PR 合并前自动验证代码是否符合要求。
PR 流程:1. 开发者在自己的分支开发完成 → 2. 推送分支到远程仓库 → 3. 在平台上发起 PR(选择源分支和目标分支) → 4. 团队审核代码 → 5. 审核通过后,合并到目标分支 → 6. 合并完成后,删除源分支。
4. 原理与进阶类
Q1:Git 的提交对象(commit object)包含哪些信息?
每个 git commit 都会创建一个提交对象,存储在 .git/objects 目录下,包含以下核心信息:
- 树对象(Tree Object):指向暂存区的快照,记录了当前提交的文件结构和文件内容的哈希值。
- 父提交对象(Parent Commit):指向当前提交的前一个(或多个,合并提交有多个父提交)提交对象的哈希值,形成提交历史链。
- 提交者信息(Author/Committer):包括用户名、邮箱、提交时间。
- 提交说明(Commit Message):开发者编写的提交描述。
Q2:Git 如何保证数据的完整性?
Git 采用 SHA-1 哈希算法对所有数据(文件内容、提交对象、树对象等)进行校验,每个对象都会生成一个唯一的 40 位哈希值(如 a1b2c3d...)。
工作原理:任何数据的修改都会导致其哈希值变化,Git 会通过校验哈希值来判断数据是否被篡改。例如:
- 修改文件内容后,文件的哈希值会改变,对应的树对象和提交对象的哈希值也会随之改变。
- 通过 git log 查看的版本号,就是提交对象的哈希值,通过该哈希值可以准确找到对应的版本数据。
Q3:什么是 Git 钩子(Git Hooks)?有哪些常见的钩子?
Git 钩子是在 Git 执行特定命令(如 commit、push、merge)时自动触发执行的脚本(可以是 Shell、Python、Node.js 等脚本),用于自定义 Git 工作流,实现自动化校验(如代码规范检查、单元测试)。
Git 钩子存储在项目 .git/hooks 目录下,默认有多个示例脚本(如 pre-commit.sample、post-commit.sample),去掉 .sample 后缀即可生效。
常见钩子:
- pre-commit:在 git commit 执行前触发,常用于代码规范检查(如 ESLint)、语法检查,若脚本执行失败,提交会被终止。
- commit-msg:在编写提交说明后触发,常用于校验提交说明是否符合规范(如必须包含 feat/fix 等类型)。
- pre-push:在 git push 执行前触发,常用于执行单元测试、构建项目,若测试失败,推送会被终止。
- post-merge:在 git merge 执行后触发,常用于自动安装依赖(如 merge 后执行 npm install)。
三、总结
本文从实战角度梳理了 Git 核心命令的使用场景和语法,同时覆盖了面试中高频的概念、操作和原理类问题。Git 的学习核心在于「多实践」,建议结合本文内容,动手操作每个命令,理解其背后的逻辑(如分支合并、版本回退的原理),而不是死记硬背。
对于面试,重点掌握 Git 与 SVN 的区别、工作区/暂存区/仓库的概念、merge 冲突解决、reset 与 revert 的区别、分支策略等核心知识点,结合实战场景理解,就能从容应对大部分考察。
如果有补充的 Git 命令或面试问题,欢迎在评论区交流~