创建工作分枝,合并分枝以及删除分枝
1. 合并和删除分支
1. 创建一个新的分枝;
2.在这个分枝上做一些工作;
3.切换回稳定的主分枝(一般git默认的主分枝名叫master);
4.在主分枝上再做点工作;
5.再切换到刚那个临时分枝完成工作;
6.最后将它们合并成为一个稳定的主分枝。
首先,查看现存的分枝,可以使用不带任何参数的'git branch'命令。
$ git branch
* master
* master
可以看到,我们现在只有一个分枝叫做'master',*代表的意思是我们正在这个主分枝上工作。下图是在主分支上的提交历史模型,绿框表示提交,箭头指向的是它的父节点。这就是git提交数据的方式。
从图中可以看出,在git中,分枝都是由一些具体的提交点组成。整个分枝的历史都是这样串联起来的,一次只有一个提交点。
创建新的分枝
可以用'git branch (branchname)'命令在当前分枝上创建一个新的分枝:
$ git branch experiment
为了将我们的工作保存到experiment分枝而不是master分枝上,我们需要切换到experiment分枝上,执行'git checkout'命令:
$ git checkout experiment
Switched to branch "experiment"
$ git branch
* experiment
master
Switched to branch "experiment"
$ git branch
* experiment
master
执行完毕后,我们就切换到了新的分枝(experiment)分枝上,看到experiment前面有了*号了。现在,我们修改文件、提交就不用再担心跟master分枝混在一起了。也没必要在我们确定一切搞定之前,将experiment分枝上的变更共享了。
在多分枝上进行工作
现在,让我们添加一个TODO文件,并修改simplegit.rb文件,然后将这些变更都提交。
$ vim lib/simplegit.rb
$ vim TODO
$ git add TODO
$ git commit -am 'added a todo and added simplegit functions'
[experiment]: created 4682c32: "added a todo and added simplegit functions"
2 files changed, 10 insertions(+), 0 deletions(-)
create mode 100644 TODO
$ vim TODO
$ git add TODO
$ git commit -am 'added a todo and added simplegit functions'
[experiment]: created 4682c32: "added a todo and added simplegit functions"
2 files changed, 10 insertions(+), 0 deletions(-)
create mode 100644 TODO
现在,我们来看一下,整个项目中有3个文件和一个子目录。
$ ls
README Rakefile TODO lib
README Rakefile TODO lib
然后,我们假设需要回到原始版本来调试simplegit.rb文件。
$ git checkout master
Switched to branch "master"
$ ls
README Rakefile lib
Switched to branch "master"
$ ls
README Rakefile lib
可以看到我们已经回到了master分枝,工作目录中也没有TODO文件,这是因为master分枝上我们就没有创建过这个文件。
如果现在我们再切换到experiment分枝,我们又会看到TODO文件,并且simplegit.rb也是我们在experiment修改后的内容。
下面这段代码是在master分枝上修改simplegit.rb文件,在文件内添加一个commit function.提交,然后再切换到experiment分枝。
$ vim lib/simplegit.rb
$ git commit -am 'added a commit function'
[master]: created 0b7434d: "added a commit function"
1 files changed, 4 insertions(+), 0 deletions(-)
$ git checkout experiment
Switched to branch "experiment"
$ ls
README Rakefile TODO lib
$ git commit -am 'added a commit function'
[master]: created 0b7434d: "added a commit function"
1 files changed, 4 insertions(+), 0 deletions(-)
$ git checkout experiment
Switched to branch "experiment"
$ ls
README Rakefile TODO lib
很多使用git的开发者通常会同时拥有很多个分枝,每一个分枝上都会进行着某个具体功能的开发,这些开发可能持续几分钟、几小时,也可能长时间的在某个分枝上进行大规模重构的工作,并定期的将其合并到主分枝上。
如果你需要在一个长期工作的分支上与其他开发者进行协作,你可以将这个分枝上传到共享服务器端。譬如,如果你想跟某人共享experiment分枝,你可以这样:
$ git push origin experiment
让你的合作伙伴同步这个分枝,然后与你协同工作。当然你也可以自己保留这些分枝作为自己的工作分枝--不用上传就可以了。
合并和移除无用分枝
当你在一个分枝上完成你的工作了,这时,如果你觉得所做的工作没什么意义,那么你可以忽略它并且将其移除;相反,你应该将这些工作合并到一个你会长期使用的分枝中(一般来说,开发者会用'master'分枝来存放稳定的代码,并行的'develop'分枝用来整合或测试变更的内容,或者将一些短期的分枝合并进来)。
合并分枝的方法:首先切换到想要合并到的分枝下,运行'git merge'命令,(例如本例中将experiment分枝合并到master分枝的话,进入master分枝运行git merge experiment命令)如果合并顺利的话:
$ git merge experiment
Auto-merging lib/simplegit.rb
Merge made by recursive.
lib/simplegit.rb | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
Auto-merging lib/simplegit.rb
Merge made by recursive.
lib/simplegit.rb | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
合并冲突处理
然而,有时候合并并不一定会顺利进行,如果碰到了问题,就会出现下面这些内容:
$ git merge experiment
Auto-merging lib/simplegit.rb
CONFLICT (content): Merge conflict in lib/simplegit.rb
Automatic merge failed; fix conflicts and then commit the result.
Auto-merging lib/simplegit.rb
CONFLICT (content): Merge conflict in lib/simplegit.rb
Automatic merge failed; fix conflicts and then commit the result.
这种情形下,提示合并冲突,你可以通过下面的方式来解决:打开提示冲突的文件,会看到冲突标记:
<<<<<<< HEAD:lib/simplegit.rb
def commit(message)
command("git commit -m '#{message}'")
=======
def add(path)
command("git add #{path}")
>>>>>>> experiment:lib/simplegit.rb
end
def commit(message)
command("git commit -m '#{message}'")
=======
def add(path)
command("git add #{path}")
>>>>>>> experiment:lib/simplegit.rb
end
修改完成之后,运行'git add'重新载入(re-stage)这个文件,然后合并:
$ git add lib/simplegit.rb
$ git commit
[master]: created 6d52a27: "Merge branch 'experiment'"
$ git commit
[master]: created 6d52a27: "Merge branch 'experiment'"
多次合并
这个问题之所以重要是因为在其他的VCS工具中多次合并实现起来是很麻烦的,但是用git,很容易解决。合并一个分枝之后,再继续在这个分枝上工作,然后再合并。这种情形一般是这样的:如果你有一个'development'分枝,你正在进行集成测试、合并实验中的变更,然后定期的将其合并到稳定的'master'分枝中。
用我们正在进行的例子来讲,假如我们现在又切换到'experiment'分枝,做点小小的改动,然后再将其合并到'master'分枝中,整个的过程大致是这样:
因为git合并是基于提交历史的快照,所以多次合并显得so easy。当你在一个分枝上做完你的工作之后,譬如例子中的'experiment'分枝,那么我们只需使用'git branch -d'命令即可删除此分枝
$ git branch -d experiment
如果分枝还没有被合并,那么执行这个命令就会将分枝上所做的工作一并删除,git是不允许你这么干的。如果你实在想删除的话,那么使用'-D'参数强行删除吧。
这就是git中分枝和合并的所有内容。
2. git 中的标签
创建有签名,无签名、轻量级标签来永久的标记项目历史中的关键点
跟大多数的VCS工具一样,git也有在历史状态的关键点“贴标签”的功能--一般人们用这个功能来标记发布点(例如'v1.0')。这节课我们学习如何使用标签列表,创建新标签,以及在git中有哪些不同类别的标签。
列出git中现有标签
要想列出git中现有的所有标签,输入'git tag'命令运行即可:
$ git tag
v0.1
v1.3
v0.1
v1.3
这个列表是按照字母表顺序给出的,其实排名先后跟重要程度没有直接联系。
当然,你也可以按照特定表达式搜索某些标签。假如在一个git仓库中有超过240个标签,而你只想得到1.4.2序列的标签,那么你可以:
$ git tag -l v1.4.2.*
v1.4.2.1
v1.4.2.2
v1.4.2.3
v1.4.2.4
v1.4.2.1
v1.4.2.2
v1.4.2.3
v1.4.2.4
创建标签
在git中有两种最主要的标签--轻量级标签(lightweight)和带注释的标签(annotated)。轻量级标签跟分枝一样,不会改变--它就是针对某个特定提交的指针。然而,带注释的标签是git仓库中的对象。它是一组校验和,包含标签名、email、日期,标签信息,GPG签名和验证。一般情况下,建议创建带注释的标签,这样就会保留这些信息,但是如果你只是需要临时性标签或者某些原因你不想在标签中附带上面说的这些信息,lightweight标签更合适些。
带注释的标签
在git中创建带注释的标签非常简单,在运行'tag'命令时加上-a就可以了。
$ git tag -a v1.4 -m 'version 1.4'
$ git tag
v0.1
v1.3
v1.4
$ git tag
v0.1
v1.3
v1.4
'-m'指明标签信息,跟标签一起存储。如果你不使用-m指明标签信息,git会自动启动文本编辑器让你输入。
可以使用 git show 命令查看相应标签的版本信息,并连同显示打标签时的提交对象。
$ git show v1.4
tag v1.4
Tagger: Scott Chacon <schacon@gmail.com>
Date: Mon Feb 9 14:45:11 2009 -0800
tag v1.4
Tagger: Scott Chacon <schacon@gmail.com>
Date: Mon Feb 9 14:45:11 2009 -0800
my version 1.4
commit 15027957951b64cf874c3557a0f3547bd83b3ff6
Merge: 4a447f7... a6b4c97...
Author: Scott Chacon <schacon@gmail.com>
Date: Sun Feb 8 19:02:46 2009 -0800
commit 15027957951b64cf874c3557a0f3547bd83b3ff6
Merge: 4a447f7... a6b4c97...
Author: Scott Chacon <schacon@gmail.com>
Date: Sun Feb 8 19:02:46 2009 -0800
Merge branch 'experiment'
我们可以看到,在提交对象信息上面,列出了此标签的提交者和提交时间,以及相应的标签信息。
有签名的标签
如果你有GPG私钥的话,你也可以用GPG来给你的标签签名,把-a换成-s就可以了:
[master]$ git tag -s v1.5 -m 'my signed 1.5 tag'
You need a passphrase to unlock the secret key for
user: "Scott Chacon <schacon@gmail.com>"
1024-bit DSA key, ID F721C45A, created 2009-02-09
user: "Scott Chacon <schacon@gmail.com>"
1024-bit DSA key, ID F721C45A, created 2009-02-09
然后,如果你对某个标签运行'git show'的话,你就会看到你的GPG前面附加上去了。
[master]$ git show v1.5
tag v1.5
Tagger: Scott Chacon <schacon@gmail.com>
Date: Mon Feb 9 15:22:20 2009 -0800
tag v1.5
Tagger: Scott Chacon <schacon@gmail.com>
Date: Mon Feb 9 15:22:20 2009 -0800
my signed 1.5 tag
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (Darwin)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (Darwin)
iEYEABECAAYFAkmQurIACgkQON3DxfchxFr5cACeIMN+ZxLKggJQf0QYiQBwgySN
Ki0An2JeAVUCAiJ7Ox6ZEtK+NvZAj82/
=WryJ
-----END PGP SIGNATURE-----
commit 15027957951b64cf874c3557a0f3547bd83b3ff6
Merge: 4a447f7... a6b4c97...
Author: Scott Chacon <schacon@gmail.com>
Date: Sun Feb 8 19:02:46 2009 -0800
Ki0An2JeAVUCAiJ7Ox6ZEtK+NvZAj82/
=WryJ
-----END PGP SIGNATURE-----
commit 15027957951b64cf874c3557a0f3547bd83b3ff6
Merge: 4a447f7... a6b4c97...
Author: Scott Chacon <schacon@gmail.com>
Date: Sun Feb 8 19:02:46 2009 -0800
Merge branch 'experiment'
稍后,我们会介绍如何验证签名标签。
轻量级标签
轻量级标签实际上就是存在一个文件中的提交校验和--没有附加任何其他信息。创建轻量级标签的方法就是把上面'-a','-s','-m'这些选项都去掉。
$ git tag v1.4-lw
$ git tag
v0.1
v1.3
v1.4
v1.4-lw
v1.5
$ git tag
v0.1
v1.3
v1.4
v1.4-lw
v1.5
如果现在对这个标签使用'git show'命令,不会看到像上面那种标签显示的那么多内容,仅仅显示这次提交的有关信息。
$ git show v1.4-lw
commit 15027957951b64cf874c3557a0f3547bd83b3ff6
Merge: 4a447f7... a6b4c97...
Author: Scott Chacon <schacon@gmail.com>
Date: Sun Feb 8 19:02:46 2009 -0800
commit 15027957951b64cf874c3557a0f3547bd83b3ff6
Merge: 4a447f7... a6b4c97...
Author: Scott Chacon <schacon@gmail.com>
Date: Sun Feb 8 19:02:46 2009 -0800
Merge branch 'experiment'
验证标签
使用'git tag -v (tag)'就可以验证一个签名标签了。这个命令会用到GPG来验证签名。前提是:你必须在密钥环中存放着签名者的公钥。
$ git tag -v v1.4.2.1
object 883653babd8ee7ea23e6a5c392bb739348b1eb61
type commit
tag v1.4.2.1
tagger Junio C Hamano <junkio@cox.net> 1158138501 -0700
object 883653babd8ee7ea23e6a5c392bb739348b1eb61
type commit
tag v1.4.2.1
tagger Junio C Hamano <junkio@cox.net> 1158138501 -0700
GIT 1.4.2.1
Minor fixes since 1.4.2, including git-mv and git-http with alternates.
gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A
gpg: Good signature from "Junio C Hamano <junkio@cox.net>"
gpg: aka "[jpeg image of size 1513]"
Primary key fingerprint: 3565 2A26 2040 E066 C9A7 4A7D C0C6 D9A4 F311 9B9A
gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A
gpg: Good signature from "Junio C Hamano <junkio@cox.net>"
gpg: aka "[jpeg image of size 1513]"
Primary key fingerprint: 3565 2A26 2040 E066 C9A7 4A7D C0C6 D9A4 F311 9B9A
如果你没有这个公钥的话,你会看到这样的信息:
gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A
gpg: Can't check signature: public key not found
error: could not verify the tag 'v1.4.2.1'
gpg: Can't check signature: public key not found
error: could not verify the tag 'v1.4.2.1'
后期贴标签
这种情况是说你想对以前的某次提交贴个标签,如果整个提交历史是这样的:
$ git log --pretty=oneline
15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment'
a6b4c97498bd301d84096da251c98a07c7723e65 beginning write support
0d52aaab4479697da7686c15f77a3d64d9165190 one more thing
6d52a271eda8725415634dd79daabbc4d9b6008e Merge branch 'experiment'
0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc added a commit function
4682c3261057305bdd616e23b64b0857d832627b added a todo file
166ae0c4d3f420721acbb115cc33848dfcc2121a started write support
9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile
964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo
8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme
15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment'
a6b4c97498bd301d84096da251c98a07c7723e65 beginning write support
0d52aaab4479697da7686c15f77a3d64d9165190 one more thing
6d52a271eda8725415634dd79daabbc4d9b6008e Merge branch 'experiment'
0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc added a commit function
4682c3261057305bdd616e23b64b0857d832627b added a todo file
166ae0c4d3f420721acbb115cc33848dfcc2121a started write support
9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile
964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo
8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme
忘记在那个提交信息为'updated rakefile'的点上贴一个'v1.2'的标签了,我可以现在贴一个上去。你可以在执行创建标签的语句后面跟上那次提交的校验和(或者部分校验和)。
$ git tag -a v1.2 9fceb02
现在我们可以列出所有的标签:
$ git tag
v0.1
v1.2
v1.3
v1.4
v1.4-lw
v1.5
v0.1
v1.2
v1.3
v1.4
v1.4-lw
v1.5
$ git show v1.2
tag v1.2
Tagger: Scott Chacon <schacon@gmail.com>
Date: Mon Feb 9 15:32:16 2009 -0800
tag v1.2
Tagger: Scott Chacon <schacon@gmail.com>
Date: Mon Feb 9 15:32:16 2009 -0800
version 1.2
commit 9fceb02d0ae598e95dc970b74767f19372d61af8
Author: Magnus Chacon <mchacon@gmail.com>
Date: Sun Apr 27 20:43:35 2008 -0700
commit 9fceb02d0ae598e95dc970b74767f19372d61af8
Author: Magnus Chacon <mchacon@gmail.com>
Date: Sun Apr 27 20:43:35 2008 -0700
updated rakefile
...
...
共享标签
默认情况下,'git push'命令不会将标签上传到远程服务器上。为了共享这些标签,你必须在'git push'命令后明确添加-tags选项
[master]$ git push --tags
Counting objects: 50, done.
Compressing objects: 100% (38/38), done.
Writing objects: 100% (44/44), 4.56 KiB, done.
Total 44 (delta 18), reused 8 (delta 1)
To git@github.com:schacon/simplegit.git
* [new tag] v0.1 -> v0.1
* [new tag] v1.2 -> v1.2
* [new tag] v1.4 -> v1.4
* [new tag] v1.4-lw -> v1.4-lw
* [new tag] v1.5 -> v1.5
Counting objects: 50, done.
Compressing objects: 100% (38/38), done.
Writing objects: 100% (44/44), 4.56 KiB, done.
Total 44 (delta 18), reused 8 (delta 1)
To git@github.com:schacon/simplegit.git
* [new tag] v0.1 -> v0.1
* [new tag] v1.2 -> v1.2
* [new tag] v1.4 -> v1.4
* [new tag] v1.4-lw -> v1.4-lw
* [new tag] v1.5 -> v1.5
现在,如果有人克隆或者在线同步你的git仓库的话,标签也会一并同步了。