gitgithub介绍

一提到最优质的开源代码社区我们不免都会听到 gayhub(全球最大的同性交友网站/bushi)“ github ”的大名。这期博客就简单来讲一讲它和它所依托的版本控制工具:git

git简介

git是一种当今使用很优秀的开源分布式版本控制工具,一种命令行工具(类似在cmd上执行命令)。在项目的分工部署和合作的各个领域,它的使用对项目的完整推进有巨大作用。

版本控制:顾名思义,就是可以记录到项目每个修改版本,并可以随时调用出你想修改的版本。可以这样想,你养了一个孩子,小时候一直给他各种束缚让他上一堆他不喜欢的辅导班,结果长大后孩子可能会很厉害但并不快乐。这时候你悔悟想要弥补,就可以用 git 这个时空穿梭工具(不知道描述的对不对-O-)回到他的童年,让他追求他喜欢的东西,这样孩子(你的项目)长大后也会健康发展。
分布式:分布式对应集中式,集中式就是将版本的各个历史信息存储在同一个服务器总站,弊端也很明显,万一总站没了,直接跑路ヾ(^▽^*)))。而分布式就是将每个客户端的历史信息存储在客户端本地,你可以在不连接服务器的情况下随时查看修改你项目的各个历史版本。

github简介

github全球最大的代码托管平台,并且是开源的。你可以在上面找到任何一个你喜欢的项目下载在本地使用,它和 git 的关系就是这个平台用于处理托管在其上的项目是用的是 git 这个工具,也就是说 githubgit 的一个代码托管中心。

git当然还有其他的代码托管中心:局域网下的 gitlab,国内的 gitee码云

这里关于 git 是有很有意思的历史的:之前有一个叫linus的牛人(没错, linux 之父)在自己的 linux 开源社区一开始是通过手工整合各个社员的开源代码来改进 linux 。这项工作数量大之后是相当累的,之后有一个公司 BitMover 出于人道主义授权 Linux 社区免费使用它公司的版本控制工具(非开源)Bitkeeper,只要求 linux 那边不要破解它。但是之后还是有人(开发 Samba 的 Andrew)试图破解 Bitkeeper 还被人家发现了结果不让用了。linus摇摇头,行吧,我写一个,画两周就自己用C语言写好了 git 的主体程序,开发了这个伟大的开源分布式系统,又过了三年, github 上线…

git 安装与github注册

git 安装

git 的安装教程网上也有很多,这里我推荐按这个B站视频来👇。

git 超详细安装教程,这里安装到配置PATH环境那里时windows系统还是推荐第二种选项,视频里是第一种,这个UP讲的很详细很好。

当你装完后打开任意一个文件夹右键出现Git Bash HereGit GUI Here,点开Git Bash Here出现如下页面,说明你已经安装成功了。

安装成功的GitBash页面

github 注册

点击 github官网主页👈,点击右上角的Sign up进行注册,输入你的用户名和邮箱,用户名好好想一个,以后如果用 github pages 搭建博客的话不至于域名太难记。按要求注册后就可以点击Sign in登陆了。

git 简单原理🤏

本地结构

git整个文件管理结构如下图。

git本地结构图
可以看到,当我们在本地编写代码时,我们一开始只是在工作区,我们需要使用git add命令将其放到暂存区,然后再用git commit命令将暂存区的内容放到本地库,这两个操作之后本地库就会装载我们这次代码的历史信息,方便我们之后进行代码回滚(roll back),从而回到我们任意的一个之前提交过的历史中。

这里应该有人会想为啥要多加个暂存区呢?我直接每次把文件直接提交(git commit)不好吗?这就有点像淘宝的购物车一样,这个暂存区就是给你一个机会让你后悔的,不会真有人购物车的东西都会买吧?(开玩笑(ಥ _ ಥ))

git 分支

很多时候我们都需要在不影响主线的情况下,去进行开发维护。这时候就需要用到我们的git的分支,我们可以在需要分支的时候利用git branch “分支名”来实现当前master分支本地库版本的分支创建。

我们刚创建一个git仓库时会默认一个分支,在git本地叫master,我们默认会在master分支上实施版本更迭。

在分支创建好后,我们利用git switch(以前叫git checkout,但因为git checkout担负的责任太多了,后来就有git switch和git restore来分担它以前的操作)转到我们的分支上,我们可以在分支上实施git add、git commit等操作不断更新我们分支的本地库,等到我们觉得功能已经完善,我们就可以再通过git switch转回到master分支上,再利用git merge 进行自动融合或者手动融合。如下图:

git分支操作

注意,这里图里的本地库事实上应该叫master分支的本地库,假设你的分支名叫devolop,图里的分支库应该叫develop分支的本地库,图里只是图方便不要混淆。

git实例讲解🤏

git本地一次完整提交过程

这里我们用一个简单的实例来讲解之前的内容。首先我们再桌面新建一个文件夹,命名“gitdemo”表示我们的项目。然后在这个文件夹写一个txt文件,命名为“good.txt”模拟项目代码,如下。

初始good文件
写好内容保存后相当于我们已经在工作区写好代码了,接下来我们需要建立 git 库(用来产生本地库暂存区)用来储存历史信息。在该文件目录下右键点击Git Bash Here,然后使用命令git init在当前目录创建一个git库。

这里用gitbash也行,用cmd也行,因为之前我们安装的时候配置PATH环境选的第二个。同时我们在命令行里用的命令都是 linux 命令,很多window命令不兼容。

1
2
$ git init
Initialized empty Git repository in C:/Users/ASUS/Desktop/gitdemo/.git/

下面的提示信息告诉我们一个空的 git 库创建好了。
然后我们需要设置本地签名,这个签名用于向 git 库表明对他进行操作的身份。方便我们知道哪次修改是哪个人做的,毕竟几乎所有大的项目都是多人一起协同实现的。

这里签名可以区分出两个级别:仓库级别/项目级别,系统用户级别。

  • 仓库级别/项目级别

    1
    2
    git config user.name 用户名
    git config user.email 用户邮箱

    上面这个设置在当前 git 库所在目录

  • 系统用户级别

    1
    2
    git config --global user.name 用户名
    git config --global user.email 用户邮箱

    当你对仓库内容进行操作时优先辨认你的仓库级别/项目级别签名,如果没有设置再去辨别系统用户级别签名,如果都没有则git仓库是不允许操作的。我们这里直接设置系统用户级别的签名就行了,输入用户名和自己的邮箱。

接下来我们就可以用git add good.txt和git commit -m “my first git demo” good.txt来向暂存区和本地库传输版本信息。

事实上这里的 git 库文件就是文件夹里的.git文件,暂存区就是.git文件里的.index文件,

不过首先我们先输入git status命令看一下暂存区与本地库状态

1
2
3
4
5
6
7
8
9
10
11
ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master)
$ git status
On branch master

No commits yet

Untracked files:
(use "git add <file>..." to include in what will be committed)
good.txt

nothing added to commit but untracked files present (use "git add" to track)

输入后会发现提示我们“good.txt”还未被跟踪,也就是还未放到暂存区,接下来我们试试用git add命令把他放到暂存器。

1
2
3
4
5
6
7
8
9
10
11
12
ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master)
$ git add good.txt

ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master)
$ git status
On branch master

No commits yet

Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: good.txt

这时候利用git status显示状态会发现提示信息变成了“to be committed”,即让我们将暂存区的文件提交到本地库。

还记得我之前说过暂存区存在的意义吗?这里我们如果觉得我们想要提交的文件不满意,可以利用

1
git rm --cached good.txt

将文件从暂存区撤回,再进行修改,也就是有一个在最终提交前一个反悔的选项。

接着我们再利用git commit -m “My first commit” good.txt命令,将暂存区文件提交到本地库。

这里如果直接用git commit good.txt命令会自动跳转的git bash的默认编辑器Vim来填写此次提交的注释信息,一般直接加上 -m + “注释信息”提交就可以。

还有,可能到这里你的git bash命令行已经显示满了,你可以使用ctrl+L来实现清屏操作。复制和粘贴在 linux中也不再是ctrl+Cctrl+V了,得右键操作。

1
2
3
4
5
ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master)
$ git commit -m "My first commit" good.txt
[master (root-commit) db0d2ca] My first commit
1 file changed, 1 insertion(+)
create mode 100644 good.txt

此时我们就进行了一次完整的提交过程。

git的一次版本回滚过程

利用git reflog

1
2
3
ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master)
$ git reflog
db0d2ca (HEAD -> master) HEAD@{0}: commit (initial): My first commit

可以很清楚看到我们已经提交了第一次的版本信息,前面的“db0d2ca”你可以理解是这个版本的版本号。

这里也可以使用git log(很详细的版本信息,版本号长)、git log –pretty=oneline(一行显示一个版本,版本号长)、git log oneline(一行显示一个版本,版本号短)来查看版本历史信息。

接着我们可以再修改工作区文件,给good.txt文件后加些内容,重新git add、git commit来提交第二次版本,用于演示版本回滚。

对good.txt进行修改
这里完整提交过程省略…
然后我们再输入git reflog

1
2
3
4
ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master)
$ git reflog
fc2a3c3 (HEAD -> master) HEAD@{0}: commit: Some changes
db0d2ca HEAD@{1}: commit (initial): My first commit

可以看到此时就有了两个版本信息,最新版本的版本号为“fc2a3c3”。

现在有意思的来了,时光倒流就在此刻。

我们输入git reset –hard db0d2ca

1
2
3
ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master)
$ git reset --hard db0d2ca
HEAD is now at db0d2ca My first commit

系统提示我们版本指针HEAD现在已经指向db0d2ca所对应的版本号了,也就是我们第一次提交时的版本。这时候看一下我们文件夹中的good.txt文件

版本回滚后的good.txt文件
你会惊喜的发现它已经变回去了!

这里版本回滚的参数 –hard其实也有–soft、–mixed可以选,–hard对应回滚本地库、暂存区、工作区,–mixed对应回滚本地库、暂存区,–soft对应回滚本地库。版本回滚的命令也有其他两种,分别是git reset –hard HEAD ^(想回滚几个版本就输入几个^)、git reset –hard HEAD ~数字(想回滚几个版本就输入数字几),推荐使用我演示的这种,因为它可以随意穿梭版本,穿梭回去还可以穿梭回来。

git一次分支的完整过程

分支无冲突修改

我们模拟一次分支操作,首先,在我们初始化 git 库时我们就在命名为master的默认分支上更迭版本信息,现在我们利用 git branch “dev”来创建一个叫做dev的分支。

1
2
3
4
5
6
7
ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master)
$ git branch "dev"

ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master)
$ git branch
dev
* master

这里我们还用了git branch 命令来查看当前的分支情况。可以看到,当前共有两个分支,*表示当前处在master分支,且新分支在创建时会直接拷贝原分支的当前版本信息作为自己的当前版本。

这里如果想删除分支,可以使用

1
git branch -D 分支名

接着,我们用git switch/git checkout 来切换当前分支

1
2
3
4
5
ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master)
$ git switch dev
Switched to branch 'dev'

ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (dev)

此时观察命令行后面的括号已经由master改为dev了,表明当前分支已经改变。我们在当前dev分支将good.txt修改一下。

在dev分支上作的good.txt修改
接着在dev分支上进行完整的提交其本地库操作,再转回到master分支,利用git merge融合dev版本上单修改版本。

1
2
3
4
5
6
7
8
9
10
ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (dev)
$ git switch master
Switched to branch 'master'

ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master)
$ git merge dev
Updating db0d2ca..fc43c90
Fast-forward
good.txt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

可以看到,master分支成功完成了融合操作。

1
2
3
4
ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master)
$ cat good.txt
我是ONE_CAN
在dev分支上做一些修改

在命令行中输入cat命令,可以预览到我们当前master分支上的文件已经成功修改了。

进行git merge操作切记:要先切换到被融合的分支再进行融合。

分支有冲突修改

此时我们在master分支上进行一些修改,在之前修改的地方改一个与之前修改内容不同的词语“修改”–>“改进”,此时master分支的good.txt是

1
2
3
4
ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master)
$ cat good.txt
我是ONE_CAN
在dev分支上做一些改进

进行完整提交后,再切回到dev分支,在之前修改的地方改一个与之前修改内容不同的词语“修改”–>“改装”。此时dev分支的good.txt文件是

1
2
3
4
ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (dev)
$ cat good.txt
我是ONE_CAN
在dev分支上做一些改装

完成完整提交后,我们再且切回master分支进行融合,此时由于相同地方出现不同修改,git无法为我们自动融合,需要我们手工融合。

1
2
3
4
5
6
7
8
ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master)
$ git merge dev
Auto-merging good.txt
CONFLICT (content): Merge conflict in good.txt
Automatic merge failed; fix conflicts and then commit the result.

ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master|MERGING)
$

可以看到此时发生了分支冲突,命令行后面的()里也变成了master分支的手动融合状态,我们再打开文件夹里的good.txt文件

出现分支冲突时进行融合的good.txt

由于两个分支都在同一版本上进行了修改,git无法判断我们想要选取哪一种修改,于是将修改处以“======”分隔上面的是被融合的部分的修改,下面是融合部分的修改,需要我们手动调整。

我们将此时的good.txt文件修改为dev分支所作修改的样子,即删除其他修改,此时good.txt文件变为

1
2
3
4
ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master|MERGING)
$ cat good.txt
我是ONE_CAN
在dev分支上做一些改装

然后,进行git add good.txt 将归并后的修改放入暂存区,我们再利用git status查看一下状态。

1
2
3
4
5
6
7
8
ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master|MERGING)
$ git status
On branch master
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)

Changes to be committed:
modified: good.txt

可以看到提示我们所有冲突都被解决了但仍然处于融合状态,我们需要利用git commit状态来结束融合状态。

1
2
3
ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master|MERGING)
$ git commit -m "resolve conflicts"
[master ddb10ac] resolve conflicts

不过这时注意,git commit命令不能再加我们的文件名good.txt,否则会报错。
这时,一次完整的分支冲突进行融合的过程就结束了。

如果我们在手动修改过程中突然不想修改了,就可以用git merge –abort终止这次融合,这只针对有冲突的情况。

gitgithub 联动操作🤏

远程库部署

以上我们学习了 git 的本地终端所有操作,现在我们来讲一讲 github 这个托管平台是怎么用的。我们登陆 github 后点击右上角的+,选择new repository来创建一个远程库。名字随便起,这里我用上一节的“gitdemo”命名我的远程库,剩下的readme.md文件之类的没有勾选。

这里我没有勾选是因为如果勾选了,它会用这个文件创建一个默认分支叫做main(以前就叫master但因为这个词有之前的黑奴农场主的意思, github 社区给它改名字了),而我们本地git库默认分支叫master,为了不产生歧义。

接下来我们想要将本地代码托管到远程库,有两种方式。

  1. 利用HTTPS,远程库的url为:
    1
    https://github.com/github用户名/仓库名.git
  2. 利用SSH,远程库的url为:
    1
    git@github.com:用户名/仓库名.git

利用git remote add 远程库地址别名 你的远程库url 命令来部署你的远程库,这里我推荐用SSH,HTTPS方式自2021年10月13日不再支持用户名密码,现在部署的时候得写成个人密钥TOKEN,至于如何配置SSH,这里照着这个B站UP视频做👇

SSH配置视频

1
2
ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master)
$ git remote add origin git@github.com:OneCanX/gitdemo.git

这里如果设置错了不要紧,可以直接利用 git remote rm origin 删除这个地址或者git remote set-url origin 新的url重新设置url。

像这样做我们就已经给远程库设置好了地址别名”origin”,完成了远程库部署。

推送操作

现在我们进行一次本地库给远程库的推送,利用git push origin master(origin 后面跟的是本地分支名)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ASUS@AKA-KAIZI MINGW64 ~/Desktop/gitdemo (master)
$ git push origin master
Enumerating objects: 21, done.
Counting objects: 100% (21/21), done.
Delta compression using up to 8 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (21/21), 1.72 KiB | 586.00 KiB/s, done.
Total 21 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), done.
remote:
remote: Create a pull request for 'master' on GitHub by visiting:
remote: https://github.com/OneCanX/gitdemo/pull/new/master
remote:
To github.com:OneCanX/gitdemo.git
* [new branch] master -> master

这时候再去观察远程库gitdemo,可以发现本地 git 库已经推送成功了。

远程库推送操作

克隆和拉取操作

当我们想要把远程git库下载到本地时,可以直接进行git clone git@github.com:OneCanX/gitdemo.git。我们在本地直接新建一个文件夹取名为“new”,然后在它里面打开 git bash,输入这个命令。

1
2
3
4
5
6
7
8
9
ASUS@AKA-KAIZI MINGW64 ~/Desktop/new
$ git clone git@github.com:OneCanX/gitdemo.git
Cloning into 'gitdemo'...
remote: Enumerating objects: 39, done.
remote: Counting objects: 100% (39/39), done.
remote: Compressing objects: 100% (15/15), done.
remote: Total 39 (delta 1), reused 39 (delta 1), pack-reused 0
Receiving objects: 100% (39/39), done.
Resolving deltas: 100% (1/1), done.

打开本地new文件夹,可以看到成功克隆了。

成功克隆后的new文件夹

这里在本地克隆是不需要本地初始化 git 库,克隆操作会直接将 github 上的项目代码以及包含它历史信息的.git库都拷贝到本地文件夹中。

之后如果再更新的话我们就需要git pull来拉取更新的版本信息。我们直接在github里将我们的good.txt改写一下,如下。

github上good.txt文件的修改
再利用git pull origin

这里注意要点击进入下载的有.git的文件夹里使用git bash才能使用git pull origin

1
2
3
4
5
6
7
8
9
10
11
12
13
ASUS@AKA-KAIZI MINGW64 ~/Desktop/new/gitdemo (main)
$ git pull origin
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 654 bytes | 5.00 KiB/s, done.
From github.com:OneCanX/gitdemo
bcc0975..f0c404c main -> origin/main
Updating bcc0975..f0c404c
Fast-forward
good.txt | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)

这时候再查看new/gitdemo里的good.txt

1
2
3
ASUS@AKA-KAIZI MINGW64 ~/Desktop/new/gitdemo (main)
$ cat good.txt
我在github上做的一些修改

可以发现文件已经更新了。

事实上git pull还可以看成git fetch+git merge,但大多数情况我们没必要按这个步骤去更新我们的版本。

git 协同工作🤏🤏🤏

这部分内容我觉得是我们利用 git 工作流最重要的部分。前面说了很多操作都是为了我们这里作铺垫。git 的存在就是方便团队协同工作的。

团队内协同工作

首先,对于一个团队,项目带头人是如何管理他的团队呢?

  1. 项目带头人在本地初始化一个 git 仓库并把它部署到 github上。
  2. 手下去在本地利用 git clone将他的 git 仓库克隆到其本地终端。
  3. 手下经过不懈努力,写好自己的项目部分并在本地完整提交,然后项目带头人在github项目界面中依次点击SettingsManage accessAdd people将生成链接发给手下,手下打开确认后成为此项目团队伙伴,此时就可以通过git push提交自己的本地项目部分。
  4. 然后在内容推送远程后,项目带头人再利用git pull将内容拉取下来做进一步修改,修改完毕后再利用git push将其推送到远程。

跨团队协同工作

对于不同团队,显然是不能给项目权限来让团队外的人协同工作的,这在 github 社区是很普遍的现象。那么应该如何合作呢?

  1. 项目带头人在本地初始化一个 git 仓库并把它部署到 github上。
  2. 团队外的人点击其 github 仓库右上角的Fork来将其仓库克隆到他的远程仓库,然后克隆到他本地。
  3. 团队外的人经过不懈努力,写好自己的项目部分在本地完整提交,然后利用git push将其推送到自己的远程仓库。
  4. 此时团队外的人点击自己 github 项目界面的 Pull Request向项目带头人发起一个请求,项目带头人同意后便可以将改动传送到项目带头人的远程仓库。
  5. 然后在内容推送远程后,项目带头人再利用git pull将内容拉取下来做进一步修改,修改完毕后再利用git push将其推送到远程。

关于 gitgithub 我想说的话

虽然也有很多没讲到,比如分支的产生原理(实际上只是一个新指针的创建),协同工作的部分很多时候还要更复杂像远程库一般会有两个分支(除了main还有develop,一般推送都是在develop上进行),还有许许多多的 git 命令,这里我也只是列出了我们平常人使用频率很高的几个。但我觉得这些内容也足够我们可以简单入门这个好用的工具了,我也并不是对这些内容烂熟于心,写这篇博客只是为了记录我之前学习这个的成果并查缺补漏。这里很多内容都参考了B站UP的视频,还有就是 github 可能登陆很慢,这需要你科学上网了,DDDD,🏃‍♂️🏃‍♂️886…