Git
$everything\ is\ local$
一、Git概述
Git是一个免费的、开源的分布式版本控制系统,可以快速高效的处理从小型到大型的各种项目。
Git易于学习, 占用空间小,性能快如闪电。它优于 SCM 工具,如 Subversion、CVS、Perforce 和 ClearCase,具有廉价的本地分支、方便的暂存区域和多个工作流等功能。
1.1Git历史
Linus在1991年创建了开源的Linux,从此,Linux系统不断发展,已经成为最大的服务器系统软件了。
Linus虽然创建了Linux,但Linux的壮大是靠全世界热心的志愿者参与的,这么多人在世界各地为Linux编写代码,那Linux的代码是如何管理的呢?
事实是,在2002年以前,世界各地的志愿者把源代码文件通过diff的方式发给Linus,然后由Linus本人通过手工方式合并代码!
你也许会想,为什么Linus不把Linux代码放到版本控制系统里呢?不是有CVS、SVN这些免费的版本控制系统吗?因为Linus坚定地反对CVS和SVN,这些集中式的版本控制系统不但速度慢,而且必须联网才能使用。有一些商用的版本控制系统,虽然比CVS、SVN好用,但那是付费的,和Linux的开源精神不符。
不过,到了2002年,Linux系统已经发展了十年了,代码库之大让Linus很难继续通过手工方式管理了,社区的弟兄们也对这种方式表达了强烈不满,于是Linus选择了一个商业的版本控制系统BitKeeper,BitKeeper的东家BitMover公司出于人道主义精神,授权Linux社区免费使用这个版本控制系统。
安定团结的大好局面在2005年就被打破了,原因是Linux社区牛人聚集,不免沾染了一些梁山好汉的江湖习气。开发Samba的Andrew试图破解BitKeeper的协议(这么干的其实也不只他一个),被BitMover公司发现了(监控工作做得不错!),于是BitMover公司怒了,要收回Linux社区的免费使用权。
Linus可以向BitMover公司道个歉,保证以后严格管教弟兄们,嗯,这是不可能的。实际情况是这样的:
Linus花了两周时间自己用C写了一个分布式版本控制系统,这就是Git!一个月之内,Linux系统的源码已经由Git管理了!牛是怎么定义的呢?大家可以体会一下。
Git迅速成为最流行的分布式版本控制系统,尤其是2008年,GitHub网站上线了,它为开源项目免费提供Git存储,无数开源项目开始迁移至GitHub,包括jQuery,PHP,Ruby等等。
历史就是这么偶然,如果不是当年BitMover公司威胁Linux社区,可能现在我们就没有免费而超级好用的Git了。
(摘录于廖雪峰官网Linux教程)
1.2版本控制
团队开发需要记录项目版本以及正确的版本控制,Git版本控制软件由此而来。
1.3版本控制工具
集中式版本控制工具
CVS、SVN(subversion)、VSS……
集中化的版本控制系统诸如CVS、SVN等,都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。多年以来,这已成为版本控制系统的标准做法。
优点是每个人都可以在一定程度上看到项目中的其他人正在做些什么。而管理员也可以轻松掌控每个开发者的权限,并且管理一个集中化的版本控制系统,要远比在各个客户端上维护本地数据库来得轻松容易。
缺点是中央服务器的单点故障。如果服务器宕机一小时,那么在这一小时内,准都无法提交更新,也就无法协同工作。
分布式版本控制工具
Git、Mercurial、Bazaar、Darcs……
像Git这种分布式版本控制工具,客户端提取的不是最新版本的文件快照,而是把代码仓库完整地镜像下来(本地库)。这样任何一处协同工作用的文件发生故障,事后都可以用其他客户端的本地仓库进行恢复。因为每个客户端的每一次文件提取操作,实际上都是一次对整个文件仓库的完整备份。
分布式的版本控制系统出现之后,解决了集中式版本控制系统的缺陷:
- 服务器断网的情况下也可以进行开发(因为版本控制是在本地进行的)
- 每个客户端保存的也都是整个完整的项目(包含历史记录,更加安全)
1.4Git工作机制

只有把代码提交到本地库,才会产生历史版本。
本地库→git push→远程库
1.5代码托管平台
代码托管中心是基于网络服务器的远程代码仓库,一般称为远程库。
局域网:Gitlab
互联网:Github、Gitee码云
二、Git安装
Git官网:https://git-scm.com/
默认选项安装
查看Git版本
1ChouS@DESKTOP-78VSLED MINGW64 ~
2$ git --version
3git version 2.37.0.windows.1
三、Git常用命令
大部分命令与Linux通用。
| 命令名称 | 作用 |
|---|---|
| git config –global user.name 用户名 | 设置用户签名 |
| git config –global user.email 邮箱 | 设置用户签名 |
| git init | 初始化本地库 |
| git status | 查看本地库状态 |
| git add 文件名 | 添加到暂存区 |
| git rm –cached 文件名 | 从暂存区删除 |
| git commit -m “版本信息” 文件名 | 提交到本地库 |
| git reflog | 查看历史纪录 |
| git reset –hard 版本号 | 版本穿梭 |
| git log | 查看当前版本详细日志 |
3.1用户签名
设置用户签名
git config --global user.name 用户签名
git config --global user.email 用户邮箱
查看用户签名

注意:
- 签名的作用是区分不同操作者的身份。用户签名信息在每一个版本的提交信息中能够看到,以此确定本次提交的谁做的。
- Git首次安装必须设置一下用户签名,否则无法提交代码。
- 这里设置的用户签名的用户名和邮箱与将来登录代码托管平台的账号没有任何关系。
3.2初始化本地库
git init
在项目根文件夹中右键选择git bush ,输入上命令,完成初始化本地库。
3.3查看本地库状态
git status
红名文件说明是改动的文件,未被添加到暂存区。
绿名文件,说明该文件状态已经从工作区add到暂存区,说明Git追踪到了该文件。
3.4添加到暂存区
添加到暂存区
git add 文件名
批量添加到暂存区
添加多个文件,文件之间以空格隔开
git add file1 file2 file3添加指定文件夹下的文件或者指定文件夹下指定格式文件
git add 算法/* //把算法文件夹下的全部文件添加到暂存区 git add 算法/*.md //把算法文件夹下.md格式的文件添加到暂存区添加所有文件
git add . git add --all
从暂存区删除
添加到暂存区还不会被版本控制记录,可以进行从暂存区删除命令。
git rm --cached 文件名
这个删除只是从暂存区删除,不会删除工作区的源文件。
3.5提交到本地库
git commit -m "版本信息" 文件名
执行该命令后,把暂存区的文件提交到本地库。此时,文件被版本控制记录。
3.6查看历史日志
git reflog
显示当前项目的所有历史版本,以及对应版本的版本号前七位(如本数据c16588d)。
3.7查看详细历史日志
1ChouS@DESKTOP-78VSLED MINGW64 /e/Github/Notes (master)
2$ git log
3commit b2325b3a938da90867449087ef4abfaaf2b96637 (HEAD -> master, notes/master)
4Author: SinbinChou <chousinbin@163.com>
5Date: Wed Jul 20 21:57:31 2022 +0800
6
7 2022-07-20
显示当前项目当前版本的详细日志信息。比如:完整的版本号、提交者的签名、提交时间、版本名等。
3.8修改文件
修改文件

修改newfile文件第一行尾添加了222。
修改后的状态

再次查看状态,我们发现有提示modified:文件名,这种状态说明此文件被修改过了。
另外这个提示是红色字体,所以这个修改的文件还没有被添加到暂存区,需要对此文件进行添加到暂存区。
添加到暂存区后的状态

添加到暂存区后,再次查看状态,绿色状态表明:当前文件是被修改且添加到暂存区后未被提交到本地库的文件。
提交到本地库

提交到本地库后返回操作者提交的版本信息、文件修改的数量、行数的插入数与删除数。
我们明明是在一行的结尾添加了数字$2$,为什么返回的信息是一行插入和一行删除呢?
因为Git是按照行来编辑的,在修改文件信息时,先删除当前行,再把修改后的信息插入到原来的位置。
提交到本地库后的状态

世界恢复了原有的平静。
虽然我们对此项目的一个文件可能进行多个版本的修改,但是本地源文件只有一个,版本控制由Git掌管。
3.9版本穿梭
git reset --hard 版本号
先找到版本号(前7位就可以)

选中要穿梭到的版本号,右击复制,执行版本穿梭命令。

查看穿梭后的日志信息

明显看到当前指向first version版本。最顶行多出一行日志记录我们进行了版本穿梭。说明版本穿梭也会被Git的日志记录,但版本号不会新增。
四、Git分支操作
4.1什么是分支
在版本控制过程中,同时推进多个任务,为每廷务,我们就可以创建每个任务的单独分支。使用分支意味着程序员可以把自己的工作从开发主线上分离开来,开发自己分支的时候,不会影响主线分支的运行。对于初学者而言,分支可以简单理解为副本,一个分支就是一个单独的副本。(分支底层其实也是指针的引用)
4.2分支的好处
同时并行推进多个功能开发,提高开发效率。
各个分支在开发过程中,如果某一个分支开发失败,不会对其他分支有任何影响。失败的分支删除重新开始即可。
4.3分支的操作
| 命令名称 | 作用 |
|---|---|
| git branch 分支名 | 创建分支 |
| git branch -v | 查看分支 |
| git checkout 分支名 | 切换分支 |
| git merge 分支名 | 把指定的分支合并到当前分支上 |
查看分支
git branch -v

创建分支
git branch 分支名
创建一个名为hot-fix的紧急修复分支。

创建的新分支,会克隆当前分支的的所有状态和信息,比如:历史版本信息等等。
切换分支
git checkout 分支名

切换成功后会返回切换成功信息,下一个提示符的蓝色括号由原来的master变成了hot-fix。
同时日志会记录分支切换信息。
分支修改文件

直接调用vim对最新版本的newfile.md文件进行修改。修改之后的状态与在同一个分支下修改文件相似,这里省略图文介绍,详细参考上文3.8修改文件。之后的步骤是:添加到暂存区、提交到本地库。
在修改分支提交的版本我们命名为hot-fix first version。

合并分支
git merge 分支名
合并前先把项目的分支切换到需要合并到的分支上**(master)**
执行合并命令

冲突合并
产生冲突的原因:合并分支时,两个分支在同一个文件的同一个位置有两套完全不同的修改。Git无法替我们决定使用哪一个。必须认为决定新代码的内容。
模拟冲突合并:
因为上一步我们刚刚把hot-fix中的 first version合并到mater中来,所以此时mater分支newfile的内容与hot-fix中newfile.md的内容一样。
我们先把master中的newfile最后一行尾加入master test。再进行添加和提交。版本命名master test。

再把分支切换到hot-fix,此时内容还未受到master分支的修改而修改。

这时我们把hot-fix中的newfile的倒数第二行末加上hot-fix test。

然后添加、提交。版本名为hotfix-version。切换回master分支,执行合并分支。

此时报错并且当前状态为在master分支上,并且正在合并分支,需要我们人为进入vim选择合并。

««« HEAD 与======之间的内容表示是当前mater分支的修改内容。
=======与»»»> hot-fix之间的内容表示hot-fix分支的修改内容。
我们需要手动修改内容并且删除多余的提示符号。

上图是人工手动修改合并后的信息,保留了两个处在不同分支的操作者对同一文件的修改。
保存完文件之后,还要把修改完的文件添加到暂存区以及提交到工作区的一系列操作,注意在手动合并后的提交到本地库的命令中不需要带文件名。

提交完成后,状态变为master。至此我们通过手动合并分支解决了代码冲突。

注意:合并分支只会修改合并到分支的文件的内容,从哪合并来的哪个分支通过合并操作不会被修改。

五、Github远程库操作
5.1配置SSH
设置用户签名
检查是否存在SSH Key
1ChouS@DESKTOP-78VSLED MINGW64 / 2$ cd ~/.ssh 3 4ChouS@DESKTOP-78VSLED MINGW64 ~/.ssh 5$ ls 6id_rsa id_rsa.pub known_hosts known_hosts.old存在
id_rsa.pub和id_rsa说明存在SSH密钥。如果没有,则执行生成SSH Key
1ChouS@DESKTOP-78VSLED MINGW64 ~/.ssh 2$ ssh -keygen -t rsa -C "邮箱地址"查看SSH Key
1ChouS@DESKTOP-78VSLED MINGW64 ~/.ssh 2$ cat id_rsa.pub 3ssh-rsa 4以下为密钥内容,此处不做展示。到Github配置添加密钥
登陆Github-右上角头像-settings-SSH and GPG keys-add。
配置好SSH后,在自己的电脑Github会自动与远程库保持通信。
5.2创建远程仓库
Repository
公网访问仓库名称为 username.github.io,每个账号只有一个。
非公网访问仓库名称用户自定义,有很多个供我们使用。
5.3远程仓库操作
创建远程仓库别名
| 操作命令 | 操作名称 |
|---|---|
| git remote -v | 查看当前所有远程地址的别名 |
| git remote add 别名 远程地址 | 设置远程地址的别名 |
查看远程地址别名有两行,说明这个别名可以用于推送、拉取、克隆等。
推送本地库代码到远程库
git push 别名/远程链接 分支
推送的最小单位是分支,需要指定推送哪一个分支。
拉取远程库到本地库
git pull 别名 分支
当本地库与远程库的项目文件内容不一致时,需要先用Pull拉取到本地,更新本地库与远程库保持一致。
克隆远程仓库到本地
git clone 远程地址
克隆会自动完成:1、拉取代码 2、初始化本地仓库 3、创建别名
当到一个新环境管理自己的或上级的项目需要克隆到本地以实现初始化和拉取最新代码。
5.4Github界面介绍
| 功能名称 | 作用 |
|---|---|
Code | 展示项目源码,提供源码Clone和打包下载。 |
Issues | 讨论区,可以对项目进行各种提问。我们每个人都可以在本区提出issuse。状态Open:讨论中状态Closed:关闭该帖,已经解决问题。 |
Pull requests | 从Fork的项目发起向原项目合并请求 |
fork | 原项目的拷贝数。 |
watch | 关注项目的变化,如果别人提交了pull、request、发起了issue,在通知中心会收到消息。 |
star | 类似于点赞,表示项目受欢迎度。 |
branch | 分支 |
tag | 标签 |
5.5Branch与Fork的区别
Fork属于远程托管平台的功能,并不属于Git的branch。
Fork是一个新的仓库,可以随便开分支,只要最后不乱 pull request 乱合并到原项目就不会出事;
branch 其实只是一个分支,比一个仓库的范围要小得多,你实际上还是处于同一个项目仓库中。
Pull Request:从Fork过衍生出的新项目向原项目发起合并推送请求。
5.6顶级域名
申请顶级域名并且指向username.github.io,会使之变为类似www.username.com等高大尚的地址。
申请渠道
- 阿里云
- 腾讯云
- GoDaddy
- freenom
从顶级域名渠道配置指向我们的GitHub地址后,要从GitHub的仓库setting中的Custom domain输入我们购买好的顶级域名,这样顶级域名就配置完成了。
5.7版本比较
在原项目的网址后面加上\compare可以访问该项目的版本比较页面,另外也有插件可以使得源码比较起来直观。