从创建仓库开始,学会提交代码、使用分支、合并 PR,再学习和别人合作开发。
个人使用 GitHub 进行开发教程
先认识几个词
| 名称 | 一句话解释 |
|---|---|
| Repository | 保存项目文件和修改历史的仓库。 |
| Clone | 把远程仓库和历史克隆到电脑。 |
| Branch | 指向某次提交的可移动标签,用来分开开发。 |
| Commit | 将暂存区的修改保存为一次本地提交。 |
| Push | 把本地提交上传到远程仓库。 |
| Fetch | 获取远程更新,暂时不合并到当前分支。 |
| Pull | 获取远程更新,再整合进当前分支。 |
| Pull Request(PR) | 提出修改,请求把一个分支合并到另一个分支。 |
| Merge | 把一个分支的修改合并进当前分支。 |
| Fork | 在自己的 GitHub 账号下创建别人的仓库副本。 |
git pull 是拉取远程更新,Pull Request 是请求合并,两者不是同一个操作。
一、创建仓库
打开 GitHub,点击右上角的 + → New repository,填写仓库名称,例如 learn-github。
选择 Public 或 Private,勾选 README,再点击 Create repository。
勾选 README 后,仓库就有了第一条提交,方便后面克隆和创建分支。
二、Clone 到本地
在电脑的任意位置打开终端,输入
1 | git clone 仓库地址 |
即可将项目克隆到本地
之后进入到项目文件夹对应的终端
三、修改项目内容
打开README.md后添加一波新的东西。然后执行以下命令可以查看分支、有哪些改动?改动提交到待提交区了没有?
1 | git status |
如果想查看具体发生了什么修改,可以执行以下命令进行查看
1 | git diff |
四、把文件放到暂存区
暂存区就是“这次准备提交的修改”,执行:
1 | git add README.md |
再次检查状态和即将提交的内容:
1 | git status |
Changes to be committed 表示修改已暂存,尚未创建 Commit。
git diff 看尚未暂存的改动,git diff --staged 看已经暂存的改动。
如图所示git diff就是本次工作区文件夹的更改 和 暂存区里的结果比较
git diff —staged 就是暂存区结果 和 最新一次提交的结果进行比较
五、提交、上传分支
想要把对当前分支的修改提交到github上去,首先得存档
存档就是把待提交区的修改成品附上commit说明后存入档,算作一次提交
1 | git commit -m "更新了README,新增了关于xxxxx的内容" |
提交后,可以通过以下命令查看提交记录,-5就是之查看5条记录
1 | git log --oneline -5 |
然后就是通过以下命令将本次提交上传到github官网上去
1 | git push -u origin main |
六、创建自己的分支
分支让新功能和稳定版本分开,开发完成后再合并回 main。
1 | main 稳定版本 |
1 | git switch -c feature/add-study-notes |
git switch -c 同时创建并切换分支,git branch 前面的 * 表示当前分支。
新分支刚创建时和主分支指向同一条提交;创建新的 Commit 后,两条分支才会出现不同内容。
七、在功能分支开发并上传
创建新文件或修改,写几条学习记录并保存:
检查、暂存、提交,再上传功能分支:
1 | git status |
推送功能分支不等于合并主分支,此时 GitHub 的 main 仍然没有这次修改。
提交后可以切换分支观察文件变化:
1 | git switch main |
本例中,新的修改在主分支消失、在功能分支出现,因为它只提交在功能分支中。
如图所示如果在新分支和主分支都进行了提交,就会进行分叉。通过log命令查看提交历史
1 | #查看当前分支的一条线提交历史 |
下一步有两种选择:第八节在本地合并,第九节在 GitHub 上用 PR 合并;练习同一个功能时选一种即可。
八、在本地合并分支
先切换到接收修改的 main,更新后再合并功能分支:
1 | git switch main |
git merge 合并到当前分支,所以要先切换到 main,不能把方向弄反。
如果显示 Fast-forward,表示主分支只需向前移动,就能包含功能分支的提交。
如果两个分支都产生了新提交,Git 可能创建一个 Merge Commit,也可能要求先解决冲突。
完成合并后,检查文件、运行项目需要的测试,再上传主分支:
1 | git status |
本地 Merge 不会自动更新 GitHub,需要再执行 Push。合并规则参见 Git 合并说明。
九、使用 Pull Request 合并分支
PR 是“请把我的功能分支合并进主分支”,它会保留修改说明、讨论和检查记录。
即使只有一个账号,也可以自己创建 PR、检查修改并合并;自己的 PR 不能给自己提交 Approve 审查。
本节假设第七节的功能分支已经推送,但还没有按第八节合并。
创建 PR
打开 GitHub 仓库,点击 Compare & pull request;没有提示时,进入 Pull requests → New pull request。
确认合并方向:
1 | base: main ← compare: feature/add-study-notes |
base 接收修改,compare 提供修改,不要选反。
填写标题和说明,再点击 Create pull request;还没写完时,可以创建 Draft PR。
说明写清两件事即可:改了什么,以及检查了什么;没运行测试就不要写“测试通过”。
检查 PR
| 页面 | 查看什么 |
|---|---|
| Conversation | 修改说明、讨论和审查结果。 |
| Commits | 这次 PR 包含哪些提交。 |
| Checks | 自动检查是否成功。 |
| Files changed | 具体修改了哪些文件和内容。 |
重点检查有没有误删文件、提交敏感信息,以及本次修改是否符合目标。
PR 创建后还可以继续修改同一个功能分支,Commit、Push 后,PR 会自动更新,不需要重新创建。
1 | git switch feature/add-study-notes |
上面的命令在继续编辑并保存 notes.md 后执行。
Merge PR 是什么意思
Merge PR 就是接受这个 PR,把修改合并到选定的目标分支。
确认修改正确、必要检查通过且没有未解决冲突,再点击 Merge pull request → Confirm merge。
按钮不能点击时,先看页面提示,可能需要解决冲突、等待检查或满足分支保护规则。
| 合并方式 | 区别 |
|---|---|
| Create a merge commit | 保留分支上的提交,并新增一条合并提交。 |
| Squash and merge | 将本次 PR 的修改合成一条新提交。 |
| Rebase and merge | 将提交依次接到目标分支后面,提交编号会变化。 |
刚开始可以选择仓库允许的普通 Merge,不必同时练习所有方式。
Close pull request 只是关闭请求,没有把修改合并到主分支。
PR 操作参见 GitHub 创建 Pull Request。
十、合并后同步并清理分支
GitHub 上完成合并后,本地 main 还没自动更新,需要拉取:
1 | git switch main |
确认文件和提交已经进入主分支,再删除已完成的本地功能分支:
1 | git branch -d feature/add-study-notes |
远程分支可以在已合并的 PR 页面点击 Delete branch,也可以执行:
1 | git push origin --delete feature/add-study-notes |
远程分支已经通过网页删除时,不用再执行远程删除命令,只需 git fetch --prune 清理本地旧记录。
git branch -d 删除本地分支,不会删除 GitHub 分支;删除分支也不会删除已经合并进主分支的文件。
Squash 或 Rebase 合并后,-d 可能仍提示未合并;先核对 PR 和主分支内容,不要为了消除提示直接强制删除。
十一、合并冲突怎么处理
冲突表示两边修改重叠,Git 无法判断该保留哪一种内容,需要你决定。
处理前先 Commit 或 Stash 保存自己的改动,保证工作区干净,再在尚未合并的功能分支中整合最新主分支:
1 | git switch feature/add-study-notes |
发生冲突时,git status 会列出文件,里面可能出现这些标记:
1 | <<<<<<< HEAD |
编辑冲突文件,保留需要的最终内容,并删除三种冲突标记。
例如冲突文件是 notes.md,解决后执行:
1 | git add notes.md |
不想继续本次合并,可以在合并尚未完成时执行:
1 | git merge --abort |
两边改动都要保留时,应把它们整理成最终内容,不是随便删掉其中一边。
十二、撤销修改和临时保存
下面是不同场景的处理方法,不要把全部命令连续执行。
文件暂存错了
取消暂存,但保留电脑上的修改:
1 | git restore --staged README.md |
放弃未暂存的修改
确认不需要这些内容,或先备份,再执行:
1 | git restore README.md |
它会用暂存区版本覆盖工作区文件,未保存到其他位置的改动会丢失。
开发到一半,需要切换分支
临时保存已跟踪文件的改动和未跟踪文件:
1 | git stash push -u -m "临时保存开发进度" |
回到原来的开发分支后,恢复最近一份暂存:
1 | git stash apply |
apply 不会删除这份 Stash;恢复可能发生冲突,检查无误后再处理,忽略文件不在 -u 的保存范围内。
撤销已经提交的修改
对于已经上传的普通提交,优先用 Revert 新增一条撤销提交,不重写别人已获取的历史。
确认工作区干净;本例撤销当前分支最近一条普通提交,不适用于 Merge Commit:
1 | git revert --no-edit HEAD |
如果撤销的是更早的提交,先用 git log --oneline 找到编号,再把 HEAD 换成该编号。
查找误操作前的提交
查看本地分支和 HEAD 的移动记录:
1 | git reflog -10 |
它可以帮助找到误操作前的提交,但不是永久备份,也不能找回从未保存的全部文件。
刚开始不要随意执行 git reset --hard、git clean -fd 或强制 Push,它们可能丢失改动或覆盖远程历史。
具体规则参见 Git Stash 和 Git Revert。
十三、哪些文件不应该上传
在项目根目录创建 .gitignore,忽略临时文件和私密配置,例如:
1 | node_modules/ |
这只是示例,按项目需要保留或修改规则,再把 .gitignore 本身提交进仓库。
.gitignore 不会自动取消已经跟踪的文件,也不会删除历史中的密码;秘密泄露后应先撤销或更换密钥。
每次提交前用 git diff --staged 检查,不上传密码、Token、验证码、私钥和不该公开的个人信息。
十四、个人开发的日常流程
开始前确认工作区干净,同步主分支并创建本次任务的分支:
1 | git status |
修改并保存 README,检查后提交和上传:
1 | git diff |
接下来创建 PR、检查修改、合并,再更新本地 main。
1 | 同步 main → 创建分支 → 修改 → Add → Commit → Push → PR → Merge → 同步 main |
一个 Commit 尽量只做一件清楚的事,一条分支尽量只完成一个任务。
这套流程也适用于多人协作,参见 GitHub Flow。
十五、和朋友协作开发
有仓库写入权限时,双方克隆同一个仓库,各自在自己的分支开发。
仓库负责人进入 Settings → Collaborators → Add people 邀请朋友,朋友接受邀请后再推送代码。
朋友先同步 main,创建自己的功能分支,修改后 Commit、Push,再提交 PR。
负责人检查 Files changed 和测试结果,有问题就留言,朋友继续在同一分支提交修改。
审查选项中,Comment 是留言,Approve 是同意,Request changes 是要求修改。
确认可以合并后由有权限的人合并,双方再拉取最新 main,不要直接覆盖对方的文件。
十六、给别人的项目贡献代码:Fork
没有原仓库写入权限时,先 Fork 到自己的账号,再在副本中修改并向原仓库提交 PR。
1 | 原作者仓库 → Fork 到自己的 GitHub → Clone 到电脑 → 分支修改 → Push 到自己的仓库 → PR 给原作者 |
克隆的是自己的 Fork,origin 指向自己的副本;原项目可另设为 upstream。
在 Fork 的项目目录中执行,下面的原仓库地址需要替换:
1 | git remote add upstream https://github.com/原作者/原仓库.git |
工作区要先保持干净;如果 Fork 的主分支已经有自己的独立提交,快进会被拒绝,应先检查差异,不要强制覆盖。
贡献代码时从同步后的主分支创建功能分支,把功能分支推送到自己的 origin,再在网页上选择原仓库的主分支作为 PR 的 base。
Fork 和 Clone 不会让你获得原仓库的写入权限,是否接受修改由原项目维护者决定。
十七、记录任务和发布版本
| 功能 | 用途 |
|---|---|
| Issues | 记录 Bug、功能需求和待办任务。 |
| Labels | 给 Issue 和 PR 分类,例如 bug、documentation。 |
| Milestones | 将一组任务归到同一个版本目标。 |
| Projects | 用看板整理待办、进行中和已完成的任务。 |
| Tags | 给某条提交标记版本号。 |
| Releases | 基于 Tag 发布版本说明和下载附件。 |
在仓库的 Issues → New issue 创建任务,写清目标和完成条件。
修复同仓库的 Issue 时,可在 PR 说明里写 Closes #1;合并到默认分支后会关闭对应 Issue,1 换成实际编号。
准备发布时,先切到最新主分支,确认代码和测试无误,再标记版本:
1 | git switch main |
版本号要选一个尚未使用的值;不要重复执行命令来覆盖已有版本。
随后在 GitHub 的 Releases 中创建发布,选择这个 Tag、填写版本说明,按需要上传安装包。
Tag 不等于安装包,上传 Tag 也不会自动替项目编译程序。
README 写清项目用途和使用方法;LICENSE 用于说明许可,没有许可文件不代表可以任意使用代码。
十八、GitHub Actions:自动检查
Actions 可以在 Push 或 PR 后自动运行任务,例如测试、编译和检查文档。
下面给 learn-github 练习仓库增加一个最小检查:确认 README 存在且不为空。
在练习项目根目录新建 .github\workflows\check.yml,内容如下:
1 | name: Check README |
创建文件的目录需要先建好;它属于 GitHub 练习仓库,不是本文所在的 Hexo 博客项目。
使用功能分支提交这个文件:
1 | git add .github/workflows/check.yml |
命令假设当前功能分支已经建立了远程对应关系;第一次推送时使用 git push -u origin 当前分支名。
打开仓库的 Actions 页面查看结果,绿色表示该任务成功,红色表示失败,应点进去看日志。
这个检查只确认 README 非空,不代表项目代码正确;实际项目要换成相应的测试或编译命令。
workflow_dispatch 用于手动运行,文件先进入默认分支后,才可以在 Actions 页面找到对应的手动运行入口。
需要 Token 或密码时,通过 GitHub 的 Secrets 配置,不直接写进 YAML,也不在日志里输出。
配置规则参见 GitHub Actions 工作流语法,Checkout 的用途参见 官方 Checkout。
十九、常见问题
Push 返回 403
先确认 git remote -v 指向自己的仓库,再检查当前登录账号是否有写入权限;设置 user.name 不会增加权限。
Push 被拒绝:non-fast-forward
远程有本地尚未包含的提交,先保存自己的改动,执行 git fetch origin 检查历史,再按需要合并或 Rebase。
本文的 --ff-only 遇到分叉会停止,不要把停止当作需要强制 Push 的理由。
PR 提示没有共同历史
功能分支和主分支不是从同一套历史分出来的,可能是重新 git init 或创建了孤立分支。
先备份自己的修改,再从正确的 origin/main 创建新分支,把需要的改动重新提交;不要直接强行合并无关历史。
明明修改了,Commit 却没内容
检查文件是否保存,执行 git status,确认需要的修改已经 git add 到暂存区。
Push 成功,主分支却没变化
可能只上传了功能分支,先切换 GitHub 网页的分支查看,再通过 Merge 或 PR 合并到 main。
切换分支时提示本地修改会被覆盖
先 Commit、Stash 或备份改动,再切换分支,不要直接强制丢弃。
二十、命令速查
| 命令 | 作用 |
|---|---|
git status |
查看分支和文件状态。 |
git diff |
查看未暂存的改动。 |
git diff --staged |
查看本次准备提交的改动。 |
git add 文件名 |
暂存文件的改动。 |
git commit -m "说明" |
创建本地提交。 |
git push |
上传当前已配置对应关系的分支。 |
git fetch origin |
获取远程更新,不合并当前分支。 |
git pull --ff-only origin main |
快进同步当前的主分支。 |
git switch -c 分支名 |
创建并切换分支。 |
git switch 分支名 |
切换已有分支。 |
git branch -a |
查看本地和远程跟踪分支。 |
git branch -d 分支名 |
删除已合并的本地分支。 |
git merge 分支名 |
将指定分支合并到当前分支。 |
git log --oneline --decorate --graph --all -10 |
查看最近的分支与提交关系。 |
git remote -v |
查看远程仓库地址。 |
最重要的区别:Add 是准备提交,Commit 是本地存档,Push 是上传,Merge 才是合并。