diff options
Diffstat (limited to 'contrib/subtree')
-rw-r--r-- | contrib/subtree/.gitignore | 3 | ||||
-rw-r--r-- | contrib/subtree/Makefile | 63 | ||||
-rwxr-xr-x | contrib/subtree/git-subtree.sh | 62 | ||||
-rw-r--r-- | contrib/subtree/git-subtree.txt | 209 | ||||
-rwxr-xr-x | contrib/subtree/t/t7900-subtree.sh | 387 |
5 files changed, 367 insertions, 357 deletions
diff --git a/contrib/subtree/.gitignore b/contrib/subtree/.gitignore index 91360a3d7f..0b9381abca 100644 --- a/contrib/subtree/.gitignore +++ b/contrib/subtree/.gitignore @@ -1,6 +1,7 @@ *~ git-subtree -git-subtree.xml git-subtree.1 +git-subtree.html +git-subtree.xml mainline subproj diff --git a/contrib/subtree/Makefile b/contrib/subtree/Makefile index 05cdd5c9b2..3071baf493 100644 --- a/contrib/subtree/Makefile +++ b/contrib/subtree/Makefile @@ -1,19 +1,34 @@ +# The default target of this Makefile is... +all:: + -include ../../config.mak.autogen -include ../../config.mak prefix ?= /usr/local +gitexecdir ?= $(prefix)/libexec/git-core mandir ?= $(prefix)/share/man -libexecdir ?= $(prefix)/libexec/git-core -gitdir ?= $(shell git --exec-path) man1dir ?= $(mandir)/man1 +htmldir ?= $(prefix)/share/doc/git-doc + +../../GIT-VERSION-FILE: FORCE + $(MAKE) -C ../../ GIT-VERSION-FILE -gitver ?= $(word 3,$(shell git --version)) +-include ../../GIT-VERSION-FILE # this should be set to a 'standard' bsd-type install program -INSTALL ?= install +INSTALL ?= install +RM ?= rm -f + +ASCIIDOC = asciidoc +XMLTO = xmlto + +ifndef SHELL_PATH + SHELL_PATH = /bin/sh +endif +SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) -ASCIIDOC_CONF = ../../Documentation/asciidoc.conf -MANPAGE_NORMAL_XSL = ../../Documentation/manpage-normal.xsl +ASCIIDOC_CONF = ../../Documentation/asciidoc.conf +MANPAGE_XSL = ../../Documentation/manpage-normal.xsl GIT_SUBTREE_SH := git-subtree.sh GIT_SUBTREE := git-subtree @@ -21,32 +36,46 @@ GIT_SUBTREE := git-subtree GIT_SUBTREE_DOC := git-subtree.1 GIT_SUBTREE_XML := git-subtree.xml GIT_SUBTREE_TXT := git-subtree.txt +GIT_SUBTREE_HTML := git-subtree.html -all: $(GIT_SUBTREE) +all:: $(GIT_SUBTREE) $(GIT_SUBTREE): $(GIT_SUBTREE_SH) - cp $< $@ && chmod +x $@ + sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' $< >$@ + chmod +x $@ -doc: $(GIT_SUBTREE_DOC) +doc: $(GIT_SUBTREE_DOC) $(GIT_SUBTREE_HTML) install: $(GIT_SUBTREE) - $(INSTALL) -m 755 $(GIT_SUBTREE) $(libexecdir) + $(INSTALL) -d -m 755 $(DESTDIR)$(gitexecdir) + $(INSTALL) -m 755 $(GIT_SUBTREE) $(DESTDIR)$(gitexecdir) -install-doc: install-man +install-doc: install-man install-html install-man: $(GIT_SUBTREE_DOC) - $(INSTALL) -m 644 $^ $(man1dir) + $(INSTALL) -d -m 755 $(DESTDIR)$(man1dir) + $(INSTALL) -m 644 $^ $(DESTDIR)$(man1dir) + +install-html: $(GIT_SUBTREE_HTML) + $(INSTALL) -d -m 755 $(DESTDIR)$(htmldir) + $(INSTALL) -m 644 $^ $(DESTDIR)$(htmldir) $(GIT_SUBTREE_DOC): $(GIT_SUBTREE_XML) - xmlto -m $(MANPAGE_NORMAL_XSL) man $^ + $(XMLTO) -m $(MANPAGE_XSL) man $^ $(GIT_SUBTREE_XML): $(GIT_SUBTREE_TXT) - asciidoc -b docbook -d manpage -f $(ASCIIDOC_CONF) \ - -agit_version=$(gitver) $^ + $(ASCIIDOC) -b docbook -d manpage -f $(ASCIIDOC_CONF) \ + -agit_version=$(GIT_VERSION) $^ + +$(GIT_SUBTREE_HTML): $(GIT_SUBTREE_TXT) + $(ASCIIDOC) -b xhtml11 -d manpage -f $(ASCIIDOC_CONF) \ + -agit_version=$(GIT_VERSION) $^ test: $(MAKE) -C t/ test clean: - rm -f *~ *.xml *.html *.1 - rm -rf subproj mainline + $(RM) $(GIT_SUBTREE) + $(RM) *.xml *.html *.1 + +.PHONY: FORCE diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh index 920c664bb7..9f06571851 100755 --- a/contrib/subtree/git-subtree.sh +++ b/contrib/subtree/git-subtree.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # git-subtree.sh: split/join git repositories in subdirectories of this one # @@ -9,9 +9,10 @@ if [ $# -eq 0 ]; then fi OPTS_SPEC="\ git subtree add --prefix=<prefix> <commit> +git subtree add --prefix=<prefix> <repository> <ref> git subtree merge --prefix=<prefix> <commit> -git subtree pull --prefix=<prefix> <repository> <refspec...> -git subtree push --prefix=<prefix> <repository> <refspec...> +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 @@ -25,7 +26,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', 'pull' and 'push' + options for 'add', 'merge', and 'pull' squash merge subtree changes as a single commit " eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)" @@ -45,18 +46,26 @@ ignore_joins= annotate= squash= message= +prefix= debug() { if [ -n "$debug" ]; then - echo "$@" >&2 + printf "%s\n" "$*" >&2 fi } say() { if [ -z "$quiet" ]; then - echo "$@" >&2 + printf "%s\n" "$*" >&2 + fi +} + +progress() +{ + if [ -z "$quiet" ]; then + printf "%s\r" "$*" >&2 fi } @@ -296,7 +305,7 @@ copy_commit() # 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}" - git log -1 --pretty=format:'%an%n%ae%n%ad%n%cn%n%ce%n%cd%n%s%n%n%b' "$1" | + git log -1 --pretty=format:'%an%n%ae%n%aD%n%cn%n%ce%n%cD%n%B' "$1" | ( read GIT_AUTHOR_NAME read GIT_AUTHOR_EMAIL @@ -310,7 +319,7 @@ copy_commit() GIT_COMMITTER_NAME \ GIT_COMMITTER_EMAIL \ GIT_COMMITTER_DATE - (echo -n "$annotate"; cat ) | + (printf "%s" "$annotate"; cat ) | git commit-tree "$2" $3 # reads the rest of stdin ) || die "Can't copy commit $1" } @@ -488,6 +497,12 @@ ensure_clean() fi } +ensure_valid_ref_format() +{ + git check-ref-format "refs/heads/$1" || + die "'$1' does not look like a ref" +} + cmd_add() { if [ -e "$dir" ]; then @@ -497,12 +512,22 @@ cmd_add() ensure_clean if [ $# -eq 1 ]; then - "cmd_add_commit" "$@" + git rev-parse -q --verify "$1^{commit}" >/dev/null || + die "'$1' does not refer to a commit" + + "cmd_add_commit" "$@" elif [ $# -eq 2 ]; then - "cmd_add_repository" "$@" + # Technically we could accept a refspec here but we're + # just going to turn around and add FETCH_HEAD under the + # specified directory. Allowing a refspec might be + # misleading because we won't do anything with any other + # branches fetched via the refspec. + ensure_valid_ref_format "$2" + + "cmd_add_repository" "$@" else say "error: parameters were '$@'" - die "Provide either a refspec or a repository and refspec." + die "Provide either a commit or a repository and commit." fi } @@ -540,8 +565,9 @@ cmd_add_commit() commit=$(add_squashed_msg "$rev" "$dir" | git commit-tree $tree $headp -p "$rev") || exit $? else + revp=$(peel_committish "$rev") && commit=$(add_msg "$dir" "$headrev" "$rev" | - git commit-tree $tree $headp -p "$rev") || exit $? + git commit-tree $tree $headp -p "$revp") || exit $? fi git reset "$commit" || exit $? @@ -580,7 +606,7 @@ cmd_split() eval "$grl" | while read rev parents; do revcount=$(($revcount + 1)) - say -n "$revcount/$revmax ($createcount)
" + progress "$revcount/$revmax ($createcount)" debug "Processing commit: $rev" exists=$(cache_get $rev) if [ -n "$exists" ]; then @@ -687,7 +713,11 @@ cmd_merge() cmd_pull() { + if [ $# -ne 2 ]; then + die "You must provide <repository> <ref>" + fi ensure_clean + ensure_valid_ref_format "$2" git fetch "$@" || exit $? revs=FETCH_HEAD set -- $revs @@ -697,13 +727,15 @@ cmd_pull() cmd_push() { if [ $# -ne 2 ]; then - die "You must provide <repository> <refspec>" + die "You must provide <repository> <ref>" fi + ensure_valid_ref_format "$2" if [ -e "$dir" ]; then repository=$1 refspec=$2 echo "git push using: " $repository $refspec - git push $repository $(git subtree split --prefix=$prefix):refs/heads/$refspec + localrev=$(git subtree split --prefix="$prefix") || die + git push $repository $localrev:refs/heads/$refspec 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 c5bce41ac7..60d76cdddf 100644 --- a/contrib/subtree/git-subtree.txt +++ b/contrib/subtree/git-subtree.txt @@ -10,8 +10,9 @@ SYNOPSIS -------- [verse] 'git subtree' add -P <prefix> <commit> -'git subtree' pull -P <prefix> <repository> <refspec...> -'git subtree' push -P <prefix> <repository> <refspec...> +'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>] @@ -67,7 +68,7 @@ COMMANDS -------- add:: Create the <prefix> subtree by importing its contents - from the given <refspec> or <repository> and remote <refspec>. + from the given <commit> or <repository> and remote <ref>. A new commit is created automatically, joining the imported project's history with your own. With '--squash', imports only a single commit from the subproject, rather than its @@ -80,22 +81,21 @@ merge:: changes into the latest <commit>. With '--squash', creates 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. ++ +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 commit from the specified remote + 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 refspec. This can be used to push your + repository and ref. This can be used to push your subtree to different branches of the remote repository. split:: @@ -106,21 +106,19 @@ split:: 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. 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 (ie. 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. - - Note that if you use '--squash' when you merge, you - should usually not just '--rejoin' when you split. ++ +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. ++ +Note that if you use '--squash' when you merge, you should usually not +just '--rejoin' when you split. OPTIONS @@ -148,111 +146,98 @@ OPTIONS OPTIONS FOR add, merge, push, pull ---------------------------------- --squash:: - This option is only valid for add, merge, push and pull + 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. - - 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 using, since none of the - interim versions were ever included in their application. - - Using '--squash' also helps avoid problems when the same - subproject is included multiple times in the same - project, or is removed and then re-added. In such a - case, it doesn't make sense to combine the histories - anyway, since it's unclear which part of the history - belongs to which subtree. - - Furthermore, with '--squash', you can switch back and - forth between different versions of a subtree, rather - than strictly forward. 'git subtree merge --squash' - always adjusts the subtree to match the exactly - specified commit, even if getting to that commit would - require undoing some changes that were added earlier. - - 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. ++ +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 +using, since none of the interim versions were ever included in their +application. ++ +Using '--squash' also helps avoid problems when the same subproject is +included multiple times in the same project, or is removed and then +re-added. In such a case, it doesn't make sense to combine the +histories anyway, since it's unclear which part of the history belongs +to which subtree. ++ +Furthermore, with '--squash', you can switch back and forth between +different versions of a subtree, rather than strictly forward. 'git +subtree merge --squash' always adjusts the subtree to match the exactly +specified commit, even if getting to that commit would require undoing +some changes that were added earlier. ++ +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. OPTIONS 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. - - 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, but it may not always be effective. ++ +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, +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 you used 'git subtree add', you should never need - this option. ++ +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. - - 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 merge algorithm to more - intelligently avoid conflicts (since it knows these - synthetic commits are already part of the upstream - repository). - - 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. ++ +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 +merge algorithm to more intelligently avoid conflicts (since it knows +these synthetic commits are already part of the upstream repository). ++ +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. EXAMPLE 1. Add command @@ -269,7 +254,7 @@ git-extensions repository in ~/git-extensions/: name You can omit the --squash flag, but doing so will increase the number -of commits that are incldued in your local repository. +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 diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh index bc2eeb0944..90519823be 100755 --- a/contrib/subtree/t/t7900-subtree.sh +++ b/contrib/subtree/t/t7900-subtree.sh @@ -8,7 +8,8 @@ This test verifies the basic operation of the merge, pull, add and split subcommands of git subtree. ' -export TEST_DIRECTORY=$(pwd)/../../../t +TEST_DIRECTORY=$(pwd)/../../../t +export TEST_DIRECTORY . ../../../t/test-lib.sh @@ -60,256 +61,238 @@ last_commit_message() git log --pretty=format:%s -1 } -# 1 test_expect_success 'init subproj' ' - test_create_repo subproj + test_create_repo subproj ' # To the subproject! cd subproj -# 2 test_expect_success 'add sub1' ' - create sub1 && - git commit -m "sub1" && - git branch sub1 && - git branch -m master subproj + create sub1 && + git commit -m "sub1" && + git branch sub1 && + git branch -m master subproj ' -# 3 +# Save this hash for testing later. + +subdir_hash=$(git rev-parse HEAD) + test_expect_success 'add sub2' ' - create sub2 && - git commit -m "sub2" && - git branch sub2 + create sub2 && + git commit -m "sub2" && + git branch sub2 ' -# 4 test_expect_success 'add sub3' ' - create sub3 && - git commit -m "sub3" && - git branch sub3 + create sub3 && + git commit -m "sub3" && + git branch sub3 ' # Back to mainline cd .. -# 5 +test_expect_success 'enable log.date=relative to catch errors' ' + git config log.date relative +' + test_expect_success 'add main4' ' - create main4 && - git commit -m "main4" && - git branch -m master mainline && - git branch subdir + create main4 && + git commit -m "main4" && + git branch -m master mainline && + git branch subdir ' -# 6 test_expect_success 'fetch subproj history' ' - git fetch ./subproj sub1 && - git branch sub1 FETCH_HEAD + git fetch ./subproj sub1 && + git branch sub1 FETCH_HEAD ' -# 7 test_expect_success 'no subtree exists in main tree' ' - test_must_fail git subtree merge --prefix=subdir sub1 + test_must_fail git subtree merge --prefix=subdir sub1 ' -# 8 test_expect_success 'no pull from non-existant subtree' ' - test_must_fail git subtree pull --prefix=subdir ./subproj sub1 + test_must_fail git subtree pull --prefix=subdir ./subproj sub1 ' -# 9 test_expect_success 'check if --message works for add' ' - git subtree add --prefix=subdir --message="Added subproject" sub1 && - check_equal ''"$(last_commit_message)"'' "Added subproject" && - undo + git subtree add --prefix=subdir --message="Added subproject" sub1 && + check_equal ''"$(last_commit_message)"'' "Added subproject" && + undo ' -# 10 test_expect_success 'check if --message works as -m and --prefix as -P' ' - git subtree add -P subdir -m "Added subproject using git subtree" sub1 && - check_equal ''"$(last_commit_message)"'' "Added subproject using git subtree" && - undo + git subtree add -P subdir -m "Added subproject using git subtree" sub1 && + check_equal ''"$(last_commit_message)"'' "Added subproject using git subtree" && + undo ' -# 11 test_expect_success 'check if --message works with squash too' ' - git subtree add -P subdir -m "Added subproject with squash" --squash sub1 && - check_equal ''"$(last_commit_message)"'' "Added subproject with squash" && - undo + git subtree add -P subdir -m "Added subproject with squash" --squash sub1 && + check_equal ''"$(last_commit_message)"'' "Added subproject with squash" && + undo ' -# 12 test_expect_success 'add subproj to mainline' ' - git subtree add --prefix=subdir/ FETCH_HEAD && - check_equal ''"$(last_commit_message)"'' "Add '"'subdir/'"' from commit '"'"'''"$(git rev-parse sub1)"'''"'"'" + git subtree add --prefix=subdir/ FETCH_HEAD && + check_equal ''"$(last_commit_message)"'' "Add '"'subdir/'"' from commit '"'"'''"$(git rev-parse sub1)"'''"'"'" ' -# 13 # this shouldn't actually do anything, since FETCH_HEAD is already a parent test_expect_success 'merge fetched subproj' ' - git merge -m "merge -s -ours" -s ours FETCH_HEAD + git merge -m "merge -s -ours" -s ours FETCH_HEAD ' -# 14 test_expect_success 'add main-sub5' ' - create subdir/main-sub5 && - git commit -m "main-sub5" + create subdir/main-sub5 && + git commit -m "main-sub5" ' -# 15 test_expect_success 'add main6' ' - create main6 && - git commit -m "main6 boring" + create main6 && + git commit -m "main6 boring" ' -# 16 test_expect_success 'add main-sub7' ' - create subdir/main-sub7 && - git commit -m "main-sub7" + create subdir/main-sub7 && + git commit -m "main-sub7" ' -# 17 test_expect_success 'fetch new subproj history' ' - git fetch ./subproj sub2 && - git branch sub2 FETCH_HEAD + git fetch ./subproj sub2 && + git branch sub2 FETCH_HEAD ' -# 18 test_expect_success 'check if --message works for merge' ' - git subtree merge --prefix=subdir -m "Merged changes from subproject" sub2 && - check_equal ''"$(last_commit_message)"'' "Merged changes from subproject" && - undo + git subtree merge --prefix=subdir -m "Merged changes from subproject" sub2 && + check_equal ''"$(last_commit_message)"'' "Merged changes from subproject" && + undo ' -# 19 test_expect_success 'check if --message for merge works with squash too' ' - git subtree merge --prefix subdir -m "Merged changes from subproject using squash" --squash sub2 && - check_equal ''"$(last_commit_message)"'' "Merged changes from subproject using squash" && - undo + git subtree merge --prefix subdir -m "Merged changes from subproject using squash" --squash sub2 && + check_equal ''"$(last_commit_message)"'' "Merged changes from subproject using squash" && + undo ' -# 20 test_expect_success 'merge new subproj history into subdir' ' - git subtree merge --prefix=subdir FETCH_HEAD && - git branch pre-split && - check_equal ''"$(last_commit_message)"'' "Merge commit '"'"'"$(git rev-parse sub2)"'"'"' into mainline" + git subtree merge --prefix=subdir FETCH_HEAD && + git branch pre-split && + check_equal ''"$(last_commit_message)"'' "Merge commit '"'"'"$(git rev-parse sub2)"'"'"' into mainline" && + undo ' -# 21 test_expect_success 'Check that prefix argument is required for split' ' - echo "You must provide the --prefix option." > expected && - test_must_fail git subtree split > actual 2>&1 && - test_debug "echo -n expected: " && - test_debug "cat expected" && - test_debug "echo -n actual: " && - test_debug "cat actual" && - test_cmp expected actual && - rm -f expected actual + 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: '"'"'" && + test_debug "cat actual" && + test_cmp expected actual && + rm -f expected actual ' -# 22 test_expect_success 'Check that the <prefix> exists for a split' ' - 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 "echo -n expected: " && - test_debug "cat expected" && - test_debug "echo -n actual: " && - test_debug "cat actual" && - test_cmp expected actual -# rm -f expected actual + 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: '"'"'" && + test_debug "cat actual" && + test_cmp expected actual +# rm -f expected actual ' -# 23 test_expect_success 'check if --message works for split+rejoin' ' - spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' && - git branch spl1 "$spl1" && - check_equal ''"$(last_commit_message)"'' "Split & rejoin" && - undo + spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' && + git branch spl1 "$spl1" && + check_equal ''"$(last_commit_message)"'' "Split & rejoin" && + undo ' -# 24 test_expect_success 'check split with --branch' ' - spl1=$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin) && - undo && - git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --branch splitbr1 && - check_equal ''"$(git rev-parse splitbr1)"'' "$spl1" + spl1=$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin) && + undo && + git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --branch splitbr1 && + check_equal ''"$(git rev-parse splitbr1)"'' "$spl1" +' + +test_expect_success 'check hash of split' ' + spl1=$(git subtree split --prefix subdir) && + git subtree split --prefix subdir --branch splitbr1test && + check_equal ''"$(git rev-parse splitbr1test)"'' "$spl1" && + new_hash=$(git rev-parse splitbr1test~2) && + check_equal ''"$new_hash"'' "$subdir_hash" ' -# 25 test_expect_success 'check split with --branch for an existing branch' ' - spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' && - undo && - git branch splitbr2 sub1 && - git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --branch splitbr2 && - check_equal ''"$(git rev-parse splitbr2)"'' "$spl1" + spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' && + undo && + git branch splitbr2 sub1 && + git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --branch splitbr2 && + check_equal ''"$(git rev-parse splitbr2)"'' "$spl1" ' -# 26 test_expect_success 'check split with --branch for an incompatible branch' ' - test_must_fail git subtree split --prefix subdir --onto FETCH_HEAD --branch subdir + test_must_fail git subtree split --prefix subdir --onto FETCH_HEAD --branch subdir ' - -# 27 test_expect_success 'check split+rejoin' ' - spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' && - undo && - git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --rejoin && - check_equal ''"$(last_commit_message)"'' "Split '"'"'subdir/'"'"' into commit '"'"'"$spl1"'"'"'" + spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' && + undo && + git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --rejoin && + check_equal ''"$(last_commit_message)"'' "Split '"'"'subdir/'"'"' into commit '"'"'"$spl1"'"'"'" ' -# 28 test_expect_success 'add main-sub8' ' - create subdir/main-sub8 && - git commit -m "main-sub8" + create subdir/main-sub8 && + git commit -m "main-sub8" ' # To the subproject! cd ./subproj -# 29 test_expect_success 'merge split into subproj' ' - git fetch .. spl1 && - git branch spl1 FETCH_HEAD && - git merge FETCH_HEAD + git fetch .. spl1 && + git branch spl1 FETCH_HEAD && + git merge FETCH_HEAD ' -# 30 test_expect_success 'add sub9' ' - create sub9 && - git commit -m "sub9" + create sub9 && + git commit -m "sub9" ' # Back to mainline cd .. -# 31 test_expect_success 'split for sub8' ' - split2=''"$(git subtree split --annotate='"'*'"' --prefix subdir/ --rejoin)"'' - git branch split2 "$split2" + split2=''"$(git subtree split --annotate='"'*'"' --prefix subdir/ --rejoin)"'' && + git branch split2 "$split2" ' -# 32 test_expect_success 'add main-sub10' ' - create subdir/main-sub10 && - git commit -m "main-sub10" + create subdir/main-sub10 && + git commit -m "main-sub10" ' -# 33 test_expect_success 'split for sub10' ' - spl3=''"$(git subtree split --annotate='"'*'"' --prefix subdir --rejoin)"'' && - git branch spl3 "$spl3" + spl3=''"$(git subtree split --annotate='"'*'"' --prefix subdir --rejoin)"'' && + git branch spl3 "$spl3" ' # To the subproject! cd ./subproj -# 34 test_expect_success 'merge split into subproj' ' - git fetch .. spl3 && - git branch spl3 FETCH_HEAD && - git merge FETCH_HEAD && - git branch subproj-merge-spl3 + git fetch .. spl3 && + git branch spl3 FETCH_HEAD && + git merge FETCH_HEAD && + git branch subproj-merge-spl3 ' chkm="main4 main6" @@ -318,123 +301,107 @@ chkms_sub=$(echo $chkms | multiline | sed 's,^,subdir/,' | fixnl) chks="sub1 sub2 sub3 sub9" chks_sub=$(echo $chks | multiline | sed 's,^,subdir/,' | fixnl) -# 35 test_expect_success 'make sure exactly the right set of files ends up in the subproj' ' - subfiles=''"$(git ls-files | fixnl)"'' && - check_equal "$subfiles" "$chkms $chks" + subfiles=''"$(git ls-files | fixnl)"'' && + check_equal "$subfiles" "$chkms $chks" ' -# 36 test_expect_success 'make sure the subproj history *only* contains commits that affect the subdir' ' - allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | fixnl)"'' && - check_equal "$allchanges" "$chkms $chks" + allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | fixnl)"'' && + check_equal "$allchanges" "$chkms $chks" ' # Back to mainline cd .. -# 37 test_expect_success 'pull from subproj' ' - git fetch ./subproj subproj-merge-spl3 && - git branch subproj-merge-spl3 FETCH_HEAD && - git subtree pull --prefix=subdir ./subproj subproj-merge-spl3 + git fetch ./subproj subproj-merge-spl3 && + git branch subproj-merge-spl3 FETCH_HEAD && + git subtree pull --prefix=subdir ./subproj subproj-merge-spl3 ' -# 38 test_expect_success 'make sure exactly the right set of files ends up in the mainline' ' - mainfiles=''"$(git ls-files | fixnl)"'' && - check_equal "$mainfiles" "$chkm $chkms_sub $chks_sub" + mainfiles=''"$(git ls-files | fixnl)"'' && + check_equal "$mainfiles" "$chkm $chkms_sub $chks_sub" ' -# 39 test_expect_success 'make sure each filename changed exactly once in the entire history' ' - # main-sub?? and /subdir/main-sub?? both change, because those are the - # changes that were split into their own history. And subdir/sub?? never - # change, since they were *only* changed in the subtree branch. - allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | fixnl)"'' && - check_equal "$allchanges" ''"$(echo $chkms $chkm $chks $chkms_sub | multiline | sort | fixnl)"'' + # main-sub?? and /subdir/main-sub?? both change, because those are the + # changes that were split into their own history. And subdir/sub?? never + # change, since they were *only* changed in the subtree branch. + allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | fixnl)"'' && + check_equal "$allchanges" ''"$(echo $chkms $chkm $chks $chkms_sub | multiline | sort | fixnl)"'' ' -# 40 test_expect_success 'make sure the --rejoin commits never make it into subproj' ' - check_equal ''"$(git log --pretty=format:'"'%s'"' HEAD^2 | grep -i split)"'' "" + check_equal ''"$(git log --pretty=format:'"'%s'"' HEAD^2 | grep -i split)"'' "" ' -# 41 test_expect_success 'make sure no "git subtree" tagged commits make it into subproj' ' - # 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.*:")"'' "" + # 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.*:")"'' "" ' # prepare second pair of repositories mkdir test2 cd test2 -# 42 test_expect_success 'init main' ' - test_create_repo main + test_create_repo main ' cd main -# 43 test_expect_success 'add main1' ' - create main1 && - git commit -m "main1" + create main1 && + git commit -m "main1" ' cd .. -# 44 test_expect_success 'init sub' ' - test_create_repo sub + test_create_repo sub ' cd sub -# 45 test_expect_success 'add sub2' ' - create sub2 && - git commit -m "sub2" + create sub2 && + git commit -m "sub2" ' cd ../main # check if split can find proper base without --onto -# 46 test_expect_success 'add sub as subdir in main' ' - git fetch ../sub master && - git branch sub2 FETCH_HEAD && - git subtree add --prefix subdir sub2 + git fetch ../sub master && + git branch sub2 FETCH_HEAD && + git subtree add --prefix subdir sub2 ' cd ../sub -# 47 test_expect_success 'add sub3' ' - create sub3 && - git commit -m "sub3" + create sub3 && + git commit -m "sub3" ' cd ../main -# 48 test_expect_success 'merge from sub' ' - git fetch ../sub master && - git branch sub3 FETCH_HEAD && - git subtree merge --prefix subdir sub3 + git fetch ../sub master && + git branch sub3 FETCH_HEAD && + git subtree merge --prefix subdir sub3 ' -# 49 test_expect_success 'add main-sub4' ' - create subdir/main-sub4 && - git commit -m "main-sub4" + create subdir/main-sub4 && + git commit -m "main-sub4" ' -# 50 test_expect_success 'split for main-sub4 without --onto' ' - git subtree split --prefix subdir --branch mainsub4 + git subtree split --prefix subdir --branch mainsub4 ' # at this point, the new commit parent should be sub3 if it is not, @@ -442,25 +409,22 @@ test_expect_success 'split for main-sub4 without --onto' ' # have been sub3, but it was not, because its cache was not set to # itself) -# 51 test_expect_success 'check that the commit parent is sub3' ' - check_equal ''"$(git log --pretty=format:%P -1 mainsub4)"'' ''"$(git rev-parse sub3)"'' + check_equal ''"$(git log --pretty=format:%P -1 mainsub4)"'' ''"$(git rev-parse sub3)"'' ' -# 52 test_expect_success 'add main-sub5' ' - mkdir subdir2 && - create subdir2/main-sub5 && - git commit -m "main-sub5" + mkdir subdir2 && + create subdir2/main-sub5 && + git commit -m "main-sub5" ' -# 53 test_expect_success 'split for main-sub5 without --onto' ' - # 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, - # then the new subtree has accidently been attached to something - git subtree split --prefix subdir2 --branch mainsub5 && - check_equal ''"$(git log --pretty=format:%P -1 mainsub5)"'' "" + # 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, + # then the new subtree has accidentally been attached to something + git subtree split --prefix subdir2 --branch mainsub5 && + check_equal ''"$(git log --pretty=format:%P -1 mainsub5)"'' "" ' # make sure no patch changes more than one file. The original set of commits @@ -487,22 +451,21 @@ joincommits() echo "$commit $all" } -# 54 test_expect_success 'verify one file change per commit' ' - x= && - list=''"$(git log --pretty=format:'"'commit: %H'"' | joincommits)"'' && -# test_debug "echo HERE" && -# test_debug "echo ''"$list"''" && - (git log --pretty=format:'"'commit: %H'"' | joincommits | - ( while read commit a b; do - test_debug "echo Verifying commit "''"$commit"'' - test_debug "echo a: "''"$a"'' - test_debug "echo b: "''"$b"'' - check_equal "$b" "" - x=1 - done - check_equal "$x" 1 - )) + x= && + list=''"$(git log --pretty=format:'"'commit: %H'"' | joincommits)"'' && +# test_debug "echo HERE" && +# test_debug "echo ''"$list"''" && + (git log --pretty=format:'"'commit: %H'"' | joincommits | + ( while read commit a b; do + test_debug "echo Verifying commit "''"$commit"'' + test_debug "echo a: "''"$a"'' + test_debug "echo b: "''"$b"'' + check_equal "$b" "" + x=1 + done + check_equal "$x" 1 + )) ' test_done |