git 学习笔记
git简介
Git是一个 开源的 分布式 版本控制 系统, 可以有效、高速的处理从很小到非常大的项目版本管理。
分布式 VS 集中式
集中式
SVN - CVS - ClearCase(IBM 收费) - VSS(微软)
分布式
git - BitKeeper(促使git诞生) - Mercurial - Bazaar
目前集中式常用的SVN, 分布式常用git
集中式
集中式版本控制系统, 版本库需要集中的放到一台服务器上, 在工作时, 用自己的电脑从中央服务器上将目前最新内容下载到本地, 实现效果后再讲内容推送到中央服务器.
缺点
- 中央服务器崩溃, 所有人都干不了活
- 网络带宽会影响文件下载和上传速度
分布式
分布式版本控制系统压根没有”中央服务器”这个东西, 每个人的电脑都是一个完整的版本库, 这样工作的时候并不需要网络. 多人协作, 在合并作品的时候, 只需将自己的内容传给对方, 对方既可以看到你修改的内容. 同时, git提供强大的分支, 可以将项目拆分, 使项目更加安全.
注意 git虽然没有”中央服务器”, 但常常找出一台电脑来充当”中央服务器”, 不过其作用是为了方便交换, 因为, 协作的两个人不在同一个局域网, 或者其中一人电脑未开启等特殊情况.
优点
- 安全性极高, 即便自己的电脑坏了, 只需要从别人的电脑上重新clone一个版本库即可
- 强大的分支, 可以将一个大项目拆分成若干小功能来实现, 实现后再合并
安装git(Linux)
- 在终端输入 git 查看git信息(如果没有安装会有下方的友好提示)
$ git
The program 'git' is currently not installed. You can install it by typing:
sudo apt-get install git
- 如果没有安装, 在终端输入 sudo apt-get install git 安装
注意:
老一点的Debian或Ubuntu Linux,要把命令改为sudo apt-get install git-core,因为以前有个软件也叫GIT(GNU Interactive Tools),结果Git就只能叫git-core了。由于Git名气实在太大,后来就把GNU Interactive Tools改成gnuit,git-core正式改为git。
创建版本库
版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
- 在一个有足够权限的地方创建空文件夹
- 在终端使用命令: git init
$ git init
Initialized empty Git repository in /Users/michael/learngit/.git/
这时git参考就建立好了, 而且是一个空仓库, 此时文件夹下会多一个.git隐藏文件, 它是来跟踪仓库变化的, 不要随意改动这个文件.
将内容放到版本库
- git add fileName
- git commit -m ‘info’
$ git add readme.md
$ git add git_study.md
$ git commit -m "add 2 files."
说明:
git add 告诉 git 我要加入某个文件, git commit告诉 git 内容可以放入版本库了, git commit后的 -m ‘xxx’ 参数的意思是这次提交做了哪些改动, 强烈建议写上, 因为用不了多久你就会忘了曾经做了什么. 因为git commit 一次可以提交多个文件, 所以可以先通过add多个文件, 然后commit一次提交.
时光机穿梭
在终端使用命令git status查看那些文件被改动, 以及那些文件将要被commit提交
在终端使用命令git diff查看文件被改动了什么
版本回退
如果在修改文件过程中出现了什么错误, 需要回退到就版本, 怎么办呢?
在终端使用命令git log查看提交历史
LileideMacBook-Air:test lilei$ git log
commit a58602bc231689eb64b91e3bea7982a16c4c19bb
Author: LLyeap <lilei@LileideMacBook-Air.local>
Date: Tue Sep 20 17:15:46 2016 +0800
test change two
commit 2f2bd852d2ef263667e15a950635a87b37a0a460
Author: LLyeap <lilei@LileideMacBook-Air.local>
Date: Tue Sep 20 17:15:13 2016 +0800
test change one
commit 48c10f3a133c58f666c67af57f706d79b97b3522
Author: LLyeap <lilei@LileideMacBook-Air.local>
Date: Tue Sep 20 17:14:15 2016 +0800
create test
如果觉得内容太多, 可以使用命令git log –pretty=oneline查看
LileideMacBook-Air:test lilei$ git log --pretty=oneline
a58602bc231689eb64b91e3bea7982a16c4c19bb test change two
2f2bd852d2ef263667e15a950635a87b37a0a460 test change one
48c10f3a133c58f666c67af57f706d79b97b3522 create test
说明:
前面的一大串数字是commit id, 和SVN不一样,Git的commit id不是1,2,3……递增的数字,而是一个SHA1计算出来的一个非常大的数字,用十六进制表示.
上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100。
LileideMacBook-Air:test lilei$ git reset --hard HEAD^
HEAD is now at 2f2bd85 test change one
注意:
要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。
工作区和暂存区
Git和其他版本控制系统如SVN的一个不同之处就是有暂存区的概念。
工作区
工作区可以简单的理解为是git仓库目录下内容.
暂存区
回顾一下, 在将内容提交到仓库时候, 需要先使用git add一下, 此时这个add其实是吧内容提交到stage暂存区, 在执行commit的使用才会将stage暂存区中的内容提交到工作区.
git add命令将文件提交到缓存区
git commit命令将文件提交到工作区
管理修改
Git跟踪并管理的是修改,而非文件。
那么什么是修改?比如你新增了一行,这就是一个修改,删除了一行,也是一个修改,更改了某些字符,也是一个修改,删了一些又加了一些,也是一个修改,甚至创建一个新文件,也算一个修改。
跟着下面的操作, 来理解一下git是如何管理修改的
1. 修改readme.md文件内容, 并且add
2. 再次修改readme.md文件内容, 不add
3. 执行commit
这时你查看一下, 第二次修改的内容并没有被提交
撤销修改
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout – file。
说明:
- 命令git checkout – readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销,这里有两种情况:
- 一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
- 一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
- 总之,就是让这个文件回到最近一次git commit或git add时的状态。
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD file,就回到了场景1,第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。
场景4. 你把不合适的修改推送到远程库, 那就等着”BOSS”来呵呵你吧。
删除文件
在git中, 删除文件其实也是一种修改操作
一般情况下我们删除一个文件就是直接在终端rm file, 这时在版本库中会提示有个文件被删除了
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
这时你可以通过命令$ git rm test.txt确定将文件删除
或通过命令$ git checkout – test.txt将文件恢复
远程仓库
Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上。最初,只有一台机器有一个原始版本库,此后,别的机器可以“克隆”这个原始版本库,而且每台机器的版本库其实都是一样的,并没有主次之分。并且一台电脑上也是可以克隆多个版本库的,只要不在同一个目录下(不过很少有这种需求)。实际情况往往是这样,找一台电脑充当服务器的角色,每天24小时开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交。(可以自己用一台电脑搭建git环境作为远程仓库, 也可以使用GitHub)
GitHub(神奇的网站 - 远程仓库)
首先, 请先注册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是公钥,可以放心地告诉任何人。
登陆GitHub,打开“Account settings”,“SSH Keys”页面:
点“Add Key”,你就应该看到已经添加的Key:
说明:
为什么GitHub需要SSH Key呢?因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。
添加远程库
- 要关联一个远程库,使用命令
git remote add origin git@server-name:path/repo-name.git;
关联后,使用命令git push -u origin master第一次推送master分支的所有内容;
此后,每次本地提交后,只要有必要,就可以使用命令git push origin master推送最新修改;
分布式版本系统的最大好处之一是在本地工作完全不需要考虑远程库的存在,也就是有没有联网都可以正常工作,而SVN在没有联网的时候是拒绝干活的!当有网络的时候,再把本地提交推送一下就完成了同步!
从远程库克隆
从零开发,那么最好的方式是先创建远程库,然后,从远程库克隆。
先在GitHub创建一个仓库(创建默认的readme.md)
使用命令git clone克隆一个本地库(多人开发就每个人都clone一份):
$ git clone git@github.com:michaelliao/gitskills.git
说明:
GitHub给出的地址不止一个,还可以用
https:// github.com/michaelliao/gitskills.git这样的地址。实际上,Git支持多种协议,默认的git://使用ssh,但也可以使用https等其他协议。
分支管理
分支是什么
分支就类似于一个平行的空间, 其相互之间是独立的, 在各个分支上工作是各不影响的
分支的作用
假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。
有了分支,你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。
创建与合并分支
git默认情况下只有一个master主分支, HEAD严格地说不是指向提交, 而是指向master, master才是指向提交. 在新建分支(branch1)后, 则是新加一个branch1指针指向最新提交, 将HEAD指向branch1. 此后, 提交内容只有branch1指针向前挪动, master不变. 间分支合并到主分支则是将master指针指向分支现在的位置. 删除分支则是去掉branch1的指针即可.
- 创建一个分支branch1
LileideMacBook-Air:test lilei$ git checkout -b branch1
M test.md
Switched to a new branch 'branch1'
查看分支
LileideMacBook-Air:test lilei$ git branch * branch1 master
说明:
前面带*表示是HEAD当前所指分支, 提交会提交到此分支- 合并分支
LileideMacBook-Air:test lilei$ git commit -m 'test merge branch' [branch1 a9a836c] test merge branch Committer: LLyeap <lilei@LileideMacBook-Air.local> 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: git config --global user.name "Your Name" git config --global user.email you@example.com After doing this, you may fix the identity used for this commit with: git commit --amend --reset-author 1 file changed, 4 insertions(+) LileideMacBook-Air:test lilei$ git status On branch branch1 nothing to commit, working directory clean LileideMacBook-Air:test lilei$ git checkout master Switched to branch 'master' LileideMacBook-Air:test lilei$ git branch branch1 * master LileideMacBook-Air:test lilei$ git merge branch1 Updating c755c79..a9a836c Fast-forward test.md | 4 ++++ 1 file changed, 4 insertions(+)
说明:
修改test.md内容, 在branch1分支下提交, 然后通过git checkout master切到主分支下, 这时你回来看刚才修改的test.md文件, 会发现刚才修改的内容并没有, 因为master分支的指向并没有向前.这时在master分之下, 通过命令git merge branch1将分支上内容合并到当前分支(master)上, 这时在去看test.md文件, 会发现刚才修改的内容有出现了, 因为命令是master分支指向了branch1的位置.
- 删除分支
LileideMacBook-Air:test lilei$ git branch -d branch1 Deleted branch branch1 (was a9a836c). LileideMacBook-Air:test lilei$ git branch * master
注意:
Git鼓励大量使用分支:
查看分支:git branch
创建分支:git branch
切换分支:git checkout
创建+切换分支:git checkout -b
合并某分支到当前分支:git merge
删除分支:git branch -d
解决冲突
如果在分支上做了修改, 并且在master分支上也做了修改, 这时候合并就会造成冲突, 无法’快速合并’, 需要手动合并
以下代码是在两个分支上进行修改
LileideMacBook-Air:test lilei$ git branch
* feature1
master
LileideMacBook-Air:test lilei$ git add test.md
LileideMacBook-Air:test lilei$ git commit -m 'feature change'
[feature1 3ac2d1e] feature change
Committer: LLyeap <lilei@LileideMacBook-Air.local>
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:
git config --global user.name "Your Name"
git config --global user.email you@example.com
After doing this, you may fix the identity used for this commit with:
git commit --amend --reset-author
1 file changed, 2 insertions(+)
LileideMacBook-Air:test lilei$ git checkout master
Switched to branch 'master'
LileideMacBook-Air:test lilei$ git branch
feature1
* master
LileideMacBook-Air:test lilei$ git add test.md
LileideMacBook-Air:test lilei$ git commit -m 'master change'
[master 4a1eb7f] master change
Committer: LLyeap <lilei@LileideMacBook-Air.local>
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:
git config --global user.name "Your Name"
git config --global user.email you@example.com
After doing this, you may fix the identity used for this commit with:
git commit --amend --reset-author
1 file changed, 2 insertions(+)
合并两个分支
LileideMacBook-Air:test lilei$ git branch
feature1
* master
LileideMacBook-Air:test lilei$ git merge feature1
Auto-merging test.md
CONFLICT (content): Merge conflict in test.md
Automatic merge failed; fix conflicts and then commit the result.
此时, 再去test.md文件看下内容, 会有以下内容
<<<<<<< HEAD
here is master change
=======
here is feature change
>>>>>>> feature1
将以上内容手动修改成你需要的内容后再add commit, 并输入命令git log –graph来查看合并记录
LileideMacBook-Air:test lilei$ git log --graph
* commit 30c7502ab3c865b17804a1ece24b8a8e4f835a3e
|\ Merge: 4a1eb7f 3ac2d1e
| | Author: LLyeap <lilei@LileideMacBook-Air.local>
| | Date: Tue Sep 20 22:43:14 2016 +0800
| |
| | solve conflict
| |
| * commit 3ac2d1e23d74d978bcdbe610c5e706202b7d1dd8
| | Author: LLyeap <lilei@LileideMacBook-Air.local>
| | Date: Tue Sep 20 22:32:14 2016 +0800
| |
| | feature change
| |
* | commit 4a1eb7f19a9857e644db2643e274c418d7c3346a
|/ Author: LLyeap <lilei@LileideMacBook-Air.local>
| Date: Tue Sep 20 22:33:40 2016 +0800
|
| master change
|
* commit a9a836c8538d25223b2738cab5dec24b863279db
| Author: LLyeap <lilei@LileideMacBook-Air.local>
| Date: Tue Sep 20 21:50:57 2016 +0800
|
| test merge branch
|
* commit c755c79618c057205963d55e51804af9906f07f9
| Author: LLyeap <lilei@LileideMacBook-Air.local>
分支管理策略
通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
合并分支时,加上–no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并。
LileideMacBook-Air:test lilei$ git merge --no-ff -m 'merge with no-ff' dev
Bug分支
在执行某些特殊任务时, 就像处理必须立即解决的Bug, 这时就行中断请求一样, 需要先保护一下现场, 处理结束后再恢复现场, git的Bug分支就类似如此, 在处理突发Bug时, 如果当前分支上的任务完成一半, 又不可以提交, 这时可以通过git stash命令把当前工作现场“储藏”起来.
处理Bug在需要的地方建立临时分支, 处理完Bug后合并到对应的分支, 再删掉临时分支即可.
处理完Bug后, 可以通过命令git stash list来查看之前’储存’的现场, 工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:
- 一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除
- 另一种方式是用git stash pop,恢复的同时把stash内容也删了
Feature分支
在软件开发时, 会有新需求加入, 这时明智的做法是新建一个分支, 在分支上开发这个功能进行测试, 这样才不会影响到master分支, 开发成功后再删除这个测试分支即可.
如果新功能需求突然取消, 此时这个分支还没有合并, 但必须销毁这个分支, 此时使用命令git branch -d xxxx, 分支还没有被合并,如果删除,将丢失掉修改,如果要强行删除,需要使用命令git branch -D xxxx。这时根据提示即可删除了.
多人协作
多人协作, 往往要用到远程仓库, 那么要如何解决与远程仓库之间的同步以及和伙伴代码合并的问题呢?
和远程仓库同步
当你从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin。
可是使用git remote查看远程仓库的信息
$ git remote
origin
或者,使用git remote -v查看详细的信息
$ git remote -v
origin git@github.com:michaelliao/learngit.git (fetch)
origin git@github.com:michaelliao/learngit.git (push)
上面显示了可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址。
推送分支
推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上, 比如下面这句就是吧本地的master分支推送到远程的master分支上:
$ git push origin master
但是并不是所有分支都需要推送, 像一些大家都需要用到的诸如: master(主分支), dev(开发分支)等这些需要推送, 像一些只是自己完成任务的独立分支, 类似:bug(修改bug的分支)就不用推送, 除非你的老板想知道你都修改了哪些bug.
抓取分支
多人协作时,大家都会往master和dev分支上推送各自的修改。
当你的协作伙伴从远程clone时, 他只能看到master分支, 如果想看到dev等其他分支, ,就必须创建远程origin的dev分支到本地,可以使用这个命令创建本地dev分支:
$ git checkout -b dev origin/dev
此后, 你的伙伴就可以在分支上做修改了, 并且会提交修改, 如果他提交后(此时有个问题: 你手里的版本已经不是最新版本了), 你同样做好了修改需要提交, 这时当你pull时, 你会发现报错, 因为你和你的伙伴可能修改了同样的文件, 这就和前面分支合并一样, 出现了冲突. 解决办法也很简单,Git已经提示我们,就是先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送(这时可能会git pull失败,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接).
创建分支链接
$ git branch --set-upstream dev origin/dev
然后pull到本地
$ git pull
这时, 在本地对伙伴修改的内容和自己修改的内容进行合并, 会有合并冲突, 需要手动解决, 解决后在推送.
注意:
多人协作的工作模式通常是这样:
- 可以试图用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。
说明:
- 查看远程库信息,使用git remote -v;
- 本地新建的分支如果不推送到远程,对其他人就是不可见的;
- 从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;
- 在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致;
- 建立本地分支和远程分支的关联,使用git branch –set-upstream branch-name origin/branch-name;
- 从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。
标签管理
标签(tag), 一个简单的理解就是它记录了一次commit id, tag一般建立在主分支上, 方便用于版本发布. 标签和分支类似, 一个指针指向某次提交, 只不过分支可以继续先前移动, 而标签不可移动.
创建标签
在创建标签前需要先切换到需要打标签的分支上, 然后使用命令 git tag v1.0 来创建标签. 默认标签是打在HEAD指向的地方(即最新提交), 如果想把标签创建在先前的提交上, 需要先知道commit id(用命令git log –pretty oneline –abbrev-commit), 然后用命令 git tag v0.9 6224937 在对应的提交上打上标签, 可以使用 git tag 查看所有标签, 使用命令 git show v0.9 来查看标签详细信息.
还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字:
$ git tag -a v0.1 -m "version 0.1 released" 3628164
还可以通过-s用私钥签名一个标签:
$ git tag -s v0.2 -m "signed version 0.2 released" fec145a
注意:
签名采用PGP签名,因此,必须首先安装gpg(GnuPG),如果没有找到gpg,或者没有gpg密钥对,就会报错
操作标签
如果标签打错了,也可以删除:
$ git tag -d v0.1
如果要推送某个标签到远程,使用命令git push origin
$ git push origin v1.0
或者,一次性推送全部尚未推送到远程的本地标签:
$ git push origin --tags
如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
$ git tag -d v0.9
然后,从远程删除。删除命令也是push,但是格式如下:
$ git push origin :refs/tags/v0.9
使用GitHub
- 在GitHub上,可以任意Fork开源仓库;
- 自己拥有Fork后的仓库的读写权限;
- 可以推送pull request给官方仓库来贡献代码。
自定义Git
让Git显示颜色,会让命令输出看起来更醒目:
$ git config --global color.ui true
忽略特殊文件
在工作目录下创建.gitignore文件, 在这个文件中填写需要忽略的文件内容, 然后git add进去. 此后这个.gitignore就开始起作用了.
忽略文件的原则是:
1. 忽略操作系统自动生成的文件,比如缩略图等;
2. 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;
3. 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。
如果有些时候,你想添加一个文件到Git,但发现添加不了,原因是这个文件被.gitignore忽略了.
如果你确实想添加该文件,可以用-f强制添加到Git:
$ git add -f App.class
配置别名
通过以下命令将status 缩写成st
$ git config --global alias.st status
搭建Git服务器
搭建Git服务器需要准备一台运行Linux的机器,强烈推荐用Ubuntu或Debian,这样,通过几条简单的apt命令就可以完成安装。
假设你已经有sudo权限的用户账号,下面,正式开始安装。
- 安装git
lilei@lilei-virtual-machine:~$ 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就是这个工具。
结语
学习摘要结束, 希望大家能够熟练使用git来帮助管理好项目, 有条理地完成开发任务.