簡體中文 ▾ 主題 ▾ 最新版本 ▾ gittutorial 最後更新於 2.46.1

名稱

gittutorial - Git 的教程入門

概要

git *

描述

本教程解釋瞭如何將新專案匯入 Git、對其進行更改以及與其他開發人員共享更改。

如果您主要對使用 Git 獲取專案感興趣,例如,要測試最新版本,您可以選擇從The Git User’s Manual的前兩章開始。

首先,請注意,您可以透過以下方式獲取類似 git log --graph 命令的文件:

$ man git-log

$ git help log

對於後者,您可以使用您選擇的手冊檢視器;有關更多資訊,請參閱 git-help[1]

在進行任何操作之前,最好先用您的姓名和公開電子郵件地址介紹自己。最簡單的方法是:

$ git config --global user.name "Your Name Comes Here"
$ git config --global user.email you@yourdomain.example.com

匯入新專案

假設您有一個包含您初步工作的 tarball 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

您現在已準備好提交。您可以使用帶 --cached 選項的 git diff 命令檢視將要提交的內容:

$ git diff --cached

(不帶 --cachedgit diff 會顯示您已進行但尚未新增到索引的任何更改。)您還可以使用 git status 命令獲得當前情況的簡要摘要:

$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)

	modified:   file1
	modified:   file2
	modified:   file3

如果您需要進行任何進一步的調整,請立即進行,然後將任何新修改的內容新增到索引中。最後,使用以下命令提交您的更改:

$ git commit

這將再次提示您輸入一條描述更改的訊息,然後記錄專案的新版本。

或者,您可以先不執行 git add,而是使用:

$ git commit -a

該命令將自動識別任何已修改(但非新增)的檔案,將它們新增到索引,然後一次性提交,全部一步完成。

關於提交訊息的說明:雖然不是必需的,但最好在提交訊息開頭寫一個簡短的(不超過 50 個字元)單行摘要,後面跟一個空行,然後是更詳細的描述。提交訊息中第一個空行之前的所有文字都被視為提交標題,Git 在整個過程中都使用這個標題。例如,git-format-patch[1] 會將一個提交轉換為電子郵件,它會將標題用在 Subject 行,而提交的其餘部分放在正文中。

Git 跟蹤內容而不是檔案

許多版本控制系統提供一個 add 命令,用於告知系統開始跟蹤新檔案的更改。Git 的 add 命令作用更簡單、更強大:git add 用於處理新增和已修改的檔案,在這兩種情況下,它都會對給定的檔案內容進行快照,並將其暫存到索引中,為下一次提交做好準備。

檢視專案歷史

在任何時候,您都可以使用以下命令檢視更改歷史:

$ git log

如果您還想在每一步都看到完整的差異,請使用:

$ git log -p

通常,對更改的概述有助於瞭解每一步的進展。

$ git log --stat --summary

管理分支

一個 Git 倉庫可以維護多個開發分支。要建立一個名為 experimental 的新分支,請使用:

$ git branch experimental

如果您現在執行:

$ git branch

您將獲得一個現有分支列表。

  experimental
* master

experimental 分支是您剛剛建立的,而 master 分支是自動為您建立的預設分支。星號標記著您當前所在的分支;輸入:

$ git switch experimental

切換到 experimental 分支。現在編輯一個檔案,提交更改,然後切換回 master 分支:

(edit file)
$ git commit -a
$ git switch 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 在 /home/alice/project 中建立了一個新的 Git 倉庫,而 Bob 在同一臺機器上有自己的主目錄,並希望貢獻程式碼。

Bob 開始時執行:

bob$ git clone /home/alice/project myrepo

這將建立一個名為 myrepo 的新目錄,其中包含 Alice 倉庫的一個克隆。這個克隆與原始專案處於同等地位,擁有原始專案歷史的副本。

Bob 接著進行一些更改並提交:

(edit files)
bob$ git commit -a
(repeat as necessary)

當他準備好時,他告訴 Alice 從 /home/bob/myrepo 的倉庫拉取更改。她透過以下命令完成:

alice$ cd /home/alice/project
alice$ git pull /home/bob/myrepo master

這將把 Bob 的 master 分支的更改合併到 Alice 當前所在的分支。如果 Alice 此期間自己也進行了更改,那麼她可能需要手動解決任何衝突。

pull 命令因此執行兩個操作:它從遠端分支獲取更改,然後將它們合併到當前分支。

請注意,通常情況下,Alice 希望在發起此 pull 命令之前提交她的本地更改。如果 Bob 的工作與 Alice 在他們的歷史分叉後所做的更改發生衝突,Alice 將需要使用她的工作樹和索引來解決衝突,而現有的本地更改會干擾衝突解決過程(Git 仍會執行獲取操作,但會拒絕合併——此時 Alice 必須以某種方式丟棄她的本地更改,然後重新拉取)。

Alice 可以在不先合併的情況下檢視 Bob 所做的更改,使用 fetch 命令;這允許 Alice 使用一個特殊的符號 FETCH_HEAD 來檢查 Bob 所做的更改,以確定他是否有值得拉取的內容,如下所示:

alice$ git fetch /home/bob/myrepo master
alice$ git log -p HEAD..FETCH_HEAD

即使 Alice 有未提交的本地更改,此操作也是安全的。HEAD..FETCH_HEAD 的範圍表示法意味著“顯示所有可從 FETCH_HEAD 可達但排除任何可從 HEAD 可達的內容”。Alice 已經知道所有導致她當前狀態(HEAD)的內容,並使用此命令檢視 Bob 的狀態(FETCH_HEAD)中她尚未看到的內容。

如果 Alice 想視覺化 Bob 在他們的歷史分叉後所做的更改,她可以發出以下命令:

$ gitk HEAD..FETCH_HEAD

這使用了我們之前在 git log 中看到的相同的兩個點範圍表示法。

Alice 可能想檢視他們分叉後各自所做的更改。她可以在兩個點表示法中使用三個點表示法:

$ gitk HEAD...FETCH_HEAD

這意味著“顯示從任一分支可達的所有內容,但排除從兩個分支都可達的內容”。

請注意,這些範圍表示法可以與 gitkgit log 一起使用。

在檢查完 Bob 的工作後,如果沒有緊急事項,Alice 可能決定繼續工作而不拉取 Bob 的更改。如果 Bob 的歷史確實有 Alice 立即需要的內容,Alice 可能選擇先暫存她的未完成工作,執行 pull,然後在由此產生的歷史之上最後恢復她的未完成工作。

當您在一個小型緊密協作的團隊中工作時,頻繁地與同一個倉庫互動是很常見的。透過定義遠端倉庫的簡寫,您可以使其更容易。

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

有了這個,Alice 可以單獨使用 git fetch 命令執行 pull 操作的第一部分,而不將其與她自己的分支合併,使用:

alice$ git fetch bob

與長格式不同,當 Alice 使用 git remote 設定的遠端倉庫簡寫從 Bob 那裡獲取時,所獲取的內容將儲存在遠端跟蹤分支中,在本例中是 bob/master。因此,在此之後:

alice$ git log -p master..bob/master

顯示了 Bob 自從從 Alice 的 master 分支分叉以來所做的所有更改的列表。

檢查完這些更改後,Alice 可以將更改合併到她的 master 分支:

alice$ git merge bob/master

這個 merge 也可以透過從她自己的遠端跟蹤分支拉取來完成,如下所示:

alice$ git pull . remotes/bob/master

請注意,git pull 始終合併到當前分支,無論命令列中還提供了什麼。

稍後,Bob 可以使用以下命令更新他的倉庫以包含 Alice 的最新更改:

bob$ git pull

請注意,他不需要提供 Alice 倉庫的路徑;當 Bob 克隆 Alice 的倉庫時,Git 將 Alice 倉庫的位置儲存在倉庫配置中,該位置用於拉取操作。

bob$ git config --get remote.origin.url
/home/alice/project

(透過 git config -l 可以看到 git clone 建立的完整配置,並且 git-config[1] man 頁解釋了每個選項的含義。)

Git 還保留了一個 Alice 的 master 分支的原始副本,名為 origin/master

bob$ git branch -r
  origin/master

如果 Bob 後來決定從不同的主機工作,他仍然可以使用 ssh 協議執行克隆和拉取操作:

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

或者,Git 有一個本地協議,或者可以使用 http;有關詳細資訊,請參閱 git-pull[1]

Git 也可以在類 CVS 模式下使用,有一箇中央倉庫供不同使用者推送更改;請參閱 git-push[1]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。如果您打算與他人共享此名稱(例如,用於標識釋出版本),您應該建立一個“標籤”物件,也許還要對其進行簽名;有關詳細資訊,請參閱 git-tag[1]

任何需要知道提交的 Git 命令都可以接受這些名稱中的任何一個。例如:

$ 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 grep 命令可以搜尋您專案任何版本中的字串,因此:

$ git grep "hello" v2.5

將在 v2.5 中搜索“hello”的所有出現。

如果省略提交名稱,git grep 將搜尋您當前目錄中它管理的任何檔案。所以:

$ 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 指定一個提交“範圍”,其中第一個不一定是第二個的祖先;例如,如果 stablemaster 分支在一段時間前從一個共同的提交分叉出來,那麼:

$ git log stable..master

將列出在 master 分支中提交但不在 stable 分支中的提交,而:

$ git log master..stable

將顯示在 stable 分支中提交但不在 master 分支中的提交列表。

git log 命令有一個弱點:它必須以列表的形式呈現提交。當歷史發展線分叉然後合併在一起時,git log 呈現這些提交的順序是沒有意義的。

大多數有多位貢獻者參與的專案(例如 Linux 核心或 Git 本身)都有頻繁的合併,而 gitk 在視覺化其歷史方面做得更好。例如:

$ gitk --since="2 weeks ago" drivers/

允許您瀏覽過去兩週內修改了 drivers 目錄下檔案的任何提交。(注意:您可以透過按住 Control 鍵同時按“-”或“+”來調整 gitk 的字型。)

最後,大多數接受檔名的命令可以選擇在任何檔名之前加上一個提交,以指定檔案的特定版本:

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

您也可以使用 git show 來檢視任何此類檔案:

$ git show v2.5:Makefile

下一步

本教程應該足以對您的專案執行基本的分散式版本控制。但是,要完全理解 Git 的深度和強大功能,您需要理解它所基於的兩個簡單概念:

  • 物件資料庫是一個相當優雅的系統,用於儲存您專案的歷史——檔案、目錄和提交。

  • 索引檔案是目錄樹狀態的快取,用於建立提交、檢出工作目錄以及儲存合併中涉及的各種樹。

本教程的第二部分將解釋物件資料庫、索引檔案以及您需要了解的其他一些零散知識,以便充分利用 Git。您可以在 gittutorial-2[7] 找到它。

如果您不想立即繼續學習,以下是一些可能在此刻引起您興趣的其他內容:

  • git-format-patch[1], git-am[1]:這些命令可以將 Git 提交序列轉換為電子郵件補丁,反之亦然,對於像 Linux 核心這樣高度依賴電子郵件補丁的專案很有用。

  • git-bisect[1]:當您的專案出現迴歸時,一種查詢 bug 的方法是搜尋歷史記錄,找到導致問題的確切提交。git bisect 可以幫助您對該提交進行二分查詢。即使在複雜的非線性歷史以及大量合併分支的情況下,它也足夠智慧,能夠執行接近最優的搜尋。

  • gitworkflows[7]:概述了推薦的工作流程。

  • giteveryday[7]:日常 Git 使用,包含大約 20 個命令。

  • gitcvs-migration[7]:Git for CVS users (CVS 使用者遷移到 Git)。

GIT

Git[1] 套件的一部分