Git零基础入门:从本地版本控制到GitHub远程推送完整指南
第一次打开终端敲下git的时候我根本不知道自己在干什么。那时候我还在用项目v1_最终版_再也不改.zip这种命名方式管理代码直到某天同时弄混了三个版本的文件才下定决心把 Git 认真学一遍。现在回头看Git 也好GitHub 也好真正拦住新手的东西并不是命令本身而是脑子里缺了一张地图。这篇内容不做历史科普也不讲原理竞赛就用一条主线带你走完装好 Git、掌握几个本地命令、把项目推到 GitHub 上。零基础完全可以跟得上中间我会把当年踩过的坑、以及后来带人时见到的瞎操作全写出来能帮你省下大量试错时间。1. 为什么所有教程都在逼你学 Git先搞懂它解决什么问题1.1 没有版本控制时我们是怎么活过来的先说一个我早期经历过的真实场景。当时做一个模拟项目代码量不大但需求改得勤。为了安全我每个阶段都会手动备份一份project_0612、project_0620、project_final_1、project_final_2……最多的时候文件夹里有十几个备份版本占空间不说最要命的是过几天根本想不起来哪个版本才是最新可用的。有一天需要回退一个功能我打开一个旧备份把代码改完扭头才发现改错文件了——新版本里好不容易修好的 bug 又回来了。那一刻我就意识到人的记忆力不可靠文件命名更不可靠我需要一个工具能回答三个问题当前这套文件是哪来的我改过什么能不能回到任意一个历史状态这就是版本控制工具存在的意义。而 Git 是目前使用最广的一种。你可以在网上找到很多分支概念、协作模型的文章但对我们这些刚起步的人来说先把它当成带存档功能的文件保险箱就好。1.2 Git 的核心思想快照而非差异我知道关于 Git 有一个很常见的误解以为它像网盘同步一样只记录每个文件的改动差异。其实 Git 的做法是快照——每次你执行提交commit它就是给整个项目拍一张完整照片把所有文件当时的状态原封不动存进内部的对象库里。这个设计有个巨大的好处。但凡玩过带即时存档的游戏都知道想要回到某个关口只要有那个关口的存档就行不需要从最早的记录一步步推论。Git 也一样只要你能找到任何一个历史提交的快照就能完整还原当时整个项目的文件状态不依赖前后提交的记录关系。新手不需要理解快照在底层是怎么存储的你只需要建立一个心智模型每次 commit 就是一个存档点。项目一小时前的状态、昨天的状态、上周的状态只要当时提交过就都能找回。1.3 你学 Git 不需要懂的那些东西网上不少教程喜欢从仓库对象、分支指针、引用规范讲起看得人非常头大。我建议新手直接跳过这些。真正上手之前你只需要知道三件事有一个隐藏的.git目录它记录了这个项目的一切历史信息你平时看到的项目文件叫工作区这里是你真正干活的地方提交之后的内容都收在.git里跟你的源文件分离。是不是很简单其实学 Git 就像学开车你不需要先成为发动机工程师才能把车开到路上。先会用油门、刹车、方向盘等开熟了再回头补底盘知识效率高得多。2. 安装环节三个平台的避坑指南2.1 Windows一路 Next 背后的三个关键选项Windows 用户直接去 Git 官网下载安装包就行。安装向导大部分时候确实可以一路 Next 点下去但有三个选项值得停一下看清楚否则后面会很难受。第一是调整 PATH 环境变量这一步默认选项是Git from the command line and also from 3rd-party software这个一定要保持。如果选成最后一个只在 Git Bash 里用你打开系统自带的命令提示符或 PowerShell 时就会找不到git命令。第二是换行符转换方式默认的 Windows 风格转提交也够用但如果你的项目将来要和 macOS 或 Linux 用户协作建议直接选Checkout as-is, commit as-is原生还原提交也保持原生这样团队之间不会因为行尾符差异产生一堆奇怪的改动。第三是默认编辑器新手选 Notepad记事本或默认项都行。反正你很快就会发现在自己的编辑器里开终端更顺手。装完后打开 Git Bash 或者 PowerShell输入git --version如果能输出版本号就说明装好了。Git Bash 是安装包自带的一个模拟终端环境新手用它做练习会很舒服因为里面的命令提示和 Linux 保持一致。2.2 macOS自带 Git 其实是个坑很多人在 macOS 上第一次输git --version系统会弹窗提示安装Command Line Tools。装完之后 Git 确实能用但那是系统自带的旧版本版本号通常比较老。我的建议是如果只是临时用一下系统自带版凑合行如果你打算长期用它做项目还是装一份最新版更省心。macOS 优先推荐用包管理器装先确认你已经装了包管理器然后跑一句安装命令装完重启终端再确认which git返回的不是系统目录路径而是你包管理器指定的路径这样才算真正用上了新版。装完新版本之后记得留意一件事终端里面的 Git 可能还是旧版。老版本的默认配置、默认分支名都会跟新版本不一样后面我会专门说分支名的问题。2.3 Linux一行命令背后的版本差异Linux 用户一般都有包管理器安装指令大体是Debian/Ubuntu 系用apt install gitRedHat/Fedora 系用dnf install gitArch 系用pacman -S git。不同发行版的命令不同但下载安装的本质是一样的。唯一的差异点是版本新旧。有些系统的官方软件源里 Git 版本可能偏老而新的命令行参数比如后面要提到的init.defaultBranch要新版本才支持。如果你发现自己某些参数怎么设置都不生效先看一眼版本号这通常就是原因。对新手来说版本只要不是老得离谱比如 2.20 以下先用着完全没问题不需要为了追求新版去折腾编译安装。2.4 安装完成后先做三件小事装完 Git 之后不要急着建仓库先做三件小事能避免后面好多麻烦。第一设置你的身份信息。打开终端执行git config --global user.name 你的名字 git config --global user.email 你的邮箱这两条配置是每次提交时必用到的东西它会作为作者信息写进每个提交里GitHub 上的贡献记录也是靠它识别你的。所以要跟 GitHub 注册信息保持一致别随手敲一个火星文否则以后看提交历史都分不清谁是谁。第二统一初始分支名。默认情况下 Git 创建的第一个分支叫master而 GitHub 上新建仓库的默认分支叫main。为了减少后面推送时的摩擦建议直接改掉git config --global init.defaultBranch main这样你本地用git init创建仓库时初始分支就直接是main跟 GitHub 默认值对齐了。第三用git config --list看一眼配置是否生效。这一步纯粹是求个心安确认输出的内容里有你的用户名和邮箱就行。3. 先别碰 GitHub把本地仓库玩明白再说3.1 三个区域的生命周期工作区、暂存区、本地仓库很多人一上来就想着git push但我带过的每个零基础朋友我都建议先不碰远程把本地流程走通三次再说。因为 Git 本地有三个区域理不顺它们你后面看到git status的输出会一头雾水。简单画一个流程就是工作区你看到的文件 --git add-- 暂存区 --git commit-- 本地仓库工作区就是你正常写代码、改文档的位置。暂存区是个中间地带相当于超市购物车——你在货架工作区上拿了东西放进购物车暂存区但还没到收银台结账提交。只有放进购物车的东西才会被结账打包。为什么要多这一道工序因为不是所有修改都想一次性提交。比如你改了代码又删了一个临时文件这两个改动可能不相关你希望它们分成两次提交那就可以精确指定哪个文件进暂存区哪个等下再说。这也是 Git 新手必须理解的核心概念之一。3.2 新手需要掌握的最小命令集合本地练习阶段你只需要五个命令。先建一个测试目录在里面创建文件玩一遍git init这个命令会在当前目录创建一个隐藏的.git文件夹。注意它只是初始化了一个仓库还没有任何可追踪的文件。你可以用ls -a看到这个隐藏目录但永远不要手动改里面的内容。git status随时查看当前仓库状态。它会告诉你哪些文件还没被追踪、哪些已经修改、哪些已经进入暂存区。我个人建议新手把git status当成回家进门时先看鞋柜的那个动作每次操作之前敲一遍输出了解一下自己现在在哪。接着创建一个文本文件比如readme.txt然后把它加进暂存区git add readme.txt也可以偷懒用git add .意思是把当前目录里所有变更都加进暂存区。对新手来说这个短命令特别方便但我还是建议你至少亲手用过几次精确加单文件的版本知道两个写法的区别不然以后项目大了会出现不想提交的东西被一锅端进暂存区的情况。暂存区准备好了就该提交git commit -m 第一次提交这里-m后面跟的是提交说明。提交说明一定要写得清楚比如修复登录页面按钮错位而不是改一下。因为再过两周只有你自己知道这行字是什么意思。最后是查看历史git log --oneline它会把所有提交记录压缩成一行列表展示。你会看到每个提交有一个长长的哈希值前几位、所在分支、提交说明。能看出提交顺序和版本脉络心里基本就有底了。把这五个命令来回用几次创建几个文件改一改提交几次本地 Git 的日常工作循环就算掌握了。3.3 撤销操作所有人都要面对的事故现场学 Git 的过程中免不了犯错所以撤销操作其实就是这节课的急救包。你只要记住一个优先级原则越早发现事故越容易恢复。如果你在工作区改了一个文件改完发现还不如不改。文件还没进暂存区用git restore 文件名它会用最近一次提交或暂存区的内容把这个文件恢复原样。注意这条命令会直接覆盖你当前的工作内容所以执行前确认一下你是真的不要当前改动了。如果你已经执行过git add文件进了暂存区发现加错了或者不想提交。使用git restore --staged 文件名这个操作只会把文件从暂存区移回工作区你的实际改动还在不会丢失。如果你已经提交了但发现提交说明写错了可以采用git commit --amend它会追加到最近一次提交上让你重新编辑提交说明。这是最安全的修正手段之一。还有一个更常见的情况提交之后发现代码写坏了想退回上一个提交。如果这个提交还没推送到 GitHub阻力很小可以重置掉这次提交把工作区保留住相当于收回这次提交动作git reset --soft HEAD~1HEAD可以理解成你现在所在的位置HEAD~1就是前一个提交。--soft的意思是只移动提交记录你的文件改动还在工作区里可以重新整理后再次提交。但要注意如果提交已经推送到 GitHub 并且可能有其他人拉取过就不要用reset了应该用git revert来新建一个反向提交。这个原则现在记住就行等你真正需要的时候自然会想起来。4. 连接 GitHubSSH 密钥才是正路4.1 HTTPS 还是 SSH为什么我更推荐 SSH连接 GitHub 主要有两种协议HTTPS 和 SSH。HTTPS 最简单在终端里输入仓库网址就能克隆和推送但是每次操作都要验证身份。现在 GitHub 上 HTTPS 方式不支持用密码直接推送了你得用个人访问令牌Personal Access Token当密码用对新手来说这就是第一个劝退点——又要进网页设置又要复制一长串令牌太麻烦。SSH 方式则是用一对密钥来验证身份一把私钥留在你电脑上一把公钥填到 GitHub 账户里。配置好之后推送拉取都不需要再输任何凭证一劳永逸。装好密钥后连接用户名容易搞混没关系下面会一步步讲清楚。表格看一下对比对比项HTTPSSSH初次配置难度低克隆时填网址即可需要生成密钥并配置略高推送时体验每次都要输令牌或配置缓存一次性配置之后无感安全性令牌泄露有风险需要定期管理私钥本地保存风险较低适合人群偶尔使用、临时拉取代码日常开发、频繁推送我的结论非常直白既然你要学 Git 并连接 GitHub直接一开始就学会 SSH不要走 HTTPS 绕弯路。这一步跑通之后你会觉得和远程仓库打交道完全没门槛。4.2 生成密钥只需要三步在终端里执行下面这条命令生成密钥注意把邮箱换成你 GitHub 注册用的邮箱它只是用来给密钥做个标识ssh-keygen -t ed25519 -C 你的邮箱现代加密算法推荐使用ed25519它比老的 RSA 方案更安全生成的密钥也更短。你会看到它问你保存位置默认是在用户目录下的.ssh/id_ed25519直接回车确认即可。后面出现设置口令passphrase的提示新手建议直接回车跳过——相当于给私钥加一层额外密码设置之后每次用都要输一遍体验上的成本的提升没有换来多少实际价值等以后有安全需求再补。命令执行完它会在你的用户目录下生成.ssh文件夹里面有两个文件id_ed25519私钥绝对不能泄露和id_ed25519.pub公钥可以给别人看。你可以用命令查看公钥cat ~/.ssh/id_ed25519.pub输出的内容是一长串字符ssh-ed25519开头最后跟着你刚才输入的邮箱。下一步需要把这个公钥整个复制出来。4.3 添加公钥到 GitHub 与验证连接登录 GitHub进入账户的设置页面找到 SSH and GPG keys 这个菜单点击新增 SSH 密钥。标题随便填比如我的办公电脑把刚才复制的公钥粘贴到 Key 输入框保存即可。接下来验证连接是否生效ssh -T gitgithub.com第一次执行时系统会问是否确认连接输入yes回车。如果配置成功终端会返回一段欢迎信息里面包含你的 GitHub 用户名。看到这个提示就可以放心了。这里有一个新手特别容易困惑的点gitgithub.com是固定的不是你自己的用户名如果你输入了自己的 GitHub 登录用户名反而会连接失败。另外GitHub 会显示你账户的用户名即使密钥文件里写的是邮箱也一样的属正常现象。做完这一步你的电脑和 GitHub 之间已经建立了一条安全通道后面所有推送都不需要再输密码了。5. 首次推送从本地到远端的完整流程5.1 在 GitHub 上建仓库时的两个选择现在去 GitHub 首页点击新建仓库。你只需要做两个关键选择仓库名字和公开还是私有。名字建议和本地项目名称保持一致方便对应。可见性方面公开仓库所有人都能看私有仓库只有你自己和被你授权的人能看。个人项目练习建议选私有等真的愿意公开分享再改成公开就行。还有一步很重要新建仓库页面底部有三个选项——自动生成 README 文件、添加 .gitignore 模板、添加许可证。如果你本地已经有一个 Git 仓库这三个选项建议一个都不要勾。为什么假如你勾了自动生成 READMEGitHub 会帮你初始化出一个带提交记录的远程仓库而这个仓库的提交历史和你本地仓库根本没关系。第一次推送的时候两边都有初始提交Git 会认为这是两个互不相干的历史拒绝合并新手遇到这种报错最让人头疼。所以最稳妥的做法是本地已经初始化了那就建一个完全空的远程仓库。5.2 关联远程仓库的底层含义仓库建好后GitHub 会给你展示两种协议的远程地址我们用的是 SSH 形式的地址长得像这样gitgithub.com:你的用户名/你的仓库名.git把它复制下来回到本地终端执行关联命令git remote add origin gitgithub.com:你的用户名/你的仓库名.git解释一下这条命令背后发生了什么remote是远程仓库的配置入口add表示新增一个远程origin只是一个名字一个约定俗成的默认远程名后面都可以改。执行之后你的本地仓库就知道有一个远端仓库存在地址是后面这个 URL。要不要确认可以随时查看当前关联的远程仓库git remote -v看到两行记录就说明关联成功了。这两行分别对应 fetch拉取和 push推送地址是一样的。5.3 关联好节点后真正的首次推送命令关联仓库之后执行推送git push -u origin main-u是--set-upstream的缩写它的意思是把本地的 main 分支和远程的 main 分支关联起来。这个参数只在第一次推送时需要之后你直接敲git push就能自动推送到关联好的远程分支。执行完之后刷新一下 GitHub 页面你的项目文件和提交记录就出现在远程仓库里了。到这一步你才算真正完成了第一次本地到远端的完整链路。送你一个日常使用频率最高的循环到新环境时先git clone克隆远程仓库到本地工作前git pull拉取队友最新提交修改代码后git add加进暂存区git commit创建存档点最后git push把本地存档推到远程。这个循环跑熟你就能独立维护一个远程项目了。5.4 一个小坑master 和 main 为什么对不上很多人第一次推送时会遇到这种情况本地仓库是之前用旧版本 Git 初始化的默认分支叫master但 GitHub 新仓库默认分支是main。你敲git push -u origin main终端会提示本地没有叫 main 的分支。解决办法是确定一个统一分支名。既然 GitHub 默认用main那我们就把本地分支也改过去git branch -M main-M表示把当前分支重命名为 main。执行完再查看git branch就会发现当前分支已经是 main 了。接着就能正常推送。如果在 2.4 节你已经设置了init.defaultBranch main以后新建仓库就不会遇到这个问题。对已经存在的旧仓库用git branch -M main这一个命令就够了。记住这个命令它能解决一大堆莫名其妙的推送失败问题。6. 新手最容易踩的五个坑以及我的固定套路6.1 一不小心手动改了 .git 目录第一个坑我在前面提过但值得单独再说一次.git目录是仓库的大脑它存储了所有版本历史和配置信息。有些新同学不熟悉隐藏目录觉得碍眼顺手就把它删了或者拖进 IDE 里乱改轻则丢失全部历史记录重则仓库直接损坏项目文件变成一滩无法追踪的数据。我自己的固定套路是把 .git 目录当作一个黑盒。我永远不会手动去看里面的文件内容除非真的在做仓库深度修复而且那也是在完全备份之后才碰的。你对 Git 的一切操作都应通过命令完成而不是直接编辑.git内部的文本。6.2 把不该提交的文件推上去了第二个高发问题是把敏感配置文件或者庞大的依赖目录推到了 GitHub。比如项目里的环境变量文件里面放着数据库地址、密钥口令一旦提交到公开仓库等于把自己的密码在世界舞台上广播了一遍。依赖目录也一样几百兆的文件推上去之后每次拉取都变成一场灾难。我的做法很朴素新建仓库的第一步永远是创建 .gitignore 文件里面提前写好哪些路径和文件类型不需要 Git 追踪。列出几个常见的忽略规则.env node_modules/ dist/ *.log .DS_Store如果你已经不小心把不该提交的文件推到远程了也别慌可以先把它从 Git 追踪中移除但保留在本地磁盘上git rm -r --cached 文件名加一个--cached参数的意思是只从版本控制里删掉不动你本地文件然后重新提交一次。这样远程仓库的历史里可能还会留存旧记录但至少当前版本是干净的。公共仓库如果涉及敏感信息最好还是彻底轮换掉暴露的口令。6.3 行尾符的跨平台大战第三个坑涉及协作开发。Windows 系统下文件默认用回车加换行CRLF作为行尾macOS 和 Linux 下用换行LF。如果在提交源代码时混入了不同类型的行尾符Git 会认为整行都变了导致一个原本只有一个字改动的地方出现整个文件被标记为全部修改。我在跨平台项目里用的固定套路是团队约定统一使用 LF 作为行尾并在仓库根目录放一个.editorconfig文件声明所有文本文件的换行规则。同时在 Windows 上把 Git 的core.autocrlf设置为true让 Git 在检出代码时自动把 LF 转成 CRLF在提交时再转换回去macOS/Linux 上则保持core.autocrlf为input或false。配置指令git config --global core.autocrlf true这条命令是在 Windows 环境下执行。总之行尾符问题不解决每次打开文件都会看到整文件飘红极其浪费生命。6.4 推送被拒绝不一定是你代码有问题第四个坑也是最常见的心理崩溃点好不容易写完了执行git push却看到终端冒出一段 rejected 的红色提示。新手第一反应是我的代码是不是被拒收了其实根本不是。真实原因往往是远程仓库已经有别人提交的新内容而你的本地提交基于的是一个落后版本。Git 出于安全考虑不允许你用本地状态直接覆盖远程历史。解决办法也很简单git pull origin main git push origin main先拉取远程更新把远程新提交合并到本地解决可能的冲突之后再推送。冲突其实没那么可怕Git 会在相关文件里标出不同版本的代码块你只要逐一确认要保留哪边、删掉哪边然后重新提交即可。冲突不等于失败它是团队协作的正常现象。6.5 只见树木不见森林Git 分支的价值第五个建议说出来可能有点反直觉刚开始学 Git 时我一直觉得分支是高级功能至少熟练三个月再学。直到某次我写新功能把主流程搞坏了想回到之前可用的提交做对比懊恼了半天——如果有用分支的习惯一条命令就能在自己尝试性的修改和稳定版本之间来回切换。其实分支的概念一点都不复杂它只是在某个提交点上放了一个可以移动的书签你在这个书签上继续提交就会沿出一条自己的路线。创建分支不需要复制任何文件所以代价几乎为零。你只需要记住两个命令git branch 分支名创建一个新分支git switch 分支名切换到那个分支。我的固定套路是任何一个新想法先开个分支去玩试好了再合并回主分支。哪怕是一个人来开发也一样先分支后合并的思路能让你永远保有一个可运行的主线版本让试错成本和风险都降到最低。最后再分享两个我自己的使用习惯第一个习惯是给常用命令起缩写。Git 允许你配置自定义别名我十多年一直是这么配的git config --global alias.lg log --oneline --graph --all --decorate配置之后输入git lg就能看到带分支结构的漂亮提交图比裸看历史列表直观得多。第二个习惯是提交频率宁可多不可少。很多人直到做完一个功能才提交一次中间过程动辄一两个小时这段时间里没有任何存档点。我更建议每次逻辑上完成一小步比如清理了一个废弃函数或修改了接口返回字段就提交一次。提交多了也不怕组合、拆分都可以后面再说存档点越多你回退时越自由。Git 的上手曲线在第一次推送成功之后会突然变缓。前面的安装配环境、密钥配置、远程关联这些事看起来繁琐但值得花一个下午把它们彻底跑通。以后无论是自己项目存档、换电脑搬代码还是和队友协作都会发自内心觉得这趟折腾值。