aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java160
5 files changed, 300 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>();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
index c40d3b7000..b08d1cb502 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
@@ -44,6 +44,7 @@
package org.eclipse.jgit.diff;
+import static org.eclipse.jgit.lib.Constants.encode;
import static org.eclipse.jgit.lib.Constants.encodeASCII;
import java.io.IOException;
@@ -51,7 +52,13 @@ import java.io.OutputStream;
import java.util.List;
import org.eclipse.jgit.JGitText;
+import org.eclipse.jgit.lib.AbbreviatedObjectId;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.patch.FileHeader;
+import org.eclipse.jgit.util.QuotedString;
/**
* Format an {@link EditList} as a Git style unified patch script.
@@ -81,6 +88,159 @@ public class DiffFormatter {
}
/**
+ * Format a patch script from a list of difference entries.
+ *
+ * @param out
+ * stream to write the patch script out to.
+ * @param src
+ * repository the file contents can be read from.
+ * @param entries
+ * entries describing the affected files.
+ * @throws IOException
+ * a file's content cannot be read, or the output stream cannot
+ * be written to.
+ */
+ public void format(final OutputStream out, Repository src,
+ List<? extends DiffEntry> entries) throws IOException {
+ for(DiffEntry ent : entries) {
+ if (ent instanceof FileHeader) {
+ format(
+ out,
+ (FileHeader) ent, //
+ newRawText(open(src, ent.getOldMode(), ent.getOldId())),
+ newRawText(open(src, ent.getNewMode(), ent.getNewId())));
+ } else {
+ format(out, src, ent);
+ }
+ }
+ }
+
+ private void format(OutputStream out, Repository src, DiffEntry ent)
+ throws IOException {
+ String oldName = quotePath("a/" + ent.getOldName());
+ String newName = quotePath("b/" + ent.getNewName());
+ out.write(encode("diff --git " + oldName + " " + newName + "\n"));
+
+ switch(ent.getChangeType()) {
+ case ADD:
+ out.write(encodeASCII("new file mode "));
+ ent.getNewMode().copyTo(out);
+ out.write('\n');
+ break;
+
+ case DELETE:
+ out.write(encodeASCII("deleted file mode "));
+ ent.getOldMode().copyTo(out);
+ out.write('\n');
+ break;
+
+ case RENAME:
+ out.write(encode("similarity index " + ent.getScore() + "%"));
+ out.write('\n');
+
+ out.write(encode("rename from " + quotePath(ent.getOldName())));
+ out.write('\n');
+
+ out.write(encode("rename to " + quotePath(ent.getNewName())));
+ out.write('\n');
+ break;
+
+ case COPY:
+ out.write(encode("similarity index " + ent.getScore() + "%"));
+ out.write('\n');
+
+ out.write(encode("copy from " + quotePath(ent.getOldName())));
+ out.write('\n');
+
+ out.write(encode("copy to " + quotePath(ent.getNewName())));
+ out.write('\n');
+
+ if (!ent.getOldMode().equals(ent.getNewMode())) {
+ out.write(encodeASCII("new file mode "));
+ ent.getNewMode().copyTo(out);
+ out.write('\n');
+ }
+ break;
+ }
+
+ switch (ent.getChangeType()) {
+ case RENAME:
+ case MODIFY:
+ if (!ent.getOldMode().equals(ent.getNewMode())) {
+ out.write(encodeASCII("old mode "));
+ ent.getOldMode().copyTo(out);
+ out.write('\n');
+
+ out.write(encodeASCII("new mode "));
+ ent.getNewMode().copyTo(out);
+ out.write('\n');
+ }
+ }
+
+ out.write(encodeASCII("index " //
+ + format(src, ent.getOldId()) //
+ + ".." //
+ + format(src, ent.getNewId())));
+ if (ent.getOldMode().equals(ent.getNewMode())) {
+ out.write(' ');
+ ent.getNewMode().copyTo(out);
+ }
+ out.write('\n');
+ out.write(encode("--- " + oldName + '\n'));
+ out.write(encode("+++ " + newName + '\n'));
+
+ byte[] aRaw = open(src, ent.getOldMode(), ent.getOldId());
+ byte[] bRaw = open(src, ent.getNewMode(), ent.getNewId());
+
+ if (RawText.isBinary(aRaw) || RawText.isBinary(bRaw)) {
+ out.write(encodeASCII("Binary files differ\n"));
+
+ } else {
+ RawText a = newRawText(aRaw);
+ RawText b = newRawText(bRaw);
+ formatEdits(out, a, b, new MyersDiff(a, b).getEdits());
+ }
+ }
+
+ /**
+ * Construct a RawText sequence for use with {@link MyersDiff}.
+ *
+ * @param content
+ * text to be compared.
+ * @return the raw text instance to handle the content.
+ */
+ protected RawText newRawText(byte[] content) {
+ return new RawText(content);
+ }
+
+ private String format(Repository db, AbbreviatedObjectId oldId) {
+ if (oldId.isComplete())
+ oldId = oldId.toObjectId().abbreviate(db, 8);
+ return oldId.name();
+ }
+
+ private static String quotePath(String name) {
+ String q = QuotedString.GIT_PATH.quote(name);
+ return ('"' + name + '"').equals(q) ? name : q;
+ }
+
+ private byte[] open(Repository src, FileMode mode, AbbreviatedObjectId id)
+ throws IOException {
+ if (mode == FileMode.MISSING)
+ return new byte[] {};
+
+ if (mode.getObjectType() != Constants.OBJ_BLOB)
+ return new byte[] {};
+
+ if (id.isComplete()) {
+ ObjectLoader ldr = src.openObject(id.toObjectId());
+ return ldr.getCachedBytes();
+ }
+
+ return new byte[] {};
+ }
+
+ /**
* Format a patch script, reusing a previously parsed FileHeader.
* <p>
* This formatter is primarily useful for editing an existing patch script