git使用總結
git目前是最流行的代碼管理軟件,包括Linux kernel源碼和android源碼都是由git來管理。git使用起來效率高,干淨,生成的中間文件不會影響到代碼,比起SVN有很大優勢。
目前在工作中也是用git來管理源碼,這裡簡單梳理一下使用細節和命令。
在ubuntu系統中安裝git
sudo apt-get install git git-core
建立統一的賬戶來管理git項目,這一點在實際中很需要,避免後期因為多用戶的修改提交而產生沖突
sudo adduser git
sudo passwd git
初始化倉庫
mkdir project
cd project
git init
此時在項目文件中多出.git文件夾,通過這個來管理
git add .(要求給當前項目制作一個snapshot)
git commit -m " xxxxxx"
此時遠程端git倉庫已經建立完畢
本地克隆遠程端庫
git clone git@ip:/source/dest
git config --global user.name "your name"
git config --global user.email "email@xxxx"
修改文件並提交
*將新增或者修改等變化的文件添加到git的索引(index)中:
git add file1 file2
將索引(index)的內容保存到git庫中
git commit
提交之前,查看修改狀態:
git diff --cached
或者
git status
分支管理:
git branch 查看分支
git branch branch1(建立分支)
git checkout branch1 切換到branch1分支
等效於git ckeckout -b branch1
git merge branch1 合並到branch1分支
git branch -d branch1 刪除分支branch1,根據提示修改錯誤
git branch -D branch1 強制刪除
提交本地分支branch1到遠程倉庫同樣作為branch1分支
git push origin branch1
刪除遠程倉庫中的branch1分支
git push origin :branch1
在使用git push代碼到倉庫時,遇到如下錯誤:
[remote rejected]master->master(branch is currently checked out)
remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsistent
這是由於git默認拒絕了push操作,需要進行設置,修改.git/config文件後面添加如下代碼:
[receive]
denyCurrentBranch = ignore
開發人員(以下稱為本地)和服務器(遠端)之間的交流;(以下都在本地進行操作)
git push 遠端項目路徑 本地分支名:遠端分支名
a. 當本地有修改文件時:
首先提交修改,輸入git commit –am “修改說明”
然後將修改的推到服務器相對應的分支,輸入:
git push origin test:master // 合並本地test分支到服務器端master分支
git push origin test:test //合並本地test分支到服務器端test分支, (origin就是克隆時在.git/config文件中自動定義的服務器項目路徑,請自行查看)
需要格外注意的是,git push好像不會自動合並文件。因此,如果git push時,發生了沖突,就會被後push的文件內容強行覆蓋,而且沒有什麼提示。
如果使用了git init初始化,則遠程倉庫的目錄下,也包含work tree,當本地倉庫向遠程倉庫push時, 如果遠程倉庫正在push的分支上(如果當時不在push的分支,就沒有問題), 那麼push後的結果不會反應在work tree上, 也即在遠程倉庫的目錄下對應的文件還是之前的內容,必須得使用git reset --hard才能看到push後的內容
b. 當本地有新建的分支時:
首先提交新分支的修改,然後將在本地新建的分支test1推到服務器, 輸入:
git push origin test1: 遠端分支名
// 將本地新test1分支推到服務器,查看服務器,此時服務器中多了一個新分支,如果沒有輸入遠端分支名,則服務器上的新分支名和本地分支名(test1)一樣;如果有輸入遠端分支名,則服務器上的新分支名為輸入的分支名;
c. 刪除遠程的分支:
如果:左邊的分支為空,那麼將刪除:右邊的遠程的分支,輸入:
git push origin :test //遠程的test將被刪除,但是本地還會保存的
需要格外注意的是,
git push好像不會自動合並文件。因此,如果git push時,發生了沖突,就會被後push的文件內容強行覆蓋,而且沒有什麼提示。
如果使用了git init初始化,則遠程倉庫的目錄下,也包含work tree,當本地倉庫向遠程倉庫push時, 如果遠程倉庫正在push的分支上(如果當時不push的分支,就沒有問題)
, 那麼push後的結果不會反應在work tree上, 也即在遠程倉庫的目錄下對應的文件還是之前的內容,必須得使用git reset --hard才能看到push後的內容
b. 當本地有新建的分支時:
首先提交新分支的修改,然後將在本地新建的分支test1推到服務器, 輸入: git push origin test1:遠端分支名
// 將本地新test1分支推到服務器,查看服務器,此時服務器中多了一個新分支,如果沒有輸入遠端分支名,
則服務器上的新分支名和本地分支名(test1)一樣;如果有輸入遠端分支名,則服務器上的新分支名為輸入的分支名;
c. 刪除遠程的分支:
如果:左邊的分支為空,那麼將刪除:右邊的遠程的分支,輸入:
git push origin :test
//遠程的test將被刪除,但是本地還會保存的
git pull 遠端項目路徑 遠端分支名:本地分支名
a. 當服務器端有修改文件或者補丁時,首先在服務器端必須是提交好的:
將修改的拉到本地相對應的分支,輸入:
git pull origin test:master // 合並服務器端test分支到本地master分支
git pull origin test:test //合並服務器端test分支到本地test分支
注意:如果在合並的時候有沖突,則手動修改沖突,提交直到沒有沖突,再進行合並;
b. 當服務器端有新建的分支時:
首先提交新分支的修改,然後將在服務器端新建的分支test1拉到本地來, 輸入:
git pull origin test1: 本地分支名 // 將服務器端新test1分支拉到本地,查看本地,此時本地中多了一個新分支,注意:必須輸入本地分支名,否則無法查看到(原因待查);
Log查看:
git log
git log -p 顯示patch
git log --stat 顯示改動的一個總結
git log --graph 只顯示當前branch的
git log --graph --all 顯示所有branch的
git log --graph --all --decorate 顯示branch的名字
git log --pretty=oneline, short, full, fuller 輸出的log 形式不同
git log --pretty=format:"%h - %an, %ar : %s" 按照指定的格式輸出。
關於--pretty的其他選項和具體的format格式,參考 git log --help中PRETTY FORMAT這部分。
git log --follow file.c 這個功能很有意思,尤其是當file.c被移動後。
通常我們會移動某個文件到某個目錄下。如果這麼做,git log是不能顯示目錄移動前的記錄的。
那就加上 --follow吧。
git log的篩選
git log -2 -p 顯示最近兩次commit的log 和 diff
git log --author="Author Name" 篩選特定作者的log
git log --since="2012-2-23" --before="2012-2-24" 篩選時間段
git log --grep="key word" 在commit 的message中查找關鍵字
git log branch --not master 查看在branch上的,但不在master上的記錄。
git撤銷:
git checkout -- filename 撤銷修改,恢復到修改前的版本
git reset HEAD filename 取消暫存 文件回到已修改未暫存的狀態
回退到指定版本,清除該版本之後所有的信息:
$ git reset --hard HEAD^(這裡可以指定commit,查詢得到)
這樣將會把當前工作分支的內容回退到"HEAD^"版本。注意,這個命令不僅會把當前的修改給移除,而且還會把自"HEAD^"以後的所有"commit"給刪除(HEAD^版本本身保留為當前的HEAD),如果當前的分支是唯一的分支的話,那麼運行這個命令之後,之前"HEAD^"以後的修改將會完全丟失(當然可以通過"pull"再將之前的HEAD拉取回來,但是自己沒有提交的本地修改是無法找回來的了);另外如果在一個公共的分支上面執行這個命令將會導致其他開發者pull的時候都進行一遍這個清除的工作,如果不加--hard選項,那麼可能當前HEAD基礎上有修改的情況導致這個命令不會成功。
回退到指定版本,並作為新版本提交上去(保留該版本之後所有的信息):
$ git revert HEAD^
這樣只會把內容回退為HEAD^之前的版本(即HEAD^^),再將這樣的內容做為新的HEAD提交上去,原來的HEAD變成HEAD^(即在庫中保留HEAD^之後的版本的提交,而不像"reset"那樣完全清除)。這裡,運行之後,會打開一個編輯窗口讓你編輯提交的log信息,退出就直接提交了,或者"revert"命令也有不編輯提交log信息的選項。
HEAD:表示最近一次的commit。(最新版本)
MERGE_HEAD:如果是merge產生的commit,那麼它表示除HEAD之外的另一個父母分支。
FETCH_HEAD:使用git-fetch獲得的object和ref的信息都存儲在這裡,這些信息是為日後git-merge准備的。
HEAD^:表示HEAD父母的信息
HEAD^^:表示HEAD父母的父母的信息
HEAD~4:表示HEAD上溯四代的信息
HEAD^1:表示HEAD的第一個父母的信息(和HEAD^相同)
HEAD^2:表示HEAD的第二個父母的信息
COMMIT_EDITMSG:最後一次commit時的提交信息。