掌握 Git 远程仓库,让团队协作更上一层楼
介绍下远程仓库的概念、常见的远程仓库以及常见的操作。
什么是远程仓库
目前,我们的版本库都是在自己的电脑上,并不方便给别人访问,更别说一起维护一个版本库了;如果我们的电脑关机了(或者坏了),岂不是别人就没法干活了?
因此,我们通常需要找一台服务器,存放我们的版本库;然后,其他人就可以访问并克隆这个原始的版本库,并且每个人的版本库都是完整的,不存在主次之分。
Git 仓库托管服务网站
如果为了学习 Git 而搭建一个 Git 服务器是没必要的,有很多网站都提供了 Git 仓库托管服务,我们可以注册后使用:
- GitHub:全球最大的 Git 仓库托管服务网站,2008 年上线,为开源项目提供 Git 存储,无数开源项目迁移到了 GitHub,例如 JQuery,PHP,Ruby。
- Gitee:由于 GitHub 是国外的,在国内有种不可抗力的因素导致经常访问失败,因此国内也上线了一个代码托管平台,那就是 Gitee。
- GitLab:在工作中,我们的项目大部分是公司内的,不太可能开源(例如银行内的项目,源代码保护的非常好),因此有必要公司自己内部搭建一个 Git 仓库,通常使用的就是 GitLab,它是一个开源项目。
关于源代码保护,这里不得不提一下,大部分科技公司都是靠自己的项目来赚钱的,不太可能开源,而且开源了还有被发现漏洞和攻击的风险,所以一般都是用 GitLab 这种可以在内网使用的工具。读者可以参考下华为内是怎么保护的,我在国企工作过,可以说这些经历非常类似了:
百度、阿里、腾讯之类的大公司用 Git 吗?他们如何管理源代码? - 知乎 作者:jiakon
华为用的是 SVN。
SVN 的权限控制,可以控制到目录的。你可以访问到哪个级别的代码,都是可以控制的。
另外,以华为的内网安全措施,周身遍布摄像头,电脑遍布监控软件,访问外网严格受限,所有 USB 接口和网口贴封条,封条上还有什么镭射喷码之类的东西,封条被撕过是可以看出来的,安全管理员定期检查封条。根据安全等级区分绿区、黄区、红区,区域之间物理隔离,访问安全级别更高的区要通过专用远程登录软件,连截屏软件都被禁用。这是一个为了信息安全不惜牺牲效率的企业。这么严格的管控措施,你还想偷偷拷走代码?当然,曾经有神人做到了,比如通过示波器的 USB 口。现在的安全措施又比我在的时候严格了很多。这种事情越来越不可能发生了。
一个在华为待了 9 年的人,离职时都忍痛放弃拷走多年的照片,这是即使走流程申请都几乎不可能做到的事情。谁知道,你图片中是否隐藏了什么保密信息呢?
另外,即使你不小心拥有了不该有的权限,你下载了一些不该拥有的文件。电脑上还有个监控软件,叫关键资产扫描。这个软件也是不能关掉的。安装时,会全盘扫描一次你的电脑,每周还会定时全盘扫描一次,看看你电脑中是否有超出你权限之外的文档和代码,如果有,要么删除,要么申请权限。
有很多不但视源代码如生命,而且视员工为窃贼的公司,会在版本控制系统里设置一套完善的权限控制,每个人是否有读写权限会精确到每个分支甚至每个目录下。因为 Git 是为 Linux 源代码托管而开发的,所以 Git 也继承了开源社区的精神,不支持权限控制。不过,因为 Git 支持钩子(hook),所以,可以在服务器端编写一系列脚本来控制提交等操作,达到权限控制的目的。Gitolite 就是这个工具。--引自 搭建 Git 服务器 - 廖雪峰的官方网站
另外,如果你访问不了 GitHub,可能是某种不可抗力的问题,请自行搜索解决,可参考我的下一篇博客。
创建公钥和私钥
我们本地 Git 仓库和远程仓库之间的传输是通过 SSH 协议加密的,因此需要创建公钥和私钥。
PS:公钥和私钥其实就是两个字符串,用于身份认证;我们先将公钥配置到远程仓库上,然后提交的时候通过 SSH 协议来加解密数据,验证我们的身份。感兴趣的同学可以学习下:非对称加密算法 - 廖雪峰的官方网站
Git 也支持其他协议,例如 HTTPS,但是不太安全,并且比较慢,较少使用。
打开命令行(或者 Git Bash),输入以下命令来创建 SSH Key:
$ ssh-keygen -t rsa -C "youremail@example.com"
注意邮箱换成你自己的,一路回车,使用默认值即可。
如果一切顺利的话,可以在用户主目录里找到 .ssh
目录,里面有 id_rsa
和 id_rsa.pub
两个文件。
PS:对于 Windows 用户来说,用户主目录是 C:\Users\你的用户名
,例如我的是:
对于 Linux 用户:
cd ~/.ssh
ssh-kengen -t -a rsa
这两个就是 SSH Key 的秘钥对,可以右键用记事本之类的工具打开。id_rsa
里的内容是私钥,不能泄露出去,id_rsa.pub
里的内容是公钥,可以放心地告诉任何人。
远程仓库就是通过公钥来识别你的身份的,对于那些没有对应私钥的人来说,是不能修改你的仓库里的内容的。
在远程仓库里配置公钥
这里假设读者已注册好(注册就不用演示了吧 😅)
对于 Gitee
登录后,在右上角点击设置
然后在左侧菜单栏选择 SSH 公钥,然后在右侧输入公钥的标题(自己取个方便记的名字),然后粘贴公钥即可:
对于 GitHub
和 Gitee 类似,登录后右上角选择设置:
然后在左侧菜单栏选择 SSH 公钥,然后选择 new ssh key:
在右侧输入公钥的标题(自己取个方便记的名字),粘贴公钥即可:
对于 GitLab 而言
GitLab 通常是需要管理员添加用户后,才可以登录。登录后同理,右上角-设置:
左侧菜单里--SSH 公钥:
补充说明
-
注意不要将敏感信息提交到版本库里,以免泄漏
-
大多数 Git 托管服务,例如 GitHub、Gitee 和 GitLab 都支持添加多个 key。例如笔者有两台笔记本,1 个台式机,有时候在笔记本开发,有时候在台式机上开发,这时候可以分别在两台电脑上生成公钥和私钥并添加到远程仓库,这样几台电脑都可以直接访问和修改远程的版本库
-
Git 服务器还可以设置是否开源,如果你的代码不想被别人看到,或者想晚点开源,可以设置私有(别人不可读,也不可写)。例如 Gitee:
-
点赞是个好习惯 😄,我们有时候能看到某某项目在 GitHub 有成千上万的点赞,赞越多,表明受欢迎更高。
Gitee 在 2022-5-18 日出了政策,开源项目必须要审核,感兴趣的同学可参考:突发!Gitee 仓库开源必须审核,官方迅速回应 - 知乎
创建远程库
我们之前都是在本地创建了 Git 仓库,现在我们想将本地的版本库推送到 Git 服务器上,这样既可以作为一个备份,也可以被别人访问到,为将来协同开发提供了可能~
首先,我们得在 Git 服务器上创建一个仓库,然后才能将本地仓库和远程仓库关联起来。
在 GitHub 创建仓库
登录后,在右上角的 + 号里选择创建仓库
然后我们输入 Git 仓库的名字,和相关描述、是否公私有等。注意其他选项请保持默认,我们需要的是一个空的仓库(相当于在一个空目录里使用 git init
):
然后我们就创建好了!
在 Gitee 创建仓库
登录后,在右上角的加号里选择新建仓库:
然后也是一样,需要填写创建仓库的信息:
此时我们就创建好啦~:
关联本地仓库和远程库
我们需要将本地仓库 和远程仓库关联起来,这样我们才能将本地仓库推送到远程仓库上。我们可以将本地仓库和多个远程仓库关联起来。
不知道你有没注意,在创建好仓库后,在项目底部有很贴心的提示,告诉我们如何关联:
--GitHub 的提示:
$ git remote add origin git@github.com:Peter-JXL/LearnGit.git
--Gitee 的提示:
$ git remote add origin git@gitee.com:peterjxl/LearnGit.git
remote add 就是只添加一个远程库,origin 是我们给远程仓库的命名(默认是 origin,关联一个远程库时必须给远程库指定一个名字。为什么要命名?因为我们可能有多个远程仓库,需要起不同的名字来区分),后面跟的是远程仓库的地址。
输入以下命令,就可以将本地仓库和两个远程仓库关联起来(我这里给两个远程仓库分别命名为 Gitee 和 GitHub):
$ git remote add gitee git@gitee.com:peterjxl/LearnGit.git
$ git remote add github git@github.com:Peter-JXL/LearnGit.git
注意,如果你也创建了远程仓库,在关联的时候需要输入自己的远程仓库地址,而不是直接 copy 我的
接下来,我们就可以推送本地仓库内容到远程仓库了,我这里分别推送了两个远程仓库:
$ git push -u github master
Enumerating objects: 30, done.
Counting objects: 100% (30/30), done.
Delta compression using up to 20 threads
Compressing objects: 100% (21/21), done.
Writing objects: 100% (30/30), 2.69 KiB | 688.00 KiB/s, done.
Total 30 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (2/2), done.
To github.com:Peter-JXL/LearnGit.git
* [new branch] master -> master
Branch 'master' set up to track remote branch 'master' from 'github'.
$ git push -u gitee master
Enumerating objects: 30, done.
Counting objects: 100% (30/30), done.
Delta compression using up to 20 threads
Compressing objects: 100% (21/21), done.
Writing objects: 100% (30/30), 2.69 KiB | 688.00 KiB/s, done.
Total 30 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Powered by GITEE.COM [GNK-6.4]
To gitee.com:peterjxl/LearnGit.git
* [new branch] master -> master
Branch 'master' set up to track remote branch 'master' from 'gitee'.
用 git push
命令,实际上是把当前分支 master
推送到远程。由于远程库是空的,我们第一次推送 master
分支时,加上了 -u
参数,Git 不但会把本地的 master
分支内容推送的远程新的 master
分支,还会把本地的 master
分支和远程的 master
分支关联起来。
在以后的推送或者拉取时就可以简化命令,不用带-u 参数了:
$ git push github
$ git push gitee
我们可以刷新下远程仓库的页面,此时可以看到都有内容啦 😎😎:
即使在没有联网的情况下,我们也可以先在本地开发,联网后再推送即可完成同步,这就是分布式版本系统的好处。
管理远程仓库
如何查看本地仓库关联多少个远程库呢?可以用 git remove -v
命令:
$ git remote -v
gitee git@gitee.com:peterjxl/LearnGit.git (fetch)
gitee git@gitee.com:peterjxl/LearnGit.git (push)
github git@github.com:Peter-JXL/LearnGit.git (fetch)
github git@github.com:Peter-JXL/LearnGit.git (push)
为什么一个仓库有两个输出?末尾的 fetch 表明是拉取,push 表明是推送,我们后续再说
如果我们添加错了远程仓库呢?可以使用 git remote rm 仓库名
删除:
$ git remote rm github
此处的“删除”其实是解除了本地和远程的绑定关系,并不是物理上删除了远程库。远程库本身并没有任何改动。要真正删除远程库,需要登录到代码托管平台,在后台页面找到删除按钮再删除:
更多使用 git remote 的用法,可以使用 -h 参数来查看:
$ git remote -h
usage: git remote [-v | --verbose]
or: git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--mirror=<fetch|push>] <name> <url>
or: git remote rename <old> <new>
or: git remote remove <name>
or: git remote set-head <name> (-a | --auto | -d | --delete | <branch>)
or: git remote [-v | --verbose] show [-n] <name>
or: git remote prune [-n | --dry-run] <name>
or: git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]
or: git remote set-branches [--add] <name> <branch>...
or: git remote get-url [--push] [--all] <name>
or: git remote set-url [--push] <name> <newurl> [<oldurl>]
or: git remote set-url --add <name> <newurl>
or: git remote set-url --delete <name> <url>
-v, --verbose be verbose; must be placed before a subcommand
可以看到,改名可以使用 git remote rename <old> <new>
。
从远程仓库克隆
之前我们是先本地创建了仓库,然后再创建的远程仓库,并关联。
然而,实际情况是我们经常是维护旧项目,即已经有了远程仓库,此时我们需要从远程仓库里下载;
为了模拟并实践这种情况,我们假设目前没有本地仓库(我们换一个本地目录),然后使用 git clone 远程仓库地址
下载:
$ git clone git@github.com:Peter-JXL/LearnGit.git
Cloning into 'LearnGit'...
remote: Enumerating objects: 30, done.
remote: Counting objects: 100% (30/30), done.
remote: Compressing objects: 100% (19/19), done.
remote: Total 30 (delta 2), reused 30 (delta 2), pack-reused 0
Receiving objects: 100% (30/30), done.
Resolving deltas: 100% (2/2), done.
$ cd LearnGit
$ ls
d----- 2023-01-13 22:42 1-diffAndPath
d----- 2023-01-13 22:42 2-versionControl
其他人下载的方式也是一样的,自己选择一个目录后下载。
那么如何获取一个仓库的地址呢?可以在代码托管平台里复制。
对于 Gitee:
对于 GitHub:
一个仓库应该有的东西
一个仓库,除了有代码之外,应该还有这些东西:
- 说明文档 readme.md,用于展示在仓库首页
- LICENSE:项目的许可证,例如是否别人随意的使用你的项目
.gitignore
:一个 Git 配置文件,用于说明哪些文件不用纳入到 Git 管理,我们后续再说
readme.md
以说明文档为例:我们打开我们的 Git 仓库
可以看到直接就是一堆目录,外人点进来是不知道你这个项目是干嘛的。并且 Github 也提示我们
Help people interested in this repository understand your project by adding a README.
因此,我们可以尝试给该仓库添加一个 readme.md 文档。我们创建一个 Markdown 文档,并添加到版本库后推送:
$ echo "This project is use to Learn Git" > readme.md
$ git commit -m "add readme.md"
$ git push gitee
$ git push github
然后我们查看远程仓库:
当然,我们写的比较简单,后续会逐步完善;一般大型项目的说明文档都写的很完善的,例如 jQuery:
LICENSE
关于开源证书的问题,可以参考阮一峰老师的博客:开源许可证教程 - 阮一峰的网络日志,这里引用一部分内容:
开源许可证是一种法律许可。通过它,版权拥有人明确允许,用户可以免费地使用、修改、共享版权软件。
版权法默认禁止共享,也就是说,没有许可证的软件,就等同于保留版权,虽然开源了,用户只能看看源码,不能用,一用就会侵犯版权。所以软件开源的话,必须明确地授予用户开源许可证。
.gitignore
有些时候,你必须把某些文件放到 Git 工作目录中,但又不能提交它们,比如:
- 保存了数据库密码或其他敏感信息的配置文件(感兴趣看看搜搜相关新闻,时不时都有爆出来:将代码(含密钥)上传 Github“开源” 5 年:30 万客户信息泄漏)
- 编译产生的中间文件,例如 Java 的 .class 文件等
Git 考虑到了这一点,我们只需在 Git 工作区的根目录下创建一个特殊的 .gitignore
文本文件,然后把要忽略的文件名填进去(支持正则),Git 就会自动忽略这些文件(不追踪 track)。
例如,我们进行 Java 开发,需要忽略所有的.class 文件,可以这样写:
*.class
想要忽略某个文件,只需写上文件名即可:
Desktop.ini
Thumbs.db
最后一步就是把 .gitignore
也提交到 Git 了,并且可以对 .gitignore
做版本管理!
我们来实践下:
> echo "*.class" > .gitignore
> cat .gitignore
*.class
然后我们可以新建一个 class 文件,并且查看仓库状态:
$ echo "fuk" > Fuk.class
$ ll
total 10
drwxr-xr-x 1 peterjxl 197121 0 1月 11 07:37 1-diffAndPath/
drwxr-xr-x 1 peterjxl 197121 0 1月 14 07:19 2-versionControl/
-rw-r--r-- 1 peterjxl 197121 4 1月 14 09:31 Fuk.class
-rw-r--r-- 1 peterjxl 197121 33 1月 13 22:53 readme.md
$ git st
On branch master
Your branch is ahead of 'gitee/master' by 2 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
有些时候,你想添加一个文件到 Git,但发现添加不了,原因是这个文件被 .gitignore
忽略了:
$ git add Fuk.class
The following paths are ignored by one of your .gitignore files:
Fuk.class
hint: Use -f if you really want to add them.
hint: Turn this message off by running
hint: "git config advice.addIgnoredFile fals
Git 告诉我们,如果你确实想添加该文件,可以用 -f
强制添加到 Git:
$ git add -f Fuk.class
或者你发现,可能是 .gitignore
写得有问题,需要找出来到底哪个规则写错了,可以用 git check-ignore
命令检查:
$ git check-ignore -v Fuk.class
.gitignore:1:*.class Fuk.class
Git 会告诉我们,.gitignore
的第 1 行规则忽略了该文件,于是我们就可以知道应该修订哪个规则。
git check-ignore -v . 检查当前文件夹被哪一个配置忽略了
git check-ignore -v fileName 检查指定的文件被哪一个配置忽略了
还有些时候,当我们编写了规则排除了部分文件时:
# 排除所有.开头的隐藏文件:
.*
# 排除所有.class文件:
*.class
但是我们发现 .*
这个规则把 .gitignore
也排除了,并且 App.class
需要被添加到版本库,但是被 *.class
规则排除了。
虽然可以用 git add -f
强制添加进去,但有强迫症的童鞋还是希望不要破坏 .gitignore
规则,这个时候,可以添加两条例外规则:
# 排除所有.开头的隐藏文件:
.*
# 排除所有.class文件:
*.class
# 不排除.gitignore和App.class:
!.gitignore
!App.class
把指定文件排除在 .gitignore
规则外的写法就是 !
+ 文件名,所以,只需把例外文件添加进去即可。
可以通过 https://gitignore.itranswarp.com 在线生成 .gitignore
文件。
其实我们在创建远程仓库的时候,一般也会提醒我们是否创建这些文件,读者可以回顾下我们创建远程仓库时的界面:
协同开发
即使是开源项目,也不是任何人都可以随意修改你的代码,万一有人不小心将所有文件删除了呢?或者随意提交了几个 bug 上去。开源意味着人人都能获取,但修改的话需要经过作者同意之后(GitHub、Gitee 和 GitLab 都可以提出这样的申请),才能修改。
一般来说,一个项目可以由作者设置多个开发者,这些开发者对仓库有较大的权限,可以直接通过 git add
和 git commit
等命令修改代码。
例如本博客的 Gitee 项目,可以在管理界面里邀请别人,这样别人就可以来开发和维护项目了。
而非本仓库的人员,可以先 fork 项目(右上角),自己拥有 Fork 后的仓库的读写权限,然后通过提出 pull request,来给官方仓库做出贡献:
在公司内开发的话,我们一般都是先找项目管理员,配置好权限后,才可以通过远程仓库拉去代码,然后开发,开发完后提交到远程仓库。
小结
本文主要介绍了如下内容:
-
什么是远程仓库
-
常见的 Git 仓库托管服务网站:GitHub,Gitee 和 GitLab
-
创建远程仓库:登录后,点击右上角加号输入相关信息即可
-
创建和配置公钥和私钥
-
关联本地仓库和远程仓库:
git remote add 远程仓库名 远程仓库地址
-
管理远程仓库
- 推送到远程仓库:
git push -u gitee master
,git push 仓库名
- 查看远程仓库信息:
git remote -v
- 删除远程仓库:
git remote rm 仓库名
- 推送到远程仓库:
-
从远程仓库克隆:
git clone 仓库地址
-
一个仓库里应该有的文件(标配):
- 说明文档 readme.md,使用 Markdown 语法
- 许可证 LICENSE,
- 配置文件
.gitignore
。git add -f
强制添加,git check-ignore -v 文件名
检查配置
内容比较多,没必要一次看完,每次看一点也是可以的。
推荐阅读
15 年封神,GitHub 开发者破亿!这个滋养了全世界码农的网站,已成传奇