Git学习笔记
[TOC]
根据廖雪峰博客《Git教程》整理。
1 什么是Git
相比“集中式”:中央服务器,联网
分布式不需要中央的服务器,每个人都有一套完整的版本库。
功能很强大,简单易用。
2 安装Git
3 创建版本库
3.1 什么是版本库
又名仓库,英文是repository,就是一个文件夹。而这个文件夹里面的所有东西全部被管理起来。
因此,创建一个版本库,只要创建一个文件夹就好了。
另,建议不要在路径里面出现任何中文,否则可能会出现奇奇怪怪的问题。
举例:
![image-20200816162401990](D:\Document\Typora Images\image-20200816162401990.png)
如图所示,我在桌面下创建了一个GitLearn的文件夹,并且进入这个文件夹,使用git init
命令完成了初始化。
进入gitLearn文件夹,发现多了一个隐藏的文件夹.git,这就是用来管理的。所以没事不要动哦~
![image-20200816162514143](D:\Document\Typora Images\image-20200816162514143.png)
3.2 把文件添加到版本库
写一个readme.txt
![image-20200816163500148](D:\Document\Typora Images\image-20200816163500148.png)
然后告诉Git自己是谁
![image-20200816164022625](D:\Document\Typora Images\image-20200816164022625.png)
然后进行add和commit。
![image-20200816164105269](D:\Document\Typora Images\image-20200816164105269.png)
git commit -m "注释"
尽量要写清楚注释是干什么的。
如图,告诉我1个文件被改动,增加了2行。
第一步是去添加文件,第二步是一次性把所有更改都提交上去。
小结:
第一步git add <filename>
第二步git commit -m "注释"
4 时光机穿梭
修改了一下这个文件:
![image-20200816164707559](D:\Document\Typora Images\image-20200816164707559.png)
并且使用git status
查看当前状态。
![image-20200816164741615](D:\Document\Typora Images\image-20200816164741615.png)
告诉我有个文件被修改了但是还没提交。
我们用git diff
查看是哪里被修改了。
![image-20200816164903554](D:\Document\Typora Images\image-20200816164903554.png)
然后进行提交:
![image-20200816165003666](D:\Document\Typora Images\image-20200816165003666.png)
4.1 版本回退
再次改动,追加了一个hohoho。
![image-20200816165538757](D:\Document\Typora Images\image-20200816165538757.png)
每当你觉得文件修改到一定程度的时候,就可以“保存一个快照”,这个快照在Git中被称为commit
。一旦你把文件改乱了,或者误删了文件,还可以从最近的一个commit
恢复,然后继续工作,而不是把几个月的工作成果全部丢失。
版本控制系统肯定有某个命令可以告诉我们历史记录,在Git中,我们用git log
命令查看:
![image-20200816165723675](D:\Document\Typora Images\image-20200816165723675.png)
精简:git log --pretty=oneline
![image-20200816165835643](D:\Document\Typora Images\image-20200816165835643.png)
每提交一个新版本,实际上Git就会把它们自动串成一条时间线。如果使用可视化工具查看Git历史,就可以更清楚地看到提交历史的时间线:
![image-20200816170015605](D:\Document\Typora Images\image-20200816170015605.png)
如上图,可以用可视化工具看清楚时间线。
现在我们把他恢复到第二个版本。
在Git中,用HEAD
表示当前版本,也就是最新的提交f74bcd...
(注意我的提交ID和你的肯定不一样),上一个版本就是HEAD^
,上上一个版本就是HEAD^^
,当然往上100个版本写100个^
比较容易数不过来,所以写成HEAD~100
。
现在,我们要把当前版本append hohoho
回退到上一个版本add some !
,就可以使用git reset
命令:
![image-20200816170559622](D:\Document\Typora Images\image-20200816170559622.png)
打开这个readme.txt
,发现已经变成了第二个版本!
![image-20200816170649145](D:\Document\Typora Images\image-20200816170649145.png)
我们再git log
一下:
![image-20200816170731149](D:\Document\Typora Images\image-20200816170731149.png)
没有第三个版本了!不过没关系,想要恢复,我们用哪个一长串ID即可。
![image-20200816170901607](D:\Document\Typora Images\image-20200816170901607.png)
如图,恢复成功。再看看readme.txt的内容:
![image-20200816170940232](D:\Document\Typora Images\image-20200816170940232.png)
背后的原理:有一个head指针,仅仅移动head指针,用head指针表示当前版本。
如果找不到这个ID了怎么办?有一个记录了所有命令的文件:
git reflog
![image-20200816171128278](D:\Document\Typora Images\image-20200816171128278.png)
这样又可以找到了。
4.2 工作区和暂存区
- 工作区:电脑里能看到的目录 比如gitLearn
- 版本库 Repository:
.git
Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master
,以及指向master
的一个指针叫HEAD
。
第一步是用git add
把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用git commit
提交更改,实际上就是把暂存区的所有内容提交到当前分支。
因为我们创建Git版本库时,Git自动为我们创建了唯一一个master
分支,所以,现在,git commit
就是往master
分支上提交更改。
(图片来自廖雪峰的Git教程)
现在加一行:
![image-20200816173439892](D:\Document\Typora Images\image-20200816173439892.png)
再创建一个LICENSE文件:
![image-20200816173530009](D:\Document\Typora Images\image-20200816173530009.png)
现在的状态:
![image-20200816173555093](D:\Document\Typora Images\image-20200816173555093.png)
都add,然后这两个文件都在暂存区stage了。最后commit:
![image-20200816173753435](D:\Document\Typora Images\image-20200816173753435.png)
此时暂存区的内容提交到了master,stage被清空了。
4.3 管理修改
Git管理的是修改,而不是文件。
![image-20200817144218041](D:\Document\Typora Images\image-20200817144218041.png)
加上一行内容。
提交查看status并再次修改。
![image-20200817144356383](D:\Document\Typora Images\image-20200817144356383.png)
直接commit。
![image-20200817144446946](D:\Document\Typora Images\image-20200817144446946.png)
查看status:
![image-20200817144604210](D:\Document\Typora Images\image-20200817144604210.png)
这里面告诉我我没有成功提交修改。no changes added to commit
这说明,必须add提交到暂存区,再commit把暂存区的内容提交到仓库里面。
使用git diff HEAD -- readme.txt
查看区别。
![image-20200817144758399](D:\Document\Typora Images\image-20200817144758399.png)
4.4 撤销修改
当你修改的内容是错误的,如何恢复?
如果不小心加了一行胡话:
![image-20200817145324887](D:\Document\Typora Images\image-20200817145324887.png)
4.4.1 还没add
手动删除最后一行。
也可以用命令:
![image-20200817145554431](D:\Document\Typora Images\image-20200817145554431.png)
git checkout -- readme.txt
git restore readme.txt
4.4.2 add了
![image-20200817145735402](D:\Document\Typora Images\image-20200817145735402.png)
然后git status一下:
![image-20200817145836287](D:\Document\Typora Images\image-20200817145836287.png)
1
| git restore --staged .\readme.txt
|
用此命令即可。
此时git status
发现暂存区没有被修改,但是本地还是有修改。于是用之前的git restore readme.txt
即可成功复原。
4.4.3 commit了
使用版本回退。当然,前提是还没有push到远程库,否则就真的惨了。
4.5 删除文件
创建了一个新的文件stupidBoss.txt
,然后对其进行提交。
![image-20200817151335210](D:\Document\Typora Images\image-20200817151335210.png)
现在我发现这个文件不能提交,需要删除。
直接在本地删除:
![image-20200817151418165](D:\Document\Typora Images\image-20200817151418165.png)
然后git status
:
![image-20200817151436652](D:\Document\Typora Images\image-20200817151436652.png)
现在有两种情况:第一,真的要从版本库里也删掉。第二,删错了,老板就是stupid。
如果也要从版本库删掉,那么先git rm stupidBoss.txt
,然后再git commit
就行了。
![image-20200817151711277](D:\Document\Typora Images\image-20200817151711277.png)
如果删错了,可以从版本库里面恢复:
git checkout -- stupidBoss.txt
![image-20200817151955196](D:\Document\Typora Images\image-20200817151955196.png)
git checkout
其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。
5 远程仓库
使用GitHub来玩玩。
第1步:创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa
和id_rsa.pub
这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:
1
| $ ssh-keygen -t rsa -C "youremail@example.com"
|
你需要把邮件地址换成你自己的邮件地址,然后一路回车,使用默认值即可,由于这个Key也不是用于军事目的,所以也无需设置密码。
如果一切顺利的话,可以在用户主目录里找到.ssh
目录,里面有id_rsa
和id_rsa.pub
两个文件,这两个就是SSH Key的秘钥对,id_rsa
是私钥,不能泄露出去,id_rsa.pub
是公钥,可以放心地告诉任何人。
第2步:登陆GitHub,打开“Account settings”,“SSH Keys”页面:
然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub
文件的内容:
![image-20200817153320210](D:\Document\Typora Images\image-20200817153320210.png)
然后在GitHub上创建一个SSH key。
![image-20200817153427047](D:\Document\Typora Images\image-20200817153427047.png)
5.1 添加远程仓库
先在GitHub上创建一个仓库。
![image-20200817153648493](D:\Document\Typora Images\image-20200817153648493.png)
在本地进行关联:
![image-20200817153847240](D:\Document\Typora Images\image-20200817153847240.png)
然后push到远程:
![image-20200817153955271](D:\Document\Typora Images\image-20200817153955271.png)
哇!push成功啦!
![image-20200817154012876](D:\Document\Typora Images\image-20200817154012876.png)
从现在起,只要本地作了提交,就可以通过命令:
1
| $ git push origin master
|
把本地master
分支的最新修改推送至GitHub,现在,你就拥有了真正的分布式版本库!
5.2 从远程库克隆
先创建一个带README.md的远程仓库。
![image-20200817154422677](D:\Document\Typora Images\image-20200817154422677.png)
然后克隆到本地。
1
| $ git clone git@github.com:michaelliao/gitskills.git
|
![image-20200817154553939](D:\Document\Typora Images\image-20200817154553939.png)
下面进入gitskills文件夹:
![image-20200817154648913](D:\Document\Typora Images\image-20200817154648913.png)
可以使用https,ssh等协议,但ssh最快。
6 分支管理
如果自己想要开发别的新功能,但是不影响别人的使用,那么自己先在自己的分支里开发,到最后再合并即可。
6.1 创建与合并分支
首先,我们创建dev
分支,然后切换到dev
分支:
1 2
| $ git checkout -b dev Switched to a new branch 'dev'
|
git checkout
命令加上-b
参数表示创建并切换,相当于以下两条命令:
1 2 3
| $ git branch dev $ git checkout dev Switched to branch 'dev'
|
然后,用git branch
命令查看当前分支:
1 2 3
| $ git branch * dev master
|
git branch
命令会列出所有分支,当前分支前面会标一个*
号。
然后,我们就可以在dev
分支上正常提交,比如对readme.txt
做个修改,加上一行:
1
| Creating a new branch is quick.
|
然后提交:
1 2 3 4
| $ git add readme.txt $ git commit -m "branch test" [dev b17d20e] branch test 1 file changed, 1 insertion(+)
|
现在,dev
分支的工作完成,我们就可以切换回master
分支:
1 2
| $ git checkout master Switched to branch 'master'
|
切换回master
分支后,再查看一个readme.txt
文件,刚才添加的内容不见了!因为那个提交是在dev
分支上,而master
分支此刻的提交点并没有变:
现在,我们把dev
分支的工作成果合并到master
分支上:
1 2 3 4 5
| $ git merge dev Updating d46f35e..b17d20e Fast-forward readme.txt | 1 + 1 file changed, 1 insertion(+)
|
git merge
命令用于合并指定分支到当前分支。合并后,再查看readme.txt
的内容,就可以看到,和dev
分支的最新提交是完全一样的。
注意到上面的Fast-forward
信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master
指向dev
的当前提交,所以合并速度非常快。
当然,也不是每次合并都能Fast-forward
,我们后面会讲其他方式的合并。
合并完成后,就可以放心地删除dev
分支了:
1 2
| $ git branch -d dev Deleted branch dev (was b17d20e).
|
删除后,查看branch
,就只剩下master
分支了:
因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master
分支上工作效果是一样的,但过程更安全。
switch
我们注意到切换分支使用git checkout <branch>
,而前面讲过的撤销修改则是git checkout -- <file>
,同一个命令,有两种作用,确实有点令人迷惑。
实际上,切换分支这个动作,用switch
更科学。因此,最新版本的Git提供了新的git switch
命令来切换分支:
创建并切换到新的dev
分支,可以使用:
直接切换到已有的master
分支,可以使用:
使用新的git switch
命令,比git checkout
要更容易理解。
分支操作小结
查看分支: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>
6.2 解决冲突
![image-20200817194958999](D:\Document\Typora Images\image-20200817194958999.png)
![image-20200817194757912](D:\Document\Typora Images\image-20200817194757912.png)
(VSCode可以直接识别出来)
![image-20200817195035590](D:\Document\Typora Images\image-20200817195035590.png)
当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。
解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。
用git log --graph
命令可以看到分支合并图。