This changes the tag / head list functions GetTags and GetHeads to use
for-each-ref to let git do the age sorting internally (which is much
faster) and changes them to build off of the data already loaded by the
main ref list loading function
Use a shared ref ref list for finding a commit's tags and heads
This uses a new function to just load all refs without any accompanying
data, which we use to find the heads or refs for a given commit. Since
when displaying ref badges we only care about its type and name.
Try to guess the right binary on a Windows x64 system
I really hate making use of php_uname especially because it's disabled
for security reasons on some shared hosting providers. However there
isn't really another reliable way - you can't just test the integer size
in PHP because the build of php might not match the operating system
word size itself (eg running 32bit php on 64bit windows).
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