You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DiffCommand.java 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /*
  2. * Copyright (C) 2011, Tomasz Zarna <Tomasz.Zarna@pl.ibm.com> and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.api;
  11. import static org.eclipse.jgit.lib.Constants.HEAD;
  12. import java.io.BufferedOutputStream;
  13. import java.io.IOException;
  14. import java.io.OutputStream;
  15. import java.util.List;
  16. import org.eclipse.jgit.api.errors.GitAPIException;
  17. import org.eclipse.jgit.api.errors.JGitInternalException;
  18. import org.eclipse.jgit.api.errors.NoHeadException;
  19. import org.eclipse.jgit.diff.DiffEntry;
  20. import org.eclipse.jgit.diff.DiffFormatter;
  21. import org.eclipse.jgit.dircache.DirCacheIterator;
  22. import org.eclipse.jgit.internal.JGitText;
  23. import org.eclipse.jgit.lib.NullProgressMonitor;
  24. import org.eclipse.jgit.lib.ObjectId;
  25. import org.eclipse.jgit.lib.ObjectReader;
  26. import org.eclipse.jgit.lib.ProgressMonitor;
  27. import org.eclipse.jgit.lib.Repository;
  28. import org.eclipse.jgit.treewalk.AbstractTreeIterator;
  29. import org.eclipse.jgit.treewalk.CanonicalTreeParser;
  30. import org.eclipse.jgit.treewalk.FileTreeIterator;
  31. import org.eclipse.jgit.treewalk.filter.TreeFilter;
  32. import org.eclipse.jgit.util.io.NullOutputStream;
  33. /**
  34. * Show changes between commits, commit and working tree, etc.
  35. *
  36. * @see <a href="http://www.kernel.org/pub/software/scm/git/docs/git-diff.html"
  37. * >Git documentation about diff</a>
  38. */
  39. public class DiffCommand extends GitCommand<List<DiffEntry>> {
  40. private AbstractTreeIterator oldTree;
  41. private AbstractTreeIterator newTree;
  42. private boolean cached;
  43. private TreeFilter pathFilter = TreeFilter.ALL;
  44. private boolean showNameAndStatusOnly;
  45. private OutputStream out;
  46. private int contextLines = -1;
  47. private String sourcePrefix;
  48. private String destinationPrefix;
  49. private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
  50. /**
  51. * Constructor for DiffCommand
  52. *
  53. * @param repo
  54. * a {@link org.eclipse.jgit.lib.Repository} object.
  55. */
  56. protected DiffCommand(Repository repo) {
  57. super(repo);
  58. }
  59. private DiffFormatter getDiffFormatter() {
  60. return out != null && !showNameAndStatusOnly
  61. ? new DiffFormatter(new BufferedOutputStream(out))
  62. : new DiffFormatter(NullOutputStream.INSTANCE);
  63. }
  64. /**
  65. * {@inheritDoc}
  66. * <p>
  67. * Executes the {@code Diff} command with all the options and parameters
  68. * collected by the setter methods (e.g. {@link #setCached(boolean)} of this
  69. * class. Each instance of this class should only be used for one invocation
  70. * of the command. Don't call this method twice on an instance.
  71. */
  72. @Override
  73. public List<DiffEntry> call() throws GitAPIException {
  74. try (DiffFormatter diffFmt = getDiffFormatter()) {
  75. diffFmt.setRepository(repo);
  76. diffFmt.setProgressMonitor(monitor);
  77. if (cached) {
  78. if (oldTree == null) {
  79. ObjectId head = repo.resolve(HEAD + "^{tree}"); //$NON-NLS-1$
  80. if (head == null)
  81. throw new NoHeadException(JGitText.get().cannotReadTree);
  82. CanonicalTreeParser p = new CanonicalTreeParser();
  83. try (ObjectReader reader = repo.newObjectReader()) {
  84. p.reset(reader, head);
  85. }
  86. oldTree = p;
  87. }
  88. newTree = new DirCacheIterator(repo.readDirCache());
  89. } else {
  90. if (oldTree == null) {
  91. oldTree = new DirCacheIterator(repo.readDirCache());
  92. }
  93. if (newTree == null) {
  94. newTree = new FileTreeIterator(repo);
  95. }
  96. }
  97. diffFmt.setPathFilter(pathFilter);
  98. List<DiffEntry> result = diffFmt.scan(oldTree, newTree);
  99. if (showNameAndStatusOnly) {
  100. return result;
  101. }
  102. if (contextLines >= 0) {
  103. diffFmt.setContext(contextLines);
  104. }
  105. if (destinationPrefix != null) {
  106. diffFmt.setNewPrefix(destinationPrefix);
  107. }
  108. if (sourcePrefix != null) {
  109. diffFmt.setOldPrefix(sourcePrefix);
  110. }
  111. diffFmt.format(result);
  112. diffFmt.flush();
  113. return result;
  114. } catch (IOException e) {
  115. throw new JGitInternalException(e.getMessage(), e);
  116. }
  117. }
  118. /**
  119. * Whether to view the changes staged for the next commit
  120. *
  121. * @param cached
  122. * whether to view the changes staged for the next commit
  123. * @return this instance
  124. */
  125. public DiffCommand setCached(boolean cached) {
  126. this.cached = cached;
  127. return this;
  128. }
  129. /**
  130. * Set path filter
  131. *
  132. * @param pathFilter
  133. * parameter, used to limit the diff to the named path
  134. * @return this instance
  135. */
  136. public DiffCommand setPathFilter(TreeFilter pathFilter) {
  137. this.pathFilter = pathFilter;
  138. return this;
  139. }
  140. /**
  141. * Set old tree
  142. *
  143. * @param oldTree
  144. * the previous state
  145. * @return this instance
  146. */
  147. public DiffCommand setOldTree(AbstractTreeIterator oldTree) {
  148. this.oldTree = oldTree;
  149. return this;
  150. }
  151. /**
  152. * Set new tree
  153. *
  154. * @param newTree
  155. * the updated state
  156. * @return this instance
  157. */
  158. public DiffCommand setNewTree(AbstractTreeIterator newTree) {
  159. this.newTree = newTree;
  160. return this;
  161. }
  162. /**
  163. * Set whether to return only names and status of changed files
  164. *
  165. * @param showNameAndStatusOnly
  166. * whether to return only names and status of changed files
  167. * @return this instance
  168. */
  169. public DiffCommand setShowNameAndStatusOnly(boolean showNameAndStatusOnly) {
  170. this.showNameAndStatusOnly = showNameAndStatusOnly;
  171. return this;
  172. }
  173. /**
  174. * Set output stream
  175. *
  176. * @param out
  177. * the stream to write line data
  178. * @return this instance
  179. */
  180. public DiffCommand setOutputStream(OutputStream out) {
  181. this.out = out;
  182. return this;
  183. }
  184. /**
  185. * Set number of context lines instead of the usual three.
  186. *
  187. * @param contextLines
  188. * the number of context lines
  189. * @return this instance
  190. */
  191. public DiffCommand setContextLines(int contextLines) {
  192. this.contextLines = contextLines;
  193. return this;
  194. }
  195. /**
  196. * Set the given source prefix instead of "a/".
  197. *
  198. * @param sourcePrefix
  199. * the prefix
  200. * @return this instance
  201. */
  202. public DiffCommand setSourcePrefix(String sourcePrefix) {
  203. this.sourcePrefix = sourcePrefix;
  204. return this;
  205. }
  206. /**
  207. * Set the given destination prefix instead of "b/".
  208. *
  209. * @param destinationPrefix
  210. * the prefix
  211. * @return this instance
  212. */
  213. public DiffCommand setDestinationPrefix(String destinationPrefix) {
  214. this.destinationPrefix = destinationPrefix;
  215. return this;
  216. }
  217. /**
  218. * The progress monitor associated with the diff operation. By default, this
  219. * is set to <code>NullProgressMonitor</code>
  220. *
  221. * @see NullProgressMonitor
  222. * @param monitor
  223. * a progress monitor
  224. * @return this instance
  225. */
  226. public DiffCommand setProgressMonitor(ProgressMonitor monitor) {
  227. if (monitor == null) {
  228. monitor = NullProgressMonitor.INSTANCE;
  229. }
  230. this.monitor = monitor;
  231. return this;
  232. }
  233. }