Merge branch 'master' of ssh://git.eclipse.org/gitroot/orion/org.eclipse.orion.client
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/fileClient.js b/bundles/org.eclipse.orion.client.core/web/orion/fileClient.js
index f0bc66f..15bedc9 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/fileClient.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/fileClient.js
@@ -14,7 +14,7 @@
 
 /** @namespace The global container for eclipse APIs. */
 
-define(['i18n!orion/navigate/nls/messages', "orion/Deferred", "orion/auth",  "orion/i18nUtil", "orion/es5shim"], function(messages, Deferred, mAuth, i18nUtil){
+define(['i18n!orion/navigate/nls/messages', "orion/Deferred", "orion/auth",  "orion/i18nUtil"], function(messages, Deferred, mAuth, i18nUtil){
 
 	/**
 	 * This helper method implements invocation of the service call,
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/plugin.js b/bundles/org.eclipse.orion.client.core/web/orion/plugin.js
index df6f709..d850bc9 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/plugin.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/plugin.js
@@ -27,7 +27,6 @@
 	function PluginProvider(headers) {
 		var _headers = headers;
 		var _services = [];
-		var _conditions = [];
 		var _connected = false;
 		var _activePromises = {};
 		var _target = null;
@@ -51,7 +50,7 @@
 			for (var i = 0; i < _services.length; i++) {
 				services.push({serviceId: i, names: _services[i].names, methods: _services[i].methods, properties: _services[i].properties });
 			}
-			return {headers: _headers || {}, services: services, conditions: _conditions};		
+			return {headers: _headers || {}, services: services};		
 		}
 		
 		function _jsonXMLHttpRequestReplacer(name, value) {
@@ -150,8 +149,10 @@
 				throw new Error("Cannot register service. Plugin Provider is connected");
 			}
 			
-			if (typeof(names) === "string") {
+			if (typeof names === "string") {
 				names = [names];
+			} else if (!Array.isArray(names)) {
+				names =[];
 			}
 			
 			var method = null;
@@ -166,13 +167,6 @@
 		};
 		this.registerServiceProvider = this.registerService; // (deprecated) backwards compatibility only
 		
-		this.registerCondition = function(name, properties) {
-			if (_connected) {
-				throw new Error("Cannot register condition. Plugin Provider is connected");
-			}
-			_conditions.push({name: name, properties: properties});
-		};
-		
 		this.connect = function(callback, errback) {
 			if (_connected) {
 				if (callback) {
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/pluginregistry.js b/bundles/org.eclipse.orion.client.core/web/orion/pluginregistry.js
index 5256593..234c602 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/pluginregistry.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/pluginregistry.js
@@ -165,13 +165,11 @@
 		function _createServiceProperties(service) {
 			var properties = JSON.parse(JSON.stringify(service.properties));
 			properties.__plugin__ = _url; //TODO: eliminate
-			if (!properties.objectClass) {
-				var objectClass = service.names || service.type || [];
-				if (!Array.isArray(objectClass)) {
-					objectClass = [objectClass];
-				}
-				properties.objectClass = objectClass;
+			var objectClass = service.names || service.type || [];
+			if (!Array.isArray(objectClass)) {
+				objectClass = [objectClass];
 			}
+			properties.objectClass = objectClass;
 			return properties;
 		}
 		
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/preferences.js b/bundles/org.eclipse.orion.client.core/web/orion/preferences.js
index b87971a..d7e938d 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/preferences.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/preferences.js
@@ -11,7 +11,7 @@
 
 /*global define window localStorage */
 
-define(['require', 'orion/Deferred', 'orion/xhr', 'orion/es5shim'], function(require, Deferred, xhr){
+define(['require', 'orion/Deferred', 'orion/xhr'], function(require, Deferred, xhr){
 	/**
 	 * Constructs a new preferences instance. This constructor is not
 	 * intended to be used by clients. Preferences should instead be
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/serviceregistry.js b/bundles/org.eclipse.orion.client.core/web/orion/serviceregistry.js
index 11a809a..cc4c2eb 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/serviceregistry.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/serviceregistry.js
@@ -11,7 +11,7 @@
  *******************************************************************************/
 /*global define console */
 
-define(["orion/Deferred", "orion/EventTarget", "orion/es5shim"], function(Deferred, EventTarget) {
+define(["orion/Deferred", "orion/EventTarget"], function(Deferred, EventTarget) {
 
 	/**
 	 * Creates a new service reference.
@@ -25,8 +25,8 @@
 
 	function ServiceReference(serviceId, objectClass, properties) {
 		this._properties = properties || {};
-		this._properties.objectClass = objectClass;
 		this._properties["service.id"] = serviceId;
+		this._properties.objectClass = objectClass;
 		this._properties["service.names"] = objectClass;
 	}
 
@@ -93,8 +93,8 @@
 		setProperties: function(properties) {
 			var oldProperties = this._serviceReference._properties;
 			this._serviceReference._properties = properties || {};
-			properties.objectClass = oldProperties.objectClass;
 			properties["service.id"] = this._serviceId;
+			properties.objectClass = oldProperties.objectClass;
 			properties["service.names"] = oldProperties["service.names"];
 			this._internalRegistry.modifyService(this._serviceId);
 		}
@@ -147,7 +147,7 @@
 
 	function ServiceRegistry() {
 		this._entries = [];
-		this._typedReferences = {};
+		this._namedReferences = {};
 		this._serviceEventTarget = new EventTarget();
 		var _this = this;
 		this._internalRegistry = {
@@ -164,13 +164,13 @@
 				_this._entries[serviceId] = null;
 				var objectClass = reference.getProperty("objectClass");
 				objectClass.forEach(function(type) {
-					var typedReferences = _this._typedReferences[type];
-					for (var i = 0; i < typedReferences.length; i++) {
-						if (typedReferences[i] === reference) {
-							if (typedReferences.length === 1) {
-								delete _this._typedReferences[type];
+					var namedReferences = _this._namedReferences[type];
+					for (var i = 0; i < namedReferences.length; i++) {
+						if (namedReferences[i] === reference) {
+							if (namedReferences.length === 1) {
+								delete _this._namedReferences[type];
 							} else {
-								typedReferences.splice(i, 1);
+								namedReferences.splice(i, 1);
 							}
 							break;
 						}
@@ -198,7 +198,7 @@
 		getService: function(typeOrServiceReference) {
 			var service;
 			if (typeof typeOrServiceReference === "string") {
-				var references = this._typedReferences[typeOrServiceReference];
+				var references = this._namedReferences[typeOrServiceReference];
 				if (references) {
 					references.some(function(reference) {
 						service = this._entries[reference.getProperty("service.id")].service;
@@ -221,7 +221,7 @@
 		 */
 		getServiceReferences: function(name) {
 			if (name) {
-				return this._typedReferences[name] ? this._typedReferences[name] : [];
+				return this._namedReferences[name] ? this._namedReferences[name] : [];
 			}
 			var result = [];
 			this._entries.forEach(function(entry) {
@@ -233,28 +233,28 @@
 		},
 		/**
 		 * Registers a service with this registry.
-		 * @param {String|String[]} types the types of the service being registered
+		 * @param {String|String[]} names the name or names of the service being registered
 		 * @param {Object} service The service implementation
 		 * @param {Object} properties A JSON collection of declarative service properties
 		 * @returns {orion.serviceregistry.ServiceRegistration} A service registration object for the service.
 		 */
-		registerService: function(types, service, properties) {
+		registerService: function(names, service, properties) {
 			if (typeof service === "undefined" ||  service === null) {
 				throw new Error("invalid service");
 			}
 			
-			if (typeof types === "string") {
-				types = [types];
-			} else if (!Array.isArray(types)) {
-				types = [];
+			if (typeof names === "string") {
+				names = [names];
+			} else if (!Array.isArray(names)) {
+				names = [];
 			}
 			
 			var serviceId = this._entries.length;			
-			var reference = new ServiceReference(serviceId, types, properties);
-			var typedReferences = this._typedReferences;
-			types.forEach(function(name) {
-				typedReferences[name] = typedReferences[name] || [];
-				typedReferences[name].push(reference);
+			var reference = new ServiceReference(serviceId, names, properties);
+			var namedReferences = this._namedReferences;
+			names.forEach(function(name) {
+				namedReferences[name] = namedReferences[name] || [];
+				namedReferences[name].push(reference);
 			});
 			var deferredService = new DeferredService(service, this._internalRegistry.isRegistered.bind(null, serviceId));
 			this._entries.push({
diff --git a/bundles/org.eclipse.orion.client.editor/web/orion/textview/textView.js b/bundles/org.eclipse.orion.client.editor/web/orion/textview/textView.js
index fe53fb8..6653e72 100644
--- a/bundles/org.eclipse.orion.client.editor/web/orion/textview/textView.js
+++ b/bundles/org.eclipse.orion.client.editor/web/orion/textview/textView.js
@@ -583,10 +583,12 @@
 							}
 						}
 						if (isIE) {
-							var logicalXDPI = window.screen.logicalXDPI;
-							var deviceXDPI = window.screen.deviceXDPI;
-							result.left = result.left * logicalXDPI / deviceXDPI;
-							result.right = result.right * logicalXDPI / deviceXDPI;
+							var xFactor = window.screen.logicalXDPI / window.screen.deviceXDPI;
+							var yFactor = window.screen.logicalYDPI / window.screen.deviceYDPI;
+							result.left = result.left * xFactor;
+							result.right = result.right * xFactor;
+							result.top = result.top * yFactor;
+							result.bottom = result.bottom * yFactor;
 						}
 						break;
 					}
@@ -752,8 +754,8 @@
 				if (x < 0) { x = 0; }
 				if (x > (lineRect.right - lineRect.left)) { x = lineRect.right - lineRect.left; }
 			}
-			var logicalXDPI = isIE ? window.screen.logicalXDPI : 1;
-			var deviceXDPI = isIE ? window.screen.deviceXDPI : 1;
+			var xFactor = isIE ? window.screen.logicalXDPI / window.screen.deviceXDPI : 1;
+			var yFactor = isIE ? window.screen.logicalYDPI / window.screen.deviceYDPI : 1;
 			var offset = lineStart;
 			var lineChild = child.firstChild;
 			done:
@@ -789,10 +791,10 @@
 								var found = false;
 								for (var k = 0; k < rects.length; k++) {
 									rect = rects[k];
-									rangeLeft = rect.left * logicalXDPI / deviceXDPI - lineRect.left;
-									rangeRight = rect.right * logicalXDPI / deviceXDPI - lineRect.left;
-									rangeTop = rect.top * logicalXDPI / deviceXDPI - lineRect.top;
-									rangeBottom = rect.bottom * logicalXDPI / deviceXDPI - lineRect.top;
+									rangeLeft = rect.left * xFactor - lineRect.left;
+									rangeRight = rect.right * xFactor - lineRect.left;
+									rangeTop = rect.top * yFactor - lineRect.top;
+									rangeBottom = rect.bottom * yFactor - lineRect.top;
 									if (rangeLeft <= x && x < rangeRight && (!view._wrapMode || (rangeTop <= y && y < rangeBottom))) {
 										found = true;
 										break;
@@ -816,8 +818,8 @@
 								range.moveEnd("character", end - start); //$NON-NLS-0$
 							}
 							rect = range.getClientRects()[0];
-							rangeLeft = rect.left * logicalXDPI / deviceXDPI - lineRect.left;
-							rangeRight = rect.right * logicalXDPI / deviceXDPI - lineRect.left;
+							rangeLeft = rect.left * xFactor - lineRect.left;
+							rangeRight = rect.right * xFactor - lineRect.left;
 							//TODO test for character trailing (wrong for bidi)
 							if (x > (rangeLeft + (rangeRight - rangeLeft) / 2)) {
 								offset++;
diff --git a/bundles/org.eclipse.orion.client.git/web/git/git-log.css b/bundles/org.eclipse.orion.client.git/web/git/git-log.css
index c56acd3..9f75bd7 100644
--- a/bundles/org.eclipse.orion.client.git/web/git/git-log.css
+++ b/bundles/org.eclipse.orion.client.git/web/git/git-log.css
@@ -12,4 +12,32 @@
 
 @import "css/git.css";
 
-@import "../css/images.css";
\ No newline at end of file
+@import "../css/images.css";
+
+@import "../settings/settings.css";
+
+@import "../css/UploaderFileList.css";
+
+@import "../css/sections.css";
+
+.tag-description {
+	white-space: normal;
+	padding-right: 10px;
+	min-width: 100px;
+	max-width: 700px;
+}
+
+.lightTreeTableRow {
+	border-bottom: 1px solid #e6e6e6;
+}
+
+.darkTreeTableRow {
+	border-bottom: 1px solid #e6e6e6;
+}
+
+.stretch {
+	float: left;
+	position: relative;
+	white-space:normal;
+	max-width:600px;
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.orion.client.git/web/git/git-log2.css b/bundles/org.eclipse.orion.client.git/web/git/git-log2.css
new file mode 100644
index 0000000..27feab1
--- /dev/null
+++ b/bundles/org.eclipse.orion.client.git/web/git/git-log2.css
@@ -0,0 +1,43 @@
+@import "../org.dojotoolkit/dojo/resources/dojo.css";

+

+@import "../org.dojotoolkit/dijit/themes/claro/claro.css";

+

+@import "../org.dojotoolkit/dijit/themes/claro/form/Common.css";

+

+@import "../org.dojotoolkit/dijit/themes/claro/form/Button.css";

+

+@import "../css/layout.css";

+

+@import "../css/ide.css";

+

+@import "css/git.css";

+

+@import "../css/images.css";

+

+@import "../settings/settings.css";

+

+@import "../css/UploaderFileList.css";

+

+@import "../css/sections.css";

+

+.tag-description {

+	white-space: normal;

+	padding-right: 10px;

+	min-width: 100px;

+	max-width: 700px;

+}

+

+.lightTreeTableRow {

+	border-bottom: 1px solid #e6e6e6;

+}

+

+.darkTreeTableRow {

+	border-bottom: 1px solid #e6e6e6;

+}

+

+.stretch {

+	float: left;

+	position: relative;

+	white-space:normal;

+	max-width:600px;

+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.orion.client.git/web/git/git-log2.html b/bundles/org.eclipse.orion.client.git/web/git/git-log2.html
new file mode 100644
index 0000000..527e800
--- /dev/null
+++ b/bundles/org.eclipse.orion.client.git/web/git/git-log2.html
@@ -0,0 +1,57 @@
+<!doctype html>

+<html style="height: 100%" >

+    <head>

+		<meta name="copyright" content="Copyright (c) IBM Corporation and others 2012." >

+		<meta http-equiv="Content-Language" content="en-us">

+		<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

+    	<title>Git Log</title>

+    	<link rel="stylesheet" type="text/css" href="git-log2.css" />

+		<link rel="shortcut icon" href="/log.ico" />

+   		<script type="text/javascript" src="../requirejs/require.js"></script>

+		<script type="text/javascript">

+		require({

+			  baseUrl: '..',

+			  packages: [

+			    {

+			      name: 'dojo',

+			      location: 'org.dojotoolkit/dojo',

+			      main: 'lib/main-browser',

+			      lib: '.'

+			    },

+			    {

+			      name: 'dijit',

+			      location: 'org.dojotoolkit/dijit',

+			      main: 'lib/main',

+			      lib: '.'

+			    },

+			    {

+			      name: 'dojox',

+			      location: 'org.dojotoolkit/dojox',

+			      main: 'lib/main',

+			      lib: '.'

+			    }		    

+			  ],

+			  paths: {

+				  text: 'requirejs/text',

+				  i18n: 'requirejs/i18n',

+			      domReady: 'requirejs/domReady'	    

+			  }

+			});

+		

+		require(["git-log2.js"]);

+		</script>

+   </head>

+

+	<body id="orion-gitlog" style="height: 100%;" class="claro orionPage">

+		<div class="content-fixedHeight">

+			<div class="fixedToolbarHolder mainpane mainPanelLayout">

+				<div class="mainToolbar toolComposite" id="pageToolbar"></div>

+				<div id="mainNode" class="toolbarTarget">

+					<div id="table" class="settings displayTable" style="padding-bottom: 20px;">

+					</div>

+				</div>

+			</div>

+		</div>

+		<div class="footer-fixed-bottom footer" id="footer"></div>

+	</body>

+</html>

diff --git a/bundles/org.eclipse.orion.client.git/web/git/git-log2.js b/bundles/org.eclipse.orion.client.git/web/git/git-log2.js
new file mode 100644
index 0000000..780cf8e
--- /dev/null
+++ b/bundles/org.eclipse.orion.client.git/web/git/git-log2.js
@@ -0,0 +1,79 @@
+/******************************************************************************* 

+ * @license

+ * Copyright (c) 2011, 2012 IBM Corporation and others.

+ * All rights reserved. This program and the accompanying materials are made 

+ * available under the terms of the Eclipse Public License v1.0 

+ * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 

+ * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 

+ * 

+ * Contributors: IBM Corporation - initial API and implementation

+ ******************************************************************************/

+

+/*global window define document dijit */

+/*browser:true*/

+define(['i18n!git/nls/gitmessages', 'require', 'dojo', 'orion/bootstrap', 'orion/status', 'orion/progress', 'orion/commands',

+        'orion/auth', 'orion/dialogs', 'orion/selection', 'orion/fileClient', 'orion/operationsClient', 'orion/searchClient', 'orion/globalCommands', 'orion/git/gitClient',

+        'orion/ssh/sshTools', 'orion/git/gitLogExplorer', 'orion/git/gitCommands',

+	    'orion/links', 'dojo/hash'], 

+		function(messages, require, dojo, mBootstrap, mStatus, mProgress, mCommands, mAuth, mDialogs, mSelection, mFileClient, mOperationsClient,

+					mSearchClient, mGlobalCommands, mGitClient, mSshTools, mGitLogExplorer, mGitCommands, mLinks) {

+

+		mBootstrap.startup().then(function(core) {

+			var serviceRegistry = core.serviceRegistry;

+			var preferences = core.preferences;

+			

+			var operationsClient = new mOperationsClient.OperationsClient(serviceRegistry);

+			new mStatus.StatusReportingService(serviceRegistry, operationsClient, "statusPane", "notifications", "notificationArea"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+			new mProgress.ProgressService(serviceRegistry, operationsClient);

+			new mDialogs.DialogService(serviceRegistry);

+			var selection = new mSelection.Selection(serviceRegistry);

+			new mSshTools.SshService(serviceRegistry);

+			var commandService = new mCommands.CommandService({serviceRegistry: serviceRegistry, selection: selection});

+			var linkService = new mLinks.TextLinkService({serviceRegistry: serviceRegistry});

+		

+			// Git operations

+			var gitClient = new mGitClient.GitService(serviceRegistry);

+			var fileClient = new mFileClient.FileClient(serviceRegistry);

+			var searcher = new mSearchClient.Searcher({serviceRegistry: serviceRegistry, fileService: fileClient, commandService: commandService});

+

+			// Git log explorer

+			var explorer = new mGitLogExplorer.GitLogExplorer(serviceRegistry, selection, null, "table", "pageTitle", "pageActions", "selectionTools", "pageNavigationActions", "itemLevelCommands");

+			mGlobalCommands.setPageCommandExclusions(["eclipse.git.remote", "eclipse.git.log"]); //$NON-NLS-1$ //$NON-NLS-0$

+			mGlobalCommands.generateBanner("orion-gitlog", serviceRegistry, commandService, preferences, searcher, explorer); //$NON-NLS-0$

+			

+			//TODO this should be removed and contributed by a plug-in

+			mGitCommands.createFileCommands(serviceRegistry, commandService, explorer, "pageActions", "selectionTools"); //$NON-NLS-1$ //$NON-NLS-0$

+			

+			// define the command contributions - where things appear, first the groups

+			commandService.addCommandGroup("itemLevelCommands", "eclipse.gitGroup.nav", 200, messages["More"]); //$NON-NLS-1$ //$NON-NLS-0$

+			commandService.addCommandGroup("pageActions", "eclipse.gitGroup.page", 100); //$NON-NLS-1$ //$NON-NLS-0$

+			commandService.addCommandGroup("selectionTools", "eclipse.selectionGroup", 500, "More"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+			

+			// commands appearing directly in local actions column

+			commandService.registerCommandContribution("itemLevelCommands", "eclipse.openGitCommit", 1); //$NON-NLS-1$ //$NON-NLS-0$

+			commandService.registerCommandContribution("itemLevelCommands", "eclipse.compareWithWorkingTree", 2); //$NON-NLS-1$ //$NON-NLS-0$

+		

+			// selection based command contributions in nav toolbar

+			commandService.registerCommandContribution("selectionTools", "eclipse.compareGitCommits", 1, "eclipse.selectionGroup"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+			

+			// git contributions

+			commandService.registerCommandContribution("pageActions", "eclipse.orion.git.fetch", 100, "eclipse.gitGroup.page"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+			commandService.registerCommandContribution("pageActions", "eclipse.orion.git.fetchForce", 100, "eclipse.gitGroup.page"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+			commandService.registerCommandContribution("pageActions", "eclipse.orion.git.merge", 100, "eclipse.gitGroup.page"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+			commandService.registerCommandContribution("pageActions", "eclipse.orion.git.push", 100, "eclipse.gitGroup.page"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+			commandService.registerCommandContribution("pageActions", "eclipse.orion.git.pushForce", 100, "eclipse.gitGroup.page"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+			commandService.registerCommandContribution("itemLevelCommands", "eclipse.orion.git.addTag", 3); //$NON-NLS-1$ //$NON-NLS-0$

+			commandService.registerCommandContribution("itemLevelCommands", "eclipse.orion.git.cherryPick", 3); //$NON-NLS-1$ //$NON-NLS-0$

+			// page navigation actions

+			commandService.registerCommandContribution("pageNavigationActions", "eclipse.orion.git.previousLog2Page", 1); //$NON-NLS-1$ //$NON-NLS-0$

+			commandService.registerCommandContribution("pageNavigationActions", "eclipse.orion.git.nextLog2Page", 2); //$NON-NLS-1$ //$NON-NLS-0$

+

+			explorer.redisplay();

+

+			// every time the user manually changes the hash, we need to load the

+			// workspace with that name

+			dojo.subscribe("/dojo/hashchange", explorer, function(){

+				explorer.redisplay();

+			});

+		});

+	});

diff --git a/bundles/org.eclipse.orion.client.git/web/git/nls/root/gitmessages.js b/bundles/org.eclipse.orion.client.git/web/git/nls/root/gitmessages.js
index cfdbf0a..af9e0d9 100644
--- a/bundles/org.eclipse.orion.client.git/web/git/nls/root/gitmessages.js
+++ b/bundles/org.eclipse.orion.client.git/web/git/nls/root/gitmessages.js
@@ -192,7 +192,9 @@
 	"Private key:": "Private key:",
 	"Passphrase (optional):": "Passphrase (optional):",
 	" commit: ": " commit: ",
-	"parent: ": "parent: ",
+	"parent: ": "parent: ",

+	"branches: ": "branches: ",

+	"tags: ": "tags: ",
 	" authored by ${0} {${1}) on ${2}": " authored by ${0} {${1}) on ${2}",
 	"Content": "Content",
 	"Go to ${0} section": "Go to ${0} section",
diff --git a/bundles/org.eclipse.orion.client.git/web/orion/git/gitCommands.js b/bundles/org.eclipse.orion.client.git/web/orion/git/gitCommands.js
index 3a2d793..c5b868d 100644
--- a/bundles/org.eclipse.orion.client.git/web/orion/git/gitCommands.js
+++ b/bundles/org.eclipse.orion.client.git/web/orion/git/gitCommands.js
@@ -840,7 +840,7 @@
 				return mCompareUtils.generateCompareHref(data.items.DiffLocation, {});
 			},
 			visibleWhen : function(item) {
-				return item.Type === "Commit" && !explorer.isDirectory; //$NON-NLS-0$
+				return item.Type === "Commit" && item.ContentLocation != null && !explorer.isDirectory; //$NON-NLS-0$
 			}
 		});
 		commandService.addCommand(compareWithWorkingTree);
@@ -992,57 +992,75 @@
 					commandService.collectParameters(commandInvocation);
 				};
 				
-				if (commandInvocation.parameters && commandInvocation.parameters.optionsRequested){
-					commandInvocation.parameters = null;
-					commandInvocation.optionsRequested = true;
-					commandService.collectParameters(commandInvocation);
-					return;
-				}
-
-				exports.gatherSshCredentials(serviceRegistry, commandInvocation).then(
-					function(options) {
-						var gitService = serviceRegistry.getService("orion.git.provider"); //$NON-NLS-0$
-						var statusService = serviceRegistry.getService("orion.page.message"); //$NON-NLS-0$
-						var deferred = gitService.doFetch(path, true,
-								options.gitSshUsername,
-								options.gitSshPassword,
-								options.knownHosts,
-								options.gitPrivateKey,
-								options.gitPassphrase);
-						statusService.createProgressMonitor(deferred, messages['Fetching remote: '] + path);
-						deferred.then(
-							function(jsonData, secondArg) {
-								exports.handleProgressServiceResponse2(jsonData, serviceRegistry, 
-									function() {
-										gitService.getGitRemote(path).then(
-											function(jsonData){
-												var remoteJsonData = jsonData;
-												if (explorer.parentId === "explorer-tree") { //$NON-NLS-0$
-													dojo.place(document.createTextNode(messages['Getting git incoming changes...']), "explorer-tree", "only"); //$NON-NLS-2$ //$NON-NLS-1$
-													gitService.getLog(remoteJsonData.HeadLocation, remoteJsonData.Id).then(function(loadScopedCommitsList) {
-														explorer.renderer.setIncomingCommits(loadScopedCommitsList.Children);
-														explorer.loadCommitsList(remoteJsonData.CommitLocation + "?page=1", remoteJsonData, true); //$NON-NLS-0$
-													});
-												}
-												dojo.hitch(explorer, explorer.changedItem)(item);
-											}, displayErrorOnStatus
-										);
-									}, function (jsonData) {
-										handleResponse(jsonData, commandInvocation);
-									}
-								);
-							}, function(jsonData, secondArg) {
-								exports.handleProgressServiceResponse2(jsonData, serviceRegistry, 
-									function() {
-									
-									}, function (jsonData) {
-										handleResponse(jsonData, commandInvocation);
-									}
-								);
-							}
-						);
+				var fetchForceLogic = function(){
+					if (commandInvocation.parameters && commandInvocation.parameters.optionsRequested){
+						commandInvocation.parameters = null;
+						commandInvocation.optionsRequested = true;
+						commandService.collectParameters(commandInvocation);
+						return;
 					}
-				);
+	
+					exports.gatherSshCredentials(serviceRegistry, commandInvocation).then(
+						function(options) {
+							var gitService = serviceRegistry.getService("orion.git.provider"); //$NON-NLS-0$
+							var statusService = serviceRegistry.getService("orion.page.message"); //$NON-NLS-0$
+							var deferred = gitService.doFetch(path, true,
+									options.gitSshUsername,
+									options.gitSshPassword,
+									options.knownHosts,
+									options.gitPrivateKey,
+									options.gitPassphrase);
+							statusService.createProgressMonitor(deferred, messages['Fetching remote: '] + path);
+							deferred.then(
+								function(jsonData, secondArg) {
+									exports.handleProgressServiceResponse2(jsonData, serviceRegistry, 
+										function() {
+											gitService.getGitRemote(path).then(
+												function(jsonData){
+													var remoteJsonData = jsonData;
+													if (explorer.parentId === "explorer-tree") { //$NON-NLS-0$
+														dojo.place(document.createTextNode(messages['Getting git incoming changes...']), "explorer-tree", "only"); //$NON-NLS-2$ //$NON-NLS-1$
+														gitService.getLog(remoteJsonData.HeadLocation, remoteJsonData.Id).then(function(loadScopedCommitsList) {
+															explorer.renderer.setIncomingCommits(loadScopedCommitsList.Children);
+															explorer.loadCommitsList(remoteJsonData.CommitLocation + "?page=1", remoteJsonData, true); //$NON-NLS-0$
+														});
+													}
+													dojo.hitch(explorer, explorer.changedItem)(item);
+												}, displayErrorOnStatus
+											);
+										}, function (jsonData) {
+											handleResponse(jsonData, commandInvocation);
+										}
+									);
+								}, function(jsonData, secondArg) {
+									exports.handleProgressServiceResponse2(jsonData, serviceRegistry, 
+										function() {
+										
+										}, function (jsonData) {
+											handleResponse(jsonData, commandInvocation);
+										}
+									);
+								}
+							);
+						}
+					);
+				};
+				
+				//TODO HACK remoteTrackingBranch does not provide git url - we have to collect manually
+				if(!commandInvocation.items.GitUrl){
+					// have to determine manually
+					var gitService = serviceRegistry.getService("orion.git.provider");
+					gitService.getGitRemote(path).then(
+						function(resp){
+							gitService.getGitClone(resp.CloneLocation).then(
+								function(resp){
+									commandInvocation.items.GitUrl = resp.Children[0].GitUrl;
+									fetchForceLogic();
+								}
+							);
+						}
+					);
+				} else { fetchForceLogic(); }
 			},
 			visibleWhen : function(item) {
 				if (item.Type === "RemoteTrackingBranch") //$NON-NLS-0$
@@ -1652,6 +1670,24 @@
 			}
 		});
 		commandService.addCommand(previousLogPage);
+		
+		//TODO: This is used only in git-log2. Merge with previousLogPage command
+		var previousLog2Page = new mCommands.Command({
+			name : messages["< Previous Page"],
+			tooltip: messages["Show previous page of git log"],
+			id : "eclipse.orion.git.previousLog2Page",
+			hrefCallback : function(data){
+				return require.toUrl("git/git-log2.html") + "#" + data.items.PreviousLocation; //$NON-NLS-1$ //$NON-NLS-0$
+			},
+			visibleWhen : function(item){
+				if(item.Type === "RemoteTrackingBranch" || (item.toRef != null && item.toRef.Type === "Branch") || item.RepositoryPath != null){ //$NON-NLS-1$ //$NON-NLS-0$
+					return (item.PreviousLocation !== undefined);
+				}
+				
+				return false;
+			}
+		});
+		commandService.addCommand(previousLog2Page);
 
 		var nextLogPage = new mCommands.Command({
 			name : messages["Next Page >"],
@@ -1669,6 +1705,24 @@
 		});
 		commandService.addCommand(nextLogPage);
 		
+		//TODO: This is used only in git-log2. Merge with nextLogPage command
+		var nextLog2Page = new mCommands.Command({
+			name : messages["Next Page >"],
+			tooltip: messages["Show next page of git log"],
+			id : "eclipse.orion.git.nextLog2Page", //$NON-NLS-0$
+			hrefCallback : function(data) {
+				return require.toUrl("git/git-log2.html") + "#" + data.items.NextLocation; //$NON-NLS-1$ //$NON-NLS-0$
+			},
+			visibleWhen : function(item) {
+				if(item.Type === "RemoteTrackingBranch" ||(item.toRef != null && item.toRef.Type === "Branch") || item.RepositoryPath != null){ //$NON-NLS-1$ //$NON-NLS-0$
+					return (item.NextLocation !== undefined);
+				}
+				
+				return false;
+			}
+		});
+		commandService.addCommand(nextLog2Page);
+		
 		var previousTagPage = new mCommands.Command({
 			name : messages["< Previous Page"],
 			tooltip : messages["Show previous page of git tags"],
diff --git a/bundles/org.eclipse.orion.client.git/web/orion/git/gitLogExplorer.js b/bundles/org.eclipse.orion.client.git/web/orion/git/gitLogExplorer.js
new file mode 100644
index 0000000..21f28c4
--- /dev/null
+++ b/bundles/org.eclipse.orion.client.git/web/orion/git/gitLogExplorer.js
@@ -0,0 +1,405 @@
+/******************************************************************************* 

+ * @license

+ * Copyright (c) 2011, 2012 IBM Corporation and others.

+ * All rights reserved. This program and the accompanying materials are made 

+ * available under the terms of the Eclipse Public License v1.0 

+ * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 

+ * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 

+ * 

+ * Contributors: IBM Corporation - initial API and implementation

+ ******************************************************************************/

+

+/*global define dijit console document Image */

+

+define(['i18n!git/nls/gitmessages', 'require', 'dojo', 'orion/commands', 'orion/fileClient', 'orion/section', 'orion/dynamicContent', 'orion/git/widgets/FilterSearchBox', 'orion/util', 'orion/PageUtil', 'orion/globalCommands', 'orion/git/gitCommands',

+'orion/selection', 'orion/git/gitClient', 'orion/searchClient', 'orion/git/widgets/CommitTooltipDialog'], 

+		function(messages, require, dojo, mCommands, mFileClient, mSection, mDynamicContent, mFilterSearchBox, mUtil, PageUtil, mGlobalCommands, mGitCommands, mSelection, mGitClient, mSearchClient) {

+var exports = {};

+

+exports.GitLogExplorer = (function() {

+	

+	/**

+	 * Creates a new Git log explorer.

+	 * @class Git repository explorer

+	 * @name orion.git.GitLogExplorer

+	 * @param registry

+	 * @param commandService

+	 * @param linkService

+	 * @param selection

+	 * @param parentId

+	 * @param actionScopeId

+	 */

+	function GitLogExplorer(serviceRegistry, selection, options, parentId, pageTitleId, toolbarId, selectionToolsId, pageNavId, actionScopeId) {

+		this.registry = serviceRegistry;

+		this.selection = selection;

+		this.checkbox = options !== null ? options.checkbox : true;

+		this.minimal = options !== null ? options.minimal : false;

+		this.parentId = parentId;

+		this.pageTitleId = pageTitleId;

+		this.toolbarId = toolbarId;

+		this.pageNavId = pageNavId;

+		this.selectionToolsId = selectionToolsId;

+		this.actionScopeId = actionScopeId || options.actionScopeId;

+		this.fileClient = new mFileClient.FileClient(serviceRegistry);

+		

+		this.incomingCommits = [];

+		this.outgoingCommits = [];

+		

+		var selection = new mSelection.Selection(serviceRegistry);

+		this.commandService = new mCommands.CommandService({serviceRegistry: serviceRegistry, selection: selection});

+		

+		// Git operations

+		var that = this;

+		var gitClient = new mGitClient.GitService(serviceRegistry);

+		var fileClient = new mFileClient.FileClient(serviceRegistry);

+		this.searcher = new mSearchClient.Searcher({serviceRegistry: serviceRegistry, fileService: fileClient, commandService: that.commandService});

+	}

+	

+	GitLogExplorer.prototype.getCloneFileUri = function(){

+		var fileURI;

+		var path = dojo.hash().split("gitapi/commit/"); //$NON-NLS-0$

+		if(path.length === 2){

+			path = path[1].split("/"); //$NON-NLS-0$

+			if(path.length > 1){

+				fileURI = "";

+				for(var i = 0; i < path.length - 1; i++){

+					fileURI += "/" + path[i]; //$NON-NLS-0$

+				}

+				fileURI += "/" + path[path.length - 1].split("?")[0]; //$NON-NLS-1$ //$NON-NLS-0$

+			}

+		}

+		return fileURI;

+	};

+		

+	GitLogExplorer.prototype.getHeadFileUri = function(){

+		var fileURI;

+		var path = dojo.hash().split("gitapi/commit/"); //$NON-NLS-0$

+		if(path.length === 2){

+			path = path[1].split("/"); //$NON-NLS-0$

+			if(path.length > 1){

+				fileURI="";

+				for(var i=1; i<path.length-1; i++){

+					//first segment is a branch name

+					fileURI+= "/" + path[i]; //$NON-NLS-0$

+				}

+				fileURI+="/" + path[path.length-1].split("?")[0]; //$NON-NLS-1$ //$NON-NLS-0$

+			}

+		}

+		return fileURI;

+	};

+		

+	

+	GitLogExplorer.prototype.makeHref = function(fileClient, seg, location, isRemote) {

+		if (!location) {

+			return;

+		}

+			

+		fileClient.read(location, true).then(dojo.hitch(this, function(metadata) {

+			if (isRemote) {

+				var gitService = this.registry.getService("orion.git.provider"); //$NON-NLS-0$

+				if (metadata.Git) {

+					gitService.getDefaultRemoteBranch(metadata.Git.RemoteLocation).then(function(defaultRemoteBranchJsonData, secondArg) {

+						seg.href = require.toUrl("git/git-log2.html") + "#" + defaultRemoteBranchJsonData.Location + "?page=1"; //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+					});

+				}

+			} else {

+				if (metadata.Git) {

+					seg.href = require.toUrl("git/git-log2.html") + "#" + metadata.Git.CommitLocation + "?page=1"; //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+				}

+			}

+		}), dojo.hitch(this, function(error) {

+			console.error("Error loading file metadata: " + error.message); //$NON-NLS-0$

+		}));

+	};

+	

+	GitLogExplorer.prototype.initTitleBar = function(item){

+		var deferred = new dojo.Deferred();

+		var isRemote = (item.toRef && item.toRef.Type === "RemoteTrackingBranch"); //$NON-NLS-0$

+		var isBranch = (item.toRef && item.toRef.Type === "Branch"); //$NON-NLS-0$

+		

+		//TODO we are calculating file path from the URL, it should be returned by git API

+		var fileURI, branchName;

+		if (isRemote || isBranch) {

+			fileURI = this.getHeadFileUri();

+			branchName = item.toRef.Name;

+		} else { fileURI = this.getCloneFileUri(); }	

+			

+		var that = this;

+		

+		if(fileURI){		

+			this.fileClient.read(fileURI, true).then(dojo.hitch(this, function(metadata) {

+				var title = branchName ? branchName + " on " + metadata.Name + " - Git Log" : metadata.Name + " - " + "Git Log";

+				var breadcrumbRootName;

+				var branchIdentifier = branchName ? " (" + branchName + ") " : "";

+		

+				// adjust top name of breadcrumb segment

+				if (metadata.Parents && metadata.Parents.length > 0) {

+					var rootParent = metadata.Parents[metadata.Parents.length - 1];

+					breadcrumbRootName = "Log" + branchIdentifier + rootParent.Name;

+				} else {

+					breadcrumbRootName = "Log" + branchIdentifier + metadata.Name;

+				}

+				

+				mGlobalCommands.setPageTarget({task: "Git Log", title: title, target: item, breadcrumbTarget: metadata, breadcrumbRootName: breadcrumbRootName,

+					makeBreadcrumbLink: function(seg, location) {

+						that.makeHref(that.fileClient, seg, location, isRemote);

+					}, serviceRegistry: that.registry, commandService: that.commandService, searchService: that.searcher}); 

+					

+					mGitCommands.updateNavTools(that.registry, that, "pageActions", "selectionTools", item); //$NON-NLS-1$ //$NON-NLS-0$

+					deferred.callback();

+				}), dojo.hitch(this, function(error) { deferred.errback(error);}));

+			} else {

+				deferred.callback();

+			}

+			return deferred;

+	};

+	

+	GitLogExplorer.prototype.redisplay = function(){

+		this.display(dojo.hash());

+	};

+	

+	GitLogExplorer.prototype.changedItem = function(parent, children) {

+		this.redisplay();

+	};

+	

+	GitLogExplorer.prototype.renderCommit = function(commit, i){

+		var extensionListItem = dojo.create( "div", { "class":"sectionTableItem " + ((i % 2) ? "darkTreeTableRow" : "lightTreeTableRow") }, dojo.byId("logNode") ); //$NON-NLS-5$ //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+		var horizontalBox = dojo.create( "div", null, extensionListItem ); //$NON-NLS-0$

+		

+		var incomingCommit = false;

+		dojo.forEach(this.incomingCommits, function(comm, i){

+			if (commit.Name === comm.Name){

+				incomingCommit = true;

+			}

+		});

+			

+		var outgoingCommit = false;

+		dojo.forEach(this.outgoingCommits, function(comm, i){

+			if (commit.Name === comm.Name){

+				outgoingCommit = true;

+			}

+		});

+		

+		if(!incomingCommit && !outgoingCommit){

+			dojo.create( "span", null, horizontalBox );

+		} else {

+			var imgSpriteName = (outgoingCommit ? "git-sprite-outgoing_commit" : "git-sprite-incoming_commit");

+			dojo.create( "span", { "class":"sectionIcon gitImageSprite " + imgSpriteName}, horizontalBox ); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+		}

+		

+		if (commit.AuthorImage) {

+			var authorImage = dojo.create("span", {"class":"git-author-icon"}, horizontalBox); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+			

+			var image = new Image();

+			image.src = commit.AuthorImage;

+			image.name = commit.AuthorName;

+			image.width = 30;

+			image.height = 30;

+			dojo.place(image, authorImage, "first"); //$NON-NLS-0$

+		}

+		

+		var detailsView = dojo.create( "div", { "class":"stretch"}, horizontalBox ); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+		

+		var titleLink = dojo.create("a", {"class": "gitMainDescription navlinkonpage", href: "/git/git-commit.html#" + commit.Location + "?page=1&pageSize=1"}, detailsView); //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+		dojo.place(document.createTextNode(commit.Message), titleLink);		

+		

+		var _timer;

+		

+		var tooltipDialog = new orion.git.widgets.CommitTooltipDialog({

+		    commit: commit,

+		    onMouseLeave: function(){

+		    	if(dijit.popup.hide)

+					dijit.popup.hide(tooltipDialog); //close doesn't work on FF

+				dijit.popup.close(tooltipDialog);

+            },

+            onMouseEnter: function(){

+		    	clearTimeout(_timer);

+            }

+		});

+		

+		dojo.connect(titleLink, "onmouseover", titleLink, function() { //$NON-NLS-0$

+			clearTimeout(_timer);

+			

+			_timer = setTimeout(function(){

+				dijit.popup.open({

+					popup: tooltipDialog,

+					around: titleLink,

+					orient: {'BR':'TL', 'TR':'BL'} //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+				});

+			}, 600);

+		});

+		

+		dojo.connect(titleLink, "onmouseout", titleLink, function() { //$NON-NLS-0$

+			clearTimeout(_timer);

+			

+			_timer = setTimeout(function(){

+				if(dijit.popup.hide)

+					dijit.popup.hide(tooltipDialog); //close doesn't work on FF

+				dijit.popup.close(tooltipDialog);

+			}, 200);

+		});

+		

+		dojo.create( "div", null, detailsView ); //$NON-NLS-0$

+		var description = dojo.create( "span", { "class":"gitSecondaryDescription",  //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+			innerHTML: messages[" (SHA "] + commit.Name + messages[") by "] + commit.AuthorName 

+			+ " on " + dojo.date.locale.format(new Date(commit.Time), {formatLength: "short"})}, detailsView ); //$NON-NLS-1$ //$NON-NLS-0$

+					

+		var actionsArea = dojo.create( "div", {"id":"branchActionsArea", "class":"sectionTableItemActions" }, horizontalBox ); //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+		this.registry.getService("orion.page.command").renderCommands(this.actionScopeId, actionsArea, commit, this, "tool");	 //$NON-NLS-0$

+	};

+	

+	GitLogExplorer.prototype.renderLog = function(commits){

+		var tableNode = dojo.byId('table');	 //$NON-NLS-0$

+		dojo.empty(tableNode);

+		

+		var contentParent = dojo.create("div", {"role": "region", "class":"sectionTable"}, tableNode, "last");

+		contentParent.innerHTML = '<list id="logNode" class="mainPadding"></list>'; //$NON-NLS-0$

+		

+		for(var i=0; i<commits.length; ++i){

+			this.renderCommit(commits[i], i);

+		}

+	};

+	

+	GitLogExplorer.prototype.getOutgoingIncomingChanges = function(resource){

+		var that = this;

+		var d = new dojo.Deferred();

+		

+		var progressService = this.registry.getService("orion.page.message");

+		progressService.showWhile(d, messages["Getting git incoming changes..."]);

+	

+		var processRemoteTrackingBranch = function(remoteResource) {

+			var newRefEncoded = encodeURIComponent(remoteResource.FullName);

+			

+			// update page navigation

+			if (that.toolbarId && that.selectionToolsId){

+				mGitCommands.updateNavTools(that.registry, that, that.toolbarId, that.selectionToolsId, remoteResource, that.pageNavId);

+			}

+			

+			that.registry.getService("orion.git.provider").getLog(remoteResource.HeadLocation, newRefEncoded).then(function(scopedCommitsJsonData) {

+				that.incomingCommits = scopedCommitsJsonData.Children;

+				that.outgoingCommits = [];

+				

+				that.registry.getService("orion.git.provider").doGitLog(remoteResource.CommitLocation + "?" + new dojo._Url(dojo.hash()).query).then(function(jsonData) { //$NON-NLS-0$

+					remoteResource.Children = jsonData.Children;

+					if(jsonData.NextLocation){

+						remoteResource.NextLocation = remoteResource.Location + "?" + new dojo._Url(jsonData.NextLocation).query; //$NON-NLS-0$

+					}

+					

+					if(jsonData.PreviousLocation ){

+						remoteResource.PreviousLocation  = remoteResource.Location + "?" + new dojo._Url(jsonData.PreviousLocation).query; //$NON-NLS-0$

+					}

+					

+					d.callback(remoteResource);

+				});

+			});

+		};

+											

+		if (resource.Type === "RemoteTrackingBranch"){ //$NON-NLS-0$

+			processRemoteTrackingBranch(resource);

+		} else if (resource.Type === "Commit" && resource.toRef.Type === "RemoteTrackingBranch"){ //$NON-NLS-1$ //$NON-NLS-0$

+			processRemoteTrackingBranch(resource.toRef);

+		} else if (resource.toRef){

+			if (resource.toRef.RemoteLocation && resource.toRef.RemoteLocation.length===1 && resource.toRef.RemoteLocation[0].Children && resource.toRef.RemoteLocation[0].Children.length===1){

+				that.registry.getService("orion.git.provider").getGitRemote(resource.toRef.RemoteLocation[0].Children[0].Location).then(

+					function(remoteJsonData, secondArg) {

+						that.registry.getService("orion.git.provider").getLog(remoteJsonData.CommitLocation, "HEAD").then(function(scopedCommitsJsonData) { //$NON-NLS-0$

+							that.incomingCommits = [];

+							that.outgoingCommits = scopedCommitsJsonData.Children;

+							d.callback(resource);

+						});

+					}

+				);

+			} else {

+				d.callback(resource);

+			}

+		} else {

+			d.callback(resource);

+		}

+		

+		return d;

+	};

+	

+	GitLogExplorer.prototype.handleError = function(error) {

+		var display = {};

+		display.Severity = "Error"; //$NON-NLS-0$

+		display.HTML = false;

+		try {

+			var resp = JSON.parse(error.responseText);

+			display.Message = resp.DetailedMessage ? resp.DetailedMessage : resp.Message;

+		} catch (Exception) {

+			display.Message = error.message;

+		}

+		this.registry.getService("orion.page.message").setProgressResult(display); //$NON-NLS-0$

+	};

+	

+	GitLogExplorer.prototype.loadResource = function(location){

+		var loadingDeferred = new dojo.Deferred();

+		var progressService = this.registry.getService("orion.page.message");

+		progressService.showWhile(loadingDeferred, messages['Loading git log...']);

+		

+		var that = this;

+		var gitService = this.registry.getService("orion.git.provider"); //$NON-NLS-0$

+		gitService.doGitLog(location).then(

+			function(resp) {

+				var resource = resp;

+				gitService.getGitClone(resource.CloneLocation).then(

+					function(resp){

+						var clone = resp.Children[0];	

+						resource.Clone = clone;

+						resource.ContentLocation = clone.ContentLocation;

+						gitService.getGitBranch(clone.BranchLocation).then(

+							function(branches){

+								dojo.forEach(branches.Children, function(branch, i) {

+									if (branch.Current === true){

+										resource.Clone.ActiveBranch = branch.CommitLocation;

+										loadingDeferred.callback(resource);

+									}

+								});

+							}

+						);

+					}

+				);

+			}

+		);

+		

+		return loadingDeferred;

+	};

+	

+	GitLogExplorer.prototype.display = function(location){

+		var that = this;

+		var progressService = this.registry.getService("orion.page.message"); //$NON-NLS-0$

+		

+		var loadingDeferred = new dojo.Deferred();

+		progressService.showWhile(loadingDeferred, messages['Loading...']);

+		

+		that.loadResource(location).then(

+			function(resp){

+				var resource = resp;

+				loadingDeferred.callback();

+				that.initTitleBar(resource).then(

+					function(){

+						that.getOutgoingIncomingChanges(resource).then(function(items){

+							// update page navigation

+							if (that.toolbarId && that.selectionToolsId){

+								mGitCommands.updateNavTools(that.registry, that, that.toolbarId, that.selectionToolsId, items, that.pageNavId);

+							}

+						

+							that.renderLog(items.Children);

+						});

+					}

+				);

+			},

+			function(err){

+				loadingDeferred.callback();

+				that.handleError(err);

+			}

+		);

+	};

+	

+	return GitLogExplorer;

+}());

+

+return exports;

+

+// end of define

+});

diff --git a/bundles/org.eclipse.orion.client.git/web/orion/git/widgets/CommitTooltipDialog.js b/bundles/org.eclipse.orion.client.git/web/orion/git/widgets/CommitTooltipDialog.js
index 32f87d3..63f2ad7 100644
--- a/bundles/org.eclipse.orion.client.git/web/orion/git/widgets/CommitTooltipDialog.js
+++ b/bundles/org.eclipse.orion.client.git/web/orion/git/widgets/CommitTooltipDialog.js
@@ -27,27 +27,18 @@
 		},

 		

 		displayCommit: function(commit){

-			

-			var tableNode = dojo.create( "div", {"style":"padding:10px; max-width:480px"}, this.containerNode); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+			var tableNode = dojo.create( "div", {"style":"padding:10px; max-width:520px"}, this.containerNode); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

 			

 			var commitMessage0 = commit.Message.split(/(\r?\n|$)/)[0];

 			var link = dojo.create("a", {"class": "gitMainDescription", href: "/git/git-commit.html#" + commit.Location + "?page=1&pageSize=1"}, tableNode); //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

 			dojo.place(document.createTextNode(commitMessage0), link);

 

 			dojo.create( "div", {"style":"padding-top:15px"}, tableNode ); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

-			dojo.create( "span", {"class": "gitSecondaryDescription", innerHTML: messages[" commit: "] + commit.Name}, tableNode ); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

-			if (commit.Parents && commit.Parents.length > 0){

-				dojo.create( "div", null, tableNode ); //$NON-NLS-0$

-				

-				dojo.place(document.createTextNode(messages["parent: "]), tableNode);

-				link = dojo.create("a", {"class": "gitSecondaryDescription", href: "/git/git-commit.html#" + commit.Parents[0].Location + "?page=1&pageSize=1"}, tableNode); //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

-				dojo.place(document.createTextNode(commit.Parents[0].Name), link);

-			}

+			var imageDiv = dojo.create("div", {"style":"display: inline-block; vertical-align:text-top;"}, tableNode);

+			var textDiv = dojo.create("div", {"style":"display: inline-block; vertical-align:text-top;"}, tableNode);

 

-			dojo.create( "div", {"style":"padding-top:15px"}, tableNode ); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

-			

 			if (commit.AuthorImage) {

-				var authorImage = dojo.create("div", {"class":"git-author-icon-small", "style":"margin-bottom:30px"}, tableNode); //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+				var authorImage = dojo.create("div", {"class":"git-author-icon-small"}, imageDiv); //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

 				var image = new Image();

 				image.src = commit.AuthorImage;

 				image.name = commit.AuthorName;

@@ -55,13 +46,57 @@
 				image.height = 35;

 				dojo.place(image, authorImage, "first"); //$NON-NLS-0$

 			}

-			

+

 			dojo.create( "span", { "class":"gitSecondaryDescription",  //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

 				innerHTML: dojo.string.substitute(messages[" authored by ${0} {${1}) on ${2}"], [commit.AuthorName, commit.AuthorEmail,

-				 dojo.date.locale.format(new Date(commit.Time), {formatLength: "short"})])}, tableNode ); //$NON-NLS-0$

-			dojo.create( "div", null, tableNode ); //$NON-NLS-0$

+				 dojo.date.locale.format(new Date(commit.Time), {formatLength: "short"})])}, textDiv ); //$NON-NLS-0$

+			dojo.create( "div", null, textDiv ); //$NON-NLS-0$

 			dojo.create( "span", { "class":"gitSecondaryDescription",  //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

-				innerHTML: dojo.string.substitute(messages['committed by 0 (1)'], [commit.CommitterName, commit.CommitterEmail])}, tableNode );

+				innerHTML: dojo.string.substitute(messages['committed by 0 (1)'], [commit.CommitterName, commit.CommitterEmail])}, textDiv );

+

+			dojo.create( "div", {"style":"padding-top:15px"}, textDiv ); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+			

+			dojo.create( "span", {"class": "gitSecondaryDescription", innerHTML: messages[" commit: "] + commit.Name}, textDiv ); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+			if (commit.Parents && commit.Parents.length > 0){

+				dojo.create( "div", null, textDiv ); //$NON-NLS-0$

+				

+				link = dojo.create("a", {"class": "gitSecondaryDescription", href: "/git/git-commit.html#" + commit.Parents[0].Location + "?page=1&pageSize=1"}, textDiv); //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+				dojo.place(document.createTextNode(commit.Parents[0].Name), link);

+				

+				var parentNode = dojo.create( "span", { "class":"gitSecondaryDescription",  //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+				innerHTML: messages["parent: "]}, textDiv );

+				

+				dojo.place(link, parentNode, "last");

+			}

+			

+			var displayBranches = commit.Branches && commit.Branches.length > 0;

+			var displayTags = commit.Tags && commit.Tags.length > 0;

+						

+			if(displayBranches){

+				dojo.create( "div", {"style":"padding-top:15px"}, textDiv );

+				var branchesSection = dojo.create("section", {"style" : "display: inline-block; vertical-align:text-top;"}, textDiv);

+				var branchesNode = dojo.create( "span", { "class":"gitSecondaryDescription",  //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+				innerHTML: messages["branches: "]}, branchesSection );

+				

+				var branchesList = dojo.create( "list", null, branchesSection);

+				

+				for(var i=0; i<commit.Branches.length; ++i){

+					dojo.create("span", {"class":"gitSecondaryDescription", "style" : "padding-left:10px;", innerHTML: commit.Branches[i].FullName}, branchesList);

+				}

+			}

+			

+			if(displayTags){

+				dojo.create( "div", {"style":"padding-top:15px"}, textDiv );

+				var tagsSection = dojo.create("section", {"style" : "display: inline-block; vertical-align:text-top;"}, textDiv);

+				var tagsNode = dojo.create( "span", { "class":"gitSecondaryDescription",  //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$

+				innerHTML: messages["tags: "]}, tagsSection );

+				

+				var tagsList = dojo.create( "list", null, tagsSection);

+				

+				for(var i=0; i<commit.Tags.length; ++i){

+					dojo.create("span", {"class":"gitSecondaryDescription", "style" : "padding-left:10px;", innerHTML: commit.Tags[i].Name}, tagsList);

+				}

+			}

 		},

 		

 		_onBlur: function(){