很多刚开始接触Linux的朋友,都会卡在同一关:系统装好了,终端能进能出了,但一说到代码版本管理,下意识还是想找个图形界面。其实Git在Linux里才是真正的主场,命令行下这套设计逻辑反而比在Windows下面更自然。这篇文章我不讲虚的,就从Git在Linux下的安装、首次配置、日常命令、分支合并、远程仓库、常用避坑技巧这几个方面,把整个工作流串起来,所有命令都会说明为什么这么写,以及哪些坑是教程里不会提醒你的。
适合两类人看:一类是刚在虚拟机上装了Linux、准备开始正经写代码的新手;另一类是已经会敲几条git命令、但遇到报错就只能去搜索、心里没底的开发者。读完之后,你至少能独立完成“装好Git、配好环境、日常提交、开分支合并、连远程仓库免密push/pull”这一整条链路。
1. 装Git之前要想清楚的事:用包管理器还是源码编译
1.1 apt/yum/dnf:90%情况下的最快路径
Linux发行版虽然多,但安装Git这件事在绝大多数发行版上就是一条命令的事。Debian/Ubuntu系用apt:
bash复制sudo apt update
sudo apt install git -y
RHEL/CentOS/Rocky Linux这类用yum或dnf:
bash复制sudo yum install git -y
# 或者新版系统上
sudo dnf install git -y
推荐优先用包管理器,理由有三个。第一,依赖处理不用操心,编译Git需要的openssl、zlib、curl这些库,包管理器会一并装好;第二,安装位置和系统保持统一,将来卸载只需要一条remove命令;第三,会附带安装bash补全脚本,你在终端敲git时按Tab能自动补全子命令和参数,这个体验对新手来说非常重要。另外,刚装好的虚拟机会遇到一个小坎:apt update偶尔会因为软件源列表初始化不完整或者网络配得不对而下不动。这种情况不用慌,检查一下虚拟机网络是否正常,或者把软件源列表更新到可用状态再重试即可。
有些发行版的仓库里Git版本偏老,比如某些长期支持版的Ubuntu可能还停留在2.x中段版本。如果你只是学习基本用法,仓库里的版本完全够用,没必要追新。真需要比较新版本的时候,可以在Ubuntu上通过官方Git维护的PPA源来装,具体这里不过多展开。
1.2 源码编译:什么时候值得自己来
源码编译安装Git的场景其实很特定:比如发行版仓库里的Git版本实在太老,某些新功能用不上,或者你需要特定编译参数。对普通学习使用来说,源码编译性价比很低,因为要先把一堆编译依赖装齐,再经历configure、make、make install这整套流程,中途任何一个依赖缺失都会报错。
如果确实需要,大致流程是这样的:先用包管理器安装编译依赖,Debian系大概需要gcc、make、autoconf、libcurl4-openssl-dev、libexpat1-dev、gettext、libssl-dev、zlib1g-dev这些;然后去Git官网下载对应版本的源码包,执行:
bash复制tar -zxvf git-2.x.x.tar.gz
cd git-2.x.x
./configure --prefix=/usr/local
make
sudo make install
编译完成后,git会装到/usr/local/bin下。如果系统自带的git还在,注意看which git指向哪里,必要时调整PATH顺序,或者干脆把系统自带的卸载掉,避免同一台机器上出现两个版本混用。
1.3 装完先别急:确认版本与命令补全
装完之后用git --version确认一下版本号,能正常输出就说明安装成功。顺手再执行git,不带任何参数,会打印出所有常用命令列表,这本身就是一个很好的速查手册。在虚拟机里装Linux的朋友要格外注意一件事:某些精简版的服务器系统默认没有装bash-completion,这时候git --version正常,但按Tab不会补全命令。装一下bash-completion,然后重新加载bash配置,补全就回来了:
bash复制sudo apt install bash-completion -y
source /etc/bash_completion
这一步很不起眼,但实际体验差距巨大。我见过太多人因为Tab补全失效,以为是自己Git没装好,折腾了半天后发现只是系统缺了一个补全包。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 第一次配置Git:四个global设置帮我省了后面太多事
2.1 不配姓名和邮箱,第一次commit就会报错
装完Git马上就能用吗?能,但第一次提交commit时你一定会被拦下来。Git会报一段很具体的错误:Please tell me who you are,然后提示你设置user.name和user.email。这一步绕不开,因为每次提交记录里都必须有作者信息,这是Git设计里最基本的要求。这个配置在终端执行起来极其简单,就两条命令,放进去之后Git会在你当前用户下的配置文件里写入对应键值:
bash复制git config --global user.name "Your Name"
git config --global user.email "you@example.com"
理解一下这里的三层作用域:--system影响整台机器所有用户,--global影响当前登录用户,--local只影响当前仓库。平时几乎只用--global,个别仓库想用不同身份时(比如公司仓库用公司邮箱),在仓库目录下不加--global设置一次,local配置会覆盖global。
有个细节值得注意:email并不强制校验真伪,但强烈建议和你在Git托管平台(比如GitHub、GitLab、Gitee)上绑定的邮箱保持一致。否则你提交的代码推送到远程后,头像和个人主页不会关联到你的账号,团队别人看提交记录也认不出是谁。我见过不少人因为当时随手填了个邮箱,后面发现所有历史提交都归属在陌生人名下,改起来非常麻烦。
2.2 core.quotepath与换行符配置:中文路径和跨平台文件不乱的秘密
第二个容易踩的坑是中文文件名和中文路径。Linux终端下中文显示没问题,但git status和git log里一旦出现中文字符,默认会显示成转义后的八进制编码,像“\346\x96\x87\xe4\xbb\xb6”这样一串,非常影响阅读。解决办法是设置:
bash复制git config --global core.quotepath false
这个配置的含义是不要对非ASCII字符做路径转义。设置完之后,中文文件名在git输出里就能正常显示了。
再一个是换行符问题。Linux下文件用LF,Windows下用CRLF。如果你只是一个人在Linux上开发,文件里全是LF,没有争议。但如果你参与的项目里有人用Windows,他的编辑器或Git可能会把换行符改掉,导致git diff里出现整文件变红变绿的假差异。在团队项目里,最规范的解法是在仓库根目录维护一个.gitattributes文件,统一声明各类文件的换行符规则。个人学习场景下,保持默认即可,但要知道有这回事,别等遇到诡异的diff时才瞎猜。
2.3 别名:把status/checkout这类高频命令压缩成一个词
Git本身命令不长,但叠加参数之后就啰嗦了。我建议一开始就把高频操作的别名配好,养成习惯后每天能省下大量无意义输入。以下是我用了很久的一组:
bash复制git config --global alias.st status
git config --global alias.co checkout
git config --global alias.ci commit
git config --global alias.br branch
git config --global alias.lg "log --oneline --graph --all --decorate"
配完之后,git st、git co、git lg都能直接用。尤其那个lg别名,输出一页带分支图和时间线的提交历史,可读性比默认的git log强很多,我后来基本不用原版log命令了。别名不改变命令行为,只是把长串命令缩短,所以放心用。查看已经配置的global设置,执行git config --list --global,改错了用git config --global --unset 键名删掉再配就行。
3. 本地仓库一天到晚在用的命令:理解暂存区后一切都顺了
3.1 init、add、commit背后的工作区/暂存区/版本库逻辑
新手学Git最容易懵的地方,是明明只记了几个命令,却怎么也搞不清它们之间的关系。根子在于没有理解Git把仓库分成了三个区域:工作区就是你眼前的文件目录;暂存区(也叫索引)是你用git add放进去的一批待提交内容;版本库是每次commit生成的完整历史快照。
用个生活类比:工作区是写字台,文件散落在桌上;暂存区是打包箱,你往里放东西,但箱子还没封口;commit是封箱上架,一旦上架,这个箱子的内容就永远记录在案了。
回到你的项目目录,执行git init,初始化动作在这一秒就完成了:
bash复制git init
这条命令会在当前目录创建.git隐藏目录,这个目录就是版本库本体。之后新建和修改文件都在工作区,git add把文件纳入暂存区,git commit把暂存区内容固化成一次提交。这三个命令的链路,覆盖了本地单人开发90%的动作:
bash复制git add file.txt
git add . # 添加所有改动
git commit -m "提交说明"
注意commit不加-m会打开编辑器让你写提交说明,新手经常卡在vim里不知道怎么退出。建议一次性养成写-m参数的习惯。
3.2 status、diff、log:怎么看清仓库里正在发生什么
三个查看类命令组成了日常巡检主力。git status告诉你当前处于什么状态,哪些文件改过、哪些已暂存、哪些还没被Git跟踪。刚上手时建议用完整输出,信息详细;用熟了可以试试git status -s,每行一个文件,紧凑利落。
git diff看具体改动内容。直接git diff比较的是工作区和暂存区的差异,也就是你改了但还没add的部分;git diff --staged比较的是暂存区和版本库的差异,也就是你add了但还没commit的部分。搞清这两个方向,就不会出现“我明明改了怎么diff里什么都没有”的困惑。
git log看提交历史。基础用法是git log --oneline,每条提交一行,只显示简短哈希和提交说明。想看得更细就加--stat看每个提交改了哪些文件、--author "名字"按作者筛选、-n 5只看最近5条。日志是你复盘代码演进的唯一线索,养成每次提交说明都写清楚的习惯,比会再多命令都值钱。
3.3 回滚与恢复:restore、reset、reflog的区别与使用边界
改错代码想回退,是新手问得最多的问题。Git的回滚工具不少,但每个都有明确边界。文件级别的操作,优先用restore。git restore --staged file可以把已暂存的文件退回到暂存前的状态,就是取消add;git restore file可以把工作区里未暂存的改动直接恢复到上次暂存的版本。注意restore文件改动是破坏性的,执行前想清楚,没有后悔药。
提交级别的回退用reset。git reset --soft HEAD~1回退一次提交但保留改动;--mixed(默认)回退提交并取消暂存;--hard回退提交且清空所有改动。实战中--soft用于“刚提交完发现漏了文件,想补进来重新提交”,--hard用于“彻底抛弃最近这几条提交”。但记住一条铁律:不要对已经推送到远程、且别人可能拉取过的提交执行reset --hard,这会破坏协作者的本地历史。
万一真的误操作了,还有个兜底工具reflog:
bash复制git reflog
reflog记录了HEAD指针最近的一切移动,包括reset、checkout、merge。即使你reset --hard丢掉了一次提交,也能在reflog里找到那个提交的哈希,再用git reset --hard 哈希救回来。这也是我为什么劝新手别怕犯错,Git的恢复能力远比想象中强。
4. 分支合并这件事:从一个人单干到多人协作的关卡
4.1 创建和切换分支:其实分支只是一个会移动的指针
很多人把分支想象成一个目录,这是最常见的认知偏差。分支本质上只是一个指向某次提交的指针,创建分支就是创建新指针,切换分支就是让HEAD这个“当前分支指针”指向另一个分支。创建和切换分支非常轻快,这也是Git鼓励多开分支的原因。
bash复制git branch feature # 创建feature分支,指向当前提交
git switch feature # 切到feature分支
git switch -c feature2 # 直接创建并切换,等效于上面两条
如果系统Git版本较老不支持switch命令,用git checkout -b feature2效果一样。切分支之后做的commit会自动落在feature2这条指针上,main分支原地不动。实际经验是,哪怕是自己一个人写项目,也建议把功能开发放在独立分支上,主干main只保留可用状态。这样每个功能可以独立提交、独立回退,main随时都是干净的。养成这个习惯之后,你再和同事协作,就只需要操心合并,不用操心互相覆盖。
4.2 合并冲突长什么样,以及怎么一步步处理
多人协作后,git merge给你制造的第一个麻烦就是冲突。冲突的本质是:在两个分支上,同一文件同一个位置被不同提交改出了不同内容,Git无法替你裁决,只能把选择权交给你。
冲突发生时,git status会列出冲突文件,文件边上有both modified的标记。打开任意冲突文件,会看到类似这样的内容:
text复制<<<<<<< HEAD
专辑:Git入门
=======
专辑:Linux下的Git实操
>>>>>>> feature
<<<<<<< HEAD和=======之间是当前分支的版本,=======和>>>>>>> feature之间是被合并分支的版本。你要做的不是删掉这些标记就完事,而是真正读代码、决定保留哪边、两边都留还是改成第三种写法。改完之后删掉三行标记,然后:
bash复制git add 冲突文件
git commit
Git会用你暂存的内容生成合并提交,冲突就算解决了。新手最容易犯的错有二:一是看到冲突就懵,来回切分支想把改动弄丢;二是直接git merge --abort放弃合并,把已经手动解决一半的内容全丢掉。我的建议是,冲突出现先深呼吸,它是正常且频繁的事,解决一次之后你对Git的理解会上一个台阶。
4.3 merge还是rebase:新手先记住这条原则
合并分支有两条路线。merge会把两个分支的历史汇合起来,生成一个合并节点;rebase会把当前分支的提交一个个重新应用到目标分支之上,历史变成一条直线。
bash复制git merge main
git rebase main
对新手,我心里有一张很清楚的决策表:只在本地、还没推送到远程的分支,嫌历史线杂乱的时候可以rebase main,让提交记录更整洁;已经推送到远程、别人可能拉取过的分支,一律merge,不要rebase。原因很简单:rebase会改写提交哈希,改写别人已经基于其开发的提交,会让协作者的仓库历史出现分叉混乱。这条原则记住一条就够应付绝大多数场景:共享分支不rebase,本地分支随意。
5. 远程仓库实操:clone、push、pull和免密登录
5.1 HTTPS还是SSH:两种远程连接方式怎么选
把本地仓库和远程平台接起来,本质是选传输协议。第一次接触远程仓库的人,常被clone时的两个地址搞晕。HTTPS地址形如https://github.com/user/repo.git,SSH地址形如git@github.com:user/repo.git。
两条路线的体验差别在于认证方式。HTTPS每次push大概率要向你要用户名和密码,现在主流平台还普遍改用token代替密码,记起来更麻烦;SSH走密钥对,公钥放在平台账号里,私钥留在本机,配置好之后push和pull全程无感,不需要二次输入。我的建议很直接:如果你打算长期用一台Linux机器和远程仓库打交道,花十分钟配一次SSH,收益是之后每次push都省掉认证环节。如果只是临时拉一次别人的代码看看,HTTPS地址直接clone也不损失什么。
5.2 SSH免密从生成密钥到测试连通的一整套操作
先在Linux机器上生成密钥对:
bash复制ssh-keygen -t ed25519 -C "you@example.com"
一路回车会在~/.ssh目录下生成id_ed25519(私钥)和id_ed25519.pub(公钥)。想更安全可以设置一个密钥密码,只是之后每次使用会多一步解锁。然后让SSH代理记住密钥,并把公钥内容复制出来:
bash复制eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
cat ~/.ssh/id_ed25519.pub
复制公钥输出,粘贴到Git托管平台的SSH Keys设置页面里就行。不同平台入口名称略有差异,一般在个人设置的SSH and GPG keys或安全设置里。
配完公钥之后别急着push,先用一条命令确认整个链路是通的:
bash复制ssh -T git@github.com
首次连接会问是否信任主机,输入yes,确认后如果看到账号欢迎信息,说明免密配置成功。这里有个Linux下特别常见的坑:~/.ssh目录权限不对,SSH客户端会直接拒绝。私钥文件要求只有自己可读写,目录要求只有自己可进,执行:
bash复制chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
这也是很多人在网上复制了一堆教程步骤后依然连接失败的最大原因。配好之后,之前用HTTPS克隆下来的仓库可以直接把remote地址改成SSH形式:
bash复制git remote set-url origin git@github.com:user/repo.git
5.3 push被拒绝怎么办:先pull再push的正确姿势
初次push就能成功的体验当然最好,但很快你会碰到这个经典报错:
text复制! [rejected] main -> main (fetch first)
error: failed to push some refs to ...
Updates were rejected because the remote contains work that you do not have locally.
报错信息已经把原因说清楚了:远程仓库有你本地没有的提交。比如在网页上直接改过文件,或者同事push了新代码,你的本地历史落后了。这时候硬把本地代码推到远程是不行的,因为Git保证历史不能凭空覆盖。
正确处理是先拉取再推送:
bash复制git pull --rebase origin main
git push origin main
--rebase的意思是把本地高出远程的那些提交,重新接到远程最新提交的后面,让历史保持线性。如果拉取过程中又产生冲突,处理方法跟前面讲的分支合并冲突完全一样。如果远程仓库默认分支叫master而不是main,把命令里的分支名换掉即可。还有一个危险选项git push --force,它的意思是强行让远程分支指向本地提交,无视差异。只建议在确定自己的本地是唯一合法版本、且没有任何其他人会受影响时使用。新手阶段默认不要碰它。
6. 日常避坑补充:.gitignore、stash和后续学习建议
6.1 .gitignore生效的逻辑:忽略规则与已跟踪文件的区别
仓库里总有一些不该进版本库的东西:编译产物、日志、临时文件、本地环境配置。老手不用特意清理,因为项目根目录有个.gitignore文件在起作用。它的规则很简单,每行一个忽略模式,支持通配符:
text复制*.log
*.class
build/
dist/
.env
.DS_Store
.idea/
理解.gitignore有一个关键点:它只对尚未被Git跟踪的文件生效。如果一个文件已经通过git add进了版本库,之后你再把它写进.gitignore,Git仍然会继续跟踪它。想让这类文件彻底不再被跟踪,要先把它们从索引里移除:
bash复制git rm --cached 文件名
--cached参数只移除索引记录,不删磁盘文件,执行后git status里该文件会显示为deleted,你把它写进.gitignore然后commit一次,此后这个文件就不再被跟踪了。整个过程不加--cached的话,会直接删除物理文件,遇到过我估计都记得那股酸爽。
6.2 stash暂存与log查看:两个切换场景里的实用工具
场景:你在feature分支写到一半,需要立刻切回main修复一个紧急问题,但手头这些改动还没到可以提交的程度。commit掉吧,提交信息都不好写;直接切分支吧,又会带着未提交的改动过去,容易混乱。git stash就是为这个场景准备的:
bash复制git stash # 把当前未提交的改动暂存起来,工作区回到干净状态
git stash list # 查看暂存列表
git stash pop # 恢复到最近一次暂存,并从暂存栈移除
stash就像一个临时收纳盒,可以存多批改动,按栈的顺序进出。注意pop可能因为和当前文件的改动冲突而失败,到时手动处理一下就行。
log这边还有两个高频场景:想知道某个人最近改了什么,git log --author="名字" --oneline -n 10;想知道某次提交具体动了哪些代码,git show 提交哈希直接看完整diff。把log、show、diff这三件套用好,你在团队里查问题时的效率会明显高于靠记忆猜代码的人。
6.3 从“简单使用”往上走:自建仓库与整洁提交习惯
把这一整套本地+远程流程跑通之后,你已经超过了大多数只会图形工具的用户。再往上走,值得做的方向有几个。一是自建一个类似GitHub的个人远程仓库。在服务器上找个目录执行git init --bare repo.git,然后本地加一个SSH协议的remote地址往里push,就拥有了一台私有Git服务器。这个玩法不仅是练手,还能让你理解远程仓库和普通工作区仓库的本质区别:bare仓库没有工作区,纯粹存放历史,所以不能被直接拿来改代码。
二是提交习惯的打磨。一次提交只做一件事,提交说明用一句话讲清楚“改了什么、为什么改”。这两点坚持几个月,你会体会到代码审查和历史追溯时的巨大便利。Git的命令再多,最后真正决定协作效率的,反而是这些看起来没那么技术的习惯。
最后分享一点我自己刚过渡到Linux命令行Git时的体会:不要急着背命令,先花半小时把工作区、暂存区、版本库以及分支指针这几个概念弄透彻,后面遇到任何报错,你都能顺着这个模型先自己推一遍。Git的报错信息写得非常诚实,它告诉你的每一次拒绝都是有原因的。先读报错,再决定搜什么,最后动手解决,这套流程跑顺之后,你会发现Git从一个需要“学习”的工具,变成了一件自然到几乎忘记它存在的事。
