I think that in general to get what you want, you'll have to do some sort of merge/rebase operation in order to create something to compare with.
When you really think about it, the idea of a diff between changesets is fuzzy. I'm assuming here that you're in a situation like this:
[other history] [ "changeset 1" ]
o - o - o - o - o ( - o - o - o - o)
\
(o - o - o - o - o)
[ "changeset 2" ]
So what does it mean to compare those two? Maybe in your case, the diffs in the other history are completely disjoint from those of the two changesets, but in general, the contents of changeset 1 may depend on that other history! This means that there's no good general way for git to perform an operation like this; to do it properly, it'd have to essentially say "what would the difference between the two end commits be if I rebased?" In other words, I believe that the only reasonable definition of the diff between the changesets is the diff between the resulting end commits if they're rebased to have a common ancestor. And of course, if that's what you want, then you'll have to perform an operation in the work tree - there's no other way to muck around with diffs like this. The obvious thing to do would be to rebase, and compare the new endpoints (branches):
[other history] [ "changeset 1" ]
o - o - o - o - o ( - o - o - o - o)
\
(o - o - o - o - o)
[ "changeset 2'" ]
Rebases aren't always the most fun, though, and I can think of one little way to work around this. The resulting work tree of the rebase, assuming you resolve conflicts appropriately, ought to be the same as the result of a merge:
[other history] [ "changeset 1" ]
o - o - o - o - o ( - o - o - o - o)
\ \
\ ------
\ \
(o - o - o - o - o) - X
[ "changeset 2" ]
So you could perform that temporary merge, and compare the resulting commit to the end commit of the other changeset. That'll be a lot faster than doing the rebase. (Either way, you'll of course use a throwaway branch, not the real one for changeset 2.)