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 * @return the full tracking branch name or <code>null</code> if it could
117 * not be determined
118 */
119 public String getTrackingBranch() {
120 String remote = getRemoteOrDefault();
121 String mergeRef = getMerge();
122 if (remote == null || mergeRef == null)
123 return null;
124
125 if (isRemoteLocal())
126 return mergeRef;
127
128 return findRemoteTrackingBranch(remote, mergeRef);
129 }
130
131 /**
132 * @return the full remote-tracking branch name or {@code null} if it could
133 * not be determined. If you also want local tracked branches use
134 * {@link #getTrackingBranch()} instead.
135 */
136 public String getRemoteTrackingBranch() {
137 String remote = getRemoteOrDefault();
138 String mergeRef = getMerge();
139 if (remote == null || mergeRef == null)
140 return null;
141
142 return findRemoteTrackingBranch(remote, mergeRef);
143 }
144
145 /**
146 * @return {@code true} if the "remote" setting points to the local
147 * repository (with {@value #LOCAL_REPOSITORY}), false otherwise
148 * @since 3.5
149 */
150 public boolean isRemoteLocal() {
151 return LOCAL_REPOSITORY.equals(getRemote());
152 }
153
154 /**
155 * @return the remote this branch is configured to fetch from/push to, or
156 * {@code null} if not defined
157 * @since 3.5
158 */
159 public String getRemote() {
160 return config.getString(ConfigConstants.CONFIG_BRANCH_SECTION,
161 branchName, ConfigConstants.CONFIG_KEY_REMOTE);
162 }
163
164 /**
165 * @return the name of the upstream branch as it is called on the remote, or
166 * {@code null} if not defined
167 * @since 3.5
168 */
169 public String getMerge() {
170 return config.getString(ConfigConstants.CONFIG_BRANCH_SECTION,
171 branchName, ConfigConstants.CONFIG_KEY_MERGE);
172 }
173
174 /**
175 * @return {@code true} if the branch is configured to be rebased
176 * @since 3.5
177 */
178 public boolean isRebase() {
179 return getRebaseMode() != BranchRebaseMode.NONE;
180 }
181
182 /**
183 * Retrieves the config value of branch.[name].rebase.
184 *
185 * @return the {@link BranchRebaseMode}
186 * @since 4.5
187 */
188 public BranchRebaseMode getRebaseMode() {
189 return config.getEnum(BranchRebaseMode.values(),
190 ConfigConstants.CONFIG_BRANCH_SECTION, branchName,
191 ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE);
192 }
193
194 /**
195 * Finds the tracked remote tracking branch
196 *
197 * @param remote
198 * Remote name
199 * @param mergeRef
200 * merge Ref of the local branch tracking the remote tracking
201 * branch
202 * @return full remote tracking branch name or null
203 */
204 private String findRemoteTrackingBranch(String remote, String mergeRef) {
205 RemoteConfig remoteConfig;
206 try {
207 remoteConfig = new RemoteConfig(config, remote);
208 } catch (URISyntaxException e) {
209 return null;
210 }
211 for (RefSpec refSpec : remoteConfig.getFetchRefSpecs()) {
212 if (refSpec.matchSource(mergeRef)) {
213 RefSpec expanded = refSpec.expandFromSource(mergeRef);
214 return expanded.getDestination();
215 }
216 }
217 return null;
218 }
219
220 private String getRemoteOrDefault() {
221 String remote = getRemote();
222 if (remote == null)
223 return Constants.DEFAULT_REMOTE_NAME;
224 else
225 return remote;
226 }
227 }