PageRenderTime 57ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/jgit-flow-core/src/main/java/com/atlassian/jgitflow/core/util/GitHelper.java

https://bitbucket.org/ronsmits/jgit-flow
Java | 397 lines | 273 code | 46 blank | 78 comment | 30 complexity | f94d19488a31be1097d535707387d23a MD5 | raw file
  1. package com.atlassian.jgitflow.core.util;
  2. import java.io.IOException;
  3. import java.util.ArrayList;
  4. import java.util.Arrays;
  5. import java.util.List;
  6. import java.util.Map;
  7. import com.atlassian.jgitflow.core.JGitFlowConstants;
  8. import com.atlassian.jgitflow.core.exception.JGitFlowGitAPIException;
  9. import com.atlassian.jgitflow.core.exception.JGitFlowIOException;
  10. import com.atlassian.jgitflow.core.exception.LocalBranchMissingException;
  11. import org.eclipse.jgit.api.Git;
  12. import org.eclipse.jgit.api.ListBranchCommand;
  13. import org.eclipse.jgit.api.errors.GitAPIException;
  14. import org.eclipse.jgit.diff.DiffEntry;
  15. import org.eclipse.jgit.lib.*;
  16. import org.eclipse.jgit.revwalk.RevCommit;
  17. import org.eclipse.jgit.revwalk.RevWalk;
  18. import org.eclipse.jgit.treewalk.FileTreeIterator;
  19. import org.eclipse.jgit.util.StringUtils;
  20. /**
  21. * A helper class for common Git operations
  22. */
  23. public class GitHelper
  24. {
  25. /**
  26. * Checks to see if one branch is merged into another
  27. * @param git The git instance to use
  28. * @param branchName The name of the branch we're testing
  29. * @param baseName The name of the base branch to look for the merge
  30. * @return if the contents of branchName has been merged into baseName
  31. * @throws LocalBranchMissingException
  32. * @throws JGitFlowIOException
  33. * @throws JGitFlowGitAPIException
  34. */
  35. public static boolean isMergedInto(Git git, String branchName, String baseName) throws LocalBranchMissingException, JGitFlowIOException, JGitFlowGitAPIException
  36. {
  37. Repository repo = git.getRepository();
  38. RevWalk walk = new RevWalk(repo);
  39. walk.setRetainBody(false);
  40. try
  41. {
  42. ObjectId branch = repo.resolve(branchName);
  43. if (null == branch)
  44. {
  45. throw new LocalBranchMissingException(branchName + " does not exist");
  46. }
  47. RevCommit branchCommit = walk.parseCommit(branch);
  48. return isMergedInto(git, branchCommit, baseName);
  49. }
  50. catch (IOException e)
  51. {
  52. throw new JGitFlowIOException(e);
  53. }
  54. }
  55. /**
  56. * Checks to see if a specific commit is merged into a branch
  57. * @param git The git instance to use
  58. * @param commit The commit to test
  59. * @param branchName The name of the base branch to look for the merge
  60. * @return if the contents of commit has been merged into baseName
  61. * @throws JGitFlowGitAPIException
  62. * @throws JGitFlowIOException
  63. */
  64. public static boolean isMergedInto(Git git, RevCommit commit, String branchName) throws JGitFlowGitAPIException, JGitFlowIOException
  65. {
  66. Repository repo = git.getRepository();
  67. try
  68. {
  69. ObjectId base = repo.resolve(branchName);
  70. if (null == base)
  71. {
  72. return false;
  73. }
  74. Iterable<RevCommit> baseCommits = git.log().add(base).call();
  75. boolean merged = false;
  76. for (RevCommit entry : baseCommits)
  77. {
  78. if (entry.getId().equals(commit))
  79. {
  80. merged = true;
  81. break;
  82. }
  83. if (entry.getParentCount() > 1 && Arrays.asList(entry.getParents()).contains(commit))
  84. {
  85. merged = true;
  86. break;
  87. }
  88. }
  89. return merged;
  90. }
  91. catch (GitAPIException e)
  92. {
  93. throw new JGitFlowGitAPIException(e);
  94. }
  95. catch (IOException e)
  96. {
  97. throw new JGitFlowIOException(e);
  98. }
  99. }
  100. /**
  101. * Gets the latest commit for a branch
  102. * @param git The git instance to use
  103. * @param branchName The name of the branch to find the commit on
  104. * @return The latest commit for the branch
  105. * @throws JGitFlowIOException
  106. */
  107. public static RevCommit getLatestCommit(Git git, String branchName) throws JGitFlowIOException
  108. {
  109. RevWalk walk = null;
  110. try
  111. {
  112. ObjectId branch = git.getRepository().resolve(branchName);
  113. walk = new RevWalk(git.getRepository());
  114. walk.setRetainBody(true);
  115. return walk.parseCommit(branch);
  116. }
  117. catch (IOException e)
  118. {
  119. throw new JGitFlowIOException(e);
  120. }
  121. finally
  122. {
  123. if (null != walk)
  124. {
  125. walk.release();
  126. }
  127. }
  128. }
  129. /**
  130. * Checks to see if a local branch with the given name exists
  131. * @param git The git instance to use
  132. * @param branchName The name of the branch to look for
  133. * @return if the branch exists or not
  134. * @throws JGitFlowGitAPIException
  135. */
  136. public static boolean localBranchExists(Git git, String branchName) throws JGitFlowGitAPIException
  137. {
  138. boolean exists = false;
  139. if (StringUtils.isEmptyOrNull(branchName))
  140. {
  141. return exists;
  142. }
  143. try
  144. {
  145. List<Ref> refs = git.branchList().setListMode(null).call();
  146. for (Ref ref : refs)
  147. {
  148. String simpleName = ref.getName().substring(ref.getName().indexOf(Constants.R_HEADS) + Constants.R_HEADS.length());
  149. if (simpleName.equals(branchName))
  150. {
  151. exists = true;
  152. break;
  153. }
  154. }
  155. return exists;
  156. }
  157. catch (GitAPIException e)
  158. {
  159. throw new JGitFlowGitAPIException(e);
  160. }
  161. }
  162. /**
  163. * Checks to see if a remote branch with the given name exists
  164. * @param git The git instance to use
  165. * @param branch The name of the branch to look for
  166. * @return if the branch exists or not
  167. * @throws JGitFlowGitAPIException
  168. */
  169. public static boolean remoteBranchExists(Git git, final String branch) throws JGitFlowGitAPIException
  170. {
  171. boolean exists = false;
  172. if (StringUtils.isEmptyOrNull(branch))
  173. {
  174. return exists;
  175. }
  176. try
  177. {
  178. List<Ref> refs = git.branchList().setListMode(ListBranchCommand.ListMode.REMOTE).call();
  179. for (Ref ref : refs)
  180. {
  181. String simpleName = ref.getName().substring(ref.getName().indexOf(JGitFlowConstants.R_REMOTE_ORIGIN) + JGitFlowConstants.R_REMOTE_ORIGIN.length());
  182. if (simpleName.equals(branch))
  183. {
  184. exists = true;
  185. break;
  186. }
  187. }
  188. return exists;
  189. }
  190. catch (GitAPIException e)
  191. {
  192. throw new JGitFlowGitAPIException(e);
  193. }
  194. }
  195. /**
  196. * Gets a reference to a remote branch with the given name
  197. * @param git The git instance to use
  198. * @param branchName The name of the remote branch
  199. * @return A reference to the remote branch or null
  200. * @throws JGitFlowIOException
  201. */
  202. public static Ref getRemoteBranch(Git git, String branchName) throws JGitFlowIOException
  203. {
  204. try
  205. {
  206. final Map<String, Ref> refList = git.getRepository().getRefDatabase().getRefs(Constants.R_REMOTES);
  207. Ref remote = null;
  208. for (Map.Entry<String, Ref> entry : refList.entrySet())
  209. {
  210. int index = entry.getValue().getName().indexOf(JGitFlowConstants.R_REMOTE_ORIGIN);
  211. if (index < 0)
  212. {
  213. continue;
  214. }
  215. String simpleName = entry.getValue().getName().substring(index + JGitFlowConstants.R_REMOTE_ORIGIN.length());
  216. if (simpleName.equals(branchName))
  217. {
  218. remote = entry.getValue();
  219. break;
  220. }
  221. }
  222. return remote;
  223. }
  224. catch (IOException e)
  225. {
  226. throw new JGitFlowIOException(e);
  227. }
  228. }
  229. /**
  230. * Gets a reference to a local branch with the given name
  231. * @param git The git instance to use
  232. * @param branchName The name of the remote branch
  233. * @return A reference to the local branch or null
  234. * @throws JGitFlowIOException
  235. */
  236. public static Ref getLocalBranch(Git git, String branchName) throws JGitFlowIOException
  237. {
  238. try
  239. {
  240. Ref ref2check = git.getRepository().getRef(branchName);
  241. Ref local = null;
  242. if (ref2check != null && ref2check.getName().startsWith(Constants.R_HEADS))
  243. {
  244. local = ref2check;
  245. }
  246. return local;
  247. }
  248. catch (IOException e)
  249. {
  250. throw new JGitFlowIOException(e);
  251. }
  252. }
  253. /**
  254. * Gets a list of branch references that begin with the given prefix
  255. * @param git The git instance to use
  256. * @param prefix The prefix to test for
  257. * @return A list of branch references matching the given prefix
  258. * @throws JGitFlowGitAPIException
  259. */
  260. public static List<Ref> listBranchesWithPrefix(Git git, String prefix) throws JGitFlowGitAPIException
  261. {
  262. List<Ref> branches = new ArrayList<Ref>();
  263. try
  264. {
  265. List<Ref> refs = git.branchList().setListMode(null).call();
  266. for (Ref ref : refs)
  267. {
  268. String simpleName = ref.getName().substring(ref.getName().indexOf(Constants.R_HEADS) + Constants.R_HEADS.length());
  269. if (simpleName.startsWith(prefix))
  270. {
  271. branches.add(ref);
  272. }
  273. }
  274. return branches;
  275. }
  276. catch (GitAPIException e)
  277. {
  278. throw new JGitFlowGitAPIException(e);
  279. }
  280. }
  281. /**
  282. * Tests to see if a working folder is clean. e.g. all changes have been committed.
  283. * @param git The git instance to use
  284. * @return if the branch is clean or not
  285. * @throws JGitFlowIOException
  286. * @throws JGitFlowGitAPIException
  287. */
  288. public static boolean workingTreeIsClean(Git git) throws JGitFlowIOException, JGitFlowGitAPIException
  289. {
  290. try
  291. {
  292. List<DiffEntry> branchDiffs = git.diff().call();
  293. if (!branchDiffs.isEmpty())
  294. {
  295. return false;
  296. }
  297. branchDiffs = git.diff().setCached(true).call();
  298. if (!branchDiffs.isEmpty())
  299. {
  300. return false;
  301. }
  302. IndexDiff diffIndex = new IndexDiff(git.getRepository(), Constants.HEAD, new FileTreeIterator(git.getRepository()));
  303. if (diffIndex.diff())
  304. {
  305. return false;
  306. }
  307. return true;
  308. }
  309. catch (GitAPIException e)
  310. {
  311. throw new JGitFlowGitAPIException(e);
  312. }
  313. catch (IOException e)
  314. {
  315. throw new JGitFlowIOException(e);
  316. }
  317. }
  318. /**
  319. * Tests to see if a tag exists with the given name
  320. * @param git The git instance to use
  321. * @param tagName The name of the tag to test for
  322. * @return if the tag exists or not
  323. * @throws JGitFlowGitAPIException
  324. */
  325. public static boolean tagExists(Git git, final String tagName) throws JGitFlowGitAPIException
  326. {
  327. boolean exists = false;
  328. if (StringUtils.isEmptyOrNull(tagName))
  329. {
  330. return exists;
  331. }
  332. try
  333. {
  334. List<Ref> refs = git.tagList().call();
  335. for (Ref ref : refs)
  336. {
  337. String simpleName = ref.getName().substring(ref.getName().indexOf(Constants.R_TAGS) + Constants.R_TAGS.length());
  338. if (simpleName.equals(tagName))
  339. {
  340. exists = true;
  341. break;
  342. }
  343. }
  344. return exists;
  345. }
  346. catch (GitAPIException e)
  347. {
  348. throw new JGitFlowGitAPIException(e);
  349. }
  350. }
  351. }