Git 常用招
Git 可以說是比寫 code 還要重要的東西,現在的專案基本上都要共同協作,所以如何避免衝突,不在開發的時候發生災難,可以說是非常的重要,寫 code 寫不好可以問人,但 Git 不行的話可能連工作都沒有辦法一起 co-work 。另外如果對 vim 還沒有很熟的話建議去多了解一下 vim 的編輯、儲存、查尋方式,對你在使用 git 上會更加的得心應手。 # Git 常用 commend line
git 起手式
在專案位置下初使化 git ,表示可開始用 git 來管理你的專案,此時專案中會出現一個隱藏資料夾 .git ,然而你在開發的過程中也一定會有你不想要推到 remote 的東西,這個時候你可以建立一個 .gitignore 的檔案,在裡面編寫你不想要上傳的文件 or 資料夾
git init
# .gitignore 檔案
node_modules # 資料夾不 推上 git
/dist
.env # 檔案不推上 git
在來你需要對專案說,你是誰,所以把你的 email 和名稱和 git 說,因此在 git.config 裡面建立資訊
# 查看你目前的 config 清單
git config --list
# 建立名稱
git config --global user.name [YOUR_NAME]
# 建立 email
git config --global user.email [YOUT_EMAIL]
clone 專案
開發其它的專案,透過 clone 的方式,把 .git 的檔案一起抓下來
git clone [YOUR_PROJECT]
remote 相關指令
# 查詢remote相關指令
git remote -h
# 將遠端數據庫的名稱從 <old> 改為 <new>
git remote rename `<old>` `<new>`
# 在 <newurl> 內指定遠端數據庫的新地址
git remote set-url `<name>` `<newurl>`
# 加入 remote 資料
git remote add origin [YOUR_PROJECT]
# 移除 remote 資料
git remote remove origin
切換遠端分支
首先你應該不會知道專案中所有的 br 叫什麼名稱,所以可透過
# 查看所有 local 遠端 br
git branch -a
在確認完之後,在回到專案的位置上,進行切換分支
git checkout -b [BRANCH_NAME] [origin/BRANCH_NAME]
加入暫存區
把資料加入暫存區
# add all file stage
git add .
# after everyone check, add file to stage
git add -p
取消加入暫存區
git checkout
檔案名稱大小寫修正
core.ignorecase 在做什麼?
- 預設情況 (
true):在 Windows 或 macOS 這類檔案系統「不區分大小寫」的環境中,Git 預設會忽略大小寫差異。例如把index.html改名成Index.html,Git 可能顯示「沒事發生」。 - 設為
false:強迫 Git 必須區分大小寫。對 Git 而言,index.html和Index.html就像apple.html和banana.html一樣,是兩個不同的檔案。
設成 false 後會發生什麼?
- 若原本有
index.html,再手動新增一個Index.html。 - 執行
git status時,Git 會顯示一個全新的未追蹤檔案 (Untracked file)。 - 兩者都可以
git add,暫存區(Index)裡會同時存在這兩個檔案的紀錄。
在非 Linux 系統上不建議手動把 core.ignorecase 設為 false:
- 「看得見,摸不著」:Git 紀錄裡可以有兩個檔名(只差大小寫),但 macOS/Windows 無法在同一個資料夾裡真的放兩個這樣的檔案。
git checkout時可能其中一個被覆蓋,或 Git 報錯無法切換分支。 - 遠端衝突:若團隊有人用 Linux(區分大小寫)並推了
index.html與Index.html,你在 Mac/Windows 上 pull 時可能造成混亂甚至檔案內容遺失。
正確做法:只改大小寫時用 git mv
若只是想將 index.html 改成 Index.html(且不打算同時存在兩個檔),不必改 core.ignorecase,用 git mv 最安全:
# 讓 Git 幫你完成改名,會自動 處理大小寫切換
git mv index.html Index.html
若已經弄亂(Git 顯示兩個檔但資料夾只有一個),可先重設索引再重新加入:
git rm -r --cached .
git add .
除非在開發僅在 Linux 上跑的軟體,否則建議維持預設:
git config --local core.ignorecase true
若只是「改名後 Git 沒反應」,用 git mv 才是正解,不需動 core.ignorecase。
加入本地儲存區
把資料加入本地儲存區,方法其實有很多種,但主要就是要把你的資料寫到 git 裡面,如果你所要寫的東很多的話,建議你可以用 vim 的方式去作編輯歐
git commit # 會直接進到 vim IDE 中
git commit -m 'msg content'
退回本地儲存區
# get commit id
git log
# 本地數據庫不見
git reset --hard `<id>^`
# 本地數據庫還在
git reset --soft `<id>^`
commit 訊息邏輯以大寫開頭以
<動詞> + <受詞> + <內 容>的文法撰寫內容不宜過長內容需要據有代表性
如要編輯 head 的 commit 的話
git commit --amend
stash
會使用它最常有的情境是,你開發到一半,但是 BOSS 請你趕快的去處理另一件是,這個時候你也還沒有到可下 commit 的時候,這個時候,可用 stash 把你開發的 code 先到一個地方,之後只要回來,在把東西 stash 回來便可繼續開發。
在 stash 之前建議先把所有的 code 放到暫區,因有時候我們是新建檔,直接 stash 的話新檔就會被遺留在,原本的 br 上面 git add . 為了確保我們所寫的東西不要被分別放在不同的 stash list 裡面
暫時存現狀
git stash save 'msg ...'
顯示暫存清單
git stash list
回復暫清單,通當你會去看一下你的清單有什麼,然後確定是第幾個之後用 stash@{0} 的方式來還原你想的的暫存。
這裡的 0 是表示,你最一次 stash 起來的東西,1 的話就是倒數第二次的東西,依此類推
# 拿回最後一次 stash 的 code
git stash pop shash@{0}
# delete stash data
git stash pop `<shash ID>`
git stash apply `<shash ID>`
刪除暫檔
git stash drop `<shash ID>`
git stash clear # clear all
合併分之
通常在有規模的專案下面開發,比較不會用到 merge ,因為主要都是透過 lib 去發 merge request ,而不是自己在本地,就把 code merged 到其它的分支。
merge
git merge [BRANCH_NAME]
但是我們在拉分支的時候,其實就是常常在用 merge 的指令,只是被合併在一起了。
rebase
git rebase [BRANCH_NAME]
這兩個都是把 br 作合並的效果,但是 rebase 是直接把原本的分支合回到另一個 br 的分支上,變成一個,也就是說,有些 commit 你可能會沒有辦法在 tree 上面直接的看到,因為被合到另一個 tree 上面了
rebase 的 squash(壓縮 commit)
用 interactive rebase(-i)可以把多個 commit 合併成一個,常用在整理分支歷史、送 MR 前把「修正 typo」「再改一下」這類小 commit 壓成一個清楚的 commit。
# 從目前分支「往前數 N 個 commit」做互動式 rebase
git rebase -i HEAD~N
# 或指定要 rebase 的基底 commit(不包含該 commit)
git rebase -i [COMMIT_HASH]
執行後會開啟編輯器,列出這 N 個 commit,例如:
pick abc1234 feat: 新增登入 API
pick def5678 fix: 修正 typo
pick ghi9012 docs: 補充註解
把要「壓進前一個」的 commit 前面的 pick 改成 squash(或簡寫 s),保留最上面一個為 pick,其餘改為 squash:
pick abc1234 feat: 新增登入 API
squash def5678 fix: 修正 typo
squash ghi9012 docs: 補充註解
存檔離開後,Git 會把這三個 commit 合成一個,並再開一次編輯器讓你編輯合併後的 commit message。
- pick:保留該 commit
- squash / s:合併到前一個 commit,並保留兩邊的 message 讓你編輯
- fixup / f:合併到前一個 commit,但丟棄這個 commit 的 message(適合「只是小修正」的 commit)
若已經 push 過該分支,squash / rebase 後會改寫歷史,需要強推(請確認沒有其他人依賴該分支):
--force-with-lease(有條件強推)
git push --force-with-lease
刪除 branch
-d(安全刪除)
- 只在分支已合併到當前分支時才會刪除
- 若未合併會報錯,避免誤刪未合併的工作
git branch -d [BRANCH_NAME]
-D(強制刪除)
- 等同
git branch -d -f,不論是否合併都會強制刪除 - 適用於確定要丟棄該分支的變更時
- ⚠️ 未合併的變更會遺失,使用時請謹慎
git branch -D [BRANCH_NAME]
建議
| 情境 | 建議指令 |
|---|---|
| 確定分支已合併 | git branch -d |
| 確定要丟棄未合併的工作 | git branch -D |
重新 rename
git branch -m [oldname] [newname]
git branch -m [new_name]
遠端數據庫
fetch
主要只執行拉 code 的動作,但它不會把 code 和你現在的 br 進行合併,所以執行完後你是會在 HEAD 上面的
# 把你在遠端的 br 拉下來
git fetch
pull
那 pull 的這個動作,就是我們把 fetch + merge 的動作一起作完,把 code 拉下來,然後 merge 到你現在的 branch 中
# git fetch + git merge
git pull
# 當然你也可選擇 rebase
git pull --rebase
NOTE 在開發過程中如果你遇到需要設定 config 你可能會看到這個畫面
# bla... bla...
push
把你所 commit 好的的檔案往上傳到 remote 端,但是需先確認是否已設定好 origin 的 remote 位置
git push origin [BRANCH_NAME]
改寫歷史(例如 rebase、squash)後需要強推時,兩者差別如下:
| 選項 | 行為 | 風險 |
|---|---|---|
--force | 無條件覆蓋遠端,不檢查是否有他人新提交 | 高 ,可能蓋掉別人的 code |
--force-with-lease | 先檢查遠端是否與本地紀錄一致,一致才覆蓋、不一致則拒絕 | 低,可避免意外蓋掉他人提交 |
建議優先使用 --force-with-lease。詳見 `--force-with-lease`(有條件強推)。
tag
若要添加標示標籤,可以在 tag 命令加上 -a 參數執行,執行後會啟動編輯器,請輸入要給予的註解。也可以用 -am 參數來直接添加註解。
git tag -a [TAG_NAME]
在 HEAD 指向的提交裡增加名為 [TAG_NAME] 的標籤,請執行以下的命令。
git tag -am 'msg...' [TAG_NAME]
git tag -n # 可以顯示出標籤和註解
fork 專案
在 github 選擇 fork ,需在把你的 remote 專案名稱修正,因為通常 origin 指的是自己的開發 remote。然後在把 fork 的 repositories 設定到你的 origin 裡面。
確認 remote 的名稱 ⇒ 修正名稱 ⇒ 加入新的 fork repositories ⇒ 確認 remote 的名稱
它會產生一個新的專案,然有過去一樣整的 commit (這個很種要不然會沒有辦法 merge code 進來 fork 的專案)
git remote add upstream [UPSTRESM_PROJECT]
fetch 一下有沒有新的 code 和改變
git fetch upstream
切而你要的 branch , 然後 merge 原本的 upstream/main 進來現在的 code
git checkout [TARGET_BR]
git merge upstream/main ## merge upstream branch code
git rebase upstream/main ## 也是可以,就是讓 git tree 在 clear 一點
檢查 git
下列這些指令是在你開發到一半,想要回去查東西時很用的指令
# 看一下還有多少東西沒有進暫存區
git status
# 確認這個 br commit 的狀況
git log
# 確認一下遠端
git remote -v
# stash 的清單
git stash list
# 可以檢看一下指令
git remote -h