损坏的Git代码库

3

我最近继承了一个项目,发现git仓库树已经破损。enter image description here

第一个蓝色的提交包含整个应用程序的所有代码以及提交中的一些更改。

我有两个问题:

  1. 这种状态是如何产生的?
  2. 是否可能修复这个树呢?也许把蓝色子分支的头推到红色主分支上?

任何想法都将不胜感激。


4
要创建这样的分支(现在),您可以使用 git branch --orphan 命令,它通常被称为“无关分支”。您可以将它们合并起来,但必须指定 --allow-unrelated-histories 参数。 - Lasse V. Karlsen
2
你的视图设置为日期或祖先顺序了吗? - LightBender
视图设置为祖先顺序。 - remudada
尝试合并时,Git出现了100个冲突。是否可以将这棵蓝色的树强制覆盖在旧的红色树上? - remudada
1
@LasseVågsætherKarlsen:git checkout --orphan(后跟新提交);不是 git branch --orphan。允许不相关历史记录标志在 Git 2.9 中是新的;在此之前,git merge 对不相关的历史记录只是耸了耸肩,无论如何都会合并。 - torek
1个回答

2

使用 git filter-branch 可以将不相关的历史记录合并在一起。以下是来自 manpage 的摘录:

To set a commit (which typically is at the tip of another history) to be the
parent of the current initial commit, in order to paste the other history behind
the current history:

    git filter-branch --parent-filter 'sed "s/^\$/-p <graft-id>/"' HEAD

(if the parent string is empty - which happens when we are dealing with the
initial commit - add graftcommit as a parent). Note that this assumes history
with a single root (that is, no merge without common ancestors happened). If
this is not the case, use:

    git filter-branch --parent-filter \
            'test $GIT_COMMIT = <commit-id> && echo "-p <graft-id>" || cat' HEAD

or even simpler:

    git replace --graft $commit-id $graft-id
    git filter-branch $graft-id..HEAD

在您的情况下,$commit-id 是第一个蓝色提交,$graft-id 是最后一个红色提交。
以下是完整过程的示例:
让我们创建一个仓库和一些红色提交:
$ git init
$ echo a >a
$ git add a
$ git commit -m c1
[master (root-commit) 6a6b98f] c1
 1 file changed, 1 insertion(+)
 create mode 100644 a
$ echo b >>a
$ git add a
$ git commit -m c2
[master d91d385] c2
 1 file changed, 1 insertion(+)

现在创建一个不相关的分支 o1,并添加一些蓝色提交:
$ git checkout --orphan=o1
Switched to a new branch 'o1'
$ echo c >>a
$ git add a
$ git commit -m c3
[o1 (root-commit) ed2b106] c3
 1 file changed, 3 insertions(+)
 create mode 100644 a
$ echo d >>a
$ git add a
$ git commit -m c4
[o1 5b655a6] c4
 1 file changed, 1 insertion(+)

检查我们得到了想要的内容:

$ git log --format=short --graph --all
* commit 5b655a615f8a729c123d89180ca1928451b465b2 (HEAD -> o1)
| 
|     c4
| 
* commit ed2b106d7bd0ffef317a723f2921808bc8ad9f45

      c3

* commit d91d385c7811ba07f4092133c435b55323562686 (master)
| 
|     c2
| 
* commit 6a6b98fca7150839f607d9d55c6b9f10861375f8

      c1

ed2b106(c3,第一个蓝色)创建一个嫁接提交,以d91d385(c2,最后一个红色)作为其新的父提交:

$ git replace --graft ed2b106d7bd0ffef317a723f2921808bc8ad9f45 d91d385c7811ba07f4092133c435b55323562686
$ git log --format=short --graph --all
* commit 5b655a615f8a729c123d89180ca1928451b465b2 (HEAD -> o1)
| 
|     c4
| 
* commit ed2b106d7bd0ffef317a723f2921808bc8ad9f45 (replaced)
| 
|     c3
|   
| * commit 4656e5bca003770b1a35aff10e3ffb51f7fb1ad9
|/
|       c3
| 
* commit d91d385c7811ba07f4092133c435b55323562686 (master)
| 
|     c2
| 
* commit 6a6b98fca7150839f607d9d55c6b9f10861375f8

      c1

我们得到了一个带有固定父级的替代品4656e5b(修复c3),但是这个替代品只是本地的,所以我们现在需要重写所有蓝色的提交:

$ git filter-branch d91d385c7811ba07f4092133c435b55323562686..HEAD
Rewrite 5b655a615f8a729c123d89180ca1928451b465b2 (2/2) (0 seconds passed, remaining 0 predicted)    
Ref 'refs/heads/o1' was rewritten
$ git log --format=short --graph
* commit 2cf6b0d3a0ee2deff99bbe327d065f90c82c1c2b (HEAD -> o1)
| 
|     c4
| 
* commit 4656e5bca003770b1a35aff10e3ffb51f7fb1ad9
| 
|     c3
| 
* commit d91d385c7811ba07f4092133c435b55323562686 (master)
| 
|     c2
| 
* commit 6a6b98fca7150839f607d9d55c6b9f10861375f8

      c1

4656e5b(修正的c3)已经很好了(与ed2b106,原始的c3相同,只是有不同的父级),但是5b655a6(c4)被重写,以便其父级为4656e5b(修正的c3),而不是ed2b106(原始的c3)。现在我们可以安全地删除替换,因为ed2b106在我们的历史记录中不再使用:

$ git replace -d ed2b106d7bd0ffef317a723f2921808bc8ad9f45
Deleted replace ref 'ed2b106d7bd0ffef317a723f2921808bc8ad9f45'

2
值得指出的是,这样做会导致一个新的和不同的存储库(从移植点开始不同),这基本上意味着每个使用克隆的人都必须丢弃他们的旧克隆并获取一个新的。 - torek
哇!那真是太有帮助了! - remudada
我完成了所有步骤,一切都运行得很完美。谢谢!我的 Git 树不再出现问题了! - remudada

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接