Git学习记录
git官网书籍《Pro Git》
目录
- 基础
- 更新与提交:add, status, diff, commit, rm, mv
- 提交历史:log
- 撤销:restore
- 远程仓库: remote
- 标签:tag
- 别名
- .gitingore
- 分支
- 远程分支
- 变基:rebase
- 原理
- 对象
- 引用
- ...
Git基础
更新与提交
工作目录下的文件只有两种状态:已跟踪, 未跟踪,对于已跟踪的文件,只有暂存的文件才会被提交
git status查看状态git add <file>跟踪文件以及将文件暂存(staged)git diff查看未暂存的修改--staged或--cached查看暂存文件与上次提交的文件差异
git commit提交文件,提交前git status下确认所需文件是否在暂存区-a可跳过暂存阶段,直接将跟踪文件暂存提交
git rm <file>删除已跟踪文件。相当于rm <file>后,git add进暂存区,与创建文件后git add<file>对应个人理解,可能有误。
当<file>修改过或已暂存后,可使用:-f安全特性,防止未添加到快照的数据误删--cached仅仅从暂存区删除,文件还在
git mv <file_a> <file_b>等价于:$ mv file_a file_b $ git rm file_a $ git add file_b
查看提交历史
git log
-p或--patch,以补丁的格式输出每次提交的所引入的差异--stat每次提交的简略统计信息--pretty=oneline一行显示一条提交,其他样式--pretty=short,--pretty=full,--pretty=fuller仅信息详细程度不同--pretty=format自定义输出格式--graph更形象的显示分支-<n>如git log -2显示两条记录--since=<time_a>与--until=<time_b>,显示从time_a到time_b的提交--after=<time_a>与--before=<time_b>与上条相同-S <string>过滤器,只显示增加或删除该字符串的提交- 其他。。。
比如:
$ git log --pretty="%h - %s" --author='Junio C Hamano' --since="2008-10-01" \
--before="2008-11-01" --no-merges -- t/
-- t/指对t文件夹的提交
撤销操作
git commit --amend重新提交,替代上一次的提交结果,如:$ git commit -m 'initial commit' $ git add forgotten_file $ git commit --amendgit restore --staged <file>取消暂存git restore <file>撤销修改
上两条与《Pro Git》不同,可能更新了
远程仓库
git remote查看远程仓库-v显示远程仓库以及urladd <shortname> <url>添加新的远程仓库并指定简写show <remote>查看remote的信息rename <remote> <new_remote>远程仓库重命名remove <remote>或者rm <remote>移除remote仓库
git fetch <remote>访问remote仓库,拉取没有的数据git push <reomte> <branch>推送
标签
git tag列出所有标签可带-l或--list。
而标签分为轻量与附注,附注标签包含打标签人的信息、日期等,另外可以附加标签信息
git tag <tagname>创建轻量标签git tag -a <tagname> -m <tag_message>创建附注标签git tag -a <tagname> <commit>为commit打标签,commit为提交的完整或部分校验和git show <tagname>查看标签信息与对应的提交信息git push <remote> <tagname>推送标签,或git push <remote> --tags推送所有标签git tage -d <tagname>删除标签,同时git push <remote>:refs/tags/<tagname>或git push <remote> --delete <tagname>删除远程仓库的标签git checkout <tagname>检出标签
别名
敬请期待
Git分支
git branch列出分支-v查看每个分支的最后一次提交<branch>创建分支-d <branch>删除分支--merged和--no-merged已经与当前分支合并和未合并的分支
git checkout <branch>分支切换git checkout -b <branch>创建并切换分支
git merge <branch>合并分支- 顺着分支能到达另一分支时,只会简单的指针前进(右移),合并操作并无分歧,叫做
fast-forward - 两分支岔开(diverged),会与两分支的共同祖先三方合并,创建一个新的提交。而遇到冲突,即两个分支对同一文件进行修改,会进行合并但没创建提交,需修改后自行提交
- 顺着分支能到达另一分支时,只会简单的指针前进(右移),合并操作并无分歧,叫做
远程分支
远程跟踪分支检出本地分支会自动创建"跟踪分支"(所跟踪的分支称为上游分支),使用
git checkout -b <branch> <remote>/<branch>或git checkout --track <remote>/<branch>
而已有的本地分支需要跟踪或者修改上游分支则可以使用:
git branch -u <remote>/<branch>或着--set-upstream-to
同时可以使用@{u}或@{upstream}代表上游分支,如git merge @{u}代替git merge origin/main
可使用git branch -vv来查看本地与上游分支的更多信息
删除远程分支git push <remote> --delete <branch>
变基
git rebase <branch>
待续。。。
Git内部原理
太无聊了.git中重要文件:HEAD文件、index文件、objects目录、refs目录
objects目录
保存所有数据,以Key-Value存储。通过git hash-object演示存储效果:
$ echo "hello" | git hash-object -w --stdin
ce013625030ba8dba906f756967f9e9ca394464a
-w写入数据库,--stdin从标准输入读取,或直接git hash-object -w <file>。通过git cat-file读取数据:
$ git cat-file -p ce013625030ba8dba906f756967f9e9ca394464a
hello
只保存了文件内容没有文件名等信息,该类型对象称为数据对象(blob object)。通过-t读取数据类型
$ git cat-file -t ce013625030ba8dba906f756967f9e9ca394464a
blob
树对象
一个树对象有一条或多条树对象记录(tree entry),每条记录指向:文件模式、类型、数据对象或者子树对象的指针、文件名信息。
$ git cat-file -p main^{tree}
100644 blob 45f16d261584a37f3c3f3f631c7c08d0958baa2a init.lua
100644 blob 7bf88613cead41206b364137ca310a829645f228 lazy-lock.json
040000 tree aff0b5e3d38b57a379d538056f60fa6f7a386fd0 lua
提交对象
包含树对象的SHA-1值、父提交对象、作者信息以及提交注释
对象存储
假设数据为content = "hello",令header = "blob #{content.length}\0",
头部信息为对象类型 + 空格 + 数据的字节数 + 空字节。即blob 5\u0000
而store = heander + content,Git会对store计算SHA-1校验和(作为Key)。
由zlib压缩后即为对象的内容(Value)数据对象的content无限制但树对象与提交对象的内容固定
引用
.git/refs目录下的含有SHA-1值的文件
echo 1a410efbd13591db07496601ebc7a059dd55cfe9 > .git/refs/heads/mastergit update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9,git提供的方法更安全
Git分支的本质就是一个指向某一系列提交之首的指针或引用
HEAD引用
运行git branch <branch>时,通过HEAD文件获取最新提交的SHA-1值
HEAD文件通常是一个符号引用,即指向其他引用的指针
标签引用
除三种主要对象类型外,还有标签对象。
而标签就是一个引用
- 轻量标签:
$ git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d - 附注标签:
$ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 -m 'test tag' $ cat .git/refs/tags/v1.1 9585191f37f7b0fb9444f35a9bf50de191beadc2
先创建标签对象再通过引用指向标签对象,通过git cat-file -p得到:$ git cat-file -p 9585191f37f7b0fb9444f35a9bf50de191beadc2 object 1a410efbd13591db07496601ebc7a059dd55cfe9 type commit tag v1.1 tagger Scott Chacon <[email protected]> Sat May 23 16:48:58 2009 -0700 test tag标签对象并不一定需要指向提交对象,也可以为数据对象或树对象打标签
远程引用
保存在refs/remotes下。当添加了远程仓库并进行推送,Git会记录最近一次推送的每一个分支对应的值,并保存在refs/remotes目录下:
$ git remote add origin [email protected]:schacon/simplegit-progit.git
$ git push origin master
Counting objects: 11, done.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (7/7), 716 bytes, done.
Total 7 (delta 2), reused 4 (delta 1)
To [email protected]:schacon/simplegit-progit.git
a11bef0..ca82a6d master -> master
而查看refs/remotes/origin/master文件
$ cat .git/refs/remotes/origin/master
ca82a6dff817ec66f44342007202690a93763949
即为origin/master分支的SHA-1值
相对引用
^,例如HEAD^表示HEAD的上一次提交^{num},一个提交可能有多个父节点,num表示选择第几个父节点
~{num},例如main~3表示main的上三次提交
扩展
git branch -f <branch> <commit>将branch分支指向commit提交git switch -c <branch>等同于git checkout -b <branch>
撤销变更
git reset <commit>将当前分支回退到commit提交上git revert <commit>反做commit的操作后添加提交
待续。。。