From 3deea89c5feb0dfdfb99ea752f83497d97a3bdd5 Mon Sep 17 00:00:00 2001 From: Johan Herland Date: Tue, 16 Feb 2010 11:21:14 +0100 Subject: submodule summary: Don't barf when invoked in an empty repo When invoking "git submodule summary" in an empty repo (which can be indirectly done by setting status.submodulesummary = true), it currently emits an error message (via "git diff-index") since HEAD points to an unborn branch. This patch adds handling of the HEAD-points-to-unborn-branch special case, so that "git submodule summary" no longer emits this error message. The patch also adds a test case that verifies the fix. Suggested-by: Jeff King Signed-off-by: Johan Herland Signed-off-by: Junio C Hamano --- git-submodule.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'git-submodule.sh') diff --git a/git-submodule.sh b/git-submodule.sh index 664f21721c..5869c00f2d 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -553,12 +553,15 @@ cmd_summary() { test $summary_limit = 0 && return - if rev=$(git rev-parse -q --verify "$1^0") + if rev=$(git rev-parse -q --verify --default HEAD ${1+"$1"}) then head=$rev shift + elif test -z "$1" -o "$1" = "HEAD" + then + return else - head=HEAD + head="HEAD" fi if [ -n "$files" ] -- cgit v1.3 From 74ae14199dfb4b3b22a10d3dcecb62b457245564 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Thu, 25 Feb 2010 00:34:17 +0100 Subject: submodules: ensure clean environment when operating in a submodule git-submodule used to take care of clearing GIT_DIR whenever it operated on a submodule index or configuration, but forgot to unset GIT_WORK_TREE or other repo-local variables. This would lead to failures e.g. when GIT_WORK_TREE was set. This only happened in very unusual contexts such as operating on the main worktree from outside of it, but since "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" (a9fa11fe5bd5978bb) such failures could also be provoked by invoking an external tool such as "git submodule update" from the Git Gui in a standard setup. Solve by using the newly introduced clear_local_git_env() shell function to ensure that all repo-local environment variables are unset. Signed-off-by: Giuseppe Bilotta Signed-off-by: Junio C Hamano --- git-submodule.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'git-submodule.sh') diff --git a/git-submodule.sh b/git-submodule.sh index 664f21721c..e2082fd149 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -222,7 +222,7 @@ cmd_add() module_clone "$path" "$realrepo" "$reference" || exit ( - unset GIT_DIR + clear_local_git_env cd "$path" && # ash fails to wordsplit ${branch:+-b "$branch"...} case "$branch" in @@ -278,7 +278,7 @@ cmd_foreach() name=$(module_name "$path") ( prefix="$prefix$path/" - unset GIT_DIR + clear_local_git_env cd "$path" && eval "$@" && if test -n "$recursive" @@ -434,7 +434,7 @@ cmd_update() module_clone "$path" "$url" "$reference"|| exit subsha1= else - subsha1=$(unset GIT_DIR; cd "$path" && + subsha1=$(clear_local_git_env; cd "$path" && git rev-parse --verify HEAD) || die "Unable to find current revision in submodule path '$path'" fi @@ -454,7 +454,7 @@ cmd_update() if test -z "$nofetch" then - (unset GIT_DIR; cd "$path" && + (clear_local_git_env; cd "$path" && git-fetch) || die "Unable to fetch in submodule path '$path'" fi @@ -477,14 +477,14 @@ cmd_update() ;; esac - (unset GIT_DIR; cd "$path" && $command "$sha1") || + (clear_local_git_env; cd "$path" && $command "$sha1") || die "Unable to $action '$sha1' in submodule path '$path'" say "Submodule path '$path': $msg '$sha1'" fi if test -n "$recursive" then - (unset GIT_DIR; cd "$path" && cmd_update $orig_args) || + (clear_local_git_env; cd "$path" && cmd_update $orig_args) || die "Failed to recurse into submodule path '$path'" fi done @@ -492,7 +492,7 @@ cmd_update() set_name_rev () { revname=$( ( - unset GIT_DIR + clear_local_git_env cd "$1" && { git describe "$2" 2>/dev/null || git describe --tags "$2" 2>/dev/null || @@ -757,7 +757,7 @@ cmd_status() else if test -z "$cached" then - sha1=$(unset GIT_DIR; cd "$path" && git rev-parse --verify HEAD) + sha1=$(clear_local_git_env; cd "$path" && git rev-parse --verify HEAD) set_name_rev "$path" "$sha1" fi say "+$sha1 $displaypath$revname" @@ -767,7 +767,7 @@ cmd_status() then ( prefix="$displaypath/" - unset GIT_DIR + clear_local_git_env cd "$path" && cmd_status $orig_args ) || @@ -818,7 +818,7 @@ cmd_sync() if test -e "$path"/.git then ( - unset GIT_DIR + clear_local_git_env cd "$path" remote=$(get_default_remote) say "Synchronizing submodule url for '$name'" -- cgit v1.3 From caa9c3cabe9c2719a340425db5c0968fd3588fc9 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 3 Mar 2010 14:19:09 -0800 Subject: submodule summary: do not shift a non-existent positional variable When "git submodule summary" is run without any argument, we default to compare the state of index with the HEAD, but tried to shift out $1 that does not exist (and worse yet, we didn't use it). Signed-off-by: Junio C Hamano --- git-submodule.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'git-submodule.sh') diff --git a/git-submodule.sh b/git-submodule.sh index 5869c00f2d..383dc45119 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -556,7 +556,7 @@ cmd_summary() { if rev=$(git rev-parse -q --verify --default HEAD ${1+"$1"}) then head=$rev - shift + test $# = 0 || shift elif test -z "$1" -o "$1" = "HEAD" then return -- cgit v1.3 From 14e940d719e9d3250b802fbc975210dafaf896d8 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 3 Mar 2010 14:19:10 -0800 Subject: submodule summary: do not fail before the first commit When "git status" collects changes for the index (usually relative to HEAD), it compares the index with an empty tree when the repository does not have an initial commit yet. "git submodule summary" is about asking what submodule changes would be recorded if a commit is made right now, and should do the same comparison to report all the added submodules, instead of punting and being silent. Signed-off-by: Junio C Hamano --- git-submodule.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'git-submodule.sh') diff --git a/git-submodule.sh b/git-submodule.sh index 383dc45119..9aa57dd6f7 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -559,7 +559,8 @@ cmd_summary() { test $# = 0 || shift elif test -z "$1" -o "$1" = "HEAD" then - return + # before the first commit: compare with an empty tree + head=$(git hash-object -w -t tree --stdin Date: Tue, 9 Mar 2010 15:55:32 +0100 Subject: git submodule summary: Handle HEAD as argument when on an unborn branch When calling "git submodule summary HEAD" on an unborn branch the output was empty even when it shouldn't have been ("git submodule summary" without the HEAD argument prints the expected output since commit "submodule summary: do not fail before the first commit"). This also fixes "git status" to emit the "Submodule changes to be committed" section on an unborn branch when used with the status.submodulesummary config option. Signed-off-by: Jens Lehmann Signed-off-by: Junio C Hamano --- git-submodule.sh | 1 + 1 file changed, 1 insertion(+) (limited to 'git-submodule.sh') diff --git a/git-submodule.sh b/git-submodule.sh index 9aa57dd6f7..5a9d3c0b30 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -561,6 +561,7 @@ cmd_summary() { then # before the first commit: compare with an empty tree head=$(git hash-object -w -t tree --stdin Date: Thu, 8 Apr 2010 15:42:37 -0400 Subject: script with rev-list instead of log Because log.decorate now shows decorations for --pretty=oneline, we must explicitly turn it off when scripting. Otherwise, users with log.decorate set will get cruft like: $ git stash Saved working directory and index state WIP on master: 2c1f7f5 (HEAD, master) commit subject Instead of adding --no-decorate to the log command line, let's just use the rev-list plumbing interface instead, which does the right thing. git-submodule has a similar call. Since it just counts the commit lines, nothing is broken, but let's switch it, too, for the sake of consistency and cleanliness. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- git-stash.sh | 2 +- git-submodule.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'git-submodule.sh') diff --git a/git-stash.sh b/git-stash.sh index 3a0685f189..0726a4a725 100755 --- a/git-stash.sh +++ b/git-stash.sh @@ -57,7 +57,7 @@ create_stash () { # state of the base commit if b_commit=$(git rev-parse --verify HEAD) then - head=$(git log --no-color --abbrev-commit --pretty=oneline -n 1 HEAD --) + head=$(git rev-list --oneline -n 1 HEAD --) else die "You do not have the initial commit yet" fi diff --git a/git-submodule.sh b/git-submodule.sh index 664f21721c..c8d80822c2 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -643,7 +643,7 @@ cmd_summary() { range=$sha1_dst fi GIT_DIR="$name/.git" \ - git log --pretty=oneline --first-parent $range | wc -l + git rev-list --first-parent $range -- | wc -l ) total_commits=" ($(($total_commits + 0)))" ;; -- cgit v1.3 From 48bb30331dc1139a7279d1665cfc76f14b5d0e67 Mon Sep 17 00:00:00 2001 From: Gerrit Pape Date: Mon, 26 Apr 2010 11:50:39 +0200 Subject: git-submodule.sh: properly initialize shell variables git-submodule inherits variables from the environment it is started in, expects the internal variables init= and recursive= to have an empty value, but doesn't initialize them appropriately. Thanks to the selftests, this can be reproduced through init=1 make test recursive=1 make test With this commit the variables are initialized, and the selftests succeed even if these variables have some values in the environment. The bug was discovered through the Debian autobuilders http://bugs.debian.org/569594 Signed-off-by: Gerrit Pape Signed-off-by: Junio C Hamano --- git-submodule.sh | 2 ++ 1 file changed, 2 insertions(+) (limited to 'git-submodule.sh') diff --git a/git-submodule.sh b/git-submodule.sh index e2082fd149..d3c583d011 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -21,6 +21,8 @@ command= branch= reference= cached= +recursive= +init= files= nofetch= update= -- cgit v1.3 From f030c96d8643fa0a1a9b2bd9c2f36a77721fb61f Mon Sep 17 00:00:00 2001 From: Ævar Arnfjörð Bjarmason Date: Fri, 21 May 2010 16:10:10 +0000 Subject: git-submodule foreach: Add $toplevel variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a $toplevel variable accessible to `git submodule foreach`, it contains the absolute path of the top level directory (where .gitmodules is). This makes it possible to e.g. read data in .gitmodules from within foreach commands. I'm using this to configure the branch names I want to track for each submodule: git submodule foreach 'git checkout $(git config --file $toplevel/.gitmodules submodule.$name.branch) && git pull' For a little history: This patch is borne out of my continuing fight of trying to have Git track the branches of submodules, not just their commits. Obviously that's not how they work (they only track commits), but I'm just interested in being able to do: git submodule foreach 'git pull' Of course that won't work because the submodule is in a disconnected head, so I first have to connect it, but connect it *to what*. For a while I was happy with this because as fate had it, it just so happened to do what I meant: git submodule foreach 'git checkout $(git describe --all --always) && git pull' But then that broke down, if there's a tag and a branch the tag will win out, and I can't git pull a branch: $ git branch -a * master remotes/origin/HEAD -> origin/master remotes/origin/master $ git tag -l release-0.0.6 $ git describe --always --all release-0.0.6 So I figured that I might as well start tracking the branches I want in .gitmodules itself: [submodule "yaml-mode"] path = yaml-mode url = git://github.com/yoshiki/yaml-mode.git branch = master So now I can just do (as stated above): git submodule foreach 'git checkout $(git config --file $toplevel/.gitmodules submodule.$name.branch) && git pull' Maybe there's a less painful way to do *that* (I'd love to hear about it). But regardless of that I think it's a good idea to be able to know what the top-level is from git submodule foreach. Signed-off-by: Ævar Arnfjörð Bjarmason Signed-off-by: Junio C Hamano --- Documentation/git-submodule.txt | 6 ++++-- git-submodule.sh | 2 ++ t/t7407-submodule-foreach.sh | 10 +++++++--- 3 files changed, 13 insertions(+), 5 deletions(-) (limited to 'git-submodule.sh') diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index 2502531a3d..cdabfd29ad 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -145,10 +145,12 @@ summary:: foreach:: Evaluates an arbitrary shell command in each checked out submodule. - The command has access to the variables $name, $path and $sha1: + The command has access to the variables $name, $path, $sha1 and + $toplevel: $name is the name of the relevant submodule section in .gitmodules, $path is the name of the submodule directory relative to the - superproject, and $sha1 is the commit as recorded in the superproject. + superproject, $sha1 is the commit as recorded in the superproject, + and $toplevel is the absolute path to the top-level of the superproject. Any submodules defined in the superproject but not checked out are ignored by this command. Unless given --quiet, foreach prints the name of each submodule before evaluating the command. diff --git a/git-submodule.sh b/git-submodule.sh index 8175cb279d..8c562a72e6 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -271,6 +271,8 @@ cmd_foreach() shift done + toplevel=$(pwd) + module_list | while read mode sha1 stage path do diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 2a527750ce..db9365b645 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -59,11 +59,13 @@ test_expect_success 'setup a submodule tree' ' sub1sha1=$(cd super/sub1 && git rev-parse HEAD) sub3sha1=$(cd super/sub3 && git rev-parse HEAD) +pwd=$(pwd) + cat > expect < ../actual + git submodule foreach "echo \$toplevel-\$name-\$path-\$sha1" > ../actual && + git config foo.bar zar && + git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar" ) && test_cmp expect actual ' -- cgit v1.3 From 18076502cb282482f3cd75d766e1478cc3fccc29 Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Fri, 25 Jun 2010 16:56:02 +0200 Subject: git submodule: ignore dirty submodules for summary and status The summary and status commands only care about submodule commits, so it is rather pointless that they check for dirty work trees. This saves the time needed to scan the submodules work tree. Even "git status" profits from these savings when the status.submodulesummary config option is set, as this lead to traversing the submodule work trees twice, once for status and once again for the submodule summary. And if the submodule was just dirty, submodule summary produced rather meaningless output anyway: * sub 1234567...1234567 (0): Signed-off-by: Jens Lehmann Signed-off-by: Junio C Hamano --- git-submodule.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'git-submodule.sh') diff --git a/git-submodule.sh b/git-submodule.sh index 3319b836b2..5e7b1279c4 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -578,7 +578,7 @@ cmd_summary() { cd_to_toplevel # Get modified modules cared by user - modules=$(git $diff_cmd $cached --raw $head -- "$@" | + modules=$(git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- "$@" | sane_egrep '^:([0-7]* )?160000' | while read mod_src mod_dst sha1_src sha1_dst status name do @@ -592,7 +592,7 @@ cmd_summary() { test -z "$modules" && return - git $diff_cmd $cached --raw $head -- $modules | + git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- $modules | sane_egrep '^:([0-7]* )?160000' | cut -c2- | while read mod_src mod_dst sha1_src sha1_dst status name @@ -758,7 +758,7 @@ cmd_status() continue; fi set_name_rev "$path" "$sha1" - if git diff-files --quiet -- "$path" + if git diff-files --ignore-submodules=dirty --quiet -- "$path" then say " $sha1 $displaypath$revname" else -- cgit v1.3 From 31991b0260216d16f2e447e68bcabd9d9cce26ba Mon Sep 17 00:00:00 2001 From: Ævar Arnfjörð Bjarmason Date: Mon, 5 Jul 2010 17:33:03 +0000 Subject: git submodule: add submodules with git add -f MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change `git submodule add' to add the new submodule with `git add --force'. I keep my /etc in .git with a .gitignore that contains just "*". I.e. `git status' will ignore everything that isn't in the tree already. When I do: git submodule add hlagh git-submodule will get as far as checking out the remote repository into hlagh, but it'll die right afterwards when it fails to add the new path: The following paths are ignored by one of your .gitignore files: hlagh Use -f if you really want to add them. fatal: no files added Failed to add submodule 'hlagh' Currently there's no way to add a submodule in this situation other than to remove the ignored path from the .gitignore while I'm at it. That's silly, when you run `git submodule add' you're explicitly saying that you want to add something *new* to the repository. Instead it should just add the path with `git add --force'. Initially I implemented this by adding new -f and --force options to `git submodule add'. But if the --force option isn't supplied it'll get as far as cloning `hlagh', but won't add it. So the first thing the user has to do is to remove `hlagh' and then try again with the --force option. That sucks, it should just add the path to begin with. I can't think of any usecase where you've gone through the trouble of typing out `git submodule add ..', but wish to be overriden by a `gitignore'. The submodule semantics should be more like `git init', not `git add'. Signed-off-by: Ævar Arnfjörð Bjarmason Signed-off-by: Junio C Hamano --- Documentation/git-submodule.txt | 4 ++++ git-submodule.sh | 4 ++-- t/t7400-submodule-basic.sh | 24 +++++++++++++++++++++++- 3 files changed, 29 insertions(+), 3 deletions(-) (limited to 'git-submodule.sh') diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index cdabfd29ad..76a832a3ac 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -95,6 +95,10 @@ is the superproject and submodule repositories will be kept together in the same relative location, and only the superproject's URL needs to be provided: git-submodule will correctly locate the submodule using the relative URL in .gitmodules. ++ +The submodule will be added with "git add --force ". I.e. git +doesn't care if the new path is in a `gitignore`. Your invocation of +"git submodule add" is considered enough to override it. status:: Show the status of the submodules. This will print the SHA-1 of the diff --git a/git-submodule.sh b/git-submodule.sh index d9950c2b7f..ad2417d1b0 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -234,12 +234,12 @@ cmd_add() ) || die "Unable to checkout submodule '$path'" fi - git add "$path" || + git add --force "$path" || die "Failed to add submodule '$path'" git config -f .gitmodules submodule."$path".path "$path" && git config -f .gitmodules submodule."$path".url "$repo" && - git add .gitmodules || + git add --force .gitmodules || die "Failed to register submodule '$path'" } diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 97ff074da7..d9f2785993 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -42,7 +42,8 @@ test_expect_success 'setup - hide init subdirectory' ' ' test_expect_success 'setup - repository to add submodules to' ' - git init addtest + git init addtest && + git init addtest-ignore ' # The 'submodule add' tests need some repository to add as a submodule. @@ -85,6 +86,27 @@ test_expect_success 'submodule add' ' test_cmp empty untracked ' +test_expect_success 'submodule add to .gitignored path' ' + echo "refs/heads/master" >expect && + >empty && + + ( + cd addtest-ignore && + # Does not use test_commit due to the ignore + echo "*" > .gitignore && + git add --force .gitignore && + git commit -m"Ignore everything" && + git submodule add "$submodurl" submod && + git submodule init + ) && + + rm -f heads head untracked && + inspect addtest/submod ../.. && + test_cmp expect heads && + test_cmp expect head && + test_cmp empty untracked +' + test_expect_success 'submodule add --branch' ' echo "refs/heads/initial" >expect-head && cat <<-\EOF >expect-heads && -- cgit v1.3 From d27b876b284b8fb82db971bc7cea8c9782614ab2 Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Sat, 17 Jul 2010 17:11:43 +0200 Subject: git submodule add: Require the new --force option to add ignored paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To make the behavior of "git submodule add" more consistent with "git add" ignored submodule paths should not be silently added when they match an entry in a .gitignore file. To be able to override that default behavior in the same way as we can do that for "git add", the new option "--force" is introduced. Signed-off-by: Jens Lehmann Acked-by: Ævar Arnfjörð Bjarmason Signed-off-by: Junio C Hamano --- Documentation/git-submodule.txt | 7 ++++++- git-submodule.sh | 16 ++++++++++++++-- t/t7400-submodule-basic.sh | 27 +++++++++++++++------------ 3 files changed, 35 insertions(+), 15 deletions(-) (limited to 'git-submodule.sh') diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index 76a832a3ac..617069fb04 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -9,7 +9,7 @@ git-submodule - Initialize, update or inspect submodules SYNOPSIS -------- [verse] -'git submodule' [--quiet] add [-b branch] +'git submodule' [--quiet] add [-b branch] [-f|--force] [--reference ] [--] [] 'git submodule' [--quiet] status [--cached] [--recursive] [--] [...] 'git submodule' [--quiet] init [--] [...] @@ -187,6 +187,11 @@ OPTIONS --branch:: Branch of repository to add as submodule. +-f:: +--force:: + This option is only valid for the add command. + Allow adding an otherwise ignored submodule path. + --cached:: This option is only valid for status and summary commands. These commands typically use the commit found in the submodule HEAD, but diff --git a/git-submodule.sh b/git-submodule.sh index ad2417d1b0..170186f494 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -5,7 +5,7 @@ # Copyright (c) 2007 Lars Hjemli dashless=$(basename "$0" | sed -e 's/-/ /') -USAGE="[--quiet] add [-b branch] [--reference ] [--] [] +USAGE="[--quiet] add [-b branch] [-f|--force] [--reference ] [--] [] or: $dashless [--quiet] status [--cached] [--recursive] [--] [...] or: $dashless [--quiet] init [--] [...] or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference ] [--merge] [--recursive] [--] [...] @@ -19,6 +19,7 @@ require_work_tree command= branch= +force= reference= cached= recursive= @@ -133,6 +134,9 @@ cmd_add() branch=$2 shift ;; + -f | --force) + force=$1 + ;; -q|--quiet) GIT_QUIET=1 ;; @@ -201,6 +205,14 @@ cmd_add() git ls-files --error-unmatch "$path" > /dev/null 2>&1 && die "'$path' already exists in the index" + if test -z "$force" && ! git add --dry-run --ignore-missing "$path" > /dev/null 2>&1 + then + echo >&2 "The following path is ignored by one of your .gitignore files:" && + echo >&2 $path && + echo >&2 "Use -f if you really want to add it." + exit 1 + fi + # perhaps the path exists and is already a git repo, else clone it if test -e "$path" then @@ -234,7 +246,7 @@ cmd_add() ) || die "Unable to checkout submodule '$path'" fi - git add --force "$path" || + git add $force "$path" || die "Failed to add submodule '$path'" git config -f .gitmodules submodule."$path".path "$path" && diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index d9f2785993..9bda970584 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -86,25 +86,28 @@ test_expect_success 'submodule add' ' test_cmp empty untracked ' -test_expect_success 'submodule add to .gitignored path' ' - echo "refs/heads/master" >expect && - >empty && - +test_expect_success 'submodule add to .gitignored path fails' ' ( cd addtest-ignore && + cat <<-\EOF >expect && + The following path is ignored by one of your .gitignore files: + submod + Use -f if you really want to add it. + EOF # Does not use test_commit due to the ignore echo "*" > .gitignore && git add --force .gitignore && git commit -m"Ignore everything" && - git submodule add "$submodurl" submod && - git submodule init - ) && + ! git submodule add "$submodurl" submod >actual 2>&1 && + test_cmp expect actual + ) +' - rm -f heads head untracked && - inspect addtest/submod ../.. && - test_cmp expect heads && - test_cmp expect head && - test_cmp empty untracked +test_expect_success 'submodule add to .gitignored path with --force' ' + ( + cd addtest-ignore && + git submodule add --force "$submodurl" submod + ) ' test_expect_success 'submodule add --branch' ' -- cgit v1.3 From 0b9dca434f5d9208a26f47f7ec11453f1cfdfae8 Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Wed, 18 Aug 2010 08:58:33 -0700 Subject: submodule sync: Update "submodule..url" When "git submodule sync" synchronizes the repository URLs it only updates submodules' .git/config. However, the old URLs still exist in the super-project's .git/config. Update the super-project's configuration so that commands such as "git submodule update" use the URLs from .gitmodules. Signed-off-by: David Aguilar Signed-off-by: Junio C Hamano --- git-submodule.sh | 3 ++- t/t7403-submodule-sync.sh | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'git-submodule.sh') diff --git a/git-submodule.sh b/git-submodule.sh index 170186f494..9ebbab798d 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -839,10 +839,11 @@ cmd_sync() if test -e "$path"/.git then ( + say "Synchronizing submodule url for '$name'" + git config submodule."$name".url "$url" clear_local_git_env cd "$path" remote=$(get_default_remote) - say "Synchronizing submodule url for '$name'" git config remote."$remote".url "$url" ) fi diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh index 7538756487..3033c4a22d 100755 --- a/t/t7403-submodule-sync.sh +++ b/t/t7403-submodule-sync.sh @@ -58,6 +58,9 @@ test_expect_success '"git submodule sync" should update submodule URLs' ' (cd super-clone/submodule && git checkout master && git pull + ) && + (cd super-clone && + test -d "$(git config submodule.submodule.url)" ) ' -- cgit v1.3 From 33f072f8910081b12780197a2a5423227e437af8 Mon Sep 17 00:00:00 2001 From: Andreas Köhler Date: Fri, 8 Oct 2010 03:07:48 +0200 Subject: submodule sync: Update "submodule..url" for empty directories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a submodule directory has not been filled by "git submodule update" yet, then "git submodule sync" must still update the super-project's configuration for submodule..url. This situation occurs when switching between branches with a module from different urls and other branches without the submodule. Signed-off-by: Andreas Köhler Signed-off-by: Junio C Hamano --- git-submodule.sh | 5 +++-- t/t7403-submodule-sync.sh | 12 +++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'git-submodule.sh') diff --git a/git-submodule.sh b/git-submodule.sh index 9ebbab798d..c291eed59c 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -836,11 +836,12 @@ cmd_sync() ;; esac + say "Synchronizing submodule url for '$name'" + git config submodule."$name".url "$url" + if test -e "$path"/.git then ( - say "Synchronizing submodule url for '$name'" - git config submodule."$name".url "$url" clear_local_git_env cd "$path" remote=$(get_default_remote) diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh index 02522f9627..e5b19538b0 100755 --- a/t/t7403-submodule-sync.sh +++ b/t/t7403-submodule-sync.sh @@ -23,7 +23,9 @@ test_expect_success setup ' git commit -m "submodule" ) && git clone super super-clone && - (cd super-clone && git submodule update --init) + (cd super-clone && git submodule update --init) && + git clone super empty-clone && + (cd empty-clone && git submodule init) ' test_expect_success 'change submodule' ' @@ -64,4 +66,12 @@ test_expect_success '"git submodule sync" should update submodule URLs' ' ) ' +test_expect_success '"git submodule sync" should update submodule URLs if not yet cloned' ' + (cd empty-clone && + git pull && + git submodule sync && + test -d "$(git config submodule.submodule.url)" + ) +' + test_done -- cgit v1.3 From a7eff1a87ad8cdcb93f60efc7969042bc3e669ee Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Tue, 2 Nov 2010 23:26:24 -0700 Subject: submodule: preserve all arguments exactly when recursing Shell variables only hold strings, not lists of parameters, so $orig_args after orig_args="$@" fails to remember where each parameter starts and ends, if some include whitespace. So git submodule update \ --reference='/var/lib/common objects.git' \ --recursive --init becomes git submodule update --reference=/var/lib/common \ objects.git --recursive --init in the inner repositories. Use "git rev-parse --sq-quote" to save parameters in quoted form ready for evaluation by the shell, avoiding this problem. Helped-By: Jonathan Nieder Signed-off-by: Kevin Ballard Signed-off-by: Junio C Hamano --- git-submodule.sh | 8 ++++---- t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) (limited to 'git-submodule.sh') diff --git a/git-submodule.sh b/git-submodule.sh index 9ebbab798d..4d2bb37215 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -374,7 +374,7 @@ cmd_init() cmd_update() { # parse $args after "submodule ... update". - orig_args="$@" + orig_args=$(git rev-parse --sq-quote "$@") while test $# -ne 0 do case "$1" in @@ -500,7 +500,7 @@ cmd_update() if test -n "$recursive" then - (clear_local_git_env; cd "$path" && cmd_update $orig_args) || + (clear_local_git_env; cd "$path" && eval cmd_update "$orig_args") || die "Failed to recurse into submodule path '$path'" fi done @@ -733,7 +733,7 @@ cmd_summary() { cmd_status() { # parse $args after "submodule ... status". - orig_args="$@" + orig_args=$(git rev-parse --sq-quote "$@") while test $# -ne 0 do case "$1" in @@ -790,7 +790,7 @@ cmd_status() prefix="$displaypath/" clear_local_git_env cd "$path" && - cmd_status $orig_args + eval cmd_status "$orig_args" ) || die "Failed to recurse into submodule path '$path'" fi diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 905a8baae9..15d420fca6 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -238,4 +238,20 @@ test_expect_success 'use "git clone --recursive" to checkout all submodules' ' test -d clone4/nested1/nested2/nested3/submodule/.git ' +test_expect_success 'test "update --recursive" with a flag with spaces' ' + git clone super "common objects" && + git clone super clone5 && + ( + cd clone5 && + test ! -d nested1/.git && + git submodule update --init --recursive --reference="$(dirname "$PWD")/common objects" && + test -d nested1/.git && + test -d nested1/nested2/.git && + test -d nested1/nested2/nested3/.git && + test -f nested1/.git/objects/info/alternates && + test -f nested1/nested2/.git/objects/info/alternates && + test -f nested1/nested2/nested3/.git/objects/info/alternates + ) +' + test_done -- cgit v1.3 From 98dbe63dbcb44218e23ccc92e1491c36b2e31945 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Tue, 2 Nov 2010 23:26:25 -0700 Subject: submodule: only preserve flags across recursive status/update invocations Recursive invocations of submodule update/status preserve all arguments, so executing git submodule update --recursive -- foo attempts to recursively update a submodule named "foo". Naturally, this fails as one cannot have an infinitely-deep stack of submodules each containing a submodule named "foo". The desired behavior is instead to update foo and then recursively update all submodules inside of foo. This commit accomplishes that by only saving the flags for use in the recursive invocation. Signed-off-by: Kevin Ballard Signed-off-by: Junio C Hamano --- git-submodule.sh | 19 ++++++++----------- t/t7407-submodule-foreach.sh | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 11 deletions(-) (limited to 'git-submodule.sh') diff --git a/git-submodule.sh b/git-submodule.sh index 4d2bb37215..4fd8982894 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -374,41 +374,35 @@ cmd_init() cmd_update() { # parse $args after "submodule ... update". - orig_args=$(git rev-parse --sq-quote "$@") + orig_flags= while test $# -ne 0 do case "$1" in -q|--quiet) - shift GIT_QUIET=1 ;; -i|--init) init=1 - shift ;; -N|--no-fetch) - shift nofetch=1 ;; -r|--rebase) - shift update="rebase" ;; --reference) case "$2" in '') usage ;; esac reference="--reference=$2" - shift 2 + orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")" + shift ;; --reference=*) reference="$1" - shift ;; -m|--merge) - shift update="merge" ;; --recursive) - shift recursive=1 ;; --) @@ -422,6 +416,8 @@ cmd_update() break ;; esac + orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")" + shift done if test -n "$init" @@ -500,7 +496,7 @@ cmd_update() if test -n "$recursive" then - (clear_local_git_env; cd "$path" && eval cmd_update "$orig_args") || + (clear_local_git_env; cd "$path" && eval cmd_update "$orig_flags") || die "Failed to recurse into submodule path '$path'" fi done @@ -733,7 +729,7 @@ cmd_summary() { cmd_status() { # parse $args after "submodule ... status". - orig_args=$(git rev-parse --sq-quote "$@") + orig_flags= while test $# -ne 0 do case "$1" in @@ -757,6 +753,7 @@ cmd_status() break ;; esac + orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")" shift done diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 15d420fca6..d8ad25036f 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -226,6 +226,21 @@ test_expect_success 'test "status --recursive"' ' test_cmp expect actual ' +sed -e "/nested1 /s/.*/+$nested1sha1 nested1 (file2~1)/;/sub[1-3]/d" < expect > expect2 +mv -f expect2 expect + +test_expect_success 'ensure "status --cached --recursive" preserves the --cached flag' ' + ( + cd clone3 && + ( + cd nested1 && + test_commit file2 + ) && + git submodule status --cached --recursive -- nested1 > ../actual + ) && + test_cmp expect actual +' + test_expect_success 'use "git clone --recursive" to checkout all submodules' ' git clone --recursive super clone4 && test -d clone4/.git && @@ -254,4 +269,23 @@ test_expect_success 'test "update --recursive" with a flag with spaces' ' ) ' +test_expect_success 'use "update --recursive nested1" to checkout all submodules rooted in nested1' ' + git clone super clone6 && + ( + cd clone6 && + test ! -d sub1/.git && + test ! -d sub2/.git && + test ! -d sub3/.git && + test ! -d nested1/.git && + git submodule update --init --recursive -- nested1 && + test ! -d sub1/.git && + test ! -d sub2/.git && + test ! -d sub3/.git && + test -d nested1/.git && + test -d nested1/nested2/.git && + test -d nested1/nested2/nested3/.git && + test -d nested1/nested2/nested3/submodule/.git + ) +' + test_done -- cgit v1.3 From 502dc5b663fe3fe241accca5eda28a94d674fbb6 Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Wed, 1 Dec 2010 12:50:46 -0600 Subject: git submodule -b ... of current HEAD fails git submodule add -b $branch $repository fails when HEAD already points to $branch in $repository. Reported-by: Klaus Ethgen Signed-off-by: Jonathan Nieder Acked-by: Jens Lehmann Signed-off-by: Junio C Hamano --- git-submodule.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'git-submodule.sh') diff --git a/git-submodule.sh b/git-submodule.sh index 9ebbab798d..09107467fe 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -241,7 +241,7 @@ cmd_add() # ash fails to wordsplit ${branch:+-b "$branch"...} case "$branch" in '') git checkout -f -q ;; - ?*) git checkout -f -q -b "$branch" "origin/$branch" ;; + ?*) git checkout -f -q -B "$branch" "origin/$branch" ;; esac ) || die "Unable to checkout submodule '$path'" fi -- cgit v1.3 From 69e7236c6df44bfcde8913972b75a6ccb360d58f Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Sun, 5 Dec 2010 00:27:35 +0100 Subject: git submodule: Remove now obsolete tests before cloning a repo Since 55892d23 "git clone" itself checks that the destination path is not a file but an empty directory if it exists, so there is no need anymore for module_clone() to check that too. Two tests have been added to test the behavior of "git submodule add" when path is a file or a directory (A subshell had to be added to the former last test to stay in the right directory). Signed-off-by: Jens Lehmann Signed-off-by: Junio C Hamano --- git-submodule.sh | 14 -------------- t/t7400-submodule-basic.sh | 28 +++++++++++++++++++++++----- 2 files changed, 23 insertions(+), 19 deletions(-) (limited to 'git-submodule.sh') diff --git a/git-submodule.sh b/git-submodule.sh index 09107467fe..a84418f1aa 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -93,20 +93,6 @@ module_clone() url=$2 reference="$3" - # If there already is a directory at the submodule path, - # expect it to be empty (since that is the default checkout - # action) and try to remove it. - # Note: if $path is a symlink to a directory the test will - # succeed but the rmdir will fail. We might want to fix this. - if test -d "$path" - then - rmdir "$path" 2>/dev/null || - die "Directory '$path' exists, but is neither empty nor a git repository" - fi - - test -e "$path" && - die "A file already exist at path '$path'" - if test -n "$reference" then git-clone "$reference" -n "$url" "$path" diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 782b0a3ece..2c49db9f62 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -421,11 +421,29 @@ test_expect_success 'add submodules without specifying an explicit path' ' git commit -m "repo commit 1" ) && git clone --bare repo/ bare.git && - cd addtest && - git submodule add "$submodurl/repo" && - git config -f .gitmodules submodule.repo.path repo && - git submodule add "$submodurl/bare.git" && - git config -f .gitmodules submodule.bare.path bare + ( + cd addtest && + git submodule add "$submodurl/repo" && + git config -f .gitmodules submodule.repo.path repo && + git submodule add "$submodurl/bare.git" && + git config -f .gitmodules submodule.bare.path bare + ) +' + +test_expect_success 'add should fail when path is used by a file' ' + ( + cd addtest && + touch file && + test_must_fail git submodule add "$submodurl/repo" file + ) +' + +test_expect_success 'add should fail when path is used by an existing directory' ' + ( + cd addtest && + mkdir empty-dir && + test_must_fail git submodule add "$submodurl/repo" empty-dir + ) ' test_done -- cgit v1.3 From ea640cc691d56f7151c5ba654b09c4a987dbef93 Mon Sep 17 00:00:00 2001 From: Thomas Rast Date: Mon, 10 Jan 2011 11:37:26 +0100 Subject: submodule: fix relative url parsing for scp-style origin The function resolve_relative_url was not prepared to deal with an scp-style origin 'user@host:path' in the case where 'path' is only a single component. Fix this by extending the logic that strips one path component from the $remoteurl. Also add tests for both styles of URLs. Noticed-by: Jeffrey Phillips Freeman Signed-off-by: Thomas Rast Signed-off-by: Junio C Hamano --- git-submodule.sh | 16 ++++++++++++++-- t/t7400-submodule-basic.sh | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) (limited to 'git-submodule.sh') diff --git a/git-submodule.sh b/git-submodule.sh index d3c583d011..ac371e6253 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -36,12 +36,24 @@ resolve_relative_url () die "remote ($remote) does not have a url defined in .git/config" url="$1" remoteurl=${remoteurl%/} + sep=/ while test -n "$url" do case "$url" in ../*) url="${url#../}" - remoteurl="${remoteurl%/*}" + case "$remoteurl" in + */*) + remoteurl="${remoteurl%/*}" + ;; + *:*) + remoteurl="${remoteurl%:*}" + sep=: + ;; + *) + die "cannot strip one component off url '$remoteurl'" + ;; + esac ;; ./*) url="${url#./}" @@ -50,7 +62,7 @@ resolve_relative_url () break;; esac done - echo "$remoteurl/${url%/}" + echo "$remoteurl$sep${url%/}" } # diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 1a4dc5f893..8b004f60d6 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -331,4 +331,42 @@ test_expect_success 'add submodules without specifying an explicit path' ' git config -f .gitmodules submodule.bare.path bare ' +test_expect_success 'set up for relative path tests' ' + mkdir reltest && + ( + cd reltest && + git init && + mkdir sub && + ( + cd sub && + git init && + test_commit foo + ) && + git add sub && + git config -f .gitmodules submodule.sub.path sub && + git config -f .gitmodules submodule.sub.url ../subrepo && + cp .git/config pristine-.git-config + ) +' + +test_expect_success 'relative path works with URL' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + git config remote.origin.url ssh://hostname/repo && + git submodule init && + test "$(git config submodule.sub.url)" = ssh://hostname/subrepo + ) +' + +test_expect_success 'relative path works with user@host:path' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + git config remote.origin.url user@host:repo && + git submodule init && + test "$(git config submodule.sub.url)" = user@host:subrepo + ) +' + test_done -- cgit v1.3 From 1b4735d9f3e0b7ea62c7c22f0afcb45e10c46c7e Mon Sep 17 00:00:00 2001 From: "Spencer E. Olson" Date: Thu, 17 Feb 2011 09:18:45 -0700 Subject: submodule: no [--merge|--rebase] when newly cloned "git submodule update" can be run with either the "--merge" or "--rebase" option, or submodule..update configuration variable can be set to "merge" or "rebase, to cause local work to get integrated when updating the submodule. When a submodule is newly cloned, however, it does not have a check out when a rebase or merge is attempted, leading to a failure. For newly cloned submodules, simply check out the appropriate revision. There is no local work to integrate with for them. Signed-off-by: Spencer E. Olson Acked-by: Jens Lehmann Signed-off-by: Junio C Hamano --- git-submodule.sh | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'git-submodule.sh') diff --git a/git-submodule.sh b/git-submodule.sh index 8b90589717..3a13397e05 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -423,6 +423,7 @@ cmd_update() cmd_init "--" "$@" || return fi + cloned_modules= module_list "$@" | while read mode sha1 stage path do @@ -442,6 +443,7 @@ cmd_update() if ! test -d "$path"/.git -o -f "$path"/.git then module_clone "$path" "$url" "$reference"|| exit + cloned_modules="$cloned_modules;$name" subsha1= else subsha1=$(clear_local_git_env; cd "$path" && @@ -469,6 +471,13 @@ cmd_update() die "Unable to fetch in submodule path '$path'" fi + # Is this something we just cloned? + case ";$cloned_modules;" in + *";$name;"*) + # then there is no local change to integrate + update_module= ;; + esac + case "$update_module" in rebase) command="git rebase" -- cgit v1.3 From e5f522d610d34914e3fcf8b23de1b771c467196e Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Sun, 6 Mar 2011 23:13:36 +0100 Subject: submodule update: Don't fetch when the submodule commit is already present If the commit to be checked out on "git submodule update" has already been fetched in the submodule there is no need to run "git fetch" again. Since "git fetch" recently learned recursion (and the new on-demand mode to fetch commits recorded in the superproject is enabled by default) this will happen pretty often, thereby making the unconditional fetch during "git submodule update" unnecessary. If the commit is not present in the submodule (e.g. the user disabled the fetch on-demand mode) the fetch will be run as before. Signed-off-by: Jens Lehmann Signed-off-by: Junio C Hamano --- git-submodule.sh | 5 ++++- t/t7406-submodule-update.sh | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) (limited to 'git-submodule.sh') diff --git a/git-submodule.sh b/git-submodule.sh index 8b90589717..514d2eb7ab 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -464,8 +464,11 @@ cmd_update() if test -z "$nofetch" then + # Run fetch only if $sha1 isn't present or it + # is not reachable from a ref. (clear_local_git_env; cd "$path" && - git-fetch) || + ((rev=$(git rev-list -n 1 $sha1 --not --all 2>/dev/null) && + test -z "$rev") || git-fetch)) || die "Unable to fetch in submodule path '$path'" fi diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh index bfb4975e94..ee3eec5157 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -74,6 +74,26 @@ test_expect_success 'submodule update detaching the HEAD ' ' ) ' +apos="'"; +test_expect_success 'submodule update does not fetch already present commits' ' + (cd submodule && + echo line3 >> file && + git add file && + test_tick && + git commit -m "upstream line3" + ) && + (cd super/submodule && + head=$(git rev-parse --verify HEAD) && + echo "Submodule path ${apos}submodule$apos: checked out $apos$head$apos" > ../../expected && + git reset --hard HEAD~1 + ) && + (cd super && + git submodule update > ../actual 2> ../actual.err + ) && + test_cmp expected actual && + ! test -s actual.err +' + test_expect_success 'submodule update --rebase staying on master' ' (cd super/submodule && git checkout master -- cgit v1.3 From 313ee0d69f58c2bf2f4e0a62b812c9d08a39b240 Mon Sep 17 00:00:00 2001 From: Nicolas Morey-Chaisemartin Date: Wed, 30 Mar 2011 07:20:02 +0200 Subject: submodule: process conflicting submodules only once During a merge module_list returns conflicting submodules several times (stage 1,2,3) which caused the submodules to be used multiple times in git submodule init, sync, update and status command. There are 5 callers of module_list; they all read (mode, sha1, stage, path) tuple, and most of them care only about path. As a first level approximation, it should be Ok (in the sense that it does not make things worse than it currently is) to filter the duplicate paths from module_list output, but some callers should change their behaviour when the merge in the superproject still has conflicts. Notice the higher-stage entries, and emit only one record from module_list, but while doing so, mark the entry with "U" (not [0-3]) in the $stage field and null out the SHA-1 part, as the object name for the lowest stage does not give any useful information to the caller, and this way any caller that uses the object name would hopefully barf. Then update the codepaths for each subcommands this way: - "update" should not touch the submodule repository, because we do not know what commit should be checked out yet. - "status" reports the conflicting submodules as 'U000...000' and does not recurse into them (we might later want to make it recurse). - The command called by "foreach" may want to do whatever it wants to do by noticing the merged status in the superproject itself, so feed the path to it from module_list as before, but only once per submodule. - "init" and "sync" are unlikely things to do while the superproject is still not merged, but as long as a submodule is there in $path, there is no point skipping it. It might however want to take the merged status of .gitmodules into account, but that is outside of the scope of this topic. Acked-by: Jens Lehmann Thanks-to: Junio C Hamano Signed-off-by: Nicolas Morey-Chaisemartin Signed-off-by: Junio C Hamano --- Documentation/git-submodule.txt | 5 ++-- git-submodule.sh | 29 ++++++++++++++++++++- t/t7405-submodule-merge.sh | 58 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 83 insertions(+), 9 deletions(-) (limited to 'git-submodule.sh') diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index 1ed331c599..e8ed2f2c0f 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -101,9 +101,10 @@ status:: currently checked out commit for each submodule, along with the submodule path and the output of 'git describe' for the SHA-1. Each SHA-1 will be prefixed with `-` if the submodule is not - initialized and `+` if the currently checked out submodule commit + initialized, `+` if the currently checked out submodule commit does not match the SHA-1 found in the index of the containing - repository. This command is the default command for 'git submodule'. + repository and `U` if the submodule has merge conflicts. + This command is the default command for 'git submodule'. + If '--recursive' is specified, this command will recurse into nested submodules, and show their status as well. diff --git a/git-submodule.sh b/git-submodule.sh index 3a13397e05..7f6b3cf207 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -72,7 +72,24 @@ resolve_relative_url () # module_list() { - git ls-files --error-unmatch --stage -- "$@" | sane_grep '^160000 ' + git ls-files --error-unmatch --stage -- "$@" | + perl -e ' + my %unmerged = (); + my ($null_sha1) = ("0" x 40); + while () { + chomp; + my ($mode, $sha1, $stage, $path) = + /^([0-7]+) ([0-9a-f]{40}) ([0-3])\t(.*)$/; + next unless $mode eq "160000"; + if ($stage ne "0") { + if (!$unmerged{$path}++) { + print "$mode $null_sha1 U\t$path\n"; + } + next; + } + print "$_\n"; + } + ' } # @@ -427,6 +444,11 @@ cmd_update() module_list "$@" | while read mode sha1 stage path do + if test "$stage" = U + then + echo >&2 "Skipping unmerged submodule $path" + continue + fi name=$(module_name "$path") || exit url=$(git config submodule."$name".url) update_module=$(git config submodule."$name".update) @@ -770,6 +792,11 @@ cmd_status() name=$(module_name "$path") || exit url=$(git config submodule."$name".url) displaypath="$prefix$path" + if test "$stage" = U + then + say "U$sha1 $displaypath" + continue + fi if test -z "$url" || ! test -d "$path"/.git -o -f "$path"/.git then say "-$sha1 $displaypath" diff --git a/t/t7405-submodule-merge.sh b/t/t7405-submodule-merge.sh index 7e2e258950..a8fb30b792 100755 --- a/t/t7405-submodule-merge.sh +++ b/t/t7405-submodule-merge.sh @@ -56,11 +56,11 @@ test_expect_success setup ' # History setup # -# b -# / \ -# a d -# \ / -# c +# b +# / \ +# init -- a d +# \ \ / +# g c # # a in the main repository records to sub-a in the submodule and # analogous b and c. d should be automatically found by merging c into @@ -76,6 +76,8 @@ test_expect_success 'setup for merge search' ' git add file-a && git commit -m "sub-a" && git branch sub-a) && + git commit --allow-empty -m init && + git branch init && git add sub && git commit -m "a" && git branch a && @@ -101,7 +103,13 @@ test_expect_success 'setup for merge search' ' git checkout -b sub-d sub-b && git merge sub-c) && git commit -a -m "d" && - git branch test b) + git branch test b && + + git checkout -b g init && + (cd sub && + git checkout -b sub-g sub-c) && + git add sub && + git commit -a -m "g") ' test_expect_success 'merge with one side as a fast-forward of the other' ' @@ -176,6 +184,44 @@ test_expect_success 'merging should fail for changes that are backwards' ' test_must_fail git merge f) ' + +# Check that the conflicting submodule is detected when it is +# in the common ancestor. status should be 'U00...00" +test_expect_success 'git submodule status should display the merge conflict properly with merge base' ' + (cd merge-search && + cat >.gitmodules <expect < actual && + test_cmp expect actual && + git reset --hard) +' + +# Check that the conflicting submodule is detected when it is +# not in the common ancestor. status should be 'U00...00" +test_expect_success 'git submodule status should display the merge conflict properly without merge-base' ' + (cd merge-search && + git checkout -b test-no-merge-base g && + test_must_fail git merge b && + cat >.gitmodules <expect < actual && + test_cmp expect actual && + git reset --hard) +' + + test_expect_success 'merging with a modify/modify conflict between merge bases' ' git reset --hard HEAD && git checkout -b test2 c && -- cgit v1.3 From 9db31bdf5c834689c826f809d6d15bf7ab8d3598 Mon Sep 17 00:00:00 2001 From: Nicolas Morey-Chaisemartin Date: Fri, 1 Apr 2011 11:42:03 +0200 Subject: submodule: Add --force option for git submodule update By default git submodule update runs a simple checkout on submodules that are not up-to-date. If the submodules contains modified or untracked files, the command may exit sanely with an error: $ git submodule update error: Your local changes to the following files would be overwritten by checkout: file Please, commit your changes or stash them before you can switch branches. Aborting Unable to checkout '1b69c6e55606b48d3284a3a9efe4b58bfb7e8c9e' in submodule path 'test1' In order to reset a whole git submodule tree, a user has to run first 'git submodule foreach --recursive git checkout -f' and then run 'git submodule update'. This patch adds a --force option for the update command (only used for submodules without --rebase or --merge options). It passes the --force option to git checkout which will throw away the local changes. Signed-off-by: Nicolas Morey-Chaisemartin Acked-by: Jens Lehmann Signed-off-by: Junio C Hamano --- Documentation/git-submodule.txt | 6 ++++-- git-submodule.sh | 14 +++++++++----- t/t7406-submodule-update.sh | 23 +++++++++++++++++++++++ 3 files changed, 36 insertions(+), 7 deletions(-) (limited to 'git-submodule.sh') diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index 1ed331c599..9f84da7ad6 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -185,8 +185,10 @@ OPTIONS -f:: --force:: - This option is only valid for the add command. - Allow adding an otherwise ignored submodule path. + This option is only valid for add and update commands. + When running add, allow adding an otherwise ignored submodule path. + When running update, throw away local changes in submodules when + switching to a different commit. --cached:: This option is only valid for status and summary commands. These diff --git a/git-submodule.sh b/git-submodule.sh index 3a13397e05..f7327090bb 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -8,7 +8,7 @@ dashless=$(basename "$0" | sed -e 's/-/ /') USAGE="[--quiet] add [-b branch] [-f|--force] [--reference ] [--] [] or: $dashless [--quiet] status [--cached] [--recursive] [--] [...] or: $dashless [--quiet] init [--] [...] - or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference ] [--merge] [--recursive] [--] [...] + or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] [--rebase] [--reference ] [--merge] [--recursive] [--] [...] or: $dashless [--quiet] summary [--cached|--files] [--summary-limit ] [commit] [--] [...] or: $dashless [--quiet] foreach [--recursive] or: $dashless [--quiet] sync [--] [...]" @@ -385,6 +385,9 @@ cmd_update() -N|--no-fetch) nofetch=1 ;; + -f|--force) + force=$1 + ;; -r|--rebase) update="rebase" ;; @@ -458,10 +461,11 @@ cmd_update() if test "$subsha1" != "$sha1" then - force= - if test -z "$subsha1" + subforce=$force + # If we don't already have a -f flag and the submodule has never been checked out + if test -z "$subsha1" -a -z "$force" then - force="-f" + subforce="-f" fi if test -z "$nofetch" @@ -490,7 +494,7 @@ cmd_update() msg="merged in" ;; *) - command="git checkout $force -q" + command="git checkout $subforce -q" action="checkout" msg="checked out" ;; diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh index fa9d23aa31..5d24d9ff74 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -74,6 +74,29 @@ test_expect_success 'submodule update detaching the HEAD ' ' ) ' +test_expect_success 'submodule update should fail due to local changes' ' + (cd super/submodule && + git reset --hard HEAD~1 && + echo "local change" > file + ) && + (cd super && + (cd submodule && + compare_head + ) && + test_must_fail git submodule update submodule + ) +' +test_expect_success 'submodule update should throw away changes with --force ' ' + (cd super && + (cd submodule && + compare_head + ) && + git submodule update --force submodule && + cd submodule && + ! compare_head + ) +' + test_expect_success 'submodule update --rebase staying on master' ' (cd super/submodule && git checkout master -- cgit v1.3 From f5799e05c0e7fbee32ca32995c7c4a627eeff469 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Thu, 26 May 2011 13:52:04 -0700 Subject: git-submodule.sh: separate parens by a space to avoid confusing some shells Some shells interpret '(( ))' according to the rules for arithmetic expansion. This may not follow POSIX, but is prevalent in commonly used shells. Bash does not have a problem with this particular instance of '((', likely because it is not followed by a '))', but the public domain ksh does, and so does ksh on IRIX 6.5. So, add a space between the parenthesis to avoid confusing these shells. Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- git-submodule.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'git-submodule.sh') diff --git a/git-submodule.sh b/git-submodule.sh index b010a67309..4361ae418c 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -491,7 +491,7 @@ cmd_update() # Run fetch only if $sha1 isn't present or it # is not reachable from a ref. (clear_local_git_env; cd "$path" && - ((rev=$(git rev-list -n 1 $sha1 --not --all 2>/dev/null) && + ( (rev=$(git rev-list -n 1 $sha1 --not --all 2>/dev/null) && test -z "$rev") || git-fetch)) || die "Unable to fetch in submodule path '$path'" fi -- cgit v1.3