summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.pgm
diff options
context:
space:
mode:
authorShawn O. Pearce <spearce@spearce.org>2010-07-03 18:13:10 -0700
committerShawn O. Pearce <spearce@spearce.org>2010-07-03 18:17:55 -0700
commit1913b41bc749ed8a176d7ea8100fb4b260547523 (patch)
tree6592da4054933991cb42b5edc1cbbbfc14d7291d /org.eclipse.jgit.pgm
parente9de5643fad6abdfe081d1a11416f2e4fa669038 (diff)
downloadjgit-1913b41bc749ed8a176d7ea8100fb4b260547523.tar.gz
jgit-1913b41bc749ed8a176d7ea8100fb4b260547523.zip
log: Implement --follow
The FollowFilter can be installed on a RevWalk to cause the path to be updated through rename detection when the affected file is found to be added to the project. The filter works reasonably well, for example we can follow the history of the fsck command in git-core: $ jgit log --name-status --follow builtin/fsck.c | grep ^R R100 builtin-fsck.c builtin/fsck.c R099 fsck.c builtin-fsck.c R099 fsck-objects.c fsck.c R099 fsck-cache.c fsck-objects.c Change-Id: I4017bcfd150126aa342fdd423a688493ca660a1f Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Diffstat (limited to 'org.eclipse.jgit.pgm')
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java63
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java10
2 files changed, 62 insertions, 11 deletions
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
index 83ef6eb875..48a05915e4 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
@@ -51,6 +51,7 @@ import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
+import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
@@ -65,11 +66,12 @@ import org.eclipse.jgit.diff.RawTextIgnoreLeadingWhitespace;
import org.eclipse.jgit.diff.RawTextIgnoreTrailingWhitespace;
import org.eclipse.jgit.diff.RawTextIgnoreWhitespaceChange;
import org.eclipse.jgit.diff.RenameDetector;
+import org.eclipse.jgit.diff.DiffEntry.ChangeType;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.TextProgressMonitor;
+import org.eclipse.jgit.revwalk.FollowFilter;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
@@ -195,20 +197,26 @@ class Log extends RevWalkTextBuiltin {
private void showDiff(RevCommit c) throws IOException {
final TreeWalk tw = new TreeWalk(db);
- tw.reset();
tw.setRecursive(true);
+ tw.reset();
tw.addTree(c.getParent(0).getTree());
tw.addTree(c.getTree());
- tw.setFilter(AndTreeFilter.create(TreeFilter.ANY_DIFF, pathFilter));
+ tw.setFilter(AndTreeFilter.create(pathFilter, TreeFilter.ANY_DIFF));
List<DiffEntry> files = DiffEntry.scan(tw);
- if (detectRenames) {
- RenameDetector rd = new RenameDetector(db);
- if (renameLimit != null)
- rd.setRenameLimit(renameLimit.intValue());
- rd.addAll(files);
- files = rd.compute(new TextProgressMonitor());
- }
+ if (pathFilter instanceof FollowFilter && isAdd(files)) {
+ // The file we are following was added here, find where it
+ // came from so we can properly show the rename or copy,
+ // then continue digging backwards.
+ //
+ tw.reset();
+ tw.addTree(c.getParent(0).getTree());
+ tw.addTree(c.getTree());
+ tw.setFilter(TreeFilter.ANY_DIFF);
+ files = updateFollowFilter(detectRenames(DiffEntry.scan(tw)));
+
+ } else if (detectRenames)
+ files = detectRenames(files);
if (showNameAndStatusOnly) {
Diff.nameStatus(out, files);
@@ -220,4 +228,39 @@ class Log extends RevWalkTextBuiltin {
}
out.println();
}
+
+ private List<DiffEntry> detectRenames(List<DiffEntry> files)
+ throws IOException {
+ RenameDetector rd = new RenameDetector(db);
+ if (renameLimit != null)
+ rd.setRenameLimit(renameLimit.intValue());
+ rd.addAll(files);
+ return rd.compute();
+ }
+
+ private boolean isAdd(List<DiffEntry> files) {
+ String oldPath = ((FollowFilter) pathFilter).getPath();
+ for (DiffEntry ent : files) {
+ if (ent.getChangeType() == ChangeType.ADD
+ && ent.getNewName().equals(oldPath))
+ return true;
+ }
+ return false;
+ }
+
+ private List<DiffEntry> updateFollowFilter(List<DiffEntry> files) {
+ String oldPath = ((FollowFilter) pathFilter).getPath();
+ for (DiffEntry ent : files) {
+ if (isRename(ent) && ent.getNewName().equals(oldPath)) {
+ pathFilter = FollowFilter.create(ent.getOldName());
+ return Collections.singletonList(ent);
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ private static boolean isRename(DiffEntry ent) {
+ return ent.getChangeType() == ChangeType.RENAME
+ || ent.getChangeType() == ChangeType.COPY;
+ }
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java
index beb961d99c..bf3924b70b 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java
@@ -53,6 +53,7 @@ import org.kohsuke.args4j.Option;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler;
+import org.eclipse.jgit.revwalk.FollowFilter;
import org.eclipse.jgit.revwalk.ObjectWalk;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevFlag;
@@ -110,6 +111,11 @@ abstract class RevWalkTextBuiltin extends TextBuiltin {
enableRevSort(RevSort.BOUNDARY, on);
}
+ @Option(name = "--follow", metaVar = "metaVar_path")
+ void follow(final String path) {
+ pathFilter = FollowFilter.create(path);
+ }
+
@Argument(index = 0, metaVar = "metaVar_commitish")
private final List<RevCommit> commits = new ArrayList<RevCommit>();
@@ -139,7 +145,9 @@ abstract class RevWalkTextBuiltin extends TextBuiltin {
for (final RevSort s : sorting)
walk.sort(s, true);
- if (pathFilter != TreeFilter.ALL)
+ if (pathFilter instanceof FollowFilter)
+ walk.setTreeFilter(pathFilter);
+ else if (pathFilter != TreeFilter.ALL)
walk.setTreeFilter(AndTreeFilter.create(pathFilter,
TreeFilter.ANY_DIFF));