合并到与已删除分支同名的分支后缺少提交

时间:2014-02-04 19:50:57

标签: git

在将功能分支合并到与功能分支来自现在已删除分支同名的分支后,我们缺少一些提交。

为了更清楚一点,这是事件的顺序:

  1. 我们有一个根与Root分支的生产支持的回购
  2. 我从生产支持分支到创建功能分支
  3. 时间已过,工作已在功能分支
  4. 中完成
  5. 有人删除了生产支持分支,并从根
  6. 重新创建了一个名称相同的新分支
  7. 我将新的生产支持分支撤回到本地
  8. 然后我将功能分支合并到生产支持
  9. 完成合并后,我在功能分支中缺少生产支持中的提交。

    编辑:合并后,我错过了一些但不是所有来自Prod支持中的功能分支的提交。

    我是否认为删除生产支持部门可能会导致此问题?或者我应该去别处看看?

3 个答案:

答案 0 :(得分:2)

合并不会删除提交。合并要么添加提交,要么在“快进”合并的情况下,只需“向前滑动标签”。

我发现提交图的图纸,甚至(或者可能是“特别”)简化的图表,帮助很多。

根据你的描述你有类似的东西:

..- o - o - o - o - o - o       <-- root
              \
                o - C - P       <-- production_support
                      \
                        o - o   <-- feature

其中每个o是一个“无趣的”提交(或者甚至可能是相当多的提交),而大写字母是我打算在下面讨论的提交,所以我给了它们字母名称。< / p>

这里有三个分支,其分支标记为rootproduction_supportfeature。提交Cproduction_supportfeature共有的提交,提交P只能通过branch-tip-label production_support访问。

同样,根据您的描述,有人删除了分支标签production_support。该图现在看起来像这样:

..- o - o - o - o - o - o       <-- root
              \
                o - C - P       [no label - abandoned]
                      \
                        o - o   <-- feature

提交P现在无法访问,除非通过git的“reflogs”,它会记录标签用于指向的位置。

删除标签时删除分支标签production_support的reflog,这样就没有帮助;但至少在一个存储库中,在提交P时,它是在HEAD以及production_support上创建的。那个特定的HEAD-reflog-entry可以保护P一段时间(默认为30天)。

一旦提交的最后一个引用消失,提交就有资格进行垃圾回收。因此,如果没有其他任何内容挂起来提交P,它将与其他垃圾一起收集并丢弃。

回到你的描述,在上面发生之后(也可能在P被垃圾收集之后),有人做了一个新的分支标签,拼写方式与旧的分支标签相同,然后提交了在那里,将图片改为这样的:

                            o   <-- production_support
                          /
..- o - o - o - o - o - o       <-- root
              \
                o - C
                      \
                        o - o   <-- feature

然后你做了:

$ git checkout production_support && git merge feature

它创建了一个新的合并提交M(图形现在变得非常混乱:-) ...我们可以重绘它,但这可能同样糟糕,在这一点上):

                            o - M <-- production_support
                          /    /
..- o - o - o - o - o - o   <-------- root
              \               |
                o - C         |
                      \      /
                        o - o   <---- feature

确实提交P(仍然)无处可见,但这不是因为合并。合并刚刚添加了一个新的提交M,有两个父母。 M的第一个父级是旧的分支提示(o左侧的M; production_support现在指向M而是第二个parent是合并提交(feature指向的提交。)

要返回提交P,如果它完全存在(没有被垃圾收集),你必须通过branch-label-name之外的其他方式找到它,因为当分支标签时它就消失了production_support首先被删除。查看创建它的存储库中的HEAD reflog,或使用git fsck查看是否存在可以通过添加标签(例如分支或标记名称)来恢复的“悬空提交”他们。

在这种特殊情况下,提交PC作为其直接祖先,如果您发现SHA-1 ID提交并认为可能为{{ 1}},你可以通过查看它和它的父母来检查。例如:

P

这将显示“might-be-P”及其父项的日志,如果提交$ git fsck ... dangling commit de7c26f2b124f0038ab0ed03da9cb47647fc9867 ... $ git log de7c26f2b124f0038ab0ed03da9cb47647fc9867 显示可能是它。或者,您可以通过收集所有候选项,查找提交C的原始SHA-1以及比较每个候选项的父项来自动化它:

C

(未经过实际测试,可能包含拼写错误或类似内容)。

如果$ id_for_c=... # find SHA-1 for commit C, put that in here $ for id in $(cat /tmp/candidates); do > [ $(git rev-parse ${id}^) = $id_for_c ] && echo "likely match: ${id}" > done 确实代表了一系列提交,那么检查P作为直接父级将是毫无意义的(您需要知道找回C的距离)但是您仍然可以进行血统测试(请参阅C的{​​{1}}选项。)

答案 1 :(得分:2)

好的,每个人(我们所有人:-))都将这个问题解释为“查看提交图,我希望成为合并提交的祖先的一些提交,不是合并提交的祖先”。但那不是你要问的。你的意思是“我做了一个合并,似乎进展顺利,但现在合并的内容并不是我所期望的。”

让我们快速了解一下合并的机制,特别是它在git中的完成方式。让我们从这个提交DAG开始,基本上与我的其他答案中的相同,但我会略有不同。我还将小o个节点更改为*,以便首都 - O节点更加明显。

..- * - * - B - * - * - *   <-------- root
              \           \
                \           O   <---- production_support
                  \
                    * - * - T   <---- feature

要合并这些,请运行:

$ git checkout production_support; git merge feature

重要:我假设此处没有--strategy=ours-X ours个参数。

要进行合并,git需要识别三个特定的提交:“O urs”,“T继承人”和“B ase”。提交O只是当前分支的提示,即production_support指向的提交(因为这是您在开始合并时检出的内容)。提交T来自git merge的参数,而且只是提交本身。

提交B是棘手的。 Git需要为两个分支找到“merge-base”。为此,它从两个已识别的提交中倒退,以找到“最佳共同祖先”。在这样一个简单的图中,“最常见的祖先”是第一个共同的祖先:很明显,两个分支在B分歧,所以它们在B - 和 - 之前是相同的永远不同以后。 (在具有多个交叉点的复杂图形中,有时没有明显的最佳共同祖先。有关详细信息,请参阅the git-merge-base documentation。)

找到三个提交后,git会对三个提交进行标准的三向合并(例如,参见三向合并的Stack OverflowWikipedia描述)。但是,嘿,等等,等一下。 : - )

三向合并适用于文件,而不适用于提交。 git在这里做的是查看三次提交中的所有文件。实际上,它会“检出”所有三次提交BOT。 (它们分别在内部编号为-1,2和3,并且在冲突的情况下实际显示在索引/登台区域中。请参阅gitrevisions及其:n:path语法。) Git还应用了它的重命名检测逻辑 - 就像你在两次提交时运行git diff时看到的那样 - 猜测基本版本中的文件data-format.txt现在是否被命名为doc/data-format.txt例如,在OT中。运行重命名检测并确定基本data-format.txt与“他们的”data-format.txt相同,但现在在“我们的”版本中称为doc/data-format.txt,git执行三个 - 合并这三个,使用“我们的”版本中的名称作为“最终”名称。

Git会自动检测一些冲突,并强迫你进行合并,解决这些冲突。但是不能保证它会自动检测每个冲突......如果代码库“过多”分歧,它可能会错误检测或不检测各种文件重命名。它总是总是由你来做,合并的人,检查合并结果是否合理, git是否能够自动解决冲突。例如,如果有人向文件A添加了一个文本块,而另一个人从文件B中删除了一个文本块,那么git可以轻松地合并它 - 但是如果文件A中的新文本是文件B中的内容的描述,你现在已经对不再存在的东西进行了描述。

还有一种替代方法(git-imerge,一种“渐进式”合并)理论上应该(我还没有测试过)在历史逐渐分化的情况下帮助很多。根据各种文件的修改方式,这仍然可能无法帮助您。实际查看提交本身是无可替代的。

在任何情况下,如果您不喜欢合并的结果,即与新提交M相关联的工作树:

..- * - * - B - * - * - *   <-------- root
              \           \
                \           O - M <-- production_support
                  \           /
                    * - * - T   <---- feature

你可以(只要你没有push编辑这个)(逻辑提交M保留在存储库中,由reflog引用,如其他答案中所述)删除它,使用git reset --hard production_support^,使production_support再次指向提交O。然后,您可以重新执行git merge(如果需要,可以使用--no-commit)并在这次修复工作树,并git add生成的文件然后git commit

答案 2 :(得分:1)

让我先警告你:我不是Git的专家。由于我自己的愚蠢(嗯,就是:尝试使用Git而不阅读手册......)我碰巧“失去”了一些东西,并且不得不以某种方式恢复它们。任何提示/描述都是非正式的。你必须阅读更多关于我在下面说的话

-

根据您提供的事件顺序,我想:

  • old Prod分支有hash = AAAA
  • 新的Prod分支有hash = BBBB!= AAAA
  • 您首先将功能合并到Prod中,然后使用newProdBranch将已更换的Prod分支更改为已拉出的

如果我是对的,你真的第一次合并,那么拉拉,那么你当地的Git还不知道新的分支。它将功能合并为AAA。然后你拉了,删除了AAA并创建了BBB。

如果是这样,你现在的目标是找到丢失的AAA分支并用“Prod”之外的某个名称重命名/标记它,现在它指向BBB。然后,您将能够将ProdOld中的更改移动/复制/等等到NewProd。

-

如果您在本地合并了分支,那么您仍然可以恢复它。通常,Git不会立即删除内容。您可能仍然拥有本地“工作副本”上的所有内容,它可能只是“分离/孤立”。它失去了它的名字并且没有连接,因此看不见,但是如果你知道它的HASH,那么你可以像普通的“生活”分支那样简单地检查它。

..好吧,当然除非你在此期间删除并重新克隆它。或以任何其他方式清理/修剪/ GC,这将导致孤立的条目被永久删除..

首先,尽可能多地记住丢失的提交。记录消息,日期,ID /哈希值?

如果你知道哈希,那很好,请跳到下一点。 如果您不知道哈希值,但记得日志消息,日期或任何有用的内容,请尝试reflog命令。它将向您显示存储库中任何分支的任何提示的所有“最近”更新。 Git经常会记住旧条目一段时间。即使他们被遗弃/删除/丢失,他们仍然可能坐在那里。只需运行

git reflog

在您进行合并的本地工作目录中 它会告诉你一些提交,最重要的是 - 它们的哈希值。如果你不知道丢失的提交的哈希 - 现在你可以学习它们。

如果reflog没有它们,我不知道该怎么办。我记得我读到有另一个较低级别的机制可以让你失去哈希,但我不记得那是什么,对不起。

假设您现在拥有丢失提交的哈希值:

明确地检查出来:

git checkout a76sa7..THE_HASH_HERE

即使提交“丢失”,如果只有git repo还没有'pruned / GC'ed',提交将被提取,当前提示将指向它。现在从中创建一个分支,只是为了标记它并防止被修剪/ GCed,例如:

git branch temp_restoring_commit

新分支temp_restoring_commit将标记提交以便于参考。从现在开始,您可以将提交视为“已恢复且安全”,除非您删除分支,否则它将不会消失。 (当然,仍然可以通过reflog再次帮助你)

现在,您可以尝试:

  • 将提交合并到其他位置(将更改复制/移植到另一个分支)
  • 重新提交提交(字面将丢失的提交连接到正确的分支)
  • 将其推送到远程仓库,以便其他人可以为您清理它:)

正如我所说,当我在本地删除一个尚未推向生产的分支时,我已经做了几次。我很幸运,因为“损坏”是新的,当地的回购还没有“清理”。如果您的本地仓库不再记住这些提交,您可以将实时连接到Prod仓库并尝试reflog /分支,但我的知识在此处结束。只是不要尝试克隆远程仓库 - 它不会像旧的未连接的丢失提交那样获取“垃圾”。您需要将手放在“脏”的存储库中。