rugged 0.19.0 → 0.21.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 +151 -25
- data/ext/rugged/extconf.rb +48 -27
- data/ext/rugged/rugged.c +107 -35
- data/ext/rugged/rugged.h +44 -8
- data/ext/rugged/rugged_blame.c +292 -0
- data/ext/rugged/rugged_blob.c +84 -31
- data/ext/rugged/rugged_branch.c +90 -223
- data/ext/rugged/rugged_branch_collection.c +445 -0
- data/ext/rugged/rugged_commit.c +190 -9
- data/ext/rugged/rugged_config.c +1 -1
- data/ext/rugged/rugged_cred.c +125 -0
- data/ext/rugged/rugged_diff.c +267 -94
- data/ext/rugged/rugged_diff_delta.c +14 -3
- data/ext/rugged/rugged_diff_hunk.c +31 -28
- data/ext/rugged/rugged_diff_line.c +21 -17
- data/ext/rugged/rugged_index.c +326 -6
- data/ext/rugged/rugged_note.c +39 -34
- data/ext/rugged/rugged_object.c +9 -9
- data/ext/rugged/rugged_patch.c +245 -0
- data/ext/rugged/rugged_reference.c +67 -332
- data/ext/rugged/rugged_reference_collection.c +490 -0
- data/ext/rugged/rugged_remote.c +447 -351
- data/ext/rugged/rugged_remote_collection.c +285 -0
- data/ext/rugged/rugged_repo.c +752 -203
- data/ext/rugged/rugged_revwalk.c +119 -27
- data/ext/rugged/rugged_settings.c +48 -1
- data/ext/rugged/rugged_signature.c +30 -16
- data/ext/rugged/rugged_tag.c +86 -191
- data/ext/rugged/rugged_tag_collection.c +279 -0
- data/ext/rugged/rugged_tree.c +159 -22
- data/lib/rugged/branch.rb +8 -17
- data/lib/rugged/credentials.rb +43 -0
- data/lib/rugged/diff/delta.rb +1 -2
- data/lib/rugged/diff/hunk.rb +4 -9
- data/lib/rugged/diff/line.rb +23 -3
- data/lib/rugged/diff.rb +3 -1
- data/lib/rugged/patch.rb +26 -0
- data/lib/rugged/reference.rb +1 -3
- data/lib/rugged/remote.rb +0 -9
- data/lib/rugged/repository.rb +70 -13
- data/lib/rugged/tag.rb +23 -18
- data/lib/rugged/tree.rb +7 -0
- data/lib/rugged/version.rb +1 -1
- data/lib/rugged.rb +8 -1
- data/vendor/libgit2/AUTHORS +75 -0
- data/vendor/libgit2/CMakeLists.txt +490 -0
- data/vendor/libgit2/COPYING +920 -0
- data/vendor/libgit2/Makefile.embed +25 -7
- data/vendor/libgit2/cmake/Modules/AddCFlagIfSupported.cmake +16 -0
- data/vendor/libgit2/cmake/Modules/FindHTTP_Parser.cmake +39 -0
- data/vendor/libgit2/cmake/Modules/FindIconv.cmake +43 -0
- data/vendor/libgit2/cmake/Modules/FindLIBSSH2.cmake +44 -0
- data/vendor/libgit2/deps/http-parser/LICENSE-MIT +23 -0
- data/vendor/libgit2/deps/regex/regex.c +10 -3
- data/vendor/libgit2/include/git2/attr.h +2 -1
- data/vendor/libgit2/include/git2/blame.h +213 -0
- data/vendor/libgit2/include/git2/blob.h +57 -29
- data/vendor/libgit2/include/git2/branch.h +56 -44
- data/vendor/libgit2/include/git2/buffer.h +112 -0
- data/vendor/libgit2/include/git2/checkout.h +72 -37
- data/vendor/libgit2/include/git2/cherrypick.h +87 -0
- data/vendor/libgit2/include/git2/clone.h +153 -56
- data/vendor/libgit2/include/git2/commit.h +82 -12
- data/vendor/libgit2/include/git2/common.h +31 -19
- data/vendor/libgit2/include/git2/config.h +124 -19
- data/vendor/libgit2/include/git2/cred_helpers.h +1 -1
- data/vendor/libgit2/include/git2/diff.h +636 -494
- data/vendor/libgit2/include/git2/errors.h +48 -15
- data/vendor/libgit2/include/git2/filter.h +149 -0
- data/vendor/libgit2/include/git2/graph.h +14 -0
- data/vendor/libgit2/include/git2/index.h +95 -54
- data/vendor/libgit2/include/git2/indexer.h +15 -9
- data/vendor/libgit2/include/git2/merge.h +402 -39
- data/vendor/libgit2/include/git2/message.h +9 -14
- data/vendor/libgit2/include/git2/net.h +5 -0
- data/vendor/libgit2/include/git2/notes.h +6 -6
- data/vendor/libgit2/include/git2/object.h +34 -2
- data/vendor/libgit2/include/git2/odb.h +77 -14
- data/vendor/libgit2/include/git2/odb_backend.h +50 -6
- data/vendor/libgit2/include/git2/oid.h +4 -8
- data/vendor/libgit2/include/git2/pack.h +58 -4
- data/vendor/libgit2/include/git2/patch.h +277 -0
- data/vendor/libgit2/include/git2/pathspec.h +263 -0
- data/vendor/libgit2/include/git2/push.h +55 -5
- data/vendor/libgit2/include/git2/reflog.h +11 -8
- data/vendor/libgit2/include/git2/refs.h +219 -33
- data/vendor/libgit2/include/git2/refspec.h +3 -4
- data/vendor/libgit2/include/git2/remote.h +216 -76
- data/vendor/libgit2/include/git2/repository.h +85 -40
- data/vendor/libgit2/include/git2/reset.h +15 -4
- data/vendor/libgit2/include/git2/revert.h +86 -0
- data/vendor/libgit2/include/git2/revparse.h +27 -16
- data/vendor/libgit2/include/git2/revwalk.h +44 -6
- data/vendor/libgit2/include/git2/signature.h +17 -3
- data/vendor/libgit2/include/git2/stash.h +8 -12
- data/vendor/libgit2/include/git2/status.h +67 -18
- data/vendor/libgit2/include/git2/submodule.h +100 -85
- data/vendor/libgit2/include/git2/sys/commit.h +38 -4
- data/vendor/libgit2/include/git2/sys/config.h +44 -3
- data/vendor/libgit2/include/git2/sys/diff.h +91 -0
- data/vendor/libgit2/include/git2/sys/filter.h +301 -0
- data/vendor/libgit2/include/git2/sys/index.h +0 -2
- data/vendor/libgit2/include/git2/sys/mempack.h +85 -0
- data/vendor/libgit2/include/git2/sys/odb_backend.h +33 -11
- data/vendor/libgit2/include/git2/sys/refdb_backend.h +51 -5
- data/vendor/libgit2/include/git2/sys/reflog.h +21 -0
- data/vendor/libgit2/include/git2/sys/refs.h +2 -2
- data/vendor/libgit2/include/git2/sys/repository.h +19 -1
- data/vendor/libgit2/include/git2/transport.h +216 -75
- data/vendor/libgit2/include/git2/tree.h +32 -11
- data/vendor/libgit2/include/git2/types.h +124 -10
- data/vendor/libgit2/include/git2/version.h +4 -2
- data/vendor/libgit2/include/git2.h +41 -40
- data/vendor/libgit2/libgit2.pc.in +10 -0
- data/vendor/libgit2/src/array.h +16 -8
- data/vendor/libgit2/src/attr.c +140 -402
- data/vendor/libgit2/src/attr.h +1 -33
- data/vendor/libgit2/src/attr_file.c +298 -135
- data/vendor/libgit2/src/attr_file.h +61 -22
- data/vendor/libgit2/src/attrcache.c +449 -0
- data/vendor/libgit2/src/attrcache.h +38 -6
- data/vendor/libgit2/src/bitvec.h +75 -0
- data/vendor/libgit2/src/blame.c +488 -0
- data/vendor/libgit2/src/blame.h +93 -0
- data/vendor/libgit2/src/blame_git.c +624 -0
- data/vendor/libgit2/src/blame_git.h +20 -0
- data/vendor/libgit2/src/blob.c +137 -92
- data/vendor/libgit2/src/blob.h +9 -0
- data/vendor/libgit2/src/branch.c +175 -156
- data/vendor/libgit2/src/buf_text.c +29 -14
- data/vendor/libgit2/src/buf_text.h +5 -4
- data/vendor/libgit2/src/buffer.c +158 -15
- data/vendor/libgit2/src/buffer.h +33 -20
- data/vendor/libgit2/src/cc-compat.h +8 -2
- data/vendor/libgit2/src/checkout.c +1081 -287
- data/vendor/libgit2/src/checkout.h +1 -1
- data/vendor/libgit2/src/cherrypick.c +226 -0
- data/vendor/libgit2/src/clone.c +297 -245
- data/vendor/libgit2/src/{compress.h → clone.h} +4 -8
- data/vendor/libgit2/src/commit.c +313 -101
- data/vendor/libgit2/src/commit.h +6 -3
- data/vendor/libgit2/src/commit_list.c +3 -3
- data/vendor/libgit2/src/commit_list.h +1 -1
- data/vendor/libgit2/src/common.h +74 -1
- data/vendor/libgit2/src/config.c +570 -145
- data/vendor/libgit2/src/config.h +39 -6
- data/vendor/libgit2/src/config_cache.c +32 -18
- data/vendor/libgit2/src/config_file.c +711 -424
- data/vendor/libgit2/src/config_file.h +4 -3
- data/vendor/libgit2/src/crlf.c +149 -109
- data/vendor/libgit2/src/date.c +35 -7
- data/vendor/libgit2/src/delta.c +1 -1
- data/vendor/libgit2/src/diff.c +719 -414
- data/vendor/libgit2/src/diff.h +52 -7
- data/vendor/libgit2/src/diff_driver.c +183 -85
- data/vendor/libgit2/src/diff_driver.h +1 -1
- data/vendor/libgit2/src/diff_file.c +65 -84
- data/vendor/libgit2/src/diff_file.h +12 -10
- data/vendor/libgit2/src/diff_patch.c +274 -333
- data/vendor/libgit2/src/diff_patch.h +10 -9
- data/vendor/libgit2/src/diff_print.c +381 -179
- data/vendor/libgit2/src/diff_stats.c +336 -0
- data/vendor/libgit2/src/diff_tform.c +393 -215
- data/vendor/libgit2/src/diff_xdiff.c +117 -42
- data/vendor/libgit2/src/errors.c +59 -4
- data/vendor/libgit2/src/fetch.c +40 -34
- data/vendor/libgit2/src/fetch.h +2 -5
- data/vendor/libgit2/src/fetchhead.c +14 -7
- data/vendor/libgit2/src/filebuf.c +13 -24
- data/vendor/libgit2/src/filebuf.h +3 -3
- data/vendor/libgit2/src/fileops.c +104 -296
- data/vendor/libgit2/src/fileops.h +23 -94
- data/vendor/libgit2/src/filter.c +642 -43
- data/vendor/libgit2/src/filter.h +7 -66
- data/vendor/libgit2/src/fnmatch.c +46 -3
- data/vendor/libgit2/src/fnmatch.h +24 -3
- data/vendor/libgit2/src/global.c +158 -42
- data/vendor/libgit2/src/global.h +9 -0
- data/vendor/libgit2/src/graph.c +34 -20
- data/vendor/libgit2/src/hash/hash_generic.h +0 -1
- data/vendor/libgit2/src/hash/hash_openssl.h +0 -1
- data/vendor/libgit2/src/hash/hash_win32.c +14 -29
- data/vendor/libgit2/src/hash.h +0 -2
- data/vendor/libgit2/src/hashsig.c +97 -117
- data/vendor/libgit2/src/ident.c +125 -0
- data/vendor/libgit2/src/ignore.c +159 -110
- data/vendor/libgit2/src/ignore.h +13 -3
- data/vendor/libgit2/src/index.c +803 -445
- data/vendor/libgit2/src/index.h +43 -6
- data/vendor/libgit2/src/indexer.c +475 -157
- data/vendor/libgit2/src/iterator.c +198 -55
- data/vendor/libgit2/src/iterator.h +28 -4
- data/vendor/libgit2/src/map.h +1 -0
- data/vendor/libgit2/src/merge.c +849 -142
- data/vendor/libgit2/src/merge.h +11 -4
- data/vendor/libgit2/src/merge_file.c +183 -78
- data/vendor/libgit2/src/merge_file.h +0 -57
- data/vendor/libgit2/src/message.c +4 -28
- data/vendor/libgit2/src/mwindow.c +117 -8
- data/vendor/libgit2/src/mwindow.h +9 -1
- data/vendor/libgit2/src/netops.c +164 -59
- data/vendor/libgit2/src/netops.h +37 -1
- data/vendor/libgit2/src/notes.c +9 -18
- data/vendor/libgit2/src/notes.h +1 -1
- data/vendor/libgit2/src/object.c +78 -2
- data/vendor/libgit2/src/odb.c +191 -59
- data/vendor/libgit2/src/odb.h +2 -1
- data/vendor/libgit2/src/odb_loose.c +66 -51
- data/vendor/libgit2/src/odb_mempack.c +182 -0
- data/vendor/libgit2/src/odb_pack.c +151 -61
- data/vendor/libgit2/src/oid.c +30 -19
- data/vendor/libgit2/src/oid.h +13 -10
- data/vendor/libgit2/src/pack-objects.c +198 -147
- data/vendor/libgit2/src/pack-objects.h +7 -0
- data/vendor/libgit2/src/pack.c +272 -101
- data/vendor/libgit2/src/pack.h +15 -1
- data/vendor/libgit2/src/path.c +359 -117
- data/vendor/libgit2/src/path.h +110 -20
- data/vendor/libgit2/src/pathspec.c +583 -57
- data/vendor/libgit2/src/pathspec.h +36 -15
- data/vendor/libgit2/src/pool.c +4 -5
- data/vendor/libgit2/src/posix.c +45 -2
- data/vendor/libgit2/src/posix.h +13 -5
- data/vendor/libgit2/src/pqueue.c +73 -119
- data/vendor/libgit2/src/pqueue.h +35 -82
- data/vendor/libgit2/src/push.c +116 -48
- data/vendor/libgit2/src/push.h +5 -0
- data/vendor/libgit2/src/refdb.c +45 -6
- data/vendor/libgit2/src/refdb.h +13 -3
- data/vendor/libgit2/src/refdb_fs.c +1130 -551
- data/vendor/libgit2/src/reflog.c +36 -327
- data/vendor/libgit2/src/reflog.h +6 -1
- data/vendor/libgit2/src/refs.c +345 -142
- data/vendor/libgit2/src/refs.h +9 -2
- data/vendor/libgit2/src/refspec.c +90 -62
- data/vendor/libgit2/src/refspec.h +7 -24
- data/vendor/libgit2/src/remote.c +815 -415
- data/vendor/libgit2/src/remote.h +3 -4
- data/vendor/libgit2/src/repository.c +360 -207
- data/vendor/libgit2/src/repository.h +16 -10
- data/vendor/libgit2/src/reset.c +28 -13
- data/vendor/libgit2/src/revert.c +228 -0
- data/vendor/libgit2/src/revparse.c +29 -30
- data/vendor/libgit2/src/revwalk.c +141 -96
- data/vendor/libgit2/src/revwalk.h +6 -1
- data/vendor/libgit2/src/settings.c +140 -0
- data/vendor/libgit2/src/sha1_lookup.c +71 -0
- data/vendor/libgit2/src/sha1_lookup.h +5 -0
- data/vendor/libgit2/src/signature.c +38 -10
- data/vendor/libgit2/src/sortedcache.c +378 -0
- data/vendor/libgit2/src/sortedcache.h +178 -0
- data/vendor/libgit2/src/stash.c +98 -116
- data/vendor/libgit2/src/status.c +88 -60
- data/vendor/libgit2/src/status.h +2 -2
- data/vendor/libgit2/src/strmap.c +32 -0
- data/vendor/libgit2/src/strmap.h +14 -1
- data/vendor/libgit2/src/strnlen.h +23 -0
- data/vendor/libgit2/src/submodule.c +1073 -615
- data/vendor/libgit2/src/submodule.h +89 -21
- data/vendor/libgit2/src/sysdir.c +252 -0
- data/vendor/libgit2/src/sysdir.h +101 -0
- data/vendor/libgit2/src/tag.c +31 -20
- data/vendor/libgit2/src/thread-utils.h +98 -17
- data/vendor/libgit2/src/trace.h +0 -2
- data/vendor/libgit2/src/transport.c +76 -6
- data/vendor/libgit2/src/transports/cred.c +164 -61
- data/vendor/libgit2/src/transports/git.c +41 -48
- data/vendor/libgit2/src/transports/http.c +65 -109
- data/vendor/libgit2/src/transports/local.c +88 -65
- data/vendor/libgit2/src/transports/smart.c +91 -19
- data/vendor/libgit2/src/transports/smart.h +13 -5
- data/vendor/libgit2/src/transports/smart_pkt.c +24 -14
- data/vendor/libgit2/src/transports/smart_protocol.c +268 -113
- data/vendor/libgit2/src/transports/ssh.c +284 -186
- data/vendor/libgit2/src/transports/winhttp.c +279 -198
- data/vendor/libgit2/src/tree-cache.c +21 -23
- data/vendor/libgit2/src/tree-cache.h +1 -0
- data/vendor/libgit2/src/tree.c +109 -92
- data/vendor/libgit2/src/tree.h +2 -3
- data/vendor/libgit2/src/unix/map.c +7 -1
- data/vendor/libgit2/src/unix/posix.h +0 -1
- data/vendor/libgit2/src/userdiff.h +208 -0
- data/vendor/libgit2/src/util.c +16 -112
- data/vendor/libgit2/src/util.h +107 -3
- data/vendor/libgit2/src/vector.c +72 -17
- data/vendor/libgit2/src/vector.h +32 -5
- data/vendor/libgit2/src/win32/dir.c +15 -40
- data/vendor/libgit2/src/win32/dir.h +3 -2
- data/vendor/libgit2/src/win32/error.c +5 -31
- data/vendor/libgit2/src/win32/findfile.c +47 -66
- data/vendor/libgit2/src/win32/findfile.h +1 -12
- data/vendor/libgit2/src/win32/git2.rc +40 -0
- data/vendor/libgit2/src/win32/map.c +7 -1
- data/vendor/libgit2/src/win32/mingw-compat.h +3 -0
- data/vendor/libgit2/src/win32/posix.h +17 -11
- data/vendor/libgit2/src/win32/posix_w32.c +424 -292
- data/vendor/libgit2/src/win32/precompiled.h +6 -2
- data/vendor/libgit2/src/win32/pthread.c +141 -18
- data/vendor/libgit2/src/win32/pthread.h +50 -8
- data/vendor/libgit2/src/win32/reparse.h +57 -0
- data/vendor/libgit2/src/win32/utf-conv.c +117 -60
- data/vendor/libgit2/src/win32/utf-conv.h +81 -6
- data/vendor/libgit2/src/win32/version.h +21 -4
- data/vendor/libgit2/src/win32/w32_util.c +139 -0
- data/vendor/libgit2/src/win32/w32_util.h +54 -0
- data/vendor/libgit2/src/zstream.c +156 -0
- data/vendor/libgit2/src/zstream.h +39 -0
- metadata +84 -167
- 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/src/amiga/map.c +0 -48
- data/vendor/libgit2/src/compress.c +0 -53
data/vendor/libgit2/src/merge.c
CHANGED
@@ -26,6 +26,7 @@
|
|
26
26
|
#include "oid.h"
|
27
27
|
#include "index.h"
|
28
28
|
#include "filebuf.h"
|
29
|
+
#include "config.h"
|
29
30
|
|
30
31
|
#include "git2/types.h"
|
31
32
|
#include "git2/repository.h"
|
@@ -41,6 +42,7 @@
|
|
41
42
|
#include "git2/sys/index.h"
|
42
43
|
|
43
44
|
#define GIT_MERGE_INDEX_ENTRY_EXISTS(X) ((X).mode != 0)
|
45
|
+
#define GIT_MERGE_INDEX_ENTRY_ISFILE(X) S_ISREG((X).mode)
|
44
46
|
|
45
47
|
typedef enum {
|
46
48
|
TREE_IDX_ANCESTOR = 0,
|
@@ -58,7 +60,7 @@ struct merge_diff_df_data {
|
|
58
60
|
|
59
61
|
/* Merge base computation */
|
60
62
|
|
61
|
-
int git_merge_base_many(git_oid *out, git_repository *repo, const git_oid input_array[]
|
63
|
+
int git_merge_base_many(git_oid *out, git_repository *repo, size_t length, const git_oid input_array[])
|
62
64
|
{
|
63
65
|
git_revwalk *walk;
|
64
66
|
git_vector list;
|
@@ -112,6 +114,31 @@ cleanup:
|
|
112
114
|
return error;
|
113
115
|
}
|
114
116
|
|
117
|
+
int git_merge_base_octopus(git_oid *out, git_repository *repo, size_t length, const git_oid input_array[])
|
118
|
+
{
|
119
|
+
git_oid result;
|
120
|
+
unsigned int i;
|
121
|
+
int error = -1;
|
122
|
+
|
123
|
+
assert(out && repo && input_array);
|
124
|
+
|
125
|
+
if (length < 2) {
|
126
|
+
giterr_set(GITERR_INVALID, "At least two commits are required to find an ancestor. Provided 'length' was %u.", length);
|
127
|
+
return -1;
|
128
|
+
}
|
129
|
+
|
130
|
+
result = input_array[0];
|
131
|
+
for (i = 1; i < length; i++) {
|
132
|
+
error = git_merge_base(&result, repo, &result, &input_array[i]);
|
133
|
+
if (error < 0)
|
134
|
+
return error;
|
135
|
+
}
|
136
|
+
|
137
|
+
*out = result;
|
138
|
+
|
139
|
+
return 0;
|
140
|
+
}
|
141
|
+
|
115
142
|
int git_merge_base(git_oid *out, git_repository *repo, const git_oid *one, const git_oid *two)
|
116
143
|
{
|
117
144
|
git_revwalk *walk;
|
@@ -159,10 +186,10 @@ on_error:
|
|
159
186
|
|
160
187
|
static int interesting(git_pqueue *list)
|
161
188
|
{
|
162
|
-
|
163
|
-
|
164
|
-
for (i =
|
165
|
-
git_commit_list_node *commit = list
|
189
|
+
size_t i;
|
190
|
+
|
191
|
+
for (i = 0; i < git_pqueue_size(list); i++) {
|
192
|
+
git_commit_list_node *commit = git_pqueue_get(list, i);
|
166
193
|
if ((commit->flags & STALE) == 0)
|
167
194
|
return 1;
|
168
195
|
}
|
@@ -178,13 +205,19 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l
|
|
178
205
|
git_commit_list *result = NULL, *tmp = NULL;
|
179
206
|
git_pqueue list;
|
180
207
|
|
208
|
+
/* If there's only the one commit, there can be no merge bases */
|
209
|
+
if (twos->length == 0) {
|
210
|
+
*out = NULL;
|
211
|
+
return 0;
|
212
|
+
}
|
213
|
+
|
181
214
|
/* if the commit is repeated, we have a our merge base already */
|
182
215
|
git_vector_foreach(twos, i, two) {
|
183
216
|
if (one == two)
|
184
217
|
return git_commit_list_insert(one, out) ? 0 : -1;
|
185
218
|
}
|
186
219
|
|
187
|
-
if (git_pqueue_init(&list, twos->length * 2, git_commit_list_time_cmp) < 0)
|
220
|
+
if (git_pqueue_init(&list, 0, twos->length * 2, git_commit_list_time_cmp) < 0)
|
188
221
|
return -1;
|
189
222
|
|
190
223
|
if (git_commit_list_parse(walk, one) < 0)
|
@@ -203,10 +236,11 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l
|
|
203
236
|
|
204
237
|
/* as long as there are non-STALE commits */
|
205
238
|
while (interesting(&list)) {
|
206
|
-
git_commit_list_node *commit;
|
239
|
+
git_commit_list_node *commit = git_pqueue_pop(&list);
|
207
240
|
int flags;
|
208
241
|
|
209
|
-
commit
|
242
|
+
if (commit == NULL)
|
243
|
+
break;
|
210
244
|
|
211
245
|
flags = commit->flags & (PARENT1 | PARENT2 | STALE);
|
212
246
|
if (flags == (PARENT1 | PARENT2)) {
|
@@ -253,7 +287,8 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l
|
|
253
287
|
return 0;
|
254
288
|
}
|
255
289
|
|
256
|
-
int git_repository_mergehead_foreach(
|
290
|
+
int git_repository_mergehead_foreach(
|
291
|
+
git_repository *repo,
|
257
292
|
git_repository_mergehead_foreach_cb cb,
|
258
293
|
void *payload)
|
259
294
|
{
|
@@ -285,8 +320,8 @@ int git_repository_mergehead_foreach(git_repository *repo,
|
|
285
320
|
if ((error = git_oid_fromstr(&oid, line)) < 0)
|
286
321
|
goto cleanup;
|
287
322
|
|
288
|
-
if (cb(&oid, payload)
|
289
|
-
error
|
323
|
+
if ((error = cb(&oid, payload)) != 0) {
|
324
|
+
giterr_set_after_callback(error);
|
290
325
|
goto cleanup;
|
291
326
|
}
|
292
327
|
|
@@ -314,7 +349,7 @@ GIT_INLINE(int) index_entry_cmp(const git_index_entry *a, const git_index_entry
|
|
314
349
|
return (b->path == NULL) ? 0 : 1;
|
315
350
|
|
316
351
|
if ((value = a->mode - b->mode) == 0 &&
|
317
|
-
(value = git_oid__cmp(&a->
|
352
|
+
(value = git_oid__cmp(&a->id, &b->id)) == 0)
|
318
353
|
value = strcmp(a->path, b->path);
|
319
354
|
|
320
355
|
return value;
|
@@ -445,7 +480,6 @@ static int merge_conflict_resolve_one_removed(
|
|
445
480
|
return error;
|
446
481
|
}
|
447
482
|
|
448
|
-
|
449
483
|
static int merge_conflict_resolve_one_renamed(
|
450
484
|
int *resolved,
|
451
485
|
git_merge_diff_list *diff_list,
|
@@ -476,12 +510,12 @@ static int merge_conflict_resolve_one_renamed(
|
|
476
510
|
conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED)
|
477
511
|
return 0;
|
478
512
|
|
479
|
-
ours_changed = (git_oid__cmp(&conflict->ancestor_entry.
|
480
|
-
theirs_changed = (git_oid__cmp(&conflict->ancestor_entry.
|
513
|
+
ours_changed = (git_oid__cmp(&conflict->ancestor_entry.id, &conflict->our_entry.id) != 0);
|
514
|
+
theirs_changed = (git_oid__cmp(&conflict->ancestor_entry.id, &conflict->their_entry.id) != 0);
|
481
515
|
|
482
516
|
/* if both are modified (and not to a common target) require a merge */
|
483
517
|
if (ours_changed && theirs_changed &&
|
484
|
-
git_oid__cmp(&conflict->our_entry.
|
518
|
+
git_oid__cmp(&conflict->our_entry.id, &conflict->their_entry.id) != 0)
|
485
519
|
return 0;
|
486
520
|
|
487
521
|
if ((merged = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry))) == NULL)
|
@@ -509,12 +543,11 @@ static int merge_conflict_resolve_automerge(
|
|
509
543
|
int *resolved,
|
510
544
|
git_merge_diff_list *diff_list,
|
511
545
|
const git_merge_diff *conflict,
|
512
|
-
unsigned int
|
546
|
+
unsigned int merge_file_favor)
|
513
547
|
{
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
git_merge_file_result result = GIT_MERGE_FILE_RESULT_INIT;
|
548
|
+
const git_index_entry *ancestor = NULL, *ours = NULL, *theirs = NULL;
|
549
|
+
git_merge_file_options opts = GIT_MERGE_FILE_OPTIONS_INIT;
|
550
|
+
git_merge_file_result result = {0};
|
518
551
|
git_index_entry *index_entry;
|
519
552
|
git_odb *odb = NULL;
|
520
553
|
git_oid automerge_oid;
|
@@ -524,13 +557,20 @@ static int merge_conflict_resolve_automerge(
|
|
524
557
|
|
525
558
|
*resolved = 0;
|
526
559
|
|
527
|
-
if (
|
560
|
+
if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ||
|
561
|
+
!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry))
|
528
562
|
return 0;
|
529
563
|
|
530
564
|
/* Reject D/F conflicts */
|
531
565
|
if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE)
|
532
566
|
return 0;
|
533
567
|
|
568
|
+
/* Reject submodules. */
|
569
|
+
if (S_ISGITLINK(conflict->ancestor_entry.mode) ||
|
570
|
+
S_ISGITLINK(conflict->our_entry.mode) ||
|
571
|
+
S_ISGITLINK(conflict->their_entry.mode))
|
572
|
+
return 0;
|
573
|
+
|
534
574
|
/* Reject link/file conflicts. */
|
535
575
|
if ((S_ISLNK(conflict->ancestor_entry.mode) ^ S_ISLNK(conflict->our_entry.mode)) ||
|
536
576
|
(S_ISLNK(conflict->ancestor_entry.mode) ^ S_ISLNK(conflict->their_entry.mode)))
|
@@ -546,13 +586,23 @@ static int merge_conflict_resolve_automerge(
|
|
546
586
|
strcmp(conflict->ancestor_entry.path, conflict->their_entry.path) != 0)
|
547
587
|
return 0;
|
548
588
|
|
589
|
+
/* Reject binary conflicts */
|
590
|
+
if (conflict->binary)
|
591
|
+
return 0;
|
592
|
+
|
593
|
+
ancestor = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) ?
|
594
|
+
&conflict->ancestor_entry : NULL;
|
595
|
+
ours = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ?
|
596
|
+
&conflict->our_entry : NULL;
|
597
|
+
theirs = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ?
|
598
|
+
&conflict->their_entry : NULL;
|
599
|
+
|
600
|
+
opts.favor = merge_file_favor;
|
601
|
+
|
549
602
|
if ((error = git_repository_odb(&odb, diff_list->repo)) < 0 ||
|
550
|
-
(error =
|
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 ||
|
603
|
+
(error = git_merge_file_from_index(&result, diff_list->repo, ancestor, ours, theirs, &opts)) < 0 ||
|
554
604
|
!result.automergeable ||
|
555
|
-
(error = git_odb_write(&automerge_oid, odb, result.
|
605
|
+
(error = git_odb_write(&automerge_oid, odb, result.ptr, result.len, GIT_OBJ_BLOB)) < 0)
|
556
606
|
goto done;
|
557
607
|
|
558
608
|
if ((index_entry = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry))) == NULL)
|
@@ -563,7 +613,7 @@ static int merge_conflict_resolve_automerge(
|
|
563
613
|
|
564
614
|
index_entry->file_size = result.len;
|
565
615
|
index_entry->mode = result.mode;
|
566
|
-
git_oid_cpy(&index_entry->
|
616
|
+
git_oid_cpy(&index_entry->id, &automerge_oid);
|
567
617
|
|
568
618
|
git_vector_insert(&diff_list->staged, index_entry);
|
569
619
|
git_vector_insert(&diff_list->resolved, (git_merge_diff *)conflict);
|
@@ -571,9 +621,6 @@ static int merge_conflict_resolve_automerge(
|
|
571
621
|
*resolved = 1;
|
572
622
|
|
573
623
|
done:
|
574
|
-
git_merge_file_input_free(&ancestor);
|
575
|
-
git_merge_file_input_free(&ours);
|
576
|
-
git_merge_file_input_free(&theirs);
|
577
624
|
git_merge_file_result_free(&result);
|
578
625
|
git_odb_free(odb);
|
579
626
|
|
@@ -584,7 +631,7 @@ static int merge_conflict_resolve(
|
|
584
631
|
int *out,
|
585
632
|
git_merge_diff_list *diff_list,
|
586
633
|
const git_merge_diff *conflict,
|
587
|
-
unsigned int
|
634
|
+
unsigned int merge_file_favor)
|
588
635
|
{
|
589
636
|
int resolved = 0;
|
590
637
|
int error = 0;
|
@@ -594,16 +641,14 @@ static int merge_conflict_resolve(
|
|
594
641
|
if ((error = merge_conflict_resolve_trivial(&resolved, diff_list, conflict)) < 0)
|
595
642
|
goto done;
|
596
643
|
|
597
|
-
if (
|
598
|
-
|
599
|
-
goto done;
|
644
|
+
if (!resolved && (error = merge_conflict_resolve_one_removed(&resolved, diff_list, conflict)) < 0)
|
645
|
+
goto done;
|
600
646
|
|
601
|
-
|
602
|
-
|
647
|
+
if (!resolved && (error = merge_conflict_resolve_one_renamed(&resolved, diff_list, conflict)) < 0)
|
648
|
+
goto done;
|
603
649
|
|
604
|
-
|
605
|
-
|
606
|
-
}
|
650
|
+
if (!resolved && (error = merge_conflict_resolve_automerge(&resolved, diff_list, conflict, merge_file_favor)) < 0)
|
651
|
+
goto done;
|
607
652
|
|
608
653
|
*out = resolved;
|
609
654
|
|
@@ -625,7 +670,7 @@ static int index_entry_similarity_exact(
|
|
625
670
|
git_index_entry *b,
|
626
671
|
size_t b_idx,
|
627
672
|
void **cache,
|
628
|
-
const
|
673
|
+
const git_merge_options *opts)
|
629
674
|
{
|
630
675
|
GIT_UNUSED(repo);
|
631
676
|
GIT_UNUSED(a_idx);
|
@@ -633,7 +678,7 @@ static int index_entry_similarity_exact(
|
|
633
678
|
GIT_UNUSED(cache);
|
634
679
|
GIT_UNUSED(opts);
|
635
680
|
|
636
|
-
if (git_oid__cmp(&a->
|
681
|
+
if (git_oid__cmp(&a->id, &b->id) == 0)
|
637
682
|
return 100;
|
638
683
|
|
639
684
|
return 0;
|
@@ -643,7 +688,7 @@ static int index_entry_similarity_calc(
|
|
643
688
|
void **out,
|
644
689
|
git_repository *repo,
|
645
690
|
git_index_entry *entry,
|
646
|
-
const
|
691
|
+
const git_merge_options *opts)
|
647
692
|
{
|
648
693
|
git_blob *blob;
|
649
694
|
git_diff_file diff_file = {{{0}}};
|
@@ -652,10 +697,10 @@ static int index_entry_similarity_calc(
|
|
652
697
|
|
653
698
|
*out = NULL;
|
654
699
|
|
655
|
-
if ((error = git_blob_lookup(&blob, repo, &entry->
|
700
|
+
if ((error = git_blob_lookup(&blob, repo, &entry->id)) < 0)
|
656
701
|
return error;
|
657
702
|
|
658
|
-
git_oid_cpy(&diff_file.
|
703
|
+
git_oid_cpy(&diff_file.id, &entry->id);
|
659
704
|
diff_file.path = entry->path;
|
660
705
|
diff_file.size = entry->file_size;
|
661
706
|
diff_file.mode = entry->mode;
|
@@ -683,7 +728,7 @@ static int index_entry_similarity_inexact(
|
|
683
728
|
git_index_entry *b,
|
684
729
|
size_t b_idx,
|
685
730
|
void **cache,
|
686
|
-
const
|
731
|
+
const git_merge_options *opts)
|
687
732
|
{
|
688
733
|
int score = 0;
|
689
734
|
int error = 0;
|
@@ -720,9 +765,9 @@ static int merge_diff_mark_similarity(
|
|
720
765
|
git_merge_diff_list *diff_list,
|
721
766
|
struct merge_diff_similarity *similarity_ours,
|
722
767
|
struct merge_diff_similarity *similarity_theirs,
|
723
|
-
int (*similarity_fn)(git_repository *, git_index_entry *, size_t, git_index_entry *, size_t, void **, const
|
768
|
+
int (*similarity_fn)(git_repository *, git_index_entry *, size_t, git_index_entry *, size_t, void **, const git_merge_options *),
|
724
769
|
void **cache,
|
725
|
-
const
|
770
|
+
const git_merge_options *opts)
|
726
771
|
{
|
727
772
|
size_t i, j;
|
728
773
|
git_merge_diff *conflict_src, *conflict_tgt;
|
@@ -823,7 +868,7 @@ static void merge_diff_mark_rename_conflict(
|
|
823
868
|
bool theirs_renamed,
|
824
869
|
size_t theirs_source_idx,
|
825
870
|
git_merge_diff *target,
|
826
|
-
const
|
871
|
+
const git_merge_options *opts)
|
827
872
|
{
|
828
873
|
git_merge_diff *ours_source = NULL, *theirs_source = NULL;
|
829
874
|
|
@@ -893,7 +938,7 @@ static void merge_diff_list_coalesce_renames(
|
|
893
938
|
git_merge_diff_list *diff_list,
|
894
939
|
struct merge_diff_similarity *similarity_ours,
|
895
940
|
struct merge_diff_similarity *similarity_theirs,
|
896
|
-
const
|
941
|
+
const git_merge_options *opts)
|
897
942
|
{
|
898
943
|
size_t i;
|
899
944
|
bool ours_renamed = 0, theirs_renamed = 0;
|
@@ -950,10 +995,12 @@ static void merge_diff_list_coalesce_renames(
|
|
950
995
|
}
|
951
996
|
}
|
952
997
|
|
953
|
-
static int merge_diff_empty(const git_vector *conflicts, size_t idx)
|
998
|
+
static int merge_diff_empty(const git_vector *conflicts, size_t idx, void *p)
|
954
999
|
{
|
955
1000
|
git_merge_diff *conflict = conflicts->contents[idx];
|
956
1001
|
|
1002
|
+
GIT_UNUSED(p);
|
1003
|
+
|
957
1004
|
return (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) &&
|
958
1005
|
!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) &&
|
959
1006
|
!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry));
|
@@ -983,7 +1030,7 @@ static void merge_diff_list_count_candidates(
|
|
983
1030
|
int git_merge_diff_list__find_renames(
|
984
1031
|
git_repository *repo,
|
985
1032
|
git_merge_diff_list *diff_list,
|
986
|
-
const
|
1033
|
+
const git_merge_options *opts)
|
987
1034
|
{
|
988
1035
|
struct merge_diff_similarity *similarity_ours, *similarity_theirs;
|
989
1036
|
void **cache = NULL;
|
@@ -1034,7 +1081,7 @@ int git_merge_diff_list__find_renames(
|
|
1034
1081
|
merge_diff_list_coalesce_renames(diff_list, similarity_ours, similarity_theirs, opts);
|
1035
1082
|
|
1036
1083
|
/* And remove any entries that were merged and are now empty. */
|
1037
|
-
git_vector_remove_matching(&diff_list->conflicts, merge_diff_empty);
|
1084
|
+
git_vector_remove_matching(&diff_list->conflicts, merge_diff_empty, NULL);
|
1038
1085
|
|
1039
1086
|
done:
|
1040
1087
|
if (cache != NULL) {
|
@@ -1145,7 +1192,45 @@ GIT_INLINE(int) merge_diff_detect_type(
|
|
1145
1192
|
return 0;
|
1146
1193
|
}
|
1147
1194
|
|
1148
|
-
GIT_INLINE(int)
|
1195
|
+
GIT_INLINE(int) merge_diff_detect_binary(
|
1196
|
+
git_repository *repo,
|
1197
|
+
git_merge_diff *conflict)
|
1198
|
+
{
|
1199
|
+
git_blob *ancestor_blob = NULL, *our_blob = NULL, *their_blob = NULL;
|
1200
|
+
int error = 0;
|
1201
|
+
|
1202
|
+
if (GIT_MERGE_INDEX_ENTRY_ISFILE(conflict->ancestor_entry)) {
|
1203
|
+
if ((error = git_blob_lookup(&ancestor_blob, repo, &conflict->ancestor_entry.id)) < 0)
|
1204
|
+
goto done;
|
1205
|
+
|
1206
|
+
conflict->binary = git_blob_is_binary(ancestor_blob);
|
1207
|
+
}
|
1208
|
+
|
1209
|
+
if (!conflict->binary &&
|
1210
|
+
GIT_MERGE_INDEX_ENTRY_ISFILE(conflict->our_entry)) {
|
1211
|
+
if ((error = git_blob_lookup(&our_blob, repo, &conflict->our_entry.id)) < 0)
|
1212
|
+
goto done;
|
1213
|
+
|
1214
|
+
conflict->binary = git_blob_is_binary(our_blob);
|
1215
|
+
}
|
1216
|
+
|
1217
|
+
if (!conflict->binary &&
|
1218
|
+
GIT_MERGE_INDEX_ENTRY_ISFILE(conflict->their_entry)) {
|
1219
|
+
if ((error = git_blob_lookup(&their_blob, repo, &conflict->their_entry.id)) < 0)
|
1220
|
+
goto done;
|
1221
|
+
|
1222
|
+
conflict->binary = git_blob_is_binary(their_blob);
|
1223
|
+
}
|
1224
|
+
|
1225
|
+
done:
|
1226
|
+
git_blob_free(ancestor_blob);
|
1227
|
+
git_blob_free(our_blob);
|
1228
|
+
git_blob_free(their_blob);
|
1229
|
+
|
1230
|
+
return error;
|
1231
|
+
}
|
1232
|
+
|
1233
|
+
GIT_INLINE(int) index_entry_dup_pool(
|
1149
1234
|
git_index_entry *out,
|
1150
1235
|
git_pool *pool,
|
1151
1236
|
const git_index_entry *src)
|
@@ -1174,7 +1259,7 @@ GIT_INLINE(int) merge_delta_type_from_index_entries(
|
|
1174
1259
|
return GIT_DELTA_TYPECHANGE;
|
1175
1260
|
else if(S_ISLNK(ancestor->mode) ^ S_ISLNK(other->mode))
|
1176
1261
|
return GIT_DELTA_TYPECHANGE;
|
1177
|
-
else if (git_oid__cmp(&ancestor->
|
1262
|
+
else if (git_oid__cmp(&ancestor->id, &other->id) ||
|
1178
1263
|
ancestor->mode != other->mode)
|
1179
1264
|
return GIT_DELTA_MODIFIED;
|
1180
1265
|
|
@@ -1191,9 +1276,9 @@ static git_merge_diff *merge_diff_from_index_entries(
|
|
1191
1276
|
if ((conflict = git_pool_malloc(pool, sizeof(git_merge_diff))) == NULL)
|
1192
1277
|
return NULL;
|
1193
1278
|
|
1194
|
-
if (
|
1195
|
-
|
1196
|
-
|
1279
|
+
if (index_entry_dup_pool(&conflict->ancestor_entry, pool, entries[TREE_IDX_ANCESTOR]) < 0 ||
|
1280
|
+
index_entry_dup_pool(&conflict->our_entry, pool, entries[TREE_IDX_OURS]) < 0 ||
|
1281
|
+
index_entry_dup_pool(&conflict->their_entry, pool, entries[TREE_IDX_THEIRS]) < 0)
|
1197
1282
|
return NULL;
|
1198
1283
|
|
1199
1284
|
conflict->our_status = merge_delta_type_from_index_entries(
|
@@ -1206,7 +1291,7 @@ static git_merge_diff *merge_diff_from_index_entries(
|
|
1206
1291
|
|
1207
1292
|
/* Merge trees */
|
1208
1293
|
|
1209
|
-
static int
|
1294
|
+
static int merge_diff_list_insert_conflict(
|
1210
1295
|
git_merge_diff_list *diff_list,
|
1211
1296
|
struct merge_diff_df_data *merge_df_data,
|
1212
1297
|
const git_index_entry *tree_items[3])
|
@@ -1216,13 +1301,14 @@ static int merge_index_insert_conflict(
|
|
1216
1301
|
if ((conflict = merge_diff_from_index_entries(diff_list, tree_items)) == NULL ||
|
1217
1302
|
merge_diff_detect_type(conflict) < 0 ||
|
1218
1303
|
merge_diff_detect_df_conflict(merge_df_data, conflict) < 0 ||
|
1304
|
+
merge_diff_detect_binary(diff_list->repo, conflict) < 0 ||
|
1219
1305
|
git_vector_insert(&diff_list->conflicts, conflict) < 0)
|
1220
1306
|
return -1;
|
1221
1307
|
|
1222
1308
|
return 0;
|
1223
1309
|
}
|
1224
1310
|
|
1225
|
-
static int
|
1311
|
+
static int merge_diff_list_insert_unmodified(
|
1226
1312
|
git_merge_diff_list *diff_list,
|
1227
1313
|
const git_index_entry *tree_items[3])
|
1228
1314
|
{
|
@@ -1232,7 +1318,7 @@ static int merge_index_insert_unmodified(
|
|
1232
1318
|
entry = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry));
|
1233
1319
|
GITERR_CHECK_ALLOC(entry);
|
1234
1320
|
|
1235
|
-
if ((error =
|
1321
|
+
if ((error = index_entry_dup_pool(entry, &diff_list->pool, tree_items[0])) >= 0)
|
1236
1322
|
error = git_vector_insert(&diff_list->staged, entry);
|
1237
1323
|
|
1238
1324
|
return error;
|
@@ -1246,13 +1332,13 @@ int git_merge_diff_list__find_differences(
|
|
1246
1332
|
{
|
1247
1333
|
git_iterator *iterators[3] = {0};
|
1248
1334
|
const git_index_entry *items[3] = {0}, *best_cur_item, *cur_items[3];
|
1249
|
-
git_vector_cmp entry_compare =
|
1335
|
+
git_vector_cmp entry_compare = git_index_entry_cmp;
|
1250
1336
|
struct merge_diff_df_data df_data = {0};
|
1251
1337
|
int cur_item_modified;
|
1252
1338
|
size_t i, j;
|
1253
1339
|
int error = 0;
|
1254
1340
|
|
1255
|
-
assert(diff_list && our_tree
|
1341
|
+
assert(diff_list && (our_tree || their_tree));
|
1256
1342
|
|
1257
1343
|
if ((error = git_iterator_for_tree(&iterators[TREE_IDX_ANCESTOR], (git_tree *)ancestor_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
|
1258
1344
|
(error = git_iterator_for_tree(&iterators[TREE_IDX_OURS], (git_tree *)our_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
|
@@ -1262,6 +1348,7 @@ int git_merge_diff_list__find_differences(
|
|
1262
1348
|
/* Set up the iterators */
|
1263
1349
|
for (i = 0; i < 3; i++) {
|
1264
1350
|
error = git_iterator_current(&items[i], iterators[i]);
|
1351
|
+
|
1265
1352
|
if (error < 0 && error != GIT_ITEROVER)
|
1266
1353
|
goto done;
|
1267
1354
|
}
|
@@ -1313,9 +1400,9 @@ int git_merge_diff_list__find_differences(
|
|
1313
1400
|
break;
|
1314
1401
|
|
1315
1402
|
if (cur_item_modified)
|
1316
|
-
error =
|
1403
|
+
error = merge_diff_list_insert_conflict(diff_list, &df_data, cur_items);
|
1317
1404
|
else
|
1318
|
-
error =
|
1405
|
+
error = merge_diff_list_insert_unmodified(diff_list, cur_items);
|
1319
1406
|
if (error < 0)
|
1320
1407
|
goto done;
|
1321
1408
|
|
@@ -1325,6 +1412,7 @@ int git_merge_diff_list__find_differences(
|
|
1325
1412
|
continue;
|
1326
1413
|
|
1327
1414
|
error = git_iterator_advance(&items[i], iterators[i]);
|
1415
|
+
|
1328
1416
|
if (error < 0 && error != GIT_ITEROVER)
|
1329
1417
|
goto done;
|
1330
1418
|
}
|
@@ -1370,10 +1458,10 @@ void git_merge_diff_list__free(git_merge_diff_list *diff_list)
|
|
1370
1458
|
git__free(diff_list);
|
1371
1459
|
}
|
1372
1460
|
|
1373
|
-
static int
|
1461
|
+
static int merge_normalize_opts(
|
1374
1462
|
git_repository *repo,
|
1375
|
-
|
1376
|
-
const
|
1463
|
+
git_merge_options *opts,
|
1464
|
+
const git_merge_options *given)
|
1377
1465
|
{
|
1378
1466
|
git_config *cfg = NULL;
|
1379
1467
|
int error = 0;
|
@@ -1384,9 +1472,9 @@ static int merge_tree_normalize_opts(
|
|
1384
1472
|
return error;
|
1385
1473
|
|
1386
1474
|
if (given != NULL)
|
1387
|
-
memcpy(opts, given, sizeof(
|
1475
|
+
memcpy(opts, given, sizeof(git_merge_options));
|
1388
1476
|
else {
|
1389
|
-
|
1477
|
+
git_merge_options init = GIT_MERGE_OPTIONS_INIT;
|
1390
1478
|
memcpy(opts, &init, sizeof(init));
|
1391
1479
|
|
1392
1480
|
opts->flags = GIT_MERGE_TREE_FIND_RENAMES;
|
@@ -1394,19 +1482,13 @@ static int merge_tree_normalize_opts(
|
|
1394
1482
|
}
|
1395
1483
|
|
1396
1484
|
if (!opts->target_limit) {
|
1397
|
-
|
1398
|
-
|
1399
|
-
opts->target_limit = GIT_MERGE_TREE_TARGET_LIMIT;
|
1400
|
-
|
1401
|
-
if (git_config_get_int32(&limit, cfg, "merge.renameLimit") < 0) {
|
1402
|
-
giterr_clear();
|
1485
|
+
int limit = git_config__get_int_force(cfg, "merge.renamelimit", 0);
|
1403
1486
|
|
1404
|
-
|
1405
|
-
|
1406
|
-
}
|
1487
|
+
if (!limit)
|
1488
|
+
limit = git_config__get_int_force(cfg, "diff.renamelimit", 0);
|
1407
1489
|
|
1408
|
-
|
1409
|
-
|
1490
|
+
opts->target_limit = (limit <= 0) ?
|
1491
|
+
GIT_MERGE_TREE_TARGET_LIMIT : (unsigned int)limit;
|
1410
1492
|
}
|
1411
1493
|
|
1412
1494
|
/* assign the internal metric with whitespace flag as payload */
|
@@ -1452,7 +1534,7 @@ static int merge_index_insert_reuc(
|
|
1452
1534
|
}
|
1453
1535
|
|
1454
1536
|
mode[idx] = entry->mode;
|
1455
|
-
oid[idx] = &entry->
|
1537
|
+
oid[idx] = &entry->id;
|
1456
1538
|
|
1457
1539
|
return git_index_reuc_add(index, entry->path,
|
1458
1540
|
mode[0], oid[0], mode[1], oid[1], mode[2], oid[2]);
|
@@ -1560,20 +1642,22 @@ int git_merge_trees(
|
|
1560
1642
|
const git_tree *ancestor_tree,
|
1561
1643
|
const git_tree *our_tree,
|
1562
1644
|
const git_tree *their_tree,
|
1563
|
-
const
|
1645
|
+
const git_merge_options *given_opts)
|
1564
1646
|
{
|
1565
1647
|
git_merge_diff_list *diff_list;
|
1566
|
-
|
1648
|
+
git_merge_options opts;
|
1567
1649
|
git_merge_diff *conflict;
|
1568
1650
|
git_vector changes;
|
1569
1651
|
size_t i;
|
1570
1652
|
int error = 0;
|
1571
1653
|
|
1572
|
-
assert(out && repo && our_tree
|
1654
|
+
assert(out && repo && (our_tree || their_tree));
|
1573
1655
|
|
1574
1656
|
*out = NULL;
|
1575
1657
|
|
1576
|
-
|
1658
|
+
GITERR_CHECK_VERSION(given_opts, GIT_MERGE_OPTIONS_VERSION, "git_merge_options");
|
1659
|
+
|
1660
|
+
if ((error = merge_normalize_opts(repo, &opts, given_opts)) < 0)
|
1577
1661
|
return error;
|
1578
1662
|
|
1579
1663
|
diff_list = git_merge_diff_list__alloc(repo);
|
@@ -1589,7 +1673,7 @@ int git_merge_trees(
|
|
1589
1673
|
git_vector_foreach(&changes, i, conflict) {
|
1590
1674
|
int resolved = 0;
|
1591
1675
|
|
1592
|
-
if ((error = merge_conflict_resolve(&resolved, diff_list, conflict, opts.
|
1676
|
+
if ((error = merge_conflict_resolve(&resolved, diff_list, conflict, opts.file_favor)) < 0)
|
1593
1677
|
goto done;
|
1594
1678
|
|
1595
1679
|
if (!resolved)
|
@@ -1607,6 +1691,40 @@ done:
|
|
1607
1691
|
return error;
|
1608
1692
|
}
|
1609
1693
|
|
1694
|
+
int git_merge_commits(
|
1695
|
+
git_index **out,
|
1696
|
+
git_repository *repo,
|
1697
|
+
const git_commit *our_commit,
|
1698
|
+
const git_commit *their_commit,
|
1699
|
+
const git_merge_options *opts)
|
1700
|
+
{
|
1701
|
+
git_oid ancestor_oid;
|
1702
|
+
git_commit *ancestor_commit = NULL;
|
1703
|
+
git_tree *our_tree = NULL, *their_tree = NULL, *ancestor_tree = NULL;
|
1704
|
+
int error = 0;
|
1705
|
+
|
1706
|
+
if ((error = git_merge_base(&ancestor_oid, repo, git_commit_id(our_commit), git_commit_id(their_commit))) < 0 &&
|
1707
|
+
error == GIT_ENOTFOUND)
|
1708
|
+
giterr_clear();
|
1709
|
+
else if (error < 0 ||
|
1710
|
+
(error = git_commit_lookup(&ancestor_commit, repo, &ancestor_oid)) < 0 ||
|
1711
|
+
(error = git_commit_tree(&ancestor_tree, ancestor_commit)) < 0)
|
1712
|
+
goto done;
|
1713
|
+
|
1714
|
+
if ((error = git_commit_tree(&our_tree, our_commit)) < 0 ||
|
1715
|
+
(error = git_commit_tree(&their_tree, their_commit)) < 0 ||
|
1716
|
+
(error = git_merge_trees(out, repo, ancestor_tree, our_tree, their_tree, opts)) < 0)
|
1717
|
+
goto done;
|
1718
|
+
|
1719
|
+
done:
|
1720
|
+
git_commit_free(ancestor_commit);
|
1721
|
+
git_tree_free(our_tree);
|
1722
|
+
git_tree_free(their_tree);
|
1723
|
+
git_tree_free(ancestor_tree);
|
1724
|
+
|
1725
|
+
return error;
|
1726
|
+
}
|
1727
|
+
|
1610
1728
|
/* Merge setup / cleanup */
|
1611
1729
|
|
1612
1730
|
static int write_orig_head(
|
@@ -1615,17 +1733,14 @@ static int write_orig_head(
|
|
1615
1733
|
{
|
1616
1734
|
git_filebuf file = GIT_FILEBUF_INIT;
|
1617
1735
|
git_buf file_path = GIT_BUF_INIT;
|
1618
|
-
char orig_oid_str[GIT_OID_HEXSZ + 1];
|
1619
1736
|
int error = 0;
|
1620
1737
|
|
1621
1738
|
assert(repo && our_head);
|
1622
1739
|
|
1623
|
-
git_oid_tostr(orig_oid_str, GIT_OID_HEXSZ+1, &our_head->oid);
|
1624
|
-
|
1625
1740
|
if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_ORIG_HEAD_FILE)) == 0 &&
|
1626
|
-
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE)) == 0 &&
|
1627
|
-
(error = git_filebuf_printf(&file, "%s\n",
|
1628
|
-
error = git_filebuf_commit(&file
|
1741
|
+
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) == 0 &&
|
1742
|
+
(error = git_filebuf_printf(&file, "%s\n", our_head->oid_str)) == 0)
|
1743
|
+
error = git_filebuf_commit(&file);
|
1629
1744
|
|
1630
1745
|
if (error < 0)
|
1631
1746
|
git_filebuf_cleanup(&file);
|
@@ -1642,24 +1757,21 @@ static int write_merge_head(
|
|
1642
1757
|
{
|
1643
1758
|
git_filebuf file = GIT_FILEBUF_INIT;
|
1644
1759
|
git_buf file_path = GIT_BUF_INIT;
|
1645
|
-
char merge_oid_str[GIT_OID_HEXSZ + 1];
|
1646
1760
|
size_t i;
|
1647
1761
|
int error = 0;
|
1648
1762
|
|
1649
1763
|
assert(repo && heads);
|
1650
1764
|
|
1651
1765
|
if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_HEAD_FILE)) < 0 ||
|
1652
|
-
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE)) < 0)
|
1766
|
+
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0)
|
1653
1767
|
goto cleanup;
|
1654
1768
|
|
1655
1769
|
for (i = 0; i < heads_len; i++) {
|
1656
|
-
|
1657
|
-
|
1658
|
-
if ((error = git_filebuf_printf(&file, "%s\n", merge_oid_str)) < 0)
|
1770
|
+
if ((error = git_filebuf_printf(&file, "%s\n", heads[i]->oid_str)) < 0)
|
1659
1771
|
goto cleanup;
|
1660
1772
|
}
|
1661
1773
|
|
1662
|
-
error = git_filebuf_commit(&file
|
1774
|
+
error = git_filebuf_commit(&file);
|
1663
1775
|
|
1664
1776
|
cleanup:
|
1665
1777
|
if (error < 0)
|
@@ -1670,22 +1782,22 @@ cleanup:
|
|
1670
1782
|
return error;
|
1671
1783
|
}
|
1672
1784
|
|
1673
|
-
static int write_merge_mode(git_repository *repo
|
1785
|
+
static int write_merge_mode(git_repository *repo)
|
1674
1786
|
{
|
1675
1787
|
git_filebuf file = GIT_FILEBUF_INIT;
|
1676
1788
|
git_buf file_path = GIT_BUF_INIT;
|
1677
1789
|
int error = 0;
|
1678
1790
|
|
1679
|
-
/* For future expansion */
|
1680
|
-
GIT_UNUSED(flags);
|
1681
|
-
|
1682
1791
|
assert(repo);
|
1683
1792
|
|
1684
1793
|
if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_MODE_FILE)) < 0 ||
|
1685
|
-
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE)) < 0)
|
1794
|
+
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0)
|
1795
|
+
goto cleanup;
|
1796
|
+
|
1797
|
+
if ((error = git_filebuf_write(&file, "no-ff", 5)) < 0)
|
1686
1798
|
goto cleanup;
|
1687
1799
|
|
1688
|
-
error = git_filebuf_commit(&file
|
1800
|
+
error = git_filebuf_commit(&file);
|
1689
1801
|
|
1690
1802
|
cleanup:
|
1691
1803
|
if (error < 0)
|
@@ -1890,7 +2002,6 @@ static int write_merge_msg(
|
|
1890
2002
|
{
|
1891
2003
|
git_filebuf file = GIT_FILEBUF_INIT;
|
1892
2004
|
git_buf file_path = GIT_BUF_INIT;
|
1893
|
-
char oid_str[GIT_OID_HEXSZ + 1];
|
1894
2005
|
struct merge_msg_entry *entries;
|
1895
2006
|
git_vector matching = GIT_VECTOR_INIT;
|
1896
2007
|
size_t i;
|
@@ -1902,14 +2013,16 @@ static int write_merge_msg(
|
|
1902
2013
|
entries = git__calloc(heads_len, sizeof(struct merge_msg_entry));
|
1903
2014
|
GITERR_CHECK_ALLOC(entries);
|
1904
2015
|
|
1905
|
-
if (git_vector_init(&matching, heads_len, NULL) < 0)
|
2016
|
+
if (git_vector_init(&matching, heads_len, NULL) < 0) {
|
2017
|
+
git__free(entries);
|
1906
2018
|
return -1;
|
2019
|
+
}
|
1907
2020
|
|
1908
2021
|
for (i = 0; i < heads_len; i++)
|
1909
2022
|
entries[i].merge_head = heads[i];
|
1910
2023
|
|
1911
2024
|
if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_MSG_FILE)) < 0 ||
|
1912
|
-
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE)) < 0 ||
|
2025
|
+
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0 ||
|
1913
2026
|
(error = git_filebuf_write(&file, "Merge ", 6)) < 0)
|
1914
2027
|
goto cleanup;
|
1915
2028
|
|
@@ -1928,10 +2041,9 @@ static int write_merge_msg(
|
|
1928
2041
|
if (!msg_entry_is_oid(&entries[i]))
|
1929
2042
|
break;
|
1930
2043
|
|
1931
|
-
|
1932
|
-
|
1933
|
-
|
1934
|
-
if ((error = git_filebuf_printf(&file, "%scommit '%s'", (i > 0) ? "; " : "", oid_str)) < 0)
|
2044
|
+
if ((error = git_filebuf_printf(&file,
|
2045
|
+
"%scommit '%s'", (i > 0) ? "; " : "",
|
2046
|
+
entries[i].merge_head->oid_str)) < 0)
|
1935
2047
|
goto cleanup;
|
1936
2048
|
|
1937
2049
|
entries[i].written = 1;
|
@@ -1978,15 +2090,13 @@ static int write_merge_msg(
|
|
1978
2090
|
if (merge_msg_entry_written(&entries[i]))
|
1979
2091
|
continue;
|
1980
2092
|
|
1981
|
-
|
1982
|
-
|
1983
|
-
|
1984
|
-
if ((error = git_filebuf_printf(&file, "; commit '%s'", oid_str)) < 0)
|
2093
|
+
if ((error = git_filebuf_printf(&file, "; commit '%s'",
|
2094
|
+
entries[i].merge_head->oid_str)) < 0)
|
1985
2095
|
goto cleanup;
|
1986
2096
|
}
|
1987
2097
|
|
1988
2098
|
if ((error = git_filebuf_printf(&file, "\n")) < 0 ||
|
1989
|
-
(error = git_filebuf_commit(&file
|
2099
|
+
(error = git_filebuf_commit(&file)) < 0)
|
1990
2100
|
goto cleanup;
|
1991
2101
|
|
1992
2102
|
cleanup:
|
@@ -2005,51 +2115,615 @@ int git_merge__setup(
|
|
2005
2115
|
git_repository *repo,
|
2006
2116
|
const git_merge_head *our_head,
|
2007
2117
|
const git_merge_head *heads[],
|
2008
|
-
size_t heads_len
|
2009
|
-
unsigned int flags)
|
2118
|
+
size_t heads_len)
|
2010
2119
|
{
|
2011
2120
|
int error = 0;
|
2012
2121
|
|
2013
2122
|
assert (repo && our_head && heads);
|
2014
|
-
|
2123
|
+
|
2015
2124
|
if ((error = write_orig_head(repo, our_head)) == 0 &&
|
2016
2125
|
(error = write_merge_head(repo, heads, heads_len)) == 0 &&
|
2017
|
-
(error = write_merge_mode(repo
|
2126
|
+
(error = write_merge_mode(repo)) == 0) {
|
2018
2127
|
error = write_merge_msg(repo, heads, heads_len);
|
2019
2128
|
}
|
2020
2129
|
|
2021
2130
|
return error;
|
2022
2131
|
}
|
2023
2132
|
|
2024
|
-
|
2133
|
+
/* Merge branches */
|
2134
|
+
|
2135
|
+
static int merge_ancestor_head(
|
2136
|
+
git_merge_head **ancestor_head,
|
2137
|
+
git_repository *repo,
|
2138
|
+
const git_merge_head *our_head,
|
2139
|
+
const git_merge_head **their_heads,
|
2140
|
+
size_t their_heads_len)
|
2025
2141
|
{
|
2142
|
+
git_oid *oids, ancestor_oid;
|
2143
|
+
size_t i;
|
2026
2144
|
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
2145
|
|
2031
|
-
assert(repo);
|
2146
|
+
assert(repo && our_head && their_heads);
|
2032
2147
|
|
2033
|
-
|
2034
|
-
|
2035
|
-
git_buf_joinpath(&merge_msg_path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0)
|
2036
|
-
return -1;
|
2148
|
+
oids = git__calloc(their_heads_len + 1, sizeof(git_oid));
|
2149
|
+
GITERR_CHECK_ALLOC(oids);
|
2037
2150
|
|
2038
|
-
|
2039
|
-
|
2040
|
-
|
2151
|
+
git_oid_cpy(&oids[0], git_commit_id(our_head->commit));
|
2152
|
+
|
2153
|
+
for (i = 0; i < their_heads_len; i++)
|
2154
|
+
git_oid_cpy(&oids[i + 1], &their_heads[i]->oid);
|
2155
|
+
|
2156
|
+
if ((error = git_merge_base_many(&ancestor_oid, repo, their_heads_len + 1, oids)) < 0)
|
2157
|
+
goto on_error;
|
2158
|
+
|
2159
|
+
error = git_merge_head_from_id(ancestor_head, repo, &ancestor_oid);
|
2160
|
+
|
2161
|
+
on_error:
|
2162
|
+
git__free(oids);
|
2163
|
+
return error;
|
2164
|
+
}
|
2165
|
+
|
2166
|
+
const char *merge_their_label(const char *branchname)
|
2167
|
+
{
|
2168
|
+
const char *slash;
|
2169
|
+
|
2170
|
+
if ((slash = strrchr(branchname, '/')) == NULL)
|
2171
|
+
return branchname;
|
2172
|
+
|
2173
|
+
if (*(slash+1) == '\0')
|
2174
|
+
return "theirs";
|
2175
|
+
|
2176
|
+
return slash+1;
|
2177
|
+
}
|
2178
|
+
|
2179
|
+
static int merge_normalize_checkout_opts(
|
2180
|
+
git_repository *repo,
|
2181
|
+
git_checkout_options *checkout_opts,
|
2182
|
+
const git_checkout_options *given_checkout_opts,
|
2183
|
+
const git_merge_head *ancestor_head,
|
2184
|
+
const git_merge_head *our_head,
|
2185
|
+
size_t their_heads_len,
|
2186
|
+
const git_merge_head **their_heads)
|
2187
|
+
{
|
2188
|
+
int error = 0;
|
2189
|
+
|
2190
|
+
GIT_UNUSED(repo);
|
2191
|
+
|
2192
|
+
if (given_checkout_opts != NULL)
|
2193
|
+
memcpy(checkout_opts, given_checkout_opts, sizeof(git_checkout_options));
|
2194
|
+
else {
|
2195
|
+
git_checkout_options default_checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
|
2196
|
+
default_checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE |
|
2197
|
+
GIT_CHECKOUT_ALLOW_CONFLICTS;
|
2198
|
+
|
2199
|
+
memcpy(checkout_opts, &default_checkout_opts, sizeof(git_checkout_options));
|
2200
|
+
}
|
2201
|
+
|
2202
|
+
/* TODO: for multiple ancestors in merge-recursive, this is "merged common ancestors" */
|
2203
|
+
if (!checkout_opts->ancestor_label) {
|
2204
|
+
if (ancestor_head && ancestor_head->commit)
|
2205
|
+
checkout_opts->ancestor_label = git_commit_summary(ancestor_head->commit);
|
2206
|
+
else
|
2207
|
+
checkout_opts->ancestor_label = "ancestor";
|
2208
|
+
}
|
2209
|
+
|
2210
|
+
if (!checkout_opts->our_label) {
|
2211
|
+
if (our_head && our_head->ref_name)
|
2212
|
+
checkout_opts->our_label = our_head->ref_name;
|
2213
|
+
else
|
2214
|
+
checkout_opts->our_label = "ours";
|
2215
|
+
}
|
2216
|
+
|
2217
|
+
if (!checkout_opts->their_label) {
|
2218
|
+
if (their_heads_len == 1 && their_heads[0]->ref_name)
|
2219
|
+
checkout_opts->their_label = merge_their_label(their_heads[0]->ref_name);
|
2220
|
+
else if (their_heads_len == 1)
|
2221
|
+
checkout_opts->their_label = their_heads[0]->oid_str;
|
2222
|
+
else
|
2223
|
+
checkout_opts->their_label = "theirs";
|
2224
|
+
}
|
2225
|
+
|
2226
|
+
return error;
|
2227
|
+
}
|
2228
|
+
|
2229
|
+
static int merge_affected_paths(git_vector *paths, git_repository *repo, git_index *index_new)
|
2230
|
+
{
|
2231
|
+
git_tree *head_tree = NULL;
|
2232
|
+
git_iterator *iter_head = NULL, *iter_new = NULL;
|
2233
|
+
git_diff *merged_list = NULL;
|
2234
|
+
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
|
2235
|
+
git_diff_delta *delta;
|
2236
|
+
size_t i;
|
2237
|
+
const git_index_entry *e;
|
2238
|
+
char *path;
|
2239
|
+
int error = 0;
|
2240
|
+
|
2241
|
+
if ((error = git_repository_head_tree(&head_tree, repo)) < 0 ||
|
2242
|
+
(error = git_iterator_for_tree(&iter_head, head_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
|
2243
|
+
(error = git_iterator_for_index(&iter_new, index_new, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
|
2244
|
+
(error = git_diff__from_iterators(&merged_list, repo, iter_head, iter_new, &opts)) < 0)
|
2245
|
+
goto done;
|
2246
|
+
|
2247
|
+
git_vector_foreach(&merged_list->deltas, i, delta) {
|
2248
|
+
path = git__strdup(delta->new_file.path);
|
2249
|
+
GITERR_CHECK_ALLOC(path);
|
2250
|
+
|
2251
|
+
if ((error = git_vector_insert(paths, path)) < 0)
|
2252
|
+
goto on_error;
|
2253
|
+
}
|
2254
|
+
|
2255
|
+
for (i = 0; i < git_index_entrycount(index_new); i++) {
|
2256
|
+
e = git_index_get_byindex(index_new, i);
|
2257
|
+
|
2258
|
+
if (git_index_entry_stage(e) != 0 &&
|
2259
|
+
(git_vector_last(paths) == NULL ||
|
2260
|
+
strcmp(git_vector_last(paths), e->path) != 0)) {
|
2261
|
+
|
2262
|
+
path = git__strdup(e->path);
|
2263
|
+
GITERR_CHECK_ALLOC(path);
|
2264
|
+
|
2265
|
+
if ((error = git_vector_insert(paths, path)) < 0)
|
2266
|
+
goto on_error;
|
2267
|
+
}
|
2268
|
+
}
|
2269
|
+
|
2270
|
+
goto done;
|
2271
|
+
|
2272
|
+
on_error:
|
2273
|
+
git_vector_foreach(paths, i, path)
|
2274
|
+
git__free(path);
|
2275
|
+
|
2276
|
+
git_vector_clear(paths);
|
2277
|
+
|
2278
|
+
done:
|
2279
|
+
git_tree_free(head_tree);
|
2280
|
+
git_iterator_free(iter_head);
|
2281
|
+
git_iterator_free(iter_new);
|
2282
|
+
git_diff_free(merged_list);
|
2283
|
+
|
2284
|
+
return error;
|
2285
|
+
}
|
2286
|
+
|
2287
|
+
static int merge_check_index(size_t *conflicts, git_repository *repo, git_index *index_new, git_vector *merged_paths)
|
2288
|
+
{
|
2289
|
+
git_tree *head_tree = NULL;
|
2290
|
+
git_index *index_repo = NULL;
|
2291
|
+
git_iterator *iter_repo = NULL, *iter_new = NULL;
|
2292
|
+
git_diff *staged_diff_list = NULL, *index_diff_list = NULL;
|
2293
|
+
git_diff_delta *delta;
|
2294
|
+
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
|
2295
|
+
git_vector staged_paths = GIT_VECTOR_INIT;
|
2296
|
+
size_t i;
|
2297
|
+
int error = 0;
|
2298
|
+
|
2299
|
+
GIT_UNUSED(merged_paths);
|
2300
|
+
|
2301
|
+
*conflicts = 0;
|
2302
|
+
|
2303
|
+
/* No staged changes may exist unless the change staged is identical to
|
2304
|
+
* the result of the merge. This allows one to apply to merge manually,
|
2305
|
+
* then run merge. Any other staged change would be overwritten by
|
2306
|
+
* a reset merge.
|
2307
|
+
*/
|
2308
|
+
if ((error = git_repository_head_tree(&head_tree, repo)) < 0 ||
|
2309
|
+
(error = git_repository_index(&index_repo, repo)) < 0 ||
|
2310
|
+
(error = git_diff_tree_to_index(&staged_diff_list, repo, head_tree, index_repo, &opts)) < 0)
|
2311
|
+
goto done;
|
2312
|
+
|
2313
|
+
if (staged_diff_list->deltas.length == 0)
|
2314
|
+
goto done;
|
2315
|
+
|
2316
|
+
git_vector_foreach(&staged_diff_list->deltas, i, delta) {
|
2317
|
+
if ((error = git_vector_insert(&staged_paths, (char *)delta->new_file.path)) < 0)
|
2318
|
+
goto done;
|
2319
|
+
}
|
2320
|
+
|
2321
|
+
opts.pathspec.count = staged_paths.length;
|
2322
|
+
opts.pathspec.strings = (char **)staged_paths.contents;
|
2323
|
+
|
2324
|
+
if ((error = git_iterator_for_index(&iter_repo, index_repo, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
|
2325
|
+
(error = git_iterator_for_index(&iter_new, index_new, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
|
2326
|
+
(error = git_diff__from_iterators(&index_diff_list, repo, iter_repo, iter_new, &opts)) < 0)
|
2327
|
+
goto done;
|
2328
|
+
|
2329
|
+
*conflicts = index_diff_list->deltas.length;
|
2330
|
+
|
2331
|
+
done:
|
2332
|
+
git_tree_free(head_tree);
|
2333
|
+
git_index_free(index_repo);
|
2334
|
+
git_iterator_free(iter_repo);
|
2335
|
+
git_iterator_free(iter_new);
|
2336
|
+
git_diff_free(staged_diff_list);
|
2337
|
+
git_diff_free(index_diff_list);
|
2338
|
+
git_vector_free(&staged_paths);
|
2339
|
+
|
2340
|
+
return error;
|
2341
|
+
}
|
2342
|
+
|
2343
|
+
static int merge_check_workdir(size_t *conflicts, git_repository *repo, git_index *index_new, git_vector *merged_paths)
|
2344
|
+
{
|
2345
|
+
git_index *index_repo = NULL;
|
2346
|
+
git_diff *wd_diff_list = NULL;
|
2347
|
+
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
|
2348
|
+
int error = 0;
|
2349
|
+
|
2350
|
+
GIT_UNUSED(index_new);
|
2351
|
+
|
2352
|
+
*conflicts = 0;
|
2353
|
+
|
2354
|
+
opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED;
|
2355
|
+
|
2356
|
+
/* Workdir changes may exist iff they do not conflict with changes that
|
2357
|
+
* will be applied by the merge (including conflicts). Ensure that there
|
2358
|
+
* are no changes in the workdir to these paths.
|
2359
|
+
*/
|
2360
|
+
opts.pathspec.count = merged_paths->length;
|
2361
|
+
opts.pathspec.strings = (char **)merged_paths->contents;
|
2362
|
+
|
2363
|
+
if ((error = git_diff_index_to_workdir(&wd_diff_list, repo, index_repo, &opts)) < 0)
|
2364
|
+
goto done;
|
2365
|
+
|
2366
|
+
*conflicts = wd_diff_list->deltas.length;
|
2367
|
+
|
2368
|
+
done:
|
2369
|
+
git_index_free(index_repo);
|
2370
|
+
git_diff_free(wd_diff_list);
|
2371
|
+
|
2372
|
+
return error;
|
2373
|
+
}
|
2374
|
+
|
2375
|
+
int git_merge__indexes(git_repository *repo, git_index *index_new)
|
2376
|
+
{
|
2377
|
+
git_index *index_repo = NULL;
|
2378
|
+
int index_repo_caps = 0;
|
2379
|
+
git_vector paths = GIT_VECTOR_INIT;
|
2380
|
+
size_t index_conflicts = 0, wd_conflicts = 0, conflicts, i;
|
2381
|
+
char *path;
|
2382
|
+
const git_index_entry *e;
|
2383
|
+
const git_index_name_entry *name;
|
2384
|
+
const git_index_reuc_entry *reuc;
|
2385
|
+
int error = 0;
|
2386
|
+
|
2387
|
+
if ((error = git_repository_index(&index_repo, repo)) < 0)
|
2388
|
+
goto done;
|
2389
|
+
|
2390
|
+
/* Set the index to case sensitive to handle the merge */
|
2391
|
+
index_repo_caps = git_index_caps(index_repo);
|
2392
|
+
|
2393
|
+
if ((error = git_index_set_caps(index_repo, (index_repo_caps & ~GIT_INDEXCAP_IGNORE_CASE))) < 0)
|
2394
|
+
goto done;
|
2395
|
+
|
2396
|
+
/* Make sure the index and workdir state do not prevent merging */
|
2397
|
+
if ((error = merge_affected_paths(&paths, repo, index_new)) < 0 ||
|
2398
|
+
(error = merge_check_index(&index_conflicts, repo, index_new, &paths)) < 0 ||
|
2399
|
+
(error = merge_check_workdir(&wd_conflicts, repo, index_new, &paths)) < 0)
|
2400
|
+
goto done;
|
2401
|
+
|
2402
|
+
if ((conflicts = index_conflicts + wd_conflicts) > 0) {
|
2403
|
+
giterr_set(GITERR_MERGE, "%d uncommitted change%s would be overwritten by merge",
|
2404
|
+
conflicts, (conflicts != 1) ? "s" : "");
|
2405
|
+
error = GIT_EMERGECONFLICT;
|
2406
|
+
|
2407
|
+
goto done;
|
2408
|
+
}
|
2409
|
+
|
2410
|
+
/* Remove removed items from the index */
|
2411
|
+
git_vector_foreach(&paths, i, path) {
|
2412
|
+
if (git_index_get_bypath(index_new, path, 0) == NULL) {
|
2413
|
+
if ((error = git_index_remove(index_repo, path, 0)) < 0 &&
|
2414
|
+
error != GIT_ENOTFOUND)
|
2415
|
+
goto done;
|
2416
|
+
}
|
2417
|
+
}
|
2418
|
+
|
2419
|
+
/* Add updated items to the index */
|
2420
|
+
git_vector_foreach(&paths, i, path) {
|
2421
|
+
if ((e = git_index_get_bypath(index_new, path, 0)) != NULL) {
|
2422
|
+
if ((error = git_index_add(index_repo, e)) < 0)
|
2423
|
+
goto done;
|
2424
|
+
}
|
2041
2425
|
}
|
2042
2426
|
|
2043
|
-
|
2044
|
-
|
2427
|
+
/* Add conflicts */
|
2428
|
+
git_index_conflict_cleanup(index_repo);
|
2429
|
+
|
2430
|
+
for (i = 0; i < git_index_entrycount(index_new); i++) {
|
2431
|
+
e = git_index_get_byindex(index_new, i);
|
2432
|
+
|
2433
|
+
if (git_index_entry_stage(e) != 0 &&
|
2434
|
+
(error = git_index_add(index_repo, e)) < 0)
|
2435
|
+
goto done;
|
2436
|
+
}
|
2437
|
+
|
2438
|
+
/* Add name entries */
|
2439
|
+
git_index_name_clear(index_repo);
|
2440
|
+
|
2441
|
+
for (i = 0; i < git_index_name_entrycount(index_new); i++) {
|
2442
|
+
name = git_index_name_get_byindex(index_new, i);
|
2443
|
+
|
2444
|
+
if ((error = git_index_name_add(index_repo,
|
2445
|
+
name->ancestor, name->ours, name->theirs)) < 0)
|
2446
|
+
goto done;
|
2447
|
+
}
|
2448
|
+
|
2449
|
+
/* Add the reuc */
|
2450
|
+
git_index_reuc_clear(index_repo);
|
2451
|
+
|
2452
|
+
for (i = 0; i < git_index_reuc_entrycount(index_new); i++) {
|
2453
|
+
reuc = (git_index_reuc_entry *)git_index_reuc_get_byindex(index_new, i);
|
2454
|
+
|
2455
|
+
if ((error = git_index_reuc_add(index_repo, reuc->path,
|
2456
|
+
reuc->mode[0], &reuc->oid[0],
|
2457
|
+
reuc->mode[1], &reuc->oid[1],
|
2458
|
+
reuc->mode[2], &reuc->oid[2])) < 0)
|
2459
|
+
goto done;
|
2460
|
+
}
|
2461
|
+
|
2462
|
+
done:
|
2463
|
+
if (index_repo != NULL)
|
2464
|
+
git_index_set_caps(index_repo, index_repo_caps);
|
2465
|
+
|
2466
|
+
git_index_free(index_repo);
|
2467
|
+
git_vector_free_deep(&paths);
|
2468
|
+
|
2469
|
+
return error;
|
2470
|
+
}
|
2471
|
+
|
2472
|
+
int git_merge__append_conflicts_to_merge_msg(
|
2473
|
+
git_repository *repo,
|
2474
|
+
git_index *index)
|
2475
|
+
{
|
2476
|
+
git_filebuf file = GIT_FILEBUF_INIT;
|
2477
|
+
git_buf file_path = GIT_BUF_INIT;
|
2478
|
+
const char *last = NULL;
|
2479
|
+
size_t i;
|
2480
|
+
int error;
|
2481
|
+
|
2482
|
+
if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_MERGE_MSG_FILE)) < 0 ||
|
2483
|
+
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_APPEND, GIT_MERGE_FILE_MODE)) < 0)
|
2484
|
+
goto cleanup;
|
2485
|
+
|
2486
|
+
if (git_index_has_conflicts(index))
|
2487
|
+
git_filebuf_printf(&file, "\nConflicts:\n");
|
2045
2488
|
|
2046
|
-
|
2047
|
-
(
|
2489
|
+
for (i = 0; i < git_index_entrycount(index); i++) {
|
2490
|
+
const git_index_entry *e = git_index_get_byindex(index, i);
|
2491
|
+
|
2492
|
+
if (git_index_entry_stage(e) == 0)
|
2493
|
+
continue;
|
2494
|
+
|
2495
|
+
if (last == NULL || strcmp(e->path, last) != 0)
|
2496
|
+
git_filebuf_printf(&file, "\t%s\n", e->path);
|
2497
|
+
|
2498
|
+
last = e->path;
|
2499
|
+
}
|
2500
|
+
|
2501
|
+
error = git_filebuf_commit(&file);
|
2048
2502
|
|
2049
2503
|
cleanup:
|
2050
|
-
|
2051
|
-
|
2052
|
-
|
2504
|
+
if (error < 0)
|
2505
|
+
git_filebuf_cleanup(&file);
|
2506
|
+
|
2507
|
+
git_buf_free(&file_path);
|
2508
|
+
|
2509
|
+
return error;
|
2510
|
+
}
|
2511
|
+
|
2512
|
+
|
2513
|
+
static int merge_state_cleanup(git_repository *repo)
|
2514
|
+
{
|
2515
|
+
const char *state_files[] = {
|
2516
|
+
GIT_MERGE_HEAD_FILE,
|
2517
|
+
GIT_MERGE_MODE_FILE,
|
2518
|
+
GIT_MERGE_MSG_FILE,
|
2519
|
+
};
|
2520
|
+
|
2521
|
+
return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files));
|
2522
|
+
}
|
2523
|
+
|
2524
|
+
static int merge_heads(
|
2525
|
+
git_merge_head **ancestor_head_out,
|
2526
|
+
git_merge_head **our_head_out,
|
2527
|
+
git_repository *repo,
|
2528
|
+
const git_merge_head **their_heads,
|
2529
|
+
size_t their_heads_len)
|
2530
|
+
{
|
2531
|
+
git_merge_head *ancestor_head = NULL, *our_head = NULL;
|
2532
|
+
git_reference *our_ref = NULL;
|
2533
|
+
int error = 0;
|
2534
|
+
|
2535
|
+
*ancestor_head_out = NULL;
|
2536
|
+
*our_head_out = NULL;
|
2537
|
+
|
2538
|
+
if ((error = git_repository__ensure_not_bare(repo, "merge")) < 0)
|
2539
|
+
goto done;
|
2540
|
+
|
2541
|
+
if ((error = git_reference_lookup(&our_ref, repo, GIT_HEAD_FILE)) < 0 ||
|
2542
|
+
(error = git_merge_head_from_ref(&our_head, repo, our_ref)) < 0)
|
2543
|
+
goto done;
|
2544
|
+
|
2545
|
+
if ((error = merge_ancestor_head(&ancestor_head, repo, our_head, their_heads, their_heads_len)) < 0) {
|
2546
|
+
if (error != GIT_ENOTFOUND)
|
2547
|
+
goto done;
|
2548
|
+
|
2549
|
+
giterr_clear();
|
2550
|
+
error = 0;
|
2551
|
+
}
|
2552
|
+
|
2553
|
+
*ancestor_head_out = ancestor_head;
|
2554
|
+
*our_head_out = our_head;
|
2555
|
+
|
2556
|
+
done:
|
2557
|
+
if (error < 0) {
|
2558
|
+
git_merge_head_free(ancestor_head);
|
2559
|
+
git_merge_head_free(our_head);
|
2560
|
+
}
|
2561
|
+
|
2562
|
+
git_reference_free(our_ref);
|
2563
|
+
|
2564
|
+
return error;
|
2565
|
+
}
|
2566
|
+
|
2567
|
+
static int merge_preference(git_merge_preference_t *out, git_repository *repo)
|
2568
|
+
{
|
2569
|
+
git_config *config;
|
2570
|
+
const char *value;
|
2571
|
+
int bool_value, error = 0;
|
2572
|
+
|
2573
|
+
*out = GIT_MERGE_PREFERENCE_NONE;
|
2574
|
+
|
2575
|
+
if ((error = git_repository_config_snapshot(&config, repo)) < 0)
|
2576
|
+
goto done;
|
2577
|
+
|
2578
|
+
if ((error = git_config_get_string(&value, config, "merge.ff")) < 0) {
|
2579
|
+
if (error == GIT_ENOTFOUND) {
|
2580
|
+
giterr_clear();
|
2581
|
+
error = 0;
|
2582
|
+
}
|
2583
|
+
|
2584
|
+
goto done;
|
2585
|
+
}
|
2586
|
+
|
2587
|
+
if (git_config_parse_bool(&bool_value, value) == 0) {
|
2588
|
+
if (!bool_value)
|
2589
|
+
*out |= GIT_MERGE_PREFERENCE_NO_FASTFORWARD;
|
2590
|
+
} else {
|
2591
|
+
if (strcasecmp(value, "only") == 0)
|
2592
|
+
*out |= GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY;
|
2593
|
+
}
|
2594
|
+
|
2595
|
+
done:
|
2596
|
+
git_config_free(config);
|
2597
|
+
return error;
|
2598
|
+
}
|
2599
|
+
|
2600
|
+
int git_merge_analysis(
|
2601
|
+
git_merge_analysis_t *analysis_out,
|
2602
|
+
git_merge_preference_t *preference_out,
|
2603
|
+
git_repository *repo,
|
2604
|
+
const git_merge_head **their_heads,
|
2605
|
+
size_t their_heads_len)
|
2606
|
+
{
|
2607
|
+
git_merge_head *ancestor_head = NULL, *our_head = NULL;
|
2608
|
+
int error = 0;
|
2609
|
+
|
2610
|
+
assert(analysis_out && preference_out && repo && their_heads);
|
2611
|
+
|
2612
|
+
if (their_heads_len != 1) {
|
2613
|
+
giterr_set(GITERR_MERGE, "Can only merge a single branch");
|
2614
|
+
error = -1;
|
2615
|
+
goto done;
|
2616
|
+
}
|
2617
|
+
|
2618
|
+
*analysis_out = GIT_MERGE_ANALYSIS_NONE;
|
2619
|
+
|
2620
|
+
if ((error = merge_preference(preference_out, repo)) < 0)
|
2621
|
+
goto done;
|
2622
|
+
|
2623
|
+
if (git_repository_head_unborn(repo)) {
|
2624
|
+
*analysis_out |= GIT_MERGE_ANALYSIS_FASTFORWARD | GIT_MERGE_ANALYSIS_UNBORN;
|
2625
|
+
goto done;
|
2626
|
+
}
|
2627
|
+
|
2628
|
+
if ((error = merge_heads(&ancestor_head, &our_head, repo, their_heads, their_heads_len)) < 0)
|
2629
|
+
goto done;
|
2630
|
+
|
2631
|
+
/* We're up-to-date if we're trying to merge our own common ancestor. */
|
2632
|
+
if (ancestor_head && git_oid_equal(&ancestor_head->oid, &their_heads[0]->oid))
|
2633
|
+
*analysis_out |= GIT_MERGE_ANALYSIS_UP_TO_DATE;
|
2634
|
+
|
2635
|
+
/* We're fastforwardable if we're our own common ancestor. */
|
2636
|
+
else if (ancestor_head && git_oid_equal(&ancestor_head->oid, &our_head->oid))
|
2637
|
+
*analysis_out |= GIT_MERGE_ANALYSIS_FASTFORWARD | GIT_MERGE_ANALYSIS_NORMAL;
|
2638
|
+
|
2639
|
+
/* Otherwise, just a normal merge is possible. */
|
2640
|
+
else
|
2641
|
+
*analysis_out |= GIT_MERGE_ANALYSIS_NORMAL;
|
2642
|
+
|
2643
|
+
done:
|
2644
|
+
git_merge_head_free(ancestor_head);
|
2645
|
+
git_merge_head_free(our_head);
|
2646
|
+
return error;
|
2647
|
+
}
|
2648
|
+
|
2649
|
+
int git_merge(
|
2650
|
+
git_repository *repo,
|
2651
|
+
const git_merge_head **their_heads,
|
2652
|
+
size_t their_heads_len,
|
2653
|
+
const git_merge_options *merge_opts,
|
2654
|
+
const git_checkout_options *given_checkout_opts)
|
2655
|
+
{
|
2656
|
+
git_reference *our_ref = NULL;
|
2657
|
+
git_checkout_options checkout_opts;
|
2658
|
+
git_merge_head *ancestor_head = NULL, *our_head = NULL;
|
2659
|
+
git_tree *ancestor_tree = NULL, *our_tree = NULL, **their_trees = NULL;
|
2660
|
+
git_index *index_new = NULL, *index_repo = NULL;
|
2661
|
+
size_t i;
|
2662
|
+
int error = 0;
|
2663
|
+
|
2664
|
+
assert(repo && their_heads);
|
2665
|
+
|
2666
|
+
if (their_heads_len != 1) {
|
2667
|
+
giterr_set(GITERR_MERGE, "Can only merge a single branch");
|
2668
|
+
return -1;
|
2669
|
+
}
|
2670
|
+
|
2671
|
+
their_trees = git__calloc(their_heads_len, sizeof(git_tree *));
|
2672
|
+
GITERR_CHECK_ALLOC(their_trees);
|
2673
|
+
|
2674
|
+
if ((error = merge_heads(&ancestor_head, &our_head, repo, their_heads, their_heads_len)) < 0)
|
2675
|
+
goto on_error;
|
2676
|
+
|
2677
|
+
if ((error = merge_normalize_checkout_opts(repo, &checkout_opts, given_checkout_opts,
|
2678
|
+
ancestor_head, our_head, their_heads_len, their_heads)) < 0)
|
2679
|
+
goto on_error;
|
2680
|
+
|
2681
|
+
/* Write the merge files to the repository. */
|
2682
|
+
if ((error = git_merge__setup(repo, our_head, their_heads, their_heads_len)) < 0)
|
2683
|
+
goto on_error;
|
2684
|
+
|
2685
|
+
if (ancestor_head != NULL &&
|
2686
|
+
(error = git_commit_tree(&ancestor_tree, ancestor_head->commit)) < 0)
|
2687
|
+
goto on_error;
|
2688
|
+
|
2689
|
+
if ((error = git_commit_tree(&our_tree, our_head->commit)) < 0)
|
2690
|
+
goto on_error;
|
2691
|
+
|
2692
|
+
for (i = 0; i < their_heads_len; i++) {
|
2693
|
+
if ((error = git_commit_tree(&their_trees[i], their_heads[i]->commit)) < 0)
|
2694
|
+
goto on_error;
|
2695
|
+
}
|
2696
|
+
|
2697
|
+
/* TODO: recursive, octopus, etc... */
|
2698
|
+
|
2699
|
+
if ((error = git_merge_trees(&index_new, repo, ancestor_tree, our_tree, their_trees[0], merge_opts)) < 0 ||
|
2700
|
+
(error = git_merge__indexes(repo, index_new)) < 0 ||
|
2701
|
+
(error = git_repository_index(&index_repo, repo)) < 0 ||
|
2702
|
+
(error = git_merge__append_conflicts_to_merge_msg(repo, index_repo)) < 0 ||
|
2703
|
+
(error = git_checkout_index(repo, index_repo, &checkout_opts)) < 0)
|
2704
|
+
goto on_error;
|
2705
|
+
|
2706
|
+
goto done;
|
2707
|
+
|
2708
|
+
on_error:
|
2709
|
+
merge_state_cleanup(repo);
|
2710
|
+
|
2711
|
+
done:
|
2712
|
+
git_index_free(index_new);
|
2713
|
+
git_index_free(index_repo);
|
2714
|
+
|
2715
|
+
git_tree_free(ancestor_tree);
|
2716
|
+
git_tree_free(our_tree);
|
2717
|
+
|
2718
|
+
for (i = 0; i < their_heads_len; i++)
|
2719
|
+
git_tree_free(their_trees[i]);
|
2720
|
+
|
2721
|
+
git__free(their_trees);
|
2722
|
+
|
2723
|
+
git_merge_head_free(our_head);
|
2724
|
+
git_merge_head_free(ancestor_head);
|
2725
|
+
|
2726
|
+
git_reference_free(our_ref);
|
2053
2727
|
|
2054
2728
|
return error;
|
2055
2729
|
}
|
@@ -2085,6 +2759,9 @@ static int merge_head_init(
|
|
2085
2759
|
|
2086
2760
|
git_oid_cpy(&head->oid, oid);
|
2087
2761
|
|
2762
|
+
git_oid_fmt(head->oid_str, oid);
|
2763
|
+
head->oid_str[GIT_OID_HEXSZ] = '\0';
|
2764
|
+
|
2088
2765
|
if ((error = git_commit_lookup(&head->commit, repo, &head->oid)) < 0) {
|
2089
2766
|
git_merge_head_free(head);
|
2090
2767
|
return error;
|
@@ -2097,7 +2774,7 @@ static int merge_head_init(
|
|
2097
2774
|
int git_merge_head_from_ref(
|
2098
2775
|
git_merge_head **out,
|
2099
2776
|
git_repository *repo,
|
2100
|
-
git_reference *ref)
|
2777
|
+
const git_reference *ref)
|
2101
2778
|
{
|
2102
2779
|
git_reference *resolved;
|
2103
2780
|
int error = 0;
|
@@ -2116,7 +2793,7 @@ int git_merge_head_from_ref(
|
|
2116
2793
|
return error;
|
2117
2794
|
}
|
2118
2795
|
|
2119
|
-
int
|
2796
|
+
int git_merge_head_from_id(
|
2120
2797
|
git_merge_head **out,
|
2121
2798
|
git_repository *repo,
|
2122
2799
|
const git_oid *oid)
|
@@ -2138,6 +2815,14 @@ int git_merge_head_from_fetchhead(
|
|
2138
2815
|
return merge_head_init(out, repo, branch_name, remote_url, oid);
|
2139
2816
|
}
|
2140
2817
|
|
2818
|
+
const git_oid *git_merge_head_id(
|
2819
|
+
const git_merge_head *head)
|
2820
|
+
{
|
2821
|
+
assert(head);
|
2822
|
+
|
2823
|
+
return &head->oid;
|
2824
|
+
}
|
2825
|
+
|
2141
2826
|
void git_merge_head_free(git_merge_head *head)
|
2142
2827
|
{
|
2143
2828
|
if (head == NULL)
|
@@ -2154,3 +2839,25 @@ void git_merge_head_free(git_merge_head *head)
|
|
2154
2839
|
|
2155
2840
|
git__free(head);
|
2156
2841
|
}
|
2842
|
+
|
2843
|
+
int git_merge_init_options(git_merge_options *opts, unsigned int version)
|
2844
|
+
{
|
2845
|
+
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
|
2846
|
+
opts, version, git_merge_options, GIT_MERGE_OPTIONS_INIT);
|
2847
|
+
return 0;
|
2848
|
+
}
|
2849
|
+
|
2850
|
+
int git_merge_file_init_input(git_merge_file_input *input, unsigned int version)
|
2851
|
+
{
|
2852
|
+
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
|
2853
|
+
input, version, git_merge_file_input, GIT_MERGE_FILE_INPUT_INIT);
|
2854
|
+
return 0;
|
2855
|
+
}
|
2856
|
+
|
2857
|
+
int git_merge_file_init_options(
|
2858
|
+
git_merge_file_options *opts, unsigned int version)
|
2859
|
+
{
|
2860
|
+
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
|
2861
|
+
opts, version, git_merge_file_options, GIT_MERGE_FILE_OPTIONS_INIT);
|
2862
|
+
return 0;
|
2863
|
+
}
|