您好,我是码农飞哥,感谢您阅读本文,欢迎一键三连哦。
1. Python基础专栏,基础知识一网打尽,9.9元买不了吃亏,买不了上当。 Python从入门到精通
❤️ 2. Python爬虫专栏,系统性的学习爬虫的知识点。9.9元买不了吃亏,买不了上当,持续更新中 。python爬虫入门进阶
❤️ 3. Ceph实战,从原理到实战应有尽有。 Ceph实战
❤️ 4. Java高并发编程入门,打卡学习Java高并发。 Java高并发编程入门
5. 社区逛一逛,周周有福利,周周有惊喜。码农飞哥社区,飞跃计划
全网同名【码农飞哥】欢迎关注,个人VX: wei158556
Git是一款开源的分布式版本控制系统,可以有效,高速处理从很小到非常大的项目版本管理。 Git是通过C语言开发实现的。
Git和SVN是两种截然不同的版本控制系统,Git是分布式版本控制系统,而SVN则是集中式版本控制系统。要想比较Git和SVN的区别,首先需要了解分布式版本控制系统和集中式版本控制系统的基本概念。
集中式版本控制系统:一个显著的特征是版本库是存放在中央服务器上的,由中央服务器统一管理项目的版本信息和分支信息。团队中的每个成员在工作时都需要先从中央服务器上拉取最新的代码,然后开始干活。干完活之后再将代码提交到中央服务器上。集中式版本服务器有两个弊端:
集中式版本控制系统的网络拓扑图如下图所示:
可以看出团队中所有成员的工作电脑都只与中央服务器打交道。如果把版本库比做书库的话,那么每个人(每个电脑)都需要先从书库借到书(拉取最新的代码),阅读完之后然后还给书库(修改之后提交到中央服务器)
分布式版本控制系统: 与集中式版本控制系统最大的不同是团队中所有成员的工作电脑上都有一个完整的版本库,并且没有中央服务器。,这就相当于团队中每个成员都有一个自己的小书库(版本库),成员之间可以互相交换自己书库中的图书(将自己的修改提交给对方)。这里完全不需要中央服务器来管理协调管理。
在实际使用分布式版本控制系统时,其实很少在两人之间的电脑上进行版本库推送,这是因为有时候你们不在同一个局域网内,或者你同事的电脑关机了。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。这台充当“中央服务器”的电脑上的版本库称之为远程版本库,其他成员电脑上的版本库称之为本地版本库。后面会详细介绍。
分布式版本控制系统的网络拓扑图如下图所示:
分布式版本控制系统剔除了中央服务器,这充分体现了分布式的核心概念,就是去中心化。这样带来的好处有两点:
系统 | 版本 |
---|---|
Windows | Windows10 |
Linux | Ubuntu16.04 |
说完了Git的基本概念,接下来还是安装个Git客户端下来耍一耍。这里分不同的操作系统简单的介绍一下Git客户端的安装。
首先通过git --version
命令查看电脑上是否已经安装了Git客户端。
如果已经安装了就可以跳过此章节。如果没有安装的话就接着往下面看:
Linux系统有不同的发行版本,可以通过cat /proc/version
命令查看Linux的版本。
sudo apt-get install git
yum install git -y
如果找不到yum命令的话,则需要先安装yum工具。可以参考下面命令
#删除yum.repos.d目录下所有文件
rm -f /etc/yum.repos.d/*
#然后重新下载阿里的yum源
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
#清理缓存
yun clean all
Git的官方下载地址是:Git的下载地址
下载好安装包之后,一直点击下一步即可安装。再次就不在赘述。
Windows下安装好Git之后会出现Git Bash 和Git GUI两个应用程序,其中Git Bash是Git的命令行工具,而Git GUI则是Git的可视化工具(一般很少用)。
创建本地版本库分为两步:
第一步是创建一个空文件夹,命名为: git_learn。
第二步就是在该文件夹下执行git init
命令将该文件夹变成git可以管理的版本库。
执行第二步之后,在 git_learn目录下会出现一个名为.git的隐藏文件夹,该文件夹就是git的版本库。切记不要手动修改.git文件夹下的任何内容,以免本地版本库不可用。
本地版本库建好之后就可以在git_learn文件夹下创建一个文件进行测试了。这里创建了一个名为readme.txt的文件。
添加到暂存区
通过git add readme.txt
命令可以将readme.txt文件提交到暂存区(关于暂存区的概念后面会详细介绍)。如果有多个文件需要添加的话,可以执行git add .
命令。
提交到版本库
因为git的本地都是有完整版本库的,所以还需要将前面创建的readme.txt文件提交到本地版本库的当前分支,默认是master。命令格式是git commit -m '
,其中写入你的提交备注。
这里有两个很重要的概念,一个是工作区,另一个是暂存区(Git特有的概念)。
工作区
工作区就是你电脑上能看到的目录(不包括隐藏文件),例如:git_learn目录就是一个工作区。
暂存区
工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库,其中最重要的是暂存区(stage)。
还有Git为我们自动创建的第一个分支叫master,以及指向master的一个指针叫HEAD。
前面提到了工作区,暂存区,git add
命令和git comit
命令。那么他们之间有啥关系呢?下面就用一张流程图展示一下:
通过add命令将工作区中ABC文件夹提交到暂存区stage,在通过commit命令将stage中的ABC文件夹提交到当前分支master。
Git管理的是修改而非文件。这里的修改指的是对工作区的任何操作,包括新增文件;删除文件;修改文件等等。哪怕是在文件中增加一句话或者删除一个字符都可以算是修改。下面就举例说明下,还是以readme.txt文件为例:
git add readme.txt
,并通过命令git status
查看状态。git tracks changes
。直接执行git commit -m 'git tracks changes'
命令。然后通过 git status
,可以发现第二次的修改没有提交。这是因为第二次的修改没有先提交到暂存区中。
我们的操作过程是第一次修改 -> git add -> 第二次修改 -> git commit
。当使用git add
命令后,在工作区中的第一次修改被放入暂存区中,准备提交,在工作区中的第二次修改没有被放入暂存区中,所以,git commit
只负责把暂存区中的修改提交到当前分支。所以第二次的修改没有提交。
也就是说,所有的修改必须先通过git add 提交到暂存区,然后通过git commit 提交到当前分支。。在实际开发中一般是将所有修改合并起来add,然后在一起commit。
当前分支上有一个已经废弃不用的文件,该如何删除呢?比如要删除一个名为test1.txt文件。只需要两行命令。
git rm test1.txt
git commit -m "remove test.txt"
前面介绍了在实际开发中,一般会拿一台电脑作为“中央仓库”,充当中央仓库的电脑需要安装一个代码仓库软件,这里选用开源软件GitLab,它是基于git实现的在线代码仓库软件,提供web可视化管理界面,可以在本地部署。通常用于企业团队内部协作开发。当然,如果你不想搭建私人的git仓库,那么也可以直接使用最大的同性交友网站Github(使用与GitLab类似)。
那么该如何在Ubuntu上安装GitLab软件,搭建私有的Git仓库呢?
#更新apt源
sudo apt-get update
#安装依赖包,运行命令
sudo apt-get install curl openssh-server ca-certificates postfix
sudo apt-get install -y postfix
curl https://packages.gitlab.com/gpg.key 2> /dev/null | sudo apt-key add - &>/dev/null
sudo vi /etc/apt/sources.list.d/gitlab-ce.list
在该文件中写入如下代码
deb https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/ubuntu xenial main
sudo apt-get update
sudo apt-get install gitlab-ce
安装gitlab-ce成功之后。
5. 修改外部url
在gitlab配置文件/etc/gitlab/gitlab.rb中修改外部url,改为自己的ip地址或者域名。
sudo vi /etc/gitlab/gitlab.rb
找到external_url,修改其默认的地址,这里改成了我本机局域网IP:192.168.40.138
external_url 'http://192.168.40.138/' ## 本机的局域网ip地址为192.168.41.128
sudo gitlab-ctl reconfigure
sudo gitlab-ctl start
可以通过ps -ef|grep gitlab
命令查看GitLab是否启动成功。
8. 进行浏览器访问
GitLab成功启动之后就可以通过浏览器访问GitLab的主页了。在浏览器上输入http://192.168.40.138/
;
默认输入的用户名是root用户,输入的密码是root的账户密码。
至此GitLab的安装就全部结束,我们也成功的搭建了属于自己的Git仓库。
点击设置按钮,进入设置栏,选中Users->New User
进入添加用户页面。
输入姓名,用户名,和邮箱即可注册添加新用户。
用户添加好之后,就是将用户添加到团队中,GitLab中默认会有一个名为GitLab Instance的团队,你也可以添加自己的团队,这里我添加了一个名为ai_edu的团队。并在团队中添加了两个成员。
选中要添加成员的团队,在右侧会出现一个添加Add user(s) to the group的栏目。再此栏目中所有用户并添加到团队中。用户的角色有游客,测试人员,开发人员,管理者,拥有者等几个不同的角色。
说完了用户和团队的设置后,现在就进入了重点了,如何新建一个远程仓库。同样也是比较方便。操作步骤是:Project->Your projects->New project
这里新建了一个名为git_test的远程仓库,仓库的所有这是属于ai_edu团队。
这里仓库的权限等级有三个等级,分别是:Private(只有你团队的人才能拉取和推送代码),Internal(除了黑名单之外的用户可以拉取和推送代码)。Public (所有的用户都可以拉取)。
为啥要配置SSH key呢?这是因为GitLab与你的电脑是通过SSH协议来通信的。说白了,如果你没有配置SSH key的话,则你不能推送代码到远程库。这里首先在你本地生成公钥和私钥文件,然后把公钥文件的内容复制到GitLab上。
git config --global user.name “username”
git config --global user.email [email protected]
[email protected]替换成你实际的邮箱地址。不需要加单引号。
4. 生成公钥和私钥
ssh-keygen -C 'you email [email protected]' -t rsa
如果简单些的话可以直接填写ssh-keygen
命令。邮箱地址填写前面设置的邮箱地址。有提示的话一直按Enter键。正确执行后会输入如下信息
2 找到公钥文件id_rsa.pub,复制公钥内容到GitLab
分支的概念:分支就是每次提交创建的点所连接成的时间线。这条时间线就是一个分支,默认的话只有一个主分支master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交,HEAD指向的就是当前分支。
一开始的时候,master分支就是一条线,Git用master指向最新的提交,再用HEAD指向master,就能够确定当前的分支以及当前分支的提交点。
每次提交,master分支都会向前进移动一步,这样随着你不断提交,master分支的线也会越来越长。其结构如下图所示:
当我们新创建一个分支dev时,Git会创建一个指针dev指向master分支当前的提交点。当切换到dev分支后,HEAD指针会指向dev。也就是说HEAD始终是指向当前分支的。
git checkout -b dev
git checkout 加上-b参数表示创建并切换到dev分支上,相当于下面两条命令。
$ git branch dev
$ git checkout dev
执行该上面的命令之后的git的提交时间线如下图所示:
当在dev分支上提交代码(未改变master分支)之后,dev分支会不断的向后推进。而master指针的指向则不会变。
git checkout
命令是一个比较特殊的命令,传入不同的参数会有截然不同的效果。例如:git checkout -- file
命令,表示的意思是撤销file文件中所有的修改。所以Git还提供了git switch
命令用于创建和切换分支。
## 创建并切换到新的dev分支
git switch -c dev
## 切换到已有的master分支
git switch master
分支创建好之后,可以通过git branch
命令进行查看。
当团队成员在dev分支上开发完毕之后,就可以将dev分支上的内容合并到master分支上,合并分支的原理就是将master指针指向dev的当前提交。Git合并分支只是改了下指针,工作区的内容没有改变。
其合并的命令分两步,第一步是切换到master分支,第二步是合并dev分支
#切换到master分支
git checkout master
#合并dev分支
git merge dev
通过merge合并的话会有两个分支路径,如果觉得这样不好看的话,可以通过rebase来合并
#切换到master分支
git checkout master
#合并dev分支
git rebase origin/dev
这样同样可以将dev分支合并到master分支上。
4. 删除dev分支
现在dev分支的内容也合并到了master分支上了,可以将dev分支删除了。Git删除dev分支其实就是删除dev指针。删除之后又只剩下master分支了。需要注意的是必须要先切换到master分支上再进行删除dev分支的操作。删除dev分支的命令如下:
git branch -d dev
在团队协作过程中,难免会碰到各种修改冲突。那么该如何解决这些冲突呢? 例如:你和你同事分别修改了readme.txt文件,那么当你们同时提交时就会出现冲突。又或者在你在master分支和feature1分支上分别修改了readme.txt文件。那么当你合并feature1分支到master分支时就会出现冲突。举个栗子吧:
处理冲突
。然后提交到feature1分支。冲突处理
master有冲突
然后提交到master分支上。
3. 将feature1分支合并到master分支,此时就会出现合并冲突。如下图所示:
冲突之后,Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容。如下图所示:
处理冲突的方式就是编辑冲突内容。然后重新提交。
$ git add README.md
$ git commit -m "解决冲突"
通常情况下,Git在合并分支时,会使用Fast forward模式。但是,这种模式下,删除分支后,会丢掉分支信息。如下图所示,删除dev分支之后,分支的信息也就就丢失了
如果要强制禁用Fast forward模式,Git会在merge时生成一个新的commit。当删除分支时就不会丢失分支信息。其命令是
git merge --no-ff -m "merge with no-ff" dev
准备合并dev分支,其中--no-ff
参数,表示禁用Fast forward,因为本次合并要创建一个新的commit,所以加上-m
参数。把commit描述写进去。
当你接到一个修复代号为01的bug的任务时,很自然地,你会创建一个分支issue-01来修复它,但是,如果这是你正在dev分支上进行的工作还没有提交,提交吧,可是你在dev上的工作只进行了一般,还没法提交,预计完成还需1天的时间。但是,现在必须要在两个小时内修复代号01的bug。这时候该怎么办呢?你不是期望有一个功能可以隐藏你当前在dev上未提交的工作,然后,切换到issue-01分支修改bug呢。
通过stash功能可以满足你的愿望,将当前工作现场隐藏起来。如下图所示:执行git stash
命令之后,新建的hello.html文件就从工作区中消失了。
git stash
git stash命令可以将当前未提交的工作隐藏起来。让你的工作区变的干净清爽。
git stash list 可以查看当前仓库所有已经保存的工作现场。
git stash list
现在代号为01的bug已经修复好了,你可以继续切换到dev分支上进行开发了。那么这时候你需要做的第一件事就是恢复之前保存的工作现场。恢复工作现场的命令是:
git stash apply
通过git stash apply
命令可以恢复工作现场。但是,恢复之后工作现场还在。那么这时候我们还需要一个命令来删除工作现场。其命令是:
git stash drop
恢复工作现场一条命令,删除工作现场又是一条命令。未免有点繁琐了吧。有没有将两者合二为一的命令呢?答案是有的:通过下面的命令就可以实现:
git stash pop
在master分支上修复了bug后,我们想一想,dev分支是早期从master分支分出来的,所以,这个bug其实在当前dev分支上也存在。那怎么在dev分支上修复同样的bug?重复操作一次,提交不就行了?这种方法也不是不行,如果该BUG涉及的修改过多,这样的方式就显得有点捉襟见肘了。那么我们能不能把修改BUG做的提交复制到当前的dev分支呢?答案是有的:
git cherry-pick 821ea4d
通过git cherry-pick
命令可以将单个的提交复制到当前分支。可以通过 git log 查看提交的提交的版本号。
添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。
前面介绍可以通过git branch -d branchname
命令删除分支。但是,如果被删除的分支还没有合并到主分支的话,用该命令删除的话分支的话,Git会抛出一个错误提示并不能删除该分支。如下:要删除一个名为feature-01的分支。但是该分支还没有被merge。这时候就需要强制删除分支的命令了。
git branch -D feature-01
其中feature-01为待删除的分支名。其实就是将-d
参数换成-D
参数。
前面说了那么多,好像都是一个人在本地操作,没有涉及到多人协作的情况。这在团队开发中肯定是不可能的啦,因为我们是一个team。那么多人协作的情况涉及哪些操作呢?
git remote add origin http://192.168.40.138/ai-edu/git-demo.git
或者,推荐使用下面这种,因为前面配置了SSH公钥和私钥
git remote add origin [email protected]:jayxiang31/python_learn.git
git pull --rebase origin master
前面第三章已经搭好了私有的Git仓库管理器GitLab。同时也创建了一个名为git_test的仓库。现在要做的就是将远程仓库克隆下来。克隆的命令是git clone
git clone http://192.168.40.138/ai-edu/git_test.git
其中http://192.168.40.138/ai-edu/git_test.git
是远程仓库的地址。
当然也可以在IDEA上直接通过图形界面操作,还省去了导入项目的过程。其操作步骤是:
File->New->Project from Version Control->Git
。如下图所示: git remote rm origin
通过git remote
命令可以查看远程仓库,origin表示远程主机。
通过git remote -v
命令可以查看远程仓库详细的信息,包括远程仓库的地址。
$ git remote -v
origin http://192.168.40.138/ai-edu/git_test.git (fetch)
origin http://192.168.40.138/ai-edu/git_test.git (push)
上面显示了可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址。
现在将远程仓库克隆下来了,那么该如何将当前分支上所有的本地提交推送到远程库呢?答案是通过git push
命令,其语法结构是git push
其中
表示远程分支名,
表示本地分支名。
git push origin master
该语句表示将本地的master分支推送到远程的origin分支上。在实际应用中会在git push
命令后面加上-u
参数,就像git push -u origin master
这样。这是因为如果当前分支与多个主机存在追踪关系,则可以使用 -u 参数指定一个默认主机,这样后面就可以不加任何参数使用git push。那么哪些分支该与远程分支保持一致呢?一般认为:
通过git push
命令还能创建远程分支。
git push origin dev
假设你本地已经有了dev分支。通过上面的命令可以将dev分支推送到远程库,并创建远程的dev分支。
通过git pull
命令可以拉取远程仓库的数据和分支信息。假设如下这个场景:你同事在他本地创建了一个dev分支,并提交到了远程库。同时你也在本地创建了一个dev库,当你push时会推送失败。结果如下图所示:
因为你同事的最新提交和你试图推送的的提交有冲突。解决的办法就是根据Git的提示,先用git pull
把最新的提交从origin/dev
抓下来,然后,在本地合并,解决冲突后,在推送。
$ git pull
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.
git pull <remote> <branch>
If you wish to set tracking information for this branch you can do so with:
git branch --set-upstream-to=origin/<branch> dev
git pull
也失败了。原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接:
$ git branch --set-upstream-to=origin/dev dev
Branch 'dev' set up to track remote branch 'dev' from 'origin'.
关联好本地分支和远程分支之后,在pull就能成功了。这回git pull
成功,但是合并有冲突,需要手动解决,解决的方式也是在本地手动处理冲突文件,解决后,提交,在push。
git checkout -b 本地分支名x origin/远程分支名x
该命令会在本地新建分支x,并自动切换到该本地分支x。
采用此种方法建立的本地分支会和远程分支建立映射关系。
例如:
git checkout -b dev origin/dev
通过
git push origin :dev
命令可以删除远程dev分支。但是这时候本地的dev分支还是存在的。所以还需要通过git branch -d dev
删除本地的dev分支。
通过git branch
可以查看本地分支
通过git branch -a
可以查看本地分支和远程分支。
在实际开发中我们经常会碰到这样一个场景,比如:你误提交了一段有问题的代码,导致其他同事更新代码之后项目启动不了,这时候该怎么办呢?我们首先想到的就是将版本回退。回退到之前那个没有问题的版本。
git log
命令找到当前的仓库所有的提交日志。然后,找到你需要回退到的版本。如下图所示:git reset HEAD
git reset commitId
其中commitId是指定版本的版本号,比如这里将版本信息回退到b50c9bdcbf9641d33e4b531bd96dc1f27d4bf602
这个版本。那么命令就是:git reset b50c9bdcbf9641d33e4b531bd96dc1f27d4bf602
回退之后,再次通过git log
查看,则最新的提交日志已经变成了hello 提交
这个版本了。
当然,通过IDEA来回退则更加的简单。直接在Version Control->Log
在待回退到的版本上右键,选中Reset Current Branch to Here
即可。
其实回退操作的本质,就是将HEAD指针的指向要回退的那个版本上。
在实际开发中我们经常需要进行代码Review。如果同一个功能点分了很多次提交话,那么在进行代码Review时则会非常的不方便。这时候就需要将多次提交合并成一次提交。具体的步骤是:
git switch
命令切换到需要合并提交的代码的分支,比如:git switch test
git rebase -i HEAD~3
表示查看最近的三次提交命令,合并几次则需要将对应的数字改成几。git rebase -i HEAD~3
执行该命令之后会打开提交指令的日志文件,这里只保留第一次的提交,将另外的两次提交改成 s
保存之后会进入另外一个文件,该文件无需修改,直接输入:q!
命令退出即可。操作之后我们可以看到之前的三次提交记录变成了一次提交记录。
4. 如何要把这次提交合并到其他分支只需要切换到目标分支,执行如下命令;
git cherry-pick <commitid>
git branch -m oldname newname
标签管理比较简单,再此只是简单描述一下。
#创建标签 v1.0
git tag v1.0
#查看标签
git tag
#删除标签v1.0
git tag -d v0.1
#*****还可以加上-a参数来创建一个带备注的tag,备注信息由-m指定。如果你未传入-m则创建过程系统会自动为你打开编辑器让你填写备注信息。
git tag -a v1.0 -m "这是第一次发版"
#推送标签
git push origin --tags
#删除远程标签
git push origin :refs/tags/v1.0
回滚本地仓库的某次提交,回滚的命令是
git revert <subcommand>
例如:本次提交的commandId 是311737d3
git revert 311737d3
一万六千多字,我写的累,你们看的也累!!!文中奉上几张美女照片给各位读者大大解解乏。我真真正正的肝了两天了。现在终于肝完了。希望对读者朋友们有所帮助。
看文字实在是太累了。下面就用一张图来做一个总结吧。
这张图清晰的表明了Git的基本流程。