简介
Git 是一个免费的开源分布式版本控制系统,用于高效地处理从小型到大型的各种项目。它由 Linus Torvalds 于 2005 年创建,旨在管理 Linux 内核开发。Git 以其速度、数据完整性和分布式工作流的灵活性而闻名,已成为软件开发中最受欢迎的版本控制工具之一。
原理(https://git-scm.com/book/en/v2)
其本质是一个基于 Key-Value 的内容寻址文件系统,核心部分是一个简单的键值对数据库(key-value data store)
1 git文件系统的结构如下
COMMIT_EDITMSG最后一次提交备注信息
FETCH_HEAD 保存了远程仓库中每个分支
ORIG_HEAD当前分支最新的提交
config 文件包含项目特有的配置选项
description 文件仅供 GitWeb 程序使用
hooks 目录包含客户端或服务端的钩子脚本(hook scripts)
info 目录包含一个全局性排除(global exclude)文件
packed-refs 拉取远端的所有分支,标签
refs 目录存储指向数据(分支、远程仓库和标签等)的提交对象的指针
logs引用日志数据
HEAD 文件指向目前被检出的分支
objects 目录存储所有数据内容
index 文件保存暂存区信息。
2 objects 存储方式
在 Git 文件系统中,使用Object 存储所有类型的内容,也称为 Git 对象,不同类型的 Object 共同构成了一整套对象模型。
3 Git 对象模型主要包括以下 4 种对象
● 二进制对象(Blob Object)存储文件内容。
● 树对象(Tree Object)目录类型文件
● 提交对象(Commit Object)
● 标签对象(Tag Object)
在 Git 文件系统中,使用一个 40 位的 SHA-1 值 作为一个文件或目录存储内容时所占用的,一个 Object 文件的唯一标识符,在进行匹配查找时候,其中前 2 位 SHA-1 值作为存储子目录,后 38 位 SHA-1 值作为文件名。
git所有对象均存储在 .git/objects/ 目录下,并采用相同格式进行表示: 类型 + 空格 + 存储内容
可以使用底层命令 git cat-file 来查看仓库的一个 git Object 的存储内容
查看对象的类型 git cat-file -t SHA-1
查看对象的内容长度 git cat-file -s SHA-1
查看对象的内容 git cat-file -p SHA-1
下面分析下提交对象
下图是一个提交对象(Commit Object)
tree aaaa5e107a54b94dc11d45420a31cbd6c77cb244: 表示提交文件所处的文件目录
parent 7557a68d51cfa50194c8be76e4b59e787a2d26e9: 上一次提交所生成的哈希值
分析下树对象(Tree Object)目录类型文件
里面包含了下一级的树对象(Tree Object)以及二进制对象(Blob Object)可以进一步通过git cat-file -p SHA-1命令查看内容
如果直接查看二进制对象(Blob Object)可以直接看到文件的具体内容
4 包文件
如果两次提交同一个文件,Git 也会用一个全新的对象来存储新的文件内容,你的磁盘上现在有两个几乎完全相同的对象。
如果 Git 只完整保存其中一个,再保存另一个对象与之前版本的差异内容,岂不更好?
事实上 Git 可以那样做。 Git 最初向磁盘中存储对象时所使用的格式被称为“松散(loose)”对象格式。 但是,Git 会时不时地将多个这些对象打包成一个称为“包文件(packfile)”的二进制文件,以节省空间和提高效率。 当版本库中有太多的松散对象,或者你手动执行 git gc 命令,或者你向远程服务器执行推送时,Git 都会这样做。 要看到打包过程,你可以手动执行 git gc 命令让 Git 对对象进行打包,这样可以大大节约你的磁盘存储
下面是手动进行git gc 命令后的文件夹
打包后还保留着的几个文件夹的对象是未被任何提交记录引用的数据对象
剩下的文件会新创建的包文件和一个索引
Git 打包对象时,会查找命名及大小相近的文件,并只保存文件不同版本之间的差异内容。
你可以查看包文件,观察它是如何节省空间的。 git verify-pack 这个底层命令可以让你查看已打包的内容:
git使用
Mac上安装git方法:通过Xcode安装 $ xcode-select --install
配置git用户信息(git提交所带的用户信息):
git config user.name ; git config —global user.name
git config email ; git config —global user.email
注意事项:在同一台电脑上更换gitlab的账号时需要把电脑钥匙串里面之前存储的账号密码删除。
1 Git本地操作
工作区:我们平时编辑代码的目录文件夹
暂存区:用于临时存放你的改动(git add .)
提交修改到本地:只提交暂存区的修改: git commit git commit -m “提交信息”
把暂存区的修改回退到工作区: git reset HEAD flie
丢弃工作区的修改: git checkout -- file
回退到上一次的提交: git reset -- hard HEAD^
回退到某一次提交:
● git log 获取某一次的提交commitId
● git reset -- hard commitId
恢复回退的提交: git reflog获得commitId
2分支管理
远程库克隆: git clone 远程库地址
查看远程库的信息: git remote
查看远程库详细信息: git remote -v
创建分支同时切换分支: git checkout -b 分支名或者: git switch -c 分支名
创建分支: git branch 分支名
切换分支: git checkout 分支名或者: git switch 分支名
查看分支: git branch
推送分支: git push origin 分支名字
分支合并: git merge 要合并的分支名字 或者: git merge --no-ff -m “提交信息” 分支名
当前分支变基到目标分支(即 master)上:git rebase master
server分支变基到目标分支(即 master)上:git rebase master server
选中在 client 分支里但不在 server 分支里的修改,将它们在 master 分支上重放作为 client 分支: git rebase --onto master server client
将某一个分支中的一段提交同时应用到其master分支中: git rebase commit1 commit2 --onto master
删除某一个分支的一系列提交: git rebase --onto 分支名~5 分支名~3 分支名(需要未push的提交,否则需要强制push)
交互式变基(交互式变基可以把多个提交合并成一个提交): git rebase -i master (操作未推到服务器的提交)
指定的提交(commit)应用于其他分支: git cherry-pick commitID
指定的多个提交应用于其他分支: git cherry-pick commitID1 commitID2
转移一系列的连续提交: git cherry-pick commitID1..commitID2
删除本地分支: git branch -d 分支名
强行删除分支: git branch -D 分支名
删除远程分支: git push origin --delete 分支名
回滚远程提交:
● 本地代码回滚到某一次提交: git reset --hard commitID
● 加入-f参数,强制提交,远程端将强制跟新到reset版本: git push -f origin 分支名
3 储藏功能
储藏功能 把当前工作现场“储藏”起来: git stash 或者: git stash save “信息”
恢复暂存恢复后,stash内容并不删除: git stash apply
恢复暂存恢复后,stash内容删除: git stash pop
查看暂存列表: git stash list
恢复某一个暂存: git stash apply stash@{0}
4 标签管理
默认标签是打在当前的内置最新提交的commit上的.
查看所有标签: git tag
打新标签: git tag 标签名
打之前提交的标签:
● Git log找到历史提commit id, 然后打上: git tag 标签名 commitId
● 还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字: git tag -a 标签名 -m “标签说明” commitId
看标签的文字说明: git show 标签名
删除标签: git tag -d 标签名
推送某个标签到远程: git push origin 标签名
一次性推送全部尚未推送到远程的本地标签: git push origin --tags
删除远程标签:
● 先删除本地标签
● 然后: git push origin :refs/tags/标签名
Sourcetree使用
1 是否展示暂存区
建议平时使用时候打开暂存区,这样避免一些不想提交的文件,比如一些环境的配置等直接提交上去
2 merge操作
把目标分支合并到当前分支
如果你想要合并某一分支的某一提交节点到当前分支,也可以直接使用merge操作,像下图那样。这样某个提交节点之前的所有提交会合并到当前分支
3 rebase操作(https://git-scm.com/docs/git-rebase)
使用场景:
变基基础功能和合并类似,起到分支合并的作用,而且使用变基操作可以保持当前分支提交记录的整洁性,使我们可以更容易查看分支的提交记录。未推送过远端,或者一个人开发一个分支,没有进行合并操作的情况下,的时候可以放心的在你自己的分支上使用rebase操作。
有时候当我们执行commit操作之前忘记pull远端分支会造成。拉取失败,这个时候我们可以勾选上用变基代替合并,可以让代码拉取下来
变基还有一些更加强大,方便与我们的操作,在下面的交互式变基会详细讲解,先说下变基的基本操作
变基实现的过程:git会从两个分支的共同(待变基分支,变基到的分支)的第一个提交节点开始提取待变基(一般是当前分支)分支上的修改,然后将待变基分支指向基分支的最新提交,最后将刚才提取的修改应用到基分支的最新提交的后面
rebase后
注意事项:尽量在你未推送过远端的时候才进行rebase操作
● 如果多人开发同一个分支的时候如果你已经push过,基分支又有改动,这个时候进行rebase操作的时候后,另外一个人在push代码就会出现错误。
思考总结meger和rebase:
相同点:都可以进行两个分支合并
不同点:
● 合并可以保存整个历史记录,变基可以创建线性历史记录,难以追溯历史,可能会造成提交丢失,
● 使用sourcetree解决冲突时候,使用“我的版本”解决冲突,使用“他人的版本”解决冲突是相反的
● rebase可以让某一段提交合并到分支上,也可以删除某各分支上的某一段提交,等等
meger只能合并某一个提交之前的所有的提交合并到某一个分支上
4 interactive Rebase 操作
使用场景:
● 可以把多次提交合并成一次提交,比如你调试某个功能,或者修复某个bug时候进行了多次提交,这个时候可以把这些提交合并成一次提交,保持功能的完整性。
● 修改历史提交记录,可以使你的提交看起来更加的友好
● 修改历史提交顺序
● 修改历史提交,例如将中间的某一次分割成多次提交,保证功能的独立性
● 删除历史提交,比如你提交记录中的任意某一次提交的功能,或者修改不想要了,可以使用该功能,和下面的提交回滚比较提交的纪录也会被删除。
这些功能保证提交记录的整洁性,提高review代码的效率
更多其他的功能可以使用git命令实现
注意事项:
需要是未push的提交,否者只能强制push(sourcetree设置成允许强制push,sourcetree语言设置为英文时有这个设置选项)
强制推送可能会导致数据丢失,所以在使用它之前,应该与团队成员沟通,确保你有完整的备份,确保这个操作是安全的
5 重置提交
把分支重置到某一个提交节点,比如:你的分支合并错了,或者刚提交功能产品不要了,提交的bug修改错误等等
下面看下具体操作
软合并:将此次提交回滚到指定提交位置,但这个过程中会将修改过的文件暂存到暂存区
混合合并:将此次提交回滚到指定的位置,但这个过程中不会将修改过的文件暂存到暂存区,而是将修改过的文件存放在工作区
强行合并:将此次提交回滚到指定的位置,但这个过程中将直接丢弃之前修改的所有文件
● 回滚本地的提交
根据实际需求选取合并类型,再点击确定即可
● 回滚远程提交(不建议)
注意事项:不建议进行此操作
1.先按照上面回滚本地提交的操作重置到某次提交,
2.强制push(sourcetree设置成允许强制push,sourcetree语言设置为英文时有这个设置选项)
6 提交回滚(把某一次提交回滚掉,本地远程都可以)
当我们开发的时候某一次提交的功能,不想要了,可以使用这个操作
注意事项:会有提交记录,和回滚记录
7 patch
应用场景:可以灵活的把某些提交记录,应用到其他分支,在某些极端情况下我当前分支只想要另一个分支的某几个提交,比如向测试在我的分支功能上模拟在另一个分支修复的某个bug,或者是产品是想上线某个分支上的一部分功能。避免再人工写一遍代码,这样提高效率,避免出错,和人工再一次修改相比合并代码的时候,也不会有冲突
● 创建补丁(生成一个.diff文件)
注意事项:
- 点击创建前注意选择好存储位置
-
可以把多个提交记录一块创建补丁
● 应用补丁
注意点:
sourcetree工作区或者暂存区有内容时候右键该区域有应用补丁的入口,或者通过sourcetree—>动作—>应用补丁
8 cherry-pick
应用场景:把某些提交记录,应用到其他分支,和上面的patch使用场景类似
● cherry-pick patch区别:
cherry-pick 操作比较快捷,patch可以把生成的.diff文件发送给别人使用,也可以对未提交的改变创建补丁。
● cherry-pick, merge区别:
merge只能合并某一个提交之前的所有的提交记录合并到某一个分支上,会把整个分支上的所有修改都合并过来。cherry-pick可以灵活的操作某一个或者某些提交
9 stash(可以跨分支使用)
使用场景:把暂时不提交的代码修改存贮下来以便下次使用,比如在某一个分支还没开发完的功能暂时存储下来,切换到另一个分支紧急开。或者把某些公用的调试代码暂存起来在多个分支上使用
10 tag
使用场景: 可以在某个版本发布后打上标签用于记录,如果你在版本打包上线后,打了tag,发现审核未通过,又进行了一些修改,这个时候如果版本号没有变化,你可以不必删掉这次tag重新打tag,可以使用下面的移动标签的功能
移动标签功能:(已经打好的标签移动提交节点)
● 在“标签名称”列中,键入要移动的现有标签。
● 在高级选项下,选中“ 移动现有标签 ” 框。通过点击下面的按钮(箭头指向)指定要移动的提交:
11 checkout
把HEAD指向任何一个提交记录,以便进行其他操作,比如,以这个节点创建新分支
12 存档
以某个提交节点把工程存储到某个文件夹下