Merge branch 'nd/mv-code-cleaning'
[alt-git.git] / branch.c
blobdf6b1203de75618fd7aaff28f7f38ecbcd82066e
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"
8 struct tracking {
9 struct refspec spec;
10 char *src;
11 const char *remote;
12 int matches;
15 static int find_tracked_branch(struct remote *remote, void *priv)
17 struct tracking *tracking = priv;
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;
30 tracking->spec.src = NULL;
33 return 0;
36 static int should_setup_rebase(const char *origin)
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;
48 return 0;
51 void install_branch_config(int flag, const char *local, const char *origin, const char *remote)
53 const char *shortname = NULL;
54 struct strbuf key = STRBUF_INIT;
55 int rebasing = should_setup_rebase(origin);
57 if (skip_prefix(remote, "refs/heads/", &shortname)
58 && !strcmp(local, shortname)
59 && !origin) {
60 warning(_("Not setting branch %s as its own upstream."),
61 local);
62 return;
65 strbuf_addf(&key, "branch.%s.remote", local);
66 git_config_set(key.buf, origin ? origin : ".");
68 strbuf_reset(&key);
69 strbuf_addf(&key, "branch.%s.merge", local);
70 git_config_set(key.buf, remote);
72 if (rebasing) {
73 strbuf_reset(&key);
74 strbuf_addf(&key, "branch.%s.rebase", local);
75 git_config_set(key.buf, "true");
77 strbuf_release(&key);
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);
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.
111 static int setup_tracking(const char *new_ref, const char *orig_ref,
112 enum branch_track track, int quiet)
114 struct tracking tracking;
115 int config_flags = quiet ? 0 : BRANCH_CONFIG_VERBOSE;
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;
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;
132 if (tracking.matches > 1)
133 return error(_("Not tracking: ambiguous information for ref %s"),
134 orig_ref);
136 install_branch_config(config_flags, new_ref, tracking.remote,
137 tracking.src ? tracking.src : orig_ref);
139 free(tracking.src);
140 return 0;
143 int read_branch_desc(struct strbuf *buf, const char *branch_name)
145 char *v = NULL;
146 struct strbuf name = STRBUF_INIT;
147 strbuf_addf(&name, "branch.%s.description", branch_name);
148 if (git_config_get_string(name.buf, &v)) {
149 strbuf_release(&name);
150 return -1;
152 strbuf_addstr(buf, v);
153 free(v);
154 strbuf_release(&name);
155 return 0;
158 int validate_new_branchname(const char *name, struct strbuf *ref,
159 int force, int attr_only)
161 if (strbuf_check_branch_ref(ref, name))
162 die(_("'%s' is not a valid branch name."), name);
164 if (!ref_exists(ref->buf))
165 return 0;
166 else if (!force && !attr_only)
167 die(_("A branch named '%s' already exists."), ref->buf + strlen("refs/heads/"));
169 if (!attr_only) {
170 const char *head;
171 unsigned char sha1[20];
173 head = resolve_ref_unsafe("HEAD", sha1, 0, NULL);
174 if (!is_bare_repository() && head && !strcmp(head, ref->buf))
175 die(_("Cannot force update the current branch."));
177 return 1;
180 static int check_tracking_branch(struct remote *remote, void *cb_data)
182 char *tracking_branch = cb_data;
183 struct refspec query;
184 memset(&query, 0, sizeof(struct refspec));
185 query.dst = tracking_branch;
186 return !remote_find_tracking(remote, &query);
189 static int validate_remote_tracking_branch(char *ref)
191 return !for_each_remote(check_tracking_branch, ref);
194 static const char upstream_not_branch[] =
195 N_("Cannot setup tracking information; starting point '%s' is not a branch.");
196 static const char upstream_missing[] =
197 N_("the requested upstream branch '%s' does not exist");
198 static const char upstream_advice[] =
199 N_("\n"
200 "If you are planning on basing your work on an upstream\n"
201 "branch that already exists at the remote, you may need to\n"
202 "run \"git fetch\" to retrieve it.\n"
203 "\n"
204 "If you are planning to push out a new local branch that\n"
205 "will track its remote counterpart, you may want to use\n"
206 "\"git push -u\" to set the upstream config as you push.");
208 void create_branch(const char *head,
209 const char *name, const char *start_name,
210 int force, int reflog, int clobber_head,
211 int quiet, enum branch_track track)
213 struct ref_lock *lock = NULL;
214 struct commit *commit;
215 unsigned char sha1[20];
216 char *real_ref, msg[PATH_MAX + 20];
217 struct strbuf ref = STRBUF_INIT;
218 int forcing = 0;
219 int dont_change_ref = 0;
220 int explicit_tracking = 0;
222 if (track == BRANCH_TRACK_EXPLICIT || track == BRANCH_TRACK_OVERRIDE)
223 explicit_tracking = 1;
225 if (validate_new_branchname(name, &ref, force,
226 track == BRANCH_TRACK_OVERRIDE ||
227 clobber_head)) {
228 if (!force)
229 dont_change_ref = 1;
230 else
231 forcing = 1;
234 real_ref = NULL;
235 if (get_sha1(start_name, sha1)) {
236 if (explicit_tracking) {
237 if (advice_set_upstream_failure) {
238 error(_(upstream_missing), start_name);
239 advise(_(upstream_advice));
240 exit(1);
242 die(_(upstream_missing), start_name);
244 die(_("Not a valid object name: '%s'."), start_name);
247 switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) {
248 case 0:
249 /* Not branching from any existing branch */
250 if (explicit_tracking)
251 die(_(upstream_not_branch), start_name);
252 break;
253 case 1:
254 /* Unique completion -- good, only if it is a real branch */
255 if (!starts_with(real_ref, "refs/heads/") &&
256 validate_remote_tracking_branch(real_ref)) {
257 if (explicit_tracking)
258 die(_(upstream_not_branch), start_name);
259 else
260 real_ref = NULL;
262 break;
263 default:
264 die(_("Ambiguous object name: '%s'."), start_name);
265 break;
268 if ((commit = lookup_commit_reference(sha1)) == NULL)
269 die(_("Not a valid branch point: '%s'."), start_name);
270 hashcpy(sha1, commit->object.sha1);
272 if (!dont_change_ref) {
273 lock = lock_any_ref_for_update(ref.buf, NULL, 0, NULL);
274 if (!lock)
275 die_errno(_("Failed to lock ref for update"));
278 if (reflog)
279 log_all_ref_updates = 1;
281 if (forcing)
282 snprintf(msg, sizeof msg, "branch: Reset to %s",
283 start_name);
284 else if (!dont_change_ref)
285 snprintf(msg, sizeof msg, "branch: Created from %s",
286 start_name);
288 if (real_ref && track)
289 setup_tracking(ref.buf + 11, real_ref, track, quiet);
291 if (!dont_change_ref)
292 if (write_ref_sha1(lock, sha1, msg) < 0)
293 die_errno(_("Failed to write ref"));
295 strbuf_release(&ref);
296 free(real_ref);
299 void remove_branch_state(void)
301 unlink(git_path("CHERRY_PICK_HEAD"));
302 unlink(git_path("REVERT_HEAD"));
303 unlink(git_path("MERGE_HEAD"));
304 unlink(git_path("MERGE_RR"));
305 unlink(git_path("MERGE_MSG"));
306 unlink(git_path("MERGE_MODE"));
307 unlink(git_path("SQUASH_MSG"));