天天看點

SVN與Git的差別以及日常使用SVN與Git比較的優缺點差異

目錄

SVN與Git比較的優缺點差異

 集中式vs分布式

常見操作

配置使用者資訊

分支的合并

場景:基于master分支的代碼,開發一個新的特性

合并分支時,如果存在分叉

解決合并時發生的沖突

日常操作積累

修改密碼(曲線救國)

修改已經push的某次commit的作者資訊

将 branch1的某個commit1合并到branch2當中

20190118-修改GitHub已送出的使用者名和郵箱

git用戶端推薦

推薦書籍

推薦連接配接

SVN與Git比較的優缺點差異

SVN與Git的差別以及日常使用SVN與Git比較的優缺點差異
SVN與Git的差別以及日常使用SVN與Git比較的優缺點差異

作者:Tse先生

出處:https://www.cnblogs.com/Sungeek/

一、 集中式vs分布式

1. Subversion屬于集中式的版本控制系統

集中式的版本控制系統都有一個單一的集中管理的伺服器,儲存所有檔案的修訂版本,而協同工作的人們都通過用戶端連到這台伺服器,取出最新的檔案或者送出更新。

SVN與Git的差別以及日常使用SVN與Git比較的優缺點差異

Subversion的特點概括起來主要由以下幾條:

  •  每個版本庫有唯一的URL(官方位址),每個使用者都從這個位址擷取代碼和資料;
  •  擷取代碼的更新,也隻能連接配接到這個唯一的版本庫,同步以取得最新資料;
  •  送出必須有網絡連接配接(非本地版本庫);
  •  送出需要授權,如果沒有寫權限,送出會失敗;
  •  送出并非每次都能夠成功。如果有其他人先于你送出,會提示“改動基于過時的版本,先更新再送出”… 諸如此類;
  •  沖突解決是一個送出速度的競賽:手快者,先送出,平安無事;手慢者,後送出,可能遇到麻煩的沖突解決。

好處:每個人都可以一定程度上看到項目中的其他人正在做些什麼。而管理者也可以輕松掌控每個開發者的權限。

缺點:中央伺服器的單點故障。

若是當機一小時,那麼在這一小時内,誰都無法送出更新、還原、對比等,也就無法協同工作。如果中央伺服器的磁盤發生故障,并且沒做過備份或者備份得不夠及時的話,還會有丢失資料的風險。最壞的情況是徹底丢失整個項目的所有曆史更改記錄,被用戶端提取出來的某些快照資料除外,但這樣的話依然是個問題,你不能保證所有的資料都已經有人提取出來。

Subversion原理上隻關心檔案内容的具體差異。每次記錄有哪些檔案作了更新,以及都更新了哪些行的什麼内容。

2. Git屬于分布式的版本控制系統

SVN與Git的差別以及日常使用SVN與Git比較的優缺點差異

Git記錄版本曆史隻關心檔案資料的整體是否發生變化。Git 不儲存檔案内容前後變化的差異資料。

實際上,Git 更像是把變化的檔案作快照後,記錄在一個微型的檔案系統中。每次送出更新時,它會縱覽一遍所有檔案的指紋資訊并對檔案作一快照,然後儲存一個指向這次快照的索引。為提高性能,若檔案沒有變化,Git 不會再次儲存,而隻對上次儲存的快照作一連接配接。

在分布式版本控制系統中,用戶端并不隻提取最新版本的檔案快照,而是把原始的代碼倉庫完整地鏡像下來。這麼一來,任何一處協同工作用的伺服器發生故障,事後都可以用任何一個鏡像出來的本地倉庫恢複。這類系統都可以指定和若幹不同的遠端代碼倉庫進行互動。籍此,你就可以在同一個項目中,分别和不同工作小組的人互相協作。你可以根據需要設定不同的協作流程。

另外,因為Git在本地磁盤上就儲存着所有有關目前項目的曆史更新,并且Git中的絕大多數操作都隻需要通路本地檔案和資源,不用連網,是以處理起來速度飛快。用SVN的話,沒有網絡或者斷開VPN你就無法做任何事情。但用Git的話,就算你在飛機或者火車上,都可以非常愉快地頻繁送出更新,等到了有網絡的時候再上傳到遠端的鏡像倉庫。換作其他版本控制系統,這麼做幾乎不可能,抑或是非常麻煩。

Git具有以下特點:

  • Git中每個克隆(clone)的版本庫都是平等的。你可以從任何一個版本庫的克隆來建立屬于你自己的版本庫,同時你的版本庫也可以作為源提供給他人,隻要你願意。
  • Git的每一次提取操作,實際上都是一次對代碼倉庫的完整備份。
  • 送出完全在本地完成,無須别人給你授權,你的版本庫你作主,并且送出總是會成功。
  • 甚至基于舊版本的改動也可以成功送出,送出會基于舊的版本建立一個新的分支。
  • Git的送出不會被打斷,直到你的工作完全滿意了,PUSH給他人或者他人PULL你的版本庫,合并會發生在PULL和PUSH過程中,不能自動解決的沖突會提示您手工完成。
  • 沖突解決不再像是SVN一樣的送出競賽,而是在需要的時候才進行合并和沖突解決。
  • Git 也可以模拟集中式的工作模式
  • Git版本庫統一放在伺服器中
  • 可以為 Git 版本庫進行授權:誰能建立版本庫,誰能向版本庫PUSH,誰能夠讀取(克隆)版本庫
  • 團隊的成員先将伺服器的版本庫克隆到本地;并經常的從伺服器的版本庫拉(PULL)最新的更新;
  • 團隊的成員将自己的改動推(PUSH)到伺服器的版本庫中,當其他人和版本庫同步(PULL)時,會自動擷取改變
  • Git 的集中式工作模式非常靈活
  • 你完全可以在脫離Git伺服器所在網絡的情況下,如移動辦公/出差時,照常使用代碼庫
  • 你隻需要在能夠接入Git伺服器所在網絡時,PULL和PUSH即可完成和伺服器同步以及送出
  • Git提供 rebase 指令,可以讓你的改動看起來是基于最新的代碼實作的改動
  • Git 有更多的工作模式可以選擇,遠非 Subversion可比

二、 版本庫與工作區

Subversion的工作區和版本庫是截然分開的,而Git的工作區和版本庫是如影随形的。

1. SVN的版本庫和工作區是分離的

• Subversion 的工作區和版本庫實體上分開:Subversion的版本庫和工作區是存儲在不同路徑下,一般是在不同的主機中,Subversion的企業級部署中,版本庫在伺服器上,隻能通過 https, http, svn 等協定通路,而不能直接被使用者接觸到。

• Subversion的工作區是一份版本庫在某個曆史狀态下的快照,如:版本庫最新的資料檢出到工作區。

• Subversion的工作區中每一個目錄下都包含一個名為 .svn 的控制目錄(隐藏的目錄),該目錄的作用是:

① 辨別工作區和版本庫的對應關系。

② 包含一份該子目錄下檢出檔案的原始拷貝。當檔案改動的差異比較或者本地改動的回退時,可以直接參考原始拷貝而無須通過網絡通路遠端版本庫。

• Subversion 的 .svn 控制目錄會引入很多麻煩:

① .svn 下的檔案原始考本,會導緻在目錄下按照檔案内容搜尋時,多出一倍的搜尋時間和搜尋結果。

② .svn 很容易在內建時,引入産品中,尤其是 Web 應用,将 .svn 目錄帶入Web伺服器會導緻安全隐患。因為一個不允許目錄浏覽的Web目錄,可以通過 .svn/entries 檔案檢視到該目錄下可能存在的檔案。

2 .Git 的版本庫和工作區如影随形

• Git 的版本庫和工作區在同一個目錄下,工作區的根目錄有一個.git的子目錄,這個名為 .git的目錄就是版本庫本身,它是Git 用來儲存中繼資料和對象資料庫的地方。該目錄非常重要,每次克隆鏡像倉庫的時候,實際拷貝的就是這個目錄裡面的資料。是以千萬要小心删除這個檔案。

• 工作區中其他檔案為工作區檔案,可能是從 .git 中檢出的,或者是要檢入的,或者是運作産生的臨時檔案等。

• 版本庫可以脫離工作區而存在,成為 bare(赤裸)版本庫。可以用 –bare 參數來建立。但是工作區不能脫離版本庫而存在,即工作區的根目錄下必須有一個名為 .git 的版本庫克隆檔案。

• Git 的版本庫因為就在工作區中,能直接被使用者接觸到。

① 使用者可以編輯 .git/config 檔案,修改配置,增添新的源

② 使用者可以編輯 .git/info/exclude 檔案,建立本地忽略…

• Git 的工作區中隻在工作區的根目錄下有一個 .git 目錄,此外再無任何控制目錄。Git 工作區下唯一的 .git 目錄是版本庫,并非 .svn 的等價物,如果删除了 .git 目錄,而又沒有該版本庫的其他鏡像(克隆)的話,你破壞了整個曆史,版本庫也永遠的失去了。

• Git 在本地的 .git 版本庫,提供了完全的改動曆史。除了和其他人資料交換外,任何版本庫相關的操作都在本地完成,更多的本地操作,避免了冗長的網絡延遲,大大節省了時間。例如:檢視 log,切換到任何曆史版本等操作都無須連接配接網絡。

• Git如何保證安全:本地建立一個Git庫,因為工作區和庫是在同一個目錄中,如果工作區删除了,或者所在的磁盤分區格式化了,資料不是全都沒有了麼?其實我們可以這樣做:

① 在一個磁盤分區中建立版本庫(最好是用 –bare 參數建立),然後在另外的磁盤分區中克隆一個新的作為工作區。在工作區的送出要不時的PUSH到另外分區的版本庫,這樣就實作了本地的資料鏡像。你甚至可以在本地建立更多的版本庫鏡像,安全性要比Subversion的一個庫加上一個工作區安全。

② 另一個辦法:把你的版本庫共享給他人,當他人克隆了你的版本庫時,你就擁有了一個異地備份。

三、 全局版本号和全球版本号

SVN的全局版本号和CVS的每個檔案都獨立維護一套版本号相比,是一個非常大的進步。在看似簡單的全局版本号的背後,是Subversion提供對于事物處理的支援,每一個事物處理(即一次送出)都具有整個版本庫全局唯一的版本号。

Git的版本号則更進一步,版本号是全球唯一的。Git 對于每一次送出,通過對檔案的内容或目錄的結構計算出一個SHA-1 哈希值,得到一個40位的十六進制字元串,Git将此字元串作為版本号。

1. SVN與Git版本号比較

• 所有儲存在Git 資料庫中的資料都是用此40位的哈希值作索引的,而不是靠檔案名。

• 使用哈希值作版本号的好處就是對于一個分布式的版本控制系統,每個人每次送出後形成的版本号都不會出現重複。另一好處是保證資料的完整性,因為哈希值是根據内容或目錄結構計算出來的,是以我們還可以據此來判斷資料内容是否被篡改。

• SVN 的版本号是連續的,可以預判下一個版本号,而 Git 的版本号則不是。

因為 subversion 是集中式版本控制,很容易實作版本号的連續性。Git 是分布式的版本控制系統,而且 Git 采用 40 位長的哈希值作為版本号,每個人的送出都是各自獨立完成的,沒有先後之分(即使送出有先後之分,也由于PUSH/PULL的方向和時機而不同)。Git 的版本号雖然不連續,但是是有線索的,即每一個版本都有對應的父版本(一個或者兩個),進而可以形成一個複雜的送出鍊

• Git 的版本号簡化:Git 可以使用從左面開始任意長度的字串作為簡化版本号,隻要該簡化的版本号不産生歧義。一般采用7位的短版本号(隻要不會出現重複的,你也可以使用更短的版本号)。

四、 部分檢出

Subversion可以将整個庫檢出到工作區,也可以将某個目錄檢出到工作區。對于要使用一個龐大、臃腫的版本庫的使用者來說,部分檢出是非常友善和實際的。

但是Git隻能全部檢出,不支援按照目錄進行的部分檢出。

1. SVN的部分檢出

• 在SVN中,從倉庫checkout的一個工作樹,每個子目錄下都維護着自己的.svn目錄,記錄着該目錄中檔案的修改情況以及和伺服器端倉庫的對應關系。是以SVN可以checkout部分路徑下的内容(部分檢出),而不用checkout整個版本庫或分支。

• Subversion 有一條指令:svn export ,可以将 subversion 版本庫的一個目錄下所有内容導出到指定的目錄下。Subversion 需要 svn export 指令是因為該指令可以導出一個幹淨的目錄,即不包含 .svn 目錄(包含配置檔案和檔案原始拷貝)。

2. Git的檢出

• Git 沒有部分檢出,這并不是說隻有将整個庫克隆下來才能檢視檔案。有很多 git 工具,提供直接浏覽git庫的功能,例如 gitweb, trac 的 git 版本庫浏覽, redmine 的 git 版本庫浏覽。

• Git-submodule 可以實作版本庫的子產品化:Git 通過子子產品處理這個問題。

子子產品允許你将一個Git 倉庫當作另外一個Git倉庫的子目錄。這允許你克隆另外一個倉庫到你的項目中并且保持你的送出相對獨立。

• Git 為什麼沒有實作 svn export 的功能?由于git的本地倉庫資訊完全維護在project根目錄的.git目錄下,(不像svn一樣,每個子目錄下都有單獨的.svn目錄)。是以,隻要clone,checkout然後删除.git目錄就可以了。

五、 更新和送出

1.更新操作

在SVN中,因為隻有一個中心倉庫,是以所謂的遠端更新,也就是svn update ,通過此指令來使工作區和版本庫保持同步。

對于git來說,别人的改動是存在于遠端倉庫上的,是以git checkout指令盡管在某些功能上和svn中的update類似(例如取倉庫特定版本的内容),但是在遠端更新這一點上,還是不同的,不屬于git checkout的功能涵蓋範圍。 Git使用git fetch和git pull來完成遠端更新任務,fetch操作隻是将遠端資料庫的object拷貝到本地,然後更新remotes head的refs,git pull 的操作則是在git fetch的基礎上對目前分支外加merge操作。

2.SVN中的commit指令

對于SVN來說,由于是中心式的倉庫管理形式,是以并不存在特殊的遠端送出的概念,所有的commit操作都可以認為是對遠端倉庫的更新動作。在工作區中對檔案進行添加、修改、删除操作要同步到版本庫,必須使用 commit指令。

• add 指令,是将未标記為版本控制狀态的檔案标記為添加狀态,并在下次送出時入庫。

• delete指令,是通過SVN來删除檔案,并在下次送出後有效。

• Subversion 有送出清單功能,即将某些檔案加入一個修改清單,送出可以隻送出處于該清單的檔案。

3.Git中的暫存區域(stage)

Git 管理項目時,檔案在三個工作區域中流轉:Git 的本地資料目錄,工作目錄以及暫存區域。暫存區域(stage)是介于 workcopy 和 版本庫  HEAD 版本的一種中間狀态。所謂的暫存區域隻不過是個簡單的檔案,一般都放在git 目錄中。有時候人們會把這個檔案叫做索引檔案,不過标準說法還是叫暫存區域。

要将一個檔案納入版本管理的範疇,首先是要用git  add将檔案納入stage的監控範圍,隻有更新到stage中的内容才會在commit的時候被送出。另外,檔案本身的改動并不會自動更新到stage中,每次的任何修改都必須重新更新到stage中去才會被送出。對于工作區直接删除的檔案,需要用 git rm 指令進行标記,在下次送出時,在版本庫中删除。

• 工作區的檔案改動(新增檔案,修改檔案,删除檔案),必須用 git add 或者 git rm 指令辨別,使得改動進入 stage

• 送出隻對加入 stage 的改動進行送出

• 如果一個檔案改動加入 stage 後再次改動,則後續改動不改變 stage。即該檔案的改動有兩個狀态,一個是标記到 stage 中并将在下次送出時入庫的改動,另外的後續改動則不被送出,除非再次使用 git add 指令将改動加入到 stage 中。

• Git的stag讓你在送出的時候清楚的知道git将要送出哪些改動。除非送出的時候使用 -a 參數(不建議使用)。

我們可以從檔案所處的位置來判斷其狀态:如果是git目錄中儲存着的特定版本檔案,就屬于已送出狀态;如果作了修改并已放入暫存區域,就屬于已暫存狀态;如果自上次取出後,作了修改但還沒有放到暫存區域,就是已修改狀态,如果取出後未進行修改則是未修改狀态。

在git中,因為有本地倉庫和remote倉庫之分,是以也就差別于commit 操作,存在額外的push指令,用于将本地倉庫的資料更新到遠端倉庫中去。git push 可以選擇需要送出的、更新的分支以及制定該分支在遠端倉庫上的名字。

六、 分支和裡程碑的實作

幾乎每一種版本控制系統都以某種形式支援分支。使用分支意味着你可以從開發主線上分離開來,然後在不影響主線的同時繼續工作。在很多版本控制系統中,這是個昂貴的過程,常常需要建立一個源代碼目錄的完整副本,對大型項目來說會花費很長時間。

輕量級分支/裡程碑的含義是,建立分支/裡程碑的複雜度是o(1),不會因為版本庫的愈加龐大而變得緩慢。在CVS中,建立分支的複雜度是o(n)的,導緻大的版本庫的的分支建立非常緩慢。

1.Subversion的分支/裡程碑

Subversion輕量級分支和裡程碑的實作是通過svn cp指令,即帶曆史的拷貝就是建立快速建立分支和裡程碑的秘籍。Subversion的版本庫有特殊的設計,當你複制一個目錄,你不需要擔心版本庫會變得十分巨大—Subversion并不是拷貝所有的資料,相反,它隻是建立了一個已存在目錄樹的入口。這種“廉價的拷貝”就是建立分支/裡程碑是輕量級的原因。

由于Svn的分支和标簽是來自目錄拷貝,約定俗成是拷貝在 branches/和tags/目錄下。所謂分支,tag等概念都隻是倉庫中不同路徑上的一個對象或索引而已,和普通的路徑并沒有什麼本質的差別,誰也不能阻止在一個送出中同時修改不同分支中的資料。

裡程碑是對某個曆史送出所起的一個别名,作為曆史的标記,是不應該被更改的。svn的裡程碑要建立到 tags/目錄下,要求不要在tags/下的裡程碑目錄下進行送出。但是誰也阻止不了對未進行權限控制的裡程碑的篡改。

2.Git 的輕量級分支和裡程碑

Git中的分支實際上僅是一個包含所指對象校驗和(40個字元長度SHA-1 哈希值)的檔案,是以建立和銷毀一個分支就變得非常廉價。說白了,建立一個分支就是向一個檔案寫入41個位元組(版本号外加一個換行符)那麼簡單,自然速度就很快了。 Git的實作與項目複雜度無關,它永遠可以在幾毫秒的時間内完成分支的建立和切換。這和大多數版本控制系統形成了鮮明對比。

Git的分支是完全隔離的,而Subversion則沒有。分支本來就應該是相對獨立的命名空間,一個送出一般隻能發生在一個分支中。在Git中,其内部的對象層級依賴關系或許和SVN類似,但是其工作樹的視圖表現形式和SVN完全不同。工作樹永遠是一個完整的分支,不同的分支由不同的head索引去建構,你不可能在工作樹中同時獲得多個分支的内容。

Git使用的标簽有兩種類型:輕量級的(lightweight)和含附注的(annotated)。① 輕量級标簽就像是個不會變化的分支,實際上它就是個指向特定送出對象的引用。② 而含附注标簽,實際上是存儲在倉庫中的一個獨立對象,它有自身的校驗和資訊,包含着标簽的名字,電子郵件位址和日期,以及标簽說明,标簽本身也允許使用GNU Privacy Guard (GPG) 來簽署或驗證。

Git的裡程碑是隻讀的,Git完全遵守曆史不可更改這一時空法則。使用者不能向git的裡程碑中送出,否則裡程碑就不是标記,而成了一個分支。當然Git允許使用者删除裡程碑再重新建立指定到不同曆史送出。

3.多分支間的切換

SVN中提供了一個功能switch,使用switch可以在同一個工作樹上,在不同的分支中進行切換。

Git在分支中進行切換使用的指令是checkout。

七、 分支與合并

Git 和 Svn 的分支實作機制完全的不同,這也直接導緻了 SVN 在分支合并中困難重重。盡管在 SVN 1.5 之後,通過 svn:mergeinfo 屬性引入了合并追蹤機制,但是在特定情況下,合并仍會出現很多困難。

1. SVN的分支合并

當你在一個分支上工作數周或幾個月之後,主幹的修改也同時在進行着,兩條線的開發會差別巨大,當你想合并分支回主幹,可能因為太多沖突,已經無法輕易合并你的分支和主幹的修改。

另一個問題,Subversion不會記錄任何合并操作,當你送出本地修改,版本庫并不能判斷出你是通過svn merge還是手工修改得到這些檔案。是以你必須手工記錄這些資訊(說明合并的特定版本号或是版本号的範圍)。

要解決以上的問題隻有通過有規律的将主幹合并到分支來避免,制定這樣一個政策:每周将上周的修改合并到分支,注意這樣做時需要小心,你必須手工記錄合并的過程,以避免重複的合并,你需要小心的撰寫合并的日志資訊,精确的描述合并包括的範圍。這樣做看起來有點像是脅迫。

SVN 的版本号是連續的版本号。每一次新的送出都會版本号+1 ,而無論這個送出是在哪個分支中進行的。SVN一個送出可以同時修改不同分支的不同檔案,因為送出指令可以在 /trunk, /branches, /tags 的上一級目錄執行。

• SVN 的送出是單線索的,每一個送出(最原始的送出0除外)都隻有一個父節點(版本号小一個的送出節點)

• SVN 的送出鍊隻有一條,僅從版本号和送出說明,我們無法獲得分支圖

• SVN 的分支圖在某些工具(如烏龜SVN)可以提供,那是需要對送出内容進行檢查,對目錄拷貝動作視為分支,對 svn:mergeinfo 的改動視為合并,但這會由于目錄管理的靈活性,導緻千奇百怪的分支圖表。

2.Git的分支合并

在 git 版本庫中建立分支的成本幾乎為零,是以,不必吝啬多建立幾個分支。當第一次執行git-init時,系統就會建立一個名為”master”的分支。 而其它分支則通過手工建立。下面列舉一些常見的分支政策。 

① 建立一個屬于自己的個人工作分支,以避免對主分支 master 造成太多的幹擾,也友善與他人交流協作。 

② 當進行高風險的工作時,建立一個試驗性的分支,扔掉一個爛攤子總比收拾一個爛攤子好得多。 

③ 合并别人修改的時候,最好建立一個臨時的分支用來合并,合并完成後再“fatch”到自己的分支。

Git分支相關的操作指令

八、 撤消操作

1.送出的撤銷

在Subversion中一旦完成向伺服器的資料送出,你就沒有辦法再從用戶端追回,隻能在後續的送出中修正(回退或者修改)等。因為Subversion作為集中式的版本控制,不能允許個人對已送出的資料進行篡改。Subversion具有一個非常重要的特性就是它的資訊從不丢失,即使當你删除了檔案或目錄,它也許從最新版本中消失了 ,但這個對象依然存在于曆史的早期版本中。

Git則不同,Git是分布式版本控制系統,代碼庫是屬于個人,允許任意修改。Git通過對送出建立數字摘要來保證送出的唯一性和不可更改性,通過版本庫在多人之間的多份拷貝來保障資料的安全性。Git可以丢棄最新的一個或幾個送出,使用 git reset –hard指令可以永遠丢棄最新的一個或者幾個送出。

2.送出說明的修改

送出後如果對送出說明不滿意,如何實作對送出說明的修改:

⑴ Git可以使用指令git commit –amend修改送出說明。

• Git可以修改最後一次送出說明,并不是說不能修改曆史版本的送出說明,隻是修改最後一個版本送出說明擁有最簡單的指令;

• Git修改送出說明,會改變送出的commit-id。即修改送出說明後,将産生一個新的送出;

• Git可以通過git reset –hard ,git commit –amend,git rebase onto 等指令來實作對曆史送出的修改;

• 使用stg工具可以更為簡單的修改曆史送出的送出說明,包括送出内容;

⑵ Subversion也可以修改送出說明,是通過修改送出的svn:log版本屬性實作的:

• 不但可以修改最後一次送出的說明,并且可以修改曆史送出的送出說明;

• Subversion修改送出說明是不可逆的操作,可能會造成說明被惡意修改;

• Subversion預設關閉修改送出說明的功能。管理者在設定了送出說明更改的郵件通知後,才可以打開該功能。

3.修改和重構曆史送出

Git可以修改和重構曆史送出:使用Git本身的reset以及 rebase 指令可以修改或者重整/重構曆史送出,非常靈活。使用強大的 stg 可以使得曆史送出的重構更為簡潔,如果您對 stg 或者 Hg/MQ 熟悉的話。

Subversion 修改曆史送出,隻能由管理者完成。

Subversion 是集中式版本控制系統,從用戶端一旦完成送出,就沒有辦法從用戶端撤銷送出。但是管理者可以在伺服器端完成送出的撤銷和修改,但是操作過程和代價較大。

九、 權限管理

Subversion通過對檔案目錄授權來實作權限管理,子目錄預設繼承父目錄的權限。但是也有缺憾,即權限不能在分支中繼承,不能對單個檔案授權。例如為 /trunk及其子目錄的授權,不能繼承到分支或者标簽中相應的目錄下。

Git 的授權做不到Subversion那樣精細。Git的授權模型隻能實作非零即壹式的授權,要麼擁有全部的寫權限,要麼沒有寫權限,要麼擁有整個版本庫的讀權限,要麼禁用。

從技術上将,Git可能永遠也做不到類似SVN的路徑授權(讀授權):

• 如果允許按照路徑授權,則各個克隆的關系将不再是平等的關系,有的内容多,有的内容少,分布式的理念被破壞

• 如果隻有部分路徑可讀,則克隆出來的送出和原始送出的送出ID可能不同。因為送出ID是和送出内容有關的,克隆中送出的部分内容被丢棄,勢必送出的ID也要重新計算

• 允許全部代碼可讀,隻允許部分代碼可寫,在版本控制的管理下,是沒有多大實際意義的,而且導緻了送出的邏輯上的不完整。

那麼有什麼辦法來解決授權的問題?

1. 公司内部代碼開放。即代碼在公司内部,對項目組成員一視同仁的開放。

2. 公司對代碼庫進行合理分解,對每個代碼庫分别授權。即某個代碼庫對團隊成員完全開放,對其它團隊完全封閉。

3. 公司使用Subversion做集中式的版本控制,個人和/或團隊使用 Git-svn。這樣在無法改變公司版本控制政策時,程式員可以采用的變通之法。

4. Git伺服器的部署實際上可以使用鈎子對分支和路徑進行寫授權,即可以控制誰能夠建立分支,能夠寫特定檔案。

十、優缺點比較

1.SVN優缺點

優點: 

1、 管理友善,邏輯明确,符合一般人思維習慣。 

2、 易于管理,集中式伺服器更能保證安全性。 

3、 代碼一緻性非常高。 

4、 适合開發人數不多的項目開發。 

缺點: 

1、 伺服器壓力太大,資料庫容量暴增。 

2、 如果不能連接配接到伺服器上,基本上不可以工作,看上面第二步,如果伺服器不能連接配接上,就不能送出,還原,對比等等。 

3、 不适合開源開發(開發人數非常非常多,但是Google app engine就是用svn的)。但是一般集中式管理的有非常明确的權限管理機制(例如分支通路限制),可以實作分層管理,進而很好的解決開發人數衆多的問題。

2.Git優缺點

優點: 

1、适合分布式開發,強調個體。 

2、公共伺服器壓力和資料量都不會太大。 

3、速度快、靈活。 

4、任意兩個開發者之間可以很容易的解決沖突。 

5、離線工作。 

缺點: 

1、學習周期相對而言比較長。 

2、不符合正常思維。 

3、代碼保密性差,一旦開發者把整個庫克隆下來就可以完全公開所有代碼和版本資訊。

常見操作

配置使用者資訊

git config --global user.name "smyhvae"

git config --global user.email "[email protected]"
           

分支的合并

場景:基于master分支的代碼,開發一個新的特性

如果你直接在master分支上開發這個新特性,是不好的,萬一你在開發

特性1

的時候,上司突然又要叫你去開發

特性2

,就不好處理了。難道開發的兩個特性都送出到master?一會兒送出特性1的commit,一會兒送出特性2的commit?這會導緻commit記錄很混亂。

是以,我給你的建議做法是:給每個特性都單獨建一個的新的分支。

比如說,我專門給

特性1

建一個分支

feature_item_recommend

。具體做法如下:

(1)基于master分支,建立一個新的分支,起名為

feature_item_recommend

$ git checkout -b feature_item_recommend

Switched to a new branch 'feature_item_recommend'
           

上面這行指令,相當于:

$ git branch feature_item_recommend    // 建立新的分支

$ git checkout feature_item_recommend  //切換到新的分支
           

(2)在新的分支

feature_item_recommend

上,完成開發工作,并 commit 、push。

(3)将分支

feature_item_recommend

上的開發進度合并到master分支:

$ git checkout master  //切換到master分支

$ git merge feature_item_recommend    //将分支 feature_item_recommend 的開發進度合并到 master 分支

           

合并之後,

master

分支和

feature_item_recommend

分支會指向同一個位置。

(3)删除分支

feature_item_recommend

既然 特性1 開發完了,也放心地送出到master了,那我們就可以将這個分支删除了。
git branch -d feature_item_recommend
           

注意,我們目前是處于

master

分支的位置,來删除

feature_item_recommend

分支。如果目前是處于

feature_item_recommend

分支,是沒辦法删除它自己的。

同理,當我轉身去開發

特性2

的時候,也是采用同樣的步驟。

合并分支時,如果存在分叉

SVN與Git的差別以及日常使用SVN與Git比較的優缺點差異

比如說上面這張圖中,最早的時候,master分支是位于

C2

節點。我基于

C2

節點,new出一個新的分支

iss53

,我在

iss53

上送出了好幾個commit。

現在,我準備把

iss53

上的幾個commit合并到master上,此時發現,master分支已經前進到C4了。那該怎麼合并呢?

合并的指令仍然是:

$ git checkout master

$ git merge iss53
           

解釋:

這次合并的實作,并不同于簡單的并入方式。這一次,我的開發曆史是從更早的地方開始分叉的。

由于目前 master 分支所指向的commit (C4)并非想要并入分支(iss53)的直接祖先,Git 不得不進行一些處理。就此例而言,Git 會用兩個分支的末端(C4 和C5)和它們的共同祖先(C2)進行一次簡單的三方合并計算。

Git 沒有簡單地把分支指針右移,而是對三方合并的結果作一新的快照,并自動建立一個指向它的commit(C6)(如下圖所示)。我們把這個特殊的commit 稱作合并送出(mergecommit),因為它的祖先不止一個。

值得一提的是Git 可以自己裁決哪個共同祖先才是最佳合并基礎;這和CVS 或Subversion(1.5 以後的版本)不同,它們需要開發者手工指定合并基礎。是以此特性讓Git 的合并操作比其他系統都要簡單不少。

SVN與Git的差別以及日常使用SVN與Git比較的優缺點差異

解決合并時發生的沖突

SVN與Git的差別以及日常使用SVN與Git比較的優缺點差異

如果 feature1和feature2修改的是同一個檔案中代碼的同一個位置,那麼,把feature1合并到feature2時,就會産生沖突。這個沖突需要人工解決。步驟如下:

(1)手動修改檔案:手動修改沖突的那個檔案,決定到底要用哪個分支的代碼。

(2)git add:解決好沖突後,輸入

git status

,會提示

Unmerged paths

。這個時候,輸入

git add

即可,表示:修改沖突成功,加入暫存區。

(3)git commit 送出。

然後,我們可以繼續把 feature1 分支合并到 master分支,最後删除feature1、feature2。

注意:兩個分支的同一個檔案的不同地方合并時,git會自動合并,不會産生沖突。

比如分支feture1對index.html原來的第二行之前加入了一段代碼。 分支feature2對index.html在原來的最後一行的後面加入了一段代碼。 這個時候在對兩個分支合并,git不會産生沖突,因為兩個分支是修改同一檔案的不同位置。 git自動合并成功。不管是git自動合并成功,還是在人工解決沖突下合并成功,送出之前,都要對代碼進行測試。

日常操作積累

修改密碼(曲線救國)

網上查了很久,沒找到答案。最終,在cld童鞋的提示下,采取如下方式進行曲線救國。
# 設定目前倉庫的使用者名為空
git config  user.name ""
           

然後,當我們再輸入

git pull

等指令行時,就會被要求重新輸入新的賬号密碼。此時,密碼就可以修改成功了。最後,我們還要輸入如下指令,還原目前倉庫的使用者名:

git config user.name "smyhvae"
           

修改已經push的某次commit的作者資訊

已經push的記錄,如果要修改作者資訊的話,隻能 通過--force指令。我反正是查了很久,但最終還是不敢用公司的倉庫嘗試。

參考連結:

  • git 修改已送出的某一次的郵箱和使用者資訊

看最後一條答案。

  • 修改 git repo 曆史送出的 author

将 

branch1

的某個

commit1

合并到

branch2

當中

切換到branch2中,然後執行如下指令:

git cherry-pick commit1
           

20190118-修改GitHub已送出的使用者名和郵箱

參考連結:(親測有效)

  • 修改Git全部Commit送出記錄的使用者名Name和郵箱Email
  • Mac 運作sh檔案,也就是傳說中的shell腳本

git用戶端推薦

20180623時,網上看了下Git用戶端的推薦排名:

SVN與Git的差別以及日常使用SVN與Git比較的優缺點差異

上面的Git用戶端我基本都用過了,我最推薦的一款Git用戶端是:Tower。

SmartGit:

商業用途收費, 個人使用者免費:

SVN與Git的差別以及日常使用SVN與Git比較的優缺點差異

推薦書籍

  • 《pro.git中文版》

推薦連接配接

2018-06

  • 聊下git pull --rebase

繼續閱讀