1 /*
2 * Copyright (C) 2011, Robin Stocker <robin@nibor.org>
3 * Copyright (C) 2012, Matthias Sohn <matthias.sohn@sap.com>
4 * and other copyright owners as documented in the project's IP log.
5 *
6 * This program and the accompanying materials are made available
7 * under the terms of the Eclipse Distribution License v1.0 which
8 * accompanies this distribution, is reproduced below, and is
9 * available at http://www.eclipse.org/org/documents/edl-v10.php
10 *
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or
14 * without modification, are permitted provided that the following
15 * conditions are met:
16 *
17 * - Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 *
20 * - Redistributions in binary form must reproduce the above
21 * copyright notice, this list of conditions and the following
22 * disclaimer in the documentation and/or other materials provided
23 * with the distribution.
24 *
25 * - Neither the name of the Eclipse Foundation, Inc. nor the
26 * names of its contributors may be used to endorse or promote
27 * products derived from this software without specific prior
28 * written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
31 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
32 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
33 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
35 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
37 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
42 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 */
44
45 package org.eclipse.jgit.lib;
46
47 import java.net.URISyntaxException;
48
49 import org.eclipse.jgit.transport.RefSpec;
50 import org.eclipse.jgit.transport.RemoteConfig;
51
52 /**
53 * Branch section of a Git configuration file.
54 */
55 public class BranchConfig {
56
57 /**
58 * Config values for branch.[name].rebase (and pull.rebase).
59 *
60 * @since 4.5
61 */
62 public enum BranchRebaseMode implements Config.ConfigEnum {
63
64 /** Value for rebasing */
65 REBASE("true"), //$NON-NLS-1$
66 /** Value for rebasing preserving local merge commits */
67 PRESERVE("preserve"), //$NON-NLS-1$
68 /** Value for rebasing interactively */
69 INTERACTIVE("interactive"), //$NON-NLS-1$
70 /** Value for not rebasing at all but merging */
71 NONE("false"); //$NON-NLS-1$
72
73 private final String configValue;
74
75 private BranchRebaseMode(String configValue) {
76 this.configValue = configValue;
77 }
78
79 @Override
80 public String toConfigValue() {
81 return configValue;
82 }
83
84 @Override
85 public boolean matchConfigValue(String s) {
86 return configValue.equals(s);
87 }
88 }
89
90 /**
91 * The value that means "local repository" for {@link #getRemote()}:
92 * {@value}
93 *
94 * @since 3.5
95 */
96 public static final String LOCAL_REPOSITORY = "."; //$NON-NLS-1$
97
98 private final Config config;
99 private final String branchName;
100
101 /**
102 * Create a new branch config, which will read configuration from config
103 * about specified branch.
104 *
105 * @param config
106 * the config to read from
107 * @param branchName
108 * the short branch name of the section to read
109 */
110 public BranchConfig(final Config config, String branchName) {
111 this.config = config;
112 this.branchName = branchName;
113 }
114
115 /**
116 * Get the full tracking branch name
117 *
118 * @return the full tracking branch name or <code>null</code> if it could
119 * not be determined
120 */
121 public String getTrackingBranch() {
122 String remote = getRemoteOrDefault();
123 String mergeRef = getMerge();
124 if (remote == null || mergeRef == null)
125 return null;
126
127 if (isRemoteLocal())
128 return mergeRef;
129
130 return findRemoteTrackingBranch(remote, mergeRef);
131 }
132
133 /**
134 * Get the full remote-tracking branch name
135 *
136 * @return the full remote-tracking branch name or {@code null} if it could
137 * not be determined. If you also want local tracked branches use
138 * {@link #getTrackingBranch()} instead.
139 */
140 public String getRemoteTrackingBranch() {
141 String remote = getRemoteOrDefault();
142 String mergeRef = getMerge();
143 if (remote == null || mergeRef == null)
144 return null;
145
146 return findRemoteTrackingBranch(remote, mergeRef);
147 }
148
149 /**
150 * Whether the "remote" setting points to the local repository (with
151 * {@value #LOCAL_REPOSITORY})
152 *
153 * @return {@code true} if the "remote" setting points to the local
154 * repository (with {@value #LOCAL_REPOSITORY}), false otherwise
155 * @since 3.5
156 */
157 public boolean isRemoteLocal() {
158 return LOCAL_REPOSITORY.equals(getRemote());
159 }
160
161 /**
162 * Get the remote this branch is configured to fetch from/push to
163 *
164 * @return the remote this branch is configured to fetch from/push to, or
165 * {@code null} if not defined
166 * @since 3.5
167 */
168 public String getRemote() {
169 return config.getString(ConfigConstants.CONFIG_BRANCH_SECTION,
170 branchName, ConfigConstants.CONFIG_KEY_REMOTE);
171 }
172
173 /**
174 * Get the name of the upstream branch as it is called on the remote
175 *
176 * @return the name of the upstream branch as it is called on the remote, or
177 * {@code null} if not defined
178 * @since 3.5
179 */
180 public String getMerge() {
181 return config.getString(ConfigConstants.CONFIG_BRANCH_SECTION,
182 branchName, ConfigConstants.CONFIG_KEY_MERGE);
183 }
184
185 /**
186 * Whether the branch is configured to be rebased
187 *
188 * @return {@code true} if the branch is configured to be rebased
189 * @since 3.5
190 */
191 public boolean isRebase() {
192 return getRebaseMode() != BranchRebaseMode.NONE;
193 }
194
195 /**
196 * Retrieves the config value of branch.[name].rebase.
197 *
198 * @return the {@link org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode}
199 * @since 4.5
200 */
201 public BranchRebaseMode getRebaseMode() {
202 return config.getEnum(BranchRebaseMode.values(),
203 ConfigConstants.CONFIG_BRANCH_SECTION, branchName,
204 ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE);
205 }
206
207 /**
208 * Finds the tracked remote tracking branch
209 *
210 * @param remote
211 * Remote name
212 * @param mergeRef
213 * merge Ref of the local branch tracking the remote tracking
214 * branch
215 * @return full remote tracking branch name or null
216 */
217 private String findRemoteTrackingBranch(String remote, String mergeRef) {
218 RemoteConfig remoteConfig;
219 try {
220 remoteConfig = new RemoteConfig(config, remote);
221 } catch (URISyntaxException e) {
222 return null;
223 }
224 for (RefSpec refSpec : remoteConfig.getFetchRefSpecs()) {
225 if (refSpec.matchSource(mergeRef)) {
226 RefSpec expanded = refSpec.expandFromSource(mergeRef);
227 return expanded.getDestination();
228 }
229 }
230 return null;
231 }
232
233 private String getRemoteOrDefault() {
234 String remote = getRemote();
235 if (remote == null)
236 return Constants.DEFAULT_REMOTE_NAME;
237 else
238 return remote;
239 }
240 }