diff options
| author | Carsten Pfeiffer | 2011-10-24 09:04:34 +0000 |
|---|---|---|
| committer | Carsten Pfeiffer | 2011-10-24 10:27:55 +0000 |
| commit | 7e8fef95439e087e2621d9f33c6790675a1cfa57 (patch) | |
| tree | 06e32d304e46e7fadfef9fc8f975976d122fc935 | |
| parent | 1ba41922b09d98eb7aeb72d94e41e4a9b7b6acc0 (diff) | |
| download | egit-7e8fef95439e087e2621d9f33c6790675a1cfa57.tar.gz egit-7e8fef95439e087e2621d9f33c6790675a1cfa57.tar.xz egit-7e8fef95439e087e2621d9f33c6790675a1cfa57.zip | |
Added the 'Follow Renames' feature to the history page.
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
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 ebf326122c..c58d89fab2 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 1d24d06eb1..6d994d5066 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 047821b363..9d6646d30b 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 9f64e6e798..6ec4fc2258 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 958d5891a5..5ffc130f8f 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 3653caac9d..6731bf521b 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 |
