你电脑里是不是有一堆这样的文件:论文终版.doc、论文终版2.doc、论文真的不改了.doc、最终版打死也不改了.docx?如果是,那你急需 Git。如果你们团队协作还是靠“我改完发你,你再改完发我”的微信文件传输模式,那你也该认识一下 Git 了。很多人把 Git 当成一个“程序员专用工具”,其实它本质上就是一个极其好用的“版本管理神器”,你能用它管代码、管文档、管配置,甚至可以管你写书的草稿。这篇文章我不打算给你讲太多高深理论,我也不会把它写成一本 Git 教科书。我就按照我自己从零折腾 Git 到真正在工作中用明白的路子,带你从安装配置、常用命令、分支协作,再到 Gitee 远程仓库实战,最后把高频问题一网打尽。保证你读完能直接上手,在工作里立刻用起来。
1. 为什么要用 Git:先搞清楚它解决了什么
1.1 从“版本管理”这件事说起
想象一下你正在写一份年度总结报告,改到第三版的时候,领导说“还是第一版的感觉对”。如果你没有版本管理工具,你可能已经完全找不回第一版了。就算你非常机智地存了第一版.doc、第二版.doc,你怎么精确知道第二版和第一版之间到底改了什么?第三版又删了哪些关键数据?
Git 解决的就是这件事。它把你每一次“我要保存一下当前进度”的动作都记录下来,生成一个提交(commit)。每个提交里保存着这一个瞬间所有文件的快照,以及这次提交相对于上一次提交改动的地方。这样你随时可以回到过去任何一个保存过的状态,也可以随时对比任意两个版本之间的差异。它就像给你的整个工作目录安装了一台时光机,想停在哪里就停在哪里。
1.2 为什么选 Git 而不是 SVN 这类老牌工具
很多老项目还在用 SVN。SVN 是集中式版本控制,服务器挂了大家就都歇菜了;Git 是分布式版本控制,每个开发者本地都有一个完整的仓库历史,服务器挂了你的本地照常提交,等服务器恢复后再同步就行。这一点在出差、飞机上写代码时优势巨大。
再有一个关键差异是分支的成本。在 SVN 里创建分支是个又慢又重的操作,通常要复制整个目录,所以很多团队干脆不分叉,所有人都挤在主线上开发。Git 的分支创建和切换都极其轻量,本质只是移动一个指针,所以 Git 社区的协作玩法是“人手一个分支,随时开叉随时合并”。这个差异直接决定了团队的协作效率和代码仓库的整洁度。
1.3 Git 的核心价值观念
- 后悔药自由:任何一次误删、误改、误合并,只要你有提交记录,都能恢复。
- 并行开发:你和同事可以同时改同一个项目的不同模块,互不干扰,最后合并即可。
- 代码审查:通过分支和合并请求(Pull Request 或 Merge Request),别人在合入你代码之前,可以清楚地看到你改了什么,这比直接往主干上怼代码要安全得多。
我自己在实际使用中体会最深的,不是那些炫酷的高级命令,而是git status和git log这两个“只读”命令。每当我迷茫的时候,敲一下这两个命令,看一眼当前在哪个分支、工作区有没有改动、历史上的提交是啥样,心里就踏实了。Git 对你的要求其实不高——你先学会“查看状态”和“查看历史”这两个动作,整个工具就变得不那么可怕了。
2. 环境准备:把 Git 装好并完成最基础配置
2.1 各平台安装方式一览
安装 Git 的教程网上满天飞,其实核心就是三步:下载对应平台的安装包、下一步下一步、打开终端验证。我按平台把关键点列一下。
Windows
去 Git 官网下载安装包(或者用国内的软件管理器),安装时注意几个选项:
- 开始菜单目录名保持默认即可。
- 默认编辑器建议选 Vim 或 Notepad++ 都行,或者选 VS Code 也可以。你要是完全没接触过 Vim,我建议选 VS Code,免得提交的时候不小心进了 Vim 不知道怎么退出。
- 调整 PATH 环境变量,选 “Git from the command line and also from 3rd-party software” 最保险,这样无论你在哪个终端里都能直接敲
git命令。 - 行结束符转换,选 “Checkout Windows-style, commit Unix-style line endings” 就行,这个选项能有效避免大多数跨平台换行符问题。
安装完成后,打开命令行,敲git --version,能输出版本号就说明装好了。
macOS
macOS 上最简单的方式是用 Homebrew:
brew install git如果你没装 Homebrew,也可以去官网下载 macOS 安装包。或者你只需要 Xcode Command Line Tools,它自带了 Git:
xcode-select --installLinux(Debian/Ubuntu 系)
sudo apt update sudo apt install gitRed Hat/CentOS 系用:
sudo yum install git2.2 安装后必做的基础配置
Git 安装完成后,第一件事不是急着建仓库,而是告诉它“你是谁”。后续你每一次提交,Git 都会把这些信息记录在提交记录里。如果没配,提交的时候会弹出提示让你补。
git config --global user.name "你的名字" git config --global user.email "你的邮箱"这两条命令里的--global表示全局生效,也就是在这台机器上所有 Git 仓库默认都会用这个身份。如果你某个特定项目想用不同的身份,可以在那个项目目录里去掉--global再设置一次,项目级别的配置会覆盖全局配置。
顺便说一下,很多人忽视了一个配置:
git config --global core.editor "code --wait"这个命令把默认编辑器改成 VS Code。我个人实测下来,确实比默认的 Vim 对新手友好太多。你要是平时用其他编辑器,替换成对应的启动命令就行。
最后再推荐一个非常实用的配置:
git config --global pull.rebase false这是现在 Git 的默认行为,你在拉取远程更新时不会意外地把历史改写成一条直线,这一点在团队协作中能避免很多心理负担。这个选项用默认值就行,不用特意去改。
2.3 验证配置是否生效
配置完成后,可以敲:
git config --list这个命令会列出当前所有生效的配置项。你只要看到user.name和user.email都正确,就说明环境就绪了。
实测下来,新手最容易栽的跟头反而是在 Windows 上安装了 Git 却找不到命令行入口。记住,装完 Git for Windows 后,在任意文件夹里右键,选择“Git Bash Here”,Git 命令就在这个终端里敲。别用系统自带的“命令提示符”去试,不是说不行,而是 Git Bash 的操作体验更接近 Linux,命令兼容性更好。
3. 高频命令实战:把日常工作跑通
3.1 工作区、暂存区、版本库这三个概念必须懂
我见过太多人把 Git 命令背得滚瓜烂熟,却始终不理解为什么会冒出个“暂存区”。简单打一个比方:你在厨房里做菜(工作区),做好了先端到餐桌上(暂存区),拍完照发朋友圈(生成提交)后,这顿饭才算正式记录在册(版本库)。这中间有个很重要的设计意图:你可以一次改很多文件,但可以分批次地提交,比如把“修复 A 问题”相关的文件放到一个提交里,把“新增 B 功能”的文件放到另一个提交里,这样以后查历史的时候,每个提交的目的都清清楚楚,别人 code review 也轻松得多。
在 Git 中,三个区域的关系就是:
- 工作区(Working Directory):你当前能看到的、正在编辑的文件所在的地方。
- 暂存区(Staging Area / Index):你通过
git add把工作区中的改动“挑选”出来,放到一个待提交的缓冲区。 - 版本库(Repository):
git commit之后,暂存区里的内容被固化成一个新的提交,永久记录在.git目录中。
3.2 创建仓库:从零开始
假设你新建了一个项目文件夹myproject,你想让 Git 接管这里的版本管理:
cd myproject git init执行完git init后,文件夹里会多一个隐藏的.git目录,所有版本信息都存在这里。如果你买了新电脑,想把云端仓库克隆到本地,就不用init,而是:
git clone <远程仓库地址>关于init和clone的选择:init是你从零新建项目时用,clone是拿到一个已存在的项目时用。两者不冲突,你的绝大多数工作流程都会涉及这俩。
3.3 日常三连:add、commit、status
现在你在项目里创建了一个文件README.md,写了几行内容。当你准备“保存当前进度”时,需要执行:
git add README.md git commit -m "初始化项目,添加README"add是把改动放到暂存区,commit才是真正生成一个版本记录。-m后面的内容是本次提交的说明,这个说明非常重要。我看到太多人把提交信息写成“修改”“更新”“dev”,这种信息回头看毫无价值。好的提交信息应该回答“这次改动做了什么、为什么”,比如“修复用户登录时验证码过期问题”或者“优化首页图片懒加载,首屏速度提升20%”。
如果你想把所有改动一次性全部暂存(包括删除和新建的文件),可以用:
git add .但要注意,git add .会把当前目录下所有未暂存的改动全部加进去。如果里面有临时文件、编译产物、密钥文件,你就摊上大事了。所以更稳妥的做法是我后面要讲的.gitignore。
执行完commit后,强烈建议养成一个习惯:看一眼git status。
git status这个命令会告诉你当前工作区是否干净、哪些文件被修改过、哪些文件还在暂存区没提交。我工作这几年,git status是使用频率最高的命令,没有之一。
3.4 查看历史与差异:git log、git diff、git show
git log:查看提交历史。默认展示一串提交哈希、作者、日期和提交信息。git diff:查看工作区改动和暂存区/版本库之间的差异。git show:查看某一次提交时具体改了哪些内容。
如果你觉得git log输出的信息太冗长,可以试试:
git log --oneline --graph --all这个组合命令会以一行一条提交的方式展示历史,并且用图形化的分支线条展示分支合并关系,非常直观。我每次看仓库结构都会用这条命令。
git diff在使用时最常见的是两种场景:想看看改了但没add的内容,直接git diff;想看看已经add但还没commit的内容,用:
git diff --cached这些都是“只读”操作,不会对仓库产生任何破坏,你大可以随便敲。
3.5 .gitignore 是保命符
项目里总有一些文件是不该进版本库的,比如:
- 编译输出目录(
node_modules、dist、build) - 日志文件(
.log) - 系统文件(
.DS_Store、Thumbs.db) - 环境配置和密钥(
.env、*.pem)
你需要在项目根目录创建一个.gitignore文件,把需要忽略的路径规则写进去。一个简单的示例:
node_modules/ dist/ *.log .env .DS_Store.gitignore的作用是让 Git 自动忽略这些文件和目录,这样你执行git add .时就不会不小心把它们提交进去。这个文件本身应该提交到版本库,因为它对团队所有人都有用。
我踩过最大的坑就是项目早期没写.gitignore,直接把包含数据库密码的.env文件提交到了仓库。虽然后来删了,但历史记录里还留着,最后不得不花一个下午清理 Git 历史,还心惊胆战地怕密码泄露。所以,新建项目的第一步,先建.gitignore,永远是值得的。
4. 分支协作:多人在一个仓库里不打架的玩法
4.1 分支的本质:平行世界的副本
分支这个概念,听起来玄乎,其实可以理解成平行世界。你在主线(通常是main或master)上开发到一半,突然想尝试一个激进的新功能。你不想把半成品直接往主线上怼,免得队友拿到一个跑不起来的代码。这时候你就拉一个分支,在分支里随便折腾,成功了再合并回主线,失败了直接丢弃,对主线毫无影响。
分支在 Git 里非常轻量,创建分支就是创建一个指针,指向某个提交对象。这也是 Git 和 SVN 显著的差异点。
创建一个新分支并切换过去:
git branch feature-login git checkout feature-login或者一步到位:
git checkout -b feature-login现在你已经身处feature-login分支了,你在这个分支里的提交不会影响main。等你的开发完成,先切回main,再合并:
git checkout main git merge feature-login4.2 合并时遇到冲突怎么办
冲突是 Git 新人最害怕的场景,但它其实并不可怕。冲突的发生条件很明确:两个分支改了同一个文件的同一个位置,Git 不知道谁说了算,只能让你来决定。
我举一个真实的例子。你在feature-login分支里改了README.md,加了一句“这是一个登录功能项目”;同时同事在main分支也改了README.md,改成“这是一个电商项目”。你合并时会看到这样的提示:
Auto-merging README.md CONFLICT (content): Merge conflict in README.md Automatic merge failed; fix conflicts and then commit the result.打开README.md,你会看到类似这样的内容:
<<<<<<< HEAD 这是一个电商项目 ======= 这是一个登录功能项目 >>>>>>> feature-loginHEAD表示当前所在分支的内容,feature-login表示被合并分支的内容。你需要手动决定保留哪一边,或者两边都融合一下。编辑完后,删除掉那些<<<<<<<、=======、>>>>>>>标记,然后:
git add README.md git commit -m "解决README.md合并冲突"重点说一下,解决冲突的过程本质上就是你手动编辑文件的过程,Git 不会替你智能合并有争议的片段。它的“自动合并”能力仅限于两个分支改动不重叠的部分。
我实际工作中的体会:尽量减少冲突的最好办法是勤提交、勤合并、小步快跑。一个分支存活的时间越长,跟主线的分叉越大,合并冲突的概率就越高。
4.3 一个够用的分支策略:主干-功能分支模式
网上关于 Git Flow、GitHub Flow、GitLab Flow 的文章一抓一大把。对于小团队和大多数项目,我强烈推荐最简单的模式:
main:始终保持可发布状态,代码稳定,受保护,不允许直接推代码。feature/*:每个人从main拉出功能分支,开发完合并回去。
这样一个功能一个分支,一个分支对应一次合并请求,审查起来清清楚楚。至于更复杂的环境分支、发布时间线,等团队规模上来了再考虑也不迟。
4.4 远程分支:把分支推到远端
你本地创建了分支,同事是看不见的。要把分支推到远程仓库:
git push -u origin feature-login-u的作用是建立本地分支和远程分支的关联。以后你再在这个分支上执行git push或git pull,就不用再指定远程分支名了。
从远程拉取一个新分支并切换过去:
git fetch origin git checkout -b feature-login origin/feature-login或者用简写:
git checkout --track origin/feature-login这里我想特别强调fetch和pull的区别。git pull本质上是git fetch加git merge的组合。fetch只是把远程的更新下载到本地,但还没有合并到你的当前分支;pull则是直接下载并合并。如果你不确定远程更新会不会对你的当前工作造成冲突,可以用fetch先看看情况,再决定什么时候合并。
5. 进阶操作:后悔药、暂存与历史穿梭
5.1 git commit --amend 到底怎么用
这个命令是热搜词里点名出现的,估计不少人卡在这里过。
git commit --amend的作用是修改最近的一次提交。它的典型使用场景有三个:
第一个场景,提交信息写错了,想重新改一下:
git commit --amend -m "正确的提交信息"执行后,最近一次提交的信息就被替换成新内容了,提交哈希也会改变。
第二个场景,提交完发现漏掉了一个文件,或者某个文件没保存完全:
git add 漏掉的文件 git commit --amend --no-edit--no-edit的意思是保持原有提交信息不变,只把新暂存的内容并入前一个提交。这样你就不会为了补一个小文件而多出一个毫无意义的“fix typo”提交。
第三个场景,你想把前一次提交的内容整体重构一下,比如发现之前提交的代码有严重 bug,改完后又不想保留原来的提交记录,那也可以直接修改文件后git add .,再执行git commit --amend --no-edit。
但是,这里有一个极其重要的注意点:amend会改写提交历史。如果之前那个提交已经被你推送到了远程仓库,并且同事已经基于那个提交做了开发,你这时候amend再强推,历史就分叉了,同事拉取时会遇到一堆冲突。所以我的铁律是:只对还没有推送过的本地提交使用amend,已经推送到远程的提交,永远不要去编写历史。
万一你确实需要修改一个已经推送过的提交,流程是:本地amend后,用git push --force-with-lease强制推送。注意这里的--force-with-lease比裸的--force更安全,它会在推送前检查远程分支是否被其他人更新过,如果有人更新过就会拒绝推送,避免覆盖别人的工作。但这仍然只适用于你确认不会有其他人在该分支上工作的情况。
5.2 git stash:临时放下手里的活
你正在开发功能 A,改到一半,开发还没完成,不敢提交,因为一提交就是一个半成品。这时候突然来了个紧急 bug,需要你在当前分支上切换出去修。怎么办?
git stash就是为这个场景设计的。它的作用是把当前工作区和暂存区中的改动临时保存起来,让工作目录恢复干净。
git stash执行后你再git status,工作区是干净的。你可以放心切换到别的分支或者做其他事。等那边处理完了,回到这个分支,恢复你的改动:
git stash pop如果你存了多个 stash,想查看列表,用git stash list,恢复指定的一条用git stash pop stash@{1}。
git stash还有一个好用的参数-u:
git stash -u这个会把未跟踪的新文件也一起存起来。如果你不放心,推荐加上。
5.3 git reset:回退提交的三种模式
git reset可以让你把 HEAD 指向历史中的某个提交。它有三个模式,区别很大:
--soft:只移动 HEAD 的指针,不改变暂存区和工作区。相当于“软回退”,所有的变更都还在,而且都处于暂存状态,你可以重新组织提交。--mixed(默认):移动 HEAD 并重置暂存区,但不动工作区。改动还在工作区里,但暂存状态被清掉了。--hard:移动 HEAD,并且把暂存区和工作区都重置到目标提交的状态。这是一个破坏性操作,所有未提交的改动都会丢失。
举个例子,你连续提交了三次,发现第三次提交的内容根本不要了:
git reset --hard HEAD~1这条命令会让 HEAD 回到前一次提交的位置,第三次提交的内容就没了,工作区也同步回到那个状态。
特意说一下,--hard是非常危险的操作,它会把工作区中所有未提交的改动一并抹掉。我在早期对 Git 不熟时,用了reset --hard以为自己只是撤销提交,结果把一上午写的代码全弄丢了。所以如果你不确定,就先git stash或者备份一下当前工作区的文件。
5.4 git reflog:找到丢失的提交
如果你遇到过reset --hard之后后悔的痛点,git reflog就是解药。Git 会在本地记录所有分支指针的移动历史,包括你用reset、rebase、merge造成的各种变化,这些记录就是 reflog。
git reflog输出类似这样:
abc1234 HEAD@{0}: reset: moving to HEAD~1 abc5678 HEAD@{1}: commit: 完成登录功能如果你reset --hard HEAD~1后反悔了,想去回那个被丢掉的提交,只需要:
git reset --hard abc5678这样你就能重新回到那个提交。reflog是本地操作,不会推送到远程,但它确实是 Git 中“后悔药”的最后一道保险。我的体会是,操作reset和rebase之前先看一眼reflog,其实深呼吸一下就行了。只要你的提交在本地曾经存在过,reflog都能带你回去。
5.5 git cherry-pick 与 rebase:高级归并手段
git cherry-pick的作用是把某个分支上的一次提交“挑”到当前分支来。比如线上分支出了 bug,你在feature分支上修复并提交了,现在想把这次修复同步到main分支,却不想把整个 feature 分支合并过去,就可以在main分支上:
git cherry-pick <提交哈希>git rebase的作用是把当前分支的提交,重新“搬到”另一个分支的顶端,从而让提交历史保持线性。相对地,merge会产生一个合并提交,历史会有分叉。
我不建议新手一上来就用 rebase 去重写历史,但你可以先用一种很安全的场景:拉取远程更新时用 rebase 而不是 merge,这样你的本地提交会被“垫”在远程更新之后,历史保持一条直线:
git pull --rebase如果你已经习惯了这一套,再逐步探索交互式变基git rebase -i,它可以让你任意合并、修改、重排多个提交。这是 Git 最强大的功能之一,但也是最容易制造混乱的地方,操作前务必确认这是你的“私人分支”。
6. 远程仓库实战:以 Gitee 为例配置 SSH 密钥
6.1 为什么推荐用 SSH 方式连接
远程仓库的平台有很多,Gitee 是国内使用非常广泛的代码托管平台,对国内网络的访问速度和稳定性都有保证。在你把本地仓库和远程仓库联通的过程中,你会遇到两种协议:HTTPS 和 SSH。
HTTPS 方式的 URL 是https://gitee.com/user/repo.git,每次 push 拉取代码时都要输入用户名密码(或者个人访问令牌),虽然可以靠凭据管理器记住密码,但体验一般。SSH 方式是git@gitee.com:user/repo.git,只要配置好密钥,以后 push 拉取都不需要频繁输密码,更安全也更顺滑。所以,只要能配 SSH,我建议一律用 SSH。
6.2 生成 SSH 密钥并添加到 Gitee
第一步,在本地生成 SSH 密钥。打开 Git Bash(Linux/macOS 直接打开终端),输入:
ssh-keygen -t ed25519 -C "你的邮箱"这里的-t ed25519指定生成 ed25519 类型的密钥,这是目前比较推荐的安全算法,比传统的 RSA 更短更安全。执行后会出现交互提示,询问保存路径和密码短语。路径直接回车用默认的~/.ssh/id_ed25519就行;密码短语可空可设,如果设了,后续每次使用密钥时都要输入,不习惯的话可以直接回车留空。
生成完成后,你会看到两个文件:id_ed25519(私钥,留在本地,千万别外传)和id_ed25519.pub(公钥,可以分享给别人)。用命令查看公钥内容:
cat ~/.ssh/id_ed25519.pub把输出的一整行内容复制下来。然后登录 Gitee,点击右上角头像,选择“设置”,在左侧菜单里找到“安全设置”下的“SSH 公钥”,把刚才复制的内容粘贴到公钥框内,标题随便填一个,点击确定保存。
6.3 测试 SSH 连接是否成功
配置完成后,在终端里执行:
ssh -T git@gitee.com如果是第一次连接,会提示你确认主机指纹,输入yes回车即可。成功后会看到类似这样的提示:
Hi 用户名! You've successfully authenticated, but GITEE.COM does not provide shell access.看到这个提示,就说明 SSH 密钥配置成功了。
以后你在 Gitee 上新建项目时,选择 SSH 协议的地址克隆或关联,就不必每天重复录入密码了。
6.4 把本地仓库推送到远程仓库
在 Gitee 上新建一个空仓库(不要勾选“初始化仓库”里的任何选项),然后把本地仓库关联到远程:
git remote add origin git@gitee.com:你的用户名/仓库名.git把本地main分支推送到远程:
git push -u origin main之后每次推送,直接git push就够了。
如果你本地仓库还没任何提交,第一次推送之前记得先至少 commit 一次,否则会提示“Everything up-to-date”或者根本没有可推送的分支。我当年就踩过这个坑,建完远程仓库发现 push 不上去,排查了半天才发现本地连一次 commit 都没有。
6.5 SSH 配置常见报错与处理
- Permission denied (publickey):大概率是公钥没有正确添加到 Gitee,或者
ssh-keygen生成密钥时换了文件名,导致 Git 找不到默认的私钥。可以先执行ls ~/.ssh看看文件是否存在,再确认 Gitee 后台的公钥是否和本地id_ed25519.pub完全一致。 - Host key verification failed:这是因为本机没有信任对方的主机指纹。执行
ssh-keyscan -t ed25519 gitee.com >> ~/.ssh/known_hosts可以解决,或者删掉known_hosts里旧的 gitee.com 记录后重连。 - 多个 SSH 密钥共存:你公司 Gitee 和个人 GitHub 可能用了不同的密钥文件,这时需要在
~/.ssh/config里配置不同域名对应不同的私钥文件,否则 Git 只会默认找id_ed25519文件。
配置~/.ssh/config的大致格式:
Host gitee.com HostName gitee.com User git IdentityFile ~/.ssh/id_ed25519_gitee Host github.com HostName github.com User git IdentityFile ~/.ssh/id_ed25519_github这个文件能给你的多账号 SSH 场景省下不少心,推荐早点了解一下。
7. 常见问题与排查技巧实录
7.1 中文文件名变成转义序列怎么办
很多 Windows 用户在 Git 状态或输出里看到中文文件名显示成\346\265\213\350\257\225.txt这种八进制转义序列,非常头疼。这是因为 Git 默认会对非 ASCII 文件名进行转义。解决办法是关掉这个转义:
git config --global core.quotepath false这个配置也是热词“git -c core.quotepath=false”出现的原因。在命令行里敲git -c core.quotepath=false status也能临时生效,但一次性的参数不能永久改变行为,所以我建议直接用git config --global core.quotepath false设置一次,一劳永逸。设置完后,中文文件名就能正常显示了。
7.2 amend 之后远程被拒怎么办
我前面说过,不建议对已推送的提交做amend。如果你已经犯了,推的时候报错:
! [rejected] main -> main (non-fast-forward)这说明远程和本地历史不一致了。如果你确认远程分支只有你自己在用,没有人基于旧提交做工作,可以强推:
git push --force-with-lease但要记住,这个操作覆盖的是远程的提交历史,如果你误操作会严重影响团队成员。所以强推之前一定要和团队确认,或者干脆在功能分支上用这个方法,永远别在公共主干上轻易改写历史。
7.3 执行 git add 后想撤销怎么办
你执行了git add,把文件加入了暂存区,突然发现这不是你想提交的文件。不用慌,用:
git reset HEAD <文件路径>这个命令会把文件从暂存区移回到工作区,但文件内容不变。在旧版 Git 中常用git reset HEAD来实现,新版 Git 更推荐:
git restore --staged <文件路径>这两种方式效果一样,选一个你看着顺眼的使用即可。
7.4 合并时提示 refusing to merge unrelated histories
这个报错通常出现在你本地仓库和远程仓库都有自己的独立提交历史,且互不关联时。比如你在 Gitee 上新建了空仓库,但本地也先做了 init 和提交,这时候去 pull 远程就会报这个错。
解决方法是在 pull 或 merge 时加一个参数:
git pull origin main --allow-unrelated-historiesGit 会把两个不相干的历史强行合并在一起,但接着一般会出现冲突,你需要手动解决。最简单的方式其实是避免这种情况:新建远程仓库时不要初始化任何文件,或者本地直接用 clone 方式来获取远程仓库。
7.5 换行符警告:LF will be replaced by CRLF
在 Windows 上使用 Git 时,你可能会见到这样的警告:
warning: LF will be replaced by CRLF这是因为 Windows 系统默认行尾是CRLF,而 Linux/macOS 是LF。Git 在提交时会把文件统一成LF存到仓库,而在 Windows 检出时再转成CRLF,所以提示“LF will be replaced by CRLF”实际上是在告诉你换行符策略正在生效。大多数情况下,这个警告可以直接忽略,不会对项目造成实质影响。
如果你实在不喜欢,可以设置:
git config --global core.autocrlf false但这可能导致跨平台协作时出现大量换行符差异的 diff,推荐普通用户还是保持默认配置。
7.6 文件删除后怎么恢复
误删文件是每个人都会遇到的情况。如果你还没执行git commit,可以直接:
git checkout -- <被删除的文件>这个命令会用暂存区(或当前 HEAD)中的版本恢复文件。如果你已经提交过,甚至删除了之后还提交过一次,那就需要找到没有删除文件的那个提交,然后从那个提交中恢复:
git restore --source=<提交哈希> -- <被删除的文件>这也是 Git 的威力——只要你的操作留下了提交记录,大多数误删误改都能找回。
7.7 为什么明明改了文件,git status 却提示无变化
这种情况一般在大小写改名时出现。Windows 和 macOS 默认文件系统不区分大小写,你把readme.md改成README.md,Git 可能完全感知不到变化。解决方法是让 Git 自己识别重命名:
git mv readme.md README.md如果已经改乱了,也可以临时设置git config core.ignorecase false来让 Git 更敏感地追踪大小写,但这个配置对已有改动不一定能自动生效,最稳妥的方式还是用git mv来执行文件名变更。
最后再分享一个实用的小习惯
我个人实际工作中,Git 用得越久,越觉得真正提升效率的未必是最复杂的命令,而是一些微小的习惯。比如每次敲完git commit后,我都会顺手跑一次git log --oneline -3确认一下刚才的提交信息没写错;每次git push前先git fetch,看一眼远程有没有新提交,能避免不少冲突。
还有一个我认为价值极高的习惯:提交信息不要只写“update”,而是把这个改动的前因后果用一两句话写清楚。三个月后你再回来看历史,会深深感谢当时那个认真写提交信息的自己。这些细节看着不起眼,积累起来,就是你和别人协作时最大的“效率杠杆”。
如果你刚开始接触 Git,不需要把上面所有内容一次性记下来。先把add、commit、status、log、push、pull这六条命令跑熟,再把分支和合并用利索,你就已经能覆盖日常 90% 的工作场景了。剩下的,都是遇到问题再回来翻的“武器库”,随时都能用得上。