你能解释一下“git reset”吗?用纯英语做? [英] Can you explain what "git reset" does in plain english?
问题描述
我见过有趣的帖子
a>解释有关 git reset
的细节。 不幸的是,我读到的越多,看起来越多我完全不理解它。我来自SVN背景,Git是一个全新的范例。我很容易获得mercurial,但Git技术性更强。
我认为 git reset
接近 hg revert
,但似乎有差异。
那么 git reset
呢?请详细说明:
- hard
, - soft
和 - merge
;
HEAD
,例如 HEAD ^
和 HEAD〜1
;
HEAD
和您的全局压力级别。
通常, git reset
的功能是获取当前分支并将其重置为指向其他位置,并且可能带来索引和工作树。更具体地说,如果你的master分支(当前签出)如下所示:
- A - B - C(HEAD,master )
并且您意识到您希望高手指向B,而不是C,您将使用<$ c
- A - B(HEAD,master; $ c> git reset B
)# - C仍然在这里,但没有分支指向它
Digression:这是不同的从结帐。如果你运行 git checkout B
,你会得到这个:
- A - B(HEAD) - C(master)
脱离HEAD状态。 HEAD
,工作树,索引全部匹配 B
,但主分支留在 ç
。如果你在这时做了一个新的提交 D
,你会得到这个,这可能不是你想要的:
- A - B - C(主)
$ p记住,重置不会进行提交,它只是更新一个分支(这是一个提交的指针)指向一个不同的提交。其余的只是你的索引和工作树发生了什么的细节。
\
D(HEAD)
用例
在我对下一节中各种选项的描述中,
git reset
的主要用例。它可以真正用于各种各样的事情;通用线程是所有这些都涉及重置分支,索引和/或工作树以指向/匹配给定的提交。
需要注意的事项
-
- 很难
会导致你真的失去工作。它修改你的工作树。 -
git reset [options] commit
)失去提交。在上面的玩具例子中,我们失去了提交C
。它仍然在回购中,您可以通过查看git reflog show HEAD
或git reflog show master
找到它,但它实际上不再可以从任何分支访问。 Git在30天后永久删除这些提交,但在此之前,您可以通过指向分支来恢复C再次(
git checkout C; git分支<新分行名称>
)。 参数
解释手册页时,最常见的用法是 git reset [
,它会将给定的路径从给定的提交重置为它们的状态。如果未提供路径,则整个树将被重置,如果未提供提交,则将其视为HEAD(当前提交)。这是一个跨git命令的常见模式(例如checkout,diff,log,尽管确切的语义有所不同),所以它不应该太令人吃惊。
git reset other-branch path / to / foo
将路径/到/ foo中的所有内容重置为其他分支中的状态, git reset - 。
将当前目录重置为其在HEAD中的状态,并且简单的 git reset
将所有内容都重置为其在HEAD中的状态。 主工作树和索引选项
有四个主要选项可用来控制复位过程中工作树和索引发生的情况。 / p>
请记住,该索引是git的暂存区域 - 当您说 git add
准备提交。
-
- hard
已重置为。可能这是最容易理解的。你所有的本地修改都会被破坏。一个主要用途是吹走你的工作,但不切换提交:git reset --hard
表示git reset --hard HEAD
,即不要更改分支,但要摆脱所有本地更改。另一种方法是将分支从一个地方移动到另一个地方,并保持索引/工作树同步。 这是真正让你失去工作的原因,因为它会修改你的工作树。在你运行任何reset之前,非常确定你要丢掉本地工作。很难
。 -
- 混合
是默认值,即git reset
表示git reset --mixed
。它重置索引,但不重置工作树。这意味着所有的文件都是完整的,但是原始提交和重置之间的任何差异都将显示为具有git状态的本地修改(或未跟踪文件)。当你意识到你做了一些不好的提交时,请使用它,但是你想保留所有你已经完成的工作,这样你就可以修复它并重新提交。为了提交,你必须再次将文件添加到索引(git add ...
)。 -
- soft
不会触及索引或工作树。所有文件与- mixed
一样完好无损,但所有更改都显示为要更改的提交
with git状态(即在准备提交时签入)。当你意识到你做了一些不好的提交时使用它,但这项工作很好 - 你需要做的就是以不同的方式重新提交。索引是未触及的,因此如果您愿意,您可以立即提交 - 所产生的提交将具有与重置之前的位置相同的内容。 code> - merge 是最近添加的,旨在帮助您中止失败的合并。这是必要的,因为
git merge
实际上允许您尝试与脏工作树(一个具有本地修改)合并,只要这些修改不受合并影响的文件中。 git reset --merge
重置索引(例如 - mixed - 所有更改都显示为本地修改),以及重置受合并影响的文件,但保留其他文件。这将有希望将所有事情恢复到糟糕合并之前的状况。您通常将它作为 git reset --merge
(意味着 git reset --merge HEAD
),因为您只有想重置合并,而不是实际移动分支。 ( HEAD
尚未更新,因为合并失败)
更具体地说,我修改了文件A和B,并尝试在修改文件C和D的分支中进行合并。由于某种原因合并失败,并且您决定中止它。您可以使用 git reset --merge
。它将C和D带回到它们在 HEAD
中的方式,但它们只是对A和B的修改,因为它们不是尝试合并的一部分。
想知道更多吗?
我认为 man git reset
对此非常有用 - 也许你需要对git的工作方式有所了解,尽管他们真的沉入其中。尤其是,如果您花时间仔细阅读它们,那些详细说明索引和工作树中文件状态的表格对于所有各种选项和案例都非常有帮助。 (但是,它们非常密集 - 它们以非常简洁的形式传达了上述很多信息。)
奇怪的记法
奇怪的符号( HEAD ^
和 HEAD〜1
)你提及仅仅是指定提交的简写,而不必使用像 3ebe3f6
这样的哈希名称。它在指定修订中有详细记录git-rev-parse的手册页的部分,其中包含大量示例和相关语法。插入符号和代字符实际上意味着不同的东西:
-
HEAD〜
是HEAD〜1 $ c的简写$ c>并且表示提交的第一个父代。
HEAD〜2
表示提交的第一个父代的第一个父代。将HEAD〜n
看作n在HEAD之前提交或HEAD的第n代祖先。
HEAD ^
(或HEAD ^ 1
)也意味着提交的第一个父代。HEAD ^ 2
表示提交的第二个父。请记住,正常的合并提交有两个父母 - 第一个父母是合并提交,第二个父母是合并的提交。一般而言,合并实际上可以有许多父母(章鱼合并)。
^
和〜
运算符可以串在一起,如HEAD〜3 ^ 2
,是HEAD的第三代祖先的第二个父
,
HEAD ^^ 2
,是HEAD
的第一个父项的第二个父项,或者甚至HEAD ^^^
,相当于HEAD〜3
。
ul>
I have seen interesting posts explaining subtleties about
git reset
.Unfortunately, the more I read about it, the more it appears that I don't understand it fully. I come from a SVN background and Git is a whole new paradigm. I got mercurial easily, but Git is much more technical.
I think
git reset
is close tohg revert
, but it seems there are differences.So what exactly does
git reset
do? Please include detailed explanations about:- the options
--hard
,--soft
and--merge
; - the strange notation you use with
HEAD
such asHEAD^
andHEAD~1
; - concrete use cases and work flows;
- consequences on the working copy, the
HEAD
and your global stress level.
解决方案In general,
git reset
's function is to take the current branch and reset it to point somewhere else, and possibly bring the index and work tree along. More concretely, if your master branch (currently checked out) is like this:- A - B - C (HEAD, master)
and you realize you want master to point to B, not C, you will use
git reset B
to move it there:- A - B (HEAD, master) # - C is still here, but there's no branch pointing to it anymore
Digression: This is different from a checkout. If you'd run
git checkout B
, you'd get this:- A - B (HEAD) - C (master)
You've ended up in a detached HEAD state.
HEAD
, work tree, index all matchB
, but the master branch was left behind atC
. If you make a new commitD
at this point, you'll get this, which is probably not what you want:- A - B - C (master) \ D (HEAD)
Remember, reset doesn't make commits, it just updates a branch (which is a pointer to a commit) to point to a different commit. The rest is just details of what happens to your index and work tree.
Use cases
I cover many of the main use cases for
git reset
within my descriptions of the various options in the next section. It can really be used for a wide variety of things; the common thread is that all of them involve resetting the branch, index, and/or work tree to point to/match a given commit.Things to be careful of
--hard
can cause you to really lose work. It modifies your work tree.git reset [options] commit
can cause you to (sort of) lose commits. In the toy example above, we lost commitC
. It's still in the repo, and you can find it by looking atgit reflog show HEAD
orgit reflog show master
, but it's not actually accessible from any branch anymore.Git permanently deletes such commits after 30 days, but until then you can recover C by pointing a branch at it again (
git checkout C; git branch <new branch name>
).
Arguments
Paraphrasing the man page, most common usage is of the form
git reset [<commit>] [paths...]
, which will reset the given paths to their state from the given commit. If the paths aren't provided, the entire tree is reset, and if the commit isn't provided, it's taken to be HEAD (the current commit). This is a common pattern across git commands (e.g. checkout, diff, log, though the exact semantics vary), so it shouldn't be too surprising.For example,
git reset other-branch path/to/foo
resets everything in path/to/foo to its state in other-branch,git reset -- .
resets the current directory to its state in HEAD, and a simplegit reset
resets everything to its state in HEAD.The main work tree and index options
There are four main options to control what happens to your work tree and index during the reset.
Remember, the index is git's "staging area" - it's where things go when you say
git add
in preparation to commit.--hard
makes everything match the commit you've reset to. This is the easiest to understand, probably. All of your local changes get clobbered. One primary use is blowing away your work but not switching commits:git reset --hard
meansgit reset --hard HEAD
, i.e. don't change the branch but get rid of all local changes. The other is simply moving a branch from one place to another, and keeping index/work tree in sync. This is the one that can really make you lose work, because it modifies your work tree. Be very very sure you want to throw away local work before you run anyreset --hard
.--mixed
is the default, i.e.git reset
meansgit reset --mixed
. It resets the index, but not the work tree. This means all your files are intact, but any differences between the original commit and the one you reset to will show up as local modifications (or untracked files) with git status. Use this when you realize you made some bad commits, but you want to keep all the work you've done so you can fix it up and recommit. In order to commit, you'll have to add files to the index again (git add ...
).--soft
doesn't touch the index or work tree. All your files are intact as with--mixed
, but all the changes show up aschanges to be committed
with git status (i.e. checked in in preparation for committing). Use this when you realize you've made some bad commits, but the work's all good - all you need to do is recommit it differently. The index is untouched, so you can commit immediately if you want - the resulting commit will have all the same content as where you were before you reset.--merge
was added recently, and is intended to help you abort a failed merge. This is necessary becausegit merge
will actually let you attempt a merge with a dirty work tree (one with local modifications) as long as those modifications are in files unaffected by the merge.git reset --merge
resets the index (like--mixed
- all changes show up as local modifications), and resets the files affected by the merge, but leaves the others alone. This will hopefully restore everything to how it was before the bad merge. You'll usually use it asgit reset --merge
(meaninggit reset --merge HEAD
) because you only want to reset away the merge, not actually move the branch. (HEAD
hasn't been updated yet, since the merge failed)To be more concrete, suppose you've modified files A and B, and you attempt to merge in a branch which modified files C and D. The merge fails for some reason, and you decide to abort it. You use
git reset --merge
. It brings C and D back to how they were inHEAD
, but leaves your modifications to A and B alone, since they weren't part of the attempted merge.
Want to know more?
I do think
man git reset
is really quite good for this - perhaps you do need a bit of a sense of the way git works for them to really sink in though. In particular, if you take the time to carefully read them, those tables detailing states of files in index and work tree for all the various options and cases are very very helpful. (But yes, they're very dense - they're conveying an awful lot of the above information in a very concise form.)Strange notation
The "strange notation" (
HEAD^
andHEAD~1
) you mention is simply a shorthand for specifying commits, without having to use a hash name like3ebe3f6
. It's fully documented in the "specifying revisions" section of the man page for git-rev-parse, with lots of examples and related syntax. The caret and the tilde actually mean different things:HEAD~
is short forHEAD~1
and means the commit's first parent.HEAD~2
means the commit's first parent's first parent. Think ofHEAD~n
as "n commits before HEAD" or "the nth generation ancestor of HEAD".HEAD^
(orHEAD^1
) also means the commit's first parent.HEAD^2
means the commit's second parent. Remember, a normal merge commit has two parents - the first parent is the merged-into commit, and the second parent is the commit that was merged. In general, merges can actually have arbitrarily many parents (octopus merges).- The
^
and~
operators can be strung together, as inHEAD~3^2
, the second parent of the third-generation ancestor ofHEAD
,HEAD^^2
, the second parent of the first parent ofHEAD
, or evenHEAD^^^
, which is equivalent toHEAD~3
.
这篇关于你能解释一下“git reset”吗?用纯英语做?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!