基本概念
-
工作區(working Directory)就是你在電腦裡能看到的目錄
-
版本庫(repository) 工作區有一個隱藏目錄.git,這個不算工作區,是版本庫
-
暫存區 Git的版本庫裡存了很多東西,其中最重要的就是稱為stage(或者叫index)的暫存區
-
master 還有Git為我們自動建立的第一個分支master
-
HEAD 指向master的一個指標叫HEAD
我們把檔案往Git版本庫裡新增的時候,是分兩步執行的:
第一步是用git add
把檔案新增進去,實際上就是把檔案修改新增到暫存區;
第二步是用git commit
提交更改,實際上就是把暫存區的所有內容提交到當前分支。因為我們建立Git版本庫時,Git自動為我們建立了唯一一個master分支,所以,現在,git commit
就是往master分支上提交更改。可以簡單理解為,需要提交的檔案修改通通放到暫存區,然後,一次性提交暫存區的所有修改
安裝git
mac上
-
安裝brew
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
-
安裝git
➜ ~ brew install git
#若出現下面的情況表示安裝成功
➜ ~ git --version
git version 2.10.1
ubuntu上
root@fan:~# sudo apt-get install git
sudo: 無法解析主機:fan
正在讀取軟體包列表... 完成
正在分析軟體包的依賴關係樹
正在讀取狀態資訊... 完成
git 已經是最新版 (1:2.7.4-0ubuntu1)。
升級了 0 個軟體包,新安裝了 0 個軟體包,要解除安裝 0 個軟體包,有 0 個軟體包未被升級。
安裝成功後還需要配置git
$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"
#配置別名
git config --global alias.st status #檢視狀態
git config --global alias.co checkout
git config --global alias.ci commit #提交
git config --global alias.br branch #分支
git config --global alias.unstage `reset HEAD --`
git config --global alias.last `log -1 HEAD`
git config --global alias.clog "log --color --graph --pretty=format:`%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset` --abbrev-commit"
git config --global alias.llog "log -graph --pretty=oneline --abbrev-commit"
還可以設定編輯器
git config --global core.editor vim
建立本地版本庫
-
建立裸倉庫
git --base init
sh-3.2# pwd
/Applications/XAMPP/htdocs
sh-3.2# mkdir learngit
sh-3.2# cd learngit/
sh-3.2# #初始化目錄為git可以管理的倉庫
sh-3.2# git init
Initialized empty Git repository in /Applications/XAMPP/xamppfiles/htdocs/learngit/.git/
檢視當前目錄下會多了一個.git目錄
sh-3.2# ls -ah
. .. .git
在這時最好先建好.gitignore 檔案然後在commit,或者克隆遠端倉庫前,確保遠端倉庫.gitignore檔案正確
遠端倉庫的管理和使用
克隆遠端倉庫
一次 Git 克隆會建立你自己的本地分支 master 和遠端分支 origin/master,它們都指向 origin/master 分支的最後一次提交
克隆操作會預設使用的 master作為分支名 和 origin遠端庫名
git clone [url]
或者 git clone [url] + 要克隆到哪個目錄
$ git clone git://github.com/schacon/grit.git
$ git clone git://github.com/schacon/grit.git mygrit
新增遠端倉庫
-
git remote add [shortname] [url]
新增新的遠端倉庫 -
git remote
檢視當前配置中每個遠端庫的簡短名稱-
git remote -v
顯示克隆地址
-
-
git pull
命令自動抓取資料下來,然後將遠端分支自動合併到本地倉庫中當前分支 -
git fetch [shortname]
要抓取所有遠端倉庫有的,但本地倉庫的遠端分支沒有的資訊。如果是克隆了一個倉庫,此命令會抓取從你上次克隆以來別人上傳到此遠端倉庫中的所有更新。
fetch 命令只是將遠端的資料拉到本地倉庫的遠端分支,並不自動合併到當前工作分支,只有當你確實準備好了,才能手工合併
$ git fetch origin
remote: Counting objects: 20, done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 15 (delta 5), reused 0 (delta 0)
Unpacking objects: 100% (15/15), done.
From git@github.com:schacon/simplegit
* [new branch] serverfix -> origin/serverfix
在 fetch 操作下載好新的遠端分支之後,你仍然無法在本地編輯該遠端倉庫中的分支。換句話說,在本例中,你不會有一個新的serverfix 分支,有的只是一個你無法移動的 origin/serverfix 指標
如果要把該內容合併到當前分支,可以執行 git merge origin/serverfix
。如果想要一份自己的 serverfix 來開發,可以在遠端分支的基礎上分化出一個新的分支來:
$ git checkout -b serverfix origin/serverfix
Branch serverfix set up to track remote branch refs/remotes/origin/serverfix.
Switched to a new branch "serverfix"
這會切換到新建的 serverfix 本地分支,其內容同遠端分支 origin/serverfix 一致,這樣你就可以在裡面繼續開發了。
舉例
root@fan:/home/wwwroot/git# git init
初始化空的 Git 倉庫於 /home/wwwroot/git/.git/
root@fan:/home/wwwroot/git# git status
位於分支 master
初始提交
無檔案要提交(建立/拷貝檔案並使用 "git add" 建立跟蹤)
root@fan:/home/wwwroot/git# git remote add demo git@git.coding.net:fan_code/ceshi2.git
root@fan:/home/wwwroot/git# git remote
demo
root@fan:/home/wwwroot/git# git remote -v
demo git@git.coding.net:fan_code/ceshi2.git (fetch)
demo git@git.coding.net:fan_code/ceshi2.git (push)
root@fan:/home/wwwroot/git# git fetch demo
remote: Counting objects: 7993, done.
remote: Compressing objects: 100% (4985/4985), done.
remote: Total 7993 (delta 2470), reused 7993 (delta 2470)
接收物件中: 100% (7993/7993), 7.59 MiB | 337.00 KiB/s, 完成.
處理 delta 中: 100% (2470/2470), 完成.
來自 git.coding.net:fan_code/ceshi2
* [新分支] master -> demo/master
現在,遠端倉庫[shortname]
的主幹分支(master)已經完全可以在本地訪問了,對應的名字是 demo/master,你可以將它合併到自己的某個分支,或者切換到這個分支,看看有些什麼有趣的更新。
修改遠端倉庫地址
Git 倉庫地址修改辦法 git remote set-url origin [NEW_URL]
推送資料到遠端倉庫
-
git push [remote-name] [branch-name]
例如:把本地的 master 分支推送到origin 伺服器上
$ git push origin master
把本地的 master 分支推送到 origin 上並改名為 test
$ git push origin master:test
檢視遠端倉庫資訊
-
git remote show [remote-name]
檢視某個遠端倉庫的詳細資訊
舉例
$ git remote show origin
* remote origin
URL: git@github.com:defunkt/github.git
Remote branch merged with `git pull` while on branch issues
issues
Remote branch merged with `git pull` while on branch master
master
New remote branches (next fetch will store in remotes/origin)
caching
Stale tracking branches (use `git remote prune`)
libwalker
walker2
Tracked remote branches
acl
apiv2
dashboard2
issues
master
postgres
Local branch pushed with `git push`
master:master
它告訴我們,執行 git push
時預設推送的分支是什麼(譯註:最後兩行)。它還顯示了有哪些遠端分支還沒有同步到本地(譯註:第六行的caching 分支),哪些已同步到本地的遠端分支在遠端伺服器上已被刪除(譯註:Stale tracking branches 下面的兩個分支),以及執行git pull 時將自動合併哪些分支(譯註:前四行中列出的 issues 和 master 分支)。
遠端倉庫的移除和重新命名
-
git remote rename 原名 新名
-
git remote rm 遠端倉庫別名
碰到遠端倉庫伺服器遷移,或者原來的克隆映象不再使用,又或者某個參與者不再貢獻程式碼,那麼需要移除對應的遠端倉庫,可以執行
檔案管理
將已被git跟蹤的檔案移除跟蹤
另外一種情況是,我們想把檔案從Git倉庫中刪除(亦即從暫存區域移除),但仍然希望保留在當前工作目錄中。換句話說,僅是從跟蹤清單中刪除。比如一些大型日誌檔案或者一堆.a 編譯檔案,不小心納入倉庫後,要移除跟蹤但不刪除檔案,以便稍後在 .gitignore 檔案中補上,用 –cached 選項即可:
$ git rm --cached readme.txt
刪除檔案
後面可以列出檔案或者目錄的名字,也可以使用 glob 模式。比方說:
$ git rm log/*.log
注意到星號*之前的反斜槓,因為Git有它自己的檔案模式擴充套件匹配方式,所以我們不用shell來幫忙展開(譯註:實際上不加反斜槓也可以執行,只不過按照shell擴充套件的話,僅僅刪除指定目錄下的檔案而不會遞迴匹配。上面的例子本來就指定了目錄,所以效果等同,但下面的例子就會用遞迴方式匹配,所以必須加反斜 槓。)。此命令刪除所有log/ 目錄下副檔名為 .log 的檔案。類似的比如:
$ git rm *~
會遞迴刪除當前目錄及其子目錄中所有 ~ 結尾的檔案。
移動檔案
不像其他的VCS系統,Git並不跟蹤檔案移動操作。如果在Git中重新命名了某個檔案,倉庫中儲存的後設資料並不會體現出這是一次改名操作。不過Git非常聰明,它會推斷出究竟發生了什麼,至於具體是如何做到的,我們稍後再談。
既然如此,當你看到 Git 的 mv 命令時一定會困惑不已。要在 Git 中對檔案改名,可以這麼做:
$ git mv file_from file_to
它會恰如預期般正常工作。實際上,即便此時檢視狀態資訊,也會明白無誤地看到關於重新命名操作的說明:
$ git mv README.txt README
$ git status
# On branch master
# Your branch is ahead of `origin/master` by 1 commit.
#
# Changes to be committed:
# (use "git reset HEAD
..." to unstage)
#
# renamed: README.txt -> README
#
其實,執行 git mv 就相當於執行了下面三條命令:
$ mv README.txt README
$ git rm README.txt
$ git add README
如此分開操作,Git也會意識到這是一次改名,所以不管何種方式都一樣。當然,直接用 git mv
輕便得多,不過有時候用其他工具批處理改名的話,要記得在提交前刪除老的檔名,再新增新的檔名。
檔案對比
-
git diff
比較工作區和暫存區檔案差異 -
git diff –staged/–cached
比較暫存區和版本庫檔案差異 -
git diff HEAD 可以檢視工作區和版本庫裡面最新版本的區別
-
git diff HEAD — 檔名 可以檢視指定檔案工作區和版本庫裡面最新版本的區別
舉例
root@fan:/home/wwwroot/Demo# vim t2 root@fan:/home/wwwroot/Demo# git diff diff --git a/t2 b/t2 index 9bc7ad0..2672a75 100644 --- a/t2 +++ b/t2 @@ -1 +1,2 @@ t2 +t2 root@fan:/home/wwwroot/Demo# git add t2 root@fan:/home/wwwroot/Demo# git diff root@fan:/home/wwwroot/Demo# git diff --staged diff --git a/t2 b/t2 index 9bc7ad0..2672a75 100644 --- a/t2 +++ b/t2 @@ -1 +1,2 @@ t2 +t2 root@fan:/home/wwwroot/Demo# git commit -m `+t2` [master 8a74487] +t2 1 file changed, 1 insertion(+) root@fan:/home/wwwroot/Demo# git status 位於分支 master 您的分支領先 `origin/master` 共 5 個提交。 (使用 "git push" 來發布您的本地提交) 無檔案要提交,乾淨的工作區 root@fan:/home/wwwroot/Demo# git diff root@fan:/home/wwwroot/Demo# git diff --staged
提交歷史
檢視
git log
有許多選項可以幫助你搜尋感興趣的提交,接下來我們介紹些最常用的。
我們常用 -p
選項展開顯示每次提交的內容差異,
-
-2
則僅顯示最近的兩次更新:
$ git log -p -2
-
–stat,僅顯示簡要的增改行數統計
$ git log --stat
-
--pretty
選項可以指定使用完全不同於預設格式的方式展示提交歷史。比如用oneline將每個提交放在一行顯示,這在提交數很大時非常有用**
$ git log --pretty=oneline
edde8f5624c75017e81004b221d2a70e5ed31092 update README.md
75cc8c7ad7cf14f6eaded270c6b472b0b18accbd Initial commit
-
還可以用
oneline
結合--graph
選項顯示ASCII圖形表示的分支合併歷史,形象地展示了每個提交所在的分支及其分化衍合情況, `--abbrev-commit` 僅顯示sha-1前幾個字元,而非所有字元**
$ git log --graph --pretty=oneline --abbrev-commit
* 6be44b4 merge dev
|
| * d081be9 I am dev
* | c65bc40 I am master
|/
* aaa7a54 初始化
-
format
可以定製要顯示的記錄格式,這樣的輸出便於後期程式設計提取分析
$ git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 11 months ago : changed the version number
085bb3b - Scott Chacon, 11 months ago : removed unnecessary test code
a11bef0 - Scott Chacon, 11 months ago : first commit
格式佔位符說明
選項 說明
%H 提交物件(commit)的完整雜湊字串
%h 提交物件的簡短雜湊字串
%T 樹物件(tree)的完整雜湊字串
%t 樹物件的簡短雜湊字串
%P 父物件(parent)的完整雜湊字串
%p 父物件的簡短雜湊字串
%an 作者(author)的名字
%ae 作者的電子郵件地址
%ad 作者修訂日期(可以用 -date= 選項定製格式)
%ar 作者修訂日期,按多久以前的方式顯示
%cn 提交者(committer)的名字
%ce 提交者的電子郵件地址
%cd 提交日期
%cr 提交日期,按多久以前的方式顯示
%s 提交說明
-
git log
支援的其他命令選項
選項 說明
-p 按補丁格式顯示每個更新之間的差異。
--stat 顯示每次更新的檔案修改統計資訊。
--shortstat 只顯示 --stat 中最後的行數修改新增移除統計。
--name-only 僅在提交資訊後顯示已修改的檔案清單。
--name-status 顯示新增、修改、刪除的檔案清單。
--abbrev-commit 僅顯示 SHA-1 的前幾個字元,而非所有的 40 個字元。
--relative-date 使用較短的相對時間顯示(比如,“2 weeks ago”)。
--graph 顯示 ASCII 圖形表示的分支合併歷史。
--pretty 使用其他格式顯示歷史提交資訊。可用的選項包括 oneline,short,full,fuller 和 format(後跟指定格式)。
-
過濾log輸出
選項 說明
-(n) 僅顯示最近的 n 條提交
--since, --after 僅顯示指定時間之後的提交。
--until, --before 僅顯示指定時間之前的提交。
--author 僅顯示指定作者相關的提交。
--committer 僅顯示指定提交者相關的提交。
例如
$ git log --pretty="%h - %s" --author=gitster --since="2008-10-01" --before="2008-11-01" --no-merges -- t/
修改最後一次提交
有時候我們提交完了才發現漏掉了幾個檔案沒有加,或者提交資訊寫錯了。想要撤消剛才的提交操作,可以使用--amend
選項重新提交:啟動文字編輯器後,會看到上次提交時的說明,編輯它確認沒問題後儲存退出,就會使用新的提交說明覆蓋剛才失誤的提交。
$ git commit -m `initial commit`
$ git add forgotten_file
$ git commit --amend
上面的三條命令最終只是產生一個提交,第二個提交命令修正了第一個的提交內容。
例如:本機mac舉例
root@fan:/home/wwwroot/Demo# vim README.md
root@fan:/home/wwwroot/Demo# vim test.md
root@fan:/home/wwwroot/Demo# git log --pretty=oneline --abbrev-commit -2
097860c one
90a8fec phpstorm idea
root@fan:/home/wwwroot/Demo# git add README.md
root@fan:/home/wwwroot/Demo# git commit -m `two`
[master 490cf35] two
1 file changed, 1 insertion(+)
root@fan:/home/wwwroot/Demo# git status
位於分支 master
您的分支領先 `origin/master` 共 2 個提交。
(使用 "git push" 來發布您的本地提交)
尚未暫存以備提交的變更:
(使用 "git add <檔案>..." 更新要提交的內容)
(使用 "git checkout -- <檔案>..." 丟棄工作區的改動)
修改: test.md
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
root@fan:/home/wwwroot/Demo# git add test.md
root@fan:/home/wwwroot/Demo# git log --pretty=oneline --abbrev-commit -2
490cf35 two
097860c one
root@fan:/home/wwwroot/Demo# git commit --amend
[master 372f01e] ootwo
Date: Tue Dec 6 20:13:35 2016 +0800
2 files changed, 2 insertions(+)
root@fan:/home/wwwroot/Demo# git log --pretty=oneline --abbrev-commit -2
372f01e ootwo
097860c one
git 各種撤銷操作
版本回退
說明
類似3628164…882e1e0的是
commit_id
(版本號),和SVN不一樣,Git的commit_id
不是1,2,3……遞增的數字,而是一個SHA1計算出來的一個非常大的數字,用十六進位制表示,而且你看到的commit_id
和我的肯定不一樣,以你自己的為準。為什麼commit_id
需要用這麼一大串數字表示呢?因為Git是分散式的版本控制系統,後面我們還要研究多人在同一個版本庫裡工作,如果大家都用1,2,3……作為版本號,那肯定就衝突了。
每提交一個新版本,實際上Git就會把它們自動串成一條時間線。如果使用視覺化工具檢視Git歷史,就可以更清楚地看到提交歷史的時間線
root@fan:/home/wwwroot/Demo# git log --pretty=oneline
8a744873ac755647767abd149adef2e86ae53d71 +t2
97a15f36b57f6a0c588a058f654901ebeab6de31 +t1
ec30b4cb269ca10560b9abfe203fdd7a5abc7cfb 初始化
-
HEAD
指向的版本就是當前版本,HEAD^
指的是上一個版本,HEAD^^
指的是上上個版本。因此,Git允許我們在版本的歷史之間穿梭,使用命令git reset --hard commit_id
。commit id版本號沒必要寫全,前幾位就可以了,Git會自動去找 -
穿梭前,用
git log
可以檢視提交歷史,以便確定要回退到哪個版本。要重返未來,用git reflog
檢視命令提交歷史,以便確定要回到未來的哪個版本舉例
root@fan:/home/wwwroot/Demo# git log --pretty=oneline --abbrev-commit 8a74487 +t2 97a15f3 +t1 ec30b4c 初始化 root@fan:/home/wwwroot/Demo# git reset --hard HEAD^ HEAD 現在位於 97a15f3 +t1 root@fan:/home/wwwroot/Demo# git log --pretty=oneline --abbrev-commit 97a15f3 +t1 ec30b4c 初始化 root@fan:/home/wwwroot/Demo# git reflog 97a15f3 HEAD@{0}: reset: moving to HEAD^ 8a74487 HEAD@{1}: commit: +t2 97a15f3 HEAD@{2}: commit: +t1 ec30b4c HEAD@{3}: commit: 初始化 root@fan:/home/wwwroot/Demo# git reset --hard 8a74487 HEAD 現在位於 8a74487 +t2 root@fan:/home/wwwroot/Demo# git log --pretty=oneline --abbrev-commit 8a74487 +t2 97a15f3 +t1 ec30b4c 初始化 root@fan:/home/wwwroot/Demo# git reflog 8a74487 HEAD@{0}: reset: moving to 8a74487 97a15f3 HEAD@{1}: reset: moving to HEAD^ 8a74487 HEAD@{2}: commit: +t2 97a15f3 HEAD@{3}: commit: +t1 ec30b4c HEAD@{4}: commit: 初始化
撤銷檔案修改
假如現在工作區,暫存區某個檔案為版本2,版本庫為版本1,修改工作區檔案後,工作區變為版本3,執行命令git reset HAED file ,暫存區變為版本1,跟版本庫一致,而工作區的版本還為版本3
-
場景1:使用git checkout — readme.txt丟棄工作區修改
當你改亂了工作區某個檔案的內容,想直接丟棄工作區的修改時,用命令
git checkout -- file
。命令git checkout — readme.txt
把readme.txt檔案在工作區的修改全部撤銷,這裡有兩種情況:一種是readme.txt自修改後還沒有被放到暫存區,現在,撤銷修改就回到和版本庫一模一樣的狀態;
一種是readme.txt已經新增到暫存區後,又作了修改,現在,撤銷修改就回到新增到暫存區後的狀態。
總之,就是讓這個檔案回到最近一次
git commit
或git add
時的狀態。 -
場景2:使用git reset HEAD file丟棄暫存區修改
當你不但改亂了工作區某個檔案的內容,還新增到了暫存區時,新增完之後又修改了工作區,想丟棄暫存區的修改,分兩步,
-
第一步用命令
git reset HEAD file
,
用命令
git reset HEAD file
可以把暫存區的修改撤銷掉(unstage),而工作區的檔案沒有變化就回到了場景1,
-
第二步按場景1操作。
-
-
場景3:版本回退
已經提交了不合適的修改到版本庫時,想要撤銷本次提交,參考版本回退,不過前提是沒有推送到遠端庫。
標籤管理
新建
-
git tag <name>
用於新建一個標籤,預設標籤是打在最新提交的commit上,也可以指定一個commit id; -
git tag -a <tagname> -m "blablabla..."
可以指定標籤資訊; -
git tag -s <tagname> -m "blablabla..."
可以用PGP簽名標籤;
檢視
-
git tag
可以檢視所有標籤,git show <tagname>
檢視標籤所指向的提交例子
root@fan:/home/wwwroot/git/demo# git status 位於分支 master 無檔案要提交,乾淨的工作區 root@fan:/home/wwwroot/git/demo# git reflog 7aca999 HEAD@{0}: commit: c a8e8e16 HEAD@{1}: commit: b 9cab6a8 HEAD@{2}: commit (initial): a root@fan:/home/wwwroot/git/demo# clear root@fan:/home/wwwroot/git/demo# git tag `cc` root@fan:/home/wwwroot/git/demo# git tag cc root@fan:/home/wwwroot/git/demo# git reflog 7aca999 HEAD@{0}: commit: c a8e8e16 HEAD@{1}: commit: b 9cab6a8 HEAD@{2}: commit (initial): a root@fan:/home/wwwroot/git/demo# git show cc commit 7aca999821cd3384d634a7985782e8816d851d9b Author: fan <fan@qq.com> Date: Wed Dec 7 21:08:35 2016 +0800 c diff --git a/c b/c new file mode 100644 index 0000000..f2ad6c7 --- /dev/null +++ b/c @@ -0,0 +1 @@ +c root@fan:/home/wwwroot/git/demo# git tag -a bb -m `bbbbb` a8e8e16 root@fan:/home/wwwroot/git/demo# git tag bb cc root@fan:/home/wwwroot/git/demo# git show bb tag bb Tagger: fan <fan@qq.com> Date: Wed Dec 7 21:09:52 2016 +0800 bbbbb commit a8e8e16567a8c9adf06fe2778ee647250425451d Author: fan <fan@qq.com> Date: Wed Dec 7 21:07:53 2016 +0800 b diff --git a/b b/b new file mode 100644 index 0000000..6178079 --- /dev/null +++ b/b @@ -0,0 +1 @@ +b
推送標籤到伺服器
-
推送單個標籤
git push origin <tagname>
-
推送所有標籤
git push origin --tags
刪除伺服器標籤
-
首先刪除本地標籤
git tag -d [tagname]
-
刪除伺服器上標籤
git push origin :refs/tags/[tagname]
例子
root@fan:/home/wwwroot/git/Demo# git pull Already up-to-date. root@fan:/home/wwwroot/git/Demo# git push origin --tags Total 0 (delta 0), reused 0 (delta 0) To git@git.coding.net:fan_code/Demo.git * [new tag] 1 -> 1 * [new tag] 2 -> 2 root@fan:/home/wwwroot/git/Demo# git tag -d 1 已刪除標籤 `1`(曾為 90a8fec) root@fan:/home/wwwroot/git/Demo# git tag 2 root@fan:/home/wwwroot/git/Demo# git push origin :refs/tags/1 To git@git.coding.net:fan_code/Demo.git - [deleted] 1
分支管理
工作場景
假設此時,你突然接到一個電話說有個很嚴重的問題需要緊急修補,那麼可以按照下面的方式處理:
-
返回到原先已經發布到生產伺服器上的分支。
-
為這次緊急修補建立一個新分支,並在其中修復問題。
-
通過測試後,回到生產伺服器所在的分支,將修補分支合併進來,然後再推送到生產伺服器上。
-
切換到之前實現新需求的分支,繼續工作。在切換回來之後,應該也把當前分支的bug修復
檢視分支 git branch [name]
-
[name] 是新增分支
-
-d [name] 刪除乾淨的分支(假如分支中包含尚未合併進來的工作成果,則為不乾淨的分支)
-
-D [name] 強制刪除
-
-v 檢視各個分支最後一個提交物件的資訊
-
–merged 檢視哪些分支已被併入當前分支(也就是說哪些分支是當前分支的直接上游,如果有分支內容與當前分支內容一致,也會顯示)
-
–no-merged 檢視哪些分支未被併入當前分支
切換分支 git checkout [name]
git checkout master
它把 HEAD 指標移回到 master 分支,並把工作目錄中的檔案換成了 master 分支所指向的快照內容
建立並切換分支 git checkout -b [name]
合併分支到當前工作分支 git merge [被合併的分支]
分支合併分為:直接祖先合併、非直接祖先合併(會進行三方合併)
-
直接祖先合併
-
合併時出現了“Fast forward”的提示。由於當前 master 分支所在的提交物件是要併入的 hotfix 分支的直接上游,Git 只需把master 分支指標直接右移。換句話說,如果順著一個分支走下去可以到達另一個分支的話,那麼 Git 在合併兩者時,只會簡單地把指標右移,因為這種單線的歷史分支不存在任何需要解決的分歧,所以這種合併過程可以稱為快進(Fast forward)。
-
-
非直接祖先合併(合併mster-c4和iss53->c5)
-
-
這次你的開發歷史是從更早的地方開始分叉的。由於當前 master 分支所指向的提交物件(C4)並不是 iss53 分支的直接祖先,Git 不得不進行一些額外處理。就此例而言,Git 會用兩個分支的末端(C4 和 C5)以及它們的共同祖先(C2)進行一次簡單的三方合併計算。這次,Git 沒有簡單地把分支指標右移,而是對三方合併後的結果重新做一個新的快照,並自動建立一個指向它的提交物件(C6)。這個提交物件比較特殊,它有兩個祖先(C4 和 C5)。
-
-
刪除分支 git branch -d [name]
推送所有分支到遠端倉庫origin git push origin –all
root@fan:/home/wwwroot/git/Demo# git push origin --all
物件計數中: 3, 完成.
壓縮物件中: 100% (3/3), 完成.
寫入物件中: 100% (3/3), 280 bytes | 0 bytes/s, 完成.
Total 3 (delta 2), reused 0 (delta 0)
To git@git.coding.net:fan_code/Demo.git
* [new branch] dev -> dev
* [new branch] dev2 -> dev2
* [new branch] test -> test
長期分支
由於 Git 使用簡單的三方合併,所以就算在較長一段時間內,反覆多次把某個分支合併到另一分支,也不是什麼難事。也就是說,你可以同時擁有多個開放的分支,每個分支用於完成特定的任務,隨著開發的推進,你可以隨時把某個特性分支的成果併到其他分支中。
特性分支
在任何規模的專案中都可以使用特性(Topic)分支。一個特性分支是指一個短期的,用來實現單一特性或與其相關工作的分支。可能你在以前的版本控 制系統裡從未做過類似這樣的事情,因為通常建立與合併分支消耗太大。然而在 Git 中,一天之內建立、使用、合併再刪除多個分支是常見的事。
遠端分支
遠端分支(remote branch)是對遠端倉庫中的分支的索引。它們是一些無法移動的本地分支;只有在 Git 進行網路互動時才會更新。
我們用 (遠端倉庫名)/(分支名) 這樣的形式表示遠端分支
一次 Git 克隆會建立你自己的本地分支 master 和遠端分支 origin/master,它們都指向 origin/master 分支的最後一次提交
跟蹤遠端分支
從遠端分支 checkout 出來的本地分支,稱為_跟蹤分支(tracking branch)_。跟蹤分支是一種和遠端分支有直接聯絡的本地分支。在跟蹤分支裡輸入git push,Git 會自行推斷應該向哪個伺服器的哪個分支推送資料。反過來,在這些分支裡執行 git pull 會獲取所有遠端索引,並把它們的資料都合併到本地分支中來。
在克隆倉庫時,Git 通常會自動建立一個名為 master 的分支來跟蹤 origin/master。這正是git push 和 git pull 一開始就能正常工作的原因。當然,你可以隨心所欲地設定為其它跟蹤分支,比如origin 上除了 master 之外的其它分支。剛才我們已經看到了這樣的一個例子:git checkout -b [分支名] [遠端名]/[分支名]。如果你有 1.6.2 以上版本的 Git,還可以用–track 選項簡化:
$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch refs/remotes/origin/serverfix.
Switched to a new branch "serverfix"
要為本地分支設定不同於遠端分支的名字,只需在前個版本的命令裡換個名字:
$ git checkout -b sf origin/serverfix
Branch sf set up to track remote branch refs/remotes/origin/serverfix.
Switched to a new branch "sf"
現在你的本地分支 sf 會自動向 origin/serverfix 推送和抓取資料了。
刪除遠端分支
如果不再需要某個遠端分支了,比如搞定了某個特性並把它合併進了遠端的 master 分支(或任何其他存放穩定程式碼的地方),可以用這個非常無厘頭的語法來刪除它:git push [遠端名] :[分支名]
。如果想在伺服器上刪除serverfix 分支,執行下面的命令:
$ git push origin :serverfix
To git@github.com:schacon/simplegit.git
- [deleted] serverfix
有種方便記憶這條命令的方法:記住我們不久前見過的 git push [遠端名] [本地分支]:[遠端分支]
語法,如果省略 [本地分支]
,那就等於是在說“在這裡提取空白然後把它變成[遠端分支]
”。
在伺服器上部署 Git
開始架設 Git 伺服器前,需要先把現有倉庫匯出為裸倉庫 — 即一個不包含當前工作目錄的倉庫。克隆時用 --bare
選項即可。裸倉庫的目錄名一般以.git
結尾,像這樣:
$ git clone --bare my_project my_project.git
Initialized empty Git repository in /opt/projects/my_project.git/
有了裸倉庫的副本後,剩下的就是把它放到伺服器上並設定相關協議。假設一個域名為 git.example.com
的伺服器已經架設好,並可以通過 SSH 訪問,我們打算把所有 Git 倉庫儲存在/opt/git 目錄下。只要把裸倉庫複製過去:
$ scp -r my_project.git user@git.example.com:/opt/git
現在,所有對該伺服器有 SSH 訪問許可權,並可讀取 /opt/git 目錄的使用者都可以用下面的命令克隆該專案:
$ git clone user@git.example.com:/opt/git/my_project.git
如果某個 SSH 使用者對 /opt/git/my_project.git
目錄有寫許可權,那他就有推送許可權。
由此可見,根據現有的 Git 倉庫建立一個裸倉庫,然後把它放上你和同事都有 SSH 訪問權的伺服器是多麼容易。現在已經可以開始在同一專案上密切合作了。
這是架設一個少數人具有連線權的 Git 服務的全部 — 只要在伺服器上加入可以用 SSH 登入的帳號,然後把裸倉庫放在大家都有讀寫許可權的地方。一切都準備停當,無需更多。
小型安裝
如果裝置較少或者你只想在小型開發團隊裡嘗試 Git ,那麼一切都很簡單。架設 Git 服務最複雜的地方在於賬戶管理。如果需要倉庫對特定的使用者可讀,而給另一部分使用者讀寫許可權,那麼訪問和許可的安排就比較困難。
SSH 連線
如果已經有了一個所有開發成員都可以用 SSH 訪問的伺服器,架設第一個伺服器將變得異常簡單,幾乎什麼都不用做(正如上節中介紹的那樣)。如果需要對倉庫進行更復雜的訪問控制,只要使用伺服器作業系統的本地檔案訪問許可機制就行了。
如果需要團隊裡的每個人都對倉庫有寫許可權,又不能給每個人在伺服器上建立賬戶,那麼提供 SSH 連線就是唯一的選擇了。我們假設用來共享倉庫的伺服器已經安裝了 SSH 服務,而且你通過它訪問伺服器。
有好幾個辦法可以讓團隊的每個人都有訪問權。
第一個辦法是給每個人建立一個賬戶,直截了當但略過繁瑣。反覆執行 adduser 並給所有人設定臨時密碼可不是好玩的。
第二個辦法是在主機上建立一個 git 賬戶,讓每個需要寫許可權的人傳送一個 SSH 公鑰,然後將其加入 git 賬戶的~/.ssh/authorized_keys 檔案。這樣一來,所有人都將通過 git 賬戶訪問主機。這絲毫不會影響提交的資料 — 訪問主機用的身份不會影響提交物件的提交者資訊。
另一個辦法是讓 SSH 伺服器通過某個 LDAP 服務,或者其他已經設定好的集中授權機制,來進行授權。只要每個人都能獲得主機的 shell 訪問權,任何可用的 SSH 授權機制都能達到相同效果。
1. 生成 SSH 公鑰
大多數 Git 伺服器都會選擇使用 SSH 公鑰來進行授權。系統中的每個使用者都必須提供一個公鑰用於授權,沒有的話就要生成一個。生成公鑰的過程在所有作業系統上都差不多。首先先確認一下是否已經有一個公鑰了。SSH 公鑰預設儲存在賬戶的主目錄下的~/.ssh 目錄。進去看看:
$ cd ~/.ssh
$ ls
authorized_keys2 id_dsa known_hosts
config id_dsa.pub
關鍵是看有沒有用 something 和 something.pub 來命名的一對檔案,這個 something 通常就是 id_dsa 或 id_rsa。有 .pub 字尾的檔案就是公鑰,另一個檔案則是金鑰。假如沒有這些檔案,或者乾脆連.ssh 目錄都沒有,可以用 ssh-keygen 來建立。該程式在 Linux/Mac 系統上由 SSH 包提供,而在 Windows 上則包含在 MSysGit 包裡:
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/schacon/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/schacon/.ssh/id_rsa.
Your public key has been saved in /Users/schacon/.ssh/id_rsa.pub.
The key fingerprint is:
43:c5:5b:5f:b1:f1:50:43:ad:20:a6:92:6a:1f:9a:3a schacon@agadorlaptop.local
它先要求你確認儲存公鑰的位置(.ssh/id_rsa)
,然後它會讓你重複一個密碼兩次,如果不想在使用公鑰的時候輸入密碼,可以留空。
現在,所有做過這一步的使用者都得把它們的公鑰給你或者 Git 伺服器的管理員(假設 SSH 服務被設定為使用公鑰機制)。他們只需要複製 .pub 檔案的內容然後發郵件給管理員。公鑰的樣子大致如下:
$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU
GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3
Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA
t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En
mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx
NrRFi9wrf+M7Q== schacon@agadorlaptop.local
關於在多個作業系統上設立相同 SSH 公鑰的教程,可以查閱 GitHub 上有關 SSH 公鑰的嚮導:http://github.com/guides/prov…。
2. 架設伺服器
現在我們過一邊伺服器端架設 SSH 訪問的流程。本例將使用 authorized_keys
方法來給使用者授權。我們還將假定使用類似 Ubuntu 這樣的標準 Linux 發行版。首先,建立一個名為 ‘git’ 的使用者,併為其建立一個.ssh 目錄。
$ sudo adduser git
$ su git
$ cd
$ mkdir .ssh
接下來,把開發者的 SSH 公鑰新增到這個使用者的 authorized_keys 檔案中。假設你通過電郵收到了幾個公鑰並存到了臨時檔案裡。重複一下,公鑰大致看起來是這個樣子:
$ cat /tmp/id_rsa.john.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCB007n/ww+ouN4gSLKssMxXnBOvf9LGt4L
ojG6rs6hPB09j9R/T17/x4lhJA0F3FR1rP6kYBRsWj2aThGw6HXLm9/5zytK6Ztg3RPKK+4k
Yjh6541NYsnEAZuXz0jTTyAUfrtU3Z5E003C4oxOj6H0rfIF1kKI9MAQLMdpGW1GYEIgS9Ez
Sdfd8AcCIicTDWbqLAcU4UpkaX8KyGlLwsNuuGztobF8m72ALC/nLF6JLtPofwFBlgc+myiv
O7TCUSBdLQlgMVOFq1I2uPWQOkOWQAHukEOmfjy2jctxSDBQ220ymjaNsHT4kgtZg2AYYgPq
dAv8JggJICUvax2T9va5 gsg-keypair
只要把它們逐個追加到 authorized_keys 檔案尾部即可:
$ cat /tmp/id_rsa.john.pub >> ~/.ssh/authorized_keys
$ cat /tmp/id_rsa.josie.pub >> ~/.ssh/authorized_keys
$ cat /tmp/id_rsa.jessica.pub >> ~/.ssh/authorized_keys
現在可以用 –bare 選項執行 git init 來建立一個裸倉庫,這會初始化一個不包含工作目錄的倉庫。
$ cd /opt/git
$ mkdir project.git
$ cd project.git
$ git --bare init
這時,Join,Josie 或者 Jessica 就可以把它加為遠端倉庫,推送一個分支,從而把第一個版本的專案檔案上傳到倉庫裡了。值得注意的是,每次新增一個新專案都需要通過 shell 登入主機並建立一個裸倉庫目錄。我們不妨以gitserver 作為 git 使用者及專案倉庫所在的主機名。如果在網路內部執行該主機,並在 DNS 中設定 gitserver 指向該主機,那麼以下這些命令都是可用的:
# 在 John 的電腦上
$ cd myproject
$ git init
$ git add .
$ git commit -m `initial commit`
$ git remote add origin git@gitserver:/opt/git/project.git
$ git push origin master
這樣,其他人的克隆和推送也一樣變得很簡單:
$ git clone git@gitserver:/opt/git/project.git
$ vim README
$ git commit -am `fix for the README file`
$ git push origin master
用這個方法可以很快捷地為少數幾個開發者架設一個可讀寫的 Git 服務。
作為一個額外的防範措施,你可以用 Git 自帶的 git-shell 工具限制 git 使用者的活動範圍。只要把它設為git 使用者登入的 shell,那麼該使用者就無法使用普通的 bash 或者 csh 什麼的 shell 程式。編輯 /etc/passwd 檔案:
$ sudo vim /etc/passwd
在檔案末尾,你應該能找到類似這樣的行:
git:x:1000:1000::/home/git:/bin/sh
把 bin/sh
改為 /usr/bin/git-shell
(或者用 which git-shell 檢視它的實際安裝路徑)。該行修改後的樣子如下:
git:x:1000:1000::/home/git:/usr/bin/git-shell
現在 git 使用者只能用 SSH 連線來推送和獲取 Git 倉庫,而不能直接使用主機 shell。嘗試普通 SSH 登入的話,會看到下面這樣的拒絕資訊:
$ ssh git@gitserver
fatal: What do you think I am? A shell?
Connection to gitserver closed.
Gitosis 可以設定誰能讀或者寫哪個專案
把所有使用者的公鑰儲存在 authorized_keys 檔案的做法,只能湊和一陣子,當使用者數量達到幾百人的規模時,管理起來就會十分痛苦。每次改刪使用者都必須登入伺服器不去說,這種做法還缺少必要的許可權管理 — 每個人都對所有專案擁有完整的讀寫許可權。
幸好我們還可以選擇應用廣泛的 Gitosis 專案。簡單地說,Gitosis 就是一套用來管理 authorized_keys 檔案和實現簡單連線限制的指令碼。有趣的是,用來新增使用者和設定許可權的並非通過網頁程式,而只是管理一個特殊的 Git 倉庫。你只需要在這個特殊倉庫內做好相應的設定,然後推送到伺服器上,Gitosis 就會隨之改變執行策略,聽起來就很酷,對吧?
Gitosis 的安裝算不上傻瓜化,但也不算太難。用 Linux 伺服器架設起來最簡單 — 以下例子中,我們使用裝有 Ubuntu 8.10 系統的伺服器。
Gitosis 的工作依賴於某些 Python 工具,所以首先要安裝 Python 的 setuptools 包,在 Ubuntu 上稱為 python-setuptools:
$ apt-get install python-setuptools
接下來,從 Gitosis 專案主頁克隆並安裝:
$ git clone git://eagain.net/gitosis.git
$ cd gitosis
$ sudo python setup.py install
這會安裝幾個供 Gitosis 使用的工具。預設 Gitosis 會把 /home/git 作為儲存所有 Git 倉庫的根目錄,這沒什麼不好,不過我們之前已經把專案倉庫都放在/opt/git 裡面了,所以為方便起見,我們可以做一個符號連線,直接劃轉過去,而不必重新配置:
$ ln -s /opt/git /home/git/repositories
Gitosis 將會幫我們管理使用者公鑰,所以先把當前控制檔案改名備份,以便稍後重新新增,準備好讓 Gitosis 自動管理 authorized_keys 檔案:
$ mv /home/git/.ssh/authorized_keys /home/git/.ssh/ak.bak
接下來,如果之前把 git 使用者的登入 shell 改為 git-shell 命令的話,先恢復 ‘git’ 使用者的登入 shell。改過之後,大家仍然無法通過該帳號登入(譯註:因為authorized_keys 檔案已經沒有了。),不過不用擔心,這會交給 Gitosis 來實現。所以現在先開啟 /etc/passwd 檔案,把這行:
git:x:1000:1000::/home/git:/usr/bin/git-shell
改回:
git:x:1000:1000::/home/git:/bin/sh
好了,現在可以初始化 Gitosis 了。你可以用自己的公鑰執行 gitosis-init 命令,要是公鑰不在伺服器上,先臨時複製一份:
$ sudo -H -u git gitosis-init < /tmp/id_dsa.pub
Initialized empty Git repository in /opt/git/gitosis-admin.git/
Reinitialized existing Git repository in /opt/git/gitosis-admin.git/
這樣該公鑰的擁有者就能修改用於配置 Gitosis 的那個特殊 Git 倉庫了。接下來,需要手工對該倉庫中的 post-update 指令碼加上可執行許可權:
$ sudo chmod 755 /opt/git/gitosis-admin.git/hooks/post-update
基本上就算是好了。如果設定過程沒出什麼差錯,現在可以試一下用初始化 Gitosis 的公鑰的擁有者身份 SSH 登入伺服器,應該會看到類似下面這樣:
$ ssh git@gitserver
PTY allocation request failed on channel 0
fatal: unrecognized command `gitosis-serve schacon@quaternion`
Connection to gitserver closed.
說明 Gitosis 認出了該使用者的身份,但由於沒有執行任何 Git 命令,所以它切斷了連線。那麼,現在執行一個實際的 Git 命令 — 克隆 Gitosis 的控制倉庫:
# 在你本地計算機上
$ git clone git@gitserver:gitosis-admin.git
這會得到一個名為 gitosis-admin 的工作目錄,主要由兩部分組成:
$ cd gitosis-admin
$ find .
./gitosis.conf
./keydir
./keydir/scott.pub
gitosis.conf 檔案是用來設定使用者、倉庫和許可權的控制檔案。keydir 目錄則是儲存所有具有訪問許可權使用者公鑰的地方— 每人一個。在keydir 裡的檔名(比如上面的 scott.pub)應該跟你的不一樣 — Gitosis 會自動從使用 gitosis-init 指令碼匯入的公鑰尾部的描述中獲取該名字。
看一下 gitosis.conf 檔案的內容,它應該只包含與剛剛克隆的 gitosis-admin 相關的資訊:
$ cat gitosis.conf
[gitosis]
[group gitosis-admin]
writable = gitosis-admin
members = scott
它顯示使用者 scott — 初始化 Gitosis 公鑰的擁有者 — 是唯一能管理 gitosis-admin 專案的人。
現在我們來新增一個新專案。為此我們要建立一個名為 mobile 的新段落,在其中羅列手機開發團隊的開發者,以及他們擁有寫許可權的專案。由於 ‘scott’ 是系統中的唯一使用者,我們把他設為唯一使用者,並允許他讀寫名為iphone_project 的新專案:
[group mobile]
writable = iphone_project
members = scott
修改完之後,提交 gitosis-admin 裡的改動,並推送到伺服器使其生效:
$ git commit -am `add iphone_project and mobile group`
[master]: created 8962da8: "changed name"
1 files changed, 4 insertions(+), 0 deletions(-)
$ git push
Counting objects: 5, done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 272 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
To git@gitserver:/opt/git/gitosis-admin.git
fb27aec..8962da8 master -> master
在新工程 iphone_project 裡首次推送資料到伺服器前,得先設定該伺服器地址為遠端倉庫。但你不用事先到伺服器上手工建立該專案的裸倉庫— Gitosis 會在第一次遇到推送時自動建立:
$ git remote add origin git@gitserver:iphone_project.git
$ git push origin master
Initialized empty Git repository in /opt/git/iphone_project.git/
Counting objects: 3, done.
Writing objects: 100% (3/3), 230 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@gitserver:iphone_project.git
* [new branch] master -> master
請注意,這裡不用指明完整路徑(實際上,如果加上反而沒用),只需要一個冒號加專案名字即可 — Gitosis 會自動幫你對映到實際位置。
要和朋友們在一個專案上協同工作,就得重新新增他們的公鑰。不過這次不用在伺服器上一個一個手工新增到 ~/.ssh/authorized_keys 檔案末端,而只需管理keydir 目錄中的公鑰檔案。檔案的命名將決定在 gitosis.conf 中對使用者的標識。現在我們為 John,Josie 和 Jessica 新增公鑰:
$ cp /tmp/id_rsa.john.pub keydir/john.pub
$ cp /tmp/id_rsa.josie.pub keydir/josie.pub
$ cp /tmp/id_rsa.jessica.pub keydir/jessica.pub
然後把他們都加進 ‘mobile’ 團隊,讓他們對 iphone_project 具有讀寫許可權:
[group mobile]
writable = iphone_project
members = scott john josie jessica
如果你提交併推送這個修改,四個使用者將同時具有該專案的讀寫許可權。
Gitosis 也具有簡單的訪問控制功能。如果想讓 John 只有讀許可權,可以這樣做:
[group mobile]
writable = iphone_project
members = scott josie jessica
[group mobile_ro]
readonly = iphone_project
members = john
現在 John 可以克隆和獲取更新,但 Gitosis 不會允許他向專案推送任何內容。像這樣的組可以隨意建立,多少不限,每個都可以包含若干不同的使用者和專案。甚至還可以指定某個組為成員之一(在組名前加上@ 字首),自動繼承該組的成員:
[group mobile_committers]
members = scott josie jessica
[group mobile]
writable = iphone_project
members = @mobile_committers
[group mobile_2]
writable = another_iphone_project
members = @mobile_committers john
如果遇到意外問題,試試看把 loglevel=DEBUG 加到 [gitosis] 的段落(譯註:把日誌設定為除錯級別,記錄更詳細的執行資訊。)。如果一不小心搞錯了配置,失去了推送許可權,也可以手工修改伺服器上的/home/git/.gitosis.conf 檔案 — Gitosis 實際是從該檔案讀取資訊的。它在得到推送資料時,會把新的 gitosis.conf 存到該路徑上。所以如果你手工編輯該檔案的話,它會一直保持到下次向 gitosis-admin 推送新版本的配置內容為止。
工作流程
提交規範
請將每次提交限定於完成一次邏輯功能。並且可能的話,適當地分解為多次小更新,以便每次小型提交都更易於理解。請不要在週末窮追猛打一次性 解決五個問題,而最後拖到週一再提交。就算是這樣也請儘可能利用暫存區域,將之前的改動分解為每次修復一個問題,再分別提交和加註說明。如果針對兩個問題 改動的是同一個檔案,可以試試看git add –patch 的方式將部分內容置入暫存區域(我們會在第六章再詳細介紹)。無論是五次小提交還是混雜在一起的大提交,最終分支末端的專案快照應該還是一樣的,但分解開 來之後,更便於其他開發者複閱。這麼做也方便自己將來取消某個特定問題的修復。我們將在第六章介紹一些重寫提交歷史,同暫存區域互動的技巧和工具,以便最 終得到一個乾淨有意義,且易於理解的提交歷史
最後需要謹記的是提交說明的撰寫。寫得好可以讓大家協作起來更輕鬆。一般來說,提交說明最好限制在一行以內,50 個字元以下,簡明扼要地描述更新內容,空開一行後,再展開詳細註解。Git 專案本身需要開發者撰寫詳盡註解,包括本次修訂的因由,以及前後不同實現之間的比較,我們也該借鑑這種做法
例如
本次更新的簡要描述(50 個字元以內)
如果必要,此處展開詳盡闡述。段落寬度限定在 72 個字元以內。
某些情況下,第一行的簡要描述將用作郵件標題,其餘部分作為郵件正文。
其間的空行是必要的,以區分兩者(當然沒有正文另當別論)。
如果並在一起,rebase 這樣的工具就可能會迷惑。
另起空行後,再進一步補充其他說明。
- 可以使用這樣的條目列舉式。
- 一般以單個空格緊跟短劃線或者星號作為每項條目的起始符。每個條目間用一空行隔開。
不過這裡按自己專案的約定,可以略作變化。
-
工作流程
最簡單的協作方式之一:先在自己的特性分支中工作一段時間,完成後合併到自己的 master 分支;然後下載合併 origin/master 上的更新(如果有的話),再推回遠端伺服器。