自己之前寫過兩篇關於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是兩個完全不同的概念。
1,Git與GitHub的區別
GIT是一個開源的分佈式版本控制軟件,用以有效高速的處理從很小到非常大的項目版本管理。簡單說就是一個版本管理工具,是可以在電腦不聯網的情況下只在本地使用的版本管理工具,其作用就是可以讓我們更好的管理代碼,進行版本控制。
安裝Git,請參考博客:GIT安裝教程(windows)
而GitHub是一個基於Git的遠程文件託管平臺(同GitCafe BitBucket和GitLab等),簡單說是一個網站,比如說程序員將自己代碼存儲在GitHub的一個倉庫中,別人可以看到,也可以協同操作,方便程序員之間互相學習和交流。
2,Git的工作原理
2.1 正常的提交版本
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發現你提交的代碼有問題,或者不符合預期,需要你進行修改,就需要回滾操作了。
所以當之前保存的代碼發生問題,那麼如何回滾呢?
2.2 回滾到之前的版本
首先,使用下面代碼,查看歷史版本記錄:
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 回退,如果有差異則存在暫存區,不會輕易刪除代碼。
回滾完成了,如果某天,想回到之後的高級版本,如何做呢?(爲啥這麼多如果呢,其實就是自己回滾後,發現誤刪了別人的東西,又需要返回去,在項目開發中也是比較常見的失誤)
2.3 從之前回滾到之後的版本
首先,使用下面代碼,查看記錄(下面代碼:查看命令歷史,挽回錯誤的重置,用來記錄我們的每一次命令)
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
3,利用Git + GitHub進行團隊協作開發
團隊協作開發中,大部分使用到版本控制軟件,也許代碼存儲的地方不一樣,但是原理不盡相同。所以這裏以Git+GitHub爲例詳細聊一下在真實的工作環境中如何協作開發。
3.1 分支類型介紹
每個倉庫中可以包含多個分支,每個分支都對應一個獨享的目錄,各個分支並列在倉庫下面。不過常規的是以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分支,因爲本人並未使用過,就不誤導大家了)。
3.2 團隊協作開發項目流程
假設團隊中需要做一個新的項目,並且計劃將代碼託管到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博大精深,我也只是勉強用着。
3.3 git branch 和git checkout
之前說到了新建分支,檢出等概念,這裏詳細介紹一下,也給自己留個筆記。常用命令如下:
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分支下同時給所有開發人員創建了新的分支,命名統一管理,所以需要使用這個命令。
3.4 Git push
爲什麼要說一下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 的時候不會推送分支,如果一定要推送標籤的話,那麼可以使用這個命令。
3.5 Git stash
上面提到了一個命令叫做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的棧中,這時候拉下同事的代碼後,再把自己的代碼取出來即可。