为什么要使用Git?
Git是一款非常实用并且先进的分布式版本控制系统,在我们日常处理文件时,经常会经历反复修改的过程,最后文件夹中会躺着类似如下的情况:
一般我们都是通过文件名的不同进行版本管理,当文件数量更多的时候,这种方式的弊端就会暴露出来,以至于最后自己都不记得哪份才是最新版本。
或者在编写代码时会遇到Bug,需要回头找错误,但是却不知道是在哪个环节添加的代码出了问题,很难排查出Bug是由于哪几行代码导致的,影响开发效率。这时就需要一个可以管理版本的软件,Git优于其他版本管理系统的原因之一,就是因为Git跟踪并管理的是修改,而不是文件,这里的修改指的是每次的添加或删除,然后通过时间线的方式进行管理,这样就可以根据需求很自如地回退到某个时间点的文件。
下图展示的是集中式版本控制系统和分布式版本控制系统的区别(左图是集中式,右图是分布式):
安装Git
下面的链接是git的官方网站,根据自己使用的系统进行下载:
https://git-scm.com/downloads
安装好Git后,在桌面鼠标右键会有Git Bash的图标,点击后会弹出一个terminal,在命令行窗口中还需要进行如下设置:
$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"
你的机器作为分布式版本控制系统的一部分,需要对你的机器进行命名。
创建一个版本库
首先打开命令行窗口
输入命令创建版本库
$git init
该命令是为了在一个目录下创建版本库。
这时就会创建好一个文件夹,并在文件夹中创建了一个版本库,如果显示隐藏文件的话会看到一个.git的文件,注意一定不要修改这个文件。这个隐藏文件就是我们的版本库。
创建一个C文件,添加并提交到版本库中
创建了一个文件之后,但是没做其他操作,文件上会显示一个小感叹号
输入以下命令后,文件就会被添加并提交到版本库中。修改之后可以添加一次就提交一次,也可以添加多次之后统一提交,因为commit可以提交很多文件。-m后的部分就是对你所修改内容的一个说明。
$git add <文件名>
$git commit -m "******"
可以看到当文件被添加并提交到版本库后,文件上的小图标就会变成一个绿色的对号
这个warning是由于windows中换行符为回车,在linux下换行符是换行造成,但不影响正常工作,具体可查阅资料。
注意:在编写代码或文本时,不建议使用windows自带的编辑器,推荐使用Notepad++,且将编码设置为UTF-8 without BOM。
时光穿梭
版本回退
先添加并提交几个不同的版本的test.c文件。
(1)第一次添加并提交到版本库
(2)第二次添加并提交到版本库
(3)第三次添加并提交到版本库
查看当前提交的全部版本
$git log
也可以输入以下命令换一种形式展示全部版本。
$git log --pretty=oneline
因为在每次提交之后,git都会将操作串成一条时间线进行管理,所以现在我们也可以回退到某个时间,这里我们将会使用上图中红线标出的id(版本号)作为我们回退时的目的地。下面将展示版本回退的过程。
输入如下命令可以显示当前版本:
$git reset --hard HEAD
输入如下命令可以回退到上一个版本:
$git reset --hard HEAD^
以此类推想要回到上上一个版本的命令就是:
$git reset --hard HEAD^^
如果版本过多的话,^太多会数不清,假如想要回退到50版本,则可以表示:
$git reset --hard HEAD~50
回退到上一个版本后,查看一下test.c文件中的信息,确实是回到了"add test 2"的状态。
再试一下回到第一个版本。
此时查看一下当前的全部版本。
可以看到只剩下第一次添加的版本了。
后悔药
如果你的代码回退到了最初的版本,但是第二天你突然后悔了,还是想要从过去的版本回到新的版本,这时可以通过ID(版本号),也就是我们的目的地,回到我们想要的版本。这里有一个问题,就是当我们已经回退到最初的版本后,新添加的版本的id不就看不到了吗?如果你的命令窗口没有关闭,可以往上翻找到你新版本的ID,当然,如果找不到也没关系,可以使用如下命令:
$git reflog
这样就会显示出来你所添加的所有版本的ID了,假如我现在想要回到"add test 3"的版本,那么1589b…就是这个版本的ID。
$git reset --hard 1589b
可以看到此时,后添加的版本又回来了,查看一下test.c文件中的内容,也是如我所愿。Git的回退速度是很快的,Git内部相当于有一个HEAD指针,指向当前版本,当你输入指令回退到不同版本时,HEAD指针就进行移动,顺便工作区的文件也会更新,也就是我们test.c中的内容。
工作区和暂存区
Git和其他版本控制系统的区别在于Git有一个叫暂存区的概念。
当我们在某个目录下输入命令$git init
时就会在该目录下创建了一个版本库,此时的这个目录也就是我们的工作区。上文也提到.git这个隐藏文件是我们的版本库,内部的文件不要修改,因为版本库中包含着最重要的暂存区(stage/index),还有Git为我们自动创建的第一个分支master,以及指向master的指针HEAD。
我们想要将代码存放到版本库要分为两个步骤,分别是$git add <flie>
和$git commit -m "***"
,其中git add的过程就是将我们工作区的文件添加到版本库的暂存区(stage)中,然后$git commit -m "添加了**文件、实现**功能、解决**bug"
的过程是将版本库暂存区中的文件提交到版本库中的分支中,当前我们只有master一个分支,那么$git commit -m "添加了**文件、实现**功能、解决**bug"
后,文件就会提交到master分支中,HEAD指针指向最新提交的版本。
所以这里就可以理解了之前提到的添加和提交两个步骤,可以添加一次就提交一次,也可以多次添加后一次性提交。若添加一次就提交一次,也就是将我们本地工作区的文件添加到版本库的暂存区,紧接着就提交到master分支上进行管理;若多次添加再提交,也就是将我们在本地工作区多次的修改添加到版本库的暂存区,然后一次性的都提交到master分支进行管理。两种方式都是可行的,要根据自己的需求。接下来实际操作一下:
对test.c文件进行修改,又写入了一个打印函数。
当我们$git add <file>
将文件添加到版本库的暂存区后,还没有$git commit -m "***"
提交,我们通过如下命令查看一下当前的状态:
$git status
Git提醒我们此时有一个被更改的文件test.c还没有被提交。我们将添加到版本库暂存区的文件提交到master分支上再查看一下状态。
此时的工作区就变得干净了。
撤销修改
(1)如果在工作区中做了一些修改但是觉得不满意想要撤销如何操作。
在对test.c文件进行修改,但是并没有添加、提交,查看一下目前的状态。
如果此时你对此时所作的修改不满意,可以使用如下命令撤销修改(注:此时的修改并没有添加并提交!!!):
$git checkout -- <file>
这可以看到test.c文件又回到了修改前的版本,此时与暂存区内的版本时相同的。
(2)下面进行实际操作一下,如果修改后的文件添加到暂存区后应该如何撤销修改(注:此时已经将文件添加到暂存区,但是并没有提交!!!),输入如下命令:
$git reset HEAD <file>
输入这条命令后就代表将我们添加到暂存区的修改撤销,重新放回到工作区。工作区的修改如何撤销,就是参照上面所提到的内容,使用如下命令即可:
$git checkout -- <file>
实际操作如下,先是对test.c文件进行修改。
查看目前状态。
Git提示我们文件已被修改,如果需要添加的话就使用$git add <file>
的命令,如果需要撤销则使用$git checkout -- <file>
的命令可以撤销工作区的修改,我们现在将该版本添加到暂存区。
添加到暂存区后,Git提示我们该文件还没有被提交到分支master,如果想要撤销可以使用$git reset HEAD <file>
的命令撤销暂存区的修改,重新放回工作区,现在我们尝试一下。
此时我们可以看到在使用$git reset HEAD <file>
命令之后的状态,Git提示我们暂存区没有需要提交的修改,这与刚才没有将修改添加到暂存区时的状态是一样的,也就是回到了工作区刚被修改的状态。如果需要添加到暂存区并提交到分支master,则必须先$git add <file>
;如果想要撤销工作区的修改,再次$git checkout -- <file>
即可。
此时的状态是在分支master上没有修改被提交,而且工作区也是干净的,再次查看一下test.c文件,确实回退到了修改之前!
(3)如果你的修改文件添加到了暂存区,并且也提交到分支master,此时需要撤销的话就要使用之前提到的版本回退。
小结:
(1)如果文件只是在工作区作了修改,想要撤销修改的话使用命令$git checkout -- <file>
。
(2)如果文件在工作区作了修改之后,并添加到暂存区后,此时想要撤销修改,使用命令$git reset HEAD <file>
撤销到工作区,想要继续撤销工作区的修改,再次使用命令$git checkout -- <file>
。
(3)如果文件在工作区作了修改,并且添加到暂存区后又提交到分支master,此时想要撤销的话,就要使用版本回退。
删除文件
删除文件也是一个修改,在工作区新建一个文件并添加到暂存区,如果此时将工作区的文件删除掉之后,Git会提示此时暂存区和工作区是不一样的。
(1)如果确实希望删除掉该文件,使暂存区与工作区保持一致,则输入如下命令:
$git rm <file>
$git commit -m "***"
创建一个新的文件并添加到暂存区,然后删除掉工作区的该文件。
查看当前状态。
使用命令$git rm <file>
删除文件,并使用命令$git commit -m "***"
提交。
这样文件就成功的从暂存区删除掉了,与工作区保持一致。
注:命令$git diff
是显示工作区和暂存区目前的区别。
(2)如果是误删了工作区的文件,想要恢复该如何操作。
因为工作区的文件已经添加到了暂存区,但是现在工作区的文件被误删掉,此时工作区和暂存区中的内容不一致了,如果想要恢复的话只需要将暂存区中的内容替换到工作区即可,使用的命令和上文提到的将工作区的修改撤销是一样的,所以这里可以得出命令$git checkout -- <file>
的原理就是将暂存区的内容替换到工作区。实际操作如下:
可以看到使用命令$git checkout -- <file>
后确实将暂存区的内容替换到工作区了。
远程仓库
添加远程仓库
GitHub作为远程库,可以很方便地将我们本地库的代码进行托管,登录GitHub官网后进行申请账号,申请账号后远程仓库的添加方法如下:
(1)点new
(2)弹出这个界面后,分别编辑此项目的仓库名、对于该仓库的描述、是否公开等选项,最后点击create repository,创建成功。
(3)创建好仓库后,就要将我们的本地仓库与远程仓库进行关联。通过如下命令即可完成关联:
$git remote add origin git@github.com:xudedegit/git_tutorial.git
注:这里的origin是你在github中定义的仓库的名字,origin是默认的叫法,当然也可以起其他的名字,后面的地址即该仓库的地址,github提供两种地址方式,分别是http和ssh,http的特点就是只看账号密码,也就是你输入的账号和密码正确就可以访问;ssh的特点就是认机器,ssh url访问的这种方式是通过公钥和私钥,一个在本机另一个在github上,所以匹配成功的话就会访问成功。具体方法可以查阅资料。
(4)本地库和远程库关联好之后,即可通过如下命令将本地库的代码推送到远程库,使远程库与本地库同步。
$git push -u origin master
注:这里首次推送时需要加上-u
,使本地的分支master
和远程库的分支master
关联,后面就可以不加了。当然这里的origin
是根据自己之前对远程仓库的命名进行替换。
查看目前关联远程库状态使用如下命令:
$git remote -v
从远程库克隆文件到本地库用如下命令:
$git clone git@github.com:xudedegit/git_tutorial.git
注:这里的前提是你在本地库中已经创建了版本库,也就是命令:
$git init
忽略特殊文件
当在提交代码时,往往会存在一些不需要上传或涉密不能上传的文件,当把需要上传的文件提交后,通过$git status
查看状态时都会有untracked files present
的提示,那么如何避免呢?
需要在你版本库的目录下再创建一个.gitignore
的文件来记录你想忽略上传的文件名。
将想要忽略的文件的文件名添加到.gitignore文件中。
此时将需要提交的代码或文件提交上之后查看目前状态。
此时只提示.gitignore文件作了修改且没有提交,但是1.txt和2.txt并没有提示,这说明1.txt和2.txt两个文件已经被忽略。
将.gitignore文件提交后,查看当前状态可以看到工作区是干净的,忽略文件成功。