Pro Git
2022-05-24 23:17:16 20 举报
AI智能生成
git
作者其他创作
大纲/内容
1.起步
版本控制系统分类
本地版本控制系统
集中化
分布式
git基础
直接记录快照,而非差异比较
近乎所有操作都是本地执行
Git 在本地磁盘上就保存着所有当前项目的历史更新
时刻保持数据完整性
时刻保持数据完整性
多数操作仅添加数据
文件的三种状态
状态
已修改
已暂存
已提交
图示
子主题
2.基础
获取git仓库
在工作目录中初始化新仓库
从现有仓库克隆
git clone [url]
记录每次更新到仓库
已经暂存起来的文件和上次提交时的快照之间的差异
git diff --cached
提交更新
git commit
跳过使用暂存区域
git commit -a
移除文件
git rm <file>
从已跟踪文件清单中移除(确切地说,是从暂存区域移除), 并连带从工作目录中删除指定的文件,这样以后就不会出现在未跟踪文件清单中了
移动文件并改名
git mv file_from file_to
等价
$ mv README.txt README
$ git rm README.txt
$ git add README
$ mv README.txt README
$ git rm README.txt
$ git add README
检查当前文件状态
git status
跟踪新文件/存放到暂存区
git add <file/url>
忽略某些文件
.gitignore
查看尚未暂存的文件更新了哪些部分
git diff
比较的是工作目录中当前文件和暂存区域快照之间的差异,也就是修改之后还没有暂存起来的变化内容。
查看提交历史
git log
撤消操作
修改最后一次提交
git commit --amend
取消已经add暂存的文件
git reset HEAD <file>...
取消对文件的修改
git checkout -- <file>...
远程仓库的使用
查看当前的远程库
git remote -v
添加远程仓库
git remote add [shortname] [url]
抓取目标远程仓库最新信息
git fetch [remote-name]
会到远程仓库中拉取所有你本地仓库中还没有的数据。运行完成后,你就可以在本地访问该远程仓库中的所有分支
fetch 命令只是将远端的数据拉到本地仓库,并不自动合并到当前工作分支
推送数据到远程仓库
git push [remote-name] [branch-name]
查看远程仓库信息
git remote show [remote-name]
远程仓库的删除
git remote rename [oldName] [newName]
对远程仓库的重命名,也会使对应的分支名称发生变化
远程仓库重命名
git remote rm [remoteName]
打标签
同大多数 VCS 一样,Git 也可以对某一时间点上的版本打上标签。人们在发布某个软件版本(比如 v1.0 等等)的时候,经常这么做
列显已有的标签
git tag
3.分支
何谓分支
提交对象
在 Git 中提交时,会保存一个提交(commit)对象,该对象包含一个指向暂存内容快照的指针,包含本次提交的作者等相关附属信息
当使用 git commit 新建一个提交对象前,Git 会先计算每一个子目录(本例中就是项目根目录)的校验和,然后在 Git 仓库中将这些目录保存为树(tree)对象。之后 Git 创建的提交对象,除了包含相关提交信息以外,还包含着指向这个树对象(项目根目录)的指针,如此它就可以在将来需要的时候,重现此次快照的内容了。
单提交对象数据结构
现在,Git 仓库中有五个对象:三个表示文件快照内容的 blob 对象;一个记录着目录树内容及其中各个文件对应 blob 对象索引的 tree 对象;以及一个包含指向 tree 对象(根目录)的索引和其他提交信息元数据的 commit 对象
多个提交对象之间的链接关系
作些修改后再次提交,那么这次的提交对象会包含一个指向上次提交对象的指针(译注:即下图中的 parent 对象)。两次提交后,仓库历史会变成图 3-2 的样子:
概述
本质上仅仅是个指向 commit 对象的可变指针。Git 会使用 master 作为分支的默认名字。在若干次提交后,你其实已经有了一个指向最后一次提交对象的 master 分支,它在每次提交的时候都会自动向前移动。
操作
查看
git branch
参数
-v : 连带最后一个提交对象的信息
--merge
查看当前分支的直接上游分支
--no-merge
尚未合并的分支
新增
git branch <branch-name>
切换
git checkout <branch-name>
HEAD 在你转换分支时指向新的分支, 并把工作目录中的文件换成了目标分支所指向的快照内容
参数
-b
分支不存在则创建
合并
git merge <branch-target>
讲目标分支合并入当前分支
特别情况
快进: fast forward
子主题
多祖先合并
子主题
冲突合并
删除
git branch -d <branch-name>
参数
d大写化: 强制删除
HEAD
Git 是如何知道你当前在哪个分支上工作的呢?其实答案也很简单,它保存着一个名为 HEAD 的特别指针
它是一个指向你正在工作中的本地分支的指针(译注:将 HEAD 想象为当前分支的别名。)
运行 git branch 命令,仅仅是建立了一个新的分支,但不会自动切换到这个分支中去
HEAD 指向当前所在的分支
为什么非常快
由于 Git 中的分支实际上仅是一个包含所指对象校验和(40 个字符长度 SHA-1 字串)的文件,所以创建和销毁一个分支就变得非常廉价。说白了,新建一个分支就是向一个文件写入 41 个字节(外加一个换行符)那么简单,当然也就很快了。
这和大多数版本控制系统形成了鲜明对比,它们管理分支大多采取备份所有项目文件到特定目录的方式,所以根据项目文件数量和大小不同,可能花费的时间也会有相当大的差别,快则几秒,慢则数分钟。而 Git 的实现与项目复杂度无关,它永远可以在几毫秒的时间内完成分支的创建和切换。同时,因为每次提交时都记录了祖先信息(译注:即 parent 对象),将来要合并分支时,寻找恰当的合并基础(译注:即共同祖先)的工作其实已经自然而然地摆在那里了,所以实现起来非常容易。Git 鼓励开发者频繁使用分支,正是因为有着这些特性作保障。
分支使用
长期分支
子主题
特性分支
特性分支是指一个短期的,用来实现单一特性或与其相关工作的分支
子主题
子主题
远程分支
概述
远程分支(remote branch)是对远程仓库中的分支的索引。它们是一些无法移动的本地分支;只有在 Git 进行网络交互时才会更新。远程分支就像是书签,提醒着你上次连接远程仓库时上面各分支的位置
与本地分支的区别
我们用 (远程仓库名)/(分支名) 这样的形式表示远程分支。比如我们想看看上次同 origin 仓库通讯时 master 分支的样子,就应该查看 origin/master 分支。如果你和同伴一起修复某个问题,但他们先推送了一个 iss53 分支到远程仓库,虽然你可能也有一个本地的 iss53 分支,但指向服务器上最新更新的却应该是 origin/iss53 分支。
更新远程分支信息
git fetch <remote-name>
从远程服务器获取你尚未拥有的数据,更新你本地的数据库,然后把 origin/master 的指针移到它最新的位置上
在 fetch 操作下载好新的远程分支之后(假设为serverfix),你仍然无法在本地编辑该远程仓库中的分支。换句话说,在本例中,你不会有一个新的 serverfix 分支,有的只是一个你无法移动的 origin/serverfix 指针。
推送本地分支
git push <remote-name>:<remote-branch>
你创建的本地分支不会因为你的写入操作而被自动同步到你引入的远程服务器上,你需要明确地执行推送分支的操作
跟踪远程分支
从远程分支 checkout 出来的本地分支,称为 跟踪分支 (tracking branch)。跟踪分支是一种和某个远程分支有直接联系的本地分支。在跟踪分支里输入 git push,Git 会自行推断应该向哪个服务器的哪个分支推送数据。同样,在这些分支里运行 git pull 会获取所有远程索引,并把它们的数据都合并到本地分支中来。
创建跟踪远程分支
在克隆仓库时,Git 通常会自动创建一个名为 master 的分支来跟踪 origin/master。这正是 git push 和 git pull 一开始就能正常工作的原因
git checkout -b [分支名] [远程名]/[分支名]
$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch refs/remotes/origin/serverfix.
Switched to a new branch "serverfix"
Branch serverfix set up to track remote branch refs/remotes/origin/serverfix.
Switched to a new branch "serverfix"
--track简化版:
git checkout --track [远程名]/[分支名]
git checkout --track [远程名]/[分支名]
简化版本
$ git checkout -b sf origin/serverfix
Branch sf set up to track remote branch refs/remotes/origin/serverfix.
Switched to a new branch "sf"
$ git checkout -b sf origin/serverfix
Branch sf set up to track remote branch refs/remotes/origin/serverfix.
Switched to a new branch "sf"
删除远程分支
git push [remote] --delete [branch-name]
推送空分支到远程
git push [远程名] :[分支名]
分支的变基(衍合): rebase
基本的变基
合并结果中最后一次提交所指向的快照,无论是通过衍合,还是三方合并,都会得到相同的快照内容,只不过提交历史不同罢了。衍合是按照每行的修改次序重演一遍修改,而合并是把最终结果合在一起。
命令
git rebase [主分支] [特性分支]
会先取出特性分支 server,然后在主分支 master 上重演
特别地:
git rebase [主分支]
当前操作的即是即是特性分支
风险
准则
一旦分支中的提交对象发布到公共仓库,就千万不要对该分支进行衍合操作。
建议
如果把衍合当成一种在推送之前清理提交历史的手段,而且仅仅衍合那些尚未公开的提交对象,就没问题
4.服务器上的git
协议
本地协议
$ git clone file:///opt/git/project.git
SSH协议
$ git clone ssh://user@server/project.git
优点
安全, 高效
缺点
不支持匿名访问
git协议
优点
现存最快的传输协议
缺点
缺少授权机制, 守护线程需要定制
HTTP/S 协议
优点
架设简便
缺点
客户端访问效率低, 传输效率和网络开销最差
5.分布式git
分布式工作流程
集中式工作流
集成管理员工作流
司令官与副官工作流
合作开发中的分支
项目的管理
6.git工具
修订版本(Revision)选择
交互式暂存
储藏
经常有这样的事情发生,当你正在进行项目中某一部分的工作,里面的东西处于一个比较杂乱的状态,而你想转到其他分支上进行一些工作。问题是,你不想提交进行了一半的工作,否则以后你无法回到这个工作点。解决这个问题的办法就是git stash命令。
“‘储藏”“可以获取你工作目录的中间状态——也就是你修改过的被追踪的文件和暂存的变更——并将它保存到一个未完结变更的堆栈中,随时可以重新应用
“‘储藏”“可以获取你工作目录的中间状态——也就是你修改过的被追踪的文件和暂存的变更——并将它保存到一个未完结变更的堆栈中,随时可以重新应用
操作
储藏
$ git stash
Saved working directory and index state \
"WIP on master: 049d078 added the index file"
HEAD is now at 049d078 added the index file
(To restore them type "git stash apply")
Saved working directory and index state \
"WIP on master: 049d078 added the index file"
HEAD is now at 049d078 added the index file
(To restore them type "git stash apply")
查看储藏列表
$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051... Revert "added file_size"
stash@{2}: WIP on master: 21d80a5... added number to log
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051... Revert "added file_size"
stash@{2}: WIP on master: 21d80a5... added number to log
应用储藏
git stash apply [stashName]
不指定储藏名默认最近的储藏
取消储藏
从储藏中创建分支
重写历史
改变最近一次提交
改变提交说明
$ git commit --amend
这会把你带入文本编辑器,里面包含了你最近一次提交说明,供你修改。当你保存并退出编辑器,这个编辑器会写入一个新的提交,里面包含了那个说明,并且让它成为你的新的最近一次提交。
改变你刚刚通过增加,改变,删除而记录的快照。
步骤
进行目标增补操作如git add .
git commit -amend
注意
使用这项技术的时候你必须小心,因为修正会改变提交的SHA-1值。这个很像是一次非常小的rebase——不要在你最近一次提交被推送后还去修正它。
修改多个提交说明
rebase工具
重排提交
交互式rebase工具
压制(Squashing)提交
拆分提交
filter-branch
过滤批处理
使用 Git 调试
子模块
子树合并
7.自定义git
8.git与其它系统
9.git内部原理
底层命令和高层命令
git对象
git对象
git系统的最小单元节点, 直接存储数据.
是一个简单的键值对数据库(String: Blob)。你可以向该数据库插入任意类型
的内容,它会返回一个键值,通过该键值可以在任意时刻再次检索该内容
是一个简单的键值对数据库(String: Blob)。你可以向该数据库插入任意类型
的内容,它会返回一个键值,通过该键值可以在任意时刻再次检索该内容
树对象
暂存区最小操作对象, 可以认为树对象就是我们项目的快照
树对象(tree object),它能解决文件名保存的问题,也允许我们将多个文件组织到一起。
Git 以一种类似于 UNIX 文件系统的方式存储内容。所有内容均以
树对象和数据对象(git 对象)的形式存储.
其中树对象对应了 UNIX 中的目录项,数据对象(git 对象)则对应文件内容。
一个树对象包含了一条或多条记录(每条记录含有一个指向 git 对象或者子树对象的 SHA-1 指针,以及相应的模式、类
型、文件名信息)。一个树对象也可以包含另一个树对象。
树对象(tree object),它能解决文件名保存的问题,也允许我们将多个文件组织到一起。
Git 以一种类似于 UNIX 文件系统的方式存储内容。所有内容均以
树对象和数据对象(git 对象)的形式存储.
其中树对象对应了 UNIX 中的目录项,数据对象(git 对象)则对应文件内容。
一个树对象包含了一条或多条记录(每条记录含有一个指向 git 对象或者子树对象的 SHA-1 指针,以及相应的模式、类
型、文件名信息)。一个树对象也可以包含另一个树对象。
提交对象
通过指定一个树对象和父提交对象, 创造一个提交对象
Git References
你可以执行像 git log 1a410e 这样的命令来查看完整的历史,但是这样你就要记得 1a410e 是你最后一次提交,这样才能在提交历史中找到这些对象。你需要一个文件来用一个简单的名字来记录这些 SHA-1 值,这样你就可以用这些指针而不是原来的 SHA-1 值去检索了。
在 Git 中,我们称之为“引用”(references 或者 refs,译者注
在 Git 中,我们称之为“引用”(references 或者 refs,译者注
基本引用
新增引用指向提交对象
$ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9
每当你执行 git branch (分支名称) 这样的命令,Git 基本上就是执行 update-ref 命令,把你现在所在分支中最后一次提交的 SHA-1 值,添加到你要创建的分支的引用。
HEAD 标记
HEAD一个指向你当前所在分支的引用标识符
tag对象
Tag 对象指向一个 commit 而不是一个 tree。它就像是一个分支引用,但是不会变化——永远指向同一个 commit,仅仅是提供一个更加友好的名字。
remote reference
Packfiles
The Refspec
高级传输协议
维护及数据恢复
其它资源
Git Pro
https://git.oschina.net/progit/index.html
在线git分支游戏
https://learngitbranching.js.org/?demo
0 条评论
下一页