關于Git的使用,相關的文章已經很多了,本文不探讨具體的操作指令,主要從應用角度讨論一些版本管理的思路,包括如何進行版本管理,如何處理合并與沖突等。
一、概述
目前用到最廣泛的版本控制軟體就是SVN和Git,那麼這兩者之間有什麼不同之處呢?
1) SVN(Subversion)是集中式管理的版本控制器,而Git是分布式管理的版本控制器!
2) SVN隻有一個單一的集中管理的伺服器,儲存所有檔案的修訂版本,而協同工作的人們都通過用戶端連到這台伺服器,取出最新的檔案或者送出更新。
3) Git每一個終端都是一個倉庫,用戶端并不隻提取最新版本的檔案快照,而是把原始的代碼倉庫完整地鏡像下來。每一次的提取操作,實際上都是一次對代碼倉庫的完整備份。
4) Git具備強大的分支管理功能,SVN實際上不具備。
SVN的優點:
1) 管理友善,邏輯明确,符合一般人思維習慣。
2) 易于管理,集中式伺服器更能保證安全性。
3) 代碼一緻性高。
SVN的缺點:
1) 送出并非每次都能夠成功。如果有其他人先于你送出,會提示“改動基于過時的版本,先更新再送出”… 諸如此類;
2) 沖突解決是一個送出速度的競賽:手快者,先送出,平安無事;手慢者,後送出,可能遇到麻煩的沖突解決。
Git更适合分布式開發,離線工作,強調個體,任意兩個開發者之間可以很容易的解決沖突。最重要的是Git具備強大的分支管理功能,非常适合産品開發。
通過git指令可以檢視所有指令的介紹

git擷取倉庫的指令是clone而不是checkout,從這就可以看出Git和SVN的差別。
Git擷取的是整個庫的資訊,可以檢視所有日志資訊。
在檔案夾下運作commit指令,将檔案送出到本地版本庫。
由于本地倉庫隻有你一個人在使用,是以請放心送出,不需要考慮BUG等因素。PUSH時就要小心了。
有些檔案是不需要送出到版本管理的,比如 .vs 檔案夾、bin、obj檔案夾等,應該将其加入忽略清單中。
Git送出時要求輸入關于本次送出的說明,請認真填寫,這樣就不用維護額外的版本修改日志了。對于确實無關緊要的送出,可以團隊約定輸入一個字元,如“#”。
同步操作有兩種:
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) 如果兩個使用者修改了同一個檔案的兩個地方就會引起沖突。
版本沖突在兩個使用者修改同一個檔案的同一個位置時發生。修改同一個檔案的不同的位置會自動合并,不會沖突。二進制檔案沒有合并功能,任何同時修改都會沖突。
一個沖突解決的示例:
這是代碼的原始版本:
static void Main(string[] args)
{
Console.WriteLine("Hello");
Console.ReadLine();
}
A使用者修改後:
static void Main(string[] args)
Console.WriteLine("Hello:I'm Good Boy!");
B使用者修改後:
Console.WriteLine("Hello:I'm BAD Boy!");
首先A使用者率先進行了commit 和 PUSH,成功。B使用者此時也準備送出,送出前,要進行一次PULL,此時發生沖突:自動合并失敗!
CONFLICT (content): Merge conflict in ConsoleApp1/ConsoleApp1/Program.cs
Automatic merge failed; fix conflicts and then commit the result.
打開沖突檔案,可以看到:
<<<<<<< HEAD
Console.WriteLine("Hello:I'm BAD Boy!");
=======
Console.WriteLine("Hello:I'm Good Boy!");
>>>>>>> 129dfb44dd2978700d82493d9fa966e598b85535
}
可以看到沖突内容包含在<<<<<<<與>>>>>>>之間,通過======隔開,前面是本地版本,後面是遠端版本。
處理辦法:直接修改這個檔案,然後commit、PULL、PUSH即可。
還有一種沖突是版本庫删除了一個檔案,本地還進行了修改,這也形成沖突。
AA.txt deleted in 777b20bb5a04b3c3489318c5e7d6723d5d38d50f and modified in HEAD. Version HEAD of DOC/AA.txt left in tree.
處理辦法:先将沖突檔案移開,commit後再PULL就可以成功,如果還需要這個檔案,再重新commit即可。
為了合并、回退等操作友善,我們會對重要版本進行标記。在log界面找到指定版本,右鍵選擇:“create tag at this version…”。
如果檔案(或檔案夾)被誤删除,并且已經清空資源回收筒,可以從本地版本庫取得最新送出的檔案,注意:隻有送出過的版本才能恢複,沒有送出的内容是不可能找回的,是以要經常送出。
首先通過日志找到删除之前的某個版本,在其檔案上右鍵選擇“Revert to this version”即可,對于不想要的檔案,如果想恢複到之前版本,也可以通過這個方法處理。
可能近期寫的代碼一團糟,已經無法走上正軌了,希望恢複到某個穩定的版本重新開發,這就需要重置版本。首先在日志視窗找到要恢複的點,右鍵選擇:”reset XXX to this version…”
重置類型選擇“Hard”:
Hard表示強制恢複到指定版本,Mixed表示保留修改的檔案。
如果在回退前沒有PUSH過版本,回退後需要PUSH的話直接PUSH就可以了,如果回退的版本早于最後一次PUSH的版本,則需要進行強制PUSH(Hard)。
需要說明的是,遠端版本回退應該是一個集體行為,不存在項目組某個人進行版本回退,但其他人繼續使用目前版本的情況,回退點之後的版本是要抛棄掉的。
一般來說主線版本(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 。
一般通過Git管理平台建立分支,并為分支設定權限,也可以在本地建立分支,然後Push到遠端伺服器。如果要在某個時間點建立分支,在日志視窗找到指定的時間點,右鍵選擇“Create Branch at this version…”即可。本地建立分支後,需要切換到該分支并執行PUSH操作才能将分支同步到伺服器。
在固定的某個分支上進行開發,參照本文第二、第三部分的描述即可。本地克隆了版本庫之後,立即切換到開發分支,第一次切換時會在本地建立相同名稱的本地分支。
通過Fetch指令擷取其他分支内容。Fetch指令把遠端伺服器上所有版本同步到本地,但不做進一步操作。
通過Merge指令進行版本合并,合并時需要選擇對方分支的名稱。
Pull指令相當于 Fetch + Merge ,就是把遠端庫同步到本地并自動進行合并。如果要合并其他分支,Pull時需要選擇其他遠端分支的名稱。
采用PULL或Fetch + Merge沒有本質差別,唯一的差別就是在進行分支合并時Fetch後可以先觀察一些修改的内容在進行合并。建議在同一個分支工作時就采用Pull,在分支之間進行合并時,采用Fetch + Merge。
合并版本後,對所有沖突進行手動修改,修改完成後Commit、PUSH即可。
需要注意幾點:
1、 永遠以master分支為釋出分支;
2、 master會合并develop和fixbug版本,develop也會合并fixbug版本,不要有其他方向的合并;
3、 master版本合并其他版本後,通過建立分支的方式繼續開發,原來其他分支可以删除掉。
4、 如果develop合并fixbug時有沖突,master在合并develop和fixbug時可能任然會沖突,如果develop版本已經合并了所有fixbug,那麼master版本在合并develop後可以不用重複合并fixbug。
以下是一個常見的版本管理的流程:
具體流程描述如下:
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) 穩定版本釋出後即可删除所有臨時分支。
簽名區:
如果您覺得這篇部落格對您有幫助或啟發,請點選右側【推薦】支援,謝謝!