avoid pointer arithmetic involving NULL in FLEX_ALLOC_MEM
[git/raj.git] / branch.c
blob7ff3f204964127374ae2a337819ce0bce7be9ab2
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 #include "worktree.h"
9 struct tracking {
10 struct refspec spec;
11 char *src;
12 const char *remote;
13 int matches;
16 static int find_tracked_branch(struct remote *remote, void *priv)
18 struct tracking *tracking = priv;
20 if (!remote_find_tracking(remote, &tracking->spec)) {
21 if (++tracking->matches == 1) {
22 tracking->src = tracking->spec.src;
23 tracking->remote = remote->name;
24 } else {
25 free(tracking->spec.src);
26 if (tracking->src) {
27 free(tracking->src);
28 tracking->src = NULL;
31 tracking->spec.src = NULL;
34 return 0;
37 static int should_setup_rebase(const char *origin)
39 switch (autorebase) {
40 case AUTOREBASE_NEVER:
41 return 0;
42 case AUTOREBASE_LOCAL:
43 return origin == NULL;
44 case AUTOREBASE_REMOTE:
45 return origin != NULL;
46 case AUTOREBASE_ALWAYS:
47 return 1;
49 return 0;
52 void install_branch_config(int flag, const char *local, const char *origin, const char *remote)
54 const char *shortname = NULL;
55 struct strbuf key = STRBUF_INIT;
56 int rebasing = should_setup_rebase(origin);
58 if (skip_prefix(remote, "refs/heads/", &shortname)
59 && !strcmp(local, shortname)
60 && !origin) {
61 warning(_("Not setting branch %s as its own upstream."),
62 local);
63 return;
66 strbuf_addf(&key, "branch.%s.remote", local);
67 git_config_set(key.buf, origin ? origin : ".");
69 strbuf_reset(&key);
70 strbuf_addf(&key, "branch.%s.merge", local);
71 git_config_set(key.buf, remote);
73 if (rebasing) {
74 strbuf_reset(&key);
75 strbuf_addf(&key, "branch.%s.rebase", local);
76 git_config_set(key.buf, "true");
78 strbuf_release(&key);
80 if (flag & BRANCH_CONFIG_VERBOSE) {
81 if (shortname) {
82 if (origin)
83 printf_ln(rebasing ?
84 _("Branch %s set up to track remote branch %s from %s by rebasing.") :
85 _("Branch %s set up to track remote branch %s from %s."),
86 local, shortname, origin);
87 else
88 printf_ln(rebasing ?
89 _("Branch %s set up to track local branch %s by rebasing.") :
90 _("Branch %s set up to track local branch %s."),
91 local, shortname);
92 } else {
93 if (origin)
94 printf_ln(rebasing ?
95 _("Branch %s set up to track remote ref %s by rebasing.") :
96 _("Branch %s set up to track remote ref %s."),
97 local, remote);
98 else
99 printf_ln(rebasing ?
100 _("Branch %s set up to track local ref %s by rebasing.") :
101 _("Branch %s set up to track local ref %s."),
102 local, remote);
108 * This is called when new_ref is branched off of orig_ref, and tries
109 * to infer the settings for branch.<new_ref>.{remote,merge} from the
110 * config.
112 static int setup_tracking(const char *new_ref, const char *orig_ref,
113 enum branch_track track, int quiet)
115 struct tracking tracking;
116 int config_flags = quiet ? 0 : BRANCH_CONFIG_VERBOSE;
118 memset(&tracking, 0, sizeof(tracking));
119 tracking.spec.dst = (char *)orig_ref;
120 if (for_each_remote(find_tracked_branch, &tracking))
121 return 1;
123 if (!tracking.matches)
124 switch (track) {
125 case BRANCH_TRACK_ALWAYS:
126 case BRANCH_TRACK_EXPLICIT:
127 case BRANCH_TRACK_OVERRIDE:
128 break;
129 default:
130 return 1;
133 if (tracking.matches > 1)
134 return error(_("Not tracking: ambiguous information for ref %s"),
135 orig_ref);
137 install_branch_config(config_flags, new_ref, tracking.remote,
138 tracking.src ? tracking.src : orig_ref);
140 free(tracking.src);
141 return 0;
144 int read_branch_desc(struct strbuf *buf, const char *branch_name)
146 char *v = NULL;
147 struct strbuf name = STRBUF_INIT;
148 strbuf_addf(&name, "branch.%s.description", branch_name);
149 if (git_config_get_string(name.buf, &v)) {
150 strbuf_release(&name);
151 return -1;
153 strbuf_addstr(buf, v);
154 free(v);
155 strbuf_release(&name);
156 return 0;
159 int validate_new_branchname(const char *name, struct strbuf *ref,
160 int force, int attr_only)
162 if (strbuf_check_branch_ref(ref, name))
163 die(_("'%s' is not a valid branch name."), name);
165 if (!ref_exists(ref->buf))
166 return 0;
167 else if (!force && !attr_only)
168 die(_("A branch named '%s' already exists."), ref->buf + strlen("refs/heads/"));
170 if (!attr_only) {
171 const char *head;
172 unsigned char sha1[20];
174 head = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
175 if (!is_bare_repository() && head && !strcmp(head, ref->buf))
176 die(_("Cannot force update the current branch."));
178 return 1;
181 static int check_tracking_branch(struct remote *remote, void *cb_data)
183 char *tracking_branch = cb_data;
184 struct refspec query;
185 memset(&query, 0, sizeof(struct refspec));
186 query.dst = tracking_branch;
187 return !remote_find_tracking(remote, &query);
190 static int validate_remote_tracking_branch(char *ref)
192 return !for_each_remote(check_tracking_branch, ref);
195 static const char upstream_not_branch[] =
196 N_("Cannot setup tracking information; starting point '%s' is not a branch.");
197 static const char upstream_missing[] =
198 N_("the requested upstream branch '%s' does not exist");
199 static const char upstream_advice[] =
200 N_("\n"
201 "If you are planning on basing your work on an upstream\n"
202 "branch that already exists at the remote, you may need to\n"
203 "run \"git fetch\" to retrieve it.\n"
204 "\n"
205 "If you are planning to push out a new local branch that\n"
206 "will track its remote counterpart, you may want to use\n"
207 "\"git push -u\" to set the upstream config as you push.");
209 void create_branch(const char *head,
210 const char *name, const char *start_name,
211 int force, int reflog, int clobber_head,
212 int quiet, enum branch_track track)
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.oid.hash);
272 if (forcing)
273 snprintf(msg, sizeof msg, "branch: Reset to %s",
274 start_name);
275 else if (!dont_change_ref)
276 snprintf(msg, sizeof msg, "branch: Created from %s",
277 start_name);
279 if (reflog)
280 log_all_ref_updates = 1;
282 if (!dont_change_ref) {
283 struct ref_transaction *transaction;
284 struct strbuf err = STRBUF_INIT;
286 transaction = ref_transaction_begin(&err);
287 if (!transaction ||
288 ref_transaction_update(transaction, ref.buf,
289 sha1, forcing ? NULL : null_sha1,
290 0, msg, &err) ||
291 ref_transaction_commit(transaction, &err))
292 die("%s", err.buf);
293 ref_transaction_free(transaction);
294 strbuf_release(&err);
297 if (real_ref && track)
298 setup_tracking(ref.buf + 11, real_ref, track, quiet);
300 strbuf_release(&ref);
301 free(real_ref);
304 void remove_branch_state(void)
306 unlink(git_path_cherry_pick_head());
307 unlink(git_path_revert_head());
308 unlink(git_path_merge_head());
309 unlink(git_path_merge_rr());
310 unlink(git_path_merge_msg());
311 unlink(git_path_merge_mode());
312 unlink(git_path_squash_msg());
315 void die_if_checked_out(const char *branch)
317 char *existing;
319 existing = find_shared_symref("HEAD", branch);
320 if (existing) {
321 skip_prefix(branch, "refs/heads/", &branch);
322 die(_("'%s' is already checked out at '%s'"), branch, existing);