working on the change log model provider to show changes grouped by comment
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/listeners/LogListener.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/listeners/LogListener.java
index 9b6fd02..70036ae 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/listeners/LogListener.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/listeners/LogListener.java
@@ -130,8 +130,9 @@
 			LogEntry entry = new LogEntry(file, revision, author, date,
 				comment.toString(), fileState, (CVSTag[]) thisRevisionTags.toArray(new CVSTag[0]));
 			entries.add(entry);
+			tagNames.clear();
+			tagRevisions.clear();
 			state = BEGIN;
-			// XXX should we reset the tagNames and tagRevisions stuff?
 		}
 		return OK;
 	}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java
index b6efc81..98d7fb9 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java
@@ -15,6 +15,7 @@
 import java.util.*;
 
 import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.*;
 import org.eclipse.team.core.TeamException;
 import org.eclipse.team.internal.ccvs.core.*;
@@ -251,6 +252,48 @@
 	}
 	
 	/**
+	 * @see ICVSRemoteFile#getLogEntries()
+	 */
+	public static ILogEntry[] getLogEntries(RemoteFile[] files, IProgressMonitor monitor) throws CVSException {
+		monitor = Policy.monitorFor(monitor);
+		monitor.beginTask(Policy.bind("RemoteFile.getLogEntries"), 100); //$NON-NLS-1$
+		ILogEntry[] fileEntries = new ILogEntry[files.length];
+		final List entries = new ArrayList(2);
+		// Get the location of the workspace root
+		ICVSFolder root = CVSWorkspaceRoot.getCVSFolderFor(ResourcesPlugin.getWorkspace().getRoot());
+		Session session = new Session(files[0].getRepository(), files[0].getParent(), false /* output to console */);
+		session.open(Policy.subMonitorFor(monitor, 10), false /* read-only */);
+		try {
+			QuietOption quietness = CVSProviderPlugin.getPlugin().getQuietness();
+			try {
+				for (int i = 0; i < files.length; i++) {
+					entries.clear();
+					RemoteFile file = files[i];
+					monitor.subTask(file.getName());
+					IStatus status = Command.LOG.execute(
+							session, 
+							Command.NO_GLOBAL_OPTIONS, 
+							new LocalOption[]{Log.makeRevisionOption(file.getRevision())}, 
+							files, 
+							new LogListener(file, entries), 
+							Policy.subMonitorFor(monitor, 90));
+					if (entries.size() == 1) {
+						fileEntries[i] = (ILogEntry) entries.get(0);
+					}
+					if (status.getCode() == CVSStatus.SERVER_ERROR) {
+						throw new CVSServerException(status);
+					}
+				}
+			} finally {
+				monitor.done();
+			}
+		} finally { 
+			session.close();
+		}
+		return fileEntries;
+	}
+	
+	/**
 	 * @see ICVSRemoteFile#getRevision()
 	 */
 	public String getRevision() {
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/ChangeLogModelProvider.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/ChangeLogModelProvider.java
index 01a775c..79d4bb6 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/ChangeLogModelProvider.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/ChangeLogModelProvider.java
@@ -144,15 +144,16 @@
 	}
 
 	private SynchronizeModelElement[] calculateRoots(SyncInfoSet set, IProgressMonitor monitor) {
-		commentRoots.clear();
-		SyncInfo[] infos = set.getSyncInfos();
-		monitor.beginTask("fetching from server", set.size() * 100);
-		for (int i = 0; i < infos.length; i++) {
-			if(monitor.isCanceled()) {
-				break;
-			}
-			ILogEntry logEntry = getSyncInfoComment((CVSSyncInfo) infos[i], monitor);
-			if(logEntry != null) {
+		try {
+			commentRoots.clear();
+			SyncInfo[] infos = set.getSyncInfos();
+			monitor.beginTask("Fetching from server", set.size() * 100);
+			ILogEntry[] entries = getComments(infos, monitor);
+			for (int i = 0; i < infos.length; i++) {
+				if(monitor.isCanceled()) {
+					break;
+				}		
+				ILogEntry logEntry = entries[i];
 				DateComment dateComment = new DateComment(logEntry.getDate(), logEntry.getComment(), logEntry.getAuthor());
 				ChangeLogDiffNode changeRoot = (ChangeLogDiffNode) commentRoots.get(dateComment);
 				if (changeRoot == null) {
@@ -161,49 +162,57 @@
 				}
 				SynchronizeModelElement element = new FullPathSyncInfoElement(changeRoot, infos[i]);
 				associateDiffNode(element);
+				monitor.worked(100);
 			}
-			monitor.worked(100);
-		}
-		return (ChangeLogDiffNode[]) commentRoots.values().toArray(new ChangeLogDiffNode[commentRoots.size()]);
-	}
-	
-	/**
-	 * How do we tell which revision has the interesting log message? Use the later
-	 * revision, since it probably has the most up-to-date comment.
-	 */
-	private ILogEntry getSyncInfoComment(CVSSyncInfo info, IProgressMonitor monitor) {
-		try {
-			if(info.getLocal().getType() != IResource.FILE) {
-				return null;
-			}
-			
-			ICVSRemoteResource remote = (ICVSRemoteResource)info.getRemote();
-			ICVSRemoteResource base = (ICVSRemoteResource)info.getBase();
-			ICVSRemoteResource local = (ICVSRemoteFile)CVSWorkspaceRoot.getRemoteResourceFor(info.getLocal());
-			
-			String baseRevision = getRevisionString(base);
-			String remoteRevision = getRevisionString(remote);
-			String localRevision = getRevisionString(local);
-			
-			// TODO: handle new files where there is no local or remote	
-			boolean useRemote = true;
-			if(local != null && remote != null) {
-				useRemote = ResourceSyncInfo.isLaterRevision(remoteRevision, localRevision);
-			} else if(remote == null) {
-				useRemote = false;
-			}
-			if (useRemote) {
-				return ((RemoteFile) remote).getLogEntry(monitor);
-			} else if (local != null){
-				return ((RemoteFile) local).getLogEntry(monitor);
-			}
-			return null;
+			return (ChangeLogDiffNode[]) commentRoots.values().toArray(new ChangeLogDiffNode[commentRoots.size()]);
 		} catch (CVSException e) {
 			CVSUIPlugin.log(e);
 			return null;
 		}
 	}
 	
+	/**
+	 * How do we tell which revision has the interesting log message? Use the later
+	 * revision, since it probably has the most up-to-date comment.
+	 */
+	private ILogEntry[] getComments(SyncInfo[] infos, IProgressMonitor monitor) throws CVSException {
+		ILogEntry[] entries = new ILogEntry[infos.length];
+		for (int i = 0; i < infos.length; i++) {
+			SyncInfo info = infos[i];
+			RemoteFile remoteFile = getRemoteFile((CVSSyncInfo) info);
+			entries[i] = remoteFile.getLogEntry(monitor);			
+		}
+		return entries;
+	}
+	
+	private RemoteFile getRemoteFile(CVSSyncInfo info) throws CVSException {
+		if(info.getLocal().getType() != IResource.FILE) {
+			return null;
+		}
+		
+		ICVSRemoteResource remote = (ICVSRemoteResource)info.getRemote();
+		ICVSRemoteResource base = (ICVSRemoteResource)info.getBase();
+		ICVSRemoteResource local = (ICVSRemoteFile)CVSWorkspaceRoot.getRemoteResourceFor(info.getLocal());
+		
+		String baseRevision = getRevisionString(base);
+		String remoteRevision = getRevisionString(remote);
+		String localRevision = getRevisionString(local);
+		
+		// TODO: handle new files where there is no local or remote	
+		boolean useRemote = true;
+		if(local != null && remote != null) {
+			useRemote = ResourceSyncInfo.isLaterRevision(remoteRevision, localRevision);
+		} else if(remote == null) {
+			useRemote = false;
+		}
+		if (useRemote) {
+			return ((RemoteFile) remote);
+		} else if (local != null){
+			return ((RemoteFile) local);
+		}
+		return null;
+	}
+		
 	private String getRevisionString(ICVSRemoteResource remoteFile) {
 		if(remoteFile instanceof RemoteFile) {
 			return ((RemoteFile)remoteFile).getRevision();
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CompareParticipantPage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CompareParticipantPage.java
index 55d7aeb..e6755e9 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CompareParticipantPage.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CompareParticipantPage.java
@@ -73,7 +73,7 @@
 			toolbar.add(removeAction);
 			IMenuManager mgr = actionBars.getMenuManager();
 			//mgr.add(new Separator());
-			//mgr.add(groupByCommentAction);
+			mgr.add(groupByCommentAction);
 		}
 	}