文章目录
廖雪峰的GIT教程
什么是GIT
Git是目前世界上最先进的分布式版本控制系统(没有之一)。是Linus花了两周时间自己用C语言写的。
集中式vs分布式版本控制系统
CVS及SVN都是集中式的版本控制系统,而Git是分布式版本控制系统。
集中式版本控制系统就是所有的内容都保存在中央服务器上面,我们每次操作的时候都需要从中央服务器上面获取最新的内容,修改完了之后再传递上去。
[外链图片转存失败(img-XnlF5kB6-1566581933967)(1B9CBF61F0B04AC6A76A81D125FBD0A6)]
分布式版本控制系统就是每个人的电脑都是完整的版本库,每个人在自己的电脑上进行修改,然后在和同事的进行“同步”。(一般来说,分布式的也会有一台中央服务器,但只是为了大家同步修改的时候方便)。
[外链图片转存失败(img-p3eD7Qpw-1566581933969)(D9C7FBEF03274333858CA6153E90BAF5)]
分布式版本系统的最大好处之一是在本地工作完全不需要考虑远程库的存在,也就是有没有联网都可以正常工作,而SVN在没有联网的时候是拒绝干活的!当有网络的时候,再把本地提交推送一下就完成了同步,真是太方便了!
分布式版本控制系统除了Git以及促使Git诞生的BitKeeper外,还有类似Git的Mercurial和Bazaar等。这些分布式版本控制系统各有特点,但最快、最简单也最流行的依然是Git!
图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改成了120KB,但到底改了啥,版本控制系统不知道,也没法知道。
分支管理
创建版本库
- 创建一个空的文件夹
- 使用git init命令,把这个文件夹变成GIT管理的一个仓库(前目录下多了一个.git的目录,这个目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了)
- 使用git add命令(e.g. git add readme.txt)把文件添加到仓库
- 使用git commit命令(e.g. git commit -m “wrote a readme file”)把文件提交到仓库
GIT的版本回退
- 使用git log命令,我们可以看到每次提交的时候都干了什么,以及每个版本的版本号(版本号为一个很大的十六进制数字)
- 在GIT中,使用HEAD来表示当前的版本,HEAD来表示上一个版本,HEAD^来表示上两个版本,上100个版本为HEAD~100。然后使用git reset --hard HEAD^命令来回退到上一个版本。Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针,当你回退版本的时候,Git仅仅是把HEAD从指向回滚到的版本
[外链图片转存失败(img-0YzYRtMG-1566581933970)(353AC1A0247E43B19C30F20A9C989EC2)]
工作区和暂存区
工作区(Working Directory)
就是你电脑上的仓库文件里面的,除了.git文件夹剩下的东西都属于工作区
版本库(Repository)
工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库
Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD
[外链图片转存失败(img-xK3zGqlm-1566581933971)(B1E1E29B9DE4407CBC94E3DD2AA16597)]
把文件提交到GIT版本库的时候分为两步
- git add命令,这个实际上就是把文件添加到暂存区。
- git commit命令,这个就是一次性把暂存区的内容都提就到版本库(默认是master分支)
比如我们向一个仓库中添加了两个文件LICENSE和readme.txt
当我们执行完git add命令之后
[外链图片转存失败(img-CP4hW13D-1566581933971)(4E7C0EEA48D248458D4CF1218424DE53)]
当我们执行完git commit命令之后
[外链图片转存失败(img-p9i35wEM-1566581933972)(FF8200CE27F94195889F27D20700F9FA)]
管理修改
Git跟踪并管理的是修改,而非文件
e.g.
当你同一个文件提交两次,第一次提交的git add了,第二次的没有。你commit之后会发现只有第一次修改的被提交了。
当你用git add命令后,在工作区的第一次修改被放入暂存区,准备提交,但是,在工作区的第二次修改并没有放入暂存区,所以,git commit只负责把暂存区的修改提交了,也就是第一次的修改被提交了,第二次的修改不会被提交。
远程仓库
实际情况往往是这样,找一台电脑充当服务器的角色,每天24小时开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交
为了证明推送者的身份,我们需要在本机创建SSH Key
创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:
$ ssh-keygen -t rsa -C “youremail@example.com”
你需要把邮件地址换成你自己的邮件地址,然后一路回车,使用默认值即可,由于这个Key也不是用于军事目的,所以也无需设置密码。
如果一切顺利的话,可以在用户主目录里找到.ssh目录,里面有id_rsa和id_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。
分支
为什么需要分支
分支在实际中有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。
现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。
分支的原理
一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点:
[外链图片转存失败(img-V4O627MW-1566581933973)(FE91A393838F42639F2F5B008F92F068)]
每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长。
当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:
[外链图片转存失败(img-zO4D0Vh2-1566581933973)(9443D1BE84CC47CE888F272A540D1A79)]
你看,Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!
不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:
[外链图片转存失败(img-JRGXbIjA-1566581933974)(C77CFB333565499A9877FA36373E7F5C)]
假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:
[外链图片转存失败(img-Dlrciw7z-1566581933975)(B9FEEA953FD143388BE180726A4756B0)]
所以Git合并分支也很快!就改改指针,工作区内容也不变!
合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:
[外链图片转存失败(img-rxs8GVYe-1566581933976)(62CDEEC5B9124D339CC26491B631301D)]
GIT命令总结
命令 | 说明 |
---|---|
git --version | 查看当前主机的GIT版本 |
git config --global user.name “Your Name” | 设置本机的用户名 --golbal是本机所有仓库都使用这个配置 |
git config --global user.email “email@example.com” | 设置本机的邮箱 |
git init | 创建一个空的文件夹,然后再使用这个命令就可以把这个文件夹变成GIT管理的 |
git add | 添加文件到GIT仓库,并且一次可以添加多个文件(e.g. git add file1.txt git add file2.txt file3.txt) |
git commit | 向GIT仓库添加文件,提交的时候为了方便版本控制,最好加上注释(e.ggit commit -m “add 3 files.”) |
git status | 查看工作区的状态 |
git diff | 查看文件和GIT库中的不同(e.g. git diff readme.txt) |
git log | 命令显示从最近到最远的提交日志,–pretty=oneline将每次提交的日志信息放到一行(e.g. git log --pretty=oneline) |
git log --graph | 看到分支合并的流程图 |
git reset | 回退版本(e.g. git reset --hard HEAD^),也可以通过版本号来回滚git reset --hard 1094a(其中1094a位版本号,不需要写出全部的版本号,只需要能够区分即可) |
git reset HEAD | 撤销暂存区的修改 |
git reflog | 记录你的每一次命令操作 |
git checkout – file | 回退你工作区的一个文件,让这个文件回到最近一次git commit或git add时的状态 |
git rm | 删除版本库里面的文件,删除完了之后记得git commit |
git remote add origin | 使当前的仓库关联远程的GIT仓库 |
git push | 将当前仓库的内容推送至远程仓库(e.g. git push -u origin master)ps:第一次使用参数 -u是建立本地与远程库的联系,第二次就不用了 |
git clone | 从远程库克隆,克隆下来就直接是和远程库有关联的 |
git brance | 查看都有哪些分支 |
git branch dev | 创建一个分支dev分支 |
git checkout dev | 选择一个分支 |
git checkout -b dev | 创建并选择一个分支,是上面两条命令的合集 |
git merge dev | 选择一个分支合并到当前的分支 |
git branch -d dev | 删除某个分支 |
git branch -D | 删除一个从来没有被合并过的分支,需要使用大写参数D |
git merge --no-ff -m “merge with no-ff” dev | 合并dev分支到当前的分支,且不使用Fast forward模式(–no–ff的意思就是no fast forward) |
git stash | 把当前工作现场“储藏”起来,等以后恢复现场后继续工作,藏起来之前必须要有一次初始提交 |
git stash list | 查看藏起来的工作现场 |
git stash apply | 恢复stash的内容 |
git stash drop | 删除stash藏起来的内容 |
git stash pop | 恢复的同时也把stash的内容删除了 |
git cherry-pick 4c805e2 | 把特定一次提交的内容merge过来 |
git remote -v | 显示的origin是默认的远程仓库名,没有push权限的话就没有push的那条信息 |
git rebase | 这就是rebase操作的特点:把分叉的提交历史“整理”成一条直线,看上去更直观。缺点是本地的分叉提交已经被修改过了 |
小贴士
- 只有commit了才会有版本号,回滚版本之后暂存区的内容会被清空
- 工作区回滚git checkout – filename,如果暂存区有内容是回滚到暂存区的,暂存区没有内容才回滚到版本库的内容