您现在的位置是:首页 >技术教程 >Git常用命令reset和revert网站首页技术教程

Git常用命令reset和revert

zsx_yiyiyi 2024-06-29 00:01:02
简介Git常用命令reset和revert

Git常用命令reset和revert

1、reset

用于回退版本,可以指定退回某一次提交的版本。

checkout 可以撤销工作区的文件,reset 可以撤销工作区/暂存区的文件。

reset 和 checkout 可以作用于 commit 或者文件,revert 只能作用于 commit。

命令格式:

$ git reset [--mixed | --soft | --hard | --merge | --keep] [commit | HEAD]
  • mixed:reset HEAD and index

  • soft:reset only HEAD

  • hard:reset HEAD, index and working tree

  • merge:reset HEAD, index and working tree

  • keep:reset HEAD but keep local changes

将当前的分支重设到指定的 commit 或者 HEAD,如果不显示指定 commit,默认是 HEAD,即最新的一次提交。

并且根据 mode 有可能更新索引和工作目录,mode 的取值可以是 hard、soft、mixed、merged、keep 。默认

为 mixed。

下面将演示每一种的使用方法。

# 使用如下的提交
# master分支
echo a > a.txt
echo b > b.txt
git add a.txt
git add b.txt
git commit -m "add a.txt | add b.txt"

echo c > c.txt
echo d > d.txt
git add c.txt
git add d.txt
git commit -m "add c.txt | add d.txt"

echo e > e.txt
echo f > f.txt
git add e.txt
git add f.txt
git commit -m "add e.txt | add f.txt"

$ git log --oneline
1475123 (HEAD -> master) add e.txt | add f.txt
b41f99c add c.txt | add d.txt
a1397f6 add a.txt | add b.txt

1.1 mixed

# reset HEAD and index
# 将指定commit撤回之后所有内容全部放进工作区中,也就是没有执行git add之前的状态
$ git reset --mixed [commit | HEAD]
# 将提交 b41f99c 恢复,最后的一次提交会被撤销
$ git reset --mixed b41f99c

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

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

1.2 soft

# reset only HEAD
# 将指定commit撤回之后所有内容全部放进暂存区,也就是执行git add之后的状态
$ git reset --soft [commit | HEAD]
# 将提交 b41f99c 恢复,最后的一次提交会被撤销
$ git reset --soft b41f99c

$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   e.txt
        new file:   f.txt

1.3 hard

# reset HEAD, index and working tree
# 将指定commit撤回并清空工作目录及暂存区所有修改,也就是修改和添加文件之前的状态
$ git reset --hard [commit | HEAD]
# 将提交 b41f99c 恢复,最后的一次提交会被撤销
$ git reset --hard b41f99c
HEAD is now at b41f99c add c.txt | add d.txt

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

$ ls
a.txt  b.txt  c.txt  d.txt

1.4 merge

# reset HEAD, index and working tree
# 暂存区会被删除
# 工作区不会
$ git reset --merge [commit | HEAD]

该选项的作用,把当前分支和指定的 commit 进行合并,规则如下:

  • 重置暂存区,任何已经添加到暂存区的改动都将被抛弃

  • 如果 commit 和 HEAD 之间有文件存在不同(这个不同指的是文件被删除或者新增),那么将会把该文件重置成

    commit 中的状态(新增或删除)。

  • 如果 commit 和 HEAD 之间有文件存在不同(这个不同是指文件内容的不同),且此时工作区也存在未提交的改

    动,那么本次的 reset 将会被终止。

  • 如果一个文件在 commit 和 HEAD 中完全相同,但是它的工作区存与暂存区存在着不同(也就是改动未提交到

    暂存区),那么该文件在工作区的改动在重置之后就会被保留。

cat > a.txt << EOF 
a1
a2
a3
EOF
git add a.txt
git commit -m "add a.txt"

cat > b.txt << EOF 
b1
b2
EOF
git add b.txt
git commit -m "add b.txt"

cat > a.txt << EOF 
a1
a2
a3
a4
EOF
cat > c.txt << EOF 
c1
c2
EOF
git add c.txt

$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   c.txt

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

$ git log --oneline
65fc0d0 (HEAD -> master) add b.txt
2b89c2f add a.txt
# 将提交 2b89c2f 恢复,最后的合并会被撤销
$ git reset --merge 2b89c2f

$ ls
a.txt

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   a.txt

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

$ cat a.txt
a1
a2
a3
a4

1.5 keep

# reset HEAD but keep local changes
# 暂存不会被删除
# 工作区也不会
$ git reset --keep [commit | HEAD]

该选参的作用和 --merge 相似,唯一的区别就是暂存区中被重置的会被保留在工作区中。

cat > a.txt << EOF 
a1
a2
a3
EOF
git add a.txt
git commit -m "add a.txt"

cat > b.txt << EOF 
b1
b2
EOF
git add b.txt
git commit -m "add b.txt"

cat > a.txt << EOF 
a2
a3
EOF
cat > c.txt << EOF 
c1
c2
EOF
git add c.txt

$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   c.txt

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

$ git log --oneline
f6429e8 (HEAD -> master) add b.txt
22a85b3 add a.txt
# 将提交 22a85b3 恢复,最后的合并会被撤销
$ git reset --keep 22a85b3

$ ls
a.txt  c.txt

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   a.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        c.txt

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

$ cat a.txt
a2
a3

$ cat c.txt
c1
c2

1.6 其它用法

下面将不演示使用 [–mixed | --soft | --hard | --merge | --keep] 参数,默认使用后 --mixed。

1.6.1 reset指定文件

$ git log --oneline
1475123 (HEAD -> master) add e.txt | add f.txt
b41f99c add c.txt | add d.txt
a1397f6 add a.txt | add b.txt
# 撤回指定文件到工作区,也就是没有执行git add之前的状态
$ git reset [commit | HEAD] file
# 例子
$ git reset b41f99c f.txt

$ ls
a.txt  b.txt  c.txt  d.txt  e.txt  f.txt

$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        deleted:    f.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        f.txt
$ git reset
# 等价于
$ git reset HEAD
# 上面的操作也可以使用
# 例子
$ git reset HEAD^ f.txt

$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        deleted:    f.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        f.txt

$ ls
a.txt  b.txt  c.txt  d.txt  e.txt  f.txt
# 回退三个版本
$ git reset --hard HEAD^^^
# 可以使用HEAD~数字,表示版本的次数
$ git reset --hard HEAD~3

1.6.2 从服务器上获取最新的版本历史

# 假如你想丢弃你在本地的所有改动与提交,可以到服务器上获取最新的版本历史,并将你本地主分支指向它
git fetch origin
git reset --hard origin/master

1.7 总结

git reset 有很多种用法,它可以被用来移除提交快照,尽管它通常被用来撤销暂存区和工作区的修改。不管是

哪种情况,它应该只被用于本地修改,你永远不应该重设和其他开发者共享的快照。

当你用 reset 回滚到了某个版本后,那么在下一次 git 提交时,之前该版本后面的版本会被作为垃圾删掉。

2、revert

撤销指定的提交内容。

revert 是回滚某个 commit ,不是回滚到某个。git revert是用于反做某一个版本,以达到撤销该版本的修改的目

的。比如,我们commit了三个版本(版本一、版本二、 版本三),突然发现版本二不行(如:有bug),想要撤

销版本二,但又不想影响撤销版本三的提交,就可以用 git revert 命令来反做版本二,生成新的版本四,这个版本

四里会保留版本三的东西,但撤销了版本二的东西。

# 使用如下的提交
# master分支
echo a > a.txt
echo b > b.txt
git add a.txt
git add b.txt
git commit -m "add a.txt | add b.txt"

echo c > c.txt
echo d > d.txt
git add c.txt
git add d.txt
git commit -m "add c.txt | add d.txt"

echo e > e.txt
echo f > f.txt
git add e.txt
git add f.txt
git commit -m "add e.txt | add f.txt"

$ git log --oneline
1475123 (HEAD -> master) add e.txt | add f.txt
b41f99c add c.txt | add d.txt
a1397f6 add a.txt | add b.txt
# 用来撤销指定commit,销后会生成一个新的commit
$  git revert [commit]
# 例子
$ git revert b41f99c
Removing d.txt
Removing c.txt
[master 3671b77] Revert "add c.txt | add d.txt"
 2 files changed, 2 deletions(-)
 delete mode 100644 c.txt
 delete mode 100644 d.txt

在这里插入图片描述

$ git log --oneline
3671b77 (HEAD -> master) Revert "add c.txt | add d.txt"
1475123 add e.txt | add f.txt
b41f99c add c.txt | add d.txt
a1397f6 add a.txt | add b.txt

$ ls
a.txt  b.txt  e.txt  f.txt

$ git status
On branch master
nothing to commit, working tree clean
# 生成一个撤销指定提交版本的新提交,执行时不打开默认编辑器,直接使用Git自动生成的提交信息
# 这个和上面的命令没有什么区别,唯一的区别是不会弹出框修改commit信息
$ git revert <commit_id> --no-edit
# 例子
$ git revert b41f99c --no-edit
Removing d.txt
Removing c.txt
[master 727c8f3] Revert "add c.txt | add d.txt"
 Date: Fri May 26 10:35:08 2023 +0800
 2 files changed, 2 deletions(-)
 delete mode 100644 c.txt
 delete mode 100644 d.txt
 
$ git log --oneline
727c8f3 (HEAD -> master) Revert "add c.txt | add d.txt"
1475123 add e.txt | add f.txt
b41f99c add c.txt | add d.txt
a1397f6 add a.txt | add b.txt
# 反做,使用git revert -n 版本号命令,如下我们反做版本号为8b89621的版本
# 这里可能会出现冲突,那么需要手动修改冲突的文件,而且要git add文件名来提交
# 假如上面Revert之后的提交727c8f3我们不想要了,可以执行如下操作
$ git revert -n 727c8f3

$ git log --oneline
727c8f3 (HEAD -> master) Revert "add c.txt | add d.txt"
1475123 add e.txt | add f.txt
b41f99c add c.txt | add d.txt
a1397f6 add a.txt | add b.txt

# 会发现回到了最初的状态,文件都回来了,只是多了commit
$ ls
a.txt  b.txt  c.txt  d.txt  e.txt  f.txt
# 生成一个撤销最近的一次提交的新提交
$ git revert HEAD
# 生成一个撤销最近一次提交的上一次提交的新提交
$ git revert HEAD^
# 生成一个撤销最近一次提交的上两次提交的新提交
$ git revert HEAD^^
# 生成一个撤销最近一次提交的上n次提交的新提交
$ git revert HEAD~num 

git revert 命令用来撤销某个已经提交的快照(和 reset 重置到某个指定版本不一样)。它是在提交记录最后面加上一

个撤销了更改的新提交,而不是从项目历史中移除这个提交,这避免了 Git 丢失项目历史。

撤销(revert)应该用在你想要在项目历史中移除某个提交的时候。比如说,你在追踪一个 bug,然后你发现它是

由一个提交造成的,这时候撤销就很有用。

撤销(revert)被设计为撤销公共提交的安全方式,重设(reset)被设计为重设本地更改。

因为两个命令的目的不同,它们的实现也不一样:重设完全地移除了一堆更改,而撤销保留了原来的更改,用一个

新的提交来实现撤销。千万不要用 git reset 回退已经被推送到公共仓库上的提交,它只适用于回退本地修改(从未

提交到公共仓库中)。如果你需要修复一个公共提交,最好使用 git revert。

发布一个提交之后,你必须假设其他开发者会依赖于它。移除一个其他团队成员在上面继续开发的提交在协作时会

引发严重的问题。当他们试着和你的仓库同步时,他们会发现项目历史的一部分突然消失了。一旦你在重设之后又

增加了新的提交,Git 会认为你的本地历史已经和 origin/master 分叉了,同步你的仓库时的合并提交(merge

commit)会使你的同事困惑。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。