* [PATCH] - Added recurse command to git submodule @ 2008-01-09 5:51 imyousuf 2008-01-09 8:38 ` Junio C Hamano 0 siblings, 1 reply; 8+ messages in thread From: imyousuf @ 2008-01-09 5:51 UTC (permalink / raw) To: git; +Cc: gitster, Imran M Yousuf From: Imran M Yousuf <imyousuf@smartitengineering.com> - The purpose of the recurse command in the git submodule is to recurse a command in its submodule at depths specified. For example if one wants to do a diff on its project with submodules at once, one can simply do git-submodule recurse diff HEAD and would see the diff for all the modules it contains. If during recursion it is found that a module has not been initialized or updated than the command also initializes and updates them. It is to be noted that argument specification to the command intended (in above example diff) to recurse will be same as its original command (i.e. git diff). If the original command spec changes it will have no effect on the recurse command. Depth of recursion can be specified simply by mentioning the -d <recursion depth> argument to recurse command. If not specified or specified to 0, it will be comprehended to recurse at all depth; if a positive number is specified than maximum recursion depth will never cross that depth. In order to see some information -v option may be used Signed-off-by: Imran M Yousuf <imyousuf@smartitengineering.com> --- git-submodule.sh | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 111 insertions(+), 1 deletions(-) diff --git a/git-submodule.sh b/git-submodule.sh index 8a29382..5cb931e 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -4,7 +4,7 @@ # # Copyright (c) 2007 Lars Hjemli -USAGE='[--quiet] [--cached] [add <repo> [-b branch]|status|init|update] [--] [<path>...]' +USAGE='[[--quiet] [--cached] [add <repo> [-b branch]|status|init|update] [--] [<path>...]|[recurse [-v] [-d <recursion depth>] <command> <arguments> ...]]' OPTIONS_SPEC= . git-sh-setup require_work_tree @@ -17,6 +17,9 @@ status= quiet= cached= command= +recurse_verbose=0 +recursion_depth=0 +current_recursion_depth=0 # # print stuff on stdout unless -q was specified @@ -294,6 +297,82 @@ modules_list() done } +# Initializes the submodule if already not initialized +initialize_sub_module() { + if [ ! -d "$1"/.git ]; then + if [ $recurse_verbose -eq 1 ]; then + echo Initializing and updating "$1" + fi + git-submodule init "$1"; git-submodule update "$1" + fi +} + +# This actually traverses the module; checks +# whether the module is initialized or not. +# if not initialized, then done so and then the +# intended command is evaluated. Then it +# recursively goes into it modules. +traverse_module() { + if [ $recurse_verbose -eq 1 ]; then + echo Current recursion depth: "$current_recursion_depth" + fi + initialize_sub_module "$1" + ( + submod_path="$1" + shift + cd "$submod_path" + if [ $recurse_verbose -eq 1 ]; then + echo Working in mod "$submod_path" @ `pwd` with "$@" \("$#"\) + fi + git "$@" + # Check whether submodules exists only if recursion to that depth + # was requested by user + if test "$recursion_depth" -eq 0 || test "$current_recursion_depth" -lt "$recursion_depth" + then + if [ -f .gitmodules ]; then + for mod_path in `sed -n -e 's/path = //p' .gitmodules`; do + export current_recursion_depth=$(echo "$current_recursion_depth+1" | bc) + traverse_module "$mod_path" "$@" + export current_recursion_depth=$(echo "$current_recursion_depth-1" | bc) + done + fi + fi + ) +} + +# Propagates or recurses over all the submodules at any +# depth with any git command, e.g. git-clone, git-status, +# git-commit etc., with the arguments supplied exactly as +# it would have been supplied to the command otherwise. +# This actually starts the recursive propagation +modules_recurse() { + project_home=`pwd` + echo Project Home: "$project_home" + if [ $recurse_verbose -eq 1 ]; then + if [ $recursion_depth = 0 ]; then + echo Recursion will go to all depths + else + echo Recursion depth specified to "$recursion_depth" + fi + fi + if [ -d "$project_home"/.git/ ]; then + if [ $recurse_verbose -eq 1 ]; then + echo Command to recurse: git "$@" + fi + git "$@" + if [ -f .gitmodules ]; then + for mod_path in `sed -n -e 's/path = //p' .gitmodules`; do + export current_recursion_depth=1 + traverse_module $mod_path "$@" + done + fi + else + echo "$project_home" not a git repo thus exiting + exit + fi + unset current_recursion_depth +} + # command specifies the whole function name since # one of theirs prefix is module not modules while test $# != 0 @@ -326,6 +405,37 @@ do --cached) command="modules_list" ;; + recurse) + command="modules_$1" + repeat=1 + while test $repeat = 1 + do + case "$2" in + -v) + recurse_verbose=1 + shift + ;; + -d) + if [ -z $3 ]; then + echo No \<recursion depth\> specified + usage + elif [ `expr "$3" : '[1-9][0-9]*.*'` -eq `expr "$3" : '.*'` ]; then + recursion_depth="$3" + shift + shift + else + echo \<recursion depth\> not an integer + usage + fi + ;; + *) + repeat=0 + ;; + esac + done + shift + break + ;; --) break ;; -- 1.5.3.7 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] - Added recurse command to git submodule 2008-01-09 5:51 [PATCH] - Added recurse command to git submodule imyousuf @ 2008-01-09 8:38 ` Junio C Hamano 2008-01-09 8:55 ` Imran M Yousuf 2008-01-09 10:42 ` Lars Hjemli 0 siblings, 2 replies; 8+ messages in thread From: Junio C Hamano @ 2008-01-09 8:38 UTC (permalink / raw) To: imyousuf; +Cc: git, Imran M Yousuf imyousuf@gmail.com writes: > From: Imran M Yousuf <imyousuf@smartitengineering.com> > > > - The purpose of the recurse command in the git submodule is to recurse > a command in its submodule at depths specified. For example if one wants > to do a diff on its project with submodules at once, one can simply do > git-submodule recurse diff HEAD and would see the diff for all the modules > it contains. If during recursion it is found that a module has not been > initialized or updated than the command also initializes and updates them. > It is to be noted that argument specification to the command intended (in > above example diff) to recurse will be same as its original command (i.e. > git diff). If the original command spec changes it will have no effect on > the recurse command. Depth of recursion can be specified simply by > mentioning the -d <recursion depth> argument to recurse command. If not > specified or specified to 0, it will be comprehended to recurse at all > depth; if a positive number is specified than maximum recursion depth will > never cross that depth. In order to see some information -v option may be > used The indentation style seems, eh, unique. An overlong single paragraph with solid run of sentences is somewhat hard to read. I am not still convinced that a subcommand other than init, which is started recursively, should initialize and update submodules that are uninitialized. Currently there is no way, other than not having an initialized submodule repository, to mark that the user is _not_ interested in a particular submodule, and you will lose that if you make recursing into uninitialized ones too easy and aggressive. I suspect that it might be a saner approach to: - allow "git submodule recurse init [-d depth]" (although I am not sure if limit by depth is so useful in practice -- only experience will tell us) to auto-initialize the uninitialized submodules; - allow any other "git submodule recurse $cmd" to run recursively to _any_ depth, but never auto-initialize the uninitialized submodules. In other words, I think it is a very bad idea to rob the existing mechanism from the user to mark uninteresting submodules by not initializing them. An alternative would be to give them other means to mark "I am not interested in these submodules", if you insist on this auto-initialization, but I do not offhand think of a mechanism that is easier to use than what we already have (i.e. not checking them out). > @@ -17,6 +17,9 @@ status= > quiet= > cached= > command= > +recurse_verbose=0 > +recursion_depth=0 > +current_recursion_depth=0 I wonder if we want this "verbose" option to be specific to the recurse subcommand, or perhaps other subcommands may want to support more verbose output mode, even if they currently don't. Perhaps the variable should be just called $verbose? > +# Initializes the submodule if already not initialized > +initialize_sub_module() { > + if [ ! -d "$1"/.git ]; then > + if [ $recurse_verbose -eq 1 ]; then > + echo Initializing and updating "$1" That's a sensible message for the $verbose mode. > + fi > + git-submodule init "$1"; git-submodule update "$1" Can init fail for repository "$1"? Do you want to proceed updating it if it does? > +# This actually traverses the module; checks > +# whether the module is initialized or not. > +# if not initialized, then done so and then the > +# intended command is evaluated. Then it > +# recursively goes into it modules. > +traverse_module() { > + if [ $recurse_verbose -eq 1 ]; then > + echo Current recursion depth: "$current_recursion_depth" > + fi > + initialize_sub_module "$1" > + ( > + submod_path="$1" > + shift > + cd "$submod_path" > + if [ $recurse_verbose -eq 1 ]; then > + echo Working in mod "$submod_path" @ `pwd` with "$@" \("$#"\) Is this a sensible message, I have to wonder... Saying `pwd` after already saying "$submod_path" feels more like a debugging message than just being $verbose. > + fi > + git "$@" Is the user interested in exit status from this command? Does the user want to continue on to other submodules if this one fails? > + # Check whether submodules exists only if recursion to that depth > + # was requested by user > + if test "$recursion_depth" -eq 0 || test "$current_recursion_depth" -lt "$recursion_depth" Overly long line. Perhaps... if test "$depth" -eq 0 || test "$current_depth" -lt "$depth" then ... > + then > + if [ -f .gitmodules ]; then > + for mod_path in `sed -n -e 's/path = //p' .gitmodules`; do > + export current_recursion_depth=$(echo "$current_recursion_depth+1" | bc) (1) I do not think you need to export this variable; (2) It was reported some shells that we intend to support mishandle "export VAR=VAL" construct and we tend to write this "VAR=VAL" followed by "export VAR" as two separate commands on two separate lines; (3) We do not use "bc" (and traditionally, shell scripts outside git don't, either) in scripts. So, I think: current_recursion_depth=$(( $current_recursion_depth + 1 )) is enough, although the variable name feels overly long. Probably I would even do: if test "$depth -ne 0 && test "$current_depth" -ge "$depth" then exit 0 fi if test -f .gitmodules then current_recursion_depth=$(( $current_recursion_depth + 1 )) for p in $(sed -n -e 's/path = ....) do traverse_module "$p" "$@" done fi which would avoid one level of nesting (and indentation), and removes unnecessary increment and decrement inside the loop. You are in your own subprocess, so your increment will not affect the process that called you, and after leaving the loop the only thing you do is just to exit the subprocess. > +# Propagates or recurses over all the submodules at any > +# depth with any git command, e.g. git-clone, git-status, > +# git-commit etc., with the arguments supplied exactly as > +# it would have been supplied to the command otherwise. > +# This actually starts the recursive propagation > +modules_recurse() { > + project_home=`pwd` > + echo Project Home: "$project_home" Doesn't this message belong to $verbose mode? > + if [ $recurse_verbose -eq 1 ]; then > + if [ $recursion_depth = 0 ]; then > + echo Recursion will go to all depths > + else > + echo Recursion depth specified to "$recursion_depth" > + fi These sounds more like debugging message than $verbose. > + fi > + if [ -d "$project_home"/.git/ ]; then > + if [ $recurse_verbose -eq 1 ]; then > + echo Command to recurse: git "$@" Likewise -- you will repeat that inside traverse_module anyway. > + fi > + git "$@" > + if [ -f .gitmodules ]; then > + for mod_path in `sed -n -e 's/path = //p' .gitmodules`; do > + export current_recursion_depth=1 > + traverse_module $mod_path "$@" > + done > + fi Do I see a code duplication here? Why isn't this done as the first level recursion inside traverse_module? _Even_ _if_ you insist auto-initializing submodules, by moving the initialize_sub_module call in traverse_module a bit down (namely, before it recursively invoke traverse_module itself and make it auto initialize $submod_path, not "$1"), I think you can remove this duplication. > + else > + echo "$project_home" not a git repo thus exiting > + exit And its exit code is 0 which tells the caller that there is no error? > + fi > + unset current_recursion_depth The reason for this unset is...? > @@ -326,6 +405,37 @@ do > --cached) > command="modules_list" > ;; > + recurse) > + command="modules_$1" > + repeat=1 > + while test $repeat = 1 > + do You do not need that $repeat thing. Just use "break", like this. while : do case ... in ... *) break ;; esac done > + -d) > + if [ -z $3 ]; then (minor style) if test -z "$3" then ... > + echo No \<recursion depth\> specified > + usage > + elif [ `expr "$3" : '[1-9][0-9]*.*'` -eq `expr "$3" : '.*'` ]; then > + recursion_depth="$3" > + shift > + shift > + else > + echo \<recursion depth\> not an integer > + usage > + fi > + ;; Instead of checking integerness by hand, it would probably be much simpler if you did something like this: depth="$3" depth=$(( $depth + 0 )) if test "$depth" != "$3" then die "what's that '$3' for?" else : happy fi For a rough guideline of shell constructs we use (and do not use), please see Documentation/CodingGuidelines. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] - Added recurse command to git submodule 2008-01-09 8:38 ` Junio C Hamano @ 2008-01-09 8:55 ` Imran M Yousuf 2008-01-09 10:42 ` Lars Hjemli 1 sibling, 0 replies; 8+ messages in thread From: Imran M Yousuf @ 2008-01-09 8:55 UTC (permalink / raw) To: Junio C Hamano; +Cc: git Hi Junio, Thanks for the feedback and specially thank you for the coding standard documentation, I was looking for it. I will make fixes to both the patches and email them again. Will send this patch again, probably tomorrow. Thank you, Imran On Jan 9, 2008 2:38 PM, Junio C Hamano <gitster@pobox.com> wrote: > imyousuf@gmail.com writes: > > > From: Imran M Yousuf <imyousuf@smartitengineering.com> > > > > > > - The purpose of the recurse command in the git submodule is to recurse > > a command in its submodule at depths specified. For example if one wants > > to do a diff on its project with submodules at once, one can simply do > > git-submodule recurse diff HEAD and would see the diff for all the modules > > it contains. If during recursion it is found that a module has not been > > initialized or updated than the command also initializes and updates them. > > It is to be noted that argument specification to the command intended (in > > above example diff) to recurse will be same as its original command (i.e. > > git diff). If the original command spec changes it will have no effect on > > the recurse command. Depth of recursion can be specified simply by > > mentioning the -d <recursion depth> argument to recurse command. If not > > specified or specified to 0, it will be comprehended to recurse at all > > depth; if a positive number is specified than maximum recursion depth will > > never cross that depth. In order to see some information -v option may be > > used > > The indentation style seems, eh, unique. An overlong single > paragraph with solid run of sentences is somewhat hard to read. > > I am not still convinced that a subcommand other than init, > which is started recursively, should initialize and update > submodules that are uninitialized. Currently there is no way, > other than not having an initialized submodule repository, to > mark that the user is _not_ interested in a particular > submodule, and you will lose that if you make recursing into > uninitialized ones too easy and aggressive. > > I suspect that it might be a saner approach to: > > - allow "git submodule recurse init [-d depth]" (although I am > not sure if limit by depth is so useful in practice -- only > experience will tell us) to auto-initialize the uninitialized > submodules; > > - allow any other "git submodule recurse $cmd" to run > recursively to _any_ depth, but never auto-initialize the > uninitialized submodules. > > In other words, I think it is a very bad idea to rob the > existing mechanism from the user to mark uninteresting > submodules by not initializing them. An alternative would be to > give them other means to mark "I am not interested in these > submodules", if you insist on this auto-initialization, but I do > not offhand think of a mechanism that is easier to use than what > we already have (i.e. not checking them out). > > > @@ -17,6 +17,9 @@ status= > > quiet= > > cached= > > command= > > +recurse_verbose=0 > > +recursion_depth=0 > > +current_recursion_depth=0 > > I wonder if we want this "verbose" option to be specific to the > recurse subcommand, or perhaps other subcommands may want to > support more verbose output mode, even if they currently don't. > Perhaps the variable should be just called $verbose? > > > +# Initializes the submodule if already not initialized > > +initialize_sub_module() { > > + if [ ! -d "$1"/.git ]; then > > + if [ $recurse_verbose -eq 1 ]; then > > + echo Initializing and updating "$1" > > That's a sensible message for the $verbose mode. > > > + fi > > + git-submodule init "$1"; git-submodule update "$1" > > Can init fail for repository "$1"? Do you want to proceed > updating it if it does? > > > +# This actually traverses the module; checks > > +# whether the module is initialized or not. > > +# if not initialized, then done so and then the > > +# intended command is evaluated. Then it > > +# recursively goes into it modules. > > +traverse_module() { > > + if [ $recurse_verbose -eq 1 ]; then > > + echo Current recursion depth: "$current_recursion_depth" > > + fi > > + initialize_sub_module "$1" > > + ( > > + submod_path="$1" > > + shift > > + cd "$submod_path" > > + if [ $recurse_verbose -eq 1 ]; then > > + echo Working in mod "$submod_path" @ `pwd` with "$@" \("$#"\) > > Is this a sensible message, I have to wonder... Saying `pwd` > after already saying "$submod_path" feels more like a debugging > message than just being $verbose. > > > + fi > > + git "$@" > > Is the user interested in exit status from this command? Does > the user want to continue on to other submodules if this one > fails? > > > + # Check whether submodules exists only if recursion to that depth > > + # was requested by user > > + if test "$recursion_depth" -eq 0 || test "$current_recursion_depth" -lt "$recursion_depth" > > Overly long line. Perhaps... > > if test "$depth" -eq 0 || > test "$current_depth" -lt "$depth" > then > ... > > > + then > > + if [ -f .gitmodules ]; then > > + for mod_path in `sed -n -e 's/path = //p' .gitmodules`; do > > + export current_recursion_depth=$(echo "$current_recursion_depth+1" | bc) > > (1) I do not think you need to export this variable; > > (2) It was reported some shells that we intend to support > mishandle "export VAR=VAL" construct and we tend to write > this "VAR=VAL" followed by "export VAR" as two separate > commands on two separate lines; > > (3) We do not use "bc" (and traditionally, shell scripts > outside git don't, either) in scripts. > > So, I think: > > current_recursion_depth=$(( $current_recursion_depth + 1 )) > > is enough, although the variable name feels overly long. > > Probably I would even do: > > if test "$depth -ne 0 && test "$current_depth" -ge "$depth" > then > exit 0 > fi > if test -f .gitmodules > then > current_recursion_depth=$(( $current_recursion_depth + 1 )) > for p in $(sed -n -e 's/path = ....) > do > traverse_module "$p" "$@" > done > fi > > which would avoid one level of nesting (and indentation), and > removes unnecessary increment and decrement inside the loop. > You are in your own subprocess, so your increment will not > affect the process that called you, and after leaving the loop > the only thing you do is just to exit the subprocess. > > > +# Propagates or recurses over all the submodules at any > > +# depth with any git command, e.g. git-clone, git-status, > > +# git-commit etc., with the arguments supplied exactly as > > +# it would have been supplied to the command otherwise. > > +# This actually starts the recursive propagation > > +modules_recurse() { > > + project_home=`pwd` > > + echo Project Home: "$project_home" > > Doesn't this message belong to $verbose mode? > > > + if [ $recurse_verbose -eq 1 ]; then > > + if [ $recursion_depth = 0 ]; then > > + echo Recursion will go to all depths > > + else > > + echo Recursion depth specified to "$recursion_depth" > > + fi > > These sounds more like debugging message than $verbose. > > > + fi > > + if [ -d "$project_home"/.git/ ]; then > > + if [ $recurse_verbose -eq 1 ]; then > > + echo Command to recurse: git "$@" > > Likewise -- you will repeat that inside traverse_module anyway. > > > + fi > > + git "$@" > > + if [ -f .gitmodules ]; then > > + for mod_path in `sed -n -e 's/path = //p' .gitmodules`; do > > + export current_recursion_depth=1 > > + traverse_module $mod_path "$@" > > + done > > + fi > > Do I see a code duplication here? Why isn't this done as the > first level recursion inside traverse_module? _Even_ _if_ you > insist auto-initializing submodules, by moving the > initialize_sub_module call in traverse_module a bit down > (namely, before it recursively invoke traverse_module itself and > make it auto initialize $submod_path, not "$1"), I think you can > remove this duplication. > > > + else > > + echo "$project_home" not a git repo thus exiting > > + exit > > And its exit code is 0 which tells the caller that there is no > error? > > > + fi > > + unset current_recursion_depth > > The reason for this unset is...? > > > @@ -326,6 +405,37 @@ do > > --cached) > > command="modules_list" > > ;; > > + recurse) > > + command="modules_$1" > > + repeat=1 > > + while test $repeat = 1 > > + do > > You do not need that $repeat thing. Just use "break", like this. > > while : > do > case ... in > ... > *) > break ;; > esac > done > > > + -d) > > + if [ -z $3 ]; then > > (minor style) > > if test -z "$3" > then > ... > > > + echo No \<recursion depth\> specified > > + usage > > + elif [ `expr "$3" : '[1-9][0-9]*.*'` -eq `expr "$3" : '.*'` ]; then > > + recursion_depth="$3" > > + shift > > + shift > > + else > > + echo \<recursion depth\> not an integer > > + usage > > + fi > > + ;; > > Instead of checking integerness by hand, it would probably be > much simpler if you did something like this: > > depth="$3" > depth=$(( $depth + 0 )) > if test "$depth" != "$3" > then > die "what's that '$3' for?" > else > : happy > fi > > For a rough guideline of shell constructs we use (and do not > use), please see Documentation/CodingGuidelines. > -- Imran M Yousuf Entrepreneur & Software Engineer Smart IT Engineering Dhaka, Bangladesh Email: imran@smartitengineering.com Mobile: +880-1711402557 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] - Added recurse command to git submodule 2008-01-09 8:38 ` Junio C Hamano 2008-01-09 8:55 ` Imran M Yousuf @ 2008-01-09 10:42 ` Lars Hjemli 2008-01-09 20:26 ` Junio C Hamano 1 sibling, 1 reply; 8+ messages in thread From: Lars Hjemli @ 2008-01-09 10:42 UTC (permalink / raw) To: Junio C Hamano; +Cc: imyousuf, git, Imran M Yousuf On Jan 9, 2008 9:38 AM, Junio C Hamano <gitster@pobox.com> wrote: > I am not still convinced that a subcommand other than init, > which is started recursively, should initialize and update > submodules that are uninitialized. I very much agree; this behaviour would break the current 'usage model'. > I suspect that it might be a saner approach to: > > - allow "git submodule recurse init [-d depth]" (although I am > not sure if limit by depth is so useful in practice -- only > experience will tell us) to auto-initialize the uninitialized > submodules; A possible extension is to specifiy "inter-submodule" paths to the init subcommand, i.e. for a possible KDE layout: git submodule -r init kdelibs kdelibs/admin This should then recursively initialize the kdelibs submodule and the admin-submodule (in the kdelibs submodule). Btw: from my reading of the code, the git-command specified for 'recurse' will be done top-to-bottom: I guess that's what you want for something like 'git submodule recurse diff', but not for something like 'git submodule recurse commit' (but IMHO the latter one should never be executed ;-) -- larsh ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] - Added recurse command to git submodule 2008-01-09 10:42 ` Lars Hjemli @ 2008-01-09 20:26 ` Junio C Hamano 2008-01-10 3:27 ` Imran M Yousuf 0 siblings, 1 reply; 8+ messages in thread From: Junio C Hamano @ 2008-01-09 20:26 UTC (permalink / raw) To: Lars Hjemli; +Cc: imyousuf, git, Imran M Yousuf "Lars Hjemli" <hjemli@gmail.com> writes: > A possible extension is to specifiy "inter-submodule" paths to the > init subcommand, i.e. for a possible KDE layout: > git submodule -r init kdelibs kdelibs/admin > > This should then recursively initialize the kdelibs submodule and the > admin-submodule (in the kdelibs submodule). Beautiful. > Btw: from my reading of the code, the git-command specified for > 'recurse' will be done top-to-bottom: I guess that's what you want for > something like 'git submodule recurse diff', but not for something > like 'git submodule recurse commit' (but IMHO the latter one should > never be executed ;-) Thanks for raising a very good point. Yes, some commands inherently wants depth first. While I agree that making a recursive is a grave usage error (submodule commit and toplevel commit are logically different events and even their commit log message should be different, as they talk about changes in logically different levels) from project management point of view, I do not think it is something a tool has to explicitly forbid the users to do. I view it as a kind of a long rope, a misuse the users can be allowed to inflict on themselves if they really wanted to. Also, some commands cannot be made recursive by driving them from a higher level recursive wrapper. "git submodule recursive log" would not make much sense, not only because the order of the log entries are output from different invocations would not be useful, but because the revision range specifier would need to be different in different submodules (e.g. library submodules and application submodule will not share version name namespace, i.e. "log v1.0..v2.0" is undefined, and worse yet, running "log v1.0:path/to/sub..v2.0:path/to/sub" in a submodule when running "log v1.0..v2.0" in the toplevel is not a correct solution either in general). ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] - Added recurse command to git submodule 2008-01-09 20:26 ` Junio C Hamano @ 2008-01-10 3:27 ` Imran M Yousuf 2008-01-10 4:09 ` Junio C Hamano 0 siblings, 1 reply; 8+ messages in thread From: Imran M Yousuf @ 2008-01-10 3:27 UTC (permalink / raw) To: Junio C Hamano; +Cc: Lars Hjemli, git, Imran M Yousuf On Jan 10, 2008 2:26 AM, Junio C Hamano <gitster@pobox.com> wrote: > "Lars Hjemli" <hjemli@gmail.com> writes: > > > A possible extension is to specifiy "inter-submodule" paths to the > > init subcommand, i.e. for a possible KDE layout: > > git submodule -r init kdelibs kdelibs/admin > > > > This should then recursively initialize the kdelibs submodule and the > > admin-submodule (in the kdelibs submodule). > > Beautiful. Firstly, thank you for the feedback Junio and Lars. Secondly, I was not planning to add recurse to the init/update command, but your (Lars) suggestion seems really handy; I will implement it in my patch. About auto-initialization, I, as writing, am implementing it to be optional and an extra -i has to be specified if the user wants to do it. > > > Btw: from my reading of the code, the git-command specified for > > 'recurse' will be done top-to-bottom: I guess that's what you want for > > something like 'git submodule recurse diff', but not for something > > like 'git submodule recurse commit' (but IMHO the latter one should > > never be executed ;-) > > Thanks for raising a very good point. Yes, some commands > inherently wants depth first. > I could not agree more and in fact, I wanted to leave to the user how they use the recurse command. I basically will be using for status and diff primarily; and may be for creating and checking out branches; but as I said it mostly depends on how the user wants to use it. > While I agree that making a recursive is a grave usage error > (submodule commit and toplevel commit are logically different > events and even their commit log message should be different, as > they talk about changes in logically different levels) from > project management point of view, I do not think it is something > a tool has to explicitly forbid the users to do. I view it as a > kind of a long rope, a misuse the users can be allowed to > inflict on themselves if they really wanted to. > In fact if I am also thinking whether to add intelligence in such scenarios. What do you think if we choose DF of BF based on the command and options? > Also, some commands cannot be made recursive by driving them > from a higher level recursive wrapper. "git submodule recursive > log" would not make much sense, not only because the order of > the log entries are output from different invocations would not > be useful, but because the revision range specifier would need > to be different in different submodules (e.g. library submodules > and application submodule will not share version name namespace, > i.e. "log v1.0..v2.0" is undefined, and worse yet, running "log > v1.0:path/to/sub..v2.0:path/to/sub" in a submodule when running > "log v1.0..v2.0" in the toplevel is not a correct solution > either in general). > What is you suggestion in such cases Junio? > -- Imran M Yousuf ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] - Added recurse command to git submodule 2008-01-10 3:27 ` Imran M Yousuf @ 2008-01-10 4:09 ` Junio C Hamano 2008-01-10 4:50 ` Imran M Yousuf 0 siblings, 1 reply; 8+ messages in thread From: Junio C Hamano @ 2008-01-10 4:09 UTC (permalink / raw) To: Imran M Yousuf; +Cc: Lars Hjemli, git, Imran M Yousuf "Imran M Yousuf" <imyousuf@gmail.com> writes: >> Also, some commands cannot be made recursive by driving them >> from a higher level recursive wrapper. "git submodule recursive >> log" would not make much sense, not only because the order of >> the log entries are output from different invocations would not >> be useful, but because the revision range specifier would need >> to be different in different submodules (e.g. library submodules >> and application submodule will not share version name namespace, >> i.e. "log v1.0..v2.0" is undefined, and worse yet, running "log >> v1.0:path/to/sub..v2.0:path/to/sub" in a submodule when running >> "log v1.0..v2.0" in the toplevel is not a correct solution >> either in general). > > What is you suggestion in such cases Junio? Not doing it using the wrapper approach, but actually have the underlying command be aware of the recursiveness. Let's take a small example of library project contained within an application project as a submodule (think of ffmpeg in mplayer or something like that). Library project has this history: 3---A / ---1---2---4---B while the application project has this history: ---5---X---6---Y and at time X (and before that point), it binds commit A at a directory "lib/" as a submodule. The commit 6 (between X and Y) changes it to bind commit B there instead. You have both toplevel and submodule checked out. The HEAD in the application project is at Y while the HEAD in the library project is at B. Your work tree may or may not be clean. How would a recursive "git diff" between two versions should behave, with various arguments? $ git diff X Y Currently this will say something like: --- a/lib +++ b/lib @@ -1 +1 @@ -Subproject commit A +Subproject commit B You can make it recurse naturally by recursing into lib/ subproject instead (at least conceptually this is a simple change but it may not be so straightforward, implementation wise). How would you handle this, then? $ git diff X Y -- Documentation/ A wrapper approach that blindly descends into lib/ and runs "git diff X Y -- Documentation/" there is wrong at two levels. Commits X and Y do not even exist there, and Documentation/ pathspec is wrong. The documentation may be called docs/ in the library project, or it may not even exist, and that is not what the user asked to see anyway. If the user were interested in the documentation of the library, the pathspec would have said lib/Documentaiton/ (or lib/docs/). For "git diff", the right solution happens to be invoking the command recursively without any pathspec. The higher level chose to recurse into the directory already because it saw changes --- by definition everything underneath is interesting. Side note. If we support asking for lib/docs/ from the toplevel, the recursive one would use docs/ as its pathspec in this case. The point is that pathspec needs to be munged from the higher level iteration, and more importantly that is pretty much specific to "git diff". "git diff" itself needs to have the knowledge of what to do when working recursively --- wrapper approach would not work well. How would a recursive version of "git log" work, then? $ git log X..Y Again, a naive wrapper approach of descending into lib/ and running "git log X..Y" recursively would not give us anything useful. But if "git log" itself knew recursive behaviour, it should be able to do much better. It can show Y and 6, and at that point it could notice that between 6 and its parent X the commit bound at lib/ as submodule has changed from A to B, so it could insert the log from submodule there. If we were running with --left-right, we might see something like this: >Y >6 >B >4 >2 <A <3 -2 -X If the toplevel "git log" was invoked with a pathspec, again, it needs to be adjusted to submodule. I think a wrapper approach could be adequate for simple things like "checking out the whole tree including all of its submodules". But even that has to be done carefully. What should this command (recursive version) do? $ git checkout X The toplevel detaches head at commit X, and notices that it contains a submodule at lib/ whose HEAD now needs to point at A. The recursive command should go there, and say $ git checkout A What should it do when this checkout cannot be made because your work tree is not clean? Ideally, it should abort and roll-back the checkout of commit X at the toplevel (otherwise you will end up in a mixed state). There are more interesting issues when you bring up a situation where X and Y binds that library project at different place (i.e. submodule was moved inside the toplevel), which I avoided to talk about here to keep this message short. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] - Added recurse command to git submodule 2008-01-10 4:09 ` Junio C Hamano @ 2008-01-10 4:50 ` Imran M Yousuf 0 siblings, 0 replies; 8+ messages in thread From: Imran M Yousuf @ 2008-01-10 4:50 UTC (permalink / raw) To: Junio C Hamano; +Cc: Lars Hjemli, git On Jan 10, 2008 10:09 AM, Junio C Hamano <gitster@pobox.com> wrote: > "Imran M Yousuf" <imyousuf@gmail.com> writes: > > >> Also, some commands cannot be made recursive by driving them > >> from a higher level recursive wrapper. "git submodule recursive > >> log" would not make much sense, not only because the order of > >> the log entries are output from different invocations would not > >> be useful, but because the revision range specifier would need > >> to be different in different submodules (e.g. library submodules > >> and application submodule will not share version name namespace, > >> i.e. "log v1.0..v2.0" is undefined, and worse yet, running "log > >> v1.0:path/to/sub..v2.0:path/to/sub" in a submodule when running > >> "log v1.0..v2.0" in the toplevel is not a correct solution > >> either in general). > > > > What is you suggestion in such cases Junio? > > Not doing it using the wrapper approach, but actually have the > underlying command be aware of the recursiveness. Yes, I do agree fully that the wrapper approach has problem in recursing; as I mentioned earlier it is the user who has to be aware of the command he wants to execute recursively; as all currently available work can still be performed even if the wrapper recurse is added. But at least having recurse would allow users to execute certain simple commands from the top level which otherwise would have required to be done from each sub-module. > > Let's take a small example of library project contained within > an application project as a submodule (think of ffmpeg in > mplayer or something like that). > > Library project has this history: > > 3---A > / > ---1---2---4---B > > while the application project has this history: > > ---5---X---6---Y > > and at time X (and before that point), it binds commit A at a > directory "lib/" as a submodule. The commit 6 (between X and Y) > changes it to bind commit B there instead. You have both > toplevel and submodule checked out. The HEAD in the application > project is at Y while the HEAD in the library project is at B. > Your work tree may or may not be clean. > > How would a recursive "git diff" between two versions should > behave, with various arguments? > > $ git diff X Y > > Currently this will say something like: > > --- a/lib > +++ b/lib > @@ -1 +1 @@ > -Subproject commit A > +Subproject commit B > > You can make it recurse naturally by recursing into lib/ > subproject instead (at least conceptually this is a simple > change but it may not be so straightforward, implementation > wise). > > How would you handle this, then? > > $ git diff X Y -- Documentation/ > > A wrapper approach that blindly descends into lib/ and runs "git > diff X Y -- Documentation/" there is wrong at two levels. > Commits X and Y do not even exist there, and Documentation/ > pathspec is wrong. The documentation may be called docs/ in the > library project, or it may not even exist, and that is not what > the user asked to see anyway. If the user were interested in > the documentation of the library, the pathspec would have said > lib/Documentaiton/ (or lib/docs/). > > For "git diff", the right solution happens to be invoking the > command recursively without any pathspec. The higher level > chose to recurse into the directory already because it saw > changes --- by definition everything underneath is interesting. > > Side note. If we support asking for lib/docs/ from the > toplevel, the recursive one would use docs/ as its > pathspec in this case. > > The point is that pathspec needs to be munged from the higher > level iteration, and more importantly that is pretty much > specific to "git diff". "git diff" itself needs to have the > knowledge of what to do when working recursively --- wrapper > approach would not work well. Yes, it is absolutely right that if the command was aware of the recursion it could necessary measures to ensure that it can fallback to default execution; e.g. remove the path spec from git-diff. Alternatively, the recurse module could actually check whether if simply passed the command would generate error or not; if yes then display a message mentioning it and fallback to simplest form of the command. The real disadvantage is that, firstly in this approach the command gets executed twice in average case and secondly, the module will have to know the fallback version of the command. > > How would a recursive version of "git log" work, then? > > $ git log X..Y > > Again, a naive wrapper approach of descending into lib/ and > running "git log X..Y" recursively would not give us anything > useful. > > But if "git log" itself knew recursive behaviour, it should be > able to do much better. It can show Y and 6, and at that point > it could notice that between 6 and its parent X the commit bound > at lib/ as submodule has changed from A to B, so it could insert > the log from submodule there. If we were running with > --left-right, we might see something like this: > > >Y > >6 > >B > >4 > >2 > <A > <3 > -2 > -X > > If the toplevel "git log" was invoked with a pathspec, again, it > needs to be adjusted to submodule. > > I think a wrapper approach could be adequate for simple things > like "checking out the whole tree including all of its > submodules". But even that has to be done carefully. > > What should this command (recursive version) do? > > $ git checkout X > > The toplevel detaches head at commit X, and notices that it > contains a submodule at lib/ whose HEAD now needs to point at > A. The recursive command should go there, and say > > $ git checkout A > > What should it do when this checkout cannot be made because your > work tree is not clean? Ideally, it should abort and roll-back > the checkout of commit X at the toplevel (otherwise you will end > up in a mixed state). > > There are more interesting issues when you bring up a situation > where X and Y binds that library project at different place > (i.e. submodule was moved inside the toplevel), which I avoided > to talk about here to keep this message short. > Thank you for the detailed explanation and I can visualize more scenarios which you did not mention. From this I get the following ideas for the recurse command - 1. Instead of supporting all he git commands support a subset with limited feature 2. Support full range of git commands, as is submitted in this patch, but if error occurs in execution fall back to the default version of the command. This is probably not a efficient version; but would be beneficial as other commands will not be effected. 3. Support full range of git commands, as is submitted in this patch, leave it to the user on how he wants to use it. 4. Scrap the recurse idea (I actually do not prefer it :)). Let me know which one you prefer (please not 4 :)). > > Best regards, -- Imran M Yousuf ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2008-01-10 4:51 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-01-09 5:51 [PATCH] - Added recurse command to git submodule imyousuf 2008-01-09 8:38 ` Junio C Hamano 2008-01-09 8:55 ` Imran M Yousuf 2008-01-09 10:42 ` Lars Hjemli 2008-01-09 20:26 ` Junio C Hamano 2008-01-10 3:27 ` Imran M Yousuf 2008-01-10 4:09 ` Junio C Hamano 2008-01-10 4:50 ` Imran M Yousuf
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).