1、什么是版本控制
版本控制(Version control),是維護(hù)工程藍(lán)圖的標(biāo)準(zhǔn)做法,能追蹤工程藍(lán)圖從誕生一直到定案的過(guò)程。此外,版本控制也是一種軟件工程技巧,借此能在軟件開(kāi)發(fā)的過(guò)程中,確保由不同人所編輯的同一程序文件都得到同步。并且可以實(shí)現(xiàn)記錄文件所有歷史變化,做到可追溯、隨時(shí)恢復(fù)。
2、常見(jiàn)的版本控制工具
1)集中式版本控制系統(tǒng)
適合多人團(tuán)隊(duì)協(xié)作開(kāi)發(fā);代碼集中化管理。單點(diǎn)故障、必須聯(lián)網(wǎng),無(wú)法單機(jī)工作。
代表:SVN。
2)分布式版本控制系統(tǒng)
適合多人團(tuán)隊(duì)協(xié)作開(kāi)發(fā);代碼集中化管理;可以離線工作、每個(gè)計(jì)算機(jī)都是一個(gè)完整倉(cāng)庫(kù)。
代表:Git。
3、Git
git,是一個(gè)分布式版本控制軟件。分布式版本控制系統(tǒng)的客戶端并不只提取最新版本的文件快照,而是把代碼倉(cāng)庫(kù)完整地鏡像下來(lái)。這么一來(lái),任何一處協(xié)同工作用的服務(wù)器發(fā)生故障,事后都可以用任何一個(gè)鏡像出來(lái)的本地倉(cāng)庫(kù)恢復(fù)。
1)工作原理
當(dāng)我們通過(guò)git init創(chuàng)建或者git clone一個(gè)項(xiàng)目的時(shí)候,項(xiàng)目目錄會(huì)隱藏一個(gè).git子目錄,其作用是用來(lái)跟蹤管理版本庫(kù)的。
Git?中所有數(shù)據(jù)在存儲(chǔ)前都計(jì)算校驗(yàn)和,然后以校驗(yàn)和來(lái)引用,所以在我們修改或者刪除文件的時(shí)候,git能夠知道。Git用以計(jì)算校驗(yàn)和的機(jī)制叫做 SHA-1 散列(hash,哈希), 這是一個(gè)由 40 個(gè)十六進(jìn)制字符(0-9 和 a-f)組成字符串,基于 Git 中文件的內(nèi)容或目錄結(jié)構(gòu)計(jì)算出來(lái)。
通過(guò)git status進(jìn)行查詢,狀態(tài)情況如下:
a、已修改(modified):表示修改了文件,但還沒(méi)保存到數(shù)據(jù)庫(kù)中。
b、已暫存(staged):表示對(duì)一個(gè)已修改文件的當(dāng)前版本做了標(biāo)記,使之包含在下次提交的快照中。
c、已提交(committed):表示數(shù)據(jù)已經(jīng)安全的保存在本地?cái)?shù)據(jù)庫(kù)中。
文件狀態(tài)對(duì)應(yīng)的,不同狀態(tài)的文件在Git中處于不同的工作區(qū)域,主要分成了四部分:
a、工作區(qū):相當(dāng)于本地寫(xiě)代碼的區(qū)域,如 git clone 一個(gè)項(xiàng)目到本地,相當(dāng)于本地克隆了遠(yuǎn)程倉(cāng)庫(kù)項(xiàng)目的一個(gè)副本
b、暫存區(qū):暫存區(qū)是一個(gè)文件,保存了下次將提交的文件列表信息,一般在 Git 倉(cāng)庫(kù)目錄中
c、本地倉(cāng)庫(kù):提交更新,找到暫存區(qū)域的文件,將快照永久性存儲(chǔ)到 Git 本地倉(cāng)庫(kù)
d、遠(yuǎn)程倉(cāng)庫(kù):遠(yuǎn)程的倉(cāng)庫(kù),如 github、阿里code。

2)常見(jiàn)命令
git config --global user.name "xxx"?????? 配置用戶名
git config --global user.email "xxx@xxx.com"???? 配置郵件
git init [project-name]:創(chuàng)建或在當(dāng)前目錄初始化一個(gè)git代碼庫(kù)
git clone url:下載一個(gè)項(xiàng)目和它的整個(gè)代碼歷史
git add README 添加文件,添加至?xí)捍鎱^(qū)
git branch 查看本地所有分支
git status 查看當(dāng)前狀態(tài)
git commit 提交
git commit -am "init" 提交并且加注釋
git push origin master 將文件給推到服務(wù)器上
git checkout -b dev 建立一個(gè)新的本地分支dev
git checkout dev 切換到本地dev分支
git checkout --track origin/dev 切換到遠(yuǎn)程dev分支
git pull 本地與服務(wù)器端同步
git push (遠(yuǎn)程倉(cāng)庫(kù)名) (分支名) 將本地分支推送到服務(wù)器上去。
git fetch 相當(dāng)于是從遠(yuǎn)程獲取最新版本到本地,不會(huì)自動(dòng)merge
git status??? 查看當(dāng)前版本狀態(tài)(是否修改)?

4、Git中 fork, clone,branch的區(qū)別
1)fork
fork則可以代表分叉、克隆 出一個(gè)(倉(cāng)庫(kù)的)新拷貝。包含了原來(lái)的倉(cāng)庫(kù)(即upstream repository,上游倉(cāng)庫(kù))所有內(nèi)容,如分支、Tag、提交。如果想將你的修改合并到原項(xiàng)目中時(shí),可以通過(guò)的 Pull Request 把你的提交貢獻(xiàn)回原倉(cāng)庫(kù)。
當(dāng)你在github發(fā)現(xiàn)感興趣開(kāi)源項(xiàng)目的時(shí)候,可以通過(guò)點(diǎn)擊github倉(cāng)庫(kù)中右上角fork標(biāo)識(shí)的按鈕;
點(diǎn)擊這個(gè)操作后會(huì)將這個(gè)倉(cāng)庫(kù)的文件、提交歷史、issues和其余東西的倉(cāng)庫(kù)復(fù)制到自己的github倉(cāng)庫(kù)中,而你本地倉(cāng)庫(kù)是不會(huì)存在任何更改;
然后你就可以通過(guò)git clone對(duì)你這個(gè)復(fù)制的遠(yuǎn)程倉(cāng)庫(kù)進(jìn)行克隆;
后續(xù)更改任何東西都可以在本地完成,如git add、git commit一系列的操作,然后通過(guò)push命令推到自己的遠(yuǎn)程倉(cāng)庫(kù);
如果希望對(duì)方接受你的修改,可以通過(guò)發(fā)送pull requests給對(duì)方,如果對(duì)方接受。則會(huì)將你的修改內(nèi)容更新到倉(cāng)庫(kù)中;
2)clone
clone,譯為克隆,它的作用是將文件從遠(yuǎn)程代碼倉(cāng)下載到本地,從而形成一個(gè)本地代碼倉(cāng)。執(zhí)行clone命令后,會(huì)在當(dāng)前目錄下創(chuàng)建一個(gè)名為xxx的目錄,并在這個(gè)目錄下初始化一個(gè)?.git?文件夾,然后從中讀取最新版本的文件的拷貝。
3)branch
branch,譯為分支,其作用簡(jiǎn)單而言就是開(kāi)啟另一個(gè)分支, 使用分支意味著你可以把你的工作從開(kāi)發(fā)主線上分離開(kāi)來(lái),以免影響開(kāi)發(fā)主線。
通過(guò)git branch可以創(chuàng)建一個(gè)分支,但并不會(huì)自動(dòng)切換到新分支中去;
通過(guò)git checkout可以切換到另一個(gè)testing分支。
總結(jié)
fork 只能對(duì)代碼倉(cāng)進(jìn)行操作,且 fork 不屬于 git 的命令,通常用于代碼倉(cāng)托管平臺(tái)的一種“操作”;
clone 是 git 的一種命令,它的作用是將文件從遠(yuǎn)程代碼倉(cāng)下載到本地,從而形成一個(gè)本地代碼倉(cāng);
branch 特征與 fork 很類(lèi)似,fork 得到的是一個(gè)新的、自己的代碼倉(cāng),而 branch 得到的是一個(gè)代碼倉(cāng)的一個(gè)新分支。
5、git pull 和 git fetch 的理解
git fetch 命令用于從另一個(gè)存儲(chǔ)庫(kù)下載對(duì)象和引用;是將遠(yuǎn)程主機(jī)的最新內(nèi)容拉到本地,用戶在檢查了以后決定是否合并到工作本機(jī)分支中
git pull 命令用于從另一個(gè)存儲(chǔ)庫(kù)或本地分支獲取并集成(整合)。則是將遠(yuǎn)程主機(jī)的最新內(nèi)容拉下來(lái)后直接合并,即:git pull = git fetch + git merge,這樣可能會(huì)產(chǎn)生沖突,需要手動(dòng)解決。
6、git rebase 和 git merge的理解
當(dāng)完成一個(gè)特性的開(kāi)發(fā)并將其合并到?master?分支時(shí),會(huì)有兩種方式:git merge 和 git rebase。它們都是將一個(gè)分支的提交合并到另一分支上,但是在原理上卻不相同。
1)git merge XXX 將當(dāng)前分支合并到指定分支
例如:bugfix分支是從master分支分叉出來(lái)的,我們需要合并bugfix分支到master分支時(shí):

a、如果master分支的狀態(tài)沒(méi)有被更改過(guò),即?bugfix分支的歷史記錄包含master分支所有的歷史記錄。所以通過(guò)把master分支的位置移動(dòng)到bugfix的最新分支上,就完成合并。
b、如果master分支的歷史記錄在創(chuàng)建bugfix分支后又有新的提交。使用git merge的時(shí)候,會(huì)生成一個(gè)新的提交,并且master分支的HEAD會(huì)移動(dòng)到新的分支上。


總結(jié):git merge 會(huì)把兩個(gè)分支的最新快照以及二者最近的共同祖先進(jìn)行三方合并,合并的結(jié)果是生成一個(gè)新的快照(commit)。是一種非破壞性的操作,對(duì)現(xiàn)有分支不會(huì)以任何方式被更改,但是會(huì)導(dǎo)致歷史記錄相對(duì)復(fù)雜。
2)git rebase -i <commit>? 將當(dāng)前分支移植到指定分支或指定commit之上
常見(jiàn)的參數(shù)有--continue,git rebase --continue 用于解決沖突之后,繼續(xù)執(zhí)行rebase。
a、master分支的歷史記錄在創(chuàng)建bugfix分支后又有新的提交,通過(guò)git rebase,會(huì)bugfix分支生成的記錄加在主分支之后。


b、在移交過(guò)程中,如果發(fā)生沖突,需要修改各自的沖突。


總結(jié):git rebase 會(huì)找到不同的分支的最近共同祖先,如上圖的B。然后對(duì)比當(dāng)前分支相對(duì)于該祖先的歷次提交,提取相應(yīng)的修改并存為臨時(shí)文件X',Y'(老的提交X和Y也沒(méi)有被銷(xiāo)毀,只是簡(jiǎn)單地不能再被訪問(wèn)或者使用)。然后在當(dāng)前分支指向目標(biāo)最新位置D后,將之前另存為臨時(shí)文件的修改依序應(yīng)用。rebase會(huì)將整個(gè)分支移動(dòng)到另一個(gè)分支上,有效地整合了所有分支上的提交,好處是歷史記錄更加清晰,是在原有提交的基礎(chǔ)上將差異內(nèi)容反映進(jìn)去,消除了?git merge所需的不必要的合并提交。
7、git reset 和 git revert 的區(qū)別
git reset是直接刪除指定的commit,可以遺棄不再使用的提交,即HEAD向后移動(dòng);
git revert是用一次新的commit來(lái)回滾之前的commit,不會(huì)改變過(guò)去的歷史,主要是用于安全地取消過(guò)去發(fā)布的提交,即HEAD繼續(xù)前進(jìn)