]> asedeno.scripts.mit.edu Git - git.git/blob - branch.c
builtin-checkout.c: Remove unused prefix arguments in switch_branches path
[git.git] / branch.c
1 #include "cache.h"
2 #include "branch.h"
3 #include "refs.h"
4 #include "remote.h"
5 #include "commit.h"
6
7 struct tracking {
8         struct refspec spec;
9         char *src;
10         const char *remote;
11         int matches;
12 };
13
14 static 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  */
40 static 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
72 void 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 }
141
142 void remove_branch_state(void)
143 {
144         unlink(git_path("MERGE_HEAD"));
145         unlink(git_path("rr-cache/MERGE_RR"));
146         unlink(git_path("MERGE_MSG"));
147         unlink(git_path("SQUASH_MSG"));
148 }