删除虚假提交父指针

时间:2013-01-09 19:26:33

标签: git merge git-rebase

我将一个Bazaar存储库导入Git(使用git bzr),但生成的存储库包含一个虚假的提交父链接:

Spurious parent link

请注意,标记为1.02-6的提交基于1.02-3提交,但1.02-1也不必要地标记为父级。 (注意:repo的这一部分中的所有提交都被标记;显示的提交之间没有提交。)

我尝试过几种方式的变基(在master分支上:git rebase 1.02-3git rebase -i upstream-1.02git rebase --onto 1.02-1 1.02-3git rebase --root upstream-1.02 --onto=other_branch),但在每种情况下都是合并冲突失败。这似乎是在尝试超过必要的;历史记录正确除了,在提交标记1.02-6中记录了额外的父指针。

如何删除链接以便对历史进行线性化?有没有比按顺序手动挑选所有提交更好的方法?

4 个答案:

答案 0 :(得分:16)

最简单的方法(使用git> = 1.6.5)是使用:

def simple_cull(inputPoints, dominates):
    paretoPoints = set()
    candidateRowNr = 0
    dominatedPoints = set()
    while True:
        candidateRow = inputPoints[candidateRowNr]
        inputPoints.remove(candidateRow)
        rowNr = 0
        nonDominated = True
        while len(inputPoints) != 0 and rowNr < len(inputPoints):
            row = inputPoints[rowNr]
            if dominates(candidateRow, row):
                # If it is worse on all features remove the row from the array
                inputPoints.remove(row)
                dominatedPoints.add(tuple(row))
            elif dominates(row, candidateRow):
                nonDominated = False
                dominatedPoints.add(tuple(candidateRow))
                rowNr += 1
            else:
                rowNr += 1

        if nonDominated:
            # add the non-dominated point to the Pareto frontier
            paretoPoints.add(tuple(candidateRow))

        if len(inputPoints) == 0:
            break
    return paretoPoints, dominatedPoints

def dominates(row, candidateRow):
    return sum([row[x] >= candidateRow[x] for x in range(len(row))]) == len(row)  

import random
inputPoints = [[random.randint(70,100) for i in range(3)] for j in range(500)]
paretoPoints, dominatedPoints = simple_cull(inputPoints, dominates)

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
dp = np.array(list(dominatedPoints))
pp = np.array(list(paretoPoints))
print(pp.shape,dp.shape)
ax.scatter(dp[:,0],dp[:,1],dp[:,2])
ax.scatter(pp[:,0],pp[:,1],pp[:,2],color='red')

import matplotlib.tri as mtri
triang = mtri.Triangulation(pp[:,0],pp[:,1])
ax.plot_trisurf(triang,pp[:,2],color='red')
plt.show()

并删除/添加/更改Parent:行。

一旦你感到高兴,改变是正确的,你可以重写提交以使改变永久化:

git replace --edit <sha>

答案 1 :(得分:5)

您可以使用git commit-tree内部命令手动执行此操作。

我们要编辑提交标记1.02-6以删除虚假父指针(56a2f3b5948ab54c9239c2b384a6ea9eb1f410c4)。

首先,从现有提交对象中读取信息:

user@host:/path/repo.git$ git cat-file -p 1.02-6 
tree c658aa1ebcf2bf2a607696c7868b875be72fb01f
parent 56a2f3b5948ab54c9239c2b384a6ea9eb1f410c4
parent 4e671bf1d2298729c9e5cfd8229051cfe2c40831
author James Damour (Suvarov454) <suvarov454@users.sourceforge.net> 1146319620 -0400
committer Bazaar Package Importer <james.westby@ubuntu.com> 1146319620 -0400

The "main/" in the Section line of debian/control should be assumed.

Extract the commit message using git log --format=%B -n 1 1.02-6.

现在创建一个具有相同内容的新提交(不包括虚假父链接和提交者信息):

git log --format=%B -n 1 1.02-6 | \
    GIT_AUTHOR_NAME="James Damour (Suvarov454)" \
    GIT_AUTHOR_EMAIL="suvarov454@users.sourceforge.net" \
    GIT_AUTHOR_DATE="1146319620 -0400" \
    git commit-tree c658aa1ebcf2bf2a607696c7868b875be72fb01f \
        -p 4e671bf1d2298729c9e5cfd8229051cfe2c40831

这创建了一个新的提交,并打印了它的哈希值(cc32e66 ...)。现在把它变成一个新的分支:

git checkout -b fixed_commit cc32e66

并将master重新加入新分支:

git checkout master
git rebase fixed_commit

我们已经完成了:

Finished

您可能希望删除旧分支并重新标记相应的提交。


实际上使用git filter-branch --parent-filter可能更容易。我没试过。

答案 2 :(得分:2)

这将纠正父母而不改变任何其他内容(例如提交者日期):

git filter-branch --tag-name-filter cat --parent-filter 'test $GIT_COMMIT = [sha of 1.02-6] && echo "-p [sha of 1.02-3]" || cat' -- 1.02-1..master

您必须使用适当的提交ID替换括号内的文本。如果您有更多需要重写的下游分支,请将1.02-1..master更改为--all并准备等待。

当然,如果其他人已经在您要编辑的提交之后的任何提交中分支,请不要使用此解决方案或任何其他解决方案。他们会讨厌你。

答案 3 :(得分:1)

您可以尝试rebase。有一个例子有点下来(搜索--onto),我认为这与你的情况类似。

认为你需要做

git rebase --onto 1.02-1 1.02-3

应该将1.02-3之后的所有内容放到1.02-1上,这可能是你想要的。

请记住,哈希在第一次更改提交时的所有内容都会有所不同,但我认为你这样做是作为从bzr迁移的第一步,所以没有其他人应该克隆它。