视频资料
0x001 集中式版本控制工具
集中式版本控制工具,版本库是集中存放在中央服务器的,team里每个人work时从中央服务器下载代码,必须联网才能工作,局域网或互联网。个人修改后提交到中央版本库
比如:SVN和CVS
0x010 分布式版本控制工具
分布式版本控制系统没有 "中央服务器"的概念,每个人的电脑上都是一个完整的版本库,这样工作的时候就无需联网了,因为版本库就在本机上。多人协作只需要各自的修改推送给对方,就能互相看到对方的修改。
比如:Git
0x011 Git
特点:分布式、不需要中心服务器
Git是一个开源的分布式版本控制系统,可以有效、告诉地处理从很小到很大的版本控制管理。 Git是Linus Torvalds 先生(Linux之父)为了管理 Linux内核开发而开发的版本控制软件。
相关命令以及作用:
命令 | 作用描述 |
---|---|
clone | 克隆,从远程仓库中克隆代码到本地仓库 |
checkout | 检出,从本地仓库中检出一个仓库分支然后进行修订 |
add | 添加,在提交前先将代码提交到暂存区 |
commit | 提交,提交到本地仓库。本地仓库中保存修改的各个历史版本 |
fetch | 抓取,从远程库抓取到本地仓库,不进行任何的合并操作 |
pull | 拉取,从远程库拉到本地库,自动进行合并(merge),然后放到工作区,相当于 fetch + merge |
push | 推送,修改完成后,需要和团队成员共享代码时,将代码推送到远程仓库 |
Git官方网址:https://git-scm.com/download/win
点击 Click here to download
直接下载,下载完毕后进行安装
Git 的两个版本:
Git GUI : Git 提供的图形界面工具
Git Bash: Git 提供的命令行工具
当安装Git后首先要做的事情是设置用户名称和email地址。
0x001 打开Git Bash 配置Git的邮箱
git config --global user.name ccuni
git config --global user.email [email protected]
后面参数不填可以查询结果
0x001 使用Git Bash 在用户目录创建 bashrc文件
touch ~/.bashrc
0x010 编辑 .bashrc
vim ~/.bashrc
通过alias输入以下内容:
# 用于输出git提交日志
alias git-log='git log --pretty=oneline --all --graph --abbrev-commit'
# 用于输出当前目录所有文件及基本信息
alias ll='ls -al'
source ~/.bashrc
现在使用ll
命令则可以达到 ls -al
的效果
要使用Git对代码进行版本控制,首先需要获得本地仓库
Git工作目录下对于文件的修改(增加、删除、更新)会存在几个状态,这些修改的状态会随着我们执行Git的命令而发生变化。
git add 工作区 -> 暂存区
git commoit 暂存区 -> 本地仓库
git status
git add
单个文件名 | 通配符
git add .
git commit -m "注释内容"
关于log的配合参数在3.1部分已配置为git-log的别名命令
git log [options]
git reflog
可以查看所有提交(包括已删除)的记录git reset --hard commitID
git log
命令查看有些文件无需纳入Git的管理,也不希望它们总出现在未跟踪文件列表。通常都是些自动生成的文件,比如:日志文件、编译过程中创建的临时文件等。在这种情况下,我们可以在工作目录中创建一个名为.gitignore
的文件(文件名固定),列出要忽略的文件模式。
touch .gitignore
接下来在 .gitignore
中编辑忽略的文件格式
比如:忽略以a为后缀的文件
*.a
现创建一个a后缀的文件进行测试
touch file2.a
这里发现尽管 .gitignore
未提交到暂存区,但是仍然有过滤的作用,先将其删除,再查询log:
rm .gitignore
git log
删除.gitignore
后,file2.a
文件出现在了工作区,说明了之前的配置,即忽略.a后缀的文件是有效果的。
另,若想.gitignore
过滤的配置文件长久生效,需要先add到暂存区,然后在commit到仓库。
创建 test-git 文件夹
在里面右键打开 Git - Bash,初始化一个git仓库
git init
创建文件
touch file1.txt
查看状态
git status
可以看到 touch后的文件 一开始是 Untracked
即未跟踪的状态
将当前目录的所有文件添加到缓存区
git add .
再次查看 git的状态,列出了 Changes to be commiteed
(即将被提交)的文件列表,即Git暂存区的文件列表
将暂存区的所有文件提交到仓库(-m指定本次提交的描述)
git commit -m "test, add file1"
提交之后在查看 Git状态,暂存区的文件列表已消失。
那么提交的文件去哪里了?则可通过日志查看
查看Git运行日志
git log
现进行文件修改的测试,首先编辑本地文件 file01.txt里的内容
命令行或者直接打开文件两种方式
vi file1.txt
vi 方式保存先按ESC,在输入:wq
保存退出
修改过后再次查询 Git 状态,可以发现修改的 file01.txt文件变成了未跟踪的状态,此时它处于工作区,接下来再将整个文件add到缓存区
在暂存区出现了 modified 修改操作的文件列表,接下来再使用commit命令提交
接着查看Git的日志
可以发现,之前的创建file1.txt和修改file1.txt都在日志中记录了下来,同时还显示了当时提交指定的描述。
现使用版本回退,将仓库回退到file1.txt修改前的状态
git reset --hard 之前版本的提交ID
此时再使用 git log
查看日志,发现修改file1.txt后的提交记录消失了
提交后cat 之前修改过的file1.txt,可以发现输出内容为空,表示回退到了还没有修改的版本。
但是回退版本后,能否在返回到修改后的状态呢?答案是可以的。
首先使用 git reflog
命令查看所有提交过的命令,然后同样使用git reset --hard 版本号
回到修改后的版本
git reflog
git reset --hard 修改后的版本号
可以看到,成功切换到了后来的版本,接下来在cat file1.txt的内容
版本切换成功
几乎所有的版本控制都以某种形式支持分支。使用分支意味着你可以把你的工作从开发主线上分离开来进行重大的bug修改、开发新的功能,以免影响开发主线
git branch
git branch 分支名
git checkout 分支名
# 切换分支,若分支不存在则先创建再切换
git checkout -b 分支名
一个分支上的提交可以合并到另一个分支
git merge 分支名称
一般都是将其他分支合并到 master,即在master分支里执行merge命令合并其他的分支
不能删除当前分支,只能删除其他的分支
git branch -d b1 # 删除分支时,需要做各种检查
git branch -D b1 # 不做任何检查,强制删除
场景:当同一个仓库两个分支同时修改同一个文件的同一行,不同分支具有不同的内容,当进行分支合并时,会产生冲突。
解决冲突步骤如下:
实践:
前提:在3.3.7 部分,已初始化一个仓库,并上传了一个file1.txt文件,现进行分支的创建于切换。并且已经配置号了3.1部分的git-log
自定义的别名命令,现进行解决冲突的测试。
0x001 切换分支 dev1
,编辑 file1.txt 文件的内容
git checkout dev1
vim fil1.txt
dev1 分支 file1.txt文件的内容如下:
hello
world
修改后提交到暂存区、然后上传到仓库
git add .
git commit -m 'update fil1 1-hello 2-world'
git-log # 笔者设置的别名命令(在文章的3-1部分)
运行结果:
可以看到,刚才提交的操作已记录在ID缩写为 98b5a8f
的版本。其中的HEAD指向的则是该版本里操作的分支。
0x010 切换到分支master,同样编辑 file1.txt 的内容
git checkout master
vim file1.txt
首先尝试与dev1的分支 file1.txt 文件内容一致,即:
hello
world
修改保存file1.txt后,提交到暂存区、再提交到仓库
git add .
git commit -m 'update file1 1-hello 2-wolrd'
git-log # 笔者设置的别名命令(在文章的3-1部分)
根据结果可以看到,刚刚提交的版本e35a8a5
是在测试之前ID缩写为 902d053
版本的基础上产生的。
现在进行合并操作,看看是否会发生报错,目前dev1分支和master分支的仓库内容是一致的。(当前处于master分支)
git merge dev1
git-log # 笔者设置的别名命令(在文章的3-1部分)
刚刚的提交产生了98b5a8f
版本,并且没有发生任何警告,通过结果可以直观的发现它是由98b5a8f
和e35a8a5
合并而来的。
现再次编辑master分支的file1.txt文件,将其改为不同于dev分支的file1.txt,然后再进行分支合并。
vim file1.txt
file1.txt 只修改第二行的内容为:
hello
uni
修改后保存退出,提交到暂存区、仓库
git add .
git commit -m 'update file1 1-hello 2-uni'
git-log # 笔者设置的别名命令(在文章的3-1部分)
现再次进行合并
git merge dev1
git-log # 笔者设置的别名命令(在文章的3-1部分)
出现了 Already up to date
,所以在Master合并了其他分支后,在Master里进行文件内容的修改,是与其他分支文件内容没有关联的。
0x011 切换到 dev1 分支,编辑 file1.txt文件的内容
git checkout dev1
vim file1.txt
文件内容依旧是之前的
hello
world
现将其改成:
hi
world
git add .
git commit -m 'update file1 1-hi 2-world'
git-log # 笔者设置的别名命令(在文章的3-1部分)
0x100 切换到 master 分支 查看文件内容
git checkout master
cat file1.txt
运行结果:
可以发现,尽管合并了dev1分支,且在dev1分支里提交修改的file1.txt 文件到仓库,切换回master分支,发现文件file1.txt 未发生改变,这说明合并分支只是将其他分支的当前状态保存到了主分支,之后子分支的操作则不能影响到父分支的仓库,现在再次进行合并
git merge dev1
执行合并操作,出现合并冲突的错误提示,fix conflicts and then commit the result.
查看git的状态发现有一个同时修改 file1.txt 的提示
git status
查看file1.txt的文件内容,如下:
cat file1.txt
可以发现文件里同时出现了两个分支的修改内容
<<<<<<< HEAD
... 这里是当前分支的fil1.txt文件内容
=======
... 这里是dev分支的fil1.txt文件内容
>>>>>>> dev1
最简单粗暴的方法是将这个文本的内容改成想要的内容,然后在add、commit。比如改成:
hello,wolrd
接下来提交到暂存区、再提交到仓库
git add .
git commit -m 'update 1-hello,wolrd'
最后查看效果
git-log # 笔者设置的别名命令(在文章的3-1部分)
根据结果可观察到,刚刚提交的ee8c684
版本是由a90569b
、8a9aa0e
、1ae843c
版本合并而来的,因为在提交时使用-m参数指定本次提交的描述,所以没有显示Merge branch dev1
的字样,不过最终还是能说明merge最终还是生效了。
最后删除测试的dev1分支
git branch -d dev1
由于之前我们已经进行过合并操作,所以可以直接删除分支,但是当dev1分支有变化,而且还没有合并到master时,删除分支会提示没有merge的报错。此时要么合并该分支,要么强制删除分支
git branch -D dev1
几乎所有的版本控制系统都以某种形式支持分支。使用分支意味着你可以把你的工作从开发主线上分离开来进行重大的BUG修改、开发新的功能,以免影响开发主线。
在开发中,一般有如下分支使用原则与流程:
线上分支、主分支,中小规模项目作为线上运行的应用对应的分支
是从 master创建的分支,一般作为开发部门的主要开发分支,如果没有其他并行开发不同期上线要求,都可以在此版本进行开发,阶段开发完成后,需要合并到master分支,准备上线。
从develop创建的分支,一般是同期并行开发,但不同期上线时创建的分支,分支上的研发任务完成后合并到develop分支。
从 master 派生的分支,一般作为线上Bug修复使用,修复完成后需要合并到 master、test、develop分支。
Git具有本地仓库和远程仓库这两种类型的仓库,之前的内容是基于本地仓库的操作,接下来则进行Git远程仓库的学习,可以使用互联网上提供的代码托管服务平台来实现,比较常见的有 GitHub、码云、GitLab等。
GitHub ,网址:https://github.com/ ,是一个面向开源及私有的软件项目托管平台,因为只支持Git作为唯一的版本库进行托管,故名为GitHub
码云,网址:https://gitee.com/ ,是国内的一个代码托管平台,由于服务器在国内,所以相比GitHub,码云速度快很多。
GitLab,网址:https://about.gitlab.com/ 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的Web服务,一般用于企业、学校等内部网络搭建git私服。
在本地 Git Bash生成 SSH公钥
ssh-keygen -t rsa
Gitee设置账户公钥
在本地的 Git Bash
获取公钥
cat ~/.ssh/id_rsa.pub
接下来在 Gitee 个人中心 安全设置 - SSH公钥 里设置 刚才生成的公钥,这里笔者将标题指定为设备名称,用于区分其他的公钥。
添加完毕后:
验证是否配置成功
ssh -T [email protected]
码云注册过程略过,以下是注册完毕后的记录
网址:https://gitee.com/projects/new
是否开源根据个人情况而定,笔者这里是将仓库作为开源的资料分享
接下来复制远程仓库的 SSH地址
git remote add origin 仓库的SSH地址
git remote #查看当前Git的所有远程地址
接下来将本地仓库上传到远程的Gitee仓库
git push origin master
刷新 gitee仓库,发现仓库提交成功
先初始化本地库,确保有本地git仓库,然后与已创建的远程库进行对接。
git remote add <远程名称> <仓库路径>
git remote
命令:
git push [-f] [--set -upstream] [远程名称[本地分支名][:远程分支名]]
若远程分支名和本地分支名相同,则可以只写本地分支名,比如:
git push origin master
-f 强制覆盖 *慎用
--set -upstream
推送到远端的同时且建立起和远端分支的关联关系
比如:git push --set-upstream origin master
如果当前分支已经和远端分支关联,则可以省略分支名和远端名。
比如:git push
将 master 分支推送到已关联的远端分支
git branch -vv
命令远程分支和本地的分支一样,我们可以进行merge操作,只是需要先把远端仓库里的更新都下载到本地,再进行操作。
抓取命令:git fetch [remote name] [branch name]
拉取命令:git pull [remote name] [branch name]
fetch + merge
范例:通过Https地址进行克隆,测试的地址:https://gitee.com/ccuni/web.git
首先在克隆保存位置打开 Git Bash,然后使用 git clone 命令进行克隆,并将文件名重命名为 test-clone
git clone https://gitee.com/ccuni/web.git test-clone
第二种克隆则可以通过SSH,比如笔者之前设置了Gitee账户的远程SSH,所以可以通过本机去连接Gitee账户的仓库,其他账户则不行。
在克隆的文件夹里打开 Git Bash,创建一个测试文件
touch file3.txt
git add .
git commit -m 'add file3'
git push
接下来,在之前上传到仓库的本地Git仓库里执行拉取的命令,此时是操作同一个gitee仓库
git fetch
可以看到,使用fetch命令获取到的仓库版本号3121a5c
在当前版本号ee8c684
的上面,此时需要手动执行一个merge命令
git merge origin/master
现在换一种方式进行拉取,首先继续在克隆后的文件夹里新建一个文件并push提交
touch file4.txt
git add .
git commit -m 'add file4'
git push
接着在之前本地的git仓库里进行 pull
拉取操作
git pull
在一段时间,A、B用户修改了同一个文件,且修改了同一行位置的代码,此时会发生合并冲突。
A用户在本地修改代码后优先推送到远程仓库,此时B用户在本地修订代码,提交到本地仓库后,也需要推送到远程仓库,此时B用于比A用户提交的晚,故需要先拉取远程仓库的提交,经过合并后才能推送到远程分支,如下图所示:
在 B 用户拉取代码时,因为 A、B用户同一时间段修改了同一个文件的相同位置的代码,故会发生合并冲突。
远程分支合并时发生冲突和本地分支冲突的解决是一样的。可参考 本篇文章的 3.4.6部分
################# 1- 将本地仓库推送到远程仓库
# 完成 4.1、4.2、4.3的操作
略
# [test-git] 添加远程仓库
git remote add orgin [email protected]/**/**.git
# [test-git] 将 master分支推送到远程仓库,并与远程仓库的master分支绑定关联关系
git push --set-upstream orgin master
################# 2- 将远程仓库克隆到本地
# 将远程仓库克隆到本地 git_clone 目录下
git clone [email protected]/**/**.git git_clone
# [git_clone] 以精简的方式提交记录 3.1 部分的别名命令
git-log
################# 3- 将本地修改推送到远程仓库
# [test-git] 创建文件 file3.txt
略
# [test-git] 将修改加入暂存区并提交到仓库,提交记录内容为:add file3
git add .
git commit -m 'add file3'
# [git_clone] 将 master 分支的修改推送到远程仓库
git push origin master
################# 4- 将远程仓库的修改更新到本地
# [git_clone] 将远程仓库修改再拉取到本地
git pull
File -> Settings
搜索 Git,点击 Test 测试,可以自动识别到 Git的安装目录
场景:本地已有一个项目,但不是git项目,需要将这个项目放到码云的仓库里,和其他开发人员继续一起协作开发。
创建远程仓库参考 4.3 部分
进入 File -> Setting
首先确保版本控制这里为空,若已有一个项目之类的,需要先将其删除。
接下来使用 IDEA 创建 Git仓库
点击创建 Git 仓库后,选择当前打开的IDEA项目,设置完毕后,可以在File->Settings里看到版本控制的内容如下:
接下来在IDEA项目根目录创建.gitignore
文件,用于过滤一些不需要上传的文件夹或文件
笔者设置的.gitignore
的内容是:(参考于SpringBoot项目)
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
将当前项目提交到Git仓库
点击提交后会进行代码分析,这里提示了若干个错误和警告
笔者这里仅做测试,先提交上去试试,提交完成后
远程的地址为Gitee仓库的 SSH网址
出现错误:
这里报错的原因是,没有将远程仓库的文件pull下来,所以需要先pull远程仓库的文件,与本地仓库进行合并,之后在push到远程仓库
拉取完毕后,再次进行推送,最后的Git日志如下:
可以观察到,之前Git测试的所有操作都存储在了记录中,同时查看Gitee对应的仓库,可以查到项目的所有文件。
由于之前的测试,项目里多余了四个文件,现将其删除,首先在IDEA项目中直接将其删除
使用IDEA进行快速提交,快捷键 [Ctrl + K]
之后将本次的修改,push到远程仓库
查看Git运行日志
查看远程仓库内容,删除完毕
提示是否打开,这里笔者选择打开,因为之后会进行协作开发的模拟操作
打开项目后,可以发现具有和之前同样的Git运行日志,克隆完毕后需对项目进行Web的相关配置,这里笔者就略过了。
场景:A、B程序员同时操作和一个远程仓库同步的项目,他们都修改了同一个文件,但是修改的内容不同,现在A程序员将项目pull到远程仓库,此时B在将项目pull到远程仓库时则提示冲突。
这里笔者用克隆前的项目模拟A程序员,克隆后的项目模拟B程序员
模拟:
A程序员修改文件 CodeAction.java
,如图,注释了27行到32行之间的部分
接着提交到本地仓库,然后推送、上传到远程仓库,和 5.2.4 部分一致
接着,推送到远程仓库,执行后的结果
现模拟程序员B的操作,同样是修改CodeAction.java:
注:此时远程仓库的内容已经发现变化了,多了程序员A上传的版本,所以程序员B在进行修改前,有必要pull拉取远程仓库的内容。
注释31行到32行的内容,提交到本地仓库,然后push到远程仓库
观察Git运行日志,此时没有报错,上传成功
程序员A:
提交到远程仓库过程图略
程序员B:
同样地修改了 CodeAction.java 内容,提交到本地仓库后再上传到远程仓库。
上传时出现错误警告,提示了推送前需要合并远程更改,这里笔者选择了第三个选项
在接下来的弹窗中,直接关闭,然后去查看冲突的部分
可以发现冲突的地方,文件名直接变成了红色,并且和之前3.4.6 部分一样会有 <<<
现在将 CodeAction.java的内容改成想要的结果 然后重新提交到本地仓库,然后在提交到远程仓库
提交时出现冲突,点击[解决]
在冲突窗口中点击合并
点击应用
最后在push推送到远程仓库,解决完毕。
综上,协作开发的冲突原因主要就是多个程序员在开发时如果是操作同一个文件,存在程序员没有从远程仓库里,拉取之前最近其他人提交的版本,所以在上传时候就会提示文件内容冲突,此时得修改为想要的结果,进行了合并的操作,最后再上传到远程仓库。
第一张图的快捷入口可满足基本的开发需求(图片来自视频资料)
当前开发环境如下,项目团队的每个人都对某个项目开发了一段时间,接下来要切换成团队开发模式。
团队有组长和若干组员组成(组长就是开发中的项目经理)。注:所有操作都在IDEA中完成。(以下图片来自视频资料)
练习场景如下:
组员A和组员B修改了同一个文件的同一行,提交到本地没问题,但是推送到远程仓库时,后一个推送操作就失败了。
解决方法:需要先获取远程仓库的代码到本地仓库,编辑冲突,提交并推送代码。
File ->Settings
设置之后可以直接在IDEA项目中使用Git命令,和Git Bash里的操作一样,十分方便
核心思想:
课前:
课上:(老师和学生操作完全一样,模仿老师即可)
执行 fetch
操作,可使用IDEA可视化操作,也可使用命令操作
创建一个本次课的开发分支
格式:dev/xx
从上一次课的实现代码上创建本次课的代码,例如
book/00
创建一个开发分支 dev/01
book/00
是们项目的初始代码分支book/01
创建一个开发分支dev/02
book/09
创建一个开发分支 dev/10
通过本次的学习,对Git分布式版本控制进行了熟悉,学习起因是之前笔者的一个课设,笔者想将课设项目上传到Gitee,但结果提示每次只能上传20个文件,后来又了解到Git命令可以直接push所有文件到仓库,于是就决定好好学一下Git的相关知识。
花时间学习过后发现,Git的功能十分强大,怪不得 GitHub 在互联网领域如此重要。
Git Bash的操作十分简单,只要花时间去尝试,理解仓库、暂存区、工作区这几个概念。
另外,IDEA 集成 Git后真的十分方便,当出现冲突时可以直接看到同一个文件的哪一部分不相同,然后可以选择想要的结果。
在以后的学习当中,笔者会好好应用Git进行开发,因为它不仅方便开源,而且还适合版本更新。