1. 程式人生 > >Git基本用法2

Git基本用法2

新增 block one 其中 gin 參數 normal 密碼 nor

二、比較內容

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 diffgit 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的當前分支裏了。

如果gitprojectmyrepo修改文件內容的同時也做了修改的話,可能需要手工去修復沖突。

如果你要經常操作遠程分支(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

如果myrepogitproject在不同的主機上,可以通過ssh協議來執行clonepull操作:

$ 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命令的目地倉庫可以是sshhttp/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