精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

在 Git 中撤消更改的六種方法!

開發(fā) 前端
本文將介紹 Git 中常用的 6 種撤消更改的方法,幫助你更好地處理這些問題!

當(dāng)使用 Git 進(jìn)行項目代碼管理時,難免會出現(xiàn)一些錯誤操作或需求變更,需要對代碼進(jìn)行撤銷或修改。Git 提供了多種方式來撤消已有的更改。本文將介紹 Git 中常用的 6 種撤消更改的方法,幫助你更好地處理這些問題!

在開始示例之前,先來創(chuàng)建一個簡單的 Git 倉庫,其中包含于一些提交:

git init && \
echo {} > package.json && git add . && git commit -m "Add package.json" && \
echo FOO=bar > .env && git add . && git commit -m "Add .env" && \
touch README.md && git add . && git commit -m "Add README" && \
touch .gitignore && git add . && git commit -m "Add .gitignore"

對于這些命令,實際上包含以下歷史操作:

* 4753e23 - (HEAD -> master) Add .gitignore (4 seconds ago) <AleksandrHovhannisyan>
* 893d18d - Add README (4 seconds ago) <AleksandrHovhannisyan>
* 2beb7c7 - Add .env (4 seconds ago) <AleksandrHovhannisyan>
* 0beebfb - Add package.json (5 seconds ago) <AleksandrHovhannisyan>

1、修改最近的提交

在創(chuàng)建并提交了 .gitignore 文件后不久,決定修改這個文件:

echo node_modules > .gitignore

但不想在 git 日志歷史記錄中添加一個對于如此微小更改的提交記錄。或者需要在最近的提交消息中糾正一個拼寫錯誤。

這兩種情況都是使用 git amend 命令的經(jīng)典用例:

git commit -a --amend

簡單來說,git amend 命令用于在 git 中編輯 commit 和提交消息。這是 git 中撤銷更改的最基本方式之一。

當(dāng)運(yùn)行上述代碼時,git 會打開選擇的編輯器并顯示最近的提交,在其中加入更改以進(jìn)入暫存環(huán)境:

Add .gitignore

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Sun Oct 11 08:25:58 2022 -0400
#
# On branch master
# Changes to be committed:
#       new file:   .gitignore
#

保存并關(guān)閉文件,git 將修改最近的提交以包括新更改。也可以在保存文件之前編輯提交消息。

如果要做的只是更新提交消息本身,例如修正一個拼寫錯誤,那實際上并不需要進(jìn)入暫存環(huán)境。只需要運(yùn)行這個命令:

git commit --amend

在編輯器中更改提交消息并保存文件,關(guān)閉即可。

在修改了最近的提交后,日志將會看起來像這樣:

* 7598875 - (HEAD -> master) Add .gitignore (31 seconds ago) <AleksandrHovhannisyan>
* 893d18d - Add README (79 seconds ago) <AleksandrHovhannisyan>
* 2beb7c7 - Add .env (79 seconds ago) <AleksandrHovhannisyan>
* 0beebfb - Add package.json (80 seconds ago) <AleksandrHovhannisyan>

現(xiàn)在,假設(shè)修改之前已經(jīng)將舊提交推送到了遠(yuǎn)程分支。如果運(yùn)行 git status,就會被告知本地分支和遠(yuǎn)程分支有一個提交不同:

On branch master
Your branch and 'origin/master' have diverged,
and have 1 and 1 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)

這也是正常的,因為遠(yuǎn)程分支有舊的提交,而本地分支有修改過的提交。它們的哈希值不同,因為修改提交會更改其時間戳,這會強(qiáng)制 git 計算新的哈希值。要想用新的提交更新遠(yuǎn)程分支,就需要強(qiáng)制推送它:git push -f。這將用本地分支覆蓋遠(yuǎn)程分支的歷史記錄。

需要注意,這里我們是在自己分支上進(jìn)行的強(qiáng)制推送,在實際工作中,我們不應(yīng)該強(qiáng)制推送到公共分支;如果這樣做,每個人的本地 master 副本都將與遠(yuǎn)程副本不同,并且任何基于舊 master 的新功能現(xiàn)在都將具有不兼容的提交歷史記錄。

2、將分支重置為較舊的提交

目前為止,我們有如下提交歷史:

* 7598875 - (HEAD -> master) Add .gitignore (31 seconds ago) <AleksandrHovhannisyan>
* 893d18d - Add README (79 seconds ago) <AleksandrHovhannisyan>
* 2beb7c7 - Add .env (79 seconds ago) <AleksandrHovhannisyan>
* 0beebfb - Add package.json (80 seconds ago) <AleksandrHovhannisyan>

我們再來向 master 添加一個提交:

touch file && git add . && git commit -m "Add a file"

現(xiàn)在提交歷史變成了這樣:

* b494f6f - (HEAD -> master) Add a file (5 seconds ago) <AleksandrHovhannisyan>
* 7598875 - Add .gitignore (3 minutes ago) <AleksandrHovhannisyan>
* 893d18d - Add README (4 minutes ago) <AleksandrHovhannisyan>
* 2beb7c7 - Add .env (4 minutes ago) <AleksandrHovhannisyan>
* 0beebfb - Add package.json (4 minutes ago) <AleksandrHovhannisyan>

幾分鐘后,出于某種原因,我們決定不再保留最近的提交。要想刪除它,只需在 HEAD 指針之前硬重置一次提交,該指針始終指向當(dāng)前分支上的最新提交:

git reset --hard HEAD~1

波浪號 (~) 后跟一個數(shù)字告訴 git 它應(yīng)該從給定的提交(在本例中為 HEAD 指針)回溯多少次提交。由于 HEAD 總是指向當(dāng)前分支上的最新提交,這告訴 git 對最近提交之前的提交進(jìn)行硬重置。

輸出結(jié)果如下:

HEAD is now at 7598875 Add .gitignore

硬重置是撤消 git 更改的一個便捷方法,但這是一個破壞性過程——該提交中的所有更改都將丟失,找回它們的唯一方法是通過 git reflog命令(后面會詳細(xì)介紹)。

我們還可以重置為 HEAD~nth 提交,在這種情況下,該提交期間和之后的所有工作都將丟失:

git reset --hard HEAD~4

或者甚至是特定的提交,如果有它的哈希:

git reset --hard <hash-id>

當(dāng)然也不限于僅針對當(dāng)前分支中的提交進(jìn)行重置,還可以重置本地分支以指向另一個本地分支:

git reset --hard <someOtherBranch>

甚至到遠(yuǎn)程分支:

git reset --hard origin/master

這個就很有用,例如,如果不小心將內(nèi)容提交到本地 master 分支。假設(shè)應(yīng)該在一個 feat/X 分支上進(jìn)行提交,但忘記了創(chuàng)建它,而且一直在向本地 master 提交代碼。

當(dāng)然,我們也可以使用 git cherry-pick 來解決這個問題,但是如果有很多次提交怎么辦?這有點痛苦,而 reset 可以輕松搞定。

要解決此問題,現(xiàn)在需要創(chuàng)建功能分支:

git checkout -b feat/X

并強(qiáng)行將本地 master 分支重置為遠(yuǎn)程 master 分支:

git checkout master && git reset --hard origin/master

并且不要忘記回到功能分支,這樣就不會重復(fù)同樣的錯誤:

git checkout feat/X

軟重置分支

正如上面提到的,如果進(jìn)行硬重置,將丟失在該提交時或之后所做的所有工作。當(dāng)然,可以從那個狀態(tài)中恢復(fù)過來,但需要額外的操作。相反,如果想在 git 的暫存環(huán)境中保留更改,可以進(jìn)行軟重置:

git reset --soft HEAD~1

同樣,可以只使用提交哈希而不是從 HEAD 指針回溯:

git reset --soft a80951b

該提交引入的所有更改以及它之后的任何提交都將出現(xiàn)在 git 的暫存環(huán)境中。在這里,可以使用 git reset HEAD file(s) 取消暫存文件,對已經(jīng)暫存的文件進(jìn)行所需的任何更改。然后,可以根據(jù)需要進(jìn)行任何新的提交。

用例:在一個提交中提交了文件 A 和文件 B,但后來意識到它們實際上應(yīng)該是兩個獨立的提交。可以執(zhí)行軟重置并選擇性地提交一個文件,然后單獨進(jìn)行另一個提交,所有這些操作都不會丟失任何工作內(nèi)容。

創(chuàng)建備份分支

我們可以將分支用作備份機(jī)制,以防你知道即將運(yùn)行的某個命令(例如 git reset --hard)可能會損壞分支的提交歷史記錄。在運(yùn)行這些命令之前,可以簡單地創(chuàng)建一個臨時備份分支(例如 git branch backup)。如果出現(xiàn)任何問題,就可以針對備份分支執(zhí)行硬重置操作:

git reset --hard backup

3、交互式變基

Git 的交互式變基是其最強(qiáng)大、最靈活的命令之一,允許倒回歷史并進(jìn)行任何所需的更改。如果想要刪除舊的提交、更改舊的提交消息或者將舊的提交壓縮成其他的提交,那么這就是你需要使用的命令。所有交互式變基都始于 git rebase -i 命令,并且必須指定一個提交來重新設(shè)置當(dāng)前分支。

刪除舊提交

目前為止,我們有如下提交歷史:

* 7598875 - (HEAD -> master) Add .gitignore (20 minutes ago) <AleksandrHovhannisyan>
* 893d18d - Add README (21 minutes ago) <AleksandrHovhannisyan>
* 2beb7c7 - Add .env (21 minutes ago) <AleksandrHovhannisyan>
* 0beebfb - Add package.json (21 minutes ago) <AleksandrHovhannisyan>

第二次提交看起來有點可疑,為什么要將本地環(huán)境變量 (.env) 檢查到 git 中? 顯然,我們需要刪除此提交,同時保留所有其他提交。為此,我們將針對該提交運(yùn)行交互式變基:

git rebase -ir 2beb7c7^

這將調(diào)出這個編輯器:

pick 2beb7c7 Add .env
pick 893d18d Add README
pick 7598875 Add .gitignore

要刪除 2beb7c7,需要將 pick 命令更改為 drop(或 d)并保持其他不變:

drop 2beb7c7 Add .env
pick 893d18d Add README
pick 7598875 Add .gitignore

現(xiàn)在關(guān)閉并保存文件,會得到如下確認(rèn):

Successfully rebased and updated refs/heads/master.

現(xiàn)在,如果執(zhí)行 git log,將不再看到該提交:

* 11221d4 - (HEAD -> master) Add .gitignore (6 seconds ago) <AleksandrHovhannisyan>
* 9ed001a - Add README (6 seconds ago) <AleksandrHovhannisyan>
* 0beebfb - Add package.json (50 minutes ago) <AleksandrHovhannisyan>

注意,在已刪除提交之后的所有提交哈希都將被重新計算。因此,雖然根提交仍保持為 0beebfb,但在它之后的所有哈希值都已更改。正如現(xiàn)在已經(jīng)看到幾次,如果之前將此分支推送到了遠(yuǎn)程倉庫中,那么本地分支和遠(yuǎn)程分支現(xiàn)在將不同步。因此,只需要進(jìn)行一次強(qiáng)制推送即可更新遠(yuǎn)程分支:

git push -f

改寫提交消息

我們再來添加兩個提交,提交消息是隨便寫的:

* 094f8cb - (HEAD -> master) Do more stuff (1 second ago) <AleksandrHovhannisyan>
* 74dab36 - Do something idk (59 seconds ago) <AleksandrHovhannisyan>
* 11221d4 - Add .gitignore (3 minutes ago) <AleksandrHovhannisyan>
* 9ed001a - Add README (3 minutes ago) <AleksandrHovhannisyan>
* 0beebfb - Add package.json (53 minutes ago) <AleksandrHovhannisyan>

現(xiàn)在想修改這兩個提交消息。我們將從交互式變基開始。在這里,我們將針對最后兩個提交:

git rebase -i HEAD~2

這將打開編輯器:

pick 74dab36 Do something idk
pick 094f8cb Do more stuff

現(xiàn)在,只需將任何要更改其消息的提交的 pick 替換為 r(或 reword):

reword 74dab36 Do something idk
reword 094f8cb Do more stuff

關(guān)閉并保存文件,對于想要改寫的每個提交,git 將打開編輯器,就像正在修改該提交一樣,允許編輯消息。

也許在第一次提交時這樣做:

Update README with getting started instructions

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Sun Oct 11 09:17:41 2022 -0400
#
# interactive rebase in progress; onto 11221d4
# Last command done (1 command done):
#    reword 74dab36 Do something idk
# Next command to do (1 remaining command):
#    reword 094f8cb Do more stuff
# You are currently editing a commit while rebasing branch 'master' on '11221d4'.
#
# Changes to be committed:
#       modified:   README.md
#

第二次這樣做:

Add name and author to package.json

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# interactive rebase in progress; onto 11221d4
# Last commands done (2 commands done):
#    reword 74dab36 Do something idk
#    reword 094f8cb Do more stuff
# No commands remaining.
# You are currently rebasing branch 'master' on '11221d4'.
#
# Changes to be committed:
#       modified:   package.json
#

我們會得到以下輸出確認(rèn):

[detached HEAD 665034d] Update README with getting started instructions
 Date: Sun Oct 11 09:17:41 2020 -0400
 1 file changed, 5 insertions(+)
[detached HEAD ba88fb0] Add name and author to package.json
 1 file changed, 4 insertions(+), 1 deletion(-)
Successfully rebased and updated refs/heads/master.

現(xiàn)在提交歷史看起來像這樣:

* ba88fb0 - (HEAD -> master) Add name and author to package.json (31 seconds ago) <AleksandrHovhannisyan>
* 665034d - Update README with getting started instructions (53 seconds ago) <AleksandrHovhannisyan>
* 11221d4 - Add .gitignore (6 minutes ago) <AleksandrHovhannisyan>
* 9ed001a - Add README (6 minutes ago) <AleksandrHovhannisyan>
* 0beebfb - Add package.json (56 minutes ago) <AleksandrHovhannisyan>

編輯舊提交

編輯提交就意味著在提交之后立即轉(zhuǎn)到歷史記錄中的那個點。這允許修改提交并包含(或刪除)想要的任何更改。

目前為止,我們有如下提交歷史:

* ba88fb0 - (HEAD -> master) Add name and author to package.json (31 seconds ago) <AleksandrHovhannisyan>
* 665034d - Update README with getting started instructions (53 seconds ago) <AleksandrHovhannisyan>
* 11221d4 - Add .gitignore (6 minutes ago) <AleksandrHovhannisyan>
* 9ed001a - Add README (6 minutes ago) <AleksandrHovhannisyan>
* 0beebfb - Add package.json (56 minutes ago) <AleksandrHovhannisyan>

假設(shè)要編輯根提交(0beebfb)并添加第二個文件:

touch .yarnrc

我們將針對該提交使用交互式變基,在這種編輯根提交的特殊情況下,需要使用 --root 選項:

git rebase -i --root

這將打開編輯器,按時間順序顯示提交:

pick 0beebfb Add package.json
pick 9ed001a Add README
pick 11221d4 Add .gitignore
pick 665034d Update README with getting started instructions
pick ba88fb0 Add name and author to package.json

我們需要做的就是為該列表中的第一個提交將 pick 替換為 edit :

edit 0beebfb Add package.json
pick 9ed001a Add README
pick 11221d4 Add .gitignore
pick 665034d Update README with getting started instructions
pick ba88fb0 Add name and author to package.json

關(guān)閉并保存文件,應(yīng)該從 git 中看到這條消息:

Stopped at 0beebfb... Add package.json
You can amend the commit now, with

        git commit --amend

Once you are satisfied with your changes, run

        git rebase --continue

下面來運(yùn)行這兩個命令:

git add .yarnrc && git commit --amend

現(xiàn)在只需要修改提交,編輯器應(yīng)如下所示:

Add package.json

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Sun Oct 11 08:25:57 2020 -0400
#
# interactive rebase in progress; onto 666364d
# Last command done (1 command done):
#    edit 0beebfb Add package.json
# Next commands to do (4 remaining commands):
#    pick 9ed001a Add README
#    pick 11221d4 Add .gitignore
# You are currently editing a commit while rebasing branch 'master' on '666364d'.
#
#
# Initial commit
#
# Changes to be committed:
#       new file:   .yarnrc
#       new file:   package.json
#

現(xiàn)在將該消息更改為 Initialize npm package 保存并退出。現(xiàn)在,根據(jù) git 的建議,需要繼續(xù) rebase:

git rebase --continue

現(xiàn)在,提交歷史現(xiàn)在看起來像這樣:

* 436e421 - (HEAD -> master) Add name and author to package.json (6 seconds ago) <AleksandrHovhannisyan>
* beb7c13 - Update README with getting started instructions (6 seconds ago) <AleksandrHovhannisyan>
* 1c75f66 - Add .gitignore (6 seconds ago) <AleksandrHovhannisyan>
* 69c997b - Add README (6 seconds ago) <AleksandrHovhannisyan>
* 36210ec - Initialize npm package (56 seconds ago) <AleksandrHovhannisyan>

壓縮

壓縮可以將 n 個提交合并為一個,使提交歷史更加緊湊。如果一個功能分支引入大量提交,并且只希望該功能在歷史記錄中表示為單個提交(稱為 squash-and-rebase 工作流),這有時很有用。但是,如果將來需要,將無法恢復(fù)或修改舊的提交,這在某些情況下可能是不可取的。

同樣,作為參考,我們有如下提交歷史:

* 436e421 - (HEAD -> master) Add name and author to package.json (6 seconds ago) <AleksandrHovhannisyan>
* beb7c13 - Update README with getting started instructions (6 seconds ago) <AleksandrHovhannisyan>
* 1c75f66 - Add .gitignore (6 seconds ago) <AleksandrHovhannisyan>
* 69c997b - Add README (6 seconds ago) <AleksandrHovhannisyan>
* 36210ec - Initialize npm package (56 seconds ago) <AleksandrHovhannisyan>

下面來創(chuàng)建一個功能分支并添加一些提交:

git checkout -b feature && \
touch file1 && git add . && git commit -m "Add file1" && \
touch file2 && git add . && git commit -m "Add file2" && \
touch file3 && git add . && git commit -m "Add file3"

現(xiàn)在提交歷史如下:

* 6afa3ac - (HEAD -> feature) Add file3 (4 seconds ago) <AleksandrHovhannisyan>
* c16cbc6 - Add file2 (4 seconds ago) <AleksandrHovhannisyan>
* 0832e96 - Add file1 (4 seconds ago) <AleksandrHovhannisyan>
* 436e421 - (master) Add name and author to package.json (12 minutes ago) <AleksandrHovhannisyan>
* beb7c13 - Update README with getting started instructions (12 minutes ago) <AleksandrHovhannisyan>
* 1c75f66 - Add .gitignore (12 minutes ago) <AleksandrHovhannisyan>
* 69c997b - Add README (12 minutes ago) <AleksandrHovhannisyan>
* 36210ec - Initialize npm package (12 minutes ago) <AleksandrHovhannisyan>

我們可以使用以下命令將所有這些壓縮為一個:

git rebase -i master

這會將功能分支重新設(shè)置為 master 分支。請注意, master 是對特定提交的引用,就像其他任何提交一樣:

* 436e421 - (HEAD -> master) Add name and author to package.json (6 seconds ago) <AleksandrHovhannisyan>

這樣做也是一樣的:

git rebase -i 436e421

無論如何,一旦運(yùn)行了這些命令中的任何一個,git 就會打開編輯器:

pick 0832e96 Add file1
pick c16cbc6 Add file2
pick 6afa3ac Add file3

我們會將最后兩個提交壓縮到第一個提交中,所以將它們的 pick 命令更改為 squash:

pick 0832e96 Add file1
squash c16cbc6 Add file2
squash 6afa3ac Add file3

保存并退出,git 將打開編輯器,通知我們將要合并三個提交:

# This is a combination of 3 commits.
# This is the 1st commit message:

Add file1

# This is the commit message #2:

Add file2

# This is the commit message #3:

Add file3

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Sun Oct 11 09:37:05 2020 -0400
#
# interactive rebase in progress; onto 436e421
# Last commands done (3 commands done):
#    squash c16cbc6 Add file2
#    squash 6afa3ac Add file3
# No commands remaining.
# You are currently rebasing branch 'feature' on '436e421'.
#
# Changes to be committed:
#       new file:   file1
#       new file:   file2
#       new file:   file3
#

現(xiàn)在可以將 Add file1 更改為 Add files 1、2 和 3,或者想要的任何其他提交消息。保存并關(guān)閉文件,現(xiàn)在提交歷史已經(jīng)很緊湊了:

* b646cf6 - (HEAD -> feature) Add files 1, 2, and 3 (70 seconds ago) <AleksandrHovhannisyan>
* 436e421 - (master) Add name and author to package.json (14 minutes ago) <AleksandrHovhannisyan>
* beb7c13 - Update README with getting started instructions (14 minutes ago) <AleksandrHovhannisyan>
* 1c75f66 - Add .gitignore (14 minutes ago) <AleksandrHovhannisyan>
* 69c997b - Add README (14 minutes ago) <AleksandrHovhannisyan>
* 36210ec - Initialize npm package (15 minutes ago) <AleksandrHovhannisyan>

4、還原提交

上面學(xué)習(xí)了兩種從 git 歷史記錄中刪除提交的方法:

  • 在要刪除的提交范圍之前,將 HEAD 指針軟或硬重置為提交。
  • 對不想保留的任何提交執(zhí)行交互式變基并更改 pick 為 drop。

不幸的是,這兩種方法都會重寫提交歷史。以使用交互式變基從 master 分支中刪除 .env 文件為例。如果在現(xiàn)實中這樣做,在像 master 這樣的共享分支上刪除提交會導(dǎo)致一些麻煩,團(tuán)隊中的每個人都必須硬重置本地的 master 分支以匹配 origin/master

問題出現(xiàn)在人們正在進(jìn)行功能分支上的工作時,特別是如果他們是從舊的 master 分支切出來的——刪除的文件仍然存在。變基就是行不通的,因為它可能會重新引入在 master 分支上刪除的文件;同樣地,將 master 分支合并到功能分支中也不起作用,因為 git 沒有公共歷史可供解決:

fatal: refusing to merge unrelated histories

這就是 git revert 出現(xiàn)的原因。與通過變基或硬/軟重置刪除提交不同,revert 命令創(chuàng)建一個新提交以撤消目標(biāo)提交引入的任何更改:

git revert <hash-id>

假設(shè)在 master 分支上,想要用 beb7c13 的哈希恢復(fù)提交:

* 436e421 - (HEAD -> master) Add name and author to package.json (8 hours ago) <AleksandrHovhannisyan>
* beb7c13 - Update README with getting started instructions (8 hours ago) <AleksandrHovhannisyan>
* 1c75f66 - Add .gitignore (8 hours ago) <AleksandrHovhannisyan>
* 69c997b - Add README (8 hours ago) <AleksandrHovhannisyan>
* 36210ec - Initialize npm package (8 hours ago) <AleksandrHovhannisyan>

為此,執(zhí)行以下命令:

git revert beb7c13

Git 將打開編輯器:

Revert "Update README with getting started instructions"

This reverts commit beb7c132882ff1e3214dbd380514559fed0ef38f.

# 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:
#       modified:   README.md
#

保存并關(guān)閉文件,然后運(yùn)行 git log 以查看歷史記錄:

* e1e6e06 - (HEAD -> master) Revert "Update README with getting started instructions" (58 seconds ago) <AleksandrHovhannisyan>
* 436e421 - Add name and author to package.json (8 hours ago) <AleksandrHovhannisyan>
* beb7c13 - Update README with getting started instructions (8 hours ago) <AleksandrHovhannisyan>
* 1c75f66 - Add .gitignore (8 hours ago) <AleksandrHovhannisyan>
* 69c997b - Add README (8 hours ago) <AleksandrHovhannisyan>
* 36210ec - Initialize npm package (8 hours ago) <AleksandrHovhannisyan>

注意,原始提交仍然存在于歷史記錄中,并且其哈希值得以保留。唯一改變的是在分支的頂部添加了一個新的提交,以還原此前提交所引入的更改,就好像手動刪除了最初引入的更改。顯然,使用 git revert 比手工操作更合理。

因此,與交互式變基或重置相比,撤銷提交會引入額外的一個提交,因此會更加混亂。但這并不是非常重要的問題。而且,好處在于,它不會破壞公共分支。

5、簽出文件

git checkout 命令是另一種撤消 git 更改的基本方法。它有三個目的:

  • 創(chuàng)建新分支:git checkout -b <newBranch>。
  • 切換到分支或提交:git checkout <existingBranch>。
  • 恢復(fù)不同版本的文件。

這里我們將重點關(guān)注第三個目的。如果對本地文件進(jìn)行了未暫存的更改,則可以使用 checkout 命令輕松撤消這些更改:

git checkout <pathspec>

這里,<pathspec> 可以是任何有效的路徑說明符,例如:. 對于當(dāng)前目錄、path/to/file、file.extension,甚至是正則表達(dá)式。

這將清除對指定文件的所有未暫存更改并恢復(fù)當(dāng)前分支的文件的未修改版本。此命令不會影響暫存文件——只會清除未暫存的更改。

例如,如果想清除當(dāng)前目錄中所有未暫存的更改并從頭開始,最簡單的方法是使用 git checkout 命令和 . 作為路徑規(guī)范:

git checkout .

我們也可以使用 git checkout 來恢復(fù)文件的本地或遠(yuǎn)程版本。例如,可以簽出遠(yuǎn)程 master分支上的某個文件:

git checkout origin/master -- <pathspec>

這個命令的作用是將遠(yuǎn)程分支 origin/master 上指定的文件 <pathspec> 簽出到本地分支上。該命令會用遠(yuǎn)程分支上的文件覆蓋本地分支上的同名文件,即用遠(yuǎn)程分支的版本替換本地分支的版本,從而確保本地分支與遠(yuǎn)程分支保持同步。

同樣,也可以簽出另一個本地分支上的某個文件:

git checkout localBranchName -- <pathspec>

6、使用 Git Reflog

可以將 reflog 視為 git 的 git — 就像一個內(nèi)部記錄保存系統(tǒng),可以跟蹤大部分操作。

reflog 代表“參考日志”:HEAD 指針隨時間的不同狀態(tài)的一系列快照。這意味著任何時候引入、刪除或修改提交,或者簽出新分支,或者重寫舊提交的哈希,這些更改都將記錄在 reflog 中。我們將能夠回到過去撤消可能不需要的更改,即使它們看似不可逆轉(zhuǎn)。

查看 Git 倉庫的 reflog 的方式如下:

git reflog

例如,在功能分支上可以簽出一個新分支,git 將記錄該活動:

git checkout -b feature2

Reflog:

b646cf6 (HEAD -> feature2, origin/feature, feature) HEAD@{0}: checkout: moving from feature to feature2

這是因為 HEAD 指針從功能分支的首端重定向到新分支 feature2 的首端。

如果深入挖掘 reflog,還可以查看本文中的所有更改:

b646cf6 (HEAD -> feature2, origin/feature, feature) HEAD@{0}: checkout: moving from feature to feature2
b646cf6 (HEAD -> feature2, origin/feature, feature) HEAD@{1}: rebase -i (finish): returning to refs/heads/feature
b646cf6 (HEAD -> feature2, origin/feature, feature) HEAD@{2}: rebase -i (squash): Add files 1, 2, and 3
f3def0a HEAD@{3}: rebase -i (squash): # This is a combination of 2 commits.
0832e96 HEAD@{4}: rebase -i (start): checkout 436e421
6afa3ac HEAD@{5}: commit: Add file3
c16cbc6 HEAD@{6}: commit: Add file2
0832e96 HEAD@{7}: commit: Add file1
436e421 (master) HEAD@{8}: checkout: moving from master to feature
436e421 (master) HEAD@{9}: rebase -i (finish): returning to refs/heads/master
436e421 (master) HEAD@{10}: rebase -i (pick): Add name and author to package.json
beb7c13 HEAD@{11}: rebase -i (pick): Update README with getting started instructions
1c75f66 HEAD@{12}: rebase -i (pick): Add .gitignore
69c997b HEAD@{13}: rebase -i (pick): Add README
36210ec HEAD@{14}: commit (amend): Initialize npm package
04ba759 HEAD@{15}: rebase -i (edit): Add package.json
2bef9d4 HEAD@{16}: rebase -i (edit): Add package.json
666364d HEAD@{17}: rebase -i (start): checkout 666364da6703fc41e23515b1777de5ac84c8ad5e
ba88fb0 HEAD@{18}: rebase -i (finish): returning to refs/heads/master
ba88fb0 HEAD@{19}: rebase -i (reword): Add name and author to package.json
665034d HEAD@{20}: rebase -i (reword): Update README with getting started instructions
74dab36 HEAD@{21}: rebase -i: fast-forward
11221d4 HEAD@{22}: rebase -i (start): checkout HEAD~2
094f8cb HEAD@{23}: commit: Do more stuff
74dab36 HEAD@{24}: commit: Do something idk
11221d4 HEAD@{25}: rebase -i (finish): returning to refs/heads/master
11221d4 HEAD@{26}: rebase -i (pick): Add .gitignore
9ed001a HEAD@{27}: rebase -i (pick): Add README
0beebfb HEAD@{28}: rebase -i (start): checkout 2beb7c7^
7598875 HEAD@{29}: reset: moving to HEAD~1
b494f6f HEAD@{30}: commit: Add a file
7598875 HEAD@{31}: commit (amend): Add .gitignore
4753e23 HEAD@{32}: commit: Add .gitignore
893d18d HEAD@{33}: commit: Add README
2beb7c7 HEAD@{34}: commit: Add .env
0beebfb HEAD@{35}: commit (initial): Add package.json

可以通過檢查這些提交哈希來快速查看這些狀態(tài)中的任何一個:

git checkout <hash-id>

或者,可以將分支重置為歷史記錄中的某個點:

git reset --soft 7598875

這將當(dāng)前的 feature2 分支軟重置為以下歷史:

* 7598875 - (HEAD -> feature2) Add .gitignore (84 minutes ago) <AleksandrHovhannisyan>
* 893d18d - Add README (85 minutes ago) <AleksandrHovhannisyan>
* 2beb7c7 - Add .env (85 minutes ago) <AleksandrHovhannisyan>
* 0beebfb - Add package.json (85 minutes ago) <AleksandrHovhannisyan>

甚至可以運(yùn)行另一個 reflog 來查看更改:

7598875 (HEAD -> feature2) HEAD@{0}: reset: moving to 7598875

如果不希望本地分支被覆蓋,可以再次運(yùn)行 reflog 命令并將分支重置到在執(zhí)行該操作之前的 HEAD:

git reset --hard b646cf6

這就回到了之前的狀態(tài):

* b646cf6 - (HEAD -> feature2, origin/feature, feature) Add files 1, 2, and 3 (13 minutes ago) <AleksandrHovhannisyan>
* 436e421 - (master) Add name and author to package.json (26 minutes ago) <AleksandrHovhannisyan>
* beb7c13 - Update README with getting started instructions (26 minutes ago) <AleksandrHovhannisyan>
* 1c75f66 - Add .gitignore (26 minutes ago) <AleksandrHovhannisyan>
* 69c997b - Add README (26 minutes ago) <AleksandrHovhannisyan>
* 36210ec - Initialize npm package (27 minutes ago) <AleksandrHovhannisyan>

Git 的 reflog 命令很有用,以防進(jìn)行硬重置并丟失所有工作,只需查看 reflog 并重置到進(jìn)行硬重置之前的點,就輕松搞定!

最后,如果出于某種原因想清理 reflog,可以使用以下方法從中刪除行:

git reflog delete HEAD@{n}

將 n 替換為要從 reflog 中刪除的任何行。HEAD@{0} 指的是 reflog 中的最新行,HEAD@{1} 指的是之前的一行,依此類推。

參考:https://www.aleksandrhovhannisyan.com/blog/undoing-changes-in-git/。

責(zé)任編輯:姜華 來源: 前端充電寶
相關(guān)推薦

2011-02-24 10:56:34

人才

2010-10-08 11:13:22

MySQL修改密碼

2023-06-01 16:45:11

React開發(fā)JavaScript

2023-09-24 14:52:21

數(shù)據(jù)分析相關(guān)系數(shù)矩陣

2023-08-15 15:44:55

React開發(fā)

2025-01-02 08:21:32

2023-09-06 08:00:00

ChatGPT數(shù)據(jù)分析

2023-07-29 00:08:32

2023-04-03 20:29:00

Linux環(huán)境變量

2021-12-06 06:58:50

List重復(fù)數(shù)據(jù)

2025-01-03 08:48:20

列表推導(dǎo)式Python編程

2025-07-14 03:00:00

2022-06-09 08:46:58

ITCIO職業(yè)

2022-06-10 10:25:07

CIOIT領(lǐng)導(dǎo)者職業(yè)生涯

2015-07-09 10:13:05

IT基礎(chǔ)設(shè)施支出數(shù)據(jù)中心

2023-05-15 18:32:20

2024-11-05 08:28:50

2023-12-08 08:53:37

數(shù)據(jù)中心人工智能自動化

2022-02-21 22:47:36

首席信息官IT技術(shù)

2022-05-30 16:42:20

數(shù)據(jù)中心
點贊
收藏

51CTO技術(shù)棧公眾號

亚洲午夜无码av毛片久久| 韩国一区二区三区美女美女秀| 最新日韩免费视频| 精品久久国产一区| 午夜不卡在线视频| 先锋影音日韩| 成人小说亚洲一区二区三区| 久久综合伊人| 欧美高清电影在线看| 蜜桃av免费看| 成人动态视频| 欧美三级电影在线看| 久久久久久久9| av资源在线观看免费高清| 国产电影一区在线| 国产精品91在线观看| 免费在线看黄网址| 日本在线电影一区二区三区| 亚洲国产美女久久久久| 青青草久久伊人| 中文字幕在线免费观看视频| 亚洲欧美国产毛片在线| 日韩精品一区二区三区丰满| 人妻无码一区二区三区久久99| 久久精品国产亚洲aⅴ| 91超碰中文字幕久久精品| 天天天天天天天天操| 神马电影久久| 日韩二区三区在线| 稀缺小u女呦精品呦| 日韩电影精品| 欧美性大战久久| 欧美日韩在线中文| 2020国产在线| 一区二区三区欧美视频| 亚洲第一导航| 大地资源中文在线观看免费版| av电影一区二区| 99热在线国产| 国产激情视频在线播放| 麻豆精品视频在线| 国产精品久久不能| 无码人妻av一区二区三区波多野| 91久久在线| 久久久久九九九九| 久久免费精彩视频| 欧美另类女人| 欧美激情精品久久久久久变态| 搜索黄色一级片| 久久理论电影| 日韩在线小视频| youjizz亚洲女人| av中文一区| 亚洲天堂av图片| 久久精品成人av| 免费国产自久久久久三四区久久| 亚洲激情视频在线| 黄色性生活一级片| 欧美久久精品| 亚洲乱码av中文一区二区| 中文字幕无码人妻少妇免费| 久久影视三级福利片| 亚洲国产小视频在线观看| 国产性生活毛片| 蜜臀av一区| 日韩精品欧美国产精品忘忧草| 精品人妻一区二区免费| 免费日韩一区二区三区| 精品爽片免费看久久| 国产熟妇久久777777| 国产一区二区欧美| 日韩在线观看精品| 欧美成人一区二区三区高清| 国产一区日韩一区| 4p变态网欧美系列| 亚洲精品一区二三区| 蜜臂av日日欢夜夜爽一区| 91精品国产综合久久男男| 国产精品久久久久久久久久久久久久久久 | 日韩大片免费观看| 色欧美日韩亚洲| 亚洲久久中文字幕| 国内精品视频| 日韩电影中文字幕在线| a级黄色免费视频| 欧美国产综合| 欧美在线免费观看| 亚洲自拍第二页| 丰满亚洲少妇av| 欧美视频1区| 国产网站在线免费观看| 亚洲成人一区二区| 日日摸天天爽天天爽视频| 亚洲资源在线| 日韩精品视频中文在线观看| 久久久免费看片| 精品1区2区3区4区| 国产精品久久久久久久久久ktv| 国产精品久久久久久免费| 国产成人精品三级麻豆| 欧美精品一区二区三区在线看午夜| 波多野结衣一区二区| 亚洲影院免费观看| 性欧美极品xxxx欧美一区二区| 国产区一区二| 亚洲日本成人女熟在线观看| 唐朝av高清盛宴| 日韩va欧美va亚洲va久久| 亚洲综合一区二区不卡| 国产在线超碰| 天天操天天干天天综合网| 色一情一区二区| 网曝91综合精品门事件在线| 久久综合伊人77777蜜臀| 五月婷婷激情视频| 粉嫩欧美一区二区三区高清影视| 亚洲成人一区二区三区| 阿v视频在线| 日韩一区二区三区视频在线| 日本爱爱爱视频| 亚洲精选一区| 国产高清在线一区| 国产日产一区二区三区| 欧美色欧美亚洲另类二区| 欧美成人三级伦在线观看| 欧美+亚洲+精品+三区| 国产精品免费一区豆花| 视频国产在线观看| 亚洲一区二区三区在线| 欧洲美女亚洲激情| 第九色区aⅴ天堂久久香| 91chinesevideo永久地址| 亚洲免费成人在线| 亚洲免费看黄网站| 97超碰人人爽| 成人精品亚洲| 国产精品高清在线| 酒色婷婷桃色成人免费av网| 午夜欧美大尺度福利影院在线看| 亚洲v在线观看| 韩国一区二区三区在线观看| 亚洲自拍偷拍色图| 中文字幕有码在线视频| 91精品国产麻豆国产自产在线 | 日本xxxx免费| 91精品高清| 92国产精品视频| www免费在线观看| 51精品视频一区二区三区| 日本二区三区视频| 国产一区二区三区蝌蚪| 久久久久久久免费视频| 国产一区二区三区| 欧美老女人性生活| 亚洲黄色小说网址| 亚洲成av人在线观看| 久久久久9999| 久久久久国内| 亚洲人久久久| 国产一区二区三区黄网站| 欧美放荡办公室videos4k| 成人午夜福利视频| 精品欧美一区二区三区| 9.1成人看片免费版| 日本视频在线一区| 综合操久久久| 91精品入口| 91sa在线看| www.亚洲视频| 欧美一级片在线| 五月天婷婷网站| 久久精品亚洲精品国产欧美 | 成人影院中文字幕| 欧美一区二区视频97| jzzjzzjzz亚洲成熟少妇| 91精品午夜视频| 国产午夜精品无码一区二区| 久久女同互慰一区二区三区| 亚州精品一二三区| 午夜激情一区| 欧美久久电影| 久久视频社区| 欧美在线视频在线播放完整版免费观看| 免费国产在线观看| 5月丁香婷婷综合| 国产精品xxxx喷水欧美| 国产精品视频免费| 国产免费a级片| 日韩中文欧美在线| 日b视频免费观看| 国产欧美日韩在线观看视频| 成人午夜小视频| 在线人成日本视频| 久久视频免费观看| 手机在线精品视频| 欧美精品第1页| 波多野结衣国产| ...av二区三区久久精品| 星空大象在线观看免费播放| 久久精品国产亚洲一区二区三区 | 久久精品国产精品亚洲红杏| 无码熟妇人妻av在线电影| 精品国产乱码久久久久久蜜坠欲下 | 《视频一区视频二区| 亚洲黄色免费在线观看| 精品亚洲aⅴ乱码一区二区三区| 亚洲熟妇无码另类久久久| 97在线精品| 国产一区再线| 久久精品免视看国产成人| 国产精品99免视看9| 不卡的av影片| 久久国产色av| 超碰免费97在线观看| 精品视频在线播放免| www.久久精品.com| 在线不卡a资源高清| 久久人妻免费视频| 午夜一区二区三区视频| 侵犯稚嫩小箩莉h文系列小说| 欧美高清在线一区| 短视频在线观看| 成人国产精品视频| 日本中文字幕在线不卡| 免费成人性网站| 草草草在线视频| 一区二区高清| av免费看网址| 欧美日韩日本国产亚洲在线 | 666欧美在线视频| 中文字幕一区2区3区| 日韩欧美视频一区二区三区| 国产一级视频在线| 亚洲激情六月丁香| 欧美偷拍第一页| 中文字幕中文在线不卡住| 级毛片内射视频| 国产日韩精品一区二区三区 | 99久久婷婷这里只有精品 | 91.成人天堂一区| 亚洲性生活大片| 欧美日韩一区成人| 又污又黄的网站| 欧美日韩中文国产| 伊人久久国产精品| 欧美日韩高清一区| 成年人网站大全| 亚洲女同同性videoxma| 欧美精品99久久| 国产亚洲精品久久久久婷婷瑜伽| av日韩一区二区三区| 亚洲精品偷拍| 久久美女福利视频| 久久免费黄色| 小泽玛利亚视频在线观看| 麻豆freexxxx性91精品| 国产永久免费网站| 国产成人自拍在线| 艳妇乳肉豪妇荡乳xxx| aaa欧美日韩| 51妺嘿嘿午夜福利| 国产精品久久久久久久久久久免费看 | 欧美日韩福利在线观看| 色综合999| 欧美性做爰毛片| 国产亚洲精品精品国产亚洲综合| 国产精品亚洲综合天堂夜夜| 99久久这里有精品| 国产v亚洲v天堂无码| 人人香蕉久久| 亚洲精品二区| 午夜久久黄色| 日韩中文字幕三区| 久久精品国产亚洲一区二区三区 | 久久嫩草精品久久久久| 欧美偷拍一区二区三区| 中文字幕亚洲区| 久久精品99久久久久久| 欧美性色19p| 97国产成人无码精品久久久| 精品对白一区国产伦| 国产视频网址在线| 欧美成人手机在线| 日本成人三级电影| 91精品久久久久久久久久另类| 1204国产成人精品视频| 品久久久久久久久久96高清| 亚洲国产精品成人| 69堂免费视频| 国产传媒一区在线| 国产精品久久久久无码av色戒| 国产欧美综合在线| 久久久久久久久99| 色婷婷精品久久二区二区蜜臀av| 日韩国产成人在线| 精品久久久影院| 在线免费av网站| 91精品国产九九九久久久亚洲| 欧美精品日日操| 粉嫩av四季av绯色av第一区| 欧美精选视频在线观看| 黄色激情在线视频| 另类专区欧美蜜桃臀第一页| 国产毛片毛片毛片毛片毛片毛片| 亚洲欧美在线视频观看| 日韩一区二区视频在线| 91精品福利在线一区二区三区| 免费福利在线观看| 久久久亚洲福利精品午夜| 欧美一区二区三区婷婷| 欧美日韩免费观看一区| 欧美视频二区| 三级一区二区三区| 久久精品男人的天堂| 国产做受高潮漫动| 日韩一区和二区| 日本亚洲精品| 国产成人综合一区二区三区| 爱爱精品视频| 麻豆传媒网站在线观看| 蜜臀av一级做a爰片久久| 精品人妻无码一区二区三区 | 成人av在线播放观看| 奇米精品一区二区三区在线观看一| 日本一区二区在线免费观看| 一区二区三区不卡在线观看| 亚洲一卡二卡在线观看| 亚洲香蕉伊综合在人在线视看| 国产在线观看www| 国产精品视频免费观看| 欧美永久精品| 下面一进一出好爽视频| 亚洲日穴在线视频| 91精品国自产| 久久精品99无色码中文字幕| 精品自拍视频| 亚洲免费不卡| 久久精品av麻豆的观看方式| av永久免费观看| 欧美性生活久久| 91欧美在线视频| 国产精品亚发布| 99久久99久久精品国产片桃花| 久久婷婷综合色| 中文字幕一区二区三区视频| 一本色道久久综合亚洲| 久久精品这里热有精品| 国产精品一站二站| 日本人妻伦在线中文字幕| 国产寡妇亲子伦一区二区| 欧美人妻一区二区| 欧美va亚洲va在线观看蝴蝶网| 1234区中文字幕在线观看| 久久99精品久久久久子伦| 国产视频欧美| 亚洲AV无码成人精品区明星换面| 在线观看av一区二区| 欧美三级黄网| 91在线观看网站| 99pao成人国产永久免费视频| 爱爱的免费视频| 欧美中文字幕一区二区三区 | 国产美女精彩久久| 亚洲经典一区| 黄色av电影网站| 日本韩国一区二区| 夜级特黄日本大片_在线| 亚洲综合在线小说| 国产精品毛片在线| 美国一级黄色录像| 欧美一区二区国产| 3344国产永久在线观看视频| 欧美精品在线一区| 精彩视频一区二区| 久久免费视频6| 亚洲色图偷窥自拍| 成人污版视频| 波多野结衣乳巨码无在线| 欧美高清一级片在线观看| 性做久久久久久久久久| 日本成人在线视频网址| 婷婷综合在线| 欧美bbbbb性bbbbb视频| 欧美色涩在线第一页| 久久www人成免费看片中文| 欧美人与性禽动交精品| 精品一区免费av| 成人精品在线看| 久久精品99无色码中文字幕| 女人抽搐喷水高潮国产精品| 激情视频免费网站| 亚洲成a人v欧美综合天堂| 香蕉视频在线免费看| 精品国产一二| 国产一区日韩二区欧美三区| 成人在线免费看视频| 另类少妇人与禽zozz0性伦| 四虎影视精品| 91福利视频免费观看| 欧美综合欧美视频|