Git Reset vs Revert vs Rebase Git Reset、Revert和Rebase是Git版本控制系统中的三种不同操作。 Git Reset允许您将HEAD指针和分支指针移动到不同的提交位置。它可以用于撤消提交、移动分支指针或将分支指针移回之前的提交位置。这是一种比较强大的操作,因为它可以更改提交历史。 Git Revert操作用于撤销一个或多个提交。它会创建一个新的提交,该提交将取消所选提交引入的更改。这种方法适用于公共分支和共享代码仓库,因为它不会更改提交历史。 Git Rebase操作用于合并分支。它将当前分支中的提交应用到另一个分支,并将结果合并到目标分支中。这种操作可以使提交历史更加清晰,但它也可能带来冲突和复杂性。 了解这些操作的不同之处以及何时使用它们是很重要的,这样您就可以根据具体情况选择正确的操作。
在本文中,您将学习如何在Git中处理提交的不同方法。
作为开发人员,您可能多次遇到过希望回滚到以前的某个提交的情况,但不确定如何操作。即使您熟悉类似于reset、revert、rebase的命令,您也可能不了解它们之间的区别。因此,让我们开始了解git reset、revert和rebase是什么。
Git Reset
Git reset是一个复杂的命令,用于撤消更改。
您可以将git reset视为回滚功能。使用git reset,您可以在各个提交之间跳转。git reset命令有三种运行模式:–soft、–mixed和–hard。默认情况下,git reset命令使用mixed模式。在git reset工作流中,git的三种内部管理机制发挥作用:HEAD、暂存区(index)和工作目录。
工作目录是您当前正在工作的地方,也是您的文件所在的地方。使用git status命令,您可以查看工作目录中存在的所有文件/文件夹。
暂存区(Index)是git跟踪和保存文件中所有更改的地方。保存的更改将反映在.git目录中。您可以使用git add“文件名”将文件添加到暂存区。与以前一样,当您运行git status时,您将看到哪些文件存在于暂存区中。
Git中的当前分支称为HEAD。它指向在当前检出分支中发生的最后一次提交。它被视为任何引用的指针。一旦您切换到另一个分支,HEAD也会移动到新分支。
让我解释一下git reset在hard、soft和mixed模式下的工作原理。Hard模式用于转到指定的提交,工作目录将使用该提交的文件填充,并重置暂存区。在软重置中,只有指针更改为指定的提交。所有提交的文件在重置之前都保留在工作目录和暂存区中。在mixed模式(默认情况下),指针和暂存区都会重置。
Git Reset Hard
git hard reset的目的是将HEAD移动到指定的提交。它将删除在指定提交之后发生的所有提交。此命令将更改提交历史并指向指定的提交。
在此示例中,我将添加三个新文件,对它们进行提交,然后执行硬重置。
如下所示,您可以看到当前没有要提交的内容。
$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
现在,我将创建3个文件并添加一些内容。
$ vi file1.txt
$ vi file2.txt
$ vi file3.txt
将这些文件添加到现有仓库中。
$ git add file*
当您重新运行status命令时,它将反映我刚刚创建的新文件。
$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
(use "git push" to publish your local commits)
Changes to be committed:
(use "git restore --staged ..." to unstage)
new file:
file1.txt
new file:
file2.txt
new file:
file3.txt
在提交之前,让我向您展示,我当前在Git中有3个提交的日志。
$ git log --oneline
0db602e (HEAD -> master) one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test
现在,我将提交到仓库中。
$ git commit -m '添加了3个文件'
[master d69950b] 添加了3个文件
3个文件已更改,插入了3个条目(+)
创建了新文件 file1.txt
创建了新文件 file2.txt
创建了新文件 file3.txt
如果我运行ls-files命令,你将看到新文件已经添加。
$ git ls-files
演示
虚拟文件
新文件
file1.txt
file2.txt
file3.txt
当我在git中运行日志命令时,我有4个提交,HEAD指向最新的提交。
$ git log --oneline
d69950b (HEAD -> master) 添加了3个文件
0db602e 又提交了一次
59c86c9 新的提交
e2f44fc (origin/master, origin/HEAD) 测试
如果我手动删除file1.txt并运行git status,它将显示更改未暂存以提交的消息。
$ git status
在分支master
您的分支领先于'origin/master' 3次提交。
(使用“git push”将您的本地提交发布到远程)
待提交的更改:
(使用“git add/rm ...”来更新将要提交的内容)
(使用“git restore ...”放弃工作目录中的更改)
删除的:
file1.txt
没有要提交的更改(使用“git add”和/或“git commit -a”)
现在,我将运行硬重置命令。
$ git reset --hard
HEAD现在位于d69950b added 3 files
如果我重新检查状态,我会发现没有要提交的内容,而我删除的文件已经恢复到存储库中。回滚发生是因为在删除文件后,我没有提交,所以在硬重置后,它返回到了之前的状态。
$ git status
在分支master
您的分支领先于'origin/master' 3次提交。
(使用“git push”将您的本地提交发布到远程)
没有要提交的更改,工作树干净
如果我检查git的日志,它将是这个样子。
$ git log
提交d69950b7ea406a97499e07f9b28082db9db0b387(HEAD -> master)
作者:mrgeek
日期:
2020年5月17日星期一19:53:31 +0530
添加了3个文件
提交0db602e085a4d59cfa9393abac41ff5fd7afcb14
作者:mrgeek
日期:
2020年5月17日星期一01:04:13 +0530
又提交了一次
提交59c86c96a82589bad5ecba7668ad38aa684ab323
作者:mrgeek
日期:
2020年5月17日星期一00:54:53 +0530
新的提交
提交e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad(origin/master,origin/HEAD)
作者:mrgeek
日期:
2020年5月17日星期一00:16:33 +0530
测试
硬重置的目的是指向指定的提交并更新工作目录和暂存区域。让我给你展示另一个例子。当前,我的提交可视化如下:
在这里,我将运行带有HEAD^的命令,这意味着我要重置到上一个提交(向前一次提交)。
$ git reset --hard HEAD^
HEAD现在位于0db602e one more commit
你可以看到head指针现在已从d69950b更改为0db602e。
$ git log --oneline
0db602e (HEAD -> master) 又提交了一次
59c86c9 新的提交
e2f44fc (origin/master, origin/HEAD) 测试
如果你检查日志,d69950b的提交已经消失,头现在指向0db602e SHA。
$ git log
提交0db602e085a4d59cfa9393abac41ff5fd7afcb14(HEAD -> master)
作者:mrgeek
日期:
2020年5月17日星期一01:04:13 +0530
又提交了一次
提交59c86c96a82589bad5ecba7668ad38aa684ab323
作者:mrgeek
日期:
2020年5月17日星期一00:54:53 +0530
新的提交
提交e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad(origin/master,origin/HEAD)
作者:mrgeek
日期:
2020年5月17日星期一00:16:33 +0530
测试
如果你运行ls-files命令,你会发现file1.txt,file2.txt和file3.txt不再在仓库中,因为在硬重置之后,该提交及其文件被删除了。
Git硬重置
同样地,现在我将展示一个软重置的例子。假设我已经重新添加了上面提到的3个文件并提交了它们。git日志将显示如下。你可以看到”soft reset”是我的最新提交,HEAD也指向它。
在日志中可以使用以下命令查看提交的详细信息。
现在,使用软重置,我想切换到一个旧的提交,SHA为0db602e085a4d59cfa9393abac41ff5fd7afcb14
为了做到这一点,我将运行如下命令。你需要传递SHA的前6个字符以上,不需要完整的SHA。
现在当我运行git log时,我可以看到HEAD已经被重置到我指定的提交。
但是这里的区别是,我添加了3个文件的提交(aa400858aab3927e79116941c715749780a59fc9)的文件仍然在我的工作目录中。它们没有被删除。这就是为什么你应该使用软重置而不是硬重置。在软模式下不会丢失文件的风险。
Git撤销
在Git中,撤销命令用于执行撤销操作,即撤销某些更改。它类似于重置命令,但唯一的区别是您执行一个新的提交以返回到特定的提交。简而言之,可以说git撤销命令是一个提交。
Git撤销命令在执行撤销操作时不会删除任何数据。
假设我正在添加3个文件并执行git提交操作以进行撤销示例。
日志将显示新提交。
现在我想撤销到以前的提交,比如”59c86c9 new commit”。我将运行以下命令。
这将打开一个文件,您将在其中找到要还原的提交的详细信息,并且您可以在此处为您的新提交命名,然后保存并关闭文件。
还原“新提交”
这会还原提交 59c86c96a82589bad5ecba7668ad38aa684ab323。
#请输入更改的提交消息。以“#”开头的行将被忽略,空消息将中止提交。
#在主分支上
#您的分支比“origin/master”超前4个提交。
#(使用“git push”发布您的本地提交)
#
#将要提交的更改:
#修改:dummyfile
保存并关闭文件后,您将获得以下输出。
$ git revert 59c86c9
[master af72b7a] 还原“新提交”
更改了 1 个文件,插入了 1 行,删除了 1 行
现在,为了进行必要的更改,与reset不同,还原已执行了一个新的提交。如果再次检查日志,由于还原操作,您将找到一个新的提交。
$ git log --oneline
af72b7a(HEAD -> master)还原“新提交”
812335d 再次添加 3 个文件
0db602e 又提交了一次
59c86c9 新提交
e2f44fc(origin/master,origin/HEAD)测试
Git日志将包含所有提交的历史记录。如果要从历史记录中删除提交,则还原不是一个好选择,但如果要在历史记录中保留提交更改,则还原是适当的命令,而不是reset。
Git变基
在Git中,变基是将一个分支的提交移动或合并到另一个分支的方式。作为开发人员,在实际场景中,我不会在主分支上创建自己的功能。我会在我的分支(“功能分支”)上工作,当我的功能分支中有一些提交并添加了功能时,我会将其移动到主分支上。
变基有时可能会有点难以理解,因为它与合并非常相似。合并和变基的目标都是将我的功能分支的提交放到主分支或任何其他分支上。考虑这样一个图形:
假设您与其他开发人员一起工作。在这种情况下,您可以想象这可能会变得非常复杂,其中有许多其他开发人员在不同的功能分支上工作,并且他们一直在合并多个更改。追踪变得困惑。
这就是变基将会帮助的地方。这次,我不会执行git合并,而是执行变基,其中我要将我的两个功能分支提交移到主分支上。变基将获取我功能分支的所有提交,并将它们移到主分支提交的上方。因此,在幕后,git会将功能分支提交复制到主分支上。
这种方法会在一条干净的直线图中显示所有的提交。
这样可以轻松跟踪哪些提交放在哪里。想象一下,如果您是一个有很多开发人员的团队,所有的提交仍然在一行中。因此,即使有多人同时在同一项目上工作,也很容易跟踪。
让我来实际演示一下。
这是我的主分支当前的样子。它有4个提交。
$ git log --oneline
812335d(HEAD -> master)再次添加 3 个文件
0db602e 又提交了一次
59c86c9 新提交
e2f44fc(origin/master,origin/HEAD)测试
我将运行以下命令创建并切换到一个名为feature的新分支,该分支将从第2个提交(即59c86c9)创建。
(master)
$ git checkout -b feature 59c86c9
切换到一个新分支'feature'
如果在feature分支中检查日志,它只有来自主分支(主线)的2个提交。
(特点)
$ git log --oneline
59c86c9 (HEAD -> 特点) 新的提交
e2f44fc (origin/master, origin/HEAD) 测试
我将创建特点1并将其提交到特点分支。
(特点)
$ vi 特点1.txt
(特点)
$ git add .
该文件将在您的工作目录中保留其原始行结尾
(特点)
$ git commit -m '特点1'
[特点 c639e1b] 特点1
1个文件已更改,插入了1个(+)
创建模式100644 特点1.txt
我还将创建另一个特点,即特点2,并将其提交到特点分支。
(特点)
$ vi 特点2.txt
(特点)
$ git add .
该文件将在您的工作目录中保留其原始行结尾
(特点)
$ git commit -m '特点2'
[特点 0f4db49] 特点2
1个文件已更改,插入了1个(+)
创建模式100644 特点2.txt
现在,如果您检查特点分支的日志,它有两个新的提交,我在上面执行了这些提交。
(特点)
$ git log --oneline
0f4db49 (HEAD -> 特点) 特点2
c639e1b 特点1
59c86c9 新的提交
e2f44fc (origin/master, origin/HEAD) 测试
现在我要将这两个新功能添加到主分支。为此,我将使用rebase命令。从特点分支,我将针对主分支进行rebase。这样做的效果是将我的特点分支重新锚定在最新更改上。
(特点)
$ git rebase master
成功地rebase和更新了refs/heads/特点。
现在我要继续并切换到主分支。
(特点)
$ git checkout master
切换到分支'master'
您的分支领先于'origin/master' 3个提交。
(使用“git push”来发布您的本地提交)
最后,对主分支进行rebase,将我的特点分支上的这两个新提交取出并重放在我的主分支上。
(主)
$ git rebase 特点
成功地rebase和更新了refs/heads/主。
现在,如果我检查主分支上的日志,我可以看到我特点分支的两个提交已成功添加到我的主分支。
(主)
$ git log --oneline
766c996 (HEAD -> 主, 特点) 特点2
c036a11 特点1
812335d 再次添加3个文件
0db602e 又一次提交
59c86c9 新的提交
e2f44fc (origin/master, origin/HEAD) 测试
这就是关于Git中reset、revert和rebase命令的所有内容。
结论
这就是关于Git中reset、revert和rebase命令的所有内容。我希望这个一步一步的指南对您有所帮助。现在,您知道如何根据需要使用文章中提到的命令来处理提交。