To be fair, Emacs has had a package manager package, package.el (heh), for quite some time now. It can download and install packages from a repository, like Marmalade, though I've found it to be a bit shaky in the past; I've had to manually delete the files of a botched package, and then who-knows-what to get it to fully disappear.
It's, thankfully, been bundled in the default Emacs 24. And, thank the ghosts of the ancient lispers, that savagery of having a million-zillion different autocompletion interfaces for every damned thing may finally be put to an end with the new standardized autocompletion thingy.
I tried setting up package.el in Emacs 24 last week. "Shaky" is the word.
The big problem may be that I tried to use el-get, based on some dangerously optimistic blog posts which turned out to be obsolete because the author of el-get changed the semantics of his commands slightly at some point in the last six months. (It is vitally important to read the very bottom of the el-get web page.) But it was nothing that I couldn't figure out in two hours of tinkering and reading el-get's source code. (Good luck, beginners!)
Then I still had various packages that needed to be manually deleted, or manually have their status reset. And then I'd randomly call various el-get functions, restart emacs, and wave rubber chickens until the packages magically installed. Which, amazingly, did finally happen.
My conclusion, though, is that emacs packaging is a waste of time for me and I'm sorry I tried using it. Emacs is not Ubuntu, where every package install spreads critical binary files all over your system, has an average of ten dependencies, and is compiled against specific versions of C shared libraries on specific architectures. In Ubuntu, your packaging system is a matter of life and death. But Emacs packages tend to have few dependencies, their assets are made mostly of text files full of nice universal Lisp source, said assets all live nicely together in one directory in the filesystem where they are easy to manage via a single personal Git repository, and they get updated much more rarely than, say, the typical Ruby gem. So for me the bottleneck in adopting an Emacs package is never the time required to locate its source code and type "wget" or "git clone"; it's the time required to figure out how it works, integrate it into my workflow, define keybindings for it in .emacs, et cetera. Packaging systems solve a problem that I don't really have.
If the packaging scripts were rock solid and I could trust that, having now spent hours setting them up, I'll be able to rely on them to reinstall or update packages automatically over the next five years, that would be one thing. But I have no such confidence. I'm legitimately afraid that I will spend more time shaving yaks in the packaging system than I would have spent manually locating and downloading the packages in the first place.
el-get can install packages from non-ELPA sources, the most important of which is Github.
(It also includes emacswiki as a source, but tptacek has just reminded me that this is the world's scariest feature and I'm going to disable it posthaste.)
It also lets you declare all your packages in your setup file, and will install them from that declaration. That means you can stick your setup file on a brand-new machine, start emacs, and all your packages auto-install themselves and start working.
I've concluded, however, that I should have just done what you did. ;) Use package-install where it's handy, then commit everything that package-install pulls down to Git, along with any packages that I manually install from Github or other sources. (I could use Git submodules or subtree-merge for the latter… if I liked hairy complications.) This process is tedious, but it's conceptually simple, reliable, and results in a Git-controlled .emacs.d that I can just clone onto new machines so long as Github is up.