關於 Git 二三事

語言: CN / TW / HK

工具往往需要反覆檢驗

關於目錄

  • 關於描述問題
  • 關於經典場景 && 解決方案
  • 關於一點點小技巧
  • 關於小結
  • 關於常用指令合集

關於描述問題

一圖勝千言

git-status-module.png

例子: 選擇正確的撤銷方法

| 想要... | 備註 | 解決方案 | | ------------------------------------------------------------------------- | ------------------------------------------------------ | ----------------------------- | | 捨棄工作目錄中對一個文件的修改 | 修改的文件未被暫存或提交 | checkout --[file_name] | | 捨棄工作目錄中所有未保存的變更 | 文件已暫存,但未被提交 | reset --hard | | 合併與某個特定提交(但不含)之間的多個提交 | -- | reset [commit] | | 移除所有未保存的變更,包含未跟蹤的文件 | 修改的文件未被提交 | clean -fd | | 移除所有已暫存的變更和在某個提交之前提交的工作,但不移除工作目錄中的新文件 | --- | reset --hard [commit] | | 移除之前的工作,但完整保留提交歷史記錄( “前進式回滾” ) | 分支已經被髮布,工作目錄是乾淨的 | revert [commit] | | 從分支歷史記錄中移除一個單獨的提交 | 修改的文件已經被提交,工作目錄是乾淨的,分支尚未進行發佈 | rebase --interactive [commit] | | 保留之前的工作,但與另一提交合並 | 選擇 squash(壓縮)選項 | rebase --interactive [commit] |

通過清晰區分自己當前所要的場景並頻繁使用 git status 查看當前狀態,來明辨的場景

關於經典場景 && 解決方案

Q:文件刪除造成的變基衝突

git-rebase.png

```bash First, rewinding head to replay your work on top of it... Applying: CH10: Stub file added with notes copied from video recording lessons. Using index info to reconstruct a base tree... A ch10.asciidoc Falling back to patching base and 3-way merge... CONFLICT (modify/delete): ch10.asciidoc deleted in HEAD and modified in CH10: Stub file added with notes copied from video recording lessons.. Version CH10: Stub file added with notes copied from video recording lessons. of ch10.asciidoc left in tree. Failed to merge in the changes. Patch failed at 0001 CH10: Stub file added with notes copied from video recording lessons. The copy of the patch that failed is found in: /Users/emmajane/Git/1234000002182/.git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue". If you prefer to skip this patch, run "git rebase --skip" instead. To check out the original branch and stop rebasing, run "git rebase --abort". ```

關鍵消息

When you have resolved this problem, run "git rebase --continue".

此信息吿訴我需要按以下步驟操作
  1. 解決合併衝突 vim [file_name]
  2. 當合並衝突已經被解決,運行命令 git rebase --continue
  3. 查看當前狀態 git status
  4. 根據消息 git reset HEAD [file_name]
  5. 查看狀態 git status
  6. 添加存儲 git add [file_name]
  7. 添加提交 git commit -m [message]

Q:單個文件合併並衝突造成的變基衝突

```bash Applying: CH10: Stub file added with notes copied from video recording lessons. Applying: TOC: Adding Chapter 10 to the book build. Using index info to reconstruct a base tree... M book.asciidoc Falling back to patching base and 3-way merge... Auto-merging book.asciidoc CONFLICT (content): Merge conflict in book.asciidoc Recorded preimage for 'book.asciidoc' Failed to merge in the changes. Patch failed at 0002 TOC: Adding Chapter 10 to the book build. The copy of the patch that failed is found in: /Users/emmajane/Git/1234000002182/.git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue". If you prefer to skip this patch, run "git rebase --skip" instead. To check out the original branch and stop rebasing, run "git rebase --abort". ```

解決思路
  • 查看 git 狀態消息 git status
  • 通過 vscode 解決衝突
  • 查看 git 狀態消息 git status

Q:定位丟失的工作

臨時修改

```bash

查看 log 與 relog 的區別

查看壓縮過的項目歷史

git log --oneline

查看本地操作記錄

git relog

簽出特定提交,這時候會處於分離狀態

git checkout [commit]

遵循 git 提示

git checkout -b [restoring_old_commit]

修改完相關工作後, 合併回分支

git checkout [working_branch] git merge [restoring_old_commit]

刪除臨時分支

git branch --delete [restoring_old_commit]

如果已經發布,需要刪除遠程分支

git push --delete [restoring_old_commit] ```

複製提交 cherry-pick

```bash

查看圖形化日誌

git log --online --graph

複製另一個分支的提交 在提交信息的末尾追加一行(cherry picked from commit ...),方便以後查到這個提交是如何產生的。

git cherry-pick -x [commit]

複製一段提交,不包含 start_commit

git cherry-pick [start_commit]..[end_commit]

複製一段提交,包含 start_commit

git cherry-pick [start_commit]^..[end_commit] ```

Q:誤刪除文件

```bash

通過 HEAD 的快捷方式

git reset HEAD [file_name]

通過 checkout 恢復被刪除文件

git checout -- [file_name]

合併指令

git reset --hard HEAD -- [file_name]

批量操作

git reset --hard HEAD ```

Q:撤銷分支合併

理想情況下,合併分支後,立馬意識到這是個錯誤合併。Git 在執行合併時候會保存一個指向最新提交的指針 ORIG_HEADs,這時候直接通過 reset 取消合併即可

bash git reset --merge ORIG_HEAD

若沒有意識到這是個錯誤合併,已經繼續提交了,那麼可以開始頭腦風暴了

unmerge.png

```bash

穩健的創建一個分支

git checkout -b [pre_branch]

截取希望保存的 commit

git cherry-pick commit_to_restore

回到錯誤分支

git checkout [error_branch]

回退

git reset [last_correct_commit]

再次合併

git merge [good_commits] ```

關於一點點小技巧

```bash

stash 進行保存, 該命令只會保存已知的文件進度

git stash save

為加入未跟蹤文件,可添加 --include-untracked

git stash save --include-untracked

亦可以丟棄它們

git stash save git clean -D

查看保存的 stash

git stash list

查看 stash 中的內容

git show [email protected]{0}

可以通過添加內容來區分 stash

git stash save --include-untracked "msg"

可以繼續工作

git stash list git stash apply [email protected]{0}

刪除 stash

git stash drop [email protected]{0}

應用後刪除 stash

git stash pop [email protected]{0} ```

關於小結

本文是關於《Git 團隊協作》的閲讀筆記,該書已經過於久遠,很多指令也已經更新,例如 git checkout [branch] 已經可以使用 git switch [branch] 來替代了,閲讀之後還是能比較清晰的

關於常用指令合集

| 命令 | 用途 | | --------------------------------------------------------------------- | ------------------------------------------------------------- | | git clone [url] | 下載遠程倉庫 | | git init | 初始化倉庫 | | git status | 獲取 git 狀態 | | git add --all OR git add . | 將所有修改過的文件和新文件添加至倉庫的暫存區 | | git commit -m '[message]' | 將所有暫存的文件提交至倉庫 | | git log | 查看項目歷史 | | git log --oneline | 查看壓縮過的項目歷史 | | git branch --list | 列出所有本地分支 | | git branch --all | 列出本地和遠程分支 | | git branch --remotes | 列出所有遠程分支 | | git checkout --track [branch_name] | 創建遠程分支的副本,在本地使用 | | git checkout [branch_name] | 切換到另一個本地分支 | | git checkout -b [branch_name] [branch_name_parent] | 從指定分支創建一個新分支 | | git add [file_name] | 僅暫存並準備提交指定文件 | | git add --patch [file_name] | 僅暫存並準備提交部分文件 | | git add HEAD [file_name] | 從暫存區移除提出的文件修改 | | git commit --amend | 使用當前暫存的修改更新之前的提交,並提供一個新的提交消息 | | git show commit | 輸出某個提交的詳細信息 | | git tag tag commit | 為某個提交對象打上標籤 | | git tag | 列出所有標籤 | | git show tag | 輸出所有帶標籤提交的詳細信息 | | git remote add [remote_name] [url] | 創建一個指向遠程倉庫的引用 | | git push | 將當前分支上的修改上傳至遠程倉庫 | | git remote --verbose | 列出所有可用遠程連接中 fetch 和 push 命令使用的 URL | | git push --set-upstream [remote_name] [branch_local] [branch_remote] | 將本地分支的副本推送至遠程服務器 | | git merge [branch] | 將當前存儲在另一分支的提交併入當前分支 | | git push --delete [remote_name] [branch_remote] | 在遠程服務器中移除指定名稱的分支 | | git checkout -b [branch_name] | 創建一個名為 branch 的分支 | | git add [file_name] | 暫存文件,準備提交至倉庫 | | git commit | 將暫存的變更保存至倉庫 | | git checkout [branch] | 切換到指定分支 | | git merge [branch] | 將 branch 中的提交併入當前分支 | | git branch --delete | 移除本地分支 | | git branch -D | 移除不包含併入其他分支的提交的本地分支 | | git clone [URL] | 下載一份遠程倉庫的副本 | | git log | 查看項目歷史記錄 | | git reflog | 查看分支的詳細歷史記錄 | | git checkout [commit] | 切換到另一個本地分支 | | git cherry-pick [commit] | 將提交從一個分支複製到另一個分支 | | git reset --merge ORIG_HEAD | 移除當前分支中所有在最近一次合併中引入的提交 | | git checkout HEAD [file_name] | 還原已變更但尚未提交的文件 | | git reset HEAD [file_name] | 從暫存區移除提出的文件修改 | | git reset --hard HEAD | 將所有已變更的文件還原到之前保存的狀態 | | git reset [commit] | 取消暫存在這個提交之前的所有提交中的變更 | | git rebase --interactive [commit] | 編輯,或壓縮提交後的所有提交 | | git rebase --continue | 在解決合併衝突後,繼續變基過程 | | git revert [commit] | 取消應用指定提交中的變更,創建一個共享友好的歷史記錄還原 | | git log --oneline --graph | 顯示分支的圖形化歷史記錄 | | git revert --mainline 1 [commit] | 反轉一個合併提交 | | git branch --contains [commit] | 列出所有包含指定提交對象的分支 | | git revert --no-commit [last_commit_to_keep..newest_commit_to_reject] | 使用一個提交反轉一組提交,而不是為每個撤銷的提交都創建一個對象 | | git filter-branch | 從倉庫中永久移除文件 | | git reflog expire | 忽略詳細歷史記錄,僅使用存儲的提交消息 | | git gc --prune=now | 運行垃圾回收器並確保所有未提交的變更從本地內存中移除 |