ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

从零开始用Git命令行上传项目到GitHub的完整指南

从零开始用Git命令行上传项目到GitHub的完整指南 1. 上手前的准备工作账号、环境与仓库规划很多人第一次上传项目到GitHub都是被老师、同事或者某个开源项目“逼”着开始的。最典型的场景是本地代码写了一堆想同步到云端备份或者想让别人看到自己的项目结果打开GitHub官网盯着“Upload files”按钮心想“直接把文件夹拖上去不就行了吗”说实话这个小按钮确实能传文件但仅限于小项目、一次性上传。一旦牵扯到多个分支、多人协作、持续更新网页端上传就是个灾难——文件覆盖没有历史记录、冲突难以处理、代码review无从谈起。所以这篇文章我带你走一条真正靠谱的路用Git命令行把项目完整、规范地上传到GitHub。这套流程既能满足个人备份也能支撑团队协作是每个开发者都应该熟练到肌肉记忆的基本功。在动手敲命令之前先把三件事准备好一个GitHub账号、本地安装好的Git环境、一个想上传的项目目录。账号注册我就不展开了但有一个细节要提醒用户名一旦定下来以后对外展示、PR署名都会一直用它所以尽量取一个专业、好记、和你的技术方向相关的名字别用“xiaoming2024”这种看着像小号的名字。Git的安装同样不啰嗦Windows用户直接去官网下载安装包macOS用户用brew install gitLinux用户用发行版自带的包管理器装完后打开终端敲一句git --version能输出版本号就说明环境通了。接下来是仓库规划。很多新手一上来就急着git init但我觉得先花两分钟想清楚几件事能帮你后面少走弯路第一这个项目是公开还是私有如果只是自己写的小工具、课程作业、还不成熟的想法建议先用私有仓库private等稳定了再转公开。第二项目大概会承载多少文件是否有图片、视频、依赖包这类大体积文件这影响到后面要不要配置.gitignore甚至要不要启用Git LFS大文件存储。第三项目是否需要开放给社区贡献如果打算让别人参与那README、License、贡献指南这些文档一开始就要规划。这些问题不需要在第一次上传时就全部解决但心中有个数后面每一步都更顺。仓库规划还有一种更省心的方式事前拉一个“模板仓库”。GitHub本身就提供了一些公开的项目模板比如各类前端工程、Python包工程、数据科学项目模板你也可以自己在组织内维护一套标准模板。第一次上传时直接把这个模板克隆下来把业务代码放进去比自己从零初始化要规范得多。当然如果项目极其简单比如只有一个index.html那就不用矫情直接初始化就好。环境准备还有一个常被忽略但非常重要的事情配置SSH密钥。使用SSH协议连接GitHub比HTTPS协议更稳定而且不用每次push都输入密码。虽然现在GitHub已经不再支持账号密码直接push而是改用personal access tokenPAT但说句实话配置好SSH之后体验是最接近“一劳永逸”的。2. 首次上传的完整流程从git init到push2.1 初始化本地仓库一切就绪后打开终端进入你的项目目录。这里要特别强调不是进入项目目录的父文件夹而是进入项目本身那一层。比如你的项目叫myblog里面的文件直接就是index.html、src/、docs/这些那就cd myblog然后执行git init这条命令会在当前目录创建一个隐藏的.git文件夹这个文件夹就是Git的“数据库”所有版本历史、分支信息都藏在里面。初始化成功后Git会自动进入主分支老版本默认叫master新版本Git 2.28可能叫main。这两个名字没有本质对错但现在GitHub新仓库默认分支统一叫main我建议你后面统一用main避免不必要的认知负担。初始化完成后先别急着git add .。花点时间检查一下项目里有没有不需要上传的东西比如node_modules、__pycache__、*.log、本地配置文件.env、IDE缓存目录.idea、.vscode。这些文件严重影响仓库整洁度还可能是安全漏洞比如把密钥传上去。正确的做法是提前写一个.gitignore文件把不需要追踪的文件统统列进去。.gitignore的写法很人性化支持通配符和目录匹配。比如# 依赖目录 node_modules/ vendor/ # 编译产物 dist/ build/ *.pyc # 环境变量与本地配置 .env config.local.json # 系统文件 .DS_Store Thumbs.db # 日志 *.log如果你不记得该忽略什么GitHub官方维护了一组常用语言的.gitignore模板在新建仓库时可以直接勾选生成也可以在仓库的github/gitignore项目里找到对应文件拷过来用。一个人也要像一支队伍规范一开始就立好后面不痛苦。2.2 暂存与提交理解add和commit准备做完后把文件加入Git的暂存区git add ..代表当前目录下所有未被忽略的文件。执行完以后你可以用git status查看暂存状态绿色的文件说明已经准备好被提交了。很多新手不理解为什么需要“暂存区”这个中间地带我用一个生活化类比解释一下git add像是把要寄走的物品放进快递箱git commit才是封箱并贴上运单号。你可以陆续放进不同物品但只有封箱之后才形成一个可追踪的包裹。好处是你可以分批次、按逻辑组合提交而不是一次把所有改动揉成一坨。提交的瞬间Git会要求你填写提交信息。直接用git commit -m first commit虽然能跑但如果你想让历史记录清晰可读建议遵循一些约定俗成的格式。目前社区比较流行的是Conventional Commits风格大概长这样feat: 新增用户注册功能 fix: 修复登录页在Safari下的样式错乱 docs: 补充部署说明文档 refactor: 重构数据解析模块格式很简单类型 冒号 简短描述。类型包括feat新功能、fix修复、docs文档、style格式调整、refactor重构、test测试、chore构建或杂务等。提交信息建议用英文还是中文说实话个人项目用中文完全没问题团队项目则跟着文档规范走。真正重要的是信息本身能准确描述这次改动的意图而不是写得像“乱七八糟”“update”“aaa”这种毫无信息量的词。首次提交最好先在当前分支上做一次“初始提交”也就是把整个项目的现状作为历史的起点git branch -M main git commit -m feat: 初始化项目框架-M main的意思是强制把当前分支重命名为main。如果刚才git init后分支本来就是main这条命令不会产生副作用但写上它能让流程在任何环境下都保持一致。2.3 关联远程仓库与首次push本地提交完成接下来就要和GitHub“结对”。回到GitHub网页点击右上角的“”号选择“New repository”填写仓库名。仓库名建议和本地项目文件夹名保持一致比如本地叫myblog仓库名也叫myblog这样对应关系清晰。创建仓库时可以选择公开或私有最好先别勾选“Add a README file”“Add .gitignore”这些初始化选项——如果你勾了远程就会先产生一次提交等下本地和远程就变成了两个互不相干的历史第一次push时还得先合并平白无故增加麻烦。创建完成后GitHub页面会显示一段命令让你把本地仓库推上去。核心步骤其实是两条。先添加远程地址git remote add origin gitgithub.com:你的用户名/myblog.git这里我用的是SSH协议的地址。如果你是HTTPS流派地址是https://github.com/你的用户名/myblog.git但第一次连接会要求输入用户名和token多一道手续。SSH地址需要你事先把公钥添加到GitHub账户的Settings - SSH and GPG keys里生成密钥的命令如下ssh-keygen -t ed25519 -C youremailexample.com一路回车就行生成完成后把~/.ssh/id_ed25519.pub里面的内容复制到GitHub。测试连接用ssh -T gitgithub.com看到Hi 用户名! Youve successfully authenticated就说明通了。这个准备工作值得花时间因为以后每次克隆、拉取、推送都不需要输密码特别是配合ssh-agent体验非常丝滑。远程地址配置好后第一次push要特别带上-u参数git push -u origin main-u的全称是--set-upstream意思是把本地的main分支和远程的main分支建立追踪关系。建立之后以后你再push就能直接敲git push不需要重复指定分支名。可以说这行命令是整篇操作中最有“仪式感”的一步——执行完看到输出里出现main - main你的项目就正式在GitHub上安家了。3. 文档与规范让项目一眼看去很专业3.1 README项目的门面代码推上去了但如果你的仓库只有一个光秃秃的目录访问者看到的第一反应是“这项目是干嘛的怎么用”所以一个规范的GitHub项目README文件是必需品。Markdown格式的README.md放在仓库根目录GitHub会自动在仓库首页渲染它。一份合格的README应该包含哪些信息我用一个模板帮你梳理项目名称和一句话介绍——用一句话说清楚“这是干什么的”。功能特性列表——让读者快速了解亮点。环境要求与安装步骤——从克隆到跑起来的具体命令。使用示例——最好带代码块和预期输出。项目结构说明——简单标注每个目录的作用。参与贡献的方式——如何提Issue、如何提PR。开源协议与作者信息。不需要一次写完但至少要把“一句话介绍”和“安装步骤”补齐。有意思的是很多开发者看仓库第一眼就是扫README如果扫完还没弄懂这项目是干嘛的直接划走。所以哪怕你只是上传一个课程作业也值得花半小时把它写成“不像作业”的样子。3.2 LICENSE开源的法律边界很多个人项目上传者会忽略LICENSE但它其实特别重要。没有LICENSE的仓库从法律角度讲默认是“保留所有权利”别人虽然能看到你的代码但并没有被正式授权去使用、修改、分发。如果你希望别人能用你的代码就必须显式声明一个开源协议。选哪种协议取决于你的意图。MIT协议最宽松允许别人随便用只要保留版权声明Apache 2.0类似MIT但额外包含专利授权条款GPL协议则是“传染性”的要求基于你代码的衍生作品也必须开源。GitHub在新建仓库时可以直接选择LICENSE模板创建后会自动生成LICENSE文件。个人项目如果懒得研究从MIT开始准没错。这个选择不紧急但早做比晚做好不然别人想给你贡献代码看到没LICENSE也只能犹豫。3.3 项目目录结构与CHANGELOG除了README和LICENSE还有两个小细节能让项目显得更规范。一个是项目目录结构本身要清晰比如源码放src/文档放docs/测试放tests/示例放examples/。这种约定俗成的结构让别人以及未来的你找东西时不用猜。另一个是CHANGELOG.md记录每个版本的变更摘要。很多个人项目觉得没必要但当你发布过几个release之后回看CHANGELOG能快速回忆某个改动是哪个版本引入的配合GitHub的Release功能非常好用。不过也要提醒一句文档规范要适度。给一个玩具项目写一百页文档和给一个开源框架不写README都是走极端。我的建议是先写一个能让人跑起来的READMELICENSE选一个目录结构按习惯来其他文档等到项目确实需要了再补。GitHub是一个展示代码的地方代码本身的可读性和注释质量永远比文档篇幅更重要。4. 后续更新与协作流程从个人到团队4.1 日常更新的标准动作项目上传完成后日常更新的套路其实就三招git add、git commit、git push。但我见过太多人在这三步上出问题主要原因是分不清什么时候该add、什么时候该commit、什么时候该push。我个人的工作习惯是写代码的时候不改动任何Git状态一个功能做完先自己跑一遍测试然后git add相关的文件再git commit。先add再commit之间我会用git diff --cached看一眼即将提交的内容确认没有把无关的改动卷进来。推送到远程前如果这是多人协作的项目我会先git pull拉取远程最新代码解决冲突后再push。这样循环下来每一步都有明确目的不会出现“乱七八糟的commit历史”。一个值得养成的习惯是“小而频繁的提交”。不要攒了一周的工作量然后一次性提交那样commit信息根本写不清楚。理想状态下每完成一个逻辑单元就提交一次比如“修复了某个bug”“新增了某个接口”。这样万一某个改动出了问题你可以快速定位并回滚而不是在几千行diff里找针。4.2 分支管理与Pull Request如果你只是自己一个人开发直接在main分支上提交也不是不行。但只要你开始和任何人协作——哪怕只是帮朋友改个bug——分支管理和Pull Request简称PR就是必须掌握的技能。最简单的协作模型是GitHub Flowmain分支永远是稳定可发布的所有新功能、修复都开一个独立的分支来开发开发完提交PR经过审查后合并回main。实际操作中你只需要几条命令git checkout -b feature/login开一个名叫feature/login的分支然后在这个分支上正常提交代码。开发完成后先推到远程同名分支git push -u origin feature/login然后在GitHub仓库页面上会出现一个提示条问你要不要为这个分支创建PR。点进去之后填写PR标题和描述说明你做了什么、为什么这么做、测试了哪些场景然后点击“Create pull request”。后续的讨论、代码审查都在这个PR页面里进行所有改动以“对话”的形式沉淀下来比微信聊天记录靠谱一万倍。PR还有一个隐藏好处GitHub提供免费的CI/CD集成。你可以在PR中自动运行测试、检查代码格式合并前确保所有检查通过。GitHub Actions的配置文件放在.github/workflows/目录下对一些热门语言有现成模板可以直接用。比如一个简单的Node.js项目可以配置这样一段工作流简化版name: CI on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - uses: actions/setup-nodev4 with: node-version: 20 - run: npm ci - run: npm test配置好之后每次push代码GitHub就会自动拉起一个虚拟机跑测试通过会显示绿色勾失败会显示红色叉。这个过程帮你把很多低级错误在合并前就拦住了。4.3 Issue、提交信息规范与Release发布除了PR还有几个协作“配件”值得花篇幅讲。Issue是用来追踪bug和功能需求的工具你在GitHub仓库的“Issues”标签页可以新建Issue描述你发现的问题或想做的功能。规范的Issue模板通常包含问题描述、复现步骤、期望行为、实际行为、环境信息。多人项目里Issue就是团队的待办清单每完成一个就关闭一个历史记录一目了然。提交信息规范前面提过Conventional Commits在协作场景里它的价值更明显。比如你维护一个开源库通过自动化工具可以从规范的commit信息里自动生成CHANGELOG还能根据commit类型自动判断版本号应该升minor还是patch。虽然这些工具配置起来有点门槛但底层逻辑就是“提交信息越规范自动化越省心”。如果你现在还是一个人写项目至少从今天开始让每次commit信息都言之有物。Release功能是在代码打好tag之后发布的版本的快照。GitHub的Release页面可以上传二进制文件比如安装包、编译产物也可以只发布源码压缩包。发布Release前你需要先打taggit tag v1.0.0 git push origin v1.0.0之后在GitHub网页上选择这个tag填写发布说明就能生成一个带版本号、发布说明和附件下载的Release页面。这不仅是给别人用的入口也会在仓库首页生成“Releases”区块显得项目专业感十足。5. 常见问题与避坑记录实操中的高频事故现场5.1 认证失败与token配置第一次push时很多人会遇到fatal: Authentication failed。如果在HTTPS协议下GitHub早已不再接受账号密码认证你在终端里输入的密码必须是personal access tokenPAT。生成方式GitHub头像 - Settings - Developer settings - Personal access tokens - Tokens (classic)勾选repo权限生成的一长串字符串就是你的“密码”。备注一下这个token给人牙酸的印象它在Git的配置里一旦保存直到失效前都不需要重新输入。避免反复输入token的优雅方式是用gh命令行工具登录一次就能管理仓库、PR、Issue。安装后执行gh auth login按提示选择GitHub.com、选择HTTPS或SSH、粘贴token或浏览器登录一次性搞定。之后gh repo create myblog --public --source. --remoteorigin --push这一条命令就能直接完成“创建远程仓库并推代码”全套操作非常推荐给嫌网页端麻烦的朋友。5.2 拒绝推送rejected与冲突处理push时最打击新手的报错是![rejected] main - main (fetch first)意思是远程仓库有一些本地没有的提交。常见原因是你之前在网页端新建仓库时顺便勾了“Add a README”或者别人向这个分支推送了新代码。解决办法很简单先拉取远程更新再推送。git pull origin main --rebase git push origin main--rebase的作用是把本地的提交“重新放”到远程提交的后面形成一条没有分叉的线性历史。如果你看到CONFLICT字样说明两个提交改到了同一个文件的同一段内容Git无法自动合并。这种情况下只能用编辑器手动打开冲突文件里面会有一段特殊标记 HEAD 当前分支的内容 远程分支的内容 远程分支的内容你需要人工决定保留哪部分、删掉哪部分修改完成后保存然后执行git add 那个文件 git rebase --continue有冲突并不可怕可怕的是慌不择路地乱敲命令。记住只要没有git push -f本地历史就没那么容易被覆盖一切都有挽回空间。不过这里也要提一句push -f是把双刃剑它在大部分场景下应该被禁止使用尤其不要对公共分支强制执行否则别人的提交可能直接被抹掉这是团队协作中的大忌。5.3 误提交文件与.gitignore失效“不小心把.env文件提交上去了”是安全事故高发区。如果只是内部使用你可以直接从仓库中移除追踪同时保留本地文件git rm --cached .env echo .env .gitignore git commit -m chore: 移除.env的追踪如果文件已经推送到了远程这套操作会让它在远程消失但历史记录里仍然存在这个文件的快照——如果里面有关键内容强烈建议同时轮换这些密钥、token或密码。市面上也有工具能帮你批量清洗历史记录比如git filter-repo但“清洗历史”是个侵入性操作思路是重建仓库历史建议在确实需要时才用并且要有全量备份。还有一个现象很常见明明在.gitignore里写了node_modules/但git status还是能看到node_modules下的文件。原因多半是node_modules在.gitignore生效之前就已经被git add追踪了。Git的规则是已被追踪的文件不受.gitignore影响。解决办法就是先git rm -r --cached node_modules再提交一次之后.gitignore才真正起作用。5.4 换行符与编码相关坑跨平台协作时最容易引发莫名diff的就是换行符问题。Windows默认使用CRLF回车换行macOS和Linux使用LF换行。如果一个人用Windows一个人用macOS同一份文件的diff可能显示整份文件都变了非常令人崩溃。Git提供了一个换行符自动转换机制推荐在项目根目录放一个.gitattributes文件* textauto *.sh text eollf *.bat text eolcrlftextauto表示让Git根据内容自动判断文本文件并在提交时统一保存为LF检出时根据操作系统自动转换。.sh脚本强制使用LF.bat批处理强制使用CRLF。这算是一个写得比较妥帖的默认配置能显著减少无意义的换行符diff。如果你已经遇到了全文件diff的问题用git diff -w可以忽略空白差异先看清楚真正的代码改动。5.5 大文件与Git LFSGit是文本文件的工作利器但它天生不适合存放大型二进制文件。比如一个几十MB的视频、一个模型权重文件每次都全量存储一份历史快照仓库会迅速膨胀到几个GB。GitHub单个文件超过50MB会给出警告超过100MB会直接拒绝push。解决方案有两个第一不做版本控制的大文件比如安装包、压缩包直接放进.gitignore需要分发给别人的用Release附件的功能第二确实需要追踪的二进制大文件使用Git LFSLarge File Storage。启用方式是在仓库根目录添加.gitattributes并运行git lfs install git lfs track *.psd git add .gitattributes配置好后匹配这些模式的文件会以“指针对象存储”的方式管理不会拖垮整个仓库。免费额度是每月1GB的存储和1GB的带宽个人项目通常够用。5.6 子模块与分支混乱有些项目需要依赖另一个Git仓库的特定目录比如你的项目用到了自己维护的公共组件。这里有两个选择把公共组件打成npm包、Python包之类的东西通过包管理器引入或者用git submodule引入整个外部仓库。我个人的建议是能不用submodule就不用因为子模块的更新、切换、克隆都多一道工序新手很容易在git clone后忘记加--recursive导致子模块目录为空。如果确实要用记住两条命令git submodule add https://github.com/xxx/yyy.git path/to/sub git clone --recursive 主仓库地址分支混乱的问题同样常见。新手有时在master分支开发有时切到main分支导致push的目标混乱。如果发现本地有多个初始化分支可以把不需要的删掉统一以main为唯一主干。清理分支用git branch -D old-branch删除远程分支用git push origin --delete old-branch干净利落不留尾巴。6. 最后再分享一个提升效率的小习惯GitHub上传项目这件事说到底是“用Git来管理代码历史”的入门练习。当你把整套流程跑顺了你会发现每天开终端敲git status的次数比打开IDE的次数还多。这是好事说明你已经把版本控制内化成了开发的一部分。我自己实践下来最受益的一个习惯是每次开始新功能之前先看一眼远程仓库的最新状态。早上到工位先git fetch然后git status看一眼本地和远程的差距开始写代码前从main分支拉一条新的功能分支而不是直接在已有的分支上继续堆改动。这样做的代价很低但能让你的提交历史始终保持“每个分支一个主题”的清晰度。另外一个不起眼但很实用的技巧是在commit信息里关联Issue编号比如fix: 修复按钮无响应的问题 (#42)这样GitHub会自动在PR和Issue之间建立引用关系追查问题的时候顺藤摸瓜效率翻倍。上传到GitHub只是第一步坚持用规范的方式维护这个仓库才是真正拉开差距的地方。希望这篇文章能帮你把第一段“git push”跑通更重要的是让你从此养成一个专业开发者该有的版本管理习惯。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进