我看过一些有趣的帖子,解释git重置的微妙之处。
不幸的是,我读得越多,就越觉得我并没有完全理解它。我有SVN的背景,Git是一个全新的范例。我很容易得到mercurial,但是Git的技术含量更高。
我认为git重置接近hg恢复,但似乎有区别。
git重置到底是做什么的?请详细说明:
选项——硬、软和合并; 你对HEAD使用的奇怪符号,如HEAD^和HEAD~1; 具体的用例和工作流程; 对工作副本、HEAD和整体压力水平的影响。
我看过一些有趣的帖子,解释git重置的微妙之处。
不幸的是,我读得越多,就越觉得我并没有完全理解它。我有SVN的背景,Git是一个全新的范例。我很容易得到mercurial,但是Git的技术含量更高。
我认为git重置接近hg恢复,但似乎有区别。
git重置到底是做什么的?请详细说明:
选项——硬、软和合并; 你对HEAD使用的奇怪符号,如HEAD^和HEAD~1; 具体的用例和工作流程; 对工作副本、HEAD和整体压力水平的影响。
当前回答
博士TL;
git reset重置Staging到最后一次提交。使用——很难将工作目录中的文件重置到最后一次提交。
完整版
但这显然过于简单,因此会有许多相当啰嗦的答案。对我来说,在撤销更改的上下文中阅读git重置更有意义。请看这个:
如果git恢复是一种“安全”的方法来撤销更改,您可以考虑git 复位为危险方法。当你撤销与git重置(和 提交不再被任何ref或reflog引用),有 无法检索原始副本—这是永久撤销。护理必须 在使用这个工具的时候,你可能会遇到这样的问题,因为它是唯一一个有可能丢失你的工作的Git命令。
从https://www.atlassian.com/git/tutorials/undoing-changes/git-reset
这
在提交级别,重置是一种将分支的尖端移动到不同提交的方法。这可用于从当前分支删除提交。
从https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting/commit-level-operations
其他回答
一般来说,git reset的功能是获取当前分支并将其重置为指向其他地方,并可能将索引和工作树也一并带来。更具体地说,如果你的主分支(当前签出)是这样的:
- A - B - C (HEAD, master)
并且你意识到你想要master指向B,而不是C,你将使用git重置B来移动它:
- A - B (HEAD, master) # - C is still here, but there's no branch pointing to it anymore
题外话:这与结帐不同。如果你运行git checkout B,你会得到这个:
- A - B (HEAD) - C (master)
你最终会进入一个分离的HEAD状态。HEAD,工作树,索引都匹配B,但是主分支被留在了c。如果你在这个时候做了一个新的提交D,你会得到这个,这可能不是你想要的:
- A - B - C (master)
\
D (HEAD)
记住,reset不会进行提交,它只是更新一个分支(一个指向提交的指针)以指向不同的提交。剩下的就是索引和工作树的细节。
用例
在下一节对各种选项的描述中,我将介绍git重置的许多主要用例。它真的可以用于各种各样的事情;共同的线程是,所有这些都涉及重置分支、索引和/或工作树,以指向/匹配给定的提交。
需要注意的事情
--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 commit C. It's still in the repo, and you can find it by looking at git reflog show HEAD or git 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>).
参数
转述手册页,最常见的用法是git reset [<commit>][路径…],它将从给定的提交中将给定的路径重置为它们的状态。如果没有提供路径,则重置整个树,如果没有提供提交,则将其作为HEAD(当前提交)。这是git命令的常见模式(例如,checkout, diff, log,尽管确切的语义有所不同),所以它不应该太令人惊讶。
例如,git reset other-branch path/to/foo将路径/to/foo中的所有内容重置为其在other-branch中的状态,git reset——。将当前目录重置为其在HEAD中的状态,简单的git重置将所有内容重置为其在HEAD中的状态。
主要工作树和索引选项
有四个主要选项来控制重置期间工作树和索引的变化。
请记住,索引是git的“暂存区”——当你说git添加准备提交时,它就是东西所在的地方。
--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 means git 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 any reset --hard. --mixed is the default, i.e. git reset means git 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 as changes 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 because git 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 as git reset --merge (meaning git 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 in HEAD, but leaves your modifications to A and B alone, since they weren't part of the attempted merge.
想知道更多吗?
我确实认为男人git重置真的很好-也许你确实需要一点git工作方式的感觉,让他们真正沉浸其中。特别是,如果你花时间仔细阅读它们,那些详细描述索引和工作树中所有不同选项和情况的文件状态的表是非常非常有用的。(但是,是的,它们非常密集——它们以非常简洁的形式传达了大量上述信息。)
奇怪的符号
您提到的“奇怪的符号”(HEAD^和HEAD~1)只是指定提交的一种简写,而不必使用像3ebe3f6这样的散列名称。它在git-rev-parse手册页的“指定修订”部分中有完整的文档,其中有许多示例和相关语法。插入号和波浪号实际上有不同的含义:
HEAD~ is short for HEAD~1 and means the commit's first parent. HEAD~2 means the commit's first parent's first parent. Think of HEAD~n as "n commits before HEAD" or "the nth generation ancestor of HEAD". HEAD^ (or HEAD^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 in HEAD~3^2, the second parent of the third-generation ancestor of HEAD, HEAD^^2, the second parent of the first parent of HEAD, or even HEAD^^^, which is equivalent to HEAD~3.
博士TL;
git reset重置Staging到最后一次提交。使用——很难将工作目录中的文件重置到最后一次提交。
完整版
但这显然过于简单,因此会有许多相当啰嗦的答案。对我来说,在撤销更改的上下文中阅读git重置更有意义。请看这个:
如果git恢复是一种“安全”的方法来撤销更改,您可以考虑git 复位为危险方法。当你撤销与git重置(和 提交不再被任何ref或reflog引用),有 无法检索原始副本—这是永久撤销。护理必须 在使用这个工具的时候,你可能会遇到这样的问题,因为它是唯一一个有可能丢失你的工作的Git命令。
从https://www.atlassian.com/git/tutorials/undoing-changes/git-reset
这
在提交级别,重置是一种将分支的尖端移动到不同提交的方法。这可用于从当前分支删除提交。
从https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting/commit-level-operations
签出将头部指向特定的提交。
重置在特定提交时指向一个分支。(分支是指向提交的指针。)
顺便说一句,如果你的头没有指向分支也指向的提交,那么你就有了一个分离的头。(结果证明是错的。看到评论…)
记住在git中你有:
HEAD指针,它告诉你你在做什么提交 工作树,它表示系统上文件的状态 暂存区(也称为索引),它“暂存”更改,以便稍后可以一起提交
请详细说明: ——硬,——软,——融合;
按危险程度递增:
-轻轻移动头部,但不触及集结区或工作树。 mixed移动HEAD并更新暂存区,但不更新工作树。 ——merge移动HEAD,重置暂存区域,并尝试将工作树中的所有更改移动到新的工作树中。 -hard移动HEAD,调整你的集结区和工作树到新的HEAD,扔掉所有东西。
具体的用例和工作流;
当你想要转移到另一个地方,修补事情而不“失去你的位置”时,使用-软。你很少需要这个。
--
# git reset --soft example
touch foo // Add a file, make some changes.
git add foo //
git commit -m "bad commit message" // Commit... D'oh, that was a mistake!
git reset --soft HEAD^ // Go back one commit and fix things.
git commit -m "good commit" // There, now it's right.
--
当您想要查看另一次提交时的情况,但又不想丢失已有的任何更改时,请使用——mixed(这是默认值)。 使用—合并当你想移动到一个新的点,但合并你已经有到工作树的变化。 使用——在新的提交时很难清除所有内容并重新开始。
博客Pro Git中的Reset Demystified给出了一个关于Git重置和Git checkout的非常简单的解释。
在那篇文章的顶部进行了有益的讨论之后,作者将这些规则简化为以下简单的三步:
基本上就是这样。reset命令以特定顺序覆盖这三棵树,当您命令它停止时停止。 移动HEAD指向的分支(如果—软) 然后,让索引看起来像这样(停止在这里,除非——很难) 然后,让工作目录看起来像这样 还有“合并”和“保留”选项,但我现在宁愿让事情简单一些——这将是另一篇文章。