예제 #1
0
/**
 * 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;
}
예제 #2
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;
}
예제 #3
0
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;
}
예제 #4
0
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;
}
예제 #5
0
파일: blob.c 프로젝트: RsrchBoy/p5-Git-Raw
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);
}
예제 #6
0
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;
}
예제 #7
0
파일: diff_file.c 프로젝트: 0CV0/libgit2
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;
}
예제 #8
0
파일: fetch.c 프로젝트: bxio/.atom
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;
}
예제 #9
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;
}
예제 #10
0
파일: git.c 프로젝트: tjohann/sdk_builder
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;
}
예제 #11
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;
}
예제 #12
0
파일: sync.c 프로젝트: Airbitz/airbitz-core
/**
 * 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;
}
예제 #13
0
파일: diff_print.c 프로젝트: 0CV0/libgit2
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;
}
예제 #14
0
파일: sync.c 프로젝트: Airbitz/airbitz-core
/**
 * 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;
}
예제 #15
0
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();
}
예제 #16
0
파일: blob.c 프로젝트: RsrchBoy/p5-Git-Raw
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);
}