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.

DeleteBranchCommand.java 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
  3. * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com> and others
  4. *
  5. * This program and the accompanying materials are made available under the
  6. * terms of the Eclipse Distribution License v. 1.0 which is available at
  7. * https://www.eclipse.org/org/documents/edl-v10.php.
  8. *
  9. * SPDX-License-Identifier: BSD-3-Clause
  10. */
  11. package org.eclipse.jgit.api;
  12. import java.io.IOException;
  13. import java.text.MessageFormat;
  14. import java.util.ArrayList;
  15. import java.util.Arrays;
  16. import java.util.HashSet;
  17. import java.util.List;
  18. import java.util.Set;
  19. import org.eclipse.jgit.api.errors.CannotDeleteCurrentBranchException;
  20. import org.eclipse.jgit.api.errors.GitAPIException;
  21. import org.eclipse.jgit.api.errors.JGitInternalException;
  22. import org.eclipse.jgit.api.errors.NotMergedException;
  23. import org.eclipse.jgit.internal.JGitText;
  24. import org.eclipse.jgit.lib.ConfigConstants;
  25. import org.eclipse.jgit.lib.Constants;
  26. import org.eclipse.jgit.lib.Ref;
  27. import org.eclipse.jgit.lib.RefUpdate;
  28. import org.eclipse.jgit.lib.RefUpdate.Result;
  29. import org.eclipse.jgit.lib.Repository;
  30. import org.eclipse.jgit.lib.StoredConfig;
  31. import org.eclipse.jgit.revwalk.RevCommit;
  32. import org.eclipse.jgit.revwalk.RevWalk;
  33. /**
  34. * Used to delete one or several branches.
  35. *
  36. * The result of {@link #call()} is a list with the (full) names of the deleted
  37. * branches.
  38. *
  39. * Note that we don't have a setter corresponding to the -r option; remote
  40. * tracking branches are simply deleted just like local branches.
  41. *
  42. * @see <a
  43. * href="http://www.kernel.org/pub/software/scm/git/docs/git-branch.html"
  44. * >Git documentation about Branch</a>
  45. */
  46. public class DeleteBranchCommand extends GitCommand<List<String>> {
  47. private final Set<String> branchNames = new HashSet<>();
  48. private boolean force;
  49. /**
  50. * Constructor for DeleteBranchCommand
  51. *
  52. * @param repo
  53. * the {@link org.eclipse.jgit.lib.Repository}
  54. */
  55. protected DeleteBranchCommand(Repository repo) {
  56. super(repo);
  57. }
  58. /** {@inheritDoc} */
  59. @Override
  60. public List<String> call() throws GitAPIException,
  61. NotMergedException, CannotDeleteCurrentBranchException {
  62. checkCallable();
  63. List<String> result = new ArrayList<>();
  64. if (branchNames.isEmpty())
  65. return result;
  66. try {
  67. String currentBranch = repo.getFullBranch();
  68. if (!force) {
  69. // check if the branches to be deleted
  70. // are all merged into the current branch
  71. try (RevWalk walk = new RevWalk(repo)) {
  72. RevCommit tip = walk
  73. .parseCommit(repo.resolve(Constants.HEAD));
  74. for (String branchName : branchNames) {
  75. if (branchName == null)
  76. continue;
  77. Ref currentRef = repo.findRef(branchName);
  78. if (currentRef == null)
  79. continue;
  80. RevCommit base = walk
  81. .parseCommit(repo.resolve(branchName));
  82. if (!walk.isMergedInto(base, tip)) {
  83. throw new NotMergedException();
  84. }
  85. }
  86. }
  87. }
  88. setCallable(false);
  89. for (String branchName : branchNames) {
  90. if (branchName == null)
  91. continue;
  92. Ref currentRef = repo.findRef(branchName);
  93. if (currentRef == null)
  94. continue;
  95. String fullName = currentRef.getName();
  96. if (fullName.equals(currentBranch))
  97. throw new CannotDeleteCurrentBranchException(
  98. MessageFormat
  99. .format(
  100. JGitText.get().cannotDeleteCheckedOutBranch,
  101. branchName));
  102. RefUpdate update = repo.updateRef(fullName);
  103. update.setRefLogMessage("branch deleted", false); //$NON-NLS-1$
  104. update.setForceUpdate(true);
  105. Result deleteResult = update.delete();
  106. boolean ok = true;
  107. switch (deleteResult) {
  108. case IO_FAILURE:
  109. case LOCK_FAILURE:
  110. case REJECTED:
  111. ok = false;
  112. break;
  113. default:
  114. break;
  115. }
  116. if (ok) {
  117. result.add(fullName);
  118. if (fullName.startsWith(Constants.R_HEADS)) {
  119. String shortenedName = fullName
  120. .substring(Constants.R_HEADS.length());
  121. // remove upstream configuration if any
  122. final StoredConfig cfg = repo.getConfig();
  123. cfg.unsetSection(
  124. ConfigConstants.CONFIG_BRANCH_SECTION,
  125. shortenedName);
  126. cfg.save();
  127. }
  128. } else
  129. throw new JGitInternalException(MessageFormat.format(
  130. JGitText.get().deleteBranchUnexpectedResult,
  131. deleteResult.name()));
  132. }
  133. return result;
  134. } catch (IOException ioe) {
  135. throw new JGitInternalException(ioe.getMessage(), ioe);
  136. }
  137. }
  138. /**
  139. * Set the names of the branches to delete
  140. *
  141. * @param branchnames
  142. * the names of the branches to delete; if not set, this will do
  143. * nothing; invalid branch names will simply be ignored
  144. * @return this instance
  145. */
  146. public DeleteBranchCommand setBranchNames(String... branchnames) {
  147. checkCallable();
  148. this.branchNames.clear();
  149. this.branchNames.addAll(Arrays.asList(branchnames));
  150. return this;
  151. }
  152. /**
  153. * Set whether to forcefully delete branches
  154. *
  155. * @param force
  156. * <code>true</code> corresponds to the -D option,
  157. * <code>false</code> to the -d option (default) <br>
  158. * if <code>false</code> a check will be performed whether the
  159. * branch to be deleted is already merged into the current branch
  160. * and deletion will be refused in this case
  161. * @return this instance
  162. */
  163. public DeleteBranchCommand setForce(boolean force) {
  164. checkCallable();
  165. this.force = force;
  166. return this;
  167. }
  168. }