summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/network/fetch.c14
-rw-r--r--include/git2/diff.h15
-rw-r--r--include/git2/errors.h1
-rw-r--r--include/git2/indexer.h1
-rw-r--r--include/git2/oid.h2
-rw-r--r--include/git2/remote.h2
-rw-r--r--include/git2/submodule.h460
-rw-r--r--src/attr.c26
-rw-r--r--src/attr.h1
-rw-r--r--src/branch.c28
-rw-r--r--src/buffer.c37
-rw-r--r--src/checkout.c15
-rw-r--r--src/config.c7
-rw-r--r--src/config.h1
-rw-r--r--src/config_file.c12
-rw-r--r--src/config_file.h12
-rw-r--r--src/diff.c2
-rw-r--r--src/diff_output.c19
-rw-r--r--src/errors.c5
-rw-r--r--src/fetch.c63
-rw-r--r--src/filebuf.c1
-rw-r--r--src/fileops.c1
-rw-r--r--src/indexer.c12
-rw-r--r--src/iterator.c21
-rw-r--r--src/oid.c3
-rw-r--r--src/pkt.c51
-rw-r--r--src/pkt.h10
-rw-r--r--src/protocol.c14
-rw-r--r--src/protocol.h4
-rw-r--r--src/remote.c8
-rw-r--r--src/repository.c9
-rw-r--r--src/revwalk.c20
-rw-r--r--src/submodule.c1491
-rw-r--r--src/submodule.h102
-rw-r--r--src/transport.h12
-rw-r--r--src/transports/git.c2
-rw-r--r--src/transports/http.c2
-rw-r--r--tests-clar/refs/revparse.c9
-rw-r--r--tests-clar/resources/submod2/.gitted/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/config20
-rw-r--r--tests-clar/resources/submod2/.gitted/description1
-rwxr-xr-xtests-clar/resources/submod2/.gitted/hooks/applypatch-msg.sample15
-rw-r--r--tests-clar/resources/submod2/.gitted/indexbin0 -> 944 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/info/exclude6
-rw-r--r--tests-clar/resources/submod2/.gitted/logs/HEAD4
-rw-r--r--tests-clar/resources/submod2/.gitted/logs/refs/heads/master4
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/config13
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/description1
-rwxr-xr-xtests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/hooks/applypatch-msg.sample15
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/indexbin0 -> 192 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/info/exclude6
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/refs/heads/master1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/refs/remotes/origin/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1bin0 -> 55 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484bin0 -> 53 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5bin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/41/bd4bc3df978de695f67ace64c560913da11653bin0 -> 163 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/48/0095882d281ed676fe5b863569520e54a7d5c0bin0 -> 163 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/5e/4963595a9774b90524d35a807169049de8ccadbin0 -> 167 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/6b/31c659545507c381e9cd34ec508f16c04e149e2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/73/ba924a80437097795ae839e66e187c55d3babfbin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/78/9efbdadaa4a582778d4584385495559ea0994b2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6ebin0 -> 81 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5bin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/packed-refs2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/refs/heads/master1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/refs/remotes/origin/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/config13
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/description1
-rwxr-xr-xtests-clar/resources/submod2/.gitted/modules/sm_changed_file/hooks/applypatch-msg.sample15
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/indexbin0 -> 192 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/info/exclude6
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/refs/heads/master1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/refs/remotes/origin/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1bin0 -> 55 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484bin0 -> 53 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5bin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/41/bd4bc3df978de695f67ace64c560913da11653bin0 -> 163 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/48/0095882d281ed676fe5b863569520e54a7d5c0bin0 -> 163 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/5e/4963595a9774b90524d35a807169049de8ccadbin0 -> 167 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/6b/31c659545507c381e9cd34ec508f16c04e149e2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/73/ba924a80437097795ae839e66e187c55d3babfbin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/78/9efbdadaa4a582778d4584385495559ea0994b2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6ebin0 -> 81 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5bin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/packed-refs2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/refs/heads/master1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_file/refs/remotes/origin/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/COMMIT_EDITMSG1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/config13
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/description1
-rwxr-xr-xtests-clar/resources/submod2/.gitted/modules/sm_changed_head/hooks/applypatch-msg.sample15
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/indexbin0 -> 192 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/info/exclude6
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/HEAD2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/refs/heads/master2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/refs/remotes/origin/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1bin0 -> 55 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484bin0 -> 53 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5bin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/3d/9386c507f6b093471a3e324085657a3c2b42473
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/41/bd4bc3df978de695f67ace64c560913da11653bin0 -> 163 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/48/0095882d281ed676fe5b863569520e54a7d5c0bin0 -> 163 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/5e/4963595a9774b90524d35a807169049de8ccadbin0 -> 167 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/6b/31c659545507c381e9cd34ec508f16c04e149e2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/73/ba924a80437097795ae839e66e187c55d3babfbin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/77/fb0ed3e58568d6ad362c78de08ab8649d76e29bin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/78/9efbdadaa4a582778d4584385495559ea0994b2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6ebin0 -> 81 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/8e/b1e637ed9fc8e5454fa20d38f809091f9395f42
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5bin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/packed-refs2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/refs/heads/master1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_head/refs/remotes/origin/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/config13
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/description1
-rwxr-xr-xtests-clar/resources/submod2/.gitted/modules/sm_changed_index/hooks/applypatch-msg.sample15
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/indexbin0 -> 192 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/info/exclude6
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/refs/heads/master1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/refs/remotes/origin/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1bin0 -> 55 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484bin0 -> 53 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5bin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/41/bd4bc3df978de695f67ace64c560913da11653bin0 -> 163 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/48/0095882d281ed676fe5b863569520e54a7d5c0bin0 -> 163 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/5e/4963595a9774b90524d35a807169049de8ccadbin0 -> 167 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/6b/31c659545507c381e9cd34ec508f16c04e149e2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/73/ba924a80437097795ae839e66e187c55d3babfbin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/78/9efbdadaa4a582778d4584385495559ea0994b2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6ebin0 -> 81 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/a0/2d31770687965547ab7a04cee199b29ee458d6bin0 -> 134 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5bin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/packed-refs2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/refs/heads/master1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_index/refs/remotes/origin/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/config13
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/description1
-rwxr-xr-xtests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/hooks/applypatch-msg.sample15
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/indexbin0 -> 192 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/info/exclude6
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/refs/heads/master1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/refs/remotes/origin/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1bin0 -> 55 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484bin0 -> 53 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5bin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/41/bd4bc3df978de695f67ace64c560913da11653bin0 -> 163 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/48/0095882d281ed676fe5b863569520e54a7d5c0bin0 -> 163 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/5e/4963595a9774b90524d35a807169049de8ccadbin0 -> 167 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/6b/31c659545507c381e9cd34ec508f16c04e149e2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/73/ba924a80437097795ae839e66e187c55d3babfbin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/78/9efbdadaa4a582778d4584385495559ea0994b2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6ebin0 -> 81 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5bin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/packed-refs2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/refs/heads/master1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/refs/remotes/origin/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/config13
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/description1
-rwxr-xr-xtests-clar/resources/submod2/.gitted/modules/sm_missing_commits/hooks/applypatch-msg.sample15
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/indexbin0 -> 192 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/info/exclude6
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/refs/heads/master1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/refs/remotes/origin/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1bin0 -> 55 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484bin0 -> 53 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5bin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/41/bd4bc3df978de695f67ace64c560913da11653bin0 -> 163 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/5e/4963595a9774b90524d35a807169049de8ccadbin0 -> 167 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/6b/31c659545507c381e9cd34ec508f16c04e149e2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6ebin0 -> 81 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5bin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/packed-refs2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/refs/heads/master1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/refs/remotes/origin/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/config13
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/description1
-rwxr-xr-xtests-clar/resources/submod2/.gitted/modules/sm_unchanged/hooks/applypatch-msg.sample15
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/indexbin0 -> 192 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/info/exclude6
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/refs/heads/master1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/refs/remotes/origin/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1bin0 -> 55 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484bin0 -> 53 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5bin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/41/bd4bc3df978de695f67ace64c560913da11653bin0 -> 163 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/48/0095882d281ed676fe5b863569520e54a7d5c0bin0 -> 163 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/5e/4963595a9774b90524d35a807169049de8ccadbin0 -> 167 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/6b/31c659545507c381e9cd34ec508f16c04e149e2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/73/ba924a80437097795ae839e66e187c55d3babfbin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/78/9efbdadaa4a582778d4584385495559ea0994b2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6ebin0 -> 81 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5bin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/packed-refs2
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/refs/heads/master1
-rw-r--r--tests-clar/resources/submod2/.gitted/modules/sm_unchanged/refs/remotes/origin/HEAD1
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/09/460e5b6cbcb05a3e404593c32a3aa7221eca0ebin0 -> 197 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/14/fe9ccf104058df25e0a08361c4494e167ef2431
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/22/ce3e0311dda73a5992d54a4a595518d3876ea74
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/25/5546424b0efb847b1bfc91dbf7348b277f8970bin0 -> 157 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/2a/30f1e6f94b20917005a21273f65b406d0f8badbin0 -> 144 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/42/cfb95cd01bf9225b659b5ee3edcc78e8eeb478bin0 -> 40 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/57/958699c2dc394f81cfc76950e9c3ac3025c398bin0 -> 136 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/59/01da4f1c67756eeadc5121d206bec2431f253b2
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/60/7d96653d4d0a4f733107f7890c2e67b55b620dbin0 -> 53 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/74/84482eb8db738cafa696993664607500a3f2b9bin0 -> 173 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/7b/a4c5c3561daa5ab1a86215cfb0587e96d404d6bin0 -> 48 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/87/3585b94bdeabccea991ea5e3ec1a277895b698bin0 -> 137 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/97/4cf7c73de336b0c4e019f918f3cee367d72e842
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/9d/bc299bc013ea253583b40bf327b5a6e4037b89bin0 -> 80 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/a9/104bf89e911387244ef499413960ba472066d9bin0 -> 165 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/b6/14088620bbdc1d29549d223ceba0f4419fd4cbbin0 -> 110 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/d4/07f19e50c1da1ff584beafe0d6dac7237c5d06bin0 -> 55 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/d9/3e95571d92cceb5de28c205f1d5f3cc8b88bc82
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/e3/b83bf274ee065eee48734cf8c6dfaf5e81471cbin0 -> 246 bytes
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/f5/4414c25e6d24fe39f5c3f128d7c8a17bc238332
-rw-r--r--tests-clar/resources/submod2/.gitted/objects/f9/90a25a74d1a8281ce2ab018ea8df66795cd60b1
-rw-r--r--tests-clar/resources/submod2/.gitted/refs/heads/master1
-rw-r--r--tests-clar/resources/submod2/README.txt3
-rw-r--r--tests-clar/resources/submod2/gitmodules21
-rw-r--r--tests-clar/resources/submod2/just_a_dir/contents1
-rw-r--r--tests-clar/resources/submod2/just_a_file1
-rw-r--r--tests-clar/resources/submod2/not_submodule/.gitted/COMMIT_EDITMSG1
-rw-r--r--tests-clar/resources/submod2/not_submodule/.gitted/HEAD1
-rw-r--r--tests-clar/resources/submod2/not_submodule/.gitted/config6
-rw-r--r--tests-clar/resources/submod2/not_submodule/.gitted/description1
-rwxr-xr-xtests-clar/resources/submod2/not_submodule/.gitted/hooks/applypatch-msg.sample15
-rwxr-xr-xtests-clar/resources/submod2/not_submodule/.gitted/hooks/commit-msg.sample24
-rwxr-xr-xtests-clar/resources/submod2/not_submodule/.gitted/hooks/post-update.sample8
-rwxr-xr-xtests-clar/resources/submod2/not_submodule/.gitted/hooks/pre-applypatch.sample14
-rwxr-xr-xtests-clar/resources/submod2/not_submodule/.gitted/hooks/pre-commit.sample50
-rwxr-xr-xtests-clar/resources/submod2/not_submodule/.gitted/hooks/pre-rebase.sample169
-rwxr-xr-xtests-clar/resources/submod2/not_submodule/.gitted/hooks/prepare-commit-msg.sample36
-rwxr-xr-xtests-clar/resources/submod2/not_submodule/.gitted/hooks/update.sample128
-rw-r--r--tests-clar/resources/submod2/not_submodule/.gitted/indexbin0 -> 112 bytes
-rw-r--r--tests-clar/resources/submod2/not_submodule/.gitted/info/exclude6
-rw-r--r--tests-clar/resources/submod2/not_submodule/.gitted/logs/HEAD1
-rw-r--r--tests-clar/resources/submod2/not_submodule/.gitted/logs/refs/heads/master1
-rw-r--r--tests-clar/resources/submod2/not_submodule/.gitted/objects/68/e92c611b80ee1ed8f38314ff9577f0d15b2444bin0 -> 132 bytes
-rw-r--r--tests-clar/resources/submod2/not_submodule/.gitted/objects/71/ff9927d7c8a5639e062c38a7d35c433c424627bin0 -> 52 bytes
-rw-r--r--tests-clar/resources/submod2/not_submodule/.gitted/objects/f0/1d56b18efd353ef2bb93a4585d590a0847195ebin0 -> 55 bytes
-rw-r--r--tests-clar/resources/submod2/not_submodule/.gitted/refs/heads/master1
-rw-r--r--tests-clar/resources/submod2/not_submodule/README.txt1
-rw-r--r--tests-clar/resources/submod2/sm_added_and_uncommited/.gitted1
-rw-r--r--tests-clar/resources/submod2/sm_added_and_uncommited/README.txt3
-rw-r--r--tests-clar/resources/submod2/sm_added_and_uncommited/file_to_modify3
-rw-r--r--tests-clar/resources/submod2/sm_changed_file/.gitted1
-rw-r--r--tests-clar/resources/submod2/sm_changed_file/README.txt3
-rw-r--r--tests-clar/resources/submod2/sm_changed_file/file_to_modify4
-rw-r--r--tests-clar/resources/submod2/sm_changed_head/.gitted1
-rw-r--r--tests-clar/resources/submod2/sm_changed_head/README.txt3
-rw-r--r--tests-clar/resources/submod2/sm_changed_head/file_to_modify4
-rw-r--r--tests-clar/resources/submod2/sm_changed_index/.gitted1
-rw-r--r--tests-clar/resources/submod2/sm_changed_index/README.txt3
-rw-r--r--tests-clar/resources/submod2/sm_changed_index/file_to_modify4
-rw-r--r--tests-clar/resources/submod2/sm_changed_untracked_file/.gitted1
-rw-r--r--tests-clar/resources/submod2/sm_changed_untracked_file/README.txt3
-rw-r--r--tests-clar/resources/submod2/sm_changed_untracked_file/file_to_modify3
-rw-r--r--tests-clar/resources/submod2/sm_changed_untracked_file/i_am_untracked1
-rw-r--r--tests-clar/resources/submod2/sm_missing_commits/.gitted1
-rw-r--r--tests-clar/resources/submod2/sm_missing_commits/README.txt3
-rw-r--r--tests-clar/resources/submod2/sm_missing_commits/file_to_modify3
-rw-r--r--tests-clar/resources/submod2/sm_unchanged/.gitted1
-rw-r--r--tests-clar/resources/submod2/sm_unchanged/README.txt3
-rw-r--r--tests-clar/resources/submod2/sm_unchanged/file_to_modify3
-rw-r--r--tests-clar/resources/submod2_target/.gitted/HEAD1
-rw-r--r--tests-clar/resources/submod2_target/.gitted/config6
-rw-r--r--tests-clar/resources/submod2_target/.gitted/description1
-rwxr-xr-xtests-clar/resources/submod2_target/.gitted/hooks/applypatch-msg.sample15
-rw-r--r--tests-clar/resources/submod2_target/.gitted/indexbin0 -> 192 bytes
-rw-r--r--tests-clar/resources/submod2_target/.gitted/info/exclude6
-rw-r--r--tests-clar/resources/submod2_target/.gitted/logs/HEAD4
-rw-r--r--tests-clar/resources/submod2_target/.gitted/logs/refs/heads/master4
-rw-r--r--tests-clar/resources/submod2_target/.gitted/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1bin0 -> 55 bytes
-rw-r--r--tests-clar/resources/submod2_target/.gitted/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484bin0 -> 53 bytes
-rw-r--r--tests-clar/resources/submod2_target/.gitted/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5bin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2_target/.gitted/objects/41/bd4bc3df978de695f67ace64c560913da11653bin0 -> 163 bytes
-rw-r--r--tests-clar/resources/submod2_target/.gitted/objects/48/0095882d281ed676fe5b863569520e54a7d5c0bin0 -> 163 bytes
-rw-r--r--tests-clar/resources/submod2_target/.gitted/objects/5e/4963595a9774b90524d35a807169049de8ccadbin0 -> 167 bytes
-rw-r--r--tests-clar/resources/submod2_target/.gitted/objects/6b/31c659545507c381e9cd34ec508f16c04e149e2
-rw-r--r--tests-clar/resources/submod2_target/.gitted/objects/73/ba924a80437097795ae839e66e187c55d3babfbin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2_target/.gitted/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a2
-rw-r--r--tests-clar/resources/submod2_target/.gitted/objects/78/9efbdadaa4a582778d4584385495559ea0994b2
-rw-r--r--tests-clar/resources/submod2_target/.gitted/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6ebin0 -> 81 bytes
-rw-r--r--tests-clar/resources/submod2_target/.gitted/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5bin0 -> 93 bytes
-rw-r--r--tests-clar/resources/submod2_target/.gitted/refs/heads/master1
-rw-r--r--tests-clar/resources/submod2_target/README.txt3
-rw-r--r--tests-clar/resources/submod2_target/file_to_modify3
-rw-r--r--tests-clar/revwalk/basic.c8
-rw-r--r--tests-clar/status/submodules.c24
-rw-r--r--tests-clar/submodule/lookup.c110
-rw-r--r--tests-clar/submodule/modify.c257
-rw-r--r--tests-clar/submodule/status.c308
-rw-r--r--tests-clar/submodule/submodule_helpers.c84
-rw-r--r--tests-clar/submodule/submodule_helpers.h2
-rw-r--r--tests-clar/valgrind-supp-mac.txt82
316 files changed, 4012 insertions, 365 deletions
diff --git a/examples/network/fetch.c b/examples/network/fetch.c
index 52e0412f..fa941b97 100644
--- a/examples/network/fetch.c
+++ b/examples/network/fetch.c
@@ -14,6 +14,13 @@ struct dl_data {
int finished;
};
+static void progress_cb(const char *str, int len, void *data)
+{
+ data = data;
+ printf("remote: %.*s", len, str);
+ fflush(stdout); /* We don't have the \n to force the flush */
+}
+
static void *download(void *ptr)
{
struct dl_data *data = (struct dl_data *)ptr;
@@ -43,6 +50,7 @@ exit:
static int update_cb(const char *refname, const git_oid *a, const git_oid *b, void *data)
{
char a_str[GIT_OID_HEXSZ+1], b_str[GIT_OID_HEXSZ+1];
+ data = data;
git_oid_fmt(b_str, b);
b_str[GIT_OID_HEXSZ] = '\0';
@@ -78,6 +86,7 @@ int fetch(git_repository *repo, int argc, char **argv)
// Set up the callbacks (only update_tips for now)
memset(&callbacks, 0, sizeof(callbacks));
callbacks.update_tips = &update_cb;
+ callbacks.progress = &progress_cb;
git_remote_set_callbacks(remote, &callbacks);
// Set up the information for the background worker thread
@@ -96,7 +105,10 @@ int fetch(git_repository *repo, int argc, char **argv)
// the download rate.
do {
usleep(10000);
- printf("\rReceived %d/%d objects in %zu bytes", stats.processed, stats.total, bytes);
+
+ if (stats.total > 0)
+ printf("Received %d/%d objects (%d) in %d bytes\r",
+ stats.received, stats.total, stats.processed, bytes);
} while (!data.finished);
if (data.ret < 0)
diff --git a/include/git2/diff.h b/include/git2/diff.h
index 79ef7a49..088e1ecf 100644
--- a/include/git2/diff.h
+++ b/include/git2/diff.h
@@ -391,6 +391,21 @@ GIT_EXTERN(int) git_diff_print_patch(
void *cb_data,
git_diff_data_fn print_cb);
+/**
+ * Query how many diff records are there in a diff list.
+ *
+ * You can optionally pass in a `git_delta_t` value if you want a count
+ * of just entries that match that delta type, or pass -1 for all delta
+ * records.
+ *
+ * @param diff A git_diff_list generated by one of the above functions
+ * @param delta_t A git_delta_t value to filter the count, or -1 for all records
+ * @return Count of number of deltas matching delta_t type
+ */
+GIT_EXTERN(int) git_diff_entrycount(
+ git_diff_list *diff,
+ int delta_t);
+
/**@}*/
diff --git a/include/git2/errors.h b/include/git2/errors.h
index 2ab1da40..b55f8c30 100644
--- a/include/git2/errors.h
+++ b/include/git2/errors.h
@@ -54,6 +54,7 @@ typedef enum {
GITERR_TREE,
GITERR_INDEXER,
GITERR_SSL,
+ GITERR_SUBMODULE,
} git_error_t;
/**
diff --git a/include/git2/indexer.h b/include/git2/indexer.h
index d300ba01..87f48fe2 100644
--- a/include/git2/indexer.h
+++ b/include/git2/indexer.h
@@ -19,6 +19,7 @@ GIT_BEGIN_DECL
typedef struct git_indexer_stats {
unsigned int total;
unsigned int processed;
+ unsigned int received;
} git_indexer_stats;
diff --git a/include/git2/oid.h b/include/git2/oid.h
index 887b33e5..9e54a9f9 100644
--- a/include/git2/oid.h
+++ b/include/git2/oid.h
@@ -185,6 +185,8 @@ GIT_EXTERN(int) git_oid_streq(const git_oid *a, const char *str);
/**
* Check is an oid is all zeros.
+ *
+ * @return 1 if all zeros, 0 otherwise.
*/
GIT_EXTERN(int) git_oid_iszero(const git_oid *a);
diff --git a/include/git2/remote.h b/include/git2/remote.h
index 96f460e9..a3913af5 100644
--- a/include/git2/remote.h
+++ b/include/git2/remote.h
@@ -287,7 +287,7 @@ typedef enum git_remote_completion_type {
* Set the calbacks to be called by the remote.
*/
struct git_remote_callbacks {
- int (*progress)(const char *str, void *data);
+ void (*progress)(const char *str, int len, void *data);
int (*completion)(git_remote_completion_type type, void *data);
int (*update_tips)(const char *refname, const git_oid *a, const git_oid *b, void *data);
void *data;
diff --git a/include/git2/submodule.h b/include/git2/submodule.h
index f65911a3..fe7f26cf 100644
--- a/include/git2/submodule.h
+++ b/include/git2/submodule.h
@@ -20,54 +20,153 @@
*/
GIT_BEGIN_DECL
+/**
+ * Opaque structure representing a submodule.
+ *
+ * Submodule support in libgit2 builds a list of known submodules and keeps
+ * it in the repository. The list is built from the .gitmodules file, the
+ * .git/config file, the index, and the HEAD tree. Items in the working
+ * directory that look like submodules (i.e. a git repo) but are not
+ * mentioned in those places won't be tracked.
+ */
+typedef struct git_submodule git_submodule;
+
+/**
+ * Values that could be specified for the update rule of a submodule.
+ *
+ * Use the DEFAULT value if you have altered the update value via
+ * `git_submodule_set_update()` and wish to reset to the original default.
+ */
typedef enum {
+ GIT_SUBMODULE_UPDATE_DEFAULT = -1,
GIT_SUBMODULE_UPDATE_CHECKOUT = 0,
GIT_SUBMODULE_UPDATE_REBASE = 1,
- GIT_SUBMODULE_UPDATE_MERGE = 2
+ GIT_SUBMODULE_UPDATE_MERGE = 2,
+ GIT_SUBMODULE_UPDATE_NONE = 3
} git_submodule_update_t;
+/**
+ * Values that could be specified for how closely to examine the
+ * working directory when getting submodule status.
+ *
+ * Use the DEFUALT value if you have altered the ignore value via
+ * `git_submodule_set_ignore()` and wish to reset to the original value.
+ */
typedef enum {
- GIT_SUBMODULE_IGNORE_ALL = 0, /* never dirty */
- GIT_SUBMODULE_IGNORE_DIRTY = 1, /* only dirty if HEAD moved */
- GIT_SUBMODULE_IGNORE_UNTRACKED = 2, /* dirty if tracked files change */
- GIT_SUBMODULE_IGNORE_NONE = 3 /* any change or untracked == dirty */
+ GIT_SUBMODULE_IGNORE_DEFAULT = -1, /* reset to default */
+ GIT_SUBMODULE_IGNORE_NONE = 0, /* any change or untracked == dirty */
+ GIT_SUBMODULE_IGNORE_UNTRACKED = 1, /* dirty if tracked files change */
+ GIT_SUBMODULE_IGNORE_DIRTY = 2, /* only dirty if HEAD moved */
+ GIT_SUBMODULE_IGNORE_ALL = 3 /* never dirty */
} git_submodule_ignore_t;
/**
- * Description of submodule
+ * Return codes for submodule status.
+ *
+ * A combination of these flags will be returned to describe the status of a
+ * submodule. Depending on the "ignore" property of the submodule, some of
+ * the flags may never be returned because they indicate changes that are
+ * supposed to be ignored.
+ *
+ * Submodule info is contained in 4 places: the HEAD tree, the index, config
+ * files (both .git/config and .gitmodules), and the working directory. Any
+ * or all of those places might be missing information about the submodule
+ * depending on what state the repo is in. We consider all four places to
+ * build the combination of status flags.
+ *
+ * There are four values that are not really status, but give basic info
+ * about what sources of submodule data are available. These will be
+ * returned even if ignore is set to "ALL".
+ *
+ * * IN_HEAD - superproject head contains submodule
+ * * IN_INDEX - superproject index contains submodule
+ * * IN_CONFIG - superproject gitmodules has submodule
+ * * IN_WD - superproject workdir has submodule
+ *
+ * The following values will be returned so long as ignore is not "ALL".
+ *
+ * * INDEX_ADDED - in index, not in head
+ * * INDEX_DELETED - in head, not in index
+ * * INDEX_MODIFIED - index and head don't match
+ * * WD_UNINITIALIZED - workdir contains empty directory
+ * * WD_ADDED - in workdir, not index
+ * * WD_DELETED - in index, not workdir
+ * * WD_MODIFIED - index and workdir head don't match
+ *
+ * The following can only be returned if ignore is "NONE" or "UNTRACKED".
+ *
+ * * WD_INDEX_MODIFIED - submodule workdir index is dirty
+ * * WD_WD_MODIFIED - submodule workdir has modified files
+ *
+ * Lastly, the following will only be returned for ignore "NONE".
+ *
+ * * WD_UNTRACKED - wd contains untracked files
+ */
+typedef enum {
+ GIT_SUBMODULE_STATUS_IN_HEAD = (1u << 0),
+ GIT_SUBMODULE_STATUS_IN_INDEX = (1u << 1),
+ GIT_SUBMODULE_STATUS_IN_CONFIG = (1u << 2),
+ GIT_SUBMODULE_STATUS_IN_WD = (1u << 3),
+ GIT_SUBMODULE_STATUS_INDEX_ADDED = (1u << 4),
+ GIT_SUBMODULE_STATUS_INDEX_DELETED = (1u << 5),
+ GIT_SUBMODULE_STATUS_INDEX_MODIFIED = (1u << 6),
+ GIT_SUBMODULE_STATUS_WD_UNINITIALIZED = (1u << 7),
+ GIT_SUBMODULE_STATUS_WD_ADDED = (1u << 8),
+ GIT_SUBMODULE_STATUS_WD_DELETED = (1u << 9),
+ GIT_SUBMODULE_STATUS_WD_MODIFIED = (1u << 10),
+ GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED = (1u << 11),
+ GIT_SUBMODULE_STATUS_WD_WD_MODIFIED = (1u << 12),
+ GIT_SUBMODULE_STATUS_WD_UNTRACKED = (1u << 13),
+} git_submodule_status_t;
+
+#define GIT_SUBMODULE_STATUS_IS_UNMODIFIED(S) \
+ (((S) & ~(GIT_SUBMODULE_STATUS_IN_HEAD | GIT_SUBMODULE_STATUS_IN_INDEX | \
+ GIT_SUBMODULE_STATUS_IN_CONFIG | GIT_SUBMODULE_STATUS_IN_WD)) == 0)
+
+/**
+ * Lookup submodule information by name or path.
+ *
+ * Given either the submodule name or path (they are usually the same), this
+ * returns a structure describing the submodule.
*
- * This record describes a submodule found in a repository. There
- * should be an entry for every submodule found in the HEAD and for
- * every submodule described in .gitmodules. The fields are as follows:
+ * There are two expected error scenarios:
*
- * - `name` is the name of the submodule from .gitmodules.
- * - `path` is the path to the submodule from the repo working directory.
- * It is almost always the same as `name`.
- * - `url` is the url for the submodule.
- * - `oid` is the HEAD SHA1 for the submodule.
- * - `update` is a value from above - see gitmodules(5) update.
- * - `ignore` is a value from above - see gitmodules(5) ignore.
- * - `fetch_recurse` is 0 or 1 - see gitmodules(5) fetchRecurseSubmodules.
- * - `refcount` is for internal use.
+ * - The submodule is not mentioned in the HEAD, the index, and the config,
+ * but does "exist" in the working directory (i.e. there is a subdirectory
+ * that is a valid self-contained git repo). In this case, this function
+ * returns GIT_EEXISTS to indicate the the submodule exists but not in a
+ * state where a git_submodule can be instantiated.
+ * - The submodule is not mentioned in the HEAD, index, or config and the
+ * working directory doesn't contain a value git repo at that path.
+ * There may or may not be anything else at that path, but nothing that
+ * looks like a submodule. In this case, this returns GIT_ENOTFOUND.
*
- * If the submodule has been added to .gitmodules but not yet git added,
- * then the `oid` will be zero. If the submodule has been deleted, but
- * the delete has not been committed yet, then the `oid` will be set, but
- * the `url` will be NULL.
+ * The submodule object is owned by the containing repo and will be freed
+ * when the repo is freed. The caller need not free the submodule.
+ *
+ * @param submodule Pointer to submodule description object pointer..
+ * @param repo The repository.
+ * @param name The name of the submodule. Trailing slashes will be ignored.
+ * @return 0 on success, GIT_ENOTFOUND if submodule does not exist,
+ * GIT_EEXISTS if submodule exists in working directory only, -1 on
+ * other errors.
*/
-typedef struct {
- char *name;
- char *path;
- char *url;
- git_oid oid; /* sha1 of submodule HEAD ref or zero if not committed */
- git_submodule_update_t update;
- git_submodule_ignore_t ignore;
- int fetch_recurse;
- int refcount;
-} git_submodule;
+GIT_EXTERN(int) git_submodule_lookup(
+ git_submodule **submodule,
+ git_repository *repo,
+ const char *name);
/**
- * Iterate over all submodules of a repository.
+ * Iterate over all tracked submodules of a repository.
+ *
+ * See the note on `git_submodule` above. This iterates over the tracked
+ * submodules as decribed therein.
+ *
+ * If you are concerned about items in the working directory that look like
+ * submodules but are not tracked, the diff API will generate a diff record
+ * for workdir items that look like submodules but are not tracked, showing
+ * them as added in the workdir. Also, the status API will treat the entire
+ * subdirectory of a contained git repo as a single GIT_STATUS_WT_NEW item.
*
* @param repo The repository
* @param callback Function to be called with the name of each submodule.
@@ -77,26 +176,297 @@ typedef struct {
*/
GIT_EXTERN(int) git_submodule_foreach(
git_repository *repo,
- int (*callback)(const char *name, void *payload),
+ int (*callback)(git_submodule *sm, const char *name, void *payload),
void *payload);
/**
- * Lookup submodule information by name or path.
+ * Set up a new git submodule for checkout.
*
- * Given either the submodule name or path (they are usually the same),
- * this returns a structure describing the submodule. If the submodule
- * does not exist, this will return GIT_ENOTFOUND and set the submodule
- * pointer to NULL.
+ * This does "git submodule add" up to the fetch and checkout of the
+ * submodule contents. It preps a new submodule, creates an entry in
+ * .gitmodules and creates an empty initialized repository either at the
+ * given path in the working directory or in .git/modules with a gitlink
+ * from the working directory to the new repo.
*
- * @param submodule Pointer to submodule description object pointer..
- * @param repo The repository.
- * @param name The name of the submodule. Trailing slashes will be ignored.
- * @return 0 on success, GIT_ENOTFOUND if submodule does not exist, -1 on error
+ * To fully emulate "git submodule add" call this function, then open the
+ * submodule repo and perform the clone step as needed. Lastly, call
+ * `git_submodule_add_finalize()` to wrap up adding the new submodule and
+ * .gitmodules to the index to be ready to commit.
+ *
+ * @param submodule The newly created submodule ready to open for clone
+ * @param repo Superproject repository to contain the new submodule
+ * @param url URL for the submodules remote
+ * @param path Path at which the submodule should be created
+ * @param use_gitlink Should workdir contain a gitlink to the repo in
+ * .git/modules vs. repo directly in workdir.
+ * @return 0 on success, GIT_EEXISTS if submodule already exists,
+ * -1 on other errors.
*/
-GIT_EXTERN(int) git_submodule_lookup(
+GIT_EXTERN(int) git_submodule_add_setup(
git_submodule **submodule,
git_repository *repo,
- const char *name);
+ const char *url,
+ const char *path,
+ int use_gitlink);
+
+/**
+ * Resolve the setup of a new git submodule.
+ *
+ * This should be called on a submodule once you have called add setup
+ * and done the clone of the submodule. This adds the .gitmodules file
+ * and the newly cloned submodule to the index to be ready to be committed
+ * (but doesn't actually do the commit).
+ *
+ * @param submodule The submodule to finish adding.
+ */
+GIT_EXTERN(int) git_submodule_add_finalize(git_submodule *submodule);
+
+/**
+ * Add current submodule HEAD commit to index of superproject.
+ *
+ * @param submodule The submodule to add to the index
+ * @param write_index Boolean if this should immediately write the index
+ * file. If you pass this as false, you will have to get the
+ * git_index and explicitly call `git_index_write()` on it to
+ * save the change.
+ * @return 0 on success, <0 on failure
+ */
+GIT_EXTERN(int) git_submodule_add_to_index(
+ git_submodule *submodule,
+ int write_index);
+
+/**
+ * Write submodule settings to .gitmodules file.
+ *
+ * This commits any in-memory changes to the submodule to the gitmodules
+ * file on disk. You may also be interested in `git_submodule_init()` which
+ * writes submodule info to ".git/config" (which is better for local changes
+ * to submodule settings) and/or `git_submodule_sync()` which writes
+ * settings about remotes to the actual submodule repository.
+ *
+ * @param submodule The submodule to write.
+ * @return 0 on success, <0 on failure.
+ */
+GIT_EXTERN(int) git_submodule_save(git_submodule *submodule);
+
+/**
+ * Get the containing repository for a submodule.
+ *
+ * This returns a pointer to the repository that contains the submodule.
+ * This is a just a reference to the repository that was passed to the
+ * original `git_submodule_lookup()` call, so if that repository has been
+ * freed, then this may be a dangling reference.
+ *
+ * @param submodule Pointer to submodule object
+ * @return Pointer to `git_repository`
+ */
+GIT_EXTERN(git_repository *) git_submodule_owner(git_submodule *submodule);
+
+/**
+ * Get the name of submodule.
+ *
+ * @param submodule Pointer to submodule object
+ * @return Pointer to the submodule name
+ */
+GIT_EXTERN(const char *) git_submodule_name(git_submodule *submodule);
+
+/**
+ * Get the path to the submodule.
+ *
+ * The path is almost always the same as the submodule name, but the
+ * two are actually not required to match.
+ *
+ * @param submodule Pointer to submodule object
+ * @return Pointer to the submodule path
+ */
+GIT_EXTERN(const char *) git_submodule_path(git_submodule *submodule);
+
+/**
+ * Get the URL for the submodule.
+ *
+ * @param submodule Pointer to submodule object
+ * @return Pointer to the submodule url
+ */
+GIT_EXTERN(const char *) git_submodule_url(git_submodule *submodule);
+
+/**
+ * Set the URL for the submodule.
+ *
+ * This sets the URL in memory for the submodule. This will be used for
+ * any following submodule actions while this submodule data is in memory.
+ *
+ * After calling this, you may wish to call `git_submodule_save()` to write
+ * the changes back to the ".gitmodules" file and `git_submodule_sync()` to
+ * write the changes to the checked out submodule repository.
+ *
+ * @param submodule Pointer to the submodule object
+ * @param url URL that should be used for the submodule
+ * @return 0 on success, <0 on failure
+ */
+GIT_EXTERN(int) git_submodule_set_url(git_submodule *submodule, const char *url);
+
+/**
+ * Get the OID for the submodule in the index.
+ *
+ * @param submodule Pointer to submodule object
+ * @return Pointer to git_oid or NULL if submodule is not in index.
+ */
+GIT_EXTERN(const git_oid *) git_submodule_index_oid(git_submodule *submodule);
+
+/**
+ * Get the OID for the submodule in the current HEAD tree.
+ *
+ * @param submodule Pointer to submodule object
+ * @return Pointer to git_oid or NULL if submodule is not in the HEAD.
+ */
+GIT_EXTERN(const git_oid *) git_submodule_head_oid(git_submodule *submodule);
+
+/**
+ * Get the OID for the submodule in the current working directory.
+ *
+ * This returns the OID that corresponds to looking up 'HEAD' in the checked
+ * out submodule. If there are pending changes in the index or anything
+ * else, this won't notice that. You should call `git_submodule_status()`
+ * for a more complete picture about the state of the working directory.
+ *
+ * @param submodule Pointer to submodule object
+ * @return Pointer to git_oid or NULL if submodule is not checked out.
+ */
+GIT_EXTERN(const git_oid *) git_submodule_wd_oid(git_submodule *submodule);
+
+/**
+ * Get the ignore rule for the submodule.
+ *
+ * There are four ignore values:
+ *
+ * - **GIT_SUBMODULE_IGNORE_NONE** will consider any change to the contents
+ * of the submodule from a clean checkout to be dirty, including the
+ * addition of untracked files. This is the default if unspecified.
+ * - **GIT_SUBMODULE_IGNORE_UNTRACKED** examines the contents of the
+ * working tree (i.e. call `git_status_foreach()` on the submodule) but
+ * UNTRACKED files will not count as making the submodule dirty.
+ * - **GIT_SUBMODULE_IGNORE_DIRTY** means to only check if the HEAD of the
+ * submodule has moved for status. This is fast since it does not need to
+ * scan the working tree of the submodule at all.
+ * - **GIT_SUBMODULE_IGNORE_ALL** means not to open the submodule repo.
+ * The working directory will be consider clean so long as there is a
+ * checked out version present.
+ */
+GIT_EXTERN(git_submodule_ignore_t) git_submodule_ignore(
+ git_submodule *submodule);
+
+/**
+ * Set the ignore rule for the submodule.
+ *
+ * This sets the ignore rule in memory for the submodule. This will be used
+ * for any following actions (such as `git_submodule_status()`) while the
+ * submodule is in memory. You should call `git_submodule_save()` if you
+ * want to persist the new ignore role.
+ *
+ * Calling this again with GIT_SUBMODULE_IGNORE_DEFAULT or calling
+ * `git_submodule_reload()` will revert the rule to the value that was in the
+ * original config.
+ *
+ * @return old value for ignore
+ */
+GIT_EXTERN(git_submodule_ignore_t) git_submodule_set_ignore(
+ git_submodule *submodule,
+ git_submodule_ignore_t ignore);
+
+/**
+ * Get the update rule for the submodule.
+ */
+GIT_EXTERN(git_submodule_update_t) git_submodule_update(
+ git_submodule *submodule);
+
+/**
+ * Set the update rule for the submodule.
+ *
+ * This sets the update rule in memory for the submodule. You should call
+ * `git_submodule_save()` if you want to persist the new update rule.
+ *
+ * Calling this again with GIT_SUBMODULE_UPDATE_DEFAULT or calling
+ * `git_submodule_reload()` will revert the rule to the value that was in the
+ * original config.
+ *
+ * @return old value for update
+ */
+GIT_EXTERN(git_submodule_update_t) git_submodule_set_update(
+ git_submodule *submodule,
+ git_submodule_update_t update);
+
+/**
+ * Copy submodule info into ".git/config" file.
+ *
+ * Just like "git submodule init", this copies information about the
+ * submodule into ".git/config". You can use the accessor functions
+ * above to alter the in-memory git_submodule object and control what
+ * is written to the config, overriding what is in .gitmodules.
+ *
+ * @param submodule The submodule to write into the superproject config
+ * @param overwrite By default, existing entries will not be overwritten,
+ * but setting this to true forces them to be updated.
+ * @return 0 on success, <0 on failure.
+ */
+GIT_EXTERN(int) git_submodule_init(git_submodule *submodule, int overwrite);
+
+/**
+ * Copy submodule remote info into submodule repo.
+ *
+ * This copies the information about the submodules URL into the checked out
+ * submodule config, acting like "git submodule sync". This is useful if
+ * you have altered the URL for the submodule (or it has been altered by a
+ * fetch of upstream changes) and you need to update your local repo.
+ */
+GIT_EXTERN(int) git_submodule_sync(git_submodule *submodule);
+
+/**
+ * Open the repository for a submodule.
+ *
+ * This is a newly opened repository object. The caller is responsible for
+ * calling `git_repository_free()` on it when done. Multiple calls to this
+ * function will return distinct `git_repository` objects. This will only
+ * work if the submodule is checked out into the working directory.
+ *
+ * @param subrepo Pointer to the submodule repo which was opened
+ * @param submodule Submodule to be opened
+ * @return 0 on success, <0 if submodule repo could not be opened.
+ */
+GIT_EXTERN(int) git_submodule_open(
+ git_repository **repo,
+ git_submodule *submodule);
+
+/**
+ * Reread submodule info from config, index, and HEAD.
+ *
+ * Call this to reread cached submodule information for this submodule if
+ * you have reason to believe that it has changed.
+ */
+GIT_EXTERN(int) git_submodule_reload(git_submodule *submodule);
+
+/**
+ * Reread all submodule info.
+ *
+ * Call this to reload all cached submodule information for the repo.
+ */
+GIT_EXTERN(int) git_submodule_reload_all(git_repository *repo);
+
+/**
+ * Get the status for a submodule.
+ *
+ * This looks at a submodule and tries to determine the status. It
+ * will return a combination of the `GIT_SUBMODULE_STATUS` values above.
+ * How deeply it examines the working directory to do this will depend
+ * on the `git_submodule_ignore_t` value for the submodule - which can be
+ * set either temporarily or permanently with `git_submodule_set_ignore()`.
+ *
+ * @param status Combination of `GIT_SUBMODULE_STATUS` flags
+ * @param submodule Submodule for which to get status
+ * @return 0 on success, <0 on error
+ */
+GIT_EXTERN(int) git_submodule_status(
+ unsigned int *status,
+ git_submodule *submodule);
/** @} */
GIT_END_DECL
diff --git a/src/attr.c b/src/attr.c
index 8a7ff28c..99322066 100644
--- a/src/attr.c
+++ b/src/attr.c
@@ -590,6 +590,18 @@ static int collect_attr_files(
return error;
}
+static char *try_global_default(const char *relpath)
+{
+ git_buf dflt = GIT_BUF_INIT;
+ char *rval = NULL;
+
+ if (!git_futils_find_global_file(&dflt, relpath))
+ rval = git_buf_detach(&dflt);
+
+ git_buf_free(&dflt);
+
+ return rval;
+}
int git_attr_cache__init(git_repository *repo)
{
@@ -607,20 +619,14 @@ int git_attr_cache__init(git_repository *repo)
ret = git_config_get_string(&cache->cfg_attr_file, cfg, GIT_ATTR_CONFIG);
if (ret < 0 && ret != GIT_ENOTFOUND)
return ret;
+ if (ret == GIT_ENOTFOUND)
+ cache->cfg_attr_file = try_global_default(GIT_ATTR_CONFIG_DEFAULT);
ret = git_config_get_string(&cache->cfg_excl_file, cfg, GIT_IGNORE_CONFIG);
if (ret < 0 && ret != GIT_ENOTFOUND)
return ret;
-
- if (ret == GIT_ENOTFOUND) {
- git_buf dflt = GIT_BUF_INIT;
-
- ret = git_futils_find_global_file(&dflt, GIT_IGNORE_CONFIG_DEFAULT);
- if (!ret)
- cache->cfg_excl_file = git_buf_detach(&dflt);
-
- git_buf_free(&dflt);
- }
+ if (ret == GIT_ENOTFOUND)
+ cache->cfg_excl_file = try_global_default(GIT_IGNORE_CONFIG_DEFAULT);
giterr_clear();
diff --git a/src/attr.h b/src/attr.h
index 78cfb57c..7589bb10 100644
--- a/src/attr.h
+++ b/src/attr.h
@@ -11,6 +11,7 @@
#include "strmap.h"
#define GIT_ATTR_CONFIG "core.attributesfile"
+#define GIT_ATTR_CONFIG_DEFAULT ".config/git/attributes"
#define GIT_IGNORE_CONFIG "core.excludesfile"
#define GIT_IGNORE_CONFIG_DEFAULT ".config/git/ignore"
diff --git a/src/branch.c b/src/branch.c
index 52fed67a..f6f31403 100644
--- a/src/branch.c
+++ b/src/branch.c
@@ -57,7 +57,6 @@ int git_branch_create(
const git_object *target,
int force)
{
- git_otype target_type = GIT_OBJ_BAD;
git_object *commit = NULL;
git_reference *branch = NULL;
git_buf canonical_branch_name = GIT_BUF_INIT;
@@ -66,27 +65,8 @@ int git_branch_create(
assert(branch_name && target && ref_out);
assert(git_object_owner(target) == repository);
- target_type = git_object_type(target);
-
- switch (target_type)
- {
- case GIT_OBJ_TAG:
- if (git_tag_peel(&commit, (git_tag *)target) < 0)
- goto cleanup;
-
- if (git_object_type(commit) != GIT_OBJ_COMMIT) {
- create_error_invalid("The given target does not resolve to a commit");
- goto cleanup;
- }
- break;
-
- case GIT_OBJ_COMMIT:
- commit = (git_object *)target;
- break;
-
- default:
- return create_error_invalid("Only git_tag and git_commit objects are valid targets.");
- }
+ if (git_object_peel(&commit, (git_object *)target, GIT_OBJ_COMMIT) < 0)
+ return create_error_invalid("The given target does not resolve to a commit");
if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0)
goto cleanup;
@@ -99,9 +79,7 @@ int git_branch_create(
error = 0;
cleanup:
- if (target_type == GIT_OBJ_TAG)
- git_object_free(commit);
-
+ git_object_free(commit);
git_buf_free(&canonical_branch_name);
return error;
}
diff --git a/src/buffer.c b/src/buffer.c
index b57998e1..61cfaf9e 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -144,31 +144,40 @@ int git_buf_puts(git_buf *buf, const char *string)
int git_buf_puts_escaped(
git_buf *buf, const char *string, const char *esc_chars, const char *esc_with)
{
- const char *scan = string;
- size_t total = 0, esc_with_len = strlen(esc_with);
+ const char *scan;
+ size_t total = 0, esc_len = strlen(esc_with), count;
- while (*scan) {
- size_t count = strcspn(scan, esc_chars);
- total += count + 1 + esc_with_len;
- scan += count + 1;
+ if (!string)
+ return 0;
+
+ for (scan = string; *scan; ) {
+ /* count run of non-escaped characters */
+ count = strcspn(scan, esc_chars);
+ total += count;
+ scan += count;
+ /* count run of escaped characters */
+ count = strspn(scan, esc_chars);
+ total += count * (esc_len + 1);
+ scan += count;
}
ENSURE_SIZE(buf, buf->size + total + 1);
for (scan = string; *scan; ) {
- size_t count = strcspn(scan, esc_chars);
+ count = strcspn(scan, esc_chars);
memmove(buf->ptr + buf->size, scan, count);
scan += count;
buf->size += count;
- if (*scan) {
- memmove(buf->ptr + buf->size, esc_with, esc_with_len);
- buf->size += esc_with_len;
-
- memmove(buf->ptr + buf->size, scan, 1);
- scan += 1;
- buf->size += 1;
+ for (count = strspn(scan, esc_chars); count > 0; --count) {
+ /* copy escape sequence */
+ memmove(buf->ptr + buf->size, esc_with, esc_len);
+ buf->size += esc_len;
+ /* copy character to be escaped */
+ buf->ptr[buf->size] = *scan;
+ buf->size++;
+ scan++;
}
}
diff --git a/src/checkout.c b/src/checkout.c
index ac540391..88df2128 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -31,7 +31,7 @@ typedef struct tree_walk_data
git_checkout_opts *opts;
git_repository *repo;
git_odb *odb;
- bool do_symlinks;
+ bool no_symlinks;
} tree_walk_data;
@@ -48,9 +48,9 @@ static int blob_contents_to_link(tree_walk_data *data, git_buf *fnbuf,
/* Create the link */
const char *new = git_buf_cstr(&linktarget),
*old = git_buf_cstr(fnbuf);
- retcode = data->do_symlinks
- ? p_symlink(new, old)
- : git_futils_fake_symlink(new, old);
+ retcode = data->no_symlinks
+ ? git_futils_fake_symlink(new, old)
+ : p_symlink(new, old);
}
git_buf_free(&linktarget);
git_blob_free(blob);
@@ -176,13 +176,14 @@ int git_checkout_head(git_repository *repo, git_checkout_opts *opts, git_indexer
return GIT_ERROR;
}
+ memset(&payload, 0, sizeof(payload));
+
/* Determine if symlinks should be handled */
- if (!git_repository_config(&cfg, repo)) {
+ if (!git_repository_config__weakptr(&cfg, repo)) {
int temp = true;
if (!git_config_get_bool(&temp, cfg, "core.symlinks")) {
- payload.do_symlinks = !!temp;
+ payload.no_symlinks = !temp;
}
- git_config_free(cfg);
}
stats->total = stats->processed = 0;
diff --git a/src/config.c b/src/config.c
index 277daaaf..e62dccf5 100644
--- a/src/config.c
+++ b/src/config.c
@@ -449,7 +449,12 @@ int git_config_set_multivar(git_config *cfg, const char *name, const char *regex
int git_config_find_global_r(git_buf *path)
{
- return git_futils_find_global_file(path, GIT_CONFIG_FILENAME);
+ int error = git_futils_find_global_file(path, GIT_CONFIG_FILENAME);
+
+ if (error == GIT_ENOTFOUND)
+ error = git_futils_find_global_file(path, GIT_CONFIG_FILENAME_ALT);
+
+ return error;
}
int git_config_find_global(char *global_config_path, size_t length)
diff --git a/src/config.h b/src/config.h
index 82e98ce5..5475ef38 100644
--- a/src/config.h
+++ b/src/config.h
@@ -13,6 +13,7 @@
#include "repository.h"
#define GIT_CONFIG_FILENAME ".gitconfig"
+#define GIT_CONFIG_FILENAME_ALT ".config/git/config"
#define GIT_CONFIG_FILENAME_INREPO "config"
#define GIT_CONFIG_FILENAME_SYSTEM "gitconfig"
#define GIT_CONFIG_FILE_MODE 0666
diff --git a/src/config_file.c b/src/config_file.c
index 547509b9..d3fb56aa 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -195,7 +195,7 @@ static int file_foreach(
void *data)
{
diskfile_backend *b = (diskfile_backend *)backend;
- cvar_t *var;
+ cvar_t *var, *next_var;
const char *key;
regex_t regex;
int result = 0;
@@ -212,7 +212,9 @@ static int file_foreach(
}
git_strmap_foreach(b->values, key, var,
- for (; var != NULL; var = CVAR_LIST_NEXT(var)) {
+ for (; var != NULL; var = next_var) {
+ next_var = CVAR_LIST_NEXT(var);
+
/* skip non-matching keys if regexp was provided */
if (regexp && regexec(&regex, key, 0, NULL, 0) != 0)
continue;
@@ -253,11 +255,17 @@ static int config_set(git_config_file *cfg, const char *name, const char *value)
char *tmp = NULL;
git__free(key);
+
if (existing->next != NULL) {
giterr_set(GITERR_CONFIG, "Multivar incompatible with simple set");
return -1;
}
+ /* don't update if old and new values already match */
+ if ((!existing->value && !value) ||
+ (existing->value && value && !strcmp(existing->value, value)))
+ return 0;
+
if (value) {
tmp = git__strdup(value);
GITERR_CHECK_ALLOC(tmp);
diff --git a/src/config_file.h b/src/config_file.h
index c3129288..bf687b51 100644
--- a/src/config_file.h
+++ b/src/config_file.h
@@ -19,12 +19,24 @@ GIT_INLINE(void) git_config_file_free(git_config_file *cfg)
cfg->free(cfg);
}
+GIT_INLINE(int) git_config_file_get_string(
+ const char **out, git_config_file *cfg, const char *name)
+{
+ return cfg->get(cfg, name, out);
+}
+
GIT_INLINE(int) git_config_file_set_string(
git_config_file *cfg, const char *name, const char *value)
{
return cfg->set(cfg, name, value);
}
+GIT_INLINE(int) git_config_file_delete(
+ git_config_file *cfg, const char *name)
+{
+ return cfg->del(cfg, name);
+}
+
GIT_INLINE(int) git_config_file_foreach(
git_config_file *cfg,
int (*fn)(const char *key, const char *value, void *data),
diff --git a/src/diff.c b/src/diff.c
index 9abf8b9f..430f52e0 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -530,7 +530,7 @@ static int maybe_modified(
status = GIT_DELTA_UNMODIFIED;
else if (git_submodule_lookup(&sub, diff->repo, nitem->path) < 0)
return -1;
- else if (sub->ignore == GIT_SUBMODULE_IGNORE_ALL)
+ else if (git_submodule_ignore(sub) == GIT_SUBMODULE_IGNORE_ALL)
status = GIT_DELTA_UNMODIFIED;
else {
/* TODO: support other GIT_SUBMODULE_IGNORE values */
diff --git a/src/diff_output.c b/src/diff_output.c
index d269a4ce..2bf939f3 100644
--- a/src/diff_output.c
+++ b/src/diff_output.c
@@ -718,6 +718,25 @@ int git_diff_print_patch(
return error;
}
+int git_diff_entrycount(git_diff_list *diff, int delta_t)
+{
+ int count = 0;
+ unsigned int i;
+ git_diff_delta *delta;
+
+ assert(diff);
+
+ if (delta_t < 0)
+ return diff->deltas.length;
+
+ git_vector_foreach(&diff->deltas, i, delta) {
+ if (delta->status == (git_delta_t)delta_t)
+ count++;
+ }
+
+ return count;
+}
+
int git_diff_blobs(
git_blob *old_blob,
git_blob *new_blob,
diff --git a/src/errors.c b/src/errors.c
index d43d7d9b..802ad364 100644
--- a/src/errors.c
+++ b/src/errors.c
@@ -110,6 +110,11 @@ void giterr_set_regex(const regex_t *regex, int error_code)
void giterr_clear(void)
{
GIT_GLOBAL->last_error = NULL;
+
+ errno = 0;
+#ifdef GIT_WIN32
+ SetLastError(0);
+#endif
}
const git_error *giterr_last(void)
diff --git a/src/fetch.c b/src/fetch.c
index d96ac778..278ba3c5 100644
--- a/src/fetch.c
+++ b/src/fetch.c
@@ -292,6 +292,28 @@ int git_fetch_download_pack(git_remote *remote, git_off_t *bytes, git_indexer_st
}
+static int no_sideband(git_indexer_stream *idx, gitno_buffer *buf, git_off_t *bytes, git_indexer_stats *stats)
+{
+ int recvd;
+
+ do {
+ if (git_indexer_stream_add(idx, buf->data, buf->offset, stats) < 0)
+ return -1;
+
+ gitno_consume_n(buf, buf->offset);
+
+ if ((recvd = gitno_recv(buf)) < 0)
+ return -1;
+
+ *bytes += recvd;
+ } while(recvd > 0);
+
+ if (git_indexer_stream_finalize(idx, stats))
+ return -1;
+
+ return 0;
+}
+
/* Receiving data from a socket and storing it is pretty much the same for git and HTTP */
int git_fetch__download_pack(
git_transport *t,
@@ -299,7 +321,6 @@ int git_fetch__download_pack(
git_off_t *bytes,
git_indexer_stats *stats)
{
- int recvd;
git_buf path = GIT_BUF_INIT;
gitno_buffer *buf = &t->buffer;
git_indexer_stream *idx = NULL;
@@ -314,19 +335,45 @@ int git_fetch__download_pack(
memset(stats, 0, sizeof(git_indexer_stats));
*bytes = 0;
- do {
- if (git_indexer_stream_add(idx, buf->data, buf->offset, stats) < 0)
+ /*
+ * If the remote doesn't support the side-band, we can feed
+ * the data directly to the indexer. Otherwise, we need to
+ * check which one belongs there.
+ */
+ if (!t->caps.side_band && !t->caps.side_band_64k) {
+ if (no_sideband(idx, buf, bytes, stats) < 0)
goto on_error;
- gitno_consume_n(buf, buf->offset);
+ git_indexer_stream_free(idx);
+ return 0;
+ }
- if ((recvd = gitno_recv(buf)) < 0)
+ do {
+ git_pkt *pkt;
+ if (recv_pkt(&pkt, buf) < 0)
goto on_error;
- *bytes += recvd;
- } while(recvd > 0);
+ if (pkt->type == GIT_PKT_PROGRESS) {
+ if (t->progress_cb) {
+ git_pkt_progress *p = (git_pkt_progress *) pkt;
+ t->progress_cb(p->data, p->len, t->cb_data);
+ }
+ git__free(pkt);
+ } else if (pkt->type == GIT_PKT_DATA) {
+ git_pkt_data *p = (git_pkt_data *) pkt;
+ *bytes += p->len;
+ if (git_indexer_stream_add(idx, p->data, p->len, stats) < 0)
+ goto on_error;
- if (git_indexer_stream_finalize(idx, stats))
+ git__free(pkt);
+ } else if (pkt->type == GIT_PKT_FLUSH) {
+ /* A flush indicates the end of the packfile */
+ git__free(pkt);
+ break;
+ }
+ } while (1);
+
+ if (git_indexer_stream_finalize(idx, stats) < 0)
goto on_error;
git_indexer_stream_free(idx);
diff --git a/src/filebuf.c b/src/filebuf.c
index 8b3ebb3e..cfc8528e 100644
--- a/src/filebuf.c
+++ b/src/filebuf.c
@@ -50,6 +50,7 @@ static int lock_file(git_filebuf *file, int flags)
if (flags & GIT_FILEBUF_FORCE)
p_unlink(file->path_lock);
else {
+ giterr_clear(); /* actual OS error code just confuses */
giterr_set(GITERR_OS,
"Failed to lock file '%s' for writing", file->path_lock);
return -1;
diff --git a/src/fileops.c b/src/fileops.c
index eecfc284..76ef8c91 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -700,6 +700,7 @@ int git_futils_cp_r(
error = _cp_r_callback(&info, &path);
git_buf_free(&path);
+ git_buf_free(&info.to);
return error;
}
diff --git a/src/indexer.c b/src/indexer.c
index 797a5827..85ffb161 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -324,8 +324,8 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz
if (git_vector_init(&idx->deltas, (unsigned int)(idx->nr_objects / 2), NULL) < 0)
return -1;
+ memset(stats, 0, sizeof(git_indexer_stats));
stats->total = (unsigned int)idx->nr_objects;
- stats->processed = 0;
}
/* Now that we have data in the pack, let's try to parse it */
@@ -361,6 +361,7 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz
if (error < 0)
return error;
+ stats->received++;
continue;
}
@@ -379,6 +380,7 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz
git__free(obj.data);
stats->processed = (unsigned int)++processed;
+ stats->received++;
}
return 0;
@@ -577,9 +579,11 @@ void git_indexer_stream_free(git_indexer_stream *idx)
git_vector_foreach(&idx->objects, i, e)
git__free(e);
git_vector_free(&idx->objects);
- git_vector_foreach(&idx->pack->cache, i, pe)
- git__free(pe);
- git_vector_free(&idx->pack->cache);
+ if (idx->pack) {
+ git_vector_foreach(&idx->pack->cache, i, pe)
+ git__free(pe);
+ git_vector_free(&idx->pack->cache);
+ }
git_vector_foreach(&idx->deltas, i, delta)
git__free(delta);
git_vector_free(&idx->deltas);
diff --git a/src/iterator.c b/src/iterator.c
index 819b0e22..92fe6713 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -525,7 +525,9 @@ static int workdir_iterator__advance(
while ((wf = wi->stack) != NULL) {
next = git_vector_get(&wf->entries, ++wf->index);
if (next != NULL) {
- if (strcmp(next->path, DOT_GIT "/") == 0)
+ /* match git's behavior of ignoring anything named ".git" */
+ if (strcmp(next->path, DOT_GIT "/") == 0 ||
+ strcmp(next->path, DOT_GIT) == 0)
continue;
/* else found a good entry */
break;
@@ -607,8 +609,8 @@ static int workdir_iterator__update_entry(workdir_iterator *wi)
wi->entry.path = ps->path;
- /* skip over .git directory */
- if (strcmp(ps->path, DOT_GIT "/") == 0)
+ /* skip over .git entry */
+ if (strcmp(ps->path, DOT_GIT "/") == 0 || strcmp(ps->path, DOT_GIT) == 0)
return workdir_iterator__advance((git_iterator *)wi, NULL);
/* if there is an error processing the entry, treat as ignored */
@@ -629,15 +631,10 @@ static int workdir_iterator__update_entry(workdir_iterator *wi)
/* detect submodules */
if (S_ISDIR(wi->entry.mode)) {
- bool is_submodule = git_path_contains(&wi->path, DOT_GIT);
-
- /* if there is no .git, still check submodules data */
- if (!is_submodule) {
- int res = git_submodule_lookup(NULL, wi->repo, wi->entry.path);
- is_submodule = (res == 0);
- if (res == GIT_ENOTFOUND)
- giterr_clear();
- }
+ int res = git_submodule_lookup(NULL, wi->repo, wi->entry.path);
+ bool is_submodule = (res == 0);
+ if (res == GIT_ENOTFOUND)
+ giterr_clear();
/* if submodule, mark as GITLINK and remove trailing slash */
if (is_submodule) {
diff --git a/src/oid.c b/src/oid.c
index 821442d1..127ad611 100644
--- a/src/oid.c
+++ b/src/oid.c
@@ -24,9 +24,6 @@ int git_oid_fromstrn(git_oid *out, const char *str, size_t length)
size_t p;
int v;
- if (length < 4)
- return oid_error_invalid("input too short");
-
if (length > GIT_OID_HEXSZ)
length = GIT_OID_HEXSZ;
diff --git a/src/pkt.c b/src/pkt.c
index 8c916fff..ad0149d3 100644
--- a/src/pkt.c
+++ b/src/pkt.c
@@ -17,6 +17,7 @@
#include "netops.h"
#include "posix.h"
#include "buffer.h"
+#include "protocol.h"
#include <ctype.h>
@@ -130,6 +131,42 @@ static int err_pkt(git_pkt **out, const char *line, size_t len)
return 0;
}
+static int data_pkt(git_pkt **out, const char *line, size_t len)
+{
+ git_pkt_data *pkt;
+
+ line++;
+ len--;
+ pkt = git__malloc(sizeof(git_pkt_data) + len);
+ GITERR_CHECK_ALLOC(pkt);
+
+ pkt->type = GIT_PKT_DATA;
+ pkt->len = (int) len;
+ memcpy(pkt->data, line, len);
+
+ *out = (git_pkt *) pkt;
+
+ return 0;
+}
+
+static int progress_pkt(git_pkt **out, const char *line, size_t len)
+{
+ git_pkt_progress *pkt;
+
+ line++;
+ len--;
+ pkt = git__malloc(sizeof(git_pkt_progress) + len);
+ GITERR_CHECK_ALLOC(pkt);
+
+ pkt->type = GIT_PKT_PROGRESS;
+ pkt->len = (int) len;
+ memcpy(pkt->data, line, len);
+
+ *out = (git_pkt *) pkt;
+
+ return 0;
+}
+
/*
* Parse an other-ref line.
*/
@@ -263,8 +300,11 @@ int git_pkt_parse_line(
len -= PKT_LEN_SIZE; /* the encoded length includes its own size */
- /* Assming the minimal size is actually 4 */
- if (!git__prefixcmp(line, "ACK"))
+ if (*line == GIT_SIDE_BAND_DATA)
+ ret = data_pkt(head, line, len);
+ else if (*line == GIT_SIDE_BAND_PROGRESS)
+ ret = progress_pkt(head, line, len);
+ else if (!git__prefixcmp(line, "ACK"))
ret = ack_pkt(head, line, len);
else if (!git__prefixcmp(line, "NAK"))
ret = nak_pkt(head);
@@ -301,6 +341,13 @@ static int buffer_want_with_caps(git_remote_head *head, git_transport_caps *caps
char oid[GIT_OID_HEXSZ +1] = {0};
unsigned int len;
+ /* Prefer side-band-64k if the server supports both */
+ if (caps->side_band) {
+ if (caps->side_band_64k)
+ git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND_64K);
+ else
+ git_buf_printf(&str, "%s ", GIT_CAP_SIDE_BAND);
+ }
if (caps->ofs_delta)
git_buf_puts(&str, GIT_CAP_OFS_DELTA " ");
diff --git a/src/pkt.h b/src/pkt.h
index 75442c83..0fdb5c7c 100644
--- a/src/pkt.h
+++ b/src/pkt.h
@@ -24,6 +24,8 @@ enum git_pkt_type {
GIT_PKT_PACK,
GIT_PKT_COMMENT,
GIT_PKT_ERR,
+ GIT_PKT_DATA,
+ GIT_PKT_PROGRESS,
};
/* Used for multi-ack */
@@ -67,6 +69,14 @@ typedef struct {
typedef struct {
enum git_pkt_type type;
+ int len;
+ char data[GIT_FLEX_ARRAY];
+} git_pkt_data;
+
+typedef git_pkt_data git_pkt_progress;
+
+typedef struct {
+ enum git_pkt_type type;
char error[GIT_FLEX_ARRAY];
} git_pkt_err;
diff --git a/src/protocol.c b/src/protocol.c
index 20d6e230..4526c857 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -80,6 +80,20 @@ int git_protocol_detect_caps(git_pkt_ref *pkt, git_transport_caps *caps)
continue;
}
+ /* Keep side-band check after side-band-64k */
+ if(!git__prefixcmp(ptr, GIT_CAP_SIDE_BAND_64K)) {
+ caps->common = caps->side_band_64k = 1;
+ ptr += strlen(GIT_CAP_SIDE_BAND_64K);
+ continue;
+ }
+
+ if(!git__prefixcmp(ptr, GIT_CAP_SIDE_BAND)) {
+ caps->common = caps->side_band = 1;
+ ptr += strlen(GIT_CAP_SIDE_BAND);
+ continue;
+ }
+
+
/* We don't know this capability, so skip it */
ptr = strchr(ptr, ' ');
}
diff --git a/src/protocol.h b/src/protocol.h
index 615be8d6..a990938e 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -14,4 +14,8 @@
int git_protocol_store_refs(git_transport *t, int flushes);
int git_protocol_detect_caps(git_pkt_ref *pkt, git_transport_caps *caps);
+#define GIT_SIDE_BAND_DATA 1
+#define GIT_SIDE_BAND_PROGRESS 2
+#define GIT_SIDE_BAND_ERROR 3
+
#endif
diff --git a/src/remote.c b/src/remote.c
index fe026b17..7bc631d4 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -386,6 +386,9 @@ int git_remote_connect(git_remote *remote, int direction)
if (git_transport_new(&t, url) < 0)
return -1;
+ t->progress_cb = remote->callbacks.progress;
+ t->cb_data = remote->callbacks.data;
+
t->check_cert = remote->check_cert;
if (t->connect(t, direction) < 0) {
goto on_error;
@@ -646,4 +649,9 @@ void git_remote_set_callbacks(git_remote *remote, git_remote_callbacks *callback
assert(remote && callbacks);
memcpy(&remote->callbacks, callbacks, sizeof(git_remote_callbacks));
+
+ if (remote->transport) {
+ remote->transport->progress_cb = remote->callbacks.progress;
+ remote->transport->cb_data = remote->callbacks.data;
+ }
}
diff --git a/src/repository.c b/src/repository.c
index 18788d18..c12df25c 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -146,8 +146,13 @@ static int load_workdir(git_repository *repo, git_buf *parent_path)
return -1;
error = git_config_get_string(&worktree, config, "core.worktree");
- if (!error && worktree != NULL)
- repo->workdir = git__strdup(worktree);
+ if (!error && worktree != NULL) {
+ error = git_path_prettify_dir(
+ &worktree_buf, worktree, repo->path_repository);
+ if (error < 0)
+ return error;
+ repo->workdir = git_buf_detach(&worktree_buf);
+ }
else if (error != GIT_ENOTFOUND)
return error;
else {
diff --git a/src/revwalk.c b/src/revwalk.c
index 9dff283f..8b0e93ba 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -264,12 +264,7 @@ static int commit_parse(git_revwalk *walk, commit_object *commit)
if ((error = git_odb_read(&obj, walk->odb, &commit->oid)) < 0)
return error;
-
- if (obj->raw.type != GIT_OBJ_COMMIT) {
- git_odb_object_free(obj);
- giterr_set(GITERR_INVALID, "Failed to parse commit. Object is no commit object");
- return -1;
- }
+ assert(obj->raw.type == GIT_OBJ_COMMIT);
error = commit_quick_parse(walk, commit, &obj->raw);
git_odb_object_free(obj);
@@ -515,8 +510,21 @@ static int process_commit_parents(git_revwalk *walk, commit_object *commit)
static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting)
{
+ git_object *obj;
+ git_otype type;
commit_object *commit;
+ if (git_object_lookup(&obj, walk->repo, oid, GIT_OBJ_ANY) < 0)
+ return -1;
+
+ type = git_object_type(obj);
+ git_object_free(obj);
+
+ if (type != GIT_OBJ_COMMIT) {
+ giterr_set(GITERR_INVALID, "Object is no commit object");
+ return -1;
+ }
+
commit = commit_lookup(walk, oid);
if (commit == NULL)
return -1; /* error already reported by failed lookup */
diff --git a/src/submodule.c b/src/submodule.c
index b8537cb8..a9de9ee6 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -17,18 +17,24 @@
#include "config_file.h"
#include "config.h"
#include "repository.h"
+#include "submodule.h"
+#include "tree.h"
+#include "iterator.h"
+
+#define GIT_MODULES_FILE ".gitmodules"
static git_cvar_map _sm_update_map[] = {
{GIT_CVAR_STRING, "checkout", GIT_SUBMODULE_UPDATE_CHECKOUT},
{GIT_CVAR_STRING, "rebase", GIT_SUBMODULE_UPDATE_REBASE},
- {GIT_CVAR_STRING, "merge", GIT_SUBMODULE_UPDATE_MERGE}
+ {GIT_CVAR_STRING, "merge", GIT_SUBMODULE_UPDATE_MERGE},
+ {GIT_CVAR_STRING, "none", GIT_SUBMODULE_UPDATE_NONE},
};
static git_cvar_map _sm_ignore_map[] = {
- {GIT_CVAR_STRING, "all", GIT_SUBMODULE_IGNORE_ALL},
- {GIT_CVAR_STRING, "dirty", GIT_SUBMODULE_IGNORE_DIRTY},
+ {GIT_CVAR_STRING, "none", GIT_SUBMODULE_IGNORE_NONE},
{GIT_CVAR_STRING, "untracked", GIT_SUBMODULE_IGNORE_UNTRACKED},
- {GIT_CVAR_STRING, "none", GIT_SUBMODULE_IGNORE_NONE}
+ {GIT_CVAR_STRING, "dirty", GIT_SUBMODULE_IGNORE_DIRTY},
+ {GIT_CVAR_STRING, "all", GIT_SUBMODULE_IGNORE_ALL},
};
static kh_inline khint_t str_hash_no_trailing_slash(const char *s)
@@ -36,7 +42,7 @@ static kh_inline khint_t str_hash_no_trailing_slash(const char *s)
khint_t h;
for (h = 0; *s; ++s)
- if (s[1] || *s != '/')
+ if (s[1] != '\0' || *s != '/')
h = (h << 5) - h + *s;
return h;
@@ -47,29 +53,790 @@ static kh_inline int str_equal_no_trailing_slash(const char *a, const char *b)
size_t alen = a ? strlen(a) : 0;
size_t blen = b ? strlen(b) : 0;
- if (alen && a[alen] == '/')
+ if (alen > 0 && a[alen - 1] == '/')
alen--;
- if (blen && b[blen] == '/')
+ if (blen > 0 && b[blen - 1] == '/')
blen--;
return (alen == blen && strncmp(a, b, alen) == 0);
}
-__KHASH_IMPL(str, static kh_inline, const char *, void *, 1, str_hash_no_trailing_slash, str_equal_no_trailing_slash);
+__KHASH_IMPL(
+ str, static kh_inline, const char *, void *, 1,
+ str_hash_no_trailing_slash, str_equal_no_trailing_slash);
+
+static int load_submodule_config(git_repository *repo, bool force);
+static git_config_file *open_gitmodules(git_repository *, bool, const git_oid *);
+static int lookup_head_remote(git_buf *url, git_repository *repo);
+static int submodule_get(git_submodule **, git_repository *, const char *, const char *);
+static void submodule_release(git_submodule *sm, int decr);
+static int submodule_load_from_index(git_repository *, const git_index_entry *);
+static int submodule_load_from_head(git_repository*, const char*, const git_oid*);
+static int submodule_load_from_config(const char *, const char *, void *);
+static int submodule_load_from_wd_lite(git_submodule *, const char *, void *);
+static int submodule_update_config(git_submodule *, const char *, const char *, bool, bool);
+static void submodule_mode_mismatch(git_repository *, const char *, unsigned int);
+static int submodule_index_status(unsigned int *status, git_submodule *sm);
+static int submodule_wd_status(unsigned int *status, git_submodule *sm);
-static git_submodule *submodule_alloc(const char *name)
+static int submodule_cmp(const void *a, const void *b)
{
- git_submodule *sm = git__calloc(1, sizeof(git_submodule));
- if (sm == NULL)
- return sm;
+ return strcmp(((git_submodule *)a)->name, ((git_submodule *)b)->name);
+}
- sm->path = sm->name = git__strdup(name);
- if (!sm->name) {
- git__free(sm);
+static int submodule_config_key_trunc_puts(git_buf *key, const char *suffix)
+{
+ ssize_t idx = git_buf_rfind(key, '.');
+ git_buf_truncate(key, (size_t)(idx + 1));
+ return git_buf_puts(key, suffix);
+}
+
+/*
+ * PUBLIC APIS
+ */
+
+int git_submodule_lookup(
+ git_submodule **sm_ptr, /* NULL if user only wants to test existence */
+ git_repository *repo,
+ const char *name) /* trailing slash is allowed */
+{
+ int error;
+ khiter_t pos;
+
+ assert(repo && name);
+
+ if ((error = load_submodule_config(repo, false)) < 0)
+ return error;
+
+ pos = git_strmap_lookup_index(repo->submodules, name);
+
+ if (!git_strmap_valid_index(repo->submodules, pos)) {
+ error = GIT_ENOTFOUND;
+
+ /* check if a plausible submodule exists at path */
+ if (git_repository_workdir(repo)) {
+ git_buf path = GIT_BUF_INIT;
+
+ if (git_buf_joinpath(&path, git_repository_workdir(repo), name) < 0)
+ return -1;
+
+ if (git_path_contains_dir(&path, DOT_GIT))
+ error = GIT_EEXISTS;
+
+ git_buf_free(&path);
+ }
+
+ return error;
+ }
+
+ if (sm_ptr)
+ *sm_ptr = git_strmap_value_at(repo->submodules, pos);
+
+ return 0;
+}
+
+int git_submodule_foreach(
+ git_repository *repo,
+ int (*callback)(git_submodule *sm, const char *name, void *payload),
+ void *payload)
+{
+ int error;
+ git_submodule *sm;
+ git_vector seen = GIT_VECTOR_INIT;
+ seen._cmp = submodule_cmp;
+
+ assert(repo && callback);
+
+ if ((error = load_submodule_config(repo, false)) < 0)
+ return error;
+
+ git_strmap_foreach_value(repo->submodules, sm, {
+ /* Usually the following will not come into play - it just prevents
+ * us from issuing a callback twice for a submodule where the name
+ * and path are not the same.
+ */
+ if (sm->refcount > 1) {
+ if (git_vector_bsearch(&seen, sm) != GIT_ENOTFOUND)
+ continue;
+ if ((error = git_vector_insert(&seen, sm)) < 0)
+ break;
+ }
+
+ if (callback(sm, sm->name, payload)) {
+ error = GIT_EUSER;
+ break;
+ }
+ });
+
+ git_vector_free(&seen);
+
+ return error;
+}
+
+void git_submodule_config_free(git_repository *repo)
+{
+ git_strmap *smcfg;
+ git_submodule *sm;
+
+ assert(repo);
+
+ smcfg = repo->submodules;
+ repo->submodules = NULL;
+
+ if (smcfg == NULL)
+ return;
+
+ git_strmap_foreach_value(smcfg, sm, {
+ submodule_release(sm,1);
+ });
+ git_strmap_free(smcfg);
+}
+
+int git_submodule_add_setup(
+ git_submodule **submodule,
+ git_repository *repo,
+ const char *url,
+ const char *path,
+ int use_gitlink)
+{
+ int error = 0;
+ git_config_file *mods = NULL;
+ git_submodule *sm;
+ git_buf name = GIT_BUF_INIT, real_url = GIT_BUF_INIT;
+ git_repository_init_options initopt;
+ git_repository *subrepo = NULL;
+
+ assert(repo && url && path);
+
+ /* see if there is already an entry for this submodule */
+
+ if (git_submodule_lookup(&sm, repo, path) < 0)
+ giterr_clear();
+ else {
+ giterr_set(GITERR_SUBMODULE,
+ "Attempt to add a submodule that already exists");
+ return GIT_EEXISTS;
+ }
+
+ /* resolve parameters */
+
+ if (url[0] == '.' && (url[1] == '/' || (url[1] == '.' && url[2] == '/'))) {
+ if (!(error = lookup_head_remote(&real_url, repo)))
+ error = git_path_apply_relative(&real_url, url);
+ } else if (strchr(url, ':') != NULL || url[0] == '/') {
+ error = git_buf_sets(&real_url, url);
+ } else {
+ giterr_set(GITERR_SUBMODULE, "Invalid format for submodule URL");
+ error = -1;
+ }
+ if (error)
+ goto cleanup;
+
+ /* validate and normalize path */
+
+ if (git__prefixcmp(path, git_repository_workdir(repo)) == 0)
+ path += strlen(git_repository_workdir(repo));
+
+ if (git_path_root(path) >= 0) {
+ giterr_set(GITERR_SUBMODULE, "Submodule path must be a relative path");
+ error = -1;
+ goto cleanup;
+ }
+
+ /* update .gitmodules */
+
+ if ((mods = open_gitmodules(repo, true, NULL)) == NULL) {
+ giterr_set(GITERR_SUBMODULE,
+ "Adding submodules to a bare repository is not supported (for now)");
+ return -1;
+ }
+
+ if ((error = git_buf_printf(&name, "submodule.%s.path", path)) < 0 ||
+ (error = git_config_file_set_string(mods, name.ptr, path)) < 0)
+ goto cleanup;
+
+ if ((error = submodule_config_key_trunc_puts(&name, "url")) < 0 ||
+ (error = git_config_file_set_string(mods, name.ptr, real_url.ptr)) < 0)
+ goto cleanup;
+
+ git_buf_clear(&name);
+
+ /* init submodule repository and add origin remote as needed */
+
+ error = git_buf_joinpath(&name, git_repository_workdir(repo), path);
+ if (error < 0)
+ goto cleanup;
+
+ /* New style: sub-repo goes in <repo-dir>/modules/<name>/ with a
+ * gitlink in the sub-repo workdir directory to that repository
+ *
+ * Old style: sub-repo goes directly into repo/<name>/.git/
+ */
+
+ memset(&initopt, 0, sizeof(initopt));
+ initopt.flags = GIT_REPOSITORY_INIT_MKPATH |
+ GIT_REPOSITORY_INIT_NO_REINIT;
+ initopt.origin_url = real_url.ptr;
+
+ if (git_path_exists(name.ptr) &&
+ git_path_contains(&name, DOT_GIT))
+ {
+ /* repo appears to already exist - reinit? */
+ }
+ else if (use_gitlink) {
+ git_buf repodir = GIT_BUF_INIT;
+
+ error = git_buf_join_n(
+ &repodir, '/', 3, git_repository_path(repo), "modules", path);
+ if (error < 0)
+ goto cleanup;
+
+ initopt.workdir_path = name.ptr;
+ initopt.flags |= GIT_REPOSITORY_INIT_NO_DOTGIT_DIR;
+
+ error = git_repository_init_ext(&subrepo, repodir.ptr, &initopt);
+
+ git_buf_free(&repodir);
+ }
+ else {
+ error = git_repository_init_ext(&subrepo, name.ptr, &initopt);
+ }
+ if (error < 0)
+ goto cleanup;
+
+ /* add submodule to hash and "reload" it */
+
+ if (!(error = submodule_get(&sm, repo, path, NULL)) &&
+ !(error = git_submodule_reload(sm)))
+ error = git_submodule_init(sm, false);
+
+cleanup:
+ if (submodule != NULL)
+ *submodule = !error ? sm : NULL;
+
+ if (mods != NULL)
+ git_config_file_free(mods);
+ git_repository_free(subrepo);
+ git_buf_free(&real_url);
+ git_buf_free(&name);
+
+ return error;
+}
+
+int git_submodule_add_finalize(git_submodule *sm)
+{
+ int error;
+ git_index *index;
+
+ assert(sm);
+
+ if ((error = git_repository_index__weakptr(&index, sm->owner)) < 0 ||
+ (error = git_index_add(index, GIT_MODULES_FILE, 0)) < 0)
+ return error;
+
+ return git_submodule_add_to_index(sm, true);
+}
+
+int git_submodule_add_to_index(git_submodule *sm, int write_index)
+{
+ int error;
+ git_repository *repo, *sm_repo;
+ git_index *index;
+ git_buf path = GIT_BUF_INIT;
+ git_commit *head;
+ git_index_entry entry;
+ struct stat st;
+
+ assert(sm);
+
+ repo = sm->owner;
+
+ /* force reload of wd OID by git_submodule_open */
+ sm->flags = sm->flags & ~GIT_SUBMODULE_STATUS__WD_OID_VALID;
+
+ if ((error = git_repository_index__weakptr(&index, repo)) < 0 ||
+ (error = git_buf_joinpath(
+ &path, git_repository_workdir(repo), sm->path)) < 0 ||
+ (error = git_submodule_open(&sm_repo, sm)) < 0)
+ goto cleanup;
+
+ /* read stat information for submodule working directory */
+ if (p_stat(path.ptr, &st) < 0) {
+ giterr_set(GITERR_SUBMODULE,
+ "Cannot add submodule without working directory");
+ error = -1;
+ goto cleanup;
+ }
+
+ memset(&entry, 0, sizeof(entry));
+ entry.path = sm->path;
+ git_index__init_entry_from_stat(&st, &entry);
+
+ /* calling git_submodule_open will have set sm->wd_oid if possible */
+ if ((sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) == 0) {
+ giterr_set(GITERR_SUBMODULE,
+ "Cannot add submodule without HEAD to index");
+ error = -1;
+ goto cleanup;
+ }
+ git_oid_cpy(&entry.oid, &sm->wd_oid);
+
+ if ((error = git_commit_lookup(&head, sm_repo, &sm->wd_oid)) < 0)
+ goto cleanup;
+
+ entry.ctime.seconds = git_commit_time(head);
+ entry.ctime.nanoseconds = 0;
+ entry.mtime.seconds = git_commit_time(head);
+ entry.mtime.nanoseconds = 0;
+
+ git_commit_free(head);
+
+ /* add it */
+ error = git_index_add2(index, &entry);
+
+ /* write it, if requested */
+ if (!error && write_index) {
+ error = git_index_write(index);
+
+ if (!error)
+ git_oid_cpy(&sm->index_oid, &sm->wd_oid);
+ }
+
+cleanup:
+ git_repository_free(sm_repo);
+ git_buf_free(&path);
+ return error;
+}
+
+int git_submodule_save(git_submodule *submodule)
+{
+ int error = 0;
+ git_config_file *mods;
+ git_buf key = GIT_BUF_INIT;
+
+ assert(submodule);
+
+ mods = open_gitmodules(submodule->owner, true, NULL);
+ if (!mods) {
+ giterr_set(GITERR_SUBMODULE,
+ "Adding submodules to a bare repository is not supported (for now)");
+ return -1;
+ }
+
+ if ((error = git_buf_printf(&key, "submodule.%s.", submodule->name)) < 0)
+ goto cleanup;
+
+ /* save values for path, url, update, ignore, fetchRecurseSubmodules */
+
+ if ((error = submodule_config_key_trunc_puts(&key, "path")) < 0 ||
+ (error = git_config_file_set_string(mods, key.ptr, submodule->path)) < 0)
+ goto cleanup;
+
+ if ((error = submodule_config_key_trunc_puts(&key, "url")) < 0 ||
+ (error = git_config_file_set_string(mods, key.ptr, submodule->url)) < 0)
+ goto cleanup;
+
+ if (!(error = submodule_config_key_trunc_puts(&key, "update")) &&
+ submodule->update != GIT_SUBMODULE_UPDATE_DEFAULT)
+ {
+ const char *val = (submodule->update == GIT_SUBMODULE_UPDATE_CHECKOUT) ?
+ NULL : _sm_update_map[submodule->update].str_match;
+ error = git_config_file_set_string(mods, key.ptr, val);
+ }
+ if (error < 0)
+ goto cleanup;
+
+ if (!(error = submodule_config_key_trunc_puts(&key, "ignore")) &&
+ submodule->ignore != GIT_SUBMODULE_IGNORE_DEFAULT)
+ {
+ const char *val = (submodule->ignore == GIT_SUBMODULE_IGNORE_NONE) ?
+ NULL : _sm_ignore_map[submodule->ignore].str_match;
+ error = git_config_file_set_string(mods, key.ptr, val);
+ }
+ if (error < 0)
+ goto cleanup;
+
+ if ((error = submodule_config_key_trunc_puts(
+ &key, "fetchRecurseSubmodules")) < 0 ||
+ (error = git_config_file_set_string(
+ mods, key.ptr, submodule->fetch_recurse ? "true" : "false")) < 0)
+ goto cleanup;
+
+ /* update internal defaults */
+
+ submodule->ignore_default = submodule->ignore;
+ submodule->update_default = submodule->update;
+ submodule->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG;
+
+cleanup:
+ if (mods != NULL)
+ git_config_file_free(mods);
+ git_buf_free(&key);
+
+ return error;
+}
+
+git_repository *git_submodule_owner(git_submodule *submodule)
+{
+ assert(submodule);
+ return submodule->owner;
+}
+
+const char *git_submodule_name(git_submodule *submodule)
+{
+ assert(submodule);
+ return submodule->name;
+}
+
+const char *git_submodule_path(git_submodule *submodule)
+{
+ assert(submodule);
+ return submodule->path;
+}
+
+const char *git_submodule_url(git_submodule *submodule)
+{
+ assert(submodule);
+ return submodule->url;
+}
+
+int git_submodule_set_url(git_submodule *submodule, const char *url)
+{
+ assert(submodule && url);
+
+ git__free(submodule->url);
+
+ submodule->url = git__strdup(url);
+ GITERR_CHECK_ALLOC(submodule->url);
+
+ return 0;
+}
+
+const git_oid *git_submodule_index_oid(git_submodule *submodule)
+{
+ assert(submodule);
+
+ if (submodule->flags & GIT_SUBMODULE_STATUS__INDEX_OID_VALID)
+ return &submodule->index_oid;
+ else
+ return NULL;
+}
+
+const git_oid *git_submodule_head_oid(git_submodule *submodule)
+{
+ assert(submodule);
+
+ if (submodule->flags & GIT_SUBMODULE_STATUS__HEAD_OID_VALID)
+ return &submodule->head_oid;
+ else
return NULL;
+}
+
+const git_oid *git_submodule_wd_oid(git_submodule *submodule)
+{
+ assert(submodule);
+
+ if (!(submodule->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID)) {
+ git_repository *subrepo;
+
+ /* calling submodule open grabs the HEAD OID if possible */
+ if (!git_submodule_open(&subrepo, submodule))
+ git_repository_free(subrepo);
+ else
+ giterr_clear();
}
+ if (submodule->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID)
+ return &submodule->wd_oid;
+ else
+ return NULL;
+}
+
+git_submodule_ignore_t git_submodule_ignore(git_submodule *submodule)
+{
+ assert(submodule);
+ return submodule->ignore;
+}
+
+git_submodule_ignore_t git_submodule_set_ignore(
+ git_submodule *submodule, git_submodule_ignore_t ignore)
+{
+ git_submodule_ignore_t old;
+
+ assert(submodule);
+
+ if (ignore == GIT_SUBMODULE_IGNORE_DEFAULT)
+ ignore = submodule->ignore_default;
+
+ old = submodule->ignore;
+ submodule->ignore = ignore;
+ return old;
+}
+
+git_submodule_update_t git_submodule_update(git_submodule *submodule)
+{
+ assert(submodule);
+ return submodule->update;
+}
+
+git_submodule_update_t git_submodule_set_update(
+ git_submodule *submodule, git_submodule_update_t update)
+{
+ git_submodule_update_t old;
+
+ assert(submodule);
+
+ if (update == GIT_SUBMODULE_UPDATE_DEFAULT)
+ update = submodule->update_default;
+
+ old = submodule->update;
+ submodule->update = update;
+ return old;
+}
+
+int git_submodule_init(git_submodule *submodule, int overwrite)
+{
+ int error;
+
+ /* write "submodule.NAME.url" */
+
+ if (!submodule->url) {
+ giterr_set(GITERR_SUBMODULE,
+ "No URL configured for submodule '%s'", submodule->name);
+ return -1;
+ }
+
+ error = submodule_update_config(
+ submodule, "url", submodule->url, overwrite != 0, false);
+ if (error < 0)
+ return error;
+
+ /* write "submodule.NAME.update" if not default */
+
+ if (submodule->update == GIT_SUBMODULE_UPDATE_CHECKOUT)
+ error = submodule_update_config(
+ submodule, "update", NULL, (overwrite != 0), false);
+ else if (submodule->update != GIT_SUBMODULE_UPDATE_DEFAULT)
+ error = submodule_update_config(
+ submodule, "update",
+ _sm_update_map[submodule->update].str_match,
+ (overwrite != 0), false);
+
+ return error;
+}
+
+int git_submodule_sync(git_submodule *submodule)
+{
+ if (!submodule->url) {
+ giterr_set(GITERR_SUBMODULE,
+ "No URL configured for submodule '%s'", submodule->name);
+ return -1;
+ }
+
+ /* copy URL over to config only if it already exists */
+
+ return submodule_update_config(
+ submodule, "url", submodule->url, true, true);
+}
+
+int git_submodule_open(
+ git_repository **subrepo,
+ git_submodule *submodule)
+{
+ int error;
+ git_buf path = GIT_BUF_INIT;
+ git_repository *repo;
+ const char *workdir;
+
+ assert(submodule && subrepo);
+
+ repo = submodule->owner;
+ workdir = git_repository_workdir(repo);
+
+ if (!workdir) {
+ giterr_set(GITERR_REPOSITORY,
+ "Cannot open submodule repository in a bare repo");
+ return GIT_ENOTFOUND;
+ }
+
+ if ((submodule->flags & GIT_SUBMODULE_STATUS_IN_WD) == 0) {
+ giterr_set(GITERR_REPOSITORY,
+ "Cannot open submodule repository that is not checked out");
+ return GIT_ENOTFOUND;
+ }
+
+ if (git_buf_joinpath(&path, workdir, submodule->path) < 0)
+ return -1;
+
+ error = git_repository_open(subrepo, path.ptr);
+
+ git_buf_free(&path);
+
+ /* if we have opened the submodule successfully, let's grab the HEAD OID */
+ if (!error && !(submodule->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID)) {
+ if (!git_reference_name_to_oid(
+ &submodule->wd_oid, *subrepo, GIT_HEAD_FILE))
+ submodule->flags |= GIT_SUBMODULE_STATUS__WD_OID_VALID;
+ else
+ giterr_clear();
+ }
+
+ return error;
+}
+
+int git_submodule_reload_all(git_repository *repo)
+{
+ assert(repo);
+ return load_submodule_config(repo, true);
+}
+
+int git_submodule_reload(git_submodule *submodule)
+{
+ git_repository *repo;
+ git_index *index;
+ int pos, error;
+ git_tree *head;
+ git_config_file *mods;
+
+ assert(submodule);
+
+ /* refresh index data */
+
+ repo = submodule->owner;
+ if (git_repository_index__weakptr(&index, repo) < 0)
+ return -1;
+
+ submodule->flags = submodule->flags &
+ ~(GIT_SUBMODULE_STATUS_IN_INDEX |
+ GIT_SUBMODULE_STATUS__INDEX_OID_VALID);
+
+ pos = git_index_find(index, submodule->path);
+ if (pos >= 0) {
+ git_index_entry *entry = git_index_get(index, pos);
+
+ if (S_ISGITLINK(entry->mode)) {
+ if ((error = submodule_load_from_index(repo, entry)) < 0)
+ return error;
+ } else {
+ submodule_mode_mismatch(
+ repo, entry->path, GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE);
+ }
+ }
+
+ /* refresh HEAD tree data */
+
+ if (!(error = git_repository_head_tree(&head, repo))) {
+ git_tree_entry *te;
+
+ submodule->flags = submodule->flags &
+ ~(GIT_SUBMODULE_STATUS_IN_HEAD |
+ GIT_SUBMODULE_STATUS__HEAD_OID_VALID);
+
+ if (!(error = git_tree_entry_bypath(&te, head, submodule->path))) {
+
+ if (S_ISGITLINK(te->attr)) {
+ error = submodule_load_from_head(repo, submodule->path, &te->oid);
+ } else {
+ submodule_mode_mismatch(
+ repo, submodule->path,
+ GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE);
+ }
+
+ git_tree_entry_free(te);
+ }
+ else if (error == GIT_ENOTFOUND) {
+ giterr_clear();
+ error = 0;
+ }
+
+ git_tree_free(head);
+ }
+
+ if (error < 0)
+ return error;
+
+ /* refresh config data */
+
+ if ((mods = open_gitmodules(repo, false, NULL)) != NULL) {
+ git_buf path = GIT_BUF_INIT;
+
+ git_buf_sets(&path, "submodule\\.");
+ git_buf_puts_escape_regex(&path, submodule->name);
+ git_buf_puts(&path, ".*");
+
+ if (git_buf_oom(&path))
+ error = -1;
+ else
+ error = git_config_file_foreach_match(
+ mods, path.ptr, submodule_load_from_config, repo);
+
+ git_buf_free(&path);
+ git_config_file_free(mods);
+ }
+
+ if (error < 0)
+ return error;
+
+ /* refresh wd data */
+
+ submodule->flags = submodule->flags &
+ ~(GIT_SUBMODULE_STATUS_IN_WD | GIT_SUBMODULE_STATUS__WD_OID_VALID);
+
+ error = submodule_load_from_wd_lite(submodule, submodule->path, NULL);
+
+ return error;
+}
+
+int git_submodule_status(
+ unsigned int *status,
+ git_submodule *submodule)
+{
+ int error = 0;
+ unsigned int status_val;
+
+ assert(status && submodule);
+
+ status_val = GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(submodule->flags);
+
+ if (submodule->ignore != GIT_SUBMODULE_IGNORE_ALL) {
+ if (!(error = submodule_index_status(&status_val, submodule)))
+ error = submodule_wd_status(&status_val, submodule);
+ }
+
+ *status = status_val;
+
+ return error;
+}
+
+/*
+ * INTERNAL FUNCTIONS
+ */
+
+static git_submodule *submodule_alloc(git_repository *repo, const char *name)
+{
+ git_submodule *sm;
+
+ if (!name || !strlen(name)) {
+ giterr_set(GITERR_SUBMODULE, "Invalid submodule name");
+ return NULL;
+ }
+
+ sm = git__calloc(1, sizeof(git_submodule));
+ if (sm == NULL)
+ goto fail;
+
+ sm->path = sm->name = git__strdup(name);
+ if (!sm->name)
+ goto fail;
+
+ sm->owner = repo;
+ sm->refcount = 1;
+
return sm;
+
+fail:
+ submodule_release(sm, 0);
+ return NULL;
}
static void submodule_release(git_submodule *sm, int decr)
@@ -80,70 +847,121 @@ static void submodule_release(git_submodule *sm, int decr)
sm->refcount -= decr;
if (sm->refcount == 0) {
- if (sm->name != sm->path)
+ if (sm->name != sm->path) {
git__free(sm->path);
+ sm->path = NULL;
+ }
+
git__free(sm->name);
+ sm->name = NULL;
+
git__free(sm->url);
+ sm->url = NULL;
+
+ sm->owner = NULL;
+
git__free(sm);
}
}
-static int submodule_from_entry(
- git_strmap *smcfg, git_index_entry *entry)
+static int submodule_get(
+ git_submodule **sm_ptr,
+ git_repository *repo,
+ const char *name,
+ const char *alternate)
{
- git_submodule *sm;
- void *old_sm;
+ git_strmap *smcfg = repo->submodules;
khiter_t pos;
+ git_submodule *sm;
int error;
- pos = git_strmap_lookup_index(smcfg, entry->path);
+ assert(repo && name);
- if (git_strmap_valid_index(smcfg, pos))
- sm = git_strmap_value_at(smcfg, pos);
- else
- sm = submodule_alloc(entry->path);
+ pos = git_strmap_lookup_index(smcfg, name);
- git_oid_cpy(&sm->oid, &entry->oid);
+ if (!git_strmap_valid_index(smcfg, pos) && alternate)
+ pos = git_strmap_lookup_index(smcfg, alternate);
- if (strcmp(sm->path, entry->path) != 0) {
- if (sm->path != sm->name) {
- git__free(sm->path);
- sm->path = sm->name;
+ if (!git_strmap_valid_index(smcfg, pos)) {
+ sm = submodule_alloc(repo, name);
+
+ /* insert value at name - if another thread beats us to it, then use
+ * their record and release our own.
+ */
+ pos = kh_put(str, smcfg, sm->name, &error);
+
+ if (error < 0) {
+ submodule_release(sm, 1);
+ sm = NULL;
+ } else if (error == 0) {
+ submodule_release(sm, 1);
+ sm = git_strmap_value_at(smcfg, pos);
+ } else {
+ git_strmap_set_value_at(smcfg, pos, sm);
}
- sm->path = git__strdup(entry->path);
- if (!sm->path)
- goto fail;
+ } else {
+ sm = git_strmap_value_at(smcfg, pos);
}
- git_strmap_insert2(smcfg, sm->path, sm, old_sm, error);
- if (error < 0)
- goto fail;
- sm->refcount++;
+ *sm_ptr = sm;
- if (old_sm && ((git_submodule *)old_sm) != sm) {
- /* TODO: log warning about multiple entrys for same submodule path */
- submodule_release(old_sm, 1);
+ return (sm != NULL) ? 0 : -1;
+}
+
+static int submodule_load_from_index(
+ git_repository *repo, const git_index_entry *entry)
+{
+ git_submodule *sm;
+
+ if (submodule_get(&sm, repo, entry->path, NULL) < 0)
+ return -1;
+
+ if (sm->flags & GIT_SUBMODULE_STATUS_IN_INDEX) {
+ sm->flags |= GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES;
+ return 0;
}
+ sm->flags |= GIT_SUBMODULE_STATUS_IN_INDEX;
+
+ git_oid_cpy(&sm->index_oid, &entry->oid);
+ sm->flags |= GIT_SUBMODULE_STATUS__INDEX_OID_VALID;
+
return 0;
+}
-fail:
- submodule_release(sm, 0);
+static int submodule_load_from_head(
+ git_repository *repo, const char *path, const git_oid *oid)
+{
+ git_submodule *sm;
+
+ if (submodule_get(&sm, repo, path, NULL) < 0)
+ return -1;
+
+ sm->flags |= GIT_SUBMODULE_STATUS_IN_HEAD;
+
+ git_oid_cpy(&sm->head_oid, oid);
+ sm->flags |= GIT_SUBMODULE_STATUS__HEAD_OID_VALID;
+
+ return 0;
+}
+
+static int submodule_config_error(const char *property, const char *value)
+{
+ giterr_set(GITERR_INVALID,
+ "Invalid value for submodule '%s' property: '%s'", property, value);
return -1;
}
-static int submodule_from_config(
+static int submodule_load_from_config(
const char *key, const char *value, void *data)
{
- git_strmap *smcfg = data;
- const char *namestart;
- const char *property;
+ git_repository *repo = data;
+ git_strmap *smcfg = repo->submodules;
+ const char *namestart, *property, *alternate = NULL;
git_buf name = GIT_BUF_INIT;
git_submodule *sm;
- void *old_sm = NULL;
bool is_path;
- khiter_t pos;
- int error;
+ int error = 0;
if (git__prefixcmp(key, "submodule.") != 0)
return 0;
@@ -153,235 +971,502 @@ static int submodule_from_config(
if (property == NULL)
return 0;
property++;
- is_path = (strcmp(property, "path") == 0);
+ is_path = (strcasecmp(property, "path") == 0);
if (git_buf_set(&name, namestart, property - namestart - 1) < 0)
return -1;
- pos = git_strmap_lookup_index(smcfg, name.ptr);
- if (!git_strmap_valid_index(smcfg, pos) && is_path)
- pos = git_strmap_lookup_index(smcfg, value);
- if (!git_strmap_valid_index(smcfg, pos))
- sm = submodule_alloc(name.ptr);
- else
- sm = git_strmap_value_at(smcfg, pos);
- if (!sm)
- goto fail;
+ if (submodule_get(&sm, repo, name.ptr, is_path ? value : NULL) < 0) {
+ git_buf_free(&name);
+ return -1;
+ }
- if (strcmp(sm->name, name.ptr) != 0) {
- assert(sm->path == sm->name);
- sm->name = git_buf_detach(&name);
+ sm->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG;
- git_strmap_insert2(smcfg, sm->name, sm, old_sm, error);
- if (error < 0)
- goto fail;
- sm->refcount++;
+ /* Only from config might we get differing names & paths. If so, then
+ * update the submodule and insert under the alternative key.
+ */
+
+ /* TODO: if case insensitive filesystem, then the following strcmps
+ * should be strcasecmp
+ */
+
+ if (strcmp(sm->name, name.ptr) != 0) {
+ alternate = sm->name = git_buf_detach(&name);
+ } else if (is_path && value && strcmp(sm->path, value) != 0) {
+ alternate = sm->path = git__strdup(value);
+ if (!sm->path)
+ error = -1;
}
- else if (is_path && strcmp(sm->path, value) != 0) {
- assert(sm->path == sm->name);
- sm->path = git__strdup(value);
- if (sm->path == NULL)
- goto fail;
+ if (alternate) {
+ void *old_sm = NULL;
+ git_strmap_insert2(smcfg, alternate, sm, old_sm, error);
- git_strmap_insert2(smcfg, sm->path, sm, old_sm, error);
- if (error < 0)
- goto fail;
- sm->refcount++;
+ if (error >= 0)
+ sm->refcount++; /* inserted under a new key */
+
+ /* if we replaced an old module under this key, release the old one */
+ if (old_sm && ((git_submodule *)old_sm) != sm) {
+ submodule_release(old_sm, 1);
+ /* TODO: log warning about multiple submodules with same path */
+ }
}
+
git_buf_free(&name);
+ if (error < 0)
+ return error;
- if (old_sm && ((git_submodule *)old_sm) != sm) {
- /* TODO: log warning about multiple submodules with same path */
- submodule_release(old_sm, 1);
- }
+ /* TODO: Look up path in index and if it is present but not a GITLINK
+ * then this should be deleted (at least to match git's behavior)
+ */
if (is_path)
return 0;
/* copy other properties into submodule entry */
- if (strcmp(property, "url") == 0) {
- if (sm->url) {
- git__free(sm->url);
- sm->url = NULL;
- }
- if ((sm->url = git__strdup(value)) == NULL)
- goto fail;
+ if (strcasecmp(property, "url") == 0) {
+ git__free(sm->url);
+ sm->url = NULL;
+
+ if (value != NULL && (sm->url = git__strdup(value)) == NULL)
+ return -1;
}
- else if (strcmp(property, "update") == 0) {
+ else if (strcasecmp(property, "update") == 0) {
int val;
if (git_config_lookup_map_value(
- _sm_update_map, ARRAY_SIZE(_sm_update_map), value, &val) < 0) {
- giterr_set(GITERR_INVALID,
- "Invalid value for submodule update property: '%s'", value);
- goto fail;
- }
- sm->update = (git_submodule_update_t)val;
+ _sm_update_map, ARRAY_SIZE(_sm_update_map), value, &val) < 0)
+ return submodule_config_error("update", value);
+ sm->update_default = sm->update = (git_submodule_update_t)val;
}
- else if (strcmp(property, "fetchRecurseSubmodules") == 0) {
- if (git__parse_bool(&sm->fetch_recurse, value) < 0) {
- giterr_set(GITERR_INVALID,
- "Invalid value for submodule 'fetchRecurseSubmodules' property: '%s'", value);
- goto fail;
- }
+ else if (strcasecmp(property, "fetchRecurseSubmodules") == 0) {
+ if (git__parse_bool(&sm->fetch_recurse, value) < 0)
+ return submodule_config_error("fetchRecurseSubmodules", value);
}
- else if (strcmp(property, "ignore") == 0) {
+ else if (strcasecmp(property, "ignore") == 0) {
int val;
if (git_config_lookup_map_value(
- _sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), value, &val) < 0) {
- giterr_set(GITERR_INVALID,
- "Invalid value for submodule ignore property: '%s'", value);
- goto fail;
- }
- sm->ignore = (git_submodule_ignore_t)val;
+ _sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), value, &val) < 0)
+ return submodule_config_error("ignore", value);
+ sm->ignore_default = sm->ignore = (git_submodule_ignore_t)val;
}
/* ignore other unknown submodule properties */
return 0;
+}
-fail:
- submodule_release(sm, 0);
- git_buf_free(&name);
- return -1;
+static int submodule_load_from_wd_lite(
+ git_submodule *sm, const char *name, void *payload)
+{
+ git_repository *repo = git_submodule_owner(sm);
+ git_buf path = GIT_BUF_INIT;
+
+ GIT_UNUSED(name);
+ GIT_UNUSED(payload);
+
+ if (git_buf_joinpath(&path, git_repository_workdir(repo), sm->path) < 0)
+ return -1;
+
+ if (git_path_isdir(path.ptr))
+ sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED;
+
+ if (git_path_contains(&path, DOT_GIT))
+ sm->flags |= GIT_SUBMODULE_STATUS_IN_WD;
+
+ git_buf_free(&path);
+
+ return 0;
+}
+
+static void submodule_mode_mismatch(
+ git_repository *repo, const char *path, unsigned int flag)
+{
+ khiter_t pos = git_strmap_lookup_index(repo->submodules, path);
+
+ if (git_strmap_valid_index(repo->submodules, pos)) {
+ git_submodule *sm = git_strmap_value_at(repo->submodules, pos);
+
+ sm->flags |= flag;
+ }
}
-static int load_submodule_config(git_repository *repo)
+static int load_submodule_config_from_index(
+ git_repository *repo, git_oid *gitmodules_oid)
{
int error;
- git_index *index;
- unsigned int i, max_i;
- git_oid gitmodules_oid;
- git_strmap *smcfg;
- struct git_config_file *mods = NULL;
+ git_iterator *i;
+ const git_index_entry *entry;
- if (repo->submodules)
- return 0;
+ if ((error = git_iterator_for_index(&i, repo)) < 0)
+ return error;
- /* submodule data is kept in a hashtable with each submodule stored
- * under both its name and its path. These are usually the same, but
- * that is not guaranteed.
- */
- smcfg = git_strmap_alloc();
- GITERR_CHECK_ALLOC(smcfg);
+ error = git_iterator_current(i, &entry);
- /* scan index for gitmodules (and .gitmodules entry) */
- if ((error = git_repository_index__weakptr(&index, repo)) < 0)
- goto cleanup;
- memset(&gitmodules_oid, 0, sizeof(gitmodules_oid));
- max_i = git_index_entrycount(index);
+ while (!error && entry != NULL) {
+
+ if (S_ISGITLINK(entry->mode)) {
+ error = submodule_load_from_index(repo, entry);
+ if (error < 0)
+ break;
+ } else {
+ submodule_mode_mismatch(
+ repo, entry->path, GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE);
+
+ if (strcmp(entry->path, GIT_MODULES_FILE) == 0)
+ git_oid_cpy(gitmodules_oid, &entry->oid);
+ }
+
+ error = git_iterator_advance(i, &entry);
+ }
+
+ git_iterator_free(i);
+
+ return error;
+}
+
+static int load_submodule_config_from_head(
+ git_repository *repo, git_oid *gitmodules_oid)
+{
+ int error;
+ git_tree *head;
+ git_iterator *i;
+ const git_index_entry *entry;
+
+ if ((error = git_repository_head_tree(&head, repo)) < 0)
+ return error;
+
+ if ((error = git_iterator_for_tree(&i, repo, head)) < 0) {
+ git_tree_free(head);
+ return error;
+ }
+
+ error = git_iterator_current(i, &entry);
+
+ while (!error && entry != NULL) {
- for (i = 0; i < max_i; i++) {
- git_index_entry *entry = git_index_get(index, i);
if (S_ISGITLINK(entry->mode)) {
- if ((error = submodule_from_entry(smcfg, entry)) < 0)
- goto cleanup;
+ error = submodule_load_from_head(repo, entry->path, &entry->oid);
+ if (error < 0)
+ break;
+ } else {
+ submodule_mode_mismatch(
+ repo, entry->path, GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE);
+
+ if (strcmp(entry->path, GIT_MODULES_FILE) == 0 &&
+ git_oid_iszero(gitmodules_oid))
+ git_oid_cpy(gitmodules_oid, &entry->oid);
}
- else if (strcmp(entry->path, ".gitmodules") == 0)
- git_oid_cpy(&gitmodules_oid, &entry->oid);
+
+ error = git_iterator_advance(i, &entry);
}
- /* load .gitmodules from workdir if it exists */
- if (git_repository_workdir(repo) != NULL) {
- /* look in workdir for .gitmodules */
- git_buf path = GIT_BUF_INIT;
- if (!git_buf_joinpath(
- &path, git_repository_workdir(repo), ".gitmodules") &&
- git_path_isfile(path.ptr))
- {
- if (!(error = git_config_file__ondisk(&mods, path.ptr)))
- error = git_config_file_open(mods);
+ git_iterator_free(i);
+ git_tree_free(head);
+
+ return error;
+}
+
+static git_config_file *open_gitmodules(
+ git_repository *repo,
+ bool okay_to_create,
+ const git_oid *gitmodules_oid)
+{
+ const char *workdir = git_repository_workdir(repo);
+ git_buf path = GIT_BUF_INIT;
+ git_config_file *mods = NULL;
+
+ if (workdir != NULL) {
+ if (git_buf_joinpath(&path, workdir, GIT_MODULES_FILE) != 0)
+ return NULL;
+
+ if (okay_to_create || git_path_isfile(path.ptr)) {
+ /* git_config_file__ondisk should only fail if OOM */
+ if (git_config_file__ondisk(&mods, path.ptr) < 0)
+ mods = NULL;
+ /* open should only fail here if the file is malformed */
+ else if (git_config_file_open(mods) < 0) {
+ git_config_file_free(mods);
+ mods = NULL;
+ }
}
- git_buf_free(&path);
}
- /* load .gitmodules from object cache if not in workdir */
- if (!error && mods == NULL && !git_oid_iszero(&gitmodules_oid)) {
- /* TODO: is it worth loading gitmodules from object cache? */
+ if (!mods && gitmodules_oid && !git_oid_iszero(gitmodules_oid)) {
+ /* TODO: Retrieve .gitmodules content from ODB */
+
+ /* Should we actually do this? Core git does not, but it means you
+ * can't really get much information about submodules on bare repos.
+ */
+ }
+
+ git_buf_free(&path);
+
+ return mods;
+}
+
+static int load_submodule_config(git_repository *repo, bool force)
+{
+ int error;
+ git_oid gitmodules_oid;
+ git_buf path = GIT_BUF_INIT;
+ git_config_file *mods = NULL;
+
+ if (repo->submodules && !force)
+ return 0;
+
+ memset(&gitmodules_oid, 0, sizeof(gitmodules_oid));
+
+ /* Submodule data is kept in a hashtable keyed by both name and path.
+ * These are usually the same, but that is not guaranteed.
+ */
+ if (!repo->submodules) {
+ repo->submodules = git_strmap_alloc();
+ GITERR_CHECK_ALLOC(repo->submodules);
}
- /* process .gitmodules info */
- if (!error && mods != NULL)
- error = git_config_file_foreach(mods, submodule_from_config, smcfg);
+ /* add submodule information from index */
+
+ if ((error = load_submodule_config_from_index(repo, &gitmodules_oid)) < 0)
+ goto cleanup;
+
+ /* add submodule information from HEAD */
+
+ if ((error = load_submodule_config_from_head(repo, &gitmodules_oid)) < 0)
+ goto cleanup;
+
+ /* add submodule information from .gitmodules */
- /* store submodule config in repo */
- if (!error)
- repo->submodules = smcfg;
+ if ((mods = open_gitmodules(repo, false, &gitmodules_oid)) != NULL)
+ error = git_config_file_foreach(mods, submodule_load_from_config, repo);
+
+ if (error != 0)
+ goto cleanup;
+
+ /* shallow scan submodules in work tree */
+
+ if (!git_repository_is_bare(repo))
+ error = git_submodule_foreach(repo, submodule_load_from_wd_lite, NULL);
cleanup:
+ git_buf_free(&path);
+
if (mods != NULL)
git_config_file_free(mods);
+
if (error)
- git_strmap_free(smcfg);
+ git_submodule_config_free(repo);
+
return error;
}
-void git_submodule_config_free(git_repository *repo)
+static int lookup_head_remote(git_buf *url, git_repository *repo)
{
- git_strmap *smcfg = repo->submodules;
- git_submodule *sm;
+ int error;
+ git_config *cfg;
+ git_reference *head = NULL, *remote = NULL;
+ const char *tgt, *scan;
+ git_buf key = GIT_BUF_INIT;
+
+ /* 1. resolve HEAD -> refs/heads/BRANCH
+ * 2. lookup config branch.BRANCH.remote -> ORIGIN
+ * 3. lookup remote.ORIGIN.url
+ */
- repo->submodules = NULL;
+ if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
+ return error;
- if (smcfg == NULL)
- return;
+ if (git_reference_lookup(&head, repo, GIT_HEAD_FILE) < 0) {
+ giterr_set(GITERR_SUBMODULE,
+ "Cannot resolve relative URL when HEAD cannot be resolved");
+ error = GIT_ENOTFOUND;
+ goto cleanup;
+ }
- git_strmap_foreach_value(smcfg, sm, {
- submodule_release(sm,1);
- });
- git_strmap_free(smcfg);
-}
+ if (git_reference_type(head) != GIT_REF_SYMBOLIC) {
+ giterr_set(GITERR_SUBMODULE,
+ "Cannot resolve relative URL when HEAD is not symbolic");
+ error = GIT_ENOTFOUND;
+ goto cleanup;
+ }
-static int submodule_cmp(const void *a, const void *b)
-{
- return strcmp(((git_submodule *)a)->name, ((git_submodule *)b)->name);
+ if ((error = git_branch_tracking(&remote, head)) < 0)
+ goto cleanup;
+
+ /* remote should refer to something like refs/remotes/ORIGIN/BRANCH */
+
+ if (git_reference_type(remote) != GIT_REF_SYMBOLIC ||
+ git__prefixcmp(git_reference_target(remote), "refs/remotes/") != 0)
+ {
+ giterr_set(GITERR_SUBMODULE,
+ "Cannot resolve relative URL when HEAD is not symbolic");
+ error = GIT_ENOTFOUND;
+ goto cleanup;
+ }
+
+ scan = tgt = git_reference_target(remote) + strlen("refs/remotes/");
+ while (*scan && (*scan != '/' || (scan > tgt && scan[-1] != '\\')))
+ scan++; /* find non-escaped slash to end ORIGIN name */
+
+ error = git_buf_printf(&key, "remote.%.*s.url", (int)(scan - tgt), tgt);
+ if (error < 0)
+ goto cleanup;
+
+ if ((error = git_config_get_string(&tgt, cfg, key.ptr)) < 0)
+ goto cleanup;
+
+ error = git_buf_sets(url, tgt);
+
+cleanup:
+ git_buf_free(&key);
+ git_reference_free(head);
+ git_reference_free(remote);
+
+ return error;
}
-int git_submodule_foreach(
- git_repository *repo,
- int (*callback)(const char *name, void *payload),
- void *payload)
+static int submodule_update_config(
+ git_submodule *submodule,
+ const char *attr,
+ const char *value,
+ bool overwrite,
+ bool only_existing)
{
int error;
- git_submodule *sm;
- git_vector seen = GIT_VECTOR_INIT;
- seen._cmp = submodule_cmp;
+ git_config *config;
+ git_buf key = GIT_BUF_INIT;
+ const char *old = NULL;
+
+ assert(submodule);
- if ((error = load_submodule_config(repo)) < 0)
+ error = git_repository_config__weakptr(&config, submodule->owner);
+ if (error < 0)
return error;
- git_strmap_foreach_value(repo->submodules, sm, {
- /* usually the following will not come into play */
- if (sm->refcount > 1) {
- if (git_vector_bsearch(&seen, sm) != GIT_ENOTFOUND)
- continue;
- if ((error = git_vector_insert(&seen, sm)) < 0)
- break;
- }
+ error = git_buf_printf(&key, "submodule.%s.%s", submodule->name, attr);
+ if (error < 0)
+ goto cleanup;
- if ((error = callback(sm->name, payload)) < 0)
- break;
- });
+ if (git_config_get_string(&old, config, key.ptr) < 0)
+ giterr_clear();
- git_vector_free(&seen);
+ if (!old && only_existing)
+ goto cleanup;
+ if (old && !overwrite)
+ goto cleanup;
+ if ((!old && !value) || (old && value && strcmp(old, value) == 0))
+ goto cleanup;
+
+ if (!value)
+ error = git_config_delete(config, key.ptr);
+ else
+ error = git_config_set_string(config, key.ptr, value);
+cleanup:
+ git_buf_free(&key);
return error;
}
-int git_submodule_lookup(
- git_submodule **sm_ptr, /* NULL allowed if user only wants to test */
- git_repository *repo,
- const char *name) /* trailing slash is allowed */
+static int submodule_index_status(unsigned int *status, git_submodule *sm)
{
- khiter_t pos;
+ const git_oid *head_oid = git_submodule_head_oid(sm);
+ const git_oid *index_oid = git_submodule_index_oid(sm);
- if (load_submodule_config(repo) < 0)
- return -1;
+ if (!head_oid) {
+ if (index_oid)
+ *status |= GIT_SUBMODULE_STATUS_INDEX_ADDED;
+ }
+ else if (!index_oid)
+ *status |= GIT_SUBMODULE_STATUS_INDEX_DELETED;
+ else if (!git_oid_equal(head_oid, index_oid))
+ *status |= GIT_SUBMODULE_STATUS_INDEX_MODIFIED;
- pos = git_strmap_lookup_index(repo->submodules, name);
- if (!git_strmap_valid_index(repo->submodules, pos))
- return GIT_ENOTFOUND;
+ return 0;
+}
- if (sm_ptr)
- *sm_ptr = git_strmap_value_at(repo->submodules, pos);
+static int submodule_wd_status(unsigned int *status, git_submodule *sm)
+{
+ int error = 0;
+ const git_oid *wd_oid, *index_oid;
+ git_repository *sm_repo = NULL;
+
+ /* open repo now if we need it (so wd_oid() call won't reopen) */
+ if ((sm->ignore == GIT_SUBMODULE_IGNORE_NONE ||
+ sm->ignore == GIT_SUBMODULE_IGNORE_UNTRACKED) &&
+ (sm->flags & GIT_SUBMODULE_STATUS_IN_WD) != 0)
+ {
+ if ((error = git_submodule_open(&sm_repo, sm)) < 0)
+ return error;
+ }
- return 0;
+ index_oid = git_submodule_index_oid(sm);
+ wd_oid = git_submodule_wd_oid(sm);
+
+ if (!index_oid) {
+ if (wd_oid)
+ *status |= GIT_SUBMODULE_STATUS_WD_ADDED;
+ }
+ else if (!wd_oid) {
+ if ((sm->flags & GIT_SUBMODULE_STATUS__WD_SCANNED) != 0 &&
+ (sm->flags & GIT_SUBMODULE_STATUS_IN_WD) == 0)
+ *status |= GIT_SUBMODULE_STATUS_WD_UNINITIALIZED;
+ else
+ *status |= GIT_SUBMODULE_STATUS_WD_DELETED;
+ }
+ else if (!git_oid_equal(index_oid, wd_oid))
+ *status |= GIT_SUBMODULE_STATUS_WD_MODIFIED;
+
+ if (sm_repo != NULL) {
+ git_tree *sm_head;
+ git_diff_options opt;
+ git_diff_list *diff;
+
+ /* the diffs below could be optimized with an early termination
+ * option to the git_diff functions, but for now this is sufficient
+ * (and certainly no worse that what core git does).
+ */
+
+ /* perform head-to-index diff on submodule */
+
+ if ((error = git_repository_head_tree(&sm_head, sm_repo)) < 0)
+ return error;
+
+ memset(&opt, 0, sizeof(opt));
+ if (sm->ignore == GIT_SUBMODULE_IGNORE_NONE)
+ opt.flags |= GIT_DIFF_INCLUDE_UNTRACKED;
+
+ error = git_diff_index_to_tree(sm_repo, &opt, sm_head, &diff);
+
+ if (!error) {
+ if (git_diff_entrycount(diff, -1) > 0)
+ *status |= GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED;
+
+ git_diff_list_free(diff);
+ diff = NULL;
+ }
+
+ git_tree_free(sm_head);
+
+ if (error < 0)
+ return error;
+
+ /* perform index-to-workdir diff on submodule */
+
+ error = git_diff_workdir_to_index(sm_repo, &opt, &diff);
+
+ if (!error) {
+ int untracked = git_diff_entrycount(diff, GIT_DELTA_UNTRACKED);
+
+ if (untracked > 0)
+ *status |= GIT_SUBMODULE_STATUS_WD_UNTRACKED;
+
+ if (git_diff_entrycount(diff, -1) - untracked > 0)
+ *status |= GIT_SUBMODULE_STATUS_WD_WD_MODIFIED;
+
+ git_diff_list_free(diff);
+ diff = NULL;
+ }
+
+ git_repository_free(sm_repo);
+ }
+
+ return error;
}
diff --git a/src/submodule.h b/src/submodule.h
new file mode 100644
index 00000000..c7a6aaf7
--- /dev/null
+++ b/src/submodule.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2012 the libgit2 contributors
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_submodule_h__
+#define INCLUDE_submodule_h__
+
+/* Notes:
+ *
+ * Submodule information can be in four places: the index, the config files
+ * (both .git/config and .gitmodules), the HEAD tree, and the working
+ * directory.
+ *
+ * In the index:
+ * - submodule is found by path
+ * - may be missing, present, or of the wrong type
+ * - will have an oid if present
+ *
+ * In the HEAD tree:
+ * - submodule is found by path
+ * - may be missing, present, or of the wrong type
+ * - will have an oid if present
+ *
+ * In the config files:
+ * - submodule is found by submodule "name" which is usually the path
+ * - may be missing or present
+ * - will have a name, path, url, and other properties
+ *
+ * In the working directory:
+ * - submodule is found by path
+ * - may be missing, an empty directory, a checked out directory,
+ * or of the wrong type
+ * - if checked out, will have a HEAD oid
+ * - if checked out, will have git history that can be used to compare oids
+ * - if checked out, may have modified files and/or untracked files
+ */
+
+/**
+ * Description of submodule
+ *
+ * This record describes a submodule found in a repository. There should be
+ * an entry for every submodule found in the HEAD and index, and for every
+ * submodule described in .gitmodules. The fields are as follows:
+ *
+ * - `owner` is the git_repository containing this submodule
+ * - `name` is the name of the submodule from .gitmodules.
+ * - `path` is the path to the submodule from the repo root. It is almost
+ * always the same as `name`.
+ * - `url` is the url for the submodule.
+ * - `tree_oid` is the SHA1 for the submodule path in the repo HEAD.
+ * - `index_oid` is the SHA1 for the submodule recorded in the index.
+ * - `workdir_oid` is the SHA1 for the HEAD of the checked out submodule.
+ * - `update` is a git_submodule_update_t value - see gitmodules(5) update.
+ * - `ignore` is a git_submodule_ignore_t value - see gitmodules(5) ignore.
+ * - `fetch_recurse` is 0 or 1 - see gitmodules(5) fetchRecurseSubmodules.
+ * - `refcount` tracks how many hashmap entries there are for this submodule.
+ * It only comes into play if the name and path of the submodule differ.
+ * - `flags` is for internal use, tracking where this submodule has been
+ * found (head, index, config, workdir) and other misc info about it.
+ *
+ * If the submodule has been added to .gitmodules but not yet git added,
+ * then the `index_oid` will be valid and zero. If the submodule has been
+ * deleted, but the delete has not been committed yet, then the `index_oid`
+ * will be set, but the `url` will be NULL.
+ */
+struct git_submodule {
+ git_repository *owner;
+ char *name;
+ char *path; /* important: may point to same string data as "name" */
+ char *url;
+ uint32_t flags;
+ git_oid head_oid;
+ git_oid index_oid;
+ git_oid wd_oid;
+ /* information from config */
+ git_submodule_update_t update;
+ git_submodule_update_t update_default;
+ git_submodule_ignore_t ignore;
+ git_submodule_ignore_t ignore_default;
+ int fetch_recurse;
+ /* internal information */
+ int refcount;
+};
+
+/* Additional flags on top of public GIT_SUBMODULE_STATUS values */
+enum {
+ GIT_SUBMODULE_STATUS__WD_SCANNED = (1u << 20),
+ GIT_SUBMODULE_STATUS__HEAD_OID_VALID = (1u << 21),
+ GIT_SUBMODULE_STATUS__INDEX_OID_VALID = (1u << 22),
+ GIT_SUBMODULE_STATUS__WD_OID_VALID = (1u << 23),
+ GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE = (1u << 24),
+ GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE = (1u << 25),
+ GIT_SUBMODULE_STATUS__WD_NOT_SUBMODULE = (1u << 26),
+ GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES = (1u << 27),
+};
+
+#define GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(S) \
+ ((S) & ~(0xFFFFFFFFu << 20))
+
+#endif
diff --git a/src/transport.h b/src/transport.h
index c4306165..ff3a58d1 100644
--- a/src/transport.h
+++ b/src/transport.h
@@ -21,11 +21,15 @@
#define GIT_CAP_OFS_DELTA "ofs-delta"
#define GIT_CAP_MULTI_ACK "multi_ack"
+#define GIT_CAP_SIDE_BAND "side-band"
+#define GIT_CAP_SIDE_BAND_64K "side-band-64k"
typedef struct git_transport_caps {
int common:1,
ofs_delta:1,
- multi_ack: 1;
+ multi_ack: 1,
+ side_band:1,
+ side_band_64k:1;
} git_transport_caps;
#ifdef GIT_SSL
@@ -84,6 +88,7 @@ struct git_transport {
gitno_buffer buffer;
GIT_SOCKET socket;
git_transport_caps caps;
+ void *cb_data;
/**
* Connect and store the remote heads
*/
@@ -113,6 +118,11 @@ struct git_transport {
* Free the associated resources
*/
void (*free)(struct git_transport *transport);
+ /**
+ * Callbacks for the progress and error output
+ */
+ void (*progress_cb)(const char *str, int len, void *data);
+ void (*error_cb)(const char *str, int len, void *data);
};
diff --git a/src/transports/git.c b/src/transports/git.c
index 7a65718f..b757495c 100644
--- a/src/transports/git.c
+++ b/src/transports/git.c
@@ -24,7 +24,7 @@
typedef struct {
git_transport parent;
- char buff[1024];
+ char buff[65536];
#ifdef GIT_WIN32
WSADATA wsd;
#endif
diff --git a/src/transports/http.c b/src/transports/http.c
index ce382c3a..de33f56e 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -43,7 +43,7 @@ typedef struct {
char *host;
char *port;
char *service;
- char buffer[4096];
+ char buffer[65536];
#ifdef GIT_WIN32
WSADATA wsd;
#endif
diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c
index 02acb884..14bd9fb8 100644
--- a/tests-clar/refs/revparse.c
+++ b/tests-clar/refs/revparse.c
@@ -442,3 +442,12 @@ void test_refs_revparse__disambiguation(void)
*/
test_object("e90810", "e90810b8df3e80c413d903f631643c716887138d");
}
+
+void test_refs_revparse__a_too_short_objectid_returns_EAMBIGUOUS(void)
+{
+ int result;
+
+ result = git_revparse_single(&g_obj, g_repo, "e90");
+
+ cl_assert_equal_i(GIT_EAMBIGUOUS, result);
+}
diff --git a/tests-clar/resources/submod2/.gitted/HEAD b/tests-clar/resources/submod2/.gitted/HEAD
new file mode 100644
index 00000000..cb089cd8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests-clar/resources/submod2/.gitted/config b/tests-clar/resources/submod2/.gitted/config
new file mode 100644
index 00000000..abc42073
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/config
@@ -0,0 +1,20 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ ignorecase = true
+[submodule "sm_missing_commits"]
+ url = ../submod2_target
+[submodule "sm_unchanged"]
+ url = ../submod2_target
+[submodule "sm_changed_file"]
+ url = ../submod2_target
+[submodule "sm_changed_index"]
+ url = ../submod2_target
+[submodule "sm_changed_head"]
+ url = ../submod2_target
+[submodule "sm_changed_untracked_file"]
+ url = ../submod2_target
+[submodule "sm_added_and_uncommited"]
+ url = ../submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/description b/tests-clar/resources/submod2/.gitted/description
new file mode 100644
index 00000000..498b267a
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests-clar/resources/submod2/.gitted/hooks/applypatch-msg.sample b/tests-clar/resources/submod2/.gitted/hooks/applypatch-msg.sample
new file mode 100755
index 00000000..8b2a2fe8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/hooks/applypatch-msg.sample
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message taken by
+# applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit. The hook is
+# allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "applypatch-msg".
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/commit-msg" &&
+ exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
+:
diff --git a/tests-clar/resources/submod2/.gitted/index b/tests-clar/resources/submod2/.gitted/index
new file mode 100644
index 00000000..0c17e862
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/index
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/info/exclude b/tests-clar/resources/submod2/.gitted/info/exclude
new file mode 100644
index 00000000..a5196d1b
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests-clar/resources/submod2/.gitted/logs/HEAD b/tests-clar/resources/submod2/.gitted/logs/HEAD
new file mode 100644
index 00000000..2cf2ca74
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/logs/HEAD
@@ -0,0 +1,4 @@
+0000000000000000000000000000000000000000 14fe9ccf104058df25e0a08361c4494e167ef243 Russell Belfer <rb@github.com> 1342559771 -0700 commit (initial): Initial commit
+14fe9ccf104058df25e0a08361c4494e167ef243 a9104bf89e911387244ef499413960ba472066d9 Russell Belfer <rb@github.com> 1342559831 -0700 commit: Adding a submodule
+a9104bf89e911387244ef499413960ba472066d9 5901da4f1c67756eeadc5121d206bec2431f253b Russell Belfer <rb@github.com> 1342560036 -0700 commit: Updating submodule
+5901da4f1c67756eeadc5121d206bec2431f253b 7484482eb8db738cafa696993664607500a3f2b9 Russell Belfer <rb@github.com> 1342560288 -0700 commit: Adding a bunch more test content
diff --git a/tests-clar/resources/submod2/.gitted/logs/refs/heads/master b/tests-clar/resources/submod2/.gitted/logs/refs/heads/master
new file mode 100644
index 00000000..2cf2ca74
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/logs/refs/heads/master
@@ -0,0 +1,4 @@
+0000000000000000000000000000000000000000 14fe9ccf104058df25e0a08361c4494e167ef243 Russell Belfer <rb@github.com> 1342559771 -0700 commit (initial): Initial commit
+14fe9ccf104058df25e0a08361c4494e167ef243 a9104bf89e911387244ef499413960ba472066d9 Russell Belfer <rb@github.com> 1342559831 -0700 commit: Adding a submodule
+a9104bf89e911387244ef499413960ba472066d9 5901da4f1c67756eeadc5121d206bec2431f253b Russell Belfer <rb@github.com> 1342560036 -0700 commit: Updating submodule
+5901da4f1c67756eeadc5121d206bec2431f253b 7484482eb8db738cafa696993664607500a3f2b9 Russell Belfer <rb@github.com> 1342560288 -0700 commit: Adding a bunch more test content
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/HEAD
new file mode 100644
index 00000000..cb089cd8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/config b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/config
new file mode 100644
index 00000000..2d0583e9
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/config
@@ -0,0 +1,13 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ worktree = ../../../sm_added_and_uncommited
+ ignorecase = true
+[remote "origin"]
+ fetch = +refs/heads/*:refs/remotes/origin/*
+ url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target
+[branch "master"]
+ remote = origin
+ merge = refs/heads/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/description b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/description
new file mode 100644
index 00000000..498b267a
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/hooks/applypatch-msg.sample b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/hooks/applypatch-msg.sample
new file mode 100755
index 00000000..8b2a2fe8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/hooks/applypatch-msg.sample
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message taken by
+# applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit. The hook is
+# allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "applypatch-msg".
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/commit-msg" &&
+ exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
+:
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/index b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/index
new file mode 100644
index 00000000..65140a51
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/index
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/info/exclude b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/info/exclude
new file mode 100644
index 00000000..a5196d1b
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/HEAD
new file mode 100644
index 00000000..53753e7d
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/HEAD
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342560316 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/refs/heads/master b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/refs/heads/master
new file mode 100644
index 00000000..53753e7d
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/refs/heads/master
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342560316 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/refs/remotes/origin/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/refs/remotes/origin/HEAD
new file mode 100644
index 00000000..53753e7d
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/logs/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342560316 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1 b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
new file mode 100644
index 00000000..f4b7094c
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484 b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
new file mode 100644
index 00000000..56c845e4
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5 b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
new file mode 100644
index 00000000..bd179b5f
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/41/bd4bc3df978de695f67ace64c560913da11653 b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/41/bd4bc3df978de695f67ace64c560913da11653
new file mode 100644
index 00000000..ccf49bd1
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/41/bd4bc3df978de695f67ace64c560913da11653
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/48/0095882d281ed676fe5b863569520e54a7d5c0 b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/48/0095882d281ed676fe5b863569520e54a7d5c0
new file mode 100644
index 00000000..53029069
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/48/0095882d281ed676fe5b863569520e54a7d5c0
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/5e/4963595a9774b90524d35a807169049de8ccad b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/5e/4963595a9774b90524d35a807169049de8ccad
new file mode 100644
index 00000000..38c791eb
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/5e/4963595a9774b90524d35a807169049de8ccad
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/6b/31c659545507c381e9cd34ec508f16c04e149e b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
new file mode 100644
index 00000000..a26d2999
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
@@ -0,0 +1,2 @@
+xQ
+!Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8 \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/73/ba924a80437097795ae839e66e187c55d3babf b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/73/ba924a80437097795ae839e66e187c55d3babf
new file mode 100644
index 00000000..83d1ba48
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/73/ba924a80437097795ae839e66e187c55d3babf
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
new file mode 100644
index 00000000..6d27af8a
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
@@ -0,0 +1,2 @@
+x-10 Fa0p(N-ӡғq]>ks*? |m“i@mV'`).-1 x
+uxt(+ \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/78/9efbdadaa4a582778d4584385495559ea0994b b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/78/9efbdadaa4a582778d4584385495559ea0994b
new file mode 100644
index 00000000..17458840
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/78/9efbdadaa4a582778d4584385495559ea0994b
@@ -0,0 +1,2 @@
+x 0 )?= NlOkj8&r
+qJW7B<fK8#Q1C-"e̫>'@ \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
new file mode 100644
index 00000000..83cc29fb
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5 b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
new file mode 100644
index 00000000..55bda40e
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/packed-refs b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/packed-refs
new file mode 100644
index 00000000..5a4ebc47
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/packed-refs
@@ -0,0 +1,2 @@
+# pack-refs with: peeled
+480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/refs/heads/master b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/refs/heads/master
new file mode 100644
index 00000000..e12c44d7
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/refs/heads/master
@@ -0,0 +1 @@
+480095882d281ed676fe5b863569520e54a7d5c0
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/refs/remotes/origin/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/refs/remotes/origin/HEAD
new file mode 100644
index 00000000..6efe28ff
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_added_and_uncommited/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+ref: refs/remotes/origin/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/HEAD
new file mode 100644
index 00000000..cb089cd8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/config b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/config
new file mode 100644
index 00000000..10cc2508
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/config
@@ -0,0 +1,13 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ worktree = ../../../sm_changed_file
+ ignorecase = true
+[remote "origin"]
+ fetch = +refs/heads/*:refs/remotes/origin/*
+ url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target
+[branch "master"]
+ remote = origin
+ merge = refs/heads/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/description b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/description
new file mode 100644
index 00000000..498b267a
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/hooks/applypatch-msg.sample b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/hooks/applypatch-msg.sample
new file mode 100755
index 00000000..8b2a2fe8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/hooks/applypatch-msg.sample
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message taken by
+# applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit. The hook is
+# allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "applypatch-msg".
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/commit-msg" &&
+ exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
+:
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/index b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/index
new file mode 100644
index 00000000..6914a3b6
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/index
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/info/exclude b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/info/exclude
new file mode 100644
index 00000000..a5196d1b
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/HEAD
new file mode 100644
index 00000000..e5cb63f8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/HEAD
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342560173 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/refs/heads/master b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/refs/heads/master
new file mode 100644
index 00000000..e5cb63f8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/refs/heads/master
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342560173 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/refs/remotes/origin/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/refs/remotes/origin/HEAD
new file mode 100644
index 00000000..e5cb63f8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/logs/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342560173 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
new file mode 100644
index 00000000..f4b7094c
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
new file mode 100644
index 00000000..56c845e4
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
new file mode 100644
index 00000000..bd179b5f
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/41/bd4bc3df978de695f67ace64c560913da11653 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/41/bd4bc3df978de695f67ace64c560913da11653
new file mode 100644
index 00000000..ccf49bd1
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/41/bd4bc3df978de695f67ace64c560913da11653
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/48/0095882d281ed676fe5b863569520e54a7d5c0 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/48/0095882d281ed676fe5b863569520e54a7d5c0
new file mode 100644
index 00000000..53029069
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/48/0095882d281ed676fe5b863569520e54a7d5c0
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/5e/4963595a9774b90524d35a807169049de8ccad b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/5e/4963595a9774b90524d35a807169049de8ccad
new file mode 100644
index 00000000..38c791eb
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/5e/4963595a9774b90524d35a807169049de8ccad
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/6b/31c659545507c381e9cd34ec508f16c04e149e b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
new file mode 100644
index 00000000..a26d2999
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
@@ -0,0 +1,2 @@
+xQ
+!Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8 \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/73/ba924a80437097795ae839e66e187c55d3babf b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/73/ba924a80437097795ae839e66e187c55d3babf
new file mode 100644
index 00000000..83d1ba48
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/73/ba924a80437097795ae839e66e187c55d3babf
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
new file mode 100644
index 00000000..6d27af8a
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
@@ -0,0 +1,2 @@
+x-10 Fa0p(N-ӡғq]>ks*? |m“i@mV'`).-1 x
+uxt(+ \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/78/9efbdadaa4a582778d4584385495559ea0994b b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/78/9efbdadaa4a582778d4584385495559ea0994b
new file mode 100644
index 00000000..17458840
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/78/9efbdadaa4a582778d4584385495559ea0994b
@@ -0,0 +1,2 @@
+x 0 )?= NlOkj8&r
+qJW7B<fK8#Q1C-"e̫>'@ \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
new file mode 100644
index 00000000..83cc29fb
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
new file mode 100644
index 00000000..55bda40e
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/packed-refs b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/packed-refs
new file mode 100644
index 00000000..5a4ebc47
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/packed-refs
@@ -0,0 +1,2 @@
+# pack-refs with: peeled
+480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/refs/heads/master b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/refs/heads/master
new file mode 100644
index 00000000..e12c44d7
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/refs/heads/master
@@ -0,0 +1 @@
+480095882d281ed676fe5b863569520e54a7d5c0
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/refs/remotes/origin/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/refs/remotes/origin/HEAD
new file mode 100644
index 00000000..6efe28ff
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_file/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+ref: refs/remotes/origin/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/COMMIT_EDITMSG b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/COMMIT_EDITMSG
new file mode 100644
index 00000000..6b8d1e3f
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/COMMIT_EDITMSG
@@ -0,0 +1 @@
+Making a change in a submodule
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/HEAD
new file mode 100644
index 00000000..cb089cd8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/config b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/config
new file mode 100644
index 00000000..7d002536
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/config
@@ -0,0 +1,13 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ worktree = ../../../sm_changed_head
+ ignorecase = true
+[remote "origin"]
+ fetch = +refs/heads/*:refs/remotes/origin/*
+ url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target
+[branch "master"]
+ remote = origin
+ merge = refs/heads/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/description b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/description
new file mode 100644
index 00000000..498b267a
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/hooks/applypatch-msg.sample b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/hooks/applypatch-msg.sample
new file mode 100755
index 00000000..8b2a2fe8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/hooks/applypatch-msg.sample
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message taken by
+# applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit. The hook is
+# allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "applypatch-msg".
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/commit-msg" &&
+ exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
+:
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/index b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/index
new file mode 100644
index 00000000..728fa292
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/index
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/info/exclude b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/info/exclude
new file mode 100644
index 00000000..a5196d1b
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/HEAD
new file mode 100644
index 00000000..cabdeb2b
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/HEAD
@@ -0,0 +1,2 @@
+0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342560179 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
+480095882d281ed676fe5b863569520e54a7d5c0 3d9386c507f6b093471a3e324085657a3c2b4247 Russell Belfer <rb@github.com> 1342560431 -0700 commit: Making a change in a submodule
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/refs/heads/master b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/refs/heads/master
new file mode 100644
index 00000000..cabdeb2b
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/refs/heads/master
@@ -0,0 +1,2 @@
+0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342560179 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
+480095882d281ed676fe5b863569520e54a7d5c0 3d9386c507f6b093471a3e324085657a3c2b4247 Russell Belfer <rb@github.com> 1342560431 -0700 commit: Making a change in a submodule
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/refs/remotes/origin/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/refs/remotes/origin/HEAD
new file mode 100644
index 00000000..257ca21d
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/logs/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342560179 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
new file mode 100644
index 00000000..f4b7094c
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
new file mode 100644
index 00000000..56c845e4
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
new file mode 100644
index 00000000..bd179b5f
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/3d/9386c507f6b093471a3e324085657a3c2b4247 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/3d/9386c507f6b093471a3e324085657a3c2b4247
new file mode 100644
index 00000000..a2c37164
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/3d/9386c507f6b093471a3e324085657a3c2b4247
@@ -0,0 +1,3 @@
+xKj!E3vj#<<@Ouq .)ql osFa#v )g#{':Tl`b40 ;fr4
+
+zU-/glm\'LjrhXG_+l ʚE`;=]J \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/41/bd4bc3df978de695f67ace64c560913da11653 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/41/bd4bc3df978de695f67ace64c560913da11653
new file mode 100644
index 00000000..ccf49bd1
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/41/bd4bc3df978de695f67ace64c560913da11653
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/48/0095882d281ed676fe5b863569520e54a7d5c0 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/48/0095882d281ed676fe5b863569520e54a7d5c0
new file mode 100644
index 00000000..53029069
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/48/0095882d281ed676fe5b863569520e54a7d5c0
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/5e/4963595a9774b90524d35a807169049de8ccad b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/5e/4963595a9774b90524d35a807169049de8ccad
new file mode 100644
index 00000000..38c791eb
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/5e/4963595a9774b90524d35a807169049de8ccad
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/6b/31c659545507c381e9cd34ec508f16c04e149e b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
new file mode 100644
index 00000000..a26d2999
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
@@ -0,0 +1,2 @@
+xQ
+!Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8 \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/73/ba924a80437097795ae839e66e187c55d3babf b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/73/ba924a80437097795ae839e66e187c55d3babf
new file mode 100644
index 00000000..83d1ba48
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/73/ba924a80437097795ae839e66e187c55d3babf
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/77/fb0ed3e58568d6ad362c78de08ab8649d76e29 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/77/fb0ed3e58568d6ad362c78de08ab8649d76e29
new file mode 100644
index 00000000..f8a236f3
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/77/fb0ed3e58568d6ad362c78de08ab8649d76e29
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
new file mode 100644
index 00000000..6d27af8a
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
@@ -0,0 +1,2 @@
+x-10 Fa0p(N-ӡғq]>ks*? |m“i@mV'`).-1 x
+uxt(+ \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/78/9efbdadaa4a582778d4584385495559ea0994b b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/78/9efbdadaa4a582778d4584385495559ea0994b
new file mode 100644
index 00000000..17458840
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/78/9efbdadaa4a582778d4584385495559ea0994b
@@ -0,0 +1,2 @@
+x 0 )?= NlOkj8&r
+qJW7B<fK8#Q1C-"e̫>'@ \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
new file mode 100644
index 00000000..83cc29fb
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/8e/b1e637ed9fc8e5454fa20d38f809091f9395f4 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/8e/b1e637ed9fc8e5454fa20d38f809091f9395f4
new file mode 100644
index 00000000..8155b3e8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/8e/b1e637ed9fc8e5454fa20d38f809091f9395f4
@@ -0,0 +1,2 @@
+xMM;
+1) ZPr3k lEnl!crz ,e +lEZxuPYx QC*fuLcfR3T0'үj~G^s1b2zVk]5<v'> \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
new file mode 100644
index 00000000..55bda40e
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/packed-refs b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/packed-refs
new file mode 100644
index 00000000..5a4ebc47
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/packed-refs
@@ -0,0 +1,2 @@
+# pack-refs with: peeled
+480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/refs/heads/master b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/refs/heads/master
new file mode 100644
index 00000000..ae079bd7
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/refs/heads/master
@@ -0,0 +1 @@
+3d9386c507f6b093471a3e324085657a3c2b4247
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/refs/remotes/origin/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/refs/remotes/origin/HEAD
new file mode 100644
index 00000000..6efe28ff
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_head/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+ref: refs/remotes/origin/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/HEAD
new file mode 100644
index 00000000..cb089cd8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/config b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/config
new file mode 100644
index 00000000..0274ff7e
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/config
@@ -0,0 +1,13 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ worktree = ../../../sm_changed_index
+ ignorecase = true
+[remote "origin"]
+ fetch = +refs/heads/*:refs/remotes/origin/*
+ url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target
+[branch "master"]
+ remote = origin
+ merge = refs/heads/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/description b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/description
new file mode 100644
index 00000000..498b267a
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/hooks/applypatch-msg.sample b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/hooks/applypatch-msg.sample
new file mode 100755
index 00000000..8b2a2fe8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/hooks/applypatch-msg.sample
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message taken by
+# applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit. The hook is
+# allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "applypatch-msg".
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/commit-msg" &&
+ exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
+:
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/index b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/index
new file mode 100644
index 00000000..6fad3b43
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/index
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/info/exclude b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/info/exclude
new file mode 100644
index 00000000..a5196d1b
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/HEAD
new file mode 100644
index 00000000..80eb5410
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/HEAD
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342560175 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/refs/heads/master b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/refs/heads/master
new file mode 100644
index 00000000..80eb5410
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/refs/heads/master
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342560175 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/refs/remotes/origin/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/refs/remotes/origin/HEAD
new file mode 100644
index 00000000..80eb5410
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/logs/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342560175 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
new file mode 100644
index 00000000..f4b7094c
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
new file mode 100644
index 00000000..56c845e4
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
new file mode 100644
index 00000000..bd179b5f
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/41/bd4bc3df978de695f67ace64c560913da11653 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/41/bd4bc3df978de695f67ace64c560913da11653
new file mode 100644
index 00000000..ccf49bd1
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/41/bd4bc3df978de695f67ace64c560913da11653
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/48/0095882d281ed676fe5b863569520e54a7d5c0 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/48/0095882d281ed676fe5b863569520e54a7d5c0
new file mode 100644
index 00000000..53029069
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/48/0095882d281ed676fe5b863569520e54a7d5c0
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/5e/4963595a9774b90524d35a807169049de8ccad b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/5e/4963595a9774b90524d35a807169049de8ccad
new file mode 100644
index 00000000..38c791eb
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/5e/4963595a9774b90524d35a807169049de8ccad
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/6b/31c659545507c381e9cd34ec508f16c04e149e b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
new file mode 100644
index 00000000..a26d2999
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
@@ -0,0 +1,2 @@
+xQ
+!Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8 \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/73/ba924a80437097795ae839e66e187c55d3babf b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/73/ba924a80437097795ae839e66e187c55d3babf
new file mode 100644
index 00000000..83d1ba48
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/73/ba924a80437097795ae839e66e187c55d3babf
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
new file mode 100644
index 00000000..6d27af8a
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
@@ -0,0 +1,2 @@
+x-10 Fa0p(N-ӡғq]>ks*? |m“i@mV'`).-1 x
+uxt(+ \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/78/9efbdadaa4a582778d4584385495559ea0994b b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/78/9efbdadaa4a582778d4584385495559ea0994b
new file mode 100644
index 00000000..17458840
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/78/9efbdadaa4a582778d4584385495559ea0994b
@@ -0,0 +1,2 @@
+x 0 )?= NlOkj8&r
+qJW7B<fK8#Q1C-"e̫>'@ \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
new file mode 100644
index 00000000..83cc29fb
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/a0/2d31770687965547ab7a04cee199b29ee458d6 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/a0/2d31770687965547ab7a04cee199b29ee458d6
new file mode 100644
index 00000000..cb3f5a00
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/a0/2d31770687965547ab7a04cee199b29ee458d6
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
new file mode 100644
index 00000000..55bda40e
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/packed-refs b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/packed-refs
new file mode 100644
index 00000000..5a4ebc47
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/packed-refs
@@ -0,0 +1,2 @@
+# pack-refs with: peeled
+480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/refs/heads/master b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/refs/heads/master
new file mode 100644
index 00000000..e12c44d7
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/refs/heads/master
@@ -0,0 +1 @@
+480095882d281ed676fe5b863569520e54a7d5c0
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/refs/remotes/origin/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/refs/remotes/origin/HEAD
new file mode 100644
index 00000000..6efe28ff
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_index/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+ref: refs/remotes/origin/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/HEAD
new file mode 100644
index 00000000..cb089cd8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/config b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/config
new file mode 100644
index 00000000..7f258447
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/config
@@ -0,0 +1,13 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ worktree = ../../../sm_changed_untracked_file
+ ignorecase = true
+[remote "origin"]
+ fetch = +refs/heads/*:refs/remotes/origin/*
+ url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target
+[branch "master"]
+ remote = origin
+ merge = refs/heads/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/description b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/description
new file mode 100644
index 00000000..498b267a
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/hooks/applypatch-msg.sample b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/hooks/applypatch-msg.sample
new file mode 100755
index 00000000..8b2a2fe8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/hooks/applypatch-msg.sample
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message taken by
+# applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit. The hook is
+# allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "applypatch-msg".
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/commit-msg" &&
+ exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
+:
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/index b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/index
new file mode 100644
index 00000000..598e30a3
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/index
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/info/exclude b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/info/exclude
new file mode 100644
index 00000000..a5196d1b
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/HEAD
new file mode 100644
index 00000000..d1beafbd
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/HEAD
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342560186 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/refs/heads/master b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/refs/heads/master
new file mode 100644
index 00000000..d1beafbd
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/refs/heads/master
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342560186 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/refs/remotes/origin/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/refs/remotes/origin/HEAD
new file mode 100644
index 00000000..d1beafbd
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/logs/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342560186 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
new file mode 100644
index 00000000..f4b7094c
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
new file mode 100644
index 00000000..56c845e4
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
new file mode 100644
index 00000000..bd179b5f
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/41/bd4bc3df978de695f67ace64c560913da11653 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/41/bd4bc3df978de695f67ace64c560913da11653
new file mode 100644
index 00000000..ccf49bd1
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/41/bd4bc3df978de695f67ace64c560913da11653
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/48/0095882d281ed676fe5b863569520e54a7d5c0 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/48/0095882d281ed676fe5b863569520e54a7d5c0
new file mode 100644
index 00000000..53029069
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/48/0095882d281ed676fe5b863569520e54a7d5c0
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/5e/4963595a9774b90524d35a807169049de8ccad b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/5e/4963595a9774b90524d35a807169049de8ccad
new file mode 100644
index 00000000..38c791eb
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/5e/4963595a9774b90524d35a807169049de8ccad
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/6b/31c659545507c381e9cd34ec508f16c04e149e b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
new file mode 100644
index 00000000..a26d2999
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
@@ -0,0 +1,2 @@
+xQ
+!Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8 \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/73/ba924a80437097795ae839e66e187c55d3babf b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/73/ba924a80437097795ae839e66e187c55d3babf
new file mode 100644
index 00000000..83d1ba48
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/73/ba924a80437097795ae839e66e187c55d3babf
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
new file mode 100644
index 00000000..6d27af8a
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
@@ -0,0 +1,2 @@
+x-10 Fa0p(N-ӡғq]>ks*? |m“i@mV'`).-1 x
+uxt(+ \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/78/9efbdadaa4a582778d4584385495559ea0994b b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/78/9efbdadaa4a582778d4584385495559ea0994b
new file mode 100644
index 00000000..17458840
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/78/9efbdadaa4a582778d4584385495559ea0994b
@@ -0,0 +1,2 @@
+x 0 )?= NlOkj8&r
+qJW7B<fK8#Q1C-"e̫>'@ \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
new file mode 100644
index 00000000..83cc29fb
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5 b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
new file mode 100644
index 00000000..55bda40e
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/packed-refs b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/packed-refs
new file mode 100644
index 00000000..5a4ebc47
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/packed-refs
@@ -0,0 +1,2 @@
+# pack-refs with: peeled
+480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/refs/heads/master b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/refs/heads/master
new file mode 100644
index 00000000..e12c44d7
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/refs/heads/master
@@ -0,0 +1 @@
+480095882d281ed676fe5b863569520e54a7d5c0
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/refs/remotes/origin/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/refs/remotes/origin/HEAD
new file mode 100644
index 00000000..6efe28ff
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_changed_untracked_file/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+ref: refs/remotes/origin/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/HEAD
new file mode 100644
index 00000000..cb089cd8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/config b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/config
new file mode 100644
index 00000000..45fbb30c
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/config
@@ -0,0 +1,13 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ worktree = ../../../sm_missing_commits
+ ignorecase = true
+[remote "origin"]
+ fetch = +refs/heads/*:refs/remotes/origin/*
+ url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target
+[branch "master"]
+ remote = origin
+ merge = refs/heads/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/description b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/description
new file mode 100644
index 00000000..498b267a
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/hooks/applypatch-msg.sample b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/hooks/applypatch-msg.sample
new file mode 100755
index 00000000..8b2a2fe8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/hooks/applypatch-msg.sample
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message taken by
+# applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit. The hook is
+# allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "applypatch-msg".
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/commit-msg" &&
+ exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
+:
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/index b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/index
new file mode 100644
index 00000000..49035652
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/index
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/info/exclude b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/info/exclude
new file mode 100644
index 00000000..a5196d1b
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/HEAD
new file mode 100644
index 00000000..ee08c970
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/HEAD
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 5e4963595a9774b90524d35a807169049de8ccad Russell Belfer <rb@github.com> 1342559796 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/refs/heads/master b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/refs/heads/master
new file mode 100644
index 00000000..ee08c970
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/refs/heads/master
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 5e4963595a9774b90524d35a807169049de8ccad Russell Belfer <rb@github.com> 1342559796 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/refs/remotes/origin/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/refs/remotes/origin/HEAD
new file mode 100644
index 00000000..ee08c970
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/logs/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 5e4963595a9774b90524d35a807169049de8ccad Russell Belfer <rb@github.com> 1342559796 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1 b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
new file mode 100644
index 00000000..f4b7094c
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484 b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
new file mode 100644
index 00000000..56c845e4
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5 b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
new file mode 100644
index 00000000..bd179b5f
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/41/bd4bc3df978de695f67ace64c560913da11653 b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/41/bd4bc3df978de695f67ace64c560913da11653
new file mode 100644
index 00000000..ccf49bd1
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/41/bd4bc3df978de695f67ace64c560913da11653
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/5e/4963595a9774b90524d35a807169049de8ccad b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/5e/4963595a9774b90524d35a807169049de8ccad
new file mode 100644
index 00000000..38c791eb
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/5e/4963595a9774b90524d35a807169049de8ccad
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/6b/31c659545507c381e9cd34ec508f16c04e149e b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
new file mode 100644
index 00000000..a26d2999
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
@@ -0,0 +1,2 @@
+xQ
+!Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8 \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
new file mode 100644
index 00000000..6d27af8a
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
@@ -0,0 +1,2 @@
+x-10 Fa0p(N-ӡғq]>ks*? |m“i@mV'`).-1 x
+uxt(+ \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
new file mode 100644
index 00000000..83cc29fb
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5 b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
new file mode 100644
index 00000000..55bda40e
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/packed-refs b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/packed-refs
new file mode 100644
index 00000000..66fbf5da
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/packed-refs
@@ -0,0 +1,2 @@
+# pack-refs with: peeled
+5e4963595a9774b90524d35a807169049de8ccad refs/remotes/origin/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/refs/heads/master b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/refs/heads/master
new file mode 100644
index 00000000..3913aca5
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/refs/heads/master
@@ -0,0 +1 @@
+5e4963595a9774b90524d35a807169049de8ccad
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/refs/remotes/origin/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/refs/remotes/origin/HEAD
new file mode 100644
index 00000000..6efe28ff
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_missing_commits/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+ref: refs/remotes/origin/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/HEAD
new file mode 100644
index 00000000..cb089cd8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/config b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/config
new file mode 100644
index 00000000..fc706c9d
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/config
@@ -0,0 +1,13 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ worktree = ../../../sm_unchanged
+ ignorecase = true
+[remote "origin"]
+ fetch = +refs/heads/*:refs/remotes/origin/*
+ url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target
+[branch "master"]
+ remote = origin
+ merge = refs/heads/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/description b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/description
new file mode 100644
index 00000000..498b267a
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/hooks/applypatch-msg.sample b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/hooks/applypatch-msg.sample
new file mode 100755
index 00000000..8b2a2fe8
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/hooks/applypatch-msg.sample
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message taken by
+# applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit. The hook is
+# allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "applypatch-msg".
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/commit-msg" &&
+ exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
+:
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/index b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/index
new file mode 100644
index 00000000..629c849e
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/index
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/info/exclude b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/info/exclude
new file mode 100644
index 00000000..a5196d1b
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/HEAD
new file mode 100644
index 00000000..72653286
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/HEAD
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342560169 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/refs/heads/master b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/refs/heads/master
new file mode 100644
index 00000000..72653286
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/refs/heads/master
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342560169 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/refs/remotes/origin/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/refs/remotes/origin/HEAD
new file mode 100644
index 00000000..72653286
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/logs/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342560169 -0700 clone: from /Users/rb/src/libgit2/tests-clar/resources/submod2_target
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1 b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
new file mode 100644
index 00000000..f4b7094c
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484 b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
new file mode 100644
index 00000000..56c845e4
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5 b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
new file mode 100644
index 00000000..bd179b5f
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/41/bd4bc3df978de695f67ace64c560913da11653 b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/41/bd4bc3df978de695f67ace64c560913da11653
new file mode 100644
index 00000000..ccf49bd1
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/41/bd4bc3df978de695f67ace64c560913da11653
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/48/0095882d281ed676fe5b863569520e54a7d5c0 b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/48/0095882d281ed676fe5b863569520e54a7d5c0
new file mode 100644
index 00000000..53029069
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/48/0095882d281ed676fe5b863569520e54a7d5c0
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/5e/4963595a9774b90524d35a807169049de8ccad b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/5e/4963595a9774b90524d35a807169049de8ccad
new file mode 100644
index 00000000..38c791eb
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/5e/4963595a9774b90524d35a807169049de8ccad
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/6b/31c659545507c381e9cd34ec508f16c04e149e b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
new file mode 100644
index 00000000..a26d2999
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
@@ -0,0 +1,2 @@
+xQ
+!Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8 \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/73/ba924a80437097795ae839e66e187c55d3babf b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/73/ba924a80437097795ae839e66e187c55d3babf
new file mode 100644
index 00000000..83d1ba48
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/73/ba924a80437097795ae839e66e187c55d3babf
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
new file mode 100644
index 00000000..6d27af8a
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
@@ -0,0 +1,2 @@
+x-10 Fa0p(N-ӡғq]>ks*? |m“i@mV'`).-1 x
+uxt(+ \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/78/9efbdadaa4a582778d4584385495559ea0994b b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/78/9efbdadaa4a582778d4584385495559ea0994b
new file mode 100644
index 00000000..17458840
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/78/9efbdadaa4a582778d4584385495559ea0994b
@@ -0,0 +1,2 @@
+x 0 )?= NlOkj8&r
+qJW7B<fK8#Q1C-"e̫>'@ \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
new file mode 100644
index 00000000..83cc29fb
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5 b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
new file mode 100644
index 00000000..55bda40e
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/packed-refs b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/packed-refs
new file mode 100644
index 00000000..5a4ebc47
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/packed-refs
@@ -0,0 +1,2 @@
+# pack-refs with: peeled
+480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/refs/heads/master b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/refs/heads/master
new file mode 100644
index 00000000..e12c44d7
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/refs/heads/master
@@ -0,0 +1 @@
+480095882d281ed676fe5b863569520e54a7d5c0
diff --git a/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/refs/remotes/origin/HEAD b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/refs/remotes/origin/HEAD
new file mode 100644
index 00000000..6efe28ff
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/modules/sm_unchanged/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+ref: refs/remotes/origin/master
diff --git a/tests-clar/resources/submod2/.gitted/objects/09/460e5b6cbcb05a3e404593c32a3aa7221eca0e b/tests-clar/resources/submod2/.gitted/objects/09/460e5b6cbcb05a3e404593c32a3aa7221eca0e
new file mode 100644
index 00000000..f1ea5f4c
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/09/460e5b6cbcb05a3e404593c32a3aa7221eca0e
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/objects/14/fe9ccf104058df25e0a08361c4494e167ef243 b/tests-clar/resources/submod2/.gitted/objects/14/fe9ccf104058df25e0a08361c4494e167ef243
new file mode 100644
index 00000000..d3c8582e
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/14/fe9ccf104058df25e0a08361c4494e167ef243
@@ -0,0 +1 @@
+xM F]sfhcc;ހ@I(_O{s%@> ^!F'!諲l_q4E޶RݏS'n>>m^\w^$X_迦xE_.9} \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/objects/22/ce3e0311dda73a5992d54a4a595518d3876ea7 b/tests-clar/resources/submod2/.gitted/objects/22/ce3e0311dda73a5992d54a4a595518d3876ea7
new file mode 100644
index 00000000..fce6a94b
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/22/ce3e0311dda73a5992d54a4a595518d3876ea7
@@ -0,0 +1,4 @@
+x
+0Eݶ_Q.
+. W"!1 !3 >+.9=3W(n-:;j[" W{ޕQZW,2 iviyh T/={ !@b(bJcSPrŌ
+{`|%imp콡=IÿW26B@)|)g \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/objects/25/5546424b0efb847b1bfc91dbf7348b277f8970 b/tests-clar/resources/submod2/.gitted/objects/25/5546424b0efb847b1bfc91dbf7348b277f8970
new file mode 100644
index 00000000..2965becf
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/25/5546424b0efb847b1bfc91dbf7348b277f8970
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/objects/2a/30f1e6f94b20917005a21273f65b406d0f8bad b/tests-clar/resources/submod2/.gitted/objects/2a/30f1e6f94b20917005a21273f65b406d0f8bad
new file mode 100644
index 00000000..08faf0fa
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/2a/30f1e6f94b20917005a21273f65b406d0f8bad
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/objects/42/cfb95cd01bf9225b659b5ee3edcc78e8eeb478 b/tests-clar/resources/submod2/.gitted/objects/42/cfb95cd01bf9225b659b5ee3edcc78e8eeb478
new file mode 100644
index 00000000..ee7848ae
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/42/cfb95cd01bf9225b659b5ee3edcc78e8eeb478
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/objects/57/958699c2dc394f81cfc76950e9c3ac3025c398 b/tests-clar/resources/submod2/.gitted/objects/57/958699c2dc394f81cfc76950e9c3ac3025c398
new file mode 100644
index 00000000..ca9203a6
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/57/958699c2dc394f81cfc76950e9c3ac3025c398
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/objects/59/01da4f1c67756eeadc5121d206bec2431f253b b/tests-clar/resources/submod2/.gitted/objects/59/01da4f1c67756eeadc5121d206bec2431f253b
new file mode 100644
index 00000000..9f88f6bd
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/59/01da4f1c67756eeadc5121d206bec2431f253b
@@ -0,0 +1,2 @@
+x 1ENӀ2yg@D,A$;YE6m{΁e(/2d#jȚL 2Yd:fʞ =V^DhR $^a+tn {n8xs
+Ծ=<@jCŹک[>6#=-g?,F \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/objects/60/7d96653d4d0a4f733107f7890c2e67b55b620d b/tests-clar/resources/submod2/.gitted/objects/60/7d96653d4d0a4f733107f7890c2e67b55b620d
new file mode 100644
index 00000000..30bee40e
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/60/7d96653d4d0a4f733107f7890c2e67b55b620d
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/objects/74/84482eb8db738cafa696993664607500a3f2b9 b/tests-clar/resources/submod2/.gitted/objects/74/84482eb8db738cafa696993664607500a3f2b9
new file mode 100644
index 00000000..79018042
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/74/84482eb8db738cafa696993664607500a3f2b9
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/objects/7b/a4c5c3561daa5ab1a86215cfb0587e96d404d6 b/tests-clar/resources/submod2/.gitted/objects/7b/a4c5c3561daa5ab1a86215cfb0587e96d404d6
new file mode 100644
index 00000000..cde89e5b
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/7b/a4c5c3561daa5ab1a86215cfb0587e96d404d6
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/objects/87/3585b94bdeabccea991ea5e3ec1a277895b698 b/tests-clar/resources/submod2/.gitted/objects/87/3585b94bdeabccea991ea5e3ec1a277895b698
new file mode 100644
index 00000000..41af98aa
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/87/3585b94bdeabccea991ea5e3ec1a277895b698
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/objects/97/4cf7c73de336b0c4e019f918f3cee367d72e84 b/tests-clar/resources/submod2/.gitted/objects/97/4cf7c73de336b0c4e019f918f3cee367d72e84
new file mode 100644
index 00000000..160f1caf
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/97/4cf7c73de336b0c4e019f918f3cee367d72e84
@@ -0,0 +1,2 @@
+x
+0Eݶ_Bqg yi IYUp!΁s|R7=)XCAG:25:<-uU_IY\Ϥ%AF f{G qTPsu(Z{RA #̉0mŲ.8b?{vʌ \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/objects/9d/bc299bc013ea253583b40bf327b5a6e4037b89 b/tests-clar/resources/submod2/.gitted/objects/9d/bc299bc013ea253583b40bf327b5a6e4037b89
new file mode 100644
index 00000000..1ee52218
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/9d/bc299bc013ea253583b40bf327b5a6e4037b89
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/objects/a9/104bf89e911387244ef499413960ba472066d9 b/tests-clar/resources/submod2/.gitted/objects/a9/104bf89e911387244ef499413960ba472066d9
new file mode 100644
index 00000000..2239e14a
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/a9/104bf89e911387244ef499413960ba472066d9
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/objects/b6/14088620bbdc1d29549d223ceba0f4419fd4cb b/tests-clar/resources/submod2/.gitted/objects/b6/14088620bbdc1d29549d223ceba0f4419fd4cb
new file mode 100644
index 00000000..a03ea66e
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/b6/14088620bbdc1d29549d223ceba0f4419fd4cb
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/objects/d4/07f19e50c1da1ff584beafe0d6dac7237c5d06 b/tests-clar/resources/submod2/.gitted/objects/d4/07f19e50c1da1ff584beafe0d6dac7237c5d06
new file mode 100644
index 00000000..292303eb
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/d4/07f19e50c1da1ff584beafe0d6dac7237c5d06
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/objects/d9/3e95571d92cceb5de28c205f1d5f3cc8b88bc8 b/tests-clar/resources/submod2/.gitted/objects/d9/3e95571d92cceb5de28c205f1d5f3cc8b88bc8
new file mode 100644
index 00000000..b92c7eeb
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/d9/3e95571d92cceb5de28c205f1d5f3cc8b88bc8
@@ -0,0 +1,2 @@
+x
+!nק} ".zuRCx}Αہt .׫6,is&%9S#IW=aߐf2ABYsНa{c^K3gwM͠Fߥ4s'NI \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/objects/e3/b83bf274ee065eee48734cf8c6dfaf5e81471c b/tests-clar/resources/submod2/.gitted/objects/e3/b83bf274ee065eee48734cf8c6dfaf5e81471c
new file mode 100644
index 00000000..3c7750b1
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/e3/b83bf274ee065eee48734cf8c6dfaf5e81471c
Binary files differ
diff --git a/tests-clar/resources/submod2/.gitted/objects/f5/4414c25e6d24fe39f5c3f128d7c8a17bc23833 b/tests-clar/resources/submod2/.gitted/objects/f5/4414c25e6d24fe39f5c3f128d7c8a17bc23833
new file mode 100644
index 00000000..219620b2
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/f5/4414c25e6d24fe39f5c3f128d7c8a17bc23833
@@ -0,0 +1,2 @@
+xe
+0aSbOz1<I I+:?|st9hԥe6- H[wwM#ɪжm_; $ r1DPCvB¨McI^ \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/objects/f9/90a25a74d1a8281ce2ab018ea8df66795cd60b b/tests-clar/resources/submod2/.gitted/objects/f9/90a25a74d1a8281ce2ab018ea8df66795cd60b
new file mode 100644
index 00000000..883a40bf
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/objects/f9/90a25a74d1a8281ce2ab018ea8df66795cd60b
@@ -0,0 +1 @@
+xEA =Z)RE/b2 1usxš>2<EnG=2,ɜTĒ44!N$` \ No newline at end of file
diff --git a/tests-clar/resources/submod2/.gitted/refs/heads/master b/tests-clar/resources/submod2/.gitted/refs/heads/master
new file mode 100644
index 00000000..d1d38aa4
--- /dev/null
+++ b/tests-clar/resources/submod2/.gitted/refs/heads/master
@@ -0,0 +1 @@
+7484482eb8db738cafa696993664607500a3f2b9
diff --git a/tests-clar/resources/submod2/README.txt b/tests-clar/resources/submod2/README.txt
new file mode 100644
index 00000000..f990a25a
--- /dev/null
+++ b/tests-clar/resources/submod2/README.txt
@@ -0,0 +1,3 @@
+This is the submodule test data
+This repo will have a bunch of submodules in different states
+
diff --git a/tests-clar/resources/submod2/gitmodules b/tests-clar/resources/submod2/gitmodules
new file mode 100644
index 00000000..7b150b18
--- /dev/null
+++ b/tests-clar/resources/submod2/gitmodules
@@ -0,0 +1,21 @@
+[submodule "sm_missing_commits"]
+ path = sm_missing_commits
+ url = ../submod2_target
+[submodule "sm_unchanged"]
+ path = sm_unchanged
+ url = ../submod2_target
+[submodule "sm_changed_file"]
+ path = sm_changed_file
+ url = ../submod2_target
+[submodule "sm_changed_index"]
+ path = sm_changed_index
+ url = ../submod2_target
+[submodule "sm_changed_head"]
+ path = sm_changed_head
+ url = ../submod2_target
+[submodule "sm_changed_untracked_file"]
+ path = sm_changed_untracked_file
+ url = ../submod2_target
+[submodule "sm_added_and_uncommited"]
+ path = sm_added_and_uncommited
+ url = ../submod2_target
diff --git a/tests-clar/resources/submod2/just_a_dir/contents b/tests-clar/resources/submod2/just_a_dir/contents
new file mode 100644
index 00000000..7ba4c5c3
--- /dev/null
+++ b/tests-clar/resources/submod2/just_a_dir/contents
@@ -0,0 +1 @@
+This is a file in a plain directory
diff --git a/tests-clar/resources/submod2/just_a_file b/tests-clar/resources/submod2/just_a_file
new file mode 100644
index 00000000..42cfb95c
--- /dev/null
+++ b/tests-clar/resources/submod2/just_a_file
@@ -0,0 +1 @@
+This is just a plain file
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/COMMIT_EDITMSG b/tests-clar/resources/submod2/not_submodule/.gitted/COMMIT_EDITMSG
new file mode 100644
index 00000000..5852f446
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/COMMIT_EDITMSG
@@ -0,0 +1 @@
+Initial commit
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/HEAD b/tests-clar/resources/submod2/not_submodule/.gitted/HEAD
new file mode 100644
index 00000000..cb089cd8
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/config b/tests-clar/resources/submod2/not_submodule/.gitted/config
new file mode 100644
index 00000000..af107929
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/config
@@ -0,0 +1,6 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ ignorecase = true
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/description b/tests-clar/resources/submod2/not_submodule/.gitted/description
new file mode 100644
index 00000000..498b267a
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/hooks/applypatch-msg.sample b/tests-clar/resources/submod2/not_submodule/.gitted/hooks/applypatch-msg.sample
new file mode 100755
index 00000000..8b2a2fe8
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/hooks/applypatch-msg.sample
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message taken by
+# applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit. The hook is
+# allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "applypatch-msg".
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/commit-msg" &&
+ exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
+:
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/hooks/commit-msg.sample b/tests-clar/resources/submod2/not_submodule/.gitted/hooks/commit-msg.sample
new file mode 100755
index 00000000..b58d1184
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/hooks/commit-msg.sample
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message.
+# Called by "git commit" with one argument, the name of the file
+# that has the commit message. The hook should exit with non-zero
+# status after issuing an appropriate message if it wants to stop the
+# commit. The hook is allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "commit-msg".
+
+# Uncomment the below to add a Signed-off-by line to the message.
+# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
+# hook is more suited to it.
+#
+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
+
+# This example catches duplicate Signed-off-by lines.
+
+test "" = "$(grep '^Signed-off-by: ' "$1" |
+ sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
+ echo >&2 Duplicate Signed-off-by lines.
+ exit 1
+}
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/hooks/post-update.sample b/tests-clar/resources/submod2/not_submodule/.gitted/hooks/post-update.sample
new file mode 100755
index 00000000..ec17ec19
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/hooks/post-update.sample
@@ -0,0 +1,8 @@
+#!/bin/sh
+#
+# An example hook script to prepare a packed repository for use over
+# dumb transports.
+#
+# To enable this hook, rename this file to "post-update".
+
+exec git update-server-info
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/hooks/pre-applypatch.sample b/tests-clar/resources/submod2/not_submodule/.gitted/hooks/pre-applypatch.sample
new file mode 100755
index 00000000..b1f187c2
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/hooks/pre-applypatch.sample
@@ -0,0 +1,14 @@
+#!/bin/sh
+#
+# An example hook script to verify what is about to be committed
+# by applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit.
+#
+# To enable this hook, rename this file to "pre-applypatch".
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/pre-commit" &&
+ exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
+:
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/hooks/pre-commit.sample b/tests-clar/resources/submod2/not_submodule/.gitted/hooks/pre-commit.sample
new file mode 100755
index 00000000..18c48297
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/hooks/pre-commit.sample
@@ -0,0 +1,50 @@
+#!/bin/sh
+#
+# An example hook script to verify what is about to be committed.
+# Called by "git commit" with no arguments. The hook should
+# exit with non-zero status after issuing an appropriate message if
+# it wants to stop the commit.
+#
+# To enable this hook, rename this file to "pre-commit".
+
+if git rev-parse --verify HEAD >/dev/null 2>&1
+then
+ against=HEAD
+else
+ # Initial commit: diff against an empty tree object
+ against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+fi
+
+# If you want to allow non-ascii filenames set this variable to true.
+allownonascii=$(git config hooks.allownonascii)
+
+# Redirect output to stderr.
+exec 1>&2
+
+# Cross platform projects tend to avoid non-ascii filenames; prevent
+# them from being added to the repository. We exploit the fact that the
+# printable range starts at the space character and ends with tilde.
+if [ "$allownonascii" != "true" ] &&
+ # Note that the use of brackets around a tr range is ok here, (it's
+ # even required, for portability to Solaris 10's /usr/bin/tr), since
+ # the square bracket bytes happen to fall in the designated range.
+ test $(git diff --cached --name-only --diff-filter=A -z $against |
+ LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
+then
+ echo "Error: Attempt to add a non-ascii file name."
+ echo
+ echo "This can cause problems if you want to work"
+ echo "with people on other platforms."
+ echo
+ echo "To be portable it is advisable to rename the file ..."
+ echo
+ echo "If you know what you are doing you can disable this"
+ echo "check using:"
+ echo
+ echo " git config hooks.allownonascii true"
+ echo
+ exit 1
+fi
+
+# If there are whitespace errors, print the offending file names and fail.
+exec git diff-index --check --cached $against --
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/hooks/pre-rebase.sample b/tests-clar/resources/submod2/not_submodule/.gitted/hooks/pre-rebase.sample
new file mode 100755
index 00000000..9773ed4c
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/hooks/pre-rebase.sample
@@ -0,0 +1,169 @@
+#!/bin/sh
+#
+# Copyright (c) 2006, 2008 Junio C Hamano
+#
+# The "pre-rebase" hook is run just before "git rebase" starts doing
+# its job, and can prevent the command from running by exiting with
+# non-zero status.
+#
+# The hook is called with the following parameters:
+#
+# $1 -- the upstream the series was forked from.
+# $2 -- the branch being rebased (or empty when rebasing the current branch).
+#
+# This sample shows how to prevent topic branches that are already
+# merged to 'next' branch from getting rebased, because allowing it
+# would result in rebasing already published history.
+
+publish=next
+basebranch="$1"
+if test "$#" = 2
+then
+ topic="refs/heads/$2"
+else
+ topic=`git symbolic-ref HEAD` ||
+ exit 0 ;# we do not interrupt rebasing detached HEAD
+fi
+
+case "$topic" in
+refs/heads/??/*)
+ ;;
+*)
+ exit 0 ;# we do not interrupt others.
+ ;;
+esac
+
+# Now we are dealing with a topic branch being rebased
+# on top of master. Is it OK to rebase it?
+
+# Does the topic really exist?
+git show-ref -q "$topic" || {
+ echo >&2 "No such branch $topic"
+ exit 1
+}
+
+# Is topic fully merged to master?
+not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
+if test -z "$not_in_master"
+then
+ echo >&2 "$topic is fully merged to master; better remove it."
+ exit 1 ;# we could allow it, but there is no point.
+fi
+
+# Is topic ever merged to next? If so you should not be rebasing it.
+only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
+only_next_2=`git rev-list ^master ${publish} | sort`
+if test "$only_next_1" = "$only_next_2"
+then
+ not_in_topic=`git rev-list "^$topic" master`
+ if test -z "$not_in_topic"
+ then
+ echo >&2 "$topic is already up-to-date with master"
+ exit 1 ;# we could allow it, but there is no point.
+ else
+ exit 0
+ fi
+else
+ not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
+ /usr/bin/perl -e '
+ my $topic = $ARGV[0];
+ my $msg = "* $topic has commits already merged to public branch:\n";
+ my (%not_in_next) = map {
+ /^([0-9a-f]+) /;
+ ($1 => 1);
+ } split(/\n/, $ARGV[1]);
+ for my $elem (map {
+ /^([0-9a-f]+) (.*)$/;
+ [$1 => $2];
+ } split(/\n/, $ARGV[2])) {
+ if (!exists $not_in_next{$elem->[0]}) {
+ if ($msg) {
+ print STDERR $msg;
+ undef $msg;
+ }
+ print STDERR " $elem->[1]\n";
+ }
+ }
+ ' "$topic" "$not_in_next" "$not_in_master"
+ exit 1
+fi
+
+exit 0
+
+################################################################
+
+This sample hook safeguards topic branches that have been
+published from being rewound.
+
+The workflow assumed here is:
+
+ * Once a topic branch forks from "master", "master" is never
+ merged into it again (either directly or indirectly).
+
+ * Once a topic branch is fully cooked and merged into "master",
+ it is deleted. If you need to build on top of it to correct
+ earlier mistakes, a new topic branch is created by forking at
+ the tip of the "master". This is not strictly necessary, but
+ it makes it easier to keep your history simple.
+
+ * Whenever you need to test or publish your changes to topic
+ branches, merge them into "next" branch.
+
+The script, being an example, hardcodes the publish branch name
+to be "next", but it is trivial to make it configurable via
+$GIT_DIR/config mechanism.
+
+With this workflow, you would want to know:
+
+(1) ... if a topic branch has ever been merged to "next". Young
+ topic branches can have stupid mistakes you would rather
+ clean up before publishing, and things that have not been
+ merged into other branches can be easily rebased without
+ affecting other people. But once it is published, you would
+ not want to rewind it.
+
+(2) ... if a topic branch has been fully merged to "master".
+ Then you can delete it. More importantly, you should not
+ build on top of it -- other people may already want to
+ change things related to the topic as patches against your
+ "master", so if you need further changes, it is better to
+ fork the topic (perhaps with the same name) afresh from the
+ tip of "master".
+
+Let's look at this example:
+
+ o---o---o---o---o---o---o---o---o---o "next"
+ / / / /
+ / a---a---b A / /
+ / / / /
+ / / c---c---c---c B /
+ / / / \ /
+ / / / b---b C \ /
+ / / / / \ /
+ ---o---o---o---o---o---o---o---o---o---o---o "master"
+
+
+A, B and C are topic branches.
+
+ * A has one fix since it was merged up to "next".
+
+ * B has finished. It has been fully merged up to "master" and "next",
+ and is ready to be deleted.
+
+ * C has not merged to "next" at all.
+
+We would want to allow C to be rebased, refuse A, and encourage
+B to be deleted.
+
+To compute (1):
+
+ git rev-list ^master ^topic next
+ git rev-list ^master next
+
+ if these match, topic has not merged in next at all.
+
+To compute (2):
+
+ git rev-list master..topic
+
+ if this is empty, it is fully merged to "master".
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/hooks/prepare-commit-msg.sample b/tests-clar/resources/submod2/not_submodule/.gitted/hooks/prepare-commit-msg.sample
new file mode 100755
index 00000000..f093a02e
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/hooks/prepare-commit-msg.sample
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# An example hook script to prepare the commit log message.
+# Called by "git commit" with the name of the file that has the
+# commit message, followed by the description of the commit
+# message's source. The hook's purpose is to edit the commit
+# message file. If the hook fails with a non-zero status,
+# the commit is aborted.
+#
+# To enable this hook, rename this file to "prepare-commit-msg".
+
+# This hook includes three examples. The first comments out the
+# "Conflicts:" part of a merge commit.
+#
+# The second includes the output of "git diff --name-status -r"
+# into the message, just before the "git status" output. It is
+# commented because it doesn't cope with --amend or with squashed
+# commits.
+#
+# The third example adds a Signed-off-by line to the message, that can
+# still be edited. This is rarely a good idea.
+
+case "$2,$3" in
+ merge,)
+ /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
+
+# ,|template,)
+# /usr/bin/perl -i.bak -pe '
+# print "\n" . `git diff --cached --name-status -r`
+# if /^#/ && $first++ == 0' "$1" ;;
+
+ *) ;;
+esac
+
+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/hooks/update.sample b/tests-clar/resources/submod2/not_submodule/.gitted/hooks/update.sample
new file mode 100755
index 00000000..71ab04ed
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/hooks/update.sample
@@ -0,0 +1,128 @@
+#!/bin/sh
+#
+# An example hook script to blocks unannotated tags from entering.
+# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
+#
+# To enable this hook, rename this file to "update".
+#
+# Config
+# ------
+# hooks.allowunannotated
+# This boolean sets whether unannotated tags will be allowed into the
+# repository. By default they won't be.
+# hooks.allowdeletetag
+# This boolean sets whether deleting tags will be allowed in the
+# repository. By default they won't be.
+# hooks.allowmodifytag
+# This boolean sets whether a tag may be modified after creation. By default
+# it won't be.
+# hooks.allowdeletebranch
+# This boolean sets whether deleting branches will be allowed in the
+# repository. By default they won't be.
+# hooks.denycreatebranch
+# This boolean sets whether remotely creating branches will be denied
+# in the repository. By default this is allowed.
+#
+
+# --- Command line
+refname="$1"
+oldrev="$2"
+newrev="$3"
+
+# --- Safety check
+if [ -z "$GIT_DIR" ]; then
+ echo "Don't run this script from the command line." >&2
+ echo " (if you want, you could supply GIT_DIR then run" >&2
+ echo " $0 <ref> <oldrev> <newrev>)" >&2
+ exit 1
+fi
+
+if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
+ echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
+ exit 1
+fi
+
+# --- Config
+allowunannotated=$(git config --bool hooks.allowunannotated)
+allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
+denycreatebranch=$(git config --bool hooks.denycreatebranch)
+allowdeletetag=$(git config --bool hooks.allowdeletetag)
+allowmodifytag=$(git config --bool hooks.allowmodifytag)
+
+# check for no description
+projectdesc=$(sed -e '1q' "$GIT_DIR/description")
+case "$projectdesc" in
+"Unnamed repository"* | "")
+ echo "*** Project description file hasn't been set" >&2
+ exit 1
+ ;;
+esac
+
+# --- Check types
+# if $newrev is 0000...0000, it's a commit to delete a ref.
+zero="0000000000000000000000000000000000000000"
+if [ "$newrev" = "$zero" ]; then
+ newrev_type=delete
+else
+ newrev_type=$(git cat-file -t $newrev)
+fi
+
+case "$refname","$newrev_type" in
+ refs/tags/*,commit)
+ # un-annotated tag
+ short_refname=${refname##refs/tags/}
+ if [ "$allowunannotated" != "true" ]; then
+ echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
+ echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
+ exit 1
+ fi
+ ;;
+ refs/tags/*,delete)
+ # delete tag
+ if [ "$allowdeletetag" != "true" ]; then
+ echo "*** Deleting a tag is not allowed in this repository" >&2
+ exit 1
+ fi
+ ;;
+ refs/tags/*,tag)
+ # annotated tag
+ if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
+ then
+ echo "*** Tag '$refname' already exists." >&2
+ echo "*** Modifying a tag is not allowed in this repository." >&2
+ exit 1
+ fi
+ ;;
+ refs/heads/*,commit)
+ # branch
+ if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
+ echo "*** Creating a branch is not allowed in this repository" >&2
+ exit 1
+ fi
+ ;;
+ refs/heads/*,delete)
+ # delete branch
+ if [ "$allowdeletebranch" != "true" ]; then
+ echo "*** Deleting a branch is not allowed in this repository" >&2
+ exit 1
+ fi
+ ;;
+ refs/remotes/*,commit)
+ # tracking branch
+ ;;
+ refs/remotes/*,delete)
+ # delete tracking branch
+ if [ "$allowdeletebranch" != "true" ]; then
+ echo "*** Deleting a tracking branch is not allowed in this repository" >&2
+ exit 1
+ fi
+ ;;
+ *)
+ # Anything else (is there anything else?)
+ echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
+ exit 1
+ ;;
+esac
+
+# --- Finished
+exit 0
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/index b/tests-clar/resources/submod2/not_submodule/.gitted/index
new file mode 100644
index 00000000..f3fafa53
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/index
Binary files differ
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/info/exclude b/tests-clar/resources/submod2/not_submodule/.gitted/info/exclude
new file mode 100644
index 00000000..a5196d1b
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/logs/HEAD b/tests-clar/resources/submod2/not_submodule/.gitted/logs/HEAD
new file mode 100644
index 00000000..1749e7df
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/logs/HEAD
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 68e92c611b80ee1ed8f38314ff9577f0d15b2444 Russell Belfer <rb@github.com> 1342560358 -0700 commit (initial): Initial commit
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/logs/refs/heads/master b/tests-clar/resources/submod2/not_submodule/.gitted/logs/refs/heads/master
new file mode 100644
index 00000000..1749e7df
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/logs/refs/heads/master
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 68e92c611b80ee1ed8f38314ff9577f0d15b2444 Russell Belfer <rb@github.com> 1342560358 -0700 commit (initial): Initial commit
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/objects/68/e92c611b80ee1ed8f38314ff9577f0d15b2444 b/tests-clar/resources/submod2/not_submodule/.gitted/objects/68/e92c611b80ee1ed8f38314ff9577f0d15b2444
new file mode 100644
index 00000000..8892531a
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/objects/68/e92c611b80ee1ed8f38314ff9577f0d15b2444
Binary files differ
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/objects/71/ff9927d7c8a5639e062c38a7d35c433c424627 b/tests-clar/resources/submod2/not_submodule/.gitted/objects/71/ff9927d7c8a5639e062c38a7d35c433c424627
new file mode 100644
index 00000000..c4e1a77d
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/objects/71/ff9927d7c8a5639e062c38a7d35c433c424627
Binary files differ
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/objects/f0/1d56b18efd353ef2bb93a4585d590a0847195e b/tests-clar/resources/submod2/not_submodule/.gitted/objects/f0/1d56b18efd353ef2bb93a4585d590a0847195e
new file mode 100644
index 00000000..e9f1942a
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/objects/f0/1d56b18efd353ef2bb93a4585d590a0847195e
Binary files differ
diff --git a/tests-clar/resources/submod2/not_submodule/.gitted/refs/heads/master b/tests-clar/resources/submod2/not_submodule/.gitted/refs/heads/master
new file mode 100644
index 00000000..0bd8514b
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/.gitted/refs/heads/master
@@ -0,0 +1 @@
+68e92c611b80ee1ed8f38314ff9577f0d15b2444
diff --git a/tests-clar/resources/submod2/not_submodule/README.txt b/tests-clar/resources/submod2/not_submodule/README.txt
new file mode 100644
index 00000000..71ff9927
--- /dev/null
+++ b/tests-clar/resources/submod2/not_submodule/README.txt
@@ -0,0 +1 @@
+This is a git repo but not a submodule
diff --git a/tests-clar/resources/submod2/sm_added_and_uncommited/.gitted b/tests-clar/resources/submod2/sm_added_and_uncommited/.gitted
new file mode 100644
index 00000000..2b2a4cf9
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_added_and_uncommited/.gitted
@@ -0,0 +1 @@
+gitdir: ../.git/modules/sm_added_and_uncommited
diff --git a/tests-clar/resources/submod2/sm_added_and_uncommited/README.txt b/tests-clar/resources/submod2/sm_added_and_uncommited/README.txt
new file mode 100644
index 00000000..780d7397
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_added_and_uncommited/README.txt
@@ -0,0 +1,3 @@
+This is the target for submod2 submodule links.
+Don't add commits casually because you make break tests.
+
diff --git a/tests-clar/resources/submod2/sm_added_and_uncommited/file_to_modify b/tests-clar/resources/submod2/sm_added_and_uncommited/file_to_modify
new file mode 100644
index 00000000..789efbda
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_added_and_uncommited/file_to_modify
@@ -0,0 +1,3 @@
+This is a file to modify in submodules
+It already has some history.
+You can add local changes as needed.
diff --git a/tests-clar/resources/submod2/sm_changed_file/.gitted b/tests-clar/resources/submod2/sm_changed_file/.gitted
new file mode 100644
index 00000000..dc98b167
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_changed_file/.gitted
@@ -0,0 +1 @@
+gitdir: ../.git/modules/sm_changed_file
diff --git a/tests-clar/resources/submod2/sm_changed_file/README.txt b/tests-clar/resources/submod2/sm_changed_file/README.txt
new file mode 100644
index 00000000..780d7397
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_changed_file/README.txt
@@ -0,0 +1,3 @@
+This is the target for submod2 submodule links.
+Don't add commits casually because you make break tests.
+
diff --git a/tests-clar/resources/submod2/sm_changed_file/file_to_modify b/tests-clar/resources/submod2/sm_changed_file/file_to_modify
new file mode 100644
index 00000000..e5ba6716
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_changed_file/file_to_modify
@@ -0,0 +1,4 @@
+This is a file to modify in submodules
+It already has some history.
+You can add local changes as needed.
+In this case, the file is changed in the workdir
diff --git a/tests-clar/resources/submod2/sm_changed_head/.gitted b/tests-clar/resources/submod2/sm_changed_head/.gitted
new file mode 100644
index 00000000..d5419b62
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_changed_head/.gitted
@@ -0,0 +1 @@
+gitdir: ../.git/modules/sm_changed_head
diff --git a/tests-clar/resources/submod2/sm_changed_head/README.txt b/tests-clar/resources/submod2/sm_changed_head/README.txt
new file mode 100644
index 00000000..780d7397
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_changed_head/README.txt
@@ -0,0 +1,3 @@
+This is the target for submod2 submodule links.
+Don't add commits casually because you make break tests.
+
diff --git a/tests-clar/resources/submod2/sm_changed_head/file_to_modify b/tests-clar/resources/submod2/sm_changed_head/file_to_modify
new file mode 100644
index 00000000..8eb1e637
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_changed_head/file_to_modify
@@ -0,0 +1,4 @@
+This is a file to modify in submodules
+It already has some history.
+You can add local changes as needed.
+This one has been changed and the change has been committed to HEAD.
diff --git a/tests-clar/resources/submod2/sm_changed_index/.gitted b/tests-clar/resources/submod2/sm_changed_index/.gitted
new file mode 100644
index 00000000..2c7a5b27
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_changed_index/.gitted
@@ -0,0 +1 @@
+gitdir: ../.git/modules/sm_changed_index
diff --git a/tests-clar/resources/submod2/sm_changed_index/README.txt b/tests-clar/resources/submod2/sm_changed_index/README.txt
new file mode 100644
index 00000000..780d7397
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_changed_index/README.txt
@@ -0,0 +1,3 @@
+This is the target for submod2 submodule links.
+Don't add commits casually because you make break tests.
+
diff --git a/tests-clar/resources/submod2/sm_changed_index/file_to_modify b/tests-clar/resources/submod2/sm_changed_index/file_to_modify
new file mode 100644
index 00000000..a02d3177
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_changed_index/file_to_modify
@@ -0,0 +1,4 @@
+This is a file to modify in submodules
+It already has some history.
+You can add local changes as needed.
+Here the file is changed in the index and the workdir
diff --git a/tests-clar/resources/submod2/sm_changed_untracked_file/.gitted b/tests-clar/resources/submod2/sm_changed_untracked_file/.gitted
new file mode 100644
index 00000000..9a107064
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_changed_untracked_file/.gitted
@@ -0,0 +1 @@
+gitdir: ../.git/modules/sm_changed_untracked_file
diff --git a/tests-clar/resources/submod2/sm_changed_untracked_file/README.txt b/tests-clar/resources/submod2/sm_changed_untracked_file/README.txt
new file mode 100644
index 00000000..780d7397
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_changed_untracked_file/README.txt
@@ -0,0 +1,3 @@
+This is the target for submod2 submodule links.
+Don't add commits casually because you make break tests.
+
diff --git a/tests-clar/resources/submod2/sm_changed_untracked_file/file_to_modify b/tests-clar/resources/submod2/sm_changed_untracked_file/file_to_modify
new file mode 100644
index 00000000..789efbda
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_changed_untracked_file/file_to_modify
@@ -0,0 +1,3 @@
+This is a file to modify in submodules
+It already has some history.
+You can add local changes as needed.
diff --git a/tests-clar/resources/submod2/sm_changed_untracked_file/i_am_untracked b/tests-clar/resources/submod2/sm_changed_untracked_file/i_am_untracked
new file mode 100644
index 00000000..d2bae616
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_changed_untracked_file/i_am_untracked
@@ -0,0 +1 @@
+This file is untracked, but in a submodule
diff --git a/tests-clar/resources/submod2/sm_missing_commits/.gitted b/tests-clar/resources/submod2/sm_missing_commits/.gitted
new file mode 100644
index 00000000..70193be8
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_missing_commits/.gitted
@@ -0,0 +1 @@
+gitdir: ../.git/modules/sm_missing_commits
diff --git a/tests-clar/resources/submod2/sm_missing_commits/README.txt b/tests-clar/resources/submod2/sm_missing_commits/README.txt
new file mode 100644
index 00000000..780d7397
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_missing_commits/README.txt
@@ -0,0 +1,3 @@
+This is the target for submod2 submodule links.
+Don't add commits casually because you make break tests.
+
diff --git a/tests-clar/resources/submod2/sm_missing_commits/file_to_modify b/tests-clar/resources/submod2/sm_missing_commits/file_to_modify
new file mode 100644
index 00000000..8834b635
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_missing_commits/file_to_modify
@@ -0,0 +1,3 @@
+This is a file to modify in submodules
+It already has some history.
+
diff --git a/tests-clar/resources/submod2/sm_unchanged/.gitted b/tests-clar/resources/submod2/sm_unchanged/.gitted
new file mode 100644
index 00000000..51a679c8
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_unchanged/.gitted
@@ -0,0 +1 @@
+gitdir: ../.git/modules/sm_unchanged
diff --git a/tests-clar/resources/submod2/sm_unchanged/README.txt b/tests-clar/resources/submod2/sm_unchanged/README.txt
new file mode 100644
index 00000000..780d7397
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_unchanged/README.txt
@@ -0,0 +1,3 @@
+This is the target for submod2 submodule links.
+Don't add commits casually because you make break tests.
+
diff --git a/tests-clar/resources/submod2/sm_unchanged/file_to_modify b/tests-clar/resources/submod2/sm_unchanged/file_to_modify
new file mode 100644
index 00000000..789efbda
--- /dev/null
+++ b/tests-clar/resources/submod2/sm_unchanged/file_to_modify
@@ -0,0 +1,3 @@
+This is a file to modify in submodules
+It already has some history.
+You can add local changes as needed.
diff --git a/tests-clar/resources/submod2_target/.gitted/HEAD b/tests-clar/resources/submod2_target/.gitted/HEAD
new file mode 100644
index 00000000..cb089cd8
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests-clar/resources/submod2_target/.gitted/config b/tests-clar/resources/submod2_target/.gitted/config
new file mode 100644
index 00000000..af107929
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/config
@@ -0,0 +1,6 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ ignorecase = true
diff --git a/tests-clar/resources/submod2_target/.gitted/description b/tests-clar/resources/submod2_target/.gitted/description
new file mode 100644
index 00000000..498b267a
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests-clar/resources/submod2_target/.gitted/hooks/applypatch-msg.sample b/tests-clar/resources/submod2_target/.gitted/hooks/applypatch-msg.sample
new file mode 100755
index 00000000..8b2a2fe8
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/hooks/applypatch-msg.sample
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message taken by
+# applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit. The hook is
+# allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "applypatch-msg".
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/commit-msg" &&
+ exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
+:
diff --git a/tests-clar/resources/submod2_target/.gitted/index b/tests-clar/resources/submod2_target/.gitted/index
new file mode 100644
index 00000000..eb3ff8c1
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/index
Binary files differ
diff --git a/tests-clar/resources/submod2_target/.gitted/info/exclude b/tests-clar/resources/submod2_target/.gitted/info/exclude
new file mode 100644
index 00000000..a5196d1b
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests-clar/resources/submod2_target/.gitted/logs/HEAD b/tests-clar/resources/submod2_target/.gitted/logs/HEAD
new file mode 100644
index 00000000..0ecd1113
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/logs/HEAD
@@ -0,0 +1,4 @@
+0000000000000000000000000000000000000000 6b31c659545507c381e9cd34ec508f16c04e149e Russell Belfer <rb@github.com> 1342559662 -0700 commit (initial): Initial commit
+6b31c659545507c381e9cd34ec508f16c04e149e 41bd4bc3df978de695f67ace64c560913da11653 Russell Belfer <rb@github.com> 1342559709 -0700 commit: Adding test file
+41bd4bc3df978de695f67ace64c560913da11653 5e4963595a9774b90524d35a807169049de8ccad Russell Belfer <rb@github.com> 1342559726 -0700 commit: Updating test file
+5e4963595a9774b90524d35a807169049de8ccad 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342559925 -0700 commit: One more update
diff --git a/tests-clar/resources/submod2_target/.gitted/logs/refs/heads/master b/tests-clar/resources/submod2_target/.gitted/logs/refs/heads/master
new file mode 100644
index 00000000..0ecd1113
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/logs/refs/heads/master
@@ -0,0 +1,4 @@
+0000000000000000000000000000000000000000 6b31c659545507c381e9cd34ec508f16c04e149e Russell Belfer <rb@github.com> 1342559662 -0700 commit (initial): Initial commit
+6b31c659545507c381e9cd34ec508f16c04e149e 41bd4bc3df978de695f67ace64c560913da11653 Russell Belfer <rb@github.com> 1342559709 -0700 commit: Adding test file
+41bd4bc3df978de695f67ace64c560913da11653 5e4963595a9774b90524d35a807169049de8ccad Russell Belfer <rb@github.com> 1342559726 -0700 commit: Updating test file
+5e4963595a9774b90524d35a807169049de8ccad 480095882d281ed676fe5b863569520e54a7d5c0 Russell Belfer <rb@github.com> 1342559925 -0700 commit: One more update
diff --git a/tests-clar/resources/submod2_target/.gitted/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1 b/tests-clar/resources/submod2_target/.gitted/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
new file mode 100644
index 00000000..f4b7094c
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
Binary files differ
diff --git a/tests-clar/resources/submod2_target/.gitted/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484 b/tests-clar/resources/submod2_target/.gitted/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
new file mode 100644
index 00000000..56c845e4
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
Binary files differ
diff --git a/tests-clar/resources/submod2_target/.gitted/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5 b/tests-clar/resources/submod2_target/.gitted/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
new file mode 100644
index 00000000..bd179b5f
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
Binary files differ
diff --git a/tests-clar/resources/submod2_target/.gitted/objects/41/bd4bc3df978de695f67ace64c560913da11653 b/tests-clar/resources/submod2_target/.gitted/objects/41/bd4bc3df978de695f67ace64c560913da11653
new file mode 100644
index 00000000..ccf49bd1
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/objects/41/bd4bc3df978de695f67ace64c560913da11653
Binary files differ
diff --git a/tests-clar/resources/submod2_target/.gitted/objects/48/0095882d281ed676fe5b863569520e54a7d5c0 b/tests-clar/resources/submod2_target/.gitted/objects/48/0095882d281ed676fe5b863569520e54a7d5c0
new file mode 100644
index 00000000..53029069
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/objects/48/0095882d281ed676fe5b863569520e54a7d5c0
Binary files differ
diff --git a/tests-clar/resources/submod2_target/.gitted/objects/5e/4963595a9774b90524d35a807169049de8ccad b/tests-clar/resources/submod2_target/.gitted/objects/5e/4963595a9774b90524d35a807169049de8ccad
new file mode 100644
index 00000000..38c791eb
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/objects/5e/4963595a9774b90524d35a807169049de8ccad
Binary files differ
diff --git a/tests-clar/resources/submod2_target/.gitted/objects/6b/31c659545507c381e9cd34ec508f16c04e149e b/tests-clar/resources/submod2_target/.gitted/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
new file mode 100644
index 00000000..a26d2999
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
@@ -0,0 +1,2 @@
+xQ
+!Evoy*_@g#hOh^9wSòf1*[Ic Ԥpk Α\S߇l@.^QpF(:D5zr~ en8 \ No newline at end of file
diff --git a/tests-clar/resources/submod2_target/.gitted/objects/73/ba924a80437097795ae839e66e187c55d3babf b/tests-clar/resources/submod2_target/.gitted/objects/73/ba924a80437097795ae839e66e187c55d3babf
new file mode 100644
index 00000000..83d1ba48
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/objects/73/ba924a80437097795ae839e66e187c55d3babf
Binary files differ
diff --git a/tests-clar/resources/submod2_target/.gitted/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a b/tests-clar/resources/submod2_target/.gitted/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
new file mode 100644
index 00000000..6d27af8a
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
@@ -0,0 +1,2 @@
+x-10 Fa0p(N-ӡғq]>ks*? |m“i@mV'`).-1 x
+uxt(+ \ No newline at end of file
diff --git a/tests-clar/resources/submod2_target/.gitted/objects/78/9efbdadaa4a582778d4584385495559ea0994b b/tests-clar/resources/submod2_target/.gitted/objects/78/9efbdadaa4a582778d4584385495559ea0994b
new file mode 100644
index 00000000..17458840
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/objects/78/9efbdadaa4a582778d4584385495559ea0994b
@@ -0,0 +1,2 @@
+x 0 )?= NlOkj8&r
+qJW7B<fK8#Q1C-"e̫>'@ \ No newline at end of file
diff --git a/tests-clar/resources/submod2_target/.gitted/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e b/tests-clar/resources/submod2_target/.gitted/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
new file mode 100644
index 00000000..83cc29fb
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
Binary files differ
diff --git a/tests-clar/resources/submod2_target/.gitted/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5 b/tests-clar/resources/submod2_target/.gitted/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
new file mode 100644
index 00000000..55bda40e
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
Binary files differ
diff --git a/tests-clar/resources/submod2_target/.gitted/refs/heads/master b/tests-clar/resources/submod2_target/.gitted/refs/heads/master
new file mode 100644
index 00000000..e12c44d7
--- /dev/null
+++ b/tests-clar/resources/submod2_target/.gitted/refs/heads/master
@@ -0,0 +1 @@
+480095882d281ed676fe5b863569520e54a7d5c0
diff --git a/tests-clar/resources/submod2_target/README.txt b/tests-clar/resources/submod2_target/README.txt
new file mode 100644
index 00000000..780d7397
--- /dev/null
+++ b/tests-clar/resources/submod2_target/README.txt
@@ -0,0 +1,3 @@
+This is the target for submod2 submodule links.
+Don't add commits casually because you make break tests.
+
diff --git a/tests-clar/resources/submod2_target/file_to_modify b/tests-clar/resources/submod2_target/file_to_modify
new file mode 100644
index 00000000..789efbda
--- /dev/null
+++ b/tests-clar/resources/submod2_target/file_to_modify
@@ -0,0 +1,3 @@
+This is a file to modify in submodules
+It already has some history.
+You can add local changes as needed.
diff --git a/tests-clar/revwalk/basic.c b/tests-clar/revwalk/basic.c
index 6f3c1c06..126ca7d9 100644
--- a/tests-clar/revwalk/basic.c
+++ b/tests-clar/revwalk/basic.c
@@ -179,3 +179,11 @@ void test_revwalk_basic__push_head_hide_ref_nobase(void)
/* git log HEAD --oneline --not refs/heads/packed | wc -l => 7 */
cl_assert(i == 7);
}
+
+void test_revwalk_basic__disallow_non_commit(void)
+{
+ git_oid oid;
+
+ cl_git_pass(git_oid_fromstr(&oid, "521d87c1ec3aef9824daf6d96cc0ae3710766d91"));
+ cl_git_fail(git_revwalk_push(_walk, &oid));
+}
diff --git a/tests-clar/status/submodules.c b/tests-clar/status/submodules.c
index 9423e849..24dd660a 100644
--- a/tests-clar/status/submodules.c
+++ b/tests-clar/status/submodules.c
@@ -3,24 +3,17 @@
#include "path.h"
#include "posix.h"
#include "status_helpers.h"
+#include "../submodule/submodule_helpers.h"
static git_repository *g_repo = NULL;
void test_status_submodules__initialize(void)
{
- git_buf modpath = GIT_BUF_INIT;
-
g_repo = cl_git_sandbox_init("submodules");
cl_fixture_sandbox("testrepo.git");
- cl_git_pass(git_buf_sets(&modpath, git_repository_workdir(g_repo)));
- cl_assert(git_path_dirname_r(&modpath, modpath.ptr) >= 0);
- cl_git_pass(git_buf_joinpath(&modpath, modpath.ptr, "testrepo.git\n"));
-
- p_rename("submodules/gitmodules", "submodules/.gitmodules");
- cl_git_append2file("submodules/.gitmodules", modpath.ptr);
- git_buf_free(&modpath);
+ rewrite_gitmodules(git_repository_workdir(g_repo));
p_rename("submodules/testrepo/.gitted", "submodules/testrepo/.git");
}
@@ -28,6 +21,7 @@ void test_status_submodules__initialize(void)
void test_status_submodules__cleanup(void)
{
cl_git_sandbox_cleanup();
+ cl_fixture_cleanup("testrepo.git");
}
void test_status_submodules__api(void)
@@ -40,8 +34,8 @@ void test_status_submodules__api(void)
cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo"));
cl_assert(sm != NULL);
- cl_assert_equal_s("testrepo", sm->name);
- cl_assert_equal_s("testrepo", sm->path);
+ cl_assert_equal_s("testrepo", git_submodule_name(sm));
+ cl_assert_equal_s("testrepo", git_submodule_path(sm));
}
void test_status_submodules__0(void)
@@ -56,7 +50,7 @@ void test_status_submodules__0(void)
git_status_foreach(g_repo, cb_status__count, &counts)
);
- cl_assert(counts == 6);
+ cl_assert_equal_i(6, counts);
}
static const char *expected_files[] = {
@@ -101,12 +95,12 @@ void test_status_submodules__1(void)
git_status_foreach(g_repo, cb_status__match, &index)
);
- cl_assert(index == 6);
+ cl_assert_equal_i(6, index);
}
void test_status_submodules__single_file(void)
{
- unsigned int status;
+ unsigned int status = 0;
cl_git_pass( git_status_file(&status, g_repo, "testrepo") );
- cl_assert(status == 0);
+ cl_assert(!status);
}
diff --git a/tests-clar/submodule/lookup.c b/tests-clar/submodule/lookup.c
new file mode 100644
index 00000000..669338f1
--- /dev/null
+++ b/tests-clar/submodule/lookup.c
@@ -0,0 +1,110 @@
+#include "clar_libgit2.h"
+#include "submodule_helpers.h"
+#include "posix.h"
+
+static git_repository *g_repo = NULL;
+
+void test_submodule_lookup__initialize(void)
+{
+ g_repo = cl_git_sandbox_init("submod2");
+
+ cl_fixture_sandbox("submod2_target");
+ p_rename("submod2_target/.gitted", "submod2_target/.git");
+
+ /* must create submod2_target before rewrite so prettify will work */
+ rewrite_gitmodules(git_repository_workdir(g_repo));
+ p_rename("submod2/not_submodule/.gitted", "submod2/not_submodule/.git");
+}
+
+void test_submodule_lookup__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+ cl_fixture_cleanup("submod2_target");
+}
+
+void test_submodule_lookup__simple_lookup(void)
+{
+ git_submodule *sm;
+
+ /* lookup existing */
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
+ cl_assert(sm);
+
+ /* lookup pending change in .gitmodules that is not in HEAD */
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited"));
+ cl_assert(sm);
+
+ /* lookup git repo subdir that is not added as submodule */
+ cl_assert(git_submodule_lookup(&sm, g_repo, "not_submodule") == GIT_EEXISTS);
+
+ /* lookup existing directory that is not a submodule */
+ cl_assert(git_submodule_lookup(&sm, g_repo, "just_a_dir") == GIT_ENOTFOUND);
+
+ /* lookup existing file that is not a submodule */
+ cl_assert(git_submodule_lookup(&sm, g_repo, "just_a_file") == GIT_ENOTFOUND);
+
+ /* lookup non-existent item */
+ cl_assert(git_submodule_lookup(&sm, g_repo, "no_such_file") == GIT_ENOTFOUND);
+}
+
+void test_submodule_lookup__accessors(void)
+{
+ git_submodule *sm;
+ const char *oid = "480095882d281ed676fe5b863569520e54a7d5c0";
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
+ cl_assert(git_submodule_owner(sm) == g_repo);
+ cl_assert_equal_s("sm_unchanged", git_submodule_name(sm));
+ cl_assert(git__suffixcmp(git_submodule_path(sm), "sm_unchanged") == 0);
+ cl_assert(git__suffixcmp(git_submodule_url(sm), "/submod2_target") == 0);
+
+ cl_assert(git_oid_streq(git_submodule_index_oid(sm), oid) == 0);
+ cl_assert(git_oid_streq(git_submodule_head_oid(sm), oid) == 0);
+ cl_assert(git_oid_streq(git_submodule_wd_oid(sm), oid) == 0);
+
+ cl_assert(git_submodule_ignore(sm) == GIT_SUBMODULE_IGNORE_NONE);
+ cl_assert(git_submodule_update(sm) == GIT_SUBMODULE_UPDATE_CHECKOUT);
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
+ cl_assert_equal_s("sm_changed_head", git_submodule_name(sm));
+
+ cl_assert(git_oid_streq(git_submodule_index_oid(sm), oid) == 0);
+ cl_assert(git_oid_streq(git_submodule_head_oid(sm), oid) == 0);
+ cl_assert(git_oid_streq(git_submodule_wd_oid(sm),
+ "3d9386c507f6b093471a3e324085657a3c2b4247") == 0);
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited"));
+ cl_assert_equal_s("sm_added_and_uncommited", git_submodule_name(sm));
+
+ cl_assert(git_oid_streq(git_submodule_index_oid(sm), oid) == 0);
+ cl_assert(git_submodule_head_oid(sm) == NULL);
+ cl_assert(git_oid_streq(git_submodule_wd_oid(sm), oid) == 0);
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_missing_commits"));
+ cl_assert_equal_s("sm_missing_commits", git_submodule_name(sm));
+
+ cl_assert(git_oid_streq(git_submodule_index_oid(sm), oid) == 0);
+ cl_assert(git_oid_streq(git_submodule_head_oid(sm), oid) == 0);
+ cl_assert(git_oid_streq(git_submodule_wd_oid(sm),
+ "5e4963595a9774b90524d35a807169049de8ccad") == 0);
+}
+
+typedef struct {
+ int count;
+} sm_lookup_data;
+
+static int sm_lookup_cb(git_submodule *sm, const char *name, void *payload)
+{
+ sm_lookup_data *data = payload;
+ data->count += 1;
+ cl_assert_equal_s(git_submodule_name(sm), name);
+ return 0;
+}
+
+void test_submodule_lookup__foreach(void)
+{
+ sm_lookup_data data;
+ memset(&data, 0, sizeof(data));
+ cl_git_pass(git_submodule_foreach(g_repo, sm_lookup_cb, &data));
+ cl_assert_equal_i(7, data.count);
+}
diff --git a/tests-clar/submodule/modify.c b/tests-clar/submodule/modify.c
new file mode 100644
index 00000000..ffbbe891
--- /dev/null
+++ b/tests-clar/submodule/modify.c
@@ -0,0 +1,257 @@
+#include "clar_libgit2.h"
+#include "posix.h"
+#include "path.h"
+#include "submodule_helpers.h"
+
+static git_repository *g_repo = NULL;
+
+#define SM_LIBGIT2_URL "https://github.com/libgit2/libgit2.git"
+#define SM_LIBGIT2 "sm_libgit2"
+#define SM_LIBGIT2B "sm_libgit2b"
+
+void test_submodule_modify__initialize(void)
+{
+ g_repo = cl_git_sandbox_init("submod2");
+
+ cl_fixture_sandbox("submod2_target");
+ p_rename("submod2_target/.gitted", "submod2_target/.git");
+
+ /* must create submod2_target before rewrite so prettify will work */
+ rewrite_gitmodules(git_repository_workdir(g_repo));
+ p_rename("submod2/not_submodule/.gitted", "submod2/not_submodule/.git");
+}
+
+void test_submodule_modify__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+ cl_fixture_cleanup("submod2_target");
+}
+
+void test_submodule_modify__add(void)
+{
+ git_submodule *sm;
+ git_config *cfg;
+ const char *s;
+
+ /* re-add existing submodule */
+ cl_assert(
+ git_submodule_add_setup(NULL, g_repo, "whatever", "sm_unchanged", 1) ==
+ GIT_EEXISTS );
+
+ /* add a submodule using a gitlink */
+
+ cl_git_pass(
+ git_submodule_add_setup(&sm, g_repo, SM_LIBGIT2_URL, SM_LIBGIT2, 1)
+ );
+
+ cl_assert(git_path_isfile("submod2/" SM_LIBGIT2 "/.git"));
+
+ cl_assert(git_path_isdir("submod2/.git/modules"));
+ cl_assert(git_path_isdir("submod2/.git/modules/" SM_LIBGIT2));
+ cl_assert(git_path_isfile("submod2/.git/modules/" SM_LIBGIT2 "/HEAD"));
+
+ cl_git_pass(git_repository_config(&cfg, g_repo));
+ cl_git_pass(
+ git_config_get_string(&s, cfg, "submodule." SM_LIBGIT2 ".url"));
+ cl_assert_equal_s(s, SM_LIBGIT2_URL);
+ git_config_free(cfg);
+
+ /* add a submodule not using a gitlink */
+
+ cl_git_pass(
+ git_submodule_add_setup(&sm, g_repo, SM_LIBGIT2_URL, SM_LIBGIT2B, 0)
+ );
+
+ cl_assert(git_path_isdir("submod2/" SM_LIBGIT2B "/.git"));
+ cl_assert(git_path_isfile("submod2/" SM_LIBGIT2B "/.git/HEAD"));
+ cl_assert(!git_path_exists("submod2/.git/modules/" SM_LIBGIT2B));
+
+ cl_git_pass(git_repository_config(&cfg, g_repo));
+ cl_git_pass(
+ git_config_get_string(&s, cfg, "submodule." SM_LIBGIT2B ".url"));
+ cl_assert_equal_s(s, SM_LIBGIT2_URL);
+ git_config_free(cfg);
+}
+
+static int delete_one_config(
+ const char *var_name, const char *value, void *payload)
+{
+ git_config *cfg = payload;
+ GIT_UNUSED(value);
+ return git_config_delete(cfg, var_name);
+}
+
+static int init_one_submodule(
+ git_submodule *sm, const char *name, void *payload)
+{
+ GIT_UNUSED(name);
+ GIT_UNUSED(payload);
+ return git_submodule_init(sm, false);
+}
+
+void test_submodule_modify__init(void)
+{
+ git_config *cfg;
+ const char *str;
+
+ /* erase submodule data from .git/config */
+ cl_git_pass(git_repository_config(&cfg, g_repo));
+ cl_git_pass(
+ git_config_foreach_match(cfg, "submodule\\..*", delete_one_config, cfg));
+ git_config_free(cfg);
+
+ /* confirm no submodule data in config */
+ cl_git_pass(git_repository_config(&cfg, g_repo));
+ cl_git_fail(git_config_get_string(&str, cfg, "submodule.sm_unchanged.url"));
+ cl_git_fail(git_config_get_string(&str, cfg, "submodule.sm_changed_head.url"));
+ cl_git_fail(git_config_get_string(&str, cfg, "submodule.sm_added_and_uncommited.url"));
+ git_config_free(cfg);
+
+ /* call init and see that settings are copied */
+ cl_git_pass(git_submodule_foreach(g_repo, init_one_submodule, NULL));
+
+ git_submodule_reload_all(g_repo);
+
+ /* confirm submodule data in config */
+ cl_git_pass(git_repository_config(&cfg, g_repo));
+ cl_git_pass(git_config_get_string(&str, cfg, "submodule.sm_unchanged.url"));
+ cl_assert(git__suffixcmp(str, "/submod2_target") == 0);
+ cl_git_pass(git_config_get_string(&str, cfg, "submodule.sm_changed_head.url"));
+ cl_assert(git__suffixcmp(str, "/submod2_target") == 0);
+ cl_git_pass(git_config_get_string(&str, cfg, "submodule.sm_added_and_uncommited.url"));
+ cl_assert(git__suffixcmp(str, "/submod2_target") == 0);
+ git_config_free(cfg);
+}
+
+static int sync_one_submodule(
+ git_submodule *sm, const char *name, void *payload)
+{
+ GIT_UNUSED(name);
+ GIT_UNUSED(payload);
+ return git_submodule_sync(sm);
+}
+
+void test_submodule_modify__sync(void)
+{
+ git_submodule *sm1, *sm2, *sm3;
+ git_config *cfg;
+ const char *str;
+
+#define SM1 "sm_unchanged"
+#define SM2 "sm_changed_head"
+#define SM3 "sm_added_and_uncommited"
+
+ /* look up some submodules */
+ cl_git_pass(git_submodule_lookup(&sm1, g_repo, SM1));
+ cl_git_pass(git_submodule_lookup(&sm2, g_repo, SM2));
+ cl_git_pass(git_submodule_lookup(&sm3, g_repo, SM3));
+
+ /* At this point, the .git/config URLs for the submodules have
+ * not be rewritten with the absolute paths (although the
+ * .gitmodules have. Let's confirm that they DO NOT match
+ * yet, then we can do a sync to make them match...
+ */
+
+ /* check submodule info does not match before sync */
+ cl_git_pass(git_repository_config(&cfg, g_repo));
+ cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM1".url"));
+ cl_assert(strcmp(git_submodule_url(sm1), str) != 0);
+ cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM2".url"));
+ cl_assert(strcmp(git_submodule_url(sm2), str) != 0);
+ cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM3".url"));
+ cl_assert(strcmp(git_submodule_url(sm3), str) != 0);
+ git_config_free(cfg);
+
+ /* sync all the submodules */
+ cl_git_pass(git_submodule_foreach(g_repo, sync_one_submodule, NULL));
+
+ /* check that submodule config is updated */
+ cl_git_pass(git_repository_config(&cfg, g_repo));
+ cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM1".url"));
+ cl_assert_equal_s(git_submodule_url(sm1), str);
+ cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM2".url"));
+ cl_assert_equal_s(git_submodule_url(sm2), str);
+ cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM3".url"));
+ cl_assert_equal_s(git_submodule_url(sm3), str);
+ git_config_free(cfg);
+}
+
+void test_submodule_modify__edit_and_save(void)
+{
+ git_submodule *sm1, *sm2;
+ char *old_url;
+ git_submodule_ignore_t old_ignore;
+ git_submodule_update_t old_update;
+ git_repository *r2;
+
+ cl_git_pass(git_submodule_lookup(&sm1, g_repo, "sm_changed_head"));
+
+ old_url = git__strdup(git_submodule_url(sm1));
+
+ /* modify properties of submodule */
+ cl_git_pass(git_submodule_set_url(sm1, SM_LIBGIT2_URL));
+ old_ignore = git_submodule_set_ignore(sm1, GIT_SUBMODULE_IGNORE_UNTRACKED);
+ old_update = git_submodule_set_update(sm1, GIT_SUBMODULE_UPDATE_REBASE);
+
+ cl_assert_equal_s(SM_LIBGIT2_URL, git_submodule_url(sm1));
+ cl_assert_equal_i(
+ (int)GIT_SUBMODULE_IGNORE_UNTRACKED, (int)git_submodule_ignore(sm1));
+ cl_assert_equal_i(
+ (int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_update(sm1));
+
+ /* revert without saving (and confirm setters return old value) */
+ cl_git_pass(git_submodule_set_url(sm1, old_url));
+ cl_assert_equal_i(
+ (int)GIT_SUBMODULE_IGNORE_UNTRACKED,
+ (int)git_submodule_set_ignore(sm1, GIT_SUBMODULE_IGNORE_DEFAULT));
+ cl_assert_equal_i(
+ (int)GIT_SUBMODULE_UPDATE_REBASE,
+ (int)git_submodule_set_update(sm1, GIT_SUBMODULE_UPDATE_DEFAULT));
+
+ /* check that revert was successful */
+ cl_assert_equal_s(old_url, git_submodule_url(sm1));
+ cl_assert_equal_i((int)old_ignore, (int)git_submodule_ignore(sm1));
+ cl_assert_equal_i((int)old_update, (int)git_submodule_update(sm1));
+
+ /* modify properties of submodule (again) */
+ cl_git_pass(git_submodule_set_url(sm1, SM_LIBGIT2_URL));
+ git_submodule_set_ignore(sm1, GIT_SUBMODULE_IGNORE_UNTRACKED);
+ git_submodule_set_update(sm1, GIT_SUBMODULE_UPDATE_REBASE);
+
+ /* call save */
+ cl_git_pass(git_submodule_save(sm1));
+
+ /* attempt to "revert" values */
+ git_submodule_set_ignore(sm1, GIT_SUBMODULE_IGNORE_DEFAULT);
+ git_submodule_set_update(sm1, GIT_SUBMODULE_UPDATE_DEFAULT);
+
+ /* but ignore and update should NOT revert because the DEFAULT
+ * should now be the newly saved value...
+ */
+ cl_assert_equal_i(
+ (int)GIT_SUBMODULE_IGNORE_UNTRACKED, (int)git_submodule_ignore(sm1));
+ cl_assert_equal_i(
+ (int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_update(sm1));
+
+ /* call reload and check that the new values are loaded */
+ cl_git_pass(git_submodule_reload(sm1));
+
+ cl_assert_equal_s(SM_LIBGIT2_URL, git_submodule_url(sm1));
+ cl_assert_equal_i(
+ (int)GIT_SUBMODULE_IGNORE_UNTRACKED, (int)git_submodule_ignore(sm1));
+ cl_assert_equal_i(
+ (int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_update(sm1));
+
+ /* open a second copy of the repo and compare submodule */
+ cl_git_pass(git_repository_open(&r2, "submod2"));
+ cl_git_pass(git_submodule_lookup(&sm2, r2, "sm_changed_head"));
+
+ cl_assert_equal_s(SM_LIBGIT2_URL, git_submodule_url(sm2));
+ cl_assert_equal_i(
+ (int)GIT_SUBMODULE_IGNORE_UNTRACKED, (int)git_submodule_ignore(sm2));
+ cl_assert_equal_i(
+ (int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_update(sm2));
+
+ git_repository_free(r2);
+ git__free(old_url);
+}
diff --git a/tests-clar/submodule/status.c b/tests-clar/submodule/status.c
new file mode 100644
index 00000000..d3a39235
--- /dev/null
+++ b/tests-clar/submodule/status.c
@@ -0,0 +1,308 @@
+#include "clar_libgit2.h"
+#include "posix.h"
+#include "path.h"
+#include "submodule_helpers.h"
+#include "fileops.h"
+
+static git_repository *g_repo = NULL;
+
+void test_submodule_status__initialize(void)
+{
+ g_repo = cl_git_sandbox_init("submod2");
+
+ cl_fixture_sandbox("submod2_target");
+ p_rename("submod2_target/.gitted", "submod2_target/.git");
+
+ /* must create submod2_target before rewrite so prettify will work */
+ rewrite_gitmodules(git_repository_workdir(g_repo));
+ p_rename("submod2/not_submodule/.gitted", "submod2/not_submodule/.git");
+}
+
+void test_submodule_status__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+ cl_fixture_cleanup("submod2_target");
+}
+
+void test_submodule_status__unchanged(void)
+{
+ unsigned int status, expected;
+ git_submodule *sm;
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
+
+ expected = GIT_SUBMODULE_STATUS_IN_HEAD |
+ GIT_SUBMODULE_STATUS_IN_INDEX |
+ GIT_SUBMODULE_STATUS_IN_CONFIG |
+ GIT_SUBMODULE_STATUS_IN_WD;
+
+ cl_assert(status == expected);
+}
+
+/* 4 values of GIT_SUBMODULE_IGNORE to check */
+
+void test_submodule_status__ignore_none(void)
+{
+ unsigned int status;
+ git_submodule *sm;
+ git_buf path = GIT_BUF_INIT;
+
+ cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged"));
+ cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), GIT_DIRREMOVAL_FILES_AND_DIRS));
+
+ cl_git_fail(git_submodule_lookup(&sm, g_repo, "not_submodule"));
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_index"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED) != 0);
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_file"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED) != 0);
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_untracked_file"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNTRACKED) != 0);
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_missing_commits"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0);
+
+ /* removed sm_unchanged for deleted workdir */
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0);
+
+ /* now mkdir sm_unchanged to test uninitialized */
+ cl_git_pass(git_futils_mkdir(git_buf_cstr(&path), NULL, 0755, 0));
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
+ cl_git_pass(git_submodule_reload(sm));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0);
+
+ /* update sm_changed_head in index */
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
+ cl_git_pass(git_submodule_add_to_index(sm, true));
+ /* reload is not needed because add_to_index updates the submodule data */
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) != 0);
+
+ /* remove sm_changed_head from index */
+ {
+ git_index *index;
+ int pos;
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+ pos = git_index_find(index, "sm_changed_head");
+ cl_assert(pos >= 0);
+ cl_git_pass(git_index_remove(index, pos));
+ cl_git_pass(git_index_write(index));
+
+ git_index_free(index);
+ }
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
+ cl_git_pass(git_submodule_reload(sm));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_DELETED) != 0);
+
+ git_buf_free(&path);
+}
+
+static int set_sm_ignore(git_submodule *sm, const char *name, void *payload)
+{
+ git_submodule_ignore_t ignore = *(git_submodule_ignore_t *)payload;
+ GIT_UNUSED(name);
+ git_submodule_set_ignore(sm, ignore);
+ return 0;
+}
+
+void test_submodule_status__ignore_untracked(void)
+{
+ unsigned int status;
+ git_submodule *sm;
+ git_buf path = GIT_BUF_INIT;
+ git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_UNTRACKED;
+
+ cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged"));
+ cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), GIT_DIRREMOVAL_FILES_AND_DIRS));
+
+ cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign));
+
+ cl_git_fail(git_submodule_lookup(&sm, g_repo, "not_submodule"));
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_index"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED) != 0);
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_file"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED) != 0);
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_untracked_file"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_missing_commits"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0);
+
+ /* removed sm_unchanged for deleted workdir */
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0);
+
+ /* now mkdir sm_unchanged to test uninitialized */
+ cl_git_pass(git_futils_mkdir(git_buf_cstr(&path), NULL, 0755, 0));
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
+ cl_git_pass(git_submodule_reload(sm));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0);
+
+ /* update sm_changed_head in index */
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
+ cl_git_pass(git_submodule_add_to_index(sm, true));
+ /* reload is not needed because add_to_index updates the submodule data */
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) != 0);
+
+ git_buf_free(&path);
+}
+
+void test_submodule_status__ignore_dirty(void)
+{
+ unsigned int status;
+ git_submodule *sm;
+ git_buf path = GIT_BUF_INIT;
+ git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_DIRTY;
+
+ cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged"));
+ cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), GIT_DIRREMOVAL_FILES_AND_DIRS));
+
+ cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign));
+
+ cl_git_fail(git_submodule_lookup(&sm, g_repo, "not_submodule"));
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_index"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_file"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_untracked_file"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_missing_commits"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0);
+
+ /* removed sm_unchanged for deleted workdir */
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0);
+
+ /* now mkdir sm_unchanged to test uninitialized */
+ cl_git_pass(git_futils_mkdir(git_buf_cstr(&path), NULL, 0755, 0));
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
+ cl_git_pass(git_submodule_reload(sm));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0);
+
+ /* update sm_changed_head in index */
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
+ cl_git_pass(git_submodule_add_to_index(sm, true));
+ /* reload is not needed because add_to_index updates the submodule data */
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) != 0);
+
+ git_buf_free(&path);
+}
+
+void test_submodule_status__ignore_all(void)
+{
+ unsigned int status;
+ git_submodule *sm;
+ git_buf path = GIT_BUF_INIT;
+ git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_ALL;
+
+ cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged"));
+ cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), GIT_DIRREMOVAL_FILES_AND_DIRS));
+
+ cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign));
+
+ cl_git_fail(git_submodule_lookup(&sm, g_repo, "not_submodule"));
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_index"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_file"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_untracked_file"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_missing_commits"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
+
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
+
+ /* removed sm_unchanged for deleted workdir */
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
+
+ /* now mkdir sm_unchanged to test uninitialized */
+ cl_git_pass(git_futils_mkdir(git_buf_cstr(&path), NULL, 0755, 0));
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
+ cl_git_pass(git_submodule_reload(sm));
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
+
+ /* update sm_changed_head in index */
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_changed_head"));
+ cl_git_pass(git_submodule_add_to_index(sm, true));
+ /* reload is not needed because add_to_index updates the submodule data */
+ cl_git_pass(git_submodule_status(&status, sm));
+ cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
+
+ git_buf_free(&path);
+}
diff --git a/tests-clar/submodule/submodule_helpers.c b/tests-clar/submodule/submodule_helpers.c
new file mode 100644
index 00000000..0c3e79f7
--- /dev/null
+++ b/tests-clar/submodule/submodule_helpers.c
@@ -0,0 +1,84 @@
+#include "clar_libgit2.h"
+#include "buffer.h"
+#include "path.h"
+#include "util.h"
+#include "posix.h"
+#include "submodule_helpers.h"
+
+/* rewrite gitmodules -> .gitmodules
+ * rewrite the empty or relative urls inside each module
+ * rename the .gitted directory inside any submodule to .git
+ */
+void rewrite_gitmodules(const char *workdir)
+{
+ git_buf in_f = GIT_BUF_INIT, out_f = GIT_BUF_INIT, path = GIT_BUF_INIT;
+ FILE *in, *out;
+ char line[256];
+
+ cl_git_pass(git_buf_joinpath(&in_f, workdir, "gitmodules"));
+ cl_git_pass(git_buf_joinpath(&out_f, workdir, ".gitmodules"));
+
+ cl_assert((in = fopen(in_f.ptr, "r")) != NULL);
+ cl_assert((out = fopen(out_f.ptr, "w")) != NULL);
+
+ while (fgets(line, sizeof(line), in) != NULL) {
+ char *scan = line;
+
+ while (*scan == ' ' || *scan == '\t') scan++;
+
+ /* rename .gitted -> .git in submodule directories */
+ if (git__prefixcmp(scan, "path =") == 0) {
+ scan += strlen("path =");
+ while (*scan == ' ') scan++;
+
+ git_buf_joinpath(&path, workdir, scan);
+ git_buf_rtrim(&path);
+ git_buf_joinpath(&path, path.ptr, ".gitted");
+
+ if (!git_buf_oom(&path) && p_access(path.ptr, F_OK) == 0) {
+ git_buf_joinpath(&out_f, workdir, scan);
+ git_buf_rtrim(&out_f);
+ git_buf_joinpath(&out_f, out_f.ptr, ".git");
+
+ if (!git_buf_oom(&out_f))
+ p_rename(path.ptr, out_f.ptr);
+ }
+ }
+
+ /* copy non-"url =" lines verbatim */
+ if (git__prefixcmp(scan, "url =") != 0) {
+ fputs(line, out);
+ continue;
+ }
+
+ /* convert relative URLs in "url =" lines */
+ scan += strlen("url =");
+ while (*scan == ' ') scan++;
+
+ if (*scan == '.') {
+ git_buf_joinpath(&path, workdir, scan);
+ git_buf_rtrim(&path);
+ } else if (!*scan || *scan == '\n') {
+ git_buf_joinpath(&path, workdir, "../testrepo.git");
+ } else {
+ fputs(line, out);
+ continue;
+ }
+
+ git_path_prettify(&path, path.ptr, NULL);
+ git_buf_putc(&path, '\n');
+ cl_assert(!git_buf_oom(&path));
+
+ fwrite(line, scan - line, sizeof(char), out);
+ fputs(path.ptr, out);
+ }
+
+ fclose(in);
+ fclose(out);
+
+ cl_must_pass(p_unlink(in_f.ptr));
+
+ git_buf_free(&in_f);
+ git_buf_free(&out_f);
+ git_buf_free(&path);
+}
diff --git a/tests-clar/submodule/submodule_helpers.h b/tests-clar/submodule/submodule_helpers.h
new file mode 100644
index 00000000..6b76a832
--- /dev/null
+++ b/tests-clar/submodule/submodule_helpers.h
@@ -0,0 +1,2 @@
+extern void rewrite_gitmodules(const char *workdir);
+
diff --git a/tests-clar/valgrind-supp-mac.txt b/tests-clar/valgrind-supp-mac.txt
new file mode 100644
index 00000000..03e60dcd
--- /dev/null
+++ b/tests-clar/valgrind-supp-mac.txt
@@ -0,0 +1,82 @@
+{
+ libgit2-giterr-set-buffer
+ Memcheck:Leak
+ ...
+ fun:git__realloc
+ fun:git_buf_try_grow
+ fun:git_buf_grow
+ fun:git_buf_vprintf
+ fun:giterr_set
+}
+{
+ mac-setenv-leak-1
+ Memcheck:Leak
+ fun:malloc_zone_malloc
+ fun:__setenv
+ fun:setenv
+}
+{
+ mac-setenv-leak-2
+ Memcheck:Leak
+ fun:malloc_zone_malloc
+ fun:malloc_set_zone_name
+ ...
+ fun:init__zone0
+ fun:setenv
+}
+{
+ mac-dyld-initializer-leak
+ Memcheck:Leak
+ fun:malloc
+ ...
+ fun:dyld_register_image_state_change_handler
+ fun:_dyld_initializer
+}
+{
+ mac-tz-leak-1
+ Memcheck:Leak
+ ...
+ fun:token_table_add
+ fun:notify_register_check
+ fun:notify_register_tz
+}
+{
+ mac-tz-leak-2
+ Memcheck:Leak
+ fun:malloc
+ fun:tzload
+}
+{
+ mac-tz-leak-3
+ Memcheck:Leak
+ fun:malloc
+ fun:tzsetwall_basic
+}
+{
+ mac-tz-leak-4
+ Memcheck:Leak
+ fun:malloc
+ fun:gmtsub
+}
+{
+ mac-system-init-leak-1
+ Memcheck:Leak
+ ...
+ fun:_libxpc_initializer
+ fun:libSystem_initializer
+}
+{
+ mac-system-init-leak-2
+ Memcheck:Leak
+ ...
+ fun:__keymgr_initializer
+ fun:libSystem_initializer
+}
+{
+ mac-puts-leak
+ Memcheck:Leak
+ fun:malloc
+ fun:__smakebuf
+ ...
+ fun:puts
+}