Actually, how about making the default configurable _AND_ have
the --no-track option (for scripting)?
Fine by me. And also --track in case you want to try it out. ;-)
I made it default true, environment.c can be changed by Junio if he
applies the patch.
Patch attached. --remove-section will go in a separate patch.
Paolo
* git-branch: register where to merge from, when branching off a remote branch.
A rather standard (in 1.5) procedure for branching off a remote archive is:
git checkout -b branchname remote/upstreambranch
git config --add branch.branchname.remote remote
git config --add branch.branchname.merge refs/heads/upstreambranch
In this case, we can save the user some effort if "git branch" (and
"git checkout -b") automatically do the two "git-config --add"s when the
source branch is remote. There is a good chance that some user wants
to merge something different, but in that case they have to specify what
to merge _anyway_.
The behavior is controlled by core.trackremotebranches, and can be
fine-grained to a specific invocation of "git branch" using the new
--track and --no-track options.
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index aa1fdd4..14dc07d 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -9,7 +9,7 @@ SYNOPSIS
--------
[verse]
'git-branch' [--color | --no-color] [-r | -a] [-v [--abbrev=<length>]]
-'git-branch' [-l] [-f] <branchname> [<start-point>]
+'git-branch' [--track | --no-track] [-l] [-f] <branchname> [<start-point>]
'git-branch' (-m | -M) [<oldbranch>] <newbranch>
'git-branch' (-d | -D) [-r] <branchname>...
@@ -25,6 +25,12 @@ It will start out with a head equal to the one given as <start-point>.
If no <start-point> is given, the branch will be created with a head
equal to that of the currently checked out branch.
+When a local branch is started off a remote branch, git will setup
+the branch so that gitlink:git-pull[1] will appropriately merge from
+that remote branch. If this behavior is undesired, it is possible
+to change it using the `core.trackremotebranches` option, or the
+`--track` and `--no-track` options.
+
With a '-m' or '-M' option, <oldbranch> will be renamed to <newbranch>.
If <oldbranch> had a corresponding reflog, it is renamed to match
<newbranch>, and a reflog entry is created to remember the branch
diff --git a/builtin-branch.c b/builtin-branch.c
index d0179b0..20de049 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -12,7 +12,7 @@
#include "builtin.h"
static const char builtin_branch_usage[] =
- "git-branch [-r] (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length>]]";
+ "git-branch [-r] (-d | -D) <branchname> | [--track | --no-track] [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length>]]";
#define REF_UNKNOWN_TYPE 0x00
#define REF_LOCAL_BRANCH 0x01
@@ -308,15 +307,36 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev)
free_ref_list(&ref_list);
}
+static void register_branch_pull (const char *name, const char *remote_name)
+{
+ char *slash = strchr(remote_name, '/');
+
+ char *config_key = xmalloc(strlen(name) + 15);
+ char *merge_value = xmalloc(strlen(remote_name) + 10);
+
+ char *remote_value = xstrdup(remote_name);
+ remote_value[slash - remote_name] = 0;
+ sprintf(config_key, "branch.%s.remote", name);
+ git_config_set(config_key, remote_value);
+
+ sprintf(merge_value, "refs/heads/%s", slash + 1);
+ sprintf(config_key, "branch.%s.merge", name);
+ git_config_set(config_key, merge_value);
+
+ free (config_key);
+ free (remote_value);
+ free (merge_value);
+}
+
static void create_branch(const char *name, const char *start_name,
unsigned char *start_sha1,
- int force, int reflog)
+ int force, int reflog, int track)
{
struct ref_lock *lock;
struct commit *commit;
unsigned char sha1[20];
- char ref[PATH_MAX], msg[PATH_MAX + 20];
- int forcing = 0;
+ char *real_ref = NULL, ref[PATH_MAX], msg[PATH_MAX + 20];
+ int forcing = 0, remote = 0;
snprintf(ref, sizeof ref, "refs/heads/%s", name);
if (check_ref_format(ref))
@@ -333,7 +353,9 @@ static void create_branch(const char *name, const char *start_name,
if (start_sha1)
/* detached HEAD */
hashcpy(sha1, start_sha1);
- else if (get_sha1(start_name, sha1))
+ else if (dwim_ref(start_name, strlen (start_name), sha1, &real_ref))
+ remote = !prefixcmp(real_ref, "refs/remotes/");
+ else
die("Not a valid object name: '%s'.", start_name);
if ((commit = lookup_commit_reference(sha1)) == NULL)
@@ -354,8 +376,16 @@ static void create_branch(const char *name, const char *start_name,
snprintf(msg, sizeof msg, "branch: Created from %s",
start_name);
+ /* When branching off a remote branch, set up so that git-pull
+ automatically merges from there. */
+ if (remote && track)
+ register_branch_pull (name, real_ref + 13);
+
if (write_ref_sha1(lock, sha1, msg) < 0)
die("Failed to write ref: %s.", strerror(errno));
+
+ if (real_ref)
+ free (real_ref);
}
static void rename_branch(const char *oldname, const char *newname, int force)
@@ -397,11 +427,12 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
int delete = 0, force_delete = 0, force_create = 0;
int rename = 0, force_rename = 0;
int verbose = 0, abbrev = DEFAULT_ABBREV, detached = 0;
- int reflog = 0;
+ int reflog = 0, track;
int kinds = REF_LOCAL_BRANCH;
int i;
git_config(git_branch_config);
+ track = track_remote_branches;
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
@@ -412,6 +443,14 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
i++;
break;
}
+ if (!strcmp(arg, "--track")) {
+ track = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--no-track")) {
+ track = 0;
+ continue;
+ }
if (!strcmp(arg, "-d")) {
delete = 1;
continue;
@@ -490,9 +529,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
else if (rename && (i == argc - 2))
rename_branch(argv[i], argv[i + 1], force_rename);
else if (i == argc - 1)
- create_branch(argv[i], head, head_sha1, force_create, reflog);
+ create_branch(argv[i], head, head_sha1, force_create, reflog,
+ track);
else if (i == argc - 2)
- create_branch(argv[i], argv[i+1], NULL, force_create, reflog);
+ create_branch(argv[i], argv[i+1], NULL, force_create, reflog,
+ track);
else
usage(builtin_branch_usage);
diff --git a/cache.h b/cache.h
index 8bbc142..585a9b4 100644
--- a/cache.h
+++ b/cache.h
@@ -205,6 +205,7 @@ extern int trust_executable_bit;
extern int assume_unchanged;
extern int prefer_symlink_refs;
extern int log_all_ref_updates;
+extern int track_remote_branches;
extern int warn_ambiguous_refs;
extern int shared_repository;
extern const char *apply_default_whitespace;
diff --git a/config.c b/config.c
index 0ff413b..49df7bd 100644
--- a/config.c
+++ b/config.c
@@ -294,6 +294,11 @@ int git_default_config(const char *var, const char *value)
return 0;
}
+ if (!strcmp(var, "core.trackremotebranches")) {
+ track_remote_branches = git_config_bool(var, value);
+ return 0;
+ }
+
if (!strcmp(var, "core.legacyheaders")) {
use_legacy_headers = git_config_bool(var, value);
return 0;
diff --git a/environment.c b/environment.c
index 570e32a..e440d05 100644
--- a/environment.c
+++ b/environment.c
@@ -17,6 +17,7 @@ int assume_unchanged;
int prefer_symlink_refs;
int is_bare_repository_cfg = -1; /* unspecified */
int log_all_ref_updates = -1; /* unspecified */
+int track_remote_branches = 1;
int warn_ambiguous_refs = 1;
int repository_format_version;
char *git_commit_encoding;