Push command line utility
[egit.git] / org.spearce.jgit / src / org / spearce / jgit / pgm / Push.java
blobcbdf465c836929f62f1b3de3c8f31ae7fbaefde1
1 /*
2 * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
8 * conditions are met:
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * - Neither the name of the Git Development Community nor the
19 * names of its contributors may be used to endorse or promote
20 * products derived from this software without specific prior
21 * written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 package org.spearce.jgit.pgm;
40 import java.util.Collection;
41 import java.util.LinkedList;
43 import org.spearce.jgit.lib.Ref;
44 import org.spearce.jgit.lib.TextProgressMonitor;
45 import org.spearce.jgit.transport.PushResult;
46 import org.spearce.jgit.transport.RefSpec;
47 import org.spearce.jgit.transport.RemoteRefUpdate;
48 import org.spearce.jgit.transport.Transport;
49 import org.spearce.jgit.transport.RemoteRefUpdate.Status;
51 class Push extends TextBuiltin {
53 private boolean verbose = false;
55 private Transport transport;
57 private boolean first = true;
59 @Override
60 void execute(String[] args) throws Exception {
61 final LinkedList<RefSpec> refSpecs = new LinkedList<RefSpec>();
62 Boolean thin = null;
63 String exec = null;
64 boolean forceAll = false;
66 int argi = 0;
67 for (; argi < args.length; argi++) {
68 final String a = args[argi];
69 if ("--thin".equals(a))
70 thin = true;
71 else if ("--no-thin".equals(a))
72 thin = false;
73 else if ("-f".equals(a) || "--force".equals(a))
74 forceAll = true;
75 else if (a.startsWith("--exec="))
76 exec = a.substring("--exec=".length());
77 else if (a.startsWith("--receive-pack="))
78 exec = a.substring("--receive-pack=".length());
79 else if ("--tags".equals(a))
80 refSpecs.add(Transport.REFSPEC_TAGS);
81 else if ("--all".equals(a))
82 refSpecs.add(Transport.REFSPEC_PUSH_ALL);
83 else if ("-v".equals(a))
84 verbose = true;
85 else if ("--".equals(a)) {
86 argi++;
87 break;
88 } else if (a.startsWith("-"))
89 die("usage: push [--all] [--tags] [--force] [--thin]\n"
90 + "[--receive-pack=<git-receive-pack>] [<repository> [<refspec>]...]");
91 else
92 break;
95 final String repository;
96 if (argi == args.length)
97 repository = "origin";
98 else
99 repository = args[argi++];
100 transport = Transport.open(db, repository);
101 if (thin != null)
102 transport.setPushThin(thin);
103 if (exec != null)
104 transport.setOptionReceivePack(exec);
106 for (; argi < args.length; argi++) {
107 RefSpec spec = new RefSpec(args[argi]);
108 if (forceAll)
109 spec = spec.setForceUpdate(true);
110 refSpecs.add(spec);
112 final Collection<RemoteRefUpdate> toPush = transport
113 .findRemoteRefUpdatesFor(refSpecs);
115 final PushResult result = transport.push(new TextProgressMonitor(),
116 toPush);
117 printPushResult(result);
120 private void printPushResult(final PushResult result) {
121 boolean everythingUpToDate = true;
122 // at first, print up-to-date ones...
123 for (final RemoteRefUpdate rru : result.getRemoteUpdates()) {
124 if (rru.getStatus() == Status.UP_TO_DATE) {
125 if (verbose)
126 printRefUpdateResult(result, rru);
127 } else
128 everythingUpToDate = false;
131 for (final RemoteRefUpdate rru : result.getRemoteUpdates()) {
132 // ...then successful updates...
133 if (rru.getStatus() == Status.OK)
134 printRefUpdateResult(result, rru);
137 for (final RemoteRefUpdate rru : result.getRemoteUpdates()) {
138 // ...finally, others (problematic)
139 if (rru.getStatus() != Status.OK
140 && rru.getStatus() != Status.UP_TO_DATE)
141 printRefUpdateResult(result, rru);
144 if (everythingUpToDate)
145 out.println("Everything up-to-date");
148 private void printRefUpdateResult(final PushResult result,
149 final RemoteRefUpdate rru) {
150 if (first) {
151 first = false;
152 out.format("To %s\n", transport.getURI());
155 final String remoteName = rru.getRemoteName();
156 final String srcRef = rru.isDelete() ? null : rru.getSrcRef();
158 switch (rru.getStatus()) {
159 case OK:
160 if (rru.isDelete())
161 printUpdateLine('-', "[deleted]", null, remoteName, null);
162 else {
163 final Ref oldRef = result.getAdvertisedRef(remoteName);
164 if (oldRef == null) {
165 final String summary;
166 if (remoteName.startsWith(REFS_TAGS))
167 summary = "[new tag]";
168 else
169 summary = "[new branch]";
170 printUpdateLine('*', summary, srcRef, remoteName, null);
171 } else {
172 boolean fastForward = rru.isFastForward();
173 final char flag = fastForward ? ' ' : '+';
174 final String summary = abbreviateObject(oldRef
175 .getObjectId())
176 + (fastForward ? ".." : "...")
177 + abbreviateObject(rru.getNewObjectId());
178 final String message = fastForward ? null : "forced update";
179 printUpdateLine(flag, summary, srcRef, remoteName, message);
182 break;
184 case NON_EXISTING:
185 printUpdateLine('X', "[no match]", null, remoteName, null);
186 break;
188 case REJECTED_NODELETE:
189 printUpdateLine('!', "[rejected]", null, remoteName,
190 "remote side does not support deleting refs");
191 break;
193 case REJECTED_NONFASTFORWARD:
194 printUpdateLine('!', "[rejected]", srcRef, remoteName,
195 "non-fast forward");
196 break;
198 case REJECTED_REMOTE_CHANGED:
199 final String message = "remote ref object changed - is not expected one "
200 + abbreviateObject(rru.getExpectedOldObjectId());
201 printUpdateLine('!', "[rejected]", srcRef, remoteName, message);
202 break;
204 case REJECTED_OTHER_REASON:
205 printUpdateLine('!', "[remote rejected]", srcRef, remoteName, rru
206 .getMessage());
207 break;
209 case UP_TO_DATE:
210 if (verbose)
211 printUpdateLine('=', "[up to date]", srcRef, remoteName, null);
212 break;
214 case NOT_ATTEMPTED:
215 case AWAITING_REPORT:
216 printUpdateLine('?', "[unexpected push-process behavior]", srcRef,
217 remoteName, rru.getMessage());
218 break;
222 private void printUpdateLine(final char flag, final String summary,
223 final String srcRef, final String destRef, final String message) {
224 out.format(" %c %-17s", flag, summary);
226 if (srcRef != null)
227 out.format(" %s ->", abbreviateRef(srcRef, true));
228 out.format(" %s", abbreviateRef(destRef, true));
230 if (message != null)
231 out.format(" (%s)", message);
233 out.println();