Move create_branch into a library file
You can also create branches, in exactly the same way, with checkout -b. This introduces branch.{c,h} library files for doing porcelain-level operations on branches (such as creating them with their appropriate default configuration). Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
Daniel Barkalow committed
Feb 7, 2008 at 11:40 UTC
e496c00348140e73bdd202443df52192f6928541
4 files changed
+151
-137
Makefile
+1
-1
@@ -317,7 +317,7 @@ LIB_OBJS = \
317
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
318
color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
319
convert.o attr.o decorate.o progress.o mailmap.o symlinks.o remote.o \
320
- transport.o bundle.o walker.o parse-options.o ws.o archive.o
320
+ transport.o bundle.o walker.o parse-options.o ws.o archive.o branch.o
321
322
BUILTIN_OBJS = \
323
builtin-add.o \
branch.c
new
+140
@@ -0,0 +1,140 @@
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
+}
branch.h
new
+8
@@ -0,0 +1,8 @@
1
+#ifndef BRANCH_H
2
+#define BRANCH_H
3
+
4
+void create_branch(const char *head,
5
+ const char *name, const char *start_name,
6
+ int force, int reflog, int track);
7
+
8
+#endif
builtin-branch.c
+2
-136
@@ -12,6 +12,7 @@
12
#include "builtin.h"
13
#include "remote.h"
14
#include "parse-options.h"
15
+#include "branch.h"
16
17
static const char * const builtin_branch_usage[] = {
18
"git-branch [options] [-r | -a]",
@@ -356,141 +357,6 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str
357
free_ref_list(&ref_list);
358
}
359
359
-struct tracking {
360
- struct refspec spec;
361
- char *src;
362
- const char *remote;
363
- int matches;
364
-};
365
-
366
-static int find_tracked_branch(struct remote *remote, void *priv)
367
-{
368
- struct tracking *tracking = priv;
369
-
370
- if (!remote_find_tracking(remote, &tracking->spec)) {
371
- if (++tracking->matches == 1) {
372
- tracking->src = tracking->spec.src;
373
- tracking->remote = remote->name;
374
- } else {
375
- free(tracking->spec.src);
376
- if (tracking->src) {
377
- free(tracking->src);
378
- tracking->src = NULL;
379
- }
380
- }
381
- tracking->spec.src = NULL;
382
- }
383
-
384
- return 0;
385
-}
386
-
387
-
388
-/*
389
- * This is called when new_ref is branched off of orig_ref, and tries
390
- * to infer the settings for branch.<new_ref>.{remote,merge} from the
391
- * config.
392
- */
393
-static int setup_tracking(const char *new_ref, const char *orig_ref)
394
-{
395
- char key[1024];
396
- struct tracking tracking;
397
-
398
- if (strlen(new_ref) > 1024 - 7 - 7 - 1)
399
- return error("Tracking not set up: name too long: %s",
400
- new_ref);
401
-
402
- memset(&tracking, 0, sizeof(tracking));
403
- tracking.spec.dst = (char *)orig_ref;
404
- if (for_each_remote(find_tracked_branch, &tracking) ||
405
- !tracking.matches)
406
- return 1;
407
-
408
- if (tracking.matches > 1)
409
- return error("Not tracking: ambiguous information for ref %s",
410
- orig_ref);
411
-
412
- if (tracking.matches == 1) {
413
- sprintf(key, "branch.%s.remote", new_ref);
414
- git_config_set(key, tracking.remote ? tracking.remote : ".");
415
- sprintf(key, "branch.%s.merge", new_ref);
416
- git_config_set(key, tracking.src);
417
- free(tracking.src);
418
- printf("Branch %s set up to track remote branch %s.\n",
419
- new_ref, orig_ref);
420
- }
421
-
422
- return 0;
423
-}
424
-
425
-static void create_branch(const char *name, const char *start_name,
426
- int force, int reflog, int track)
427
-{
428
- struct ref_lock *lock;
429
- struct commit *commit;
430
- unsigned char sha1[20];
431
- char *real_ref, ref[PATH_MAX], msg[PATH_MAX + 20];
432
- int forcing = 0;
433
-
434
- snprintf(ref, sizeof ref, "refs/heads/%s", name);
435
- if (check_ref_format(ref))
436
- die("'%s' is not a valid branch name.", name);
437
-
438
- if (resolve_ref(ref, sha1, 1, NULL)) {
439
- if (!force)
440
- die("A branch named '%s' already exists.", name);
441
- else if (!is_bare_repository() && !strcmp(head, name))
442
- die("Cannot force update the current branch.");
443
- forcing = 1;
444
- }
445
-
446
- real_ref = NULL;
447
- if (get_sha1(start_name, sha1))
448
- die("Not a valid object name: '%s'.", start_name);
449
-
450
- switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) {
451
- case 0:
452
- /* Not branching from any existing branch */
453
- real_ref = NULL;
454
- break;
455
- case 1:
456
- /* Unique completion -- good */
457
- break;
458
- default:
459
- die("Ambiguous object name: '%s'.", start_name);
460
- break;
461
- }
462
-
463
- if ((commit = lookup_commit_reference(sha1)) == NULL)
464
- die("Not a valid branch point: '%s'.", start_name);
465
- hashcpy(sha1, commit->object.sha1);
466
-
467
- lock = lock_any_ref_for_update(ref, NULL, 0);
468
- if (!lock)
469
- die("Failed to lock ref for update: %s.", strerror(errno));
470
-
471
- if (reflog)
472
- log_all_ref_updates = 1;
473
-
474
- if (forcing)
475
- snprintf(msg, sizeof msg, "branch: Reset from %s",
476
- start_name);
477
- else
478
- snprintf(msg, sizeof msg, "branch: Created from %s",
479
- start_name);
480
-
481
- /* When branching off a remote branch, set up so that git-pull
482
- automatically merges from there. So far, this is only done for
483
- remotes registered via .git/config. */
484
- if (real_ref && track)
485
- setup_tracking(name, real_ref);
486
-
487
- if (write_ref_sha1(lock, sha1, msg) < 0)
488
- die("Failed to write ref: %s.", strerror(errno));
489
-
490
- if (real_ref)
491
- free(real_ref);
492
-}
493
-
360
static void rename_branch(const char *oldname, const char *newname, int force)
361
{
362
char oldref[PATH_MAX], newref[PATH_MAX], logmsg[PATH_MAX*2 + 100];
@@ -611,7 +477,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
477
else if (rename && (argc == 2))
478
rename_branch(argv[0], argv[1], rename > 1);
479
else if (argc <= 2)
614
- create_branch(argv[0], (argc == 2) ? argv[1] : head,
480
+ create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
481
force_create, reflog, track);
482
else
483
usage_with_options(builtin_branch_usage, options);