Git代码回滚

部分内容翻译自:Resetting,Checking Out & Reverting

Introduction

在git中以下三个命令可以帮助代码回滚。

  • git reset
  • git checkout
  • git revert

checkout和reset通常是进行local或者private的撤销。当push的时候会很容易发生冲突。

revert是一个对public撤销安全的操作。因为会创建一个新的commit。

Prerequirements

可以看做three trees。

The three trees of Git

不同的操作对工作目录、暂存区和commit history的影响。(index为暂存区)

img

Checkout

checkout可以把当前的HEAD指向某个具体的commit。

是commit级别或者文件级别的操作。文件级别会把文件内容变成要求的commit的内容。

git checkout是commit histroy树的更新。

Example

HEAD和Main当前都指向d

![Move the HEAD ref pointer to a specified commit](/Volumes/D/zhangjunyu/笔记/Git/git代码回滚.assets/01 git-sequence-transparent kopiera.png)

git checkout b

Sequence of commits on the master branch

Revert

会用一个新的commit来撤销指定的commit上的更改。

是commit级别的操作。不能用在文件级别。

Reset

reset会重置three trees到要求的commit。

git reset --hard commit_id

提交:

git push origin

回退到上一个版本:

git reset --hard HEAD^ 

Sum

总结三个命令的常用场景。

Command Scope Common use cases
git reset Commit-level Discard commits in a private branch or throw away uncommited changes
git reset File-level Unstage a file
git checkout Commit-level Switch between branches or inspect old snapshots
git checkout File-level Discard changes in the working directory
git revert Commit-level Undo commits in a public branch
git revert File-level (N/A)

Commit-Level Operations

Git reset和git checkout的scope由传给他们的参数决定。如果没有指定file path,那么就是commit-level。

Reset A Specific Commit

把hotfix分支移动到两个commit之前。

git checkout hotfix git reset HEAD~2

Resetting the hotfix branch to HEAD-2

reset通常用来撤回没有和别人共享的commit。

除了撤回到之前的commit,也有可以用通过设置下列参数来更改暂存区或者工作目录。

  • –soft:不会改变暂存区或者工作目录。(即原本的更新内容还在工作目录和暂存区,但是commit id回到之前的。可以重新git commit)
  • –mixed:暂存区会更新到指定的commit。但是工作目录不受影响。默认参数。(可以重新编辑、然后add和commit)
  • –hard:暂存区和工作目录都会更新到指定的commit。(即指定commit之后的更新会全部消失)

Checkout old commit

checkout通常可以用来切换分支,即HEAD会从一个分支切换到另一个分支:

git checkout hotfix

Moving HEAD from master to hotfix

因为可能会覆盖本地的更改,所以git会强制我们commit或者stash所有的更改。

也可以用checkout来切换到之前的commit。例如:

git checkout HEAD~2

Moving  to an arbitrary commit

以为没有任何的分支引用,所以这种情况的HEAD处于游离状态。如果这个时候添加新的commit会非常危险,因为如果你切换到了其他的分支就没有办法再切回来了。所以HEAD处于游离状态的时候,一定要新建一个分支来进行操作。

Undo Public Commits with Revert

revert会通过添加一个新的commit来撤销一个commit。这是一个非常安全的撤销操作。因为它不会更改原来的commit历史。

git checkout hotfix git revert HEAD~2

Reverting the 2nd to last commit

这个操作会撤销两个commit之前的更新,但是是建立一个新的commit来实现的。

总的来说,git reset适合在private branch上使用,git revert适合在public上使用。

File-level Operations

Git Reset A Specific File

git reset会根据指定的commit id更新暂存区的内容。

git reset HEAD~2 foo.py

这个命令会按照两个commit之前的内容来更新foo.py文件。

Moving a file from the commit history into the staged snapshot

–soft、–mixed和–hard在file level上不会有任何影响。

Git Checkout File

git checkout会更改工作目录。不会更改HEAD的引用。

git checkout HEAD~2 foo.py

Moving a file from the commit history into the working directory

请注意,这会删除对文件的所有后续更改,而 git revert 命令仅撤消由指定提交引入的更改。

Reference

  1. 拜托,不要再问我Git如何回滚代码

  2. Resetting,Checking Out & Reverting

  3. Git中的git reset的三种参数的区别