git是一种分布式版本控制系统。而与之相对就是集中式版本控制系统。集中式版本控制系统的表明是CVS和Subversion,其版本库集中存放在中央服务器上,干活的时候,要先从中央服务器取得最新的版本,而后开始干活,干完活了,再把本身的活推送给中央服务器。每一个开发者之间没法进行版本的传递。因此集中式版本控制系统最大的毛病就是必须联网才能工做。html
而分布式版本控制系统根本没有“中央服务器”,每一个人的电脑上都是一个完整的版本库,这样,你工做的时候,就不须要联网了,由于版本库就在你本身的电脑上,因此能够在本地进行提交。既然每一个人电脑上都有一个完整的版本库,那多我的如何协做呢?对于分布式版本库系统,每一个开发者之间是能够直接进行版本的传递的,比方说你在本身电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,大家俩之间只需把各自的修改推送给对方,就能够互相看到对方的修改了。可是在实际开发中,为了方便版本的传递(交换修改),一般也会有一个中央服务,这个中央服务器是一个裸版本库,仅仅是为了方便版本传递,没有这个中央服务器也能正常工做,只是没有这么方便而已。git
① 初始化,建立版本库
要想使用git,那么咱们须要建立一个版本库,用于存储该项目自己及其历史。为此,咱们须要建立一个项目根目录,如first-steps,而后进入到项目根目录下,而后在该项目根目录下执行git init
,init命令会在当前目录下建立一个名为.git的隐藏目录,并在其中建立一个版本库,这个带版本库的项目目录,咱们一般称为工做区。服务器
> cd /path/to/first-steps > git init Initialized empty Git repository in /path/to/first-steps/.git/
② 首次提交
版本库建立好以后,就能够进行提交了,提交分为两步,第一,先使用add命令将须要提交的文件添加到暂存区;第二,而后使用commit命令将暂存区中的内容提交到版本库中。提交完成后,git会给该提交赋予一个散列值,以下面的c12ac1c,用于标识此次新提交。分布式
> git add foo.txt bar.txt > git commit --message "Sample project imported." [master (root-commit) c12ac1c] Sample project imported. 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 bar.txt create mode 100644 foo.txt
③ 检查状态
如今咱们能够修改一下foo.txt内容而且删除bar.txt,而后天就一个index.html文件,而后经过git status
命令,能够查看到该项目从上次提交以来全部发生的修改。fetch
> git status On branch master Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) deleted: bar.txt modified: foo.txt Untracked files: (use "git add <file>..." to include in what will be committed) index.html no changes added to commit (use "git add" and/or "git commit -a")
④ 提交修改
工做区有了修改后,一样也是须要使用add和commit进行提交。版本控制
> git add foo.txt index.html > git rm bar.txt rm 'bar.txt' > git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) deleted: bar.txt modified: foo.txt new file: index.html > git commit --message "Some changes" [master f1c648a] Some changes 3 files changed, 13 insertions(+) delete mode 100644 bar.txt create mode 100644 index.html
能够看到,新的提交也有一个对应的散列值(f1c648a),这里使用到了git rm
命令,其与rm命令的区别就是,rm仅仅是删除工做区的文件,并无从暂存区中删除;而git rm 是删除工做区的文件同时将修改添加到暂存区中。 因此,git rm bar.txt
等价于 rm bar.txt
和 git add bar.txt
,就是多了一个将工做区修改添加到暂存区的操做。code
⑤ 显示历史
咱们能够经过git log
来查看项目的提交历史,全部的提交都会按时间顺序被降序排列出来。htm
> git log commit f1c648a033ad509f5ffe08f96152432be1c12c7b (**HEAD ->** **master**) Author: hongbiao.lhb <hongbiao.lhb@alibaba-inc.com> Date: Tue Dec 31 11:01:40 2019 +0800 Some changes commit c12ac1ced34a57104f29f4bceea13f88e2c3cbcf Author: hongbiao.lhb <hongbiao.lhb@alibaba-inc.com> Date: Tue Dec 31 10:32:32 2019 +0800 Sample project imported.
① 克隆版本库
git提供了一个clone命令,能够将某个版本库克隆到指定的目录下面。其用法为git clone 版本库地址 目标版本库所在目录
,能够在任何目录下执行clone命令,若是没有指定目标版本库所在的目录,那么是直接将版本库克隆到当前目录下面,而且是将.git目录和工做区内容及其所在的目录都克隆过去,即整个项目克隆过去,可是若是指定了目标版本库所在的目录,那么克隆的仅仅是.git目录和工做区内容,即以目标版本库所在目录做为项目根目录。ci
> mkdir /path/to/first-steps-clone > git clone /path/to/first-steps /path/to/first-steps-clone Cloning into first-steps-clone... done.
② 从源版本库中取回修改
如今咱们分别在first-steps 和 first-steps-clone中进行一次提交,如:开发
// first-steps修改foo.txt的内容 > cd /path/to/first-steps > git add foo.txt > git commit --message 'A change in the original'
// first-steps-clone修改index.html的内容 > cd /path/to/first-steps-clone > git add index.html > git commit --message 'A change in the clone'
如今两个版本库中都做了相应的修改,就像两个开发者分别在开发,这个时候就须要同步对方的修改,对于clone版本库(first-steps-clone)而言,由于克隆的时候,源版本库的路径已经存储在了克隆版本库中,因此能够直接用git pull
命令取回源版本库的修改。
这里须要注意的是,虽然源版本库修改的是foo.txt文件,克隆版本库修改的是index.html文件,可是执行git pull
命令后并不能自动合并,由于执行git pull
命令的时候,克隆版本库中对index.html进行了修改而且提交到了版本库中,而执行git pull
命令以后,获取到了修改foo.txt的提交,与当前修改index.html的提交出现分叉了,因此须要把源版本库中对foo.txt的修改和克隆版本库中对index.html的修改进行一次手动合并merge。由于同一个分支中不能出现分叉,必须将其合并成一个。可是若是执行git pull
命令的时候,克隆版本库中没有进行任何提交,那么获取到foo.txt的提交后就没有出现分叉,因此能够自动合并。
> git log --graph * commit 3f78c7f4b0c6c3bd9e8ee5b15d061cb9018c9f44 (**HEAD ->** **master**) |\ Merge: f324964 b40f4a0 | | Author: hongbiao.lhb <hongbiao.lhb@alibaba-inc.com> | | Date: Tue Dec 31 12:43:05 2019 +0800 | | | | Merge branch 'master' of /Users/banma-798/Downloads/first-steps | | | * commit b40f4a0d0e4344f49afaad609659046014031fbc (**origin/master**, **origin/HEAD**) | | Author: hongbiao.lhb <hongbiao.lhb@alibaba-inc.com> | | Date: Tue Dec 31 12:25:34 2019 +0800 | | | | A change in the original | | * | commit f324964540fbc031fbbea42d3fc853c5722a4236 |/ Author: hongbiao.lhb <hongbiao.lhb@alibaba-inc.com> | Date: Tue Dec 31 12:42:55 2019 +0800 | | A change in the clone | * commit f1c648a033ad509f5ffe08f96152432be1c12c7b | Author: hongbiao.lhb <hongbiao.lhb@alibaba-inc.com> | Date: Tue Dec 31 11:01:40 2019 +0800 | | Some changes | * commit c12ac1ced34a57104f29f4bceea13f88e2c3cbcf Author: hongbiao.lhb <hongbiao.lhb@alibaba-inc.com> Date: Tue Dec 31 10:32:32 2019 +0800 Sample project imported.
能够看到,分支出现了分叉,而后又收到merge合并为了一个分支。总共有5次提交,最初的2次提交+克隆版本库的提交+源版本库的提交+手动merge的提交。
③ 从任意版本库中取回修改git pull
在没有参数的状况,只能在克隆版本库中执行,去取回源版本库的修改。而源版本库中执行git pull是没法从克隆版本库获取到克隆版本库的修改的。
> cd /path/to/first-steps > git pull fatal: No remote repository specified. Please, specify either a URL or a remote name from which new revisions should be fetched.
可是能够经过指定版本库路径和分支名的方式来从任何一个版本库中取回修改,即git pull 版本库路径 分支名
,如:
> cd /path/to/first-steps > git pull /path/to/first-steps-clone master
① 克隆裸版本库
所谓裸版本库,就是一个不带工做区的版本库,仅仅用于开发者之间传递提交的一个汇聚点,能够经过git clone --bare来建立一个裸的版本库。
> git clone --bare /path/to/first-steps /path/to/first-steps-bare.git > Cloning into bare repository first-steps-bare.git... done.
② push推送修改到裸版本库
为何必需要建立一个裸版本库呢?由于push命令只能将修改推送到裸版本库中。用法为git push 裸版本库路径 分支
> git push /path/to/first-steps-bare.git master
这里须要注意的是,若是另外一个开发者在咱们以前已经作过一次push操做,那么咱们再次执行push命令就会被拒绝推送,这个时候,咱们必须先把其余人的提交pull过来而后才能接着push。
对于克隆版本库而言,执行push和pull命令的时候,能够直接用origin表明源版本库,如:
> git push origin master > git pull origin master
因此能够看到,若是本身的版本库比目标版本库的要落后,那么是没法push推送本身的修改到目标版本库的,因此在实际开发中,若是咱们提交了一个版本,可是忽然发现该次提交存在重大bug,咱们没法经过在本地直接回退到上一个版本而后在push推送到目标版本库的方式去取消上次提交,由于一旦回退版本,那么你的版本库就比目标版本库落后了,因此push推送失败。固然,咱们能够经过带上-f参数来强制提交上去,可是不建议这么作。
// 强制推送修改到目标版本库 > git push -f origin master