<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Git使用記錄

      目錄

      1 介紹

      ??Git是一個開源的版本管理系統,和Linux系統是同一作者——Linus Torvalds,用于管理Linux內核開發而開發的,作者給它起名Git(飯桶),介紹是The stupid content tracker, 傻瓜內容跟蹤器……
      ??為什么要認真了解它?因為它是個主流團隊協作工具,協作工具用不好會影響到別人——《因代碼不規范,國外程序員槍擊4個同事》,據說是因為同事每次都git push -f,也不知道真實情況如何……
      ??最近使用比較多,Git命令的各種參數每次都是查完就忘,除了一些常用的外,遇到復雜點的場景都得重新查,其實也有一些圖形界面工具(類似Sourcetree[1])可以簡化Git的使用,不過相對于命令行來說,圖形界面的一個動作可能會執行一套組合命令,有時感覺不太可控。Git的官方文檔[2]已經很詳細,但太全面了查起某個具體功能來也有點大海撈針的感覺,為了擺脫查找的耗費,把常用命令和常見場景總結一下,畢竟查自己的要比查搜索引擎的要更方便。
      ??有關Git相關的基礎知識可以參考Git教程-廖雪峰的官方網站[3],講得挺清晰。

      1.1 示意圖

      1.1.1 主要區域

      Git工作涉及的區域主要有四個——工作樹、、暫存區、本地分支、遠端分支。

      graph LR W[工作樹<br/>Working Tree<br/>Working Directory] -- add --> I I[暫存區<br/>Index<br/>Stage] -- commit --> B B[本地分支<br/>Branch<br/>] -- push --> REB B -- checkout --> W REB[遠端分支<br/>RemoteBranch<br/>] -- pull --> B

      圖中的命令標示的只是常規使用方式,Git的命令通過附帶參數的不同可以達到不同的效果,同一個效果也可以使用不同的命令來完成,并不是絕對的。

      工作樹(工作區)

      工作樹就是當前作業正在進行的地方,所有對文件的改動都是在工作樹上進行的。

      官方文檔里叫“Working Tree”,也有的資料里叫“Working Directory”。

      暫存區(Index)

      修改完成的文件可以放入暫存區,此時的文件狀態變為Staged,暫存區是工作區和分支之間的過渡區域。

      官方文檔里叫“Index”,也有的資料里叫“Stage”。

      分支(Branch)

      分支是由多個commit構成的歷史記錄的鏈路,可以存在多條不同的分支。

      每個分支的瞬時狀態其實是指向某個特定commit的指針;
      本地目錄中的“.git/refs/heads/”目錄以普通的文本形式保存了本地倉庫下的所有分支。

      遠端分支(RemoteBranch)

      保存在服務器端的Git倉庫內的分支。

      本地目錄中的“.git/refs/remotes/”目錄以普通的文本形式保存了遠端倉庫下的所有分支,也包含遠端Head指針當前的位置。

      1.1.2 文件狀態

      Git管理的文件有四種狀態——Untracked、Unmodify、Modified、Staged。

      sequenceDiagram participant Untracked participant Unmodify participant Modified participant Staged Untracked->>Staged: 對文件執行git add命令,進行暫存 Unmodify->>Modified: 修改文件 Modified->>Staged: 對文件執行git add命令,進行暫存 Staged->>Unmodify: 對文件執行git commit命令,提交文件 Unmodify->>Untracked: 對文件執行git rm命令,移除文件

      圖中的命令同樣只是常規使用方式,命令通過附帶參數可以達到不同效果,同一效果也可以使用不同命令來完成,并不絕對。

      Untracked

      文件未跟蹤。此文件在文件夾中, 但沒有加入版本跟蹤, 不參與版本控制。

      可通過git add命令變為Staged狀態。

      Unmodify

      文件已跟蹤, 但未修改。文件與版本庫中完全一致。

      可直接修改文件, 變為Modified狀態。
      使用git rm命令可將文件移出版本跟蹤, 則成為Untracked狀態。

      Modified

      文件已修改。文件與版本庫中不一致

      可通過git add命令變為Staged狀態。
      使用git restore命令可丟棄修改,返回Unmodify狀態。

      Staged

      文件已暫存。文件放入暫存區。

      執行git commit可將修改同步到本地庫中, 執行后版本庫中的文件和本地文件又變為一致, 文件為Unmodify狀態。

      1.2 概念

      提交(commit)

      提交是從暫存區向分支進行上傳的操作,每一次提交就會生成一個對應的commit。

      每次進行提交時,Git通過SHA-1算法生成一個40位的十六進制Hash值,該SHA1哈希值就是commit-id,這個commit-id使每次commit提交都是獨一無二的;
      每個commit提交還會包含它的上一次commit提交的哈希值,Git以此來構建歷史記錄的提交鏈路;
      每個commit-id是由其內容決定的,數值不能被改變,要修改commit-id只能重新創建一個全新的提交。
      commit內部包含tree、blob,需要進一步了解的可以參考Git中三大對象commit、tree和blob之間的關系[4]

      Head指針(HEAD)

      一個指向你正在工作的當前分支的指針。

      Head指針一般都是指的本地Head指針,遠端其實也有這個Head指針,但是正常情況下不會手動去更改遠端Head指針的位置。
      本地目錄中的“.git/HEAD”文件以普通的文本形式保存了本地倉庫的Head指針。

      本地倉庫(Repository)

      通過git init對文件夾進行初始化,Git會在對應的文件夾構建管理空間,包括配置信息,commit提交信息,以及分支狀態等。

      本地倉庫包含了暫存區和本地分支;
      本地目錄中的“.git/”隱藏目錄保存了Git在當前文件夾的管理信息。

      遠端倉庫(Remote)

      服務器端的Git倉庫,可以向遠端服務器推送代碼用于開源或者團隊協作。

      遠端倉庫名默認為“origin”;
      本地目錄中的“.git/ORIG_HEAD”文件以普通的文本形式保存了遠端倉庫的Head指針對應的commit-id。

      上游分支/下游分支(upstream/downstream)

      某個本地分支與某個遠端分支建立了追蹤關系,則該遠端分支成為該本地分支的上游分支;該本地分支則是該遠端分支的下游分支。

      upstream常作為命令中的參數被使用,例如:--set-upstream-to、--set-upstream等

      標簽(tag)

      在某個具有特定意義的commit上做的標記,一般用來標識具有里程碑意義的各個commit,比如項目發布的各個歷史版本都可以打上對應的tag來進行標記。

      引用(refs)

      refs是采用更加親切的名稱來指定某個commit,而不必使用Hash值來指定對應的commit,分支名就是一種引用。

      其實引用直接或者間接指向了某個commit提交;
      分支名是一種引用,比如分支“master”,但它的引用全稱是“refs/heads/master”;
      引用的具體內容以普通的文本形式被放在“.git/refs/”路徑下;
      “refs/heads/”下描述了本地倉庫的分支;
      “refs/remotes/”下是遠端倉庫以及對應的分支;
      “refs/tags/”描述了在commit上打上的本地倉庫的標簽。

      相對引用(符號‘~’與符號‘^’)

      可以使用相對引用來指定某個commit,相對引用的使用涉及到兩個符號^,兩個符號的意義如下:
      ~在第一父級上追蹤,可用多個~表示向前追蹤的級數,也可在~后接數字表示向前追蹤的級數;
      ^在父級上追蹤,通過在^后綴數字1或2可以指定追蹤的父級是第一父級還是第二父級,可省略后綴數字,表示默認追蹤第一父級,可用多個^表示向前追蹤的級數。

      第一父級是執行合并命令時所在的分支;
      第二父級是執行合并命令時被合并的分支;
      ~^可以在同一個表達式里配合使用。

      示例:
      以下分支圖展示了在master分支上通過git marge hotfix命令將hotfix分支合并到master分支之上的情況,通過~^可以引用到不同分支的commit。

      graph LR subgraph First[master分支] M1((master<br/>1<br/>HEAD ^1^1^1^1^1<br/>HEAD &#126 5)) --> M2 M2((master<br/>2<br/>HEAD ^1^1^1^1<br/>HEAD &#126 4<br/>head &#126 1^2 &#126 2)) --> M5 M5((master<br/>5<br/>HEAD ^1^1^1<br/>HEAD &#126 3)) --> M6 M6((master<br/>6<br/>HEAD ^1^1<br/>HEAD &#126 2)) --> M7 M7((master<br/>7<br/>HEAD ^1<br/>HEAD &#126 1)) --> M8 M8((master<br/>8<br/>HEAD<br/>HEAD &#126 0)) end subgraph Second[hotfix分支] M3((hotfix<br/>3<br/>head ^1^2^1<br/>head &#126 1^2 &#126 1)) --> M4 M4((hotfix<br/>4<br/>head ^1^2<br/>或 head &#126 1^2)) M2 --> M3 M4 --> M7 end
      • 對于commit節點8來說,它是當前的HEAD節點,而且它只有一個父級,即節點7,同時也是它的第一父級,所以節點7可以表示成HEAD~1或者HEAD^1(也可省略數字1表示為HEAD~HEAD^);
      • 對于commit節點7來說,它是一個合并節點,它的第一父級是節點6(因為是從hotfix向master合并),第二父級是節點4,所以在節點7引用的基礎上,以下形式都可以是節點6的表示方式:HEAD~1~1、HEAD~1^1、HEAD^1~1、HEAD^1^1HEAD~~HEAD^^、HEAD~^、HEAD^~、HEAD~2
      • 其他commit節點以此類推……

      具體引用(refspec)

      Git通過“具體引用”來表示本地倉庫分支到遠程倉庫分支的映射,refspec本質上是一種格式。

      refspec被表示為[+]<src>:<dst>的形式,<src>表示本地倉庫的源分支,dst表示遠程倉庫的目標分支,可選的+表示是否執行non-fast-forward(一種快速合并方式);
      refspec可用在對遠端的推送、刪除等操作上。

      1.3 Git目錄下的文件

      ".git/"——根目錄
      ".git/hooks/"——存放一些shell腳本
      ".git/info/exclude"——倉庫的一些注釋信息
      ".git/logs/"——存放所有更新的引用記錄
      ".git/objects/"——存放所有的Git對象,對象的SHA1哈希值的前兩位是文件夾名稱,后38位作為對象文件名。
      ".git/refs/"——存放了所有引用內容
      ".git/refs/heads/"——本地引用
      ".git/refs/remotes/"——遠端引用
      ".git/refs/tags/"——標簽引用
      ".git/CHERRY_PICK_HEAD"——使用cherry-pick命令會更新此commit
      ".git/COMMIT_EDITMSG"——最新一次commit所附帶的描述
      ".git/config"——倉庫的配置信息
      ".git/description"——倉庫的描述信息
      ".git/FETCH_HEAD"——使用fetch命令后會更新此commit,用于組合操作中的引用暫存,例如pull會先fetch再merge
      ".git/HEAD"——當前檢出的commit
      ".git/index"——暫存區(二進制文件)
      ".git/MERGE_HEAD"——使用merge命令會更新此commit,對應合并進當前分支的commit
      ".git/ORIG_HEAD"——指向操作前的Head,用于某些命令的回退
      ".git/packed-refs"——存放git運行垃圾回收機制后的一些引用,用于提高性能,垃圾回收不影響正常的Git功能,refs/文件夾下的一些內容有可能會被壓縮到該文件內
      ".git/REBASE_HEAD"——使用rebase命令會更新此commit

      要更改主分支的位置就是修改refs/heads/master指向的內容。同樣地,創建一個新的分支就是把commit哈希寫入新文件這樣簡單。這也是為何Gi相比SVN是更加輕量的重要原因。

      2 操作

      2.1 基本快照操作

      狀態查看(status)

      常用形式:

      // 用得最多的一個命令了
      git status
      

      暫存改動內容(add)

      常用形式:

      // 將“工作樹”所有改動添加至“暫存區”
      git add .
      

      附加參數:

      // 干跑,演示執行效果,并不實際運行(這個參數在很多命令里都可以附帶,很有用)
      --dry-run | -n
      
      // 只跟蹤tracked狀態的文件,無視新增的文件
      --update | -u
      

      擴展:

      // 針對所有改動
      git add .
      git add *
      
      // 針對某個文件
      git add myFile.cs
      
      // 針對多個文件(用空格間隔)
      git add myFile.cs myFile2.cs
      
      // 針對某個文件夾(遞歸)
      git add myFolder/
      
      // 針對某類型文件
      git add *.cs
      

      提交改動內容(commit)

      常用形式:

      // 將“暫存區”所有改動提交至“當前分支”
      git commit -m <msg>
      

      配置了git的默認編輯器之后,不帶-m可自動打開編輯器處理描述文字

      附加參數:

      // 先自動執行add操作,再commit
      --all | -a
      
      // 修改上一次的commit,會重新生成一個commitId(可以只修改message,也可以附帶add到暫存區的改動)
      --amend
      
      // 演示執行效果
      --dry-run
      
      // 添加描述文字
      --message=<msg> | -m <msg>
      
      // 修改指定的commit內容,會生成一個以“fixup!”開頭的描述文字的commit提交
      // fixup功能需要配合附帶--autosquash參數的rebase命令執行
      --fixup=<commit-id>
      
      // 修改指定的commit內容和描述文字,會生成一個以“fixup!”開頭的描述文字的commit提交
      --fixup=amend:<commit-id>
      
      // 修改指定的commit描述文字,會生成一個以“fixup!”開頭的描述文字的commit提交
      --fixup=reword:<commit-id>
      

      查看提交歷史(log)

      常用形式:

      // 顯示所有提交的歷史記錄
      git log
      

      附加參數:

      // 將信息壓縮在一行顯示
      --oneline
      
      // 以分支圖的形式顯示歷史信息
      --graph
      
      // 限制顯示的歷史記錄數目
      --max-count=<number> | -n <number> | -<number>
      
      // 使用作者來過濾顯示的歷史記錄
      --author=<pattern> | --committer=<pattern>
      
      

      刪除文件(rm)

      常用形式:

      // 刪除文件,并記錄這次的刪除操作(刪除操作會記入暫存區,用于commit的時候對分支中的文件進行處理)
      git rm myFile.cs
      

      附加參數:

      // 強制刪除,如果文件被改動過(不管是否add到暫存區),使用普通刪除都會報錯,需要使用強制刪除
      --force | -f
      
      // 刪除暫存區文件,但保留工作區文件
      --cached
      

      比較文件(diff)

      常用形式:(這個功能其實用得不多,因為在VisualStudio或VSCode等IDE環境中在合并的時候有更完善的diff功能)

      // 對比文件。當工作樹有改動,暫存區為空,對比工作樹與最后一次commit的共同文件差異;當工作樹與暫存區都有改動,對比的是工作樹與暫存區的共同文件差異
      git diff
      

      附加參數:

      // 對比暫存區與最后一次commit間的差異文件
      --cached | --staged
      

      還原文件(restore)

      可以從“暫存區”向“工作樹”還原;
      也可以從“當前分支”向“暫存區”還原;
      也可以從“當前分支”向“工作樹”還原

      常用形式:(restore命令只修改工作樹和暫存區,不會進行提交)

      // 還原工作樹文件,即撤銷更改
      git restore myFile.cs
      

      附加參數:

      // 還原工作樹文件(這也是默認參數),優先以暫存區為源,如果暫存區沒有,則以Head為源
      --worktree | -W
      
      // 還原暫存區文件
      --staged | -S
      
      // 指定被還原文件的來源,默認使用Head
      --source=<tree> | -s <tree>
      

      擴展:

      // 針對當前目錄下的所有內容
      git restore .
      
      // 針對頂層目錄下的所有內容
      git restore :/
      
      // 針對某個文件
      git restore myFile.cs
      
      // 針對某類文件
      git restore '*.cs'
      

      版本回退(reset)

      常用形式:(該命令通過移動本地Head指針至指定的提交上,以此進行回退)

      // 默認還原工作樹文件(使用相對引用,也可直接使用commit-id)
      git reset --hard HEAD^
      

      附加參數:

      // 重置工作樹和暫存區的改動
      --hard
      
      // 保留工作樹的改動,重置暫存區的改動(默認)
      --mixed
      
      // 保留工作樹和暫存區的改動
      --soft
      

      版本回滾(revert)

      常用形式:(該命令不會更改之前的提交,而是進行新的提交,以此還原其它提交所做的變動,常用于已經push到遠端的提交進行功能回撤)

      // 回滾某個指定的commit,會自動進行新的提交,生成新的commit-id
      git revert <commit-id>
      

      附加參數:

      // 回滾的改動不自動進行提交,而是放入暫存區
      --no-commit | -n
      
      // 回滾范圍內所有的commit,并按照順序依次生成多個新的提交
      // 范圍:從<old commit-id>(不包含)到<new commit-id>(包含)
      // 新提交的順序:先生成<new commit-id>,最后生成<old commit-id>(并不包含)
      // 想要只生成單個commit,可以使用-n參數,再手動提交一次即可
      git revert <old commit-id>..<new commit-id>
      
      // 針對merge合并的分支進行回滾,相當于拋棄某個分支內的所有修改,并生成新的提交
      // <parent-number>是1或者2,表示需要保留的分支
      // 可以用show命令查看合并點的信息,在顯示的“Merge行”可以看到commit順序,從左到右分別為1、2
      --mainline | -m <parent-number> <合并點的commit-id>
      
      // 繼續回滾操作(回滾過程中,如果有沖突,會產生暫停,需要解決完沖突)
      --continue
      
      // 跳過當前commit,繼續余下的回滾操作(回滾過程中)
      --skip
      
      // 放棄回滾操作,回到操作前的狀態(回滾過程中)
      --abort
      
      // 退出回滾操作,保持當前狀態,不回到操作前的狀態(回滾過程中)
      --quit
      

      這里要提一下在合并的分支上進行回滾操作的一些注意事項

      ??假設當前的情況是在feature分支(臨時功能分支)上開發了一個新功能,并合并到了dev分支(主要開發分支)上,之后又在dev分支上提交了幾個commit,在某一天突然發現該新功能存在Bug,需要revert掉,于是執行git revert -m 1 xxxx生成了回滾commit提交W,如下:

      graph LR subgraph dev[dev] 1[o] --> 2[o] --> 3[o] --> M[M] --> 4[x] --> 5[x] --> W[W] end subgraph feature[feature] 1 --> A A[A] --> B[B] --> M end

      回到feature分支后,進行了兩次提交C和D之后,修復了新功能中的Bug,之后又向dev分支合并,如下:

      graph LR subgraph dev[dev] 1[o] --> 2[o] --> 3[o] --> M[M] --> 4[x] --> 5[x] --> W[W] --> 6[x] end subgraph feature[feature] 1 --> A A[A] --> B[B] --> M B --> C --> D --> 6 end

      此時會出現一個問題,就是A提交和B提交中的改動不會被合并到dev分支中,因為它們已經在W提交中被回滾了。
      ??此時想要把A提交和B提交的改動一起合并到dev分支,則需要在合并前在dev分支上再做一些操作,把回滾M提交而生成的W提交再做一次回滾,如下:(M'是回滾W而生成的提交)

      graph LR subgraph dev[dev] 1[o] --> 2[o] --> 3[o] --> M[M] --> 4[x] --> 5[x] --> W[W] --> M'[M'] --> 6[x] end subgraph feature[feature] 1 --> A A[A] --> B[B] --> M B --> C --> D --> 6 end

      這樣之前的A提交和B提交的改動就能正確地合并進dev分支了。參考revert-a-faulty-merge[5]

      查看操作記錄(reflog)

      常用形式:

      // 查看之前的改動記錄,可以得到檢索列表,在其它命令中可使用檢索到的commit-id進行操作,也可以使用改動記錄標識`HEAD@{n}`作為commit-id進行操作
      git reflog
      

      在Git的相關圖形界面上對分支進行的操作也同樣能在reflog命令里被查找到。

      揀選(cherry-pick)

      常用形式:(該命令用于將一個分支上的某些commit改動應用到目標分支上,而不必將整個分支的改動合并到目標分支)

      // 揀選特定的commit到當前分支,會產生新的commit提交
      git cherry-pick <commit-id>
      

      附加參數:

      // 將改動放入工作區,不產生新的提交
      --no-commit | -n
      
      // 針對merge合并的節點也可以揀選,但需要指定揀選的改動來自哪個父級的代碼變動
      // <parent-number>是1或者2,表示需要保留的分支
      // 可以用show命令查看合并點的信息,在顯示的“Merge行”可以看到commit順序,從左到右分別為1、2
      --mainline | -m <parent-number> <合并點的commit-id>
      
      // 繼續揀選操作(揀選過程中,如果有沖突,會產生暫停,需要解決完沖突)
      --continue
      
      // 跳過當前commit,繼續余下的揀選操作(揀選過程中)
      --skip
      
      // 放棄揀選操作,回到操作前的狀態(揀選過程中)
      --abort
      
      // 退出揀選操作,保持當前狀態,不回到操作前的狀態(揀選過程中)
      --quit
      

      擴展:

      // 打開外部編輯器,編輯描述
      --edit | -e
      
      // 揀選多個commit到當前分支
      git cherry-pick <commit-id1> <commit-id2>
      
      // 揀選多個連續的commit到當前分支,不包含`commit-id1`,如果需要包含,可用`<commit-id1>^`
      git cherry-pick <commit-id1>..<commit-idn>
      

      衍合(rebase)

      常用形式:(以某個commit為基點,重構之后的commit(一般針對分叉的情況),在分支圖上形成一條直線,強迫癥患者之友)

      // 以指定的上游分支與當前分支的分叉點為基,進行重構,當前分支的所有改動會鏈接在上游分支的最后一個commit之后
      git rebase <Branch>
      

      附加參數:

      // 在衍合操作時使用交互模式,可以在編輯器內手動對每個commit指定相應的操作(pick、drop、squash等)來完成整個衍合
      --interactive | -i
      
      // 自動按照需要的方式完成衍合操作,一般需要之前的commit中附帶了--fixup、--squash、--amend等待定操作來指示自動衍合的行為,即commit中會出現以“fixup!”或“amend!”或"squash!"為開頭的描述文字
      --autosquash
      
      // 將當前分支在新的基點處進行衍合
      --onto <NewBase>
      
      // 繼續衍合操作(衍合過程中,如果有沖突,會產生暫停,需要解決完沖突)
      --continue
      
      // 跳過當前commit,繼續余下的衍合操作(衍合過程中)
      --skip
      
      // 放棄衍合操作,回到操作前的狀態(衍合過程中)
      --abort
      
      // 退出衍合操作,保持當前狀態,不回到操作前的狀態(衍合過程中)
      --quit
      

      關于rebase的理解

      ??其實rebase的本質就是把當前產生變化的commit在需要的地方重新執行一遍,以相同的信息重構基點之后的commit,重構會導致大部分commit-id的變化,以master為基進行衍合不會修改master,這意味著你的子分支的commit將在master的最后一個commit之后執行,即變成一條直線。

      ??假設當前的情況是在feature分支(功能分支)上開發了新功能,并合并到了dev分支(主要開發分支)上,如果我們在dev分支上使用git merge feature進行合并(merge是合并指定分支到當前分支的操作),會產生如下分支圖:

      graph LR subgraph dev[dev] 1[commit 1] --> 2[commit 2] --> 4[commit 4] --> 7[commit 7: Merge Branch 'feature'] end subgraph feature[feature] 2 --> 3 3[commit 3]--> 5[commit 5] --> 6[commit 6] --> 7 end

      merge可以正常地工作,但這只是一個分支的合并,試想在一個分支眾多、存在交叉提交的環境下,分支圖會像沒有整理好的電纜線箱一樣,錯綜復雜,很快失去可讀性。但是如果使用rebase的方式來處理,在feature分支中使用git rebase dev,會產生如下分支圖:

      graph LR subgraph dev[dev] 1[commit 1] --> 2[commit 2] --> 4[commit 4] -.- x((dev分支頭)) end subgraph feature[feature] 4 --> 3 3[commit 3]--> 5[commit 5] --> 6[commit 6] -.- y((feature分支頭)) end

      分支圖里沒有分叉,featrue分支的所有commit以dev分支頭(commit 4)為基點,進行了重構,這期間feature分支上的所有commit對應的commit-id都會重新生成,目前分支的合并還未完成,還需要切換到dev分支,在dev分支上使用git merge feature,此時的合并會自動使用fast-forward快進合并(直接移動dev的分支頭指針到feature的分支頭指針位置)來完成合并,分支圖最終形成一條直線,如下:

      graph LR 1[commit 1] --> 2[commit 2] --> 4[commit 4] 4 --> 3 x((dev分支頭)) -.- 6 3[commit 3]--> 5[commit 5] --> 6[commit 6] y((feature分支頭)) -.- 6

      2.2 分支與合并操作

      2.2.1 遠端操作(remote)

      添加遠端倉庫關聯

      常用形式:

      // 添加遠端倉庫,Remote一般約定為origin,也可以自己起名,RemoteURL有以下兩種形式
      // ssh協議形式:git@github.com:myName/myProject.git
      // http協議形式:https://github.com/myName/myProject.git
      git remote add <Remote> <RemoteURL>
      
      顯示遠端倉庫列表信息

      常用形式:

      // 顯示所有遠端倉庫的信息
      git remote -v
      
      修改遠端倉庫名

      常用形式:

      // 修改遠端倉庫名在本地的簡稱
      git remote rename <OldRemote> <NewRemote>
      
      移除遠端倉庫

      常用形式:

      // 移除簡稱對應的遠端倉庫
      git remote rm <Remote>
      

      2.2.2 分支操作(branch/switch/checkout)

      ??因為git版本的不斷發展,在新關鍵字的加入的同時為了兼容老版本,同一個操作會有不同的命令能夠完成。

      查看分支

      常用形式:

      // 查看所有分支
      git branch -a
      

      附加參數:

      // 查看遠端分支
      --remotes | -r
      // 查看本地分支對應的遠程分支
      -vv
      
      創建分支

      常用形式:

      // 從當前Head創建本地分支
      git branch <New-Branch>
      
      // 從當前Head創建本地分支,并切換到新分支
      git checkout -b <New-Branch>
      git switch -c <New-Branch>
      
      // 從遠程分支創建本地分支
      git branch --track <New-Branch> <Remote>/<RemoteBranch>
      git checkout -b <New-Branch> <Remote>/<RemoteBranch>
      git switch -c <New-Branch> <Remote>/<RemoteBranch>
      

      附加參數:

      // 創建分支
      (git checkout) -b
      (git switch) --create | -c
      // 強制創建分支,分支名被占用的情況下會覆蓋舊分支
      (git branch) --force | -f
      (git checkout) -B
      (git switch)--force-create | -C
      // 從遠程分支創建本地分支的同時附帶追蹤關系
      (git branch)(git checkout)(git switch) --track | -t
      // 從遠程分支創建本地分支的同時不附帶追蹤關系
      (git branch)(git checkout)(git switch) --no-track
      

      擴展:

      // 從某個commit或者tag創建分支
      git branch <New-Branch> <commit-id>
      
      切換分支

      常用形式:

      git checkout <Branch>
      git switch <Branch>
      
      刪除分支

      常用形式:

      // 刪除本地分支,刪除分支時不能停留在當前分支上,否則會報錯
      git branch -d <Branch>
      
      // 刪除遠端分支
      git push -delete origin <RemoteBranch>
      

      附加參數:

      // 創建分支
      (git checkout) -b
      (git switch) --create | -c
      // 強制創建分支,分支名被占用的情況下會進行覆蓋
      (git branch) --force | -f
      (git checkout) -B
      (git switch)--force-create | -C
      
      移動(重命名)分支

      常用形式:

      // 移動分支會附帶分支上的配置和操作記錄(reflog)
      git branch -m <Old-Branch> <New-Branch>
      

      附加參數:

      // 強制移動分支,分支名被占用的情況下會進行覆蓋
      -M
      
      復制分支
      // 復制分支會附帶舊分支上的配置和操作記錄(reflog)到新分支
      git branch -c <Old-Branch> <New-Branch>
      

      附加參數:

      // 強制復制分支,分支名被占用的情況下會進行覆蓋
      -C
      
      合并分支(merge)
      // 合并指定分支到當前分支
      git merge <Branch>
      

      附加參數:

      // 附帶描述文字
      -m <msg>
      
      // 是否執行fast-forward快進合并
      --ff
      --no-ff
      --ff-only
      
      // 合并時執行squash擠壓操作,并將結果暫停commit提交,執行完成需要手動提交。squash會在合并時將指定分支的所有commit放入一個新生成的commit之中,新commit的作者為當前的操作者,指定分支上的歷史提交記錄將不會轉移到合并分支,意味著歷史提交記錄的丟失
      --squash
      
      // 繼續合并操作(合并過程中,如果有沖突,會產生暫停,需要解決完沖突)
      --continue
      
      // 放棄合并操作,回到操作前的狀態(合并過程中)
      --abort
      
      // 退出合并操作,保持當前狀態,不回到操作前的狀態(合并過程中)
      --quit
      
      建立本地和遠端的追蹤關系

      常用形式:

      // 建立分支與遠端分支的追蹤關系
      git branch -u <Remote>/<RemoteBranch> <Branch>
      

      附加參數:

      // 創建追蹤關系,未指定<Branch>則默認當前分支
      --set-upstream-to | -u
      // 解除追蹤關系,未指定<Branch>則默認當前分支
      --unset-upstream
      
      拉取遠端分支的改動到本地分支(pull)

      常用形式:

      // 從建立追蹤關系的遠端分支拉取改動到本地分支,如果當前分支只有一個追蹤分支,則本地分支名<dst>可?。蝗绻斍胺种е慌c一個主機存在追蹤關系,則遠端主機名<repository>可省
      git pull <repository> <src>:<dst>
      

      <src>:<dst>是具體引用<refspec>,完整形式是[+]<src>:<dst>,可以寫成<RemoteBranch>:<Branch>,遠端->本地,與push的方向相反。
      關于無參數的git pull行為,可以參考Git push與pull的默認行為[6]

      附加參數:

      // 是否執行fast-forward快進合并
      --ff
      --no-ff
      --ff-only
      
      // 以rebase的方式執行pull合并
      --rebase | -r
      
      推送本地分支的改動到遠端分支(push)

      常用形式:

      // 推送當前分支到建立追蹤關系的遠端分支,如果當前分支只有一個追蹤分支,則遠端分支名<dst>可?。蝗绻斍胺种е慌c一個主機存在追蹤關系,則遠端主機名<repository>可省
      git push <repository> <src>:<dst>
      

      <src>:<dst>是具體引用<refspec>,完整形式是[+]<src>:<dst>,可以寫成<Branch>:<RemoteBranch>,本地->遠端。
      關于無參數的git push行為,可以參考Git push與pull的默認行為[6:1]

      附加參數:

      // 強制推送,使用本地分支覆蓋遠端分支
      --force | -f
      
      // 推送所有標簽到遠端
      --tags
      

      擴展:

      // 直接推送(假設遠端主機名origin,遠端同名分支dev)
      git push origin dev:refs/heads/dev
      
      // 如果遠端開始了code review,使用上面的push會產生“remote rejected”錯誤,需要使用`refs/for/`的形式
      git push origin dev:refs/for/dev
      
      // 推送單個標簽,第二行是完整形式
      git push origin <tagname>
      git push origin refs/tags/tagname:refs/tags/tagname
      
      // 刪除遠程標簽,推送空標簽到遠端相當于刪除標簽
      git push origin :refs/tags/tagname
      git push origin --delete <tagname>
      
      儲藏當前工作狀態(stash)

      常用形式:

      // 儲藏當前工作樹和暫存區的改動到儲藏棧
      git stash -m <msg>
      

      附加參數:

      // 查看儲藏棧內的內容
      git stash list
      // 顯示某個儲藏的詳細內容
      git stash show [<stash>]
      // 帶push允許指定具體的文件
      git stash push <myFile1> <myFile2>
      // 從儲藏棧內彈出儲藏的場景,恢復至工作樹,不帶儲藏記錄標識[<stash>]的話,默認指定為儲藏棧頂元素
      git stash pop [<stash>]
      // 應用儲藏的場景,恢復至工作樹,但不從儲藏棧內彈出
      git stash apply [<stash>]
      // pop和apply命令中使用,用于將儲藏的內容按照原有的形式分別放回工作樹和暫存區,默認情況下儲藏將全部放回工作樹
      --index
      // 從儲藏棧內丟棄某個儲藏,不帶儲藏記錄標識[<stash>]的話,默認指定為儲藏棧頂元素
      git stash drop [<stash>]
      // 清空儲藏棧
      git stash clear
      

      stash支持把當前工作區和暫存區保存起來然后在切換到其它分支上再pop或者apply出來

      打標簽(tag)

      常用形式:(標簽相當于一個指向對應commit的不可移動的指針,對某個commit進行標記)

      // 對指定的commit進行標簽標記
      git tag <tagname> <commit-id>
      

      附加參數:

      // 生成附注標簽,附注標簽會包含日期、作者、描述文字等相關信息,并且有自己的commit-id,附注標簽可以看作commit的別名,一般用于推送到遠端,而普通標簽一般只在本地使用
      --annotate | -a
      
      // 刪除指定標簽
      --delete | -d
      
      // 查看標簽列表
      --list | -l
      
      // 為附注標簽添加描述文字,普通標簽不能帶該參數
      --message=<msg> | -m <msg>
      

      擴展:

      // 查看遠程標簽
      git ls-remote --tags origin
      

      3 使用場景

      3.1 版本回退之后,又想要找回

      查看之前的改動記錄,得到檢索列表,可使用檢索到的commit-id進行操作,也可以使用改動記錄標識HEAD@{n}作為commit-id進行操作

      git reflog
      

      操作對應的commit-id或者改動標識

      git reset --hard HEAD@{5}
      

      3.1 遠程分支已刪除,但在本地分支查看遠端依然存在

      查看所有分支

      git branch -a
      

      查看遠端分支情況

      git remote show origin
      

      同步已刪除的遠程分支在本地的索引,支持--dry-run

      git remote prune origin
      

      3.2 需要修改遠程分支名稱,但不想丟失歷史操作記錄

      移動(相當于重命名)本地分支,帶配置信息和操作記錄(reflog)

      git branch -m <Old-Branch> <New-Branch>
      

      刪除遠端舊分支

      git push --delete origin <Old-RemoteBranch>
      

      推送修改后的本地分支

      git push origin <New-Branch>:<New-RemoteBranch>
      

      建立本地分支和新遠端分支的追蹤關系

      git branch --set-upsteam-to <Remote>/<New-RemoteBranch> <New-Branch>
      

      3.3 在功能分支上開發完成后,想要通過rebase衍合進主分支

      ??場景一:在某個分支上(例如dev分支)直接開發,拉取遠端分支(遠端dev分支)代碼的時候,在pull命令中附帶--rebase參數進行衍合。

      git pull --rebase origin dev:refs/heads/dev
      

      ??場景二:在某個功能分支上(例如feature)開發,開發完成后需要向主分支(dev分支)合并,此時需要先從遠端向本地更新dev分支,再對本地的feature分支進行以dev分支為基的衍合。

      切換到dev分支上:

      git switch dev
      

      更新遠端dev分支到本地dev分支(也使用衍合方式):

      git pull --rebase origin dev:refs/heads/dev
      

      切換回feature分支:

      git switch feature
      

      對feature分支以dev為基進行衍合:

      > `git rebase dev`
      

      再次切換到dev分支上:

      git switch dev
      

      將feature分支合并入dev分支(自動fast-forward):

      git merge feature
      

      3.4 修改某個歷史commit提交(協作倉庫慎用)

      ??突然覺得之前的某次提交不夠完美,需要重新修正一下,但是在那次提交之后又進行了很多次提交,需要這樣操作:

      查找需要修正的提交的commit-id:

      git log --oneline --graph
      

      在工作樹上進行修正并將改動放入暫存區:

      git add .
      

      進行fixup方式的提交,指定需要被修正的commit的commit-id,執行完成后本地會生成一個commit,它的描述文字會以“fixup!”開頭:

      git commit --fixup=<commit-id>
      

      進行對需要修正的commit的rebase衍合操作,此處指定的commit-id是作為基點的commit,所以不能是被修正的commit本身,而應該比它更早某個commit即可,這里我們用相對引用“^”符號來指定被修正的commit的父級:

      git rebase -i --autosquash <commit-id>^
      

      4 Git工作流規范(時間不夠,以后再完善這一部分……)

      GitFlow工作流

      待補充

      分支命名規范

      待補充

      commit描述文字格式規范

      待補充

      關于pull request 和 merge request

      它們其實是一個東西,都是合并請求,只是因為不同的git站點的方式不同

      細節待補充

      5 總結一些注意事項

      ??Git的本質是針對commit的管理,Git的上手難度不難,只使用基本功能也能正常地進行工作,但是一些高級的功能能夠更好地幫助維護者進行版本管理,需要在實踐中不斷熟練,以后有更深入的理解再來添加內容,下面列出一些使用時候的注意事項:

      Git對大小寫敏感

      雖然Git對大小寫敏感,但會在倉庫克隆或初始化時,根據當前系統來設置是否忽略大小寫,在Windows下會設置為忽略大小寫。

      少量多次進行commit提交

      將任務劃分成比較細的粒度,多次commit提交,在解決合并沖突的時候會更加輕松,cherry-pick等操作也會更加清晰。

      盡量少用checkout命令,防止誤操作

      對分支的操作不推薦使用checkout命令,使用switch、branch可以替代分支操作方面的功能,因為checkout除了可以操作分支,它還可以操作文件,可能會因為誤操作而修改工作區。

      切換分支時,保證當前分支的工作區和緩存區是干凈的

      如果當前分支工作樹和緩存區是干凈的(即你在上次commit之后再沒做任何改動,可用git status查看),切換到別的分支跳不會有影響。但是如果當前分支下有未完成的工作,切換到別的分支會把改動帶過去,可以stash后再切換。

      避免revert -m對合并點的回滾

      針對合并的commit節點進行revert回滾操作,不會在未來的分支有提示,如果未來需要把回滾的分支重新合并到主分支上,需要revert之前執行revert的那個commit節點(非合并節點),第一容易遺忘,第二還需要艱難地沿著分支樹尋找到執行revert的節點。(文中有詳細提到)

      慎用git push -f操作

      這個操作實際上只是把問題丟給了別人(即同在一個遠端倉庫提交代碼的小伙伴),而別人并不清楚你把毛線打了什么結,要解開這個結,花費的成本往往會成倍增長,還記得開頭提到的新聞嗎……

      使用rebase時要注意對base的選擇

      如果試圖通過以子分支(例如feature功能分支)為基來衍合主分支(master分支),就是在自找苦吃,除非你的倉庫只有你自己在使用,否則你會花費更多的時間去修復你的錯誤,或者git push -f把問題丟給別人……

      對squash功能要特別注意

      帶有squash參數的命令,可能會涉及到使用rebase來完成最后的操作,會導致重構,使得某些commit-id發生變化,在協作的倉庫中使用需要特別注意

      如果不完全明白某個操作的含義,不要隨便使用

      查看相關文檔,正確地使用命令和參數,可以先使用--dry-run(很多命令附帶這個參數)來演示執行一下,否則當你試圖操作,但是并不知道自己在做什么的時候,就是惡夢的開始,不正確的使用有可能會丟失大量工作,


      1. Sourcetree:https://www.sourcetreeapp.com ??

      2. git官方文檔:https://git-scm.com/docs ??

      3. Git教程-廖雪峰的官方網站:https://www.liaoxuefeng.com/wiki/896043488029600 ??

      4. Git中三大對象commit、tree和blob之間的關系:https://blog.csdn.net/yao_94/article/details/88648468 ??

      5. revert-a-faulty-merge:https://github.com/git/git/blob/master/Documentation/howto/revert-a-faulty-merge.txt ??

      6. Git push與pull的默認行為:https://segmentfault.com/a/1190000002783245 ?? ??

      posted @ 2021-08-12 00:51  seedoubleu  閱讀(113)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 99久久无码一区人妻a黑| 成人动漫综合网| 一区二区视频观看在线| 九九热爱视频精品视频| 国产中文字幕精品在线| 久久这里只精品国产2| 无码av永久免费专区麻豆| 亚洲欧美中文字幕5发布 | 亚洲一二三区精品美妇| 欧美激情一区二区| 欧美肥老太交视频免费| 天堂www在线中文| 97一期涩涩97片久久久久久久| 亚洲久悠悠色悠在线播放| 国产亚洲一区二区三不卡| 广德县| 色综合天天综合网国产人| 国产亚洲午夜高清国产拍精品| 日韩少妇人妻vs中文字幕| 国产性色的免费视频网站| 无码综合天天久久综合网| 18禁无遮挡啪啪无码网站| 精品国产成人a在线观看| 欧美日韩中文国产一区| 亚洲一区二区三区激情在线| 麻豆精品一区二区综合av| 久久无码中文字幕免费影院| 又大又粗又爽的少妇免费视频| 久久97人人超人人超碰超国产| 特黄 做受又硬又粗又大视频| 国产最新精品系列第三页| 亚洲a成人片在线观看| 国产精品免费重口又黄又粗| 丰满少妇内射一区| 日韩精品人妻中文字幕| 午夜激情福利在线免费看| 熟女一区| 亚洲av无码牛牛影视在线二区 | 精品国偷自产在线视频99| 亚洲精品香蕉一区二区| 亚洲欧美成人aⅴ在线|