The question is a little unusual/unclear, mostly because it doesn't seem to be set in "The Git Way"/context of looking at source control. "Heads" in Git have more than one meaning...it doesn't mean the same thing like it does in SVN, for example. This is a point I will come back to later, but for now, I will attempt to address what seems to be the issue of adding previous versions of a code base to a Git repo.
How to retroactively add commits in Git
You have at least two options:
- Add previous versions of the code base as orphaned, separate branches. This is not something I recommend, because in my experience orphaned branches are inefficient to switch between in your working copy, probably because the
checkout
operation doesn't have access to common ancestors and stuff like that.
- You can add the previous versions as orphaned branches, but then rebase the newest
v10
/master
branch on top of them, and add new tags.
I recommend you use option #2, since it's a problem that's been addressed on Stack Overflow before, and it's more of "The Git Way" to do solve this issue:
- git: how to insert a commit as the first, shifting all the others?
- Git: how to add commits before first/initial/root commit?)
In particular, I recommend you follow these basic steps that I give a detailed explanation of in this answer:
Create a backup clone of your repo:
git clone original-repo backup-repo
Create an orphan branch (this will be your new root).
git checkout --orphan new-master firstCommitOfOldMaster
Remove working directory files from orphan branch.
git rm -rf .
Recommit older work into new-master
.
Rebase old master
onto new-master
.
git rebase --onto new-master --root master
Verify that the final commit is still the same.
git diff master@{1}
Either before you rebase the old master onto the new master, or afterwards, you can tag your v9
branch with either a lightweight tag or an annotated tag:
# Lightweight
$ git tag "v9"
# Annotated
$ git tag -a "v9" -m "Tag version 9"
Explanation of HEAD
So "heads" in Git have several meanings, depending on context. In the context you're using it—as a commit reference—HEAD
simply means the commit that you currently have checked out into your working copy. It does not mean the same thing as in SVN, i.e. HEAD
does not represent the most recent global commit in a repository.
As you checkout between branches or commits along those branches, HEAD
will point to different commits in your history (sometimes previous commits), because your're checking out different commits into your working copy. See
- What is git HEAD, exactly?.
- HEAD and ORIG_HEAD in Git.
There is another context in Git where "heads" are used: branches that are local to a repository are generally stored under the .git/refs/heads/
directory. In this context, "heads" just means branch pointers/references, and are the "tips"/most recent commit for a branch. You can see your local repo's branch heads/tips by running git show-ref
:
git show-ref
35ec88f1c5b319b7ca08f5d3dca3cafdebddecd4 refs/heads/awesome-feature
ea112e91953e02f9c6dcc7b9470b8bdf0a69a3eb refs/heads/epic-feature
a9874fd23f67c245fadd23bef449971fa7338755 refs/heads/master
Here you can see that I have 3 branch heads/tips/references: the master
branch, awesome-feature
branch, and the epic-feature
branch. To the left of each branch, you'll see the full commit sha that the branch currently points to, i.e. the most recent commit for that branch.
Explanation of rebase
First off, let me begin by saying that you should learn to rebase
. Period. I argue that it's the most fundamental, essential, and powerful tool in Git, and that if you're not using it, then you're not using Git effectively. So learn to rebase, both interactively and non-interactively.
With that out of the way, I won't go into too much detail about how git rebase
works, since there are plenty of online resources that explain it (I will list them), and this answer is already very very long.
But in a nutshell, rebase allows you to rewrite your history, in just about any way you could possibly want to. It takes a set of commits, and re-applies copies of those commits to wherever you want in your history. So that's what the solution I suggested above does, it takes your old v10
history, and recreates it on top of the new v9
history, as if that's the way the history was created all along.
Rebase resources
Here are excellent resources for learning more about rebase. Remember that you can always create a practice Git repo full of .txt
files or whatever you want, and then practice branching, rebasing, and merging with it:
- Git Tools - Rewriting History.
- git-rebase(1) Manual Page.
- Learn Git Branching, see the Interactive Rebase demo.
- Code School course Git Real, lesson 6.