Git

291 阅读8分钟

一、集中式 vs 分布式

1、集中式

image.png 先说集中式版本控制系统,版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。

image.png 集中式版本控制系统最大的毛病就是必须联网才能工作,如果在局域网内还好,带宽够大,速度够快,可如果在互联网上,遇到网速慢的话,可能提交一个10M的文件就需要5分钟,这还不得把人给憋死啊。

2、分布式

image.png 首先,分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上。既然每个人电脑上都有一个完整的版本库,那多个人如何协作呢?比方说你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。

和集中式版本控制系统相比,分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。而集中式版本控制系统的中央服务器要是出了问题,所有人都没法干活了。

在实际使用分布式版本控制系统的时候,其实很少在两人之间的电脑上推送版本库的修改,因为可能你们俩不在一个局域网内,两台电脑互相访问不了,也可能今天你的同事病了,他的电脑压根没有开机。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。

3、vs

image.png

二、本地的操作

1、创建版本库

找一个文件夹,执行 git init

image.png

创建完成后,可以在文件夹里面看到一个.git文件,这个目录是Git来跟踪管理版本库的,
没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。

image.png

2、工作区、版本库(暂存区、历史区)

(1)工作区

工作区(Working Directory)
就是你在电脑里能看到的目录,比如我的learngit文件夹就是一个工作区:

(2)版本库

工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。
Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,
还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。

image.png

3、本地正向流程

(1)工作区=>暂存区

创建了一个1.txt文件,git status用于查看当前文件在哪个区,
红色代表工作区,绿色代表暂存区

image.png

目前文件处在工作区,现在用git add XXX 提交到暂存区域 git add .表示提交所有的工作区文件

image.png

(2)暂存区=>历史区

目前文件处于暂存区,使用git commit命令给文件提交到了历史区,此时执行git status发现什么也没有了

image.png

git log 可以查看所有commit的记录,目前只有一个

image.png

至此,本地的正向流程结束

4、本地的逆向流程(回滚代码)

(1)回滚工作区代码

  git checkout -- filename //放弃单个文件在工作区的修改
  git checkout . //放弃所有文件在工作区的修改

  我们在1.txt文件里面加一刚222

image.png

  此时git status查看状态,此时1个文件被修改了 

image.png

  我们可以执行命令放弃工作区的修改
  

image.png

  此时文件代码为

image.png

(2)回滚暂存区代码

现在我们修改了1.txt文件,在底下新增加了一行,提交到了暂存区域

image.png

此时我们想回到上一个暂存区,目的是把上一个暂存区的代码弄到工作区
此时我们执行git reset HEAD 1.txt就可以回滚到上一个暂存区
然后再执行git checkout -- 1.txt就可以把上一个暂存区的内容同步到了工作区

image.png

(3)回滚历史区代码

首先我们用git log 查看一下当前的commit信息,现在只有一个commit

image.png

我们再次创建一个2.txt文件,并且把这个文件commit

image.png

git log 查看一下所有的提交,此时有两个commit

image.png

 此时我们想回到第一个commit,这个时候,我们可以git reset --hard XXX来回到某个commit,
 前提是我们还没有push到远程,否则不要用这个命令,因为即使我们改了,直接push到远程也会push不上去,
 因为当前的commit版本低于远程的;除非强制push,但是会把别人的代码弄没,
 不要这样操作,这里记住,只是在没有push到远程之前这样做即可   

image.png

 此时git log 看下,只剩下了一个commit

image.png

如果想看完整的log 可以执行git reflog

image.png

 到此,我们本地的这些逆向操作完成

5、删除工作区提交到暂存区的文件

我们执行命令git rm --cached 1.txt 能够把我们暂存区的某个文件删除,又让其回到了工作区

image.png

当我们工作区域把这个文件改了,此时执行命令是会删除失败的

image.png

 这个时候需要-f强制删除
 

image.png

三、远程

1、添加生成ssh公钥

gitee.com/help/articl…

2、添加远程仓库

本地建了一个版本库

image.png

添加一个文件,提交到历史区

image.png

git remote add origin git@gitee.com:jlin7/git_test.git  与远程的空仓库建立了关联。

image.png

git remote -v 查看当前远程的仓库信息

image.png

关联后,使用命令git push -u origin master第一次推送master分支的所有内容;

image.png

此后,每次本地提交后,只要有必要,就可以使用命令git push origin master推送最新修改;

image.png

解除与git的关联:如果添加的时候地址写错了,或者就是想删除远程库,可以用git remote rm <name>命令。使用前,建议先用git remote -v查看远程库信息:

image.png

3、从远程仓库克隆

要克隆一个仓库,首先必须知道仓库的地址,然后使用git clone命令克隆

使用ssh方式

image.png

使用https方式,这种方式有时候会提示让输入用户名和密码

image.png

四、分支管理

1、理解分支的创建与合并

我们每次提交都是由每一个commit构成,穿成了一条线,主线为master分支,
HEAD指针指向的是master指针,master指针指向提交

image.png

每次提交,master会向前移动一步,越来越长,当我们创建新的分支,例如dev时,
Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,
就表示当前分支在dev上:

image.png

从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,
dev指针往前移动一步,而master指针不变:

image.png

假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?
最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:

image.png

所以Git合并分支也很快!就改改指针,工作区内容也不变!

合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,
删掉后,我们就剩下了一条master分支:

image.png

2、实战分支

首先,我们创建dev分支,然后切换到dev分支:git checkout -b dev
git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:

$ git branch dev
$ git checkout dev
然后,用git branch命令查看当前分支:
git branch命令会列出所有分支,当前分支前面会标一个*号

image.png

我们在当前的dev分支上面修改1.txt文件,加了一行文字,然后提交,再切换回master分支,
会发现我们的修改没有了,因为那个提交是在dev分支上,而master分支此刻的提交点并没有变

image.png

image.png

现在,我们把dev分支的工作成果合并到master分支上:
git merge命令用于合并指定分支到当前分支

image.png

合并完成后,就可以放心地删除dev分支了:

$ git branch -d dev

image.png

小结
Git鼓励大量使用分支:

查看分支:git branch

创建分支:git branch <name>

切换分支:git checkout <name>或者git switch <name>

创建+切换分支:git checkout -b <name>或者git switch -c <name>

合并某分支到当前分支:git merge <name>

删除分支:git branch -d <name>

3、解决冲突

我们现在新创建了一个dev分支,并且在这个分支上修改了1.txt文件

image.png

我们再次切换到master分支上面,也在1.txt文件上修改内容,并且两次的修改不同

image.png

merge dev 分支的内容,现在提示我们1.txt文件存在冲突

image.png

这个时候,我们手动的去解决这个冲突,然后提交

image.png

此时我们可以查看commit记录,多了一个commit

image.png

此时分支情况如下所示

image.png

用带参数的git log也可以看到分支的合并情况:
git log --graph --pretty=oneline --abbrev-commit

image.png

最后删除分支dev

image.png

小结
当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。

解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。

用git log --graph命令可以看到分支合并图。

4、分支管理策略

通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。

如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。

下面我们实战一下--no-ff方式的git merge:

我们新创建一个dev分支,然后增加一个3.txt文件

image.png

切换回master分支,merge dev分支

image.png

git log 查看下

image.png

可以看到,不使用Fast forward模式,merge后就像这样:

image.png

如果是Fast forward模式是下面这样的,我们创建另一个分支dev2试一下,添加了一个4.txt文件,提交

image.png

git merge的时候默认是Fast forward模式,这个时候merge的时候不会产生新的commit,不会保留之前的分支记录

image.png 小结 Git分支十分强大,在团队开发中应该充分应用。

合并分支时,加上--no-ff参数就可以用普通模式合并,合并后的历史有分支,
能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。

5、暂存分支

在gdd_user分支上改动了一些东西,增加了一个文件,修改了两个文件,
这个时候我要去修复一个bug,这个时候我还不想提交产生无用的commit,
所以我这个时候需要的是暂存这些内容

git stash // 可以暂存改动的文件
git stash -u // 可以把新增加的文件也暂存起来
git stash save -u '写注释'//一般用这个完整的命令

image.png

我们修复完了bug,这个时候回到gdd_user分支,再把暂存的文件恢复
执行git stash pop //恢复的同时删除这个stash

image.png

这个时候我们的这些改动就都回来了

image.png

具体的还有一些细节命令可以看这篇文档
https://blog.csdn.net/lamp_yang_3533/article/details/80370380

6、cherry-pick复制提交

对于多分支的代码库,将代码从一个分支转移到另一个分支是常见需求。

这时分两种情况。一种情况是,你需要另一个分支的所有代码变动,
那么就采用合并(git merge)。另一种情况是,你只需要部分代码变动(某几个提交),
这时可以采用 Cherry pick。

image.png

我们创建一个分支cherry-pick,提交了两次

image.png

前两次是最新的提交

image.png

image.png 这个时候我们切换回master分支,想把cherry-pick的最后一次提交复制过来,就可以这样做 image.png

此时我们git log一下,多了一个commit,这个一般用于复制某个分支的代码

image.png

转移多个提交

$ git cherry-pick <HashA> <HashB>

image.png image.png

image.png image.png

image.png image.png

具体可看文档:http://www.ruanyifeng.com/blog/2020/04/git-cherry-pick.html

image.png

7、删除分支

如果一个分支还没有被合并过,那么我们删除是不成功的,此时我们需要-D强制删除

image.png

8、从远端检出分支

从远端检出分支 git checkout -b branch-name origin/branch-name

image.png

小结

image.png

五、总结

至此所有的git常用的就这些了,还有一个就是rebase我没学,平时感觉用不到;等什么时候用到再看;之后有什么还会在这个文档上面修改;

参考文档: 1、廖雪峰 :www.liaoxuefeng.com/wiki/896043… 2、阮一峰:www.ruanyifeng.com/blog/2020/0…