繁体   English   中英

在 Git 中的根提交之前插入非空提交?

[英]Insert a NON-EMPTY commit before the root commit in Git?

我有问题,请多多指教! 我有一个现有的 git repo,出于各种原因(我不会在这里讨论),我正在尝试创建一个 ROOT 提交

说这是我的 git 提交历史:

(ROOT) C1 <-C2 <-C3 <-C4 <-C5   <--branchname (HEAD)

我想在 C1 之前添加一个初始提交(CX,它不是空的)。 所以它应该像这样结束:

(NEW ROOT) CX-C1 <-C2 <-C3 <-C4 <-C5   <--branchname (HEAD)

我在这里发现了一个类似的问题: 在 Git 中的根提交之前插入提交? 但它用于在现有根目录之前附加一个 EMPTY git commit。 我还尝试了此处答案中的步骤: https : git commit --allow-empty -m 'initial'了一项更改:我将git commit --allow-empty -m 'initial'替换为git add .; git commit -m "initial laravel commit"; git push; git add .; git commit -m "initial laravel commit"; git push; 然后这个 rebase 步骤: git rebase --onto newroot --root master因大量合并冲突而失败:

First, rewinding head to replay your work on top of it...
Applying: add initial quickadminpanel, with admin intrface and APIs for tags. Also added (but not yet enabled) ajax datatables module
Using index info to reconstruct a base tree...
.git/rebase-apply/patch:4537: trailing whitespace.
     * 
.git/rebase-apply/patch:4539: trailing whitespace.
     * 
.git/rebase-apply/patch:4547: trailing whitespace.
     * 
warning: 3 lines add whitespace errors.
Falling back to patching base and 3-way merge...
CONFLICT (add/add): Merge conflict in webpack.mix.js
Auto-merging webpack.mix.js
CONFLICT (add/add): Merge conflict in routes/web.php
Auto-merging routes/web.php
CONFLICT (add/add): Merge conflict in routes/api.php
Auto-merging routes/api.php
CONFLICT (add/add): Merge conflict in resources/views/welcome.blade.php
Auto-merging resources/views/welcome.blade.php
CONFLICT (add/add): Merge conflict in resources/sass/app.scss
Auto-merging resources/sass/app.scss
CONFLICT (add/add): Merge conflict in resources/sass/_variables.scss
Auto-merging resources/sass/_variables.scss
CONFLICT (add/add): Merge conflict in resources/lang/en/validation.php
Auto-merging resources/lang/en/validation.php
CONFLICT (add/add): Merge conflict in resources/lang/en/passwords.php
Auto-merging resources/lang/en/passwords.php
CONFLICT (add/add): Merge conflict in resources/lang/en/pagination.php
Auto-merging resources/lang/en/pagination.php
CONFLICT (add/add): Merge conflict in resources/lang/en/auth.php
Auto-merging resources/lang/en/auth.php
CONFLICT (add/add): Merge conflict in resources/js/bootstrap.js
Auto-merging resources/js/bootstrap.js
CONFLICT (add/add): Merge conflict in resources/js/app.js
Auto-merging resources/js/app.js
CONFLICT (add/add): Merge conflict in package.json
Auto-merging package.json
CONFLICT (add/add): Merge conflict in database/seeds/DatabaseSeeder.php
Auto-merging database/seeds/DatabaseSeeder.php
CONFLICT (add/add): Merge conflict in database/migrations/2014_10_12_100000_create_password_resets_table.php
Auto-merging database/migrations/2014_10_12_100000_create_password_resets_table.php
CONFLICT (add/add): Merge conflict in database/factories/UserFactory.php
Auto-merging database/factories/UserFactory.php
CONFLICT (add/add): Merge conflict in database/.gitignore
Auto-merging database/.gitignore
CONFLICT (add/add): Merge conflict in config/services.php
Auto-merging config/services.php
CONFLICT (add/add): Merge conflict in config/logging.php
Auto-merging config/logging.php
CONFLICT (add/add): Merge conflict in config/database.php
Auto-merging config/database.php
CONFLICT (add/add): Merge conflict in config/cache.php
Auto-merging config/cache.php
CONFLICT (add/add): Merge conflict in config/broadcasting.php
Auto-merging config/broadcasting.php

我该如何解决这个问题? 请帮忙!

首先,附注:您已将存储库向前绘制。 Git 反过来做。 将根提交放在最后,即放在左侧,将最新的提交放在最前面,即放在右侧:

C1 <-C2 <-C3 <-C4 <-C5   <--branchname

分支名称始终包含最新提交的哈希 ID。 这就是 Git 知道哪一个最新的。 Git 使用C5来查找C4 ,因为提交C5本身具有唯一的哈希 ID,包含提交C4的唯一哈希 ID。 同时C4持有C3的哈希 ID,依此类推; C2持有C1的唯一哈希 ID,而C1根提交,因为它内部没有父哈希 ID。

其次,实际上不能更改任何提交。 所以你在这里要做的不是“更改提交C1 ”——你和 Git 都不能这样做——而是进行一个新的提交, C1'C21或我们想称之为的任何东西。 在这个新提交之前,我们需要另一个新提交CX ,它是一个根提交并包含所需的内容。

可以使用Antony Hatchkins 的回答中的方法,但是现在,这样做的方法是从git checkout --orphan (而不是棘手的符号引用命令)开始:

git checkout --orphan newroot
git rm -rf --cached .            # same as before
<arrange work tree as desired>   # same as before
git add .                        # or git add each file, same as before
git commit                       # same as before

这是创建提交CX的操作序列,因此我们有:

C1--C2--C3--C4--C5   <-- master

CX   <-- newroot

现在我们进入最有趣的部分。 使用git rebase是错误的方法,因为rebase 是通过挑选来工作的。 这将提交C1变成添加每个文件的请求——提交C1作为根提交,与空树进行比较以查看更改的内容——正如您所见,这会导致您添加/添加每个文件的冲突添加在已经在CX中的C1中。

你必须回答的问题在这里,我不能为您一一解答,就是:要在新的副本,哪些内容C1就是喜欢C1除了它具有CX作为其父? 也就是说,最终,我们将拥有:

C1--C2--C3--C4--C5    [abandoned]

CX--C1'-C2'-C3'-C4-C5'   <-- master

在我们的存储库中。 如果我对C1'的哈希 ID 运行git checkout ,我是否应该看到C1的哈希 ID 运行git checkout相同的内容 两次提交将具有不同的哈希 ID,但具有相同的作者和提交者以及时间戳和日志消息等。 如果他们也应该有相同的(快照),那么工作现在非常简单,使用git replacegit filter-branch 这是基本配方:

git replace --graft <hash-of-C1> newroot

(此时您可以运行git log以确保它看起来正确)。 然后运行:

git filter-branch -- master

(假设您只希望从master复制可访问的提交,并更新 ref master )。 无操作过滤器分支(未指定过滤器)以正确的(即向前,向后到 Git)顺序复制每个可到达的提交,首先复制C1 ,然后复制C2 ,依此类推,但至关重要的是遵守替换指令 所以现在我们有了这个:

C1--C2--C3--C4--C5    refs/original/refs/heads/master

CX   <-- refs/replace/<hash-of-C1>
  \
   C1'-C2'-C3'-C4-C5'   <-- master

如果这是所需的最终结果,我们现在只需要删除refs/original/名称和不再有用的refs/replace/<hash-of-C1>名称:

git update-ref -d refs/original/refs/heads/master
git update-ref -d refs/replace/<hash-of-C1>

你的历史现在被改写了。 所有旧的克隆都必须被销毁(或者至少,你应该停止使用它们),因为它们中的哈希 ID 是原始提交的哈希 ID,你不想回到你的生活中,让生活变得悲惨。 更新后的克隆中废弃的 C1 到 C5 是无害的:它们可以留在那里,处于废弃状态,直到 Git 的死神收集器git gc开始对它们进行垃圾收集。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM