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

Re: [PATCH v6 5/5] branch: add --recurse-submodules option for branch creation

From
Glen Choo <chooglen@google.com>
Date
Jan 11, 2022, 18:11 UTC
Message-ID
<kl6l4k6akurn.fsf@chooglen-macbookpro.roam.corp.google.com>
In-Reply-To
<20220111032842.1247928-1-jonathantanmy@google.com>
Jonathan Tan <jonathantanmy@google.com> writes:
Show 31 quoted lines
> I am not very familiar with branch tracking, so I'll review everything
> except that part.
>
> Glen Choo <chooglen@google.com> writes:
>> Although this commit does not introduce breaking changes, it is
>> incompatible with existing --recurse-submodules semantics e.g. `git
>> checkout` does not recursively checkout the expected branches created by
>> `git branch` yet. 
>
> Probably worth explaining that it will not recursively checkout the
> expected branches *if* any of them are subsequently updated. Maybe say:
>
>   If a user were to create branches in this way, create a commit on the
>   branch in a submodule, and run "git checkout --recurse-submodules" in
>   the superproject, the commits to be checked out (which are based on
>   the gitlink in the superproject, not on the ref store of the
>   submodule) probably wouldn't match the user's expectation.
>
>> To ensure that the correct set of semantics is used,
>> this commit introduces a new configuration value,
>> `submodule.propagateBranches`, which enables submodule branching when
>> true (defaults to false).
>
> And then this could be reworded to:
>
>   Because of this, this commit introduces a new configuration value
>   `submodule.propagateBranches`. The plan is for Git commands to
>   prioritize submodule ref store information over superproject gitlink
>   if this is true. Because "git branch --recurse-submodules" writes to
>   submodule ref stores, for the sake of clarity, it will not function
>   unless this configuration value is set.

Thanks! I'll use this wording - otherwise it might not be clear to readers what the difference in 'semantics' refers to.

Show 17 quoted lines
>
>> @@ -71,6 +68,23 @@ submodule.recurse::
>>  	`git fetch` but does not have a `--no-recurse-submodules` option.
>>  	For these commands a workaround is to temporarily change the
>>  	configuration value by using `git -c submodule.recurse=0`.
>> +	+
>> +	The following list shows the commands that accept
>> +	`--recurse-submodules` and whether they are supported by this
>> +	setting.
>> +	* `checkout`, `fetch`, `grep`, `pull`, `push`, `read-tree`,
>> +	`reset`, `restore` and `switch` are always supported.
>> +	* `clone` and `ls-files` are not supported.
>> +	* `branch` is supported only if `submodule.propagateBranches` is
>> +	enabled
>
> One oddity is that paragraphs after the "+" cannot be indented - see
> other documentation files for examples.

Ah, thanks for the catch. Interestingly, it still rendered as expected when I ran `make` - perhaps a deviation from the asciidoc spec.

Show 26 quoted lines
>> diff --git a/branch.c b/branch.c
>> index 55c7ba4a25..6d0d9a8e1b 100644
>> --- a/branch.c
>> +++ b/branch.c
>> @@ -8,6 +8,8 @@
>>  #include "sequencer.h"
>>  #include "commit.h"
>>  #include "worktree.h"
>> +#include "submodule-config.h"
>> +#include "run-command.h"
>>  
>>  struct tracking {
>>  	struct refspec_item spec;
>> @@ -478,6 +480,134 @@ void dwim_and_setup_tracking(struct repository *r, const char *new_ref,
>>  	setup_tracking(new_ref, real_orig_ref, track, quiet);
>>  }
>>  
>> +/**
>> + * Creates a branch in a submodule by calling
>> + * create_branches_recursively() in a child process. The child process
>> + * is necessary because install_branch_config() (and its variants) do
>> + * not support writing configs to submodules.
>> + */
>
> Makes sense that we need a child process, but could the child process be
> "branch" instead of "submodule--helper"? If not, also mention why.

I'll mention why it has to be "submodule--helper"; I can see why a reader might wonder this.

> As for the reason, probably better to explicitly mention
> install_branch_config_multiple_remotes() and say "(which is called by
> setup_tracking())".
Sounds good.
Show 62 quoted lines
>> diff --git a/t/t3207-branch-submodule.sh b/t/t3207-branch-submodule.sh
>> new file mode 100755
>> index 0000000000..a2dfb5ad7f
>> --- /dev/null
>> +++ b/t/t3207-branch-submodule.sh
>> @@ -0,0 +1,291 @@
>> +#!/bin/sh
>> +
>> +test_description='git branch submodule tests'
>> +
>> +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
>> +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
>> +
>> +. ./test-lib.sh
>> +. "$TEST_DIRECTORY"/lib-rebase.sh
>> +
>> +test_expect_success 'setup superproject and submodule' '
>> +	git init super &&
>> +	test_commit foo &&
>> +	git init sub-sub-upstream &&
>> +	test_commit -C sub-sub-upstream foo &&
>> +	git init sub-upstream &&
>> +	# Submodule in a submodule
>> +	git -C sub-upstream submodule add "$TRASH_DIRECTORY/sub-sub-upstream" sub-sub &&
>> +	git -C sub-upstream commit -m "add submodule" &&
>> +	# Regular submodule
>> +	git -C super submodule add "$TRASH_DIRECTORY/sub-upstream" sub &&
>> +	# Submodule in a subdirectory
>> +	git -C super submodule add "$TRASH_DIRECTORY/sub-sub-upstream" second/sub &&
>> +	git -C super commit -m "add submodule" &&
>> +	git -C super config submodule.propagateBranches true &&
>> +	git -C super/sub submodule update --init
>> +'
>> +
>> +CLEANUP_SCRIPT_PATH="$TRASH_DIRECTORY/cleanup_branches.sh"
>> +
>> +cat >"$CLEANUP_SCRIPT_PATH" <<'EOF'
>> +	#!/bin/sh
>> +
>> +	super_dir="$1"
>> +	shift
>> +	(
>> +		cd "$super_dir" &&
>> +		git checkout main &&
>> +		for branch_name in "$@"; do
>> +			git branch -D "$branch_name"
>> +			git submodule foreach "$TRASH_DIRECTORY/cleanup_branches.sh . $branch_name || true"
>> +		done
>> +	)
>> +EOF
>> +chmod +x "$CLEANUP_SCRIPT_PATH"
>> +
>> +cleanup_branches() {
>> +	TRASH_DIRECTORY="\"$TRASH_DIRECTORY\"" "$CLEANUP_SCRIPT_PATH" "$@"
>> +} >/dev/null 2>/dev/null
>
> I don't think that the cleanup is saving much in process invocation
> anymore - could we just delete the whole thing and start anew in each
> test?
>
> The rest of the tests are assuming that the cleanup works as expected -
> I didn't take a close look.

Hm, you're right - deleting the branches is already quite slow, starting anew would be easier and might not be much slower. I'll test the 'starting anew' approach to make sure it's not too slow.

> Also, you should probably use "$(pwd)" instead of $TRASH_DIRECTORY.
Thanks!
Show 14 quoted lines
>> +test_expect_success '--recurse-submodules should fail when not creating branches' '
>> +	test_when_finished "cleanup_branches super branch-a" &&
>> +	(
>> +		cd super &&
>> +		git branch --recurse-submodules branch-a &&
>> +		test_must_fail git branch --recurse-submodules -D branch-a &&
>> +		# Assert that the branches were not deleted
>> +		git rev-parse --abbrev-ref branch-a &&
>> +		git -C sub rev-parse --abbrev-ref branch-a
>> +	)
>> +'
>
> If we're just checking that the ref exists, no need for "--abbrev-ref".
> Same comment throughout the file.
Ah yes, thanks.
Show 18 quoted lines
>> +test_expect_success 'should not create any branches if branch is not valid for all repos' '
>> +	test_when_finished "cleanup_branches super branch-a" &&
>> +	(
>> +		cd super &&
>> +		git -C sub branch branch-a &&
>> +		test_must_fail git branch --recurse-submodules branch-a 2>actual &&
>> +		test_must_fail git rev-parse branch-a &&
>> +
>> +		cat >expected <<-EOF &&
>> +		submodule ${SQ}sub${SQ}: fatal: A branch named ${SQ}branch-a${SQ} already exists.
>> +		fatal: submodule ${SQ}sub${SQ}: cannot create branch ${SQ}branch-a${SQ}
>> +		EOF
>> +		test_cmp expected actual
>> +	)
>> +'
>
> The error message seems too specific - probably enough to grep for the
> information about the branch already existing.
Makes sense.
Show 17 quoted lines
>
>> +test_expect_success 'should create branches if branch exists and --force is given' '
>> +	test_when_finished "cleanup_branches super branch-a" &&
>> +	(
>> +		cd super &&
>> +		git -C sub rev-parse HEAD >expected &&
>> +		test_commit -C sub baz &&
>> +		git -C sub branch branch-a HEAD~1 &&
>> +		git branch --recurse-submodules --force branch-a &&
>> +		git rev-parse branch-a &&
>> +		# assert that sub:branch-a was moved
>> +		git -C sub rev-parse branch-a >actual &&
>> +		test_cmp expected actual
>> +	)
>> +'
>
> Should we create branch-a at HEAD instead of HEAD~1?

If we create branch-a at HEAD, we won't be testing that --force moves the branch head. This means that the test might pass if we simply ignore any existing branch-a - which is not the intended behavior of --force, but this is behavior that we might want in the future (probably using another option).

Show 22 quoted lines
>> +test_expect_success 'should create branch when submodule is not in HEAD:.gitmodules' '
>> +	test_when_finished "cleanup_branches super branch-a branch-b branch-c" &&
>> +	(
>> +		cd super &&
>> +		git branch branch-a &&
>> +		git checkout -b branch-b &&
>> +		git submodule add ../sub-upstream sub2 &&
>> +		git -C sub2 submodule update --init &&
>> +		# branch-b now has a committed submodule not in branch-a
>> +		git commit -m "add second submodule" &&
>> +		git checkout branch-a &&
>> +		git branch --recurse-submodules branch-c branch-b &&
>> +		git rev-parse branch-c &&
>> +		git -C sub rev-parse branch-c &&
>> +		git -C second/sub rev-parse branch-c &&
>> +		git checkout --recurse-submodules branch-c &&
>> +		git -C sub2 rev-parse branch-c &&
>> +		git -C sub2/sub-sub rev-parse branch-c
>> +	)
>> +'
>
> No need to check so many repos, I think - just sub2 will do.

Hm yes, there isn't a reason to think that the branch wouldn't be created in the other repos.

Show 16 quoted lines
>
> [skip tracking tests]
>
>> +test_expect_success 'should not create branches in inactive submodules' '
>> +	test_when_finished "cleanup_branches super branch-a" &&
>> +	test_config -C super submodule.sub.active false &&
>> +	(
>> +		cd super &&
>> +		git branch --recurse-submodules branch-a &&
>> +		git rev-parse branch-a &&
>> +		test_must_fail git -C sub branch-a
>> +	)
>> +'
>
> Makes sense, but could all the tracking tests be together in the file?
> Or is this order for a reason?

No, you're right, the order doesn't make sense. I'll move this to before the tracking tests.

>> +test_expect_success 'setup remote-tracking tests' '
>
> This setup is not just for remote-tracking tests.
Yes, this is misleading, thanks.
Show 18 quoted lines
>
>> +	(
>> +		cd super &&
>> +		git branch branch-a &&
>> +		git checkout -b branch-b &&
>> +		git submodule add ../sub-upstream sub2 &&
>> +		# branch-b now has a committed submodule not in branch-a
>> +		git commit -m "add second submodule"
>> +	) &&
>> +	git clone --branch main --recurse-submodules super super-clone &&
>> +	git -C super-clone config submodule.propagateBranches true
>> +'
>> +
>> +test_expect_success 'should not create branch when submodule is not in .git/modules' '
>
> I understand that no branch is created, but the title is ambiguous, to
> me, whether it is a fatal error or not. Maybe the title should be "fatal
> error upon branch creation when submodule is not in .git/modules".
Ok, makes sense.
Show 15 quoted lines
>
>> +	# The cleanup needs to delete sub2 separately because main does not have sub2
>> +	test_when_finished "git -C super-clone/sub2 branch -D branch-b && \
>> +		git -C super-clone/sub2/sub-sub branch -D branch-b && \
>> +		cleanup_branches super-clone branch-a branch-b" &&
>> +	(
>> +		cd super-clone &&
>> +		# This should succeed because super-clone has sub.
>
> "has sub in .git/modules", I think.
>
>> +		git branch --recurse-submodules branch-a origin/branch-a &&
>> +		# This should fail because super-clone does not have sub2.
>
> Likewise.
Ah, yes, it might be confusing otherwise.
Previous: Jonathan TanNext: Jonathan Tan
Message 81 of 110 in “implement branch --recurse-submodules”
  1. 0/4 implement branch --recurse-submodulesGlen Choo, Nov 22, 2021
  2. 1/4 submodule-config: add submodules_of_tree() helperGlen Choo, Nov 22, 2021
  3. Jonathan TanNov 23, 2021
  4. Glen ChooNov 23, 2021
  5. Ævar Arnfjörð BjarmasonNov 23, 2021
  6. Glen ChooNov 23, 2021
  7. Junio C HamanoNov 23, 2021
  8. 2/4 branch: refactor out branch validation from create_branch()Glen Choo, Nov 22, 2021
  9. 3/4 branch: add --dry-run option to branchGlen Choo, Nov 22, 2021
  10. Ævar Arnfjörð BjarmasonNov 23, 2021
  11. Glen ChooNov 23, 2021
  12. Jonathan TanNov 23, 2021
  13. Glen ChooNov 24, 2021
  14. 4/4 branch: add --recurse-submodules option for branch creationGlen Choo, Nov 22, 2021
  15. Ævar Arnfjörð BjarmasonNov 23, 2021
  16. Glen ChooNov 23, 2021
  17. Philippe BlainNov 23, 2021
  18. Glen ChooNov 23, 2021
  19. Jonathan TanNov 24, 2021
  20. Glen ChooNov 24, 2021
  21. Jonathan TanNov 29, 2021
  22. 0/3 implement branch --recurse-submodulesGlen Choo, Dec 6, 2021
  23. 1/3 branch: move --set-upstream-to behavior to setup_tracking()Glen Choo, Dec 6, 2021
  24. Junio C HamanoDec 6, 2021
  25. Glen ChooDec 8, 2021
  26. Junio C HamanoDec 6, 2021
  27. Glen ChooDec 8, 2021
  28. 2/3 builtin/branch: clean up action-picking logic in cmd_branch()Glen Choo, Dec 6, 2021
  29. 3/3 branch: add --recurse-submodules option for branch creationGlen Choo, Dec 6, 2021
  30. 0/5 implement branch --recurse-submodulesGlen Choo, Dec 9, 2021
  31. 1/5 branch: move --set-upstream-to behavior to setup_tracking()Glen Choo, Dec 9, 2021
  32. Jonathan TanDec 9, 2021
  33. Glen ChooDec 9, 2021
  34. 2/5 branch: remove forward declaration of validate_branch_start()Glen Choo, Dec 9, 2021
  35. 3/5 builtin/branch: clean up action-picking logic in cmd_branch()Glen Choo, Dec 9, 2021
  36. Jonathan TanDec 9, 2021
  37. Glen ChooDec 9, 2021
  38. 4/5 branch: add --recurse-submodules option for branch creationGlen Choo, Dec 9, 2021
  39. Philippe BlainDec 11, 2021
  40. Glen ChooDec 14, 2021
  41. 5/5 branch.c: replace questionable exit() codesGlen Choo, Dec 9, 2021
  42. Ævar Arnfjörð BjarmasonDec 10, 2021
  43. Glen ChooDec 10, 2021
  44. Junio C HamanoDec 13, 2021
  45. Ævar Arnfjörð BjarmasonDec 13, 2021
  46. Junio C HamanoDec 13, 2021
  47. Jonathan TanDec 9, 2021
  48. Glen ChooDec 9, 2021
  49. Jonathan TanDec 13, 2021
  50. Glen ChooDec 14, 2021
  51. 0/5 implement branch --recurse-submodulesGlen Choo, Dec 16, 2021
  52. 1/5 branch: move --set-upstream-to behavior to dwim_and_setup_tracking()Glen Choo, Dec 16, 2021
  53. 2/5 branch: make create_branch() always create a branchGlen Choo, Dec 16, 2021
  54. 3/5 branch: add a dry_run parameter to create_branch()Glen Choo, Dec 16, 2021
  55. 4/5 builtin/branch: clean up action-picking logic in cmd_branch()Glen Choo, Dec 16, 2021
  56. 5/5 branch: add --recurse-submodules option for branch creationGlen Choo, Dec 16, 2021
  57. 0/5 implement branch --recurse-submodulesGlen Choo, Dec 16, 2021
  58. 1/5 branch: move --set-upstream-to behavior to dwim_and_setup_tracking()Glen Choo, Dec 16, 2021
  59. 2/5 branch: make create_branch() always create a branchGlen Choo, Dec 16, 2021
  60. 3/5 branch: add a dry_run parameter to create_branch()Glen Choo, Dec 16, 2021
  61. 4/5 builtin/branch: clean up action-picking logic in cmd_branch()Glen Choo, Dec 16, 2021
  62. 5/5 branch: add --recurse-submodules option for branch creationGlen Choo, Dec 16, 2021
  63. Junio C HamanoDec 17, 2021
  64. Junio C HamanoDec 17, 2021
  65. Glen ChooDec 20, 2021
  66. Junio C HamanoDec 20, 2021
  67. Glen ChooDec 20, 2021
  68. 0/5 implement branch --recurse-submodulesGlen Choo, Dec 20, 2021
  69. 1/5 branch: move --set-upstream-to behavior to dwim_and_setup_tracking()Glen Choo, Dec 20, 2021
  70. Jonathan TanJan 11, 2022
  71. Glen ChooJan 11, 2022
  72. Jonathan TanJan 11, 2022
  73. 2/5 branch: make create_branch() always create a branchGlen Choo, Dec 20, 2021
  74. Jonathan TanJan 11, 2022
  75. Glen ChooJan 11, 2022
  76. 3/5 branch: add a dry_run parameter to create_branch()Glen Choo, Dec 20, 2021
  77. 4/5 builtin/branch: clean up action-picking logic in cmd_branch()Glen Choo, Dec 20, 2021
  78. 5/5 branch: add --recurse-submodules option for branch creationGlen Choo, Dec 20, 2021
  79. Junio C HamanoDec 26, 2021
  80. Jonathan TanJan 11, 2022
  81. Glen ChooJan 11, 2022
  82. Jonathan TanJan 11, 2022
  83. Glen ChooJan 11, 2022
  84. Glen ChooDec 20, 2021
  85. Junio C HamanoDec 21, 2021
  86. Glen ChooDec 21, 2021
  87. 0/6 implement branch --recurse-submodulesGlen Choo, Jan 24, 2022
  88. 2/6 branch: make create_branch() always create a branchGlen Choo, Jan 24, 2022
  89. 1/6 branch: move --set-upstream-to behavior to dwim_and_setup_tracking()Glen Choo, Jan 24, 2022
  90. 3/6 branch: add a dry_run parameter to create_branch()Glen Choo, Jan 24, 2022
  91. 4/6 builtin/branch: consolidate action-picking logic in cmd_branch()Glen Choo, Jan 24, 2022
  92. 5/6 branch: add --recurse-submodules option for branch creationGlen Choo, Jan 24, 2022
  93. Jonathan TanJan 27, 2022
  94. Glen ChooJan 27, 2022
  95. Glen ChooJan 27, 2022
  96. 6/6 branch.c: use 'goto cleanup' in setup_tracking() to fix memory leaksGlen Choo, Jan 24, 2022
  97. Junio C HamanoJan 27, 2022
  98. Glen ChooJan 28, 2022
  99. 0/6 implement branch --recurse-submodulesGlen Choo, Jan 29, 2022
  100. 1/6 branch: move --set-upstream-to behavior to dwim_and_setup_tracking()Glen Choo, Jan 29, 2022
  101. 2/6 branch: make create_branch() always create a branchGlen Choo, Jan 29, 2022
  102. Junio C HamanoFeb 1, 2022
  103. 3/6 branch: add a dry_run parameter to create_branch()Glen Choo, Jan 29, 2022
  104. 4/6 builtin/branch: consolidate action-picking logic in cmd_branch()Glen Choo, Jan 29, 2022
  105. 5/6 branch: add --recurse-submodules option for branch creationGlen Choo, Jan 29, 2022
  106. Glen ChooFeb 4, 2022
  107. Junio C HamanoFeb 4, 2022
  108. Glen ChooFeb 4, 2022
  109. 6/6 branch.c: use 'goto cleanup' in setup_tracking() to fix memory leaksGlen Choo, Jan 29, 2022
  110. Jonathan TanFeb 1, 2022

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.