Git 的进阶操作

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c4/c40423c15e0082f6ad677ef571694e7d.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"1. Git 进阶使用"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1.1. 版本历史更改"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1.1.1. 最近一次 commit 的 message 修改"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用如下命令就可以对最近一次 commit 的 message 进行变更了"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"git commit --amend "}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1.1.2. 老旧 commit 的 message 修改 --- rebase + reword"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"输入如下命令"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"git rebase -i hash_value # hash_value,是需要的 commit 的父亲 commit 的 hash_value"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"之后会发生一系列交互,比如你想"},{"type":"text","marks":[{"type":"strong"}],"text":"某个 commit 对应的message,那么将该 commit 之前的 pick 改为 reword"},{"type":"text","text":" 或者 r(看下面的注释信息),然后保存退出。之后就跳到了修改 message 的文档了,在这里输入改变之后的 message 保存退出即可。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b3/b3dabc3fe959d1fad197c5be93293adf.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}},{"type":"strong"}],"text":"注意:这种方式修改之后会导致该 commit 及后面 commit 的 hash_value 都被改变掉"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}}],"text":",所以不适合团队集成开发中使用。"}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1.1.3. 把连续的多个 commit 合并成一个 --- rebase + squash"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"输入如下命令,"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"git rebase -i hash_value # hash_value 是要合并的 commit 的父亲 commit"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"输入之后会发生一系列的交互,如下所示,"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/37/37267a108da49e4580324ab01a415431.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"假如我想要把上面两个 commit 合并成一个,需要使用 "},{"type":"codeinline","content":[{"type":"text","text":"squash"}],"marks":[{"type":"color","attrs":{"color":"#1e6bb8","name":"user"}}]},{"type":"text","text":" ,版本历史中较早的 commit 在上面,较晚的 commit 在下面,进行合并的话,是把较早的保留,较晚的合并到较早中去,所以要将上述两个 commit 进行合并的话,修改为如下所示,并保存退出"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c2/c27ccf03392d902d1e76c5e28124bf64.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"之后会进入另一个交互,在下面填写更改之后的 message 信息,保存退出之后即可。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/e3/e3a7e4ec6d20b05a51733d7083112e09.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1.1.4. 把间隔的几个 commit 合并成一个 --- rebase + squash"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"与上述类似,就是把间隔的 commit 移到一块即可。同样首先是输入如下命令,hash_value 是间隔多个 commit 中的最开始那个 commit 的父亲 commit 的 hash_value"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"git rebase -i hash_value"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"之后会进入交互界面,"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/67/67ef483626b8eb2297bebdeba6ca4ca5.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"比如想要合并 760df21 和 2234131 这两个 commit的话,那么修改为如下内容,保存退出即可"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a2/a27360f5c241ccfe90f7f007af65cc0d.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"之后会进入修改 message 的页面,修改之后保存退出即可"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/8e/8e310856fc6666b1a551833f1356cd20.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1.1.5. rebase 其他操作"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上述都使用了 "},{"type":"codeinline","content":[{"type":"text","text":"git rebase"}],"marks":[{"type":"color","attrs":{"color":"#1e6bb8","name":"user"}}]},{"type":"text","text":" 的命令,rebase 的意思是说改变基底,把版本历史中的某些 commit 给修改了。"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"git rebase origin/master # 把当前分支基于 origin/master 做 rebase 操作,也就相当于把当前分支的东西加到 origin/master 中\n\ngit rerere # 记录冲突解决的方式,然后可以在 rebase 的时候反复应用,可以和 rebase 结合用"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1.1.6. 碎碎念"}]},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"上述对 commit 的修改和合并,会导致该 commit 及后面 commit 的 hash_value 都被改变掉,所以不适合团队集成开发中使用。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"假如 commit 修改和合并这一步操作完成之后不是直接进入修改 message 的页面,请根据提示进行进一步操作,比如"},{"type":"codeinline","content":[{"type":"text","text":"git rebase --continue"}],"marks":[{"type":"color","attrs":{"color":"#1e6bb8","name":"user"}},{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":"。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"假如合并的包含了根 commit,那么 hash_value 则是根 commit 的 hash_value,之后在交互文档中把根 commit 填入即可,只需要填入要操作的名称和 hash_value 即可。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"在合并 commit 中,假如一个 commit 没有被 pick 的话,比如注释了或者删除,那么在完成一系列操作中之后,这个 commit 将会被丢弃。如下图所示,275a765 这个 commit 被注释掉了的话,那么在完成之后,这个 commit 将会被丢弃。"}]}]}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/36/367081bd51119c6995e6448211a15741.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null}}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1.2. 回滚操作 --- git reset"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1.2.1. 暂存区恢复成和 HEAD 一样"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"git reset HEAD\ngit reset HEAD -- file_name1 file_name2 # 暂存区部分文件变得跟 HEAD 一样"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"比如一开始的话,HEAD 、暂存区和工作目录都是一样的,都是状态A,并且 readme*.md 文件都已经被跟踪起来了。下面我们修改 readme3.md 文件,之后把它 add 到暂存区。那么这样子工作目录和暂存区都是状态 B,而 HEAD 是状态 A。那么使用上述命令之后,会将暂存区恢复成状态 A。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/1a/1a468fc60980b4a92c857aeb6c24a70b.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1.2.2. 工作目录恢复为和暂存区一样"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"git checkout -- file_name # 工作目录中指定文件恢复为和暂存区一样\ngit checkout -- *|. ## 工作目录全部文件恢复为和暂存区一样"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a2/a28106037c6f0d47abf16218617d6951.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1.2.3. 回滚到某个 commit"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"git reset --hard hash_value # 把 HEAD、暂存区、工作目录都回滚到 hash_value 所代表的 commit 中。\ngit reset --hard # 把暂存区里面的修改去掉,也就是让暂存区、工作目录默认恢复到 HEAD 的位置"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a3/a31c2345d7b8a0fca5ab9dc3ba1dc0cb.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/0e/0e23c8affe618768a5effeabeb580fb8.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"1.2.4. 碎碎念"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"工作目录内容的修改使用 "},{"type":"codeinline","content":[{"type":"text","text":"git checkout"}],"marks":[{"type":"color","attrs":{"color":"#1e6bb8","name":"user"}},{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":","}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"暂存区内容的修改使用 "},{"type":"codeinline","content":[{"type":"text","text":"git reset"}],"marks":[{"type":"color","attrs":{"color":"#1e6bb8","name":"user"}},{"type":"strong"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"版本历史的修改使用 "},{"type":"codeinline","content":[{"type":"text","text":"git rabase"}],"marks":[{"type":"color","attrs":{"color":"#1e6bb8","name":"user"}},{"type":"strong"}]}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1.3. 工作目录、暂存区的更改状态保存下来"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这个应用在开发中临时加塞了紧急任务的情况,可以把处理了一半,还在工作目录、暂存区的更改状态保存下来。"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"git stash # 把相应的修改内容给存下来,之后 git status 查看的话又变为什么都没改变的了\ngit stash list # 查看存下来的内容\ngit stash apply # 存下来的内容又恢复了,但是存下来的内容还在 stash 中\ngit stash pop # 存下来的内容恢复了,但是存下来的内容也没了"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/37/378691501cf3c885910d1ad55a312e4b.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1.4. git merge"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"将两个分支或者两个 commit 进行 merge,merge 之后也会产生一个 commit"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"git merge branch_name1 branch_name2\ngit merge hash_value1 hash_value2\ngit merge --squash # 以 squash 方式进行 merge"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 merge 的过程中有时候会产生冲突,比如两个分支修改或者两个 commit 修改的是同文件的同一区域,那么就会发生冲突,那么会在相应文件冲突的地方有提示,大致如下所示。"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"<<<<<<< HEAD\nwindows\n=======\nroot\n>>>>>>> origin/master"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过协商和决定之后,确定文件最终内容,同时把上述内容删除。之后 "},{"type":"codeinline","content":[{"type":"text","text":"git add"}],"marks":[{"type":"color","attrs":{"color":"#1e6bb8","name":"user"}}]},{"type":"text","text":" 、"},{"type":"codeinline","content":[{"type":"text","text":"git commit"}],"marks":[{"type":"color","attrs":{"color":"#1e6bb8","name":"user"}}]},{"type":"text","text":" 即可。"}]},{"type":"blockquote","content":[{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}},{"type":"strong"}],"text":"不同人修改了不同文件不会产生冲突。比如说两个人维护一个仓库,一个人修改 A 文件,另一个修改 B 文件,那么 merge 的话不会产生冲突,直接将内容合并在一起。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}},{"type":"strong"}],"text":"不同人修改了同文件不同区域不会产生冲突。merge 的话直接将内容合并在一起。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}},{"type":"strong"}],"text":"同一文件改成不同的文件名会产生冲突。同上,一个人把文件名改成了 rename1,另一个人把文件名改成了 rename2,那么 merge 会发生冲突,需要进行协商确定最终的文件名。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}},{"type":"strong"}],"text":"不同人修改了同文件的同一区域会产生冲突。merge 的话因为不能确定保留谁的内容所以会产生冲突。"}]}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1.5. 分离头指针"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"分离头指针的例子如下所示,上面提到切换到某个分支的用法是"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"$ git checkout branch_name"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那么假如把 branch_name 变成了 hash_value,那么这个就相当于“分离头指针”(PS:个人的理解是相当于创建了一个匿名 branch,这个匿名的 branch 是从 hash_value 的地方分出来的)"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"$ git checkout hash_value"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"之后的 commit 都是基于这个分离头指针的位置开始的,这些 commit 都没有基于某个 branch,相当于都是“游离”状态的。那么当切回到某个分支之后,这些 commit 都会被当成垃圾一样清理掉。如果这些 commit 很重要,那么请把这些 commit 跟某个 branch 绑在一起。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另外分类头指针也是可以用的,比如我们先用分离头指针进行一波修改和测试,如果测试不错,那么就把这些修改的 commit 添加成 branch。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1.6. .gitignore --- 指定不需要 git 管理的文件"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"git 更多是管理代码的版本控制,而代码构建出来的东西可以不用管理,因为这些是可以复现的。那么 .gitignore 这个文件就是告诉 git 哪些文件不需要被纳入版本控制系统的,也就是相当于会被忽视。"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"doc # doc 文件和 doc 目录都不会被管理\ndoc/ # 只指定 doc 目录不会被管理,但是 doc 文件没被说明,假如 doc 在的话,还是会被管理起来的"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面内容的有效范围是在整个项目中,即包括子目录等"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/af/af2929faf5995d812ca15566d171892c.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a3/a3068a4d43f51d4c07ab87d753c9cf35.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}}],"text":".gitignore 可以借助 github 创建仓库时生成,常用的 .gitignore 如下所示,自己写的时候也值得参考一波:https://github.com/github/gitignore ;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}}],"text":"另外想要 git 不管理某些文件,只能在 .gitignore 文件中指定;"}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1.7. 团队合作注意事项"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你的 git 仓库是跟其他人一起维护的,那么请注意一下几点:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"git push -f"}],"marks":[{"type":"color","attrs":{"color":"#1e6bb8","name":"user"}},{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":" 不能使用"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"公共的分支严禁拉倒本地做 rebase 操作的"},{"type":"text","text":",因为一旦做了 rebase 操作之后,历史的 commit 就变了,但是其他人那边还是老旧的 commit,他们是基于老旧的 commit 做事情的,而你是几于新的 commit 做事情了,那么就相当于是两条分支了。所以记住了,不能向集成分支执行变更历史操作,建议的方式是在现在 commit 的基础之上再做调整。"}]}]}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/6f/6f0b5e9888823f039014f35a1b21c2ea.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"A 在 temp 分支上做 rabase 操作,那么 temp 分支就会和 master 分开。如下图所示,"}]}]}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b7/b7a1fad64e6dae0f70c8a8d4a8ea78c4.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"然而在另一个人,还是基于如下情况做的 commit 等,那么这样,就出现问题了"}]}]}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/6f/6f0b5e9888823f039014f35a1b21c2ea.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2. git 中的对象及其操作"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"git 中的对象有三种:commit、tree、blob。下面对这三种对象进行阐述。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.1. commit"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"每次执行"},{"type":"codeinline","content":[{"type":"text","text":"git commit"}],"marks":[{"type":"color","attrs":{"color":"#1e6bb8","name":"user"}}]},{"type":"text","text":"都会创建一个commit对象,一个 commit 对象只包含一个 tree 对象,这个 tree 对象是 "},{"type":"codeinline","content":[{"type":"text","text":".git"}],"marks":[{"type":"color","attrs":{"color":"#1e6bb8","name":"user"}}]},{"type":"text","text":" 所在父目录的对象, 那么这样子的话,一次 commit 就相当于把当前目录的情况给记录下来了。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.2. tree"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目录的对象,那么由于目录中可以包含目录,也可以包含文件,所以 tree 对象可以包含 tree 对象,也可以包含 blob 对象。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.3. blob"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"blob 是一个文件的具体对象,比如png图像,css文件,这些文件都会对应一个blob对象,可以说是 git 对象中最基本的。另外,blob 跟文件名一点关系都么有,只要文件内容相同,不管文件名叫什么,blob 只有一份。"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}}],"text":"新建的Git 仓库中,有且仅有一个 commit,仅仅包含了 /doc/readme,请问内含多少个 tree,多个 blob?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#6a737d","name":"user"}}],"text":"含两个 tree,一个 blob。首先是 git 仓库所在目录是一个 tree (也就是 /doc/readme 的父目录),doc 是一个tree,而 readme 文件是唯一 blob。"}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.4. 对象的相关操作"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"git cat-file -t|p|s hash_value # 显示版本库对象的内容,类型及大小信息\ngit cat-file -t hash_value # 查看版本库对象的类型\ngit cat-file -p hash_value # 查看版本库对象的内容\ngit cat-file -s hash_value # 查看版本库对象的大小"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"3. .git 目录探索"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.1. HEAD 文件"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"HEAD文件的内容显示了 HEAD 当前所指的分支信息,通过下面的内容可以佐证上面 HEAD 说到的一点:HEAD 指向的是某个分支,但通过查看分支文件内容可以发现里面其实是 commit 的 hash_value,也就是说 HEAD 实际指向的是某个commit。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/21/21c40f96e3e57f7fccd13ec5948bf579.png","alt":"git_head_temp","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"git_head_temp"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用 "},{"type":"codeinline","content":[{"type":"text","text":"git checkout"}],"marks":[{"type":"color","attrs":{"color":"#1e6bb8","name":"user"}}]},{"type":"text","text":" 命令之后,查看"},{"type":"codeinline","content":[{"type":"text","text":"HEAD"}],"marks":[{"type":"color","attrs":{"color":"#1e6bb8","name":"user"}}]},{"type":"text","text":" 文件的内容"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/2f/2f39b9a48062d28f2ee342444921eebf.png","alt":"git_head_chang_to_master","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"git_head_chang_to_master"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.2. config 文件"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"存放本地仓库(local)相关的配置信息,假如之前设置了 local 下的 "},{"type":"codeinline","content":[{"type":"text","text":"user.name"}],"marks":[{"type":"color","attrs":{"color":"#1e6bb8","name":"user"}}]},{"type":"text","text":" ,那么会在这个文件中存储相关的内容等信息。修改 config 文件中 "},{"type":"codeinline","content":[{"type":"text","text":"user.name"}],"marks":[{"type":"color","attrs":{"color":"#1e6bb8","name":"user"}}]},{"type":"text","text":" 配置项的内容,使用命令查看到的也是修改之后的。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.3. refs 目录"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"3.3.1. heads 子目录"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目录中包含的是各分支信息,每一个文件的内容都是 hash value,这个是值是该分支最后一次 commit 的 hash_value 值"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":".../.git/refs/heads# ls\nmaster temp temp2\n.../.git/refs/heads# cat master\n9ef147d58eb7e09987cf5ce92254b1600ac92cd9"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"3.3.2. tags 子目录"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"里面显示的是标签的信息,Git 仓库可以有很多标签,项目开发到一定程度,是一个关键的成果了,比如开发到 v1.0,那可以打上一个标签了。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.4. objects 目录"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"存放对象的目录。"},{"type":"text","marks":[{"type":"strong"}],"text":"git 中的对象都是由 40 位字符组成"},{"type":"text","text":",前两位字符用来当 object 目录中子目录名,后 38 位做文件名。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章