尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Git 与 GitHub 版本控制全流程:安装配置、分支协作与安全回滚

Git 与 GitHub 版本控制全流程:安装配置、分支协作与安全回滚 接手一个没有任何版本控制的项目那种感觉就像走进一间没有标签的仓库——满地零件谁也不知道哪一箱才是最终版。上一版能跑的代码被覆盖了怎么办、同事改的那行逻辑去哪了、线上环境部署的是哪个提交……这些问题在没有 Git 之前全靠手动复制文件夹解决项目_v2_最终版_真的最终.zip这种命名我见过太多次了。这篇内容讲的就是怎么用 Git 配合 GitHub 把项目的版本控制彻底理顺从安装配置、本地提交、分支管理到推到远端仓库、多人协作、出事后怎么安全回滚。不管你是完全没碰过命令行的小白还是用了一阵子但总在冲突和回滚上翻车的同学这里面的步骤和坑都能直接拿去用。1. 先把版本控制这件事想明白1.1 手工管版本到底会烂在哪里先说清楚不解决的问题。大部分人的项目管理起点是复制一份改改完再复制一份。这个做法在单人、短期、一次性脚本的场景下勉强能用一旦项目活过两周麻烦就来了。第一个问题是无法回答这行代码是谁改的、为什么改。你只能看到一个结果看不到动机。第二个问题更致命想回退到三天前的状态你得靠文件夹时间戳去猜哪个是对的而且那份文件夹里可能混着调试用的 print 语句和临时注释。第三个问题是协作两个人同时改一个文件最后只能靠人工比对一个人把另一个人的修改覆盖掉这种事在多人项目里几乎每周都会发生。版本控制的核心价值不是备份而是记录意图。每次提交都带着作者、时间、一行说明把改了什么和为什么改绑在一起。备份只是顺带的结果真正省时间的是可追溯。注意项目一旦开始多人协作或者你打算把它开源、部署到线上就别再用文件夹复制法。迁移成本会随着文件数量指数上升越早切换越省事。1.2 Git 属于哪一类工具它凭什么成了事实标准版本控制工具分两代。老一代是集中式的代表是 SVN仓库只有一份放在中心服务器上你本地只存当前版本的文件。想提交就得联网服务器挂了所有人都停摆想看历史也得先从服务器拉。Git 是分布式的核心区别在于每个人本地都是一个完整仓库包含全部历史记录。这意味着你在飞机上、断网状态下照样能提交、能看 log、能切分支等有网了再同步。这个设计带来的直接好处是操作快几乎所有命令都是本地操作不依赖网络往返。除此之外Git 的分支成本极低。它内部存的是文件快照加内容寻址建一个分支不是复制一堆文件只是在某个提交对象上挂一个新指针几毫秒的事。正因为分支便宜才有了现在这套每做一个功能就开一条分支的工作流。GitHub 是建立在这套基础上的托管平台它本身不参与版本控制的逻辑只提供远端仓库存储、网页端浏览、Pull Request 评审、Issue 跟踪这些协作能力。理解这个分工很重要——Git 是工具GitHub 是服务。没有 GitHub你照样能用 Git但只用 Git 不用远端托管多人协作会很痛苦。1.3 工作区、暂存区、本地仓库三张桌子模型初学者最容易卡住的地方是搞不清add和commit为什么是两步。用一个生活化的比喻把你的项目想象成一张办公桌。工作区办公桌上正在处理的文件你随手改随手存桌面很乱。暂存区一个待归档托盘。你把确定要归档的纸张挑出来放进去还没归档的文件继续留在桌面上。本地仓库档案柜。托盘里的东西一次性封成一个档案袋一次 commit贴上标签永久保存。这三层的意义在于提交的粒度控制。你可能同时改了三个文件修了一个 bug、加了一段调试代码、顺手改了文档。调试代码不应该进版本库bug 修复和文档改动可以考虑分成两次提交。暂存区就是让你做这个挑拣动作的地方。区域对应命令存放形式说明工作区编辑文件实际文件你看到的目录内容暂存区git add索引文件下次提交的内容清单本地仓库git commit提交对象完整历史可离线查看远端仓库git push远端副本GitHub 等平台上的副本再加上远端仓库就有了四种状态的流转未跟踪、已修改、已暂存、已提交。git status干的事就是告诉你每个文件现在处于哪个状态。我强烈建议在初学阶段养成习惯每次动手前先跑一遍git status它会直接告诉你下一步该敲什么。2. 环境搭建Git 安装与首次配置踩坑记录2.1 Windows 下安装 Git 的完整流程与选项解读Windows 上的安装包从官网或国内高校镜像站都能下到装的时候大部分选项保持默认即可但有几个关键页面值得停下来看一眼因为这决定了你后面用命令行的体验。Adjusting your PATH environment这一页默认选项是 Git from the command line and also from 3rd-party software。这个选项会把 Git 的可执行目录加进系统 PATH装完之后你在 PowerShell 或 CMD 里直接敲git就能用。如果选了别的选项比如只让 Git Bash 使用那你就会在 CMD 里收到那句经典报错无法将git项识别为 cmdlet、函数、脚本文件或可运行程序的名称。遇到这个报错不用慌重装一遍选对选项或者手动把安装目录下的cmd文件夹加到环境变量 Path 里就行。Configuring the line ending conversions这一页是换行符转换跨平台协作的老大难。Windows 用 CRLFLinux 和 macOS 用 LF。默认的 Checkout Windows-style, commit Unix-style 对应core.autocrlftrue是 Windows 单人开发的稳妥选择。剩下的编辑器选择、默认分支名、凭据管理器默认值都够用。凭据管理器建议保持开启它会把你第一次输入的凭据存进系统的凭据管理器后面推拉代码就不用反复输入了。提示安装完成后打开一个新的终端窗口再敲git --version验证是否真的能全局调用。已经开着的终端不会自动刷新环境变量很多人就是在这里怀疑自己装失败了。2.2 首次配置用户名、邮箱与换行符装完立刻要做的一件事是配置身份。Git 的每次提交都会记录作者信息如果没配置提交时会直接报错或者在某些环境里用主机的默认值凑合导致历史记录里出现一串奇怪的作者名。git config --global user.name Your Name git config --global user.email your_emailexample.com git config --global init.defaultBranch main git config --global core.autocrlf true这几行的作用分别是设置提交时显示的作者名、设置邮箱、把新仓库的默认分支名定为mainGit 2.28 之前的版本默认还是master统一一下能避免和远端仓库对不上、设置换行符自动转换。邮箱这里有个细节值得提如果你希望 GitHub 把你本地提交和账号关联起来邮箱要和你 GitHub 账号里验证过的邮箱一致或者用 GitHub 提供的隐私邮箱。如果只写了一个随便编的地址提交在 GitHub 网页上就不会显示你的头像和账号链接。配置是有层级优先级的从高到低是--local当前仓库、--global当前用户、--system整台机器。同一个配置项--local会覆盖--global。查看当前所有生效配置直接跑git config --list --show-origin加上--show-origin能看到每一项来自哪个配置文件排查为什么我的配置没生效时特别有用。2.3 命令行与图形化客户端怎么选网上经常有人问是不是该用小乌龟TortoiseGit这类图形化客户端。我的实际做法是两个一起用各管各的场景。命令行是底层的真相。所有图形工具都是对命令的封装遇到冲突、回滚、rebase 这类稍复杂的操作图形界面要么藏得太深要么直接不给你这个选项。碰上问题的时候你还是得回到命令行看它到底在说什么。图形客户端擅长的是两件事一是看差异左右对比的着色视图比git diff的输出直观太多二是挑选提交内容用鼠标勾选要暂存的行比记git add -p的交互按键舒服。所以合理的分工是日常提交、切分支、推拉用命令行代码审查看 diff、处理局部暂存用图形工具。TortoiseGit 在 Windows 上和资源管理器集成得很好文件图标上的绿勾红叹号能让你一眼看出哪些文件被改过这个提示本身就有价值。注意TortoiseGit 是独立的客户端它需要本机已经装好 Git 才能工作。安装顺序是先装 Git再装 TortoiseGit。装反了会报找不到 git.exe。3. 本地仓库实操从初始化到第一次提交3.1 初始化、暂存、提交的完整闭环假设你有一个现成的项目文件夹想让它进入版本控制。进入项目根目录执行git init git statusgit init会在当前目录下生成一个隐藏的.git文件夹这就是本地仓库的全部内容。.git里存着对象库、引用、配置、钩子脚本删掉它等于把这个目录的版本历史一笔勾销。注意千万别在项目根目录之外误执行init更不要在主目录下乱跑这个命令否则你会得到一个覆盖整个用户目录的仓库之后每次git status都慢得让人怀疑人生。初始化之后git status会列出所有未跟踪文件。第一次提交通常文件很多可以整体添加git add . git commit -m chore: initialize project structure git log --oneline这里解释一下git add的几个变体它们的差异在实际操作中会踩到命令作用范围是否处理删除git add .当前目录及子目录是Git 2.0 起git add -A整个仓库是git add -u已被跟踪的文件是git add file指定文件否在仓库根目录执行时git add .和git add -A效果基本一致但如果你在某个子目录里执行两者范围就不一样了这一点在大型项目里很容易出错。提交信息的写法我建议从第一天就用规范格式。前缀用动词简短说明做了什么需要时在正文补充原因。这不是形式主义等你半年后需要查哪个提交引入了这个 bug时规范的信息能让你用关键词直接搜到而不是一个个点开看。3.2 .gitignore 怎么写才不返工.gitignore是项目里的排除清单。没有它你会把依赖目录、编译产物、日志、本地配置文件、密钥文件全部提交进去仓库体积膨胀得飞快还容易泄露敏感信息。一个可用的起步模板长这样# 依赖目录 node_modules/ venv/ __pycache__/ # 构建产物 dist/ build/ *.pyc *.class # 编辑器与系统文件 .vscode/ .idea/ .DS_Store Thumbs.db # 本地配置与密钥 .env .env.local *.pem *.key # 日志 logs/ *.log语法上要记住几条/开头表示从仓库根目录开始匹配末尾/表示只匹配目录*匹配任意字符但不跨目录**可以跨目录匹配!开头表示取反把之前排除的重新包含进来。!这个用法容易被忽略但很实用比如你想忽略整个config/目录但保留config/default.jsonconfig/* !config/default.json最容易踩的坑是已经被跟踪的文件加进 .gitignore 不会生效。因为 .gitignore 只对未跟踪文件起作用。处理办法是先把它从索引里移除但保留工作区的实际文件git rm --cached .env git rm -r --cached node_modules git commit -m chore: remove ignored files from index3.3 查看历史与安全回退reset、revert、checkout 的边界git log是每天都要用的命令但默认输出的信息密度太低。我个人习惯的查看方式是git log --oneline --graph --all --decorate它会把提交画成一行一个的简图标出各分支位置和标签一眼看出分支的合并走向。想单独看某个提交改了什么用git show commit想看已暂存和未暂存的区别分别用git diff --staged和git diff。回退是新手最怕的部分其实只要分清三个命令的适用场景就稳了。git reset是移动分支指针操作对象是本地历史。它有三个模式差异在于是否动暂存区和工作区模式分支指针暂存区工作区适用场景--soft回退保留保留想把几个提交合并成一个重新提交--mixed默认回退重置保留提交内容写错了想重新挑文件--hard回退重置重置彻底丢弃最危险--hard会直接覆盖工作区的文件内容没提交的改动会永久消失。用之前先跑一次git status确认没有想保留的东西。git revert的作用是生成一个反向提交来抵消某次修改。它不重写历史而是在末尾追加一个新提交。已经推到远端、别人可能已经拉过的提交只能用 revert不能用 reset因为 reset 会把历史抹掉导致别人本地的历史和远端对不上。万一真的用 reset 删过头了别急着重新写代码先跑git reflog。它会列出 HEAD 的移动记录包括所有被你回退掉的操作找到对应的哈希值再git reset --hard 哈希就能救回来。这个命令救过我不止一次默认的 reflog 记录会保留一段时间所以发现越早越好。注意git checkout file会用最近一次提交的版本覆盖工作区文件未提交的修改直接丢掉且不在 reflog 里。这个命令比 reset --hard 更隐蔽用之前务必确认。4. 远程协作仓库创建、密钥配置与推送4.1 创建远端仓库与两种连接方式的取舍在 GitHub 上点新建仓库时页面上有几个选项要知道含义。公开和私有决定谁能看初始化 README如果勾上远端会先有一个提交这时候你本地push就会遇到 Updates were rejected because the remote contains work that you do not have locally 的报错因为两边的历史是各自独立开始的。解决方式是先git pull --rebase origin main把远端历史拉下来并把自己的提交放到后面再推。本地关联远端并推送的标准动作git remote add origin gitgithub.com:username/repo.git git branch -M main git push -u origin main-u参数是设置上游分支设置之后以后直接敲git push和git pull就不用再带仓库名和分支名了。这个参数新手经常漏掉然后抱怨每次都要敲一长串。连接方式有 HTTPS 和 SSH 两种。HTTPS 的地址形如https://github.com/username/repo.git优点是配置简单、网络环境限制少缺点是需要凭据而且现在不能用账号密码得用个人访问令牌。SSH 的地址形如gitgithub.com:username/repo.git配好密钥之后完全免密日常高频推拉更省事。我的建议是主力用 SSH遇到网络波动时临时切 HTTPSgit remote set-url origin https://github.com/username/repo.git git remote -v另外提一个实用做法远端可以配多个。比如同时配一个origin指向 GitHub再配一个backup指向国内代码托管平台。国内服务器上部署时从backup拉代码速度和稳定性都会好一些代码本身两边保持同步。git remote add backup https://gitee.com/username/repo.git git push backup main4.2 生成密钥与免密配置SSH 密钥用一条命令生成现在推荐用 ed25519 算法比传统的 RSA 更短更安全ssh-keygen -t ed25519 -C your_emailexample.com执行后会问你保存路径直接回车用默认位置。然后问你要不要设密码短语设了更安全但每次用都要输本机是个人电脑的话可以不设图省事。生成完后公钥在~/.ssh/id_ed25519.pub把它整个内容复制出来粘贴到 GitHub 的 Settings → SSH and GPG keys → New SSH key 里。注意是.pub结尾的那个公钥文件不是没后缀的私钥。私钥是绝对不能外传的谁拿到谁就能以你的身份操作仓库。配置完成后验证一下ssh -T gitgithub.com看到类似 Hi username! Youve successfully authenticated 的提示就说明通了。注意如果你有多台设备或者多个账号可以在~/.ssh/config里给不同主机配不同的密钥文件避免密钥冲突导致验证失败。这一步在企业内网环境中用得很多。4.3 分支策略从单干到团队的分级方案分支策略没有标准答案取决于团队规模和发布节奏。我把常见的三档方案列出来你对号入座。单人项目或小工具直接用main一条线每次改动前开个短分支改完合回来删掉。够用且简单。两到五人的持续交付项目主干加短分支。main永远保持可发布状态功能分支命名feature/xxx修 bug 用fix/xxx改完提 Pull Request 合并。分支存活时间控制在两三天以内避免长期分支和主干越差越远。有版本发布节奏的项目Git Flow 那套。main存发布版本develop做集成分支feature/*从 develop 切出release/*准备发版hotfix/*处理线上紧急问题。这套流程规范但偏重分支多、合并多小团队用起来会觉得累。分支生命周期来源合并目标main永久初始无develop永久mainreleasefeature/*短期developdeveloprelease/*短期developmain 和 develophotfix/*短期mainmain 和 develop常用分支操作git switch -c feature/login git switch main git branch -d feature/login git push origin --delete feature/logingit switch是较新版本引入的命令专门用来切分支比git checkout语义更清晰checkout 既能切分支又能恢复文件容易误操作。新版本 Git 里建议优先用switch和restore。4.4 团队协作流程Pull Request 与代码评审多人协作里最值得养成的习惯是走 Pull Request而不是直接往main推。PR 的价值有三点改动可见、有讨论记录、可以配置自动化检查构建、测试、格式检查。典型流程是这样的先把远端最新状态同步到本地再开分支开发完成后推到远端然后在网页上发起 PR指定评审人。评审通过后由负责人合并合并方式一般选 squash merge把分支上的多个提交压成一个干净的提交进主干。git switch main git pull --rebase git switch -c feature/order-export # 开发... git add . git commit -m feat: 增加订单导出功能 git push -u origin feature/order-export关于git pull这里有个建议默认的 pull 行为在不同 Git 版本下不一致有的 merge、有的 rebase会在历史里留下一堆没意义的合并提交。我个人的做法是统一配置成 rebase 拉取git config --global pull.rebase true这样本地未推送的提交会被放到远端最新提交之后历史保持一条直线看起来干净很多。代价是如果本地有冲突需要手动解决。提示修改提交信息里的换行、缩进这类细节不涉及合规问题但提交信息本身要写清楚意图。我见过有人 PR 里十几个提交全是 fix、update、aaa评审人根本不知道从哪看起。5. 分支与合并冲突处理与历史整理5.1 合并的两种方式与选择依据把一个分支的改动合进另一个分支Git 有两种方式merge 和 rebase理解差异对团队协作很重要。git merge会创建一个新的合并提交把两条历史线汇到一起。历史呈网状保留了完整的分支轨迹适合合并到主干这种需要留痕的场景。git rebase的做法是把当前分支的提交一个个摘下来重新接到目标分支的最新提交后面。历史变成一条直线非常整洁但它重写了提交哈希。理解哈希变化的意义很关键如果你的分支已经推到远端并且别人基于它做了工作你一 rebase 再强推别人的本地历史就和远端彻底分叉了他得手动处理一堆乱七八糟的冲突。所以有条铁律注意已经推送到共享分支的提交不要 rebase。只对本地未推送的提交做 rebase 整理。合并时还有一个参数值得知道--no-ff。它强制生成合并提交即使可以快进合并fast-forward。好处是分支的存在痕迹被保留下来将来查这个功能是哪次合并进来的能一眼找到边界。git switch main git merge --no-ff feature/login5.2 冲突是怎么产生的怎么解得干净冲突的根源是同一个文件的同一块区域被两边分别改了Git 无法自动判断该保留哪个。注意同一块区域这个条件两个人改同一个文件的不同部分通常不会冲突Git 能自动合并。发生冲突时文件里会出现这样的标记 HEAD const timeout 3000; const timeout 5000; feature/config HEAD到之间是当前分支的内容到之间是合过来的分支的内容。解决冲突就是手工编辑这段决定最终留哪一版或者两个都留但逻辑上要能跑通然后把所有标记行删掉。解决步骤git status # 查看哪些文件冲突 # 手工编辑冲突文件删掉冲突标记 git add 已解决的文件 git commit # merge 场景下会生成合并提交如果是 rebase 过程中遇到冲突处理完用git rebase --continue继续想放弃就git rebase --abort回到 rebase 之前的状态。几条实战经验。第一解冲突不要只看冲突块本身要往上往下多看几十行理解上下文否则很容易解出一个语法正确但逻辑错误的版本。第二解完一定要跑一遍测试或至少启动一次项目Git 只保证文本层面合并成功不保证语义正确。第三冲突块超过五处的时候考虑跟对方当面过一遍比来回改效率高得多。5.3 临时切换stash 的正确用法开发到一半被叫去修线上 bug代码还不完整不想提交这时候用git stash把工作区暂存起来。git stash push -m 订单导出草稿 git switch main git switch -c hotfix/pay-timeout # 修完合并... git switch feature/order-export git stash popgit stash pop会恢复并删除这条 stash 记录git stash apply则恢复但保留记录。想查看所有 stash 用git stash list。要留意的坑是stash 默认不包含未跟踪的新文件得加-u参数才会带上。很多人 stash 完切分支再切回来发现新建的文件不见了其实一直都在工作区只是当时没被 stash 带走逻辑上不矛盾但容易吓一跳。6. 常见问题与排查速查6.1 高频报错速查表下面这张表是我这些年遇到频率最高的报错基本覆盖了日常九成的问题。报错信息触发原因解决思路无法将git项识别为 cmdlet安装时没加 PATH 或终端未重启重装并勾选命令行选项或手动配置环境变量重启终端Updates were rejected远端有本地没有的提交先git pull --rebase再 pushfatal: refusing to merge unrelated histories两边历史独立确认无误后git pull --allow-unrelated-historiesPermission denied (publickey)SSH 密钥未配置或未加载检查公钥是否已添加到平台用ssh -T验证Support for password authentication was removed用了账号密码做 HTTPS 认证改用个人访问令牌或个人密钥src refspec main does not match any本地还没提交或分支名拼错先 commit确认分支名用git branch查看Your local changes would be overwritten切换分支时未提交改动冲突先 commit 或 stash 再切LF will be replaced by CRLF换行符配置不一致统一core.autocrlf必要时git add --renormalize .排查的基本方法论是先看git status确认当前状态再看报错里的关键词定位到是网络问题、权限问题还是历史分叉问题。这三类占了绝大多数剩下的才需要单独查。6.2 几个容易被忽略的安全与性能细节部署环节有个隐患值得单独说。有些人把项目直接上传到 Web 服务器目录时没注意把.git一起传上去了。这个目录里包含完整的提交历史和配置通过浏览器就能访问到里面的文件。防护很简单在服务器配置里加一条拒绝规则比如 Nginx 里location ~ /\.git { deny all; return 404; }历史提交里如果曾经硬编码过数据库密码、接口密钥光删掉文件是没用的历史记录里还留着。正确做法是把这些密钥全部作废并重新生成再用git filter-repo之类工具清理历史最后强制推送并通知所有协作者重新克隆。另一个是仓库体积问题。二进制大文件、数据集、视频素材这类东西提交进去之后每次克隆都要下载全部历史版本仓库很快就变得没法用。这类文件要么放对象存储要么用 Git LFS 管理。判断标准很简单如果一个文件超过了 10MB 且会多次修改就不适合直接提交。.gitignore生效范围的检查也有个小技巧文件已经被忽略但你不确定是哪条规则命中的用git check-ignore -v path/to/file它会告诉你具体是哪个 .gitignore 文件里的哪一行规则匹配到了。6.3 日常命令清单与个人习惯最后整理一份高频命令清单贴在顺手的地方前两周基本靠它渡过。# 状态与历史 git status git log --oneline --graph --all --decorate git diff git diff --staged # 提交 git add . git add -p git commit -m feat: xxx git commit --amend # 分支 git switch -c feature/xxx git branch -a git merge --no-ff feature/xxx git branch -d feature/xxx # 远端 git remote -v git fetch --all --prune git pull --rebase git push -u origin main # 回退与救援 git restore file git reset --soft HEAD~1 git revert commit git reflog git stash push -u -m msg关于提交信息前缀我一直在用这一套团队里推广过一次之后大家就统一了前缀含义场景举例feat新功能feat: 增加批量导入fix修 bugfix: 修正分页越界docs文档docs: 补充部署说明refactor重构refactor: 抽取公共请求方法style格式调整style: 统一缩进为两空格chore杂项chore: 升级依赖版本test测试test: 补充登录用例最后分享一个我坚持了好几年的小习惯。每天收工前跑一遍git status和git log --oneline -5确认今天的改动都提交了、提交信息能看懂、没有把不该提交的文件带进去。这个动作不到一分钟但能省掉大量第二天早上我昨天改的东西去哪了的时间。还有一条改代码前先拉一次远端改完立刻推别攒着。攒三天再推等着你的就是一场冲突大戏而且那时候你已经记不清每处改动为什么那么写了。
返回列表