Git
1、Git是什么?
Git 是分布式版本控制系统,是一款源代码管理工具
集中式和分布式
SVN是集中式的版本控制系统,而Git是分布式版本控制系统
集中式
版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。
缺点: 必须联网才能工作,如果在局域网内还好,带宽够大,速度够快,可如果在互联网上,遇到网速慢的话,可能提交一个10M的文件就需要5分钟,这还不得把人给憋死啊。
分布式
分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上。既然每个人电脑上都有一个完整的版本库,那多个人如何协作呢?比方说你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
2、Git的核心概念
工作区、暂存区、版本库、远程仓库
workspace(工作区): 工作区,就是你平时存放项目代码的地方
*Index/Stage(暂存区): *用于临时存放你的改动,事实上它只是一个文件,保存即将提交到文件列表信息
Repository(仓库区/版本库): 就是安全存放数据的位置,这里面有你提交到所有版本的数据。其中HEAD指向最新放入仓库的版本
Remote(远程仓库):托管代码的服务器,例如github
分支
3、Git使用
安装完git之后,需要进行设置
1 | $ git config --global user.name "Your Name" //github上注册的用户名 |
注意:git config
命令的--global
参数,用了这个参数,表示你这台机器上所有的Git仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和Email地址.
1、创建版本库
版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
1 | <!-- |
可以发现当前目录下多了一个.git
的目录,这个目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。
2、添加文件到版本库中
- 编写一个 readme.txt ,内容如下
1 | Git is a version control system. |
注意:一定要放到learngit
目录下(子目录也行),因为这是一个Git仓库,放到其他地方Git再厉害也找不到这个文件。
- 用命令
git add
告诉Git,把文件添加到仓库:
1 | $ git add readme.txt |
没有任何显示,说明添加成功。
- 用命令
git commit
告诉Git,把文件提交到仓库:
1 | git commit -m "wrote a readme file" |
git commit
命令,-m
后面输入的是本次提交的说明,可以输入任意内容,当然最好是有意义的,这样你就能从历史记录里方便地找到改动记录。
git commit
命令执行成功后会告诉你:
1 file changed
:1个文件被改动(我们新添加的readme.txt文件);2 insertions
:插入了两行内容(readme.txt有两行内容)。
为什么Git添加文件需要add
,commit
一共两步呢?
因为
commit
可以一次提交很多文件,所以你可以多次add
不同的文件,比如:
1 | $ git add file1.txt |
3、修改文件
继续修改readme.txt文件
1 | Git is a distributed version control system. |
git status
运行git status
命令看看结果:
git status
命令可以让我们时刻掌握仓库当前的状态,上面的命令输出告诉我们,readme.txt
被修改过了,但还没有准备提交的修改。
git diff
查看具体修改了什么内容,需要用git diff
这个命令看看:
知道了对readme.txt作了什么修改后,再把它提交到仓库就放心多了,提交修改和提交新文件是一样的两步:
第一步git add
1 | git add readme.txt |
在执行第二步git commit
之前,我们再运行git status
看看当前仓库的状态:
1 | git status |
第二步git commit
提交后,我们再用git status
命令看看仓库的当前状态:
Git告诉我们当前没有需要提交的修改,而且,工作目录是干净(working tree clean)的。
4、版本回退
再继续修改readme.txt文件
1 | Git is a distributed version control system. |
然后尝试git add
和git commit
现在有以下版本:
版本1:wrote a readme file
1 | Git is a version control system. |
版本2:add distributed
1 | Git is a distributed version control system. |
版本3:append GPL
1 | Git is a distributed version control system. |
git log
我们用git log
命令查看历史版本
git log
命令显示从最近到最远的提交日志,我们可以看到3次提交,最近的一次是append GPL
,上一次是add distributed
,最早的一次是wrote a readme file
。
如果嫌输出信息太多,可以试试加上--pretty=oneline
参数:
1094adb...
的是commit id
(版本号)是SHA1计算出来的一个非常大的数字,用十六进制表示。
怎么回退到上一个版本呢?
首先, Git必须知道当前版本是哪个版本, 在Git中,用
HEAD
表示当前版本, 上一个版本就是HEAD^
,上上一个版本就是HEAD^^
,当然往上100个版本写100个^
比较容易数不过来,所以写成HEAD~100
我们要把当前版本append GPL
回退到上一个版本add distributed
,就可以使用git reset
命令:
1 | $ git reset --hard HEAD^ |
看看readme.txt的内容是不是版本add distributed
:
我们用git log
再看看现在版本库的状态:最新的那个版本append GPL
已经看不到了!
想再回去已经回不去了,肿么办?
找到那个
append GPL
的commit id
是1094adb...
,于是就可以指定回到未来的某个版本:
1 | $ git reset --hard 1094a |
版本号没必要写全,前几位就可以了,Git会自动去找
再小心翼翼地看看readme.txt的内容:发现又回来了
HEAD
Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD
指针,当你回退版本的时候,Git仅仅是把HEAD
从指向append GPL
:
1 | ┌────┐ |
改为指向add distributed
:
1 | ┌────┐ |
git reflog
Git提供了一个命令git reflog
用来记录你的每一次命令:
5、工作区和暂存区
工作区(Working Directory)
下面的gitLearning
文件夹目录就是工作区
版本库(Repository)
工作区有一个隐藏目录.git
,这个不算工作区,而是Git的版本库。
Git的版本库里存了很多东西,其中最重要的就是称为stage
(或者叫index
)的暂存区,还有Git为我们自动创建的第一个分支master
,以及指向master
的一个指针叫HEAD
。
往版本库添加文件步骤
把文件往Git版本库里添加的时候,是分两步执行的:
第一步是用
git add
把文件添加进去,实际上就是把文件修改添加到暂存区;第二步是用
git commit
提交更改,实际上就是把暂存区的所有内容提交到当前分支。因为我们创建Git版本库时,Git自动为我们创建了唯一一个
master
分支,所以,现在,git commit
就是往master
分支上提交更改。你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
6、撤销修改
git checkout
1 | $ git checkout -- readme.txt |
git checkout -- file
可以丢弃工作区的修改:
命令
git checkout -- readme.txt
意思就是,把readme.txt
文件在工作区的修改全部撤销,这里有两种情况:
一种是
readme.txt
自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;一种是
readme.txt
已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。总之,就是让这个文件回到最近一次
git commit
或者git add
时的状态。
git reset
如果已经git add
到暂存区了,如何撤销呢?
命令git reset HEAD <file>
可以把暂存区的修改撤销掉(unstage),重新放回工作区。
git reset
命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD
时,表示最新的版本。
场景总结
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令
git checkout -- file
。场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令
git reset HEAD <file>
,就回到了场景1,第二步按场景1操作。场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库
7、删除文件
一般情况下,你通常直接在文件管理器中把没用的文件删了,或者用rm
命令删了
1 | $ rm test.txt |
这个时候,Git知道你删除了文件,因此,工作区和版本库就不一致了,git status
命令会立刻告诉你哪些文件被删除了:
现在只是删除了工作区文件,下面会有两种情况
一是确实要从版本库中删除该文件,那就用命令
git rm
删掉,并且git commit
:二种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本
1 $ git checkout -- test.txt
git checkout
其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。
4、远程仓库
常用的远程仓库就是Github
由于你的本地Git仓库和GitHub仓库之间的传输是通过SSH加密的,所以,需要一点设置:
第1步:创建SSH Key 。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有
id_rsa
和id_rsa.pub
这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:1
$ ssh-keygen -t rsa -C "youremail@example.com"
如果一切顺利的话,可以在用户主目录里找到
.ssh
目录,里面有id_rsa
和id_rsa.pub
两个文件,这两个就是SSH Key的秘钥对,id_rsa
是私钥,不能泄露出去,id_rsa.pub
是公钥,可以放心地告诉任何人.))第二步:SSH密钥设置,登陆GitHub,打开settings-> SSH and GPG keys页面:
然后,点New SSH Key,填上任意Title,在Key文本框里粘贴
id_rsa.pub
文件的内容:为什么GitHub需要SSH Key呢?
因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送
添加远程仓库
- 首先,登陆GitHub,然后,在右上角找到“Create a new repo”按钮,创建一个新的仓库:
- 在Repository name填入
gitLearn
,其他保持默认设置,点击Create repository按钮,就成功地创建了一个新的Git仓库:
目前,在GitHub上的这个
gitLearn
仓库还是空的,GitHub告诉我们,可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到GitHub仓库。 在本地的gitlearn
仓库下运行命令1
$ git remote add origin git@github.com:michaelliao/learngit.git
添加后,远程库的名字就是
origin
,这是Git默认的叫法,也可以改成别的,但是origin
这个名字一看就知道是远程库.下一步,就可以把本地库的所有内容推送到远程库上:
1
2git branch -M main //对已经存在的分支重命名
git push -u origin main把本地库的内容推送到远程,用
git push
命令,实际上是把当前分支master
推送到远程。由于远程库是空的,我们第一次推送
master
分支时,加上了-u
参数,Git不但会把本地的master
分支内容推送的远程新的master
分支,还会把本地的master
分支和远程的master
分支关联起来,在以后的推送或者拉取时就可以简化命令。推送成功后,可以立刻在GitHub页面中看到远程库的内容已经和本地一模一样:从现在起,只要本地作了提交,就可以通过命令:
1
$ git push origin master
总结
关联一个远程库,使用命令
git remote add origin git@server-name:path/repo-name.git
;关联后,使用命令
git push -u origin master
第一次推送master分支的所有内容;此后,每次本地提交后,只要有必要,就可以使用命令
git push origin master
推送最新修改;
从远程库克隆
首先,登陆GitHub,创建一个新的仓库,名字叫
gitskills
:现在,远程库已经准备好了,下一步是用命令
git clone
克隆一个本地库:1
git clone git@github.com:LiuYanFeiYu2020/gitskills.git
注意把Git库的地址换成你自己的,然后进入
gitskills
目录看看,已经有README.md
文件了:
你也许还注意到,GitHub给出的地址不止一个,还可以用https://github.com/michaelliao/gitskills.git
这样的地址。实际上,Git支持多种协议,默认的git://
使用ssh,但也可以使用https
等其他协议。
使用https
除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh
协议而只能用https
。
5、分支管理
每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即
master
分支。HEAD
严格来说不是指向提交,而是指向master
,master
才是指向提交的,所以,HEAD
指向的就是当前分支
- 一开始的时候,
master
分支是一条线,Git用master
指向最新的提交,再用HEAD
指向master
,就能确定当前分支,以及当前分支的提交点:
创建分支命令:
1 | git branch <branch_name> #创建指定名称的分支 |
查看分支命令:
1 | git branch #查看所有分支,* 号代表当前工作分支 |
示例:
切换分支命令:
1 | git checkout <branch_name> #切换到指定分支 |
示例:切换到dev分支,然后添加dev.txt文件并进行提交
示例:在dev分支上创建并切换到test分支
删除分支命令:
1 | #删除一个干净的分支(即相对当前分支而言该分支没有新的提交记录) |
注意:删除分支前都需要先切换到其他分支才能进行删除操作
示例:在dev分支上删除test分支,test分支相对于dev来说是干净的分支,所以可以直接删除,然后切换到master分支,删除dev分支,此时需要进行强制删除。
恢复分支命令:
思路:对于已经有提交记录的分支删除后,实际上只是删除指针,commit记录还保留,如果想恢复,需要使用git reflog
查找该分支指向的commitId,然后根据commitId创建新的分支
1 | #根据指定commit创建新分支 |
示例:
重命名分支命令:
1 | git branch -m <branch_name> newname |
示例:
合并分支命令:
1 | git merge <branch_name> #将指定分支合并到当前分支 |
6、Git的常用命令流程
- 从远程仓库中克隆 Git 资源作为本地仓库;
- 从本地仓库中checkout代码然后进行代码修改;
- 在提交本地仓库前先将代码提交到暂存区;
- 提交修改,提交到本地仓库;本地仓库中保存修改的各个历史版本;
- 在需要和团队成员共享代码时,可以将修改代码push到远程仓库。
7、Git常用命令
1 | git init # 初始化本地git仓库(创建新仓库) |