Git版本控制軟件結(jié)合GitHub從入門到精通常用命令學(xué)習(xí)手冊 – 愛分享
GIT 學(xué)習(xí)手冊簡介本站為 Git 學(xué)習(xí)參考手冊。目的是為學(xué)習(xí)與記憶 Git 使用中最重要、最普遍的命令提供快速翻閱。 這些命令以你可能需要的操作類型劃分,并且將提供日常使用中需要的一些常用的命令以及參數(shù)。 本手冊將從入門到精通指導(dǎo)大家。 首先,我們要從如何以 Git 的思維方式管理源代碼開始。 如何以 GIT 的方式思考(這節(jié)可以不用看懂,接著看下面的內(nèi)容,看完就全懂了。)懂得 Git,第一件重要的事情就是要知道它與 Subversion、Perforce 或者任何你用過的版本控制工具都有著很大的差別。 通常,忘掉你預(yù)想的版本控制方式,改以 Git 的方式思考,能夠幫助你更好地學(xué)習(xí) Git。 讓我們從頭開始。假設(shè)你正在設(shè)計一個新的源代碼管理系統(tǒng)。在你使用某個工具之前,是如何完成基本的源碼版本控制工作的呢? 十有八九,你只是在項目到達(dá)某些階段的時候,對項目做一份拷貝。 $ cp -R project project.bak 這樣,你就可以在事情變得一團(tuán)糟的時候很方便的返回到之前的狀態(tài),或者通過對比當(dāng)前的項目與之前的拷貝,看看自己在之后的工作中,都做了哪些修改。 如果你有點偏執(zhí),你可能會經(jīng)常作上面說的事情,或許還會給項目拷貝加個日期: $ cp -R project project.2010-06-01.bak 如此,你就有了一堆項目在各個階段的快照,來作比較、查看。使用這種模式,你還可以有效地與人分享項目變更。 如果你會在項目到達(dá)一定階段的時候給它打個包,丟到自己的網(wǎng)站上,那其他的開發(fā)者們,就能很方便地下載它,做點改動,并給你補丁回饋。 $ wget http:///project.2010-06-01.zip $ unzip project.2010-06-01.zip $ cp -R project.2010-06-01 project-my-copy $ cd project-my-copy $ (做了某些修改) $ diff project-my-copy project.2010-06-01 > change.patch $ (通過E-mail發(fā)送修改補丁) 以此方式,原先的開發(fā)者就能將其他人的改動應(yīng)用到他的項目中去,其他開發(fā)者也能了解你做的變更。其實這便是許多開源項目采用過多年的協(xié)作方式。 這辦法其實很好使,所以假設(shè)我們現(xiàn)在想要寫個工具,讓這個辦法更快、更簡單。 我們與其實現(xiàn)一個工具以記錄每個文件的版本,可能不如去實現(xiàn)個工具以使創(chuàng)建、儲存項目的快照更加方便,不用每次都去人肉作整個項目的拷貝。 這就是 Git 的精要所在。你通過 目錄獲取與創(chuàng)建項目基本的快照分支與合并分享與更新項目檢查與比較一、獲取與創(chuàng)建項目你得先有一個 Git 倉庫,才能用它進(jìn)行操作。倉庫是 Git 存放你要保存的快照的數(shù)據(jù)的地方。 擁有一個 Git 倉庫的途徑有兩種。在已有的目錄中,初始化一個新的,其一。 比如一個新的項目,或者一個已存在的項目,但該項目尚未有版本控制。如果你想要復(fù)制一份別人的項目, 或者與別人合作某個項目,也可以從一個公開的 Git 倉庫克隆,其二。本章將對兩者都做介紹。 Git使用前配置如果設(shè)置了,在輸入命令示界面可以很方便的使用復(fù)制和粘貼(用左鍵選取要復(fù)制的,點右鍵直接就可以復(fù)制,粘貼時只需點一下右鍵。)設(shè)置方法:Git Bash快捷圖標(biāo)(桌面圖標(biāo))右鍵屬性-選項,把快速編輯模式勾上就可以,如下圖: 設(shè)置Git本地項目開發(fā)庫默認(rèn)路徑如果設(shè)置了,就不用每次打開Git再cd打開目錄了。方法:右鍵Git Bash快捷圖標(biāo)(桌面圖標(biāo))屬性,找到快捷方式-起始位置,把你的項目地址放在這里就可以了。如下圖: 配置本地用戶和郵箱用戶名郵箱作用 : 我們需要設(shè)置一個用戶名 和 郵箱, 這是用來上傳本地倉庫到GitHub中, 在GitHub中顯示代碼上傳者; git config --global user.name "HanShuliang" //設(shè)置用戶名 git config --global user.email "13241153187@163.com" //設(shè)置郵箱 到此Git客戶端已安裝及GitHub配置完成,現(xiàn)在可以從GitHub傳輸代碼了。 git init 將一個目錄初始化為 Git 倉庫在目錄中執(zhí)行 $ cd konnichiwa$ lsREADME hello.rb 在這個項目里頭,我們會用各種編程語言寫 “Hello World” 實例。 到目前為止,我們只有 Ruby 的,不過,這才剛上路嘛。為了開始用 Git 對這個項目作版本控制,我們執(zhí)行一下 $ git initInitialized empty Git repository in /opt/konnichiwa/.git/ # 在 /opt/konnichiwa/.git 目錄初始化空 Git 倉庫完畢。 現(xiàn)在你可以看到在你的項目目錄中有個 $ ls -a. .. .git README hello.rb 恭喜,現(xiàn)在你就有了一個 Git 倉庫的架子,可以開始快照你的項目了。
git clone 復(fù)制一個 Git 倉庫,以上下其手如果你需要與他人合作一個項目,或者想要復(fù)制一個項目,看看代碼,你就可以克隆那個項目。 執(zhí)行 $ git clone git://github.com/schacon/simplegit.gitInitialized empty Git repository in /private/tmp/simplegit/.git/
remote: Counting objects: 100, done.
remote: Compressing objects: 100% (86/86), done.
remote: Total 100 (delta 35), reused 0 (delta 0)
Receiving objects: 100% (100/100), 9.51 KiB, done.
Resolving deltas: 100% (35/35), done.$ cd simplegit/$ lsREADME Rakefile lib 上述操作將復(fù)制該項目的全部記錄,讓你本地?fù)碛羞@些。并且該操作將拷貝該項目的主分支, 使你能夠查看代碼,或編輯、修改。進(jìn)到該目錄中,你會看到 $ ls -a. .. .git README Rakefile lib$ cd .git$ lsHEAD description info packed-refsbranches hooks logs refsconfig index objects 默認(rèn)情況下,Git 會按照你提供的 URL 所指示的項目的名稱創(chuàng)建你的本地項目目錄。 通常就是該 URL 最后一個
二、基本快照Git 的工作就是創(chuàng)建和保存你的項目的快照及與之后的快照進(jìn)行對比。本章將對有關(guān)創(chuàng)建與提交你的項目的快照的命令作介紹。 這里有個重要的概念,Git 有一個叫做“索引”的東東,有點像是你的快照的緩存區(qū)。這就使你能夠從更改的文件中創(chuàng)建出一系列組織良好的快照,而不是一次提交所有的更改。
git add 添加文件到緩存在 Git 中,在提交你修改的文件之前,你需要把它們添加到緩存。如果該文件是新創(chuàng)建的,你可以執(zhí)行 回到我們的 Hello World 示例,初始化該項目之后,我們就要用 $ git status -s?? README?? hello.rb 我們有倆尚未被追蹤的文件,得添加一下。 $ git add README hello.rb 現(xiàn)在我們再執(zhí)行 $ git status -sA READMEA hello.rb 新項目中,添加所有文件很普遍,可以在當(dāng)前工作目錄執(zhí)行命令: 好了,現(xiàn)在我們改個文件,再跑一下 $ vim README$ git status -sAM READMEA hello.rb “AM” 狀態(tài)的意思是,這個文件在我們將它添加到緩存之后又有改動。這意味著如果我們現(xiàn)在提交快照, 我們記錄的將是上次跑
請查看《Pro Git》中 git status 查看你的文件在工作目錄與緩存的狀態(tài)正如你在 $ git status -sAM READMEA hello.rb 而同樣的狀態(tài),詳細(xì)的輸出看起來是這樣的: $ git status# On branch master # # Initial commit # # Changes to be committed: # (use "git rm --cached <file>..." to unstage) # # new file: README# new file: hello.rb# # Changed but not updated: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: README# 你很容易發(fā)現(xiàn)簡短的輸出看起來很緊湊。而詳細(xì)輸出則很有幫助,提示你可以用何種命令完成你接下來可能要做的事情。 Git 還會告訴你在你上次提交之后,有哪些文件被刪除、修改或者存入緩存了。 $ git status -sM README D hello.rb 你可以看到,在簡短輸出中,有兩欄。第一欄是緩存的,第二欄則是工作目錄的。 所以假設(shè)你臨時提交了 README 文件,然后又改了些,并且沒有執(zhí)行 $ git status -sMM README D hello.rb
git diff 顯示已寫入緩存與已修改但尚未寫入緩存的改動的區(qū)別
git diff #尚未緩存的改動如果沒有其他參數(shù), $ vim hello.rb$ git status -s M hello.rb$ git diffdiff --git a/hello.rb b/hello.rb index d62ac43..8d15d50 100644 --- a/hello.rb +++ b/hello.rb@@ -1,7 +1,7 @@ class HelloWorld def self.hello- puts "hello world"+ puts "hola mundo" end end 所以, git diff –cached #查看已緩存的改動
$ git status -s M hello.rb$ git add hello.rb $ git status -sM hello.rb$ git diff$ 如果你想看看已緩存的改動,你需要執(zhí)行的是 $ git status -sM hello.rb$ git diff$ $ git diff --cacheddiff --git a/hello.rb b/hello.rb index d62ac43..8d15d50 100644 --- a/hello.rb +++ b/hello.rb@@ -1,7 +1,7 @@ class HelloWorld def self.hello- puts "hello world"+ puts "hola mundo" end end git diff HEAD 查看已緩存的與未緩存的所有改動如果你想一并查看已緩存的與未緩存的改動,可以執(zhí)行 $ vim hello.rb $ git diffdiff --git a/hello.rb b/hello.rb index 4f40006..2ae9ba4 100644 --- a/hello.rb +++ b/hello.rb@@ -1,7 +1,7 @@ class HelloWorld+ # says hello def self.hello puts "hola mundo" end end$ git diff --cacheddiff --git a/hello.rb b/hello.rb index 2aabb6e..4f40006 100644 --- a/hello.rb +++ b/hello.rb@@ -1,7 +1,7 @@ class HelloWorld def self.hello- puts "hello world"+ puts "hola mundo" end end$ git diff HEADdiff --git a/hello.rb b/hello.rb index 2aabb6e..2ae9ba4 100644 --- a/hello.rb +++ b/hello.rb@@ -1,7 +1,8 @@ class HelloWorld+ # says hello def self.hello- puts "hello world"+ puts "hola mundo" end end git diff –stat 顯示摘要而非整個 diff如果我們不想要看整個 diff 輸出,但是又想比 $ git status -sMM hello.rb$ git diff --stat hello.rb | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)$ git diff --cached --stat hello.rb | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)$ git diff HEAD --stat hello.rb | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) 你還可以在上述命令后面制定一個目錄,從而只查看特定文件或子目錄的
git commit 記錄緩存內(nèi)容的快照現(xiàn)在你使用 $ git config --global user.name 'Your Name'$ git config --global user.email you@somedomain.com 讓我們寫入緩存,并提交對 $ git add hello.rb $ git status -sM hello.rb$ git commit -m 'my hola mundo changes'[master 68aa034] my hola mundo changes
1 files changed, 2 insertions(+), 1 deletions(-) 現(xiàn)在我們已經(jīng)記錄了快照。如果我們再執(zhí)行 $ git status# On branch master nothing to commit (working directory clean) 如果你漏掉了 # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # modified: hello.rb # ~ ~ ".git/COMMIT_EDITMSG" 9L, 257C 在此,你在文件頭部添加實際的提交信息。以“#”開頭的行都會被無視 ——Git 將 通常,撰寫良好的提交信息是很重要的。以開放源代碼項目為例,多多少少以以下格式寫你的提示消息是個不成文的規(guī)定: 簡短的關(guān)于改動的總結(jié)(25個字或者更少) 如果有必要,更詳細(xì)的解釋文字。約 36 字時換行。在某些情況下, 第一行會被作為電子郵件的開頭,而剩余的則會作為郵件內(nèi)容。 將小結(jié)從內(nèi)容隔開的空行是至關(guān)重要的(除非你沒有內(nèi)容); 如果這兩個待在一起,有些 git 工具會犯迷糊。 空行之后是更多的段落。 - 列表也可以 - 通常使用連字符(-)或者星號(*)來標(biāo)記列表,前面有個空格, 在列表項之間有空行,不過這些約定也會有些變化。 # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # modified: hello.rb # ~ ~ ~ ".git/COMMIT_EDITMSG" 25L, 884C written 提交注解是很重要的。因為 Git 很大一部分能耐就是它在組織本地提交和與他人分享的彈性, 它很給力地能夠讓你為邏輯獨立的改變寫三到四條提交注解,以便你的工作被同仁審閱。因為提交與推送改動是有區(qū)別的, 請務(wù)必花時間將各個邏輯獨立的改動放到另外一個提交,并附上一份良好的提交注解, 以使與你合作的人能夠方便地了解你所做的,以及你為何要這么做。 git commit -a 自動將在提交前將已記錄、修改的文件放入緩存區(qū)如果你覺得 $ vim hello.rb$ git status -s
M hello.rb$ git commit -m 'changes to hello file'# On branch master
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: hello.rb
#no changes added to commit (use "git add" and/or "git commit -a")$ git commit -am 'changes to hello file'[master 78b2670] changes to hello file
1 files changed, 2 insertions(+), 1 deletions(-) 注意,如果你不緩存改動,直接執(zhí)行 現(xiàn)在你就完成了整個快照的流程 ——改些文件,然后用
git reset HEAD 取消緩存已緩存的內(nèi)容
在此例中,我們可以用它來將不小心緩存的東東取消緩存。假設(shè)你修改了兩個文件,想要將它們記錄到兩個不同的提交中去。 你應(yīng)該緩存并提交一個,再緩存并提交另外一個。如果你不小心兩個都緩存了,那要如何才能取消緩存呢? 你可以用 好,讓我們看看取消緩存是什么樣子的。這里我們有兩個最近提交之后又有所改動的文件。我們將兩個都緩存,并取消緩存其中一個。 $ git status -s M README M hello.rb$ git add .$ git status -sM READMEM hello.rb$ git reset HEAD -- hello.rb Unstaged changes after reset: M hello.rb$ git status -sM README M hello.rb 現(xiàn)在你執(zhí)行 如果你好奇,它實際的操作是將該文件在“索引”中的校驗和重置為最近一次提交中的值。 如果你想直接執(zhí)行 如果你忘了取消緩存的命令,Git 的常規(guī) $ git status# On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage)# # modified: README# modified: hello.rb#
git rm 將文件從緩存區(qū)移除
默認(rèn)情況下, git mv git rm –cached orig; mv orig new; git add new不像絕大多數(shù)其他版本控制系統(tǒng),Git 并不記錄記錄文件重命名。它反而只記錄快照,并對比快照以找到有啥文件可能被重命名了。 如果一個文件從更新中刪除了,而在下次快照中新添加的另一個文件的內(nèi)容與它很相似,Git 就知道這極有可能是個重命名。 因此,雖然有 我自己并不使用此命令的普通形式 —— 刪除文件。通常直接從硬盤刪除文件,然后執(zhí)行
三、分支與合并分支是我最喜歡的 Git 特性之一。如果你用過其他版本控制系統(tǒng),把你所知的分支給忘記,倒可能更有幫助些 —— 事實上,以我們使用分支的方式,把 Git 的分支看作 上下文 反而更合適。 當(dāng)你檢出分支時,你可以在兩三個不同的分支之間來回切換。
git branch 列出、創(chuàng)建與管理工作上下文 git checkout 切換到新的分支上下文
git branch 列出可用的分支沒有參數(shù)時, $ git branch
* master 此例的意思就是,我們有一個叫做“master”的分支,并且該分支是當(dāng)前分支。 當(dāng)你執(zhí)行 git branch (branchname) 創(chuàng)建新分支我們動手創(chuàng)建一個分支,并切換過去。執(zhí)行 $ git branch testing
$ git branch
* master
testing 現(xiàn)在我們可以看到,有了一個新分支。當(dāng)你以此方式在上次提交更新之后創(chuàng)建了新分支,如果后來又有更新提交, 然后又切換到了“testing”分支,Git 將還原你的工作目錄到你創(chuàng)建分支時候的樣子 —— 你可以把它看作一個記錄你當(dāng)前進(jìn)度的書簽。讓我們實際運用看看 —— 我們用 $ lsREADME hello.rb$ echo 'test content' > test.txt$ echo 'more content' > more.txt$ git add *.txt$ git commit -m 'added two files'[master 8bd6d8b] added two files 2 files changed, 2 insertions(+), 0 deletions(-) create mode 100644 more.txt create mode 100644 test.txt$ lsREADME hello.rb more.txt test.txt$ git checkout testingSwitched to branch 'testing'$ lsREADME hello.rb 當(dāng)我們切換到“測試”分支的時候,我們添加的新文件被移除了。切換回“master”分支的時候,它們有重新出現(xiàn)了。 $ lsREADME hello.rb$ git checkout masterSwitched to branch 'master'$ lsREADME hello.rb more.txt test.txt git checkout -b (branchname) 創(chuàng)建新分支,并立即切換到它通常情況下,你會更希望立即切換到新分支,從而在該分支中操作,然后當(dāng)此分支的開發(fā)日趨穩(wěn)定時, 將它合并到穩(wěn)定版本的分支(例如“master”)中去。 執(zhí)行 $ git branch* master$ lsREADME hello.rb more.txt test.txt$ git checkout -b removalsSwitched to a new branch 'removals'$ git rm more.txt rm 'more.txt'$ git rm test.txt rm 'test.txt'$ lsREADME hello.rb$ git commit -am 'removed useless files'[removals 8f7c949] removed useless files 2 files changed, 0 insertions(+), 2 deletions(-) delete mode 100644 more.txt delete mode 100644 test.txt$ git checkout masterSwitched to branch 'master'$ lsREADME hello.rb more.txt test.txt 如你所見,我們創(chuàng)建了一個分支,在該分支的上下文中移除了一些文件,然后切換回我們的主分支,那些文件又回來了。 使用分支將工作切分開來,從而讓我們能夠在不同上下文中做事,并來回切換。 創(chuàng)建新分支,在其中完成一部分工作,完成之后將它合并到主分支并刪除。你會覺得這很方便,因為這么做很快很容易。 如此,當(dāng)你覺得這部分工作并不靠譜,舍棄它很容易。并且,如果你必須回到穩(wěn)定分支做些事情, 也可以很方便地這個獨立分支的工作先丟在一邊,完成要事之后再切換回來。 git branch -d (branchname) 刪除分支假設(shè)我們要刪除一個分支(比如上例中的“testing”分支,該分支沒啥特殊的內(nèi)容了), 可以執(zhí)行 $ git branch* master testing$ git branch -d testingDeleted branch testing (was 78b2670).$ git branch* master
git merge 將分支合并到你的當(dāng)前分支一旦某分支有了獨立內(nèi)容,你終究會希望將它合并回到你的主分支。 你可以使用 $ git branch* master
removals$ lsREADME hello.rb more.txt test.txt$ git merge removalsUpdating 8bd6d8b..8f7c949
Fast-forward
more.txt | 1 -
test.txt | 1 -
2 files changed, 0 insertions(+), 2 deletions(-)
delete mode 100644 more.txt
delete mode 100644 test.txt$ lsREADME hello.rb 更多復(fù)雜合并當(dāng)然,合并并不僅僅是簡單的文件添加、移除的操作,Git 也會合并修改 —— 事實上,它很會合并修改。 舉例,我們看看在某分支中編輯某個文件,然后在另一個分支中把它的名字改掉再做些修改, 最后將這倆分支合并起來。你覺得會變成一坨 shi?我們試試看。 $ git branch* master$ cat hello.rb class HelloWorld def self.hello puts "Hello World" end end HelloWorld.hello 首先,我們創(chuàng)建一個叫做“change_class”的分支,切換過去,從而將重命名類等操作獨立出來。我們將類名從 “HelloWorld” 改為 “HiWorld”。 $ git checkout -b change_classM hello.rb Switched to a new branch 'change_class'$ vim hello.rb $ head -1 hello.rb class HiWorld$ git commit -am 'changed the class name'[change_class 3467b0a] changed the class name 1 files changed, 2 insertions(+), 4 deletions(-) 然后,將重命名類操作提交到 “change_class” 分支中。 現(xiàn)在,假如切換回 “master” 分支我們可以看到類名恢復(fù)到了我們切換到 “change_class” 分支之前的樣子。 現(xiàn)在,再做些修改(即代碼中的輸出),同時將文件名從 $ git checkout masterSwitched to branch 'master'$ git mv hello.rb ruby.rb$ vim ruby.rb $ git diffdiff --git a/ruby.rb b/ruby.rb index 2aabb6e..bf64b17 100644 --- a/ruby.rb +++ b/ruby.rb@@ -1,7 +1,7 @@ class HelloWorld def self.hello- puts "Hello World"+ puts "Hello World from Ruby" end end$ git commit -am 'added from ruby'[master b7ae93b] added from ruby 1 files changed, 1 insertions(+), 1 deletions(-) rename hello.rb => ruby.rb (65%) 現(xiàn)在這些改變已經(jīng)記錄到我的 “master” 分支了。請注意,這里類名還是 “HelloWorld”,而不是 “HiWorld”。 然后我想將類名的改變合并過來,我把 “change_class” 分支合并過來就行了。 但是,我已經(jīng)將文件名都改掉了,Git 知道該怎么辦么? $ git branch change_class * master$ git merge change_classRenaming hello.rb => ruby.rb Auto-merging ruby.rb Merge made by recursive. ruby.rb | 6 ++---- 1 files changed, 2 insertions(+), 4 deletions(-)$ cat ruby.rbclass HiWorld def self.hello puts "Hello World from Ruby" end end HiWorld.hello 不錯,它就是發(fā)現(xiàn)了。請注意,在這部操作,我沒有遇到合并沖突,并且文件已經(jīng)重命名、類名也換掉了。挺酷。 合并沖突那么,Git 合并很有魔力,我們再也不用處理合并沖突了,對嗎?不太確切。 不同分支中修改了相同區(qū)塊的代碼,電腦自己猜不透神馬的情況下,沖突就擺在我們面前了。 我們看看兩個分支中改了同一行代碼的例子。 $ git branch* master$ git checkout -b fix_readmeSwitched to a new branch 'fix_readme'$ vim README $ git commit -am 'fixed readme title'[fix_readme 3ac015d] fixed readme title 1 files changed, 1 insertions(+), 1 deletions(-) 我們在某分支中修改了 README 文件中的一行,并提交了。我們再在 “master” 分支中對同個文件的同一行內(nèi)容作不同的修改。 $ git checkout masterSwitched to branch 'master'$ vim README $ git commit -am 'fixed readme title differently'[master 3cbb6aa] fixed readme title differently 1 files changed, 1 insertions(+), 1 deletions(-) 有意思的來了 —— 我們將前一個分支合并到 “master” 分支,一個合并沖突就出現(xiàn)了。 $ git merge fix_readmeAuto-merging README CONFLICT (content): Merge conflict in README Automatic merge failed; fix conflicts and then commit the result.$ cat README <<<<<<< HEAD Many Hello World Examples ======= Hello World Lang Examples >>>>>>> fix_readme This project has examples of hello world in nearly every programming language. 你可以看到,Git 在產(chǎn)生合并沖突的地方插入了標(biāo)準(zhǔn)的與 Subversion 很像的合并沖突標(biāo)記。 輪到我們?nèi)ソ鉀Q這些沖突了。在這里我們就手動把它解決。如果你要 Git 打開一個圖形化的合并工具, 可以看看 git 合并工具 (比如 kdiff3、emerge、p4merge 等)。 $ vim README here I'm fixing the conflict$ git diffdiff --cc README index 9103e27,69cad1a..0000000 --- a/README +++ b/README@@@ -1,4 -1,4 +1,4 @@@- Many Hello World Examples -Hello World Lang Examples++Many Hello World Lang Examples This project has examples of hello world in 在 Git 中,處理合并沖突的時候有個很酷的提示。 如果你執(zhí)行 $ git status -sUU README$ git add README $ git status -sM README$ git commit [master 8d585ea] Merge branch 'fix_readme' 現(xiàn)在我們成功解決了合并中的沖突,并提交了結(jié)果
git log 顯示一個分支中提交的更改記錄到目前為止,我們已經(jīng)提交快照到項目中,在不同的各自分離的上下文中切換, 但假如我們忘了自己是如何到目前這一步的那該怎么辦?或者假如我們想知道此分支與彼分支到底有啥區(qū)別? Git 提供了一個告訴你使你達(dá)成當(dāng)前快照的所有提交消息的工具,叫做 要理解日志(log)命令,你需要了解當(dāng)執(zhí)行 某分支的按時間排序的“父親”列表,當(dāng)你在該分支時,可以執(zhí)行 $ git logcommit 8d585ea6faf99facd39b55d6f6a3b3f481ad0d3dMerge: 3cbb6aa 3ac015d Author: Scott Chacon <schacon@gmail.com> Date: Fri Jun 4 12:59:47 2010 +0200 Merge branch 'fix_readme' Conflicts: READMEcommit 3cbb6aae5c0cbd711c098e113ae436801371c95eAuthor: Scott Chacon <schacon@gmail.com> Date: Fri Jun 4 12:58:53 2010 +0200 fixed readme title differentlycommit 3ac015da8ade34d4c7ebeffa2053fcac33fb495bAuthor: Scott Chacon <schacon@gmail.com> Date: Fri Jun 4 12:58:36 2010 +0200 fixed readme titlecommit 558151a95567ba4181bab5746bc8f34bd87143d6Merge: b7ae93b 3467b0a Author: Scott Chacon <schacon@gmail.com> Date: Fri Jun 4 12:37:05 2010 +0200 Merge branch 'change_class' ... 我們可以用 $ git log --oneline8d585ea Merge branch 'fix_readme' 3cbb6aa fixed readme title differently 3ac015d fixed readme title 558151a Merge branch 'change_class' b7ae93b added from ruby 3467b0a changed the class name 17f4acf first commit 這告訴我們的是,此項目的開發(fā)歷史。如果提交消息描述性很好,這就能為我們提供關(guān)于有啥改動被應(yīng)用、或者影響了當(dāng)前快照的狀態(tài)、以及這快照里頭都有啥。 我們還可以用它的十分有幫助的 $ git log --oneline --graph* 8d585ea Merge branch 'fix_readme' || * 3ac015d fixed readme title * | 3cbb6aa fixed readme title differently |/ * 558151a Merge branch 'change_class' || * 3467b0a changed the class name * | b7ae93b added from ruby |/ * 17f4acf first commit 現(xiàn)在我們可以更清楚明了地看到何時工作分叉、又何時歸并。 這對查看發(fā)生了什么、應(yīng)用了什么改變很有幫助,并且極大地幫助你管理你的分支。 讓我們創(chuàng)建一個分支,在里頭做些事情,然后切回到主分支,也做點事情,然后看看 首先我們創(chuàng)建一個分支,來添加 Erlang 編程語言的 Hello World 示例 —— 我們想要在一個分支里頭做這個,以避免讓可能還不能工作的代碼弄亂我們的穩(wěn)定分支。 這樣就可以切來切去,片葉不沾身。 $ git checkout -b erlangSwitched to a new branch 'erlang'$ vim erlang_hw.erl$ git add erlang_hw.erl $ git commit -m 'added erlang'[erlang ab5ab4c] added erlang 1 files changed, 5 insertions(+), 0 deletions(-) create mode 100644 erlang_hw.erl 由于我們玩函數(shù)式編程很開心,以至于沉迷其中,又在“erlang”分支中添加了一個 Haskell 的示例程序。 $ vim haskell.hs$ git add haskell.hs $ git commit -m 'added haskell'[erlang 1834130] added haskell 1 files changed, 4 insertions(+), 0 deletions(-) create mode 100644 haskell.hs 最后,我們決定還是把 Ruby 程序的類名改回原先的樣子。與其創(chuàng)建另一個分支,我們可以返回主分支,改變它,然后直接提交。 $ git checkout masterSwitched to branch 'master'$ lsREADME ruby.rb$ vim ruby.rb $ git commit -am 'reverted to old class name'[master 594f90b] reverted to old class name 1 files changed, 2 insertions(+), 2 deletions(-) 現(xiàn)在假設(shè)我們有段時間不做這個項目了,我們做別的去了。 當(dāng)我們回來的時候,我們想知道“erlang”分支都是啥,而主分支的進(jìn)度又是怎樣。 僅僅看分支的名字,我們是無從知道自己還在里面有 Haskell 的改動的,但是用 $ git log --oneline erlang1834130 added haskellab5ab4c added erlang 8d585ea Merge branch 'fix_readme' 3cbb6aa fixed readme title differently 3ac015d fixed readme title 558151a Merge branch 'change_class' b7ae93b added from ruby 3467b0a changed the class name 17f4acf first commit 如此,我們很容易就看到分支里頭還包括了 Haskell 代碼(高亮顯示了)。 更酷的是,我們很容易地告訴 Git,我們只對某個分支中可及的提交感興趣。換句話說,某分支中與其他分支相比唯一的提交。 在此例中,如果我們想要合并“erlang”分支,我們需要看當(dāng)合并的時候,都有啥提交會作用到我們的快照上去。 我們告訴 Git 的方式是,在不想要看到的分支前放一個 $ git log --oneline erlang ^master1834130 added haskell ab5ab4c added erlang$ git log --oneline master ^erlang594f90b reverted to old class name 這為我們提供了一個良好的、簡易的分支管理工具。它使我們能夠非常容易地查看對某個分支唯一的提交,從而知道我們?nèi)鄙偈裁?,以及?dāng)我們要合并時,會有什么被合并進(jìn)去。
git tag 給歷史記錄中的某個重要的一點打上標(biāo)簽如果你達(dá)到一個重要的階段,并希望永遠(yuǎn)記住那個特別的提交快照,你可以使用 比如說,我們想為我們的 Hello World 項目發(fā)布一個“1.0”版本。 我們可以用 $ git tag -a v1.0 當(dāng)你執(zhí)行 現(xiàn)在,注意當(dāng)我們執(zhí)行 $ git log --oneline --decorate --graph* 594f90b (HEAD, tag: v1.0, master) reverted to old class name * 8d585ea Merge branch 'fix_readme' || * 3ac015d (fix_readme) fixed readme title * | 3cbb6aa fixed readme title differently |/ * 558151a Merge branch 'change_class' || * 3467b0a changed the class name * | b7ae93b added from ruby |/ * 17f4acf first commit 如果我們有新提交,該標(biāo)簽依然會待在該提交的邊上,所以我們已經(jīng)給那個特定快照永久打上標(biāo)簽,并且能夠?qū)⑺c未來的快照做比較。 不過我們并不需要給當(dāng)前提交打標(biāo)簽。如果我們忘了給某個提交打標(biāo)簽,又將它發(fā)布了,我們可以給它追加標(biāo)簽。 在相同的命令末尾加上提交的 SHA,執(zhí)行,就可以了。 例如,假設(shè)我們發(fā)布了提交 $ git tag -a v0.9 558151a$ git log --oneline --decorate --graph* 594f90b (HEAD, tag: v1.0, master) reverted to old class name * 8d585ea Merge branch 'fix_readme' || * 3ac015d (fix_readme) fixed readme title * | 3cbb6aa fixed readme title differently |/ * 558151a (tag: v0.9) Merge branch 'change_class' || * 3467b0a changed the class name * | b7ae93b added from ruby |/ * 17f4acf first commit 四、分享與更新項目Git 并不像 Subversion 那樣有個中心服務(wù)器。 目前為止所有的命令都是本地執(zhí)行的,更新的知識本地的數(shù)據(jù)庫。 要通過 Git 與其他開發(fā)者合作,你需要將數(shù)據(jù)放到一臺其他開發(fā)者能夠連接的服務(wù)器上。 Git 實現(xiàn)此流程的方式是將你的數(shù)據(jù)與另一個倉庫同步。在服務(wù)器與客戶端之間并沒有實質(zhì)的區(qū)別 —— Git 倉庫就是 Git 倉庫,你可以很容易地在兩者之間同步。 一旦你有了個 Git 倉庫,不管它是在你自己的服務(wù)器上,或者是由 GitHub 之類的地方提供, 你都可以告訴 Git 推送你擁有的遠(yuǎn)端倉庫還沒有的數(shù)據(jù),或者叫 Git 從別的倉庫把差別取過來。 聯(lián)網(wǎng)的時候你可以隨時做這個,它并不需要對應(yīng)一個
git remote 羅列、添加和刪除遠(yuǎn)端倉庫別名不像中心化的版本控制系統(tǒng)(客戶端與服務(wù)端很不一樣),Git 倉庫基本上都是一致的,并且并可以同步他們。 這使得擁有多個遠(yuǎn)端倉庫變得容易 —— 你可以擁有一些只讀的倉庫,另外的一些也可寫的倉庫。 當(dāng)你需要與遠(yuǎn)端倉庫同步的時候,不需要使用它詳細(xì)的鏈接。Git 儲存了你感興趣的遠(yuǎn)端倉庫的鏈接的別名或者昵稱。 你可以使用 git remote 列出遠(yuǎn)端別名如果沒有任何參數(shù),Git 會列出它存儲的遠(yuǎn)端倉庫別名了事。默認(rèn)情況下,如果你的項目是克隆的(與本地創(chuàng)建一個新的相反), Git 會自動將你的項目克隆自的倉庫添加到列表中,并取名“origin”。 如果你執(zhí)行時加上 $ git remoteorigin$ git remote -vorigin git@github.com:github/git-reference.git (fetch) origin git@github.com:github/git-reference.git (push) 在此你看到了該鏈接兩次,是因為 Git 允許你為每個遠(yuǎn)端倉庫添加不同的推送與獲取的鏈接,以備你讀寫時希望使用不同的協(xié)議。 git remote add 為你的項目添加一個新的遠(yuǎn)端倉庫如果你希望分享一個本地創(chuàng)建的倉庫,或者你想要獲取別人的倉庫中的貢獻(xiàn) —— 如果你想要以任何方式與一個新倉庫溝通,最簡單的方式通常就是把它添加為一個遠(yuǎn)端倉庫。 執(zhí)行 例如,假設(shè)我們想要與整個世界分享我們的 Hello World 程序。 我們可以在一臺服務(wù)器上創(chuàng)建一個新倉庫(我以 GitHub 為例子)。 它應(yīng)該會給你一個鏈接,在這里就是“git@github.com:schacon/hw.git”。 要把它添加到我們的項目以便我們推送以及獲取更新,我們可以這樣: $ git remote$ git remote add github git@github.com:schacon/hw.git$ git remote -vgithub git@github.com:schacon/hw.git (fetch) github git@github.com:schacon/hw.git (push) 像分支的命名一樣,遠(yuǎn)端倉庫的別名是強(qiáng)制的 —— 就像“master”,沒有特別意義,但它廣為使用, 因為 git remote rm 刪除現(xiàn)存的某個別名Git addeth and Git taketh away. 如果你需要刪除一個遠(yuǎn)端 —— 不再需要它了、項目已經(jīng)沒了,等等 —— 你可以使用 $ git remote -vgithub git@github.com:schacon/hw.git (fetch) github git@github.com:schacon/hw.git (push)$ git remote add origin git://github.com/pjhyett/hw.git$ git remote -vgithub git@github.com:schacon/hw.git (fetch) github git@github.com:schacon/hw.git (push) origin git://github.com/pjhyett/hw.git (fetch) origin git://github.com/pjhyett/hw.git (push)$ git remote rm origin$ git remote -vgithub git@github.com:schacon/hw.git (fetch) github git@github.com:schacon/hw.git (push)
git fetch 從遠(yuǎn)端倉庫下載新分支與數(shù)據(jù) git pull 從遠(yuǎn)端倉庫提取數(shù)據(jù)并嘗試合并到當(dāng)前分支Git 有兩個命令用來從某一遠(yuǎn)端倉庫更新。 第二個會從遠(yuǎn)端服務(wù)器提取新數(shù)據(jù)的命令是 假設(shè)你配置好了一個遠(yuǎn)端,并且你想要提取更新,你可以首先執(zhí)行 $ git fetch githubremote: Counting objects: 4006, done. remote: Compressing objects: 100% (1322/1322), done. remote: Total 2783 (delta 1526), reused 2587 (delta 1387) Receiving objects: 100% (2783/2783), 1.23 MiB | 10 KiB/s, done. Resolving deltas: 100% (1526/1526), completed with 387 local objects. From github.com:schacon/hw 8e29b09..c7c5a10 master -> github/master 0709fdc..d4ccf73 c-langs -> github/c-langs 6684f82..ae06d2b java -> github/java * [new branch] ada -> github/ada * [new branch] lisp -> github/lisp 可以看到自從上一次與遠(yuǎn)端倉庫同步以后,又新贈或更新了五個分支。 “ada”與“l(fā)isp”分支是新的,而“master”、“clang”與“java”分支則被更新了。 在此例中,我的團(tuán)隊在合并入主分支之前,將提議的更新推送到遠(yuǎn)端分支以審核。 你可以看到 Git 做的映射。遠(yuǎn)端倉庫的主分支成為了本地的一個叫做“github/master”的分支。 這樣我就可以執(zhí)行 如果你有多個遠(yuǎn)端倉庫,你可以執(zhí)行
git push 推送你的新分支與數(shù)據(jù)到某個遠(yuǎn)端倉庫想要與他人分享你牛鼻的提交,你需要將改動推送到遠(yuǎn)端倉庫。 執(zhí)行 $ git push github masterCounting objects: 25, done. Delta compression using up to 2 threads. Compressing objects: 100% (25/25), done. Writing objects: 100% (25/25), 2.43 KiB, done. Total 25 (delta 4), reused 0 (delta 0) To git@github.com:schacon/hw.git * [new branch] master -> master 挺簡單。現(xiàn)在如果有人從該倉庫克隆,他會得到我提交的完完全全的一份歷史記錄了。 如果有個像之前創(chuàng)建的“erlang”分支那樣的主題分支,想只分享這個,該怎么辦呢?你可以相應(yīng)的只推送該分支。 $ git push github erlangCounting objects: 7, done. Delta compression using up to 2 threads. Compressing objects: 100% (6/6), done. Writing objects: 100% (6/6), 652 bytes, done. Total 6 (delta 1), reused 0 (delta 0) To git@github.com:schacon/hw.git * [new branch] erlang -> erlang 現(xiàn)在當(dāng)人們從該倉庫克隆時,他們就會得到一個“erlang”分支以查閱、合并。 用這種方式,你可以推送任何分支到任何你有寫權(quán)限的倉庫。 如果你的分支已經(jīng)在該倉庫中了,它會試著去更新,如果它不再,Git 會把它加上。 最后一個當(dāng)你推送到遠(yuǎn)端分支時會碰到的主要問題是,其他人在此期間也推送了的情況。 如果你和另一個開發(fā)者同時克隆了,又都有提交,那么當(dāng)她推送后你也想推送時,默認(rèn)情況下 Git 不會讓你覆蓋她的改動。 相反的,它會在你試圖推送的分支上執(zhí)行 當(dāng)你試圖推送到某個以被更新的遠(yuǎn)端分支時,會出現(xiàn)下面這種情況: $ git push github masterTo git@github.com:schacon/hw.git ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to 'git@github.com:schacon/hw.git' To prevent you from losing history, non-fast-forward updates were rejected Merge the remote changes before pushing again. See the 'Note about fast-forwards' section of 'git push --help' for details. 你可以修正這個問題。執(zhí)行
五、檢查與比較現(xiàn)在你有了一堆分支,短期的主題、長期的特性或者其它。怎樣追蹤他們呢? Git 有一組工具,可以幫助你弄明白工作是在哪兒完成的,兩個分支間的區(qū)別是啥,等等。
git log 過濾你的提交歷史記錄通過查看分支中另一分支看不到的提交記錄,我們已經(jīng)看到如何用 git log –author 只尋找某個特定作者的提交要過濾你的提交歷史,只尋找某個特定作者的提交,你可以使用 $ git log --author=Linus --oneline -581b50f3 Move 'builtin-*' into a 'builtin/' subdirectory 3bb7256 make "index-pack" a built-in 377d027 make "git pack-redundant" a built-in b532581 make "git unpack-file" a built-in 112dd51 make "mktag" a built-in git log –since –before 根據(jù)日期過濾提交記錄如果你要指定一個你感興趣的日期范圍以過濾你的提交,可以執(zhí)行幾個選項 —— 我用 $ git log --oneline --before={3.weeks.ago} --after={2010-04-18} --no-merges5469e2d Git 1.7.1-rc2 d43427d Documentation/remote-helpers: Fix typos and improve language 272a36b Fixup: Second argument may be any arbitrary string b6c8d2d Documentation/remote-helpers: Add invocation section 5ce4f4e Documentation/urls: Rewrite to accomodate transport::address 00b84e9 Documentation/remote-helpers: Rewrite description 03aa87e Documentation: Describe other situations where -z affects git diff 77bc694 rebase-interactive: silence warning when no commits rewritten 636db2c t3301: add tests to use --format="%N" git log –grep 根據(jù)提交注釋過濾提交記錄你或許還想根據(jù)提交注釋中的某個特定短語查找提交記錄。可以用 $ git log --grep=P4EDITOR --no-mergescommit 82cea9ffb1c4677155e3e2996d76542502611370Author: Shawn Bohrer
Date: Wed Mar 12 19:03:24 2008 -0500
git-p4: Use P4EDITOR environment variable when set
Perforce allows you to set the P4EDITOR environment variable to your
preferred editor for use in perforce. Since we are displaying a
perforce changelog to the user we should use it when it is defined.
Signed-off-by: Shawn Bohrer <shawn.bohrer@gmail.com>
Signed-off-by: Simon Hausmann <simon@lst.de> Git 會對所有的 如果我查找注釋內(nèi)容含有 “p4 depo”的提交,我得到了三個提交: $ git log --grep="p4 depo" --format="%h %an %s"ee4fd1a Junio C Hamano Merge branch 'master' of git://repo.or.cz/git/fastimport da4a660 Benjamin Sergeant git-p4 fails when cloning a p4 depo. 1cd5738 Simon Hausmann Make incremental imports easier to use by storing the p4 d 如果我加上 $ git log --grep="p4 depo" --format="%h %an %s" --author="Hausmann"cdc7e38 Simon Hausmann Make it possible to abort the submission of a change to Pe f5f7e4a Simon Hausmann Clean up the git-p4 documentation 30b5940 Simon Hausmann git-p4: Fix import of changesets with file deletions 4c750c0 Simon Hausmann git-p4: git-p4 submit cleanups. 0e36f2d Simon Hausmann git-p4: Removed git-p4 submit --direct. edae1e2 Simon Hausmann git-p4: Clean up git-p4 submit's log message handling. 4b61b5c Simon Hausmann git-p4: Remove --log-substitutions feature. 36ee4ee Simon Hausmann git-p4: Ensure the working directory and the index are cle e96e400 Simon Hausmann git-p4: Fix submit user-interface. 38f9f5e Simon Hausmann git-p4: Fix direct import from perforce after fetching cha 2094714 Simon Hausmann git-p4: When skipping a patch as part of "git-p4 submit" m 1ca3d71 Simon Hausmann git-p4: Added support for automatically importing newly ap ... 不過,如果加上 $ git log --grep="p4 depo" --format="%h %an %s" --author="Hausmann" --all-match1cd5738 Simon Hausmann Make incremental imports easier to use by storing the p4 d git log -S 依據(jù)所引入的差值過濾如果你寫的提交注釋都極度糟糕怎么辦?或者,如果你要找某個函數(shù)是何時引入的,某些變量是在哪里開始被使用的? 你可以告訴 Git 在每個提交之間的差值中查找特定字符串。 例如,如果我們想要找出哪個提交修改出了類似函數(shù)名“userformat_find_requirements”, 我們可以執(zhí)行(注意在“-S”與你要找的東東之間沒有“=”): $ git log -Suserformat_find_requirementscommit 5b16360330822527eac1fa84131d185ff784c9fbAuthor: Johannes Gilger
Date: Tue Apr 13 22:31:12 2010 +0200
pretty: Initialize notes if %N is used
When using git log --pretty='%N' without an explicit --show-notes, git
would segfault. This patches fixes this behaviour by loading the needed
notes datastructures if --pretty is used and the format contains %N.
When --pretty='%N' is used together with --no-notes, %N won't be
expanded.
This is an extension to a proposed patch by Jeff King.
Signed-off-by: Johannes Gilger
Signed-off-by: Junio C Hamano git log -p 顯示每個提交引入的補丁每個提交都是項目的一個快照。由于每個提交都記錄它所基于的快照,Git 能夠經(jīng)常對它們求差值,并以補丁形式向你展示。 這意味著,對任意提交,你都可以獲取該提交給項目引入補丁。 你可以用 $ git log -p --no-merges -2commit 594f90bdee4faf063ad07a4a6f503fdead3ef606Author: Scott Chacon <schacon@gmail.com> Date: Fri Jun 4 15:46:55 2010 +0200 reverted to old class namediff --git a/ruby.rb b/ruby.rb index bb86f00..192151c 100644 --- a/ruby.rb +++ b/ruby.rb@@ -1,7 +1,7 @@-class HiWorld+class HelloWorld def self.hello puts "Hello World from Ruby" end end-HiWorld.hello+HelloWorld.hellocommit 3cbb6aae5c0cbd711c098e113ae436801371c95eAuthor: Scott Chacon <schacon@gmail.com> Date: Fri Jun 4 12:58:53 2010 +0200 fixed readme title differentlydiff --git a/README b/README index d053cc8..9103e27 100644 --- a/README +++ b/README@@ -1,4 +1,4 @@-Hello World Examples+Many Hello World Examples ====================== This project has examples of hello world in 這是個總結(jié)改動,以及合并或發(fā)布之前重審一系列提交的好方式。 git log –stat 顯示每個提交引入的改動的差值統(tǒng)計如果 $ git log --stat --no-merges -2commit 594f90bdee4faf063ad07a4a6f503fdead3ef606Author: Scott Chacon <schacon@gmail.com> Date: Fri Jun 4 15:46:55 2010 +0200 reverted to old class name ruby.rb | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)commit 3cbb6aae5c0cbd711c098e113ae436801371c95eAuthor: Scott Chacon <schacon@gmail.com> Date: Fri Jun 4 12:58:53 2010 +0200 fixed readme title differently README | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) 同樣的基本信息,但更緊湊 —— 它仍然讓你看到相對改動,和改動了哪些文件。 git diff最后,要查看兩個提交快照的絕對改動,你可以用 你僅需執(zhí)行 $ git diff v0.9diff --git a/README b/README index d053cc8..d4173d5 100644 --- a/README +++ b/README@@ -1,4 +1,4 @@-Hello World Examples+Many Hello World Lang Examples ====================== This project has examples of hello world indiff --git a/ruby.rb b/ruby.rb index bb86f00..192151c 100644 --- a/ruby.rb +++ b/ruby.rb@@ -1,7 +1,7 @@-class HiWorld+class HelloWorld def self.hello puts "Hello World from Ruby" end end-HiWorld.hello+HelloWorld.hello 正如 $ git diff v0.9 --stat README | 2 +- ruby.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 要比較兩個不同的分支,你可以執(zhí)行類似 $ git log --graph --oneline --decorate --all* 594f90b (HEAD, tag: v1.0, master) reverted to old class name | * 1834130 (erlang) added haskell | * ab5ab4c added erlang |/ * 8d585ea Merge branch 'fix_readme' ... 并且,我們想要看“erlang”分支與主分支相比的查別。執(zhí)行 $ git diff --stat master erlang erlang_hw.erl | 5 +++++ haskell.hs | 4 ++++ ruby.rb | 4 ++-- 3 files changed, 11 insertions(+), 2 deletions(-) 你可以看到,它加上了 erlang 和 haskell 文件,這確實是我們在該分支中做的, 但是它同時恢復(fù)了我們在主分支中改動的 ruby 文件。我們真心想要的只是“erlang”分支中的改動(添加兩個文件)。 我們可以通過求兩個分支分歧時的共同提交與該分支的差值得到想要的結(jié)果: $ git diff --stat 8d585ea erlang erlang_hw.erl | 5 +++++ haskell.hs | 4 ++++ 2 files changed, 9 insertions(+), 0 deletions(-) 這才是我們在找的,但是我們可不想要每次都要找出兩個分支分歧時的那次提交。 幸運的是,Git 為此提供了一個快捷方式。 如果你執(zhí)行 $ git diff --stat master erlang erlang_hw.erl | 5 +++++ haskell.hs | 4 ++++ ruby.rb | 4 ++-- 3 files changed, 11 insertions(+), 2 deletions(-)$ git diff --stat master...erlang erlang_hw.erl | 5 +++++ haskell.hs | 4 ++++ 2 files changed, 9 insertions(+), 0 deletions(-) 幾乎每一次你要對比兩個分支的時候,你都會想用三個點的語法,因為它通常會給你你想要的。 順帶提一句,你還可以讓 Git 手工計算兩次提交的合并基礎(chǔ)(第一個共同的祖提交),即 $ git merge-base master erlang8d585ea6faf99facd39b55d6f6a3b3f481ad0d3d 所以你執(zhí)行下面這個也跟 $ git diff --stat $(git merge-base master erlang) erlang erlang_hw.erl | 5 +++++ haskell.hs | 4 ++++ 2 files changed, 9 insertions(+), 0 deletions(-) 當(dāng)然,我會推薦簡單點的那個。
|
|