发布一个版本时,咱们一般先在版本库中打一个标签(tag),这样,就惟一肯定了打标签时刻的版本。未来不管何时,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。因此,标签也是版本库的一个快照。python
Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针(跟分支很像对不对?可是分支能够移动,标签不能移动),因此,建立和删除标签都是瞬间完成的。git
Git有commit,为何还要引入tag?github
“请把上周一的那个版本打包发布,commit号是6a5819e...”sql
“一串乱七八糟的数字很差找!”shell
若是换一个办法:数据库
“请把上周一的那个版本打包发布,版本号是v1.2”bootstrap
“好的,按照tag v1.2查找commit就行!”安全
因此,tag就是一个让人容易记住的有意义的名字,它跟某个commit绑在一块儿。ruby
在Git中打标签很是简单,首先,切换到须要打标签的分支上:bash
$ git branch * dev master $ git checkout master Switched to branch 'master'
而后,敲命令git tag <name>
就能够打一个新标签:
$ git tag v1.0
能够用命令git tag
查看全部标签:
$ git tag v1.0
默认标签是打在最新提交的commit上的。有时候,若是忘了打标签,好比,如今已是周五了,但应该在周一打的标签没有打,怎么办?
方法是找到历史提交的commit id,而后打上就能够了:
$ git log --pretty=oneline --abbrev-commit 12a631b (HEAD -> master, tag: v1.0, origin/master) merged bug fix 101 4c805e2 fix bug 101 e1e9c68 merge with no-ff f52c633 add merge cf810e4 conflict fixed 5dc6824 & simple 14096d0 AND simple b17d20e branch test d46f35e remove test.txt b84166e add test.txt 519219b git tracks changes e43a48b understand how stage works 1094adb append GPL e475afc add distributed eaadf4e wrote a readme file
比方说要对add merge
此次提交打标签,它对应的commit id是f52c633
,敲入命令:
$ git tag v0.9 f52c633
再用命令git tag
查看标签:
$ git tag v0.9 v1.0
注意,标签不是按时间顺序列出,而是按字母排序的。能够用git show <tagname>
查看标签信息:
$ git show v0.9 commit f52c63349bc3c1593499807e5c8e972b82c8f286 (tag: v0.9) Author: Michael Liao <askxuefeng@gmail.com> Date: Fri May 18 21:56:54 2018 +0800 add merge diff --git a/readme.txt b/readme.txt ...
能够看到,v0.9
确实打在add merge
此次提交上。
还能够建立带有说明的标签,用-a
指定标签名,-m
指定说明文字:
$ git tag -a v0.1 -m "version 0.1 released" 1094adb
用命令git show <tagname>
能够看到说明文字:
$ git show v0.1
tag v0.1
Tagger: Michael Liao <askxuefeng@gmail.com> Date: Fri May 18 22:48:43 2018 +0800 version 0.1 released commit 1094adb7b9b3807259d8cb349e7df1d4d6477073 (tag: v0.1) Author: Michael Liao <askxuefeng@gmail.com> Date: Fri May 18 21:06:15 2018 +0800 append GPL diff --git a/readme.txt b/readme.txt ...
命令git tag <tagname>
用于新建一个标签,默认为HEAD
,也能够指定一个commit id;
命令git tag -a <tagname> -m "blablabla..."
能够指定标签信息;
命令git tag
能够查看全部标签。
若是标签打错了,也能够删除:
$ git tag -d v0.1 Deleted tag 'v0.1' (was f15b0dd)
由于建立的标签都只存储在本地,不会自动推送到远程。因此,打错的标签能够在本地安全删除。
若是要推送某个标签到远程,使用命令git push origin <tagname>
:
$ git push origin v1.0 Total 0 (delta 0), reused 0 (delta 0) To github.com:michaelliao/learngit.git * [new tag] v1.0 -> v1.0
或者,一次性推送所有还没有推送到远程的本地标签:
$ git push origin --tags Total 0 (delta 0), reused 0 (delta 0) To github.com:michaelliao/learngit.git * [new tag] v0.9 -> v0.9
若是标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
$ git tag -d v0.9 Deleted tag 'v0.9' (was f52c633)
而后,从远程删除。删除命令也是push,可是格式以下:
$ git push origin :refs/tags/v0.9 To github.com:michaelliao/learngit.git - [deleted] v0.9
要看看是否真的从远程库删除了标签,能够登录GitHub查看。
命令git push origin <tagname>
能够推送一个本地标签;
命令git push origin --tags
能够推送所有未推送过的本地标签;
命令git tag -d <tagname>
能够删除一个本地标签;
命令git push origin :refs/tags/<tagname>
能够删除一个远程标签。
咱们一直用GitHub做为免费的远程仓库,若是是我的的开源项目,放到GitHub上是彻底没有问题的。其实GitHub仍是一个开源协做社区,经过GitHub,既可让别人参与你的开源项目,也能够参与别人的开源项目。
在GitHub出现之前,开源项目开源容易,但让广大人民群众参与进来比较困难,由于要参与,就要提交代码,而给每一个想提交代码的群众都开一个帐号那是不现实的,所以,群众也仅限于报个bug,即便能改掉bug,也只能把diff文件用邮件发过去,很不方便。
可是在GitHub上,利用Git极其强大的克隆和分支功能,广大人民群众真正能够第一次自由参与各类开源项目了。
如何参与一个开源项目呢?好比人气极高的bootstrap项目,这是一个很是强大的CSS框架,你能够访问它的项目主页https://github.com/twbs/bootstrap,点“Fork”就在本身的帐号下克隆了一个bootstrap仓库,而后,从本身的帐号下clone:
git clone git@github.com:michaelliao/bootstrap.git
必定要从本身的帐号下clone仓库,这样你才能推送修改。若是从bootstrap的做者的仓库地址git@github.com:twbs/bootstrap.git
克隆,由于没有权限,你将不能推送修改。
Bootstrap的官方仓库twbs/bootstrap
、你在GitHub上克隆的仓库my/bootstrap
,以及你本身克隆到本地电脑的仓库,他们的关系就像下图显示的那样:
┌─ GitHub ────────────────────────────────────┐ │ │ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ twbs/bootstrap │────>│ my/bootstrap │ │ │ └─────────────────┘ └─────────────────┘ │ │ ▲ │ └──────────────────────────────────┼──────────┘ ▼ ┌─────────────────┐ │ local/bootstrap │ └─────────────────┘
若是你想修复bootstrap的一个bug,或者新增一个功能,马上就能够开始干活,干完后,往本身的仓库推送。
若是你但愿bootstrap的官方库能接受你的修改,你就能够在GitHub上发起一个pull request。固然,对方是否接受你的pull request就不必定了。
若是你没能力修改bootstrap,但又想要试一把pull request,那就Fork一下个人仓库:https://github.com/michaelliao/learngit,建立一个your-github-id.txt
的文本文件,写点本身学习Git的心得,而后推送一个pull request给我,我会视心情而定是否接受。
在GitHub上,能够任意Fork开源仓库;
本身拥有Fork后的仓库的读写权限;
能够推送pull request给官方仓库来贡献代码。
在安装Git一节中,咱们已经配置了user.name
和user.email
,实际上,Git还有不少可配置项。
好比,让Git显示颜色,会让命令输出看起来更醒目:
$ git config --global color.ui true
这样,Git会适当地显示不一样的颜色,好比git status
命令:
文件名就会标上颜色。
有些时候,你必须把某些文件放到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
作版本管理!
有没有常常敲错命令?好比git status
?status
这个单词真心很差记。
若是敲git st
就表示git status
那就简单多了,固然这种偷懒的办法咱们是极力同意的。
咱们只须要敲一行命令,告诉Git,之后st
就表示status
:
$ git config --global alias.st status
好了,如今敲git st
看看效果。
固然还有别的命令能够简写,不少人都用co
表示checkout
,ci
表示commit
,br
表示branch
:
$ git config --global alias.co checkout $ git config --global alias.ci commit $ git config --global alias.br branch
之后提交就能够简写成:
$ git ci -m "bala bala bala..."
--global
参数是全局参数,也就是这些命令在这台电脑的全部Git仓库下都有用。
在撤销修改一节中,咱们知道,命令git reset HEAD file
能够把暂存区的修改撤销掉(unstage),从新放回工做区。既然是一个unstage操做,就能够配置一个unstage
别名:
$ git config --global alias.unstage 'reset HEAD'
当你敲入命令:
$ git unstage test.py
实际上Git执行的是:
$ git reset HEAD test.py
配置一个git last
,让其显示最后一次提交信息:
$ git config --global alias.last 'log -1'
这样,用git last
就能显示最近一次的提交:
$ git last
commit adca45d317e6d8a4b23f9811c3d7b7f0f180bfe2
Merge: bd6ae48 291bea8
Author: Michael Liao <askxuefeng@gmail.com> Date: Thu Aug 22 22:49:22 2013 +0800 merge & fix hello.py
甚至还有人丧心病狂地把lg
配置成了:
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
来看看git lg
的效果:
为何不早点告诉我?别激动,咱不是为了多记几个英文单词嘛!
配置Git的时候,加上--global
是针对当前用户起做用的,若是不加,那只针对当前的仓库起做用。
配置文件放哪了?每一个仓库的Git配置文件都放在.git/config
文件中:
$ cat .git/config [core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true precomposeunicode = true [remote "origin"] url = git@github.com:michaelliao/learngit.git fetch = +refs/heads/*:refs/remotes/origin/* [branch "master"] remote = origin merge = refs/heads/master [alias] last = log -1
别名就在[alias]
后面,要删除别名,直接把对应的行删掉便可。
而当前用户的Git配置文件放在用户主目录下的一个隐藏文件.gitconfig
中:
$ cat .gitconfig [alias] co = checkout ci = commit br = branch st = status [user] name = Your Name email = your@email.com
配置别名也能够直接修改这个文件,若是改错了,能够删掉文件从新经过命令配置。
在远程仓库一节中,咱们讲了远程仓库实际上和本地仓库没啥不一样,纯粹为了7x24小时开机并交换你们的修改。
GitHub就是一个免费托管开源代码的远程仓库。可是对于某些视源代码如生命的商业公司来讲,既不想公开源代码,又舍不得给GitHub交保护费,那就只能本身搭建一台Git服务器做为私有仓库使用。
搭建Git服务器须要准备一台运行Linux的机器,强烈推荐用Ubuntu或Debian,这样,经过几条简单的apt
命令就能够完成安装。
假设你已经有sudo
权限的用户帐号,下面,正式开始安装。
第一步,安装git
:
$ sudo apt-get install git
第二步,建立一个git
用户,用来运行git
服务:
$ sudo adduser git
第三步,建立证书登陆:
收集全部须要登陆的用户的公钥,就是他们本身的id_rsa.pub
文件,把全部公钥导入到/home/git/.ssh/authorized_keys
文件里,一行一个。
第四步,初始化Git仓库:
先选定一个目录做为Git仓库,假定是/srv/sample.git
,在/srv
目录下输入命令:
$ sudo git init --bare sample.git
Git就会建立一个裸仓库,裸仓库没有工做区,由于服务器上的Git仓库纯粹是为了共享,因此不让用户直接登陆到服务器上去改工做区,而且服务器上的Git仓库一般都以.git
结尾。而后,把owner改成git
:
$ sudo chown -R git:git sample.git
第五步,禁用shell登陆:
出于安全考虑,第二步建立的git用户不容许登陆shell,这能够经过编辑/etc/passwd
文件完成。找到相似下面的一行:
git:x:1001:1001:,,,:/home/git:/bin/bash
改成:
git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell
这样,git
用户能够正常经过ssh使用git,但没法登陆shell,由于咱们为git
用户指定的git-shell
每次一登陆就自动退出。
第六步,克隆远程仓库:
如今,能够经过git clone
命令克隆远程仓库了,在各自的电脑上运行:
$ git clone git@server:/srv/sample.git Cloning into 'sample'... warning: You appear to have cloned an empty repository.
剩下的推送就简单了。
若是团队很小,把每一个人的公钥收集起来放到服务器的/home/git/.ssh/authorized_keys
文件里就是可行的。若是团队有几百号人,就无法这么玩了,这时,能够用Gitosis来管理公钥。
这里咱们不介绍怎么玩Gitosis了,几百号人的团队基本都在500强了,相信找个高水平的Linux管理员问题不大。
有不少不但视源代码如生命,并且视员工为窃贼的公司,会在版本控制系统里设置一套完善的权限控制,每一个人是否有读写权限会精确到每一个分支甚至每一个目录下。由于Git是为Linux源代码托管而开发的,因此Git也继承了开源社区的精神,不支持权限控制。不过,由于Git支持钩子(hook),因此,能够在服务器端编写一系列脚原本控制提交等操做,达到权限控制的目的。Gitolite就是这个工具。
这里咱们也不介绍Gitolite了,不要把有限的生命浪费到权限斗争中。