git原理及相關指令介紹
一、git代碼狀态轉換圖
(本圖來源網上作者blog)
1>>如圖所示:未被git跟蹤的狀态為unstage狀态,已經被git跟蹤的狀态為stage狀态。【包括staging狀态和staged狀态】
2>>untrack files是指尚未被git所管理的檔案;changed but not updated是指檔案被git管理,并且發生了改變,但改動還沒被git管理;這兩種狀态,都可以看成是改動還沒被git管理的狀态,我們這裡稱非stage狀态。
3>>changes to be commited是指進入stage狀态的檔案,stage是commit和未管理之間的一個狀态,也有别名叫index狀态,也就是git已經管理了這些改動,但是還沒完成送出。【.gitignore中的檔案,不會出現在以上三個狀态中】
二,git的個人本地使用及操作
1, 建立Git庫
cd 源碼目錄
git init #初始化 在源碼目錄内生成一個.git的目錄
2, 注冊使用者資訊
git config --global user.name XXX 使用者名
git config --global user.email XXX 使用者郵箱
git config –list #檢視使用者資訊
3, 向git庫中添加或删除檔案
git add XX #加單個檔案
git add . #加所有
git add [path]會把對應目錄或檔案,添加到stage狀态
git add . 會把目前所有的untrack files和changed but not updated添加到stage狀态
4, 向版本庫送出變化
git commit –m “XXXX” #直接添加簡單送出資訊,添加注釋
git status #檢視目前代碼庫的狀态
git log #檢視版本資訊
git log –p #檢視版本資訊并顯示每次修改的diff
git show sdjf974654dd…. #檢視指定版本資訊
#(show後面為每次送出系統自動生成的一串哈希值)
git show sdji97 #一般隻使用版本号的前幾個字元即可
5, 撤銷與恢複
git reset
git reset --hard #回到原來編輯的地方,改動會丢失。
#(同樣适用于團隊對于其他人的修改恢複)
git reset --hard sdv143kvf…... #可回到指定的版本
#(hard後面為每次送出系統自動生成的一串哈希值)
git reset [path] 會改變path指定的檔案或目錄的stage狀态,到非stage狀
git reset 會将所有stage的檔案狀态,都改變成非stage狀
回退1個change的寫法就是git reset HEAD^,2個為HEAD^^,3個為HEAD~3,以此類推。
6, 向伺服器送出變化
git push #向伺服器送出
7, 暫存改動
git stash可以把目前的改動(stage和unstage,但不包括untrack的檔案)暫存。然後通過git stash list檢視。并通過git stash apply重新取出來。但apply之前要保證worktree是幹淨的。
三,git的團隊開發及操作
1, 擷取項目
cd 本地工作目錄(自定)
git clone 伺服器帳戶@IP:項目.根路經
這裡具體操作為:
git clone [email protected]:android2.2.git
說明:這裡假定伺服器的使用者名為git,伺服器IP為192.168.20.22,項目名為android2.2,根路經為git的home(即根路徑)
2, 團隊開發的基本流程
git add 改動的檔案
git commit #(送出至本地)
git pull #(将伺服器項目與本地項目合并)
git push #(将本地項目上傳至伺服器)(在送出前要git pull --rebase一下,確定目前的本地的代碼為最新。)
四,git的分支管理
git分支操作在本地建立分支,然後與本地主枝合并,最終送出到伺服器。有效的避免了因個人操作不當向伺服器送出過多髒資料,避免頻繁git clone伺服器來更新本地庫。
分支操作指令:
1, 建立分支
git branch AAA #建立分支AAA
2,分支切換
git checkout AAA #從目前分支切換到AAA分支
3, 将分支與主枝master合并
git checkout master #(首先切換回主枝)
git merge AAA #(将分支AAA與主枝合并)
4, 目前分支檢視
git branch #預設有master(也稱為主枝)
git branch –a 檢視目前所有分支
5, 删除分支
git branch –d AAA #删除分支AAA
備注:上面隻是一些基本的操作指令,更多的指令可通過幫助文檔查詢。
幫助文檔的使用:
man git-<需查詢的指令> #(git後面有“-”)
如commit的查詢為 man git-commit
删除分支 ; 如果你要删除的分支并沒有被merge到目前分支的話,将産生一個錯誤提示。
----------------------------------------------------------------------------------------------------------------------------------------
git bash和eclipse下git插件
gitbash
首先,下載下傳gitbash桌面版的用戶端:
http://code.google.com/p/msysgit/downloads/list
進入後尋找Git-1.8.1.2-preview20130201.exe,安裝上。
安裝的時候,一直預設下一步就ok了。
打開gitbash相當于打開一個指令行輸入模式
其次:可以用git clone 指令行下載下傳代碼倉庫的代碼
在使用git來進行版本控制時,為了得一個項目的拷貝(copy),我們需要知道這個項目倉庫的位址(Git URL). Git能在許多協定下使用,是以Git URL可能以ssh://, http(s)://, git://,或是隻是以一個使用者名(git 會認為這是一個ssh 位址)為前辍。
如上圖所示,輸入git clone指令後,輸入使用者名和密碼驗證成功後就會把代碼check out到本地,一般都在C:\Documents and Settings\Administrator目錄下
常用指令:
git log 看記錄
git diff 看與上一次的改變
建分支用git branch [分支名]
切換分支用 get checkout [分支名]
檢視分支就用 git branch
想回到上一個不版本,不要這一次修改 get reset --hard HARD
具體一下檔案 get checkout xxxxxx.xx檔案
生成DIFF(patch)檔案
HEAD是目前最新的版本,HEAD~是上一個版本,HEAD~~是上上一個版本,也可以 git diff HEAD HEAD~
update,更新版本
git pull 拉伺服器的版本
commit ,送出代碼
git commit 注意,這個送出隻是在本地送出,真正想到伺服器,commit後還需要使用git push,推送到伺服器
推送到伺服器
git push把剛才送出的推送到伺服器去
20120822更新---------------------------------------------------
檢視目前git位址下的所有分支:
我們想切換到第三個分支:
如上圖所示,我們已經成功從master切換到了pinganbb_en的分支,使用ls 指令可以檢視目前分支下的内容
那麼,我們如何checkout 目前分支下的代碼呢?(使用我們的git位址,預設會checkout master主分支下的内容,而我們想checkout 分支下的内容)
在windows環境下,新建立一個檔案夾:test
進入檔案夾内,滑鼠右鍵 --- Git Bash
如上圖所示,直接git clone 分支名稱 是無效的,提示沒有找到,是以我們要加上 -b,也就是:
git clone -b 分支名 http://code.google.wdadwa/en.git 輸入使用者名和密碼,成功後就可以checkout 到目前建立的test檔案夾下了。
上傳項目到代碼倉庫(伺服器),(第一次上傳,并非update)
找到要上傳的項目的檔案夾,右鍵- Git Bash 這個時候如果直接輸入:
$ git remote add origin [email protected]:yourName/yourRepo.git 會發現目前git 不存在,因為我們還沒有add 和commit(小白)
error: src refspec master does not match any.引起該錯誤的原因是,目錄中沒有檔案,空目錄是不能送出上去的
現在最簡單的辦法,在一個新的空白檔案夾下,右鍵 Git Bash,輸入下面的指令:
$ git clone http://dev.dbjtech.com/kaka/test.git
輸入使用者名和密碼後,成功checkout後,會發現有一個空的.git檔案夾(隐藏),把這個檔案夾拷貝到我們要上傳的項目裡,這樣項目中就有了.git了
在.git中的config檔案,可以看到目前項目下的git origin位址
【注意,如果有不需要上傳的檔案,可以通過.gitignore檔案屏蔽,也可以在add 的時候選擇性的上傳】
這個時候檢視status,會發現沒有任何的commit,是以我們需要先add 所要上傳的檔案到本地倉庫,然後送出,最後才是push
$ git add .
如上圖所示,現在我們需要commit到本地倉庫了
$ git commit -m "this is first push "
成功送出本地後,就可以上傳到伺服器啦
$ git push 【預設回事master主分支】
等待上傳,成功後我們再看一下log日志
$ git log
大功告成,項目已經成功送出到了伺服器的代碼倉庫,我們在一個建立的檔案夾下驗證一下吧
$ git clone http://test.test.com/test.git
通過ls可以看到,checkout下來的就是我們之前上傳的那些檔案/檔案夾
http://blog.csdn.net/code52/article/details/8807785
回退版本
首先輸入指令:
git log
會看到目前所有的送出版本記錄
2,git reset
git reset 5f0deba043dbfa96e5d27f8e43c1e13f9fd312e4
可能出現的error
error: RPC failed; result=22, HTTP code = 411
fatal: The remote end hung up unexpectedly
fatal: The remote end hung up unexpectedly
Everything up-to-date
當使用git送出(push)比較大的檔案的時候可能會出現411這個錯誤
解決辦法:改一下git的傳輸位元組限制(500M)
git config --global http.postBuffer 524288000
error: RPC failed; result=22, HTTP code = 413
fatal: The remote end hung up unexpectedly
fatal: The remote end hung up unexpectedly
Everything up-to-date
這個錯誤是因為目前的account沒有一個有效的SSH Key,這個時候需要你登入github去SSH配置一個私鑰。
http://zhidao.baidu.com/link?url=a3Ngecc9jBgpgYET95aJ7nqLrg1mAeIfA9P1q2QA2gX0dFQq90EltDIkC8CVZu_C6oFx8DWHg0cgAh_chZpnWoNkQvjhzPpB7eV-r9hrMYm
實際操作
現在隻要cat ~/.ssh/id_rsa.pub 就可以看到以ssh-rsa開頭和以account結尾的的長串私鑰,複制這個到gitLab個人賬戶SSH配置項,添加到key中即可。
然後 git push origin master就可以了。
git pull時,commit your changes or stash them before you can merge.
error: Your local changes to 'c/environ.c' would be overwritten by merge. Aborting.
Please, commit your changes or stash them before you can merge.
這個意思是說更新下來的内容和本地修改的内容有沖突(修改到同一檔案同一位置),先送出你的改變或者先将本地修改暫時存儲起來,前者是解決這種沖突,後者是先隐藏
處理的方式非常簡單,主要是使用git stash指令進行處理,分成以下幾個步驟進行處理。
1,先将本地修改存儲起來
$ git stash
這樣本地的所有修改就都被暫時存儲起來 。是用git stash list可以看到儲存的資訊:
其中stash@{0}就是剛才儲存的标記。
2,暫存了本地修改之後,就可以重新pull了。
3,還原暫存的内容
$ git stash pop stash@{0}
系統提示如下類似的資訊:
Auto-merging c/environ.c
CONFLICT (content): Merge conflict in c/environ.c
意思就是系統自動合并修改的内容,但是其中有沖突,需要解決其中的沖突。
4,解決檔案中沖突的的部分
打開沖突的檔案,會看到類似如下的内容:
其中Updated upstream 和=====之間的内容就是pull下來的内容,====和stashed changes之間的内容就是本地修改的内容。git不知道哪行内容是需要的,是以要自行确定需要的内容,二者取其一。
解決完成之後,就可以正常的送出了。
eclipse下 egit插件
打開eclipse-help-install new software
location輸入如上位址,下載下傳好egit插件後,選中項目(項目是從代碼倉庫checkout下來的,也就是說項目有.git檔案),右鍵Team,就會顯示egit菜單,和svn插件類似。
需要注意的是:需要檢視diff檔案,就Create Path,儲存到指定位置;當需要送出代碼時,需要先commit一下,然後pull,兩個缺一不可,不pull,代碼無法同步到倉庫(當我們使用svn時,隻需要commit,直接會送出到代碼倉庫)。
git和svn使用
svn
需要搭建一個svn伺服器(HTTP/SVN),搭建svn伺服器需要看一些手冊
git
不需要git伺服器,任何一台安裝git的PC都可以是git伺服器,其他人可以用任何現有的方式(SSH/HTTP/本地檔案系統)更新上傳代碼
我有兩台PC:A和B,他們在一個網段(192.168.6.0/24),為了使得這個git使用記錄更加嚴謹,以下的每一個指令都在這兩台PC上進行測試。其中A位址為192.168.6.1, B位址為192.168.6.15, B可以通過ssh登入到A
1.初始化一個A機器上的git目錄
最近在開始學習scala,在A機器上有一個目錄是/home/le/workspace/scala_test,在這個目錄下初始話一個git目錄
$ git init
此時你在目前目錄下會發現一個.git的目錄
$ ls -la
2.向git庫中送出檔案
$ touch Test1.scala
$ vim Test1.scala
$ git status . #git會告訴你新的改動,接下來選擇需要送出的檔案
$ git add Test1.scala
$ git status . #再來看看,git會告訴你将要commit什麼
$ git commit -m 'initial git repo' #送出到本地branch
A可以作為git server了,接下來到B上操作。
2. 從A上克隆代碼到B上,位于/home/le/workspace/git/repo1/
$ git clone [email protected]:/home/le/workspace/scala_test
3. 建立分支,切換分支,送出分支到遠端git庫
$ git branch scala_dev #建立分支
$ git checkout scala_dev #切換到該分支
$ git branch #檢視本地目前的分支
$ git push origin scala_dev #送出scala_dev分支到遠端git庫
$ git branch -r #檢視遠端所有的分支
$ git branch -a #檢視本地和遠端所有的分支
4.修改檔案,并且送出到遠端庫
$ touch Test2.scala
$ git add Test2.scala
$ git commit
$ git log #在push之前确認commit是否正确
$ git push
5.從遠端git庫克隆指定的分支,這次在B機器的/home/le/workspace/git/repo2/目錄重新克隆一份代碼
$ git clone -b scala_dev [email protected]:/home/le/workspace/scala_test
$ git branch #檢視目前分支
#送出新的代碼
$ touch Test3.scala
$ git add Test3.scala
$ git commit
$ git log #在push之前确認commit是否正确
$ git push
6.回到/home/le/workspace/git/repo2/更新代碼
$ git pull #如果有錯誤,請按照錯誤提示修改.git/config檔案
一些可能會遇到的問題
1.合并多個commit多一個commit
在本地的git庫commit了多次,在push到遠端的git庫時,可以在本地合并這些commit。
每次合并兩個commit
$ git reset --soft HEAD^1
$ git commit --amend
合并最後n個commit
$ git rebase -i HEAD~n
#替換第n個pick為s儲存
2.取消本地的commit
有時候commit了代碼到了本地git庫中,之後某種原因想删掉最後1條commit,可以直接恢複到之前的commit
$git reset --hard HEAD~1
3.使用git stash
如果你跟我一樣也使用gerrit做code review,那麼有可能遇到這樣問題:
在同一個分支上有多個bug需要fix,fix完一個bug然後就commit代碼到gerrit server上等待code review,在等待的過程中又開始fix另外一個bug,就在這個時候之前送出的代碼被reviewer提示出錯誤,需要更新之前的代碼,這個時候可以 使用git stash來儲存目前本地的修改。
在一個分支上修改了代碼但是不想commit到本地git庫,需要切換一個分支去修改代碼,這個時候也可以使用git stash
$ git stash
# modify your code or checkout to another branch
# git commit --amend
$ git stash pop
4.從另外一個分支裡面挑選一些commit到目前分支
假如你有兩個分支,一個是dev分支,一個是release分支,在dev分支上已經有很了很多的commit,有時需要從dev分支上挑選一些commit到release分支上。
$ git log #查找到需要的commit id, 假設為5b531cb8c62cdb8b5f10c406e41824a6388e3a82
$ git checkout release
$ git log #看一下目前的commit log
$ git cherry-pick 5b531cb8c62cdb8b5f10c406e41824a6388e3a82
$ git log #此時可以看到commit log增加了
5. 出現error: The following untracked working tree files would be overwritten by checkout
$ git clean -d -fx ""
6.我一次commit 5個檔案到gerrit上面,然後發現有一個不需要送出,隻要送出4個就好,我想重新送出一次在同一個commit ID下面,我該怎麼做?
前提代碼還沒有被merge進庫
例如要取消檔案2.txt, 那麼先恢複2.txt到commit id 9a42e8e3f41dcf5029a11ce651f36cbdf37fc84d,你送出之前的那一個commit id
git reset 9a42e8e3f41dcf5029a11ce651f36cbdf37fc84d -- 2.txt
git checkout -- 2.txt
git add .
git commit --amend
轉自:http://blog.chinaunix.net/uid-23366077-id-3581375.html
GIT和SVN之間的五個基本差別
GIT不僅僅是個版本控制系統,它也是個内容管理系統(CMS),工作管理系統等。如果你是一個具有使用SVN背景的人,你需要做一定的思想轉換,來适應GIT提供的一些概念和特征。是以,這篇文章的主要目的就是通過介紹GIT能做什麼、它和SVN在深層次上究竟有什麼不同來幫助你認識它。
那好,這就開始吧…
1.GIT是分布式的,SVN不是:
這是GIT和其它非分布式的版本控制系統,例如SVN,CVS等,最核心的差別。如果你能了解這個概念,那麼你就已經上手一半了。需要做一點聲明,GIT并不是目前第一個或唯一的分布式版本控制系統。還有一些系統,例如Bitkeeper, Mercurial等,也是運作在分布式模式上的。但GIT在這方面做的更好,而且有更多強大的功能特征。
GIT跟SVN一樣有自己的集中式版本庫或伺服器。但,GIT更傾向于被使用于分布式模式,也就是每個開發人員從中心版本庫/伺服器上chect out代碼後會在自己的機器上克隆一個自己的版本庫。可以這樣說,如果你被困在一個不能連接配接網絡的地方時,就像在飛機上,地下室,電梯裡等,你仍然能夠提 交檔案,檢視曆史版本記錄,建立項目分支,等。對一些人來說,這好像沒多大用處,但當你突然遇到沒有網絡的環境時,這個将解決你的大麻煩。
同樣,這種分布式的操作模式對于開源軟體社群的開發來說也是個巨大的恩賜,你不必再像以前那樣做出更新檔包,通過email方式發送出去,你隻需要建立一個分支,向項目團隊發送一個推請求。這能讓你的代碼保持最新,而且不會在傳輸過程中丢失。GitHub.com就是一個這樣的優秀案例。
有些謠言傳出來說subversion将來的版本也會基于分布式模式。但至少目前還看不出來。
2.GIT把内容按中繼資料方式存儲,而SVN是按檔案:
所有的資源控制系統都是把檔案的元資訊隐藏在一個類似.svn,.cvs等的檔案夾裡。如果你把.git目錄的 體積大小跟.svn比較,你會發現它們差距很大。因為,.git目錄是處于你的機器上的一個克隆版的版本庫,它擁有中心版本庫上所有的東西,例如标簽,分 支,版本記錄等。
3.GIT分支和SVN的分支不同:
分支在SVN中一點不特别,就是版本庫中的另外的一個目錄。如果你想知道是否合并了一個分支,你需要手工運作像這樣的指令svn propget svn:mergeinfo,來确認代碼是否被合并。感謝Ben同學指出這個特征。是以,經常會發生有些分支被遺漏的情況。
然而,處理GIT的分支卻是相當的簡單和有趣。你可以從同一個工作目錄下快速的在幾個分支間切換。你很容易發現未被合并的分支,你能簡單而快捷的合并這些檔案。
4.GIT沒有一個全局的版本号,而SVN有:
目前為止這是跟SVN相比GIT缺少的最大的一個特征。你也知道,SVN的版本号實際是任何一個相應時間的源代 碼快照。我認為它是從CVS進化到SVN的最大的一個突破。因為GIT和SVN從概念上就不同,我不知道GIT裡是什麼特征與之對應。如果你有任何的線 索,請在評論裡奉獻出來與大家共享。
更新:有些讀者指出,我們可以使用GIT的SHA-1來唯一的辨別一個代碼快照。這個并不能完全的代替SVN裡容易閱讀的數字版本号。但,用途應該是相同的。
5.GIT的内容完整性要優于SVN:
GIT的内容存儲使用的是SHA-1雜湊演算法。這能確定代碼内容的完整性,確定在遇到磁盤故障和網絡問題時降低對版本庫的破壞。這裡有一個很好的關于GIT内容完整性的讨論 –http://stackoverflow.com/questions/964331/git-file-integrity
英文原文: http://boxysystems.com/index.php/5-fundamental-differences-between-git-svn/