说明
- 阅读此博文之前,请先阅读本人有关CSDN博客的 相关说明
- 本文的 git教程 基于 Ubuntu 18.04 64位,所有命令均由本人亲手敲过验证。Windows下未进行实操,请有需要者自行尝试
- 本文的 git教程 属于新手教程,但满足日常工作的基本需要。git的进阶请需要时自行查找相关资料
- 本文可能较长,但知识点分类较明确,若当作手册使用,请点击右侧工具栏的目录选项
- 部分重要说明是以 注释 形式呈现,请勿忽视!
集中式
- 集中式版本控制系统,版本库集中存放在中央服务器,工作之前要先从中央服务器取得最新的版本,然后开始工作,工作结束,再把更新后的版本推送给中央服务器
- 集中式版本控制系统最大的缺点就是必须联网才能工作
- CVS、SVN、ClearCase
分布式
- 分布式版本控制系统没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,工作的时候,就不需要联网。对于多人协作,只需把各自的修改推送给对方,就可以互相看到对方的修改了
- 和集中式版本控制系统相比,分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。而集中式版本控制系统的中央服务器要是出了问题,所有人都没法工作
- 在实际使用分布式版本控制系统的时候,其实很少在两人之间的电脑上推送版本库的修改,因为可能双方不在一个局域网内,两台电脑互相访问不了,也可能其他人电脑没有开机。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也可以正常工作,只是交换修改不方便而已
- git、BitKeeper、Mercurial、Bazaar
安装
- 终端输入
git
会有提示安装的命令 - 配置
git config --global user.name "Your Name" git config --global user.email "email@example.com" 注:git config命令的--global参数,表示这台机器上所有的Git仓库都会使用这个配置,也可以对某个仓库指定不同的用户名和Email地址
创建版本库
mkdir xxx
cd xxx
git init
- 注: Windows系统下,为了避免遇到各种莫名其妙的问题,确保目录名(包括父目录)不包含中文
- 所有的版本控制系统,只能跟踪文本文件的改动,比如TXT文件,网页,所有的程序代码等等,Git也不例外。版本控制系统可以显示每次的改动,比如在第5行加了一个单词“Linux”,在第8行删了一个单词“Windows”。而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改成了120KB,但到底改了什么,版本控制系统不知道,也没法知道
- 不幸的是,Microsoft的Word格式是二进制格式,因此,版本控制系统是没法跟踪Word文件的改动的,如果要真正使用版本控制系统,就要以纯文本方式编写文件。因为文本是有编码的,比如中文有常用的GBK编码,日文有Shift_JIS编码,如果没有历史遗留问题,强烈建议使用标准的UTF-8编码,所有语言使用同一种编码,既没有冲突,又被所有平台所支持
- 使用Windows要特别注意: 千万不要使用Windows自带的记事本编辑任何文本文件。原因是Microsoft开发记事本的团队在每个文件开头添加了0xefbbbf(十六进制)的字符,可能会遇到很多不可思议的问题,比如,网页第一行可能会显示一个“?”,明明正确的程序一编译就报语法错误等等,都是由记事本的行为带来的。可以使用Notepad++ 代替记事本(把Notepad++的默认编码设置为UTF-8 without BOM)
删除本地版本库
- 删除版本库中的
.git
目录 - 删除整个版本库目录
添加文件
vi README
git add README
git commit -m "wrote a README file"
注:commit可以一次提交很多文件,所以可以多次add不同的文件
改动文件并提交
(1)
vi README
git diff <file> # 查看不同
git add README
git commit -m "modify README"
(2)
vi README
git commit -am "modify README"
注:git commit -am "message" = git add . + git commit -m "message"
(3) 提交多行注释
git commit -m '1. xxx
>2. xxx'
(4) 修改最后一次commit描述
// 修改方式同vi的使用
git commit --amend
(5) 修改指定commit描述
git rebase -i HEAD~n
然后将 pick 修改为 r或edit
git commit --amend
git rebase --continue
合并多个commit
- 假设有如下提交记录
* b1b8189 - (HEAD -> master) Commit-3 * 5756e15 - Commit-2 * e7ba81d - Commit-1 * 5d39ff2 - Commit-0
- 假设需求是合并commit-3和commit-2
git rebase -i e7ba81d # 不包含指定的e7ba81d pick e7ba81d Commit-2 pick 5756e15 Commit-3 # Rebase e7ba81d..b1b8189 onto e7ba81d (2 command(s)) # # Commands: # p, pick <commit> = use commit # r, reword <commit> = use commit, but edit the commit message # e, edit <commit> = use commit, but stop for amending # s, squash <commit> = use commit, but meld into previous commit # f, fixup <commit> = like "squash", but discard this commit's log message # x, exec <command> = run command (the rest of the line) using shell # b, break = stop here (continue rebase later with 'git rebase --continue') # d, drop <commit> = remove commit # l, label <label> = label current HEAD with a name # t, reset <label> = reset HEAD to a label # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>] # . create a merge commit using the original merge commit's # . message (or the oneline, if no original merge commit was # . specified). Use -c <commit> to reword the commit message.
- 将 5756e15 前的 pick 修改为 squash 或 s,表示与前一个commit进行合并,即e7ba81d,退出前会让你决定commit message,最后仓库是commit-3的状态
- 或将 5756e15 前的 pick 修改为 fixup 或 f,表示与前一个commit进行合并,即e7ba81d,但会直接使用commit-2 的commit message,最后仓库是commit-3的状态
- 注:使用drop的话会删除提交的内容,慎用
版本回退
git log [--pretty=oneline]
481f602ef4693fe40f393447014e95ee8e535a72 (HEAD -> master) add try
22929efaca9b2f12bad10420f4c1e41ba043c2e8 add distributed
7c5124871bb5a58afe2c3826ecc0a492be85a1e6 wrote a README file
# 前面一大串类似481f602...的是commit id(版本号)
# 和SVN不一样,Git的commit id不是1,2,3……递增的数字,而是一个SHA1计算出来的一个非常大的数字,用十六进制表示
# 每个人看到的commit id肯定不一样,以自己的为准
# Git是分布式的版本控制系统,当多人在同一个版本库里工作,如果大家都用1,2,3……作为版本号,会产生冲突
- 在Git中,用HEAD表示当前版本,也就是最新的提交481f602…,上一个版本就是
HEAD^
,上上一个版本就是HEAD^^
,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100
# 回退到上一个版本
git reset --hard HEAD^
# 回到指定的未来版本(版本号没必要写全)
git reset --hard 481f602
# 记录每一次命令
# 可用于找回 commit id
git reflog
暂存当前工作内容
git stash # 不会暂存untracked files
# 推荐使用
git stash save -a "temporary save"
git stash pop # 将缓存堆栈中的第一个stash删除,并将对应修改应用到当前的工作目录下
git stash apply # 将缓存堆栈中的stash多次应用到工作目录中,但并不删除stash拷贝
git stash list # 查看现有stash
git stash drop stash@{0} # 移除stash
工作区和暂存区
- 工作区:在电脑里能看到的目录
- 版本库:工作区的隐藏目录
.git
- Git的版本库里存了很多东西,其中最重要的就是称为
stage
(或者叫index
)的暂存区,还有Git为我们自动创建的第一个分支master
,以及指向master
的一个指针叫HEAD
- 把文件往Git版本库里添加的时候,是分两步执行的
- 第一步是用
git add
把文件添加进去,实际上就是把文件修改添加到暂存区 - 第二步是用
git commit
提交更改,实际上就是把暂存区的所有内容提交到当前分支
- 第一步是用
- Git的版本库里存了很多东西,其中最重要的就是称为
- 注: 每次修改,如果不用
git add
到暂存区,那就不会加入到commit
中
状态查询
- 显示工作目录和暂存区的状态
$ git status
- 仓库很大,管理文件较多时使用以下命令可能可以加快速度
$ git status -uno
撤销修改
- 当修改了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令
git checkout -- <file>
- 当修改了工作区某个文件的内容,且添加到了暂存区时,想丢弃修改,分两步,第一步用命令
git reset HEAD <file>
,就回到了上一步,第二步按上一步操作 - 已经提交了不合适的修改到版本库时,想要撤销本次提交,进行版本回退,不过前提是没有推送到远程库
删除文件
# 从工作区删除文件,可以使用 git checkout -- <file> 恢复
rm text
# 从暂存区删除文件,可以使用 git reset HEAD <file> 恢复
git rm text
# 将暂存区的操作提交到版本库
git commit -m "rm text"
远程仓库
- 创建SSH Key: 在用户主目录下,查看是否存在
.ssh
目录,如果有,再查看该目录下是存在id_rsa
(私钥)和id_rsa.pub
(公钥)这两个文件,如果有,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Keyssh-keygen -t rsa -C "youremail@example.com"
- 登陆GitHub,打开【Settings】->【SSH and GPG Keys】页面。然后点【New SSH Key】,填上任意Title,在Key文本框里粘贴
id_rsa.pub
文件的内容
添加远程库
- 登陆GitHub,创建一个新的仓库
- 关联本地仓库
git remote add origin git@github.com:yourLoginName/yourRepository.git
- 把本地库的所有内容推送到远程库上
git push -u origin master # 用git push命令,实际上是把当前分支master推送到远程 # 由于远程库是空的,第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令:git push origin master
- SSH警告: 当第一次使用Git的
clone
或者push
命令连接GitHub时,会得到一个警告The authenticity of host 'github.com (192.23.253.75)' can't be established. RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8. Are you sure you want to continue connecting (yes/no)?
- 这是因为Git使用SSH连接,而SSH连接在第一次验证GitHub服务器的Key时,需要确认GitHub的Key的指纹信息是否真的来自GitHub的服务器,输入yes回车即可
- Git会输出一个警告,告诉你已经把GitHub的Key添加到本机的一个信任列表里了
Warning: Permanently added 'github.com,192.23.253.75' (RSA) to the list of known hosts.
从远程库克隆
- 假设从零开发,最好的方式是先创建远程库,然后,从远程库克隆
- 首先,登陆GitHub,创建一个新的仓库,名字叫
gitskills
- 克隆一个本地库
# 地址可以直接在github上复制 git clone git@github.com:yourLoginName/gitskills.git
分支优势
- 假设准备开发一个新功能,但是需要两周才能完成,第一周写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致其他人不能工作。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险
- 现在有了分支,就不用怕了。每个人创建一个属于自己的分支,别人看不到,还继续在原来的分支上正常工作,而自己则在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作
创建与合并分支
查看分支:git branch
查看远程分支:git branch -r # 还有其他命令,需要时查询
创建分支:git branch <name>
切换分支:git checkout <name>
创建+切换分支:git checkout -b <name>
合并某分支到当前分支:git merge <name>
删除分支:git branch -d <name>
合并某分支上特定commit到某/新分支:
(1) git checkout master
git cherry-pick commit-id
(2) git checkout -b new-branch commit-id
合并某分支上一系列commits到某/新分支
# 假设需要合并feature分支的commit 76cada ~ 62ecb3
(1) git checkout -b newbranch 62ecb3
git rebase --onto master 76cada^
HEAD
严格来说不是指向提交,而是指向master
,master
才是指向提交的,所以,HEAD
指向的就是当前分支。- 一开始的时候,
master
分支是一条线,Git用master
指向最新的提交,再用HEAD
指向master
,就能确定当前分支,以及当前分支的提交点。每次提交,master
分支都会向前移动一步 - 当创建新的分支,例如
dev
时,Git新建了一个指针叫dev
,指向master
相同的提交,再把HEAD
指向dev
,就表示当前分支在dev
上 - 从现在开始,对工作区的修改和提交就是针对
dev
分支了,比如新提交一次后,dev
指针往前移动一步,而master
指针不变 - 假如在
dev
上的工作完成了,就可以把dev
合并到master
上,即直接把master
指向dev
的当前提交,就完成了合并 - 合并完分支后,可以删除
dev
分支。删除dev
分支就是把dev
指针给删掉,删掉后,就剩下了一条master
分支
解决冲突
master
分支和其他分支各自都分别有新的提交,则产生冲突- 合并时会提醒冲突或使用
git status
查看 - 修改冲突再提交(只针对master)
- 查看分支合并情况
git log --graph --pretty=oneline --abbrev-commit
分支管理策略
-
通常,合并分支时,如果可能,Git会用
Fast forward
模式,但这种模式下,删除分支后,会丢掉分支信息 -
如果要强制禁用
Fast forward
模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息# 本次合并要创建一个新的commit,加上-m参数,写入commit描述 git merge --no-ff -m "merge with no-ff" dev
-
首先,
master
分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面工作 -
工作都在
dev
分支上,也就是说,dev
分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev
分支合并到master
上,在master
分支发布1.0版本 -
每个人都在
dev
分支上工作,每个人都有自己的分支,时不时地往dev
分支上合并即 -
所以,团队合作的分支看起来就像这样
Bug分支
- 有其他任务进来,需要创建一个新的分支完任务,但是当前分支上任务还未完成,无法提交
# "储藏"当前工作现场,等以后恢复现场后继续工作 git stash # 查看“储藏”的工作现 git stash list # 恢复工作现场,但恢复后,stash内容并不删除 git stash apply # 删除stash中被恢复的工作现场 git stash drop # 恢复的同时把stash内容也删了 git stash pop # 可以多次stash # 恢复的时候,先进行查看stash git stash list # 恢复指定的stash git stash apply stash@{0}
Feature分支
- 添加一个新功能时,肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支
- 如果要丢弃一个没有被合并过的分支,可以通过
git branch -D <name>
强行删除
多人协作
- 查看远程库的信息
git remote # 显示更详细的信息 # 假设远程仓库名为 repository $ git remote -v origin git@github.com:yourLoginName/repository.git (fetch) origin git@github.com:yourLoginName/repository.git (push) 注:显示可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址
- 推送分支
# 推送分支,就是把该分支上的所有本地提交推送到远程库 # 推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上 $ git push origin master # 推送其他分支,比如dev $ git push origin dev
- 并不是一定要把本地分支往远程推送
- master分支是主分支,因此要时刻与远程同步
- dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步
- bug分支只用于在本地修复bug,就没必要推到远程
- feature分支是否推到远程,取决于你是否和你的团队合作在上面开发
- 抓取分支
- 当其他人从远程库
clone
时,默认情况下,他只能看到本地的master
分支 - 要在dev分支上开发,就必须创建远程
origin
的dev
分支到本地# 本地和远程分支的名称最好一致 git checkout -b dev origin/dev
- 当其他人从远程库
- 更新远程分支列表
git remote update origin --prune
- 解决冲突
- 指定本地
dev
分支与远程origin/dev
分支的链接git branch --set-upstream-to=origin/dev dev
- 把最新的提交从
origin/dev
抓下来git pull
- 本地合并,解决冲突,推送
- 指定本地
与远程同步
- 这一部分是后来补充进来的,主要是实际遇到了两个场景,可以利用以下方法解决,可能在此过程中会需要一些比较操作,故都整合在了这里,而没有放入相对应的小节
- 向更新频繁的开源项目贡献代码的时候,经常会遇到远程代码比自己本地要超前几个版本。这时候就需要先进行同步
- 之前有同事一直使用 svn,刚刚转战 git,抱怨 git 不能查看远程仓库的变化,其实还是对 git 不熟悉啦
- 抓取远程分支
# master 想要抓取的远程某分支 # latest 本地电脑上的分支,如果不存在会自动创建 $ git fetch git@github.com:loginName/project.git master:latest 注:git pull 等同于先利用 git fetch 获得当前指向的远程分支,然后利用 git merge 将其与本地的当前分支合并
- 分支比较
- 查看 dev 有,master 中没有的
$ git log dev ^master
- 查看 master 中有,dev 中没有的
$ git log master ^dev
- 查看 dev 中比 master 多提交的内容
# 结果为两个点后的分支比两个点前的分支多提交的内容 $ git log master..dev # 同理 $ git log dev..master
- 纯粹比较两分支间的不同
$ git log master...dev
- 显示出每个提交是在哪个分支上
# 注意 commit 后面的箭头,根据在 –left-right dev…master 的顺序,左箭头 < 表示是 dev 的,右箭头 > 表示是 master的 $ git log --left-right dev...master
- 查看 dev 有,master 中没有的
- 分支间文件比较
# 显示出所有有差异的文件列表以及内容增删行数情况 $ git diff branch1 branch2 --stat # 显示分支间指定文件的详细差异 $ git diff branch1 branch2 <filename> # 显示出所有有差异的文件的详细差异 $ git diff branch1 branch2
- 图形化操作
- Windows 下使用
git
提供的gui
工具gitk
,可以清晰地查看搜索提交历史及git
相关操作。在终端git
仓库目录下输入gitk
命令即可使用
- Windows 下使用
标签管理
- 发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照
- Git的标签虽然是版本库的快照,但其实它就是指向某个
commit
的指针(分支可以移动,标签不能移动) tag
就是一个让人容易记住的有意义的名字,它跟某个commit
绑在一起- 创建标签
- 切换到需要打标签的分支上
# 打一个新标签 $ git tag <name> 注:默认标签是打在最新提交的commit上的
# 针对特定提交打标签 $ git tag <tag_name> <commit_id>
# 创建带有说明的标签,用-a指定标签名,-m指定说明文字 $ git tag -a <tag_name> -m "message" <commit_id>
- 切换到需要打标签的分支上
- 查看所有标签
$ git tag 注:标签不是按时间顺序列出,而是按字母排序
- 查看标签信息
$ git show <tagname>
- 删除标签
$ git tag -d <tag_name> 注:创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除
- 推送某个标签到远程
$ git push origin <tagname>
- 一次性推送全部尚未推送到远程的本地标签
$ git push origin --tags
- 删除远程标签
# 先从本地删除 $ git tag -d <tag_name> # 然后,从远程删除 $ git push origin :refs/tags/<tagname>
Patch
- 生成 patch
# -M 表示从 commit_id 开始,向下的 M 次提交(包含此次),计数从1开始 # commit_id 写前几位即可 $ git format-patch commit_id -M
- 检查 patch
# 若 patch 与需要打 patch 的文件不在同一目录,则需要加上 patch 所在路径名 $ git apply --check xxx.patch
- 打 patch(无冲突情况)
# 打 patch 前需检查 patch 是否可用 # 若 patch 与需要打 patch 的文件不在同一目录,则需要加上 patch 所在路径名 $ git am *.patch
忽略特殊文件
- 有些时候,必须把某些文件放到Git工作目录中,但又不能提交它们,比如保存了数据库密码的配置文件等等,每次
git status
都会显示Untracked files ...
- 在Git工作区的根目录下创建一个特殊的
.gitignore
文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件 - 不需要从头写
.gitignore
文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用。所有配置文件可以直接在线浏览:https://github.com/github/gitignore - 忽略文件的原则
- 忽略操作系统自动生成的文件,比如缩略图等;
- 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如
Java
编译产生的.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
忽略了,如果确实想添加该文件,可以用-f
强制添加到Gitgit add -f <filename>
- 可能是
.gitignore
写得有问题,需要找出来到底哪个规则写错了,可以用git check-ignore
命令检查$ git check-ignore -v App.class .gitignore:3:*.class App.class
.gitignore
文件本身要放到版本库里,并且可以对.gitignore
做版本管理
- 假设在Windows下进行Python开发,Windows会自动在有图片的目录下生成隐藏的缩略图文件,如果有自定义目录,目录下就会有
自定义git
- 让Git显示颜色
git config --global color.ui true
- 配置别名
--global
参数是全局参数,也就是以下命令在这台电脑的所有Git仓库下都有用- 配置Git的时候,加上
--global
是针对当前用户起作用的,如果不加,那只针对当前的仓库起作用
# 为 status 设置别名 st $ git config --global alias.st status # 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 config --global alias.unstage 'reset HEAD' 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配置文件都放在
.git/config
文件中 - 当前用户的Git配置文件放在用户主目录下的一个隐藏文件
.gitconfig
中[user] name = xxx email = xxxxxx@xxx.com [color] ui = true [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配置文件都放在
搭建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
- 先选定一个目录作为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
来管理公钥
- 如果团队很小,把每个人的公钥收集起来放到服务器的
- 管理权限
- 有很多不但视源代码如生命,而且视员工为窃贼的公司,会在版本控制系统里设置一套完善的权限控制,每个人是否有读写权限会精确到每个分支甚至每个目录下。因为Git是为Linux源代码托管而开发的,所以Git也继承了开源社区的精神,不支持权限控制。不过,因为Git支持钩子(
hook
),所以,可以在服务器端编写一系列脚本来控制提交等操作,达到权限控制的目的。Gitolite
就是这个工具
- 有很多不但视源代码如生命,而且视员工为窃贼的公司,会在版本控制系统里设置一套完善的权限控制,每个人是否有读写权限会精确到每个分支甚至每个目录下。因为Git是为Linux源代码托管而开发的,所以Git也继承了开源社区的精神,不支持权限控制。不过,因为Git支持钩子(