git 教程(7)
==============
名稱
----
git 教程 - 介紹git的教程 (僅用於 1.5.1 版本或以上)
摘要
--------
git *
描述
-----------
本教程講述如何將一個新項目匯入到git,如何做修改並將所做的改動共用給其他開發人員。
如果你主要是想知道如何用git擷取一個項目,比如想測試最新的版本,你可能更適合從
user-manual.html[Git 使用者手冊]的前兩章開始。
首先,要知道可以用下面的方式來獲得某個命令的的用法:
------------------------------------------------
$ man git-log
------------------------------------------------
或者:
------------------------------------------------
$ git help log
------------------------------------------------
上面命令會列出log的各種用法; 詳細可參看linkgit:git-help[1]。
建議你在做任何git操作前先公布一下你的名字和郵箱,做法很簡單:
------------------------------------------------
$ git config --global user.name "Your Name Comes Here"
$ git config --global user.email you@yourdomain.example.com
------------------------------------------------
匯入一個新項目
-----------------------
假如你有一個新項目為project.tar.gz,你可以通過下面的操作將git版本控制加進去
------------------------------------------------
$ tar xzf project.tar.gz
$ cd project
$ git init
------------------------------------------------
Git 會列印出:
------------------------------------------------
Initialized empty Git repository in .git/
------------------------------------------------
你已經初始化了一個工作目錄--你可能注意到已建立了一個名為".git"的檔案夾.
下面,用 'git add' 讓git將當前錄所有檔案的內容拍個快照:
------------------------------------------------
$ git add .
------------------------------------------------
這個快照會被儲存在一個git稱為“索引”的臨時緩衝區裡。你可以通過'git commit'將
索引的內容永久地儲存在版本控制倉庫裡:
------------------------------------------------
$ git commit
------------------------------------------------
該命令會提示你輸入提交資訊。至此,你已將項目的第一個版本儲存到git了。
作修改
--------------
修改檔案,並將已更改的內容添加到索引:
------------------------------------------------
$ git add file1 file2 file3
------------------------------------------------
現在就可以提交了。你還可以用下面的命令來查看所做的改動:
用 'git diff' 帶 --cached 選項:
------------------------------------------------
$ git diff --cached
------------------------------------------------
(不帶 --cached, 'git diff' 將會顯示還沒添加到索引的改動.) 你還可以通過 'git status'
來查看哪些檔案有改動:
------------------------------------------------
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: file1
# modified: file2
# modified: file3
#
------------------------------------------------
如果你還想作一些改動,可以繼續改,改完後再將它們添加到索引,最後用下面的命令來提交所做的改動:
------------------------------------------------
$ git commit
------------------------------------------------
該命還會提醒你輸入描述改動的提交資訊,然後會記下項目的一個新版本號碼。
還有,不想運行'git add',你還可以用:
------------------------------------------------
$ git commit -a
------------------------------------------------
該命令會自動識別那些改動的檔案(新建立的除外,建立的檔案必須得用git add),將
它們添加到索引,並提交,所有操作一步到位。
提交資訊格式的建議:
雖然不是強制要求,但最好還是寫一句關於改動的簡短概要(少於50個字元),
然後寫一個間隔線隔開,接著再寫詳細描述。因為工具在將提交資訊發到郵箱時,
會將第一行作為標題,其他作為常值內容。格式如下:
Git 跟蹤的是內容,而不是檔案
----------------------------
一些版本控制系統提供add命令用於告訴系統開始跟蹤一個新檔案的變動。Git的add命令
也做一些相似的功能,但還有更強大的功能:add可以用於新建立,也可以用於改動的檔案,
這兩種情況下,都會對檔案的內容拍一個快照儲存在臨時工作區,即索引上,然後再下一步
提交時永久儲存到倉庫。
查看項目記錄
-----------------------
用下面的命令,可以查看所有你作修改的記錄:
------------------------------------------------
$ git log
------------------------------------------------
如果還想看每次改動的差異,還可以使用:
------------------------------------------------
$ git log -p
------------------------------------------------
通常查看更改概要也有助於瞭解每一次的改動:
------------------------------------------------
$ git log --stat --summary
------------------------------------------------
Managing branches
-----------------
單個git倉庫可以維持多個開發分支。比如建立一個"experimental"分支,可使用:
------------------------------------------------
$ git branch experimental
------------------------------------------------
如果你現在運行:
------------------------------------------------
$ git branch
------------------------------------------------
你會看到所有已存分支的列表:
------------------------------------------------
experimental
* master
------------------------------------------------
"experimental" 正是你剛建立的分支,"master" 分支是預設分支,是系統自動給你建立的。
*號表示你當前所處的分支是master。
敲入如下命令:
------------------------------------------------
$ git checkout experimental
------------------------------------------------
將會切換到 experimental 分支。此時編輯一個檔案,並提交改動,然後再切換回master分支:
------------------------------------------------
(edit file)
$ git commit -a
$ git checkout master
------------------------------------------------
可以看到你的改動不見了,這因為你作的改動是在experimental分支上,而現在你是在master分支了。
你還可以在master上作一個不同的改動:
------------------------------------------------
(edit file)
$ git commit -a
------------------------------------------------
這樣兩個分支就分流了,彼此有不同的改動。將experimental上的改動合并到master,可以運行:
------------------------------------------------
$ git merge experimental
------------------------------------------------
如果彼此的改動不衝突,那麼你就完成了。如果存在衝突,會有顯示衝突的標識留在衝突的檔案上,讓你手動更改。
------------------------------------------------
$ git diff
------------------------------------------------
上面命令會顯示衝突的地方。一旦改好衝突檔案後,
------------------------------------------------
$ git commit -a
------------------------------------------------
上面將提交併合的結果。最後,
------------------------------------------------
$ gitk
------------------------------------------------
將顯示一個關於操作記錄的友好圖形介面。
此時,你可以將experimental分支刪除,使用下面命令:
------------------------------------------------
$ git branch -d experimental
------------------------------------------------
該命令提示你是否已將experimental所有的改動合并到當前分支了,如果沒有,則不讓刪除。
如果你建立了一個分支叫crazy-idea,想丟棄它,可以用下面命令強制移除:
-------------------------------------
$ git branch -D crazy-idea
-------------------------------------
使用分支方便節省,這是個作不同嘗試的好方法。
git用於合作開發
---------------------------
Alice建立了一個帶git倉庫的項目/home/alice/project,
Alice 和 Bob兩人同時進行開發。
Bob 開始下載源碼:
------------------------------------------------
bob$ git clone /home/alice/project myrepo
------------------------------------------------
這將建立一個名為"myrepo"的目錄,該目錄包含伺服器倉庫的一份複製。該複製地位
同等伺服器倉庫,可以處理拷自原始倉庫的記錄。
Bob 做了一些修改並提交:
------------------------------------------------
(edit files)
bob$ git commit -a
(repeat as necessary)
------------------------------------------------
當Bob完成後,告訴Alice去更新這些改動。
Alice將會做:
------------------------------------------------
alice$ cd /home/alice/project
alice$ git pull /home/bob/myrepo master
------------------------------------------------
上面的操作將會將Bob庫分支"master"的改動合并到Alice當前的分支。
如果Alice也對這些檔案有作改動,則需要手動修複衝突。
"pull"命令執行了兩個操作:從伺服器上將改動的檔案抓下來,然後將它們合并到當前分支。
注意,一般情況下,Alice會在"pull"前將自己的改動提交。
如果Bob的工作與 Alice的有衝突,Alice會用自己的工作樹和索引去解決這些衝突,
衝突越多,解決時間越長;衝突發生時git 不會執行合并的操作,Alice解決完衝突後,還需
再pull一下。
Alice可以使用"fetch"命令,先將改動的檔案抓下來,用"FETCH_HEAD"查看改動,再做是否需要更新的決定:
------------------------------------------------
alice$ git fetch /home/bob/myrepo master
alice$ git log -p HEAD..FETCH_HEAD
------------------------------------------------
即使Alice沒有提交本地的更改,該操作也是安全的。
"HEAD..FETCH_HEAD" 的意思是:顯示HEAD與FETCH_HEAD記錄分開後FETCH_HEAD的記錄。
還可以用圖形化工具查看:
------------------------------------------------
$ gitk HEAD..FETCH_HEAD
------------------------------------------------
Alice 還可以查看HEAD與FETCH_HEAD記錄分開後彼此的記錄
她可以用三點形式來代替兩點形式:
------------------------------------------------
$ gitk HEAD...FETCH_HEAD
------------------------------------------------
看了Bob的改動後,如果沒什麼要緊的改動,Alice或許不會去更新。如果有比較急需的,
Alice可能先將自己的改動移走,更新最新代碼,最後再把原先的工作放回來。
當你是在一個小型緊湊型團隊工作,會經常對同一個伺服器打交道。通過簡單定義一個'remote'
倉庫,這樣你做起來會更簡單:
------------------------------------------------
alice$ git remote add bob /home/bob/myrepo
------------------------------------------------
該命令的意思是將bob映射為遠程倉庫/home/bob/myrepo,其實就是用bob表示/home/bob/myrepo。
執行該命令之後,Alice就可以執行"pull"操作的第一部分,即'git fetch':
-------------------------------------
alice$ git fetch bob
-------------------------------------
不像一般形式,fetch後面跟的是遠程倉庫的地址,現在採用的是git remote add 建立代的代號,
其映射關係可以通過'git remote'命令來查看。
bob後面沒跟分支,表示`bob/master`。
fetch操作之後執行:
-------------------------------------
alice$ git log -p master..bob/master
-------------------------------------
將顯示Bob和Alice主分支記錄分開後Bob的記錄,其功能相當於git log -p HEAD..FETCH_HEAD
檢查完改動後,Alice可以將這些改動合并到她的當前分支:
-------------------------------------
alice$ git merge bob/master
-------------------------------------
`merge` 的操作也可用'pull'來代替:
-------------------------------------
alice$ git pull . remotes/bob/master
-------------------------------------
注意,不管給什麼參數,git pull的操作總會將代碼合并到當前分支
後面,Bob可以更新Alice的最新改動。
-------------------------------------
bob$ git pull
-------------------------------------
注意到Bob並不需要提定Alice的倉庫地址,因為Bob在複製Alice的倉庫後,本地的倉庫配置已儲存了
Alice的倉庫地址了,如下命令可獲得該地址:
-------------------------------------
bob$ git config --get remote.origin.url
/home/alice/project
-------------------------------------
('git clone' 建立的配置資訊可以通過`git config -l`來查看, 詳細請參看linkgit:git-config[1])
Git也保留了Alice 主分支的原始拷貝在"origin/master":
-------------------------------------
bob$ git branch -r
origin/master
-------------------------------------
如果Bob以後想換個電腦,他還可以通過ssh 協議來執行clone和pull操作:
-------------------------------------
bob$ git clone alice.org:/home/alice/project myrepo
-------------------------------------
還有,git 可以用git協議,或者rsync或者http;詳細請參看linkgit:git-pull[1]
Git還可以像CVS那樣,作為一個中央倉庫,讓很多人可以提交改動,詳細請參看linkgit:gitcvs-migration[7]。
瀏覽歷程記錄
-----------------
Git 記錄是用一連串相關提交資訊組成的。我們已知道可以通過'git log'命令來列出這些提交資訊。
注意每個git log列出的第一行是提交名稱:
-------------------------------------
$ git log
commit c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
Author: Junio C Hamano <junkio@cox.net>
Date: Tue May 16 17:18:22 2006 -0700
merge-base: Clarify the comments on post processing.
-------------------------------------
我們可以'git show'來看某個提交名稱所包含的詳細資料。
-------------------------------------
$ git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
-------------------------------------
還有其他方法可以查看提交資訊。可以用提交名稱前幾個字元,只要足以定位就行,去查看該提交的詳細資料:
-------------------------------------
$ git show c82a22c39c # the first few characters of the name are
# usually enough
$ git show HEAD # the tip of the current branch
$ git show experimental # the tip of the "experimental" branch
-------------------------------------
每一個提交一般有一個表示項目上一個狀態點的“父級”提交:
-------------------------------------
$ git show HEAD^ # to see the parent of HEAD
$ git show HEAD^^ # to see the grandparent of HEAD
$ git show HEAD~4 # to see the great-great grandparent of HEAD
-------------------------------------
注意,合并的提交可能會有多個“父級”
-------------------------------------
$ git show HEAD^1 # show the first parent of HEAD (same as HEAD^)
$ git show HEAD^2 # show the second parent of HEAD
-------------------------------------
通過運行下面的命令,可以將提交名稱改為自訂的:
-------------------------------------
$ git tag v2.5 1b2e1d63ff
-------------------------------------
可以用"v2.5"來代替1b2e1d63ff。如果你想將這個名稱與其他人分享(比如,標識一個發布版本號碼),
你需建立一個"tag"的對象,可能要簽名;詳細請參看linkgit:git-tag[1]。
任何git命令需要提交名稱的都可以用tag或都HEAD的表達來代替,例如:
-------------------------------------
$ git diff v2.5 HEAD # compare the current HEAD to v2.5
$ git branch stable v2.5 # start a new branch named "stable" based
# at v2.5
$ git reset --hard HEAD^ # reset your current branch and working
# directory to its state at HEAD^
-------------------------------------
注意最後一個命令:除了會丟掉當前所有的改動,還會將其後面的提交刪除。
如果這些已提交的東西只有當前分支有,則執行完這個命令後會永久丟失。
同樣,不要在一個共用的分支上使用'git reset'命令,否則會引起一些不必要的合并,迫使
其他開發人員清除記錄。如果想撤消已提交的改動,可以使用'git revert'來代替'git reset'。
'git grep'命令可以搜尋項目任何版本的字串。
-------------------------------------
$ git grep "hello" v2.5
-------------------------------------
在v2.5版本搜尋所有出現"hello"的檔案。
如果不加提交名稱,'git grep'會搜尋目前的目錄git管理的所有檔案。
-------------------------------------
$ git grep "hello"
-------------------------------------
這是一個在git所記錄的檔案裡搜尋的捷徑。
有些git命令可以帶幾個提交名稱,這些名稱有幾種表達方式,例如'git log':
-------------------------------------
$ git log v2.5..v2.6 # commits between v2.5 and v2.6
$ git log v2.5.. # commits since v2.5
$ git log --since="2 weeks ago" # commits from the last 2 weeks
$ git log v2.5.. Makefile # commits since v2.5 which modify
# Makefile
-------------------------------------
git log 提交名稱之間的範圍符號,即'..',還可以表只存在於第二個名稱裡,但不存在於
第一個名稱裡;例如,有"stable" 和 "master"兩個分支,它們的提交記錄在某個時間就已
分開:
-------------------------------------
$ git log stable..master
-------------------------------------
將列出stable分支沒有,master分支有的記錄。
-------------------------------------
$ git log master..stable
-------------------------------------
將列出master分支沒有,stable分支有的記錄。
'git log'命令有一個缺陷:只能以列表的形式來表現提交記錄。如果同時有多條
開發分支,後面合并到一起,用git log所列出來的提交順序是沒意義的。
大多項目會有許多開發分支,會經常合并,使用gitk可以更好瀏覽歷程記錄。例如:
-------------------------------------
$ gitk --since="2 weeks ago" drivers/
-------------------------------------
允許你瀏覽兩周來,在drivers目錄下的修改記錄。(提示:你可以通過'ctrl' + '-' 或 'ctrl' + '+'
來調整gitk的字型)
最後,大多數命令可以帶檔案名稱,這樣可以優先處理該檔案,如指定一個檔案的版本:
-------------------------------------
$ git diff v2.5:Makefile HEAD:Makefile.in
-------------------------------------
還可以用'git show'來看任何檔案:
-------------------------------------
$ git show v2.5:Makefile
-------------------------------------
往後
----------
通過本教程的學習,應該可以做一般的分布式版本控制項目了。然而,想全面了git的深度和力量,還需要
理解下面兩個簡單的思想:
* 對象資料庫是一種比較高端的系統,用於儲存項目的記錄,比如檔案,目錄,提交等。
* 索引檔案是分類樹狀態的一個緩衝,用於建立提交,切換工作目錄,保留合并後的不同樹。
本教程的第二部分解釋了對象資料庫,檔案索引,和一些通命令用法。
如果你不想走尋常路,下面一些東西可能會適合你:
If you don't want to continue with that right away, a few other
digressions that may be interesting at this point are:
* linkgit:git-format-patch[1], linkgit:git-am[1]: These convert
series of git commits into emailed patches, and vice versa,
useful for projects such as the Linux kernel which rely heavily
on emailed patches.
* linkgit:git-bisect[1]: When there is a regression in your
project, one way to track down the bug is by searching through
the history to find the exact commit that's to blame. Git bisect
can help you perform a binary search for that commit. It is
smart enough to perform a close-to-optimal search even in the
case of complex non-linear history with lots of merged branches.
* linkgit:gitworkflows[7]: Gives an overview of recommended
workflows.
* link:everyday.html[Everyday GIT with 20 Commands Or So]
* linkgit:gitcvs-migration[7]: Git for CVS users.
還可以參看
--------
linkgit:gittutorial-2[7],
linkgit:gitcvs-migration[7],
linkgit:gitcore-tutorial[7],
linkgit:gitglossary[7],
linkgit:git-help[1],
linkgit:gitworkflows[7],
link:everyday.html[Everyday git],
link:user-manual.html[The Git User's Manual]
GIT
---
Part of the linkgit:git[1] suite.