Skip to content

Commit e496c00

Browse files
iabervongitster
authored andcommitted
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 <[email protected]>
1 parent e1b3a2c commit e496c00

File tree

4 files changed

+151
-137
lines changed

4 files changed

+151
-137
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ LIB_OBJS = \
317317
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
318318
color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
319319
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
321321

322322
BUILTIN_OBJS = \
323323
builtin-add.o \

branch.c

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 2 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "builtin.h"
1313
#include "remote.h"
1414
#include "parse-options.h"
15+
#include "branch.h"
1516

1617
static const char * const builtin_branch_usage[] = {
1718
"git-branch [options] [-r | -a]",
@@ -356,141 +357,6 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str
356357
free_ref_list(&ref_list);
357358
}
358359

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-
494360
static void rename_branch(const char *oldname, const char *newname, int force)
495361
{
496362
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)
611477
else if (rename && (argc == 2))
612478
rename_branch(argv[0], argv[1], rename > 1);
613479
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,
615481
force_create, reflog, track);
616482
else
617483
usage_with_options(builtin_branch_usage, options);

0 commit comments

Comments
 (0)