在项目开发过程中,我们经常会遇到这样的情况:
GitHub 上已经有一个旧版本项目,而电脑里已经修改出了一个新版本。如何用 Git 把新版本上传到 GitHub,同时保留以前的修改记录?
最近我完整走了一遍这个流程,也踩了几个比较典型的坑。这篇文章就从实际操作出发,记录如何在 macOS 上使用 Git + GitHub CLI 完成项目更新。
适合刚开始接触 Git 和 GitHub 的朋友。
一、先理解 Git 到底在干什么
很多刚接触 Git 的人会把 Git 和 GitHub 混在一起。
实际上:
Git:运行在电脑上的版本管理工具
GitHub:存放 Git 仓库的在线平台
GitHub CLI(gh):帮助我们在终端中登录和操作 GitHub
整个工作流程可以简单理解成:
电脑上的项目
↓
Git 发现文件变化
↓
git add
↓
选择准备保存的变化
↓
git commit
↓
生成一个本地版本记录
↓
git push
↓
上传到 GitHub所以,git push 只是最后一步。
真正重要的是 Git 帮我们记录:
这个版本和上一个版本相比,到底发生了什么变化。
二、我的实际需求
我的情况是:
GitHub
└── 已经存在旧版本项目
Mac
└── 已经开发出新的 1.1.0 版本我的目标并不是创建一个全新的 GitHub 项目,而是:
用电脑里的 1.1.0 替换 GitHub 当前版本,同时保留 GitHub 原来的 Commit 历史。
最终希望形成:
第一次提交
↓
第二次修改
↓
发布 1.1.0
↓
未来继续更新……这样以后不仅能看到最新代码,还能查看每个版本到底修改了什么。
三、第一步:进入项目目录
macOS 打开「终端 Terminal」。
使用:
cd "项目完整路径"例如:
cd "/Users/zane/Downloads/同步空间/个人信息/微信小程序/顺手补1.1.0"这里遇到的第一个坑就是:
cd/Users/zane/Downloads/...这样是错误的。
因为 cd 是一个命令,后面必须有空格:
cd + 空格 + 路径另外,如果路径里面包含:
中文
空格
括号
特殊字符
建议直接使用双引号:
cd "/完整/项目/路径"这是最省心的写法。
四、第二步:检查当前文件夹是不是 Git 仓库
进入项目以后执行:
git status如果出现:
fatal: Not a git repository意思就是:
当前文件夹只是一个普通文件夹,还不是 Git 仓库。
Git 仓库通常会包含一个隐藏目录:
.git这个 .git 非常重要,它记录了项目的:
Commit 历史
分支
Git 配置
远程仓库信息
版本关系
因为 GitHub 上已经有我的旧项目,并且我希望保留历史记录,所以这时候不应该简单粗暴地重新 git init。
更合适的方法是:
把 GitHub 原来的仓库 Clone 下来。
五、第三步:Clone 原来的 GitHub 仓库
先进入准备存放项目的位置,然后:
git clone https://github.com/你的用户名/你的仓库.git例如:
git clone https://github.com/KKXLIVE/Wechat_shunshoubu.gitGit 会把 GitHub 上的仓库下载到电脑。
此时得到:
Wechat_shunshoubu/
├── 项目文件
├── README.md
├── ...
└── .git/其中最重要的就是:
.git不要删除它。
因为我们后面之所以还能保留原来的 GitHub Commit 历史,就是因为这个目录还存在。
六、第四步:使用电脑里的新版本覆盖旧版本
进入刚刚 Clone 下来的仓库:
cd Wechat_shunshoubu然后把新版本项目内容复制进来。
例如:
cp -R "/Users/zane/Downloads/同步空间/个人信息/微信小程序/顺手补1.1.0/." .这条命令第一次看可能比较奇怪。
其实可以拆成:
cp -R表示递归复制文件夹。
然后:
顺手补1.1.0/.表示复制这个目录里面的内容。
最后:
.表示:
复制到当前目录。
所以整条命令可以理解成:
把「顺手补1.1.0」里面的所有项目内容复制到当前 Git 仓库。
我一开始曾经输入:
cp -R /项目路径/顺手补1.1.0然后出现:
usage: cp ...原因也很简单:
只告诉了
cp从哪里复制,却没有告诉它复制到哪里。
因此一个完整的复制命令必须同时包含:
来源 + 目标七、第五步:让 Git 检查到底发生了什么变化
复制完成以后执行:
git status这时候 Git 会自动比较:
原来的 GitHub 版本
VS
电脑里的新版本然后可能出现:
deleted: LICENSE
modified: README.md
modified: app.js
modified: env.js
Untracked files:
.gitignore
server/这里主要有三种状态。
modified
例如:
modified: app.js代表:
这个文件以前就存在,但是现在内容发生了修改。
deleted
例如:
deleted: LICENSE代表:
旧版本存在这个文件,但是新版本里已经没有了。
Untracked files
例如:
server/代表:
这是新版本中新增加的文件或目录,以前 Git 没有记录过。
这也是 Git 最强大的地方之一。
它不是简单地“重新上传整个项目”,而是在记录:
这一次版本更新相对于上一次到底改变了什么。
八、第六步:查看具体修改了什么
除了:
git status还可以使用:
git diff例如原来的代码:
const version = "1.0.0"现在修改成:
const version = "1.1.0"Git Diff 会类似显示:
- const version = "1.0.0"
+ const version = "1.1.0"其中:
- 删除的内容
+ 新增加的内容所以在正式提交之前,我比较推荐:
git status
git diff先看看自己到底改了什么。
九、第七步:一定要检查敏感文件
这是 GitHub 使用过程中非常重要的一步。
不要随便把这些东西上传到公开仓库:
.env
API Key
Secret
Token
数据库密码
服务器密码
私钥
node_modules
本地开发配置
日志文件因此项目通常需要一个:
.gitignore例如:
# macOS
.DS_Store
# Dependencies
node_modules/
# WeChat Developer Tools
project.private.config.json
*.local.*
# Build
dist/
build/
.cache/
# Secrets
.env
.env.*
secrets/
# Logs
*.log这样 Git 就会自动忽略这些文件。
十、一个容易踩坑的地方:为什么写了 .gitignore 还是会上传?
我这次就遇到了这个问题。
明明 .gitignore 已经写了:
project.private.config.json但是执行:
git status仍然显示:
modified: project.private.config.json原因是:
.gitignore主要针对还没有被 Git 跟踪的文件。
如果这个文件以前已经 Commit 过,那么 Git 已经认识它了。
即使后来把它加入 .gitignore,Git 仍然会继续跟踪。
解决方法:
git rm --cached project.private.config.json注意这里的:
--cached非常重要。
它的意思大致是:
从 Git 的版本管理中移除,但是保留电脑本地文件。
这样:
电脑:文件还在
Git:以后不再跟踪
GitHub:新版本中移除
.gitignore:以后负责忽略十一、第八步:把所有变化加入准备提交区
确认没有问题以后:
git add -A这一步可以理解成:
把这一次需要保存的修改全部放进“准备提交区”。
-A 会处理:
新增
修改
删除然后再次:
git status确认准备提交的文件是否正确。
十二、第九步:创建 Commit
接下来:
git commit -m "发布 1.1.0,更新项目并新增服务端"这里一定要理解一个概念:
Commit 不等于上传 GitHub。
它只是:
在本地 Git 中创建一个新的版本记录。
例如:
● 发布 1.1.0,更新项目并新增服务端
│
● 修复部分功能
│
● 初始化项目每一个点都可以理解成一个项目版本。
因此 Commit Message 最好不要写:
修改
更新
123
test而是尽量写清楚:
修复家庭成员页面显示异常或者:
新增服务端 API 并优化云函数调用以后回头看历史记录会舒服很多。
十三、第十步:Push 到 GitHub
Commit 完成以后:
git push正常情况下 Git 就会把本地的新 Commit 上传到 GitHub。
但是我在这里遇到了整个过程中最大的一个坑:
GitHub 身份认证。
十四、Git Push 为什么一直提示密码错误?
第一次 Push 时出现:
Username for 'https://github.com':
Password for 'https://xxx@github.com':输入 GitHub 登录密码后:
remote: Invalid username or token.
Password authentication is not supported for Git operations.原因是:
GitHub 的 Git HTTPS 操作已经不支持直接使用账号登录密码进行认证。
所以即使 GitHub 网页登录密码完全正确,也不能这样 Push。
可以使用 Token、SSH 等方式解决。
但对于刚开始接触 Git 的用户,我最后采用的是:
GitHub CLI。
十五、使用 GitHub CLI 解决登录问题
GitHub CLI 的命令是:
gh登录:
gh auth login根据提示选择:
GitHub.com
↓
HTTPS
↓
使用浏览器登录然后在浏览器里完成 GitHub 授权。
完成以后可以检查:
gh auth status如果看到类似:
Logged in to github.com account YOUR_USERNAME
Active account: true
Git operations protocol: https就说明 GitHub CLI 已经登录成功。
然后再次:
git push最终出现:
main -> main说明:
上传成功。
十六、最终 GitHub 上发生了什么?
整个操作完成以后,并不是把以前的项目历史清空。
而是形成:
旧版本 Commit
↓
旧版本 Commit
↓
发布 1.1.0
↓
未来 1.1.1
↓
未来 1.2.0GitHub 当前显示的是最新项目文件,但是以前所有 Commit 仍然存在。
因此可以:
查看以前的代码
查看每次修改了什么
比较两个版本
找到 Bug 是哪次修改引入的
必要时恢复以前版本
这才是使用 Git,而不是简单上传文件的真正意义。
十七、以后更新项目其实只需要 5 条命令
第一次配置比较麻烦。
但是 Git 仓库和 GitHub 登录都配置好以后,日常开发就简单很多。
每次修改代码以后:
git status看看哪些文件变了。
然后:
git diff检查具体改动。
确认以后:
git add -A加入准备提交区。
然后:
git commit -m "说明这一次修改了什么"创建版本记录。
最后:
git push上传 GitHub。
所以可以记住一个非常简单的口诀:
status 看 → diff 查 → add 收 → commit 存 → push 传
十八、这次遇到的主要问题总结
十九、几个最值得记住的 Git 命令
查看当前状态:
git status查看具体修改:
git diff加入所有修改:
git add -A创建版本:
git commit -m "修改说明"上传 GitHub:
git push查看 GitHub CLI 登录状态:
gh auth status二十、最后
刚开始接触 Git 时,很容易把它理解成一个“上传 GitHub 的工具”。
但真正使用一次以后会发现,Git 最重要的能力其实不是上传,而是:
版本管理。
一个项目可以不断经历:
1.0.0
↓
1.1.0
↓
1.2.0
↓
2.0.0而 Git 可以帮助我们记录每一次变化。
GitHub 则让这些版本记录能够被远程保存、分享和协作。
如果只想记住最核心的一套工作流,那么就是:
git status
git diff
git add -A
git commit -m "本次修改说明"
git push从第一次成功 Push 开始,Git 就不再只是几个看不懂的终端命令,而真正变成了项目开发过程中非常实用的版本管理工具。
评论