1. 为什么先解决SSH免密:HTTPS口令认证的日常痛点
先说个很实际的场景。用Gitee拉代码、推代码,很多新手默认走HTTPS地址,因为复制起来方便、看着也直观。但用上一个月,你大概率会烦透一件事:每次git push都要输用户名和密码,甚至每个仓库都要输一遍。有的人为了省事,把密码记在系统凭据管理器里,换台电脑又得重新配;有的团队在服务器上拉代码,没法交互式输密码,CI直接卡死在认证这步。
我当初从HTTPS切到SSH,其实不是因为Gitee强制要求,纯粹是有一天连续推送了七八个仓库,输密码输到怀疑人生。后来花十分钟把SSH免密配好,整个人都清爽了。这也是一切后续操作的基础——如果你连推代码都要频繁输密码,做分支合并的时候心态很容易崩,因为每次操作都在打断思路。
1.1 SSH密钥对的工作原理
SSH免密的核心是非对称加密,简单说就是一对钥匙:公钥和私钥。公钥可以随意公开,私钥必须自己收好。
类比一下就是一把锁和一把钥匙的关系。你把锁(公钥)挂在Gitee服务器上,你自己拿着钥匙(私钥)。每次你要跟服务器通信,服务器用那把锁验证:你能证明自己持有匹配的钥匙,就让你进门;验证不通过,门就锁着。
具体到技术层面,Git客户端发起SSH连接时,会先向服务端出示自己的公钥指纹,服务端查到自己记录里有这把公钥,就生成一个随机挑战用公钥加密发回来。客户端用私钥解密后返回约定的响应,服务端确认后认证通过。整个过程中,私钥始终不出本地机器,所以比密码传输安全得多——密码在网络上传输有被截获的风险,私钥不参与网络传输。
1.2 HTTPS与SSH的对比选择
HTTPS方式走的是账号密码或令牌认证,443端口几乎不会被防火墙拦,这是它的优势。但代价就是每次操作都要认证,虽然新版Git可以配置credential helper缓存凭据,但在Linux服务器、CI环境里还是会遇到非交互场景的麻烦。
SSH方式走22端口,配置好之后一劳永逸,推送、拉取、fetch都不再需要任何交互。唯一需要注意的是,某些企业内网会封22端口,这种情况下可以改用SSH over HTTPS(默认走443)。Gitee官方文档里有这块说明,遇到连接超时的时候值得试一下。
我的建议是:个人日常开发优先走SSH;如果你所在的网络环境对22端口不友好,再退回HTTPS方案,配合凭据存储也能凑合用。但正常的开发机,SSH一定是第一选择。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 完整配置流程:从生成密钥到连通性测试
2.1 密钥生成与算法选型
打开终端,直接执行:
bash复制ssh-keygen -t ed25519 -C "你的备注信息"
这里用ed25519而不是传统的rsa,原因有两个。第一,ed25519密钥更短、生成更快、安全性不低于2048位的RSA;第二,Gitee和GitHub现在都原生支持ed25519,老旧的RSA密钥没必要再用了。如果你的Git版本比较老,或者需要兼容非常旧的服务器,才考虑用:
bash复制ssh-keygen -t rsa -b 4096 -C "你的备注信息"
-C后面的备注信息只是给你自己看的,通常会写邮箱或者机器名,方便以后在多个密钥里区分哪个对应哪台设备。生成过程中会问你要不要把密钥存到~/.ssh/id_ed25519,默认直接回车就好;然后会问是否设置passphrase,这里我的建议是:本地个人电脑可以不设,但如果你的笔记本经常带着跑,设一个也不亏,只是每次用密钥时要输一次口令而已。
2.2 部署到Gitee平台的步骤
密钥生成完毕,你的~/.ssh目录下会有两个文件:id_ed25519是私钥,id_ed25519.pub是公钥。查看公钥内容:
bash复制cat ~/.ssh/id_ed25519.pub
把输出的一大串字符串完整复制下来,然后登录Gitee网页端:
- 点击头像,进入个人设置。
- 左侧菜单找到“安全设置”里的“SSH公钥”页面。
- 标题随便填一个,比如“我的办公电脑”,公钥内容粘贴进文本框。
- 确认添加。
添加完毕之后先别急着clone,先验证连通性:
bash复制ssh -T git@gitee.com
第一次连接会提示确认主机指纹,输入yes回车即可。如果一切正常,你会看到一段欢迎语,大意是“你已经通过SSH认证”。看到这个,配置就算完成了。
2.3 常见坑:权限、多密钥、SSH复用
第一个坑是权限问题。SSH对私钥文件的权限很敏感,如果~/.ssh目录权限太宽松,SSH会直接拒绝使用这个密钥。Linux和macOS下执行:
bash复制chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
Windows用户一般不用管这个,Git for Windows安装时基本处理好了。
第二个坑是多密钥冲突。如果你同时用Gitee和另一个Git平台,或者在不同平台用了不同密钥,SSH默认只读id_ed25519这一对,别的密钥不认。解决办法是在~/.ssh/config文件里配置Host别名:
bash复制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会自动按Host名匹配,不会串。
第三个坑是Agent缓存。有些环境下配置了ssh-agent,私钥需要手动加进去才能免密生效:
bash复制ssh-add ~/.ssh/id_ed25519
如果你重启电脑后发现免密失效了,十有八九就是ssh-agent没加载密钥,重新ssh-add一次就好。
3. 分支管理的基本功:创建、切换、删除的正确姿势
SSH免密配置好之后,分支操作才真正称得上行云流水。每次切分支、拉远程都不需要再输入密码,你可以把全部注意力放在分支本身。
3.1 分支的本质理解
分支在Git里其实是一个指针,指向某条提交记录。你创建分支、切换分支,本质上就是在移动这个指针,代码文件本身不会复制多份。
很多人第一次用分支会觉得抽象,我当初的理解方式是:把分支想象成贴纸,贴在某个提交上。你在这个分支上做了新提交,贴纸就自动往前挪;你切回主分支,主分支的贴纸还停留在原来的位置。分支之间互不干扰,等到完成一个功能后,再把两条线重新汇合。
理解了这一点,你就明白了为什么Git切分支这么轻快——它不需要把代码复制来复制去,只是换了个指针,然后更新工作区文件而已。
3.2 常用分支操作命令清单
Gitee上建仓库时,默认分支通常叫master(也可以设置成main),这里我以master为例说。
创建分支的标准组合是:
bash复制# 基于当前分支创建并切换
git checkout -b feature/login
# 新版Git推荐的写法
git switch -c feature/login
我个人习惯用git switch -c,语义更清楚,checkout历史上承担了太多职责,一会儿切分支一会儿恢复文件,新手容易看晕。
切换分支:
bash复制git switch feature/login
查看所有分支,包括远程的:
bash复制git branch -a
删除本地分支:
bash复制# 已合并的分支
git branch -d feature/login
# 强制删除(未合并但确定不要了)
git branch -D feature/login
删除远程分支:
bash复制git push origin --delete feature/login
这里有个细节:删除本地分支时,如果分支上有尚未合并的提交,Git会拦你一下,提示not fully merged,这是防止你误删工作成果的保护机制。你真的确定不要了,再用-D强删。这个设计很良心,别嫌他烦。
3.3 远程分支与本地分支的同步关系
本地分支和远程分支不是自动同步的。你第一次把本地分支推到远程要指定上游:
bash复制git push -u origin feature/login
-u参数的意思是“记住这条分支对应的远程分支”,以后直接git push和git pull就不用再带参数了。
拉取远程的新分支到本地:
bash复制git fetch origin
git switch feature/login
现在的新版Git会在git switch时自动识别远程分支并建立跟踪关系,非常方便。
需要提醒的是,git pull默认执行的是fetch加merge,如果远程分支被别人推进了新提交,你本地的这个分支又有了自己的提交,pull的时候会产生一次合并提交。想要更线性的历史,可以用git pull --rebase,但要注意rebase的规则,这个放到下一节细说。
4. 合并的完整链路:Fast-forward、三方合并与冲突处理
分支的存在的意义是并行做事,但最终要合到一起,所以合并是绕不开的。这个环节出问题最多,也最能体现一个人对Git的理解深浅。
4.1 两种合并模式的底层区别
合并有两条路:merge和rebase。
先看merge。merge会找两个分支的共同祖先,然后把这个祖先之后的两边改动都合并起来,生成一个专门的合并提交。如果两个分支上改的是不同文件,那合并过程很顺滑,Git自动处理;如果改了同一个文件的同一片区域,就产生冲突需要手动解决。
Fast-forward是merge的一种特殊形式。当你的主分支从创建分支之后没有产生新的提交,合并时Git只需把主分支的指针往前拨到功能分支的顶端,不需要生成合并提交,历史就是一条直线。很多团队在合功能分支时加--no-ff参数,强制生成一个合并节点,就是为了保留“这里曾经发生过一次合并”这个信息,方便回溯。
rebase则是另一种思路。它不是把两条线并起来,而是把你当前分支的提交“重新播放”到目标分支的最新提交之上。效果是历史变成单线,看起来像是这个功能分支就是直接从主分支最新位置长出来的。
4.2 冲突发生时的完整处理流程
冲突是所有人都会遇到的事,不用怕,关键是流程要对。
比如你在feature/login分支上改了login.py的第三行,主分支上另一个同事也改了同一行。合并时:
bash复制git switch master
git merge feature/login
Git会报出冲突,并用特殊标记标出冲突区域:
text复制<<<<<<< HEAD
这里是主分支上的代码
=======
这里是功能分支上的代码
>>>>>>> feature/login
处理步骤是:
- 打开冲突文件,仔细看两边的改动,理解双方意图。
- 改成一个双方都能接受的结果,把
<<<<<<<、=======、>>>>>>>这些标记全部删除。 - 逐个文件处理完后,
git add标记为已解决。 - 最后执行
git commit完成合并提交。
如果你改到一半发现不对,想回到合并前状态:
bash复制git merge --abort
这个命令会把你恢复到你执行merge之前的样子,缩回去重来。新手多试几次就知道这是个安全网,别怕用它。
强烈建议在解决冲突时不要只靠眼睛看,我一般会开可视化编辑器。VSCode里自带三路合并视图,左右分栏显示“当前分支”和“收入分支”,中间是你的合并结果,点一下就能选用哪边的代码。比在终端里对着<<<<<<<猜来的高效得多。命令行工具里meld、kdiff3也都是老牌的合并工具,装好之后在.gitconfig里配一下merge.tool就能用。
4.3 rebase与merge的选择标准
这个问题在社区吵了很多年,我的态度很明确:功能分支合回主分支,用merge;个人功能分支同步主分支的新代码,用rebase。
举例说明。你在feature/login分支上写了两天,主分支上游同事合并了三个新功能,你的功能分支已经落后了。这时候你想让功能分支拿到底层的最新代码,避免最后合并时冲突爆炸,就在功能分支上:
bash复制git switch feature/login
git fetch origin
git rebase origin/master
这样你之前的提交会按顺序重新应用在origin/master最新提交之上,之后再把功能分支合回主分支,就是一次干净的快速前进。
但不要对共享分支做rebase。比如大家都在develop上提交,你偷偷执行git rebase把develop的提交顺序改了,其他人的本地历史就对不上了,下次push会被拒,整个团队都得跟着收拾烂摊子。记住一条铁律:rebase只动自己独有、还没推上去的提交,merge用于汇合公共分支。
5. 团队协作中的分支策略与个人心得
5.1 分支模型的取舍
工具层面的操作学完,接下来是策略问题。分支模型社区里提得最多的就是Git Flow和GitHub Flow,但落到Gitee这种平台,我个人更推荐一套简化得多的模型。
主分支只保留稳定版本,所有开发都在功能分支上做,功能完成后通过Pull Request(Gitee里叫“Pull Requests”)合入主分支。功能分支的命名直接用业务前缀加描述即可,比如feature/user-register、fix/login-timeout,一眼就能看出这个分支在干什么。
这套模型最大的好处是没有太多繁文缛节,一个人做一个项目时也完全适用。你不需要维护develop、release、hotfix等多套分支,一个master加上若干个短期功能分支就已经能覆盖绝大多数需求了。等团队规模上来了,再考虑引入更重的流程也不迟。
5.2 Pull Request与保护分支
用Gitee的Pull Request功能做合并,加上保护分支设置,是防止手滑直接推到主分支的利器。
在Gitee仓库的“管理”里找到“分支管理”,把master设置成保护分支。保护之后,普通成员不能直接向master提交代码,只能通过Pull Request合入。配合仓库设置里的“需要评审”功能,每次合并都有人看过再合,质量自然有保障。
Pull Request里我习惯写清楚三件事:这个分支做了什么、为什么这么做、怎么验证的。有时候还会贴一张运行截图或测试结果。别小看这几行字,两周后再回来看,这些记录比什么文档都好用。
5.3 实操心得
最后分享几个我自己踩出来的经验。
第一,功能分支的寿命不要超过三天。分支放得越久,跟主分支偏离越远,合并时冲突越多,心态越容易炸。写一半的功能如果一时完不成,宁可先提交一部分能编译通过的代码,也不要一直闷头写,等到分支长到几百个提交再合。
第二,合并功能分支时建议加--no-ff。虽然多了一个空白的合并提交,但换来了“这个功能是一次独立合并进来的”这个历史信息。用git log --graph看历史,一条条分明的合并节点比一条拉通的长线好读得多。
第三,遇到冲突不要慌,更不要直接在网页端改。把冲突拉到本地处理完,测试通过再推,比在网页里盲改靠谱得多。我在Gitee上见过太多人在网页端点合并,冲突界面里改了半天下线重启,最后代码直接废了。
第四,git stash是你的好帮手。有时候主分支坏了要紧急切过去看,功能分支上的改动又没完成,不想带过去。git stash把当前工作区存起来,处理完主分支再git stash pop恢复,省得临时提交污染历史。
SSH免密和分支管理这两块,配置和命令本身都不难,难的是在真实工作流里把每一步的原因想明白。花点时间把人机交互的环节磨顺了,后面做合并、做评审、做持续集成,都会省下大量重复劳动。希望这篇整理能让你少走几步弯路。
