This question already has an answer here:
New Question
Two questions:
I'm trying to put a commit before ALL commits.
The bottommost commit has660fb2a76211f36ec9a67d0454a90eab469e9fd0
as SHA. When I typegit 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!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:
- How do I in general put a commit before other ones?
- How could I do this fast? (I have many backups!)
- 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?
1) You can use
git rebase
. In this case you could do the following:First thing first, commit your old changes. Then:
This will open a file with your commits in a text editor. Just change the order of the commits (cut/paste your last commits to be the first ones, including the "pick" command on the left), save and close the editor. At this point the rebase will begin. To continue when you're asked for confirmation, type:
Until it's all done. More information here.
2) I don't know any method to make this faster, but it should be pretty fast already.
3) To change the date of a commit you must change GIT_AUTHOR_DATE and GIT_COMMITTER_DATE. For this there's a pretty example in the accepted answer for this StackOverflow question.
Hope it helps!
Update
I found another, slightly simpler way to do this, using the
--root
flag ofgit 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:
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):
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: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):
This is the explanation from the docs:
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: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
ontonew-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!:
TA-DA! You might have to resolve conflicts between the last-commit of
new-master
and the first-commit ofmaster
, but other than that, that should be it!The
--root
flag torebase
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 therebase
: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 therebase
. Either of the following commands will work (they're identical). While on themaster
branch:If you get no output from the
diff
, then that means the final state of your rebasedmaster
is identical to what it was before therebase
. 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 withrebase
might help you keep those merges, but the docs mention that that flag also interacts with the--onto
and--root
flags: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:So maybe you can try
Then commit your backup files to it. Then with
temp_branch
checked out, doI think you would probably need to
cherry-pick
the first commit because the 2nd argument torebase --onto
is the old base of the branch you want to rebase (in this casemaster
), and the old base isn't included. So that's why I figure you need tocherry-pick
it in order to get it, since it has no base commit itself, so you can't specify one for it in therebase
.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:So, maybe all of that will work?