目录git
什么是github,github能作什么?它是一个代码仓库,可是你能够把它当作一个远程硬盘(云盘、网盘)。和通常网盘的区别在于,它经过一个叫作git的软件进行同步,上传或下载操做,这个软件有很是强大的同步功能,甚至能够创建不一样的存储分支,让同步的文件有多个不一样的版本(这对代码开发来讲是颇有意义的)。可是,若是你不想要,不须要这个功能,也能够把它当作纯粹的免费网盘使用。github
如今就有不少人,经过github来存放我的笔记,日记,博客等文档资料,在不一样电脑上,只要同步一下,就能继续编辑,很是方便。这个甚至比通常的网盘要来得轻松,由于git对版本的控制更好,数据传输量更少。同步更加智能化,版本管理更加方便。安全
多说无益,本文介绍git的原理和使用方法,你亲自看一下是否对你有用。bash
git是一个分布式同步工具,简单来讲,它不要求你创建一个特定的服务器,你能够在任何地方创建本身的存储仓库,不一样的仓库没有地位的差别,都是平等的,这就去中心化了,因此叫分布式。服务器
这有什么好处,好比你不须要依赖某个网盘提供商,若是它不当心倒闭了,只要你把仓库搬到另外一个提供商就能够,甚至,你直接弄一台电脑放仓库也是能够的。这个理念我认为是很是有居安思危精神的。千万别过于相信网络,要给数据一个备份。网络
若是是传统的网盘,你须要用它的软件,下载文件到你的电脑,而后用另外一家的软件,上传到另外一个网盘备份,不用两天你就受不了。若是你不跟踪备份,可能网盘没通知你就把你的学习资料删除了,那你是怎么也要不回来的。相信经历过的朋友都知道。而只需用git,就能统一的管理各个仓库,轻松进行复杂的同步。编辑器
也就是储存仓库,可是这个仓库不但能够放文件,还对文件的修改、删除等历史记录做跟踪,让你能够回溯到某个历史时期。这是git 最强大的功能。分布式
为了利用好版本管理功能,要求文件类型是文本类型,最好是UTF-8编码的。工具
git init #在当前目录下创建仓库,将新建一个.git文件夹来存储仓库数据
在当前目录新建文件,而后加入仓库,git便可维护该文件的同步管理。性能
git add file.txt #将当file.txt文件加入git仓库
添加并不会马上提交,也不会自动同步,这个交给用户本身判断恰当的提交时机。
git commit -m "这里写备注" #提交数据
每次提交,都要求你写一个备注,来记录你此次提交作了什么,这是个良好的习惯,由于这样你回溯历史的时候,才知道哪一个版本是你的目标版本。
当前被跟踪的文件,和仓库版本有什么差别,能够用git status
列出哪些文件改动了的文件。
若是你还想知道具体修改了什么地方,能够用git diff xxx
来查看xxx文件的改动状况。
这个是比较高级的功能,也许你用得上,也许用不上。首先,git reflog
会显示你提交文档的版本:
#样例输出 f9adcba (HEAD -> master) HEAD@{0}: reset: moving to f9adc 9a75fd8 HEAD@{1}: reset: moving to HEAD~1 f9adcba (HEAD -> master) HEAD@{2}: commit: 测试回退功能 9a75fd8 HEAD@{3}: commit: 加了一点 781b0ad HEAD@{4}: commit: 有加了一点 55227c1 HEAD@{5}: commit: git文档修改 f2d5850 HEAD@{6}: commit (amend): ss2 ff6877d HEAD@{7}: commit (initial): ss
要跳到那个版本,使用git reset --hard f9ad
,其中f9ad
用具体的版本号替换。在以上样例的第一列,只须要给出几位,git就会寻找到对应版本。
当跳转到该版本,相应的文档数据会当即修改。
当你在某个目录下面,建立仓库git init
,该目录就是你的工做区,而具体的仓库的一些配置信息,是放在.git
目录下的(可能被隐藏)。
工做区的做用就是你要同步的文件,应该放在这个目录下面,你只须要修改对应的文件,git负责其他的一切。你不须要刻意的去修改或者理会.git目录下面的内容,而应该使用git软件来输入命令。
当用git add xxx
添加文件,实际上就是把文件放入暂存区。当git commit
就会把暂存区的内容正式提交到某个分支(之后解释分支),并清空暂存区。
若是要撤销工做区的修改,能够用git checkout -- xxx
;若是要撤销暂存区的修改,能够用git reset HEAD xxx
。
还记的我说过git是分布式的么?若是只是在本身电脑目录建立一个仓库,那就没什么意思了,如今学习怎么添加远端的仓库。
首先,申请github.com网站的帐户,并申请一个仓库的使用权,而后获得一个仓库的连接地址,而后:
git remote add 仓库别名 连接 #添加远端仓库 git push -u 仓库别名 master #将本地分支master提交到仓库。-u表示关联对应分支 git remote -v #显示远程仓库状况 git pull #从远程仓库拉取最新版本
git容许创建不一样分支,所谓的分支,就是另外一条修改文件的路线。git记录每一条路线不一样的修改内容,当合并的时候会要求你对有冲突的修改内容进行选择。
git branch git #建立名为git的分支 git checkout git #切换到git分支 git branch #查看当前分支状况 git merge git #将git合并到当前分支 git branch -d git #删除git分支
建立分支后,所作任何修改,只影响当前分支,当切换分支,文件会瞬间回到另外一个分支的状态下。
虽然git分支这个功能看上去很强大,又很复杂,但实际上运做很是高效,它总能按照你指望的方式去运做。所以,推荐多使用,用来划分不一样的关注点也是挺好的。
一个合理的使用分支的方法是:
这样就算再多人一块儿合做编辑,也能保证主分支是稳定可靠的。
不过,最好仍是不要随便跳转分支,由于跳转分支容易致使当前数据丢失,而后还会致使不少不少的误操做。(本博客就是这样丢失了一些历史信息,╮(╯▽╰)╭!)q
特别要注意,切换分支是一个高度危险的操做!由于它会毁掉当前工做区的状态。切换分支以前,应该先提交当前修改内容到仓库。可是,若是占时没法提交,能够借助储藏功能,把当前工做区保存在一个栈表里面。
git stash #保存并清空当前工做区修改状态 git stash pop #回弹当前工做区上一个状态。 git stash list #显示储藏栈表
标签对应了commit 提交版本,由于这个版本号太复杂,所以用标签名来代替,更加容易识别。也做为一个发行版本号来使用。
git tag v0.9 #当前版本命名为标签v0.9 git tag #查看当前标签 git tag -d v0.9 #删除对应标签 git push origin v0.9 #提交标签到远程仓库
纵观理论知识,咱们能够得出一些结论:
有些操做是危险的:若是没有提交到仓库,就切换分支,当前工做内容就可能丢失,由于切换分支并不懂得自动保存当前工做区的状态。只要是会对当前工做区产生影响的操做,都有可能影响到数据安全(若是当前工做区没有提交,有修改状态),好比拉取,同步,切换分支,版本跳转,所以这些操做以前特别要注意查看当前工做区状态,先提交,或者储藏现场。
工做区和暂存区,都是不安全的,能够视为临时数据,他们之间造成一个小型的临时版本控制机制。工做区的内容能够放到暂存区,暂存区的内容也可能回退到工做区。
git 官网在http://git-scm.com,下面以deepin系统为例:
apt install git #安装git git --version #版本号2.17
cd ~ mkdir gittest cd gittest git init #在gittest目录下建立仓库,当前工做区便是gittest git help #查看使用说明
非新项目,能够从远程仓库克隆建立。
git clone https://github.com/Anduin2017/HSharp.git cloneProj #从已有的远程仓库克隆建立名为cloneProj的本地仓库。该远程连接能够在github任意一个公开项目中获取。
git仓库的配置信息,能够存在三个地方:
/etc/gitconfig
~/.gitconfig
.git/config
#添加用户名和邮箱信息,必备,由于每一次提交仓库都要记录当前提交人的这些信息 git config --local user.name "myname" #添加user.name的记录为myname,其中--local为默认值,能够省略 git config user.email myname@163.com #添加user.email为myname@163.com git config --list #列出当前已经配置的内容 git config user.name #列出某项的值,即myname
若是不想某些文件被加入仓库,能够用.gitignore文件指定,内容例如:
#忽略.cpp文件和~符号结尾的文件 *.cpp *~
应该常用这个命令确认文件状态。
注意: 若是你使用编辑器来编辑,要注意当前编辑状态和当前文件状态是不一样的。git是针对文件而不能知道你有没有正在编辑。若是你正在编辑,又经过git命令修改了文件,你的编辑器就会提示你原始文件已经被修改,你没法保存等异常状态。所以,你在使用git命令前,应该先把编辑状态下的文件,用编辑器保存一下。
git status #查询状态
#建立一个新文件,并在末尾输入内容“hello world!” cat >>myfile.txt hello world! ^C #将该文件放入暂存区 git add myfile.txt #继续编辑,并在末尾添加“hello.” cat >>myfile.txt hello. ^C # 这时,就存在两个不一样的版本,一个是修改前放进暂存区的"hello word!"版本,一个是工做区内的“hello word!hello."版本。 git status #遇事不决,先用这个确认状态。能够发现同一个文件,有两种状态。一种是放在暂存区的,提示让你提交;另外一种是在工做区的,提示让你暂存变动。 git diff myfile.txt #确认一下文件内容的差异。显示工做区和暂存区两个同名文件的对比,若是你会看diff输出格式,就能发现差异是添加"hello." #选择1,放弃当前修改,返回上次暂存内容 git checkout -- myfile.txt #选择2,确认修改,放入暂存 git add myfile.txt #git status的提示很丰富,提示上面有以上指令的使用格式 #删除文件 #若是某个文件被删除,这在git中也是一个特殊的修改 git rm xxx #删除xxx,并把删除状况告知暂存区 git rm --staged yyy #从暂存区删除yyy文件,但不影响工做区
暂存区的内容并不会产生一个稳定的版本,最终要正式加入仓库,须要commit提交。
提交会要让你输入每次提交的备注,命令行下面的编辑器由git config core.editor
选项控制。
git commit #向本地仓库提交暂存区的内容 git reset HEAD myfile.txt #取消暂存区内容。 git diff --staged #比较暂存区和仓库版本的不一样 git commit -a -m ”备注“ #把工做区的改动所有暂存起来,而后直接提交。-a参数将缩减提交的步骤。 git log -2 #观察最近两条提交记录 git log --pretty="%h %an,%ar:%s" #按指定格式显示记录 git log --pretty=oneline --graph #显示按分支提交结构图 apt install gitk #安装图形化显示记录的工具
git remote -v #查看远程仓库列表 git remote add remotegit https://github.com/Anduin2017/HSharp.git #添加一个远程仓库,命名为remotegit git fetch remotegit #下载远程仓库remotegit的对象和引用 git remote show remotegit #显示远程仓库关联信息 git remote rename remotegit newname #把远程仓库命名进行修改 git remote rm newname #删除远程仓库的关联 git clone https://github.com/Anduin2017/HSharp.git clonegit #克隆生成一个彻底同样的本地仓库,建立工做目录为clonegit
远程仓库上面的分支,称为远程分支。
git remote -v #查看远端仓库状况 git remote add gitbak file:///home/user/git #加入本地另外一处仓库 git fetch gitbak #下载仓库信息 git branch -av #查看全部分支,包括远端仓库 git branch --set-upstream-to=gitbak/master #当前分支关联gitbak/master分支 git pull gitbak master --allow-unrelated-histories #合并不关联的历史数据 git push cloneProj HEAD:master #提交本地分支到远端仓库 #注意:应该尽可能保持本地分支名称和远程一致。
这个功能比较简单。
git stash #储藏当前工做区和暂存区变更 git stash pop #恢复
每一次提交,都会产生一个版本,任什么时候候均可以跳转到该版本,可是版本标识是一个字符串哈希序列(sha-1 40字符哈希),不方便对外公布。
git tag #显示现有标签 git tag v1.0 #为当前版本命名标签 git show #显示HEAD关联提交对象信息 git show v1.0 #显示特定版本信息 git push origin v1.0 #向远程仓库提交标签 git commit -am"备注" #建立一个新提交"commit"对象,并改变HEAD指针指向新对象,若是头指针指向某个分支,先改变该分支指向新对象,再用HEAD指针指向该分支。简而言之,建立新版本 git reset 2341a --hard #HEAD指针调到散列为2341a开始的commit对象,即跳到该版本,--hard参数重置当先工做区和暂存区
git中的分支,相似一个指针,一个提交(commit)相似链表中的一个节点。commit保存了父节点,和整个目录树结构,所以当分支(指针)指向某个commit,内容天然就是该节点的状态。理解这点很重要。也许你会担忧每次提交都产生一个当前文件目录的快照,会不会致使存储量变得很大,实质上是不须要担忧的。git以一种高效的方式进行相关记录,无论是性能仍是空间,都容许你瞬间执行提交,产生新的快照。
一开始有个master的分支,有个HEAD指针,它指向master,而master指向具体的commit节点,每次提交,master都会更新到新的节点上。若是你使用某种命令移动这个指向,天然就会变动到不一样的版本,这就是实现版本管理的基础。
git branch -va #显示分支状况,-a表示全部分支,包括远程分支,这个命令常用,由于它会显示分支的状况,相似git status显示文件状况。 git branch testbranch #基于当前分支建立一个新分支,实质不过是复制一个指针而已,效率很是高 #当你想切换到其余分支 #1. 保存正在编辑的文件 #2. 储藏现场git stash push -m "备注" #2.2 或者提交git commit #3. 切换分支 #为何?由于切换分支会清空现场,你将丢失掉工做区和暂存区的改动数据 git checkout testbranch #切换到testbranch,它和此前分支上一次提交版本如出一辙 git commit -m “备注” #每次提交,都会移动当前分支,指向最新的commit对象 #分支的成果最终要合并起来 git merge master #将master分支合并到当前分支 #合并过程可能会出现数据冲突,参考提示,手工选择后合并成功 git checkout master git merge testbranch #更新master分支,通常这个分支做为默认的主分支 git branch -d testbranch #删除分支 #若是该分支新增的内容没有被合并到其余分支,就会提示让你先合并,善用git status,根据提示来操做便可。 git mergetool #调用图形界面来解决内容冲突
分支的功能并不算太复杂,可是如何设计适合本身须要的分支系统,就是一门值得思考的功课。建议master做为集成主分支,有若干分支负责实际编辑,编辑完毕合并到主分支。而后每一个细分支有里程碑(用标签标注),发布版本应该选择恰当的里程碑组合,进度稍微比主分支慢。
另外,若是须要修补,能够选择在里程碑新建一个补丁分支,它须要和主分支合并,也须要和发布分支合并。
可能用到的技术包括:
git branch 分支名 提交对象
git checkout 分支名
git checkout xxx
git merge x1
git tag v1.0.0.f1
git checkout --detach
git reset --hard commit对象
集成merge的基本逻辑是:
所以应该采起的策略:每一个分支应该尽可能寻求共同祖先。那么共同祖先是怎么来的?实质之前某个merge节点(或者是分裂的初始点),不然分支怎么会有共同祖先?所以解决集成merge冲突复杂化的办法,实际是分红屡次集成,也就是持续集成的意义所在。
\344\275\277\347\224\250
相似的编码格式,能够用:git config --global core.quotepath false