Git基本使用指南
- 2019 年 10 月 25 日
- 筆記
一、概述
1. Git與SVN比較
目前用到最廣泛的版本控制軟體就是SVN和Git,那麼這兩者之間有什麼不同之處呢?
1) SVN(Subversion)是集中式管理的版本控制器,而Git是分散式管理的版本控制器!
2) SVN只有一個單一的集中管理的伺服器,保存所有文件的修訂版本,而協同工作的人們都通過客戶端連到這台伺服器,取出最新的文件或者提交更新。
3) Git每一個終端都是一個倉庫,客戶端並不只提取最新版本的文件快照,而是把原始的程式碼倉庫完整地鏡像下來。每一次的提取操作,實際上都是一次對程式碼倉庫的完整備份。
4) Git具備強大的分支管理功能,SVN實際上不具備。
2. 為什麼選擇Git
SVN的優點:
1) 管理方便,邏輯明確,符合一般人思維習慣。
2) 易於管理,集中式伺服器更能保證安全性。
3) 程式碼一致性高。
SVN的缺點:
1) 提交並非每次都能夠成功。如果有其他人先於你提交,會提示“改動基於過時的版本,先更新再提交”… 諸如此類;
2) 衝突解決是一個提交速度的競賽:手快者,先提交,平安無事;手慢者,後提交,可能遇到麻煩的衝突解決。
Git更適合分散式開發,離線工作,強調個體,任意兩個開發者之間可以很容易的解決衝突。最重要的是Git具備強大的分支管理功能,非常適合產品開發。
二、基本操作
1. 獲取幫助
通過git命令可以查看所有命令的介紹
2. 倉庫的克隆
git獲取倉庫的命令是clone而不是checkout,從這就可以看出Git和SVN的區別。
Git獲取的是整個庫的資訊,可以查看所有日誌資訊。
3. 提交程式碼
在文件夾下運行commit命令,將文件提交到本地版本庫。
由於本地倉庫只有你一個人在使用,所以請放心提交,不需要考慮BUG等因素。PUSH時就要小心了。
有些文件是不需要提交到版本管理的,比如 .vs 文件夾、bin、obj文件夾等,應該將其加入忽略列表中。
Git提交時要求輸入關於本次提交的說明,請認真填寫,這樣就不用維護額外的版本修改日誌了。對於確實無關緊要的提交,可以團隊約定輸入一個字元,如“#”。
4. 同步倉庫
同步操作有兩種:
1、 PULL:將遠程伺服器程式碼同步到本地
2、 PUSH:將本地程式碼同步到遠程伺服器
具體的操作流程應該如下:
1、 commit的操作應該是頻繁進行的,和遠程庫無關;
2、 執行PULL操作獲取團隊最新程式碼;
3、 本地確認編譯成功後PUSH到遠程庫,以便分享個人程式碼。PUSH前應該確認個人版本是可以編譯通過的。
模擬一個操作場景:
1) A用戶早上PULL了最新版本,然後在此版本基礎上進行了一天的開發,下班時進行了PUSH操作,沒有發生任何問題;(應該先PULL再PUSH)
2) B用戶早上也PULL最新版本,開發了一天,此時B進行PUSH會報錯(本地庫版本和遠程庫不一致),必須先進行PULL獲得最新版本後才能進行PUSH。(PUSH前應保證版本可以編譯)
3) 如果兩個用戶修改了同一個文件,當B用戶在進行PULL時會進行合併,一般不會發生衝突。A用戶會在下次PULL時獲得合併後的版本。
4) 如果兩個用戶修改了同一個文件的兩個地方就會引起衝突。
5. 解決衝突
版本衝突在兩個用戶修改同一個文件的同一個位置時發生。修改同一個文件的不同的位置會自動合併,不會衝突。二進位文件沒有合併功能,任何同時修改都會衝突。
一個衝突解決的示例:
這是程式碼的原始版本:
static void Main(string[] args) { Console.WriteLine(“Hello”);
Console.ReadLine(); } |
A用戶修改後:
static void Main(string[] args) { Console.WriteLine(“Hello”); Console.WriteLine(“Hello:I’m Good Boy!”); Console.ReadLine(); } |
B用戶修改後:
static void Main(string[] args) { Console.WriteLine(“Hello”); Console.WriteLine(“Hello:I’m BAD Boy!”); Console.ReadLine(); } |
首先A用戶率先進行了commit 和 PUSH,成功。B用戶此時也準備提交,提交前,要進行一次PULL,此時發生衝突:自動合併失敗!
CONFLICT (content): Merge conflict in ConsoleApp1/ConsoleApp1/Program.cs
Automatic merge failed; fix conflicts and then commit the result.
打開衝突文件,可以看到:
static void Main(string[] args) { Console.WriteLine(“Hello”); <<<<<<< HEAD Console.WriteLine(“Hello:I’m BAD Boy!”); ======= Console.WriteLine(“Hello:I’m Good Boy!”); >>>>>>> 129dfb44dd2978700d82493d9fa966e598b85535 Console.ReadLine(); } } |
可以看到衝突內容包含在<<<<<<<與>>>>>>>之間,通過======隔開,前面是本地版本,後面是遠程版本。
處理辦法:直接修改這個文件,然後commit、PULL、PUSH即可。
還有一種衝突是版本庫刪除了一個文件,本地還進行了修改,這也形成衝突。
AA.txt deleted in 777b20bb5a04b3c3489318c5e7d6723d5d38d50f and modified in HEAD. Version HEAD of DOC/AA.txt left in tree.
處理辦法:先將衝突文件移開,commit後再PULL就可以成功,如果還需要這個文件,再重新commit即可。
三、進階操作
1. 版本標記
為了合併、回退等操作方便,我們會對重要版本進行標記。在log介面找到指定版本,右鍵選擇:“create tag at this version…”。
2. 恢復誤刪除的文件
如果文件(或文件夾)被誤刪除,並且已經清空回收站,可以從本地版本庫取得最新提交的文件,注意:只有提交過的版本才能恢復,沒有提交的內容是不可能找回的,所以要經常提交。
首先通過日誌找到刪除之前的某個版本,在其文件上右鍵選擇“Revert to this version”即可,對於不想要的文件,如果想恢復到之前版本,也可以通過這個方法處理。
3. 獲取指定版本庫
可能近期寫的程式碼一團糟,已經無法走上正軌了,希望恢復到某個穩定的版本重新開發,這就需要重置版本。首先在日誌窗口找到要恢復的點,右鍵選擇:”reset XXX to this version…”
重置類型選擇“Hard”:
Hard表示強制恢復到指定版本,Mixed表示保留修改的文件。
如果在回退前沒有PUSH過版本,回退後需要PUSH的話直接PUSH就可以了,如果回退的版本早於最後一次PUSH的版本,則需要進行強制PUSH(Hard)。
需要說明的是,遠程版本回退應該是一個集體行為,不存在項目組某個人進行版本回退,但其他人繼續使用當前版本的情況,回退點之後的版本是要拋棄掉的。
四、分支管理
1. 分支管理概述
一般來說主線版本(master)是不會用來開發的,只用來進行版本發布,如果一個項目採用master單線版本進行開發,建議不要採用Git進行版本管理,採用SVN會更加方便一點。
下面介紹一下版本分支管理的主要流程與意圖:
某公司1號發布了產品版本V1.0,15號開發人員在開發V1.1過程中接到客戶回饋,發現重大BUG需要緊急修復,假設採用單分支開發,就必須在當前分支進行修復並發布,造成的問題是本次發布的版本包含未經驗證的V1.1版本的內容。
正確的做法應該是:master主分支發布V1.0版本後,創建分支V1.1進行下一個版本開發,當收到用戶BUG回饋時,創建V1.0_DEBUG分支進行修復,並發布。當V1.1版本開發完成並驗證通過後,將V1.1分支合併到master分支,同時合併V1.0_DEBUG分支修復的BUG。
版本合併後,繼續創建V1.2版本進行下一個版本開發。V1.1版本發現的BUG可以繼續在原來V1.1分支上進行修復,V1.0_DEBUG版本可以不用繼續維護了,之前發出的版本如果發現問題,可以在V1.1版本進行修改,並將客戶版本升級到V1.1 。
2. 創建分支
一般通過Git管理平台創建分支,並為分支設置許可權,也可以在本地創建分支,然後Push到遠程伺服器。如果要在某個時間點創建分支,在日誌窗口找到指定的時間點,右鍵選擇“Create Branch at this version…”即可。本地創建分支後,需要切換到該分支並執行PUSH操作才能將分支同步到伺服器。
3. 在某分支上進行開發
在固定的某個分支上進行開發,參照本文第二、第三部分的描述即可。本地克隆了版本庫之後,立即切換到開發分支,第一次切換時會在本地建立相同名稱的本地分支。
4. 分支的合併
通過Fetch命令獲取其他分支內容。Fetch命令把遠程伺服器上所有版本同步到本地,但不做進一步操作。
通過Merge命令進行版本合併,合併時需要選擇對方分支的名稱。
5. Fetch與Pull的區別
Pull命令相當於 Fetch + Merge ,就是把遠程庫同步到本地並自動進行合併。如果要合併其他分支,Pull時需要選擇其他遠程分支的名稱。
採用PULL或Fetch + Merge沒有本質區別,唯一的區別就是在進行分支合併時Fetch後可以先觀察一些修改的內容在進行合併。建議在同一個分支工作時就採用Pull,在分支之間進行合併時,採用Fetch + Merge。
6. 分支衝突
合併版本後,對所有衝突進行手動修改,修改完成後Commit、PUSH即可。
需要注意幾點:
1、 永遠以master分支為發布分支;
2、 master會合併develop和fixbug版本,develop也會合併fixbug版本,不要有其他方向的合併;
3、 master版本合併其他版本後,通過新建分支的方式繼續開發,原來其他分支可以刪除掉。
4、 如果develop合併fixbug時有衝突,master在合併develop和fixbug時可能任然會衝突,如果develop版本已經合併了所有fixbug,那麼master版本在合併develop後可以不用重複合併fixbug。
五、Git版本管理最佳實踐
以下是一個常見的版本管理的流程:
具體流程描述如下:
1) 首先建立版本庫,自動創建master版本,在master版本上持續開發,直到發布V1.0版本;
2) V1.0版本發布後同時面臨兩個任務:V1.1版本開發和V1.0版本的Bug修復。此時創建V1.1_develop分支和V1.0_bugfix兩個分支,相關的開發團隊應該立即Fetch庫後Switch到各自的庫上開展工作;
3) 新版本V1.1_develop研發完成並驗證後,合併到master庫,同時master庫合併V1.0_bugfix分支,經驗證後發布V1.1版本;
4) 刪除V1.1_develop和V1.0_bugfix分支;
5) 創建新分支,循環以上過程。
需要注意幾點:
1) 如果更嚴謹一些的話,應該還要具備測試分支,測試分支從develop分支創建,測試通過後合併到主分支。
2) 以上第三個過程的操作,可以更積極一點,master版本可以更頻繁地合併兩個版本以及時處理衝突,develop分支也可以積極合併fixbug分支,但fixbug分支不能合併其他分支。
3) 穩定版本發布後即可刪除所有臨時分支。