github入门
简介:
很多人都知道,Linus在1991年创建了开源的Linux,从此,Linux系统不断发展,已经成为最大的服务器系统软件了。
Linus虽然创建了Linux,但Linux的壮大是靠全世界热心的志愿者参与的,这么多人在世界各地为Linux编写代码,那Linux的代码是如何管理的呢?
事实是,在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管理了!牛是怎么定义的呢?大家可以体会一下。
Git迅速成为最流行的分布式版本控制系统,尤其是2008年,GitHub网站上线了(github是一个基于git的代码托管平台,付费用户可以建私人仓库,我们一般的免费用户只能使用公共仓库,也就是代码要公开。),它为开源项目免费提供Git存储,无数开源项目开始迁移至GitHub,包括jQuery,PHP,Ruby等等。
历史就是这么偶然,如果不是当年BitMover公司威胁Linux社区,可能现在我们就没有免费而超级好用的Git了。
今天,GitHub已是:
- 一个拥有143万开发者的社区。其中不乏Linux发明者Torvalds这样的*黑客,以及Rails创始人DHH这样的年轻极客。
- 这个星球上最流行的开源托管服务。目前已托管431万git项目,不仅越来越多知名开源项目迁入GitHub,比如Ruby on Rails、jQuery、Ruby、Erlang/OTP;近三年流行的开源库往往在GitHub首发,例如:BootStrap、Node.js、CoffeScript等。
- alexa全球排名414的网站。
1、密钥连接
首先申请github账号,由于你的本地Git仓库和GitHub仓库之间的传输是通过SSH加密的,所以,需要一点设置,在本地生成密钥对:
[root@localhost ~]# ssh-keygen -t rsa -C 'lianzhilei0711@163.com'
你需要把邮件地址换成你自己的邮件地址,然后一路回车,使用默认值即可,由于这个Key也不是用于军事目的,所以也无需设置密码。如果一切顺利的话,可以在用户主目录里找到.ssh目录,里面有id_rsa和id_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。
然后登陆GitHub,打开“Account settings”,“SSH Keys”页面。点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容:
2、创建仓库
首先,登陆GitHub,然后,在右上角找到“New repository”按钮,创建一个新的仓库:
点击创建后跳转到仓库:
3、远程仓库
① 目前,在GitHub上的这个spider仓库还是空的,GitHub告诉我们,可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到GitHub仓库,由于本地还从未进行过repository创建,所以先用第一种方式创建本地仓库,然后进行远程上传:
[root@localhost lzl]# mkdir spider
[root@localhost lzl]# cd spider
[root@localhost spider]# git init # 生成仓库
初始化空的 Git 版本库于 /lzl/spider/.git/
[root@localhost spider]# echo '# -spider' >>README.md # 创建文件
[root@localhost spider]# git add README.md
[root@localhost spider]# git commit -m 'first commit' # 提交
[master(根提交) 872c5e6] first commit
1 file changed, 1 insertion(+)
create mode 100644 README.md
[root@localhost spider]# git remote add origin git@github.com:jefreylian/-spider.git # 远程连接
[root@localhost spider]# git push -u origin master # 推送数据
The authenticity of host 'github.com (192.30.255.113)' can't be established.
RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'github.com,192.30.255.113' (RSA) to the list of known hosts.
Counting objects: 3, done.
Writing objects: 100% (3/3), 217 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:jefreylian/-spider.git
* [new branch] master -> master
分支 master 设置为跟踪来自 origin 的远程分支 master。 # 推送成功
此时刷新github下spider仓库,可以看到新上传的README.md文件已经上传
② 刚刚是先有本地库,后有远程库的时候,如何关联远程库。现在要做的是如何把远程库克隆到本地,然后再进行其他操作:
在本地找一个你想存放这个远程仓库的目录,然后在本地命令行用git clone 命令来克隆这个远程库
[root@localhost project]# git clone git@github.com:jefreylian/spider.git
正克隆到 '-spider'...
remote: Counting objects: 9, done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 9 (delta 0), reused 9 (delta 0), pack-reused 0
接收对象中: 100% (9/9), done. [root@localhost project]# cd spider/
[root@localhost spider]# ll
总用量 8
-rw-r--r-- 1 root root 27 7月 5 15:51 index.html
-rw-r--r-- 1 root root 10 7月 5 15:51 README.md
如果有多个人协作开发,那么每个人各自从远程克隆一份就可以了。
你也许还注意到,GitHub给出的地址不止一个,还可以用https://github.com/jefrey/spider.git 这样的地址。实际上,Git支持多种协议,默认的git://
使用ssh,但也可以使用https
等其他协议。
使用https
除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh
协议而只能用https
。
git精通
前言:
因为最初是从Linux起家的,非常依赖文件系统的一些特性,这些在 Linux 下表现的很好,而 Windows 下特别糟糕Git 中文教程
Git是一个开源的分布式版本控制系统,用以有效、高速的处理从很小到非常大的项目版本管理.
Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。
Torvalds 开始着手开发 Git 是为了作为一种过渡方案来替代 BitKeeper,后者之前一直是 Linux 内核开发人员在全球使用的主要源代码工具。开放源码社区中的有些人觉得 BitKeeper 的许可证并不适合开放源码社区的工作,因此 Torvalds 决定着手研究许可证更为灵活的版本控制系统。尽管最初 Git 的开发是为了辅助 Linux 内核开发的过程,但是我们已经发现在很多其他*软件项目中也使用了 Git。例如 最近就迁移到 Git 上来了,很多 Freedesktop 的项目也迁移到了 Git 上。
1、安装git:
最早Git是在Linux上开发的,很长一段时间内,Git也只能在Linux和Unix系统上跑。不过,慢慢地有人把它移植到了Windows上。现在,Git可以在Linux、Unix、Mac和Windows这几大平台上正常运行了。
linux系统下,你可以试着输入git
,看看系统有没有安装Git:
[root@localhost lzl]# git
The program 'git' is currently not installed. You can install it by typing:
sudo apt-get install git
像上面的命令,有很多Linux会友好地告诉你Git没有安装,还会告诉你如何安装Git。
如果你碰巧用Debian或Ubuntu Linux,通过一条sudo apt-get install git
就可以直接完成Git的安装,非常简单。
2、远程上传:
[root@localhost project]# git clone git@github.com:jefreylian/spider.git
[root@localhost project]# cd spider/
[root@localhost spider]# echo '#create new file' > new.py # 创建新文件
[root@localhost spider]# git status # 查看状态
# 位于分支 master
# 未跟踪的文件:
# (使用 "git add <file>..." 以包含要提交的内容)
#
# new.py
提交为空,但是存在尚未跟踪的文件(使用 "git add" 建立跟踪)
[root@localhost spider]# git add new.py # 文件由工作区提交到暂存区
[root@localhost spider]# git commit -m 'first commit' # 加提交标识
[root@localhost spider]# git push -u origin master # 把代码提交到仓库
补充:
[root@localhost spider]# git add new.py # 添加new.py
[root@localhost spider]# git add . # 添加所有
[root@localhost spider]# git config --global user.email "lianzhilei0711@163.com" # 更改log显示名
[root@localhost spider]# git config --global user.name 'Jefrey'
[root@localhost spider]# vim .git/config # 查看本地git设置
3、工作区和暂存区
Git和其他版本控制系统如SVN的一个不同之处就是有暂存区的概念。
先来看名词解释。
工作区(Working Directory)
就是你在电脑里能看到的目录,比如我的spider文件夹就是一个工作区:
[root@localhost spider]# ll
drwxr-xr-x 2 root root 20 7月 5 17:09 conf
-rw-r--r-- 1 root root 27 7月 5 15:51 index.html
-rw-r--r-- 1 root root 44 7月 5 17:31 new.py
-rw-r--r-- 1 root root 23 7月 5 15:57 README.md
版本库(Repository)
工作区有一个隐藏目录.git
,这个不算工作区,而是Git的版本库。
Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master
,以及指向master
的一个指针叫HEAD
。
分支和HEAD
的概念我们以后再讲。
前面讲了我们把文件往Git版本库里添加的时候,是分两步执行的:
第一步是用git add
把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用git commit
提交更改,实际上就是把暂存区的所有内容提交到当前分支。
因为我们创建Git版本库时,Git自动为我们创建了唯一一个master
分支,所以,现在,git commit
就是往master
分支上提交更改。
你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
4、本地回滚
现在,你已经学会了修改文件,然后把修改提交到Git版本库,假如要恢复到之前的代码也就是回滚,如何操作:
[root@localhost spider]# git log # 查看提交记录
commit 1560f36d2ebb48a47c7db12cd0aedf88e3d2a0f9
Author: Jefrey <lianzhilei0711@163.com>
Date: Wed Jul 5 16:43:16 2017 +0800
conf commit
commit 81a32a17078f92d290ea29a7bbc928e1b30bf501
Author: Jefrey <lianzhilei0711@163.com>
Date: Wed Jul 5 16:34:08 2017 +0800
third commit
commit 40ac1cff6d9bc827c1c3d8dac2b3aa838e4dfe70
Author: lianzl <lianzl@commchina.net>
Date: Wed Jul 5 16:29:56 2017 +0800
second commit
commit daf94f4cf0919b0fbc86b4a0318568a19bceb307
Author: lianzl <lianzl@commchina.net>
Date: Wed Jul 5 16:18:54 2017 +0800
first commit
git log命令显示从最近到最远的提交日志,我们可以看到4次提交,最近的一次是conf commit,上一次是third commit,最早的一次是first commit。 如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline
参数
[root@localhost spider]# git log --pretty=oneline
1560f36d2ebb48a47c7db12cd0aedf88e3d2a0f9 conf commit
81a32a17078f92d290ea29a7bbc928e1b30bf501 third commit
40ac1cff6d9bc827c1c3d8dac2b3aa838e4dfe70 second commit
daf94f4cf0919b0fbc86b4a0318568a19bceb307 first commit
① 回滚到上一次提交的代码:
[root@localhost spider]# git reset --hard HEAD^
HEAD 现在位于 81a32a1 third commit
[root@localhost spider]# git log --pretty=oneline
81a32a17078f92d290ea29a7bbc928e1b30bf501 third commit
40ac1cff6d9bc827c1c3d8dac2b3aa838e4dfe70 second commit
daf94f4cf0919b0fbc86b4a0318568a19bceb307 first commit
查看文件,发现现在已经回滚到上一次提交代码的状态
② 回滚到指定版本代码:
[root@localhost spider]# git reset --hard 40ac1cff # 指定前7位即可
HEAD 现在位于 40ac1cf second commit
[root@localhost spider]# git log --pretty=oneline
40ac1cff6d9bc827c1c3d8dac2b3aa838e4dfe70 second commit
daf94f4cf0919b0fbc86b4a0318568a19bceb307 first commit
现在,你回退到了某个版本,关掉了电脑,第二天早上就后悔了,想恢复到新版本怎么办?找不到新版本的commit id怎么办?
在Git中,总是有后悔药可以吃的。当你用$ git reset --hard HEAD^回退到third commit版本时,再想恢复到最新conf commit的版本,就必须找到conf commit的commit id。Git提供了一个命令git reflog用来记录你的每一次命令:
[root@localhost spider]# git reflog
40ac1cf HEAD@{0}: reset: moving to 40ac1cff
81a32a1 HEAD@{1}: reset: moving to HEAD^
1560f36 HEAD@{2}: commit: conf commit
81a32a1 HEAD@{3}: commit: third commit
40ac1cf HEAD@{4}: commit: second commit
daf94f4 HEAD@{5}: commit: first commit
[root@localhost spider]# git reset --hard 1560f36 # 指定最新提交代码id
HEAD 现在位于 1560f36 conf commit
[root@localhost spider]# git log --pretty=oneline # 恢复如初
1560f36d2ebb48a47c7db12cd0aedf88e3d2a0f9 conf commit
81a32a17078f92d290ea29a7bbc928e1b30bf501 third commit
40ac1cff6d9bc827c1c3d8dac2b3aa838e4dfe70 second commit
daf94f4cf0919b0fbc86b4a0318568a19bceb307 first commit
注:切记是本地代码回滚,不会影响到github上的仓库内容
5、撤销修改
① 未提交到暂存区撤销
假如现在在new.py文件中添加了两行代码:
#create new file
second commit
third commit
git is great
but my stupid boss still prefers SVN.
在你准备提交前,一杯咖啡起了作用,你猛然发现了“stupid boss”可能会让你丢掉这个月的奖金!
此时用git status
查看一下:
[root@localhost spider]# git status
# 位于分支 master
# 尚未暂存以备提交的变更:
# (使用 "git add <file>..." 更新要提交的内容)
# (使用 "git checkout -- <file>..." 丢弃工作区的改动)
#
# 修改: new.py
#
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
你可以发现,Git会告诉你,git checkout -- file
可以丢弃工作区的修改:
[root@localhost spider]# git checkout -- new.py
[root@localhost spider]# more new.py
#create new file
second commit
third commit
好了,一切恢复如初,文件中修改的内容全部清除;new.py文件修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态
-
new.py
自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态; - new.py已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态;
② 已经提交到暂存区的文件撤销
不但修改了代码,而且还add存放到缓存区了:
[root@localhost spider]# more new.py
#create new file
second commit
third commit
Git tracks changes of files.
My stupid boss still prefers SVN.
[root@localhost spider]# git add new.py
庆幸的是,在commit
之前,你发现了这个问题。用git status
查看一下,修改只是添加到了暂存区,还没有提交:
[root@localhost spider]# git status
# 位于分支 master
# 要提交的变更:
# (使用 "git reset HEAD <file>..." 撤出暂存区)
#
# 修改: new.py
Git同样告诉我们,用命令git reset HEAD file
可以把暂存区的修改撤销掉(unstage),重新放回工作区:
[root@localhost spider]# git reset HEAD new.py
重置后撤出暂存区的变更:
M new.py
[root@localhost spider]# git status
# 位于分支 master
# 尚未暂存以备提交的变更:
# (使用 "git add <file>..." 更新要提交的内容)
# (使用 "git checkout -- <file>..." 丢弃工作区的改动)
#
# 修改: new.py
#
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
再次执行git checkout -- <file>,恢复到最初:
[root@localhost spider]# git checkout -- new.py
[root@localhost spider]# git status
# 位于分支 master
无文件要提交,干净的工作区
注:这里所有的撤销都是指代码未提交到仓库时的撤销
6、删除操作
在Git中,删除也是一个修改操作,我们实战一下,先添加一个新文件test.txt到Git并且提交:
$ git add .
$ git commit -m "add test.txt"
[master a8fa95a] add test.txt
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test.txt
一般情况下,你通常直接在文件管理器中把没用的文件删了,或者用rm
命令删了
[root@localhost spider]# rm test.txt
这个时候,Git知道你删除了文件,因此,工作区和版本库就不一致了,git status
命令会立刻告诉你哪些文件被删除了:
$ 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: test.txt no changes added to commit (use "git add" and/or "git commit -a")
现在你有两个选择,一是确实要从版本库中删除该文件,那就用命令git rm
删掉,并且git commit
:
x$ git rm test.txt
rm 'test.txt' $ git commit -m "remove test"
[master 03df00a] remove test
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 test.txt
现在,文件就从版本库中被删除了。
另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:
[root@localhost spider]# git checkout -- test.txt
git checkout
其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。
7、删除远程文件
假如远程文件index.html是多余文件,需要把他删除,如何做?
# 先把本地文件进行删除,查看git状态
[root@localhost spider]# rm index.html
rm:是否删除普通文件 "index.html"?y
[root@localhost spider]# git status
# 位于分支 master
# 尚未暂存以备提交的变更:
# (使用 "git add/rm <file>..." 更新要提交的内容)
# (使用 "git checkout -- <file>..." 丢弃工作区的改动)
#
# 删除: index.html
#
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
用git rm清除刚刚删除的文件,上传更新:
[root@localhost spider]# git rm index.html
rm 'index.html'
[root@localhost spider]# git commit -m 'rm index.html'
[master c54c7fe] rm index.html
1 file changed, 2 deletions(-)
delete mode 100644 index.html
[root@localhost spider]# git push -u origin master
bbaa116..99c5dfe master -> master
查看远程代码库,文件index.html文件已经删除
8、忽略文件
有些时候,你必须把某些文件放到Git工作目录中,但又不能提交它们,比如保存了数据库密码的配置文件啦,等等,每次git status
都会显示Untracked files ...
,有强迫症的童鞋心里肯定不爽。好在Git考虑到了大家的感受,这个问题解决起来也很简单,在Git工作区的根目录下创建一个特殊的.gitignore
文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件。不需要从头写.gitignore
文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore
忽略文件的原则是:
- 忽略操作系统自动生成的文件,比如缩略图等;
- 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的
.class
文件; - 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件;
编写忽略文件.gitignore:
# Python:
*.py[cod]
*.so
*.egg
*.egg-info
dist
build
编写new.pyc文件及func.py文件:
[root@localhost spider]# echo 'sssssss' >new.pyc
[root@localhost spider]# echo 'new file' >func.py # 查看此时status
[root@localhost spider]# git status
# 位于分支 master
# 未跟踪的文件:
# (使用 "git add <file>..." 以包含要提交的内容)
#
# .gitignore
# func.py
提交为空,但是存在尚未跟踪的文件(使用 "git add" 建立跟踪)
上传新增文件,.gitignore会被提交到git上去,new.pyc会被过滤掉,不会进行上传
如果你确实想添加该文件,可以用-f
强制添加到Git:
[root@localhost spider]# git add -f new.pyc
[root@localhost spider]# git status
# 位于分支 master
# 要提交的变更:
# (使用 "git reset HEAD <file>..." 撤出暂存区)
#
# 新文件: new.pyc
或者你发现,可能是.gitignore
写得有问题,需要找出来到底哪个规则写错了,可以用git check-ignore
命令检查:
[root@localhost spider]# git check-ignore -v new.pyc
.gitignore:2:*.py[cod] new.pyc
Git会告诉我们,.gitignore
的第2行规则忽略了该文件,于是我们就可以知道应该修订哪个规则。
小结
忽略某些文件时,需要编写
.gitignore
;.gitignore
文件本身要放到版本库里,并且可以对.gitignore
做版本管理!
9、强制覆盖本地代码
[root@localhost spider]# git reset --hard origin/master
HEAD 现在位于 3d64925 gitignore
分支
分支在实际中有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。
现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。
其他版本控制系统如SVN等都有分支管理,但是用过之后你会发现,这些版本控制系统创建和切换分支比蜗牛还慢,简直让人无法忍受,结果分支功能成了摆设,大家都不去用。
但Git的分支是与众不同的,无论创建、切换和删除分支,Git在1秒钟之内就能完成!无论你的版本库是1个文件还是1万个文件。
1、创建与合并分支
首先,我们创建dev
分支,然后切换到dev
分支:
[root@localhost spider]# git checkout -b dev
切换到一个新分支 'dev'
git checkout
命令加上-b
参数表示创建并切换,相当于以下两条命令:
[root@localhost spider]# git branch dev
[root@localhost spider]# git checkout dev
切换到一个新分支 'dev'
然后,用git branch
命令查看当前分支:
[root@localhost spider]# git branch
* dev
master
然后,我们就可以在dev
分支上正常提交,比如对readme.txt做个修改,加上一行:
[root@localhost spider]# echo 'create a new branch' >> README.md
然后提交,在远程端生成dev分支:
[root@localhost spider]# git add README.md
[root@localhost spider]# git commit -m 'branch first'
[root@localhost spider]# git push -u origin dev
现在,dev
分支的工作完成,我们就可以切换回master
分支:
master
[root@localhost spider]# git checkout master
切换到分支 'master'
[root@localhost spider]# git branch
dev
* master
切换回master
分支后,再查看一个readme.txt文件,刚才添加的内容不见了!因为那个提交是在dev
分支上,而master
分支此刻的提交点并没有变:
现在,我们把dev
分支的工作成果合并到master
分支上:
[root@localhost spider]# git merge dev
更新 3d64925..fbbba8c
Fast-forward
README.md | 1 +
1 file changed, 1 insertion(+)
git merge
命令用于合并指定分支到当前分支。合并后,再查看readme.txt的内容,就可以看到,和dev
分支的最新提交是完全一样的。
注意到上面的Fast-forward
信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master
指向dev
的当前提交,所以合并速度非常快。
当然,也不是每次合并都能Fast-forward
,我们后面会讲其他方式的合并。
合并完成后,就可以放心地删除dev
分支了:
[root@localhost spider]# git branch -d dev
已删除分支 dev(曾为 fbbba8c)。
[root@localhost spider]# git branch
* master
因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master
分支上工作效果是一样的,但过程更安全。
之前dev已经上传到远程仓库,但是本地已经删除了,怎么把远程端代码再拷贝到本地,so easy:
[root@localhost spider]# git checkout dev
分支 dev 设置为跟踪来自 origin 的远程分支 dev。
切换到一个新分支 'dev'
[root@localhost spider]# git branch
* dev
master
自动连接远程分支代码,如果远程仓库dev有代码更新,git pull 更新本地代码
2、解决冲突
人生不如意之事十之八九,合并分支往往也不是一帆风顺的。
准备新的feature1
分支,继续我们的新分支开发:
[root@localhost spider]# git checkout -b feature
切换到一个新分支 'feature'
修改README.md最后一行,改为:
[root@localhost spider]# echo 'added this line from branch feature' >> README.md
在feature
分支上提交:
[root@localhost spider]# git add README.md
[root@localhost spider]# git commit -m 'add feature'
[feature 8880f27] add feature
* [new branch] feature -> feature
分支 feature 设置为跟踪来自 origin 的远程分支 feature。
切换到master
分支:
[root@localhost spider]# git checkout master
切换到分支 'master'
您的分支领先 'origin/master' 共 2 个提交。
(使用 "git push" 来发布您的本地提交)
Git还会自动提示我们当前master
分支比远程的master
分支要超前1个提交。
在master
分支上把README.md文件的最后一行改为:
[root@localhost spider]# echo 'added this line from master' >> README.md
提交上传仓库:
[root@localhost spider]# git add README.md
[root@localhost spider]# git commit -m 'mASTER UPDATE'
[master d735926] mASTER UPDATE
1 file changed, 1 insertion(+)
e886050..d735926 master -> master
现在,master
分支和feature1
分支各自都分别有新的提交,变成了这样:
这种情况下,Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突,我们试试看:
[root@localhost spider]# git merge feature
error: 'merge' is not possible because you have unmerged files.
提示:请先在工作区改正文件,然后酌情使用
提示:'git add/rm <file>' 标记解决方案,
提示:或使用 'git commit -a'。
fatal: Exiting because of an unresolved conflict
果然冲突了!Git告诉我们,readme.txt文件存在冲突,必须手动解决冲突后再提交。git status
也可以告诉我们冲突的文件:
[root@localhost spider]# git branch
dev
feature
* master
[root@localhost spider]# git status
# 位于分支 master
# 您有尚未合并的路径。
# (解决冲突并运行 "git commit")
#
# 未合并的路径:
# (使用 "git add <file>..." 标记解决方案)
#
# 双方修改: README.md
#
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
我们可以直接查看README.md的内容:
# spider forth commit
create a new branch
<<<<<<< HEAD
added this line from master
=======
added this line from branch feature
>>>>>>> feature
Git用<<<<<<<
,=======
,>>>>>>>
标记出不同分支的内容,我们修改如下后保存:
# spider forth commit
create a new branch
added this line from master
added this line from branch feature
再次提交:
[root@localhost spider]# git add README.md
[root@localhost spider]# git commit -m 'conflict fixed'
[master 92fe979] conflict fixed
[root@localhost spider]# git push -u origin master
d735926..92fe979 master -> master
分支 master 设置为跟踪来自 origin 的远程分支 master。
现在,master
分支和feature
分支变成了下图所示:
用带参数的git log
也可以看到分支的合并情况:
[root@localhost spider]# git log --graph --pretty=oneline
* 92fe979409a534673f7f35c3613f65dcd8e9660b conflict fixed
|\
| * 8880f27f77477481232ab28fd1fe42cc87c33683 add feature
* | d73592620ebd7d368e0c4d7293ff228386fd243a mASTER UPDATE
|/
* 9182888e813b69bf08f9eff5cd899b6a07861507 Merge branch 'dev'
|\
| * 5a4ba4248b1b4982d48e570b1038c995e1e75ef0 Update README.md
* | e8860504de4b2975055943a353f6267d75984504 branch dev second
|/
* fbbba8c24902b2c4e52e693dc7503b400012fe76 branch first
* 3d649257c8778c5a40f52cfad9a6acfbc59d26dc gitignore
* 1560f36d2ebb48a47c7db12cd0aedf88e3d2a0f9 conf commit
* 81a32a17078f92d290ea29a7bbc928e1b30bf501 third commit
* 40ac1cff6d9bc827c1c3d8dac2b3aa838e4dfe70 second commit
* daf94f4cf0919b0fbc86b4a0318568a19bceb307 first commit
3、存储代码:
当前正在dev
上进行的工作还没有提交,你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101
来修复它;此时并不是你不想提交,而是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?
幸好,Git还提供了一个stash
功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:
[root@localhost spider]# echo 'create stash file' >> README.md
[root@localhost spider]# git stash
Saved working directory and index state WIP on dev: 5a4ba42 Update README.md
HEAD 现在位于 5a4ba42 Update README.md
[root@localhost spider]# git status
# 位于分支 dev
无文件要提交,干净的工作区
现在,用git status
查看工作区,就是干净的(除非有没有被Git管理的文件),因此可以放心地创建分支来修复bug。
首先确定要在哪个分支上修复bug,假定需要在master
分支上修复,就从master
创建临时分支:
[root@localhost spider]# git checkout master
[root@localhost spider]# git checkout -b issue-101
[root@localhost spider]# echo 'fixed bug' >> README.md
[root@localhost spider]# git add README.md
[root@localhost spider]# git commit -m 'fixed bug 101'
[issue-101 80feda6] fixed bug 101
1 file changed, 1 insertion(+)
[root@localhost spider]# git push -u origin master
修复完成后,切换到master
分支,并完成合并,最后删除issue-101
分支:
[root@localhost spider]# git checkout master
[root@localhost spider]# git merge issue-101
[root@localhost spider]# git branch -d issue-101
太棒了,原计划两个小时的bug修复只花了5分钟!现在,是时候接着回到dev
分支干活了!用git stash list
命令看看:
[root@localhost spider]# git checkout dev
切换到分支 'dev'
[root@localhost spider]# git status
# 位于分支 dev
无文件要提交,干净的工作区
[root@localhost spider]# git stash list
stash@{0}: WIP on dev: 5a4ba42 Update README.md
工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:
一是用git stash apply
恢复,但是恢复后,stash内容并不删除,你需要用git stash drop
来删除;另一种方式是用git stash pop
,恢复的同时把stash内容也删了;
[root@localhost spider]# git stash pop
# 位于分支 dev
# 尚未暂存以备提交的变更:
# (使用 "git add <file>..." 更新要提交的内容)
# (使用 "git checkout -- <file>..." 丢弃工作区的改动)
#
# 修改: README.md
#
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
丢弃了 refs/stash@{0} (601f28699d51d05c9eec7d15ebaa8698287c3105)
再用git stash list
查看,就看不到任何stash内容了:
[root@localhost spider]# git stash list
你可以多次stash,恢复的时候,先用git stash list
查看,然后恢复指定的stash,用命令:
[root@localhost spider]# git stash apply stash@{0}