I think you are clouding this a little, in that it seems that you are attempting to combine the way that version control handles things with the way that the API is exposed (i.e. how the web server handles things).
In order for multiple versions of the API to work simultaneously, the consumer presumably needs to specify with version they want to use for a given call. For the purposes of this answer I'll assume you are working in a similar way to the Stack Exchange API, so that the version is specified as the first "directory" component of the API URL (e.g. for version 1.5 I direct my request to http://domain.tld/1.5/call
, version 1.6 I use http://domain/1.6/?method=call
, etc etc). But really this element doesn't matter, as long as you have some mechanism for determining the appropriate version and routing the request to the correct controller at the web server level.
Version control
The approach I would take here is fairly simple. Every version gets its own branch in the repository. Any development work performed against that version is either done in a branch from the version's branch, or committed directly to the version. Master always contains the most recent stable release.
For example, let's say the current release is 1.5 and everything is currently under master and you have no historical branches. Draw a line under the current stable code, and create a branch called 1.5. Now, to start development on 1.6, which will build on the 1.5 branch, create a new branch from master and call it 1.6.
Any development that works towards 1.6 happens in the 1.6 branch, or other branches created using 1.6 as a base. This means everything can be nice and cleanly push/pulled into the 1.6 branch as appropriate.
If you need to apply a small bugfix in the 1.5 release, you can easily do this in the 1.5 branch. If you want to pull a commit from the 1.6 branch, you will need to "cherry-pick" it - since the branches have started to diverge, any such issues would need to be dealt with manually to ensure maximum safely for protecting the "stable" codebase.
When the time comes to create 1.7/2.0/whatever, pull the 1.6 release into master, tag it, and create a new branch for the new version.
In this manner, a complete history of who did what and when for each version/release is stored in the branches. As mentioned by others, don't forget to tag your milestone releases.
Web server
With the above approach, the web server setup is fairly trivial to maintain. The root of each release is simply synced with the appropriate branch.
So, for the sake of simplicity let's imagine that the root directory of the repository in version control corresponds to the document root of the API code (in reality this is unlikely to be the case, but a bit of URL rewriting or similar approaches can resolve this).
In the document root for the domain on the web server, we create the following directory structure:
<document-root>
|
|--- 1.5
|
|--- 1.6
Into each of the 1.5, 1.6 directories we clone the repository from central version control, and switch to the appropriate branch. Every time you wish to push a change live, simply pull down the changes from version control in the appropriate branch.
In a high volume environment you might have a whole server dedicated to serving each version with the version identifier as a subdomain, but the same general principle apply - except that the repository can be cloned straight into each server's document root.
A lot (if not all) of the process of creating the directories for new branches, cloning the repo into it and switching to the appropriate branch, as well as pulling down patches/bugfixes for releases can be automated with scripts/cron etc, but before you do this don't forget: pushing changes to a live server without human involvement often ends in tears.
An alternative approach
...would be to create a single parent repository that serves as the document root for the domain. In this you would create submodules in the root of the repository for each version. The overall effect this would create would be quite similar, but have the "advantage" of only having to sync a single repository on the server, and keeping the web server's directory structure defined by version control. However, personally, I don't like this approach, for a couple of reasons:
- Submodules are a pain to maintain. They are attached to a particular commit, and it's easy to forget that.
- I believe the control afforded by the branch-driven approach is more granular, and clearer as to exactly what is going on.
I accept that both of those reasons are largely personal preference though, which is why I bring it up as a possibility.