/* Copyright (c) 2012-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: * Gabriel Roldan (Boundless) - initial implementation */ package org.locationtech.geogig.cli.porcelain; import java.io.IOException; import java.util.List; import jline.console.ConsoleReader; import org.locationtech.geogig.api.GeoGIG; import org.locationtech.geogig.api.porcelain.CheckoutException; import org.locationtech.geogig.api.porcelain.CheckoutOp; import org.locationtech.geogig.api.porcelain.CheckoutResult; import org.locationtech.geogig.cli.AbstractCommand; import org.locationtech.geogig.cli.CLICommand; import org.locationtech.geogig.cli.CommandFailedException; import org.locationtech.geogig.cli.GeogigCLI; import org.locationtech.geogig.cli.annotation.ObjectDatabaseReadOnly; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import com.google.common.collect.Lists; /** * This command checks out a branch into the working tree. Checkout also updates HEAD to set the * specified branch as the current branch. This command can also be used to discard local changes if * used with force option. * <p> * When used with the {@code -p} option and path names are given it will update those paths in the * working tree from the index tree if {@code <branchOrCommitName>} isn't given otherwise it will * update from that tree. Note that this doesn't switch what branch you are on. * <p> * CLI proxy for {@link CheckoutOp} * <p> * Usage: * <ul> * <li> {@code geogig checkout [-f] [<branchName>]} * <li> {@code geogig checkout [<branchOrCommitName>] [-p <paths>...]} * </ul> * * @see CheckoutOp */ @ObjectDatabaseReadOnly @Parameters(commandNames = "checkout", commandDescription = "Checkout a branch or paths to the working tree") public class Checkout extends AbstractCommand implements CLICommand { @Parameter(arity = 1, description = "<branch|commit>") private List<String> branchOrStartPoint = Lists.newArrayList(); @Parameter(names = { "--force", "-f" }, description = "When switching branches, proceed even if the index or the " + "working tree differs from HEAD. This is used to throw away local changes.") private boolean force = false; @Parameter(names = { "--path", "-p" }, description = "Don't switch branches just update the named paths in the " + "working tree from the index tree or a named treeish object.", variableArity = true) private List<String> paths = Lists.newArrayList(); @Parameter(names = "--ours", description = "When checking out paths from the index, check out 'ours' version for unmerged paths") private boolean ours; @Parameter(names = "--theirs", description = "When checking out paths from the index, check out 'theirs' version for unmerged paths") private boolean theirs; @Override public void runInternal(GeogigCLI cli) throws IOException { final GeoGIG geogig = cli.getGeogig(); checkParameter(branchOrStartPoint.size() != 0 || !paths.isEmpty(), "no branch or paths specified"); checkParameter(branchOrStartPoint.size() < 2, "too many arguments"); try { final ConsoleReader console = cli.getConsole(); String branchOrCommit = (branchOrStartPoint.size() > 0 ? branchOrStartPoint.get(0) : null); CheckoutResult result = geogig.command(CheckoutOp.class).setForce(force) .setSource(branchOrCommit).addPaths(paths).setOurs(ours).setTheirs(theirs) .call(); switch (result.getResult()) { case CHECKOUT_LOCAL_BRANCH: console.println("Switched to branch '" + result.getNewRef().localName() + "'"); break; case CHECKOUT_REMOTE_BRANCH: console.println("Branch '" + result.getNewRef().localName() + "' was set up to track remote branch '" + result.getNewRef().localName() + "' from " + result.getRemoteName() + "."); console.println("Switched to a new branch '" + result.getNewRef().localName() + "'"); break; case UPDATE_OBJECTS: console.println("Objects in the working tree were updated to the specifed version."); break; case DETACHED_HEAD: console.println("You are in 'detached HEAD' state. HEAD is now at " + result.getOid().toString().substring(0, 7) + "..."); break; default: break; } } catch (CheckoutException e) { switch (e.statusCode) { case LOCAL_CHANGES_NOT_COMMITTED: throw new CommandFailedException( "Working tree and index are not clean. To overwrite local changes, use the --force option", e); case UNMERGED_PATHS: throw new CommandFailedException(e.getMessage(), e); } } } }