Git

该文档是:Git学习,感谢尚硅谷的教程!

博客连接:https://www.loveuluo.cn

日期:2021-01-27

1. 版本控制工具应该具备的功能

协同修改:

  • 多人并行不悖的修改服务器端的同一个文件。

数据备份:

  • 不仅保存目录和文件的当前状态,还能够保存每一个提交过的历史状态。

版本管理:

  • 在保存每一个版本的文件信息的时候要做到不保存重复数据,以节约存储空
    间,提高运行效率。这方面SVN 采用的是增量式管理的方式,而Git 采取了文

件系统快照的方式。

权限控制:

  • 对团队中参与开发的人员进行权限控制。
  • 对团队外开发者贡献的代码进行审核——Git 独有。

历史记录:

  • 查看修改人、修改时间、修改内容、日志信息。
  • 将本地文件恢复到某一个历史状态。

分支管理:

  • 允许开发团队在工作过程中多条生产线同时推进任务,进一步提高效率。

2. Git简介

2.1 Git 的优势

  • 大部分操作在本地完成,不需要联网
  • 完整性保证
  • 尽可能添加数据而不是删除或修改数据
  • 分支操作非常快捷流畅
  • 与Linux 命令全面兼容

2.2 Git结构

image-20210127134506848

2.3 Git 和代码托管中心

代码托管中心的任务:维护远程库

  • 局域网环境下

    • GitLab 服务器
  • 外网环境下

    • GitHub
    • 码云

2.4 本地库和远程库

团队内部协作:

image-20210127134853759

跨团队协作:

image-20210127135203145

3. Git 命令行操作

3.1 本地库初始化

其实就是把本地库建出来。

  • 创建一个文件夹作为本地库

image-20210127135901422

  • 右键Git bash here代表在这个文件夹中打开Git命令行窗口,其实操作和linux基本相同,也可以在外边打开 cd 进来。

image-20210127135949591

  • 输入git init命令初始化一个空的git仓库(这个.git是一个隐藏目录)

image-20210127140110367

  • 效果

image-20210127140321442

  • 注意:.git 目录中存放的是本地库相关的子目录和文件,不要删除,也不要胡乱修改。

3.2 设置签名

  • 形式

用户名:tom
Email 地址:goodMorning@atguigu.com

  • 作用:区分不同开发人员的身份
  • 辨析:这里设置的签名和登录远程库(代码托管中心)的账号、密码没有任何关系。
  • 命令

    • 项目级别/仓库级别:仅在当前本地库范围内有效

      • git config user.name tom_pro
      • git config user.email goodMorning_pro@atguigu.com
      • 信息保存位置:./.git/config 文件

      image-20210127141536513

    • 系统用户级别:登录当前操作系统的用户范围(一般来说实际中直接设置这个即可)

      • git config --global user.name tom_glb
      • git config --global user.email goodMorning_glb@atguigu.com
      • 信息保存位置:~/.gitconfig 文件

      image-20210127142623909

3.3 基本操作

git专属的命令都是以git开始的。

(1)状态查看

git status
查看工作区、暂存区状态

image-20210127143406978

(2)添加

git add [file name]
将工作区的“新建/修改”添加到暂存区

image-20210127144715506

image-20210127145111333

(3)提交

可以直接 git commit -m "提交的消息" [file name](不指定文件名的话就是提交所有暂存区的文件)
也可以git commit [file name]然后它会进入vim界面让你自己填写提交的消息
将暂存区的内容提交到本地库
这里演示第二种:

image-20210127145729531

image-20210127145852983

:wq保存退出文件,并且查看一下状态:

image-20210127150250420

此时修改一下good.txt文件,再查看一下状态:

image-20210127151318593

(4)查看历史记录

为了演示效果明显,这里多修改几次,多add 和 commit几次多弄几个版本。

git log命令查看多屏历史记录:
多屏显示控制方式
空格向下翻页
b 向上翻页
q 退出

image-20210127152536924

git log --pretty=oneline命令代表变成一行显示,更美观一点:

image-20210127152428952

git log --oneline变成一行并且哈希值就选其中的一部分:

image-20210127152642342

git reflog会多了HEAD@{xxx}的信息:
HEAD@{HEAD指针移动到当前版本需要多少步}

image-20210127152917213

(5)前进后退

  • 本质是什么

image-20210127155006043

  • 基于索引值操作[推荐]

    • git reset --hard [局部索引值]
    • git reset --hard 0d0c660

    image-20210127155407830

    image-20210127160048523

  • 使用^符号:只能后退

    • git reset --hard HEAD^
    • 注:一个^表示后退一步,n 个表示后退n 步
  • 使用~符号:只能后退

    • git reset --hard HEAD~n
    • 注:表示后退n 步

(6)前进后退中reset 命令的三个参数对比

  • --soft 参数

    • 仅仅在本地库移动HEAD 指针

    image-20210127161250443

回退到某个版本,只回退了commit的信息,不会恢复到index file一级。如果还要提交,直接commit即可。如果commit后,改错了文件,此时执行这个命令,stage会回退到提交之前的状态,修改后再次commit即可。

  • --mixed 参数

    • 在本地库移动HEAD 指针
    • 重置暂存区

    image-20210127161553451

此为默认方式,不带任何参数的git reset,即时这种方式,它回退到某个版本,保留本地源码,只是回退commit和index信息。此时stage区状态没有保留。

  • --hard 参数(常用)
  • 在本地库移动HEAD 指针
  • 重置暂存区
  • 重置工作区

彻底回退到某个版本,本地的源码也会变为上一个版本的内容。

(7)删除文件并找回

  • 前提:删除前,文件存在时的状态提交到了本地库。
  • 操作:git reset --hard [指针位置]

    • 删除操作已经提交到本地库:指针位置指向历史记录(删除aaa.txt这个操作也是一个版本可以add和commit)

    image-20210127162841405

    • 删除操作尚未提交到本地库:指针位置使用HEAD(删除文件的时候只add了没有commit)

    image-20210127163330760

    image-20210127163459806

(8)比较文件差异

  • git diff [文件名]

    • 将工作区中的文件和暂存区进行比较
  • git diff [本地库中历史版本] [文件名]

    • 将工作区中的文件和本地库历史记录比较

    image-20210127163945847

  • 不带文件名比较多个文件

3.4 分支管理*

(1)什么是分支?

合并分支之master一直没有改变版本的(commit)的情况,以master和feature_blue为例,创建分支feature_blue,此时feature_blue和master一模一样。feature_blue开始修改内容,master依旧不改变,feature_blue完毕后commit会生成一个新的版本号,此时master执行合并操作。当你合并时,首先会比较master的版本号,发现master版本号一直没有改变,git会自动覆盖修改的部分

合并分支之master改变了版本号的情况,还是以master和feature_blue为例,创建分支feature_blue,此时feature_blue和master一模一样。feature_blue开始修改内容,完成后提交生成一个新的版本号。此时master也进行了改变并且提交然后生成了新的版本号,此时master执行合并操作。比较master的版本号时发现master有了新的版本号,那么会对比改动的地方有没有冲突,如果有就要解决冲突。

image-20210127173304890

(2)分支的好处?

  • 同时并行推进多个功能开发,提高开发效率
  • 各个分支在开发过程中,如果某一个分支开发失败,不会对其他分支有任何影响。失败的分支删除重新开始即可。

(3)分支操作

  • 创建分支

    • git branch [分支名]

    image-20210127173624971

  • 查看分支

    • git branch -v

    image-20210127173653148

  • 切换分支

    • git checkout [分支名]

    image-20210127173824747

  • 合并分支

    • 第一步:切换到要被合并的分支(增加新内容) git checkout [要被合并的分支名]

    image-20210127183725879

    • 第二步:执行merge 命令 git merge [有新内容分支名(被合并)]

    image-20210127184254771

  • 解决冲突

    • 冲突的表现

      • Master主干的修改

    image-20210127185538293

    image-20210127185126921

    • hellofenzhi1分支的修改

      image-20210127185903858

    image-20210127185709896

    • 进行合并操作

    image-20210127190045035

    • 最终的冲突的表现

    image-20210127190437899

    • 冲突的解决

      • 第一步:编辑文件,删除特殊符号

      image-20210127190629149

      • 第二步:把文件修改到满意的程度,保存退出
      • 第三步:git add [文件名]

      image-20210127190918869

      • 第四步:git commit -m "日志信息"(结束合并)
      • 注意:此时commit 一定不能带具体文件名,现在是合并操作而不是提交

      image-20210127191045837

4. Git 基本原理

4.1 哈希

image-20210127192137380

哈希是一个系列的加密算法,各个不同的哈希算法虽然加密强度不同,但是有以下几个共同点:
①不管输入数据的数据量有多大,输入同一个哈希算法,得到的加密结果长度固定。
②哈希算法确定,输入数据确定,输出数据能够保证不变
③哈希算法确定,输入数据有变化,输出数据一定有变化,而且通常变化很大
④哈希算法不可逆
Git 底层采用的是SHA-1 算法。

哈希算法可以被用来验证文件。原理如下图所示:

image-20210127192151838

4.2 保存版本的机制

(1)集中式版本控制工具的文件管理机制

以文件变更列表的方式存储信息。这类系统将它们保存的信息看作是一组基本文件和每个文件随时间逐步累积的差异。

image-20210127193142276

(2)Git 的文件管理机制

Git 把数据看作是小型文件系统的一组快照。每次提交更新时Git 都会对当前的全部文件制作一个快照并保存这个快照的索引。为了高效,如果文件没有修改,Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件。所以Git 的工作方式可以称之为快照流。

image-20210127193201802

(3)Git 文件管理机制细节

  • Git 的“提交对象”

image-20210127193225614

  • 提交对象及其父对象形成的链条

image-20210127193235819

4.3 Git 分支管理机制

(1)分支的创建

image-20210127193615591

(2)分支的切换

image-20210127193716944

image-20210127193807256

image-20210127193908735

image-20210127194119336

5. GitHub

5.1 创建github账户

GitHub 首页就是注册页面:https://github.com/

5.2 新建一个本地库测试用

名字就叫做GitTest02。

image-20210127195753636

5.3 创建远程库

image-20210127200019371

image-20210127200031242

5.4 创建远程库地址别名

image-20210127200616262

每次操作都带着那么长一串地址肯定不方便,所以给远程库地址起个别名:

git remote -v 查看当前所有远程地址别名
git remote add [别名] [远程地址]

image-20210127200820411

5.5 推送

image-20210127205126647

git push [别名] [分支名]

image-20210127201247664

image-20210127201328452

5.6 克隆

  • 随便再创建一个文件夹 演示另一个人进行克隆效果,这个文件夹不用进行初始化,直接进行克隆操作
  • git origin [地址]

image-20210127201750474

image-20210127201840745

  • 效果

    • 完整的把远程库下载到本地
    • 自动创建origin 远程地址别名
    • 自动初始化本地库

    image-20210127202049881

5.7 团队成员邀请

修改huashan.txt add然后commit。

image-20210127202356529

image-20210127202350726

此时flamie(演示用当作另一个人)想要推送代码,但是还没有加入团队。演示如何拉人进入团队

image-20210127202730259

“GitTest02”用其他方式(qq、vx)把邀请链接发送给“flamie”,“flamie”登录自己的GitHub账号,访问邀请链接。

image-20210127202828036

接受了之后就变成了团队成员,再进行推送操作。

image-20210127204334861

5.8 拉取

  • pull=fetch+merge
  • git fetch [远程库地址别名] [远程分支名]:抓取操作(本地文件还没有变,只是把远程的内容下载到本地,没有改本地工作区的文件)
  • git merge [远程库地址别名/远程库的分支名]:把远程的master合并到我们本地的master
  • git pull [远程库地址别名] [远程分支名]

image-20210127210114933

5.9 协同开发时冲突的解决

例如:两个人改了同一个文件的同一个位置,只有先推送的那个人能推送到远程库里。后推送的推送不上去,后推送的必须先拉取下来然后才能去推送。拉取下来的时候同一个位置 有别人的内容和你自己的内容,这个时候git就不能替我们去做决定了,必须我们自己做决定。

  • 如果不是基于GitHub 远程库的最新版所做的修改,不能推送,必须先拉取。
  • 拉取下来后如果进入冲突状态,则按照“分支冲突解决”操作解决即可。

5.10 跨团队协作

image-20210127135203145

  • Fork

image-20210127213222112

image-20210127213228790

image-20210127213233767

  • 本地修改,然后推送到远程
  • Pull Request

image-20210127213247350

image-20210127213251523

image-20210127213257347

image-20210127213303386

image-20210127213307848

  • 对话

image-20210127213321402

image-20210127213327433

  • 审核代码

image-20210127213336349

  • 合并代码

image-20210127213347481

image-20210127213353682

  • 将远程库修改拉取到本地

5.11 SSH免密登录

  • 进入当前用户的家目录

$ cd ~

  • 删除.ssh 目录

$ rm -rvf .ssh

  • 运行命令生成.ssh 密钥目录

$ ssh-keygen -t rsa -C atguigu2018ybuq@aliyun.com

[注意:这里-C 这个参数是大写的C,后边是github登录的邮箱]

  • 进入.ssh 目录查看文件列表

$ cd .ssh
$ ls -lF

  • 查看id_rsa.pub 文件内容

$ cat id_rsa.pub

  • 复制id_rsa.pub 文件内容,登录GitHub,点击用户头像→Settings→SSH and GPGkeys
  • New SSH Key
  • 输入复制的密钥信息
  • 回到Git bash 创建远程地址别名

git remote add origin_ssh git@github.com:atguigu2018ybuq/huashan.git

  • 推送文件进行测试

6. 在IDEA中使用Git

6.1 全局配置

(1)配置Git核心程序

  • 配置git.exe执行文件

点击工具栏中的settings→Version Control→Git

image-20210128090051885

  • 点击Test测试

image-20210127213424

(2)配置GitHub账户

image-20210128090345705

image-20210128091653407

6.2 创建本地库和基本操作

(1)创建一个Empty Project:

image-20210128092730342

(2)在空工程(Empty Project)中添加模块(Modules):

image-20210128092744072

(3)添加一个Maven模块:

image-20210128092808851

(4)选择我无论如何都想编辑这个文件:

image-20210128092844038

(5)创建本地库
image-20210128092904895

(6)选择当前模块的上一级目录

image-20210128092916095

(7)点击OK本地库创建成功

image-20210128092930339

image-20210128092936118

(8)同时工具栏会出现Git相关操作

image-20210128092950419

(9)在src/main/java和src/main/resources目录下创建文件,创建了新文件之后会提示是否添加到暂存区

image-20210128093006932

(10)这里我们先点击Cancel,此时文件只存在于工作区,文件的状态如下图:

image-20210128093017390

(11)设置忽略文件

image-20210128094110058

要先安装.ignore插件

image-20210128094444155

(12)在模块上右键->New ->.ignore file ->.gitignore file(Git)

image-20210128094936426

(13)先选择Example user template好了,以后有什么想过滤的可以自行添加,~最后点击Generate生成

image-20210128095023960

下面是一些.gitignore文件忽略的匹配规则:

*.a       # 忽略所有 .a 结尾的文件
!lib.a    # 但 lib.a 除外
/TODO     # 仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO
build/    # 忽略 build/ 目录下的所有文件
doc/*.txt # 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt

.gitignore只能忽略那些原来没有被track的文件,如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的。那么解决方法就是先把本地缓存删除(改变成未track状态),然后再提交:
输入:
git rm -r –cached filePath
git commit -m “remove xx”
或者:
git rm -r –cached .
git add .
git commit -m “update .gitignore”

来解释下几个参数 -r 是删除文件夹及其子目录 –cached 是删除暂存区里的文件而不删除工作区里的文件,第一种是删除某个文件,第二种方法就把所有暂存区里的文件删了,再加一遍,相当于更新了一遍。

(14)创建.gitignore文件并把它add入暂存区之后发现被忽略的文件变成了灰色(有时候可能需要刷新模块或重启Idea才能看到

image-20210128093129767

(15)在模块上右键将所有文件除了忽略的添加到暂存区

image-20210128093142001

(16)添加到暂存区之后文件的状态如下图:

image-20210128093151501

(17)在模块上右键或点击工具栏将文件添加到本地库

image-20210128093200415

工具栏

image-20210128093206325

(18)添加注释内容后提交

image-20210128093218192

(19)提交到本地库之后文件的状态如下图:

image-20210128093227772

6.3 版本间切换

(1)在模块上右键或者点击工具栏查看历史

image-20210128101150388

(2)选择要切换的版本

image-20210128101157286

(3)右键→Copy Revision Number复制哈希值

image-20210128101204054

(4)在模块上右键

image-20210128101214870

(5)选择Hard并粘贴版本号

image-20210128101226579

(6)版本切换成功

image-20210128101237412

(7)此时发现历史记录中只剩下更新1和添加文件了,怎么切换回更新3版本呢?

image-20210128101417626

image-20210128101358042

6.4 创建分支

(1)在模块上右键

image-20210128101451119

(2)点击New Branch

image-20210128101505245

(3)给新分支命名

image-20210128101513999

(4)点击Create后自动切换到新分支

(5)在新分支添加新的代码并提交

image-20210128101528402

6.5 合并分支

(1)在模块上右键切换到主干

image-20210128102315901

image-20210128102321462

(2)在模块上右键选择合并改变

image-20210128102332628

(3)选择要并的分支

(4)合并成功

image-20210128102356937

6.6 解决冲突

让主干和分支在同一个位置添加一行代码

(1)分支添加内容,并添加到暂存区和本地库

image-20210128103855114

(2)主干添加内容,并添加到暂存区和本地库

image-20210128103903467

(3)在主干合并分支内容,出现冲突

image-20210128103912696

(4)选择合并,出现处理窗口

image-20210128103920021

(5)处理之后

image-20210128103928245

(6)点击Apply应用

image-20210128103938731

6.7 将本地库上传到GitHub

(1)在GitHub网站上创建仓库

image-20210128115646278

(2)复制仓库地址

image-20210128115702577

(3)在Idea中的模块上右键

image-20210128115710188

(4)设置远程地址别名

image-20210128115718510

(5)点击Push推送到GitHub仓库

image-20210128115728235

(6)上传成功

image-20210128115736316

6.8 更新本地库

正常情况下是合作伙伴上传新的代码到GitHub,如果此时本地库不更新将无法上传,为了简单起见,我们直接在GitHub上在线修改文件。

(1)在GitHub上在线添加一个文件

image-20210128121418658

(2)Idea中的本地库也修改文件、添加到暂存库、添加到本地库,然后上传,发现上传被拒绝

image-20210128121432369

(3)此时点击Merge或Rebase都可以实现本地库与远程GitHub的同步[可能会有冲突需要处理冲突]

(4)也可以点击Cancel之后通过以下方式更新本地库

image-20210128121500134

(5)点击Pull将GitHub上最新的代码合并都本地库

image-20210128121509358

(6)点击Pull之后新本地库成功

6.9 从GitHub上克隆项目到本地

(1)点击Idea中的CVS选项

image-20210128122215300

(2)输入GitHub中的仓库地址并指定项目的存放路径

image-20210128122224400

(3)提示是否为克隆的项目创建一个新工程

image-20210128122231215

(4)点击Yes弹出导入工程的提示框

image-20210128123433256

(5)点击Next之后选择自己要的东西

image-20210128123450964

(6)点击finsh克隆成功

最后修改:2021 年 01 月 30 日 10 : 59 PM
如果觉得我的文章对你有用,请随意赞赏