rugged 0.17.0.b7 → 0.18.0.b1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +1 -1
- data/README.md +88 -32
- data/ext/rugged/extconf.rb +4 -2
- data/ext/rugged/rugged.c +72 -10
- data/ext/rugged/rugged.h +14 -10
- data/ext/rugged/rugged_blob.c +8 -10
- data/ext/rugged/rugged_branch.c +11 -14
- data/ext/rugged/rugged_commit.c +31 -24
- data/ext/rugged/rugged_config.c +2 -2
- data/ext/rugged/rugged_index.c +133 -198
- data/ext/rugged/rugged_note.c +372 -0
- data/ext/rugged/rugged_object.c +50 -22
- data/ext/rugged/rugged_reference.c +122 -130
- data/ext/rugged/rugged_remote.c +72 -29
- data/ext/rugged/rugged_repo.c +402 -20
- data/ext/rugged/rugged_revwalk.c +7 -3
- data/ext/rugged/rugged_settings.c +110 -0
- data/ext/rugged/rugged_signature.c +23 -7
- data/ext/rugged/rugged_tag.c +32 -16
- data/ext/rugged/rugged_tree.c +44 -15
- data/lib/rugged.rb +1 -0
- data/lib/rugged/index.rb +8 -0
- data/lib/rugged/remote.rb +13 -0
- data/lib/rugged/repository.rb +3 -3
- data/lib/rugged/version.rb +1 -1
- data/test/blob_test.rb +13 -15
- data/test/branch_test.rb +32 -67
- data/test/commit_test.rb +50 -12
- data/test/config_test.rb +12 -11
- data/test/coverage/HEAD.json +1 -1
- data/test/coverage/cover.rb +40 -21
- data/test/errors_test.rb +34 -0
- data/test/fixtures/alternate/objects/14/6ae76773c91e3b1d00cf7a338ec55ae58297e2 +0 -0
- data/test/fixtures/alternate/objects/14/9c32d47e99d0a3572ff1e70a2e0051bbf347a9 +0 -0
- data/test/fixtures/alternate/objects/14/fb3108588f9421bf764041e5e3ac305eb6277f +0 -0
- data/test/fixtures/testrepo.git/logs/refs/notes/commits +1 -0
- data/test/fixtures/testrepo.git/objects/44/1034f860c1d5d90e4188d11ae0d325176869a8 +1 -0
- data/test/fixtures/testrepo.git/objects/60/d415052a33de2150bf68757f6461df4f563ae4 +0 -0
- data/test/fixtures/testrepo.git/objects/68/8a8f4ef7496901d15322972f96e212a9e466cc +1 -0
- data/test/fixtures/testrepo.git/objects/94/eca2de348d5f672faf56b0decafa5937e3235e +0 -0
- data/test/fixtures/testrepo.git/objects/9b/7384fe1676186192842f5d3e129457b62db9e3 +0 -0
- data/test/fixtures/testrepo.git/objects/b7/4713326bc972cc15751ed504dca6f6f3b91f7a +3 -0
- data/test/fixtures/testrepo.git/refs/notes/commits +1 -0
- data/test/index_test.rb +65 -69
- data/test/lib_test.rb +76 -11
- data/test/note_test.rb +158 -0
- data/test/object_test.rb +8 -11
- data/test/reference_test.rb +77 -85
- data/test/remote_test.rb +86 -8
- data/test/repo_pack_test.rb +9 -7
- data/test/repo_reset_test.rb +80 -0
- data/test/repo_test.rb +176 -53
- data/test/tag_test.rb +44 -7
- data/test/test_helper.rb +63 -35
- data/test/tree_test.rb +34 -13
- data/test/walker_test.rb +14 -14
- data/vendor/libgit2/Makefile.embed +1 -1
- data/vendor/libgit2/deps/http-parser/http_parser.c +974 -578
- data/vendor/libgit2/deps/http-parser/http_parser.h +106 -70
- data/vendor/libgit2/deps/regex/regcomp.c +7 -6
- data/vendor/libgit2/deps/regex/regex_internal.c +1 -1
- data/vendor/libgit2/deps/regex/regex_internal.h +12 -3
- data/vendor/libgit2/deps/regex/regexec.c +5 -5
- data/vendor/libgit2/include/git2.h +5 -1
- data/vendor/libgit2/include/git2/attr.h +4 -2
- data/vendor/libgit2/include/git2/blob.h +39 -12
- data/vendor/libgit2/include/git2/branch.h +123 -35
- data/vendor/libgit2/include/git2/checkout.h +206 -48
- data/vendor/libgit2/include/git2/clone.h +72 -27
- data/vendor/libgit2/include/git2/commit.h +20 -17
- data/vendor/libgit2/include/git2/common.h +67 -1
- data/vendor/libgit2/include/git2/config.h +81 -60
- data/vendor/libgit2/include/git2/cred_helpers.h +53 -0
- data/vendor/libgit2/include/git2/diff.h +459 -150
- data/vendor/libgit2/include/git2/errors.h +9 -1
- data/vendor/libgit2/include/git2/graph.h +41 -0
- data/vendor/libgit2/include/git2/ignore.h +7 -6
- data/vendor/libgit2/include/git2/index.h +323 -97
- data/vendor/libgit2/include/git2/indexer.h +27 -59
- data/vendor/libgit2/include/git2/inttypes.h +4 -0
- data/vendor/libgit2/include/git2/merge.h +13 -3
- data/vendor/libgit2/include/git2/message.h +14 -8
- data/vendor/libgit2/include/git2/net.h +9 -7
- data/vendor/libgit2/include/git2/notes.h +88 -29
- data/vendor/libgit2/include/git2/object.h +16 -6
- data/vendor/libgit2/include/git2/odb.h +80 -17
- data/vendor/libgit2/include/git2/odb_backend.h +47 -11
- data/vendor/libgit2/include/git2/oid.h +26 -17
- data/vendor/libgit2/include/git2/pack.h +62 -8
- data/vendor/libgit2/include/git2/push.h +131 -0
- data/vendor/libgit2/include/git2/refdb.h +103 -0
- data/vendor/libgit2/include/git2/refdb_backend.h +109 -0
- data/vendor/libgit2/include/git2/reflog.h +30 -21
- data/vendor/libgit2/include/git2/refs.h +215 -193
- data/vendor/libgit2/include/git2/refspec.h +22 -2
- data/vendor/libgit2/include/git2/remote.h +158 -37
- data/vendor/libgit2/include/git2/repository.h +150 -31
- data/vendor/libgit2/include/git2/reset.h +43 -9
- data/vendor/libgit2/include/git2/revparse.h +48 -4
- data/vendor/libgit2/include/git2/revwalk.h +25 -10
- data/vendor/libgit2/include/git2/signature.h +20 -12
- data/vendor/libgit2/include/git2/stash.h +121 -0
- data/vendor/libgit2/include/git2/status.h +122 -53
- data/vendor/libgit2/include/git2/strarray.h +17 -11
- data/vendor/libgit2/include/git2/submodule.h +42 -7
- data/vendor/libgit2/include/git2/tag.h +72 -59
- data/vendor/libgit2/include/git2/threads.h +4 -2
- data/vendor/libgit2/include/git2/trace.h +68 -0
- data/vendor/libgit2/include/git2/transport.h +328 -0
- data/vendor/libgit2/include/git2/tree.h +149 -120
- data/vendor/libgit2/include/git2/types.h +13 -12
- data/vendor/libgit2/include/git2/version.h +3 -3
- data/vendor/libgit2/src/amiga/map.c +2 -2
- data/vendor/libgit2/src/attr.c +58 -48
- data/vendor/libgit2/src/attr.h +4 -18
- data/vendor/libgit2/src/attr_file.c +30 -6
- data/vendor/libgit2/src/attr_file.h +6 -8
- data/vendor/libgit2/src/attrcache.h +24 -0
- data/vendor/libgit2/src/blob.c +30 -7
- data/vendor/libgit2/src/blob.h +1 -1
- data/vendor/libgit2/src/branch.c +361 -68
- data/vendor/libgit2/src/branch.h +17 -0
- data/vendor/libgit2/src/bswap.h +1 -1
- data/vendor/libgit2/src/buf_text.c +291 -0
- data/vendor/libgit2/src/buf_text.h +122 -0
- data/vendor/libgit2/src/buffer.c +27 -101
- data/vendor/libgit2/src/buffer.h +54 -39
- data/vendor/libgit2/src/cache.c +15 -6
- data/vendor/libgit2/src/cache.h +1 -1
- data/vendor/libgit2/src/cc-compat.h +3 -1
- data/vendor/libgit2/src/checkout.c +1165 -222
- data/vendor/libgit2/src/checkout.h +24 -0
- data/vendor/libgit2/src/clone.c +171 -86
- data/vendor/libgit2/src/commit.c +44 -45
- data/vendor/libgit2/src/commit.h +3 -3
- data/vendor/libgit2/src/commit_list.c +194 -0
- data/vendor/libgit2/src/commit_list.h +49 -0
- data/vendor/libgit2/src/common.h +44 -10
- data/vendor/libgit2/src/compress.c +1 -1
- data/vendor/libgit2/src/compress.h +1 -1
- data/vendor/libgit2/src/config.c +211 -124
- data/vendor/libgit2/src/config.h +23 -4
- data/vendor/libgit2/src/config_cache.c +2 -2
- data/vendor/libgit2/src/config_file.c +129 -53
- data/vendor/libgit2/src/config_file.h +10 -8
- data/vendor/libgit2/src/crlf.c +66 -67
- data/vendor/libgit2/src/date.c +12 -12
- data/vendor/libgit2/src/delta-apply.c +14 -1
- data/vendor/libgit2/src/delta-apply.h +18 -1
- data/vendor/libgit2/src/delta.c +40 -107
- data/vendor/libgit2/src/delta.h +19 -17
- data/vendor/libgit2/src/diff.c +347 -496
- data/vendor/libgit2/src/diff.h +27 -1
- data/vendor/libgit2/src/diff_output.c +564 -249
- data/vendor/libgit2/src/diff_output.h +15 -8
- data/vendor/libgit2/src/diff_tform.c +687 -0
- data/vendor/libgit2/src/errors.c +27 -36
- data/vendor/libgit2/src/fetch.c +13 -351
- data/vendor/libgit2/src/fetch.h +13 -3
- data/vendor/libgit2/src/fetchhead.c +295 -0
- data/vendor/libgit2/src/fetchhead.h +34 -0
- data/vendor/libgit2/src/filebuf.c +42 -15
- data/vendor/libgit2/src/filebuf.h +4 -2
- data/vendor/libgit2/src/fileops.c +466 -113
- data/vendor/libgit2/src/fileops.h +154 -28
- data/vendor/libgit2/src/filter.c +3 -75
- data/vendor/libgit2/src/filter.h +1 -29
- data/vendor/libgit2/src/fnmatch.c +1 -1
- data/vendor/libgit2/src/fnmatch.h +1 -1
- data/vendor/libgit2/src/global.c +54 -10
- data/vendor/libgit2/src/global.h +10 -1
- data/vendor/libgit2/src/graph.c +178 -0
- data/vendor/libgit2/src/hash.c +25 -52
- data/vendor/libgit2/src/hash.h +21 -9
- data/vendor/libgit2/src/{sha1/sha1.c → hash/hash_generic.c} +20 -12
- data/vendor/libgit2/src/hash/hash_generic.h +24 -0
- data/vendor/libgit2/src/hash/hash_openssl.h +45 -0
- data/vendor/libgit2/src/hash/hash_win32.c +291 -0
- data/vendor/libgit2/src/hash/hash_win32.h +140 -0
- data/vendor/libgit2/src/hashsig.c +368 -0
- data/vendor/libgit2/src/hashsig.h +72 -0
- data/vendor/libgit2/src/ignore.c +22 -15
- data/vendor/libgit2/src/ignore.h +6 -1
- data/vendor/libgit2/src/index.c +770 -171
- data/vendor/libgit2/src/index.h +13 -5
- data/vendor/libgit2/src/indexer.c +286 -431
- data/vendor/libgit2/src/iterator.c +854 -466
- data/vendor/libgit2/src/iterator.h +134 -109
- data/vendor/libgit2/src/map.h +1 -1
- data/vendor/libgit2/src/merge.c +296 -0
- data/vendor/libgit2/src/merge.h +22 -0
- data/vendor/libgit2/src/message.c +1 -1
- data/vendor/libgit2/src/message.h +1 -1
- data/vendor/libgit2/src/mwindow.c +35 -30
- data/vendor/libgit2/src/mwindow.h +2 -2
- data/vendor/libgit2/src/netops.c +162 -98
- data/vendor/libgit2/src/netops.h +50 -15
- data/vendor/libgit2/src/notes.c +109 -58
- data/vendor/libgit2/src/notes.h +2 -1
- data/vendor/libgit2/src/object.c +46 -57
- data/vendor/libgit2/src/object.h +1 -8
- data/vendor/libgit2/src/odb.c +151 -40
- data/vendor/libgit2/src/odb.h +5 -1
- data/vendor/libgit2/src/odb_loose.c +4 -5
- data/vendor/libgit2/src/odb_pack.c +122 -80
- data/vendor/libgit2/src/offmap.h +65 -0
- data/vendor/libgit2/src/oid.c +12 -4
- data/vendor/libgit2/src/oidmap.h +1 -1
- data/vendor/libgit2/src/pack-objects.c +88 -61
- data/vendor/libgit2/src/pack-objects.h +8 -8
- data/vendor/libgit2/src/pack.c +293 -28
- data/vendor/libgit2/src/pack.h +49 -4
- data/vendor/libgit2/src/path.c +103 -14
- data/vendor/libgit2/src/path.h +23 -7
- data/vendor/libgit2/src/pathspec.c +168 -0
- data/vendor/libgit2/src/pathspec.h +40 -0
- data/vendor/libgit2/src/pool.c +29 -4
- data/vendor/libgit2/src/pool.h +8 -1
- data/vendor/libgit2/src/posix.c +26 -27
- data/vendor/libgit2/src/posix.h +2 -3
- data/vendor/libgit2/src/pqueue.c +23 -1
- data/vendor/libgit2/src/pqueue.h +23 -1
- data/vendor/libgit2/src/push.c +653 -0
- data/vendor/libgit2/src/push.h +51 -0
- data/vendor/libgit2/src/refdb.c +185 -0
- data/vendor/libgit2/src/refdb.h +46 -0
- data/vendor/libgit2/src/refdb_fs.c +1024 -0
- data/vendor/libgit2/src/refdb_fs.h +15 -0
- data/vendor/libgit2/src/reflog.c +77 -45
- data/vendor/libgit2/src/reflog.h +1 -3
- data/vendor/libgit2/src/refs.c +366 -1326
- data/vendor/libgit2/src/refs.h +22 -13
- data/vendor/libgit2/src/refspec.c +46 -7
- data/vendor/libgit2/src/refspec.h +11 -1
- data/vendor/libgit2/src/remote.c +758 -120
- data/vendor/libgit2/src/remote.h +10 -5
- data/vendor/libgit2/src/repo_template.h +6 -6
- data/vendor/libgit2/src/repository.c +315 -96
- data/vendor/libgit2/src/repository.h +5 -3
- data/vendor/libgit2/src/reset.c +99 -81
- data/vendor/libgit2/src/revparse.c +157 -84
- data/vendor/libgit2/src/revwalk.c +68 -470
- data/vendor/libgit2/src/revwalk.h +44 -0
- data/vendor/libgit2/src/sha1_lookup.c +1 -1
- data/vendor/libgit2/src/sha1_lookup.h +1 -1
- data/vendor/libgit2/src/signature.c +68 -200
- data/vendor/libgit2/src/signature.h +1 -1
- data/vendor/libgit2/src/stash.c +663 -0
- data/vendor/libgit2/src/status.c +101 -79
- data/vendor/libgit2/src/strmap.h +1 -1
- data/vendor/libgit2/src/submodule.c +67 -51
- data/vendor/libgit2/src/submodule.h +1 -1
- data/vendor/libgit2/src/tag.c +35 -29
- data/vendor/libgit2/src/tag.h +1 -1
- data/vendor/libgit2/src/thread-utils.c +1 -1
- data/vendor/libgit2/src/thread-utils.h +2 -2
- data/vendor/libgit2/src/trace.c +39 -0
- data/vendor/libgit2/src/trace.h +56 -0
- data/vendor/libgit2/src/transport.c +81 -34
- data/vendor/libgit2/src/transports/cred.c +60 -0
- data/vendor/libgit2/src/transports/cred_helpers.c +49 -0
- data/vendor/libgit2/src/transports/git.c +234 -127
- data/vendor/libgit2/src/transports/http.c +761 -433
- data/vendor/libgit2/src/transports/local.c +460 -64
- data/vendor/libgit2/src/transports/smart.c +345 -0
- data/vendor/libgit2/src/transports/smart.h +179 -0
- data/vendor/libgit2/src/{pkt.c → transports/smart_pkt.c} +131 -12
- data/vendor/libgit2/src/transports/smart_protocol.c +856 -0
- data/vendor/libgit2/src/transports/winhttp.c +1136 -0
- data/vendor/libgit2/src/tree-cache.c +2 -2
- data/vendor/libgit2/src/tree-cache.h +1 -1
- data/vendor/libgit2/src/tree.c +239 -166
- data/vendor/libgit2/src/tree.h +11 -2
- data/vendor/libgit2/src/tsort.c +39 -23
- data/vendor/libgit2/src/unix/map.c +1 -1
- data/vendor/libgit2/src/unix/posix.h +12 -2
- data/vendor/libgit2/src/unix/realpath.c +30 -0
- data/vendor/libgit2/src/util.c +250 -13
- data/vendor/libgit2/src/util.h +71 -14
- data/vendor/libgit2/src/vector.c +123 -60
- data/vendor/libgit2/src/vector.h +24 -22
- data/vendor/libgit2/src/win32/dir.c +1 -1
- data/vendor/libgit2/src/win32/dir.h +1 -1
- data/vendor/libgit2/src/win32/error.c +77 -0
- data/vendor/libgit2/src/win32/error.h +13 -0
- data/vendor/libgit2/src/win32/findfile.c +143 -54
- data/vendor/libgit2/src/win32/findfile.h +10 -6
- data/vendor/libgit2/src/win32/map.c +1 -1
- data/vendor/libgit2/src/win32/mingw-compat.h +1 -1
- data/vendor/libgit2/src/win32/msvc-compat.h +10 -1
- data/vendor/libgit2/src/win32/posix.h +10 -1
- data/vendor/libgit2/src/win32/posix_w32.c +132 -63
- data/vendor/libgit2/src/win32/precompiled.c +1 -1
- data/vendor/libgit2/src/win32/pthread.c +1 -1
- data/vendor/libgit2/src/win32/pthread.h +1 -1
- data/vendor/libgit2/src/win32/utf-conv.c +5 -5
- data/vendor/libgit2/src/win32/utf-conv.h +3 -3
- data/vendor/libgit2/src/win32/version.h +20 -0
- metadata +308 -252
- data/test/fixtures/testrepo.git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 +0 -0
- data/test/fixtures/testrepo.git/objects/7f/043268ea43ce18e3540acaabf9e090c91965b0 +0 -0
- data/test/fixtures/testrepo.git/objects/a3/e05719b428a2d0ed7a55c4ce53dcc5768c6d5e +0 -0
- data/test/index_test.rb~ +0 -218
- data/vendor/libgit2/src/pkt.h +0 -91
- data/vendor/libgit2/src/ppc/sha1.c +0 -70
- data/vendor/libgit2/src/ppc/sha1.h +0 -26
- data/vendor/libgit2/src/protocol.c +0 -110
- data/vendor/libgit2/src/protocol.h +0 -21
- data/vendor/libgit2/src/sha1.h +0 -33
- data/vendor/libgit2/src/transport.h +0 -148
data/vendor/libgit2/src/buffer.h
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright (C)
|
|
2
|
+
* Copyright (C) the libgit2 contributors. All rights reserved.
|
|
3
3
|
*
|
|
4
4
|
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
|
5
5
|
* a Linking Exception. For full terms see the included COPYING file.
|
|
@@ -27,30 +27,35 @@ extern char git_buf__oom[];
|
|
|
27
27
|
* For the cases where GIT_BUF_INIT cannot be used to do static
|
|
28
28
|
* initialization.
|
|
29
29
|
*/
|
|
30
|
-
void git_buf_init(git_buf *buf, size_t initial_size);
|
|
30
|
+
extern void git_buf_init(git_buf *buf, size_t initial_size);
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* Attempt to grow the buffer to hold at least `target_size` bytes.
|
|
34
34
|
*
|
|
35
|
-
* If the allocation fails, this will return an error
|
|
36
|
-
* will
|
|
37
|
-
*
|
|
38
|
-
*
|
|
35
|
+
* If the allocation fails, this will return an error. If mark_oom is true,
|
|
36
|
+
* this will mark the buffer as invalid for future operations; if false,
|
|
37
|
+
* existing buffer content will be preserved, but calling code must handle
|
|
38
|
+
* that buffer was not expanded.
|
|
39
39
|
*/
|
|
40
|
-
int
|
|
40
|
+
extern int git_buf_try_grow(git_buf *buf, size_t target_size, bool mark_oom);
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
43
|
+
* Grow the buffer to hold at least `target_size` bytes.
|
|
44
|
+
*
|
|
45
|
+
* If the allocation fails, this will return an error and the buffer will be
|
|
46
|
+
* marked as invalid for future operations, invaliding contents.
|
|
44
47
|
*
|
|
45
|
-
*
|
|
46
|
-
* fails, the git_buf will still be left in a valid state.
|
|
48
|
+
* @return 0 on success or -1 on failure
|
|
47
49
|
*/
|
|
48
|
-
int
|
|
50
|
+
GIT_INLINE(int) git_buf_grow(git_buf *buf, size_t target_size)
|
|
51
|
+
{
|
|
52
|
+
return git_buf_try_grow(buf, target_size, true);
|
|
53
|
+
}
|
|
49
54
|
|
|
50
|
-
void git_buf_free(git_buf *buf);
|
|
51
|
-
void git_buf_swap(git_buf *buf_a, git_buf *buf_b);
|
|
52
|
-
char *git_buf_detach(git_buf *buf);
|
|
53
|
-
void git_buf_attach(git_buf *buf, char *ptr, size_t asize);
|
|
55
|
+
extern void git_buf_free(git_buf *buf);
|
|
56
|
+
extern void git_buf_swap(git_buf *buf_a, git_buf *buf_b);
|
|
57
|
+
extern char *git_buf_detach(git_buf *buf);
|
|
58
|
+
extern void git_buf_attach(git_buf *buf, char *ptr, size_t asize);
|
|
54
59
|
|
|
55
60
|
/**
|
|
56
61
|
* Test if there have been any reallocation failures with this git_buf.
|
|
@@ -91,18 +96,6 @@ void git_buf_rtruncate_at_char(git_buf *path, char separator);
|
|
|
91
96
|
int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...);
|
|
92
97
|
int git_buf_join(git_buf *buf, char separator, const char *str_a, const char *str_b);
|
|
93
98
|
|
|
94
|
-
/**
|
|
95
|
-
* Copy string into buf prefixing every character that is contained in the
|
|
96
|
-
* esc_chars string with the esc_with string.
|
|
97
|
-
*/
|
|
98
|
-
int git_buf_puts_escaped(
|
|
99
|
-
git_buf *buf, const char *string, const char *esc_chars, const char *esc_with);
|
|
100
|
-
|
|
101
|
-
GIT_INLINE(int) git_buf_puts_escape_regex(git_buf *buf, const char *string)
|
|
102
|
-
{
|
|
103
|
-
return git_buf_puts_escaped(buf, string, "^.[]$()|*+?{}\\", "\\");
|
|
104
|
-
}
|
|
105
|
-
|
|
106
99
|
/**
|
|
107
100
|
* Join two strings as paths, inserting a slash between as needed.
|
|
108
101
|
* @return 0 on success, -1 on failure
|
|
@@ -126,7 +119,7 @@ void git_buf_copy_cstr(char *data, size_t datasize, const git_buf *buf);
|
|
|
126
119
|
|
|
127
120
|
#define git_buf_PUTS(buf, str) git_buf_put(buf, str, sizeof(str) - 1)
|
|
128
121
|
|
|
129
|
-
GIT_INLINE(ssize_t) git_buf_rfind_next(git_buf *buf, char ch)
|
|
122
|
+
GIT_INLINE(ssize_t) git_buf_rfind_next(const git_buf *buf, char ch)
|
|
130
123
|
{
|
|
131
124
|
ssize_t idx = (ssize_t)buf->size - 1;
|
|
132
125
|
while (idx >= 0 && buf->ptr[idx] == ch) idx--;
|
|
@@ -134,28 +127,50 @@ GIT_INLINE(ssize_t) git_buf_rfind_next(git_buf *buf, char ch)
|
|
|
134
127
|
return idx;
|
|
135
128
|
}
|
|
136
129
|
|
|
137
|
-
GIT_INLINE(ssize_t) git_buf_rfind(git_buf *buf, char ch)
|
|
130
|
+
GIT_INLINE(ssize_t) git_buf_rfind(const git_buf *buf, char ch)
|
|
138
131
|
{
|
|
139
132
|
ssize_t idx = (ssize_t)buf->size - 1;
|
|
140
133
|
while (idx >= 0 && buf->ptr[idx] != ch) idx--;
|
|
141
134
|
return idx;
|
|
142
135
|
}
|
|
143
136
|
|
|
137
|
+
GIT_INLINE(ssize_t) git_buf_find(const git_buf *buf, char ch)
|
|
138
|
+
{
|
|
139
|
+
void *found = memchr(buf->ptr, ch, buf->size);
|
|
140
|
+
return found ? (ssize_t)((const char *)found - buf->ptr) : -1;
|
|
141
|
+
}
|
|
142
|
+
|
|
144
143
|
/* Remove whitespace from the end of the buffer */
|
|
145
144
|
void git_buf_rtrim(git_buf *buf);
|
|
146
145
|
|
|
147
146
|
int git_buf_cmp(const git_buf *a, const git_buf *b);
|
|
148
147
|
|
|
149
|
-
/* Fill buf with the common prefix of a array of strings */
|
|
150
|
-
int git_buf_common_prefix(git_buf *buf, const git_strarray *strings);
|
|
151
|
-
|
|
152
|
-
/* Check if buffer looks like it contains binary data */
|
|
153
|
-
bool git_buf_is_binary(const git_buf *buf);
|
|
154
|
-
|
|
155
|
-
/* Unescape all characters in a buffer */
|
|
156
|
-
void git_buf_unescape(git_buf *buf);
|
|
157
|
-
|
|
158
148
|
/* Write data as base64 encoded in buffer */
|
|
159
149
|
int git_buf_put_base64(git_buf *buf, const char *data, size_t len);
|
|
160
150
|
|
|
151
|
+
/*
|
|
152
|
+
* Insert, remove or replace a portion of the buffer.
|
|
153
|
+
*
|
|
154
|
+
* @param buf The buffer to work with
|
|
155
|
+
*
|
|
156
|
+
* @param where The location in the buffer where the transformation
|
|
157
|
+
* should be applied.
|
|
158
|
+
*
|
|
159
|
+
* @param nb_to_remove The number of chars to be removed. 0 to not
|
|
160
|
+
* remove any character in the buffer.
|
|
161
|
+
*
|
|
162
|
+
* @param data A pointer to the data which should be inserted.
|
|
163
|
+
*
|
|
164
|
+
* @param nb_to_insert The number of chars to be inserted. 0 to not
|
|
165
|
+
* insert any character from the buffer.
|
|
166
|
+
*
|
|
167
|
+
* @return 0 or an error code.
|
|
168
|
+
*/
|
|
169
|
+
int git_buf_splice(
|
|
170
|
+
git_buf *buf,
|
|
171
|
+
size_t where,
|
|
172
|
+
size_t nb_to_remove,
|
|
173
|
+
const char *data,
|
|
174
|
+
size_t nb_to_insert);
|
|
175
|
+
|
|
161
176
|
#endif
|
data/vendor/libgit2/src/cache.c
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright (C)
|
|
2
|
+
* Copyright (C) the libgit2 contributors. All rights reserved.
|
|
3
3
|
*
|
|
4
4
|
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
|
5
5
|
* a Linking Exception. For full terms see the included COPYING file.
|
|
@@ -41,6 +41,7 @@ void git_cache_free(git_cache *cache)
|
|
|
41
41
|
git_cached_obj_decref(cache->nodes[i], cache->free_obj);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
git_mutex_free(&cache->lock);
|
|
44
45
|
git__free(cache->nodes);
|
|
45
46
|
}
|
|
46
47
|
|
|
@@ -51,7 +52,11 @@ void *git_cache_get(git_cache *cache, const git_oid *oid)
|
|
|
51
52
|
|
|
52
53
|
memcpy(&hash, oid->id, sizeof(hash));
|
|
53
54
|
|
|
54
|
-
git_mutex_lock(&cache->lock)
|
|
55
|
+
if (git_mutex_lock(&cache->lock)) {
|
|
56
|
+
giterr_set(GITERR_THREAD, "unable to lock cache mutex");
|
|
57
|
+
return NULL;
|
|
58
|
+
}
|
|
59
|
+
|
|
55
60
|
{
|
|
56
61
|
node = cache->nodes[hash & cache->size_mask];
|
|
57
62
|
|
|
@@ -72,14 +77,18 @@ void *git_cache_try_store(git_cache *cache, void *_entry)
|
|
|
72
77
|
|
|
73
78
|
memcpy(&hash, &entry->oid, sizeof(uint32_t));
|
|
74
79
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
80
|
+
if (git_mutex_lock(&cache->lock)) {
|
|
81
|
+
giterr_set(GITERR_THREAD, "unable to lock cache mutex");
|
|
82
|
+
return NULL;
|
|
83
|
+
}
|
|
78
84
|
|
|
79
|
-
git_mutex_lock(&cache->lock);
|
|
80
85
|
{
|
|
81
86
|
git_cached_obj *node = cache->nodes[hash & cache->size_mask];
|
|
82
87
|
|
|
88
|
+
/* increase the refcount on this object, because
|
|
89
|
+
* the cache now owns it */
|
|
90
|
+
git_cached_obj_incref(entry);
|
|
91
|
+
|
|
83
92
|
if (node == NULL) {
|
|
84
93
|
cache->nodes[hash & cache->size_mask] = entry;
|
|
85
94
|
} else if (git_oid_cmp(&node->oid, &entry->oid) == 0) {
|
data/vendor/libgit2/src/cache.h
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright (C)
|
|
2
|
+
* Copyright (C) the libgit2 contributors. All rights reserved.
|
|
3
3
|
*
|
|
4
4
|
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
|
5
5
|
* a Linking Exception. For full terms see the included COPYING file.
|
|
@@ -38,8 +38,10 @@
|
|
|
38
38
|
/* Define the printf format specifer to use for size_t output */
|
|
39
39
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
|
40
40
|
# define PRIuZ "Iu"
|
|
41
|
+
# define PRIxZ "Ix"
|
|
41
42
|
#else
|
|
42
43
|
# define PRIuZ "zu"
|
|
44
|
+
# define PRIxZ "zx"
|
|
43
45
|
#endif
|
|
44
46
|
|
|
45
47
|
/* Micosoft Visual C/C++ */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright (C)
|
|
2
|
+
* Copyright (C) the libgit2 contributors. All rights reserved.
|
|
3
3
|
*
|
|
4
4
|
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
|
5
5
|
* a Linking Exception. For full terms see the included COPYING file.
|
|
@@ -7,55 +7,686 @@
|
|
|
7
7
|
|
|
8
8
|
#include <assert.h>
|
|
9
9
|
|
|
10
|
-
#include "
|
|
10
|
+
#include "checkout.h"
|
|
11
|
+
|
|
11
12
|
#include "git2/repository.h"
|
|
12
13
|
#include "git2/refs.h"
|
|
13
14
|
#include "git2/tree.h"
|
|
14
15
|
#include "git2/blob.h"
|
|
15
16
|
#include "git2/config.h"
|
|
16
17
|
#include "git2/diff.h"
|
|
18
|
+
#include "git2/submodule.h"
|
|
17
19
|
|
|
18
|
-
#include "common.h"
|
|
19
20
|
#include "refs.h"
|
|
20
|
-
#include "buffer.h"
|
|
21
21
|
#include "repository.h"
|
|
22
22
|
#include "filter.h"
|
|
23
23
|
#include "blob.h"
|
|
24
|
+
#include "diff.h"
|
|
25
|
+
#include "pathspec.h"
|
|
26
|
+
#include "buf_text.h"
|
|
27
|
+
|
|
28
|
+
/* See docs/checkout-internals.md for more information */
|
|
29
|
+
|
|
30
|
+
enum {
|
|
31
|
+
CHECKOUT_ACTION__NONE = 0,
|
|
32
|
+
CHECKOUT_ACTION__REMOVE = 1,
|
|
33
|
+
CHECKOUT_ACTION__UPDATE_BLOB = 2,
|
|
34
|
+
CHECKOUT_ACTION__UPDATE_SUBMODULE = 4,
|
|
35
|
+
CHECKOUT_ACTION__CONFLICT = 8,
|
|
36
|
+
CHECKOUT_ACTION__MAX = 8,
|
|
37
|
+
CHECKOUT_ACTION__DEFER_REMOVE = 16,
|
|
38
|
+
CHECKOUT_ACTION__REMOVE_AND_UPDATE =
|
|
39
|
+
(CHECKOUT_ACTION__UPDATE_BLOB | CHECKOUT_ACTION__REMOVE),
|
|
40
|
+
};
|
|
24
41
|
|
|
25
|
-
struct
|
|
26
|
-
|
|
27
|
-
|
|
42
|
+
typedef struct {
|
|
43
|
+
git_repository *repo;
|
|
44
|
+
git_diff_list *diff;
|
|
45
|
+
git_checkout_opts opts;
|
|
46
|
+
bool opts_free_baseline;
|
|
47
|
+
char *pfx;
|
|
48
|
+
git_index *index;
|
|
49
|
+
git_pool pool;
|
|
50
|
+
git_vector removes;
|
|
51
|
+
git_buf path;
|
|
28
52
|
size_t workdir_len;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
53
|
+
unsigned int strategy;
|
|
54
|
+
int can_symlink;
|
|
55
|
+
bool reload_submodules;
|
|
56
|
+
size_t total_steps;
|
|
57
|
+
size_t completed_steps;
|
|
58
|
+
} checkout_data;
|
|
59
|
+
|
|
60
|
+
static int checkout_notify(
|
|
61
|
+
checkout_data *data,
|
|
62
|
+
git_checkout_notify_t why,
|
|
63
|
+
const git_diff_delta *delta,
|
|
64
|
+
const git_index_entry *wditem)
|
|
65
|
+
{
|
|
66
|
+
git_diff_file wdfile;
|
|
67
|
+
const git_diff_file *baseline = NULL, *target = NULL, *workdir = NULL;
|
|
68
|
+
const char *path = NULL;
|
|
69
|
+
|
|
70
|
+
if (!data->opts.notify_cb)
|
|
71
|
+
return 0;
|
|
72
|
+
|
|
73
|
+
if ((why & data->opts.notify_flags) == 0)
|
|
74
|
+
return 0;
|
|
75
|
+
|
|
76
|
+
if (wditem) {
|
|
77
|
+
memset(&wdfile, 0, sizeof(wdfile));
|
|
78
|
+
|
|
79
|
+
git_oid_cpy(&wdfile.oid, &wditem->oid);
|
|
80
|
+
wdfile.path = wditem->path;
|
|
81
|
+
wdfile.size = wditem->file_size;
|
|
82
|
+
wdfile.flags = GIT_DIFF_FLAG_VALID_OID;
|
|
83
|
+
wdfile.mode = wditem->mode;
|
|
84
|
+
|
|
85
|
+
workdir = &wdfile;
|
|
86
|
+
|
|
87
|
+
path = wditem->path;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (delta) {
|
|
91
|
+
switch (delta->status) {
|
|
92
|
+
case GIT_DELTA_UNMODIFIED:
|
|
93
|
+
case GIT_DELTA_MODIFIED:
|
|
94
|
+
case GIT_DELTA_TYPECHANGE:
|
|
95
|
+
default:
|
|
96
|
+
baseline = &delta->old_file;
|
|
97
|
+
target = &delta->new_file;
|
|
98
|
+
break;
|
|
99
|
+
case GIT_DELTA_ADDED:
|
|
100
|
+
case GIT_DELTA_IGNORED:
|
|
101
|
+
case GIT_DELTA_UNTRACKED:
|
|
102
|
+
target = &delta->new_file;
|
|
103
|
+
break;
|
|
104
|
+
case GIT_DELTA_DELETED:
|
|
105
|
+
baseline = &delta->old_file;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
path = delta->old_file.path;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return data->opts.notify_cb(
|
|
113
|
+
why, path, baseline, target, workdir, data->opts.notify_payload);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
static bool checkout_is_workdir_modified(
|
|
117
|
+
checkout_data *data,
|
|
118
|
+
const git_diff_file *baseitem,
|
|
119
|
+
const git_index_entry *wditem)
|
|
120
|
+
{
|
|
121
|
+
git_oid oid;
|
|
122
|
+
const git_index_entry *ie;
|
|
123
|
+
|
|
124
|
+
/* handle "modified" submodule */
|
|
125
|
+
if (wditem->mode == GIT_FILEMODE_COMMIT) {
|
|
126
|
+
git_submodule *sm;
|
|
127
|
+
unsigned int sm_status = 0;
|
|
128
|
+
const git_oid *sm_oid = NULL;
|
|
129
|
+
|
|
130
|
+
if (git_submodule_lookup(&sm, data->repo, wditem->path) < 0 ||
|
|
131
|
+
git_submodule_status(&sm_status, sm) < 0)
|
|
132
|
+
return true;
|
|
133
|
+
|
|
134
|
+
if (GIT_SUBMODULE_STATUS_IS_WD_DIRTY(sm_status))
|
|
135
|
+
return true;
|
|
136
|
+
|
|
137
|
+
sm_oid = git_submodule_wd_id(sm);
|
|
138
|
+
if (!sm_oid)
|
|
139
|
+
return false;
|
|
140
|
+
|
|
141
|
+
return (git_oid_cmp(&baseitem->oid, sm_oid) != 0);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* Look at the cache to decide if the workdir is modified. If not,
|
|
145
|
+
* we can simply compare the oid in the cache to the baseitem instead
|
|
146
|
+
* of hashing the file.
|
|
147
|
+
*/
|
|
148
|
+
if ((ie = git_index_get_bypath(data->index, wditem->path, 0)) != NULL) {
|
|
149
|
+
if (wditem->mtime.seconds == ie->mtime.seconds &&
|
|
150
|
+
wditem->mtime.nanoseconds == ie->mtime.nanoseconds &&
|
|
151
|
+
wditem->file_size == ie->file_size)
|
|
152
|
+
return (git_oid_cmp(&baseitem->oid, &ie->oid) != 0);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* depending on where base is coming from, we may or may not know
|
|
156
|
+
* the actual size of the data, so we can't rely on this shortcut.
|
|
157
|
+
*/
|
|
158
|
+
if (baseitem->size && wditem->file_size != baseitem->size)
|
|
159
|
+
return true;
|
|
160
|
+
|
|
161
|
+
if (git_diff__oid_for_file(
|
|
162
|
+
data->repo, wditem->path, wditem->mode,
|
|
163
|
+
wditem->file_size, &oid) < 0)
|
|
164
|
+
return false;
|
|
165
|
+
|
|
166
|
+
return (git_oid_cmp(&baseitem->oid, &oid) != 0);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
#define CHECKOUT_ACTION_IF(FLAG,YES,NO) \
|
|
170
|
+
((data->strategy & GIT_CHECKOUT_##FLAG) ? CHECKOUT_ACTION__##YES : CHECKOUT_ACTION__##NO)
|
|
171
|
+
|
|
172
|
+
static int checkout_action_common(
|
|
173
|
+
checkout_data *data,
|
|
174
|
+
int action,
|
|
175
|
+
const git_diff_delta *delta,
|
|
176
|
+
const git_index_entry *wd)
|
|
177
|
+
{
|
|
178
|
+
git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE;
|
|
179
|
+
|
|
180
|
+
if (action <= 0)
|
|
181
|
+
return action;
|
|
182
|
+
|
|
183
|
+
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0)
|
|
184
|
+
action = (action & ~CHECKOUT_ACTION__REMOVE);
|
|
185
|
+
|
|
186
|
+
if ((action & CHECKOUT_ACTION__UPDATE_BLOB) != 0) {
|
|
187
|
+
if (S_ISGITLINK(delta->new_file.mode))
|
|
188
|
+
action = (action & ~CHECKOUT_ACTION__UPDATE_BLOB) |
|
|
189
|
+
CHECKOUT_ACTION__UPDATE_SUBMODULE;
|
|
190
|
+
|
|
191
|
+
notify = GIT_CHECKOUT_NOTIFY_UPDATED;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if ((action & CHECKOUT_ACTION__CONFLICT) != 0)
|
|
195
|
+
notify = GIT_CHECKOUT_NOTIFY_CONFLICT;
|
|
196
|
+
|
|
197
|
+
if (notify != GIT_CHECKOUT_NOTIFY_NONE &&
|
|
198
|
+
checkout_notify(data, notify, delta, wd) != 0)
|
|
199
|
+
return GIT_EUSER;
|
|
200
|
+
|
|
201
|
+
return action;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
static int checkout_action_no_wd(
|
|
205
|
+
checkout_data *data,
|
|
206
|
+
const git_diff_delta *delta)
|
|
207
|
+
{
|
|
208
|
+
int action = CHECKOUT_ACTION__NONE;
|
|
209
|
+
|
|
210
|
+
switch (delta->status) {
|
|
211
|
+
case GIT_DELTA_UNMODIFIED: /* case 12 */
|
|
212
|
+
if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL))
|
|
213
|
+
return GIT_EUSER;
|
|
214
|
+
action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, NONE);
|
|
215
|
+
break;
|
|
216
|
+
case GIT_DELTA_ADDED: /* case 2 or 28 (and 5 but not really) */
|
|
217
|
+
case GIT_DELTA_MODIFIED: /* case 13 (and 35 but not really) */
|
|
218
|
+
action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
|
|
219
|
+
break;
|
|
220
|
+
case GIT_DELTA_TYPECHANGE: /* case 21 (B->T) and 28 (T->B)*/
|
|
221
|
+
if (delta->new_file.mode == GIT_FILEMODE_TREE)
|
|
222
|
+
action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
|
|
223
|
+
break;
|
|
224
|
+
case GIT_DELTA_DELETED: /* case 8 or 25 */
|
|
225
|
+
default: /* impossible */
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return checkout_action_common(data, action, delta, NULL);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
static int checkout_action_wd_only(
|
|
233
|
+
checkout_data *data,
|
|
234
|
+
git_iterator *workdir,
|
|
235
|
+
const git_index_entry *wd,
|
|
236
|
+
git_vector *pathspec)
|
|
237
|
+
{
|
|
238
|
+
bool remove = false;
|
|
239
|
+
git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE;
|
|
240
|
+
|
|
241
|
+
if (!git_pathspec_match_path(
|
|
242
|
+
pathspec, wd->path,
|
|
243
|
+
(data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
|
|
244
|
+
git_iterator_ignore_case(workdir), NULL))
|
|
245
|
+
return 0;
|
|
246
|
+
|
|
247
|
+
/* check if item is tracked in the index but not in the checkout diff */
|
|
248
|
+
if (data->index != NULL) {
|
|
249
|
+
if (wd->mode != GIT_FILEMODE_TREE) {
|
|
250
|
+
int error;
|
|
251
|
+
|
|
252
|
+
if ((error = git_index_find(NULL, data->index, wd->path)) == 0) {
|
|
253
|
+
notify = GIT_CHECKOUT_NOTIFY_DIRTY;
|
|
254
|
+
remove = ((data->strategy & GIT_CHECKOUT_FORCE) != 0);
|
|
255
|
+
} else if (error != GIT_ENOTFOUND)
|
|
256
|
+
return error;
|
|
257
|
+
} else {
|
|
258
|
+
/* for tree entries, we have to see if there are any index
|
|
259
|
+
* entries that are contained inside that tree
|
|
260
|
+
*/
|
|
261
|
+
size_t pos = git_index__prefix_position(data->index, wd->path);
|
|
262
|
+
const git_index_entry *e = git_index_get_byindex(data->index, pos);
|
|
263
|
+
|
|
264
|
+
if (e != NULL && data->diff->pfxcomp(e->path, wd->path) == 0) {
|
|
265
|
+
notify = GIT_CHECKOUT_NOTIFY_DIRTY;
|
|
266
|
+
remove = ((data->strategy & GIT_CHECKOUT_FORCE) != 0);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (notify != GIT_CHECKOUT_NOTIFY_NONE)
|
|
272
|
+
/* found in index */;
|
|
273
|
+
else if (git_iterator_current_is_ignored(workdir)) {
|
|
274
|
+
notify = GIT_CHECKOUT_NOTIFY_IGNORED;
|
|
275
|
+
remove = ((data->strategy & GIT_CHECKOUT_REMOVE_IGNORED) != 0);
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
notify = GIT_CHECKOUT_NOTIFY_UNTRACKED;
|
|
279
|
+
remove = ((data->strategy & GIT_CHECKOUT_REMOVE_UNTRACKED) != 0);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (checkout_notify(data, notify, NULL, wd))
|
|
283
|
+
return GIT_EUSER;
|
|
284
|
+
|
|
285
|
+
if (remove) {
|
|
286
|
+
char *path = git_pool_strdup(&data->pool, wd->path);
|
|
287
|
+
GITERR_CHECK_ALLOC(path);
|
|
288
|
+
|
|
289
|
+
if (git_vector_insert(&data->removes, path) < 0)
|
|
290
|
+
return -1;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return 0;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
static bool submodule_is_config_only(
|
|
297
|
+
checkout_data *data,
|
|
298
|
+
const char *path)
|
|
299
|
+
{
|
|
300
|
+
git_submodule *sm = NULL;
|
|
301
|
+
unsigned int sm_loc = 0;
|
|
302
|
+
|
|
303
|
+
if (git_submodule_lookup(&sm, data->repo, path) < 0 ||
|
|
304
|
+
git_submodule_location(&sm_loc, sm) < 0 ||
|
|
305
|
+
sm_loc == GIT_SUBMODULE_STATUS_IN_CONFIG)
|
|
306
|
+
return true;
|
|
307
|
+
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
static int checkout_action_with_wd(
|
|
312
|
+
checkout_data *data,
|
|
313
|
+
const git_diff_delta *delta,
|
|
314
|
+
const git_index_entry *wd)
|
|
315
|
+
{
|
|
316
|
+
int action = CHECKOUT_ACTION__NONE;
|
|
317
|
+
|
|
318
|
+
switch (delta->status) {
|
|
319
|
+
case GIT_DELTA_UNMODIFIED: /* case 14/15 or 33 */
|
|
320
|
+
if (checkout_is_workdir_modified(data, &delta->old_file, wd)) {
|
|
321
|
+
if (checkout_notify(
|
|
322
|
+
data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd))
|
|
323
|
+
return GIT_EUSER;
|
|
324
|
+
action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, NONE);
|
|
325
|
+
}
|
|
326
|
+
break;
|
|
327
|
+
case GIT_DELTA_ADDED: /* case 3, 4 or 6 */
|
|
328
|
+
action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT);
|
|
329
|
+
break;
|
|
330
|
+
case GIT_DELTA_DELETED: /* case 9 or 10 (or 26 but not really) */
|
|
331
|
+
if (checkout_is_workdir_modified(data, &delta->old_file, wd))
|
|
332
|
+
action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
|
|
333
|
+
else
|
|
334
|
+
action = CHECKOUT_ACTION_IF(SAFE, REMOVE, NONE);
|
|
335
|
+
break;
|
|
336
|
+
case GIT_DELTA_MODIFIED: /* case 16, 17, 18 (or 36 but not really) */
|
|
337
|
+
if (checkout_is_workdir_modified(data, &delta->old_file, wd))
|
|
338
|
+
action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT);
|
|
339
|
+
else
|
|
340
|
+
action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
|
|
341
|
+
break;
|
|
342
|
+
case GIT_DELTA_TYPECHANGE: /* case 22, 23, 29, 30 */
|
|
343
|
+
if (delta->old_file.mode == GIT_FILEMODE_TREE) {
|
|
344
|
+
if (wd->mode == GIT_FILEMODE_TREE)
|
|
345
|
+
/* either deleting items in old tree will delete the wd dir,
|
|
346
|
+
* or we'll get a conflict when we attempt blob update...
|
|
347
|
+
*/
|
|
348
|
+
action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
|
|
349
|
+
else if (wd->mode == GIT_FILEMODE_COMMIT) {
|
|
350
|
+
/* workdir is possibly a "phantom" submodule - treat as a
|
|
351
|
+
* tree if the only submodule info came from the config
|
|
352
|
+
*/
|
|
353
|
+
if (submodule_is_config_only(data, wd->path))
|
|
354
|
+
action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
|
|
355
|
+
else
|
|
356
|
+
action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
|
|
357
|
+
} else
|
|
358
|
+
action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
|
|
359
|
+
}
|
|
360
|
+
else if (checkout_is_workdir_modified(data, &delta->old_file, wd))
|
|
361
|
+
action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
|
|
362
|
+
else
|
|
363
|
+
action = CHECKOUT_ACTION_IF(SAFE, REMOVE_AND_UPDATE, NONE);
|
|
364
|
+
|
|
365
|
+
/* don't update if the typechange is to a tree */
|
|
366
|
+
if (delta->new_file.mode == GIT_FILEMODE_TREE)
|
|
367
|
+
action = (action & ~CHECKOUT_ACTION__UPDATE_BLOB);
|
|
368
|
+
break;
|
|
369
|
+
default: /* impossible */
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return checkout_action_common(data, action, delta, wd);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
static int checkout_action_with_wd_blocker(
|
|
377
|
+
checkout_data *data,
|
|
378
|
+
const git_diff_delta *delta,
|
|
379
|
+
const git_index_entry *wd)
|
|
380
|
+
{
|
|
381
|
+
int action = CHECKOUT_ACTION__NONE;
|
|
382
|
+
|
|
383
|
+
switch (delta->status) {
|
|
384
|
+
case GIT_DELTA_UNMODIFIED:
|
|
385
|
+
/* should show delta as dirty / deleted */
|
|
386
|
+
if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd))
|
|
387
|
+
return GIT_EUSER;
|
|
388
|
+
action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, NONE);
|
|
389
|
+
break;
|
|
390
|
+
case GIT_DELTA_ADDED:
|
|
391
|
+
case GIT_DELTA_MODIFIED:
|
|
392
|
+
action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
|
|
393
|
+
break;
|
|
394
|
+
case GIT_DELTA_DELETED:
|
|
395
|
+
action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
|
|
396
|
+
break;
|
|
397
|
+
case GIT_DELTA_TYPECHANGE:
|
|
398
|
+
/* not 100% certain about this... */
|
|
399
|
+
action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
|
|
400
|
+
break;
|
|
401
|
+
default: /* impossible */
|
|
402
|
+
break;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return checkout_action_common(data, action, delta, wd);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
static int checkout_action_with_wd_dir(
|
|
409
|
+
checkout_data *data,
|
|
410
|
+
const git_diff_delta *delta,
|
|
411
|
+
const git_index_entry *wd)
|
|
412
|
+
{
|
|
413
|
+
int action = CHECKOUT_ACTION__NONE;
|
|
414
|
+
|
|
415
|
+
switch (delta->status) {
|
|
416
|
+
case GIT_DELTA_UNMODIFIED: /* case 19 or 24 (or 34 but not really) */
|
|
417
|
+
if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL) ||
|
|
418
|
+
checkout_notify(
|
|
419
|
+
data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd))
|
|
420
|
+
return GIT_EUSER;
|
|
421
|
+
break;
|
|
422
|
+
case GIT_DELTA_ADDED:/* case 4 (and 7 for dir) */
|
|
423
|
+
case GIT_DELTA_MODIFIED: /* case 20 (or 37 but not really) */
|
|
424
|
+
if (delta->old_file.mode == GIT_FILEMODE_COMMIT)
|
|
425
|
+
/* expected submodule (and maybe found one) */;
|
|
426
|
+
else if (delta->new_file.mode != GIT_FILEMODE_TREE)
|
|
427
|
+
action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
|
|
428
|
+
break;
|
|
429
|
+
case GIT_DELTA_DELETED: /* case 11 (and 27 for dir) */
|
|
430
|
+
if (delta->old_file.mode != GIT_FILEMODE_TREE &&
|
|
431
|
+
checkout_notify(
|
|
432
|
+
data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd))
|
|
433
|
+
return GIT_EUSER;
|
|
434
|
+
break;
|
|
435
|
+
case GIT_DELTA_TYPECHANGE: /* case 24 or 31 */
|
|
436
|
+
if (delta->old_file.mode == GIT_FILEMODE_TREE) {
|
|
437
|
+
/* For typechange from dir, remove dir and add blob, but it is
|
|
438
|
+
* not safe to remove dir if it contains modified files.
|
|
439
|
+
* However, safely removing child files will remove the parent
|
|
440
|
+
* directory if is it left empty, so we can defer removing the
|
|
441
|
+
* dir and it will succeed if no children are left.
|
|
442
|
+
*/
|
|
443
|
+
action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
|
|
444
|
+
if (action != CHECKOUT_ACTION__NONE)
|
|
445
|
+
action |= CHECKOUT_ACTION__DEFER_REMOVE;
|
|
446
|
+
}
|
|
447
|
+
else if (delta->new_file.mode != GIT_FILEMODE_TREE)
|
|
448
|
+
/* For typechange to dir, dir is already created so no action */
|
|
449
|
+
action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
|
|
450
|
+
break;
|
|
451
|
+
default: /* impossible */
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return checkout_action_common(data, action, delta, wd);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
static int checkout_action(
|
|
459
|
+
checkout_data *data,
|
|
460
|
+
git_diff_delta *delta,
|
|
461
|
+
git_iterator *workdir,
|
|
462
|
+
const git_index_entry **wditem_ptr,
|
|
463
|
+
git_vector *pathspec)
|
|
464
|
+
{
|
|
465
|
+
const git_index_entry *wd = *wditem_ptr;
|
|
466
|
+
int cmp = -1, act;
|
|
467
|
+
int (*strcomp)(const char *, const char *) = data->diff->strcomp;
|
|
468
|
+
int (*pfxcomp)(const char *str, const char *pfx) = data->diff->pfxcomp;
|
|
469
|
+
|
|
470
|
+
/* move workdir iterator to follow along with deltas */
|
|
471
|
+
|
|
472
|
+
while (1) {
|
|
473
|
+
if (!wd)
|
|
474
|
+
return checkout_action_no_wd(data, delta);
|
|
475
|
+
|
|
476
|
+
cmp = strcomp(wd->path, delta->old_file.path);
|
|
477
|
+
|
|
478
|
+
/* 1. wd before delta ("a/a" before "a/b")
|
|
479
|
+
* 2. wd prefixes delta & should expand ("a/" before "a/b")
|
|
480
|
+
* 3. wd prefixes delta & cannot expand ("a/b" before "a/b/c")
|
|
481
|
+
* 4. wd equals delta ("a/b" and "a/b")
|
|
482
|
+
* 5. wd after delta & delta prefixes wd ("a/b/c" after "a/b/" or "a/b")
|
|
483
|
+
* 6. wd after delta ("a/c" after "a/b")
|
|
484
|
+
*/
|
|
485
|
+
|
|
486
|
+
if (cmp < 0) {
|
|
487
|
+
cmp = pfxcomp(delta->old_file.path, wd->path);
|
|
488
|
+
|
|
489
|
+
if (cmp == 0) {
|
|
490
|
+
if (wd->mode == GIT_FILEMODE_TREE) {
|
|
491
|
+
/* case 2 - entry prefixed by workdir tree */
|
|
492
|
+
if (git_iterator_advance_into(&wd, workdir) < 0)
|
|
493
|
+
goto fail;
|
|
494
|
+
|
|
495
|
+
*wditem_ptr = wd;
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/* case 3 maybe - wd contains non-dir where dir expected */
|
|
500
|
+
if (delta->old_file.path[strlen(wd->path)] == '/') {
|
|
501
|
+
act = checkout_action_with_wd_blocker(data, delta, wd);
|
|
502
|
+
*wditem_ptr =
|
|
503
|
+
git_iterator_advance(&wd, workdir) ? NULL : wd;
|
|
504
|
+
return act;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/* case 1 - handle wd item (if it matches pathspec) */
|
|
509
|
+
if (checkout_action_wd_only(data, workdir, wd, pathspec) < 0 ||
|
|
510
|
+
git_iterator_advance(&wd, workdir) < 0)
|
|
511
|
+
goto fail;
|
|
512
|
+
|
|
513
|
+
*wditem_ptr = wd;
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (cmp == 0) {
|
|
518
|
+
/* case 4 */
|
|
519
|
+
act = checkout_action_with_wd(data, delta, wd);
|
|
520
|
+
*wditem_ptr = git_iterator_advance(&wd, workdir) ? NULL : wd;
|
|
521
|
+
return act;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
cmp = pfxcomp(wd->path, delta->old_file.path);
|
|
525
|
+
|
|
526
|
+
if (cmp == 0) { /* case 5 */
|
|
527
|
+
if (wd->path[strlen(delta->old_file.path)] != '/')
|
|
528
|
+
return checkout_action_no_wd(data, delta);
|
|
529
|
+
|
|
530
|
+
if (delta->status == GIT_DELTA_TYPECHANGE) {
|
|
531
|
+
if (delta->old_file.mode == GIT_FILEMODE_TREE) {
|
|
532
|
+
act = checkout_action_with_wd(data, delta, wd);
|
|
533
|
+
if (git_iterator_advance_into(&wd, workdir) < 0)
|
|
534
|
+
wd = NULL;
|
|
535
|
+
*wditem_ptr = wd;
|
|
536
|
+
return act;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (delta->new_file.mode == GIT_FILEMODE_TREE ||
|
|
540
|
+
delta->new_file.mode == GIT_FILEMODE_COMMIT ||
|
|
541
|
+
delta->old_file.mode == GIT_FILEMODE_COMMIT)
|
|
542
|
+
{
|
|
543
|
+
act = checkout_action_with_wd(data, delta, wd);
|
|
544
|
+
if (git_iterator_advance(&wd, workdir) < 0)
|
|
545
|
+
wd = NULL;
|
|
546
|
+
*wditem_ptr = wd;
|
|
547
|
+
return act;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
return checkout_action_with_wd_dir(data, delta, wd);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/* case 6 - wd is after delta */
|
|
555
|
+
return checkout_action_no_wd(data, delta);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
fail:
|
|
559
|
+
*wditem_ptr = NULL;
|
|
560
|
+
return -1;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
static int checkout_remaining_wd_items(
|
|
564
|
+
checkout_data *data,
|
|
565
|
+
git_iterator *workdir,
|
|
566
|
+
const git_index_entry *wd,
|
|
567
|
+
git_vector *spec)
|
|
568
|
+
{
|
|
569
|
+
int error = 0;
|
|
570
|
+
|
|
571
|
+
while (wd && !error) {
|
|
572
|
+
if (!(error = checkout_action_wd_only(data, workdir, wd, spec)))
|
|
573
|
+
error = git_iterator_advance(&wd, workdir);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
return error;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
static int checkout_get_actions(
|
|
580
|
+
uint32_t **actions_ptr,
|
|
581
|
+
size_t **counts_ptr,
|
|
582
|
+
checkout_data *data,
|
|
583
|
+
git_iterator *workdir)
|
|
584
|
+
{
|
|
585
|
+
int error = 0;
|
|
586
|
+
const git_index_entry *wditem;
|
|
587
|
+
git_vector pathspec = GIT_VECTOR_INIT, *deltas;
|
|
588
|
+
git_pool pathpool = GIT_POOL_INIT_STRINGPOOL;
|
|
589
|
+
git_diff_delta *delta;
|
|
590
|
+
size_t i, *counts = NULL;
|
|
591
|
+
uint32_t *actions = NULL;
|
|
592
|
+
|
|
593
|
+
if (data->opts.paths.count > 0 &&
|
|
594
|
+
git_pathspec_init(&pathspec, &data->opts.paths, &pathpool) < 0)
|
|
595
|
+
return -1;
|
|
596
|
+
|
|
597
|
+
if ((error = git_iterator_current(&wditem, workdir)) < 0)
|
|
598
|
+
goto fail;
|
|
599
|
+
|
|
600
|
+
deltas = &data->diff->deltas;
|
|
601
|
+
|
|
602
|
+
*counts_ptr = counts = git__calloc(CHECKOUT_ACTION__MAX+1, sizeof(size_t));
|
|
603
|
+
*actions_ptr = actions = git__calloc(
|
|
604
|
+
deltas->length ? deltas->length : 1, sizeof(uint32_t));
|
|
605
|
+
if (!counts || !actions) {
|
|
606
|
+
error = -1;
|
|
607
|
+
goto fail;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
git_vector_foreach(deltas, i, delta) {
|
|
611
|
+
int act = checkout_action(data, delta, workdir, &wditem, &pathspec);
|
|
612
|
+
|
|
613
|
+
if (act < 0) {
|
|
614
|
+
error = act;
|
|
615
|
+
goto fail;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
actions[i] = act;
|
|
619
|
+
|
|
620
|
+
if (act & CHECKOUT_ACTION__REMOVE)
|
|
621
|
+
counts[CHECKOUT_ACTION__REMOVE]++;
|
|
622
|
+
if (act & CHECKOUT_ACTION__UPDATE_BLOB)
|
|
623
|
+
counts[CHECKOUT_ACTION__UPDATE_BLOB]++;
|
|
624
|
+
if (act & CHECKOUT_ACTION__UPDATE_SUBMODULE)
|
|
625
|
+
counts[CHECKOUT_ACTION__UPDATE_SUBMODULE]++;
|
|
626
|
+
if (act & CHECKOUT_ACTION__CONFLICT)
|
|
627
|
+
counts[CHECKOUT_ACTION__CONFLICT]++;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
error = checkout_remaining_wd_items(data, workdir, wditem, &pathspec);
|
|
631
|
+
if (error < 0)
|
|
632
|
+
goto fail;
|
|
633
|
+
|
|
634
|
+
counts[CHECKOUT_ACTION__REMOVE] += data->removes.length;
|
|
635
|
+
|
|
636
|
+
if (counts[CHECKOUT_ACTION__CONFLICT] > 0 &&
|
|
637
|
+
(data->strategy & GIT_CHECKOUT_ALLOW_CONFLICTS) == 0)
|
|
638
|
+
{
|
|
639
|
+
giterr_set(GITERR_CHECKOUT, "%d conflicts prevent checkout",
|
|
640
|
+
(int)counts[CHECKOUT_ACTION__CONFLICT]);
|
|
641
|
+
error = GIT_EMERGECONFLICT;
|
|
642
|
+
goto fail;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
git_pathspec_free(&pathspec);
|
|
646
|
+
git_pool_clear(&pathpool);
|
|
647
|
+
|
|
648
|
+
return 0;
|
|
649
|
+
|
|
650
|
+
fail:
|
|
651
|
+
*counts_ptr = NULL;
|
|
652
|
+
git__free(counts);
|
|
653
|
+
*actions_ptr = NULL;
|
|
654
|
+
git__free(actions);
|
|
655
|
+
|
|
656
|
+
git_pathspec_free(&pathspec);
|
|
657
|
+
git_pool_clear(&pathpool);
|
|
658
|
+
|
|
659
|
+
return error;
|
|
660
|
+
}
|
|
37
661
|
|
|
38
662
|
static int buffer_to_file(
|
|
663
|
+
struct stat *st,
|
|
39
664
|
git_buf *buffer,
|
|
40
665
|
const char *path,
|
|
41
666
|
mode_t dir_mode,
|
|
42
667
|
int file_open_flags,
|
|
43
668
|
mode_t file_mode)
|
|
44
669
|
{
|
|
45
|
-
int fd, error
|
|
670
|
+
int fd, error;
|
|
46
671
|
|
|
47
672
|
if ((error = git_futils_mkpath2file(path, dir_mode)) < 0)
|
|
48
673
|
return error;
|
|
49
674
|
|
|
50
|
-
if ((fd = p_open(path, file_open_flags, file_mode)) < 0)
|
|
675
|
+
if ((fd = p_open(path, file_open_flags, file_mode)) < 0) {
|
|
676
|
+
giterr_set(GITERR_OS, "Could not open '%s' for writing", path);
|
|
51
677
|
return fd;
|
|
678
|
+
}
|
|
52
679
|
|
|
53
|
-
error = p_write(fd, git_buf_cstr(buffer), git_buf_len(buffer))
|
|
54
|
-
|
|
55
|
-
|
|
680
|
+
if ((error = p_write(fd, git_buf_cstr(buffer), git_buf_len(buffer))) < 0) {
|
|
681
|
+
giterr_set(GITERR_OS, "Could not write to '%s'", path);
|
|
682
|
+
(void)p_close(fd);
|
|
683
|
+
} else {
|
|
684
|
+
if ((error = p_close(fd)) < 0)
|
|
685
|
+
giterr_set(GITERR_OS, "Error while closing '%s'", path);
|
|
56
686
|
|
|
57
|
-
|
|
58
|
-
|
|
687
|
+
if ((error = p_stat(path, st)) < 0)
|
|
688
|
+
giterr_set(GITERR_OS, "Error while statting '%s'", path);
|
|
689
|
+
}
|
|
59
690
|
|
|
60
691
|
if (!error &&
|
|
61
692
|
(file_mode & 0100) != 0 &&
|
|
@@ -66,6 +697,7 @@ static int buffer_to_file(
|
|
|
66
697
|
}
|
|
67
698
|
|
|
68
699
|
static int blob_content_to_file(
|
|
700
|
+
struct stat *st,
|
|
69
701
|
git_blob *blob,
|
|
70
702
|
const char *path,
|
|
71
703
|
mode_t entry_filemode,
|
|
@@ -73,23 +705,27 @@ static int blob_content_to_file(
|
|
|
73
705
|
{
|
|
74
706
|
int error = -1, nb_filters = 0;
|
|
75
707
|
mode_t file_mode = opts->file_mode;
|
|
76
|
-
bool dont_free_filtered
|
|
708
|
+
bool dont_free_filtered;
|
|
77
709
|
git_buf unfiltered = GIT_BUF_INIT, filtered = GIT_BUF_INIT;
|
|
78
710
|
git_vector filters = GIT_VECTOR_INIT;
|
|
79
711
|
|
|
80
|
-
|
|
712
|
+
/* Create a fake git_buf from the blob raw data... */
|
|
713
|
+
filtered.ptr = blob->odb_object->raw.data;
|
|
714
|
+
filtered.size = blob->odb_object->raw.len;
|
|
715
|
+
/* ... and make sure it doesn't get unexpectedly freed */
|
|
716
|
+
dont_free_filtered = true;
|
|
717
|
+
|
|
718
|
+
if (!opts->disable_filters &&
|
|
719
|
+
!git_buf_text_is_binary(&filtered) &&
|
|
81
720
|
(nb_filters = git_filters_load(
|
|
82
721
|
&filters,
|
|
83
722
|
git_object_owner((git_object *)blob),
|
|
84
723
|
path,
|
|
85
|
-
GIT_FILTER_TO_WORKTREE))
|
|
86
|
-
|
|
87
|
-
/*
|
|
88
|
-
filtered
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
/* ... and make sure it doesn't get unexpectedly freed */
|
|
92
|
-
dont_free_filtered = true;
|
|
724
|
+
GIT_FILTER_TO_WORKTREE)) > 0)
|
|
725
|
+
{
|
|
726
|
+
/* reset 'filtered' so it can be a filter target */
|
|
727
|
+
git_buf_init(&filtered, 0);
|
|
728
|
+
dont_free_filtered = false;
|
|
93
729
|
}
|
|
94
730
|
|
|
95
731
|
if (nb_filters < 0)
|
|
@@ -107,7 +743,11 @@ static int blob_content_to_file(
|
|
|
107
743
|
if (!file_mode)
|
|
108
744
|
file_mode = entry_filemode;
|
|
109
745
|
|
|
110
|
-
error = buffer_to_file(
|
|
746
|
+
error = buffer_to_file(
|
|
747
|
+
st, &filtered, path, opts->dir_mode, opts->file_open_flags, file_mode);
|
|
748
|
+
|
|
749
|
+
if (!error)
|
|
750
|
+
st->st_mode = entry_filemode;
|
|
111
751
|
|
|
112
752
|
cleanup:
|
|
113
753
|
git_filters_free(&filters);
|
|
@@ -118,7 +758,8 @@ cleanup:
|
|
|
118
758
|
return error;
|
|
119
759
|
}
|
|
120
760
|
|
|
121
|
-
static int blob_content_to_link(
|
|
761
|
+
static int blob_content_to_link(
|
|
762
|
+
struct stat *st, git_blob *blob, const char *path, int can_symlink)
|
|
122
763
|
{
|
|
123
764
|
git_buf linktarget = GIT_BUF_INIT;
|
|
124
765
|
int error;
|
|
@@ -126,327 +767,629 @@ static int blob_content_to_link(git_blob *blob, const char *path, bool can_symli
|
|
|
126
767
|
if ((error = git_blob__getbuf(&linktarget, blob)) < 0)
|
|
127
768
|
return error;
|
|
128
769
|
|
|
129
|
-
if (can_symlink)
|
|
130
|
-
error = p_symlink(git_buf_cstr(&linktarget), path)
|
|
131
|
-
|
|
770
|
+
if (can_symlink) {
|
|
771
|
+
if ((error = p_symlink(git_buf_cstr(&linktarget), path)) < 0)
|
|
772
|
+
giterr_set(GITERR_CHECKOUT, "Could not create symlink %s\n", path);
|
|
773
|
+
} else {
|
|
132
774
|
error = git_futils_fake_symlink(git_buf_cstr(&linktarget), path);
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
if (!error) {
|
|
778
|
+
if ((error = p_lstat(path, st)) < 0)
|
|
779
|
+
giterr_set(GITERR_CHECKOUT, "Could not stat symlink %s", path);
|
|
780
|
+
|
|
781
|
+
st->st_mode = GIT_FILEMODE_LINK;
|
|
782
|
+
}
|
|
133
783
|
|
|
134
784
|
git_buf_free(&linktarget);
|
|
135
785
|
|
|
136
786
|
return error;
|
|
137
787
|
}
|
|
138
788
|
|
|
789
|
+
static int checkout_update_index(
|
|
790
|
+
checkout_data *data,
|
|
791
|
+
const git_diff_file *file,
|
|
792
|
+
struct stat *st)
|
|
793
|
+
{
|
|
794
|
+
git_index_entry entry;
|
|
795
|
+
|
|
796
|
+
if (!data->index)
|
|
797
|
+
return 0;
|
|
798
|
+
|
|
799
|
+
memset(&entry, 0, sizeof(entry));
|
|
800
|
+
entry.path = (char *)file->path; /* cast to prevent warning */
|
|
801
|
+
git_index_entry__init_from_stat(&entry, st);
|
|
802
|
+
git_oid_cpy(&entry.oid, &file->oid);
|
|
803
|
+
|
|
804
|
+
return git_index_add(data->index, &entry);
|
|
805
|
+
}
|
|
806
|
+
|
|
139
807
|
static int checkout_submodule(
|
|
140
|
-
|
|
808
|
+
checkout_data *data,
|
|
141
809
|
const git_diff_file *file)
|
|
142
810
|
{
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
811
|
+
int error = 0;
|
|
812
|
+
git_submodule *sm;
|
|
813
|
+
|
|
814
|
+
/* Until submodules are supported, UPDATE_ONLY means do nothing here */
|
|
815
|
+
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0)
|
|
816
|
+
return 0;
|
|
817
|
+
|
|
818
|
+
if ((error = git_futils_mkdir(
|
|
819
|
+
file->path, git_repository_workdir(data->repo),
|
|
820
|
+
data->opts.dir_mode, GIT_MKDIR_PATH)) < 0)
|
|
821
|
+
return error;
|
|
822
|
+
|
|
823
|
+
if ((error = git_submodule_lookup(&sm, data->repo, file->path)) < 0)
|
|
824
|
+
return error;
|
|
147
825
|
|
|
148
|
-
/* TODO:
|
|
826
|
+
/* TODO: Support checkout_strategy options. Two circumstances:
|
|
149
827
|
* 1 - submodule already checked out, but we need to move the HEAD
|
|
150
828
|
* to the new OID, or
|
|
151
829
|
* 2 - submodule not checked out and we should recursively check it out
|
|
152
830
|
*
|
|
153
|
-
* Checkout will not execute a pull
|
|
154
|
-
*
|
|
155
|
-
* callback option?
|
|
831
|
+
* Checkout will not execute a pull on the submodule, but a clone
|
|
832
|
+
* command should probably be able to. Do we need a submodule callback?
|
|
156
833
|
*/
|
|
157
834
|
|
|
835
|
+
/* update the index unless prevented */
|
|
836
|
+
if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0) {
|
|
837
|
+
struct stat st;
|
|
838
|
+
|
|
839
|
+
git_buf_truncate(&data->path, data->workdir_len);
|
|
840
|
+
if (git_buf_puts(&data->path, file->path) < 0)
|
|
841
|
+
return -1;
|
|
842
|
+
|
|
843
|
+
if ((error = p_stat(git_buf_cstr(&data->path), &st)) < 0) {
|
|
844
|
+
giterr_set(
|
|
845
|
+
GITERR_CHECKOUT, "Could not stat submodule %s\n", file->path);
|
|
846
|
+
return error;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
st.st_mode = GIT_FILEMODE_COMMIT;
|
|
850
|
+
|
|
851
|
+
error = checkout_update_index(data, file, &st);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
return error;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
static void report_progress(
|
|
858
|
+
checkout_data *data,
|
|
859
|
+
const char *path)
|
|
860
|
+
{
|
|
861
|
+
if (data->opts.progress_cb)
|
|
862
|
+
data->opts.progress_cb(
|
|
863
|
+
path, data->completed_steps, data->total_steps,
|
|
864
|
+
data->opts.progress_payload);
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
static int checkout_safe_for_update_only(const char *path, mode_t expected_mode)
|
|
868
|
+
{
|
|
869
|
+
struct stat st;
|
|
870
|
+
|
|
871
|
+
if (p_lstat(path, &st) < 0) {
|
|
872
|
+
/* if doesn't exist, then no error and no update */
|
|
873
|
+
if (errno == ENOENT || errno == ENOTDIR)
|
|
874
|
+
return 0;
|
|
875
|
+
|
|
876
|
+
/* otherwise, stat error and no update */
|
|
877
|
+
giterr_set(GITERR_OS, "Failed to stat file '%s'", path);
|
|
878
|
+
return -1;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
/* only safe for update if this is the same type of file */
|
|
882
|
+
if ((st.st_mode & ~0777) == (expected_mode & ~0777))
|
|
883
|
+
return 1;
|
|
884
|
+
|
|
158
885
|
return 0;
|
|
159
886
|
}
|
|
160
887
|
|
|
161
888
|
static int checkout_blob(
|
|
162
|
-
|
|
889
|
+
checkout_data *data,
|
|
163
890
|
const git_diff_file *file)
|
|
164
891
|
{
|
|
892
|
+
int error = 0;
|
|
165
893
|
git_blob *blob;
|
|
166
|
-
|
|
894
|
+
struct stat st;
|
|
167
895
|
|
|
168
|
-
git_buf_truncate(data->path, data->workdir_len);
|
|
169
|
-
if (
|
|
896
|
+
git_buf_truncate(&data->path, data->workdir_len);
|
|
897
|
+
if (git_buf_puts(&data->path, file->path) < 0)
|
|
170
898
|
return -1;
|
|
171
899
|
|
|
172
|
-
if ((
|
|
900
|
+
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0) {
|
|
901
|
+
int rval = checkout_safe_for_update_only(
|
|
902
|
+
git_buf_cstr(&data->path), file->mode);
|
|
903
|
+
if (rval <= 0)
|
|
904
|
+
return rval;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
if ((error = git_blob_lookup(&blob, data->repo, &file->oid)) < 0)
|
|
173
908
|
return error;
|
|
174
909
|
|
|
175
910
|
if (S_ISLNK(file->mode))
|
|
176
911
|
error = blob_content_to_link(
|
|
177
|
-
blob, git_buf_cstr(data->path), data->can_symlink);
|
|
912
|
+
&st, blob, git_buf_cstr(&data->path), data->can_symlink);
|
|
178
913
|
else
|
|
179
914
|
error = blob_content_to_file(
|
|
180
|
-
blob, git_buf_cstr(data->path), file->mode, data->
|
|
915
|
+
&st, blob, git_buf_cstr(&data->path), file->mode, &data->opts);
|
|
181
916
|
|
|
182
917
|
git_blob_free(blob);
|
|
183
918
|
|
|
919
|
+
/* if we try to create the blob and an existing directory blocks it from
|
|
920
|
+
* being written, then there must have been a typechange conflict in a
|
|
921
|
+
* parent directory - suppress the error and try to continue.
|
|
922
|
+
*/
|
|
923
|
+
if ((data->strategy & GIT_CHECKOUT_ALLOW_CONFLICTS) != 0 &&
|
|
924
|
+
(error == GIT_ENOTFOUND || error == GIT_EEXISTS))
|
|
925
|
+
{
|
|
926
|
+
giterr_clear();
|
|
927
|
+
error = 0;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/* update the index unless prevented */
|
|
931
|
+
if (!error && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
|
|
932
|
+
error = checkout_update_index(data, file, &st);
|
|
933
|
+
|
|
934
|
+
/* update the submodule data if this was a new .gitmodules file */
|
|
935
|
+
if (!error && strcmp(file->path, ".gitmodules") == 0)
|
|
936
|
+
data->reload_submodules = true;
|
|
937
|
+
|
|
184
938
|
return error;
|
|
185
939
|
}
|
|
186
940
|
|
|
187
941
|
static int checkout_remove_the_old(
|
|
188
|
-
|
|
942
|
+
unsigned int *actions,
|
|
943
|
+
checkout_data *data)
|
|
189
944
|
{
|
|
190
|
-
|
|
191
|
-
|
|
945
|
+
int error = 0;
|
|
946
|
+
git_diff_delta *delta;
|
|
947
|
+
const char *str;
|
|
948
|
+
size_t i;
|
|
949
|
+
const char *workdir = git_buf_cstr(&data->path);
|
|
950
|
+
uint32_t flg = GIT_RMDIR_EMPTY_PARENTS |
|
|
951
|
+
GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS;
|
|
952
|
+
|
|
953
|
+
git_buf_truncate(&data->path, data->workdir_len);
|
|
954
|
+
|
|
955
|
+
git_vector_foreach(&data->diff->deltas, i, delta) {
|
|
956
|
+
if (actions[i] & CHECKOUT_ACTION__REMOVE) {
|
|
957
|
+
error = git_futils_rmdir_r(delta->old_file.path, workdir, flg);
|
|
958
|
+
if (error < 0)
|
|
959
|
+
return error;
|
|
960
|
+
|
|
961
|
+
data->completed_steps++;
|
|
962
|
+
report_progress(data, delta->old_file.path);
|
|
963
|
+
|
|
964
|
+
if ((actions[i] & CHECKOUT_ACTION__UPDATE_BLOB) == 0 &&
|
|
965
|
+
(data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0 &&
|
|
966
|
+
data->index != NULL)
|
|
967
|
+
{
|
|
968
|
+
(void)git_index_remove(data->index, delta->old_file.path, 0);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
}
|
|
192
972
|
|
|
193
|
-
|
|
194
|
-
|
|
973
|
+
git_vector_foreach(&data->removes, i, str) {
|
|
974
|
+
error = git_futils_rmdir_r(str, workdir, flg);
|
|
975
|
+
if (error < 0)
|
|
976
|
+
return error;
|
|
195
977
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
978
|
+
data->completed_steps++;
|
|
979
|
+
report_progress(data, str);
|
|
980
|
+
|
|
981
|
+
if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0 &&
|
|
982
|
+
data->index != NULL)
|
|
983
|
+
{
|
|
984
|
+
if (str[strlen(str) - 1] == '/')
|
|
985
|
+
(void)git_index_remove_directory(data->index, str, 0);
|
|
986
|
+
else
|
|
987
|
+
(void)git_index_remove(data->index, str, 0);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
return 0;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
static int checkout_deferred_remove(git_repository *repo, const char *path)
|
|
995
|
+
{
|
|
996
|
+
#if 0
|
|
997
|
+
int error = git_futils_rmdir_r(
|
|
998
|
+
path, git_repository_workdir(repo), GIT_RMDIR_EMPTY_PARENTS);
|
|
999
|
+
|
|
1000
|
+
if (error == GIT_ENOTFOUND) {
|
|
1001
|
+
error = 0;
|
|
1002
|
+
giterr_clear();
|
|
205
1003
|
}
|
|
206
1004
|
|
|
207
|
-
return
|
|
1005
|
+
return error;
|
|
1006
|
+
#else
|
|
1007
|
+
GIT_UNUSED(repo);
|
|
1008
|
+
GIT_UNUSED(path);
|
|
1009
|
+
assert(false);
|
|
1010
|
+
return 0;
|
|
1011
|
+
#endif
|
|
208
1012
|
}
|
|
209
1013
|
|
|
210
1014
|
static int checkout_create_the_new(
|
|
211
|
-
|
|
1015
|
+
unsigned int *actions,
|
|
1016
|
+
checkout_data *data)
|
|
212
1017
|
{
|
|
213
1018
|
int error = 0;
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
1019
|
+
git_diff_delta *delta;
|
|
1020
|
+
size_t i;
|
|
1021
|
+
|
|
1022
|
+
git_vector_foreach(&data->diff->deltas, i, delta) {
|
|
1023
|
+
if (actions[i] & CHECKOUT_ACTION__DEFER_REMOVE) {
|
|
1024
|
+
/* this had a blocker directory that should only be removed iff
|
|
1025
|
+
* all of the contents of the directory were safely removed
|
|
1026
|
+
*/
|
|
1027
|
+
if ((error = checkout_deferred_remove(
|
|
1028
|
+
data->repo, delta->old_file.path)) < 0)
|
|
1029
|
+
return error;
|
|
1030
|
+
}
|
|
217
1031
|
|
|
218
|
-
|
|
219
|
-
|
|
1032
|
+
if (actions[i] & CHECKOUT_ACTION__UPDATE_BLOB) {
|
|
1033
|
+
error = checkout_blob(data, &delta->new_file);
|
|
1034
|
+
if (error < 0)
|
|
1035
|
+
return error;
|
|
220
1036
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
{
|
|
224
|
-
if ((opts->checkout_strategy & GIT_CHECKOUT_OVERWRITE_MODIFIED) != 0)
|
|
225
|
-
do_checkout = true;
|
|
226
|
-
else if (opts->skipped_notify_cb != NULL)
|
|
227
|
-
do_notify = !data->create_submodules;
|
|
228
|
-
}
|
|
229
|
-
else if (delta->status == GIT_DELTA_DELETED &&
|
|
230
|
-
(opts->checkout_strategy & GIT_CHECKOUT_CREATE_MISSING) != 0)
|
|
231
|
-
do_checkout = true;
|
|
232
|
-
|
|
233
|
-
if (do_notify) {
|
|
234
|
-
if (opts->skipped_notify_cb(
|
|
235
|
-
delta->old_file.path, &delta->old_file.oid,
|
|
236
|
-
delta->old_file.mode, opts->notify_payload))
|
|
237
|
-
{
|
|
238
|
-
giterr_clear();
|
|
239
|
-
error = GIT_EUSER;
|
|
1037
|
+
data->completed_steps++;
|
|
1038
|
+
report_progress(data, delta->new_file.path);
|
|
240
1039
|
}
|
|
241
1040
|
}
|
|
242
1041
|
|
|
243
|
-
|
|
244
|
-
|
|
1042
|
+
return 0;
|
|
1043
|
+
}
|
|
245
1044
|
|
|
246
|
-
|
|
247
|
-
|
|
1045
|
+
static int checkout_create_submodules(
|
|
1046
|
+
unsigned int *actions,
|
|
1047
|
+
checkout_data *data)
|
|
1048
|
+
{
|
|
1049
|
+
int error = 0;
|
|
1050
|
+
git_diff_delta *delta;
|
|
1051
|
+
size_t i;
|
|
248
1052
|
|
|
249
|
-
|
|
250
|
-
|
|
1053
|
+
/* initial reload of submodules if .gitmodules was changed */
|
|
1054
|
+
if (data->reload_submodules &&
|
|
1055
|
+
(error = git_submodule_reload_all(data->repo)) < 0)
|
|
1056
|
+
return error;
|
|
1057
|
+
|
|
1058
|
+
git_vector_foreach(&data->diff->deltas, i, delta) {
|
|
1059
|
+
if (actions[i] & CHECKOUT_ACTION__DEFER_REMOVE) {
|
|
1060
|
+
/* this has a blocker directory that should only be removed iff
|
|
1061
|
+
* all of the contents of the directory were safely removed
|
|
1062
|
+
*/
|
|
1063
|
+
if ((error = checkout_deferred_remove(
|
|
1064
|
+
data->repo, delta->old_file.path)) < 0)
|
|
1065
|
+
return error;
|
|
1066
|
+
}
|
|
251
1067
|
|
|
252
|
-
|
|
253
|
-
error = checkout_submodule(data, &delta->
|
|
1068
|
+
if (actions[i] & CHECKOUT_ACTION__UPDATE_SUBMODULE) {
|
|
1069
|
+
int error = checkout_submodule(data, &delta->new_file);
|
|
1070
|
+
if (error < 0)
|
|
1071
|
+
return error;
|
|
1072
|
+
|
|
1073
|
+
data->completed_steps++;
|
|
1074
|
+
report_progress(data, delta->new_file.path);
|
|
1075
|
+
}
|
|
254
1076
|
}
|
|
255
1077
|
|
|
256
|
-
|
|
257
|
-
|
|
1078
|
+
/* final reload once submodules have been updated */
|
|
1079
|
+
return git_submodule_reload_all(data->repo);
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
static int checkout_lookup_head_tree(git_tree **out, git_repository *repo)
|
|
1083
|
+
{
|
|
1084
|
+
int error = 0;
|
|
1085
|
+
git_reference *ref = NULL;
|
|
1086
|
+
git_object *head;
|
|
1087
|
+
|
|
1088
|
+
if (!(error = git_repository_head(&ref, repo)) &&
|
|
1089
|
+
!(error = git_reference_peel(&head, ref, GIT_OBJ_TREE)))
|
|
1090
|
+
*out = (git_tree *)head;
|
|
1091
|
+
|
|
1092
|
+
git_reference_free(ref);
|
|
258
1093
|
|
|
259
1094
|
return error;
|
|
260
1095
|
}
|
|
261
1096
|
|
|
262
|
-
static
|
|
1097
|
+
static void checkout_data_clear(checkout_data *data)
|
|
263
1098
|
{
|
|
264
|
-
|
|
265
|
-
|
|
1099
|
+
if (data->opts_free_baseline) {
|
|
1100
|
+
git_tree_free(data->opts.baseline);
|
|
1101
|
+
data->opts.baseline = NULL;
|
|
1102
|
+
}
|
|
266
1103
|
|
|
267
|
-
|
|
268
|
-
|
|
1104
|
+
git_vector_free(&data->removes);
|
|
1105
|
+
git_pool_clear(&data->pool);
|
|
269
1106
|
|
|
270
|
-
|
|
1107
|
+
git__free(data->pfx);
|
|
1108
|
+
data->pfx = NULL;
|
|
271
1109
|
|
|
272
|
-
|
|
273
|
-
* When no "core.symlinks" entry is found in any of the configuration
|
|
274
|
-
* store (local, global or system), default value is "true".
|
|
275
|
-
*/
|
|
276
|
-
if (error == GIT_ENOTFOUND) {
|
|
277
|
-
*can_symlink = true;
|
|
278
|
-
error = 0;
|
|
279
|
-
}
|
|
1110
|
+
git_buf_free(&data->path);
|
|
280
1111
|
|
|
281
|
-
|
|
1112
|
+
git_index_free(data->index);
|
|
1113
|
+
data->index = NULL;
|
|
282
1114
|
}
|
|
283
1115
|
|
|
284
|
-
static
|
|
1116
|
+
static int checkout_data_init(
|
|
1117
|
+
checkout_data *data,
|
|
1118
|
+
git_iterator *target,
|
|
1119
|
+
git_checkout_opts *proposed)
|
|
285
1120
|
{
|
|
286
|
-
|
|
1121
|
+
int error = 0;
|
|
1122
|
+
git_config *cfg;
|
|
1123
|
+
git_repository *repo = git_iterator_owner(target);
|
|
1124
|
+
|
|
1125
|
+
memset(data, 0, sizeof(*data));
|
|
1126
|
+
|
|
1127
|
+
if (!repo) {
|
|
1128
|
+
giterr_set(GITERR_CHECKOUT, "Cannot checkout nothing");
|
|
1129
|
+
return -1;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
if ((error = git_repository__ensure_not_bare(repo, "checkout")) < 0)
|
|
1133
|
+
return error;
|
|
1134
|
+
|
|
1135
|
+
if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
|
|
1136
|
+
return error;
|
|
1137
|
+
|
|
1138
|
+
data->repo = repo;
|
|
1139
|
+
|
|
1140
|
+
GITERR_CHECK_VERSION(
|
|
1141
|
+
proposed, GIT_CHECKOUT_OPTS_VERSION, "git_checkout_opts");
|
|
287
1142
|
|
|
288
1143
|
if (!proposed)
|
|
289
|
-
|
|
1144
|
+
GIT_INIT_STRUCTURE(&data->opts, GIT_CHECKOUT_OPTS_VERSION);
|
|
290
1145
|
else
|
|
291
|
-
memmove(
|
|
1146
|
+
memmove(&data->opts, proposed, sizeof(git_checkout_opts));
|
|
1147
|
+
|
|
1148
|
+
/* refresh config and index content unless NO_REFRESH is given */
|
|
1149
|
+
if ((data->opts.checkout_strategy & GIT_CHECKOUT_NO_REFRESH) == 0) {
|
|
1150
|
+
if ((error = git_config_refresh(cfg)) < 0)
|
|
1151
|
+
goto cleanup;
|
|
292
1152
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
1153
|
+
/* if we are checking out the index, don't reload,
|
|
1154
|
+
* otherwise get index and force reload
|
|
1155
|
+
*/
|
|
1156
|
+
if ((data->index = git_iterator_get_index(target)) != NULL) {
|
|
1157
|
+
GIT_REFCOUNT_INC(data->index);
|
|
1158
|
+
} else {
|
|
1159
|
+
/* otherwise, grab and reload the index */
|
|
1160
|
+
if ((error = git_repository_index(&data->index, data->repo)) < 0 ||
|
|
1161
|
+
(error = git_index_read(data->index)) < 0)
|
|
1162
|
+
goto cleanup;
|
|
1163
|
+
|
|
1164
|
+
/* clear the REUC when doing a tree or commit checkout */
|
|
1165
|
+
git_index_reuc_clear(data->index);
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
/* if you are forcing, definitely allow safe updates */
|
|
1170
|
+
if ((data->opts.checkout_strategy & GIT_CHECKOUT_FORCE) != 0)
|
|
1171
|
+
data->opts.checkout_strategy |= GIT_CHECKOUT_SAFE_CREATE;
|
|
1172
|
+
if ((data->opts.checkout_strategy & GIT_CHECKOUT_SAFE_CREATE) != 0)
|
|
1173
|
+
data->opts.checkout_strategy |= GIT_CHECKOUT_SAFE;
|
|
1174
|
+
|
|
1175
|
+
data->strategy = data->opts.checkout_strategy;
|
|
296
1176
|
|
|
297
1177
|
/* opts->disable_filters is false by default */
|
|
298
|
-
if (!normalized->dir_mode)
|
|
299
|
-
normalized->dir_mode = GIT_DIR_MODE;
|
|
300
1178
|
|
|
301
|
-
if (!
|
|
302
|
-
|
|
303
|
-
}
|
|
1179
|
+
if (!data->opts.dir_mode)
|
|
1180
|
+
data->opts.dir_mode = GIT_DIR_MODE;
|
|
304
1181
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
git_checkout_opts *opts,
|
|
308
|
-
git_indexer_stats *stats)
|
|
309
|
-
{
|
|
310
|
-
git_diff_list *diff = NULL;
|
|
311
|
-
git_indexer_stats dummy_stats;
|
|
1182
|
+
if (!data->opts.file_open_flags)
|
|
1183
|
+
data->opts.file_open_flags = O_CREAT | O_TRUNC | O_WRONLY;
|
|
312
1184
|
|
|
313
|
-
|
|
314
|
-
git_checkout_opts checkout_opts;
|
|
1185
|
+
data->pfx = git_pathspec_prefix(&data->opts.paths);
|
|
315
1186
|
|
|
316
|
-
|
|
317
|
-
|
|
1187
|
+
error = git_config_get_bool(&data->can_symlink, cfg, "core.symlinks");
|
|
1188
|
+
if (error < 0) {
|
|
1189
|
+
if (error != GIT_ENOTFOUND)
|
|
1190
|
+
goto cleanup;
|
|
318
1191
|
|
|
319
|
-
|
|
1192
|
+
/* If "core.symlinks" is not found anywhere, default to true. */
|
|
1193
|
+
data->can_symlink = true;
|
|
1194
|
+
giterr_clear();
|
|
1195
|
+
error = 0;
|
|
1196
|
+
}
|
|
320
1197
|
|
|
321
|
-
|
|
1198
|
+
if (!data->opts.baseline) {
|
|
1199
|
+
data->opts_free_baseline = true;
|
|
1200
|
+
error = checkout_lookup_head_tree(&data->opts.baseline, repo);
|
|
322
1201
|
|
|
323
|
-
|
|
1202
|
+
if (error == GIT_EORPHANEDHEAD) {
|
|
1203
|
+
error = 0;
|
|
1204
|
+
giterr_clear();
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
if (error < 0)
|
|
1208
|
+
goto cleanup;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
if ((error = git_vector_init(&data->removes, 0, git__strcmp_cb)) < 0 ||
|
|
1212
|
+
(error = git_pool_init(&data->pool, 1, 0)) < 0 ||
|
|
1213
|
+
(error = git_buf_puts(&data->path, git_repository_workdir(repo))) < 0)
|
|
1214
|
+
goto cleanup;
|
|
1215
|
+
|
|
1216
|
+
data->workdir_len = git_buf_len(&data->path);
|
|
1217
|
+
|
|
1218
|
+
cleanup:
|
|
1219
|
+
if (error < 0)
|
|
1220
|
+
checkout_data_clear(data);
|
|
1221
|
+
|
|
1222
|
+
return error;
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
int git_checkout_iterator(
|
|
1226
|
+
git_iterator *target,
|
|
1227
|
+
git_checkout_opts *opts)
|
|
1228
|
+
{
|
|
1229
|
+
int error = 0;
|
|
1230
|
+
git_iterator *baseline = NULL, *workdir = NULL;
|
|
1231
|
+
checkout_data data = {0};
|
|
1232
|
+
git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
|
|
1233
|
+
uint32_t *actions = NULL;
|
|
1234
|
+
size_t *counts = NULL;
|
|
1235
|
+
git_iterator_flag_t iterflags = 0;
|
|
1236
|
+
|
|
1237
|
+
/* initialize structures and options */
|
|
1238
|
+
error = checkout_data_init(&data, target, opts);
|
|
1239
|
+
if (error < 0)
|
|
324
1240
|
return error;
|
|
325
1241
|
|
|
326
1242
|
diff_opts.flags =
|
|
1243
|
+
GIT_DIFF_INCLUDE_UNMODIFIED |
|
|
327
1244
|
GIT_DIFF_INCLUDE_UNTRACKED |
|
|
1245
|
+
GIT_DIFF_RECURSE_UNTRACKED_DIRS | /* needed to match baseline */
|
|
1246
|
+
GIT_DIFF_INCLUDE_IGNORED |
|
|
328
1247
|
GIT_DIFF_INCLUDE_TYPECHANGE |
|
|
1248
|
+
GIT_DIFF_INCLUDE_TYPECHANGE_TREES |
|
|
329
1249
|
GIT_DIFF_SKIP_BINARY_CHECK;
|
|
1250
|
+
if (data.opts.checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)
|
|
1251
|
+
diff_opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH;
|
|
1252
|
+
if (data.opts.paths.count > 0)
|
|
1253
|
+
diff_opts.pathspec = data.opts.paths;
|
|
1254
|
+
|
|
1255
|
+
/* set up iterators */
|
|
1256
|
+
|
|
1257
|
+
iterflags = git_iterator_ignore_case(target) ?
|
|
1258
|
+
GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE;
|
|
1259
|
+
|
|
1260
|
+
if ((error = git_iterator_reset(target, data.pfx, data.pfx)) < 0 ||
|
|
1261
|
+
(error = git_iterator_for_workdir(
|
|
1262
|
+
&workdir, data.repo, iterflags | GIT_ITERATOR_DONT_AUTOEXPAND,
|
|
1263
|
+
data.pfx, data.pfx)) < 0 ||
|
|
1264
|
+
(error = git_iterator_for_tree(
|
|
1265
|
+
&baseline, data.opts.baseline, iterflags, data.pfx, data.pfx)) < 0)
|
|
1266
|
+
goto cleanup;
|
|
330
1267
|
|
|
331
|
-
|
|
332
|
-
|
|
1268
|
+
/* Should not have case insensitivity mismatch */
|
|
1269
|
+
assert(git_iterator_ignore_case(workdir) == git_iterator_ignore_case(baseline));
|
|
333
1270
|
|
|
334
|
-
|
|
1271
|
+
/* Generate baseline-to-target diff which will include an entry for
|
|
1272
|
+
* every possible update that might need to be made.
|
|
1273
|
+
*/
|
|
1274
|
+
if ((error = git_diff__from_iterators(
|
|
1275
|
+
&data.diff, data.repo, baseline, target, &diff_opts)) < 0)
|
|
335
1276
|
goto cleanup;
|
|
336
1277
|
|
|
337
|
-
|
|
1278
|
+
/* Loop through diff (and working directory iterator) building a list of
|
|
1279
|
+
* actions to be taken, plus look for conflicts and send notifications.
|
|
1280
|
+
*/
|
|
1281
|
+
if ((error = checkout_get_actions(&actions, &counts, &data, workdir)) < 0)
|
|
338
1282
|
goto cleanup;
|
|
339
1283
|
|
|
340
|
-
|
|
1284
|
+
data.total_steps = counts[CHECKOUT_ACTION__REMOVE] +
|
|
1285
|
+
counts[CHECKOUT_ACTION__UPDATE_BLOB] +
|
|
1286
|
+
counts[CHECKOUT_ACTION__UPDATE_SUBMODULE];
|
|
341
1287
|
|
|
342
|
-
|
|
343
|
-
stats = &dummy_stats;
|
|
1288
|
+
report_progress(&data, NULL); /* establish 0 baseline */
|
|
344
1289
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
data.path = &workdir;
|
|
352
|
-
data.workdir_len = git_buf_len(&workdir);
|
|
353
|
-
data.checkout_opts = &checkout_opts;
|
|
354
|
-
data.stats = stats;
|
|
355
|
-
data.owner = repo;
|
|
356
|
-
|
|
357
|
-
if ((error = retrieve_symlink_capabilities(repo, &data.can_symlink)) < 0)
|
|
1290
|
+
/* To deal with some order dependencies, perform remaining checkout
|
|
1291
|
+
* in three passes: removes, then update blobs, then update submodules.
|
|
1292
|
+
*/
|
|
1293
|
+
if (counts[CHECKOUT_ACTION__REMOVE] > 0 &&
|
|
1294
|
+
(error = checkout_remove_the_old(actions, &data)) < 0)
|
|
358
1295
|
goto cleanup;
|
|
359
1296
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
* a new untracked directory will end up sorted *after* a blob that
|
|
364
|
-
* should be checked out with the same name.
|
|
365
|
-
* 2. Then checkout all blobs.
|
|
366
|
-
* 3. Then checkout all submodules in case a new .gitmodules blob was
|
|
367
|
-
* checked out during pass #2.
|
|
368
|
-
*/
|
|
1297
|
+
if (counts[CHECKOUT_ACTION__UPDATE_BLOB] > 0 &&
|
|
1298
|
+
(error = checkout_create_the_new(actions, &data)) < 0)
|
|
1299
|
+
goto cleanup;
|
|
369
1300
|
|
|
370
|
-
if (
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
diff, &data, checkout_create_the_new, NULL, NULL)) &&
|
|
374
|
-
data.found_submodules)
|
|
375
|
-
{
|
|
376
|
-
data.create_submodules = true;
|
|
377
|
-
error = git_diff_foreach(
|
|
378
|
-
diff, &data, checkout_create_the_new, NULL, NULL);
|
|
379
|
-
}
|
|
1301
|
+
if (counts[CHECKOUT_ACTION__UPDATE_SUBMODULE] > 0 &&
|
|
1302
|
+
(error = checkout_create_submodules(actions, &data)) < 0)
|
|
1303
|
+
goto cleanup;
|
|
380
1304
|
|
|
381
|
-
|
|
1305
|
+
assert(data.completed_steps == data.total_steps);
|
|
382
1306
|
|
|
383
1307
|
cleanup:
|
|
384
1308
|
if (error == GIT_EUSER)
|
|
385
|
-
|
|
1309
|
+
giterr_clear();
|
|
1310
|
+
|
|
1311
|
+
if (!error && data.index != NULL &&
|
|
1312
|
+
(data.strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
|
|
1313
|
+
error = git_index_write(data.index);
|
|
386
1314
|
|
|
387
|
-
git_diff_list_free(diff);
|
|
388
|
-
|
|
1315
|
+
git_diff_list_free(data.diff);
|
|
1316
|
+
git_iterator_free(workdir);
|
|
1317
|
+
git_iterator_free(baseline);
|
|
1318
|
+
git__free(actions);
|
|
1319
|
+
git__free(counts);
|
|
1320
|
+
checkout_data_clear(&data);
|
|
389
1321
|
|
|
390
1322
|
return error;
|
|
391
1323
|
}
|
|
392
1324
|
|
|
393
|
-
int
|
|
1325
|
+
int git_checkout_index(
|
|
394
1326
|
git_repository *repo,
|
|
395
|
-
|
|
396
|
-
git_checkout_opts *opts
|
|
397
|
-
git_indexer_stats *stats)
|
|
1327
|
+
git_index *index,
|
|
1328
|
+
git_checkout_opts *opts)
|
|
398
1329
|
{
|
|
399
|
-
git_index *index = NULL;
|
|
400
|
-
git_tree *tree = NULL;
|
|
401
|
-
|
|
402
1330
|
int error;
|
|
1331
|
+
git_iterator *index_i;
|
|
403
1332
|
|
|
404
|
-
|
|
1333
|
+
if ((error = git_repository__ensure_not_bare(repo, "checkout index")) < 0)
|
|
1334
|
+
return error;
|
|
405
1335
|
|
|
406
|
-
if (
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
}
|
|
1336
|
+
if (!index && (error = git_repository_index__weakptr(&index, repo)) < 0)
|
|
1337
|
+
return error;
|
|
1338
|
+
GIT_REFCOUNT_INC(index);
|
|
410
1339
|
|
|
411
|
-
if ((error =
|
|
412
|
-
|
|
1340
|
+
if (!(error = git_iterator_for_index(&index_i, index, 0, NULL, NULL)))
|
|
1341
|
+
error = git_checkout_iterator(index_i, opts);
|
|
413
1342
|
|
|
414
|
-
|
|
415
|
-
|
|
1343
|
+
git_iterator_free(index_i);
|
|
1344
|
+
git_index_free(index);
|
|
416
1345
|
|
|
417
|
-
|
|
418
|
-
|
|
1346
|
+
return error;
|
|
1347
|
+
}
|
|
419
1348
|
|
|
420
|
-
|
|
1349
|
+
int git_checkout_tree(
|
|
1350
|
+
git_repository *repo,
|
|
1351
|
+
const git_object *treeish,
|
|
1352
|
+
git_checkout_opts *opts)
|
|
1353
|
+
{
|
|
1354
|
+
int error;
|
|
1355
|
+
git_tree *tree = NULL;
|
|
1356
|
+
git_iterator *tree_i = NULL;
|
|
421
1357
|
|
|
422
|
-
|
|
423
|
-
|
|
1358
|
+
if ((error = git_repository__ensure_not_bare(repo, "checkout tree")) < 0)
|
|
1359
|
+
return error;
|
|
1360
|
+
|
|
1361
|
+
if (git_object_peel((git_object **)&tree, treeish, GIT_OBJ_TREE) < 0) {
|
|
1362
|
+
giterr_set(
|
|
1363
|
+
GITERR_CHECKOUT, "Provided object cannot be peeled to a tree");
|
|
1364
|
+
return -1;
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
if (!(error = git_iterator_for_tree(&tree_i, tree, 0, NULL, NULL)))
|
|
1368
|
+
error = git_checkout_iterator(tree_i, opts);
|
|
1369
|
+
|
|
1370
|
+
git_iterator_free(tree_i);
|
|
424
1371
|
git_tree_free(tree);
|
|
1372
|
+
|
|
425
1373
|
return error;
|
|
426
1374
|
}
|
|
427
1375
|
|
|
428
1376
|
int git_checkout_head(
|
|
429
1377
|
git_repository *repo,
|
|
430
|
-
git_checkout_opts *opts
|
|
431
|
-
git_indexer_stats *stats)
|
|
1378
|
+
git_checkout_opts *opts)
|
|
432
1379
|
{
|
|
433
|
-
git_reference *head;
|
|
434
1380
|
int error;
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
assert(repo);
|
|
1381
|
+
git_tree *head = NULL;
|
|
1382
|
+
git_iterator *head_i = NULL;
|
|
438
1383
|
|
|
439
|
-
if ((error =
|
|
1384
|
+
if ((error = git_repository__ensure_not_bare(repo, "checkout head")) < 0)
|
|
440
1385
|
return error;
|
|
441
|
-
|
|
442
|
-
if ((error = git_reference_peel(&tree, head, GIT_OBJ_TREE)) < 0)
|
|
443
|
-
goto cleanup;
|
|
444
1386
|
|
|
445
|
-
error =
|
|
1387
|
+
if (!(error = checkout_lookup_head_tree(&head, repo)) &&
|
|
1388
|
+
!(error = git_iterator_for_tree(&head_i, head, 0, NULL, NULL)))
|
|
1389
|
+
error = git_checkout_iterator(head_i, opts);
|
|
446
1390
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
git_object_free(tree);
|
|
1391
|
+
git_iterator_free(head_i);
|
|
1392
|
+
git_tree_free(head);
|
|
450
1393
|
|
|
451
1394
|
return error;
|
|
452
1395
|
}
|