Git是一个开源的分布式版本控制系统,用以有效、高速的处理从很小到很是大的项目版本管理。Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。
Torvalds 开始着手开发 Git 是为了做为一种过渡方案来替代 BitKeeper,后者以前一直是 Linux 内核开发人员在全球使用的主要源代码工具。开放源码社区中的有些人以为 BitKeeper 的许可证并不适合开放源码社区的工做,所以 Torvalds 决定着手研究许可证更为灵活的版本控制系统。尽管最初 Git 的开发是为了辅助 Linux 内核开发的过程,可是咱们已经发如今不少其余自由软件项目中也使用了 Git。html
版本管理:前端
在开发中,这是刚需,必须容许能够很容易对产品的版本进行任意回滚,版本控制工具实现这个功能的原理简单来说,就是你每修改一次代码,它就帮你作一次快照。node
协做开发:python
一个复杂点的软件,每每不是一个开发人员能够搞定的,IT公司为加快产品开发速度,会招聘一堆跟你同样的开发人员开发这个产品,拿QQ来举例,如今假设3我的一块儿开发QQ,A开发联系人功能,B开发发文 字、图片、语音通信功能,C开发视频通话功能, B和C的功能都是要基于通信录的,你说简单,直接把A开发的代码copy过来,在它的基础上开发就行了,能够,可是你在他的代码基础上开发了2周后,这期间A没闲 着,对通信录代码做了更新,此时怎么办?你和他的代码不一致了,此时咱们知道,你确定要再把A的新代码拿过来替换掉你手上的旧通信录功能代码, 如今人少,3我的之间沟通很简单,但想一想,若是团队变成30 我的呢?来回这样copy代码,很快就乱了,因此此时急需一个工具,能确保一直存储最新的代码库,全部人的代码应该和最新的代码库保持一致。git
Linus在1991年建立了开源的Linux,今后,Linux系统不断发展,已经成为最大的服务器系统软件了。Linus虽然建立了Linux,但Linux的壮大是靠全世界热心的志愿者参与的,这么多人在世界各地为Linux编写代码,那Linux的代码是如何管理的呢?github
事实是,在2002年之前,世界各地的志愿者把源代码文件经过diff的方式发给Linus,而后由Linus本人经过手工方式合并代码!你也许会想,为何Linus不把Linux代码放到版本控制系统里呢?不是有CVS、SVN这些免费的版本控制系统吗?由于Linus坚决地反对CVS和SVN,这些集中式的版本控制系统不但速度慢,并且必须联网才能使用。有一些商用的版本控制系统,虽然比CVS、SVN好用,但那是付费的,和Linux的开源精神不符。数据库
不过,到了2002年,Linux系统已经发展了十年了,代码库之大让Linus很难继续经过手工方式管理了,社区的弟兄们也对这种方式表达了强烈不满,因而Linus选择了一个商业的版本控制系BitKeeper,BitKeeper的老板BitMover公司出于人道主义精神,受权Linux社区无偿使用这个版本控制系统。安定团结的大好局面在2005年就被打破了,缘由是Linux社区汇集,难免沾染了一些梁山好汉的江湖习气。开发Samba的Andrew试图破解BitKeeper的协议(这么干的其实也不仅他一个),被BitMover公司发现了(监控工做作得不错!),因而BitMover公司怒了,要收回Linux社区的无偿使用权。Linus能够向BitMover公司道个歉,保证之后严格管教弟兄们,嗯,这是不可能的。实际状况是这样的:Linus花了两周时间本身用C写了一个分布式版本控制系统,这就是Git!一个月以内,Linux系统的源码已经由Git管理了!牛是怎么定义的呢?你们能够体会一下。bootstrap
Git迅速成为最流行的分布式版本控制系统,尤为是2008年,GitHub网站上线了(github是一个基于git的代码托管平台,付费用户能够建私人仓库,咱们通常的免费用户只能使用公共仓库,也就是代码要公开。),它为开源项目免费提供Git存储,无数开源项目开始迁移至GitHub,包括jQuery,PHP,Ruby等等。vim
历史就是这么偶然,若是不是当年BitMover公司威胁Linux社区,可能如今咱们就没有免费而超级好用的Git了。windows
今天,GitHub已经是:
Git能够在Linux、Unix、Mac和Windows这几大平台上正常运行了。
Linux上安装Git:sudo
apt-get
install
git
Window上安装Git:
一、在Git官网下载windows版的git,可是官网几乎很难进去。SO,我在网盘存了Windows-Git-2.17。
连接:https://pan.baidu.com/s/14y7F7t9gKaZyG2Q_SHGH6A
提取码:2ds0
二、安装教程
https://jingyan.baidu.com/article/afd8f4dea2ff0b34e286e984.html
版本仓库能够简单理解成一个目录,这个目录里面的全部文件均可以被Git管理起来,每一个文件的修改、删除,Git都能跟踪,以便任什么时候刻均可以追踪历史,或者在未来某个时刻能够“还原”。
一、建立版本库
$ mkdir git_test $ cd git_test/ $ git init Initialized empty Git repository in /Users/luban/git_test/.git/
.git
的目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,否则改乱了,就把Git仓库给破坏了。
若是你没有看到.git
目录,那是由于这个目录默认是隐藏的,用ls -ah
命令就能够看见。
二、把文件添加到版本库
版本控制系统,其实只能跟踪文本文件的改动,好比TXT文件,网页,全部的程序代码等等,Git也不例外。版本控制系统能够告诉你每次的改动,好比在第7行加了一个单词“Linux”,在第8行删了一个单词“Windows”。而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但无法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改为了120KB,但到底改了啥,版本控制系统不知道,也无法知道。
不幸的是,Microsoft的Word格式是二进制格式,所以,版本控制系统是无法跟踪Word文件的改动的。若是要真正使用版本控制系统,就要以纯文本方式编写文件。由于文本是有编码的,建议使用标准的UTF-8编码,全部语言使用同一种编码,既没有冲突,又被全部平台所支持。
先编写一个文件:
$ vim first_git_file.txt
第一次使用git哈哈
注意:文件要放到git_test目录下(子目录也行),由于这是一个Git仓库,放到其余地方Git再厉害也找不到这个文件。
把一个文件放到Git仓库只须要两步:
一、把文件添加到仓库(在git_test目录下)
$ git add first_git_file.txt
执行上面的命令,没有error说明添加成功。
二、把文件提交到仓库
$ git commit -m "commit my first git file" [master (root-commit) 621e6e4] commit my first git file Committer: Your name and email address were configured automatically based on your username and hostname. Please check that they are accurate. You can suppress this message by setting them explicitly. Run the following command and follow the instructions in your editor to edit your configuration file: git config --global --edit After doing this, you may fix the identity used for this commit with: git commit --amend --reset-author 1 file changed, 2 insertions(+) create mode 100644 first_git_file.txt
中间红色部分的意思是,你在往git库里提交代码时,你须要告诉git你是谁,这样git就会纪录下来是谁改的代码,其实就是为了往后查询方便,你只须要提供一个名字和邮件地址就能够,
$ git config --global user.email "test@example.com" $ git config --global user.name "test"
$git commit -m "commit my first git file"
git commit
命令,-m
后面输入的是本次提交的说明,能够输入任意内容,固然最好是有意义的,这样你就能从历史记录里方便地找到改动记录。
为何Git添加文件须要add
,commit
一共两步呢?由于commit
能够一次提交不少文件,因此你能够屡次add
不一样的文件,好比:
$ git add file1.txt $ git add file2.txt file3.txt $ git commit -m "add 3 files."
添加当前目录到仓库:git add .
查看当前仓库状态:git status
查看日志:git log
一、修改并提交代码
咱们已经成功地添加并提交了一个first_git_file.txt文件,如今,是时候继续工做了,因而,咱们继续修改first_git_file.txt文件,改为以下内容:
第一次使用git,哈哈
11111111111111111
如今,运行git status
命令看看结果:
$ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: first_git_file.txt no changes added to commit (use "git add" and/or "git commit -a")
虽然Git告诉咱们first_git_file.txt被修改了,但若是能看看具体修改了什么内容,天然是很好的。好比你外出两周从国外回来,第一天上班时,已经记不清上次怎么修改的first_git_file.txt,
因此,须要用git diff
这个命令看看:
输出中+号绿色显示的就是修改或新增的内容,-号红色显示的就是去掉或被修改的内容
知道了对first_git_file.txt 做了什么修改后,再把它提交到仓库就放心多了,提交修改和提交新文件是同样的两步,第一步是git add
:
提交后,咱们再用git status
命令看看仓库的当前状态:
Git告诉咱们当前没有须要提交的修改,并且,工做目录是干净(working directory clean)的。
代码回滚
再一次修改first_git_file.txtt文件以下:
第一次使用git,哈哈 11111111111111111,hello python! 22222222222222222
而后尝试提交:
像这样,不断对文件进行修改,而后不断提交修改到版本库里,就比如玩RPG游戏时,每经过一关就会自动把游戏状态存档,若是某一关没过去,你还能够选择读取前一关的状态。有些时候,在打Boss以前,你会手动存档,以便万一打Boss失败了,能够读取最新的存档从新开始。Git也是同样,每当你以为文件修改到必定程度的时候,就能够“保存一个快照”,这个快照在Git中被称为commit
。一旦你把文件改乱了,或者误删了文件,还能够从最近的一个commit
恢复,而后继续工做,而不是把几个月的工做成果所有丢失。
如今,回顾一下first_git_file.txt文件一共有几个版本被提交到Git仓库里了:
版本1:
第一次使用git哈哈
版本2:
第一次使用git,哈哈
11111111111111111
版本3:
第一次使用git,哈哈 11111111111111111,hello python! 22222222222222222
在实际工做中,咱们脑子里怎么可能记得一个几千行的文件每次都改了什么内容,否则要版本控制系统干什么。
版本控制系统确定有某个命令能够告诉咱们历史记录,在Git中,咱们用git log
命令查看:
git log
命令显示从最近到最远的提交日志,咱们能够看到3次提交,最近的一次是second change,上一次是first change,最先的一次是commit my first git file
。
若是嫌输出信息太多,看得眼花缭乱的,能够试试加上--pretty=oneline
参数:
友情提示的是,你看到的一大串相似的5175f849175073e17fa6f28eee4a3b6d41a3a822是commit id
(版本号),和SVN不同,Git的commit id
不是1,2,3……递增的数字,而是一个SHA1计算出来的一个很是大的数字,用十六进制表示,并且每一个人的commit id
确定不同,以本身的为准。为何commit id
须要用这么一大串数字表示呢?由于Git是分布式的版本控制系统,后面咱们还要研究多人在同一个版本库里工做,若是你们都用1,2,3……做为版本号,那确定就冲突了。
回滚回滚回滚
好了,如今咱们启动时光穿梭机,准备把first_git_file.txt回退到上一个版本,也就是“first change”的那个版本,怎么作呢?
首先,Git必须知道当前版本是哪一个版本,在Git中,用HEAD
表示当前版本,也就是最新的提交c71fa92ffa180708f9169ba90673dc05219d5ab9(注意个人提交ID和你的确定不同),上一个版本就是HEAD^
,上上一个版本就是HEAD^^
,固然往上100个版本写100个^
比较容易数不过来,因此写成HEAD~100
。
如今,咱们要把当前版本“second change”回退到上一个版本“first change”,就能够使用git reset
命令:
此时再看你的文件内容,果真就退回去了
此时还能够继续再往前回退一个版本,不过且慢,然咱们用git log
再看看如今版本库的状态:
最新的那个版本second change 已经看不到了!比如你从21世纪坐时光穿梭机来到了18世纪,想再回去已经回不去了,怎么办?
办法其实仍是有的,只要上面的命令行窗口尚未被关掉,你就能够顺着往上找啊找啊,找到那个second change的commit id
是c71fa92ffa180708f9169ba90673dc05219d5ab9
因而就能够指定回到将来的某个版本:
胖子,没错,仍是我胡汉三!
Git的版本回退速度很是快,由于Git在内部有个指向当前版本的HEAD
指针,当你回退版本的时候,Git仅仅是把HEAD从指向second change
如今假设,你回退到了first change版本,关掉了电脑,次日早上就后悔了,想恢复到新版本second change怎么办?找不到新版本的commit id怎么办?毕竟咱们并不是圣贤。
在Git中,老是有后悔药能够吃的。当你用$ git reset --hard HEAD^回退到first change版本时,再想恢复到最新second change的版本,就必须找到second change的commit id。
救命稻草------Git提供了一个命令git reflog用来记录你的每一次命令:
如今,你又能够乘坐时光机回到将来了。
Git和其余版本控制系统如SVN的一个不一样之处就是有暂存区的概念。
工做区(Working Directory)
就是你在电脑里能看到的目录,好比个人git_test文件夹就是一个工做区:
$ ls git_test/
first_git_file.txt
版本库(Repository)
工做区有一个隐藏目录.git
,这个不算工做区,而是Git的版本库。
Git的版本库里存了不少东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为咱们自动建立的第一个分支master
,以及指向master
的一个指针叫HEAD
。
分支和HEAD
的概念用后面的示例引出。
前面咱们把文件往Git版本库里添加的时候,是分两步执行的:
第一步是用git add
把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用git commit
提交更改,实际上就是把暂存区的全部内容提交到当前分支。
由于咱们建立Git版本库时,Git自动为咱们建立了惟一一个master
分支,因此,如今,git commit
就是往master
分支上提交更改。
简单理解为,须要提交的修改文件统统放到暂存区,而后,一次性提交暂存区的全部修改文件。
咱们再次修改first_git_file.txt,而且新建一个readme.md,随便写点解释语句(针对本次修改)
先用git status
查看一下状态:
Git很是清楚地告诉咱们,first_git_file.txt
被修改了,而readme.md
还历来没有被添加过,因此它的状态是Untracked
。
如今,使用命令git add .
,再用git status
再查看一下:
如今暂存区的状态就变成以下图所示:
因此,git add
命令实际上就是把要提交的全部修改放到暂存区(Stage),而后,执行git commit
就能够一次性把暂存区的全部修改提交到分支。
一旦提交后,若是你又没有对工做区作任何修改,那么工做区就是“干净”的:
如今的版本库变成了这样,暂存区没有东西
暂存区是Git很是重要的概念,弄明白了暂存区,就弄明白了Git的不少操做到底干了什么。
假设本身在readme.md写了不合适的语句:
在你准备提交前,你猛然发现了“鲁班大师智障二百五!”可能会让你丢掉这个月的奖金!
既然错误发现得很及时,就能够很容易地纠正它。你能够删掉最后一行,手动把文件恢复到上一个版本的状态。
但若是用git status
查看一下:
你能够发现,Git会告诉你,git checkout -- file
能够丢弃工做区的修改:
你刚才添加的话就被撤销了,命令git checkout -- readme.md
意思就是,把readme.md
文件在工做区的修改所有撤销,这里有两种状况:
第一种是readme.md
自修改后尚未被放到暂存区,如今,撤销修改就回到和版本库如出一辙的状态;
第二种是readme.md
已经添加到暂存区后,又做了修改,如今,撤销修改就回到添加到暂存区后的状态。
总之,就是让这个文件回到最近一次git commit
或git add
时的状态。
git checkout -- file
命令中的--
很重要,没有--
,就变成了“切换到另外一个分支”的命令。
假设咱们遇到第二种状况:在readme.md中写了脏话,而且添加到了暂存区该怎样解决呢?
庆幸的是在没提交以前,咱们发现了它。Git一样告诉咱们,用命令git reset HEAD file
能够把暂存区的修改撤销掉(unstage),从新放回工做区:
如今,咱们将readme.md的修改撤回到了工做区:
如今只需按照第一种在工做区的状况对待便可。
step1:git checkout -- readme.md
step2: git status
step3: cat readme.md
世界终于清净了!哈哈哈
在Git中,删除也是一个修改操做,先添加一个新文件test.txt到Git而且提交:
通常状况下,你一般直接在文件管理器中把没用的文件删了,或者用rm
命令删了
这个时候,Git知道你删除了文件,所以,工做区和版本库就不一致了,git status
命令会马上告诉你哪些文件被删除了:
如今咱们有两个选择,一是确实要从版本库中删除该文件,那就用命令git rm
删掉,而且git commit
:
如今,文件就从版本库中被删除了。
另外一种状况是删错了,由于版本库里还有呢,因此能够很轻松地把误删的文件恢复到最新版本:
git checkout --
test
.txt
git checkout
实际上是用版本库里的版本替换工做区的版本,不管工做区是修改仍是删除,均可以“一键还原”。
可是版本库里的文件被删就完全没了。
一个神奇的网站--GitHub,这个网站就是提供Git仓库托管服务的。因此,只要注册一个GitHub帐号,就能够免费得到Git远程仓库。
在继续阅读后续内容前,请自行注册GitHub帐号。因为你的本地Git仓库和GitHub仓库之间的传输是经过SSH加密的,因此,须要一点设置:
第1步:建立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
是公钥,能够放心地告诉任何人。
第2步:登录GitHub,打开“Account settings”,“SSH Keys”页面:
而后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub
文件的内容:
点“Add Key”,你就应该看到已经添加的Key。
为何GitHub须要SSH Key呢?由于GitHub须要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,因此,GitHub只要知道了你的公钥,就能够确认只有你本身才能推送。
固然,GitHub容许你添加多个Key。假定你有若干电脑,你一下子在公司提交,一下子在家里提交,只要把每台电脑的Key都添加到GitHub,就能够在每台电脑上往GitHub推送了。
友情提示,在GitHub上免费托管的Git仓库,任何人均可以看到喔(但只有你本身才能改)。因此,不要把敏感信息放进去。
若是你不想让别人看到Git库,有两个办法,一个是交点保护费,让GitHub把公开的仓库变成私有的,这样别人就看不见了(不可读更不可写)。另外一个办法是本身动手,搭一个Git服务器,由于是你本身的Git服务器,因此别人也是看不见的。
11.1 建立远程仓库
在本地建立了一个Git仓库后,又想在GitHub建立一个Git仓库,而且让这两个仓库进行远程同步,这样,GitHub上的仓库既能够做为备份,又可让其余人经过该仓库来协做,真是一举多得。
首先,登录GitHub,而后,在右上角找到“New repository”按钮,建立一个新的仓库:
目前,在GitHub上的这个Gittest仓库仍是空的,GitHub告诉咱们,能够从这个仓库克隆出新的仓库,也能够把一个已有的本地仓库与之关联,而后,把本地仓库的内容推送到GitHub仓库。
如今,咱们根据GitHub的提示,在本地已有的git_test仓库下运行命令:
注意,把上面的Yun-Wangjun替换成你本身的GitHub帐户名,不然,你在本地关联的就是个人远程库,关联没有问题,可是你之后推送是推不上去的,
由于你的SSH Key公钥不在个人帐户列表中。添加后,远程库的名字就是origin
,这是Git默认的叫法,也能够改为别的,可是origin
这个名字一看就知道是远程库。
把本地库的内容推送到远程,用git push
命令,其实是把当前分支master
推送到远程。此时刷新远程仓库页面, 就看到了你刚从本地推上来的代码了。
从如今起,只要本地做了提交,就能够经过命令:
$ git push origin master
建立一个hello.py文件,同时上传到远程
而后刷新下远程仓库页面,就看到你的新建立的文件了。
首先,登录GitHub,建立一个新的仓库,名字叫remote_to_local
:
如今,远程库已经准备好了,下一步是用命令
git clone
克隆一个本地库:
在本地找一个你想存放这个远程仓库的目录,而后在本地命令行用git clone 命令来克隆这个远程库。
若是有多我的协做开发,那么每一个人各自从远程克隆一份就能够了。GitHub给出的地址不止一个,还能够用 https://github.com/Yun-Wangjun/remote_to_local.git这样的地址。实际上,Git支持多种协议,默认的git://
使用ssh,但也能够使用https
等其余协议。使用https
除了速度慢之外,还有个最大的麻烦是每次推送都必须输入口令。
分支就是科幻电影里面的平行宇宙,当你正在电脑前努力学习Git的时候,另外一个你正在另外一个平行宇宙里努力学习SVN。
若是两个平行宇宙互不干扰,那对如今的你也没啥影响。不过,在某个时间点,两个平行宇宙合并了,结果,你既学会了Git又学会了SVN!
好比:2我的开发一个购物商城,你负责前端,另外一个负责后端。你开发一个新功能,可是须要两周才能完成,第一周你写了50%的代码,若是马上提交,因为代码还没写完,不完整的代码库会致使别人不能干活了。若是等代码所有写完再一次提交,又存在丢失天天进度的巨大风险。你建立了一个属于你本身的分支,别人看不到,还继续在原来的分支上正常工做,而你在本身的分支上干活,
想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工做。
其余版本控制系统如SVN等都有分支管理,可是用过以后你会发现,这些版本控制系统建立和切换分支比蜗牛还慢,
但Git的分支是不同凡响的,不管建立、切换和删除分支,Git在1秒钟以内就能完成!不管你的版本库是1个文件仍是1万个文件。
12.1建立与合并分支
在版本回退部分时,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master
分支。HEAD
严格来讲不是指向提交,而是指向master
,master
才是指向提交的,因此,HEAD
指向的就是当前分支。
一开始的时候,master
分支是一条线,Git用master
指向最新的提交,再用HEAD
指向master
,就能肯定当前分支,以及当前分支的提交点:
每次提交,master
分支都会向前移动一步,这样,随着你不断提交,master
分支的线也愈来愈长, 当咱们建立新的分支,
例如dev
时,Git新建了一个指针叫dev
,指向master
相同的提交,再把HEAD
指向dev
,就表示当前分支在dev
上:
$ git checkout -b dev Switched to a new branch 'dev'
#注意:命令加上参数表示建立并切换,至关于如下两条命令:
命令会列出全部分支,当前分支前面会标一个号。
#切换分支:git checkout branch_name
git checkout-bgit branch devgit checkout dev#git branch*
咱们能够在dev
分支上正常提交,好比对readme.txt作个修改,加上一行,而后提交:
如今,dev
分支的工做完成,咱们就能够切换回master
分支:切换回master
分支后,再查看一个readme.txt文件,刚才添加的内容不见了!由于那个提交是在dev
分支上,而master
分支此刻的提交点并无变:
如今就能够把dev
合并到master
上。Git怎么合并呢?最简单的方法,就是直接把master
指向dev
的当前提交,就完成了合并:
注意到上面的Fast-forward
信息,Git告诉咱们,此次合并是“快进模式”,也就是直接把master
指向dev
的当前提交,因此合并速度很是快。
因此Git合并分支也很快!就改改指针,工做区内容也不变!
合并完分支后,甚至能够删除dev
分支。删除dev
分支就是把dev
指针给删掉,删掉后,咱们就剩下了一条master
分支:
由于建立、合并和删除分支很是快,因此Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master
分支上工做效果是同样的,但过程更安全。
12.2解决冲突
合并分支每每也不是一路顺风的。准备新的feature_1
分支,继续咱们的新分支开发:
修改readme.txt最后一行,改成:
在feature_1
分支上提交:
切换到master
分支:
Git还会自动提示咱们当前master
分支比远程的master
分支要超前1个提交。
在master
分支上把readme.txt文件的最后一行修改并提交:
如今,master
分支和feature_1
分支各自都分别有新的提交,变成了这样:
这种状况下,Git没法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突:
git告诉咱们:
自动合并README.md
CONFLICT(内容):在README.md中合并冲突
自动合并失败; 修复冲突,而后提交结果。
readme.txt文件存在冲突, 必须手动解决冲突后再提交。git status
也能够告诉咱们冲突的文件:
git告诉咱们:
在分支master 你的分支在2次提交以前领先于'origin / master'。 (使用“git push”发布您的本地提交) 你有未合并的路径。 (修复冲突并运行“git commit”) (使用“git merge --abort”停止合并) 未合并的路径: (使用“git add <file> ...”来标记分辨率) 二者都修改过:README.md 没有更改添加到提交(使用“git add”和/或“git commit -a”)
咱们能够直接查看readme.txt的内容:
Git用<<<<<<<
,=======
,>>>>>>>
标记出不一样分支的内容,咱们修改以下后保存,提交:
如今,master
分支和feature1
分支变成了下图所示:
用带参数的git log
也能够看到分支的合并状况:
首先,master
分支应该是很是稳定的,也就是仅用来发布新版本,平时不能在上面开发;
那在哪干活呢?干活都在dev
分支上,也就是说,dev
分支是不稳定的,到某个时候,好比1.0版本发布时,再把dev
分支合并到master
上,在master
分支发布1.0版本;
你和你的小伙伴们每一个人都在dev
分支上干活,每一个人都有本身的分支,时不时地往dev
分支上合并就能够了。
因此,团队合做的分支看起来就像这样:
软件开发中,bug就像屡见不鲜同样。有了bug就须要修复,在Git中,因为分支是如此的强大,因此,每一个bug均可以经过一个新的临时分支来修复,修复后,合并分支,而后将临时分支删除。
当你接到一个修复一个代号101的bug的任务时,很天然地,你想建立一个分支issue-101
来修复它,可是,等等,当前正在dev
上进行的工做尚未提交:
$ git status # On branch dev # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # new file: hello.py # # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: readme.txt #
并非你不想提交,而是工做只进行到一半,还无法提交,预计完成还需1天时间。可是,必须在两个小时内修复该bug,怎么办?
幸亏,Git还提供了一个stash
功能,能够把当前工做现场“储藏”起来,等之后恢复现场后继续工做:
$ git stash Saved working directory and index state WIP on dev: 6224937 add merge HEAD is now at 6224937 add merge
如今,用git status
查看工做区,就是干净的(除非有没有被Git管理的文件),所以能够放心地建立分支来修复bug。
首先肯定要在哪一个分支上修复bug,假定须要在master
分支上修复,就从master
建立临时分支:
$ git checkout master Switched to branch 'master' Your branch is ahead of 'origin/master' by 6 commits. $ git checkout -b issue-101 Switched to a new branch 'issue-101'
如今修复bug,须要把“Git is free software ...”改成“Git is a free software ...”,而后提交:
$ git add readme.txt $ git commit -m "fix bug 101" [issue-101 cc17032] fix bug 101 1 file changed, 1 insertion(+), 1 deletion(-)
修复完成后,切换到master
分支,并完成合并,最后删除issue-101
分支:
$ git checkout master Switched to branch 'master' Your branch is ahead of 'origin/master' by 2 commits. $ git merge --no-ff -m "merged bug fix 101" issue-101 Merge made by the 'recursive' strategy. readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) $ git branch -d issue-101 Deleted branch issue-101 (was cc17032).
原计划两个小时的bug修复只花了5分钟!如今,是时候接着回到dev
分支干活了!
$ git checkout dev Switched to branch 'dev' $ git status # On branch dev nothing to commit (working directory clean)
工做区是干净的,刚才的工做现场存到哪去了?用git stash list
命令看看:
$ git stash list
stash@{0}: WIP on dev: 6224937 add merge
工做现场还在,Git把stash内容存在某个地方了,可是须要恢复一下,有两个办法:
一是用git stash apply
恢复,可是恢复后,stash内容并不删除,你须要用git stash drop
来删除;
另外一种方式是用git stash pop
,恢复的同时把stash内容也删了
$ git stash pop # On branch dev # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # new file: hello.py # # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: readme.txt # Dropped refs/stash@{0} (f624f8e5f082f2df2bed8a4e09c12fd2943bdd40)
再用git stash list
查看,就看不到任何stash内容了:
$ git stash list
你能够屡次stash,恢复的时候,先用git stash list
查看,而后恢复指定的stash,用命令:
$ git stash apply stash@{0}
当你从远程仓库克隆时,实际上Git自动把本地的master
分支和远程的master
分支对应起来了,而且,远程仓库的默认名称是origin
。
要查看远程库的信息,用git remote
:
或者,用git remote -v
显示更详细的信息:
上面显示了能够抓取和推送的origin
的地址。若是没有推送权限,就看不到push的地址
13.1推送分支
推送分支,就是把该分支上的全部本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上:
$ git push origin master
若是要推送其余分支,好比dev
,就改为:
$ git push origin dev
可是,并非必定要把本地分支往远程推送,那么,哪些分支须要推送,哪些不须要呢?
master分支是主分支,所以要时刻与远程同步;
dev分支是开发分支,团队全部成员都须要在上面工做,因此也须要与远程同步;
bug分支只用于在本地修复bug,就不必推到远程了,除非老板要看看你每周到底修复了几个bug;
feature分支是否推到远程,取决于你是否和你的小伙伴合做在上面开发。
总之,就是在Git中,分支彻底能够在本地本身藏着玩,是否推送,由本身而定!
多人协做时,你们都会往master
和dev
分支上推送各自的修改。
如今,模拟一个你的小伙伴,能够在另外一台电脑(注意要把SSH Key添加到GitHub)或者同一台电脑的另外一个目录下克隆:
默认状况下,你的小伙伴只能看到本地的master
分支。不信能够用git branch
命令看看:
如今,你的小伙伴要在dev
分支上开发,就必须建立远程origin
的dev
分支到本地,因而他用这个命令建立本地dev
分支并在dev
上继续修改:
你的小伙伴已经向origin/dev分支推送了他的提交,而碰巧你也对一样的文件做了修改,并试图推送:
推送失败,由于你的小伙伴的最新提交和你试图推送的提交有冲突,解决办法也很简单,Git已经提示咱们,
先用git pull
把最新的提交从origin/dev
抓下来,而后,在本地合并,解决冲突,再推
git pull
也失败了,缘由是没有指定本地dev
分支与远程origin/dev
分支的连接,根据提示,设置dev
和origin/dev
的连接:
再pull:
这回git pull
成功,可是合并有冲突,须要手动解决,解决的方法和分支管理中的解决冲突彻底同样。解决后,提交,再push:
所以,多人协做的工做模式一般是这样:
首先,能够试图用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
。
这就是多人协做的工做模式,一旦熟悉了,就很是简单。
咱们一直用GitHub做为免费的远程仓库,若是是我的的开源项目,放到GitHub上是彻底没有问题的。其实GitHub仍是一个开源协做社区,经过GitHub,既可让别人参与你的开源项目,也能够参与别人的开源项目。
在GitHub上,利用Git极其强大的克隆和分支功能,IT人员真正能够第一次自由参与各类开源项目了。
如何参与一个开源项目呢?好比人气极高的bootstrap项目,这是一个很是强大的CSS框架,你能够访问它的项目主页https://github.com/twbs/bootstrap,点“Fork”就在本身的帐号下克隆了一个bootstrap仓库,而后,从本身的帐号下clone:
必定要从本身的帐号下clone仓库,这样你才能推送修改。若是从bootstrap的做者的仓库地址克隆
,由于没有权限,你将不能推送修改。
Bootstrap的官方仓库twbs/bootstrap
、你在GitHub上克隆的仓库my/bootstrap
,以及你本身克隆到本地电脑的仓库,他们的关系就像下图显示的那样:
若是你想修复bootstrap的一个bug,或者新增一个功能,马上就能够开始干活,干完后,往本身的仓库推送。
若是你但愿bootstrap的官方库能接受你的修改,你就能够在GitHub上发起一个pull request。固然,对方是否接受你的pull request就不必定了。
若是你没能力修改bootstrap,但又想要试一把pull request,那就Fork一下个人仓库 ,建立一个your-github-id.txt
的文本文件,写点本身学习Git的心得,而后推送一个pull request给我,我会视心情而定是否接受。
小结
在GitHub上,能够任意Fork开源仓库;
本身拥有Fork后的仓库的读写权限;
能够推送pull request给官方仓库来贡献代码。
有些时候,你必须把某些文件放到Git工做目录中,但又不能提交它们,好比保存了数据库密码的配置文件啦,等等,每次git status
都会显示Untracked files ...
,有强迫症的童鞋内心确定不爽。
好在Git考虑到了你们的感觉,这个问题解决起来也很简单,在Git工做区的根目录下建立一个特殊的.gitignore
文件,而后把要忽略的文件名填进去,Git就会自动忽略这些文件。
不须要从头写.gitignore
文件,GitHub已经为咱们准备了各类配置文件,只须要组合一下就能够使用了。全部配置文件能够直接在线浏览:https://github.com/github/gitignore
忽略文件的原则是:
.class
文件;举个例子:
假设你在Windows下进行Python开发,Windows会自动在有图片的目录下生成隐藏的缩略图文件,若是有自定义目录,目录下就会有Desktop.ini
文件,所以你须要忽略Windows自动生成的垃圾文件:
# Windows: Thumbs.db ehthumbs.db Desktop.ini
而后,继续忽略Python编译产生的.pyc
、.pyo
、dist
等文件或目录:
# Python: *.py[cod] *.so *.egg *.egg-info dist build
加上你本身定义的文件,最终获得一个完整的.gitignore
文件,内容以下:
# Windows: Thumbs.db ehthumbs.db Desktop.ini # Python: *.py[cod] *.so *.egg *.egg-info dist build # My configurations: db.ini deploy_key_rsa
最后一步就是把.gitignore
也提交到Git,就完成了!固然检验.gitignore
的标准是git status
命令是否是说working directory clean
。
使用Windows的童鞋注意了,若是你在资源管理器里新建一个.gitignore
文件,它会很是弱智地提示你必须输入文件名,可是在文本编辑器里“保存”或者“另存为”就能够把文件保存为.gitignore
了。
有些时候,你想添加一个文件到Git,但发现添加不了,缘由是这个文件被.gitignore
忽略了:
$ git add App.class The following paths are ignored by one of your .gitignore files: App.class Use -f if you really want to add them.
若是你确实想添加该文件,能够用-f
强制添加到Git:
$ git add -f App.class
或者你发现,多是.gitignore写得有问题,须要找出来到底哪一个规则写错了,能够用git check-ignore命令检查:
$ git check-ignore -v App.class .gitignore:3:*.class App.class
Git会告诉咱们,.gitignore
的第3行规则忽略了该文件,因而咱们就能够知道应该修订哪一个规则。
小结
忽略某些文件时,须要编写.gitignore
;
.gitignore
文件自己要放到版本库里,而且能够对.gitignore
作版本管理!