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間的修改均被保留,所有文件都在工作區,需重新被追蹤;

下面是三張示意圖,

 

 

 

 

 

 

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