在 Git 中的根提交之前插入一个 NON-EMPTY 提交?
Insert a NON-EMPTY commit before the root commit in Git?
有问题请指教!我有一个现有的 git 存储库,出于各种原因(我不会在这里讨论),我正在尝试创建一个 ROOT 提交
假设这是我的 git 提交历史:
(ROOT) C1 <-C2 <-C3 <-C4 <-C5 <--branchname (HEAD)
我想在 C1 之前添加一个初始提交(CX,它不是空的)。所以它应该像这样结束:
(NEW ROOT) CX-C1 <-C2 <-C3 <-C4 <-C5 <--branchname (HEAD)
我在这里发现了一个类似的问题:Insert a commit before the root commit in Git?
但它用于在现有根之前附加 EMPTY git 提交。
我还尝试了此处答案中的步骤:
有一个变化:我用 git add .; git commit -m "initial laravel commit"; git push;
替换了 git commit --allow-empty -m 'initial'
,然后这个变基步骤: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 倒着做。将根提交 last,即放在左侧,将 latest 提交 first,即,右边:
C1 <-C2 <-C3 <-C4 <-C5 <--branchname
分支名称始终包含 最新 提交的哈希 ID。这就是 Git 知道哪个 是 最新的。 Git使用C5
查找C4
,因为提交C5
本身,它有一个唯一的哈希ID,包含唯一的哈希ID提交 C4
。同时C4
持有C3
的hash ID,依此类推; C2
持有 C1
的唯一哈希 ID,并且 C1
是 根提交 因为 它有里面没有 parent 哈希 ID。
其次,实际上无法更改任何提交。所以你在这里要做的是 而不是 "change commit C1
"——你和 Git 都不能这样做——而是做一个新的提交,C1'
或者C21
或任何我们想称呼的名称。在这个新提交之前,我们需要另一个新提交,CX
,这是一个根提交并包含所需的内容。
您 可以 使用 Antony Hatchkins's answer 中的方法,但是现在,这样做的方法是从 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 由 cherry-picking 工作。这会将提交 C1
变成对每个文件 添加 的请求——提交 C1
作为根提交,与 empty tree 进行比较以查看什么已更改 — 如您所见,这会导致您在 C1
中添加且已在 CX
.
中的每个文件发生 add/add 冲突
你必须在这里回答的问题——我不能为你回答——是:你想在你的新副本C1
中有什么内容 ] 就像 C1
除了它有 CX
作为它的 parent? 也就是说,最后,我们将有:
C1--C2--C3--C4--C5 [abandoned]
CX--C1'-C2'-C3'-C4-C5' <-- master
在我们的存储库中。如果我 运行 git checkout
在 C1'
的哈希 ID 上,我是否应该看到 相同的内容 就好像我 运行 [=41] =] 在 C1
的哈希 ID 上?这两个提交将具有不同的哈希 ID,但具有相同的作者和提交者以及时间戳和日志消息等。如果他们也应该有相同的 tree(快照),现在使用 git replace
和 git filter-branch
就很容易了。这是基本配方:
git replace --graft <hash-of-C1> newroot
(此时您可以 运行 git log
以确保它看起来正确)。然后 运行:
git filter-branch -- master
(假设您只想复制可从 master
访问的提交,并更新 ref master
)。 no-op filter-branch(未指定过滤器)复制每个可到达的提交,在右边(即向前,向后到 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/
名称和 no-longer-useful refs/replace/<hash-of-C1>
名称:
git update-ref -d refs/original/refs/heads/master
git update-ref -d refs/replace/<hash-of-C1>
您的历史现已改写。所有 old 克隆必须被销毁(或者至少,你应该停止使用它们)因为它们中的哈希 ID 是那些 original 提交,你不想回到你的生活让生活变得悲惨。更新后的克隆中被遗弃的 C1 到 C5 是无害的:它们可以以被遗弃的状态留在那里,直到 Git 的 Grim Reaper Collector,git gc
,绕过 garbage-collecting 他们。
有问题请指教!我有一个现有的 git 存储库,出于各种原因(我不会在这里讨论),我正在尝试创建一个 ROOT 提交
假设这是我的 git 提交历史:
(ROOT) C1 <-C2 <-C3 <-C4 <-C5 <--branchname (HEAD)
我想在 C1 之前添加一个初始提交(CX,它不是空的)。所以它应该像这样结束:
(NEW ROOT) CX-C1 <-C2 <-C3 <-C4 <-C5 <--branchname (HEAD)
我在这里发现了一个类似的问题:Insert a commit before the root commit in Git?
但它用于在现有根之前附加 EMPTY git 提交。
我还尝试了此处答案中的步骤:
有一个变化:我用 git add .; git commit -m "initial laravel commit"; git push;
替换了 git commit --allow-empty -m 'initial'
,然后这个变基步骤: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 倒着做。将根提交 last,即放在左侧,将 latest 提交 first,即,右边:
C1 <-C2 <-C3 <-C4 <-C5 <--branchname
分支名称始终包含 最新 提交的哈希 ID。这就是 Git 知道哪个 是 最新的。 Git使用C5
查找C4
,因为提交C5
本身,它有一个唯一的哈希ID,包含唯一的哈希ID提交 C4
。同时C4
持有C3
的hash ID,依此类推; C2
持有 C1
的唯一哈希 ID,并且 C1
是 根提交 因为 它有里面没有 parent 哈希 ID。
其次,实际上无法更改任何提交。所以你在这里要做的是 而不是 "change commit C1
"——你和 Git 都不能这样做——而是做一个新的提交,C1'
或者C21
或任何我们想称呼的名称。在这个新提交之前,我们需要另一个新提交,CX
,这是一个根提交并包含所需的内容。
您 可以 使用 Antony Hatchkins's answer 中的方法,但是现在,这样做的方法是从 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 由 cherry-picking 工作。这会将提交 C1
变成对每个文件 添加 的请求——提交 C1
作为根提交,与 empty tree 进行比较以查看什么已更改 — 如您所见,这会导致您在 C1
中添加且已在 CX
.
你必须在这里回答的问题——我不能为你回答——是:你想在你的新副本C1
中有什么内容 ] 就像 C1
除了它有 CX
作为它的 parent? 也就是说,最后,我们将有:
C1--C2--C3--C4--C5 [abandoned]
CX--C1'-C2'-C3'-C4-C5' <-- master
在我们的存储库中。如果我 运行 git checkout
在 C1'
的哈希 ID 上,我是否应该看到 相同的内容 就好像我 运行 [=41] =] 在 C1
的哈希 ID 上?这两个提交将具有不同的哈希 ID,但具有相同的作者和提交者以及时间戳和日志消息等。如果他们也应该有相同的 tree(快照),现在使用 git replace
和 git filter-branch
就很容易了。这是基本配方:
git replace --graft <hash-of-C1> newroot
(此时您可以 运行 git log
以确保它看起来正确)。然后 运行:
git filter-branch -- master
(假设您只想复制可从 master
访问的提交,并更新 ref master
)。 no-op filter-branch(未指定过滤器)复制每个可到达的提交,在右边(即向前,向后到 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/
名称和 no-longer-useful refs/replace/<hash-of-C1>
名称:
git update-ref -d refs/original/refs/heads/master
git update-ref -d refs/replace/<hash-of-C1>
您的历史现已改写。所有 old 克隆必须被销毁(或者至少,你应该停止使用它们)因为它们中的哈希 ID 是那些 original 提交,你不想回到你的生活让生活变得悲惨。更新后的克隆中被遗弃的 C1 到 C5 是无害的:它们可以以被遗弃的状态留在那里,直到 Git 的 Grim Reaper Collector,git gc
,绕过 garbage-collecting 他们。