Version Control(git)
# Version Control (git)
因为上层的命令写得较为杂乱,推荐自底向上的学习方式,能帮我们更好地理解
Git
。
# 架构图
# 本地仓库
git add
: 创建blob索引,生成哈希。(所有被git track的文件都能保证不会再丢失!)stagedgit commit
:把 file/blob 纳入本地仓库
管理
# 远程仓库
# 底层实现
以伪代码的形式来学习 Git 的数据模型,可能更加清晰:
// 文件就是一组数据
type blob = array<byte>
// 一个包含文件和目录的目录
type tree = map<string, tree | blob>
// 每个提交都包含一个父辈,元数据和顶层树
type commit = struct {
parent: array<commit>
author: string
message: string
snapshot: tree
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
使用了一个 map 来存储所有的文件
objects = map<string, object>
def store(object):
id = sha1(object)
objects[id] = object
def load(id):
return objects[id]
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
更详细的内容要画图,参考 get 官方文档吧
# 常用命令
# 基本操作
git init
git clone xxxxxxxx
git add #---》 精确地将内容添加到下一次提交中【文件提交,将文件交给 git 管理】
git diff #---》 比较不推荐用给官方给的来比较文件的差异,推荐使用其他的图形化的工具,例如 git小乌龟
# 查看暂存区状态
git status
# ---》 git checkout — <file> 是一个危险的命令。 你对那个文件在本地的任何修改都会消失——Git 会用最近提交的版本覆盖掉它。
git commit -a -m "提交备注" # ---》 会将当前 git 目录下的所有文件都放到跟踪区,并且作为一次 commit 提交
# 查看提交历史
git log --all --graph --decorate
# 移动操作
$ git mv README.md README
$ mv README.md README
$ git rm README.md
$ git add README
【撤销操作】
# 有时候我们提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了。 此时,可以运行带有 --amend 选项的提交命令来重新提交:
# 完全用一个 新的提交 替换旧的提交
$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
.gitignore
配置 :GitHub 有一个十分详细的针对数十种项目及语言的.gitignore
文件列表, 你可以在 https://github.com/github/gitignore (opens new window) 找到它。
# 分支操作
git branch 命令仅仅 创建 一个新分支,并不会自动切换到新分支中去。
通常我们会在创建一个新分支后立即切换过去,这可以用 git checkout -b <newbranchname> 一条命令搞定。
当你试图合并两个分支时, 如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者的时候, 只会简单的将指针向前推进(指针右移),因为这种情况下的合并操作没有需要解决的分歧——这就叫做 “快进(fast-forward)”。
1
2
3
4
5
2
3
4
5
使用 rebase
命令将提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一样。
- 变基是将一系列提交按照原有次序依次应用到另一分支上,而合并是把最终结果合在一起。
$ git rebase --onto master server client
1
以上命令的意思是:“取出 client
分支,找出它从 server
分支分歧之后的补丁, 然后把这些补丁在 master
分支上重放一遍,让 client
看起来像直接基于 master
修改一样”。
git rebase hotfix master
git checkout master
git merge hotfix
1
2
3
4
2
3
4
- 将
hotfix
中的修改变基到master
上 (opens new window) 所示,hotfix
中的代码被“续”到了master
后面。
# rebase 的风险
如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。
如果你遵循这条金科玉律,就不会出差错。 否则,人民群众会仇恨你,你的朋友和家人也会嘲笑你,唾弃你。
git自带的修复方式:git rebase teamone/master
。或者修改git 仓库配置
最好只对自己本地的代码库进行rebase
操作,或者是自己独有的分支进行变基
操作(推到远端但是自己私有的分支)。如果你对已经推送至共用仓库的提交上执行变基命令(不可对公有的远端分支执行rebase操作
),并因此丢失了一些别人的开发所基于的提交, 那你就有大麻烦了,你的同事也会因此鄙视你。
总的原则是,只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作,这样,你才能享受到两种方式带来的便利。
# Remote Repo
# Command
都是以 git remote 打头的一些命令,操作远程仓库的
git remote [-v | --verbose]
git remote add [-t <branch>] [-m <master>] [-f] [--[no-]tags] [--mirror=(fetch|push)] <name> <URL>
git remote rename [--[no-]progress] <old> <new>
git remote remove <name>
git remote [-v | --verbose] show [-n] <name>…
git remote prune [-n | --dry-run] <name>…
git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)…]
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
运行 `git remote add <shortname> <url>` 添加一个新的远程 Git 仓库,同时指定一个方便使用的简写
当你想分享你的项目时,必须将其推送到上游。 这个命令很简单:`git push <remote> <branch>`。
【prune】
在本地存在但已经在远程仓库中被删除的远程分支
1、git remote prune
2、git fetch prune
3、git config配置自动删除 ---》 推荐
git config remote.<remote_name>.prune true
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 从远端拉取一个项目
$ mkdir project.git
$ cd project.git
$ git init
$ git remote add -f -t master -m master origin git://example.com/git.git/
$ git merge origin
1
2
3
4
5
2
3
4
5
- 如果将
-t
和-m
参数同时使用- -t:track,跟踪;-m:merge,合并
- 跟踪表示会强制把本地的巴斯特分支给去除强制覆盖,merge 会将远端的 master 分支给强制合并进来。保证了本地的 master 分支和远端的 master 分支是强一致的
# tag
默认情况下,git push 命令并不会传送标签到远程仓库服务器上。 在创建完标签后你必须显式地推送标签到共享服务器上。 这个过程就像共享远程分支一样——你可以运行 git push origin <tagname>。
使用 git push <remote> --tags 推送标签并不会区分轻量标签和附注标签, 没有简单的选项能够让你只选择推送一种标签。
git push origin v1.0
git push origin --tags
1
2
3
4
5
6
2
3
4
5
6
# Others
# 效率提升
# 取别名alias
git config --global alias.st "status -sb"
git config --global alias.ll "log --oneline"
git config --global alias.lg "log --all --graph --decorate"
git config --global alias.cm "commit -m"
git config --global alias.rv "remote -v"
git config --global alias.d "diff"
git config --global alias.gl "config --global -l"
git config --global alias.se "!git rev-list --all | xargs git grep -F"
git config --global help.autocorrect 20
git config --global credential.helper cache
# 避免变基错误
git config --global pull.rebase true
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 杂项
# 名词解释
- 裸仓库:包含点 git 的夹子
- 本地协议:本地文件的传输协议
- https协议、ssh协议:这是我们常用的两种拉取推送协议
# 拓展资料
- [x] How to explain git in simple words (opens new window);帮助理解数据结构,一个blob就是一个file,不同的哈希指向 file 的不同 snapshot。
- [x] Pro Git (opens new window) ,强烈推荐!学习前五章的内容可以教会您流畅使用 Git 的绝大多数技巧,因为您已经理解了 Git 的数据模型。后面的章节提供了很多有趣的高级主题。(Pro Git 中文版 (opens new window));
- [x] Learn Git Branching (opens new window) 通过基于浏览器的游戏来学习 Git ;【动画式的学习每个snapshot之间的关系】
- Oh Shit, Git!?! (opens new window) ,简短的介绍了如何从 Git 错误中恢复;
- Git for Computer Scientists (opens new window) ,简短的介绍了 Git 的数据模型,与本文相比包含较少量的伪代码以及大量的精美图片;
- Git from the Bottom Up (opens new window)详细的介绍了 Git 的实现细节,而不仅仅局限于数据模型。好奇的同学可以看看;
# 帮助
- 图形用户界面: Git 的 图形用户界面客户端 (opens new window) 有很多,但是我们自己并不使用这些图形用户界面的客户端,我们选择使用命令行接口
- Shell 集成: 将 Git 状态集成到您的 shell 中会非常方便。(zsh (opens new window), bash (opens new window))。Oh My Zsh (opens new window)这样的框架中一般以及集成了这一功能
- 编辑器集成: 和上面一条类似,将 Git 集成到编辑器中好处多多。fugitive.vim (opens new window) 是 Vim 中集成 GIt 的常用插件
- 工作流: 我们已经讲解了数据模型与一些基础命令,但还没讨论到进行大型项目时的一些惯例 ( 有很多 (opens new window) 不同的 (opens new window) 处理方法 (opens new window))
- GitHub: Git 并不等同于 GitHub。 在 GitHub 中您需要使用一个被称作拉取请求(pull request) (opens new window)的方法来向其他项目贡献代码
- 其他 Git 提供商: GitHub 并不是唯一的。还有像 GitLab (opens new window) 和 BitBucket (opens new window) 这样的平台。