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