diff options
author | Shawn O. Pearce <spearce@spearce.org> | 2010-07-03 15:49:07 -0700 |
---|---|---|
committer | Shawn O. Pearce <spearce@spearce.org> | 2010-07-03 16:32:03 -0700 |
commit | 04a9d23b9ad1a49b81d6ffb0e5cf7637ba2c6d27 (patch) | |
tree | 9066e85b55d10d4b52aada1063b5fdd5069c24f2 /org.eclipse.jgit.pgm | |
parent | 978535b09080edcc01302e80b37b9e1263c21db3 (diff) | |
download | jgit-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')
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>(); |