1 | #include "git-compat-util.h"
|
---|
2 | #include "cache.h"
|
---|
3 | #include "branch.h"
|
---|
4 | #include "refs.h"
|
---|
5 | #include "remote.h"
|
---|
6 | #include "commit.h"
|
---|
7 |
|
---|
8 | struct tracking {
|
---|
9 | struct refspec spec;
|
---|
10 | char *src;
|
---|
11 | const char *remote;
|
---|
12 | int matches;
|
---|
13 | };
|
---|
14 |
|
---|
15 | static int find_tracked_branch(struct remote *remote, void *priv)
|
---|
16 | {
|
---|
17 | struct tracking *tracking = priv;
|
---|
18 |
|
---|
19 | if (!remote_find_tracking(remote, &tracking->spec)) {
|
---|
20 | if (++tracking->matches == 1) {
|
---|
21 | tracking->src = tracking->spec.src;
|
---|
22 | tracking->remote = remote->name;
|
---|
23 | } else {
|
---|
24 | free(tracking->spec.src);
|
---|
25 | if (tracking->src) {
|
---|
26 | free(tracking->src);
|
---|
27 | tracking->src = NULL;
|
---|
28 | }
|
---|
29 | }
|
---|
30 | tracking->spec.src = NULL;
|
---|
31 | }
|
---|
32 |
|
---|
33 | return 0;
|
---|
34 | }
|
---|
35 |
|
---|
36 | static int should_setup_rebase(const char *origin)
|
---|
37 | {
|
---|
38 | switch (autorebase) {
|
---|
39 | case AUTOREBASE_NEVER:
|
---|
40 | return 0;
|
---|
41 | case AUTOREBASE_LOCAL:
|
---|
42 | return origin == NULL;
|
---|
43 | case AUTOREBASE_REMOTE:
|
---|
44 | return origin != NULL;
|
---|
45 | case AUTOREBASE_ALWAYS:
|
---|
46 | return 1;
|
---|
47 | }
|
---|
48 | return 0;
|
---|
49 | }
|
---|
50 |
|
---|
51 | void install_branch_config(int flag, const char *local, const char *origin, const char *remote)
|
---|
52 | {
|
---|
53 | const char *shortname = skip_prefix(remote, "refs/heads/");
|
---|
54 | struct strbuf key = STRBUF_INIT;
|
---|
55 | int rebasing = should_setup_rebase(origin);
|
---|
56 |
|
---|
57 | if (shortname
|
---|
58 | && !strcmp(local, shortname)
|
---|
59 | && !origin) {
|
---|
60 | warning(_("Not setting branch %s as its own upstream."),
|
---|
61 | local);
|
---|
62 | return;
|
---|
63 | }
|
---|
64 |
|
---|
65 | strbuf_addf(&key, "branch.%s.remote", local);
|
---|
66 | git_config_set(key.buf, origin ? origin : ".");
|
---|
67 |
|
---|
68 | strbuf_reset(&key);
|
---|
69 | strbuf_addf(&key, "branch.%s.merge", local);
|
---|
70 | git_config_set(key.buf, remote);
|
---|
71 |
|
---|
72 | if (rebasing) {
|
---|
73 | strbuf_reset(&key);
|
---|
74 | strbuf_addf(&key, "branch.%s.rebase", local);
|
---|
75 | git_config_set(key.buf, "true");
|
---|
76 | }
|
---|
77 | strbuf_release(&key);
|
---|
78 |
|
---|
79 | if (flag & BRANCH_CONFIG_VERBOSE) {
|
---|
80 | if (shortname) {
|
---|
81 | if (origin)
|
---|
82 | printf_ln(rebasing ?
|
---|
83 | _("Branch %s set up to track remote branch %s from %s by rebasing.") :
|
---|
84 | _("Branch %s set up to track remote branch %s from %s."),
|
---|
85 | local, shortname, origin);
|
---|
86 | else
|
---|
87 | printf_ln(rebasing ?
|
---|
88 | _("Branch %s set up to track local branch %s by rebasing.") :
|
---|
89 | _("Branch %s set up to track local branch %s."),
|
---|
90 | local, shortname);
|
---|
91 | } else {
|
---|
92 | if (origin)
|
---|
93 | printf_ln(rebasing ?
|
---|
94 | _("Branch %s set up to track remote ref %s by rebasing.") :
|
---|
95 | _("Branch %s set up to track remote ref %s."),
|
---|
96 | local, remote);
|
---|
97 | else
|
---|
98 | printf_ln(rebasing ?
|
---|
99 | _("Branch %s set up to track local ref %s by rebasing.") :
|
---|
100 | _("Branch %s set up to track local ref %s."),
|
---|
101 | local, remote);
|
---|
102 | }
|
---|
103 | }
|
---|
104 | }
|
---|
105 |
|
---|
106 | /*
|
---|
107 | * This is called when new_ref is branched off of orig_ref, and tries
|
---|
108 | * to infer the settings for branch.<new_ref>.{remote,merge} from the
|
---|
109 | * config.
|
---|
110 | */
|
---|
111 | static int setup_tracking(const char *new_ref, const char *orig_ref,
|
---|
112 | enum branch_track track, int quiet)
|
---|
113 | {
|
---|
114 | struct tracking tracking;
|
---|
115 | int config_flags = quiet ? 0 : BRANCH_CONFIG_VERBOSE;
|
---|
116 |
|
---|
117 | memset(&tracking, 0, sizeof(tracking));
|
---|
118 | tracking.spec.dst = (char *)orig_ref;
|
---|
119 | if (for_each_remote(find_tracked_branch, &tracking))
|
---|
120 | return 1;
|
---|
121 |
|
---|
122 | if (!tracking.matches)
|
---|
123 | switch (track) {
|
---|
124 | case BRANCH_TRACK_ALWAYS:
|
---|
125 | case BRANCH_TRACK_EXPLICIT:
|
---|
126 | case BRANCH_TRACK_OVERRIDE:
|
---|
127 | break;
|
---|
128 | default:
|
---|
129 | return 1;
|
---|
130 | }
|
---|
131 |
|
---|
132 | if (tracking.matches > 1)
|
---|
133 | return error(_("Not tracking: ambiguous information for ref %s"),
|
---|
134 | orig_ref);
|
---|
135 |
|
---|
136 | install_branch_config(config_flags, new_ref, tracking.remote,
|
---|
137 | tracking.src ? tracking.src : orig_ref);
|
---|
138 |
|
---|
139 | free(tracking.src);
|
---|
140 | return 0;
|
---|
141 | }
|
---|
142 |
|
---|
143 | struct branch_desc_cb {
|
---|
144 | const char *config_name;
|
---|
145 | const char *value;
|
---|
146 | };
|
---|
147 |
|
---|
148 | static int read_branch_desc_cb(const char *var, const char *value, void *cb)
|
---|
149 | {
|
---|
150 | struct branch_desc_cb *desc = cb;
|
---|
151 | if (strcmp(desc->config_name, var))
|
---|
152 | return 0;
|
---|
153 | free((char *)desc->value);
|
---|
154 | return git_config_string(&desc->value, var, value);
|
---|
155 | }
|
---|
156 |
|
---|
157 | int read_branch_desc(struct strbuf *buf, const char *branch_name)
|
---|
158 | {
|
---|
159 | struct branch_desc_cb cb;
|
---|
160 | struct strbuf name = STRBUF_INIT;
|
---|
161 | strbuf_addf(&name, "branch.%s.description", branch_name);
|
---|
162 | cb.config_name = name.buf;
|
---|
163 | cb.value = NULL;
|
---|
164 | if (git_config(read_branch_desc_cb, &cb) < 0) {
|
---|
165 | strbuf_release(&name);
|
---|
166 | return -1;
|
---|
167 | }
|
---|
168 | if (cb.value)
|
---|
169 | strbuf_addstr(buf, cb.value);
|
---|
170 | strbuf_release(&name);
|
---|
171 | return 0;
|
---|
172 | }
|
---|
173 |
|
---|
174 | int validate_new_branchname(const char *name, struct strbuf *ref,
|
---|
175 | int force, int attr_only)
|
---|
176 | {
|
---|
177 | if (strbuf_check_branch_ref(ref, name))
|
---|
178 | die(_("'%s' is not a valid branch name."), name);
|
---|
179 |
|
---|
180 | if (!ref_exists(ref->buf))
|
---|
181 | return 0;
|
---|
182 | else if (!force && !attr_only)
|
---|
183 | die(_("A branch named '%s' already exists."), ref->buf + strlen("refs/heads/"));
|
---|
184 |
|
---|
185 | if (!attr_only) {
|
---|
186 | const char *head;
|
---|
187 | unsigned char sha1[20];
|
---|
188 |
|
---|
189 | head = resolve_ref_unsafe("HEAD", sha1, 0, NULL);
|
---|
190 | if (!is_bare_repository() && head && !strcmp(head, ref->buf))
|
---|
191 | die(_("Cannot force update the current branch."));
|
---|
192 | }
|
---|
193 | return 1;
|
---|
194 | }
|
---|
195 |
|
---|
196 | static int check_tracking_branch(struct remote *remote, void *cb_data)
|
---|
197 | {
|
---|
198 | char *tracking_branch = cb_data;
|
---|
199 | struct refspec query;
|
---|
200 | memset(&query, 0, sizeof(struct refspec));
|
---|
201 | query.dst = tracking_branch;
|
---|
202 | return !remote_find_tracking(remote, &query);
|
---|
203 | }
|
---|
204 |
|
---|
205 | static int validate_remote_tracking_branch(char *ref)
|
---|
206 | {
|
---|
207 | return !for_each_remote(check_tracking_branch, ref);
|
---|
208 | }
|
---|
209 |
|
---|
210 | static const char upstream_not_branch[] =
|
---|
211 | N_("Cannot setup tracking information; starting point '%s' is not a branch.");
|
---|
212 | static const char upstream_missing[] =
|
---|
213 | N_("the requested upstream branch '%s' does not exist");
|
---|
214 | static const char upstream_advice[] =
|
---|
215 | N_("\n"
|
---|
216 | "If you are planning on basing your work on an upstream\n"
|
---|
217 | "branch that already exists at the remote, you may need to\n"
|
---|
218 | "run \"git fetch\" to retrieve it.\n"
|
---|
219 | "\n"
|
---|
220 | "If you are planning to push out a new local branch that\n"
|
---|
221 | "will track its remote counterpart, you may want to use\n"
|
---|
222 | "\"git push -u\" to set the upstream config as you push.");
|
---|
223 |
|
---|
224 | void create_branch(const char *head,
|
---|
225 | const char *name, const char *start_name,
|
---|
226 | int force, int reflog, int clobber_head,
|
---|
227 | int quiet, enum branch_track track)
|
---|
228 | {
|
---|
229 | struct ref_lock *lock = NULL;
|
---|
230 | struct commit *commit;
|
---|
231 | unsigned char sha1[20];
|
---|
232 | char *real_ref, msg[PATH_MAX + 20];
|
---|
233 | struct strbuf ref = STRBUF_INIT;
|
---|
234 | int forcing = 0;
|
---|
235 | int dont_change_ref = 0;
|
---|
236 | int explicit_tracking = 0;
|
---|
237 |
|
---|
238 | if (track == BRANCH_TRACK_EXPLICIT || track == BRANCH_TRACK_OVERRIDE)
|
---|
239 | explicit_tracking = 1;
|
---|
240 |
|
---|
241 | if (validate_new_branchname(name, &ref, force,
|
---|
242 | track == BRANCH_TRACK_OVERRIDE ||
|
---|
243 | clobber_head)) {
|
---|
244 | if (!force)
|
---|
245 | dont_change_ref = 1;
|
---|
246 | else
|
---|
247 | forcing = 1;
|
---|
248 | }
|
---|
249 |
|
---|
250 | real_ref = NULL;
|
---|
251 | if (get_sha1(start_name, sha1)) {
|
---|
252 | if (explicit_tracking) {
|
---|
253 | if (advice_set_upstream_failure) {
|
---|
254 | error(_(upstream_missing), start_name);
|
---|
255 | advise(_(upstream_advice));
|
---|
256 | exit(1);
|
---|
257 | }
|
---|
258 | die(_(upstream_missing), start_name);
|
---|
259 | }
|
---|
260 | die(_("Not a valid object name: '%s'."), start_name);
|
---|
261 | }
|
---|
262 |
|
---|
263 | switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) {
|
---|
264 | case 0:
|
---|
265 | /* Not branching from any existing branch */
|
---|
266 | if (explicit_tracking)
|
---|
267 | die(_(upstream_not_branch), start_name);
|
---|
268 | break;
|
---|
269 | case 1:
|
---|
270 | /* Unique completion -- good, only if it is a real branch */
|
---|
271 | if (!starts_with(real_ref, "refs/heads/") &&
|
---|
272 | validate_remote_tracking_branch(real_ref)) {
|
---|
273 | if (explicit_tracking)
|
---|
274 | die(_(upstream_not_branch), start_name);
|
---|
275 | else
|
---|
276 | real_ref = NULL;
|
---|
277 | }
|
---|
278 | break;
|
---|
279 | default:
|
---|
280 | die(_("Ambiguous object name: '%s'."), start_name);
|
---|
281 | break;
|
---|
282 | }
|
---|
283 |
|
---|
284 | if ((commit = lookup_commit_reference(sha1)) == NULL)
|
---|
285 | die(_("Not a valid branch point: '%s'."), start_name);
|
---|
286 | hashcpy(sha1, commit->object.sha1);
|
---|
287 |
|
---|
288 | if (!dont_change_ref) {
|
---|
289 | lock = lock_any_ref_for_update(ref.buf, NULL, 0, NULL);
|
---|
290 | if (!lock)
|
---|
291 | die_errno(_("Failed to lock ref for update"));
|
---|
292 | }
|
---|
293 |
|
---|
294 | if (reflog)
|
---|
295 | log_all_ref_updates = 1;
|
---|
296 |
|
---|
297 | if (forcing)
|
---|
298 | snprintf(msg, sizeof msg, "branch: Reset to %s",
|
---|
299 | start_name);
|
---|
300 | else if (!dont_change_ref)
|
---|
301 | snprintf(msg, sizeof msg, "branch: Created from %s",
|
---|
302 | start_name);
|
---|
303 |
|
---|
304 | if (real_ref && track)
|
---|
305 | setup_tracking(ref.buf + 11, real_ref, track, quiet);
|
---|
306 |
|
---|
307 | if (!dont_change_ref)
|
---|
308 | if (write_ref_sha1(lock, sha1, msg) < 0)
|
---|
309 | die_errno(_("Failed to write ref"));
|
---|
310 |
|
---|
311 | strbuf_release(&ref);
|
---|
312 | free(real_ref);
|
---|
313 | }
|
---|
314 |
|
---|
315 | void remove_branch_state(void)
|
---|
316 | {
|
---|
317 | unlink(git_path("CHERRY_PICK_HEAD"));
|
---|
318 | unlink(git_path("REVERT_HEAD"));
|
---|
319 | unlink(git_path("MERGE_HEAD"));
|
---|
320 | unlink(git_path("MERGE_RR"));
|
---|
321 | unlink(git_path("MERGE_MSG"));
|
---|
322 | unlink(git_path("MERGE_MODE"));
|
---|
323 | unlink(git_path("SQUASH_MSG"));
|
---|
324 | }
|
---|