Git(分布式版本控制系统)
Git
Git是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。
Git的特点
分布式相比于集中式的最大区别在于开发者可以提交到本地,每个开发者可以通过克隆(git clone)在本地机器上拷贝一个完整的Git仓库。
优点
1.适合分布式开发,强调个体。
2.公共服务器压力和数据量都不会太大。
3.速度快、灵活。
4.任意两个开发者之间可以很容易的解决冲突。
5.离线工作。
缺点
1.学习周期相对而言比较长。
2.代码保密性差,一旦开发者把整个库克隆下来就可以完全公开所有代码和版本信息。
Git的一些操作及相关概念
创建版本库:git init
版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
- 首先,选择一个合适的地方,创建一个空目录(目录名不要包含中文):
例如:
然后在该文件夹里右键单击选择Git Bush Here,在弹窗中输入:
$ mkdir learngit
$ cd learngit
$ pwd
pwd命令用于显示当前目录。我的仓库位于/e/Git/the first repository/learngit
-
第二步,通过git init命令把这个目录变成Git可以管理的仓库:
(这是一个空仓库,当前目录下多了一个.git的目录,这个目录是Git来跟踪管理版本库的,不能乱动。如果没有看到.git目录,那是因为这个目录默认是隐藏的,用ls -ah命令就可以看见。)
把文件添加到版本库
所有的版本控制系统,其实只能跟踪文本文件的改动,比如TXT文件,网页,所有的程序代码等等,Git也不例外。版本控制系统可以告诉你每次的改动,而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片的占用内存大小变了,但到底改了啥,版本控制系统不知道,也没法知道。
(windows系统不要使用自带文本软件,可使用Notepad++代替)
先编写一个readme.text
文件,内容如下:
Git is a version control system.
Git is a free software.
把这个文件放到learngit
目录下(子目录也行),即一定要放到你的Git仓库里面。接下来添加命令使文件添加到仓库里面:
- 第一步,用命令
git add
将文件添加到仓库(可以同时将多个文件添加进仓库):
$ git add readme.text
(没有显示其他东西就说明成功了) - 第二步,用命令
git commit
将文件提交到仓库:
$ git commit -m"wrote a readme file"
-m
后面输入的是本次提交的说明,可以输入任意内容,方便自己能从历史记录里找到自己的改动记录。
git commit
命令执行成功后会有:1 file changed
:1个文件被改动(新添加的readme. text
文件);2 insertions
:插入了两行内容(readme. text
有两行内容)。
修改仓库里的文件
在前面已经添加了readme. text
文件的基础上,我们可以对文件进行修改,改成如下内容:
Git is a distributed version control system.
Git is a free software.
用命令git status
查看结果:
git status
命令可以让我们看到仓库当前的状态,这里显示
readme. text
已经被修改过了,但是这个修改还没有提交。
用命令
git diff
可以查看文件具体修改的内容:
这里显示我们在第一行添加了
distributed
。
接下来就是提交修改的文件,提交修改的文件和之前提交新文件的步骤是一样的:
- 第一步
git add
用命令git status
查看仓库当前状态:
这里显示将要被提交的修改包括了readme. text
- 第二步
git commit
提交后,再用命令git status
查看仓库当前状态:
这里显示没有需要提交的修改,工作目录是干净的。
查看历史记录
用命令git log
可以查看提交日志:
这里可以看到最近的一次是
add distributed
,最早的一次是
wrote a readme file
可以试试加上
--pretty=oneline
参数使显示的更简洁:
(这里的一串数字和字母的组合是
commit id
即版本号,例如
33b2d9c···
就是
wrote a readme file
的版本号)
每提交一个新版本,Git就会把它们自动串成一条时间线。
版本回退
在Git中,用HEAD
表示当前版本,上一个版本是HEAD^
,上上个版本是HEAD^^
。如果版本过多可以用HEAD~number
,例如往上100个版本:HEAD~100
。
可以使用命令git reset
使版本从add distributed
回退到wrote a readme file
:
可以看到版本已经退回到了
wrote a readme file
。
使用命令
cat
可以查看
readme.text
是否真的退回到了上一个版本:
使用命令
git log
再次查看当前版本库的状态:
可以看到版本库中只剩下第一个版本了。
现在可以使用
add distributed
的版本号回到
add distributed
的版本:
这样版本又回到了
add distributed
。
如果不记得版本号而且还把弹窗关了,可以使用命令
git reflog
来查找之前的命令:
这样就找到之前的版本号了。
工作区与暂存区
工作区(Working Directory)
就是能在电脑里面看到的目录,比如这里的learngit
文件夹就是一个工作区
版本库(Repository)
工作区有一个隐藏目录.git
,这个不算工作区,而是Git的版本库。
暂存区(Temporary Area)
Git的版本库里存了很多东西,其中最重要的就是称为stage
(或者叫index
)的暂存区,还有Git自动创建的第一个分支master
,而前面用到的HEAD
命令就是指向master
的指针。
在之前的提交文件到仓库的过程中:用
git add
把文件添加进去,实际上就是把文件修改添加到暂存区;用
git commit
提交更改,实际上就是把暂存区的所有内容提交到当前分支。因为创建Git版本库时,Git自动创建了唯一一个
master
分支,所以现在,
git commit
就是往
master
分支上提交更改。可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
管理修改
Git管理的是修改,而不是文件。
举个例子:
在readme.text
中添加一行:
Git has a mutable index called stage.
然后添加并查看状态:
然后再修改一次
readme.text
的内容:
删除第一行的
distributed
再提交:
查看状态:
可以看到第二次的修改并没有被提交。
提交后,用
git diff HEAD -- readme.text
命令可以查看工作区和版本库里面最新版本的区别:
如果想要第二次修改也被提交,则可以在第二次修改后
git add
,和第一次修改一起
git commit
;或者在第一次修改被提交之后,再将第二次修改
git add
,然后单独将第二次修改
git commit
:
撤销修改
我们可以使用git checkout --
来撤销工作区(还没有git add
)的修改。
命令git checkout -- readme.text
意思就是,把readme.text
文件在工作区的修改全部撤销,这里有两种情况:
- 一种是
readme.text
自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态; - 一种是
readme.text
已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
总之,就是让这个文件回到最近一次git commit
或git add
时的状态。
先在readme.text
里面加一句话:
oh my god!
此时并没有
git add
,我们可以使用命令
git checkout -- readme.text
进行撤销:
如果不小心把这句话已经
git add
到暂存区了(但是还没有
git commit
):
可以使用命令
git reset HEAD
把暂存区的修改重新放回工作区:
然后再用
git checkout -- readme.text
撤销工作区的修改;
如果已经将修改
git commit
到版本库里了,就使用版本回退的方法。(前提是没有推送到远程仓库)
删除文件
我们可以使用命令rm
来删除文件。
首先,先建立一个新的文件new.text
并且提交:
现在使用命令
rm new text
删除文件:
此时只是在工作区中执行了删除
new.text
文件的命令,但是文件依然存在于版本库中,如果想要在版本库中删除
new.text
文件,那就用命令
git rm
删掉,并且
git commit
:
假如是不小心误删了这个文件(还没有从版本库里删除),我们依然可以用命令
git checkout
来还原(即撤销上一步操作)。(从来没有被添加到版本库就被删除的文件,是无法恢复的!)
远程仓库
远程仓库相当于是一个服务器,你可以推送自己的东西到这个服务器上,同时也能拉取别人的推送。
创建远程仓库(在GitHub上创建)
- 第1步:创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有
id_rsa
和id_rsa.pub
这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:
$ ssh-keygen -t rsa -C "[email protected]"
把邮件地址换成自己的邮件地址,然后一路回车,使用默认值即可,由于这个Key也不是用于军事目的,所以也无需设置密码。如果一切顺利的话,可以在用户主目录里找到.ssh
目录,里面有id_rsa
和id_rsa.pub
两个文件,这两个就是SSH Key的秘钥对,id_rsa
是私钥,不能泄露出去,id_rsa.pub
是公钥,可以放心地告诉任何人。 - 第2步:登陆GitHub,在主页点击右上角的个人头像,选择setting,然后在边的列表里点击SSH and GPG keys,再点击New SSH key。填上任意Title,在Key文本框里粘贴
id_rsa.pub
文件的内容:
添加远程库
先在GitHub上新建一个仓库
GitHub告诉我们,可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到GitHub仓库。
现在,我们根据GitHub的提示,在本地的learngit仓库下运行命令:
$ git remote add origin [email protected]:dragon-mystic/binglan-week1.git
其中
orgin
是远程库的意思,
dragon-mystic
是自己在GitHub上的账户名,
binglan-week1
是GitHub仓库名称。
下面就可以把把本地库的内容推送到远程,用
git push
命令,实际上是把当前分支
master
推送到远程。
由于远程库是空的,第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
这里出现了一个 SSH警告,这是因为Git使用SSH连接,而SSH连接在第一次验证GitHub服务器的Key时,需要你确认GitHub的Key的指纹信息是否真的来自GitHub的服务器,输入yes回车即可。Git会输出一个警告,告诉你已经把GitHub的Key添加到本机的一个信任列表里了。这个警告只会出现一次,后面的操作就不会有任何警告了。
此时刷新网页可以看到GitHub的仓库内容和本地的一样了:
从现在起,只要本地作了提交,就可以通过命令:
$ git push origin master
把本地master分支的最新修改推送至GitHub。
从远程库克隆
首先先建立一个新的仓库copy
:
勾选
Initialize this repository with a README
,这样GitHub会自动为我们创建一个
README.md
文件。创建完毕后,可以看到
README.md
文件:
现在可以用命令
git clone
来克隆仓库:
$ git clone [email protected]:dragon-mystic/copy.git
(这里克隆的是本地库,后面同样写的是自己GitHub的仓库地址)
copy
会存在于本地库的
learngit
目录下,而且可以看到
copy
目录下有
README.md
文件;
分支管理
一开始Git会自动创建一个分支master
,Git用master
指向最新的提交,再用HEAD
指向master
,就能确定当前分支,以及当前分支的提交点。每次提交master
会跟着提交不断延长,指向最新的提交。
创建与合并分支
创建新的分支之后,把HEAD
的指向改变到新的分支上,继续提交,新的分支就会根据后来的提交而移动,而原来的master
就会停止在HEAD
指向改变之前的最后一次的提交。
使用命令git checkout
创建新的分支binglan
:
git checkout
命令加上
-b
参数表示创建并切换,相当于以下两条命令:
$ git branch binglan
$ git checkout binglan
Switched to branch 'binglan'
用git branch
命令查看当前分支:
*
后面就是当前分支。然后就可以在分支
binglan
上提交工作了。如果再想回到分支
master
上就使用命令
git checkout
就行了:
如果之前在分支上
binglan
上做了任何的操作,在回到分支
master
之后是看不到的。
使用命令
git merge
可以合并分支(前提是你在分支
binglan
上进行了修改):
此时分支
master
上的内容就会和分支
binglan
上的一样。上面显示的
Fast-foward
是快进的意思,由于这次的修改你较小,所以合并速度很快。
合并完成后可以使用命令
git branch -d
删除分支:
就只剩下
master
分支了:
switch
这是一个更科学的命令,同样可以用来创建合并分支:
创建并切换到新的binglan
分支,可以使用:
$ git switch -c dev
直接切换到已有的master
分支,可以使用:
$ git switch master
解决冲突
在两个分支上分别做一个修改时(master分支和新分支各自都分别有新的提交),Git无法执行“快速合并”,只能试图把各自的修改合并,此时很有可能会发生冲突,此时Git会提示冲突,使用命令git status
同样可以查看这个冲突。此时需要手动去更改,使用命令git log --graph --pretty=oneline --abbrev-commit
可以查看合并情况,最后再删去新分支。
分支管理策略
在合并时,Git一般会使用Fast-forward
的模式,但是在删除分支之后会丢失这条分支的信息。使用命令git merge --no-ff -m "merge with no-ff" binglan
可以强制禁用Fast-forward
模式,Git会在merge
时产生一个新的commit
,这样就可以在分支历史上查看分支信息(git log
)。
Git创建的master
分支是很稳定的,而自己创建的新分支是不稳定的。所以一般都在自己创建的新分支上进行工作,最后再合并到master
上。(在团队合作的情况下非常实用,一人一条分支,最终合并到一起)
Bug分支
用于临时修复Bug创建的一个临时分支。当在用自己创建的分支工作时突然要修复一个Bug,此时使用命令git stash
可以隐藏当前工作的分支并保存工作进度,再创建一个临时分支去修复Bug。可以使用命令git stash list
查看隐藏的分支,在Bug修复之后,删去临时分支,使用命令git stash apply
恢复隐藏的分支,再使用命令git stash drop
删除隐藏分支时stash内容(也可以使用命令git stash pop
恢复并删除)。stash
可以重复使用多次,要恢复指定的stash,用命令$ git stash apply stash@{0}
({}
里面就是恢复的第几次的stash)。
使用命令cherry-pick ···
能复制一个特定的提交到当前分支,···
即你想要的`commit·的版本号。
Feature分支
用于开发新的东西,防止一些实验性质的代码把主分支搞乱,Feature分支在合并时和Bug分支是一样的,如果要强行删除这个Feature分支,则要使用命令git branch -D
。
推送分支
当从远程仓库克隆时,Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin。可以使用命令git remote
查看远程库的信息,或者,用git remote -v
显示更详细的信息:
上面显示了可以抓取和推送的origin的地址。
推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,例如:
$ git push origin master
。
- master分支是主分支,因此要时刻与远程同步;
- 自己创建的主分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
- bug分支只用于在本地修复bug,就没必要推到远程了。
- feature分支是否推到远程,取决于是否和其他人合作在上面开发。
抓取分支
一般情况下,别人从你的远程库clone
只能看到你的master
分支,但是如果别人想在你自己创建的分支binglan
上开发,就必须使用命令$ git checkout -b binglan origin/binglan
创建远程origin的binglan
分支到本地。然后他就可以在binglan
这个分支上进行修改并push
。如果别人和你在这个分支上对相同的文件进行了修改,并且试图推送,会发生冲突,此时需要用命令git pull
把最新的提交从origin/binglan
上抓取下来,然后在本地合并,解决冲突,再推送(在git pull
时一定要先设置binglan和origin/binglan的链接: $ git branch --set-upstream-to=origin/binglan binglan
再pull
)。再将合并的冲突进行手动解决,就和分支管理的一样。解决后再push
。
结语
Git的功能真的很强大,可以实现多人协作开发,能与别人分享自己的经验和作品,有关Git还要学的东西还很多。
插上一个Git常用命令总结(方便快速查找):
未完待续······