git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] defaults for where to merge from (take 2)

From
Paolo Bonzini <paolo.bonzini@gmail.com>
Date
Mar 1, 2007, 07:52 UTC
Message-ID
<45E68648.6090407@lu.unisi.ch>
In-Reply-To
<Pine.LNX.4.63.0702281903470.22628@wbgn013.biozentrum.uni-wuerzburg.de>
> I'd rather remove the complete section (However, that means that you have 
> to introduce a function to do that in config.c)
No problem.
> Also, the second part of your patch would be clearer (methinks) if you 
> replaced the call to get_sha1() with dwim_ref(). You'd get the real 
> refname for free...

Not only that, my previous version did not work if somebody specified remotes/remote/upstreambranch instead of remote/upstreambranch.

Updated version attached.
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_.

Dually, we remove the branch.branchname section when the user does "git branch -d".

diff --git a/builtin-branch.c b/builtin-branch.c
index d0179b0..c1563cf 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -147,8 +147,16 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
 			error("Error deleting %sbranch '%s'", remote,
 			       argv[i]);
 			ret = 1;
-		} else
+		} else {
+			/* Remove git-config keys.  */
+			if (kinds == REF_LOCAL_BRANCH) {
+				char *config_key = xmalloc(strlen(argv[i]) + 8);
+				sprintf(config_key, "branch.%s", argv[i]);
+				git_config_remove_section(config_key);
+			}
+
 			printf("Deleted %sbranch %s.\n", remote, argv[i]);
+		}
 
 	}
 
@@ -308,6 +316,27 @@ 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)
@@ -315,8 +344,8 @@ static void create_branch(const char *name, const char *start_name,
 	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 +362,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 +385,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)
+		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)
diff --git a/cache.h b/cache.h
index 8bbc142..797483b 100644
--- a/cache.h
+++ b/cache.h
@@ -438,6 +438,7 @@ extern int git_config_bool(const char *, const char *);
 extern int git_config_set(const char *, const char *);
 extern int git_config_set_multivar(const char *, const char *, const char *, int);
 extern int git_config_rename_section(const char *, const char *);
+extern int git_config_remove_section(const char *);
 extern int check_repository_format_version(const char *var, const char *value);
 
 #define MAX_GITNAME (1000)
diff --git a/config.c b/config.c
index 0ff413b..acd83aa 100644
--- a/config.c
+++ b/config.c
@@ -854,6 +854,33 @@ write_err_out:
 
 }
 
+static int section_name_match (const char *buf, const char *name)
+{
+	int i = 0, j = 0, dot = 0;
+	for (; buf[i] && buf[i] != ']'; i++) {
+		if (!dot && isspace(buf[i])) {
+			dot = 1;
+			if (name[j++] != '.')
+				break;
+			for (i++; isspace(buf[i]); i++)
+				; /* do nothing */
+			if (buf[i] != '"')
+				break;
+			continue;
+		}
+		if (buf[i] == '\\' && dot)
+			i++;
+		else if (buf[i] == '"' && dot) {
+			for (i++; isspace(buf[i]); i++)
+				; /* do_nothing */
+			break;
+		}
+		if (buf[i] != name[j++])
+			break;
+	}
+	return (buf[i] == ']' && name[j] == 0);
+}
+
 int git_config_rename_section(const char *old_name, const char *new_name)
 {
 	int ret = 0;
@@ -885,40 +912,15 @@ int git_config_rename_section(const char *old_name, const char *new_name)
 		int length;
 		for (i = 0; buf[i] && isspace(buf[i]); i++)
 			; /* do nothing */
-		if (buf[i] == '[') {
+		if (buf[i] == '[' && section_name_match (&buf[i+1], old_name)) {
 			/* it's a section */
-			int j = 0, dot = 0;
-			for (i++; buf[i] && buf[i] != ']'; i++) {
-				if (!dot && isspace(buf[i])) {
-					dot = 1;
-					if (old_name[j++] != '.')
-						break;
-					for (i++; isspace(buf[i]); i++)
-						; /* do nothing */
-					if (buf[i] != '"')
-						break;
-					continue;
-				}
-				if (buf[i] == '\\' && dot)
-					i++;
-				else if (buf[i] == '"' && dot) {
-					for (i++; isspace(buf[i]); i++)
-						; /* do_nothing */
-					break;
-				}
-				if (buf[i] != old_name[j++])
-					break;
-			}
-			if (buf[i] == ']' && old_name[j] == 0) {
-				/* old_name matches */
-				ret++;
-				store.baselen = strlen(new_name);
-				if (!store_write_section(out_fd, new_name)) {
-					ret = write_error();
-					goto out;
-				}
-				continue;
+			ret++;
+			store.baselen = strlen(new_name);
+			if (!store_write_section(out_fd, new_name)) {
+				ret = write_error();
+				goto out;
 			}
+			continue;
 		}
 		length = strlen(buf);
 		if (write_in_full(out_fd, buf, length) != length) {
@@ -934,3 +936,58 @@ int git_config_rename_section(const char *old_name, const char *new_name)
 	return ret;
 }
 
+int git_config_remove_section(const char *name)
+{
+	int ret = 0;
+	char *config_filename;
+	struct lock_file *lock = xcalloc(sizeof(struct lock_file), 1);
+	int out_fd;
+	int removing = 0;
+	char buf[1024];
+
+	config_filename = getenv(CONFIG_ENVIRONMENT);
+	if (!config_filename) {
+		config_filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
+		if (!config_filename)
+			config_filename  = git_path("config");
+	}
+	config_filename = xstrdup(config_filename);
+	out_fd = hold_lock_file_for_update(lock, config_filename, 0);
+	if (out_fd < 0) {
+		ret = error("Could not lock config file!");
+		goto out;
+	}
+
+	if (!(config_file = fopen(config_filename, "rb"))) {
+		ret = error("Could not open config file!");
+		goto out;
+	}
+
+	while (fgets(buf, sizeof(buf), config_file)) {
+		int i;
+		int length;
+		for (i = 0; buf[i] && isspace(buf[i]); i++)
+			; /* do nothing */
+		if (buf[i] == '[') {
+			if (section_name_match (&buf[i + 1], name)) {
+				/* name matches */
+				ret++;
+				removing = 1;
+			} else
+				removing = 0;
+		}
+		if (removing)
+			continue;
+		length = strlen(buf);
+		if (write_in_full(out_fd, buf, length) != length) {
+			ret = write_error();
+			goto out;
+		}
+	}
+	fclose(config_file);
+	if (close(out_fd) || commit_lock_file(lock) < 0)
+			ret = error("Cannot commit config file!");
+ out:
+	free(config_filename);
+	return ret;
+}
Previous: Johannes SchindelinNext: Alex Riesen
Message 10 of 48 in “defaults for where to merge from”
  1. Paolo BonziniFeb 28, 2007
  2. Johannes SchindelinFeb 28, 2007
  3. Andy ParkinsFeb 28, 2007
  4. Paolo BonziniFeb 28, 2007
  5. Andy ParkinsFeb 28, 2007
  6. Julian PhillipsFeb 28, 2007
  7. Johannes SchindelinFeb 28, 2007
  8. Paolo BonziniFeb 28, 2007
  9. Johannes SchindelinFeb 28, 2007
  10. defaults for where to merge from (take 2)Paolo Bonzini, Mar 1, 2007
  11. Alex RiesenFeb 28, 2007
  12. Paolo BonziniFeb 28, 2007
  13. Alex RiesenMar 1, 2007
  14. Johannes SchindelinMar 1, 2007
  15. Alex RiesenMar 1, 2007
  16. Paolo BonziniMar 1, 2007
  17. Alex RiesenMar 1, 2007
  18. Junio C HamanoMar 1, 2007
  19. J. Bruce FieldsMar 2, 2007
  20. Paolo BonziniMar 1, 2007
  21. Alex RiesenMar 1, 2007
  22. Paolo BonziniMar 1, 2007
  23. Alex RiesenMar 1, 2007
  24. defaults for where to merge from (take 3)Paolo Bonzini, Mar 1, 2007
  25. Alex RiesenMar 1, 2007
  26. Paolo BonziniMar 1, 2007
  27. Junio C HamanoMar 1, 2007
  28. Alex RiesenMar 1, 2007
  29. Junio C HamanoMar 2, 2007
  30. Alex RiesenMar 2, 2007
  31. Junio C HamanoMar 2, 2007
  32. Alex RiesenMar 1, 2007
  33. Paolo BonziniMar 1, 2007
  34. Johannes SchindelinMar 1, 2007
  35. Paolo BonziniMar 2, 2007
  36. git-branch: register where to merge from, when branching off a remote branchPaolo Bonzini, Mar 2, 2007
  37. Junio C HamanoMar 2, 2007
  38. Junio C HamanoMar 2, 2007
  39. Jeff KingMar 2, 2007
  40. Paolo BonziniMar 2, 2007
  41. Jeff KingMar 2, 2007
  42. Paolo BonziniMar 2, 2007
  43. Johannes SchindelinMar 2, 2007
  44. Paolo BonziniMar 2, 2007
  45. Johannes SchindelinMar 2, 2007
  46. Johannes SchindelinMar 2, 2007
  47. Jakub NarebskiMar 2, 2007
  48. Peter BaumannFeb 28, 2007

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.