很多人学 Git 和 GitHub,不是被概念难住的,而是被“不知道自己不知道什么”这件事难住的。装一个 Git 不难,注册一个 GitHub 账号也不难,难的是第一次遇到fatal: Not a git repository、第一次被拒绝提交、第一次把node_modules推到仓库,又不知道怎么撤回。这篇文章会把你当成真正零基础的人来写,但不会把你当“笨人”来写。你不需要提前掌握任何版本控制知识,只需要跟着步骤走完一遍,就会建立一个非常完整的 Git 工作流心智模型。
学完这篇文章,你能做到三件事:在自己的电脑上完成 Git 安装与配置;在 GitHub 上创建仓库并把本地代码同步上去;理解分支、提交、推送、拉取这些最常见操作背后的逻辑,而不是靠背命令来“假会”。另外,我还会专门讲国内开发者几乎都会遇到的 GitHub 连接不稳定、下载慢、克隆失败的问题,给你一套不折腾的安全应对方案。
1. 这件事真的值得学吗?——写给还没上车的朋友
先回答一个非常现实的问题:如果我以后不做专业开发,只是偶尔写点脚本、做点小项目,有必要学 Git 和 GitHub 吗?
我的判断是:只要你的代码超过 200 行,或者你的代码需要换电脑、换环境、让别人看,Git 的收益就已经大于学习成本。
回忆一下没有版本管理时的典型场景:你的项目文件夹里可能已经出现了final.py、final_2.py、final_真正最终版.py、new_final_v3.py。没有人能说清每一版到底改了什么,也没有人能保证删掉某段代码后,明天还能找回来。更可怕的是,你想回退到三天前正常工作的版本,但你已经记不清当时改了哪些文件。这种“反馈黑洞”会极大消耗开发热情。
Git 解决的就是这个核心痛点:它是一个给代码拍摄“存档点”的系统。每次你确认“目前这个状态是好的”,就给代码打一个快照,之后随便折腾,随时可以回到任意一个快照。
而 GitHub 解决的是另一个问题:如何让代码在多个设备、多个开发者之间安全共享。它本质上是一个存放 Git 仓库的远程服务器,提供网页界面、权限控制、Issue 管理、Pull Request 代码评审等功能。
所以更准确的表述是:Git 是工具,GitHub 是平台。你可以不注册 GitHub 单独用 Git,但只要你想和他人协作、开源代码、或者在不同电脑之间同步,GitHub 就是绕不开的配套环节。
2. 核心概念:版本控制的底层逻辑与 Git 的三个区
很多教程一上来就让你敲git add、git commit、git push,然后你照做了,感觉“会了”,但换个场景就不会了。根本原因是没理解 Git 的设计模型。
2.1 集中式版本控制与分布式版本控制的区别
早期的版本控制工具(比如 SVN)是集中式的:代码全部存在一台中央服务器上,每个人从服务器拉取代码到自己电脑,改完再提交回去。这种方式有一个命门——服务器一旦挂了,所有人都无法提交和获取最新代码,而且历史记录也可能丢失。
Git 是分布式的。每个开发者本地都有一份完整的仓库拷贝,包括全部历史记录。这意味着:
- 你可以离线提交、离线查看历史。
- 局域网或网络出问题时,你照样能干活。
- 任何一个节点挂了,只要还有一个人本地有完整仓库,就能恢复。
这也是 Git「快」的底层原因:绝大多数操作都发生在本地,只有push和pull需要网络通信。
2.2 工作区、暂存区、本地仓库、远程仓库
初学者最需要建立的就是这四个区域的概念:
| 区域 | 通俗理解 | 对应命令 |
|---|---|---|
| 工作区(Working Directory) | 你眼睛看到的、正在编辑的文件目录 | 不用命令 |
| 暂存区(Staging Area / Index) | 临时存放你“预备提交”的改动list | git add |
| 本地仓库(Local Repository) | 你电脑里的.git目录,保存所有提交记录 | git commit |
| 远程仓库(Remote Repository) | GitHub/Gitee 上的服务器仓库 | git push/git pull |
为什么分这么细?因为现实的开发流程里,你不会希望每次修改一个字符都生成一个历史版本。你可能改了好几个文件,但只有其中一部分属于同一个逻辑改动。这时你先把这部分文件git add进暂存区,再一次性git commit成一个提交,历史才会清晰。
一个直观类比:git add是选菜,git commit是下单,git push是把菜从厨房端到桌上。菜(代码)最终只有端上桌(推到远程仓库),别人才能吃到(看到)。
2.3 一个容易忽略的认知:Git 保存的是快照,不是差异
浅层理解 Git,会觉得它记录了“每次改了什么”。这不算全错,但不够准确。Git 在每次提交时,实际上把当前所有文件的状态做成了一个快照(snapshot),如果文件没有变化,它只保存一个指向上一个版本的指针。这种设计保证了 Git 切换分支、回退版本时速度极快,因为本质上只是指针切换到另一个快照图。
理解这一点对你日常使用有什么帮助?它解释了为什么 Git 分支成本极低,也解释了为什么你可以放心创建大量实验分支——分支只是一个指向提交的指针,创建和销毁都不动文件内容。
3. 环境准备:在不同操作系统上安装 Git
3.1 如何确认你的电脑是否已经安装 Git
在终端(Windows 上是 PowerShell 或 CMD,macOS 是 Terminal)输入:
git --version如果输出类似git version 2.44.0,说明已经安装。如果提示“command not found”或“无法识别”,就需要安装。我建议无论系统是否自带,都用官方源安装较新版本,避免老版本兼容问题。
3.2 Windows 安装 Git
推荐使用 Git 官方安装包。下载后一路点击 Next,但有几个关键选项需要留意:
- “Select Components” 页面,建议勾选 “Git Bash Here” 和 “Git GUI Here”,这样在文件夹右键菜单里可以直接打开终端。
- “Choosing the default editor” 页面,建议选 Notepad(记事本)或 Visual Studio Code。不要选 Vim,零基础默认用 Vim 会在 commit 写说明时卡住——你可能会不知道怎么退出编辑器,实际上 Vim 保存退出要先按 Esc,再输入
:wq回车。 - “Adjusting your PATH environment” 页面,选默认的推荐选项即可。
- “Configuring the line ending conversions” 页面,选 “Checkout as-is, commit as-is” 或默认选项都可以,并在项目里统一用
.gitattributes管理换行符,避免团队 Windows/macOS 混用时的 CRLF/LF 冲突。
安装完成后重新打开终端,再次执行git --version验证。
也可以用 Windows 包管理器自动安装:
winget install --id Git.Git -e --source winget3.3 macOS 安装 Git
macOS 自带 Git,但版本可能较老。如果你已经安装 Xcode Command Line Tools,可以直接用系统自带版;如果想用最新版,推荐通过 Homebrew 安装:
brew install git安装后确认路径,避免用的是系统自带版本:
which git /usr/local/bin/git3.4 Linux 安装 Git
Debian/Ubuntu 系列:
sudo apt update sudo apt install git -yCentOS/RHEL/Fedora 系列:
sudo yum install git -y # 或者新版 Fedora 使用 dnf sudo dnf install git -y安装完成后,统一验证:
git --version3.5 第一次全局配置
安装完成后,必须配置你的用户名和邮箱。Git 每次提交都会把这两条信息写入提交记录,这相当于代码的“签名”。注意,这个提交人信息不会从 GitHub 账号自动获取,必须手动配置。
git config --global user.name "你的名字" git config --global user.email "你的邮箱@example.com"如果只想修改某一个仓库的提交者信息,去掉--global即可,这样该仓库优先使用仓库级配置:
cd /path/to/your/repo git config user.name "仓库专用名字" git config user.email "仓库专用邮箱"查看当前配置:
git config --global --list4. 连接 GitHub:SSH 密钥配置与 HTTPS 备用方案
配置好 Git 之后,还需要让本地 Git 和 GitHub 账号之间建立安全连接。GitHub 支持两种远程连接协议:HTTPS 和 SSH。
- HTTPS:推送时输入 GitHub 用户名和密码(或 Token),简单直接,但每次都要输入凭证,配置 Personal Access Token 后也麻烦。
- SSH:通过密钥对免密认证,一次配置长期使用,更符合开发习惯。
对零基础用户,我建议直接用 SSH。看上去多生成一对密钥,但后面推送就完全免输密码,长期体验顺滑很多。
4.1 生成 SSH 密钥对
在终端执行:
ssh-keygen -t ed25519 -C "你的邮箱@example.com"按回车确认默认保存路径(~/.ssh/id_ed25519),然后可以设置一个 passphrase(建议空密码直接回车,或者设置一个简单密码,取决于你对安全的偏好)。生成完成后,你会看到指纹信息,说明密钥对创建成功。
如果你使用的系统或环境不支持 ed25519,可以改用 RSA:
ssh-keygen -t rsa -b 4096 -C "你的邮箱@example.com"4.2 把公钥添加到 GitHub
查看公钥内容:
cat ~/.ssh/id_ed25519.pub然后复制输出的一长串ssh-ed25519 AAAA...内容。登录 GitHub,点击右上角头像,进入Settings > SSH and GPG keys,点击New SSH key,标题随意填写(比如My Laptop),Key type 保持默认Authentication Key,把公钥粘贴进去,点击Add SSH key。
最后测试连接:
ssh -T git@github.com如果看到类似输出,说明配置成功:
Hi yourname! You've successfully authenticated, but GitHub does not provide shell access.需要注意:id_ed25519.pub是公钥,可以给任何人;id_ed25519是私钥,永远不要上传到任何网站、仓库,也不要发给别人。私钥泄露等同账号密码泄露。
4.3 HTTPS + Personal Access Token 的备用方案
有些网络环境只允许 443 端口访问,或者你暂时不想生成 SSH 密钥,那就用 HTTPS。但注意:GitHub 已经不支持纯密码推代码,你需要生成一个 Personal Access Token(PAT)。
步骤:GitHub -> Settings -> Developer settings -> Personal access tokens -> Tokens (classic) -> Generate new token。勾选repo权限,生成后复制一次(只显示一次),然后推送时用它代替密码输入。
如果不想每次输入,Windows 的 Git Credential Manager 会自动保存 Token。macOS 会弹窗询问是否允许访问钥匙串。
5. 第一次把本地代码推送到 GitHub 仓库
现在进入核心实操。我们用一个“本地已有项目 -> 推到 GitHub 新仓库”的完整流程,把最常用的命令串起来。
5.1 在 GitHub 创建远程仓库
登录 GitHub,右上角+->New repository。Repository name 填写项目名(比如my-first-project),可见性选 Private 或 Public,不要勾选 “Add a README file”,因为我们本地已经有项目需要推送,避免产生初始提交冲突。点击 Create repository。
创建后页面会显示三种连接方式:HTTPS 地址形如https://github.com/你的用户名/my-first-project.git,SSH 地址形如git@github.com:你的用户名/my-first-project.git。我们这里用 SSH。
5.2 本地初始化仓库并提交
假设你本地有一个项目文件夹,里面有一些代码文件。进入该目录:
cd /path/to/my-first-project git initgit init表示把当前目录变成一个 Git 仓库。执行后文件夹里会多一个隐藏的.git目录,所有版本信息都存在这里。接下来先看当前状态:
git status输出会列出未被追踪的文件。然后逐个操作:
git add . git commit -m "feat: 初始化项目"git add .是“把当前目录所有改动加入暂存区”。也可以指定单个文件,比如git add README.md。git commit -m "说明"是“把暂存区内容打成一个提交”,-m后面的字符串就是提交说明。规范提交说明是职业习惯,后面会专门讲。
如果执行 commit 时弹出文本编辑器,多半是配置 Git 时默认选到了 Vim。无论你选了 Nano 还是 Vim,都可以执行git config --global core.editor "code --wait"改成 VS Code,或者"notepad"、"nano"。
5.3 关联远程仓库并推送
把本地仓库与 GitHub 仓库建立关联:
git remote add origin git@github.com:你的用户名/my-first-project.git这里需要解释一下origin:它只是远程仓库的默认别名,代表“主远程仓库”。你完全可以命名成别的,但大家都默认使用origin,不需要改。
然后把本地分支推送到远程:
git branch -M main git push -u origin maingit branch -M main是把当前分支重命名为main(如果你的 Git 默认分支叫master)。git push -u origin main是把本地main分支推送到远程origin的main分支,-u表示将本地分支与远程分支建立上游关联。后续再推送只要直接git push即可。
推送成功后,刷新 GitHub 仓库页面,你会看到代码已经出现在远程仓库里。整个过程是:工作区修改 ->git add->git commit->git push。
6. 日常开发循环:提交、拉取、分支与合并冲突
第一次推送成功只是开始。接下来的问题是:每天写代码时,到底什么时候该提交?多人协作时,怎么保证代码不冲突?
6.1 推荐的提交节奏
提交粒度没有绝对标准,但有一个非常实用的原则:每个提交只包含一个逻辑改动,提交说明要说清楚“为什么”。
比如你修复了一个 bug,又顺手改了另一个配置,最好分两次提交。因为将来有人看到某次变更造成了线上事故,会想通过git revert精确回退某一次提交。如果你把无关改动混在一起,回退就变得很难。
6.2 拉取与推送的正确顺序
协作时,最安全的工作流是:
- 写代码前先
git pull拉取最新代码。 - 本地修改并提交。
- 推送前再次
git pull,如果出现冲突就地解决。 git push推送本地提交。
git pull # ...做一些修改... git add . git commit -m "feat: 增加用户注册接口" git pull git push为什么推送前要再pull一次?因为在你写代码期间,同事可能已经推送了新提交。如果你直接 push,Git 会拒绝推送并提示本地落后于远程。此时必须先把远程更新拉到本地,再推送。这里的“拉取”实际做了两件事:下载远程新提交(fetch),并合并到当前分支(merge)。
6.3 分支:让你的实验代码不影响主分支
分支是 Git 最重要也最被低估的功能。一个能支撑实际项目的最佳实践是:main分支永远保持可运行,新功能在feature分支上开发,开发完再合并回main。
创建并切换到新分支:
# 创建并切换分支,等价于 git branch feature/login + git checkout feature/login git switch -c feature/login在新分支上修改代码、提交、推送:
git add . git commit -m "feat: 完成登录功能" git push -u origin feature/login然后切回main,拉取最新代码,合并功能分支:
git switch main git pull git merge feature/login如果合并顺利,feature/login的提交就会进入main。合并后如果功能分支不再需要,就可以删除:
git branch -d feature/login6.4 合并冲突到底长什么样
当两个人改了同一个文件的同一段代码,Git 不知道该保留哪一份,就会产生合并冲突。冲突文件内部会显示这样的标记:
<<<<<<< HEAD 这是当前分支(main)的内容 ======= 这是待合并分支(feature/login)的内容 >>>>>>> feature/login你不需要背“冲突怎么解决”,只需要理解:Git 把两个版本都标出来了,你手动把文件改成最终想要的样子,删除尖括号标记,然后提交一次,就算解决冲突。
git add . git commit -m "merge: 解决登录模块冲突"建议刚开始时,用 Visual Studio Code 等图形界面解决冲突,它会提供 “Accept Current Change / Accept Incoming Change / Accept Both” 三个按钮,比纯文本编辑直观很多。
7. 完整示例:模拟一次多人协作提交
下面用一个具体场景把上面所有命令串起来。假设你受邀参加一个开源项目的协作,先克隆仓库到本地:
git clone git@github.com:some-org/open-source-demo.git cd open-source-demo创建一个功能分支,写代码,提交,推送:
git switch -c fix/typo # 修改 README.md 里的一个拼写错误 git add README.md git commit -m "docs: 修复 README 拼写错误" git push -u origin fix/typo然后在 GitHub 页面上点击Compare & pull request,创建 Pull Request,等待维护者审查合并。
这个流程就是开源协作的标准节奏,也是现代公司里 Git 协作的缩影。你会发现,最核心的 Git 命令其实不多:clone、switch、add、commit、push、pull、merge。把这几条练熟,日常开发就足够用了。
8. GitHub 访问连接不稳定、下载慢的常见应对
这个问题在国内开发者中很常见。具体表现有两种:一是浏览器打不开 GitHub 网页,加载很慢;二是git clone或下载 Release 资源时速度极慢,甚至直接超时。
8.1 先确认是网络波动还是普遍问题
不要一遇到打不开就先想到“换工具”。第一步要做的是确认网络状态:
ping github.com如果丢包严重,说明网络出口到 GitHub 线路质量差。再访问github.com网页,观察是否长时间白屏。如果网页能打开但极慢,多半是 DNS 解析或 CDN 路由问题;如果完全打不开,可能需要换网络或使用代码托管平台替代方案。
8.2 修改 DNS 和使用官方 CDN 域名
国内运营商 DNS 解析 GitHub 域名时,可能解析出到海外节点的 IP,导致访问慢。可以尝试把 DNS 修改为公共 DNS,比如 223.5.5.5(阿里 DNS)、119.29.29.29(腾讯 DNS),再刷新本地 DNS 缓存:
# Windows ipconfig /flushdns # macOS sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder # Linux(取决于 systemd 版本) sudo systemd-resolve --flush-caches这些手段都属于常规网络调优,不涉及任何特殊工具,目的只是让域名解析更快、更准。
8.3 下载 Release 大文件时使用镜像加速
git clone走的是 Git 协议或 SSH 协议,镜像加速效果有限。但 Release 资源下载(比如项目打好的.exe、.zip安装包)走的是 HTTP,可以用 GitHub 官方加速地址或社区镜像代理来提速。
一个稳妥的做法是:打开 GitHub 仓库的 Release 页面,复制要下载的链接,它通常长这样:
https://github.com/owner/repo/releases/download/v1.0.0/app.zip这类链接在部分地区下载缓慢。常见思路是:
- 使用 GitHub 镜像站或加速前缀,例如
ghproxy.com这类社区代理服务,把链接前面加上加速前缀再下载。 - 很多项目官方会提供国内镜像,比如某些工具会在 Gitee 上同步 Release 资源。
注意,这属于第三方的行为,请从可信的社区渠道获取镜像地址,不要随意把链接粘贴到不明网站。
8.4 代码同步需求可以迁移到国内托管平台
如果你的项目本身不需要依赖 GitHub 独有的社区生态,纯粹是私人代码备份和团队协作,完全可以考虑使用 Gitee 等国内代码托管平台。它们的服务器在国内,推拉代码速度明显更快。
一个典型的双平台工作流是:主仓库在 Gitee,GitHub 作为公开镜像。你可以把 GitHub 同步到 Gitee,这样 GitHub“打不开”的时候,团队仍然可以从 Gitee 拉代码。
需要提醒的是:涉及团队协作时,不要把“远程仓库地址”固定成某个平台,否则一旦该平台访问异常,整个团队就卡住了。建议在 README 里写清楚多个仓库地址的用途。
9. 常见问题与排查思路
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
git push报Permission denied (publickey) | SSH 密钥未添加或未指定 | 执行ssh -T git@github.com查看鉴权结果 | 将公钥加入 GitHub;确认 clone 地址是 SSH 格式 |
推送时提示Updates were rejected | 远程有新提交,本地落后 | git pull看合并结果 | 先拉取解决冲突,再git push |
| 提交时卡在 Vim 编辑器退出不了 | 默认编辑器是 Vim | 按 Esc,输入:wq回车保存退出 | 执行git config --global core.editor "code --wait"改用 VS Code |
| 文件改乱了想回退 | 没有备份也不想丢历史 | git log --oneline找提交点 | 用git checkout -- <file>丢弃未提交修改;用git reset回退已提交内容 |
明明改了很多文件,但git status没显示 | .gitignore 忽略了这些文件 | 执行git status --ignored | 检查.gitignore规则 |
clone 报RPC failed; curl 18 HTTP/2 stream error | 网络不稳定或仓库过大 | 调整 Git 缓冲和压缩配置 | git config --global http.version HTTP/1.1,增大http.postBuffer |
| 误把密码写进代码并推送了 | 敏感信息入库 | 立刻在 GitHub 撤销该 Token,修改密码 | 从历史中移除敏感文件,追加.gitignore |
10. 最佳实践与工程建议
学完基础命令,下一步要把 Git 用到“像专业人士一样”的程度。这部分不是进阶,而是避免你踩到真正的坑。
10.1 提交信息写规范
提交信息是给未来的自己和队友看的。建议采用约定式提交风格:
feat: 增加用户注册接口 fix: 修复登录页面点击无响应 docs: 更新 README 部署说明 refactor: 重构订单查询逻辑 test: 补充下单接口单元测试 chore: 更新依赖版本这样以后执行git log --oneline,一眼就能看出每次提交的类型和意图。
10.2 不要提交敏感信息
.gitignore必须在一开始就配好。模板如下:
# 依赖目录 node_modules/ # 编译产物 dist/ build/ target/ # 环境变量,通常包含密钥 .env .env.local # IDE 配置 .idea/ .vscode/ *.iml # 操作系统文件 .DS_Store Thumbs.db如果你已经把一个含密钥的文件提交进仓库,后来才加入.gitignore,该文件在历史记录里还是存在的。处理方式是把密钥从所有历史提交中清除,或者直接换新密钥,并尽快推送历史改写后的仓库。
10.3 每个提交保持可运行
一个常见的坏习惯是连续写两小时代码,然后一次git commit提交了一大坨。这样出现问题后,你无法定位是哪个小改动引入了 bug。
更好的做法是:每完成一个小的逻辑单元,就git add对应文件,git commit一次。哪怕一天提交十多次,只要每个提交都能运行通过,未来排错效率会高很多。
10.4 生产环境操作要谨慎
如果你的项目部署脚本或数据库配置也在 Git 管理里,涉及生产环境分支的操作必须比普通代码更谨慎:
- 推送前先看差异:
git diff确认改动范围。 - 不要直接在主分支上做破坏性实验,先开分支。
- 需要回退线上时,优先用
git revert <commit>生成一个新的反向提交,而不是git reset改写历史。因为git revert会保留“回退”这一操作的记录,团队其他人拉取后不会乱。 - 涉及生产数据库的变更,绝不要依靠
git push这种方式一键执行,必须走专门的发布系统和审批流程。
10.5 文件大小限制与大文件存储
GitHub 仓库单文件建议不超过 100 MB,超过 50 MB 就会警示。如果你要管理二进制大文件,比如游戏资源、机器学习模型权重、视频素材,应该使用 Git LFS,而不是直接把文件塞进普通 Git 仓库。
10.6 学会看错误信息
初学者最大的问题不是不会敲命令,而是看不懂错误提示。我的建议是:遇到错误先复制完整英文报错,粘贴到搜索引擎或者直接在终端执行git --help <命令>阅读文档,而不是盲目重试。Git 的错误提示其实已经写清楚了它想要什么、哪里不满足。
11. 总结与后续学习方向
现在可以把整个 Git 工作流模型完整串起来了:我们用git init或git clone在本地建立仓库,代码修改发生在工作区,用git add放入暂存区,用git commit生成一个本地提交,用git push推送到远程 GitHub,用git pull获取队友的新提交,用分支隔离功能开发,用合并把功能并入主分支,用.gitignore保护敏感文件,用规范提交信息让历史可读。
下一步你可以安排三个小练习来巩固:
- 用这篇文章的流程,把一个已有项目推送到 GitHub 私有仓库。
- 在电脑上创建两个目录,分别 clone 同一个仓库,在一边修改提交推送,在另一边拉取,模拟两个开发者协作。
- 把
main分支设为保护分支(GitHub 仓库 Settings -> Branches -> Branch protection rule),体验一下禁止直接推送到main、必须走 Pull Request 的团队流程。
Git 的命令远不止这些,但掌握核心工作流之后,其余命令都是在这个模型上按需扩展。遇到没见过的场景,先判断问题落在四个区域中的哪个,再找对应命令,基本就不会迷失方向。
建议你把这篇文章收藏备用,第一次看只需要跟着做一遍,后面遇到报错再回来查对应的章节。真正让 Git 发挥作用的,不是记住更多命令,而是建立一个“小步提交、清晰分支、稳定主干”的开发习惯。