- Git 从新手走向专家
Git 从新手走向专家
Git 从新手走向专家,一站式服务,让你从一个对 Git 一无所知的小白,走向一个对 Git 了如指掌的专家。
1. 常见版本管理工具一览
1.1 VSS
VSS(Visual Source Safe),是 Microsoft Visual Studio 的一员,基于 C/S 架构的,只支持 windows 环境。(已被官方抛弃)
1.2 CVS
CSV(Concurrent Version System), 是中心版本控制系统,C/S 架构也是 C/S 架构的,买2009 停止维护,大多数服务改迁至 SVN 维护。
TFS
1.3TFS(Team Foundation Server), TFS 是微软系产品,Windows 下小型团队开发利器,支持 SVN,最新版也支持 Git 的。
AB
1.4AB(AlienBrain),针对计算机图象及数字娱乐项目的资产管理系统
SVN
1.5SVN(Subversion),是开源版本集中式版本控制系统,C/S 架构。
Git
1.6Git 开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。
2. SVN 和 Git 区别
2.1 仓库的组织结构不同
Git 属于分布式的仓库管理;SVN 属于中心式的仓库管理。
仓库的组织结构不同:Git 内部的对象层级依赖关系或许和 SVN 类似,工作树永远是一个完整的分支,不同的分支由不同的 head 索引去构建,同一时刻不可能出现在多个分支。
SVN 默认采用 FSFS 的数据库格式,分支、tag 等默认只是一个不同的路径而已,本质上和普通路径没什么区别的。
2.2 数据组织方式不同
Git 把内容按元数据唯一哈希算法存储,Git 数据完整性更好;SVN 按照文件来组织。
Git 把内容按照元数据方式存储,每次提交的文件全部内容(snapshot)都会记录,SVN 是按照文件存储的,存储每次提交(commit)之间的差异。
2.3 版本号的不同
Git 通过 SHA-1 哈希算法的唯一 commit 号辨识度低;SVN 更容易识别的全局唯一数字版本号。
2.4 权限控制
Git,只能针对仓库进行权限控制;SVN,可以对用户精确控制到文件级别的读写权限。
2.5 日志查看
Git 的代码日志是在本地的;SVN 日志在服务器上的,必须连网查看。
2.6 远程提交
Git 两段式提交:
git commit
–>git push
;SVN 一次性提交svn commit
。
2.7 远程更新
Git 使用
git fetch
或git pull
分段式更新;SVN 直接svn update
即可。
2.8 多分支协作
Git,使用
git checkout
来切切换分支;SVN,svn switch
切换分支协同工作。多模块合作,Git 的另一种解决方案 Git Submodule。
多分支协作: Git,使用 Checkout 后,只更新当前分支的内容的,不更新其他分支的,多分支操作一般是 fetch 远程分支 然后 merge 到当前分支的。
SVN,使用 Switch 可以在同一个工作树上,对不同的模块 checkout 不同分支上的代码。
3. Git 对象(object)
3.1 什么是对象
对象(object),表示版本历史信息的文件
通过一个 40 个字符的(40-digit)“对象名” 来索引的,对象名看起来像这样:
3ff87c4664981e243g625791c8ea3bbb5f2279a3
。对象名是对文件内容用 SHA1 哈希计算得来的,保证对象名的唯一性。
3.2 对象的构成
对象 = 类型 + 内容(内容取决于对象的类型) + 内容大小。
- blob – 用来存储文件数据,通常是一个文件;
- tree – 类似目录,用来管理一些 tree 和 blob;
- commit – 一个 commit 只指向一个 tree,标记项目某一个特定的时间点状态,包括一些时间点的是元数据,如 时间戳、最后一个提交者等;
- tag – 标记某一个 commit 的方法。
4. Git 的四区及使用时的数据转换
4.1 四区划分
本地 3 区:工作区(workspace)、暂存区(index)、本地仓库(local repository)
远程 1 区:远程仓库(remote repository)
4.2 四区间数据转换
工作区 暂存区 本地仓库 远程仓库 | --> add (-u) --> | | | | <-- checkout <-- | | | | <-- diff --> | | | | rm --cached <-- | | | | | --> commit --> | | | | <-- reset HEAD <-- | | | <----------- diff HEAD ------------> | | | -----------> commit -a ------------> | | | <----------- checkout HEAD <---------- | | | | | --> push --> | | | | <-- fetch <-- | | <----------- merge <----------- | | | <----------- pull or rebase <------------ |
5. Git 常用命令众生相
5.1 常用命令
$git help $git init $git clone url $git config –global user.name "user_name" $git config –global user.email "email@126.com" $git branch $git branch -a $git branch -d/D branch_name $git checkout -b new_branch_name $git checkout file_name $git fetch $git fetch –prune $git pull $git log $git show $git status -s $git diff $git add file_name $git mv file_A file_B $git rm file_name $git rm --cached file_name $git merge other_branch_name $git commit $git push
5.2 高级命令
$git commit --amend -m new_message //修改上次提交的msg $git blame -L 38,40 file_name //查看文件逐行修改 $git reset –head HEAD //回退到上个版 $git reset commit_hash //回退到指定的提交 $git revert HEAD //撤销最近操作 $git revert commit //撤销某次操作 $git stash //代码暂存 $git stash pop //代码取出 $git cherry-pick 38361a68 //复制一个提交的工作 $git tag //里程碑管理 $git rebase -i HEAD~4 //重新定义起点 $git clean -n //删除未被跟踪文件 $git reflog //查看所有分支操作 $git shortlog //日志的汇总查询 $git remote -v show [remote] //远程仓库操作 $git archive //生成可发布的压缩包 $git bisect start HEAD 4d83cf //二分查找错误开始 $git bisect good/bad //二分查找错误标记状态 $git gc --aggressive --auto //数据维护和恢复
5.3 奇技淫巧
$git branch -m old_name new_name //修改分支名 $git log --follow file_name //显示某个文件的历史 $git push origin --delete branch_name //删除远程分支-1 $git push origin :remote_branch_name //删除远程分支-2 $git branch -dr remote/branch_name //删除远程分支-3 $git push origin :refs/tags/tag_name //删除远程tag $git remote add short_name url //添加新别名的远程仓库 $git log –reverse -p //历史重演 $git show HEAD~1 //历史追溯 $git shortlog -sn --no-merges //提交次数排行榜 $git diff --shortstat "@{0 day ago}" //查看今天的代码行数 $git whatchanged --since='2 weeks ago' //查看最近两周的记录 $git config --global alias.st status //给命令起别名 $git bundle create file_name branch_name //把分支导出成文件 $git clone repo.bundle repo_dir -b branch_name //从包中导入分支
6. .gitignore 停止跟踪文件
文本文件 .gitignore 可以防止一些特定的文件进入到版本控制中。
查看所有项目中忽略的文件 $git ls-files --others --ignored --exclude-standard
规则 | 备注 |
---|---|
fd1/* | 忽略目录 fd1 下面的全部内容 |
/fd1/* | 忽略根目录下的 /fd1/ 目录的全部内容 |
!.gitignore | 不忽略 .gitignore 文件 |
!/fw/sf/ | 不忽略 根目录下的 /fw/sf/ 目录 |
7. git config 配置文件
7.1 文件路径
Linux、macOS 下
/etc/gitconfig 文件:包含了适用于系统所有用户和所有库的值。 –system
~/.gitconfig 文件:具体到你的用户。 –global
.git/config 文件:Git 目录的,
配置文件优先级: 3 > 2 > 1,优先级高的值覆盖优先级低的值。
Windows下
一般位于 C:\Documents and Settings$USER.gitconfig 下
7.2 可以配置的内容
姓名和邮箱(必须配置)、编辑器、比较工具、配置命令别名或自定义命令、配置显示颜色……
8. 安装使用管理
8.1 在 Linux 上安装
- Fedora :
$sudo yum install -y git
- Debian :
$sudo apt-get install -y git
- 更多系统安装
8.2 在 Windows 上安装
- Git
- msysGit
- GitHub for Windows
- Window GUI 支持: 4.1 TortoiseGit 4.2 Sourcetree 4.3 VSCode 插件。
8.3 认证方式
一般使用 ssh 认证,当然也可以使用 http。 http 方式的话,Github 只支持 Public 的库,私有库必须使用 ssh 方式。
8.4 仓库和权限管理
- 纯人肉
把所有用户的公钥保存在 authorized_keys 文件。
- 自己搭建 Git 服务器:
- 使用第三方平台:
9. 分支合并及冲突解决
9.1 git merge
9.1.1 fast-forward 合并
当待合并的分支比当前分支超前的话,会发生快速合并。
$git checkout master && git merge test HEAD HEAD | | master master | | A_0 --> A_1 --> A_2 --> B_1 ==> A_0 --> A_1 --> A_2 --> B_1 | | test test
9.1.2 –no-ff 合并
不想快速合并,加上 –no-ff 的非快速合并,会新建一个节点保留被合并记录。
$git checkout master && git merge –no-ff test HEAD HEAD | | master master | | A_0 --> A_1 --> A_2 ==> A_0 --> A_1 --> A_2 -------> A_3【新增】 \ \ / > B_1 > B_1 | | test test
9.1.3 –squash 合并
SVN 的合并方式,新增一个节点,但是不保留对被合并分支的引用信息。
$git checkout master && git merge –squash test HEAD HEAD | | master master | | A_0 --> A_1 --> A_2 ==> A_0 --> A_1 --> A_2 -------> A_3【新增】 \ \ > B_1 > B_1 | | test test
9.4 git rebase
当要合并两个分叉的分支时
- merge 是将待合入分支和当前分支不同的部分,在当前分支新建节点。
$git checkout master && git merge –no-ff test HEAD HEAD | | master master | | A_0 --> A_1 --> A_2 ==> A_0 --> A_1 --> A_2 --> A_3【新增】 \ \ / > B_1 > B_1 | | test test
- rebase 会将合入分支上超前的节点在待合入分支上重新提交一遍。
$git checkout master && git rebase test HEAD HEAD | | master master | | A_0 --> A_1 --> A_2 ==> A_0 --> A_1 --> A_2 --> B_1'【从新提交 B_1】 \ \ > B_1 > B_1 | | test test
9.5 git cherry-pick
只合并某一个分支的某一个特定节点,而不是分支所有的记录。
$git checkout master && git cherry-pick B_1 HEAD HEAD | | master master | | A_0 --> A_1 --> A_2 ==> A_0 --> A_1 --> A_2 --> B_1【复制 B_1】 \ \ > B_1 -> B_2 > B_1 --> B_2 | | test test
9.6 冲突解决
不同分支修改同一份文件时,在合并时可能出现冲突。比如
$git merge feature1 Auto-merging readme.txt CONFLICT (content): Merge conflict in readme.txt Automatic merge failed; fix conflicts and then commit the result.
Git用 <<<<<<<,=======,>>>>>>> 标记出不同分支的内容,比查看 readme.txt 如:
<<<<<<< HEAD Creating a new branch is quick & simple. ======= Creating a new branch is quick AND simple. >>>>>>> feature1
我们修改如下后保存:
Creating a new branch is quick and simple.
保存后再提交:
$git add readme.txt && git commit -m "conflict fixed"
10. 团队开发实践之 GitFlow
10.1 什么是 Gitflow
Gitflow,一个荷兰人 nvie 提出的一个基于 Git 版本开发的模型,包括以下内容:
- master 分支,1 个,总是稳定版本的代码,随时可发布;
- develop 分支,1 个,合并 feature 分支的,可用于创建 release 版本。
- feature 分支,同时存在多个;
- release 分支,同一时间只有 1 个,周期很短,为了发布版本;
- hotfix 分支,同一时间只有 1 个,周期较短,用来修复 bug 或小粒度修改发布。
10.2 图解 GitFlow
10.3 GitFlow 的模型使用
11. 基于 Git 的高效团队协作
11.1 Git + Jenkins 自动化集成
git 提交代码后 –> 自动或手动触发 jenkins 执行相应脚本 –> 查看构建历史。
11.2 通过编程实现 Git 的自动化
11.3 Git + Jira 高效开发
在 Jira 中查看 Git 提交,分支,标签和请求。
连接 git 服务器 + GitHub、Bitbucket、GitLab 和 Azure、Repos、VSTS/TFS
12. 杂项:子模块钩子和大文件管理
12.1 GIT Submodule
GIT Submodule,项目间是独立的,但是项目需要使用其他项目的时候。
$git submodule add sub_project_url add_path //添加子项目 $git submodule init //初始化子模块 $git submodule update --recursive //更新子模块 $git submodule foreach git pull //更新所有子模块 //以下为删除子模块操作 $rm -rf sub_project_dir //删除子模块目录及源码 $vi .gitmodules //删除项目目录下子模块相关条目 $vi .git/config //删除配置项中子模块相关条目 $rm .git/module/* //删除模块下的子模块目录 $git rm --cached sub_project_name
12.2 Git 钩子
Git 钩子:在特定的重要动作发生时触发自定义脚本,分客户端和服务端钩子。
12.2.1 钩子的基本概念
位置:在 Git 目录下的 hooks 子目录中。 即项目中 .git/hooks 。
客户端钩子:提交工作流钩子、电子邮件工作流钩子和其它钩子。服务端钩子:对项目强制执行各种类型的策略。
任何可执行的文件都可以作为钩子的脚本。
12.2.1 钩子样例(commit-msg)
#!/usr/bin/env python # coding=utf-8 # commit msg checker import sys, re, io if hasattr(sys.stdout, 'buffer'): sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') TIPS_INFO = ''' 不符合 commit 规范,提交失败(当前状态等于没做刚刚的 commit 操作),请按下面规则从新提交! commit 规范: 类型: 详细消息 说明: 类型 - 功能、优化、Bug; 连接符 - 英文冒号 + 空格,即 “: ”; 详细信息 - 自定义描述,当类型是 Bug 时,详细信息必须要包括 Jira 上的Bug 标识 “OTDEFECT-” 或 “修复” 字样。 规范样例: 1. 功能: 匹配增加接受确认步骤 2. 优化: 天梯匹配分组优化 3. Bug: OTDEFECT-1001 当通过玩家ID搜索站内信时,结果能返回但是标题等字段返回值为空 4. Bug: 修复通过接口不能踢人的问题 ''' def check_commit_line1_format(msg): regOther = r'\S{3,} (.){4,100}' if msg.find("功能") != 0 and msg.find("优化") != 0 and msg.find("Bug") !=0 and msg.find(": ") != -1: return False if msg.find("Bug") == 0 and msg.find("OTDEFECT-") != -1 and msg.find("修复") != -1: return False matchObj = re.match(regOther, msg) return matchObj if __name__=="__main__": with open(sys.argv[1], 'r', encoding='utf-8') as f: for line in f: if (check_commit_line1_format(line)): sys.exit(0) else: print(TIPS_INFO) sys.exit(1)
12.3 Git LFS
GIT 提交文件,不要超过 100M,GitHub 超过 50M 警告、超过 100M 禁止。
Git LFS 是 Github 开发的一个 Git 的扩展,用于实现 Git 对大文件的支持。
在 Working with large files - GitHub Help 中提到:不建议对大文件如日志、database 等使用 Git 进行版本控制,如果非要有这种需求,则建议使用 Git LFS。
12.3.1 安装
注意:安装 Git LFS 需要 Git 的版本不低于 1.8.5。不管什么系统,安装后都需要全局初始化一次。
- Linux
$curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash $sudo apt-get install git-lfs $git lfs install
- Mac
//安装 HomeBrew $/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" $brew install git-lfs $git lfs install
- Windows
- 下载:git-lfs
- 运行 windows installer(git-lfs-windows-v2.8.0.exe)
- 在命令行执行
$git lfs install
12.3.2 使用
$git lfs install //需要在项目根目录执行一次,初始化 $git lfs track README.md //跟踪大文件 $git lfs track //显示被跟踪的文件 $git add .gitattributes //需要跟踪记录大文件信息 .gitattributes 文件 $git add README.md $git commit -m "Add README.md and init git-lfs" $git push $git lfs clone URL //lfs clone ,或者直接 git clone
12.3.3 相关资源
- git-lfs
- git-lfs - windows
- git-lfs - Release
- git-lfs - 参考
- lfs 删除文件
- 使用 filter-branch 从 Git 历史中删除一个文件
- 使用 BFG Repo-Cleaner 清除 git 的历史错误提交