@matheusbsbs / matheus-bagliano / commits / e496c00348
Fork 0

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);