Git 的原理與使用(上)中介紹了Git初識,Git的安裝與初始化以及工作區、暫存區、版本庫相關的概念與操作,本文接著上篇的內容,繼續深入介紹Git在的分支管理與遠程操作方面的應用。
目錄
五、分支管理
1.理解分支
2.創建分支 branch?
3.切換分支
4.合并分支
5.創建、切換、合并分支流程圖
6.刪除分支?
7.合并沖突
補充:查看分支合并的情況
8.分支管理策略
Fast Forward 模式(ff模式)
非Fast Forward模式(no-ff模式)
9.分支策略
10.bug分支
疑問解決
11.刪除臨時分支
12.分支小結
六、遠程操作
1.理解分布式版本控制系統
2.遠程倉庫
新建遠程倉庫
Issues
Pull Request
克隆遠程倉庫
HTTPS協議克隆
SSH協議克隆
向遠程倉庫推送 push
拉取遠程倉庫
3.配置Git
忽略特殊文件
給命令配置別名
**小結
**下篇內容
五、分支管理
1.理解分支
分支是Git的殺手級功能之一。
它就像是科幻電影里面的平行宇宙,當你正在電腦前努力學習C++的時候,也許另一個平行宇宙里的另一個你正在努力學習JAVA。這兩個平行宇宙互不干擾,而在某個時間點,它倆發生了合并——于是,你既精通了C++,又精通了JAVA!
在版本回退章節里我們已經知道,Git會把每次提交串成一條時間線,這條時間線就可以理解為是一個分支。截止到目前我們的Git倉庫里中只有一條時間線,這個分支叫主分支,即master分支(也叫main分支)。
然后再來理解一下HEAD。HEAD嚴格來說指向的不是“提交(commit)”,而是當前所在的分支,而分支才是指向“提交(commit)”的。比如當前我們所在的分支是master,那么HEAD指向的就是master,master指向的才是“提交”。如下圖所示:
每次執行commit操作,master分支都會向前移動一步以指向最新的“提交”。這樣,隨著你不斷commit,master分支的線也會越來越長。而HEAD則一直指向指向當前分支不變,即現在我們所在的master分支。
可以通過
git cat-file -p <commit ID>
命令來查看提交信息:
2.創建分支 branch?
如何查看當前本地倉庫中已有的所有分支?
在工作目錄下執行
git branch
命令,系統就能為我們打印出當前本地倉庫中有哪些分支:
hyb@139-159-150-152:~/gitcode$ git branch #查看當前本地所有分支
* master # 顯示結果
這里查詢到當前本地倉庫中只有一個master主分支。
在我們創建本地倉庫時,git會自動給我們創建出一個master主分支。master前面有一個? *? ,*master
?既表示master是當前的工作分支,也表示master分支正在被HEAD指針所指向。
關于HEAD:
HEAD不僅可以指向master主分支,也可以指向其它任意分支。
被HEAD指向的分支是當前正在工作的分支。由于之前我們的HEAD一直指向的是master分支,因此add操作、commit操作都是在master主分支上完成的。
為了演示多分支的情況,這里我們來創建第一個新的分支dev,對應的命令為:
git branch <分支名>
hyb@139-159-150-152:~/gitcode$ git branch dev #新建分支dev
hyb@139-159-150-152:~/gitcode$ git branchdev
* master
當我們創建新的分支后,Git 便新建了一個指針叫 dev。而?*HEAD
表示當前的 HEAD 仍然指向?master 分支,并沒有發生變化。
也就是說,單純的創建分支,是不會自動切換分支的。?
# 打印一下HEAD指針的內容,可見HEAD指向的還是master
hyb@139-159-150-152:~/gitcode$ cat .git/HEAD
ref: refs/heads/master
此時,cat一下dev和master的內容,會發現它們兩個指向的是同一個修改(即commit Id),這是因為dev分支是站在當前的版本去創建的,所以dev分支初始情況下也指向了最新的提交:
一張圖總結:
3.切換分支
我們要想在dev上進行操作,就必須把dev分支當作工作分支。那如何切換到dev分支下進行開發呢?使用
git checkout <分支名>
命令即可完成切換。示例如下:
執行 git checkout
dev切換分支后,HEAD就指向了dev,表示我們已經成功地切換到了dev上。隨后,我們在dev分支下修改ReadMe文件,在末尾新增了一行內容 aaa on dev branch,并進行了一次提交操作。
現在,dev分支的工作完成,我們切換回master分支:
hyb@139-159-150-152:~/gitcode$ git checkout master
Switched to branch 'master'
切換回master分支后再查看ReadMe文件內容,此時發現ReadMe文件中剛才新增的內容不見了:
而再切回dev查看,剛才新增的內容又有了:
為什么會出現這個現象呢?
我們來看看dev分支和master分支的指向,發現dev和master兩者此時指向的提交已經不一樣了:
hyb@139-159-150-152:~/gitcode$cat.git/refs/heads/dev
bdaf528ffbb8e05aee34d37685408f0e315e31a4 # dev和剛創建時相比已經發生了改變
hyb@139-159-150-152:~/gitcode$cat.git/refs/heads/master
5476bdeb12510f7cd72ac4766db7988925ebd302
進一步的,可以通過命令
git cat-file -p bdaf528ffbb8e05aee34d37685408f0e315e31a4
來查看此時dev所指向的提交的詳情。查詢到的詳情中,parent
關鍵字標識了當前commit的上一個commit是哪一個。可以看到,dev當前指向的上一個指向,正是剛創建dev時dev的指向。因為我們是在dev分支上提交的,所以dev會指向最新的提交;而master分支此刻的指向并沒有改變(正如兩個平行宇宙之間彼此獨立的)。
master的視角下,當然就看不到在dev下的提交了,因此在master和dev兩個分支下的ReadMe文件內容會有差別。
4.合并分支
為了在master主分支上能看到新的提交,就需要將dev分支合并到master分支。
使用
git merge dev
命令,示例如下:
git merge
命令用于合并指定分支到當前分支。合并后,master分支上就能看到dev分支提交的內容了。此時的狀態如圖如下所示:?
仍然可以用 cat .git/refs/heads/master
命令和 cat .git/refs/heads/dev
命令分別查看master和dev的指向,此時發現二者指向再次相同,dev中存儲的commitID也被同步給了master。
By the way,細心的朋友可能注意到,剛才
merge
操作后,結果其實有些特殊:
這里的 Fast-forward?代表“快進模式”,它是Git分支合并的一種方式。快進模式意味著合并的方式是直接把master指向dev的當前提交,所以合并速度非常快。當然,也不是每次合并都是Fast-forward,我們后面會講其他方式的合并。
5.創建、切換、合并分支流程圖
1、創建新的dev分支。
2、git checkout dev
:切換至dev分支。
3、在dev分支上commit。
4、切換回master分支,git merge dev
6.刪除分支?
合并完成后,dev分支對于我們來說就沒用了,那么dev分支就可以被刪除掉。刪除分支的命令為:
git branch -d <分支名>
注意,如果當前正處于dev分支下,是不能刪除dev分支本身的:
hyb@139-159-150-152:~/gitcode$ git branch
*devmaster
hyb@139-159-150-152:~/gitcode$ git branch -d dev
error:Cannot delete branch 'dev' checked out at'/home/hyb/gitcode'
要刪除當前分支,只能先切換到其他分支下,再執行刪除操作,如:
hyb@139-159-150-152:~/gitcode$ git checkout master
Switched to branch 'master'
hyb@139-159-150-152:~/gitcode$ git branch -d dev
Deleted branch dev(was bdaf528).
hyb@139-159-150-152:~/gitcode$ git branch
* master
此時的狀態如圖如下所示:
因為創建、合并和刪除分支非常快,所以Git鼓勵你使用分支完成某個任務,合并后再刪掉分支,這和直接在master分支上工作效果是一樣的,但過程更安全(“安全”正是使用分支的一個原因)。
7.合并沖突
在實際中,分支并不是想合并就一定能合并成功的,有時可能會遇到代碼沖突的問題。
為了演示這問題,我們創建一個新的分支 dev1 ,并切換至目標分支。
注意,可以使用
git checkout -b dev1
一步完成創建并切換的動作,示例如下:
git checkout -b dev1
和
git branch dev1
+ git checkout dev1
效果是相等的。
我們在dev1分支下修改ReadMe文件,將 aaa on dev branch 改為 bbb on dev branch,然后提交:
此時在dev1分支中,ReadMe文件最終修改并提交的結果為 bbb on dev branch。
切回master分支,然后在master分支下將ReadMe文件最終修改并提交為 ccc on dev branch:
現在master分支和dev1分支中都各自有了新的提交:
Git只能試圖把各自的修改合并起來,但這種合并可能會有沖突。
在master分支中執行 git merge dev1
,將dev1分支與master分支上提交的修改合并,結果如下:
發現ReadMe文件有沖突后,可以直接查看文件內容來查看沖突詳情。Git會用<<<<<<<,=======,>>>>>>>來標記出不同分支沖突的具體內容,如下所示:
此時我們要做的是手動調整發生沖突的代碼(將不要的內容手動刪除,把要的內容保留下來),并需要再次提交修正后的結果!!
(再次提交很重要,切勿忘記)
到這里沖突就解決完成,此時的狀態變成了:
補充:查看分支合并的情況
用帶參數的 git log
?命令可以看到分支的合并情況:
命令:git log --graph --abbrev-commit
上圖中,星號? *? 代表的就是之前的“提交(commit)”。
最后,不要忘記dev1分支使用完畢后就可以刪除了:git branch -d dev
8.分支管理策略
Fast Forward 模式(ff模式)
通常合并分支時,如果可以,Git 會采用?Fast forward 模式。
Fast forward 模式形成的合并結果:
在Fast forward模式下,當我們合并分支后查看分支歷史時,分支歷史的展示中會丟失部分分支信息,即看不出來最新的提交到底是merge進來的還是正常提交的。
非Fast Forward模式(no-ff模式)
我們知道,當發生合并沖突時,在解決沖突問題后還需要再進行一次新的commit,然后才能得到最終狀態:
這里就不是 Fast forward 模式了。
在非 Fast forward 模式中,從分支歷史上是可以看出分支信息的。例如我們現在已經刪除了在合并沖突部分創建的 dev1 分支,但依舊能看到 master 其實是由其他分支合并得到的:
如何在正常提交的時也選擇no-ff模式呢?
Git支持我們強制禁用fast forward,那么就會在 merge 時生成?個新的 commit 。這樣,從分?歷史中就可以看出分支信息。
在執行 git merge
時添加 --no-ff
選項,就表示不使用ff模式。--no-ff
選項表示的就是禁用 Fast forward 模式。禁用 Fast forward 模式后,在合并分支后會創建一個新的 commit ,所以要加上-m
參數,把描述(message)也寫進去:
由下面的圖可知,在no-ff模式下生成一個新的commit,最終master也會指向一個新的提交:
ff模式和no-ff模式最大的區別是,用
git log --graph --abbrev-commit
命令查看提交日志時,能否區別出git的master中的每個commit是merge進來的還是正常提交的。
(在企業實操中一般更建議使用no-ff模式。)
9.分支策略
在實際開發中,我們應該按照幾個基本原則進行分支管理:
-
首先,master分支應該是非常穩定的,也就是僅用來發布新版本,平時不能在上面干活。
-
干活都在dev分支上。(dev分支是不穩定的,到某個時候,比如1.0版本發布時,再把dev分支合并到master上,在master分支發布1.0版本)。
你和你的小伙伴們每個人都在dev分支上干活,每個人都有自己的分支,時不時地往dev分支上合并就可以了。
所以,團隊合作的分支看起來就像這樣:
10.bug分支
假設我們現在正在 dev2 分支上進行開發,開發到一半還沒提交,突然發現 master 分支(即線上環境的代碼)上有嚴重的 bug(如閃退之類的),需要馬上解決。
直接在master主分支上編輯代碼進行bug修復,這肯定是不可以的。
安全起見,必須遵守分支的策略,即在本地創建一個新的臨時分支來修復,修復后,經過測試團隊的測試后將穩定的代碼合并到master分支,然后將臨時分支刪除。
可現在dev2的代碼在工作區中開發了一半,還無法提交,而要修復master中的bug怎么辦?
dev2中的修改都在工作區中,dev2在工作區中的做的修改會影響在其余分支的工作區進行工作。此時就需要先對dev2工作區中的內容進行保存。Git 提供了
git stash
命令,可以將當前的工作區信息進行儲藏,被儲藏的內容可以在將來某個時間恢復出來:
執行完git stash
命令后,tree ./git
,可以查看到當前git目錄下多了一個stash目錄,dev2的修改就被存儲在這個stash目錄中:?
git stash
后用git status
查看工作區,工作區是干凈的(除非有沒有被 Git 管理的文件),因此可以放心地創建分支來修復bug:
注意,如果工作區還有沒被 git 管理起來的文件,則該文件不能被暫存起來:
儲藏dev2工作區之后,由于我們要基于master分支修復bug,所以需要切回分支,再新建臨時分支來修復bug,示例如下:
修復完成后,切換回master主分支,并將bug分支合并到master分支,最后刪除bug分支即可:
至此,針對master主分支上的bug修復工作(即:切回主分支,拉一個bug_fix新分支,在bug_fix上修復完bug后再合并到master這樣的一系列操作)已經做完了,我們還要繼續回到dev2分支進行一開始未完成的內容的開發。
切換回dev2分支:
在dev2分支下檢查 git status
會發現,工作區是干凈的:
hyb@bite:~/gitcode$ git status
On branch dev2
nothing to commit, working tree clean
可以用git stash list
查看stash存放哪些內容,使用
git stash pop
命令來恢復現場,恢復的同時會把stash中的內容刪了,示例如下:?
補充: 恢復現場除了
git stash pop,
也可以采?git stash apply
。但是,用git stash apply
恢復后,stash內容并不刪除,需要我們自己調?git stash drop
來刪除。可以多次進行git stash
,恢復的時候,先?git stash list
查看,然后恢復指定的stash,?命令git stash apply stash@{0}
即可。
再次查看stash中的內容,我們已經發現已經沒有現場可以恢復了:?
hyb@bite:~/gitcode$ git stash list
# 沒有內容顯示
恢復完工作區的代碼之后,我們便可以繼續在dev2完成開發,開發完成后便可以進行提交:
但修復bug的內容并沒有在 dev2 上顯示。
為什么dev2下的ReadMe文件中,內容還是abcde而不是abcdef呢?這是因為創建dev2的時候,是基于還未修復的master的,也就是還有bug的master的。
此時的狀態圖為:
最終目的是要讓 master 分支和 dev2 分支合并。正常情況下我們切回 master 分支,直接將dev2分支的內容合并到master中即可,但這樣其實是有一定風險的。
因為在master分支與dev2分支合并時可能會發生沖突,而代碼沖突需要我們手動解決(在 master 上解決)。我們無法保證對于沖突問題可以正確地一次性解決掉,因為在實際的項目中,代碼沖突不只一兩行那么簡單,有可能幾十上百行,甚至更多,解決的過程中難免手誤出錯,導致錯誤的代碼被合并到 master 上。此時的狀態為:
解決這個問題的一個好的建議是:先在自己的dev2分支上合并 master主分支,再讓 master 去合并dev2分支。這樣做的目的是,一旦有沖突可以在本地分支dev2上解決并進行測試,而不影響 master 。
此時的狀態為:
實操演示如下:
最后執行 git branch -d
,將已經完成使命的dev2分支和bug_fix分支合并即可。
疑問解決
對于上述分支策略下的一系列操作,有的朋友可能會有疑問:dev2從master中拉出來的時候,ReadMe文件內容是abcde;但是master后來又拉了bug_fix分支,并把內容改成了 abcdef。如果工作區是共享的話,在bug_fix分支更改為abcdef的時候為什么沒有影響到dev2分支呢?
原因:
abcdef已經提交了,屬于版本庫的內容,對于master來說,此時工作區是干凈(clean)的,無變動。工作區是干凈的,那么dev2分支的工作區也是干凈的。git是基于提交來管理文件的,提交之前工作區共享。提交之后,提交的內容就已經被隔離了。
也就是說,如果bug_fix分支改成abcdef之后,沒有進行add操作,那么bug_fix、master和dev2三個分支工作區的內容都會是abcdef;而如果bug_fix提交修改之后,工作區變成干凈的,其他的分支的工作區也會變回原本的樣子。
11.刪除臨時分支
軟件開發中,總有無窮無盡的新的功能要不斷添加進來。
添加一個新功能時,我們肯定不希望一些實驗性質的代碼把主分支搞亂了。所以,每添加一個新功能,最好新建一個分支,我們可以將其稱之為 feature 分支。在feature 分支上進行開發,開發完成后再合并,最后刪除該 feature 分支。
可是,如果我們今天正在某個 feature 分支上開發了一半,被產品經理突然叫停,說是要停止新功能的開發。雖然白干了,但是這個 feature 分支還是必須就地銷毀,留著無用了。
這時使用原來的 git branch -d
命令刪除分支的方法是不行的。
之前之所以有可以用git branch -d
刪除分支的情況,是因為當時已經把分支和master主分支merge過了。而如果當前分支沒有和master主分支merge過、且已在當前分支進行過一些提交的時,git是會在刪除時保護當前分支的(git認為只要分支被創建出來了且在上面有過提交,那么這個分支就是有用的,不能隨便刪除)。
使用
git branch -D
命令則可以強制刪除:
12.分支小結
分支在實際中有什么用呢?
假設你準備開發一個新功能,但是需要兩周才能完成,第一周你寫了50%的代碼,如果立刻提交,由于代碼還沒寫完,不完整的代碼庫會導致別人不能干活了。如果等代碼全部寫完再一次提交,又存在丟失每天進度的巨大風險。現在有了分支,就不用怕了。你創建了一個屬于你自己的分支,別人看不到,還繼續在原來的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到開發完畢后,再一次性合并到原來的分支上,這樣既安全,又不影響別人工作。
并且 Git 無論創建、切換和刪除分支,Git在1秒鐘之內就能完成!無論你的版本庫是1個文件還是1萬個文件。
六、遠程操作
1.理解分布式版本控制系統
我們目前所說的所有內容(工作區,暫存區,版本庫等等),都是在本地,也就是在你的筆記本或者計算機上。而我們的Git其實是分布式版本控制系統。什么意思呢?
可以簡單理解為,我們每個人的電腦上都是一個完整的版本庫,這樣你工作的時候,就不需要聯網了,因為版本庫就在你自己的電腦上。既然每個人電腦上都有一個完整的版本庫,那多個人如何協作呢?比方說你在自己電腦上改了文件A,你的同事也在他的電腦上改了文件A,這時,你們倆之間只需把各自的修改推送給對方,就可以互相看到對方的修改了。
分布式版本控制系統的安全性要高很多,因為每個人電腦里都有完整的版本庫,某一個人的電腦壞掉了不要緊,隨便從其他人那里復制一個就可以了。
在實際使用分布式版本控制系統的時候,其實很少在兩人之間的電腦上推送版本庫的修改,因為可能你們倆不在一個局域網內,兩臺電腦互相訪問不了。也可能今天你的同事病了,他的電腦壓根沒有開機。因此,分布式版本控制系統通常也有一臺充當“中央服務器”的電腦,但這個服務器的作用僅僅是用來方便“交換”大家的修改,沒有它大家也一樣干活,只是交換修改不方便而已。有了這個“中央服務器”的電腦,這樣就不怕本地出現什么故障了(比如運氣差,硬盤壞了,上面的所有東西全部丟失,包括git的所有內容)。
2.遠程倉庫
Git是分布式版本控制系統,同一個Git倉庫,可以分布到不同的機器上。怎么分布呢?最早,肯定只有一臺機器有一個原始版本庫,此后,別的機器可以“克隆”這個原始版本庫,而且每臺機器的版本庫其實都是一樣的,并沒有主次之分。
你肯定會想,至少需要兩臺機器才能玩遠程庫不是?但是我只有一臺電腦,怎么玩?
其實一臺電腦上也是可以克隆多個版本庫的,只要不在同一個目錄下。不過,現實生活中是不會有人這么傻的在一臺電腦上搞幾個遠程庫玩,因為一臺電腦上搞幾個遠程庫完全沒有意義,而且硬盤掛了會導致所有庫都掛掉,所以我也不告訴你在一臺電腦上怎么克隆多個倉庫。
實際情況往往是這樣,找一臺電腦充當服務器的角色,每天24小時開機,其他每個人都從這個“服務器”倉庫克隆一份到自己的電腦上,并且各自把各自的提交推送到服務器倉庫里,也從服務器倉庫中拉取別人的提交。
完全可以自己搭建一臺運行Git的服務器,不過現階段,為了學Git先搭個服務器絕對是小題大作。好在這個世界上有個叫GitHub的神奇的網站,從名字就可以看出,這個網站就是提供Git倉庫托管服務的,所以,只要注冊一個GitHub賬號,就可以免費獲得Git遠程倉庫。
這里貼一個博主本人的Github主頁:GitHub,里面分享了一些開源項目,歡迎來訪交流。
不過,Github是國外的網站,速度比較慢。而國內也有好用的開源平臺,即Gitee(碼云)。
這里采用碼云來托管代碼,我們從零開始來使用一下碼云遠程倉庫。
新建遠程倉庫
1、新建遠程項目倉庫:
2、填寫基本信息:
3、創建成功:
4、創建成功后,我們可以對遠程倉庫進行一個基本的設置:開源or私有
5、也可以在設置-倉庫成員管理中管理協作者:
6、從創建好的遠程倉庫中我們便能看到,之前在本地學習過的分支,也存在于遠程倉庫中并被管理起來了。剛創建的倉庫有且只有一個默認的master分支:
Issues
當把倉庫設置為開源后,所有的用戶都可以瀏覽這個倉庫的內容。如果瀏覽者發現了你倉庫中代碼的bug,該怎么和你聯系呢?
gitee和github都提供了Issues功能,這個功能是讓倉庫的瀏覽者和倉庫的成員進行交流的地方。
點擊「新建Issue」,就進入編輯Issue的頁面:
選擇完畢之后,點擊「創建」,在Issues版塊中就會顯示剛才提交的問題:
如果已經處理完這個bug,那么可以繼續進入問題詳情更改問題的狀態:
Pull Request
實際開發中,直接允許dev分支的內容合并到master分支上是非常不安全的,很容易影響master分支上代碼的穩定性。
因此,在有dev分支與master分支合并的需要時,應當由開發者提出一個dev分支的PR(即Pull Request,合并申請單)給倉庫的管理員,PR中需要包含dev分支的一些信息,如做了什么改動、為什么要合并等。只有倉庫管理員同意了,才能將dev中的代碼merge到master中去。
倉庫的PR信息在Pull Request版塊可以看:
在創建項目時,也可以選擇Pull Request的模板。
克隆遠程倉庫
克隆/下載遠端倉庫到本地,需要使用 git clone
命令,后面跟上我們的遠端倉庫的鏈接。
遠端倉庫的鏈接可以從倉庫中找到:選擇“克隆/下載”獲取遠程倉庫鏈接:
SSH協議和HTTPS協議是Git最常使用的兩種數據傳輸協議。
SSH協議使用了公鑰加密和公鑰登錄機制,體現了其實用性和安全性,使用此協議需要將我們的公鑰放上服務器,由Git服務器進行管理(Git服務器就由gitee平臺代替了,gitee平臺上有地方可以配置本地服務器的公鑰,等到使用ssh協議的時候再來配置)。
使用HTTPS方式時,沒有任何要求,可以直接克隆下來。
HTTPS協議克隆
在執行克隆 git clone
操作時,不能在本地倉庫(.git
)所在的目錄下執行,其他地方都可以執行:
origin是遠程倉庫默認的倉庫名,可以用 git remote
命令來查詢遠程倉庫信息:
上面顯示了可以抓取和推送的origin的地址。如果沒有push / fetch權限,就看不到相應的push / fetch的地址。fetch和push表示當前本地倉庫擁有對遠程倉庫的抓取權限和推送權限:
-
克隆遠程倉庫后,所有的操作是在本地來完成的,本地提交的修改如何推送到遠端呢?就要使用到push權限去push遠端倉庫的地址
-
fetch表示抓取,如果遠程倉庫中存在一些本地沒有的內容時,就需要去遠程倉庫獲取新的內容,這就要使用到fech權限。
有了這兩個權限,才能讓本地倉庫和遠程倉庫之間有一些交互的操作。
SSH協議克隆
SSH協議使用的是公鑰加密和公鑰登錄的機制。
如果要使用SSH協議來進行git倉庫克隆,必須要把自己本地服務器上的公鑰放到git服務器上來進行管理,才可以克隆成功。
可以在設置頁中查看公鑰的使用情況:
在沒有配置任何公鑰的情況下進行SSH克隆:
使用SSH方式克隆倉庫,由于我們沒有添加公鑰到遠端庫中,服務器拒絕了我們的clone鏈接。需要我們設置一下。
如何在本地服務器上查看公鑰的內容?
首先在用戶主目錄(即家目錄,cd ~)下,看看有沒有.ssh
目錄,如果有,再看看這個目錄下有沒有id_rsa
(私鑰,保存在自己的服務器上,不對外展示)和id_rsa.pub
(公鑰)這兩個文件。如果有公鑰,那直接把公鑰的內容復制到上面的頁面中即可。
如果已經有了,可直接跳到下一步。如果沒有,需要創建SSHKey。
在~
目錄下使用命令:
ssh-keygen -t rsa -C "<你在gitee上綁定的郵箱地址>"
gitee上綁定的個人郵箱地址在設置頁中查看:
此時命令就是:
ssh-keygen -t rsa -C "xxxxxxxxxx@qq.com"
注意輸入自己的郵箱,然后一路回車,都使用默認值即可:
此時就把我們的公鑰和私鑰都創建好了。可以在用戶主目錄里找到 .ssh 目錄,里面有 id_rsa
和 id_rsa.pub
兩個文件,這兩個就是SSH Key的秘鑰對, id_rsa
是私鑰,不能泄露出去;id_rsa.pub
是公鑰,可以放心地告訴任何人。
cat
一下公鑰,將其中的內容一字不差地復制粘貼到gitee的公鑰配置頁面即可。
然后添加自己的公鑰到遠端倉庫:
配置好后可見:
點擊確認后,需要對你進行認證,輸入你的賬號密碼即可。至此,我們的準備工作全部做完,可以開始歡快地clone
了~
done,成功!
如果有多個人協作開發,GitHub/Gitee允許添加多個公鑰,只要把每個人的電腦上的公鑰都添加到GitHub/Gitee,就可以在每臺電腦上往GitHub/Gitee上提交推送了。
向遠程倉庫推送 push
當本地倉庫的內容領先于遠程倉庫時,就可以通過本地向遠程倉庫推送的方式把本地最新的修改推送上去。
將遠程倉庫克隆下來后,依然要先配置本地git倉庫的配置項,使用 git config -l
命令:
本地倉庫的郵箱和用戶名必須與遠程倉庫的郵箱用戶名一致。如果之前配置過 --global
的config,那么遠程倉庫拉到本地時,user和email也會自動使用之前配置的global配置項。若本地的配置和遠程倉庫的配置不一樣,則會出錯;若從來沒有配置過global配置項,那么克隆到本地的本地倉庫是沒有用戶名和郵箱配置項的,第一次提交時也會報錯,需要重新配置。
可直接更改:
git config --global user.email "<郵箱地址>"git config --global user.name "<用戶名>"
當我們從遠程倉庫克隆后,Git會自動把本地的master分支和遠程的master分支對應起來,并且,遠程倉庫的默認名稱是origin。
在本地我們仍然可以使用git remote
命令來查看遠程庫的信息,或者用git remote -v
顯示更詳細的信息。
如何把本地倉庫中的修改推送到遠程倉庫中?
將本地倉庫的內容推送至遠程倉庫,需要使用push
命令,該命令用于將本地的分支版本上傳到遠程并合并,如果遠程倉庫下當前并沒有push
命令中指定的遠程分支名,則會自動在遠程創建。
命令格式如下:
git push <遠程主機名> <本地分支名>:<遠程分支名># 如果本地分支名與遠程分支名相同,則可以省略冒號
git push <遠程主機名> <本地分支名>
此時我們要將本地的master分支推送到origin主機的master分支:
推送成功!這里由于我們使用的是SSH協議,是不用每一次推送都輸入密碼的,方便了我們的推送操作。如果你使用的是HTTPS協議,有個麻煩地方就是每次推送都必須輸入口令。
接下來看碼云遠端,就能看到本地的代碼已經被推送上來了。
拉取遠程倉庫
當遠程倉庫的內容領先于本地倉庫時,可以通過拉取遠程倉庫來把遠程倉庫的修改拉取到本地。
使用 pull
命令。
注意:不要直接在遠程倉庫更改任何的代碼,如果要改,也要在本地改完再推送上去。
這里用于模擬遠程倉庫內容領先于本地倉庫的情況:
1、在gitee上點擊README.md文件并在線修改它。
2、修改內容。
此時,遠程倉庫是要領先于本地倉庫一個版本,為了使本地倉庫保持最新的版本,我們需要拉取下遠端代碼,并合并到本地。
git pull
命令會從遠程倉庫獲取更新,并自動將這些更新合并到當前所在的本地分支。【pull
等于拉取+合并】
當運行 git pull
時,它其實執行了兩個操作:git fetch
和 git merge
。
首先,它使用 git fetch
從遠程倉庫獲取最新的提交和文件,并將這些更新存儲在本地的遠程跟蹤分支中(例如origin/main
(遠程跟蹤分支的名稱由遠程倉庫名和分支名組成,它們用斜杠 /
分隔))。
接著,它自動使用 git merge
將遠程跟蹤分支的內容合并到當前所在的本地分支。
Git提供了命令,該命令用于從遠程獲取代碼并合并本地的版本。格式如下:
git pull <遠程主機名> <遠程分支名>:<本地分支名># 如果遠程分支與當前分支名稱相同,則冒號后面的部分可以省略。
git pull <遠程主機名> <遠程分支名>
同名分支對應關系時冒號可以省略:如果你當前的本地分支與遠程分支存在同名且已經建立了追蹤關系,那么可以直接執行 git pull
,Git 會自動識別并拉取對應的遠程分支。例如:
如果你當前在本地的 master
分支上,并且要拉取遠程倉庫的 origin/master
分支,那么可以省略冒號的使用。
通常情況下,如果沒有指定遠程倉庫和分支,則會將與當前本地分支相關聯的遠程分支合并到本地分支。
如果你不在 dev
分支上,也可以使用以下方式在不用切換到dev分支的前提下就能將遠程 origin
的 dev
分支到本地的 dev
分支上。
git pull origin dev:dev
3.配置Git
忽略特殊文件
在日常開發中,我們有些文件不想或者不應該提交到遠端,比如保存了數據庫密碼的配置文件。
那怎么讓Git知道呢?在Git工作區的根目錄下創建一個特殊的.gitignore
文件,然后把要忽略的文件名填進去,Git就不會追蹤管理這些文件了。
不需要我們自己從頭寫.gitignore
文件,gitee在創建倉庫時就可以為我們生成。在創建git倉庫時,有一個初始化倉庫的選項,里面有一個“添加 .gitignore模板”:
當然,如果我們要寫的是Java程序,那么就可以選擇Java的.gitignore
文件模板。
選擇完畢后點擊創建,就會在倉庫中自動生成一個.gitignore
文件,并且文件中的內容會根據我們所選的模板來進行初始化。
如果當時創建倉庫的時候沒有選擇.gitignore
文件模板,那么自己在工作區創建一個也是可以的。
例如我們想忽略以 .so
和 .ini
結尾所有文件,.gitignore
的內容如下:
#省略選擇模本的內容
...# Myconfigurations:
# 可以直接寫文件名(指定某個確定的文件),也可以用通配符
*.ini
*.so
檢驗 .gitignore
的標準是 git status
命令是不是說 working tree clean 。我們發現Git 并沒有提示在工作區中有文件新增,說明 .gitignore 生效了:
以下的演示中,.gitignore
文件是本地新創建的,還沒有commit或推送給遠端,因此它本身的修改也會被記錄,就沒有顯示working tree clean了。
但有些時候,你就是想添加一個文件到 Git,但由于這個文件被 .gitignore
忽略了,根本添加不了怎么辦呢?
1、方法一
可以在add時加上 -f
選項進行強制add:
git add -f b.so
但不建議使用這種方式,因為最好不要違背.gitignore
文件中的配置。
2、方法二
有些時候,當我們編寫了規則排除了部分文件時,比如.*
,但是我們發現 .*
這個規則把 .gitignore
也排除了。此時不想更改.gitignore
規則又要做到不把.gitignore
排除,可以在.gitignore
文件中編輯規則:
把指定文件排除在 .gitignore
規則外的寫法就是 ! +文件名
,所以,只需把例外文件添加進去即可。
Changes to be commited:已經add了,提示需要commit
Changes not staged for commit:曾經已經提交過的文件,已經被git管理了,然后再去修改就會有這個提示。
Untracked files:新建的文件,git還未追蹤管理它
如果一個文件沒有被git管理,但又忘記是否存入.gitignore
中,可以使用命令進行ignore規則檢查:
git check-ignore -v <文件名>
來查看原因。
給命令配置別名
我們可以通過
git config [--global] alias.別名 原命令名
的方式來給git命令配置別名。
如將 git status
簡化為 git st
,對應的命令為:
git config --global alias.st status
--global
參數是全局參數,也就是這些命令在這臺電腦的所有Git倉庫下都有用。如果不加,那只針對當前的倉庫起作用。
再來將git log -l
配置為 git last
,讓其顯示最后一次提交信息:
git config --global alias.last 'log -1'
再將查看提交日志(--pretty=oneline
意思是以一行的格式打印, --abbrev-commit
意思是只打印commit id的前幾位數)
git log --pretty=oneline --abbrev-commit
這一命令配置為更為簡短的git lpa
:
不過還是不推薦大家太早去使用它,還是應當所有的Git命令都手動輸入,以盡快熟悉Git。
**小結
本篇涉及的部分git命令:
git cat-file -p <commit ID>:查看提交信息
git branch:顯示當前所有分支
git branch <分支名>:創建分支
git checkout <分支名>:切換分支
git merge <分支名>:合并分支
git checkout <分支名>:切換分支
git branch -d <分支名>:刪除分支(非強制)
git branch -D?<分支名>:刪除分支(強制)
git checkout -b <分支名>:創建并切換分支
git log --graph --abbrev-commit:查看分支合并情況
git stash:儲藏工作區內容
git stash list:查看stash存放哪些內容
git stash pop:恢復工作區內容
git clone:克隆遠程倉庫
git push:將本地的分支版本上傳到遠程并合并
git fetch:從遠程倉庫獲取最新的提交和文件
**下篇內容
七、標簽管理
八、多人協作
九、企業級開發模型