/** * Each time a reference is updated locally, this function will be * called with information about it. * * Based on the libgit2 network/fetch.c example. * * @param refname The name of the remote * @param a The previous position of branch * @param b The new position of branch * @param payload Callback data. * @return 0 */ static int git2r_update_tips_cb( const char *refname, const git_oid *a, const git_oid *b, void *payload) { git2r_transfer_data *cb_data = (git2r_transfer_data*)payload; if (cb_data->verbose) { char b_str[GIT_OID_HEXSZ + 1]; git_oid_fmt(b_str, b); b_str[GIT_OID_HEXSZ] = '\0'; if (git_oid_iszero(a)) { Rprintf("[new] %.20s %s\n", b_str, refname); } else { char a_str[GIT_OID_HEXSZ + 1]; git_oid_fmt(a_str, a); a_str[GIT_OID_HEXSZ] = '\0'; Rprintf("[updated] %.10s..%.10s %s\n", a_str, b_str, refname); } } return 0; }
static int update_tips_cb(const char *refname, const git_oid *src, const git_oid *dest, void *data) { struct rugged_remote_cb_payload *payload = data; VALUE args = rb_ary_new2(4); if (NIL_P(payload->update_tips)) return 0; rb_ary_push(args, payload->update_tips); rb_ary_push(args, rb_str_new_utf8(refname)); rb_ary_push(args, git_oid_iszero(src) ? Qnil : rugged_create_oid(src)); rb_ary_push(args, git_oid_iszero(dest) ? Qnil : rugged_create_oid(dest)); rb_protect(rugged__block_yield_splat, args, &payload->exception); return payload->exception ? GIT_ERROR : GIT_OK; }
const git_oid *git_reference_target_peel(const git_reference *ref) { assert(ref); if (ref->type != GIT_REF_OID || git_oid_iszero(&ref->peel)) return NULL; return &ref->peel; }
static VALUE rugged_rhead_new(const git_remote_head *head) { VALUE rb_head = rb_hash_new(); rb_hash_aset(rb_head, CSTR2SYM("local?"), head->local ? Qtrue : Qfalse); rb_hash_aset(rb_head, CSTR2SYM("oid"), rugged_create_oid(&head->oid)); rb_hash_aset(rb_head, CSTR2SYM("loid"), git_oid_iszero(&head->loid) ? Qnil : rugged_create_oid(&head->loid)); rb_hash_aset(rb_head, CSTR2SYM("name"), rb_str_new_utf8(head->name)); return rb_head; }
void test_diff_blob__can_compare_identical_blobs_with_patch(void) { git_patch *p; const git_diff_delta *delta; cl_git_pass(git_patch_from_blobs(&p, d, NULL, d, NULL, &opts)); cl_assert(p != NULL); delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_UNMODIFIED, delta->status); cl_assert_equal_sz(delta->old_file.size, git_blob_rawsize(d)); cl_assert_equal_oid(git_blob_id(d), &delta->old_file.id); cl_assert_equal_sz(delta->new_file.size, git_blob_rawsize(d)); cl_assert_equal_oid(git_blob_id(d), &delta->new_file.id); cl_assert_equal_i(0, (int)git_patch_num_hunks(p)); git_patch_free(p); cl_git_pass(git_patch_from_blobs(&p, NULL, NULL, NULL, NULL, &opts)); cl_assert(p != NULL); delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_UNMODIFIED, delta->status); cl_assert_equal_sz(0, delta->old_file.size); cl_assert(git_oid_iszero(&delta->old_file.id)); cl_assert_equal_sz(0, delta->new_file.size); cl_assert(git_oid_iszero(&delta->new_file.id)); cl_assert_equal_i(0, (int)git_patch_num_hunks(p)); git_patch_free(p); cl_git_pass(git_patch_from_blobs(&p, alien, NULL, alien, NULL, &opts)); cl_assert(p != NULL); cl_assert_equal_i(GIT_DELTA_UNMODIFIED, git_patch_get_delta(p)->status); cl_assert_equal_i(0, (int)git_patch_num_hunks(p)); git_patch_free(p); }
int RemoteProgressCommand::RemoteUpdatetipsCallback(const char* refname, const git_oid* oldOid, const git_oid* newOid, void* data) { auto ptr = (CGitProgressList::Payload*)data; bool nonff = false; if (!git_oid_iszero(oldOid) && !git_oid_iszero(newOid)) { git_oid baseOid = { 0 }; if (!git_merge_base(&baseOid, ptr->repo, newOid, oldOid)) if (!git_oid_equal(oldOid, &baseOid)) nonff = true; } CString change; if (!git_oid_iszero(oldOid) && !git_oid_iszero(newOid)) { if (git_oid_equal(oldOid, newOid)) { change.LoadString(IDS_SAME); } else { size_t ahead = 0, behind = 0; if (!git_graph_ahead_behind(&ahead, &behind, ptr->repo, newOid, oldOid)) { if (ahead > 0 && behind == 0) { change.Format(IDS_FORWARDN, ahead); } else if (ahead == 0 && behind > 0) { change.Format(IDS_REWINDN, behind); } else { git_commit* oldCommit, * newCommit; git_time_t oldTime = 0, newTime = 0; if (!git_commit_lookup(&oldCommit, ptr->repo, oldOid)) oldTime = git_commit_committer(oldCommit)->when.time; if (!git_commit_lookup(&newCommit, ptr->repo, newOid)) newTime = git_commit_committer(newCommit)->when.time; if (oldTime < newTime) change.LoadString(IDS_SUBMODULEDIFF_NEWERTIME); else if (oldTime > newTime) change.LoadString(IDS_SUBMODULEDIFF_OLDERTIME); else change.LoadString(IDS_SUBMODULEDIFF_SAMETIME); } } } } else if (!git_oid_iszero(oldOid)) change.LoadString(IDS_DELETED); else if (!git_oid_iszero(newOid)) change.LoadString(IDS_NEW); ptr->list->AddNotify(new RefUpdateNotificationData(refname, oldOid, newOid, change)); return 0; }
static int diff_file_content_load_blob(git_diff_file_content *fc) { int error = 0; git_odb_object *odb_obj = NULL; if (git_oid_iszero(&fc->file->oid)) return 0; if (fc->file->mode == GIT_FILEMODE_COMMIT) return diff_file_content_commit_to_str(fc, false); /* if we don't know size, try to peek at object header first */ if (!fc->file->size) { git_odb *odb; size_t len; git_otype type; if (!(error = git_repository_odb__weakptr(&odb, fc->repo))) { error = git_odb__read_header_or_object( &odb_obj, &len, &type, odb, &fc->file->oid); git_odb_free(odb); } if (error) return error; fc->file->size = len; } if (diff_file_content_binary_by_size(fc)) return 0; if (odb_obj != NULL) { error = git_object__from_odb_object( (git_object **)&fc->blob, fc->repo, odb_obj, GIT_OBJ_BLOB); git_odb_object_free(odb_obj); } else { error = git_blob_lookup( (git_blob **)&fc->blob, fc->repo, &fc->file->oid); } if (!error) { fc->flags |= GIT_DIFF_FLAG__FREE_BLOB; fc->map.data = (void *)git_blob_rawcontent(fc->blob); fc->map.len = (size_t)git_blob_rawsize(fc->blob); } return error; }
static int update_cb(const char *refname, const git_oid *a, const git_oid *b, void *data) { char a_str[GIT_OID_HEXSZ+1], b_str[GIT_OID_HEXSZ+1]; data = data; git_oid_fmt(b_str, b); b_str[GIT_OID_HEXSZ] = '\0'; if (git_oid_iszero(a)) { printf("[new] %.20s %s\n", b_str, refname); } else { git_oid_fmt(a_str, a); a_str[GIT_OID_HEXSZ] = '\0'; printf("[updated] %.10s..%.10s %s\n", a_str, b_str, refname); } return 0; }
int git_reference_peel( git_object **peeled, git_reference *ref, git_otype target_type) { git_reference *resolved = NULL; git_object *target = NULL; int error; assert(ref); if (ref->type == GIT_REF_OID) { resolved = ref; } else { if ((error = git_reference_resolve(&resolved, ref)) < 0) return peel_error(error, ref, "Cannot resolve reference"); } if (!git_oid_iszero(&resolved->peel)) { error = git_object_lookup(&target, git_reference_owner(ref), &resolved->peel, GIT_OBJ_ANY); } else { error = git_object_lookup(&target, git_reference_owner(ref), &resolved->target.oid, GIT_OBJ_ANY); } if (error < 0) { peel_error(error, ref, "Cannot retrieve reference target"); goto cleanup; } if (target_type == GIT_OBJ_ANY && git_object_type(target) != GIT_OBJ_TAG) error = git_object_dup(peeled, target); else error = git_object_peel(peeled, target, target_type); cleanup: git_object_free(target); if (resolved != ref) git_reference_free(resolved); return error; }
static int update_tips(const char *refname, const git_oid *first, const git_oid *second, void *payload) { char first_oid_s[GIT_OID_HEXSZ+1]; char second_oid_s[GIT_OID_HEXSZ+1]; char textfield_update_string[MAXLINE]; memset(textfield_update_string, 0, sizeof(textfield_update_string)); (void) payload; // not used memset(first_oid_s, 0, GIT_OID_HEXSZ+1); memset(second_oid_s, 0, GIT_OID_HEXSZ+1); git_oid_fmt(second_oid_s, second); second_oid_s[GIT_OID_HEXSZ] = '\0'; /* The first oid indicates if it's a new object or not - first oid == 0 -> second oid is a new object - first oid != 0 -> update of an old object */ if (git_oid_iszero(first)) { snprintf(textfield_update_string, sizeof(textfield_update_string), _("[new] %.20s %s"), second_oid_s, refname); write_info_msg(textfield_update_string); } else { git_oid_fmt(first_oid_s, first); first_oid_s[GIT_OID_HEXSZ] = '\0'; snprintf(textfield_update_string, sizeof(textfield_update_string), _("[updated] %.10s..%.10s %s"), first_oid_s, second_oid_s, refname); write_info_msg(textfield_update_string); } return 0; }
static int diff_file_content_load_blob( git_diff_file_content *fc, git_diff_options *opts) { int error = 0; git_odb_object *odb_obj = NULL; if (git_oid_iszero(&fc->file->id)) return 0; if (fc->file->mode == GIT_FILEMODE_COMMIT) return diff_file_content_commit_to_str(fc, false); /* if we don't know size, try to peek at object header first */ if (!fc->file->size) { if ((error = git_diff_file__resolve_zero_size( fc->file, &odb_obj, fc->repo)) < 0) return error; } if ((opts->flags & GIT_DIFF_SHOW_BINARY) == 0 && diff_file_content_binary_by_size(fc)) return 0; if (odb_obj != NULL) { error = git_object__from_odb_object( (git_object **)&fc->blob, fc->repo, odb_obj, GIT_OBJECT_BLOB); git_odb_object_free(odb_obj); } else { error = git_blob_lookup( (git_blob **)&fc->blob, fc->repo, &fc->file->id); } if (!error) { fc->flags |= GIT_DIFF_FLAG__FREE_BLOB; fc->map.data = (void *)git_blob_rawcontent(fc->blob); fc->map.len = (size_t)git_blob_rawsize(fc->blob); } return error; }
/** * Reads the tree object out of a commit object, or returns an empty tree * if the commit id is zero. */ static int sync_get_tree(git_oid *out, git_repository *repo, const git_oid *commit_id) { int e = 0; git_treebuilder *tb = NULL; git_commit *commit = NULL; if (git_oid_iszero(commit_id)) { git_check(git_treebuilder_new(&tb, repo, NULL)); git_check(git_treebuilder_write(out, tb)); } else { git_check(git_commit_lookup(&commit, repo, commit_id)); git_oid_cpy(out, git_commit_tree_id(commit)); } exit: if (tb) git_treebuilder_free(tb); if (commit) git_commit_free(commit); return e; }
static int diff_print_patch_file( const git_diff_delta *delta, float progress, void *data) { diff_print_info *pi = data; const char *oldpfx = pi->diff ? pi->diff->opts.old_prefix : NULL; const char *oldpath = delta->old_file.path; const char *newpfx = pi->diff ? pi->diff->opts.new_prefix : NULL; const char *newpath = delta->new_file.path; uint32_t opts_flags = pi->diff ? pi->diff->opts.flags : GIT_DIFF_NORMAL; GIT_UNUSED(progress); if (S_ISDIR(delta->new_file.mode) || delta->status == GIT_DELTA_UNMODIFIED || delta->status == GIT_DELTA_IGNORED || (delta->status == GIT_DELTA_UNTRACKED && (opts_flags & GIT_DIFF_INCLUDE_UNTRACKED_CONTENT) == 0)) return 0; if (!oldpfx) oldpfx = DIFF_OLD_PREFIX_DEFAULT; if (!newpfx) newpfx = DIFF_NEW_PREFIX_DEFAULT; git_buf_clear(pi->buf); git_buf_printf(pi->buf, "diff --git %s%s %s%s\n", oldpfx, delta->old_file.path, newpfx, delta->new_file.path); if (diff_print_oid_range(pi, delta) < 0) return -1; if (git_oid_iszero(&delta->old_file.oid)) { oldpfx = ""; oldpath = "/dev/null"; } if (git_oid_iszero(&delta->new_file.oid)) { newpfx = ""; newpath = "/dev/null"; } if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0) { git_buf_printf(pi->buf, "--- %s%s\n", oldpfx, oldpath); git_buf_printf(pi->buf, "+++ %s%s\n", newpfx, newpath); } if (git_buf_oom(pi->buf)) return -1; if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_FILE_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) return callback_error(); if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0) return 0; git_buf_clear(pi->buf); git_buf_printf( pi->buf, "Binary files %s%s and %s%s differ\n", oldpfx, oldpath, newpfx, newpath); if (git_buf_oom(pi->buf)) return -1; if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_BINARY, git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) return callback_error(); return 0; }
/** * Updates the master branch with the latest changes, including local * changes and changes from the remote repository. */ int sync_master(git_repository *repo, int *files_changed, int *need_push) { int e = 0; git_oid master_id = {{0}}; git_oid remote_id = {{0}}; git_oid base_id = {{0}}; int master_dirty = 0; int remote_dirty = 0; int local_dirty = 0; // Find the relevant commit objects: git_check(sync_lookup_soft(&master_id, repo, SYNC_REF_MASTER)); git_check(sync_lookup_soft(&remote_id, repo, SYNC_REF_REMOTE)); if (!git_oid_iszero(&remote_id) && !git_oid_iszero(&master_id)) { e = git_merge_base(&base_id, repo, &master_id, &remote_id); if (e < 0 && e != GIT_ENOTFOUND) { goto exit; } } // Figure out what needs syncing: master_dirty = git_oid_cmp(&master_id, &base_id); remote_dirty = git_oid_cmp(&remote_id, &base_id); git_check(sync_local_dirty(&local_dirty, repo, &master_id)); if (remote_dirty) { if (master_dirty || local_dirty) { // 3-way merge: git_oid local_tree; git_oid base_tree; git_oid remote_tree; if (local_dirty) { git_check(sync_workdir_tree(&local_tree, repo)); } else { git_check(sync_get_tree(&local_tree, repo, &master_id)); } git_check(sync_get_tree(&remote_tree, repo, &remote_id)); git_check(sync_get_tree(&base_tree, repo, &base_id)); // Do merge: git_oid merged_tree; git_check(sync_merge_trees(&merged_tree, repo, &base_tree, &remote_tree, &local_tree)); // Commit to master: char const *message = local_dirty ? "merge local changes" : "merge"; if (git_oid_iszero(&master_id)) { const git_oid *parents[] = {&remote_id}; git_check(sync_commit_master(repo, message, &merged_tree, 1, parents)); } else { const git_oid *parents[] = {&master_id, &remote_id}; git_check(sync_commit_master(repo, message, &merged_tree, 2, parents)); } } else { // Fast-forward to remote: git_check(sync_fast_forward(repo, SYNC_REF_MASTER, &remote_id)); } if (!git_repository_is_bare(repo)) { git_check(sync_checkout(repo, SYNC_REF_MASTER)); } } else if (local_dirty) { // Commit local changes: git_oid local_tree; git_check(sync_workdir_tree(&local_tree, repo)); if (git_oid_iszero(&master_id)) { const git_oid *parents[] = {NULL}; git_check(sync_commit_master(repo, "first commit", &local_tree, 0, parents)); } else { const git_oid *parents[] = {&master_id}; git_check(sync_commit_master(repo, "commit local changes", &local_tree, 1, parents)); } } // Report the outcome: *files_changed = !!remote_dirty; *need_push = local_dirty || master_dirty; exit: return e; }
static git_commit* FindFileRecentCommit(git_repository* repository, const CString& path) { CAutoRevwalk walk; if (git_revwalk_new(walk.GetPointer(), repository)) return nullptr; CStringA pathA = CUnicodeUtils::GetUTF8(path); if (pathA.GetLength() >= MAX_PATH) return nullptr; const char *pathC = pathA; char folder[MAX_PATH] = {0}, file[MAX_PATH] = {0}; const char *slash = strrchr(pathC, '/'); if (slash) { strncpy(folder, pathC, slash - pathC + 1); folder[slash - pathC + 1] = '\0'; strcpy(file, slash + 1); } else { folder[0] = '\0'; strcpy(file, pathC); } TreewalkStruct treewalkstruct = { folder, file }; if (git_revwalk_push_head(walk)) return nullptr; git_oid oid; CAutoCommit commit; while (!git_revwalk_next(&oid, walk)) { if (git_commit_lookup(commit.GetPointer(), repository, &oid)) return nullptr; CAutoTree tree; if (git_commit_tree(tree.GetPointer(), commit)) return nullptr; memset(&treewalkstruct.oid.id, 0, sizeof(treewalkstruct.oid.id)); int ret = git_tree_walk(tree, GIT_TREEWALK_PRE, TreewalkCB_FindFileRecentCommit, &treewalkstruct); if (ret < 0 && ret != GIT_EUSER) return nullptr; // check if file not found if (git_oid_iszero(&treewalkstruct.oid)) return nullptr; bool diff = true; // for merge point, check if it is different to all parents, if yes then there are real change in the merge point. // if no parent then of course it is different for (unsigned int i = 0; i < git_commit_parentcount(commit); ++i) { CAutoCommit commit2; if (git_commit_parent(commit2.GetPointer(), commit, i)) return nullptr; CAutoTree tree2; if (git_commit_tree(tree2.GetPointer(), commit2)) return nullptr; TreewalkStruct treewalkstruct2 = { folder, file }; memset(&treewalkstruct2.oid.id, 0, sizeof(treewalkstruct2.oid.id)); int ret = git_tree_walk(tree2, GIT_TREEWALK_PRE, TreewalkCB_FindFileRecentCommit, &treewalkstruct2); if (ret < 0 && ret != GIT_EUSER) return nullptr; if (!git_oid_cmp(&treewalkstruct.oid, &treewalkstruct2.oid)) diff = false; else if (git_revwalk_hide(walk, git_commit_parent_id(commit, i))) return nullptr; } if (diff) break; } return commit.Detach(); }
void test_diff_blob__can_compare_against_null_blobs_with_patch(void) { git_blob *e = NULL; git_patch *p; const git_diff_delta *delta; const git_diff_line *line; int l, max_l; cl_git_pass(git_patch_from_blobs(&p, d, NULL, e, NULL, &opts)); cl_assert(p != NULL); delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_DELETED, delta->status); cl_assert_equal_oid(git_blob_id(d), &delta->old_file.id); cl_assert_equal_sz(git_blob_rawsize(d), delta->old_file.size); cl_assert(git_oid_iszero(&delta->new_file.id)); cl_assert_equal_sz(0, delta->new_file.size); cl_assert_equal_i(1, (int)git_patch_num_hunks(p)); cl_assert_equal_i(14, git_patch_num_lines_in_hunk(p, 0)); max_l = git_patch_num_lines_in_hunk(p, 0); for (l = 0; l < max_l; ++l) { cl_git_pass(git_patch_get_line_in_hunk(&line, p, 0, l)); cl_assert_equal_i(GIT_DIFF_LINE_DELETION, (int)line->origin); } git_patch_free(p); opts.flags |= GIT_DIFF_REVERSE; cl_git_pass(git_patch_from_blobs(&p, d, NULL, e, NULL, &opts)); cl_assert(p != NULL); delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_ADDED, delta->status); cl_assert(git_oid_iszero(&delta->old_file.id)); cl_assert_equal_sz(0, delta->old_file.size); cl_assert_equal_oid(git_blob_id(d), &delta->new_file.id); cl_assert_equal_sz(git_blob_rawsize(d), delta->new_file.size); cl_assert_equal_i(1, (int)git_patch_num_hunks(p)); cl_assert_equal_i(14, git_patch_num_lines_in_hunk(p, 0)); max_l = git_patch_num_lines_in_hunk(p, 0); for (l = 0; l < max_l; ++l) { cl_git_pass(git_patch_get_line_in_hunk(&line, p, 0, l)); cl_assert_equal_i(GIT_DIFF_LINE_ADDITION, (int)line->origin); } git_patch_free(p); opts.flags ^= GIT_DIFF_REVERSE; cl_git_pass(git_patch_from_blobs(&p, alien, NULL, NULL, NULL, &opts)); cl_assert(p != NULL); delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_DELETED, delta->status); cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0); cl_assert_equal_i(0, (int)git_patch_num_hunks(p)); git_patch_free(p); cl_git_pass(git_patch_from_blobs(&p, NULL, NULL, alien, NULL, &opts)); cl_assert(p != NULL); delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_ADDED, delta->status); cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0); cl_assert_equal_i(0, (int)git_patch_num_hunks(p)); git_patch_free(p); }