]> git.ipfire.org Git - thirdparty/git.git/blame - branch.c
Move create_branch into a library file
[thirdparty/git.git] / branch.c
CommitLineData
e496c003
DB
1#include "cache.h"
2#include "branch.h"
3#include "refs.h"
4#include "remote.h"
5#include "commit.h"
6
7struct tracking {
8 struct refspec spec;
9 char *src;
10 const char *remote;
11 int matches;
12};
13
14static int find_tracked_branch(struct remote *remote, void *priv)
15{
16 struct tracking *tracking = priv;
17
18 if (!remote_find_tracking(remote, &tracking->spec)) {
19 if (++tracking->matches == 1) {
20 tracking->src = tracking->spec.src;
21 tracking->remote = remote->name;
22 } else {
23 free(tracking->spec.src);
24 if (tracking->src) {
25 free(tracking->src);
26 tracking->src = NULL;
27 }
28 }
29 tracking->spec.src = NULL;
30 }
31
32 return 0;
33}
34
35/*
36 * This is called when new_ref is branched off of orig_ref, and tries
37 * to infer the settings for branch.<new_ref>.{remote,merge} from the
38 * config.
39 */
40static int setup_tracking(const char *new_ref, const char *orig_ref)
41{
42 char key[1024];
43 struct tracking tracking;
44
45 if (strlen(new_ref) > 1024 - 7 - 7 - 1)
46 return error("Tracking not set up: name too long: %s",
47 new_ref);
48
49 memset(&tracking, 0, sizeof(tracking));
50 tracking.spec.dst = (char *)orig_ref;
51 if (for_each_remote(find_tracked_branch, &tracking) ||
52 !tracking.matches)
53 return 1;
54
55 if (tracking.matches > 1)
56 return error("Not tracking: ambiguous information for ref %s",
57 orig_ref);
58
59 if (tracking.matches == 1) {
60 sprintf(key, "branch.%s.remote", new_ref);
61 git_config_set(key, tracking.remote ? tracking.remote : ".");
62 sprintf(key, "branch.%s.merge", new_ref);
63 git_config_set(key, tracking.src);
64 free(tracking.src);
65 printf("Branch %s set up to track remote branch %s.\n",
66 new_ref, orig_ref);
67 }
68
69 return 0;
70}
71
72void create_branch(const char *head,
73 const char *name, const char *start_name,
74 int force, int reflog, int track)
75{
76 struct ref_lock *lock;
77 struct commit *commit;
78 unsigned char sha1[20];
79 char *real_ref, ref[PATH_MAX], msg[PATH_MAX + 20];
80 int forcing = 0;
81
82 snprintf(ref, sizeof ref, "refs/heads/%s", name);
83 if (check_ref_format(ref))
84 die("'%s' is not a valid branch name.", name);
85
86 if (resolve_ref(ref, sha1, 1, NULL)) {
87 if (!force)
88 die("A branch named '%s' already exists.", name);
89 else if (!is_bare_repository() && !strcmp(head, name))
90 die("Cannot force update the current branch.");
91 forcing = 1;
92 }
93
94 real_ref = NULL;
95 if (get_sha1(start_name, sha1))
96 die("Not a valid object name: '%s'.", start_name);
97
98 switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) {
99 case 0:
100 /* Not branching from any existing branch */
101 real_ref = NULL;
102 break;
103 case 1:
104 /* Unique completion -- good */
105 break;
106 default:
107 die("Ambiguous object name: '%s'.", start_name);
108 break;
109 }
110
111 if ((commit = lookup_commit_reference(sha1)) == NULL)
112 die("Not a valid branch point: '%s'.", start_name);
113 hashcpy(sha1, commit->object.sha1);
114
115 lock = lock_any_ref_for_update(ref, NULL, 0);
116 if (!lock)
117 die("Failed to lock ref for update: %s.", strerror(errno));
118
119 if (reflog)
120 log_all_ref_updates = 1;
121
122 if (forcing)
123 snprintf(msg, sizeof msg, "branch: Reset from %s",
124 start_name);
125 else
126 snprintf(msg, sizeof msg, "branch: Created from %s",
127 start_name);
128
129 /* When branching off a remote branch, set up so that git-pull
130 automatically merges from there. So far, this is only done for
131 remotes registered via .git/config. */
132 if (real_ref && track)
133 setup_tracking(name, real_ref);
134
135 if (write_ref_sha1(lock, sha1, msg) < 0)
136 die("Failed to write ref: %s.", strerror(errno));
137
138 if (real_ref)
139 free(real_ref);
140}