2019獨角獸企業重金招聘Python工程師標準>>>
###Git克隆 Git使用git clone命令實現版本庫克隆,主要有如下3種用法:
1)git clone <repository> <direcctory>
將repository指向的版本庫創建一個克隆島directory目錄。目錄directory相當于克隆版本庫的工作區,文件都會從版本庫中檢出,版本庫位于工作區下的.git目錄中。
2個版本庫之間可以通過PULL和PUSH操作實現同步。但是對于這種git clone出來對等工作區模式,版本庫的同步只有一種可行的操作模式,就是備份庫執行git pull命令從源版本庫中拉回新的提交實現版本庫同步。git pull命令無需指定上游版本庫的地址,是因為在執行git clone后,克隆出來的版本庫中對源版本庫進行了注冊。備份庫中上游版本庫的注冊保存在git配置文件中。
2)git clone --bare <repository> <direcctory.git>
創建的版本庫不包含工作區,直接就是版本庫的目錄,這樣的版本庫稱為裸版本庫。一般約定成俗裸版本庫以.git為后綴。
這種模式的git clone可以支持原版本庫到備份版本庫的git push操作,因為備份版本庫沒有工作區。git配置文件中decore.bare的配置為true
裸版本庫也可以通過git init生成:
git init --bare 備份庫路徑pathB
git push 源版本庫路徑A master:master
3)git clone --mirror <repository> <direcctory.git>
和2一樣,另外克隆出來的裸版本對上游版本庫進行了注冊,這樣可以在裸版本庫中使用git fetch命令和上游版本庫進行持續同步。
###Git庫管理 ####打包 從遠程克隆一個庫到本地,發現refs目錄下沒有引用文件,原有的引用文件都被打爆到一個文本文件.git/packed-refs中。objects目錄下沒有對象文件,原有的對象文件都被打包到.pack結尾的打包文件和.idx結尾的索引文件并保存在.git/objects/pack目錄下。
克隆遠程版本庫時,使用了“智能”的通信協議,遠程Git服務器將對象打包后傳輸給本地,形成本地版本庫的對象庫中的一個包含所有對象的包及索引文件。
Git對于以SHA1哈希值作為目錄名和文件名保存的對象有一個術語:松散對象。松散對象打包后悔提高訪問效率,而且不同的對象可以通過增量存儲節省磁盤空間。
####臨時對象 暫存區操作有可能在對象庫中產生臨時對象,例如,文件反復修改、反復地向暫存區添加,或者添加到暫存區后不提交甚至直接撤銷,就會產生垃圾數據占用磁盤空間。
git fsck:查看版本庫中包含的沒有被任何引用關聯的松散對象
git fsck --no-reflogs:查看包括reflog記錄中的臨時對象
git prune:清理臨時對象
如果是使用重置命令引入的臨時對象用git prune就不能被清除,因為這些臨時對象還是可以通過reflog追蹤到的,還在使用著,所以不能被git prune刪除。要丟棄這些臨時對象,需要把reflog做過期操作,相當于把.git/logs下的文件清空:git reflog expire -all
####Git管家 git-gc 相比git prune更常用的命令是git gc,它對版本庫進行一系列的優化動作:
1)對分散在.git/refs下的文件進行打包,打包到文件.git/packed-refs中:git pack-refs --all --prune;
2)丟棄90天前的reflog記錄:git reflog expire --all;
3)對松散對象進行打包:git repack:凡是有引用關聯的對象都被打包,未被關聯的對象仍舊以送松散對象的形式保存;
4)清除未被關聯的對象。默認只清楚2周以前的未被關聯的對象。
5)其他清理:對合并沖突的歷史記錄進行過期操作。
git gc -- prune=<date> 中時間參數是傳遞給git prune --expire <date>實現對指定日期之前的未被關聯的松散對象進行清理。
git gc會在部分git命令下會自動執行,如git merge, git receice-pack, git rebase -i, git am 等。 共享式寫操作的git版本庫因為會push觸發自動gc,非獨立工作的本地庫要pull merge觸發自動gc。
git gc觸發的條件:松散對象只有草果一定數量才會只寫。在統計松散對象數量時,為降低在.git/objects目錄下搜索松散對象對系統造成的負擔,實際采取取樣搜索,即只對對象庫下的一個子目錄.git/objects/17進行文件搜索。在默認配置下,只有該目錄中對象數目草果27個才會觸發版本庫的整理。至于為什么只在對象庫中選擇一個子目錄進行松散對象搜索,這是因為SHA1哈希值是完全隨機的,文件有前2位哈希值組成的文件中差不多是平均分布的。gc.auto是觸發版本庫整理的全部松散對象樹的閾值。
###Git協議與工作協同 ####Git支持的協議 版本庫間數據交換需要使用協議,協議分2種:
1)智能協議:在使用智能協議時,會在會話的2個版本庫的各自一段打開相應的程序進行數據交換,在數據傳輸過程中會有清晰的進度顯示,而且因為是按需傳輸所以傳輸量更小速度更快。SSH、GIT、本地協議、特殊配置的HTTP是智能協議。
2)啞協議:使用啞協議時,遠程版本庫不會允許輔助襯線,完全靠客戶端去主動發現,需要訪問refs獲取引用列表,根據引用再去訪問objects下的對象文件,如果對象文件被打包了還要訪問packs以獲取打包文件列表,在讀取完整的打包文件獲取對象。整個過程效率非常低,沒有進度條。FTP、RSYNC、沒有特殊配置的HTTP是啞協議。
####強制非快進式推送 快進式推送faset-forwards:要推送的本地版本的提交時建立在遠程版本庫相應分支的現有提交基礎上的,即遠程版本庫相應分支的最新提交時本地版本庫最新提交的祖先提交。
git push -f:強制推送,推送的提交會覆蓋刷新版本庫中的版本。
####合并后推送 理性的工作協同要避免非快進式推送。一旦向服務器推送后,如果發現錯誤,不要使用會更改歷史的操作(變基、修補提交),而是采用不會改變歷史提交的反轉提交等操作。
如果在想服務器推送過程中,由于他人率先推送了新的提交導致遭遇到非快進式推送的警告,應該先執行git pull獲取服務器最新的提交并和本地提交進行合并,合并成功后再向服務器提交。
####禁止非快進式推送 1)配置receive.denyNonFastForwards設置為true可以禁止任何用戶進行非快進式推送操作。
2)通過鉤子腳本進行設置,可以僅對某些情況下的非快進式推送進行限制,而不是全部拒絕。
###沖突解決 實際上拉回操作git pull 由2步驟組成:獲取操作git fetch,合并操作git merge
git merge [選項...] <commit>...
合并操作的大多數情況,只須提供一個commit(提交ID或對應的引用:分支、tag等)作為參數。合并操作將commit對應的目錄樹和當前工作分支的目錄樹的內容進行合并,合并后的提交以當前分支的提交作為第一個父提交,以commit為第二個父提交。合并操作還支持多個commit代表的分支和當前分支進行合并,過程類似。 默認情況下合并后的結果會自動提交,但是如果提供--no-commit選項,則合并后的結果會放入暫存區,用戶可以對合并結果進行檢查、更改,然后手動提交。
沖突類型:成功的自動合并、邏輯沖突、真正的沖突、樹沖突。
####自動合并 1)修改不同的文件;
2)修改相同文件的不同區域; 3)一個修改文件名,一個修改文件內容;
####邏輯沖突 例子:一個用戶修改了一個文件的文件名,而另外的用戶在其他文件中引用舊的文件名,這樣的合并雖然能成功,但是包含著邏輯沖突。
####真正的沖突 執行git pull時所做的合并操作由于遇到沖突導致中斷。合并過程是通過.git目錄下的MERGE_HEAD(記錄合并的提交ID),MERGE_MSG(記錄合并失敗的信息),MERGE_MODE(標記合并狀態)。 并且版本庫庫暫存區會記錄沖突文件的多個不同版本。使用git ls-files查看。當合并沖突發生后,會用到0以上的暫存區編號,編號1暫存區用于保存沖突文件修改之前的副本,即沖突雙方共同的祖先版本,可以使用:1:xxx訪問;編號2暫存區用于保存當前沖突文件在當前分支中修改的副本,可以使用:2:xxx訪問;編號3暫存區用于保存當前沖突文件在合并版本(分支)中修改的副本,可以使用:3:xxx訪問。這3個副本實際上是提供沖突解決工具,用于實現三向文件合并的。
工作區的版本則可能同時包含了成功的合并和沖突的合并,其中沖突的合并會用特殊的標記7個小于號,7個等號,7個大于號進行標識。7個小于號和7個等號之間的內容是當前分支所更改的內容。7個等號和7個大于號之間的內容是所合并的版本更改的內容。
沖突解決的實質就是通過編輯操作,將沖突標識的沖突內容替換為合適的內容,并去掉沖突標識。編輯完畢后執行git add命令將文件添加到暫存區(標號0),然后載提交完成沖突解決。
當工作去處于合并沖突狀態,無法再執行提交操作。此時又2個選擇:放棄合并操作,或者對合并沖突進行沖突解決操作。放棄合并操作就是執行git reset將暫存區重置即可。而沖突解決有2種辦法:1)手工編輯操作;2)圖形化解決沖突工具git mergetool。
當沖突解決完畢后,會看到.git目錄下與合并相關的文件MERGE_HEAD、MERGE_MSG、MERGE_MODE文件會自動刪除,而且暫存區中的3個副本也會都清除了。
####樹沖突 如果一個用戶將某個文件改名,另外一個用戶將同樣的文件改為另外的名字,當這2個用戶的提交進行合并操作時,就發生樹沖突。
解決方法:git rm掉暫存區中當前分支的沖突文件和合并版本的沖突文件,然后git add工作區中修改好的文件,提交完成沖突解決。同樣也可以用git mergetool交互式解決
####合并策略
git merge [-s <strategy>] [-X <strategy-option>] <commit>...
-s:用于設定合并策略,-X用于為所選的合并策略提供附加的參數
1)resolve:該合并策略只能用于合并2個頭(當前分支和另外一個分支),使用三向合并策略
2)recursive:該合并策略只能用于合并2個頭(當前分支和另外一個分支),使用三向合并策略,是2個頭指針合并時的默認合并策略。當合并的頭指針擁有一個以上的祖先時,會針對多個公共祖先先創建一個合并的樹,并以此作為三向合并的參照。 附加選項:ours,thires,substree
3)octopus:主要用于多個主題分支合并,是>=3個以上的頭指針合并的默認策略
4)ours:合并任意數量的頭指針,合并總是使用自己的內容,丟棄其他分支的內容
5)substree:經過調整的recursive策略,當合并樹A和樹B時,如果B和A的一個子樹相同,B首先會調整已匹配A樹的結構,以避免2顆樹在同一級被進行合并。
####合并相關的配置 1)merge.conflictstyle:定義沖突文件中沖突的標記風格:merge或diff3
2)merge.tool:執行git mergetool進行解決時條用的圖形化工具:
3)merge.<tool>.path:
4)merge.<tool>.cmd:
5)merge.log:是否在合并提交的提交說明中包含合并提交的概要信息,默認false
###Git里程碑Tag 里程碑即Tag,是人為對提交進行的命名。
git tag:顯示當前版本庫的tag列表
git tag -n<num>:顯示tag時同時顯示num行的說明
git describe:將提交顯示成一個易記的名稱,這個易記的名稱來自于建立在該提交上的里程碑,若該提交沒有里程碑則使用該提交歷史版本上的里程碑并加上可理解的尋址信息。規則:
1)如果該提交恰好被打上一個tag,則顯示該tag;
2)若提交沒有對應的tag,則用<tag>-<num>-g<commit>的格式顯示。tag是最接近祖先提交的tag,num是該tag和提交之間的距離,commit是提交的精簡提交id;
3)若工作區對文件有修改,還可以通過后綴-dirty表示出來;
4)若提交本身沒有包含tag,可以通過傳遞--always參數顯示精簡提交ID
git name-rev:和git describe類似,會顯示提交id及其對應的一個引用。默認優先使用分支名,除非使用--tags參數。如果提交上沒有相對應的引用,則會使用最新提交上的引用名稱并加上向后回溯的符號~<num>
####輕量級tag git tag <tagename> <commit>:創建輕量級tag,無需輸入描述信息。忽略commit則默認在HEAD上創建tag。
創建tag后,會在版本庫的.git/refs/tags目錄下創建一個新文件。
1)這個文件的內容是一個40位的SHA1哈希值;
2)這個tag指向的對象類型是commit;
3)查看tag指向的提交,其內容是普通的提交信息。
4)輕量級tag的創建過程沒有記錄,因此無法知道是誰創建的tag,何時創建tag。
5)git describe命令默認不使用輕量級tag生成版本描述字符串。但使用--tags參數,可以將輕量級tag作為版本描述符。
####帶說明tag git tag -a <tagename> <commit> git tag -m <msg> <tagename> <commit> 在創建tag時提供一個關于該tag的說明。
創建帶說明的tag后,會在版本庫的.git/refs/tags目錄下創建一個新文件。 1)這個文件的內容是一個40位的SHA1哈希值;
2)這個tag指向的對象類型是tag;
3)tag對象的內容是:創建tag時的說明+對應的提交ID+創建tag的用戶+創建tag時間
####帶簽名的tag 帶簽名的tag和帶說明的tag本質上是一樣的,相比多了一個工作:為tag對象添加GnuPG簽名。創建tag時候使用參數-s或-u <key=id>即可創建一個帶簽名的tag
####刪除tag git tag -d <tagname>:刪除tag tag沒有類似reflog的變更記錄機制,一旦刪除不易恢復慎用。Git沒有提供對tag重命名的命令。如果需要修改,可以刪除舊tag然后再用新名稱創建tag。
####共享tag 創建的tag默認只能在本地版本庫中可見,不會因為對分支執行推送而將tag也推送到遠程版本庫。這樣的設計顯然更為合理,否則的話,每個用戶本地創建的tag都自動向上游推送,那么上游的tag將有那么雜亂,而且不同用戶創建的相同名稱的tag會互相覆蓋。
git push origin mytag:把名稱為mytag的tag共享到上游版本庫。
git push origin refs/tags/*:將本地建立的所有tag全部推送到遠程版本庫,可以使用通配符。
在執行執行git pull操作,能夠在獲取遠程共享版本庫的提交的同時,獲取新的tag。 只會獲取遠程分支所包含的新tag,不會將遠程版本庫的其他分支的tag獲取到本地。
如果本地已有同名的tag,默認是不會從上游同步tag,即使二兩tag的指向不同,需要顯示的執行拉回操作:git pull origin refs/tags/mytag2:refs/tags/mytag2
####刪除遠程版本庫的tag
git push <remote_url> :<tagname>
該命令的最后一個參數實際上是一個引用表達式,引用表達式格式為<ref>:<ref>,該推送命令使用的引用表達式冒號前的引用被省略,其含義是將一個空值推送到遠程版本庫對應的應用中,即刪除遠程版本庫中相關的引用。這個命令不但可以用于刪除tag,還有可以刪除分支。
git push origin :mytag2
###Git分支 ####代碼管理 1)發布分支Realease Branch:或Bugfix分支,在軟件新版本發布后經常使用此技術進行軟件維護,發布升級版本。
2)特性分支Feature Branch:或主題分支Topic Branch,采用分支將某個功能或模塊的開發與開發主線獨立出來。 以下幾種情況應該建立特性分支:1)試驗性、探索性的功能開發;2)功能復雜、開發周期長的模塊;3)會更改軟件體系架構,破壞軟件集成,或容易導致沖突、影響他人開發進度的模塊。
3)賣主分支Vendor Branch:在版本庫中創建一個專門和上游代碼進行同步的分支,一旦有上游代碼發布就檢入到賣主分支中。再在主線版本上合并賣主分支上的提交。
####分支命令 1)git branch:顯示本地分支列表;
2)git branch <branchname>:基于HEAD所指的提交創建名為branchname的分支;
3)git branch <branchname> <start-point>:基于提交start-point創建名為branchname的新分支;
4)git branch -d <branchname>:刪除分支,如果該分支還未合并到其他分支,則拒絕刪除;
5)git branch -D <branchname>:強制刪除分支;
6)git branch -m <oldbranch> <newbranch>:重命名分支,如果名稱已存在則失敗; 7)git branch -M <oldbranch> <newbranch>:強制重命名分支;
####開發常用命令 git checkout -b <new_branch> [<start_point>]:用于基于start_point創建分支,并切換到新分支上;
###遠程版本庫git remote ####遠程分支 git branch -r :查看遠程分支;
從遠程版本庫執行獲取操作時,不是把遠程版本庫的分支原封不動地復制到本地版本庫的分支中,而是復制到另外一個命名空間。如在克隆一個版本庫時,會將遠程分支都復制到目錄.git/refs/remotes/origin/下。這樣從不同的遠程版本庫執行獲取操作,因為通過明明空間的相互隔離,所以就避免了在本地的相互覆蓋。
那么克隆操作產生的遠程分支為什么都有一個名為"origin/"的前綴? 答案就在配置文件.git/config中。
6 [remote "origin"]
7 fetch= +refs/heads/*:refs/remotes/origin/*
8 url= file:///path/to/repos/hello-world.git
這個小節可以稱為[remote]小節,該小節以origin為名注冊了一個遠程版本庫。該版本庫的URL地址由第8行給出,會發現這個URL地址就是執行git clone命令時所使用的地址。第7行設置了執行git fetch origin操作時使用的默認引用表達式:+表示是牽制進行引用的替換,應用表達式使用了通配符,冒號前含有通配符的引用值得是遠程版本庫的所有分支,冒號后的引用含義是復制到本地的遠程分支目錄中。
遠程分支類似tag,如果檢出就會使得頭指針HEAD處于分離頭指針狀態。實際上除了以refs/heads為前綴的引用之外,如果檢出任何其他引用,都將使工作區處于分離頭指針狀態。如果對遠程分支進行修改需要創建新的本地分支。
git checkout -b hello-1.x origin/hello-1.x 執行上面命令后,會自動建立了本地分支和遠程分支的跟蹤,建立跟蹤的分支就具有以下特征: 1)檢查工作去狀態時,會顯示本地分支和被跟蹤遠程分支提交之間的狀態;
2)執行git pull時,會從遠程分支拉取最新提交并合并;
3)執行git push時,會把最新的提交推送到遠程版本庫的同名分支中;
但是如果基于本地分支創建另外一個本地分支則新建的分支沒有跟蹤功能。如果需要能夠使用跟蹤功能,則創建分支時增加--track參數即可。
####遠程版本庫 名為origin的遠程版本庫是在版本庫克隆時注冊的,那么如何注冊新的遠程版本庫? git remote add new-remote file:///path/to/repos/hello-user.git
以new-remote為名進行注冊,打開配置文件可以看到remote "new-remote"小節。
git remote:顯示已注冊的遠程版本庫 git fetch:從當前默認遠程版本庫origin獲取最新提交
git fetch new-remote:從new-remote遠程版本庫中獲取最新提交 git remote set-url new-remote file:///path/to/repos/hello-user2.git更改遠程版本庫的地址
git remote set-url --push new-remote /path/to/repos/hello-user2.git 每個遠程版本庫都顯示2個URL地址,分別用于執行git fetch和git push命令時用到的URL地址。
git remote rename new-remote user2:更改遠程版本庫的名稱
git remote update:獲取所有遠程版本庫的更新;
如果某個遠程版本庫不想再執行git remote update時獲取更新,可以通過參數關閉自動更新:git config remote.user2.skipDefaultUpdate true
####push和pull操作與遠程版本庫 當不帶任何參數執行git push命令時,實際的執行過程是:
1)如果為當前分支設置了<remote>,即由配置branch.<branchname>.remote給出了遠程版本庫代號,則不帶參數執行git push相當于執行了git push <remote>;
2)如果沒有為當前分支設置<remote>,則不帶參數執行git push相當于執行了git push origin;
3)要推送的遠程版本庫的URL地址由remote.<remote>.pushurl給出。如果沒有配置,則使用remote.<remote/>.url配置的URL地址;
4)如果為注冊的遠程版本庫設置了push參數,即通過remote.<remote>.push配置了一個引用表達式,則使用該應用表達式執行推送。
5)否則使用“:”作為引用表達式。該表達式的含義是同步分支推送,即對所有在遠程版本庫中有同名分支的本地分支進行推送
git push <remote> <new_branch>:用本地分支推送到遠程版本庫的方式在遠程版本庫中創建分支。但是本地不能執行git pull(不帶參數)獲取遠程版本庫中其他人的推送。這是因為沒有建立本地分支和遠程分支的跟蹤,沒有設置branch.<branchname>.remote的值和branch.<branchname>.merge的值。
git push命令的執行過程:
1)如果為當前分支設置了<remote>,即由配置branch.<branchname>.remote給出了遠程版本庫代號,則不帶參數執行git pull相當于執行了git pull <remote>;
2)如果沒有為當前分支設置<remote>,則不帶參數執行git pull相當于執行了git pull origin;
3)要獲取的遠程版本庫的URL地址由remote.<remote>.url給出。
4)如果為注冊的遠程版本庫設置了fetch參數,即通過remote.<remote>.fetch配置了一個引用表達式,則使用該應用表達式執行推獲取。
5)接下來要確定合并的分支。如果設定了branch.<branchname>.merge,則對其設定的分支執行合并,否則報錯推出。
在執行git pull操作的時候可以通過參數--rebase設置使用變基而非合并操作,將本地分支的改動變基到跟蹤分支上。為避免因為忘記使用--rebase可以設置配置git config branch.<branchname>.rebase true。 為本地版本庫設置參數branch.autosetuprebase為true時,基于遠程分支建立的本地追蹤分支會自動配置branch.<branchname>.rebase參數。
####tag和遠程版本庫 遠程版本庫中的tag同步到本地版本庫,會使用相同的名稱,而不像分支那樣有另外的命名空間,所以tag會很混亂。在push的時候不會把tag帶入其他版本庫,但是fetch的時候會把tag一起獲取,而且刪除分支的時候,分支上的tag不會被刪除。tag會越來越亂。 使用git fetch命令時加上--no-tags參數就不會把tag也獲取到。 使用git remote add 注冊版本庫的時候帶--no-tags不iba本地庫的tag引到遠程庫上。
###補丁文件交互 git format-patch 版本范圍列表:創建補丁,將提交批量轉為補丁文件;
git am 補丁文件:應用補丁;
###其他命令 git help -g: 展示幫助信息