# git-reset
> 原文: [https://git-scm.com/docs/git-reset](https://git-scm.com/docs/git-reset)
## 名稱
git-reset - 將當前HEAD重置為指定狀態
## 概要
```
git reset [-q] [<tree-ish>] [--] <paths>…?
git reset (--patch | -p) [<tree-ish>] [--] [<paths>…?]
git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
```
## 描述
在第一種和第二種形式中,將條目從`<tree-ish>`復制到索引。在第三種形式中,將當前分支頭(`HEAD`)設置為`<commit>`,可選擇修改索引和工作樹以匹配。所有形式的`<tree-ish>` / `<commit>`默認為`HEAD`。
```
git reset [-q] [<tree-ish>] [--] <paths>…?
```
此表單將所有`<paths>`的索引條目重置為`<tree-ish>`的狀態。(它不會影響工作樹或當前分支。)
這意味著`git reset <paths>`與`git add <paths>`相反。
運行`git reset <paths>`更新索引條目后,可以使用 [git-checkout [1]](https://git-scm.com/docs/git-checkout) 檢查工作樹索引中的內容。或者,使用 [git-checkout [1]](https://git-scm.com/docs/git-checkout) 并指定提交,您可以一次性將提交中的路徑內容復制到索引和工作樹。
```
git reset (--patch | -p) [<tree-ish>] [--] [<paths>…?]
```
在索引和`<tree-ish>`(默認為`HEAD`)之間的差異中交互式選擇某塊。選擇的塊與索引相反。
這意味著`git reset -p`與`git add -p`相反,即您可以使用它來選擇性地重置代碼塊。請參閱 [git-add [1]](https://git-scm.com/docs/git-add) 的“交互模式”部分,了解如何操作`--patch`模式。
```
git reset [<mode>] [<commit>]
```
此表單將當前分支頭重置為`<commit>`,并可能根據`<mode>`更新索引(將其重置為`<commit>`的樹)和工作樹。如果省略`<mode>`,則默認為`--mixed`。 `<mode>`必須是以下之一:
```
--soft
```
根本不接觸索引文件或工作樹(但將頭節點重置為`<commit>`,就像所有模式一樣)。這將保留所有已更改的文件“要提交的更改”,如`git status`所示。
```
--mixed
```
重置索引但不重置工作樹(即,保留更改的文件但未標記為提交)并報告尚未更新的內容。這是默認操作。
如果指定了`-N`,則刪除的路徑將標記為意圖添加(請參閱 [git-add [1]](https://git-scm.com/docs/git-add) )。
```
--hard
```
重置索引和工作樹。自`<commit>`以來對工作樹中跟蹤文件的任何更改都將被丟棄。
```
--merge
```
重置索引并更新工作樹中`<commit>`和`HEAD`之間不同的文件,但保留索引和工作樹之間不同的文件(即具有尚未添加的更改)。如果`<commit>`和索引之間不同的文件具有未暫存更改,則重置將中止。
換句話說,`--merge`執行類似`git read-tree -u -m <commit>`的操作,但會繼承未合并的索引條目。
```
--keep
```
重置索引條目并更新工作樹中`<commit>`和`HEAD`之間不同的文件。如果`<commit>`和`HEAD`之間不同的文件具有本地更改,則重置將中止。
如果你想撤消除分支上最新的提交, [git-revert [1]](https://git-scm.com/docs/git-revert) 是你的朋友。
## 選項
```
-q
```
```
--quiet
```
```
--no-quiet
```
保持安靜,只報告錯誤。默認行為由`reset.quiet`配置選項設置。 `--quiet`和`--no-quiet`將覆蓋默認行為。
## 例子
```
Undo add
```
```
$ edit (1)
$ git add frotz.c filfre.c
$ mailx (2)
$ git reset (3)
$ git pull git://info.example.com/ nitfol (4)
```
1. 您正在愉快地處理某些事情,并發現這些文件中的更改處于良好狀態。當您運行`git diff`時,您不希望看到它們,因為您計劃處理其他文件,并且使用這些文件進行更改會分散注意力。
2. 有人要求你拉更新,這些變化聽起來值得合并。
3. 但是,您已經弄臟了索引(即您的索引與`HEAD`提交不匹配)。但是你知道你要做的更新不會影響`frotz.c`或`filfre.c`,所以你還原這兩個文件的索引變化。您在工作樹中的更改仍然存在。
4. 然后你可以更新和合并,在工作樹中仍然保留`frotz.c`和`filfre.c`。
```
Undo a commit and redo
```
```
$ git commit ...
$ git reset --soft HEAD^ (1)
$ edit (2)
$ git commit -a -c ORIG_HEAD (3)
```
1. 當您記得剛剛提交的內容不完整,或者拼錯了提交消息,或者兩者兼而有之時,通常會這樣做。在“重置”之前留下工作樹。
2. 對工作樹文件進行更正。
3. “重置”將舊頭復制到`.git/ORIG_HEAD`;通過從其日志消息開始重做提交。如果您不需要進一步編輯消息,則可以改為使用`-C`選項。
另請參見 [git-commit [1]](https://git-scm.com/docs/git-commit) 的`--amend`選項。
```
Undo a commit, making it a topic branch
```
```
$ git branch topic/wip (1)
$ git reset --hard HEAD~3 (2)
$ git checkout topic/wip (3)
```
1. 你做了一些提交,但意識到他們在`master`分支中還為時過早。您想在主題分支中繼續拋光它們,因此從當前`HEAD`創建`topic/wip`分支。
2. 倒回master分支以擺脫這三個提交。
3. 切換到`topic/wip`分支并繼續工作。
```
Undo commits permanently
```
```
$ git commit ...
$ git reset --hard HEAD~3 (1)
```
1. 最后三次提交(`HEAD`,`HEAD^`和`HEAD~2`)很糟糕,你不想再看到它們。如果你已經將這些提交給了其他人,那么**不要**這樣做。 (有關這樣做的含義,請參閱 [git-rebase [1]](https://git-scm.com/docs/git-rebase) 中的“從上游返回的恢復”部分。)
```
Undo a merge or pull
```
```
$ git pull (1)
Auto-merging nitfol
CONFLICT (content): Merge conflict in nitfol
Automatic merge failed; fix conflicts and then commit the result.
$ git reset --hard (2)
$ git pull . topic/branch (3)
Updating from 41223... to 13134...
Fast-forward
$ git reset --hard ORIG_HEAD (4)
```
1. 嘗試從上游更新導致了很多沖突;你現在還沒有準備好花很多時間合并,所以你決定稍后再這樣做。
2. “pull”沒有進行合并提交,因此作為`git reset --hard HEAD`同義詞的`git reset --hard`清除了索引文件和工作樹中的混亂。
3. 將主題分支合并到當前分支,這導致快進。
4. 但是你決定主題分支尚未準備好供公眾使用。 “pull”或“merge”總是在`ORIG_HEAD`中保留當前分支的原始提示,因此重新設置它會使您的索引文件和工作樹返回到該狀態,并將分支的提示重置為該提交。
```
Undo a merge or pull inside a dirty working tree
```
```
$ git pull (1)
Auto-merging nitfol
Merge made by recursive.
nitfol | 20 +++++----
...
$ git reset --merge ORIG_HEAD (2)
```
1. 即使您可能在工作樹中進行了本地修改,當您知道另一個分支中的更改與它們不重疊時,您也可以安全地說出`git pull`。
2. 檢查合并結果后,您可能會發現另一個分支的更改不能令人滿意。運行`git reset --hard ORIG_HEAD`將讓您回到原來的位置,但它會丟棄您不想要的本地更改。 `git reset --merge`保留您的本地更改。
```
Interrupted workflow
```
假設您在進行大量更改時被緊急修復請求打斷。工作樹中的文件尚未提交任何形狀,但您需要到另一個分支進行快速修復。
```
$ git checkout feature ;# you were working in "feature" branch and
$ work work work ;# got interrupted
$ git commit -a -m "snapshot WIP" (1)
$ git checkout master
$ fix fix fix
$ git commit ;# commit with real log
$ git checkout feature
$ git reset --soft HEAD^ ;# go back to WIP state (2)
$ git reset (3)
```
1. 這個提交將被吹走,所以扔掉日志消息就可以了。
2. 這將從提交歷史記錄中刪除 _WIP_ 提交,并將工作樹設置為創建快照之前的狀態。
3. 此時,索引文件仍然包含您作為 _快照WIP_ 提交的所有WIP更改。這將更新索引以將您的WIP文件顯示為未提交。
另見 [git-stash [1]](https://git-scm.com/docs/git-stash) 。
```
Reset a single file in the index
```
假設您已將文件添加到索引中,但后來決定不想將其添加到提交中。您可以從索引中刪除文件,同時使用git reset保留更改。
```
$ git reset -- frotz.c (1)
$ git commit -m "Commit files in index" (2)
$ git add frotz.c (3)
```
1. 這會將文件從索引中刪除,同時將其保留在工作目錄中。
2. 這將提交索引中的所有其他更改。
3. 再次將文件添加到索引。
```
Keep changes in working tree while discarding some previous commits
```
假設您正在處理某些事情并且提交它,然后您繼續工作,但現在您認為您工作樹中的內容應該位于與您之前提交的內容無關的另一個分支中。您可以啟動新分支并重置它,同時保持工作樹中的更改。
```
$ git tag start
$ git checkout -b branch1
$ edit
$ git commit ... (1)
$ edit
$ git checkout -b branch2 (2)
$ git reset --keep start (3)
```
1. 這將在`branch1`中提交您的第一次編輯。
2. 在理想世界中,您可能已經意識到,當您創建并切換到`branch2`(即`git checkout -b branch2 start`)時,較早的提交不屬于新主題,但沒有人是完美的。
3. 但是,切換到`branch2`后,可以使用`reset --keep`刪除不需要的提交。
```
Split a commit apart into a sequence of commits
```
假設您已經創建了許多邏輯上獨立的更改并將它們一起提交。然后,稍后您決定讓每個邏輯塊與其自己的提交相關聯可能更好。您可以使用git reset來回滾歷史記錄而不更改本地文件的內容,然后使用`git add -p`以交互方式選擇要包含在每個提交中的數據庫,使用`git commit -c`預先填充提交消息。
```
$ git reset -N HEAD^ (1)
$ git add -p (2)
$ git diff --cached (3)
$ git commit -c HEAD@{1} (4)
... (5)
$ git add ... (6)
$ git diff --cached (7)
$ git commit ... (8)
```
1. 首先,將歷史記錄重置為一次提交,以便我們刪除原始提交,但保留工作樹中的所有更改。 -N確保添加`HEAD`的任何新文件仍然被標記,以便`git add -p`找到它們。
2. 接下來,我們使用`git add -p`工具以交互方式選擇要添加的差異。這將按順序詢問每個差異塊,您可以使用簡單的命令,例如“是,包括此”,“不包括此”,甚至是非常強大的“編輯”工具。
3. 一旦對您想要包含的代碼塊感到滿意,您應該使用`git diff --cached`為第一次提交準備的內容驗證。這顯示了已移入索引并即將提交的所有更改。
4. 接下來,提交存儲在索引中的更改。 `-c`選項指定從第一次提交中啟動的原始消息預填充提交消息。這有助于避免重新輸入。 `HEAD@{1}`是`HEAD`曾經在原始重置提交之前進行的提交的特殊表示法(1更改前)。有關詳細信息,請參閱 [git-reflog [1]](https://git-scm.com/docs/git-reflog) 。您還可以使用任何其他有效的提交引用。
5. 您可以多次重復步驟2-4,將原始代碼分解為任意數量的提交。
6. 現在,您已將許多更改拆分為自己的提交,并且可能不再使用`git add`的修補程序模式,以便選擇所有剩余的未提交更改。
7. 再次檢查以確認您已包含所需內容。您可能還希望驗證git diff不會顯示稍后要提交的任何剩余更改。
8. 最后創建最終提交。
## 討論
下表顯示了運行時會發生什么:
```
git reset --option target
```
根據文件的狀態,使用不同的重置選項將`HEAD`重置為另一個提交(`target`)。
在這些表中,`A`,`B`,`C`和`D`是文件的某些不同狀態。例如,第一個表的第一行表示如果文件在工作樹中處于狀態`A`,在索引中處于狀態`B`,在`HEAD`上是狀態`C`,在目標節點中是狀態`D`,`git reset --soft target`將文件保留在狀態`A`的工作樹中和狀態`B`的索引中。它將`HEAD`(即當前分支的尖端,如果你在其中)重置(即移動)到`target`(其文件處于狀態`D`)。
```
working index HEAD target working index HEAD
----------------------------------------------------
A B C D --soft A B D
--mixed A D D
--hard D D D
--merge (disallowed)
--keep (disallowed)
```
```
working index HEAD target working index HEAD
----------------------------------------------------
A B C C --soft A B C
--mixed A C C
--hard C C C
--merge (disallowed)
--keep A C C
```
```
working index HEAD target working index HEAD
----------------------------------------------------
B B C D --soft B B D
--mixed B D D
--hard D D D
--merge D D D
--keep (disallowed)
```
```
working index HEAD target working index HEAD
----------------------------------------------------
B B C C --soft B B C
--mixed B C C
--hard C C C
--merge C C C
--keep B C C
```
```
working index HEAD target working index HEAD
----------------------------------------------------
B C C D --soft B C D
--mixed B D D
--hard D D D
--merge (disallowed)
--keep (disallowed)
```
```
working index HEAD target working index HEAD
----------------------------------------------------
B C C C --soft B C C
--mixed B C C
--hard C C C
--merge B C C
--keep B C C
```
`reset --merge`用于在重置合并沖突時使用。任何mergy操作都應保證在工作樹中涉及的合的文件,在開始合并之前,本地索引沒有相應更改,并且它將合并結果寫入工作樹中。因此,如果我們看到索引和目標之間以及索引和工作樹之間存在某些差異,那么這意味著當由于沖突導致合并失敗后,我們不能通過reset操作將狀態重置出來。這就是我們在這種情況下不允許`--merge`選項的原因。
在保留當前分支中的一些最后提交的同時保留工作樹中的更改時,將使用`reset --keep`。如果我們要刪除的提交中的更改與我們要保留的工作樹中的更改之間可能存在沖突,則不允許重置。如果工作樹和`HEAD`之間以及`HEAD`和目標之間存在變化,那么就不允許這樣做。為了安全起見,當有未合并的條目時也不允許這樣做。
下表顯示了存在未合并條目時會發生什么:
```
working index HEAD target working index HEAD
----------------------------------------------------
X U A B --soft (disallowed)
--mixed X B B
--hard B B B
--merge B B B
--keep (disallowed)
```
```
working index HEAD target working index HEAD
----------------------------------------------------
X U A A --soft (disallowed)
--mixed X A A
--hard A A A
--merge A A A
--keep (disallowed)
```
`X`表示任何狀態,`U`表示未合并的索引。
## GIT
部分 [git [1]](https://git-scm.com/docs/git) 套件
- git
- git-config
- git-help
- git-init
- git-clone
- git-add
- git-status
- git-diff
- git-commit
- git-reset
- git-rm
- git-mv
- git-branch
- git-checkout
- git-merge
- git-mergetool
- git-log
- git-stash
- git-tag
- git-worktree
- git-fetch
- git-pull
- git-push
- git-remote
- git-submodule
- git-show
- git-log
- git-shortlog
- git-describe
- git-apply
- git-cherry-pick
- git-rebase
- git-revert
- git-bisect
- git-blame
- git-grep
- gitattributes
- giteveryday
- gitglossary
- githooks
- gitignore
- gitmodules
- gitrevisions
- gittutorial
- gitworkflows
- git-am
- git-format-patch
- git-send-email
- git-request-pull
- git-svn
- git-fast-import
- git-clean
- git-gc
- git-fsck
- git-reflog
- git-filter-branch
- git-instaweb
- git-archive
- git-bundle
- git-daemon
- git-update-server-info
- git-cat-file
- git-check-ignore
- git-checkout-index
- git-commit-tree
- git-count-objects
- git-diff-index
- git-for-each-ref
- git-hash-object
- git-ls-files
- git-merge-base
- git-read-tree
- git-rev-list
- git-rev-parse
- git-show-ref
- git-symbolic-ref
- git-update-index
- git-update-ref
- git-verify-pack
- git-write-tree