Tree and blob objects can't be reliably cached in-memory during runtime
because trees and blobs are hashes of their content, but the objects
also contain info such as parent commit and filename - something not
inherently tied to a blob hash. If the same blob or tree is used in two
different places for two different paths and loaded from the cache, the
second time will carry over the path and commit from the first, which is
When these objects are enabled for the object cache, they'll have
fine-grained control over their serialization, so we can skip data like
these fields that shouldn't carry over to multiple instances.
Also improves performance by not requiring the entire tag list to be
loaded if a single tag object is needed. The full list is loaded if all
tags are needed (and it doesn't reload already loaded tags).
I bent the serialization rules a little here. Git commit objects store
pointers to various other objects - other parent commits, the project,
the tree, etc. These references would be lost upon serialization.
Therefore, in the __sleep magic method to prepare for serialization, I
"reference" each object - I turn the object into a string identifier
that can be used to retrieve the object again later (for commits and
trees the hash, for the project the name, etc).
But the problem is that I can't "dereference" these objects in the
equivalent __wakeup method - if the commit points to the tree and the
tree points to the commit, then when you try to deserialize the commit
it'll try to deserialize the tree, which will then try to deserialize
the commit... which is an infinite loop.
Therefore, now these references actually remain in the object and are
just-in-time dereferenced when you want to actually access that
referenced object (using a getter). This also has the advantage of
easing the processing when loading from the cache, so that all the
object references aren't resolved at once, they're only resolved when
you need them.
This allows specification of a regex and url to find bug references in
commit messages, and allows them to be linked to an external bug
tracker. Currently this is just a very basic regex find and replace,
there's no advanced logic such as finding patterns that span lines, or
Currently this also only display in places where the full message text
is shown, and is not a link - the commit page, the commitdiff page, and
the log page. In the various other places where commit messages may be
shown (shortlog, headers, summary, etc), the message text is already a
link to the commit itself. Putting a link inside a link is weird
usability wise since that's not the way the user is expecting things to
There is an existing smarty memcache cache handler function out there,
however examples I've seen out there are incomplete in that they only
support evicting items from the cache using an exact key. However,
GitPHP takes advantage of some of the more advanced cache expiration
features of smarty, such as using cache groups and expiration based on
Therefore this is an implementation done by me from scratch to support
these extra cache expiration mechanisms. Memcache doesn't inherently
support things like iterating over stored keys and getting the age of
a stored item. Therefore, I'm using a hack, where I maintain a mapping
table of stored keys and cache ages in a fixed key, and update that key
manually and use it for cache group or age expiration.
This also provides a memcache wrapper class to be able to transparently
support both the PECL Memcache and PECL Memcached extensions using the
This moves all archiver functions into a class to wrap around a commit.
This makes it a lot easier to share code, so we don't have to repeatedly
test everywhere if the gzip and bzip2 functions exist, and the
controller doesn't have to worry about things like compressing data.
Plus it gives a central place to add additional archiving related
On the user's first visit, default language from HTTP_ACCEPT_LANGUAGE
On the very first visit when no language preference cookie is set,
attempt to guess what the user wants from their HTTP_ACCEPT_LANGUAGE
setting from their browser. (Their OS language)
This will attempt to match the preferences in the order they're
specified by the browser, which should be the user's order of
For full language + country code preferences (eg en_US) it
will attempt to match the whole thing. For just language preferences
(eg en) it will match the first locale with that same language code.