Git 使用手冊

*** last update: 2010.11.30 ***
*** 本篇文章已經過舊,請參考以下連結閱讀新版內容 ***
*** http://zx1986.github.io/blog/using-git.html ***

Git(http://git-scm.com/)是一套分散式的版本管理系統。
類似 SVN(Subversion)或 CVS(Concurrent Version System)對程式碼或文件進行管理。

Git 的概念很單純,想像一下:
你的書櫃裡有許多書,偶而有新書進來,有舊書捐出去。
有時候你還會在某些書上作筆記、寫心得、畫畫。
你在書櫃的側邊貼上一張「大大的白紙」,對書櫃裡的所有變動作紀錄。
紀錄新書擺入的時間,擺放的位置,甚至後面加個註記:『購於網路拍賣』;
紀錄舊書清除的時間,原本的位置,加個註記:『oh,好捨不得』;
紀錄某書寫入筆記的時間,什麼樣的筆記,心得或隨手塗鴉;
紀錄……
當然很少人會這麼費工書寫自己書櫃的變遷歷史。
但這張書櫃側邊貼著的「大大白紙」就類似於 Git,而且 Git 會做得更鉅細靡遺。

當你對一個資料夾啟用 Git 進行追蹤管理與控制時(其實就是 Git 初始化),
Git 程式會在該資料夾底下新增一個名為「.git」的隱藏資料夾。
「.git」類似於前面提到那張「大大的白紙」,裡面紀錄了檔案的變化史。
「.git」會對該資料夾內所有的檔案與其底層的所有資料夾進行紀錄追蹤。
不過,Git 並不會主動、自動紀錄,必須靠使用者操作。使用者類似於史官的角色。
當然,Git 的背後的運作方式更為聰明而且複雜。

Git 的功能不僅僅如此。
團隊合作時,同樣一個文件,在你手上跟在他人手上,可能有不一樣的變化史。
當你的檔案要與他人的合併時,內容有出入的地方,Git 會協助進行處理。
(例如開發同一個程式,你寫的 code 可能被他人改動到,或反之。)

Git 還有其他許多功能與應用,請慢慢挖掘。

建議先執行以下指令,將系統預設編輯器選擇為 Vim:

sudo update-alternatives --config editor

Ubuntu 底下安裝 Git 非常簡單,只要在終端機執行:

sudo apt-get install git-core git-doc

[ 註:亦可以使用 tarball 進行安裝。]

每個使用者帳號都會有它自己的 Git 設定檔,通常是:
~/.gitconfig 例如我的設定檔內容是:

[user]
name = Z
email = zx1986@gmail.com
[color]
diff = auto

設定完成後可以開一個新的資料夾進行練習。

設計上 Git 不會把空的資料夾加入控管。
建議可以在空的資料夾底下建立一個隱藏檔,例如:.gitignore
執行以下指令產生 .gitignore:

tocuh .gitignore

.gitignore 可以寫入「不希望被 Git 控管的檔案」,例如:

*.log
*.o
*.so
*.a
*.exe
*~

執行以下指令初始化 Git(資料夾內會多出一個名為 .git 的隱藏資料夾):

git init

之後只要每次修改或新增檔案後,執行以下兩個指令,Git 就會做一次紀錄:

git add . git commit -a -m '關於此次修改的描述訊息'

好了,您已經開始在使用 Git 啦!

執行:
git 會顯示常用的 Git 指令與參數,例如:

git add
git commit
git clone
git pull
git status
git rm
git mv

在整個 Git 指令後面加上 -h 參數,能夠查詢該指令可以附加哪些參數,例如:

git add -h
git commit -h

要查詢完整的指令手冊,可以執行:

git help 指令名稱

【關於 Git Repository】

一個被 Git 所追蹤管理的專案,稱為一個 Git Repository(倉儲)。

Git Repository 裡預設的 Trunk(主幹)稱為「master」,
Git Repository 裡其他的 Branch(分支)則由使用者命名。

Git 是一個分散式的版本控制系統,不同於 SVN 傳統的 Server/Client 架構。
Git 不需要像 SVN 必須有一個 Repository Server 作為主要的儲存倉儲。
Git 只要安裝好,預設就可以使用 ssh 互相進行 Repository 傳輸了。

當使用 git clone 指令從遠端複製一個 Git Repository 到本地端電腦上時,
遠端的 Git Repository 通常稱為「origin」;
本地端的 Git Repository 則沒有特殊的名稱(或許可稱為「Local Trunk」?)。

一般應用情形是這樣:

假設遠端的電腦叫做 Remote;本地端的電腦叫做 Local。
Remote 上面有一個 Git Repository 資料夾叫做 remote_repository。

要將 remote_repository 整個複製到 Local 上並命名為 local_repository,在 Local 上執行:

Local$ git clone 「Remote 使用者帳號@Remote 位址」:「remote_repository 在 Remote 上的路徑」 local_repository

複製完成(git clone)後,Local 與 Remote 已經可以分開獨立工作了。
Git 不必拘泥於一定要把修改過的檔案更新存回當初取得檔案的地方。
Remote 可以在 remote_repository 裡發展它的檔案;
Local 可以在 local_repository 裡發展它的檔案。

等到哪天 Remote 突然想取得並合併 Local 發展的檔案,可以在 Remote 上執行:

Remote$ git pull 「Local 使用者帳號@Local 位址」:「local_repository 在 Local 上的路徑」 

當然,如果 Local 想取得與合併其他人發展的檔案,可以在 Local 上執行:

Local$ git pull 「使用者帳號@位址」:「路徑」 

#特別說明
git pull – Fetch from and merge with another repository or a local branch
git fetch – Download objects and refs from another repository

官方文件對這兩個指令是這般解釋的,看起來似乎是「git pull」會多進行一項合併的動作。
簡單說,「git pull」其實等於先執行了「git fetch」,然後再自動執行「git merge」。
有人建議少用「git pull」,多用「git fetch」然後「git merge」,請見 Reference 05。

透過底下這張圖可以稍微了解一下 Local 與 Remote 間的關係:

Git Repository
上圖中間黃色部份的「Staging Area」工作階段是一個緩衝地帶,
它讓只有被 add 過的東西,才可以被 commit。
可以直接觀察下圖了解其間的關係:

【SVN 式的往日時光】

之前,我在不同的電腦上修改程式,有可能是研究室的電腦、宿舍的電腦或筆記型電腦。
所以我在研究室的一台主機上架了 SVN 伺服器,程式主要版本儲存在 SVN 伺服器上。
每當在不同的電腦進行程式編輯時,會先從 SVN 伺服器上抓最新版本的程式下來。
編輯告一段落後,再把修改過的程式上傳回 SVN 伺服器。
簡單而言,程式集中在一台 SVN 伺服器上,要編輯時從上面更新下來,編輯完再更新回去。

像我這種從 SVN 轉換到 Git 的使用者,還很習慣於從前 SVN 那種模式:
1] 使用 svn checkout 從 SVN 伺服器將整個 Repository 複製到本機端。
2] 本機端對 Repository 的內容進行編輯、修改、新增、刪除等等。
3] 使用 svn update 檢查 SVN 伺服器有沒有其他更新與自己修改的內容有衝突。
4] 解決內容衝突的情況。
5] 使用 svn commit 將自己本機端的所有修改上傳到 SVN 伺服器。

怎麼用 Git 做到類似 SVN 那樣的情形?
有個簡單的方法。

首先,選定一台要當 Repository Server 的機器,假設叫 Server。
在 Server 開一個空的資料夾,假設叫 origin,並切換到該資料夾下。

Server$ mkdir origin
Server$ cd origin

在空資料夾底下執行:

Server$ git init --bare

該資料夾底下會產生以下檔案與資料夾:

branches/
config
description
HEAD
hooks/
info/
objects/
refs/

本地端的電腦,假設叫 Local。
Local 上一個叫 local_project 的資料夾要上傳到 Server 進行統一管理。

切換到該資料夾底下,執行:

Local$ git add .
Local$ git commit -a -m 'initialization' Local$ git remote add origin 「Server 使用者帳號@Server 位址」:「Server 上 origin 資料夾的路徑」
Local$ git push origin master
[bash]
完成以後,其他的電腦就可以使用以下指令,
從 Server 上的 origin 複製 local_project 的內容:
[bash]
Other$ git clone 「Server 使用者帳號@Server 位址」:「Server 上 origin 資料夾的路徑」 「自訂的資料夾名稱」

其他電腦要將其修改的內容傳回 Server,可以使用:

Other$ git push origin master

【Git Repository Hosting】

Git Repository 還可以使用 http 等其他方式傳輸、瀏覽、管理。

- gitosis

Git 常用指令:

git init                # 將當前資料夾進行 Git 初始化

git add .               # 將當前資料夾內所有檔案加入 Git 追蹤(tracking 或 staging)
git add 檔案名稱         # 把當前資料夾內某個檔案加入 Git 追蹤(tracking 或 staging)

git commit -a           # 將目前的變動送繳 Git 進行紀錄,會進入編寫修改訊息的畫面
git commit -a -m "*"    # commit 時直接寫入修改訊息,不進入編寫修改訊息的畫面

git tag v1.0            # 將當前 commit 過後的檔案版本命名為 v1.0

git status              # 查詢從上一次 commit 到現在,資料夾裡有哪些變化,各個檔案處於什麼狀況

git diff                                # 比較所有檔案的內容與上一次 commit 時有何差異
git diff v1.0 v2.0                      # 比較 v1.0 與 v2.0 兩個版本間所有檔案的內容
git diff v1.0:檔案名稱 v2.0:檔案名稱      # 比較 v1.0 與 v2.0 兩個版本間某個檔案的內容

git log                         # 查詢所有版本的修改狀況,顯示各版本的 hash 編號
git log -p                      # 查詢哪幾行被修改
git log --stat --summary        # 查詢每個版本間變動的檔案跟行數

git show v1.0                   # 查詢 v1.0 版裡的修改內容
git show v1.0:檔案名稱           # 查詢某個檔案在 v1.0 時的內容

git show HEAD             # 看此版本修改的資料
git show HEAD^            # 看此版本前一版的修改的資料
git show HEAD^^           # 看此版本前前一版的修改的資料

git grep "*" v1.0       # 查詢 0.01 版裡頭有沒有某些內容
git grep "*"            # 查詢現在的版本裡有沒有某些內容

git branch                     # 查看現有的分支
git branch 分支名稱             # 建立新的分支
git branch 分支名稱 v1.0        # 依照 v1.0 版本裡的內容來建立一個分支
git branch -d 分支名稱          # 刪除某個分支

git merge 某個分支名稱    # 將當前所在的分支與某個分支合併,如果出現衝突,會紀錄在有衝突的檔案中

git checkout master       # 切換到主幹上
git checkout 分支名稱      # 切換到某個分支上

git checkout HEAD   # 將所有檔案恢復到上次 commit 的狀態
git checkout -- 檔案名稱   # 將某個檔案恢復到上次 commit 的狀態

git reset --hard 某個版本的 hash 編號   # 整個 Repository 恢復到某個版本的狀態

git count-objects     # 分析 Git 資料庫狀況,計算鬆散的物件
git gc                # 維護 Git 資料庫,重組物件
git fsck --full       # 應該是類似 Git 磁碟重組之類的東西

Reference:
01. http://zh-tw.whygitisbetterthanx.com
02. http://www.qweruiop.org/nchcrails/posts/49
03. http://walkingice.twbbs.org/blog/archives/504
04. http://ihower.tw/blog/archives/3843
05. http://longair.net/blog/2009/04/16/git-fetch-and-merge

  • Trackback are closed
  • Comments (6)
  1. Well done dude!!!

    • chassic
    • 七月 15th, 2012 2:16上午

    相当不错

    • Ethan
    • 四月 14th, 2012 5:18下午

    看過不少資料 但都是原文 即使中文也只提供命令的使用與解釋
    對於使用上還是有著小小的模糊不清

    這篇文章看到一半卻已經豁然開朗了大半 真的是手冊中的精選

    感謝您的奉獻 我會留著好好研讀

  2. 很詳細的說明,謝謝分享

    • 張旭
    • 十一月 30th, 2010 4:27下午

    很高興對你有幫助!

    • 謝坤龍
    • 十一月 2nd, 2010 3:46下午

    寫得太好了,繁中手冊中的精選!

Comment are closed.