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

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

问题描述

新问题



两个问题:


  1. m试图在 ALL 之前提交一个提交。

    最底层的提交具有 660fb2a76211f36ec9a67d0454a90eab469e9fd0 作为SHA。当我输入 git rebase -i 660fb2a76211f36ec9a67d0454a90eab469e9fd0 每一个提交,但最后一个显示在列表中。

    我真的需要这个提交出现,所以我可以把第一次提交作为最后一次提交!

  2. 当我把第一次提交作为第一次提交到列表中时(意味着第二次提交,因为第一个不在上面提到的列表中)我得到一个错误:错误:无法应用b722c76 ... v1.4.3 BEAT版本 >
    我只是将它从列表的底部切下并放到顶部! 我没有更改号码!

    我也试了几次。同样的结果。

到目前为止,如果您有任何疑问,请继续询问!



原始问题



我刚刚发现了我的项目的旧备份。这些备份是在我使用git之前创建的。

我现在想将它们作为旧提交添加到我的存储库中。这意味着我必须将这些提交放在所有其他提交之前。



现在有几个问题:


  1. 我如何在其他人之前进行提交?
  2. 我该如何快速执行此操作?
  3. 承诺? (我知道备份的日期!)

如果有什么不清楚的地方,请提一提。我会解决这个问题然后!



最后一件事:

我已经在GitHub上发布了这个。我主要使用他们的软件来提交提交。那么我该如何将它推回GitHub? >使用 - root 标志,我发现了另一种更简单的方法。 /scm/git/docs/git-rebase.htmlrel =nofollow noreferrer> git rebase 。我试着用我的回购试用它,所以我知道它是有效的(至少对于一个完整的 线性 历史记录,最后更多)。



第1步:创建您的存储库的备份克隆 让我们安全地进行安全备份,以防万一我们结束你可以做一些灾难性的事情并丢失你的数据:

  git clone original-repo backup-repo 


结账孤儿分支。指定一个起点提交/分支是可选的,如果你不提供该参数,那么Git将默认使用你当前的提交作为起点(它遵循标准分支语法的模式):

  git checkout --orphan new-master firstCommitOfOldMaster 

我将旧主设备的根指定为起始点,因为它可能会使以下步骤更快(删除工作目录文件)。



步骤3:删除工作目录文件



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


索引和调整工作树,就好像您以前运行过 git checkout< start_point> 一样。这允许您通过轻松运行 git commit -a 来启动一个新的历史记录,记录一组类似<< start_point> $ c>使根提交。 &MDASH; git checkout文档


你现在要做的是彻底清除分支的状态,这样你就可以从一个干净的平板上重新开始(运行从顶级文件夹):

  git rm -rf。 

这是来自文档的解释:

< blockquote>

如果您想开始一个断开的历史记录,记录一组完全不同于< start_point> 的路径,那么您应该通过从工作树的顶层运行 git rm -rf。来创建孤立分支后立即清除索引和工作树。之后,您将准备好准备新文件,重新填充工作树,从其他地方复制它们,提取压缩包等。




步骤4:将旧作重新编译为 new-master



现在您要开始提交旧作品成新主人。完成后,您将重新绑定您的旧主人。



我并不确定您的备份文件夹是如何组织的,但我要假设每一个只是您的项目文件夹的一个过期副本,以 YYYY-MM-DD 格式命名,例如二零一三年一月三十零日。您可以手动将每个文件夹的内容添加为新提交,也可以编写脚本来自动执行该流程。

名为 backup 的顶级文件夹位于与主项目文件夹相同的目录中。那么这里有一些脚本的伪代码来自动化提交每个文件夹: #获取备份并将它们从最旧到最新排序
backups = open(backups).toList()。sort(日期升序)
(备份中的备份)
copy文件从备份到项目文件夹
执行`git add*`
执行`git commit --date =#{backup.date}--message =#{backup.date} `

上面的脚本只会在提交之间添加和修改文件。如果您的任何备份被删除,移动或重命名文件,该脚本将不会记录该文件。你需要编写一个更聪明的脚本来做到这一点(也许是利用 git diff 或其他一些差异化工具),或手动记录这些更改。 p>

步骤5:将旧的 master 重新映射到 new-master



摆脱GIT的强大威力!现在我们将重温您的整个历史!背诵这些奥术权力的话,并观看神奇的事情发生!:

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

TA-DA!您可能必须解决 new-master 的最后提交与 master 的第一次提交之间的冲突,但



- root 标记为 rebase 解决了我们之前遇到的问题,即通常是< code> rebase 不会在Git的第一个(根)提交上运行回购。 --root 标志基本上告诉Git将它包含在 rebase 中:


对所有可从< branch> 访问的提交进行重新存储,而不是将其限制为<上游> 。这允许您重新分支分支上的根提交。在与 - 一起使用时,它将跳过已包含在< newbase> 中的更改(而不是< upstream> ),而没有 - 到,它会在每次更改时运行。 &MDASH; 转发文档




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



为了确保我们没有错误,将任何代码搞乱,我们要比较 master 的当前最终状态与我们执行 rebase之前的状态。以下任一命令都可以工作(它们是相同的)。在 master 分支上:

  git diff orig_head#Original头部
git diff主人@ {1}#在其第一个在前位置的主人

如果你从 diff 不会得到任何输出,那么这意味着重新发布的 master 的最终状态与之前的状态相同 rebase 。好的工作!

注意:不知道合并提交会发生什么...



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


当[ - root is]与一起使用时 - -onto - preserve-merges ,所有的根提交将被重写为< newbase> 作为父代。 &MDASH; 转发文档


我不完全确定此时的含义......我可能必须尝试一下,看看会发生什么。这是否意味着如果您有超过1个根提交(例如10个),那么这些根提交中的9个最终将被重新绑定到最后一个作为新根的位置?这看起来不像我们想要的行为。我们只是想保留一个root的合并提交到另一个。

b

MGA拥有正确的创意 rebase 。我不确定这是否能解决您的问题,但也许您需要在您的仓库中进行新的根提交,将您的备份文件作为新提交添加到其上,然后重新绑定旧的提交图。



例如, git checkout 有一个 - orphan 标志,根据文档


- orphan< new_branch>

创建一个新的孤立分支, code>< new_branch> ,从< start_point> 开始并切换到它。在这个新分支上进行的第一次提交将没有父母,它将成为与所有其他分支和提交完全断开连接的新历史记录的根。


所以也许你可以试试

  git checkout --orphan< temp_branch> 

然后将您的备份文件提交给它。然后用 temp_branch 签出,做

  git cherry-pick <第一次提交从master> 
git rebase --onto temp_branch<来自master的第一次提交> master

我想你可能需要 cherry-pick 第一次提交,因为 rebase --onto 的第二个参数是您希望重新分支的分支的旧基础(在本例中为 master ),并且不包括旧的基础。所以这就是为什么我想你需要> cherry-pick 才能得到它,因为它本身没有基本提交,所以你不能在 rebase



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


> -p

- preserve-合并

而不是忽略合并,尝试重新创建合并。



这使用<$ c内部的$ c> - interactive 机制,但明确地将它与 - interactive 选项结合通常不是一个好主意,除非你知道你正在做(见下面的BUGS)。


所以,也许所有这些都可行?


New Question

Two questions:

  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!

  2. 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!

Original Question

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.

Now there are several problems with this:

  1. How do I in general put a commit before other ones?
  2. How could I do this fast? (I have many backups!)
  3. How do I set a date for these "old" commits? (I know the dates of the backups!)

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

One last thing:

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

解决方案

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).

Step 1: Create a backup clone of your repo

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

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

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).

Step 3: Remove working directory files

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:

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 .

This is the explanation from the docs:

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.

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.

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.

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}"`

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.

Step 5: Rebase old master onto new-master

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! 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!

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:

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

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

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!

NOTE: not sure what happens to merge commits...

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:

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

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.


Previous answer

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 <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.

So maybe you can try

git checkout --orphan <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

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.

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
Instead of ignoring merges, try to recreate them.

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的根提交之前添加提交?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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