天天看點

GIT常用指令 && GIT本地使用 && GIT報錯解決 && GIT的忽略檔案(ignore files)

(0)GIT目錄結構及版本控制原理

        一個Git項目中檔案的狀态大概分成下面的兩大類,而第二大類又分為三小類:

1,未被跟蹤的檔案(untracked file)

2,已被跟蹤的檔案(tracked file)

     2.1,被修改但未被暫存的檔案(changed but not updated或modified)

     2.2,已暫存可以被送出的檔案(changes to be committed 或staged)

     2.3,自上次送出以來,未修改的檔案(clean 或 unmodified)

Git把它所管理的所有對象(blob,tree,commit,tag……),全部根據它們的内容生成SHA1哈希串值作為對象名;根據目前的數學知識,如果兩塊資料的SHA1哈希串值相等,那麼我們就可以認為這兩塊資料是相同的。這樣會帶來的幾個好處:

1,Git隻要比較對象名,就可以很快的判斷兩個對象的内容是否相同。

2,因為在每個倉庫(repository)的“對象名”的計算方法都完全一樣,如果同樣的内容存在兩個不同的倉庫中,就會存在相同的“對象名”。

3,Git還可以通過檢查對象内容的SHA1的哈希值和“對象名”是否比對,來判斷對象内容是否正确。

4,根據上面的原則:Git确實根據内容來生成名字的,而且同名(SHA1哈希串值)肯定會有相同内容,但是送出對象(commit)和其它對象有點不一樣,它裡面會多一個時間戳(timestamp),是以在不同的時間生成的送出對象,即使内容完全一樣其名字也不會相同。

    1300697913 +0800就是時間戳,refs/heads/master對應的就是commit對象

(1)git add:添加至暫存區,但并未送出至伺服器。git add . 是表示把目前目錄下的所有更新添加至暫存區。有時在終端操作這個會提示:

warning: CRLF will be replaced by LF in GeneSmartStay/res/values-zh-rTW/strings.xml.The file will have its original line endings in your working directory.

這是因為檔案中換行符的差别導緻的。這個提示的意思是說:會把windows格式(CRLF)轉換成Unix格式(LF),這些是轉換檔案格式的警告,不影響使用。

        需要注意的是:如果在上次執行“git add”之後再對檔案的内容進行了修改,那麼在執行“git status”指令時,Git會對檔案内容進行SHA1哈希運算就會發現檔案又被修改了,仍會提示需要add,這是因為SVN是追加式的,隻需要add一次;而GIT每次修改後的送出都是新檔案,是以需要重新add。其實這時“readme.txt“就同時呈現了兩個狀态:被修改但未被暫存的檔案(changed but not updated),已暫存可以被送出的檔案(changes to be committed)。如果我們這時送出的話,就是隻會送出第一次“git add"是以暫存的檔案内容;隻有再add後再送出,才是commit修改後的内容。

        我們用一個實驗來證明git的每次commit是獨立的檔案,不是追加的增量。我們在readme.txt複制後,在新檔案的末尾增加了一行語句,變成了readme2.txt。檢視兩次送出的資訊并cat檔案内容

readme2.txt僅僅是末尾加了一行,但是可以看到不同commit對象對應的仍是完整的内容,而不是差異。

(2)git branch:可以建立一個新的分支,也可以檢視目前倉庫裡所有的分支。git branch test建立名為test的分支,可以用git checkout test切換到test分支工作。如果倉庫下的某分支不用了,可以用“git branch -d”指令把這個分支删掉。如果你想要删除的分支還沒有被合并到其它分支中去,那麼就不能用“git branch -d”來删除它,需要改用“git branch -D”來強制删除。

(3)git checkout:從暫存區恢複檔案到工作區git checkout  --  <file>;有可以把Git 倉庫(隐藏目錄中的那些檔案)導出到工作目錄中;可以切換到某分支進行工作。Git把所有的曆史送出資訊全部存儲在“Git目錄”裡,它就是一個Git項目的倉庫;你對本地的源代碼進行編輯修改後建立的送出也都會先儲存在這裡面,然後再推送到遠端的伺服器。當我們把項目目錄和“Git目錄”一起拷到其它電腦裡,它能馬上正常的工作(所有的送出資訊全都儲存在Git目錄裡);甚至可以隻把“Git目錄”拷走也行,但是要再簽出(checkout)一次。git checkout -- filename 這個是恢複到某檔案修改前的版本,這樣你做的本地修改都忽略不見了;如果不帶具體檔案名,隻會提示更改記錄,并不會做任何更新。git-checkout -f ,可以使用 -f 選項導出檔案,覆寫本地修改,這樣就可以将您帶回到一個幹淨的狀态。

        另一個較重要的功能類似于svn update,如果某次之前的commit有多個不同目錄下的檔案,現在隻想恢複其中的某個檔案到曆史版本,用git checkout  commit_id file_name  //取檔案file_name的 在commit_id是的版本,commit_id為 git commit 時的sha值。

(4)git clean:清除工作區未跟蹤檔案或者手工檔案。

(5)git cat-file:檢視節點檔案,-p檢視節點内容,-t檢視節點類型。Git的資料對象包括:送出(commits)、樹對象(trees)、二進制對象(blobs)、标簽對象(tags)。這些對象之間是什麼關系呢?

        A,先用git log檢視GIT本地建立的資訊:

大家可以看到目前隻有一個送出(commit)對象,而它的名字就是:”4f8d94496150661c48cb9fa119869702be1f3af6”。這個名字就是對象内容的一個簽名串值,隻要對象裡面的内容不同,那麼我們就可以認為對象的名字不會相同,反之也成立。為了友善表示,在不影響表達的情況下,一般隻寫SHA串值的前6個字元。

       B,用 git cat-file -p檢視節點資訊,如下:

大家可以看到:送出“4f8d94” 是引用一個名為“5494546f6903153c9b16a81a6d9000debd275d31”的樹對象(tree)。一個樹對象(tree)可以引用一個或多個二進制對象(blob), 每個二進制對象都對應一個檔案。 更進一步, 樹對象也可以引用其他的樹對象,進而構成一個目錄層次結構。我們再看一下這個樹對象(tree)裡面有什麼東東:

可以它直接引用alps我們代碼的根目錄。所有CODE就是根據這個來聯系起來的。

      C,我們可以用這個指令完成另一個實驗,即相同内容的檔案具有相同的哈希值,建跟readme.txt内容完全相同的另一個檔案。執行:

這個指令是檢視目前的送出(HEAD)所包含的blob對象,可見,它們的對象名完全一樣。

(6)git commit:本地送出。git commit -m 'xxxxx',以添加LOG的形式送出更改。送出的是暫存區的内容,而不是工作區的内容。

(7)git config:查詢和修改配置。當使用git時回報*** Please tell me who you are,說明個人賬戶沒有配置。git的配置檔案;一共有三個:

            A,/etc/gitconfig: 所有使用者普遍适用的、系統的,git config --system選項

            B,~/.gitconfig: 隻适用該使用者, git config --global選項

            C,.git/config目前項目.git目錄中,隻适用目前項目, .git/config

            每一層都覆寫上一層,也就是優先級  .gitconfig  >  ~/.gitconfig  >  /etc/gitconfig。配置内容:A,使用者資訊:包括個人使用者名稱和電子郵件名稱;B,文本編輯器:設定在需要打開文本編輯器來輸入某些資訊時預設編輯器,例如vi、 vim、 emacs等;C,差異分析工具:在解決合并沖突時使用哪種差異分析工具。比如vimdiff;

        檢視配置内容:git config --list, 有時候會看到重複的變量名,那就說明它們來自不同的配置檔案。不過最終Git 實際采用的是最後一個。

(8)git diff:本地檔案與暫存區差異比較。檢視本地檔案和倉庫已送出内容的差異:git diff HEAD;暫存區與HEAD的對比:git diff --cached;檢視某個檔案與倉庫的差别:git diff filename.c 。檢視master分支與子分支的差異:git diff 分支名。

(9)git fetch:擷取遠端版本庫

(10)git init 和git clone:建立一個git倉庫。有兩種方式可以建立git倉庫,一個是建立,一個是克隆現有的git倉庫。 建立一個git倉庫:  git init;克隆現有的git倉庫:  git clone [url] [目錄名(如果木有,則建立一個和原倉庫同名的目錄)。建立起來的git倉庫都是在目錄下多了一個.git目錄,不同點是init的裡邊啥也木有,clone的是把目标git倉庫複制過來了。android GIT源目錄https://android.googlesource.com/?format=HTML

        一個例子來說明git clone。如果想看一下最新的linux核心源代碼,當我們打開它的網站時,發現有如下面的一段提示:

三行字元串表示三個位址,我們可以通過這三個位址得到同樣的一份Linux核心源代碼,即用git clone上面的任一行得到的是同樣的内容。

         我們先來看一下URL,git://、http://、https://這些代表是傳輸git倉庫的協定形式,而“git.kernel.org“則代表了Git倉庫存儲的伺服器名字(域名),“/pub/scm/linux/kernel/git/torvalds/linux-2.6.git” 則代表了Git倉庫在伺服器上位置。Git 倉庫除了可以通過上面的git、http、https協定傳輸外還可以通過ssh、ftp(s)、rsync等協定來傳輸。git clone的本質就是把“Git目錄”裡面的内容拷貝過來,執行git clone的結果如下:

     initialized這行意味着我們在本地先建了一個“linux-2.6”目錄,然後在這個目錄建了一個空的Git本地倉庫(Git目錄),裡面将會存儲從網上拉下來的曆史送出。remote這兩行代表伺服器現在調用 git-pack-objects 對它的倉庫進行打包和壓縮。receving這行代表用戶端接收伺服器端發過送過來的資料。在我們執行完上面的clone linux-2.6代碼的的操作後,Git會從“Git目錄”裡把最新的代碼到簽出(checkout)到“linux-2.6”這個目錄裡面。

(11)git log:顯示送出日志(如果是clone來的,它也會繼承所克隆的倉庫的資訊)。帶參數-- fileName,fileName為任意檔案名,檢視指定檔案的送出資訊。 帶參數 file/ ,    檢視file檔案夾下所有檔案的送出記錄。git log .:目前目錄下的送出記錄。

        另外,git log -n 1:檢視最後一次送出的資訊;git log -n 1 --stat:想看到最近一次送出所有更改過的檔案;git log -n 1 -p:想看到最近一次送出所有更改的細節。git log -p xxx.c:檢視某檔案所有次送出的詳細修改細節。

         如果log跟tag都有使用,可以用git log tag_relold..tag_relnew來顯示這兩次tag之間所列出的commit Log記錄。

(12)git merge:分支合并。git merge子分支名,把子分支與master合并。

“Updating b765df9..7f3c997”表示現在正在更新合并“b765df9”和“7f3c997”兩個送出(commit)之間的内容;“b765df9”代表着主分支(master),“7f3c997”代表測試分支(test)。“Fast-forward”在這裡可以了解為順利合并,沒有沖突。

        如果修改的内容有沖突,則會有如下的提示:

合并指令的執行結果不是“Fast-foward”,而是“CONFLICT”。是的,兩個分支的内容有差異,緻使它們不能自動合并(Auto-merging)。先看一下工作目錄的狀态:

        提示目前有一個檔案“readme.txt”沒有被合并,原因是“both modified”。再看一下暫存區裡的内容:

“aac629”是目前主分支的内容,“034a81”是測試分支裡的内容,而“4b5fa6”是它們共同父對象(Parent)裡的内容。是以我們用編輯器合并編輯了工作區的内容後,在add 、commit,這個沖突就算解決了。怎麼用“git add”添加到暫存區去,“git add”不是用來未暫存檔案的吧,怎麼又來解決沖突了?因為Git是一個“snapshot”存儲系統,所有新增加的内容都是直接存儲的,而不是和老版本作一個比較後存儲新舊版本間的差異。

(13)git mv:重命名

(14)git pull:拉回遠端版本庫的更新,也即把伺服器上的最新更改變更更新到本地工作區上( 比如git-pull git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git,即拉取源代碼樹的更新)。如果pull時提示諸如 fc7cc33..ebf8026  master     -> origin/master,說明mastar已從fc7cc33更新到了ebf8026。本地如果想恢複到fc7cc33版本,再重新pull即可,要先恢複參見git reset。

(15)git push:推送至遠端版本庫

(16)git remote:遠端版本庫管理

(17)git rm:删除檔案。git rm --cached <file>從暫存區删除某檔案;git rm <file> 從暫存區和倉庫中都删除某檔案。

        A,git rm file1 //删除檔案跟蹤并且删除倉庫中的檔案file1

              git commit //送出剛才的删除動作,之後git不再管理該檔案。

        B,git rm --cached file1 //删除檔案跟蹤但不删除倉庫的檔案file1

               git commit //送出剛才的删除動作,之後git不再管理該檔案。但是檔案系統中還是有file1。

不再跟蹤某個目錄,用git rm -rf xxx/(可能需要先儲存好本地檔案,避免誤删),之後再commit。

(18)git status:顯示整個工作區檔案狀态,該指令無法獲知伺服器上是否有更新,隻能檢測目前目錄是否有未送出的。git status .:目前目錄的差異狀态。

(19)git reset:重置改變分支“遊标”指向,或者從資料倉庫恢複檔案到工作區。git reset HEAD filename 取消暫存,檔案回到已修改未暫存的狀态。用git reset --hard 哈希碼 ,可以恢複到之前舊的某個版本,比如:git reset --hard fc7cc33,則終端回顯HEAD is now at fc7cc33 Support AccessibilityService。

(20)git sp:生成差分更新包。用git lg列出LOG記錄後,用sp  哈希碼舊..哈希碼新,就可以生成一個兩個版本間的差別差分包XXX.PATCH。

(21)git  apply:在收到别人sp出給的patch,合并到自己的CODE中時,可以用指令來做這份工作。在master目錄下git apply --reject  xxx.patch就行了,不必手工來做。如果自己在合并patch之前做了其他修改,該指令會執行失敗,需要手工合并。

(22)git ls-files --stage:檢視暫存區内容。

        你會發現“git目錄“裡多出了”.git/objects/2d/832d9044c698081e59c322d5a2a459da546469”這麼一個檔案,再執行“git cat-file -p 2d832d” 的話,就可以看到裡面的内容正是“hello,world"。Git在把一個檔案添加暫存區時,不但把它在索引檔案(.git/index)裡挂了号,而且把它的内容先儲存到了“git目錄“裡面去了。

(23)git show:顯示某次commit送出的細節和差異。比如git show commit_id,如果隻看這次送出的某個檔案的細節和差異,後面再加上路徑和文加名就行了。

(24)git tag:可以用 git tag建立一個标簽(tag)指定某個送出(commit)。比如 git tag stable-1 1b2e1d63ff,這樣我們可以用stable-1 作為送出(commit) "1b2e1d63ff" 的代稱(refer)。也即tag是某些典型log的另一個名稱。用git tag -l可以列出所有的tag記錄。

 ========================================================================================

       假如項目在路經/home/ryan/codes/下面:

cd /home/ryan/codes/

git init

git add *

git commit -m "my project"

即可。需要注意的是,子目錄需沒有被GIT管理過,不然會遺留.git目錄,導緻最上層的GIT添加過程不會完整。

==========================================================================================

(1)當執行GIT操作時,如果回顯:fatal: Unable to create ‘xxxx/.git/index.lock': File exists.If no other git process is currently running, this probably means a

git process crashed in this repository earlier. Make sure no other git process is running and remove the file manually to continue.

解決方法:rm -f ./.git/index.lock

===========================================================================================

       使用GIT管理代碼倉庫時,有些檔案是不需要進行管理的(不需要老被提示Untracked files,因為根本不用關注),比如編譯生成的.o .a檔案、某些生成檔案夾等,這個時候就需要用到ignore檔案。ignore檔案均為如下格式: 

        比較常用的一種方法是在倉庫所在目錄下建立一個名為.gitignore的檔案,編輯如上内容。.gitignore檔案對其所在的目錄及所在目錄的全部子目錄均有效。常用規則還有:

# 忽略*.o和*.a檔案

 *.[oa]

# 忽略*.b和*.B檔案,my.b除外

*.[bB]

!my.b

# 忽略dbg檔案和dbg目錄

dbg

# 隻忽略dbg目錄,不忽略dbg檔案

dbg/

# 隻忽略dbg檔案,不忽略dbg目錄

!dbg/

# 隻忽略目前目錄下的dbg檔案和目錄,子目錄的dbg不在忽略範圍内

/dbg

       需要注意的是.gitignore檔案放置位置,如果是對alps執行了git add/git commit,那麼.git目錄跟alps是同一層目錄的。在目前目錄下建立.gitignore檔案,如果需要忽略alps/out目錄,則添加内容out/即可,也即設定的目前所在目錄是alps/。

繼續閱讀