aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarsten Pfeiffer2011-10-24 05:04:34 (EDT)
committerCarsten Pfeiffer2011-10-24 06:27:55 (EDT)
commit7e8fef95439e087e2621d9f33c6790675a1cfa57 (patch)
tree06e32d304e46e7fadfef9fc8f975976d122fc935
parent1ba41922b09d98eb7aeb72d94e41e4a9b7b6acc0 (diff)
downloadegit-7e8fef95439e087e2621d9f33c6790675a1cfa57.zip
egit-7e8fef95439e087e2621d9f33c6790675a1cfa57.tar.gz
egit-7e8fef95439e087e2621d9f33c6790675a1cfa57.tar.bz2
Added the 'Follow Renames' feature to the history page.refs/changes/43/3743/6
This adds a dedicated BooleanPrefAction, which is added to the 'Show' sub-menu and the EGit preferences. When activated, a history page for regular files sets proper FollowFilter instances as TreeFilter for the current walk. The fileViewer now correctly displays those files that are related to the currently selected commit and file, taking renaming of files into account). Also set initial pathFilter for those files that have not been renamed at all. Following is disabled by default to match C git. Note: depends on jgit change I4761e9f5cfb4f0ef0b0e1e38991401a1d5003bea AlsoBy: Benjamin Gandon <benje@linkeo.com> Change-Id: Id810e22db3f415a8471a7c4c80d9abe9fcaeb21f
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/PluginPreferenceInitializer.java1
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIPreferences.java2
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java3
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java160
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/preferences/ViewsPreferencePage.java3
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties1
6 files changed, 167 insertions, 3 deletions
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/PluginPreferenceInitializer.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/PluginPreferenceInitializer.java
index ebf3261..c58d89f 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/PluginPreferenceInitializer.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/PluginPreferenceInitializer.java
@@ -44,6 +44,7 @@ public class PluginPreferenceInitializer extends AbstractPreferenceInitializer {
store.setDefault(UIPreferences.RESOURCEHISTORY_SHOW_REV_COMMENT, true);
store.setDefault(UIPreferences.RESOURCEHISTORY_SHOW_TOOLTIPS, false);
store.setDefault(UIPreferences.RESOURCEHISTORY_SHOW_ALL_BRANCHES, false);
+ store.setDefault(UIPreferences.RESOURCEHISTORY_FOLLOW_RENAMES, false);
store.setDefault(UIPreferences.RESOURCEHISTORY_COMPARE_MODE, false);
store.setDefault(UIPreferences.DECORATOR_RECOMPUTE_ANCESTORS, true);
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIPreferences.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIPreferences.java
index 1d24d06..6d994d5 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIPreferences.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIPreferences.java
@@ -42,6 +42,8 @@ public class UIPreferences {
/** */
public final static String RESOURCEHISTORY_SHOW_ALL_BRANCHES = "resourcehistory_show_all_branches"; //$NON-NLS-1$
/** */
+ public static final String RESOURCEHISTORY_FOLLOW_RENAMES = "resourcehistory_follow_renames"; //$NON-NLS-1$
+ /** */
public final static String RESOURCEHISTORY_COMPARE_MODE = "resourcehistory_compare_mode"; //$NON-NLS-1$
/** */
public final static String FINDTOOLBAR_IGNORE_CASE = "findtoolbar_ignore_case"; //$NON-NLS-1$
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java
index 047821b..9d6646d 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java
@@ -502,6 +502,9 @@ public class UIText extends NLS {
public static String GitHistoryPage_ShowAllBranchesMenuLabel;
/** */
+ public static String GitHistoryPage_FollowRenames;
+
+ /** */
public static String GitHistoryPage_FilterSubMenuLabel;
/** */
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java
index 9f64e6e..6ec4fc2 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java
@@ -58,6 +58,7 @@ import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.events.ListenerHandle;
@@ -69,6 +70,8 @@ import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revplot.PlotCommit;
+import org.eclipse.jgit.revwalk.FollowFilter;
+import org.eclipse.jgit.revwalk.RenameCallback;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevFlag;
import org.eclipse.jgit.revwalk.RevObject;
@@ -77,6 +80,7 @@ import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
+import org.eclipse.jgit.treewalk.filter.OrTreeFilter;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
import org.eclipse.osgi.util.NLS;
@@ -225,6 +229,8 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener {
IWorkbenchAction showAllBranchesAction;
+ BooleanPrefAction followRenamesAction;
+
IWorkbenchAction reuseCompareEditorAction;
ShowFilterAction showAllRepoVersionsAction;
@@ -256,6 +262,7 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener {
createShowNotesAction();
createWrapCommentAction();
createFillCommentAction();
+ createFollowRenamesAction();
wrapCommentAction.setEnabled(showCommentAction.isChecked());
fillCommentAction.setEnabled(showCommentAction.isChecked());
@@ -360,6 +367,19 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener {
actionsToDispose.add(showAllBranchesAction);
}
+ private void createFollowRenamesAction() {
+ followRenamesAction = new BooleanPrefAction(
+ UIPreferences.RESOURCEHISTORY_FOLLOW_RENAMES,
+ UIText.GitHistoryPage_FollowRenames) {
+ @Override
+ void apply(boolean follow) {
+ historyPage.refresh();
+ }
+ };
+ followRenamesAction.apply(followRenamesAction.isChecked());
+ actionsToDispose.add(followRenamesAction);
+ }
+
private void createShowCommentAction() {
showCommentAction = new BooleanPrefAction(
UIPreferences.RESOURCEHISTORY_SHOW_REV_COMMENT,
@@ -571,6 +591,8 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener {
private boolean currentShowNotes;
+ private boolean currentFollowRenames;
+
// react on changes to the relative date preference
private final IPropertyChangeListener listener = new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
@@ -804,9 +826,12 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener {
fileViewer.setInput(null);
return;
}
+
final PlotCommit<?> c = (PlotCommit<?>) sel.getFirstElement();
+
commentViewer.setInput(c);
fileViewer.setInput(c);
+
}
});
commentViewer
@@ -865,6 +890,8 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener {
viewMenuMgr.add(showSubMenuMgr);
showSubMenuMgr.add(actions.showAllBranchesAction);
showSubMenuMgr.add(actions.showNotesAction);
+ showSubMenuMgr.add(actions.followRenamesAction);
+ showSubMenuMgr.add(new Separator());
showSubMenuMgr.add(actions.findAction);
showSubMenuMgr.add(actions.showFilesAction);
showSubMenuMgr.add(actions.showCommentAction);
@@ -1383,6 +1410,8 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener {
graph.getControl().getDisplay().asyncExec(new Runnable() {
public void run() {
if (!graph.getControl().isDisposed() && job == j) {
+ if (getFollowRenames())
+ updateFollowFilter();
graph.setInput(highlightFlag, list, asArray, input);
if (trace)
GitTraceLocation.getTrace().trace(
@@ -1403,6 +1432,32 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener {
GitTraceLocation.HISTORYVIEW.getLocation());
}
+ /**
+ * Updates the filter for the fileviewer with the information
+ * from the revwalk, which files have been renamed. This makes sure
+ * that the fileViewer only shows those files that part of the selected
+ * file and its rename-history.
+ */
+ protected void updateFollowFilter() {
+ if (currentWalk instanceof FollowingSWTWalk) {
+ List<DiffEntry> renamedEntries = ((FollowingSWTWalk) currentWalk).getRenamedEntries();
+ List<String> pathList = new ArrayList<String>(renamedEntries.size());
+ for (DiffEntry entry : renamedEntries) {
+ if (!pathList.contains(entry.getOldPath()))
+ pathList.add(entry.getOldPath());
+
+ if (!pathList.contains(entry.getNewPath()))
+ pathList.add(entry.getNewPath());
+ }
+
+ if (pathList.size() > 0) {
+ TreeWalk fileWalker = fileViewer.getTreeWalk();
+ fileWalker.setFilter(AndTreeFilter.create(PathFilterGroup
+ .createFromStrings(pathList), TreeFilter.ANY_DIFF));
+ }
+ }
+ }
+
private void setWarningText(String warning) {
if (warningComposite == null || warningComposite.isDisposed())
return;
@@ -1477,6 +1532,8 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener {
.getBoolean(UIPreferences.RESOURCEHISTORY_SHOW_NOTES);
currentShowNotes = store
.getBoolean(UIPreferences.RESOURCEHISTORY_SHOW_NOTES);
+ boolean followRenamesChanged = currentFollowRenames != getFollowRenames();
+ currentFollowRenames = getFollowRenames();
if (!db.equals(currentRepo)) {
repoChanged = true;
@@ -1485,7 +1542,14 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener {
return pathChanged
|| currentWalk == null || headChanged || repoChanged || allBranchesChanged
- || showNotesChanged;
+ || showNotesChanged || followRenamesChanged;
+ }
+
+ /**
+ * @return whether following renames is currently enabled
+ */
+ protected boolean getFollowRenames() {
+ return store.getBoolean(UIPreferences.RESOURCEHISTORY_FOLLOW_RENAMES);
}
private AnyObjectId resolveHead(Repository db, boolean acceptNull) {
@@ -1594,7 +1658,10 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener {
currentHeadId = headId;
if (currentWalk != null)
currentWalk.release();
- currentWalk = new SWTWalk(db);
+ if (getFollowRenames())
+ currentWalk = new FollowingSWTWalk(db);
+ else
+ currentWalk = new SWTWalk(db);
try {
currentWalk.addAdditionalRefs(db.getRefDatabase().getAdditionalRefs());
currentWalk.addAdditionalRefs(db.getRefDatabase().
@@ -1651,11 +1718,27 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener {
private TreeWalk createFileWalker(Repository db, List<FilterPath> paths) {
final TreeWalk fileWalker = new TreeWalk(db);
fileWalker.setRecursive(true);
- if (paths.size() > 0) {
+ if (store.getBoolean(UIPreferences.RESOURCEHISTORY_FOLLOW_RENAMES)
+ && !paths.isEmpty()
+ && allRegularFiles(paths)) {
+ pathFilters = paths;
+
+ List<String> selectedPaths = new ArrayList<String>(paths.size());
+ for (FilterPath filterPath : paths)
+ selectedPaths.add(filterPath.getPath());
+
+ TreeFilter followFilter = createFollowFilterFor(selectedPaths);
+ currentWalk.setTreeFilter(followFilter);
+ // for the fileViewer, we start with a simple path filter, until we know
+ // all its names from the rename-history (see updateFollowFilter)
+ fileWalker.setFilter(AndTreeFilter.create(PathFilterGroup
+ .createFromStrings(selectedPaths), TreeFilter.ANY_DIFF));
+ } else if (paths.size() > 0) {
pathFilters = paths;
List<String> stringPaths = new ArrayList<String>(paths.size());
for (FilterPath p : paths)
stringPaths.add(p.getPath());
+
currentWalk.setTreeFilter(AndTreeFilter.create(PathFilterGroup
.createFromStrings(stringPaths), TreeFilter.ANY_DIFF));
fileWalker.setFilter(currentWalk.getTreeFilter().clone());
@@ -1668,6 +1751,39 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener {
return fileWalker;
}
+ /**
+ * Creates a filter for the given files, will make sure that renames/copies
+ * of all files will be followed.
+ * @param paths the list of files to follow, must not be <code>null</code> or empty
+ * @return the ORed list of {@link FollowFilter follow filters}
+ */
+ private TreeFilter createFollowFilterFor(List<String> paths) {
+ if (paths == null || paths.isEmpty())
+ throw new IllegalArgumentException("paths must not be null nor empty"); //$NON-NLS-1$
+
+ List<TreeFilter> followFilters = new ArrayList<TreeFilter>(paths.size());
+ for (String path : paths)
+ followFilters.add(FollowFilter.create(path));
+
+ if (followFilters.size() == 1)
+ return followFilters.get(0);
+
+ return OrTreeFilter.create(followFilters);
+ }
+
+ /**
+ * @return Returns <code>true</code> if <b>all</b> filterpaths refer to plain files,
+ * or if the list is empty.
+ * @param paths the paths to check
+ */
+ private boolean allRegularFiles(List<FilterPath> paths) {
+ for (FilterPath filterPath : paths) {
+ if (!filterPath.isRegularFile())
+ return false;
+ }
+ return true;
+ }
+
private void scheduleNewGenerateHistoryJob() {
final SWTCommitList list = new SWTCommitList(graph.getControl()
.getDisplay());
@@ -1778,4 +1894,42 @@ public class GitHistoryPage extends HistoryPage implements RefsChangedListener {
job = null;
}
}
+
+ /**
+ * Special version of SWTWalk that tracks which files are renamed/copied.
+ */
+ private static class FollowingSWTWalk extends SWTWalk {
+ private RenameCallback callback = new RenameCallback() {
+ @Override
+ public void renamed(DiffEntry entry) {
+ renamedEntries.add(entry);
+ }
+ };
+ private List<DiffEntry> renamedEntries = new ArrayList<DiffEntry>(4);
+
+ FollowingSWTWalk(Repository repo) {
+ super(repo);
+ }
+
+ @Override
+ protected void reset(int aRetainFlags) {
+ super.reset(aRetainFlags);
+ renamedEntries.clear();
+ }
+
+ public List<DiffEntry> getRenamedEntries() {
+ return new ArrayList<DiffEntry>(renamedEntries);
+ }
+
+ @Override
+ public void setTreeFilter(TreeFilter filter) {
+ super.setTreeFilter(filter);
+ if (filter instanceof FollowFilter) {
+ FollowFilter followFilter = (FollowFilter) filter;
+ RenameCallback renameCallback = followFilter.getRenameCallback();
+ if (renameCallback == null)
+ followFilter.setRenameCallback(callback);
+ }
+ }
+ }
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/preferences/ViewsPreferencePage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/preferences/ViewsPreferencePage.java
index 958d589..5ffc130 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/preferences/ViewsPreferencePage.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/preferences/ViewsPreferencePage.java
@@ -59,6 +59,9 @@ public class ViewsPreferencePage extends FieldEditorPreferencePage implements
UIPreferences.RESOURCEHISTORY_SHOW_NOTES,
UIText.ResourceHistory_toggleShowNotes, historyGroup));
addField(new BooleanFieldEditor(
+ UIPreferences.RESOURCEHISTORY_FOLLOW_RENAMES,
+ UIText.GitHistoryPage_FollowRenames, historyGroup));
+ addField(new BooleanFieldEditor(
UIPreferences.RESOURCEHISTORY_SHOW_COMMENT_WRAP,
UIText.ResourceHistory_toggleCommentWrap, historyGroup));
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
index 3653caa..6731bf5 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
@@ -175,6 +175,7 @@ GitHistoryPage_mergeMenuItem=Merge
GitHistoryPage_rebaseMenuItem=Rebase on Top of
GitHistoryPage_SetAsBaselineMenuLabel=&Set as Baseline
GitHistoryPage_ShowAllBranchesMenuLabel=All &Branches and Tags
+GitHistoryPage_FollowRenames=&Follow Renames
GitHistoryPage_FilterSubMenuLabel=&Filter
GitHistoryPage_IncompleteListTooltip=Not all commits are shown, the limit may be exceeded or the job building the list may have been aborted
GitHistoryPage_ListIncompleteWarningMessage=The list is incomplete