git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH 00/30] subtree: clean up, improve UX
@ 2021-04-23 19:42 Luke Shumaker
  2021-04-23 19:42 ` [PATCH 01/30] .gitignore: Ignore /git-subtree Luke Shumaker
                   ` (31 more replies)
  0 siblings, 32 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Ostensibly, this patch set is about improving various aspects of `git
subtree`'s user interface (and it is!), but it's also mostly about
setting the foundation and being "batch 1" of a bunch more changes to
subtree that I'm getting queued up.  So please forgive the large
amount of churn in the leading clean-up commits, I promise that
there's more work coming on top of it (we've discovered lots of ways
to break the "subtree split" algorithm, and come up with fixes for
most of them).  In the mean-time, I do think that the UX improvements
in this patchset are already worth it themselves.

 - The first 11 commits improve subtree's tests, largely around the
   code-quality of the tests, but a few of the commits do actually
   improve what's being tested.

 - The middle 12 commits improve the code-quality of subtree's
   implementation.

 - The final 7 commits improve various aspects of subtree's user
   experience, from readability of the debug output, to documentation,
   to option flag handling.

The very last commit is likely to be a little objectionable--it makes
some option flag parsing more strict, so there will probably be worry
that the change breaks existing users.  However, it's being strict
about arg combinations that were always invalid, the difference is
that now it reports that to the users and bails.  Those users were
already broken, they just didn't know it.  `git subtree` should tell
them.

As a final question, would it be all right to amend CI to run the
subtree tests?  And if so, what would be the best way to do it?  For
my own testing, I just made the following edit to the main Makefile,
but I'm not sure it's the mos appropriate approach:

    --- a/Makefile
    +++ b/Makefile
    @@ -2836,6 +2836,7 @@
     
     test: all
            $(MAKE) -C t/ all
    +       $(MAKE) -C contrib/subtree/ test
     
     perf: all
            $(MAKE) -C t/perf/ all

The first two commits are about getting that to pass.  I'd prefer to
avoid that type of bitrot in the future.

Luke Shumaker (30):
  .gitignore: Ignore /git-subtree
  subtree: t7900: update for having the default branch name be 'main'
  subtree: t7900: use test-lib.sh's test_count
  subtree: t7900: use consistent formatting
  subtree: t7900: comment subtree_test_create_repo
  subtree: t7900: use 'test' for string equality
  subtree: t7900: delete some dead code
  subtree: t7900: fix 'verify one file change per commit'
  subtree: t7900: rename last_commit_message to last_commit_subject
  subtree: t7900: add a test for the -h flag
  subtree: t7900: add porcelain tests for 'pull' and 'push'
  subtree: don't have loose code outside of a function
  subtree: more consistent error propagation
  subtree: drop support for git < 1.7
  subtree: use `git merge-base --is-ancestor`
  subtree: use git-sh-setup's `say`
  subtree: use more explicit variable names for cmdline args
  subtree: use $* instead of $@ as appropriate
  subtree: give `$(git --exec-path)` precedence over `$PATH`
  subtree: use "^{commit}" instead of "^0"
  subtree: parse revs in individual cmd_ functions
  subtree: remove duplicate check
  subtree: add comments and sanity checks
  subtree: don't let debug and progress output clash
  subtree: have $indent actually affect indentation
  subtree: give the docs a once-over
  subtree: allow --squash to be used with --rejoin
  subtree: allow 'split' flags to be passed to 'push'
  subtree: push: allow specifying a local rev other than HEAD
  subtree: be stricter about validating flags

 .gitignore                         |    1 +
 contrib/subtree/git-subtree.sh     |  613 +++++++-----
 contrib/subtree/git-subtree.txt    |  184 ++--
 contrib/subtree/t/t7900-subtree.sh | 1421 ++++++++++++++++++----------
 4 files changed, 1363 insertions(+), 856 deletions(-)

-- 
2.31.1

Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* [PATCH 01/30] .gitignore: Ignore /git-subtree
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 02/30] subtree: t7900: update for having the default branch name be 'main' Luke Shumaker
                   ` (30 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Running `make -C contrib/subtree/ test` creates a `git-subtree` executable
in the root of the repo.  Add it to the .gitignore so that anyone hacking
on subtree won't have to deal with that noise.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index 3dcdb6bb5a..a203678e9e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -162,6 +162,7 @@
 /git-stripspace
 /git-submodule
 /git-submodule--helper
+/git-subtree
 /git-svn
 /git-switch
 /git-symbolic-ref
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 02/30] subtree: t7900: update for having the default branch name be 'main'
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
  2021-04-23 19:42 ` [PATCH 01/30] .gitignore: Ignore /git-subtree Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 03/30] subtree: t7900: use test-lib.sh's test_count Luke Shumaker
                   ` (29 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Most of the tests had been converted to support
`GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main`, but `contrib/subtree/t/`
hadn't.

Convert it.  Most of the mentions of 'master' can just be replaced with
'HEAD'.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 117 +++++++++++++++--------------
 1 file changed, 59 insertions(+), 58 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 57ff4b25c1..4b982e6c2e 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -103,7 +103,7 @@ test_expect_success 'no merge from non-existent subtree' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		test_must_fail git subtree merge --prefix="sub dir" FETCH_HEAD
 	)
 '
@@ -116,8 +116,8 @@ test_expect_success 'no pull from non-existent subtree' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
-		test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" master
+		git fetch ./"sub proj" HEAD &&
+		test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" HEAD
 	)'
 
 next_test
@@ -128,7 +128,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Add '\''sub dir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
@@ -142,7 +142,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix and --me
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Added subproject"
 	)
@@ -156,7 +156,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix as -P an
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add -P "sub dir" -m "Added subproject" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Added subproject"
 	)
@@ -170,7 +170,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --squash and --pr
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject with squash" --squash FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Added subproject with squash"
 	)
@@ -188,13 +188,13 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count/sub proj" sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
@@ -208,13 +208,13 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix and -
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count/sub proj" sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merged changes from subproject"
 	)
@@ -228,13 +228,13 @@ test_expect_success 'merge new subproj history into sub dir/ with --squash and -
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count/sub proj" sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject using squash" --squash FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merged changes from subproject using squash"
 	)
@@ -248,7 +248,7 @@ test_expect_success 'merge the added subproj again, should do nothing' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		# this shouldn not actually do anything, since FETCH_HEAD
 		# is already a parent
@@ -265,13 +265,13 @@ test_expect_success 'merge new subproj history into subdir/ with a slash appende
 	test_create_commit "$test_count/subproj" sub1 &&
 	(
 		cd "$test_count" &&
-		git fetch ./subproj master &&
+		git fetch ./subproj HEAD &&
 		git subtree add --prefix=subdir/ FETCH_HEAD
 	) &&
 	test_create_commit "$test_count/subproj" sub2 &&
 	(
 		cd "$test_count" &&
-		git fetch ./subproj master &&
+		git fetch ./subproj HEAD &&
 		git subtree merge --prefix=subdir/ FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
@@ -289,7 +289,7 @@ test_expect_success 'split requires option --prefix' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		echo "You must provide the --prefix option." > expected &&
 		test_must_fail git subtree split > actual 2>&1 &&
@@ -309,7 +309,7 @@ test_expect_success 'split requires path given by option --prefix must exist' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		echo "'\''non-existent-directory'\'' does not exist; use '\''git subtree add'\''" > expected &&
 		test_must_fail git subtree split --prefix=non-existent-directory > actual 2>&1 &&
@@ -329,7 +329,7 @@ test_expect_success 'split sub dir/ with --rejoin' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -338,7 +338,7 @@ test_expect_success 'split sub dir/ with --rejoin' '
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --rejoin &&
@@ -370,7 +370,7 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -379,7 +379,7 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --message="Split & rejoin" --annotate="*" --rejoin &&
 		check_equal "$(last_commit_message)" "Split & rejoin"
@@ -394,7 +394,7 @@ test_expect_success 'split "sub dir"/ with --branch' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -403,7 +403,7 @@ test_expect_success 'split "sub dir"/ with --branch' '
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br &&
@@ -419,7 +419,7 @@ test_expect_success 'check hash of split' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -428,7 +428,7 @@ test_expect_success 'check hash of split' '
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br &&
@@ -451,7 +451,7 @@ test_expect_success 'split "sub dir"/ with --branch for an existing branch' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git branch subproj-br FETCH_HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
@@ -461,7 +461,7 @@ test_expect_success 'split "sub dir"/ with --branch for an existing branch' '
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br &&
@@ -478,7 +478,7 @@ test_expect_success 'split "sub dir"/ with --branch for an incompatible branch'
 	(
 		cd "$subtree_test_count" &&
 		git branch init HEAD &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -487,7 +487,7 @@ test_expect_success 'split "sub dir"/ with --branch for an incompatible branch'
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		test_must_fail git subtree split --prefix="sub dir" --branch init
 	)
@@ -505,7 +505,7 @@ test_expect_success 'make sure exactly the right set of files ends up in the sub
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -514,7 +514,7 @@ test_expect_success 'make sure exactly the right set of files ends up in the sub
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
@@ -555,7 +555,7 @@ test_expect_success 'make sure the subproj *only* contains commits that affect t
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -564,7 +564,7 @@ test_expect_success 'make sure the subproj *only* contains commits that affect t
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
@@ -606,7 +606,7 @@ test_expect_success 'make sure exactly the right set of files ends up in the mai
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -615,7 +615,7 @@ test_expect_success 'make sure exactly the right set of files ends up in the mai
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
@@ -643,7 +643,7 @@ test_expect_success 'make sure exactly the right set of files ends up in the mai
 	) &&
 	(
 		cd "$subtree_test_count" &&
-		git subtree pull --prefix="sub dir" ./"sub proj" master &&
+		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		test_write_lines main1 main2 >chkm &&
 		test_write_lines main-sub1 main-sub2 main-sub3 main-sub4 >chkms &&
@@ -666,7 +666,7 @@ test_expect_success 'make sure each filename changed exactly once in the entire
 	(
 		cd "$subtree_test_count" &&
 		git config log.date relative &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -675,7 +675,7 @@ test_expect_success 'make sure each filename changed exactly once in the entire
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
@@ -703,7 +703,7 @@ test_expect_success 'make sure each filename changed exactly once in the entire
 	) &&
 	(
 		cd "$subtree_test_count" &&
-		git subtree pull --prefix="sub dir" ./"sub proj" master &&
+		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		test_write_lines main1 main2 >chkm &&
 		test_write_lines sub1 sub2 sub3 sub4 >chks &&
@@ -731,7 +731,7 @@ test_expect_success 'make sure the --rejoin commits never make it into subproj'
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -740,7 +740,7 @@ test_expect_success 'make sure the --rejoin commits never make it into subproj'
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
@@ -768,7 +768,7 @@ test_expect_success 'make sure the --rejoin commits never make it into subproj'
 	) &&
 	(
 		cd "$subtree_test_count" &&
-		git subtree pull --prefix="sub dir" ./"sub proj" master &&
+		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 		check_equal "$(git log --pretty=format:"%s" HEAD^2 | grep -i split)" ""
 	)
 '
@@ -781,7 +781,7 @@ test_expect_success 'make sure no "git subtree" tagged commits make it into subp
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -790,7 +790,7 @@ test_expect_success 'make sure no "git subtree" tagged commits make it into subp
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
@@ -818,7 +818,7 @@ test_expect_success 'make sure no "git subtree" tagged commits make it into subp
 	) &&
 	(
 		cd "$subtree_test_count" &&
-		git subtree pull --prefix="sub dir" ./"sub proj" master &&
+		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		# They are meaningless to subproj since one side of the merge refers to the mainline
 		check_equal "$(git log --pretty=format:"%s%n%b" HEAD^2 | grep "git-subtree.*:")" ""
@@ -837,13 +837,13 @@ test_expect_success 'make sure "git subtree split" find the correct parent' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count/sub proj" sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git branch subproj-ref FETCH_HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
@@ -853,7 +853,7 @@ test_expect_success 'make sure "git subtree split" find the correct parent' '
 		git subtree split --prefix="sub dir" --branch subproj-br &&
 
 		# at this point, the new commit parent should be subproj-ref, if it is
-		# not, something went wrong (the "newparent" of "master~" commit should
+		# not, something went wrong (the "newparent" of "HEAD~" commit should
 		# have been sub2, but it was not, because its cache was not set to
 		# itself)
 		check_equal "$(git log --pretty=format:%P -1 subproj-br)" "$(git rev-parse subproj-ref)"
@@ -868,13 +868,13 @@ test_expect_success 'split a new subtree without --onto option' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count/sub proj" sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -903,14 +903,14 @@ test_expect_success 'verify one file change per commit' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git branch sub1 FETCH_HEAD &&
 		git subtree add --prefix="sub dir" sub1
 	) &&
 	test_create_commit "$subtree_test_count/sub proj" sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -947,7 +947,7 @@ test_expect_success 'push split to subproj' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -958,7 +958,7 @@ test_expect_success 'push split to subproj' '
 		cd $subtree_test_count/"sub proj" &&
                 git branch sub-branch-1 &&
                 cd .. &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
@@ -994,6 +994,7 @@ test_expect_success 'push split to subproj' '
 next_test
 test_expect_success 'subtree descendant check' '
 	subtree_test_create_repo "$subtree_test_count" &&
+	defaultBranch=$(sed "s,ref: refs/heads/,," "$subtree_test_count/.git/HEAD") &&
 	test_create_commit "$subtree_test_count" folder_subtree/a &&
 	(
 		cd "$subtree_test_count" &&
@@ -1010,7 +1011,7 @@ test_expect_success 'subtree descendant check' '
 	(
 		cd "$subtree_test_count" &&
 		git cherry-pick $cherry &&
-		git checkout master &&
+		git checkout $defaultBranch &&
 		git merge -m "merge should be kept on subtree" branch &&
 		git branch no_subtree_work_branch
 	) &&
@@ -1022,10 +1023,10 @@ test_expect_success 'subtree descendant check' '
 	test_create_commit "$subtree_test_count" not_a_subtree_change &&
 	(
 		cd "$subtree_test_count" &&
-		git checkout master &&
+		git checkout $defaultBranch &&
 		git merge -m "merge should be skipped on subtree" no_subtree_work_branch &&
 
-		git subtree split --prefix folder_subtree/ --branch subtree_tip master &&
+		git subtree split --prefix folder_subtree/ --branch subtree_tip $defaultBranch &&
 		git subtree split --prefix folder_subtree/ --branch subtree_branch branch &&
 		check_equal $(git rev-list --count subtree_tip..subtree_branch) 0
 	)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 03/30] subtree: t7900: use test-lib.sh's test_count
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
  2021-04-23 19:42 ` [PATCH 01/30] .gitignore: Ignore /git-subtree Luke Shumaker
  2021-04-23 19:42 ` [PATCH 02/30] subtree: t7900: update for having the default branch name be 'main' Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 04/30] subtree: t7900: use consistent formatting Luke Shumaker
                   ` (28 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Use test-lib.sh's `test_count`, instead instead of having
t7900-subtree.sh do its own book-keeping with `subtree_test_count` that
has to be explicitly incremented by calling `next_test`.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 636 ++++++++++++++---------------
 1 file changed, 300 insertions(+), 336 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 4b982e6c2e..a6351d9195 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -86,90 +86,79 @@ last_commit_message()
 	git log --pretty=format:%s -1
 }
 
-subtree_test_count=0
-next_test() {
-	subtree_test_count=$(($subtree_test_count+1))
-}
-
 #
 # Tests for 'git subtree add'
 #
 
-next_test
 test_expect_success 'no merge from non-existent subtree' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		test_must_fail git subtree merge --prefix="sub dir" FETCH_HEAD
 	)
 '
 
-next_test
 test_expect_success 'no pull from non-existent subtree' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" HEAD
 	)'
 
-next_test
 test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Add '\''sub dir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
-next_test
 test_expect_success 'add subproj as subtree into sub dir/ with --prefix and --message' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Added subproject"
 	)
 '
 
-next_test
 test_expect_success 'add subproj as subtree into sub dir/ with --prefix as -P and --message as -m' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add -P "sub dir" -m "Added subproject" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Added subproject"
 	)
 '
 
-next_test
 test_expect_success 'add subproj as subtree into sub dir/ with --squash and --prefix and --message' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject with squash" --squash FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Added subproject with squash"
@@ -180,74 +169,70 @@ test_expect_success 'add subproj as subtree into sub dir/ with --squash and --pr
 # Tests for 'git subtree merge'
 #
 
-next_test
 test_expect_success 'merge new subproj history into sub dir/ with --prefix' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
-next_test
 test_expect_success 'merge new subproj history into sub dir/ with --prefix and --message' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merged changes from subproject"
 	)
 '
 
-next_test
 test_expect_success 'merge new subproj history into sub dir/ with --squash and --prefix and --message' '
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	subtree_test_create_repo "$subtree_test_count" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	subtree_test_create_repo "$test_count" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject using squash" --squash FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merged changes from subproject using squash"
 	)
 '
 
-next_test
 test_expect_success 'merge the added subproj again, should do nothing' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		# this shouldn not actually do anything, since FETCH_HEAD
@@ -257,7 +242,6 @@ test_expect_success 'merge the added subproj again, should do nothing' '
 	)
 '
 
-next_test
 test_expect_success 'merge new subproj history into subdir/ with a slash appended to the argument of --prefix' '
 	test_create_repo "$test_count" &&
 	test_create_repo "$test_count/subproj" &&
@@ -281,14 +265,13 @@ test_expect_success 'merge new subproj history into subdir/ with a slash appende
 # Tests for 'git subtree split'
 #
 
-next_test
 test_expect_success 'split requires option --prefix' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		echo "You must provide the --prefix option." > expected &&
@@ -301,14 +284,13 @@ test_expect_success 'split requires option --prefix' '
 	)
 '
 
-next_test
 test_expect_success 'split requires path given by option --prefix must exist' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		echo "'\''non-existent-directory'\'' does not exist; use '\''git subtree add'\''" > expected &&
@@ -321,23 +303,22 @@ test_expect_success 'split requires path given by option --prefix must exist' '
 	)
 '
 
-next_test
 test_expect_success 'split sub dir/ with --rejoin' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
@@ -346,12 +327,11 @@ test_expect_success 'split sub dir/ with --rejoin' '
 	)
  '
 
-next_test
 test_expect_success 'split sub dir/ with --rejoin from scratch' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	test_create_commit "$subtree_test_count" main1 &&
+	subtree_test_create_repo "$test_count" &&
+	test_create_commit "$test_count" main1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		mkdir "sub dir" &&
 		echo file >"sub dir"/file &&
 		git add "sub dir/file" &&
@@ -362,23 +342,22 @@ test_expect_success 'split sub dir/ with --rejoin from scratch' '
 	)
  '
 
-next_test
 test_expect_success 'split sub dir/ with --rejoin and --message' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --message="Split & rejoin" --annotate="*" --rejoin &&
@@ -386,23 +365,22 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
 	)
 '
 
-next_test
 test_expect_success 'split "sub dir"/ with --branch' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
@@ -411,23 +389,22 @@ test_expect_success 'split "sub dir"/ with --branch' '
 	)
 '
 
-next_test
 test_expect_success 'check hash of split' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
@@ -443,24 +420,23 @@ test_expect_success 'check hash of split' '
 	)
 '
 
-next_test
 test_expect_success 'split "sub dir"/ with --branch for an existing branch' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git branch subproj-br FETCH_HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
@@ -469,24 +445,23 @@ test_expect_success 'split "sub dir"/ with --branch for an existing branch' '
 	)
 '
 
-next_test
 test_expect_success 'split "sub dir"/ with --branch for an incompatible branch' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git branch init HEAD &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		test_must_fail git subtree split --prefix="sub dir" --branch init
@@ -497,46 +472,45 @@ test_expect_success 'split "sub dir"/ with --branch for an incompatible branch'
 # Validity checking
 #
 
-next_test
 test_expect_success 'make sure exactly the right set of files ends up in the subproj' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub3 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count/sub proj" sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub4 &&
+	test_create_commit "$test_count/sub proj" sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub4 &&
+	test_create_commit "$test_count" "sub dir"/main-sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD &&
 
@@ -547,46 +521,45 @@ test_expect_success 'make sure exactly the right set of files ends up in the sub
 	)
 '
 
-next_test
 test_expect_success 'make sure the subproj *only* contains commits that affect the "sub dir"' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub3 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count/sub proj" sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub4 &&
+	test_create_commit "$test_count/sub proj" sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub4 &&
+	test_create_commit "$test_count" "sub dir"/main-sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD &&
 
@@ -598,51 +571,50 @@ test_expect_success 'make sure the subproj *only* contains commits that affect t
 	)
 '
 
-next_test
 test_expect_success 'make sure exactly the right set of files ends up in the mainline' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub3 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count/sub proj" sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub4 &&
+	test_create_commit "$test_count/sub proj" sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub4 &&
+	test_create_commit "$test_count" "sub dir"/main-sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		test_write_lines main1 main2 >chkm &&
@@ -657,52 +629,51 @@ test_expect_success 'make sure exactly the right set of files ends up in the mai
 	)
 '
 
-next_test
 test_expect_success 'make sure each filename changed exactly once in the entire history' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git config log.date relative &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub3 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count/sub proj" sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub4 &&
+	test_create_commit "$test_count/sub proj" sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub4 &&
+	test_create_commit "$test_count" "sub dir"/main-sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		test_write_lines main1 main2 >chkm &&
@@ -723,101 +694,99 @@ test_expect_success 'make sure each filename changed exactly once in the entire
 	)
 '
 
-next_test
 test_expect_success 'make sure the --rejoin commits never make it into subproj' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub3 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count/sub proj" sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub4 &&
+	test_create_commit "$test_count/sub proj" sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub4 &&
+	test_create_commit "$test_count" "sub dir"/main-sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 		check_equal "$(git log --pretty=format:"%s" HEAD^2 | grep -i split)" ""
 	)
 '
 
-next_test
 test_expect_success 'make sure no "git subtree" tagged commits make it into subproj' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub3 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count/sub proj" sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		 git merge FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub4 &&
+	test_create_commit "$test_count/sub proj" sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub4 &&
+	test_create_commit "$test_count" "sub dir"/main-sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		# They are meaningless to subproj since one side of the merge refers to the mainline
@@ -829,27 +798,26 @@ test_expect_success 'make sure no "git subtree" tagged commits make it into subp
 # A new set of tests
 #
 
-next_test
 test_expect_success 'make sure "git subtree split" find the correct parent' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git branch subproj-ref FETCH_HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --branch subproj-br &&
 
 		# at this point, the new commit parent should be subproj-ref, if it is
@@ -860,32 +828,31 @@ test_expect_success 'make sure "git subtree split" find the correct parent' '
 	)
 '
 
-next_test
 test_expect_success 'split a new subtree without --onto option' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --branch subproj-br
 	) &&
-	mkdir "$subtree_test_count"/"sub dir2" &&
-	test_create_commit "$subtree_test_count" "sub dir2"/main-sub2 &&
+	mkdir "$test_count"/"sub dir2" &&
+	test_create_commit "$test_count" "sub dir2"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 
 		# also test that we still can split out an entirely new subtree
 		# if the parent of the first commit in the tree is not empty,
@@ -895,33 +862,32 @@ test_expect_success 'split a new subtree without --onto option' '
 	)
 '
 
-next_test
 test_expect_success 'verify one file change per commit' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git branch sub1 FETCH_HEAD &&
 		git subtree add --prefix="sub dir" sub1
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --branch subproj-br
 	) &&
-	mkdir "$subtree_test_count"/"sub dir2" &&
-	test_create_commit "$subtree_test_count" "sub dir2"/main-sub2 &&
+	mkdir "$test_count"/"sub dir2" &&
+	test_create_commit "$test_count" "sub dir2"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir2" --branch subproj2-br &&
 
 		x= &&
@@ -939,31 +905,30 @@ test_expect_success 'verify one file change per commit' '
 	)
 '
 
-next_test
 test_expect_success 'push split to subproj' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd $subtree_test_count/"sub proj" &&
+		cd $test_count/"sub proj" &&
                 git branch sub-branch-1 &&
                 cd .. &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
         (
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 	        git subtree push ./"sub proj" --prefix "sub dir" sub-branch-1 &&
                 cd ./"sub proj" &&
                 git checkout sub-branch-1 &&
@@ -991,38 +956,37 @@ test_expect_success 'push split to subproj' '
 #   set of commits.
 #
 
-next_test
 test_expect_success 'subtree descendant check' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	defaultBranch=$(sed "s,ref: refs/heads/,," "$subtree_test_count/.git/HEAD") &&
-	test_create_commit "$subtree_test_count" folder_subtree/a &&
+	subtree_test_create_repo "$test_count" &&
+	defaultBranch=$(sed "s,ref: refs/heads/,," "$test_count/.git/HEAD") &&
+	test_create_commit "$test_count" folder_subtree/a &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git branch branch
 	) &&
-	test_create_commit "$subtree_test_count" folder_subtree/0 &&
-	test_create_commit "$subtree_test_count" folder_subtree/b &&
-	cherry=$(cd "$subtree_test_count"; git rev-parse HEAD) &&
+	test_create_commit "$test_count" folder_subtree/0 &&
+	test_create_commit "$test_count" folder_subtree/b &&
+	cherry=$(cd "$test_count"; git rev-parse HEAD) &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git checkout branch
 	) &&
-	test_create_commit "$subtree_test_count" commit_on_branch &&
+	test_create_commit "$test_count" commit_on_branch &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git cherry-pick $cherry &&
 		git checkout $defaultBranch &&
 		git merge -m "merge should be kept on subtree" branch &&
 		git branch no_subtree_work_branch
 	) &&
-	test_create_commit "$subtree_test_count" folder_subtree/d &&
+	test_create_commit "$test_count" folder_subtree/d &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git checkout no_subtree_work_branch
 	) &&
-	test_create_commit "$subtree_test_count" not_a_subtree_change &&
+	test_create_commit "$test_count" not_a_subtree_change &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git checkout $defaultBranch &&
 		git merge -m "merge should be skipped on subtree" no_subtree_work_branch &&
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 04/30] subtree: t7900: use consistent formatting
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (2 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 03/30] subtree: t7900: use test-lib.sh's test_count Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 21:51   ` Eric Sunshine
  2021-04-23 19:42 ` [PATCH 05/30] subtree: t7900: comment subtree_test_create_repo Luke Shumaker
                   ` (27 subsequent siblings)
  31 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

The formatting in t7900-subtree.sh isn't even consistent throughout the
file.  Fix that; make it consistent throughout the file.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 47 +++++++++++++-----------------
 1 file changed, 21 insertions(+), 26 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index a6351d9195..74516513cd 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -11,11 +11,9 @@ and split subcommands of git subtree.
 
 TEST_DIRECTORY=$(pwd)/../../../t
 export TEST_DIRECTORY
+. "$TEST_DIRECTORY"/test-lib.sh
 
-. ../../../t/test-lib.sh
-
-subtree_test_create_repo()
-{
+subtree_test_create_repo () {
 	test_create_repo "$1" &&
 	(
 		cd "$1" &&
@@ -23,26 +21,24 @@ subtree_test_create_repo()
 	)
 }
 
-create()
-{
+create () {
 	echo "$1" >"$1" &&
 	git add "$1"
 }
 
-check_equal()
-{
+check_equal () {
 	test_debug 'echo'
 	test_debug "echo \"check a:\" \"{$1}\""
 	test_debug "echo \"      b:\" \"{$2}\""
-	if [ "$1" = "$2" ]; then
+	if [ "$1" = "$2" ]
+	then
 		return 0
 	else
 		return 1
 	fi
 }
 
-undo()
-{
+undo () {
 	git reset --hard HEAD~
 }
 
@@ -50,8 +46,7 @@ undo()
 # The original set of commits changed only one file each.
 # A multi-file change would imply that we pruned commits
 # too aggressively.
-join_commits()
-{
+join_commits () {
 	commit=
 	all=
 	while read x y; do
@@ -70,7 +65,7 @@ join_commits()
 	echo "$commit $all"
 }
 
-test_create_commit() (
+test_create_commit () (
 	repo=$1 &&
 	commit=$2 &&
 	cd "$repo" &&
@@ -81,8 +76,7 @@ test_create_commit() (
 	git commit -m "$commit" || error "Could not commit"
 )
 
-last_commit_message()
-{
+last_commit_message () {
 	git log --pretty=format:%s -1
 }
 
@@ -111,7 +105,8 @@ test_expect_success 'no pull from non-existent subtree' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" HEAD
-	)'
+	)
+'
 
 test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
 	subtree_test_create_repo "$test_count" &&
@@ -325,7 +320,7 @@ test_expect_success 'split sub dir/ with --rejoin' '
 		git subtree split --prefix="sub dir" --annotate="*" --rejoin &&
 		check_equal "$(last_commit_message)" "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
 	)
- '
+'
 
 test_expect_success 'split sub dir/ with --rejoin from scratch' '
 	subtree_test_create_repo "$test_count" &&
@@ -340,7 +335,7 @@ test_expect_success 'split sub dir/ with --rejoin from scratch' '
 		git subtree split --prefix="sub dir" --rejoin &&
 		check_equal "$(last_commit_message)" "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
 	)
- '
+'
 
 test_expect_success 'split sub dir/ with --rejoin and --message' '
 	subtree_test_create_repo "$test_count" &&
@@ -921,18 +916,18 @@ test_expect_success 'push split to subproj' '
 	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
 		cd $test_count/"sub proj" &&
-                git branch sub-branch-1 &&
-                cd .. &&
+		git branch sub-branch-1 &&
+		cd .. &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$test_count" "sub dir"/main-sub3 &&
-        (
+	(
 		cd "$test_count" &&
-	        git subtree push ./"sub proj" --prefix "sub dir" sub-branch-1 &&
-                cd ./"sub proj" &&
-                git checkout sub-branch-1 &&
-         	check_equal "$(last_commit_message)" "sub dir/main-sub3"
+		git subtree push ./"sub proj" --prefix "sub dir" sub-branch-1 &&
+		cd ./"sub proj" &&
+		git checkout sub-branch-1 &&
+		check_equal "$(last_commit_message)" "sub dir/main-sub3"
 	)
 '
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 05/30] subtree: t7900: comment subtree_test_create_repo
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (3 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 04/30] subtree: t7900: use consistent formatting Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 06/30] subtree: t7900: use 'test' for string equality Luke Shumaker
                   ` (26 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

It's unclear what the purpose of t7900-subtree.sh's
`subtree_test_create_repo` helper function is.  It wraps test-lib.sh's,
`test_create_repo` but follows that up by setting log.date=relative.  Why
does it set log.date=relative?

My first guess was that at one point the tests required that, but no
longer do, and that the function is now vestigial.  I even wrote a patch
to get rid of it and was moments away from `git send-email`ing it.

However, by chance when looking for something else in the history, I
discovered the true reason, from e7aac44ed2 (contrib/subtree: ignore
log.date configuration, 2015-07-21).  It's testing that setting
log.date=relative doesn't break `git subtree`, as at one point in the past
that did break `git subtree`.

So, add a comment about this, to avoid future such confusion.

And while at it, go ahead and touch up the function to avoid a pointless
subshell.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 74516513cd..827bd3fcd8 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -13,12 +13,14 @@ TEST_DIRECTORY=$(pwd)/../../../t
 export TEST_DIRECTORY
 . "$TEST_DIRECTORY"/test-lib.sh
 
+# Use our own wrapper around test-lib.sh's test_create_repo, in order
+# to set log.date=relative.  `git subtree` parses the output of `git
+# log`, and so it must be careful to not be affected by settings that
+# change the `git log` output.  We test this by setting
+# log.date=relative for every repo in the tests.
 subtree_test_create_repo () {
 	test_create_repo "$1" &&
-	(
-		cd "$1" &&
-		git config log.date relative
-	)
+	git -C "$1" config log.date relative
 }
 
 create () {
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 06/30] subtree: t7900: use 'test' for string equality
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (4 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 05/30] subtree: t7900: comment subtree_test_create_repo Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 07/30] subtree: t7900: delete some dead code Luke Shumaker
                   ` (25 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

t7900-subtree.sh defines its own `check_equal A B` function, instead of
just using `test A = B` like all of the other tests.  Don't be special,
get rid of `check_equal` in favor of `test`.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 60 ++++++++++++------------------
 1 file changed, 24 insertions(+), 36 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 827bd3fcd8..ae96c8cff5 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -28,18 +28,6 @@ create () {
 	git add "$1"
 }
 
-check_equal () {
-	test_debug 'echo'
-	test_debug "echo \"check a:\" \"{$1}\""
-	test_debug "echo \"      b:\" \"{$2}\""
-	if [ "$1" = "$2" ]
-	then
-		return 0
-	else
-		return 1
-	fi
-}
-
 undo () {
 	git reset --hard HEAD~
 }
@@ -119,7 +107,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Add '\''sub dir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
+		test "$(last_commit_message)" = "Add '\''sub dir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -132,7 +120,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix and --me
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject" FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Added subproject"
+		test "$(last_commit_message)" = "Added subproject"
 	)
 '
 
@@ -145,7 +133,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix as -P an
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add -P "sub dir" -m "Added subproject" FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Added subproject"
+		test "$(last_commit_message)" = "Added subproject"
 	)
 '
 
@@ -158,7 +146,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --squash and --pr
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject with squash" --squash FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Added subproject with squash"
+		test "$(last_commit_message)" = "Added subproject with squash"
 	)
 '
 
@@ -181,7 +169,7 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
+		test "$(last_commit_message)" = "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -200,7 +188,7 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix and -
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject" FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Merged changes from subproject"
+		test "$(last_commit_message)" = "Merged changes from subproject"
 	)
 '
 
@@ -219,7 +207,7 @@ test_expect_success 'merge new subproj history into sub dir/ with --squash and -
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject using squash" --squash FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Merged changes from subproject using squash"
+		test "$(last_commit_message)" = "Merged changes from subproject using squash"
 	)
 '
 
@@ -235,7 +223,7 @@ test_expect_success 'merge the added subproj again, should do nothing' '
 		# this shouldn not actually do anything, since FETCH_HEAD
 		# is already a parent
 		result=$(git merge -s ours -m "merge -s -ours" FETCH_HEAD) &&
-		check_equal "${result}" "Already up to date."
+		test "${result}" = "Already up to date."
 	)
 '
 
@@ -254,7 +242,7 @@ test_expect_success 'merge new subproj history into subdir/ with a slash appende
 		cd "$test_count" &&
 		git fetch ./subproj HEAD &&
 		git subtree merge --prefix=subdir/ FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
+		test "$(last_commit_message)" = "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -320,7 +308,7 @@ test_expect_success 'split sub dir/ with --rejoin' '
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --rejoin &&
-		check_equal "$(last_commit_message)" "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
+		test "$(last_commit_message)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
 	)
 '
 
@@ -335,7 +323,7 @@ test_expect_success 'split sub dir/ with --rejoin from scratch' '
 		git commit -m"sub dir file" &&
 		split_hash=$(git subtree split --prefix="sub dir" --rejoin) &&
 		git subtree split --prefix="sub dir" --rejoin &&
-		check_equal "$(last_commit_message)" "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
+		test "$(last_commit_message)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
 	)
 '
 
@@ -358,7 +346,7 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --message="Split & rejoin" --annotate="*" --rejoin &&
-		check_equal "$(last_commit_message)" "Split & rejoin"
+		test "$(last_commit_message)" = "Split & rejoin"
 	)
 '
 
@@ -382,7 +370,7 @@ test_expect_success 'split "sub dir"/ with --branch' '
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br &&
-		check_equal "$(git rev-parse subproj-br)" "$split_hash"
+		test "$(git rev-parse subproj-br)" = "$split_hash"
 	)
 '
 
@@ -406,13 +394,13 @@ test_expect_success 'check hash of split' '
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br &&
-		check_equal "$(git rev-parse subproj-br)" "$split_hash" &&
+		test "$(git rev-parse subproj-br)" = "$split_hash" &&
 		# Check hash of split
 		new_hash=$(git rev-parse subproj-br^2) &&
 		(
 			cd ./"sub proj" &&
 			subdir_hash=$(git rev-parse HEAD) &&
-			check_equal ''"$new_hash"'' "$subdir_hash"
+			test ''"$new_hash"'' = "$subdir_hash"
 		)
 	)
 '
@@ -438,7 +426,7 @@ test_expect_success 'split "sub dir"/ with --branch for an existing branch' '
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br &&
-		check_equal "$(git rev-parse subproj-br)" "$split_hash"
+		test "$(git rev-parse subproj-br)" = "$split_hash"
 	)
 '
 
@@ -736,7 +724,7 @@ test_expect_success 'make sure the --rejoin commits never make it into subproj'
 	(
 		cd "$test_count" &&
 		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
-		check_equal "$(git log --pretty=format:"%s" HEAD^2 | grep -i split)" ""
+		test "$(git log --pretty=format:"%s" HEAD^2 | grep -i split)" = ""
 	)
 '
 
@@ -787,7 +775,7 @@ test_expect_success 'make sure no "git subtree" tagged commits make it into subp
 		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		# They are meaningless to subproj since one side of the merge refers to the mainline
-		check_equal "$(git log --pretty=format:"%s%n%b" HEAD^2 | grep "git-subtree.*:")" ""
+		test "$(git log --pretty=format:"%s%n%b" HEAD^2 | grep "git-subtree.*:")" = ""
 	)
 '
 
@@ -821,7 +809,7 @@ test_expect_success 'make sure "git subtree split" find the correct parent' '
 		# not, something went wrong (the "newparent" of "HEAD~" commit should
 		# have been sub2, but it was not, because its cache was not set to
 		# itself)
-		check_equal "$(git log --pretty=format:%P -1 subproj-br)" "$(git rev-parse subproj-ref)"
+		test "$(git log --pretty=format:%P -1 subproj-br)" = "$(git rev-parse subproj-ref)"
 	)
 '
 
@@ -855,7 +843,7 @@ test_expect_success 'split a new subtree without --onto option' '
 		# if the parent of the first commit in the tree is not empty,
 		# then the new subtree has accidentally been attached to something
 		git subtree split --prefix="sub dir2" --branch subproj2-br &&
-		check_equal "$(git log --pretty=format:%P -1 subproj2-br)" ""
+		test "$(git log --pretty=format:%P -1 subproj2-br)" = ""
 	)
 '
 
@@ -894,10 +882,10 @@ test_expect_success 'verify one file change per commit' '
 				test_debug "echo Verifying commit $commit"
 				test_debug "echo a: $a"
 				test_debug "echo b: $b"
-				check_equal "$b" ""
+				test "$b" = ""
 				x=1
 			done
-			check_equal "$x" 1
+			test "$x" = 1
 		)
 	)
 '
@@ -929,7 +917,7 @@ test_expect_success 'push split to subproj' '
 		git subtree push ./"sub proj" --prefix "sub dir" sub-branch-1 &&
 		cd ./"sub proj" &&
 		git checkout sub-branch-1 &&
-		check_equal "$(last_commit_message)" "sub dir/main-sub3"
+		test "$(last_commit_message)" = "sub dir/main-sub3"
 	)
 '
 
@@ -989,7 +977,7 @@ test_expect_success 'subtree descendant check' '
 
 		git subtree split --prefix folder_subtree/ --branch subtree_tip $defaultBranch &&
 		git subtree split --prefix folder_subtree/ --branch subtree_branch branch &&
-		check_equal $(git rev-list --count subtree_tip..subtree_branch) 0
+		test $(git rev-list --count subtree_tip..subtree_branch) = 0
 	)
 '
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 07/30] subtree: t7900: delete some dead code
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (5 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 06/30] subtree: t7900: use 'test' for string equality Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 08/30] subtree: t7900: fix 'verify one file change per commit' Luke Shumaker
                   ` (24 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index ae96c8cff5..96acd4f8be 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -10,7 +10,6 @@ and split subcommands of git subtree.
 '
 
 TEST_DIRECTORY=$(pwd)/../../../t
-export TEST_DIRECTORY
 . "$TEST_DIRECTORY"/test-lib.sh
 
 # Use our own wrapper around test-lib.sh's test_create_repo, in order
@@ -23,15 +22,6 @@ subtree_test_create_repo () {
 	git -C "$1" config log.date relative
 }
 
-create () {
-	echo "$1" >"$1" &&
-	git add "$1"
-}
-
-undo () {
-	git reset --hard HEAD~
-}
-
 # Make sure no patch changes more than one file.
 # The original set of commits changed only one file each.
 # A multi-file change would imply that we pruned commits
@@ -400,7 +390,7 @@ test_expect_success 'check hash of split' '
 		(
 			cd ./"sub proj" &&
 			subdir_hash=$(git rev-parse HEAD) &&
-			test ''"$new_hash"'' = "$subdir_hash"
+			test "$new_hash" = "$subdir_hash"
 		)
 	)
 '
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 08/30] subtree: t7900: fix 'verify one file change per commit'
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (6 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 07/30] subtree: t7900: delete some dead code Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 09/30] subtree: t7900: rename last_commit_message to last_commit_subject Luke Shumaker
                   ` (23 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

As far as I can tell, this test isn't actually testing anything, because
someone forgot to tack on `--name-only` to `git log`.  This seems to
have been the case since the test was first written, back in fa16ab36ad
("test.sh: make sure no commit changes more than one file at a time.",
2009-04-26), unless `git log` used to do that by default and didn't need
the flag back then?

Convincing myself that it's not actually testing anything was tricky,
the code is a little hard to reason about.  It can be made a lot simpler
if instead of trying to parse all of the info from a single `git log`,
we're OK calling `git log` from inside of a loop.  And it's my opinion
that tests are not the place for clever optimized code.

So, fix and simplify the test, so that it's actually testing something
and is simpler to reason about.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 41 +++++-------------------------
 1 file changed, 6 insertions(+), 35 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 96acd4f8be..70be18246b 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -22,29 +22,6 @@ subtree_test_create_repo () {
 	git -C "$1" config log.date relative
 }
 
-# Make sure no patch changes more than one file.
-# The original set of commits changed only one file each.
-# A multi-file change would imply that we pruned commits
-# too aggressively.
-join_commits () {
-	commit=
-	all=
-	while read x y; do
-		if [ -z "$x" ]; then
-			continue
-		elif [ "$x" = "commit:" ]; then
-			if [ -n "$commit" ]; then
-				echo "$commit $all"
-				all=
-			fi
-			commit="$y"
-		else
-			all="$all $y"
-		fi
-	done
-	echo "$commit $all"
-}
-
 test_create_commit () (
 	repo=$1 &&
 	commit=$2 &&
@@ -865,18 +842,12 @@ test_expect_success 'verify one file change per commit' '
 		cd "$test_count" &&
 		git subtree split --prefix="sub dir2" --branch subproj2-br &&
 
-		x= &&
-		git log --pretty=format:"commit: %H" | join_commits |
-		(
-			while read commit a b; do
-				test_debug "echo Verifying commit $commit"
-				test_debug "echo a: $a"
-				test_debug "echo b: $b"
-				test "$b" = ""
-				x=1
-			done
-			test "$x" = 1
-		)
+		git log --format="%H" > commit-list &&
+		while read commit
+		do
+			git log -n1 --format="" --name-only "$commit" >file-list &&
+			test_line_count -le 1 file-list || return 1
+		done <commit-list
 	)
 '
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 09/30] subtree: t7900: rename last_commit_message to last_commit_subject
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (7 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 08/30] subtree: t7900: fix 'verify one file change per commit' Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 10/30] subtree: t7900: add a test for the -h flag Luke Shumaker
                   ` (22 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

t7900-subtree.sh defines a helper function named last_commit_message.
However, it only returns the subject line of the commit message, not the
entire commit message.  So rename it, to make the name less confusing.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 70be18246b..4c4d6c8e6b 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -33,7 +33,7 @@ test_create_commit () (
 	git commit -m "$commit" || error "Could not commit"
 )
 
-last_commit_message () {
+last_commit_subject () {
 	git log --pretty=format:%s -1
 }
 
@@ -74,7 +74,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
-		test "$(last_commit_message)" = "Add '\''sub dir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
+		test "$(last_commit_subject)" = "Add '\''sub dir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -87,7 +87,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix and --me
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject" FETCH_HEAD &&
-		test "$(last_commit_message)" = "Added subproject"
+		test "$(last_commit_subject)" = "Added subproject"
 	)
 '
 
@@ -100,7 +100,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix as -P an
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add -P "sub dir" -m "Added subproject" FETCH_HEAD &&
-		test "$(last_commit_message)" = "Added subproject"
+		test "$(last_commit_subject)" = "Added subproject"
 	)
 '
 
@@ -113,7 +113,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --squash and --pr
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject with squash" --squash FETCH_HEAD &&
-		test "$(last_commit_message)" = "Added subproject with squash"
+		test "$(last_commit_subject)" = "Added subproject with squash"
 	)
 '
 
@@ -136,7 +136,7 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
-		test "$(last_commit_message)" = "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
+		test "$(last_commit_subject)" = "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -155,7 +155,7 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix and -
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject" FETCH_HEAD &&
-		test "$(last_commit_message)" = "Merged changes from subproject"
+		test "$(last_commit_subject)" = "Merged changes from subproject"
 	)
 '
 
@@ -174,7 +174,7 @@ test_expect_success 'merge new subproj history into sub dir/ with --squash and -
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject using squash" --squash FETCH_HEAD &&
-		test "$(last_commit_message)" = "Merged changes from subproject using squash"
+		test "$(last_commit_subject)" = "Merged changes from subproject using squash"
 	)
 '
 
@@ -209,7 +209,7 @@ test_expect_success 'merge new subproj history into subdir/ with a slash appende
 		cd "$test_count" &&
 		git fetch ./subproj HEAD &&
 		git subtree merge --prefix=subdir/ FETCH_HEAD &&
-		test "$(last_commit_message)" = "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
+		test "$(last_commit_subject)" = "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -275,7 +275,7 @@ test_expect_success 'split sub dir/ with --rejoin' '
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --rejoin &&
-		test "$(last_commit_message)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
+		test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
 	)
 '
 
@@ -290,7 +290,7 @@ test_expect_success 'split sub dir/ with --rejoin from scratch' '
 		git commit -m"sub dir file" &&
 		split_hash=$(git subtree split --prefix="sub dir" --rejoin) &&
 		git subtree split --prefix="sub dir" --rejoin &&
-		test "$(last_commit_message)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
+		test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
 	)
 '
 
@@ -313,7 +313,7 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --message="Split & rejoin" --annotate="*" --rejoin &&
-		test "$(last_commit_message)" = "Split & rejoin"
+		test "$(last_commit_subject)" = "Split & rejoin"
 	)
 '
 
@@ -878,7 +878,7 @@ test_expect_success 'push split to subproj' '
 		git subtree push ./"sub proj" --prefix "sub dir" sub-branch-1 &&
 		cd ./"sub proj" &&
 		git checkout sub-branch-1 &&
-		test "$(last_commit_message)" = "sub dir/main-sub3"
+		test "$(last_commit_subject)" = "sub dir/main-sub3"
 	)
 '
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 10/30] subtree: t7900: add a test for the -h flag
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (8 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 09/30] subtree: t7900: rename last_commit_message to last_commit_subject Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 11/30] subtree: t7900: add porcelain tests for 'pull' and 'push' Luke Shumaker
                   ` (21 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

It's a dumb test, but it's surprisingly easy to break.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 4c4d6c8e6b..6b655ab4b5 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -37,6 +37,13 @@ last_commit_subject () {
 	git log --pretty=format:%s -1
 }
 
+test_expect_success 'shows short help text for -h' '
+	test_expect_code 129 git subtree -h >out 2>err &&
+	test_must_be_empty err &&
+	grep -e "^ *or: git subtree pull" out &&
+	grep -e --annotate out
+'
+
 #
 # Tests for 'git subtree add'
 #
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 11/30] subtree: t7900: add porcelain tests for 'pull' and 'push'
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (9 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 10/30] subtree: t7900: add a test for the -h flag Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 20:19   ` Eric Sunshine
  2021-04-23 19:42 ` [PATCH 12/30] subtree: don't have loose code outside of a function Luke Shumaker
                   ` (20 subsequent siblings)
  31 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

The 'pull' and 'push' subcommands deserve their own sections in the tests.
Add some basic tests for them.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 131 ++++++++++++++++++++++++++++-
 1 file changed, 129 insertions(+), 2 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 6b655ab4b5..3ee0524233 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -202,8 +202,8 @@ test_expect_success 'merge the added subproj again, should do nothing' '
 '
 
 test_expect_success 'merge new subproj history into subdir/ with a slash appended to the argument of --prefix' '
-	test_create_repo "$test_count" &&
-	test_create_repo "$test_count/subproj" &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/subproj" &&
 	test_create_commit "$test_count" main1 &&
 	test_create_commit "$test_count/subproj" sub1 &&
 	(
@@ -427,6 +427,133 @@ test_expect_success 'split "sub dir"/ with --branch for an incompatible branch'
 	)
 '
 
+#
+# Tests for 'git subtree pull'
+#
+
+test_expect_success 'pull requires option --prefix' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	(
+		cd "$test_count" &&
+		test_must_fail git subtree pull ./"sub proj" HEAD >out 2>err &&
+
+		echo "You must provide the --prefix option." >expected &&
+		test_must_be_empty out &&
+		test_cmp expected err
+	)
+'
+
+test_expect_success 'pull requires path given by option --prefix must exist' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" HEAD >out 2>err &&
+
+		echo "'\''sub dir'\'' does not exist; use '\''git subtree add'\''" > expected &&
+		test_must_be_empty out &&
+		test_cmp expected err
+	)
+'
+
+test_expect_success 'pull basic operation' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	(
+		cd "$test_count" &&
+		exp=$(git -C "sub proj" rev-parse --verify HEAD:) &&
+		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
+		act=$(git rev-parse --verify HEAD:"sub dir") &&
+		test "$act" = "$exp"
+	)
+'
+
+#
+# Tests for 'git subtree push'
+#
+
+test_expect_success 'push requires option --prefix' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD &&
+		echo "You must provide the --prefix option." > expected &&
+		test_must_fail git subtree push "./sub proj" from-mainline > actual 2>&1 &&
+		test_debug "printf '"expected: "'" &&
+		test_debug "cat expected" &&
+		test_debug "printf '"actual: "'" &&
+		test_debug "cat actual" &&
+		test_cmp expected actual
+	)
+'
+
+test_expect_success 'push requires path given by option --prefix must exist' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD &&
+		echo "'\''non-existent-directory'\'' does not exist; use '\''git subtree add'\''" > expected &&
+		test_must_fail git subtree push --prefix=non-existent-directory "./sub proj" from-mainline > actual 2>&1 &&
+		test_debug "printf '"expected: "'" &&
+		test_debug "cat expected" &&
+		test_debug "printf '"actual: "'" &&
+		test_debug "cat actual" &&
+		test_cmp expected actual
+	)
+'
+
+test_expect_success 'push basic operation' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		before=$(git rev-parse --verify HEAD) &&
+		split_hash=$(git subtree split --prefix="sub dir") &&
+		git subtree push --prefix="sub dir" ./"sub proj" from-mainline &&
+		test "$before" = "$(git rev-parse --verify HEAD)" &&
+		test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
 #
 # Validity checking
 #
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 12/30] subtree: don't have loose code outside of a function
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (10 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 11/30] subtree: t7900: add porcelain tests for 'pull' and 'push' Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 20:05   ` Luke Shumaker
  2021-04-23 20:23   ` Eric Sunshine
  2021-04-23 19:42 ` [PATCH 13/30] subtree: more consistent error propagation Luke Shumaker
                   ` (19 subsequent siblings)
  31 siblings, 2 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Shove all of the loose code inside of a main() function.

"Ignore space change" is probably helpful when viewing this diff.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 245 +++++++++++++++++----------------
 1 file changed, 125 insertions(+), 120 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 868e18b9a1..d1ed7f9a6c 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -4,10 +4,7 @@
 #
 # Copyright (C) 2009 Avery Pennarun <apenwarr@gmail.com>
 #
-if test $# -eq 0
-then
-	set -- -h
-fi
+
 OPTS_SPEC="\
 git subtree add   --prefix=<prefix> <commit>
 git subtree add   --prefix=<prefix> <repository> <ref>
@@ -30,12 +27,8 @@ rejoin        merge the new branch back into HEAD
  options for 'add', 'merge', and 'pull'
 squash        merge subtree changes as a single commit
 "
-eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
 
 PATH=$PATH:$(git --exec-path)
-. git-sh-setup
-
-require_work_tree
 
 quiet=
 branch=
@@ -84,126 +77,138 @@ ensure_single_rev () {
 	fi
 }
 
-while test $# -gt 0
-do
-	opt="$1"
-	shift
+main () {
+	if test $# -eq 0
+	then
+		set -- -h
+	fi
+	eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
+	. git-sh-setup
+	require_work_tree
 
-	case "$opt" in
-	-q)
-		quiet=1
-		;;
-	-d)
-		debug=1
-		;;
-	--annotate)
-		annotate="$1"
-		shift
-		;;
-	--no-annotate)
-		annotate=
-		;;
-	-b)
-		branch="$1"
-		shift
-		;;
-	-P)
-		prefix="${1%/}"
-		shift
-		;;
-	-m)
-		message="$1"
-		shift
-		;;
-	--no-prefix)
-		prefix=
-		;;
-	--onto)
-		onto="$1"
+	while test $# -gt 0
+	do
+		opt="$1"
 		shift
+
+		case "$opt" in
+		-q)
+			quiet=1
+			;;
+		-d)
+			debug=1
+			;;
+		--annotate)
+			annotate="$1"
+			shift
+			;;
+		--no-annotate)
+			annotate=
+			;;
+		-b)
+			branch="$1"
+			shift
+			;;
+		-P)
+			prefix="${1%/}"
+			shift
+			;;
+		-m)
+			message="$1"
+			shift
+			;;
+		--no-prefix)
+			prefix=
+			;;
+		--onto)
+			onto="$1"
+			shift
+			;;
+		--no-onto)
+			onto=
+			;;
+		--rejoin)
+			rejoin=1
+			;;
+		--no-rejoin)
+			rejoin=
+			;;
+		--ignore-joins)
+			ignore_joins=1
+			;;
+		--no-ignore-joins)
+			ignore_joins=
+			;;
+		--squash)
+			squash=1
+			;;
+		--no-squash)
+			squash=
+			;;
+		--)
+			break
+			;;
+		*)
+			die "Unexpected option: $opt"
+			;;
+		esac
+	done
+
+	command="$1"
+	shift
+
+	case "$command" in
+	add|merge|pull)
+		default=
 		;;
-	--no-onto)
-		onto=
-		;;
-	--rejoin)
-		rejoin=1
-		;;
-	--no-rejoin)
-		rejoin=
-		;;
-	--ignore-joins)
-		ignore_joins=1
-		;;
-	--no-ignore-joins)
-		ignore_joins=
-		;;
-	--squash)
-		squash=1
+	split|push)
+		default="--default HEAD"
 		;;
-	--no-squash)
-		squash=
+	*)
+		die "Unknown command '$command'"
 		;;
-	--)
-		break
+	esac
+
+	if test -z "$prefix"
+	then
+		die "You must provide the --prefix option."
+	fi
+
+	case "$command" in
+	add)
+		test -e "$prefix" &&
+			die "prefix '$prefix' already exists."
 		;;
 	*)
-		die "Unexpected option: $opt"
+		test -e "$prefix" ||
+			die "'$prefix' does not exist; use 'git subtree add'"
 		;;
 	esac
-done
-
-command="$1"
-shift
-
-case "$command" in
-add|merge|pull)
-	default=
-	;;
-split|push)
-	default="--default HEAD"
-	;;
-*)
-	die "Unknown command '$command'"
-	;;
-esac
-
-if test -z "$prefix"
-then
-	die "You must provide the --prefix option."
-fi
-
-case "$command" in
-add)
-	test -e "$prefix" &&
-		die "prefix '$prefix' already exists."
-	;;
-*)
-	test -e "$prefix" ||
-		die "'$prefix' does not exist; use 'git subtree add'"
-	;;
-esac
-
-dir="$(dirname "$prefix/.")"
-
-if test "$command" != "pull" &&
-		test "$command" != "add" &&
-		test "$command" != "push"
-then
-	revs=$(git rev-parse $default --revs-only "$@") || exit $?
-	dirs=$(git rev-parse --no-revs --no-flags "$@") || exit $?
-	ensure_single_rev $revs
-	if test -n "$dirs"
-	then
-		die "Error: Use --prefix instead of bare filenames."
-	fi
-fi
-
-debug "command: {$command}"
-debug "quiet: {$quiet}"
-debug "revs: {$revs}"
-debug "dir: {$dir}"
-debug "opts: {$*}"
-debug
+
+	dir="$(dirname "$prefix/.")"
+
+	if test "$command" != "pull" &&
+			test "$command" != "add" &&
+			test "$command" != "push"
+	then
+		revs=$(git rev-parse $default --revs-only "$@") || exit $?
+		dirs=$(git rev-parse --no-revs --no-flags "$@") || exit $?
+		ensure_single_rev $revs
+		if test -n "$dirs"
+		then
+			die "Error: Use --prefix instead of bare filenames."
+		fi
+	fi
+
+	debug "command: {$command}"
+	debug "quiet: {$quiet}"
+	debug "revs: {$revs}"
+	debug "dir: {$dir}"
+	debug "opts: {$*}"
+	debug
+
+	"cmd_$command" "$@"
+}
 
 cache_setup () {
 	cachedir="$GIT_DIR/subtree-cache/$$"
@@ -898,4 +903,4 @@ cmd_push () {
 	fi
 }
 
-"cmd_$command" "$@"
+main "$@"
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 13/30] subtree: more consistent error propagation
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (11 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 12/30] subtree: don't have loose code outside of a function Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 14/30] subtree: drop support for git < 1.7 Luke Shumaker
                   ` (18 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Ensure that every $(subshell) that calls a function (as opposed to an
external executable) is followed by `|| exit $?`.  Similarly, ensure that
every `cmd | while read; do ... done` loop is followed by `|| exit $?`.

Both of those constructs mean that it can miss `die` calls, and keep
running when it shouldn't.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index d1ed7f9a6c..9ca498f81c 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -243,7 +243,7 @@ cache_miss () {
 }
 
 check_parents () {
-	missed=$(cache_miss "$1")
+	missed=$(cache_miss "$1") || exit $?
 	local indent=$(($2 + 1))
 	for miss in $missed
 	do
@@ -345,7 +345,7 @@ find_latest_squash () {
 			sub=
 			;;
 		esac
-	done
+	done || exit $?
 }
 
 find_existing_splits () {
@@ -394,7 +394,7 @@ find_existing_splits () {
 			sub=
 			;;
 		esac
-	done
+	done || exit $?
 }
 
 copy_commit () {
@@ -508,7 +508,7 @@ subtree_for_commit () {
 		test "$type" = "commit" && continue  # ignore submodules
 		echo $tree
 		break
-	done
+	done || exit $?
 }
 
 tree_changed () {
@@ -518,7 +518,7 @@ tree_changed () {
 	then
 		return 0   # weird parents, consider it changed
 	else
-		ptree=$(toptree_for_commit $1)
+		ptree=$(toptree_for_commit $1) || exit $?
 		if test "$ptree" != "$tree"
 		then
 			return 0   # changed
@@ -652,7 +652,7 @@ process_split_commit () {
 	progress "$revcount/$revmax ($createcount) [$extracount]"
 
 	debug "Processing commit: $rev"
-	exists=$(cache_get "$rev")
+	exists=$(cache_get "$rev") || exit $?
 	if test -n "$exists"
 	then
 		debug "  prior: $exists"
@@ -661,10 +661,10 @@ process_split_commit () {
 	createcount=$(($createcount + 1))
 	debug "  parents: $parents"
 	check_parents "$parents" "$indent"
-	newparents=$(cache_get $parents)
+	newparents=$(cache_get $parents) || exit $?
 	debug "  newparents: $newparents"
 
-	tree=$(subtree_for_commit "$rev" "$dir")
+	tree=$(subtree_for_commit "$rev" "$dir") || exit $?
 	debug "  tree is: $tree"
 
 	# ugly.  is there no better way to tell if this is a subtree
@@ -750,7 +750,7 @@ cmd_add_commit () {
 		commit=$(add_squashed_msg "$rev" "$dir" |
 			git commit-tree "$tree" $headp -p "$rev") || exit $?
 	else
-		revp=$(peel_committish "$rev") &&
+		revp=$(peel_committish "$rev") || exit $?
 		commit=$(add_msg "$dir" $headrev "$rev" |
 			git commit-tree "$tree" $headp -p "$revp") || exit $?
 	fi
@@ -773,10 +773,10 @@ cmd_split () {
 			# any parent we find there can be used verbatim
 			debug "  cache: $rev"
 			cache_set "$rev" "$rev"
-		done
+		done || exit $?
 	fi
 
-	unrevs="$(find_existing_splits "$dir" "$revs")"
+	unrevs="$(find_existing_splits "$dir" "$revs")" || exit $?
 
 	# We can't restrict rev-list to only $dir here, because some of our
 	# parents have the $dir contents the root, and those won't match.
@@ -792,7 +792,7 @@ cmd_split () {
 		process_split_commit "$rev" "$parents" 0
 	done || exit $?
 
-	latest_new=$(cache_get latest_new)
+	latest_new=$(cache_get latest_new) || exit $?
 	if test -z "$latest_new"
 	then
 		die "No new revisions were found"
@@ -801,7 +801,7 @@ cmd_split () {
 	if test -n "$rejoin"
 	then
 		debug "Merging split branch into HEAD..."
-		latest_old=$(cache_get latest_old)
+		latest_old=$(cache_get latest_old) || exit $?
 		git merge -s ours \
 			--allow-unrelated-histories \
 			-m "$(rejoin_msg "$dir" "$latest_old" "$latest_new")" \
@@ -834,7 +834,7 @@ cmd_merge () {
 
 	if test -n "$squash"
 	then
-		first_split="$(find_latest_squash "$dir")"
+		first_split="$(find_latest_squash "$dir")" || exit $?
 		if test -z "$first_split"
 		then
 			die "Can't squash-merge: '$dir' was never added."
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 14/30] subtree: drop support for git < 1.7
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (12 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 13/30] subtree: more consistent error propagation Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 20:07   ` Luke Shumaker
  2021-04-23 20:31   ` Eric Sunshine
  2021-04-23 19:42 ` [PATCH 15/30] subtree: use `git merge-base --is-ancestor` Luke Shumaker
                   ` (17 subsequent siblings)
  31 siblings, 2 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

That was nice to have when git-subtree lived out-of-tree.  But now that
it lives in git.git, it's not nescessary to keep around.

"Ignore space change" is probably helpful when viewing this diff.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 19 ++++---------------
 1 file changed, 4 insertions(+), 15 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 9ca498f81c..4503564f7e 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -852,23 +852,12 @@ cmd_merge () {
 		rev="$new"
 	fi
 
-	version=$(git version)
-	if test "$version" \< "git version 1.7"
+	if test -n "$message"
 	then
-		if test -n "$message"
-		then
-			git merge -s subtree --message="$message" "$rev"
-		else
-			git merge -s subtree "$rev"
-		fi
+		git merge -Xsubtree="$prefix" \
+		    --message="$message" "$rev"
 	else
-		if test -n "$message"
-		then
-			git merge -Xsubtree="$prefix" \
-				--message="$message" "$rev"
-		else
-			git merge -Xsubtree="$prefix" $rev
-		fi
+		git merge -Xsubtree="$prefix" $rev
 	fi
 }
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 15/30] subtree: use `git merge-base --is-ancestor`
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (13 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 14/30] subtree: drop support for git < 1.7 Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 16/30] subtree: use git-sh-setup's `say` Luke Shumaker
                   ` (16 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Instead of writing a slow `rev_is_descendant_of_branch $a $b` function
in shell, just use the fast `git merge-base --is-ancestor $b $a`.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 16 +---------------
 1 file changed, 1 insertion(+), 15 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 4503564f7e..70e16b807b 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -280,20 +280,6 @@ rev_exists () {
 	fi
 }
 
-rev_is_descendant_of_branch () {
-	newrev="$1"
-	branch="$2"
-	branch_hash=$(git rev-parse "$branch")
-	match=$(git rev-list -1 "$branch_hash" "^$newrev")
-
-	if test -z "$match"
-	then
-		return 0
-	else
-		return 1
-	fi
-}
-
 # if a commit doesn't have a parent, this might not work.  But we only want
 # to remove the parent from the rev-list, and since it doesn't exist, it won't
 # be there anyway, so do nothing in that case.
@@ -811,7 +797,7 @@ cmd_split () {
 	then
 		if rev_exists "refs/heads/$branch"
 		then
-			if ! rev_is_descendant_of_branch "$latest_new" "$branch"
+			if ! git merge-base --is-ancestor "$branch" "$latest_new"
 			then
 				die "Branch '$branch' is not an ancestor of commit '$latest_new'."
 			fi
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 16/30] subtree: use git-sh-setup's `say`
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (14 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 15/30] subtree: use `git merge-base --is-ancestor` Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 17/30] subtree: use more explicit variable names for cmdline args Luke Shumaker
                   ` (15 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

subtree currently defines its own `say` implementation, rather than
using git-sh-setups's implementation.  Change that, don't re-invent the
wheel.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 22 +++++++---------------
 1 file changed, 7 insertions(+), 15 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 70e16b807b..bb4934dbc0 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -30,7 +30,6 @@ squash        merge subtree changes as a single commit
 
 PATH=$PATH:$(git --exec-path)
 
-quiet=
 branch=
 debug=
 command=
@@ -49,15 +48,8 @@ debug () {
 	fi
 }
 
-say () {
-	if test -z "$quiet"
-	then
-		printf "%s\n" "$*" >&2
-	fi
-}
-
 progress () {
-	if test -z "$quiet"
+	if test -z "$GIT_QUIET"
 	then
 		printf "%s\r" "$*" >&2
 	fi
@@ -93,7 +85,7 @@ main () {
 
 		case "$opt" in
 		-q)
-			quiet=1
+			GIT_QUIET=1
 			;;
 		-d)
 			debug=1
@@ -201,7 +193,7 @@ main () {
 	fi
 
 	debug "command: {$command}"
-	debug "quiet: {$quiet}"
+	debug "quiet: {$GIT_QUIET}"
 	debug "revs: {$revs}"
 	debug "dir: {$dir}"
 	debug "opts: {$*}"
@@ -698,7 +690,7 @@ cmd_add () {
 
 		cmd_add_repository "$@"
 	else
-		say "error: parameters were '$@'"
+		say >&2 "error: parameters were '$@'"
 		die "Provide either a commit or a repository and commit."
 	fi
 }
@@ -742,7 +734,7 @@ cmd_add_commit () {
 	fi
 	git reset "$commit" || exit $?
 
-	say "Added dir '$dir'"
+	say >&2 "Added dir '$dir'"
 }
 
 cmd_split () {
@@ -807,7 +799,7 @@ cmd_split () {
 		fi
 		git update-ref -m 'subtree split' \
 			"refs/heads/$branch" "$latest_new" || exit $?
-		say "$action branch '$branch'"
+		say >&2 "$action branch '$branch'"
 	fi
 	echo "$latest_new"
 	exit 0
@@ -830,7 +822,7 @@ cmd_merge () {
 		sub=$2
 		if test "$sub" = "$rev"
 		then
-			say "Subtree is already at commit $rev."
+			say >&2 "Subtree is already at commit $rev."
 			exit 0
 		fi
 		new=$(new_squash_commit "$old" "$sub" "$rev") || exit $?
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 17/30] subtree: use more explicit variable names for cmdline args
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (15 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 16/30] subtree: use git-sh-setup's `say` Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 18/30] subtree: use $* instead of $@ as appropriate Luke Shumaker
                   ` (14 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Make it painfully obvious when reading the code which variables are
direct parsings of command line arguments.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 132 ++++++++++++++++-----------------
 1 file changed, 66 insertions(+), 66 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index bb4934dbc0..d7de4b0653 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -30,19 +30,19 @@ squash        merge subtree changes as a single commit
 
 PATH=$PATH:$(git --exec-path)
 
-branch=
-debug=
-command=
-onto=
-rejoin=
-ignore_joins=
-annotate=
-squash=
-message=
-prefix=
+arg_debug=
+arg_command=
+arg_prefix=
+arg_split_branch=
+arg_split_onto=
+arg_split_rejoin=
+arg_split_ignore_joins=
+arg_split_annotate=
+arg_addmerge_squash=
+arg_addmerge_message=
 
 debug () {
-	if test -n "$debug"
+	if test -n "$arg_debug"
 	then
 		printf "%s\n" "$*" >&2
 	fi
@@ -88,54 +88,54 @@ main () {
 			GIT_QUIET=1
 			;;
 		-d)
-			debug=1
+			arg_debug=1
 			;;
 		--annotate)
-			annotate="$1"
+			arg_split_annotate="$1"
 			shift
 			;;
 		--no-annotate)
-			annotate=
+			arg_split_annotate=
 			;;
 		-b)
-			branch="$1"
+			arg_split_branch="$1"
 			shift
 			;;
 		-P)
-			prefix="${1%/}"
+			arg_prefix="${1%/}"
 			shift
 			;;
 		-m)
-			message="$1"
+			arg_addmerge_message="$1"
 			shift
 			;;
 		--no-prefix)
-			prefix=
+			arg_prefix=
 			;;
 		--onto)
-			onto="$1"
+			arg_split_onto="$1"
 			shift
 			;;
 		--no-onto)
-			onto=
+			arg_split_onto=
 			;;
 		--rejoin)
-			rejoin=1
+			arg_split_rejoin=1
 			;;
 		--no-rejoin)
-			rejoin=
+			arg_split_rejoin=
 			;;
 		--ignore-joins)
-			ignore_joins=1
+			arg_split_ignore_joins=1
 			;;
 		--no-ignore-joins)
-			ignore_joins=
+			arg_split_ignore_joins=
 			;;
 		--squash)
-			squash=1
+			arg_addmerge_squash=1
 			;;
 		--no-squash)
-			squash=
+			arg_addmerge_squash=
 			;;
 		--)
 			break
@@ -146,10 +146,10 @@ main () {
 		esac
 	done
 
-	command="$1"
+	arg_command="$1"
 	shift
 
-	case "$command" in
+	case "$arg_command" in
 	add|merge|pull)
 		default=
 		;;
@@ -157,31 +157,31 @@ main () {
 		default="--default HEAD"
 		;;
 	*)
-		die "Unknown command '$command'"
+		die "Unknown command '$arg_command'"
 		;;
 	esac
 
-	if test -z "$prefix"
+	if test -z "$arg_prefix"
 	then
 		die "You must provide the --prefix option."
 	fi
 
-	case "$command" in
+	case "$arg_command" in
 	add)
-		test -e "$prefix" &&
-			die "prefix '$prefix' already exists."
+		test -e "$arg_prefix" &&
+			die "prefix '$arg_prefix' already exists."
 		;;
 	*)
-		test -e "$prefix" ||
-			die "'$prefix' does not exist; use 'git subtree add'"
+		test -e "$arg_prefix" ||
+			die "'$arg_prefix' does not exist; use 'git subtree add'"
 		;;
 	esac
 
-	dir="$(dirname "$prefix/.")"
+	dir="$(dirname "$arg_prefix/.")"
 
-	if test "$command" != "pull" &&
-			test "$command" != "add" &&
-			test "$command" != "push"
+	if test "$arg_command" != "pull" &&
+			test "$arg_command" != "add" &&
+			test "$arg_command" != "push"
 	then
 		revs=$(git rev-parse $default --revs-only "$@") || exit $?
 		dirs=$(git rev-parse --no-revs --no-flags "$@") || exit $?
@@ -192,14 +192,14 @@ main () {
 		fi
 	fi
 
-	debug "command: {$command}"
+	debug "command: {$arg_command}"
 	debug "quiet: {$GIT_QUIET}"
 	debug "revs: {$revs}"
 	debug "dir: {$dir}"
 	debug "opts: {$*}"
 	debug
 
-	"cmd_$command" "$@"
+	"cmd_$arg_command" "$@"
 }
 
 cache_setup () {
@@ -333,7 +333,7 @@ find_existing_splits () {
 	main=
 	sub=
 	local grep_format="^git-subtree-dir: $dir/*\$"
-	if test -n "$ignore_joins"
+	if test -n "$arg_split_ignore_joins"
 	then
 		grep_format="^Add '$dir/' from commit '"
 	fi
@@ -394,7 +394,7 @@ copy_commit () {
 			GIT_COMMITTER_EMAIL \
 			GIT_COMMITTER_DATE
 		(
-			printf "%s" "$annotate"
+			printf "%s" "$arg_split_annotate"
 			cat
 		) |
 		git commit-tree "$2" $3  # reads the rest of stdin
@@ -405,9 +405,9 @@ add_msg () {
 	dir="$1"
 	latest_old="$2"
 	latest_new="$3"
-	if test -n "$message"
+	if test -n "$arg_addmerge_message"
 	then
-		commit_message="$message"
+		commit_message="$arg_addmerge_message"
 	else
 		commit_message="Add '$dir/' from commit '$latest_new'"
 	fi
@@ -421,9 +421,9 @@ add_msg () {
 }
 
 add_squashed_msg () {
-	if test -n "$message"
+	if test -n "$arg_addmerge_message"
 	then
-		echo "$message"
+		echo "$arg_addmerge_message"
 	else
 		echo "Merge commit '$1' as '$2'"
 	fi
@@ -433,9 +433,9 @@ rejoin_msg () {
 	dir="$1"
 	latest_old="$2"
 	latest_new="$3"
-	if test -n "$message"
+	if test -n "$arg_addmerge_message"
 	then
-		commit_message="$message"
+		commit_message="$arg_addmerge_message"
 	else
 		commit_message="Split '$dir/' into commit '$latest_new'"
 	fi
@@ -722,7 +722,7 @@ cmd_add_commit () {
 		headp=
 	fi
 
-	if test -n "$squash"
+	if test -n "$arg_addmerge_squash"
 	then
 		rev=$(new_squash_commit "" "" "$rev") || exit $?
 		commit=$(add_squashed_msg "$rev" "$dir" |
@@ -741,10 +741,10 @@ cmd_split () {
 	debug "Splitting $dir..."
 	cache_setup || exit $?
 
-	if test -n "$onto"
+	if test -n "$arg_split_onto"
 	then
-		debug "Reading history for --onto=$onto..."
-		git rev-list $onto |
+		debug "Reading history for --onto=$arg_split_onto..."
+		git rev-list $arg_split_onto |
 		while read rev
 		do
 			# the 'onto' history is already just the subdir, so
@@ -776,7 +776,7 @@ cmd_split () {
 		die "No new revisions were found"
 	fi
 
-	if test -n "$rejoin"
+	if test -n "$arg_split_rejoin"
 	then
 		debug "Merging split branch into HEAD..."
 		latest_old=$(cache_get latest_old) || exit $?
@@ -785,21 +785,21 @@ cmd_split () {
 			-m "$(rejoin_msg "$dir" "$latest_old" "$latest_new")" \
 			"$latest_new" >&2 || exit $?
 	fi
-	if test -n "$branch"
+	if test -n "$arg_split_branch"
 	then
-		if rev_exists "refs/heads/$branch"
+		if rev_exists "refs/heads/$arg_split_branch"
 		then
-			if ! git merge-base --is-ancestor "$branch" "$latest_new"
+			if ! git merge-base --is-ancestor "$arg_split_branch" "$latest_new"
 			then
-				die "Branch '$branch' is not an ancestor of commit '$latest_new'."
+				die "Branch '$arg_split_branch' is not an ancestor of commit '$latest_new'."
 			fi
 			action='Updated'
 		else
 			action='Created'
 		fi
 		git update-ref -m 'subtree split' \
-			"refs/heads/$branch" "$latest_new" || exit $?
-		say >&2 "$action branch '$branch'"
+			"refs/heads/$arg_split_branch" "$latest_new" || exit $?
+		say >&2 "$action branch '$arg_split_branch'"
 	fi
 	echo "$latest_new"
 	exit 0
@@ -810,7 +810,7 @@ cmd_merge () {
 	ensure_single_rev $rev
 	ensure_clean
 
-	if test -n "$squash"
+	if test -n "$arg_addmerge_squash"
 	then
 		first_split="$(find_latest_squash "$dir")" || exit $?
 		if test -z "$first_split"
@@ -830,12 +830,12 @@ cmd_merge () {
 		rev="$new"
 	fi
 
-	if test -n "$message"
+	if test -n "$arg_addmerge_message"
 	then
-		git merge -Xsubtree="$prefix" \
-		    --message="$message" "$rev"
+		git merge -Xsubtree="$arg_prefix" \
+			--message="$arg_addmerge_message" "$rev"
 	else
-		git merge -Xsubtree="$prefix" $rev
+		git merge -Xsubtree="$arg_prefix" $rev
 	fi
 }
 
@@ -863,7 +863,7 @@ cmd_push () {
 		repository=$1
 		refspec=$2
 		echo "git push using: " "$repository" "$refspec"
-		localrev=$(git subtree split --prefix="$prefix") || die
+		localrev=$(git subtree split --prefix="$arg_prefix") || die
 		git push "$repository" "$localrev":"refs/heads/$refspec"
 	else
 		die "'$dir' must already exist. Try 'git subtree add'."
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 18/30] subtree: use $* instead of $@ as appropriate
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (16 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 17/30] subtree: use more explicit variable names for cmdline args Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 20:40   ` Eric Sunshine
  2021-04-23 19:42 ` [PATCH 19/30] subtree: give `$(git --exec-path)` precedence over `$PATH` Luke Shumaker
                   ` (13 subsequent siblings)
  31 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

$* is for when you want to smash things together, whitespace-separated;
$@ is for when you want them to be separate strings.  There are a couple
of places in subtree that erroneously use $@ when smashing args together
in to an error message.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index d7de4b0653..3105eb8033 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -58,14 +58,14 @@ progress () {
 assert () {
 	if ! "$@"
 	then
-		die "assertion failed: " "$@"
+		die "assertion failed: $*"
 	fi
 }
 
 ensure_single_rev () {
 	if test $# -ne 1
 	then
-		die "You must provide exactly one revision.  Got: '$@'"
+		die "You must provide exactly one revision.  Got: '$*'"
 	fi
 }
 
@@ -690,7 +690,7 @@ cmd_add () {
 
 		cmd_add_repository "$@"
 	else
-		say >&2 "error: parameters were '$@'"
+		say >&2 "error: parameters were '$*'"
 		die "Provide either a commit or a repository and commit."
 	fi
 }
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 19/30] subtree: give `$(git --exec-path)` precedence over `$PATH`
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (17 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 18/30] subtree: use $* instead of $@ as appropriate Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-26  8:27   ` =?utf-8?B?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason
  2021-04-23 19:42 ` [PATCH 20/30] subtree: use "^{commit}" instead of "^0" Luke Shumaker
                   ` (12 subsequent siblings)
  31 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Other Git commands implemented in shell give `git --exec-path`
precedence over the existing $PATH, but subtree gives the existing $PATH
precedence.  Flip subtree's PATH around to match what other commands do.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 3105eb8033..9d365c9f2f 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -28,7 +28,7 @@ rejoin        merge the new branch back into HEAD
 squash        merge subtree changes as a single commit
 "
 
-PATH=$PATH:$(git --exec-path)
+PATH=$(git --exec-path):$PATH
 
 arg_debug=
 arg_command=
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 20/30] subtree: use "^{commit}" instead of "^0"
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (18 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 19/30] subtree: give `$(git --exec-path)` precedence over `$PATH` Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-26  7:43   ` Ævar Arnfjörð Bjarmason
  2021-04-23 19:42 ` [PATCH 21/30] subtree: parse revs in individual cmd_ functions Luke Shumaker
                   ` (11 subsequent siblings)
  31 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

They are synonyms.  Both are used in the file.  ^{commit} is clearer, so
"standardize" on that.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 9d365c9f2f..d200fbfed7 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -302,7 +302,7 @@ find_latest_squash () {
 			main="$b"
 			;;
 		git-subtree-split:)
-			sub="$(git rev-parse "$b^0")" ||
+			sub="$(git rev-parse "$b^{commit}")" ||
 			die "could not rev-parse split hash $b from commit $sq"
 			;;
 		END)
@@ -349,7 +349,7 @@ find_existing_splits () {
 			main="$b"
 			;;
 		git-subtree-split:)
-			sub="$(git rev-parse "$b^0")" ||
+			sub="$(git rev-parse "$b^{commit}")" ||
 			die "could not rev-parse split hash $b from commit $sq"
 			;;
 		END)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 21/30] subtree: parse revs in individual cmd_ functions
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (19 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 20/30] subtree: use "^{commit}" instead of "^0" Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 22/30] subtree: remove duplicate check Luke Shumaker
                   ` (10 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

The main argument parser goes ahead and tries to parse revs to make
things simpler for the sub-command implementations.  But, it includes
enough special cases for different sub-commands.  And it's difficult
having having to think about "is this info coming from an argument, or a
global variable?".  So the main argument parser's effort to make things
"simpler" ends up just making it more confusing and complicated.

Begone with the 'revs' global variable; parse 'rev=$(...)' as needed in
individual 'cmd_*' functions.

Begone with the 'default' global variable.  Its would-be value is
knowable just from which function we're in.

Begone with the 'ensure_single_rev' function.  Its functionality can be
achieved by passing '--verify' to 'git rev-parse'.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 62 +++++++++++++---------------------
 1 file changed, 24 insertions(+), 38 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index d200fbfed7..2efad85768 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -62,13 +62,6 @@ assert () {
 	fi
 }
 
-ensure_single_rev () {
-	if test $# -ne 1
-	then
-		die "You must provide exactly one revision.  Got: '$*'"
-	fi
-}
-
 main () {
 	if test $# -eq 0
 	then
@@ -150,11 +143,8 @@ main () {
 	shift
 
 	case "$arg_command" in
-	add|merge|pull)
-		default=
-		;;
-	split|push)
-		default="--default HEAD"
+	add|merge|pull|split|push)
+		:
 		;;
 	*)
 		die "Unknown command '$arg_command'"
@@ -179,22 +169,8 @@ main () {
 
 	dir="$(dirname "$arg_prefix/.")"
 
-	if test "$arg_command" != "pull" &&
-			test "$arg_command" != "add" &&
-			test "$arg_command" != "push"
-	then
-		revs=$(git rev-parse $default --revs-only "$@") || exit $?
-		dirs=$(git rev-parse --no-revs --no-flags "$@") || exit $?
-		ensure_single_rev $revs
-		if test -n "$dirs"
-		then
-			die "Error: Use --prefix instead of bare filenames."
-		fi
-	fi
-
 	debug "command: {$arg_command}"
 	debug "quiet: {$GIT_QUIET}"
-	debug "revs: {$revs}"
 	debug "dir: {$dir}"
 	debug "opts: {$*}"
 	debug
@@ -700,14 +676,13 @@ cmd_add_repository () {
 	repository=$1
 	refspec=$2
 	git fetch "$@" || exit $?
-	revs=FETCH_HEAD
-	set -- $revs
-	cmd_add_commit "$@"
+	cmd_add_commit FETCH_HEAD
 }
 
 cmd_add_commit () {
-	rev=$(git rev-parse $default --revs-only "$@") || exit $?
-	ensure_single_rev $rev
+	# The rev has already been validated by cmd_add(), we just
+	# need to normalize it.
+	rev=$(git rev-parse --verify "$1^{commit}") || exit $?
 
 	debug "Adding $dir as '$rev'..."
 	git read-tree --prefix="$dir" $rev || exit $?
@@ -738,6 +713,17 @@ cmd_add_commit () {
 }
 
 cmd_split () {
+	if test $# -eq 0
+	then
+		rev=$(git rev-parse HEAD)
+	elif test $# -eq 1
+	then
+		rev=$(git rev-parse -q --verify "$1^{commit}") ||
+			die "'$1' does not refer to a commit"
+	else
+		die "You must provide exactly one revision.  Got: '$*'"
+	fi
+
 	debug "Splitting $dir..."
 	cache_setup || exit $?
 
@@ -754,12 +740,12 @@ cmd_split () {
 		done || exit $?
 	fi
 
-	unrevs="$(find_existing_splits "$dir" "$revs")" || exit $?
+	unrevs="$(find_existing_splits "$dir" "$rev")" || exit $?
 
 	# We can't restrict rev-list to only $dir here, because some of our
 	# parents have the $dir contents the root, and those won't match.
 	# (and rev-list --follow doesn't seem to solve this)
-	grl='git rev-list --topo-order --reverse --parents $revs $unrevs'
+	grl='git rev-list --topo-order --reverse --parents $rev $unrevs'
 	revmax=$(eval "$grl" | wc -l)
 	revcount=0
 	createcount=0
@@ -806,8 +792,10 @@ cmd_split () {
 }
 
 cmd_merge () {
-	rev=$(git rev-parse $default --revs-only "$@") || exit $?
-	ensure_single_rev $rev
+	test $# -eq 1 ||
+		die "You must provide exactly one revision.  Got: '$*'"
+	rev=$(git rev-parse -q --verify "$1^{commit}") ||
+		die "'$1' does not refer to a commit"
 	ensure_clean
 
 	if test -n "$arg_addmerge_squash"
@@ -847,9 +835,7 @@ cmd_pull () {
 	ensure_clean
 	ensure_valid_ref_format "$2"
 	git fetch "$@" || exit $?
-	revs=FETCH_HEAD
-	set -- $revs
-	cmd_merge "$@"
+	cmd_merge FETCH_HEAD
 }
 
 cmd_push () {
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 22/30] subtree: remove duplicate check
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (20 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 21/30] subtree: parse revs in individual cmd_ functions Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 23/30] subtree: add comments and sanity checks Luke Shumaker
                   ` (9 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

`cmd_add` starts with a check that the directory doesn't yet exist.
However, the `main` function performs the exact same check before
calling `cmd_add`.  So remove the check from `cmd_add`.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 2efad85768..04dfaf443e 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -641,10 +641,6 @@ process_split_commit () {
 }
 
 cmd_add () {
-	if test -e "$dir"
-	then
-		die "'$dir' already exists.  Cannot add."
-	fi
 
 	ensure_clean
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 23/30] subtree: add comments and sanity checks
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (21 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 22/30] subtree: remove duplicate check Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 20:58   ` Eric Sunshine
  2021-04-23 19:42 ` [PATCH 24/30] subtree: don't let debug and progress output clash Luke Shumaker
                   ` (8 subsequent siblings)
  31 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 62 ++++++++++++++++++++++++++++++++--
 1 file changed, 60 insertions(+), 2 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 04dfaf443e..ddfa74c3bf 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -41,6 +41,7 @@ arg_split_annotate=
 arg_addmerge_squash=
 arg_addmerge_message=
 
+# Usage: debug [MSG...]
 debug () {
 	if test -n "$arg_debug"
 	then
@@ -48,6 +49,7 @@ debug () {
 	fi
 }
 
+# Usage: progress [MSG...]
 progress () {
 	if test -z "$GIT_QUIET"
 	then
@@ -55,6 +57,7 @@ progress () {
 	fi
 }
 
+# Usage: assert CMD...
 assert () {
 	if ! "$@"
 	then
@@ -178,7 +181,9 @@ main () {
 	"cmd_$arg_command" "$@"
 }
 
+# Usage: cache_setup
 cache_setup () {
+	assert test $# = 0
 	cachedir="$GIT_DIR/subtree-cache/$$"
 	rm -rf "$cachedir" ||
 		die "Can't delete old cachedir: $cachedir"
@@ -189,6 +194,7 @@ cache_setup () {
 	debug "Using cachedir: $cachedir" >&2
 }
 
+# Usage: cache_get [REVS...]
 cache_get () {
 	for oldrev in "$@"
 	do
@@ -200,6 +206,7 @@ cache_get () {
 	done
 }
 
+# Usage: cache_miss [REVS...]
 cache_miss () {
 	for oldrev in "$@"
 	do
@@ -210,7 +217,9 @@ cache_miss () {
 	done
 }
 
+# Usage: check_parents PARENTS_EXPR INDENT
 check_parents () {
+	assert test $# = 2
 	missed=$(cache_miss "$1") || exit $?
 	local indent=$(($2 + 1))
 	for miss in $missed
@@ -223,11 +232,15 @@ check_parents () {
 	done
 }
 
+# Usage: set_notree REV
 set_notree () {
+	assert test $# = 1
 	echo "1" > "$cachedir/notree/$1"
 }
 
+# Usage: cache_set OLDREV NEWREV
 cache_set () {
+	assert test $# = 2
 	oldrev="$1"
 	newrev="$2"
 	if test "$oldrev" != "latest_old" &&
@@ -239,7 +252,9 @@ cache_set () {
 	echo "$newrev" >"$cachedir/$oldrev"
 }
 
+# Usage: rev_exists REV
 rev_exists () {
+	assert test $# = 1
 	if git rev-parse "$1" >/dev/null 2>&1
 	then
 		return 0
@@ -248,17 +263,22 @@ rev_exists () {
 	fi
 }
 
+# Usage: try_remove_previous REV
+#
 # if a commit doesn't have a parent, this might not work.  But we only want
 # to remove the parent from the rev-list, and since it doesn't exist, it won't
 # be there anyway, so do nothing in that case.
 try_remove_previous () {
+	assert test $# = 1
 	if rev_exists "$1^"
 	then
 		echo "^$1^"
 	fi
 }
 
+# Usage: find_latest_squash DIR
 find_latest_squash () {
+	assert test $# = 1
 	debug "Looking for latest squash ($dir)..."
 	dir="$1"
 	sq=
@@ -302,10 +322,12 @@ find_latest_squash () {
 	done || exit $?
 }
 
+# Usage: find_existing_splits DIR REV
 find_existing_splits () {
+	assert test $# = 2
 	debug "Looking for prior splits..."
 	dir="$1"
-	revs="$2"
+	rev="$2"
 	main=
 	sub=
 	local grep_format="^git-subtree-dir: $dir/*\$"
@@ -314,7 +336,7 @@ find_existing_splits () {
 		grep_format="^Add '$dir/' from commit '"
 	fi
 	git log --grep="$grep_format" \
-		--no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' $revs |
+		--no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' "$rev" |
 	while read a b junk
 	do
 		case "$a" in
@@ -351,7 +373,9 @@ find_existing_splits () {
 	done || exit $?
 }
 
+# Usage: copy_commit REV TREE FLAGS_STR
 copy_commit () {
+	assert test $# = 3
 	# We're going to set some environment vars here, so
 	# do it in a subshell to get rid of them safely later
 	debug copy_commit "{$1}" "{$2}" "{$3}"
@@ -377,7 +401,9 @@ copy_commit () {
 	) || die "Can't copy commit $1"
 }
 
+# Usage: add_msg DIR LATEST_OLD LATEST_NEW
 add_msg () {
+	assert test $# = 3
 	dir="$1"
 	latest_old="$2"
 	latest_new="$3"
@@ -396,7 +422,9 @@ add_msg () {
 	EOF
 }
 
+# Usage: add_squashed_msg REV DIR
 add_squashed_msg () {
+	assert test $# = 2
 	if test -n "$arg_addmerge_message"
 	then
 		echo "$arg_addmerge_message"
@@ -405,7 +433,9 @@ add_squashed_msg () {
 	fi
 }
 
+# Usage: rejoin_msg DIR LATEST_OLD LATEST_NEW
 rejoin_msg () {
+	assert test $# = 3
 	dir="$1"
 	latest_old="$2"
 	latest_new="$3"
@@ -424,7 +454,9 @@ rejoin_msg () {
 	EOF
 }
 
+# Usage: squash_msg DIR OLD_SUBTREE_COMMIT NEW_SUBTREE_COMMIT
 squash_msg () {
+	assert test $# = 3
 	dir="$1"
 	oldsub="$2"
 	newsub="$3"
@@ -446,12 +478,16 @@ squash_msg () {
 	echo "git-subtree-split: $newsub"
 }
 
+# Usage: toptree_for_commit COMMIT
 toptree_for_commit () {
+	assert test $# = 1
 	commit="$1"
 	git rev-parse --verify "$commit^{tree}" || exit $?
 }
 
+# Usage: subtree_for_commit COMMIT DIR
 subtree_for_commit () {
+	assert test $# = 2
 	commit="$1"
 	dir="$2"
 	git ls-tree "$commit" -- "$dir" |
@@ -465,7 +501,9 @@ subtree_for_commit () {
 	done || exit $?
 }
 
+# Usage: tree_changed TREE [PARENTS...]
 tree_changed () {
+	assert test $# -gt 0
 	tree=$1
 	shift
 	if test $# -ne 1
@@ -482,7 +520,9 @@ tree_changed () {
 	fi
 }
 
+# Usage: new_squash_commit OLD_SQUASHED_COMMIT OLD_NONSQUASHED_COMMIT NEW_NONSQUASHED_COMMIT
 new_squash_commit () {
+	assert test $# = 3
 	old="$1"
 	oldsub="$2"
 	newsub="$3"
@@ -497,7 +537,9 @@ new_squash_commit () {
 	fi
 }
 
+# Usage: copy_or_skip REV TREE NEWPARENTS
 copy_or_skip () {
+	assert test $# = 3
 	rev="$1"
 	tree="$2"
 	newparents="$3"
@@ -572,7 +614,9 @@ copy_or_skip () {
 	fi
 }
 
+# Usage: ensure_clean
 ensure_clean () {
+	assert test $# = 0
 	if ! git diff-index HEAD --exit-code --quiet 2>&1
 	then
 		die "Working tree has modifications.  Cannot add."
@@ -583,12 +627,16 @@ ensure_clean () {
 	fi
 }
 
+# Usage: ensure_valid_ref_format REF
 ensure_valid_ref_format () {
+	assert test $# = 1
 	git check-ref-format "refs/heads/$1" ||
 		die "'$1' does not look like a ref"
 }
 
+# Usage: process_split_commit REV PARENTS INDENT
 process_split_commit () {
+	assert test $# = 3
 	local rev="$1"
 	local parents="$2"
 	local indent=$3
@@ -640,6 +688,8 @@ process_split_commit () {
 	cache_set latest_old "$rev"
 }
 
+# Usage: cmd_add REV
+#    Or: cmd_add REPOSITORY REF
 cmd_add () {
 
 	ensure_clean
@@ -667,7 +717,9 @@ cmd_add () {
 	fi
 }
 
+# Usage: cmd_add_repository REPOSITORY REFSPEC
 cmd_add_repository () {
+	assert test $# = 2
 	echo "git fetch" "$@"
 	repository=$1
 	refspec=$2
@@ -675,9 +727,11 @@ cmd_add_repository () {
 	cmd_add_commit FETCH_HEAD
 }
 
+# Usage: cmd_add_commit REV
 cmd_add_commit () {
 	# The rev has already been validated by cmd_add(), we just
 	# need to normalize it.
+	assert test $# = 1
 	rev=$(git rev-parse --verify "$1^{commit}") || exit $?
 
 	debug "Adding $dir as '$rev'..."
@@ -708,6 +762,7 @@ cmd_add_commit () {
 	say >&2 "Added dir '$dir'"
 }
 
+# Usage: cmd_split [REV]
 cmd_split () {
 	if test $# -eq 0
 	then
@@ -787,6 +842,7 @@ cmd_split () {
 	exit 0
 }
 
+# Usage: cmd_merge REV
 cmd_merge () {
 	test $# -eq 1 ||
 		die "You must provide exactly one revision.  Got: '$*'"
@@ -823,6 +879,7 @@ cmd_merge () {
 	fi
 }
 
+# Usage: cmd_pull REPOSITORY REMOTEREF
 cmd_pull () {
 	if test $# -ne 2
 	then
@@ -834,6 +891,7 @@ cmd_pull () {
 	cmd_merge FETCH_HEAD
 }
 
+# Usage: cmd_push REPOSITORY REMOTEREF
 cmd_push () {
 	if test $# -ne 2
 	then
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 24/30] subtree: don't let debug and progress output clash
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (22 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 23/30] subtree: add comments and sanity checks Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 21:07   ` Eric Sunshine
  2021-04-23 19:42 ` [PATCH 25/30] subtree: have $indent actually affect indentation Luke Shumaker
                   ` (7 subsequent siblings)
  31 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Currently, debug output (triggered by passing '-d') and progress output
stomp on eachother.  The debug output is just streamed as lines to
stderr, and the progress output is sent to stderr as '%s\r'.  It is
difficult to distinguish between the debug output and a progress line.
When writing to a terminal the debug lines hide progress lines.

So, when '-d' has been passed, spit out progress as 'progress: %s\n',
instead of as '%s\r', so that it can be detected, and so that the debug
lines don't overwrite the progress when written to a terminal.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index ddfa74c3bf..62cf54928e 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -53,7 +53,12 @@ debug () {
 progress () {
 	if test -z "$GIT_QUIET"
 	then
-		printf "%s\r" "$*" >&2
+		if test -n "$arg_debug"
+		then
+			printf "progress: %s\n" "$*" >&2
+		else
+			printf "%s\r" "$*" >&2
+		fi
 	fi
 }
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 25/30] subtree: have $indent actually affect indentation
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (23 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 24/30] subtree: don't let debug and progress output clash Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 26/30] subtree: give the docs a once-over Luke Shumaker
                   ` (6 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Currently, the $indent variable is just used to track how deeply we're
nested, and the debug log is indented by things like

   debug "  foo"

That is: The indentation-level is hard-coded.  It used to be that the
code couldn't recurse, so the indentation level could be known
statically, so it made sense to just hard-code it in the
output. However, since 315a84f9aa ("subtree: use commits before rejoins
for splits", 2018-09-28), it can now recurse, and the debug log is
misleading.

So fix that.  Indent according to $indent.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 42 +++++++++++++++++++---------------
 1 file changed, 24 insertions(+), 18 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 62cf54928e..54e904516b 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -41,11 +41,13 @@ arg_split_annotate=
 arg_addmerge_squash=
 arg_addmerge_message=
 
+indent=0
+
 # Usage: debug [MSG...]
 debug () {
 	if test -n "$arg_debug"
 	then
-		printf "%s\n" "$*" >&2
+		printf "%$(($indent * 2))s%s\n" '' "$*" >&2
 	fi
 }
 
@@ -222,17 +224,17 @@ cache_miss () {
 	done
 }
 
-# Usage: check_parents PARENTS_EXPR INDENT
+# Usage: check_parents PARENTS_EXPR
 check_parents () {
-	assert test $# = 2
+	assert test $# = 1
 	missed=$(cache_miss "$1") || exit $?
-	local indent=$(($2 + 1))
+	local indent=$(($indent + 1))
 	for miss in $missed
 	do
 		if ! test -r "$cachedir/notree/$miss"
 		then
-			debug "  incorrect order: $miss"
-			process_split_commit "$miss" "" "$indent"
+			debug "incorrect order: $miss"
+			process_split_commit "$miss" ""
 		fi
 	done
 }
@@ -285,6 +287,8 @@ try_remove_previous () {
 find_latest_squash () {
 	assert test $# = 1
 	debug "Looking for latest squash ($dir)..."
+	local indent=$(($indent + 1))
+
 	dir="$1"
 	sq=
 	main=
@@ -331,6 +335,8 @@ find_latest_squash () {
 find_existing_splits () {
 	assert test $# = 2
 	debug "Looking for prior splits..."
+	local indent=$(($indent + 1))
+
 	dir="$1"
 	rev="$2"
 	main=
@@ -356,7 +362,7 @@ find_existing_splits () {
 			die "could not rev-parse split hash $b from commit $sq"
 			;;
 		END)
-			debug "  Main is: '$main'"
+			debug "Main is: '$main'"
 			if test -z "$main" -a -n "$sub"
 			then
 				# squash commits refer to a subtree
@@ -639,12 +645,11 @@ ensure_valid_ref_format () {
 		die "'$1' does not look like a ref"
 }
 
-# Usage: process_split_commit REV PARENTS INDENT
+# Usage: process_split_commit REV PARENTS
 process_split_commit () {
-	assert test $# = 3
+	assert test $# = 2
 	local rev="$1"
 	local parents="$2"
-	local indent=$3
 
 	if test $indent -eq 0
 	then
@@ -659,20 +664,21 @@ process_split_commit () {
 	progress "$revcount/$revmax ($createcount) [$extracount]"
 
 	debug "Processing commit: $rev"
+	local indent=$(($indent + 1))
 	exists=$(cache_get "$rev") || exit $?
 	if test -n "$exists"
 	then
-		debug "  prior: $exists"
+		debug "prior: $exists"
 		return
 	fi
 	createcount=$(($createcount + 1))
-	debug "  parents: $parents"
-	check_parents "$parents" "$indent"
+	debug "parents: $parents"
+	check_parents "$parents"
 	newparents=$(cache_get $parents) || exit $?
-	debug "  newparents: $newparents"
+	debug "newparents: $newparents"
 
 	tree=$(subtree_for_commit "$rev" "$dir") || exit $?
-	debug "  tree is: $tree"
+	debug "tree is: $tree"
 
 	# ugly.  is there no better way to tell if this is a subtree
 	# vs. a mainline commit?  Does it matter?
@@ -687,7 +693,7 @@ process_split_commit () {
 	fi
 
 	newrev=$(copy_or_skip "$rev" "$tree" "$newparents") || exit $?
-	debug "  newrev is: $newrev"
+	debug "newrev is: $newrev"
 	cache_set "$rev" "$newrev"
 	cache_set latest_new "$newrev"
 	cache_set latest_old "$rev"
@@ -791,7 +797,7 @@ cmd_split () {
 		do
 			# the 'onto' history is already just the subdir, so
 			# any parent we find there can be used verbatim
-			debug "  cache: $rev"
+			debug "cache: $rev"
 			cache_set "$rev" "$rev"
 		done || exit $?
 	fi
@@ -809,7 +815,7 @@ cmd_split () {
 	eval "$grl" |
 	while read rev parents
 	do
-		process_split_commit "$rev" "$parents" 0
+		process_split_commit "$rev" "$parents"
 	done || exit $?
 
 	latest_new=$(cache_get latest_new) || exit $?
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 26/30] subtree: give the docs a once-over
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (24 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 25/30] subtree: have $indent actually affect indentation Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 27/30] subtree: allow --squash to be used with --rejoin Luke Shumaker
                   ` (5 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Just went through the docs looking for anything inaccurate or that can
be improved.

In the '-h' text, in the man page synopsis, and in the man page
description: Normalize the ordering of the list of sub-commands: 'add',
'merge', 'split', 'pull', 'push'.  This allows us to kinda separate the
lower-level add/merge/split from the higher-level pull/push.

'-h' text:
 - correction: Indicate that split's arg is optional.
 - clarity: Emphasize that 'pull' takes the 'add'/'merge' flags.

man page:

 - correction: State that all subcommands take options (it seemed to
   indicate that only 'split' takes any options other than '-P').
 - correction: 'split' only guarantees that the results are identical if
   the flags are identical.
 - completeness: Clarify that 'push' always operates on HEAD, and that
   'split' operates on HEAD if no local commit is given.
 - clarity: In the description, when listing commands, repeat what their
   arguments are.  This way the reader doesn't need to flip back and
   forth between the command description and the synopsis and the full
   description to understand what's being said.
 - clarity: In the <variables> used to give command arguments, give
   slightly longer, descriptive names.  Like <local-commit> instead of
   just <commit>.
 - clarity: Emphasize that 'pull' takes the 'add'/'merge' flags.
 - style: In the synopsis, list options before the subcommand.  This
   makes things line up and be much more readable when shown
   non-monospace (such as in `make html`), and also more closely matches
   other man pages (like `git-submodule.txt`).
 - style: Use the correct syntax for indicating the options ([<options>]
   instead of [OPTIONS]).
 - style: In the synopsis, separate 'pull' and 'push' from the other
   lower-level commands.  I think this helps readability.
 - style: Code-quote things in prose that seem like they should be
   code-quoted, like '.gitmodules', flags, or full commands.
 - style: Minor wording improvements, like more consistent mood (many
   of the command descriptions start in the imperative mood and switch
   to the indicative mode by the end).  That sort of thing.
 - style: Capitalize "ID".
 - style: Remove the "This option is only valid for XXX command" remarks
   from each option, and instead rely on the section headings.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh  |   4 +-
 contrib/subtree/git-subtree.txt | 162 +++++++++++++++-----------------
 2 files changed, 80 insertions(+), 86 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 54e904516b..4d0be1ad5c 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -9,9 +9,9 @@ OPTS_SPEC="\
 git subtree add   --prefix=<prefix> <commit>
 git subtree add   --prefix=<prefix> <repository> <ref>
 git subtree merge --prefix=<prefix> <commit>
+git subtree split --prefix=<prefix> [<commit>]
 git subtree pull  --prefix=<prefix> <repository> <ref>
 git subtree push  --prefix=<prefix> <repository> <ref>
-git subtree split --prefix=<prefix> <commit>
 --
 h,help        show the help
 q             quiet
@@ -24,7 +24,7 @@ b,branch=     create a new branch from the split subtree
 ignore-joins  ignore prior --rejoin commits
 onto=         try connecting new tree to an existing one
 rejoin        merge the new branch back into HEAD
- options for 'add', 'merge', and 'pull'
+ options for 'add' and 'merge' (also: 'pull')
 squash        merge subtree changes as a single commit
 "
 
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index 0db02fe3c0..5728778bdf 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -9,13 +9,14 @@ git-subtree - Merge subtrees together and split repository into subtrees
 SYNOPSIS
 --------
 [verse]
-'git subtree' add   -P <prefix> <commit>
-'git subtree' add   -P <prefix> <repository> <ref>
-'git subtree' pull  -P <prefix> <repository> <ref>
-'git subtree' push  -P <prefix> <repository> <ref>
-'git subtree' merge -P <prefix> <commit>
-'git subtree' split -P <prefix> [OPTIONS] [<commit>]
+'git subtree' [<options>] -P <prefix> add <local-commit>
+'git subtree' [<options>] -P <prefix> add <repository> <remote-ref>
+'git subtree' [<options>] -P <prefix> merge <local-commit>
+'git subtree' [<options>] -P <prefix> split [<local-commit>]
 
+[verse]
+'git subtree' [<options>] -P <prefix> pull <repository> <remote-ref>
+'git subtree' [<options>] -P <prefix> push <repository> <remote-ref>
 
 DESCRIPTION
 -----------
@@ -28,7 +29,7 @@ as a subdirectory of your application.
 
 Subtrees are not to be confused with submodules, which are meant for
 the same task. Unlike submodules, subtrees do not need any special
-constructions (like .gitmodules files or gitlinks) be present in
+constructions (like '.gitmodules' files or gitlinks) be present in
 your repository, and do not force end-users of your
 repository to do anything special or to understand how subtrees
 work. A subtree is just a subdirectory that can be
@@ -59,27 +60,28 @@ project as much as possible.  That is, if you make a change that
 affects both the library and the main application, commit it in
 two pieces.  That way, when you split the library commits out
 later, their descriptions will still make sense.  But if this
-isn't important to you, it's not *necessary*.  git subtree will
+isn't important to you, it's not *necessary*.  'git subtree' will
 simply leave out the non-library-related parts of the commit
 when it splits it out into the subproject later.
 
 
 COMMANDS
 --------
-add::
+add <local-commit>::
+add <repository> <remote-ref>::
 	Create the <prefix> subtree by importing its contents
-	from the given <commit> or <repository> and remote <ref>.
+	from the given <local-commit> or <repository> and <remote-ref>.
 	A new commit is created	automatically, joining the imported
-	project's history with your own.  With '--squash', imports
+	project's history with your own.  With '--squash', import
 	only a single commit from the subproject, rather than its
 	entire history.
 
-merge::
-	Merge recent changes up to <commit> into the <prefix>
+merge <local-commit>::
+	Merge recent changes up to <local-commit> into the <prefix>
 	subtree.  As with normal 'git merge', this doesn't
 	remove your own local changes; it just merges those
-	changes into the latest <commit>.  With '--squash',
-	creates only one commit that contains all the changes,
+	changes into the latest <local-commit>.  With '--squash',
+	create only one commit that contains all the changes,
 	rather than merging in the entire history.
 +
 If you use '--squash', the merge direction doesn't always have to be
@@ -87,39 +89,40 @@ forward; you can use this command to go back in time from v2.5 to v2.4,
 for example.  If your merge introduces a conflict, you can resolve it in
 the usual ways.
 	
-pull::
-	Exactly like 'merge', but parallels 'git pull' in that
-	it fetches the given ref from the specified remote
-	repository.
-	
-push::
-	Does a 'split' (see below) using the <prefix> supplied
-	and then does a 'git push' to push the result to the 
-	repository and ref. This can be used to push your
-	subtree to different branches of the remote repository.
-
-split::
+split [<local-commit>]::
 	Extract a new, synthetic project history from the
-	history of the <prefix> subtree.  The new history
+	history of the <prefix> subtree of <local-commit>, or of
+	HEAD if no <local-commit> is given.  The new history
 	includes only the commits (including merges) that
 	affected <prefix>, and each of those commits now has the
 	contents of <prefix> at the root of the project instead
 	of in a subdirectory.  Thus, the newly created history
 	is suitable for export as a separate git repository.
 +
-After splitting successfully, a single commit id is printed to stdout.
+After splitting successfully, a single commit ID is printed to stdout.
 This corresponds to the HEAD of the newly created tree, which you can
 manipulate however you want.
 +
 Repeated splits of exactly the same history are guaranteed to be
-identical (i.e. to produce the same commit ids).  Because of this, if
-you add new commits and then re-split, the new commits will be attached
-as commits on top of the history you generated last time, so 'git merge'
-and friends will work as expected.
+identical (i.e. to produce the same commit IDs) as long as the
+settings passed to 'split' (such as '--annotate') are the same.
+Because of this, if you add new commits and then re-split, the new
+commits will be attached as commits on top of the history you
+generated last time, so 'git merge' and friends will work as expected.
 +
 Note that if you use '--squash' when you merge, you should usually not
 just '--rejoin' when you split.
 
+pull <repository> <remote-ref>::
+	Exactly like 'merge', but parallels 'git pull' in that
+	it fetches the given ref from the specified remote
+	repository.
+
+push <repository> <remote-ref>::
+	Does a 'split' using the <prefix> subtree of HEAD and then
+	does a 'git push' to push the result to the <repository> and
+	<remote-ref>.  This can be used to push your subtree to
+	different branches of the remote repository.
 
 OPTIONS
 -------
@@ -139,19 +142,18 @@ OPTIONS
 
 -m <message>::
 --message=<message>::
-	This option is only valid for add, merge, pull, and split --rejoin.
+	This option is only valid for 'add', 'merge', 'pull', and 'split --rejoin'.
 	Specify <message> as the commit message for the merge commit.
 
+OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull')
+--------------------------------------------
+These options for 'add' and 'merge' may also be given to 'pull' (which
+wraps 'merge').
 
-OPTIONS FOR add, merge, and pull
---------------------------------
 --squash::
-	This option is only valid for add, merge, and pull
-	commands.
-+
-Instead of merging the entire history from the subtree project, produce
-only a single commit that contains all the differences you want to
-merge, and then merge that new commit into your project.
+	Instead of merging the entire history from the subtree project, produce
+	only a single commit that contains all the differences you want to
+	merge, and then merge that new commit into your project.
 +
 Using this option helps to reduce log clutter. People rarely want to see
 every change that happened between v1.0 and v1.1 of the library they're
@@ -175,56 +177,48 @@ remain intact and can be later split and send upstream to the
 subproject.
 
 
-OPTIONS FOR split
------------------
+OPTIONS FOR 'split'
+-------------------
+These options are only valid for 'split'.
+
 --annotate=<annotation>::
-	This option is only valid for the split command.
-+
-When generating synthetic history, add <annotation> as a prefix to each
-commit message.  Since we're creating new commits with the same commit
-message, but possibly different content, from the original commits, this
-can help to differentiate them and avoid confusion.
+	When generating synthetic history, add <annotation> as a prefix to each
+	commit message.  Since we're creating new commits with the same commit
+	message, but possibly different content, from the original commits, this
+	can help to differentiate them and avoid confusion.
 +
 Whenever you split, you need to use the same <annotation>, or else you
 don't have a guarantee that the new re-created history will be identical
 to the old one.  That will prevent merging from working correctly.  git
-subtree tries to make it work anyway, particularly if you use --rejoin,
+subtree tries to make it work anyway, particularly if you use '--rejoin',
 but it may not always be effective.
 
 -b <branch>::
 --branch=<branch>::
-	This option is only valid for the split command.
-+
-After generating the synthetic history, create a new branch called
-<branch> that contains the new history.  This is suitable for immediate
-pushing upstream.  <branch> must not already exist.
+	After generating the synthetic history, create a new branch called
+	<branch> that contains the new history.  This is suitable for immediate
+	pushing upstream.  <branch> must not already exist.
 
 --ignore-joins::
-	This option is only valid for the split command.
-+
-If you use '--rejoin', git subtree attempts to optimize its history
-reconstruction to generate only the new commits since the last
-'--rejoin'.  '--ignore-join' disables this behaviour, forcing it to
-regenerate the entire history.  In a large project, this can take a long
-time.
+	If you use '--rejoin', git subtree attempts to optimize its history
+	reconstruction to generate only the new commits since the last
+	'--rejoin'.  '--ignore-join' disables this behaviour, forcing it to
+	regenerate the entire history.  In a large project, this can take a long
+	time.
 
 --onto=<onto>::
-	This option is only valid for the split command.
-+
-If your subtree was originally imported using something other than git
-subtree, its history may not match what git subtree is expecting.  In
-that case, you can specify the commit id <onto> that corresponds to the
-first revision of the subproject's history that was imported into your
-project, and git subtree will attempt to build its history from there.
+	If your subtree was originally imported using something other than git
+	subtree, its history may not match what git subtree is expecting.  In
+	that case, you can specify the commit ID <onto> that corresponds to the
+	first revision of the subproject's history that was imported into your
+	project, and git subtree will attempt to build its history from there.
 +
 If you used 'git subtree add', you should never need this option.
 
 --rejoin::
-	This option is only valid for the split command.
-+
-After splitting, merge the newly created synthetic history back into
-your main project.  That way, future splits can search only the part of
-history that has been added since the most recent --rejoin.
+	After splitting, merge the newly created synthetic history back into
+	your main project.  That way, future splits can search only the part of
+	history that has been added since the most recent '--rejoin'.
 +
 If your split commits end up merged into the upstream subproject, and
 then you want to get the latest upstream version, this will allow git's
@@ -240,8 +234,8 @@ split, because you don't want the subproject's history to be part of
 your project anyway.
 
 
-EXAMPLE 1. Add command
-----------------------
+EXAMPLE 1. 'add' command
+------------------------
 Let's assume that you have a local repository that you would like
 to add an external vendor library to. In this case we will add the
 git-subtree repository as a subdirectory of your already existing
@@ -253,15 +247,15 @@ git-extensions repository in ~/git-extensions/:
 'master' needs to be a valid remote ref and can be a different branch
 name
 
-You can omit the --squash flag, but doing so will increase the number
+You can omit the '--squash' flag, but doing so will increase the number
 of commits that are included in your local repository.
 
 We now have a ~/git-extensions/git-subtree directory containing code
 from the master branch of git://github.com/apenwarr/git-subtree.git
 in our git-extensions repository.
 
-EXAMPLE 2. Extract a subtree using commit, merge and pull
----------------------------------------------------------
+EXAMPLE 2. Extract a subtree using 'commit', 'merge' and 'pull'
+---------------------------------------------------------------
 Let's use the repository for the git source code as an example.
 First, get your own copy of the git.git repository:
 
@@ -284,9 +278,9 @@ the upstream.  You could do this:
 0a8f4f0 to the current version, including 0a8f4f0 itself.")
 
 If gitweb had originally been merged using 'git subtree add' (or
-a previous split had already been done with --rejoin specified)
+a previous split had already been done with '--rejoin' specified)
 then you can do all your splits without having to remember any
-weird commit ids:
+weird commit IDs:
 
 	$ git subtree split --prefix=gitweb --annotate='(split) ' --rejoin \
 		--branch gitweb-latest2
@@ -321,8 +315,8 @@ the standard gitweb:
 
 	git log gitweb-latest..$(git subtree split --prefix=gitweb)
 
-EXAMPLE 3. Extract a subtree using branch
------------------------------------------
+EXAMPLE 3. Extract a subtree using a branch
+-------------------------------------------
 Suppose you have a source directory with many files and
 subdirectories, and you want to extract the lib directory to its own
 git project. Here's a short way to do it:
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 27/30] subtree: allow --squash to be used with --rejoin
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (25 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 26/30] subtree: give the docs a once-over Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-24  5:50   ` Eric Sunshine
  2021-04-23 19:42 ` [PATCH 28/30] subtree: allow 'split' flags to be passed to 'push' Luke Shumaker
                   ` (4 subsequent siblings)
  31 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Besides being a genuinely useful thing to do, this also just makes sense
and harmonizes which flags may be used when.  `git subtree split
--rejoin` amounts to "automatically go ahead and do a `git subtree
merge` after doing the main `git subtree split`", so it's weird and
arbitrary that you can't pass `--squash` to `git subtree split --rejoin`
like you can `git subtree merge`.  It's weird that `git subtree split
--rejoin` inherits `git subtree merge`'s `--message` but not `--squash`.

Reconcile the situation by just having `split --rejoin` actually just
call `merge` internally (or call `add` instead, as appropriate), so it
can get access to the full `merge` behavior, including `--squash`.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh     | 33 ++++++++++++++++++++++------
 contrib/subtree/git-subtree.txt    | 27 ++++++++++-------------
 contrib/subtree/t/t7900-subtree.sh | 35 ++++++++++++++++++++++++++++++
 3 files changed, 72 insertions(+), 23 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 4d0be1ad5c..ff54009c49 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -17,15 +17,15 @@ h,help        show the help
 q             quiet
 d             show debug messages
 P,prefix=     the name of the subdir to split out
-m,message=    use the given message as the commit message for the merge commit
  options for 'split'
 annotate=     add a prefix to commit message of new commits
 b,branch=     create a new branch from the split subtree
 ignore-joins  ignore prior --rejoin commits
 onto=         try connecting new tree to an existing one
 rejoin        merge the new branch back into HEAD
- options for 'add' and 'merge' (also: 'pull')
+ options for 'add' and 'merge' (also: 'pull' and 'split --rejoin')
 squash        merge subtree changes as a single commit
+m,message=    use the given message as the commit message for the merge commit
 "
 
 PATH=$(git --exec-path):$PATH
@@ -424,6 +424,13 @@ add_msg () {
 	else
 		commit_message="Add '$dir/' from commit '$latest_new'"
 	fi
+	if test -n "$arg_split_rejoin"
+	then
+		# If this is from a --rejoin, then rejoin_msg has
+		# already inserted the `git-subtree-xxx:` tags
+		echo "$commit_message"
+		return
+	fi
 	cat <<-EOF
 		$commit_message
 
@@ -746,7 +753,12 @@ cmd_add_commit () {
 	rev=$(git rev-parse --verify "$1^{commit}") || exit $?
 
 	debug "Adding $dir as '$rev'..."
-	git read-tree --prefix="$dir" $rev || exit $?
+	if test -z "$arg_split_rejoin"
+	then
+		# Only bother doing this if this is a genuine 'add',
+		# not a synthetic 'add' from '--rejoin'.
+		git read-tree --prefix="$dir" $rev || exit $?
+	fi
 	git checkout -- "$dir" || exit $?
 	tree=$(git write-tree) || exit $?
 
@@ -786,6 +798,11 @@ cmd_split () {
 		die "You must provide exactly one revision.  Got: '$*'"
 	fi
 
+	if test -n "$arg_split_rejoin"
+	then
+		ensure_clean
+	fi
+
 	debug "Splitting $dir..."
 	cache_setup || exit $?
 
@@ -828,10 +845,12 @@ cmd_split () {
 	then
 		debug "Merging split branch into HEAD..."
 		latest_old=$(cache_get latest_old) || exit $?
-		git merge -s ours \
-			--allow-unrelated-histories \
-			-m "$(rejoin_msg "$dir" "$latest_old" "$latest_new")" \
-			"$latest_new" >&2 || exit $?
+		arg_addmerge_message="$(rejoin_msg "$dir" "$latest_old" "$latest_new")" || exit $?
+		if test -z "$(find_latest_squash "$dir")"; then
+			cmd_add "$latest_new" >&2 || exit $?
+		else
+			cmd_merge "$latest_new" >&2 || exit $?
+		fi
 	fi
 	if test -n "$arg_split_branch"
 	then
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index 5728778bdf..b03ef88e1a 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -109,9 +109,6 @@ settings passed to 'split' (such as '--annotate') are the same.
 Because of this, if you add new commits and then re-split, the new
 commits will be attached as commits on top of the history you
 generated last time, so 'git merge' and friends will work as expected.
-+
-Note that if you use '--squash' when you merge, you should usually not
-just '--rejoin' when you split.
 
 pull <repository> <remote-ref>::
 	Exactly like 'merge', but parallels 'git pull' in that
@@ -124,8 +121,8 @@ push <repository> <remote-ref>::
 	<remote-ref>.  This can be used to push your subtree to
 	different branches of the remote repository.
 
-OPTIONS
--------
+OPTIONS FOR ALL COMMANDS
+------------------------
 -q::
 --quiet::
 	Suppress unnecessary output messages on stderr.
@@ -140,15 +137,11 @@ OPTIONS
 	want to manipulate.  This option is mandatory
 	for all commands.
 
--m <message>::
---message=<message>::
-	This option is only valid for 'add', 'merge', 'pull', and 'split --rejoin'.
-	Specify <message> as the commit message for the merge commit.
-
-OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull')
---------------------------------------------
+OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull' AND 'split --rejoin')
+-----------------------------------------------------------------
 These options for 'add' and 'merge' may also be given to 'pull' (which
-wraps 'merge').
+wraps 'merge') and 'split --rejoin' (which wraps either 'add' or
+'merge' as appropriate).
 
 --squash::
 	Instead of merging the entire history from the subtree project, produce
@@ -176,6 +169,9 @@ Whether or not you use '--squash', changes made in your local repository
 remain intact and can be later split and send upstream to the
 subproject.
 
+-m <message>::
+--message=<message>::
+	Specify <message> as the commit message for the merge commit.
 
 OPTIONS FOR 'split'
 -------------------
@@ -229,9 +225,8 @@ Unfortunately, using this option results in 'git log' showing an extra
 copy of every new commit that was created (the original, and the
 synthetic one).
 +
-If you do all your merges with '--squash', don't use '--rejoin' when you
-split, because you don't want the subproject's history to be part of
-your project anyway.
+If you do all your merges with '--squash', make sure you also use
+'--squash' when you 'split --rejoin'.
 
 
 EXAMPLE 1. 'add' command
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 3ee0524233..e5467c117b 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -324,6 +324,41 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
 	)
 '
 
+test_expect_success 'split "sub dir"/ with --rejoin and --squash' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" --squash FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git subtree pull --prefix="sub dir" --squash ./"sub proj" HEAD &&
+		MAIN=$(git rev-parse --verify HEAD) &&
+		SUB=$(git -C "sub proj" rev-parse --verify HEAD) &&
+
+		SPLIT=$(git subtree split --prefix="sub dir" --annotate="*" --rejoin --squash) &&
+
+		! git merge-base --is-ancestor $SUB HEAD &&
+		! git merge-base --is-ancestor $SPLIT HEAD &&
+		git rev-list HEAD ^$MAIN >commit-list &&
+		test_line_count = 2 commit-list &&
+		test "$(git rev-parse --verify HEAD:)"           = "$(git rev-parse --verify $MAIN:)" &&
+		test "$(git rev-parse --verify HEAD:"sub dir")"  = "$(git rev-parse --verify $SPLIT:)" &&
+		test "$(git rev-parse --verify HEAD^1)"          = $MAIN &&
+		test "$(git rev-parse --verify HEAD^2)"         != $SPLIT &&
+		test "$(git rev-parse --verify HEAD^2:)"         = "$(git rev-parse --verify $SPLIT:)" &&
+		test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$SPLIT'\''"
+	)
+'
+
 test_expect_success 'split "sub dir"/ with --branch' '
 	subtree_test_create_repo "$test_count" &&
 	subtree_test_create_repo "$test_count/sub proj" &&
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 28/30] subtree: allow 'split' flags to be passed to 'push'
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (26 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 27/30] subtree: allow --squash to be used with --rejoin Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 29/30] subtree: push: allow specifying a local rev other than HEAD Luke Shumaker
                   ` (3 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

'push' does a 'split' internally, but it doesn't pass flags through to the
'split'.  This is silly, if you need to pass flags to 'split', then it
means that you can't use 'push'!

So, have 'push' accept 'split' flags, and pass them through to 'split'.

Add tests for this by copying split's tests with minimal modification.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh     |   6 +-
 contrib/subtree/git-subtree.txt    |  15 +-
 contrib/subtree/t/t7900-subtree.sh | 214 ++++++++++++++++++++++++++++-
 3 files changed, 223 insertions(+), 12 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index ff54009c49..2846bd21b4 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -17,13 +17,13 @@ h,help        show the help
 q             quiet
 d             show debug messages
 P,prefix=     the name of the subdir to split out
- options for 'split'
+ options for 'split' (also: 'push')
 annotate=     add a prefix to commit message of new commits
 b,branch=     create a new branch from the split subtree
 ignore-joins  ignore prior --rejoin commits
 onto=         try connecting new tree to an existing one
 rejoin        merge the new branch back into HEAD
- options for 'add' and 'merge' (also: 'pull' and 'split --rejoin')
+ options for 'add' and 'merge' (also: 'pull', 'split --rejoin', and 'push --rejoin')
 squash        merge subtree changes as a single commit
 m,message=    use the given message as the commit message for the merge commit
 "
@@ -933,7 +933,7 @@ cmd_push () {
 		repository=$1
 		refspec=$2
 		echo "git push using: " "$repository" "$refspec"
-		localrev=$(git subtree split --prefix="$arg_prefix") || die
+		localrev=$(cmd_split) || die
 		git push "$repository" "$localrev":"refs/heads/$refspec"
 	else
 		die "'$dir' must already exist. Try 'git subtree add'."
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index b03ef88e1a..a597d61d0f 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -137,11 +137,11 @@ OPTIONS FOR ALL COMMANDS
 	want to manipulate.  This option is mandatory
 	for all commands.
 
-OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull' AND 'split --rejoin')
------------------------------------------------------------------
+OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull', 'split --rejoin', AND 'push --rejoin')
+-----------------------------------------------------------------------------------
 These options for 'add' and 'merge' may also be given to 'pull' (which
-wraps 'merge') and 'split --rejoin' (which wraps either 'add' or
-'merge' as appropriate).
+wraps 'merge'), 'split --rejoin' (which wraps either 'add' or 'merge'
+as appropriate), and 'push --rejoin' (which wraps 'split --rejoin').
 
 --squash::
 	Instead of merging the entire history from the subtree project, produce
@@ -173,9 +173,10 @@ subproject.
 --message=<message>::
 	Specify <message> as the commit message for the merge commit.
 
-OPTIONS FOR 'split'
--------------------
-These options are only valid for 'split'.
+OPTIONS FOR 'split' (ALSO: 'push')
+----------------------------------
+These options for 'split' may also be given to 'push' (which wraps
+'split').
 
 --annotate=<annotation>::
 	When generating synthetic history, add <annotation> as a prefix to each
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index e5467c117b..e89e46fe65 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -5,8 +5,8 @@
 #
 test_description='Basic porcelain support for subtrees
 
-This test verifies the basic operation of the add, pull, merge
-and split subcommands of git subtree.
+This test verifies the basic operation of the add, merge, split, pull,
+and push subcommands of git subtree.
 '
 
 TEST_DIRECTORY=$(pwd)/../../../t
@@ -589,6 +589,216 @@ test_expect_success 'push basic operation' '
 	)
 '
 
+test_expect_success 'push sub dir/ with --rejoin' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+		git subtree push --prefix="sub dir" --annotate="*" --rejoin ./"sub proj" from-mainline &&
+		test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''" &&
+		test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'push sub dir/ with --rejoin from scratch' '
+	subtree_test_create_repo "$test_count" &&
+	test_create_commit "$test_count" main1 &&
+	(
+		cd "$test_count" &&
+		mkdir "sub dir" &&
+		echo file >"sub dir"/file &&
+		git add "sub dir/file" &&
+		git commit -m"sub dir file" &&
+		split_hash=$(git subtree split --prefix="sub dir" --rejoin) &&
+		git init --bare "sub proj.git" &&
+		git subtree push --prefix="sub dir" --rejoin ./"sub proj.git" from-mainline &&
+		test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''" &&
+		test "$split_hash" = "$(git -C "sub proj.git" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'push sub dir/ with --rejoin and --message' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		git subtree push --prefix="sub dir" --message="Split & rejoin" --annotate="*" --rejoin ./"sub proj" from-mainline &&
+		test "$(last_commit_subject)" = "Split & rejoin" &&
+		split_hash="$(git rev-parse --verify HEAD^2)" &&
+		test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'push "sub dir"/ with --rejoin and --squash' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" --squash FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git subtree pull --prefix="sub dir" --squash ./"sub proj" HEAD &&
+		MAIN=$(git rev-parse --verify HEAD) &&
+		SUB=$(git -C "sub proj" rev-parse --verify HEAD) &&
+
+		SPLIT=$(git subtree split --prefix="sub dir" --annotate="*") &&
+		git subtree push --prefix="sub dir" --annotate="*" --rejoin --squash ./"sub proj" from-mainline &&
+
+		! git merge-base --is-ancestor $SUB HEAD &&
+		! git merge-base --is-ancestor $SPLIT HEAD &&
+		git rev-list HEAD ^$MAIN >commit-list &&
+		test_line_count = 2 commit-list &&
+		test "$(git rev-parse --verify HEAD:)"           = "$(git rev-parse --verify $MAIN:)" &&
+		test "$(git rev-parse --verify HEAD:"sub dir")"  = "$(git rev-parse --verify $SPLIT:)" &&
+		test "$(git rev-parse --verify HEAD^1)"          = $MAIN &&
+		test "$(git rev-parse --verify HEAD^2)"         != $SPLIT &&
+		test "$(git rev-parse --verify HEAD^2:)"         = "$(git rev-parse --verify $SPLIT:)" &&
+		test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$SPLIT'\''" &&
+		test "$SPLIT" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'push "sub dir"/ with --branch' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+		git subtree push --prefix="sub dir" --annotate="*" --branch subproj-br ./"sub proj" from-mainline &&
+		test "$(git rev-parse subproj-br)" = "$split_hash" &&
+		test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'check hash of push' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+		git subtree push --prefix="sub dir" --annotate="*" --branch subproj-br ./"sub proj" from-mainline &&
+		test "$(git rev-parse subproj-br)" = "$split_hash" &&
+		# Check hash of split
+		new_hash=$(git rev-parse subproj-br^2) &&
+		(
+			cd ./"sub proj" &&
+			subdir_hash=$(git rev-parse HEAD) &&
+			test "$new_hash" = "$subdir_hash"
+		) &&
+		test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'push "sub dir"/ with --branch for an existing branch' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git branch subproj-br FETCH_HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+		git subtree push --prefix="sub dir" --annotate="*" --branch subproj-br ./"sub proj" from-mainline &&
+		test "$(git rev-parse subproj-br)" = "$split_hash" &&
+		test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'push "sub dir"/ with --branch for an incompatible branch' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git branch init HEAD &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		test_must_fail git subtree push --prefix="sub dir" --branch init "./sub proj" from-mainline
+	)
+'
+
 #
 # Validity checking
 #
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 29/30] subtree: push: allow specifying a local rev other than HEAD
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (27 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 28/30] subtree: allow 'split' flags to be passed to 'push' Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-23 19:42 ` [PATCH 30/30] subtree: be stricter about validating flags Luke Shumaker
                   ` (2 subsequent siblings)
  31 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

'git subtree split' lets you specify a rev other than HEAD.  'git push'
lets you specify a mapping between a local thing and a remot ref.  So
smash those together, and have 'git subtree push' let you specify which
local thing to run split on and push the result of that split to the
remote ref.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh     | 24 +++++++++++++++++-------
 contrib/subtree/git-subtree.txt    | 14 ++++++++------
 contrib/subtree/t/t7900-subtree.sh | 22 ++++++++++++++++++++++
 3 files changed, 47 insertions(+), 13 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 2846bd21b4..7361d8de3f 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -11,7 +11,7 @@ git subtree add   --prefix=<prefix> <repository> <ref>
 git subtree merge --prefix=<prefix> <commit>
 git subtree split --prefix=<prefix> [<commit>]
 git subtree pull  --prefix=<prefix> <repository> <ref>
-git subtree push  --prefix=<prefix> <repository> <ref>
+git subtree push  --prefix=<prefix> <repository> <refspec>
 --
 h,help        show the help
 q             quiet
@@ -921,20 +921,30 @@ cmd_pull () {
 	cmd_merge FETCH_HEAD
 }
 
-# Usage: cmd_push REPOSITORY REMOTEREF
+# Usage: cmd_push REPOSITORY [+][LOCALREV:]REMOTEREF
 cmd_push () {
 	if test $# -ne 2
 	then
-		die "You must provide <repository> <ref>"
+		die "You must provide <repository> <refspec>"
 	fi
-	ensure_valid_ref_format "$2"
 	if test -e "$dir"
 	then
 		repository=$1
-		refspec=$2
+		refspec=${2#+}
+		remoteref=${refspec#*:}
+		if test "$remoteref" = "$refspec"
+		then
+			localrevname_presplit=HEAD
+		else
+			localrevname_presplit=${refspec%%:*}
+		fi
+		ensure_valid_ref_format "$remoteref"
+		localrev_presplit=$(git rev-parse -q --verify "$localrevname_presplit^{commit}") ||
+			die "'$localrevname_presplit' does not refer to a commit"
+
 		echo "git push using: " "$repository" "$refspec"
-		localrev=$(cmd_split) || die
-		git push "$repository" "$localrev":"refs/heads/$refspec"
+		localrev=$(cmd_split "$localrev_presplit") || die
+		git push "$repository" "$localrev":"refs/heads/$remoteref"
 	else
 		die "'$dir' must already exist. Try 'git subtree add'."
 	fi
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index a597d61d0f..c049827cb5 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -16,7 +16,7 @@ SYNOPSIS
 
 [verse]
 'git subtree' [<options>] -P <prefix> pull <repository> <remote-ref>
-'git subtree' [<options>] -P <prefix> push <repository> <remote-ref>
+'git subtree' [<options>] -P <prefix> push <repository> <refspec>
 
 DESCRIPTION
 -----------
@@ -115,11 +115,13 @@ pull <repository> <remote-ref>::
 	it fetches the given ref from the specified remote
 	repository.
 
-push <repository> <remote-ref>::
-	Does a 'split' using the <prefix> subtree of HEAD and then
-	does a 'git push' to push the result to the <repository> and
-	<remote-ref>.  This can be used to push your subtree to
-	different branches of the remote repository.
+push <repository> [+][<local-commit>:]<remote-ref>::
+	Does a 'split' using the <prefix> subtree of <local-commit>
+	and then does a 'git push' to push the result to the
+	<repository> and <remote-ref>.  This can be used to push your
+	subtree to different branches of the remote repository.  Just
+	as with 'split', if no <local-commit> is given, then HEAD is
+	used.  The optional leading '+' is ignored.
 
 OPTIONS FOR ALL COMMANDS
 ------------------------
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index e89e46fe65..fb85eed5fc 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -799,6 +799,28 @@ test_expect_success 'push "sub dir"/ with --branch for an incompatible branch' '
 	)
 '
 
+test_expect_success 'push "sub dir"/ with a local rev' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		bad_tree=$(git rev-parse --verify HEAD:"sub dir") &&
+		good_tree=$(git rev-parse --verify HEAD^:"sub dir") &&
+		git subtree push --prefix="sub dir" --annotate="*" ./"sub proj" HEAD^:from-mainline &&
+		split_tree=$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline:) &&
+		test "$split_tree" = "$good_tree"
+	)
+'
+
 #
 # Validity checking
 #
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH 30/30] subtree: be stricter about validating flags
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (28 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 29/30] subtree: push: allow specifying a local rev other than HEAD Luke Shumaker
@ 2021-04-23 19:42 ` Luke Shumaker
  2021-04-25  2:55   ` Danny Lin
  2021-04-23 20:12 ` [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
  31 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 19:42 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Don't silently ignore a flag that's invalid for a given subcommand.  The
user expected it to do something; we should tell the user that they are
mistaken, instead of surprising the user.

It could be argued that this change might break existing users.  I'd
argue that those existing users are already broken, and they just don't
know it.  Let them know that they're broken.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh     |  89 ++++++++++++++++-------
 contrib/subtree/t/t7900-subtree.sh | 111 +++++++++++++++++++++++++++++
 2 files changed, 175 insertions(+), 25 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 7361d8de3f..5073d82b2e 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -30,17 +30,6 @@ m,message=    use the given message as the commit message for the merge commit
 
 PATH=$(git --exec-path):$PATH
 
-arg_debug=
-arg_command=
-arg_prefix=
-arg_split_branch=
-arg_split_onto=
-arg_split_rejoin=
-arg_split_ignore_joins=
-arg_split_annotate=
-arg_addmerge_squash=
-arg_addmerge_message=
-
 indent=0
 
 # Usage: debug [MSG...]
@@ -77,10 +66,61 @@ main () {
 	then
 		set -- -h
 	fi
-	eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
+	set_args="$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
+	eval "$set_args"
 	. git-sh-setup
 	require_work_tree
 
+	# First figure out the command and whether we use --rejoin, so
+	# that we can provide more helpful validation when we do the
+	# "real" flag parsing.
+	arg_split_rejoin=
+	allow_split=
+	allow_addmerge=
+	while test $# -gt 0
+	do
+		opt="$1"
+		shift
+		case "$opt" in
+			--annotate|-b|-P|-m|--onto)
+				shift
+				;;
+			--rejoin)
+				arg_split_rejoin=1
+				;;
+			--no-rejoin)
+				arg_split_rejoin=
+				;;
+			--)
+				break
+				;;
+		esac
+	done
+	arg_command=$1
+	case "$arg_command" in
+	add|merge|pull)
+		allow_addmerge=1
+		;;
+	split|push)
+		allow_split=1
+		allow_addmerge=$arg_split_rejoin
+		;;
+	*)
+		die "Unknown command '$arg_command'"
+		;;
+	esac
+	# Reset the arguments array for "real" flag parsing.
+	eval "$set_args"
+
+	# Begin "real" flag parsing.
+	arg_debug=
+	arg_prefix=
+	arg_split_branch=
+	arg_split_onto=
+	arg_split_ignore_joins=
+	arg_split_annotate=
+	arg_addmerge_squash=
+	arg_addmerge_message=
 	while test $# -gt 0
 	do
 		opt="$1"
@@ -94,13 +134,16 @@ main () {
 			arg_debug=1
 			;;
 		--annotate)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_annotate="$1"
 			shift
 			;;
 		--no-annotate)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_annotate=
 			;;
 		-b)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_branch="$1"
 			shift
 			;;
@@ -109,6 +152,7 @@ main () {
 			shift
 			;;
 		-m)
+			test -n "$allow_addmerge" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_addmerge_message="$1"
 			shift
 			;;
@@ -116,28 +160,34 @@ main () {
 			arg_prefix=
 			;;
 		--onto)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_onto="$1"
 			shift
 			;;
 		--no-onto)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_onto=
 			;;
 		--rejoin)
-			arg_split_rejoin=1
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			;;
 		--no-rejoin)
-			arg_split_rejoin=
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			;;
 		--ignore-joins)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_ignore_joins=1
 			;;
 		--no-ignore-joins)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_ignore_joins=
 			;;
 		--squash)
+			test -n "$allow_addmerge" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_addmerge_squash=1
 			;;
 		--no-squash)
+			test -n "$allow_addmerge" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_addmerge_squash=
 			;;
 		--)
@@ -148,19 +198,8 @@ main () {
 			;;
 		esac
 	done
-
-	arg_command="$1"
 	shift
 
-	case "$arg_command" in
-	add|merge|pull|split|push)
-		:
-		;;
-	*)
-		die "Unknown command '$arg_command'"
-		;;
-	esac
-
 	if test -z "$arg_prefix"
 	then
 		die "You must provide the --prefix option."
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index fb85eed5fc..f83c491a61 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -33,6 +33,12 @@ test_create_commit () (
 	git commit -m "$commit" || error "Could not commit"
 )
 
+test_wrong_flag() {
+	test_must_fail "$@" >out 2>err &&
+	test_must_be_empty out &&
+	grep "flag does not make sense with" err
+}
+
 last_commit_subject () {
 	git log --pretty=format:%s -1
 }
@@ -72,6 +78,22 @@ test_expect_success 'no pull from non-existent subtree' '
 	)
 '
 
+test_expect_success 'add rejects flags for split' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		test_wrong_flag git subtree add --prefix="sub dir" --annotate=foo FETCH_HEAD &&
+		test_wrong_flag git subtree add --prefix="sub dir" --branch=foo FETCH_HEAD &&
+		test_wrong_flag git subtree add --prefix="sub dir" --ignore-joins FETCH_HEAD &&
+		test_wrong_flag git subtree add --prefix="sub dir" --onto=foo FETCH_HEAD &&
+		test_wrong_flag git subtree add --prefix="sub dir" --rejoin FETCH_HEAD
+	)
+'
+
 test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
 	subtree_test_create_repo "$test_count" &&
 	subtree_test_create_repo "$test_count/sub proj" &&
@@ -128,6 +150,28 @@ test_expect_success 'add subproj as subtree into sub dir/ with --squash and --pr
 # Tests for 'git subtree merge'
 #
 
+test_expect_success 'merge rejects flags for split' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		test_wrong_flag git subtree merge --prefix="sub dir" --annotate=foo FETCH_HEAD &&
+		test_wrong_flag git subtree merge --prefix="sub dir" --branch=foo FETCH_HEAD &&
+		test_wrong_flag git subtree merge --prefix="sub dir" --ignore-joins FETCH_HEAD &&
+		test_wrong_flag git subtree merge --prefix="sub dir" --onto=foo FETCH_HEAD &&
+		test_wrong_flag git subtree merge --prefix="sub dir" --rejoin FETCH_HEAD
+	)
+'
+
 test_expect_success 'merge new subproj history into sub dir/ with --prefix' '
 	subtree_test_create_repo "$test_count" &&
 	subtree_test_create_repo "$test_count/sub proj" &&
@@ -262,6 +306,30 @@ test_expect_success 'split requires path given by option --prefix must exist' '
 	)
 '
 
+test_expect_success 'split rejects flags for add' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+		test_wrong_flag git subtree split --prefix="sub dir" --squash &&
+		test_wrong_flag git subtree split --prefix="sub dir" --message=foo
+	)
+'
+
 test_expect_success 'split sub dir/ with --rejoin' '
 	subtree_test_create_repo "$test_count" &&
 	subtree_test_create_repo "$test_count/sub proj" &&
@@ -521,6 +589,26 @@ test_expect_success 'pull basic operation' '
 	)
 '
 
+test_expect_success 'pull rejects flags for split' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	(
+		test_must_fail git subtree pull --prefix="sub dir" --annotate=foo ./"sub proj" HEAD &&
+		test_must_fail git subtree pull --prefix="sub dir" --branch=foo ./"sub proj" HEAD &&
+		test_must_fail git subtree pull --prefix="sub dir" --ignore-joins ./"sub proj" HEAD &&
+		test_must_fail git subtree pull --prefix="sub dir" --onto=foo ./"sub proj" HEAD &&
+		test_must_fail git subtree pull --prefix="sub dir" --rejoin ./"sub proj" HEAD
+	)
+'
+
 #
 # Tests for 'git subtree push'
 #
@@ -563,6 +651,29 @@ test_expect_success 'push requires path given by option --prefix must exist' '
 	)
 '
 
+test_expect_success 'push rejects flags for add' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		test_wrong_flag git subtree split --prefix="sub dir" --squash ./"sub proj" from-mainline &&
+		test_wrong_flag git subtree split --prefix="sub dir" --message=foo ./"sub proj" from-mainline
+	)
+'
+
 test_expect_success 'push basic operation' '
 	subtree_test_create_repo "$test_count" &&
 	subtree_test_create_repo "$test_count/sub proj" &&
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* Re: [PATCH 12/30] subtree: don't have loose code outside of a function
  2021-04-23 19:42 ` [PATCH 12/30] subtree: don't have loose code outside of a function Luke Shumaker
@ 2021-04-23 20:05   ` Luke Shumaker
  2021-04-23 20:23   ` Eric Sunshine
  1 sibling, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 20:05 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, 23 Apr 2021 13:42:12 -0600,
Luke Shumaker wrote:
> "Ignore space change" is probably helpful when viewing this diff.

For mailing-list reading, the `git show -w` is

---
diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 868e18b9a1..d1ed7f9a6c 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -4,10 +4,7 @@
 #
 # Copyright (C) 2009 Avery Pennarun <apenwarr@gmail.com>
 #
-if test $# -eq 0
-then
-	set -- -h
-fi
+
 OPTS_SPEC="\
 git subtree add   --prefix=<prefix> <commit>
 git subtree add   --prefix=<prefix> <repository> <ref>
@@ -30,12 +27,8 @@ rejoin        merge the new branch back into HEAD
  options for 'add', 'merge', and 'pull'
 squash        merge subtree changes as a single commit
 "
-eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
 
 PATH=$PATH:$(git --exec-path)
-. git-sh-setup
-
-require_work_tree
 
 quiet=
 branch=
@@ -84,6 +77,15 @@ ensure_single_rev () {
 	fi
 }
 
+main () {
+	if test $# -eq 0
+	then
+		set -- -h
+	fi
+	eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
+	. git-sh-setup
+	require_work_tree
+
 	while test $# -gt 0
 	do
 		opt="$1"
@@ -205,6 +207,9 @@ debug "dir: {$dir}"
 	debug "opts: {$*}"
 	debug
 
+	"cmd_$command" "$@"
+}
+
 cache_setup () {
 	cachedir="$GIT_DIR/subtree-cache/$$"
 	rm -rf "$cachedir" ||
@@ -898,4 +903,4 @@ cmd_push () {
 	fi
 }
 
-"cmd_$command" "$@"
+main "$@"

^ permalink raw reply related	[flat|nested] 144+ messages in thread

* Re: [PATCH 14/30] subtree: drop support for git < 1.7
  2021-04-23 19:42 ` [PATCH 14/30] subtree: drop support for git < 1.7 Luke Shumaker
@ 2021-04-23 20:07   ` Luke Shumaker
  2021-04-23 20:31   ` Eric Sunshine
  1 sibling, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 20:07 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, 23 Apr 2021 13:42:14 -0600,
Luke Shumaker wrote:
> "Ignore space change" is probably helpful when viewing this diff.

For mailing-list reading, the `git show -w` is:

---
diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 9ca498f81c..4503564f7e 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -852,16 +852,6 @@ cmd_merge () {
 		rev="$new"
 	fi
 
-	version=$(git version)
-	if test "$version" \< "git version 1.7"
-	then
-		if test -n "$message"
-		then
-			git merge -s subtree --message="$message" "$rev"
-		else
-			git merge -s subtree "$rev"
-		fi
-	else
 	if test -n "$message"
 	then
 		git merge -Xsubtree="$prefix" \
@@ -869,7 +859,6 @@ cmd_merge () {
 	else
 		git merge -Xsubtree="$prefix" $rev
 	fi
-	fi
 }
 
 cmd_pull () {

^ permalink raw reply related	[flat|nested] 144+ messages in thread

* Re: [PATCH 00/30] subtree: clean up, improve UX
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (29 preceding siblings ...)
  2021-04-23 19:42 ` [PATCH 30/30] subtree: be stricter about validating flags Luke Shumaker
@ 2021-04-23 20:12 ` Luke Shumaker
  2021-04-26  7:55   ` =?utf-8?B?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason
  2021-04-27  7:27   ` Junio C Hamano
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
  31 siblings, 2 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 20:12 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, 23 Apr 2021 13:42:00 -0600,
Luke Shumaker wrote:
>                                                  I promise that
> there's more work coming on top of it (we've discovered lots of ways
> to break the "subtree split" algorithm, and come up with fixes for
> most of them).

Follow-up question: If in that work I changed the shebang from
"#!/bin/sh" to "#!/usr/bin/env bash" and started using Bash arrays,
would that be so bad?  Would that be land-able?

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 11/30] subtree: t7900: add porcelain tests for 'pull' and 'push'
  2021-04-23 19:42 ` [PATCH 11/30] subtree: t7900: add porcelain tests for 'pull' and 'push' Luke Shumaker
@ 2021-04-23 20:19   ` Eric Sunshine
  2021-04-23 22:27     ` Luke Shumaker
  0 siblings, 1 reply; 144+ messages in thread
From: Eric Sunshine @ 2021-04-23 20:19 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: Git List, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, Jakub Suder, James Denholm,
	Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, Apr 23, 2021 at 3:43 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> The 'pull' and 'push' subcommands deserve their own sections in the tests.
> Add some basic tests for them.
>
> Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
> ---
> diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
> @@ -202,8 +202,8 @@ test_expect_success 'merge the added subproj again, should do nothing' '
>  test_expect_success 'merge new subproj history into subdir/ with a slash appended to the argument of --prefix' '
> -       test_create_repo "$test_count" &&
> -       test_create_repo "$test_count/subproj" &&
> +       subtree_test_create_repo "$test_count" &&
> +       subtree_test_create_repo "$test_count/subproj" &&
>         test_create_commit "$test_count" main1 &&
>         test_create_commit "$test_count/subproj" sub1 &&

This change doesn't seem to be related to the stated purpose of this
patch. Was it included by accident or is it just a drive-by "while at
it" fix that seems somewhat related since you're using
subtree_test_create_repo() in the newly-added tests? It might deserve
mention in the commit message.

> @@ -427,6 +427,133 @@ test_expect_success 'split "sub dir"/ with --branch for an incompatible branch'
> +test_expect_success 'pull requires path given by option --prefix must exist' '
> +       test_create_commit "$test_count/sub proj" sub1 &&
> +       (
> +               test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" HEAD >out 2>err &&
> +
> +               echo "'\''sub dir'\'' does not exist; use '\''git subtree add'\''" > expected &&
> +               test_must_be_empty out &&
> +               test_cmp expected err
> +       )
> +'

The use of single-quotes and escaped single-quotes within the
single-quoted test body is breaking my brain. Perhaps take advantage
of SQ from test-lib.sh and interoplate it into the string rather than
dealing with raw single-quotes?

    echo "this $SQ is a single-quote"

(After writing the above, I now see that you are just mirroring
existing practice in this test script. The single-quotes are
confusing, but following existing style may be important -- or not.)

> +test_expect_success 'pull basic operation' '
> +       subtree_test_create_repo "$test_count" &&
> +       subtree_test_create_repo "$test_count/sub proj" &&
> +       test_create_commit "$test_count" main1 &&
> +       test_create_commit "$test_count/sub proj" sub1 &&
> +       (
> +               cd "$test_count" &&
> +               git fetch ./"sub proj" HEAD &&

I was going to comment on the unusual:

    ./"sub proj"

rather than the more typical:

    "./sub proj"

but I see that that also is mirroring existing practice in this
script, so... [intentionally left blank]

> +test_expect_success 'push requires option --prefix' '
> +       subtree_test_create_repo "$test_count" &&
> +       subtree_test_create_repo "$test_count/sub proj" &&
> +       test_create_commit "$test_count" main1 &&
> +       test_create_commit "$test_count/sub proj" sub1 &&
> +       (
> +               cd "$test_count" &&
> +               git fetch ./"sub proj" HEAD &&
> +               git subtree add --prefix="sub dir" FETCH_HEAD &&
> +               echo "You must provide the --prefix option." > expected &&
> +               test_must_fail git subtree push "./sub proj" from-mainline > actual 2>&1 &&

Style: There is an inconsistent mix of "> foo" and ">foo" formatting
in the newly-added tests. These days, we prefer ">foo".

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 12/30] subtree: don't have loose code outside of a function
  2021-04-23 19:42 ` [PATCH 12/30] subtree: don't have loose code outside of a function Luke Shumaker
  2021-04-23 20:05   ` Luke Shumaker
@ 2021-04-23 20:23   ` Eric Sunshine
  2021-04-23 22:43     ` Luke Shumaker
  1 sibling, 1 reply; 144+ messages in thread
From: Eric Sunshine @ 2021-04-23 20:23 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: Git List, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, Jakub Suder, James Denholm,
	Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, Apr 23, 2021 at 3:43 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> Shove all of the loose code inside of a main() function.
>
> "Ignore space change" is probably helpful when viewing this diff.
>
> Signed-off-by: Luke Shumaker <lukeshu@datawire.io>

What is the purpose of this change? Does some subsequent commit depend
upon this or is it just a personal preference? The commit message
explains the "what" of the change but not the "why".

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 14/30] subtree: drop support for git < 1.7
  2021-04-23 19:42 ` [PATCH 14/30] subtree: drop support for git < 1.7 Luke Shumaker
  2021-04-23 20:07   ` Luke Shumaker
@ 2021-04-23 20:31   ` Eric Sunshine
  2021-04-23 23:28     ` Luke Shumaker
  1 sibling, 1 reply; 144+ messages in thread
From: Eric Sunshine @ 2021-04-23 20:31 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: Git List, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, Jakub Suder, James Denholm,
	Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, Apr 23, 2021 at 3:43 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> That was nice to have when git-subtree lived out-of-tree.  But now that
> it lives in git.git, it's not nescessary to keep around.

s/nescessary/necessary/

> Signed-off-by: Luke Shumaker <lukeshu@datawire.io>

Is there a higher reason for this change aside from "let's do it
because we can"? For instance, are subsequent changes going to take
advantage of features only present in more recent Git versions which
would be painful or impossible to support with the older Git?

The downside of this change is that, while git-subtree may live in
git.git, it's still just "contrib", so people might grab git-subtree
from a modern git.git but then end up using it with an older Git
installation. That's not to say that doing such a thing is guaranteed
to work anyhow, but we don't need to make it harder on people if there
isn't a good reason (hence my question about whether subsequent
changes will actually take advantage of newer Git features).

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 18/30] subtree: use $* instead of $@ as appropriate
  2021-04-23 19:42 ` [PATCH 18/30] subtree: use $* instead of $@ as appropriate Luke Shumaker
@ 2021-04-23 20:40   ` Eric Sunshine
  2021-04-23 23:50     ` Luke Shumaker
  0 siblings, 1 reply; 144+ messages in thread
From: Eric Sunshine @ 2021-04-23 20:40 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: Git List, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, Jakub Suder, James Denholm,
	Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, Apr 23, 2021 at 3:43 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> $* is for when you want to smash things together, whitespace-separated;
> $@ is for when you want them to be separate strings.  There are a couple
> of places in subtree that erroneously use $@ when smashing args together
> in to an error message.

Can we be explicit and say "$@" in the commit message rather than bare
$@ since the unquoted form is not magical and acts exactly like $*.

Also: s/in to/into/

Nit: I have some trouble following what the commit message is actually
trying to say with "smash things" and "separate strings". It might be
simpler to say merely that use of "$@" in these particular instances
is overkill and possibly misleading to readers not familiar with the
finer details of $* vs. "$@".

The patch itself makes sense.

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 23/30] subtree: add comments and sanity checks
  2021-04-23 19:42 ` [PATCH 23/30] subtree: add comments and sanity checks Luke Shumaker
@ 2021-04-23 20:58   ` Eric Sunshine
  2021-04-23 23:58     ` Luke Shumaker
  0 siblings, 1 reply; 144+ messages in thread
From: Eric Sunshine @ 2021-04-23 20:58 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: Git List, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, Jakub Suder, James Denholm,
	Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, Apr 23, 2021 at 3:43 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
> ---
> diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
> @@ -248,17 +263,22 @@ rev_exists () {
> +# Usage: try_remove_previous REV
> +#
>  # if a commit doesn't have a parent, this might not work.  But we only want

s/if/If/ perhaps

>  # to remove the parent from the rev-list, and since it doesn't exist, it won't
>  # be there anyway, so do nothing in that case.
> @@ -302,10 +322,12 @@ find_latest_squash () {
> +# Usage: find_existing_splits DIR REV
>  find_existing_splits () {
> +       assert test $# = 2
>         debug "Looking for prior splits..."
>         dir="$1"
> -       revs="$2"
> +       rev="$2"
> @@ -314,7 +336,7 @@ find_existing_splits () {
>         git log --grep="$grep_format" \
> -               --no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' $revs |
> +               --no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' "$rev" |

The caller of this function is passing in "$revs". Did you make this
semantic change because the caller's `revs` is guaranteed to be a
single rev? In any case, this change may deserve mention in the commit
message so readers don't have to wonder about it.

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 24/30] subtree: don't let debug and progress output clash
  2021-04-23 19:42 ` [PATCH 24/30] subtree: don't let debug and progress output clash Luke Shumaker
@ 2021-04-23 21:07   ` Eric Sunshine
  2021-04-24  0:44     ` Luke Shumaker
  0 siblings, 1 reply; 144+ messages in thread
From: Eric Sunshine @ 2021-04-23 21:07 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: Git List, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, Jakub Suder, James Denholm,
	Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, Apr 23, 2021 at 3:43 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> Currently, debug output (triggered by passing '-d') and progress output
> stomp on eachother.  The debug output is just streamed as lines to

s/eachother/each other/

> stderr, and the progress output is sent to stderr as '%s\r'.  It is
> difficult to distinguish between the debug output and a progress line.
> When writing to a terminal the debug lines hide progress lines.
>
> So, when '-d' has been passed, spit out progress as 'progress: %s\n',
> instead of as '%s\r', so that it can be detected, and so that the debug
> lines don't overwrite the progress when written to a terminal.

Makes perfect sense when output is to a terminal, though might be
annoying for the person who redirects stderr to a file. Just idly
wondering if it makes sense to take that case into consideration...
(but maybe it doesn't matter much when someone is working at debugging
a problem).

> Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
> ---
> diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
> @@ -53,7 +53,12 @@ debug () {
>  progress () {
>         if test -z "$GIT_QUIET"
>         then
> -               printf "%s\r" "$*" >&2
> +               if test -n "$arg_debug"
> +               then
> +                       printf "progress: %s\n" "$*" >&2
> +               else
> +                       printf "%s\r" "$*" >&2
> +               fi
>         fi
>  }

Subjective (not necessarily worth changing): An `echo` would suffice
in place of `printf "...\n"`:

    echo "progress: $*" >&2

It _might_ be worthwhile to have an in-code comment here explaining
why progress() behaves differently in debug mode, especially if the
reader is confused about why one case explicitly emits "progress:" and
the other doesn't.

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 04/30] subtree: t7900: use consistent formatting
  2021-04-23 19:42 ` [PATCH 04/30] subtree: t7900: use consistent formatting Luke Shumaker
@ 2021-04-23 21:51   ` Eric Sunshine
  2021-04-23 22:54     ` Luke Shumaker
  2021-04-27  7:17     ` Junio C Hamano
  0 siblings, 2 replies; 144+ messages in thread
From: Eric Sunshine @ 2021-04-23 21:51 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: Git List, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, Jakub Suder, James Denholm,
	Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, Apr 23, 2021 at 3:43 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> The formatting in t7900-subtree.sh isn't even consistent throughout the
> file.  Fix that; make it consistent throughout the file.
>
> Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
> ---
> diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
> @@ -23,26 +21,24 @@ subtree_test_create_repo()
> -check_equal()
> -{
> +check_equal () {
>         test_debug 'echo'
>         test_debug "echo \"check a:\" \"{$1}\""
>         test_debug "echo \"      b:\" \"{$2}\""
> -       if [ "$1" = "$2" ]; then
> +       if [ "$1" = "$2" ]
> +       then

We prefer `test` over `[`, so it might make sense to update that, as
well, along with these other style cleanups.

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 11/30] subtree: t7900: add porcelain tests for 'pull' and 'push'
  2021-04-23 20:19   ` Eric Sunshine
@ 2021-04-23 22:27     ` Luke Shumaker
  0 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 22:27 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Luke Shumaker, Git List, Avery Pennarun, Charles Bailey,
	Danny Lin, David A . Greene, David Aguilar, Jakub Suder,
	James Denholm, Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, 23 Apr 2021 14:19:28 -0600,
Eric Sunshine wrote:
> 
> On Fri, Apr 23, 2021 at 3:43 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> > The 'pull' and 'push' subcommands deserve their own sections in the tests.
> > Add some basic tests for them.
> >
> > Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
> > ---
> > diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
> > @@ -202,8 +202,8 @@ test_expect_success 'merge the added subproj again, should do nothing' '
> >  test_expect_success 'merge new subproj history into subdir/ with a slash appended to the argument of --prefix' '
> > -       test_create_repo "$test_count" &&
> > -       test_create_repo "$test_count/subproj" &&
> > +       subtree_test_create_repo "$test_count" &&
> > +       subtree_test_create_repo "$test_count/subproj" &&
> >         test_create_commit "$test_count" main1 &&
> >         test_create_commit "$test_count/subproj" sub1 &&
> 
> This change doesn't seem to be related to the stated purpose of this
> patch. Was it included by accident or is it just a drive-by "while at
> it" fix that seems somewhat related since you're using
> subtree_test_create_repo() in the newly-added tests? It might deserve
> mention in the commit message.

It was included by accident.  I guess I'll move it to be in the
"comment subtree_test_create_repo" commit, and mention it in the
commit message there.

> > @@ -427,6 +427,133 @@ test_expect_success 'split "sub dir"/ with --branch for an incompatible branch'
> > +test_expect_success 'pull requires path given by option --prefix must exist' '
> > +       test_create_commit "$test_count/sub proj" sub1 &&
> > +       (
> > +               test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" HEAD >out 2>err &&
> > +
> > +               echo "'\''sub dir'\'' does not exist; use '\''git subtree add'\''" > expected &&
> > +               test_must_be_empty out &&
> > +               test_cmp expected err
> > +       )
> > +'
> 
> The use of single-quotes and escaped single-quotes within the
> single-quoted test body is breaking my brain. Perhaps take advantage
> of SQ from test-lib.sh and interoplate it into the string rather than
> dealing with raw single-quotes?
> 
>     echo "this $SQ is a single-quote"
> 
> (After writing the above, I now see that you are just mirroring
> existing practice in this test script. The single-quotes are
> confusing, but following existing style may be important -- or not.)

I don't think I'll change it, for consistency with the rest of the
file... and I don't want to change the rest of the file, because
there's enough churn already.  But thanks for the tip, I wasn't aware
of $SQ.

> > +test_expect_success 'pull basic operation' '
> > +       subtree_test_create_repo "$test_count" &&
> > +       subtree_test_create_repo "$test_count/sub proj" &&
> > +       test_create_commit "$test_count" main1 &&
> > +       test_create_commit "$test_count/sub proj" sub1 &&
> > +       (
> > +               cd "$test_count" &&
> > +               git fetch ./"sub proj" HEAD &&
> 
> I was going to comment on the unusual:
> 
>     ./"sub proj"
> 
> rather than the more typical:
> 
>     "./sub proj"
> 
> but I see that that also is mirroring existing practice in this
> script, so... [intentionally left blank]

...yeah

> > +test_expect_success 'push requires option --prefix' '
> > +       subtree_test_create_repo "$test_count" &&
> > +       subtree_test_create_repo "$test_count/sub proj" &&
> > +       test_create_commit "$test_count" main1 &&
> > +       test_create_commit "$test_count/sub proj" sub1 &&
> > +       (
> > +               cd "$test_count" &&
> > +               git fetch ./"sub proj" HEAD &&
> > +               git subtree add --prefix="sub dir" FETCH_HEAD &&
> > +               echo "You must provide the --prefix option." > expected &&
> > +               test_must_fail git subtree push "./sub proj" from-mainline > actual 2>&1 &&
> 
> Style: There is an inconsistent mix of "> foo" and ">foo" formatting
> in the newly-added tests. These days, we prefer ">foo".

Indeed, so do I :) That test was copied with minimal modification from
the pre-existing 'split requires option --prefix' test, which wrote it
that way.  I guess I'll update the formatting commit to also normalize
away the whitespace after ">"s.

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 12/30] subtree: don't have loose code outside of a function
  2021-04-23 20:23   ` Eric Sunshine
@ 2021-04-23 22:43     ` Luke Shumaker
  2021-04-23 23:11       ` Eric Sunshine
  0 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 22:43 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Luke Shumaker, Git List, Avery Pennarun, Charles Bailey,
	Danny Lin, David A . Greene, David Aguilar, Jakub Suder,
	James Denholm, Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, 23 Apr 2021 14:23:18 -0600,
Eric Sunshine wrote:
> 
> On Fri, Apr 23, 2021 at 3:43 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> > Shove all of the loose code inside of a main() function.
> >
> > "Ignore space change" is probably helpful when viewing this diff.
> >
> > Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
> 
> What is the purpose of this change? Does some subsequent commit depend
> upon this or is it just a personal preference? The commit message
> explains the "what" of the change but not the "why".

Dropping the commit would surely cause me much trouble with rebasing
both the subsequent commits in this patchset and the commits I haven't
yet submitted.  But I don't think they "depend" on it.

I guess it is personal preference... one that I've developed from
years of maintaining Bash scripts.  It's in a nearby part of my brain
to "avoid global variables".  It's related to my notion that the
reason most people think shell scripts are so terrible is that most
people don't treat it like a real programming language and don't apply
normal programming best practices; that not littering code around
outside of a function is part of treating it like a real language (at
least once the program grows beyond a certain size, which git-subtree
surely has).  It's probably related to the Python idiom

    if __name__ == "__main__":
        main()

that is often seen at the bottom of Python scripts.

In this specific case, it's also moving the `set -- -h`, the `git
rev-parse --parseopt`, and the `. git-sh-setup` to be closer to all
the rest of the argument parsing, which is a readability win on its
own, IMO.

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 04/30] subtree: t7900: use consistent formatting
  2021-04-23 21:51   ` Eric Sunshine
@ 2021-04-23 22:54     ` Luke Shumaker
  2021-04-27  7:17     ` Junio C Hamano
  1 sibling, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 22:54 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Luke Shumaker, Git List, Avery Pennarun, Charles Bailey,
	Danny Lin, David A . Greene, David Aguilar, Jakub Suder,
	James Denholm, Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, 23 Apr 2021 15:51:53 -0600,
Eric Sunshine wrote:
> 
> On Fri, Apr 23, 2021 at 3:43 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> > The formatting in t7900-subtree.sh isn't even consistent throughout the
> > file.  Fix that; make it consistent throughout the file.
> >
> > Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
> > ---
> > diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
> > @@ -23,26 +21,24 @@ subtree_test_create_repo()
> > -check_equal()
> > -{
> > +check_equal () {
> >         test_debug 'echo'
> >         test_debug "echo \"check a:\" \"{$1}\""
> >         test_debug "echo \"      b:\" \"{$2}\""
> > -       if [ "$1" = "$2" ]; then
> > +       if [ "$1" = "$2" ]
> > +       then
> 
> We prefer `test` over `[`, so it might make sense to update that, as
> well, along with these other style cleanups.

OK, I'll include that in this commit.

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 12/30] subtree: don't have loose code outside of a function
  2021-04-23 22:43     ` Luke Shumaker
@ 2021-04-23 23:11       ` Eric Sunshine
  2021-04-23 23:37         ` Luke Shumaker
  0 siblings, 1 reply; 144+ messages in thread
From: Eric Sunshine @ 2021-04-23 23:11 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: Git List, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, Jakub Suder, James Denholm,
	Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, Apr 23, 2021 at 6:43 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> On Fri, 23 Apr 2021 14:23:18 -0600, Eric Sunshine wrote:
> > What is the purpose of this change? Does some subsequent commit depend
> > upon this or is it just a personal preference? The commit message
> > explains the "what" of the change but not the "why".
>
> Dropping the commit would surely cause me much trouble with rebasing
> both the subsequent commits in this patchset and the commits I haven't
> yet submitted.  But I don't think they "depend" on it.
>
> I guess it is personal preference... [...]

That's fine. I wasn't suggesting removing the commit but was
interested in having the commit message explain the reason for the
change, which is often the most important part of the commit message
to convince readers (reviewers) that the patch isn't just needless
noise. Obviously, if changes in subsequent patches become easier by
making this change, then that's easier to explain than something which
is mere personal preference -- which isn't to say that such preference
isn't important, especially if you're going to be living in the code
for a while.

> In this specific case, it's also moving the `set -- -h`, the `git
> rev-parse --parseopt`, and the `. git-sh-setup` to be closer to all
> the rest of the argument parsing, which is a readability win on its
> own, IMO.

If you happen to re-roll, perhaps update the commit message to include
a small bit of your explanation (which I've mostly snipped here). The
last bit about moving `set -- -h` and whatnot closer to the rest of
the argument parsing -- basically improving encapsulation -- may be
justification enough for readers.

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 14/30] subtree: drop support for git < 1.7
  2021-04-23 20:31   ` Eric Sunshine
@ 2021-04-23 23:28     ` Luke Shumaker
  2021-04-23 23:50       ` Eric Sunshine
  0 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 23:28 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Luke Shumaker, Git List, Avery Pennarun, Charles Bailey,
	Danny Lin, David A . Greene, David Aguilar, Jakub Suder,
	James Denholm, Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, 23 Apr 2021 14:31:46 -0600,
Eric Sunshine wrote:
> 
> On Fri, Apr 23, 2021 at 3:43 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> > That was nice to have when git-subtree lived out-of-tree.  But now that
> > it lives in git.git, it's not nescessary to keep around.
> 
> s/nescessary/necessary/

Ack.

> > Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
> 
> Is there a higher reason for this change aside from "let's do it
> because we can"? For instance, are subsequent changes going to take
> advantage of features only present in more recent Git versions which
> would be painful or impossible to support with the older Git?
> 
> The downside of this change is that, while git-subtree may live in
> git.git, it's still just "contrib", so people might grab git-subtree
> from a modern git.git but then end up using it with an older Git
> installation. That's not to say that doing such a thing is guaranteed
> to work anyhow, but we don't need to make it harder on people if there
> isn't a good reason (hence my question about whether subsequent
> changes will actually take advantage of newer Git features).

With the goal of making the whole thing easier to hack on, this just
seemed like an easy (if small) piece of fat to trim.

I guess I should include here that my bias is: With the 'git' package
that Parabola inherits from Arch Linux, you install 'git', you get a
working 'git subtree'.  If you want 'git send-email' to work, you also
need to install several other Perl packages.  Like, it might live in
the "contrib" directory, but it's de-facto at least as much a "part
of" Git as send-email is.

So that's the mindset I started from.  It looks like the latest macOS
supports me on that, but other distros like Fedora don't (Fedora has a
separate 'git-subtree' package).  If I take a step back, I realize
that mindset is flawed, but that's where I started from.

I don't think any of the other work depends on this (I think the only
commit that will conflict if we drop it is the "rename a some
variables" commit in this patchset).  It's very possible that
something else I do relies on newer git features (I'm not testing
against older git), but that's not something I did intentionally.

I just figured this would be a welcome piece of cleanup.  If that's
not the case, I don't have a problem dropping it.

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 12/30] subtree: don't have loose code outside of a function
  2021-04-23 23:11       ` Eric Sunshine
@ 2021-04-23 23:37         ` Luke Shumaker
  0 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 23:37 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Luke Shumaker, Git List, Avery Pennarun, Charles Bailey,
	Danny Lin, David A . Greene, David Aguilar, Jakub Suder,
	James Denholm, Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, 23 Apr 2021 17:11:11 -0600,
Eric Sunshine wrote:
> If you happen to re-roll, perhaps update the commit message to include
> a small bit of your explanation (which I've mostly snipped here). The
> last bit about moving `set -- -h` and whatnot closer to the rest of
> the argument parsing -- basically improving encapsulation -- may be
> justification enough for readers.

Whenever I end up explaining something on-list, I assume that I should
update either a comment or a commit-message when I re-roll :)

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 14/30] subtree: drop support for git < 1.7
  2021-04-23 23:28     ` Luke Shumaker
@ 2021-04-23 23:50       ` Eric Sunshine
  2021-04-24  0:20         ` Luke Shumaker
  0 siblings, 1 reply; 144+ messages in thread
From: Eric Sunshine @ 2021-04-23 23:50 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: Git List, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, Jakub Suder, James Denholm,
	Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, Apr 23, 2021 at 7:28 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> On Fri, 23 Apr 2021 14:31:46 -0600, Eric Sunshine wrote:
> > Is there a higher reason for this change aside from "let's do it
> > because we can"? For instance, are subsequent changes going to take
> > advantage of features only present in more recent Git versions which
> > would be painful or impossible to support with the older Git?
> >
> > The downside of this change is that, while git-subtree may live in
> > git.git, it's still just "contrib", so people might grab git-subtree
> > from a modern git.git but then end up using it with an older Git
> > installation. That's not to say that doing such a thing is guaranteed
> > to work anyhow, but we don't need to make it harder on people if there
> > isn't a good reason (hence my question about whether subsequent
> > changes will actually take advantage of newer Git features).
>
> With the goal of making the whole thing easier to hack on, this just
> seemed like an easy (if small) piece of fat to trim.
>
> I guess I should include here that my bias is: With the 'git' package
> that Parabola inherits from Arch Linux, you install 'git', you get a
> working 'git subtree'.  If you want 'git send-email' to work, you also
> need to install several other Perl packages.  Like, it might live in
> the "contrib" directory, but it's de-facto at least as much a "part
> of" Git as send-email is.
>
> So that's the mindset I started from.  It looks like the latest macOS
> supports me on that, but other distros like Fedora don't (Fedora has a
> separate 'git-subtree' package).  If I take a step back, I realize
> that mindset is flawed, but that's where I started from.
>
> I don't think any of the other work depends on this (I think the only
> commit that will conflict if we drop it is the "rename a some
> variables" commit in this patchset).  It's very possible that
> something else I do relies on newer git features (I'm not testing
> against older git), but that's not something I did intentionally.
>
> I just figured this would be a welcome piece of cleanup.  If that's
> not the case, I don't have a problem dropping it.

As a person who does not and has never used git-subtree, I don't have
a strong opinion, and any git-subtree opinion I might have wouldn't
carry any weight. I do have a bit of reflexive negative reaction to
such removals in general if there's no clear and strong benefit,
perhaps because my daily-use computers are old (perhaps ancient, as in
10-25 years old), so I am regularly stung by support being dropped by
packages I use. That's why I was asking if later patches would take
advantage of some newer Git feature.

Anyhow, I wasn't specifically asking for the patch to be dropped. As a
reviewer I rather wanted to better understand the reason for the
change beyond the somewhat hand-wavy "git-subtree now lives in-tree".
If you happen to re-roll, perhaps you can expand the commit message a
bit with something more concrete (for instance, how some packagers
include git-subtree by default) to better sell the patch to reviewers
who actually have investment in git-subtree (of which I am not one).
Considering how old Git <1.7 is, it's quite likely that no current
git-subtree users/reviewers would care about dropping support for such
old versions.

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 18/30] subtree: use $* instead of $@ as appropriate
  2021-04-23 20:40   ` Eric Sunshine
@ 2021-04-23 23:50     ` Luke Shumaker
  2021-04-24  5:18       ` Eric Sunshine
  0 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 23:50 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Luke Shumaker, Git List, Avery Pennarun, Charles Bailey,
	Danny Lin, David A . Greene, David Aguilar, Jakub Suder,
	James Denholm, Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, 23 Apr 2021 14:40:31 -0600,
Eric Sunshine wrote:
> 
> On Fri, Apr 23, 2021 at 3:43 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> > $* is for when you want to smash things together, whitespace-separated;
> > $@ is for when you want them to be separate strings.  There are a couple
> > of places in subtree that erroneously use $@ when smashing args together
> > in to an error message.
> 
> Can we be explicit and say "$@" in the commit message rather than bare
> $@ since the unquoted form is not magical and acts exactly like $*.
> 
> Also: s/in to/into/
> 
> Nit: I have some trouble following what the commit message is actually
> trying to say with "smash things" and "separate strings". It might be
> simpler to say merely that use of "$@" in these particular instances
> is overkill and possibly misleading to readers not familiar with the
> finer details of $* vs. "$@".
> 
> The patch itself makes sense.

How's this:

---
subtree: use "$*" instead of "$@" as appropriate

"$*" is for when you want to concatenate the args together,
whitespace-separated; and "$@" is for when you want them to be separate
strings.

There are several places in subtree that erroneously use $@ when
concatenating args together into an error message.

For instance, if the args are argv[1]="dead" and argv[2]="beef", then
the line

    die "You must provide exactly one revision.  Got: '$@'"

surely intends to call 'die' with the argument

    argv[1]="You must provide exactly one revision.  Got: 'dead beef'"

however, because the line used $@ instead of $*, it will actually call
'die' with the arguments

    argv[1]="You must provide exactly one revision.  Got: 'dead"
    argv[2]="beef'"

This isn't a big deal, because 'die' concatenates its arguments together
anyway (using "$*").  But that doesn't change the fact that it was a
mistake to use $@ instead of $*, even though in the end $@ still ended
up doing the right thing.
---

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 23/30] subtree: add comments and sanity checks
  2021-04-23 20:58   ` Eric Sunshine
@ 2021-04-23 23:58     ` Luke Shumaker
  0 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-23 23:58 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Luke Shumaker, Git List, Avery Pennarun, Charles Bailey,
	Danny Lin, David A . Greene, David Aguilar, Jakub Suder,
	James Denholm, Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, 23 Apr 2021 14:58:34 -0600,
Eric Sunshine wrote:
> 
> On Fri, Apr 23, 2021 at 3:43 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> > Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
> > ---
> > diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
> > @@ -248,17 +263,22 @@ rev_exists () {
> > +# Usage: try_remove_previous REV
> > +#
> >  # if a commit doesn't have a parent, this might not work.  But we only want
> 
> s/if/If/ perhaps

Ack.

> >  # to remove the parent from the rev-list, and since it doesn't exist, it won't
> >  # be there anyway, so do nothing in that case.
> > @@ -302,10 +322,12 @@ find_latest_squash () {
> > +# Usage: find_existing_splits DIR REV
> >  find_existing_splits () {
> > +       assert test $# = 2
> >         debug "Looking for prior splits..."
> >         dir="$1"
> > -       revs="$2"
> > +       rev="$2"
> > @@ -314,7 +336,7 @@ find_existing_splits () {
> >         git log --grep="$grep_format" \
> > -               --no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' $revs |
> > +               --no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' "$rev" |
> 
> The caller of this function is passing in "$revs". Did you make this
> semantic change because the caller's `revs` is guaranteed to be a
> single rev? In any case, this change may deserve mention in the commit
> message so readers don't have to wonder about it.

No it's not?  The only caller is

	unrevs="$(find_existing_splits "$dir" "$rev")" || exit $?

But yeah, this would be a good thing for me to call out in the commit
message.

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 14/30] subtree: drop support for git < 1.7
  2021-04-23 23:50       ` Eric Sunshine
@ 2021-04-24  0:20         ` Luke Shumaker
  0 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-24  0:20 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Luke Shumaker, Git List, Avery Pennarun, Charles Bailey,
	Danny Lin, David A . Greene, David Aguilar, Jakub Suder,
	James Denholm, Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, 23 Apr 2021 17:50:11 -0600,
Eric Sunshine wrote:
> 
> On Fri, Apr 23, 2021 at 7:28 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> > On Fri, 23 Apr 2021 14:31:46 -0600, Eric Sunshine wrote:
> > > Is there a higher reason for this change aside from "let's do it
> > > because we can"? For instance, are subsequent changes going to take
> > > advantage of features only present in more recent Git versions which
> > > would be painful or impossible to support with the older Git?
> > >
> > > The downside of this change is that, while git-subtree may live in
> > > git.git, it's still just "contrib", so people might grab git-subtree
> > > from a modern git.git but then end up using it with an older Git
> > > installation. That's not to say that doing such a thing is guaranteed
> > > to work anyhow, but we don't need to make it harder on people if there
> > > isn't a good reason (hence my question about whether subsequent
> > > changes will actually take advantage of newer Git features).
> >
> > With the goal of making the whole thing easier to hack on, this just
> > seemed like an easy (if small) piece of fat to trim.
> >
> > I guess I should include here that my bias is: With the 'git' package
> > that Parabola inherits from Arch Linux, you install 'git', you get a
> > working 'git subtree'.  If you want 'git send-email' to work, you also
> > need to install several other Perl packages.  Like, it might live in
> > the "contrib" directory, but it's de-facto at least as much a "part
> > of" Git as send-email is.
> >
> > So that's the mindset I started from.  It looks like the latest macOS
> > supports me on that, but other distros like Fedora don't (Fedora has a
> > separate 'git-subtree' package).  If I take a step back, I realize
> > that mindset is flawed, but that's where I started from.
> >
> > I don't think any of the other work depends on this (I think the only
> > commit that will conflict if we drop it is the "rename a some
> > variables" commit in this patchset).  It's very possible that
> > something else I do relies on newer git features (I'm not testing
> > against older git), but that's not something I did intentionally.
> >
> > I just figured this would be a welcome piece of cleanup.  If that's
> > not the case, I don't have a problem dropping it.
> 
> As a person who does not and has never used git-subtree, I don't have
> a strong opinion, and any git-subtree opinion I might have wouldn't
> carry any weight. I do have a bit of reflexive negative reaction to
> such removals in general if there's no clear and strong benefit,
> perhaps because my daily-use computers are old (perhaps ancient, as in
> 10-25 years old), so I am regularly stung by support being dropped by
> packages I use. That's why I was asking if later patches would take
> advantage of some newer Git feature.

I'm sending this from my work laptop, which is a little newer (2015),
but my personal laptop (2007) is sitting on the end-table.  So I
commiserate.  I'm a modern-software on old-hardware kind of guy
though, so I don't mind dropping support for old software versions.

> Anyhow, I wasn't specifically asking for the patch to be dropped. As a
> reviewer I rather wanted to better understand the reason for the
> change beyond the somewhat hand-wavy "git-subtree now lives in-tree".
> If you happen to re-roll, perhaps you can expand the commit message a
> bit with something more concrete (for instance, how some packagers
> include git-subtree by default) to better sell the patch to reviewers
> who actually have investment in git-subtree (of which I am not one).
> Considering how old Git <1.7 is, it's quite likely that no current
> git-subtree users/reviewers would care about dropping support for such
> old versions.

I'll expand the commit message.

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 24/30] subtree: don't let debug and progress output clash
  2021-04-23 21:07   ` Eric Sunshine
@ 2021-04-24  0:44     ` Luke Shumaker
  2021-04-24  4:54       ` Eric Sunshine
  0 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-24  0:44 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Luke Shumaker, Git List, Avery Pennarun, Charles Bailey,
	Danny Lin, David A . Greene, David Aguilar, Jakub Suder,
	James Denholm, Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, 23 Apr 2021 15:07:12 -0600,
Eric Sunshine wrote:
> 
> On Fri, Apr 23, 2021 at 3:43 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> > Currently, debug output (triggered by passing '-d') and progress output
> > stomp on eachother.  The debug output is just streamed as lines to
> 
> s/eachother/each other/

Ack.

> > stderr, and the progress output is sent to stderr as '%s\r'.  It is
> > difficult to distinguish between the debug output and a progress line.
> > When writing to a terminal the debug lines hide progress lines.
> >
> > So, when '-d' has been passed, spit out progress as 'progress: %s\n',
> > instead of as '%s\r', so that it can be detected, and so that the debug
> > lines don't overwrite the progress when written to a terminal.
> 
> Makes perfect sense when output is to a terminal, though might be
> annoying for the person who redirects stderr to a file. Just idly
> wondering if it makes sense to take that case into consideration...
> (but maybe it doesn't matter much when someone is working at debugging
> a problem).

The '%s\r' isn't really useful when written to a file, so this change
is useful in the file case too.  I'll add a comment and update the
commit-message.

> > Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
> > ---
> > diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
> > @@ -53,7 +53,12 @@ debug () {
> >  progress () {
> >         if test -z "$GIT_QUIET"
> >         then
> > -               printf "%s\r" "$*" >&2
> > +               if test -n "$arg_debug"
> > +               then
> > +                       printf "progress: %s\n" "$*" >&2
> > +               else
> > +                       printf "%s\r" "$*" >&2
> > +               fi
> >         fi
> >  }
> 
> Subjective (not necessarily worth changing): An `echo` would suffice
> in place of `printf "...\n"`:
> 
>     echo "progress: $*" >&2

echo would suffice, but I prefer the printf.

> It _might_ be worthwhile to have an in-code comment here explaining
> why progress() behaves differently in debug mode, especially if the
> reader is confused about why one case explicitly emits "progress:" and
> the other doesn't.

Adding a comment is a good idea, I'll do that.

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 24/30] subtree: don't let debug and progress output clash
  2021-04-24  0:44     ` Luke Shumaker
@ 2021-04-24  4:54       ` Eric Sunshine
  0 siblings, 0 replies; 144+ messages in thread
From: Eric Sunshine @ 2021-04-24  4:54 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: Git List, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, Jakub Suder, James Denholm,
	Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, Apr 23, 2021 at 8:44 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> On Fri, 23 Apr 2021 15:07:12 -0600, Eric Sunshine wrote:
> > Makes perfect sense when output is to a terminal, though might be
> > annoying for the person who redirects stderr to a file. Just idly
> > wondering if it makes sense to take that case into consideration...
> > (but maybe it doesn't matter much when someone is working at debugging
> > a problem).
>
> The '%s\r' isn't really useful when written to a file, so this change
> is useful in the file case too.  I'll add a comment and update the
> commit-message.

Ah, right. I didn't pay close enough attention to really notice that
the "\r"-terminated line was going to stderr, so ignore that bit in my
review comment.

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 18/30] subtree: use $* instead of $@ as appropriate
  2021-04-23 23:50     ` Luke Shumaker
@ 2021-04-24  5:18       ` Eric Sunshine
  0 siblings, 0 replies; 144+ messages in thread
From: Eric Sunshine @ 2021-04-24  5:18 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: Git List, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, Jakub Suder, James Denholm,
	Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, Apr 23, 2021 at 7:50 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> On Fri, 23 Apr 2021 14:40:31 -0600, Eric Sunshine wrote:
> > Nit: I have some trouble following what the commit message is actually
> > trying to say with "smash things" and "separate strings". It might be
> > simpler to say merely that use of "$@" in these particular instances
> > is overkill and possibly misleading to readers not familiar with the
> > finer details of $* vs. "$@".

Oof, I somehow misread the code this patch is touching and ended up
confusing myself, and the confusion bled into my review comments.
Sorry.

> How's this:
> ---
> subtree: use "$*" instead of "$@" as appropriate
>
> "$*" is for when you want to concatenate the args together,
> whitespace-separated; and "$@" is for when you want them to be separate
> strings.
>
> There are several places in subtree that erroneously use $@ when
> concatenating args together into an error message.
>
> For instance, if the args are argv[1]="dead" and argv[2]="beef", then
> the line
>
>     die "You must provide exactly one revision.  Got: '$@'"
>
> surely intends to call 'die' with the argument
>
>     argv[1]="You must provide exactly one revision.  Got: 'dead beef'"
>
> however, because the line used $@ instead of $*, it will actually call
> 'die' with the arguments
>
>     argv[1]="You must provide exactly one revision.  Got: 'dead"
>     argv[2]="beef'"
>
> This isn't a big deal, because 'die' concatenates its arguments together
> anyway (using "$*").  But that doesn't change the fact that it was a
> mistake to use $@ instead of $*, even though in the end $@ still ended
> up doing the right thing.

This explanation spells out the problem nicely.

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 27/30] subtree: allow --squash to be used with --rejoin
  2021-04-23 19:42 ` [PATCH 27/30] subtree: allow --squash to be used with --rejoin Luke Shumaker
@ 2021-04-24  5:50   ` Eric Sunshine
  2021-04-25  0:04     ` Luke Shumaker
  0 siblings, 1 reply; 144+ messages in thread
From: Eric Sunshine @ 2021-04-24  5:50 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: Git List, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, Jakub Suder, James Denholm,
	Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, Apr 23, 2021 at 3:43 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> Besides being a genuinely useful thing to do, this also just makes sense
> and harmonizes which flags may be used when.  `git subtree split
> --rejoin` amounts to "automatically go ahead and do a `git subtree
> merge` after doing the main `git subtree split`", so it's weird and
> arbitrary that you can't pass `--squash` to `git subtree split --rejoin`
> like you can `git subtree merge`.  It's weird that `git subtree split
> --rejoin` inherits `git subtree merge`'s `--message` but not `--squash`.
>
> Reconcile the situation by just having `split --rejoin` actually just
> call `merge` internally (or call `add` instead, as appropriate), so it
> can get access to the full `merge` behavior, including `--squash`.
>
> Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
> ---
> diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
> @@ -324,6 +324,41 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
> +test_expect_success 'split "sub dir"/ with --rejoin and --squash' '
> +       [...]
> +               SPLIT=$(git subtree split --prefix="sub dir" --annotate="*" --rejoin --squash) &&
> +
> +               ! git merge-base --is-ancestor $SUB HEAD &&
> +               ! git merge-base --is-ancestor $SPLIT HEAD &&

It's preferable to use `test_must_fail` rather than `!` for Git
commands (but not for non-Git commands) since `test_must_fail`
correctly distinguishes between an expected failure and an unexpected
one such as a crash, whereas `!` can't make that distinction and would
even consider a crashed Git invocation to be successful.

Existing tests in this script already employ `test_must_fail` rather
than `!`, so using `test_must_fail` would also match precedent.

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 27/30] subtree: allow --squash to be used with --rejoin
  2021-04-24  5:50   ` Eric Sunshine
@ 2021-04-25  0:04     ` Luke Shumaker
  0 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-25  0:04 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Luke Shumaker, Git List, Avery Pennarun, Charles Bailey,
	Danny Lin, David A . Greene, David Aguilar, Jakub Suder,
	James Denholm, Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Fri, 23 Apr 2021 23:50:08 -0600,
Eric Sunshine wrote:
> On Fri, Apr 23, 2021 at 3:43 PM Luke Shumaker <lukeshu@lukeshu.com> wrote:
> > +               ! git merge-base --is-ancestor $SUB HEAD &&
> > +               ! git merge-base --is-ancestor $SPLIT HEAD &&
> 
> It's preferable to use `test_must_fail` rather than `!` for Git
> commands

Indeed, this was an oversight on my part.  I'll adjust it.

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 30/30] subtree: be stricter about validating flags
  2021-04-23 19:42 ` [PATCH 30/30] subtree: be stricter about validating flags Luke Shumaker
@ 2021-04-25  2:55   ` Danny Lin
  2021-04-26 17:35     ` Luke Shumaker
  0 siblings, 1 reply; 144+ messages in thread
From: Danny Lin @ 2021-04-25  2:55 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: git develop, Avery Pennarun, Charles Bailey, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker, Eric Sunshine

>
> From: Luke Shumaker <lukeshu@datawire.io>
>
> Don't silently ignore a flag that's invalid for a given subcommand.  The
> user expected it to do something; we should tell the user that they are
> mistaken, instead of surprising the user.
>
> It could be argued that this change might break existing users.  I'd
> argue that those existing users are already broken, and they just don't
> know it.  Let them know that they're broken.
>
> Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
> ......

Thank you for the recent works, Luke.

I'd like to know if you are aware or working on the issue that branches
before "git subtree add --squash" are pushed via "git subtree push",
which has been reported by me at Tue, 16 Jul 2019 02:30:44 +0800, as I
haven't seen an obvious fix about it in the recent patches in a quick
glance.

Below is the original report (with a slight modification):

-----------------------------------------------------------------------

Say we have a repository with "master" and "sub" branches like below:

    A---B---C---D---E---F  master
               /
          X---Y

    X---Y  sub

where commits A and B include changes in subdirectory "sub", commit C
removes subdirectory "sub", commit D is generated by "git subtree add
-P sub Y", and commits E and F also include changes in subdirectory
"sub".

We'd get this if we run "git subtree push -P sub . sub" on master at F:

    X---Y---E'--F'  sub (after push)

On the other hand, if we have simliar trees except that commit D is
generated by "git subtree add --squash -P sub Y":

    A---B---C---D---E---F  master
               /
              Y'

    X---Y  sub

We'd expect to get this after we run "git subtree push -P sub . sub" on
master at F:

    X---Y---E'--F'  sub (after push, expected)

But actually we get this (in Git 2.22.0):

    A---B---C---D'--E'--F'  sub (after push, actual)
               /
          X---Y

This seems to be a side effect of 2.7.0 -> 2.7.1 in which a change is
made to include merged branches in "git subtree push", but mistakenly
causes branches before "git subtree add --squash" be included.



This bug is especially obvious if we simply run `git subtree push`
after a `git subtree add --squash`:

If master is at commit D, which is generated by
`git subtree add --squash -P sub Y`:

    A---B---C---D  master
               /
              Y'

    X---Y  sub

After running `git subtree push -P sub . sub`, we get:

    A---B---C---D'  sub (after push, actual)
               /
          X---Y

While the sub branch should not change at all!

This bug, seemingly introduced by 933cfeb90b5d03b4096db6d60494a6eedea25d03
critically makes --squash approach for `git subtree` almost unusable.

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 20/30] subtree: use "^{commit}" instead of "^0"
  2021-04-23 19:42 ` [PATCH 20/30] subtree: use "^{commit}" instead of "^0" Luke Shumaker
@ 2021-04-26  7:43   ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 144+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-04-26  7:43 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: git, Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano, pclouds, Roger L Strain,
	Techlive Zheng, Luke Shumaker


On Fri, Apr 23 2021, Luke Shumaker wrote:

> From: Luke Shumaker <lukeshu@datawire.io>
>
> They are synonyms.  Both are used in the file.  ^{commit} is clearer, so
> "standardize" on that.
>
> Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
> ---
>  contrib/subtree/git-subtree.sh | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
> index 9d365c9f2f..d200fbfed7 100755
> --- a/contrib/subtree/git-subtree.sh
> +++ b/contrib/subtree/git-subtree.sh
> @@ -302,7 +302,7 @@ find_latest_squash () {
>  			main="$b"
>  			;;
>  		git-subtree-split:)
> -			sub="$(git rev-parse "$b^0")" ||
> +			sub="$(git rev-parse "$b^{commit}")" ||
>  			die "could not rev-parse split hash $b from commit $sq"
>  			;;
>  		END)
> @@ -349,7 +349,7 @@ find_existing_splits () {
>  			main="$b"
>  			;;
>  		git-subtree-split:)
> -			sub="$(git rev-parse "$b^0")" ||
> +			sub="$(git rev-parse "$b^{commit}")" ||
>  			die "could not rev-parse split hash $b from commit $sq"
>  			;;
>  		END)

Not a new problem, but those error messages seem weird/bad, isn't that
message originally from find_existing_splits() and copied over to
find_latest_squash() where talking about "split hash" doesn't make
sense?

I'd expect something like "could not peel $b to commit" as the error for
both.

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 00/30] subtree: clean up, improve UX
  2021-04-23 20:12 ` [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
@ 2021-04-26  7:55   ` =?utf-8?B?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason
  2021-04-27  7:27   ` Junio C Hamano
  1 sibling, 0 replies; 144+ messages in thread
From: =?utf-8?B?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason @ 2021-04-26  7:55 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: git, Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	=?utf-8?B?Tmd1eeG7hW4gVGjDoWkgTmfhu41j?= Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker


On Fri, Apr 23 2021, Luke Shumaker wrote:

> On Fri, 23 Apr 2021 13:42:00 -0600,
> Luke Shumaker wrote:
>>                                                  I promise that
>> there's more work coming on top of it (we've discovered lots of ways
>> to break the "subtree split" algorithm, and come up with fixes for
>> most of them).
>
> Follow-up question: If in that work I changed the shebang from
> "#!/bin/sh" to "#!/usr/bin/env bash" and started using Bash arrays,
> would that be so bad?  Would that be land-able?

It's in contrib, so personally I don't care much. But e.g. on OSX that
means targeting some ancient (and going away?) version of bash + having
*BSDs needing to install bash for this etc.

Bash or not it seems to me like that argument parsing code could be much
simplified by simply declaring strings of arguments accepted for each
sub-command, and then parsing those arguments + dying on unknown ones.

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 19/30] subtree: give `$(git --exec-path)` precedence over `$PATH`
  2021-04-23 19:42 ` [PATCH 19/30] subtree: give `$(git --exec-path)` precedence over `$PATH` Luke Shumaker
@ 2021-04-26  8:27   ` =?utf-8?B?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason
  0 siblings, 0 replies; 144+ messages in thread
From: =?utf-8?B?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason @ 2021-04-26  8:27 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: git, Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	=?utf-8?B?Tmd1eeG7hW4gVGjDoWkgTmfhu41j?= Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker


On Fri, Apr 23 2021, Luke Shumaker wrote:

> From: Luke Shumaker <lukeshu@datawire.io>
>
> Other Git commands implemented in shell give `git --exec-path`
> precedence over the existing $PATH, but subtree gives the existing $PATH
> precedence.  Flip subtree's PATH around to match what other commands do.
>
> Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
> ---
>  contrib/subtree/git-subtree.sh | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
> index 3105eb8033..9d365c9f2f 100755
> --- a/contrib/subtree/git-subtree.sh
> +++ b/contrib/subtree/git-subtree.sh
> @@ -28,7 +28,7 @@ rejoin        merge the new branch back into HEAD
>  squash        merge subtree changes as a single commit
>  "
>  
> -PATH=$PATH:$(git --exec-path)
> +PATH=$(git --exec-path):$PATH

The history of git-subtree.sh suggests that instead of this change we'd
be better of removing this PATH assignment, and then later doing:

    . "$(git --exec-path)/git-sh-setup"

Isn't that closer to what git-subtree.sh wants here?

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 30/30] subtree: be stricter about validating flags
  2021-04-25  2:55   ` Danny Lin
@ 2021-04-26 17:35     ` Luke Shumaker
  0 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:35 UTC (permalink / raw)
  To: Danny Lin
  Cc: Luke Shumaker, git develop, Avery Pennarun, Charles Bailey,
	David A . Greene, David Aguilar, Jakub Suder, James Denholm,
	Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker, Eric Sunshine

On Sat, 24 Apr 2021 20:55:17 -0600,
Danny Lin wrote:
> Thank you for the recent works, Luke.
> 
> I'd like to know if you are aware or working on the issue that branches
> before "git subtree add --squash" are pushed via "git subtree push",
> which has been reported by me at Tue, 16 Jul 2019 02:30:44 +0800, as I
> haven't seen an obvious fix about it in the recent patches in a quick
> glance.

I'm not sure if I was aware of it before, but I'll be sure to keep it
in mind when I'm updating my (yet to be submitted) fixes to the
'split' algorithm.

Thanks for the additional test-case!

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* [PATCH v2 00/30] subtree: clean up, improve UX
  2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
                   ` (30 preceding siblings ...)
  2021-04-23 20:12 ` [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
@ 2021-04-26 17:44 ` Luke Shumaker
  2021-04-26 17:44   ` [PATCH v2 01/30] .gitignore: Ignore /git-subtree Luke Shumaker
                     ` (30 more replies)
  31 siblings, 31 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:44 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

The diff between v1 and v2 is largely stylistic.  The only
non-stylistic changes are fixing the tests to use `test_must_fail`
instead of `!`, and re-thinking the commit about fussing with PATH.

Ostensibly, this patch set is about improving various aspects of `git
subtree`'s user interface (and it is!), but it's also mostly about
setting the foundation and being "batch 1" of a bunch more changes to
subtree that I'm getting queued up.  So please forgive the large
amount of churn in the leading clean-up commits, I promise that
there's more work coming on top of it (we've discovered lots of ways
to break the "subtree split" algorithm, and come up with fixes for
most of them).  In the mean-time, I do think that the UX improvements
in this patchset are already worth it themselves.

 - The first 11 commits improve subtree's tests, largely around the
   code-quality of the tests, but a few of the commits do actually
   improve what's being tested.

 - The middle 12 commits improve the code-quality of subtree's
   implementation.

 - The final 7 commits improve various aspects of subtree's user
   experience, from readability of the debug output, to documentation,
   to option flag handling.

The very last commit is likely to be a little objectionable--it makes
some option flag parsing more strict, so there will probably be worry
that the change breaks existing users.  However, it's being strict
about arg combinations that were always invalid, the difference is
that now it reports that to the users and bails.  Those users were
already broken, they just didn't know it.  `git subtree` should tell
them.

Finally, two questions for my continuing work:

1. Would it be all right to amend CI to run the subtree tests?  And if
so, what would be the best way to do it?  For my own testing, I just
made the following edit to the main Makefile, but I'm not sure it's
the mos appropriate approach:

    --- a/Makefile
    +++ b/Makefile
    @@ -2836,6 +2836,7 @@
     
     test: all
            $(MAKE) -C t/ all
    +       $(MAKE) -C contrib/subtree/ test
     
     perf: all
            $(MAKE) -C t/perf/ all

The first two commits are about getting that to pass.  I'd prefer to
avoid that type of bitrot in the future.

2. If in that work I changed the shebang from "#!/bin/sh" to
"#!/usr/bin/env bash" and started using Bash arrays, would that be so
bad?  Would that be land-able?

Luke Shumaker (30):
  .gitignore: Ignore /git-subtree
  subtree: t7900: update for having the default branch name be 'main'
  subtree: t7900: use test-lib.sh's test_count
  subtree: t7900: use consistent formatting
    v2:
     - Also normalize on `test X` instead of `[ X ]`.
     - Also normalize on `>FILENAME` with no spaces.
     - Fix a few if statements with `if` and `then` on the same line
       that I missed in v1.
  subtree: t7900: comment subtree_test_create_repo
    v2:
     - Also switch the few uses of vanilla test_create_repo over to
       subtree_test_create_repo.  In v1 this was erroneously included
       in a different commit.
  subtree: t7900: use 'test' for string equality
  subtree: t7900: delete some dead code
  subtree: t7900: fix 'verify one file change per commit'
    v2:
     - Fix whitespace.
  subtree: t7900: rename last_commit_message to last_commit_subject
  subtree: t7900: add a test for the -h flag
  subtree: t7900: add porcelain tests for 'pull' and 'push'
    v2:
     - Don't switch unrelated uses of vanilla test_create_repo over to
       subtree_test_create_repo; this has been moved to happen in an
       earlier commit.
     - Fix whitespace.
  subtree: don't have loose code outside of a function
    v2:
     - Include rationale in the the commit message.
  subtree: more consistent error propagation
  subtree: drop support for git < 1.7
    v2:
     - Include rationale in the the commit message.
  subtree: use `git merge-base --is-ancestor`
  subtree: use git-sh-setup's `say`
  subtree: use more explicit variable names for cmdline args
  subtree: use "$*" instead of "$@" as appropriate
    v2:
     - Improve the commit message with quoting and clearer
       explanation.
  subtree: Don't fuss with PATH
    v2:
     - This commit changed entirely.  In v1 it changed how git-subtree
       adjusts the PATH.  In v2, it removes any fussing with the PATH,
       and in its place adds a pre-flight sanity check that it doesn't
       need to fuss with the PATH.
  subtree: use "^{commit}" instead of "^0"
  subtree: parse revs in individual cmd_ functions
  subtree: remove duplicate check
  subtree: add comments and sanity checks
    v2:
     - Expand on the the commit message.
     - Fix capitalization in one of the comments.
  subtree: don't let debug and progress output clash
    v2:
     - Reword the commit message to be clearer.
     - Add comments to the code.
     - Flip the `if` and `else` cases around, so that the comments
       read better.
  subtree: have $indent actually affect indentation
  subtree: give the docs a once-over
    v2:
     - behaviour -> behavior
  subtree: allow --squash to be used with --rejoin
    v2:
     - In the added tests, use `test_must_fail` instead of `!`, as
       appropriate.
  subtree: allow 'split' flags to be passed to 'push'
    v2:
     - In the added tests, use `test_must_fail` instead of `!`, as
       appropriate.
  subtree: push: allow specifying a local rev other than HEAD
  subtree: be stricter about validating flags

 .gitignore                         |    1 +
 contrib/subtree/git-subtree.sh     |  638 ++++++++-----
 contrib/subtree/git-subtree.txt    |  184 ++--
 contrib/subtree/t/t7900-subtree.sh | 1429 ++++++++++++++++++----------
 4 files changed, 1394 insertions(+), 858 deletions(-)

-- 
2.31.1

Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* [PATCH v2 01/30] .gitignore: Ignore /git-subtree
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
@ 2021-04-26 17:44   ` Luke Shumaker
  2021-04-26 17:44   ` [PATCH v2 02/30] subtree: t7900: update for having the default branch name be 'main' Luke Shumaker
                     ` (29 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:44 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Running `make -C contrib/subtree/ test` creates a `git-subtree` executable
in the root of the repo.  Add it to the .gitignore so that anyone hacking
on subtree won't have to deal with that noise.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index 3dcdb6bb5a..a203678e9e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -162,6 +162,7 @@
 /git-stripspace
 /git-submodule
 /git-submodule--helper
+/git-subtree
 /git-svn
 /git-switch
 /git-symbolic-ref
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 02/30] subtree: t7900: update for having the default branch name be 'main'
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
  2021-04-26 17:44   ` [PATCH v2 01/30] .gitignore: Ignore /git-subtree Luke Shumaker
@ 2021-04-26 17:44   ` Luke Shumaker
  2021-04-26 17:44   ` [PATCH v2 03/30] subtree: t7900: use test-lib.sh's test_count Luke Shumaker
                     ` (28 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:44 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Most of the tests had been converted to support
`GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main`, but `contrib/subtree/t/`
hadn't.

Convert it.  Most of the mentions of 'master' can just be replaced with
'HEAD'.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 117 +++++++++++++++--------------
 1 file changed, 59 insertions(+), 58 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 57ff4b25c1..4b982e6c2e 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -103,7 +103,7 @@ test_expect_success 'no merge from non-existent subtree' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		test_must_fail git subtree merge --prefix="sub dir" FETCH_HEAD
 	)
 '
@@ -116,8 +116,8 @@ test_expect_success 'no pull from non-existent subtree' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
-		test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" master
+		git fetch ./"sub proj" HEAD &&
+		test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" HEAD
 	)'
 
 next_test
@@ -128,7 +128,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Add '\''sub dir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
@@ -142,7 +142,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix and --me
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Added subproject"
 	)
@@ -156,7 +156,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix as -P an
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add -P "sub dir" -m "Added subproject" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Added subproject"
 	)
@@ -170,7 +170,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --squash and --pr
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject with squash" --squash FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Added subproject with squash"
 	)
@@ -188,13 +188,13 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count/sub proj" sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
@@ -208,13 +208,13 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix and -
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count/sub proj" sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merged changes from subproject"
 	)
@@ -228,13 +228,13 @@ test_expect_success 'merge new subproj history into sub dir/ with --squash and -
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count/sub proj" sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject using squash" --squash FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merged changes from subproject using squash"
 	)
@@ -248,7 +248,7 @@ test_expect_success 'merge the added subproj again, should do nothing' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		# this shouldn not actually do anything, since FETCH_HEAD
 		# is already a parent
@@ -265,13 +265,13 @@ test_expect_success 'merge new subproj history into subdir/ with a slash appende
 	test_create_commit "$test_count/subproj" sub1 &&
 	(
 		cd "$test_count" &&
-		git fetch ./subproj master &&
+		git fetch ./subproj HEAD &&
 		git subtree add --prefix=subdir/ FETCH_HEAD
 	) &&
 	test_create_commit "$test_count/subproj" sub2 &&
 	(
 		cd "$test_count" &&
-		git fetch ./subproj master &&
+		git fetch ./subproj HEAD &&
 		git subtree merge --prefix=subdir/ FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
@@ -289,7 +289,7 @@ test_expect_success 'split requires option --prefix' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		echo "You must provide the --prefix option." > expected &&
 		test_must_fail git subtree split > actual 2>&1 &&
@@ -309,7 +309,7 @@ test_expect_success 'split requires path given by option --prefix must exist' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		echo "'\''non-existent-directory'\'' does not exist; use '\''git subtree add'\''" > expected &&
 		test_must_fail git subtree split --prefix=non-existent-directory > actual 2>&1 &&
@@ -329,7 +329,7 @@ test_expect_success 'split sub dir/ with --rejoin' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -338,7 +338,7 @@ test_expect_success 'split sub dir/ with --rejoin' '
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --rejoin &&
@@ -370,7 +370,7 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -379,7 +379,7 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --message="Split & rejoin" --annotate="*" --rejoin &&
 		check_equal "$(last_commit_message)" "Split & rejoin"
@@ -394,7 +394,7 @@ test_expect_success 'split "sub dir"/ with --branch' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -403,7 +403,7 @@ test_expect_success 'split "sub dir"/ with --branch' '
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br &&
@@ -419,7 +419,7 @@ test_expect_success 'check hash of split' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -428,7 +428,7 @@ test_expect_success 'check hash of split' '
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br &&
@@ -451,7 +451,7 @@ test_expect_success 'split "sub dir"/ with --branch for an existing branch' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git branch subproj-br FETCH_HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
@@ -461,7 +461,7 @@ test_expect_success 'split "sub dir"/ with --branch for an existing branch' '
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br &&
@@ -478,7 +478,7 @@ test_expect_success 'split "sub dir"/ with --branch for an incompatible branch'
 	(
 		cd "$subtree_test_count" &&
 		git branch init HEAD &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -487,7 +487,7 @@ test_expect_success 'split "sub dir"/ with --branch for an incompatible branch'
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		test_must_fail git subtree split --prefix="sub dir" --branch init
 	)
@@ -505,7 +505,7 @@ test_expect_success 'make sure exactly the right set of files ends up in the sub
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -514,7 +514,7 @@ test_expect_success 'make sure exactly the right set of files ends up in the sub
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
@@ -555,7 +555,7 @@ test_expect_success 'make sure the subproj *only* contains commits that affect t
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -564,7 +564,7 @@ test_expect_success 'make sure the subproj *only* contains commits that affect t
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
@@ -606,7 +606,7 @@ test_expect_success 'make sure exactly the right set of files ends up in the mai
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -615,7 +615,7 @@ test_expect_success 'make sure exactly the right set of files ends up in the mai
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
@@ -643,7 +643,7 @@ test_expect_success 'make sure exactly the right set of files ends up in the mai
 	) &&
 	(
 		cd "$subtree_test_count" &&
-		git subtree pull --prefix="sub dir" ./"sub proj" master &&
+		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		test_write_lines main1 main2 >chkm &&
 		test_write_lines main-sub1 main-sub2 main-sub3 main-sub4 >chkms &&
@@ -666,7 +666,7 @@ test_expect_success 'make sure each filename changed exactly once in the entire
 	(
 		cd "$subtree_test_count" &&
 		git config log.date relative &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -675,7 +675,7 @@ test_expect_success 'make sure each filename changed exactly once in the entire
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
@@ -703,7 +703,7 @@ test_expect_success 'make sure each filename changed exactly once in the entire
 	) &&
 	(
 		cd "$subtree_test_count" &&
-		git subtree pull --prefix="sub dir" ./"sub proj" master &&
+		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		test_write_lines main1 main2 >chkm &&
 		test_write_lines sub1 sub2 sub3 sub4 >chks &&
@@ -731,7 +731,7 @@ test_expect_success 'make sure the --rejoin commits never make it into subproj'
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -740,7 +740,7 @@ test_expect_success 'make sure the --rejoin commits never make it into subproj'
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
@@ -768,7 +768,7 @@ test_expect_success 'make sure the --rejoin commits never make it into subproj'
 	) &&
 	(
 		cd "$subtree_test_count" &&
-		git subtree pull --prefix="sub dir" ./"sub proj" master &&
+		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 		check_equal "$(git log --pretty=format:"%s" HEAD^2 | grep -i split)" ""
 	)
 '
@@ -781,7 +781,7 @@ test_expect_success 'make sure no "git subtree" tagged commits make it into subp
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -790,7 +790,7 @@ test_expect_success 'make sure no "git subtree" tagged commits make it into subp
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
@@ -818,7 +818,7 @@ test_expect_success 'make sure no "git subtree" tagged commits make it into subp
 	) &&
 	(
 		cd "$subtree_test_count" &&
-		git subtree pull --prefix="sub dir" ./"sub proj" master &&
+		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		# They are meaningless to subproj since one side of the merge refers to the mainline
 		check_equal "$(git log --pretty=format:"%s%n%b" HEAD^2 | grep "git-subtree.*:")" ""
@@ -837,13 +837,13 @@ test_expect_success 'make sure "git subtree split" find the correct parent' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count/sub proj" sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git branch subproj-ref FETCH_HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
@@ -853,7 +853,7 @@ test_expect_success 'make sure "git subtree split" find the correct parent' '
 		git subtree split --prefix="sub dir" --branch subproj-br &&
 
 		# at this point, the new commit parent should be subproj-ref, if it is
-		# not, something went wrong (the "newparent" of "master~" commit should
+		# not, something went wrong (the "newparent" of "HEAD~" commit should
 		# have been sub2, but it was not, because its cache was not set to
 		# itself)
 		check_equal "$(git log --pretty=format:%P -1 subproj-br)" "$(git rev-parse subproj-ref)"
@@ -868,13 +868,13 @@ test_expect_success 'split a new subtree without --onto option' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count/sub proj" sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -903,14 +903,14 @@ test_expect_success 'verify one file change per commit' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git branch sub1 FETCH_HEAD &&
 		git subtree add --prefix="sub dir" sub1
 	) &&
 	test_create_commit "$subtree_test_count/sub proj" sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -947,7 +947,7 @@ test_expect_success 'push split to subproj' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -958,7 +958,7 @@ test_expect_success 'push split to subproj' '
 		cd $subtree_test_count/"sub proj" &&
                 git branch sub-branch-1 &&
                 cd .. &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
@@ -994,6 +994,7 @@ test_expect_success 'push split to subproj' '
 next_test
 test_expect_success 'subtree descendant check' '
 	subtree_test_create_repo "$subtree_test_count" &&
+	defaultBranch=$(sed "s,ref: refs/heads/,," "$subtree_test_count/.git/HEAD") &&
 	test_create_commit "$subtree_test_count" folder_subtree/a &&
 	(
 		cd "$subtree_test_count" &&
@@ -1010,7 +1011,7 @@ test_expect_success 'subtree descendant check' '
 	(
 		cd "$subtree_test_count" &&
 		git cherry-pick $cherry &&
-		git checkout master &&
+		git checkout $defaultBranch &&
 		git merge -m "merge should be kept on subtree" branch &&
 		git branch no_subtree_work_branch
 	) &&
@@ -1022,10 +1023,10 @@ test_expect_success 'subtree descendant check' '
 	test_create_commit "$subtree_test_count" not_a_subtree_change &&
 	(
 		cd "$subtree_test_count" &&
-		git checkout master &&
+		git checkout $defaultBranch &&
 		git merge -m "merge should be skipped on subtree" no_subtree_work_branch &&
 
-		git subtree split --prefix folder_subtree/ --branch subtree_tip master &&
+		git subtree split --prefix folder_subtree/ --branch subtree_tip $defaultBranch &&
 		git subtree split --prefix folder_subtree/ --branch subtree_branch branch &&
 		check_equal $(git rev-list --count subtree_tip..subtree_branch) 0
 	)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 03/30] subtree: t7900: use test-lib.sh's test_count
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
  2021-04-26 17:44   ` [PATCH v2 01/30] .gitignore: Ignore /git-subtree Luke Shumaker
  2021-04-26 17:44   ` [PATCH v2 02/30] subtree: t7900: update for having the default branch name be 'main' Luke Shumaker
@ 2021-04-26 17:44   ` Luke Shumaker
  2021-04-26 17:44   ` [PATCH v2 04/30] subtree: t7900: use consistent formatting Luke Shumaker
                     ` (27 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:44 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Use test-lib.sh's `test_count`, instead instead of having
t7900-subtree.sh do its own book-keeping with `subtree_test_count` that
has to be explicitly incremented by calling `next_test`.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 636 ++++++++++++++---------------
 1 file changed, 300 insertions(+), 336 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 4b982e6c2e..a6351d9195 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -86,90 +86,79 @@ last_commit_message()
 	git log --pretty=format:%s -1
 }
 
-subtree_test_count=0
-next_test() {
-	subtree_test_count=$(($subtree_test_count+1))
-}
-
 #
 # Tests for 'git subtree add'
 #
 
-next_test
 test_expect_success 'no merge from non-existent subtree' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		test_must_fail git subtree merge --prefix="sub dir" FETCH_HEAD
 	)
 '
 
-next_test
 test_expect_success 'no pull from non-existent subtree' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" HEAD
 	)'
 
-next_test
 test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Add '\''sub dir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
-next_test
 test_expect_success 'add subproj as subtree into sub dir/ with --prefix and --message' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Added subproject"
 	)
 '
 
-next_test
 test_expect_success 'add subproj as subtree into sub dir/ with --prefix as -P and --message as -m' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add -P "sub dir" -m "Added subproject" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Added subproject"
 	)
 '
 
-next_test
 test_expect_success 'add subproj as subtree into sub dir/ with --squash and --prefix and --message' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject with squash" --squash FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Added subproject with squash"
@@ -180,74 +169,70 @@ test_expect_success 'add subproj as subtree into sub dir/ with --squash and --pr
 # Tests for 'git subtree merge'
 #
 
-next_test
 test_expect_success 'merge new subproj history into sub dir/ with --prefix' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
-next_test
 test_expect_success 'merge new subproj history into sub dir/ with --prefix and --message' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merged changes from subproject"
 	)
 '
 
-next_test
 test_expect_success 'merge new subproj history into sub dir/ with --squash and --prefix and --message' '
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	subtree_test_create_repo "$subtree_test_count" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	subtree_test_create_repo "$test_count" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject using squash" --squash FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merged changes from subproject using squash"
 	)
 '
 
-next_test
 test_expect_success 'merge the added subproj again, should do nothing' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		# this shouldn not actually do anything, since FETCH_HEAD
@@ -257,7 +242,6 @@ test_expect_success 'merge the added subproj again, should do nothing' '
 	)
 '
 
-next_test
 test_expect_success 'merge new subproj history into subdir/ with a slash appended to the argument of --prefix' '
 	test_create_repo "$test_count" &&
 	test_create_repo "$test_count/subproj" &&
@@ -281,14 +265,13 @@ test_expect_success 'merge new subproj history into subdir/ with a slash appende
 # Tests for 'git subtree split'
 #
 
-next_test
 test_expect_success 'split requires option --prefix' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		echo "You must provide the --prefix option." > expected &&
@@ -301,14 +284,13 @@ test_expect_success 'split requires option --prefix' '
 	)
 '
 
-next_test
 test_expect_success 'split requires path given by option --prefix must exist' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		echo "'\''non-existent-directory'\'' does not exist; use '\''git subtree add'\''" > expected &&
@@ -321,23 +303,22 @@ test_expect_success 'split requires path given by option --prefix must exist' '
 	)
 '
 
-next_test
 test_expect_success 'split sub dir/ with --rejoin' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
@@ -346,12 +327,11 @@ test_expect_success 'split sub dir/ with --rejoin' '
 	)
  '
 
-next_test
 test_expect_success 'split sub dir/ with --rejoin from scratch' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	test_create_commit "$subtree_test_count" main1 &&
+	subtree_test_create_repo "$test_count" &&
+	test_create_commit "$test_count" main1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		mkdir "sub dir" &&
 		echo file >"sub dir"/file &&
 		git add "sub dir/file" &&
@@ -362,23 +342,22 @@ test_expect_success 'split sub dir/ with --rejoin from scratch' '
 	)
  '
 
-next_test
 test_expect_success 'split sub dir/ with --rejoin and --message' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --message="Split & rejoin" --annotate="*" --rejoin &&
@@ -386,23 +365,22 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
 	)
 '
 
-next_test
 test_expect_success 'split "sub dir"/ with --branch' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
@@ -411,23 +389,22 @@ test_expect_success 'split "sub dir"/ with --branch' '
 	)
 '
 
-next_test
 test_expect_success 'check hash of split' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
@@ -443,24 +420,23 @@ test_expect_success 'check hash of split' '
 	)
 '
 
-next_test
 test_expect_success 'split "sub dir"/ with --branch for an existing branch' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git branch subproj-br FETCH_HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
@@ -469,24 +445,23 @@ test_expect_success 'split "sub dir"/ with --branch for an existing branch' '
 	)
 '
 
-next_test
 test_expect_success 'split "sub dir"/ with --branch for an incompatible branch' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git branch init HEAD &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		test_must_fail git subtree split --prefix="sub dir" --branch init
@@ -497,46 +472,45 @@ test_expect_success 'split "sub dir"/ with --branch for an incompatible branch'
 # Validity checking
 #
 
-next_test
 test_expect_success 'make sure exactly the right set of files ends up in the subproj' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub3 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count/sub proj" sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub4 &&
+	test_create_commit "$test_count/sub proj" sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub4 &&
+	test_create_commit "$test_count" "sub dir"/main-sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD &&
 
@@ -547,46 +521,45 @@ test_expect_success 'make sure exactly the right set of files ends up in the sub
 	)
 '
 
-next_test
 test_expect_success 'make sure the subproj *only* contains commits that affect the "sub dir"' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub3 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count/sub proj" sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub4 &&
+	test_create_commit "$test_count/sub proj" sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub4 &&
+	test_create_commit "$test_count" "sub dir"/main-sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD &&
 
@@ -598,51 +571,50 @@ test_expect_success 'make sure the subproj *only* contains commits that affect t
 	)
 '
 
-next_test
 test_expect_success 'make sure exactly the right set of files ends up in the mainline' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub3 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count/sub proj" sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub4 &&
+	test_create_commit "$test_count/sub proj" sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub4 &&
+	test_create_commit "$test_count" "sub dir"/main-sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		test_write_lines main1 main2 >chkm &&
@@ -657,52 +629,51 @@ test_expect_success 'make sure exactly the right set of files ends up in the mai
 	)
 '
 
-next_test
 test_expect_success 'make sure each filename changed exactly once in the entire history' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git config log.date relative &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub3 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count/sub proj" sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub4 &&
+	test_create_commit "$test_count/sub proj" sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub4 &&
+	test_create_commit "$test_count" "sub dir"/main-sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		test_write_lines main1 main2 >chkm &&
@@ -723,101 +694,99 @@ test_expect_success 'make sure each filename changed exactly once in the entire
 	)
 '
 
-next_test
 test_expect_success 'make sure the --rejoin commits never make it into subproj' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub3 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count/sub proj" sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub4 &&
+	test_create_commit "$test_count/sub proj" sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub4 &&
+	test_create_commit "$test_count" "sub dir"/main-sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 		check_equal "$(git log --pretty=format:"%s" HEAD^2 | grep -i split)" ""
 	)
 '
 
-next_test
 test_expect_success 'make sure no "git subtree" tagged commits make it into subproj' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub3 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count/sub proj" sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		 git merge FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub4 &&
+	test_create_commit "$test_count/sub proj" sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub4 &&
+	test_create_commit "$test_count" "sub dir"/main-sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		# They are meaningless to subproj since one side of the merge refers to the mainline
@@ -829,27 +798,26 @@ test_expect_success 'make sure no "git subtree" tagged commits make it into subp
 # A new set of tests
 #
 
-next_test
 test_expect_success 'make sure "git subtree split" find the correct parent' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git branch subproj-ref FETCH_HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --branch subproj-br &&
 
 		# at this point, the new commit parent should be subproj-ref, if it is
@@ -860,32 +828,31 @@ test_expect_success 'make sure "git subtree split" find the correct parent' '
 	)
 '
 
-next_test
 test_expect_success 'split a new subtree without --onto option' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --branch subproj-br
 	) &&
-	mkdir "$subtree_test_count"/"sub dir2" &&
-	test_create_commit "$subtree_test_count" "sub dir2"/main-sub2 &&
+	mkdir "$test_count"/"sub dir2" &&
+	test_create_commit "$test_count" "sub dir2"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 
 		# also test that we still can split out an entirely new subtree
 		# if the parent of the first commit in the tree is not empty,
@@ -895,33 +862,32 @@ test_expect_success 'split a new subtree without --onto option' '
 	)
 '
 
-next_test
 test_expect_success 'verify one file change per commit' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git branch sub1 FETCH_HEAD &&
 		git subtree add --prefix="sub dir" sub1
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --branch subproj-br
 	) &&
-	mkdir "$subtree_test_count"/"sub dir2" &&
-	test_create_commit "$subtree_test_count" "sub dir2"/main-sub2 &&
+	mkdir "$test_count"/"sub dir2" &&
+	test_create_commit "$test_count" "sub dir2"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir2" --branch subproj2-br &&
 
 		x= &&
@@ -939,31 +905,30 @@ test_expect_success 'verify one file change per commit' '
 	)
 '
 
-next_test
 test_expect_success 'push split to subproj' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd $subtree_test_count/"sub proj" &&
+		cd $test_count/"sub proj" &&
                 git branch sub-branch-1 &&
                 cd .. &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
         (
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 	        git subtree push ./"sub proj" --prefix "sub dir" sub-branch-1 &&
                 cd ./"sub proj" &&
                 git checkout sub-branch-1 &&
@@ -991,38 +956,37 @@ test_expect_success 'push split to subproj' '
 #   set of commits.
 #
 
-next_test
 test_expect_success 'subtree descendant check' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	defaultBranch=$(sed "s,ref: refs/heads/,," "$subtree_test_count/.git/HEAD") &&
-	test_create_commit "$subtree_test_count" folder_subtree/a &&
+	subtree_test_create_repo "$test_count" &&
+	defaultBranch=$(sed "s,ref: refs/heads/,," "$test_count/.git/HEAD") &&
+	test_create_commit "$test_count" folder_subtree/a &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git branch branch
 	) &&
-	test_create_commit "$subtree_test_count" folder_subtree/0 &&
-	test_create_commit "$subtree_test_count" folder_subtree/b &&
-	cherry=$(cd "$subtree_test_count"; git rev-parse HEAD) &&
+	test_create_commit "$test_count" folder_subtree/0 &&
+	test_create_commit "$test_count" folder_subtree/b &&
+	cherry=$(cd "$test_count"; git rev-parse HEAD) &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git checkout branch
 	) &&
-	test_create_commit "$subtree_test_count" commit_on_branch &&
+	test_create_commit "$test_count" commit_on_branch &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git cherry-pick $cherry &&
 		git checkout $defaultBranch &&
 		git merge -m "merge should be kept on subtree" branch &&
 		git branch no_subtree_work_branch
 	) &&
-	test_create_commit "$subtree_test_count" folder_subtree/d &&
+	test_create_commit "$test_count" folder_subtree/d &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git checkout no_subtree_work_branch
 	) &&
-	test_create_commit "$subtree_test_count" not_a_subtree_change &&
+	test_create_commit "$test_count" not_a_subtree_change &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git checkout $defaultBranch &&
 		git merge -m "merge should be skipped on subtree" no_subtree_work_branch &&
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 04/30] subtree: t7900: use consistent formatting
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (2 preceding siblings ...)
  2021-04-26 17:44   ` [PATCH v2 03/30] subtree: t7900: use test-lib.sh's test_count Luke Shumaker
@ 2021-04-26 17:44   ` Luke Shumaker
  2021-04-26 19:57     ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 05/30] subtree: t7900: comment subtree_test_create_repo Luke Shumaker
                     ` (26 subsequent siblings)
  30 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:44 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

The formatting in t7900-subtree.sh isn't even consistent throughout the
file.  Fix that; make it consistent throughout the file.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - Also normalize on `test X` instead of `[ X ]`.
 - Also normalize on `>FILENAME` with no spaces.
 - Fix a few if statements with `if` and `then` on the same line
   that I missed in v1.

 contrib/subtree/t/t7900-subtree.sh | 64 +++++++++++++++---------------
 1 file changed, 31 insertions(+), 33 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index a6351d9195..5e1390c287 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -11,11 +11,9 @@ and split subcommands of git subtree.
 
 TEST_DIRECTORY=$(pwd)/../../../t
 export TEST_DIRECTORY
+. "$TEST_DIRECTORY"/test-lib.sh
 
-. ../../../t/test-lib.sh
-
-subtree_test_create_repo()
-{
+subtree_test_create_repo () {
 	test_create_repo "$1" &&
 	(
 		cd "$1" &&
@@ -23,26 +21,24 @@ subtree_test_create_repo()
 	)
 }
 
-create()
-{
+create () {
 	echo "$1" >"$1" &&
 	git add "$1"
 }
 
-check_equal()
-{
+check_equal () {
 	test_debug 'echo'
 	test_debug "echo \"check a:\" \"{$1}\""
 	test_debug "echo \"      b:\" \"{$2}\""
-	if [ "$1" = "$2" ]; then
+	if test "$1" = "$2"
+	then
 		return 0
 	else
 		return 1
 	fi
 }
 
-undo()
-{
+undo () {
 	git reset --hard HEAD~
 }
 
@@ -50,15 +46,17 @@ undo()
 # The original set of commits changed only one file each.
 # A multi-file change would imply that we pruned commits
 # too aggressively.
-join_commits()
-{
+join_commits () {
 	commit=
 	all=
 	while read x y; do
-		if [ -z "$x" ]; then
+		if test -z "$x"
+		then
 			continue
-		elif [ "$x" = "commit:" ]; then
-			if [ -n "$commit" ]; then
+		elif test "$x" = "commit:"
+		then
+			if test -n "$commit"
+			then
 				echo "$commit $all"
 				all=
 			fi
@@ -70,7 +68,7 @@ join_commits()
 	echo "$commit $all"
 }
 
-test_create_commit() (
+test_create_commit () (
 	repo=$1 &&
 	commit=$2 &&
 	cd "$repo" &&
@@ -81,8 +79,7 @@ test_create_commit() (
 	git commit -m "$commit" || error "Could not commit"
 )
 
-last_commit_message()
-{
+last_commit_message () {
 	git log --pretty=format:%s -1
 }
 
@@ -111,7 +108,8 @@ test_expect_success 'no pull from non-existent subtree' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" HEAD
-	)'
+	)
+'
 
 test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
 	subtree_test_create_repo "$test_count" &&
@@ -274,8 +272,8 @@ test_expect_success 'split requires option --prefix' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
-		echo "You must provide the --prefix option." > expected &&
-		test_must_fail git subtree split > actual 2>&1 &&
+		echo "You must provide the --prefix option." >expected &&
+		test_must_fail git subtree split >actual 2>&1 &&
 		test_debug "printf '"expected: "'" &&
 		test_debug "cat expected" &&
 		test_debug "printf '"actual: "'" &&
@@ -293,8 +291,8 @@ test_expect_success 'split requires path given by option --prefix must exist' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
-		echo "'\''non-existent-directory'\'' does not exist; use '\''git subtree add'\''" > expected &&
-		test_must_fail git subtree split --prefix=non-existent-directory > actual 2>&1 &&
+		echo "'\''non-existent-directory'\'' does not exist; use '\''git subtree add'\''" >expected &&
+		test_must_fail git subtree split --prefix=non-existent-directory >actual 2>&1 &&
 		test_debug "printf '"expected: "'" &&
 		test_debug "cat expected" &&
 		test_debug "printf '"actual: "'" &&
@@ -325,7 +323,7 @@ test_expect_success 'split sub dir/ with --rejoin' '
 		git subtree split --prefix="sub dir" --annotate="*" --rejoin &&
 		check_equal "$(last_commit_message)" "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
 	)
- '
+'
 
 test_expect_success 'split sub dir/ with --rejoin from scratch' '
 	subtree_test_create_repo "$test_count" &&
@@ -340,7 +338,7 @@ test_expect_success 'split sub dir/ with --rejoin from scratch' '
 		git subtree split --prefix="sub dir" --rejoin &&
 		check_equal "$(last_commit_message)" "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
 	)
- '
+'
 
 test_expect_success 'split sub dir/ with --rejoin and --message' '
 	subtree_test_create_repo "$test_count" &&
@@ -921,18 +919,18 @@ test_expect_success 'push split to subproj' '
 	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
 		cd $test_count/"sub proj" &&
-                git branch sub-branch-1 &&
-                cd .. &&
+		git branch sub-branch-1 &&
+		cd .. &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$test_count" "sub dir"/main-sub3 &&
-        (
+	(
 		cd "$test_count" &&
-	        git subtree push ./"sub proj" --prefix "sub dir" sub-branch-1 &&
-                cd ./"sub proj" &&
-                git checkout sub-branch-1 &&
-         	check_equal "$(last_commit_message)" "sub dir/main-sub3"
+		git subtree push ./"sub proj" --prefix "sub dir" sub-branch-1 &&
+		cd ./"sub proj" &&
+		git checkout sub-branch-1 &&
+		check_equal "$(last_commit_message)" "sub dir/main-sub3"
 	)
 '
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 05/30] subtree: t7900: comment subtree_test_create_repo
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (3 preceding siblings ...)
  2021-04-26 17:44   ` [PATCH v2 04/30] subtree: t7900: use consistent formatting Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 06/30] subtree: t7900: use 'test' for string equality Luke Shumaker
                     ` (25 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

It's unclear what the purpose of t7900-subtree.sh's
`subtree_test_create_repo` helper function is.  It wraps test-lib.sh's,
`test_create_repo` but follows that up by setting log.date=relative.  Why
does it set log.date=relative?

My first guess was that at one point the tests required that, but no
longer do, and that the function is now vestigial.  I even wrote a patch
to get rid of it and was moments away from `git send-email`ing it.

However, by chance when looking for something else in the history, I
discovered the true reason, from e7aac44ed2 (contrib/subtree: ignore
log.date configuration, 2015-07-21).  It's testing that setting
log.date=relative doesn't break `git subtree`, as at one point in the past
that did break `git subtree`.

So, add a comment about this, to avoid future such confusion.

And while at it, go ahead and (1) touch up the function to avoid a
pointless subshell and (2) update the one test that didn't use it.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - Also switch the few uses of vanilla test_create_repo over to
   subtree_test_create_repo.  In v1 this was erroneously included
   in a different commit.

 contrib/subtree/t/t7900-subtree.sh | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 5e1390c287..cac08af7f7 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -13,12 +13,14 @@ TEST_DIRECTORY=$(pwd)/../../../t
 export TEST_DIRECTORY
 . "$TEST_DIRECTORY"/test-lib.sh
 
+# Use our own wrapper around test-lib.sh's test_create_repo, in order
+# to set log.date=relative.  `git subtree` parses the output of `git
+# log`, and so it must be careful to not be affected by settings that
+# change the `git log` output.  We test this by setting
+# log.date=relative for every repo in the tests.
 subtree_test_create_repo () {
 	test_create_repo "$1" &&
-	(
-		cd "$1" &&
-		git config log.date relative
-	)
+	git -C "$1" config log.date relative
 }
 
 create () {
@@ -241,8 +243,8 @@ test_expect_success 'merge the added subproj again, should do nothing' '
 '
 
 test_expect_success 'merge new subproj history into subdir/ with a slash appended to the argument of --prefix' '
-	test_create_repo "$test_count" &&
-	test_create_repo "$test_count/subproj" &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/subproj" &&
 	test_create_commit "$test_count" main1 &&
 	test_create_commit "$test_count/subproj" sub1 &&
 	(
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 06/30] subtree: t7900: use 'test' for string equality
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (4 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 05/30] subtree: t7900: comment subtree_test_create_repo Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 07/30] subtree: t7900: delete some dead code Luke Shumaker
                     ` (24 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

t7900-subtree.sh defines its own `check_equal A B` function, instead of
just using `test A = B` like all of the other tests.  Don't be special,
get rid of `check_equal` in favor of `test`.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 60 ++++++++++++------------------
 1 file changed, 24 insertions(+), 36 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index cac08af7f7..3aa5545e5e 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -28,18 +28,6 @@ create () {
 	git add "$1"
 }
 
-check_equal () {
-	test_debug 'echo'
-	test_debug "echo \"check a:\" \"{$1}\""
-	test_debug "echo \"      b:\" \"{$2}\""
-	if test "$1" = "$2"
-	then
-		return 0
-	else
-		return 1
-	fi
-}
-
 undo () {
 	git reset --hard HEAD~
 }
@@ -122,7 +110,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Add '\''sub dir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
+		test "$(last_commit_message)" = "Add '\''sub dir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -135,7 +123,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix and --me
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject" FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Added subproject"
+		test "$(last_commit_message)" = "Added subproject"
 	)
 '
 
@@ -148,7 +136,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix as -P an
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add -P "sub dir" -m "Added subproject" FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Added subproject"
+		test "$(last_commit_message)" = "Added subproject"
 	)
 '
 
@@ -161,7 +149,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --squash and --pr
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject with squash" --squash FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Added subproject with squash"
+		test "$(last_commit_message)" = "Added subproject with squash"
 	)
 '
 
@@ -184,7 +172,7 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
+		test "$(last_commit_message)" = "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -203,7 +191,7 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix and -
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject" FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Merged changes from subproject"
+		test "$(last_commit_message)" = "Merged changes from subproject"
 	)
 '
 
@@ -222,7 +210,7 @@ test_expect_success 'merge new subproj history into sub dir/ with --squash and -
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject using squash" --squash FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Merged changes from subproject using squash"
+		test "$(last_commit_message)" = "Merged changes from subproject using squash"
 	)
 '
 
@@ -238,7 +226,7 @@ test_expect_success 'merge the added subproj again, should do nothing' '
 		# this shouldn not actually do anything, since FETCH_HEAD
 		# is already a parent
 		result=$(git merge -s ours -m "merge -s -ours" FETCH_HEAD) &&
-		check_equal "${result}" "Already up to date."
+		test "${result}" = "Already up to date."
 	)
 '
 
@@ -257,7 +245,7 @@ test_expect_success 'merge new subproj history into subdir/ with a slash appende
 		cd "$test_count" &&
 		git fetch ./subproj HEAD &&
 		git subtree merge --prefix=subdir/ FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
+		test "$(last_commit_message)" = "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -323,7 +311,7 @@ test_expect_success 'split sub dir/ with --rejoin' '
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --rejoin &&
-		check_equal "$(last_commit_message)" "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
+		test "$(last_commit_message)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
 	)
 '
 
@@ -338,7 +326,7 @@ test_expect_success 'split sub dir/ with --rejoin from scratch' '
 		git commit -m"sub dir file" &&
 		split_hash=$(git subtree split --prefix="sub dir" --rejoin) &&
 		git subtree split --prefix="sub dir" --rejoin &&
-		check_equal "$(last_commit_message)" "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
+		test "$(last_commit_message)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
 	)
 '
 
@@ -361,7 +349,7 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --message="Split & rejoin" --annotate="*" --rejoin &&
-		check_equal "$(last_commit_message)" "Split & rejoin"
+		test "$(last_commit_message)" = "Split & rejoin"
 	)
 '
 
@@ -385,7 +373,7 @@ test_expect_success 'split "sub dir"/ with --branch' '
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br &&
-		check_equal "$(git rev-parse subproj-br)" "$split_hash"
+		test "$(git rev-parse subproj-br)" = "$split_hash"
 	)
 '
 
@@ -409,13 +397,13 @@ test_expect_success 'check hash of split' '
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br &&
-		check_equal "$(git rev-parse subproj-br)" "$split_hash" &&
+		test "$(git rev-parse subproj-br)" = "$split_hash" &&
 		# Check hash of split
 		new_hash=$(git rev-parse subproj-br^2) &&
 		(
 			cd ./"sub proj" &&
 			subdir_hash=$(git rev-parse HEAD) &&
-			check_equal ''"$new_hash"'' "$subdir_hash"
+			test ''"$new_hash"'' = "$subdir_hash"
 		)
 	)
 '
@@ -441,7 +429,7 @@ test_expect_success 'split "sub dir"/ with --branch for an existing branch' '
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br &&
-		check_equal "$(git rev-parse subproj-br)" "$split_hash"
+		test "$(git rev-parse subproj-br)" = "$split_hash"
 	)
 '
 
@@ -739,7 +727,7 @@ test_expect_success 'make sure the --rejoin commits never make it into subproj'
 	(
 		cd "$test_count" &&
 		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
-		check_equal "$(git log --pretty=format:"%s" HEAD^2 | grep -i split)" ""
+		test "$(git log --pretty=format:"%s" HEAD^2 | grep -i split)" = ""
 	)
 '
 
@@ -790,7 +778,7 @@ test_expect_success 'make sure no "git subtree" tagged commits make it into subp
 		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		# They are meaningless to subproj since one side of the merge refers to the mainline
-		check_equal "$(git log --pretty=format:"%s%n%b" HEAD^2 | grep "git-subtree.*:")" ""
+		test "$(git log --pretty=format:"%s%n%b" HEAD^2 | grep "git-subtree.*:")" = ""
 	)
 '
 
@@ -824,7 +812,7 @@ test_expect_success 'make sure "git subtree split" find the correct parent' '
 		# not, something went wrong (the "newparent" of "HEAD~" commit should
 		# have been sub2, but it was not, because its cache was not set to
 		# itself)
-		check_equal "$(git log --pretty=format:%P -1 subproj-br)" "$(git rev-parse subproj-ref)"
+		test "$(git log --pretty=format:%P -1 subproj-br)" = "$(git rev-parse subproj-ref)"
 	)
 '
 
@@ -858,7 +846,7 @@ test_expect_success 'split a new subtree without --onto option' '
 		# if the parent of the first commit in the tree is not empty,
 		# then the new subtree has accidentally been attached to something
 		git subtree split --prefix="sub dir2" --branch subproj2-br &&
-		check_equal "$(git log --pretty=format:%P -1 subproj2-br)" ""
+		test "$(git log --pretty=format:%P -1 subproj2-br)" = ""
 	)
 '
 
@@ -897,10 +885,10 @@ test_expect_success 'verify one file change per commit' '
 				test_debug "echo Verifying commit $commit"
 				test_debug "echo a: $a"
 				test_debug "echo b: $b"
-				check_equal "$b" ""
+				test "$b" = ""
 				x=1
 			done
-			check_equal "$x" 1
+			test "$x" = 1
 		)
 	)
 '
@@ -932,7 +920,7 @@ test_expect_success 'push split to subproj' '
 		git subtree push ./"sub proj" --prefix "sub dir" sub-branch-1 &&
 		cd ./"sub proj" &&
 		git checkout sub-branch-1 &&
-		check_equal "$(last_commit_message)" "sub dir/main-sub3"
+		test "$(last_commit_message)" = "sub dir/main-sub3"
 	)
 '
 
@@ -992,7 +980,7 @@ test_expect_success 'subtree descendant check' '
 
 		git subtree split --prefix folder_subtree/ --branch subtree_tip $defaultBranch &&
 		git subtree split --prefix folder_subtree/ --branch subtree_branch branch &&
-		check_equal $(git rev-list --count subtree_tip..subtree_branch) 0
+		test $(git rev-list --count subtree_tip..subtree_branch) = 0
 	)
 '
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 07/30] subtree: t7900: delete some dead code
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (5 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 06/30] subtree: t7900: use 'test' for string equality Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 08/30] subtree: t7900: fix 'verify one file change per commit' Luke Shumaker
                     ` (23 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 3aa5545e5e..c8bd58cedb 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -10,7 +10,6 @@ and split subcommands of git subtree.
 '
 
 TEST_DIRECTORY=$(pwd)/../../../t
-export TEST_DIRECTORY
 . "$TEST_DIRECTORY"/test-lib.sh
 
 # Use our own wrapper around test-lib.sh's test_create_repo, in order
@@ -23,15 +22,6 @@ subtree_test_create_repo () {
 	git -C "$1" config log.date relative
 }
 
-create () {
-	echo "$1" >"$1" &&
-	git add "$1"
-}
-
-undo () {
-	git reset --hard HEAD~
-}
-
 # Make sure no patch changes more than one file.
 # The original set of commits changed only one file each.
 # A multi-file change would imply that we pruned commits
@@ -403,7 +393,7 @@ test_expect_success 'check hash of split' '
 		(
 			cd ./"sub proj" &&
 			subdir_hash=$(git rev-parse HEAD) &&
-			test ''"$new_hash"'' = "$subdir_hash"
+			test "$new_hash" = "$subdir_hash"
 		)
 	)
 '
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 08/30] subtree: t7900: fix 'verify one file change per commit'
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (6 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 07/30] subtree: t7900: delete some dead code Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 09/30] subtree: t7900: rename last_commit_message to last_commit_subject Luke Shumaker
                     ` (22 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

As far as I can tell, this test isn't actually testing anything, because
someone forgot to tack on `--name-only` to `git log`.  This seems to
have been the case since the test was first written, back in fa16ab36ad
("test.sh: make sure no commit changes more than one file at a time.",
2009-04-26), unless `git log` used to do that by default and didn't need
the flag back then?

Convincing myself that it's not actually testing anything was tricky,
the code is a little hard to reason about.  It can be made a lot simpler
if instead of trying to parse all of the info from a single `git log`,
we're OK calling `git log` from inside of a loop.  And it's my opinion
that tests are not the place for clever optimized code.

So, fix and simplify the test, so that it's actually testing something
and is simpler to reason about.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - Fix whitespace.

 contrib/subtree/t/t7900-subtree.sh | 44 ++++--------------------------
 1 file changed, 6 insertions(+), 38 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index c8bd58cedb..1c717fcb96 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -22,32 +22,6 @@ subtree_test_create_repo () {
 	git -C "$1" config log.date relative
 }
 
-# Make sure no patch changes more than one file.
-# The original set of commits changed only one file each.
-# A multi-file change would imply that we pruned commits
-# too aggressively.
-join_commits () {
-	commit=
-	all=
-	while read x y; do
-		if test -z "$x"
-		then
-			continue
-		elif test "$x" = "commit:"
-		then
-			if test -n "$commit"
-			then
-				echo "$commit $all"
-				all=
-			fi
-			commit="$y"
-		else
-			all="$all $y"
-		fi
-	done
-	echo "$commit $all"
-}
-
 test_create_commit () (
 	repo=$1 &&
 	commit=$2 &&
@@ -868,18 +842,12 @@ test_expect_success 'verify one file change per commit' '
 		cd "$test_count" &&
 		git subtree split --prefix="sub dir2" --branch subproj2-br &&
 
-		x= &&
-		git log --pretty=format:"commit: %H" | join_commits |
-		(
-			while read commit a b; do
-				test_debug "echo Verifying commit $commit"
-				test_debug "echo a: $a"
-				test_debug "echo b: $b"
-				test "$b" = ""
-				x=1
-			done
-			test "$x" = 1
-		)
+		git log --format="%H" >commit-list &&
+		while read commit
+		do
+			git log -n1 --format="" --name-only "$commit" >file-list &&
+			test_line_count -le 1 file-list || return 1
+		done <commit-list
 	)
 '
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 09/30] subtree: t7900: rename last_commit_message to last_commit_subject
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (7 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 08/30] subtree: t7900: fix 'verify one file change per commit' Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 10/30] subtree: t7900: add a test for the -h flag Luke Shumaker
                     ` (21 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

t7900-subtree.sh defines a helper function named last_commit_message.
However, it only returns the subject line of the commit message, not the
entire commit message.  So rename it, to make the name less confusing.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 1c717fcb96..5c2510f1f5 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -33,7 +33,7 @@ test_create_commit () (
 	git commit -m "$commit" || error "Could not commit"
 )
 
-last_commit_message () {
+last_commit_subject () {
 	git log --pretty=format:%s -1
 }
 
@@ -74,7 +74,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
-		test "$(last_commit_message)" = "Add '\''sub dir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
+		test "$(last_commit_subject)" = "Add '\''sub dir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -87,7 +87,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix and --me
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject" FETCH_HEAD &&
-		test "$(last_commit_message)" = "Added subproject"
+		test "$(last_commit_subject)" = "Added subproject"
 	)
 '
 
@@ -100,7 +100,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix as -P an
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add -P "sub dir" -m "Added subproject" FETCH_HEAD &&
-		test "$(last_commit_message)" = "Added subproject"
+		test "$(last_commit_subject)" = "Added subproject"
 	)
 '
 
@@ -113,7 +113,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --squash and --pr
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject with squash" --squash FETCH_HEAD &&
-		test "$(last_commit_message)" = "Added subproject with squash"
+		test "$(last_commit_subject)" = "Added subproject with squash"
 	)
 '
 
@@ -136,7 +136,7 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
-		test "$(last_commit_message)" = "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
+		test "$(last_commit_subject)" = "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -155,7 +155,7 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix and -
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject" FETCH_HEAD &&
-		test "$(last_commit_message)" = "Merged changes from subproject"
+		test "$(last_commit_subject)" = "Merged changes from subproject"
 	)
 '
 
@@ -174,7 +174,7 @@ test_expect_success 'merge new subproj history into sub dir/ with --squash and -
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject using squash" --squash FETCH_HEAD &&
-		test "$(last_commit_message)" = "Merged changes from subproject using squash"
+		test "$(last_commit_subject)" = "Merged changes from subproject using squash"
 	)
 '
 
@@ -209,7 +209,7 @@ test_expect_success 'merge new subproj history into subdir/ with a slash appende
 		cd "$test_count" &&
 		git fetch ./subproj HEAD &&
 		git subtree merge --prefix=subdir/ FETCH_HEAD &&
-		test "$(last_commit_message)" = "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
+		test "$(last_commit_subject)" = "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -275,7 +275,7 @@ test_expect_success 'split sub dir/ with --rejoin' '
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --rejoin &&
-		test "$(last_commit_message)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
+		test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
 	)
 '
 
@@ -290,7 +290,7 @@ test_expect_success 'split sub dir/ with --rejoin from scratch' '
 		git commit -m"sub dir file" &&
 		split_hash=$(git subtree split --prefix="sub dir" --rejoin) &&
 		git subtree split --prefix="sub dir" --rejoin &&
-		test "$(last_commit_message)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
+		test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
 	)
 '
 
@@ -313,7 +313,7 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --message="Split & rejoin" --annotate="*" --rejoin &&
-		test "$(last_commit_message)" = "Split & rejoin"
+		test "$(last_commit_subject)" = "Split & rejoin"
 	)
 '
 
@@ -878,7 +878,7 @@ test_expect_success 'push split to subproj' '
 		git subtree push ./"sub proj" --prefix "sub dir" sub-branch-1 &&
 		cd ./"sub proj" &&
 		git checkout sub-branch-1 &&
-		test "$(last_commit_message)" = "sub dir/main-sub3"
+		test "$(last_commit_subject)" = "sub dir/main-sub3"
 	)
 '
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 10/30] subtree: t7900: add a test for the -h flag
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (8 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 09/30] subtree: t7900: rename last_commit_message to last_commit_subject Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 11/30] subtree: t7900: add porcelain tests for 'pull' and 'push' Luke Shumaker
                     ` (20 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

It's a dumb test, but it's surprisingly easy to break.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 5c2510f1f5..9afba2f282 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -37,6 +37,13 @@ last_commit_subject () {
 	git log --pretty=format:%s -1
 }
 
+test_expect_success 'shows short help text for -h' '
+	test_expect_code 129 git subtree -h >out 2>err &&
+	test_must_be_empty err &&
+	grep -e "^ *or: git subtree pull" out &&
+	grep -e --annotate out
+'
+
 #
 # Tests for 'git subtree add'
 #
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 11/30] subtree: t7900: add porcelain tests for 'pull' and 'push'
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (9 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 10/30] subtree: t7900: add a test for the -h flag Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 12/30] subtree: don't have loose code outside of a function Luke Shumaker
                     ` (19 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

The 'pull' and 'push' subcommands deserve their own sections in the tests.
Add some basic tests for them.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - Don't switch unrelated uses of vanilla test_create_repo over to
   subtree_test_create_repo; this has been moved to happen in an
   earlier commit.
 - Fix whitespace.

 contrib/subtree/t/t7900-subtree.sh | 127 +++++++++++++++++++++++++++++
 1 file changed, 127 insertions(+)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 9afba2f282..ce6861c22d 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -427,6 +427,133 @@ test_expect_success 'split "sub dir"/ with --branch for an incompatible branch'
 	)
 '
 
+#
+# Tests for 'git subtree pull'
+#
+
+test_expect_success 'pull requires option --prefix' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	(
+		cd "$test_count" &&
+		test_must_fail git subtree pull ./"sub proj" HEAD >out 2>err &&
+
+		echo "You must provide the --prefix option." >expected &&
+		test_must_be_empty out &&
+		test_cmp expected err
+	)
+'
+
+test_expect_success 'pull requires path given by option --prefix must exist' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" HEAD >out 2>err &&
+
+		echo "'\''sub dir'\'' does not exist; use '\''git subtree add'\''" >expected &&
+		test_must_be_empty out &&
+		test_cmp expected err
+	)
+'
+
+test_expect_success 'pull basic operation' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	(
+		cd "$test_count" &&
+		exp=$(git -C "sub proj" rev-parse --verify HEAD:) &&
+		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
+		act=$(git rev-parse --verify HEAD:"sub dir") &&
+		test "$act" = "$exp"
+	)
+'
+
+#
+# Tests for 'git subtree push'
+#
+
+test_expect_success 'push requires option --prefix' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD &&
+		echo "You must provide the --prefix option." >expected &&
+		test_must_fail git subtree push "./sub proj" from-mainline >actual 2>&1 &&
+		test_debug "printf '"expected: "'" &&
+		test_debug "cat expected" &&
+		test_debug "printf '"actual: "'" &&
+		test_debug "cat actual" &&
+		test_cmp expected actual
+	)
+'
+
+test_expect_success 'push requires path given by option --prefix must exist' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD &&
+		echo "'\''non-existent-directory'\'' does not exist; use '\''git subtree add'\''" >expected &&
+		test_must_fail git subtree push --prefix=non-existent-directory "./sub proj" from-mainline >actual 2>&1 &&
+		test_debug "printf '"expected: "'" &&
+		test_debug "cat expected" &&
+		test_debug "printf '"actual: "'" &&
+		test_debug "cat actual" &&
+		test_cmp expected actual
+	)
+'
+
+test_expect_success 'push basic operation' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		before=$(git rev-parse --verify HEAD) &&
+		split_hash=$(git subtree split --prefix="sub dir") &&
+		git subtree push --prefix="sub dir" ./"sub proj" from-mainline &&
+		test "$before" = "$(git rev-parse --verify HEAD)" &&
+		test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
 #
 # Validity checking
 #
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 12/30] subtree: don't have loose code outside of a function
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (10 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 11/30] subtree: t7900: add porcelain tests for 'pull' and 'push' Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 13/30] subtree: more consistent error propagation Luke Shumaker
                     ` (18 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Shove all of the loose code inside of a main() function.

This comes down to personal preference more than anything else.  A
preference that I've developed over years of maintaining large Bash
scripts, but still a mere personal preference.

In this specific case, it's also moving the `set -- -h`, the `git
rev-parse --parseopt`, and the `. git-sh-setup` to be closer to all
the rest of the argument parsing, which is a readability win on its
own, IMO.

"Ignore space change" is probably helpful when viewing this diff.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - Include rationale in the the commit message.

 contrib/subtree/git-subtree.sh | 245 +++++++++++++++++----------------
 1 file changed, 125 insertions(+), 120 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 868e18b9a1..d1ed7f9a6c 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -4,10 +4,7 @@
 #
 # Copyright (C) 2009 Avery Pennarun <apenwarr@gmail.com>
 #
-if test $# -eq 0
-then
-	set -- -h
-fi
+
 OPTS_SPEC="\
 git subtree add   --prefix=<prefix> <commit>
 git subtree add   --prefix=<prefix> <repository> <ref>
@@ -30,12 +27,8 @@ rejoin        merge the new branch back into HEAD
  options for 'add', 'merge', and 'pull'
 squash        merge subtree changes as a single commit
 "
-eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
 
 PATH=$PATH:$(git --exec-path)
-. git-sh-setup
-
-require_work_tree
 
 quiet=
 branch=
@@ -84,126 +77,138 @@ ensure_single_rev () {
 	fi
 }
 
-while test $# -gt 0
-do
-	opt="$1"
-	shift
+main () {
+	if test $# -eq 0
+	then
+		set -- -h
+	fi
+	eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
+	. git-sh-setup
+	require_work_tree
 
-	case "$opt" in
-	-q)
-		quiet=1
-		;;
-	-d)
-		debug=1
-		;;
-	--annotate)
-		annotate="$1"
-		shift
-		;;
-	--no-annotate)
-		annotate=
-		;;
-	-b)
-		branch="$1"
-		shift
-		;;
-	-P)
-		prefix="${1%/}"
-		shift
-		;;
-	-m)
-		message="$1"
-		shift
-		;;
-	--no-prefix)
-		prefix=
-		;;
-	--onto)
-		onto="$1"
+	while test $# -gt 0
+	do
+		opt="$1"
 		shift
+
+		case "$opt" in
+		-q)
+			quiet=1
+			;;
+		-d)
+			debug=1
+			;;
+		--annotate)
+			annotate="$1"
+			shift
+			;;
+		--no-annotate)
+			annotate=
+			;;
+		-b)
+			branch="$1"
+			shift
+			;;
+		-P)
+			prefix="${1%/}"
+			shift
+			;;
+		-m)
+			message="$1"
+			shift
+			;;
+		--no-prefix)
+			prefix=
+			;;
+		--onto)
+			onto="$1"
+			shift
+			;;
+		--no-onto)
+			onto=
+			;;
+		--rejoin)
+			rejoin=1
+			;;
+		--no-rejoin)
+			rejoin=
+			;;
+		--ignore-joins)
+			ignore_joins=1
+			;;
+		--no-ignore-joins)
+			ignore_joins=
+			;;
+		--squash)
+			squash=1
+			;;
+		--no-squash)
+			squash=
+			;;
+		--)
+			break
+			;;
+		*)
+			die "Unexpected option: $opt"
+			;;
+		esac
+	done
+
+	command="$1"
+	shift
+
+	case "$command" in
+	add|merge|pull)
+		default=
 		;;
-	--no-onto)
-		onto=
-		;;
-	--rejoin)
-		rejoin=1
-		;;
-	--no-rejoin)
-		rejoin=
-		;;
-	--ignore-joins)
-		ignore_joins=1
-		;;
-	--no-ignore-joins)
-		ignore_joins=
-		;;
-	--squash)
-		squash=1
+	split|push)
+		default="--default HEAD"
 		;;
-	--no-squash)
-		squash=
+	*)
+		die "Unknown command '$command'"
 		;;
-	--)
-		break
+	esac
+
+	if test -z "$prefix"
+	then
+		die "You must provide the --prefix option."
+	fi
+
+	case "$command" in
+	add)
+		test -e "$prefix" &&
+			die "prefix '$prefix' already exists."
 		;;
 	*)
-		die "Unexpected option: $opt"
+		test -e "$prefix" ||
+			die "'$prefix' does not exist; use 'git subtree add'"
 		;;
 	esac
-done
-
-command="$1"
-shift
-
-case "$command" in
-add|merge|pull)
-	default=
-	;;
-split|push)
-	default="--default HEAD"
-	;;
-*)
-	die "Unknown command '$command'"
-	;;
-esac
-
-if test -z "$prefix"
-then
-	die "You must provide the --prefix option."
-fi
-
-case "$command" in
-add)
-	test -e "$prefix" &&
-		die "prefix '$prefix' already exists."
-	;;
-*)
-	test -e "$prefix" ||
-		die "'$prefix' does not exist; use 'git subtree add'"
-	;;
-esac
-
-dir="$(dirname "$prefix/.")"
-
-if test "$command" != "pull" &&
-		test "$command" != "add" &&
-		test "$command" != "push"
-then
-	revs=$(git rev-parse $default --revs-only "$@") || exit $?
-	dirs=$(git rev-parse --no-revs --no-flags "$@") || exit $?
-	ensure_single_rev $revs
-	if test -n "$dirs"
-	then
-		die "Error: Use --prefix instead of bare filenames."
-	fi
-fi
-
-debug "command: {$command}"
-debug "quiet: {$quiet}"
-debug "revs: {$revs}"
-debug "dir: {$dir}"
-debug "opts: {$*}"
-debug
+
+	dir="$(dirname "$prefix/.")"
+
+	if test "$command" != "pull" &&
+			test "$command" != "add" &&
+			test "$command" != "push"
+	then
+		revs=$(git rev-parse $default --revs-only "$@") || exit $?
+		dirs=$(git rev-parse --no-revs --no-flags "$@") || exit $?
+		ensure_single_rev $revs
+		if test -n "$dirs"
+		then
+			die "Error: Use --prefix instead of bare filenames."
+		fi
+	fi
+
+	debug "command: {$command}"
+	debug "quiet: {$quiet}"
+	debug "revs: {$revs}"
+	debug "dir: {$dir}"
+	debug "opts: {$*}"
+	debug
+
+	"cmd_$command" "$@"
+}
 
 cache_setup () {
 	cachedir="$GIT_DIR/subtree-cache/$$"
@@ -898,4 +903,4 @@ cmd_push () {
 	fi
 }
 
-"cmd_$command" "$@"
+main "$@"
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 13/30] subtree: more consistent error propagation
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (11 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 12/30] subtree: don't have loose code outside of a function Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 14/30] subtree: drop support for git < 1.7 Luke Shumaker
                     ` (17 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Ensure that every $(subshell) that calls a function (as opposed to an
external executable) is followed by `|| exit $?`.  Similarly, ensure that
every `cmd | while read; do ... done` loop is followed by `|| exit $?`.

Both of those constructs mean that it can miss `die` calls, and keep
running when it shouldn't.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index d1ed7f9a6c..9ca498f81c 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -243,7 +243,7 @@ cache_miss () {
 }
 
 check_parents () {
-	missed=$(cache_miss "$1")
+	missed=$(cache_miss "$1") || exit $?
 	local indent=$(($2 + 1))
 	for miss in $missed
 	do
@@ -345,7 +345,7 @@ find_latest_squash () {
 			sub=
 			;;
 		esac
-	done
+	done || exit $?
 }
 
 find_existing_splits () {
@@ -394,7 +394,7 @@ find_existing_splits () {
 			sub=
 			;;
 		esac
-	done
+	done || exit $?
 }
 
 copy_commit () {
@@ -508,7 +508,7 @@ subtree_for_commit () {
 		test "$type" = "commit" && continue  # ignore submodules
 		echo $tree
 		break
-	done
+	done || exit $?
 }
 
 tree_changed () {
@@ -518,7 +518,7 @@ tree_changed () {
 	then
 		return 0   # weird parents, consider it changed
 	else
-		ptree=$(toptree_for_commit $1)
+		ptree=$(toptree_for_commit $1) || exit $?
 		if test "$ptree" != "$tree"
 		then
 			return 0   # changed
@@ -652,7 +652,7 @@ process_split_commit () {
 	progress "$revcount/$revmax ($createcount) [$extracount]"
 
 	debug "Processing commit: $rev"
-	exists=$(cache_get "$rev")
+	exists=$(cache_get "$rev") || exit $?
 	if test -n "$exists"
 	then
 		debug "  prior: $exists"
@@ -661,10 +661,10 @@ process_split_commit () {
 	createcount=$(($createcount + 1))
 	debug "  parents: $parents"
 	check_parents "$parents" "$indent"
-	newparents=$(cache_get $parents)
+	newparents=$(cache_get $parents) || exit $?
 	debug "  newparents: $newparents"
 
-	tree=$(subtree_for_commit "$rev" "$dir")
+	tree=$(subtree_for_commit "$rev" "$dir") || exit $?
 	debug "  tree is: $tree"
 
 	# ugly.  is there no better way to tell if this is a subtree
@@ -750,7 +750,7 @@ cmd_add_commit () {
 		commit=$(add_squashed_msg "$rev" "$dir" |
 			git commit-tree "$tree" $headp -p "$rev") || exit $?
 	else
-		revp=$(peel_committish "$rev") &&
+		revp=$(peel_committish "$rev") || exit $?
 		commit=$(add_msg "$dir" $headrev "$rev" |
 			git commit-tree "$tree" $headp -p "$revp") || exit $?
 	fi
@@ -773,10 +773,10 @@ cmd_split () {
 			# any parent we find there can be used verbatim
 			debug "  cache: $rev"
 			cache_set "$rev" "$rev"
-		done
+		done || exit $?
 	fi
 
-	unrevs="$(find_existing_splits "$dir" "$revs")"
+	unrevs="$(find_existing_splits "$dir" "$revs")" || exit $?
 
 	# We can't restrict rev-list to only $dir here, because some of our
 	# parents have the $dir contents the root, and those won't match.
@@ -792,7 +792,7 @@ cmd_split () {
 		process_split_commit "$rev" "$parents" 0
 	done || exit $?
 
-	latest_new=$(cache_get latest_new)
+	latest_new=$(cache_get latest_new) || exit $?
 	if test -z "$latest_new"
 	then
 		die "No new revisions were found"
@@ -801,7 +801,7 @@ cmd_split () {
 	if test -n "$rejoin"
 	then
 		debug "Merging split branch into HEAD..."
-		latest_old=$(cache_get latest_old)
+		latest_old=$(cache_get latest_old) || exit $?
 		git merge -s ours \
 			--allow-unrelated-histories \
 			-m "$(rejoin_msg "$dir" "$latest_old" "$latest_new")" \
@@ -834,7 +834,7 @@ cmd_merge () {
 
 	if test -n "$squash"
 	then
-		first_split="$(find_latest_squash "$dir")"
+		first_split="$(find_latest_squash "$dir")" || exit $?
 		if test -z "$first_split"
 		then
 			die "Can't squash-merge: '$dir' was never added."
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 14/30] subtree: drop support for git < 1.7
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (12 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 13/30] subtree: more consistent error propagation Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 15/30] subtree: use `git merge-base --is-ancestor` Luke Shumaker
                     ` (16 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Suport for Git versions older than 1.7.0 (older than February 2010) was
nice to have when git-subtree lived out-of-tree.  But now that it lives
in git.git, it's not necessary to keep around.  While it's technically
in contrib, with the standard 'git' packages for common systems
(including Arch Linux and macOS) including git-subtree, it seems
vanishingly likely to me that people are separately installing
git-subtree from git.git alongside an older 'git' install (although it
also seems vanishingly likely that people are still using >11 year old
git installs).

Not that there's much reason to remove it either, it's not much code,
and none of my changes depend on a newer git (to my knowledge, anyway;
I'm not actually testing against older git).  I just figure it's an easy
piece of fat to trim, in the journey to making the whole thing easier to
hack on.

"Ignore space change" is probably helpful when viewing this diff.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - Include rationale in the the commit message.

 contrib/subtree/git-subtree.sh | 19 ++++---------------
 1 file changed, 4 insertions(+), 15 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 9ca498f81c..4503564f7e 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -852,23 +852,12 @@ cmd_merge () {
 		rev="$new"
 	fi
 
-	version=$(git version)
-	if test "$version" \< "git version 1.7"
+	if test -n "$message"
 	then
-		if test -n "$message"
-		then
-			git merge -s subtree --message="$message" "$rev"
-		else
-			git merge -s subtree "$rev"
-		fi
+		git merge -Xsubtree="$prefix" \
+		    --message="$message" "$rev"
 	else
-		if test -n "$message"
-		then
-			git merge -Xsubtree="$prefix" \
-				--message="$message" "$rev"
-		else
-			git merge -Xsubtree="$prefix" $rev
-		fi
+		git merge -Xsubtree="$prefix" $rev
 	fi
 }
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 15/30] subtree: use `git merge-base --is-ancestor`
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (13 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 14/30] subtree: drop support for git < 1.7 Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 16/30] subtree: use git-sh-setup's `say` Luke Shumaker
                     ` (15 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Instead of writing a slow `rev_is_descendant_of_branch $a $b` function
in shell, just use the fast `git merge-base --is-ancestor $b $a`.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 16 +---------------
 1 file changed, 1 insertion(+), 15 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 4503564f7e..70e16b807b 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -280,20 +280,6 @@ rev_exists () {
 	fi
 }
 
-rev_is_descendant_of_branch () {
-	newrev="$1"
-	branch="$2"
-	branch_hash=$(git rev-parse "$branch")
-	match=$(git rev-list -1 "$branch_hash" "^$newrev")
-
-	if test -z "$match"
-	then
-		return 0
-	else
-		return 1
-	fi
-}
-
 # if a commit doesn't have a parent, this might not work.  But we only want
 # to remove the parent from the rev-list, and since it doesn't exist, it won't
 # be there anyway, so do nothing in that case.
@@ -811,7 +797,7 @@ cmd_split () {
 	then
 		if rev_exists "refs/heads/$branch"
 		then
-			if ! rev_is_descendant_of_branch "$latest_new" "$branch"
+			if ! git merge-base --is-ancestor "$branch" "$latest_new"
 			then
 				die "Branch '$branch' is not an ancestor of commit '$latest_new'."
 			fi
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 16/30] subtree: use git-sh-setup's `say`
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (14 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 15/30] subtree: use `git merge-base --is-ancestor` Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 17/30] subtree: use more explicit variable names for cmdline args Luke Shumaker
                     ` (14 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

subtree currently defines its own `say` implementation, rather than
using git-sh-setups's implementation.  Change that, don't re-invent the
wheel.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 22 +++++++---------------
 1 file changed, 7 insertions(+), 15 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 70e16b807b..bb4934dbc0 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -30,7 +30,6 @@ squash        merge subtree changes as a single commit
 
 PATH=$PATH:$(git --exec-path)
 
-quiet=
 branch=
 debug=
 command=
@@ -49,15 +48,8 @@ debug () {
 	fi
 }
 
-say () {
-	if test -z "$quiet"
-	then
-		printf "%s\n" "$*" >&2
-	fi
-}
-
 progress () {
-	if test -z "$quiet"
+	if test -z "$GIT_QUIET"
 	then
 		printf "%s\r" "$*" >&2
 	fi
@@ -93,7 +85,7 @@ main () {
 
 		case "$opt" in
 		-q)
-			quiet=1
+			GIT_QUIET=1
 			;;
 		-d)
 			debug=1
@@ -201,7 +193,7 @@ main () {
 	fi
 
 	debug "command: {$command}"
-	debug "quiet: {$quiet}"
+	debug "quiet: {$GIT_QUIET}"
 	debug "revs: {$revs}"
 	debug "dir: {$dir}"
 	debug "opts: {$*}"
@@ -698,7 +690,7 @@ cmd_add () {
 
 		cmd_add_repository "$@"
 	else
-		say "error: parameters were '$@'"
+		say >&2 "error: parameters were '$@'"
 		die "Provide either a commit or a repository and commit."
 	fi
 }
@@ -742,7 +734,7 @@ cmd_add_commit () {
 	fi
 	git reset "$commit" || exit $?
 
-	say "Added dir '$dir'"
+	say >&2 "Added dir '$dir'"
 }
 
 cmd_split () {
@@ -807,7 +799,7 @@ cmd_split () {
 		fi
 		git update-ref -m 'subtree split' \
 			"refs/heads/$branch" "$latest_new" || exit $?
-		say "$action branch '$branch'"
+		say >&2 "$action branch '$branch'"
 	fi
 	echo "$latest_new"
 	exit 0
@@ -830,7 +822,7 @@ cmd_merge () {
 		sub=$2
 		if test "$sub" = "$rev"
 		then
-			say "Subtree is already at commit $rev."
+			say >&2 "Subtree is already at commit $rev."
 			exit 0
 		fi
 		new=$(new_squash_commit "$old" "$sub" "$rev") || exit $?
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 17/30] subtree: use more explicit variable names for cmdline args
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (15 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 16/30] subtree: use git-sh-setup's `say` Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 18/30] subtree: use "$*" instead of "$@" as appropriate Luke Shumaker
                     ` (13 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Make it painfully obvious when reading the code which variables are
direct parsings of command line arguments.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 132 ++++++++++++++++-----------------
 1 file changed, 66 insertions(+), 66 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index bb4934dbc0..d7de4b0653 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -30,19 +30,19 @@ squash        merge subtree changes as a single commit
 
 PATH=$PATH:$(git --exec-path)
 
-branch=
-debug=
-command=
-onto=
-rejoin=
-ignore_joins=
-annotate=
-squash=
-message=
-prefix=
+arg_debug=
+arg_command=
+arg_prefix=
+arg_split_branch=
+arg_split_onto=
+arg_split_rejoin=
+arg_split_ignore_joins=
+arg_split_annotate=
+arg_addmerge_squash=
+arg_addmerge_message=
 
 debug () {
-	if test -n "$debug"
+	if test -n "$arg_debug"
 	then
 		printf "%s\n" "$*" >&2
 	fi
@@ -88,54 +88,54 @@ main () {
 			GIT_QUIET=1
 			;;
 		-d)
-			debug=1
+			arg_debug=1
 			;;
 		--annotate)
-			annotate="$1"
+			arg_split_annotate="$1"
 			shift
 			;;
 		--no-annotate)
-			annotate=
+			arg_split_annotate=
 			;;
 		-b)
-			branch="$1"
+			arg_split_branch="$1"
 			shift
 			;;
 		-P)
-			prefix="${1%/}"
+			arg_prefix="${1%/}"
 			shift
 			;;
 		-m)
-			message="$1"
+			arg_addmerge_message="$1"
 			shift
 			;;
 		--no-prefix)
-			prefix=
+			arg_prefix=
 			;;
 		--onto)
-			onto="$1"
+			arg_split_onto="$1"
 			shift
 			;;
 		--no-onto)
-			onto=
+			arg_split_onto=
 			;;
 		--rejoin)
-			rejoin=1
+			arg_split_rejoin=1
 			;;
 		--no-rejoin)
-			rejoin=
+			arg_split_rejoin=
 			;;
 		--ignore-joins)
-			ignore_joins=1
+			arg_split_ignore_joins=1
 			;;
 		--no-ignore-joins)
-			ignore_joins=
+			arg_split_ignore_joins=
 			;;
 		--squash)
-			squash=1
+			arg_addmerge_squash=1
 			;;
 		--no-squash)
-			squash=
+			arg_addmerge_squash=
 			;;
 		--)
 			break
@@ -146,10 +146,10 @@ main () {
 		esac
 	done
 
-	command="$1"
+	arg_command="$1"
 	shift
 
-	case "$command" in
+	case "$arg_command" in
 	add|merge|pull)
 		default=
 		;;
@@ -157,31 +157,31 @@ main () {
 		default="--default HEAD"
 		;;
 	*)
-		die "Unknown command '$command'"
+		die "Unknown command '$arg_command'"
 		;;
 	esac
 
-	if test -z "$prefix"
+	if test -z "$arg_prefix"
 	then
 		die "You must provide the --prefix option."
 	fi
 
-	case "$command" in
+	case "$arg_command" in
 	add)
-		test -e "$prefix" &&
-			die "prefix '$prefix' already exists."
+		test -e "$arg_prefix" &&
+			die "prefix '$arg_prefix' already exists."
 		;;
 	*)
-		test -e "$prefix" ||
-			die "'$prefix' does not exist; use 'git subtree add'"
+		test -e "$arg_prefix" ||
+			die "'$arg_prefix' does not exist; use 'git subtree add'"
 		;;
 	esac
 
-	dir="$(dirname "$prefix/.")"
+	dir="$(dirname "$arg_prefix/.")"
 
-	if test "$command" != "pull" &&
-			test "$command" != "add" &&
-			test "$command" != "push"
+	if test "$arg_command" != "pull" &&
+			test "$arg_command" != "add" &&
+			test "$arg_command" != "push"
 	then
 		revs=$(git rev-parse $default --revs-only "$@") || exit $?
 		dirs=$(git rev-parse --no-revs --no-flags "$@") || exit $?
@@ -192,14 +192,14 @@ main () {
 		fi
 	fi
 
-	debug "command: {$command}"
+	debug "command: {$arg_command}"
 	debug "quiet: {$GIT_QUIET}"
 	debug "revs: {$revs}"
 	debug "dir: {$dir}"
 	debug "opts: {$*}"
 	debug
 
-	"cmd_$command" "$@"
+	"cmd_$arg_command" "$@"
 }
 
 cache_setup () {
@@ -333,7 +333,7 @@ find_existing_splits () {
 	main=
 	sub=
 	local grep_format="^git-subtree-dir: $dir/*\$"
-	if test -n "$ignore_joins"
+	if test -n "$arg_split_ignore_joins"
 	then
 		grep_format="^Add '$dir/' from commit '"
 	fi
@@ -394,7 +394,7 @@ copy_commit () {
 			GIT_COMMITTER_EMAIL \
 			GIT_COMMITTER_DATE
 		(
-			printf "%s" "$annotate"
+			printf "%s" "$arg_split_annotate"
 			cat
 		) |
 		git commit-tree "$2" $3  # reads the rest of stdin
@@ -405,9 +405,9 @@ add_msg () {
 	dir="$1"
 	latest_old="$2"
 	latest_new="$3"
-	if test -n "$message"
+	if test -n "$arg_addmerge_message"
 	then
-		commit_message="$message"
+		commit_message="$arg_addmerge_message"
 	else
 		commit_message="Add '$dir/' from commit '$latest_new'"
 	fi
@@ -421,9 +421,9 @@ add_msg () {
 }
 
 add_squashed_msg () {
-	if test -n "$message"
+	if test -n "$arg_addmerge_message"
 	then
-		echo "$message"
+		echo "$arg_addmerge_message"
 	else
 		echo "Merge commit '$1' as '$2'"
 	fi
@@ -433,9 +433,9 @@ rejoin_msg () {
 	dir="$1"
 	latest_old="$2"
 	latest_new="$3"
-	if test -n "$message"
+	if test -n "$arg_addmerge_message"
 	then
-		commit_message="$message"
+		commit_message="$arg_addmerge_message"
 	else
 		commit_message="Split '$dir/' into commit '$latest_new'"
 	fi
@@ -722,7 +722,7 @@ cmd_add_commit () {
 		headp=
 	fi
 
-	if test -n "$squash"
+	if test -n "$arg_addmerge_squash"
 	then
 		rev=$(new_squash_commit "" "" "$rev") || exit $?
 		commit=$(add_squashed_msg "$rev" "$dir" |
@@ -741,10 +741,10 @@ cmd_split () {
 	debug "Splitting $dir..."
 	cache_setup || exit $?
 
-	if test -n "$onto"
+	if test -n "$arg_split_onto"
 	then
-		debug "Reading history for --onto=$onto..."
-		git rev-list $onto |
+		debug "Reading history for --onto=$arg_split_onto..."
+		git rev-list $arg_split_onto |
 		while read rev
 		do
 			# the 'onto' history is already just the subdir, so
@@ -776,7 +776,7 @@ cmd_split () {
 		die "No new revisions were found"
 	fi
 
-	if test -n "$rejoin"
+	if test -n "$arg_split_rejoin"
 	then
 		debug "Merging split branch into HEAD..."
 		latest_old=$(cache_get latest_old) || exit $?
@@ -785,21 +785,21 @@ cmd_split () {
 			-m "$(rejoin_msg "$dir" "$latest_old" "$latest_new")" \
 			"$latest_new" >&2 || exit $?
 	fi
-	if test -n "$branch"
+	if test -n "$arg_split_branch"
 	then
-		if rev_exists "refs/heads/$branch"
+		if rev_exists "refs/heads/$arg_split_branch"
 		then
-			if ! git merge-base --is-ancestor "$branch" "$latest_new"
+			if ! git merge-base --is-ancestor "$arg_split_branch" "$latest_new"
 			then
-				die "Branch '$branch' is not an ancestor of commit '$latest_new'."
+				die "Branch '$arg_split_branch' is not an ancestor of commit '$latest_new'."
 			fi
 			action='Updated'
 		else
 			action='Created'
 		fi
 		git update-ref -m 'subtree split' \
-			"refs/heads/$branch" "$latest_new" || exit $?
-		say >&2 "$action branch '$branch'"
+			"refs/heads/$arg_split_branch" "$latest_new" || exit $?
+		say >&2 "$action branch '$arg_split_branch'"
 	fi
 	echo "$latest_new"
 	exit 0
@@ -810,7 +810,7 @@ cmd_merge () {
 	ensure_single_rev $rev
 	ensure_clean
 
-	if test -n "$squash"
+	if test -n "$arg_addmerge_squash"
 	then
 		first_split="$(find_latest_squash "$dir")" || exit $?
 		if test -z "$first_split"
@@ -830,12 +830,12 @@ cmd_merge () {
 		rev="$new"
 	fi
 
-	if test -n "$message"
+	if test -n "$arg_addmerge_message"
 	then
-		git merge -Xsubtree="$prefix" \
-		    --message="$message" "$rev"
+		git merge -Xsubtree="$arg_prefix" \
+			--message="$arg_addmerge_message" "$rev"
 	else
-		git merge -Xsubtree="$prefix" $rev
+		git merge -Xsubtree="$arg_prefix" $rev
 	fi
 }
 
@@ -863,7 +863,7 @@ cmd_push () {
 		repository=$1
 		refspec=$2
 		echo "git push using: " "$repository" "$refspec"
-		localrev=$(git subtree split --prefix="$prefix") || die
+		localrev=$(git subtree split --prefix="$arg_prefix") || die
 		git push "$repository" "$localrev":"refs/heads/$refspec"
 	else
 		die "'$dir' must already exist. Try 'git subtree add'."
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 18/30] subtree: use "$*" instead of "$@" as appropriate
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (16 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 17/30] subtree: use more explicit variable names for cmdline args Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 19/30] subtree: Don't fuss with PATH Luke Shumaker
                     ` (12 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

"$*" is for when you want to concatenate the args together,
whitespace-separated; and "$@" is for when you want them to be separate
strings.

There are several places in subtree that erroneously use $@ when
concatenating args together into an error message.

For instance, if the args are argv[1]="dead" and argv[2]="beef", then
the line

    die "You must provide exactly one revision.  Got: '$@'"

surely intends to call 'die' with the argument

    argv[1]="You must provide exactly one revision.  Got: 'dead beef'"

however, because the line used $@ instead of $*, it will actually call
'die' with the arguments

    argv[1]="You must provide exactly one revision.  Got: 'dead"
    argv[2]="beef'"

This isn't a big deal, because 'die' concatenates its arguments together
anyway (using "$*").  But that doesn't change the fact that it was a
mistake to use $@ instead of $*, even though in the end $@ still ended
up doing the right thing.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - Improve the commit message with quoting and clearer
   explanation.

 contrib/subtree/git-subtree.sh | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index d7de4b0653..3105eb8033 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -58,14 +58,14 @@ progress () {
 assert () {
 	if ! "$@"
 	then
-		die "assertion failed: " "$@"
+		die "assertion failed: $*"
 	fi
 }
 
 ensure_single_rev () {
 	if test $# -ne 1
 	then
-		die "You must provide exactly one revision.  Got: '$@'"
+		die "You must provide exactly one revision.  Got: '$*'"
 	fi
 }
 
@@ -690,7 +690,7 @@ cmd_add () {
 
 		cmd_add_repository "$@"
 	else
-		say >&2 "error: parameters were '$@'"
+		say >&2 "error: parameters were '$*'"
 		die "Provide either a commit or a repository and commit."
 	fi
 }
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 19/30] subtree: Don't fuss with PATH
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (17 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 18/30] subtree: use "$*" instead of "$@" as appropriate Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 23:16     ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 20/30] subtree: use "^{commit}" instead of "^0" Luke Shumaker
                     ` (11 subsequent siblings)
  30 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Scripts needing to fuss with with adding $(git --exec-prefix) PATH
before loading git-sh-setup is a thing of the past.  As far as I can
tell, it's been a thing of the past since since Git v1.2.0 (2006-02-12),
or more specifically, since 77cb17e940 (Exec git programs without using
PATH, 2006-01-10).  However, it stuck around in contrib scripts and in
third-party scripts for long enough that it wasn't unusual to see.

Originally `git subtree` didn't fuss with PATH, but when people
(including the original subtree author) had problems, because it was a
common thing to see, it seemed that having subtree fuss with PATH was a
reasonable solution.

Here is an abridged history of fussing with PATH in subtree:

  2987e6add3 (Add explicit path of git installation by 'git --exec-path', Gianluca Pacchiella, 2009-08-20)

    As pointed out by documentation, the correct use of 'git-sh-setup' is
    using $(git --exec-path) to avoid problems with not standard
    installations.

    -. git-sh-setup
    +. $(git --exec-path)/git-sh-setup

  33aaa697a2 (Improve patch to use git --exec-path: add to PATH instead, Avery Pennarun, 2009-08-26)

    If you (like me) are using a modified git straight out of its source
    directory (ie. without installing), then --exec-path isn't actually correct.
    Add it to the PATH instead, so if it is correct, it'll work, but if it's
    not, we fall back to the previous behaviour.

    -. $(git --exec-path)/git-sh-setup
    +PATH=$(git --exec-path):$PATH
    +. git-sh-setup

  9c632ea29c ((Hopefully) fix PATH setting for msysgit, Avery Pennarun, 2010-06-24)

    Reported by Evan Shaw.  The problem is that $(git --exec-path) includes a
    'git' binary which is incompatible with the one in /usr/bin; if you run it,
    it gives you an error about libiconv2.dll.

    +OPATH=$PATH
     PATH=$(git --exec-path):$PATH
     . git-sh-setup
    +PATH=$OPATH  # apparently needed for some versions of msysgit

  df2302d774 (Another fix for PATH and msysgit, Avery Pennarun, 2010-06-24)

    Evan Shaw tells me the previous fix didn't work.  Let's use this one
    instead, which he says does work.

    This fix is kind of wrong because it will run the "correct" git-sh-setup
    *after* the one in /usr/bin, if there is one, which could be weird if you
    have multiple versions of git installed.  But it works on my Linux and his
    msysgit, so it's obviously better than what we had before.

    -OPATH=$PATH
    -PATH=$(git --exec-path):$PATH
    +PATH=$PATH:$(git --exec-path)
     . git-sh-setup
    -PATH=$OPATH  # apparently needed for some versions of msysgit

First of all, I disagree with Gianluca's reading of the documentation:
 - I haven't gone back to read what the documentation said in 2009, but
   in my reading of the 2021 documentation is that it includes "$(git
   --exec-path)/" in the synopsis for illustrative purposes, not to say
   it's the proper way.
 - After being executed by `git`, the git exec path should be the very
   first entry in PATH, so it shouldn't matter.
 - None of the scripts that are part of git do it that way.

But secondly, the root reason for fussing with PATH seems to be that
Avery didn't know that he needs to set GIT_EXEC_PATH if he's going to
use git from the source directory without installing.

And finally, Evan's issue is clearly just a bug in msysgit.  I assume
that msysgit has since fixed the issue, and also msysgit has been
deprecated for 6 years now, so let's drop the workaround for it.

So, remove the line fussing with PATH.  However, since subtree *is* in
'contrib/' and it might get installed in funny ways by users
after-the-fact, add a sanity check to the top of the script, checking
that it is installed correctly.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 3105eb8033..af636fbb43 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -5,6 +5,22 @@
 # Copyright (C) 2009 Avery Pennarun <apenwarr@gmail.com>
 #
 
+if test -z "$GIT_EXEC_PATH" || test "${PATH#"${GIT_EXEC_PATH}:"}" = "$PATH" || ! test -f "$GIT_EXEC_PATH/git-sh-setup"
+then
+	echo >&2 'It looks like either your git installation or your'
+	echo >&2 'git-subtree installation is broken.'
+	echo >&2
+	echo >&2 "Tips:"
+	echo >&2 " - If \`git --exec-path\` does not print the correct path to"
+	echo >&2 "   your git install directory, then set the GIT_EXEC_PATH"
+	echo >&2 "   environment variable to the correct directory."
+	echo >&2 " - Make sure that your \`${0##*/}\` file is either in your"
+	echo >&2 "   PATH or in your git exec path (\`$(git --exec-path)\`)."
+	echo >&2 " - You should run git-subtree as \`git ${0##*/git-}\`,"
+	echo >&2 "   not as \`${0##*/}\`." >&2
+	exit 126
+fi
+
 OPTS_SPEC="\
 git subtree add   --prefix=<prefix> <commit>
 git subtree add   --prefix=<prefix> <repository> <ref>
@@ -28,8 +44,6 @@ rejoin        merge the new branch back into HEAD
 squash        merge subtree changes as a single commit
 "
 
-PATH=$PATH:$(git --exec-path)
-
 arg_debug=
 arg_command=
 arg_prefix=
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 20/30] subtree: use "^{commit}" instead of "^0"
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (18 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 19/30] subtree: Don't fuss with PATH Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 21/30] subtree: parse revs in individual cmd_ functions Luke Shumaker
                     ` (10 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

They are synonyms.  Both are used in the file.  ^{commit} is clearer, so
"standardize" on that.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index af636fbb43..ee7fda3672 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -316,7 +316,7 @@ find_latest_squash () {
 			main="$b"
 			;;
 		git-subtree-split:)
-			sub="$(git rev-parse "$b^0")" ||
+			sub="$(git rev-parse "$b^{commit}")" ||
 			die "could not rev-parse split hash $b from commit $sq"
 			;;
 		END)
@@ -363,7 +363,7 @@ find_existing_splits () {
 			main="$b"
 			;;
 		git-subtree-split:)
-			sub="$(git rev-parse "$b^0")" ||
+			sub="$(git rev-parse "$b^{commit}")" ||
 			die "could not rev-parse split hash $b from commit $sq"
 			;;
 		END)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 21/30] subtree: parse revs in individual cmd_ functions
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (19 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 20/30] subtree: use "^{commit}" instead of "^0" Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 22/30] subtree: remove duplicate check Luke Shumaker
                     ` (9 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

The main argument parser goes ahead and tries to parse revs to make
things simpler for the sub-command implementations.  But, it includes
enough special cases for different sub-commands.  And it's difficult
having having to think about "is this info coming from an argument, or a
global variable?".  So the main argument parser's effort to make things
"simpler" ends up just making it more confusing and complicated.

Begone with the 'revs' global variable; parse 'rev=$(...)' as needed in
individual 'cmd_*' functions.

Begone with the 'default' global variable.  Its would-be value is
knowable just from which function we're in.

Begone with the 'ensure_single_rev' function.  Its functionality can be
achieved by passing '--verify' to 'git rev-parse'.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 62 +++++++++++++---------------------
 1 file changed, 24 insertions(+), 38 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index ee7fda3672..0df8d1b7d4 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -76,13 +76,6 @@ assert () {
 	fi
 }
 
-ensure_single_rev () {
-	if test $# -ne 1
-	then
-		die "You must provide exactly one revision.  Got: '$*'"
-	fi
-}
-
 main () {
 	if test $# -eq 0
 	then
@@ -164,11 +157,8 @@ main () {
 	shift
 
 	case "$arg_command" in
-	add|merge|pull)
-		default=
-		;;
-	split|push)
-		default="--default HEAD"
+	add|merge|pull|split|push)
+		:
 		;;
 	*)
 		die "Unknown command '$arg_command'"
@@ -193,22 +183,8 @@ main () {
 
 	dir="$(dirname "$arg_prefix/.")"
 
-	if test "$arg_command" != "pull" &&
-			test "$arg_command" != "add" &&
-			test "$arg_command" != "push"
-	then
-		revs=$(git rev-parse $default --revs-only "$@") || exit $?
-		dirs=$(git rev-parse --no-revs --no-flags "$@") || exit $?
-		ensure_single_rev $revs
-		if test -n "$dirs"
-		then
-			die "Error: Use --prefix instead of bare filenames."
-		fi
-	fi
-
 	debug "command: {$arg_command}"
 	debug "quiet: {$GIT_QUIET}"
-	debug "revs: {$revs}"
 	debug "dir: {$dir}"
 	debug "opts: {$*}"
 	debug
@@ -714,14 +690,13 @@ cmd_add_repository () {
 	repository=$1
 	refspec=$2
 	git fetch "$@" || exit $?
-	revs=FETCH_HEAD
-	set -- $revs
-	cmd_add_commit "$@"
+	cmd_add_commit FETCH_HEAD
 }
 
 cmd_add_commit () {
-	rev=$(git rev-parse $default --revs-only "$@") || exit $?
-	ensure_single_rev $rev
+	# The rev has already been validated by cmd_add(), we just
+	# need to normalize it.
+	rev=$(git rev-parse --verify "$1^{commit}") || exit $?
 
 	debug "Adding $dir as '$rev'..."
 	git read-tree --prefix="$dir" $rev || exit $?
@@ -752,6 +727,17 @@ cmd_add_commit () {
 }
 
 cmd_split () {
+	if test $# -eq 0
+	then
+		rev=$(git rev-parse HEAD)
+	elif test $# -eq 1
+	then
+		rev=$(git rev-parse -q --verify "$1^{commit}") ||
+			die "'$1' does not refer to a commit"
+	else
+		die "You must provide exactly one revision.  Got: '$*'"
+	fi
+
 	debug "Splitting $dir..."
 	cache_setup || exit $?
 
@@ -768,12 +754,12 @@ cmd_split () {
 		done || exit $?
 	fi
 
-	unrevs="$(find_existing_splits "$dir" "$revs")" || exit $?
+	unrevs="$(find_existing_splits "$dir" "$rev")" || exit $?
 
 	# We can't restrict rev-list to only $dir here, because some of our
 	# parents have the $dir contents the root, and those won't match.
 	# (and rev-list --follow doesn't seem to solve this)
-	grl='git rev-list --topo-order --reverse --parents $revs $unrevs'
+	grl='git rev-list --topo-order --reverse --parents $rev $unrevs'
 	revmax=$(eval "$grl" | wc -l)
 	revcount=0
 	createcount=0
@@ -820,8 +806,10 @@ cmd_split () {
 }
 
 cmd_merge () {
-	rev=$(git rev-parse $default --revs-only "$@") || exit $?
-	ensure_single_rev $rev
+	test $# -eq 1 ||
+		die "You must provide exactly one revision.  Got: '$*'"
+	rev=$(git rev-parse -q --verify "$1^{commit}") ||
+		die "'$1' does not refer to a commit"
 	ensure_clean
 
 	if test -n "$arg_addmerge_squash"
@@ -861,9 +849,7 @@ cmd_pull () {
 	ensure_clean
 	ensure_valid_ref_format "$2"
 	git fetch "$@" || exit $?
-	revs=FETCH_HEAD
-	set -- $revs
-	cmd_merge "$@"
+	cmd_merge FETCH_HEAD
 }
 
 cmd_push () {
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 22/30] subtree: remove duplicate check
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (20 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 21/30] subtree: parse revs in individual cmd_ functions Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 23/30] subtree: add comments and sanity checks Luke Shumaker
                     ` (8 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

`cmd_add` starts with a check that the directory doesn't yet exist.
However, the `main` function performs the exact same check before
calling `cmd_add`.  So remove the check from `cmd_add`.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 0df8d1b7d4..7fbd8481ed 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -655,10 +655,6 @@ process_split_commit () {
 }
 
 cmd_add () {
-	if test -e "$dir"
-	then
-		die "'$dir' already exists.  Cannot add."
-	fi
 
 	ensure_clean
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 23/30] subtree: add comments and sanity checks
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (21 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 22/30] subtree: remove duplicate check Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 24/30] subtree: don't let debug and progress output clash Luke Shumaker
                     ` (7 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

For each function in subtree, add a usage comment saying what the
arguments are, and add an `assert` checking the number of arguments.

In figuring out each thing's arguments in order to write those comments
and assertions, it turns out that find_existing_splits is written as if
it takes multiple 'revs', but it is in fact only ever passed a single
'rev':

	unrevs="$(find_existing_splits "$dir" "$rev")" || exit $?

So go ahead and codify that by documenting and asserting that it takes
exactly two arguments, one dir and one rev.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - Expand on the the commit message.
 - Fix capitalization in one of the comments.

 contrib/subtree/git-subtree.sh | 64 ++++++++++++++++++++++++++++++++--
 1 file changed, 61 insertions(+), 3 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 7fbd8481ed..441571c85a 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -55,6 +55,7 @@ arg_split_annotate=
 arg_addmerge_squash=
 arg_addmerge_message=
 
+# Usage: debug [MSG...]
 debug () {
 	if test -n "$arg_debug"
 	then
@@ -62,6 +63,7 @@ debug () {
 	fi
 }
 
+# Usage: progress [MSG...]
 progress () {
 	if test -z "$GIT_QUIET"
 	then
@@ -69,6 +71,7 @@ progress () {
 	fi
 }
 
+# Usage: assert CMD...
 assert () {
 	if ! "$@"
 	then
@@ -192,7 +195,9 @@ main () {
 	"cmd_$arg_command" "$@"
 }
 
+# Usage: cache_setup
 cache_setup () {
+	assert test $# = 0
 	cachedir="$GIT_DIR/subtree-cache/$$"
 	rm -rf "$cachedir" ||
 		die "Can't delete old cachedir: $cachedir"
@@ -203,6 +208,7 @@ cache_setup () {
 	debug "Using cachedir: $cachedir" >&2
 }
 
+# Usage: cache_get [REVS...]
 cache_get () {
 	for oldrev in "$@"
 	do
@@ -214,6 +220,7 @@ cache_get () {
 	done
 }
 
+# Usage: cache_miss [REVS...]
 cache_miss () {
 	for oldrev in "$@"
 	do
@@ -224,7 +231,9 @@ cache_miss () {
 	done
 }
 
+# Usage: check_parents PARENTS_EXPR INDENT
 check_parents () {
+	assert test $# = 2
 	missed=$(cache_miss "$1") || exit $?
 	local indent=$(($2 + 1))
 	for miss in $missed
@@ -237,11 +246,15 @@ check_parents () {
 	done
 }
 
+# Usage: set_notree REV
 set_notree () {
+	assert test $# = 1
 	echo "1" > "$cachedir/notree/$1"
 }
 
+# Usage: cache_set OLDREV NEWREV
 cache_set () {
+	assert test $# = 2
 	oldrev="$1"
 	newrev="$2"
 	if test "$oldrev" != "latest_old" &&
@@ -253,7 +266,9 @@ cache_set () {
 	echo "$newrev" >"$cachedir/$oldrev"
 }
 
+# Usage: rev_exists REV
 rev_exists () {
+	assert test $# = 1
 	if git rev-parse "$1" >/dev/null 2>&1
 	then
 		return 0
@@ -262,17 +277,22 @@ rev_exists () {
 	fi
 }
 
-# if a commit doesn't have a parent, this might not work.  But we only want
+# Usage: try_remove_previous REV
+#
+# If a commit doesn't have a parent, this might not work.  But we only want
 # to remove the parent from the rev-list, and since it doesn't exist, it won't
 # be there anyway, so do nothing in that case.
 try_remove_previous () {
+	assert test $# = 1
 	if rev_exists "$1^"
 	then
 		echo "^$1^"
 	fi
 }
 
+# Usage: find_latest_squash DIR
 find_latest_squash () {
+	assert test $# = 1
 	debug "Looking for latest squash ($dir)..."
 	dir="$1"
 	sq=
@@ -316,10 +336,12 @@ find_latest_squash () {
 	done || exit $?
 }
 
+# Usage: find_existing_splits DIR REV
 find_existing_splits () {
+	assert test $# = 2
 	debug "Looking for prior splits..."
 	dir="$1"
-	revs="$2"
+	rev="$2"
 	main=
 	sub=
 	local grep_format="^git-subtree-dir: $dir/*\$"
@@ -328,7 +350,7 @@ find_existing_splits () {
 		grep_format="^Add '$dir/' from commit '"
 	fi
 	git log --grep="$grep_format" \
-		--no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' $revs |
+		--no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' "$rev" |
 	while read a b junk
 	do
 		case "$a" in
@@ -365,7 +387,9 @@ find_existing_splits () {
 	done || exit $?
 }
 
+# Usage: copy_commit REV TREE FLAGS_STR
 copy_commit () {
+	assert test $# = 3
 	# We're going to set some environment vars here, so
 	# do it in a subshell to get rid of them safely later
 	debug copy_commit "{$1}" "{$2}" "{$3}"
@@ -391,7 +415,9 @@ copy_commit () {
 	) || die "Can't copy commit $1"
 }
 
+# Usage: add_msg DIR LATEST_OLD LATEST_NEW
 add_msg () {
+	assert test $# = 3
 	dir="$1"
 	latest_old="$2"
 	latest_new="$3"
@@ -410,7 +436,9 @@ add_msg () {
 	EOF
 }
 
+# Usage: add_squashed_msg REV DIR
 add_squashed_msg () {
+	assert test $# = 2
 	if test -n "$arg_addmerge_message"
 	then
 		echo "$arg_addmerge_message"
@@ -419,7 +447,9 @@ add_squashed_msg () {
 	fi
 }
 
+# Usage: rejoin_msg DIR LATEST_OLD LATEST_NEW
 rejoin_msg () {
+	assert test $# = 3
 	dir="$1"
 	latest_old="$2"
 	latest_new="$3"
@@ -438,7 +468,9 @@ rejoin_msg () {
 	EOF
 }
 
+# Usage: squash_msg DIR OLD_SUBTREE_COMMIT NEW_SUBTREE_COMMIT
 squash_msg () {
+	assert test $# = 3
 	dir="$1"
 	oldsub="$2"
 	newsub="$3"
@@ -460,12 +492,16 @@ squash_msg () {
 	echo "git-subtree-split: $newsub"
 }
 
+# Usage: toptree_for_commit COMMIT
 toptree_for_commit () {
+	assert test $# = 1
 	commit="$1"
 	git rev-parse --verify "$commit^{tree}" || exit $?
 }
 
+# Usage: subtree_for_commit COMMIT DIR
 subtree_for_commit () {
+	assert test $# = 2
 	commit="$1"
 	dir="$2"
 	git ls-tree "$commit" -- "$dir" |
@@ -479,7 +515,9 @@ subtree_for_commit () {
 	done || exit $?
 }
 
+# Usage: tree_changed TREE [PARENTS...]
 tree_changed () {
+	assert test $# -gt 0
 	tree=$1
 	shift
 	if test $# -ne 1
@@ -496,7 +534,9 @@ tree_changed () {
 	fi
 }
 
+# Usage: new_squash_commit OLD_SQUASHED_COMMIT OLD_NONSQUASHED_COMMIT NEW_NONSQUASHED_COMMIT
 new_squash_commit () {
+	assert test $# = 3
 	old="$1"
 	oldsub="$2"
 	newsub="$3"
@@ -511,7 +551,9 @@ new_squash_commit () {
 	fi
 }
 
+# Usage: copy_or_skip REV TREE NEWPARENTS
 copy_or_skip () {
+	assert test $# = 3
 	rev="$1"
 	tree="$2"
 	newparents="$3"
@@ -586,7 +628,9 @@ copy_or_skip () {
 	fi
 }
 
+# Usage: ensure_clean
 ensure_clean () {
+	assert test $# = 0
 	if ! git diff-index HEAD --exit-code --quiet 2>&1
 	then
 		die "Working tree has modifications.  Cannot add."
@@ -597,12 +641,16 @@ ensure_clean () {
 	fi
 }
 
+# Usage: ensure_valid_ref_format REF
 ensure_valid_ref_format () {
+	assert test $# = 1
 	git check-ref-format "refs/heads/$1" ||
 		die "'$1' does not look like a ref"
 }
 
+# Usage: process_split_commit REV PARENTS INDENT
 process_split_commit () {
+	assert test $# = 3
 	local rev="$1"
 	local parents="$2"
 	local indent=$3
@@ -654,6 +702,8 @@ process_split_commit () {
 	cache_set latest_old "$rev"
 }
 
+# Usage: cmd_add REV
+#    Or: cmd_add REPOSITORY REF
 cmd_add () {
 
 	ensure_clean
@@ -681,7 +731,9 @@ cmd_add () {
 	fi
 }
 
+# Usage: cmd_add_repository REPOSITORY REFSPEC
 cmd_add_repository () {
+	assert test $# = 2
 	echo "git fetch" "$@"
 	repository=$1
 	refspec=$2
@@ -689,9 +741,11 @@ cmd_add_repository () {
 	cmd_add_commit FETCH_HEAD
 }
 
+# Usage: cmd_add_commit REV
 cmd_add_commit () {
 	# The rev has already been validated by cmd_add(), we just
 	# need to normalize it.
+	assert test $# = 1
 	rev=$(git rev-parse --verify "$1^{commit}") || exit $?
 
 	debug "Adding $dir as '$rev'..."
@@ -722,6 +776,7 @@ cmd_add_commit () {
 	say >&2 "Added dir '$dir'"
 }
 
+# Usage: cmd_split [REV]
 cmd_split () {
 	if test $# -eq 0
 	then
@@ -801,6 +856,7 @@ cmd_split () {
 	exit 0
 }
 
+# Usage: cmd_merge REV
 cmd_merge () {
 	test $# -eq 1 ||
 		die "You must provide exactly one revision.  Got: '$*'"
@@ -837,6 +893,7 @@ cmd_merge () {
 	fi
 }
 
+# Usage: cmd_pull REPOSITORY REMOTEREF
 cmd_pull () {
 	if test $# -ne 2
 	then
@@ -848,6 +905,7 @@ cmd_pull () {
 	cmd_merge FETCH_HEAD
 }
 
+# Usage: cmd_push REPOSITORY REMOTEREF
 cmd_push () {
 	if test $# -ne 2
 	then
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 24/30] subtree: don't let debug and progress output clash
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (22 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 23/30] subtree: add comments and sanity checks Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 25/30] subtree: have $indent actually affect indentation Luke Shumaker
                     ` (6 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Currently, debug output (triggered by passing '-d') and progress output
stomp on each other.  The debug output is just streamed as lines to
stderr, and the progress output is sent to stderr as '%s\r'.  When
writing to a file, it is awkward to read and difficult to distinguish
between the debug output and a progress line.  When writing to a
terminal the debug lines hide progress lines.

So, when '-d' has been passed, spit out progress as 'progress: %s\n',
instead of as '%s\r', so that it can be detected, and so that the debug
lines don't overwrite the progress when written to a terminal.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - Reword the commit message to be clearer.
 - Add comments to the code.
 - Flip the `if` and `else` cases around, so that the comments
   read better.

 contrib/subtree/git-subtree.sh | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 441571c85a..53a1a025f5 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -67,7 +67,27 @@ debug () {
 progress () {
 	if test -z "$GIT_QUIET"
 	then
-		printf "%s\r" "$*" >&2
+		if test -z "$arg_debug"
+		then
+			# Debug mode is off.
+			#
+			# Print one progress line that we keep updating (use
+			# "\r" to return to the beginning of the line, rather
+			# than "\n" to start a new line).  This only really
+			# works when stderr is a terminal.
+			printf "%s\r" "$*" >&2
+		else
+			# Debug mode is on.  The `debug` function is regularly
+			# printing to stderr.
+			#
+			# Don't do the one-line-with-"\r" thing, because on a
+			# terminal the debug output would overwrite and hide the
+			# progress output.  Add a "progress:" prefix to make the
+			# progress output and the debug output easy to
+			# distinguish.  This ensures maximum readability whether
+			# stderr is a terminal or a file.
+			printf "progress: %s\n" "$*" >&2
+		fi
 	fi
 }
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 25/30] subtree: have $indent actually affect indentation
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (23 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 24/30] subtree: don't let debug and progress output clash Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 26/30] subtree: give the docs a once-over Luke Shumaker
                     ` (5 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Currently, the $indent variable is just used to track how deeply we're
nested, and the debug log is indented by things like

   debug "  foo"

That is: The indentation-level is hard-coded.  It used to be that the
code couldn't recurse, so the indentation level could be known
statically, so it made sense to just hard-code it in the
output. However, since 315a84f9aa ("subtree: use commits before rejoins
for splits", 2018-09-28), it can now recurse, and the debug log is
misleading.

So fix that.  Indent according to $indent.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 42 +++++++++++++++++++---------------
 1 file changed, 24 insertions(+), 18 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 53a1a025f5..768fa7b6b6 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -55,11 +55,13 @@ arg_split_annotate=
 arg_addmerge_squash=
 arg_addmerge_message=
 
+indent=0
+
 # Usage: debug [MSG...]
 debug () {
 	if test -n "$arg_debug"
 	then
-		printf "%s\n" "$*" >&2
+		printf "%$(($indent * 2))s%s\n" '' "$*" >&2
 	fi
 }
 
@@ -251,17 +253,17 @@ cache_miss () {
 	done
 }
 
-# Usage: check_parents PARENTS_EXPR INDENT
+# Usage: check_parents PARENTS_EXPR
 check_parents () {
-	assert test $# = 2
+	assert test $# = 1
 	missed=$(cache_miss "$1") || exit $?
-	local indent=$(($2 + 1))
+	local indent=$(($indent + 1))
 	for miss in $missed
 	do
 		if ! test -r "$cachedir/notree/$miss"
 		then
-			debug "  incorrect order: $miss"
-			process_split_commit "$miss" "" "$indent"
+			debug "incorrect order: $miss"
+			process_split_commit "$miss" ""
 		fi
 	done
 }
@@ -314,6 +316,8 @@ try_remove_previous () {
 find_latest_squash () {
 	assert test $# = 1
 	debug "Looking for latest squash ($dir)..."
+	local indent=$(($indent + 1))
+
 	dir="$1"
 	sq=
 	main=
@@ -360,6 +364,8 @@ find_latest_squash () {
 find_existing_splits () {
 	assert test $# = 2
 	debug "Looking for prior splits..."
+	local indent=$(($indent + 1))
+
 	dir="$1"
 	rev="$2"
 	main=
@@ -385,7 +391,7 @@ find_existing_splits () {
 			die "could not rev-parse split hash $b from commit $sq"
 			;;
 		END)
-			debug "  Main is: '$main'"
+			debug "Main is: '$main'"
 			if test -z "$main" -a -n "$sub"
 			then
 				# squash commits refer to a subtree
@@ -668,12 +674,11 @@ ensure_valid_ref_format () {
 		die "'$1' does not look like a ref"
 }
 
-# Usage: process_split_commit REV PARENTS INDENT
+# Usage: process_split_commit REV PARENTS
 process_split_commit () {
-	assert test $# = 3
+	assert test $# = 2
 	local rev="$1"
 	local parents="$2"
-	local indent=$3
 
 	if test $indent -eq 0
 	then
@@ -688,20 +693,21 @@ process_split_commit () {
 	progress "$revcount/$revmax ($createcount) [$extracount]"
 
 	debug "Processing commit: $rev"
+	local indent=$(($indent + 1))
 	exists=$(cache_get "$rev") || exit $?
 	if test -n "$exists"
 	then
-		debug "  prior: $exists"
+		debug "prior: $exists"
 		return
 	fi
 	createcount=$(($createcount + 1))
-	debug "  parents: $parents"
-	check_parents "$parents" "$indent"
+	debug "parents: $parents"
+	check_parents "$parents"
 	newparents=$(cache_get $parents) || exit $?
-	debug "  newparents: $newparents"
+	debug "newparents: $newparents"
 
 	tree=$(subtree_for_commit "$rev" "$dir") || exit $?
-	debug "  tree is: $tree"
+	debug "tree is: $tree"
 
 	# ugly.  is there no better way to tell if this is a subtree
 	# vs. a mainline commit?  Does it matter?
@@ -716,7 +722,7 @@ process_split_commit () {
 	fi
 
 	newrev=$(copy_or_skip "$rev" "$tree" "$newparents") || exit $?
-	debug "  newrev is: $newrev"
+	debug "newrev is: $newrev"
 	cache_set "$rev" "$newrev"
 	cache_set latest_new "$newrev"
 	cache_set latest_old "$rev"
@@ -820,7 +826,7 @@ cmd_split () {
 		do
 			# the 'onto' history is already just the subdir, so
 			# any parent we find there can be used verbatim
-			debug "  cache: $rev"
+			debug "cache: $rev"
 			cache_set "$rev" "$rev"
 		done || exit $?
 	fi
@@ -838,7 +844,7 @@ cmd_split () {
 	eval "$grl" |
 	while read rev parents
 	do
-		process_split_commit "$rev" "$parents" 0
+		process_split_commit "$rev" "$parents"
 	done || exit $?
 
 	latest_new=$(cache_get latest_new) || exit $?
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 26/30] subtree: give the docs a once-over
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (24 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 25/30] subtree: have $indent actually affect indentation Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 27/30] subtree: allow --squash to be used with --rejoin Luke Shumaker
                     ` (4 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Just went through the docs looking for anything inaccurate or that can
be improved.

In the '-h' text, in the man page synopsis, and in the man page
description: Normalize the ordering of the list of sub-commands: 'add',
'merge', 'split', 'pull', 'push'.  This allows us to kinda separate the
lower-level add/merge/split from the higher-level pull/push.

'-h' text:
 - correction: Indicate that split's arg is optional.
 - clarity: Emphasize that 'pull' takes the 'add'/'merge' flags.

man page:

 - correction: State that all subcommands take options (it seemed to
   indicate that only 'split' takes any options other than '-P').
 - correction: 'split' only guarantees that the results are identical if
   the flags are identical.
 - completeness: Clarify that 'push' always operates on HEAD, and that
   'split' operates on HEAD if no local commit is given.
 - clarity: In the description, when listing commands, repeat what their
   arguments are.  This way the reader doesn't need to flip back and
   forth between the command description and the synopsis and the full
   description to understand what's being said.
 - clarity: In the <variables> used to give command arguments, give
   slightly longer, descriptive names.  Like <local-commit> instead of
   just <commit>.
 - clarity: Emphasize that 'pull' takes the 'add'/'merge' flags.
 - style: In the synopsis, list options before the subcommand.  This
   makes things line up and be much more readable when shown
   non-monospace (such as in `make html`), and also more closely matches
   other man pages (like `git-submodule.txt`).
 - style: Use the correct syntax for indicating the options ([<options>]
   instead of [OPTIONS]).
 - style: In the synopsis, separate 'pull' and 'push' from the other
   lower-level commands.  I think this helps readability.
 - style: Code-quote things in prose that seem like they should be
   code-quoted, like '.gitmodules', flags, or full commands.
 - style: Minor wording improvements, like more consistent mood (many
   of the command descriptions start in the imperative mood and switch
   to the indicative mode by the end).  That sort of thing.
 - style: Capitalize "ID".
 - style: Remove the "This option is only valid for XXX command" remarks
   from each option, and instead rely on the section headings.
 - style: Since that line is getting edited anyway, switch "behaviour" to
   American "behavior".

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - behaviour -> behavior

 contrib/subtree/git-subtree.sh  |   4 +-
 contrib/subtree/git-subtree.txt | 162 +++++++++++++++-----------------
 2 files changed, 80 insertions(+), 86 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 768fa7b6b6..3bffddf277 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -25,9 +25,9 @@ OPTS_SPEC="\
 git subtree add   --prefix=<prefix> <commit>
 git subtree add   --prefix=<prefix> <repository> <ref>
 git subtree merge --prefix=<prefix> <commit>
+git subtree split --prefix=<prefix> [<commit>]
 git subtree pull  --prefix=<prefix> <repository> <ref>
 git subtree push  --prefix=<prefix> <repository> <ref>
-git subtree split --prefix=<prefix> <commit>
 --
 h,help        show the help
 q             quiet
@@ -40,7 +40,7 @@ b,branch=     create a new branch from the split subtree
 ignore-joins  ignore prior --rejoin commits
 onto=         try connecting new tree to an existing one
 rejoin        merge the new branch back into HEAD
- options for 'add', 'merge', and 'pull'
+ options for 'add' and 'merge' (also: 'pull')
 squash        merge subtree changes as a single commit
 "
 
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index 0db02fe3c0..7baac17260 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -9,13 +9,14 @@ git-subtree - Merge subtrees together and split repository into subtrees
 SYNOPSIS
 --------
 [verse]
-'git subtree' add   -P <prefix> <commit>
-'git subtree' add   -P <prefix> <repository> <ref>
-'git subtree' pull  -P <prefix> <repository> <ref>
-'git subtree' push  -P <prefix> <repository> <ref>
-'git subtree' merge -P <prefix> <commit>
-'git subtree' split -P <prefix> [OPTIONS] [<commit>]
+'git subtree' [<options>] -P <prefix> add <local-commit>
+'git subtree' [<options>] -P <prefix> add <repository> <remote-ref>
+'git subtree' [<options>] -P <prefix> merge <local-commit>
+'git subtree' [<options>] -P <prefix> split [<local-commit>]
 
+[verse]
+'git subtree' [<options>] -P <prefix> pull <repository> <remote-ref>
+'git subtree' [<options>] -P <prefix> push <repository> <remote-ref>
 
 DESCRIPTION
 -----------
@@ -28,7 +29,7 @@ as a subdirectory of your application.
 
 Subtrees are not to be confused with submodules, which are meant for
 the same task. Unlike submodules, subtrees do not need any special
-constructions (like .gitmodules files or gitlinks) be present in
+constructions (like '.gitmodules' files or gitlinks) be present in
 your repository, and do not force end-users of your
 repository to do anything special or to understand how subtrees
 work. A subtree is just a subdirectory that can be
@@ -59,27 +60,28 @@ project as much as possible.  That is, if you make a change that
 affects both the library and the main application, commit it in
 two pieces.  That way, when you split the library commits out
 later, their descriptions will still make sense.  But if this
-isn't important to you, it's not *necessary*.  git subtree will
+isn't important to you, it's not *necessary*.  'git subtree' will
 simply leave out the non-library-related parts of the commit
 when it splits it out into the subproject later.
 
 
 COMMANDS
 --------
-add::
+add <local-commit>::
+add <repository> <remote-ref>::
 	Create the <prefix> subtree by importing its contents
-	from the given <commit> or <repository> and remote <ref>.
+	from the given <local-commit> or <repository> and <remote-ref>.
 	A new commit is created	automatically, joining the imported
-	project's history with your own.  With '--squash', imports
+	project's history with your own.  With '--squash', import
 	only a single commit from the subproject, rather than its
 	entire history.
 
-merge::
-	Merge recent changes up to <commit> into the <prefix>
+merge <local-commit>::
+	Merge recent changes up to <local-commit> into the <prefix>
 	subtree.  As with normal 'git merge', this doesn't
 	remove your own local changes; it just merges those
-	changes into the latest <commit>.  With '--squash',
-	creates only one commit that contains all the changes,
+	changes into the latest <local-commit>.  With '--squash',
+	create only one commit that contains all the changes,
 	rather than merging in the entire history.
 +
 If you use '--squash', the merge direction doesn't always have to be
@@ -87,39 +89,40 @@ forward; you can use this command to go back in time from v2.5 to v2.4,
 for example.  If your merge introduces a conflict, you can resolve it in
 the usual ways.
 	
-pull::
-	Exactly like 'merge', but parallels 'git pull' in that
-	it fetches the given ref from the specified remote
-	repository.
-	
-push::
-	Does a 'split' (see below) using the <prefix> supplied
-	and then does a 'git push' to push the result to the 
-	repository and ref. This can be used to push your
-	subtree to different branches of the remote repository.
-
-split::
+split [<local-commit>]::
 	Extract a new, synthetic project history from the
-	history of the <prefix> subtree.  The new history
+	history of the <prefix> subtree of <local-commit>, or of
+	HEAD if no <local-commit> is given.  The new history
 	includes only the commits (including merges) that
 	affected <prefix>, and each of those commits now has the
 	contents of <prefix> at the root of the project instead
 	of in a subdirectory.  Thus, the newly created history
 	is suitable for export as a separate git repository.
 +
-After splitting successfully, a single commit id is printed to stdout.
+After splitting successfully, a single commit ID is printed to stdout.
 This corresponds to the HEAD of the newly created tree, which you can
 manipulate however you want.
 +
 Repeated splits of exactly the same history are guaranteed to be
-identical (i.e. to produce the same commit ids).  Because of this, if
-you add new commits and then re-split, the new commits will be attached
-as commits on top of the history you generated last time, so 'git merge'
-and friends will work as expected.
+identical (i.e. to produce the same commit IDs) as long as the
+settings passed to 'split' (such as '--annotate') are the same.
+Because of this, if you add new commits and then re-split, the new
+commits will be attached as commits on top of the history you
+generated last time, so 'git merge' and friends will work as expected.
 +
 Note that if you use '--squash' when you merge, you should usually not
 just '--rejoin' when you split.
 
+pull <repository> <remote-ref>::
+	Exactly like 'merge', but parallels 'git pull' in that
+	it fetches the given ref from the specified remote
+	repository.
+
+push <repository> <remote-ref>::
+	Does a 'split' using the <prefix> subtree of HEAD and then
+	does a 'git push' to push the result to the <repository> and
+	<remote-ref>.  This can be used to push your subtree to
+	different branches of the remote repository.
 
 OPTIONS
 -------
@@ -139,19 +142,18 @@ OPTIONS
 
 -m <message>::
 --message=<message>::
-	This option is only valid for add, merge, pull, and split --rejoin.
+	This option is only valid for 'add', 'merge', 'pull', and 'split --rejoin'.
 	Specify <message> as the commit message for the merge commit.
 
+OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull')
+--------------------------------------------
+These options for 'add' and 'merge' may also be given to 'pull' (which
+wraps 'merge').
 
-OPTIONS FOR add, merge, and pull
---------------------------------
 --squash::
-	This option is only valid for add, merge, and pull
-	commands.
-+
-Instead of merging the entire history from the subtree project, produce
-only a single commit that contains all the differences you want to
-merge, and then merge that new commit into your project.
+	Instead of merging the entire history from the subtree project, produce
+	only a single commit that contains all the differences you want to
+	merge, and then merge that new commit into your project.
 +
 Using this option helps to reduce log clutter. People rarely want to see
 every change that happened between v1.0 and v1.1 of the library they're
@@ -175,56 +177,48 @@ remain intact and can be later split and send upstream to the
 subproject.
 
 
-OPTIONS FOR split
------------------
+OPTIONS FOR 'split'
+-------------------
+These options are only valid for 'split'.
+
 --annotate=<annotation>::
-	This option is only valid for the split command.
-+
-When generating synthetic history, add <annotation> as a prefix to each
-commit message.  Since we're creating new commits with the same commit
-message, but possibly different content, from the original commits, this
-can help to differentiate them and avoid confusion.
+	When generating synthetic history, add <annotation> as a prefix to each
+	commit message.  Since we're creating new commits with the same commit
+	message, but possibly different content, from the original commits, this
+	can help to differentiate them and avoid confusion.
 +
 Whenever you split, you need to use the same <annotation>, or else you
 don't have a guarantee that the new re-created history will be identical
 to the old one.  That will prevent merging from working correctly.  git
-subtree tries to make it work anyway, particularly if you use --rejoin,
+subtree tries to make it work anyway, particularly if you use '--rejoin',
 but it may not always be effective.
 
 -b <branch>::
 --branch=<branch>::
-	This option is only valid for the split command.
-+
-After generating the synthetic history, create a new branch called
-<branch> that contains the new history.  This is suitable for immediate
-pushing upstream.  <branch> must not already exist.
+	After generating the synthetic history, create a new branch called
+	<branch> that contains the new history.  This is suitable for immediate
+	pushing upstream.  <branch> must not already exist.
 
 --ignore-joins::
-	This option is only valid for the split command.
-+
-If you use '--rejoin', git subtree attempts to optimize its history
-reconstruction to generate only the new commits since the last
-'--rejoin'.  '--ignore-join' disables this behaviour, forcing it to
-regenerate the entire history.  In a large project, this can take a long
-time.
+	If you use '--rejoin', git subtree attempts to optimize its history
+	reconstruction to generate only the new commits since the last
+	'--rejoin'.  '--ignore-join' disables this behavior, forcing it to
+	regenerate the entire history.  In a large project, this can take a long
+	time.
 
 --onto=<onto>::
-	This option is only valid for the split command.
-+
-If your subtree was originally imported using something other than git
-subtree, its history may not match what git subtree is expecting.  In
-that case, you can specify the commit id <onto> that corresponds to the
-first revision of the subproject's history that was imported into your
-project, and git subtree will attempt to build its history from there.
+	If your subtree was originally imported using something other than git
+	subtree, its history may not match what git subtree is expecting.  In
+	that case, you can specify the commit ID <onto> that corresponds to the
+	first revision of the subproject's history that was imported into your
+	project, and git subtree will attempt to build its history from there.
 +
 If you used 'git subtree add', you should never need this option.
 
 --rejoin::
-	This option is only valid for the split command.
-+
-After splitting, merge the newly created synthetic history back into
-your main project.  That way, future splits can search only the part of
-history that has been added since the most recent --rejoin.
+	After splitting, merge the newly created synthetic history back into
+	your main project.  That way, future splits can search only the part of
+	history that has been added since the most recent '--rejoin'.
 +
 If your split commits end up merged into the upstream subproject, and
 then you want to get the latest upstream version, this will allow git's
@@ -240,8 +234,8 @@ split, because you don't want the subproject's history to be part of
 your project anyway.
 
 
-EXAMPLE 1. Add command
-----------------------
+EXAMPLE 1. 'add' command
+------------------------
 Let's assume that you have a local repository that you would like
 to add an external vendor library to. In this case we will add the
 git-subtree repository as a subdirectory of your already existing
@@ -253,15 +247,15 @@ git-extensions repository in ~/git-extensions/:
 'master' needs to be a valid remote ref and can be a different branch
 name
 
-You can omit the --squash flag, but doing so will increase the number
+You can omit the '--squash' flag, but doing so will increase the number
 of commits that are included in your local repository.
 
 We now have a ~/git-extensions/git-subtree directory containing code
 from the master branch of git://github.com/apenwarr/git-subtree.git
 in our git-extensions repository.
 
-EXAMPLE 2. Extract a subtree using commit, merge and pull
----------------------------------------------------------
+EXAMPLE 2. Extract a subtree using 'commit', 'merge' and 'pull'
+---------------------------------------------------------------
 Let's use the repository for the git source code as an example.
 First, get your own copy of the git.git repository:
 
@@ -284,9 +278,9 @@ the upstream.  You could do this:
 0a8f4f0 to the current version, including 0a8f4f0 itself.")
 
 If gitweb had originally been merged using 'git subtree add' (or
-a previous split had already been done with --rejoin specified)
+a previous split had already been done with '--rejoin' specified)
 then you can do all your splits without having to remember any
-weird commit ids:
+weird commit IDs:
 
 	$ git subtree split --prefix=gitweb --annotate='(split) ' --rejoin \
 		--branch gitweb-latest2
@@ -321,8 +315,8 @@ the standard gitweb:
 
 	git log gitweb-latest..$(git subtree split --prefix=gitweb)
 
-EXAMPLE 3. Extract a subtree using branch
------------------------------------------
+EXAMPLE 3. Extract a subtree using a branch
+-------------------------------------------
 Suppose you have a source directory with many files and
 subdirectories, and you want to extract the lib directory to its own
 git project. Here's a short way to do it:
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 27/30] subtree: allow --squash to be used with --rejoin
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (25 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 26/30] subtree: give the docs a once-over Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 19:58     ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 28/30] subtree: allow 'split' flags to be passed to 'push' Luke Shumaker
                     ` (3 subsequent siblings)
  30 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Besides being a genuinely useful thing to do, this also just makes sense
and harmonizes which flags may be used when.  `git subtree split
--rejoin` amounts to "automatically go ahead and do a `git subtree
merge` after doing the main `git subtree split`", so it's weird and
arbitrary that you can't pass `--squash` to `git subtree split --rejoin`
like you can `git subtree merge`.  It's weird that `git subtree split
--rejoin` inherits `git subtree merge`'s `--message` but not `--squash`.

Reconcile the situation by just having `split --rejoin` actually just
call `merge` internally (or call `add` instead, as appropriate), so it
can get access to the full `merge` behavior, including `--squash`.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - In the added tests, use `test_must_fail` instead of `!`, as
   appropriate.

 contrib/subtree/git-subtree.sh     | 33 ++++++++++++++++++++++------
 contrib/subtree/git-subtree.txt    | 27 ++++++++++-------------
 contrib/subtree/t/t7900-subtree.sh | 35 ++++++++++++++++++++++++++++++
 3 files changed, 72 insertions(+), 23 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 3bffddf277..74b02c69b3 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -33,15 +33,15 @@ h,help        show the help
 q             quiet
 d             show debug messages
 P,prefix=     the name of the subdir to split out
-m,message=    use the given message as the commit message for the merge commit
  options for 'split'
 annotate=     add a prefix to commit message of new commits
 b,branch=     create a new branch from the split subtree
 ignore-joins  ignore prior --rejoin commits
 onto=         try connecting new tree to an existing one
 rejoin        merge the new branch back into HEAD
- options for 'add' and 'merge' (also: 'pull')
+ options for 'add' and 'merge' (also: 'pull' and 'split --rejoin')
 squash        merge subtree changes as a single commit
+m,message=    use the given message as the commit message for the merge commit
 "
 
 arg_debug=
@@ -453,6 +453,13 @@ add_msg () {
 	else
 		commit_message="Add '$dir/' from commit '$latest_new'"
 	fi
+	if test -n "$arg_split_rejoin"
+	then
+		# If this is from a --rejoin, then rejoin_msg has
+		# already inserted the `git-subtree-xxx:` tags
+		echo "$commit_message"
+		return
+	fi
 	cat <<-EOF
 		$commit_message
 
@@ -775,7 +782,12 @@ cmd_add_commit () {
 	rev=$(git rev-parse --verify "$1^{commit}") || exit $?
 
 	debug "Adding $dir as '$rev'..."
-	git read-tree --prefix="$dir" $rev || exit $?
+	if test -z "$arg_split_rejoin"
+	then
+		# Only bother doing this if this is a genuine 'add',
+		# not a synthetic 'add' from '--rejoin'.
+		git read-tree --prefix="$dir" $rev || exit $?
+	fi
 	git checkout -- "$dir" || exit $?
 	tree=$(git write-tree) || exit $?
 
@@ -815,6 +827,11 @@ cmd_split () {
 		die "You must provide exactly one revision.  Got: '$*'"
 	fi
 
+	if test -n "$arg_split_rejoin"
+	then
+		ensure_clean
+	fi
+
 	debug "Splitting $dir..."
 	cache_setup || exit $?
 
@@ -857,10 +874,12 @@ cmd_split () {
 	then
 		debug "Merging split branch into HEAD..."
 		latest_old=$(cache_get latest_old) || exit $?
-		git merge -s ours \
-			--allow-unrelated-histories \
-			-m "$(rejoin_msg "$dir" "$latest_old" "$latest_new")" \
-			"$latest_new" >&2 || exit $?
+		arg_addmerge_message="$(rejoin_msg "$dir" "$latest_old" "$latest_new")" || exit $?
+		if test -z "$(find_latest_squash "$dir")"; then
+			cmd_add "$latest_new" >&2 || exit $?
+		else
+			cmd_merge "$latest_new" >&2 || exit $?
+		fi
 	fi
 	if test -n "$arg_split_branch"
 	then
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index 7baac17260..743e1bbc9e 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -109,9 +109,6 @@ settings passed to 'split' (such as '--annotate') are the same.
 Because of this, if you add new commits and then re-split, the new
 commits will be attached as commits on top of the history you
 generated last time, so 'git merge' and friends will work as expected.
-+
-Note that if you use '--squash' when you merge, you should usually not
-just '--rejoin' when you split.
 
 pull <repository> <remote-ref>::
 	Exactly like 'merge', but parallels 'git pull' in that
@@ -124,8 +121,8 @@ push <repository> <remote-ref>::
 	<remote-ref>.  This can be used to push your subtree to
 	different branches of the remote repository.
 
-OPTIONS
--------
+OPTIONS FOR ALL COMMANDS
+------------------------
 -q::
 --quiet::
 	Suppress unnecessary output messages on stderr.
@@ -140,15 +137,11 @@ OPTIONS
 	want to manipulate.  This option is mandatory
 	for all commands.
 
--m <message>::
---message=<message>::
-	This option is only valid for 'add', 'merge', 'pull', and 'split --rejoin'.
-	Specify <message> as the commit message for the merge commit.
-
-OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull')
---------------------------------------------
+OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull' AND 'split --rejoin')
+-----------------------------------------------------------------
 These options for 'add' and 'merge' may also be given to 'pull' (which
-wraps 'merge').
+wraps 'merge') and 'split --rejoin' (which wraps either 'add' or
+'merge' as appropriate).
 
 --squash::
 	Instead of merging the entire history from the subtree project, produce
@@ -176,6 +169,9 @@ Whether or not you use '--squash', changes made in your local repository
 remain intact and can be later split and send upstream to the
 subproject.
 
+-m <message>::
+--message=<message>::
+	Specify <message> as the commit message for the merge commit.
 
 OPTIONS FOR 'split'
 -------------------
@@ -229,9 +225,8 @@ Unfortunately, using this option results in 'git log' showing an extra
 copy of every new commit that was created (the original, and the
 synthetic one).
 +
-If you do all your merges with '--squash', don't use '--rejoin' when you
-split, because you don't want the subproject's history to be part of
-your project anyway.
+If you do all your merges with '--squash', make sure you also use
+'--squash' when you 'split --rejoin'.
 
 
 EXAMPLE 1. 'add' command
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index ce6861c22d..6f1529935f 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -324,6 +324,41 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
 	)
 '
 
+test_expect_success 'split "sub dir"/ with --rejoin and --squash' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" --squash FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git subtree pull --prefix="sub dir" --squash ./"sub proj" HEAD &&
+		MAIN=$(git rev-parse --verify HEAD) &&
+		SUB=$(git -C "sub proj" rev-parse --verify HEAD) &&
+
+		SPLIT=$(git subtree split --prefix="sub dir" --annotate="*" --rejoin --squash) &&
+
+		test_must_fail git merge-base --is-ancestor $SUB HEAD &&
+		test_must_fail git merge-base --is-ancestor $SPLIT HEAD &&
+		git rev-list HEAD ^$MAIN >commit-list &&
+		test_line_count = 2 commit-list &&
+		test "$(git rev-parse --verify HEAD:)"           = "$(git rev-parse --verify $MAIN:)" &&
+		test "$(git rev-parse --verify HEAD:"sub dir")"  = "$(git rev-parse --verify $SPLIT:)" &&
+		test "$(git rev-parse --verify HEAD^1)"          = $MAIN &&
+		test "$(git rev-parse --verify HEAD^2)"         != $SPLIT &&
+		test "$(git rev-parse --verify HEAD^2:)"         = "$(git rev-parse --verify $SPLIT:)" &&
+		test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$SPLIT'\''"
+	)
+'
+
 test_expect_success 'split "sub dir"/ with --branch' '
 	subtree_test_create_repo "$test_count" &&
 	subtree_test_create_repo "$test_count/sub proj" &&
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 28/30] subtree: allow 'split' flags to be passed to 'push'
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (26 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 27/30] subtree: allow --squash to be used with --rejoin Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 29/30] subtree: push: allow specifying a local rev other than HEAD Luke Shumaker
                     ` (2 subsequent siblings)
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

'push' does a 'split' internally, but it doesn't pass flags through to the
'split'.  This is silly, if you need to pass flags to 'split', then it
means that you can't use 'push'!

So, have 'push' accept 'split' flags, and pass them through to 'split'.

Add tests for this by copying split's tests with minimal modification.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - In the added tests, use `test_must_fail` instead of `!`, as
   appropriate.

 contrib/subtree/git-subtree.sh     |   6 +-
 contrib/subtree/git-subtree.txt    |  15 +-
 contrib/subtree/t/t7900-subtree.sh | 214 ++++++++++++++++++++++++++++-
 3 files changed, 223 insertions(+), 12 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 74b02c69b3..1e5ac82f9b 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -33,13 +33,13 @@ h,help        show the help
 q             quiet
 d             show debug messages
 P,prefix=     the name of the subdir to split out
- options for 'split'
+ options for 'split' (also: 'push')
 annotate=     add a prefix to commit message of new commits
 b,branch=     create a new branch from the split subtree
 ignore-joins  ignore prior --rejoin commits
 onto=         try connecting new tree to an existing one
 rejoin        merge the new branch back into HEAD
- options for 'add' and 'merge' (also: 'pull' and 'split --rejoin')
+ options for 'add' and 'merge' (also: 'pull', 'split --rejoin', and 'push --rejoin')
 squash        merge subtree changes as a single commit
 m,message=    use the given message as the commit message for the merge commit
 "
@@ -962,7 +962,7 @@ cmd_push () {
 		repository=$1
 		refspec=$2
 		echo "git push using: " "$repository" "$refspec"
-		localrev=$(git subtree split --prefix="$arg_prefix") || die
+		localrev=$(cmd_split) || die
 		git push "$repository" "$localrev":"refs/heads/$refspec"
 	else
 		die "'$dir' must already exist. Try 'git subtree add'."
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index 743e1bbc9e..1282aa705f 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -137,11 +137,11 @@ OPTIONS FOR ALL COMMANDS
 	want to manipulate.  This option is mandatory
 	for all commands.
 
-OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull' AND 'split --rejoin')
------------------------------------------------------------------
+OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull', 'split --rejoin', AND 'push --rejoin')
+-----------------------------------------------------------------------------------
 These options for 'add' and 'merge' may also be given to 'pull' (which
-wraps 'merge') and 'split --rejoin' (which wraps either 'add' or
-'merge' as appropriate).
+wraps 'merge'), 'split --rejoin' (which wraps either 'add' or 'merge'
+as appropriate), and 'push --rejoin' (which wraps 'split --rejoin').
 
 --squash::
 	Instead of merging the entire history from the subtree project, produce
@@ -173,9 +173,10 @@ subproject.
 --message=<message>::
 	Specify <message> as the commit message for the merge commit.
 
-OPTIONS FOR 'split'
--------------------
-These options are only valid for 'split'.
+OPTIONS FOR 'split' (ALSO: 'push')
+----------------------------------
+These options for 'split' may also be given to 'push' (which wraps
+'split').
 
 --annotate=<annotation>::
 	When generating synthetic history, add <annotation> as a prefix to each
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 6f1529935f..8bc0e488aa 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -5,8 +5,8 @@
 #
 test_description='Basic porcelain support for subtrees
 
-This test verifies the basic operation of the add, pull, merge
-and split subcommands of git subtree.
+This test verifies the basic operation of the add, merge, split, pull,
+and push subcommands of git subtree.
 '
 
 TEST_DIRECTORY=$(pwd)/../../../t
@@ -589,6 +589,216 @@ test_expect_success 'push basic operation' '
 	)
 '
 
+test_expect_success 'push sub dir/ with --rejoin' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+		git subtree push --prefix="sub dir" --annotate="*" --rejoin ./"sub proj" from-mainline &&
+		test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''" &&
+		test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'push sub dir/ with --rejoin from scratch' '
+	subtree_test_create_repo "$test_count" &&
+	test_create_commit "$test_count" main1 &&
+	(
+		cd "$test_count" &&
+		mkdir "sub dir" &&
+		echo file >"sub dir"/file &&
+		git add "sub dir/file" &&
+		git commit -m"sub dir file" &&
+		split_hash=$(git subtree split --prefix="sub dir" --rejoin) &&
+		git init --bare "sub proj.git" &&
+		git subtree push --prefix="sub dir" --rejoin ./"sub proj.git" from-mainline &&
+		test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''" &&
+		test "$split_hash" = "$(git -C "sub proj.git" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'push sub dir/ with --rejoin and --message' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		git subtree push --prefix="sub dir" --message="Split & rejoin" --annotate="*" --rejoin ./"sub proj" from-mainline &&
+		test "$(last_commit_subject)" = "Split & rejoin" &&
+		split_hash="$(git rev-parse --verify HEAD^2)" &&
+		test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'push "sub dir"/ with --rejoin and --squash' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" --squash FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git subtree pull --prefix="sub dir" --squash ./"sub proj" HEAD &&
+		MAIN=$(git rev-parse --verify HEAD) &&
+		SUB=$(git -C "sub proj" rev-parse --verify HEAD) &&
+
+		SPLIT=$(git subtree split --prefix="sub dir" --annotate="*") &&
+		git subtree push --prefix="sub dir" --annotate="*" --rejoin --squash ./"sub proj" from-mainline &&
+
+		test_must_fail git merge-base --is-ancestor $SUB HEAD &&
+		test_must_fail git merge-base --is-ancestor $SPLIT HEAD &&
+		git rev-list HEAD ^$MAIN >commit-list &&
+		test_line_count = 2 commit-list &&
+		test "$(git rev-parse --verify HEAD:)"           = "$(git rev-parse --verify $MAIN:)" &&
+		test "$(git rev-parse --verify HEAD:"sub dir")"  = "$(git rev-parse --verify $SPLIT:)" &&
+		test "$(git rev-parse --verify HEAD^1)"          = $MAIN &&
+		test "$(git rev-parse --verify HEAD^2)"         != $SPLIT &&
+		test "$(git rev-parse --verify HEAD^2:)"         = "$(git rev-parse --verify $SPLIT:)" &&
+		test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$SPLIT'\''" &&
+		test "$SPLIT" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'push "sub dir"/ with --branch' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+		git subtree push --prefix="sub dir" --annotate="*" --branch subproj-br ./"sub proj" from-mainline &&
+		test "$(git rev-parse subproj-br)" = "$split_hash" &&
+		test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'check hash of push' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+		git subtree push --prefix="sub dir" --annotate="*" --branch subproj-br ./"sub proj" from-mainline &&
+		test "$(git rev-parse subproj-br)" = "$split_hash" &&
+		# Check hash of split
+		new_hash=$(git rev-parse subproj-br^2) &&
+		(
+			cd ./"sub proj" &&
+			subdir_hash=$(git rev-parse HEAD) &&
+			test "$new_hash" = "$subdir_hash"
+		) &&
+		test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'push "sub dir"/ with --branch for an existing branch' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git branch subproj-br FETCH_HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+		git subtree push --prefix="sub dir" --annotate="*" --branch subproj-br ./"sub proj" from-mainline &&
+		test "$(git rev-parse subproj-br)" = "$split_hash" &&
+		test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'push "sub dir"/ with --branch for an incompatible branch' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git branch init HEAD &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		test_must_fail git subtree push --prefix="sub dir" --branch init "./sub proj" from-mainline
+	)
+'
+
 #
 # Validity checking
 #
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 29/30] subtree: push: allow specifying a local rev other than HEAD
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (27 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 28/30] subtree: allow 'split' flags to be passed to 'push' Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-26 17:45   ` [PATCH v2 30/30] subtree: be stricter about validating flags Luke Shumaker
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

'git subtree split' lets you specify a rev other than HEAD.  'git push'
lets you specify a mapping between a local thing and a remot ref.  So
smash those together, and have 'git subtree push' let you specify which
local thing to run split on and push the result of that split to the
remote ref.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh     | 24 +++++++++++++++++-------
 contrib/subtree/git-subtree.txt    | 14 ++++++++------
 contrib/subtree/t/t7900-subtree.sh | 22 ++++++++++++++++++++++
 3 files changed, 47 insertions(+), 13 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 1e5ac82f9b..678dd1dc19 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -27,7 +27,7 @@ git subtree add   --prefix=<prefix> <repository> <ref>
 git subtree merge --prefix=<prefix> <commit>
 git subtree split --prefix=<prefix> [<commit>]
 git subtree pull  --prefix=<prefix> <repository> <ref>
-git subtree push  --prefix=<prefix> <repository> <ref>
+git subtree push  --prefix=<prefix> <repository> <refspec>
 --
 h,help        show the help
 q             quiet
@@ -950,20 +950,30 @@ cmd_pull () {
 	cmd_merge FETCH_HEAD
 }
 
-# Usage: cmd_push REPOSITORY REMOTEREF
+# Usage: cmd_push REPOSITORY [+][LOCALREV:]REMOTEREF
 cmd_push () {
 	if test $# -ne 2
 	then
-		die "You must provide <repository> <ref>"
+		die "You must provide <repository> <refspec>"
 	fi
-	ensure_valid_ref_format "$2"
 	if test -e "$dir"
 	then
 		repository=$1
-		refspec=$2
+		refspec=${2#+}
+		remoteref=${refspec#*:}
+		if test "$remoteref" = "$refspec"
+		then
+			localrevname_presplit=HEAD
+		else
+			localrevname_presplit=${refspec%%:*}
+		fi
+		ensure_valid_ref_format "$remoteref"
+		localrev_presplit=$(git rev-parse -q --verify "$localrevname_presplit^{commit}") ||
+			die "'$localrevname_presplit' does not refer to a commit"
+
 		echo "git push using: " "$repository" "$refspec"
-		localrev=$(cmd_split) || die
-		git push "$repository" "$localrev":"refs/heads/$refspec"
+		localrev=$(cmd_split "$localrev_presplit") || die
+		git push "$repository" "$localrev":"refs/heads/$remoteref"
 	else
 		die "'$dir' must already exist. Try 'git subtree add'."
 	fi
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index 1282aa705f..559b64aa96 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -16,7 +16,7 @@ SYNOPSIS
 
 [verse]
 'git subtree' [<options>] -P <prefix> pull <repository> <remote-ref>
-'git subtree' [<options>] -P <prefix> push <repository> <remote-ref>
+'git subtree' [<options>] -P <prefix> push <repository> <refspec>
 
 DESCRIPTION
 -----------
@@ -115,11 +115,13 @@ pull <repository> <remote-ref>::
 	it fetches the given ref from the specified remote
 	repository.
 
-push <repository> <remote-ref>::
-	Does a 'split' using the <prefix> subtree of HEAD and then
-	does a 'git push' to push the result to the <repository> and
-	<remote-ref>.  This can be used to push your subtree to
-	different branches of the remote repository.
+push <repository> [+][<local-commit>:]<remote-ref>::
+	Does a 'split' using the <prefix> subtree of <local-commit>
+	and then does a 'git push' to push the result to the
+	<repository> and <remote-ref>.  This can be used to push your
+	subtree to different branches of the remote repository.  Just
+	as with 'split', if no <local-commit> is given, then HEAD is
+	used.  The optional leading '+' is ignored.
 
 OPTIONS FOR ALL COMMANDS
 ------------------------
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 8bc0e488aa..8a3530305e 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -799,6 +799,28 @@ test_expect_success 'push "sub dir"/ with --branch for an incompatible branch' '
 	)
 '
 
+test_expect_success 'push "sub dir"/ with a local rev' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		bad_tree=$(git rev-parse --verify HEAD:"sub dir") &&
+		good_tree=$(git rev-parse --verify HEAD^:"sub dir") &&
+		git subtree push --prefix="sub dir" --annotate="*" ./"sub proj" HEAD^:from-mainline &&
+		split_tree=$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline:) &&
+		test "$split_tree" = "$good_tree"
+	)
+'
+
 #
 # Validity checking
 #
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v2 30/30] subtree: be stricter about validating flags
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (28 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 29/30] subtree: push: allow specifying a local rev other than HEAD Luke Shumaker
@ 2021-04-26 17:45   ` Luke Shumaker
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
  30 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 17:45 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Don't silently ignore a flag that's invalid for a given subcommand.  The
user expected it to do something; we should tell the user that they are
mistaken, instead of surprising the user.

It could be argued that this change might break existing users.  I'd
argue that those existing users are already broken, and they just don't
know it.  Let them know that they're broken.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh     |  89 ++++++++++++++++-------
 contrib/subtree/t/t7900-subtree.sh | 111 +++++++++++++++++++++++++++++
 2 files changed, 175 insertions(+), 25 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 678dd1dc19..1fd3c287dd 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -44,17 +44,6 @@ squash        merge subtree changes as a single commit
 m,message=    use the given message as the commit message for the merge commit
 "
 
-arg_debug=
-arg_command=
-arg_prefix=
-arg_split_branch=
-arg_split_onto=
-arg_split_rejoin=
-arg_split_ignore_joins=
-arg_split_annotate=
-arg_addmerge_squash=
-arg_addmerge_message=
-
 indent=0
 
 # Usage: debug [MSG...]
@@ -106,10 +95,61 @@ main () {
 	then
 		set -- -h
 	fi
-	eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
+	set_args="$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
+	eval "$set_args"
 	. git-sh-setup
 	require_work_tree
 
+	# First figure out the command and whether we use --rejoin, so
+	# that we can provide more helpful validation when we do the
+	# "real" flag parsing.
+	arg_split_rejoin=
+	allow_split=
+	allow_addmerge=
+	while test $# -gt 0
+	do
+		opt="$1"
+		shift
+		case "$opt" in
+			--annotate|-b|-P|-m|--onto)
+				shift
+				;;
+			--rejoin)
+				arg_split_rejoin=1
+				;;
+			--no-rejoin)
+				arg_split_rejoin=
+				;;
+			--)
+				break
+				;;
+		esac
+	done
+	arg_command=$1
+	case "$arg_command" in
+	add|merge|pull)
+		allow_addmerge=1
+		;;
+	split|push)
+		allow_split=1
+		allow_addmerge=$arg_split_rejoin
+		;;
+	*)
+		die "Unknown command '$arg_command'"
+		;;
+	esac
+	# Reset the arguments array for "real" flag parsing.
+	eval "$set_args"
+
+	# Begin "real" flag parsing.
+	arg_debug=
+	arg_prefix=
+	arg_split_branch=
+	arg_split_onto=
+	arg_split_ignore_joins=
+	arg_split_annotate=
+	arg_addmerge_squash=
+	arg_addmerge_message=
 	while test $# -gt 0
 	do
 		opt="$1"
@@ -123,13 +163,16 @@ main () {
 			arg_debug=1
 			;;
 		--annotate)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_annotate="$1"
 			shift
 			;;
 		--no-annotate)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_annotate=
 			;;
 		-b)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_branch="$1"
 			shift
 			;;
@@ -138,6 +181,7 @@ main () {
 			shift
 			;;
 		-m)
+			test -n "$allow_addmerge" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_addmerge_message="$1"
 			shift
 			;;
@@ -145,28 +189,34 @@ main () {
 			arg_prefix=
 			;;
 		--onto)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_onto="$1"
 			shift
 			;;
 		--no-onto)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_onto=
 			;;
 		--rejoin)
-			arg_split_rejoin=1
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			;;
 		--no-rejoin)
-			arg_split_rejoin=
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			;;
 		--ignore-joins)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_ignore_joins=1
 			;;
 		--no-ignore-joins)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_ignore_joins=
 			;;
 		--squash)
+			test -n "$allow_addmerge" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_addmerge_squash=1
 			;;
 		--no-squash)
+			test -n "$allow_addmerge" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_addmerge_squash=
 			;;
 		--)
@@ -177,19 +227,8 @@ main () {
 			;;
 		esac
 	done
-
-	arg_command="$1"
 	shift
 
-	case "$arg_command" in
-	add|merge|pull|split|push)
-		:
-		;;
-	*)
-		die "Unknown command '$arg_command'"
-		;;
-	esac
-
 	if test -z "$arg_prefix"
 	then
 		die "You must provide the --prefix option."
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 8a3530305e..6348c13c5c 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -33,6 +33,12 @@ test_create_commit () (
 	git commit -m "$commit" || error "Could not commit"
 )
 
+test_wrong_flag() {
+	test_must_fail "$@" >out 2>err &&
+	test_must_be_empty out &&
+	grep "flag does not make sense with" err
+}
+
 last_commit_subject () {
 	git log --pretty=format:%s -1
 }
@@ -72,6 +78,22 @@ test_expect_success 'no pull from non-existent subtree' '
 	)
 '
 
+test_expect_success 'add rejects flags for split' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		test_wrong_flag git subtree add --prefix="sub dir" --annotate=foo FETCH_HEAD &&
+		test_wrong_flag git subtree add --prefix="sub dir" --branch=foo FETCH_HEAD &&
+		test_wrong_flag git subtree add --prefix="sub dir" --ignore-joins FETCH_HEAD &&
+		test_wrong_flag git subtree add --prefix="sub dir" --onto=foo FETCH_HEAD &&
+		test_wrong_flag git subtree add --prefix="sub dir" --rejoin FETCH_HEAD
+	)
+'
+
 test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
 	subtree_test_create_repo "$test_count" &&
 	subtree_test_create_repo "$test_count/sub proj" &&
@@ -128,6 +150,28 @@ test_expect_success 'add subproj as subtree into sub dir/ with --squash and --pr
 # Tests for 'git subtree merge'
 #
 
+test_expect_success 'merge rejects flags for split' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		test_wrong_flag git subtree merge --prefix="sub dir" --annotate=foo FETCH_HEAD &&
+		test_wrong_flag git subtree merge --prefix="sub dir" --branch=foo FETCH_HEAD &&
+		test_wrong_flag git subtree merge --prefix="sub dir" --ignore-joins FETCH_HEAD &&
+		test_wrong_flag git subtree merge --prefix="sub dir" --onto=foo FETCH_HEAD &&
+		test_wrong_flag git subtree merge --prefix="sub dir" --rejoin FETCH_HEAD
+	)
+'
+
 test_expect_success 'merge new subproj history into sub dir/ with --prefix' '
 	subtree_test_create_repo "$test_count" &&
 	subtree_test_create_repo "$test_count/sub proj" &&
@@ -262,6 +306,30 @@ test_expect_success 'split requires path given by option --prefix must exist' '
 	)
 '
 
+test_expect_success 'split rejects flags for add' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+		test_wrong_flag git subtree split --prefix="sub dir" --squash &&
+		test_wrong_flag git subtree split --prefix="sub dir" --message=foo
+	)
+'
+
 test_expect_success 'split sub dir/ with --rejoin' '
 	subtree_test_create_repo "$test_count" &&
 	subtree_test_create_repo "$test_count/sub proj" &&
@@ -521,6 +589,26 @@ test_expect_success 'pull basic operation' '
 	)
 '
 
+test_expect_success 'pull rejects flags for split' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	(
+		test_must_fail git subtree pull --prefix="sub dir" --annotate=foo ./"sub proj" HEAD &&
+		test_must_fail git subtree pull --prefix="sub dir" --branch=foo ./"sub proj" HEAD &&
+		test_must_fail git subtree pull --prefix="sub dir" --ignore-joins ./"sub proj" HEAD &&
+		test_must_fail git subtree pull --prefix="sub dir" --onto=foo ./"sub proj" HEAD &&
+		test_must_fail git subtree pull --prefix="sub dir" --rejoin ./"sub proj" HEAD
+	)
+'
+
 #
 # Tests for 'git subtree push'
 #
@@ -563,6 +651,29 @@ test_expect_success 'push requires path given by option --prefix must exist' '
 	)
 '
 
+test_expect_success 'push rejects flags for add' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		test_wrong_flag git subtree split --prefix="sub dir" --squash ./"sub proj" from-mainline &&
+		test_wrong_flag git subtree split --prefix="sub dir" --message=foo ./"sub proj" from-mainline
+	)
+'
+
 test_expect_success 'push basic operation' '
 	subtree_test_create_repo "$test_count" &&
 	subtree_test_create_repo "$test_count/sub proj" &&
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* Re: [PATCH v2 04/30] subtree: t7900: use consistent formatting
  2021-04-26 17:44   ` [PATCH v2 04/30] subtree: t7900: use consistent formatting Luke Shumaker
@ 2021-04-26 19:57     ` Luke Shumaker
  0 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 19:57 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

On Mon, 26 Apr 2021 11:44:59 -0600,
Luke Shumaker wrote:
> @@ -50,15 +46,17 @@ undo()
>  # The original set of commits changed only one file each.
>  # A multi-file change would imply that we pruned commits
>  # too aggressively.
> -join_commits()
> -{
> +join_commits () {
>  	commit=
>  	all=
>  	while read x y; do
> -		if [ -z "$x" ]; then
> +		if test -z "$x"
> +		then
>  			continue
> -		elif [ "$x" = "commit:" ]; then
> -			if [ -n "$commit" ]; then
> +		elif test "$x" = "commit:"
> +		then
> +			if test -n "$commit"
> +			then
>  				echo "$commit $all"
>  				all=
>  			fi

Whoops, I should have changed those 1-line `while ...; do`'s, in
addition to the 1-line `if ...; then`'s.

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH v2 27/30] subtree: allow --squash to be used with --rejoin
  2021-04-26 17:45   ` [PATCH v2 27/30] subtree: allow --squash to be used with --rejoin Luke Shumaker
@ 2021-04-26 19:58     ` Luke Shumaker
  0 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 19:58 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

On Mon, 26 Apr 2021 11:45:22 -0600,
Luke Shumaker wrote:
> @@ -857,10 +874,12 @@ cmd_split () {
>  	then
>  		debug "Merging split branch into HEAD..."
>  		latest_old=$(cache_get latest_old) || exit $?
> -		git merge -s ours \
> -			--allow-unrelated-histories \
> -			-m "$(rejoin_msg "$dir" "$latest_old" "$latest_new")" \
> -			"$latest_new" >&2 || exit $?
> +		arg_addmerge_message="$(rejoin_msg "$dir" "$latest_old" "$latest_new")" || exit $?
> +		if test -z "$(find_latest_squash "$dir")"; then
> +			cmd_add "$latest_new" >&2 || exit $?
> +		else
> +			cmd_merge "$latest_new" >&2 || exit $?
> +		fi
>  	fi
>  	if test -n "$arg_split_branch"
>  	then

Whoops, that `if ...; then` should put the `then` on its own line.

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH v2 19/30] subtree: Don't fuss with PATH
  2021-04-26 17:45   ` [PATCH v2 19/30] subtree: Don't fuss with PATH Luke Shumaker
@ 2021-04-26 23:16     ` Luke Shumaker
  0 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-26 23:16 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

On Mon, 26 Apr 2021 11:45:14 -0600,
Luke Shumaker wrote:
> Subject: [PATCH v2 19/30] subtree: Don't fuss with PATH

Whoops, I shouldn't have capitalized "Don't".

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 04/30] subtree: t7900: use consistent formatting
  2021-04-23 21:51   ` Eric Sunshine
  2021-04-23 22:54     ` Luke Shumaker
@ 2021-04-27  7:17     ` Junio C Hamano
  2021-04-27 20:41       ` Luke Shumaker
  1 sibling, 1 reply; 144+ messages in thread
From: Junio C Hamano @ 2021-04-27  7:17 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Luke Shumaker, Git List, Avery Pennarun, Charles Bailey,
	Danny Lin, David A . Greene, David Aguilar, Jakub Suder,
	James Denholm, Jeff King, Jonathan Nieder,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

Eric Sunshine <sunshine@sunshineco.com> writes:

>> +check_equal () {
>>         test_debug 'echo'
>>         test_debug "echo \"check a:\" \"{$1}\""
>>         test_debug "echo \"      b:\" \"{$2}\""
>> -       if [ "$1" = "$2" ]; then
>> +       if [ "$1" = "$2" ]
>> +       then
>
> We prefer `test` over `[`, so it might make sense to update that, as
> well, along with these other style cleanups.

If I were working on this, I wouldn't bother.

As far as I am concerned, contrib/subtree has always been treated as
a borrowed code [*] that is written in a dialect of shell that is
different from what our scripts are written in, and there are too
many style differences (I wouldn't call them violations---nobody has
expected the code there to follow our style, or attempted to enforce
our style there) to bother coercing.

If Luke is volunteering to take over its maintainership, it would be
appreciated by its users.  It has been in the "abandonware" status
for too long.


[Footnote]

* ... as opposed to a properly maintained part of the git-core
  proper.

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 00/30] subtree: clean up, improve UX
  2021-04-23 20:12 ` [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
  2021-04-26  7:55   ` =?utf-8?B?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason
@ 2021-04-27  7:27   ` Junio C Hamano
  1 sibling, 0 replies; 144+ messages in thread
From: Junio C Hamano @ 2021-04-27  7:27 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: git, Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Nguyễn Thái Ngọc Duy,
	Roger L Strain, Techlive Zheng, Luke Shumaker

Luke Shumaker <lukeshu@lukeshu.com> writes:

> On Fri, 23 Apr 2021 13:42:00 -0600,
> Luke Shumaker wrote:
>>                                                  I promise that
>> there's more work coming on top of it (we've discovered lots of ways
>> to break the "subtree split" algorithm, and come up with fixes for
>> most of them).
>
> Follow-up question: If in that work I changed the shebang from
> "#!/bin/sh" to "#!/usr/bin/env bash" and started using Bash arrays,
> would that be so bad?  Would that be land-able?

I'd rather see "git subtree" tool taken out of my tree and flourish
as a standalone project of its own.

Over its long history, from time to time people stepped in only to
scratch their own itch and then went away.  Without having continued
presense of an area expert (or two) who can give consistent guidance
to the tool's evolution, I feel that Git project itself failed to
give sufficient service to users of "git subtree".

As I won't be that area expert, and we do not seem to be growing
such an area expert who can be responsible for the tool in the long
haul, it probably is a disservice to its users to keep it in my tree
and pretend that it is maintained to the same degree as the rest of
Git.

If those who are interested and/or have stake in the "git subtree"
tool can unite and take its development in their hands, with their
own style, that might be better for the health of the "git subtree"
tool in the long run.

Thanks.




^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 04/30] subtree: t7900: use consistent formatting
  2021-04-27  7:17     ` Junio C Hamano
@ 2021-04-27 20:41       ` Luke Shumaker
  2021-04-28  4:33         ` Junio C Hamano
  0 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 20:41 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Eric Sunshine, Luke Shumaker, Git List, Avery Pennarun,
	Charles Bailey, Danny Lin, David A . Greene, David Aguilar,
	Jakub Suder, James Denholm, Jeff King, Jonathan Nieder,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

On Tue, 27 Apr 2021 01:17:38 -0600,
Junio C Hamano wrote:
> 
> Eric Sunshine <sunshine@sunshineco.com> writes:
> 
> >> +check_equal () {
> >>         test_debug 'echo'
> >>         test_debug "echo \"check a:\" \"{$1}\""
> >>         test_debug "echo \"      b:\" \"{$2}\""
> >> -       if [ "$1" = "$2" ]; then
> >> +       if [ "$1" = "$2" ]
> >> +       then
> >
> > We prefer `test` over `[`, so it might make sense to update that, as
> > well, along with these other style cleanups.
> 
> If I were working on this, I wouldn't bother.

In this case, it's not just about consistency with git-core, it's
about consistency within contrib/subtree; there were just 2 or 3
places where it used `[` instead of `test`.

> If Luke is volunteering to take over its maintainership, it would be
> appreciated by its users.  It has been in the "abandonware" status
> for too long.

I think I am volunteering.

We have been using git-subtree increasingly heavily at Ambassador Labs
(née Datawire) for about 2 years now, and I don't see that changing.
What I'm doing now is trying to get >2 years of accumulated patches in
to a submittable state (a lot of the patches were bad; for instance on
my main branch `git subtree add` is broken, but that's fine, because
you don't use `add` all the time like you do `split` or `merge`, but
that's something I need to fix before submitting it).  Assuming that
we're going to continue being heavy users of it, and are going to
continue to patch issues with it, I'd rather let that live upstream
rather than telling all of my coworkers to get it from
<https://github.com/LukeShu/git>.

With a recent change in project scheduling, I anticipate that I'll
have bandwidth to be able to handle that.  (It's what's giving me
adequate time to work through this pile of existing patches, anyway.)

What does being a maintainer consist of?  Are there standups that I
should join?

> As far as I am concerned, contrib/subtree has always been treated as
> a borrowed code [*] that is written in a dialect of shell that is
> different from what our scripts are written in, and there are too
> many style differences (I wouldn't call them violations---nobody has
> expected the code there to follow our style, or attempted to enforce
> our style there) to bother coercing.
> 
> [Footnote]
> 
> * ... as opposed to a properly maintained part of the git-core
>   proper.

Elsewhere in the thread, you suggested that subtree be taken out of
git.git, and live as a standalone project.

I'm not entirely opposed to that, but

 1. I'm not sure how whoever picks it up (me) establishes their
    git-subtree as the "real" subtree (get a blessing from Avery?).

 2. I think a lot of the reason why more people don't use git-subtree
    is that the core 'split' operation doesn't quite work reliably
    (and also it can be quite slow), and so it doesn't get
    recommended.  I would like nothing more than to improve the
    'split' reliability to where it does start to gain adoption, to
    where we can think about it graduating from contrib/ to git-core.

 3. Many systems (Arch Linux and macOS, at least) give users
    git-subtree as part of the stock Git install.  If I'm interested
    in growing git-subtree adoption, I'd be a fool to give that up :)

On the other hand, I think that in the long-ish term git-subtree wants
to be rewritten in a better-suited language.  My personal inclination
would be Go, but if I ever want it to graduate to git-core, it'd have
to be C, huh?

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* [PATCH v3 00/30] subtree: clean up, improve UX
  2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
                     ` (29 preceding siblings ...)
  2021-04-26 17:45   ` [PATCH v2 30/30] subtree: be stricter about validating flags Luke Shumaker
@ 2021-04-27 21:17   ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 01/30] .gitignore: Ignore /git-subtree Luke Shumaker
                       ` (29 more replies)
  30 siblings, 30 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

The diff between v1 and v2 is largely stylistic.  The only
non-stylistic changes are fixing the tests to use `test_must_fail`
instead of `!`, and re-thinking the commit about fussing with PATH.

The diff between v2 and v3 contains a few stylistic changes, but the
meat of it is that it fixes a bug with `--squash` and `--rejoin` being
used together, and that it fixes a mistake in the man page.

Ostensibly, this patch set is about improving various aspects of `git
subtree`'s user interface (and it is!), but it's also mostly about
setting the foundation and being "batch 1" of a bunch more changes to
subtree that I'm getting queued up.  So please forgive the large
amount of churn in the leading clean-up commits, I promise that
there's more work coming on top of it (we've discovered lots of ways
to break the "subtree split" algorithm, and come up with fixes for
most of them).  In the mean-time, I do think that the UX improvements
in this patchset are already worth it themselves.

 - The first 11 commits improve subtree's tests, largely around the
   code-quality of the tests, but a few of the commits do actually
   improve what's being tested.

 - The middle 12 commits improve the code-quality of subtree's
   implementation.

 - The final 7 commits improve various aspects of subtree's user
   experience, from readability of the debug output, to documentation,
   to option flag handling.

The very last commit is likely to be a little objectionable--it makes
some option flag parsing more strict, so there will probably be worry
that the change breaks existing users.  However, it's being strict
about arg combinations that were always invalid, the difference is
that now it reports that to the users and bails.  Those users were
already broken, they just didn't know it.  `git subtree` should tell
them.

Luke Shumaker (30):
  .gitignore: Ignore /git-subtree
  subtree: t7900: update for having the default branch name be 'main'
  subtree: t7900: use test-lib.sh's test_count
  subtree: t7900: use consistent formatting
    v2:
     - Also normalize on `test X` instead of `[ X ]`.
     - Also normalize on `>FILENAME` with no spaces.
     - Fix a few if statements with `if` and `then` on the same line
       that I missed in v1.
    v3:
     - Consistently put the `do` of a loop on its own line.
  subtree: t7900: comment subtree_test_create_repo
    v2:
     - Also switch the few uses of vanilla test_create_repo over to
       subtree_test_create_repo.  In v1 this was erroneously included
       in a different commit.
  subtree: t7900: use 'test' for string equality
  subtree: t7900: delete some dead code
  subtree: t7900: fix 'verify one file change per commit'
    v2:
     - Fix whitespace.
  subtree: t7900: rename last_commit_message to last_commit_subject
  subtree: t7900: add a test for the -h flag
  subtree: t7900: add porcelain tests for 'pull' and 'push'
    v2:
     - Don't switch unrelated uses of vanilla test_create_repo over to
       subtree_test_create_repo; this has been moved to happen in an
       earlier commit.
     - Fix whitespace.
  subtree: don't have loose code outside of a function
    v2:
     - Include rationale in the the commit message.
  subtree: more consistent error propagation
  subtree: drop support for git < 1.7
    v2:
     - Include rationale in the the commit message.
  subtree: use `git merge-base --is-ancestor`
  subtree: use git-sh-setup's `say`
  subtree: use more explicit variable names for cmdline args
  subtree: use "$*" instead of "$@" as appropriate
    v2:
     - Improve the commit message with quoting and clearer
       explanation.
  subtree: don't fuss with PATH
    v2:
     - This commit changed entirely.  In v1 it changed how git-subtree
       adjusts the PATH.  In v2, it removes any fussing with the PATH,
       and in its place adds a pre-flight sanity check that it doesn't
       need to fuss with the PATH.
    v3:
     - Fix capitalization in the commit message.
  subtree: use "^{commit}" instead of "^0"
  subtree: parse revs in individual cmd_ functions
  subtree: remove duplicate check
  subtree: add comments and sanity checks
    v2:
     - Expand on the the commit message.
     - Fix capitalization in one of the comments.
  subtree: don't let debug and progress output clash
    v2:
     - Reword the commit message to be clearer.
     - Add comments to the code.
     - Flip the `if` and `else` cases around, so that the comments
       read better.
  subtree: have $indent actually affect indentation
  subtree: give the docs a once-over
    v2:
     - behaviour -> behavior
    v3:
     - Trim trailing whitespace.
     - Fix the man page saying "--ignore-join" instead of "--ignore-joins".
  subtree: allow --squash to be used with --rejoin
    v2:
     - In the added tests, use `test_must_fail` instead of `!`, as
       appropriate.
    v3:
     - Style: Put the `then` of an `if/then` on its own line.
     - Fix a bug (and add a test) where the resulting commits confuse a
       subsequent `git subtree merge --squash`.
  subtree: allow 'split' flags to be passed to 'push'
    v2:
     - In the added tests, use `test_must_fail` instead of `!`, as
       appropriate.
  subtree: push: allow specifying a local rev other than HEAD
  subtree: be stricter about validating flags

 .gitignore                         |    1 +
 contrib/subtree/git-subtree.sh     |  642 +++++++-----
 contrib/subtree/git-subtree.txt    |  192 ++--
 contrib/subtree/t/t7900-subtree.sh | 1450 ++++++++++++++++++----------
 contrib/subtree/todo               |    6 +-
 5 files changed, 1425 insertions(+), 866 deletions(-)

-- 
2.31.1

Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* [PATCH v3 01/30] .gitignore: Ignore /git-subtree
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 02/30] subtree: t7900: update for having the default branch name be 'main' Luke Shumaker
                       ` (28 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Running `make -C contrib/subtree/ test` creates a `git-subtree` executable
in the root of the repo.  Add it to the .gitignore so that anyone hacking
on subtree won't have to deal with that noise.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index 3dcdb6bb5a..a203678e9e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -162,6 +162,7 @@
 /git-stripspace
 /git-submodule
 /git-submodule--helper
+/git-subtree
 /git-svn
 /git-switch
 /git-symbolic-ref
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 02/30] subtree: t7900: update for having the default branch name be 'main'
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 01/30] .gitignore: Ignore /git-subtree Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-30  9:38       ` Ævar Arnfjörð Bjarmason
  2021-04-27 21:17     ` [PATCH v3 03/30] subtree: t7900: use test-lib.sh's test_count Luke Shumaker
                       ` (27 subsequent siblings)
  29 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Most of the tests had been converted to support
`GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main`, but `contrib/subtree/t/`
hadn't.

Convert it.  Most of the mentions of 'master' can just be replaced with
'HEAD'.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 117 +++++++++++++++--------------
 1 file changed, 59 insertions(+), 58 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 57ff4b25c1..4b982e6c2e 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -103,7 +103,7 @@ test_expect_success 'no merge from non-existent subtree' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		test_must_fail git subtree merge --prefix="sub dir" FETCH_HEAD
 	)
 '
@@ -116,8 +116,8 @@ test_expect_success 'no pull from non-existent subtree' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
-		test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" master
+		git fetch ./"sub proj" HEAD &&
+		test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" HEAD
 	)'
 
 next_test
@@ -128,7 +128,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Add '\''sub dir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
@@ -142,7 +142,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix and --me
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Added subproject"
 	)
@@ -156,7 +156,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix as -P an
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add -P "sub dir" -m "Added subproject" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Added subproject"
 	)
@@ -170,7 +170,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --squash and --pr
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject with squash" --squash FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Added subproject with squash"
 	)
@@ -188,13 +188,13 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count/sub proj" sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
@@ -208,13 +208,13 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix and -
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count/sub proj" sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merged changes from subproject"
 	)
@@ -228,13 +228,13 @@ test_expect_success 'merge new subproj history into sub dir/ with --squash and -
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count/sub proj" sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject using squash" --squash FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merged changes from subproject using squash"
 	)
@@ -248,7 +248,7 @@ test_expect_success 'merge the added subproj again, should do nothing' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		# this shouldn not actually do anything, since FETCH_HEAD
 		# is already a parent
@@ -265,13 +265,13 @@ test_expect_success 'merge new subproj history into subdir/ with a slash appende
 	test_create_commit "$test_count/subproj" sub1 &&
 	(
 		cd "$test_count" &&
-		git fetch ./subproj master &&
+		git fetch ./subproj HEAD &&
 		git subtree add --prefix=subdir/ FETCH_HEAD
 	) &&
 	test_create_commit "$test_count/subproj" sub2 &&
 	(
 		cd "$test_count" &&
-		git fetch ./subproj master &&
+		git fetch ./subproj HEAD &&
 		git subtree merge --prefix=subdir/ FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
@@ -289,7 +289,7 @@ test_expect_success 'split requires option --prefix' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		echo "You must provide the --prefix option." > expected &&
 		test_must_fail git subtree split > actual 2>&1 &&
@@ -309,7 +309,7 @@ test_expect_success 'split requires path given by option --prefix must exist' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		echo "'\''non-existent-directory'\'' does not exist; use '\''git subtree add'\''" > expected &&
 		test_must_fail git subtree split --prefix=non-existent-directory > actual 2>&1 &&
@@ -329,7 +329,7 @@ test_expect_success 'split sub dir/ with --rejoin' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -338,7 +338,7 @@ test_expect_success 'split sub dir/ with --rejoin' '
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --rejoin &&
@@ -370,7 +370,7 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -379,7 +379,7 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --message="Split & rejoin" --annotate="*" --rejoin &&
 		check_equal "$(last_commit_message)" "Split & rejoin"
@@ -394,7 +394,7 @@ test_expect_success 'split "sub dir"/ with --branch' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -403,7 +403,7 @@ test_expect_success 'split "sub dir"/ with --branch' '
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br &&
@@ -419,7 +419,7 @@ test_expect_success 'check hash of split' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -428,7 +428,7 @@ test_expect_success 'check hash of split' '
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br &&
@@ -451,7 +451,7 @@ test_expect_success 'split "sub dir"/ with --branch for an existing branch' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git branch subproj-br FETCH_HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
@@ -461,7 +461,7 @@ test_expect_success 'split "sub dir"/ with --branch for an existing branch' '
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br &&
@@ -478,7 +478,7 @@ test_expect_success 'split "sub dir"/ with --branch for an incompatible branch'
 	(
 		cd "$subtree_test_count" &&
 		git branch init HEAD &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -487,7 +487,7 @@ test_expect_success 'split "sub dir"/ with --branch for an incompatible branch'
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		test_must_fail git subtree split --prefix="sub dir" --branch init
 	)
@@ -505,7 +505,7 @@ test_expect_success 'make sure exactly the right set of files ends up in the sub
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -514,7 +514,7 @@ test_expect_success 'make sure exactly the right set of files ends up in the sub
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
@@ -555,7 +555,7 @@ test_expect_success 'make sure the subproj *only* contains commits that affect t
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -564,7 +564,7 @@ test_expect_success 'make sure the subproj *only* contains commits that affect t
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
@@ -606,7 +606,7 @@ test_expect_success 'make sure exactly the right set of files ends up in the mai
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -615,7 +615,7 @@ test_expect_success 'make sure exactly the right set of files ends up in the mai
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
@@ -643,7 +643,7 @@ test_expect_success 'make sure exactly the right set of files ends up in the mai
 	) &&
 	(
 		cd "$subtree_test_count" &&
-		git subtree pull --prefix="sub dir" ./"sub proj" master &&
+		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		test_write_lines main1 main2 >chkm &&
 		test_write_lines main-sub1 main-sub2 main-sub3 main-sub4 >chkms &&
@@ -666,7 +666,7 @@ test_expect_success 'make sure each filename changed exactly once in the entire
 	(
 		cd "$subtree_test_count" &&
 		git config log.date relative &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -675,7 +675,7 @@ test_expect_success 'make sure each filename changed exactly once in the entire
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
@@ -703,7 +703,7 @@ test_expect_success 'make sure each filename changed exactly once in the entire
 	) &&
 	(
 		cd "$subtree_test_count" &&
-		git subtree pull --prefix="sub dir" ./"sub proj" master &&
+		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		test_write_lines main1 main2 >chkm &&
 		test_write_lines sub1 sub2 sub3 sub4 >chks &&
@@ -731,7 +731,7 @@ test_expect_success 'make sure the --rejoin commits never make it into subproj'
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -740,7 +740,7 @@ test_expect_success 'make sure the --rejoin commits never make it into subproj'
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
@@ -768,7 +768,7 @@ test_expect_success 'make sure the --rejoin commits never make it into subproj'
 	) &&
 	(
 		cd "$subtree_test_count" &&
-		git subtree pull --prefix="sub dir" ./"sub proj" master &&
+		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 		check_equal "$(git log --pretty=format:"%s" HEAD^2 | grep -i split)" ""
 	)
 '
@@ -781,7 +781,7 @@ test_expect_success 'make sure no "git subtree" tagged commits make it into subp
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -790,7 +790,7 @@ test_expect_success 'make sure no "git subtree" tagged commits make it into subp
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
@@ -818,7 +818,7 @@ test_expect_success 'make sure no "git subtree" tagged commits make it into subp
 	) &&
 	(
 		cd "$subtree_test_count" &&
-		git subtree pull --prefix="sub dir" ./"sub proj" master &&
+		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		# They are meaningless to subproj since one side of the merge refers to the mainline
 		check_equal "$(git log --pretty=format:"%s%n%b" HEAD^2 | grep "git-subtree.*:")" ""
@@ -837,13 +837,13 @@ test_expect_success 'make sure "git subtree split" find the correct parent' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count/sub proj" sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git branch subproj-ref FETCH_HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
@@ -853,7 +853,7 @@ test_expect_success 'make sure "git subtree split" find the correct parent' '
 		git subtree split --prefix="sub dir" --branch subproj-br &&
 
 		# at this point, the new commit parent should be subproj-ref, if it is
-		# not, something went wrong (the "newparent" of "master~" commit should
+		# not, something went wrong (the "newparent" of "HEAD~" commit should
 		# have been sub2, but it was not, because its cache was not set to
 		# itself)
 		check_equal "$(git log --pretty=format:%P -1 subproj-br)" "$(git rev-parse subproj-ref)"
@@ -868,13 +868,13 @@ test_expect_success 'split a new subtree without --onto option' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count/sub proj" sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -903,14 +903,14 @@ test_expect_success 'verify one file change per commit' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git branch sub1 FETCH_HEAD &&
 		git subtree add --prefix="sub dir" sub1
 	) &&
 	test_create_commit "$subtree_test_count/sub proj" sub2 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -947,7 +947,7 @@ test_expect_success 'push split to subproj' '
 	test_create_commit "$subtree_test_count/sub proj" sub1 &&
 	(
 		cd "$subtree_test_count" &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
@@ -958,7 +958,7 @@ test_expect_success 'push split to subproj' '
 		cd $subtree_test_count/"sub proj" &&
                 git branch sub-branch-1 &&
                 cd .. &&
-		git fetch ./"sub proj" master &&
+		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
@@ -994,6 +994,7 @@ test_expect_success 'push split to subproj' '
 next_test
 test_expect_success 'subtree descendant check' '
 	subtree_test_create_repo "$subtree_test_count" &&
+	defaultBranch=$(sed "s,ref: refs/heads/,," "$subtree_test_count/.git/HEAD") &&
 	test_create_commit "$subtree_test_count" folder_subtree/a &&
 	(
 		cd "$subtree_test_count" &&
@@ -1010,7 +1011,7 @@ test_expect_success 'subtree descendant check' '
 	(
 		cd "$subtree_test_count" &&
 		git cherry-pick $cherry &&
-		git checkout master &&
+		git checkout $defaultBranch &&
 		git merge -m "merge should be kept on subtree" branch &&
 		git branch no_subtree_work_branch
 	) &&
@@ -1022,10 +1023,10 @@ test_expect_success 'subtree descendant check' '
 	test_create_commit "$subtree_test_count" not_a_subtree_change &&
 	(
 		cd "$subtree_test_count" &&
-		git checkout master &&
+		git checkout $defaultBranch &&
 		git merge -m "merge should be skipped on subtree" no_subtree_work_branch &&
 
-		git subtree split --prefix folder_subtree/ --branch subtree_tip master &&
+		git subtree split --prefix folder_subtree/ --branch subtree_tip $defaultBranch &&
 		git subtree split --prefix folder_subtree/ --branch subtree_branch branch &&
 		check_equal $(git rev-list --count subtree_tip..subtree_branch) 0
 	)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 03/30] subtree: t7900: use test-lib.sh's test_count
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 01/30] .gitignore: Ignore /git-subtree Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 02/30] subtree: t7900: update for having the default branch name be 'main' Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-30  9:45       ` Ævar Arnfjörð Bjarmason
  2021-04-27 21:17     ` [PATCH v3 04/30] subtree: t7900: use consistent formatting Luke Shumaker
                       ` (26 subsequent siblings)
  29 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Use test-lib.sh's `test_count`, instead instead of having
t7900-subtree.sh do its own book-keeping with `subtree_test_count` that
has to be explicitly incremented by calling `next_test`.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 636 ++++++++++++++---------------
 1 file changed, 300 insertions(+), 336 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 4b982e6c2e..a6351d9195 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -86,90 +86,79 @@ last_commit_message()
 	git log --pretty=format:%s -1
 }
 
-subtree_test_count=0
-next_test() {
-	subtree_test_count=$(($subtree_test_count+1))
-}
-
 #
 # Tests for 'git subtree add'
 #
 
-next_test
 test_expect_success 'no merge from non-existent subtree' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		test_must_fail git subtree merge --prefix="sub dir" FETCH_HEAD
 	)
 '
 
-next_test
 test_expect_success 'no pull from non-existent subtree' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" HEAD
 	)'
 
-next_test
 test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Add '\''sub dir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
-next_test
 test_expect_success 'add subproj as subtree into sub dir/ with --prefix and --message' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Added subproject"
 	)
 '
 
-next_test
 test_expect_success 'add subproj as subtree into sub dir/ with --prefix as -P and --message as -m' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add -P "sub dir" -m "Added subproject" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Added subproject"
 	)
 '
 
-next_test
 test_expect_success 'add subproj as subtree into sub dir/ with --squash and --prefix and --message' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject with squash" --squash FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Added subproject with squash"
@@ -180,74 +169,70 @@ test_expect_success 'add subproj as subtree into sub dir/ with --squash and --pr
 # Tests for 'git subtree merge'
 #
 
-next_test
 test_expect_success 'merge new subproj history into sub dir/ with --prefix' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
-next_test
 test_expect_success 'merge new subproj history into sub dir/ with --prefix and --message' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject" FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merged changes from subproject"
 	)
 '
 
-next_test
 test_expect_success 'merge new subproj history into sub dir/ with --squash and --prefix and --message' '
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	subtree_test_create_repo "$subtree_test_count" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	subtree_test_create_repo "$test_count" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject using squash" --squash FETCH_HEAD &&
 		check_equal "$(last_commit_message)" "Merged changes from subproject using squash"
 	)
 '
 
-next_test
 test_expect_success 'merge the added subproj again, should do nothing' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		# this shouldn not actually do anything, since FETCH_HEAD
@@ -257,7 +242,6 @@ test_expect_success 'merge the added subproj again, should do nothing' '
 	)
 '
 
-next_test
 test_expect_success 'merge new subproj history into subdir/ with a slash appended to the argument of --prefix' '
 	test_create_repo "$test_count" &&
 	test_create_repo "$test_count/subproj" &&
@@ -281,14 +265,13 @@ test_expect_success 'merge new subproj history into subdir/ with a slash appende
 # Tests for 'git subtree split'
 #
 
-next_test
 test_expect_success 'split requires option --prefix' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		echo "You must provide the --prefix option." > expected &&
@@ -301,14 +284,13 @@ test_expect_success 'split requires option --prefix' '
 	)
 '
 
-next_test
 test_expect_success 'split requires path given by option --prefix must exist' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
 		echo "'\''non-existent-directory'\'' does not exist; use '\''git subtree add'\''" > expected &&
@@ -321,23 +303,22 @@ test_expect_success 'split requires path given by option --prefix must exist' '
 	)
 '
 
-next_test
 test_expect_success 'split sub dir/ with --rejoin' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
@@ -346,12 +327,11 @@ test_expect_success 'split sub dir/ with --rejoin' '
 	)
  '
 
-next_test
 test_expect_success 'split sub dir/ with --rejoin from scratch' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	test_create_commit "$subtree_test_count" main1 &&
+	subtree_test_create_repo "$test_count" &&
+	test_create_commit "$test_count" main1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		mkdir "sub dir" &&
 		echo file >"sub dir"/file &&
 		git add "sub dir/file" &&
@@ -362,23 +342,22 @@ test_expect_success 'split sub dir/ with --rejoin from scratch' '
 	)
  '
 
-next_test
 test_expect_success 'split sub dir/ with --rejoin and --message' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --message="Split & rejoin" --annotate="*" --rejoin &&
@@ -386,23 +365,22 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
 	)
 '
 
-next_test
 test_expect_success 'split "sub dir"/ with --branch' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
@@ -411,23 +389,22 @@ test_expect_success 'split "sub dir"/ with --branch' '
 	)
 '
 
-next_test
 test_expect_success 'check hash of split' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
@@ -443,24 +420,23 @@ test_expect_success 'check hash of split' '
 	)
 '
 
-next_test
 test_expect_success 'split "sub dir"/ with --branch for an existing branch' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git branch subproj-br FETCH_HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
@@ -469,24 +445,23 @@ test_expect_success 'split "sub dir"/ with --branch for an existing branch' '
 	)
 '
 
-next_test
 test_expect_success 'split "sub dir"/ with --branch for an incompatible branch' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git branch init HEAD &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		test_must_fail git subtree split --prefix="sub dir" --branch init
@@ -497,46 +472,45 @@ test_expect_success 'split "sub dir"/ with --branch for an incompatible branch'
 # Validity checking
 #
 
-next_test
 test_expect_success 'make sure exactly the right set of files ends up in the subproj' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub3 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count/sub proj" sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub4 &&
+	test_create_commit "$test_count/sub proj" sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub4 &&
+	test_create_commit "$test_count" "sub dir"/main-sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD &&
 
@@ -547,46 +521,45 @@ test_expect_success 'make sure exactly the right set of files ends up in the sub
 	)
 '
 
-next_test
 test_expect_success 'make sure the subproj *only* contains commits that affect the "sub dir"' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub3 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count/sub proj" sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub4 &&
+	test_create_commit "$test_count/sub proj" sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub4 &&
+	test_create_commit "$test_count" "sub dir"/main-sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD &&
 
@@ -598,51 +571,50 @@ test_expect_success 'make sure the subproj *only* contains commits that affect t
 	)
 '
 
-next_test
 test_expect_success 'make sure exactly the right set of files ends up in the mainline' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub3 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count/sub proj" sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub4 &&
+	test_create_commit "$test_count/sub proj" sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub4 &&
+	test_create_commit "$test_count" "sub dir"/main-sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		test_write_lines main1 main2 >chkm &&
@@ -657,52 +629,51 @@ test_expect_success 'make sure exactly the right set of files ends up in the mai
 	)
 '
 
-next_test
 test_expect_success 'make sure each filename changed exactly once in the entire history' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git config log.date relative &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub3 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count/sub proj" sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub4 &&
+	test_create_commit "$test_count/sub proj" sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub4 &&
+	test_create_commit "$test_count" "sub dir"/main-sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		test_write_lines main1 main2 >chkm &&
@@ -723,101 +694,99 @@ test_expect_success 'make sure each filename changed exactly once in the entire
 	)
 '
 
-next_test
 test_expect_success 'make sure the --rejoin commits never make it into subproj' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub3 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count/sub proj" sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub4 &&
+	test_create_commit "$test_count/sub proj" sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub4 &&
+	test_create_commit "$test_count" "sub dir"/main-sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 		check_equal "$(git log --pretty=format:"%s" HEAD^2 | grep -i split)" ""
 	)
 '
 
-next_test
 test_expect_success 'make sure no "git subtree" tagged commits make it into subproj' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub3 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count/sub proj" sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		 git merge FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub4 &&
+	test_create_commit "$test_count/sub proj" sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub4 &&
+	test_create_commit "$test_count" "sub dir"/main-sub4 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br --rejoin
 	) &&
 	(
-		cd "$subtree_test_count/sub proj" &&
+		cd "$test_count/sub proj" &&
 		git fetch .. subproj-br &&
 		git merge FETCH_HEAD
 	) &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		# They are meaningless to subproj since one side of the merge refers to the mainline
@@ -829,27 +798,26 @@ test_expect_success 'make sure no "git subtree" tagged commits make it into subp
 # A new set of tests
 #
 
-next_test
 test_expect_success 'make sure "git subtree split" find the correct parent' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git branch subproj-ref FETCH_HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --branch subproj-br &&
 
 		# at this point, the new commit parent should be subproj-ref, if it is
@@ -860,32 +828,31 @@ test_expect_success 'make sure "git subtree split" find the correct parent' '
 	)
 '
 
-next_test
 test_expect_success 'split a new subtree without --onto option' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --branch subproj-br
 	) &&
-	mkdir "$subtree_test_count"/"sub dir2" &&
-	test_create_commit "$subtree_test_count" "sub dir2"/main-sub2 &&
+	mkdir "$test_count"/"sub dir2" &&
+	test_create_commit "$test_count" "sub dir2"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 
 		# also test that we still can split out an entirely new subtree
 		# if the parent of the first commit in the tree is not empty,
@@ -895,33 +862,32 @@ test_expect_success 'split a new subtree without --onto option' '
 	)
 '
 
-next_test
 test_expect_success 'verify one file change per commit' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git branch sub1 FETCH_HEAD &&
 		git subtree add --prefix="sub dir" sub1
 	) &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir" --branch subproj-br
 	) &&
-	mkdir "$subtree_test_count"/"sub dir2" &&
-	test_create_commit "$subtree_test_count" "sub dir2"/main-sub2 &&
+	mkdir "$test_count"/"sub dir2" &&
+	test_create_commit "$test_count" "sub dir2"/main-sub2 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git subtree split --prefix="sub dir2" --branch subproj2-br &&
 
 		x= &&
@@ -939,31 +905,30 @@ test_expect_success 'verify one file change per commit' '
 	)
 '
 
-next_test
 test_expect_success 'push split to subproj' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	subtree_test_create_repo "$subtree_test_count/sub proj" &&
-	test_create_commit "$subtree_test_count" main1 &&
-	test_create_commit "$subtree_test_count/sub proj" sub1 &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub1 &&
-	test_create_commit "$subtree_test_count" main2 &&
-	test_create_commit "$subtree_test_count/sub proj" sub2 &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
-		cd $subtree_test_count/"sub proj" &&
+		cd $test_count/"sub proj" &&
                 git branch sub-branch-1 &&
                 cd .. &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
-	test_create_commit "$subtree_test_count" "sub dir"/main-sub3 &&
+	test_create_commit "$test_count" "sub dir"/main-sub3 &&
         (
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 	        git subtree push ./"sub proj" --prefix "sub dir" sub-branch-1 &&
                 cd ./"sub proj" &&
                 git checkout sub-branch-1 &&
@@ -991,38 +956,37 @@ test_expect_success 'push split to subproj' '
 #   set of commits.
 #
 
-next_test
 test_expect_success 'subtree descendant check' '
-	subtree_test_create_repo "$subtree_test_count" &&
-	defaultBranch=$(sed "s,ref: refs/heads/,," "$subtree_test_count/.git/HEAD") &&
-	test_create_commit "$subtree_test_count" folder_subtree/a &&
+	subtree_test_create_repo "$test_count" &&
+	defaultBranch=$(sed "s,ref: refs/heads/,," "$test_count/.git/HEAD") &&
+	test_create_commit "$test_count" folder_subtree/a &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git branch branch
 	) &&
-	test_create_commit "$subtree_test_count" folder_subtree/0 &&
-	test_create_commit "$subtree_test_count" folder_subtree/b &&
-	cherry=$(cd "$subtree_test_count"; git rev-parse HEAD) &&
+	test_create_commit "$test_count" folder_subtree/0 &&
+	test_create_commit "$test_count" folder_subtree/b &&
+	cherry=$(cd "$test_count"; git rev-parse HEAD) &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git checkout branch
 	) &&
-	test_create_commit "$subtree_test_count" commit_on_branch &&
+	test_create_commit "$test_count" commit_on_branch &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git cherry-pick $cherry &&
 		git checkout $defaultBranch &&
 		git merge -m "merge should be kept on subtree" branch &&
 		git branch no_subtree_work_branch
 	) &&
-	test_create_commit "$subtree_test_count" folder_subtree/d &&
+	test_create_commit "$test_count" folder_subtree/d &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git checkout no_subtree_work_branch
 	) &&
-	test_create_commit "$subtree_test_count" not_a_subtree_change &&
+	test_create_commit "$test_count" not_a_subtree_change &&
 	(
-		cd "$subtree_test_count" &&
+		cd "$test_count" &&
 		git checkout $defaultBranch &&
 		git merge -m "merge should be skipped on subtree" no_subtree_work_branch &&
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 04/30] subtree: t7900: use consistent formatting
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (2 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 03/30] subtree: t7900: use test-lib.sh's test_count Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 05/30] subtree: t7900: comment subtree_test_create_repo Luke Shumaker
                       ` (25 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

The formatting in t7900-subtree.sh isn't even consistent throughout the
file.  Fix that; make it consistent throughout the file.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - Also normalize on `test X` instead of `[ X ]`.
 - Also normalize on `>FILENAME` with no spaces.
 - Fix a few if statements with `if` and `then` on the same line
   that I missed in v1.
v3:
 - Consistently put the `do` of a loop on its own line.

 contrib/subtree/t/t7900-subtree.sh | 70 +++++++++++++++---------------
 1 file changed, 35 insertions(+), 35 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index a6351d9195..2319c3fd1c 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -11,11 +11,9 @@ and split subcommands of git subtree.
 
 TEST_DIRECTORY=$(pwd)/../../../t
 export TEST_DIRECTORY
+. "$TEST_DIRECTORY"/test-lib.sh
 
-. ../../../t/test-lib.sh
-
-subtree_test_create_repo()
-{
+subtree_test_create_repo () {
 	test_create_repo "$1" &&
 	(
 		cd "$1" &&
@@ -23,26 +21,24 @@ subtree_test_create_repo()
 	)
 }
 
-create()
-{
+create () {
 	echo "$1" >"$1" &&
 	git add "$1"
 }
 
-check_equal()
-{
+check_equal () {
 	test_debug 'echo'
 	test_debug "echo \"check a:\" \"{$1}\""
 	test_debug "echo \"      b:\" \"{$2}\""
-	if [ "$1" = "$2" ]; then
+	if test "$1" = "$2"
+	then
 		return 0
 	else
 		return 1
 	fi
 }
 
-undo()
-{
+undo () {
 	git reset --hard HEAD~
 }
 
@@ -50,15 +46,18 @@ undo()
 # The original set of commits changed only one file each.
 # A multi-file change would imply that we pruned commits
 # too aggressively.
-join_commits()
-{
+join_commits () {
 	commit=
 	all=
-	while read x y; do
-		if [ -z "$x" ]; then
+	while read x y
+	do
+		if test -z "$x"
+		then
 			continue
-		elif [ "$x" = "commit:" ]; then
-			if [ -n "$commit" ]; then
+		elif test "$x" = "commit:"
+		then
+			if test -n "$commit"
+			then
 				echo "$commit $all"
 				all=
 			fi
@@ -70,7 +69,7 @@ join_commits()
 	echo "$commit $all"
 }
 
-test_create_commit() (
+test_create_commit () (
 	repo=$1 &&
 	commit=$2 &&
 	cd "$repo" &&
@@ -81,8 +80,7 @@ test_create_commit() (
 	git commit -m "$commit" || error "Could not commit"
 )
 
-last_commit_message()
-{
+last_commit_message () {
 	git log --pretty=format:%s -1
 }
 
@@ -111,7 +109,8 @@ test_expect_success 'no pull from non-existent subtree' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" HEAD
-	)'
+	)
+'
 
 test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
 	subtree_test_create_repo "$test_count" &&
@@ -274,8 +273,8 @@ test_expect_success 'split requires option --prefix' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
-		echo "You must provide the --prefix option." > expected &&
-		test_must_fail git subtree split > actual 2>&1 &&
+		echo "You must provide the --prefix option." >expected &&
+		test_must_fail git subtree split >actual 2>&1 &&
 		test_debug "printf '"expected: "'" &&
 		test_debug "cat expected" &&
 		test_debug "printf '"actual: "'" &&
@@ -293,8 +292,8 @@ test_expect_success 'split requires path given by option --prefix must exist' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
-		echo "'\''non-existent-directory'\'' does not exist; use '\''git subtree add'\''" > expected &&
-		test_must_fail git subtree split --prefix=non-existent-directory > actual 2>&1 &&
+		echo "'\''non-existent-directory'\'' does not exist; use '\''git subtree add'\''" >expected &&
+		test_must_fail git subtree split --prefix=non-existent-directory >actual 2>&1 &&
 		test_debug "printf '"expected: "'" &&
 		test_debug "cat expected" &&
 		test_debug "printf '"actual: "'" &&
@@ -325,7 +324,7 @@ test_expect_success 'split sub dir/ with --rejoin' '
 		git subtree split --prefix="sub dir" --annotate="*" --rejoin &&
 		check_equal "$(last_commit_message)" "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
 	)
- '
+'
 
 test_expect_success 'split sub dir/ with --rejoin from scratch' '
 	subtree_test_create_repo "$test_count" &&
@@ -340,7 +339,7 @@ test_expect_success 'split sub dir/ with --rejoin from scratch' '
 		git subtree split --prefix="sub dir" --rejoin &&
 		check_equal "$(last_commit_message)" "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
 	)
- '
+'
 
 test_expect_success 'split sub dir/ with --rejoin and --message' '
 	subtree_test_create_repo "$test_count" &&
@@ -893,7 +892,8 @@ test_expect_success 'verify one file change per commit' '
 		x= &&
 		git log --pretty=format:"commit: %H" | join_commits |
 		(
-			while read commit a b; do
+			while read commit a b
+			do
 				test_debug "echo Verifying commit $commit"
 				test_debug "echo a: $a"
 				test_debug "echo b: $b"
@@ -921,18 +921,18 @@ test_expect_success 'push split to subproj' '
 	test_create_commit "$test_count" "sub dir"/main-sub2 &&
 	(
 		cd $test_count/"sub proj" &&
-                git branch sub-branch-1 &&
-                cd .. &&
+		git branch sub-branch-1 &&
+		cd .. &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD
 	) &&
 	test_create_commit "$test_count" "sub dir"/main-sub3 &&
-        (
+	(
 		cd "$test_count" &&
-	        git subtree push ./"sub proj" --prefix "sub dir" sub-branch-1 &&
-                cd ./"sub proj" &&
-                git checkout sub-branch-1 &&
-         	check_equal "$(last_commit_message)" "sub dir/main-sub3"
+		git subtree push ./"sub proj" --prefix "sub dir" sub-branch-1 &&
+		cd ./"sub proj" &&
+		git checkout sub-branch-1 &&
+		check_equal "$(last_commit_message)" "sub dir/main-sub3"
 	)
 '
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 05/30] subtree: t7900: comment subtree_test_create_repo
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (3 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 04/30] subtree: t7900: use consistent formatting Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-30  9:48       ` Ævar Arnfjörð Bjarmason
  2021-04-27 21:17     ` [PATCH v3 06/30] subtree: t7900: use 'test' for string equality Luke Shumaker
                       ` (24 subsequent siblings)
  29 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

It's unclear what the purpose of t7900-subtree.sh's
`subtree_test_create_repo` helper function is.  It wraps test-lib.sh's,
`test_create_repo` but follows that up by setting log.date=relative.  Why
does it set log.date=relative?

My first guess was that at one point the tests required that, but no
longer do, and that the function is now vestigial.  I even wrote a patch
to get rid of it and was moments away from `git send-email`ing it.

However, by chance when looking for something else in the history, I
discovered the true reason, from e7aac44ed2 (contrib/subtree: ignore
log.date configuration, 2015-07-21).  It's testing that setting
log.date=relative doesn't break `git subtree`, as at one point in the past
that did break `git subtree`.

So, add a comment about this, to avoid future such confusion.

And while at it, go ahead and (1) touch up the function to avoid a
pointless subshell and (2) update the one test that didn't use it.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - Also switch the few uses of vanilla test_create_repo over to
   subtree_test_create_repo.  In v1 this was erroneously included
   in a different commit.

 contrib/subtree/t/t7900-subtree.sh | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 2319c3fd1c..12b8cb03c7 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -13,12 +13,14 @@ TEST_DIRECTORY=$(pwd)/../../../t
 export TEST_DIRECTORY
 . "$TEST_DIRECTORY"/test-lib.sh
 
+# Use our own wrapper around test-lib.sh's test_create_repo, in order
+# to set log.date=relative.  `git subtree` parses the output of `git
+# log`, and so it must be careful to not be affected by settings that
+# change the `git log` output.  We test this by setting
+# log.date=relative for every repo in the tests.
 subtree_test_create_repo () {
 	test_create_repo "$1" &&
-	(
-		cd "$1" &&
-		git config log.date relative
-	)
+	git -C "$1" config log.date relative
 }
 
 create () {
@@ -242,8 +244,8 @@ test_expect_success 'merge the added subproj again, should do nothing' '
 '
 
 test_expect_success 'merge new subproj history into subdir/ with a slash appended to the argument of --prefix' '
-	test_create_repo "$test_count" &&
-	test_create_repo "$test_count/subproj" &&
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/subproj" &&
 	test_create_commit "$test_count" main1 &&
 	test_create_commit "$test_count/subproj" sub1 &&
 	(
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 06/30] subtree: t7900: use 'test' for string equality
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (4 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 05/30] subtree: t7900: comment subtree_test_create_repo Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-30  9:55       ` Ævar Arnfjörð Bjarmason
  2021-04-27 21:17     ` [PATCH v3 07/30] subtree: t7900: delete some dead code Luke Shumaker
                       ` (23 subsequent siblings)
  29 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

t7900-subtree.sh defines its own `check_equal A B` function, instead of
just using `test A = B` like all of the other tests.  Don't be special,
get rid of `check_equal` in favor of `test`.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 60 ++++++++++++------------------
 1 file changed, 24 insertions(+), 36 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 12b8cb03c7..76183153c9 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -28,18 +28,6 @@ create () {
 	git add "$1"
 }
 
-check_equal () {
-	test_debug 'echo'
-	test_debug "echo \"check a:\" \"{$1}\""
-	test_debug "echo \"      b:\" \"{$2}\""
-	if test "$1" = "$2"
-	then
-		return 0
-	else
-		return 1
-	fi
-}
-
 undo () {
 	git reset --hard HEAD~
 }
@@ -123,7 +111,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Add '\''sub dir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
+		test "$(last_commit_message)" = "Add '\''sub dir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -136,7 +124,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix and --me
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject" FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Added subproject"
+		test "$(last_commit_message)" = "Added subproject"
 	)
 '
 
@@ -149,7 +137,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix as -P an
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add -P "sub dir" -m "Added subproject" FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Added subproject"
+		test "$(last_commit_message)" = "Added subproject"
 	)
 '
 
@@ -162,7 +150,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --squash and --pr
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject with squash" --squash FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Added subproject with squash"
+		test "$(last_commit_message)" = "Added subproject with squash"
 	)
 '
 
@@ -185,7 +173,7 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
+		test "$(last_commit_message)" = "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -204,7 +192,7 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix and -
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject" FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Merged changes from subproject"
+		test "$(last_commit_message)" = "Merged changes from subproject"
 	)
 '
 
@@ -223,7 +211,7 @@ test_expect_success 'merge new subproj history into sub dir/ with --squash and -
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject using squash" --squash FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Merged changes from subproject using squash"
+		test "$(last_commit_message)" = "Merged changes from subproject using squash"
 	)
 '
 
@@ -239,7 +227,7 @@ test_expect_success 'merge the added subproj again, should do nothing' '
 		# this shouldn not actually do anything, since FETCH_HEAD
 		# is already a parent
 		result=$(git merge -s ours -m "merge -s -ours" FETCH_HEAD) &&
-		check_equal "${result}" "Already up to date."
+		test "${result}" = "Already up to date."
 	)
 '
 
@@ -258,7 +246,7 @@ test_expect_success 'merge new subproj history into subdir/ with a slash appende
 		cd "$test_count" &&
 		git fetch ./subproj HEAD &&
 		git subtree merge --prefix=subdir/ FETCH_HEAD &&
-		check_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
+		test "$(last_commit_message)" = "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -324,7 +312,7 @@ test_expect_success 'split sub dir/ with --rejoin' '
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --rejoin &&
-		check_equal "$(last_commit_message)" "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
+		test "$(last_commit_message)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
 	)
 '
 
@@ -339,7 +327,7 @@ test_expect_success 'split sub dir/ with --rejoin from scratch' '
 		git commit -m"sub dir file" &&
 		split_hash=$(git subtree split --prefix="sub dir" --rejoin) &&
 		git subtree split --prefix="sub dir" --rejoin &&
-		check_equal "$(last_commit_message)" "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
+		test "$(last_commit_message)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
 	)
 '
 
@@ -362,7 +350,7 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --message="Split & rejoin" --annotate="*" --rejoin &&
-		check_equal "$(last_commit_message)" "Split & rejoin"
+		test "$(last_commit_message)" = "Split & rejoin"
 	)
 '
 
@@ -386,7 +374,7 @@ test_expect_success 'split "sub dir"/ with --branch' '
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br &&
-		check_equal "$(git rev-parse subproj-br)" "$split_hash"
+		test "$(git rev-parse subproj-br)" = "$split_hash"
 	)
 '
 
@@ -410,13 +398,13 @@ test_expect_success 'check hash of split' '
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br &&
-		check_equal "$(git rev-parse subproj-br)" "$split_hash" &&
+		test "$(git rev-parse subproj-br)" = "$split_hash" &&
 		# Check hash of split
 		new_hash=$(git rev-parse subproj-br^2) &&
 		(
 			cd ./"sub proj" &&
 			subdir_hash=$(git rev-parse HEAD) &&
-			check_equal ''"$new_hash"'' "$subdir_hash"
+			test ''"$new_hash"'' = "$subdir_hash"
 		)
 	)
 '
@@ -442,7 +430,7 @@ test_expect_success 'split "sub dir"/ with --branch for an existing branch' '
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --branch subproj-br &&
-		check_equal "$(git rev-parse subproj-br)" "$split_hash"
+		test "$(git rev-parse subproj-br)" = "$split_hash"
 	)
 '
 
@@ -740,7 +728,7 @@ test_expect_success 'make sure the --rejoin commits never make it into subproj'
 	(
 		cd "$test_count" &&
 		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
-		check_equal "$(git log --pretty=format:"%s" HEAD^2 | grep -i split)" ""
+		test "$(git log --pretty=format:"%s" HEAD^2 | grep -i split)" = ""
 	)
 '
 
@@ -791,7 +779,7 @@ test_expect_success 'make sure no "git subtree" tagged commits make it into subp
 		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
 
 		# They are meaningless to subproj since one side of the merge refers to the mainline
-		check_equal "$(git log --pretty=format:"%s%n%b" HEAD^2 | grep "git-subtree.*:")" ""
+		test "$(git log --pretty=format:"%s%n%b" HEAD^2 | grep "git-subtree.*:")" = ""
 	)
 '
 
@@ -825,7 +813,7 @@ test_expect_success 'make sure "git subtree split" find the correct parent' '
 		# not, something went wrong (the "newparent" of "HEAD~" commit should
 		# have been sub2, but it was not, because its cache was not set to
 		# itself)
-		check_equal "$(git log --pretty=format:%P -1 subproj-br)" "$(git rev-parse subproj-ref)"
+		test "$(git log --pretty=format:%P -1 subproj-br)" = "$(git rev-parse subproj-ref)"
 	)
 '
 
@@ -859,7 +847,7 @@ test_expect_success 'split a new subtree without --onto option' '
 		# if the parent of the first commit in the tree is not empty,
 		# then the new subtree has accidentally been attached to something
 		git subtree split --prefix="sub dir2" --branch subproj2-br &&
-		check_equal "$(git log --pretty=format:%P -1 subproj2-br)" ""
+		test "$(git log --pretty=format:%P -1 subproj2-br)" = ""
 	)
 '
 
@@ -899,10 +887,10 @@ test_expect_success 'verify one file change per commit' '
 				test_debug "echo Verifying commit $commit"
 				test_debug "echo a: $a"
 				test_debug "echo b: $b"
-				check_equal "$b" ""
+				test "$b" = ""
 				x=1
 			done
-			check_equal "$x" 1
+			test "$x" = 1
 		)
 	)
 '
@@ -934,7 +922,7 @@ test_expect_success 'push split to subproj' '
 		git subtree push ./"sub proj" --prefix "sub dir" sub-branch-1 &&
 		cd ./"sub proj" &&
 		git checkout sub-branch-1 &&
-		check_equal "$(last_commit_message)" "sub dir/main-sub3"
+		test "$(last_commit_message)" = "sub dir/main-sub3"
 	)
 '
 
@@ -994,7 +982,7 @@ test_expect_success 'subtree descendant check' '
 
 		git subtree split --prefix folder_subtree/ --branch subtree_tip $defaultBranch &&
 		git subtree split --prefix folder_subtree/ --branch subtree_branch branch &&
-		check_equal $(git rev-list --count subtree_tip..subtree_branch) 0
+		test $(git rev-list --count subtree_tip..subtree_branch) = 0
 	)
 '
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 07/30] subtree: t7900: delete some dead code
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (5 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 06/30] subtree: t7900: use 'test' for string equality Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 08/30] subtree: t7900: fix 'verify one file change per commit' Luke Shumaker
                       ` (22 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 76183153c9..421ed9f003 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -10,7 +10,6 @@ and split subcommands of git subtree.
 '
 
 TEST_DIRECTORY=$(pwd)/../../../t
-export TEST_DIRECTORY
 . "$TEST_DIRECTORY"/test-lib.sh
 
 # Use our own wrapper around test-lib.sh's test_create_repo, in order
@@ -23,15 +22,6 @@ subtree_test_create_repo () {
 	git -C "$1" config log.date relative
 }
 
-create () {
-	echo "$1" >"$1" &&
-	git add "$1"
-}
-
-undo () {
-	git reset --hard HEAD~
-}
-
 # Make sure no patch changes more than one file.
 # The original set of commits changed only one file each.
 # A multi-file change would imply that we pruned commits
@@ -404,7 +394,7 @@ test_expect_success 'check hash of split' '
 		(
 			cd ./"sub proj" &&
 			subdir_hash=$(git rev-parse HEAD) &&
-			test ''"$new_hash"'' = "$subdir_hash"
+			test "$new_hash" = "$subdir_hash"
 		)
 	)
 '
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 08/30] subtree: t7900: fix 'verify one file change per commit'
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (6 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 07/30] subtree: t7900: delete some dead code Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 09/30] subtree: t7900: rename last_commit_message to last_commit_subject Luke Shumaker
                       ` (21 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

As far as I can tell, this test isn't actually testing anything, because
someone forgot to tack on `--name-only` to `git log`.  This seems to
have been the case since the test was first written, back in fa16ab36ad
("test.sh: make sure no commit changes more than one file at a time.",
2009-04-26), unless `git log` used to do that by default and didn't need
the flag back then?

Convincing myself that it's not actually testing anything was tricky,
the code is a little hard to reason about.  It can be made a lot simpler
if instead of trying to parse all of the info from a single `git log`,
we're OK calling `git log` from inside of a loop.  And it's my opinion
that tests are not the place for clever optimized code.

So, fix and simplify the test, so that it's actually testing something
and is simpler to reason about.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 46 ++++--------------------------
 1 file changed, 6 insertions(+), 40 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 421ed9f003..1c717fcb96 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -22,33 +22,6 @@ subtree_test_create_repo () {
 	git -C "$1" config log.date relative
 }
 
-# Make sure no patch changes more than one file.
-# The original set of commits changed only one file each.
-# A multi-file change would imply that we pruned commits
-# too aggressively.
-join_commits () {
-	commit=
-	all=
-	while read x y
-	do
-		if test -z "$x"
-		then
-			continue
-		elif test "$x" = "commit:"
-		then
-			if test -n "$commit"
-			then
-				echo "$commit $all"
-				all=
-			fi
-			commit="$y"
-		else
-			all="$all $y"
-		fi
-	done
-	echo "$commit $all"
-}
-
 test_create_commit () (
 	repo=$1 &&
 	commit=$2 &&
@@ -869,19 +842,12 @@ test_expect_success 'verify one file change per commit' '
 		cd "$test_count" &&
 		git subtree split --prefix="sub dir2" --branch subproj2-br &&
 
-		x= &&
-		git log --pretty=format:"commit: %H" | join_commits |
-		(
-			while read commit a b
-			do
-				test_debug "echo Verifying commit $commit"
-				test_debug "echo a: $a"
-				test_debug "echo b: $b"
-				test "$b" = ""
-				x=1
-			done
-			test "$x" = 1
-		)
+		git log --format="%H" >commit-list &&
+		while read commit
+		do
+			git log -n1 --format="" --name-only "$commit" >file-list &&
+			test_line_count -le 1 file-list || return 1
+		done <commit-list
 	)
 '
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 09/30] subtree: t7900: rename last_commit_message to last_commit_subject
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (7 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 08/30] subtree: t7900: fix 'verify one file change per commit' Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-30  9:59       ` Ævar Arnfjörð Bjarmason
  2021-04-27 21:17     ` [PATCH v3 10/30] subtree: t7900: add a test for the -h flag Luke Shumaker
                       ` (20 subsequent siblings)
  29 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

t7900-subtree.sh defines a helper function named last_commit_message.
However, it only returns the subject line of the commit message, not the
entire commit message.  So rename it, to make the name less confusing.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 1c717fcb96..5c2510f1f5 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -33,7 +33,7 @@ test_create_commit () (
 	git commit -m "$commit" || error "Could not commit"
 )
 
-last_commit_message () {
+last_commit_subject () {
 	git log --pretty=format:%s -1
 }
 
@@ -74,7 +74,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" FETCH_HEAD &&
-		test "$(last_commit_message)" = "Add '\''sub dir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
+		test "$(last_commit_subject)" = "Add '\''sub dir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -87,7 +87,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix and --me
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject" FETCH_HEAD &&
-		test "$(last_commit_message)" = "Added subproject"
+		test "$(last_commit_subject)" = "Added subproject"
 	)
 '
 
@@ -100,7 +100,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --prefix as -P an
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add -P "sub dir" -m "Added subproject" FETCH_HEAD &&
-		test "$(last_commit_message)" = "Added subproject"
+		test "$(last_commit_subject)" = "Added subproject"
 	)
 '
 
@@ -113,7 +113,7 @@ test_expect_success 'add subproj as subtree into sub dir/ with --squash and --pr
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree add --prefix="sub dir" --message="Added subproject with squash" --squash FETCH_HEAD &&
-		test "$(last_commit_message)" = "Added subproject with squash"
+		test "$(last_commit_subject)" = "Added subproject with squash"
 	)
 '
 
@@ -136,7 +136,7 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix' '
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
-		test "$(last_commit_message)" = "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
+		test "$(last_commit_subject)" = "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -155,7 +155,7 @@ test_expect_success 'merge new subproj history into sub dir/ with --prefix and -
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject" FETCH_HEAD &&
-		test "$(last_commit_message)" = "Merged changes from subproject"
+		test "$(last_commit_subject)" = "Merged changes from subproject"
 	)
 '
 
@@ -174,7 +174,7 @@ test_expect_success 'merge new subproj history into sub dir/ with --squash and -
 		cd "$test_count" &&
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" --message="Merged changes from subproject using squash" --squash FETCH_HEAD &&
-		test "$(last_commit_message)" = "Merged changes from subproject using squash"
+		test "$(last_commit_subject)" = "Merged changes from subproject using squash"
 	)
 '
 
@@ -209,7 +209,7 @@ test_expect_success 'merge new subproj history into subdir/ with a slash appende
 		cd "$test_count" &&
 		git fetch ./subproj HEAD &&
 		git subtree merge --prefix=subdir/ FETCH_HEAD &&
-		test "$(last_commit_message)" = "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
+		test "$(last_commit_subject)" = "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
 	)
 '
 
@@ -275,7 +275,7 @@ test_expect_success 'split sub dir/ with --rejoin' '
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
 		git subtree split --prefix="sub dir" --annotate="*" --rejoin &&
-		test "$(last_commit_message)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
+		test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
 	)
 '
 
@@ -290,7 +290,7 @@ test_expect_success 'split sub dir/ with --rejoin from scratch' '
 		git commit -m"sub dir file" &&
 		split_hash=$(git subtree split --prefix="sub dir" --rejoin) &&
 		git subtree split --prefix="sub dir" --rejoin &&
-		test "$(last_commit_message)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
+		test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''"
 	)
 '
 
@@ -313,7 +313,7 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
 		git fetch ./"sub proj" HEAD &&
 		git subtree merge --prefix="sub dir" FETCH_HEAD &&
 		git subtree split --prefix="sub dir" --message="Split & rejoin" --annotate="*" --rejoin &&
-		test "$(last_commit_message)" = "Split & rejoin"
+		test "$(last_commit_subject)" = "Split & rejoin"
 	)
 '
 
@@ -878,7 +878,7 @@ test_expect_success 'push split to subproj' '
 		git subtree push ./"sub proj" --prefix "sub dir" sub-branch-1 &&
 		cd ./"sub proj" &&
 		git checkout sub-branch-1 &&
-		test "$(last_commit_message)" = "sub dir/main-sub3"
+		test "$(last_commit_subject)" = "sub dir/main-sub3"
 	)
 '
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 10/30] subtree: t7900: add a test for the -h flag
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (8 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 09/30] subtree: t7900: rename last_commit_message to last_commit_subject Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-30 10:01       ` Ævar Arnfjörð Bjarmason
  2021-04-30 12:22       ` Bagas Sanjaya
  2021-04-27 21:17     ` [PATCH v3 11/30] subtree: t7900: add porcelain tests for 'pull' and 'push' Luke Shumaker
                       ` (19 subsequent siblings)
  29 siblings, 2 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

It's a dumb test, but it's surprisingly easy to break.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/t/t7900-subtree.sh | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 5c2510f1f5..9afba2f282 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -37,6 +37,13 @@ last_commit_subject () {
 	git log --pretty=format:%s -1
 }
 
+test_expect_success 'shows short help text for -h' '
+	test_expect_code 129 git subtree -h >out 2>err &&
+	test_must_be_empty err &&
+	grep -e "^ *or: git subtree pull" out &&
+	grep -e --annotate out
+'
+
 #
 # Tests for 'git subtree add'
 #
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 11/30] subtree: t7900: add porcelain tests for 'pull' and 'push'
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (9 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 10/30] subtree: t7900: add a test for the -h flag Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 12/30] subtree: don't have loose code outside of a function Luke Shumaker
                       ` (18 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

The 'pull' and 'push' subcommands deserve their own sections in the tests.
Add some basic tests for them.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - Don't switch unrelated uses of vanilla test_create_repo over to
   subtree_test_create_repo; this has been moved to happen in an
   earlier commit.
 - Fix whitespace.

 contrib/subtree/t/t7900-subtree.sh | 127 +++++++++++++++++++++++++++++
 1 file changed, 127 insertions(+)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 9afba2f282..ce6861c22d 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -427,6 +427,133 @@ test_expect_success 'split "sub dir"/ with --branch for an incompatible branch'
 	)
 '
 
+#
+# Tests for 'git subtree pull'
+#
+
+test_expect_success 'pull requires option --prefix' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	(
+		cd "$test_count" &&
+		test_must_fail git subtree pull ./"sub proj" HEAD >out 2>err &&
+
+		echo "You must provide the --prefix option." >expected &&
+		test_must_be_empty out &&
+		test_cmp expected err
+	)
+'
+
+test_expect_success 'pull requires path given by option --prefix must exist' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		test_must_fail git subtree pull --prefix="sub dir" ./"sub proj" HEAD >out 2>err &&
+
+		echo "'\''sub dir'\'' does not exist; use '\''git subtree add'\''" >expected &&
+		test_must_be_empty out &&
+		test_cmp expected err
+	)
+'
+
+test_expect_success 'pull basic operation' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	(
+		cd "$test_count" &&
+		exp=$(git -C "sub proj" rev-parse --verify HEAD:) &&
+		git subtree pull --prefix="sub dir" ./"sub proj" HEAD &&
+		act=$(git rev-parse --verify HEAD:"sub dir") &&
+		test "$act" = "$exp"
+	)
+'
+
+#
+# Tests for 'git subtree push'
+#
+
+test_expect_success 'push requires option --prefix' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD &&
+		echo "You must provide the --prefix option." >expected &&
+		test_must_fail git subtree push "./sub proj" from-mainline >actual 2>&1 &&
+		test_debug "printf '"expected: "'" &&
+		test_debug "cat expected" &&
+		test_debug "printf '"actual: "'" &&
+		test_debug "cat actual" &&
+		test_cmp expected actual
+	)
+'
+
+test_expect_success 'push requires path given by option --prefix must exist' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD &&
+		echo "'\''non-existent-directory'\'' does not exist; use '\''git subtree add'\''" >expected &&
+		test_must_fail git subtree push --prefix=non-existent-directory "./sub proj" from-mainline >actual 2>&1 &&
+		test_debug "printf '"expected: "'" &&
+		test_debug "cat expected" &&
+		test_debug "printf '"actual: "'" &&
+		test_debug "cat actual" &&
+		test_cmp expected actual
+	)
+'
+
+test_expect_success 'push basic operation' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		before=$(git rev-parse --verify HEAD) &&
+		split_hash=$(git subtree split --prefix="sub dir") &&
+		git subtree push --prefix="sub dir" ./"sub proj" from-mainline &&
+		test "$before" = "$(git rev-parse --verify HEAD)" &&
+		test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
 #
 # Validity checking
 #
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 12/30] subtree: don't have loose code outside of a function
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (10 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 11/30] subtree: t7900: add porcelain tests for 'pull' and 'push' Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 13/30] subtree: more consistent error propagation Luke Shumaker
                       ` (17 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Shove all of the loose code inside of a main() function.

This comes down to personal preference more than anything else.  A
preference that I've developed over years of maintaining large Bash
scripts, but still a mere personal preference.

In this specific case, it's also moving the `set -- -h`, the `git
rev-parse --parseopt`, and the `. git-sh-setup` to be closer to all
the rest of the argument parsing, which is a readability win on its
own, IMO.

"Ignore space change" is probably helpful when viewing this diff.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - Include rationale in the the commit message.

 contrib/subtree/git-subtree.sh | 245 +++++++++++++++++----------------
 1 file changed, 125 insertions(+), 120 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 868e18b9a1..d1ed7f9a6c 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -4,10 +4,7 @@
 #
 # Copyright (C) 2009 Avery Pennarun <apenwarr@gmail.com>
 #
-if test $# -eq 0
-then
-	set -- -h
-fi
+
 OPTS_SPEC="\
 git subtree add   --prefix=<prefix> <commit>
 git subtree add   --prefix=<prefix> <repository> <ref>
@@ -30,12 +27,8 @@ rejoin        merge the new branch back into HEAD
  options for 'add', 'merge', and 'pull'
 squash        merge subtree changes as a single commit
 "
-eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
 
 PATH=$PATH:$(git --exec-path)
-. git-sh-setup
-
-require_work_tree
 
 quiet=
 branch=
@@ -84,126 +77,138 @@ ensure_single_rev () {
 	fi
 }
 
-while test $# -gt 0
-do
-	opt="$1"
-	shift
+main () {
+	if test $# -eq 0
+	then
+		set -- -h
+	fi
+	eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
+	. git-sh-setup
+	require_work_tree
 
-	case "$opt" in
-	-q)
-		quiet=1
-		;;
-	-d)
-		debug=1
-		;;
-	--annotate)
-		annotate="$1"
-		shift
-		;;
-	--no-annotate)
-		annotate=
-		;;
-	-b)
-		branch="$1"
-		shift
-		;;
-	-P)
-		prefix="${1%/}"
-		shift
-		;;
-	-m)
-		message="$1"
-		shift
-		;;
-	--no-prefix)
-		prefix=
-		;;
-	--onto)
-		onto="$1"
+	while test $# -gt 0
+	do
+		opt="$1"
 		shift
+
+		case "$opt" in
+		-q)
+			quiet=1
+			;;
+		-d)
+			debug=1
+			;;
+		--annotate)
+			annotate="$1"
+			shift
+			;;
+		--no-annotate)
+			annotate=
+			;;
+		-b)
+			branch="$1"
+			shift
+			;;
+		-P)
+			prefix="${1%/}"
+			shift
+			;;
+		-m)
+			message="$1"
+			shift
+			;;
+		--no-prefix)
+			prefix=
+			;;
+		--onto)
+			onto="$1"
+			shift
+			;;
+		--no-onto)
+			onto=
+			;;
+		--rejoin)
+			rejoin=1
+			;;
+		--no-rejoin)
+			rejoin=
+			;;
+		--ignore-joins)
+			ignore_joins=1
+			;;
+		--no-ignore-joins)
+			ignore_joins=
+			;;
+		--squash)
+			squash=1
+			;;
+		--no-squash)
+			squash=
+			;;
+		--)
+			break
+			;;
+		*)
+			die "Unexpected option: $opt"
+			;;
+		esac
+	done
+
+	command="$1"
+	shift
+
+	case "$command" in
+	add|merge|pull)
+		default=
 		;;
-	--no-onto)
-		onto=
-		;;
-	--rejoin)
-		rejoin=1
-		;;
-	--no-rejoin)
-		rejoin=
-		;;
-	--ignore-joins)
-		ignore_joins=1
-		;;
-	--no-ignore-joins)
-		ignore_joins=
-		;;
-	--squash)
-		squash=1
+	split|push)
+		default="--default HEAD"
 		;;
-	--no-squash)
-		squash=
+	*)
+		die "Unknown command '$command'"
 		;;
-	--)
-		break
+	esac
+
+	if test -z "$prefix"
+	then
+		die "You must provide the --prefix option."
+	fi
+
+	case "$command" in
+	add)
+		test -e "$prefix" &&
+			die "prefix '$prefix' already exists."
 		;;
 	*)
-		die "Unexpected option: $opt"
+		test -e "$prefix" ||
+			die "'$prefix' does not exist; use 'git subtree add'"
 		;;
 	esac
-done
-
-command="$1"
-shift
-
-case "$command" in
-add|merge|pull)
-	default=
-	;;
-split|push)
-	default="--default HEAD"
-	;;
-*)
-	die "Unknown command '$command'"
-	;;
-esac
-
-if test -z "$prefix"
-then
-	die "You must provide the --prefix option."
-fi
-
-case "$command" in
-add)
-	test -e "$prefix" &&
-		die "prefix '$prefix' already exists."
-	;;
-*)
-	test -e "$prefix" ||
-		die "'$prefix' does not exist; use 'git subtree add'"
-	;;
-esac
-
-dir="$(dirname "$prefix/.")"
-
-if test "$command" != "pull" &&
-		test "$command" != "add" &&
-		test "$command" != "push"
-then
-	revs=$(git rev-parse $default --revs-only "$@") || exit $?
-	dirs=$(git rev-parse --no-revs --no-flags "$@") || exit $?
-	ensure_single_rev $revs
-	if test -n "$dirs"
-	then
-		die "Error: Use --prefix instead of bare filenames."
-	fi
-fi
-
-debug "command: {$command}"
-debug "quiet: {$quiet}"
-debug "revs: {$revs}"
-debug "dir: {$dir}"
-debug "opts: {$*}"
-debug
+
+	dir="$(dirname "$prefix/.")"
+
+	if test "$command" != "pull" &&
+			test "$command" != "add" &&
+			test "$command" != "push"
+	then
+		revs=$(git rev-parse $default --revs-only "$@") || exit $?
+		dirs=$(git rev-parse --no-revs --no-flags "$@") || exit $?
+		ensure_single_rev $revs
+		if test -n "$dirs"
+		then
+			die "Error: Use --prefix instead of bare filenames."
+		fi
+	fi
+
+	debug "command: {$command}"
+	debug "quiet: {$quiet}"
+	debug "revs: {$revs}"
+	debug "dir: {$dir}"
+	debug "opts: {$*}"
+	debug
+
+	"cmd_$command" "$@"
+}
 
 cache_setup () {
 	cachedir="$GIT_DIR/subtree-cache/$$"
@@ -898,4 +903,4 @@ cmd_push () {
 	fi
 }
 
-"cmd_$command" "$@"
+main "$@"
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 13/30] subtree: more consistent error propagation
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (11 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 12/30] subtree: don't have loose code outside of a function Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 14/30] subtree: drop support for git < 1.7 Luke Shumaker
                       ` (16 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Ensure that every $(subshell) that calls a function (as opposed to an
external executable) is followed by `|| exit $?`.  Similarly, ensure that
every `cmd | while read; do ... done` loop is followed by `|| exit $?`.

Both of those constructs mean that it can miss `die` calls, and keep
running when it shouldn't.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index d1ed7f9a6c..9ca498f81c 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -243,7 +243,7 @@ cache_miss () {
 }
 
 check_parents () {
-	missed=$(cache_miss "$1")
+	missed=$(cache_miss "$1") || exit $?
 	local indent=$(($2 + 1))
 	for miss in $missed
 	do
@@ -345,7 +345,7 @@ find_latest_squash () {
 			sub=
 			;;
 		esac
-	done
+	done || exit $?
 }
 
 find_existing_splits () {
@@ -394,7 +394,7 @@ find_existing_splits () {
 			sub=
 			;;
 		esac
-	done
+	done || exit $?
 }
 
 copy_commit () {
@@ -508,7 +508,7 @@ subtree_for_commit () {
 		test "$type" = "commit" && continue  # ignore submodules
 		echo $tree
 		break
-	done
+	done || exit $?
 }
 
 tree_changed () {
@@ -518,7 +518,7 @@ tree_changed () {
 	then
 		return 0   # weird parents, consider it changed
 	else
-		ptree=$(toptree_for_commit $1)
+		ptree=$(toptree_for_commit $1) || exit $?
 		if test "$ptree" != "$tree"
 		then
 			return 0   # changed
@@ -652,7 +652,7 @@ process_split_commit () {
 	progress "$revcount/$revmax ($createcount) [$extracount]"
 
 	debug "Processing commit: $rev"
-	exists=$(cache_get "$rev")
+	exists=$(cache_get "$rev") || exit $?
 	if test -n "$exists"
 	then
 		debug "  prior: $exists"
@@ -661,10 +661,10 @@ process_split_commit () {
 	createcount=$(($createcount + 1))
 	debug "  parents: $parents"
 	check_parents "$parents" "$indent"
-	newparents=$(cache_get $parents)
+	newparents=$(cache_get $parents) || exit $?
 	debug "  newparents: $newparents"
 
-	tree=$(subtree_for_commit "$rev" "$dir")
+	tree=$(subtree_for_commit "$rev" "$dir") || exit $?
 	debug "  tree is: $tree"
 
 	# ugly.  is there no better way to tell if this is a subtree
@@ -750,7 +750,7 @@ cmd_add_commit () {
 		commit=$(add_squashed_msg "$rev" "$dir" |
 			git commit-tree "$tree" $headp -p "$rev") || exit $?
 	else
-		revp=$(peel_committish "$rev") &&
+		revp=$(peel_committish "$rev") || exit $?
 		commit=$(add_msg "$dir" $headrev "$rev" |
 			git commit-tree "$tree" $headp -p "$revp") || exit $?
 	fi
@@ -773,10 +773,10 @@ cmd_split () {
 			# any parent we find there can be used verbatim
 			debug "  cache: $rev"
 			cache_set "$rev" "$rev"
-		done
+		done || exit $?
 	fi
 
-	unrevs="$(find_existing_splits "$dir" "$revs")"
+	unrevs="$(find_existing_splits "$dir" "$revs")" || exit $?
 
 	# We can't restrict rev-list to only $dir here, because some of our
 	# parents have the $dir contents the root, and those won't match.
@@ -792,7 +792,7 @@ cmd_split () {
 		process_split_commit "$rev" "$parents" 0
 	done || exit $?
 
-	latest_new=$(cache_get latest_new)
+	latest_new=$(cache_get latest_new) || exit $?
 	if test -z "$latest_new"
 	then
 		die "No new revisions were found"
@@ -801,7 +801,7 @@ cmd_split () {
 	if test -n "$rejoin"
 	then
 		debug "Merging split branch into HEAD..."
-		latest_old=$(cache_get latest_old)
+		latest_old=$(cache_get latest_old) || exit $?
 		git merge -s ours \
 			--allow-unrelated-histories \
 			-m "$(rejoin_msg "$dir" "$latest_old" "$latest_new")" \
@@ -834,7 +834,7 @@ cmd_merge () {
 
 	if test -n "$squash"
 	then
-		first_split="$(find_latest_squash "$dir")"
+		first_split="$(find_latest_squash "$dir")" || exit $?
 		if test -z "$first_split"
 		then
 			die "Can't squash-merge: '$dir' was never added."
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 14/30] subtree: drop support for git < 1.7
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (12 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 13/30] subtree: more consistent error propagation Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 15/30] subtree: use `git merge-base --is-ancestor` Luke Shumaker
                       ` (15 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Suport for Git versions older than 1.7.0 (older than February 2010) was
nice to have when git-subtree lived out-of-tree.  But now that it lives
in git.git, it's not necessary to keep around.  While it's technically
in contrib, with the standard 'git' packages for common systems
(including Arch Linux and macOS) including git-subtree, it seems
vanishingly likely to me that people are separately installing
git-subtree from git.git alongside an older 'git' install (although it
also seems vanishingly likely that people are still using >11 year old
git installs).

Not that there's much reason to remove it either, it's not much code,
and none of my changes depend on a newer git (to my knowledge, anyway;
I'm not actually testing against older git).  I just figure it's an easy
piece of fat to trim, in the journey to making the whole thing easier to
hack on.

"Ignore space change" is probably helpful when viewing this diff.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - Include rationale in the the commit message.

 contrib/subtree/git-subtree.sh | 19 ++++---------------
 1 file changed, 4 insertions(+), 15 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 9ca498f81c..4503564f7e 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -852,23 +852,12 @@ cmd_merge () {
 		rev="$new"
 	fi
 
-	version=$(git version)
-	if test "$version" \< "git version 1.7"
+	if test -n "$message"
 	then
-		if test -n "$message"
-		then
-			git merge -s subtree --message="$message" "$rev"
-		else
-			git merge -s subtree "$rev"
-		fi
+		git merge -Xsubtree="$prefix" \
+		    --message="$message" "$rev"
 	else
-		if test -n "$message"
-		then
-			git merge -Xsubtree="$prefix" \
-				--message="$message" "$rev"
-		else
-			git merge -Xsubtree="$prefix" $rev
-		fi
+		git merge -Xsubtree="$prefix" $rev
 	fi
 }
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 15/30] subtree: use `git merge-base --is-ancestor`
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (13 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 14/30] subtree: drop support for git < 1.7 Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 16/30] subtree: use git-sh-setup's `say` Luke Shumaker
                       ` (14 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Instead of writing a slow `rev_is_descendant_of_branch $a $b` function
in shell, just use the fast `git merge-base --is-ancestor $b $a`.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 16 +---------------
 1 file changed, 1 insertion(+), 15 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 4503564f7e..70e16b807b 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -280,20 +280,6 @@ rev_exists () {
 	fi
 }
 
-rev_is_descendant_of_branch () {
-	newrev="$1"
-	branch="$2"
-	branch_hash=$(git rev-parse "$branch")
-	match=$(git rev-list -1 "$branch_hash" "^$newrev")
-
-	if test -z "$match"
-	then
-		return 0
-	else
-		return 1
-	fi
-}
-
 # if a commit doesn't have a parent, this might not work.  But we only want
 # to remove the parent from the rev-list, and since it doesn't exist, it won't
 # be there anyway, so do nothing in that case.
@@ -811,7 +797,7 @@ cmd_split () {
 	then
 		if rev_exists "refs/heads/$branch"
 		then
-			if ! rev_is_descendant_of_branch "$latest_new" "$branch"
+			if ! git merge-base --is-ancestor "$branch" "$latest_new"
 			then
 				die "Branch '$branch' is not an ancestor of commit '$latest_new'."
 			fi
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 16/30] subtree: use git-sh-setup's `say`
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (14 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 15/30] subtree: use `git merge-base --is-ancestor` Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 17/30] subtree: use more explicit variable names for cmdline args Luke Shumaker
                       ` (13 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

subtree currently defines its own `say` implementation, rather than
using git-sh-setups's implementation.  Change that, don't re-invent the
wheel.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 22 +++++++---------------
 1 file changed, 7 insertions(+), 15 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 70e16b807b..bb4934dbc0 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -30,7 +30,6 @@ squash        merge subtree changes as a single commit
 
 PATH=$PATH:$(git --exec-path)
 
-quiet=
 branch=
 debug=
 command=
@@ -49,15 +48,8 @@ debug () {
 	fi
 }
 
-say () {
-	if test -z "$quiet"
-	then
-		printf "%s\n" "$*" >&2
-	fi
-}
-
 progress () {
-	if test -z "$quiet"
+	if test -z "$GIT_QUIET"
 	then
 		printf "%s\r" "$*" >&2
 	fi
@@ -93,7 +85,7 @@ main () {
 
 		case "$opt" in
 		-q)
-			quiet=1
+			GIT_QUIET=1
 			;;
 		-d)
 			debug=1
@@ -201,7 +193,7 @@ main () {
 	fi
 
 	debug "command: {$command}"
-	debug "quiet: {$quiet}"
+	debug "quiet: {$GIT_QUIET}"
 	debug "revs: {$revs}"
 	debug "dir: {$dir}"
 	debug "opts: {$*}"
@@ -698,7 +690,7 @@ cmd_add () {
 
 		cmd_add_repository "$@"
 	else
-		say "error: parameters were '$@'"
+		say >&2 "error: parameters were '$@'"
 		die "Provide either a commit or a repository and commit."
 	fi
 }
@@ -742,7 +734,7 @@ cmd_add_commit () {
 	fi
 	git reset "$commit" || exit $?
 
-	say "Added dir '$dir'"
+	say >&2 "Added dir '$dir'"
 }
 
 cmd_split () {
@@ -807,7 +799,7 @@ cmd_split () {
 		fi
 		git update-ref -m 'subtree split' \
 			"refs/heads/$branch" "$latest_new" || exit $?
-		say "$action branch '$branch'"
+		say >&2 "$action branch '$branch'"
 	fi
 	echo "$latest_new"
 	exit 0
@@ -830,7 +822,7 @@ cmd_merge () {
 		sub=$2
 		if test "$sub" = "$rev"
 		then
-			say "Subtree is already at commit $rev."
+			say >&2 "Subtree is already at commit $rev."
 			exit 0
 		fi
 		new=$(new_squash_commit "$old" "$sub" "$rev") || exit $?
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 17/30] subtree: use more explicit variable names for cmdline args
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (15 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 16/30] subtree: use git-sh-setup's `say` Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 18/30] subtree: use "$*" instead of "$@" as appropriate Luke Shumaker
                       ` (12 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Make it painfully obvious when reading the code which variables are
direct parsings of command line arguments.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 132 ++++++++++++++++-----------------
 1 file changed, 66 insertions(+), 66 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index bb4934dbc0..d7de4b0653 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -30,19 +30,19 @@ squash        merge subtree changes as a single commit
 
 PATH=$PATH:$(git --exec-path)
 
-branch=
-debug=
-command=
-onto=
-rejoin=
-ignore_joins=
-annotate=
-squash=
-message=
-prefix=
+arg_debug=
+arg_command=
+arg_prefix=
+arg_split_branch=
+arg_split_onto=
+arg_split_rejoin=
+arg_split_ignore_joins=
+arg_split_annotate=
+arg_addmerge_squash=
+arg_addmerge_message=
 
 debug () {
-	if test -n "$debug"
+	if test -n "$arg_debug"
 	then
 		printf "%s\n" "$*" >&2
 	fi
@@ -88,54 +88,54 @@ main () {
 			GIT_QUIET=1
 			;;
 		-d)
-			debug=1
+			arg_debug=1
 			;;
 		--annotate)
-			annotate="$1"
+			arg_split_annotate="$1"
 			shift
 			;;
 		--no-annotate)
-			annotate=
+			arg_split_annotate=
 			;;
 		-b)
-			branch="$1"
+			arg_split_branch="$1"
 			shift
 			;;
 		-P)
-			prefix="${1%/}"
+			arg_prefix="${1%/}"
 			shift
 			;;
 		-m)
-			message="$1"
+			arg_addmerge_message="$1"
 			shift
 			;;
 		--no-prefix)
-			prefix=
+			arg_prefix=
 			;;
 		--onto)
-			onto="$1"
+			arg_split_onto="$1"
 			shift
 			;;
 		--no-onto)
-			onto=
+			arg_split_onto=
 			;;
 		--rejoin)
-			rejoin=1
+			arg_split_rejoin=1
 			;;
 		--no-rejoin)
-			rejoin=
+			arg_split_rejoin=
 			;;
 		--ignore-joins)
-			ignore_joins=1
+			arg_split_ignore_joins=1
 			;;
 		--no-ignore-joins)
-			ignore_joins=
+			arg_split_ignore_joins=
 			;;
 		--squash)
-			squash=1
+			arg_addmerge_squash=1
 			;;
 		--no-squash)
-			squash=
+			arg_addmerge_squash=
 			;;
 		--)
 			break
@@ -146,10 +146,10 @@ main () {
 		esac
 	done
 
-	command="$1"
+	arg_command="$1"
 	shift
 
-	case "$command" in
+	case "$arg_command" in
 	add|merge|pull)
 		default=
 		;;
@@ -157,31 +157,31 @@ main () {
 		default="--default HEAD"
 		;;
 	*)
-		die "Unknown command '$command'"
+		die "Unknown command '$arg_command'"
 		;;
 	esac
 
-	if test -z "$prefix"
+	if test -z "$arg_prefix"
 	then
 		die "You must provide the --prefix option."
 	fi
 
-	case "$command" in
+	case "$arg_command" in
 	add)
-		test -e "$prefix" &&
-			die "prefix '$prefix' already exists."
+		test -e "$arg_prefix" &&
+			die "prefix '$arg_prefix' already exists."
 		;;
 	*)
-		test -e "$prefix" ||
-			die "'$prefix' does not exist; use 'git subtree add'"
+		test -e "$arg_prefix" ||
+			die "'$arg_prefix' does not exist; use 'git subtree add'"
 		;;
 	esac
 
-	dir="$(dirname "$prefix/.")"
+	dir="$(dirname "$arg_prefix/.")"
 
-	if test "$command" != "pull" &&
-			test "$command" != "add" &&
-			test "$command" != "push"
+	if test "$arg_command" != "pull" &&
+			test "$arg_command" != "add" &&
+			test "$arg_command" != "push"
 	then
 		revs=$(git rev-parse $default --revs-only "$@") || exit $?
 		dirs=$(git rev-parse --no-revs --no-flags "$@") || exit $?
@@ -192,14 +192,14 @@ main () {
 		fi
 	fi
 
-	debug "command: {$command}"
+	debug "command: {$arg_command}"
 	debug "quiet: {$GIT_QUIET}"
 	debug "revs: {$revs}"
 	debug "dir: {$dir}"
 	debug "opts: {$*}"
 	debug
 
-	"cmd_$command" "$@"
+	"cmd_$arg_command" "$@"
 }
 
 cache_setup () {
@@ -333,7 +333,7 @@ find_existing_splits () {
 	main=
 	sub=
 	local grep_format="^git-subtree-dir: $dir/*\$"
-	if test -n "$ignore_joins"
+	if test -n "$arg_split_ignore_joins"
 	then
 		grep_format="^Add '$dir/' from commit '"
 	fi
@@ -394,7 +394,7 @@ copy_commit () {
 			GIT_COMMITTER_EMAIL \
 			GIT_COMMITTER_DATE
 		(
-			printf "%s" "$annotate"
+			printf "%s" "$arg_split_annotate"
 			cat
 		) |
 		git commit-tree "$2" $3  # reads the rest of stdin
@@ -405,9 +405,9 @@ add_msg () {
 	dir="$1"
 	latest_old="$2"
 	latest_new="$3"
-	if test -n "$message"
+	if test -n "$arg_addmerge_message"
 	then
-		commit_message="$message"
+		commit_message="$arg_addmerge_message"
 	else
 		commit_message="Add '$dir/' from commit '$latest_new'"
 	fi
@@ -421,9 +421,9 @@ add_msg () {
 }
 
 add_squashed_msg () {
-	if test -n "$message"
+	if test -n "$arg_addmerge_message"
 	then
-		echo "$message"
+		echo "$arg_addmerge_message"
 	else
 		echo "Merge commit '$1' as '$2'"
 	fi
@@ -433,9 +433,9 @@ rejoin_msg () {
 	dir="$1"
 	latest_old="$2"
 	latest_new="$3"
-	if test -n "$message"
+	if test -n "$arg_addmerge_message"
 	then
-		commit_message="$message"
+		commit_message="$arg_addmerge_message"
 	else
 		commit_message="Split '$dir/' into commit '$latest_new'"
 	fi
@@ -722,7 +722,7 @@ cmd_add_commit () {
 		headp=
 	fi
 
-	if test -n "$squash"
+	if test -n "$arg_addmerge_squash"
 	then
 		rev=$(new_squash_commit "" "" "$rev") || exit $?
 		commit=$(add_squashed_msg "$rev" "$dir" |
@@ -741,10 +741,10 @@ cmd_split () {
 	debug "Splitting $dir..."
 	cache_setup || exit $?
 
-	if test -n "$onto"
+	if test -n "$arg_split_onto"
 	then
-		debug "Reading history for --onto=$onto..."
-		git rev-list $onto |
+		debug "Reading history for --onto=$arg_split_onto..."
+		git rev-list $arg_split_onto |
 		while read rev
 		do
 			# the 'onto' history is already just the subdir, so
@@ -776,7 +776,7 @@ cmd_split () {
 		die "No new revisions were found"
 	fi
 
-	if test -n "$rejoin"
+	if test -n "$arg_split_rejoin"
 	then
 		debug "Merging split branch into HEAD..."
 		latest_old=$(cache_get latest_old) || exit $?
@@ -785,21 +785,21 @@ cmd_split () {
 			-m "$(rejoin_msg "$dir" "$latest_old" "$latest_new")" \
 			"$latest_new" >&2 || exit $?
 	fi
-	if test -n "$branch"
+	if test -n "$arg_split_branch"
 	then
-		if rev_exists "refs/heads/$branch"
+		if rev_exists "refs/heads/$arg_split_branch"
 		then
-			if ! git merge-base --is-ancestor "$branch" "$latest_new"
+			if ! git merge-base --is-ancestor "$arg_split_branch" "$latest_new"
 			then
-				die "Branch '$branch' is not an ancestor of commit '$latest_new'."
+				die "Branch '$arg_split_branch' is not an ancestor of commit '$latest_new'."
 			fi
 			action='Updated'
 		else
 			action='Created'
 		fi
 		git update-ref -m 'subtree split' \
-			"refs/heads/$branch" "$latest_new" || exit $?
-		say >&2 "$action branch '$branch'"
+			"refs/heads/$arg_split_branch" "$latest_new" || exit $?
+		say >&2 "$action branch '$arg_split_branch'"
 	fi
 	echo "$latest_new"
 	exit 0
@@ -810,7 +810,7 @@ cmd_merge () {
 	ensure_single_rev $rev
 	ensure_clean
 
-	if test -n "$squash"
+	if test -n "$arg_addmerge_squash"
 	then
 		first_split="$(find_latest_squash "$dir")" || exit $?
 		if test -z "$first_split"
@@ -830,12 +830,12 @@ cmd_merge () {
 		rev="$new"
 	fi
 
-	if test -n "$message"
+	if test -n "$arg_addmerge_message"
 	then
-		git merge -Xsubtree="$prefix" \
-		    --message="$message" "$rev"
+		git merge -Xsubtree="$arg_prefix" \
+			--message="$arg_addmerge_message" "$rev"
 	else
-		git merge -Xsubtree="$prefix" $rev
+		git merge -Xsubtree="$arg_prefix" $rev
 	fi
 }
 
@@ -863,7 +863,7 @@ cmd_push () {
 		repository=$1
 		refspec=$2
 		echo "git push using: " "$repository" "$refspec"
-		localrev=$(git subtree split --prefix="$prefix") || die
+		localrev=$(git subtree split --prefix="$arg_prefix") || die
 		git push "$repository" "$localrev":"refs/heads/$refspec"
 	else
 		die "'$dir' must already exist. Try 'git subtree add'."
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 18/30] subtree: use "$*" instead of "$@" as appropriate
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (16 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 17/30] subtree: use more explicit variable names for cmdline args Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 19/30] subtree: don't fuss with PATH Luke Shumaker
                       ` (11 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

"$*" is for when you want to concatenate the args together,
whitespace-separated; and "$@" is for when you want them to be separate
strings.

There are several places in subtree that erroneously use $@ when
concatenating args together into an error message.

For instance, if the args are argv[1]="dead" and argv[2]="beef", then
the line

    die "You must provide exactly one revision.  Got: '$@'"

surely intends to call 'die' with the argument

    argv[1]="You must provide exactly one revision.  Got: 'dead beef'"

however, because the line used $@ instead of $*, it will actually call
'die' with the arguments

    argv[1]="You must provide exactly one revision.  Got: 'dead"
    argv[2]="beef'"

This isn't a big deal, because 'die' concatenates its arguments together
anyway (using "$*").  But that doesn't change the fact that it was a
mistake to use $@ instead of $*, even though in the end $@ still ended
up doing the right thing.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - Improve the commit message with quoting and clearer
   explanation.

 contrib/subtree/git-subtree.sh | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index d7de4b0653..3105eb8033 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -58,14 +58,14 @@ progress () {
 assert () {
 	if ! "$@"
 	then
-		die "assertion failed: " "$@"
+		die "assertion failed: $*"
 	fi
 }
 
 ensure_single_rev () {
 	if test $# -ne 1
 	then
-		die "You must provide exactly one revision.  Got: '$@'"
+		die "You must provide exactly one revision.  Got: '$*'"
 	fi
 }
 
@@ -690,7 +690,7 @@ cmd_add () {
 
 		cmd_add_repository "$@"
 	else
-		say >&2 "error: parameters were '$@'"
+		say >&2 "error: parameters were '$*'"
 		die "Provide either a commit or a repository and commit."
 	fi
 }
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 19/30] subtree: don't fuss with PATH
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (17 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 18/30] subtree: use "$*" instead of "$@" as appropriate Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 20/30] subtree: use "^{commit}" instead of "^0" Luke Shumaker
                       ` (10 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Scripts needing to fuss with with adding $(git --exec-prefix) PATH
before loading git-sh-setup is a thing of the past.  As far as I can
tell, it's been a thing of the past since since Git v1.2.0 (2006-02-12),
or more specifically, since 77cb17e940 (Exec git programs without using
PATH, 2006-01-10).  However, it stuck around in contrib scripts and in
third-party scripts for long enough that it wasn't unusual to see.

Originally `git subtree` didn't fuss with PATH, but when people
(including the original subtree author) had problems, because it was a
common thing to see, it seemed that having subtree fuss with PATH was a
reasonable solution.

Here is an abridged history of fussing with PATH in subtree:

  2987e6add3 (Add explicit path of git installation by 'git --exec-path', Gianluca Pacchiella, 2009-08-20)

    As pointed out by documentation, the correct use of 'git-sh-setup' is
    using $(git --exec-path) to avoid problems with not standard
    installations.

    -. git-sh-setup
    +. $(git --exec-path)/git-sh-setup

  33aaa697a2 (Improve patch to use git --exec-path: add to PATH instead, Avery Pennarun, 2009-08-26)

    If you (like me) are using a modified git straight out of its source
    directory (ie. without installing), then --exec-path isn't actually correct.
    Add it to the PATH instead, so if it is correct, it'll work, but if it's
    not, we fall back to the previous behaviour.

    -. $(git --exec-path)/git-sh-setup
    +PATH=$(git --exec-path):$PATH
    +. git-sh-setup

  9c632ea29c ((Hopefully) fix PATH setting for msysgit, Avery Pennarun, 2010-06-24)

    Reported by Evan Shaw.  The problem is that $(git --exec-path) includes a
    'git' binary which is incompatible with the one in /usr/bin; if you run it,
    it gives you an error about libiconv2.dll.

    +OPATH=$PATH
     PATH=$(git --exec-path):$PATH
     . git-sh-setup
    +PATH=$OPATH  # apparently needed for some versions of msysgit

  df2302d774 (Another fix for PATH and msysgit, Avery Pennarun, 2010-06-24)

    Evan Shaw tells me the previous fix didn't work.  Let's use this one
    instead, which he says does work.

    This fix is kind of wrong because it will run the "correct" git-sh-setup
    *after* the one in /usr/bin, if there is one, which could be weird if you
    have multiple versions of git installed.  But it works on my Linux and his
    msysgit, so it's obviously better than what we had before.

    -OPATH=$PATH
    -PATH=$(git --exec-path):$PATH
    +PATH=$PATH:$(git --exec-path)
     . git-sh-setup
    -PATH=$OPATH  # apparently needed for some versions of msysgit

First of all, I disagree with Gianluca's reading of the documentation:
 - I haven't gone back to read what the documentation said in 2009, but
   in my reading of the 2021 documentation is that it includes "$(git
   --exec-path)/" in the synopsis for illustrative purposes, not to say
   it's the proper way.
 - After being executed by `git`, the git exec path should be the very
   first entry in PATH, so it shouldn't matter.
 - None of the scripts that are part of git do it that way.

But secondly, the root reason for fussing with PATH seems to be that
Avery didn't know that he needs to set GIT_EXEC_PATH if he's going to
use git from the source directory without installing.

And finally, Evan's issue is clearly just a bug in msysgit.  I assume
that msysgit has since fixed the issue, and also msysgit has been
deprecated for 6 years now, so let's drop the workaround for it.

So, remove the line fussing with PATH.  However, since subtree *is* in
'contrib/' and it might get installed in funny ways by users
after-the-fact, add a sanity check to the top of the script, checking
that it is installed correctly.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v3:
 - Fix capitalization in the commit message.

 contrib/subtree/git-subtree.sh | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 3105eb8033..af636fbb43 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -5,6 +5,22 @@
 # Copyright (C) 2009 Avery Pennarun <apenwarr@gmail.com>
 #
 
+if test -z "$GIT_EXEC_PATH" || test "${PATH#"${GIT_EXEC_PATH}:"}" = "$PATH" || ! test -f "$GIT_EXEC_PATH/git-sh-setup"
+then
+	echo >&2 'It looks like either your git installation or your'
+	echo >&2 'git-subtree installation is broken.'
+	echo >&2
+	echo >&2 "Tips:"
+	echo >&2 " - If \`git --exec-path\` does not print the correct path to"
+	echo >&2 "   your git install directory, then set the GIT_EXEC_PATH"
+	echo >&2 "   environment variable to the correct directory."
+	echo >&2 " - Make sure that your \`${0##*/}\` file is either in your"
+	echo >&2 "   PATH or in your git exec path (\`$(git --exec-path)\`)."
+	echo >&2 " - You should run git-subtree as \`git ${0##*/git-}\`,"
+	echo >&2 "   not as \`${0##*/}\`." >&2
+	exit 126
+fi
+
 OPTS_SPEC="\
 git subtree add   --prefix=<prefix> <commit>
 git subtree add   --prefix=<prefix> <repository> <ref>
@@ -28,8 +44,6 @@ rejoin        merge the new branch back into HEAD
 squash        merge subtree changes as a single commit
 "
 
-PATH=$PATH:$(git --exec-path)
-
 arg_debug=
 arg_command=
 arg_prefix=
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 20/30] subtree: use "^{commit}" instead of "^0"
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (18 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 19/30] subtree: don't fuss with PATH Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 21/30] subtree: parse revs in individual cmd_ functions Luke Shumaker
                       ` (9 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

They are synonyms.  Both are used in the file.  ^{commit} is clearer, so
"standardize" on that.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index af636fbb43..ee7fda3672 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -316,7 +316,7 @@ find_latest_squash () {
 			main="$b"
 			;;
 		git-subtree-split:)
-			sub="$(git rev-parse "$b^0")" ||
+			sub="$(git rev-parse "$b^{commit}")" ||
 			die "could not rev-parse split hash $b from commit $sq"
 			;;
 		END)
@@ -363,7 +363,7 @@ find_existing_splits () {
 			main="$b"
 			;;
 		git-subtree-split:)
-			sub="$(git rev-parse "$b^0")" ||
+			sub="$(git rev-parse "$b^{commit}")" ||
 			die "could not rev-parse split hash $b from commit $sq"
 			;;
 		END)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 21/30] subtree: parse revs in individual cmd_ functions
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (19 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 20/30] subtree: use "^{commit}" instead of "^0" Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 22/30] subtree: remove duplicate check Luke Shumaker
                       ` (8 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

The main argument parser goes ahead and tries to parse revs to make
things simpler for the sub-command implementations.  But, it includes
enough special cases for different sub-commands.  And it's difficult
having having to think about "is this info coming from an argument, or a
global variable?".  So the main argument parser's effort to make things
"simpler" ends up just making it more confusing and complicated.

Begone with the 'revs' global variable; parse 'rev=$(...)' as needed in
individual 'cmd_*' functions.

Begone with the 'default' global variable.  Its would-be value is
knowable just from which function we're in.

Begone with the 'ensure_single_rev' function.  Its functionality can be
achieved by passing '--verify' to 'git rev-parse'.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 62 +++++++++++++---------------------
 1 file changed, 24 insertions(+), 38 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index ee7fda3672..0df8d1b7d4 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -76,13 +76,6 @@ assert () {
 	fi
 }
 
-ensure_single_rev () {
-	if test $# -ne 1
-	then
-		die "You must provide exactly one revision.  Got: '$*'"
-	fi
-}
-
 main () {
 	if test $# -eq 0
 	then
@@ -164,11 +157,8 @@ main () {
 	shift
 
 	case "$arg_command" in
-	add|merge|pull)
-		default=
-		;;
-	split|push)
-		default="--default HEAD"
+	add|merge|pull|split|push)
+		:
 		;;
 	*)
 		die "Unknown command '$arg_command'"
@@ -193,22 +183,8 @@ main () {
 
 	dir="$(dirname "$arg_prefix/.")"
 
-	if test "$arg_command" != "pull" &&
-			test "$arg_command" != "add" &&
-			test "$arg_command" != "push"
-	then
-		revs=$(git rev-parse $default --revs-only "$@") || exit $?
-		dirs=$(git rev-parse --no-revs --no-flags "$@") || exit $?
-		ensure_single_rev $revs
-		if test -n "$dirs"
-		then
-			die "Error: Use --prefix instead of bare filenames."
-		fi
-	fi
-
 	debug "command: {$arg_command}"
 	debug "quiet: {$GIT_QUIET}"
-	debug "revs: {$revs}"
 	debug "dir: {$dir}"
 	debug "opts: {$*}"
 	debug
@@ -714,14 +690,13 @@ cmd_add_repository () {
 	repository=$1
 	refspec=$2
 	git fetch "$@" || exit $?
-	revs=FETCH_HEAD
-	set -- $revs
-	cmd_add_commit "$@"
+	cmd_add_commit FETCH_HEAD
 }
 
 cmd_add_commit () {
-	rev=$(git rev-parse $default --revs-only "$@") || exit $?
-	ensure_single_rev $rev
+	# The rev has already been validated by cmd_add(), we just
+	# need to normalize it.
+	rev=$(git rev-parse --verify "$1^{commit}") || exit $?
 
 	debug "Adding $dir as '$rev'..."
 	git read-tree --prefix="$dir" $rev || exit $?
@@ -752,6 +727,17 @@ cmd_add_commit () {
 }
 
 cmd_split () {
+	if test $# -eq 0
+	then
+		rev=$(git rev-parse HEAD)
+	elif test $# -eq 1
+	then
+		rev=$(git rev-parse -q --verify "$1^{commit}") ||
+			die "'$1' does not refer to a commit"
+	else
+		die "You must provide exactly one revision.  Got: '$*'"
+	fi
+
 	debug "Splitting $dir..."
 	cache_setup || exit $?
 
@@ -768,12 +754,12 @@ cmd_split () {
 		done || exit $?
 	fi
 
-	unrevs="$(find_existing_splits "$dir" "$revs")" || exit $?
+	unrevs="$(find_existing_splits "$dir" "$rev")" || exit $?
 
 	# We can't restrict rev-list to only $dir here, because some of our
 	# parents have the $dir contents the root, and those won't match.
 	# (and rev-list --follow doesn't seem to solve this)
-	grl='git rev-list --topo-order --reverse --parents $revs $unrevs'
+	grl='git rev-list --topo-order --reverse --parents $rev $unrevs'
 	revmax=$(eval "$grl" | wc -l)
 	revcount=0
 	createcount=0
@@ -820,8 +806,10 @@ cmd_split () {
 }
 
 cmd_merge () {
-	rev=$(git rev-parse $default --revs-only "$@") || exit $?
-	ensure_single_rev $rev
+	test $# -eq 1 ||
+		die "You must provide exactly one revision.  Got: '$*'"
+	rev=$(git rev-parse -q --verify "$1^{commit}") ||
+		die "'$1' does not refer to a commit"
 	ensure_clean
 
 	if test -n "$arg_addmerge_squash"
@@ -861,9 +849,7 @@ cmd_pull () {
 	ensure_clean
 	ensure_valid_ref_format "$2"
 	git fetch "$@" || exit $?
-	revs=FETCH_HEAD
-	set -- $revs
-	cmd_merge "$@"
+	cmd_merge FETCH_HEAD
 }
 
 cmd_push () {
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 22/30] subtree: remove duplicate check
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (20 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 21/30] subtree: parse revs in individual cmd_ functions Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 23/30] subtree: add comments and sanity checks Luke Shumaker
                       ` (7 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

`cmd_add` starts with a check that the directory doesn't yet exist.
However, the `main` function performs the exact same check before
calling `cmd_add`.  So remove the check from `cmd_add`.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 0df8d1b7d4..7fbd8481ed 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -655,10 +655,6 @@ process_split_commit () {
 }
 
 cmd_add () {
-	if test -e "$dir"
-	then
-		die "'$dir' already exists.  Cannot add."
-	fi
 
 	ensure_clean
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 23/30] subtree: add comments and sanity checks
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (21 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 22/30] subtree: remove duplicate check Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 24/30] subtree: don't let debug and progress output clash Luke Shumaker
                       ` (6 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

For each function in subtree, add a usage comment saying what the
arguments are, and add an `assert` checking the number of arguments.

In figuring out each thing's arguments in order to write those comments
and assertions, it turns out that find_existing_splits is written as if
it takes multiple 'revs', but it is in fact only ever passed a single
'rev':

	unrevs="$(find_existing_splits "$dir" "$rev")" || exit $?

So go ahead and codify that by documenting and asserting that it takes
exactly two arguments, one dir and one rev.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - Expand on the the commit message.
 - Fix capitalization in one of the comments.

 contrib/subtree/git-subtree.sh | 64 ++++++++++++++++++++++++++++++++--
 1 file changed, 61 insertions(+), 3 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 7fbd8481ed..441571c85a 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -55,6 +55,7 @@ arg_split_annotate=
 arg_addmerge_squash=
 arg_addmerge_message=
 
+# Usage: debug [MSG...]
 debug () {
 	if test -n "$arg_debug"
 	then
@@ -62,6 +63,7 @@ debug () {
 	fi
 }
 
+# Usage: progress [MSG...]
 progress () {
 	if test -z "$GIT_QUIET"
 	then
@@ -69,6 +71,7 @@ progress () {
 	fi
 }
 
+# Usage: assert CMD...
 assert () {
 	if ! "$@"
 	then
@@ -192,7 +195,9 @@ main () {
 	"cmd_$arg_command" "$@"
 }
 
+# Usage: cache_setup
 cache_setup () {
+	assert test $# = 0
 	cachedir="$GIT_DIR/subtree-cache/$$"
 	rm -rf "$cachedir" ||
 		die "Can't delete old cachedir: $cachedir"
@@ -203,6 +208,7 @@ cache_setup () {
 	debug "Using cachedir: $cachedir" >&2
 }
 
+# Usage: cache_get [REVS...]
 cache_get () {
 	for oldrev in "$@"
 	do
@@ -214,6 +220,7 @@ cache_get () {
 	done
 }
 
+# Usage: cache_miss [REVS...]
 cache_miss () {
 	for oldrev in "$@"
 	do
@@ -224,7 +231,9 @@ cache_miss () {
 	done
 }
 
+# Usage: check_parents PARENTS_EXPR INDENT
 check_parents () {
+	assert test $# = 2
 	missed=$(cache_miss "$1") || exit $?
 	local indent=$(($2 + 1))
 	for miss in $missed
@@ -237,11 +246,15 @@ check_parents () {
 	done
 }
 
+# Usage: set_notree REV
 set_notree () {
+	assert test $# = 1
 	echo "1" > "$cachedir/notree/$1"
 }
 
+# Usage: cache_set OLDREV NEWREV
 cache_set () {
+	assert test $# = 2
 	oldrev="$1"
 	newrev="$2"
 	if test "$oldrev" != "latest_old" &&
@@ -253,7 +266,9 @@ cache_set () {
 	echo "$newrev" >"$cachedir/$oldrev"
 }
 
+# Usage: rev_exists REV
 rev_exists () {
+	assert test $# = 1
 	if git rev-parse "$1" >/dev/null 2>&1
 	then
 		return 0
@@ -262,17 +277,22 @@ rev_exists () {
 	fi
 }
 
-# if a commit doesn't have a parent, this might not work.  But we only want
+# Usage: try_remove_previous REV
+#
+# If a commit doesn't have a parent, this might not work.  But we only want
 # to remove the parent from the rev-list, and since it doesn't exist, it won't
 # be there anyway, so do nothing in that case.
 try_remove_previous () {
+	assert test $# = 1
 	if rev_exists "$1^"
 	then
 		echo "^$1^"
 	fi
 }
 
+# Usage: find_latest_squash DIR
 find_latest_squash () {
+	assert test $# = 1
 	debug "Looking for latest squash ($dir)..."
 	dir="$1"
 	sq=
@@ -316,10 +336,12 @@ find_latest_squash () {
 	done || exit $?
 }
 
+# Usage: find_existing_splits DIR REV
 find_existing_splits () {
+	assert test $# = 2
 	debug "Looking for prior splits..."
 	dir="$1"
-	revs="$2"
+	rev="$2"
 	main=
 	sub=
 	local grep_format="^git-subtree-dir: $dir/*\$"
@@ -328,7 +350,7 @@ find_existing_splits () {
 		grep_format="^Add '$dir/' from commit '"
 	fi
 	git log --grep="$grep_format" \
-		--no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' $revs |
+		--no-show-signature --pretty=format:'START %H%n%s%n%n%b%nEND%n' "$rev" |
 	while read a b junk
 	do
 		case "$a" in
@@ -365,7 +387,9 @@ find_existing_splits () {
 	done || exit $?
 }
 
+# Usage: copy_commit REV TREE FLAGS_STR
 copy_commit () {
+	assert test $# = 3
 	# We're going to set some environment vars here, so
 	# do it in a subshell to get rid of them safely later
 	debug copy_commit "{$1}" "{$2}" "{$3}"
@@ -391,7 +415,9 @@ copy_commit () {
 	) || die "Can't copy commit $1"
 }
 
+# Usage: add_msg DIR LATEST_OLD LATEST_NEW
 add_msg () {
+	assert test $# = 3
 	dir="$1"
 	latest_old="$2"
 	latest_new="$3"
@@ -410,7 +436,9 @@ add_msg () {
 	EOF
 }
 
+# Usage: add_squashed_msg REV DIR
 add_squashed_msg () {
+	assert test $# = 2
 	if test -n "$arg_addmerge_message"
 	then
 		echo "$arg_addmerge_message"
@@ -419,7 +447,9 @@ add_squashed_msg () {
 	fi
 }
 
+# Usage: rejoin_msg DIR LATEST_OLD LATEST_NEW
 rejoin_msg () {
+	assert test $# = 3
 	dir="$1"
 	latest_old="$2"
 	latest_new="$3"
@@ -438,7 +468,9 @@ rejoin_msg () {
 	EOF
 }
 
+# Usage: squash_msg DIR OLD_SUBTREE_COMMIT NEW_SUBTREE_COMMIT
 squash_msg () {
+	assert test $# = 3
 	dir="$1"
 	oldsub="$2"
 	newsub="$3"
@@ -460,12 +492,16 @@ squash_msg () {
 	echo "git-subtree-split: $newsub"
 }
 
+# Usage: toptree_for_commit COMMIT
 toptree_for_commit () {
+	assert test $# = 1
 	commit="$1"
 	git rev-parse --verify "$commit^{tree}" || exit $?
 }
 
+# Usage: subtree_for_commit COMMIT DIR
 subtree_for_commit () {
+	assert test $# = 2
 	commit="$1"
 	dir="$2"
 	git ls-tree "$commit" -- "$dir" |
@@ -479,7 +515,9 @@ subtree_for_commit () {
 	done || exit $?
 }
 
+# Usage: tree_changed TREE [PARENTS...]
 tree_changed () {
+	assert test $# -gt 0
 	tree=$1
 	shift
 	if test $# -ne 1
@@ -496,7 +534,9 @@ tree_changed () {
 	fi
 }
 
+# Usage: new_squash_commit OLD_SQUASHED_COMMIT OLD_NONSQUASHED_COMMIT NEW_NONSQUASHED_COMMIT
 new_squash_commit () {
+	assert test $# = 3
 	old="$1"
 	oldsub="$2"
 	newsub="$3"
@@ -511,7 +551,9 @@ new_squash_commit () {
 	fi
 }
 
+# Usage: copy_or_skip REV TREE NEWPARENTS
 copy_or_skip () {
+	assert test $# = 3
 	rev="$1"
 	tree="$2"
 	newparents="$3"
@@ -586,7 +628,9 @@ copy_or_skip () {
 	fi
 }
 
+# Usage: ensure_clean
 ensure_clean () {
+	assert test $# = 0
 	if ! git diff-index HEAD --exit-code --quiet 2>&1
 	then
 		die "Working tree has modifications.  Cannot add."
@@ -597,12 +641,16 @@ ensure_clean () {
 	fi
 }
 
+# Usage: ensure_valid_ref_format REF
 ensure_valid_ref_format () {
+	assert test $# = 1
 	git check-ref-format "refs/heads/$1" ||
 		die "'$1' does not look like a ref"
 }
 
+# Usage: process_split_commit REV PARENTS INDENT
 process_split_commit () {
+	assert test $# = 3
 	local rev="$1"
 	local parents="$2"
 	local indent=$3
@@ -654,6 +702,8 @@ process_split_commit () {
 	cache_set latest_old "$rev"
 }
 
+# Usage: cmd_add REV
+#    Or: cmd_add REPOSITORY REF
 cmd_add () {
 
 	ensure_clean
@@ -681,7 +731,9 @@ cmd_add () {
 	fi
 }
 
+# Usage: cmd_add_repository REPOSITORY REFSPEC
 cmd_add_repository () {
+	assert test $# = 2
 	echo "git fetch" "$@"
 	repository=$1
 	refspec=$2
@@ -689,9 +741,11 @@ cmd_add_repository () {
 	cmd_add_commit FETCH_HEAD
 }
 
+# Usage: cmd_add_commit REV
 cmd_add_commit () {
 	# The rev has already been validated by cmd_add(), we just
 	# need to normalize it.
+	assert test $# = 1
 	rev=$(git rev-parse --verify "$1^{commit}") || exit $?
 
 	debug "Adding $dir as '$rev'..."
@@ -722,6 +776,7 @@ cmd_add_commit () {
 	say >&2 "Added dir '$dir'"
 }
 
+# Usage: cmd_split [REV]
 cmd_split () {
 	if test $# -eq 0
 	then
@@ -801,6 +856,7 @@ cmd_split () {
 	exit 0
 }
 
+# Usage: cmd_merge REV
 cmd_merge () {
 	test $# -eq 1 ||
 		die "You must provide exactly one revision.  Got: '$*'"
@@ -837,6 +893,7 @@ cmd_merge () {
 	fi
 }
 
+# Usage: cmd_pull REPOSITORY REMOTEREF
 cmd_pull () {
 	if test $# -ne 2
 	then
@@ -848,6 +905,7 @@ cmd_pull () {
 	cmd_merge FETCH_HEAD
 }
 
+# Usage: cmd_push REPOSITORY REMOTEREF
 cmd_push () {
 	if test $# -ne 2
 	then
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 24/30] subtree: don't let debug and progress output clash
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (22 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 23/30] subtree: add comments and sanity checks Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 25/30] subtree: have $indent actually affect indentation Luke Shumaker
                       ` (5 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Currently, debug output (triggered by passing '-d') and progress output
stomp on each other.  The debug output is just streamed as lines to
stderr, and the progress output is sent to stderr as '%s\r'.  When
writing to a file, it is awkward to read and difficult to distinguish
between the debug output and a progress line.  When writing to a
terminal the debug lines hide progress lines.

So, when '-d' has been passed, spit out progress as 'progress: %s\n',
instead of as '%s\r', so that it can be detected, and so that the debug
lines don't overwrite the progress when written to a terminal.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - Reword the commit message to be clearer.
 - Add comments to the code.
 - Flip the `if` and `else` cases around, so that the comments
   read better.

 contrib/subtree/git-subtree.sh | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 441571c85a..53a1a025f5 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -67,7 +67,27 @@ debug () {
 progress () {
 	if test -z "$GIT_QUIET"
 	then
-		printf "%s\r" "$*" >&2
+		if test -z "$arg_debug"
+		then
+			# Debug mode is off.
+			#
+			# Print one progress line that we keep updating (use
+			# "\r" to return to the beginning of the line, rather
+			# than "\n" to start a new line).  This only really
+			# works when stderr is a terminal.
+			printf "%s\r" "$*" >&2
+		else
+			# Debug mode is on.  The `debug` function is regularly
+			# printing to stderr.
+			#
+			# Don't do the one-line-with-"\r" thing, because on a
+			# terminal the debug output would overwrite and hide the
+			# progress output.  Add a "progress:" prefix to make the
+			# progress output and the debug output easy to
+			# distinguish.  This ensures maximum readability whether
+			# stderr is a terminal or a file.
+			printf "progress: %s\n" "$*" >&2
+		fi
 	fi
 }
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 25/30] subtree: have $indent actually affect indentation
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (23 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 24/30] subtree: don't let debug and progress output clash Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 26/30] subtree: give the docs a once-over Luke Shumaker
                       ` (4 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Currently, the $indent variable is just used to track how deeply we're
nested, and the debug log is indented by things like

   debug "  foo"

That is: The indentation-level is hard-coded.  It used to be that the
code couldn't recurse, so the indentation level could be known
statically, so it made sense to just hard-code it in the
output. However, since 315a84f9aa ("subtree: use commits before rejoins
for splits", 2018-09-28), it can now recurse, and the debug log is
misleading.

So fix that.  Indent according to $indent.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh | 42 +++++++++++++++++++---------------
 1 file changed, 24 insertions(+), 18 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 53a1a025f5..768fa7b6b6 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -55,11 +55,13 @@ arg_split_annotate=
 arg_addmerge_squash=
 arg_addmerge_message=
 
+indent=0
+
 # Usage: debug [MSG...]
 debug () {
 	if test -n "$arg_debug"
 	then
-		printf "%s\n" "$*" >&2
+		printf "%$(($indent * 2))s%s\n" '' "$*" >&2
 	fi
 }
 
@@ -251,17 +253,17 @@ cache_miss () {
 	done
 }
 
-# Usage: check_parents PARENTS_EXPR INDENT
+# Usage: check_parents PARENTS_EXPR
 check_parents () {
-	assert test $# = 2
+	assert test $# = 1
 	missed=$(cache_miss "$1") || exit $?
-	local indent=$(($2 + 1))
+	local indent=$(($indent + 1))
 	for miss in $missed
 	do
 		if ! test -r "$cachedir/notree/$miss"
 		then
-			debug "  incorrect order: $miss"
-			process_split_commit "$miss" "" "$indent"
+			debug "incorrect order: $miss"
+			process_split_commit "$miss" ""
 		fi
 	done
 }
@@ -314,6 +316,8 @@ try_remove_previous () {
 find_latest_squash () {
 	assert test $# = 1
 	debug "Looking for latest squash ($dir)..."
+	local indent=$(($indent + 1))
+
 	dir="$1"
 	sq=
 	main=
@@ -360,6 +364,8 @@ find_latest_squash () {
 find_existing_splits () {
 	assert test $# = 2
 	debug "Looking for prior splits..."
+	local indent=$(($indent + 1))
+
 	dir="$1"
 	rev="$2"
 	main=
@@ -385,7 +391,7 @@ find_existing_splits () {
 			die "could not rev-parse split hash $b from commit $sq"
 			;;
 		END)
-			debug "  Main is: '$main'"
+			debug "Main is: '$main'"
 			if test -z "$main" -a -n "$sub"
 			then
 				# squash commits refer to a subtree
@@ -668,12 +674,11 @@ ensure_valid_ref_format () {
 		die "'$1' does not look like a ref"
 }
 
-# Usage: process_split_commit REV PARENTS INDENT
+# Usage: process_split_commit REV PARENTS
 process_split_commit () {
-	assert test $# = 3
+	assert test $# = 2
 	local rev="$1"
 	local parents="$2"
-	local indent=$3
 
 	if test $indent -eq 0
 	then
@@ -688,20 +693,21 @@ process_split_commit () {
 	progress "$revcount/$revmax ($createcount) [$extracount]"
 
 	debug "Processing commit: $rev"
+	local indent=$(($indent + 1))
 	exists=$(cache_get "$rev") || exit $?
 	if test -n "$exists"
 	then
-		debug "  prior: $exists"
+		debug "prior: $exists"
 		return
 	fi
 	createcount=$(($createcount + 1))
-	debug "  parents: $parents"
-	check_parents "$parents" "$indent"
+	debug "parents: $parents"
+	check_parents "$parents"
 	newparents=$(cache_get $parents) || exit $?
-	debug "  newparents: $newparents"
+	debug "newparents: $newparents"
 
 	tree=$(subtree_for_commit "$rev" "$dir") || exit $?
-	debug "  tree is: $tree"
+	debug "tree is: $tree"
 
 	# ugly.  is there no better way to tell if this is a subtree
 	# vs. a mainline commit?  Does it matter?
@@ -716,7 +722,7 @@ process_split_commit () {
 	fi
 
 	newrev=$(copy_or_skip "$rev" "$tree" "$newparents") || exit $?
-	debug "  newrev is: $newrev"
+	debug "newrev is: $newrev"
 	cache_set "$rev" "$newrev"
 	cache_set latest_new "$newrev"
 	cache_set latest_old "$rev"
@@ -820,7 +826,7 @@ cmd_split () {
 		do
 			# the 'onto' history is already just the subdir, so
 			# any parent we find there can be used verbatim
-			debug "  cache: $rev"
+			debug "cache: $rev"
 			cache_set "$rev" "$rev"
 		done || exit $?
 	fi
@@ -838,7 +844,7 @@ cmd_split () {
 	eval "$grl" |
 	while read rev parents
 	do
-		process_split_commit "$rev" "$parents" 0
+		process_split_commit "$rev" "$parents"
 	done || exit $?
 
 	latest_new=$(cache_get latest_new) || exit $?
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 26/30] subtree: give the docs a once-over
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (24 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 25/30] subtree: have $indent actually affect indentation Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 27/30] subtree: allow --squash to be used with --rejoin Luke Shumaker
                       ` (3 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Just went through the docs looking for anything inaccurate or that can
be improved.

In the '-h' text, in the man page synopsis, and in the man page
description: Normalize the ordering of the list of sub-commands: 'add',
'merge', 'split', 'pull', 'push'.  This allows us to kinda separate the
lower-level add/merge/split from the higher-level pull/push.

'-h' text:
 - correction: Indicate that split's arg is optional.
 - clarity: Emphasize that 'pull' takes the 'add'/'merge' flags.

man page:

 - correction: State that all subcommands take options (it seemed to
   indicate that only 'split' takes any options other than '-P').
 - correction: 'split' only guarantees that the results are identical if
   the flags are identical.
 - correction: The flag is named '--ignore-joins', not '--ignore-join'.
 - completeness: Clarify that 'push' always operates on HEAD, and that
   'split' operates on HEAD if no local commit is given.
 - clarity: In the description, when listing commands, repeat what their
   arguments are.  This way the reader doesn't need to flip back and
   forth between the command description and the synopsis and the full
   description to understand what's being said.
 - clarity: In the <variables> used to give command arguments, give
   slightly longer, descriptive names.  Like <local-commit> instead of
   just <commit>.
 - clarity: Emphasize that 'pull' takes the 'add'/'merge' flags.
 - style: In the synopsis, list options before the subcommand.  This
   makes things line up and be much more readable when shown
   non-monospace (such as in `make html`), and also more closely matches
   other man pages (like `git-submodule.txt`).
 - style: Use the correct syntax for indicating the options ([<options>]
   instead of [OPTIONS]).
 - style: In the synopsis, separate 'pull' and 'push' from the other
   lower-level commands.  I think this helps readability.
 - style: Code-quote things in prose that seem like they should be
   code-quoted, like '.gitmodules', flags, or full commands.
 - style: Minor wording improvements, like more consistent mood (many
   of the command descriptions start in the imperative mood and switch
   to the indicative mode by the end).  That sort of thing.
 - style: Capitalize "ID".
 - style: Remove the "This option is only valid for XXX command" remarks
   from each option, and instead rely on the section headings.
 - style: Since that line is getting edited anyway, switch "behaviour" to
   American "behavior".
 - style: Trim trailing whitespace.

`todo`:
 - style: Trim trailing whitespace.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - behaviour -> behavior
v3:
 - Trim trailing whitespace.
 - Fix the man page saying "--ignore-join" instead of "--ignore-joins".

 contrib/subtree/git-subtree.sh  |   4 +-
 contrib/subtree/git-subtree.txt | 170 +++++++++++++++-----------------
 contrib/subtree/todo            |   6 +-
 3 files changed, 87 insertions(+), 93 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 768fa7b6b6..3bffddf277 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -25,9 +25,9 @@ OPTS_SPEC="\
 git subtree add   --prefix=<prefix> <commit>
 git subtree add   --prefix=<prefix> <repository> <ref>
 git subtree merge --prefix=<prefix> <commit>
+git subtree split --prefix=<prefix> [<commit>]
 git subtree pull  --prefix=<prefix> <repository> <ref>
 git subtree push  --prefix=<prefix> <repository> <ref>
-git subtree split --prefix=<prefix> <commit>
 --
 h,help        show the help
 q             quiet
@@ -40,7 +40,7 @@ b,branch=     create a new branch from the split subtree
 ignore-joins  ignore prior --rejoin commits
 onto=         try connecting new tree to an existing one
 rejoin        merge the new branch back into HEAD
- options for 'add', 'merge', and 'pull'
+ options for 'add' and 'merge' (also: 'pull')
 squash        merge subtree changes as a single commit
 "
 
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index 0db02fe3c0..78baac1e6b 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -9,13 +9,14 @@ git-subtree - Merge subtrees together and split repository into subtrees
 SYNOPSIS
 --------
 [verse]
-'git subtree' add   -P <prefix> <commit>
-'git subtree' add   -P <prefix> <repository> <ref>
-'git subtree' pull  -P <prefix> <repository> <ref>
-'git subtree' push  -P <prefix> <repository> <ref>
-'git subtree' merge -P <prefix> <commit>
-'git subtree' split -P <prefix> [OPTIONS] [<commit>]
+'git subtree' [<options>] -P <prefix> add <local-commit>
+'git subtree' [<options>] -P <prefix> add <repository> <remote-ref>
+'git subtree' [<options>] -P <prefix> merge <local-commit>
+'git subtree' [<options>] -P <prefix> split [<local-commit>]
 
+[verse]
+'git subtree' [<options>] -P <prefix> pull <repository> <remote-ref>
+'git subtree' [<options>] -P <prefix> push <repository> <remote-ref>
 
 DESCRIPTION
 -----------
@@ -28,7 +29,7 @@ as a subdirectory of your application.
 
 Subtrees are not to be confused with submodules, which are meant for
 the same task. Unlike submodules, subtrees do not need any special
-constructions (like .gitmodules files or gitlinks) be present in
+constructions (like '.gitmodules' files or gitlinks) be present in
 your repository, and do not force end-users of your
 repository to do anything special or to understand how subtrees
 work. A subtree is just a subdirectory that can be
@@ -59,67 +60,69 @@ project as much as possible.  That is, if you make a change that
 affects both the library and the main application, commit it in
 two pieces.  That way, when you split the library commits out
 later, their descriptions will still make sense.  But if this
-isn't important to you, it's not *necessary*.  git subtree will
+isn't important to you, it's not *necessary*.  'git subtree' will
 simply leave out the non-library-related parts of the commit
 when it splits it out into the subproject later.
 
 
 COMMANDS
 --------
-add::
+add <local-commit>::
+add <repository> <remote-ref>::
 	Create the <prefix> subtree by importing its contents
-	from the given <commit> or <repository> and remote <ref>.
+	from the given <local-commit> or <repository> and <remote-ref>.
 	A new commit is created	automatically, joining the imported
-	project's history with your own.  With '--squash', imports
+	project's history with your own.  With '--squash', import
 	only a single commit from the subproject, rather than its
 	entire history.
 
-merge::
-	Merge recent changes up to <commit> into the <prefix>
+merge <local-commit>::
+	Merge recent changes up to <local-commit> into the <prefix>
 	subtree.  As with normal 'git merge', this doesn't
 	remove your own local changes; it just merges those
-	changes into the latest <commit>.  With '--squash',
-	creates only one commit that contains all the changes,
+	changes into the latest <local-commit>.  With '--squash',
+	create only one commit that contains all the changes,
 	rather than merging in the entire history.
 +
 If you use '--squash', the merge direction doesn't always have to be
 forward; you can use this command to go back in time from v2.5 to v2.4,
 for example.  If your merge introduces a conflict, you can resolve it in
 the usual ways.
-	
-pull::
-	Exactly like 'merge', but parallels 'git pull' in that
-	it fetches the given ref from the specified remote
-	repository.
-	
-push::
-	Does a 'split' (see below) using the <prefix> supplied
-	and then does a 'git push' to push the result to the 
-	repository and ref. This can be used to push your
-	subtree to different branches of the remote repository.
-
-split::
+
+split [<local-commit>]::
 	Extract a new, synthetic project history from the
-	history of the <prefix> subtree.  The new history
+	history of the <prefix> subtree of <local-commit>, or of
+	HEAD if no <local-commit> is given.  The new history
 	includes only the commits (including merges) that
 	affected <prefix>, and each of those commits now has the
 	contents of <prefix> at the root of the project instead
 	of in a subdirectory.  Thus, the newly created history
 	is suitable for export as a separate git repository.
 +
-After splitting successfully, a single commit id is printed to stdout.
+After splitting successfully, a single commit ID is printed to stdout.
 This corresponds to the HEAD of the newly created tree, which you can
 manipulate however you want.
 +
 Repeated splits of exactly the same history are guaranteed to be
-identical (i.e. to produce the same commit ids).  Because of this, if
-you add new commits and then re-split, the new commits will be attached
-as commits on top of the history you generated last time, so 'git merge'
-and friends will work as expected.
+identical (i.e. to produce the same commit IDs) as long as the
+settings passed to 'split' (such as '--annotate') are the same.
+Because of this, if you add new commits and then re-split, the new
+commits will be attached as commits on top of the history you
+generated last time, so 'git merge' and friends will work as expected.
 +
 Note that if you use '--squash' when you merge, you should usually not
 just '--rejoin' when you split.
 
+pull <repository> <remote-ref>::
+	Exactly like 'merge', but parallels 'git pull' in that
+	it fetches the given ref from the specified remote
+	repository.
+
+push <repository> <remote-ref>::
+	Does a 'split' using the <prefix> subtree of HEAD and then
+	does a 'git push' to push the result to the <repository> and
+	<remote-ref>.  This can be used to push your subtree to
+	different branches of the remote repository.
 
 OPTIONS
 -------
@@ -139,19 +142,18 @@ OPTIONS
 
 -m <message>::
 --message=<message>::
-	This option is only valid for add, merge, pull, and split --rejoin.
+	This option is only valid for 'add', 'merge', 'pull', and 'split --rejoin'.
 	Specify <message> as the commit message for the merge commit.
 
+OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull')
+--------------------------------------------
+These options for 'add' and 'merge' may also be given to 'pull' (which
+wraps 'merge').
 
-OPTIONS FOR add, merge, and pull
---------------------------------
 --squash::
-	This option is only valid for add, merge, and pull
-	commands.
-+
-Instead of merging the entire history from the subtree project, produce
-only a single commit that contains all the differences you want to
-merge, and then merge that new commit into your project.
+	Instead of merging the entire history from the subtree project, produce
+	only a single commit that contains all the differences you want to
+	merge, and then merge that new commit into your project.
 +
 Using this option helps to reduce log clutter. People rarely want to see
 every change that happened between v1.0 and v1.1 of the library they're
@@ -175,56 +177,48 @@ remain intact and can be later split and send upstream to the
 subproject.
 
 
-OPTIONS FOR split
------------------
+OPTIONS FOR 'split'
+-------------------
+These options are only valid for 'split'.
+
 --annotate=<annotation>::
-	This option is only valid for the split command.
-+
-When generating synthetic history, add <annotation> as a prefix to each
-commit message.  Since we're creating new commits with the same commit
-message, but possibly different content, from the original commits, this
-can help to differentiate them and avoid confusion.
+	When generating synthetic history, add <annotation> as a prefix to each
+	commit message.  Since we're creating new commits with the same commit
+	message, but possibly different content, from the original commits, this
+	can help to differentiate them and avoid confusion.
 +
 Whenever you split, you need to use the same <annotation>, or else you
 don't have a guarantee that the new re-created history will be identical
 to the old one.  That will prevent merging from working correctly.  git
-subtree tries to make it work anyway, particularly if you use --rejoin,
+subtree tries to make it work anyway, particularly if you use '--rejoin',
 but it may not always be effective.
 
 -b <branch>::
 --branch=<branch>::
-	This option is only valid for the split command.
-+
-After generating the synthetic history, create a new branch called
-<branch> that contains the new history.  This is suitable for immediate
-pushing upstream.  <branch> must not already exist.
+	After generating the synthetic history, create a new branch called
+	<branch> that contains the new history.  This is suitable for immediate
+	pushing upstream.  <branch> must not already exist.
 
 --ignore-joins::
-	This option is only valid for the split command.
-+
-If you use '--rejoin', git subtree attempts to optimize its history
-reconstruction to generate only the new commits since the last
-'--rejoin'.  '--ignore-join' disables this behaviour, forcing it to
-regenerate the entire history.  In a large project, this can take a long
-time.
+	If you use '--rejoin', git subtree attempts to optimize its history
+	reconstruction to generate only the new commits since the last
+	'--rejoin'.  '--ignore-joins' disables this behavior, forcing it to
+	regenerate the entire history.  In a large project, this can take a long
+	time.
 
 --onto=<onto>::
-	This option is only valid for the split command.
-+
-If your subtree was originally imported using something other than git
-subtree, its history may not match what git subtree is expecting.  In
-that case, you can specify the commit id <onto> that corresponds to the
-first revision of the subproject's history that was imported into your
-project, and git subtree will attempt to build its history from there.
+	If your subtree was originally imported using something other than git
+	subtree, its history may not match what git subtree is expecting.  In
+	that case, you can specify the commit ID <onto> that corresponds to the
+	first revision of the subproject's history that was imported into your
+	project, and git subtree will attempt to build its history from there.
 +
 If you used 'git subtree add', you should never need this option.
 
 --rejoin::
-	This option is only valid for the split command.
-+
-After splitting, merge the newly created synthetic history back into
-your main project.  That way, future splits can search only the part of
-history that has been added since the most recent --rejoin.
+	After splitting, merge the newly created synthetic history back into
+	your main project.  That way, future splits can search only the part of
+	history that has been added since the most recent '--rejoin'.
 +
 If your split commits end up merged into the upstream subproject, and
 then you want to get the latest upstream version, this will allow git's
@@ -240,8 +234,8 @@ split, because you don't want the subproject's history to be part of
 your project anyway.
 
 
-EXAMPLE 1. Add command
-----------------------
+EXAMPLE 1. 'add' command
+------------------------
 Let's assume that you have a local repository that you would like
 to add an external vendor library to. In this case we will add the
 git-subtree repository as a subdirectory of your already existing
@@ -253,15 +247,15 @@ git-extensions repository in ~/git-extensions/:
 'master' needs to be a valid remote ref and can be a different branch
 name
 
-You can omit the --squash flag, but doing so will increase the number
+You can omit the '--squash' flag, but doing so will increase the number
 of commits that are included in your local repository.
 
 We now have a ~/git-extensions/git-subtree directory containing code
 from the master branch of git://github.com/apenwarr/git-subtree.git
 in our git-extensions repository.
 
-EXAMPLE 2. Extract a subtree using commit, merge and pull
----------------------------------------------------------
+EXAMPLE 2. Extract a subtree using 'commit', 'merge' and 'pull'
+---------------------------------------------------------------
 Let's use the repository for the git source code as an example.
 First, get your own copy of the git.git repository:
 
@@ -269,7 +263,7 @@ First, get your own copy of the git.git repository:
 	$ cd test-git
 
 gitweb (commit 1130ef3) was merged into git as of commit
-0a8f4f0, after which it was no longer maintained separately. 
+0a8f4f0, after which it was no longer maintained separately.
 But imagine it had been maintained separately, and we wanted to
 extract git's changes to gitweb since that time, to share with
 the upstream.  You could do this:
@@ -279,14 +273,14 @@ the upstream.  You could do this:
         	--branch gitweb-latest
         $ gitk gitweb-latest
         $ git push git@github.com:whatever/gitweb.git gitweb-latest:master
-        
+
 (We use '0a8f4f0^..' because that means "all the changes from
 0a8f4f0 to the current version, including 0a8f4f0 itself.")
 
 If gitweb had originally been merged using 'git subtree add' (or
-a previous split had already been done with --rejoin specified)
+a previous split had already been done with '--rejoin' specified)
 then you can do all your splits without having to remember any
-weird commit ids:
+weird commit IDs:
 
 	$ git subtree split --prefix=gitweb --annotate='(split) ' --rejoin \
 		--branch gitweb-latest2
@@ -313,7 +307,7 @@ And fast forward again:
 	$ git subtree merge --prefix=gitweb --squash gitweb-latest
 
 And notice that your change is still intact:
-	
+
 	$ ls -l gitweb/myfile
 
 And you can split it out and look at your changes versus
@@ -321,8 +315,8 @@ the standard gitweb:
 
 	git log gitweb-latest..$(git subtree split --prefix=gitweb)
 
-EXAMPLE 3. Extract a subtree using branch
------------------------------------------
+EXAMPLE 3. Extract a subtree using a branch
+-------------------------------------------
 Suppose you have a source directory with many files and
 subdirectories, and you want to extract the lib directory to its own
 git project. Here's a short way to do it:
diff --git a/contrib/subtree/todo b/contrib/subtree/todo
index 0d0e777651..32d2ce3a40 100644
--- a/contrib/subtree/todo
+++ b/contrib/subtree/todo
@@ -23,9 +23,9 @@
 
 	"pull" and "merge" commands should fail if you've never merged
 		that --prefix before
-		
+
 	docs should provide an example of "add"
-	
+
 	note that the initial split doesn't *have* to have a commitid
 		specified... that's just an optimization
 
@@ -33,7 +33,7 @@
 		get a misleading "prefix must end with /" message from
 		one of the other git tools that git-subtree calls.  Should
 		detect this situation and print the *real* problem.
-	
+
 	"pull --squash" should do fetch-synthesize-merge, but instead just
 		does "pull" directly, which doesn't work at all.
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 27/30] subtree: allow --squash to be used with --rejoin
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (25 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 26/30] subtree: give the docs a once-over Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 28/30] subtree: allow 'split' flags to be passed to 'push' Luke Shumaker
                       ` (2 subsequent siblings)
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Besides being a genuinely useful thing to do, this also just makes sense
and harmonizes which flags may be used when.  `git subtree split
--rejoin` amounts to "automatically go ahead and do a `git subtree
merge` after doing the main `git subtree split`", so it's weird and
arbitrary that you can't pass `--squash` to `git subtree split --rejoin`
like you can `git subtree merge`.  It's weird that `git subtree split
--rejoin` inherits `git subtree merge`'s `--message` but not `--squash`.

Reconcile the situation by just having `split --rejoin` actually just
call `merge` internally (or call `add` instead, as appropriate), so it
can get access to the full `merge` behavior, including `--squash`.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - In the added tests, use `test_must_fail` instead of `!`, as
   appropriate.
v3:
 - Style: Put the `then` of an `if/then` on its own line.
 - Fix a bug (and add a test) where the resulting commits confuse a
   subsequent `git subtree merge --squash`.

 contrib/subtree/git-subtree.sh     | 37 +++++++++++++++-----
 contrib/subtree/git-subtree.txt    | 27 ++++++--------
 contrib/subtree/t/t7900-subtree.sh | 56 ++++++++++++++++++++++++++++++
 3 files changed, 96 insertions(+), 24 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 3bffddf277..25d69d7973 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -33,15 +33,15 @@ h,help        show the help
 q             quiet
 d             show debug messages
 P,prefix=     the name of the subdir to split out
-m,message=    use the given message as the commit message for the merge commit
  options for 'split'
 annotate=     add a prefix to commit message of new commits
 b,branch=     create a new branch from the split subtree
 ignore-joins  ignore prior --rejoin commits
 onto=         try connecting new tree to an existing one
 rejoin        merge the new branch back into HEAD
- options for 'add' and 'merge' (also: 'pull')
+ options for 'add' and 'merge' (also: 'pull' and 'split --rejoin')
 squash        merge subtree changes as a single commit
+m,message=    use the given message as the commit message for the merge commit
 "
 
 arg_debug=
@@ -346,7 +346,8 @@ find_latest_squash () {
 				then
 					# a rejoin commit?
 					# Pretend its sub was a squash.
-					sq="$sub"
+					sq=$(git rev-parse --verify "$sq^2") ||
+						die
 				fi
 				debug "Squash found: $sq $sub"
 				echo "$sq" "$sub"
@@ -453,6 +454,13 @@ add_msg () {
 	else
 		commit_message="Add '$dir/' from commit '$latest_new'"
 	fi
+	if test -n "$arg_split_rejoin"
+	then
+		# If this is from a --rejoin, then rejoin_msg has
+		# already inserted the `git-subtree-xxx:` tags
+		echo "$commit_message"
+		return
+	fi
 	cat <<-EOF
 		$commit_message
 
@@ -775,7 +783,12 @@ cmd_add_commit () {
 	rev=$(git rev-parse --verify "$1^{commit}") || exit $?
 
 	debug "Adding $dir as '$rev'..."
-	git read-tree --prefix="$dir" $rev || exit $?
+	if test -z "$arg_split_rejoin"
+	then
+		# Only bother doing this if this is a genuine 'add',
+		# not a synthetic 'add' from '--rejoin'.
+		git read-tree --prefix="$dir" $rev || exit $?
+	fi
 	git checkout -- "$dir" || exit $?
 	tree=$(git write-tree) || exit $?
 
@@ -815,6 +828,11 @@ cmd_split () {
 		die "You must provide exactly one revision.  Got: '$*'"
 	fi
 
+	if test -n "$arg_split_rejoin"
+	then
+		ensure_clean
+	fi
+
 	debug "Splitting $dir..."
 	cache_setup || exit $?
 
@@ -857,10 +875,13 @@ cmd_split () {
 	then
 		debug "Merging split branch into HEAD..."
 		latest_old=$(cache_get latest_old) || exit $?
-		git merge -s ours \
-			--allow-unrelated-histories \
-			-m "$(rejoin_msg "$dir" "$latest_old" "$latest_new")" \
-			"$latest_new" >&2 || exit $?
+		arg_addmerge_message="$(rejoin_msg "$dir" "$latest_old" "$latest_new")" || exit $?
+		if test -z "$(find_latest_squash "$dir")"
+		then
+			cmd_add "$latest_new" >&2 || exit $?
+		else
+			cmd_merge "$latest_new" >&2 || exit $?
+		fi
 	fi
 	if test -n "$arg_split_branch"
 	then
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index 78baac1e6b..d7e6e7867c 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -109,9 +109,6 @@ settings passed to 'split' (such as '--annotate') are the same.
 Because of this, if you add new commits and then re-split, the new
 commits will be attached as commits on top of the history you
 generated last time, so 'git merge' and friends will work as expected.
-+
-Note that if you use '--squash' when you merge, you should usually not
-just '--rejoin' when you split.
 
 pull <repository> <remote-ref>::
 	Exactly like 'merge', but parallels 'git pull' in that
@@ -124,8 +121,8 @@ push <repository> <remote-ref>::
 	<remote-ref>.  This can be used to push your subtree to
 	different branches of the remote repository.
 
-OPTIONS
--------
+OPTIONS FOR ALL COMMANDS
+------------------------
 -q::
 --quiet::
 	Suppress unnecessary output messages on stderr.
@@ -140,15 +137,11 @@ OPTIONS
 	want to manipulate.  This option is mandatory
 	for all commands.
 
--m <message>::
---message=<message>::
-	This option is only valid for 'add', 'merge', 'pull', and 'split --rejoin'.
-	Specify <message> as the commit message for the merge commit.
-
-OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull')
---------------------------------------------
+OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull' AND 'split --rejoin')
+-----------------------------------------------------------------
 These options for 'add' and 'merge' may also be given to 'pull' (which
-wraps 'merge').
+wraps 'merge') and 'split --rejoin' (which wraps either 'add' or
+'merge' as appropriate).
 
 --squash::
 	Instead of merging the entire history from the subtree project, produce
@@ -176,6 +169,9 @@ Whether or not you use '--squash', changes made in your local repository
 remain intact and can be later split and send upstream to the
 subproject.
 
+-m <message>::
+--message=<message>::
+	Specify <message> as the commit message for the merge commit.
 
 OPTIONS FOR 'split'
 -------------------
@@ -229,9 +225,8 @@ Unfortunately, using this option results in 'git log' showing an extra
 copy of every new commit that was created (the original, and the
 synthetic one).
 +
-If you do all your merges with '--squash', don't use '--rejoin' when you
-split, because you don't want the subproject's history to be part of
-your project anyway.
+If you do all your merges with '--squash', make sure you also use
+'--squash' when you 'split --rejoin'.
 
 
 EXAMPLE 1. 'add' command
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index ce6861c22d..2561e25f43 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -324,6 +324,62 @@ test_expect_success 'split sub dir/ with --rejoin and --message' '
 	)
 '
 
+test_expect_success 'split "sub dir"/ with --rejoin and --squash' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" --squash FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git subtree pull --prefix="sub dir" --squash ./"sub proj" HEAD &&
+		MAIN=$(git rev-parse --verify HEAD) &&
+		SUB=$(git -C "sub proj" rev-parse --verify HEAD) &&
+
+		SPLIT=$(git subtree split --prefix="sub dir" --annotate="*" --rejoin --squash) &&
+
+		test_must_fail git merge-base --is-ancestor $SUB HEAD &&
+		test_must_fail git merge-base --is-ancestor $SPLIT HEAD &&
+		git rev-list HEAD ^$MAIN >commit-list &&
+		test_line_count = 2 commit-list &&
+		test "$(git rev-parse --verify HEAD:)"           = "$(git rev-parse --verify $MAIN:)" &&
+		test "$(git rev-parse --verify HEAD:"sub dir")"  = "$(git rev-parse --verify $SPLIT:)" &&
+		test "$(git rev-parse --verify HEAD^1)"          = $MAIN &&
+		test "$(git rev-parse --verify HEAD^2)"         != $SPLIT &&
+		test "$(git rev-parse --verify HEAD^2:)"         = "$(git rev-parse --verify $SPLIT:)" &&
+		test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$SPLIT'\''"
+	)
+'
+
+test_expect_success 'split then pull "sub dir"/ with --rejoin and --squash' '
+	# 1. "add"
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	git -C "$test_count" subtree --prefix="sub dir" add --squash ./"sub proj" HEAD &&
+
+	# 2. commit from parent
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+
+	# 3. "split --rejoin --squash"
+	git -C "$test_count" subtree --prefix="sub dir" split --rejoin --squash &&
+
+	# 4. "pull --squash"
+	test_create_commit "$test_count/sub proj" sub2 &&
+	git -C "$test_count" subtree -d --prefix="sub dir" pull --squash ./"sub proj" HEAD &&
+
+	test_must_fail git merge-base HEAD FETCH_HEAD
+'
+
 test_expect_success 'split "sub dir"/ with --branch' '
 	subtree_test_create_repo "$test_count" &&
 	subtree_test_create_repo "$test_count/sub proj" &&
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 28/30] subtree: allow 'split' flags to be passed to 'push'
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (26 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 27/30] subtree: allow --squash to be used with --rejoin Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 29/30] subtree: push: allow specifying a local rev other than HEAD Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 30/30] subtree: be stricter about validating flags Luke Shumaker
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

'push' does a 'split' internally, but it doesn't pass flags through to the
'split'.  This is silly, if you need to pass flags to 'split', then it
means that you can't use 'push'!

So, have 'push' accept 'split' flags, and pass them through to 'split'.

Add tests for this by copying split's tests with minimal modification.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
v2:
 - In the added tests, use `test_must_fail` instead of `!`, as
   appropriate.

 contrib/subtree/git-subtree.sh     |   6 +-
 contrib/subtree/git-subtree.txt    |  15 +-
 contrib/subtree/t/t7900-subtree.sh | 214 ++++++++++++++++++++++++++++-
 3 files changed, 223 insertions(+), 12 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 25d69d7973..431214a1d3 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -33,13 +33,13 @@ h,help        show the help
 q             quiet
 d             show debug messages
 P,prefix=     the name of the subdir to split out
- options for 'split'
+ options for 'split' (also: 'push')
 annotate=     add a prefix to commit message of new commits
 b,branch=     create a new branch from the split subtree
 ignore-joins  ignore prior --rejoin commits
 onto=         try connecting new tree to an existing one
 rejoin        merge the new branch back into HEAD
- options for 'add' and 'merge' (also: 'pull' and 'split --rejoin')
+ options for 'add' and 'merge' (also: 'pull', 'split --rejoin', and 'push --rejoin')
 squash        merge subtree changes as a single commit
 m,message=    use the given message as the commit message for the merge commit
 "
@@ -964,7 +964,7 @@ cmd_push () {
 		repository=$1
 		refspec=$2
 		echo "git push using: " "$repository" "$refspec"
-		localrev=$(git subtree split --prefix="$arg_prefix") || die
+		localrev=$(cmd_split) || die
 		git push "$repository" "$localrev":"refs/heads/$refspec"
 	else
 		die "'$dir' must already exist. Try 'git subtree add'."
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index d7e6e7867c..fbb52f127b 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -137,11 +137,11 @@ OPTIONS FOR ALL COMMANDS
 	want to manipulate.  This option is mandatory
 	for all commands.
 
-OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull' AND 'split --rejoin')
------------------------------------------------------------------
+OPTIONS FOR 'add' AND 'merge' (ALSO: 'pull', 'split --rejoin', AND 'push --rejoin')
+-----------------------------------------------------------------------------------
 These options for 'add' and 'merge' may also be given to 'pull' (which
-wraps 'merge') and 'split --rejoin' (which wraps either 'add' or
-'merge' as appropriate).
+wraps 'merge'), 'split --rejoin' (which wraps either 'add' or 'merge'
+as appropriate), and 'push --rejoin' (which wraps 'split --rejoin').
 
 --squash::
 	Instead of merging the entire history from the subtree project, produce
@@ -173,9 +173,10 @@ subproject.
 --message=<message>::
 	Specify <message> as the commit message for the merge commit.
 
-OPTIONS FOR 'split'
--------------------
-These options are only valid for 'split'.
+OPTIONS FOR 'split' (ALSO: 'push')
+----------------------------------
+These options for 'split' may also be given to 'push' (which wraps
+'split').
 
 --annotate=<annotation>::
 	When generating synthetic history, add <annotation> as a prefix to each
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 2561e25f43..5a6541437b 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -5,8 +5,8 @@
 #
 test_description='Basic porcelain support for subtrees
 
-This test verifies the basic operation of the add, pull, merge
-and split subcommands of git subtree.
+This test verifies the basic operation of the add, merge, split, pull,
+and push subcommands of git subtree.
 '
 
 TEST_DIRECTORY=$(pwd)/../../../t
@@ -610,6 +610,216 @@ test_expect_success 'push basic operation' '
 	)
 '
 
+test_expect_success 'push sub dir/ with --rejoin' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+		git subtree push --prefix="sub dir" --annotate="*" --rejoin ./"sub proj" from-mainline &&
+		test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''" &&
+		test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'push sub dir/ with --rejoin from scratch' '
+	subtree_test_create_repo "$test_count" &&
+	test_create_commit "$test_count" main1 &&
+	(
+		cd "$test_count" &&
+		mkdir "sub dir" &&
+		echo file >"sub dir"/file &&
+		git add "sub dir/file" &&
+		git commit -m"sub dir file" &&
+		split_hash=$(git subtree split --prefix="sub dir" --rejoin) &&
+		git init --bare "sub proj.git" &&
+		git subtree push --prefix="sub dir" --rejoin ./"sub proj.git" from-mainline &&
+		test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$split_hash'\''" &&
+		test "$split_hash" = "$(git -C "sub proj.git" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'push sub dir/ with --rejoin and --message' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		git subtree push --prefix="sub dir" --message="Split & rejoin" --annotate="*" --rejoin ./"sub proj" from-mainline &&
+		test "$(last_commit_subject)" = "Split & rejoin" &&
+		split_hash="$(git rev-parse --verify HEAD^2)" &&
+		test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'push "sub dir"/ with --rejoin and --squash' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" --squash FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git subtree pull --prefix="sub dir" --squash ./"sub proj" HEAD &&
+		MAIN=$(git rev-parse --verify HEAD) &&
+		SUB=$(git -C "sub proj" rev-parse --verify HEAD) &&
+
+		SPLIT=$(git subtree split --prefix="sub dir" --annotate="*") &&
+		git subtree push --prefix="sub dir" --annotate="*" --rejoin --squash ./"sub proj" from-mainline &&
+
+		test_must_fail git merge-base --is-ancestor $SUB HEAD &&
+		test_must_fail git merge-base --is-ancestor $SPLIT HEAD &&
+		git rev-list HEAD ^$MAIN >commit-list &&
+		test_line_count = 2 commit-list &&
+		test "$(git rev-parse --verify HEAD:)"           = "$(git rev-parse --verify $MAIN:)" &&
+		test "$(git rev-parse --verify HEAD:"sub dir")"  = "$(git rev-parse --verify $SPLIT:)" &&
+		test "$(git rev-parse --verify HEAD^1)"          = $MAIN &&
+		test "$(git rev-parse --verify HEAD^2)"         != $SPLIT &&
+		test "$(git rev-parse --verify HEAD^2:)"         = "$(git rev-parse --verify $SPLIT:)" &&
+		test "$(last_commit_subject)" = "Split '\''sub dir/'\'' into commit '\''$SPLIT'\''" &&
+		test "$SPLIT" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'push "sub dir"/ with --branch' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+		git subtree push --prefix="sub dir" --annotate="*" --branch subproj-br ./"sub proj" from-mainline &&
+		test "$(git rev-parse subproj-br)" = "$split_hash" &&
+		test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'check hash of push' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+		git subtree push --prefix="sub dir" --annotate="*" --branch subproj-br ./"sub proj" from-mainline &&
+		test "$(git rev-parse subproj-br)" = "$split_hash" &&
+		# Check hash of split
+		new_hash=$(git rev-parse subproj-br^2) &&
+		(
+			cd ./"sub proj" &&
+			subdir_hash=$(git rev-parse HEAD) &&
+			test "$new_hash" = "$subdir_hash"
+		) &&
+		test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'push "sub dir"/ with --branch for an existing branch' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git branch subproj-br FETCH_HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+		git subtree push --prefix="sub dir" --annotate="*" --branch subproj-br ./"sub proj" from-mainline &&
+		test "$(git rev-parse subproj-br)" = "$split_hash" &&
+		test "$split_hash" = "$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline)"
+	)
+'
+
+test_expect_success 'push "sub dir"/ with --branch for an incompatible branch' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git branch init HEAD &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		test_must_fail git subtree push --prefix="sub dir" --branch init "./sub proj" from-mainline
+	)
+'
+
 #
 # Validity checking
 #
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 29/30] subtree: push: allow specifying a local rev other than HEAD
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (27 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 28/30] subtree: allow 'split' flags to be passed to 'push' Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
  2021-04-27 21:17     ` [PATCH v3 30/30] subtree: be stricter about validating flags Luke Shumaker
  29 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

'git subtree split' lets you specify a rev other than HEAD.  'git push'
lets you specify a mapping between a local thing and a remot ref.  So
smash those together, and have 'git subtree push' let you specify which
local thing to run split on and push the result of that split to the
remote ref.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh     | 24 +++++++++++++++++-------
 contrib/subtree/git-subtree.txt    | 14 ++++++++------
 contrib/subtree/t/t7900-subtree.sh | 22 ++++++++++++++++++++++
 3 files changed, 47 insertions(+), 13 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 431214a1d3..9e4d9a0619 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -27,7 +27,7 @@ git subtree add   --prefix=<prefix> <repository> <ref>
 git subtree merge --prefix=<prefix> <commit>
 git subtree split --prefix=<prefix> [<commit>]
 git subtree pull  --prefix=<prefix> <repository> <ref>
-git subtree push  --prefix=<prefix> <repository> <ref>
+git subtree push  --prefix=<prefix> <repository> <refspec>
 --
 h,help        show the help
 q             quiet
@@ -952,20 +952,30 @@ cmd_pull () {
 	cmd_merge FETCH_HEAD
 }
 
-# Usage: cmd_push REPOSITORY REMOTEREF
+# Usage: cmd_push REPOSITORY [+][LOCALREV:]REMOTEREF
 cmd_push () {
 	if test $# -ne 2
 	then
-		die "You must provide <repository> <ref>"
+		die "You must provide <repository> <refspec>"
 	fi
-	ensure_valid_ref_format "$2"
 	if test -e "$dir"
 	then
 		repository=$1
-		refspec=$2
+		refspec=${2#+}
+		remoteref=${refspec#*:}
+		if test "$remoteref" = "$refspec"
+		then
+			localrevname_presplit=HEAD
+		else
+			localrevname_presplit=${refspec%%:*}
+		fi
+		ensure_valid_ref_format "$remoteref"
+		localrev_presplit=$(git rev-parse -q --verify "$localrevname_presplit^{commit}") ||
+			die "'$localrevname_presplit' does not refer to a commit"
+
 		echo "git push using: " "$repository" "$refspec"
-		localrev=$(cmd_split) || die
-		git push "$repository" "$localrev":"refs/heads/$refspec"
+		localrev=$(cmd_split "$localrev_presplit") || die
+		git push "$repository" "$localrev":"refs/heads/$remoteref"
 	else
 		die "'$dir' must already exist. Try 'git subtree add'."
 	fi
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index fbb52f127b..9cddfa2654 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -16,7 +16,7 @@ SYNOPSIS
 
 [verse]
 'git subtree' [<options>] -P <prefix> pull <repository> <remote-ref>
-'git subtree' [<options>] -P <prefix> push <repository> <remote-ref>
+'git subtree' [<options>] -P <prefix> push <repository> <refspec>
 
 DESCRIPTION
 -----------
@@ -115,11 +115,13 @@ pull <repository> <remote-ref>::
 	it fetches the given ref from the specified remote
 	repository.
 
-push <repository> <remote-ref>::
-	Does a 'split' using the <prefix> subtree of HEAD and then
-	does a 'git push' to push the result to the <repository> and
-	<remote-ref>.  This can be used to push your subtree to
-	different branches of the remote repository.
+push <repository> [+][<local-commit>:]<remote-ref>::
+	Does a 'split' using the <prefix> subtree of <local-commit>
+	and then does a 'git push' to push the result to the
+	<repository> and <remote-ref>.  This can be used to push your
+	subtree to different branches of the remote repository.  Just
+	as with 'split', if no <local-commit> is given, then HEAD is
+	used.  The optional leading '+' is ignored.
 
 OPTIONS FOR ALL COMMANDS
 ------------------------
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 5a6541437b..d7ad6ffff0 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -820,6 +820,28 @@ test_expect_success 'push "sub dir"/ with --branch for an incompatible branch' '
 	)
 '
 
+test_expect_success 'push "sub dir"/ with a local rev' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		bad_tree=$(git rev-parse --verify HEAD:"sub dir") &&
+		good_tree=$(git rev-parse --verify HEAD^:"sub dir") &&
+		git subtree push --prefix="sub dir" --annotate="*" ./"sub proj" HEAD^:from-mainline &&
+		split_tree=$(git -C "sub proj" rev-parse --verify refs/heads/from-mainline:) &&
+		test "$split_tree" = "$good_tree"
+	)
+'
+
 #
 # Validity checking
 #
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* [PATCH v3 30/30] subtree: be stricter about validating flags
  2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
                       ` (28 preceding siblings ...)
  2021-04-27 21:17     ` [PATCH v3 29/30] subtree: push: allow specifying a local rev other than HEAD Luke Shumaker
@ 2021-04-27 21:17     ` Luke Shumaker
       [not found]       ` <CAAgkN4cKUSPKpwuaLG-vR5Z7WFUZ81QXuRcsX-10obaRBAvwBA@mail.gmail.com>
  29 siblings, 1 reply; 144+ messages in thread
From: Luke Shumaker @ 2021-04-27 21:17 UTC (permalink / raw)
  To: git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

From: Luke Shumaker <lukeshu@datawire.io>

Don't silently ignore a flag that's invalid for a given subcommand.  The
user expected it to do something; we should tell the user that they are
mistaken, instead of surprising the user.

It could be argued that this change might break existing users.  I'd
argue that those existing users are already broken, and they just don't
know it.  Let them know that they're broken.

Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
---
 contrib/subtree/git-subtree.sh     |  89 ++++++++++++++++-------
 contrib/subtree/t/t7900-subtree.sh | 111 +++++++++++++++++++++++++++++
 2 files changed, 175 insertions(+), 25 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 9e4d9a0619..b06782bc79 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -44,17 +44,6 @@ squash        merge subtree changes as a single commit
 m,message=    use the given message as the commit message for the merge commit
 "
 
-arg_debug=
-arg_command=
-arg_prefix=
-arg_split_branch=
-arg_split_onto=
-arg_split_rejoin=
-arg_split_ignore_joins=
-arg_split_annotate=
-arg_addmerge_squash=
-arg_addmerge_message=
-
 indent=0
 
 # Usage: debug [MSG...]
@@ -106,10 +95,61 @@ main () {
 	then
 		set -- -h
 	fi
-	eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
+	set_args="$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
+	eval "$set_args"
 	. git-sh-setup
 	require_work_tree
 
+	# First figure out the command and whether we use --rejoin, so
+	# that we can provide more helpful validation when we do the
+	# "real" flag parsing.
+	arg_split_rejoin=
+	allow_split=
+	allow_addmerge=
+	while test $# -gt 0
+	do
+		opt="$1"
+		shift
+		case "$opt" in
+			--annotate|-b|-P|-m|--onto)
+				shift
+				;;
+			--rejoin)
+				arg_split_rejoin=1
+				;;
+			--no-rejoin)
+				arg_split_rejoin=
+				;;
+			--)
+				break
+				;;
+		esac
+	done
+	arg_command=$1
+	case "$arg_command" in
+	add|merge|pull)
+		allow_addmerge=1
+		;;
+	split|push)
+		allow_split=1
+		allow_addmerge=$arg_split_rejoin
+		;;
+	*)
+		die "Unknown command '$arg_command'"
+		;;
+	esac
+	# Reset the arguments array for "real" flag parsing.
+	eval "$set_args"
+
+	# Begin "real" flag parsing.
+	arg_debug=
+	arg_prefix=
+	arg_split_branch=
+	arg_split_onto=
+	arg_split_ignore_joins=
+	arg_split_annotate=
+	arg_addmerge_squash=
+	arg_addmerge_message=
 	while test $# -gt 0
 	do
 		opt="$1"
@@ -123,13 +163,16 @@ main () {
 			arg_debug=1
 			;;
 		--annotate)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_annotate="$1"
 			shift
 			;;
 		--no-annotate)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_annotate=
 			;;
 		-b)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_branch="$1"
 			shift
 			;;
@@ -138,6 +181,7 @@ main () {
 			shift
 			;;
 		-m)
+			test -n "$allow_addmerge" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_addmerge_message="$1"
 			shift
 			;;
@@ -145,28 +189,34 @@ main () {
 			arg_prefix=
 			;;
 		--onto)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_onto="$1"
 			shift
 			;;
 		--no-onto)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_onto=
 			;;
 		--rejoin)
-			arg_split_rejoin=1
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			;;
 		--no-rejoin)
-			arg_split_rejoin=
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			;;
 		--ignore-joins)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_ignore_joins=1
 			;;
 		--no-ignore-joins)
+			test -n "$allow_split" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_split_ignore_joins=
 			;;
 		--squash)
+			test -n "$allow_addmerge" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_addmerge_squash=1
 			;;
 		--no-squash)
+			test -n "$allow_addmerge" || die "The '$opt' flag does not make sense with 'git subtree $arg_command'."
 			arg_addmerge_squash=
 			;;
 		--)
@@ -177,19 +227,8 @@ main () {
 			;;
 		esac
 	done
-
-	arg_command="$1"
 	shift
 
-	case "$arg_command" in
-	add|merge|pull|split|push)
-		:
-		;;
-	*)
-		die "Unknown command '$arg_command'"
-		;;
-	esac
-
 	if test -z "$arg_prefix"
 	then
 		die "You must provide the --prefix option."
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index d7ad6ffff0..4153b65321 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -33,6 +33,12 @@ test_create_commit () (
 	git commit -m "$commit" || error "Could not commit"
 )
 
+test_wrong_flag() {
+	test_must_fail "$@" >out 2>err &&
+	test_must_be_empty out &&
+	grep "flag does not make sense with" err
+}
+
 last_commit_subject () {
 	git log --pretty=format:%s -1
 }
@@ -72,6 +78,22 @@ test_expect_success 'no pull from non-existent subtree' '
 	)
 '
 
+test_expect_success 'add rejects flags for split' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		test_wrong_flag git subtree add --prefix="sub dir" --annotate=foo FETCH_HEAD &&
+		test_wrong_flag git subtree add --prefix="sub dir" --branch=foo FETCH_HEAD &&
+		test_wrong_flag git subtree add --prefix="sub dir" --ignore-joins FETCH_HEAD &&
+		test_wrong_flag git subtree add --prefix="sub dir" --onto=foo FETCH_HEAD &&
+		test_wrong_flag git subtree add --prefix="sub dir" --rejoin FETCH_HEAD
+	)
+'
+
 test_expect_success 'add subproj as subtree into sub dir/ with --prefix' '
 	subtree_test_create_repo "$test_count" &&
 	subtree_test_create_repo "$test_count/sub proj" &&
@@ -128,6 +150,28 @@ test_expect_success 'add subproj as subtree into sub dir/ with --squash and --pr
 # Tests for 'git subtree merge'
 #
 
+test_expect_success 'merge rejects flags for split' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		test_wrong_flag git subtree merge --prefix="sub dir" --annotate=foo FETCH_HEAD &&
+		test_wrong_flag git subtree merge --prefix="sub dir" --branch=foo FETCH_HEAD &&
+		test_wrong_flag git subtree merge --prefix="sub dir" --ignore-joins FETCH_HEAD &&
+		test_wrong_flag git subtree merge --prefix="sub dir" --onto=foo FETCH_HEAD &&
+		test_wrong_flag git subtree merge --prefix="sub dir" --rejoin FETCH_HEAD
+	)
+'
+
 test_expect_success 'merge new subproj history into sub dir/ with --prefix' '
 	subtree_test_create_repo "$test_count" &&
 	subtree_test_create_repo "$test_count/sub proj" &&
@@ -262,6 +306,30 @@ test_expect_success 'split requires path given by option --prefix must exist' '
 	)
 '
 
+test_expect_success 'split rejects flags for add' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		split_hash=$(git subtree split --prefix="sub dir" --annotate="*") &&
+		test_wrong_flag git subtree split --prefix="sub dir" --squash &&
+		test_wrong_flag git subtree split --prefix="sub dir" --message=foo
+	)
+'
+
 test_expect_success 'split sub dir/ with --rejoin' '
 	subtree_test_create_repo "$test_count" &&
 	subtree_test_create_repo "$test_count/sub proj" &&
@@ -542,6 +610,26 @@ test_expect_success 'pull basic operation' '
 	)
 '
 
+test_expect_success 'pull rejects flags for split' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	(
+		test_must_fail git subtree pull --prefix="sub dir" --annotate=foo ./"sub proj" HEAD &&
+		test_must_fail git subtree pull --prefix="sub dir" --branch=foo ./"sub proj" HEAD &&
+		test_must_fail git subtree pull --prefix="sub dir" --ignore-joins ./"sub proj" HEAD &&
+		test_must_fail git subtree pull --prefix="sub dir" --onto=foo ./"sub proj" HEAD &&
+		test_must_fail git subtree pull --prefix="sub dir" --rejoin ./"sub proj" HEAD
+	)
+'
+
 #
 # Tests for 'git subtree push'
 #
@@ -584,6 +672,29 @@ test_expect_success 'push requires path given by option --prefix must exist' '
 	)
 '
 
+test_expect_success 'push rejects flags for add' '
+	subtree_test_create_repo "$test_count" &&
+	subtree_test_create_repo "$test_count/sub proj" &&
+	test_create_commit "$test_count" main1 &&
+	test_create_commit "$test_count/sub proj" sub1 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree add --prefix="sub dir" FETCH_HEAD
+	) &&
+	test_create_commit "$test_count" "sub dir"/main-sub1 &&
+	test_create_commit "$test_count" main2 &&
+	test_create_commit "$test_count/sub proj" sub2 &&
+	test_create_commit "$test_count" "sub dir"/main-sub2 &&
+	(
+		cd "$test_count" &&
+		git fetch ./"sub proj" HEAD &&
+		git subtree merge --prefix="sub dir" FETCH_HEAD &&
+		test_wrong_flag git subtree split --prefix="sub dir" --squash ./"sub proj" from-mainline &&
+		test_wrong_flag git subtree split --prefix="sub dir" --message=foo ./"sub proj" from-mainline
+	)
+'
+
 test_expect_success 'push basic operation' '
 	subtree_test_create_repo "$test_count" &&
 	subtree_test_create_repo "$test_count/sub proj" &&
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 144+ messages in thread

* Re: [PATCH v3 30/30] subtree: be stricter about validating flags
       [not found]       ` <CAAgkN4cKUSPKpwuaLG-vR5Z7WFUZ81QXuRcsX-10obaRBAvwBA@mail.gmail.com>
@ 2021-04-28  0:24         ` Luke Shumaker
  0 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-28  0:24 UTC (permalink / raw)
  To: Jakub Suder
  Cc: Luke Shumaker, git, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

On Tue, 27 Apr 2021 15:38:01 -0600,
Jakub Suder wrote:

> Sorry for the contributing to the problem, but whom do I have to
> bribe to finally stop getting these emails that started filling my
> inbox last week?… I have a vague memory that I might have done
> something with git-subtree once a long time ago, but I'm not
> generally a contributor to git and I don't know what I'm doing here
> or how to get out…
> 
> JS

My apologies.  I'll stop CC'ing you on my emails and further revisions
of the patcheset.  You may yet get a few straggling emails as others
reply-all to emails that have already been sent (unless they manually
remove you from the CC list).

As explanation (but not excuse): The usual etiquette is to CC recent
or substantial contributors to the code area, and because subtree
hasn't been touched in a while, I reached back further in to the
history than usual when creating the CC list.

Again, I'm sorry for bothering you.

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH 04/30] subtree: t7900: use consistent formatting
  2021-04-27 20:41       ` Luke Shumaker
@ 2021-04-28  4:33         ` Junio C Hamano
  0 siblings, 0 replies; 144+ messages in thread
From: Junio C Hamano @ 2021-04-28  4:33 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: Eric Sunshine, Git List, Avery Pennarun, Charles Bailey,
	Danny Lin, David A . Greene, David Aguilar, Jakub Suder,
	James Denholm, Jeff King, Jonathan Nieder,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Luke Shumaker

Luke Shumaker <lukeshu@lukeshu.com> writes:

>> If Luke is volunteering to take over its maintainership, it would be
>> appreciated by its users.  It has been in the "abandonware" status
>> for too long.
>
> I think I am volunteering.

Wonderful, and thanks.

> Elsewhere in the thread, you suggested that subtree be taken out of
> git.git, and live as a standalone project.
>
> I'm not entirely opposed to that, but
>
>  1. I'm not sure how whoever picks it up (me) establishes their
>     git-subtree as the "real" subtree (get a blessing from Avery?).

Avery is so distant a past, but a work like this series, while we
still have it in contrib/ in my tree, will help build necessary
trust in you by the Git user/developer community, and when that
happens, it would be obvious to everybody that you would be the new
owner of the tool.

And when that happens while the tool is in the contrib/ in my tree,
and you'd be an established trusted member of the development
community by then, I do not mind if you take it and maintain out of
tree, if you keep working on the tool still in contrib/, or if you
polish it to the main porcelain status and take it out of contrib/
and make it part of the git-core proper.

> On the other hand, I think that in the long-ish term git-subtree wants
> to be rewritten in a better-suited language.  My personal inclination
> would be Go, but if I ever want it to graduate to git-core, it'd have
> to be C, huh?

If somebody is willing to do a rewrite and will maintain it for a
long haul, I'd say that it would not necessarily have to be in C
especially if it is not performance sensitive.

As long as it is done in a widely available language, that is (which
used to man Perl or Python, but my persoonal preference won't carry
that much weight these days ;-)

Then folks who really want it in C can rewrite the rewrite on their
own after that.

One advantage you may have if you choose to take it out of my tree
and make it a standalone project is that you have more latitude on
the future implementation technology, but we'd need to start from
helping you earn the trust by convincing others that "subtree" would
be in good hands with your volunteering ;-)

Thanks.


^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH v3 02/30] subtree: t7900: update for having the default branch name be 'main'
  2021-04-27 21:17     ` [PATCH v3 02/30] subtree: t7900: update for having the default branch name be 'main' Luke Shumaker
@ 2021-04-30  9:38       ` Ævar Arnfjörð Bjarmason
  2021-04-30 16:07         ` Luke Shumaker
  0 siblings, 1 reply; 144+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-04-30  9:38 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: git, Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine, Luke Shumaker


On Tue, Apr 27 2021, Luke Shumaker wrote:

> From: Luke Shumaker <lukeshu@datawire.io>
>
> Most of the tests had been converted to support
> `GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main`, but `contrib/subtree/t/`
> hadn't.
>
> Convert it.  Most of the mentions of 'master' can just be replaced with
> 'HEAD'.

Looks good to me. FWIW (without having looked carefully) I'd have
probably just set up a "sub-proj" remote and done a "git fetch" after
configuring a refspec during the setup, but just s/master/HEAD/ is the
smaller change to just fix the "bug".

> [...]
> @@ -994,6 +994,7 @@ test_expect_success 'push split to subproj' '
>  next_test
>  test_expect_success 'subtree descendant check' '
>  	subtree_test_create_repo "$subtree_test_count" &&
> +	defaultBranch=$(sed "s,ref: refs/heads/,," "$subtree_test_count/.git/HEAD") &&
>  	test_create_commit "$subtree_test_count" folder_subtree/a &&
>  	(
>  		cd "$subtree_test_count" &&

This though needlessly peeks into the raw refstore. Use branch=$(git
symbolic-ref --short HEAD) instead. See e.g. my
https://lore.kernel.org/git/patch-08.11-7fb8849ce66-20210423T072006Z-avarab@gmail.com/

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH v3 03/30] subtree: t7900: use test-lib.sh's test_count
  2021-04-27 21:17     ` [PATCH v3 03/30] subtree: t7900: use test-lib.sh's test_count Luke Shumaker
@ 2021-04-30  9:45       ` Ævar Arnfjörð Bjarmason
  2021-04-30 16:10         ` Luke Shumaker
  0 siblings, 1 reply; 144+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-04-30  9:45 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: git, Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine, Luke Shumaker


On Tue, Apr 27 2021, Luke Shumaker wrote:

> From: Luke Shumaker <lukeshu@datawire.io>
>
> Use test-lib.sh's `test_count`, instead instead of having
> t7900-subtree.sh do its own book-keeping with `subtree_test_count` that
> has to be explicitly incremented by calling `next_test`.

This just retains an existing pattern and all that, but I think this
pattern of testing makes for hard to read & maintain tests. It looks
like all of these could just be:

    test_when_finished "rm -rf repo" &&
    git init repo &&
    [...]

I.e. the only thing that's being done here is to piggy-back on the test
count to create a unique repo.

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH v3 05/30] subtree: t7900: comment subtree_test_create_repo
  2021-04-27 21:17     ` [PATCH v3 05/30] subtree: t7900: comment subtree_test_create_repo Luke Shumaker
@ 2021-04-30  9:48       ` Ævar Arnfjörð Bjarmason
  2021-04-30 16:13         ` Luke Shumaker
  0 siblings, 1 reply; 144+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-04-30  9:48 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: git, Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine, Luke Shumaker


On Tue, Apr 27 2021, Luke Shumaker wrote:

> It's unclear what the purpose of t7900-subtree.sh's
> `subtree_test_create_repo` helper function is.  It wraps test-lib.sh's,
> `test_create_repo` but follows that up by setting log.date=relative.  Why
> does it set log.date=relative?
>
> My first guess was that at one point the tests required that, but no
> longer do, and that the function is now vestigial.  I even wrote a patch
> to get rid of it and was moments away from `git send-email`ing it.
>
> However, by chance when looking for something else in the history, I
> discovered the true reason, from e7aac44ed2 (contrib/subtree: ignore
> log.date configuration, 2015-07-21).  It's testing that setting
> log.date=relative doesn't break `git subtree`, as at one point in the past
> that did break `git subtree`.

This commit message is too much about describing the journey IMO. We
could just get straight to the point, e.g. something like:

    Add a comment about why the git-subtree.sh tests set
    log.relative. It's to test that we don't have a regression of the
    bug fixed in e7aac44ed2 [...].

FWIW I think just having an isolated test for this would be better, but
since you're just refactoring existing code I think this is fine.

I.e. we'd use "git init" in the rest, and just have a test that stresses
this specifically. Or is the entry into git-subtree.sh so varied that we
need to "fuzz" all the tests like this to fully test it? I haven't
checked.

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH v3 06/30] subtree: t7900: use 'test' for string equality
  2021-04-27 21:17     ` [PATCH v3 06/30] subtree: t7900: use 'test' for string equality Luke Shumaker
@ 2021-04-30  9:55       ` Ævar Arnfjörð Bjarmason
  2021-04-30 16:33         ` Luke Shumaker
  0 siblings, 1 reply; 144+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-04-30  9:55 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: git, Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine, Luke Shumaker


On Tue, Apr 27 2021, Luke Shumaker wrote:

> From: Luke Shumaker <lukeshu@datawire.io>
>
> t7900-subtree.sh defines its own `check_equal A B` function, instead of
> just using `test A = B` like all of the other tests.  Don't be special,
> get rid of `check_equal` in favor of `test`.
>
> Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
> ---
>  contrib/subtree/t/t7900-subtree.sh | 60 ++++++++++++------------------
>  1 file changed, 24 insertions(+), 36 deletions(-)
>
> diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
> index 12b8cb03c7..76183153c9 100755
> --- a/contrib/subtree/t/t7900-subtree.sh
> +++ b/contrib/subtree/t/t7900-subtree.sh
> @@ -28,18 +28,6 @@ create () {
>  	git add "$1"
>  }
>  
> -check_equal () {
> -	test_debug 'echo'
> -	test_debug "echo \"check a:\" \"{$1}\""
> -	test_debug "echo \"      b:\" \"{$2}\""
> -	if test "$1" = "$2"
> -	then
> -		return 0
> -	else
> -		return 1
> -	fi
> -}

It looks like the reason this was used because when this fails just
having the "test" makes for bad debugging. I.e. if the values don't
match the $1 and $2 are not aligned, so it's hard to eyeball what went
wrong.

These days this is more idiomatic:

    echo "Add [...]" >expected
    last_commit_message >actual &&
    test_cmp expected actual

So I think in this case a better narrower improvement would be to keep
the check_equal function. I wonder if we shouldn't just in general in
t/test-lib.sh have a test_cmp_str for this use-case. I.e. a trivial
wrapper that echos the two strings to a file for you, before running
diff(1).

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH v3 09/30] subtree: t7900: rename last_commit_message to last_commit_subject
  2021-04-27 21:17     ` [PATCH v3 09/30] subtree: t7900: rename last_commit_message to last_commit_subject Luke Shumaker
@ 2021-04-30  9:59       ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 144+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-04-30  9:59 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: git, Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine, Luke Shumaker


On Tue, Apr 27 2021, Luke Shumaker wrote:

> From: Luke Shumaker <lukeshu@datawire.io>
>
> t7900-subtree.sh defines a helper function named last_commit_message.
> However, it only returns the subject line of the commit message, not the
> entire commit message.  So rename it, to make the name less confusing.

This and 06/30 (which I also had a comment on) would be less churn if it
were arranged to e.g. use the helper / only touch all these lines once.

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH v3 10/30] subtree: t7900: add a test for the -h flag
  2021-04-27 21:17     ` [PATCH v3 10/30] subtree: t7900: add a test for the -h flag Luke Shumaker
@ 2021-04-30 10:01       ` Ævar Arnfjörð Bjarmason
  2021-04-30 16:40         ` Luke Shumaker
  2021-04-30 12:22       ` Bagas Sanjaya
  1 sibling, 1 reply; 144+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-04-30 10:01 UTC (permalink / raw)
  To: Luke Shumaker
  Cc: git, Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine, Luke Shumaker


On Tue, Apr 27 2021, Luke Shumaker wrote:

> From: Luke Shumaker <lukeshu@datawire.io>
>
> It's a dumb test, but it's surprisingly easy to break.
>
> Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
> ---
>  contrib/subtree/t/t7900-subtree.sh | 7 +++++++
>  1 file changed, 7 insertions(+)
>
> diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
> index 5c2510f1f5..9afba2f282 100755
> --- a/contrib/subtree/t/t7900-subtree.sh
> +++ b/contrib/subtree/t/t7900-subtree.sh
> @@ -37,6 +37,13 @@ last_commit_subject () {
>  	git log --pretty=format:%s -1
>  }
>  
> +test_expect_success 'shows short help text for -h' '
> +	test_expect_code 129 git subtree -h >out 2>err &&
> +	test_must_be_empty err &&
> +	grep -e "^ *or: git subtree pull" out &&
> +	grep -e --annotate out

I wonder if "grep -e --could-be-an-option-if-not-for-e" is portable,
probably....

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH v3 10/30] subtree: t7900: add a test for the -h flag
  2021-04-27 21:17     ` [PATCH v3 10/30] subtree: t7900: add a test for the -h flag Luke Shumaker
  2021-04-30 10:01       ` Ævar Arnfjörð Bjarmason
@ 2021-04-30 12:22       ` Bagas Sanjaya
  2021-04-30 16:48         ` Luke Shumaker
  1 sibling, 1 reply; 144+ messages in thread
From: Bagas Sanjaya @ 2021-04-30 12:22 UTC (permalink / raw)
  To: Luke Shumaker, git
  Cc: Avery Pennarun, Charles Bailey, Danny Lin, David A . Greene,
	David Aguilar, Jakub Suder, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

On 28/04/21 04.17, Luke Shumaker wrote:
> It's a dumb test, but it's surprisingly easy to break.

Why did you say that? Very sensitive?

-- 
An old man doll... just what I always wanted! - Clara

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH v3 02/30] subtree: t7900: update for having the default branch name be 'main'
  2021-04-30  9:38       ` Ævar Arnfjörð Bjarmason
@ 2021-04-30 16:07         ` Luke Shumaker
  0 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-30 16:07 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Luke Shumaker, git, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine, Luke Shumaker

On Fri, 30 Apr 2021 03:38:52 -0600,
Ævar Arnfjörð Bjarmason wrote:
> > @@ -994,6 +994,7 @@ test_expect_success 'push split to subproj' '
> >  next_test
> >  test_expect_success 'subtree descendant check' '
> >  	subtree_test_create_repo "$subtree_test_count" &&
> > +	defaultBranch=$(sed "s,ref: refs/heads/,," "$subtree_test_count/.git/HEAD") &&
> >  	test_create_commit "$subtree_test_count" folder_subtree/a &&
> >  	(
> >  		cd "$subtree_test_count" &&
> 
> This though needlessly peeks into the raw refstore. Use branch=$(git
> symbolic-ref --short HEAD) instead. See e.g. my
> https://lore.kernel.org/git/patch-08.11-7fb8849ce66-20210423T072006Z-avarab@gmail.com/

I was about to say that doesn't work with a freshly initialized repo
without a commit yet, but I'm thinking of `git rev-parse --abbrev-ref
HEAD`.

I'll change it if I have to re-roll for another reason.

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH v3 03/30] subtree: t7900: use test-lib.sh's test_count
  2021-04-30  9:45       ` Ævar Arnfjörð Bjarmason
@ 2021-04-30 16:10         ` Luke Shumaker
  0 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-30 16:10 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Luke Shumaker, git, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, Jakub Suder, James Denholm,
	Jeff King, Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine, Luke Shumaker

On Fri, 30 Apr 2021 03:45:10 -0600,
Ævar Arnfjörð Bjarmason wrote:
> On Tue, Apr 27 2021, Luke Shumaker wrote:
> > Use test-lib.sh's `test_count`, instead instead of having
> > t7900-subtree.sh do its own book-keeping with `subtree_test_count` that
> > has to be explicitly incremented by calling `next_test`.
> 
> This just retains an existing pattern and all that, but I think this
> pattern of testing makes for hard to read & maintain tests. It looks
> like all of these could just be:
> 
>     test_when_finished "rm -rf repo" &&
>     git init repo &&
>     [...]
> 
> I.e. the only thing that's being done here is to piggy-back on the test
> count to create a unique repo.

Thanks for the tip, I'll do that for any new tests I add, going
forward.

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH v3 05/30] subtree: t7900: comment subtree_test_create_repo
  2021-04-30  9:48       ` Ævar Arnfjörð Bjarmason
@ 2021-04-30 16:13         ` Luke Shumaker
  0 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-30 16:13 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Luke Shumaker, git, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine, Luke Shumaker

On Fri, 30 Apr 2021 03:48:36 -0600,
Ævar Arnfjörð Bjarmason wrote:
> On Tue, Apr 27 2021, Luke Shumaker wrote:
> > It's unclear what the purpose of t7900-subtree.sh's
> > `subtree_test_create_repo` helper function is.  It wraps test-lib.sh's,
> > `test_create_repo` but follows that up by setting log.date=relative.  Why
> > does it set log.date=relative?
> >
> > My first guess was that at one point the tests required that, but no
> > longer do, and that the function is now vestigial.  I even wrote a patch
> > to get rid of it and was moments away from `git send-email`ing it.
> >
> > However, by chance when looking for something else in the history, I
> > discovered the true reason, from e7aac44ed2 (contrib/subtree: ignore
> > log.date configuration, 2015-07-21).  It's testing that setting
> > log.date=relative doesn't break `git subtree`, as at one point in the past
> > that did break `git subtree`.
> 
> This commit message is too much about describing the journey IMO. We
> could just get straight to the point, e.g. something like:
> 
>     Add a comment about why the git-subtree.sh tests set
>     log.relative. It's to test that we don't have a regression of the
>     bug fixed in e7aac44ed2 [...].

OK, I'll reword it if I re-roll.

> FWIW I think just having an isolated test for this would be better, but
> since you're just refactoring existing code I think this is fine.
> 
> I.e. we'd use "git init" in the rest, and just have a test that stresses
> this specifically. Or is the entry into git-subtree.sh so varied that we
> need to "fuzz" all the tests like this to fully test it? I haven't
> checked.

I'd have to examine it a bit more to be sure, but I think that you're
right.  That as long as the test does a 'split' that creates new
commits, then just one test should be fine.

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH v3 06/30] subtree: t7900: use 'test' for string equality
  2021-04-30  9:55       ` Ævar Arnfjörð Bjarmason
@ 2021-04-30 16:33         ` Luke Shumaker
  0 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-30 16:33 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Luke Shumaker, git, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine, Luke Shumaker

On Fri, 30 Apr 2021 03:55:04 -0600,
Ævar Arnfjörð Bjarmason wrote:
> 
> 
> On Tue, Apr 27 2021, Luke Shumaker wrote:
> 
> > From: Luke Shumaker <lukeshu@datawire.io>
> >
> > t7900-subtree.sh defines its own `check_equal A B` function, instead of
> > just using `test A = B` like all of the other tests.  Don't be special,
> > get rid of `check_equal` in favor of `test`.
> >
> > Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
> > ---
> >  contrib/subtree/t/t7900-subtree.sh | 60 ++++++++++++------------------
> >  1 file changed, 24 insertions(+), 36 deletions(-)
> >
> > diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
> > index 12b8cb03c7..76183153c9 100755
> > --- a/contrib/subtree/t/t7900-subtree.sh
> > +++ b/contrib/subtree/t/t7900-subtree.sh
> > @@ -28,18 +28,6 @@ create () {
> >  	git add "$1"
> >  }
> >  
> > -check_equal () {
> > -	test_debug 'echo'
> > -	test_debug "echo \"check a:\" \"{$1}\""
> > -	test_debug "echo \"      b:\" \"{$2}\""
> > -	if test "$1" = "$2"
> > -	then
> > -		return 0
> > -	else
> > -		return 1
> > -	fi
> > -}
> 
> It looks like the reason this was used because when this fails just
> having the "test" makes for bad debugging. I.e. if the values don't
> match the $1 and $2 are not aligned, so it's hard to eyeball what went
> wrong.

It's easy to make that assumption, but looking at the history it seems
the "actual" reason it exists is that it's vestigial from before the
subtree tests used test-lib.sh, and echoing it like that was the only
way you'd get feedback.

> These days this is more idiomatic:
> 
>     echo "Add [...]" >expected
>     last_commit_message >actual &&
>     test_cmp expected actual
> 
> So I think in this case a better narrower improvement would be to keep
> the check_equal function. I wonder if we shouldn't just in general in
> t/test-lib.sh have a test_cmp_str for this use-case. I.e. a trivial
> wrapper that echos the two strings to a file for you, before running
> diff(1).

But it's been my experience that the tests are already impossible to
debug without passing `-x`, so everything from `check_equal` ends up
being just noise.

And also I figured if `test` is good enough for t9350-fast-export.sh,
then it's good enough for t7900-subtree.sh... after working with
subtree, I'd accidentally written a couple of the checks in one of my
fast-export patchsets using `check_equal`.  Being special makes things
harder to hack on.

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH v3 10/30] subtree: t7900: add a test for the -h flag
  2021-04-30 10:01       ` Ævar Arnfjörð Bjarmason
@ 2021-04-30 16:40         ` Luke Shumaker
  0 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-30 16:40 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Luke Shumaker, git, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine, Luke Shumaker

On Fri, 30 Apr 2021 04:01:50 -0600,
Ævar Arnfjörð Bjarmason wrote:
> 
> 
> On Tue, Apr 27 2021, Luke Shumaker wrote:
> 
> > From: Luke Shumaker <lukeshu@datawire.io>
> >
> > It's a dumb test, but it's surprisingly easy to break.
> >
> > Signed-off-by: Luke Shumaker <lukeshu@datawire.io>
> > ---
> >  contrib/subtree/t/t7900-subtree.sh | 7 +++++++
> >  1 file changed, 7 insertions(+)
> >
> > diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
> > index 5c2510f1f5..9afba2f282 100755
> > --- a/contrib/subtree/t/t7900-subtree.sh
> > +++ b/contrib/subtree/t/t7900-subtree.sh
> > @@ -37,6 +37,13 @@ last_commit_subject () {
> >  	git log --pretty=format:%s -1
> >  }
> >  
> > +test_expect_success 'shows short help text for -h' '
> > +	test_expect_code 129 git subtree -h >out 2>err &&
> > +	test_must_be_empty err &&
> > +	grep -e "^ *or: git subtree pull" out &&
> > +	grep -e --annotate out
> 
> I wonder if "grep -e --could-be-an-option-if-not-for-e" is portable,
> probably....

It's POSIX, and at least works on GNU, busybox, and macOS
(based-on-FreeBSD) grep.  If it turns out there's somewhere it doesn't
work, I'd be happy to change it, but my baseline assumption is that
it's portable.

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

* Re: [PATCH v3 10/30] subtree: t7900: add a test for the -h flag
  2021-04-30 12:22       ` Bagas Sanjaya
@ 2021-04-30 16:48         ` Luke Shumaker
  0 siblings, 0 replies; 144+ messages in thread
From: Luke Shumaker @ 2021-04-30 16:48 UTC (permalink / raw)
  To: Bagas Sanjaya
  Cc: Luke Shumaker, git, Avery Pennarun, Charles Bailey, Danny Lin,
	David A . Greene, David Aguilar, James Denholm, Jeff King,
	Jonathan Nieder, Junio C Hamano,
	Nguyễn Thái Ngọc Duy, Roger L Strain,
	Techlive Zheng, Eric Sunshine,
	Ævar Arnfjörð Bjarmason, Luke Shumaker

On Fri, 30 Apr 2021 06:22:50 -0600,
Bagas Sanjaya wrote:
> 
> On 28/04/21 04.17, Luke Shumaker wrote:
> > It's a dumb test, but it's surprisingly easy to break.
> 
> Why did you say that? Very sensitive?

Because I very nearly sent v1 of this patchset with a broken '-h' flag
:)

I don't recall for certain, but I think the mistake I made was
allowing the ordering of `eval "$(echo "$OPTS_SPEC" | git rev-parse
--parseopt -- "$@")"` and `. git-sh-setup` to get flipped.  That
certainly will break '-h', anyway.

-- 
Happy hacking,
~ Luke Shumaker

^ permalink raw reply	[flat|nested] 144+ messages in thread

end of thread, other threads:[~2021-04-30 16:49 UTC | newest]

Thread overview: 144+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-23 19:42 [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
2021-04-23 19:42 ` [PATCH 01/30] .gitignore: Ignore /git-subtree Luke Shumaker
2021-04-23 19:42 ` [PATCH 02/30] subtree: t7900: update for having the default branch name be 'main' Luke Shumaker
2021-04-23 19:42 ` [PATCH 03/30] subtree: t7900: use test-lib.sh's test_count Luke Shumaker
2021-04-23 19:42 ` [PATCH 04/30] subtree: t7900: use consistent formatting Luke Shumaker
2021-04-23 21:51   ` Eric Sunshine
2021-04-23 22:54     ` Luke Shumaker
2021-04-27  7:17     ` Junio C Hamano
2021-04-27 20:41       ` Luke Shumaker
2021-04-28  4:33         ` Junio C Hamano
2021-04-23 19:42 ` [PATCH 05/30] subtree: t7900: comment subtree_test_create_repo Luke Shumaker
2021-04-23 19:42 ` [PATCH 06/30] subtree: t7900: use 'test' for string equality Luke Shumaker
2021-04-23 19:42 ` [PATCH 07/30] subtree: t7900: delete some dead code Luke Shumaker
2021-04-23 19:42 ` [PATCH 08/30] subtree: t7900: fix 'verify one file change per commit' Luke Shumaker
2021-04-23 19:42 ` [PATCH 09/30] subtree: t7900: rename last_commit_message to last_commit_subject Luke Shumaker
2021-04-23 19:42 ` [PATCH 10/30] subtree: t7900: add a test for the -h flag Luke Shumaker
2021-04-23 19:42 ` [PATCH 11/30] subtree: t7900: add porcelain tests for 'pull' and 'push' Luke Shumaker
2021-04-23 20:19   ` Eric Sunshine
2021-04-23 22:27     ` Luke Shumaker
2021-04-23 19:42 ` [PATCH 12/30] subtree: don't have loose code outside of a function Luke Shumaker
2021-04-23 20:05   ` Luke Shumaker
2021-04-23 20:23   ` Eric Sunshine
2021-04-23 22:43     ` Luke Shumaker
2021-04-23 23:11       ` Eric Sunshine
2021-04-23 23:37         ` Luke Shumaker
2021-04-23 19:42 ` [PATCH 13/30] subtree: more consistent error propagation Luke Shumaker
2021-04-23 19:42 ` [PATCH 14/30] subtree: drop support for git < 1.7 Luke Shumaker
2021-04-23 20:07   ` Luke Shumaker
2021-04-23 20:31   ` Eric Sunshine
2021-04-23 23:28     ` Luke Shumaker
2021-04-23 23:50       ` Eric Sunshine
2021-04-24  0:20         ` Luke Shumaker
2021-04-23 19:42 ` [PATCH 15/30] subtree: use `git merge-base --is-ancestor` Luke Shumaker
2021-04-23 19:42 ` [PATCH 16/30] subtree: use git-sh-setup's `say` Luke Shumaker
2021-04-23 19:42 ` [PATCH 17/30] subtree: use more explicit variable names for cmdline args Luke Shumaker
2021-04-23 19:42 ` [PATCH 18/30] subtree: use $* instead of $@ as appropriate Luke Shumaker
2021-04-23 20:40   ` Eric Sunshine
2021-04-23 23:50     ` Luke Shumaker
2021-04-24  5:18       ` Eric Sunshine
2021-04-23 19:42 ` [PATCH 19/30] subtree: give `$(git --exec-path)` precedence over `$PATH` Luke Shumaker
2021-04-26  8:27   ` =?utf-8?B?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason
2021-04-23 19:42 ` [PATCH 20/30] subtree: use "^{commit}" instead of "^0" Luke Shumaker
2021-04-26  7:43   ` Ævar Arnfjörð Bjarmason
2021-04-23 19:42 ` [PATCH 21/30] subtree: parse revs in individual cmd_ functions Luke Shumaker
2021-04-23 19:42 ` [PATCH 22/30] subtree: remove duplicate check Luke Shumaker
2021-04-23 19:42 ` [PATCH 23/30] subtree: add comments and sanity checks Luke Shumaker
2021-04-23 20:58   ` Eric Sunshine
2021-04-23 23:58     ` Luke Shumaker
2021-04-23 19:42 ` [PATCH 24/30] subtree: don't let debug and progress output clash Luke Shumaker
2021-04-23 21:07   ` Eric Sunshine
2021-04-24  0:44     ` Luke Shumaker
2021-04-24  4:54       ` Eric Sunshine
2021-04-23 19:42 ` [PATCH 25/30] subtree: have $indent actually affect indentation Luke Shumaker
2021-04-23 19:42 ` [PATCH 26/30] subtree: give the docs a once-over Luke Shumaker
2021-04-23 19:42 ` [PATCH 27/30] subtree: allow --squash to be used with --rejoin Luke Shumaker
2021-04-24  5:50   ` Eric Sunshine
2021-04-25  0:04     ` Luke Shumaker
2021-04-23 19:42 ` [PATCH 28/30] subtree: allow 'split' flags to be passed to 'push' Luke Shumaker
2021-04-23 19:42 ` [PATCH 29/30] subtree: push: allow specifying a local rev other than HEAD Luke Shumaker
2021-04-23 19:42 ` [PATCH 30/30] subtree: be stricter about validating flags Luke Shumaker
2021-04-25  2:55   ` Danny Lin
2021-04-26 17:35     ` Luke Shumaker
2021-04-23 20:12 ` [PATCH 00/30] subtree: clean up, improve UX Luke Shumaker
2021-04-26  7:55   ` =?utf-8?B?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason
2021-04-27  7:27   ` Junio C Hamano
2021-04-26 17:44 ` [PATCH v2 " Luke Shumaker
2021-04-26 17:44   ` [PATCH v2 01/30] .gitignore: Ignore /git-subtree Luke Shumaker
2021-04-26 17:44   ` [PATCH v2 02/30] subtree: t7900: update for having the default branch name be 'main' Luke Shumaker
2021-04-26 17:44   ` [PATCH v2 03/30] subtree: t7900: use test-lib.sh's test_count Luke Shumaker
2021-04-26 17:44   ` [PATCH v2 04/30] subtree: t7900: use consistent formatting Luke Shumaker
2021-04-26 19:57     ` Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 05/30] subtree: t7900: comment subtree_test_create_repo Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 06/30] subtree: t7900: use 'test' for string equality Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 07/30] subtree: t7900: delete some dead code Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 08/30] subtree: t7900: fix 'verify one file change per commit' Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 09/30] subtree: t7900: rename last_commit_message to last_commit_subject Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 10/30] subtree: t7900: add a test for the -h flag Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 11/30] subtree: t7900: add porcelain tests for 'pull' and 'push' Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 12/30] subtree: don't have loose code outside of a function Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 13/30] subtree: more consistent error propagation Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 14/30] subtree: drop support for git < 1.7 Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 15/30] subtree: use `git merge-base --is-ancestor` Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 16/30] subtree: use git-sh-setup's `say` Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 17/30] subtree: use more explicit variable names for cmdline args Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 18/30] subtree: use "$*" instead of "$@" as appropriate Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 19/30] subtree: Don't fuss with PATH Luke Shumaker
2021-04-26 23:16     ` Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 20/30] subtree: use "^{commit}" instead of "^0" Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 21/30] subtree: parse revs in individual cmd_ functions Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 22/30] subtree: remove duplicate check Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 23/30] subtree: add comments and sanity checks Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 24/30] subtree: don't let debug and progress output clash Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 25/30] subtree: have $indent actually affect indentation Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 26/30] subtree: give the docs a once-over Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 27/30] subtree: allow --squash to be used with --rejoin Luke Shumaker
2021-04-26 19:58     ` Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 28/30] subtree: allow 'split' flags to be passed to 'push' Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 29/30] subtree: push: allow specifying a local rev other than HEAD Luke Shumaker
2021-04-26 17:45   ` [PATCH v2 30/30] subtree: be stricter about validating flags Luke Shumaker
2021-04-27 21:17   ` [PATCH v3 00/30] subtree: clean up, improve UX Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 01/30] .gitignore: Ignore /git-subtree Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 02/30] subtree: t7900: update for having the default branch name be 'main' Luke Shumaker
2021-04-30  9:38       ` Ævar Arnfjörð Bjarmason
2021-04-30 16:07         ` Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 03/30] subtree: t7900: use test-lib.sh's test_count Luke Shumaker
2021-04-30  9:45       ` Ævar Arnfjörð Bjarmason
2021-04-30 16:10         ` Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 04/30] subtree: t7900: use consistent formatting Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 05/30] subtree: t7900: comment subtree_test_create_repo Luke Shumaker
2021-04-30  9:48       ` Ævar Arnfjörð Bjarmason
2021-04-30 16:13         ` Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 06/30] subtree: t7900: use 'test' for string equality Luke Shumaker
2021-04-30  9:55       ` Ævar Arnfjörð Bjarmason
2021-04-30 16:33         ` Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 07/30] subtree: t7900: delete some dead code Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 08/30] subtree: t7900: fix 'verify one file change per commit' Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 09/30] subtree: t7900: rename last_commit_message to last_commit_subject Luke Shumaker
2021-04-30  9:59       ` Ævar Arnfjörð Bjarmason
2021-04-27 21:17     ` [PATCH v3 10/30] subtree: t7900: add a test for the -h flag Luke Shumaker
2021-04-30 10:01       ` Ævar Arnfjörð Bjarmason
2021-04-30 16:40         ` Luke Shumaker
2021-04-30 12:22       ` Bagas Sanjaya
2021-04-30 16:48         ` Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 11/30] subtree: t7900: add porcelain tests for 'pull' and 'push' Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 12/30] subtree: don't have loose code outside of a function Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 13/30] subtree: more consistent error propagation Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 14/30] subtree: drop support for git < 1.7 Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 15/30] subtree: use `git merge-base --is-ancestor` Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 16/30] subtree: use git-sh-setup's `say` Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 17/30] subtree: use more explicit variable names for cmdline args Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 18/30] subtree: use "$*" instead of "$@" as appropriate Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 19/30] subtree: don't fuss with PATH Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 20/30] subtree: use "^{commit}" instead of "^0" Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 21/30] subtree: parse revs in individual cmd_ functions Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 22/30] subtree: remove duplicate check Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 23/30] subtree: add comments and sanity checks Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 24/30] subtree: don't let debug and progress output clash Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 25/30] subtree: have $indent actually affect indentation Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 26/30] subtree: give the docs a once-over Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 27/30] subtree: allow --squash to be used with --rejoin Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 28/30] subtree: allow 'split' flags to be passed to 'push' Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 29/30] subtree: push: allow specifying a local rev other than HEAD Luke Shumaker
2021-04-27 21:17     ` [PATCH v3 30/30] subtree: be stricter about validating flags Luke Shumaker
     [not found]       ` <CAAgkN4cKUSPKpwuaLG-vR5Z7WFUZ81QXuRcsX-10obaRBAvwBA@mail.gmail.com>
2021-04-28  0:24         ` Luke Shumaker

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).