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}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章