天天看點

git基礎(二)——基本操作

文章目錄

    • 1. 取得項目的Git倉庫
      • 1.1 在工作目錄中初始化新倉庫
      • 1.2 從現有倉庫克隆
    • 2. 記錄每次更新
      • 2.1 檢查目前檔案狀态
      • 2.2 跟蹤新檔案
      • 2.3 暫存已修改檔案
      • 2.4 檢視已暫存和未暫存的更新
      • 2.5 送出更新
    • 3. 移除檔案
    • 4. 檔案改名
    • 5. 忽略某些檔案(.gitignore)
    • 6.檢視送出曆史
    • 7. 撤銷操作
      • 7.1 修改最後一次送出
      • 7.2 取消已經暫存的檔案
      • 7.3 取消對檔案的修改
    • 8.版本回退

1. 取得項目的Git倉庫

有兩種取得 Git 項目倉庫的方法。第一種是在現存的目錄下,通過導入所有檔案來建立新的 Git 倉庫。第二種是從已有的 Git 倉庫克隆出一個新的鏡像倉庫來。

1.1 在工作目錄中初始化新倉庫

要對現有的某個項目開始用 Git 管理,隻需到此項目所在的目錄,執行:

$ git init
           

初始化後,在目前目錄下會出現一個名為 .git 的目錄,所有 Git 需要的資料和資源都存放在這個目錄中。不過目前還沒有開始跟蹤管理項目中的任何一個檔案。

也就是說,git init指令隻是讓code_test目錄擁有了版本管理的能力,無論code_test目錄中原來是否存在檔案,".git"目錄都是新建立出來的,從git倉庫的角度來說,這就是一個新的倉庫,還沒有任何檔案被這個倉庫所管理。

需要注意

git init指令是把目前目錄轉化成git repo

git init repo_name 指令是在目前目錄中建立一個以repo_name命名的新目錄,新目錄是一個git repo

如果目前目錄下有幾個檔案想要納入版本控制,需要先用

git add

指令告訴 Git 開始對這些檔案進行跟蹤,然後送出:

$ git add *.c
$ git add README
$ git commit -m 'initial project version'
           

1.2 從現有倉庫克隆

如果想對某個開源項目出一份力,可以先把該項目的 Git 倉庫複制一份出來,這就需要用到

git clone

指令。

克隆倉庫的指令格式為

git clone [url]

。比如,要克隆 Ruby 語言的 Git 代碼倉庫 Grit,可以用下面的指令:

$ git clone git://github.com/schacon/grit.git
           

這會在目前目錄下建立一個名為

grit

的目錄,其中包含一個

.git

的目錄,用于儲存下載下傳下來的所有版本記錄,然後從中取出最新版本的檔案拷貝。如果進入這個建立的

grit

目錄,你會看到項目中的所有檔案已經在裡邊了,準備好後續的開發和使用。如果希望在克隆的時候,自己定義要建立的項目目錄名稱,可以在上面的指令末尾指定新的名字:

$ git clone git://github.com/schacon/grit.git mygrit
           

唯一的差别就是,現在建立的目錄成了

mygrit

,其他的都和上邊的一樣。

Git 支援許多資料傳輸協定。之前的例子使用的是

git://

協定,不過你也可以用

http(s)://

或者

[email protected]:/path.git

表示的 SSH 傳輸協定。

2. 記錄每次更新

請記住,工作目錄下面的所有檔案都不外乎這兩種狀态:已跟蹤或未跟蹤。已跟蹤的檔案是指本來就被納入版本控制管理的檔案,在上次快照中有它們的記錄,工作一段時間後,它們的狀态可能是未更新,已修改或者已放入暫存區。而所有其他檔案都屬于未跟蹤檔案。它們既沒有上次更新時的快照,也不在目前的暫存區域。初次克隆某個倉庫時,工作目錄中的所有檔案都屬于已跟蹤檔案,且狀态為未修改。

在編輯過某些檔案之後,Git 将這些檔案标為已修改。我們逐漸把這些修改過的檔案放到暫存區域,直到最後一次性送出所有這些暫存起來的檔案,如此重複。

2.1 檢查目前檔案狀态

要确定哪些檔案目前處于什麼狀态,可以用

git status

指令。如果在克隆倉庫之後立即執行此指令,會看到類似這樣的輸出:

$ git status
On branch master
nothing to commit, working directory clean
           

這說明你現在的工作目錄相當幹淨。換句話說,所有已跟蹤檔案在上次送出後都未被更改過。此外,上面的資訊還表明,目前目錄下沒有出現任何處于未跟蹤的新檔案,否則 Git 會在這裡列出來。最後,該指令還顯示了目前所在的分支是

master

,這是預設的分支名稱。

現在讓我們用 vim 建立一個新檔案 README,儲存退出後運作

git status

會看到該檔案出現在未跟蹤檔案清單中:

$ vim README
$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)

        README

nothing added to commit but untracked files present (use "git add" to track)
           

在狀态報告中可以看到建立的

README

檔案出現在**“Untracked files”**下面。未跟蹤的檔案意味着Git在之前的快照(送出)中沒有這些檔案;Git 不會自動将之納入跟蹤範圍,除非你明明白白地告訴它“我需要跟蹤該檔案”,因而不用擔心把臨時檔案什麼的也歸入版本管理。不過現在的例子中,我們确實想要跟蹤管理 README 這個檔案。

2.2 跟蹤新檔案

使用指令

git add

開始跟蹤一個新檔案。是以,要跟蹤 README 檔案,運作:

$ git add README
           

此時再運作

git status

指令,會看到 README 檔案已被跟蹤,并處于暫存狀态:

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   README
           

隻要在 “Changes to be committed” 這行下面的,就說明是已暫存狀态。如果此時送出,那麼該檔案此時此刻的版本将被留存在曆史記錄中。

2.3 暫存已修改檔案

現在我們修改下之前已跟蹤過的檔案

benchmarks.rb

,然後再次運作

status

指令,會看到這樣的狀态報告:

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   benchmarks.rb
           

檔案

benchmarks.rb

出現在 **“Changes not staged for commit” **這行下面,說明已跟蹤檔案的内容發生了變化,但還沒有放到暫存區。要暫存這次更新,需要運作

git add

指令。

很多時候可以通過git status下的提示來進行下一步操作。

現在讓我們運作

git add

将 benchmarks.rb 放到暫存區,然後再看看

git status

的輸出:

$ git add benchmarks.rb
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   README
        modified:   benchmarks.rb
           

現在兩個檔案都已暫存,下次送出時就會一并記錄到倉庫。假設此時,你想要在

benchmarks.rb

裡再加條注釋,重新編輯存盤後,準備好送出。不過且慢,再運作

git status

看看:

$ vim benchmarks.rb
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   README
        modified:   benchmarks.rb

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   benchmarks.rb
           

怎麼回事?

benchmarks.rb

檔案出現了兩次!一次算未暫存,一次算已暫存,這怎麼可能呢?好吧,實際上 Git 隻不過暫存了你運作

git add

指令時的版本,如果現在送出,那麼送出的是添加注釋前的版本,而非目前工作目錄中的版本。是以,運作了

git add

之後又作了修訂的檔案,需要重新運作

git add

把最新版本重新暫存起來:

$ git add benchmarks.rb
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   README
        modified:   benchmarks.rb
           

2.4 檢視已暫存和未暫存的更新

實際上

git status

的顯示比較簡單,僅僅是列出了修改過的檔案,如果要檢視具體修改了什麼地方,可以用

git diff

指令。

假如再次修改

README

檔案後暫存,然後編輯

benchmarks.rb

檔案後先别暫存,運作

status

指令将會看到:

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   benchmarks.rb
           

要檢視尚未暫存的檔案更新了哪些部分,不加參數直接輸入

git diff

$ git diff
diff --git a/benchmarks.rb b/benchmarks.rb
index 3cb747f..da65585 100644
--- a/benchmarks.rb
+++ b/benchmarks.rb
@@ -36,6 +36,10 @@ def main
           @commit.parents[0].parents[0].parents[0]
         end

+        run_code(x, 'commits 1') do
+          git.commits.size
+        end
+
         run_code(x, 'commits 2') do
           log = git.commits('master', 15)
           log.size
           

若要看已經暫存起來的檔案和上次送出時的快照之間的差異,可以用

git diff --cached

指令。(Git 1.6.1 及更高版本還允許使用

git diff --staged

,效果是相同的,但更好記些。)來看看實際的效果:

$ git diff --cached
diff --git a/README b/README
new file mode 100644
index 0000000..03902a1
--- /dev/null
+++ b/README2
@@ -0,0 +1,5 @@
+grit
+ by Tom Preston-Werner, Chris Wanstrath
+ http://github.com/mojombo/grit
+
+Grit is a Ruby library for extracting information from a Git repository
           

請注意,單單

git diff

不過是顯示還沒有暫存起來的改動,而不是這次工作和上次送出之間的差異。

2.5 送出更新

現在的暫存區域已經準備妥當可以送出了。在此之前,請一定要确認還有什麼修改過的或建立的檔案還沒有

git add

過,否則送出的時候不會記錄這些還沒暫存起來的變化。是以,每次準備送出前,先用

git status

看下,是不是都已暫存起來了,然後再運作送出指令

git commit

$ git commit
           

這種方式會啟動文本編輯器以便輸入本次送出的說明。(預設會啟用 shell 的環境變量

$EDITOR

所指定的軟體,一般都是 vim 或 emacs。當然也可以按照第一章介紹的方式,使用

git config --global core.editor

指令設定你喜歡的編輯軟體。)

編輯器會顯示類似下面的文本資訊(本例選用 Vim 的屏顯方式展示):

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
#       new file:   README
#       modified:   benchmarks.rb
#
~
~
~
".git/COMMIT_EDITMSG" 10L, 283C
           

可以看到,預設的送出消息包含最後一次運作

git status

的輸出,放在注釋行裡,另外開頭還有一空行,供你輸入送出說明。你完全可以去掉這些注釋行,不過留着也沒關系,多少能幫你回想起這次更新的内容有哪些。(如果覺得這還不夠,可以用

-v

選項将修改差異的每一行都包含到注釋中來。)退出編輯器時,Git 會丢掉注釋行,将說明内容和本次更新送出到倉庫。

另外也可以用 -m 參數後跟送出說明的方式,在一行指令中送出更新:

$ git commit -m "Story 182: Fix benchmarks for speed"
[master 463dc4f] Story 182: Fix benchmarks for speed
 2 files changed, 3 insertions(+)
 create mode 100644 README
           

好,現在你已經建立了第一個送出!可以看到,送出後它會告訴你,目前是在哪個分支(master)送出的,本次送出的完整 SHA-1 校驗和是什麼(

463dc4f

),以及在本次送出中,有多少檔案修訂過,多少行添改和删改過。

記住,送出時記錄的是放在暫存區域的快照,任何還未暫存的仍然保持已修改狀态,可以在下次送出時納入版本管理。每一次運作送出操作,都是對你項目作一次快照,以後可以回到這個狀态,或者進行比較。

3. 移除檔案

要從 Git 中移除某個檔案,就必須要從已跟蹤檔案清單中移除(确切地說,是從暫存區域移除),然後送出。可以用

git rm

指令完成此項工作,并連帶從工作目錄中删除指定的檔案。

如果隻是簡單地從工作目錄中手工删除檔案,運作

git status

時就會在 “Changes not staged for commit” 部分(也就是未暫存清單)看到:

$ rm grit.gemspec
$ git status
On branch master
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        deleted:    grit.gemspec

no changes added to commit (use "git add" and/or "git commit -a")
           

然後再運作

git rm

記錄此次移除檔案的操作:

$ git rm grit.gemspec
rm 'grit.gemspec'
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        deleted:    grit.gemspec
           

4. 檔案改名

既然如此,當你看到 Git 的

mv

指令時一定會困惑不已。要在 Git 中對檔案改名,可以這麼做:

$ git mv file_from file_to
           

它會恰如預期般正常工作。實際上,即便此時檢視狀态資訊,也會明白無誤地看到關于重命名操作的說明:

$ git mv README.txt README
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        renamed:    README.txt -> README
           

其實,運作

git mv

就相當于運作了下面三條指令:

$ mv README.txt README
$ git rm README.txt
$ git add README
           

5. 忽略某些檔案(.gitignore)

一般我們總會有些檔案無需納入 Git 的管理,也不希望它們總出現在未跟蹤檔案清單。通常都是些自動生成的檔案,比如日志檔案,或者編譯過程中建立的臨時檔案等。

不需要從頭寫

.gitignore

檔案,GitHub已經為我們準備了各種配置檔案,隻需要組合一下就可以使用了。所有配置檔案可以直接線上浏覽:https://github.com/github/gitignore

在版本管理的根目錄下(與.Git檔案夾同級)建立一個 .gitignore(沒有檔案名,在Windows下需要編寫完文本文檔後另存為,在win10系統下還是文本文檔,隻不過屬性裡能看到是文本文檔(.gitignore檔案)

git基礎(二)——基本操作

檔案

.gitignore

的格式規範如下:

  • 所有空行或者以注釋符号

    開頭的行都會被 Git 忽略。
  • 可以使用标準的 glob 模式比對。
  • 比對模式最後跟反斜杠(

    /

    )說明要忽略的是目錄。
  • 要忽略指定模式以外的檔案或目錄,可以在模式前加上驚歎号(

    !

    )取反。

很簡單吧,被過濾掉的檔案就不會出現在你的GitHub庫中了,當然本地庫中還有,隻是push的時候不會上傳。以及未追蹤時,不會顯示出未追蹤狀态。

git基礎(二)——基本操作

想象一個場景:我們隻需要管理/mtk/目錄中的one.txt檔案,這個目錄中的其他檔案都不需要管理。那麼我們就需要使用:

  • /mtk/
  • !/mtk/one.txt

假設我們隻有過濾規則沒有添加規則,那麼我們就需要把/mtk/目錄下除了one.txt以外的所有檔案都寫出來!

删除了.gitignore檔案後

git基礎(二)——基本操作

之前的a.c檔案又出現了未追蹤狀态。

有些時候,你想添加一個檔案到Git,但發現添加不了,原因是這個檔案被

.gitignore

忽略了:

$ git add App.class
The following paths are ignored by one of your .gitignore files:
App.class
Use -f if you really want to add them.
           

如果你确實想添加該檔案,可以用

-f

強制添加到Git:

$ git add -f App.class
           

或者你發現,可能是

.gitignore

寫得有問題,需要找出來到底哪個規則寫錯了,可以用

git check-ignore

指令檢查:

$ git check-ignore -v App.class
.gitignore:3:*.class	App.class
           

Git會告訴我們,

.gitignore

的第3行規則忽略了該檔案,于是我們就可以知道應該修訂哪個規則。

最後需要強調的一點是,如果你不慎在建立.gitignore檔案之前就push了項目,那麼即使你在.gitignore檔案中寫入新的過濾規則,這些規則也不會起作用,Git仍然會對所有檔案進行版本管理。

簡單來說,出現這種問題的原因就是Git已經開始管理這些檔案了,是以你無法再通過過濾規則過濾它們。

是以大家一定要養成在項目開始就建立.gitignore檔案的習慣,否則一旦push,處理起來會非常麻煩。

.gitignore

檔案本身要放到版本庫裡,并且可以對

.gitignore

做版本管理!

6.檢視送出曆史

在送出了若幹更新之後,又或者克隆了某個項目,想回顧下送出曆史,可以使用

git log

指令檢視。

$ git log
commit 1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master)
Author: Michael Liao <[email protected]>
Date:   Fri May 18 21:06:15 2018 +0800

    append GPL

commit e475afc93c209a690c39c13a46716e8fa000c366
Author: Michael Liao <[email protected]>
Date:   Fri May 18 21:03:36 2018 +0800

    add distributed

commit eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0
Author: Michael Liao <[email protected]>
Date:   Fri May 18 20:59:18 2018 +0800

    wrote a readme file
           

git log

指令顯示從最近到最遠的送出日志,我們可以看到3次送出,最近的一次是

append GPL

,上一次是

add distributed

,最早的一次是

wrote a readme file

每次更新都有一個 SHA-1 校驗和、作者的名字和電子郵件位址、送出時間,最後縮進一個段落顯示送出說明。

下面介紹常用的一些選項:

我們常用

-p

選項展開顯示每次送出的内容差異,用

-2

則僅顯示最近的兩次更新

常用的

--pretty

選項,可以指定使用完全不同于預設格式的方式展示送出曆史。比如用

oneline

将每個送出放在一行顯示,這在送出數很大時非常有用。另外還有

short

full

fuller

可以用,展示的資訊或多或少有些不同

$ git log --pretty=oneline
ca82a6dff817ec66f44342007202690a93763949 changed the version number
085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary test code
a11bef06a3f659402fe7563abf99ad00de2209e6 first commit
           

--stat

,僅顯示簡要的增改行數統計

format

,可以定制要顯示的記錄格式,這樣的輸出便于後期程式設計提取分析,像這樣:

$ git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 11 months ago : changed the version number
085bb3b - Scott Chacon, 11 months ago : removed unnecessary test code
a11bef0 - Scott Chacon, 11 months ago : first commit
           

用 oneline 或 format 時結合

--graph

選項,可以看到開頭多出一些 ASCII 字元串表示的簡單圖形,形象地展示了每個送出所在的分支及其分化衍合情況。在我們之前提到的 Grit 項目倉庫中可以看到:

$ git log --pretty=format:"%h %s" --graph
* 2d3acf9 ignore errors from SIGCHLD on trap
*  5e3ee11 Merge branch 'master' of git://github.com/dustin/grit
|\
| * 420eac9 Added a method for getting the current branch.
* | 30e367c timeout code and tests
* | 5a09431 add timeout protection to grit
* | e1193f8 support for heads with slashes in them
|/
* d6016bc require time for xmlschema
*  11d191e Merge branch 'defunkt' into local
           

7. 撤銷操作

7.1 修改最後一次送出

在本地已有的 commit 資訊上再次送出改動,而不是在已有的 commit 上再新增一個 commit。

使用

git commit --amend

指令可以達到在現有最新 commit 上再次送出改動的效果。

有時候我們送出完了才發現漏掉了幾個檔案沒有加,或者送出資訊寫錯了。想要撤消剛才的送出操作,可以使用

--amend

選項重新送出:

$ git commit --amend
           

此指令将使用目前的暫存區域快照送出。如果剛才送出完沒有作任何改動,直接運作此指令的話,相當于有機會重新編輯送出說明,但将要送出的檔案快照和之前的一樣。

啟動文本編輯器後,會看到上次送出時的說明,編輯它确認沒問題後儲存退出,就會使用新的送出說明覆寫剛才失誤的送出。

如果剛才送出時忘了暫存某些修改,可以先補上暫存操作,然後再運作

--amend

送出:

$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend
           

上面的三條指令最終隻是産生一個送出,第二個送出指令修正了第一個的送出内容。

7.2 取消已經暫存的檔案

情景:檔案add後想要取消暫存

來看下面的例子,有兩個修改過的檔案,我們想要分開送出,但不小心用

git add .

全加到了暫存區域。該如何撤消暫存其中的一個檔案呢?其實,

git status

的指令輸出已經告訴了我們該怎麼做:

$ git add .
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   README.txt
        modified:   benchmarks.rb
           

就在 “Changes to be committed” 下面,括号中有提示,可以使用

git reset HEAD <file>...

的方式取消暫存。好吧,我們來試試取消暫存 benchmarks.rb 檔案:

$ git reset HEAD benchmarks.rb
Unstaged changes after reset:
M       benchmarks.rb
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   README.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   benchmarks.rb
           

現在 benchmarks.rb 檔案又回到了之前已修改未暫存的狀态。把暫存區的修改回退到工作區。

7.3 取消對檔案的修改

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   benchmarks.rb
           

在第二個括号中,我們看到了抛棄檔案修改的指令,讓我們試試看:

$ git checkout -- benchmarks.rb
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   README.txt
           

可以看到,該檔案已經恢複到修改前的版本。

指令

git checkout -- readme.txt

意思就是,把

readme.txt

檔案在工作區的修改全部撤銷,這裡有兩種情況:

  • 一種是

    readme.txt

    自修改後還沒有被放到暫存區,現在,撤銷修改就回到和版本庫一模一樣的狀态;
  • 一種是

    readme.txt

    已經添加到暫存區後,又作了修改,現在,撤銷修改就回到添加到暫存區後的狀态。

總之,就是讓這個檔案回到最近一次

git commit

git add

時的狀态。

8.版本回退

在Git中,我們用

git log

指令檢視:

$ git log
commit 1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master)
Author: Michael Liao <[email protected]>
Date:   Fri May 18 21:06:15 2018 +0800

    append GPL

commit e475afc93c209a690c39c13a46716e8fa000c366
Author: Michael Liao <[email protected]>
Date:   Fri May 18 21:03:36 2018 +0800

    add distributed

commit eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0
Author: Michael Liao <[email protected]>
Date:   Fri May 18 20:59:18 2018 +0800

    wrote a readme file
           

一大串類似

1094adb...

的是

commit id

(版本号也稱SHA-1校驗和),和SVN不一樣,Git的

commit id

不是1,2,3……遞增的數字,而是一個SHA1計算出來的一個非常大的數字,用十六進制表示,而且每個人都不一樣,以你自己的為準。(SHA-1校驗和)為什麼

commit id

需要用這麼一大串數字表示呢?因為Git是分布式的版本控制系統,後面我們還要研究多人在同一個版本庫裡工作,如果大家都用1,2,3……作為版本号,那肯定就沖突了。

首先,Git必須知道目前版本是哪個版本,在Git中,用

HEAD

表示目前版本,也就是最新的送出

1094adb...

(注意我的送出ID和你的肯定不一樣),上一個版本就是

HEAD^

,上上一個版本就是

HEAD^^

,當然往上100個版本寫100個

^

比較容易數不過來,是以寫成

HEAD~100

。HEAD^對應 HEAD~1

實際使用指令時,可以指定版本号或者使用HEAD

執行個體:

–hard 參數撤銷工作區中所有未送出的修改内容,将暫存區與工作區都回到上一次版本,并删除之前的所有資訊送出:

現在,我們要把目前版本

append GPL

回退到上一個版本

add distributed

,就可以使用

git reset

指令:

$ git reset --hard HEAD^
HEAD is now at e475afc add distributed
           

不過且慢,讓我們用

git log

再看看現在版本庫的狀态:

$ git log
commit e475afc93c209a690c39c13a46716e8fa000c366 (HEAD -> master)
Author: Michael Liao <[email protected]>
Date:   Fri May 18 21:03:36 2018 +0800

    add distributed

commit eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0
Author: Michael Liao <[email protected]>
Date:   Fri May 18 20:59:18 2018 +0800

    wrote a readme file
           

最新的那個版本

append GPL

已經看不到了!好比你從21世紀坐時光穿梭機來到了19世紀,想再回去已經回不去了,腫麼辦?

辦法其實還是有的,隻要上面的指令行視窗還沒有被關掉,你就可以順着往上找啊找啊,找到那個

append GPL

commit id

1094adb...

,于是就可以指定回到未來的某個版本:如果之前指令行視窗被關掉的話,就還有一條指令,那就是"git reflog"指令,用于檢視操作記錄。

$ git reflog
aa81e63 (HEAD -> master) [email protected]{0}: reset: moving to aa81e63
526ff66 [email protected]{1}: commit: 5E
866b6de [email protected]{2}: commit: 4D
aa81e63 (HEAD -> master) [email protected]{3}: commit: 3C
2fc70fe [email protected]{4}: commit: 2B
510658e [email protected]{5}: commit (initial): 1A
           

版本号沒必要寫全,前幾位就可以了,Git會自動去找。當然也不能隻寫前一兩位,因為Git可能會找到多個版本号,就無法确定是哪一個了。

git reset 分為三種:軟 --soft,中 —mixed,硬 --hard 對應着三種復原的程度,程度越硬,復原的越“狠”
  1. –soft 已 add,但尚未 commit
  2. –mixed(git reset 的預設設定,可以省略不寫),檔案會回退到未 add(未暫存)的狀态
  3. –hard 硬核,徹底,會徹底傳回到回退前的版本狀态,了無痕迹