Git版本管理之旅(二)—— Git基本操作流程及相關命令
本章繼續上章的型別,介紹基於空專案的版本庫操作,本教程基於Ubuntu
- 建立版本庫
- 新增檔案
- 修改檔案
- 刪除檔案
- 版本回退
- 基本概念
- 管理以及撤銷修改
- 新增到遠端倉庫
- 從遠端倉庫克隆
建立版本庫
版本庫又名倉庫,英文名repository,可以理解成一個目錄,這個目錄裡面的所有檔案都可以被Git管理起來,每個檔案的修改、刪除,Git都能跟蹤,以便任何時刻都可以追蹤歷史。
xq@xq-VPCEG17YC:~/git$ pwd
/home/xq/git
xq@xq-VPCEG17YC:~/git$ mkdir test
xq@xq-VPCEG17YC:~/git$ cd test/
xq@xq -VPCEG17YC:~/git/test$ git init
初始化空的 Git 倉庫於 /home/xq/git/test/.git/
xq@xq-VPCEG17YC:~/git/test$ ls
xq@xq-VPCEG17YC:~/git/test$ ls -ah
. .. .git
首先新建一個test的資料夾(不一定都是空資料夾,只是託管的檔案自己需要把握),在該目錄下執行git init命令,該目錄就會變成git管理的倉庫。
目錄下多了一個.git的目錄,這個目錄是Git來跟蹤管理版本庫的,不可隨意修改。
新增檔案
xq@xq-VPCEG17YC:~/git/test$ vi hello.txt
xq@xq -VPCEG17YC:~/git/test$ cat hello.txt
this is my first try.
xq@xq-VPCEG17YC:~/git/test$ git add hello.txt
xq@xq-VPCEG17YC:~/git/test$ git commit -m "add a file[hello.txt]"
[master (根提交) b10613a] add a file[hello.txt]
1 file changed, 1 insertion(+)
create mode 100644 hello.txt
新建一個hello.txt的檔案
通過git add xxx的命令新增到本地倉庫
通過git commit的命令提交本次修改,-m是本次提交的說明,可以輸入任意內容
修改檔案
xq@xq-VPCEG17YC:~/git/test$ vi hello.txt
xq@xq-VPCEG17YC:~/git/test$ cat hello.txt
this is my second try.
xq@xq-VPCEG17YC:~/git/test$ git status
位於分支 master
尚未暫存以備提交的變更:
(使用 "git add <檔案>..." 更新要提交的內容)
(使用 "git checkout -- <檔案>..." 丟棄工作區的改動)
修改: hello.txt
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
xq@xq-VPCEG17YC:~/git/test$ git diff
diff --git a/hello.txt b/hello.txt
index df723d7..55ef308 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1 +1 @@
-this is my first try.
+this is my second try.
修改hello.txt檔案
通過git status倉庫當前的狀態
通過git diff比較差異
xq@xq-VPCEG17YC:~/git/test$ git add hello.txt
xq@xq-VPCEG17YC:~/git/test$ git status
位於分支 master
要提交的變更:
(使用 "git reset HEAD <檔案>..." 以取消暫存)
修改: hello.txt
xq@xq-VPCEG17YC:~/git/test$ git commit -m "update hello.txt"
[master 9d94f3b] update hello.txt
1 file changed, 1 insertion(+), 1 deletion(-)
xq@xq-VPCEG17YC:~/git/test$ git status
位於分支 master
無檔案要提交,乾淨的工作區
修改之後提交檔案和新增時時一樣的,通過git status檢視各種情況下倉庫的狀態
刪除檔案
本地工作空間刪除檔案 rm xxx
Git知道你刪除了檔案,因此,工作區和版本庫就不一致了,可用git status檢視狀態
如果時本地空間誤刪可用git checkout – xxx從版本庫中檢出到本地;如果是要從版本庫中刪除該檔案,那就用命令git rm刪掉,並且git commit
版本回退
我們再次修改hello.txt然後commit
之後通過git log檢視修改記錄
xq@xq-VPCEG17YC:~/git/test$ git log --pretty=oneline
774045528c64b1b541a045093836c1845f14a908 update again
9d94f3ba85cfac45b0e30010fca1265f15e9aaf7 update hello.txt
b10613a11dbae7c93d2cf49f654ade68ad675030 add a file[hello.txt]
日誌中記錄的hash值,上一章我們解釋過
檔案在儲存到 Git 時,資料都要使用 SHA-1 演算法進行內容的校驗和(checksum)計算,得到一個 SHA-1 雜湊值,作為指紋字串。該字串由 40 個十六進位制字元(0-9 及 a-f)組成,並將此結果作為資料的唯一標識和索引。通過唯一標誌判斷檔案的完整性以及是否變更。所有儲存在 Git 資料庫中的東西都是用此雜湊值來作索引的,而不是靠檔名。
後面記錄的是我們每次commit時的說明
在Git中,用HEAD表示當前版本,也就是最新的提交,上一個版本就是HEAD^,上上一個版本就是HEAD^^,當然往上100個版本寫100個^比較容易數不過來,所以寫成HEAD~100。
以下對應hello.txt的三個版本
- HEAD –> 774045528c64b1b541a045093836c1845f14a908
- HEAD^ –> 9d94f3ba85cfac45b0e30010fca1265f15e9aaf7
- HEAD^^ –> b10613a11dbae7c93d2cf49f654ade68ad675030
我們將版本回退到上一個版本,並檢視檔案,發現確實已經回退。
此時檢視日誌,發現只剩下兩個版本了。此時版本對應如下
- HEAD –> 9d94f3ba85cfac45b0e30010fca1265f15e9aaf7
- HEAD^ –> b10613a11dbae7c93d2cf49f654ade68ad675030
xq@xq-VPCEG17YC:~/git/test$ git reset --hard HEAD^
HEAD 現在位於 9d94f3b update hello.txt
xq@xq-VPCEG17YC:~/git/test$ cat hello.txt
this is my second try.
xq@xq-VPCEG17YC:~/git/test$ git log --pretty=oneline
9d94f3ba85cfac45b0e30010fca1265f15e9aaf7 update hello.txt
b10613a11dbae7c93d2cf49f654ade68ad675030 add a file[hello.txt]
當然通過git reset –hard 9d94f3ba85cf(hashId 前幾位也行,系統會自動查詢),也是可以回退的。
如果回退後,又希望恢復到第三個版本怎麼辦呢?git reflog會記錄每一次命令,然後找到對應的hashId恢復就可以啦。
xq@xq-VPCEG17YC:~/git/test$ git reflog
9d94f3b HEAD@{0}: reset: moving to HEAD^
7740455 HEAD@{1}: commit: update again
9d94f3b HEAD@{2}: commit: update hello.txt
b10613a HEAD@{3}: commit (initial): add a file[hello.txt]
xq@xq-VPCEG17YC:~/git/test$ git reset --hard 7740455
HEAD 現在位於 7740455 update again
xq@xq-VPCEG17YC:~/git/test$ cat hello.txt
this is my third try.
基本概念
到了這裡我們繼續鞏固上一章的內容,理論+實踐+理論
- 工作區(Working Directory)
就是你在電腦裡能看到的目錄,比如我的test資料夾就是一個工作區 - 版本庫(Repository)
工作區有一個隱藏目錄.git,這個不算工作區,而是Git的版本庫。
Git的版本庫裡存了很多東西,其中最重要的就是稱為stage(或者叫index)的暫存區,還有Git為我們自動建立的第一個分支master,以及指向master的一個指標叫HEAD。
前面講了我們把檔案往Git版本庫裡新增的時候,是分兩步執行的:
第一步是用git add把檔案新增進去,實際上就是把檔案修改新增到暫存區;
第二步是用git commit提交更改,實際上就是把暫存區的所有內容提交到當前分支。
因為我們建立Git版本庫時,Git自動為我們建立了唯一一個master分支,所以,現在,git commit就是往master分支上提交更改。
你可以簡單理解為,需要提交的檔案修改通通放到暫存區,然後,一次性提交暫存區的所有修改。
管理以及撤銷修改
Git比其他版本控制系統設計得優秀,因為Git跟蹤並管理的是修改,而非檔案。
比如你新增了一行,這就是一個修改,刪除了一行,也是一個修改,更改了某些字元,也是一個修改,刪了一些又加了一些,也是一個修改,甚至建立一個新檔案,也算一個修改。
我們修改hello.txt然後git add新增到暫存區,然後再次修改hello.txt,最後執行git commit命令,提交後,用git diff HEAD – hello.txt命令可以檢視工作區和版本庫裡面最新版本的區別,發現並不一致。
原因是:Git管理的是修改,當你用git add命令後,在工作區的第一次修改被放入暫存區,準備提交,但是,在工作區的第二次修改並沒有放入暫存區,所以,git commit只負責把暫存區的修改提交了,也就是第一次的修改被提交了,第二次的修改不會被提交。
xq@xq-VPCEG17YC:~/git/test$ cat hello.txt
this is my third try.
xq@xq-VPCEG17YC:~/git/test$ vi hello.txt
xq@xq-VPCEG17YC:~/git/test$ cat hello.txt
this is my fourth try.
xq@xq-VPCEG17YC:~/git/test$ git add hello.txt
xq@xq-VPCEG17YC:~/git/test$ vi hello.txt
xq@xq-VPCEG17YC:~/git/test$ cat hello.txt
this is my fifth try.
xq@xq-VPCEG17YC:~/git/test$ git commit -m "stage test"
[master 1a465a0] stage test
1 file changed, 1 insertion(+), 1 deletion(-)
xq@xq-VPCEG17YC:~/git/test$ cat hello.txt
this is my fifth try.
xq@xq-VPCEG17YC:~/git/test$ git status
位於分支 master
尚未暫存以備提交的變更:
(使用 "git add <檔案>..." 更新要提交的內容)
(使用 "git checkout -- <檔案>..." 丟棄工作區的改動)
修改: hello.txt
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
xq@xq-VPCEG17YC:~/git/test$ git diff HEAD -- hello.txt
diff --git a/hello.txt b/hello.txt
index fd3f316..3d7585b 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1 +1 @@
-this is my fourth try.
+this is my fifth try.
檔案修改錯誤需要撤銷怎麼辦
本地工作區撤銷
1.檔案還在工作區可以手動修改檔案;
2.git checkout – file也可以丟棄工作區的修改(命令中的–很重要,沒有–,就變成了“切換到另一個分支”的命令)一種是hello.txt自修改後還沒有被放到暫存區,現在,撤銷修改就回到和版本庫一模一樣的狀態;
一種是hello.txt已經新增到暫存區後,又作了修改,現在,撤銷修改就回到新增到暫存區後的狀態。
總之,就是讓這個檔案回到最近一次git commit或git add時的狀態。
已經add到暫存區撤銷
用命令git reset HEAD file可以把暫存區的修改撤銷掉(unstage),重新放回工作區git reset命令既可以回退版本,也可以把暫存區的修改回退到工作區。當我們用HEAD時,表示最新的版本
- 已經commit到版本庫撤銷
參考《版本回退》小節
xq@xq-VPCEG17YC:~/git/test$ git checkout -- hello.txt
xq@xq-VPCEG17YC:~/git/test$ cat hello.txt
this is my fourth try.
xq@xq-VPCEG17YC:~/git/test$ cat hello.txt
this is my fifth try.
xq@xq-VPCEG17YC:~/git/test$ git add hello.txt
xq@xq-VPCEG17YC:~/git/test$ vi hello.txt
xq@xq-VPCEG17YC:~/git/test$ cat hello.txt
this is my sixth try.
xq@xq-VPCEG17YC:~/git/test$ git reset HEAD hello.txt
重置後取消暫存的變更:
M hello.txt
新增到遠端倉庫
Git是分散式版本控制系統,同一個Git倉庫,可以分佈到不同的機器上。別的機器可以“克隆”這個原始版本庫,而且每臺機器的版本庫其實都是一樣的,並沒有主次之分。
單機也是可以克隆多個版本庫,但是毫無意義。我們將GitHub作為伺服器的角色,提供7*24的服務,從GitHub倉庫克隆一份到自己的電腦上,並且各自把各自的提交推送到伺服器倉庫裡,也從伺服器倉庫中拉取別人的提交。
GitHub申請以及SSH祕鑰設定見上一章
我們可以把一個已有的本地倉庫與之關聯,然後,把本地倉庫的內容推送到GitHub倉庫。
在GitHub上新建一個test的版本庫
現在,我們根據GitHub的提示,在本地的test倉庫下執行命令:
git remote add origin https://github.com/rickey17/test.git
請千萬注意,把上面的rickey17替換成你自己的GitHub賬戶名,否則,你在本地關聯的就是我的遠端庫,關聯沒有問題,但是你以後推送是推不上去的,因為你的SSH Key公鑰不在我的賬戶列表中。
新增後,遠端庫的名字就是origin,這是Git預設的叫法,也可以改成別的,但是origin這個名字一看就知道是遠端庫。
下一步,就可以把本地庫的所有內容推送到遠端庫上:
git push -u origin master
這樣你就可以在GitHub上看見你的檔案了。
把本地庫的內容推送到遠端,用git push命令,實際上是把當前分支master推送到遠端。
由於遠端庫是空的,我們第一次推送master分支時,加上了-u引數,Git不但會把本地的master分支內容推送的遠端新的master分支,還會把本地的master分支和遠端的master分支關聯起來,在以後的推送或者拉取時就可以簡化命令。
從現在起,只要本地作了提交,就可以通過命令:
git push origin master
把本地master分支的最新修改推送至GitHub,現在,你就擁有了真正的分散式版本庫!
從遠端倉庫克隆
xq@xq-VPCEG17YC:~/git/test$ git status
位於分支 master
您的分支與上游分支 'origin/master' 一致。
尚未暫存以備提交的變更:
(使用 "git add <檔案>..." 更新要提交的內容)
(使用 "git checkout -- <檔案>..." 丟棄工作區的改動)
修改: hello.txt
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
xq@xq-VPCEG17YC:~/git/test$ git add hello.txt
xq@xq-VPCEG17YC:~/git/test$ git commit -m "commit to GitHub"
[master 3742dca] commit to GitHub
1 file changed, 1 insertion(+), 1 deletion(-)
xq@xq-VPCEG17YC:~/git/test$ git push origin master
物件計數中: 3, 完成.
寫入物件中: 100% (3/3), 272 bytes | 0 bytes/s, 完成.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:rickey17/test.git
1a465a0..3742dca master -> master
xq@xq-VPCEG17YC:~/git/test$ git clone https://github.com/rickey17/test.git
正克隆到 'test'...
remote: Counting objects: 15, done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 15 (delta 0), reused 15 (delta 0), pack-reused 0
展開物件中: 100% (15/15), 完成.
檢查連線... 完成。