rugged 0.19.0 → 0.28.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +1 -1
- data/README.md +184 -33
- data/ext/rugged/extconf.rb +111 -28
- data/ext/rugged/rugged.c +327 -89
- data/ext/rugged/rugged.h +64 -28
- data/ext/rugged/rugged_allocator.c +89 -0
- data/ext/rugged/rugged_backend.c +17 -0
- data/ext/rugged/rugged_blame.c +278 -0
- data/ext/rugged/rugged_blob.c +301 -75
- data/ext/rugged/rugged_branch.c +92 -242
- data/ext/rugged/rugged_branch_collection.c +388 -0
- data/ext/rugged/rugged_commit.c +575 -79
- data/ext/rugged/rugged_config.c +129 -36
- data/ext/rugged/rugged_cred.c +131 -0
- data/ext/rugged/rugged_diff.c +291 -122
- data/ext/rugged/rugged_diff_delta.c +16 -22
- data/ext/rugged/rugged_diff_hunk.c +35 -51
- data/ext/rugged/rugged_diff_line.c +23 -36
- data/ext/rugged/rugged_index.c +289 -152
- data/ext/rugged/rugged_note.c +50 -60
- data/ext/rugged/rugged_object.c +13 -30
- data/ext/rugged/rugged_patch.c +400 -0
- data/ext/rugged/rugged_rebase.c +397 -0
- data/ext/rugged/rugged_reference.c +76 -346
- data/ext/rugged/rugged_reference_collection.c +423 -0
- data/ext/rugged/rugged_remote.c +438 -461
- data/ext/rugged/rugged_remote_collection.c +435 -0
- data/ext/rugged/rugged_repo.c +1548 -365
- data/ext/rugged/rugged_revwalk.c +378 -99
- data/ext/rugged/rugged_settings.c +86 -23
- data/ext/rugged/rugged_signature.c +47 -37
- data/ext/rugged/rugged_submodule.c +835 -0
- data/ext/rugged/rugged_submodule_collection.c +366 -0
- data/ext/rugged/rugged_tag.c +88 -210
- data/ext/rugged/rugged_tag_collection.c +326 -0
- data/ext/rugged/rugged_tree.c +460 -217
- data/lib/rugged/attributes.rb +46 -0
- data/lib/rugged/blob.rb +33 -0
- data/lib/rugged/branch.rb +12 -16
- data/lib/rugged/commit.rb +9 -0
- data/lib/rugged/console.rb +5 -0
- data/lib/rugged/credentials.rb +48 -0
- data/lib/rugged/diff/delta.rb +6 -2
- data/lib/rugged/diff/hunk.rb +9 -9
- data/lib/rugged/diff/line.rb +28 -5
- data/lib/rugged/diff.rb +7 -1
- data/lib/rugged/index.rb +120 -0
- data/lib/rugged/object.rb +5 -0
- data/lib/rugged/patch.rb +41 -0
- data/lib/rugged/reference.rb +6 -3
- data/lib/rugged/remote.rb +5 -9
- data/lib/rugged/repository.rb +126 -14
- data/lib/rugged/submodule_collection.rb +53 -0
- data/lib/rugged/tag.rb +45 -16
- data/lib/rugged/tree.rb +163 -1
- data/lib/rugged/version.rb +6 -1
- data/lib/rugged/walker.rb +5 -0
- data/lib/rugged.rb +16 -1
- data/vendor/libgit2/AUTHORS +77 -0
- data/vendor/libgit2/CMakeLists.txt +317 -0
- data/vendor/libgit2/COPYING +993 -0
- data/vendor/libgit2/cmake/Modules/AddCFlagIfSupported.cmake +30 -0
- data/vendor/libgit2/cmake/Modules/CheckPrototypeDefinition.c.in +29 -0
- data/vendor/libgit2/cmake/Modules/CheckPrototypeDefinition.cmake +96 -0
- data/vendor/libgit2/cmake/Modules/EnableWarnings.cmake +11 -0
- data/vendor/libgit2/cmake/Modules/FindCoreFoundation.cmake +26 -0
- data/vendor/libgit2/cmake/Modules/FindGSSAPI.cmake +324 -0
- data/vendor/libgit2/cmake/Modules/FindHTTP_Parser.cmake +39 -0
- data/vendor/libgit2/cmake/Modules/FindIconv.cmake +45 -0
- data/vendor/libgit2/cmake/Modules/FindPkgLibraries.cmake +28 -0
- data/vendor/libgit2/cmake/Modules/FindSecurity.cmake +28 -0
- data/vendor/libgit2/cmake/Modules/FindStatNsec.cmake +20 -0
- data/vendor/libgit2/cmake/Modules/FindmbedTLS.cmake +93 -0
- data/vendor/libgit2/cmake/Modules/IdeSplitSources.cmake +22 -0
- data/vendor/libgit2/deps/http-parser/CMakeLists.txt +5 -0
- data/vendor/libgit2/deps/http-parser/COPYING +23 -0
- data/vendor/libgit2/deps/http-parser/http_parser.c +5 -2
- data/vendor/libgit2/deps/http-parser/http_parser.h +2 -0
- data/vendor/libgit2/deps/regex/CMakeLists.txt +2 -0
- data/vendor/libgit2/deps/regex/COPYING +502 -0
- data/vendor/libgit2/deps/regex/regex.c +10 -3
- data/vendor/libgit2/deps/winhttp/CMakeLists.txt +26 -0
- data/vendor/libgit2/deps/winhttp/COPYING.GPL +993 -0
- data/vendor/libgit2/deps/winhttp/COPYING.LGPL +502 -0
- data/vendor/libgit2/deps/winhttp/urlmon.h +45 -0
- data/vendor/libgit2/deps/winhttp/winhttp.def +29 -0
- data/vendor/libgit2/deps/winhttp/winhttp.h +594 -0
- data/vendor/libgit2/deps/winhttp/winhttp64.def +29 -0
- data/vendor/libgit2/deps/zlib/CMakeLists.txt +5 -0
- data/vendor/libgit2/deps/zlib/COPYING +27 -0
- data/vendor/libgit2/deps/zlib/adler32.c +51 -34
- data/vendor/libgit2/deps/zlib/crc32.c +61 -61
- data/vendor/libgit2/deps/zlib/crc32.h +1 -1
- data/vendor/libgit2/deps/zlib/deflate.c +681 -352
- data/vendor/libgit2/deps/zlib/deflate.h +25 -18
- data/vendor/libgit2/deps/zlib/gzguts.h +218 -0
- data/vendor/libgit2/deps/zlib/infback.c +640 -0
- data/vendor/libgit2/deps/zlib/inffast.c +36 -53
- data/vendor/libgit2/deps/zlib/inffixed.h +3 -3
- data/vendor/libgit2/deps/zlib/inflate.c +167 -86
- data/vendor/libgit2/deps/zlib/inflate.h +7 -4
- data/vendor/libgit2/deps/zlib/inftrees.c +24 -50
- data/vendor/libgit2/deps/zlib/trees.c +55 -96
- data/vendor/libgit2/deps/zlib/zconf.h +499 -19
- data/vendor/libgit2/deps/zlib/zlib.h +526 -227
- data/vendor/libgit2/deps/zlib/zutil.c +39 -32
- data/vendor/libgit2/deps/zlib/zutil.h +75 -78
- data/vendor/libgit2/include/git2/annotated_commit.h +125 -0
- data/vendor/libgit2/include/git2/apply.h +129 -0
- data/vendor/libgit2/include/git2/attr.h +36 -21
- data/vendor/libgit2/include/git2/blame.h +229 -0
- data/vendor/libgit2/include/git2/blob.h +81 -44
- data/vendor/libgit2/include/git2/branch.h +81 -42
- data/vendor/libgit2/include/git2/buffer.h +128 -0
- data/vendor/libgit2/include/git2/checkout.h +141 -67
- data/vendor/libgit2/include/git2/cherrypick.h +92 -0
- data/vendor/libgit2/include/git2/clone.h +157 -58
- data/vendor/libgit2/include/git2/commit.h +231 -12
- data/vendor/libgit2/include/git2/common.h +216 -30
- data/vendor/libgit2/include/git2/config.h +274 -48
- data/vendor/libgit2/include/git2/cred_helpers.h +4 -4
- data/vendor/libgit2/include/git2/deprecated.h +253 -0
- data/vendor/libgit2/include/git2/describe.h +189 -0
- data/vendor/libgit2/include/git2/diff.h +985 -575
- data/vendor/libgit2/include/git2/errors.h +93 -52
- data/vendor/libgit2/include/git2/filter.h +217 -0
- data/vendor/libgit2/include/git2/global.h +44 -0
- data/vendor/libgit2/include/git2/graph.h +17 -0
- data/vendor/libgit2/include/git2/ignore.h +2 -2
- data/vendor/libgit2/include/git2/index.h +269 -94
- data/vendor/libgit2/include/git2/indexer.h +44 -12
- data/vendor/libgit2/include/git2/mailmap.h +115 -0
- data/vendor/libgit2/include/git2/merge.h +501 -64
- data/vendor/libgit2/include/git2/message.h +52 -17
- data/vendor/libgit2/include/git2/net.h +11 -5
- data/vendor/libgit2/include/git2/notes.h +120 -16
- data/vendor/libgit2/include/git2/object.h +62 -23
- data/vendor/libgit2/include/git2/odb.h +140 -24
- data/vendor/libgit2/include/git2/odb_backend.h +56 -12
- data/vendor/libgit2/include/git2/oid.h +17 -18
- data/vendor/libgit2/include/git2/oidarray.h +40 -0
- data/vendor/libgit2/include/git2/pack.h +86 -7
- data/vendor/libgit2/include/git2/patch.h +274 -0
- data/vendor/libgit2/include/git2/pathspec.h +280 -0
- data/vendor/libgit2/include/git2/proxy.h +96 -0
- data/vendor/libgit2/include/git2/rebase.h +323 -0
- data/vendor/libgit2/include/git2/reflog.h +12 -9
- data/vendor/libgit2/include/git2/refs.h +241 -46
- data/vendor/libgit2/include/git2/refspec.h +20 -4
- data/vendor/libgit2/include/git2/remote.h +636 -209
- data/vendor/libgit2/include/git2/repository.h +267 -57
- data/vendor/libgit2/include/git2/reset.h +36 -6
- data/vendor/libgit2/include/git2/revert.h +91 -0
- data/vendor/libgit2/include/git2/revparse.h +27 -16
- data/vendor/libgit2/include/git2/revwalk.h +78 -35
- data/vendor/libgit2/include/git2/signature.h +32 -5
- data/vendor/libgit2/include/git2/stash.h +160 -21
- data/vendor/libgit2/include/git2/status.h +92 -30
- data/vendor/libgit2/include/git2/submodule.h +226 -133
- data/vendor/libgit2/include/git2/sys/alloc.h +101 -0
- data/vendor/libgit2/include/git2/sys/commit.h +38 -4
- data/vendor/libgit2/include/git2/sys/config.h +68 -9
- data/vendor/libgit2/include/git2/sys/diff.h +94 -0
- data/vendor/libgit2/include/git2/sys/filter.h +332 -0
- data/vendor/libgit2/include/git2/sys/hashsig.h +106 -0
- data/vendor/libgit2/include/git2/sys/index.h +6 -5
- data/vendor/libgit2/include/git2/sys/mempack.h +86 -0
- data/vendor/libgit2/include/git2/sys/merge.h +182 -0
- data/vendor/libgit2/include/git2/sys/odb_backend.h +66 -28
- data/vendor/libgit2/include/git2/sys/openssl.h +38 -0
- data/vendor/libgit2/include/git2/sys/path.h +64 -0
- data/vendor/libgit2/include/git2/sys/refdb_backend.h +79 -19
- data/vendor/libgit2/include/git2/sys/reflog.h +21 -0
- data/vendor/libgit2/include/git2/sys/refs.h +13 -2
- data/vendor/libgit2/include/git2/sys/repository.h +64 -1
- data/vendor/libgit2/include/git2/sys/stream.h +138 -0
- data/vendor/libgit2/include/git2/sys/time.h +31 -0
- data/vendor/libgit2/include/git2/sys/transport.h +439 -0
- data/vendor/libgit2/include/git2/tag.h +11 -2
- data/vendor/libgit2/include/git2/trace.h +1 -1
- data/vendor/libgit2/include/git2/transaction.h +121 -0
- data/vendor/libgit2/include/git2/transport.h +261 -292
- data/vendor/libgit2/include/git2/tree.h +111 -21
- data/vendor/libgit2/include/git2/types.h +244 -32
- data/vendor/libgit2/include/git2/version.h +5 -2
- data/vendor/libgit2/include/git2/worktree.h +255 -0
- data/vendor/libgit2/include/git2.h +50 -40
- data/vendor/libgit2/libgit2.pc.in +13 -0
- data/vendor/libgit2/src/CMakeLists.txt +525 -0
- data/vendor/libgit2/src/alloc.c +55 -0
- data/vendor/libgit2/src/alloc.h +40 -0
- data/vendor/libgit2/src/annotated_commit.c +228 -0
- data/vendor/libgit2/src/annotated_commit.h +52 -0
- data/vendor/libgit2/src/apply.c +855 -0
- data/vendor/libgit2/src/apply.h +25 -0
- data/vendor/libgit2/src/array.h +74 -16
- data/vendor/libgit2/src/attr.c +239 -408
- data/vendor/libgit2/src/attr.h +3 -33
- data/vendor/libgit2/src/attr_file.c +424 -156
- data/vendor/libgit2/src/attr_file.h +95 -23
- data/vendor/libgit2/src/attrcache.c +469 -0
- data/vendor/libgit2/src/attrcache.h +37 -5
- data/vendor/libgit2/src/bitvec.h +75 -0
- data/vendor/libgit2/src/blame.c +532 -0
- data/vendor/libgit2/src/blame.h +95 -0
- data/vendor/libgit2/src/blame_git.c +668 -0
- data/vendor/libgit2/src/blame_git.h +22 -0
- data/vendor/libgit2/src/blob.c +233 -129
- data/vendor/libgit2/src/blob.h +29 -1
- data/vendor/libgit2/src/branch.c +295 -197
- data/vendor/libgit2/src/branch.h +2 -0
- data/vendor/libgit2/src/buf_text.c +52 -27
- data/vendor/libgit2/src/buf_text.h +7 -7
- data/vendor/libgit2/src/buffer.c +609 -52
- data/vendor/libgit2/src/buffer.h +68 -23
- data/vendor/libgit2/src/cache.c +48 -51
- data/vendor/libgit2/src/cache.h +6 -4
- data/vendor/libgit2/src/cc-compat.h +35 -7
- data/vendor/libgit2/src/checkout.c +1827 -483
- data/vendor/libgit2/src/checkout.h +4 -1
- data/vendor/libgit2/src/cherrypick.c +230 -0
- data/vendor/libgit2/src/clone.c +338 -258
- data/vendor/libgit2/src/{compress.h → clone.h} +5 -5
- data/vendor/libgit2/src/commit.c +711 -124
- data/vendor/libgit2/src/commit.h +10 -3
- data/vendor/libgit2/src/commit_list.c +21 -14
- data/vendor/libgit2/src/commit_list.h +9 -3
- data/vendor/libgit2/src/common.h +153 -13
- data/vendor/libgit2/src/config.c +871 -242
- data/vendor/libgit2/src/config.h +58 -14
- data/vendor/libgit2/src/config_backend.h +84 -0
- data/vendor/libgit2/src/config_cache.c +44 -18
- data/vendor/libgit2/src/config_entries.c +259 -0
- data/vendor/libgit2/src/config_entries.h +23 -0
- data/vendor/libgit2/src/config_file.c +837 -1113
- data/vendor/libgit2/src/config_mem.c +224 -0
- data/vendor/libgit2/src/config_parse.c +558 -0
- data/vendor/libgit2/src/config_parse.h +64 -0
- data/vendor/libgit2/src/crlf.c +290 -195
- data/vendor/libgit2/src/date.c +35 -7
- data/vendor/libgit2/src/delta.c +275 -71
- data/vendor/libgit2/src/delta.h +80 -58
- data/vendor/libgit2/src/describe.c +893 -0
- data/vendor/libgit2/src/diff.c +330 -1128
- data/vendor/libgit2/src/diff.h +25 -67
- data/vendor/libgit2/src/diff_driver.c +225 -109
- data/vendor/libgit2/src/diff_driver.h +5 -2
- data/vendor/libgit2/src/diff_file.c +128 -103
- data/vendor/libgit2/src/diff_file.h +17 -12
- data/vendor/libgit2/src/diff_generate.c +1622 -0
- data/vendor/libgit2/src/diff_generate.h +128 -0
- data/vendor/libgit2/src/diff_parse.c +108 -0
- data/vendor/libgit2/src/diff_parse.h +20 -0
- data/vendor/libgit2/src/diff_print.c +578 -218
- data/vendor/libgit2/src/diff_stats.c +362 -0
- data/vendor/libgit2/src/diff_tform.c +429 -257
- data/vendor/libgit2/src/diff_tform.h +25 -0
- data/vendor/libgit2/src/diff_xdiff.c +143 -46
- data/vendor/libgit2/src/diff_xdiff.h +12 -5
- data/vendor/libgit2/src/errors.c +150 -34
- data/vendor/libgit2/src/features.h.in +37 -0
- data/vendor/libgit2/src/fetch.c +69 -46
- data/vendor/libgit2/src/fetch.h +6 -12
- data/vendor/libgit2/src/fetchhead.c +40 -33
- data/vendor/libgit2/src/fetchhead.h +5 -4
- data/vendor/libgit2/src/filebuf.c +163 -61
- data/vendor/libgit2/src/filebuf.h +13 -7
- data/vendor/libgit2/src/fileops.c +549 -407
- data/vendor/libgit2/src/fileops.h +97 -106
- data/vendor/libgit2/src/filter.c +989 -46
- data/vendor/libgit2/src/filter.h +21 -70
- data/vendor/libgit2/src/fnmatch.c +67 -11
- data/vendor/libgit2/src/fnmatch.h +27 -7
- data/vendor/libgit2/src/global.c +257 -63
- data/vendor/libgit2/src/global.h +19 -0
- data/vendor/libgit2/src/graph.c +39 -23
- data/vendor/libgit2/src/hash/hash_collisiondetect.h +51 -0
- data/vendor/libgit2/src/hash/hash_common_crypto.h +61 -0
- data/vendor/libgit2/src/hash/hash_generic.c +3 -3
- data/vendor/libgit2/src/hash/hash_generic.h +10 -5
- data/vendor/libgit2/src/hash/hash_mbedtls.c +38 -0
- data/vendor/libgit2/src/hash/hash_mbedtls.h +24 -0
- data/vendor/libgit2/src/hash/hash_openssl.h +26 -8
- data/vendor/libgit2/src/hash/hash_win32.c +71 -43
- data/vendor/libgit2/src/hash/hash_win32.h +4 -3
- data/vendor/libgit2/src/hash/sha1dc/sha1.c +1900 -0
- data/vendor/libgit2/src/hash/sha1dc/sha1.h +110 -0
- data/vendor/libgit2/src/hash/sha1dc/ubc_check.c +372 -0
- data/vendor/libgit2/src/hash/sha1dc/ubc_check.h +52 -0
- data/vendor/libgit2/src/hash.c +0 -1
- data/vendor/libgit2/src/hash.h +13 -6
- data/vendor/libgit2/src/hashsig.c +121 -126
- data/vendor/libgit2/src/ident.c +129 -0
- data/vendor/libgit2/src/idxmap.c +153 -0
- data/vendor/libgit2/src/idxmap.h +41 -0
- data/vendor/libgit2/src/ignore.c +362 -123
- data/vendor/libgit2/src/ignore.h +16 -4
- data/vendor/libgit2/src/index.c +2131 -692
- data/vendor/libgit2/src/index.h +138 -6
- data/vendor/libgit2/src/indexer.c +866 -266
- data/vendor/libgit2/src/indexer.h +16 -0
- data/vendor/libgit2/src/integer.h +106 -0
- data/vendor/libgit2/src/iterator.c +1888 -967
- data/vendor/libgit2/src/iterator.h +130 -67
- data/vendor/libgit2/src/khash.h +43 -29
- data/vendor/libgit2/src/mailmap.c +485 -0
- data/vendor/libgit2/src/mailmap.h +35 -0
- data/vendor/libgit2/src/map.h +1 -1
- data/vendor/libgit2/src/merge.c +1679 -479
- data/vendor/libgit2/src/merge.h +89 -22
- data/vendor/libgit2/src/merge_driver.c +426 -0
- data/vendor/libgit2/src/merge_driver.h +62 -0
- data/vendor/libgit2/src/merge_file.c +238 -101
- data/vendor/libgit2/src/message.c +4 -28
- data/vendor/libgit2/src/message.h +3 -1
- data/vendor/libgit2/src/mwindow.c +123 -15
- data/vendor/libgit2/src/mwindow.h +10 -1
- data/vendor/libgit2/src/netops.c +178 -499
- data/vendor/libgit2/src/netops.h +51 -27
- data/vendor/libgit2/src/notes.c +251 -94
- data/vendor/libgit2/src/notes.h +5 -2
- data/vendor/libgit2/src/object.c +253 -67
- data/vendor/libgit2/src/object.h +40 -2
- data/vendor/libgit2/src/object_api.c +30 -11
- data/vendor/libgit2/src/odb.c +765 -201
- data/vendor/libgit2/src/odb.h +40 -8
- data/vendor/libgit2/src/odb_loose.c +560 -346
- data/vendor/libgit2/src/odb_mempack.c +185 -0
- data/vendor/libgit2/src/odb_pack.c +117 -73
- data/vendor/libgit2/src/offmap.c +113 -0
- data/vendor/libgit2/src/offmap.h +32 -42
- data/vendor/libgit2/src/oid.c +45 -25
- data/vendor/libgit2/src/oid.h +26 -8
- data/vendor/libgit2/src/oidarray.c +34 -0
- data/vendor/libgit2/src/oidarray.h +20 -0
- data/vendor/libgit2/src/oidmap.c +125 -0
- data/vendor/libgit2/src/oidmap.h +30 -17
- data/vendor/libgit2/src/pack-objects.c +688 -265
- data/vendor/libgit2/src/pack-objects.h +27 -13
- data/vendor/libgit2/src/pack.c +418 -202
- data/vendor/libgit2/src/pack.h +25 -16
- data/vendor/libgit2/src/parse.c +124 -0
- data/vendor/libgit2/src/parse.h +61 -0
- data/vendor/libgit2/src/patch.c +223 -0
- data/vendor/libgit2/src/patch.h +68 -0
- data/vendor/libgit2/src/patch_generate.c +901 -0
- data/vendor/libgit2/src/patch_generate.h +69 -0
- data/vendor/libgit2/src/patch_parse.c +1136 -0
- data/vendor/libgit2/src/patch_parse.h +51 -0
- data/vendor/libgit2/src/path.c +1247 -241
- data/vendor/libgit2/src/path.h +353 -57
- data/vendor/libgit2/src/pathspec.c +586 -58
- data/vendor/libgit2/src/pathspec.h +37 -15
- data/vendor/libgit2/src/pool.c +134 -221
- data/vendor/libgit2/src/pool.h +38 -50
- data/vendor/libgit2/src/posix.c +76 -10
- data/vendor/libgit2/src/posix.h +74 -32
- data/vendor/libgit2/src/pqueue.c +79 -117
- data/vendor/libgit2/src/pqueue.h +38 -82
- data/vendor/libgit2/src/proxy.c +39 -0
- data/vendor/libgit2/src/proxy.h +17 -0
- data/vendor/libgit2/src/push.c +178 -279
- data/vendor/libgit2/src/push.h +93 -4
- data/vendor/libgit2/src/reader.c +265 -0
- data/vendor/libgit2/src/reader.h +107 -0
- data/vendor/libgit2/src/rebase.c +1364 -0
- data/vendor/libgit2/src/refdb.c +74 -19
- data/vendor/libgit2/src/refdb.h +16 -3
- data/vendor/libgit2/src/refdb_fs.c +1472 -603
- data/vendor/libgit2/src/refdb_fs.h +4 -0
- data/vendor/libgit2/src/reflog.c +40 -330
- data/vendor/libgit2/src/reflog.h +8 -2
- data/vendor/libgit2/src/refs.c +641 -225
- data/vendor/libgit2/src/refs.h +53 -6
- data/vendor/libgit2/src/refspec.c +175 -62
- data/vendor/libgit2/src/refspec.h +10 -25
- data/vendor/libgit2/src/remote.c +1741 -723
- data/vendor/libgit2/src/remote.h +17 -5
- data/vendor/libgit2/src/repository.c +1505 -421
- data/vendor/libgit2/src/repository.h +95 -15
- data/vendor/libgit2/src/reset.c +63 -26
- data/vendor/libgit2/src/revert.c +232 -0
- data/vendor/libgit2/src/revparse.c +94 -80
- data/vendor/libgit2/src/revwalk.c +427 -194
- data/vendor/libgit2/src/revwalk.h +14 -5
- data/vendor/libgit2/src/settings.c +290 -0
- data/vendor/libgit2/src/sha1_lookup.c +16 -159
- data/vendor/libgit2/src/sha1_lookup.h +5 -4
- data/vendor/libgit2/src/signature.c +138 -26
- data/vendor/libgit2/src/signature.h +5 -0
- data/vendor/libgit2/src/sortedcache.c +395 -0
- data/vendor/libgit2/src/sortedcache.h +180 -0
- data/vendor/libgit2/src/stash.c +629 -168
- data/vendor/libgit2/src/status.c +125 -75
- data/vendor/libgit2/src/status.h +4 -2
- data/vendor/libgit2/src/stdalloc.c +120 -0
- data/vendor/libgit2/src/stdalloc.h +17 -0
- data/vendor/libgit2/src/stream.h +86 -0
- data/vendor/libgit2/src/streams/mbedtls.c +483 -0
- data/vendor/libgit2/src/streams/mbedtls.h +23 -0
- data/vendor/libgit2/src/streams/openssl.c +789 -0
- data/vendor/libgit2/src/streams/openssl.h +23 -0
- data/vendor/libgit2/src/streams/registry.c +118 -0
- data/vendor/libgit2/src/streams/registry.h +19 -0
- data/vendor/libgit2/src/streams/socket.c +235 -0
- data/vendor/libgit2/src/streams/socket.h +23 -0
- data/vendor/libgit2/src/streams/stransport.c +323 -0
- data/vendor/libgit2/src/streams/stransport.h +21 -0
- data/vendor/libgit2/src/streams/tls.c +73 -0
- data/vendor/libgit2/src/streams/tls.h +31 -0
- data/vendor/libgit2/src/strmap.c +147 -0
- data/vendor/libgit2/src/strmap.h +46 -51
- data/vendor/libgit2/src/strnlen.h +24 -0
- data/vendor/libgit2/src/submodule.c +1633 -877
- data/vendor/libgit2/src/submodule.h +83 -21
- data/vendor/libgit2/src/sysdir.c +355 -0
- data/vendor/libgit2/src/sysdir.h +119 -0
- data/vendor/libgit2/src/tag.c +87 -62
- data/vendor/libgit2/src/tag.h +4 -1
- data/vendor/libgit2/src/thread-utils.c +3 -0
- data/vendor/libgit2/src/thread-utils.h +71 -35
- data/vendor/libgit2/src/trace.c +4 -4
- data/vendor/libgit2/src/trace.h +11 -3
- data/vendor/libgit2/src/trailer.c +416 -0
- data/vendor/libgit2/src/transaction.c +382 -0
- data/vendor/libgit2/src/transaction.h +14 -0
- data/vendor/libgit2/src/transport.c +133 -67
- data/vendor/libgit2/src/transports/auth.c +75 -0
- data/vendor/libgit2/src/transports/auth.h +64 -0
- data/vendor/libgit2/src/transports/auth_negotiate.c +277 -0
- data/vendor/libgit2/src/transports/auth_negotiate.h +27 -0
- data/vendor/libgit2/src/transports/cred.c +296 -68
- data/vendor/libgit2/src/transports/cred.h +16 -0
- data/vendor/libgit2/src/transports/cred_helpers.c +4 -0
- data/vendor/libgit2/src/transports/git.c +108 -90
- data/vendor/libgit2/src/transports/http.c +803 -258
- data/vendor/libgit2/src/transports/http.h +25 -0
- data/vendor/libgit2/src/transports/local.c +265 -169
- data/vendor/libgit2/src/transports/smart.c +255 -45
- data/vendor/libgit2/src/transports/smart.h +42 -22
- data/vendor/libgit2/src/transports/smart_pkt.c +250 -159
- data/vendor/libgit2/src/transports/smart_protocol.c +414 -196
- data/vendor/libgit2/src/transports/ssh.c +645 -236
- data/vendor/libgit2/src/transports/ssh.h +14 -0
- data/vendor/libgit2/src/transports/winhttp.c +809 -353
- data/vendor/libgit2/src/tree-cache.c +138 -52
- data/vendor/libgit2/src/tree-cache.h +14 -7
- data/vendor/libgit2/src/tree.c +620 -259
- data/vendor/libgit2/src/tree.h +12 -19
- data/vendor/libgit2/src/tsort.c +3 -2
- data/vendor/libgit2/src/unix/map.c +25 -7
- data/vendor/libgit2/src/unix/posix.h +77 -12
- data/vendor/libgit2/src/unix/pthread.h +56 -0
- data/vendor/libgit2/src/unix/realpath.c +12 -8
- data/vendor/libgit2/src/userdiff.h +208 -0
- data/vendor/libgit2/src/util.c +349 -165
- data/vendor/libgit2/src/util.h +167 -85
- data/vendor/libgit2/src/varint.c +43 -0
- data/vendor/libgit2/src/varint.h +17 -0
- data/vendor/libgit2/src/vector.c +156 -33
- data/vendor/libgit2/src/vector.h +41 -5
- data/vendor/libgit2/src/win32/dir.c +22 -42
- data/vendor/libgit2/src/win32/dir.h +7 -5
- data/vendor/libgit2/src/win32/error.c +6 -32
- data/vendor/libgit2/src/win32/error.h +4 -2
- data/vendor/libgit2/src/win32/findfile.c +62 -69
- data/vendor/libgit2/src/win32/findfile.h +5 -13
- data/vendor/libgit2/src/win32/git2.rc +44 -0
- data/vendor/libgit2/src/win32/map.c +39 -11
- data/vendor/libgit2/src/win32/mingw-compat.h +10 -11
- data/vendor/libgit2/src/win32/msvc-compat.h +10 -33
- data/vendor/libgit2/src/win32/path_w32.c +476 -0
- data/vendor/libgit2/src/win32/path_w32.h +104 -0
- data/vendor/libgit2/src/win32/posix.h +35 -30
- data/vendor/libgit2/src/win32/posix_w32.c +659 -327
- data/vendor/libgit2/src/win32/precompiled.h +7 -2
- data/vendor/libgit2/src/win32/reparse.h +57 -0
- data/vendor/libgit2/src/win32/thread.c +258 -0
- data/vendor/libgit2/src/win32/thread.h +64 -0
- data/vendor/libgit2/src/win32/utf-conv.c +127 -62
- data/vendor/libgit2/src/win32/utf-conv.h +47 -6
- data/vendor/libgit2/src/win32/version.h +21 -4
- data/vendor/libgit2/src/win32/w32_buffer.c +54 -0
- data/vendor/libgit2/src/win32/w32_buffer.h +20 -0
- data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.c +438 -0
- data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.h +129 -0
- data/vendor/libgit2/src/win32/w32_stack.c +193 -0
- data/vendor/libgit2/src/win32/w32_stack.h +140 -0
- data/vendor/libgit2/src/win32/w32_util.c +95 -0
- data/vendor/libgit2/src/win32/w32_util.h +170 -0
- data/vendor/libgit2/src/win32/win32-compat.h +52 -0
- data/vendor/libgit2/src/worktree.c +578 -0
- data/vendor/libgit2/src/worktree.h +39 -0
- data/vendor/libgit2/src/xdiff/xdiff.h +33 -18
- data/vendor/libgit2/src/xdiff/xdiffi.c +578 -88
- data/vendor/libgit2/src/xdiff/xdiffi.h +3 -2
- data/vendor/libgit2/src/xdiff/xemit.c +106 -45
- data/vendor/libgit2/src/xdiff/xemit.h +3 -3
- data/vendor/libgit2/src/xdiff/xhistogram.c +5 -4
- data/vendor/libgit2/src/xdiff/xinclude.h +3 -2
- data/vendor/libgit2/src/xdiff/xmacros.h +2 -2
- data/vendor/libgit2/src/xdiff/xmerge.c +167 -48
- data/vendor/libgit2/src/xdiff/xpatience.c +42 -10
- data/vendor/libgit2/src/xdiff/xprepare.c +14 -14
- data/vendor/libgit2/src/xdiff/xprepare.h +2 -2
- data/vendor/libgit2/src/xdiff/xtypes.h +2 -2
- data/vendor/libgit2/src/xdiff/xutils.c +60 -56
- data/vendor/libgit2/src/xdiff/xutils.h +3 -5
- data/vendor/libgit2/src/zstream.c +205 -0
- data/vendor/libgit2/src/zstream.h +53 -0
- metadata +281 -233
- data/Rakefile +0 -61
- data/ext/rugged/rugged_diff_patch.c +0 -169
- data/lib/rugged/diff/patch.rb +0 -28
- data/test/blob_test.rb +0 -341
- data/test/branch_test.rb +0 -199
- data/test/commit_test.rb +0 -104
- data/test/config_test.rb +0 -45
- data/test/coverage/cover.rb +0 -133
- data/test/diff_test.rb +0 -777
- data/test/errors_test.rb +0 -34
- 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/archive.tar.gz +0 -0
- data/test/fixtures/attr/attr0 +0 -1
- data/test/fixtures/attr/attr1 +0 -29
- data/test/fixtures/attr/attr2 +0 -21
- data/test/fixtures/attr/attr3 +0 -4
- data/test/fixtures/attr/binfile +0 -1
- data/test/fixtures/attr/dir/file +0 -0
- data/test/fixtures/attr/file +0 -1
- data/test/fixtures/attr/gitattributes +0 -29
- data/test/fixtures/attr/gitignore +0 -2
- data/test/fixtures/attr/ign +0 -1
- data/test/fixtures/attr/macro_bad +0 -1
- data/test/fixtures/attr/macro_test +0 -1
- data/test/fixtures/attr/root_test1 +0 -1
- data/test/fixtures/attr/root_test2 +0 -6
- data/test/fixtures/attr/root_test3 +0 -19
- data/test/fixtures/attr/root_test4.txt +0 -14
- data/test/fixtures/attr/sub/abc +0 -37
- data/test/fixtures/attr/sub/dir/file +0 -0
- data/test/fixtures/attr/sub/file +0 -1
- data/test/fixtures/attr/sub/ign/file +0 -1
- data/test/fixtures/attr/sub/ign/sub/file +0 -1
- data/test/fixtures/attr/sub/sub/dir +0 -0
- data/test/fixtures/attr/sub/sub/file +0 -1
- data/test/fixtures/attr/sub/sub/subsub.txt +0 -1
- data/test/fixtures/attr/sub/subdir_test1 +0 -2
- data/test/fixtures/attr/sub/subdir_test2.txt +0 -1
- data/test/fixtures/diff/another.txt +0 -38
- data/test/fixtures/diff/readme.txt +0 -36
- data/test/fixtures/mergedrepo/conflicts-one.txt +0 -5
- data/test/fixtures/mergedrepo/conflicts-two.txt +0 -5
- data/test/fixtures/mergedrepo/one.txt +0 -10
- data/test/fixtures/mergedrepo/two.txt +0 -12
- data/test/fixtures/status/current_file +0 -1
- data/test/fixtures/status/ignored_file +0 -1
- data/test/fixtures/status/modified_file +0 -2
- data/test/fixtures/status/new_file +0 -1
- data/test/fixtures/status/staged_changes +0 -2
- data/test/fixtures/status/staged_changes_modified_file +0 -3
- data/test/fixtures/status/staged_delete_modified_file +0 -1
- data/test/fixtures/status/staged_new_file +0 -1
- data/test/fixtures/status/staged_new_file_modified_file +0 -2
- data/test/fixtures/status/subdir/current_file +0 -1
- data/test/fixtures/status/subdir/modified_file +0 -2
- data/test/fixtures/status/subdir/new_file +0 -1
- data/test/fixtures/status/subdir.txt +0 -2
- data/test/fixtures/status//350/277/231 +0 -1
- data/test/fixtures/testrepo.git/HEAD +0 -1
- data/test/fixtures/testrepo.git/config +0 -13
- data/test/fixtures/testrepo.git/description +0 -1
- data/test/fixtures/testrepo.git/index +0 -0
- data/test/fixtures/testrepo.git/info/exclude +0 -6
- data/test/fixtures/testrepo.git/logs/HEAD +0 -3
- data/test/fixtures/testrepo.git/logs/refs/heads/master +0 -3
- data/test/fixtures/testrepo.git/logs/refs/notes/commits +0 -1
- data/test/fixtures/testrepo.git/objects/0c/37a5391bbff43c37f0d0371823a5509eed5b1d +0 -0
- data/test/fixtures/testrepo.git/objects/13/85f264afb75a56a5bec74243be9b367ba4ca08 +0 -0
- data/test/fixtures/testrepo.git/objects/18/1037049a54a1eb5fab404658a3a250b44335d7 +0 -0
- data/test/fixtures/testrepo.git/objects/18/10dff58d8a660512d4832e740f692884338ccd +0 -0
- data/test/fixtures/testrepo.git/objects/2d/2eff63372b08adf0a9eb84109ccf7d19e2f3a2 +0 -0
- data/test/fixtures/testrepo.git/objects/36/060c58702ed4c2a40832c51758d5344201d89a +0 -2
- data/test/fixtures/testrepo.git/objects/44/1034f860c1d5d90e4188d11ae0d325176869a8 +0 -1
- data/test/fixtures/testrepo.git/objects/45/b983be36b73c0788dc9cbcb76cbb80fc7bb057 +0 -0
- data/test/fixtures/testrepo.git/objects/4a/202b346bb0fb0db7eff3cffeb3c70babbd2045 +0 -2
- data/test/fixtures/testrepo.git/objects/5b/5b025afb0b4c913b4c338a42934a3863bf3644 +0 -2
- data/test/fixtures/testrepo.git/objects/60/d415052a33de2150bf68757f6461df4f563ae4 +0 -0
- data/test/fixtures/testrepo.git/objects/61/9f9935957e010c419cb9d15621916ddfcc0b96 +0 -0
- data/test/fixtures/testrepo.git/objects/68/8a8f4ef7496901d15322972f96e212a9e466cc +0 -1
- data/test/fixtures/testrepo.git/objects/75/057dd4114e74cca1d750d0aee1647c903cb60a +0 -0
- data/test/fixtures/testrepo.git/objects/77/71329dfa3002caf8c61a0ceb62a31d09023f37 +0 -0
- data/test/fixtures/testrepo.git/objects/81/4889a078c031f61ed08ab5fa863aea9314344d +0 -0
- data/test/fixtures/testrepo.git/objects/84/96071c1b46c854b31185ea97743be6a8774479 +0 -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/9f/d738e8f7967c078dceed8190330fc8648ee56a +0 -3
- data/test/fixtures/testrepo.git/objects/a4/a7dce85cf63874e984719f4fdd239f5145052f +0 -2
- data/test/fixtures/testrepo.git/objects/a7/1586c1dfe8a71c6cbf6c129f404c5642ff31bd +0 -0
- data/test/fixtures/testrepo.git/objects/a8/233120f6ad708f843d861ce2b7228ec4e3dec6 +0 -0
- data/test/fixtures/testrepo.git/objects/b7/4713326bc972cc15751ed504dca6f6f3b91f7a +0 -3
- data/test/fixtures/testrepo.git/objects/be/3563ae3f795b2b4353bcce3a527ad0a4f7f644 +0 -3
- data/test/fixtures/testrepo.git/objects/c4/7800c7266a2be04c571c04d5a6614691ea99bd +0 -3
- data/test/fixtures/testrepo.git/objects/c4/dc1555e4d4fa0e0c9c3fc46734c7c35b3ce90b +0 -0
- data/test/fixtures/testrepo.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
- data/test/fixtures/testrepo.git/objects/f6/0079018b664e4e79329a7ef9559c8d9e0378d1 +0 -0
- data/test/fixtures/testrepo.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 +0 -0
- data/test/fixtures/testrepo.git/objects/fd/093bff70906175335656e6ce6ae05783708765 +0 -0
- data/test/fixtures/testrepo.git/objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx +0 -0
- data/test/fixtures/testrepo.git/objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.pack +0 -0
- data/test/fixtures/testrepo.git/packed-refs +0 -2
- data/test/fixtures/testrepo.git/refs/heads/master +0 -1
- data/test/fixtures/testrepo.git/refs/notes/commits +0 -1
- data/test/fixtures/testrepo.git/refs/tags/v0.9 +0 -1
- data/test/fixtures/testrepo.git/refs/tags/v1.0 +0 -1
- data/test/fixtures/text_file.md +0 -464
- data/test/fixtures/unsymlinked.git/HEAD +0 -1
- data/test/fixtures/unsymlinked.git/config +0 -6
- data/test/fixtures/unsymlinked.git/description +0 -1
- data/test/fixtures/unsymlinked.git/info/exclude +0 -2
- data/test/fixtures/unsymlinked.git/objects/08/8b64704e0d6b8bd061dea879418cb5442a3fbf +0 -0
- data/test/fixtures/unsymlinked.git/objects/13/a5e939bca25940c069fd2169d993dba328e30b +0 -0
- data/test/fixtures/unsymlinked.git/objects/19/bf568e59e3a0b363cafb4106226e62d4a4c41c +0 -0
- data/test/fixtures/unsymlinked.git/objects/58/1fadd35b4cf320d102a152f918729011604773 +0 -0
- data/test/fixtures/unsymlinked.git/objects/5c/87b6791e8b13da658a14d1ef7e09b5dc3bac8c +0 -0
- data/test/fixtures/unsymlinked.git/objects/6f/e5f5398af85fb3de8a6aba0339b6d3bfa26a27 +0 -0
- data/test/fixtures/unsymlinked.git/objects/7f/ccd75616ec188b8f1b23d67506a334cc34a49d +0 -0
- data/test/fixtures/unsymlinked.git/objects/80/6999882bf91d24241e4077906b9017605eb1f3 +0 -0
- data/test/fixtures/unsymlinked.git/objects/83/7d176303c5005505ec1e4a30231c40930c0230 +0 -0
- data/test/fixtures/unsymlinked.git/objects/a8/595ccca04f40818ae0155c8f9c77a230e597b6 +0 -2
- data/test/fixtures/unsymlinked.git/objects/cf/8f1cf5cce859c438d6cc067284cb5e161206e7 +0 -0
- data/test/fixtures/unsymlinked.git/objects/d5/278d05c8607ec420bfee4cf219fbc0eeebfd6a +0 -0
- data/test/fixtures/unsymlinked.git/objects/f4/e16fb76536591a41454194058d048d8e4dd2e9 +0 -0
- data/test/fixtures/unsymlinked.git/objects/f9/e65619d93fdf2673882e0a261c5e93b1a84006 +0 -0
- data/test/fixtures/unsymlinked.git/refs/heads/exe-file +0 -1
- data/test/fixtures/unsymlinked.git/refs/heads/master +0 -1
- data/test/fixtures/unsymlinked.git/refs/heads/reg-file +0 -1
- data/test/index_test.rb +0 -333
- data/test/lib_test.rb +0 -127
- data/test/note_test.rb +0 -158
- data/test/object_test.rb +0 -43
- data/test/reference_test.rb +0 -207
- data/test/remote_test.rb +0 -324
- data/test/repo_pack_test.rb +0 -24
- data/test/repo_reset_test.rb +0 -82
- data/test/repo_test.rb +0 -402
- data/test/tag_test.rb +0 -68
- data/test/test_helper.rb +0 -92
- data/test/tree_test.rb +0 -91
- data/test/walker_test.rb +0 -88
- data/vendor/libgit2/Makefile.embed +0 -42
- data/vendor/libgit2/include/git2/push.h +0 -131
- data/vendor/libgit2/include/git2/threads.h +0 -50
- data/vendor/libgit2/src/amiga/map.c +0 -48
- data/vendor/libgit2/src/bswap.h +0 -97
- data/vendor/libgit2/src/compress.c +0 -53
- data/vendor/libgit2/src/config_file.h +0 -60
- data/vendor/libgit2/src/delta-apply.c +0 -134
- data/vendor/libgit2/src/delta-apply.h +0 -50
- data/vendor/libgit2/src/diff_patch.c +0 -995
- data/vendor/libgit2/src/diff_patch.h +0 -46
- data/vendor/libgit2/src/hashsig.h +0 -72
- data/vendor/libgit2/src/merge_file.h +0 -71
- data/vendor/libgit2/src/win32/pthread.c +0 -144
- data/vendor/libgit2/src/win32/pthread.h +0 -50
data/vendor/libgit2/src/merge.c
CHANGED
@@ -5,27 +5,35 @@
|
|
5
5
|
* a Linking Exception. For full terms see the included COPYING file.
|
6
6
|
*/
|
7
7
|
|
8
|
-
#include "
|
8
|
+
#include "merge.h"
|
9
|
+
|
9
10
|
#include "posix.h"
|
10
11
|
#include "buffer.h"
|
11
12
|
#include "repository.h"
|
12
13
|
#include "revwalk.h"
|
13
14
|
#include "commit_list.h"
|
14
|
-
#include "merge.h"
|
15
15
|
#include "path.h"
|
16
16
|
#include "refs.h"
|
17
17
|
#include "object.h"
|
18
18
|
#include "iterator.h"
|
19
19
|
#include "refs.h"
|
20
20
|
#include "diff.h"
|
21
|
+
#include "diff_generate.h"
|
22
|
+
#include "diff_tform.h"
|
21
23
|
#include "checkout.h"
|
22
24
|
#include "tree.h"
|
23
|
-
#include "merge_file.h"
|
24
25
|
#include "blob.h"
|
25
|
-
#include "hashsig.h"
|
26
26
|
#include "oid.h"
|
27
27
|
#include "index.h"
|
28
28
|
#include "filebuf.h"
|
29
|
+
#include "config.h"
|
30
|
+
#include "oidarray.h"
|
31
|
+
#include "annotated_commit.h"
|
32
|
+
#include "commit.h"
|
33
|
+
#include "oidarray.h"
|
34
|
+
#include "merge_driver.h"
|
35
|
+
#include "oidmap.h"
|
36
|
+
#include "array.h"
|
29
37
|
|
30
38
|
#include "git2/types.h"
|
31
39
|
#include "git2/repository.h"
|
@@ -38,9 +46,14 @@
|
|
38
46
|
#include "git2/signature.h"
|
39
47
|
#include "git2/config.h"
|
40
48
|
#include "git2/tree.h"
|
49
|
+
#include "git2/oidarray.h"
|
50
|
+
#include "git2/annotated_commit.h"
|
41
51
|
#include "git2/sys/index.h"
|
52
|
+
#include "git2/sys/hashsig.h"
|
42
53
|
|
43
54
|
#define GIT_MERGE_INDEX_ENTRY_EXISTS(X) ((X).mode != 0)
|
55
|
+
#define GIT_MERGE_INDEX_ENTRY_ISFILE(X) S_ISREG((X).mode)
|
56
|
+
|
44
57
|
|
45
58
|
typedef enum {
|
46
59
|
TREE_IDX_ANCESTOR = 0,
|
@@ -55,22 +68,19 @@ struct merge_diff_df_data {
|
|
55
68
|
git_merge_diff *prev_conflict;
|
56
69
|
};
|
57
70
|
|
58
|
-
|
59
71
|
/* Merge base computation */
|
60
72
|
|
61
|
-
int
|
73
|
+
int merge_bases_many(git_commit_list **out, git_revwalk **walk_out, git_repository *repo, size_t length, const git_oid input_array[])
|
62
74
|
{
|
63
|
-
git_revwalk *walk;
|
75
|
+
git_revwalk *walk = NULL;
|
64
76
|
git_vector list;
|
65
77
|
git_commit_list *result = NULL;
|
78
|
+
git_commit_list_node *commit;
|
66
79
|
int error = -1;
|
67
80
|
unsigned int i;
|
68
|
-
git_commit_list_node *commit;
|
69
|
-
|
70
|
-
assert(out && repo && input_array);
|
71
81
|
|
72
82
|
if (length < 2) {
|
73
|
-
|
83
|
+
git_error_set(GIT_ERROR_INVALID, "at least two commits are required to find an ancestor");
|
74
84
|
return -1;
|
75
85
|
}
|
76
86
|
|
@@ -78,41 +88,121 @@ int git_merge_base_many(git_oid *out, git_repository *repo, const git_oid input_
|
|
78
88
|
return -1;
|
79
89
|
|
80
90
|
if (git_revwalk_new(&walk, repo) < 0)
|
81
|
-
goto
|
91
|
+
goto on_error;
|
82
92
|
|
83
93
|
for (i = 1; i < length; i++) {
|
84
94
|
commit = git_revwalk__commit_lookup(walk, &input_array[i]);
|
85
95
|
if (commit == NULL)
|
86
|
-
goto
|
96
|
+
goto on_error;
|
87
97
|
|
88
98
|
git_vector_insert(&list, commit);
|
89
99
|
}
|
90
100
|
|
91
101
|
commit = git_revwalk__commit_lookup(walk, &input_array[0]);
|
92
102
|
if (commit == NULL)
|
93
|
-
goto
|
103
|
+
goto on_error;
|
94
104
|
|
95
105
|
if (git_merge__bases_many(&result, walk, commit, &list) < 0)
|
96
|
-
goto
|
106
|
+
goto on_error;
|
97
107
|
|
98
108
|
if (!result) {
|
99
|
-
|
109
|
+
git_error_set(GIT_ERROR_MERGE, "no merge base found");
|
100
110
|
error = GIT_ENOTFOUND;
|
101
|
-
goto
|
111
|
+
goto on_error;
|
102
112
|
}
|
103
113
|
|
114
|
+
*out = result;
|
115
|
+
*walk_out = walk;
|
116
|
+
|
117
|
+
git_vector_free(&list);
|
118
|
+
return 0;
|
119
|
+
|
120
|
+
on_error:
|
121
|
+
git_vector_free(&list);
|
122
|
+
git_revwalk_free(walk);
|
123
|
+
return error;
|
124
|
+
}
|
125
|
+
|
126
|
+
int git_merge_base_many(git_oid *out, git_repository *repo, size_t length, const git_oid input_array[])
|
127
|
+
{
|
128
|
+
git_revwalk *walk;
|
129
|
+
git_commit_list *result = NULL;
|
130
|
+
int error = 0;
|
131
|
+
|
132
|
+
assert(out && repo && input_array);
|
133
|
+
|
134
|
+
if ((error = merge_bases_many(&result, &walk, repo, length, input_array)) < 0)
|
135
|
+
return error;
|
136
|
+
|
104
137
|
git_oid_cpy(out, &result->item->oid);
|
105
138
|
|
106
|
-
|
139
|
+
git_commit_list_free(&result);
|
140
|
+
git_revwalk_free(walk);
|
141
|
+
|
142
|
+
return 0;
|
143
|
+
}
|
144
|
+
|
145
|
+
int git_merge_bases_many(git_oidarray *out, git_repository *repo, size_t length, const git_oid input_array[])
|
146
|
+
{
|
147
|
+
git_revwalk *walk;
|
148
|
+
git_commit_list *list, *result = NULL;
|
149
|
+
int error = 0;
|
150
|
+
git_array_oid_t array;
|
151
|
+
|
152
|
+
assert(out && repo && input_array);
|
153
|
+
|
154
|
+
if ((error = merge_bases_many(&result, &walk, repo, length, input_array)) < 0)
|
155
|
+
return error;
|
156
|
+
|
157
|
+
git_array_init(array);
|
158
|
+
|
159
|
+
list = result;
|
160
|
+
while (list) {
|
161
|
+
git_oid *id = git_array_alloc(array);
|
162
|
+
if (id == NULL) {
|
163
|
+
error = -1;
|
164
|
+
goto cleanup;
|
165
|
+
}
|
166
|
+
|
167
|
+
git_oid_cpy(id, &list->item->oid);
|
168
|
+
list = list->next;
|
169
|
+
}
|
170
|
+
|
171
|
+
git_oidarray__from_array(out, &array);
|
107
172
|
|
108
173
|
cleanup:
|
109
174
|
git_commit_list_free(&result);
|
110
175
|
git_revwalk_free(walk);
|
111
|
-
|
176
|
+
|
112
177
|
return error;
|
113
178
|
}
|
114
179
|
|
115
|
-
int
|
180
|
+
int git_merge_base_octopus(git_oid *out, git_repository *repo, size_t length, const git_oid input_array[])
|
181
|
+
{
|
182
|
+
git_oid result;
|
183
|
+
unsigned int i;
|
184
|
+
int error = -1;
|
185
|
+
|
186
|
+
assert(out && repo && input_array);
|
187
|
+
|
188
|
+
if (length < 2) {
|
189
|
+
git_error_set(GIT_ERROR_INVALID, "at least two commits are required to find an ancestor");
|
190
|
+
return -1;
|
191
|
+
}
|
192
|
+
|
193
|
+
result = input_array[0];
|
194
|
+
for (i = 1; i < length; i++) {
|
195
|
+
error = git_merge_base(&result, repo, &result, &input_array[i]);
|
196
|
+
if (error < 0)
|
197
|
+
return error;
|
198
|
+
}
|
199
|
+
|
200
|
+
*out = result;
|
201
|
+
|
202
|
+
return 0;
|
203
|
+
}
|
204
|
+
|
205
|
+
static int merge_bases(git_commit_list **out, git_revwalk **walk_out, git_repository *repo, const git_oid *one, const git_oid *two)
|
116
206
|
{
|
117
207
|
git_revwalk *walk;
|
118
208
|
git_vector list;
|
@@ -142,27 +232,77 @@ int git_merge_base(git_oid *out, git_repository *repo, const git_oid *one, const
|
|
142
232
|
|
143
233
|
if (!result) {
|
144
234
|
git_revwalk_free(walk);
|
145
|
-
|
235
|
+
git_error_set(GIT_ERROR_MERGE, "no merge base found");
|
146
236
|
return GIT_ENOTFOUND;
|
147
237
|
}
|
148
238
|
|
239
|
+
*out = result;
|
240
|
+
*walk_out = walk;
|
241
|
+
|
242
|
+
return 0;
|
243
|
+
|
244
|
+
on_error:
|
245
|
+
git_revwalk_free(walk);
|
246
|
+
return -1;
|
247
|
+
|
248
|
+
}
|
249
|
+
|
250
|
+
int git_merge_base(git_oid *out, git_repository *repo, const git_oid *one, const git_oid *two)
|
251
|
+
{
|
252
|
+
int error;
|
253
|
+
git_revwalk *walk;
|
254
|
+
git_commit_list *result;
|
255
|
+
|
256
|
+
if ((error = merge_bases(&result, &walk, repo, one, two)) < 0)
|
257
|
+
return error;
|
258
|
+
|
149
259
|
git_oid_cpy(out, &result->item->oid);
|
150
260
|
git_commit_list_free(&result);
|
151
261
|
git_revwalk_free(walk);
|
152
262
|
|
263
|
+
return 0;
|
264
|
+
}
|
265
|
+
|
266
|
+
int git_merge_bases(git_oidarray *out, git_repository *repo, const git_oid *one, const git_oid *two)
|
267
|
+
{
|
268
|
+
int error;
|
269
|
+
git_revwalk *walk;
|
270
|
+
git_commit_list *result, *list;
|
271
|
+
git_array_oid_t array;
|
272
|
+
|
273
|
+
git_array_init(array);
|
274
|
+
|
275
|
+
if ((error = merge_bases(&result, &walk, repo, one, two)) < 0)
|
276
|
+
return error;
|
277
|
+
|
278
|
+
list = result;
|
279
|
+
while (list) {
|
280
|
+
git_oid *id = git_array_alloc(array);
|
281
|
+
if (id == NULL)
|
282
|
+
goto on_error;
|
283
|
+
|
284
|
+
git_oid_cpy(id, &list->item->oid);
|
285
|
+
list = list->next;
|
286
|
+
}
|
287
|
+
|
288
|
+
git_oidarray__from_array(out, &array);
|
289
|
+
git_commit_list_free(&result);
|
290
|
+
git_revwalk_free(walk);
|
291
|
+
|
153
292
|
return 0;
|
154
293
|
|
155
294
|
on_error:
|
295
|
+
git_commit_list_free(&result);
|
156
296
|
git_revwalk_free(walk);
|
157
297
|
return -1;
|
158
298
|
}
|
159
299
|
|
160
300
|
static int interesting(git_pqueue *list)
|
161
301
|
{
|
162
|
-
|
163
|
-
|
164
|
-
for (i =
|
165
|
-
git_commit_list_node *commit = list
|
302
|
+
size_t i;
|
303
|
+
|
304
|
+
for (i = 0; i < git_pqueue_size(list); i++) {
|
305
|
+
git_commit_list_node *commit = git_pqueue_get(list, i);
|
166
306
|
if ((commit->flags & STALE) == 0)
|
167
307
|
return 1;
|
168
308
|
}
|
@@ -170,24 +310,59 @@ static int interesting(git_pqueue *list)
|
|
170
310
|
return 0;
|
171
311
|
}
|
172
312
|
|
173
|
-
|
313
|
+
static void clear_commit_marks_1(git_commit_list **plist,
|
314
|
+
git_commit_list_node *commit, unsigned int mark)
|
174
315
|
{
|
175
|
-
|
316
|
+
while (commit) {
|
317
|
+
unsigned int i;
|
318
|
+
|
319
|
+
if (!(mark & commit->flags))
|
320
|
+
return;
|
321
|
+
|
322
|
+
commit->flags &= ~mark;
|
323
|
+
|
324
|
+
for (i = 1; i < commit->out_degree; i++) {
|
325
|
+
git_commit_list_node *p = commit->parents[i];
|
326
|
+
git_commit_list_insert(p, plist);
|
327
|
+
}
|
328
|
+
|
329
|
+
commit = commit->out_degree ? commit->parents[0] : NULL;
|
330
|
+
}
|
331
|
+
}
|
332
|
+
|
333
|
+
static void clear_commit_marks_many(git_vector *commits, unsigned int mark)
|
334
|
+
{
|
335
|
+
git_commit_list *list = NULL;
|
336
|
+
git_commit_list_node *c;
|
176
337
|
unsigned int i;
|
177
|
-
git_commit_list_node *two;
|
178
|
-
git_commit_list *result = NULL, *tmp = NULL;
|
179
|
-
git_pqueue list;
|
180
338
|
|
181
|
-
|
182
|
-
|
183
|
-
if (one == two)
|
184
|
-
return git_commit_list_insert(one, out) ? 0 : -1;
|
339
|
+
git_vector_foreach(commits, i, c) {
|
340
|
+
git_commit_list_insert(c, &list);
|
185
341
|
}
|
186
342
|
|
187
|
-
|
188
|
-
|
343
|
+
while (list)
|
344
|
+
clear_commit_marks_1(&list, git_commit_list_pop(&list), mark);
|
345
|
+
}
|
189
346
|
|
190
|
-
|
347
|
+
static void clear_commit_marks(git_commit_list_node *commit, unsigned int mark)
|
348
|
+
{
|
349
|
+
git_commit_list *list = NULL;
|
350
|
+
git_commit_list_insert(commit, &list);
|
351
|
+
while (list)
|
352
|
+
clear_commit_marks_1(&list, git_commit_list_pop(&list), mark);
|
353
|
+
}
|
354
|
+
|
355
|
+
static int paint_down_to_common(
|
356
|
+
git_commit_list **out, git_revwalk *walk, git_commit_list_node *one, git_vector *twos)
|
357
|
+
{
|
358
|
+
git_pqueue list;
|
359
|
+
git_commit_list *result = NULL;
|
360
|
+
git_commit_list_node *two;
|
361
|
+
|
362
|
+
int error;
|
363
|
+
unsigned int i;
|
364
|
+
|
365
|
+
if (git_pqueue_init(&list, 0, twos->length * 2, git_commit_list_time_cmp) < 0)
|
191
366
|
return -1;
|
192
367
|
|
193
368
|
one->flags |= PARENT1;
|
@@ -195,18 +370,22 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l
|
|
195
370
|
return -1;
|
196
371
|
|
197
372
|
git_vector_foreach(twos, i, two) {
|
198
|
-
git_commit_list_parse(walk, two)
|
373
|
+
if (git_commit_list_parse(walk, two) < 0)
|
374
|
+
return -1;
|
375
|
+
|
199
376
|
two->flags |= PARENT2;
|
377
|
+
|
200
378
|
if (git_pqueue_insert(&list, two) < 0)
|
201
379
|
return -1;
|
202
380
|
}
|
203
381
|
|
204
382
|
/* as long as there are non-STALE commits */
|
205
383
|
while (interesting(&list)) {
|
206
|
-
git_commit_list_node *commit;
|
384
|
+
git_commit_list_node *commit = git_pqueue_pop(&list);
|
207
385
|
int flags;
|
208
386
|
|
209
|
-
commit
|
387
|
+
if (commit == NULL)
|
388
|
+
break;
|
210
389
|
|
211
390
|
flags = commit->flags & (PARENT1 | PARENT2 | STALE);
|
212
391
|
if (flags == (PARENT1 | PARENT2)) {
|
@@ -234,26 +413,146 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l
|
|
234
413
|
}
|
235
414
|
|
236
415
|
git_pqueue_free(&list);
|
416
|
+
*out = result;
|
417
|
+
return 0;
|
418
|
+
}
|
419
|
+
|
420
|
+
static int remove_redundant(git_revwalk *walk, git_vector *commits)
|
421
|
+
{
|
422
|
+
git_vector work = GIT_VECTOR_INIT;
|
423
|
+
unsigned char *redundant;
|
424
|
+
unsigned int *filled_index;
|
425
|
+
unsigned int i, j;
|
426
|
+
int error = 0;
|
427
|
+
|
428
|
+
redundant = git__calloc(commits->length, 1);
|
429
|
+
GIT_ERROR_CHECK_ALLOC(redundant);
|
430
|
+
filled_index = git__calloc((commits->length - 1), sizeof(unsigned int));
|
431
|
+
GIT_ERROR_CHECK_ALLOC(filled_index);
|
432
|
+
|
433
|
+
for (i = 0; i < commits->length; ++i) {
|
434
|
+
if ((error = git_commit_list_parse(walk, commits->contents[i])) < 0)
|
435
|
+
goto done;
|
436
|
+
}
|
437
|
+
|
438
|
+
for (i = 0; i < commits->length; ++i) {
|
439
|
+
git_commit_list *common = NULL;
|
440
|
+
git_commit_list_node *commit = commits->contents[i];
|
441
|
+
|
442
|
+
if (redundant[i])
|
443
|
+
continue;
|
444
|
+
|
445
|
+
git_vector_clear(&work);
|
446
|
+
|
447
|
+
for (j = 0; j < commits->length; j++) {
|
448
|
+
if (i == j || redundant[j])
|
449
|
+
continue;
|
450
|
+
|
451
|
+
filled_index[work.length] = j;
|
452
|
+
if ((error = git_vector_insert(&work, commits->contents[j])) < 0)
|
453
|
+
goto done;
|
454
|
+
}
|
455
|
+
|
456
|
+
error = paint_down_to_common(&common, walk, commit, &work);
|
457
|
+
if (error < 0)
|
458
|
+
goto done;
|
459
|
+
|
460
|
+
if (commit->flags & PARENT2)
|
461
|
+
redundant[i] = 1;
|
462
|
+
|
463
|
+
for (j = 0; j < work.length; j++) {
|
464
|
+
git_commit_list_node *w = work.contents[j];
|
465
|
+
if (w->flags & PARENT1)
|
466
|
+
redundant[filled_index[j]] = 1;
|
467
|
+
}
|
468
|
+
|
469
|
+
clear_commit_marks(commit, ALL_FLAGS);
|
470
|
+
clear_commit_marks_many(&work, ALL_FLAGS);
|
471
|
+
|
472
|
+
git_commit_list_free(&common);
|
473
|
+
}
|
474
|
+
|
475
|
+
for (i = 0; i < commits->length; ++i) {
|
476
|
+
if (redundant[i])
|
477
|
+
commits->contents[i] = NULL;
|
478
|
+
}
|
479
|
+
|
480
|
+
done:
|
481
|
+
git__free(redundant);
|
482
|
+
git__free(filled_index);
|
483
|
+
git_vector_free(&work);
|
484
|
+
return error;
|
485
|
+
}
|
486
|
+
|
487
|
+
int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_list_node *one, git_vector *twos)
|
488
|
+
{
|
489
|
+
int error;
|
490
|
+
unsigned int i;
|
491
|
+
git_commit_list_node *two;
|
492
|
+
git_commit_list *result = NULL, *tmp = NULL;
|
493
|
+
|
494
|
+
/* If there's only the one commit, there can be no merge bases */
|
495
|
+
if (twos->length == 0) {
|
496
|
+
*out = NULL;
|
497
|
+
return 0;
|
498
|
+
}
|
499
|
+
|
500
|
+
/* if the commit is repeated, we have a our merge base already */
|
501
|
+
git_vector_foreach(twos, i, two) {
|
502
|
+
if (one == two)
|
503
|
+
return git_commit_list_insert(one, out) ? 0 : -1;
|
504
|
+
}
|
505
|
+
|
506
|
+
if (git_commit_list_parse(walk, one) < 0)
|
507
|
+
return -1;
|
508
|
+
|
509
|
+
error = paint_down_to_common(&result, walk, one, twos);
|
510
|
+
if (error < 0)
|
511
|
+
return error;
|
237
512
|
|
238
513
|
/* filter out any stale commits in the results */
|
239
514
|
tmp = result;
|
240
515
|
result = NULL;
|
241
516
|
|
242
517
|
while (tmp) {
|
243
|
-
|
244
|
-
if (!(
|
245
|
-
if (git_commit_list_insert_by_date(
|
518
|
+
git_commit_list_node *c = git_commit_list_pop(&tmp);
|
519
|
+
if (!(c->flags & STALE))
|
520
|
+
if (git_commit_list_insert_by_date(c, &result) == NULL)
|
246
521
|
return -1;
|
522
|
+
}
|
523
|
+
|
524
|
+
/*
|
525
|
+
* more than one merge base -- see if there are redundant merge
|
526
|
+
* bases and remove them
|
527
|
+
*/
|
528
|
+
if (result && result->next) {
|
529
|
+
git_vector redundant = GIT_VECTOR_INIT;
|
530
|
+
|
531
|
+
while (result)
|
532
|
+
git_vector_insert(&redundant, git_commit_list_pop(&result));
|
533
|
+
|
534
|
+
clear_commit_marks(one, ALL_FLAGS);
|
535
|
+
clear_commit_marks_many(twos, ALL_FLAGS);
|
536
|
+
|
537
|
+
if ((error = remove_redundant(walk, &redundant)) < 0) {
|
538
|
+
git_vector_free(&redundant);
|
539
|
+
return error;
|
540
|
+
}
|
541
|
+
|
542
|
+
git_vector_foreach(&redundant, i, two) {
|
543
|
+
if (two != NULL)
|
544
|
+
git_commit_list_insert_by_date(two, &result);
|
545
|
+
}
|
247
546
|
|
248
|
-
|
249
|
-
tmp = next;
|
547
|
+
git_vector_free(&redundant);
|
250
548
|
}
|
251
549
|
|
252
550
|
*out = result;
|
253
551
|
return 0;
|
254
552
|
}
|
255
553
|
|
256
|
-
int git_repository_mergehead_foreach(
|
554
|
+
int git_repository_mergehead_foreach(
|
555
|
+
git_repository *repo,
|
257
556
|
git_repository_mergehead_foreach_cb cb,
|
258
557
|
void *payload)
|
259
558
|
{
|
@@ -265,7 +564,7 @@ int git_repository_mergehead_foreach(git_repository *repo,
|
|
265
564
|
|
266
565
|
assert(repo && cb);
|
267
566
|
|
268
|
-
if ((error = git_buf_joinpath(&merge_head_path, repo->
|
567
|
+
if ((error = git_buf_joinpath(&merge_head_path, repo->gitdir,
|
269
568
|
GIT_MERGE_HEAD_FILE)) < 0)
|
270
569
|
return error;
|
271
570
|
|
@@ -277,7 +576,7 @@ int git_repository_mergehead_foreach(git_repository *repo,
|
|
277
576
|
|
278
577
|
while ((line = git__strsep(&buffer, "\n")) != NULL) {
|
279
578
|
if (strlen(line) != GIT_OID_HEXSZ) {
|
280
|
-
|
579
|
+
git_error_set(GIT_ERROR_INVALID, "unable to parse OID - invalid length");
|
281
580
|
error = -1;
|
282
581
|
goto cleanup;
|
283
582
|
}
|
@@ -285,8 +584,8 @@ int git_repository_mergehead_foreach(git_repository *repo,
|
|
285
584
|
if ((error = git_oid_fromstr(&oid, line)) < 0)
|
286
585
|
goto cleanup;
|
287
586
|
|
288
|
-
if (cb(&oid, payload)
|
289
|
-
error
|
587
|
+
if ((error = cb(&oid, payload)) != 0) {
|
588
|
+
git_error_set_after_callback(error);
|
290
589
|
goto cleanup;
|
291
590
|
}
|
292
591
|
|
@@ -294,14 +593,14 @@ int git_repository_mergehead_foreach(git_repository *repo,
|
|
294
593
|
}
|
295
594
|
|
296
595
|
if (*buffer) {
|
297
|
-
|
596
|
+
git_error_set(GIT_ERROR_MERGE, "no EOL at line %"PRIuZ, line_num);
|
298
597
|
error = -1;
|
299
598
|
goto cleanup;
|
300
599
|
}
|
301
600
|
|
302
601
|
cleanup:
|
303
|
-
|
304
|
-
|
602
|
+
git_buf_dispose(&merge_head_path);
|
603
|
+
git_buf_dispose(&merge_head_file);
|
305
604
|
|
306
605
|
return error;
|
307
606
|
}
|
@@ -314,7 +613,7 @@ GIT_INLINE(int) index_entry_cmp(const git_index_entry *a, const git_index_entry
|
|
314
613
|
return (b->path == NULL) ? 0 : 1;
|
315
614
|
|
316
615
|
if ((value = a->mode - b->mode) == 0 &&
|
317
|
-
(value = git_oid__cmp(&a->
|
616
|
+
(value = git_oid__cmp(&a->id, &b->id)) == 0)
|
318
617
|
value = strcmp(a->path, b->path);
|
319
618
|
|
320
619
|
return value;
|
@@ -445,7 +744,6 @@ static int merge_conflict_resolve_one_removed(
|
|
445
744
|
return error;
|
446
745
|
}
|
447
746
|
|
448
|
-
|
449
747
|
static int merge_conflict_resolve_one_renamed(
|
450
748
|
int *resolved,
|
451
749
|
git_merge_diff_list *diff_list,
|
@@ -476,12 +774,12 @@ static int merge_conflict_resolve_one_renamed(
|
|
476
774
|
conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED)
|
477
775
|
return 0;
|
478
776
|
|
479
|
-
ours_changed = (git_oid__cmp(&conflict->ancestor_entry.
|
480
|
-
theirs_changed = (git_oid__cmp(&conflict->ancestor_entry.
|
777
|
+
ours_changed = (git_oid__cmp(&conflict->ancestor_entry.id, &conflict->our_entry.id) != 0);
|
778
|
+
theirs_changed = (git_oid__cmp(&conflict->ancestor_entry.id, &conflict->their_entry.id) != 0);
|
481
779
|
|
482
780
|
/* if both are modified (and not to a common target) require a merge */
|
483
781
|
if (ours_changed && theirs_changed &&
|
484
|
-
git_oid__cmp(&conflict->our_entry.
|
782
|
+
git_oid__cmp(&conflict->our_entry.id, &conflict->their_entry.id) != 0)
|
485
783
|
return 0;
|
486
784
|
|
487
785
|
if ((merged = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry))) == NULL)
|
@@ -505,75 +803,163 @@ static int merge_conflict_resolve_one_renamed(
|
|
505
803
|
return error;
|
506
804
|
}
|
507
805
|
|
508
|
-
static
|
509
|
-
|
510
|
-
git_merge_diff_list *diff_list,
|
511
|
-
const git_merge_diff *conflict,
|
512
|
-
unsigned int automerge_flags)
|
806
|
+
static bool merge_conflict_can_resolve_contents(
|
807
|
+
const git_merge_diff *conflict)
|
513
808
|
{
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
git_merge_file_result result = GIT_MERGE_FILE_RESULT_INIT;
|
518
|
-
git_index_entry *index_entry;
|
519
|
-
git_odb *odb = NULL;
|
520
|
-
git_oid automerge_oid;
|
521
|
-
int error = 0;
|
522
|
-
|
523
|
-
assert(resolved && diff_list && conflict);
|
524
|
-
|
525
|
-
*resolved = 0;
|
526
|
-
|
527
|
-
if (automerge_flags == GIT_MERGE_AUTOMERGE_NONE)
|
528
|
-
return 0;
|
809
|
+
if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ||
|
810
|
+
!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry))
|
811
|
+
return false;
|
529
812
|
|
530
813
|
/* Reject D/F conflicts */
|
531
814
|
if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE)
|
532
|
-
return
|
815
|
+
return false;
|
816
|
+
|
817
|
+
/* Reject submodules. */
|
818
|
+
if (S_ISGITLINK(conflict->ancestor_entry.mode) ||
|
819
|
+
S_ISGITLINK(conflict->our_entry.mode) ||
|
820
|
+
S_ISGITLINK(conflict->their_entry.mode))
|
821
|
+
return false;
|
533
822
|
|
534
823
|
/* Reject link/file conflicts. */
|
535
|
-
if ((S_ISLNK(conflict->ancestor_entry.mode) ^
|
536
|
-
|
537
|
-
|
824
|
+
if ((S_ISLNK(conflict->ancestor_entry.mode) ^
|
825
|
+
S_ISLNK(conflict->our_entry.mode)) ||
|
826
|
+
(S_ISLNK(conflict->ancestor_entry.mode) ^
|
827
|
+
S_ISLNK(conflict->their_entry.mode)))
|
828
|
+
return false;
|
538
829
|
|
539
830
|
/* Reject name conflicts */
|
540
831
|
if (conflict->type == GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1 ||
|
541
832
|
conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED)
|
542
|
-
return
|
833
|
+
return false;
|
543
834
|
|
544
835
|
if ((conflict->our_status & GIT_DELTA_RENAMED) == GIT_DELTA_RENAMED &&
|
545
836
|
(conflict->their_status & GIT_DELTA_RENAMED) == GIT_DELTA_RENAMED &&
|
546
837
|
strcmp(conflict->ancestor_entry.path, conflict->their_entry.path) != 0)
|
547
|
-
return
|
838
|
+
return false;
|
548
839
|
|
549
|
-
|
550
|
-
|
551
|
-
(error = git_merge_file_input_from_index_entry(&ours, diff_list->repo, &conflict->our_entry)) < 0 ||
|
552
|
-
(error = git_merge_file_input_from_index_entry(&theirs, diff_list->repo, &conflict->their_entry)) < 0 ||
|
553
|
-
(error = git_merge_files(&result, &ancestor, &ours, &theirs, automerge_flags)) < 0 ||
|
554
|
-
!result.automergeable ||
|
555
|
-
(error = git_odb_write(&automerge_oid, odb, result.data, result.len, GIT_OBJ_BLOB)) < 0)
|
556
|
-
goto done;
|
840
|
+
return true;
|
841
|
+
}
|
557
842
|
|
558
|
-
|
559
|
-
|
843
|
+
static int merge_conflict_invoke_driver(
|
844
|
+
git_index_entry **out,
|
845
|
+
const char *name,
|
846
|
+
git_merge_driver *driver,
|
847
|
+
git_merge_diff_list *diff_list,
|
848
|
+
git_merge_driver_source *src)
|
849
|
+
{
|
850
|
+
git_index_entry *result;
|
851
|
+
git_buf buf = GIT_BUF_INIT;
|
852
|
+
const char *path;
|
853
|
+
uint32_t mode;
|
854
|
+
git_odb *odb = NULL;
|
855
|
+
git_oid oid;
|
856
|
+
int error;
|
560
857
|
|
561
|
-
|
562
|
-
GITERR_CHECK_ALLOC(index_entry->path);
|
858
|
+
*out = NULL;
|
563
859
|
|
564
|
-
|
565
|
-
|
566
|
-
|
860
|
+
if ((error = driver->apply(driver, &path, &mode, &buf, name, src)) < 0 ||
|
861
|
+
(error = git_repository_odb(&odb, src->repo)) < 0 ||
|
862
|
+
(error = git_odb_write(&oid, odb, buf.ptr, buf.size, GIT_OBJECT_BLOB)) < 0)
|
863
|
+
goto done;
|
567
864
|
|
568
|
-
|
569
|
-
|
865
|
+
result = git_pool_mallocz(&diff_list->pool, sizeof(git_index_entry));
|
866
|
+
GIT_ERROR_CHECK_ALLOC(result);
|
867
|
+
|
868
|
+
git_oid_cpy(&result->id, &oid);
|
869
|
+
result->mode = mode;
|
870
|
+
result->file_size = buf.size;
|
871
|
+
|
872
|
+
result->path = git_pool_strdup(&diff_list->pool, path);
|
873
|
+
GIT_ERROR_CHECK_ALLOC(result->path);
|
874
|
+
|
875
|
+
*out = result;
|
876
|
+
|
877
|
+
done:
|
878
|
+
git_buf_dispose(&buf);
|
879
|
+
git_odb_free(odb);
|
880
|
+
|
881
|
+
return error;
|
882
|
+
}
|
883
|
+
|
884
|
+
static int merge_conflict_resolve_contents(
|
885
|
+
int *resolved,
|
886
|
+
git_merge_diff_list *diff_list,
|
887
|
+
const git_merge_diff *conflict,
|
888
|
+
const git_merge_options *merge_opts,
|
889
|
+
const git_merge_file_options *file_opts)
|
890
|
+
{
|
891
|
+
git_merge_driver_source source = {0};
|
892
|
+
git_merge_file_result result = {0};
|
893
|
+
git_merge_driver *driver;
|
894
|
+
git_merge_driver__builtin builtin = {{0}};
|
895
|
+
git_index_entry *merge_result;
|
896
|
+
git_odb *odb = NULL;
|
897
|
+
const char *name;
|
898
|
+
bool fallback = false;
|
899
|
+
int error;
|
900
|
+
|
901
|
+
assert(resolved && diff_list && conflict);
|
902
|
+
|
903
|
+
*resolved = 0;
|
904
|
+
|
905
|
+
if (!merge_conflict_can_resolve_contents(conflict))
|
906
|
+
return 0;
|
907
|
+
|
908
|
+
source.repo = diff_list->repo;
|
909
|
+
source.default_driver = merge_opts->default_driver;
|
910
|
+
source.file_opts = file_opts;
|
911
|
+
source.ancestor = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) ?
|
912
|
+
&conflict->ancestor_entry : NULL;
|
913
|
+
source.ours = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ?
|
914
|
+
&conflict->our_entry : NULL;
|
915
|
+
source.theirs = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ?
|
916
|
+
&conflict->their_entry : NULL;
|
917
|
+
|
918
|
+
if (file_opts->favor != GIT_MERGE_FILE_FAVOR_NORMAL) {
|
919
|
+
/* if the user requested a particular type of resolution (via the
|
920
|
+
* favor flag) then let that override the gitattributes and use
|
921
|
+
* the builtin driver.
|
922
|
+
*/
|
923
|
+
name = "text";
|
924
|
+
builtin.base.apply = git_merge_driver__builtin_apply;
|
925
|
+
builtin.favor = file_opts->favor;
|
926
|
+
|
927
|
+
driver = &builtin.base;
|
928
|
+
} else {
|
929
|
+
/* find the merge driver for this file */
|
930
|
+
if ((error = git_merge_driver_for_source(&name, &driver, &source)) < 0)
|
931
|
+
goto done;
|
932
|
+
|
933
|
+
if (driver == NULL)
|
934
|
+
fallback = true;
|
935
|
+
}
|
936
|
+
|
937
|
+
if (driver) {
|
938
|
+
error = merge_conflict_invoke_driver(&merge_result, name, driver,
|
939
|
+
diff_list, &source);
|
940
|
+
|
941
|
+
if (error == GIT_PASSTHROUGH)
|
942
|
+
fallback = true;
|
943
|
+
}
|
944
|
+
|
945
|
+
if (fallback) {
|
946
|
+
error = merge_conflict_invoke_driver(&merge_result, "text",
|
947
|
+
&git_merge_driver__text.base, diff_list, &source);
|
948
|
+
}
|
949
|
+
|
950
|
+
if (error < 0) {
|
951
|
+
if (error == GIT_EMERGECONFLICT)
|
952
|
+
error = 0;
|
953
|
+
|
954
|
+
goto done;
|
955
|
+
}
|
956
|
+
|
957
|
+
git_vector_insert(&diff_list->staged, merge_result);
|
958
|
+
git_vector_insert(&diff_list->resolved, (git_merge_diff *)conflict);
|
570
959
|
|
571
960
|
*resolved = 1;
|
572
961
|
|
573
962
|
done:
|
574
|
-
git_merge_file_input_free(&ancestor);
|
575
|
-
git_merge_file_input_free(&ours);
|
576
|
-
git_merge_file_input_free(&theirs);
|
577
963
|
git_merge_file_result_free(&result);
|
578
964
|
git_odb_free(odb);
|
579
965
|
|
@@ -584,26 +970,29 @@ static int merge_conflict_resolve(
|
|
584
970
|
int *out,
|
585
971
|
git_merge_diff_list *diff_list,
|
586
972
|
const git_merge_diff *conflict,
|
587
|
-
|
973
|
+
const git_merge_options *merge_opts,
|
974
|
+
const git_merge_file_options *file_opts)
|
588
975
|
{
|
589
976
|
int resolved = 0;
|
590
977
|
int error = 0;
|
591
978
|
|
592
979
|
*out = 0;
|
593
980
|
|
594
|
-
if ((error = merge_conflict_resolve_trivial(
|
981
|
+
if ((error = merge_conflict_resolve_trivial(
|
982
|
+
&resolved, diff_list, conflict)) < 0)
|
595
983
|
goto done;
|
596
984
|
|
597
|
-
if (
|
598
|
-
|
599
|
-
|
985
|
+
if (!resolved && (error = merge_conflict_resolve_one_removed(
|
986
|
+
&resolved, diff_list, conflict)) < 0)
|
987
|
+
goto done;
|
600
988
|
|
601
|
-
|
602
|
-
|
989
|
+
if (!resolved && (error = merge_conflict_resolve_one_renamed(
|
990
|
+
&resolved, diff_list, conflict)) < 0)
|
991
|
+
goto done;
|
603
992
|
|
604
|
-
|
605
|
-
|
606
|
-
|
993
|
+
if (!resolved && (error = merge_conflict_resolve_contents(
|
994
|
+
&resolved, diff_list, conflict, merge_opts, file_opts)) < 0)
|
995
|
+
goto done;
|
607
996
|
|
608
997
|
*out = resolved;
|
609
998
|
|
@@ -618,32 +1007,11 @@ struct merge_diff_similarity {
|
|
618
1007
|
size_t other_idx;
|
619
1008
|
};
|
620
1009
|
|
621
|
-
static int index_entry_similarity_exact(
|
622
|
-
git_repository *repo,
|
623
|
-
git_index_entry *a,
|
624
|
-
size_t a_idx,
|
625
|
-
git_index_entry *b,
|
626
|
-
size_t b_idx,
|
627
|
-
void **cache,
|
628
|
-
const git_merge_tree_opts *opts)
|
629
|
-
{
|
630
|
-
GIT_UNUSED(repo);
|
631
|
-
GIT_UNUSED(a_idx);
|
632
|
-
GIT_UNUSED(b_idx);
|
633
|
-
GIT_UNUSED(cache);
|
634
|
-
GIT_UNUSED(opts);
|
635
|
-
|
636
|
-
if (git_oid__cmp(&a->oid, &b->oid) == 0)
|
637
|
-
return 100;
|
638
|
-
|
639
|
-
return 0;
|
640
|
-
}
|
641
|
-
|
642
1010
|
static int index_entry_similarity_calc(
|
643
1011
|
void **out,
|
644
1012
|
git_repository *repo,
|
645
1013
|
git_index_entry *entry,
|
646
|
-
const
|
1014
|
+
const git_merge_options *opts)
|
647
1015
|
{
|
648
1016
|
git_blob *blob;
|
649
1017
|
git_diff_file diff_file = {{{0}}};
|
@@ -652,10 +1020,10 @@ static int index_entry_similarity_calc(
|
|
652
1020
|
|
653
1021
|
*out = NULL;
|
654
1022
|
|
655
|
-
if ((error = git_blob_lookup(&blob, repo, &entry->
|
1023
|
+
if ((error = git_blob_lookup(&blob, repo, &entry->id)) < 0)
|
656
1024
|
return error;
|
657
1025
|
|
658
|
-
git_oid_cpy(&diff_file.
|
1026
|
+
git_oid_cpy(&diff_file.id, &entry->id);
|
659
1027
|
diff_file.path = entry->path;
|
660
1028
|
diff_file.size = entry->file_size;
|
661
1029
|
diff_file.mode = entry->mode;
|
@@ -683,12 +1051,12 @@ static int index_entry_similarity_inexact(
|
|
683
1051
|
git_index_entry *b,
|
684
1052
|
size_t b_idx,
|
685
1053
|
void **cache,
|
686
|
-
const
|
1054
|
+
const git_merge_options *opts)
|
687
1055
|
{
|
688
1056
|
int score = 0;
|
689
1057
|
int error = 0;
|
690
1058
|
|
691
|
-
if (
|
1059
|
+
if (!GIT_MODE_ISBLOB(a->mode) || !GIT_MODE_ISBLOB(b->mode))
|
692
1060
|
return 0;
|
693
1061
|
|
694
1062
|
/* update signature cache if needed */
|
@@ -715,14 +1083,156 @@ static int index_entry_similarity_inexact(
|
|
715
1083
|
return score;
|
716
1084
|
}
|
717
1085
|
|
718
|
-
|
1086
|
+
/* Tracks deletes by oid for merge_diff_mark_similarity_exact(). This is a
|
1087
|
+
* non-shrinking queue where next_pos is the next position to dequeue.
|
1088
|
+
*/
|
1089
|
+
typedef struct {
|
1090
|
+
git_array_t(size_t) arr;
|
1091
|
+
size_t next_pos;
|
1092
|
+
size_t first_entry;
|
1093
|
+
} deletes_by_oid_queue;
|
1094
|
+
|
1095
|
+
static void deletes_by_oid_free(git_oidmap *map) {
|
1096
|
+
deletes_by_oid_queue *queue;
|
1097
|
+
|
1098
|
+
if (!map)
|
1099
|
+
return;
|
1100
|
+
|
1101
|
+
git_oidmap_foreach_value(map, queue, {
|
1102
|
+
git_array_clear(queue->arr);
|
1103
|
+
});
|
1104
|
+
git_oidmap_free(map);
|
1105
|
+
}
|
1106
|
+
|
1107
|
+
static int deletes_by_oid_enqueue(git_oidmap *map, git_pool* pool, const git_oid *id, size_t idx) {
|
1108
|
+
size_t pos;
|
1109
|
+
deletes_by_oid_queue *queue;
|
1110
|
+
size_t *array_entry;
|
1111
|
+
int error;
|
1112
|
+
|
1113
|
+
pos = git_oidmap_lookup_index(map, id);
|
1114
|
+
if (!git_oidmap_valid_index(map, pos)) {
|
1115
|
+
queue = git_pool_malloc(pool, sizeof(deletes_by_oid_queue));
|
1116
|
+
GIT_ERROR_CHECK_ALLOC(queue);
|
1117
|
+
|
1118
|
+
git_array_init(queue->arr);
|
1119
|
+
queue->next_pos = 0;
|
1120
|
+
queue->first_entry = idx;
|
1121
|
+
|
1122
|
+
git_oidmap_insert(map, id, queue, &error);
|
1123
|
+
if (error < 0)
|
1124
|
+
return -1;
|
1125
|
+
} else {
|
1126
|
+
queue = git_oidmap_value_at(map, pos);
|
1127
|
+
array_entry = git_array_alloc(queue->arr);
|
1128
|
+
GIT_ERROR_CHECK_ALLOC(array_entry);
|
1129
|
+
*array_entry = idx;
|
1130
|
+
}
|
1131
|
+
|
1132
|
+
return 0;
|
1133
|
+
}
|
1134
|
+
|
1135
|
+
static int deletes_by_oid_dequeue(size_t *idx, git_oidmap *map, const git_oid *id) {
|
1136
|
+
size_t pos;
|
1137
|
+
deletes_by_oid_queue *queue;
|
1138
|
+
size_t *array_entry;
|
1139
|
+
|
1140
|
+
pos = git_oidmap_lookup_index(map, id);
|
1141
|
+
|
1142
|
+
if (!git_oidmap_valid_index(map, pos))
|
1143
|
+
return GIT_ENOTFOUND;
|
1144
|
+
|
1145
|
+
queue = git_oidmap_value_at(map, pos);
|
1146
|
+
|
1147
|
+
if (queue->next_pos == 0) {
|
1148
|
+
*idx = queue->first_entry;
|
1149
|
+
} else {
|
1150
|
+
array_entry = git_array_get(queue->arr, queue->next_pos - 1);
|
1151
|
+
if (array_entry == NULL)
|
1152
|
+
return GIT_ENOTFOUND;
|
1153
|
+
|
1154
|
+
*idx = *array_entry;
|
1155
|
+
}
|
1156
|
+
|
1157
|
+
queue->next_pos++;
|
1158
|
+
return 0;
|
1159
|
+
}
|
1160
|
+
|
1161
|
+
static int merge_diff_mark_similarity_exact(
|
1162
|
+
git_merge_diff_list *diff_list,
|
1163
|
+
struct merge_diff_similarity *similarity_ours,
|
1164
|
+
struct merge_diff_similarity *similarity_theirs)
|
1165
|
+
{
|
1166
|
+
size_t i, j;
|
1167
|
+
git_merge_diff *conflict_src, *conflict_tgt;
|
1168
|
+
git_oidmap *ours_deletes_by_oid = NULL, *theirs_deletes_by_oid = NULL;
|
1169
|
+
int error = 0;
|
1170
|
+
|
1171
|
+
if (!(ours_deletes_by_oid = git_oidmap_alloc()) ||
|
1172
|
+
!(theirs_deletes_by_oid = git_oidmap_alloc())) {
|
1173
|
+
error = -1;
|
1174
|
+
goto done;
|
1175
|
+
}
|
1176
|
+
|
1177
|
+
/* Build a map of object ids to conflicts */
|
1178
|
+
git_vector_foreach(&diff_list->conflicts, i, conflict_src) {
|
1179
|
+
/* Items can be the source of a rename iff they have an item in the
|
1180
|
+
* ancestor slot and lack an item in the ours or theirs slot. */
|
1181
|
+
if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->ancestor_entry))
|
1182
|
+
continue;
|
1183
|
+
|
1184
|
+
if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->our_entry)) {
|
1185
|
+
error = deletes_by_oid_enqueue(ours_deletes_by_oid, &diff_list->pool, &conflict_src->ancestor_entry.id, i);
|
1186
|
+
if (error < 0)
|
1187
|
+
goto done;
|
1188
|
+
}
|
1189
|
+
|
1190
|
+
if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->their_entry)) {
|
1191
|
+
error = deletes_by_oid_enqueue(theirs_deletes_by_oid, &diff_list->pool, &conflict_src->ancestor_entry.id, i);
|
1192
|
+
if (error < 0)
|
1193
|
+
goto done;
|
1194
|
+
}
|
1195
|
+
}
|
1196
|
+
|
1197
|
+
git_vector_foreach(&diff_list->conflicts, j, conflict_tgt) {
|
1198
|
+
if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->ancestor_entry))
|
1199
|
+
continue;
|
1200
|
+
|
1201
|
+
if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->our_entry)) {
|
1202
|
+
if (deletes_by_oid_dequeue(&i, ours_deletes_by_oid, &conflict_tgt->our_entry.id) == 0) {
|
1203
|
+
similarity_ours[i].similarity = 100;
|
1204
|
+
similarity_ours[i].other_idx = j;
|
1205
|
+
|
1206
|
+
similarity_ours[j].similarity = 100;
|
1207
|
+
similarity_ours[j].other_idx = i;
|
1208
|
+
}
|
1209
|
+
}
|
1210
|
+
|
1211
|
+
if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->their_entry)) {
|
1212
|
+
if (deletes_by_oid_dequeue(&i, theirs_deletes_by_oid, &conflict_tgt->their_entry.id) == 0) {
|
1213
|
+
similarity_theirs[i].similarity = 100;
|
1214
|
+
similarity_theirs[i].other_idx = j;
|
1215
|
+
|
1216
|
+
similarity_theirs[j].similarity = 100;
|
1217
|
+
similarity_theirs[j].other_idx = i;
|
1218
|
+
}
|
1219
|
+
}
|
1220
|
+
}
|
1221
|
+
|
1222
|
+
done:
|
1223
|
+
deletes_by_oid_free(ours_deletes_by_oid);
|
1224
|
+
deletes_by_oid_free(theirs_deletes_by_oid);
|
1225
|
+
|
1226
|
+
return error;
|
1227
|
+
}
|
1228
|
+
|
1229
|
+
static int merge_diff_mark_similarity_inexact(
|
719
1230
|
git_repository *repo,
|
720
1231
|
git_merge_diff_list *diff_list,
|
721
1232
|
struct merge_diff_similarity *similarity_ours,
|
722
1233
|
struct merge_diff_similarity *similarity_theirs,
|
723
|
-
int (*similarity_fn)(git_repository *, git_index_entry *, size_t, git_index_entry *, size_t, void **, const git_merge_tree_opts *),
|
724
1234
|
void **cache,
|
725
|
-
const
|
1235
|
+
const git_merge_options *opts)
|
726
1236
|
{
|
727
1237
|
size_t i, j;
|
728
1238
|
git_merge_diff *conflict_src, *conflict_tgt;
|
@@ -745,7 +1255,7 @@ static int merge_diff_mark_similarity(
|
|
745
1255
|
|
746
1256
|
if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->our_entry) &&
|
747
1257
|
!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->our_entry)) {
|
748
|
-
similarity =
|
1258
|
+
similarity = index_entry_similarity_inexact(repo, &conflict_src->ancestor_entry, i, &conflict_tgt->our_entry, our_idx, cache, opts);
|
749
1259
|
|
750
1260
|
if (similarity == GIT_EBUFS)
|
751
1261
|
continue;
|
@@ -771,7 +1281,7 @@ static int merge_diff_mark_similarity(
|
|
771
1281
|
|
772
1282
|
if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->their_entry) &&
|
773
1283
|
!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->their_entry)) {
|
774
|
-
similarity =
|
1284
|
+
similarity = index_entry_similarity_inexact(repo, &conflict_src->ancestor_entry, i, &conflict_tgt->their_entry, their_idx, cache, opts);
|
775
1285
|
|
776
1286
|
if (similarity > similarity_theirs[i].similarity &&
|
777
1287
|
similarity > similarity_theirs[j].similarity) {
|
@@ -823,7 +1333,7 @@ static void merge_diff_mark_rename_conflict(
|
|
823
1333
|
bool theirs_renamed,
|
824
1334
|
size_t theirs_source_idx,
|
825
1335
|
git_merge_diff *target,
|
826
|
-
const
|
1336
|
+
const git_merge_options *opts)
|
827
1337
|
{
|
828
1338
|
git_merge_diff *ours_source = NULL, *theirs_source = NULL;
|
829
1339
|
|
@@ -893,7 +1403,7 @@ static void merge_diff_list_coalesce_renames(
|
|
893
1403
|
git_merge_diff_list *diff_list,
|
894
1404
|
struct merge_diff_similarity *similarity_ours,
|
895
1405
|
struct merge_diff_similarity *similarity_theirs,
|
896
|
-
const
|
1406
|
+
const git_merge_options *opts)
|
897
1407
|
{
|
898
1408
|
size_t i;
|
899
1409
|
bool ours_renamed = 0, theirs_renamed = 0;
|
@@ -950,10 +1460,12 @@ static void merge_diff_list_coalesce_renames(
|
|
950
1460
|
}
|
951
1461
|
}
|
952
1462
|
|
953
|
-
static int merge_diff_empty(const git_vector *conflicts, size_t idx)
|
1463
|
+
static int merge_diff_empty(const git_vector *conflicts, size_t idx, void *p)
|
954
1464
|
{
|
955
1465
|
git_merge_diff *conflict = conflicts->contents[idx];
|
956
1466
|
|
1467
|
+
GIT_UNUSED(p);
|
1468
|
+
|
957
1469
|
return (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) &&
|
958
1470
|
!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) &&
|
959
1471
|
!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry));
|
@@ -974,16 +1486,16 @@ static void merge_diff_list_count_candidates(
|
|
974
1486
|
if (GIT_MERGE_INDEX_ENTRY_EXISTS(entry->ancestor_entry) &&
|
975
1487
|
(!GIT_MERGE_INDEX_ENTRY_EXISTS(entry->our_entry) ||
|
976
1488
|
!GIT_MERGE_INDEX_ENTRY_EXISTS(entry->their_entry)))
|
977
|
-
src_count++;
|
1489
|
+
(*src_count)++;
|
978
1490
|
else if (!GIT_MERGE_INDEX_ENTRY_EXISTS(entry->ancestor_entry))
|
979
|
-
tgt_count++;
|
1491
|
+
(*tgt_count)++;
|
980
1492
|
}
|
981
1493
|
}
|
982
1494
|
|
983
1495
|
int git_merge_diff_list__find_renames(
|
984
1496
|
git_repository *repo,
|
985
1497
|
git_merge_diff_list *diff_list,
|
986
|
-
const
|
1498
|
+
const git_merge_options *opts)
|
987
1499
|
{
|
988
1500
|
struct merge_diff_similarity *similarity_ours, *similarity_theirs;
|
989
1501
|
void **cache = NULL;
|
@@ -993,37 +1505,35 @@ int git_merge_diff_list__find_renames(
|
|
993
1505
|
|
994
1506
|
assert(diff_list && opts);
|
995
1507
|
|
996
|
-
if ((opts->flags &
|
1508
|
+
if ((opts->flags & GIT_MERGE_FIND_RENAMES) == 0)
|
997
1509
|
return 0;
|
998
1510
|
|
999
1511
|
similarity_ours = git__calloc(diff_list->conflicts.length,
|
1000
1512
|
sizeof(struct merge_diff_similarity));
|
1001
|
-
|
1513
|
+
GIT_ERROR_CHECK_ALLOC(similarity_ours);
|
1002
1514
|
|
1003
1515
|
similarity_theirs = git__calloc(diff_list->conflicts.length,
|
1004
1516
|
sizeof(struct merge_diff_similarity));
|
1005
|
-
|
1517
|
+
GIT_ERROR_CHECK_ALLOC(similarity_theirs);
|
1006
1518
|
|
1007
1519
|
/* Calculate similarity between items that were deleted from the ancestor
|
1008
1520
|
* and added in the other branch.
|
1009
1521
|
*/
|
1010
|
-
if ((error =
|
1011
|
-
similarity_theirs, index_entry_similarity_exact, NULL, opts)) < 0)
|
1522
|
+
if ((error = merge_diff_mark_similarity_exact(diff_list, similarity_ours, similarity_theirs)) < 0)
|
1012
1523
|
goto done;
|
1013
1524
|
|
1014
|
-
if (diff_list->conflicts.length <= opts->target_limit) {
|
1015
|
-
cache_size
|
1525
|
+
if (opts->rename_threshold < 100 && diff_list->conflicts.length <= opts->target_limit) {
|
1526
|
+
GIT_ERROR_CHECK_ALLOC_MULTIPLY(&cache_size, diff_list->conflicts.length, 3);
|
1016
1527
|
cache = git__calloc(cache_size, sizeof(void *));
|
1017
|
-
|
1528
|
+
GIT_ERROR_CHECK_ALLOC(cache);
|
1018
1529
|
|
1019
1530
|
merge_diff_list_count_candidates(diff_list, &src_count, &tgt_count);
|
1020
1531
|
|
1021
1532
|
if (src_count > opts->target_limit || tgt_count > opts->target_limit) {
|
1022
1533
|
/* TODO: report! */
|
1023
1534
|
} else {
|
1024
|
-
if ((error =
|
1025
|
-
repo, diff_list, similarity_ours, similarity_theirs,
|
1026
|
-
index_entry_similarity_inexact, cache, opts)) < 0)
|
1535
|
+
if ((error = merge_diff_mark_similarity_inexact(
|
1536
|
+
repo, diff_list, similarity_ours, similarity_theirs, cache, opts)) < 0)
|
1027
1537
|
goto done;
|
1028
1538
|
}
|
1029
1539
|
}
|
@@ -1034,7 +1544,7 @@ int git_merge_diff_list__find_renames(
|
|
1034
1544
|
merge_diff_list_coalesce_renames(diff_list, similarity_ours, similarity_theirs, opts);
|
1035
1545
|
|
1036
1546
|
/* And remove any entries that were merged and are now empty. */
|
1037
|
-
git_vector_remove_matching(&diff_list->conflicts, merge_diff_empty);
|
1547
|
+
git_vector_remove_matching(&diff_list->conflicts, merge_diff_empty, NULL);
|
1038
1548
|
|
1039
1549
|
done:
|
1040
1550
|
if (cache != NULL) {
|
@@ -1145,14 +1655,13 @@ GIT_INLINE(int) merge_diff_detect_type(
|
|
1145
1655
|
return 0;
|
1146
1656
|
}
|
1147
1657
|
|
1148
|
-
GIT_INLINE(int)
|
1658
|
+
GIT_INLINE(int) index_entry_dup_pool(
|
1149
1659
|
git_index_entry *out,
|
1150
1660
|
git_pool *pool,
|
1151
1661
|
const git_index_entry *src)
|
1152
1662
|
{
|
1153
1663
|
if (src != NULL) {
|
1154
1664
|
memcpy(out, src, sizeof(git_index_entry));
|
1155
|
-
|
1156
1665
|
if ((out->path = git_pool_strdup(pool, src->path)) == NULL)
|
1157
1666
|
return -1;
|
1158
1667
|
}
|
@@ -1174,7 +1683,7 @@ GIT_INLINE(int) merge_delta_type_from_index_entries(
|
|
1174
1683
|
return GIT_DELTA_TYPECHANGE;
|
1175
1684
|
else if(S_ISLNK(ancestor->mode) ^ S_ISLNK(other->mode))
|
1176
1685
|
return GIT_DELTA_TYPECHANGE;
|
1177
|
-
else if (git_oid__cmp(&ancestor->
|
1686
|
+
else if (git_oid__cmp(&ancestor->id, &other->id) ||
|
1178
1687
|
ancestor->mode != other->mode)
|
1179
1688
|
return GIT_DELTA_MODIFIED;
|
1180
1689
|
|
@@ -1188,12 +1697,12 @@ static git_merge_diff *merge_diff_from_index_entries(
|
|
1188
1697
|
git_merge_diff *conflict;
|
1189
1698
|
git_pool *pool = &diff_list->pool;
|
1190
1699
|
|
1191
|
-
if ((conflict =
|
1700
|
+
if ((conflict = git_pool_mallocz(pool, sizeof(git_merge_diff))) == NULL)
|
1192
1701
|
return NULL;
|
1193
1702
|
|
1194
|
-
if (
|
1195
|
-
|
1196
|
-
|
1703
|
+
if (index_entry_dup_pool(&conflict->ancestor_entry, pool, entries[TREE_IDX_ANCESTOR]) < 0 ||
|
1704
|
+
index_entry_dup_pool(&conflict->our_entry, pool, entries[TREE_IDX_OURS]) < 0 ||
|
1705
|
+
index_entry_dup_pool(&conflict->their_entry, pool, entries[TREE_IDX_THEIRS]) < 0)
|
1197
1706
|
return NULL;
|
1198
1707
|
|
1199
1708
|
conflict->our_status = merge_delta_type_from_index_entries(
|
@@ -1206,7 +1715,7 @@ static git_merge_diff *merge_diff_from_index_entries(
|
|
1206
1715
|
|
1207
1716
|
/* Merge trees */
|
1208
1717
|
|
1209
|
-
static int
|
1718
|
+
static int merge_diff_list_insert_conflict(
|
1210
1719
|
git_merge_diff_list *diff_list,
|
1211
1720
|
struct merge_diff_df_data *merge_df_data,
|
1212
1721
|
const git_index_entry *tree_items[3])
|
@@ -1222,7 +1731,7 @@ static int merge_index_insert_conflict(
|
|
1222
1731
|
return 0;
|
1223
1732
|
}
|
1224
1733
|
|
1225
|
-
static int
|
1734
|
+
static int merge_diff_list_insert_unmodified(
|
1226
1735
|
git_merge_diff_list *diff_list,
|
1227
1736
|
const git_index_entry *tree_items[3])
|
1228
1737
|
{
|
@@ -1230,114 +1739,52 @@ static int merge_index_insert_unmodified(
|
|
1230
1739
|
git_index_entry *entry;
|
1231
1740
|
|
1232
1741
|
entry = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry));
|
1233
|
-
|
1742
|
+
GIT_ERROR_CHECK_ALLOC(entry);
|
1234
1743
|
|
1235
|
-
if ((error =
|
1744
|
+
if ((error = index_entry_dup_pool(entry, &diff_list->pool, tree_items[0])) >= 0)
|
1236
1745
|
error = git_vector_insert(&diff_list->staged, entry);
|
1237
1746
|
|
1238
1747
|
return error;
|
1239
1748
|
}
|
1240
1749
|
|
1241
|
-
|
1242
|
-
git_merge_diff_list *diff_list
|
1243
|
-
|
1244
|
-
|
1245
|
-
const git_tree *their_tree)
|
1246
|
-
{
|
1247
|
-
git_iterator *iterators[3] = {0};
|
1248
|
-
const git_index_entry *items[3] = {0}, *best_cur_item, *cur_items[3];
|
1249
|
-
git_vector_cmp entry_compare = git_index_entry__cmp;
|
1250
|
-
struct merge_diff_df_data df_data = {0};
|
1251
|
-
int cur_item_modified;
|
1252
|
-
size_t i, j;
|
1253
|
-
int error = 0;
|
1254
|
-
|
1255
|
-
assert(diff_list && our_tree && their_tree);
|
1256
|
-
|
1257
|
-
if ((error = git_iterator_for_tree(&iterators[TREE_IDX_ANCESTOR], (git_tree *)ancestor_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
|
1258
|
-
(error = git_iterator_for_tree(&iterators[TREE_IDX_OURS], (git_tree *)our_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
|
1259
|
-
(error = git_iterator_for_tree(&iterators[TREE_IDX_THEIRS], (git_tree *)their_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0)
|
1260
|
-
goto done;
|
1261
|
-
|
1262
|
-
/* Set up the iterators */
|
1263
|
-
for (i = 0; i < 3; i++) {
|
1264
|
-
error = git_iterator_current(&items[i], iterators[i]);
|
1265
|
-
if (error < 0 && error != GIT_ITEROVER)
|
1266
|
-
goto done;
|
1267
|
-
}
|
1268
|
-
|
1269
|
-
while (true) {
|
1270
|
-
for (i = 0; i < 3; i++)
|
1271
|
-
cur_items[i] = NULL;
|
1272
|
-
|
1273
|
-
best_cur_item = NULL;
|
1274
|
-
cur_item_modified = 0;
|
1750
|
+
struct merge_diff_find_data {
|
1751
|
+
git_merge_diff_list *diff_list;
|
1752
|
+
struct merge_diff_df_data df_data;
|
1753
|
+
};
|
1275
1754
|
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
}
|
1755
|
+
static int queue_difference(const git_index_entry **entries, void *data)
|
1756
|
+
{
|
1757
|
+
struct merge_diff_find_data *find_data = data;
|
1758
|
+
bool item_modified = false;
|
1759
|
+
size_t i;
|
1282
1760
|
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
/*
|
1291
|
-
* Found an item that sorts before our current item, make
|
1292
|
-
* our current item this one.
|
1293
|
-
*/
|
1294
|
-
for (j = 0; j < i; j++)
|
1295
|
-
cur_items[j] = NULL;
|
1296
|
-
|
1297
|
-
cur_item_modified = 1;
|
1298
|
-
best_cur_item = items[i];
|
1299
|
-
cur_items[i] = items[i];
|
1300
|
-
} else if (path_diff > 0) {
|
1301
|
-
/* No entry for the current item, this is modified */
|
1302
|
-
cur_item_modified = 1;
|
1303
|
-
} else if (path_diff == 0) {
|
1304
|
-
cur_items[i] = items[i];
|
1305
|
-
|
1306
|
-
if (!cur_item_modified)
|
1307
|
-
cur_item_modified = index_entry_cmp(best_cur_item, items[i]);
|
1308
|
-
}
|
1761
|
+
if (!entries[0] || !entries[1] || !entries[2]) {
|
1762
|
+
item_modified = true;
|
1763
|
+
} else {
|
1764
|
+
for (i = 1; i < 3; i++) {
|
1765
|
+
if (index_entry_cmp(entries[0], entries[i]) != 0) {
|
1766
|
+
item_modified = true;
|
1767
|
+
break;
|
1309
1768
|
}
|
1310
1769
|
}
|
1311
|
-
|
1312
|
-
if (best_cur_item == NULL)
|
1313
|
-
break;
|
1314
|
-
|
1315
|
-
if (cur_item_modified)
|
1316
|
-
error = merge_index_insert_conflict(diff_list, &df_data, cur_items);
|
1317
|
-
else
|
1318
|
-
error = merge_index_insert_unmodified(diff_list, cur_items);
|
1319
|
-
if (error < 0)
|
1320
|
-
goto done;
|
1321
|
-
|
1322
|
-
/* Advance each iterator that participated */
|
1323
|
-
for (i = 0; i < 3; i++) {
|
1324
|
-
if (cur_items[i] == NULL)
|
1325
|
-
continue;
|
1326
|
-
|
1327
|
-
error = git_iterator_advance(&items[i], iterators[i]);
|
1328
|
-
if (error < 0 && error != GIT_ITEROVER)
|
1329
|
-
goto done;
|
1330
|
-
}
|
1331
1770
|
}
|
1332
1771
|
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1772
|
+
return item_modified ?
|
1773
|
+
merge_diff_list_insert_conflict(
|
1774
|
+
find_data->diff_list, &find_data->df_data, entries) :
|
1775
|
+
merge_diff_list_insert_unmodified(find_data->diff_list, entries);
|
1776
|
+
}
|
1336
1777
|
|
1337
|
-
|
1338
|
-
|
1778
|
+
int git_merge_diff_list__find_differences(
|
1779
|
+
git_merge_diff_list *diff_list,
|
1780
|
+
git_iterator *ancestor_iter,
|
1781
|
+
git_iterator *our_iter,
|
1782
|
+
git_iterator *their_iter)
|
1783
|
+
{
|
1784
|
+
git_iterator *iterators[3] = { ancestor_iter, our_iter, their_iter };
|
1785
|
+
struct merge_diff_find_data find_data = { diff_list };
|
1339
1786
|
|
1340
|
-
return
|
1787
|
+
return git_iterator_walk(iterators, 3, queue_difference, &find_data);
|
1341
1788
|
}
|
1342
1789
|
|
1343
1790
|
git_merge_diff_list *git_merge_diff_list__alloc(git_repository *repo)
|
@@ -1349,11 +1796,14 @@ git_merge_diff_list *git_merge_diff_list__alloc(git_repository *repo)
|
|
1349
1796
|
|
1350
1797
|
diff_list->repo = repo;
|
1351
1798
|
|
1799
|
+
git_pool_init(&diff_list->pool, 1);
|
1800
|
+
|
1352
1801
|
if (git_vector_init(&diff_list->staged, 0, NULL) < 0 ||
|
1353
1802
|
git_vector_init(&diff_list->conflicts, 0, NULL) < 0 ||
|
1354
|
-
git_vector_init(&diff_list->resolved, 0, NULL) < 0
|
1355
|
-
|
1803
|
+
git_vector_init(&diff_list->resolved, 0, NULL) < 0) {
|
1804
|
+
git_merge_diff_list__free(diff_list);
|
1356
1805
|
return NULL;
|
1806
|
+
}
|
1357
1807
|
|
1358
1808
|
return diff_list;
|
1359
1809
|
}
|
@@ -1370,12 +1820,13 @@ void git_merge_diff_list__free(git_merge_diff_list *diff_list)
|
|
1370
1820
|
git__free(diff_list);
|
1371
1821
|
}
|
1372
1822
|
|
1373
|
-
static int
|
1823
|
+
static int merge_normalize_opts(
|
1374
1824
|
git_repository *repo,
|
1375
|
-
|
1376
|
-
const
|
1825
|
+
git_merge_options *opts,
|
1826
|
+
const git_merge_options *given)
|
1377
1827
|
{
|
1378
1828
|
git_config *cfg = NULL;
|
1829
|
+
git_config_entry *entry = NULL;
|
1379
1830
|
int error = 0;
|
1380
1831
|
|
1381
1832
|
assert(repo && opts);
|
@@ -1383,51 +1834,57 @@ static int merge_tree_normalize_opts(
|
|
1383
1834
|
if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
|
1384
1835
|
return error;
|
1385
1836
|
|
1386
|
-
if (given != NULL)
|
1387
|
-
memcpy(opts, given, sizeof(
|
1388
|
-
else {
|
1389
|
-
|
1837
|
+
if (given != NULL) {
|
1838
|
+
memcpy(opts, given, sizeof(git_merge_options));
|
1839
|
+
} else {
|
1840
|
+
git_merge_options init = GIT_MERGE_OPTIONS_INIT;
|
1390
1841
|
memcpy(opts, &init, sizeof(init));
|
1391
|
-
|
1392
|
-
opts->flags = GIT_MERGE_TREE_FIND_RENAMES;
|
1393
|
-
opts->rename_threshold = GIT_MERGE_TREE_RENAME_THRESHOLD;
|
1394
1842
|
}
|
1395
1843
|
|
1396
|
-
if (!opts->
|
1397
|
-
|
1398
|
-
|
1399
|
-
opts->target_limit = GIT_MERGE_TREE_TARGET_LIMIT;
|
1844
|
+
if ((opts->flags & GIT_MERGE_FIND_RENAMES) && !opts->rename_threshold)
|
1845
|
+
opts->rename_threshold = GIT_MERGE_DEFAULT_RENAME_THRESHOLD;
|
1400
1846
|
|
1401
|
-
|
1402
|
-
|
1847
|
+
if (given && given->default_driver) {
|
1848
|
+
opts->default_driver = git__strdup(given->default_driver);
|
1849
|
+
GIT_ERROR_CHECK_ALLOC(opts->default_driver);
|
1850
|
+
} else {
|
1851
|
+
error = git_config_get_entry(&entry, cfg, "merge.default");
|
1403
1852
|
|
1404
|
-
|
1405
|
-
|
1853
|
+
if (error == 0) {
|
1854
|
+
opts->default_driver = git__strdup(entry->value);
|
1855
|
+
GIT_ERROR_CHECK_ALLOC(opts->default_driver);
|
1856
|
+
} else if (error == GIT_ENOTFOUND) {
|
1857
|
+
error = 0;
|
1858
|
+
} else {
|
1859
|
+
goto done;
|
1406
1860
|
}
|
1861
|
+
}
|
1407
1862
|
|
1408
|
-
|
1409
|
-
|
1863
|
+
if (!opts->target_limit) {
|
1864
|
+
int limit = git_config__get_int_force(cfg, "merge.renamelimit", 0);
|
1865
|
+
|
1866
|
+
if (!limit)
|
1867
|
+
limit = git_config__get_int_force(cfg, "diff.renamelimit", 0);
|
1868
|
+
|
1869
|
+
opts->target_limit = (limit <= 0) ?
|
1870
|
+
GIT_MERGE_DEFAULT_TARGET_LIMIT : (unsigned int)limit;
|
1410
1871
|
}
|
1411
1872
|
|
1412
1873
|
/* assign the internal metric with whitespace flag as payload */
|
1413
1874
|
if (!opts->metric) {
|
1414
1875
|
opts->metric = git__malloc(sizeof(git_diff_similarity_metric));
|
1415
|
-
|
1876
|
+
GIT_ERROR_CHECK_ALLOC(opts->metric);
|
1416
1877
|
|
1417
1878
|
opts->metric->file_signature = git_diff_find_similar__hashsig_for_file;
|
1418
1879
|
opts->metric->buffer_signature = git_diff_find_similar__hashsig_for_buf;
|
1419
1880
|
opts->metric->free_signature = git_diff_find_similar__hashsig_free;
|
1420
1881
|
opts->metric->similarity = git_diff_find_similar__calc_similarity;
|
1421
|
-
|
1422
|
-
if (opts->flags & GIT_DIFF_FIND_IGNORE_WHITESPACE)
|
1423
|
-
opts->metric->payload = (void *)GIT_HASHSIG_IGNORE_WHITESPACE;
|
1424
|
-
else if (opts->flags & GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE)
|
1425
|
-
opts->metric->payload = (void *)GIT_HASHSIG_NORMAL;
|
1426
|
-
else
|
1427
|
-
opts->metric->payload = (void *)GIT_HASHSIG_SMART_WHITESPACE;
|
1882
|
+
opts->metric->payload = (void *)GIT_HASHSIG_SMART_WHITESPACE;
|
1428
1883
|
}
|
1429
1884
|
|
1430
|
-
|
1885
|
+
done:
|
1886
|
+
git_config_entry_free(entry);
|
1887
|
+
return error;
|
1431
1888
|
}
|
1432
1889
|
|
1433
1890
|
|
@@ -1452,17 +1909,54 @@ static int merge_index_insert_reuc(
|
|
1452
1909
|
}
|
1453
1910
|
|
1454
1911
|
mode[idx] = entry->mode;
|
1455
|
-
oid[idx] = &entry->
|
1912
|
+
oid[idx] = &entry->id;
|
1456
1913
|
|
1457
1914
|
return git_index_reuc_add(index, entry->path,
|
1458
1915
|
mode[0], oid[0], mode[1], oid[1], mode[2], oid[2]);
|
1459
1916
|
}
|
1460
1917
|
|
1461
|
-
int
|
1918
|
+
static int index_update_reuc(git_index *index, git_merge_diff_list *diff_list)
|
1919
|
+
{
|
1920
|
+
int error;
|
1921
|
+
size_t i;
|
1922
|
+
git_merge_diff *conflict;
|
1923
|
+
|
1924
|
+
/* Add each entry in the resolved conflict to the REUC independently, since
|
1925
|
+
* the paths may differ due to renames. */
|
1926
|
+
git_vector_foreach(&diff_list->resolved, i, conflict) {
|
1927
|
+
const git_index_entry *ancestor =
|
1928
|
+
GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) ?
|
1929
|
+
&conflict->ancestor_entry : NULL;
|
1930
|
+
|
1931
|
+
const git_index_entry *ours =
|
1932
|
+
GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ?
|
1933
|
+
&conflict->our_entry : NULL;
|
1934
|
+
|
1935
|
+
const git_index_entry *theirs =
|
1936
|
+
GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ?
|
1937
|
+
&conflict->their_entry : NULL;
|
1938
|
+
|
1939
|
+
if (ancestor != NULL &&
|
1940
|
+
(error = merge_index_insert_reuc(index, TREE_IDX_ANCESTOR, ancestor)) < 0)
|
1941
|
+
return error;
|
1942
|
+
|
1943
|
+
if (ours != NULL &&
|
1944
|
+
(error = merge_index_insert_reuc(index, TREE_IDX_OURS, ours)) < 0)
|
1945
|
+
return error;
|
1946
|
+
|
1947
|
+
if (theirs != NULL &&
|
1948
|
+
(error = merge_index_insert_reuc(index, TREE_IDX_THEIRS, theirs)) < 0)
|
1949
|
+
return error;
|
1950
|
+
}
|
1951
|
+
|
1952
|
+
return 0;
|
1953
|
+
}
|
1954
|
+
|
1955
|
+
static int index_from_diff_list(git_index **out,
|
1956
|
+
git_merge_diff_list *diff_list, bool skip_reuc)
|
1462
1957
|
{
|
1463
1958
|
git_index *index;
|
1464
1959
|
size_t i;
|
1465
|
-
git_index_entry *entry;
|
1466
1960
|
git_merge_diff *conflict;
|
1467
1961
|
int error = 0;
|
1468
1962
|
|
@@ -1471,10 +1965,8 @@ int index_from_diff_list(git_index **out, git_merge_diff_list *diff_list)
|
|
1471
1965
|
if ((error = git_index_new(&index)) < 0)
|
1472
1966
|
return error;
|
1473
1967
|
|
1474
|
-
|
1475
|
-
|
1476
|
-
goto on_error;
|
1477
|
-
}
|
1968
|
+
if ((error = git_index__fill(index, &diff_list->staged)) < 0)
|
1969
|
+
goto on_error;
|
1478
1970
|
|
1479
1971
|
git_vector_foreach(&diff_list->conflicts, i, conflict) {
|
1480
1972
|
const git_index_entry *ancestor =
|
@@ -1517,31 +2009,8 @@ int index_from_diff_list(git_index **out, git_merge_diff_list *diff_list)
|
|
1517
2009
|
}
|
1518
2010
|
}
|
1519
2011
|
|
1520
|
-
|
1521
|
-
|
1522
|
-
git_vector_foreach(&diff_list->resolved, i, conflict) {
|
1523
|
-
const git_index_entry *ancestor =
|
1524
|
-
GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) ?
|
1525
|
-
&conflict->ancestor_entry : NULL;
|
1526
|
-
|
1527
|
-
const git_index_entry *ours =
|
1528
|
-
GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ?
|
1529
|
-
&conflict->our_entry : NULL;
|
1530
|
-
|
1531
|
-
const git_index_entry *theirs =
|
1532
|
-
GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ?
|
1533
|
-
&conflict->their_entry : NULL;
|
1534
|
-
|
1535
|
-
if (ancestor != NULL &&
|
1536
|
-
(error = merge_index_insert_reuc(index, TREE_IDX_ANCESTOR, ancestor)) < 0)
|
1537
|
-
goto on_error;
|
1538
|
-
|
1539
|
-
if (ours != NULL &&
|
1540
|
-
(error = merge_index_insert_reuc(index, TREE_IDX_OURS, ours)) < 0)
|
1541
|
-
goto on_error;
|
1542
|
-
|
1543
|
-
if (theirs != NULL &&
|
1544
|
-
(error = merge_index_insert_reuc(index, TREE_IDX_THEIRS, theirs)) < 0)
|
2012
|
+
if (!skip_reuc) {
|
2013
|
+
if ((error = index_update_reuc(index, diff_list)) < 0)
|
1545
2014
|
goto on_error;
|
1546
2015
|
}
|
1547
2016
|
|
@@ -1550,36 +2019,74 @@ int index_from_diff_list(git_index **out, git_merge_diff_list *diff_list)
|
|
1550
2019
|
|
1551
2020
|
on_error:
|
1552
2021
|
git_index_free(index);
|
1553
|
-
|
1554
2022
|
return error;
|
1555
2023
|
}
|
1556
2024
|
|
1557
|
-
|
2025
|
+
static git_iterator *iterator_given_or_empty(git_iterator **empty, git_iterator *given)
|
2026
|
+
{
|
2027
|
+
git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT;
|
2028
|
+
|
2029
|
+
if (given)
|
2030
|
+
return given;
|
2031
|
+
|
2032
|
+
opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;
|
2033
|
+
|
2034
|
+
if (git_iterator_for_nothing(empty, &opts) < 0)
|
2035
|
+
return NULL;
|
2036
|
+
|
2037
|
+
return *empty;
|
2038
|
+
}
|
2039
|
+
|
2040
|
+
int git_merge__iterators(
|
1558
2041
|
git_index **out,
|
1559
2042
|
git_repository *repo,
|
1560
|
-
|
1561
|
-
|
1562
|
-
|
1563
|
-
const
|
2043
|
+
git_iterator *ancestor_iter,
|
2044
|
+
git_iterator *our_iter,
|
2045
|
+
git_iterator *theirs_iter,
|
2046
|
+
const git_merge_options *given_opts)
|
1564
2047
|
{
|
2048
|
+
git_iterator *empty_ancestor = NULL,
|
2049
|
+
*empty_ours = NULL,
|
2050
|
+
*empty_theirs = NULL;
|
1565
2051
|
git_merge_diff_list *diff_list;
|
1566
|
-
|
2052
|
+
git_merge_options opts;
|
2053
|
+
git_merge_file_options file_opts = GIT_MERGE_FILE_OPTIONS_INIT;
|
1567
2054
|
git_merge_diff *conflict;
|
1568
2055
|
git_vector changes;
|
1569
2056
|
size_t i;
|
1570
2057
|
int error = 0;
|
1571
2058
|
|
1572
|
-
assert(out && repo
|
2059
|
+
assert(out && repo);
|
1573
2060
|
|
1574
2061
|
*out = NULL;
|
1575
2062
|
|
1576
|
-
|
2063
|
+
GIT_ERROR_CHECK_VERSION(
|
2064
|
+
given_opts, GIT_MERGE_OPTIONS_VERSION, "git_merge_options");
|
2065
|
+
|
2066
|
+
if ((error = merge_normalize_opts(repo, &opts, given_opts)) < 0)
|
1577
2067
|
return error;
|
1578
2068
|
|
2069
|
+
file_opts.favor = opts.file_favor;
|
2070
|
+
file_opts.flags = opts.file_flags;
|
2071
|
+
|
2072
|
+
/* use the git-inspired labels when virtual base building */
|
2073
|
+
if (opts.flags & GIT_MERGE__VIRTUAL_BASE) {
|
2074
|
+
file_opts.ancestor_label = "merged common ancestors";
|
2075
|
+
file_opts.our_label = "Temporary merge branch 1";
|
2076
|
+
file_opts.their_label = "Temporary merge branch 2";
|
2077
|
+
file_opts.flags |= GIT_MERGE_FILE_FAVOR__CONFLICTED;
|
2078
|
+
file_opts.marker_size = GIT_MERGE_CONFLICT_MARKER_SIZE + 2;
|
2079
|
+
}
|
2080
|
+
|
1579
2081
|
diff_list = git_merge_diff_list__alloc(repo);
|
1580
|
-
|
2082
|
+
GIT_ERROR_CHECK_ALLOC(diff_list);
|
2083
|
+
|
2084
|
+
ancestor_iter = iterator_given_or_empty(&empty_ancestor, ancestor_iter);
|
2085
|
+
our_iter = iterator_given_or_empty(&empty_ours, our_iter);
|
2086
|
+
theirs_iter = iterator_given_or_empty(&empty_theirs, theirs_iter);
|
1581
2087
|
|
1582
|
-
if ((error = git_merge_diff_list__find_differences(
|
2088
|
+
if ((error = git_merge_diff_list__find_differences(
|
2089
|
+
diff_list, ancestor_iter, our_iter, theirs_iter)) < 0 ||
|
1583
2090
|
(error = git_merge_diff_list__find_renames(repo, diff_list, &opts)) < 0)
|
1584
2091
|
goto done;
|
1585
2092
|
|
@@ -1589,115 +2096,387 @@ int git_merge_trees(
|
|
1589
2096
|
git_vector_foreach(&changes, i, conflict) {
|
1590
2097
|
int resolved = 0;
|
1591
2098
|
|
1592
|
-
if ((error = merge_conflict_resolve(
|
2099
|
+
if ((error = merge_conflict_resolve(
|
2100
|
+
&resolved, diff_list, conflict, &opts, &file_opts)) < 0)
|
1593
2101
|
goto done;
|
1594
2102
|
|
1595
|
-
if (!resolved)
|
2103
|
+
if (!resolved) {
|
2104
|
+
if ((opts.flags & GIT_MERGE_FAIL_ON_CONFLICT)) {
|
2105
|
+
git_error_set(GIT_ERROR_MERGE, "merge conflicts exist");
|
2106
|
+
error = GIT_EMERGECONFLICT;
|
2107
|
+
goto done;
|
2108
|
+
}
|
2109
|
+
|
1596
2110
|
git_vector_insert(&diff_list->conflicts, conflict);
|
2111
|
+
}
|
1597
2112
|
}
|
1598
2113
|
|
2114
|
+
error = index_from_diff_list(out, diff_list,
|
2115
|
+
(opts.flags & GIT_MERGE_SKIP_REUC));
|
2116
|
+
|
2117
|
+
done:
|
1599
2118
|
if (!given_opts || !given_opts->metric)
|
1600
2119
|
git__free(opts.metric);
|
1601
2120
|
|
1602
|
-
|
2121
|
+
git__free((char *)opts.default_driver);
|
1603
2122
|
|
1604
|
-
done:
|
1605
2123
|
git_merge_diff_list__free(diff_list);
|
2124
|
+
git_iterator_free(empty_ancestor);
|
2125
|
+
git_iterator_free(empty_ours);
|
2126
|
+
git_iterator_free(empty_theirs);
|
1606
2127
|
|
1607
2128
|
return error;
|
1608
2129
|
}
|
1609
2130
|
|
1610
|
-
|
2131
|
+
int git_merge_trees(
|
2132
|
+
git_index **out,
|
2133
|
+
git_repository *repo,
|
2134
|
+
const git_tree *ancestor_tree,
|
2135
|
+
const git_tree *our_tree,
|
2136
|
+
const git_tree *their_tree,
|
2137
|
+
const git_merge_options *merge_opts)
|
2138
|
+
{
|
2139
|
+
git_iterator *ancestor_iter = NULL, *our_iter = NULL, *their_iter = NULL;
|
2140
|
+
git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
|
2141
|
+
int error;
|
2142
|
+
|
2143
|
+
assert(out && repo);
|
2144
|
+
|
2145
|
+
/* if one side is treesame to the ancestor, take the other side */
|
2146
|
+
if (ancestor_tree && merge_opts && (merge_opts->flags & GIT_MERGE_SKIP_REUC)) {
|
2147
|
+
const git_tree *result = NULL;
|
2148
|
+
const git_oid *ancestor_tree_id = git_tree_id(ancestor_tree);
|
2149
|
+
|
2150
|
+
if (our_tree && !git_oid_cmp(ancestor_tree_id, git_tree_id(our_tree)))
|
2151
|
+
result = their_tree;
|
2152
|
+
else if (their_tree && !git_oid_cmp(ancestor_tree_id, git_tree_id(their_tree)))
|
2153
|
+
result = our_tree;
|
2154
|
+
|
2155
|
+
if (result) {
|
2156
|
+
if ((error = git_index_new(out)) == 0)
|
2157
|
+
error = git_index_read_tree(*out, result);
|
2158
|
+
|
2159
|
+
return error;
|
2160
|
+
}
|
2161
|
+
}
|
2162
|
+
|
2163
|
+
iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;
|
2164
|
+
|
2165
|
+
if ((error = git_iterator_for_tree(
|
2166
|
+
&ancestor_iter, (git_tree *)ancestor_tree, &iter_opts)) < 0 ||
|
2167
|
+
(error = git_iterator_for_tree(
|
2168
|
+
&our_iter, (git_tree *)our_tree, &iter_opts)) < 0 ||
|
2169
|
+
(error = git_iterator_for_tree(
|
2170
|
+
&their_iter, (git_tree *)their_tree, &iter_opts)) < 0)
|
2171
|
+
goto done;
|
1611
2172
|
|
1612
|
-
|
2173
|
+
error = git_merge__iterators(
|
2174
|
+
out, repo, ancestor_iter, our_iter, their_iter, merge_opts);
|
2175
|
+
|
2176
|
+
done:
|
2177
|
+
git_iterator_free(ancestor_iter);
|
2178
|
+
git_iterator_free(our_iter);
|
2179
|
+
git_iterator_free(their_iter);
|
2180
|
+
|
2181
|
+
return error;
|
2182
|
+
}
|
2183
|
+
|
2184
|
+
static int merge_annotated_commits(
|
2185
|
+
git_index **index_out,
|
2186
|
+
git_annotated_commit **base_out,
|
1613
2187
|
git_repository *repo,
|
1614
|
-
|
2188
|
+
git_annotated_commit *our_commit,
|
2189
|
+
git_annotated_commit *their_commit,
|
2190
|
+
size_t recursion_level,
|
2191
|
+
const git_merge_options *opts);
|
2192
|
+
|
2193
|
+
GIT_INLINE(int) insert_head_ids(
|
2194
|
+
git_array_oid_t *ids,
|
2195
|
+
const git_annotated_commit *annotated_commit)
|
1615
2196
|
{
|
1616
|
-
|
1617
|
-
|
1618
|
-
char orig_oid_str[GIT_OID_HEXSZ + 1];
|
1619
|
-
int error = 0;
|
2197
|
+
git_oid *id;
|
2198
|
+
size_t i;
|
1620
2199
|
|
1621
|
-
|
2200
|
+
if (annotated_commit->type == GIT_ANNOTATED_COMMIT_REAL) {
|
2201
|
+
id = git_array_alloc(*ids);
|
2202
|
+
GIT_ERROR_CHECK_ALLOC(id);
|
1622
2203
|
|
1623
|
-
|
2204
|
+
git_oid_cpy(id, git_commit_id(annotated_commit->commit));
|
2205
|
+
} else {
|
2206
|
+
for (i = 0; i < annotated_commit->parents.size; i++) {
|
2207
|
+
id = git_array_alloc(*ids);
|
2208
|
+
GIT_ERROR_CHECK_ALLOC(id);
|
1624
2209
|
|
1625
|
-
|
1626
|
-
|
1627
|
-
|
1628
|
-
error = git_filebuf_commit(&file, 0666);
|
2210
|
+
git_oid_cpy(id, &annotated_commit->parents.ptr[i]);
|
2211
|
+
}
|
2212
|
+
}
|
1629
2213
|
|
1630
|
-
|
1631
|
-
|
2214
|
+
return 0;
|
2215
|
+
}
|
2216
|
+
|
2217
|
+
static int create_virtual_base(
|
2218
|
+
git_annotated_commit **out,
|
2219
|
+
git_repository *repo,
|
2220
|
+
git_annotated_commit *one,
|
2221
|
+
git_annotated_commit *two,
|
2222
|
+
const git_merge_options *opts,
|
2223
|
+
size_t recursion_level)
|
2224
|
+
{
|
2225
|
+
git_annotated_commit *result = NULL;
|
2226
|
+
git_index *index = NULL;
|
2227
|
+
git_merge_options virtual_opts = GIT_MERGE_OPTIONS_INIT;
|
2228
|
+
|
2229
|
+
/* Conflicts in the merge base creation do not propagate to conflicts
|
2230
|
+
* in the result; the conflicted base will act as the common ancestor.
|
2231
|
+
*/
|
2232
|
+
if (opts)
|
2233
|
+
memcpy(&virtual_opts, opts, sizeof(git_merge_options));
|
2234
|
+
|
2235
|
+
virtual_opts.flags &= ~GIT_MERGE_FAIL_ON_CONFLICT;
|
2236
|
+
virtual_opts.flags |= GIT_MERGE__VIRTUAL_BASE;
|
2237
|
+
|
2238
|
+
if ((merge_annotated_commits(&index, NULL, repo, one, two,
|
2239
|
+
recursion_level + 1, &virtual_opts)) < 0)
|
2240
|
+
return -1;
|
2241
|
+
|
2242
|
+
result = git__calloc(1, sizeof(git_annotated_commit));
|
2243
|
+
GIT_ERROR_CHECK_ALLOC(result);
|
2244
|
+
result->type = GIT_ANNOTATED_COMMIT_VIRTUAL;
|
2245
|
+
result->index = index;
|
2246
|
+
|
2247
|
+
insert_head_ids(&result->parents, one);
|
2248
|
+
insert_head_ids(&result->parents, two);
|
2249
|
+
|
2250
|
+
*out = result;
|
2251
|
+
return 0;
|
2252
|
+
}
|
2253
|
+
|
2254
|
+
static int compute_base(
|
2255
|
+
git_annotated_commit **out,
|
2256
|
+
git_repository *repo,
|
2257
|
+
const git_annotated_commit *one,
|
2258
|
+
const git_annotated_commit *two,
|
2259
|
+
const git_merge_options *given_opts,
|
2260
|
+
size_t recursion_level)
|
2261
|
+
{
|
2262
|
+
git_array_oid_t head_ids = GIT_ARRAY_INIT;
|
2263
|
+
git_oidarray bases = {0};
|
2264
|
+
git_annotated_commit *base = NULL, *other = NULL, *new_base = NULL;
|
2265
|
+
git_merge_options opts = GIT_MERGE_OPTIONS_INIT;
|
2266
|
+
size_t i, base_count;
|
2267
|
+
int error;
|
2268
|
+
|
2269
|
+
*out = NULL;
|
2270
|
+
|
2271
|
+
if (given_opts)
|
2272
|
+
memcpy(&opts, given_opts, sizeof(git_merge_options));
|
2273
|
+
|
2274
|
+
/* With more than two commits, merge_bases_many finds the base of
|
2275
|
+
* the first commit and a hypothetical merge of the others. Since
|
2276
|
+
* "one" may itself be a virtual commit, which insert_head_ids
|
2277
|
+
* substitutes multiple ancestors for, it needs to be added
|
2278
|
+
* after "two" which is always a single real commit.
|
2279
|
+
*/
|
2280
|
+
if ((error = insert_head_ids(&head_ids, two)) < 0 ||
|
2281
|
+
(error = insert_head_ids(&head_ids, one)) < 0 ||
|
2282
|
+
(error = git_merge_bases_many(&bases, repo,
|
2283
|
+
head_ids.size, head_ids.ptr)) < 0)
|
2284
|
+
goto done;
|
2285
|
+
|
2286
|
+
base_count = (opts.flags & GIT_MERGE_NO_RECURSIVE) ? 0 : bases.count;
|
2287
|
+
|
2288
|
+
if (base_count)
|
2289
|
+
git_oidarray__reverse(&bases);
|
2290
|
+
|
2291
|
+
if ((error = git_annotated_commit_lookup(&base, repo, &bases.ids[0])) < 0)
|
2292
|
+
goto done;
|
2293
|
+
|
2294
|
+
for (i = 1; i < base_count; i++) {
|
2295
|
+
recursion_level++;
|
2296
|
+
|
2297
|
+
if (opts.recursion_limit && recursion_level > opts.recursion_limit)
|
2298
|
+
break;
|
2299
|
+
|
2300
|
+
if ((error = git_annotated_commit_lookup(&other, repo,
|
2301
|
+
&bases.ids[i])) < 0 ||
|
2302
|
+
(error = create_virtual_base(&new_base, repo, base, other, &opts,
|
2303
|
+
recursion_level)) < 0)
|
2304
|
+
goto done;
|
2305
|
+
|
2306
|
+
git_annotated_commit_free(base);
|
2307
|
+
git_annotated_commit_free(other);
|
2308
|
+
|
2309
|
+
base = new_base;
|
2310
|
+
new_base = NULL;
|
2311
|
+
other = NULL;
|
2312
|
+
}
|
2313
|
+
|
2314
|
+
done:
|
2315
|
+
if (error == 0)
|
2316
|
+
*out = base;
|
2317
|
+
else
|
2318
|
+
git_annotated_commit_free(base);
|
1632
2319
|
|
1633
|
-
|
2320
|
+
git_annotated_commit_free(other);
|
2321
|
+
git_annotated_commit_free(new_base);
|
2322
|
+
git_oidarray_free(&bases);
|
2323
|
+
git_array_clear(head_ids);
|
2324
|
+
return error;
|
2325
|
+
}
|
2326
|
+
|
2327
|
+
static int iterator_for_annotated_commit(
|
2328
|
+
git_iterator **out,
|
2329
|
+
git_annotated_commit *commit)
|
2330
|
+
{
|
2331
|
+
git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT;
|
2332
|
+
int error;
|
2333
|
+
|
2334
|
+
opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;
|
1634
2335
|
|
2336
|
+
if (commit == NULL) {
|
2337
|
+
error = git_iterator_for_nothing(out, &opts);
|
2338
|
+
} else if (commit->type == GIT_ANNOTATED_COMMIT_VIRTUAL) {
|
2339
|
+
error = git_iterator_for_index(out, git_index_owner(commit->index), commit->index, &opts);
|
2340
|
+
} else {
|
2341
|
+
if (!commit->tree &&
|
2342
|
+
(error = git_commit_tree(&commit->tree, commit->commit)) < 0)
|
2343
|
+
goto done;
|
2344
|
+
|
2345
|
+
error = git_iterator_for_tree(out, commit->tree, &opts);
|
2346
|
+
}
|
2347
|
+
|
2348
|
+
done:
|
1635
2349
|
return error;
|
1636
2350
|
}
|
1637
2351
|
|
2352
|
+
static int merge_annotated_commits(
|
2353
|
+
git_index **index_out,
|
2354
|
+
git_annotated_commit **base_out,
|
2355
|
+
git_repository *repo,
|
2356
|
+
git_annotated_commit *ours,
|
2357
|
+
git_annotated_commit *theirs,
|
2358
|
+
size_t recursion_level,
|
2359
|
+
const git_merge_options *opts)
|
2360
|
+
{
|
2361
|
+
git_annotated_commit *base = NULL;
|
2362
|
+
git_iterator *base_iter = NULL, *our_iter = NULL, *their_iter = NULL;
|
2363
|
+
int error;
|
2364
|
+
|
2365
|
+
if ((error = compute_base(&base, repo, ours, theirs, opts,
|
2366
|
+
recursion_level)) < 0) {
|
2367
|
+
|
2368
|
+
if (error != GIT_ENOTFOUND)
|
2369
|
+
goto done;
|
2370
|
+
|
2371
|
+
git_error_clear();
|
2372
|
+
}
|
2373
|
+
|
2374
|
+
if ((error = iterator_for_annotated_commit(&base_iter, base)) < 0 ||
|
2375
|
+
(error = iterator_for_annotated_commit(&our_iter, ours)) < 0 ||
|
2376
|
+
(error = iterator_for_annotated_commit(&their_iter, theirs)) < 0 ||
|
2377
|
+
(error = git_merge__iterators(index_out, repo, base_iter, our_iter,
|
2378
|
+
their_iter, opts)) < 0)
|
2379
|
+
goto done;
|
2380
|
+
|
2381
|
+
if (base_out) {
|
2382
|
+
*base_out = base;
|
2383
|
+
base = NULL;
|
2384
|
+
}
|
2385
|
+
|
2386
|
+
done:
|
2387
|
+
git_annotated_commit_free(base);
|
2388
|
+
git_iterator_free(base_iter);
|
2389
|
+
git_iterator_free(our_iter);
|
2390
|
+
git_iterator_free(their_iter);
|
2391
|
+
return error;
|
2392
|
+
}
|
2393
|
+
|
2394
|
+
|
2395
|
+
int git_merge_commits(
|
2396
|
+
git_index **out,
|
2397
|
+
git_repository *repo,
|
2398
|
+
const git_commit *our_commit,
|
2399
|
+
const git_commit *their_commit,
|
2400
|
+
const git_merge_options *opts)
|
2401
|
+
{
|
2402
|
+
git_annotated_commit *ours = NULL, *theirs = NULL, *base = NULL;
|
2403
|
+
int error = 0;
|
2404
|
+
|
2405
|
+
if ((error = git_annotated_commit_from_commit(&ours, (git_commit *)our_commit)) < 0 ||
|
2406
|
+
(error = git_annotated_commit_from_commit(&theirs, (git_commit *)their_commit)) < 0)
|
2407
|
+
goto done;
|
2408
|
+
|
2409
|
+
error = merge_annotated_commits(out, &base, repo, ours, theirs, 0, opts);
|
2410
|
+
|
2411
|
+
done:
|
2412
|
+
git_annotated_commit_free(ours);
|
2413
|
+
git_annotated_commit_free(theirs);
|
2414
|
+
git_annotated_commit_free(base);
|
2415
|
+
return error;
|
2416
|
+
}
|
2417
|
+
|
2418
|
+
/* Merge setup / cleanup */
|
2419
|
+
|
1638
2420
|
static int write_merge_head(
|
1639
2421
|
git_repository *repo,
|
1640
|
-
const
|
2422
|
+
const git_annotated_commit *heads[],
|
1641
2423
|
size_t heads_len)
|
1642
2424
|
{
|
1643
2425
|
git_filebuf file = GIT_FILEBUF_INIT;
|
1644
2426
|
git_buf file_path = GIT_BUF_INIT;
|
1645
|
-
char merge_oid_str[GIT_OID_HEXSZ + 1];
|
1646
2427
|
size_t i;
|
1647
2428
|
int error = 0;
|
1648
2429
|
|
1649
2430
|
assert(repo && heads);
|
1650
2431
|
|
1651
|
-
if ((error = git_buf_joinpath(&file_path, repo->
|
1652
|
-
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE)) < 0)
|
2432
|
+
if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_HEAD_FILE)) < 0 ||
|
2433
|
+
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0)
|
1653
2434
|
goto cleanup;
|
1654
2435
|
|
1655
2436
|
for (i = 0; i < heads_len; i++) {
|
1656
|
-
|
1657
|
-
|
1658
|
-
if ((error = git_filebuf_printf(&file, "%s\n", merge_oid_str)) < 0)
|
2437
|
+
if ((error = git_filebuf_printf(&file, "%s\n", heads[i]->id_str)) < 0)
|
1659
2438
|
goto cleanup;
|
1660
2439
|
}
|
1661
2440
|
|
1662
|
-
error = git_filebuf_commit(&file
|
2441
|
+
error = git_filebuf_commit(&file);
|
1663
2442
|
|
1664
2443
|
cleanup:
|
1665
2444
|
if (error < 0)
|
1666
2445
|
git_filebuf_cleanup(&file);
|
1667
2446
|
|
1668
|
-
|
2447
|
+
git_buf_dispose(&file_path);
|
1669
2448
|
|
1670
2449
|
return error;
|
1671
2450
|
}
|
1672
2451
|
|
1673
|
-
static int write_merge_mode(git_repository *repo
|
2452
|
+
static int write_merge_mode(git_repository *repo)
|
1674
2453
|
{
|
1675
2454
|
git_filebuf file = GIT_FILEBUF_INIT;
|
1676
2455
|
git_buf file_path = GIT_BUF_INIT;
|
1677
2456
|
int error = 0;
|
1678
2457
|
|
1679
|
-
/* For future expansion */
|
1680
|
-
GIT_UNUSED(flags);
|
1681
|
-
|
1682
2458
|
assert(repo);
|
1683
2459
|
|
1684
|
-
if ((error = git_buf_joinpath(&file_path, repo->
|
1685
|
-
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE)) < 0)
|
2460
|
+
if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MODE_FILE)) < 0 ||
|
2461
|
+
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0)
|
1686
2462
|
goto cleanup;
|
1687
2463
|
|
1688
|
-
error =
|
2464
|
+
if ((error = git_filebuf_write(&file, "no-ff", 5)) < 0)
|
2465
|
+
goto cleanup;
|
2466
|
+
|
2467
|
+
error = git_filebuf_commit(&file);
|
1689
2468
|
|
1690
2469
|
cleanup:
|
1691
2470
|
if (error < 0)
|
1692
2471
|
git_filebuf_cleanup(&file);
|
1693
2472
|
|
1694
|
-
|
2473
|
+
git_buf_dispose(&file_path);
|
1695
2474
|
|
1696
2475
|
return error;
|
1697
2476
|
}
|
1698
2477
|
|
1699
2478
|
struct merge_msg_entry {
|
1700
|
-
const
|
2479
|
+
const git_annotated_commit *merge_head;
|
1701
2480
|
bool written;
|
1702
2481
|
};
|
1703
2482
|
|
@@ -1885,12 +2664,11 @@ static int merge_msg_write_remotes(
|
|
1885
2664
|
|
1886
2665
|
static int write_merge_msg(
|
1887
2666
|
git_repository *repo,
|
1888
|
-
const
|
2667
|
+
const git_annotated_commit *heads[],
|
1889
2668
|
size_t heads_len)
|
1890
2669
|
{
|
1891
2670
|
git_filebuf file = GIT_FILEBUF_INIT;
|
1892
2671
|
git_buf file_path = GIT_BUF_INIT;
|
1893
|
-
char oid_str[GIT_OID_HEXSZ + 1];
|
1894
2672
|
struct merge_msg_entry *entries;
|
1895
2673
|
git_vector matching = GIT_VECTOR_INIT;
|
1896
2674
|
size_t i;
|
@@ -1900,16 +2678,18 @@ static int write_merge_msg(
|
|
1900
2678
|
assert(repo && heads);
|
1901
2679
|
|
1902
2680
|
entries = git__calloc(heads_len, sizeof(struct merge_msg_entry));
|
1903
|
-
|
2681
|
+
GIT_ERROR_CHECK_ALLOC(entries);
|
1904
2682
|
|
1905
|
-
if (git_vector_init(&matching, heads_len, NULL) < 0)
|
2683
|
+
if (git_vector_init(&matching, heads_len, NULL) < 0) {
|
2684
|
+
git__free(entries);
|
1906
2685
|
return -1;
|
2686
|
+
}
|
1907
2687
|
|
1908
2688
|
for (i = 0; i < heads_len; i++)
|
1909
2689
|
entries[i].merge_head = heads[i];
|
1910
2690
|
|
1911
|
-
if ((error = git_buf_joinpath(&file_path, repo->
|
1912
|
-
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE)) < 0 ||
|
2691
|
+
if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 ||
|
2692
|
+
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0 ||
|
1913
2693
|
(error = git_filebuf_write(&file, "Merge ", 6)) < 0)
|
1914
2694
|
goto cleanup;
|
1915
2695
|
|
@@ -1928,10 +2708,9 @@ static int write_merge_msg(
|
|
1928
2708
|
if (!msg_entry_is_oid(&entries[i]))
|
1929
2709
|
break;
|
1930
2710
|
|
1931
|
-
|
1932
|
-
|
1933
|
-
|
1934
|
-
if ((error = git_filebuf_printf(&file, "%scommit '%s'", (i > 0) ? "; " : "", oid_str)) < 0)
|
2711
|
+
if ((error = git_filebuf_printf(&file,
|
2712
|
+
"%scommit '%s'", (i > 0) ? "; " : "",
|
2713
|
+
entries[i].merge_head->id_str)) < 0)
|
1935
2714
|
goto cleanup;
|
1936
2715
|
|
1937
2716
|
entries[i].written = 1;
|
@@ -1953,7 +2732,7 @@ static int write_merge_msg(
|
|
1953
2732
|
|
1954
2733
|
if (matching.length)
|
1955
2734
|
sep =',';
|
1956
|
-
|
2735
|
+
|
1957
2736
|
if ((error = merge_msg_entries(&matching, entries, heads_len, msg_entry_is_tag)) < 0 ||
|
1958
2737
|
(error = merge_msg_write_tags(&file, &matching, sep)) < 0)
|
1959
2738
|
goto cleanup;
|
@@ -1978,22 +2757,20 @@ static int write_merge_msg(
|
|
1978
2757
|
if (merge_msg_entry_written(&entries[i]))
|
1979
2758
|
continue;
|
1980
2759
|
|
1981
|
-
|
1982
|
-
|
1983
|
-
|
1984
|
-
if ((error = git_filebuf_printf(&file, "; commit '%s'", oid_str)) < 0)
|
2760
|
+
if ((error = git_filebuf_printf(&file, "; commit '%s'",
|
2761
|
+
entries[i].merge_head->id_str)) < 0)
|
1985
2762
|
goto cleanup;
|
1986
2763
|
}
|
1987
2764
|
|
1988
2765
|
if ((error = git_filebuf_printf(&file, "\n")) < 0 ||
|
1989
|
-
(error = git_filebuf_commit(&file
|
2766
|
+
(error = git_filebuf_commit(&file)) < 0)
|
1990
2767
|
goto cleanup;
|
1991
2768
|
|
1992
2769
|
cleanup:
|
1993
2770
|
if (error < 0)
|
1994
2771
|
git_filebuf_cleanup(&file);
|
1995
2772
|
|
1996
|
-
|
2773
|
+
git_buf_dispose(&file_path);
|
1997
2774
|
|
1998
2775
|
git_vector_free(&matching);
|
1999
2776
|
git__free(entries);
|
@@ -2003,154 +2780,577 @@ cleanup:
|
|
2003
2780
|
|
2004
2781
|
int git_merge__setup(
|
2005
2782
|
git_repository *repo,
|
2006
|
-
const
|
2007
|
-
const
|
2008
|
-
size_t heads_len
|
2009
|
-
unsigned int flags)
|
2783
|
+
const git_annotated_commit *our_head,
|
2784
|
+
const git_annotated_commit *heads[],
|
2785
|
+
size_t heads_len)
|
2010
2786
|
{
|
2011
2787
|
int error = 0;
|
2012
2788
|
|
2013
2789
|
assert (repo && our_head && heads);
|
2014
|
-
|
2015
|
-
if ((error =
|
2790
|
+
|
2791
|
+
if ((error = git_repository__set_orig_head(repo, git_annotated_commit_id(our_head))) == 0 &&
|
2016
2792
|
(error = write_merge_head(repo, heads, heads_len)) == 0 &&
|
2017
|
-
(error = write_merge_mode(repo
|
2793
|
+
(error = write_merge_mode(repo)) == 0) {
|
2018
2794
|
error = write_merge_msg(repo, heads, heads_len);
|
2019
2795
|
}
|
2020
2796
|
|
2021
2797
|
return error;
|
2022
2798
|
}
|
2023
2799
|
|
2024
|
-
|
2800
|
+
/* Merge branches */
|
2801
|
+
|
2802
|
+
static int merge_ancestor_head(
|
2803
|
+
git_annotated_commit **ancestor_head,
|
2804
|
+
git_repository *repo,
|
2805
|
+
const git_annotated_commit *our_head,
|
2806
|
+
const git_annotated_commit **their_heads,
|
2807
|
+
size_t their_heads_len)
|
2025
2808
|
{
|
2809
|
+
git_oid *oids, ancestor_oid;
|
2810
|
+
size_t i, alloc_len;
|
2026
2811
|
int error = 0;
|
2027
|
-
git_buf merge_head_path = GIT_BUF_INIT,
|
2028
|
-
merge_mode_path = GIT_BUF_INIT,
|
2029
|
-
merge_msg_path = GIT_BUF_INIT;
|
2030
2812
|
|
2031
|
-
assert(repo);
|
2813
|
+
assert(repo && our_head && their_heads);
|
2032
2814
|
|
2033
|
-
|
2034
|
-
|
2035
|
-
|
2036
|
-
return -1;
|
2815
|
+
GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, their_heads_len, 1);
|
2816
|
+
oids = git__calloc(alloc_len, sizeof(git_oid));
|
2817
|
+
GIT_ERROR_CHECK_ALLOC(oids);
|
2037
2818
|
|
2038
|
-
|
2039
|
-
if ((error = p_unlink(merge_head_path.ptr)) < 0)
|
2040
|
-
goto cleanup;
|
2041
|
-
}
|
2819
|
+
git_oid_cpy(&oids[0], git_commit_id(our_head->commit));
|
2042
2820
|
|
2043
|
-
|
2044
|
-
(
|
2821
|
+
for (i = 0; i < their_heads_len; i++)
|
2822
|
+
git_oid_cpy(&oids[i + 1], git_annotated_commit_id(their_heads[i]));
|
2045
2823
|
|
2046
|
-
if (
|
2047
|
-
|
2824
|
+
if ((error = git_merge_base_many(&ancestor_oid, repo, their_heads_len + 1, oids)) < 0)
|
2825
|
+
goto on_error;
|
2048
2826
|
|
2049
|
-
|
2050
|
-
git_buf_free(&merge_msg_path);
|
2051
|
-
git_buf_free(&merge_mode_path);
|
2052
|
-
git_buf_free(&merge_head_path);
|
2827
|
+
error = git_annotated_commit_lookup(ancestor_head, repo, &ancestor_oid);
|
2053
2828
|
|
2829
|
+
on_error:
|
2830
|
+
git__free(oids);
|
2054
2831
|
return error;
|
2055
2832
|
}
|
2056
2833
|
|
2057
|
-
|
2834
|
+
const char *merge_their_label(const char *branchname)
|
2835
|
+
{
|
2836
|
+
const char *slash;
|
2837
|
+
|
2838
|
+
if ((slash = strrchr(branchname, '/')) == NULL)
|
2839
|
+
return branchname;
|
2840
|
+
|
2841
|
+
if (*(slash+1) == '\0')
|
2842
|
+
return "theirs";
|
2843
|
+
|
2844
|
+
return slash+1;
|
2845
|
+
}
|
2058
2846
|
|
2059
|
-
static int
|
2060
|
-
|
2847
|
+
static int merge_normalize_checkout_opts(
|
2848
|
+
git_checkout_options *out,
|
2061
2849
|
git_repository *repo,
|
2062
|
-
const
|
2063
|
-
|
2064
|
-
|
2850
|
+
const git_checkout_options *given_checkout_opts,
|
2851
|
+
unsigned int checkout_strategy,
|
2852
|
+
git_annotated_commit *ancestor,
|
2853
|
+
const git_annotated_commit *our_head,
|
2854
|
+
const git_annotated_commit **their_heads,
|
2855
|
+
size_t their_heads_len)
|
2065
2856
|
{
|
2066
|
-
|
2857
|
+
git_checkout_options default_checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
|
2067
2858
|
int error = 0;
|
2068
2859
|
|
2069
|
-
|
2860
|
+
GIT_UNUSED(repo);
|
2070
2861
|
|
2071
|
-
|
2862
|
+
if (given_checkout_opts != NULL)
|
2863
|
+
memcpy(out, given_checkout_opts, sizeof(git_checkout_options));
|
2864
|
+
else
|
2865
|
+
memcpy(out, &default_checkout_opts, sizeof(git_checkout_options));
|
2072
2866
|
|
2073
|
-
|
2074
|
-
GITERR_CHECK_ALLOC(head);
|
2867
|
+
out->checkout_strategy = checkout_strategy;
|
2075
2868
|
|
2076
|
-
if (
|
2077
|
-
|
2078
|
-
|
2869
|
+
if (!out->ancestor_label) {
|
2870
|
+
if (ancestor && ancestor->type == GIT_ANNOTATED_COMMIT_REAL)
|
2871
|
+
out->ancestor_label = git_commit_summary(ancestor->commit);
|
2872
|
+
else if (ancestor)
|
2873
|
+
out->ancestor_label = "merged common ancestors";
|
2874
|
+
else
|
2875
|
+
out->ancestor_label = "empty base";
|
2079
2876
|
}
|
2080
2877
|
|
2081
|
-
if (
|
2082
|
-
|
2083
|
-
|
2878
|
+
if (!out->our_label) {
|
2879
|
+
if (our_head && our_head->ref_name)
|
2880
|
+
out->our_label = our_head->ref_name;
|
2881
|
+
else
|
2882
|
+
out->our_label = "ours";
|
2084
2883
|
}
|
2085
2884
|
|
2086
|
-
|
2885
|
+
if (!out->their_label) {
|
2886
|
+
if (their_heads_len == 1 && their_heads[0]->ref_name)
|
2887
|
+
out->their_label = merge_their_label(their_heads[0]->ref_name);
|
2888
|
+
else if (their_heads_len == 1)
|
2889
|
+
out->their_label = their_heads[0]->id_str;
|
2890
|
+
else
|
2891
|
+
out->their_label = "theirs";
|
2892
|
+
}
|
2087
2893
|
|
2088
|
-
|
2089
|
-
|
2090
|
-
|
2894
|
+
return error;
|
2895
|
+
}
|
2896
|
+
|
2897
|
+
static int merge_check_index(size_t *conflicts, git_repository *repo, git_index *index_new, git_vector *merged_paths)
|
2898
|
+
{
|
2899
|
+
git_tree *head_tree = NULL;
|
2900
|
+
git_index *index_repo = NULL;
|
2901
|
+
git_iterator *iter_repo = NULL, *iter_new = NULL;
|
2902
|
+
git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
|
2903
|
+
git_diff *staged_diff_list = NULL, *index_diff_list = NULL;
|
2904
|
+
git_diff_delta *delta;
|
2905
|
+
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
|
2906
|
+
git_vector staged_paths = GIT_VECTOR_INIT;
|
2907
|
+
size_t i;
|
2908
|
+
int error = 0;
|
2909
|
+
|
2910
|
+
GIT_UNUSED(merged_paths);
|
2911
|
+
|
2912
|
+
*conflicts = 0;
|
2913
|
+
|
2914
|
+
/* No staged changes may exist unless the change staged is identical to
|
2915
|
+
* the result of the merge. This allows one to apply to merge manually,
|
2916
|
+
* then run merge. Any other staged change would be overwritten by
|
2917
|
+
* a reset merge.
|
2918
|
+
*/
|
2919
|
+
if ((error = git_repository_head_tree(&head_tree, repo)) < 0 ||
|
2920
|
+
(error = git_repository_index(&index_repo, repo)) < 0 ||
|
2921
|
+
(error = git_diff_tree_to_index(&staged_diff_list, repo, head_tree, index_repo, &opts)) < 0)
|
2922
|
+
goto done;
|
2923
|
+
|
2924
|
+
if (staged_diff_list->deltas.length == 0)
|
2925
|
+
goto done;
|
2926
|
+
|
2927
|
+
git_vector_foreach(&staged_diff_list->deltas, i, delta) {
|
2928
|
+
if ((error = git_vector_insert(&staged_paths, (char *)delta->new_file.path)) < 0)
|
2929
|
+
goto done;
|
2091
2930
|
}
|
2092
2931
|
|
2093
|
-
|
2932
|
+
iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;
|
2933
|
+
iter_opts.pathlist.strings = (char **)staged_paths.contents;
|
2934
|
+
iter_opts.pathlist.count = staged_paths.length;
|
2935
|
+
|
2936
|
+
if ((error = git_iterator_for_index(&iter_repo, repo, index_repo, &iter_opts)) < 0 ||
|
2937
|
+
(error = git_iterator_for_index(&iter_new, repo, index_new, &iter_opts)) < 0 ||
|
2938
|
+
(error = git_diff__from_iterators(&index_diff_list, repo, iter_repo, iter_new, &opts)) < 0)
|
2939
|
+
goto done;
|
2940
|
+
|
2941
|
+
*conflicts = index_diff_list->deltas.length;
|
2942
|
+
|
2943
|
+
done:
|
2944
|
+
git_tree_free(head_tree);
|
2945
|
+
git_index_free(index_repo);
|
2946
|
+
git_iterator_free(iter_repo);
|
2947
|
+
git_iterator_free(iter_new);
|
2948
|
+
git_diff_free(staged_diff_list);
|
2949
|
+
git_diff_free(index_diff_list);
|
2950
|
+
git_vector_free(&staged_paths);
|
2951
|
+
|
2094
2952
|
return error;
|
2095
2953
|
}
|
2096
2954
|
|
2097
|
-
int
|
2098
|
-
|
2955
|
+
static int merge_check_workdir(size_t *conflicts, git_repository *repo, git_index *index_new, git_vector *merged_paths)
|
2956
|
+
{
|
2957
|
+
git_diff *wd_diff_list = NULL;
|
2958
|
+
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
|
2959
|
+
int error = 0;
|
2960
|
+
|
2961
|
+
GIT_UNUSED(index_new);
|
2962
|
+
|
2963
|
+
*conflicts = 0;
|
2964
|
+
|
2965
|
+
/* We need to have merged at least 1 file for the possibility to exist to
|
2966
|
+
* have conflicts with the workdir. Passing 0 as the pathspec count paramter
|
2967
|
+
* will consider all files in the working directory, that is, we may detect
|
2968
|
+
* a conflict if there were untracked files in the workdir prior to starting
|
2969
|
+
* the merge. This typically happens when cherry-picking a commmit whose
|
2970
|
+
* changes have already been applied.
|
2971
|
+
*/
|
2972
|
+
if (merged_paths->length == 0)
|
2973
|
+
return 0;
|
2974
|
+
|
2975
|
+
opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED;
|
2976
|
+
|
2977
|
+
/* Workdir changes may exist iff they do not conflict with changes that
|
2978
|
+
* will be applied by the merge (including conflicts). Ensure that there
|
2979
|
+
* are no changes in the workdir to these paths.
|
2980
|
+
*/
|
2981
|
+
opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH;
|
2982
|
+
opts.pathspec.count = merged_paths->length;
|
2983
|
+
opts.pathspec.strings = (char **)merged_paths->contents;
|
2984
|
+
opts.ignore_submodules = GIT_SUBMODULE_IGNORE_ALL;
|
2985
|
+
|
2986
|
+
if ((error = git_diff_index_to_workdir(&wd_diff_list, repo, NULL, &opts)) < 0)
|
2987
|
+
goto done;
|
2988
|
+
|
2989
|
+
*conflicts = wd_diff_list->deltas.length;
|
2990
|
+
|
2991
|
+
done:
|
2992
|
+
git_diff_free(wd_diff_list);
|
2993
|
+
|
2994
|
+
return error;
|
2995
|
+
}
|
2996
|
+
|
2997
|
+
int git_merge__check_result(git_repository *repo, git_index *index_new)
|
2998
|
+
{
|
2999
|
+
git_tree *head_tree = NULL;
|
3000
|
+
git_iterator *iter_head = NULL, *iter_new = NULL;
|
3001
|
+
git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
|
3002
|
+
git_diff *merged_list = NULL;
|
3003
|
+
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
|
3004
|
+
git_diff_delta *delta;
|
3005
|
+
git_vector paths = GIT_VECTOR_INIT;
|
3006
|
+
size_t i, index_conflicts = 0, wd_conflicts = 0, conflicts;
|
3007
|
+
const git_index_entry *e;
|
3008
|
+
int error = 0;
|
3009
|
+
|
3010
|
+
iter_opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE;
|
3011
|
+
|
3012
|
+
if ((error = git_repository_head_tree(&head_tree, repo)) < 0 ||
|
3013
|
+
(error = git_iterator_for_tree(&iter_head, head_tree, &iter_opts)) < 0 ||
|
3014
|
+
(error = git_iterator_for_index(&iter_new, repo, index_new, &iter_opts)) < 0 ||
|
3015
|
+
(error = git_diff__from_iterators(&merged_list, repo, iter_head, iter_new, &opts)) < 0)
|
3016
|
+
goto done;
|
3017
|
+
|
3018
|
+
git_vector_foreach(&merged_list->deltas, i, delta) {
|
3019
|
+
if ((error = git_vector_insert(&paths, (char *)delta->new_file.path)) < 0)
|
3020
|
+
goto done;
|
3021
|
+
}
|
3022
|
+
|
3023
|
+
for (i = 0; i < git_index_entrycount(index_new); i++) {
|
3024
|
+
e = git_index_get_byindex(index_new, i);
|
3025
|
+
|
3026
|
+
if (git_index_entry_is_conflict(e) &&
|
3027
|
+
(git_vector_last(&paths) == NULL ||
|
3028
|
+
strcmp(git_vector_last(&paths), e->path) != 0)) {
|
3029
|
+
|
3030
|
+
if ((error = git_vector_insert(&paths, (char *)e->path)) < 0)
|
3031
|
+
goto done;
|
3032
|
+
}
|
3033
|
+
}
|
3034
|
+
|
3035
|
+
/* Make sure the index and workdir state do not prevent merging */
|
3036
|
+
if ((error = merge_check_index(&index_conflicts, repo, index_new, &paths)) < 0 ||
|
3037
|
+
(error = merge_check_workdir(&wd_conflicts, repo, index_new, &paths)) < 0)
|
3038
|
+
goto done;
|
3039
|
+
|
3040
|
+
if ((conflicts = index_conflicts + wd_conflicts) > 0) {
|
3041
|
+
git_error_set(GIT_ERROR_MERGE, "%" PRIuZ " uncommitted change%s would be overwritten by merge",
|
3042
|
+
conflicts, (conflicts != 1) ? "s" : "");
|
3043
|
+
error = GIT_ECONFLICT;
|
3044
|
+
}
|
3045
|
+
|
3046
|
+
done:
|
3047
|
+
git_vector_free(&paths);
|
3048
|
+
git_tree_free(head_tree);
|
3049
|
+
git_iterator_free(iter_head);
|
3050
|
+
git_iterator_free(iter_new);
|
3051
|
+
git_diff_free(merged_list);
|
3052
|
+
|
3053
|
+
return error;
|
3054
|
+
}
|
3055
|
+
|
3056
|
+
int git_merge__append_conflicts_to_merge_msg(
|
3057
|
+
git_repository *repo,
|
3058
|
+
git_index *index)
|
3059
|
+
{
|
3060
|
+
git_filebuf file = GIT_FILEBUF_INIT;
|
3061
|
+
git_buf file_path = GIT_BUF_INIT;
|
3062
|
+
const char *last = NULL;
|
3063
|
+
size_t i;
|
3064
|
+
int error;
|
3065
|
+
|
3066
|
+
if (!git_index_has_conflicts(index))
|
3067
|
+
return 0;
|
3068
|
+
|
3069
|
+
if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 ||
|
3070
|
+
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_APPEND, GIT_MERGE_FILE_MODE)) < 0)
|
3071
|
+
goto cleanup;
|
3072
|
+
|
3073
|
+
git_filebuf_printf(&file, "\nConflicts:\n");
|
3074
|
+
|
3075
|
+
for (i = 0; i < git_index_entrycount(index); i++) {
|
3076
|
+
const git_index_entry *e = git_index_get_byindex(index, i);
|
3077
|
+
|
3078
|
+
if (!git_index_entry_is_conflict(e))
|
3079
|
+
continue;
|
3080
|
+
|
3081
|
+
if (last == NULL || strcmp(e->path, last) != 0)
|
3082
|
+
git_filebuf_printf(&file, "\t%s\n", e->path);
|
3083
|
+
|
3084
|
+
last = e->path;
|
3085
|
+
}
|
3086
|
+
|
3087
|
+
error = git_filebuf_commit(&file);
|
3088
|
+
|
3089
|
+
cleanup:
|
3090
|
+
if (error < 0)
|
3091
|
+
git_filebuf_cleanup(&file);
|
3092
|
+
|
3093
|
+
git_buf_dispose(&file_path);
|
3094
|
+
|
3095
|
+
return error;
|
3096
|
+
}
|
3097
|
+
|
3098
|
+
static int merge_state_cleanup(git_repository *repo)
|
3099
|
+
{
|
3100
|
+
const char *state_files[] = {
|
3101
|
+
GIT_MERGE_HEAD_FILE,
|
3102
|
+
GIT_MERGE_MODE_FILE,
|
3103
|
+
GIT_MERGE_MSG_FILE,
|
3104
|
+
};
|
3105
|
+
|
3106
|
+
return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files));
|
3107
|
+
}
|
3108
|
+
|
3109
|
+
static int merge_heads(
|
3110
|
+
git_annotated_commit **ancestor_head_out,
|
3111
|
+
git_annotated_commit **our_head_out,
|
2099
3112
|
git_repository *repo,
|
2100
|
-
git_reference *
|
3113
|
+
git_reference *our_ref,
|
3114
|
+
const git_annotated_commit **their_heads,
|
3115
|
+
size_t their_heads_len)
|
2101
3116
|
{
|
2102
|
-
|
3117
|
+
git_annotated_commit *ancestor_head = NULL, *our_head = NULL;
|
2103
3118
|
int error = 0;
|
2104
3119
|
|
2105
|
-
|
3120
|
+
*ancestor_head_out = NULL;
|
3121
|
+
*our_head_out = NULL;
|
2106
3122
|
|
2107
|
-
|
3123
|
+
if ((error = git_repository__ensure_not_bare(repo, "merge")) < 0)
|
3124
|
+
goto done;
|
2108
3125
|
|
2109
|
-
if ((error =
|
2110
|
-
|
2111
|
-
|
2112
|
-
error =
|
2113
|
-
|
3126
|
+
if ((error = git_annotated_commit_from_ref(&our_head, repo, our_ref)) < 0)
|
3127
|
+
goto done;
|
3128
|
+
|
3129
|
+
if ((error = merge_ancestor_head(&ancestor_head, repo, our_head, their_heads, their_heads_len)) < 0) {
|
3130
|
+
if (error != GIT_ENOTFOUND)
|
3131
|
+
goto done;
|
3132
|
+
|
3133
|
+
git_error_clear();
|
3134
|
+
error = 0;
|
3135
|
+
}
|
3136
|
+
|
3137
|
+
*ancestor_head_out = ancestor_head;
|
3138
|
+
*our_head_out = our_head;
|
3139
|
+
|
3140
|
+
done:
|
3141
|
+
if (error < 0) {
|
3142
|
+
git_annotated_commit_free(ancestor_head);
|
3143
|
+
git_annotated_commit_free(our_head);
|
3144
|
+
}
|
2114
3145
|
|
2115
|
-
git_reference_free(resolved);
|
2116
3146
|
return error;
|
2117
3147
|
}
|
2118
3148
|
|
2119
|
-
int
|
2120
|
-
|
3149
|
+
static int merge_preference(git_merge_preference_t *out, git_repository *repo)
|
3150
|
+
{
|
3151
|
+
git_config *config;
|
3152
|
+
const char *value;
|
3153
|
+
int bool_value, error = 0;
|
3154
|
+
|
3155
|
+
*out = GIT_MERGE_PREFERENCE_NONE;
|
3156
|
+
|
3157
|
+
if ((error = git_repository_config_snapshot(&config, repo)) < 0)
|
3158
|
+
goto done;
|
3159
|
+
|
3160
|
+
if ((error = git_config_get_string(&value, config, "merge.ff")) < 0) {
|
3161
|
+
if (error == GIT_ENOTFOUND) {
|
3162
|
+
git_error_clear();
|
3163
|
+
error = 0;
|
3164
|
+
}
|
3165
|
+
|
3166
|
+
goto done;
|
3167
|
+
}
|
3168
|
+
|
3169
|
+
if (git_config_parse_bool(&bool_value, value) == 0) {
|
3170
|
+
if (!bool_value)
|
3171
|
+
*out |= GIT_MERGE_PREFERENCE_NO_FASTFORWARD;
|
3172
|
+
} else {
|
3173
|
+
if (strcasecmp(value, "only") == 0)
|
3174
|
+
*out |= GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY;
|
3175
|
+
}
|
3176
|
+
|
3177
|
+
done:
|
3178
|
+
git_config_free(config);
|
3179
|
+
return error;
|
3180
|
+
}
|
3181
|
+
|
3182
|
+
int git_merge_analysis_for_ref(
|
3183
|
+
git_merge_analysis_t *analysis_out,
|
3184
|
+
git_merge_preference_t *preference_out,
|
2121
3185
|
git_repository *repo,
|
2122
|
-
|
3186
|
+
git_reference *our_ref,
|
3187
|
+
const git_annotated_commit **their_heads,
|
3188
|
+
size_t their_heads_len)
|
2123
3189
|
{
|
2124
|
-
|
3190
|
+
git_annotated_commit *ancestor_head = NULL, *our_head = NULL;
|
3191
|
+
int error = 0;
|
3192
|
+
bool unborn;
|
3193
|
+
|
3194
|
+
assert(analysis_out && preference_out && repo && their_heads && their_heads_len > 0);
|
2125
3195
|
|
2126
|
-
|
3196
|
+
if (their_heads_len != 1) {
|
3197
|
+
git_error_set(GIT_ERROR_MERGE, "can only merge a single branch");
|
3198
|
+
error = -1;
|
3199
|
+
goto done;
|
3200
|
+
}
|
3201
|
+
|
3202
|
+
*analysis_out = GIT_MERGE_ANALYSIS_NONE;
|
3203
|
+
|
3204
|
+
if ((error = merge_preference(preference_out, repo)) < 0)
|
3205
|
+
goto done;
|
3206
|
+
|
3207
|
+
if ((error = git_reference__is_unborn_head(&unborn, our_ref, repo)) < 0)
|
3208
|
+
goto done;
|
3209
|
+
|
3210
|
+
if (unborn) {
|
3211
|
+
*analysis_out |= GIT_MERGE_ANALYSIS_FASTFORWARD | GIT_MERGE_ANALYSIS_UNBORN;
|
3212
|
+
error = 0;
|
3213
|
+
goto done;
|
3214
|
+
}
|
3215
|
+
|
3216
|
+
if ((error = merge_heads(&ancestor_head, &our_head, repo, our_ref, their_heads, their_heads_len)) < 0)
|
3217
|
+
goto done;
|
3218
|
+
|
3219
|
+
/* We're up-to-date if we're trying to merge our own common ancestor. */
|
3220
|
+
if (ancestor_head && git_oid_equal(
|
3221
|
+
git_annotated_commit_id(ancestor_head), git_annotated_commit_id(their_heads[0])))
|
3222
|
+
*analysis_out |= GIT_MERGE_ANALYSIS_UP_TO_DATE;
|
3223
|
+
|
3224
|
+
/* We're fastforwardable if we're our own common ancestor. */
|
3225
|
+
else if (ancestor_head && git_oid_equal(
|
3226
|
+
git_annotated_commit_id(ancestor_head), git_annotated_commit_id(our_head)))
|
3227
|
+
*analysis_out |= GIT_MERGE_ANALYSIS_FASTFORWARD | GIT_MERGE_ANALYSIS_NORMAL;
|
3228
|
+
|
3229
|
+
/* Otherwise, just a normal merge is possible. */
|
3230
|
+
else
|
3231
|
+
*analysis_out |= GIT_MERGE_ANALYSIS_NORMAL;
|
3232
|
+
|
3233
|
+
done:
|
3234
|
+
git_annotated_commit_free(ancestor_head);
|
3235
|
+
git_annotated_commit_free(our_head);
|
3236
|
+
return error;
|
2127
3237
|
}
|
2128
3238
|
|
2129
|
-
int
|
2130
|
-
|
3239
|
+
int git_merge_analysis(
|
3240
|
+
git_merge_analysis_t *analysis_out,
|
3241
|
+
git_merge_preference_t *preference_out,
|
2131
3242
|
git_repository *repo,
|
2132
|
-
const
|
2133
|
-
|
2134
|
-
const git_oid *oid)
|
3243
|
+
const git_annotated_commit **their_heads,
|
3244
|
+
size_t their_heads_len)
|
2135
3245
|
{
|
2136
|
-
|
3246
|
+
git_reference *head_ref = NULL;
|
3247
|
+
int error = 0;
|
2137
3248
|
|
2138
|
-
|
3249
|
+
if ((error = git_reference_lookup(&head_ref, repo, GIT_HEAD_FILE)) < 0) {
|
3250
|
+
git_error_set(GIT_ERROR_MERGE, "failed to lookup HEAD reference");
|
3251
|
+
return error;
|
3252
|
+
}
|
3253
|
+
|
3254
|
+
error = git_merge_analysis_for_ref(analysis_out, preference_out, repo, head_ref, their_heads, their_heads_len);
|
3255
|
+
|
3256
|
+
git_reference_free(head_ref);
|
3257
|
+
|
3258
|
+
return error;
|
2139
3259
|
}
|
2140
3260
|
|
2141
|
-
|
3261
|
+
int git_merge(
|
3262
|
+
git_repository *repo,
|
3263
|
+
const git_annotated_commit **their_heads,
|
3264
|
+
size_t their_heads_len,
|
3265
|
+
const git_merge_options *merge_opts,
|
3266
|
+
const git_checkout_options *given_checkout_opts)
|
2142
3267
|
{
|
2143
|
-
|
2144
|
-
|
3268
|
+
git_reference *our_ref = NULL;
|
3269
|
+
git_checkout_options checkout_opts;
|
3270
|
+
git_annotated_commit *our_head = NULL, *base = NULL;
|
3271
|
+
git_index *repo_index = NULL, *index = NULL;
|
3272
|
+
git_indexwriter indexwriter = GIT_INDEXWRITER_INIT;
|
3273
|
+
unsigned int checkout_strategy;
|
3274
|
+
int error = 0;
|
3275
|
+
|
3276
|
+
assert(repo && their_heads && their_heads_len > 0);
|
3277
|
+
|
3278
|
+
if (their_heads_len != 1) {
|
3279
|
+
git_error_set(GIT_ERROR_MERGE, "can only merge a single branch");
|
3280
|
+
return -1;
|
3281
|
+
}
|
3282
|
+
|
3283
|
+
if ((error = git_repository__ensure_not_bare(repo, "merge")) < 0)
|
3284
|
+
goto done;
|
3285
|
+
|
3286
|
+
checkout_strategy = given_checkout_opts ?
|
3287
|
+
given_checkout_opts->checkout_strategy :
|
3288
|
+
GIT_CHECKOUT_SAFE;
|
3289
|
+
|
3290
|
+
if ((error = git_indexwriter_init_for_operation(&indexwriter, repo,
|
3291
|
+
&checkout_strategy)) < 0)
|
3292
|
+
goto done;
|
3293
|
+
|
3294
|
+
if ((error = git_repository_index(&repo_index, repo) < 0) ||
|
3295
|
+
(error = git_index_read(repo_index, 0) < 0))
|
3296
|
+
goto done;
|
3297
|
+
|
3298
|
+
/* Write the merge setup files to the repository. */
|
3299
|
+
if ((error = git_annotated_commit_from_head(&our_head, repo)) < 0 ||
|
3300
|
+
(error = git_merge__setup(repo, our_head, their_heads,
|
3301
|
+
their_heads_len)) < 0)
|
3302
|
+
goto done;
|
2145
3303
|
|
2146
|
-
|
2147
|
-
git_object_free((git_object *)head->commit);
|
3304
|
+
/* TODO: octopus */
|
2148
3305
|
|
2149
|
-
if (
|
2150
|
-
|
3306
|
+
if ((error = merge_annotated_commits(&index, &base, repo, our_head,
|
3307
|
+
(git_annotated_commit *)their_heads[0], 0, merge_opts)) < 0 ||
|
3308
|
+
(error = git_merge__check_result(repo, index)) < 0 ||
|
3309
|
+
(error = git_merge__append_conflicts_to_merge_msg(repo, index)) < 0)
|
3310
|
+
goto done;
|
3311
|
+
|
3312
|
+
/* check out the merge results */
|
3313
|
+
|
3314
|
+
if ((error = merge_normalize_checkout_opts(&checkout_opts, repo,
|
3315
|
+
given_checkout_opts, checkout_strategy,
|
3316
|
+
base, our_head, their_heads, their_heads_len)) < 0 ||
|
3317
|
+
(error = git_checkout_index(repo, index, &checkout_opts)) < 0)
|
3318
|
+
goto done;
|
3319
|
+
|
3320
|
+
error = git_indexwriter_commit(&indexwriter);
|
3321
|
+
|
3322
|
+
done:
|
3323
|
+
if (error < 0)
|
3324
|
+
merge_state_cleanup(repo);
|
3325
|
+
|
3326
|
+
git_indexwriter_cleanup(&indexwriter);
|
3327
|
+
git_index_free(index);
|
3328
|
+
git_annotated_commit_free(our_head);
|
3329
|
+
git_annotated_commit_free(base);
|
3330
|
+
git_reference_free(our_ref);
|
3331
|
+
git_index_free(repo_index);
|
3332
|
+
|
3333
|
+
return error;
|
3334
|
+
}
|
2151
3335
|
|
2152
|
-
|
2153
|
-
|
3336
|
+
int git_merge_init_options(git_merge_options *opts, unsigned int version)
|
3337
|
+
{
|
3338
|
+
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
|
3339
|
+
opts, version, git_merge_options, GIT_MERGE_OPTIONS_INIT);
|
3340
|
+
return 0;
|
3341
|
+
}
|
2154
3342
|
|
2155
|
-
|
3343
|
+
int git_merge_file_init_input(git_merge_file_input *input, unsigned int version)
|
3344
|
+
{
|
3345
|
+
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
|
3346
|
+
input, version, git_merge_file_input, GIT_MERGE_FILE_INPUT_INIT);
|
3347
|
+
return 0;
|
3348
|
+
}
|
3349
|
+
|
3350
|
+
int git_merge_file_init_options(
|
3351
|
+
git_merge_file_options *opts, unsigned int version)
|
3352
|
+
{
|
3353
|
+
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
|
3354
|
+
opts, version, git_merge_file_options, GIT_MERGE_FILE_OPTIONS_INIT);
|
3355
|
+
return 0;
|
2156
3356
|
}
|