aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.pgm/src/org
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit.pgm/src/org')
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java174
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java143
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java12
3 files changed, 253 insertions, 76 deletions
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java
index fc1e400ab0..77ed73048d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java
@@ -45,31 +45,34 @@
package org.eclipse.jgit.pgm;
+import java.io.BufferedOutputStream;
import java.io.IOException;
-import java.io.PrintStream;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
-import org.kohsuke.args4j.Argument;
-import org.kohsuke.args4j.Option;
-
+import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffFormatter;
-import org.eclipse.jgit.diff.MyersDiff;
-import org.eclipse.jgit.diff.RawText;
import org.eclipse.jgit.diff.RawTextIgnoreAllWhitespace;
import org.eclipse.jgit.diff.RawTextIgnoreLeadingWhitespace;
import org.eclipse.jgit.diff.RawTextIgnoreTrailingWhitespace;
import org.eclipse.jgit.diff.RawTextIgnoreWhitespaceChange;
-import org.eclipse.jgit.lib.FileMode;
-import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.diff.RenameDetector;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.TextProgressMonitor;
import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler;
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
@Command(common = true, usage = "usage_ShowDiffs")
class Diff extends TextBuiltin {
+ private final DiffFormatter diffFmt = new DiffFormatter( //
+ new BufferedOutputStream(System.out));
+
@Argument(index = 0, metaVar = "metaVar_treeish", required = true)
void tree_0(final AbstractTreeIterator c) {
trees.add(c);
@@ -78,25 +81,101 @@ class Diff extends TextBuiltin {
@Argument(index = 1, metaVar = "metaVar_treeish", required = true)
private final List<AbstractTreeIterator> trees = new ArrayList<AbstractTreeIterator>();
- @Option(name = "--", metaVar = "metaVar_port", multiValued = true, handler = PathTreeFilterHandler.class)
+ @Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = PathTreeFilterHandler.class)
private TreeFilter pathFilter = TreeFilter.ALL;
+ // BEGIN -- Options shared with Log
+ @Option(name = "-p", usage = "usage_showPatch")
+ boolean showPatch;
+
+ @Option(name = "-M", usage = "usage_detectRenames")
+ private boolean detectRenames;
+
+ @Option(name = "-l", usage = "usage_renameLimit")
+ private Integer renameLimit;
+
+ @Option(name = "--name-status", usage = "usage_nameStatus")
+ private boolean showNameAndStatusOnly;
+
@Option(name = "--ignore-space-at-eol")
- private boolean ignoreWsTrailing;
+ void ignoreSpaceAtEol(@SuppressWarnings("unused") boolean on) {
+ diffFmt.setRawTextFactory(RawTextIgnoreTrailingWhitespace.FACTORY);
+ }
@Option(name = "--ignore-leading-space")
- private boolean ignoreWsLeading;
+ void ignoreLeadingSpace(@SuppressWarnings("unused") boolean on) {
+ diffFmt.setRawTextFactory(RawTextIgnoreLeadingWhitespace.FACTORY);
+ }
@Option(name = "-b", aliases = { "--ignore-space-change" })
- private boolean ignoreWsChange;
+ void ignoreSpaceChange(@SuppressWarnings("unused") boolean on) {
+ diffFmt.setRawTextFactory(RawTextIgnoreWhitespaceChange.FACTORY);
+ }
@Option(name = "-w", aliases = { "--ignore-all-space" })
- private boolean ignoreWsAll;
+ void ignoreAllSpace(@SuppressWarnings("unused") boolean on) {
+ diffFmt.setRawTextFactory(RawTextIgnoreAllWhitespace.FACTORY);
+ }
+
+ @Option(name = "-U", aliases = { "--unified" }, metaVar = "metaVar_linesOfContext")
+ void unified(int lines) {
+ diffFmt.setContext(lines);
+ }
+
+ @Option(name = "--abbrev", metaVar = "n")
+ void abbrev(int lines) {
+ diffFmt.setAbbreviationLength(lines);
+ }
- private DiffFormatter fmt = new DiffFormatter();
+ @Option(name = "--full-index")
+ void abbrev(@SuppressWarnings("unused") boolean on) {
+ diffFmt.setAbbreviationLength(Constants.OBJECT_ID_STRING_LENGTH);
+ }
+
+ // END -- Options shared with Log
@Override
protected void run() throws Exception {
+ List<DiffEntry> files = scan();
+
+ if (showNameAndStatusOnly) {
+ nameStatus(out, files);
+ out.flush();
+
+ } else {
+ diffFmt.setRepository(db);
+ diffFmt.format(files);
+ diffFmt.flush();
+ }
+ }
+
+ static void nameStatus(PrintWriter out, List<DiffEntry> files) {
+ for (DiffEntry ent : files) {
+ switch (ent.getChangeType()) {
+ case ADD:
+ out.println("A\t" + ent.getNewName());
+ break;
+ case DELETE:
+ out.println("D\t" + ent.getOldName());
+ break;
+ case MODIFY:
+ out.println("M\t" + ent.getNewName());
+ break;
+ case COPY:
+ out.format("C%1$03d\t%2$s\t%3$s", ent.getScore(), //
+ ent.getOldName(), ent.getNewName());
+ out.println();
+ break;
+ case RENAME:
+ out.format("R%1$03d\t%2$s\t%3$s", ent.getScore(), //
+ ent.getOldName(), ent.getNewName());
+ out.println();
+ break;
+ }
+ }
+ }
+
+ private List<DiffEntry> scan() throws IOException {
final TreeWalk walk = new TreeWalk(db);
walk.reset();
walk.setRecursive(true);
@@ -104,65 +183,14 @@ class Diff extends TextBuiltin {
walk.addTree(i);
walk.setFilter(AndTreeFilter.create(TreeFilter.ANY_DIFF, pathFilter));
- while (walk.next())
- outputDiff(System.out, walk.getPathString(),
- walk.getObjectId(0), walk.getFileMode(0),
- walk.getObjectId(1), walk.getFileMode(1));
- }
-
- protected void outputDiff(PrintStream out, String path,
- ObjectId id1, FileMode mode1, ObjectId id2, FileMode mode2) throws IOException {
- String name1 = "a/" + path;
- String name2 = "b/" + path;
- out.println("diff --git " + name1 + " " + name2);
- boolean isNew=false;
- boolean isDelete=false;
- if (id1.equals(ObjectId.zeroId())) {
- out.println("new file mode " + mode2);
- isNew=true;
- } else if (id2.equals(ObjectId.zeroId())) {
- out.println("deleted file mode " + mode1);
- isDelete=true;
- } else if (!mode1.equals(mode2)) {
- out.println("old mode " + mode1);
- out.println("new mode " + mode2);
+ List<DiffEntry> files = DiffEntry.scan(walk);
+ if (detectRenames) {
+ RenameDetector rd = new RenameDetector(db);
+ if (renameLimit != null)
+ rd.setRenameLimit(renameLimit.intValue());
+ rd.addAll(files);
+ files = rd.compute(new TextProgressMonitor());
}
- out.println("index " + id1.abbreviate(db, 7).name()
- + ".." + id2.abbreviate(db, 7).name()
- + (mode1.equals(mode2) ? " " + mode1 : ""));
- out.println("--- " + (isNew ? "/dev/null" : name1));
- out.println("+++ " + (isDelete ? "/dev/null" : name2));
-
- byte[] aRaw = getRawBytes(id1);
- byte[] bRaw = getRawBytes(id2);
-
- if (RawText.isBinary(aRaw) || RawText.isBinary(bRaw)) {
- out.println("Binary files differ");
- return;
- }
-
- RawText a = getRawText(aRaw);
- RawText b = getRawText(bRaw);
- MyersDiff diff = new MyersDiff(a, b);
- fmt.formatEdits(out, a, b, diff.getEdits());
- }
-
- private byte[] getRawBytes(ObjectId id) throws IOException {
- if (id.equals(ObjectId.zeroId()))
- return new byte[] {};
- return db.openBlob(id).getCachedBytes();
- }
-
- private RawText getRawText(byte[] raw) {
- if (ignoreWsAll)
- return new RawTextIgnoreAllWhitespace(raw);
- else if (ignoreWsTrailing)
- return new RawTextIgnoreTrailingWhitespace(raw);
- else if (ignoreWsChange)
- return new RawTextIgnoreWhitespaceChange(raw);
- else if (ignoreWsLeading)
- return new RawTextIgnoreLeadingWhitespace(raw);
- else
- return new RawText(raw);
+ return files;
}
}
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 9aa197e4ab..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
@@ -45,22 +45,39 @@
package org.eclipse.jgit.pgm;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
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;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
-import org.kohsuke.args4j.Option;
+import org.eclipse.jgit.diff.DiffEntry;
+import org.eclipse.jgit.diff.DiffFormatter;
+import org.eclipse.jgit.diff.RawTextIgnoreAllWhitespace;
+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.revwalk.FollowFilter;
import org.eclipse.jgit.revwalk.RevCommit;
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.TreeFilter;
+import org.kohsuke.args4j.Option;
@Command(common = true, usage = "usage_viewCommitHistory")
class Log extends RevWalkTextBuiltin {
@@ -68,11 +85,64 @@ class Log extends RevWalkTextBuiltin {
private final DateFormat fmt;
+ private final DiffFormatter diffFmt = new DiffFormatter( //
+ new BufferedOutputStream(System.out));
+
private Map<AnyObjectId, Set<Ref>> allRefsByPeeledObjectId;
@Option(name="--decorate", usage="usage_showRefNamesMatchingCommits")
private boolean decorate;
+ // BEGIN -- Options shared with Diff
+ @Option(name = "-p", usage = "usage_showPatch")
+ boolean showPatch;
+
+ @Option(name = "-M", usage = "usage_detectRenames")
+ private boolean detectRenames;
+
+ @Option(name = "-l", usage = "usage_renameLimit")
+ private Integer renameLimit;
+
+ @Option(name = "--name-status", usage = "usage_nameStatus")
+ private boolean showNameAndStatusOnly;
+
+ @Option(name = "--ignore-space-at-eol")
+ void ignoreSpaceAtEol(@SuppressWarnings("unused") boolean on) {
+ diffFmt.setRawTextFactory(RawTextIgnoreTrailingWhitespace.FACTORY);
+ }
+
+ @Option(name = "--ignore-leading-space")
+ void ignoreLeadingSpace(@SuppressWarnings("unused") boolean on) {
+ diffFmt.setRawTextFactory(RawTextIgnoreLeadingWhitespace.FACTORY);
+ }
+
+ @Option(name = "-b", aliases = { "--ignore-space-change" })
+ void ignoreSpaceChange(@SuppressWarnings("unused") boolean on) {
+ diffFmt.setRawTextFactory(RawTextIgnoreWhitespaceChange.FACTORY);
+ }
+
+ @Option(name = "-w", aliases = { "--ignore-all-space" })
+ void ignoreAllSpace(@SuppressWarnings("unused") boolean on) {
+ diffFmt.setRawTextFactory(RawTextIgnoreAllWhitespace.FACTORY);
+ }
+
+ @Option(name = "-U", aliases = { "--unified" }, metaVar = "metaVar_linesOfContext")
+ void unified(int lines) {
+ diffFmt.setContext(lines);
+ }
+
+ @Option(name = "--abbrev", metaVar = "metaVar_n")
+ void abbrev(int lines) {
+ diffFmt.setAbbreviationLength(lines);
+ }
+
+ @Option(name = "--full-index")
+ void abbrev(@SuppressWarnings("unused") boolean on) {
+ diffFmt.setAbbreviationLength(Constants.OBJECT_ID_STRING_LENGTH);
+ }
+
+ // END -- Options shared with Diff
+
Log() {
fmt = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZZZZ", Locale.US);
}
@@ -120,6 +190,77 @@ class Log extends RevWalkTextBuiltin {
}
out.println();
+ if (c.getParentCount() == 1 && (showNameAndStatusOnly || showPatch))
+ showDiff(c);
out.flush();
}
+
+ private void showDiff(RevCommit c) throws IOException {
+ final TreeWalk tw = new TreeWalk(db);
+ tw.setRecursive(true);
+ tw.reset();
+ tw.addTree(c.getParent(0).getTree());
+ tw.addTree(c.getTree());
+ tw.setFilter(AndTreeFilter.create(pathFilter, TreeFilter.ANY_DIFF));
+
+ List<DiffEntry> files = DiffEntry.scan(tw);
+ 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);
+
+ } else {
+ diffFmt.setRepository(db);
+ diffFmt.format(files);
+ diffFmt.flush();
+ }
+ 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 ea6eeb102c..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,11 +111,16 @@ 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>();
@Option(name = "--", metaVar = "metaVar_path", multiValued = true, handler = PathTreeFilterHandler.class)
- private TreeFilter pathFilter = TreeFilter.ALL;
+ protected TreeFilter pathFilter = TreeFilter.ALL;
private final List<RevFilter> revLimiter = new ArrayList<RevFilter>();
@@ -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));