Git基本用法2
二、比較內容
1.比較提交 - Git Diff
現在我們對項目做些修改:
$ cd gitproject
# 向README文件添加一行
$ echo "new line" >> README.md
# 添加新的文件file1
$ echo "new file" >> file1
使用git status
查看當前修改的狀態:
$ git status
On branch master
Your branch is up-to-date with ‘origin/master‘.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: README.md
Untracked files:
(use "git add <file>..." to include in what will be committed)
file1
no changes added to commit (use "git add" and/or "git commit -a" )
可以看到一個文件修改了,另外一個文件添加了。如何查看修改的文件內容呢,那就需要使用git diff
命令。git diff
命令的作用是比較修改的或提交的文件內容。
$ git diff
diff --git a/README.md b/README.md
index 21781dd..410e719 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,3 @@
gitproject
==========
+new line
上面的命令執行後需要使用q
退出。命令輸出當前工作目錄中修改的內容,並不包含新加文件,請註意這些內容還沒有添加到本地緩存區。
將修改內容添加到本地緩存區,通配符可以把當前目錄下所有修改的新增的文件都自動添加:
$ git add *
再執行git diff
會發現沒有任何內容輸出,說明當前目錄的修改都被添加到了緩存區,如何查看緩存區內與上次提交之間的差別呢?需要使用--cached
參數:
$ git diff --cached
diff --git a/README.md b/README.md
index 21781dd..410e719 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,3 @@
gitproject
==========
+new line
diff --git a/file1 b/file1
new file mode 100644
index 0000000..fa49b07
--- /dev/null
+++ b/file1
@@ -0,0 +1 @@
+new file
可以看到輸出中已經包含了新加文件的內容,因為file1已經添加到了緩存區。
最後我們提交代碼:
$ git commit -m ‘update code‘
提交後git diff
與git diff --cached
都不會有任何輸出了。
2.比較分支
可以用 git diff 來比較項目中任意兩個分支的差異。
我們首先創建一個新的分支test
,並在該分支上提交一些修改:
# 創建test分支並切換到該分支
$ git branch test
$ git checkout test
# 添加新的一行到file1
$ echo "branch test" >> file1
# 創建新的文件file2
$ echo "new file2" >> file2
# 提交所有修改
$ git add *
$ git commit -m ‘update test branch‘
然後,我們查看test分支和master之間的差別:
$ git diff master test
diff --git a/file1 b/file1
index fa49b07..17059cd 100644
--- a/file1
+++ b/file1
@@ -1 +1,2 @@
new file
+branch test
diff --git a/file2 b/file2
new file mode 100644
index 0000000..80e7991
--- /dev/null
+++ b/file2
@@ -0,0 +1 @@
+new file2
git diff 是一個難以置信的有用的工具,可以找出你項目上任意兩個提交點間的差異。可以使用git help diff
詳細查看其他參數和功能。
3.更多的比較選項
如果你要查看當前的工作目錄與另外一個分支的差別,你可以用下面的命令執行:
# 切換到master
$ git checkout master
# 查看與test分支的區別
$ git diff test
diff --git a/file1 b/file1
index 17059cd..fa49b07 100644
--- a/file1
+++ b/file1
@@ -1,2 +1 @@
new file
-branch test
diff --git a/file2 b/file2
deleted file mode 100644
index 80e7991..0000000
--- a/file2
+++ /dev/null
@@ -1 +0,0 @@
-new file2
你也以加上路徑限定符,來只比較某一個文件或目錄:
$ git diff test file1
diff --git a/file1 b/file1
index 17059cd..fa49b07 100644
--- a/file1
+++ b/file1
@@ -1,2 +1 @@
new file
-branch test
上面這條命令會顯示你當前工作目錄下的file1與test分支之間的差別。
--stat
參數可以統計一下有哪些文件被改動,有多少行被改動:
$ git diff test --stat
file1 | 1 -
file2 | 1 -
2 files changed, 2 deletions(-)
三、分布式的工作流程
1.分布式的工作流程
你目前的項目在/home/shiyanlou/gitproject
目錄下,這是我們的git 倉庫(repository),另一個用戶也想與你協作開發。他的工作目錄在這臺機器上,如何讓他提交代碼到你的git倉庫呢?
首先,我們假設另一個用戶也用shiyanlou用戶登錄,只是工作在不同的目錄下開發代碼,實際工作中不太可能發生,大部分情況都是多個用戶,這個假設只是為了讓實驗簡化。
該用戶需要從git倉庫進行克隆:
# 進入到臨時目錄
$ cd /tmp
# 克隆git倉庫
$ git clone /home/shiyanlou/gitproject myrepo
$ ls -l myrepo
-rw-rw-r-- 1 shiyanlou shiyanlou 31 Dec 22 08:24 README.md
-rw-rw-r-- 1 shiyanlou shiyanlou 9 Dec 22 08:24 file1
這就建了一個新的叫"myrepo"的目錄,這個目錄裏包含了一份gitproject倉庫的克隆。這份克隆和原始的項目一模一樣,並且擁有原始項目的歷史記錄。
在myrepo做了一些修改並且提交:
$ cd myrepo
# 添加新的文件newfile
$ echo "newcontent" > newfile
# 提交修改
$ git add newfile
$ git commit -m "add newfile"
myrepo修改完成後,如果我們想合並這份修改到gitproject
的git倉庫該如何做呢?
可以在倉庫/home/shiyanlou/gitproject
中把myrepo的修改給拉 (pull)下來。執行下面幾條命令:
$ cd /home/shiyanlou/gitproject
$ git pull /tmp/myrepo master
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /tmp/myrepo
* branch master -> FETCH_HEAD
Updating 8bb57aa..866c452
Fast-forward
newfile | 1 +
1 file changed, 1 insertion(+)
create mode 100644 newfile
# 查看當前目錄文件
$ ls [8:28:02]
README.md file1 newfile
這就把myrepo
的主分支合並到了gitproject
的當前分支裏了。
如果gitproject
在myrepo
修改文件內容的同時也做了修改的話,可能需要手工去修復沖突。
如果你要經常操作遠程分支(remote branch),你可以定義它們的縮寫:
$ git remote add myrepo /tmp/myrepo
git pull命令執行兩個操作: 它從遠程分支(remote branch)抓取修改git fetch
的內容,然後把它合並git merge
進當前的分支。
gitproject
裏可以用git fetch
來執行git pull
前半部分的工作, 但是這條命令並不會把抓下來的修改合並到當前分支裏:
$ git fetch myrepo
From /tmp/myrepo
* [new branch] master -> myrepo/master
獲取後,我們可以通過git log
查看遠程分支做的所有修改,由於我們已經合並了所有修改,所以不會有任何輸出:
$ git log -p master..myrepo/master
當檢查完修改後,gitproject
可以把修改合並到它的主分支中:
$ git merge myrepo/master
Already up-to-date.
如果我們在myrepo
目錄下執行git pull
會發生什麽呢?
myrepo
會從克隆的位置拉取代碼並更新本地倉庫,就是把gitproject
上的修改同步到本地:
# 進入到gitproject
$ cd /home/shiyanlou/gitproject
# 添加一行內容到newfile
$ echo "gitproject: new line" >> newfile
# 提交修改
$ git commit -a -m ‘add newline to newfile‘
[master 8c31532] add newline to newfile
1 file changed, 1 insertion(+)
# 進入myrepo目錄
$ cd /tmp/myrepo
# 同步gitproject的所有修改
$ git pull
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /home/shiyanlou/gitproject
8bb57aa..8c31532 master -> origin/master
Updating 866c452..8c31532
Fast-forward
newfile | 1 +
1 file changed, 1 insertion(+)
因為myrepo
是從gitproject
倉庫克隆的,那麽他就不需要指定gitproject
倉庫的地 址。因為Git把gitproject
倉庫的地址存儲到myrepo
的配置文件中,這個地址就是在git pull
時默認使用的遠程倉庫:
$ git config --get remote.origin.url
/home/shiyanlou/gitproject
如果myrepo
和gitproject
在不同的主機上,可以通過ssh協議來執行clone
和pull
操作:
$ git clone localhost:/home/shiyanlou/gitproject test
這個命令會提示你輸入shiyanlou用戶的密碼,用戶密碼隨機,可以點擊屏幕上方的SSH
按鈕查看。
2.公共Git倉庫
開發過程中,通常大家都會使用一個公共的倉庫,並clone到自己的開發環境中,完成一個階段的代碼後可以告訴目標倉庫的維護者來pull
自己的代碼。
如果你和維護者都在同一臺機器上有帳號,那麽你們可以互相從對 方的倉庫目錄裏直接拉所作的修改,git命令裏的倉庫地址也可以是本地的某個目錄名:
$ git clone /path/to/repository
$ git pull /path/to/other/repository
也可以是一個ssh地址:
$ git clone ssh://yourhost/~you/repository
3.將修改推到一個公共倉庫
通過http或是git協議,其它維護者可以通過遠程訪問的方式抓取(fetch)你最近的修改,但是他們 沒有寫權限。如何將本地私有倉庫的最近修改主動上傳到公共倉庫中呢?
最簡單的辦法就是用git push
命令,推送本地的修改到遠程Git倉庫,執行下面的命令:
$ git push ssh://yourserver.com/~you/proj.git master:master
或者
$ git push ssh://yourserver.com/~you/proj.git master
git push
命令的目地倉庫可以是ssh
或http/https
協議訪問。
4.當推送代碼失敗時要怎麽辦
如果推送(push)結果不是快速向前fast forward
,可能會報像下面一樣的錯誤:
error: remote ‘refs/heads/master‘ is not an ancestor of
local ‘refs/heads/master‘.
Maybe you are not up-to-date and need to pull first?
error: failed to push to ‘ssh://yourserver.com/~you/proj.git‘
這種情況通常是因為沒有使用git pull
獲取遠端倉庫的最新更新,在本地修改的同時,遠端倉庫已經變化了(其他協作者提交了代碼),此時應該先使用git pull
合並最新的修改後再執行git push
:
$ git pull
$ git push ssh://yourserver.com/~you/proj.git master
四、Git標簽
1.輕量級標簽
我們可以用 git tag不帶任何參數創建一個標簽(tag)指定某個提交(commit):
# 進入到gitproject目錄
$ cd /home/shiyanlou/gitproject
# 查看git提交記錄
$ git log
# 選擇其中一個記錄標誌位stable-1的標簽,註意需要將後面的8c315325替換成倉庫下的真實提交內,commit的名稱很長,通常我們只需要寫前面8位即可
$ git tag stable-1 8c315325
# 查看當前所有tag
$ git tag
stable-1
這樣,我們可以用stable-1 作為提交 8c315325
的代稱。
前面這樣創建的是一個“輕量級標簽”。
如果你想為一個tag添加註釋,或是為它添加一個簽名, 那麽我們就需要創建一個 "標簽對象"。
標簽對象
git tag
中使用-a
, -s
或是 -u
三個參數中任意一個,都會創建一個標簽對象,並且需要一個標簽消息(tag message)來為tag添加註釋。 如果沒有-m
或是 -F
這些參數,命令執行時會啟動一個編輯器來讓用戶輸入標簽消息。
當這樣的一條命令執行後,一個新的對象被添加到Git對象庫中,並且標簽引用就指向了一個標簽對象,而不是指向一個提交,這就是與輕量級標簽的區別。
下面是一個創建標簽對象的例子:
$ git tag -a stable-2 8c315325 -m "stable 2"
$ git tag
stable-1
stable-2
2.簽名的標簽
簽名標簽可以讓提交和標簽更加完整可信。如果你配有GPG key
,那麽你就很容易創建簽名的標簽。首先你要在你的 .git/config
或 ~/.gitconfig
裏配好key。
下面是示例:
[user]
signingkey = <gpg-key-id>
你也可以用命令行來配置:
$ git config (--global) user.signingkey <gpg-key-id>
現在你可以在創建標簽的時候使用-s
參數來創建“簽名的標簽”:
$ git tag -s stable-1 1b2e1d63ff
如果沒有在配置文件中配GPG key,你可以用-u
參數直接指定。
$ git tag -u <gpg-key-id> stable-1 1b2e1d63ff
五、小結
本節學習了下面知識點:
- git diff
- 分布式的工作流程
- git tag
對於初學者,如果不想深入git強大的高級功能的話,學完這個實驗就可以了,因為後續實驗內容用到的比較少,並且理解難度大。如果仍然感興趣,建議使用一段時間git後再仔細學習後續實驗,會有更好的收獲。
Git基本用法2