在 Git 中的 root 提交之前添加提交? [英] Add commits before root commit in Git?

查看:35
本文介绍了在 Git 中的 root 提交之前添加提交?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

两个问题:

  1. 我正在尝试在 ALL 提交之前提交.
    最底层的提交将 660fb2a76211f36ec9a67d0454a90eab469e9fd0 作为 SHA.当我输入 git rebase -i 660fb2a76211f36ec9a67d0454a90eab469e9fd0 时,每次提交但最后一个都显示在列表中.
    我真的需要这个提交出现,这样我就可以把第一个提交放在最后!

  1. I'm trying to put a commit before ALL commits.
    The bottommost commit has 660fb2a76211f36ec9a67d0454a90eab469e9fd0 as SHA. When I type git rebase -i 660fb2a76211f36ec9a67d0454a90eab469e9fd0 every commit but the last one gets displayed in the list.
    I really need this commit to appear so I can put the very first commit as very last!

当我将第一个提交放在列表中的第一个 (意味着总共第二个提交,因为第一个提交不在上面提到的列表中) 我收到一个错误:错误:无法应用 b722c76... v1.4.3 BEAT 发布
我只是把它从列表的底部剪下来,放到最上面!我没有更改号码!
我也试过几次.相同的结果.

When I put the very first commit as first in the list (meaning second commit in total, because the very first is not in the list as mentioned above) I get an error: error: could not apply b722c76... v1.4.3 BEAT release
I just cut it from the bottom of the list and put it to the top! I did not change the number!
I also tried this several times. The same result.

到此为止.如果您有问题,请继续提问!

That's it so far. If you have questions go ahead and ask!

我刚刚发现了我项目的旧备份.这些备份是在我使用 git 之前创建的.
我现在想将它们作为旧提交添加到我的存储库中.这意味着我必须将这些提交放在所有其他提交之前.

I just dicovered old backups of my project. These backups where created before I used git.
I now would like to add them to my repository as old commits. That would mean I have to put these commit in front of all other commits.

现在有几个问题:

  1. 我通常如何将提交置于其他提交之前?
  2. 我怎么能这么快?(我有很多备份!)
  3. 如何为这些旧" 提交设置日期?(我知道备份的日期!)

如果有什么不清楚的,请提出来.到时候我会解决这个问题!

If something is not clear, please mention it. I will fix the issue then!

最后一件事:

我已经在 GitHub 上发布了这个.我主要使用他们的软件来提交.那么我如何将其推回 GitHub?

I have published this on GitHub. And I mainly used their software to commit commits. So how do I push this back to GitHub?

推荐答案

更新

我找到了另一种稍微简单的方法,使用 git rebase.我用我的一个 repo 进行了尝试,所以我知道它是有效的(至少对于完全线性的历史,最后会详细介绍).

Update

I found another, slightly simpler way to do this, using the --root flag of git rebase. I tried it out with a repo of mine, so I know it works (at least for a completely linear history, more on that at the end).

让我们安全一点并进行备份,以防万一我们最终做了一些灾难性的事情并丢失了您的数据:

Let's play it safe and make a backup, just in case we end up doing something disastrous and losing your data:

git clone original-repo backup-repo

第 2 步:创建孤立分支(这将是您的新根)

检查孤立分支.指定起点提交/分支是可选的,如果您忽略该参数,则 Git 将默认使用您当前的提交作为起点(它遵循标准分支语法的模式):

Step 2: Create orphan branch (this will be your new root)

Checkout the orphan branch. Specifying a start-point commit/branch is optional, if you leave that argument out, then Git will default to using your current commit as the start-point (it follows the pattern of standard branching syntax):

git checkout --orphan new-master firstCommitOfOldMaster

我指定了旧 master 的根目录作为起点,因为它可能会使下面的步骤更快(删除工作目录文件).

I specified the root of the old master as the start-point, because it will probably make the following step faster (removing the working directory files).

从旧的 master 创建孤立分支 new-master 可能会在您的工作目录和索引中留下文件,具体取决于您分支的提交中文件的状态:

Creating the orphan branch new-master from your old master might leave behind files in your working directory and index, depending on what the state of the files were in the commit you branched off of:

调整索引和工作树就像您之前运行过 git checkout 一样.这允许您通过轻松运行 git commit -a 进行根提交来开始一个新的历史记录,该历史记录记录一组类似于 的路径.—git checkout 文档

The index and the working tree are adjusted as if you had previously run git checkout <start_point>. This allows you to start a new history that records a set of paths similar to <start_point> by easily running git commit -a to make the root commit. — git checkout docs

您现在要做的是完全清除分支的状态,以便您真正从一个干净的石板(从顶级文件夹运行)重新开始:

What you'll want to do now is to completely clear the state of the branch, so that you're really starting again from a clean slate (run from top level folder):

git rm -rf .

这是文档中的解释:

如果你想开始一个断开的历史记录,记录一组与完全不同的路径,那么你应该在创建后立即清除索引和工作树通过从工作树的顶层运行 git rm -rf . 来创建孤立分支.之后,您将准备好准备新文件、重新填充工作树、从别处复制它们、提取 tarball 等.

If you want to start a disconnected history that records a set of paths that is totally different from the one of <start_point>, then you should clear the index and the working tree right after creating the orphan branch by running git rm -rf . from the top level of the working tree. Afterwards you will be ready to prepare your new files, repopulating the working tree, by copying them from elsewhere, extracting a tarball, etc.

第 4 步:将旧工作重新提交到 new-master

现在您要开始将旧工作提交到 new-master.完成后,您将在顶部重新设置您的旧主人.

Step 4: Recommit older work into new-master

Now you'll want to start commiting your older work into new-master. When you're done, you'll rebase your old master on top.

我不确定您的备份文件夹是如何组织的,但我将假设每个文件夹都只是您的项目文件夹的过时副本,以 YYYY-MM-DD 命名格式,例如2013-01-30.您可以手动将每个文件夹的内容添加为新提交,也可以编写脚本来自动执行此过程.

I'm not exactly sure how your backup folders are organized, but I'm going to assume that each one is just a dated copy of your project folder, named in YYYY-MM-DD format, e.g. 2013-01-30. You can add the contents of each folder as a new commit manually, or you can write a script to automate the process.

假设您将所有备份文件夹都放在名为 backup 的顶级文件夹中,该文件夹与您的主项目文件夹位于同一目录中.然后这里是一些脚本的伪代码,用于自动提交每个文件夹的过程:

Let's assume you have all your backup folders in a top folder called backup that sits in the same directory as your main project folder. Then here is some pseudo-code for a script to automate the process of commiting each folder:

# Get backups and sort them from oldest to newest
backups = open("backups").toList().sort("date ascending")
for each (backup in backups)
    copy files from backup to project folder
    execute `git add "*"`
    execute `git commit --date="#{backup.date}" --message="#{backup.date}"`

上面的脚本只会在提交之间添加和修改文件.如果您的任何备份删除、移动或重命名文件,脚本将不会记录.您需要编写一个更聪明的脚本来做到这一点(可能会使用 git diff 或其他一些差异工具),或者手动记录这些更改.

The script above will only add and modify files between commits. If any of your backups deleted, moved, or renamed files, the script won't record that. You'll need to write a more clever script to do that (maybe something that makes use of git diff or some other diffing tool), or record those changes manually.

看看 GIT 的强大力量!现在我们要改写你的整个历史! 背诵这些神秘的力量词,看看魔法的发生!:

BEHOLD THE AWESOME POWER THAT IS GIT! Now we're going to REWRITE YOUR ENTIRE HISTORY! Recite these arcane words of power, and watch the magic happen!:

git rebase --onto new-master --root master

TA-DA!您可能需要解决 new-master 的最后一次提交和 master 的第一次提交之间的冲突,但除此之外,应该就是这样了!

TA-DA! You might have to resolve conflicts between the last-commit of new-master and the first-commit of master, but other than that, that should be it!

rebase--root 标志解决了我们之前遇到的问题,即—通常—rebase 不会对 Git 存储库的第一次(根)提交进行操作.--root 标志基本上告诉 Git 将它包含在 rebase 中:

The --root flag to rebase gets around the problem we were having earlier about the fact that—normally—rebase won't operate on the first (root) commit of a Git repo. The --root flag basically tells Git to include it in the rebase:

重新设置从 可达的所有提交,而不是用 限制它们.这允许您在分支上重新设置根提交.当与 --onto 一起使用时,它将跳过 (而不是 )中已经包含的更改,而没有 --onto 它将对每次更改进行操作.—重新定位文档

Rebase all commits reachable from <branch>, instead of limiting them with an <upstream>. This allows you to rebase the root commit(s) on a branch. When used with --onto, it will skip changes already contained in <newbase> (instead of <upstream>) whereas without --onto it will operate on every change. — rebase docs

第 6 步:验证最终提交是否仍然相同

为了确保我们没有弄乱任何代码,我们需要将 master 的当前最终状态与其在执行 rebase<之前的状态进行比较/代码>.以下任一命令都可以使用(它们是相同的).在 master 分支上:

Step 6: Verify that final commit is still the same

Just to make sure we didn't mess any of the code up, we'll want to compare the current, final state of master to its state before we did the rebase. Either of the following commands will work (they're identical). While on the master branch:

git diff orig_head   # "Original" head
git diff master@{1}  # Master at its 1st prior position

如果 diff 没有任何输出,那么这意味着重新定位的 master 的最终状态与 rebase.干得好!

If you get no output from the diff, then that means the final state of your rebased master is identical to what it was before the rebase. Good job!

现在,如果您有完美的线性 历史记录,即您没有任何合并提交,则上述步骤将正常工作.如果你这样做,我不确定它是否仍然有效.在我之前的回答中,我提到使用 --preserve-merges 标志和 rebase 可能会帮助您保持这些合并,但文档提到该标志也与--onto--root 标志:

Now the above steps will work fine if you have a perfectly linear history, i.e. you don't have any merge commits. I'm not sure if it will still work if you do. In my previous answer below I mentioned that using the --preserve-merges flag with rebase might help you keep those merges, but the docs mention that that flag also interacts with the --onto and --root flags:

当 [--root is] 与 --onto--preserve-merges 一起使用时,所有的根提交都将被重写为将 作为父级.—重新定位文档

When [--root is] used together with both --onto and --preserve-merges, all root commits will be rewritten to have <newbase> as parent instead. — rebase docs

目前我不确定这意味着什么……我可能需要尝试一下,看看会发生什么.这是否意味着如果您有 1 个以上的根提交(例如 10 个),那么这些根提交中的 9 个最终将重新基于作为新根的最后一个提交?这似乎不是我们想要的行为.我们只是想保留一个根的合并提交被重新基于另一个根.

I'm not exactly sure what that means at the moment...I might have to try it out and see what happens. Does it mean that if you have more than 1 root commit (like 10 for example), then 9 of those root commits will end up being rebased onto the last one acting as the new root? That doesn't seem like the behavior we would want. We just want to preserve merge commits for one root being rebased onto another.

MGA 有 rebase 的正确想法.我不确定这是否能解决您的问题,但也许您需要在您的存储库中进行新的根提交,将您的备份文件作为新提交添加到它之上,然后将您的旧提交图重新设置在顶部.

MGA had the right idea with rebase. I'm not sure if this will fix your problem, but maybe you need to make a new root commit in your repo, add your backup files as new commits on top of it, then rebase your old commit graph on top.

例如,根据 文档:

For example, git checkout has an --orphan flag according to the documentation:

--orphan
创建一个新的孤立分支,命名为 ,从 开始并切换到它.在这个新分支上进行的第一次提交将没有父级,它将成为与所有其他分支和提交完全断开的新历史记录的根.

--orphan <new_branch>
Create a new orphan branch, named <new_branch>, started from <start_point> and switch to it. The first commit made on this new branch will have no parents and it will be the root of a new history totally disconnected from all the other branches and commits.

也许你可以试试

git checkout --orphan <temp_branch>

然后将您的备份文件提交给它.然后检出 temp_branch,做

Then commit your backup files to it. Then with temp_branch checked out, do

git cherry-pick <first commit from master>
git rebase --onto temp_branch <first commit from master> master

我认为您可能需要 cherry-pick 第一次提交,因为 rebase --onto 的第二个参数是您想要 rebase 的分支的旧基础(在这种情况下 master),并且不包括旧的基础.所以这就是为什么我认为你需要 cherry-pick 它才能得到它,因为它本身没有基础提交,所以你不能在 rebase.

I think you would probably need to cherry-pick the first commit because the 2nd argument to rebase --onto is the old base of the branch you want to rebase (in this case master), and the old base isn't included. So that's why I figure you need to cherry-pick it in order to get it, since it has no base commit itself, so you can't specify one for it in the rebase.

另请注意,如果您的提交历史不是线性的(即它有合并提交),那么 rebase 通常不会保留这些.它有一个 --preserve-merges 标志,但我以前从未使用过它,所以我不确定它是如何工作的.来自文档:

Also note that if your commit history isn't linear (i.e. it has merge commits), then rebase won't normally preserve those. It has a --preserve-merges flag, but I've never used it before, so I'm not really sure of how it will work. From the docs:

-p
--preserve-merges
不要忽略合并,而是尝试重新创建它们.

-p
--preserve-merges
Instead of ignoring merges, try to recreate them.

这在内部使用 --interactive 机制,但是将它与 --interactive 选项显式结合起来通常不是一个好主意,除非您知道自己在做什么(请参阅下面的错误).

This uses the --interactive machinery internally, but combining it with the --interactive option explicitly is generally not a good idea unless you know what you are doing (see BUGS below).

那么,也许所有这些都会奏效?

So, maybe all of that will work?

这篇关于在 Git 中的 root 提交之前添加提交?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆