svn,git的對比以及常用命令

robert_chao發表於2016-06-02

之前定製Rom,需要下載android原始碼,修改系統應用。android原始碼管理使用repo+git,下載速度快的嚇人。(直接下載的話,被牆了當然慢,請忽略這個因素)。感覺git更適合大型專案管理。專案經驗不是非常多,個人無論大小專案,自己選擇的話還是喜歡用git。

個人總結的git優點

1、分支管理非常方便

2、回退,檢視歷史更加方便,支援命令更多

3、速度更快

4、可以離線提交到本地庫,可以離線檢視log

5....

下面參照大牛的介紹,來具體看一下git和svn的不同

參考http://stackoverflow.com/questions/871/why-is-git-better-than-subversion

http://stackoverflow.com/questions/964331/git-file-integrity

GIT是分散式的,SVN不是

這是GIT和其它非分散式的版本控制系統,例如SVN,CVS等,最核心的區別。GIT並不是目前第一個或唯一的分散式版本控制系統。還有一些系統,例如Bitkeeper , Mercurial 等,也是執行在分散式模式上的。但GIT在這方面做的更好,而且有更多強大的功能特徵。
GIT跟SVN一樣有自己的集中式版本庫或伺服器。但,GIT更傾向於被使用於分散式模式,也就是每個開發人員從中心版本庫/伺服器上chect out程式碼後會在自己的機器上克隆一個自己的版本庫。,如果被困在一個不能連線網路的地方時,就像在飛機上,地下室,電梯裡等,你仍然能夠提交檔案,檢視歷史版本記錄,建立專案分支,等。對一些人來說,這好像沒多大用處,但當突然遇到沒有網路的環境時,這個將解決大麻煩。
同樣,這種分散式的操作模式對於開源軟體社群的開發來說也是個巨大的恩賜,不必再像以前那樣做出補丁包,通過email方式傳送出去,你只需要建立一個分支,向專案團隊傳送一個推請求。這能讓程式碼保持最新,而且不會在傳輸過程中丟失。GitHub.com 就是一個這樣的優秀案例。
有些謠言傳出來說subversion將來的版本也會基於分散式模式。但至少目前還看不出來。

GIT把內容按後設資料方式儲存,而SVN是按檔案

所有的資源控制系統都是把檔案的元資訊隱藏在一個類似.svn,.cvs等的資料夾裡。如果把.git目錄的體積大小跟.svn比較,會發現它 們差距很大。因為,.git目錄是處於機器上的一個克隆版的版本庫,它擁有中心版本庫上所有的東西,例如標籤,分支,版本記錄等。

GIT分支和SVN的分支不同

分支在SVN中一點不特別,就是版本庫中的另外的一個目錄。如果想知道是否合併了一個分支,需要手工執行像這樣的命令svn propget svn:mergeinfo ,來確認程式碼是否被合併。所以,經常會發生有些分支被遺漏的情況。
然而,處理GIT的分支卻是相當的簡單和有趣。可以從同一個工作目錄下快速的在幾個分支間切換。很容易發現未被合併的分支,能簡單而快捷的合併這些檔案。

GIT沒有一個全域性的版本號,而SVN有

目前為止這是跟SVN相比GIT缺少的最大的一個特徵。SVN的版本號實際是任何一個相應時間的原始碼快照。
但是我們可以使用GIT的SHA-1來唯一的標識一個程式碼快照。這個並不能完全的代替SVN裡容易閱讀的數字版本號。但,用途應該是相同的。

GIT的內容完整性要優於SVN

GIT的內容儲存使用的是SHA-1 雜湊演算法。這能確保程式碼內容的完整性,確保在遇到磁碟故障和網路問題時降低對版本庫的破壞。

以下是svn客戶端常用命令一覽:

檢視最近3個版本日誌
svn log [PATH] -v -l3
log訊息程式碼 A :added  D:deleted  M:modified  R:replaced

檢視某兩個版本,用來對比
svn log -r 14:15

新增檔案或目錄到你的wc,打上新增標記。這些檔案會在下一次你提交wc的時候提交到svn伺服器。
在提交前,你也可以用svn revert撤銷新增的檔案。
svn add file.java

取消提交
svn revert --recursive file.java

顯示某個已受控檔案的每一行的最後修改版本和作者
svn blame file.java

輸出指定目標的內容,這裡的目標一般是檔案。
svn cat file.java 顯示file.java內容。
svn cat file.java -r 2 ##顯示版本號為二的file.java內容。
svn cat file.java --revision HEAD ##顯示最新版本的file.java內容。

將wc中的檔案從邏輯上分組.
svn changelist CLNAME TARGET...
svn changelist --remove TARGET
別名:cl
svn cl clName file.java file2.java file3.java  ##將file.java等三個檔案加入名叫clName的changelist 
svn commit --changelist clName -m "ci"  ##將clName下的所有檔案提交

檢出
svn checkout URL[@REV]... [PATH]
別名:co
svn checkout file:///var/svn/repos/test  file:///var/svn/repos/quiz working-copies
svn checkout -r 2 file:///var/svn/repos/test mine  ##check out 版本號為2的專案

遞迴的清理WC中過期的鎖和未完成的操作
svn cleanup

把你WC的更改提交到倉庫
svn commit [PATH...]
別名:ci
svn commit -m "added howto section." ##預設情況下提交必須提供log message 

javaopy操作可以從WC到WC;WC到URL;URL到WC;URL到URL。現在SVN只支援同一個倉庫內檔案的拷貝,不允許跨倉庫操作。
svn copy SRC[@REV]... DST
別名:cp
svn copy -r 11 file:///var/svn/repos/test/trunk \
           file:///var/svn/repos/test/tags/0.6.32-prerelease \
           -m "Forgot to tag at rev 11"
##copy命令是建立分支和標記的常用方式。copy到url的操作隱含了提交動作,所以需要提供log messages。

刪除
svn delete PATH...
別名:del,remove,rm
訪問庫:如果PATH是庫地址時會,刪除WC內的檔案不會。
svn del localfile.java    ##刪除WC裡的檔案,在下一次提交WC的時候才會真正在倉庫裡將對應檔案刪除。
svn del file:///var/svn/repos/test/yourfile  ##刪除倉庫裡的檔案

比較並顯示修改點
svn diff
別名:di
svn diff   ##最常用的方式,用來顯示WC基於最近一次更新以後的所有的本地修改點。
svn diff -r 301 bin ## 比較WC和版本301中的bin目錄的修改點
svn diff -r 3000:3500 file:///var/svn/repos/myProject/trunk   ##比較庫裡主幹3000版和3500版的差異。
svn diff --summarize --xml http://svn.red-bean.javaom/repos/test@r2 http://svn.red-bean.javaom/repos/test  ##--summarize --xml 引數將差異情況以xml文件的方式顯示出來。

匯出一個乾淨的目錄樹,不包含所有的受控資訊。可以選擇從URL或WC中匯出。
svn export [-r REV] URL[@PEGREV] [PATH]
svn export [-r REV] PATH1[@PEGREV] [PATH2]
訪問庫:如果訪問的是URL則會。
svn export file:///var/svn/repos my-export   ##匯出到my-export目錄。

檢視幫助文件
svn help 
訪問庫:否。

匯入本地一個目錄到庫中。但是匯入後,本地的目錄並不會處於受控狀態。
svn import [PATH] URL
別名:無
訪問庫:是。
svn import -m "New import" myproj http://svn.myProject.javaom/repos/trunk/misc

顯示指定WC和URL資訊。
svn info [TARGET[@REV]...]
別名:無
訪問庫:僅當訪問的是庫路徑時。
svn info --xml http://svn.myProject.javaom/repos/test  ##將資訊以xml格式顯示。

顯示目標下的檔案和目錄列表。
svn list [TARGET[@REV]...]
別名:ls
訪問庫:如果訪問的是庫地址就會。
svn list --verbose file:///var/svn/repos   ##--verbose參數列示顯示詳細資訊。

對目標獲得修改鎖。如果目標已被其他使用者鎖定,則會丟擲警告資訊。用--force引數強制從其他使用者那裡獲得鎖。
svn lock TARGET...
別名:無
訪問庫:是
svn lock --force tree.jpg

合併兩個受控源的不同之處,存放到一個WC裡。
svn merge sourceURL1[@N] sourceURL2[@M] [WCPATH]
svn merge sourceWCPATH1@N sourceWCPATH2@M [WCPATH]
svn merge [[-c M]... | [-r N:M]...] [SOURCE[@REV] [WCPATH]]
訪問庫:只有當訪問庫地址時。
svn merge --reintegrate http://svn.example.javaom/repos/calc/branches/my-calc-branch  ##合併分支上的改變項到WC,往往用於分支合併到主幹。
svn merge -r 156:157 http://svn.example.javaom/repos/calc/branches/my-calc-branch   ##將制定URL版本156到157的所有更新合併到WC。

在WC或庫路徑建立目錄
svn mkdir PATH...
svn mkdir URL...
訪問庫:只有當訪問庫地址時。
svn mkdir newdir
 
svn move SRC... DST
別名:mv, rename, ren
描述:等同於svn copy命令跟個svn delete命令。WC到URL的重新命名是不被允許的。
訪問庫:只有當訪問庫地址時。
svn move foo.java bar.java  ##將foo.java改名成bar.java。
 
svn propdel PROPNAME [PATH...]
svn propdel PROPNAME --revprop -r REV [TARGET]
別名:pdel, pd
描述:從受控檔案,目錄等刪除屬性。第二種是刪除某個指定版本上的附加屬性。
訪問庫:只有當訪問庫地址時。
svn propdel svn:mime-type someFile    ##從someFile上移除svn:mime-type這個屬性。
 
svn propedit PROPNAME TARGET...
svn propedit PROPNAME --revprop -r REV [TARGET]
別名:pedit, pe
描述:編輯屬性
訪問庫:只有當訪問庫地址時。
svn propedit svn:keywords  file.java  ##修改file.java上的svn:keywords屬性。
 
svn propget PROPNAME [TARGET[@REV]...]
svn propget PROPNAME --revprop -r REV [URL]
別名:pget,pg
描述:從檔案,目錄或版本取得指定屬性的值。
訪問庫:只有當訪問庫地址時。
svn propget svn:keywords file.java   ##從file.java中取得svn:keywords屬性的值
 
svn proplist [TARGET[@REV]...]
svn proplist --revprop -r REV [TARGET]
別名:plist, pl
描述:列出檔案、目錄或版本上的所有附加屬性
訪問庫:只有當訪問庫地址時。
svn proplist --verbose file.java
 
svn propset PROPNAME [PROPVAL | -F VALFILE] PATH...
svn propset PROPNAME --revprop -r REV [PROPVAL | -F VALFILE] [TARGET]
別名:pset,ps
描述:給檔案、目錄或版本附加屬性並賦值
訪問庫:只有當訪問庫地址時。
svn propset svn:mime-type image/jpeg file.jpg   ##給file.jpg附加屬性svn:mime-type 其值為image/jpeg
svn propset --revprop -r 25 svn:log "Journaled about trip to New York."
##給版本25補上log message
svn propset svn:ignore '.javalasspath' . 
##在本地忽略掉.javalasspath檔案
 
svn resolve PATH...
別名:無
描述:將衝突的檔案標記為已解決,並且刪掉衝突產生的臨時檔案。注意這個命令並不是能把衝突解決,解決衝突還是得靠人工。
訪問庫:否
svn resolve --accept mine-full foo.java   ##1.5版本後,加上--accept引數,嘗試自動處理衝突。
 
svn resolved PATH...
別名:無
描述:已過時,被resolve --accept取代。去除衝突的狀態和衝突臨時檔案。
訪問庫:否
 
svn revert PATH...
別名:無
描述:還原WC中所有的本地更改。
訪問庫:否
svn revert --depth=infinity .   ##將整個目錄所有檔案還原
 
svn status [PATH...]
別名:stat, st
描述:輸出WC中檔案和目錄的狀態。如果WC提交,這些狀態就會同步到庫裡。
一般狀態有         ' '  沒有修改
'A'  新增
'D'  刪除
'M'  修改
'R'  替代
'C'  衝突
'I'  忽略
'?'  未受控
'!'  丟失,一般是將受控檔案直接刪除導致
訪問庫:加上--show-updates引數時會
svn status wc
 
svn switch URL[@PEGREV] [PATH]
svn switch --relocate FROM TO [PATH...]
別名:sw
描述:將WC轉向一個其他的庫地址同步
訪問庫:是
svn sw http://svn.myProject.javaom/repos/trunk/vendors .  ##將當前WC切換到另一個URL
 
svn unlock TARGET...
別名:無
描述:解鎖
訪問庫:是
svn unlock somefile
 
svn update [PATH...]
別名:up
描述:更新WC,更新反饋有如下幾種分類。
A  新增
B  鎖破壞
D  刪除
U  更新
C  衝突
G  合併
E  存在的
訪問庫:是
svn up -r22   ##更新到一個指定版本

建立分支
svn cp -m "create branch" http://svn_server/xxx_repository/trunk http://svn_server/xxx_repository/branches/br_feature001

獲得分支
svn co http://svn_server/xxx_repository/branches/br_feature001

合併主幹上的最新程式碼到分支上
cd br_feature001
svn merge http://svn_server/xxx_repository/trunk
如果需要預覽該重新整理操作,可以使用svn mergeinfo命令,如:
svn mergeinfo http://svn_server/xxx_repository/trunk --show-revs eligible
或使用svn merge --dry-run選項以獲取更為詳盡的資訊。

分支合併到主幹
一旦分支上的開發結束,分支上的程式碼需要合併到主幹。SVN中執行該操作需要在trunk的工作目錄下進行。命令如下:
cd trunk
svn merge --reintegrate http://svn_server/xxx_repository/branches/br_feature001
分支合併到主幹中完成後應當刪該分支,因為在SVN中該分支已經不能進行重新整理也不能合併到主幹。

合併版本並將合併後的結果應用到現有的分支上
svn -r 148:149 merge http://svn_server/xxx_repository/trunk

建立tags
產品開發已經基本完成,並且通過很嚴格的測試,這時候我們就想釋出給客戶使用,釋出我們的1.0版本
svn copy http://svn_server/xxx_repository/trunk http://svn_server/xxx_repository/tags/release-1.0 -m "1.0 released"

刪除分支或tags
svn rm http://svn_server/xxx_repository/branches/br_feature001
svn rm http://svn_server/xxx_repository/tags/release-1.0



一、 Git 命令初識

在正式介紹Git命令之前,先介紹一下Git 的基本命令和操作,對Git命令有一個總體的認識
示例:從Git 版本庫的初始化,通常有兩種方式:
1、git clone:這是一種較為簡單的初始化方式,當你已經有一個遠端的Git版本庫,只需要在本地克隆一份
例如:git clone https://github.com/robertjc/simplealgorithm.git
上面的命令就是將'https://github.com/robertjc/simplealgorithm.git'這個URL地址的遠端版本庫,完全克隆到本地。
2、git init 和 git remote:這種方式稍微複雜一些,當本地建立了一個工作目錄,可以進入這個目錄,使用'git init'命令進行初始化;Git以後就會對該目錄下的檔案進行版本控制,這時候如果需要將它放到遠端伺服器上,可以在遠端伺服器上建立一個目錄,並把可訪問的URL記錄下來,此時你就可以利用'git remote add'命令來增加一個遠端伺服器端,
例如:git remote add orign git://github.com/someone/another_project.git
上面的命令就會增加URL地址為'git: //github.com/someone/another_project.git',名稱為origin的遠端伺服器,以後提交程式碼的時候只需要使用 origin別名即可

二、 Git 常用命令

1、遠端倉庫相關命令

檢出倉庫: $ git clone https://github.com/robertjc/simplealgorithm.git
檢視遠端倉庫:$ git remote -v
新增遠端倉庫:$ git remote add [name] [url]
刪除遠端倉庫:$ git remote rm [name]
修改遠端倉庫:$ git remote set-url --push [name] [newUrl]
拉取遠端倉庫:$ git pull [remoteName] [localBranchName]
推送遠端倉庫:$ git push [remoteName] [localBranchName]
*如果想把本地的某個分支test提交到遠端倉庫,並作為遠端倉庫的master分支,或者作為另外一個名叫test的分支,如下:
$git push origin test:master // 提交本地test分支作為遠端的master分支
$git push origin test:test // 提交本地test分支作為遠端的test分支

2、分支(branch)操作相關命令

檢視本地分支:$ git branch
檢視遠端分支:$ git branch -r
建立本地分支:$ git branch [name] ----注意新分支建立後不會自動切換為當前分支
切換分支:$ git checkout [name]
建立新分支並立即切換到新分支:$ git checkout -b [name]
刪除分支:$ git branch -d [name] ---- -d選項只能刪除已經參與了合併的分支,對於未有合併的分支是無法刪除的。如果想強制刪除一個分支,可以使用-D選項
合併分支:$ git merge [name] ----將名稱為[name]的分支與當前分支合併
建立遠端分支(本地分支push到遠端):$ git push origin [name]
刪除遠端分支:$ git push origin :heads/[name] 或 $ gitpush origin :[name]
*建立空的分支:(執行命令之前記得先提交你當前分支的修改,否則會被強制刪乾淨沒得後悔)
$git symbolic-ref HEAD refs/heads/[name]
$rm .git/index
$git clean -fdx

3、版本(tag)操作相關命令

檢視版本:$ git tag
建立版本:$ git tag [name]
刪除版本:$ git tag -d [name]
檢視遠端版本:$ git tag -r
建立遠端版本(本地版本push到遠端):$ git push origin [name]
刪除遠端版本:$ git push origin :refs/tags/[name]
合併遠端倉庫的tag到本地:$ git pull origin --tags
上傳本地tag到遠端倉庫:$ git push origin --tags
建立帶註釋的tag:$ git tag -a [name] -m 'yourMessage'

4、子模組(submodule)相關操作命令

新增子模組:$ git submodule add [url] [path]
如:$git submodule add git://github.com/robertjc/project.git src/main/src/com/robert
初始化子模組:$ git submodule init ----只在首次檢出倉庫時執行一次就行
更新子模組:$ git submodule update ----每次更新或切換分支後都需要執行一下
刪除子模組:(分4步走哦)
1) $ git rm --cached [path]
2) 編輯“.gitmodules”檔案,將子模組的相關配置節點刪除掉
3) 編輯“ .git/config”檔案,將子模組的相關配置節點刪除掉
4) 手動刪除子模組殘留的目錄

5、忽略一些檔案、資料夾不提交

在倉庫根目錄下建立名稱為“.gitignore”的檔案,寫入不需要的資料夾名或檔案,每個元素佔一行即可,如
target
bin
*.db

三、 Git 命令詳解

現在我們有了本地和遠端的版本庫,讓我們來試著用用Git的基本命令:
git pull:從其他的版本庫(既可以是遠端的也可以是本地的)將程式碼更新到本地,例如:'git pull origin master'就是將origin這個版本庫的程式碼更新到本地的master主枝,該功能類似於SVN的update
git add:是將當前更改或者新增的檔案加入到Git的索引中,加入到Git的索引中就表示記入了版本歷史中,這也是提交之前所需要執行的一步,例如'git add app/model/user.rb'就會增加app/model/user.rb檔案到Git的索引中,該功能類似於SVN的add
git rm:從當前的工作空間中和索引中刪除檔案,例如'git rm app/model/user.rb',該功能類似於SVN的rm、del
git commit:提交當前工作空間的修改內容,類似於SVN的commit命令,例如'git commit -m story #3, add user model',提交的時候必須用-m來輸入一條提交資訊,該功能類似於SVN的commit
git push:將本地commit的程式碼更新到遠端版本庫中,例如'git push origin'就會將本地的程式碼更新到名為orgin的遠端版本庫中
git log:檢視歷史日誌,該功能類似於SVN的log
git revert:還原一個版本的修改,必須提供一個具體的Git版本號,例如'git revert ccaf6fb6060b4875b18ff9ff637ce118256d6f20',Git的版本號都是生成的一個雜湊值
上面的命令幾乎都是每個版本控制工具所公有的,下面就開始嘗試一下Git獨有的一些命令:
git branch:對分支的增、刪、查等操作,例如'git branch new_branch'會從當前的工作版本建立一個叫做new_branch的新分支,'git branch -D new_branch'就會強制刪除叫做new_branch的分支,'git branch'就會列出本地所有的分支
git checkout:Git的checkout有兩個作用,其一是在不同的branch之間進行切換,例如'git checkout new_branch'就會切換到new_branch的分支上去;另一個功能是還原始碼的作用,例如'git checkout app/readme.txt'就會將readme.txt檔案從上一個已提交的版本中更新回來,未提交的內容全部會回滾
git rebase:通常用於在向別處推送提交之前對它們進行重寫。互動式rebase提供了一個簡單易用的途徑讓你在和別人分享提交之前對你的提交進行分割、合併或者重排序。在把從其他開發者處拉取的提交應用到本地時,也可以使用互動式rebase對它們進行清理
git reset:將當前的工作目錄完全回滾到指定的版本號
git stash:將當前未提交的工作存入Git工作棧中
git config:利用這個命令可以新增、更改Git的各種設定
git config --global user.name "robert"  
git config --global user.email 805467553@qq.com
https方式每次都要輸入密碼,按照如下設定即可輸入一次就不用再手輸入密碼的困擾而且又享受https帶來的極速
設定記住密碼(預設15分鐘):
git config --global credential.helper cache
如果想自己設定時間,可以這樣做:
git config credential.helper 'cache --timeout=3600'
這樣就設定一個小時之後失效
長期儲存密碼:
git config --global credential.helper store
git tag:可以將某個具體的版本打上一個標籤,這樣就不需要記憶複雜的版本號雜湊值了

四、git的Patch功能

git提供了兩種簡單的patch方案。一是用git diff生成的標準patch,二是git format-patch生成的Git專用Patch。

1.git diff生成的標準patch

新建fix分支,並切換到該分支
git branch Fix
git checkout Fix
修改完成之後,打補丁
git diff master > patch
git checkout master
我們現在有一個patch檔案,並且簽出了master,接下來我們可以使用git apply來應用這個patch。當然了,實際應用中,我們不會這樣在一個分支建patch,到另一個分支去應用,因為只有merge一下就好了。我們現 在權當沒有這個Fix分支。一般情況下,為了保護master,我們會建立一個專門處理新交來的patch的分支:
新建branch分支,並切換到該分支,應用補丁
git branch PATCH
git checkout PATCH
git apply patch
現在我們在PATCH分支中應用了這個補丁,我們可以把PATCH分支和Fix比對一下,結果肯定是什麼也沒有,說明PATCH分支和Fix分支完全一樣。patch應用成功。即使有多個檔案git diff 也能生成一個patch。


2.git format-patch生成的git專用補丁。

# git format-patch -M master         // 當前分支所有超前master的提交
# git format-patch -s 4e16                // 某次提交以後的所有patch, --4e16指的是SHA1 ID
# git format-patch -1                     //  單次提交
# git format-patch -3                    // 從master往前3個提交的內容,可修改為你想要的數值
# git format-patch –n 07fe            // -n指patch數,07fe對應提交的名稱, 某次提交(含)之前的幾次提交
# git format-patch -s --root origin     // 從origin到指定提交的所有patch
應用patch:
先檢查patch檔案:# git apply --stat newpatch.patch
檢查能否應用成功:# git apply --check  newpatch.patch
打補丁:# git am --signoff < newpatch.patch
(使用-s或--signoff選項,可以commit資訊中加入Signed-off-by資訊)
或git am

3.兩種patch的比較:

    相容性:很明顯,git diff生成的Patch相容性強。如果你在修改的程式碼的官方版本庫不是Git管理的版本庫,那麼你必須使用git diff生成的patch才能讓你的程式碼被專案的維護人接受。
    除錯功能:對於git diff生成的patch,你可以用git apply --check 檢視補丁是否能夠乾淨順利地應用到當前分支中;如果git format-patch 生成的補丁不能打到當前分支,git am會給出提示,並協助你完成打補丁工作,你也可以使用git am -3進行三方合併,詳細的做法可以參考git手冊或者《Progit》。從這一點上看,兩者除錯功能都很強。
    版本庫資訊:由於git format-patch生成的補丁中含有這個補丁開發者的名字,因此在應用補丁時,這個名字會被記錄進版本庫,顯然,這樣做是恰當的。因此,目前使用Git的開源社群往往建議大家使用format-patch生成補丁。



通常整合開發環境都有整合svn,git相關外掛,提供視覺化操作。


歡迎掃描二維碼,關注公眾賬號



相關文章