It appears to me that when the SPM runs, it actually performs a fork operation first (repositories folder) which is followed up with a clone operation (checkouts folder). If the SPM had mod_rewrite like functionality (Apache HTTPD), the URLs could be updated on-the-fly without having to change the package's Package.swift, nor the repository's history. The 'mod_rewrite' extension would, of course, need to be able to handle protocols, domains, paths, and users, and enable a means of authentication (I tend to use Public Key) where the local repository server requires such.
Thus, the SPM (swiftenv) configuration would be setup to specify how to perform the URLs alterations (regex, mappings, or otherwise) (1). The SPM, during the fork phase, would initially check the local mirror to see if the package repository exists locally. If not, then the package would be retrieved from its original source and placed directly into the location determined by the rewritten URL. The git hook: pre-receive (2) trigger handler would be used to create the repository .git folder in the correct location and call
git init --bare --shared (or whatever is appropriate) within it.
The clone would then be performed using the rewritten URL (again on-the-fly) and the checked out version placed into usual place inside the
.build folder. If the correct checkout cannot be resolved in the cloned repository, then either an error would be issued, or some other appropriate action taken (maybe the package could be retrieved from its original location and replace the locally stored URL rewritten version).
Because the contents of the locally checked out repository will not have changed from that of the pristine original, the local package repository would still track the authentic origin, thus SPM could have a feature that enables it to indicate if there have been noteworthy changes upstream.
If the developer wishes to make changes to a dependency, then they would need to consider whether to perform a real fork (and think of how it would be distributed) or issue a pull request. I believe, on principle that, once forked, you have a new product, and usage of the new product in place of the original is a risk.
I don't know anything about SPM's design, nor whether it is reliant on libgit2, so I can't say how practical or feasible the above procedure would be. Also, I'm not sure how this suggestion would fare in scenarios where build scripts run within the package and access external resources. Nevertheless, perhaps this thread could be treated as an initial brainstorming on how to resolve this problem.
(1) This could be done on a per project basis or globally for the user (perhaps similar to how git manages configuration settings).
(2) Git hook: pre-receive itself cannot be used for this, unfortunately, because it isn't triggered when a repository does not already exist. Personally I think this trigger should not depend on the existence of a repository, and that a feature request to the libgit2 team should be made to provide it. I feel this would almost be the ideal mechanism, and would require the least amount of work all round to implement..