git操作之三:git reset

迷茫中守候發表於2020-11-22

在上篇文章中介紹了git restore命令,該命令的可以看作是撤銷命令,檔案在不同的狀態下,使用git restore <file> 命令,會撤銷對檔案的修改,是檔案回到修改前的狀態也就是暫存區或者原生程式碼區,而使用git restore --staged <file>命令,則是使檔案從暫存區回到工作區,且保留檔案的修改。那麼如果使檔案從原生程式碼區移除那,或者說如何撤銷已commit的檔案那。

一、概述

通過前邊的介紹,瞭解到使用git commit -m "提交說明" <file>可以把檔案提交到原生程式碼庫,如果是誤提交,要把提交的檔案撤回要使用git reset 命令。

二、詳述

命令格式如下,

git reset [--hard | --mixed | --soft] HEAD^

git reset --hard

命令如下,

git reset --hard HEAD^/git reset --hard HEAD~1 其中HEAD^指的是後退一次提交,同理HEAD^^後退兩次提交;HEAD~1 後退一次提交,HEAD~2 後退兩次提交;

現在看下我的提交記錄,

那麼現在我執行下git reset --hard HEAD^命令,再看提交記錄

從上圖可以看到提交記錄回到了上個版本,那麼此刻檔案的內容也發生變化。

現在又這樣一種情況,如果在MyFirst.java、MyFirst2.java均提交的情況下,修改MyFirst.java、MyFirst2.java,然後把MyFirst2.java執行git add命令後再執行git reset --hard HEAD^命令後兩個檔案會發生什麼變化,

現在兩個檔案的內容如下,

package cn.com.my;

public class MyFirst {
    public static void main(String[] args) {
        System.out.println("a");


    }

}
package cn.com.my;

public class MyFirst2 {
    public static void main(String[] args) {
        System.out.println("b");
    }
}

再看下現在git的狀態,

現在對MyFirst.java進行修改,但不執行git add 命令

package cn.com.my;

public class MyFirst {
    public static void main(String[] args) {
        System.out.println("a");
        System.out.println("修改未追蹤");


    }

}

對MyFirst2.java,執行git add命令

package cn.com.my;

public class MyFirst2 {
    public static void main(String[] args) {
        System.out.println("b");
        System.out.println("修改且追蹤");
    }
}

現在看下git的狀態,

現在執行git reset --hard HEAD~1命令,兩個檔案的內容如下,

package cn.com.my;

public class MyFirst {
    public static void main(String[] args) {
        System.out.println("a");
        System.out.println("提交後修改");

    }

}
package cn.com.my;

public class MyFirst2 {
    public static void main(String[] args) {
        
    }
}

對比下上面的檔案,發現和上邊的修改後的也不一樣,這說明,git reset --hard HEAD~1 命令會回退到上個版本,中間做的修改會被撤銷,包括在工作區中的修改和已放入暫存區的修改都會被撤銷。

git reset --soft

現在看下git的狀態,

可以看到沒有待提交的檔案也就是沒有在暫存區的檔案,現在修改MyFirst.java、修改MyFirst2.java並加入到暫存區,看下當前的狀態,

可以看到MyFirst2.java在暫存區中等待commit,而MyFirst.java在工作區中未被追蹤,看下兩個檔案的內容,

package cn.com.my;

public class MyFirst {
    public static void main(String[] args) {
        System.out.println("a");
        System.out.println("提交後修改");
        System.out.println("MyFirst,2020-11-22");
        System.out.println("MyFirst,2020-11-22-2");

    }

}
package cn.com.my;

public class MyFirst2 {
    public static void main(String[] args) {
        System.out.println("MyFirst2,2020-11-22");
        System.out.println("MyFirst2,2020-11-22-2");
    }
}

下面執行git reset --soft HEAD~1命令,並檢視git的狀態,

可以看到在暫存區有MyFirst.java、MyFirst2.java兩個檔案,在工作區有MyFirst.java,在工作區有MyFirst.java可以理解,因為該檔案被修改過未執行git add命令,回退和這個沒關係。那麼為什麼MyFirst.java還會出現在暫存區那,因為git reset --soft HEAD~1命令,該命令會讓版本回退一個版本,且在工作區和暫存區的檔案不會發生改變,但是會把回退前的版本和回退後版本的差異放到暫存區,那麼就好理解了,從MyFirst2.java說起,在回退前該檔案做了修改並提交到了暫存區,回退後肯定也在暫存區,MyFirst.java在回退前進行了修改,但是沒有儲存到暫存區,在回退後,MyFirst.java回退到了上個版本,回退前和回退後會兩個版本會有差異,這個差異在回退後被放到了暫存區,所以在暫存區肯定會出現MyFirst.java,為什麼會有未追蹤的MyFirst.java,因為回退前對其進行了修改未追蹤該檔案。

git reset --mixed/git reset 

下面看最後一個引數--mixed或者說預設的引數

演示環境仍是下面的環境,對MyFirst.java進行修改且不追蹤,對MyFirst2.java進行修改且新增到暫存區,

檔案的內容如下,

package cn.com.my;

public class MyFirst {
    public static void main(String[] args) {
        System.out.println("a");
        System.out.println("提交後修改");
        System.out.println("MyFirst,2020-11-22");
        System.out.println("MyFirst,2020-11-22-2");
        System.out.println("MyFirst,2020-11-22-3");

    }

}
package cn.com.my;

public class MyFirst2 {
    public static void main(String[] args) {
        System.out.println("MyFirst2,2020-11-22");
        System.out.println("MyFirst2,2020-11-22-2");
        System.out.println("MyFirst2,2020-11-22-3");
    }
}

下面執行git reset --mixed HEAD~1/git reset HEAD~1,檢視git的狀態

可以看到MyFirst.java和MyFirst2.java均未追蹤,再看下檔案的內容,

package cn.com.my;

public class MyFirst {
    public static void main(String[] args) {
        System.out.println("a");
        System.out.println("提交後修改");
        System.out.println("MyFirst,2020-11-22");
        System.out.println("MyFirst,2020-11-22-2");
        System.out.println("MyFirst,2020-11-22-3");

    }

}
package cn.com.my;

public class MyFirst2 {
    public static void main(String[] args) {
        System.out.println("MyFirst2,2020-11-22");
        System.out.println("MyFirst2,2020-11-22-2");
        System.out.println("MyFirst2,2020-11-22-3");
    }
}

可以看到檔案的內容和執行git reset HEAD~1前沒有改變,git reset HEAD~1命令不會改變檔案的內容,但在reset前所做的修改在reset後都會反應在工作區,具體表現未MyFirst2.java在reset前在暫存區,但reset後在工作區。

三、總結

git reset [--hard | --soft | --mixed] HEAD^命令總結如下,

git reset --hard HEAD^  會撤銷版本V-1到版本V間的修改,直接回退到版本V-1,無論所做的修改是否被追蹤;

git reset --soft HEAD^  在版本V-1到版本V間的修改均被保留,如一個檔案已提交到暫存區,在回退後仍在暫存區;如一個檔案在工作區,在回退後該檔案修改前的內容在暫存區,修改後的內容仍在工作區;這時如果執行git commit -m <file> 命令,在暫存區的都會被commit(包括在後退前追蹤的暫存區的內容);

git reset --mixed HEAD^ 在版本V-1到版本V間的修改均被保留,所有檔案都在工作區,需重新被追蹤;

下面是三張示意圖,

 

 

 

 

 

 

有不正之處,歡迎指正,謝謝!

 

相關文章