diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index 6573b1230..1d9cba1c3 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1,581 +1,589 @@
 <?php
 
 /**
  * This file is automatically generated. Use 'phutil_mapper.php' to rebuild it.
  * @generated
  */
 
 phutil_register_library_map(array(
   'class' =>
   array(
     'Aphront400Response' => 'aphront/response/400',
     'Aphront404Response' => 'aphront/response/404',
     'AphrontAjaxResponse' => 'aphront/response/ajax',
     'AphrontApplicationConfiguration' => 'aphront/applicationconfiguration',
     'AphrontController' => 'aphront/controller',
     'AphrontDatabaseConnection' => 'storage/connection/base',
     'AphrontDefaultApplicationConfiguration' => 'aphront/default/configuration',
     'AphrontDefaultApplicationController' => 'aphront/default/controller',
     'AphrontDialogResponse' => 'aphront/response/dialog',
     'AphrontDialogView' => 'view/dialog',
     'AphrontErrorView' => 'view/form/error',
     'AphrontException' => 'aphront/exception/base',
     'AphrontFileResponse' => 'aphront/response/file',
     'AphrontFormCheckboxControl' => 'view/form/control/checkbox',
     'AphrontFormControl' => 'view/form/control/base',
     'AphrontFormDividerControl' => 'view/form/control/divider',
     'AphrontFormFileControl' => 'view/form/control/file',
     'AphrontFormMarkupControl' => 'view/form/control/markup',
     'AphrontFormPasswordControl' => 'view/form/control/password',
     'AphrontFormRecaptchaControl' => 'view/form/control/recaptcha',
     'AphrontFormSelectControl' => 'view/form/control/select',
     'AphrontFormStaticControl' => 'view/form/control/static',
     'AphrontFormSubmitControl' => 'view/form/control/submit',
     'AphrontFormTextAreaControl' => 'view/form/control/textarea',
     'AphrontFormTextControl' => 'view/form/control/text',
     'AphrontFormTokenizerControl' => 'view/form/control/tokenizer',
     'AphrontFormView' => 'view/form/base',
     'AphrontHeadsupActionListView' => 'view/layout/headsup/actionlist',
     'AphrontHeadsupActionView' => 'view/layout/headsup/action',
     'AphrontMySQLDatabaseConnection' => 'storage/connection/mysql',
     'AphrontNullView' => 'view/null',
     'AphrontPageView' => 'view/page/base',
     'AphrontPanelView' => 'view/layout/panel',
     'AphrontQueryConnectionException' => 'storage/exception/connection',
     'AphrontQueryConnectionLostException' => 'storage/exception/connectionlost',
     'AphrontQueryCountException' => 'storage/exception/count',
     'AphrontQueryDuplicateKeyException' => 'storage/exception/duplicatekey',
     'AphrontQueryException' => 'storage/exception/base',
     'AphrontQueryObjectMissingException' => 'storage/exception/objectmissing',
     'AphrontQueryParameterException' => 'storage/exception/parameter',
     'AphrontQueryRecoverableException' => 'storage/exception/recoverable',
     'AphrontRedirectException' => 'aphront/exception/redirect',
     'AphrontRedirectResponse' => 'aphront/response/redirect',
     'AphrontRequest' => 'aphront/request',
     'AphrontRequestFailureView' => 'view/page/failure',
     'AphrontResponse' => 'aphront/response/base',
     'AphrontSideNavView' => 'view/layout/sidenav',
     'AphrontTableView' => 'view/control/table',
     'AphrontURIMapper' => 'aphront/mapper',
     'AphrontView' => 'view/base',
     'AphrontWebpageResponse' => 'aphront/response/webpage',
     'CelerityAPI' => 'infrastructure/celerity/api',
     'CelerityResourceController' => 'infrastructure/celerity/controller',
     'CelerityResourceMap' => 'infrastructure/celerity/map',
     'CelerityStaticResourceResponse' => 'infrastructure/celerity/response',
     'ConduitAPIMethod' => 'applications/conduit/method/base',
     'ConduitAPIRequest' => 'applications/conduit/protocol/request',
     'ConduitAPI_conduit_connect_Method' => 'applications/conduit/method/conduit/connect',
     'ConduitAPI_conduit_ping_Method' => 'applications/conduit/method/conduit/ping',
     'ConduitAPI_differential_creatediff_Method' => 'applications/conduit/method/differential/creatediff',
     'ConduitAPI_differential_createrevision_Method' => 'applications/conduit/method/differential/createrevision',
     'ConduitAPI_differential_find_Method' => 'applications/conduit/method/differential/find',
     'ConduitAPI_differential_getcommitmessage_Method' => 'applications/conduit/method/differential/getcommitmessage',
     'ConduitAPI_differential_getcommitpaths_Method' => 'applications/conduit/method/differential/getcommitpaths',
     'ConduitAPI_differential_getdiff_Method' => 'applications/conduit/method/differential/getdiff',
     'ConduitAPI_differential_markcommitted_Method' => 'applications/conduit/method/differential/markcommitted',
     'ConduitAPI_differential_parsecommitmessage_Method' => 'applications/conduit/method/differential/parsecommitmessage',
     'ConduitAPI_differential_setdiffproperty_Method' => 'applications/conduit/method/differential/setdiffproperty',
     'ConduitAPI_differential_updaterevision_Method' => 'applications/conduit/method/differential/updaterevision',
     'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload',
     'ConduitAPI_user_find_Method' => 'applications/conduit/method/user/find',
     'ConduitException' => 'applications/conduit/protocol/exception',
     'DarkConsole' => 'aphront/console/api',
     'DarkConsoleConfigPlugin' => 'aphront/console/plugin/config',
     'DarkConsoleController' => 'aphront/console/controller',
     'DarkConsoleCore' => 'aphront/console/core',
     'DarkConsoleErrorLogPlugin' => 'aphront/console/plugin/errorlog',
     'DarkConsoleErrorLogPluginAPI' => 'aphront/console/plugin/errorlog/api',
     'DarkConsolePlugin' => 'aphront/console/plugin/base',
     'DarkConsoleRequestPlugin' => 'aphront/console/plugin/request',
     'DarkConsoleServicesPlugin' => 'aphront/console/plugin/services',
     'DarkConsoleServicesPluginAPI' => 'aphront/console/plugin/services/api',
     'DarkConsoleXHProfPlugin' => 'aphront/console/plugin/xhprof',
     'DarkConsoleXHProfPluginAPI' => 'aphront/console/plugin/xhprof/api',
     'DifferentialAction' => 'applications/differential/constants/action',
     'DifferentialAddCommentView' => 'applications/differential/view/addcomment',
     'DifferentialAttachController' => 'applications/differential/controller/attach',
     'DifferentialCCWelcomeMail' => 'applications/differential/mail/ccwelcome',
     'DifferentialChangeType' => 'applications/differential/constants/changetype',
     'DifferentialChangeset' => 'applications/differential/storage/changeset',
     'DifferentialChangesetDetailView' => 'applications/differential/view/changesetdetailview',
     'DifferentialChangesetListView' => 'applications/differential/view/changesetlistview',
     'DifferentialChangesetParser' => 'applications/differential/parser/changeset',
     'DifferentialChangesetViewController' => 'applications/differential/controller/changesetview',
     'DifferentialComment' => 'applications/differential/storage/comment',
     'DifferentialCommentEditor' => 'applications/differential/editor/comment',
     'DifferentialCommentMail' => 'applications/differential/mail/comment',
     'DifferentialCommentPreviewController' => 'applications/differential/controller/commentpreview',
     'DifferentialCommentSaveController' => 'applications/differential/controller/commentsave',
     'DifferentialCommitMessage' => 'applications/differential/parser/commitmessage',
     'DifferentialCommitMessageData' => 'applications/differential/data/commitmessage',
     'DifferentialCommitMessageParserException' => 'applications/differential/parser/commitmessage/exception',
     'DifferentialController' => 'applications/differential/controller/base',
     'DifferentialDAO' => 'applications/differential/storage/base',
     'DifferentialDiff' => 'applications/differential/storage/diff',
     'DifferentialDiffContentMail' => 'applications/differential/mail/diffcontent',
     'DifferentialDiffCreateController' => 'applications/differential/controller/diffcreate',
     'DifferentialDiffProperty' => 'applications/differential/storage/diffproperty',
     'DifferentialDiffTableOfContentsView' => 'applications/differential/view/difftableofcontents',
     'DifferentialDiffViewController' => 'applications/differential/controller/diffview',
     'DifferentialHunk' => 'applications/differential/storage/hunk',
     'DifferentialInlineComment' => 'applications/differential/storage/inlinecomment',
     'DifferentialInlineCommentEditController' => 'applications/differential/controller/inlinecommentedit',
     'DifferentialInlineCommentPreviewController' => 'applications/differential/controller/inlinecommentpreview',
     'DifferentialInlineCommentView' => 'applications/differential/view/inlinecomment',
     'DifferentialLintStatus' => 'applications/differential/constants/lintstatus',
     'DifferentialMail' => 'applications/differential/mail/base',
     'DifferentialMarkupEngineFactory' => 'applications/differential/parser/markup',
     'DifferentialNewDiffMail' => 'applications/differential/mail/newdiff',
     'DifferentialReviewRequestMail' => 'applications/differential/mail/reviewrequest',
     'DifferentialRevision' => 'applications/differential/storage/revision',
     'DifferentialRevisionCommentListView' => 'applications/differential/view/revisioncommentlist',
     'DifferentialRevisionCommentView' => 'applications/differential/view/revisioncomment',
     'DifferentialRevisionControlSystem' => 'applications/differential/constants/revisioncontrolsystem',
     'DifferentialRevisionDetailView' => 'applications/differential/view/revisiondetail',
     'DifferentialRevisionEditController' => 'applications/differential/controller/revisionedit',
     'DifferentialRevisionEditor' => 'applications/differential/editor/revision',
     'DifferentialRevisionListController' => 'applications/differential/controller/revisionlist',
     'DifferentialRevisionListData' => 'applications/differential/data/revisionlist',
     'DifferentialRevisionStatus' => 'applications/differential/constants/revisionstatus',
     'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/revisionupdatehistory',
     'DifferentialRevisionViewController' => 'applications/differential/controller/revisionview',
     'DifferentialSubscribeController' => 'applications/differential/controller/subscribe',
     'DifferentialUnitStatus' => 'applications/differential/constants/unitstatus',
     'DiffusionBrowseController' => 'applications/diffusion/controller/browse',
     'DiffusionBrowseFileController' => 'applications/diffusion/controller/file',
     'DiffusionBrowseQuery' => 'applications/diffusion/query/browse/base',
     'DiffusionBrowseTableView' => 'applications/diffusion/view/browsetable',
     'DiffusionController' => 'applications/diffusion/controller/base',
     'DiffusionFileContent' => 'applications/diffusion/data/filecontent',
     'DiffusionFileContentQuery' => 'applications/diffusion/query/filecontent/base',
     'DiffusionGitBrowseQuery' => 'applications/diffusion/query/browse/git',
     'DiffusionGitFileContentQuery' => 'applications/diffusion/query/filecontent/git',
+    'DiffusionGitHistoryQuery' => 'applications/diffusion/query/history/git',
     'DiffusionGitRequest' => 'applications/diffusion/request/git',
+    'DiffusionHistoryController' => 'applications/diffusion/controller/history',
+    'DiffusionHistoryQuery' => 'applications/diffusion/query/history/base',
+    'DiffusionHistoryTableView' => 'applications/diffusion/view/historytable',
     'DiffusionHomeController' => 'applications/diffusion/controller/home',
+    'DiffusionPathChange' => 'applications/diffusion/data/pathchange',
     'DiffusionRepositoryPath' => 'applications/diffusion/data/repositorypath',
     'DiffusionRequest' => 'applications/diffusion/request/base',
     'Javelin' => 'infrastructure/javelin/api',
     'LiskDAO' => 'storage/lisk/dao',
     'ManiphestController' => 'applications/maniphest/controller/base',
     'ManiphestDAO' => 'applications/maniphest/storage/base',
     'ManiphestTask' => 'applications/maniphest/storage/task',
     'ManiphestTaskDetailController' => 'applications/maniphest/controller/taskdetail',
     'ManiphestTaskEditController' => 'applications/maniphest/controller/taskedit',
     'ManiphestTaskListController' => 'applications/maniphest/controller/tasklist',
     'ManiphestTaskListView' => 'applications/maniphest/view/tasklist',
     'ManiphestTaskPriority' => 'applications/maniphest/constants/priority',
     'ManiphestTaskSelectorSearchController' => 'applications/maniphest/controller/taskselectorsearch',
     'ManiphestTaskStatus' => 'applications/maniphest/constants/status',
     'ManiphestTaskSummaryView' => 'applications/maniphest/view/tasksummary',
     'ManiphestTransaction' => 'applications/maniphest/storage/transaction',
     'ManiphestTransactionDetailView' => 'applications/maniphest/view/transactiondetail',
     'ManiphestTransactionEditor' => 'applications/maniphest/editor/transaction',
     'ManiphestTransactionListView' => 'applications/maniphest/view/transactionlist',
     'ManiphestTransactionSaveController' => 'applications/maniphest/controller/transactionsave',
     'ManiphestTransactionType' => 'applications/maniphest/constants/transactiontype',
     'Phabricator404Controller' => 'applications/base/controller/404',
     'PhabricatorAuthController' => 'applications/auth/controller/base',
     'PhabricatorConduitAPIController' => 'applications/conduit/controller/api',
     'PhabricatorConduitConnectionLog' => 'applications/conduit/storage/connectionlog',
     'PhabricatorConduitConsoleController' => 'applications/conduit/controller/console',
     'PhabricatorConduitController' => 'applications/conduit/controller/base',
     'PhabricatorConduitDAO' => 'applications/conduit/storage/base',
     'PhabricatorConduitLogController' => 'applications/conduit/controller/log',
     'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/methodcalllog',
     'PhabricatorController' => 'applications/base/controller/base',
     'PhabricatorDaemon' => 'infrastructure/daemon/base',
     'PhabricatorDirectoryCategory' => 'applications/directory/storage/category',
     'PhabricatorDirectoryCategoryDeleteController' => 'applications/directory/controller/categorydelete',
     'PhabricatorDirectoryCategoryEditController' => 'applications/directory/controller/categoryedit',
     'PhabricatorDirectoryCategoryListController' => 'applications/directory/controller/categorylist',
     'PhabricatorDirectoryController' => 'applications/directory/controller/base',
     'PhabricatorDirectoryDAO' => 'applications/directory/storage/base',
     'PhabricatorDirectoryItem' => 'applications/directory/storage/item',
     'PhabricatorDirectoryItemDeleteController' => 'applications/directory/controller/itemdelete',
     'PhabricatorDirectoryItemEditController' => 'applications/directory/controller/itemedit',
     'PhabricatorDirectoryItemListController' => 'applications/directory/controller/itemlist',
     'PhabricatorDirectoryMainController' => 'applications/directory/controller/main',
     'PhabricatorDraft' => 'applications/draft/storage/draft',
     'PhabricatorDraftDAO' => 'applications/draft/storage/base',
     'PhabricatorEmailLoginController' => 'applications/auth/controller/email',
     'PhabricatorEmailTokenController' => 'applications/auth/controller/emailtoken',
     'PhabricatorEnv' => 'infrastructure/env',
     'PhabricatorFile' => 'applications/files/storage/file',
     'PhabricatorFileController' => 'applications/files/controller/base',
     'PhabricatorFileDAO' => 'applications/files/storage/base',
     'PhabricatorFileListController' => 'applications/files/controller/list',
     'PhabricatorFileStorageBlob' => 'applications/files/storage/storageblob',
     'PhabricatorFileURI' => 'applications/files/uri',
     'PhabricatorFileUploadController' => 'applications/files/controller/upload',
     'PhabricatorFileViewController' => 'applications/files/controller/view',
     'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/selector',
     'PhabricatorLiskDAO' => 'applications/base/storage/lisk',
     'PhabricatorLoginController' => 'applications/auth/controller/login',
     'PhabricatorLogoutController' => 'applications/auth/controller/logout',
     'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/base',
     'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/amazonses',
     'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/phpmailerlite',
     'PhabricatorMetaMTAController' => 'applications/metamta/controller/base',
     'PhabricatorMetaMTADAO' => 'applications/metamta/storage/base',
     'PhabricatorMetaMTADaemon' => 'applications/metamta/daemon/mta',
     'PhabricatorMetaMTAListController' => 'applications/metamta/controller/list',
     'PhabricatorMetaMTAMail' => 'applications/metamta/storage/mail',
     'PhabricatorMetaMTAMailingList' => 'applications/metamta/storage/mailinglist',
     'PhabricatorMetaMTAMailingListEditController' => 'applications/metamta/controller/mailinglistedit',
     'PhabricatorMetaMTAMailingListsController' => 'applications/metamta/controller/mailinglists',
     'PhabricatorMetaMTASendController' => 'applications/metamta/controller/send',
     'PhabricatorMetaMTAViewController' => 'applications/metamta/controller/view',
     'PhabricatorOAuthDefaultRegistrationController' => 'applications/auth/controller/oauthregistration/default',
     'PhabricatorOAuthDiagnosticsController' => 'applications/auth/controller/oauthdiagnostics',
     'PhabricatorOAuthFailureView' => 'applications/auth/view/oauthfailure',
     'PhabricatorOAuthLoginController' => 'applications/auth/controller/oauth',
     'PhabricatorOAuthProvider' => 'applications/auth/oauth/provider/base',
     'PhabricatorOAuthProviderFacebook' => 'applications/auth/oauth/provider/facebook',
     'PhabricatorOAuthProviderGithub' => 'applications/auth/oauth/provider/github',
     'PhabricatorOAuthRegistrationController' => 'applications/auth/controller/oauthregistration/base',
     'PhabricatorOAuthUnlinkController' => 'applications/auth/controller/unlink',
     'PhabricatorObjectHandle' => 'applications/phid/handle',
     'PhabricatorObjectHandleData' => 'applications/phid/handle/data',
     'PhabricatorObjectSelectorDialog' => 'view/control/objectselector',
     'PhabricatorPHID' => 'applications/phid/storage/phid',
     'PhabricatorPHIDAllocateController' => 'applications/phid/controller/allocate',
     'PhabricatorPHIDConstants' => 'applications/phid/constants',
     'PhabricatorPHIDController' => 'applications/phid/controller/base',
     'PhabricatorPHIDDAO' => 'applications/phid/storage/base',
     'PhabricatorPHIDListController' => 'applications/phid/controller/list',
     'PhabricatorPHIDLookupController' => 'applications/phid/controller/lookup',
     'PhabricatorPHIDType' => 'applications/phid/storage/type',
     'PhabricatorPHIDTypeEditController' => 'applications/phid/controller/typeedit',
     'PhabricatorPHIDTypeListController' => 'applications/phid/controller/typelist',
     'PhabricatorPeopleController' => 'applications/people/controller/base',
     'PhabricatorPeopleEditController' => 'applications/people/controller/edit',
     'PhabricatorPeopleListController' => 'applications/people/controller/list',
     'PhabricatorPeopleProfileController' => 'applications/people/controller/profile',
     'PhabricatorPeopleProfileEditController' => 'applications/people/controller/profileedit',
     'PhabricatorProject' => 'applications/project/storage/project',
     'PhabricatorProjectAffiliation' => 'applications/project/storage/affiliation',
     'PhabricatorProjectAffiliationEditController' => 'applications/project/controller/editaffiliation',
     'PhabricatorProjectController' => 'applications/project/controller/base',
     'PhabricatorProjectDAO' => 'applications/project/storage/base',
     'PhabricatorProjectEditController' => 'applications/project/controller/edit',
     'PhabricatorProjectListController' => 'applications/project/controller/list',
     'PhabricatorProjectProfile' => 'applications/project/storage/profile',
     'PhabricatorProjectProfileController' => 'applications/project/controller/profile',
     'PhabricatorRemarkupRuleDifferential' => 'infrastructure/markup/remarkup/markuprule/differential',
     'PhabricatorRemarkupRuleManiphest' => 'infrastructure/markup/remarkup/markuprule/maniphest',
     'PhabricatorRepository' => 'applications/repository/storage/repository',
     'PhabricatorRepositoryCommit' => 'applications/repository/storage/commit',
     'PhabricatorRepositoryCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/base',
     'PhabricatorRepositoryCommitParserDaemon' => 'applications/repository/daemon/commitparser',
     'PhabricatorRepositoryController' => 'applications/repository/controller/base',
     'PhabricatorRepositoryCreateController' => 'applications/repository/controller/create',
     'PhabricatorRepositoryDAO' => 'applications/repository/storage/base',
     'PhabricatorRepositoryDaemon' => 'applications/repository/daemon/base',
     'PhabricatorRepositoryEditController' => 'applications/repository/controller/edit',
     'PhabricatorRepositoryGitCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/git',
     'PhabricatorRepositoryGitHubNotification' => 'applications/repository/storage/githubnotification',
     'PhabricatorRepositoryGitHubPostReceiveController' => 'applications/repository/controller/github-post-receive',
     'PhabricatorRepositoryGitPullDaemon' => 'applications/repository/daemon/gitpull',
     'PhabricatorRepositoryListController' => 'applications/repository/controller/list',
     'PhabricatorRepositoryType' => 'applications/repository/constants/repositorytype',
     'PhabricatorSearchAbstractDocument' => 'applications/search/index/abstractdocument',
     'PhabricatorSearchBaseController' => 'applications/search/controller/base',
     'PhabricatorSearchController' => 'applications/search/controller/search',
     'PhabricatorSearchDAO' => 'applications/search/storage/base',
     'PhabricatorSearchDifferentialIndexer' => 'applications/search/index/indexer/differential',
     'PhabricatorSearchDocument' => 'applications/search/storage/document/document',
     'PhabricatorSearchDocumentField' => 'applications/search/storage/document/field',
     'PhabricatorSearchDocumentIndexer' => 'applications/search/index/indexer/base',
     'PhabricatorSearchDocumentRelationship' => 'applications/search/storage/document/relationship',
     'PhabricatorSearchExecutor' => 'applications/search/execute/base',
     'PhabricatorSearchField' => 'applications/search/constants/field',
     'PhabricatorSearchManiphestIndexer' => 'applications/search/index/indexer/maniphest',
     'PhabricatorSearchMySQLExecutor' => 'applications/search/execute/mysql',
     'PhabricatorSearchQuery' => 'applications/search/storage/query',
     'PhabricatorSearchRelationship' => 'applications/search/constants/relationship',
     'PhabricatorStandardPageView' => 'view/page/standard',
     'PhabricatorTimelineCursor' => 'applications/timeline/storage/cursor',
     'PhabricatorTimelineDAO' => 'applications/timeline/storage/base',
     'PhabricatorTimelineEvent' => 'applications/timeline/storage/event',
     'PhabricatorTimelineEventData' => 'applications/timeline/storage/eventdata',
     'PhabricatorTimelineIterator' => 'applications/timeline/cursor/iterator',
     'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/common',
     'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/base',
     'PhabricatorUser' => 'applications/people/storage/user',
     'PhabricatorUserDAO' => 'applications/people/storage/base',
     'PhabricatorUserOAuthInfo' => 'applications/people/storage/useroauthinfo',
     'PhabricatorUserProfile' => 'applications/people/storage/profile',
     'PhabricatorUserSettingsController' => 'applications/people/controller/settings',
     'PhabricatorXHProfController' => 'applications/xhprof/controller/base',
     'PhabricatorXHProfProfileController' => 'applications/xhprof/controller/profile',
     'PhabricatorXHProfProfileSymbolView' => 'applications/xhprof/view/symbol',
     'PhabricatorXHProfProfileTopLevelView' => 'applications/xhprof/view/toplevel',
   ),
   'function' =>
   array(
     '_qsprintf_check_scalar_type' => 'storage/qsprintf',
     '_qsprintf_check_type' => 'storage/qsprintf',
     'celerity_generate_unique_node_id' => 'infrastructure/celerity/api',
     'celerity_register_resource_map' => 'infrastructure/celerity/map',
     'javelin_render_tag' => 'infrastructure/javelin/markup',
     'phabricator_format_relative_time' => 'view/utils',
     'phabricator_format_timestamp' => 'view/utils',
     'phabricator_format_units_generic' => 'view/utils',
     'phabricator_render_form' => 'infrastructure/javelin/markup',
     'qsprintf' => 'storage/qsprintf',
     'queryfx' => 'storage/queryfx',
     'queryfx_all' => 'storage/queryfx',
     'queryfx_one' => 'storage/queryfx',
     'require_celerity_resource' => 'infrastructure/celerity/api',
     'vqsprintf' => 'storage/qsprintf',
     'vqueryfx' => 'storage/queryfx',
     'vqueryfx_all' => 'storage/queryfx',
     'xsprintf_query' => 'storage/qsprintf',
   ),
   'requires_class' =>
   array(
     'Aphront400Response' => 'AphrontResponse',
     'Aphront404Response' => 'AphrontResponse',
     'AphrontAjaxResponse' => 'AphrontResponse',
     'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration',
     'AphrontDefaultApplicationController' => 'AphrontController',
     'AphrontDialogResponse' => 'AphrontResponse',
     'AphrontDialogView' => 'AphrontView',
     'AphrontErrorView' => 'AphrontView',
     'AphrontFileResponse' => 'AphrontResponse',
     'AphrontFormCheckboxControl' => 'AphrontFormControl',
     'AphrontFormControl' => 'AphrontView',
     'AphrontFormDividerControl' => 'AphrontFormControl',
     'AphrontFormFileControl' => 'AphrontFormControl',
     'AphrontFormMarkupControl' => 'AphrontFormControl',
     'AphrontFormPasswordControl' => 'AphrontFormControl',
     'AphrontFormRecaptchaControl' => 'AphrontFormControl',
     'AphrontFormSelectControl' => 'AphrontFormControl',
     'AphrontFormStaticControl' => 'AphrontFormControl',
     'AphrontFormSubmitControl' => 'AphrontFormControl',
     'AphrontFormTextAreaControl' => 'AphrontFormControl',
     'AphrontFormTextControl' => 'AphrontFormControl',
     'AphrontFormTokenizerControl' => 'AphrontFormControl',
     'AphrontFormView' => 'AphrontView',
     'AphrontHeadsupActionListView' => 'AphrontView',
     'AphrontHeadsupActionView' => 'AphrontView',
     'AphrontMySQLDatabaseConnection' => 'AphrontDatabaseConnection',
     'AphrontNullView' => 'AphrontView',
     'AphrontPageView' => 'AphrontView',
     'AphrontPanelView' => 'AphrontView',
     'AphrontQueryConnectionException' => 'AphrontQueryException',
     'AphrontQueryConnectionLostException' => 'AphrontQueryRecoverableException',
     'AphrontQueryCountException' => 'AphrontQueryException',
     'AphrontQueryDuplicateKeyException' => 'AphrontQueryException',
     'AphrontQueryObjectMissingException' => 'AphrontQueryException',
     'AphrontQueryParameterException' => 'AphrontQueryException',
     'AphrontQueryRecoverableException' => 'AphrontQueryException',
     'AphrontRedirectException' => 'AphrontException',
     'AphrontRedirectResponse' => 'AphrontResponse',
     'AphrontRequestFailureView' => 'AphrontView',
     'AphrontSideNavView' => 'AphrontView',
     'AphrontTableView' => 'AphrontView',
     'AphrontWebpageResponse' => 'AphrontResponse',
     'CelerityResourceController' => 'AphrontController',
     'ConduitAPI_conduit_connect_Method' => 'ConduitAPIMethod',
     'ConduitAPI_conduit_ping_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_creatediff_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_createrevision_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_find_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_getcommitmessage_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_getcommitpaths_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_getdiff_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_markcommitted_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_parsecommitmessage_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_setdiffproperty_Method' => 'ConduitAPIMethod',
     'ConduitAPI_differential_updaterevision_Method' => 'ConduitAPIMethod',
     'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod',
     'ConduitAPI_user_find_Method' => 'ConduitAPIMethod',
     'DarkConsoleConfigPlugin' => 'DarkConsolePlugin',
     'DarkConsoleController' => 'PhabricatorController',
     'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin',
     'DarkConsoleRequestPlugin' => 'DarkConsolePlugin',
     'DarkConsoleServicesPlugin' => 'DarkConsolePlugin',
     'DarkConsoleXHProfPlugin' => 'DarkConsolePlugin',
     'DifferentialAddCommentView' => 'AphrontView',
     'DifferentialAttachController' => 'DifferentialController',
     'DifferentialCCWelcomeMail' => 'DifferentialReviewRequestMail',
     'DifferentialChangeset' => 'DifferentialDAO',
     'DifferentialChangesetDetailView' => 'AphrontView',
     'DifferentialChangesetListView' => 'AphrontView',
     'DifferentialChangesetViewController' => 'DifferentialController',
     'DifferentialComment' => 'DifferentialDAO',
     'DifferentialCommentMail' => 'DifferentialMail',
     'DifferentialCommentPreviewController' => 'DifferentialController',
     'DifferentialCommentSaveController' => 'DifferentialController',
     'DifferentialController' => 'PhabricatorController',
     'DifferentialDAO' => 'PhabricatorLiskDAO',
     'DifferentialDiff' => 'DifferentialDAO',
     'DifferentialDiffContentMail' => 'DifferentialMail',
     'DifferentialDiffCreateController' => 'DifferentialController',
     'DifferentialDiffProperty' => 'DifferentialDAO',
     'DifferentialDiffTableOfContentsView' => 'AphrontView',
     'DifferentialDiffViewController' => 'DifferentialController',
     'DifferentialHunk' => 'DifferentialDAO',
     'DifferentialInlineComment' => 'DifferentialDAO',
     'DifferentialInlineCommentEditController' => 'DifferentialController',
     'DifferentialInlineCommentPreviewController' => 'DifferentialController',
     'DifferentialInlineCommentView' => 'AphrontView',
     'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail',
     'DifferentialReviewRequestMail' => 'DifferentialMail',
     'DifferentialRevision' => 'DifferentialDAO',
     'DifferentialRevisionCommentListView' => 'AphrontView',
     'DifferentialRevisionCommentView' => 'AphrontView',
     'DifferentialRevisionDetailView' => 'AphrontView',
     'DifferentialRevisionEditController' => 'DifferentialController',
     'DifferentialRevisionListController' => 'DifferentialController',
     'DifferentialRevisionUpdateHistoryView' => 'AphrontView',
     'DifferentialRevisionViewController' => 'DifferentialController',
     'DifferentialSubscribeController' => 'DifferentialController',
     'DiffusionBrowseController' => 'DiffusionController',
     'DiffusionBrowseFileController' => 'DiffusionController',
     'DiffusionBrowseTableView' => 'AphrontView',
     'DiffusionController' => 'PhabricatorController',
     'DiffusionGitBrowseQuery' => 'DiffusionBrowseQuery',
     'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery',
+    'DiffusionGitHistoryQuery' => 'DiffusionHistoryQuery',
     'DiffusionGitRequest' => 'DiffusionRequest',
+    'DiffusionHistoryController' => 'DiffusionController',
+    'DiffusionHistoryTableView' => 'AphrontView',
     'DiffusionHomeController' => 'DiffusionController',
     'ManiphestController' => 'PhabricatorController',
     'ManiphestDAO' => 'PhabricatorLiskDAO',
     'ManiphestTask' => 'ManiphestDAO',
     'ManiphestTaskDetailController' => 'ManiphestController',
     'ManiphestTaskEditController' => 'ManiphestController',
     'ManiphestTaskListController' => 'ManiphestController',
     'ManiphestTaskListView' => 'AphrontView',
     'ManiphestTaskSelectorSearchController' => 'ManiphestController',
     'ManiphestTaskSummaryView' => 'AphrontView',
     'ManiphestTransaction' => 'ManiphestDAO',
     'ManiphestTransactionDetailView' => 'AphrontView',
     'ManiphestTransactionListView' => 'AphrontView',
     'ManiphestTransactionSaveController' => 'ManiphestController',
     'Phabricator404Controller' => 'PhabricatorController',
     'PhabricatorAuthController' => 'PhabricatorController',
     'PhabricatorConduitAPIController' => 'PhabricatorConduitController',
     'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO',
     'PhabricatorConduitConsoleController' => 'PhabricatorConduitController',
     'PhabricatorConduitController' => 'PhabricatorController',
     'PhabricatorConduitDAO' => 'PhabricatorLiskDAO',
     'PhabricatorConduitLogController' => 'PhabricatorConduitController',
     'PhabricatorConduitMethodCallLog' => 'PhabricatorConduitDAO',
     'PhabricatorController' => 'AphrontController',
     'PhabricatorDaemon' => 'PhutilDaemon',
     'PhabricatorDirectoryCategory' => 'PhabricatorDirectoryDAO',
     'PhabricatorDirectoryCategoryDeleteController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryCategoryEditController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryCategoryListController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryController' => 'PhabricatorController',
     'PhabricatorDirectoryDAO' => 'PhabricatorLiskDAO',
     'PhabricatorDirectoryItem' => 'PhabricatorDirectoryDAO',
     'PhabricatorDirectoryItemDeleteController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryItemEditController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryItemListController' => 'PhabricatorDirectoryController',
     'PhabricatorDirectoryMainController' => 'PhabricatorDirectoryController',
     'PhabricatorDraft' => 'PhabricatorDraftDAO',
     'PhabricatorDraftDAO' => 'PhabricatorLiskDAO',
     'PhabricatorEmailLoginController' => 'PhabricatorAuthController',
     'PhabricatorEmailTokenController' => 'PhabricatorAuthController',
     'PhabricatorFile' => 'PhabricatorFileDAO',
     'PhabricatorFileController' => 'PhabricatorController',
     'PhabricatorFileDAO' => 'PhabricatorLiskDAO',
     'PhabricatorFileListController' => 'PhabricatorFileController',
     'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO',
     'PhabricatorFileUploadController' => 'PhabricatorFileController',
     'PhabricatorFileViewController' => 'PhabricatorFileController',
     'PhabricatorLiskDAO' => 'LiskDAO',
     'PhabricatorLoginController' => 'PhabricatorAuthController',
     'PhabricatorLogoutController' => 'PhabricatorAuthController',
     'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter',
     'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter',
     'PhabricatorMetaMTAController' => 'PhabricatorController',
     'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO',
     'PhabricatorMetaMTAListController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTAMail' => 'PhabricatorMetaMTADAO',
     'PhabricatorMetaMTAMailingList' => 'PhabricatorMetaMTADAO',
     'PhabricatorMetaMTAMailingListEditController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTAMailingListsController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTASendController' => 'PhabricatorMetaMTAController',
     'PhabricatorMetaMTAViewController' => 'PhabricatorMetaMTAController',
     'PhabricatorOAuthDefaultRegistrationController' => 'PhabricatorOAuthRegistrationController',
     'PhabricatorOAuthDiagnosticsController' => 'PhabricatorAuthController',
     'PhabricatorOAuthFailureView' => 'AphrontView',
     'PhabricatorOAuthLoginController' => 'PhabricatorAuthController',
     'PhabricatorOAuthProviderFacebook' => 'PhabricatorOAuthProvider',
     'PhabricatorOAuthProviderGithub' => 'PhabricatorOAuthProvider',
     'PhabricatorOAuthRegistrationController' => 'PhabricatorAuthController',
     'PhabricatorOAuthUnlinkController' => 'PhabricatorAuthController',
     'PhabricatorPHID' => 'PhabricatorPHIDDAO',
     'PhabricatorPHIDAllocateController' => 'PhabricatorPHIDController',
     'PhabricatorPHIDController' => 'PhabricatorController',
     'PhabricatorPHIDDAO' => 'PhabricatorLiskDAO',
     'PhabricatorPHIDListController' => 'PhabricatorPHIDController',
     'PhabricatorPHIDLookupController' => 'PhabricatorPHIDController',
     'PhabricatorPHIDType' => 'PhabricatorPHIDDAO',
     'PhabricatorPHIDTypeEditController' => 'PhabricatorPHIDController',
     'PhabricatorPHIDTypeListController' => 'PhabricatorPHIDController',
     'PhabricatorPeopleController' => 'PhabricatorController',
     'PhabricatorPeopleEditController' => 'PhabricatorPeopleController',
     'PhabricatorPeopleListController' => 'PhabricatorPeopleController',
     'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController',
     'PhabricatorPeopleProfileEditController' => 'PhabricatorPeopleController',
     'PhabricatorProject' => 'PhabricatorProjectDAO',
     'PhabricatorProjectAffiliation' => 'PhabricatorProjectDAO',
     'PhabricatorProjectAffiliationEditController' => 'PhabricatorProjectController',
     'PhabricatorProjectController' => 'PhabricatorController',
     'PhabricatorProjectDAO' => 'PhabricatorLiskDAO',
     'PhabricatorProjectEditController' => 'PhabricatorProjectController',
     'PhabricatorProjectListController' => 'PhabricatorProjectController',
     'PhabricatorProjectProfile' => 'PhabricatorProjectDAO',
     'PhabricatorProjectProfileController' => 'PhabricatorProjectController',
     'PhabricatorRemarkupRuleDifferential' => 'PhutilRemarkupRule',
     'PhabricatorRemarkupRuleManiphest' => 'PhutilRemarkupRule',
     'PhabricatorRepository' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryCommit' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryCommitDiscoveryDaemon' => 'PhabricatorRepositoryDaemon',
     'PhabricatorRepositoryCommitParserDaemon' => 'PhabricatorRepositoryDaemon',
     'PhabricatorRepositoryController' => 'PhabricatorController',
     'PhabricatorRepositoryCreateController' => 'PhabricatorController',
     'PhabricatorRepositoryDAO' => 'PhabricatorLiskDAO',
     'PhabricatorRepositoryDaemon' => 'PhabricatorDaemon',
     'PhabricatorRepositoryEditController' => 'PhabricatorController',
     'PhabricatorRepositoryGitCommitDiscoveryDaemon' => 'PhabricatorRepositoryCommitDiscoveryDaemon',
     'PhabricatorRepositoryGitHubNotification' => 'PhabricatorRepositoryDAO',
     'PhabricatorRepositoryGitHubPostReceiveController' => 'PhabricatorRepositoryController',
     'PhabricatorRepositoryGitPullDaemon' => 'PhabricatorRepositoryDaemon',
     'PhabricatorRepositoryListController' => 'PhabricatorController',
     'PhabricatorSearchBaseController' => 'PhabricatorController',
     'PhabricatorSearchController' => 'PhabricatorSearchBaseController',
     'PhabricatorSearchDAO' => 'PhabricatorLiskDAO',
     'PhabricatorSearchDifferentialIndexer' => 'PhabricatorSearchDocumentIndexer',
     'PhabricatorSearchDocument' => 'PhabricatorSearchDAO',
     'PhabricatorSearchDocumentField' => 'PhabricatorSearchDAO',
     'PhabricatorSearchDocumentRelationship' => 'PhabricatorSearchDAO',
     'PhabricatorSearchManiphestIndexer' => 'PhabricatorSearchDocumentIndexer',
     'PhabricatorSearchMySQLExecutor' => 'PhabricatorSearchExecutor',
     'PhabricatorSearchQuery' => 'PhabricatorSearchDAO',
     'PhabricatorStandardPageView' => 'AphrontPageView',
     'PhabricatorTimelineCursor' => 'PhabricatorTimelineDAO',
     'PhabricatorTimelineDAO' => 'PhabricatorLiskDAO',
     'PhabricatorTimelineEvent' => 'PhabricatorTimelineDAO',
     'PhabricatorTimelineEventData' => 'PhabricatorTimelineDAO',
     'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController',
     'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController',
     'PhabricatorUser' => 'PhabricatorUserDAO',
     'PhabricatorUserDAO' => 'PhabricatorLiskDAO',
     'PhabricatorUserOAuthInfo' => 'PhabricatorUserDAO',
     'PhabricatorUserProfile' => 'PhabricatorUserDAO',
     'PhabricatorUserSettingsController' => 'PhabricatorPeopleController',
     'PhabricatorXHProfController' => 'PhabricatorController',
     'PhabricatorXHProfProfileController' => 'PhabricatorXHProfController',
     'PhabricatorXHProfProfileSymbolView' => 'AphrontView',
     'PhabricatorXHProfProfileTopLevelView' => 'AphrontView',
   ),
   'requires_interface' =>
   array(
   ),
 ));
diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php
index cc2ac4d24..9b6e8ef52 100644
--- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php
+++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php
@@ -1,298 +1,306 @@
 <?php
 
 /*
  * Copyright 2011 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 /**
  * @group aphront
  */
 class AphrontDefaultApplicationConfiguration
   extends AphrontApplicationConfiguration {
 
   public function __construct() {
 
   }
 
   public function getApplicationName() {
     return 'aphront-default';
   }
 
   public function getURIMap() {
     return $this->getResourceURIMapRules() + array(
       '/' => array(
         '$'                     => 'PhabricatorDirectoryMainController',
       ),
       '/directory/' => array(
         'item/$'
           => 'PhabricatorDirectoryItemListController',
         'item/edit/(?:(?P<id>\d+)/)?$'
           => 'PhabricatorDirectoryItemEditController',
         'item/delete/(?P<id>\d+)/'
           => 'PhabricatorDirectoryItemDeleteController',
         'category/$'
           => 'PhabricatorDirectoryCategoryListController',
         'category/edit/(?:(?P<id>\d+)/)?$'
           => 'PhabricatorDirectoryCategoryEditController',
         'category/delete/(?P<id>\d+)/'
           => 'PhabricatorDirectoryCategoryDeleteController',
       ),
       '/file/' => array(
         '$' => 'PhabricatorFileListController',
         'upload/$' => 'PhabricatorFileUploadController',
         '(?P<view>info)/(?P<phid>[^/]+)/' => 'PhabricatorFileViewController',
         '(?P<view>view)/(?P<phid>[^/]+)/' => 'PhabricatorFileViewController',
         '(?P<view>download)/(?P<phid>[^/]+)/' => 'PhabricatorFileViewController',
       ),
       '/phid/' => array(
         '$' => 'PhabricatorPHIDLookupController',
         'list/$' => 'PhabricatorPHIDListController',
         'type/$' => 'PhabricatorPHIDTypeListController',
         'type/edit/(?:(?P<id>\d+)/)?$' => 'PhabricatorPHIDTypeEditController',
         'new/$' => 'PhabricatorPHIDAllocateController',
       ),
       '/people/' => array(
         '$' => 'PhabricatorPeopleListController',
         'edit/(?:(?P<username>\w+)/)?$' => 'PhabricatorPeopleEditController',
       ),
       '/p/(?P<username>\w+)/$' => 'PhabricatorPeopleProfileController',
       '/profile/' => array(
         'edit/$' => 'PhabricatorPeopleProfileEditController',
       ),
       '/conduit/' => array(
         '$' => 'PhabricatorConduitConsoleController',
         'method/(?P<method>[^/]+)$' => 'PhabricatorConduitConsoleController',
         'log/$' => 'PhabricatorConduitLogController',
       ),
       '/api/(?P<method>[^/]+)$' => 'PhabricatorConduitAPIController',
 
 
       '/D(?P<id>\d+)' => 'DifferentialRevisionViewController',
       '/differential/' => array(
         '$' => 'DifferentialRevisionListController',
         'filter/(?P<filter>\w+)/$' => 'DifferentialRevisionListController',
         'diff/' => array(
           '(?P<id>\d+)/$' => 'DifferentialDiffViewController',
           'create/$' => 'DifferentialDiffCreateController',
         ),
         'changeset/$'  => 'DifferentialChangesetViewController',
         'revision/edit/(?:(?P<id>\d+)/)?$'
           => 'DifferentialRevisionEditController',
         'comment/' => array(
           'preview/(?P<id>\d+)/$' => 'DifferentialCommentPreviewController',
           'save/$' => 'DifferentialCommentSaveController',
           'inline/' => array(
             'preview/(?P<id>\d+)/$' =>
               'DifferentialInlineCommentPreviewController',
             'edit/(?P<id>\d+)/$' => 'DifferentialInlineCommentEditController',
           ),
         ),
         'attach/(?P<id>\d+)/(?P<type>\w+)/$' => 'DifferentialAttachController',
         'subscribe/(?P<action>add|rem)/(?P<id>\d+)/$'
           => 'DifferentialSubscribeController',
       ),
 
       '/typeahead/' => array(
         'common/(?P<type>\w+)/$'
           => 'PhabricatorTypeaheadCommonDatasourceController',
       ),
 
       '/mail/' => array(
         '$' => 'PhabricatorMetaMTAListController',
         'send/$' => 'PhabricatorMetaMTASendController',
         'view/(?P<id>\d+)/$' => 'PhabricatorMetaMTAViewController',
         'lists/$' => 'PhabricatorMetaMTAMailingListsController',
         'lists/edit/(?:(?P<id>\d+)/)?$'
           => 'PhabricatorMetaMTAMailingListEditController',
       ),
 
       '/login/' => array(
         '$' => 'PhabricatorLoginController',
         'email/$' => 'PhabricatorEmailLoginController',
         'etoken/(?P<token>\w+)/$' => 'PhabricatorEmailTokenController',
       ),
 
       '/logout/$' => 'PhabricatorLogoutController',
 
       '/oauth/' => array(
         '(?P<provider>github|facebook)/' => array(
           'login/$'     => 'PhabricatorOAuthLoginController',
           'diagnose/$'  => 'PhabricatorOAuthDiagnosticsController',
           'unlink/$'    => 'PhabricatorOAuthUnlinkController',
         ),
       ),
 
       '/xhprof/' => array(
         'profile/(?P<phid>[^/]+)/$' => 'PhabricatorXHProfProfileController',
       ),
 
       '/~/' => 'DarkConsoleController',
 
       '/settings/' => array(
         '(?:page/(?P<page>[^/]+)/)?$' => 'PhabricatorUserSettingsController',
       ),
 
       '/maniphest/' => array(
         '$' => 'ManiphestTaskListController',
         'view/(?P<view>\w+)/$' => 'ManiphestTaskListController',
         'task/' => array(
           'create/$' => 'ManiphestTaskEditController',
           'edit/(?P<id>\d+)/$' => 'ManiphestTaskEditController',
         ),
         'transaction/' => array(
           'save/' => 'ManiphestTransactionSaveController',
         ),
         'select/search/$' => 'ManiphestTaskSelectorSearchController',
       ),
 
       '/T(?P<id>\d+)$' => 'ManiphestTaskDetailController',
 
       '/github-post-receive/(?P<id>\d+)/(?P<token>[^/]+)/$'
         => 'PhabricatorRepositoryGitHubPostReceiveController',
 
       '/repository/' => array(
         '$'                     => 'PhabricatorRepositoryListController',
         'create/$'              => 'PhabricatorRepositoryCreateController',
         'edit/(?P<id>\d+)/(?:(?P<view>\w+)?/)?$' =>
           'PhabricatorRepositoryEditController',
         'delete/(?P<id>\d+)/$'  => 'PhabricatorRepositoryDeleteController',
       ),
 
       '/search/' => array(
         '$' => 'PhabricatorSearchController',
         '(?P<id>\d+)/$' => 'PhabricatorSearchController',
       ),
 
       '/project/' => array(
         '$' => 'PhabricatorProjectListController',
         'edit/(?:(?P<id>\d+)/)?$' => 'PhabricatorProjectEditController',
         'view/(?P<id>\d+)/$' => 'PhabricatorProjectProfileController',
         'affiliation/(?P<id>\d+)/$'
           => 'PhabricatorProjectAffiliationEditController',
       ),
 
       '/diffusion/' => array(
         '$' => 'DiffusionHomeController',
-        '(?P<callsign>[A-Z]+)/browse/'.
-          '(?P<path>.*?)'.
-          '(?:[;](?P<commit>[a-z0-9]+))?'.
-          '(?:[$](?P<line>\d+))?$'
-            => 'DiffusionBrowseController',
+        '(?P<callsign>[A-Z]+)' => array(
+          '/history/'.
+            '(?P<path>.*?)'.
+            '(?:[;](?P<commit>[a-z0-9]+))?'.
+            '$'
+              => 'DiffusionHistoryController',
+          '/browse/'.
+            '(?P<path>.*?)'.
+            '(?:[;](?P<commit>[a-z0-9]+))?'.
+            '(?:[$](?P<line>\d+))?'.
+            '$'
+              => 'DiffusionBrowseController',
+        ),
       ),
 
     );
   }
 
   protected function getResourceURIMapRules() {
     return array(
       '/res/' => array(
         '(?P<package>pkg/)?(?P<hash>[a-f0-9]{8})/(?P<path>.+\.(?:css|js))$'
           => 'CelerityResourceController',
       ),
     );
   }
 
   public function buildRequest() {
     $request = new AphrontRequest($this->getHost(), $this->getPath());
     $request->setRequestData($_GET + $_POST);
     $request->setApplicationConfiguration($this);
     return $request;
   }
 
   public function handleException(Exception $ex) {
 
     $class    = phutil_escape_html(get_class($ex));
     $message  = phutil_escape_html($ex->getMessage());
 
     $content =
       '<div class="aphront-unhandled-exception">'.
         '<h1>Unhandled Exception "'.$class.'": '.$message.'</h1>'.
         '<code>'.phutil_escape_html((string)$ex).'</code>'.
       '</div>';
 
     $user = $this->getRequest()->getUser();
     if (!$user) {
       // If we hit an exception very early, we won't have a user.
       $user = new PhabricatorUser();
     }
 
     $dialog = new AphrontDialogView();
     $dialog
       ->setTitle('Exception!')
       ->setClass('aphront-exception-dialog')
       ->setUser($user)
       ->appendChild($content)
       ->addCancelButton('/');
 
     $response = new AphrontDialogResponse();
     $response->setDialog($dialog);
 
     return $response;
   }
 
   public function willSendResponse(AphrontResponse $response) {
     $request = $this->getRequest();
     if ($response instanceof AphrontDialogResponse) {
       if (!$request->isAjax()) {
         $view = new PhabricatorStandardPageView();
         $view->setRequest($request);
         $view->appendChild(
           '<div style="padding: 2em 0;">'.
             $response->buildResponseString().
           '</div>');
         $response = new AphrontWebpageResponse();
         $response->setContent($view->render());
         return $response;
       } else {
         return id(new AphrontAjaxResponse())
           ->setContent(array(
             'dialog' => $response->buildResponseString(),
           ));
       }
     } else if ($response instanceof AphrontRedirectResponse) {
       if ($request->isAjax()) {
         return id(new AphrontAjaxResponse())
           ->setContent(
             array(
               'redirect' => $response->getURI(),
             ));
       }
     } else if ($response instanceof Aphront404Response) {
 
       $failure = new AphrontRequestFailureView();
       $failure->setHeader('404 Not Found');
       $failure->appendChild(
         '<p>The page you requested was not found.</p>');
 
       $view = new PhabricatorStandardPageView();
       $view->setTitle('404 Not Found');
       $view->setRequest($this->getRequest());
       $view->appendChild($failure);
 
       $response = new AphrontWebpageResponse();
       $response->setContent($view->render());
       $response->setHTTPResponseCode(404);
       return $response;
     }
 
     return $response;
   }
 
   public function build404Controller() {
     return array(new Phabricator404Controller($this->getRequest()), array());
   }
 
 
 }
diff --git a/src/applications/diffusion/controller/base/DiffusionController.php b/src/applications/diffusion/controller/base/DiffusionController.php
index 3e07b1230..5f6bc85bd 100644
--- a/src/applications/diffusion/controller/base/DiffusionController.php
+++ b/src/applications/diffusion/controller/base/DiffusionController.php
@@ -1,35 +1,47 @@
 <?php
 
 /*
  * Copyright 2011 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 abstract class DiffusionController extends PhabricatorController {
 
+  protected $diffusionRequest;
+
+  public function willProcessRequest(array $data) {
+    $this->diffusionRequest = DiffusionRequest::newFromAphrontRequestDictionary(
+      $data);
+  }
+
+  public function setDiffusionRequest(DiffusionRequest $request) {
+    $this->diffusionRequest = $request;
+    return $this;
+  }
+
   public function buildStandardPageResponse($view, array $data) {
 
     $page = $this->buildStandardPageView();
 
     $page->setApplicationName('Diffusion');
     $page->setBaseURI('/diffusion/');
     $page->setTitle(idx($data, 'title'));
     $page->setGlyph("\xE2\x89\x88");
     $page->appendChild($view);
 
     $response = new AphrontWebpageResponse();
     return $response->setContent($page->render());
   }
 
 }
diff --git a/src/applications/diffusion/controller/base/__init__.php b/src/applications/diffusion/controller/base/__init__.php
index cf7b05833..c68cb9850 100644
--- a/src/applications/diffusion/controller/base/__init__.php
+++ b/src/applications/diffusion/controller/base/__init__.php
@@ -1,15 +1,16 @@
 <?php
 /**
  * This file is automatically generated. Lint this module to rebuild it.
  * @generated
  */
 
 
 
 phutil_require_module('phabricator', 'aphront/response/webpage');
 phutil_require_module('phabricator', 'applications/base/controller/base');
+phutil_require_module('phabricator', 'applications/diffusion/request/base');
 
 phutil_require_module('phutil', 'utils');
 
 
 phutil_require_source('DiffusionController.php');
diff --git a/src/applications/diffusion/controller/browse/DiffusionBrowseController.php b/src/applications/diffusion/controller/browse/DiffusionBrowseController.php
index 411107105..5d1af4bab 100644
--- a/src/applications/diffusion/controller/browse/DiffusionBrowseController.php
+++ b/src/applications/diffusion/controller/browse/DiffusionBrowseController.php
@@ -1,95 +1,90 @@
 <?php
 
 /*
  * Copyright 2011 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 class DiffusionBrowseController extends DiffusionController {
 
-  public function willProcessRequest(array $data) {
-    $this->diffusionRequest = DiffusionRequest::newFromAphrontRequestDictionary(
-      $data);
-  }
-
   public function processRequest() {
     $drequest = $this->diffusionRequest;
 
     $browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest);
     $results = $browse_query->loadPaths();
 
     $content = array();
 
     if (!$results) {
 
       switch ($browse_query->getReasonForEmptyResultSet()) {
         case DiffusionBrowseQuery::REASON_IS_NONEXISTENT:
           $title = 'Path Does Not Exist';
           // TODO: Under git, this error message should be more specific. It
           // may exist on some other branch.
           $body  = "This path does not exist anywhere.";
           $severity = AphrontErrorView::SEVERITY_ERROR;
           break;
         case DiffusionBrowseQuery::REASON_IS_DELETED:
           // TODO: Format all these commits into nice VCS-agnostic links.
           $commit = $drequest->getCommit();
           $deleted = $browse_query->getDeletedAtCommit();
           $existed = $browse_query->getExistedAtCommit();
 
           $title = 'Path Was Deleted';
           $body = "This path does not exist at {$commit}. It was deleted in ".
                   "{$deleted} and last existed at {$existed}.";
           $severity = AphrontErrorView::SEVERITY_WARNING;
           break;
         case DiffusionBrowseQuery::REASON_IS_FILE:
           $controller = new DiffusionBrowseFileController($this->getRequest());
           $controller->setDiffusionRequest($drequest);
           return $this->delegateToController($controller);
           break;
         default:
           throw new Exception("Unknown failure reason!");
       }
 
       $error_view = new AphrontErrorView();
       $error_view->setSeverity($severity);
       $error_view->setTitle($title);
       $error_view->appendChild('<p>'.$body.'</p>');
 
       $content[] = $error_view;
 
     } else {
       $browse_table = new DiffusionBrowseTableView();
       $browse_table->setDiffusionRequest($drequest);
       $browse_table->setPaths($results);
 
       $browse_panel = new AphrontPanelView();
       $browse_panel->setHeader($drequest->getPath());
       $browse_panel->appendChild($browse_table);
 
       $content[] = $browse_panel;
 
       // TODO: Branch table
     }
 
     // TODO: Crumbs
     // TODO: Side nav
 
     return $this->buildStandardPageResponse(
       $content,
       array(
         'title' => basename($drequest->getPath()),
       ));
   }
 
 }
diff --git a/src/applications/diffusion/controller/browse/__init__.php b/src/applications/diffusion/controller/browse/__init__.php
index 39dd2990e..afb636203 100644
--- a/src/applications/diffusion/controller/browse/__init__.php
+++ b/src/applications/diffusion/controller/browse/__init__.php
@@ -1,18 +1,17 @@
 <?php
 /**
  * This file is automatically generated. Lint this module to rebuild it.
  * @generated
  */
 
 
 
 phutil_require_module('phabricator', 'applications/diffusion/controller/base');
 phutil_require_module('phabricator', 'applications/diffusion/controller/file');
 phutil_require_module('phabricator', 'applications/diffusion/query/browse/base');
-phutil_require_module('phabricator', 'applications/diffusion/request/base');
 phutil_require_module('phabricator', 'applications/diffusion/view/browsetable');
 phutil_require_module('phabricator', 'view/form/error');
 phutil_require_module('phabricator', 'view/layout/panel');
 
 
 phutil_require_source('DiffusionBrowseController.php');
diff --git a/src/applications/diffusion/controller/file/DiffusionBrowseFileController.php b/src/applications/diffusion/controller/file/DiffusionBrowseFileController.php
index 87f79b780..7dec1a0ba 100644
--- a/src/applications/diffusion/controller/file/DiffusionBrowseFileController.php
+++ b/src/applications/diffusion/controller/file/DiffusionBrowseFileController.php
@@ -1,47 +1,40 @@
 <?php
 
 /*
  * Copyright 2011 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 class DiffusionBrowseFileController extends DiffusionController {
 
-  private $diffusionRequest;
-
-  public function setDiffusionRequest(DiffusionRequest $request) {
-    $this->diffusionRequest = $request;
-    return $this;
-  }
-
   public function processRequest() {
     $file_query = DiffusionFileContentQuery::newFromDiffusionRequest(
       $this->diffusionRequest);
     $file_content = $file_query->loadFileContent();
 
     $corpus = phutil_render_tag(
       'textarea',
       array(
       ),
       phutil_escape_html($file_content->getCorpus()));
 
     // TODO: blame, color, line numbers, highlighting, etc etc
 
     return $this->buildStandardPageResponse(
       $corpus,
       array(
         'title' => 'Browse',
       ));
   }
 }
diff --git a/src/applications/diffusion/controller/file/DiffusionBrowseFileController.php b/src/applications/diffusion/controller/history/DiffusionHistoryController.php
similarity index 51%
copy from src/applications/diffusion/controller/file/DiffusionBrowseFileController.php
copy to src/applications/diffusion/controller/history/DiffusionHistoryController.php
index 87f79b780..3f5ee6869 100644
--- a/src/applications/diffusion/controller/file/DiffusionBrowseFileController.php
+++ b/src/applications/diffusion/controller/history/DiffusionHistoryController.php
@@ -1,47 +1,51 @@
 <?php
 
 /*
  * Copyright 2011 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-class DiffusionBrowseFileController extends DiffusionController {
+class DiffusionHistoryController extends DiffusionController {
 
-  private $diffusionRequest;
+  public function processRequest() {
+    $drequest = $this->diffusionRequest;
 
-  public function setDiffusionRequest(DiffusionRequest $request) {
-    $this->diffusionRequest = $request;
-    return $this;
-  }
+    $history_query = DiffusionHistoryQuery::newFromDiffusionRequest(
+      $drequest);
 
-  public function processRequest() {
-    $file_query = DiffusionFileContentQuery::newFromDiffusionRequest(
-      $this->diffusionRequest);
-    $file_content = $file_query->loadFileContent();
+    $history = $history_query->loadHistory();
 
-    $corpus = phutil_render_tag(
-      'textarea',
-      array(
-      ),
-      phutil_escape_html($file_content->getCorpus()));
+    $content = array();
 
-    // TODO: blame, color, line numbers, highlighting, etc etc
+    $history_table = new DiffusionHistoryTableView();
+    $history_table->setDiffusionRequest($drequest);
+    $history_table->setHistory($history);
+
+    $history_panel = new AphrontPanelView();
+    $history_panel->setHeader($drequest->getPath());
+    $history_panel->appendChild($history_table);
+
+    $content[] = $history_panel;
+
+    // TODO: Crumbs
+    // TODO: Side nav
 
     return $this->buildStandardPageResponse(
-      $corpus,
+      $content,
       array(
-        'title' => 'Browse',
+        'title' => 'history',
       ));
   }
+
 }
diff --git a/src/applications/diffusion/controller/browse/__init__.php b/src/applications/diffusion/controller/history/__init__.php
similarity index 55%
copy from src/applications/diffusion/controller/browse/__init__.php
copy to src/applications/diffusion/controller/history/__init__.php
index 39dd2990e..21bf7ac13 100644
--- a/src/applications/diffusion/controller/browse/__init__.php
+++ b/src/applications/diffusion/controller/history/__init__.php
@@ -1,18 +1,15 @@
 <?php
 /**
  * This file is automatically generated. Lint this module to rebuild it.
  * @generated
  */
 
 
 
 phutil_require_module('phabricator', 'applications/diffusion/controller/base');
-phutil_require_module('phabricator', 'applications/diffusion/controller/file');
-phutil_require_module('phabricator', 'applications/diffusion/query/browse/base');
-phutil_require_module('phabricator', 'applications/diffusion/request/base');
-phutil_require_module('phabricator', 'applications/diffusion/view/browsetable');
-phutil_require_module('phabricator', 'view/form/error');
+phutil_require_module('phabricator', 'applications/diffusion/query/history/base');
+phutil_require_module('phabricator', 'applications/diffusion/view/historytable');
 phutil_require_module('phabricator', 'view/layout/panel');
 
 
-phutil_require_source('DiffusionBrowseController.php');
+phutil_require_source('DiffusionHistoryController.php');
diff --git a/src/applications/diffusion/controller/base/DiffusionController.php b/src/applications/diffusion/data/pathchange/DiffusionPathChange.php
similarity index 56%
copy from src/applications/diffusion/controller/base/DiffusionController.php
copy to src/applications/diffusion/data/pathchange/DiffusionPathChange.php
index 3e07b1230..bdbda974a 100644
--- a/src/applications/diffusion/controller/base/DiffusionController.php
+++ b/src/applications/diffusion/data/pathchange/DiffusionPathChange.php
@@ -1,35 +1,33 @@
 <?php
 
 /*
  * Copyright 2011 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-abstract class DiffusionController extends PhabricatorController {
+final class DiffusionPathChange {
 
-  public function buildStandardPageResponse($view, array $data) {
+  private $commit;
 
-    $page = $this->buildStandardPageView();
-
-    $page->setApplicationName('Diffusion');
-    $page->setBaseURI('/diffusion/');
-    $page->setTitle(idx($data, 'title'));
-    $page->setGlyph("\xE2\x89\x88");
-    $page->appendChild($view);
+  final public function setCommit($commit) {
+    $this->commit = $commit;
+    return $this;
+  }
 
-    $response = new AphrontWebpageResponse();
-    return $response->setContent($page->render());
+  final public function getCommit() {
+    return $this->commit;
   }
 
+
 }
diff --git a/src/applications/diffusion/data/pathchange/__init__.php b/src/applications/diffusion/data/pathchange/__init__.php
new file mode 100644
index 000000000..1e0dcbd34
--- /dev/null
+++ b/src/applications/diffusion/data/pathchange/__init__.php
@@ -0,0 +1,10 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+
+phutil_require_source('DiffusionPathChange.php');
diff --git a/src/applications/diffusion/query/history/base/DiffusionHistoryQuery.php b/src/applications/diffusion/query/history/base/DiffusionHistoryQuery.php
new file mode 100644
index 000000000..ae20419d7
--- /dev/null
+++ b/src/applications/diffusion/query/history/base/DiffusionHistoryQuery.php
@@ -0,0 +1,57 @@
+<?php
+
+/*
+ * Copyright 2011 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+abstract class DiffusionHistoryQuery {
+
+  private $request;
+
+  final private function __construct() {
+    // <private>
+  }
+
+  final public static function newFromDiffusionRequest(
+    DiffusionRequest $request) {
+
+    $repository = $request->getRepository();
+
+    switch ($repository->getVersionControlSystem()) {
+      case 'git':
+        $class = 'DiffusionGitHistoryQuery';
+        break;
+      default:
+        throw new Exception("Unsupported VCS!");
+    }
+
+    PhutilSymbolLoader::loadClass($class);
+    $query = new $class();
+
+    $query->request = $request;
+
+    return $query;
+  }
+
+  final protected function getRequest() {
+    return $this->request;
+  }
+
+  final public function loadHistory() {
+    return $this->executeQuery();
+  }
+
+  abstract protected function executeQuery();
+}
diff --git a/src/applications/diffusion/query/history/base/__init__.php b/src/applications/diffusion/query/history/base/__init__.php
new file mode 100644
index 000000000..df2609001
--- /dev/null
+++ b/src/applications/diffusion/query/history/base/__init__.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phutil', 'symbols');
+
+
+phutil_require_source('DiffusionHistoryQuery.php');
diff --git a/src/applications/diffusion/query/history/git/DiffusionGitHistoryQuery.php b/src/applications/diffusion/query/history/git/DiffusionGitHistoryQuery.php
new file mode 100644
index 000000000..7e6cbd7e8
--- /dev/null
+++ b/src/applications/diffusion/query/history/git/DiffusionGitHistoryQuery.php
@@ -0,0 +1,66 @@
+<?php
+
+/*
+ * Copyright 2011 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+final class DiffusionGitHistoryQuery extends DiffusionHistoryQuery {
+
+  protected function executeQuery() {
+    $drequest = $this->getRequest();
+
+    $repository = $drequest->getRepository();
+    $path = $drequest->getPath();
+    $commit = $drequest->getCommit();
+
+    $local_path = $repository->getDetail('local-path');
+    $git = $drequest->getPathToGitBinary();
+
+    list($stdout) = execx(
+      '(cd %s && %s log '.
+        '-n %d '.
+        '--skip=%d '.
+        '-M '.
+        '-C '.
+        '-B '.
+        '--find-copies-harder '.
+        '--raw '.
+        '-t '.
+        '--abbrev=40 '.
+        '--pretty=format:%%x1c%%H%%x1d '.
+        '%s -- %s)',
+      $local_path,
+      $git,
+      $limit = 100,
+      $offset = 0,
+      $commit,
+      $path);
+
+    $commits = explode("\x1c", $stdout);
+    array_shift($commits); // \x1c character is first, remove empty record
+
+    $history = array();
+    foreach ($commits as $commit) {
+      list($hash, $raw) = explode("\x1d", $commit);
+
+      $item = new DiffusionPathChange();
+      $item->setCommit($hash);
+      $history[] = $item;
+    }
+
+    return $history;
+  }
+
+}
diff --git a/src/applications/diffusion/query/history/git/__init__.php b/src/applications/diffusion/query/history/git/__init__.php
new file mode 100644
index 000000000..c2a505f6d
--- /dev/null
+++ b/src/applications/diffusion/query/history/git/__init__.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/diffusion/data/pathchange');
+phutil_require_module('phabricator', 'applications/diffusion/query/history/base');
+
+phutil_require_module('phutil', 'future/exec');
+
+
+phutil_require_source('DiffusionGitHistoryQuery.php');
diff --git a/src/applications/diffusion/request/git/DiffusionGitRequest.php b/src/applications/diffusion/request/git/DiffusionGitRequest.php
index c1547d672..ab00541dc 100644
--- a/src/applications/diffusion/request/git/DiffusionGitRequest.php
+++ b/src/applications/diffusion/request/git/DiffusionGitRequest.php
@@ -1,106 +1,107 @@
 <?php
 
 /*
  * Copyright 2011 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 class DiffusionGitRequest extends DiffusionRequest {
 
   protected function initializeFromAphrontRequestDictionary() {
     parent::initializeFromAphrontRequestDictionary();
 
     $path = $this->path;
     $parts = explode('/', $path);
 
     $branch = array_shift($parts);
     $this->branch = $this->decodeBranchName($branch);
 
     $this->path = implode('/', $parts);
 
     if ($this->repository) {
       $local_path = $this->repository->getDetail('local-path');
       $git = $this->getPathToGitBinary();
 
       // TODO: This is not terribly efficient and does not produce terribly
       // good error messages, but it seems better to put error handling code
       // here than to try to do it in every query.
 
       $branch = $this->getBranch();
+
       execx(
         '(cd %s && %s rev-parse --verify %s)',
         $local_path,
         $git,
         $branch);
 
       if ($this->commit) {
         execx(
           '(cd %s && %s rev-parse --verify %s)',
           $local_path,
           $git,
           $this->commit);
         list($contains) = execx(
           '(cd %s && %s branch --contains %s)',
           $local_path,
           $git,
           $this->commit);
         $contains = array_filter(explode("\n", $contains));
         $found = false;
         foreach ($contains as $containing_branch) {
           $containing_branch = trim($containing_branch, "* \n");
           if ($containing_branch == $branch) {
             $found = true;
             break;
           }
         }
         if (!$found) {
           throw new Exception(
             "Commit does not exist on this branch!");
         }
       }
     }
 
 
   }
 
   public function getPathToGitBinary() {
     return PhabricatorEnv::getEnvConfig('git.path');
   }
 
   public function getBranch() {
     if ($this->branch) {
       return $this->branch;
     }
     if ($this->repository) {
       return $this->repository->getDetail('default-branch', 'master');
     }
     throw new Exception("Unable to determine branch!");
   }
 
   public function getCommit() {
     if ($this->commit) {
       return $this->commit;
     }
     return $this->getBranch();
   }
 
   private function decodeBranchName($branch) {
     return str_replace(':', '/', $branch);
   }
 
   private function encodeBranchName($branch) {
     return str_replace('/', ':', $branch);
   }
 
 }
diff --git a/src/applications/diffusion/view/browsetable/DiffusionBrowseTableView.php b/src/applications/diffusion/view/browsetable/DiffusionBrowseTableView.php
index 3ae2eda93..389ac421a 100644
--- a/src/applications/diffusion/view/browsetable/DiffusionBrowseTableView.php
+++ b/src/applications/diffusion/view/browsetable/DiffusionBrowseTableView.php
@@ -1,50 +1,51 @@
 <?php
 
 /*
  * Copyright 2011 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 final class DiffusionBrowseTableView extends AphrontView {
 
   private $request;
+  private $paths;
 
   public function setDiffusionRequest(DiffusionRequest $request) {
     $this->request = $request;
     return $this;
   }
 
   public function setPaths(array $paths) {
     $this->paths = $paths;
     return $this;
   }
 
   public function render() {
     $rows = array();
     foreach ($this->paths as $path) {
       $rows[] = array(
         phutil_escape_html($path->getPath()), // TODO: link
         // TODO: etc etc
       );
     }
 
     $view = new AphrontTableView($rows);
     $view->setHeaders(
       array(
         'Path',
       ));
     return $view->render();
   }
 
 }
diff --git a/src/applications/diffusion/view/browsetable/DiffusionBrowseTableView.php b/src/applications/diffusion/view/historytable/DiffusionHistoryTableView.php
similarity index 77%
copy from src/applications/diffusion/view/browsetable/DiffusionBrowseTableView.php
copy to src/applications/diffusion/view/historytable/DiffusionHistoryTableView.php
index 3ae2eda93..3f05c6d7c 100644
--- a/src/applications/diffusion/view/browsetable/DiffusionBrowseTableView.php
+++ b/src/applications/diffusion/view/historytable/DiffusionHistoryTableView.php
@@ -1,50 +1,51 @@
 <?php
 
 /*
  * Copyright 2011 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-final class DiffusionBrowseTableView extends AphrontView {
+final class DiffusionHistoryTableView extends AphrontView {
 
   private $request;
+  private $history;
 
   public function setDiffusionRequest(DiffusionRequest $request) {
     $this->request = $request;
     return $this;
   }
 
-  public function setPaths(array $paths) {
-    $this->paths = $paths;
+  public function setHistory(array $history) {
+    $this->history = $history;
     return $this;
   }
 
   public function render() {
     $rows = array();
-    foreach ($this->paths as $path) {
+    foreach ($this->history as $history) {
       $rows[] = array(
-        phutil_escape_html($path->getPath()), // TODO: link
+        phutil_escape_html($history->getCommit()), // TODO: link
         // TODO: etc etc
       );
     }
 
     $view = new AphrontTableView($rows);
     $view->setHeaders(
       array(
-        'Path',
+        'Commit',
       ));
     return $view->render();
   }
 
 }
diff --git a/src/applications/diffusion/view/historytable/__init__.php b/src/applications/diffusion/view/historytable/__init__.php
new file mode 100644
index 000000000..e53ae0b47
--- /dev/null
+++ b/src/applications/diffusion/view/historytable/__init__.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'view/base');
+phutil_require_module('phabricator', 'view/control/table');
+
+phutil_require_module('phutil', 'markup');
+
+
+phutil_require_source('DiffusionHistoryTableView.php');