1 前言
1.1 目的
本文檔對GIT版本管理常用命令進(jìn)行說明,這里只說明了常用的幾個(gè)命令,如果要了解更多,可以參考官方文檔。
1.2 術(shù)語與縮寫詞
暫無。
1.3 參考資料
Pro Git Book.
NetWork.
2 中文環(huán)境配置
2.1 Git Bash窗口ls正常顯示中文
在$GitHome\etc\git-completion.bash文件中添加:
alias ls='ls --show-control-chars --color=auto'
2.2 Git Bash窗口正常輸入中文
修改在$GitHome\etc\inputrc文件中的兩項(xiàng)配置:
set output-meta on
set convert-meta off
2.3 Git-log正常顯示中文
在$GitHome\etc\profile文件中添加:
export LESSCHARSET=utf-8
2.4 Git-gui正常顯示中文
在$GitHome \etc\gitconfig文件中修改或添加如下配置:
[gui]
encoding = utf-8
[i18n]
commitencoding = GB2312
如果沒有這一條,雖然我們在本地用$ git
log看自己的中文修訂沒問題,但,一、我們的log推到服務(wù)器后會(huì)變成亂碼;二、別人在Linux下推的中文log我們pull過來之后看起來也是亂碼。這是因?yàn)?,我們的commit
log會(huì)被先存放在項(xiàng)目的.git/COMMIT_EDITMSG文件中;在中文Windows里,新建文件用的是GB2312的編碼;但是Git不知道,當(dāng)成默認(rèn)的utf-8的送出去了,所以就亂碼了。有了這條之后,Git會(huì)先將其轉(zhuǎn)換成utf-8,再發(fā)出去,于是就沒問題了。
[core]
quotepath = false
作用:沒有這一條,$git status輸出中文會(huì)顯示為UNICODE編碼。
3 Git配置文件的優(yōu)先級
Git加載配置文件首先是git安裝目錄的etc/gitconfig文件,其次是用戶目錄(windows下是C:\Documents
and
Settings\Administrator[如果用戶為Administrator])下的.gitconfig文件,最后是Git工作目錄的.git/config文件,并且后邊的配置會(huì)覆蓋前邊的。
因此,Git配置的優(yōu)先級為:
1——git工作目錄.git/config
2——用戶目錄.gitconfig
3——安裝目錄etc/gitconfig
他們的配置方式也不相同,當(dāng)然都可以直接修改文件達(dá)到修改配置的目的。
Git config 是配置git工作目錄的選項(xiàng);
Git config –global是配置用戶目錄下的選項(xiàng);
安裝目錄下的選項(xiàng)需要手工修改文件。
4 基本操作命令
4.1 建立版本庫
建立空版本庫:
Mkdir repo
Cd repo
git init
建立空版本庫,版本庫只有版本記錄,沒有文件:
git init –bare
(假定版本庫的絕對路徑是:d:/repo)
修改版本庫屬性,允許提交:
git config receive. denyCurrentBranch ignore沒有這一條無法提交到版本庫。
如果是從頭建立一個(gè)版本庫,需要從其他目錄上傳文件到版本庫,假如資源文件在目錄d:/source,把source
目錄資源上傳的過程如下:
Cd source
Git init
git remote add repo file:///d:/repo
git add .
git commit –m “comment”
git push
4.2 克隆版本庫
git clone file://d:/repo repo_clone
如果沒有repo_clone,將建立一個(gè)repo版本庫,帶上建立repo_clone版本庫
4.3 忽略
如果要忽略某些文件或目錄可以:
1、 在.git/conf中增加忽略的文件或忽略模式
2、 在工作目錄增加.ignore文件,內(nèi)容同上
4.4 查看更新狀態(tài)
Git status
4.5 比較
比較不在暫存區(qū)的文件與上個(gè)版本的區(qū)別
Git diff
比較在暫存區(qū)的文件與上個(gè)版本的區(qū)別
Git diff –cached
比較不在和在暫存區(qū)的文件與上個(gè)版本的區(qū)別
Git diff head
4.6 移除文件
Rm file
處理過程與修改一個(gè)文件相同
Git rm file
相當(dāng)于:rm file
Git add file
以上兩個(gè)命令都會(huì)把文件從庫和本地同時(shí)刪除。
Git rm –cached file
次命令只會(huì)從庫刪除,不會(huì)刪除本地文件。
4.7 移動(dòng)文件
Git mv file_from file_to
命令:git mv README.txt README
相當(dāng)于
$ mv README.txt README
$ git rm README.txt
$ git add README
這其實(shí)是個(gè)重命名操作
4.8 查看提交歷史
Git log——命令查看方式;
Gitk——調(diào)用可視化界面查看。
默認(rèn)不用任何參數(shù)的話,git log 會(huì)按提交時(shí)間列出所有的更新,最近的更新排在最上
面。
Git log
我們常用-p 選項(xiàng)展開顯示每次提交的內(nèi)容差異,用-2 則僅顯示最近的兩次更新:
Git log –p -2
--stat,僅顯示簡要的增改行數(shù)統(tǒng)計(jì),每個(gè)提交都列出了修改過的文件,以及其中添加和移除的行數(shù),并在最后列出所有增減行數(shù)小計(jì):
Git log –stat
一下是git log的常用選項(xiàng):
選項(xiàng)說明
-p 按補(bǔ)丁格式顯示每個(gè)更新之間的差異。
--stat 顯示每次更新的文件修改統(tǒng)計(jì)信息。
--shortstat 只顯示--stat 中最后的行數(shù)修改添加移除統(tǒng)計(jì)。
--name-only 僅在提交信息后顯示已修改的文件清單。
--name-status 顯示新增、修改、刪除的文件清單。
--abbrev-commit 僅顯示SHA-1 的前幾個(gè)字符,而非所有的40 個(gè)字符。
--relative-date 使用較短的相對時(shí)間顯示(比如,“2 weeks ago”)。
--graph 顯示ASCII 圖形表示的分支合并歷史。
--pretty 使用其他格式顯示歷史提交信息??捎玫倪x項(xiàng)包括oneline,short,full,fuller
和format(后跟指
定格式)。
git log 還有許多非常實(shí)用的限制輸出長度的選項(xiàng),也就是只輸出部分提交信息。
選項(xiàng)說明
-(n) 僅顯示最近的n 條提交
--since, --after 僅顯示指定時(shí)間之后的提交。
--until, --before 僅顯示指定時(shí)間之前的提交。
--author 僅顯示指定作者相關(guān)的提交。
--committer 僅顯示指定提交者相關(guān)的提交。
來看一個(gè)實(shí)際的例子,如果要查看Git 倉庫中,2008 年10 月期間,Junio Hamano 提
交的但未合并的測試腳本(位于項(xiàng)目的t/ 目錄下的文件),可以用下面的查詢命令:
$ git log --pretty="%h:%s" --author=gitster --since="2008-10-01"
--before="2008-11-01" --no-merges -- t/
4.9 修改歷史
4.9.1 修改最后一次提交
參見3.10.1
4.9.2 修改多次提交
git rebase -i HEAD~3修改最近三次提交
把對應(yīng)的pick改為edit,關(guān)閉后,執(zhí)行:
git commit --amend
可以修改歷史記錄。
如果還要增加文件可以在git commit –amend之前執(zhí)行:
Git add file
一切修改完成后,執(zhí)行:
Git rebase –continue回到分支。
4.9.3 重排提交
你也可以使用交互式的衍合來徹底重排或刪除提交。如果你想刪除“added cat-file”這
個(gè)提交并且修改其他兩次提交引入的順序,你將rebase腳本從這個(gè)
pick f7f3f6d changed my name a bit
pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file
改為這個(gè):
pick 310154e updated README formatting and added blame
pick f7f3f6d changed my name a bit
當(dāng)你保存并退出編輯器,Git 將分支倒回至這些提交的父提交,應(yīng)用310154e,然后f7f3f6d,
接著停止。你有效地修改了這些提交的順序并且徹底刪除了“added cat-file”這次提交。
4.9.4 合并多次提交為一次提交
交互式的衍合工具還可以將一系列提交壓制為單一提交。腳本在rebase 的信息里放了一
些有用的指示:
#
# Commands:
# p, pick = use commit
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be
aborted.
#
如果不用“pick”或者“edit”,而是指定“squash”,Git 會(huì)同時(shí)應(yīng)用那個(gè)變更和它之
前的變更并將提交說明歸并。因此,如果你想將這三個(gè)提交合并為單一提交,你可以將腳本
修改成這樣:
pick f7f3f6d changed my name a bit
squash 310154e updated README formatting and added blame
squash a5f4a0d added cat-file
當(dāng)你保存并退出編輯器,Git 會(huì)應(yīng)用全部三次變更然后將你送回編輯器來歸并三次提交說明。
# This is a combination of 3 commits.
# The first commit's message is:
changed my name a bit
# This is the 2nd commit message:
updated README formatting and added blame
# This is the 3rd commit message:
added cat-file
當(dāng)你保存之后,你就擁有了一個(gè)包含前三次提交的全部變更的單一提交。
4.9.5 拆分提交
拆分提交就是撤銷一次提交,然后多次部分地暫存或提交直到結(jié)束。例如,假設(shè)你想將
三次提交中的中間一次拆分。將“updated README formatting and added blame”拆分成
兩次提交:第一次為“updated README formatting”,第二次為“added blame”。你可以
在rebase -i腳本中修改你想拆分的提交前的指令為“edit”:
pick f7f3f6d changed my name a bit
edit 310154e updated README formatting and added blame
pick a5f4a0d added cat-file
然后,這個(gè)腳本就將你帶入命令行,你重置那次提交,提取被重置的變更,從中創(chuàng)建多
次提交。當(dāng)你保存并退出編輯器,Git 倒回到列表中第一次提交的父提交,應(yīng)用第一次
提交(f7f3f6d),應(yīng)用第二次提交(310154e),然后將你帶到控制臺(tái)。那里你可以用git
reset HEAD?對那次提交進(jìn)行一次混合的重置,這將撤銷那次提交并且將修改的文件撤回。
此時(shí)你可以暫存并提交文件,直到你擁有多次提交,結(jié)束后,運(yùn)行g(shù)it rebase --continue。
$ git reset HEAD^
$ git add README
$ git commit -m 'updated README formatting'
$ git add lib/simplegit.rb
$ git commit -m 'added blame'
$ git rebase --continue
這會(huì)修改你列表中的提交的SHA 值,所以請確保這個(gè)列表里不包含你已經(jīng)推送到共享倉庫的提交。
4.10 撤銷操作
4.10.1修改最后一次提交
有時(shí)候我們提交完了才發(fā)現(xiàn)漏掉了幾個(gè)文件沒有加,或者提交信息寫錯(cuò)了。想要撤消剛才的提交操作,可以使用--amend
選項(xiàng)重新提交:
Git commit --amend
如果剛才提交完沒有作任何改動(dòng),直接運(yùn)行此命令的話,相當(dāng)于有機(jī)會(huì)重新編輯提交說明,而所提交的文件快照和之前的一樣。
啟動(dòng)文本編輯器后,會(huì)看到上次提交時(shí)的說明,編輯它確認(rèn)沒問題后保存退出,就會(huì)使用新的提交說明覆蓋剛才失誤的提交。
如果剛才提交時(shí)忘了暫存某些修改,可以先補(bǔ)上暫存操作,然后再運(yùn)行--amend 提交:
$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend
4.10.2取消已經(jīng)暫存的文件
git reset HEAD file
4.10.3取消對文件的修改
Git checkout -- file
4.11 使用遠(yuǎn)程倉庫
4.11.1 查看遠(yuǎn)程倉庫
Git remote -v
4.11.2 添加遠(yuǎn)程倉庫
git remote add [shortname] [url]
git remote add pb git://github.com/paulboone/ticgit.git
現(xiàn)在可以用字串pb 指代對應(yīng)的倉庫地址了。比如說,要抓取所有Paul 有的,但本地倉庫沒有的信息,可以運(yùn)行g(shù)it fetch
pb。
4.11.3 從遠(yuǎn)程倉庫抓取數(shù)據(jù)
git fetch [remote-name]
此命令會(huì)到遠(yuǎn)程倉庫中拉取所有你本地倉庫中還沒有的數(shù)據(jù)。運(yùn)行完成后,你就可以在本地訪問該遠(yuǎn)程倉庫中的所有分支,將其中某個(gè)分支合并到本地,或者只是取出某個(gè)分支,一探究竟。如果是克隆了一個(gè)倉庫,此命令會(huì)自動(dòng)將遠(yuǎn)程倉庫歸于origin
名下。所以,git fetch
origin 會(huì)抓取從你上次克隆以來別人上傳到此遠(yuǎn)程倉庫中的所有更新(或是上次fetch
以來別人提交的更新)。有一點(diǎn)很重要,需要記住,fetch
命令只是將遠(yuǎn)端的數(shù)據(jù)拉到本地倉庫,并不自動(dòng)合并到當(dāng)前工作分支,只有當(dāng)你確實(shí)準(zhǔn)備好了,才能手工合并。如果設(shè)置了某個(gè)分支用于跟蹤某個(gè)遠(yuǎn)端倉庫的分支,可以使用git
pull 命令自動(dòng)抓取數(shù)據(jù)下來,然后將遠(yuǎn)端分支自動(dòng)合并到本地倉庫中當(dāng)前分支。在日常工作中我們經(jīng)常這么用,既快且好。實(shí)際上,默認(rèn)情況下git clone
命令本質(zhì)上就是自動(dòng)創(chuàng)建了本地的master 分支用于跟蹤遠(yuǎn)程倉庫中的master 分支(假設(shè)遠(yuǎn)程倉庫確實(shí)有master 分支)。所以一般我們運(yùn)行g(shù)it
pull,目的都是要從原始克隆的遠(yuǎn)端倉庫中抓取數(shù)
據(jù)后,合并到工作目錄中當(dāng)前分支。
4.11.4 推送數(shù)據(jù)到遠(yuǎn)程倉庫
git push [remote-name] [branch-name]
只有在所克隆的服務(wù)器上有寫權(quán)限,或者同一時(shí)刻沒有其他人在推數(shù)據(jù),這條命令才會(huì)如期完成任務(wù)。如果在你推數(shù)據(jù)前,已經(jīng)有其他人推送了若干更新,那你的推送操作就會(huì)被駁回。你必須先把他們的更新抓取到本地,并到自己的項(xiàng)目中,然后才可以再次推送。
4.11.5 查看遠(yuǎn)程倉庫的信息
git remote show [remote-name]
4.11.6 遠(yuǎn)程倉庫的刪除和重命名
重命名:
git remote rename origin_name new_name
刪除:
git remote rm origin_name
4.12 標(biāo)簽
4.12.1 新建標(biāo)簽
Git tag –a tagName –m “comment”
4.12.2 查看標(biāo)簽
Git show tagName
4.12.3 分享標(biāo)簽
git push origin [tagname]
默認(rèn)情況下,git push 并不會(huì)把標(biāo)簽傳送到遠(yuǎn)端服務(wù)器上,只有通過顯式命令才能分享
標(biāo)簽到遠(yuǎn)端倉庫。
如果要一次推送所有(本地新增的)標(biāo)簽上去,可以使用--tags 選項(xiàng):
git push origin --tags
4.13 分支
4.13.1 創(chuàng)建分支
Git branch branch_name
4.13.2 切換到新分支
Git checkout branch_name
4.13.3 創(chuàng)建并切換到新分支
Git checkout –b branch_name
4.13.4 合并分支
Git merge
切換到master分支,把hotfix分支合并到master分支:
Git checkout master
Git merge hotfix
4.13.5 衍合分支
如果把衍合當(dāng)成一種在推送之前清理提交歷史的手段,而且僅僅衍合那些永遠(yuǎn)不會(huì)公開的commit,那就不會(huì)有任何問題。如果衍合那些已經(jīng)公開的commit,而與此同時(shí)其他人已經(jīng)用這些commit
進(jìn)行了后續(xù)的開發(fā)工作,那你有得麻煩了。
永遠(yuǎn)不要衍合那些已經(jīng)推送到公共倉庫的更新。
Git rebase
4.13.6 刪除分支
Git branch –d branch_name
4.13.7 沖突合并
如果兩個(gè)分支git merge出險(xiǎn)了沖突,可以手工打開沖突文件解決后,運(yùn)行g(shù)it
add,之后git就會(huì)認(rèn)為已經(jīng)解決了沖突。
4.13.8 查看分支
Git branch
前邊帶*的是當(dāng)前分支。
4.13.9 查看各個(gè)分支最后一次commit信息
Git branch -v
4.13.10 查看哪些分支已經(jīng)并入當(dāng)前分支
Git branch --merge
4.13.11 查看哪些分支未并入當(dāng)前分支
Git branch –no-merge
4.13.12 推送本地分支到遠(yuǎn)程服務(wù)器
git push [遠(yuǎn)程名] [本地分支]:[遠(yuǎn)程分支]
Git push origin local_branch:remote_branch
Origin:遠(yuǎn)程分支在本地的名稱
local_branch:本地分支名稱
remote_branch:遠(yuǎn)程分支名稱
如果遠(yuǎn)程分支命名為和本地名稱相同,也可以:
Git push origin local_branch
此時(shí),如果協(xié)作開發(fā)者執(zhí)行:
Git fetch origin
將得到新分支local_branch或remote_branch(根據(jù)你推送的名稱)。
值得注意的是,在fetch
操作抓來新的遠(yuǎn)程分支之后,你仍然無法在本地編輯該遠(yuǎn)程倉庫。換句話說,在本例中,你不會(huì)有一個(gè)新的serverfix
分支,有的只是一個(gè)你無法移動(dòng)的origin/serverfix 指針。
如果要把該內(nèi)容合并到當(dāng)前分支,可以運(yùn)行g(shù)it merge origin/serverfix。如果想要一份自己的serverfix
來開發(fā),可以在遠(yuǎn)程分支的基礎(chǔ)上分化出一個(gè)新的分支來:
git checkout -b local_branch origin/remote_branch
4.13.13 跟蹤分支
git checkout --track origin/remote_branch
此命令執(zhí)行后,創(chuàng)建本地分支remote_branch,同時(shí)跟蹤遠(yuǎn)程分支。
此命令,相當(dāng)于:
Git checkout –b brancheName origin/remote_branch
4.13.14 刪除遠(yuǎn)程分支
git push [遠(yuǎn)程名] :[分支名]
git push [遠(yuǎn)程名] [本地分支]:[遠(yuǎn)程分支]
語法,如果省略[本地分支],那就等于是在說“在這里提取空白然后把它變成[遠(yuǎn)程分支]”。
4.13.15 查看分支差異
比如有分支master、experiment
你想要查看你的試驗(yàn)分支上哪些沒有被提交到主分支,那么你就可以使用master..experiment來讓Git
顯示這些提交的日志——這句話的意思是“所有可從experiment分支中獲得而不能從master分支中獲得的提交”。為了使例子簡單明了,我使用了圖標(biāo)中提交對象的字母來代替真實(shí)日志的輸出,所以會(huì)顯示:
$ git log master..experiemnt
4.13.16 查看當(dāng)前分支和遠(yuǎn)程分支的差異
git log origin/master..HEAD
這條命令顯示任何在你當(dāng)前分支上而不在遠(yuǎn)程origin 上的提交。如果你運(yùn)行g(shù)it
push并且的你的當(dāng)前分支正在跟蹤origin/master,被git log origin/master..HEAD
列出的提交就是將被傳輸?shù)椒?wù)器上的提交。你也可以留空語法中的一邊來讓Git 來假定它是HEAD。例如,輸入git log origin/master..
將得到和上面的例子一樣的結(jié)果—— Git 使用HEAD 來代替不存在的一邊。
4.13.17 多點(diǎn)查詢
你也許會(huì)想針對兩個(gè)以上的分支來指明修訂版本,比如查看哪些提交被包含在某些分支中的一個(gè),但是不在你當(dāng)前的分支上。Git允許你在引用前使用?字符或者--not指明你不希望提交被包含其中的分支。因此下面三個(gè)命令是等同的:
$ git log refA..refB
$ git log ^refA refB
$ git log refB --not refA
這樣很好,因?yàn)樗试S你在查詢中指定多于兩個(gè)的引用,而這是雙點(diǎn)語法所做不到的。例如,如果你想查找所有從refA或refB包含的但是不被refC包含的提交,你可以輸入下面中的一個(gè)
$ git log refA refB ^refC
$ git log refA refB --not refC
這建立了一個(gè)非常強(qiáng)大的修訂版本查詢系統(tǒng),應(yīng)該可以幫助你解決分支里包含了什么這個(gè)問題。
4.13.18 三點(diǎn)查詢
你可以指定被兩個(gè)引用中的一個(gè)包含但又不被兩者同時(shí)包含的分支。如果你想查看master或者experiment中包含的但不是兩者共有的引用,你可以運(yùn)行
$ git log master...experiment
這種情形下,log命令的一個(gè)常用參數(shù)是--left-right,它會(huì)顯示每個(gè)提交到底處于哪一側(cè)的分支。這使得數(shù)據(jù)更加有用。
4.14 儲(chǔ)藏(Stashing)
經(jīng)常有這樣的事情發(fā)生,當(dāng)你正在進(jìn)行項(xiàng)目中某一部分的工作,里面的東西處于一個(gè)比較雜亂的狀態(tài),而你想轉(zhuǎn)到其他分支上進(jìn)行一些工作。問題是,你不想提交進(jìn)行了一半的工作,否則以后你無法回到這個(gè)工作點(diǎn)。解決這個(gè)問題的辦法就是git
stash命令。
4.14.1 儲(chǔ)藏當(dāng)前工作
Git stash
4.14.2 查看現(xiàn)有儲(chǔ)藏
Git stash list
4.14.3 應(yīng)用儲(chǔ)藏
Git stash apply
Git stash可以多次儲(chǔ)藏,如果沒有參數(shù),默認(rèn)使用最近的儲(chǔ)藏,并應(yīng)用之。
如果要應(yīng)用某個(gè)儲(chǔ)藏,可以加上儲(chǔ)藏的名字:
Git stash apply stash@{2}
4.14.4 重新應(yīng)用儲(chǔ)藏
重新應(yīng)用儲(chǔ)藏,同時(shí)立刻將其從堆棧中移走,此命令不同于git stash apply
Git stash pop
Git stash pop stash@{2}
4.14.5 刪除儲(chǔ)藏
Git stash drop
Git stash drop stash@{2}
此命令會(huì)刪除儲(chǔ)藏內(nèi)的所有變更,慎用!
4.14.6 在儲(chǔ)藏上創(chuàng)建分支
如果你儲(chǔ)藏了一些工作,暫時(shí)不去理會(huì),然后繼續(xù)在你儲(chǔ)藏工作的分支上工作,你在重新應(yīng)用工作時(shí)可能會(huì)碰到一些問題。如果嘗試應(yīng)用的變更是針對一個(gè)你那之后修改過的文件,你會(huì)碰到一個(gè)歸并沖突并且必須去化解它。如果你想用更方便的方法來重新檢驗(yàn)?zāi)銉?chǔ)藏的變更,你可以運(yùn)行g(shù)it
stash branch,這會(huì)創(chuàng)建一個(gè)新的分支,檢出你儲(chǔ)藏工作時(shí)的所處的提交,重新應(yīng)用你的工作,如果成功,將會(huì)丟棄儲(chǔ)藏。
git stash branch branch_name
4.15 全局修改的核武器
filter-branch
如果你想用腳本的方式修改大量的提交,還有一個(gè)重寫歷史的選項(xiàng)可以用——例如,全局性地修改電子郵件地址或者將一個(gè)文件從所有提交中刪除。這個(gè)命令是filter-branch,這個(gè)會(huì)大面積地修改你的歷史,所以你很有可能不該去用它,除非你的項(xiàng)目尚未公開,沒有其他人在你準(zhǔn)備修改的提交的基礎(chǔ)上工作。盡管如此,這個(gè)可以非常有用。
4.15.1 從所有提交中刪除一個(gè)文件
要從整個(gè)歷史中刪除一個(gè)名叫password.txt的文件,你可以在filter-branch上使用--tree-filter選項(xiàng):
$ git filter-branch --tree-filter 'rm -f passwords.txt' HEAD
--tree-filter選項(xiàng)會(huì)在每次檢出項(xiàng)目時(shí)先執(zhí)行指定的命令然后重新提交結(jié)果。在這個(gè)例子中,你會(huì)在所有快照中刪除一個(gè)名叫password.txt
的文件,無論它是否存在。如果你想刪除所有不小心提交上去的編輯器備份文件,你可以運(yùn)行類似git filter-branch --tree-filter 'rm
-f *~' HEAD的命令。
你可以觀察到Git
重寫目錄樹并且提交,然后將分支指針移到末尾。一個(gè)比較好的辦法是在一個(gè)測試分支上做這些然后在你確定產(chǎn)物真的是你所要的之后,再hard-reset
你的主分支。
要在你所有的分支上運(yùn)行filter-branch的話,你可以傳遞一個(gè)--all給命令。
4.15.2 將一個(gè)子目錄設(shè)置為新的根目錄
假設(shè)你完成了從另外一個(gè)代碼控制系統(tǒng)的導(dǎo)入工作,得到了一些沒有意義的子目錄(trunk,
tags等等)。如果你想讓trunk子目錄成為每一次提交的新的項(xiàng)目根目錄,filterbranch也可以幫你做到:
$ git filter-branch --subdirectory-filter trunk HEAD
Rewrite 856f0bf61e41a27326cdae8f09fe708d679f596f (12/12)
Ref 'refs/heads/master' was rewritten
現(xiàn)在你的項(xiàng)目根目錄就是trunk子目錄了。Git 會(huì)自動(dòng)地刪除不對這個(gè)子目錄產(chǎn)生影響的
提交。
4.15.3 全局性的更換電子郵件地址
另一個(gè)常見的案例是你在開始時(shí)忘了運(yùn)行g(shù)it config來設(shè)置你的姓名和電子郵件地址,也
許你想開源一個(gè)項(xiàng)目,把你所有的工作電子郵件地址修改為個(gè)人地址。無論哪種情況你都可
以用filter-branch來更換多次提交里的電子郵件地址。你必須小心一些,只改變屬于你的
電子郵件地址,所以你使用--commit-filter:
$ git filter-branch --commit-filter '
if [ "$GIT_AUTHOR_EMAIL" = "schacon@localhost" ];
then
GIT_AUTHOR_NAME="Scott Chacon";
GIT_AUTHOR_EMAIL="schacon@example.com";
git commit-tree "$@";
else
git commit-tree "$@";
fi' HEAD
這個(gè)會(huì)遍歷并重寫所有提交使之擁有你的新地址。因?yàn)樘峤焕锇怂鼈兊母柑峤坏腟HA-1值,這個(gè)命令會(huì)修改你的歷史中的所有提交,而不僅僅是包含了匹配的電子郵件地址的那些。
4.16 Git調(diào)試
4.16.1 文件標(biāo)注
Git blame
如果你在追蹤代碼中的缺陷想知道這是什么時(shí)候?yàn)槭裁幢灰M(jìn)來的,文件標(biāo)注會(huì)是你的最佳工具。它會(huì)顯示文件中對每一行進(jìn)行修改的最近一次提交。
$ git blame -L 12,22 simplegit.rb
此命令查看12至22行的修改情況。
4.16.2 二分查找
Git bitsect
標(biāo)注文件在你知道問題是哪里引入的時(shí)候會(huì)有幫助。如果你不知道,并且自上次代碼可用的狀態(tài)已經(jīng)經(jīng)歷了上百次的提交,你可能就要求助于bisect命令了。bisect會(huì)在你的提交歷史中進(jìn)行二分查找來盡快地確定哪一次提交引入了錯(cuò)誤。
首先你運(yùn)行g(shù)it bisect start啟動(dòng),然后你用git bisect
bad來告訴系統(tǒng)當(dāng)前的提交已經(jīng)有問題了。然后你必須告訴bisect已知的最后一次正常狀態(tài)是哪次提交,使用git bisect good
[good_commit]:
$ git bisect start
$ git bisect bad
$ git bisect good v1.0
Bisecting: 6 revisions left to test after this
[ecb6e1bc347ccecc5f9350d878ce677feb13d3b2] error handling on
repo
Git
發(fā)現(xiàn)在你標(biāo)記為正常的提交(v1.0)和當(dāng)前的錯(cuò)誤版本之間有大約12次提交,于是它檢出中間的一個(gè)。在這里,你可以運(yùn)行測試來檢查問題是否存在于這次提交。如果是,那么它是在這個(gè)中間提交之前的某一次引入的;如果否,那么問題是在中間提交之后引入的。假設(shè)這里是沒有錯(cuò)誤的,那么你就通過git
bisect good來告訴Git 然后繼續(xù)你的旅程:
$ git bisect good
當(dāng)你完成之后,你應(yīng)該運(yùn)行g(shù)it bisect reset來重設(shè)你的HEAD到你開始前的地方,否則你會(huì)處于一個(gè)詭異的地方:
$ git bisect reset
5 從Subversion遷移到Git
Git svn clone svn_repo_url |