使用git進行版本控制


本文將介紹一種強大的版本控制工具,git的基本使用。與之前svn工具類似,首先給出一些常見的使用需求,然後以這些需求爲中心,來展開git的學習過程。由於我也是在學習當中所以其中不準確之處可以通過後面的聯繫方式來交流,謝謝。^_^

主要內容:

簡介

基本概念

常用命令

具體實踐

其它

簡介

=========

本文將介紹一種強大的版本控制工具,git的基本使用。與之前svn工具類似,本文首先給出一些常見的使用需求,然後以這些需求爲中心,來展開git的學習過程。

帶着問題學習:

從svn過渡過來的用戶初次使用git,會遇到許多的問題,這裏以習慣了svn用戶的角度,來考慮學習使用git需要解決的一些問題:

*如何查看庫路徑信息?

*如何合併和創建分支?

*如何恢復到指定的版本?

*如何查看指定版本的信息?

*如何理解分佈式存儲?

*什麼是索引?什麼是工作樹?

*如何查看log詳細信息?

這些問題也可作爲學習之後的練習,我們可以嘗試自己來解決一下^_^。

基本概念

=========

這部分內容,大部分來自git的man手冊,更爲具體的信息可以參見"man gittutorial"的命令輸出。

svn和git都是用於進行代碼版本控制的工具。但是兩者有許多不同,這裏只對兩個重要的地方:分佈式管理、是否可更改歷史,進行說明,隨着以後的學習,我們會發現兩者之間更多的不同之處。

使用過svn的用戶可知svn有兩個比較重要的特點:(1)在svn中一個項目已經提交的歷史無法被修改。(2)svn服務器通過其中的某個統一的代碼庫集中管理某個項目代碼,其他部分的代碼都是這個服務器中庫的工作拷貝,提交時都提交到這個統一的服務器代碼庫中,不同的svn代碼庫之間不能相互同步不同的代碼修改(當然這並不是絕對的,我們可以通過特殊方法修改svn的歷史,也可以讓svn實現“分佈”管理)。

而對於git,至少在這兩點上與svn不同:(1)在git中,我們可以任意修改已經提交的內容的歷史信息。(2)git中的服務器可以不只一個,服務器中同一項目的的代碼庫也可以不止是一個。因爲我們可以將一臺機器器上面的git代碼庫拷貝到另外一臺機器上,然後提交的時候只往那個庫中提交,而這些庫之間還可以相互同步它們之間不同的修改部分。

下面是學習git時需要了解的一些重要內容,其中有些涉及到的內容,在後面的部分會詳細提及。

1、git中的"status"和"diff"以及"add"和"commit"

git中,每次提交修改文件之前要add,然後再commit。git的add命令和許多版本控制系統不一樣,不是增加新增的文件,而是以內容爲單位,將最新修改的內容,添加到一個臨時的索引中,等待commit。

實踐發現,如果修改一個文件,然後diff查看修改,然後add,然後再修改,然後在commit,那麼只把第一次修改提交了。commit的時候,建議遵守這樣的格式:開始是簡短的一行描述(不超過50字符),然後根着一個空行,最後是詳細的描述。這樣,就便於有些軟件將開始的簡短行作爲email的題目,後面的詳細描述作爲email的信息內容,完成自動化轉換。

另外,如果修改了一個文件然後沒有"git add",那麼可以用"git diff"查看修改的內容,而"git status"無法看到修改的內容;當"git add"這個文件之後,用"git diff"就看不到這個內容了,用"git status"就可以看到。例如:

lv-k@quietheart:~/temp/temp/git_t$ echo hello5 >>hello

lv-k@quietheart:~/temp/temp/git_t$ git diff

diff --git a/hello b/hello

index 0863c71..bba0e39 100644

--- a/hello

+++ b/hello

@@ -3,3 +3,4 @@ hello1

hello2

hello3

hello4

+hello5 <===這裏說明在"git add hello"之前,對hello文件進行了修改。

lv-k@quietheart:~/temp/temp/git_t$ git status

# On branch master

# Changes not staged for commit: <===這裏說明修改沒有被添加(stage),並且提示用"git add"。

# (use "git add <file>..." to update what will be committed)

# (use "git checkout -- <file>..." to discard changes in working directory)

#

# modified: hello <===這裏說明修改了hello文件

#

no changes added to commit (use "git add" and/or "git commit -a") <===說明不會提交修改,可用"git add"或者"git commit -a"來提交修改。

lv-k@quietheart:~/temp/temp/git_t$ git add hello

lv-k@quietheart:~/temp/temp/git_t$ git diff <===添加之後,沒有任何輸出。

lv-k@quietheart:~/temp/temp/git_t$ git status

# On branch master

# Changes to be committed: <===提示將會提交修改的內容,並且提示用"git reset"來取消stage。

# (use "git reset HEAD <file>..." to unstage)

#

# modified: hello

#

lv-k@quietheart:~/temp/temp/git_t$ echo hello6 >>hello <===提交之前又修改了

lv-k@quietheart:~/temp/temp/git_t$ git diff

diff --git a/hello b/hello

index bba0e39..34e8bc5 100644

--- a/hello

+++ b/hello

@@ -4,3 +4,4 @@ hello2

hello3

hello4

hello5

+hello6 <===顯示最新沒有add的修改

lv-k@quietheart:~/temp/temp/git_t$ git status

# On branch master

# Changes to be committed: <===顯示提交時會提交一部分修改

# (use "git reset HEAD <file>..." to unstage)

#

# modified: hello

#

# 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: hello

#

lv-k@quietheart:~/temp/temp/git_t$ git add hello

lv-k@quietheart:~/temp/temp/git_t$ git diff

lv-k@quietheart:~/temp/temp/git_t$ git status

# On branch master

# Changes to be committed:

# (use "git reset HEAD <file>..." to unstage)

#

# modified: hello

#

lv-k@quietheart:~/temp/temp/git_t$ git reset hello <===撤消"git add"的動作

Unstaged changes after reset:

M hello

lv-k@quietheart:~/temp/temp/git_t$ git diff

diff --git a/hello b/hello

index 0863c71..34e8bc5 100644

--- a/hello

+++ b/hello

@@ -3,3 +3,5 @@ hello1

hello2

hello3

hello4

+hello5

+hello6

lv-k@quietheart:~/temp/temp/git_t$ git status

# On branch 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: hello

#

no changes added to commit (use "git add" and/or "git commit -a")

lv-k@quietheart:~/temp/temp/git_t$ git add hello <===再次"git add"

lv-k@quietheart:~/temp/temp/git_t$ git diff

lv-k@quietheart:~/temp/temp/git_t$ git status

# On branch master

# Changes to be committed:

# (use "git reset HEAD <file>..." to unstage)

#

# modified: hello

#

對於以上內容中出現的命令,我們可以在後續的學習中看到。

2、pull、push和fetch

git中的pull子命令做兩個工作:從遠處庫的分支fetch相應的修改,然後將修改合併到當前分支。如果發生衝突,那麼也會進行fetch但是會拒絕對衝突的文件進行合併(這時需要解決衝突然後再次pull???)。

git-fetch用於從另一個reposoitory下載objects和refs,但是並不提交到本地庫。其中<repository>表示遠端的倉庫路徑。其中<refspec>的標準格式應該爲<src>:<dst>,<src>表示源的分支,如果<dst>不爲空,則表示本地的分支;如果爲空,則使用當前分支。

而push和pull相反,是向遠端發送本地提交的修改,當然需要讓遠端設置成可以接受本地提交的修改。具體參見後面的實踐。

3、常用常量和範圍表示

有一些常用常量可以表示特定的版本,它們是:

HEAD:表示最近一次的commit。

MERGE_HEAD:如果是merge產生的commit,那麼它表示除HEAD之外的另一個父母分支。

FETCH_HEAD:使用git-fetch獲得的object和ref的信息都存儲在這裏,這些信息是爲日後git-merge準備的。

HEAD^:表示HEAD父母的信息

HEAD^^:表示HEAD父母的父母的信息

HEAD~4:表示HEAD上溯四代的信息

HEAD^1:表示HEAD的第一個父母的信息(和HEAD^相同)

HEAD^2:表示HEAD的第二個父母的信息

COMMIT_EDITMSG:最後一次commit時的提交信息。

當我們表示兩個特定版本之間的內容的時候,一般有如下表示:

使用".."表示兩個提交版本之間的內容:

例如:“$ git log v2.5..v2.6”,表示查看v2.5到v2.6之間的log信息;再如:“HEAD..FETCH_HEAD”,表示顯示抓取的開始之後的信息不顯示HEAD開始之後的信息(也就是顯示的時候不顯示自HEAD以來本地庫的信息,而是隻顯示遠端的信息);還有使用"$ git log v2.5.."表示自v2.5之後提交的內容。

使用"..."表示包含更多的範圍:

例如“HEAD...FETCH_HEAD”,可以用來查看兩者都修改了什麼,是兩者分別修改的而不是同時修改的。

常用命令

=========

這裏給出常用的基本命令。

*獲取git的子命令的幫助信息的方式:

$man git-log

$git help log

這裏,子命令用"git log"或"git log --graph"之類的log子命令進行舉例。

*爲git添加自己的名字以及郵箱信息:

$ git config --global user.name "Your Name Comes Here"

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

另外,通過當前目錄的".git/config",來查看類似"svn info"輸出的url相關的信息等等。

**將一個目錄添加到git控制中

過程如下:

*初始化目錄:

$ tar xzf project.tar.gz

$ cd project

$ git init

*將當前目錄下所有文件的快照(snap)加入git

$ git add .

這樣會告訴git將當前目錄下所有的修改的文件,以及以前不在git下面的文件等的當前狀態,添加到git的一個臨時"stage area"中(但是還沒有被保存下來),git稱它爲索引(index)。

*將索引(index)的內容保存到git庫中:

$git commit

這樣會提示你輸入日誌信息,之後就將當前的目錄所有最新內容存放到git中管理了。另外需要注意的是,"commit"有一個"--amend"選項,可以給修改版本的信息,例如註釋信息,具體參見man手冊。

**

**修改文件並提交

*將新增或者修改等變化的文件添加到git的索引(index)中:

$ git add file1 file2 file3

這裏,添加之後,後面的commit命令將會把此次添加的內容都提交上去(由此可見git的"add"添加的不僅僅是文件,它是以內容爲單位的,添加的是當前的修改)。

*提交之前,查看修改狀態:

$git diff --cached

或者

$git status

這裏,diff如果沒有--cached選項,信息更多(有則只顯示沒有"add"的內容),status顯示的使概要的簡潔信息。

*提交修改:

$ git commit

這樣,會提示你輸入日誌信息,然後更新git庫的版本。

其實,每次提交修改文件之前都要用"add"將修改的內容添加進去,然後才能commit,如果合併兩步,可以這樣:

$git commit -a

這樣會自動將修改的文件(不包含新增的文件)添加到索引,並且提交。

注意,提交時候的日誌信息,最好用一個簡單行開始,然後一個空行,因爲許多工具將其日誌第一行自動轉換作爲郵件標題,剩下內容作爲郵件內容。

**

**查看歷史信息

$git log

或者$git log -p

或者$git log --stat --summary

或者$git log --graph

這裏,-p查看完整歷史消息並且重定向到"less"之類的pager程序查看,--stat --summary也會重定向到pager但是信息比較簡要,而只有"git log"則更簡要並且不會將輸出重定向到pager程序中。使用"git log --graph"可以用文本圖形的方式顯示版本之間的關係。

**

**分支管理

*創建分支:

$ git branch experimental

*查看分支:

$ git branch

這樣,會列出所有分支,並且當前分支前面用'*'標識出來。

*切換分支:

$ git checkout experimental

這樣,會切換到experimental分支,默認分支是'master'分支,它是被自動創建的。

*合併分支:

$ git merge experimental

這裏,如果正常則合併成功,如果衝突,那麼衝突文件中會有衝突標記。合併之後可以提交。使用diff可以查看衝突。

*刪除分支:

$ git branch -d experimental

這裏分支要確保被合併到上層才行,如果不考慮合併狀態,那麼使用-D代替-d。

**

**使用git合作開發

假設用戶A有一個git庫,地址爲:/home/alice/project

B和A同爲一臺機器,其用戶主目錄爲/home/bob。

*B在A庫的基礎上面工作:

bob$ git clone /home/alice/project myrepo

(edit files)

bob$ git commit -a

(repeat as necessary)

這裏,首先B從A拷貝一份庫到本地,然後在本地進行修改,並且提交,這個時候,提交的內容都是提交到B自己的庫中。

*A合併B的修改:

alice$ cd /home/alice/project

alice$ git pull /home/bob/myrepo master

這裏,當A想要合併B的內容的時候,可以通過pull實現;如果A已經在本地有過一些修改,那麼可能會出現並處理一些合併的衝突問題。其實,"pull=fetch+merge",就是先獲取遠端修改的內容,然後合併到本地。

*只查看B的修改,但是不合並:

alice$ git fetch /home/bob/myrepo master

alice$ git log -p HEAD..FETCH_HEAD

這裏,fetch只是將修改信息抓取下來,並不進行合併,這樣就能夠在合併之前看到遠端(抓取端)進行了哪些修改HEAD是最新的一次commit,FETCH_HEAD使抓取端的信息。HEAD..FETCH_HEAD表示顯示抓取的開始之後的信息不顯示HEAD開始之後的信息(也就是顯示的時候不顯示自HEAD以來本地庫的信息,而是隻顯示遠端的信息).而用HEAD...FETCH_HEAD可以用來查看兩者都修改了什麼,是兩者分別修改的而不是同時修改的。

*A設置fetch時使用的B的遠端位置的簡寫:

alice$ git remote add bob /home/bob/myrepo

如果A經常和B進行交互,那麼可以使用remote命令,這樣以後A便可以通過這個簡寫來獲取B的修改而不用輸入完整名稱了。

*A使用remote設置的B的簡寫來獲取B的修改併合並:

alice$ git fetch bob

alice$ git merge bob/master

這裏,也可以用如下命令來完成合並:

alice$ git pull . remotes/bob/master

*B獲取A最新修改的內容:

bob$ git pull

這裏,B不需要給出A的庫的位置,因爲B是來自A的一個拷貝,A的位置信息在拷貝的時候被記錄到庫的配置中了,這個位置信息在B使用沒有參數的pull的時候會被自動地應用。使用如下命令可以查看B的配置中的這個url信息:

bob$ git config --get remote.origin.url

/home/alice/project

*查看B來自A的原始master拷貝:

bob$ git branch -r

origin/master

拷貝B的時候,git會自動將一份原始的A的master分支拷貝到"origin/master"中,用這個命令可以看到。

*與A在不同主機上的B拷貝A的庫到本地:

bob$ git clone alice.org:/home/alice/project myrepo

這裏,可以使用特定的本地協議例如rsync或者http,可以查看git-pull的信息來獲取更多幫助。另外,查看git-push(1)和gitcvs-migration(7),可以知道git還可以設置成像cvs那樣集中控制版本的模式。

由上面的過程我們可以知道,git版本控制工具中分佈式管理的含義。與svn不同的是,在svn中,只能有一個svn服務器集中存放版本控制庫,其他的客戶端全部都是這個版本庫的工作拷貝,提交的時候全部都提交到這個集中的svn庫中或者庫的某個分支中。git分步式管理的意思就是可以將一個由git創建的版本控制庫拷貝到另外的地方,所有這個git庫的拷貝都可以各自作爲一個“版本控制中心”,管理自己工作拷貝以及本地分支的提交,同時這些庫之間還可以相互合併其修改到另外的庫的特定分支中。

**

**指定版本操作

這裏將git中的版本號假設爲特定的commit的id。

*查看所有歷史信息:

$git log

這樣會顯示所有的歷史信息,包括"commit"的id,使用"git log --graph"會以文本圖形的方式直觀地顯示出每個歷史版本之間的合併關係等。其實,我們可以將歷史看成一系列的"commit"。

*查看特定id的歷史信息:

$git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7

$git show c82a22c39c

這樣,我們可以看到指定"commit"的id爲"c82a22c39cbc32576f64f5c6b3f24b99ea8149c7"的歷史信息。這裏,只要能夠保證前綴唯一,也可指定部分id的前綴作爲相應歷史的標識。

*查看當前分支當前的歷史狀態:

$git show HEAD

這裏,HEAD表示當前分支最新版本。關於查看時候指定的類似"HEAD"的常量大致如下:

HEAD:表示最近一次的commit。

MERGE_HEAD:如果是merge產生的commit,那麼它表示除HEAD之外的另一個父母分支。

FETCH_HEAD:使用git-fetch獲得的object和ref的信息都存儲在這裏,這些信息是爲日後git-merge準備的。

HEAD^:表示HEAD父母的信息

HEAD^^:表示HEAD父母的父母的信息

HEAD~4:表示HEAD上溯四代的信息

HEAD^1:表示HEAD的第一個父母的信息(和HEAD^相同)

HEAD^2:表示HEAD的第二個父母的信息

COMMIT_EDITMSG:最後一次commit時的提交信息。

*自定義"commit"的id名稱:

$ git tag v2.5 1b2e1d63ff

這樣定義之後,就可以使用"v2.5"這樣比較容易理解的方式來引用"1b2e1d63ff"這種看起來沒有意義的字符串,如果想要和別人共享這個定義的名稱,需要創建一個"tag"對象,並且給它"sign",具體參見"git help tag"。

*比較兩個不同的版本:

$git diff HEAD bc32576f64f5c6b3f24b99ea8149c7

這裏,比較"HEAD"和"bc32576f64f5c6b3f24b99ea8149c7"之間的區別,也可以使用自己定義的名稱。

*回退到指定版本,清除該版本之後所有的信息:

$ git reset --hard HEAD^

這樣將會把當前工作分支的內容回退到"HEAD^"版本。注意,這個命令不僅會把當前的修改給移除,而且還會把自"HEAD^"以後的所有"commit"給刪除(HEAD^版本本身保留爲當前的HEAD),如果當前的分支是唯一的分支的話,那麼運行這個命令之後,之前"HEAD^"以後的修改將會完全丟失(當然可以通過"pull"再將之前的HEAD拉取回來,但是自己沒有提交的本地修改是無法找回來的了);另外如果在一個公共的分支上面執行這個命令將會導致其他開發者pull的時候都進行一遍這個清除的工作,如果不加--hard選項,那麼可能當前HEAD基礎上有修改的情況導致這個命令不會成功。

*回退到指定版本,並作爲新版本提交上去(保留該版本之後所有的信息):

$ git revert HEAD^

這樣只會把內容回退爲HEAD^之前的版本(即HEAD^^),再將這樣的內容做爲新的HEAD提交上去,原來的HEAD變成HEAD^(即在庫中保留HEAD^之後的版本的提交,而不像"reset"那樣完全清除)。這裏,運行之後,會打開一個編輯窗口讓你編輯提交的log信息,退出就直接提交了,或者"revert"命令也有不編輯提交log信息的選項。

*使用checkout回退

$ git checkout v2.5

這樣,會將當前v2.5版本重新檢出,效果是使用v2.5做爲當前的HEAD了,但是,原來的HEAD對應的commit id還存在於庫中,可以使用那個id用"checkout"重新檢回。另外,如果檢出v2.5之後做了修改並且提交到庫中,那麼會以v2.5爲基礎重新生成一個版本,並且提交上去,這時候可以再用原來那個HEAD檢查出,但是就“隱藏”了這個v2.5之後提交的新HEAD相關的一系列修改版本,這時候一般git會提醒你爲此次提交創建一個新分支,並且會給出提示命令。實踐發現,如果修改了沒有提交,那麼checkout會有問題,就是修改的內容併到了checkout的版本中,具體需要實踐。

*從指定版本搜索某個字符串:

$ git grep "hello" v2.5

這樣將會從"v2.5"這個自定義的commit名字的版本中的所有文件搜索"hello"字符串。如果沒有指定"v2.5"類似的commit的號碼的話,將會從當前路徑搜索這個"hello"字符串。

*介於v2.5和v2.6之間的commit信息:

$ git log v2.5..v2.6

*介於v2.5之後的commit信息:

$ git log v2.5..

*兩週以前的commit信息:

$ git log --since="2 weeks ago" # commits from the last 2 weeks

*自Makefile修改之後的commit信息:

$ git log v2.5.. Makefile # commits since v2.5 which modify

*兩個沒有前後關係的commit之間的信息:

$git log v2.5 s2.5

這裏,v2.5和s2.5是兩個沒有直系關係的版本,這樣會只顯示關於s2.5的提交信息。

*指定某個版本的文件並進行操作:

$ git diff v2.5:Makefile HEAD:Makefile.in

$ git show v2.5:Makefile

這裏,我們運行操作文件的命令的時候,可以給文件名稱添加一個commit的ID,以標識對那個版本的文件進行操作。

**

具體實踐

=========

下面用一個具體的實踐展示使用git的簡單過程。若有更多內容,再做更新。

1、簡單命令

*查看幫助:

$ git

具體如下:

lv-k@quietheart:~/temp/git_test$ git

usage: git [--version] [--exec-path[=<path>]] [--html-path]

[-p|--paginate|--no-pager] [--no-replace-objects]

[--bare] [--git-dir=<path>] [--work-tree=<path>]

[-c name=value] [--help]

<command> [<args>]

The most commonly used git commands are:

add Add file contents to the index

bisect Find by binary search the change that introduced a bug

branch List, create, or delete branches

checkout Checkout a branch or paths to the working tree

clone Clone a repository into a new directory

commit Record changes to the repository

diff Show changes between commits, commit and working tree, etc

fetch Download objects and refs from another repository

grep Print lines matching a pattern

init Create an empty git repository or reinitialize an existing one

log Show commit logs

merge Join two or more development histories together

mv Move or rename a file, a directory, or a symlink

pull Fetch from and merge with another repository or a local branch

push Update remote refs along with associated objects

rebase Forward-port local commits to the updated upstream head

reset Reset current HEAD to the specified state

rm Remove files from the working tree and from the index

show Show various types of objects

status Show the working tree status

tag Create, list, delete or verify a tag object signed with GPG

See 'git help <command>' for more information on a specific command.

這裏,通過這個命令我們可以看見git最常用的一些命令。

*創建一個空白的版本庫:

$ git init

具體如下:

lv-k@quietheart:~/temp/git_test$ git init

Initialized empty Git repository in /home/lv-k/temp/git_test/.git/

lv-k@quietheart:~/temp/git_test$ ls -a

. .. .git

*向版本庫中導入數據:

$ git add example hello mydir

$ git commit -m 'initial commit contents'

實際上,可以使用"git add ."將當前目錄加入。具體過程如下:

(1)添加文件

lv-k@quietheart:~/temp/git_test$ echo "hello world" >hello

lv-k@quietheart:~/temp/git_test$ echo "my example" >example

lv-k@quietheart:~/temp/git_test$ mkdir mydir

lv-k@quietheart:~/temp/git_test$ cd mydir/

lv-k@quietheart:~/temp/git_test/mydir$ echo "dir contents" >dir_content

lv-k@quietheart:~/temp/git_test/mydir$ cd ..

lv-k@quietheart:~/temp/git_test$ ls

example hello mydir

lv-k@quietheart:~/temp/git_test$ tree

.

├── example

├── hello

└── mydir

└── dir_content

1 directory, 3 files

(2)將文件添加到git庫

lv-k@quietheart:~/temp/git_test$ git add example hello mydir

lv-k@quietheart:~/temp/git_test$ git status

# On branch master

#

# Initial commit

#

# Changes to be committed:

# (use "git rm --cached <file>..." to unstage)

#

# new file: example

# new file: hello

# new file: mydir/dir_content

#

lv-k@quietheart:~/temp/git_test$ git commit -m 'initial commit contents'

[master (root-commit) 098e14c] initial commit contents

Committer: lv-k <lv-k@quietheart.(none)>

Your name and email address were configured automatically based

on your username and hostname. Please check that they are accurate.

You can suppress this message by setting them explicitly:

git config --global user.name "Your Name"

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

After doing this, you may fix the identity used for this commit with:

git commit --amend --reset-author

3 files changed, 3 insertions(+), 0 deletions(-)

create mode 100644 example

create mode 100644 hello

create mode 100644 mydir/dir_content

(3)查看日誌

lv-k@quietheart:~/temp/git_test$ git log

commit 098e14c671f8cef3507a8b43fba7b386892ed5bc

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 16:59:04 2012 +0800

initial commit contents

lv-k@quietheart:~/temp/git_test$ tree .git/

.git/

├── branches

├── COMMIT_EDITMSG

├── config

├── description

├── HEAD

├── hooks

│ ├── applypatch-msg.sample

│ ├── commit-msg.sample

│ ├── post-commit.sample

│ ├── post-receive.sample

│ ├── post-update.sample

│ ├── pre-applypatch.sample

│ ├── pre-commit.sample

│ ├── prepare-commit-msg.sample

│ ├── pre-rebase.sample

│ └── update.sample

├── index

├── info

│ └── exclude

├── logs

│ ├── HEAD

│ └── refs

│ └── heads

│ └── master

├── objects

│ ├── 09

│ │ └── 8e14c671f8cef3507a8b43fba7b386892ed5bc

│ ├── 31

│ │ └── 96f9d3ac40f9662f5398567d49de3e2c7dad7d

│ ├── 3b

│ │ └── 18e512dba79e4c8300dd08aeb37f8e728b8dad

│ ├── 6e

│ │ └── 93434ddde9f6fa8729896e2b52fb3ef9280b5a

│ ├── 70

│ │ └── 4d3223540b8924fb8c4bd565db016c4e601633

│ ├── cc

│ │ └── 1ef173226e0a0a130dad14e0108ec8b62eeb93

│ ├── info

│ └── pack

└── refs

├── heads

│ └── master

└── tags

18 directories, 25 files

*修改並查看修改:

#git diff

具體如下:

lv-k@quietheart:~/temp/git_test$ echo 'hello world' >>hello

lv-k@quietheart:~/temp/git_test$ git diff

diff --git a/hello b/hello

index 3b18e51..10bda51 100644

--- a/hello

+++ b/hello

@@ -1 +1,2 @@

hello world

+hello world

*提交修改:

$ git commit -a -m 'add modify'

這裏,提交不能只用"commit",應該先"add"再"commit",其實"add"命令添加的不是文件而是新變化的內容,如果將兩步合併爲一個命令,可以使用像這裏帶有"-a"選項的"commit",將修改的內容添加到索引緩存並且提交。

具體過程如下:

(1)只使用"commit"提交,無法成功:

lv-k@quietheart:~/temp/git_test$ git commit -m 'modify'

# On branch 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: hello

#

no changes added to commit (use "git add" and/or "git commit -a")

提交之後,查看提交的日誌如下:

lv-k@quietheart:~/temp/git_test$ git log

commit 098e14c671f8cef3507a8b43fba7b386892ed5bc

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 16:59:04 2012 +0800

initial commit contents

lv-k@quietheart:~/temp/git_test$ git diff

diff --git a/hello b/hello

index 3b18e51..10bda51 100644

--- a/hello

+++ b/hello

@@ -1 +1,2 @@

hello world

+hello world

由此可見,只是"git commit"無法成功提交,因爲git中的概念是首先將修改的文件"add",然後再commit,所以如果不想用add命令,那麼就用-a的commit。

(2)使用帶有"-a"選項的"commit",提交成功。

根據前面的提示,再次嘗試如下:

lv-k@quietheart:~/temp/git_test$ git commit -a -m 'add modify'

[master 07ee8b6] add modify

Committer: lv-k <lv-k@quietheart.(none)>

Your name and email address were configured automatically based

on your username and hostname. Please check that they are accurate.

You can suppress this message by setting them explicitly:

git config --global user.name "Your Name"

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

After doing this, you may fix the identity used for this commit with:

git commit --amend --reset-author

1 files changed, 1 insertions(+), 0 deletions(-)

lv-k@quietheart:~/temp/git_test$ git diff

lv-k@quietheart:~/temp/git_test$ git log

commit 07ee8b68e90a470aec9a5194079e54332093fc70

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 17:29:00 2012 +0800

add modify

commit 098e14c671f8cef3507a8b43fba7b386892ed5bc

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 16:59:04 2012 +0800

initial commit contents

如此可見,提交成功。

(嘗試使用"git add hello"之後,用"git diff"沒有輸出了,但是"git status"有修改的輸出,使用"git reset"可以恢復成沒有"git add hello"的狀態)。

2、關於分支

*查看當前分支:

$ git branch

具體如下:

lv-k@quietheart:~/temp/git_test$ git branch

* master

這裏,可知當前處於主分支"master",當前分支用'*'和高亮標記出來。

*創建分支:

$ git branch quietheart

具體如下:

lv-k@quietheart:~/temp/git_test$ git branch quietheart

lv-k@quietheart:~/temp/git_test$ git branch

* master

quietheart

這裏,創建了一個'quietheart'分支,但是創建之後並沒有切換過去。

*切換分支:

$ git checkout quietheart

具體如下:

lv-k@quietheart:~/temp/git_test$ git checkout quietheart

Switched to branch 'quietheart'

lv-k@quietheart:~/temp/git_test$ git branch

master

* quietheart

這裏,使用'checkout'命令切換到了指定的分支。

*分別在分支中進行修改:

lv-k@quietheart:~/temp/git_test$ git checkout master

lv-k@quietheart:~/temp/git_test$ echo 'change in master' >>hello

lv-k@quietheart:~/temp/git_test$ git commit -m 'change in master' -a

lv-k@quietheart:~/temp/git_test$ git checkout quietheart

lv-k@quietheart:~/temp/git_test$ echo 'changed in quietheart' >>example

lv-k@quietheart:~/temp/git_test$ git commit -m 'change in quietheart' -a

具體如下:

lv-k@quietheart:~/temp/git_test$ git checkout master

Switched to branch 'master'

lv-k@quietheart:~/temp/git_test$ git branch

* master

quietheart

lv-k@quietheart:~/temp/git_test$ ls

example hello mydir

lv-k@quietheart:~/temp/git_test$ echo 'change in master' >>hello

lv-k@quietheart:~/temp/git_test$ git diff

diff --git a/hello b/hello

index 1b11f8b..60cacc0 100644

--- a/hello

+++ b/hello

@@ -1,3 +1,4 @@

hello world

hello world

hello world

+change in master

lv-k@quietheart:~/temp/git_test$ git commit -m 'change in master' -i

fatal: No paths with --include/--only does not make sense.

lv-k@quietheart:~/temp/git_test$ git commit -m 'change in master' -a

[master d8f32e0] change in master

Committer: lv-k <lv-k@quietheart.(none)>

Your name and email address were configured automatically based

on your username and hostname. Please check that they are accurate.

You can suppress this message by setting them explicitly:

git config --global user.name "Your Name"

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

After doing this, you may fix the identity used for this commit with:

git commit --amend --reset-author

1 files changed, 1 insertions(+), 0 deletions(-)

lv-k@quietheart:~/temp/git_test$ git diff

lv-k@quietheart:~/temp/git_test$ git log

commit d8f32e0e0b16e6dc499d5295a8a13ec3938664f8

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 17:54:10 2012 +0800

change in master

commit fa4abf6455aa01cf7d74810b96e2279983287fc8

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 17:41:51 2012 +0800

add modify2

commit 07ee8b68e90a470aec9a5194079e54332093fc70

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 17:29:00 2012 +0800

add modify

commit 098e14c671f8cef3507a8b43fba7b386892ed5bc

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 16:59:04 2012 +0800

initial commit contents

這裏,在執行本例子之前提交過一次,而那次提交沒有在本文檔記錄所以所以多了一條記錄'add modify2'。

lv-k@quietheart:~/temp/git_test$ git checkout quietheart

Switched to branch 'quietheart'

lv-k@quietheart:~/temp/git_test$ git log

commit fa4abf6455aa01cf7d74810b96e2279983287fc8

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 17:41:51 2012 +0800

add modify2

commit 07ee8b68e90a470aec9a5194079e54332093fc70

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 17:29:00 2012 +0800

add modify

commit 098e14c671f8cef3507a8b43fba7b386892ed5bc

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 16:59:04 2012 +0800

initial commit contents

lv-k@quietheart:~/temp/git_test$ echo 'changed in quietheart' >>example

lv-k@quietheart:~/temp/git_test$ git diff

diff --git a/example b/example

index 6e93434..0706323 100644

--- a/example

+++ b/example

@@ -1 +1,2 @@

my example

+changed in quietheart

lv-k@quietheart:~/temp/git_test$ git commit -m 'change in quietheart' -a

[quietheart 8a95074] change in quietheart

Committer: lv-k <lv-k@quietheart.(none)>

Your name and email address were configured automatically based

on your username and hostname. Please check that they are accurate.

You can suppress this message by setting them explicitly:

git config --global user.name "Your Name"

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

After doing this, you may fix the identity used for this commit with:

git commit --amend --reset-author

1 files changed, 1 insertions(+), 0 deletions(-)

lv-k@quietheart:~/temp/git_test$ git log

commit 8a95074a30e32a4df3cdf50648fce2d6a0a73a97

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 18:00:10 2012 +0800

change in quietheart

commit fa4abf6455aa01cf7d74810b96e2279983287fc8

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 17:41:51 2012 +0800

add modify2

commit 07ee8b68e90a470aec9a5194079e54332093fc70

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 17:29:00 2012 +0800

add modify

commit 098e14c671f8cef3507a8b43fba7b386892ed5bc

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 16:59:04 2012 +0800

initial commit contents

*合併某分支到當前分支最新:

$ git checkout master

$ git merge quietheart

具體過程如下:

lv-k@quietheart:~/temp/git_test$ git branch

master

* quietheart

lv-k@quietheart:~/temp/git_test$ git checkout master

Switched to branch 'master'

lv-k@quietheart:~/temp/git_test$ git branch

* master

quietheart

lv-k@quietheart:~/temp/git_test$ git merge quietheart

Merge made by recursive.

example | 1 +

1 files changed, 1 insertions(+), 0 deletions(-)

lv-k@quietheart:~/temp/git_test$ git diff

lv-k@quietheart:~/temp/git_test$ git log

commit 83548b1a87668a5dbd606c6bcefdc984970ffb40

Merge: d8f32e0 8a95074

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 18:09:51 2012 +0800

Merge branch 'quietheart'

commit 8a95074a30e32a4df3cdf50648fce2d6a0a73a97

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 18:00:10 2012 +0800

change in quietheart

commit d8f32e0e0b16e6dc499d5295a8a13ec3938664f8

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 17:54:10 2012 +0800

change in master

commit fa4abf6455aa01cf7d74810b96e2279983287fc8

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 17:41:51 2012 +0800

add modify2

commit 07ee8b68e90a470aec9a5194079e54332093fc70

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 17:29:00 2012 +0800

add modify

commit 098e14c671f8cef3507a8b43fba7b386892ed5bc

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 16:59:04 2012 +0800

initial commit contents

這樣,就將剛纔在quietheart分支上面的從master繼承過來之後的所有修改合併到了master主分支上面來了,同時提交分支quietheart時候的日誌信息也合並進來了。

3、使用clone、pull、push實踐多人合作

*拷貝兩份遠端庫到本地:

$ git clone /home/lv-k/temp/git_test git_test_clone

具體如下:

lv-k@quietheart:~/temp$ git clone /home/lv-k/temp/git_test git_test_clone

Cloning into git_test_clone...

done.

lv-k@quietheart:~/temp$ git clone /home/lv-k/temp/git_test_clone/ /home/lv-k/temp/git_test_clone1

Cloning into /home/lv-k/temp/git_test_clone1...

done.

這裏,其實拷貝的是當前庫所在的分支,通過"git branch"查看可知,得到的git_test_clone其實只有master分支,因爲拷貝的時候,git_test庫所在的當前分支是master。

*在一個拷貝上面修改並提交:

$ cd git_test_clone1/

$ echo "hello after clone" >>hello

$ git commit -a -m 'commin in clone'

具體如下:

lv-k@quietheart:~/temp$ cd git_test_clone1/

lv-k@quietheart:~/temp/git_test_clone1$ echo "hello after clone" >>hello

lv-k@quietheart:~/temp/git_test_clone1$ git commit -a -m 'commin in clone'

[master bf44b20] commin in clone

Committer: lv-k <lv-k@quietheart.(none)>

Your name and email address were configured automatically based

on your username and hostname. Please check that they are accurate.

You can suppress this message by setting them explicitly:

git config --global user.name "Your Name"

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

After doing this, you may fix the identity used for this commit with:

git commit --amend --reset-author

1 files changed, 1 insertions(+), 0 deletions(-)

這裏,修改之後,本地庫便和遠端的原始庫發生了變化。

*將遠端拷貝修改的內容拉取過來:

$ cd git_test_clone/

$ git pull /home/lv-k/temp/git_test_clone1/

具體如下:

lv-k@quietheart:~/temp$ cd git_test_clone/

lv-k@quietheart:~/temp/git_test_clone$ git pull /home/lv-k/temp/git_test_clone1/

remote: Counting objects: 5, done.

remote: Compressing objects: 100% (3/3), done.

remote: Total 3 (delta 0), reused 0 (delta 0)

Unpacking objects: 100% (3/3), done.

From /home/lv-k/temp/git_test_clone1

* branch HEAD -> FETCH_HEAD

Updating 83548b1..bf44b20

Fast-forward

hello | 1 +

1 files changed, 1 insertions(+), 0 deletions(-)

lv-k@quietheart:~/temp/git_test_clone$ cat hello

hello world

hello world

hello world

change in master

hello after clone

lv-k@quietheart:~/temp/git_test_clone$ git log |head -n 10

commit bf44b2085fe716b1fdb4c04b0dabbca60c451f39

Author: lv-k <lv-k@quietheart.(none)>

Date: Wed Jun 13 16:28:32 2012 +0800

commin in clone

commit 83548b1a87668a5dbd606c6bcefdc984970ffb40

Merge: d8f32e0 8a95074

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 18:09:51 2012 +0800

從這裏我們可以看到,拉取過來的內容被自動地提交上去了,其實拉取內容的時候應該指明是哪個分支。實際如果沒有參數則從clone時候的來源來pull,這裏可以通過.git/config中查看來源。

*將本地庫拷貝的修改推送到遠程庫中:

$ cd git_test_clone1/

$ echo "test push" >>hello

$ cd ../git_test_clone1/

$ vim .git/config

###編輯內容,添加如下###

[receive]

denyCurrentBranch = ignore

###編輯內容,添加如上###

$ cd ../git_test_clone1

$ git push /home/lv-k/temp/git_test_clone

具體如下:

lv-k@quietheart:~/temp$ cd git_test_clone1/

lv-k@quietheart:~/temp/git_test_clone1$ echo "test push" >>hello

lv-k@quietheart:~/temp/git_test_clone1$ git push /home/lv-k/temp/git_test_clone

Everything up-to-date

lv-k@quietheart:~/temp/git_test_clone1$ cat /home/lv-k/temp/git_test_clone

cat: /home/lv-k/temp/git_test_clone: Is a directory

lv-k@quietheart:~/temp/git_test_clone1$ cat /home/lv-k/temp/git_test_clone/hello

hello world

hello world

hello world

change in master

hello after clone

lv-k@quietheart:~/temp/git_test_clone1$ git commit -a -m 'to be pushed'

[master c478225] to be pushed

Committer: lv-k <lv-k@quietheart.(none)>

Your name and email address were configured automatically based

on your username and hostname. Please check that they are accurate.

You can suppress this message by setting them explicitly:

git config --global user.name "Your Name"

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

After doing this, you may fix the identity used for this commit with:

git commit --amend --reset-author

1 files changed, 1 insertions(+), 0 deletions(-)

lv-k@quietheart:~/temp/git_test_clone1$ git status

# On branch master

# Your branch is ahead of 'origin/master' by 2 commits.

#

nothing to commit (working directory clean)

lv-k@quietheart:~/temp/git_test_clone1$ git pull

From /home/lv-k/temp/git_test_clone

83548b1..bf44b20 master -> origin/master

Already up-to-date.

lv-k@quietheart:~/temp/git_test_clone1$ git status

# On branch master

# Your branch is ahead of 'origin/master' by 1 commit.

#

nothing to commit (working directory clean)

lv-k@quietheart:~/temp/git_test_clone1$ git push

Counting objects: 5, done.

Delta compression using up to 4 threads.

Compressing objects: 100% (3/3), done.

Writing objects: 100% (3/3), 339 bytes, done.

Total 3 (delta 1), reused 0 (delta 0)

Unpacking objects: 100% (3/3), done.

remote: error: refusing to update checked out branch: refs/heads/master

remote: error: By default, updating the current branch in a non-bare repository

remote: error: is denied, because it will make the index and work tree inconsistent

remote: error: with what you pushed, and will require 'git reset --hard' to match

remote: error: the work tree to HEAD.

remote: error:

remote: error: You can set 'receive.denyCurrentBranch' configuration variable to

remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into

remote: error: its current branch; however, this is not recommended unless you

remote: error: arranged to update its work tree to match what you pushed in some

remote: error: other way.

remote: error:

remote: error: To squelch this message and still keep the default behaviour, set

remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.

To /home/lv-k/temp/git_test_clone/

! [remote rejected] master -> master (branch is currently checked out)

error: failed to push some refs to '/home/lv-k/temp/git_test_clone/'

lv-k@quietheart:~/temp$ cd ../git_test_clone/

lv-k@quietheart:~/temp/git_test_clone$ git config --bool core.bare true

lv-k@quietheart:~/temp$ cd ../git_test_clone1/

lv-k@quietheart:~/temp/git_test_clone1$ git push

Counting objects: 5, done.

Delta compression using up to 4 threads.

Compressing objects: 100% (3/3), done.

Writing objects: 100% (3/3), 339 bytes, done.

Total 3 (delta 1), reused 0 (delta 0)

Unpacking objects: 100% (3/3), done.

To /home/lv-k/temp/git_test_clone/

bf44b20..c478225 master -> master

lv-k@quietheart:~/temp/git_test_clone1$ cat ../git_test_clone/hello

hello world

hello world

hello world

change in master

hello after clone

lv-k@quietheart:~/temp$ cd git_test_clone/

lv-k@quietheart:~/temp/git_test_clone$ git reset --hard

fatal: This operation must be run in a work tree

lv-k@quietheart:~/temp/git_test_clone$ git config --bool core.bare false

lv-k@quietheart:~/temp/git_test_clone$ git reset --hard

HEAD is now at c478225 to be pushed

lv-k@quietheart:~/temp/git_test_clone$ cat hello

hello world

hello world

hello world

change in master

hello after clone

test push

lv-k@quietheart:~/temp/git_test_clone$ vim .git/config

添加如下:

[receive]

denyCurrentBranch = ignore

lv-k@quietheart:~/temp$ cd git_test_clone1

lv-k@quietheart:~/temp/git_test_clone1$ echo "push2" >>hello

lv-k@quietheart:~/temp/git_test_clone1$ git commit -a -m 'push2'

[master 8b45c2f] push2

Committer: lv-k <lv-k@quietheart.(none)>

Your name and email address were configured automatically based

on your username and hostname. Please check that they are accurate.

You can suppress this message by setting them explicitly:

git config --global user.name "Your Name"

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

After doing this, you may fix the identity used for this commit with:

git commit --amend --reset-author

1 files changed, 1 insertions(+), 0 deletions(-)

lv-k@quietheart:~/temp/git_test_clone1$ git push

Counting objects: 5, done.

Delta compression using up to 4 threads.

Compressing objects: 100% (3/3), done.

Writing objects: 100% (3/3), 332 bytes, done.

Total 3 (delta 1), reused 0 (delta 0)

Unpacking objects: 100% (3/3), done.

To /home/lv-k/temp/git_test_clone/

c478225..8b45c2f master -> master

lv-k@quietheart:~/temp$ cd git_test_clone

lv-k@quietheart:~/temp/git_test_clone$ ls

example hello mydir

lv-k@quietheart:~/temp/git_test_clone$ cat hello

hello world

hello world

hello world

change in master

hello after clone

test push

lv-k@quietheart:~/temp/git_test_clone$ git reset --hard

HEAD is now at 8b45c2f push2

lv-k@quietheart:~/temp/git_test_clone$ cat hello

hello world

hello world

hello world

change in master

hello after clone

test push

push2

這裏我們可見,本地修改之後,直接使用"git push"無法提交,還需要遠端用"git config --bool core.bare true"配置好之後,才能push,push之後,如果遠端也在同樣分支上面,並不能立即反應,需要將"core.bare"設置爲"false"然後再"git reset --hard"。

根據網上查詢的資料,push無法進行有如下解決方法:

方法1:

git config --bool core.bare true

方法2:

修改.git/config添加如下代碼:

[receive]

denyCurrentBranch = ignore

我們使用第1個方法,比較麻煩,使用第二個方法,就不用再從服務端重新設置"core.bare"了。

另外,參考資料還提到,最好用git -bare init初始化庫,而不是git init,本例子因爲使用git init初始化,所以這樣。

**

*版本回退的實踐

這裏分別對reset,revert,checkout三種方式進行一下實踐具體過程如下:

lv-k@quietheart:~/temp$ git clone git_test git_test_clone2

Cloning into git_test_clone2...

done.

lv-k@quietheart:~/temp$ cd git_test_clone2/

lv-k@quietheart:~/temp/git_test_clone2$ git log --graph

* commit 8a95074a30e32a4df3cdf50648fce2d6a0a73a97

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 18:00:10 2012 +0800

|

| change in quietheart

|

* commit fa4abf6455aa01cf7d74810b96e2279983287fc8

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 17:41:51 2012 +0800

|

| add modify2

|

* commit 07ee8b68e90a470aec9a5194079e54332093fc70

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 17:29:00 2012 +0800

|

| add modify

|

* commit 098e14c671f8cef3507a8b43fba7b386892ed5bc

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 16:59:04 2012 +0800

initial commit contents

lv-k@quietheart:~/temp/git_test_clone2$ git reset --hard fa4abf6455aa01cf7d74810b96e2279983287fc8

HEAD is now at fa4abf6 add modify2

lv-k@quietheart:~/temp/git_test_clone2$ git log --graph

* commit fa4abf6455aa01cf7d74810b96e2279983287fc8

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 17:41:51 2012 +0800

|

| add modify2

|

* commit 07ee8b68e90a470aec9a5194079e54332093fc70

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 17:29:00 2012 +0800

|

| add modify

|

* commit 098e14c671f8cef3507a8b43fba7b386892ed5bc

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 16:59:04 2012 +0800

initial commit contents

lv-k@quietheart:~/temp/git_test_clone2$ git pull

Updating fa4abf6..8a95074

Fast-forward

example | 1 +

1 files changed, 1 insertions(+), 0 deletions(-)

lv-k@quietheart:~/temp/git_test_clone2$ git log --graph

* commit 8a95074a30e32a4df3cdf50648fce2d6a0a73a97

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 18:00:10 2012 +0800

|

| change in quietheart

|

* commit fa4abf6455aa01cf7d74810b96e2279983287fc8

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 17:41:51 2012 +0800

|

| add modify2

|

* commit 07ee8b68e90a470aec9a5194079e54332093fc70

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 17:29:00 2012 +0800

|

| add modify

|

* commit 098e14c671f8cef3507a8b43fba7b386892ed5bc

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 16:59:04 2012 +0800

initial commit contents

lv-k@quietheart:~/temp/git_test_clone2$ git revert fa4abf6455aa01cf7d74810b96e2279983287fc8

...自動打開編輯器,編輯log,退出編輯器(不用保存)...

[quietheart d707529] Revert "add modify2"

Committer: lv-k <lv-k@quietheart.(none)>

Your name and email address were configured automatically based

on your username and hostname. Please check that they are accurate.

You can suppress this message by setting them explicitly:

git config --global user.name "Your Name"

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

After doing this, you may fix the identity used for this commit with:

git commit --amend --reset-author

1 files changed, 0 insertions(+), 1 deletions(-)

lv-k@quietheart:~/temp/git_test_clone2$ git log --graph

* commit d707529ef6ed1b2bca493d22d367e56751ae3f3d

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Jun 14 16:24:51 2012 +0800

|

| Revert "add modify2"

|

| This reverts commit fa4abf6455aa01cf7d74810b96e2279983287fc8.

|

* commit 8a95074a30e32a4df3cdf50648fce2d6a0a73a97

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 18:00:10 2012 +0800

|

| change in quietheart

|

* commit fa4abf6455aa01cf7d74810b96e2279983287fc8

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 17:41:51 2012 +0800

|

| add modify2

|

* commit 07ee8b68e90a470aec9a5194079e54332093fc70

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 17:29:00 2012 +0800

|

| add modify

|

* commit 098e14c671f8cef3507a8b43fba7b386892ed5bc

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 16:59:04 2012 +0800

initial commit contents

lv-k@quietheart:~/temp/git_test_clone2$ git diff d707529ef6ed1b2bca493d22d367e56751ae3f3d:hello 07ee8b68e90a470aec9a5194079e54332093fc70:hello

lv-k@quietheart:~/temp/git_test_clone2$ git reset --hard fa4abf6455aa01cf7d74810b96e2279983287fc8

HEAD is now at fa4abf6 add modify2

lv-k@quietheart:~/temp/git_test_clone2$ git pull

Updating fa4abf6..8a95074

Fast-forward

example | 1 +

1 files changed, 1 insertions(+), 0 deletions(-)

lv-k@quietheart:~/temp/git_test_clone2$ git log --graph

* commit 8a95074a30e32a4df3cdf50648fce2d6a0a73a97

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 18:00:10 2012 +0800

|

| change in quietheart

|

* commit fa4abf6455aa01cf7d74810b96e2279983287fc8

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 17:41:51 2012 +0800

|

| add modify2

|

* commit 07ee8b68e90a470aec9a5194079e54332093fc70

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 17:29:00 2012 +0800

|

| add modify

|

* commit 098e14c671f8cef3507a8b43fba7b386892ed5bc

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 16:59:04 2012 +0800

initial commit contents

lv-k@quietheart:~/temp/git_test_clone2$ git checkout fa4abf6455aa01cf7d74810b96e2279983287fc8

Note: checking out 'fa4abf6455aa01cf7d74810b96e2279983287fc8'.

You are in 'detached HEAD' state. You can look around, make experimental

changes and commit them, and you can discard any commits you make in this

state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may

do so (now or later) by using -b with the checkout command again. Example:

git checkout -b new_branch_name

HEAD is now at fa4abf6... add modify2

lv-k@quietheart:~/temp/git_test_clone2$ git log --graph

* commit fa4abf6455aa01cf7d74810b96e2279983287fc8

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 17:41:51 2012 +0800

|

| add modify2

|

* commit 07ee8b68e90a470aec9a5194079e54332093fc70

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 17:29:00 2012 +0800

|

| add modify

|

* commit 098e14c671f8cef3507a8b43fba7b386892ed5bc

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 16:59:04 2012 +0800

initial commit contents

lv-k@quietheart:~/temp/git_test_clone2$ echo "add content" >>hello

lv-k@quietheart:~/temp/git_test_clone2$ git commit -a -m 'add'

[detached HEAD 9bd6059] add

Committer: lv-k <lv-k@quietheart.(none)>

Your name and email address were configured automatically based

on your username and hostname. Please check that they are accurate.

You can suppress this message by setting them explicitly:

git config --global user.name "Your Name"

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

After doing this, you may fix the identity used for this commit with:

git commit --amend --reset-author

1 files changed, 1 insertions(+), 0 deletions(-)

lv-k@quietheart:~/temp/git_test_clone2$ git log --graph

* commit 9bd605958283f6b33264af3ec6c9a0faa07feb55

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Jun 14 16:28:51 2012 +0800

|

| add

|

* commit fa4abf6455aa01cf7d74810b96e2279983287fc8

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 17:41:51 2012 +0800

|

| add modify2

|

* commit 07ee8b68e90a470aec9a5194079e54332093fc70

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 17:29:00 2012 +0800

|

| add modify

|

* commit 098e14c671f8cef3507a8b43fba7b386892ed5bc

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 16:59:04 2012 +0800

initial commit contents

lv-k@quietheart:~/temp/git_test_clone2$ git checkout 8a95074a30e32a4df3cdf50648fce2d6a0a73a97

Warning: you are leaving 1 commit behind, not connected to

any of your branches:

9bd6059 add

If you want to keep it by creating a new branch, this may be a good time

to do so with:

git branch new_branch_name 9bd605958283f6b33264af3ec6c9a0faa07feb55

HEAD is now at 8a95074... change in quietheart

lv-k@quietheart:~/temp/git_test_clone2$ git log --graph

* commit 8a95074a30e32a4df3cdf50648fce2d6a0a73a97

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 18:00:10 2012 +0800

|

| change in quietheart

|

* commit fa4abf6455aa01cf7d74810b96e2279983287fc8

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 17:41:51 2012 +0800

|

| add modify2

|

* commit 07ee8b68e90a470aec9a5194079e54332093fc70

| Author: lv-k <lv-k@quietheart.(none)>

| Date: Thu Feb 9 17:29:00 2012 +0800

|

| add modify

|

* commit 098e14c671f8cef3507a8b43fba7b386892ed5bc

Author: lv-k <lv-k@quietheart.(none)>

Date: Thu Feb 9 16:59:04 2012 +0800

initial commit contents

這裏,根據前面的運行可知,reset可以將包括註釋以及以前的提交全部清除,實現根本的回退;revert只是將指定版本的內容做爲新的HEAD重新提交(類似打反向補丁),並且不會清除已有原來的提交;checkout是檢出一個版本,已有的版本信息仍然保存在庫中,但是在檢出的舊版本上提交會導致新的分支。

???沒有解決的問題:

使用git checkout "commit id"可以提取以前的版本,並且也可以回到以前之後的版本,但是如何回到以前的版本之後,知道以後有什麼版本?

參考資料:

http://www.cnblogs.com/abeen/archive/2010/06/17/1759496.html

http://stackoverflow.com/questions/2816369/git-push-error-remote-rejected-master-master-branch-is-currently-checked-ou

man gittutorial

作者:QuietHeart

Email:[email protected]

日期:2012年6月14日

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章