日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Git之深入解析工作流程、常用命令与Reset模式分析

發布時間:2024/5/21 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Git之深入解析工作流程、常用命令与Reset模式分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、Git 工作流程

① 工作區域

  • 四個區:
    • Workspace:工作區
    • Index / Stage:暫存區(和 git stash 命令暫存的地方不一樣)
    • Repository:倉庫區(或本地倉庫)
    • Remote:遠程倉庫
  • 五種狀態:
    • 未修改 Origin
    • 已修改 Modified
    • 已暫存 Staged
    • 已提交 Committed
    • 已推送 Pushed

  • 工作區:
    • 程序員進行開發改動的地方,是我們當前看到的,也是最新的。
    • 平常我們開發就是拷貝遠程倉庫中的一個分支,基于該分支進行開發。在開發過程中就是對工作區的操作。
  • 暫存區:
    • .git 目錄下的 index 文件,暫存區會記錄 git add 添加文件的相關信息(文件名、大小、timestamp,…),不保存文件實體,通過 id 指向每個文件實體。可以使用 git status 查看暫存區的狀態,暫存區標記了當前工作區中,哪些內容是被 git 管理的。
    • 當完成某個需求或功能后需要提交到遠程倉庫,那么第一步就是通過 git add 先提交到暫存區,被 git 管理。
  • 本地倉庫:
    • 保存了對象被提交過的各個版本,比起工作區和暫存區的內容,它要更舊一些。
    • git commit 后同步 index 的目錄樹到本地倉庫,方便從下一步通過 git push 同步本地倉庫與遠程倉庫的同步。
  • 遠程倉庫:
    • 遠程倉庫的內容可能被分布在多個地點的處于協作關系的本地倉庫修改,因此它可能與本地倉庫同步,也可能不同步,但是它的內容是最舊的。
    • 初始化遠程倉庫:
$ git init $ git add README.md $ git commit -m "first commit"
    • 關聯遠程倉庫:當使用上述命令來關聯遠程服務器倉庫的時候,本地 .git 目錄也是會發生改變的,通過命令查看 .git/config 文件的話,可以看到配置文件中出現了 [remote] 字段:
# 關聯遠程倉庫 $ git remote add origin git@github.com:escapelife/git-demo.git ? cat .git/config [core]repositoryformatversion = 0filemode = truebare = falselogallrefupdates = trueignorecase = trueprecomposeunicode = true[remote "origin"]url = git@github.com:escapelife/git-demo.gitfetch = +refs/heads/*:refs/remotes/origin/*
    • 推送本地分支:
      • 當執行如下命令,將本地 master 分支推送到遠程 origin 倉庫的 master 分支之后,登錄 GitHub 就可以看到推送的文件及目錄內容。
      • 推送分支內容的時候,會列舉推送的 objects 數量,并將其內容進行壓縮,之后推送到遠程的 GitHub 倉庫,并且創建一個遠程的 master 分支(origin 倉庫)。
# 推送本地分支 $ git push -u origin master
    • 推送之后,可以發現,本地的 .git 生成一些文件和目錄,它們都是什么呢?如下所示,會新增四個目錄和兩個文件,皆為遠程倉庫的信息,當通過命令查看 master 這個文件的內容時,會發現其也是一個 commit 對象。此時與本地 master 分支所指向的一致,而其用于表示遠程倉庫的當前版本,用于和本地進行區別和校對的:
? tree .git ├── logs │ ├── HEAD │ └── refs │ ├── heads │ │ ├── dev │ │ ├── master │ │ └── tmp │ └── remotes # 新增目錄 │ └── origin # 新增目錄 │ └── master # 新增文件 └── refs├── heads│ ├── dev│ ├── master│ └── tmp├── remotes # 新增目錄│ └── origin # 新增目錄│ └── master # 新增文件└── tags
  • 小結
    • 任何對象都是在工作區中誕生和被修改;
    • 任何修改都是從進入 index 區才開始被版本控制;
    • 只有把修改提交到本地倉庫,該修改才能在倉庫中留下痕跡;
    • 與協作者分享本地的修改,可以把它們 push 到遠程倉庫來共享。
    • 如下所示,直接闡述了四個區域之間的關系:

② 分支管理

  • 團隊開發中,遵循一個合理、清晰的 Git 使用流程,是非常重要的,否則每個人都提交一堆雜亂無章的 commit,項目很快就會變得難以協調和維護。
  • develop 分支 - 開發分支:
    • develop 分支作為常駐開發分支,用來匯總下個版本的功能提交,在下個版本的 release 分支創建之前不允許提交非下個版本的功能到 develop 分支;
    • develop 分支內容會自動發布到內網開發環境,確保 develop 分支隨時可編譯、可運行,上面的功能模塊是相對穩定、干凈的,隨時可以在 develop 上拉 feature 分支進行開發。
  • feature 分支 - 功能分支:
    • 對于新功能開發,應從 develop 上切出一個 feature 分支進行開發,命名格式為 feature/project,其中功能名使用小寫單詞結合中劃線連綴方式,如 feature/update-web-style;
    • feature 分支進行編譯通過并自測通過后,再合并到主干 develop 分支上。
  • 補丁分支 - hotfix branch:
    • 所謂補丁分支,就是當代碼已經部署到了正式環境之后發現沒有預測到底 Bug 時,通過補丁分支進行修改之后,生成補丁進行修復;
    • 當然也可以說不使用布丁分支,重新發布新版本也是可以的,但是這樣還是不太合理。
  • master 分支 - 主分支:
    • 當 develop 分支開發完成一個版本的時候,測試沒有問題之后就可以將其提交之后合并到 master 分支,master 分支內容會自動發布到內網正式環境;
    • 需要注意的是,一般情況從開發分支合入到主干分支不會有代碼沖突的,如果有的話那就是沒有按照上述流程嚴格執行的結果。
  • release 分支 - 預發布分支:
    • 最后就到了發包的最后階段,將已經在 master 內網正式環境上測試沒有問題的版本合入 release 分支,打包給客戶部署或者更新線上環境,完成最后的更新操作。

③ 代碼規范

  • 提交代碼其實是有很多講究的,如果都按照自己的想法隨意的提交代碼,到最后自己都不知道當時這次提交到底是為了解決什么問題,良好的代碼提交習慣即有利于自己之后的審查,也有助于其他人觀看,同時利用腳本來提取有價值的信息,如查看人個人的工作量,每日的工作任務等。
  • 提交模板 - commit model,我們更多使用的是如下簡化版 commit 模板:
# 模板格式 <提交類型>-<項目名稱>: <本次代碼提交的動機># 示例說明 feat-Pandas: update runtime to V1.3.0
  • 類型分類 - brand list:
提交類型類型說明使用頻率
feat增加新功能
fix修復 Bug
perf提高性能的代碼
style編碼規范或風格上的修改,不影響功能
docs僅改變項目文檔
build改變項目構建流程或包依賴
ci改變 CI 配置或執行腳本
test添加缺失測試或更正現有測試
refactor代碼更改既不修復錯誤也不添加功能

④ 使用技巧

  • 代碼合并 - pull request:
    • 功能分支合并進 master 分支,必須通過 Pull Request 操作,在 Gitlab 里面叫做 Merge Request。
    • Pull Request 本質其實就是一種對話機制,你可以在提交的時候附加上有用的信息,并 @ 相關的核心開發者或團隊,引起他們的注意,讓他們為了的代碼把好最后一道關卡,保證你的代碼質量。

  • 分支保護 - protected branch:
    • master 分支應該受到保護,不是每個人都可以修改這個分支,以及擁有審批 Pull Request 的權力;
    • Github 和 Gitlab 都提供“保護分支”的功能。

  • 新建問題 - issue:
    • Issue 用于Bug 追蹤和需求管理,建議先新建 Issue,再新建對應的功能分支;
    • 功能分支總是為了解決一個或多個 Issue,功能分支的名稱,可以與 issue 的名字保持一致,并且以 issue 的編號起首,比如 15-change-password;
    • 開發完成后,在提交說明里面,可以寫上"fixes #15" 或者 “closes #67”;
    • Github 和 gitlab 規定,只要 commit message 里面有下面這些動詞+編號,就會關閉對應的 issue。
# 以下詞語都可以關閉對應issue close closes closed fix fixes fixed resolve resolves resolved
    • 這種方式還可以一次關閉多個 issue,或者關閉其他代碼庫的 issue,格式是 username/repository#issue_number。Pull Request 被接受以后,issue 關閉,原始分支就應該刪除,如果以后該 issue 重新打開,新分支可以復用原來的名字。
  • 沖突解決 - merge:
    • Git 有兩種合并:一種是 “直進式合并”(fast forward)不生成單獨的合并節點;另一種是 “非直進式合并” (none fast-forword)會生成單獨節點;
    • 前者不利于保持 commit 信息的清晰,也不利于以后的回滾,建議總是采用后者(即使用 --no-ff 參數)只要發生合并,就要有一個單獨的合并節點。
  • 合并提交 - squash:
    • 為了便于他人閱讀你的提交,也便于 cherry-pick 或撤銷代碼變化,在發起 Pull Request 之前,應該把多個 commit 合并成一個。

    • 前提是,該分支只有你一個人開發,且沒有跟 master 合并過,這可以采用 rebase 命令附帶的 squash 操作:

# 第一步:新建分支 $ git checkout master $ git pull $ git checkout -b myfeature# 第二步:提交分支 $ git add . $ git status $ git commit -m "this is a test."# 第三步:與主干同步 $ git fetch origin $ git rebase origin/master# 第四步:合并多個commit為一個 # i參數表示互動并打開一個互動界面進行下一步操作 # 會列出當前分支最新的幾個commit,越下面越新 # 默認是pick類型,squash和fixup可以用來合并commit $ git rebase -i origin/master pick 07c5abd Introduce OpenPGP and teach basic usage s de9b1eb Fix PostChecker::Post#urls s 3e7ee36 Hey kids, stop all the highlighting pick fa20af3 git interactive rebase, squash, amend# 第六步:推送到遠程倉庫并發出合并請求 # 要加上force參數是因為rebase以后分支歷史改變 $ git push --force origin myfeature 編號參數類型使用說明
1p/pick正常選中
2r/reword正常選中,并且修改提交信息
3e/edit正常選中,rebase 時會暫停,允許你修改這個 commit
4s/squash正常選中,會將當前 commit 與上一個 commit 合并
5f/fixup與 squash 相同,但不會保存當前 commit 的提交信息
6x/exec執行其他 shell 命令

二、常用的 Git 命令

① HEAD

  • 在掌握具體命令前,先理解下 HEAD:

  • HEAD 始終指向當前所處分支的最新的提交點,所處的分支變化了,或者產生了新的提交點,HEAD 就會跟著改變。

② init

  • 執行 git init,完成如下命令之后,可以得到下圖所示的內容,右側的就是 git 創建的代碼倉庫,其中包含了用于版本管理所需要的內容:
$ mkdir git-demo $ cd git-demo && git init $ rm -rf .git/hooks/*.sample# 右邊執行 $ watch -n 1 -d find .

  • 生成的 .git 目錄的結構如下:
? tree .git .git ├── HEAD ├── config ├── description ├── hooks ├── info │ └── exclude ├── objects │ ├── info │ └── pack └── refs├── heads└── tags
  • .git/config - 當前代碼倉庫本地的配置文件:
    • 本地配置文件(.git/config)和全局配置文件(~/.gitconfig);
    • 通過執行如下命令,可以將用戶配置記錄到本地代碼倉庫的配置文件中去;
    • git config user.name “demo”;
    • git config user.email “demo@demo.com”。
? cat .git/config [core]repositoryformatversion = 0filemode = truebare = falselogallrefupdates = trueignorecase = trueprecomposeunicode = true[user]name = demoemail = demo@demo.com
  • .git/objects - 當前代碼倉庫代碼的存儲位置:
    • blob 類型;
    • commit 類型;
    • tree 類型。
# 均無內容 ? ll .git/objects total 0 drwxr-xr-x 2 escape staff 64B Nov 23 20:39 info drwxr-xr-x 2 escape staff 64B Nov 23 20:39 pack? ll .git/objects/info ? ll .git/objects/pack
  • .git/info - 當前倉庫的排除等信息:
? cat ./.git/info/exclude # git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~
  • .git/hooks - 當前代碼倉庫默認鉤子腳本:
./.git/hooks/commit-msg.sample ./.git/hooks/pre-rebase.sample ./.git/hooks/pre-commit.sample ./.git/hooks/applypatch-msg.sample ./.git/hooks/fsmonitor-watchman.sample ./.git/hooks/pre-receive.sample ./.git/hooks/prepare-commit-msg.sample ./.git/hooks/post-update.sample ./.git/hooks/pre-merge-commit.sample ./.git/hooks/pre-applypatch.sample ./.git/hooks/pre-push.sample ./.git/hooks/update.sample
  • .git/HEAD - 當前代碼倉庫的分支指針:
? cat .git/HEAD ref: refs/heads/master
  • .git/refs - 當前代碼倉庫的頭指針:
# 均無內容 ? ll .git/refs total 0 drwxr-xr-x 2 escape staff 64B Nov 23 20:39 heads drwxr-xr-x 2 escape staff 64B Nov 23 20:39 tags? ll .git/refs/heads ? ll .git/refs/tags
  • .git/description - 當前代碼倉庫的描述信息:
? cat .git/description Unnamed repository; edit this file 'description' to name the repository.

③ add

  • add 主要實現將工作區修改的內容提交到暫存區,交由 git 管理:
命令描述
git add添加當前目錄的所有文件到暫存區
git add < dir>添加指定目錄到暫存區,包括子目錄
git add < file1>添加指定文件到暫存區
  • 執行完成如下命令之后,可以得到下圖所示的內容,可以發現右側新增了一個文件,但是 git 目錄里面的內容絲毫沒有變化,這是因為,現在執行的修改默認是放在工作區的,而工作區里面的修改不歸 git 目錄去管理:
# 左邊執行 $ echo "hello git" > helle.txt $ git status $ git add hello.txt# 右邊執行 $ watch -n 1 -d find .


  • 生成的 8d 目錄以及下面的文件,而其名稱的由來是因為 git 對其進行了一個叫做 SHA1 的 Hash 算法,用于將文件內容或者字符串變成這么一串加密的字符:
# 查看objects的文件類型 $ git cat-file -t 8d0e41 blob# 查看objects的文件內容 $ git cat-file -p 8d0e41 hello git# 查看objects的文件大小 $ git cat-file -s 8d0e41 10# 拼裝起來 blob 10\0hello git
  • 執行 git add 命令將文件從工作區添加到暫存區里面,git 會把幫助我們生成一些 git 的對象,它存儲的是文件的內容和文件類型并不存儲文件名稱。
  • 為了驗證上述的說法,可以添加同樣的內容到另一個文件,然后進行提交,來觀察 .git 目錄的變化。可以看到,右側的 objects 目錄并沒有新增目錄和文件,這就可以證明,blob 類型的 object 只存儲的是文件的內容,如果兩個文件的內容一致的話,則只需要存儲一個 object 即可。
  • 那么 object 為什么沒有存儲文件名稱呢?這里因為 SHA1 的 Hash 算法計算哈希的時候,本身就不包括文件名稱,所以取什么名稱都是無所謂的。
# 左邊執行 $ echo "hello git" > tmp.txt $ git add tmp.txt# 右邊執行 $ watch -n 1 -d find .

④ commit

  • commit 主要實現將暫存區的內容提交到本地倉庫,并使得當前分支的 HEAD 向后移動一個提交點:
命令描述
git commit -m 提交暫存區到本地倉庫,message 代表說明信息
git commit -m 提交暫存區的指定文件到本地倉庫
git commit --amend -m 使用一次新的 commit,替代上一次提交
  • Git 倉庫中的提交記錄保存的是我們的目錄下所有文件的快照,就像是把整個目錄復制,然后再粘貼一樣,但比復制粘貼優雅許多。Git 希望提交記錄盡可能地輕量,因此在每次進行提交時,它并不會盲目地復制整個目錄,條件允許的情況下,它會將當前版本與倉庫中的上一個版本進行對比,并把所有的差異打包到一起作為一個提交記錄,Git 還保存提交的歷史記錄,這也是為什么大多數提交記錄的上面都有父節點的原因。
  • 當使用 add 命令將工作區提交到暫存區,而暫存區其實保存的是當前文件的一個狀態,其中包括有哪些目錄和文件,以及其對應的大小和內容等信息,但是最終是需要將其提交到代碼倉庫(本地)的,而其命令就是 git commit:

  • 而當執行 git commit 命令的時候,究竟都發生了什么呢?可以看到當提交之后,.git 目錄中生成了兩個信息的 object 對象,其中 logs 和 refs 目錄都有新的文件生成。通過如下操作,可以查看到其提交的類型和對應內容:
# 左邊執行 $ git commit -m "1st commit"$ git cat-file -t 6e4a700 # 查看commit對象的類型 $ git cat-file -p 6e4a700 # 查看commit對象的內容$ git cat-file -t 64d6ef5 # 查看tree對象的類型 $ git cat-file -p 64d6ef5 # 查看tree對象的內容# 右邊執行 $ watch -n 1 -d tree .git

  • 當執行 git commit 命令之后,會生成一個 commit 對象和一個 tree 對象,commit 對象內容里面包含一個 tree 對象和相關提交信息,而 tree 對象里面則包含這次提交版本里面的文件狀態(文件名稱和 blob 對象),這樣就知道了這次提交的變動:

  • 這次提交之后,處理 objects 目錄發生變動之外,還有一些其他的變化,比如 logs 和 refs 的目錄有所變化。再查看 refs 目錄里面的內容,發現其指向 6e4a70 這個 commit 對象,即當前 master 分支上面最新的提交就是這個 6e4a70。
  • 而這個 6e4a70 這個 commit 對象,有一個 HEAD 的指向,就是 .git 目錄下的 HEAD 文件,其實質就是一個指針,其永遠指向我們當前工作的分支,即這里我們工作在 master 分支上。當切換分支的時候,這個文件的指向也會隨機改變的。
# 左邊執行 $ cat .git/refs/heads/master $ cat .git/HEAD# 右邊執行 $ watch -n 1 -d tree .git

  • 當再次對 file2.txt 文件的內容進行變更、添加以及提交之后,發現在提交的時候,查看的 commit 對象的內容時,其包含有父節點的 commit 信息:
$ echo "file2.txt" > file2.txt $ git status $ git add file2.txt $ git ls-files -s $ git cat-file -p 0ac9638 $ git commit -m "2nd commit" $ git cat-file -p bab53ff $ git cat-file -p 2f07720# 右邊執行 $ watch -n 1 -d tree .git

  • Git 版本的提交流向如下:

  • 在 Git 中空文件夾是不算在追蹤范圍內的,而且添加文件夾并不會增加 object 對象,當查看 index 內容的時候,會發現文件名稱是包含相對路徑的。
  • 而當通過 commit 命令提交之后,會發現生成了三個 object 對象,因為 commit 操作不會生成 blob 對象,所以分別是一個 commit 對象和兩個 tree 對象。可以發現,tree 對象里面有包含一個目錄的 tree,其里面包含對象文件內容。
  • 下圖所示的文件狀態,可以體會到 git 中版本的概念,即 commit 對象指向一個該版本中的文件目錄樹的根(tree),然后 tree 在指向 blob 對象(文件)和 tree 對象(目錄),這樣就可以無限的往復下去形成一個完整的版本:
$ mkdir floder1 $ echo "file3" > floder1/file3.txt $ git add floder1 $ git ls-files -s $ git commit -m "3rd commit" $ git cat-file -p 1711e01 $ git cat-file -p 9ab67f8$ watch -n 1 -d tree .git

⑤ checkout

  • 當執行 checkout 命令的時候,其不光可以切換分支,而且可以切換到指定的 commit 上面,即 HEAD 文件會指向某個 commit 對象。在 Git 里面,將 HEAD 文件沒有指向 master 的這個現象稱之為 detached HEAD。這里不管 HEAD 文件指向的是分支名稱也好,是 commit 對象也罷,其實本質都是一樣的,因為分支名稱也是指向某個 commit 對象的。

  • 執行如下命令,結果如下:
# 左邊執行 $ git checkout 6e4a700 $ git log# 右邊執行 $ glo = git log

  • 當切換到指定的 commit 的時候,如果需要在對應的 commit 上繼續修改代碼提交的話,可以使用上文提及的 swtich 命令創建新分支,再進行提交。但是,通常我們都不會這么玩,都會使用 checkout 命令來創建新分支的:
$ git checkout -b tmp $ git log
  • 即使可以這樣操作,我們也很少使用,創建的 dev 分支的時候,創建該分支并有了一個新的提交,但是沒有合并到 master 分支就直接刪除,就無法再“看到”。其實,在 Git 里面任何的操作,比如分支的刪除,它只是刪除了指向某個特定 commit 的指針引用而已,而那個 commit 本身并不會被刪除,即 dev 分支的那個 commit 提交還是在的。
  • 那怎么找到這個 commit 呢?
    • 第一種方法:在 objects 目錄下面,自己一個一個看,然后切換過去;
    • 第二種方法:使用 Git 提供的 git reflog 專用命令來查找,該命令的作用就是用于將之前的所有操作都記錄下來。
# 左邊執行 $ git reflog $ git checkout 9fb7a14 $ git checkout -b dev# 右邊執行 $ glo = git log


⑥ branch

  • 涉及到協作,自然會涉及到分支。關于分支,大概有四種操作:
    • 展示分支
    • 切換分支
    • 創建分支
    • 刪除分支
  • 分支是用來標記特定代碼的提交,每一個分支通過 SHA1sum 值來標識,所以對分支的操作是輕量級的,改變的僅僅是 SHA1sum 值:
命令描述
git branch列出所有本地分支
git branch -r列出所有遠程分支
git branch -a列出所有本地分支和遠程分支
git branch < branch-name>新建一個分支,但依然停留在當前分支
git checkout -b < branch-name>新建一個分支,并切換到該分支
git branch --track < branch>新建一個分支,與指定的遠程分支建立追蹤關系
git checkout < branch-name>切換到指定分支,并更新工作區
git branch -d < branch-name>刪除分支
git push origin --delete < branch-name>刪除遠程分支
  • 分支就是一個有名字的(master/dev)指向 commit 對象的一個指針,在初始化倉庫的時候,會默認分配一個叫做 master 的分支(在最新的版本默認倉庫已經變更為 main),而 master 分支就是指向最新的一次提交。為什么需要給分支起名字呢?就是為了方便使用和記憶,可以簡單理解為 alias 命令的意義一致:

  • 要實現一個分支,最基本需要解決兩個問題,第一個就是需要存儲每一個分支指向的 commit,第二個問題就是在切換分支的時候幫助我們標識當前分支。在 git 中,它有一個非常特殊的 HEAD 文件,而 HEAD 文件是一個指針,其有一個特性就是總會指向當前分支的最新的一個 commit 對象。而這個 HEAD 文件正好,解決了這兩個問題。
  • 當從 master 切換分支到 dev 的時候,HEAD 文件也會隨即切換,即指向 dev 這個指針:

# 左邊執行 $ cat .git/HEAD $ cat .git/refs/heads/master $ git cat-file -t 1711e01# 右邊執行 $ glo = git log

  • 如下所示,分支切換之后,HEAD 指向發生變動:
# 左邊執行 $ git branch $ git branch dev $ ll .git/refs/heads $ cat .git/refs/heads/master $ cat .git/refs/heads/dev $ cat .git/HEAD $ git checkout dev $ cat .git/HEAD# 右邊執行 $ glo = git log

  • 即使刪除分支,但是該分支上一些特有的對象并不會被刪除的,這些對象其實就是俗稱的垃圾對象,還有多次使用 add 命令所產生的也有垃圾對象:
# 左邊執行 $ echo "dev" > dev.txt $ git add dev.txt $ git commit -m "1st commit from dev branch" $ git checkout master $ git branch -d dev $ git branch -D dev $ git cat-file -t 861832c $ git cat-file -p 861832c $ git cat-file -p 680f6e9 $ git cat-file -p 38f8e88# 右邊執行 $ glo = git log

⑦ fetch

命令描述
git fetch <遠程主機名>將某個遠程主機的更新全部取回本地
git fetch <遠程主機名> <分支名>取回特定分支的更新
git fetch origin master取回 origin 主機的 master 分支
  • 一旦遠程主機的版本庫有了更新(Git 術語叫做 commit),需要將這些更新取回本地,這時就要用到 git fetch 命令:
$ git fetch <遠程主機名>
  • 上面命令將某個遠程主機的更新,全部取回本地。git fetch 命令通常用來查看其他人的進程,因為它取回的代碼對你本地的開發代碼沒有影響。默認情況下,git fetch 取回所有分支(branch)的更新。如果只想取回特定分支的更新,可以指定分支名。
  • 取回更新后,會返回一個 FETCH_HEAD,指的是某個 branch 在服務器上的最新狀態,可以在本地通過它查看剛取回的更新信息:
$ git log -p FETCH_HEAD
  • 取回 origin 主機的 master 分支:
$ git fetch origin master
  • 所取回的更新,在本地主機上要用“遠程主機名/分支名”的形式讀取,比如 origin 主機的 master,就要用 origin/master 讀取。git branch 命令的 -r 選項,可以用來查看遠程分支,-a 選項查看所有分支:
$ git branch -r origin/master$ git branch -a* masterremotes/origin/master
  • 上面命令表示,本地主機的當前分支是 master,遠程分支是 origin/master。取回遠程主機的更新以后,可以在它的基礎上,使用 git checkout 命令創建一個新的分支。如下所示,在 origin/master 的基礎上,創建一個新分支:
$ git checkout -b newBrach origin/master
  • 此外,也可以使用 git merge 命令或者 git rebase 命令,在本地分支上合并遠程分支:
$ git merge origin/master # 或者 $ git rebase origin/master
  • 上面命令表示在當前分支上,合并 origin/master。

⑧ merge

  • merge 命令把不同的分支合并起來,如上圖,在實際開放中,我們可能從 master 分支中切出一個分支,然后進行開發完成需求,中間經過 R3、R4、R5 的 commit 記錄,最后開發完成需要合入 master 中,這便用到了 merge。
命令描述
git fetch < remote>merge 之前先拉一下遠程倉庫最新代碼
git merge < branch>合并指定分支到當前分支
  • 一般在 merge 之后,會出現 conflict,需要針對沖突情況,手動解除沖突,主要是因為兩個用戶修改了同一文件的同一塊區域。
    • 中斷合并:
git merge --abort
    • 撤銷合并:撤銷合并時采用 git reset/revert 操作。

⑨ rebase

  • rebase 又稱為衍合,是合并的另外一種選擇。在開始階段,我們處于 new 分支上,執行 git rebase dev,那么 new 分支上新的 commit 都在 master 分支上重演一遍,最后 checkout 切換回到 new 分支。這一點與 merge 是一樣的,合并前后所處的分支并沒有改變。
  • git rebase dev,通俗的解釋就是 new 分支想站在 dev 的肩膀上繼續下去,rebase 也需要手動解決沖突。
  • rebase 與 merge 的區別:
    • 現在有這樣的兩個分支:test 和 master,提交如下:
D---E test/A---B---C---F master
    • 在 master 執行 git merge test,然后會得到如下結果:
D--------E/ \A---B---C---F----G test, master
    • 在 master 執行 git rebase test,然后得到如下結果:
A---B---D---E---C'---F' test, master
    • 可以看到,merge 操作會生成一個新的節點,之前的提交分開顯示,而 rebase 操作不會生成新的節點,是將兩個分支融合成一個線性的提交。
  • 如果想要一個干凈的,沒有 merge commit 的線性歷史樹,那么應該選擇 git rebase;如果想保留完整的歷史記錄,并且想要避免重寫 commit history 的風險,應該選擇使用 git merge。

⑩ reset

  • reset 命令把當前分支指向另一個位置,并且相應的變動工作區和暫存區:
命令描述
git reset —soft < commit>只改變提交點,暫存區和工作目錄的內容都不改變
git reset —mixed < commit>改變提交點,同時改變暫存區的內容
git reset —hard < commit>暫存區、工作區的內容都會被修改到與提交點完全一致的狀態
git reset --hard HEAD讓工作區回到上次提交時的狀態

? revert

  • git revert 用一個新提交來消除一個歷史提交所做的任何修改:

  • revert 與 reset 的區別:

  • 說明:
    • git revert 是用一次新的 commit 來回滾之前的 commit,git reset 是直接刪除指定的commit;
    • 在回滾這一操作上看,效果差不多,但是在日后繼續 merge 以前的老版本時有區別。因為 git revert 是用一次逆向的 commit “中和”之前的提交,因此日后合并老的 branch 時,導致這部分改變不會再次出現,減少沖突。但是 git reset 是之間把某些 commit 在某個 branch 上刪除,因而和老的branch 再次 merge 時,這些被回滾的 commit 應該還會被引入,產生很多沖突。關于這一點,請參考:git reset revert 回退回滾取消提交返回上一版本;
    • git reset 是把 HEAD 向后移動了一下,而 git revert 是 HEAD 繼續前進,只是新的 commit 的內容和要 revert 的內容正好相反,能夠抵消要被 revert 的內容。

? push

  • 上傳本地倉庫分支到遠程倉庫分支,實現同步:
命令描述
git push < remote>上傳本地指定分支到遠程倉庫
git push < remote> --force強行推送當前分支到遠程倉庫,即使有沖突
git push < remote> --all推送所有分支到遠程倉庫
  • git push 命令用于將本地分支的更新,推送到遠程主機,它的格式與 git pull 命令相仿:
$ git push <遠程主機名> <本地分支名>:<遠程分支名>
  • 注意,分支推送順序的寫法是<來源地>:<目的地>,所以 git pull 是<遠程分支>:<本地分支>,而 git push 是<本地分支>:<遠程分支>。如果省略遠程分支名,則表示將本地分支推送與之存在“追蹤關系”的遠程分支(通常兩者同名),如果該遠程分支不存在,則會被新建。
  • 將本地的 master 分支推送到 origin 主機的 master 分支,如果后者不存在,則會被新建:
$ git push origin master
  • 如果省略本地分支名,則表示刪除指定的遠程分支,因為這等同于推送一個空的本地分支到遠程分支。刪除 origin 主機的 master 分支,如下所示:
$ git push origin :master # 等同于 $ git push origin --delete master
  • 如果當前分支與遠程分支之間存在追蹤關系,則本地分支和遠程分支都可以省略。將當前分支推送到 origin 主機的對應分支:
$ git push origin
  • 如果當前分支只有一個追蹤分支,那么主機名都可以省略:
$ git push
  • 如果當前分支與多個主機存在追蹤關系,則可以使用 -u 選項指定一個默認主機,這樣后面就可以不加任何參數使用 git push。將本地的 master 分支推送到 origin 主機,同時指定 origin 為默認主機,后面就可以不加任何參數使用 git push:
$ git push -u origin master
  • 不帶任何參數的 git push,默認只推送當前分支,這叫做 simple 方式。此外,還有一種 matching 方式,會推送所有有對應的遠程分支的本地分支。Git 2.0 版本之前,默認采用 matching 方法,現在改為默認采用 simple 方式,如果要修改這個設置,可以采用 git config 命令:
$ git config --global push.default matching # 或者 $ git config --global push.default simple
  • 還有一種情況,就是不管是否存在對應的遠程分支,將本地的所有分支都推送到遠程主機,這時需要使用 --all 選項,將所有本地分支都推送到 origin 主機:
$ git push --all origin
  • 如果遠程主機的版本比本地版本更新,推送時 Git 會報錯,要求先在本地做 git pull 合并差異,然后再推送到遠程主機。這時,如果一定要推送,可以使用 --force 選項。如下所示,使用 --force 選項,結果導致遠程主機上更新的版本被覆蓋,除非很確定要這樣做,否則應該盡量避免使用 --force 選項:
$ git push --force origin
  • 最后,git push 不會推送標簽(tag),除非使用 --tags 選項:
$ git push origin --tags

? pull

  • git pull 命令的作用是,取回遠程主機某個分支的更新,再與本地的指定分支合并。它的完整格式稍稍有點復雜:
$ git pull <遠程主機名> <遠程分支名>:<本地分支名>
  • 比如,取回 origin 主機的 next 分支,與本地的 master 分支合并,需要寫成下面這樣:
$ git pull origin next:master
  • 如果遠程分支是與當前分支合并,則冒號后面的部分可以省略:
$ git pull origin next
  • 上面命令表示,取回 origin/next 分支,再與當前分支合并。實質上,這等同于先做 git fetch,再做 git merge:
$ git fetch origin $ git merge origin/next
  • 在某些場合,Git 會自動在本地分支與遠程分支之間,建立一種追蹤關系(tracking)。比如,在 git clone 的時候,所有本地分支默認與遠程主機的同名分支,建立追蹤關系,也就是說,本地的 master 分支自動“追蹤” origin/master 分支。
  • Git 也允許手動建立追蹤關系,如下,指定 master 分支追蹤 origin/next 分支:
git branch --set-upstream master origin/next
  • 如果當前分支與遠程分支存在追蹤關系,git pull 就可以省略遠程分支名。如下,本地的當前分支自動與對應的 origin 主機"追蹤分支"(remote-tracking branch)進行合并:
$ git pull origin
  • 如果當前分支只有一個追蹤分支,連遠程主機名都可以省略。如下,當前分支自動與唯一一個追蹤分支進行合并:
$ git pull
  • 如果合并需要采用 rebase 模式,可以使用 --rebase 選項。
$ git pull --rebase <遠程主機名> <遠程分支名>:<本地分支名>
  • 如果遠程主機刪除了某個分支,默認情況下,git pull 不會在拉取遠程分支的時候,刪除對應的本地分支。這是為了防止,由于其他人操作了遠程主機,導致 git pull 不知不覺刪除了本地分支。
    但是,我們可以改變這個行為,加上參數 -p 就會在本地刪除遠程已經刪除的分支:
$ git pull -p # 等同于下面的命令 $ git fetch --prune origin $ git fetch -p

? stash

命令描述
git stash save “xx”執行存儲,并添加備注,只執行 git stash 也是可以的,但查找時不方便識別
git stash list查看 stash 了哪些存儲
git stash show顯示做了哪些修改,默認 show 第一個存儲,如果要顯示其他存儲,后面加stash@{$num},比如第二個 git stash show stash@{1}
git stash show -p顯示第一個存儲的改動,如果想顯示其他存儲,加上 stash@{$num},比如第二個:git stash show stash@{1} -p
git stash apply應用某個存儲,但不會把存儲從存儲列表中刪除,默認使用第一個存儲,即 stash@{0},如果要使用其他的,git stash apply stash@{$num} , 比如第二個:git stash apply stash@{1}
git stash pop命令恢復之前緩存的工作目錄,將緩存堆棧中的對應 stash 刪除,并將對應修改應用到當前的工作目錄下,默認為第一個 stash,即 stash@{0},如果要應用并刪除其他 stash,命令:git stash pop stash@{$num},比如應用并刪除第二個:git stash pop stash@{1}
git stash drop stash@{$num}丟棄 stash@{$num} 存儲,從列表中刪除這個存儲
git stash clear刪除所有緩存的stash

  • 注意:沒有在 git 版本控制中的文件,是不能被 git stash 存起來的。如果新增了一個文件,直接執行 git stash 是不會存起來的,可以先執行 git add,再執行 git stash。這個時候,想切分支就再也不會報錯有改動未提交了。
  • 如果要應用這些 stash,直接使用 git stash apply 或者 git stash pop 就可以再次導出來了。
  • 總結:
    • git add 只是把文件加到 git 版本控制里,并不等于就被 stash 起來了,git add 和 git stash 沒有必然的關系,但是執行 git stash 能正確存儲的前提是文件必須在 git 版本控制中才行。
    • 常規 git stash 的一個限制是它會一下暫存所有的文件。有時,只備份某些文件更為方便,讓另外一些與代碼庫保持一致。一個非常有用的技巧,用來備份部分文件:
      • add 不想備份的文件;
      • 調用 git stash –keep-index,只會備份那些沒有被 add 的文件;
      • 調用 git reset 取消已經 add 的文件的備份,繼續自己的工作。

? clone

  • 遠程操作的第一步,通常是從遠程主機克隆一個版本庫,這時就要用到 git clone 命令:
$ git clone <版本庫的網址>
  • 例如,克隆 jQuery 的版本庫:
$ git clone https://github.com/jquery/jquery.git
  • 命令會在本地主機生成一個目錄,與遠程主機的版本庫同名。如果要指定不同的目錄名,可以將目錄名作為 git clone 命令的第二個參數:
$ git clone <版本庫的網址> <本地目錄名>
  • git clone 支持多種協議,除了 HTTP(s) 以外,還支持 SSH、Git、本地文件協議等,如下:
$ git clone http[s]://example.com/path/to/repo.git/ $ git clone ssh://example.com/path/to/repo.git/ $ git clone git://example.com/path/to/repo.git/ $ git clone /opt/git/project.git $ git clone file:///opt/git/project.git $ git clone ftp[s]://example.com/path/to/repo.git/ $ git clone rsync://example.com/path/to/repo.git/
  • SSH 協議還有另一種寫法:
$ git clone [user@]example.com:path/to/repo.git/
  • 通常來說,Git 協議下載速度最快,SSH 協議用于需要用戶認證的場合。

? remote

  • 為了便于管理,Git 要求每個遠程主機都必須指定一個主機名,git remote 命令就用于管理主機名。不帶選項的時候,git remote 命令列出所有遠程主機:
$ git remote origin
  • 使用 -v 選項,可以參看遠程主機的網址:
$ git remote -v origin git@github.com:jquery/jquery.git (fetch) origin git@github.com:jquery/jquery.git (push)
  • 上面命令表示,當前只有一臺遠程主機,叫做 origin,以及它的網址。克隆版本庫的時候,所使用的遠程主機自動被 Git 命名為 origin,如果想用其他的主機名,需要用 git clone 命令的 -o 選項指定:
$ git clone -o jQuery https://github.com/jquery/jquery.git $ git remote jQuery
  • 上面命令表示,克隆的時候,指定遠程主機叫做 jQuery。git remote show 命令加上主機名,可以查看該主機的詳細信息:
$ git remote show <主機名>
  • git remote add 命令用于添加遠程主機:
$ git remote add <主機名> <網址>
  • git remote rm 命令用于刪除遠程主機:
$ git remote rm <主機名>
  • git remote rename 命令用于遠程主機的改名:
$ git remote rename <原主機名> <新主機名>

? 其他命令

命令描述
git status顯示有變更的文件
git log顯示當前分支的版本歷史
git diff顯示暫存區和工作區的差異
git diff HEAD顯示工作區與當前分支最新 commit 之間的差異
git diff --cached查看到暫存區和本地倉庫之間的差異
git diff master查看到master和本地倉庫之間的差異
git cherry-pick <commit>選擇一個 commit,合并進當前分支

三、Git Reset 三種模式

  • 使用 Git 時有可能 commit 提交代碼后,發現這一次 commit 的內容是有錯誤的,那么有兩種處理方法:
    • 修改錯誤內容,再次 commit 一次;
    • 使用 git reset 命令撤銷這一次錯誤的 commit;
    • 第一種方法多一條 commit 記錄;第二種方法,錯誤的 commit 不會被保留下來。
  • 一句話概括 git reset:
git reset:Reset current HEAD to the specified state // 讓 HEAD 指針指向其他的地方
  • 例如,有一次 commit 不是很滿意,需要回到上一次的 Commit 里面,那么這個時候就需要通過 reset,把 HEAD 指針指向上一次的 commit 的點,它有三種模式:soft、mixed、hard,如下所示:

  • 理解了這三個模式,對于使用這個命令很有幫助。在理解這三個模式之前,需要略微知道一點 Git 的基本流程,如下所示:
    • Working Tree 當前的工作區域;
    • Index/Stage 暫存區域,和 git stash 命令暫存的地方不一樣,使用 git add xx,就可以將 xx 添加近 Stage 里面;
    • Repository 提交的歷史,即使用 git commit 提交后的結果。

  • 簡單敘述一下把文件存入 Repository 流程:
    • 剛開始 working tree、index 與 repository(HEAD) 里面的內容都是一致的:

    • 當 git 管理的文件夾里面的內容出現改動后,此時 working tree 的內容就會跟 index 及 repository(HEAD) 的不一致,而 Git 知道是哪些文件(Tracked File)被改動過,直接將文件狀態設置為 modified (Unstaged files):
    • 當執行 git add 后,會將這些改變的文件內容加入 index 中 (Staged files),所以此時 working tree 跟 index 的內容是一致的,但與 repository(HEAD) 內容不一致:

    • 接著執行 git commit 后,將 Git 索引中所有改變的文件內容提交至 Repository 中,建立出新的 commit 節點(HEAD)后,working tree、index 與 repository(HEAD) 區域的內容又會保持一致:

① reset --hard:重置 stage 區和工作目錄

  • reset --hard 會在重置 HEAD 和 branch 的同時,重置 stage 區和工作目錄里的內容。當在 reset 后面加了 --hard 參數時,stage 區和工作目錄里的內容會被完全重置為和 HEAD 的新位置相同的內容,換句話說,就是沒有 commit 的修改會被全部擦掉:

  • 然后,執行 reset 并附上了 --hard 參數:
git reset --hard
  • HEAD 和當前 branch 切到上一條 commit 的同時,工作目錄里的新改動和已經 add 到 stage 區的新改動也一起全都消失:

  • 可以看到,在 reset --hard 后,所有的改動都被擦掉。

② reset --soft:保留工作目錄,并把重置 HEAD 所帶來的新的差異放進暫存區

  • reset --soft 會在重置 HEAD 和 branch 時,保留工作目錄和暫存區中的內容,并把重置 HEAD 所帶來的新的差異放進暫存區。
  • 那么,什么是“重置 HEAD 所帶來的新的差異”?如下所示:

  • 由于 HEAD 從 4 移動到了 3,而且在 reset 的過程中工作目錄和暫存區的內容沒有被清理掉,所以 4 中的改動在 reset 后就也成了工作目錄新增的“工作目錄和 HEAD 的差異”,這就是上面一段中所說的“重置 HEAD 所帶來的差異”。
  • 此模式下會保留 working tree 工作目錄的內容,不會改變到目前所有的 git 管理的文件夾的內容;也會保留 index 暫存區的內容,讓 index 暫存區與 working tree 工作目錄的內容是一致的。就只有 repository 中的內容的更變需要與 reset 目標節點一致,因此原始節點與 reset 節點之間的差異變更集合會存在與 index 暫存區中(Staged files),所以可以直接執行 git commit 將 index 暫存區中的內容提交至 repository 中。
  • 當我們想合并“當前節點”與“reset 目標節點”之間不具有太大意義的 commit 記錄(可能是階段性地頻繁提交)時,可以考慮使用 Soft Reset 來讓 commit 演進線圖較為清晰點:

    • 同樣的情況下,把修改后的 AppDelegate.h 文件 add 到 stage 區,修改后的 AppDelegate.m 保留在工作目錄:

    • 查看當前最新的 commit 記錄:
git show --stat

    • 這時,執行 git reset --soft HEAD^:

    • 那么除了 HEAD 和它所指向的 branch1 被移動到 HEAD^ 之外,原先 HEAD 處 commit 的改動(README.md 文件)也會被放進暫存區。
  • 這就是 --soft 和 --hard 的區別:–hard 會清空工作目錄和暫存區的改動,而 --soft 則會保留工作目錄的內容,并把因為保留工作目錄內容所帶來的新的文件差異放進暫存區。

③ reset --mixed:保留工作目錄,并清空暫存區

  • reset 如果不加參數,那么默認使用 --mixed 參數,它的行為是:保留工作目錄,并且清空暫存區。也就是說,工作目錄的修改、暫存區的內容以及由 reset 所導致的新的文件差異,都會被放進工作目錄。簡而言之,就是把所有差異都混合(mixed)放在工作目錄中。
  • 以上面的情況為例:

  • 工作目錄的內容和 --soft 一樣會被保留,但和 --soft 的區別在于,它會把暫存區清空,并把原節點和 reset 節點的差異的文件放在工作目錄。總而言之,工作目錄的修改、暫存區的內容以及由 reset 所導致的新的文件差異,都會被放進工作目錄。

④ Reset 三種模式總結

  • reset 的本質:移動 HEAD 以及它所指向的 branch。實質上,reset 這個指令雖然可以用來撤銷 commit,但它的實質行為并不是撤銷,而是移動 HEAD ,并且捎帶上 HEAD 所指向的 branch(如果有的話)。也就是說,reset 這個指令的行為其實和它的字面意思“重置”十分相符:它是用來重置 HEAD 以及它所指向的 branch 的位置的。
  • 而 reset --hard HEAD^ 之所以起到了撤銷 commit 的效果,是因為它把 HEAD 和它所指向的 branch 一起移動到了當前 commit 的父 commit 上,從而起到了“撤銷”的效果:

  • Git 的歷史只能往回看,不能向未來看,所以把 HEAD 和 branch 往回移動,就能起到撤回 commit 的效果。所以同理,reset --hard 不僅可以撤銷提交,還可以用來把 HEAD 和 branch 移動到其他的任何地方:
git reset --hard branch2

⑤ reset 三種模式區別和使用場景

  • 區別:
    • –hard:重置位置的同時,直接將 working Tree 工作目錄、index 暫存區及 repository 都重置成目標 Reset 節點的內容,所以效果看起來等同于清空暫存區和工作區;
    • –soft:重置位置的同時,保留 working Tree 工作目錄和 index 暫存區的內容,只讓 repository 中的內容和 reset 目標節點保持一致,因此原節點和 reset 節點之間的【差異變更集】會放入 index 暫存區中(Staged files)。所以效果看起來就是工作目錄的內容不變,暫存區原有的內容也不變,只是原節點和 Reset 節點之間的所有差異都會放到暫存區中。
    • –mixed(默認):重置位置的同時,只保留 Working Tree 工作目錄的內容,但會將 Index 暫存區和 Repository 中的內容更改和 reset 目標節點一致,因此原節點和 Reset 節點之間的【差異變更集】會放入 Working Tree 工作目錄中。所以效果看起來就是原節點和 Reset 節點之間的所有差異都會放到工作目錄中。
  • 使用場景:
    • –hard:
      • 要放棄目前本地的所有改變時,即去掉所有 add 到暫存區的文件和工作區的文件,可以執行 git reset -hard HEAD 來強制恢復 git 管理的文件夾的內容及狀態;
      • 真的想拋棄目標節點后的所有 commit(可能覺得目標節點到原節點之間的 commit 提交都是錯了,之前所有的 commit 有問題)。
    • –soft:
      • 原節點和 reset 節點之間的【差異變更集】會放入 index 暫存區中(Staged files),所以假如之前工作目錄沒有改過任何文件,也沒 add 到暫存區,那么使用 reset --soft 后,可以直接執行 git commit 將 index 暫存區中的內容提交至 repository 中。為什么要這樣呢?
      • 這樣做的使用場景是:假如想合并「當前節點」與「reset 目標節點」之間不具太大意義的 commit 記錄(可能是階段性地頻繁提交,就是開發一個功能的時候,改或者增加一個文件的時候就commit,這樣做導致一個完整的功能可能會好多個 commit 點,這時假如需要把這些 commit 整合成一個 commit 的時候)時,可以考慮使用 reset --soft 來讓 commit 演進線圖較為清晰。總而言之,可以使用 --soft 合并 commit 節點。
    • –mixed(默認):
      • 使用完 reset --mixed 后,可以直接執行 git add 將這些改變果的文件內容加入 index 暫存區中,再執行 git commit,將 Index 暫存區 中的內容提交至 Repository 中,這樣一樣可以達到合并 commit 節點的效果(與上面 --soft 合并 commit 節點差不多,只是多了 git add 添加到暫存區的操作);
      • 移除所有 Index 暫存區中準備要提交的文件(Staged files),可以執行 git reset HEAD 來 Unstage 所有已列入 Index 暫存區的待提交的文件(有時候發現 add 錯文件到暫存區,就可以使用命令);
      • commit 提交某些錯誤代碼,或者沒有必要的文件也被 commit 上去,不想再修改錯誤再 commit (因為會留下一個錯誤 commit 點),可以回退到正確的 commit 點上,然后所有原節點和 reset 節點之間差異會返回工作目錄,假如有個沒必要的文件的話就可以直接刪除了,再 commit 上去就 OK 了。

四、撤銷修改

① 已修改,未暫存

  • 如果只是在編輯器里修改了文件,但還沒有執行 git add .,這時候文件還在工作區,并沒有進入暫存區,可以用:
git checkout .
  • 或者
git reset --hard
  • 來進行撤銷操作。


  • 可以看到,在執行完 git checkout . 之后,修改已被撤銷,git diff 沒有任何內容了。git add . 的反義詞是 git checkout .,做完修改之后,如果想向前走一步,讓修改進入暫存區,就執行git add .,如果想向后退一步,撤銷剛才的修改,就執行 git checkout .。

② 已暫存,未提交

  • 已經執行 git add .,但還沒有執行 git commit -m “comment”:
git reset // 退回到 git add . 之前,即本地文件處于已修改未暫存狀態 git checkout . // 撤銷修改
  • 或者
git reset --hard
  • 可以發現兩種情況都可以用同一個命令 git reset --hard 來完成,這個強大的命令,可以一步到位地把你的修改完全恢復到未修改的狀態。

③ 已提交,未推送

  • 執行 git commit 后,代碼已經進入了本地倉庫:
git reset --hard origin/master
  • 還是這個 git reset --hard 命令,只不過這次多了一個參數 origin/master,正如上文中的,origin/master 代表遠程倉庫,既然已經污染了本地倉庫,那么就從遠程倉庫把代碼取回來。

④ 已推送

  • 如果執行了 git add -> git commit -> git push 了,這時代碼已經進入遠程倉庫。如果想恢復的話,只需要先撤銷本地修改,再強制 push 到遠程倉庫:
git reset --hard HEAD^ git push -f

五、同時 push 到多個遠程倉庫

  • 進入項目目錄,打開 .git/config 文件(.git 是隱藏目錄,需要打開顯示隱藏文件):

  • 只需要在 [remote “origin”] 下增加一條 url 地址,就可以在 push 時推送到多個遠程倉庫:

  • 如果使用 sourceTree 軟件進行 git 操作,那么需要注意在 settings -> 高級下面,多個遠程地址對應的驗證信息是否正確:

總結

以上是生活随笔為你收集整理的Git之深入解析工作流程、常用命令与Reset模式分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 亚洲国产av一区二区三区 | 久久精品一区 | 无码少妇一区二区三区 | 久久久久网 | 一本一道久久综合狠狠老精东影业 | 欧美日韩高清 | 91看片在线播放 | 99reav | 黄色av免费观看 | av网址在线免费观看 | 日韩免费网| 久久艹这里只有精品 | 97久久免费视频 | 精品久久久久亚洲 | 一区二区三区在线免费观看视频 | 懂色av| 91欧美在线视频 | 亚洲一区二区播放 | 97超碰福利 | 国产精品视频999 | 久久综合加勒比 | 国产chinesehd精品露脸 | 欧美群交射精内射颜射潮喷 | 久久亚洲私人国产精品va | 丝袜老师办公室里做好紧好爽 | 伊人称影院 | 91在线观看成人 | 亚洲精品 日韩无码 | 97精品人人妻人人 | 蜜臀尤物一区二区三区直播 | 亚欧成人精品一区二区 | 大尺度床戏揉捏胸视频 | 在线天堂v | 一级少妇片 | 天堂国产精品 | 99久久精品国产成人一区二区 | 日本裸体xx少妇18在线 | 美女视频黄色 | 欧美日韩人妻精品一区二区三区 | 我要看一级片 | 女人的洗澡毛片毛多 | 日本乱大交xxxx公交车 | 黄色a在线| av不卡免费在线 | www.av欧美| 色福利在线 | 日本大尺度做爰呻吟舌吻 | 黄色片99 | 成人一级片在线观看 | 欧美日韩成人在线观看 | 影音先锋色小姐 | 国产不卡在线播放 | 色老大网站 | 网红av在线 | av免播放器 | 高h喷汁呻吟3p | 国产精品图片 | 免费精品一区 | 成人av电影免费观看 | 国产人人草 | 久久一二三区 | 91极品视觉盛宴 | 中文字幕免费观看视频 | 91成人观看 | 激情久久一区 | 男人和女人日批视频 | 波多野吉衣在线视频 | 成人一区二区av | 欧美最猛性xxxxx(亚洲精品) | 国产精品99一区二区三区 | 韩日午夜在线资源一区二区 | 中文字幕永久在线播放 | 乱图区| 三年中文在线观看免费观看 | 91精品国产入口在线 | 黄床大片 | www.亚洲黄色| 伊人色区 | 免费成人毛片 | 自拍偷拍小视频 | 久久久久久婷婷 | 亚洲精品久久久狠狠狠爱 | freesex性hd公交车上 | 日韩影院在线 | 欧美一级夜夜爽 | v在线| 性色生活片 | 超碰公开免费 | 亚洲av永久无码精品一百度影院 | 三级视频小说 | 男女激情大尺度做爰视频 | 伊人91在线 | 久久国产柳州莫菁门 | 一级做a爱片性色毛片 | 亚洲国产精品99久久久久久久久 | 5566色 | 成人免费视频网址 | 日韩欧美字幕 | 中文字幕日韩亚洲 |