自己之前寫過兩篇關於Git和GItHub使用的文章,分別是
淺談使用git 進行版本控制部落格連結:https://www.cnblogs.com/wj-1314/p/7992543.html
使用GitHub的點點滴滴的部落格連結:https://www.cnblogs.com/wj-1314/p/9901763.html
說真的,學一遍,記錄一遍,都有不同的感悟,第一次學習Git的時候,也就是2017年12月,覺得這個東西很神奇,當時還是一個學生,只是看別人都在學,自己也學一下,但是卻沒有深入使用,只是知道一些原理和拉程式碼等;第二次學習Git上傳程式碼到GitHub上傳程式碼的時候總是遇到一些問題,就是2018年11月。有句話說的好「好記性不如爛筆頭」,所以將自己使用Git進行拉取和上傳程式碼到GitHub的流程和遇到問題記錄下來,所以就有了第二篇文章,記錄自己使用GitHub的點點滴滴,而現在已經是2023年2月份了,距離第一次學習Git已經五年了,自己也早已經會其操作了,但是女盆友不太會,所以寫一篇筆記幫一下她,也是自己對git的理解做一個總結。
首先說明一下Git和GitHub是兩個完全不同的概念。
GIT是一個開源的分散式版本控制軟體,用以有效高速的處理從很小到非常大的專案版本管理。簡單說就是一個版本管理工具,是可以在電腦不聯網的情況下只在本地使用的版本管理工具,其作用就是可以讓我們更好的管理程式碼,進行版本控制。
安裝Git,請參考部落格:GIT安裝教學(windows)
而GitHub是一個基於Git的遠端檔案託管平臺(同GitCafe BitBucket和GitLab等),簡單說是一個網站,比如說程式設計師將自己程式碼儲存在GitHub的一個倉庫中,別人可以看到,也可以協同操作,方便程式設計師之間互相學習和交流。
Git把管理的檔案分為了兩個區域四個狀態,如下圖:
工作區
當前開發程式所在的目錄稱為工作區,即:工作開發都是在該目錄,該區域的檔案會有狀態的變化且狀態由git自動檢測,如果程式中檔案做任何操作(增,刪,改),檔案狀態均會被檢測到,可以使用下面命令檢視:
git status
工作區通俗的說就是我們寫程式碼的區域,比如在vscode的IDE上開發程式碼,其專案資料夾就是工作區。
版本庫
工作區檢測到有檔案發生變化,那麼意味著較上一個版本之後對程式進行了修改,修改完成之後,可以當做下一版本進行提交,那麼就是執行下面命令:
git add .
此命令將所有檔案提交到暫存區,然後執行下一個命令:
git commit -m "下一個版本"
此命令可以提交到版本庫的分支,之後可以使用下面命令檢視版本記錄
git log
使用的命令記錄:
目前已使用Git的四個命令,這四個命令已經可以代替本地多個檔案儲存版本的方式: git init,初始化,表示即將對當前資料夾進行版本控制。 git status,檢視Git當前狀態,如:那些檔案被修改過、那些檔案還未提交到版本庫等。 git add 檔名,將指定檔案新增到版本庫的暫存狀態。 git commit -m '提交資訊',將暫存區的檔案提交到版本庫的分支。 git log,檢視提交記錄,即:歷史版本記錄
如果是遠端的程式碼,或者說團隊共同作業開發的程式碼,可能需要push到主分支上,等待專案的owner進行merge。如果專案的owner發現你提交的程式碼有問題,或者不符合預期,需要你進行修改,就需要回滾操作了。
所以當之前儲存的程式碼發生問題,那麼如何回滾呢?
首先,使用下面程式碼,檢視歷史版本記錄:
git log
一般會出現下面幾個關鍵的東西:
commit 0972f4bb43104baee15aeec2dd62bd0a312ds123 Author: james <14578457.qq.com> Date: Fri Aug 11 10:54:42 2018 +0800 Monday update 11.7 commit 0972f4bb43104baee15aeec2dd62bd0a378de456 Author: james <14578457.qq.com> Date: Fri Aug 11 10:54:42 2018 +0800 Tuseday update 11.8
你可以使用下面程式碼回滾到指定的版本:
git reset --hard 0972f4bb43104baee15aeec2dd62bd0a378de456 HEAD is now at 6c439d2 Tuesday update 11.8
hard是強制回滾,表示回退刪除,因為是不可逆操作,所以確保自己原生程式碼不需要了,才可以回退刪除。
soft 回退,如果有差異則存在暫存區,不會輕易刪除程式碼。
回滾完成了,如果某天,想回到之後的高階版本,如何做呢?(為啥這麼多如果呢,其實就是自己回滾後,發現誤刪了別人的東西,又需要返回去,在專案開發中也是比較常見的失誤)
首先,使用下面程式碼,檢視記錄(下面程式碼:檢視命令歷史,挽回錯誤的重置,用來記錄我們的每一次命令)
git reflog
會檢視到下面內容:
6c439d2 HEAD@{2}: reset: moving to 0972f4bb43104baee15aeec2dd62bd0a378de456 0972f4b HEAD@{3}: commit: Monday update 11.7 6c439d2 HEAD@{4}: commit (initial): Tuesday update 11.8
使用下面程式碼即可back的之後的版本:
git reset --hard 0972f4b
結果如下:
HEAD is now at 0972f4b monday 11.7
團隊共同作業開發中,大部分使用到版本控制軟體,也許程式碼儲存的地方不一樣,但是原理不盡相同。所以這裡以Git+GitHub為例詳細聊一下在真實的工作環境中如何共同作業開發。
每個倉庫中可以包含多個分支,每個分支都對應一個獨享的目錄,各個分支並列在倉庫下面。不過常規的是以master分支為主,還有dev分支。
master分支:即主分支,任何專案都必須有這個分支,一般都是專案的leader或演演算法的架構擁有操作權。通過主分支可以對專案進行tag或者釋出版本等操作。
develop分支:即開發分支,這個分支從master分支上檢出。而團隊開發成員一般不會直接更改這個分支,這個分支的owner也是演演算法架構。一般來說團隊開發成員會從該分支檢出自己的feature分支,開發完成後將feature分支上的改動進行pull request,由專案的owner進行程式碼check,如果沒問題則會merge到develop分支。同時release分支由此分支檢出。
release分支:即釋出分支,從develop分支上檢出。該分支用作發版前的測試,可進行簡單的bug修復,如果bug比較大,則可merge回develop分支上,由開發成員進行bug修復再提交程式碼。此分支測試完成後,需要同時merge到master和develop分支上。
feature分支:即功能分支,從develop分支上檢出。團隊成員每個人都維護一個自己的feature分支,並進行開發工作。開發完成後提交程式碼,由專案owner檢查,再merge回develop分支。此分支一般由開發人員開發新功能或進行專案維護等。
總結:如果只是開發人員,只需要關注自己的feature分支,完成程式碼後提交dev分支即可,其他分支做了解即可(其實還有hotfix分支,因為本人並未使用過,就不誤導大家了)。
假設團隊中需要做一個新的專案,並且計劃將程式碼託管到GitHub上。那麼首先就需要專案的owner在Github上建立一個新的專案,暫且稱為 Project_1。同時他將其關聯到GitHub上的origin/master上,假設這個專案的基礎版已經完成,則owner會在master分支上打tag,假設命名為V0.1,此時V0.1的專案已經正常執行了。
但是PM提出了新的需求了,所以專案owner需要分配團隊成員開發功能,那麼他負責在master分支上新建並檢出dev分支,新開發的功能肯定在dev分支上進行。
# 從master分支上新建develop分支 git branch develop master # 檢出develop分支 git checkout develop
目前dev分支建立完成了,並且團隊的十個開發成員也開完會了,每個人都有開發任務,並且開發不同的功能,這時候專案的owner會告訴開發成員,團隊的每個人都需要從程式碼倉庫中克隆專案,然後在dev下建立自己的feature分支了。
下面為其clone流程:
# step1 clone 倉庫 git clone xxxx.git # step2 檢出develop分支 git checkout develop # step 3 從develop分支新建並檢出feature分支 git checkout -b feature-xx develop
經過了一段時間。。。。。
目前程式設計師A已經完成了自己的需求了,並且提交了程式碼。其流程如下:
# step1 可以檢測一下自己當前的分支,方便複製自己的feature名稱 git branch -a # step2 提交程式碼之前,需要檢測一下dev倉庫是否有其他同事提交了程式碼 # 情況1:如果其他同事沒有提交程式碼,直接pull git pull origin develop # 情況2: 如果其他同事提交了程式碼,這裡可以先暫存自己的程式碼,然後拉取新程式碼 git stash git pull origin develop git stash pop # step3,開始上傳自己需要上傳的程式碼 git add . git commit -s -m "my code" git push origin feature_xx
此時 自己的程式碼已經上傳到自己Github的遠端倉庫了,這也是做一個備份,同時提交pull request需求,將程式碼提交到dev分支上,等待演演算法owner進行merge。
注意:在團隊合作時,commit message的書寫格式應該遵守相應規範,清晰明瞭的commit message有助於快速定位提交,自動生成change log檔案。
這時候存在兩種情況,一種是程式碼符合要求,演演算法owner直接merge程式碼;一種是程式碼存在bug,需要繼續修改,這樣自己需要繼續修改。
假設程式設計師同學完成了自己bug修復,修改完成後再提交程式碼。注意這裡不需要再commit新的資訊了,為了避擴音交無用資訊,這時候可以使用git amend。
# 完成程式碼後,檢查操作同上,這裡不再贅述,然後提交程式碼 git add . git commit --amend git push origin feature_xx
amend的好處就是提交紀錄檔只存在一次提交記錄,資訊也是顯示的是我們第二次修改的資訊,最終專案owner進行merge程式碼。開發完成。
這裡通過Pull requests 簡單說了一下團隊開發的流程,當然也可以使用GitFlow工作流的方式,主要看自己團隊和具體業務的共同作業方式是什麼。當然Git博大精深,我也只是勉強用著。
之前說到了新建分支,檢出等概念,這裡詳細介紹一下,也給自己留個筆記。常用命令如下:
git branch //檢視當前分支 git branch -r //列出遠端分支 git branch -a //列出所有分支 git branch branchName //建立分支 git checkout branchName //切換分支 git checkout -b branchName //建立並切換到分支 git checkout //後面不跟任何引數,則就是對工作區進行檢查 git checkout --filename //從暫存區中恢復檔案(確保filename與branch名稱不同) git status //檢視狀態
這裡解釋一下 git checkout -b BRANCH_NAME,意思是建立一個新的分支,並且切換到這個新的分支。為什麼說這個呢?因為常用是一方面,另一方面是這個命令其實是執行了以下兩個操作:
# 建立一個新分支 git branch BRANCH_NAME # 然後把分支從當前分支切換到新分支 git checkout BRANCH_NAME
因為git branch BRANCH_NAME雖然建立了新的分支,但是仍然將我們留在了同一分支。適用情況如下:專案的leader為了方便管理feature分支,他在dev分支下同時給所有開發人員建立了新的分支,命名統一管理,所以需要使用這個命令。
為什麼要說一下push,因為大部分人熟練後都會使用縮寫或者簡寫,這裡將push再做一個筆記,方便新手入門。
在使用 git commit 命令將修改從暫存區提交到本地版本庫後,只剩下最後一步將本地版本庫的分支推播到遠端伺服器上對應的分支了,而推播使用的命令為git push,下面詳細學習一下。
git push 的一般形式為:
git push <遠端主機名> <本地分支名> <遠端分支名>
舉個例子: git push origin master:refs/for/master ,即是將原生的master分支(本地叫什麼都無所謂,自己認識就可以)推播到遠端主機origin上的對應master分支, origin 是遠端主機名,第一個master是本地分支名,第二個master是遠端分支名。
1, git push origin master
這個是大家常用的命令,其意義是如果遠端分支被省略,如上表示將本地分支推播到與之存在追蹤關係的遠端分支(通常兩者同名),如果該遠端分支不存在,則會被新建。
2, git push origin : refs/for/master
如果省略本地分支名,則表示刪除指定的遠端分支,因為這等同於推播一個空的本地分支到遠端分支,等同於 git push origin -- delete master
關於 refs/for:
//refs/for 的意義在於我們提交程式碼到伺服器之後是需要經過 code review之後才能進行 merge的,而 refs/heads 不需要
3,git push origin
如果當前分支與遠端分支存在追蹤關係,則本地分支和遠端分支都可以省略,將當前分支推播到 origin 主機的對應分支
4,git push
如果當前分支只有一個遠端分支,那麼主機名都可以省略,可以使用 git branch -r,檢視遠端的分支名
5,git push -u origin master
如果當前分支與多個主機存在追蹤關係,則可以使用 -u 引數指定一個預設主機,這樣後面就可以不加任何引數使用 git push,注意不帶任何引數的 git push,預設只推播當前分支,這叫做 simple方式,還有一種 matching 方式,會推播所有有對應的遠端分支的本地分支,Git 2.0 之前預設使用 matching,現在改為 simple方式,如果想要更改設定,可以使用 git config命令。
git config --global push.default matching git config --global push.default simple 可以使用git config -l 檢視設定
6,git push --all orgin
當遇到這種情況就是不管是否存在對應的遠端分支,將原生的所有分支都推播到遠端主機,這時需要 --all 選項
7,git push --force origin
git push 的時候需要本地先 git pull 更新到跟伺服器版本一致,如果本地版本庫比遠端伺服器上的低,那麼一般會提示你 git pull 更新,如果一定要提交,那麼可以使用這個命令。
8,git pusj origin --tags //
git push 的時候不會推播分支,如果一定要推播標籤的話,那麼可以使用這個命令。
上面提到了一個命令叫做git stash,這是啥意思呢? 他其實處於git reset --hard(完全放棄還修改了一半的程式碼)與git commit(提交程式碼)的命令之間,很類似於「暫停」按鈕。
git stash 可以將原生的程式碼沒有提交的程式碼儲存起來。如果git stash之後,再使用git status檢視本地工作區的狀態,我們會發現所有沒有commit的程式碼,都會暫時從工作區移除,回到上次commit的狀態,並且非常乾淨,如果需要取出之前儲藏的程式碼,使用 git stash pop即可。
如果做了多次儲藏,則需要使用git stash list檢視其記錄。
# 列出所有暫時儲存的工作 $ git stash list stash@{0}: WIP on workbranch: 56cd5d4 Revert "update old files" stash@{1}: WIP on project1: 1dd87ea commit "fix typos and grammar" # 恢復某個暫時儲存的工作 $ git stash apply stash@{1} # 恢復最近一次stash的檔案 $ git stash pop # 丟棄最近一次stash的檔案 $ git stash drop # 刪除所有的stash $ git stash clear
上面命令再解釋一下,git stash pop命令總是取出最近一次的修改,但是可以使用git stash apply指定取出某一次的修改。而git stash apply不會自動刪除取出的修改,需要手動刪除,git stash drop stash@{1}。
git stash 子命令常見的用法:
git stash: 備份當前的工作區的內容,從最近的一次提交中讀取相關內容,讓工作區保證和上次提交的內容一致。同時,將當前的工作區內容儲存到Git棧中。 git stash pop: 從Git棧中讀取最近一次儲存的內容,恢復工作區的相關內容。由於可能存在多個Stash的內容,所以用棧來管理,pop會從最近的一個stash中讀取內容並恢復。 git stash list: 顯示Git棧內的所有備份,可以利用這個列表來決定從那個地方恢復。 git stash clear: 清空Git棧。此時使用gitg等圖形化工具會發現,原來stash的哪些節點都消失了。 git stash show -p :展示目前存在的stash git stash drop:丟棄最近一次stash的檔案 git stash apply stash@{1}:恢復某個暫時儲存的工作 git stash drop stash@{1} : 由於上面命令不會自動刪除取出的修改,所以需要手動刪除
git stash的應用場景就是:作為開發者使用自己的分支修改和偵錯程式碼,如果同事發現自己的分支上有一個不得不修改的bug,那麼為了不影響自己的開發,並且讓同事的bug不影響自己,那麼需要將同事修改後的程式碼拉下來,這樣使用git stash 就會將當前未提交到遠端伺服器的程式碼推入到自己的Git的棧中,這時候拉下同事的程式碼後,再把自己的程式碼取出來即可。