Git学习笔记 #4 GitHub合作开发
本文最后更新于:2024年4月20日 上午
接上文,本文介绍了 Git 基于 GitHub 的使用,以及合作开发的注意事项。文章的最后还留下了一些待填的坑...
本文大部分内容参考了 RCY 同学的教程,部分参考了 廖雪峰教程-Git,菜鸟教程-Git,以及 Git 官网文档 Git-Documentation。
GitHub 合作开发
以下内容也适用于不同的服务器平台,如 Gitee、GitLab 等。
新建远程仓库
从 GitHub 上创建一个空仓库后,通常有三个选择:
- 直接克隆到本地,会生成一个仓库文件夹,里面只有一个
.git
文件夹。可以在仓库文件夹中创作。 - 在本地新建一个同名文件夹,再创建本地仓库,添加远程仓库,推送并绑定上游分支。
- 对本地已有的一个仓库(确保同名),添加远程仓库,推送并绑定上游分支。
对于第一种方法,只需要 git clone
命令即可,对于第二种方法,GitHub 提供了一系列指引命令:
1 |
|
对于第三种情况,只需完成后面三步即可。
.gitignore
在通过 GitHub 新建仓库时,我们会发现有个 Add .gitignore
按钮,这有什么用呢?实际上我们知道,维护真正项目时可能有一次修改会涉及到多个文件,这个时候一般大家会倾向于使用 git add .
的简单操作。
但是,并非所有文件都应该被放入 Git 仓库中,如:
- IDE / 编辑器 的配置文件(如 .vscode、.idea 等);
- 数据库文件;
- 带有敏感信息的文件。
这和便利的命令形成了矛盾,为此出现了特殊文件 .gitignore
,它可以决定哪些的文件不需要添加到版本管理中。一个样例如下:
1 |
|
以行为单位,一行写一个规则,决定什么不被添加,书写规则也很简单:
- 以
#
开头的一行是注释,用\
进行转义。 - 若规则不包含
/
,会对.gitignore
同路径下的文件和目录进行屏蔽; - 若规则以
/
结束,则会匹配项目中所有同名目录下的内容,但不匹配同名文件; - 若规则以
/
开始,则会从项目根目录开始匹配; *
匹配除了/
以外的任意字符串,**
匹配完整路径名;?
匹配除了/
以外的任意单个字符;- 区间表示,如
[a-zA-Z]
,可以用于匹配任何一个区间范围内的字符; !
开头的模式标识否定,该文件将会再次被包含,通常用于在屏蔽的文件中添加特例;- 不能识别中文,因为默认编码是 GBK。
创建一个 .gitignore
文件最便捷的方法是,在创建仓库时勾选 GitHub 自动创建,并在选项中选择合适的 .gitignore
文件模板,再克隆到本地手动补充。
在实际工程中,用 GitHub 创建仓库还可以便捷地添加合适的 LICENSE 文件。
远程服务器拒绝
如果你是在一个大合作团队中工作,很可能是 main 被锁定了(只有 Collaborators 有权限推送),其他人需要 Pull Request 流程来合并修改。
如果你直接提交到本地 main,然后试图推送修改,你将会收到这样类似的信息:
1 |
|
这里推荐一个做法:Fork 最新的仓库,此时你将拥有这个远程仓库的从分支——你的用户名就是从分支名。再将你的修改提交到这条分支,最后通过 GitHub 网站来提交一个 PR,请求主分支拉取并合并你的从分支。
当然,如果只是几个人的小开发团队,还是建议在仓库的
Settings
界面找到Collaborators
,直接添加队友来得方便。
此外,即使是在小开发团队中,也可能会遇到 push 时远程服务器拒绝的情况,此时大概率是因为产生了分叉 (Branch Diverged) !具体的处理办法参见上一章。
upstream
在前文介绍 Push 时,曾提过上游(upstream)的概念,对于个人开发而言,upstream
只是标识了多个远程仓库或分支中的某个默认值。但在合作开发,特别是需要提 PR 时,upstream
有其特定意义。
upstream
通常指代你所 fork 的原始仓库,你无权修改。origin
则是你所 fork 下来的仓库,你有权修改。
因此,当需要对一个大型项目贡献时,你的操作流程应该是:
先在 GitHub 上 fork 原始仓库,得到你所有的仓库。
再 clone 你所有的仓库到本地,此时它默认为
origin
分支。将原始仓库添加到
upstream
以保持联系,跟进其变化:1
2$ git remote add upstream git://github.com/<aUser>/<aRepo.git>
$ git remote -v # 查看远程仓库情况当原始仓库有变化时,可以拉取其更新:
1
2$ git fetch upstream # 如果设置了 upstream 可以缺省
$ git merge当本地做出提交时,先推送到自己的
origin
:1
$ git push origin # 如果不加 origin 会被远程服务器拒绝
然后再通过 Pull Request 请求原始仓库拉取你的修改。
暂存本地修改
有时候在本地修改进行到一半的时候,需要拉取远程版本,此时如果直接 git pull
则会和本地版本产生冲突。一个解决办法是先将本地的代码 commit
再去 fetch
远程的并手动 merge
。但是这样则会提交一个半成品的节点。
Git 提供了一个 git stash
命令来解决这个问题:将当前未提交的修改(包括工作区和暂存区的修改)先暂时储藏起来,这样工作区干净了后,就可以直接拉取线上更新。
1 |
|
如果需要多次暂存——「修改,暂存,再修改,再暂存」,则可以使用如下命令:
1 |
|
多远程与多分支
实践中遇到的最多的问题:
- 创建空分支:https://www.jianshu.com/p/a18487d987ac
- 推送本地所有分支和拉取远程所有分支:https://blog.csdn.net/toopoo/article/details/85260277
- 将一个项目同时从本地推送到 GitHub 和 Gitee:https://www.cnblogs.com/poloyy/p/12215199.html
- 将 upstream 的分支拉到本地后没有对应的同名分支:
高端的 Git
高端的操作往往意味着危险的操作,以下将介绍前文未提及的一些操作,同时也挖下一些坑以后来填。
版本回退 (Reset)
有时候你可能希望放弃 Git 仓库中的一部分提交,退到其他某处,这种情况下可以:
1 |
|
这种情况下可以带着分支一起回退,然后重新 commit,走一条完全不同的道路,而放弃了部分数据。
但是,如果你 reset 完后又后悔了,该怎么办?没关系,只要你没玩 gc 这样的危险指令,那么你 Git 仓库中的数据总有机会找回来。
1 |
|
在看到后面的快照的版本号后,则可以 reset 回去。
Cherry-Pick
一个相对高端的分支管理命令,将一些提交复制到当前所在的位置(HEAD)下面,这些提交可以来自其他分支,但不一定是顺序的!
1 |
|
获取帮助
无论是本博客,还是网上的文档,甚至官方的教程,都未必能把每个指令的每个参数、用法提到,因此 Git 自带的帮助文档就很重要:
1 |
|