Elaine's Blog 朝著 senior 前進的工程師

Git 學習筆記

2018-01-16

git

設定 git

  • 查看 git 版本

    $ git --version
    
  • 設定

    $ git config --global user.name [你的名字]
    $ git config --global user.email [你的email]
    
  • 查詢設定

    $ git config --list
    

初始化

  • 建立資料夾

    $ mkdir demo
    
  • 移動至資料夾

    $ cd demo
    
  • 建立本地倉庫

    $ git init
    
  • 可以選擇建立本地倉庫或是複製遠端倉庫到本地

    $ git clone [遠端數據庫網址]
    

忽略檔案

  • 新增 .gitignore 檔案
    $ touch .gitignore
    
  • 編輯 .gitignore 檔案

    $ vi .gitignore
    
  • 將要忽略的檔案寫入 .gitignore

    node_modules/
    

遠端倉庫操作

  • 連結遠端倉庫

    $ git remote add origin [遠端數據庫網址]
    
  • 複製遠端倉庫到本地

    $ git clone [遠端數據庫網址]
    
  • 查詢遠端數據庫

    $ git remote
    
  • 將本地分支推送到遠端分支

    $ git push [遠端數據庫名稱] [遠端分支名稱]
    
  • 將遠端分支拉下來與本地分支進行合併

    $ git pull
    

查詢 git 狀態

  • 查詢狀態

    $ git status
    
  • 或使用簡寫

    $ gst
    

新增檔案至索引

  • 新增全部檔案

    $ git add .
    
  • 新增部分檔案

    $ git add [檔案名稱]
    

提交變更 / 建立版本至本地倉庫

  • 提交

    $ git commit -m "[版本紀錄的說明文字]"
    

查詢歷史紀錄

  • 查詢歷史紀錄

    $ git log
    
  • 只要透過一個減號 ( - ) 與一個數字,就可以限定輸出最近幾筆紀錄:

    $ git log -10
    
  • 精簡的 log

    $ git log --oneline --graph
    
  • 我想要找某個人或某些人的 Commit…

    $ git log --oneline --author="Tom\|Elaine"
    
  • 我想要找 Commit 訊息存在特定字串的紀錄

    $ git log --oneline --grep="hello"
    
  • 我要怎麼找到哪些 Commit 的檔案內容有提到 「Ruby」 這個字?

    $ git log -S "Ruby"
    
  • 找到特定時間的 Commit

    • 「今天早上 9 點到 12 點之間所有的 Commit」

      $ git log --oneline --since="9am" --until="12am"
      
    • 「從 2017 年 1 月之後,每天早上 9 點到 12 點的 Commit」

      $ git log --oneline --since="9am" --until="12am" --after="2017-01"
      
  • 查看這行程式碼是誰寫的

    • 整個檔案

      $ git blame index.html
      
    • 只會顯示第 5 ~ 10 行的資訊

      $ git blame -L 5,10 index.html
      

還原指令

  • reset 模式
    • mixed 模式
      • 這個模式會把暫存區的檔案丟掉,但不會動到工作目錄的檔案,也就是說 Commit 拆出來的檔案會留在工作目錄,但不會留在暫存區
    • soft 模式
      • 這個模式下的 reset,工作目錄跟暫存區的檔案都不會被丟掉,所以看起來就只有 HEAD 的移動而已,也因此,Commit 拆出來的檔案會直接放在暫存區
    • hard 模式
      • 在這個模式下,不管是工作目錄以及暫存區的檔案都會丟掉

  • 取消全部檔案索引,將更改的文件丟到工作目錄

    $ git reset HEAD
    
  • 取消單一檔案索引,將更改的文件丟到工作目錄

    $ git reset HEAD [檔案名稱]
    
  • 還原工作目錄與索引,會和最後一次 Commit 保持一樣 (更改文件的文件會不見)

    $ git reset --hard
    
  • 刪除最近一次 commit

    $ git reset --hard HEAD^
    
  • 刪除最近一次 commit,但保留異動內容

    $ git reset --soft HEAD^
    
  • 【狀況題】不小心使用 hard 模式 Reset 了某個 Commit,救得回來嗎?

    $ git reset --hard ORIG_HEAD
    
  • 還原其中一個被改壞的檔案(回復到上一次 Commit 的狀態)

    $ git checkout [檔案名稱]
    
  • 如果想一口氣把所有被異動的檔案救回來

    $ git checkout .
    
  • 還原其中一個被改壞的檔案,例如把 master 分支中最新版的 index.html 給還原

    $ git checkout master index.html
    

特殊符號

  • HEAD 是啥?

    • HEAD 本身是一個指標,它通常會指向某一個本地端分支或是其它 commit
    • 你在哪,HEAD 就在哪
    • 通常會指向目前所在的分支
  • ^~ 的差別?

    • 如果有 merge 的時候,^ 有分主要的與次要的…等等 A^ => 上一個(主要的) => B A^2 => 上一個(次要的,合併進主要的) => C A^^ => 上一個(主要的)的上一個(主要的) => D A^^2 => 上一個(主要的)的上一個(次要的) => E A^^3 => 上一個(主要的)的上一個(次次要的) => F

    • ~ 都是主要的 A~1 => B A~2 => D A~3 => G

  • HEAD^ = HEAD^1 = HEAD~1 = HEAD~

Git HEAD^与 HEAD~ git 理解 HEAD^与 HEAD~

分支

  • 查看分支

    $ git branch
    
  • 切換分支

    $ git checkout [分支名稱]
    
  • 新增分支並切換到該分支

    $ git checkout -b [分支名稱]
    
  • 重新命名分支

    $ git branch -m [舊分支名稱] [新分支名稱]
    
  • 刪除分支

    $ git branch -d [分支名稱]
    

    只有「現在目前所在的分支」不能刪而已(因為刪了的話要去哪裡?),不過只要先切到別的分支就可以刪掉它了

  • 直接切換到某個 Commit 點

    $ git checkout [版本號]
    

比較版本差異

$ git diff commit1 commit2
$ git diff                 // 工作目錄 vs 索引
$ git diff HEAD            // 工作目錄 vs HEAD
$ git diff --cached HEAD   // 索引 vs HEAD
$ git diff --cached        // 索引 vs HEAD
$ git diff HEAD^ HEAD      // HEAD^ vs HEAD (最新版的前一版vs最新版)

暫存

  • 會將所有已列入追蹤(tracked)的檔案建立暫存版

    $ git stash
    
  • 會包括所有已追蹤或未追蹤的檔案,全部都建立成暫存版

    $ git stash -u
    
  • 列出所有暫存

    $ git stash list
    
  • 還原暫存

    $ git stash pop
    
  • 清除最新暫存

    $ git stash drop
    
  • 清除所有暫存

    $ git stash clear
    

合併分支

  • 假如我現在在 master,想合併 feature 分支

    $ git merge feature
    

  • 合併後刪除不必要的分支

    $ git branch -d feature
    
  • 當你發生衝突的時候,切莫慌張,先執行 git diff 自動比對出到底哪些檔案的哪幾行發生衝突了

    $ git diff
    
  • 如果是兩個比較大的分支發生衝突的話,很有可能會有一大堆檔案有衝突的狀況。這時你可能會想一個一個檔案的來查看衝突的狀況

    $ git status
    $ git ls-files -u
    $ git diff a.text
    

rebase

  • 重新定義分支的參考基準

    $ git rebase [分支名稱]
    
  • 怎麼取消 rebase? ORIG_HEAD 會記錄「危險操作」之前 HEAD 的位置 例如分支合併或是 Reset 之類的都算是所謂的「危險操作」

    $ git reset ORIG_HEAD --hard
    

revert

在版本控管過程中,還有個常見的狀況,那就是當執行了多個版本之後,才發現前面有幾個版本改錯了,例如你不小心把測試中的程式碼也給 commit 進去,導致目前這個版本發生了問題

在開始說明前,我們一樣先用以下指令建立一個練習用的工作目錄與本地儲存庫。我們先建立一個 a.txt 的檔案,內容為 1。然後修正一版,內容改為 2。接著在新增一個 b.txt 檔案,內容為 1。所以一共有三個版本:

假設我們這個時候發現,在我們上一個版本 ( HEAD~ 或 HEAD~ 或 6351ff0 ) 被改錯了,你希望可以將該版本還原就好,而不是把版本重置到第一版在重改一次,那麼你可以試試 git revert 指令,他可以把某個版本的變更,透過「相反」的步驟把變更給還原

  • 使用 git revert 命令

假設我們從 git log 顯示的歷史記錄中,發現有個版本有問題,那麼我們可以先看看這個版本的變更紀錄。如下圖示,你可以先用 git log 查出版本編號,然後再用 git show [commit_id] 查出該版本的相關資訊

  • 使用 git revert 命令的注意事項 請注意:執行 git revert 命令之前,請先確保工作目錄是乾淨的!如果有改到一半的檔案,建議可透過 git stash 建立暫存版本

從上圖你可以看到 6351ff0 這個版本的 a.txt 檔案,是將第 1 行的內容從 1 修改成 2 的,那也代表著「相反」的步驟則是把 2 改成 1 才對。這時,如果我想把這個版本的變更給「還原」,則可以輸入 git revert 6351ff0 這個指令,執行成功後會額外再建立一個新版本。如下圖示:

執行過程中會讓你編輯最後要 commit 的訊息,預設會加上 Revert 字樣,還有會在第三行的地方加上 This reverts commit xxxx 告訴你說這個版本主要目的是從 xxxx 版本還原的

cherry-pick

cherry-pick 的英文是「撿櫻桃」的意思,代表你可以從其他籃子(分支)「挑」一些好的櫻桃到自己的籃子(分支)裡!

在版本控管過程中,還有個常見的狀況,那就是當你在一個分支中開發了一段時間,但後來決定整個分支都不要了,不過當中卻有幾個版本還想留下,這時要刪除分支也不是,把這個分支合併回來也不是,那該怎麼辦呢?本篇文章將說明你該如何利用 git cherry-pick 指令「手動挑出」你想套用的變更

  • 使用 git cherry-pick 命令的注意事項

首先,你的「工作目錄」必須是乾淨,工作目錄下的「索引」不能有任何準備要 commit 的檔案 (staged files) 在裡面,否則將會無法執行

今天我想套用 branch1 的 dc07017 Add b.txt! 這個版本到目前的 master 版本上,可以執行 git cherry-pick dc07017 命令,若成功執行,則會在目前的 master 分支建立一個新版本

不過,與 git revert 最大的不同之處,就在於執行完 git cherry-pick 命令後,其建立的版本訊息,將會與你指定挑選的那些版本一模一樣,其中包括 Author 與 Date 欄位,都會一模一樣,並不會用你在選項設定中指定的 user.name 與 user.email 參數。這點你必須特別注意!

不小心刪除分支

如果真的不小心刪除分支,可以利用以下指令先找到對應的版本號 (commit 號碼)

$ git log -g

之後利用 git checkout -b [分支名稱][commit號碼] 救回該分支

$ git checkout -b test

git 忽略的檔案被提交

必須先使用 git rm --cached 指令把這些想被忽略但是已經被追蹤的檔案移除 git

discard 丟棄某個檔案

$ git checkout -- package-lock.json

參考資料


Content