summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.pgm
diff options
context:
space:
mode:
authorShawn O. Pearce <spearce@spearce.org>2010-07-03 15:49:07 -0700
committerShawn O. Pearce <spearce@spearce.org>2010-07-03 16:32:03 -0700
commit04a9d23b9ad1a49b81d6ffb0e5cf7637ba2c6d27 (patch)
tree9066e85b55d10d4b52aada1063b5fdd5069c24f2 /org.eclipse.jgit.pgm
parent978535b09080edcc01302e80b37b9e1263c21db3 (diff)
downloadjgit-04a9d23b9ad1a49b81d6ffb0e5cf7637ba2c6d27.tar.gz
jgit-04a9d23b9ad1a49b81d6ffb0e5cf7637ba2c6d27.zip
log, diff: Add rename detection support
Implement rename detection in the command line diff and log commands. Also support --name-status, -p and -U flags, as these can be quite useful to view more detail. All of the Git patch file formatting code is now moved over to the DiffFormatter class. This permits us to reuse it in any context, including inside of IDEs. Change-Id: I687ccba34e18105a07e0a439d2181c323209d96c Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Diffstat (limited to 'org.eclipse.jgit.pgm')
-rw-r--r--org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties4
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java148
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java56
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java2
4 files changed, 140 insertions, 70 deletions
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties
index d13c47d297..67357be1da 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties
@@ -66,6 +66,7 @@ metaVar_directory=DIRECTORY
metaVar_file=FILE
metaVar_gitDir=GIT_DIR
metaVar_hostName=HOSTNAME
+metaVar_linesOfContext=lines
metaVar_message=message
metaVar_name=name
metaVar_object=object
@@ -139,6 +140,7 @@ usage_cloneRepositoryIntoNewDir=Clone a repository into a new directory
usage_configureTheServiceInDaemonServicename=configure the service in daemon.servicename
usage_deleteBranchEvenIfNotMerged=delete branch (even if not merged)
usage_deleteFullyMergedBranch=delete fully merged branch
+usage_detectRenames=detect renamed files
usage_directoriesToExport=directories to export
usage_disableTheServiceInAllRepositories=disable the service in all repositories
usage_displayAListOfAllRegisteredJgitCommands=Display a list of all registered jgit commands
@@ -160,6 +162,7 @@ usage_listBothRemoteTrackingAndLocalBranches=list both remote-tracking and local
usage_listCreateOrDeleteBranches=List, create, or delete branches
usage_logAllPretty=format:%H %ct %P' output=log --all '--pretty=format:%H %ct %P' output
usage_moveRenameABranch=move/rename a branch
+usage_nameStatus=show only name and status of files
usage_outputFile=Output file
usage_path=path
usage_performFsckStyleChecksOnReceive=perform fsck style checks on receive
@@ -170,6 +173,7 @@ usage_recurseIntoSubtrees=recurse into subtrees
usage_recordChangesToRepository=Record changes to the repository
usage_setTheGitRepositoryToOperateOn=set the git repository to operate on
usage_showRefNamesMatchingCommits=Show ref names matching commits
+usage_showPatch=display patch
usage_symbolicVersionForTheProject=Symbolic version for the project
usage_synchronizeIPZillaData=Synchronize IPZilla data
usage_tagMessage=tag message
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..a3fca638b5 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,28 +45,28 @@
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.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 {
@@ -78,9 +78,15 @@ 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;
+ @Option(name = "-M", usage = "usage_detectRenames")
+ private boolean detectRenames;
+
+ @Option(name = "--name-status", usage = "usage_nameStatus")
+ private boolean showNameAndStatusOnly;
+
@Option(name = "--ignore-space-at-eol")
private boolean ignoreWsTrailing;
@@ -93,10 +99,69 @@ class Diff extends TextBuiltin {
@Option(name = "-w", aliases = { "--ignore-all-space" })
private boolean ignoreWsAll;
- private DiffFormatter fmt = new DiffFormatter();
+ @Option(name = "-U", aliases = { "--unified" }, metaVar = "metaVar_linesOfContext")
+ void unified(int lines) {
+ fmt.setContext(lines);
+ }
+
+ private DiffFormatter fmt = new DiffFormatter() {
+ @Override
+ protected RawText newRawText(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);
+ }
+ };
@Override
protected void run() throws Exception {
+ List<DiffEntry> files = scan();
+
+ if (showNameAndStatusOnly) {
+ nameStatus(out, files);
+ out.flush();
+
+ } else {
+ BufferedOutputStream o = new BufferedOutputStream(System.out);
+ fmt.format(o, db, files);
+ o.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 +169,12 @@ 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);
+ 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..511da44984 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,32 @@
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.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.RenameDetector;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.TextProgressMonitor;
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 {
@@ -73,6 +83,22 @@ class Log extends RevWalkTextBuiltin {
@Option(name="--decorate", usage="usage_showRefNamesMatchingCommits")
private boolean decorate;
+ @Option(name = "-M", usage = "usage_detectRenames")
+ private boolean detectRenames;
+
+ @Option(name = "--name-status", usage = "usage_nameStatus")
+ private boolean showNameAndStatusOnly;
+
+ @Option(name = "-p", usage = "usage_showPatch")
+ private boolean showPatch;
+
+ @Option(name = "-U", aliases = { "--unified" }, metaVar = "metaVar_linesOfContext")
+ void unified(int lines) {
+ diffFmt.setContext(lines);
+ }
+
+ private DiffFormatter diffFmt = new DiffFormatter();
+
Log() {
fmt = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZZZZ", Locale.US);
}
@@ -120,6 +146,34 @@ class Log extends RevWalkTextBuiltin {
}
out.println();
+ if (c.getParentCount() > 0 && (showNameAndStatusOnly || showPatch))
+ showDiff(c);
out.flush();
}
+
+ private void showDiff(RevCommit c) throws IOException {
+ final TreeWalk tw = new TreeWalk(db);
+ tw.reset();
+ tw.setRecursive(true);
+ tw.addTree(c.getParent(0).getTree());
+ tw.addTree(c.getTree());
+ tw.setFilter(AndTreeFilter.create(TreeFilter.ANY_DIFF, pathFilter));
+
+ List<DiffEntry> files = DiffEntry.scan(tw);
+ if (detectRenames) {
+ RenameDetector rd = new RenameDetector(db);
+ rd.addAll(files);
+ files = rd.compute(new TextProgressMonitor());
+ }
+
+ if (showNameAndStatusOnly) {
+ Diff.nameStatus(out, files);
+
+ } else {
+ out.flush();
+ BufferedOutputStream o = new BufferedOutputStream(System.out);
+ diffFmt.format(o, db, files);
+ o.flush();
+ }
+ }
}
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..beb961d99c 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
@@ -114,7 +114,7 @@ abstract class RevWalkTextBuiltin extends TextBuiltin {
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>();