CVS's problems resurface in Git
lackingrhoticity.blogspot.com
lackingrhoticity.blogspot.com
The author's straw man of a git repo per file is also quite unconvincing.
Git may have some shortcoming, but this is not one of them.
When you want to build something, you would want to build against their dependencies.. which you would want to tag in some manner.
For e.g. v1.0 of ProjA needs v0.8 of ProjB and v3.2 of ProjC. A nice example is NodeJS that needs The GoogleV8 engine. Take a look at the number of changesets that are simply managing revisions of V8 inside the NodeJS tree (http://github.com/ry/node/commits/master/deps/v8)
In an ideal world, you could have tagged a version of NodeJS source code with a particular version of V8 (which lives in a different repository), all under the same directory structure.
To stay with node/v8, you would add v8 as a submodule and check out a specific revision or tag. The parent repository (node) would keep track of that revision and whenever you clone the parent, you'd be able to fetch the submodule and check out the correct revision.
If you want to update v8, you cd into the v8 dep directory and check out the newer tag. The parent repository will see this and offer you to commit that change to the submodule as a commit of the main repository.
We're using this facility internally with some projects, sometimes adding internally developped modules as submodules, sometimes adding public libraries.
Public libraries as submodules is really cool as you can use git's awesome merging features to keep around modifications you made to said libraries even if you update the target library.
I'm having a bit of difficulty at explaining the concept, but once you do it, it's simple and beautiful.
at some point I want to add a submodule for a dependency I need
$ git submodule add http://github.com/fictorial/redis-node-client.git deps/redis-node-client
this produces a commit with the following diff: diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..1695499
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "deps/redis-node-client"]
+ path = deps/redis-node-client
+ url = http://github.com/fictorial/redis-node-client.git
diff --git a/deps/redis-node-client b/deps/redis-node-client
new file mode 160000
index 0000000..5050251
--- /dev/null
+++ b/deps/redis-node-client
@@ -0,0 +1 @@
+Subproject commit 505025187faf3cf7a211f5e6bfd261e45bd0b1dc
Later, when I want to update the subproject to a new revision, i just $ cd deps/redis-node-client
$ git checkout v2.0 # or whatever
$ cd ../..
$ git diff
diff --git a/deps/redis-node-client b/deps/redis-node-client
index bdbfb96..a98a74b 160000
--- a/deps/redis-node-client
+++ b/deps/redis-node-client
@@ -1 +1 @@
-Subproject commit bdbfb96293f868dc01917a38af2dc4b66dd86157
+Subproject commit a98a74b71c1ad90f15c58bb904d17906689c85f5
From the point of view of the parent git repository it only updated the pointer to point to another commit.Or maybe it is all the anti-TDD folks upvoting first and then maybe checking the whole thing actually makes sense? :)
Submodules, if you find you must depend on external libraries at the repository level (for patching, perhaps).
See git clone's "--depth" option. There are limitations to what you can do with a shallow clone, but you do not, in fact, need to pull down an entire history.
Regarding the rest of TFA, the author should look at git submodules, as already mentioned here in the comments. However, submodules should not be used without understanding their implications and limitations (it is worth searching the Git mailing list).
There are at least three alternatives to submodules I'm aware of:
1. git-subtree - http://github.com/apenwarr/git-subtree
2. gclient - http://www.chromium.org/developers/how-tos/install-gclient
This is part of so-called "depot_tools" used by Chromium and ChromiumOS, and can tie together subversion and git repos.
3. repo - http://source.android.com/source/git-repo.html
This is used by the Android project.
The latter two are not really designed to be used outside of the projects for which they were created, but both are Python code so they can probably be adapted pretty easily.
When you learn to see this problem, you start to see it everywhere; it's so fundamental and pervasive you can't hardly even see it.
* _Creating a tag across repositories would involve visiting every repository to add a tag to it._
These two, at least, are technically accounted for by git submodules, though they are a bit of a pain to use.
It really shines, if you use them for third party libraries that you are keeping patches for. In the old days, updating said libraries was nearly impossible once you began patching them. With submodules, you can use git's really cool merging capabilities to help you.
Even better: The workflow when updating a library patched by you to a newer upstream version stays the same as if you'd just do a traditional merge in your own codebase. So there's no need to learn even more commands or new workflows - it just works.
I'm a huge, huge fan of how git submodules work.
1. Create a new repo.
2. Get the branched submodule.
3. Check that in as head: Note, now HEAD will NOT compile - I've committed broken code.
4. Go back to the original repo.
5. Get HEAD: this pulls the hash I need.
6. Do the merge. The submodule doesn merge, because it has the right hash.
Surely there must be some way to just modify the hash. But I don't know where to change it. I found it in several locations, but I don't know how it works, and hacking my VCS isnt my idea of good sense.
Please inform me, how can you ever possibly create a commit that is a "partial merge" from two parent commits? At some point, you had to explicitly choose what you wanted to merge or not merge, and you can do exactly that in Git, and I would certainly assume that you could do that in Mercurial and Bazaar too. Or am I missing something?