[英]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 replace
和git 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.