實習生的代碼被弄丟了!救命的時候絕對用的上——天天三分鐘玩轉Git (8)

分享後端開發和雲計算必備相關技術,道盡程序員小熊與老闆的愛恨情仇.linux

同名公衆號:編程三分鐘 回覆【 資源 】能夠得到程序員必備技能圖譜、數百本熱門編程電子書籍。git

新來的實習生把本身作了一個月的功能給覆蓋了,向我求救,要不要幫他?——編程三分鐘程序員

第 8 篇 找回弄丟的代碼

新來的實習生【悲郭】由於不太熟悉git的使用,老是把本身的代碼給弄丟了,此次好了,把辛苦寫了一個月的功能全弄丟了。還好我力挽狂瀾幫他恢復了過來。下面咱們分兩種代碼丟失的場景狀況來討論。面試

恢復曾今提交過的記錄

你使用了git reset --hard commit—id命令,將工做區的提交穿越到你指定的commit裏,這個時候你會發現git log根本沒有記錄這以後的提交記錄,像下面這個樣子,你是否是會很是着急呢?算法

不要太緊張,Git提供了一個命令git reflog用來記錄你的每一次改變目錄樹的命令,使用好他就能夠很方便的恢復你的提交:編程

剛纔咱們提到一個關鍵字目錄樹,那麼什麼是目錄樹呢?後端

咱們的主線每每是一根直線,多一個分支至關於多一個分叉,無數分支縱橫交錯就像一顆樹狀的結構,因此咱們稱之爲目錄樹。commit rebase reset merge這些都是改變目錄樹的操做。數據結構

  1. 這個恢復丟失代碼方法也只有存在改變目錄樹的操做才恢復的回來
  2. git log 是同樣的,也能夠看到全部分支的歷史提交,不同的是看不到已經被刪除的commit記錄和 reset rebase merge 的操做 咱們能夠看到git reflog前面的就是commit id,如今咱們就能夠用以前介紹過的方法來回滾版本了

再舉一個例子,經過上面的git reflog打印出來的記錄,咱們記住最後兩個提交的commit id和提交說明分別是00:50和18:51,咱們來使用git reset --hard commit—id去到18:51,這個時候 00:50的提交就沒有了,就算git log也看不見。而後咱們再經過咱們記住的commit id就能夠回滾回去了!app

上圖的步驟爲:ui

  • 根據git reflog返回的結果,用git reset --hard commit_id回退到856a740這個版本
  • git log -1看近一行的日誌,能夠看到目前回到了856a740這個版本,也就是上一個版本
  • 再根據git reflog的結果,用git reset --hard 35b66ed跑回最新的此次提交
  • git log -2看到兩次提交的日誌,咱們就這麼再穿梭過來了,就是這麼爽

可是咱們若是隻是想把此提交給找回來,恢復他,那仍是不要用reset的方式,能夠用git cherry-pick commitid單獨取一個commit到當前分支或者用merge來作合併。

恢復忘記提交的記錄

若是你的代碼文件沒有commit過,就被手賤刪除掉了或者也是被reset --hard的時候搞沒了。

這就不只僅是用一個git reflog命令就能夠簡單找回來的,但只要你之前有作過add的操做把他放到過暫存區,咱們就能夠把他找回來。什麼?你連add都沒有操做過那就只能開始準備新一輪的面試了。

先來建立一個災難現場。

  • 建立一個叫lose_file.txt的文件並寫入內容my lose message,並使用git add把他加到暫存區
  • git reset --hard 35b66ed8用丟棄一切修改的方式來使如今的工做區恢復到35b66ed8版本,由於還沒提交因此也就是恢復到當前的(head)版本。
  • 咱們用statusls再看,這個叫lose_file.txt的文件真的沒了,完蛋了,第一反應使用剛剛學到的命令git reflog會發現根本就很差使,那如今只能去準備跑路了呢?不慌,讓咱們進入下一節

咱們來看看git底層原理

核心命令:git fsck --lost-found,他會經過一些神奇的方式把歷史操做過的文件以某種算法算出來加到.git/lost-found文件夾裏,輸出的記錄就像下面這個樣子。

咱們能夠看到這裏有blob、commit、tree類型的數據,還有tag等類型的。他們是什麼含義呢?

來,咱們都是大神固然要學學git底層存儲方式,以下圖:

  • commit數據結構在每次提交以後都會生成一個,當咱們進行commit以後,首先會建立一個commit組件,以後建立一個tree組件,把全部的文件信息都儲存在裏面,每一個blob表明一個文件,均可以在tree裏找到
  • blob組件並不會對文件信息進行存儲,而是隻對文件的內容進行記錄,文件信息存儲在tree裏

言歸正傳,咱們來看看怎麼恢復剛剛git reset --hard後,不見了的lose_file.txt文件。

在上面執行完git fsck --lost-found命令,返回的第一行blob咱們使用git show命令來看看他的內容

正好內容就是lose_file.txt本來的內容,就是咱們丟失的文件內容,這樣就找回來了!

咱們再來看看上圖中的commit和commit下的tree內容,能夠看到他們之間的層級關係以下:

  • git cat-file -p能夠看到commit的內容,能夠選擇把這個commit合併到咱們的分支裏,仍是reset merge rebase cherry-pick這些命令來合commit
  • git ls-tree列出tree下面的文件名和id的記錄信息,而後就能夠根據blob的id來恢復文件了

後記

若是你發現執行git fsck --lost-found的輸出也找不到你想要的,那麼只能祭出終極命令來輸出近期修改的文件了,以下:

  • 這裏用find .git/objects -type f | xargs ls -lt | sed 3q這個命令,他的含義是查找.git/objects文件夾下的普通文件 按照時間排序後 打印在終端裏 sed 3q 是打印3行 sed 100q 是打印100行,隨你喜歡。
  • git cat-file -t
    7f5965523d2b9e850b39eb46e8e0f7c5755f6719 就能看見文件類型 把最後一個/去掉 複製從objects/ 後面的全部東西放在-t後面
  • git cat-file -p id就能看見文件內容,是否是很爽,你再用高超的linux技巧操做一下,就能夠批量打印出所有文件的類型啦

小結

通過一番操做之後實習生【悲郭】終於不用再背鍋了,咱們來總結一下:

1. 提交過的就用命令git reflog來查詢提交記錄找回

2. 未提交可是git add過的就用git fsck --lost-found來生成丟失文件記錄來找回。

3. 沒找回成功就用用find .git/objects -type f | xargs ls -lt | sed 3q這個命令來輸出近期修改的文件找回。

代碼恢復的前提是要保證你的項目根目錄下.git文件夾是完整的,要是手動刪除了裏面的一些東西那就真完了。還要保證一點,你的代碼之前是有過git追蹤,最少add過!

只要有一我的能得到幫助,小熊就會繼續努力

喜歡就讓咱們一塊兒玩耍吧

相關文章
相關標籤/搜索