From 17820f3a1153250a325fed23dfc2da59ce6ba777 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Mon, 31 Oct 2011 22:47:21 -0400
Subject: [PATCH] More feeds work in Manager

---
 src/com/gitblit/client/SyndicatedEntryTableModel.java    |    8 
 src/com/gitblit/client/GitblitClient.java                |  151 +++-----
 src/com/gitblit/models/FeedModel.java                    |   96 ++++++
 src/com/gitblit/client/FeedsTableModel.java              |  126 +++++++
 src/com/gitblit/client/GitblitPanel.java                 |   74 ++--
 src/com/gitblit/client/SubscribedRepositoryRenderer.java |   62 +++
 src/com/gitblit/utils/RpcUtils.java                      |   37 +
 src/com/gitblit/RpcServlet.java                          |   15 
 src/com/gitblit/build/Build.java                         |    6 
 src/com/gitblit/client/GitblitRegistration.java          |   22 +
 src/com/gitblit/client/SubscriptionsDialog.java          |  159 +++++++++
 src/com/gitblit/wicket/GitBlitWebApp.properties          |    5 
 src/com/gitblit/client/Translation.java                  |   42 +-
 tests/com/gitblit/tests/RpcTests.java                    |    2 
 src/com/gitblit/models/RepositoryModel.java              |    1 
 src/com/gitblit/client/NameRenderer.java                 |   48 --
 src/com/gitblit/client/GitblitManager.java               |   21 
 src/com/gitblit/client/BooleanCellRenderer.java          |   50 +++
 18 files changed, 702 insertions(+), 223 deletions(-)

diff --git a/src/com/gitblit/RpcServlet.java b/src/com/gitblit/RpcServlet.java
index b068a39..585770e 100644
--- a/src/com/gitblit/RpcServlet.java
+++ b/src/com/gitblit/RpcServlet.java
@@ -91,28 +91,31 @@
 			}
 			result = repositories;
 		} else if (RpcRequest.LIST_BRANCHES.equals(reqType)) {
-			// list all branches in all repositories accessible to user
-			Map<String, List<String>> allBranches = new HashMap<String, List<String>>();
+			// list all local branches in all repositories accessible to user
+			Map<String, List<String>> localBranches = new HashMap<String, List<String>>();
 			List<RepositoryModel> models = GitBlit.self().getRepositoryModels(user);
 			for (RepositoryModel model : models) {
 				if (!model.hasCommits) {
 					// skip empty repository
 					continue;
 				}
-				// get branches
+				// get local branches
 				Repository repository = GitBlit.self().getRepository(model.name);
 				List<RefModel> refs = JGitUtils.getLocalBranches(repository, false, -1);
-				refs.addAll(JGitUtils.getRemoteBranches(repository, false, -1));
+				if (model.showRemoteBranches) {
+					// add remote branches if repository displays them
+					refs.addAll(JGitUtils.getRemoteBranches(repository, false, -1));
+				}
 				if (refs.size() > 0) {
 					List<String> branches = new ArrayList<String>();
 					for (RefModel ref : refs) {
 						branches.add(ref.getName());
 					}
-					allBranches.put(model.name, branches);
+					localBranches.put(model.name, branches);
 				}
 				repository.close();
 			}
-			result = allBranches;
+			result = localBranches;
 		} else if (RpcRequest.LIST_USERS.equals(reqType)) {
 			// list users
 			List<String> names = GitBlit.self().getAllUsernames();
diff --git a/src/com/gitblit/build/Build.java b/src/com/gitblit/build/Build.java
index 4389eac..ee53ff0 100644
--- a/src/com/gitblit/build/Build.java
+++ b/src/com/gitblit/build/Build.java
@@ -398,12 +398,6 @@
 				"46a386136c901748e6a3af67ebde6c22bc6b4524",
 				"e223571d77769cdafde59040da235842f3326453");
 
-		public static final MavenObject SLF4JNOP = new MavenObject("SLF4J NOP", "org/slf4j",
-				"slf4j-nop", "1.6.1", 4800, 4100, 32300,
-				"70249094d4e5653b6bdfea46f3a1a4165c1e1993",
-				"4a8e77f7bf6897a3c3b7fc3acb4c862dfb905baa",
-				"24b2b46f9025f2db53b5b32143f7832538fa3178");
-
 		public static final MavenObject SLF4LOG4J = new MavenObject("SLF4J LOG4J", "org/slf4j",
 				"slf4j-log4j12", "1.6.1", 9800, 9500, 52400,
 				"bd245d6746cdd4e6203e976e21d597a46f115802",
diff --git a/src/com/gitblit/client/BooleanCellRenderer.java b/src/com/gitblit/client/BooleanCellRenderer.java
new file mode 100644
index 0000000..c8341df
--- /dev/null
+++ b/src/com/gitblit/client/BooleanCellRenderer.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011 gitblit.com.
+ *
+ * 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.
+ */
+package com.gitblit.client;
+
+import java.awt.Component;
+import java.io.Serializable;
+
+import javax.swing.JCheckBox;
+import javax.swing.JTable;
+import javax.swing.SwingConstants;
+import javax.swing.table.TableCellRenderer;
+
+/**
+ * Boolean checkbox cell renderer.
+ * 
+ * @author James Moger
+ * 
+ */
+public class BooleanCellRenderer extends JCheckBox implements TableCellRenderer, Serializable {
+
+	private static final long serialVersionUID = 1L;
+
+	public BooleanCellRenderer() {
+		super();
+		setOpaque(false);
+		setHorizontalAlignment(SwingConstants.CENTER);
+	}
+
+	public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
+			boolean hasFocus, int row, int column) {
+		if (value instanceof Boolean) {
+			boolean checked = (Boolean) value;
+			this.setSelected(checked);
+		}
+		return this;
+	}
+}
\ No newline at end of file
diff --git a/src/com/gitblit/client/FeedsTableModel.java b/src/com/gitblit/client/FeedsTableModel.java
new file mode 100644
index 0000000..a628fc8
--- /dev/null
+++ b/src/com/gitblit/client/FeedsTableModel.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2011 gitblit.com.
+ *
+ * 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.
+ */
+package com.gitblit.client;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.swing.table.AbstractTableModel;
+
+import com.gitblit.models.FeedModel;
+
+/**
+ * Table model of a list of available feeds.
+ * 
+ * @author James Moger
+ * 
+ */
+public class FeedsTableModel extends AbstractTableModel {
+
+	private static final long serialVersionUID = 1L;
+
+	List<FeedModel> list;
+
+	enum Columns {
+		Subscribed, Repository, Branch, Max_Length;
+
+		@Override
+		public String toString() {
+			return name().replace('_', ' ');
+		}
+	}
+
+	public FeedsTableModel() {
+		this(new ArrayList<FeedModel>());
+	}
+
+	public FeedsTableModel(List<FeedModel> feeds) {
+		this.list = feeds;
+		Collections.sort(this.list);
+	}
+
+	@Override
+	public int getRowCount() {
+		return list.size();
+	}
+
+	@Override
+	public int getColumnCount() {
+		return Columns.values().length;
+	}
+
+	@Override
+	public String getColumnName(int column) {
+		Columns col = Columns.values()[column];
+		switch (col) {
+		case Repository:
+			return Translation.get("gb.repository");
+		case Branch:
+			return Translation.get("gb.branch");
+		}
+		return "";
+	}
+
+	/**
+	 * Returns <code>Object.class</code> regardless of <code>columnIndex</code>.
+	 * 
+	 * @param columnIndex
+	 *            the column being queried
+	 * @return the Object.class
+	 */
+	public Class<?> getColumnClass(int columnIndex) {
+		Columns col = Columns.values()[columnIndex];
+		switch (col) {
+		case Subscribed:
+			return Boolean.class;
+		case Max_Length:
+			return Integer.class;
+		}
+		return String.class;
+	}
+
+	@Override
+	public boolean isCellEditable(int rowIndex, int columnIndex) {
+		Columns col = Columns.values()[columnIndex];
+		switch (col) {
+		case Subscribed:
+			return true;
+		}
+		return false;
+	}
+
+	@Override
+	public Object getValueAt(int rowIndex, int columnIndex) {
+		FeedModel model = list.get(rowIndex);
+		Columns col = Columns.values()[columnIndex];
+		switch (col) {
+		case Repository:
+			return model.repository;
+		case Branch:
+			return model.branch;
+		case Max_Length:
+			return model.maxRetrieval;
+		case Subscribed:
+			return model.subscribed;
+		}
+		return null;
+	}
+
+	public FeedModel get(int modelRow) {
+		return list.get(modelRow);
+	}
+}
diff --git a/src/com/gitblit/client/GitblitClient.java b/src/com/gitblit/client/GitblitClient.java
index ccde45a..74e0e08 100644
--- a/src/com/gitblit/client/GitblitClient.java
+++ b/src/com/gitblit/client/GitblitClient.java
@@ -19,6 +19,7 @@
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -30,13 +31,13 @@
 import com.gitblit.GitBlitException.UnknownRequestException;
 import com.gitblit.Keys;
 import com.gitblit.models.FederationModel;
+import com.gitblit.models.FeedModel;
 import com.gitblit.models.RepositoryModel;
 import com.gitblit.models.ServerSettings;
 import com.gitblit.models.ServerStatus;
 import com.gitblit.models.SyndicatedEntryModel;
 import com.gitblit.models.UserModel;
 import com.gitblit.utils.RpcUtils;
-import com.gitblit.utils.StringUtils;
 import com.gitblit.utils.SyndicationUtils;
 
 /**
@@ -70,7 +71,11 @@
 
 	private final List<FederationModel> federationRegistrations;
 
+	private final List<FeedModel> availableFeeds;
+
 	private final List<SyndicatedEntryModel> syndicatedEntries;
+
+	private final Set<String> subscribedRepositories;
 
 	private ServerStatus status;
 
@@ -83,10 +88,13 @@
 		this.allUsers = new ArrayList<UserModel>();
 		this.allRepositories = new ArrayList<RepositoryModel>();
 		this.federationRegistrations = new ArrayList<FederationModel>();
+		this.availableFeeds = new ArrayList<FeedModel>();
 		this.syndicatedEntries = new ArrayList<SyndicatedEntryModel>();
+		this.subscribedRepositories = new HashSet<String>();
 	}
 
 	public void login() throws IOException {
+		refreshAvailableFeeds();
 		refreshRepositories();
 
 		try {
@@ -95,7 +103,7 @@
 		} catch (IOException e) {
 			e.printStackTrace();
 		}
-		
+
 		try {
 			// credentials may not have administrator access
 			// or server may have disabled rpc management
@@ -155,7 +163,7 @@
 		allRepositories.clear();
 		allRepositories.addAll(repositories.values());
 		Collections.sort(allRepositories);
-		updateSubscribedStates();
+		markSubscribedFeeds();
 		return allRepositories;
 	}
 
@@ -176,108 +184,69 @@
 		return status;
 	}
 
+	public List<FeedModel> getAvailableFeeds() {
+		return availableFeeds;
+	}
+
+	public List<FeedModel> getAvailableFeeds(RepositoryModel repository) {
+		List<FeedModel> repositoryFeeds = new ArrayList<FeedModel>();
+		if (repository == null) {
+			return repositoryFeeds;
+		}
+		for (FeedModel feed : availableFeeds) {
+			if (feed.repository.equalsIgnoreCase(repository.name)) {
+				repositoryFeeds.add(feed);
+			}
+		}
+		return repositoryFeeds;
+	}
+
+	public List<FeedModel> refreshAvailableFeeds() throws IOException {
+		List<FeedModel> feeds = RpcUtils.getBranchFeeds(url, account, password);
+		availableFeeds.clear();
+		availableFeeds.addAll(feeds);
+		markSubscribedFeeds();
+		return availableFeeds;
+	}
+
 	public List<SyndicatedEntryModel> refreshSubscribedFeeds() throws IOException {
-		Set<SyndicatedEntryModel> allFeeds = new HashSet<SyndicatedEntryModel>();
-		if (reg.feeds != null && reg.feeds.size() > 0) {
-			for (String feed : reg.feeds) {
-				String[] values = feed.split(":");
-				String repository = values[0];
-				String branch = null;
-				if (values.length > 1) {
-					branch = values[1];
-				}
-				List<SyndicatedEntryModel> list = SyndicationUtils.readFeed(url, repository,
-						branch, -1, account, password);
-				allFeeds.addAll(list);
+		Set<SyndicatedEntryModel> allEntries = new HashSet<SyndicatedEntryModel>();
+		if (reg.feeds.size() > 0) {
+			for (FeedModel feed : reg.feeds) {
+				feed.lastRefresh = new Date();
+				List<SyndicatedEntryModel> entries = SyndicationUtils.readFeed(url,
+						feed.repository, feed.branch, feed.maxRetrieval, account, password);
+				allEntries.addAll(entries);
 			}
 		}
 		syndicatedEntries.clear();
-		syndicatedEntries.addAll(allFeeds);
+		syndicatedEntries.addAll(allEntries);
 		Collections.sort(syndicatedEntries);
 		return syndicatedEntries;
 	}
 
-	private void updateSubscribedStates() {
-		if (reg.feeds != null) {
-			Set<String> subscribedRepositories = new HashSet<String>();
-			for (String feed : reg.feeds) {
-				if (feed.indexOf(':') > -1) {
-					// strip branch
-					subscribedRepositories.add(feed.substring(0, feed.indexOf(':')).toLowerCase());
-				} else {
-					// default branch
-					subscribedRepositories.add(feed.toLowerCase());
-				}
-			}
-			// set subscribed flag
-			for (RepositoryModel repository : allRepositories) {
-				repository.subscribed = subscribedRepositories.contains(repository.name
-						.toLowerCase());
+	public void updateSubscribedFeeds(List<FeedModel> list) {
+		reg.updateSubscribedFeeds(list);
+		markSubscribedFeeds();
+	}
+
+	private void markSubscribedFeeds() {
+		subscribedRepositories.clear();
+		for (FeedModel feed : availableFeeds) {
+			// mark feed in the available list as subscribed
+			feed.subscribed = reg.feeds.contains(feed);
+			if (feed.subscribed) {
+				subscribedRepositories.add(feed.repository.toLowerCase());
 			}
 		}
+	}
+
+	public boolean isSubscribed(RepositoryModel repository) {
+		return subscribedRepositories.contains(repository.name.toLowerCase());
 	}
 
 	public List<SyndicatedEntryModel> getSyndicatedEntries() {
 		return syndicatedEntries;
-	}
-
-	public boolean isSubscribed(RepositoryModel repository, String branch) {
-		if (reg.feeds != null && reg.feeds.size() > 0) {
-			for (String feed : reg.feeds) {
-				String[] values = feed.split(":");
-				String repositoryName = values[0];
-				if (repository.name.equalsIgnoreCase(repositoryName)) {
-					return true;
-				}
-				// TODO check branch subscriptions
-				String branchName = null;
-				if (values.length > 1) {
-					branchName = values[1];
-				}
-			}
-		}
-		return false;
-	}
-
-	public boolean subscribe(RepositoryModel repository, String branch) {
-		String feed = repository.name;
-		if (!StringUtils.isEmpty(branch)) {
-			feed += ":" + branch;
-		}
-		if (reg.feeds == null) {
-			reg.feeds = new ArrayList<String>();
-		}
-		reg.feeds.add(feed);
-		updateSubscribedStates();
-		return true;
-	}
-
-	public boolean unsubscribe(RepositoryModel repository, String branch) {
-		String feed = repository.name;
-		if (!StringUtils.isEmpty(branch)) {
-			feed += ":" + branch;
-		}
-		reg.feeds.remove(feed);
-		if (syndicatedEntries.size() > 0) {
-			List<SyndicatedEntryModel> toRemove = new ArrayList<SyndicatedEntryModel>();
-			for (SyndicatedEntryModel model : syndicatedEntries) {
-				if (model.repository.equalsIgnoreCase(repository.name)) {
-					boolean emptyUnsubscribeBranch = StringUtils.isEmpty(branch);
-					boolean emptyFromBranch = StringUtils.isEmpty(model.branch);
-					if (emptyUnsubscribeBranch && emptyFromBranch) {
-						// default branch, remove
-						toRemove.add(model);
-					} else if (!emptyUnsubscribeBranch && !emptyFromBranch) {
-						if (model.branch.equals(branch)) {
-							// specific branch, remove
-							toRemove.add(model);
-						}
-					}
-				}
-			}
-		}
-		updateSubscribedStates();
-		return true;
 	}
 
 	public List<FederationModel> refreshFederationRegistrations() throws IOException {
diff --git a/src/com/gitblit/client/GitblitManager.java b/src/com/gitblit/client/GitblitManager.java
index 8f396f3..d9c2dcc 100644
--- a/src/com/gitblit/client/GitblitManager.java
+++ b/src/com/gitblit/client/GitblitManager.java
@@ -31,7 +31,6 @@
 import java.text.MessageFormat;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
@@ -62,6 +61,7 @@
 
 import com.gitblit.Constants;
 import com.gitblit.GitBlitException.ForbiddenException;
+import com.gitblit.models.FeedModel;
 import com.gitblit.utils.StringUtils;
 
 /**
@@ -205,8 +205,8 @@
 				return;
 			}
 			// preserve feeds
-			newReg.feeds = reg.feeds;
-			
+			newReg.feeds.addAll(reg.feeds);
+
 			// use new reg
 			reg = newReg;
 		}
@@ -311,7 +311,11 @@
 				GitblitRegistration reg = new GitblitRegistration(server, url, account, password);
 				String[] feeds = config.getStringList("servers", server, "feeds");
 				if (feeds != null) {
-					reg.feeds = new ArrayList<String>(Arrays.asList(feeds));
+					// deserialize the field definitions
+					for (String definition : feeds) {
+						FeedModel feed = new FeedModel(definition);
+						reg.feeds.add(feed);
+					}
 				}
 				reg.lastLogin = lastLogin;
 				registrations.put(reg.name, reg);
@@ -343,8 +347,13 @@
 			if (reg.lastLogin != null) {
 				config.setString("servers", reg.name, "lastLogin", dateFormat.format(reg.lastLogin));
 			}
-			if (reg.feeds != null) {
-				config.setStringList("servers", reg.name, "feeds", reg.feeds);
+			// serialize the feed definitions
+			List<String> definitions = new ArrayList<String>();
+			for (FeedModel feed : reg.feeds) {
+				definitions.add(feed.toString());
+			}
+			if (definitions.size() > 0) {
+				config.setStringList("servers", reg.name, "feeds", definitions);
 			}
 			config.save();
 			return true;
diff --git a/src/com/gitblit/client/GitblitPanel.java b/src/com/gitblit/client/GitblitPanel.java
index 10e9c2d..64e85ea 100644
--- a/src/com/gitblit/client/GitblitPanel.java
+++ b/src/com/gitblit/client/GitblitPanel.java
@@ -56,6 +56,7 @@
 
 import com.gitblit.Constants.RpcRequest;
 import com.gitblit.client.ClosableTabComponent.CloseTabListener;
+import com.gitblit.models.FeedModel;
 import com.gitblit.models.RepositoryModel;
 import com.gitblit.models.SettingModel;
 import com.gitblit.models.SyndicatedEntryModel;
@@ -127,7 +128,7 @@
 
 		tabs = new JTabbedPane(JTabbedPane.BOTTOM);
 		tabs.addTab(Translation.get("gb.repositories"), createRepositoriesPanel());
-		tabs.addTab(Translation.get("gb.recentCommits"), createFeedsPanel());
+		tabs.addTab(Translation.get("gb.recentActivity"), createFeedsPanel());
 		tabs.addTab(Translation.get("gb.users"), createUsersPanel());
 		tabs.addTab(Translation.get("gb.settings"), createSettingsPanel());
 		tabs.addTab(Translation.get("gb.status"), createStatusPanel());
@@ -186,11 +187,12 @@
 		subscribeRepository.setEnabled(false);
 		subscribeRepository.addActionListener(new ActionListener() {
 			public void actionPerformed(ActionEvent e) {
-				subscribeRepository(getSelectedRepositories().get(0));
+				List<FeedModel> feeds = gitblit.getAvailableFeeds(getSelectedRepositories().get(0));
+				subscribeFeeds(feeds);
 			}
 		});
 
-		NameRenderer nameRenderer = new NameRenderer(true);
+		SubscribedRepositoryRenderer nameRenderer = new SubscribedRepositoryRenderer(gitblit);
 		IndicatorsRenderer typeRenderer = new IndicatorsRenderer();
 
 		DefaultTableCellRenderer sizeRenderer = new DefaultTableCellRenderer();
@@ -333,19 +335,34 @@
 			}
 		});
 
+		JButton subscribeFeeds = new JButton(Translation.get("gb.subscribe") + "...");
+		subscribeFeeds.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				subscribeFeeds(gitblit.getAvailableFeeds());
+			}
+		});
+
 		JPanel controls = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0));
 		controls.add(refreshFeeds);
+		controls.add(subscribeFeeds);
 		controls.add(viewCommit);
 		controls.add(viewCommitDiff);
 		controls.add(viewTree);
 
 		NameRenderer nameRenderer = new NameRenderer();
 		syndicationModel = new SyndicatedEntryTableModel();
-		feedsHeader = new HeaderPanel(Translation.get("gb.recentCommits"), "feed_16x16.png");
+		feedsHeader = new HeaderPanel(Translation.get("gb.recentActivity"), "feed_16x16.png");
 		syndicationEntriesTable = Utils.newTable(syndicationModel, Utils.DATE_FORMAT);
 		String name = syndicationEntriesTable
 				.getColumnName(SyndicatedEntryTableModel.Columns.Author.ordinal());
 		syndicationEntriesTable.setRowHeight(nameRenderer.getFont().getSize() + 8);
+		syndicationEntriesTable.getColumn(name).setCellRenderer(nameRenderer);
+		name = syndicationEntriesTable.getColumnName(SyndicatedEntryTableModel.Columns.Repository
+				.ordinal());
+		syndicationEntriesTable.getColumn(name).setCellRenderer(nameRenderer);
+
+		name = syndicationEntriesTable.getColumnName(SyndicatedEntryTableModel.Columns.Branch
+				.ordinal());
 		syndicationEntriesTable.getColumn(name).setCellRenderer(nameRenderer);
 
 		syndicationEntriesTable.addMouseListener(new MouseAdapter() {
@@ -656,7 +673,7 @@
 		syndicationModel.entries.clear();
 		syndicationModel.entries.addAll(gitblit.getSyndicatedEntries());
 		syndicationModel.fireTableDataChanged();
-		feedsHeader.setText(Translation.get("gb.recentCommits") + " ("
+		feedsHeader.setText(Translation.get("gb.recentActivity") + " ("
 				+ gitblit.getSyndicatedEntries().size() + ")");
 	}
 
@@ -921,40 +938,21 @@
 		}
 	}
 
-	protected void subscribeRepository(final RepositoryModel repository) {
-		if (repository == null) {
-			return;
-		}
-		// TODO this is lame. need better ui.
-		if (gitblit.isSubscribed(repository, null)) {
-			// unsubscribe
-			String msg = MessageFormat.format("Do you want to unsubscribe from {0}?",
-					repository.name);
-			String[] options = { "no", "yes" };
-			int result = JOptionPane.showOptionDialog(GitblitPanel.this, msg, "Unsubscribe?",
-					JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options,
-					options[0]);
-			if (result == 1) {
-				if (gitblit.unsubscribe(repository, null)) {
-					updateFeedsTable();
-					updateRepositoriesTable();
-					listener.saveRegistration(repository.name, gitblit.reg);
-				}
+	protected void subscribeFeeds(final List<FeedModel> feeds) {
+		SubscriptionsDialog dialog = new SubscriptionsDialog(feeds) {
+
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public void save() {
+				gitblit.updateSubscribedFeeds(feeds);
+				listener.saveRegistration(gitblit.reg.name, gitblit.reg);
+				setVisible(false);
+				updateRepositoriesTable();
 			}
-		} else {
-			// subscribe
-			String msg = MessageFormat.format("Do you want to subscribe to {0}?", repository.name);
-			String[] options = { "no", "yes" };
-			int result = JOptionPane.showOptionDialog(GitblitPanel.this, msg, "Subscribe?",
-					JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options,
-					options[0]);
-			if (result == 1) {
-				if (gitblit.subscribe(repository, null)) {
-					updateRepositoriesTable();
-					listener.saveRegistration(repository.name, gitblit.reg);
-				}
-			}
-		}
+		};
+		dialog.setLocationRelativeTo(GitblitPanel.this);
+		dialog.setVisible(true);
 	}
 
 	protected void refreshFeeds() {
diff --git a/src/com/gitblit/client/GitblitRegistration.java b/src/com/gitblit/client/GitblitRegistration.java
index cbd4324..05b23d0 100644
--- a/src/com/gitblit/client/GitblitRegistration.java
+++ b/src/com/gitblit/client/GitblitRegistration.java
@@ -16,9 +16,11 @@
 package com.gitblit.client;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
+import com.gitblit.models.FeedModel;
 import com.gitblit.utils.StringUtils;
 
 /**
@@ -37,7 +39,7 @@
 	char[] password;
 	boolean savePassword;
 	Date lastLogin;
-	List<String> feeds;
+	final List<FeedModel> feeds;
 
 	public GitblitRegistration(String name, String url, String account, char[] password) {
 		this.url = url;
@@ -49,6 +51,24 @@
 		} else {
 			this.name = name;
 		}
+		feeds = new ArrayList<FeedModel>();
+	}
+
+	public void updateSubscribedFeeds(List<FeedModel> list) {
+		for (FeedModel feed : list) {
+			if (feeds.contains(feed)) {
+				// possibly unsubscribe/remove feed
+				int index = feeds.indexOf(feed);
+				FeedModel existingFeed = feeds.get(index);
+				existingFeed.subscribed = feed.subscribed;
+				if (!existingFeed.subscribed) {
+					feeds.remove(index);
+				}
+			} else if (feed.subscribed) {
+				// new subscription
+				feeds.add(feed);
+			}
+		}
 	}
 
 	@Override
diff --git a/src/com/gitblit/client/NameRenderer.java b/src/com/gitblit/client/NameRenderer.java
index ce04255..f334d42 100644
--- a/src/com/gitblit/client/NameRenderer.java
+++ b/src/com/gitblit/client/NameRenderer.java
@@ -18,11 +18,8 @@
 import java.awt.Color;
 import java.awt.Component;
 
-import javax.swing.ImageIcon;
 import javax.swing.JTable;
 import javax.swing.table.DefaultTableCellRenderer;
-
-import com.gitblit.models.RepositoryModel;
 
 /**
  * Repository name cell renderer. This renderer shows the group name in a gray
@@ -35,26 +32,13 @@
 
 	private static final long serialVersionUID = 1L;
 
-	final String groupSpan;
-
-	private final boolean displayIcon;
-
-	private final ImageIcon blankIcon;
-
-	private final ImageIcon subscribedIcon;
+	private final String groupSpan;
 
 	public NameRenderer() {
-		this(false);
+		this(Color.gray, new Color(0x00, 0x69, 0xD6));
 	}
 
-	public NameRenderer(boolean showIcon) {
-		this(Color.gray, new Color(0x00, 0x69, 0xD6), showIcon);
-	}
-
-	private NameRenderer(Color group, Color repo, boolean showIcon) {
-		blankIcon = new ImageIcon(getClass().getResource("/blank.png"));
-		subscribedIcon = new ImageIcon(getClass().getResource("/bullet_feed.png"));
-		displayIcon = showIcon;
+	private NameRenderer(Color group, Color repo) {
 		groupSpan = "<span style='color:" + getHexColor(group) + "'>";
 		setForeground(repo);
 	}
@@ -71,26 +55,14 @@
 	public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
 			boolean hasFocus, int row, int column) {
 		super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
-		if (value instanceof RepositoryModel) {
-			RepositoryModel model = (RepositoryModel) value;
-			String name = value.toString();
-			int lastSlash = name.lastIndexOf('/');
-			if (!isSelected && lastSlash > -1) {
-				String group = name.substring(0, lastSlash + 1);
-				String repo = name.substring(lastSlash + 1);
-				setText("<html><body>" + groupSpan + group + "</span>" + repo);
-			} else {
-				this.setText(name);
-			}
-			if (displayIcon) {
-				if (model.subscribed) {
-					setIcon(subscribedIcon);
-				} else {
-					setIcon(blankIcon);
-				}
-			}
+		String name = value.toString();
+		int lastSlash = name.lastIndexOf('/');
+		if (!isSelected && lastSlash > -1) {
+			String group = name.substring(0, lastSlash + 1);
+			String repo = name.substring(lastSlash + 1);
+			setText("<html><body>" + groupSpan + group + "</span>" + repo);
 		} else {
-			this.setText(value.toString());
+			this.setText(name);
 		}
 		return this;
 	}
diff --git a/src/com/gitblit/client/SubscribedRepositoryRenderer.java b/src/com/gitblit/client/SubscribedRepositoryRenderer.java
new file mode 100644
index 0000000..9943333
--- /dev/null
+++ b/src/com/gitblit/client/SubscribedRepositoryRenderer.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2011 gitblit.com.
+ *
+ * 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.
+ */
+package com.gitblit.client;
+
+import java.awt.Component;
+
+import javax.swing.ImageIcon;
+import javax.swing.JTable;
+
+import com.gitblit.models.RepositoryModel;
+
+/**
+ * Displays a subscribed icon on the left of the repository name, if there is at
+ * least one subscribed branch.
+ * 
+ * @author James Moger
+ * 
+ */
+public class SubscribedRepositoryRenderer extends NameRenderer {
+
+	private static final long serialVersionUID = 1L;
+
+	private final GitblitClient gitblit;
+
+	private final ImageIcon blankIcon;
+
+	private final ImageIcon subscribedIcon;
+
+	public SubscribedRepositoryRenderer(GitblitClient gitblit) {
+		super();
+		this.gitblit = gitblit;
+		blankIcon = new ImageIcon(getClass().getResource("/blank.png"));
+		subscribedIcon = new ImageIcon(getClass().getResource("/bullet_feed.png"));
+	}
+
+	public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
+			boolean hasFocus, int row, int column) {
+		super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+		if (value instanceof RepositoryModel) {
+			RepositoryModel model = (RepositoryModel) value;
+			if (gitblit.isSubscribed(model)) {
+				setIcon(subscribedIcon);
+			} else {
+				setIcon(blankIcon);
+			}
+		}
+		return this;
+	}
+}
diff --git a/src/com/gitblit/client/SubscriptionsDialog.java b/src/com/gitblit/client/SubscriptionsDialog.java
new file mode 100644
index 0000000..64a88d9
--- /dev/null
+++ b/src/com/gitblit/client/SubscriptionsDialog.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2011 gitblit.com.
+ *
+ * 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.
+ */
+package com.gitblit.client;
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.util.List;
+
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JPanel;
+import javax.swing.JRootPane;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.KeyStroke;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import com.gitblit.models.FeedModel;
+
+/**
+ * Displays a list of repository branches and allows the user to check or
+ * uncheck branches.
+ * 
+ * @author James Moger
+ * 
+ */
+public abstract class SubscriptionsDialog extends JDialog {
+
+	private static final long serialVersionUID = 1L;
+
+	private final List<FeedModel> feeds;
+
+	private JTable feedsTable;
+
+	private FeedsTableModel model;
+
+	public SubscriptionsDialog(List<FeedModel> registrations) {
+		super();
+		this.feeds = registrations;
+		setTitle(Translation.get("gb.manage"));
+		setIconImage(new ImageIcon(getClass().getResource("/gitblt-favicon.png")).getImage());
+		initialize();
+		setSize(600, 400);
+	}
+
+	@Override
+	protected JRootPane createRootPane() {
+		KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
+		JRootPane rootPane = new JRootPane();
+		rootPane.registerKeyboardAction(new ActionListener() {
+			public void actionPerformed(ActionEvent actionEvent) {
+				setVisible(false);
+			}
+		}, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW);
+		return rootPane;
+	}
+
+	private void initialize() {
+		NameRenderer nameRenderer = new NameRenderer();
+		model = new FeedsTableModel(feeds);
+		feedsTable = Utils.newTable(model, Utils.DATE_FORMAT);
+		feedsTable.setRowHeight(nameRenderer.getFont().getSize() + 8);
+		feedsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+			@Override
+			public void valueChanged(ListSelectionEvent e) {
+				if (e.getValueIsAdjusting()) {
+					return;
+				}
+				int viewRow = feedsTable.getSelectedRow();
+				if (viewRow == -1) {
+					return;
+				}
+				int modelRow = feedsTable.convertRowIndexToModel(viewRow);
+				FeedModel feed = model.get(modelRow);
+				feed.subscribed = !feed.subscribed;
+				model.fireTableDataChanged();
+			}
+		});
+
+		String repository = feedsTable.getColumnName(FeedsTableModel.Columns.Repository.ordinal());
+		feedsTable.getColumn(repository).setCellRenderer(nameRenderer);
+
+		String branch = feedsTable.getColumnName(FeedsTableModel.Columns.Branch.ordinal());
+		feedsTable.getColumn(branch).setCellRenderer(nameRenderer);
+
+		String subscribed = feedsTable.getColumnName(FeedsTableModel.Columns.Subscribed.ordinal());
+		feedsTable.getColumn(subscribed).setCellRenderer(new BooleanCellRenderer());
+		feedsTable.getColumn(subscribed).setMinWidth(30);
+		feedsTable.getColumn(subscribed).setMaxWidth(30);
+
+		Utils.packColumns(feedsTable, 5);
+
+		final JButton cancel = new JButton(Translation.get("gb.cancel"));
+		cancel.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent event) {
+				setVisible(false);
+			}
+		});
+
+		final JButton save = new JButton(Translation.get("gb.save"));
+		save.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent event) {
+				save();
+			}
+		});
+
+		feedsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+			@Override
+			public void valueChanged(ListSelectionEvent e) {
+				if (e.getValueIsAdjusting()) {
+					return;
+				}
+			}
+		});
+
+		JPanel controls = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0));
+		controls.add(cancel);
+		controls.add(save);
+
+		final Insets insets = new Insets(5, 5, 5, 5);
+		JPanel centerPanel = new JPanel(new BorderLayout(5, 5)) {
+
+			private static final long serialVersionUID = 1L;
+
+			public Insets getInsets() {
+				return insets;
+			}
+		};
+		centerPanel.add(new HeaderPanel(Translation.get("gb.subscribe") + "...", "feed_16x16.png"),
+				BorderLayout.NORTH);
+		centerPanel.add(new JScrollPane(feedsTable), BorderLayout.CENTER);
+		centerPanel.add(controls, BorderLayout.SOUTH);
+
+		getContentPane().setLayout(new BorderLayout(5, 5));
+		getContentPane().add(centerPanel, BorderLayout.CENTER);
+	}
+
+	public abstract void save();
+}
diff --git a/src/com/gitblit/client/SyndicatedEntryTableModel.java b/src/com/gitblit/client/SyndicatedEntryTableModel.java
index 4f25c9b..db62b1a 100644
--- a/src/com/gitblit/client/SyndicatedEntryTableModel.java
+++ b/src/com/gitblit/client/SyndicatedEntryTableModel.java
@@ -25,7 +25,7 @@
 import com.gitblit.models.SyndicatedEntryModel;
 
 /**
- * Table model of List<SyndicatedEntryModel>
+ * Table model for a list of retrieved feed entries.
  * 
  * @author James Moger
  * 
@@ -37,7 +37,7 @@
 	List<SyndicatedEntryModel> entries;
 
 	enum Columns {
-		Date, Repository, Author, Message;
+		Date, Repository, Branch, Author, Message;
 
 		@Override
 		public String toString() {
@@ -76,6 +76,8 @@
 			return Translation.get("gb.date");
 		case Repository:
 			return Translation.get("gb.repository");
+		case Branch:
+			return Translation.get("gb.branch");
 		case Author:
 			return Translation.get("gb.author");
 		case Message:
@@ -107,6 +109,8 @@
 			return entry.published;
 		case Repository:
 			return entry.repository;
+		case Branch:
+			return entry.branch;
 		case Author:
 			return entry.author;
 		case Message:
diff --git a/src/com/gitblit/client/Translation.java b/src/com/gitblit/client/Translation.java
index cd5515b..2e7b5bb 100644
--- a/src/com/gitblit/client/Translation.java
+++ b/src/com/gitblit/client/Translation.java
@@ -15,42 +15,34 @@
  */
 package com.gitblit.client;
 
-import java.io.InputStream;
-import java.util.Properties;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
 
+/**
+ * Loads the Gitblit language resource file.
+ * 
+ * @author James Moger
+ * 
+ */
 public class Translation {
 
-	private final static Properties translation;
+	private final static ResourceBundle translation;
 
 	static {
-		translation = new Properties();
-		InputStream is = null;
+		ResourceBundle bundle;
 		try {
-			is = Translation.class.getResource("/com/gitblit/wicket/GitBlitWebApp.properties")
-					.openStream();
-		} catch (Throwable t) {
-			try {
-				is = Translation.class.getResource("/GitBlitWebApp.properties").openStream();
-			} catch (Throwable x) {
-			}
+			// development location
+			bundle = ResourceBundle.getBundle("com/gitblit/wicket/GitBlitWebApp");
+		} catch (MissingResourceException e) {
+			// runtime location
+			bundle = ResourceBundle.getBundle("GitBlitWebApp");
 		}
-		if (is != null) {
-			try {
-				translation.load(is);
-			} catch (Throwable t) {
-
-			} finally {
-				try {
-					is.close();
-				} catch (Throwable t) {
-				}
-			}
-		}
+		translation = bundle;
 	}
 
 	public static String get(String key) {
 		if (translation.containsKey(key)) {
-			return translation.getProperty(key).trim();
+			return translation.getString(key).trim();
 		}
 		return key;
 	}
diff --git a/src/com/gitblit/models/FeedModel.java b/src/com/gitblit/models/FeedModel.java
new file mode 100644
index 0000000..67cff95
--- /dev/null
+++ b/src/com/gitblit/models/FeedModel.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2011 gitblit.com.
+ *
+ * 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.
+ */
+package com.gitblit.models;
+
+import java.io.Serializable;
+import java.text.MessageFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import com.gitblit.utils.StringUtils;
+
+/**
+ * FeedModel represents a syndication (RSS) feed.
+ * 
+ * @author James Moger
+ */
+public class FeedModel implements Serializable, Comparable<FeedModel> {
+
+	public String repository;
+	public String branch;
+	public int maxRetrieval;
+	public Date lastRefresh;
+
+	public boolean subscribed;
+
+	private static final long serialVersionUID = 1L;
+
+	public FeedModel() {
+		this("");
+	}
+
+	public FeedModel(String definition) {
+		maxRetrieval = -1;
+		lastRefresh = new Date(0);
+
+		String[] fields = definition.split(":");
+		repository = fields[0];
+		if (fields.length > 1) {
+			branch = fields[1];
+			maxRetrieval = Integer.parseInt(fields[2]);
+			try {
+				lastRefresh = new SimpleDateFormat("yyyyMMddHHmmss").parse(fields[3]);
+			} catch (ParseException e) {
+			}
+			subscribed = true;
+		}
+	}
+
+	@Override
+	public String toString() {
+		return MessageFormat.format("{0}:{1}:{2,number,0}:{3,date,yyyyMMddHHmmss}", repository,
+				branch, maxRetrieval, lastRefresh);
+	}
+
+	@Override
+	public int compareTo(FeedModel o) {
+		int repositoryCompare = repository.compareTo(o.repository);
+		if (repositoryCompare == 0) {
+			// same repository
+			if (StringUtils.isEmpty(branch)) {
+				return 1;
+			} else if (StringUtils.isEmpty(o.branch)) {
+				return -1;
+			}
+			return branch.compareTo(o.branch);
+		}
+		return repositoryCompare;
+	}
+
+	@Override
+	public int hashCode() {
+		return (repository + (StringUtils.isEmpty(branch) ? "" : branch)).toLowerCase().hashCode();
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		if (o instanceof FeedModel) {
+			return hashCode() == o.hashCode();
+		}
+		return false;
+	}
+}
diff --git a/src/com/gitblit/models/RepositoryModel.java b/src/com/gitblit/models/RepositoryModel.java
index af42061..9a774fb 100644
--- a/src/com/gitblit/models/RepositoryModel.java
+++ b/src/com/gitblit/models/RepositoryModel.java
@@ -55,7 +55,6 @@
 	public String frequency;
 	public String origin;
 	public String size;
-	public boolean subscribed;
 
 	public RepositoryModel() {
 		this("", "", "", new Date(0));
diff --git a/src/com/gitblit/utils/RpcUtils.java b/src/com/gitblit/utils/RpcUtils.java
index faa910b..c2f20d8 100644
--- a/src/com/gitblit/utils/RpcUtils.java
+++ b/src/com/gitblit/utils/RpcUtils.java
@@ -27,6 +27,7 @@
 import com.gitblit.models.FederationModel;
 import com.gitblit.models.FederationProposal;
 import com.gitblit.models.FederationSet;
+import com.gitblit.models.FeedModel;
 import com.gitblit.models.RepositoryModel;
 import com.gitblit.models.ServerSettings;
 import com.gitblit.models.ServerStatus;
@@ -389,7 +390,7 @@
 	}
 
 	/**
-	 * Retrieves a map of all branches in the Gitblit server keyed by
+	 * Retrieves a map of local branches in the Gitblit server keyed by
 	 * repository.
 	 * 
 	 * @param serverUrl
@@ -398,12 +399,36 @@
 	 * @return
 	 * @throws IOException
 	 */
-	public static Map<String, Collection<String>> getAllBranches(String serverUrl,
-			String account, char[] password) throws IOException {
+	public static Map<String, Collection<String>> getBranches(String serverUrl, String account,
+			char[] password) throws IOException {
 		String url = asLink(serverUrl, RpcRequest.LIST_BRANCHES);
-		Map<String, Collection<String>> allReferences = JsonUtils.retrieveJson(url,
-				BRANCHES_TYPE, account, password);
-		return allReferences;
+		Map<String, Collection<String>> branches = JsonUtils.retrieveJson(url, BRANCHES_TYPE,
+				account, password);
+		return branches;
+	}
+
+	/**
+	 * Retrieves a list of available branch feeds in the Gitblit server.
+	 * 
+	 * @param serverUrl
+	 * @param account
+	 * @param password
+	 * @return
+	 * @throws IOException
+	 */
+	public static List<FeedModel> getBranchFeeds(String serverUrl, String account, char[] password)
+			throws IOException {
+		List<FeedModel> feeds = new ArrayList<FeedModel>();
+		Map<String, Collection<String>> allBranches = getBranches(serverUrl, account, password);
+		for (Map.Entry<String, Collection<String>> entry : allBranches.entrySet()) {
+			for (String branch : entry.getValue()) {
+				FeedModel feed = new FeedModel();
+				feed.repository = entry.getKey();
+				feed.branch = branch;
+				feeds.add(feed);
+			}
+		}
+		return feeds;
 	}
 
 	/**
diff --git a/src/com/gitblit/wicket/GitBlitWebApp.properties b/src/com/gitblit/wicket/GitBlitWebApp.properties
index e16b44d..6d20a72 100644
--- a/src/com/gitblit/wicket/GitBlitWebApp.properties
+++ b/src/com/gitblit/wicket/GitBlitWebApp.properties
@@ -177,5 +177,6 @@
 gb.version = version
 gb.releaseDate = release date
 gb.date = date
-gb.recentCommits = recent commits
-gb.subscribe = subscribe
\ No newline at end of file
+gb.recentActivity = recent activity
+gb.subscribe = subscribe
+gb.branch = branch
\ No newline at end of file
diff --git a/tests/com/gitblit/tests/RpcTests.java b/tests/com/gitblit/tests/RpcTests.java
index 637d488..37a4955 100644
--- a/tests/com/gitblit/tests/RpcTests.java
+++ b/tests/com/gitblit/tests/RpcTests.java
@@ -244,7 +244,7 @@
 	}
 
 	public void testBranches() throws Exception {
-		Map<String, Collection<String>> branches = RpcUtils.getAllBranches(url, account,
+		Map<String, Collection<String>> branches = RpcUtils.getBranches(url, account,
 				password.toCharArray());
 		assertTrue(branches != null);
 		assertTrue(branches.size() > 0);

--
Gitblit v1.9.1