{"thread":{"id":"35619","subject":"What's cooking in git.git (Jan 2014, #01; Mon, 6)","startedAt":"2014-01-06T22:36:54Z","lastAt":"2014-02-07T22:08:53Z","messageCount":35,"participants":["Junio C Hamano","Francesco Pretto","Jens Lehmann","W. Trevor King","Jonathan Nieder","Duy Nguyen"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"232777","messageId":"xmqqd2k4hh4p.fsf@gitster.dls.corp.google.com","threadId":"35619","inReplyTo":null,"subject":"What's cooking in git.git (Jan 2014, #01; Mon, 6)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-01-06T22:36:54Z","receivedAt":"2014-01-06T22:36:54Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Welcome to the first issue of \"What's cooking\" report for the new\nyear.\n\nHere are the topics that have been cooking.  Commits prefixed with\n'-' are only in 'pu' (proposed updates) while commits prefixed with\n'+' are in 'next'.\n\nYou can find the changes described here in the integration branches\nof the repositories listed at\n\n    http://git-blame.blogspot.com/p/git-public-repositories.html\n\n--------------------------------------------------\n[Graduated to \"master\"]\n\n* fc/remote-helper-fixes (2013-12-26) 5 commits\n  (merged to 'next' on 2013-12-26 at ce5f872)\n + remote-hg: test 'shared_path' in a moved clone\n  (merged to 'next' on 2013-12-17 at aa4dc07)\n + remote-hg: add tests for special filenames\n + remote-hg: fix 'shared path' path\n + remote-helpers: add extra safety checks\n + remote-hg: avoid buggy strftime()\n\n\n* jc/push-refmap (2013-12-04) 3 commits\n  (merged to 'next' on 2013-12-12 at 71e358f)\n + push: also use \"upstream\" mapping when pushing a single ref\n + push: use remote.$name.push as a refmap\n + builtin/push.c: use strbuf instead of manual allocation\n\n Make \"git push origin master\" update the same ref that would be\n updated by our 'master' when \"git push origin\" (no refspecs) is run\n while the 'master' branch is checked out, which makes \"git push\"\n more symmetric to \"git fetch\" and more usable for the triangular\n workflow.\n\n\n* jk/cat-file-regression-fix (2013-12-12) 2 commits\n  (merged to 'next' on 2013-12-13 at 3713e01)\n + cat-file: handle --batch format with missing type/size\n + cat-file: pass expand_data to print_object_or_die\n\n \"git cat-file --batch=\", an admittedly useless command, did not\n behave very well.\n\n\n* jk/name-pack-after-byte-representation (2013-12-16) 3 commits\n  (merged to 'next' on 2013-12-17 at 0bc385c)\n + pack-objects doc: treat output filename as opaque\n  (merged to 'next' on 2013-12-09 at 247b2d0)\n + pack-objects: name pack files after trailer hash\n + sha1write: make buffer const-correct\n (this branch is tangled with jk/pack-bitmap.)\n\n Two packfiles that contain the same set of objects have\n traditionally been named identically, but that made repacking a\n repository that is already fully packed without any cruft with a\n different packing parameter cumbersome. Update the convention to\n name the packfile after the bytestream representation of the data,\n not after the set of objects in it.\n\n\n* jk/pull-rebase-using-fork-point (2013-12-10) 2 commits\n  (merged to 'next' on 2013-12-13 at 1862c12)\n + rebase: use reflog to find common base with upstream\n + pull: use merge-base --fork-point when appropriate\n\n\n* jk/rev-parse-double-dashes (2013-12-09) 2 commits\n  (merged to 'next' on 2013-12-13 at d26bac7)\n + rev-parse: be more careful with munging arguments\n + rev-parse: correctly diagnose revision errors before \"--\"\n\n \"git rev-parse <revs> -- <paths>\" did not implement the usual\n disambiguation rules the commands in the \"git log\" family used in\n the same way.\n\n\n* js/gnome-keyring (2013-12-16) 1 commit\n  (merged to 'next' on 2013-12-17 at 422fd61)\n + contrib/git-credential-gnome-keyring.c: small stylistic cleanups\n\n Style fix.\n\n\n* tg/diff-no-index-refactor (2013-12-16) 4 commits\n  (merged to 'next' on 2013-12-17 at 009d8d8)\n + diff: avoid some nesting\n + diff: add test for --no-index executed outside repo\n  (merged to 'next' on 2013-12-13 at 523f7c4)\n + diff: don't read index when --no-index is given\n + diff: move no-index detection to builtin/diff.c\n\n \"git diff ../else/where/A ../else/where/B\" when ../else/where is\n clearly outside the repository, and \"git diff --no-index A B\", do\n not have to look at the index at all, but we used to read the index\n unconditionally.\n\n\n* zk/difftool-counts (2013-12-16) 2 commits\n  (merged to 'next' on 2013-12-16 at 0e0d235)\n + diff.c: fix some recent whitespace style violations\n  (merged to 'next' on 2013-12-12 at ba35694)\n + difftool: display the number of files in the diff queue in the prompt\n\n Show the total number of paths and the number of paths shown so far\n when \"git difftool\" prompts to launch an external diff tool, which\n would give users some sense of progress.\n\n--------------------------------------------------\n[New Topics]\n\n* ta/format-user-manual-as-an-article (2014-01-06) 1 commit\n  (merged to 'next' on 2014-01-06 at 37858f6)\n + user-manual: improve html and pdf formatting\n\n Update the way the user-manual is formatted via AsciiDoc to save\n trees.\n\n Will merge to 'master'.\n\n\n* bm/merge-base-octopus-dedup (2013-12-30) 2 commits\n  (merged to 'next' on 2014-01-06 at 355d62b)\n + merge-base --octopus: reduce the result from get_octopus_merge_bases()\n + merge-base: separate \"--independent\" codepath into its own helper\n\n \"git merge-base --octopus\" used to leave cleaning up suboptimal\n result to the caller, but now it does the clean-up itself.\n\n Will merge to 'master'.\n\n\n* jk/test-framework-updates (2014-01-02) 3 commits\n  (merged to 'next' on 2014-01-06 at f81f373)\n + t0000: drop \"known breakage\" test\n + t0000: simplify HARNESS_ACTIVE hack\n + t0000: set TEST_OUTPUT_DIRECTORY for sub-tests\n\n The basic test used to leave unnecessary trash directories in the\n t/ directory.\n\n Will merge to 'master'.\n\n\n* js/lift-parent-count-limit (2013-12-27) 1 commit\n  (merged to 'next' on 2014-01-06 at b74133c)\n + Remove the line length limit for graft files\n\n There is no reason to have a hardcoded upper limit of the number of\n parents for an octopus merge, created via the graft mechanism.\n\n Will merge to 'master'.\n\n\n* ap/remote-hg-skip-null-bookmarks (2014-01-02) 1 commit\n - remote-hg: do not fail on invalid bookmarks\n\n Reported to break tests ($gmane/240005)\n Expecting a reroll.\n\n\n* bs/mirbsd (2014-01-02) 1 commit\n  (merged to 'next' on 2014-01-06 at d5cecbb)\n + Add MirBSD support to the build system.\n\n Will merge to 'master'.\n\n\n* jk/credential-plug-leak (2014-01-02) 1 commit\n  (merged to 'next' on 2014-01-06 at 88e29a3)\n + Revert \"prompt: clean up strbuf usage\"\n\n An earlier \"clean-up\" introduced an unnecessary memory leak.\n\n Will merge to 'master'.\n\n\n* jk/http-auth-tests-robustify (2014-01-02) 1 commit\n  (merged to 'next' on 2014-01-06 at 7e87bba)\n + use distinct username/password for http auth tests\n\n Using the same username and password during the tests would not\n catch a potential breakage of sending one when we should be sending\n the other.\n\n Will merge to 'master'.\n\n\n* km/gc-eperm (2014-01-02) 1 commit\n  (merged to 'next' on 2014-01-06 at fe107de)\n + gc: notice gc processes run by other users\n\n A \"gc\" process running as a different user should be able to stop a\n new \"gc\" process from starting.\n\n Will merge to 'master'.\n\n\n* rr/completion-branch-config (2014-01-06) 4 commits\n  (merged to 'next' on 2014-01-06 at ed9eecc)\n + completion: fix remote.pushdefault\n + completion: fix branch.autosetup(merge|rebase)\n + completion: introduce __gitcomp_nl_append ()\n + zsh completion: find matching custom bash completion\n\n Two-level configuration variable names in \"branch.*\" and \"remote.*\"\n hierarchies whose variables are predominantly three-level where not\n completed by hitting a <TAB> in bash and zsh completions.\n\n Will merge to 'master'.\n\n\n* ss/builtin-cleanup (2014-01-06) 3 commits\n  (merged to 'next' on 2014-01-06 at ffcac50)\n + builtin/help.c: speed up is_git_command() by checking for builtin commands first\n + builtin/help.c: call load_command_list() only when it is needed\n + git.c: consistently use the term \"builtin\" instead of \"internal command\"\n\n \"git help $cmd\" unnecessarily enumerated potential command names\n from the filesystem, even when $cmd is known to be a built-in.\n\n Ideas for further optimization, primarily by killing the use of\n is_in_cmdlist(), were suggested in the discussion, but they can\n come as follow-ups on top of this series.\n\n Will merge to 'master'.\n\n\n* ss/safe-create-leading-dir-with-slash (2014-01-06) 1 commit\n - safe_create_leading_directories(): on Windows, \\ can separate path components\n\n\n* vm/octopus-merge-bases-simplify (2014-01-03) 1 commit\n  (merged to 'next' on 2014-01-06 at 35df672)\n + get_octopus_merge_bases(): cleanup redundant variable\n\n Will merge to 'master'.\n\n\n* fp/submodule-checkout-mode (2014-01-06) 2 commits\n - DONOTMERGE: needs sign-off\n - git-submodule.sh: support 'checkout' as a valid update mode\n\n Need to pick up a rerolled one.\n\n--------------------------------------------------\n[Stalled]\n\n* jc/graph-post-root-gap (2013-12-30) 3 commits\n - WIP: document what we want at the end\n - graph: remove unused code a bit\n - graph: stuff the current commit into graph->columns[]\n\n This was primarily a RFH ($gmane/239580).\n\n\n* fc/transport-helper-fixes (2013-12-09) 6 commits\n - remote-bzr: support the new 'force' option\n - test-hg.sh: tests are now expected to pass\n - transport-helper: check for 'forced update' message\n - transport-helper: add 'force' to 'export' helpers\n - transport-helper: don't update refs in dry-run\n - transport-helper: mismerge fix\n\n Updates transport-helper, fast-import and fast-export to allow the\n ref mapping and ref deletion in a way similar to the natively\n supported transports.\n\n Reported to break t5541.\n Will hold.\n\n\n* fc/completion (2013-12-09) 1 commit\n - completion: fix completion of certain aliases\n\n SZEDER Gábor noticed that this breaks \"git -c var=val alias\" and\n also suggested a better description of the change.\n\n Will hold.\n\n\n* mo/subtree-split-updates (2013-12-10) 3 commits\n - subtree: add --edit option\n - subtree: allow --squash and --message with push\n - subtree: support split --rejoin --squash\n\n Comments?\n\n\n* hv/submodule-ignore-fix (2013-12-06) 4 commits\n - disable complete ignorance of submodules for index <-> HEAD diff\n - always show committed submodules in summary after commit\n - teach add -f option for ignored submodules\n - fix 'git add' to skip submodules configured as ignored\n\n Teach \"git add\" to be consistent with \"git status\" when changes to\n submodules are set to be ignored, to avoid surprises after checking\n with \"git status\" to see there isn't any change to be further added\n and then see that \"git add .\" adds changes to them.\n\n I think a reroll is coming, so this may need to be replaced, but I\n needed some practice with heavy conflict resolution.  It conflicts\n with two changes to \"git add\" that have been scheduled for Git 2.0\n quite badly, and I think I got the resolution right this time.\n\n\n* kb/fast-hashmap (2014-01-03) 19 commits\n - hashmap.h: make sure map entries are tightly packed\n  (merged to 'next' on 2014-01-03 at dc85001)\n + name-hash: retire unused index_name_exists()\n + hashmap.h: Use 'unsigned int' for hash-codes everywhere\n  (merged to 'next' on 2013-12-16 at bff99b1)\n + Drop unnecessary #includes from test-hashmap\n + Add test-hashmap to .gitignore\n  (merged to 'next' on 2013-12-06 at f90be3d)\n + read-cache.c: fix memory leaks caused by removed cache entries\n + builtin/update-index.c: cleanup update_one\n + fix 'git update-index --verbose --again' output\n + remove old hash.[ch] implementation\n + name-hash.c: remove cache entries instead of marking them CE_UNHASHED\n + name-hash.c: use new hash map implementation for cache entries\n + name-hash.c: remove unreferenced directory entries\n + name-hash.c: use new hash map implementation for directories\n + diffcore-rename.c: use new hash map implementation\n + diffcore-rename.c: simplify finding exact renames\n + diffcore-rename.c: move code around to prepare for the next patch\n + buitin/describe.c: use new hash map implementation\n + add a hashtable implementation that supports O(1) removal\n + submodule: don't access the .gitmodules cache entry after removing it\n\n Improvements to our hash table to get it to meet the needs of the\n msysgit fscache project, with some nice performance improvements.\n\n The tip one does not seem to have reached concensus (yet).\n\n\n* jc/create-directories-microopt (2013-11-11) 1 commit\n - checkout: most of the time we have good leading directories\n\n Of unknown value until tested on non-Linux platforms (especially\n Windows).\n\n Will hold.\n\n\n* jt/commit-fixes-footer (2013-10-30) 1 commit\n - commit: Add -f, --fixes <commit> option to add Fixes: line\n\n There is an ongoing discussion around this topic; in general I am\n fairly negative on a new feature that is too narrow and prefer a\n more generic solution that can be tailored for specific needs, as\n many people stated in the thread.\n\n It appears that the discussion stalled.\n\n\n* np/pack-v4 (2013-09-18) 90 commits\n . packv4-parse.c: add tree offset caching\n . t1050: replace one instance of show-index with verify-pack\n . index-pack, pack-objects: allow creating .idx v2 with .pack v4\n . unpack-objects: decode v4 trees\n . unpack-objects: allow to save processed bytes to a buffer\n - ...\n\n Nico and Duy advancing the eternal vaporware pack-v4.  This is here\n primarily for wider distribution of the preview edition.\n\n Temporarily ejected from 'pu', to try out jk/pack-bitmap, which\n this topic conflicts with.\n\n\n* mf/graph-show-root (2013-10-25) 1 commit\n . graph.c: mark root commit differently\n\n In a repository with multiple-roots, \"log --graph\", especially with\n \"--oneline\", does not give the reader enough visual cue to see\n where one line of history ended and a separate history began.\n\n This is the version that marks the roots 'x' when they would have\n been marked as '*'; Keshav Kini suggested an alternative of giving\n an extra blank line after every root, which I tend to think is a\n better approach to the problem.\n\n\n* tg/perf-lib-test-perf-cleanup (2013-09-19) 2 commits\n - perf-lib: add test_perf_cleanup target\n - perf-lib: split starting the test from the execution\n\n Add test_perf_cleanup shell function to the perf suite, that allows\n the script writers to define a test with a clean-up action.\n\n Holding until needed.\n\n\n* yt/shortened-rename (2013-10-18) 2 commits\n - SQUASH??? style fixes and s/omit/shorten/ where appropriate\n - diff.c: keep arrow(=>) on show_stats()'s shortened filename part to make rename visible\n\n Attempts to give more weight on the fact that a filepair represents\n a rename than showing substring of the actual path when diffstat\n lines are not wide enough.\n\n I am not sure if that is solving a right problem, though.\n\n\n* rv/send-email-cache-generated-mid (2013-08-21) 2 commits\n - git-send-email: Cache generated message-ids, use them when prompting\n - git-send-email: add optional 'choices' parameter to the ask sub\n\n\n* rj/read-default-config-in-show-ref-pack-refs (2013-06-17) 3 commits\n - ### DONTMERGE: needs better explanation on what config they need\n - pack-refs.c: Add missing call to git_config()\n - show-ref.c: Add missing call to git_config()\n\n The changes themselves are probably good, but it is unclear what\n basic setting needs to be read for which exact operation.\n\n Waiting for clarification.\n $gmane/228294\n\n\n* jc/format-patch (2013-04-22) 2 commits\n - format-patch: --inline-single\n - format-patch: rename \"no_inline\" field\n\n A new option to send a single patch to the standard output to be\n appended at the bottom of a message.  I personally have no need for\n this, but it was easy enough to cobble together.  Tests, docs and\n stripping out more MIMEy stuff are left as exercises to interested\n parties.\n\n\n* jk/gitweb-utf8 (2013-04-08) 4 commits\n - gitweb: Fix broken blob action parameters on blob/commitdiff pages\n - gitweb: Don't append ';js=(0|1)' to external links\n - gitweb: Make feed title valid utf8\n - gitweb: Fix utf8 encoding for blob_plain, blobdiff_plain, commitdiff_plain, and patch\n\n Various fixes to gitweb.\n\n Drew Northup volunteered to take a look into this.\n $gmane/226216\n\n\n* jc/show-branch (2013-06-07) 5 commits\n - show-branch: use commit slab to represent bitflags of arbitrary width\n - show-branch.c: remove \"all_mask\"\n - show-branch.c: abstract out \"flags\" operation\n - show-branch.c: lift all_mask/all_revs to a global static\n - show-branch.c: update comment style\n\n Waiting for the final step to lift the hard-limit before sending it out.\n\n--------------------------------------------------\n[Cooking]\n\n* bc/log-decoration (2013-12-20) 1 commit\n  (merged to 'next' on 2014-01-03 at ff8873f)\n + log: properly handle decorations with chained tags\n\n \"git log --decorate\" did not handle a tag pointed by another tag\n nicely.\n\n Will merge to 'master'.\n\n\n* jh/rlimit-nofile-fallback (2013-12-18) 1 commit\n  (merged to 'next' on 2014-01-03 at b56ae0c)\n + get_max_fd_limit(): fall back to OPEN_MAX upon getrlimit/sysconf failure\n\n When we figure out how many file descriptors to allocate for\n keeping packfiles open, a system with non-working getrlimit() could\n cause us to die(), but because we make this call only to get a\n rough estimate of how many is available and we do not even attempt\n to use up all file descriptors available ourselves, it is nicer to\n fall back to a reasonable low value rather than dying.\n\n Will merge to 'master'.\n\n\n* rt/bfg-ad-in-filter-branch-doc (2013-12-18) 1 commit\n  (merged to 'next' on 2014-01-03 at 2a45e3b)\n + docs: add filter-branch notes on The BFG\n\n Will merge to 'master'.\n\n\n* sb/diff-orderfile-config (2013-12-18) 3 commits\n  (merged to 'next' on 2014-01-03 at 744eba7)\n + diff: add diff.orderfile configuration variable\n + diff: let \"git diff -O\" read orderfile from any file and fail properly\n + t4056: add new tests for \"git diff -O\"\n\n Allow \"git diff -O<file>\" to be configured with a new configuration\n variable.\n\n Will merge to 'master'.\n\n\n* nd/daemon-informative-errors-typofix (2013-12-20) 1 commit\n  (merged to 'next' on 2014-01-03 at 1b87648)\n + daemon: be strict at parsing parameters --[no-]informative-errors\n\n Will merge to 'master'.\n\n\n* tm/fetch-prune (2014-01-03) 2 commits\n  (merged to 'next' on 2014-01-03 at a58c6b4)\n + fetch --prune: Run prune before fetching\n + fetch --prune: always print header url\n\n Fetching 'frotz' branch with \"git fetch\", while having\n 'frotz/nitfol' remote-tracking branch from an earlier fetch, would\n error out, primarily because the command has not been told to\n remove anything on our side. In such a case, \"git fetch --prune\"\n can be used to remove 'frotz/nitfol' to make room to fetch and\n store 'frotz' remote-tracking branch.\n\n Will merge to 'master'.\n\n\n* jk/oi-delta-base (2013-12-26) 2 commits\n  (merged to 'next' on 2014-01-06 at 8cf3ed2)\n + cat-file: provide %(deltabase) batch format\n + sha1_object_info_extended: provide delta base sha1s\n\n Teach \"cat-file --batch\" to show delta-base object name for a\n packed object that is represented as a delta.\n\n Will merge to 'master'.\n\n\n* jk/sha1write-void (2013-12-26) 1 commit\n  (merged to 'next' on 2014-01-06 at d8cd8ff)\n + do not pretend sha1write returns errors\n\n Code clean-up.\n\n Will merge to 'master'.\n\n\n* jl/submodule-recursive-checkout (2013-12-26) 5 commits\n - Teach checkout to recursively checkout submodules\n - submodule: teach unpack_trees() to update submodules\n - submodule: teach unpack_trees() to repopulate submodules\n - submodule: teach unpack_trees() to remove submodule contents\n - submodule: prepare for recursive checkout of submodules\n\n What is the doneness of this one???\n\n\n* mh/safe-create-leading-directories (2014-01-06) 17 commits\n - rename_tmp_log(): on SCLD_VANISHED, retry\n - rename_tmp_log(): limit the number of remote_empty_directories() attempts\n - rename_tmp_log(): handle a possible mkdir/rmdir race\n - rename_ref(): extract function rename_tmp_log()\n - remove_dir_recurse(): handle disappearing files and directories\n - remove_dir_recurse(): tighten condition for removing unreadable dir\n - lock_ref_sha1_basic(): if locking fails with ENOENT, retry\n - lock_ref_sha1_basic(): on SCLD_VANISHED, retry\n - safe_create_leading_directories(): add new error value SCLD_VANISHED\n - cmd_init_db(): when creating directories, handle errors conservatively\n - safe_create_leading_directories(): introduce enum for return values\n - safe_create_leading_directories(): always restore slash at end of loop\n - safe_create_leading_directories(): split on first of multiple slashes\n - safe_create_leading_directories(): rename local variable\n - safe_create_leading_directories(): add explicit \"slash\" pointer\n - safe_create_leading_directories(): reduce scope of local variable\n - safe_create_leading_directories(): fix format of \"if\" chaining\n\n Code clean-up and protection against concurrent write access to the\n ref namespace.\n\n Is ready for 'next', with or without minor nitfix.\n\n\n* nd/add-empty-fix (2013-12-26) 1 commit\n  (merged to 'next' on 2014-01-06 at 88a78c9)\n + add: don't complain when adding empty project root\n\n \"git add -A\" (no other arguments) in a totally empty working tree\n used to emit an error.\n\n Will merge to 'master'.\n\n\n* nd/commit-tree-constness (2013-12-26) 1 commit\n  (merged to 'next' on 2014-01-06 at a177c9f)\n + commit.c: make \"tree\" a const pointer in commit_tree*()\n\n Code clean-up.\n\n Will merge to 'master'.\n\n\n* jk/pack-bitmap (2013-12-30) 21 commits\n - pack-bitmap: implement optional name_hash cache\n - t/perf: add tests for pack bitmaps\n - t: add basic bitmap functionality tests\n - count-objects: recognize .bitmap in garbage-checking\n - repack: consider bitmaps when performing repacks\n - repack: handle optional files created by pack-objects\n - repack: turn exts array into array-of-struct\n - repack: stop using magic number for ARRAY_SIZE(exts)\n - pack-objects: implement bitmap writing\n - rev-list: add bitmap mode to speed up object lists\n - pack-objects: use bitmaps when packing objects\n - pack-objects: split add_object_entry\n - pack-bitmap: add support for bitmap indexes\n - documentation: add documentation for the bitmap format\n - ewah: compressed bitmap implementation\n - compat: add endianness helpers\n - sha1_file: export `git_open_noatime`\n - revision: allow setting custom limiter function\n - pack-objects: factor out name_hash\n - pack-objects: refactor the packing list\n - revindex: export new APIs\n\n Borrows the bitmap index into packfiles from JGit to speed up\n enumeration of objects involved in a commit range without having to\n fully traverse the history.\n\n Will merge to 'next'.\n\n\n* ap/path-max (2013-12-16) 1 commit\n  (merged to 'next' on 2014-01-03 at affc620)\n + Prevent buffer overflows when path is too long\n\n Will merge to 'master'.\n\n\n* mh/path-max (2013-12-18) 2 commits\n  (merged to 'next' on 2014-01-03 at 5227c9b)\n + builtin/prune.c: use strbuf to avoid having to worry about PATH_MAX\n + prune-packed: use strbuf to avoid having to worry about PATH_MAX\n\n A few places where we relied on a fixed length buffer to hold\n pathnames in these two programs have been converted to use strbuf.\n\n Will merge to 'master'.\n\n\n* nv/commit-gpgsign-config (2013-12-17) 3 commits\n  (merged to 'next' on 2014-01-03 at 9780cbb)\n + test the commit.gpgsign config option\n + commit-tree: add and document --no-gpg-sign\n + Add the commit.gpgsign option to sign all commits\n\n Introduce commit.gpgsign configuration variable to force every\n commit to be GPG signed.  The variable cannot be overriden from the\n command line of some of the commands that create commits except for\n \"git commit\" and \"git commit-tree\", but I am not convinced that it\n is a good idea to sprinkle support for --no-gpg-sign everywhere.\n\n\n* cc/replace-object-info (2013-12-30) 11 commits\n  (merged to 'next' on 2014-01-03 at 4473803)\n + replace info: rename 'full' to 'long' and clarify in-code symbols\n  (merged to 'next' on 2013-12-17 at aeb9e18)\n + Documentation/git-replace: describe --format option\n + builtin/replace: unset read_replace_refs\n + t6050: add tests for listing with --format\n + builtin/replace: teach listing using short, medium or full formats\n + sha1_file: perform object replacement in sha1_object_info_extended()\n + t6050: show that git cat-file --batch fails with replace objects\n + sha1_object_info_extended(): add an \"unsigned flags\" parameter\n + sha1_file.c: add lookup_replace_object_extended() to pass flags\n + replace_object: don't check read_replace_refs twice\n + rename READ_SHA1_FILE_REPLACE flag to LOOKUP_REPLACE_OBJECT\n\n read_sha1_file() that is the workhorse to read the contents given\n an object name honoured object replacements, but there is no\n corresponding mechanism to sha1_object_info() that is used to\n obtain the metainfo (e.g. type & size) about the object, leading\n callers to weird inconsistencies.\n\n Will merge to 'master'.\n\n\n* nd/shallow-clone (2014-01-06) 30 commits\n  (merged to 'next' on 2014-01-06 at 3dc7fab)\n + shallow: remove unused code\n + send-pack.c: mark a file-local function static\n  (merged to 'next' on 2014-01-03 at a776065)\n + git-clone.txt: remove shallow clone limitations\n + prune: clean .git/shallow after pruning objects\n + clone: use git protocol for cloning shallow repo locally\n + send-pack: support pushing from a shallow clone via http\n + receive-pack: support pushing to a shallow clone via http\n + smart-http: support shallow fetch/clone\n + remote-curl: pass ref SHA-1 to fetch-pack as well\n + send-pack: support pushing to a shallow clone\n + receive-pack: allow pushes that update .git/shallow\n + connected.c: add new variant that runs with --shallow-file\n + add GIT_SHALLOW_FILE to propagate --shallow-file to subprocesses\n + receive/send-pack: support pushing from a shallow clone\n + receive-pack: reorder some code in unpack()\n + fetch: add --update-shallow to accept refs that update .git/shallow\n + upload-pack: make sure deepening preserves shallow roots\n + fetch: support fetching from a shallow repository\n + clone: support remote shallow repository\n + fetch-pack.h: one statement per bitfield declaration\n + fetch-pack.c: move shallow update code out of fetch_pack()\n + shallow.c: steps 6 and 7 to select new commits for .git/shallow\n + shallow.c: the 8 steps to select new commits for .git/shallow\n + shallow.c: extend setup_*_shallow() to accept extra shallow commits\n + connect.c: teach get_remote_heads to parse \"shallow\" lines\n + make the sender advertise shallow commits to the receiver\n + clone: prevent --reference to a shallow repository\n + send-pack: forbid pushing from a shallow repository\n + remote.h: replace struct extra_have_objects with struct sha1_array\n + transport.h: remove send_pack prototype, already defined in send-pack.h\n\n Fetching from a shallow-cloned repository used to be forbidden,\n primarily because the codepaths involved were not carefully vetted\n and we did not bother supporting such usage. This attempts to allow\n object transfer out of a shallow-cloned repository in a controlled\n way (i.e. the receiver become a shallow repository with truncated\n history).\n\n Will merge to 'master'.\n\n\n* jn/git-gui-chmod+x (2013-11-25) 1 commit\n - git-gui: chmod +x po2msg, windows/git-gui.sh\n\n Parked here until I get the same change back from the upstream\n git-gui tree.\n\n\n* jn/gitk-chmod+x (2013-11-25) 1 commit\n - gitk: chmod +x po2msg\n\n Parked here until I get the same change back from the upstream gitk\n tree.\n\n\n* nd/negative-pathspec (2013-12-06) 3 commits\n  (merged to 'next' on 2013-12-12 at 9f340c8)\n + pathspec.c: support adding prefix magic to a pathspec with mnemonic magic\n + Support pathspec magic :(exclude) and its short form :!\n + glossary-content.txt: rephrase magic signature part\n\n Introduce \"negative pathspec\" magic, to allow \"git log -- . ':!dir'\" to\n tell us \"I am interested in everything but 'dir' directory\".\n\n Will merge to 'master'.\n\n\n* cc/starts-n-ends-with-endgame (2013-12-05) 1 commit\n - strbuf: remove prefixcmp() and suffixcmp()\n\n Endgame for the cc/starts-n-ends-with topic; this needs to be\n evil-merged with other topics that introduce new uses of\n prefix/suffix-cmp functions.\n\n Will merge to 'next' and cook until Git 2.0.\n\n\n* gj/push-more-verbose-advice (2013-11-13) 1 commit\n  (merged to 'next' on 2013-12-06 at 574b18a)\n + push: switch default from \"matching\" to \"simple\"\n\n Originally merged to 'next' on 2013-11-21\n\n Explain 'simple' and 'matching' in \"git push\" advice message; the\n topmost patch is a rebase of jc/push-2.0-default-to-simple on top\n of it.\n\n Will cook in 'next' until Git 2.0.\n\n\n* tr/merge-recursive-index-only (2013-10-28) 3 commits\n - merge-recursive: -Xindex-only to leave worktree unchanged\n - merge-recursive: internal flag to avoid touching the worktree\n - merge-recursive: remove dead conditional in update_stages()\n\n Will hold until using script appears.\n\n\n* jn/add-2.0-u-A-sans-pathspec (2013-04-26) 1 commit\n  (merged to 'next' on 2013-12-06 at ead2ec8)\n + git add: -u/-A now affects the entire working tree\n\n Will cook in 'next' until Git 2.0.\n\n\n* jc/core-checkstat-2.0 (2013-05-06) 1 commit\n  (merged to 'next' on 2013-12-06 at ae18007)\n + core.statinfo: remove as promised in Git 2.0\n\n Will cook in 'next' until Git 2.0.\n\n\n* jc/push-2.0-default-to-simple (2013-06-18) 1 commit\n  (merged to 'next' on 2013-12-06 at 6fad61c)\n + push: switch default from \"matching\" to \"simple\"\n\n Will cook in 'next' until Git 2.0.\n\n\n* jc/add-2.0-ignore-removal (2013-04-22) 1 commit\n  (merged to 'next' on 2013-12-06 at fbaa75a)\n + git add <pathspec>... defaults to \"-A\"\n\n Updated endgame for \"git add <pathspec>\" that defaults to \"--all\"\n aka \"--no-ignore-removal\".\n\n Will cook in 'next' until Git 2.0.\n\n\n* jc/hold-diff-remove-q-synonym-for-no-deletion (2013-07-19) 1 commit\n  (merged to 'next' on 2013-12-06 at 083d67c)\n + diff: remove \"diff-files -q\" in a version of Git in a distant future\n\n Will cook in 'next' until a distant future.\n\n--------------------------------------------------\n[Discarded]\n\n* aa/transport-non-positive-depth-only (2013-11-26) 1 commit\n . transport: catch non positive --depth option value\n\n\n* cc/remote-remove-redundant-postfixcmp (2013-11-06) 2 commits\n . Rename suffixcmp() to has_suffix() and invert its result\n . builtin/remote: remove postfixcmp() and use suffixcmp() instead\n\n\n* th/reflog-annotated-tag (2013-10-28) 1 commit\n . reflog: handle lightweight and annotated tags equally\n\n \"git log -g $annotated_tag\", when there is no reflog history, should\n have produced a single output entry (i.e. the ref creation event),\n but instead showed the history leading to the tag.\n\n Broken at the design level.  Any reflog entry that points at a non\n commit needs to be handled with new code that does not exist yet,\n and lifting the \"this code handles only commits\" without adding\n such code does not solve anything.\n"},{"id":"232782","messageId":"CALas-ii8anKWa1qhn29fNxHiLbbrak=5XUSNPw26LBViREiS4w@mail.gmail.com","threadId":"35619","inReplyTo":"xmqqd2k4hh4p.fsf@gitster.dls.corp.google.com","subject":"Re: What's cooking in git.git (Jan 2014, #01; Mon, 6)","fromName":"Francesco Pretto","fromEmail":"ceztkoml@gmail.com","sentAt":"2014-01-06T23:16:09Z","receivedAt":"2014-01-06T23:16:09Z","isPatch":false,"sender":{"key":"ceztkoml@gmail.com","avatar":null},"body":"2014/1/6 Junio C Hamano <gitster@pobox.com>:\n>\n>  - git-submodule.sh: support 'checkout' as a valid update mode\n>\n>  Need to pick up a rerolled one.\n>\n\nI resent it, can you see it?\n\nThank you,\nFrancesco\n"},{"id":"232784","messageId":"xmqqzjn8g009.fsf@gitster.dls.corp.google.com","threadId":"35619","inReplyTo":"CALas-ii8anKWa1qhn29fNxHiLbbrak=5XUSNPw26LBViREiS4w@mail.gmail.com","subject":"Re: What's cooking in git.git (Jan 2014, #01; Mon, 6)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-01-06T23:32:06Z","receivedAt":"2014-01-06T23:32:06Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Francesco Pretto <ceztkoml@gmail.com> writes:\n\n> 2014/1/6 Junio C Hamano <gitster@pobox.com>:\n>>\n>>  - git-submodule.sh: support 'checkout' as a valid update mode\n>>\n>>  Need to pick up a rerolled one.\n>>\n>\n> I resent it, can you see it?\n\nI know. I saw it and that is why I left the note to self.\n\nThe thing is, it takes a non trivial amount of time to run through a\nsingle day's integration cycle, and any reroll that comes later in a\nday once the cycle started may be too late for that day.  Otherwise\nI have to discard the the result of earlier merges and tests and\nstart over from scratch.\n"},{"id":"232787","messageId":"CALas-iiKtWQ2FjXusS03PwXHx5R6prw1naKJo4FKz=6qsm-jRg@mail.gmail.com","threadId":"35619","inReplyTo":"xmqqzjn8g009.fsf@gitster.dls.corp.google.com","subject":"Re: What's cooking in git.git (Jan 2014, #01; Mon, 6)","fromName":"Francesco Pretto","fromEmail":"ceztkoml@gmail.com","sentAt":"2014-01-06T23:45:38Z","receivedAt":"2014-01-06T23:45:38Z","isPatch":false,"sender":{"key":"ceztkoml@gmail.com","avatar":null},"body":"2014/1/7 Junio C Hamano <gitster@pobox.com>:\n> The thing is, it takes a non trivial amount of time to run through a\n> single day's integration cycle, and any reroll that comes later in a\n> day once the cycle started may be too late for that day.  Otherwise\n> I have to discard the the result of earlier merges and tests and\n> start over from scratch.\n>\n\nGot it, thank you.\n"},{"id":"232817","messageId":"52CC3E16.4060909@web.de","threadId":"35619","inReplyTo":"xmqqd2k4hh4p.fsf@gitster.dls.corp.google.com","subject":"Re: What's cooking in git.git (Jan 2014, #01; Mon, 6)","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-01-07T17:49:10Z","receivedAt":"2014-01-07T17:49:10Z","isPatch":false,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 06.01.2014 23:36, schrieb Junio C Hamano:\n> * jl/submodule-recursive-checkout (2013-12-26) 5 commits\n>  - Teach checkout to recursively checkout submodules\n>  - submodule: teach unpack_trees() to update submodules\n>  - submodule: teach unpack_trees() to repopulate submodules\n>  - submodule: teach unpack_trees() to remove submodule contents\n>  - submodule: prepare for recursive checkout of submodules\n> \n>  What is the doneness of this one???\n\nIt's still work in progress. Currently I'm working on a test\nframework so we can reuse recursive submodule checkout tests\ninstead of rewriting them for every command that learns the\n--recurse-submodule option. Will reroll this series as soon\nas I have something presentable.\n"},{"id":"234131","messageId":"52EFF25E.6080306@web.de","threadId":"35619","inReplyTo":"xmqqvbxvekwv.fsf@gitster.dls.corp.google.com","subject":"[WIP/PATCH 0/9] v2 submodule recursive checkout]","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-03T19:47:42Z","receivedAt":"2014-02-03T19:47:42Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 07.01.2014 18:55, schrieb Junio C Hamano:\n> Jens Lehmann <Jens.Lehmann@web.de> writes:\n> \n>> Am 06.01.2014 23:36, schrieb Junio C Hamano:\n>>> * jl/submodule-recursive-checkout (2013-12-26) 5 commits\n>>>  - Teach checkout to recursively checkout submodules\n>>>  - submodule: teach unpack_trees() to update submodules\n>>>  - submodule: teach unpack_trees() to repopulate submodules\n>>>  - submodule: teach unpack_trees() to remove submodule contents\n>>>  - submodule: prepare for recursive checkout of submodules\n>>>\n>>>  What is the doneness of this one???\n>>\n>> It's still work in progress. Currently I'm working on a test\n>> framework so we can reuse recursive submodule checkout tests\n>> instead of rewriting them for every command that learns the\n>> --recurse-submodule option. Will reroll this series as soon\n>> as I have something presentable.\n> \n> Thanks.\n\nOk, time for another round. This is still WIP/RFC and not\nready to be merged yet, but I believe this round makes it a\nbit more clear where this is heading.\n\nChanges to the first version are:\n\n- Reordered the commits according to Jonathan's proposal\n  (this currently makes the checkout tests fail until the\n  last commit completes the functionality; this will be\n  fixed when the test framework is added)\n\n- Fixed calling parse_fetch_recurse_submodules_arg() where\n  parse_update_recurse_submodules_arg() must be used.\n\n- Moved the documentation of the --[no-]recurse-submodule\n  option into an include file so different commands can\n  reuse it.\n\n- Added the --[no-]recurse-submodule option to bisect, merge\n  and reset too.\n\nTests, documentation and commit messages are not complete yet,\nI'll work on them in the next rounds. The wiki page in my Github\nrepository will describe the current status of this series:\n\n  https://github.com/jlehmann/git-submod-enhancements/wiki/Recursive-submodule-checkout\n\n\nJens Lehmann (9):\n  submodule: prepare for recursive checkout of submodules\n  Teach reset the --[no-]recurse-submodules option\n  Teach checkout the --[no-]recurse-submodules option\n  Teach merge the --[no-]recurse-submodules option\n  Teach bisect--helper the --[no-]recurse-submodules option\n  Teach bisect the --[no-]recurse-submodules option\n  submodule: teach unpack_trees() to remove submodule contents\n  submodule: teach unpack_trees() to repopulate submodules\n  submodule: teach unpack_trees() to update submodules\n\n Documentation/git-bisect.txt                |   5 +\n Documentation/git-checkout.txt              |   2 +\n Documentation/git-merge.txt                 |   2 +\n Documentation/git-reset.txt                 |   4 +\n Documentation/recurse-submodules-update.txt |   8 +\n bisect.c                                    |  33 ++--\n bisect.h                                    |   3 +-\n builtin/bisect--helper.c                    |   9 +-\n builtin/checkout.c                          |  14 ++\n builtin/merge.c                             |  14 ++\n builtin/reset.c                             |  14 ++\n entry.c                                     |  19 ++-\n git-bisect.sh                               |  29 +++-\n submodule.c                                 | 238 +++++++++++++++++++++++++++-\n submodule.h                                 |  12 ++\n t/t2013-checkout-submodule.sh               | 215 ++++++++++++++++++++++++-\n unpack-trees.c                              |  95 +++++++++--\n unpack-trees.h                              |   1 +\n wrapper.c                                   |   3 +\n 19 files changed, 676 insertions(+), 44 deletions(-)\n create mode 100644 Documentation/recurse-submodules-update.txt\n\n-- \n1.9.rc0.28.ge3363ff\n"},{"id":"234132","messageId":"52EFF290.5090501@web.de","threadId":"35619","inReplyTo":"52EFF25E.6080306@web.de","subject":"[WIP/PATCH 1/9] submodule: prepare for recursive checkout of submodules","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-03T19:48:32Z","receivedAt":"2014-02-03T19:48:32Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"This commit adds the functions and files needed for configuration,\ndocumentation, setting the default behavior and determining if a\nsubmodule path should be updated automatically.\n\nIt won't really enable recursive submodule update. This will be done\nby later commits.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n Documentation/recurse-submodules-update.txt |  8 +++++\n submodule.c                                 | 50 +++++++++++++++++++++++++++++\n submodule.h                                 |  6 ++++\n 3 files changed, 64 insertions(+)\n create mode 100644 Documentation/recurse-submodules-update.txt\n\ndiff --git a/Documentation/recurse-submodules-update.txt b/Documentation/recurse-submodules-update.txt\nnew file mode 100644\nindex 0000000..e57d452\n--- /dev/null\n+++ b/Documentation/recurse-submodules-update.txt\n@@ -0,0 +1,8 @@\n+--[no-]recurse-submodules::\n+\tUsing --recurse-submodules will update the work tree of all\n+\tinitialized submodules according to the commit recorded in the\n+\tsuperproject if their update configuration is set to checkout'. If\n+\tlocal modifications in a submodule would be overwritten the checkout\n+\twill fail unless forced. Without this option or with\n+\t--no-recurse-submodules is, the work trees of submodules will not be\n+\tupdated, only the hash recorded in the superproject will be updated.\ndiff --git a/submodule.c b/submodule.c\nindex 613857e..b3eb28d 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -16,6 +16,8 @@ static struct string_list config_name_for_path;\n static struct string_list config_fetch_recurse_submodules_for_name;\n static struct string_list config_ignore_for_name;\n static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;\n+static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;\n+static int option_update_recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n static struct string_list changed_submodule_paths;\n static int initialized_fetch_ref_tips;\n static struct sha1_array ref_tips_before_fetch;\n@@ -382,6 +384,48 @@ int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)\n \t}\n }\n\n+int parse_update_recurse_submodules_arg(const char *opt, const char *arg)\n+{\n+\tswitch (git_config_maybe_bool(opt, arg)) {\n+\tcase 1:\n+\t\treturn RECURSE_SUBMODULES_ON;\n+\tcase 0:\n+\t\treturn RECURSE_SUBMODULES_OFF;\n+\tdefault:\n+\t\tif (!strcmp(arg, \"checkout\"))\n+\t\t\treturn RECURSE_SUBMODULES_ON;\n+\t\tdie(\"bad %s argument: %s\", opt, arg);\n+\t}\n+}\n+\n+int option_parse_update_submodules(const struct option *opt,\n+\t\t\t\t   const char *arg, int unset)\n+{\n+\tif (unset) {\n+\t\t*(int *)opt->value = RECURSE_SUBMODULES_OFF;\n+\t} else {\n+\t\tif (arg)\n+\t\t\t*(int *)opt->value = parse_update_recurse_submodules_arg(opt->long_name, arg);\n+\t\telse\n+\t\t\t*(int *)opt->value = RECURSE_SUBMODULES_ON;\n+\t}\n+\treturn 0;\n+}\n+\n+int submodule_needs_update(const char *path)\n+{\n+\tstruct string_list_item *path_option;\n+\tpath_option = unsorted_string_list_lookup(&config_name_for_path, path);\n+\tif (!path_option)\n+\t\treturn 0;\n+\n+\t/* update can't be \"none\", \"merge\" or \"rebase\" */\n+\n+\tif (option_update_recurse_submodules != RECURSE_SUBMODULES_DEFAULT)\n+\t\treturn 1;\n+\treturn config_update_recurse_submodules != RECURSE_SUBMODULES_OFF;\n+}\n+\n void show_submodule_summary(FILE *f, const char *path,\n \t\tconst char *line_prefix,\n \t\tunsigned char one[20], unsigned char two[20],\n@@ -589,6 +633,12 @@ int push_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_nam\n \treturn ret;\n }\n\n+void set_config_update_recurse_submodules(int default_value, int option_value)\n+{\n+\tconfig_update_recurse_submodules = default_value;\n+\toption_update_recurse_submodules = option_value;\n+}\n+\n static int is_submodule_commit_present(const char *path, unsigned char sha1[20])\n {\n \tint is_present = 0;\ndiff --git a/submodule.h b/submodule.h\nindex 7beec48..79b336b 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -3,6 +3,7 @@\n\n struct diff_options;\n struct argv_array;\n+struct option;\n\n enum {\n \tRECURSE_SUBMODULES_ON_DEMAND = -1,\n@@ -22,12 +23,17 @@ void gitmodules_config(void);\n int parse_submodule_config_option(const char *var, const char *value);\n void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *);\n int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);\n+int parse_update_recurse_submodules_arg(const char *opt, const char *arg);\n+int option_parse_update_submodules(const struct option *opt,\n+\t\tconst char *arg, int unset);\n+int submodule_needs_update(const char *path);\n void show_submodule_summary(FILE *f, const char *path,\n \t\tconst char *line_prefix,\n \t\tunsigned char one[20], unsigned char two[20],\n \t\tunsigned dirty_submodule, const char *meta,\n \t\tconst char *del, const char *add, const char *reset);\n void set_config_fetch_recurse_submodules(int value);\n+void set_config_update_recurse_submodules(int default_value, int option_value);\n void check_for_new_submodule_commits(unsigned char new_sha1[20]);\n int fetch_populated_submodules(const struct argv_array *options,\n \t\t\t       const char *prefix, int command_line_option,\n-- \n1.9.rc0.28.ge3363ff\n"},{"id":"234133","messageId":"52EFF2C5.3090705@web.de","threadId":"35619","inReplyTo":"52EFF25E.6080306@web.de","subject":"[WIP/PATCH 2/9] Teach reset the --[no-]recurse-submodules option","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-03T19:49:25Z","receivedAt":"2014-02-03T19:49:25Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"This new option will allow the user to not only reset the work tree of\nthe superproject but to also update the work tree of all initialized\nsubmodules (so they match the SHA-1 recorded in the superproject) when\nused together with --hard or --merge. But this commit only adds the\noption without any functionality, that will be added to unpack_trees()\nin subsequent commits.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n Documentation/git-reset.txt |  4 ++++\n builtin/reset.c             | 14 ++++++++++++++\n 2 files changed, 18 insertions(+)\n\ndiff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt\nindex f445cb3..8f833f4 100644\n--- a/Documentation/git-reset.txt\n+++ b/Documentation/git-reset.txt\n@@ -94,6 +94,10 @@ OPTIONS\n --quiet::\n \tBe quiet, only report errors.\n\n+include::recurse-submodules-update.txt[]\n++\n+This option only makes sense together with `--hard` and `--merge` and is\n+ignored when used without these options.\n\n EXAMPLES\n --------\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 6004803..adf372e 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -20,6 +20,7 @@\n #include \"parse-options.h\"\n #include \"unpack-trees.h\"\n #include \"cache-tree.h\"\n+#include \"submodule.h\"\n\n static const char * const git_reset_usage[] = {\n \tN_(\"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]\"),\n@@ -255,6 +256,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n {\n \tint reset_type = NONE, update_ref_status = 0, quiet = 0;\n \tint patch_mode = 0, unborn;\n+\tconst char *recurse_submodules_default = \"off\";\n+\tint recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n \tconst char *rev;\n \tunsigned char sha1[20];\n \tstruct pathspec pathspec;\n@@ -270,13 +273,24 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\tOPT_SET_INT(0, \"keep\", &reset_type,\n \t\t\t\tN_(\"reset HEAD but keep local changes\"), KEEP),\n \t\tOPT_BOOL('p', \"patch\", &patch_mode, N_(\"select hunks interactively\")),\n+\t\t{ OPTION_CALLBACK, 0, \"recurse-submodules\", &recurse_submodules,\n+\t\t\t\"checkout\", \"control recursive updating of submodules\",\n+\t\t\tPARSE_OPT_OPTARG, option_parse_update_submodules },\n+\t\t{ OPTION_STRING, 0, \"recurse-submodules-default\",\n+\t\t\t&recurse_submodules_default, NULL,\n+\t\t\t\"default mode for recursion\", PARSE_OPT_HIDDEN },\n \t\tOPT_END()\n \t};\n\n+\tgitmodules_config();\n \tgit_config(git_default_config, NULL);\n\n \targc = parse_options(argc, argv, prefix, options, git_reset_usage,\n \t\t\t\t\t\tPARSE_OPT_KEEP_DASHDASH);\n+\tset_config_update_recurse_submodules(\n+\t\tparse_update_recurse_submodules_arg(\"--recurse-submodules-default\",\n+\t\t\t\t\t\t    recurse_submodules_default),\n+\t\trecurse_submodules);\n \tparse_args(&pathspec, argv, prefix, patch_mode, &rev);\n\n \tunborn = !strcmp(rev, \"HEAD\") && get_sha1(\"HEAD\", sha1);\n-- \n1.9.rc0.28.ge3363ff\n"},{"id":"234134","messageId":"52EFF2EA.9060709@web.de","threadId":"35619","inReplyTo":"52EFF25E.6080306@web.de","subject":"[WIP/PATCH 3/9] Teach checkout the --[no-]recurse-submodules option","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-03T19:50:02Z","receivedAt":"2014-02-03T19:50:02Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"This new option will allow the user to not only update the work tree of\nthe superproject according to the checked out commit but to also update\nthe work tree of all initialized submodules (so they match the SHA-1\nrecorded in the superproject). But this commit only adds the option\nwithout any functionality, that will be added to unpack_trees() in\nsubsequent commits.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n Documentation/git-checkout.txt |   2 +\n builtin/checkout.c             |  14 +++\n t/t2013-checkout-submodule.sh  | 215 ++++++++++++++++++++++++++++++++++++++++-\n 3 files changed, 228 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\nindex 91294f8..6c7d31f 100644\n--- a/Documentation/git-checkout.txt\n+++ b/Documentation/git-checkout.txt\n@@ -225,6 +225,8 @@ This means that you can use `git checkout -p` to selectively discard\n edits from your current working tree. See the ``Interactive Mode''\n section of linkgit:git-add[1] to learn how to operate the `--patch` mode.\n\n+include::recurse-submodules-update.txt[]\n+\n <branch>::\n \tBranch to checkout; if it refers to a branch (i.e., a name that,\n \twhen prepended with \"refs/heads/\", is a valid ref), then that\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 5df3837..e4ef0ba 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -21,6 +21,9 @@\n #include \"submodule.h\"\n #include \"argv-array.h\"\n\n+static const char *recurse_submodules_default = \"off\";\n+static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n+\n static const char * const checkout_usage[] = {\n \tN_(\"git checkout [options] <branch>\"),\n \tN_(\"git checkout [options] [<branch>] -- <file>...\"),\n@@ -1111,6 +1114,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"do not limit pathspecs to sparse entries only\")),\n \t\tOPT_HIDDEN_BOOL(0, \"guess\", &dwim_new_local_branch,\n \t\t\t\tN_(\"second guess 'git checkout no-such-branch'\")),\n+\t\t{ OPTION_CALLBACK, 0, \"recurse-submodules\", &recurse_submodules,\n+\t\t\t    \"checkout\", \"control recursive updating of submodules\",\n+\t\t\t    PARSE_OPT_OPTARG, option_parse_update_submodules },\n+\t\t{ OPTION_STRING, 0, \"recurse-submodules-default\",\n+\t\t\t   &recurse_submodules_default, NULL,\n+\t\t\t   \"default mode for recursion\", PARSE_OPT_HIDDEN },\n \t\tOPT_END(),\n \t};\n\n@@ -1132,6 +1141,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\tgit_xmerge_config(\"merge.conflictstyle\", conflict_style, NULL);\n \t}\n\n+\tset_config_update_recurse_submodules(\n+\t\tparse_update_recurse_submodules_arg(\"--recurse-submodules-default\",\n+\t\t\t\t\t\t    recurse_submodules_default),\n+\t\trecurse_submodules);\n+\n \tif ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1)\n \t\tdie(_(\"-b, -B and --orphan are mutually exclusive\"));\n\ndiff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh\nindex 06b18f8..bc3e1ca 100755\n--- a/t/t2013-checkout-submodule.sh\n+++ b/t/t2013-checkout-submodule.sh\n@@ -4,17 +4,57 @@ test_description='checkout can handle submodules'\n\n . ./test-lib.sh\n\n+submodule_creation_must_succeed() {\n+\t# checkout base ($1)\n+\tgit checkout -f --recurse-submodules $1 &&\n+\tgit diff-files --quiet &&\n+\tgit diff-index --quiet --cached $1 &&\n+\n+\t# checkout target ($2)\n+\tif test -d submodule; then\n+\t\techo change>>submodule/first.t &&\n+\t\ttest_must_fail git checkout --recurse-submodules $2 &&\n+\t\tgit checkout -f --recurse-submodules $2\n+\telse\n+\t\tgit checkout --recurse-submodules $2\n+\tfi &&\n+\ttest -e submodule/.git &&\n+\ttest -f submodule/first.t &&\n+\ttest -f submodule/second.t &&\n+\tgit diff-files --quiet &&\n+\tgit diff-index --quiet --cached $2\n+}\n+\n+submodule_removal_must_succeed() {\n+\t# checkout base ($1)\n+\tgit checkout -f --recurse-submodules $1 &&\n+\tgit submodule update -f &&\n+\ttest -e submodule/.git &&\n+\tgit diff-files --quiet &&\n+\tgit diff-index --quiet --cached $1 &&\n+\n+\t# checkout target ($2)\n+\techo change>>submodule/first.t &&\n+\ttest_must_fail git checkout --recurse-submodules $2 &&\n+\tgit checkout -f --recurse-submodules $2 &&\n+\tgit diff-files --quiet &&\n+\tgit diff-index --quiet --cached $2 &&\n+\t! test -d submodule\n+}\n+\n test_expect_success 'setup' '\n \tmkdir submodule &&\n \t(cd submodule &&\n \t git init &&\n \t test_commit first) &&\n-\tgit add submodule &&\n+\techo first > file &&\n+\tgit add file submodule &&\n \ttest_tick &&\n \tgit commit -m superproject &&\n \t(cd submodule &&\n \t test_commit second) &&\n-\tgit add submodule &&\n+\techo second > file &&\n+\tgit add file submodule &&\n \ttest_tick &&\n \tgit commit -m updated.superproject\n '\n@@ -36,7 +76,8 @@ test_expect_success '\"checkout <submodule>\" updates the index only' '\n \tgit checkout HEAD^ submodule &&\n \ttest_must_fail git diff-files --quiet &&\n \tgit checkout HEAD submodule &&\n-\tgit diff-files --quiet\n+\tgit diff-files --quiet &&\n+\tgit diff-index --quiet --cached HEAD\n '\n\n test_expect_success '\"checkout <submodule>\" honors diff.ignoreSubmodules' '\n@@ -62,4 +103,172 @@ test_expect_success '\"checkout <submodule>\" honors submodule.*.ignore from .git/\n \t! test -s actual\n '\n\n+test_expect_success '\"checkout --recurse-submodules\" removes deleted submodule' '\n+\tgit config -f .gitmodules submodule.submodule.path submodule &&\n+\tgit config -f .gitmodules submodule.submodule.url submodule.bare &&\n+\t(cd submodule && git clone --bare . ../submodule.bare) &&\n+\techo submodule.bare >>.gitignore &&\n+\tgit config submodule.submodule.ignore none &&\n+\tgit add .gitignore .gitmodules submodule &&\n+\tgit submodule update --init &&\n+\tgit commit -m \"submodule registered\" &&\n+\tgit checkout -b base &&\n+\tgit checkout -b delete_submodule &&\n+\trm -rf submodule &&\n+\tgit rm submodule &&\n+\tgit commit -m \"submodule deleted\" &&\n+\tsubmodule_removal_must_succeed base delete_submodule\n+'\n+\n+test_expect_success '\"checkout --recurse-submodules\" repopulates submodule' '\n+\tsubmodule_creation_must_succeed delete_submodule base\n+'\n+\n+test_expect_success '\"checkout --recurse-submodules\" repopulates submodule in existing directory' '\n+\tgit checkout --recurse-submodules delete_submodule &&\n+\tmkdir submodule &&\n+\tsubmodule_creation_must_succeed delete_submodule base\n+'\n+\n+test_expect_success '\"checkout --recurse-submodules\" replaces submodule with files' '\n+\tgit checkout -f base &&\n+\tgit checkout -b replace_submodule_with_dir &&\n+\tgit update-index --force-remove submodule &&\n+\trm -rf submodule/.git .gitmodules &&\n+\tgit add .gitmodules submodule/* &&\n+\tgit commit -m \"submodule replaced\" &&\n+\tgit checkout -f base &&\n+\tgit submodule update -f &&\n+\tgit checkout --recurse-submodules replace_submodule_with_dir &&\n+\ttest -d submodule &&\n+\t! test -e submodule/.git &&\n+\ttest -f submodule/first.t &&\n+\ttest -f submodule/second.t\n+'\n+\n+test_expect_success '\"checkout --recurse-submodules\" removes files and repopulates submodule' '\n+\tsubmodule_creation_must_succeed replace_submodule_with_dir base\n+'\n+\n+test_expect_failure '\"checkout --recurse-submodules\" replaces submodule with a file' '\n+\tgit checkout -f base &&\n+\tgit checkout -b replace_submodule_with_file &&\n+\tgit update-index --force-remove submodule &&\n+\trm -rf submodule .gitmodules &&\n+\techo content >submodule &&\n+\tgit add .gitmodules submodule &&\n+\tgit commit -m \"submodule replaced with file\" &&\n+\tgit checkout -f base &&\n+\tgit submodule update -f &&\n+\tgit checkout --recurse-submodules replace_submodule_with_file &&\n+\ttest -d submodule &&\n+\t! test -e submodule/.git &&\n+\ttest -f submodule/first.t &&\n+\ttest -f submodule/second.t\n+'\n+\n+test_expect_success '\"checkout --recurse-submodules\" removes the file and repopulates submodule' '\n+\tsubmodule_creation_must_succeed replace_submodule_with_file base\n+'\n+\n+test_expect_failure '\"checkout --recurse-submodules\" replaces submodule with a link' '\n+\tgit checkout -f base &&\n+\tgit checkout -b replace_submodule_with_link &&\n+\tgit update-index --force-remove submodule &&\n+\trm -rf submodule .gitmodules &&\n+\tln -s submodule &&\n+\tgit add .gitmodules submodule &&\n+\tgit commit -m \"submodule replaced with link\" &&\n+\tgit checkout -f base &&\n+\tgit submodule update -f &&\n+\tgit checkout --recurse-submodules replace_submodule_with_link &&\n+\ttest -d submodule &&\n+\t! test -e submodule/.git &&\n+\ttest -f submodule/first.t &&\n+\ttest -f submodule/second.t\n+'\n+\n+test_expect_success '\"checkout --recurse-submodules\" removes the link and repopulates submodule' '\n+\tsubmodule_creation_must_succeed replace_submodule_with_link base\n+'\n+\n+test_expect_success '\"checkout --recurse-submodules\" updates recursively' '\n+\tgit checkout --recurse-submodules base &&\n+\tgit diff-files --quiet &&\n+\tgit diff-index --quiet --cached HEAD &&\n+\tgit checkout -b updated_submodule &&\n+\t(cd submodule &&\n+\t echo x >>first.t &&\n+\t git add first.t &&\n+\t test_commit third) &&\n+\tgit add submodule &&\n+\ttest_tick &&\n+\tgit commit -m updated.superproject &&\n+\tgit checkout --recurse-submodules base &&\n+\tgit diff-files --quiet &&\n+\tgit diff-index --quiet --cached HEAD\n+'\n+\n+test_expect_failure '\"checkout --recurse-submodules\" needs -f to update a modifed submodule commit' '\n+\t(\n+\t\tcd submodule &&\n+\t\tgit checkout --recurse-submodules HEAD^\n+\t) &&\n+\ttest_must_fail git checkout --recurse-submodules master &&\n+\ttest_must_fail git diff-files --quiet submodule &&\n+\tgit diff-files --quiet file &&\n+\tgit checkout --recurse-submodules -f master &&\n+\tgit diff-files --quiet &&\n+\tgit diff-index --quiet --cached HEAD\n+'\n+\n+test_expect_failure '\"checkout --recurse-submodules\" needs -f to update modifed submodule content' '\n+\techo modified >submodule/second.t &&\n+\ttest_must_fail git checkout --recurse-submodules HEAD^ &&\n+\ttest_must_fail git diff-files --quiet submodule &&\n+\tgit diff-files --quiet file &&\n+\tgit checkout --recurse-submodules -f HEAD^ &&\n+\tgit diff-files --quiet &&\n+\tgit diff-index --quiet --cached HEAD &&\n+\tgit checkout --recurse-submodules -f master &&\n+\tgit diff-files --quiet &&\n+\tgit diff-index --quiet --cached HEAD\n+'\n+\n+test_expect_failure '\"checkout --recurse-submodules\" ignores modified submodule content that would not be changed' '\n+\techo modified >expected &&\n+\tcp expected submodule/first.t &&\n+\tgit checkout --recurse-submodules HEAD^ &&\n+\ttest_cmp expected submodule/first.t &&\n+\ttest_must_fail git diff-files --quiet submodule &&\n+\tgit diff-index --quiet --cached HEAD &&\n+\tgit checkout --recurse-submodules -f master &&\n+\tgit diff-files --quiet &&\n+\tgit diff-index --quiet --cached HEAD\n+'\n+\n+test_expect_failure '\"checkout --recurse-submodules\" does not care about untracked submodule content' '\n+\techo untracked >submodule/untracked &&\n+\tgit checkout --recurse-submodules master &&\n+\tgit diff-files --quiet --ignore-submodules=untracked &&\n+\tgit diff-index --quiet --cached HEAD &&\n+\trm submodule/untracked\n+'\n+\n+test_expect_failure '\"checkout --recurse-submodules\" needs -f when submodule commit is not present (but does fail anyway)' '\n+\tgit checkout --recurse-submodules -b bogus_commit master &&\n+\tgit update-index --cacheinfo 160000 0123456789012345678901234567890123456789 submodule\n+\tBOGUS_TREE=$(git write-tree) &&\n+\tBOGUS_COMMIT=$(echo \"bogus submodule commit\" | git commit-tree $BOGUS_TREE) &&\n+\tgit commit -m \"bogus submodule commit\" &&\n+\tgit checkout --recurse-submodules -f master &&\n+\ttest_must_fail git checkout --recurse-submodules bogus_commit &&\n+\tgit diff-files --quiet &&\n+\ttest_must_fail git checkout --recurse-submodules -f bogus_commit &&\n+\ttest_must_fail git diff-files --quiet submodule &&\n+\tgit diff-files --quiet file &&\n+\tgit diff-index --quiet --cached HEAD &&\n+\tgit checkout --recurse-submodules -f master\n+'\n+\n test_done\n-- \n1.9.rc0.28.ge3363ff\n"},{"id":"234135","messageId":"52EFF311.1090202@web.de","threadId":"35619","inReplyTo":"52EFF25E.6080306@web.de","subject":"[WIP/PATCH 4/9] Teach merge the --[no-]recurse-submodules option","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-03T19:50:41Z","receivedAt":"2014-02-03T19:50:41Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"This new option will allow the user to not only update the work tree of\nthe superproject according to the merge result but to also update the\nwork tree of all initialized submodules (so they match the SHA-1 recorded\nin the superproject). But this commit only adds the option without any\nfunctionality, that will be added to unpack_trees() in subsequent commits.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n Documentation/git-merge.txt |  2 ++\n builtin/merge.c             | 14 ++++++++++++++\n 2 files changed, 16 insertions(+)\n\ndiff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt\nindex 4395459..9ed1655 100644\n--- a/Documentation/git-merge.txt\n+++ b/Documentation/git-merge.txt\n@@ -96,6 +96,8 @@ commit or stash your changes before running 'git merge'.\n 'git merge --abort' is equivalent to 'git reset --merge' when\n `MERGE_HEAD` is present.\n\n+include::recurse-submodules-update.txt[]\n+\n <commit>...::\n \tCommits, usually other branch heads, to merge into our branch.\n \tSpecifying more than one commit will create a merge with\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 4941a6c..a0eb665 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -28,6 +28,7 @@\n #include \"remote.h\"\n #include \"fmt-merge-msg.h\"\n #include \"gpg-interface.h\"\n+#include \"submodule.h\"\n\n #define DEFAULT_TWOHEAD (1<<0)\n #define DEFAULT_OCTOPUS (1<<1)\n@@ -65,6 +66,8 @@ static int abort_current_merge;\n static int show_progress = -1;\n static int default_to_upstream;\n static const char *sign_commit;\n+static const char *recurse_submodules_default = \"off\";\n+static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n\n static struct strategy all_strategy[] = {\n \t{ \"recursive\",  DEFAULT_TWOHEAD | NO_TRIVIAL },\n@@ -223,6 +226,12 @@ static struct option builtin_merge_options[] = {\n \t{ OPTION_STRING, 'S', \"gpg-sign\", &sign_commit, N_(\"key id\"),\n \t  N_(\"GPG sign commit\"), PARSE_OPT_OPTARG, NULL, (intptr_t) \"\" },\n \tOPT_BOOL(0, \"overwrite-ignore\", &overwrite_ignore, N_(\"update ignored files (default)\")),\n+\t{ OPTION_CALLBACK, 0, \"recurse-submodules\", &recurse_submodules,\n+\t\t\"checkout\", \"control recursive updating of submodules\",\n+\t\tPARSE_OPT_OPTARG, option_parse_update_submodules },\n+\t{ OPTION_STRING, 0, \"recurse-submodules-default\",\n+\t\t&recurse_submodules_default, NULL,\n+\t\t\"default mode for recursion\", PARSE_OPT_HIDDEN },\n \tOPT_END()\n };\n\n@@ -1113,6 +1122,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \telse\n \t\thead_commit = lookup_commit_or_die(head_sha1, \"HEAD\");\n\n+\tgitmodules_config();\n \tgit_config(git_merge_config, NULL);\n\n \tif (branch_mergeoptions)\n@@ -1121,6 +1131,10 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\t\tbuiltin_merge_usage, 0);\n \tif (shortlog_len < 0)\n \t\tshortlog_len = (merge_log_config > 0) ? merge_log_config : 0;\n+\tset_config_update_recurse_submodules(\n+\t\tparse_update_recurse_submodules_arg(\"--recurse-submodules-default\",\n+\t\t\t\t\t\t    recurse_submodules_default),\n+\t\trecurse_submodules);\n\n \tif (verbosity < 0 && show_progress == -1)\n \t\tshow_progress = 0;\n-- \n1.9.rc0.28.ge3363ff\n"},{"id":"234136","messageId":"52EFF337.3060308@web.de","threadId":"35619","inReplyTo":"52EFF25E.6080306@web.de","subject":"[WIP/PATCH 5/9] Teach bisect--helper the --[no-]recurse-submodules option","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-03T19:51:19Z","receivedAt":"2014-02-03T19:51:19Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"This is necessary before we can teach 'git bisect' this option, as that\ncalls the bisect--helper to do the actual work which then in turn calls\n'git checkout'. The helper just passes the option given on the command\nline on to checkout. The new recurse_submodules_enum_to_option() is added\nto avoid having the helper learn the command line representation of the\ndifferent option values himself.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n bisect.c                 | 33 ++++++++++++++++++++++-----------\n bisect.h                 |  3 ++-\n builtin/bisect--helper.c |  9 ++++++++-\n submodule.c              | 21 +++++++++++++++++++++\n submodule.h              |  1 +\n 5 files changed, 54 insertions(+), 13 deletions(-)\n\ndiff --git a/bisect.c b/bisect.c\nindex 37200b4..b84e607 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -11,13 +11,13 @@\n #include \"bisect.h\"\n #include \"sha1-array.h\"\n #include \"argv-array.h\"\n+#include \"submodule.h\"\n\n static struct sha1_array good_revs;\n static struct sha1_array skipped_revs;\n\n static unsigned char *current_bad_sha1;\n\n-static const char *argv_checkout[] = {\"checkout\", \"-q\", NULL, \"--\", NULL};\n static const char *argv_show_branch[] = {\"show-branch\", NULL, NULL};\n static const char *argv_update_ref[] = {\"update-ref\", \"--no-deref\", \"BISECT_HEAD\", NULL, NULL};\n\n@@ -683,22 +683,30 @@ static void mark_expected_rev(char *bisect_rev_hex)\n \t\tdie(\"closing file %s: %s\", filename, strerror(errno));\n }\n\n-static int bisect_checkout(char *bisect_rev_hex, int no_checkout)\n+static int bisect_checkout(char *bisect_rev_hex, int no_checkout,\n+\t\t\t   const char *recurse_submodules)\n {\n \tint res;\n\n \tmark_expected_rev(bisect_rev_hex);\n\n-\targv_checkout[2] = bisect_rev_hex;\n \tif (no_checkout) {\n \t\targv_update_ref[3] = bisect_rev_hex;\n \t\tif (run_command_v_opt(argv_update_ref, RUN_GIT_CMD))\n \t\t\tdie(\"update-ref --no-deref HEAD failed on %s\",\n \t\t\t    bisect_rev_hex);\n \t} else {\n-\t\tres = run_command_v_opt(argv_checkout, RUN_GIT_CMD);\n+\t\tstruct argv_array argv = ARGV_ARRAY_INIT;\n+\t\targv_array_push(&argv, \"checkout\");\n+\t\targv_array_push(&argv, \"-q\");\n+\t\tif (recurse_submodules)\n+\t\t    argv_array_push(&argv, recurse_submodules);\n+\t\targv_array_push(&argv, bisect_rev_hex);\n+\t\targv_array_push(&argv, \"--\");\n+\t\tres = run_command_v_opt(argv.argv, RUN_GIT_CMD);\n \t\tif (res)\n \t\t\texit(res);\n+\t\targv_array_clear(&argv);\n \t}\n\n \targv_show_branch[1] = bisect_rev_hex;\n@@ -771,7 +779,7 @@ static void handle_skipped_merge_base(const unsigned char *mb)\n  * - If one is \"skipped\", we can't know but we should warn.\n  * - If we don't know, we should check it out and ask the user to test.\n  */\n-static void check_merge_bases(int no_checkout)\n+static void check_merge_bases(int no_checkout, const char *recurse_submodules)\n {\n \tstruct commit_list *result;\n \tint rev_nr;\n@@ -789,7 +797,8 @@ static void check_merge_bases(int no_checkout)\n \t\t\thandle_skipped_merge_base(mb);\n \t\t} else {\n \t\t\tprintf(\"Bisecting: a merge base must be tested\\n\");\n-\t\t\texit(bisect_checkout(sha1_to_hex(mb), no_checkout));\n+\t\t\texit(bisect_checkout(sha1_to_hex(mb), no_checkout,\n+\t\t\t\t\t     recurse_submodules));\n \t\t}\n \t}\n\n@@ -832,7 +841,8 @@ static int check_ancestors(const char *prefix)\n  * If a merge base must be tested by the user, its source code will be\n  * checked out to be tested by the user and we will exit.\n  */\n-static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)\n+static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout,\n+\t\t\t\t\t    const char *recurse_submodules)\n {\n \tchar *filename = git_pathdup(\"BISECT_ANCESTORS_OK\");\n \tstruct stat st;\n@@ -851,7 +861,7 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)\n\n \t/* Check if all good revs are ancestor of the bad rev. */\n \tif (check_ancestors(prefix))\n-\t\tcheck_merge_bases(no_checkout);\n+\t\tcheck_merge_bases(no_checkout, recurse_submodules);\n\n \t/* Create file BISECT_ANCESTORS_OK. */\n \tfd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);\n@@ -897,7 +907,8 @@ static void show_diff_tree(const char *prefix, struct commit *commit)\n  * If no_checkout is non-zero, the bisection process does not\n  * checkout the trial commit but instead simply updates BISECT_HEAD.\n  */\n-int bisect_next_all(const char *prefix, int no_checkout)\n+int bisect_next_all(const char *prefix, int no_checkout,\n+\t\t    const char *recurse_submodules)\n {\n \tstruct rev_info revs;\n \tstruct commit_list *tried;\n@@ -908,7 +919,7 @@ int bisect_next_all(const char *prefix, int no_checkout)\n \tif (read_bisect_refs())\n \t\tdie(\"reading bisect refs failed\");\n\n-\tcheck_good_are_ancestors_of_bad(prefix, no_checkout);\n+\tcheck_good_are_ancestors_of_bad(prefix, no_checkout, recurse_submodules);\n\n \tbisect_rev_setup(&revs, prefix, \"%s\", \"^%s\", 1);\n \trevs.limited = 1;\n@@ -954,7 +965,7 @@ int bisect_next_all(const char *prefix, int no_checkout)\n \t       \"(roughly %d step%s)\\n\", nr, (nr == 1 ? \"\" : \"s\"),\n \t       steps, (steps == 1 ? \"\" : \"s\"));\n\n-\treturn bisect_checkout(bisect_rev_hex, no_checkout);\n+\treturn bisect_checkout(bisect_rev_hex, no_checkout, recurse_submodules);\n }\n\n static inline int log2i(int n)\ndiff --git a/bisect.h b/bisect.h\nindex 2a6c831..5c1ea9c 100644\n--- a/bisect.h\n+++ b/bisect.h\n@@ -22,7 +22,8 @@ struct rev_list_info {\n \tconst char *header_prefix;\n };\n\n-extern int bisect_next_all(const char *prefix, int no_checkout);\n+extern int bisect_next_all(const char *prefix, int no_checkout,\n+\t\t\t   const char *recurse_submodules);\n\n extern int estimate_bisect_steps(int all);\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 3324229..b30087a 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -2,6 +2,7 @@\n #include \"cache.h\"\n #include \"parse-options.h\"\n #include \"bisect.h\"\n+#include \"submodule.h\"\n\n static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --next-all [--no-checkout]\"),\n@@ -12,11 +13,16 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tint next_all = 0;\n \tint no_checkout = 0;\n+\tint recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n+\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"next-all\", &next_all,\n \t\t\t N_(\"perform 'git bisect next'\")),\n \t\tOPT_BOOL(0, \"no-checkout\", &no_checkout,\n \t\t\t N_(\"update BISECT_HEAD instead of checking out the current commit\")),\n+\t\t{ OPTION_CALLBACK, 0, \"recurse-submodules\", &recurse_submodules,\n+\t\t\t\"checkout\", \"control recursive updating of submodules\",\n+\t\t\tPARSE_OPT_OPTARG, option_parse_update_submodules },\n \t\tOPT_END()\n \t};\n\n@@ -27,5 +33,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(git_bisect_helper_usage, options);\n\n \t/* next-all */\n-\treturn bisect_next_all(prefix, no_checkout);\n+\treturn bisect_next_all(prefix, no_checkout,\n+\t\t\t       recurse_submodules_enum_to_option(recurse_submodules));\n }\ndiff --git a/submodule.c b/submodule.c\nindex b3eb28d..448b645 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -44,6 +44,27 @@ static int gitmodules_is_unmerged;\n static int gitmodules_is_modified;\n\n\n+/*\n+ * Convert values defined in the RECURSE_SUBMODULES_* enum to the string\n+ * representation usable as command parameter. Returns NULL if no parameter\n+ * is necessary.\n+ */\n+const char *recurse_submodules_enum_to_option(int recurse_submodules)\n+{\n+\tswitch(recurse_submodules) {\n+\tcase RECURSE_SUBMODULES_ON_DEMAND:\n+\t\treturn \"--recurse-submodules=on-demand\";\n+\tcase RECURSE_SUBMODULES_OFF:\n+\t\treturn \"--no-recurse-submodules\";\n+\tcase RECURSE_SUBMODULES_ON:\n+\t\treturn \"--recurse-submodules\";\n+\tcase RECURSE_SUBMODULES_DEFAULT:\n+\t\treturn NULL;\n+\tdefault:\n+\t\tdie(\"Invalid recurse submodule value: %d\", recurse_submodules);\n+\t}\n+}\n+\n int is_staging_gitmodules_ok(void)\n {\n \treturn !gitmodules_is_modified;\ndiff --git a/submodule.h b/submodule.h\nindex 79b336b..5958010 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -11,6 +11,7 @@ enum {\n \tRECURSE_SUBMODULES_DEFAULT = 1,\n \tRECURSE_SUBMODULES_ON = 2\n };\n+const char *recurse_submodules_enum_to_option(int recurse_submodules);\n\n int is_staging_gitmodules_ok(void);\n int update_path_in_gitmodules(const char *oldpath, const char *newpath);\n-- \n1.9.rc0.28.ge3363ff\n"},{"id":"234137","messageId":"52EFF35D.7070908@web.de","threadId":"35619","inReplyTo":"52EFF25E.6080306@web.de","subject":"[WIP/PATCH 6/9] Teach bisect the --[no-]recurse-submodules option","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-03T19:51:57Z","receivedAt":"2014-02-03T19:51:57Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"When using this option 'git bisect' will automatically update the work\ntree of all initialized submodules (so they match the SHA-1 recorded in\nthe superproject) in each bisection step. This makes calling 'git\nsubmodule update' eacht time obsolete, which was tedious and error prone.\nIf the option is given it is stored in the BISECT_RECURSE_SUBMODULES file\nin the git directory so that later bisection steps can reuse it. But this\ncommit only adds the option without any functionality, that will be added\nto unpack_trees() in subsequent commits.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n Documentation/git-bisect.txt |  5 +++++\n git-bisect.sh                | 29 ++++++++++++++++++++++++-----\n 2 files changed, 29 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt\nindex f986c5c..c0aaba8 100644\n--- a/Documentation/git-bisect.txt\n+++ b/Documentation/git-bisect.txt\n@@ -276,6 +276,11 @@ does not require a checked out tree.\n +\n If the repository is bare, `--no-checkout` is assumed.\n\n+include::recurse-submodules-update.txt[]\n++\n+This option is passed to linkgit:git-checkout[1] when checking out the next\n+to be tested commit and is ignored when used together with `--no-checkout`.\n+\n EXAMPLES\n --------\n\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 73b4c14..ba64a21 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -3,7 +3,7 @@\n USAGE='[help|start|bad|good|skip|next|reset|visualize|replay|log|run]'\n LONG_USAGE='git bisect help\n \tprint this long help message.\n-git bisect start [--no-checkout] [<bad> [<good>...]] [--] [<pathspec>...]\n+git bisect start [--no-checkout] [--[no-]recurse-submodules[=<mode>]] [<bad> [<good>...]] [--] [<pathspec>...]\n \treset bisect state and start bisection.\n git bisect bad [<rev>]\n \tmark <rev> a known-bad revision.\n@@ -91,6 +91,12 @@ bisect_start() {\n \t\t--no-checkout)\n \t\t\tmode=--no-checkout\n \t\t\tshift ;;\n+\t\t--no-recurse-submodules)\n+\t\t\trecurse_submodules=\"$1\"\n+\t\t\tshift ;;\n+\t\t--recurse-submodules*)\n+\t\t\trecurse_submodules=\"$1\"\n+\t\t\tshift ;;\n \t\t--*)\n \t\t\tdie \"$(eval_gettext \"unrecognised option: '\\$arg'\")\" ;;\n \t\t*)\n@@ -124,9 +130,13 @@ bisect_start() {\n \tthen\n \t\t# Reset to the rev from where we started.\n \t\tstart_head=$(cat \"$GIT_DIR/BISECT_START\")\n+\t\tif test -s \"$GIT_DIR/BISECT_RECURSE_SUBMODULES\"\n+\t\tthen\n+\t\t\trecurse_submodules=$(cat \"$GIT_DIR/BISECT_RECURSE_SUBMODULES\")\n+\t\tfi\n \t\tif test \"z$mode\" != \"z--no-checkout\"\n \t\tthen\n-\t\t\tgit checkout \"$start_head\" -- ||\n+\t\t\tgit checkout ${recurse_submodules:+\"$recurse_submodules\"} \"$start_head\" -- ||\n \t\t\tdie \"$(eval_gettext \"Checking out '\\$start_head' failed. Try 'git bisect reset <validbranch>'.\")\"\n \t\tfi\n \telse\n@@ -168,7 +178,10 @@ bisect_start() {\n \t\ttest \"z$mode\" != \"z--no-checkout\" ||\n \t\tgit update-ref --no-deref BISECT_HEAD \"$start_head\"\n \t} &&\n-\tgit rev-parse --sq-quote \"$@\" >\"$GIT_DIR/BISECT_NAMES\" &&\n+\tgit rev-parse --sq-quote \"$@\" >\"$GIT_DIR/BISECT_NAMES\" && {\n+\t\ttest -z \"$recurse_submodules\" ||\n+\t\techo \"$recurse_submodules\" >\"$GIT_DIR/BISECT_RECURSE_SUBMODULES\"\n+\t} &&\n \teval \"$eval true\" &&\n \techo \"git bisect start$orig_args\" >>\"$GIT_DIR/BISECT_LOG\" || exit\n \t#\n@@ -306,8 +319,13 @@ bisect_next() {\n \tbisect_autostart\n \tbisect_next_check good\n\n+\tif test -f \"$GIT_DIR/BISECT_RECURSE_SUBMODULES\"\n+\tthen\n+\t\trecurse_submodules=$(cat \"$GIT_DIR/BISECT_RECURSE_SUBMODULES\")\n+\tfi\n+\n \t# Perform all bisection computation, display and checkout\n-\tgit bisect--helper --next-all $(test -f \"$GIT_DIR/BISECT_HEAD\" && echo --no-checkout)\n+\tgit bisect--helper --next-all $(test -f \"$GIT_DIR/BISECT_HEAD\" && echo --no-checkout) ${recurse_submodules:+\"$recurse_submodules\"}\n \tres=$?\n\n \t# Check if we should exit because bisection is finished\n@@ -374,7 +392,7 @@ bisect_reset() {\n \t\tusage ;;\n \tesac\n\n-\tif ! test -f \"$GIT_DIR/BISECT_HEAD\" && ! git checkout \"$branch\" --\n+\tif ! test -f \"$GIT_DIR/BISECT_HEAD\" && ! git checkout ${recurse_submodules:+\"$recurse_submodules\"} \"$branch\" --\n \tthen\n \t\tdie \"$(eval_gettext \"Could not check out original HEAD '\\$branch'.\n Try 'git bisect reset <commit>'.\")\"\n@@ -397,6 +415,7 @@ bisect_clean_state() {\n \t# Cleanup head-name if it got left by an old version of git-bisect\n \trm -f \"$GIT_DIR/head-name\" &&\n \tgit update-ref -d --no-deref BISECT_HEAD &&\n+\trm -f \"$GIT_DIR/BISECT_RECURSE_SUBMODULES\" &&\n \t# clean up BISECT_START last\n \trm -f \"$GIT_DIR/BISECT_START\"\n }\n-- \n1.9.rc0.28.ge3363ff\n"},{"id":"234139","messageId":"52EFF391.7040503@web.de","threadId":"35619","inReplyTo":"52EFF25E.6080306@web.de","subject":"[WIP/PATCH 7/9] submodule: teach unpack_trees() to remove submodule contents","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-03T19:52:49Z","receivedAt":"2014-02-03T19:52:49Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Implement the functionality needed to enable work tree manipulating\ncommands to that a deleted submodule should not only affect the index\n(leaving all the files of the submodule in the work tree) but also to\nremove the work tree of the superproject (including any untracked\nfiles).\n\nThat will only work properly when the submodule uses a gitfile instead of\na .git directory and no untracked files are present. Otherwise the removal\nwill fail with a warning (which is just what happened until now).\n\nExtend rmdir_or_warn() to remove the directories of those submodules which\nare scheduled for removal. Also teach verify_clean_submodule() to check\nthat a submodule configured to be removed is not modified before scheduling\nit for removal.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n submodule.c    | 37 +++++++++++++++++++++++++++++++++++++\n submodule.h    |  1 +\n unpack-trees.c |  7 ++++---\n wrapper.c      |  3 +++\n 4 files changed, 45 insertions(+), 3 deletions(-)\n\ndiff --git a/submodule.c b/submodule.c\nindex 448b645..f292e9e 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -447,6 +447,43 @@ int submodule_needs_update(const char *path)\n \treturn config_update_recurse_submodules != RECURSE_SUBMODULES_OFF;\n }\n\n+int depopulate_submodule(const char *path)\n+{\n+\tstruct strbuf dot_git = STRBUF_INIT;\n+\tstruct child_process cp;\n+\tconst char *argv[] = {\"rm\", \"-rf\", path, NULL};\n+\n+\t/* Is it populated? */\n+\tstrbuf_addf(&dot_git, \"%s/.git\", path);\n+\tif (!resolve_gitdir(dot_git.buf)) {\n+\t\tstrbuf_release(&dot_git);\n+\t\treturn 0;\n+\t}\n+\tstrbuf_release(&dot_git);\n+\n+\t/* Does it have a .git directory? */\n+\tif (!submodule_uses_gitfile(path)) {\n+\t\twarning(_(\"cannot remove submodule '%s' because it (or one of \"\n+\t\t\t  \"its nested submodules) uses a .git directory\"),\n+\t\t\t  path);\n+\t\treturn -1;\n+\t}\n+\n+\t/* Remove the whole submodule directory */\n+\tmemset(&cp, 0, sizeof(cp));\n+\tcp.argv = argv;\n+\tcp.env = local_repo_env;\n+\tcp.git_cmd = 0;\n+\tcp.no_stdin = 1;\n+\tif (run_command(&cp)) {\n+\t\twarning(\"Could not remove submodule %s\", path);\n+\t\tstrbuf_release(&dot_git);\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n void show_submodule_summary(FILE *f, const char *path,\n \t\tconst char *line_prefix,\n \t\tunsigned char one[20], unsigned char two[20],\ndiff --git a/submodule.h b/submodule.h\nindex 5958010..2139e08 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -28,6 +28,7 @@ int parse_update_recurse_submodules_arg(const char *opt, const char *arg);\n int option_parse_update_submodules(const struct option *opt,\n \t\tconst char *arg, int unset);\n int submodule_needs_update(const char *path);\n+int depopulate_submodule(const char *path);\n void show_submodule_summary(FILE *f, const char *path,\n \t\tconst char *line_prefix,\n \t\tunsigned char one[20], unsigned char two[20],\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 164354d..82c99eb 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -8,6 +8,7 @@\n #include \"progress.h\"\n #include \"refs.h\"\n #include \"attr.h\"\n+#include \"submodule.h\"\n\n /*\n  * Error messages expected by scripts out of plumbing commands such as\n@@ -1266,14 +1267,14 @@ static void invalidate_ce_path(const struct cache_entry *ce,\n /*\n  * Check that checking out ce->sha1 in subdir ce->name is not\n  * going to overwrite any working files.\n- *\n- * Currently, git does not checkout subprojects during a superproject\n- * checkout, so it is not going to overwrite anything.\n  */\n static int verify_clean_submodule(const struct cache_entry *ce,\n \t\t\t\t  enum unpack_trees_error_types error_type,\n \t\t\t\t  struct unpack_trees_options *o)\n {\n+\tif (submodule_needs_update(ce->name) &&\n+\t    is_submodule_modified(ce->name, 0))\n+\t\treturn 1;\n \treturn 0;\n }\n\ndiff --git a/wrapper.c b/wrapper.c\nindex 0cc5636..425a3fd 100644\n--- a/wrapper.c\n+++ b/wrapper.c\n@@ -2,6 +2,7 @@\n  * Various trivial helper wrappers around standard functions\n  */\n #include \"cache.h\"\n+#include \"submodule.h\"\n\n static void do_nothing(size_t size)\n {\n@@ -409,6 +410,8 @@ int unlink_or_warn(const char *file)\n\n int rmdir_or_warn(const char *file)\n {\n+\tif (submodule_needs_update(file) && depopulate_submodule(file))\n+\t\treturn -1;\n \treturn warn_if_unremovable(\"rmdir\", file, rmdir(file));\n }\n\n-- \n1.9.rc0.28.ge3363ff\n"},{"id":"234140","messageId":"52EFF3C7.3020805@web.de","threadId":"35619","inReplyTo":"52EFF25E.6080306@web.de","subject":"[WIP/PATCH 8/9] submodule: teach unpack_trees() to repopulate submodules","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-03T19:53:43Z","receivedAt":"2014-02-03T19:53:43Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Implement the functionality needed to enable work tree manipulating\ncommands so that an added submodule does not only affect the index and\ncreates an empty directory but it also populates the work tree of any\ninitialized submodule according to the SHA-1 recorded in the superproject.\n\nThat will only work for submodules that store their git directory in the\n.git/modules directory of the superproject. Additionally the submodule has\nto be found in the .gitmodules file before the work tree update starts as\nthe git directory is stored under the submodule name, not its path. This\nwill be fixed when the .gitmodules blob of the tree we are updating to\nwill be used for the path <-> name mapping in a later commit.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n entry.c        |  4 ++++\n submodule.c    | 44 +++++++++++++++++++++++++++++++++++++++++---\n submodule.h    |  1 +\n unpack-trees.c | 19 +++++++++++++++++++\n 4 files changed, 65 insertions(+), 3 deletions(-)\n\ndiff --git a/entry.c b/entry.c\nindex 7b7aa81..d1bf6ec 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -2,6 +2,7 @@\n #include \"blob.h\"\n #include \"dir.h\"\n #include \"streaming.h\"\n+#include \"submodule.h\"\n\n static void create_directories(const char *path, int path_len,\n \t\t\t       const struct checkout *state)\n@@ -203,6 +204,9 @@ static int write_entry(struct cache_entry *ce,\n \t\t\treturn error(\"cannot create temporary submodule %s\", path);\n \t\tif (mkdir(path, 0777) < 0)\n \t\t\treturn error(\"cannot create submodule directory %s\", path);\n+\t\tif (submodule_needs_update(path) &&\n+\t\t    populate_submodule(path, ce->sha1, state->force))\n+\t\t\treturn error(\"cannot checkout submodule %s\", path);\n \t\tbreak;\n \tdefault:\n \t\treturn error(\"unknown file mode for %s in index\", path);\ndiff --git a/submodule.c b/submodule.c\nindex f292e9e..3907034 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -447,6 +447,42 @@ int submodule_needs_update(const char *path)\n \treturn config_update_recurse_submodules != RECURSE_SUBMODULES_OFF;\n }\n\n+int populate_submodule(const char *path, unsigned char sha1[20], int force)\n+{\n+\tstruct string_list_item *path_option;\n+\tconst char *name, *real_git_dir;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tstruct child_process cp;\n+\tconst char *argv[] = {\"read-tree\", force ? \"--reset\" : \"-m\", \"-u\", NULL, NULL};\n+\n+\tpath_option = unsorted_string_list_lookup(&config_name_for_path, path);\n+\tif (!path_option)\n+\t\treturn 0;\n+\n+\tname = path_option->util;\n+\n+\tstrbuf_addf(&buf, \"%s/modules/%s\", resolve_gitdir(get_git_dir()), name);\n+\treal_git_dir = resolve_gitdir(buf.buf);\n+\tif (!real_git_dir)\n+\t\tgoto out;\n+\tconnect_work_tree_and_git_dir(path, real_git_dir);\n+\n+\t/* Run read-tree --reset sha1 */\n+\tmemset(&cp, 0, sizeof(cp));\n+\tcp.argv = argv;\n+\tcp.env = local_repo_env;\n+\tcp.git_cmd = 1;\n+\tcp.no_stdin = 1;\n+\tcp.dir = path;\n+\targv[3] = sha1_to_hex(sha1);\n+\tif (run_command(&cp))\n+\t\twarning(_(\"Checking out submodule %s failed\"), path);\n+\n+out:\n+\tstrbuf_release(&buf);\n+\treturn 0;\n+}\n+\n int depopulate_submodule(const char *path)\n {\n \tstruct strbuf dot_git = STRBUF_INIT;\n@@ -1242,6 +1278,7 @@ void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir)\n {\n \tstruct strbuf file_name = STRBUF_INIT;\n \tstruct strbuf rel_path = STRBUF_INIT;\n+\tconst char *real_git_dir = xstrdup(real_path(git_dir));\n \tconst char *real_work_tree = xstrdup(real_path(work_tree));\n \tFILE *fp;\n\n@@ -1250,15 +1287,15 @@ void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir)\n \tfp = fopen(file_name.buf, \"w\");\n \tif (!fp)\n \t\tdie(_(\"Could not create git link %s\"), file_name.buf);\n-\tfprintf(fp, \"gitdir: %s\\n\", relative_path(git_dir, real_work_tree,\n+\tfprintf(fp, \"gitdir: %s\\n\", relative_path(real_git_dir, real_work_tree,\n \t\t\t\t\t\t  &rel_path));\n \tfclose(fp);\n\n \t/* Update core.worktree setting */\n \tstrbuf_reset(&file_name);\n-\tstrbuf_addf(&file_name, \"%s/config\", git_dir);\n+\tstrbuf_addf(&file_name, \"%s/config\", real_git_dir);\n \tif (git_config_set_in_file(file_name.buf, \"core.worktree\",\n-\t\t\t\t   relative_path(real_work_tree, git_dir,\n+\t\t\t\t   relative_path(real_work_tree, real_git_dir,\n \t\t\t\t\t\t &rel_path)))\n \t\tdie(_(\"Could not set core.worktree in %s\"),\n \t\t    file_name.buf);\n@@ -1266,4 +1303,5 @@ void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir)\n \tstrbuf_release(&file_name);\n \tstrbuf_release(&rel_path);\n \tfree((void *)real_work_tree);\n+\tfree((void *)real_git_dir);\n }\ndiff --git a/submodule.h b/submodule.h\nindex 2139e08..a7d09a5 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -28,6 +28,7 @@ int parse_update_recurse_submodules_arg(const char *opt, const char *arg);\n int option_parse_update_submodules(const struct option *opt,\n \t\tconst char *arg, int unset);\n int submodule_needs_update(const char *path);\n+int populate_submodule(const char *path, unsigned char sha1[20], int force);\n int depopulate_submodule(const char *path);\n void show_submodule_summary(FILE *f, const char *path,\n \t\tconst char *line_prefix,\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 82c99eb..49d0a67 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1371,6 +1371,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,\n \t\t\t      struct unpack_trees_options *o)\n {\n \tconst struct cache_entry *result;\n+\tchar *name_copy, *separator;\n\n \t/*\n \t * It may be that the 'lstat()' succeeded even though\n@@ -1413,6 +1414,24 @@ static int check_ok_to_remove(const char *name, int len, int dtype,\n \t\t\treturn 0;\n \t}\n\n+\t/*\n+\t * If the path lies inside a to be added submodule it\n+\t * is ok to remove it.\n+\t */\n+\tname_copy = xstrdup(name);\n+\twhile ((separator = strrchr(name_copy, '/'))) {\n+\t\tint i;\n+\t\t*separator = '\\0';\n+\t\tfor (i = 0; i < the_index.cache_nr; i++) {\n+\t\t\tstruct cache_entry *ce = the_index.cache[i];\n+\t\t\tif (!strcmp(ce->name, name_copy) && S_ISGITLINK(ce->ce_mode)) {\n+\t\t\t\tfree(name_copy);\n+\t\t\t\treturn 0;\n+\t\t\t}\n+\t\t}\n+\t}\n+\tfree(name_copy);\n+\n \treturn o->gently ? -1 :\n \t\tadd_rejected_path(o, error_type, name);\n }\n-- \n1.9.rc0.28.ge3363ff\n"},{"id":"234141","messageId":"52EFF3E9.2060403@web.de","threadId":"35619","inReplyTo":"52EFF25E.6080306@web.de","subject":"[WIP/PATCH 9/9] submodule: teach unpack_trees() to update submodules","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-03T19:54:17Z","receivedAt":"2014-02-03T19:54:17Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Implement the functionality needed to enable work tree manipulating\ncommands so that an changed submodule does not only affect the index but\nit also updates the work tree of any initialized submodule according to\nthe SHA-1 recorded in the superproject.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n entry.c        | 15 ++++++++--\n submodule.c    | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n submodule.h    |  3 ++\n unpack-trees.c | 69 ++++++++++++++++++++++++++++++++++++----------\n unpack-trees.h |  1 +\n 5 files changed, 157 insertions(+), 17 deletions(-)\n\ndiff --git a/entry.c b/entry.c\nindex d1bf6ec..61a2767 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -265,7 +265,7 @@ int checkout_entry(struct cache_entry *ce,\n\n \tif (!check_path(path, len, &st, state->base_dir_len)) {\n \t\tunsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);\n-\t\tif (!changed)\n+\t\tif (!changed && (!S_ISDIR(st.st_mode) || !S_ISGITLINK(ce->ce_mode)))\n \t\t\treturn 0;\n \t\tif (!state->force) {\n \t\t\tif (!state->quiet)\n@@ -280,9 +280,18 @@ int checkout_entry(struct cache_entry *ce,\n \t\t * just do the right thing)\n \t\t */\n \t\tif (S_ISDIR(st.st_mode)) {\n-\t\t\t/* If it is a gitlink, leave it alone! */\n-\t\t\tif (S_ISGITLINK(ce->ce_mode))\n+\t\t\tif (S_ISGITLINK(ce->ce_mode)) {\n+\t\t\t\tif (submodule_needs_update(ce->name)) {\n+\t\t\t\t\tif (is_submodule_populated(ce->name)) {\n+\t\t\t\t\t\tif (update_submodule(ce->name, ce->sha1, state->force))\n+\t\t\t\t\t\t\treturn error(\"cannot checkout submodule %s\", path);\n+\t\t\t\t\t} else {\n+\t\t\t\t\t\tif (populate_submodule(path, ce->sha1, state->force))\n+\t\t\t\t\t\t\treturn error(\"cannot populate submodule %s\", path);\n+\t\t\t\t\t}\n+\t\t\t\t}\n \t\t\t\treturn 0;\n+\t\t\t}\n \t\t\tif (!state->force)\n \t\t\t\treturn error(\"%s is a directory\", path);\n \t\t\tremove_subtree(path);\ndiff --git a/submodule.c b/submodule.c\nindex 3907034..83e7595 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -520,6 +520,42 @@ int depopulate_submodule(const char *path)\n \treturn 0;\n }\n\n+int update_submodule(const char *path, const unsigned char sha1[20], int force)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tstruct child_process cp;\n+\tconst char *hex_sha1 = sha1_to_hex(sha1);\n+\tconst char *argv[] = {\n+\t\t\"checkout\",\n+\t\tforce ? \"-fq\" : \"-q\",\n+\t\thex_sha1,\n+\t\tNULL,\n+\t};\n+\tconst char *git_dir;\n+\n+\tstrbuf_addf(&buf, \"%s/.git\", path);\n+\tgit_dir = read_gitfile(buf.buf);\n+\tif (!git_dir)\n+\t\tgit_dir = buf.buf;\n+\tif (!is_directory(git_dir)) {\n+\t\tstrbuf_release(&buf);\n+\t\t/* The submodule is not populated, so we can't check it out */\n+\t\treturn 0;\n+\t}\n+\tstrbuf_release(&buf);\n+\n+\tmemset(&cp, 0, sizeof(cp));\n+\tcp.argv = argv;\n+\tcp.env = local_repo_env;\n+\tcp.git_cmd = 1;\n+\tcp.no_stdin = 1;\n+\tcp.dir = path;   /* GIT_WORK_TREE doesn't work for git checkout */\n+\tif (run_command(&cp))\n+\t\treturn error(\"Could not checkout submodule %s\", path);\n+\n+\treturn 0;\n+}\n+\n void show_submodule_summary(FILE *f, const char *path,\n \t\tconst char *line_prefix,\n \t\tunsigned char one[20], unsigned char two[20],\n@@ -961,6 +997,17 @@ out:\n \treturn result;\n }\n\n+int is_submodule_populated(const char *path)\n+{\n+\tint retval = 0;\n+\tstruct strbuf gitdir = STRBUF_INIT;\n+\tstrbuf_addf(&gitdir, \"%s/.git\", path);\n+\tif (resolve_gitdir(gitdir.buf))\n+\t\tretval = 1;\n+\tstrbuf_release(&gitdir);\n+\treturn retval;\n+}\n+\n unsigned is_submodule_modified(const char *path, int ignore_untracked)\n {\n \tssize_t len;\n@@ -1110,6 +1157,45 @@ int ok_to_remove_submodule(const char *path)\n \treturn ok_to_remove;\n }\n\n+unsigned is_submodule_checkout_safe(const char *path, const unsigned char sha1[20])\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tstruct child_process cp;\n+\tconst char *hex_sha1 = sha1_to_hex(sha1);\n+\tconst char *argv[] = {\n+\t\t\"read-tree\",\n+\t\t\"-n\",\n+\t\t\"-m\",\n+\t\t\"HEAD\",\n+\t\thex_sha1,\n+\t\tNULL,\n+\t};\n+\tconst char *git_dir;\n+\n+\tstrbuf_addf(&buf, \"%s/.git\", path);\n+\tgit_dir = read_gitfile(buf.buf);\n+\tif (!git_dir)\n+\t\tgit_dir = buf.buf;\n+\tif (!is_directory(git_dir)) {\n+\t\tstrbuf_release(&buf);\n+\t\t/* The submodule is not populated, it's safe to check it out */\n+\t\t/*\n+\t\t * TODO: When git learns to re-populate submodules, a check must be\n+\t\t * added here to assert that no local files will be overwritten.\n+\t\t */\n+\t\treturn 1;\n+\t}\n+\tstrbuf_release(&buf);\n+\n+\tmemset(&cp, 0, sizeof(cp));\n+\tcp.argv = argv;\n+\tcp.env = local_repo_env;\n+\tcp.git_cmd = 1;\n+\tcp.no_stdin = 1;\n+\tcp.dir = path;\n+\treturn run_command(&cp) == 0;\n+}\n+\n static int find_first_merges(struct object_array *result, const char *path,\n \t\tstruct commit *a, struct commit *b)\n {\ndiff --git a/submodule.h b/submodule.h\nindex a7d09a5..65f6396 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -30,6 +30,7 @@ int option_parse_update_submodules(const struct option *opt,\n int submodule_needs_update(const char *path);\n int populate_submodule(const char *path, unsigned char sha1[20], int force);\n int depopulate_submodule(const char *path);\n+int update_submodule(const char *path, const unsigned char sha1[20], int force);\n void show_submodule_summary(FILE *f, const char *path,\n \t\tconst char *line_prefix,\n \t\tunsigned char one[20], unsigned char two[20],\n@@ -41,9 +42,11 @@ void check_for_new_submodule_commits(unsigned char new_sha1[20]);\n int fetch_populated_submodules(const struct argv_array *options,\n \t\t\t       const char *prefix, int command_line_option,\n \t\t\t       int quiet);\n+int is_submodule_populated(const char *path);\n unsigned is_submodule_modified(const char *path, int ignore_untracked);\n int submodule_uses_gitfile(const char *path);\n int ok_to_remove_submodule(const char *path);\n+unsigned is_submodule_checkout_safe(const char *path, const unsigned char sha1[20]);\n int merge_submodule(unsigned char result[20], const char *path, const unsigned char base[20],\n \t\t    const unsigned char a[20], const unsigned char b[20], int search);\n int find_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_name,\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 49d0a67..46b85ac 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -27,6 +27,9 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {\n \t/* ERROR_NOT_UPTODATE_DIR */\n \t\"Updating '%s' would lose untracked files in it\",\n\n+\t/* ERROR_NOT_UPTODATE_SUBMODULE */\n+\t\"Updating submodule '%s' would lose modifications in it\",\n+\n \t/* ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN */\n \t\"Untracked working tree file '%s' would be overwritten by merge.\",\n\n@@ -71,6 +74,8 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,\n\n \tmsgs[ERROR_NOT_UPTODATE_DIR] =\n \t\t\"Updating the following directories would lose untracked files in it:\\n%s\";\n+\tmsgs[ERROR_NOT_UPTODATE_SUBMODULE] =\n+\t\t\"Updating the following submodules would lose modifications in it:\\n%s\";\n\n \tif (advice_commit_before_merge)\n \t\tmsg = \"The following untracked working tree files would be %s by %s:\\n%%s\"\n@@ -1224,17 +1229,15 @@ static int verify_uptodate_1(const struct cache_entry *ce,\n \tif (!lstat(ce->name, &st)) {\n \t\tint flags = CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE;\n \t\tunsigned changed = ie_match_stat(o->src_index, ce, &st, flags);\n-\t\tif (!changed)\n-\t\t\treturn 0;\n-\t\t/*\n-\t\t * NEEDSWORK: the current default policy is to allow\n-\t\t * submodule to be out of sync wrt the superproject\n-\t\t * index.  This needs to be tightened later for\n-\t\t * submodules that are marked to be automatically\n-\t\t * checked out.\n-\t\t */\n-\t\tif (S_ISGITLINK(ce->ce_mode))\n-\t\t\treturn 0;\n+\t\tif (!changed) {\n+\t\t\tif (!S_ISGITLINK(ce->ce_mode) || !submodule_needs_update(ce->name) ||\n+\t\t\t    (ce_stage(ce) ? is_submodule_checkout_safe(ce->name, ce->sha1)\n+\t\t\t    : !is_submodule_modified(ce->name, 1)))\n+\t\t\t\treturn 0;\n+\t\t} else\n+\t\t\tif (S_ISGITLINK(ce->ce_mode) && !submodule_needs_update(ce->name))\n+\t\t\t\treturn 0;\n+\n \t\terrno = 0;\n \t}\n \tif (errno == ENOENT)\n@@ -1257,6 +1260,36 @@ static int verify_uptodate_sparse(const struct cache_entry *ce,\n \treturn verify_uptodate_1(ce, o, ERROR_SPARSE_NOT_UPTODATE_FILE);\n }\n\n+/*\n+ * When a submodule gets turned into an unmerged entry, we want it to be\n+ * up-to-date regarding the merge changes.\n+ */\n+static int verify_uptodate_submodule(const struct cache_entry *old,\n+\t\t\t\t     const struct cache_entry *new,\n+\t\t\t\t     struct unpack_trees_options *o)\n+{\n+\tstruct stat st;\n+\n+\tif (o->index_only || (!((old->ce_flags & CE_VALID) || ce_skip_worktree(old)) && (o->reset || ce_uptodate(old))))\n+\t\treturn 0;\n+\tif (!lstat(old->name, &st)) {\n+\t\tunsigned changed = ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);\n+\t\tif (!changed) {\n+\t\t\tif (!S_ISGITLINK(old->ce_mode) ||\n+\t\t\t    !submodule_needs_update(new->name) ||\n+\t\t\t    is_submodule_checkout_safe(new->name, new->sha1))\n+\t\t\t\treturn 0;\n+\t\t} else\n+\t\t\tif (S_ISGITLINK(old->ce_mode) && !submodule_needs_update(new->name))\n+\t\t\t\treturn 0;\n+\t\terrno = 0;\n+\t}\n+\tif (errno == ENOENT)\n+\t\treturn 0;\n+\treturn o->gently ? -1 :\n+\t\tadd_rejected_path(o, ERROR_NOT_UPTODATE_SUBMODULE, old->name);\n+}\n+\n static void invalidate_ce_path(const struct cache_entry *ce,\n \t\t\t       struct unpack_trees_options *o)\n {\n@@ -1536,9 +1569,17 @@ static int merged_entry(const struct cache_entry *ce,\n \t\t\tcopy_cache_entry(merge, old);\n \t\t\tupdate = 0;\n \t\t} else {\n-\t\t\tif (verify_uptodate(old, o)) {\n-\t\t\t\tfree(merge);\n-\t\t\t\treturn -1;\n+\t\t\tif (S_ISGITLINK(old->ce_mode) ||\n+\t\t\t    S_ISGITLINK(merge->ce_mode)) {\n+\t\t\t\tif (verify_uptodate_submodule(old, merge, o)) {\n+\t\t\t\t\tfree(merge);\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\tif (verify_uptodate(old, o)) {\n+\t\t\t\t\tfree(merge);\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n \t\t\t}\n \t\t\t/* Migrate old flags over */\n \t\t\tupdate |= old->ce_flags & (CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE);\ndiff --git a/unpack-trees.h b/unpack-trees.h\nindex 36a73a6..bee8740 100644\n--- a/unpack-trees.h\n+++ b/unpack-trees.h\n@@ -15,6 +15,7 @@ enum unpack_trees_error_types {\n \tERROR_WOULD_OVERWRITE = 0,\n \tERROR_NOT_UPTODATE_FILE,\n \tERROR_NOT_UPTODATE_DIR,\n+\tERROR_NOT_UPTODATE_SUBMODULE,\n \tERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN,\n \tERROR_WOULD_LOSE_UNTRACKED_REMOVED,\n \tERROR_BIND_OVERLAP,\n-- \n1.9.rc0.28.ge3363ff\n"},{"id":"234144","messageId":"20140203200435.GA16057@odin.tremily.us","threadId":"35619","inReplyTo":"52EFF35D.7070908@web.de","subject":"Re: [WIP/PATCH 6/9] Teach bisect the --[no-]recurse-submodules option","fromName":"W. Trevor King","fromEmail":"wking@tremily.us","sentAt":"2014-02-03T20:04:35Z","receivedAt":"2014-02-03T20:04:35Z","isPatch":true,"sender":{"key":"wking@tremily.us","avatar":"https://avatars.githubusercontent.com/u/209920?v=4"},"body":"On Mon, Feb 03, 2014 at 08:51:57PM +0100, Jens Lehmann wrote:\n> submodule update' eacht time obsolete, which was tedious and error prone.\n                    ^ each\n\nI'm just reading the commit messages this pass ;).\n\nCheers,\nTrevor\n\n-- \nThis email may be signed or encrypted with GnuPG (http://www.gnupg.org).\nFor more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy\n"},{"id":"234146","messageId":"20140203201052.GB16057@odin.tremily.us","threadId":"35619","inReplyTo":"52EFF391.7040503@web.de","subject":"Re: [WIP/PATCH 7/9] submodule: teach unpack_trees() to remove submodule contents","fromName":"W. Trevor King","fromEmail":"wking@tremily.us","sentAt":"2014-02-03T20:10:52Z","receivedAt":"2014-02-03T20:10:52Z","isPatch":true,"sender":{"key":"wking@tremily.us","avatar":"https://avatars.githubusercontent.com/u/209920?v=4"},"body":"On Mon, Feb 03, 2014 at 08:52:49PM +0100, Jens Lehmann wrote:\n> Implement the functionality needed to enable work tree manipulating\n> commands to that a deleted submodule should not only affect the index\n> (leaving all the files of the submodule in the work tree) but also to\n> remove the work tree of the superproject (including any untracked\n> files).\n> \n> That will only work properly when the submodule uses a gitfile instead of\n> a .git directory and no untracked files are present. Otherwise the removal\n> will fail with a warning (which is just what happened until now).\n\nI'm having trouble parsing this one.  How about:\n\n  Add a depopulate_submodule helper which removes the submodule\n  working directory without touching the index.  This will only work\n  properly when the submodule uses a gitfile…\n\nCheers,\nTrevor\n\n-- \nThis email may be signed or encrypted with GnuPG (http://www.gnupg.org).\nFor more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy\n"},{"id":"234148","messageId":"20140203201900.GC16057@odin.tremily.us","threadId":"35619","inReplyTo":"52EFF3E9.2060403@web.de","subject":"Re: [WIP/PATCH 9/9] submodule: teach unpack_trees() to update submodules","fromName":"W. Trevor King","fromEmail":"wking@tremily.us","sentAt":"2014-02-03T20:19:00Z","receivedAt":"2014-02-03T20:19:00Z","isPatch":true,"sender":{"key":"wking@tremily.us","avatar":"https://avatars.githubusercontent.com/u/209920?v=4"},"body":"On Mon, Feb 03, 2014 at 08:54:17PM +0100, Jens Lehmann wrote:\n> Implement the functionality needed to enable work tree manipulating\n> commands so that an changed submodule does not only affect the index but\n> it also updates the work tree of any initialized submodule according to\n> the SHA-1 recorded in the superproject.\n\nHow about:\n\n  …so that *a* changed submodule ** updates the index and work tree of\n  any initialized submodule according to the SHA-1 recorded in the\n  superproject.  Before this commit it updated neither; users had to\n  run 'submodule update' to propagate gitlink updates into the\n  submodule.\n\nI'm pretty sure that's accurate anyway ;).\n\nCheers,\nTrevor\n\n-- \nThis email may be signed or encrypted with GnuPG (http://www.gnupg.org).\nFor more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy\n"},{"id":"234150","messageId":"52EFFA74.4040605@web.de","threadId":"35619","inReplyTo":"20140203200435.GA16057@odin.tremily.us","subject":"Re: [WIP/PATCH 6/9] Teach bisect the --[no-]recurse-submodules option","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-03T20:22:12Z","receivedAt":"2014-02-03T20:22:12Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 03.02.2014 21:04, schrieb W. Trevor King:\n> On Mon, Feb 03, 2014 at 08:51:57PM +0100, Jens Lehmann wrote:\n>> submodule update' eacht time obsolete, which was tedious and error prone.\n>                     ^ each\n> \n> I'm just reading the commit messages this pass ;).\n\nFair enough ;-)\n"},{"id":"234157","messageId":"xmqqha8fdeek.fsf@gitster.dls.corp.google.com","threadId":"35619","inReplyTo":"52EFF290.5090501@web.de","subject":"Re: [WIP/PATCH 1/9] submodule: prepare for recursive checkout of submodules","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-02-03T22:23:15Z","receivedAt":"2014-02-03T22:23:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jens Lehmann <Jens.Lehmann@web.de> writes:\n\n> This commit adds the functions and files needed for configuration,\n\nPlease just say \"Add the functions and files needed for ...\".\n\n> +++ b/Documentation/recurse-submodules-update.txt\n> @@ -0,0 +1,8 @@\n> +--[no-]recurse-submodules::\n> +\tUsing --recurse-submodules will update the work tree of all\n> +\tinitialized submodules according to the commit recorded in the\n> +\tsuperproject if their update configuration is set to checkout'. If\n\nThat single quote does not seem to be closing any matching quote.\n\nThe phrase \"according to\" feels a bit too fuzzy.  Merging the commit\nto what is checked out is one possible implementation of \"according to\".\nApplying the diff between the commit and what is checked out to work\ntree is another.  Resetting the work tree files to exactly match the\ncommit would be yet another.\n\nI think \"update the work trees to the commit\" (i.e. lose the\n\"according\") would be the closest to what you are trying to say\nhere.\n\n> +\tlocal modifications in a submodule would be overwritten the checkout\n> +\twill fail unless forced. Without this option or with\n> +\t--no-recurse-submodules is, the work trees of submodules will not be\n> +\tupdated, only the hash recorded in the superproject will be updated.\n\nIt is unclear what happens if their update configuration is set to\nsomething other than 'checkout'.\n\n> diff --git a/submodule.c b/submodule.c\n> index 613857e..b3eb28d 100644\n> --- a/submodule.c\n> +++ b/submodule.c\n> @@ -382,6 +384,48 @@ int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)\n> ...\n> +int option_parse_update_submodules(const struct option *opt,\n> +\t\t\t\t   const char *arg, int unset)\n> +{\n> +\tif (unset) {\n> +\t\t*(int *)opt->value = RECURSE_SUBMODULES_OFF;\n> +\t} else {\n> +\t\tif (arg)\n> +\t\t\t*(int *)opt->value = parse_update_recurse_submodules_arg(opt->long_name, arg);\n> +\t\telse\n> +\t\t\t*(int *)opt->value = RECURSE_SUBMODULES_ON;\n> +\t}\n\nYou can easily unnest to lose {}\n\n    if (unset)\n            value = off;\n    else if (arg)\n            value = parse...;\n    else\n            value = on;\n\nAlso I suspect that git_config_maybe_bool() natively knows how to\nhandle arg==NULL, so\n\n    if (unset)\n\tvalue = off;\n    else\n\tvalue = parse...;\n\nis sufficient?\n"},{"id":"234158","messageId":"xmqqd2j3ddlw.fsf@gitster.dls.corp.google.com","threadId":"35619","inReplyTo":"52EFF2C5.3090705@web.de","subject":"Re: [WIP/PATCH 2/9] Teach reset the --[no-]recurse-submodules option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-02-03T22:40:27Z","receivedAt":"2014-02-03T22:40:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jens Lehmann <Jens.Lehmann@web.de> writes:\n\n> This new option will allow the user to not only reset the work tree of\n> the superproject but to also update the work tree of all initialized\n> submodules (so they match the SHA-1 recorded in the superproject) when\n> used together with --hard or --merge. But this commit only adds the\n\nI agree that --soft and --mixed should not do anything.  I am not\nsure why --keep should not do anything to submodule working trees\nwhen asked to recurse, though.\n\n> option without any functionality, that will be added to unpack_trees()\n> in subsequent commits.\n>\n> Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n> ---\n>  Documentation/git-reset.txt |  4 ++++\n>  builtin/reset.c             | 14 ++++++++++++++\n>  2 files changed, 18 insertions(+)\n>\n> diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt\n> index f445cb3..8f833f4 100644\n> --- a/Documentation/git-reset.txt\n> +++ b/Documentation/git-reset.txt\n> @@ -94,6 +94,10 @@ OPTIONS\n>  --quiet::\n>  \tBe quiet, only report errors.\n>\n> +include::recurse-submodules-update.txt[]\n> ++\n> +This option only makes sense together with `--hard` and `--merge` and is\n> +ignored when used without these options.\n>\n>  EXAMPLES\n>  --------\n> diff --git a/builtin/reset.c b/builtin/reset.c\n> index 6004803..adf372e 100644\n> --- a/builtin/reset.c\n> +++ b/builtin/reset.c\n> @@ -20,6 +20,7 @@\n>  #include \"parse-options.h\"\n>  #include \"unpack-trees.h\"\n>  #include \"cache-tree.h\"\n> +#include \"submodule.h\"\n>\n>  static const char * const git_reset_usage[] = {\n>  \tN_(\"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]\"),\n> @@ -255,6 +256,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n>  {\n>  \tint reset_type = NONE, update_ref_status = 0, quiet = 0;\n>  \tint patch_mode = 0, unborn;\n> +\tconst char *recurse_submodules_default = \"off\";\n> +\tint recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n>  \tconst char *rev;\n>  \tunsigned char sha1[20];\n>  \tstruct pathspec pathspec;\n> @@ -270,13 +273,24 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n>  \t\tOPT_SET_INT(0, \"keep\", &reset_type,\n>  \t\t\t\tN_(\"reset HEAD but keep local changes\"), KEEP),\n>  \t\tOPT_BOOL('p', \"patch\", &patch_mode, N_(\"select hunks interactively\")),\n> +\t\t{ OPTION_CALLBACK, 0, \"recurse-submodules\", &recurse_submodules,\n> +\t\t\t\"checkout\", \"control recursive updating of submodules\",\n> +\t\t\tPARSE_OPT_OPTARG, option_parse_update_submodules },\n> +\t\t{ OPTION_STRING, 0, \"recurse-submodules-default\",\n> +\t\t\t&recurse_submodules_default, NULL,\n> +\t\t\t\"default mode for recursion\", PARSE_OPT_HIDDEN },\n>  \t\tOPT_END()\n>  \t};\n>\n> +\tgitmodules_config();\n>  \tgit_config(git_default_config, NULL);\n>\n>  \targc = parse_options(argc, argv, prefix, options, git_reset_usage,\n>  \t\t\t\t\t\tPARSE_OPT_KEEP_DASHDASH);\n> +\tset_config_update_recurse_submodules(\n> +\t\tparse_update_recurse_submodules_arg(\"--recurse-submodules-default\",\n> +\t\t\t\t\t\t    recurse_submodules_default),\n> +\t\trecurse_submodules);\n>  \tparse_args(&pathspec, argv, prefix, patch_mode, &rev);\n>\n>  \tunborn = !strcmp(rev, \"HEAD\") && get_sha1(\"HEAD\", sha1);\n"},{"id":"234164","messageId":"xmqq8utrdcuh.fsf@gitster.dls.corp.google.com","threadId":"35619","inReplyTo":"52EFF2EA.9060709@web.de","subject":"Re: [WIP/PATCH 3/9] Teach checkout the --[no-]recurse-submodules option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-02-03T22:56:54Z","receivedAt":"2014-02-03T22:56:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jens Lehmann <Jens.Lehmann@web.de> writes:\n\n> +\tset_config_update_recurse_submodules(\n> +\t\tparse_update_recurse_submodules_arg(\"--recurse-submodules-default\",\n> +\t\t\t\t\t\t    recurse_submodules_default),\n> +\t\trecurse_submodules);\n\nI think I saw these exact lines in another patch.  Perhaps the whole\nthing can become a helper function that lets the caller avoid typing\nthe whole long strings that needs a strange/unfortunate line break? \n\n> diff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh\n> index 06b18f8..bc3e1ca 100755\n> --- a/t/t2013-checkout-submodule.sh\n> +++ b/t/t2013-checkout-submodule.sh\n> @@ -4,17 +4,57 @@ test_description='checkout can handle submodules'\n>\n>  . ./test-lib.sh\n>\n> +submodule_creation_must_succeed() {\n\nStyle: SP before (), i.e.\n\n\tsubmodule_creation_must_succeed () {\n\n> +\t# checkout base ($1)\n> +\tgit checkout -f --recurse-submodules $1 &&\n> +\tgit diff-files --quiet &&\n> +\tgit diff-index --quiet --cached $1 &&\n\nPlease make it a habit to quote a parameter that is intended not to\nbe split at $IFS (e.g. write these as \"$1\" not as $1).  Otherwise\nthe reader has to wonder if this can be called with a \"foo bar\" and\nthe expects it to be split into two.\n\n> +\t# checkout target ($2)\n> +\tif test -d submodule; then\n\nStyle: no semicolons in standard control structure, i.e.\n\n\tif test -d submodule\n\tthen\n\n> +\t\techo change>>submodule/first.t &&\n\nStyle: SP before but not after redirection operator, i.e.\n\n\techo foo >>bar\n\n> +submodule_removal_must_succeed() {\n\nLikewise.\n\n> +\t# checkout base ($1)\n> +\tgit checkout -f --recurse-submodules $1 &&\n\nLikewise.\n\n> +\techo first > file &&\n\nLikewise.\n\n> +test_expect_success '\"checkout --recurse-submodules\" replaces submodule with files' '\n> +\tgit checkout -f base &&\n> +\tgit checkout -b replace_submodule_with_dir &&\n> +\tgit update-index --force-remove submodule &&\n> +\trm -rf submodule/.git .gitmodules &&\n> +\tgit add .gitmodules submodule/* &&\n> +\tgit commit -m \"submodule replaced\" &&\n> +\tgit checkout -f base &&\n> +\tgit submodule update -f &&\n> +\tgit checkout --recurse-submodules replace_submodule_with_dir &&\n> +\ttest -d submodule &&\n> +\t! test -e submodule/.git &&\n> +\ttest -f submodule/first.t &&\n> +\ttest -f submodule/second.t\n> +'\n\nHmmmm.  Is it sufficient for these files to just exist, or do we\nwant to make sure they have expected contents?\n\nThanks.\n"},{"id":"234165","messageId":"xmqq4n4fdcnd.fsf@gitster.dls.corp.google.com","threadId":"35619","inReplyTo":"52EFF311.1090202@web.de","subject":"Re: [WIP/PATCH 4/9] Teach merge the --[no-]recurse-submodules option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-02-03T23:01:10Z","receivedAt":"2014-02-03T23:01:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jens Lehmann <Jens.Lehmann@web.de> writes:\n\n> This new option will allow the user to not only update the work tree of\n> the superproject according to the merge result but to also update the\n> work tree of all initialized submodules (so they match the SHA-1 recorded\n> in the superproject). But this commit only adds the option without any\n> functionality, that will be added to unpack_trees() in subsequent commits.\n\nWhen the two branches of the superproject being merged wants to put\na submodule project to commit A and B, that conflict needs to be\nresolved, but if they agree that the submodule project should be at\nC (which is different from what the current superproject HEAD has\nfor the submodule in its gitlink), then we want a checkout of that\ncommit to happen in that submodule.  Makes sense.\n\nAfter resolving such a conflict between A and B, who is responsible\nto adjust the working tree state of the submodule involved, by the\nway?  \"git merge --continue\" does not exist and its moral equivalent\nto conclude such an interrupted merge is \"git commit\".  Should it\nlearn to do \"recurse-submodule\", or should the user run a separate\n\"checkout --recurse-submodule\"?\n"},{"id":"234176","messageId":"20140204000150.GJ30398@google.com","threadId":"35619","inReplyTo":"52EFF290.5090501@web.de","subject":"Re: [WIP/PATCH 1/9] submodule: prepare for recursive checkout of submodules","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2014-02-04T00:01:50Z","receivedAt":"2014-02-04T00:01:50Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Jens Lehmann wrote:\n\n> This commit adds the functions and files needed for configuration,\n> documentation, setting the default behavior and determining if a\n> submodule path should be updated automatically.\n\nYay!\n\n[...]\n>  Documentation/recurse-submodules-update.txt |  8 +++++\n>  submodule.c                                 | 50 +++++++++++++++++++++++++++++\n>  submodule.h                                 |  6 ++++\n>  3 files changed, 64 insertions(+)\n>  create mode 100644 Documentation/recurse-submodules-update.txt\n\nI like the shared documentation snippet.\n\nOk, naive questions and overly pedantic nitpicking follow.  Patch with\na couple of suggested changes at the end.\n\n[...]\n> --- /dev/null\n> +++ b/Documentation/recurse-submodules-update.txt\n> @@ -0,0 +1,8 @@\n> +--[no-]recurse-submodules::\n> +\tUsing --recurse-submodules will update the work tree of all\n> +\tinitialized submodules according to the commit recorded in the\n> +\tsuperproject if their update configuration is set to checkout'. If\n> +\tlocal modifications in a submodule would be overwritten the checkout\n> +\twill fail unless forced. Without this option or with\n> +\t--no-recurse-submodules is, the work trees of submodules will not be\n> +\tupdated, only the hash recorded in the superproject will be updated.\n\nTweaks:\n\n * Spelling out \"--no-recurse-submodules, --recurse-submodules\" (imitating\n   e.g. --decorate in git-log(1))\n\n * Shortening, using imperative mood\n \n * Skipping description of safety check, since it matches how checkout\n   works in general\n\nThat would make\n\n\t--no-recurse-submodules::\n\t--recurse-submodules::\n\t\tPerform the checkout in submodules, too.  This only affects\n\t\tsubmodules with update strategy `checkout` (which is the\n\t\tdefault update strategy; see `submodule.<name>.update` in\n\t\tlink:gitmodules[5]).\n\t+\n\tThe default behavior is to update submodule entries in the superproject\n\tindex and to leave the inside of submodules alone.  That behavior can also\n\tbe requested explicitly with --no-recurse-submodules.\n\nIdeas for further work:\n\n * The safety check probably deserves a new section where it could be\n   described in detail alongside a description of the corresponding check\n   for plain checkout.  Then the description of the -f option could\n   point to that section.\n\n * What happens when update = merge, rebase, or !command?  I think\n   skipping them for now like suggested above is fine, but:\n\n   - It would be even better to error out when there are changes to carry\n     over with update = merge or rebase\n\n   - Better still to perform the rebase when update = rebase\n\n   - I have no idea what update = merge should do for non-fast-forward\n     moves\n\n> --- a/submodule.c\n> +++ b/submodule.c\n> @@ -16,6 +16,8 @@ static struct string_list config_name_for_path;\n>  static struct string_list config_fetch_recurse_submodules_for_name;\n>  static struct string_list config_ignore_for_name;\n>  static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;\n> +static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;\n> +static int option_update_recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n\nConfusingly, config_update_recurse_submodules is set using the\n--recurse-submodules-default option, not configuration.  There's\nprecedent for that in fetch.recurseSubmodules handling, but perhaps\na comment would help --- something like\n\n\t/*\n\t * When no --recurse-submodules option was passed, should git fetch\n\t * from submodules where submodule.<name>.fetchRecurseSubmodules\n\t * doesn't indicate what to do?\n\t *\n\t * Controlled by fetch.recurseSubmodules.  The default is determined by\n\t * the --recurse-submodules-default option, which propagates\n\t * --recurse-submodules from the parent git process when recursing.\n\t */\n\tstatic int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;\n\n\t/*\n\t * When no --recurse-submodules option was passed, should git update\n\t * the index and worktree within submodules (and in turn their\n\t * submodules, etc)?\n\t *\n\t * Controlled by the --recurse-submodules-default option, which\n\t * propagates --recurse-submodules from the parent git process\n\t * when recursing.\n\t */\n\tstatic int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;\n\n[...]\n> @@ -382,6 +384,48 @@ int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)\n>  \t}\n>  }\n> \n> +int parse_update_recurse_submodules_arg(const char *opt, const char *arg)\n> +{\n> +\tswitch (git_config_maybe_bool(opt, arg)) {\n> +\tcase 1:\n> +\t\treturn RECURSE_SUBMODULES_ON;\n> +\tcase 0:\n> +\t\treturn RECURSE_SUBMODULES_OFF;\n> +\tdefault:\n> +\t\tif (!strcmp(arg, \"checkout\"))\n> +\t\t\treturn RECURSE_SUBMODULES_ON;\n\nHm, is this arg == checkout case futureproofing for when\n--recurse-submodules learns to handle submodules without\n'update = checkout', too?\n\nIs it safe to leave it out for now?\n\n[...]\n> +int submodule_needs_update(const char *path)\n\nReturn value convention: 1 means \"do update\"; 0 means \"don't update\".\n\nSome day later I suppose 2 or -1 could mean \"error out\".  Ok.\n\nNaming nit: needs_update sounds like it's checking if there was a\nchange at that path.  How about something like submodule_should_update(),\n!submodule_ignore_for_update(), or update_should_recurse_into_submodule()?\n\n[...]\n> @@ -589,6 +633,12 @@ int push_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_nam\n>  \treturn ret;\n>  }\n> \n> +void set_config_update_recurse_submodules(int default_value, int option_value)\n> +{\n> +\tconfig_update_recurse_submodules = default_value;\n> +\toption_update_recurse_submodules = option_value;\n> +}\n\nCould option_parse_update_submodules set\noption_update_recurse_submodules directly?  Alternatively, could this\nfunction examine option_value so that submodule.c would only need one\nvariable?\n\n\tif (option_value == RECURSE_SUBMODULES_DEFAULT)\n\t\tupdate_recurse_submodules = default_value;\n\telse\n\t\tupdate_recurse_submodules = option_value;\n\nIf .gitmodules some day grows a submodule.<name>.checkoutRecurseSubmodules\noption then it would be convenient to have the option that overrides and\nthe default tracked separately.  Is that the idea here?\n\nI might try writing a dummy command to test this basic --recurse-submodules\noption handling as a separate patch.\n\nThanks,\nJonathan\n\ndiff --git i/Documentation/recurse-submodules-update.txt w/Documentation/recurse-submodules-update.txt\nindex e57d452..eae376d 100644\n--- i/Documentation/recurse-submodules-update.txt\n+++ w/Documentation/recurse-submodules-update.txt\n@@ -1,8 +1,10 @@\n---[no-]recurse-submodules::\n-\tUsing --recurse-submodules will update the work tree of all\n-\tinitialized submodules according to the commit recorded in the\n-\tsuperproject if their update configuration is set to checkout'. If\n-\tlocal modifications in a submodule would be overwritten the checkout\n-\twill fail unless forced. Without this option or with\n-\t--no-recurse-submodules is, the work trees of submodules will not be\n-\tupdated, only the hash recorded in the superproject will be updated.\n+--no-recurse-submodules::\n+--recurse-submodules::\n+\tPerform the checkout in submodules, too.  This only affects\n+\tsubmodules with update strategy `checkout` (which is the\n+\tdefault update strategy; see `submodule.<name>.update` in\n+\tlinkgit:gitmodules[5]).\n++\n+The default behavior is to update submodule entries in the superproject\n+index and to leave the inside of submodules alone.  That behavior can\n+also be requested explicitly with `--no-recurse-submodules`.\ndiff --git i/submodule.c w/submodule.c\nindex b3eb28d..f88bf70 100644\n--- i/submodule.c\n+++ w/submodule.c\n@@ -12,11 +12,30 @@\n #include \"argv-array.h\"\n #include \"blob.h\"\n \n+/*\n+ * When no --recurse-submodules option was passed, should git fetch\n+ * from submodules where submodule.<name>.fetchRecurseSubmodules doesn't\n+ * indicate what to do?\n+ *\n+ * Controlled by fetch.recurseSubmodules.  The default is determined by\n+ * the --recurse-submodules-default option, which propagates\n+ * --recurse-submodules from the parent git process when recursing.\n+ */\n+static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;\n+\n+/*\n+ * When no --recurse-submodules option was passed, should git update the\n+ * index and worktree within submodules (and in turn their submodules,\n+ * etc)?\n+ *\n+ * Controlled by the --recurse-submodules-default option, which propagates\n+ * --recurse-submodules from the parent git process when recursing.\n+ */\n+static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;\n+\n static struct string_list config_name_for_path;\n static struct string_list config_fetch_recurse_submodules_for_name;\n static struct string_list config_ignore_for_name;\n-static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;\n-static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;\n static int option_update_recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n static struct string_list changed_submodule_paths;\n static int initialized_fetch_ref_tips;\n@@ -392,8 +411,6 @@ int parse_update_recurse_submodules_arg(const char *opt, const char *arg)\n \tcase 0:\n \t\treturn RECURSE_SUBMODULES_OFF;\n \tdefault:\n-\t\tif (!strcmp(arg, \"checkout\"))\n-\t\t\treturn RECURSE_SUBMODULES_ON;\n \t\tdie(\"bad %s argument: %s\", opt, arg);\n \t}\n }\n"},{"id":"234178","messageId":"CACsJy8CiAPnatithenDKBBKVGFHQZsu4mJLEjuWFD2GXqO56Lw@mail.gmail.com","threadId":"35619","inReplyTo":"52EFF3E9.2060403@web.de","subject":"Re: [WIP/PATCH 9/9] submodule: teach unpack_trees() to update submodules","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2014-02-04T00:11:32Z","receivedAt":"2014-02-04T00:11:32Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Feb 4, 2014 at 2:54 AM, Jens Lehmann <Jens.Lehmann@web.de> wrote:\n> Implement the functionality needed to enable work tree manipulating\n> commands so that an changed submodule does not only affect the index but\n> it also updates the work tree of any initialized submodule according to\n> the SHA-1 recorded in the superproject.\n>\n> Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n> ---\n>  entry.c        | 15 ++++++++--\n>  submodule.c    | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n>  submodule.h    |  3 ++\n>  unpack-trees.c | 69 ++++++++++++++++++++++++++++++++++++----------\n>  unpack-trees.h |  1 +\n>  5 files changed, 157 insertions(+), 17 deletions(-)\n>\n> diff --git a/entry.c b/entry.c\n> index d1bf6ec..61a2767 100644\n> --- a/entry.c\n> +++ b/entry.c\n> @@ -265,7 +265,7 @@ int checkout_entry(struct cache_entry *ce,\n>\n>         if (!check_path(path, len, &st, state->base_dir_len)) {\n>                 unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);\n> -               if (!changed)\n> +               if (!changed && (!S_ISDIR(st.st_mode) || !S_ISGITLINK(ce->ce_mode)))\n>                         return 0;\n\nShould we report something when ce is a gitlink, but path is not a\ndirectory, instead of siliently exit?\n\n> diff --git a/submodule.c b/submodule.c\n> index 3907034..83e7595 100644\n> --- a/submodule.c\n> +++ b/submodule.c\n> @@ -520,6 +520,42 @@ int depopulate_submodule(const char *path)\n>         return 0;\n>  }\n>\n> +int update_submodule(const char *path, const unsigned char sha1[20], int force)\n> +{\n> +       struct strbuf buf = STRBUF_INIT;\n> +       struct child_process cp;\n> +       const char *hex_sha1 = sha1_to_hex(sha1);\n> +       const char *argv[] = {\n> +               \"checkout\",\n> +               force ? \"-fq\" : \"-q\",\n\nrespect \"state->quiet\" in checkout_entry() as well?\n\n> +               hex_sha1,\n> +               NULL,\n> +       };\n> +       const char *git_dir;\n> +\n> +       strbuf_addf(&buf, \"%s/.git\", path);\n> +       git_dir = read_gitfile(buf.buf);\n> +       if (!git_dir)\n> +               git_dir = buf.buf;\n> +       if (!is_directory(git_dir)) {\n> +               strbuf_release(&buf);\n> +               /* The submodule is not populated, so we can't check it out */\n> +               return 0;\n> +       }\n> +       strbuf_release(&buf);\n> +\n> +       memset(&cp, 0, sizeof(cp));\n> +       cp.argv = argv;\n> +       cp.env = local_repo_env;\n> +       cp.git_cmd = 1;\n> +       cp.no_stdin = 1;\n> +       cp.dir = path;   /* GIT_WORK_TREE doesn't work for git checkout */\n\nAnd if we do respect --quiet and it's not specified, paths printed by\nthis process is relative to \"dir\", not to user cwd. Could be\nconfusing.\n\n> +       if (run_command(&cp))\n> +               return error(\"Could not checkout submodule %s\", path);\n> +\n> +       return 0;\n> +}\n> +\n-- \nDuy\n"},{"id":"234467","messageId":"52F549B1.7050305@web.de","threadId":"35619","inReplyTo":"20140204000150.GJ30398@google.com","subject":"Re: [WIP/PATCH 1/9] submodule: prepare for recursive checkout of submodules","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-07T21:01:37Z","receivedAt":"2014-02-07T21:01:37Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 04.02.2014 01:01, schrieb Jonathan Nieder:\n> Jens Lehmann wrote:\n>> --- /dev/null\n>> +++ b/Documentation/recurse-submodules-update.txt\n>> @@ -0,0 +1,8 @@\n>> +--[no-]recurse-submodules::\n>> +\tUsing --recurse-submodules will update the work tree of all\n>> +\tinitialized submodules according to the commit recorded in the\n>> +\tsuperproject if their update configuration is set to checkout'. If\n>> +\tlocal modifications in a submodule would be overwritten the checkout\n>> +\twill fail unless forced. Without this option or with\n>> +\t--no-recurse-submodules is, the work trees of submodules will not be\n>> +\tupdated, only the hash recorded in the superproject will be updated.\n> \n> Tweaks:\n> \n>  * Spelling out \"--no-recurse-submodules, --recurse-submodules\" (imitating\n>    e.g. --decorate in git-log(1))\n> \n>  * Shortening, using imperative mood\n>  \n>  * Skipping description of safety check, since it matches how checkout\n>    works in general\n> \n> That would make\n> \n> \t--no-recurse-submodules::\n> \t--recurse-submodules::\n> \t\tPerform the checkout in submodules, too.  This only affects\n> \t\tsubmodules with update strategy `checkout` (which is the\n> \t\tdefault update strategy; see `submodule.<name>.update` in\n> \t\tlink:gitmodules[5]).\n> \t+\n> \tThe default behavior is to update submodule entries in the superproject\n> \tindex and to leave the inside of submodules alone.  That behavior can also\n> \tbe requested explicitly with --no-recurse-submodules.\n\nMuch better, thanks!\n\n> Ideas for further work:\n> \n>  * The safety check probably deserves a new section where it could be\n>    described in detail alongside a description of the corresponding check\n>    for plain checkout.  Then the description of the -f option could\n>    point to that section.\n\nGood idea.\n\n>  * What happens when update = merge, rebase, or !command?  I think\n>    skipping them for now like suggested above is fine, but:\n> \n>    - It would be even better to error out when there are changes to carry\n>      over with update = merge or rebase\n\nIn the first round I'd rather do nothing (just like we do now) for merge\nor rebase. These two should be tackled in a follow up series (especially\nas I currently do not think everybody agrees on the desired behavior when\nthe branch config is set yet)\n\n>    - Better still to perform the rebase when update = rebase\n> \n>    - I have no idea what update = merge should do for non-fast-forward\n>      moves\n\nThe same it does for checkout when we would overwrite local changes:\nerror out before doing anything and let the user sort things out?\n\n>> --- a/submodule.c\n>> +++ b/submodule.c\n>> @@ -16,6 +16,8 @@ static struct string_list config_name_for_path;\n>>  static struct string_list config_fetch_recurse_submodules_for_name;\n>>  static struct string_list config_ignore_for_name;\n>>  static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;\n>> +static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;\n>> +static int option_update_recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n> \n> Confusingly, config_update_recurse_submodules is set using the\n> --recurse-submodules-default option, not configuration.  There's\n> precedent for that in fetch.recurseSubmodules handling, but perhaps\n> a comment would help --- something like\n> \n> \t/*\n> \t * When no --recurse-submodules option was passed, should git fetch\n> \t * from submodules where submodule.<name>.fetchRecurseSubmodules\n> \t * doesn't indicate what to do?\n> \t *\n> \t * Controlled by fetch.recurseSubmodules.  The default is determined by\n> \t * the --recurse-submodules-default option, which propagates\n> \t * --recurse-submodules from the parent git process when recursing.\n> \t */\n> \tstatic int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;\n> \n> \t/*\n> \t * When no --recurse-submodules option was passed, should git update\n> \t * the index and worktree within submodules (and in turn their\n> \t * submodules, etc)?\n> \t *\n> \t * Controlled by the --recurse-submodules-default option, which\n> \t * propagates --recurse-submodules from the parent git process\n> \t * when recursing.\n> \t */\n> \tstatic int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;\n\nMakes lots of sense.\n\n> [...]\n>> @@ -382,6 +384,48 @@ int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)\n>>  \t}\n>>  }\n>>\n>> +int parse_update_recurse_submodules_arg(const char *opt, const char *arg)\n>> +{\n>> +\tswitch (git_config_maybe_bool(opt, arg)) {\n>> +\tcase 1:\n>> +\t\treturn RECURSE_SUBMODULES_ON;\n>> +\tcase 0:\n>> +\t\treturn RECURSE_SUBMODULES_OFF;\n>> +\tdefault:\n>> +\t\tif (!strcmp(arg, \"checkout\"))\n>> +\t\t\treturn RECURSE_SUBMODULES_ON;\n> \n> Hm, is this arg == checkout case futureproofing for when\n> --recurse-submodules learns to handle submodules without\n> 'update = checkout', too?\n\nRight.\n\n> Is it safe to leave it out for now?\n\nYes it is.\n\n> [...]\n>> +int submodule_needs_update(const char *path)\n> \n> Return value convention: 1 means \"do update\"; 0 means \"don't update\".\n> \n> Some day later I suppose 2 or -1 could mean \"error out\".  Ok.\n> \n> Naming nit: needs_update sounds like it's checking if there was a\n> change at that path.  How about something like submodule_should_update(),\n> !submodule_ignore_for_update(), or update_should_recurse_into_submodule()?\n\nGood point, will do.\n\n> [...]\n>> @@ -589,6 +633,12 @@ int push_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_nam\n>>  \treturn ret;\n>>  }\n>>\n>> +void set_config_update_recurse_submodules(int default_value, int option_value)\n>> +{\n>> +\tconfig_update_recurse_submodules = default_value;\n>> +\toption_update_recurse_submodules = option_value;\n>> +}\n> \n> Could option_parse_update_submodules set\n> option_update_recurse_submodules directly?  Alternatively, could this\n> function examine option_value so that submodule.c would only need one\n> variable?\n> \n> \tif (option_value == RECURSE_SUBMODULES_DEFAULT)\n> \t\tupdate_recurse_submodules = default_value;\n> \telse\n> \t\tupdate_recurse_submodules = option_value;\n> \n> If .gitmodules some day grows a submodule.<name>.checkoutRecurseSubmodules\n> option then it would be convenient to have the option that overrides and\n> the default tracked separately.  Is that the idea here?\n\nCorrect. I intend to add a global and per-submodule \"autoupdate\" setting\njust like those we have for fetch.\n\n> I might try writing a dummy command to test this basic --recurse-submodules\n> option handling as a separate patch.\n\nHmm, I haven't thought of that. So far I was testing this in the regular\ntest cases and intended to add that to the test framework. Will think\nabout that.\n"},{"id":"234468","messageId":"52F54AF3.3050209@web.de","threadId":"35619","inReplyTo":"xmqqha8fdeek.fsf@gitster.dls.corp.google.com","subject":"Re: [WIP/PATCH 1/9] submodule: prepare for recursive checkout of submodules","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-07T21:06:59Z","receivedAt":"2014-02-07T21:06:59Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 03.02.2014 23:23, schrieb Junio C Hamano:\n> Jens Lehmann <Jens.Lehmann@web.de> writes:\n> \n>> This commit adds the functions and files needed for configuration,\n> \n> Please just say \"Add the functions and files needed for ...\".\n\nRoger that.\n\n>> +++ b/Documentation/recurse-submodules-update.txt\n>> @@ -0,0 +1,8 @@\n>> +--[no-]recurse-submodules::\n>> +\tUsing --recurse-submodules will update the work tree of all\n>> +\tinitialized submodules according to the commit recorded in the\n>> +\tsuperproject if their update configuration is set to checkout'. If\n> \n> That single quote does not seem to be closing any matching quote.\n> \n> The phrase \"according to\" feels a bit too fuzzy.  Merging the commit\n> to what is checked out is one possible implementation of \"according to\".\n> Applying the diff between the commit and what is checked out to work\n> tree is another.  Resetting the work tree files to exactly match the\n> commit would be yet another.\n> \n> I think \"update the work trees to the commit\" (i.e. lose the\n> \"according\") would be the closest to what you are trying to say\n> here.\n> \n>> +\tlocal modifications in a submodule would be overwritten the checkout\n>> +\twill fail unless forced. Without this option or with\n>> +\t--no-recurse-submodules is, the work trees of submodules will not be\n>> +\tupdated, only the hash recorded in the superproject will be updated.\n> \n> It is unclear what happens if their update configuration is set to\n> something other than 'checkout'.\n\nJonathan already proposed a better description, will use that in the next\nround.\n\n>> diff --git a/submodule.c b/submodule.c\n>> index 613857e..b3eb28d 100644\n>> --- a/submodule.c\n>> +++ b/submodule.c\n>> @@ -382,6 +384,48 @@ int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)\n>> ...\n>> +int option_parse_update_submodules(const struct option *opt,\n>> +\t\t\t\t   const char *arg, int unset)\n>> +{\n>> +\tif (unset) {\n>> +\t\t*(int *)opt->value = RECURSE_SUBMODULES_OFF;\n>> +\t} else {\n>> +\t\tif (arg)\n>> +\t\t\t*(int *)opt->value = parse_update_recurse_submodules_arg(opt->long_name, arg);\n>> +\t\telse\n>> +\t\t\t*(int *)opt->value = RECURSE_SUBMODULES_ON;\n>> +\t}\n> \n> You can easily unnest to lose {}\n> \n>     if (unset)\n>             value = off;\n>     else if (arg)\n>             value = parse...;\n>     else\n>             value = on;\n\nYeah, that's better.\n\n> Also I suspect that git_config_maybe_bool() natively knows how to\n> handle arg==NULL, so\n> \n>     if (unset)\n> \tvalue = off;\n>     else\n> \tvalue = parse...;\n> \n> is sufficient?\n\nWill try.\n"},{"id":"234469","messageId":"52F54B6C.7040906@web.de","threadId":"35619","inReplyTo":"xmqqd2j3ddlw.fsf@gitster.dls.corp.google.com","subject":"Re: [WIP/PATCH 2/9] Teach reset the --[no-]recurse-submodules option","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-07T21:09:00Z","receivedAt":"2014-02-07T21:09:00Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 03.02.2014 23:40, schrieb Junio C Hamano:\n> Jens Lehmann <Jens.Lehmann@web.de> writes:\n> \n>> This new option will allow the user to not only reset the work tree of\n>> the superproject but to also update the work tree of all initialized\n>> submodules (so they match the SHA-1 recorded in the superproject) when\n>> used together with --hard or --merge. But this commit only adds the\n> \n> I agree that --soft and --mixed should not do anything.  I am not\n> sure why --keep should not do anything to submodule working trees\n> when asked to recurse, though.\n\nCorrect, I missed that option. I think it should update submodules\ntoo.\n"},{"id":"234471","messageId":"52F54C56.5020604@web.de","threadId":"35619","inReplyTo":"xmqq8utrdcuh.fsf@gitster.dls.corp.google.com","subject":"Re: [WIP/PATCH 3/9] Teach checkout the --[no-]recurse-submodules option","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-07T21:12:54Z","receivedAt":"2014-02-07T21:12:54Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 03.02.2014 23:56, schrieb Junio C Hamano:\n> Jens Lehmann <Jens.Lehmann@web.de> writes:\n> \n>> +\tset_config_update_recurse_submodules(\n>> +\t\tparse_update_recurse_submodules_arg(\"--recurse-submodules-default\",\n>> +\t\t\t\t\t\t    recurse_submodules_default),\n>> +\t\trecurse_submodules);\n> \n> I think I saw these exact lines in another patch.  Perhaps the whole\n> thing can become a helper function that lets the caller avoid typing\n> the whole long strings that needs a strange/unfortunate line break? \n\nRight, that'd be better.\n\n>> diff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh\n>> index 06b18f8..bc3e1ca 100755\n>> --- a/t/t2013-checkout-submodule.sh\n>> +++ b/t/t2013-checkout-submodule.sh\n>> @@ -4,17 +4,57 @@ test_description='checkout can handle submodules'\n>>\n>>  . ./test-lib.sh\n>>\n>> +submodule_creation_must_succeed() {\n> \n> Style: SP before (), i.e.\n> \n> \tsubmodule_creation_must_succeed () {\n> \n>> +\t# checkout base ($1)\n>> +\tgit checkout -f --recurse-submodules $1 &&\n>> +\tgit diff-files --quiet &&\n>> +\tgit diff-index --quiet --cached $1 &&\n> \n> Please make it a habit to quote a parameter that is intended not to\n> be split at $IFS (e.g. write these as \"$1\" not as $1).  Otherwise\n> the reader has to wonder if this can be called with a \"foo bar\" and\n> the expects it to be split into two.\n> \n>> +\t# checkout target ($2)\n>> +\tif test -d submodule; then\n> \n> Style: no semicolons in standard control structure, i.e.\n> \n> \tif test -d submodule\n> \tthen\n> \n>> +\t\techo change>>submodule/first.t &&\n> \n> Style: SP before but not after redirection operator, i.e.\n> \n> \techo foo >>bar\n> \n>> +submodule_removal_must_succeed() {\n> \n> Likewise.\n> \n>> +\t# checkout base ($1)\n>> +\tgit checkout -f --recurse-submodules $1 &&\n> \n> Likewise.\n> \n>> +\techo first > file &&\n> \n> Likewise.\n> \n>> +test_expect_success '\"checkout --recurse-submodules\" replaces submodule with files' '\n>> +\tgit checkout -f base &&\n>> +\tgit checkout -b replace_submodule_with_dir &&\n>> +\tgit update-index --force-remove submodule &&\n>> +\trm -rf submodule/.git .gitmodules &&\n>> +\tgit add .gitmodules submodule/* &&\n>> +\tgit commit -m \"submodule replaced\" &&\n>> +\tgit checkout -f base &&\n>> +\tgit submodule update -f &&\n>> +\tgit checkout --recurse-submodules replace_submodule_with_dir &&\n>> +\ttest -d submodule &&\n>> +\t! test -e submodule/.git &&\n>> +\ttest -f submodule/first.t &&\n>> +\ttest -f submodule/second.t\n>> +'\n> \n> Hmmmm.  Is it sufficient for these files to just exist, or do we\n> want to make sure they have expected contents?\n\nThanks, will consider all you remarks above in the ongoing work for\ntesting framework which should replace these tests.\n"},{"id":"234472","messageId":"52F54ED7.2010302@web.de","threadId":"35619","inReplyTo":"xmqq4n4fdcnd.fsf@gitster.dls.corp.google.com","subject":"Re: [WIP/PATCH 4/9] Teach merge the --[no-]recurse-submodules option","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-07T21:23:35Z","receivedAt":"2014-02-07T21:23:35Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 04.02.2014 00:01, schrieb Junio C Hamano:\n> Jens Lehmann <Jens.Lehmann@web.de> writes:\n> \n>> This new option will allow the user to not only update the work tree of\n>> the superproject according to the merge result but to also update the\n>> work tree of all initialized submodules (so they match the SHA-1 recorded\n>> in the superproject). But this commit only adds the option without any\n>> functionality, that will be added to unpack_trees() in subsequent commits.\n> \n> When the two branches of the superproject being merged wants to put\n> a submodule project to commit A and B, that conflict needs to be\n> resolved, but if they agree that the submodule project should be at\n> C (which is different from what the current superproject HEAD has\n> for the submodule in its gitlink), then we want a checkout of that\n> commit to happen in that submodule.  Makes sense.\n> \n> After resolving such a conflict between A and B, who is responsible\n> to adjust the working tree state of the submodule involved, by the\n> way?  \"git merge --continue\" does not exist and its moral equivalent\n> to conclude such an interrupted merge is \"git commit\".  Should it\n> learn to do \"recurse-submodule\", or should the user run a separate\n> \"checkout --recurse-submodule\"?\n\nI think the user needs to sort things out, just like she has to do\nwhen a file has a merge conflict. But unfortunately we cannot use\nconflict markers here, so I'd propose the following:\n\n* When merge proposes a merge resolution (which it does today by\n  telling the user \"Found a possible merge resolution for the\n  submodule ... [use] git update-index --cacheinfo 160000 ...\")\n  that commit should be checked out in the submodule but not\n  staged. Then the user can simply add and commit.\n\n* If the merge resolution is not obvious to merge, it leaves the\n  submodule in an unmerged state, the local commit still being\n  checked out. The user has to manually do the merge in the\n  submodule and commits that in the superproject.\n\nDoes that make sense?\n"},{"id":"234473","messageId":"52F54F2A.6050305@web.de","threadId":"35619","inReplyTo":"20140203201052.GB16057@odin.tremily.us","subject":"Re: [WIP/PATCH 7/9] submodule: teach unpack_trees() to remove submodule contents","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-07T21:24:58Z","receivedAt":"2014-02-07T21:24:58Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 03.02.2014 21:10, schrieb W. Trevor King:\n> On Mon, Feb 03, 2014 at 08:52:49PM +0100, Jens Lehmann wrote:\n>> Implement the functionality needed to enable work tree manipulating\n>> commands to that a deleted submodule should not only affect the index\n>> (leaving all the files of the submodule in the work tree) but also to\n>> remove the work tree of the superproject (including any untracked\n>> files).\n>>\n>> That will only work properly when the submodule uses a gitfile instead of\n>> a .git directory and no untracked files are present. Otherwise the removal\n>> will fail with a warning (which is just what happened until now).\n> \n> I'm having trouble parsing this one.  How about:\n> \n>   Add a depopulate_submodule helper which removes the submodule\n>   working directory without touching the index.  This will only work\n>   properly when the submodule uses a gitfile…\n\nThanks, that's better.\n"},{"id":"234474","messageId":"52F54F60.3040103@web.de","threadId":"35619","inReplyTo":"20140203201900.GC16057@odin.tremily.us","subject":"Re: [WIP/PATCH 9/9] submodule: teach unpack_trees() to update submodules","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-07T21:25:52Z","receivedAt":"2014-02-07T21:25:52Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 03.02.2014 21:19, schrieb W. Trevor King:\n> On Mon, Feb 03, 2014 at 08:54:17PM +0100, Jens Lehmann wrote:\n>> Implement the functionality needed to enable work tree manipulating\n>> commands so that an changed submodule does not only affect the index but\n>> it also updates the work tree of any initialized submodule according to\n>> the SHA-1 recorded in the superproject.\n> \n> How about:\n> \n>   …so that *a* changed submodule ** updates the index and work tree of\n>   any initialized submodule according to the SHA-1 recorded in the\n>   superproject.  Before this commit it updated neither; users had to\n>   run 'submodule update' to propagate gitlink updates into the\n>   submodule.\n> \n> I'm pretty sure that's accurate anyway ;).\n\nAnd I like it better ;-)\n"},{"id":"234475","messageId":"52F550EC.20202@web.de","threadId":"35619","inReplyTo":"CACsJy8CiAPnatithenDKBBKVGFHQZsu4mJLEjuWFD2GXqO56Lw@mail.gmail.com","subject":"Re: [WIP/PATCH 9/9] submodule: teach unpack_trees() to update submodules","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-02-07T21:32:28Z","receivedAt":"2014-02-07T21:32:28Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 04.02.2014 01:11, schrieb Duy Nguyen:\n> On Tue, Feb 4, 2014 at 2:54 AM, Jens Lehmann <Jens.Lehmann@web.de> wrote:\n>> Implement the functionality needed to enable work tree manipulating\n>> commands so that an changed submodule does not only affect the index but\n>> it also updates the work tree of any initialized submodule according to\n>> the SHA-1 recorded in the superproject.\n>>\n>> Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n>> ---\n>>  entry.c        | 15 ++++++++--\n>>  submodule.c    | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n>>  submodule.h    |  3 ++\n>>  unpack-trees.c | 69 ++++++++++++++++++++++++++++++++++++----------\n>>  unpack-trees.h |  1 +\n>>  5 files changed, 157 insertions(+), 17 deletions(-)\n>>\n>> diff --git a/entry.c b/entry.c\n>> index d1bf6ec..61a2767 100644\n>> --- a/entry.c\n>> +++ b/entry.c\n>> @@ -265,7 +265,7 @@ int checkout_entry(struct cache_entry *ce,\n>>\n>>         if (!check_path(path, len, &st, state->base_dir_len)) {\n>>                 unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);\n>> -               if (!changed)\n>> +               if (!changed && (!S_ISDIR(st.st_mode) || !S_ISGITLINK(ce->ce_mode)))\n>>                         return 0;\n> \n> Should we report something when ce is a gitlink, but path is not a\n> directory, instead of siliently exit?\n\nGood point.\n\n>> diff --git a/submodule.c b/submodule.c\n>> index 3907034..83e7595 100644\n>> --- a/submodule.c\n>> +++ b/submodule.c\n>> @@ -520,6 +520,42 @@ int depopulate_submodule(const char *path)\n>>         return 0;\n>>  }\n>>\n>> +int update_submodule(const char *path, const unsigned char sha1[20], int force)\n>> +{\n>> +       struct strbuf buf = STRBUF_INIT;\n>> +       struct child_process cp;\n>> +       const char *hex_sha1 = sha1_to_hex(sha1);\n>> +       const char *argv[] = {\n>> +               \"checkout\",\n>> +               force ? \"-fq\" : \"-q\",\n> \n> respect \"state->quiet\" in checkout_entry() as well?\n\nSee below.\n\n>> +               hex_sha1,\n>> +               NULL,\n>> +       };\n>> +       const char *git_dir;\n>> +\n>> +       strbuf_addf(&buf, \"%s/.git\", path);\n>> +       git_dir = read_gitfile(buf.buf);\n>> +       if (!git_dir)\n>> +               git_dir = buf.buf;\n>> +       if (!is_directory(git_dir)) {\n>> +               strbuf_release(&buf);\n>> +               /* The submodule is not populated, so we can't check it out */\n>> +               return 0;\n>> +       }\n>> +       strbuf_release(&buf);\n>> +\n>> +       memset(&cp, 0, sizeof(cp));\n>> +       cp.argv = argv;\n>> +       cp.env = local_repo_env;\n>> +       cp.git_cmd = 1;\n>> +       cp.no_stdin = 1;\n>> +       cp.dir = path;   /* GIT_WORK_TREE doesn't work for git checkout */\n> \n> And if we do respect --quiet and it's not specified, paths printed by\n> this process is relative to \"dir\", not to user cwd. Could be\n> confusing.\n\nThat's the reason I'm currently always passing -q to checkout. While\ncheckout would have to learn a \"--prefix=\" option to be able to print\nthe path relative to the superproject, some (most?) users don't want\nto see this detailed information from inside the submodule. After all\ngit status and diff currently also only show a condensed view of the\nsubmodule state and don't print any detailed information about files\ninside the submodule. We might want to add means to enable that later,\nand then we'd have to conditionally provide --quiet (and --prefix)\nhere.\n\n>> +       if (run_command(&cp))\n>> +               return error(\"Could not checkout submodule %s\", path);\n>> +\n>> +       return 0;\n>> +}\n>> +\n"},{"id":"234479","messageId":"xmqqeh3etwg8.fsf@gitster.dls.corp.google.com","threadId":"35619","inReplyTo":"52F54ED7.2010302@web.de","subject":"Re: [WIP/PATCH 4/9] Teach merge the --[no-]recurse-submodules option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-02-07T22:00:23Z","receivedAt":"2014-02-07T22:00:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jens Lehmann <Jens.Lehmann@web.de> writes:\n\n> I think the user needs to sort things out, just like she has to do\n> when a file has a merge conflict. But unfortunately we cannot use\n> conflict markers here, so I'd propose the following:\n>\n> * When merge proposes a merge resolution (which it does today by\n>   telling the user \"Found a possible merge resolution for the\n>   submodule ... [use] git update-index --cacheinfo 160000 ...\")\n>   that commit should be checked out in the submodule but not\n>   staged. Then the user can simply add and commit.\n>\n> * If the merge resolution is not obvious to merge, it leaves the\n>   submodule in an unmerged state, the local commit still being\n>   checked out. The user has to manually do the merge in the\n>   submodule and commits that in the superproject.\n>\n> Does that make sense?\n\nThe latter one does not worry me too much.\n\nFor the former, \"add and commit\" at the top-level makes perfect\nsense, and the \"commit should be checked out in the submodule\" is a\nnecessary step to sanity-check and prepare for that \"add and commit\"\nstep, but what does \"checked out in the submodule\" exactly mean?  Do\nwe detach the HEAD at the commit?  Do we advance the tip of the\nbranch of the submodule to that commit?  Do we know/require/care if\nsuch a move always fast-forwards?\n"},{"id":"234480","messageId":"20140207220853.GZ14197@odin.tremily.us","threadId":"35619","inReplyTo":"xmqqeh3etwg8.fsf@gitster.dls.corp.google.com","subject":"Re: Re: [WIP/PATCH 4/9] Teach merge the --[no-]recurse-submodules option","fromName":"W. Trevor King","fromEmail":"wking@tremily.us","sentAt":"2014-02-07T22:08:53Z","receivedAt":"2014-02-07T22:08:53Z","isPatch":true,"sender":{"key":"wking@tremily.us","avatar":"https://avatars.githubusercontent.com/u/209920?v=4"},"body":"On Fri, Feb 07, 2014 at 02:00:23PM -0800, Junio C Hamano wrote:\n> Jens Lehmann <Jens.Lehmann@web.de> writes:\n> > I think the user needs to sort things out, just like she has to do\n> > when a file has a merge conflict. But unfortunately we cannot use\n> > conflict markers here, so I'd propose the following:\n> >\n> > * When merge proposes a merge resolution (which it does today by\n> >   telling the user \"Found a possible merge resolution for the\n> >   submodule ... [use] git update-index --cacheinfo 160000 ...\")\n> >   that commit should be checked out in the submodule but not\n> >   staged. Then the user can simply add and commit.\n> > …\n> …\n> \n> For the former, \"add and commit\" at the top-level makes perfect\n> sense, …\n\nThis still works if the merge issue is in a grandchild submodule, but\nit's going to be a bit tedious if the user has to add-and-commit at\neach level from the troublesome sub-sub-…-module on up to the\ntop-level superproject.  I can't think of a cleaner solution though.\n\nCheers,\nTrevor\n\n-- \nThis email may be signed or encrypted with GnuPG (http://www.gnupg.org).\nFor more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy\n"}]}