ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

学Git先掌握这15个核心命令:从安装配置到分支合并一次讲透

学Git先掌握这15个核心命令:从安装配置到分支合并一次讲透 有人问我学 Git 到底先学什么我的答案一直没变过先别急着背命令先把日常开发里最高频的那十几个命令用熟。Git 的命令有上百个但说实话你每天真正敲来敲去的翻来覆去就是那十几个。把这十几个命令的原理、参数、坑搞明白你就能覆盖日常开发 90% 以上的场景。这篇文章我就把 15 个 Git 核心命令掰开揉碎讲一遍从安装配置到分支合并从代码撤销到远程协作结合我这些年实操中踩过的坑一次性梳理清楚。这篇文章适合谁看刚入门 Git 的新手、在学校只学过 git add/commit 的科班生、以及用了很久 Git 但全靠图形界面点来点去、遇到命令行就发怵的同学。看完这篇文章你会发现 Git 命令行没那么可怕而且比图形工具高效得多尤其是在服务器上操作、批量处理、脚本自动化这些场景命令行几乎是唯一的选择。1. 先把 Git 环境收拾利索安装、配置与 SSH很多同学抱怨 Git 命令报错其实八成不是命令本身的问题是环境没弄对。这部分我按步骤讲照着做基本不会翻车。1.1 安装 GitWindows、macOS、Linux 三种方案Git 的安装本身不难但不同系统的安装方式和后续配置路径差别很大。Windows 用户直接去 Git 官网下载安装包就行安装时有一个容易忽略的选项调整 PATH 环境变量。建议选 “Git from the command line and also from 3rd-party software”这样 Git 命令不光能在自带的 Git Bash 里用在 CMD、PowerShell 里也能直接识别。安装完成后右键菜单会多出 “Git Bash Here” 和 “Git GUI Here” 两个选项日常操作强烈建议用 Git Bash它的命令语法跟 Linux 完全一致网上查到的教程命令都能直接用而 CMD 的语法在一些场景下有差异。macOS 用户分两种情况装了 Homebrew 的直接brew install git搞定没装 Homebrew 的可以去官网下 pkg 安装包装完在终端里输git --version验证。还有个隐藏方案macOS 自带的 Command Line Tools 里其实带了 Git你敲git命令时系统会提示你安装但版本通常比较旧建议还是用 Homebrew 装新版。Linux 用户最简单Debian/Ubuntu 系执行sudo apt install gitCentOS/RHEL 系执行sudo yum install git。这里有个细节系统自带的软件源里 Git 版本可能偏低如果你需要用一些较新的特性比如git switch命令2.23 版本才引入可以考虑加第三方源装新版不过日常使用系统源版本完全够了。装完验证一下git --version能看到版本号就说明安装成功了。Windows 用户如果在 PowerShell 里敲完这命令提示找不到命令大概率是 PATH 没配好去系统环境变量里把 Git 的安装路径加上然后重开终端。1.2 全局配置user.name 和 user.email 不设置好提交全是坑Git 安装完后第一件事不是急着拉代码而是配置身份信息。这一步要是跳过你 commit 的时候会提示让你补配置而且提交记录里的作者信息会变成系统默认的乱码名字团队协作时根本分不清谁是谁。git config --global user.name 你的名字 git config --global user.email 你的邮箱这里有几个容易忽略的地方。--global参数表示全局生效配一次所有仓库都能用。有些场景需要给某个特定仓库配不同的身份比如公司电脑上同时有个人项目和公司项目可以在仓库目录下去掉--global重新配置这样只对当前仓库生效。邮箱建议用你代码托管平台绑定的那个邮箱这样你的提交记录能正确关联到你的账号贡献图才会亮起来。如果你不想暴露真实邮箱GitHub 提供 noreply 的隐私邮箱在 GitHub 设置页面能看到用那个也完全没问题。配完可以查看确认git config --global --list会列出所有全局配置项包括 user.name、user.email还有后面要讲的 color.ui、core.editor 等。1.3 SSH 密钥配置一次配置免除每次输密码的烦恼很多新手第一次 clone 私有仓库时被要求输用户名密码输完发现下次还要输烦得要命。解决方案是配置 SSH 密钥。ssh-keygen -t ed25519 -C 你的邮箱一路回车就能生成密钥对。这里说明一下生成过程中会让你输 passphrase这是给私钥再加一道锁的密码如果不想每次用都输可以直接回车留空。ed25519是目前推荐的非对称加密算法比老的 RSA 更安全、密钥更短。如果你的 Git 服务器或托管平台还不支持 ed25519可以用ssh-keygen -t rsa -b 4096生成 RSA 密钥兼容性更好。生成后密钥默认在~/.ssh/目录下id_ed25519.pub是公钥id_ed25519是私钥。私钥绝对不能泄露不能提交到代码仓库也不能发给别人。公钥内容用下面的命令查看cat ~/.ssh/id_ed25519.pub复制输出的整行内容粘贴到你的代码托管平台后台。GitHub 在 Settings - SSH and GPG keys 里添加GitLab 在 Preferences - SSH Keys 里添加Gitee 在设置 - SSH 公钥里添加。配置好之后测试一下ssh -T gitgithub.com如果是 GitHub 会回一句 “Hi xxx! Youve successfully authenticated”看到这句说明 SSH 认证已经通了以后 clone、push、pull 都不用再输密码了。ssh -T这条命令经常用到排查 SSH 认证失败特别管用。常见的失败原因有两个一是公钥没粘贴正确多了或少了个字符都不行二是本机有多个密钥系统默认用了错误的那个。解决办法是在~/.ssh/config文件里指定Host github.com HostName github.com User git IdentityFile ~/.ssh/id_ed25519这样系统就知道连接 GitHub 时该用哪个私钥了。2. 拿下一个仓库clone、init 与状态查看环境配好之后开始进入真正的实操环节。第一个要掌握的是怎么把一个仓库弄到本地以及怎么随时掌握仓库的状态。2.1 git clone把远程仓库完整复制到本地克隆仓库是 Git 里最常见的操作之一。语法很简单git clone gitgithub.com:用户名/仓库名.git这里我强烈推荐使用 SSH 地址而不是 HTTPS 地址。HTTPS 地址每次 push 都要输账号密码哪怕配置了缓存也只能管一段时间SSH 地址按第一部分配置好密钥后完全免密体验差别很大。git clone默认会把远程仓库的所有分支历史都拉下来同时自动建立一个本地分支跟踪远程的默认分支一般是main或master。如果你只想克隆最近一次提交的代码、不关心历史记录可以加--depth 1参数做浅克隆这在拉取大型仓库时能省不少时间和磁盘空间git clone --depth 1 gitgithub.com:用户名/仓库名.git还有一个细节容易被忽视默认克隆下来的仓库目录名是仓库名本身。如果你希望放到别的目录名下在仓库地址后面加一个空格指定目录名即可git clone gitgithub.com:用户名/仓库名.git 新目录名这个在团队协作里有实际用途。比如你同时需要拉取同一个仓库的多个分支版本就可以克隆到不同目录避免频繁切换分支。2.2 git init从零开始初始化一个仓库新项目还没有纳入版本控制时用git init在当前目录下初始化一个全新的仓库。git init执行后目录下会多出一个.git目录所有的版本历史、配置信息都存放在这里。如果你不小心把这个目录删了整个仓库的版本历史就全没了工作区文件还在但再也无法回溯历史版本。所以没事别去动.git目录。有一种情况要特别当心如果你在一个大的目录结构下执行git init比如在/Users/username/project下它会把这个目录和它的所有子目录都纳入版本控制范围除非被.gitignore排除。所以初始化前想清楚仓库的边界别把一个包含大量临时文件、依赖包的目录整个变成仓库不然后面每次提交都要小心翼翼。git init还有一个常用变体git init 目录名会在指定目录创建新项目并初始化仓库一步到位。2.3 git status随时掌握工作区状态我刚学 Git 时最喜欢敲的命令就是git status因为它把你当前仓库的状态说得很清楚哪些文件改了、哪些文件新增还没加入暂存、当前在哪个分支、跟远程仓库差了多少个提交。git status输出信息分几个区域Changes not staged for commit已跟踪文件被修改了但还没暂存Changes to be committed文件已暂存等待提交Untracked files新增文件Git 从未跟踪过刚接触 Git 的同学第一次看这些输出可能会晕我提供一个理解方式Git 的文件状态流转是“工作区 - 暂存区 - 版本库”三层结构。工作区就是你实际编辑文件的目录暂存区是提交前的一个中间缓冲区版本库保存着每一次提交的历史快照。git status就是告诉你这三层之间当前有哪些差异。为了方便快速查看更简洁的状态建议用git status -sb-s是精简输出每个文件一行用字符表示状态-b同时显示当前分支和与远程分支的领先/落后情况。我自己的习惯是把这个起个别名git config --global alias.st status -sb以后敲git st就能看到一行非常清爽的状态概览效率提升明显。3. 日常提交的核心链路add、commit、log接下来是 Git 使用频率最高的三个命令也是很多人只知道“怎么用”但没想过“为什么这么用”的三个命令。3.1 git add把改动放进暂存区修改文件之后第一步是把改动文件加入暂存区git add 文件名如果想一次把所有改动都加入暂存用git add .这里有个重要提醒git add .会把当前目录下所有未跟踪的文件和修改文件全部加入暂存。如果你的项目里有些文件本不应该被提交比如本地的配置文件、密钥文件、依赖包目录却没在.gitignore里忽略就会被一起暂存。我见过有人把含有数据库密码的配置文件提交到仓库然后推上远程酿成安全事故。所以养成好习惯一个项目开始时就写好.gitignore提交前用git status或git diff --cached确认一下要提交的文件。git add还有一个交互模式值得学习git add -p。这个命令会逐个区块地让你确认是否暂存改动适合你在一个文件里做了多处修改、但只想提交其中一部分的场景。团队协作中这种“部分提交”能力很实用可以让单个提交只包含一个逻辑变更代码评审的人会感谢你。3.2 git commit创建一次提交记录暂存区准备好后就该提交了git commit -m 提交说明提交说明的质量直接影响团队协作效率。我总结的提交信息格式是这样用一句话说清楚“这次改动做了什么”动词开头控制在一行内尽量不超过 50 个字符。比如修复登录页面在 Safari 下样式错乱的问题比修改了一些bug强一万倍。很多团队用 Conventional Commits 规范格式是type(scope): subjectfeat(user-service): 新增用户注册接口fix(auth): 修复 token 过期时间计算错误docs(readme): 更新部署步骤说明如果你提交时忘了写-m参数Git 会打开默认编辑器让你写提交信息。默认的编辑器通常是你系统里配的vi或vim新手经常卡在里面不知道怎么退出直接关掉终端导致提交失败。两个解决办法一是设置默认编辑器为更友好的工具比如 VS Codegit config --global core.editor code --wait二是强制自己每次都用-m参数。提交之后想修改最近的提交信息可以用git commit --amend -m 新的提交说明这会把上一次提交替换掉相当于改了历史。要注意的是如果你已经把上次提交推送到了远程而且有同事基于它做了开发就不要用 amend否则会打乱所有人的历史记录。3.3 git log查看提交历史别再用肉眼翻历史了需要回顾项目演进过程、排查某次提交改了什么用git log。git log默认输出每个提交的哈希值、作者、日期、提交信息。但默认格式信息量太大看起来特别费劲。我推荐这几个参数组合# 一行一提交只看提交信息和短哈希 git log --oneline # 图形化展示分支结构 git log --graph --oneline --all # 查看具体某个文件的提交历史 git log --oneline -- 文件名--oneline把每个提交压缩成一行输出哈希前 7 位和提交信息扫一眼就能了解整体演进--graph会把分支合并的分叉线画出来配合--all能看到所有分支适合理清复杂的合并关系。还有一个参数我经常用git log -p它会连每个提交的具体改动内容diff一起显示排查某个提交具体改了什么的时候特别有用。不过输出很长配合--oneline -3限定位数更实用。3.4 核心原理解读为什么 Git 要设计“暂存区”这个概念前面多次提到暂存区这里有必要深入讲一下。你日常的编辑、查看改动、提交代码实际上都在跟“工作区和暂存区的关系”“暂存区和版本库的关系”这两组差异打交道。Git 设计暂存区的核心目的是让你可以精细控制一次提交的内容边界。工作区里可能同时存在多个文件的改动有些改动属于功能 A有些属于功能 B。如果不经过暂存区直接提交你就只能把所有改动打包成一个提交历史记录的粒度很粗后续想单独回滚功能 A 就无从下手。有了暂存区之后你可以把功能 A 的文件用git add加入暂存先提交再把功能 B 的文件加入暂存再提交。这样一条条提交互相独立每条提交只做一件事。这个理念在团队协作里特别关键因为代码评审Code Review就是基于提交记录逐个看的。回到项目实际操作层面应对“临时要切换分支”这种情况时暂存区的作用就体现出来了。如果你在工作区改到一半突然有个紧急 bug 要切到其他分支修复不处理手头的改动就直接切换会很被动——要么把半成品提交上去污染历史要么改丢。这就是暂存区和下面要讲的git stash系列命令大显身手的时候。4. 分支操作branch、checkout/switch、merge分支是 Git 最强大的设计也是对新手最不友好的功能。把它搞明白你对 Git 的理解就上升了一个台阶。4.1 git branch查看、创建、删除分支分支管理命令的第一条# 查看本地所有分支当前分支前会有星号 git branch # 查看所有分支包括远程分支 git branch -a # 创建一个新分支 git branch 新分支名 # 删除一个已合并的分支 git branch -d 分支名 # 强制删除分支即使未合并 git branch -D 分支名有个概念必须理解透彻切换到某一分支上的操作本质上是移动一个指针并不会改变你工作区的文件只有当 checkout 或 switch 的时候Git 才会根据目标分支的内容和当前分支内容的差异来更新工作区文件。这也是为什么切换分支前要求“工作区干净”不然可能带着未提交的改动进入另一个分支产生混乱。4.2 git checkout/switch切换分支的正确姿势早期 Git 只有git checkout一个命令身兼两职切换分支和恢复工作区文件。命令用是能用但职责不清晰。Git 2.23 版本引入了git switch专门负责分支切换职责单一推荐优先使用# 切换到已存在的分支 git switch 分支名 # 创建新分支并切换过去两步合成一步 git switch -c 新分支名 # 切换回上一个分支 git switch -如果你还在用旧版的git checkout -b 新分支名也没有问题只是注意别跟“用 checkout 恢复文件”混淆。切换分支前一定要记住确认当前工作区是干净的。如果你有未提交的改动可以先 commit 或者 stash不要直接切换。因为 Git 默认不允许带着会造成冲突的未提交改动切换分支有时虽然让你切过去了但改动会带过去很容易搞乱。4.3 git merge合并分支的两种方式与冲突处理把功能分支的成果合并回主干用git merge# 先切换到要接收合并的目标分支 git switch main # 将 feature 分支合并到 main git merge feature合并有两种情况快进合并Fast-forward和三方合并Three-way merge。快进合并发生在目标分支自从分支出来以后没有任何新提交Git 只需要简单地把指针往前移动历史是一条直线非常干净。但实际开发中这种情况较少因为主干通常不断有新提交。三方合并发生在两个分支都有各自的新提交Git 需要找两个分支的共同祖先结合三份内容共同祖先、当前分支、目标分支做合并。如果两个分支改动了同一个文件的同一位置Git 无法自动决定就会报冲突。冲突是新手最怕的场景报错信息长得吓人。实际处理流程其实不超过三步打开提示冲突的文件搜索、、标记手动保留需要的代码删掉这些标记保存文件后执行git add 文件名然后git commit完成合并冲突文件里 HEAD和之间是当前分支HEAD的版本和 feature之间是被合并分支的版本。你需要读懂两边代码的意图决定最终保留哪份或者融合两边内容。我的经验是两段都要的情况远多于二选一不要在冲突时急着删除另一方的代码先读懂为什么要两边都改。有些冲突文件很大处理起来耗神但这是版本控制里非常正常的一环处理多了就习惯了。4.4 分支策略为什么团队协作中 feature branch 是常态理解了分支和合并再聊聊日常开发中用得最多的分支策略。现在大多数团队都采用“主干开发 功能分支”的模式main或master是受保护的主干永远保持可发布状态每个功能在一个独立分支上开发分支名可以是feature/登录功能、fix/修复XXbug功能完成后通过合并请求Pull Request / Merge Request走代码评审流程合入主干这种做法的价值在于主干始终处于健康状态任何时刻都可以部署发版功能分支隔离了半成品的代码不会影响其他人的工作通过代码评审可以在合并前发现潜在问题。你在本地开发时也建议养成开分支的习惯。一个需求开一个新分支开发完成合并后删除分支不要所有改动都堆在主分支上。理由很简单如果改动做到一半需要去线上修 bug在干净的主干上开一个hotfix分支修复合入整个过程不会被半成品功能干扰。5. 远程协作与撤销remote、push、pull、fetch、stash、reset这部分的命令直接关系到多人协作和代码安全每一个都值得认真掌握。5.1 git remote管理远程仓库地址查看远程仓库地址git remote -v输出会列出origin对应的 URLorigin是 Git 默认给远程仓库起的名字。当你git clone一个仓库时Git 自动把远程地址命名为origin。如果你是在本地git init初始化的项目想要关联一个远程仓库git remote add origin gitgithub.com:用户名/仓库名.git如果远程地址变了需要更新git remote set-url origin 新的地址删除远程关联git remote remove origin这块操作不多但很重要因为团队协作的一切推送和拉取都是基于远程仓库来做的。5.2 git push把本地提交推送到远程把本地已提交的内容推送到远程仓库git push origin 分支名第一次推送一个新建的本地分支时会需要建立与远程分支的关联关系git push -u origin 分支名-u参数不仅推送到远程还设置当前本地分支跟踪远程同名分支。设置之后后续只要敲git push就能直接推送不用再写远程名和分支名了git pull同理。推送时有几个常见报错值得提前了解“non-fast-forward” 错误远程分支上已有你本地没有的提交说明远程被其他人推送过了。解决办法先git pull或git fetch merge再推送。“failed to push some refs”原因通常同上或者你没有该分支的写权限。推送前记得先 pull我养成的习惯是推送前先git pull --rebase把远程的新提交拉下来让自己的提交“叠”在最新代码之上保持历史线性然后再 push。这样能减少冲突概率也让历史记录更清晰。关于--rebase的详细机制我们在后面章节展开讲。5.3 git pull 与 git fetch拉取代码的两种姿势很多人以为git pull就是 “更新下本地代码”这句话不准确。git pull其实是两条命令的合体先执行git fetch拉取远程最新提交到本地一个特殊区域再执行git merge将这些提交合并进你当前所在的分支。git fetch单独执行时只会把远程仓库的最新状态下载到本地但不会动你当前分支的工作区和历史。你的本地仓库就会保留一份远程更新的引用用git log FETCH_HEAD可以查看拉取下来的内容确认无误后再手动决定如何合并。git pull把 fetch 和 merge 合二为一操作简洁但它的合并行为有时会产生不必要的合并提交merge commit把历史记录搞得乱七八糟。这种情况下我会用git pull --rebase--rebase方式下Git 会先把你的本地提交“摘下来”拉取远程最新提交后再把你的提交按顺序重放到最新代码之上。最终效果是历史保持线性没有多余的 merge commit阅读起来像一条干净的直线。这里有一个核心注意点rebase 会改写提交历史如果你已经把这些提交推送到了远程并且其他同事基于它们做了工作就不要再用 rebase 去操作这些提交否则会把大家的历史搞得一团糟。判断标准很简单只 rebase 那些“只存在于本地、从未推送过的提交”。5.4 git stash临时保存当前工作进度开发做到一半突然要切分支修 bug又不想提交半成品代码怎么办git stash就是为了解决这个问题而生。# 把当前未提交的改动包括已暂存的和未暂存的临时保存起来 git stash # 恢复最近一次保存的改动 git stash pop # 查看所有保存过的改动 git stash list # 恢复指定的一次保存不删除那条记录 git stash apply stash{1}一个我特别推荐的习惯git stash时加上描述信息方便之后识别git stash push -m 登录功能开发到一半git stash list就能看到这条描述而不是一堆随机哈希。什么时候用 stash典型场景是你正在开发功能 A线上突然出了 bug 需要马上修。此时本地改动还没到提交的程度如果直接切分支这些半成品改动会跟着工作区走非常危险。执行git stash后工作区干净了切分支修 bug、提交、推送最后切回来执行git stash pop你的改动原封不动地回来了。需要提醒的是git stash pop如果遇到冲突因为你改动过的文件在 stash 期间被别人改了会像 merge 冲突一样要求手动解决。这是 stash 机制的正常行为按冲突处理的流程走就好。5.5 git reset 与 git revert两种撤销方式别用混了撤销操作是 Git 里最容易被误用的部分也是新手事故高发区。先记住一个大原则尚未推送到远程的提交用什么方式撤销都行已经推送到远程的提交不要用 reset而应该用 revert。git reset的作用是把当前分支的 HEAD 指针回退到指定提交有--soft、--mixed、--hard三个参数影响范围从轻到重# 回退到上一个提交但保留改动在工作区改动取消暂存 git reset --soft HEAD~1 # 撤销提交和暂存但保留所有改动在工作区 git reset --mixed HEAD~1 # 彻底回退丢弃所有改动 git reset --hard HEAD~1三个参数整天把新手绕晕我提供一个简化记忆--soft只动 HEAD 指针回归--mixed在--soft基础上还清了暂存区--hard则放弃所有改动、让工作区回到目标提交状态。最常见的需求是“我提交了但提交信息写错了要用git commit --amend”和“我提交了不该提交的文件要用git reset --mixed HEAD~1”。用--hard务必想清楚它会丢掉无法找回的临时改动。git revert刚好相反它不是回退历史而是创建一个新提交把某个旧提交的改动反向撤销。这样历史是往前走的其他人拉取代码时自然就能同步到这次撤销不会因为各自 rebase 导致历史分叉git revert HEAD执行后 Git 会打开编辑器让你写撤销提交的说明保存后即完成撤销。我给你们一个最简单的选择建议代码还在自己本地没推出去随便 reset代码已经推送、或不确定别人是否已经拉取一律用 revert。这是让团队协作不翻车的基本素养。6. 高频场景实战把 15 个命令串起来跑一遍前面按命令逐个拆解有朋友可能会问真实开发中这些命令是怎么组合起来用的这里以一个典型的功能开发周期为例把完整的命令流串一遍。6.1 场景一新版本功能开发的标准流程入职一家公司第一次拿到项目代码从环境配置到功能开发结束推送到远程完整流程长这样# 1. 配置身份信息只在全新环境做一次 git config --global user.name 你的名字 git config --global user.email 你的邮箱 # 2. 生成 SSH 密钥并配置到托管平台只做一次 ssh-keygen -t ed25519 -C 你的邮箱 cat ~/.ssh/id_ed25519.pub # 3. 克隆项目到本地 git clone gitgithub.com:公司/项目.git # 4. 进入项目目录为本次需求创建功能分支 cd 项目目录 git switch -c feature/新增用户导出功能 # 5. 开始开发过程中随时查看状态 git status # 6. 开发完成暂存改动 git add src/新增的源文件 git add test/对应的测试文件 # 7. 提交写清说明 git commit -m feat(user): 新增用户导出功能 # 8. 推送前先拉取最新代码用 rebase 保持历史线性 git pull --rebase # 9. 推送到远程 git push -u origin feature/新增用户导出功能这就是一个非常标准的日常开发闭环。第 8 步如果你不做git pull --rebase而是直接 push 时被告知远程有新提交那就得停下来做合并提前 pull 一下往往能更早发现冲突冲突处理也更轻松。如果是开发到一半被紧急任务打断第 5 步之后实际操作会插一段 stash 操作# 紧急任务来了先把半成品藏起来 git stash push -m 新增用户导出功能开发中 # 切回主干修复线上 bug git switch main git switch -c hotfix/修复统计页崩溃 ... ... 修复、提交、推送 ... # 回到原功能分支恢复进度 git switch feature/新增用户导出功能 git stash pop这套流程跑完你对 Git 的核心命令基本就形成肌肉记忆了。6.2 场景二提交信息写错了、文件加错了的补救提交后发现把临时文件也包含进去了或者提交信息写得不清楚别慌按下面的方案补救# 场景还没推送只是想改最近一条提交的说明 git commit --amend -m 更准确的提交说明 # 场景还没推送想撤销最近一次提交框架但保留改动 git reset --mixed HEAD~1 # 撤销后重新选择要提交的文件 git add 正确的文件 git commit -m 正确的提交说明注意--mixed HEAD~1不回退工作区你之前的文件改动都还在只是暂存区被清空需要重新 add。6.3 场景三线上代码出 bug紧急回滚假设功能上线后出现问题需要立刻回退到上一个稳定版本。分两种状态代码还没推送到远程本地回滚git reset --hard HEAD~1代码已经推送到远程多人协作环境下的安全操作是 revertgit revert HEAD git push origin main这样远程会新增一个“撤销提交”代码内容回退到上一个版本的最终状态历史中清楚留痕。后续想再恢复这次的功能只要找到被 revert 的那个提交用git revert revert 提交的哈希再反向操作一次就行。7. 常见问题与排查技巧实录最后把我在实战中遇到的 Git 高频问题做一个整理。这些问题不是冷门角落而是几乎每个团队都踩过一遍的坑。7.1 SSH 认证失败的排查步骤不少同学配置完 SSH 密钥后执行git clone gitgithub.com:...收到Permission denied (publickey)。逐条排查确认公钥是否粘贴完整执行cat ~/.ssh/id_ed25519.pub从头到尾复制一遍不要漏字符确认粘贴的平台对不对GitHub 的公钥要加在 GitHub 后台GitLab 的加在 GitLab 后台别搞混确认本机是否有多个密钥且用的是正确的那一个查看~/.ssh/config配置确认IdentityFile指向了正确的私钥路径确认私钥权限私钥文件权限应为 600可以用chmod 600 ~/.ssh/id_ed25519修正。权限过宽会被 SSH 直接忽略这是一个防呆设计测试认证是否通过ssh -T gitgithub.com如果显示认证成功问题就出在 clone 地址写的是 HTTPS 而不是 SSH。这个排查顺序十次有九次能定位问题。7.2 不小心 commit 了不该提交的文件最常见的是把密钥文件、.env环境变量文件、大文件等误提交。此时判断是否已推送未推送的话git reset --mixed HEAD~1撤销提交但不丢改动然后把这些文件加进.gitignore重新提交已推送到远程的话这已经属于需要立即处理的情况因为文件内容和提交历史都已外泄。在团队协作中应第一时间告知同事因为这个记录没法通过简单方式彻底抹掉。普通文件误提交可以在远程用 revert 的方式提交一个反向操作但敏感信息意味着需要重新生成密钥或密码因为泄露的凭证不能再用了。避免这件事的最好办法是前置预防# 提交前一定会看的内容 git status git diff --cachedgit diff --cached专门用来看“将要提交的改动”到底改了什么把敏感信息拦截在提交之前成本最低。7.3 分支合并时冲突处理的心态与技术面对冲突文件时最常见的心态问题是慌。事实上冲突只是提示“Git 无法替你决定”并不代表代码坏了。按我前面的方法打开文件找到冲突标记区域逐段处理即可。处理冲突时有一个地方要多问一句双方代码是否在逻辑上都应该保留如果一边是重构后的新实现另一边是 bug 修复通常应该保留最新的实现并合入修复逻辑如果两边改了完全不同的模块只是恰好同一个文件的相邻行那么两边都要保留。处理完冲突后git add 文件然后git commit合并就完成了。想中途退出合并回到合并前状态执行git merge --abort7.4 误操作了 git reset --hard 如何抢救万一你已经执行了git reset --hard发现文件内容全不对了先冷静。Git 的 reflog 会记录 HEAD 指针的每一次移动是 Git 的“后悔药”机制# 查看 HEAD 的历史移动记录 git reflog # 找到误操作之前那个提交的哈希 git reset --hard 那个哈希git reflog的输出会列出所有 HEAD 变化包括你刚才 reset 产生的记录。只要你的改动在某个提交中存在过reflog 就能帮你找回。这也是为什么我反复强调“能不 reset --hard 就不 hard”但真误操作了补救路径一直是存在的。7.5 常用命令速查表把 15 个核心命令的信息汇总成一张速查表建议收藏命令核心作用高频参数适用场景git config配置身份与全局参数--global, --list新环境初始化ssh-keygen生成 SSH 密钥对-t ed25519, -C配置免密认证git clone克隆远程仓库到本地--depth 1首次拉取项目git init初始化本地仓库目录名新项目起步git status查看仓库当前状态-s, -b提交前确认git add暂存文件改动-p, .提交前准备git commit创建提交记录-m, --amend保存版本快照git log查看提交历史--oneline, --graph, -p回溯代码演进git branch管理分支-a, -d, -D分支生命周期管理git switch切换分支-c分支切换git merge合并分支--abort功能合入主干git remote管理远程仓库-v, add, set-url远程协作配置git push推送提交到远程-u分享代码git pull拉取并合并远程更新--rebase同步远程最新代码git fetch仅拉取远程更新而不合并配合 merge 使用查看远程状态后再决定git stash临时保存工作进度push -m, pop, list切换分支前暂存改动git reset回退分支历史--soft, --mixed, --hard本地提交撤销git revert用新提交反向撤销旧提交HEAD远程已推送内容的撤销这里我实际写了 18 个命令超过了标题的 15 个。原因是日常开发中这 18 个命令高度协同单拎出任何一个都会影响其他命令的理解。实际使用中你会发现真正最核心的就是config、status、add、commit、log、branch、switch、merge、remote、push、pull、stash、reset、revert、clone 这 15 个另外几个是根据场景灵活搭配使用的辅助命令同样建议掌握。7.6 把 Git 用利索的几个小习惯最后分享几个我这些年养成的 Git 使用习惯不需要额外装工具纯靠改习惯就能让协作体验提升一大截第一每次提交前必须跑一遍git status和git diff --cached。前者看哪些文件会被纳入提交后者看具体改动内容。这一步能拦截 90% 的误提交。第二提交信息遵循固定格式。我日常主力格式是type(module): descriptiontype 用 feat/fix/docs/refactor/testmodule 写模块名。这样之后回看历史或者用工具生成变更日志都能一目了然。第三推送前先git pull --rebase。这个习惯能有效减少冲突出现概率让团队历史保持线性。不要等到 push 失败才去处理远程差异。第四本地功能分支尽量在一两天内完成并合并删除。长期不合并的分支会成为“技术债”合并时冲突面巨大且分支上写的内容往往已经跟主干脱节。第五不要试图覆盖已推送的历史。已经推送出去的提交任何人可能在任何时刻拉取过。你本地怎么 reset 都只是你一个人的事但一旦覆盖了远程历史整个团队的仓库都会混乱。安全的改写历史方式只有新增提交包括 revert不会影响他人的工作副本。这些习惯挂在嘴边不难难的是真正执行。一旦它们在团队里形成共识很多协作中的磕磕绊绊会少很多。我自己的实际体验是刚开始学 Git 时总觉得命令太多记不住尤其是 merge 和 rebase、reset 和 revert 这两组概念绕了很久。后来发现与其死记硬背不如把“工作区、暂存区、版本库”三层结构和“提交 快照 指针移动”这条主线想清楚所有命令的行为都能推导出来。建议各位在遇到不确定的命令时先想清楚这一步操作会改变几个区域的状态再敲回车基本就不会出大错。Git 的学习曲线确实有点陡但把它当成肌肉记忆练一两个星期之后你就能体会到它给开发流程带来的掌控感。
返回列表