void test_reset_soft__fails_when_index_contains_conflicts_independently_of_MERGE_HEAD_file_existence(void) { git_index *index; git_reference *head; git_buf merge_head_path = GIT_BUF_INIT; cl_git_sandbox_cleanup(); repo = cl_git_sandbox_init("mergedrepo"); cl_git_pass(git_buf_joinpath(&merge_head_path, git_repository_path(repo), "MERGE_HEAD")); cl_git_pass(p_unlink(git_buf_cstr(&merge_head_path))); git_buf_free(&merge_head_path); cl_git_pass(git_repository_index(&index, repo)); cl_assert_equal_i(true, git_index_has_conflicts(index)); git_index_free(index); cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel(&target, head, GIT_OBJ_COMMIT)); git_reference_free(head); cl_assert_equal_i(GIT_EUNMERGED, git_reset(repo, target, GIT_RESET_SOFT)); }
int merge_test_workdir(git_repository *repo, const struct merge_index_entry expected[], size_t expected_len) { size_t actual_len = 0, i; git_oid actual_oid, expected_oid; git_buf wd = GIT_BUF_INIT; git_buf_puts(&wd, repo->workdir); git_path_direach(&wd, 0, dircount, &actual_len); if (actual_len != expected_len) return 0; for (i = 0; i < expected_len; i++) { git_blob_create_fromworkdir(&actual_oid, repo, expected[i].path); git_oid_fromstr(&expected_oid, expected[i].oid_str); if (git_oid_cmp(&actual_oid, &expected_oid) != 0) return 0; } git_buf_free(&wd); return 1; }
void test_filter_crlf__to_odb(void) { git_filter_list *fl; git_filter *crlf; git_buf in = { 0 }, out = { 0 }; cl_git_pass(git_filter_list_new( &fl, g_repo, GIT_FILTER_TO_ODB, 0)); crlf = git_filter_lookup(GIT_FILTER_CRLF); cl_assert(crlf != NULL); cl_git_pass(git_filter_list_push(fl, crlf, NULL)); in.ptr = "Some text\r\nRight here\r\n"; in.size = strlen(in.ptr); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); cl_assert_equal_s("Some text\nRight here\n", out.ptr); git_filter_list_free(fl); git_buf_free(&out); }
void test_repo_init__external_templates_specified_in_config(void) { git_buf template_path = GIT_BUF_INIT; git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; cl_set_cleanup(&cleanup_repository, "templated.git"); template_sandbox("template"); cl_git_pass(git_buf_joinpath(&template_path, clar_sandbox_path(), "template")); configure_templatedir(template_path.ptr); opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_BARE | GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE; cl_git_pass(git_repository_init_ext(&_repo, "templated.git", &opts)); validate_templates(_repo, "template"); cl_fixture_cleanup("template"); git_buf_free(&template_path); }
void test_refs_reflog_messages__creating_branches_default_messages(void) { git_buf buf = GIT_BUF_INIT; git_annotated_commit *annotated; git_object *obj; git_commit *target; git_reference *branch1, *branch2; cl_git_pass(git_revparse_single(&obj, g_repo, "e90810b8df3")); cl_git_pass(git_commit_lookup(&target, g_repo, git_object_id(obj))); git_object_free(obj); cl_git_pass(git_branch_create(&branch1, g_repo, NEW_BRANCH_NAME, target, false)); cl_git_pass(git_buf_printf(&buf, "branch: Created from %s", git_oid_tostr_s(git_commit_id(target)))); cl_reflog_check_entry(g_repo, "refs/heads/" NEW_BRANCH_NAME, 0, GIT_OID_HEX_ZERO, git_oid_tostr_s(git_commit_id(target)), g_email, git_buf_cstr(&buf)); cl_git_pass(git_reference_remove(g_repo, "refs/heads/" NEW_BRANCH_NAME)); cl_git_pass(git_annotated_commit_from_revspec(&annotated, g_repo, "e90810b8df3")); cl_git_pass(git_branch_create_from_annotated(&branch2, g_repo, NEW_BRANCH_NAME, annotated, true)); cl_reflog_check_entry(g_repo, "refs/heads/" NEW_BRANCH_NAME, 0, GIT_OID_HEX_ZERO, git_oid_tostr_s(git_commit_id(target)), g_email, "branch: Created from e90810b8df3"); git_annotated_commit_free(annotated); git_buf_free(&buf); git_commit_free(target); git_reference_free(branch1); git_reference_free(branch2); }
void test_object_shortid__select(void) { git_oid full; git_object *obj; git_buf shorty = {0}; git_oid_fromstr(&full, "ce013625030ba8dba906f756967f9e9ca394464a"); cl_git_pass(git_object_lookup(&obj, _repo, &full, GIT_OBJ_ANY)); cl_git_pass(git_object_short_id(&shorty, obj)); cl_assert_equal_i(7, shorty.size); cl_assert_equal_s("ce01362", shorty.ptr); git_object_free(obj); git_oid_fromstr(&full, "038d718da6a1ebbc6a7780a96ed75a70cc2ad6e2"); cl_git_pass(git_object_lookup(&obj, _repo, &full, GIT_OBJ_ANY)); cl_git_pass(git_object_short_id(&shorty, obj)); cl_assert_equal_i(7, shorty.size); cl_assert_equal_s("038d718", shorty.ptr); git_object_free(obj); git_oid_fromstr(&full, "dea509d097ce692e167dfc6a48a7a280cc5e877e"); cl_git_pass(git_object_lookup(&obj, _repo, &full, GIT_OBJ_ANY)); cl_git_pass(git_object_short_id(&shorty, obj)); cl_assert_equal_i(9, shorty.size); cl_assert_equal_s("dea509d09", shorty.ptr); git_object_free(obj); git_oid_fromstr(&full, "dea509d0b3cb8ee0650f6ca210bc83f4678851ba"); cl_git_pass(git_object_lookup(&obj, _repo, &full, GIT_OBJ_ANY)); cl_git_pass(git_object_short_id(&shorty, obj)); cl_assert_equal_i(9, shorty.size); cl_assert_equal_s("dea509d0b", shorty.ptr); git_object_free(obj); git_buf_free(&shorty); }
static int win32_find_existing_dirs( git_buf *out, const wchar_t *tmpl[]) { _findfile_path path16; git_buf buf = GIT_BUF_INIT; git_buf_clear(out); for (; *tmpl != NULL; tmpl++) { if (!git_win32__expand_path(&path16, *tmpl) && path16.path[0] != L'%' && !_waccess(path16.path, F_OK)) { win32_path_to_8(&buf, path16.path); if (buf.size) git_buf_join(out, GIT_PATH_LIST_SEPARATOR, out->ptr, buf.ptr); } } git_buf_free(&buf); return (git_buf_oom(out) ? -1 : 0); }
int git_futils_dirs_set(git_futils_dir_t which, const char *search_path) { const char *expand_path = NULL; git_buf merge = GIT_BUF_INIT; GITERR_CHECK_ERROR(git_futils_check_selector(which)); if (search_path != NULL) expand_path = strstr(search_path, PATH_MAGIC); /* init with default if not yet done and needed (ignoring error) */ if ((!search_path || expand_path) && !git_buf_len(&git_futils__dirs[which])) git_futils__dir_guess[which](&git_futils__dirs[which]); /* if $PATH is not referenced, then just set the path */ if (!expand_path) return git_buf_sets(&git_futils__dirs[which], search_path); /* otherwise set to join(before $PATH, old value, after $PATH) */ if (expand_path > search_path) git_buf_set(&merge, search_path, expand_path - search_path); if (git_buf_len(&git_futils__dirs[which])) git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR, merge.ptr, git_futils__dirs[which].ptr); expand_path += strlen(PATH_MAGIC); if (*expand_path) git_buf_join(&merge, GIT_PATH_LIST_SEPARATOR, merge.ptr, expand_path); git_buf_swap(&git_futils__dirs[which], &merge); git_buf_free(&merge); return git_buf_oom(&git_futils__dirs[which]) ? -1 : 0; }
void test_core_buffer__base64(void) { git_buf buf = GIT_BUF_INIT; /* t h i s * 0x 74 68 69 73 * 0b 01110100 01101000 01101001 01110011 * 0b 011101 000110 100001 101001 011100 110000 * 0x 1d 06 21 29 1c 30 * d G h p c w */ cl_git_pass(git_buf_put_base64(&buf, "this", 4)); cl_assert_equal_s("dGhpcw==", buf.ptr); git_buf_clear(&buf); cl_git_pass(git_buf_put_base64(&buf, "this!", 5)); cl_assert_equal_s("dGhpcyE=", buf.ptr); git_buf_clear(&buf); cl_git_pass(git_buf_put_base64(&buf, "this!\n", 6)); cl_assert_equal_s("dGhpcyEK", buf.ptr); git_buf_free(&buf); }
int git_path_diriter_init( git_path_diriter *diriter, const char *path, unsigned int flags) { assert(diriter && path); memset(diriter, 0, sizeof(git_path_diriter)); if (git_buf_puts(&diriter->path, path) < 0) return -1; git_path_trim_slashes(&diriter->path); if (diriter->path.size == 0) { giterr_set(GITERR_FILESYSTEM, "Could not open directory '%s'", path); return -1; } if ((diriter->dir = opendir(diriter->path.ptr)) == NULL) { git_buf_free(&diriter->path); giterr_set(GITERR_OS, "Failed to open directory '%s'", path); return -1; } #ifdef GIT_USE_ICONV if ((flags & GIT_PATH_DIR_PRECOMPOSE_UNICODE) != 0) (void)git_path_iconv_init_precompose(&diriter->ic); #endif diriter->parent_len = diriter->path.size; diriter->flags = flags; return 0; }
void test_checkout_index__writes_conflict_file(void) { git_index *index; git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; git_buf conflicting_buf = GIT_BUF_INIT; cl_git_pass(git_repository_index(&index, g_repo)); add_conflict(index, "conflicting.txt"); cl_git_pass(git_index_write(index)); cl_git_pass(git_checkout_index(g_repo, NULL, &opts)); cl_git_pass(git_futils_readbuffer(&conflicting_buf, "testrepo/conflicting.txt")); cl_assert(strcmp(conflicting_buf.ptr, "<<<<<<< ours\n" "this file is changed in master and branch\n" "=======\n" "this file is changed in branch and master\n" ">>>>>>> theirs\n") == 0); git_buf_free(&conflicting_buf); git_index_free(index); }
void test_config_read__path(void) { git_config *cfg; git_buf path = GIT_BUF_INIT; git_buf old_path = GIT_BUF_INIT; git_buf home_path = GIT_BUF_INIT; git_buf expected_path = GIT_BUF_INIT; cl_git_pass(p_mkdir("fakehome", 0777)); cl_git_pass(git_path_prettify(&home_path, "fakehome", NULL)); cl_git_pass(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, &old_path)); cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, home_path.ptr)); cl_git_mkfile("./testconfig", "[some]\n path = ~/somefile"); cl_git_pass(git_path_join_unrooted(&expected_path, "somefile", home_path.ptr, NULL)); cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig")); cl_git_pass(git_config_get_path(&path, cfg, "some.path")); cl_assert_equal_s(expected_path.ptr, path.ptr); git_buf_free(&path); cl_git_mkfile("./testconfig", "[some]\n path = ~/"); cl_git_pass(git_path_join_unrooted(&expected_path, "", home_path.ptr, NULL)); cl_git_pass(git_config_get_path(&path, cfg, "some.path")); cl_assert_equal_s(expected_path.ptr, path.ptr); git_buf_free(&path); cl_git_mkfile("./testconfig", "[some]\n path = ~"); cl_git_pass(git_buf_sets(&expected_path, home_path.ptr)); cl_git_pass(git_config_get_path(&path, cfg, "some.path")); cl_assert_equal_s(expected_path.ptr, path.ptr); git_buf_free(&path); cl_git_mkfile("./testconfig", "[some]\n path = ~user/foo"); cl_git_fail(git_config_get_path(&path, cfg, "some.path")); cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, old_path.ptr)); git_buf_free(&old_path); git_buf_free(&home_path); git_buf_free(&expected_path); git_config_free(cfg); }
/* git revert --no-commit 72333f47d4e83616630ff3b0ffe4c0faebcc3c45 */ void test_revert_workdir__conflicts(void) { git_reference *head_ref; git_commit *head, *commit; git_oid revert_oid; git_buf conflicting_buf = GIT_BUF_INIT, mergemsg_buf = GIT_BUF_INIT; struct merge_index_entry merge_index_entries[] = { { 0100644, "7731926a337c4eaba1e2187d90ebfa0a93659382", 1, "file1.txt" }, { 0100644, "4b8fcff56437e60f58e9a6bc630dd242ebf6ea2c", 2, "file1.txt" }, { 0100644, "3a3ef367eaf3fe79effbfb0a56b269c04c2b59fe", 3, "file1.txt" }, { 0100644, "0ab09ea6d4c3634bdf6c221626d8b6f7dd890767", 0, "file2.txt" }, { 0100644, "f4e107c230d08a60fb419d19869f1f282b272d9c", 0, "file3.txt" }, { 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" }, }; git_oid_fromstr(&revert_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45"); cl_git_pass(git_repository_head(&head_ref, repo)); cl_git_pass(git_reference_peel((git_object **)&head, head_ref, GIT_OBJ_COMMIT)); cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL)); cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); cl_git_pass(git_revert(repo, commit, NULL)); cl_assert(merge_test_index(repo_index, merge_index_entries, 6)); cl_git_pass(git_futils_readbuffer(&conflicting_buf, TEST_REPO_PATH "/file1.txt")); cl_assert(strcmp(conflicting_buf.ptr, "!File one!\n" \ "!File one!\n" \ "File one!\n" \ "File one\n" \ "File one\n" \ "File one\n" \ "File one\n" \ "File one\n" \ "File one\n" \ "File one\n" \ "<<<<<<< HEAD\n" \ "File one!\n" \ "!File one!\n" \ "!File one!\n" \ "!File one!\n" \ "=======\n" \ "File one\n" \ "File one\n" \ "File one\n" \ "File one\n" \ ">>>>>>> parent of 72333f4... automergeable changes\n") == 0); cl_assert(git_path_exists(TEST_REPO_PATH "/.git/MERGE_MSG")); cl_git_pass(git_futils_readbuffer(&mergemsg_buf, TEST_REPO_PATH "/.git/MERGE_MSG")); cl_assert(strcmp(mergemsg_buf.ptr, "Revert \"automergeable changes\"\n" \ "\n" \ "This reverts commit 72333f47d4e83616630ff3b0ffe4c0faebcc3c45.\n" "\n" \ "Conflicts:\n" \ "\tfile1.txt\n") == 0); git_commit_free(commit); git_commit_free(head); git_reference_free(head_ref); git_buf_free(&mergemsg_buf); git_buf_free(&conflicting_buf); }
static int winhttp_stream_connect(winhttp_stream *s) { winhttp_subtransport *t = OWNING_SUBTRANSPORT(s); git_buf buf = GIT_BUF_INIT; char *proxy_url = NULL; wchar_t ct[MAX_CONTENT_TYPE_LEN]; LPCWSTR types[] = { L"*/*", NULL }; BOOL peerdist = FALSE; int error = -1; unsigned long disable_redirects = WINHTTP_DISABLE_REDIRECTS; int default_timeout = TIMEOUT_INFINITE; int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT; /* Prepare URL */ git_buf_printf(&buf, "%s%s", t->connection_data.path, s->service_url); if (git_buf_oom(&buf)) return -1; /* Convert URL to wide characters */ if (git__utf8_to_16_alloc(&s->request_uri, git_buf_cstr(&buf)) < 0) { giterr_set(GITERR_OS, "Failed to convert string to wide form"); goto on_error; } /* Establish request */ s->request = WinHttpOpenRequest( t->connection, s->verb, s->request_uri, NULL, WINHTTP_NO_REFERER, types, t->connection_data.use_ssl ? WINHTTP_FLAG_SECURE : 0); if (!s->request) { giterr_set(GITERR_OS, "Failed to open request"); goto on_error; } if (!WinHttpSetTimeouts(s->request, default_timeout, default_connect_timeout, default_timeout, default_timeout)) { giterr_set(GITERR_OS, "Failed to set timeouts for WinHTTP"); goto on_error; } /* Set proxy if necessary */ if (git_remote__get_http_proxy(t->owner->owner, !!t->connection_data.use_ssl, &proxy_url) < 0) goto on_error; if (proxy_url) { WINHTTP_PROXY_INFO proxy_info; wchar_t *proxy_wide; /* Convert URL to wide characters */ int proxy_wide_len = git__utf8_to_16_alloc(&proxy_wide, proxy_url); if (proxy_wide_len < 0) { giterr_set(GITERR_OS, "Failed to convert string to wide form"); goto on_error; } /* Strip any trailing forward slash on the proxy URL; * WinHTTP doesn't like it if one is present */ if (proxy_wide_len > 1 && L'/' == proxy_wide[proxy_wide_len - 2]) proxy_wide[proxy_wide_len - 2] = L'\0'; proxy_info.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; proxy_info.lpszProxy = proxy_wide; proxy_info.lpszProxyBypass = NULL; if (!WinHttpSetOption(s->request, WINHTTP_OPTION_PROXY, &proxy_info, sizeof(WINHTTP_PROXY_INFO))) { giterr_set(GITERR_OS, "Failed to set proxy"); git__free(proxy_wide); goto on_error; } git__free(proxy_wide); } /* Disable WinHTTP redirects so we can handle them manually. Why, you ask? * http://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/b2ff8879-ab9f-4218-8f09-16d25dff87ae */ if (!WinHttpSetOption(s->request, WINHTTP_OPTION_DISABLE_FEATURE, &disable_redirects, sizeof(disable_redirects))) { giterr_set(GITERR_OS, "Failed to disable redirects"); goto on_error; } /* Strip unwanted headers (X-P2P-PeerDist, X-P2P-PeerDistEx) that WinHTTP * adds itself. This option may not be supported by the underlying * platform, so we do not error-check it */ WinHttpSetOption(s->request, WINHTTP_OPTION_PEERDIST_EXTENSION_STATE, &peerdist, sizeof(peerdist)); /* Send Pragma: no-cache header */ if (!WinHttpAddRequestHeaders(s->request, pragma_nocache, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD)) { giterr_set(GITERR_OS, "Failed to add a header to the request"); goto on_error; } if (post_verb == s->verb) { /* Send Content-Type and Accept headers -- only necessary on a POST */ git_buf_clear(&buf); if (git_buf_printf(&buf, "Content-Type: application/x-git-%s-request", s->service) < 0) goto on_error; if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) { giterr_set(GITERR_OS, "Failed to convert content-type to wide characters"); goto on_error; } if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) { giterr_set(GITERR_OS, "Failed to add a header to the request"); goto on_error; } git_buf_clear(&buf); if (git_buf_printf(&buf, "Accept: application/x-git-%s-result", s->service) < 0) goto on_error; if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) { giterr_set(GITERR_OS, "Failed to convert accept header to wide characters"); goto on_error; } if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) { giterr_set(GITERR_OS, "Failed to add a header to the request"); goto on_error; } } /* If requested, disable certificate validation */ if (t->connection_data.use_ssl) { int flags; if (t->owner->parent.read_flags(&t->owner->parent, &flags) < 0) goto on_error; } /* If we have a credential on the subtransport, apply it to the request */ if (t->cred && t->cred->credtype == GIT_CREDTYPE_USERPASS_PLAINTEXT && t->auth_mechanism == GIT_WINHTTP_AUTH_BASIC && apply_basic_credential(s->request, t->cred) < 0) goto on_error; else if (t->cred && t->cred->credtype == GIT_CREDTYPE_DEFAULT && t->auth_mechanism == GIT_WINHTTP_AUTH_NEGOTIATE && apply_default_credentials(s->request) < 0) goto on_error; /* If no other credentials have been applied and the URL has username and * password, use those */ if (!t->cred && t->connection_data.user && t->connection_data.pass) { if (!t->url_cred && git_cred_userpass_plaintext_new(&t->url_cred, t->connection_data.user, t->connection_data.pass) < 0) goto on_error; if (apply_basic_credential(s->request, t->url_cred) < 0) goto on_error; } /* We've done everything up to calling WinHttpSendRequest. */ error = 0; on_error: if (error < 0) winhttp_stream_close(s); git__free(proxy_url); git_buf_free(&buf); return error; }
static int filter_apply( git_filter *self, void **payload, /* may be read and/or set */ git_buf *to, const git_buf *from, const git_filter_source *src) { struct filter_filter *ffs = (struct filter_filter *)self; git_config *config; git_buf configKey = GIT_BUF_INIT; int isRequired = FALSE; int error; const char *cmd = NULL; git_buf cmdBuf = GIT_BUF_INIT; wchar_t *wide_cmd; COMMAND_HANDLE commandHandle = COMMAND_HANDLE_INIT; git_buf errBuf = GIT_BUF_INIT; DWORD exitCode; if (!*payload) return GIT_PASSTHROUGH; if (git_repository_config__weakptr(&config, git_filter_source_repo(src))) return -1; git_buf_join3(&configKey, '.', "filter", *payload, "required"); if (git_buf_oom(&configKey)) { giterr_set_oom(); return -1; } error = git_config_get_bool(&isRequired, config, configKey.ptr); git_buf_free(&configKey); if (error && error != GIT_ENOTFOUND) return -1; git_buf_join(&configKey, '.', "filter", *payload); if (git_filter_source_mode(src) == GIT_FILTER_SMUDGE) { git_buf_puts(&configKey, ".smudge"); } else { git_buf_puts(&configKey, ".clean"); } if (git_buf_oom(&configKey)) { giterr_set_oom(); return -1; } error = git_config_get_string(&cmd, config, configKey.ptr); git_buf_free(&configKey); if (error && error != GIT_ENOTFOUND) return -1; if (error == GIT_ENOTFOUND) { if (isRequired) return -1; return GIT_PASSTHROUGH; } git_buf_puts(&cmdBuf, cmd); if (git_buf_oom(&cmdBuf)) { giterr_set_oom(); return -1; } if (expandPerCentF(&cmdBuf, git_filter_source_path(src))) return -1; if (ffs->shexepath) { // build params for sh.exe git_buf shParams = GIT_BUF_INIT; git_buf_puts(&shParams, " -c \""); git_buf_text_puts_escaped(&shParams, cmdBuf.ptr, "\"\\", "\\"); git_buf_puts(&shParams, "\""); if (git_buf_oom(&shParams)) { git_buf_free(&cmdBuf); giterr_set_oom(); return -1; } git_buf_swap(&shParams, &cmdBuf); git_buf_free(&shParams); } if (git__utf8_to_16_alloc(&wide_cmd, cmdBuf.ptr) < 0) { git_buf_free(&cmdBuf); giterr_set_oom(); return -1; } git_buf_free(&cmdBuf); if (ffs->shexepath) { // build cmd, i.e. shexepath + params size_t len = wcslen(ffs->shexepath) + wcslen(wide_cmd) + 1; wchar_t *tmp = git__calloc(len, sizeof(wchar_t)); if (!tmp) { git__free(wide_cmd); giterr_set_oom(); return -1; } wcscat_s(tmp, len, ffs->shexepath); wcscat_s(tmp, len, wide_cmd); git__free(wide_cmd); wide_cmd = tmp; } commandHandle.errBuf = &errBuf; if (command_start(wide_cmd, &commandHandle, ffs->pEnv)) { git__free(wide_cmd); if (isRequired) return -1; return GIT_PASSTHROUGH; } git__free(wide_cmd); if (commmand_start_stdout_reading_thread(&commandHandle, to)) { command_close(&commandHandle); return -1; } if (command_write_gitbuf(&commandHandle, from)) { DWORD exitCode = command_close(&commandHandle); if (exitCode) setProcessError(exitCode, &errBuf); git_buf_free(&errBuf); if (isRequired) return -1; return GIT_PASSTHROUGH; } command_close_stdin(&commandHandle); if (command_wait_stdout_reading_thread(&commandHandle)) { DWORD exitCode = command_close(&commandHandle); if (exitCode) setProcessError(exitCode, &errBuf); git_buf_free(&errBuf); if (isRequired) return -1; return GIT_PASSTHROUGH; } exitCode = command_close(&commandHandle); if (exitCode) { if (isRequired) { setProcessError(exitCode, &errBuf); git_buf_free(&errBuf); return -1; } git_buf_free(&errBuf); return GIT_PASSTHROUGH; } git_buf_free(&errBuf); return 0; }
void test_repo_discover__0(void) { // test discover git_repository *repo; git_buf ceiling_dirs_buf = GIT_BUF_INIT; const char *ceiling_dirs; char repository_path[GIT_PATH_MAX]; char sub_repository_path[GIT_PATH_MAX]; char found_path[GIT_PATH_MAX]; const mode_t mode = 0777; git_futils_mkdir_r(DISCOVER_FOLDER, NULL, mode); append_ceiling_dir(&ceiling_dirs_buf, TEMP_REPO_FOLDER); ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf); cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(repository_path, sizeof(repository_path), DISCOVER_FOLDER, 0, ceiling_dirs)); cl_git_pass(git_repository_init(&repo, DISCOVER_FOLDER, 1)); cl_git_pass(git_repository_discover(repository_path, sizeof(repository_path), DISCOVER_FOLDER, 0, ceiling_dirs)); git_repository_free(repo); cl_git_pass(git_repository_init(&repo, SUB_REPOSITORY_FOLDER, 0)); cl_git_pass(git_futils_mkdir_r(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, NULL, mode)); cl_git_pass(git_repository_discover(sub_repository_path, sizeof(sub_repository_path), SUB_REPOSITORY_FOLDER, 0, ceiling_dirs)); cl_git_pass(git_futils_mkdir_r(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, NULL, mode)); ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs, sub_repository_path); ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB, ceiling_dirs, sub_repository_path); ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, ceiling_dirs, sub_repository_path); cl_git_pass(git_futils_mkdir_r(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, NULL, mode)); write_file(REPOSITORY_ALTERNATE_FOLDER "/" DOT_GIT, "gitdir: ../" SUB_REPOSITORY_FOLDER_NAME "/" DOT_GIT); write_file(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB "/" DOT_GIT, "gitdir: ../../../" SUB_REPOSITORY_FOLDER_NAME "/" DOT_GIT); write_file(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB "/" DOT_GIT, "gitdir: ../../../../"); ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs, sub_repository_path); ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB, ceiling_dirs, sub_repository_path); ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs, sub_repository_path); ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs, repository_path); cl_git_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER1, NULL, mode)); write_file(ALTERNATE_MALFORMED_FOLDER1 "/" DOT_GIT, "Anything but not gitdir:"); cl_git_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER2, NULL, mode)); write_file(ALTERNATE_MALFORMED_FOLDER2 "/" DOT_GIT, "gitdir:"); cl_git_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER3, NULL, mode)); write_file(ALTERNATE_MALFORMED_FOLDER3 "/" DOT_GIT, "gitdir: \n\n\n"); cl_git_pass(git_futils_mkdir_r(ALTERNATE_NOT_FOUND_FOLDER, NULL, mode)); write_file(ALTERNATE_NOT_FOUND_FOLDER "/" DOT_GIT, "gitdir: a_repository_that_surely_does_not_exist"); cl_git_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_MALFORMED_FOLDER1, 0, ceiling_dirs)); cl_git_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_MALFORMED_FOLDER2, 0, ceiling_dirs)); cl_git_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_MALFORMED_FOLDER3, 0, ceiling_dirs)); cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(found_path, sizeof(found_path), ALTERNATE_NOT_FOUND_FOLDER, 0, ceiling_dirs)); append_ceiling_dir(&ceiling_dirs_buf, SUB_REPOSITORY_FOLDER); ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf); //this must pass as ceiling_directories cannot predent the current //working directory to be checked cl_git_pass(git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER, 0, ceiling_dirs)); cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER_SUB, 0, ceiling_dirs)); cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs)); cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs)); //.gitfile redirection should not be affected by ceiling directories ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER, ceiling_dirs, sub_repository_path); ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB, ceiling_dirs, sub_repository_path); ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs, sub_repository_path); ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs, repository_path); cl_git_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, NULL, GIT_RMDIR_REMOVE_FILES)); git_repository_free(repo); git_buf_free(&ceiling_dirs_buf); }
int git_branch_remote_name(git_buf *buf, git_repository *repo, const char *refname) { git_strarray remote_list = {0}; size_t i; git_remote *remote; const git_refspec *fetchspec; int error = 0; char *remote_name = NULL; assert(buf && repo && refname); git_buf_sanitize(buf); /* Verify that this is a remote branch */ if (!git_reference__is_remote(refname)) { giterr_set(GITERR_INVALID, "Reference '%s' is not a remote branch.", refname); error = GIT_ERROR; goto cleanup; } /* Get the remotes */ if ((error = git_remote_list(&remote_list, repo)) < 0) goto cleanup; /* Find matching remotes */ for (i = 0; i < remote_list.count; i++) { if ((error = git_remote_lookup(&remote, repo, remote_list.strings[i])) < 0) continue; fetchspec = git_remote__matching_dst_refspec(remote, refname); if (fetchspec) { /* If we have not already set out yet, then set * it to the matching remote name. Otherwise * multiple remotes match this reference, and it * is ambiguous. */ if (!remote_name) { remote_name = remote_list.strings[i]; } else { git_remote_free(remote); giterr_set(GITERR_REFERENCE, "Reference '%s' is ambiguous", refname); error = GIT_EAMBIGUOUS; goto cleanup; } } git_remote_free(remote); } if (remote_name) { git_buf_clear(buf); error = git_buf_puts(buf, remote_name); } else { giterr_set(GITERR_REFERENCE, "Could not determine remote for '%s'", refname); error = GIT_ENOTFOUND; } cleanup: if (error < 0) git_buf_free(buf); git_strarray_free(&remote_list); return error; }
void test_submodule_nosubs__add_and_delete(void) { git_repository *repo = cl_git_sandbox_init("status"); git_submodule *sm; git_buf buf = GIT_BUF_INIT; /* note lack of calls to git_submodule_reload_all - this *should* work */ cl_git_fail(git_submodule_lookup(NULL, repo, "libgit2")); cl_git_fail(git_submodule_lookup(NULL, repo, "submodules/libgit2")); /* create */ cl_git_pass(git_submodule_add_setup( &sm, repo, "https://github.com/libgit2/libgit2.git", "submodules/libgit2", 1)); cl_assert_equal_s("submodules/libgit2", git_submodule_name(sm)); cl_assert_equal_s("submodules/libgit2", git_submodule_path(sm)); git_submodule_free(sm); cl_git_pass(git_futils_readbuffer(&buf, "status/.gitmodules")); cl_assert(strstr(buf.ptr, "[submodule \"submodules/libgit2\"]") != NULL); cl_assert(strstr(buf.ptr, "path = submodules/libgit2") != NULL); git_buf_free(&buf); /* lookup */ cl_git_fail(git_submodule_lookup(&sm, repo, "libgit2")); cl_git_pass(git_submodule_lookup(&sm, repo, "submodules/libgit2")); cl_assert_equal_s("submodules/libgit2", git_submodule_name(sm)); cl_assert_equal_s("submodules/libgit2", git_submodule_path(sm)); git_submodule_free(sm); /* update name */ cl_git_rewritefile( "status/.gitmodules", "[submodule \"libgit2\"]\n" " path = submodules/libgit2\n" " url = https://github.com/libgit2/libgit2.git\n"); cl_git_pass(git_submodule_lookup(&sm, repo, "libgit2")); cl_assert_equal_s("libgit2", git_submodule_name(sm)); cl_assert_equal_s("submodules/libgit2", git_submodule_path(sm)); git_submodule_free(sm); cl_git_pass(git_submodule_lookup(&sm, repo, "submodules/libgit2")); git_submodule_free(sm); /* revert name update */ cl_git_rewritefile( "status/.gitmodules", "[submodule \"submodules/libgit2\"]\n" " path = submodules/libgit2\n" " url = https://github.com/libgit2/libgit2.git\n"); cl_git_fail(git_submodule_lookup(&sm, repo, "libgit2")); cl_git_pass(git_submodule_lookup(&sm, repo, "submodules/libgit2")); git_submodule_free(sm); /* remove completely */ cl_must_pass(p_unlink("status/.gitmodules")); cl_git_fail(git_submodule_lookup(&sm, repo, "libgit2")); cl_git_fail(git_submodule_lookup(&sm, repo, "submodules/libgit2")); }
/** * Merge branch into HEAD * * @param branch S4 class git_branch to merge into HEAD. * @param merger Who is performing the merge * @param commit_on_success Commit merge commit, if one was created * during a normal merge * @return S4 class git_merge_result */ SEXP git2r_merge_branch(SEXP branch, SEXP merger, SEXP commit_on_success) { int err; SEXP result = R_NilValue; const char *name; git_buf buf = GIT_BUF_INIT; git_branch_t type; git_annotated_commit **merge_heads = NULL; git_reference *reference = NULL; git_repository *repository = NULL; git_signature *who = NULL; if (git2r_arg_check_branch(branch)) git2r_error(__func__, NULL, "'branch'", git2r_err_branch_arg); if (git2r_arg_check_logical(commit_on_success)) git2r_error(__func__, NULL, "'commit_on_success'", git2r_err_logical_arg); if (git2r_arg_check_signature(merger)) git2r_error(__func__, NULL, "'merger'", git2r_err_signature_arg); err = git2r_signature_from_arg(&who, merger); if (err) goto cleanup; repository = git2r_repository_open(GET_SLOT(branch, Rf_install("repo"))); if (!repository) git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL); name = CHAR(STRING_ELT(GET_SLOT(branch, Rf_install("name")), 0)); type = INTEGER(GET_SLOT(branch, Rf_install("type")))[0]; err = git_branch_lookup(&reference, repository, name, type); if (err) goto cleanup; merge_heads = calloc(1, sizeof(git_annotated_commit*)); if (NULL == merge_heads) { giterr_set_str(GITERR_NONE, git2r_err_alloc_memory_buffer); goto cleanup; } err = git_annotated_commit_from_ref( &(merge_heads[0]), repository, reference); if (err) goto cleanup; err = git_buf_printf(&buf, "merge %s", name); if (err) goto cleanup; PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_merge_result"))); err = git2r_merge( result, repository, (const git_annotated_commit **)merge_heads, 1, GIT_MERGE_PREFERENCE_NONE, buf.ptr, who, LOGICAL(commit_on_success)[0]); cleanup: git_buf_free(&buf); if (who) git_signature_free(who); if (merge_heads) git2r_merge_heads_free(merge_heads, 1); if (reference) git_reference_free(reference); if (repository) git_repository_free(repository); if (R_NilValue != result) UNPROTECT(1); if (err) git2r_error(__func__, giterr_last(), NULL, NULL); return result; }
static int update_head_to_remote( git_repository *repo, git_remote *remote, const git_signature *signature, const char *reflog_message) { int error = 0, found_branch = 0; size_t refs_len; git_refspec dummy_spec, *refspec; const git_remote_head *remote_head, **refs; const git_oid *remote_head_id; git_buf remote_master_name = GIT_BUF_INIT; git_buf branch = GIT_BUF_INIT; if ((error = git_remote_ls(&refs, &refs_len, remote)) < 0) return error; /* Did we just clone an empty repository? */ if (refs_len == 0) return setup_tracking_config( repo, "master", GIT_REMOTE_ORIGIN, GIT_REFS_HEADS_MASTER_FILE); error = git_remote_default_branch(&branch, remote); if (error == GIT_ENOTFOUND) { git_buf_puts(&branch, GIT_REFS_HEADS_MASTER_FILE); } else { found_branch = 1; } /* Get the remote's HEAD. This is always the first ref in the list. */ remote_head = refs[0]; assert(remote_head); remote_head_id = &remote_head->oid; refspec = git_remote__matching_refspec(remote, git_buf_cstr(&branch)); if (refspec == NULL) { memset(&dummy_spec, 0, sizeof(git_refspec)); refspec = &dummy_spec; } /* Determine the remote tracking reference name from the local master */ if ((error = git_refspec_transform( &remote_master_name, refspec, git_buf_cstr(&branch))) < 0) return error; if (found_branch) { error = update_head_to_new_branch( repo, remote_head_id, git_buf_cstr(&branch), signature, reflog_message); } else { error = git_repository_set_head_detached( repo, remote_head_id, signature, reflog_message); } git_buf_free(&remote_master_name); git_buf_free(&branch); return error; }
/** * Perform a fast-forward merge * * @param merge_result S4 class git_merge_result * @param merge_head The merge head to fast-forward merge * @param repository The repository * @param log_message First part of the one line long message in the reflog * @return 0 on success, or error code */ static int git2r_fast_forward_merge( SEXP merge_result, const git_annotated_commit *merge_head, git_repository *repository, const char *log_message) { int err; const git_oid *oid; git_buf buf = GIT_BUF_INIT; git_commit *commit = NULL; git_tree *tree = NULL; git_reference *reference = NULL; git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; oid = git_annotated_commit_id(merge_head); err = git_commit_lookup(&commit, repository, oid); if (err) goto cleanup; err = git_commit_tree(&tree, commit); if (err) goto cleanup; opts.checkout_strategy = GIT_CHECKOUT_SAFE; err = git_checkout_tree(repository, (git_object*)tree, &opts); if (err) goto cleanup; err = git_repository_head(&reference, repository); if (err) { if (GIT_ENOTFOUND != err) goto cleanup; } err = git_buf_printf(&buf, "%s: Fast-forward", log_message); if (err) goto cleanup; if (GIT_ENOTFOUND == err) { err = git_reference_create( &reference, repository, "HEAD", git_commit_id(commit), 0, /* force */ buf.ptr); } else { git_reference *target_ref = NULL; err = git_reference_set_target( &target_ref, reference, git_commit_id(commit), buf.ptr); if (target_ref) git_reference_free(target_ref); } SET_SLOT( merge_result, Rf_install("fast_forward"), ScalarLogical(1)); SET_SLOT( merge_result, Rf_install("conflicts"), ScalarLogical(0)); cleanup: git_buf_free(&buf); if (commit) git_commit_free(commit); if (reference) git_reference_free(reference); if (tree) git_tree_free(tree); return err; }
static int update_head_to_remote(git_repository *repo, git_remote *remote) { int retcode = -1; git_refspec dummy_spec; git_remote_head *remote_head; struct head_info head_info; git_buf remote_master_name = GIT_BUF_INIT; /* Did we just clone an empty repository? */ if (remote->refs.length == 0) { return setup_tracking_config( repo, "master", GIT_REMOTE_ORIGIN, GIT_REFS_HEADS_MASTER_FILE); } /* Get the remote's HEAD. This is always the first ref in remote->refs. */ remote_head = NULL; if (!remote->transport->ls(remote->transport, get_head_callback, &remote_head)) return -1; assert(remote_head); git_oid_cpy(&head_info.remote_head_oid, &remote_head->oid); git_buf_init(&head_info.branchname, 16); head_info.repo = repo; head_info.refspec = git_remote__matching_refspec(remote, GIT_REFS_HEADS_MASTER_FILE); head_info.found = 0; if (head_info.refspec == NULL) { memset(&dummy_spec, 0, sizeof(git_refspec)); head_info.refspec = &dummy_spec; } /* Determine the remote tracking reference name from the local master */ if (git_refspec_transform_r( &remote_master_name, head_info.refspec, GIT_REFS_HEADS_MASTER_FILE) < 0) return -1; /* Check to see if the remote HEAD points to the remote master */ if (reference_matches_remote_head(git_buf_cstr(&remote_master_name), &head_info) < 0) goto cleanup; if (head_info.found) { retcode = update_head_to_new_branch( repo, &head_info.remote_head_oid, git_buf_cstr(&head_info.branchname)); goto cleanup; } /* Not master. Check all the other refs. */ if (git_reference_foreach_name( repo, reference_matches_remote_head, &head_info) < 0) goto cleanup; if (head_info.found) { retcode = update_head_to_new_branch( repo, &head_info.remote_head_oid, git_buf_cstr(&head_info.branchname)); goto cleanup; } else { retcode = git_repository_set_head_detached( repo, &head_info.remote_head_oid); goto cleanup; } cleanup: git_buf_free(&remote_master_name); git_buf_free(&head_info.branchname); return retcode; }
int git_futils_mkdir( const char *path, const char *base, mode_t mode, uint32_t flags) { int error = -1; git_buf make_path = GIT_BUF_INIT; ssize_t root = 0, min_root_len; char lastch = '/', *tail; struct stat st; /* build path and find "root" where we should start calling mkdir */ if (git_path_join_unrooted(&make_path, path, base, &root) < 0) return -1; if (make_path.size == 0) { giterr_set(GITERR_OS, "Attempt to create empty path"); goto done; } /* remove trailing slashes on path */ while (make_path.ptr[make_path.size - 1] == '/') { make_path.size--; make_path.ptr[make_path.size] = '\0'; } /* if we are not supposed to made the last element, truncate it */ if ((flags & GIT_MKDIR_SKIP_LAST2) != 0) { git_buf_rtruncate_at_char(&make_path, '/'); flags |= GIT_MKDIR_SKIP_LAST; } if ((flags & GIT_MKDIR_SKIP_LAST) != 0) git_buf_rtruncate_at_char(&make_path, '/'); /* if nothing left after truncation, then we're done! */ if (!make_path.size) { error = 0; goto done; } /* if we are not supposed to make the whole path, reset root */ if ((flags & GIT_MKDIR_PATH) == 0) root = git_buf_rfind(&make_path, '/'); /* advance root past drive name or network mount prefix */ min_root_len = git_path_root(make_path.ptr); if (root < min_root_len) root = min_root_len; while (root >= 0 && make_path.ptr[root] == '/') ++root; /* clip root to make_path length */ if (root > (ssize_t)make_path.size) root = (ssize_t)make_path.size; /* i.e. NUL byte of string */ if (root < 0) root = 0; /* walk down tail of path making each directory */ for (tail = &make_path.ptr[root]; *tail; *tail = lastch) { /* advance tail to include next path component */ while (*tail == '/') tail++; while (*tail && *tail != '/') tail++; /* truncate path at next component */ lastch = *tail; *tail = '\0'; st.st_mode = 0; /* make directory */ if (p_mkdir(make_path.ptr, mode) < 0) { int tmp_errno = giterr_system_last(); /* ignore error if not at end or if directory already exists */ if (lastch == '\0' && (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode))) { giterr_system_set(tmp_errno); giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr); goto done; } /* with exclusive create, existing dir is an error */ if ((flags & GIT_MKDIR_EXCL) != 0) { giterr_set(GITERR_OS, "Directory already exists '%s'", make_path.ptr); error = GIT_EEXISTS; goto done; } } /* chmod if requested and necessary */ if (((flags & GIT_MKDIR_CHMOD_PATH) != 0 || (lastch == '\0' && (flags & GIT_MKDIR_CHMOD) != 0)) && st.st_mode != mode && (error = p_chmod(make_path.ptr, mode)) < 0 && lastch == '\0') { giterr_set(GITERR_OS, "Failed to set permissions on '%s'", make_path.ptr); goto done; } } error = 0; /* check that full path really is a directory if requested & needed */ if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 && lastch != '\0' && (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode))) { giterr_set(GITERR_OS, "Path is not a directory '%s'", make_path.ptr); error = GIT_ENOTFOUND; } done: git_buf_free(&make_path); return error; }
/* Inspired from https://github.com/git/git/blob/f06d47e7e0d9db709ee204ed13a8a7486149f494/refs.c#L36-100 */ int git_reference__normalize_name( git_buf *buf, const char *name, unsigned int flags) { const char *current; int segment_len, segments_count = 0, error = GIT_EINVALIDSPEC; unsigned int process_flags; bool normalize = (buf != NULL); #ifdef GIT_USE_ICONV git_path_iconv_t ic = GIT_PATH_ICONV_INIT; #endif assert(name); process_flags = flags; current = (char *)name; if (*current == '/') goto cleanup; if (normalize) git_buf_clear(buf); #ifdef GIT_USE_ICONV if ((flags & GIT_REF_FORMAT__PRECOMPOSE_UNICODE) != 0) { size_t namelen = strlen(current); if ((error = git_path_iconv_init_precompose(&ic)) < 0 || (error = git_path_iconv(&ic, ¤t, &namelen)) < 0) goto cleanup; error = GIT_EINVALIDSPEC; } #endif while (true) { segment_len = ensure_segment_validity(current); if (segment_len < 0) { if ((process_flags & GIT_REF_FORMAT_REFSPEC_PATTERN) && current[0] == '*' && (current[1] == '\0' || current[1] == '/')) { /* Accept one wildcard as a full refname component. */ process_flags &= ~GIT_REF_FORMAT_REFSPEC_PATTERN; segment_len = 1; } else goto cleanup; } if (segment_len > 0) { if (normalize) { size_t cur_len = git_buf_len(buf); git_buf_joinpath(buf, git_buf_cstr(buf), current); git_buf_truncate(buf, cur_len + segment_len + (segments_count ? 1 : 0)); if (git_buf_oom(buf)) { error = -1; goto cleanup; } } segments_count++; } /* No empty segment is allowed when not normalizing */ if (segment_len == 0 && !normalize) goto cleanup; if (current[segment_len] == '\0') break; current += segment_len + 1; } /* A refname can not be empty */ if (segment_len == 0 && segments_count == 0) goto cleanup; /* A refname can not end with "." */ if (current[segment_len - 1] == '.') goto cleanup; /* A refname can not end with "/" */ if (current[segment_len - 1] == '/') goto cleanup; if ((segments_count == 1 ) && !(flags & GIT_REF_FORMAT_ALLOW_ONELEVEL)) goto cleanup; if ((segments_count == 1 ) && !(flags & GIT_REF_FORMAT_REFSPEC_SHORTHAND) && !(is_all_caps_and_underscore(name, (size_t)segment_len) || ((flags & GIT_REF_FORMAT_REFSPEC_PATTERN) && !strcmp("*", name)))) goto cleanup; if ((segments_count > 1) && (is_all_caps_and_underscore(name, strchr(name, '/') - name))) goto cleanup; error = 0; cleanup: if (error == GIT_EINVALIDSPEC) giterr_set( GITERR_REFERENCE, "The given reference name '%s' is not valid", name); if (error && normalize) git_buf_free(buf); #ifdef GIT_USE_ICONV git_path_iconv_clear(&ic); #endif return error; }
/* rewrite gitmodules -> .gitmodules * rewrite the empty or relative urls inside each module * rename the .gitted directory inside any submodule to .git */ void rewrite_gitmodules(const char *workdir) { git_buf in_f = GIT_BUF_INIT, out_f = GIT_BUF_INIT, path = GIT_BUF_INIT; FILE *in, *out; char line[256]; cl_git_pass(git_buf_joinpath(&in_f, workdir, "gitmodules")); cl_git_pass(git_buf_joinpath(&out_f, workdir, ".gitmodules")); cl_assert((in = fopen(in_f.ptr, "rb")) != NULL); cl_assert((out = fopen(out_f.ptr, "wb")) != NULL); while (fgets(line, sizeof(line), in) != NULL) { char *scan = line; while (*scan == ' ' || *scan == '\t') scan++; /* rename .gitted -> .git in submodule directories */ if (git__prefixcmp(scan, "path =") == 0) { scan += strlen("path ="); while (*scan == ' ') scan++; git_buf_joinpath(&path, workdir, scan); git_buf_rtrim(&path); git_buf_joinpath(&path, path.ptr, ".gitted"); if (!git_buf_oom(&path) && p_access(path.ptr, F_OK) == 0) { git_buf_joinpath(&out_f, workdir, scan); git_buf_rtrim(&out_f); git_buf_joinpath(&out_f, out_f.ptr, ".git"); if (!git_buf_oom(&out_f)) p_rename(path.ptr, out_f.ptr); } } /* copy non-"url =" lines verbatim */ if (git__prefixcmp(scan, "url =") != 0) { fputs(line, out); continue; } /* convert relative URLs in "url =" lines */ scan += strlen("url ="); while (*scan == ' ') scan++; if (*scan == '.') { git_buf_joinpath(&path, workdir, scan); git_buf_rtrim(&path); } else if (!*scan || *scan == '\n') { git_buf_joinpath(&path, workdir, "../testrepo.git"); } else { fputs(line, out); continue; } git_path_prettify(&path, path.ptr, NULL); git_buf_putc(&path, '\n'); cl_assert(!git_buf_oom(&path)); fwrite(line, scan - line, sizeof(char), out); fputs(path.ptr, out); } fclose(in); fclose(out); cl_must_pass(p_unlink(in_f.ptr)); git_buf_free(&in_f); git_buf_free(&out_f); git_buf_free(&path); }
int git_reset( git_repository *repo, git_object *target, git_reset_t reset_type, git_checkout_options *checkout_opts, git_signature *signature, const char *log_message) { git_object *commit = NULL; git_index *index = NULL; git_tree *tree = NULL; int error = 0; git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; git_buf log_message_buf = GIT_BUF_INIT; assert(repo && target); if (checkout_opts) opts = *checkout_opts; if (git_object_owner(target) != repo) { giterr_set(GITERR_OBJECT, "%s - The given target does not belong to this repository.", ERROR_MSG); return -1; } if (reset_type != GIT_RESET_SOFT && (error = git_repository__ensure_not_bare(repo, reset_type == GIT_RESET_MIXED ? "reset mixed" : "reset hard")) < 0) return error; if ((error = git_object_peel(&commit, target, GIT_OBJ_COMMIT)) < 0 || (error = git_repository_index(&index, repo)) < 0 || (error = git_commit_tree(&tree, (git_commit *)commit)) < 0) goto cleanup; if (reset_type == GIT_RESET_SOFT && (git_repository_state(repo) == GIT_REPOSITORY_STATE_MERGE || git_index_has_conflicts(index))) { giterr_set(GITERR_OBJECT, "%s (soft) in the middle of a merge.", ERROR_MSG); error = GIT_EUNMERGED; goto cleanup; } if (log_message) git_buf_sets(&log_message_buf, log_message); else git_buf_sets(&log_message_buf, "reset: moving"); /* move HEAD to the new target */ if ((error = git_reference__update_terminal(repo, GIT_HEAD_FILE, git_object_id(commit), signature, git_buf_cstr(&log_message_buf))) < 0) goto cleanup; if (reset_type == GIT_RESET_HARD) { /* overwrite working directory with HEAD */ opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_SKIP_UNMERGED; if ((error = git_checkout_tree(repo, (git_object *)tree, &opts)) < 0) goto cleanup; } if (reset_type > GIT_RESET_SOFT) { /* reset index to the target content */ if ((error = git_index_read_tree(index, tree)) < 0 || (error = git_index_write(index)) < 0) goto cleanup; if ((error = git_repository_state_cleanup(repo)) < 0) { giterr_set(GITERR_INDEX, "%s - failed to clean up merge data", ERROR_MSG); goto cleanup; } } cleanup: git_object_free(commit); git_index_free(index); git_tree_free(tree); git_buf_free(&log_message_buf); return error; }
int git_branch_upstream_name( git_buf *out, git_repository *repo, const char *refname) { git_buf remote_name = GIT_BUF_INIT; git_buf merge_name = GIT_BUF_INIT; git_buf buf = GIT_BUF_INIT; int error = -1; git_remote *remote = NULL; const git_refspec *refspec; git_config *config; assert(out && refname); git_buf_sanitize(out); if (!git_reference__is_branch(refname)) return not_a_local_branch(refname); if ((error = git_repository_config_snapshot(&config, repo)) < 0) return error; if ((error = retrieve_upstream_configuration( &remote_name, config, refname, "branch.%s.remote")) < 0) goto cleanup; if ((error = retrieve_upstream_configuration( &merge_name, config, refname, "branch.%s.merge")) < 0) goto cleanup; if (git_buf_len(&remote_name) == 0 || git_buf_len(&merge_name) == 0) { giterr_set(GITERR_REFERENCE, "branch '%s' does not have an upstream", refname); error = GIT_ENOTFOUND; goto cleanup; } if (strcmp(".", git_buf_cstr(&remote_name)) != 0) { if ((error = git_remote_lookup(&remote, repo, git_buf_cstr(&remote_name))) < 0) goto cleanup; refspec = git_remote__matching_refspec(remote, git_buf_cstr(&merge_name)); if (!refspec) { error = GIT_ENOTFOUND; goto cleanup; } if (git_refspec_transform(&buf, refspec, git_buf_cstr(&merge_name)) < 0) goto cleanup; } else if (git_buf_set(&buf, git_buf_cstr(&merge_name), git_buf_len(&merge_name)) < 0) goto cleanup; error = git_buf_set(out, git_buf_cstr(&buf), git_buf_len(&buf)); cleanup: git_config_free(config); git_remote_free(remote); git_buf_free(&remote_name); git_buf_free(&merge_name); git_buf_free(&buf); return error; }
static int git_commit__create_internal( git_oid *id, git_repository *repo, const char *update_ref, const git_signature *author, const git_signature *committer, const char *message_encoding, const char *message, const git_oid *tree, git_commit_parent_callback parent_cb, void *parent_payload, bool validate) { git_reference *ref = NULL; int error = 0, matched_parent = 0; const git_oid *current_id = NULL; git_buf commit = GIT_BUF_INIT; size_t i = 0; git_odb *odb; const git_oid *parent; assert(id && repo && tree && parent_cb); if (validate && !git_object__is_valid(repo, tree, GIT_OBJ_TREE)) return -1; if (update_ref) { error = git_reference_lookup_resolved(&ref, repo, update_ref, 10); if (error < 0 && error != GIT_ENOTFOUND) return error; } giterr_clear(); if (ref) current_id = git_reference_target(ref); git_oid__writebuf(&commit, "tree ", tree); while ((parent = parent_cb(i, parent_payload)) != NULL) { if (validate && !git_object__is_valid(repo, parent, GIT_OBJ_COMMIT)) { error = -1; goto on_error; } git_oid__writebuf(&commit, "parent ", parent); if (i == 0 && current_id && git_oid_equal(current_id, parent)) matched_parent = 1; i++; } if (ref && !matched_parent) { git_reference_free(ref); git_buf_free(&commit); giterr_set(GITERR_OBJECT, "failed to create commit: current tip is not the first parent"); return GIT_EMODIFIED; } git_signature__writebuf(&commit, "author ", author); git_signature__writebuf(&commit, "committer ", committer); if (message_encoding != NULL) git_buf_printf(&commit, "encoding %s\n", message_encoding); git_buf_putc(&commit, '\n'); if (git_buf_puts(&commit, message) < 0) goto on_error; if (git_repository_odb__weakptr(&odb, repo) < 0) goto on_error; if (git_odb_write(id, odb, commit.ptr, commit.size, GIT_OBJ_COMMIT) < 0) goto on_error; git_buf_free(&commit); if (update_ref != NULL) { error = git_reference__update_for_commit( repo, ref, update_ref, id, "commit"); git_reference_free(ref); return error; } return 0; on_error: git_buf_free(&commit); return -1; }
int git_branch_set_upstream(git_reference *branch, const char *upstream_name) { git_buf key = GIT_BUF_INIT, value = GIT_BUF_INIT; git_reference *upstream; git_repository *repo; git_remote *remote = NULL; git_config *config; const char *name, *shortname; int local, error; const git_refspec *fetchspec; name = git_reference_name(branch); if (!git_reference__is_branch(name)) return not_a_local_branch(name); if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0) return -1; shortname = name + strlen(GIT_REFS_HEADS_DIR); if (upstream_name == NULL) return unset_upstream(config, shortname); repo = git_reference_owner(branch); /* First we need to figure out whether it's a branch or remote-tracking */ if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_LOCAL) == 0) local = 1; else if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_REMOTE) == 0) local = 0; else { giterr_set(GITERR_REFERENCE, "Cannot set upstream for branch '%s'", shortname); return GIT_ENOTFOUND; } /* * If it's local, the remote is "." and the branch name is * simply the refname. Otherwise we need to figure out what * the remote-tracking branch's name on the remote is and use * that. */ if (local) error = git_buf_puts(&value, "."); else error = git_branch_remote_name(&value, repo, git_reference_name(upstream)); if (error < 0) goto on_error; if (git_buf_printf(&key, "branch.%s.remote", shortname) < 0) goto on_error; if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0) goto on_error; if (local) { git_buf_clear(&value); if (git_buf_puts(&value, git_reference_name(upstream)) < 0) goto on_error; } else { /* Get the remoe-tracking branch's refname in its repo */ if (git_remote_lookup(&remote, repo, git_buf_cstr(&value)) < 0) goto on_error; fetchspec = git_remote__matching_dst_refspec(remote, git_reference_name(upstream)); git_buf_clear(&value); if (!fetchspec || git_refspec_rtransform(&value, fetchspec, git_reference_name(upstream)) < 0) goto on_error; git_remote_free(remote); remote = NULL; } git_buf_clear(&key); if (git_buf_printf(&key, "branch.%s.merge", shortname) < 0) goto on_error; if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0) goto on_error; git_reference_free(upstream); git_buf_free(&key); git_buf_free(&value); return 0; on_error: git_reference_free(upstream); git_buf_free(&key); git_buf_free(&value); git_remote_free(remote); return -1; }
int git_refspec__dwim_one(git_vector *out, git_refspec *spec, git_vector *refs) { git_buf buf = GIT_BUF_INIT; size_t j, pos; git_remote_head key; const char* formatters[] = { GIT_REFS_DIR "%s", GIT_REFS_TAGS_DIR "%s", GIT_REFS_HEADS_DIR "%s", NULL }; git_refspec *cur = git__calloc(1, sizeof(git_refspec)); GITERR_CHECK_ALLOC(cur); cur->force = spec->force; cur->push = spec->push; cur->pattern = spec->pattern; cur->matching = spec->matching; cur->string = git__strdup(spec->string); /* shorthand on the lhs */ if (git__prefixcmp(spec->src, GIT_REFS_DIR)) { for (j = 0; formatters[j]; j++) { git_buf_clear(&buf); if (git_buf_printf(&buf, formatters[j], spec->src) < 0) return -1; key.name = (char *) git_buf_cstr(&buf); if (!git_vector_search(&pos, refs, &key)) { /* we found something to match the shorthand, set src to that */ cur->src = git_buf_detach(&buf); } } } /* No shorthands found, copy over the name */ if (cur->src == NULL && spec->src != NULL) { cur->src = git__strdup(spec->src); GITERR_CHECK_ALLOC(cur->src); } if (spec->dst && git__prefixcmp(spec->dst, GIT_REFS_DIR)) { /* if it starts with "remotes" then we just prepend "refs/" */ if (!git__prefixcmp(spec->dst, "remotes/")) { git_buf_puts(&buf, GIT_REFS_DIR); } else { git_buf_puts(&buf, GIT_REFS_HEADS_DIR); } if (git_buf_puts(&buf, spec->dst) < 0) return -1; cur->dst = git_buf_detach(&buf); } git_buf_free(&buf); if (cur->dst == NULL && spec->dst != NULL) { cur->dst = git__strdup(spec->dst); GITERR_CHECK_ALLOC(cur->dst); } return git_vector_insert(out, cur); }