git重置两个分支的diff中的所有提交

时间:2014-08-12 15:36:14

标签: git github version-control

与其他人合作时,我通常的工作流程是创建一个功能分支,并让双方都对此分支进行更改。在一起工作时,通常会有无意义的提交,就像'嘿,我做了这个小小的改变,你觉得怎么样?'但是,在我们PR之前将它合并为master之前,我会在开始工作之前回到第一个提交git reset,并将历史分成合理的逻辑块。

然而,这次某位同事合并为主人,使我们的历史难以理解。或者至少我现在无法git reset,因为我们的提交不再是连续的。

我们的分支是master的超集,只有额外的提交。我想删除所有这些提交但离开工作,允许我将更改提交到逻辑块。

思想?

3 个答案:

答案 0 :(得分:2)

我发现你的描述比照亮更令人困惑。特别是,合并的存在(或缺乏)不是git reset的障碍。 git reset做的是更改当前分支指向的提交ID。

每当你进行任何提交(甚至是合并)时,git只会向您的存储库添加 new 提交。每个提交都有自己的SHA-1 ID,这是其真正的名称" (该提交具有该ID,该ID 表示提交,并且没有其他人将使用该ID)。每个提交还包含其父(其中一个或多个)的ID。合并只包含至少两个父ID,而常规提交只有一个父ID。我们可以说这些父母ID"指回"到父提交,因此我们可以绘制提交图:

A <- B <- C          <-- master
           \
            D <- E   <-- feature

右边的名称是分支标签,git通常 1 通过包含每个分支的tip的SHA-1 ID的文件来实现。也就是说,master的文件具有C的SHA-1,而feature的文件在此处具有E的SHA-1。

对于这张图片,我们应该添加HEAD,这基本上只是一个文件git用来保存&#34;当前分支的名称&#34;:

A <- B <- C          <-- master
           \
            D <- E   <-- HEAD=feature

现在可以非常简单地将<{1}}描述为 2 :&#34;读取HEAD以查看要更改的分支,然后更改存储在该分支中的SHA-1 ID& #39; s文件到git reset命令行上给出的commit-ID。&#34;因此,如果git resetHEADfeature说&#34;提交master&#34;,那么:

C

告诉git:&#34;将git reset [options] master 的ID写入C&#34;。 (feature部分使[options]执行更多或更少的操作,例如更新索引和/或工作树,或跳过这些更新。)

(当您通过branch-name或resetgitrevisions允许的任何名称命名提交时,git只会将其转换为提交ID。要查看此操作,使用HEAD~2,将名称转换为commit-ID:

git rev-parse

等等。)

要进行新的提交,git会将新提交写入存储库,将其父ID设置为当前(git rev-parse HEAD git rev-parse master git rev-parse feature^ )提交的ID(并使用&#34的暂存区域;进入这个提交&#34;)。然后它将新提交的ID写入当前分支文件,并且全部完成!只需将新的提交ID写入分支文件即可扩展分支。

为了便于说明,我们将合并提交添加到HEAD。首先,我们需要向feature添加更多提交,除非我们正在合并另一个分支。然后我们将添加合并提交master。我要停止画箭头,只记得它们指向左边(可能是左边和右边等)。

M

此处,提交A - B - C - F - G <-- master \ \ D - E - M <-- HEAD=feature 是一个合并提交,因为它有两个父项:MEG分支文件包含feature的ID。但是M的工作方式与以往一样:如果我们告诉git reset指向提交feature,则提交DE将变为不可见(尽管他们还在那里)我们所看到的就是:

M

A - B - C - F - G <-- master \ D <-- HEAD=feature E的幽灵版本默认至少保留一个月,保存在git&#34; ref-logs&#34; (如果您使用Mgit reflog,您实际上可以看到它们。但他们不再是&#34;在#34; git log -g分支,现在以提交feature结束,因为我们已经D

摘要

  • 每个提交都指向其父级。
  • 合并提交指向多个父母。
  • git分支名称只是指向分支的 tip ,即分支上应该被视为&#34;的最后一次提交&#34;。该ID只存储在适当的分支文件中。
  • git reset告诉git你在哪个分支。
  • 新提交执行HEAD以获取其父ID,然后将其新的提交ID写入分支文件。新的合并提交执行相同的操作,除了它们记录git rev-parse HEAD ID 合并分支的ID。
  • HEAD(现有)commit-ID写入当前分支。使用git reset,它还会更新索引/登台区域和工作树。 (--hard只有分支和索引,而--mixed只有分支。)

请注意,如果您使用--softgit reset倒回到C,然后开始执行新的feature,则只需添加新的提交,就像之前一样。它们与您之前添加的提交具有不同的ID,因此图形如下所示:

git commit

(我跳到A - B - C <-- master | \ \ D - E <-- [old feature, via reflog] \ X - Y <-- feature ,以便明确说明这些与上面的XF等不同。)


1 更具体地说,标签可以打包&#34;,这样一堆标签都可以共享一个文件。

2 也许有点简单,因为G也可以选择性地更新索引/登台区域和/或工作树。

答案 1 :(得分:0)

你的工作流程很糟糕:) 而不是重置和重做作业(我不知道你如何“清理”历史)你应该使用 rebase 命令。

此处的一部分,要恢复合并,您只需将头重置为功能分支的最后一次提交。所以得到最后一次提交的sha1(不是合并提交的id,而是普遍的提交)并且执行

git reset --hard shaidofthecommit

此时,分支的头部将重置为该提交,您将放弃合并提交。

答案 2 :(得分:0)

对于未来的人们,我发现解决我的问题的最好方法是只修改master和我自己之间的差异,然后将更改应用到新分支,然后PR。通过这种方式,我可以获得所有更改,但可以稍微清理一下历史记录。

git diff --binary master my-branch > ../thing.patch

然后

git apply ../thing.patch

我知道我的问题有点不稳定,我的解决方案也是如此。但是,希望这将有助于将来的某个人。