zoukankan      html  css  js  c++  java
  • Git学习笔记------整理自廖雪峰官网教程

    • CVS及SVN都是集中式的版本控制系统,而Git是分布式版本控制系统。集中式和分布式版本控制系统的区别

      集中式版本控制系统,版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。所以集中式版本控制系统最大的毛病就是必须联网才能工作,如果在局域网内还好,带宽够大,速度够快。如果在互联网上,则速度难以保证。

      而分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上。既然每个人电脑上都有一个完整的版本库,那多个人如何协作呢?比方说你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。在实际使用分布式版本控制系统的时候,其实很少在两人之间的电脑上推送版本库的修改,因为可能你们俩不在一个局域网内,两台电脑互相访问不了,也可能今天你的同事病了,他的电脑压根没有开机。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。

      和集中式版本控制系统相比,分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。而集中式版本控制系统的中央服务器要是出了问题,所有人都没法干活了。

    • 安装后使用

      因为Git是分布式版本控制系统,所以,每个机器都必须自报家门:你的名字和Email地址。所以安装完后使用前注意要进行设置,输入:

    $ git config --global user.name "Your Name"
    $ git config --global user.email "email@example.com"
    

      注意git config命令的--global参数,用了这个参数,表示你这台机器上所有的Git仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和Email地址。

      对于git的命令的使用,在终端输入git,得到git以下的命令列表:

      

      对于一些常规的命令的使用还是比较简单的,而且上图的说明很详细。这里不做太多介绍(大家可以继续往后看,后面会有总结)。

    • git工作原理(工作区和暂存区)

      工作区就是你在电脑里能看到的目录,即本地目录。工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD(分支和HEAD的概念之后再讲)

      现在理一下思路,涉及工作区和版本库,可见目录即是我们的工作区,隐藏目录.git即是版本库。版本库分为了暂存区(stage)和分支(master)。个人认为版本库涉及成暂存区和分支这种分了两个层级,容错性较好,比如你对其中的文件做了修改,可能想放弃修改,这是一回事,然后确定保存这个,是否提交又是另一回事。这比直接确定保存修改并提交这样一个层级容错性较好。

      了解git工作原理后,我们再来看看一些命令的具体功能。这样我们对常用的命令走一遍加深理解,并熟悉命令的使用及流程。

      首先,对于创建一个空目录,用init命令初始化,这使得该目录变成Git可以管理的仓库。然后新建一个文件(注意所有的版本控制系统,其实只能跟踪文本文件的改动,不幸的是,Microsoft的Word格式是二进制格式,因此,版本控制系统是没法跟踪Word文件的改动的),把这个文件放入新建的空目录下,子目录也行(这是一个Git仓库,放到其他地方Git再厉害也找不到这个文件)。然后输入add命令,add命令的作用即是把文件修改添加到暂存区,然后确定提交则调用commit命令,即把暂存区内容提交到分支,一般commit命令必须带提交说明,跟在-m后。

      checkout命令的意思就是,把文件在工作区的修改全部撤销,这里有两种情况:文件自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;文件已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。总之,checkout就是让这个文件回到最近一次git commitgit add时的状态

      reset的命令既可以回退版本,也可以把暂存区的修改回退到工作区。要进行版本回退,Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交3628164...882e1e0(注意我的提交ID和你的肯定不一样),上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100。当我们用HEAD时,表示最新的版本。从而用命令git reset HEAD file意思相当于把暂存区的修改撤销掉(unstage),重新放回工作区。而版本回退更常见的做法是先调用git log命令,这个命令会列出提交历史列表,每次提交说明前都有该版本对应的commit id。找到想要回退的id,使用reset命令即可(id可不用全写,写到可区分即可),而对于想回到未来,可先调用git reflog查看命令历史,以便确定要回到未来的哪个版本。

      总结一下,如果进行了错误的修改,但这修改没有add或commit,则直接调用checkout命令即可。如果进行了错误的修改,并且add或commit了,则需要用reset命令进行恢复。

      删除文件rm,在Git中,删除也是一个修改操作。确实要删除文件,则删除文件后,调用git rm命令,然后提交即可。命令git rm用于删除一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容。

    • 分支管理

      在版本回退里已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向mastermaster才是指向提交的,所以,HEAD指向的就是当前分支。

      开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点:

      当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:

      从上面可以看出Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化。从而之后的修改提交都是针对dev分支了,master分支就不动了,而dev分支则不断往后延长,在dev分支完成工作后,可以把dev分支合并到master分支,即直接把master指向dev当前提交,所以合并操作也很快。然后就可以把dev分支删除,git鼓励创建分支进行工作。相关命令:

      查看分支:git branch  创建分支:git branch <name>  切换分支:git checkout <name>

      创建+切换分支:git checkout -b <name>  合并某分支到当前分支:git merge <name>  删除分支:git branch -d <name>

      合并冲突:以上提到两个分支合并时,只有一个分支进行了提交,可以使用“快速合并”模式,如果合并的时候两个分支都进行了新的提交,这种情况下,Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突,这时必须解决冲突后再提交。可以用git status查看哪个文件冲突到相关文件修改一致后再提交。用git log --graph命令可以看到分支合并图。

      使用fast forward模式(快速合并)合并时,删除分支后会丢失分支信息。如果要强制禁用Fast forward模式(加--no-ff参数),Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。具体什么意思呢,就是用--no-ff模式合并它的合并图如下,就是会创建一个新的提交,相当于把分支提交到最后合并版本,这样可以看出中间有分支。所以这种模式调用命令如下:git merge --no-ff -m "merge with no-ff" dev后面要加提交参数即-m。  

      分支策略:首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。

      Bug分支:这是什么意思呢?就是我们正在工作的时候突然要修改bug(这个最好创建分支解决),这时我们可以用git stash将当前工作区内容保存起来,然后再创建分支,修改完毕后,再调用git stash apply恢复工作区,并且调用git stash drop来删除stash内容。或者直接调用git stash pop,恢复的同时把stash内容也删了。

      如果要丢弃一个没有被合并过的分支,可以通过git branch -D <name>强行删除

    • 远程操作

      因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。虽然github也支持http协议传输,但每次要输入用户名和密码比较麻烦。所以在进行远程操作前最好设置一下。具体操作:

      首先在shell中输入

    $ ssh-keygen -t rsa -C "youremail@example.com"
    

      一路回车后,在当前目录下的.ssh中有id_rsaid_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。然后在GitHub个人设置的ssh keys中点add new key,将id_rsa.pub中的内容全部复制即可,标题可随便写。

      从远程库克隆:首先调用如下命令即可将远程库克隆到本地:

    $ git clone git@github.com:michaelliao/gitskills.git

      实际上,Git支持多种协议,默认的git://使用ssh,但也可以使用https等其他协议。使用https除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh协议而只能用https

      所以这里一定要用git不要用http的形式,因为只有用git的ssh协议才能每次提交不用输密码之类的,如果用http之后每次提交每次要输密码,很不方便。

      当你从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin。要查看远程库的信息,用git remote,注意这句命令只能在下载下来的目录里运行,不然不会有反应。用git remote -v显示更详细的信息,所使用的协议等。

    $ git remote -v
    origin  git@github.com:michaelliao/learngit.git (fetch)
    origin  git@github.com:michaelliao/learngit.git (push)
    

      上面显示了可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址。

      推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,

    $ git push origin master
    

      Git就会把该分支推送到远程库对应的远程分支上,当然也可以指定其他分支,如dev。

      当从远程库clone时,默认情况下,只能看到本地的master分支。如果要在dev分支上开发,就必须创建远程origindev分支到本地,使用如下命令:

    $ git checkout -b dev origin/dev
    

      在dev分支上进行修改后,可以用git push origin branch-name推送自己的修改;如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;如果合并有冲突,则解决冲突,并在本地提交;没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功!如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream branch-name origin/branch-name。以上是多人协作的模式。

      添加远程库:即已经在本地创建了一个Git仓库后,又想在GitHub创建一个Git仓库,并且让这两个仓库进行远程同步,这样,GitHub上的仓库既可以作为备份,又可以让其他人通过该仓库来协作。具体为

    首先,登陆GitHub,然后,在右上角找到“Create a new repo”按钮,创建一个新的仓库比如leangit。之后可以在本地的仓库下运行命令:

    $ git remote add origin git@github.com:michaelliao/learngit.git
    

      这里要注意,把上面的michaelliao替换成你自己的GitHub账户名,否则,你在本地关联的就是别人的远程库,关联没有问题,但是你以后推送是推不上去的,因为你的SSH Key公钥不在别人的账户列表中。添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。

      下一步,就可以把本地库的所有内容推送到远程库上,由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令(不用-u参数)。

    $ git push -u origin master
    • 标签管理

      Git的标签是版本库的快照,它其实就是指向某个commit的指针(跟分支很像对不对?但是分支可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的。说白了标签就是某一commit版本的版本号别名,方便查找管理。

      创建标签:在Git中打标签非常简单,首先,切换到需要打标签的分支上,然后敲命令git tag <name>就可以打一个新标签。默认标签是打在最新提交的commit上的。有时候,如果忘了打标签,比如,现在已经是周五了,但应该在周一打的标签没有打,怎么办?方法是找到历史提交的commit id,然后打上就可以了git tag <name> <commit id>。可以用命令git tag查看所有标签。还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字。用命令git show <tagname>可以看到说明文字。

    $ git tag -a v0.1 -m "version 0.1 released" 3628164
    

      删除标签:命令git tag -d <tagname>可以删除一个本地标签。命令git push origin :refs/tags/<tagname>可以删除一个远程标签。

      推送标签:命令git push origin <tagname>可以推送一个本地标签,命令git push origin --tags可以推送全部未推送过的本地标签。

      参考资料:http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000

      

     

      

  • 相关阅读:
    Java ES api 查询例子
    leveldb学习
    Viewstamp Replication协议
    PacificA协议
    vhost架构
    数据分片方法
    常见分布式存储系统架构分析
    数据存储(B+树 vs LSM树)
    paxos算法理解
    Raft协议理解
  • 原文地址:https://www.cnblogs.com/Dzhen/p/6931276.html
Copyright © 2011-2022 走看看