Junio C Hamano <junkio@xxxxxxx> wrote: > Now, suppose "git checkout" needs to recurse into one > subdirectory that is to have a subproject. There are three > cases: So I've implemented my own Git subproject support in a Java based tool we use internally. Its actually driving the Git plumbing (as JGit isn't complete enough to do the job) but applies quite a bit to this discussion as it is a working system that implements this "checkout in superproject and recurse into subproject". First I don't use the subproject support in the core plumbing, because that came along from Linus about 2 days after I wrote this implementation. Our data file looks like: use-component: subproject1 >=df8cfac815... use-component: subproject2 >=af9b543820... Or really anything that is a valid commit-ish, and often these are actually just annotated tag names. > (1) There is no git repository yet (the plumbing layer already > makes sure there is a directory, but does not do anything > else). During our build process we scan the root project's data file, and clone by the relative URL anything we cannot find locally: $(git config remote.origin.url)/../component-links/subproject1.git to get the subproject repository. We don't require that the subproject1 directory actually be called subproject1 in the superproject, its just a recommendation. That data file is also our build-system driver and the build system driver is pretty darn smart about guessing what is going on. ;-) You'll notice however that we (more or less) have a very flat structure. The component-links directory is really just a set of symlinks pointing back up a level, as sometimes a component is not stored in a repository named the component name, but the component name matters to the build system. > (2) There already is a git repository there, which is the > correct repository (perhaps determined by .gitmodules and > .git/config in the superproject, or presense of the commit > that is recorded in the superproject's index). > > (3) There is a git repository but it is not the correct one. > > For case (2), I think what should happen there is an equivalent > of this: > > $ commit=$(git-rev-parse :subproject) > $ cd subproject > $ git-rev-parse --verify $commit || git fetch || barf > $ git checkout $commit Yes. Except we do a few things differently: - Only update the subproject if its a strict fast-forward. - Abort on a dirty working directory in the subproject or if a merge would be required to keep the current commit and the new commit. Yes, we don't really support going "backwards". - The merge aborting thing is probably wrong for some users, but blindly switching to the target commit feels somewhat wrong in our own uses. Sometimes you need the current version of the subproject to help you debug an older version of the superproject, or sibling subproject. - You can't just checkout $commit if you can rev-parse it. You need to verify it and its entire reachable object set exists. See the local fetch fast-path thing you did recently in e3c6f240fd. - We update the user's current branch. Because we are doing a strict fast-forward we're also assuming the user wants the current branch to stay correlated to the superproject branch. Why? Most of our users keep the same branch name in all repositories. -- Shawn. - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html