/* Copyright (c) 2013-2014 Boundless and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Distribution License v1.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/edl-v10.html * * Contributors: * Johnathan Garrett (LMN Solutions) - initial implementation */ package org.locationtech.geogig.api.porcelain; import static com.google.common.base.Preconditions.checkState; import org.locationtech.geogig.api.AbstractGeoGigOp; import org.locationtech.geogig.api.Ref; import org.locationtech.geogig.api.SymRef; import org.locationtech.geogig.api.plumbing.RefParse; import org.locationtech.geogig.api.plumbing.UpdateRef; import org.locationtech.geogig.api.plumbing.UpdateSymRef; import com.google.common.base.Optional; /** * Renames a branch by updating its reference * <p> * If trying to rename the current branch you can not give an oldBranchName and it will rename the * current branch to the given newBranchName. If you are trying to rename a branch to a name that is * already a branch name you cannot rename it, unless the {@link #setForce(boolean) force} is set to * {@code true} in which case it deletes the branch that exists with that name already and renames * the other branch to that name. * */ public class BranchRenameOp extends AbstractGeoGigOp<Ref> { private boolean force; private String newBranchName; private String oldBranchName; /** * @param force whether to force the renaming of a branch to a branch name that already exists * @return {@code this} */ public BranchRenameOp setForce(boolean force) { this.force = force; return this; } /** * @param oldBranchName the name of the branch that you want to change, if null it uses the * current branch, if not null must resolve to a branch reference * @return {@code this} */ public BranchRenameOp setOldName(String oldBranchName) { this.oldBranchName = oldBranchName; return this; } /** * @param newBranchName the new name that you want to assign to the branch * @return {@code this} */ public BranchRenameOp setNewName(String newBranchName) { this.newBranchName = newBranchName; return this; } /** * @return The newly renamed branch * @throws IllegalStateException if newBranchName and oldBranchName are the same or if you try * to rename a branch with a name that already exists and you don't use force * @throws IllegalArgumentException if newBranchName is not specified or if the oldBranchName * specified doesn't exist or if oldBranchName doesn't resolve to a branch */ @Override protected Ref _call() { checkState(newBranchName != null, "New branch name not specified"); checkState(!newBranchName.equals(oldBranchName), "Done"); Optional<Ref> branch = Optional.absent(); boolean headBranch = false; if (oldBranchName == null) { Optional<Ref> headRef = command(RefParse.class).setName(Ref.HEAD).call(); checkState(headRef.isPresent() && headRef.get() instanceof SymRef, "Cannot rename detached HEAD."); branch = command(RefParse.class).setName(((SymRef) (headRef.get())).getTarget()).call(); headBranch = true; } else { branch = command(RefParse.class).setName(oldBranchName).call(); } checkState(branch.isPresent(), "The branch could not be resolved."); Optional<Ref> newBranch = command(RefParse.class).setName(newBranchName).call(); if (!force) { checkState( !newBranch.isPresent(), "Cannot rename branch to '" + newBranchName + "' because a branch by that name already exists. Use force option to override this."); } Optional<Ref> renamedBranch = command(UpdateRef.class) .setName(branch.get().namespace() + newBranchName) .setNewValue(branch.get().getObjectId()).call(); command(UpdateRef.class).setName(branch.get().getName()).setDelete(true).call(); if (headBranch) { command(UpdateSymRef.class).setName(Ref.HEAD) .setNewValue(renamedBranch.get().getName()).call(); } return renamedBranch.get(); } }