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

[PATCH v2 0/2] Support updating working trees when pushing into non-bare repos

From
Johannes Schindelin <johannes.schindelin@gmx.de>
Date
Nov 10, 2014, 14:38 UTC
Message-ID
<cover.1415629053.git.johannes.schindelin@gmx.de>
In-Reply-To
<cover.1415368490.git.johannes.schindelin@gmx.de>

This patch series adds support for two new receive.denyCurrentBranch settings: one to update the working directory (which must be clean, i.e. there must not be any uncommitted changes) when pushing into the current branch, the other setting detaches the HEAD instead.

The scenario in which in particular the 'updateInstead' setting became a boon in this developer's daily work is when trying to get a bug fix from a Windows computer, a virtual machine or a user's machine onto his main machine (in all of those cases it is only possible to connect via ssh in one direction, but not in the reverse direction).

Interdiff vs v1 below the diffstat.
Johannes Schindelin (2):
  Clean stale environment pointer in finish_command()
  Add a few more options for receive.denyCurrentBranch
 Documentation/config.txt |  9 ++++++++
 builtin/receive-pack.c   | 60 ++++++++++++++++++++++++++++++++++++++++++++++--
 run-command.c            |  3 +++
 t/t5516-fetch-push.sh    | 36 +++++++++++++++++++++++++++++
 4 files changed, 106 insertions(+), 2 deletions(-)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 6fc0d6d..fc9b8db 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -2130,10 +2130,14 @@ receive.denyCurrentBranch::
 	proceed. If set to false or "ignore", allow such pushes with no
 	message. Defaults to "refuse".
 +
-There are two more options: "updateInstead" which will update the working
-directory (must be clean) if pushing into the current branch, and
-"detachInstead" which will leave the working directory untouched, detaching
-the HEAD so it does not need to change.
+Another option is "updateInstead" which will update the working
+directory (must be clean) if pushing into the current branch. This option is
+intended for synchronizing working directories when one side is not easily
+accessible via ssh (e.g. inside a VM).
++
+Yet another option is "detachInstead" which will detach the HEAD if updates
+are pushed into the current branch; That way, the current revision, the
+index and the working directory are always left untouched by pushes.
 
 receive.denyNonFastForwards::
 	If set to true, git-receive-pack will deny a ref update which is
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 2b2d797..7db860f 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.2.0-rc0
+DEF_VER=v2.2.0-rc1
 
 LF='
 '
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 4ba51df..4534e88 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -28,7 +28,7 @@ enum deny_action {
 	DENY_WARN,
 	DENY_REFUSE,
 	DENY_UPDATE_INSTEAD,
-	DENY_DETACH_INSTEAD,
+	DENY_DETACH_INSTEAD
 };
 
 static int deny_deletes;
@@ -737,7 +737,7 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
 	return 0;
 }
 
-static void merge_worktree(unsigned char *sha1)
+static const char *merge_worktree(unsigned char *sha1)
 {
 	const char *update_refresh[] = {
 		"update-index", "--ignore-submodules", "--refresh", NULL
@@ -745,41 +745,36 @@ static void merge_worktree(unsigned char *sha1)
 	const char *read_tree[] = {
 		"read-tree", "-u", "-m", sha1_to_hex(sha1), NULL
 	};
-	struct child_process child;
-	struct strbuf git_env = STRBUF_INIT;
-	const char *env[2];
+	struct child_process child = CHILD_PROCESS_INIT;
 
 	if (is_bare_repository())
-		die ("denyCurrentBranch = updateInstead needs a worktree");
-
-	strbuf_addf(&git_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
-	env[0] = git_env.buf;
-	env[1] = NULL;
+		return "denyCurrentBranch = updateInstead needs a worktree";
 
-	memset(&child, 0, sizeof(child));
+	argv_array_pushf(&child.env_array, "GIT_DIR=%s", absolute_path(get_git_dir()));
 	child.argv = update_refresh;
-	child.env = env;
 	child.dir = git_work_tree_cfg ? git_work_tree_cfg : "..";
 	child.stdout_to_stderr = 1;
 	child.git_cmd = 1;
 	if (run_command(&child))
-		die ("Could not refresh the index");
+		die("Could not refresh the index");
 
+	/* finish_command cleared the environment; reinitialize */
+	argv_array_pushf(&child.env_array, "GIT_DIR=%s", absolute_path(get_git_dir()));
 	child.argv = read_tree;
 	child.no_stdin = 1;
 	child.no_stdout = 1;
 	child.stdout_to_stderr = 0;
 	if (run_command(&child))
-		die ("Could not merge working tree with new HEAD.  Good luck.");
+		die("Could not merge working tree with new HEAD.");
 
-	strbuf_release(&git_env);
+	return NULL;
 }
 
 static const char *update(struct command *cmd, struct shallow_info *si)
 {
 	const char *name = cmd->ref_name;
 	struct strbuf namespaced_name_buf = STRBUF_INIT;
-	const char *namespaced_name;
+	const char *namespaced_name, *ret;
 	unsigned char *old_sha1 = cmd->old_sha1;
 	unsigned char *new_sha1 = cmd->new_sha1;
 
@@ -806,11 +801,17 @@ static const char *update(struct command *cmd, struct shallow_info *si)
 				refuse_unconfigured_deny();
 			return "branch is currently checked out";
 		case DENY_UPDATE_INSTEAD:
-			merge_worktree(new_sha1);
+			ret = merge_worktree(new_sha1);
+			if (ret)
+				return ret;
 			break;
 		case DENY_DETACH_INSTEAD:
-			update_ref("push into current branch (detach)", "HEAD",
-				old_sha1, NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
+			ret = update_ref("push into current branch (detach)",
+				"HEAD", old_sha1, NULL, REF_NODEREF,
+				UPDATE_REFS_DIE_ON_ERR) ?
+				"Could not detach HEAD" : NULL;
+			if (ret)
+				return ret;
 			break;
 		}
 	}
diff --git a/run-command.c b/run-command.c
index 79a0a76..85578da 100644
--- a/run-command.c
+++ b/run-command.c
@@ -555,6 +555,9 @@ int finish_command(struct child_process *cmd)
 {
 	int ret = wait_or_whine(cmd->pid, cmd->argv[0]);
 	argv_array_clear(&cmd->args);
+	/* Avoid pointing to a stale environment */
+	if (cmd->env == cmd->env_array.argv)
+		cmd->env = NULL;
 	argv_array_clear(&cmd->env_array);
 	return ret;
 }
-- 
2.0.0.rc3.9669.g840d1f9
Previous: Johannes SchindelinNext: Johannes Schindelin
Message 40 of 71 in “Support updating working trees when pushing into non-bare repos”
  1. 0/2 Support updating working trees when pushing into non-bare reposJohannes Schindelin, Nov 7, 2014
  2. 1/2 Add a few more values for receive.denyCurrentBranchJohannes Schindelin, Nov 7, 2014
  3. Junio C HamanoNov 7, 2014
  4. Johannes SchindelinNov 7, 2014
  5. Johannes SchindelinNov 10, 2014
  6. Junio C HamanoNov 10, 2014
  7. Johannes SchindelinNov 12, 2014
  8. Junio C HamanoNov 12, 2014
  9. Jeff KingNov 8, 2014
  10. brian m. carlsonNov 8, 2014
  11. Johannes SchindelinNov 10, 2014
  12. 2/2 Let deny.currentBranch=updateInstead ignore submodulesJohannes Schindelin, Nov 7, 2014
  13. Junio C HamanoNov 7, 2014
  14. Jens LehmannNov 9, 2014
  15. Johannes SchindelinNov 10, 2014
  16. Johannes SchindelinNov 10, 2014
  17. Junio C HamanoNov 10, 2014
  18. Junio C HamanoNov 10, 2014
  19. Johannes SchindelinNov 12, 2014
  20. Junio C HamanoNov 12, 2014
  21. Johannes SchindelinNov 13, 2014
  22. Johannes SchindelinNov 13, 2014
  23. Junio C HamanoNov 13, 2014
  24. Johannes SchindelinNov 13, 2014
  25. Junio C HamanoNov 13, 2014
  26. Junio C HamanoNov 13, 2014
  27. Junio C HamanoNov 14, 2014
  28. Junio C HamanoDec 2, 2014
  29. 2/2 receive-pack: support push-to-checkout hookJunio C Hamano, Dec 2, 2014
  30. Johannes SchindelinDec 2, 2014
  31. Michael J GruberDec 2, 2014
  32. Johannes SchindelinDec 2, 2014
  33. Junio C HamanoDec 2, 2014
  34. Johannes SchindelinDec 2, 2014
  35. Junio C HamanoDec 2, 2014
  36. Johannes SchindelinDec 2, 2014
  37. Junio C HamanoDec 2, 2014
  38. Junio C HamanoNov 13, 2014
  39. Johannes SchindelinNov 12, 2014
  40. 0/2 Support updating working trees when pushing into non-bare reposJohannes Schindelin, Nov 10, 2014
  41. 0/1 Support updating working trees when pushing into non-bare reposJohannes Schindelin, Nov 13, 2014
  42. 1/1 Add another option for receive.denyCurrentBranchJohannes Schindelin, Nov 13, 2014
  43. Junio C HamanoNov 13, 2014
  44. Johannes SchindelinNov 13, 2014
  45. Junio C HamanoNov 13, 2014
  46. Junio C HamanoNov 13, 2014
  47. Johannes SchindelinNov 13, 2014
  48. Support updating working trees when pushing into non-bare reposJohannes Schindelin, Nov 26, 2014
  49. Add another option for receive.denyCurrentBranchJohannes Schindelin, Nov 26, 2014
  50. Junio C HamanoNov 26, 2014
  51. Support updating working trees when pushing into non-bare reposJohannes Schindelin, Nov 26, 2014
  52. Add another option for receive.denyCurrentBranchJohannes Schindelin, Nov 26, 2014
  53. Junio C HamanoDec 1, 2014
  54. Johannes SchindelinDec 1, 2014
  55. Junio C HamanoDec 1, 2014
  56. Junio C HamanoDec 2, 2014
  57. Johannes SchindelinDec 2, 2014
  58. Junio C HamanoDec 2, 2014
  59. Johannes SchindelinDec 2, 2014
  60. Junio C HamanoDec 2, 2014
  61. 1/2 Clean stale environment pointer in finish_command()Johannes Schindelin, Nov 10, 2014
  62. Johannes SchindelinNov 10, 2014
  63. Jeff KingNov 11, 2014
  64. Junio C HamanoNov 11, 2014
  65. Johannes SchindelinNov 12, 2014
  66. Jeff KingNov 12, 2014
  67. Jeff KingNov 12, 2014
  68. Junio C HamanoNov 12, 2014
  69. Junio C HamanoNov 10, 2014
  70. Jeff KingNov 11, 2014
  71. 2/2 Add a few more options for receive.denyCurrentBranchJohannes Schindelin, Nov 10, 2014

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.