mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-02 17:42:31 +00:00
Merge remote-tracking branch 'remotes/upstream/development' into development
This commit is contained in:
commit
b5212858f1
@ -101,23 +101,4 @@ at the
|
||||
|
||||
## Starter Projects
|
||||
|
||||
So, you want to start helping out with `libgit2`? That's fantastic? We
|
||||
welcome contributions and we promise we'll try to be nice.
|
||||
|
||||
If you want to jump in, you can look at our issues list to see if there
|
||||
are any unresolved issues to jump in on. Also, here is a list of some
|
||||
smaller project ideas that could help you become familiar with the code
|
||||
base and make a nice first step:
|
||||
|
||||
* Look at the `examples/` programs, find an existing one that mirrors a
|
||||
core Git command and add a missing command-line option. There are many
|
||||
gaps right now and this helps demonstrate how to use the library.
|
||||
* Pick a Git command that is not emulates in `examples/` and write a new
|
||||
example that mirrors the behavior. Examples don't have to be perfect
|
||||
emulations, but should demonstrate how to use the libgit2 APIs to get
|
||||
results that are similar to Git commands. This lets you (and us) easily
|
||||
exercise a particular facet of the API and measure compatability and
|
||||
feature parity with core git.
|
||||
* Submit a PR to clarify documentation! While we do try to document all of
|
||||
the APIs, your fresh eyes on the documentation will find areas that are
|
||||
confusing much more easily.
|
||||
See our [projects list](https://github.com/libgit2/libgit2/blob/development/PROJECTS.md).
|
||||
|
88
PROJECTS.md
Normal file
88
PROJECTS.md
Normal file
@ -0,0 +1,88 @@
|
||||
Projects For LibGit2
|
||||
====================
|
||||
|
||||
So, you want to start helping out with `libgit2`? That's fantastic! We
|
||||
welcome contributions and we promise we'll try to be nice.
|
||||
|
||||
This is a list of libgit2 related projects that new contributors can take
|
||||
on. It includes a number of good starter projects and well as some larger
|
||||
ideas that no one is actively working on.
|
||||
|
||||
## Before You Start
|
||||
|
||||
Please start by reading the README.md, CONTRIBUTING.md, and CONVENTIONS.md
|
||||
files before diving into one of these projects. Those will explain our
|
||||
work flow and coding conventions to help ensure that your work will be
|
||||
easily integrated into libgit2.
|
||||
|
||||
Next, work through the build instructions and make sure you can clone the
|
||||
repository, compile it, and run the tests successfully. That will make
|
||||
sure that your development environment is set up correctly and you are
|
||||
ready to start on libgit2 development.
|
||||
|
||||
## Starter Projects
|
||||
|
||||
These are good small projects to get started with libgit2.
|
||||
|
||||
* Look at the `examples/` programs, find an existing one that mirrors a
|
||||
core Git command and add a missing command-line option. There are many
|
||||
gaps right now and this helps demonstrate how to use the library. Here
|
||||
are some specific ideas:
|
||||
* Add the `--minimal` flag to `examples/diff.c` since the `libgit2`
|
||||
diff API now has a flag to support it
|
||||
* Add the `--patience` flag to `examples/diff.c` since it is also now
|
||||
supported.
|
||||
* Add the `--shortstat` flag to `examples/diff.c` based on the work
|
||||
that was done to add `--numstat` already.
|
||||
* Fix the `examples/diff.c` implementation of the `-B`
|
||||
(a.k.a. `--break-rewrites`) command line option to actually look for
|
||||
the optional `[<n>][/<m>]` configuration values. There is an
|
||||
existing comment that reads `/* TODO: parse thresholds */`. The
|
||||
trick to this one will be doing it in a manner that is clean and
|
||||
simple, but still handles the various cases correctly (e.g. `-B/70%`
|
||||
is apparently a legal setting).
|
||||
* Implement the `--log-size` option for `examples/log.c`. I think all
|
||||
the data is available, you would just need to add the code into the
|
||||
`print_commit()` routine (along with a way of passing the option
|
||||
into that function).
|
||||
* For `examples/log.c`, implement any one of `--author=<...>`,
|
||||
`--committer=<...>`, or `--grep=<...>` but just use simple string
|
||||
match with `strstr()` instead of full regular expression
|
||||
matching. (I.e. I'm suggesting implementing this as if
|
||||
`--fixed-strings` was always turned on, because it will be a simpler
|
||||
project.)
|
||||
* As an extension to the matching idea for `examples/log.c`, add the
|
||||
`-i` option to use `strcasestr()` for matches.
|
||||
* For `examples/log.c`, implement the `--first-parent` option now that
|
||||
libgit2 supports it in the revwalk API.
|
||||
* Pick a Git command that is not already emulated in `examples/` and write
|
||||
a new example that mirrors the behavior. Examples don't have to be
|
||||
perfect emulations, but should demonstrate how to use the libgit2 APIs
|
||||
to get results that are similar to Git commands. This lets you (and us)
|
||||
easily exercise a particular facet of the API and measure compatability
|
||||
and feature parity with core git.
|
||||
* Submit a PR to clarify documentation! While we do try to document all of
|
||||
the APIs, your fresh eyes on the documentation will find areas that are
|
||||
confusing much more easily.
|
||||
|
||||
If none of these appeal to you, take a look at our issues list to see if
|
||||
there are any unresolved issues you'd like to jump in on.
|
||||
|
||||
## Larger Projects
|
||||
|
||||
These are ideas for larger projects mostly taken from our backlog of
|
||||
[Issues](https://github.com/libgit2/libgit2/issues). Please don't dive
|
||||
into one of these as a first project for libgit2 - we'd rather get to
|
||||
know you first by successfully shipping your work on one of the smaller
|
||||
projects above.
|
||||
|
||||
* Port part of the Git test suite to run against the command line emulation
|
||||
in examples/
|
||||
* Fix symlink support for files in the .git directory (i.e. don't overwrite
|
||||
the symlinks when writing the file contents back out)
|
||||
* Implement a 'git describe' like API
|
||||
* Add hooks API to enumerate and manage hooks (not run them at this point)
|
||||
* Isolate logic of ignore evaluation into a standalone API
|
||||
* Upgrade internal libxdiff code to latest from core Git
|
||||
* Add a hashtable lookup for files in the index instead of binary search
|
||||
every time
|
25
README.md
25
README.md
@ -4,9 +4,9 @@ libgit2 - the Git linkable library
|
||||
[](http://travis-ci.org/libgit2/libgit2)
|
||||
[](https://scan.coverity.com/projects/639)
|
||||
|
||||
`libgit2` is a portable, pure C implementation of the Git core methods provided as a
|
||||
re-entrant linkable library with a solid API, allowing you to write native
|
||||
speed custom Git applications in any language with bindings.
|
||||
`libgit2` is a portable, pure C implementation of the Git core methods
|
||||
provided as a re-entrant linkable library with a solid API, allowing you to
|
||||
write native speed custom Git applications in any language with bindings.
|
||||
|
||||
`libgit2` is licensed under a **very permissive license** (GPLv2 with a special
|
||||
Linking Exception). This basically means that you can link it (unmodified)
|
||||
@ -30,8 +30,9 @@ Additionally, the example code has been released to the public domain (see the
|
||||
What It Can Do
|
||||
==============
|
||||
|
||||
`libgit2` is already very usable and is being used in production for many applications including the GitHub.com site, in Plastic SCM
|
||||
and also powering Microsoft's Visual Studio tools for Git. The library provides:
|
||||
`libgit2` is already very usable and is being used in production for many
|
||||
applications including the GitHub.com site, in Plastic SCM and also powering
|
||||
Microsoft's Visual Studio tools for Git. The library provides:
|
||||
|
||||
* SHA conversions, formatting and shortening
|
||||
* abstracted ODB backend system
|
||||
@ -199,14 +200,16 @@ we can add it to the list.
|
||||
How Can I Contribute?
|
||||
==================================
|
||||
|
||||
Check the [contribution guidelines](CONTRIBUTING.md).
|
||||
|
||||
Check the [contribution guidelines](CONTRIBUTING.md) to understand our
|
||||
workflow, the libgit2 [coding conventions](CONVENTIONS.md), and out list of
|
||||
[good starting projects](PROJECTS.md).
|
||||
|
||||
License
|
||||
==================================
|
||||
`libgit2` is under GPL2 **with linking exemption**. This means you
|
||||
can link to and use the library from any program, proprietary or open source; paid
|
||||
or gratis. However, you cannot modify libgit2 and distribute it without
|
||||
|
||||
`libgit2` is under GPL2 **with linking exemption**. This means you can link to
|
||||
and use the library from any program, proprietary or open source; paid or
|
||||
gratis. However, you cannot modify libgit2 and distribute it without
|
||||
supplying the source.
|
||||
|
||||
See the COPYING file for the full license text.
|
||||
See the [COPYING file](COPYING) for the full license text.
|
||||
|
@ -31,6 +31,7 @@ struct opts {
|
||||
int M;
|
||||
int start_line;
|
||||
int end_line;
|
||||
int F;
|
||||
};
|
||||
static void parse_opts(struct opts *o, int argc, char *argv[]);
|
||||
|
||||
@ -52,6 +53,7 @@ int main(int argc, char *argv[])
|
||||
parse_opts(&o, argc, argv);
|
||||
if (o.M) blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES;
|
||||
if (o.C) blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES;
|
||||
if (o.F) blameopts.flags |= GIT_BLAME_FIRST_PARENT;
|
||||
|
||||
/** Open the repository. */
|
||||
check_lg2(git_repository_open_ext(&repo, ".", 0, NULL), "Couldn't open repository", NULL);
|
||||
@ -147,6 +149,7 @@ static void usage(const char *msg, const char *arg)
|
||||
fprintf(stderr, " -L <n,m> process only line range n-m, counting from 1\n");
|
||||
fprintf(stderr, " -M find line moves within and across files\n");
|
||||
fprintf(stderr, " -C find line copies within and across files\n");
|
||||
fprintf(stderr, " -F follow only the first parent commits\n");
|
||||
fprintf(stderr, "\n");
|
||||
exit(1);
|
||||
}
|
||||
@ -175,6 +178,8 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
|
||||
o->M = 1;
|
||||
else if (!strcasecmp(a, "-C"))
|
||||
o->C = 1;
|
||||
else if (!strcasecmp(a, "-F"))
|
||||
o->F = 1;
|
||||
else if (!strcasecmp(a, "-L")) {
|
||||
i++; a = argv[i];
|
||||
if (i >= argc) fatal("Not enough arguments to -L", NULL);
|
||||
|
@ -269,19 +269,23 @@ static void diff_print_numstat(git_diff *diff)
|
||||
{
|
||||
git_patch *patch;
|
||||
const git_diff_delta *delta;
|
||||
size_t i;
|
||||
size_t ndeltas;
|
||||
size_t d, ndeltas = git_diff_num_deltas(diff);
|
||||
size_t nadditions, ndeletions;
|
||||
ndeltas = git_diff_num_deltas(diff);
|
||||
for (i = 0; i < ndeltas; i++){
|
||||
|
||||
for (d = 0; d < ndeltas; d++){
|
||||
check_lg2(
|
||||
git_patch_from_diff(&patch, diff, i),
|
||||
git_patch_from_diff(&patch, diff, d),
|
||||
"generating patch from diff", NULL);
|
||||
|
||||
check_lg2(
|
||||
git_patch_line_stats(NULL, &nadditions, &ndeletions, patch),
|
||||
"generating the number of additions and deletions", NULL);
|
||||
|
||||
delta = git_patch_get_delta(patch);
|
||||
printf("%u\t%u\t%s\n", nadditions, ndeletions, delta->new_file.path);
|
||||
|
||||
printf("%ld\t%ld\t%s\n",
|
||||
(long)nadditions, (long)ndeletions, delta->new_file.path);
|
||||
|
||||
git_patch_free(patch);
|
||||
}
|
||||
git_patch_free(patch);
|
||||
}
|
||||
|
@ -28,9 +28,6 @@
|
||||
# his/her consent on a patch-by-patch basis.
|
||||
# "???" means the person is a prominent contributor who has
|
||||
# not yet made his/her standpoint clear.
|
||||
# "ign" means the authors consent is ignored for the purpose
|
||||
# of libification. This is because the author has contributed
|
||||
# to areas that aren't interesting for the library.
|
||||
#
|
||||
# Please try to keep the list alphabetically ordered. It will
|
||||
# help in case we get all 600-ish git.git authors on it.
|
||||
@ -61,7 +58,6 @@ ok Linus Torvalds <torvalds@linux-foundation.org>
|
||||
ok Lukas Sandström <lukass@etek.chalmers.se>
|
||||
ok Matthieu Moy <Matthieu.Moy@imag.fr>
|
||||
ok Michael Haggerty <mhagger@alum.mit.edu>
|
||||
ign Mike McCormack <mike@codeweavers.com> (imap-send)
|
||||
ok Nicolas Pitre <nico@fluxnic.net> <nico@cam.org>
|
||||
ok Paolo Bonzini <bonzini@gnu.org>
|
||||
ok Paul Kocher <paul@cryptography.com>
|
||||
@ -70,7 +66,6 @@ ok Petr Onderka <gsvick@gmail.com>
|
||||
ok Pierre Habouzit <madcoder@debian.org>
|
||||
ok Pieter de Bie <pdebie@ai.rug.nl>
|
||||
ok René Scharfe <rene.scharfe@lsrfire.ath.cx>
|
||||
ign Robert Shearman <rob@codeweavers.com> (imap-send)
|
||||
ok Sebastian Schuberth <sschuberth@gmail.com>
|
||||
ok Shawn O. Pearce <spearce@spearce.org>
|
||||
ok Steffen Prohaska <prohaska@zib.de>
|
||||
|
@ -40,6 +40,9 @@ typedef enum {
|
||||
* commit (like `git blame -CCC`). Implies SAME_COMMIT_COPIES.
|
||||
* NOT IMPLEMENTED. */
|
||||
GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES = (1<<3),
|
||||
/** Restrict the search of commits to those reachable following only the
|
||||
* first parents. */
|
||||
GIT_BLAME_FIRST_PARENT = (1<<4),
|
||||
} git_blame_flag_t;
|
||||
|
||||
/**
|
||||
|
@ -1013,6 +1013,39 @@ GIT_EXTERN(int) git_diff_blob_to_buffer(
|
||||
git_diff_line_cb line_cb,
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
* Directly run a diff between two buffers.
|
||||
*
|
||||
* Even more than with `git_diff_blobs`, comparing two buffer lacks
|
||||
* context, so the `git_diff_file` parameters to the callbacks will be
|
||||
* faked a la the rules for `git_diff_blobs()`.
|
||||
*
|
||||
* @param old_buffer Raw data for old side of diff, or NULL for empty
|
||||
* @param old_len Length of the raw data for old side of the diff
|
||||
* @param old_as_path Treat old buffer as if it had this filename; can be NULL
|
||||
* @param new_buffer Raw data for new side of diff, or NULL for empty
|
||||
* @param new_len Length of raw data for new side of diff
|
||||
* @param new_as_path Treat buffer as if it had this filename; can be NULL
|
||||
* @param options Options for diff, or NULL for default options
|
||||
* @param file_cb Callback for "file"; made once if there is a diff; can be NULL
|
||||
* @param hunk_cb Callback for each hunk in diff; can be NULL
|
||||
* @param line_cb Callback for each line in diff; can be NULL
|
||||
* @param payload Payload passed to each callback function
|
||||
* @return 0 on success, non-zero callback return value, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_diff_buffers(
|
||||
const void *old_buffer,
|
||||
size_t old_len,
|
||||
const char *old_as_path,
|
||||
const void *new_buffer,
|
||||
size_t new_len,
|
||||
const char *new_as_path,
|
||||
const git_diff_options *options,
|
||||
git_diff_file_cb file_cb,
|
||||
git_diff_hunk_cb hunk_cb,
|
||||
git_diff_line_cb line_cb,
|
||||
void *payload);
|
||||
|
||||
|
||||
GIT_END_DECL
|
||||
|
||||
|
@ -105,6 +105,34 @@ GIT_EXTERN(int) git_patch_from_blob_and_buffer(
|
||||
const char *buffer_as_path,
|
||||
const git_diff_options *opts);
|
||||
|
||||
/**
|
||||
* Directly generate a patch from the difference between two buffers.
|
||||
*
|
||||
* This is just like `git_diff_buffers()` except it generates a patch
|
||||
* object for the difference instead of directly making callbacks. You can
|
||||
* use the standard `git_patch` accessor functions to read the patch
|
||||
* data, and you must call `git_patch_free()` on the patch when done.
|
||||
*
|
||||
* @param out The generated patch; NULL on error
|
||||
* @param old_buffer Raw data for old side of diff, or NULL for empty
|
||||
* @param old_len Length of the raw data for old side of the diff
|
||||
* @param old_as_path Treat old buffer as if it had this filename; can be NULL
|
||||
* @param new_buffer Raw data for new side of diff, or NULL for empty
|
||||
* @param new_len Length of raw data for new side of diff
|
||||
* @param new_as_path Treat buffer as if it had this filename; can be NULL
|
||||
* @param opts Options for diff, or NULL for default options
|
||||
* @return 0 on success or error code < 0
|
||||
*/
|
||||
GIT_EXTERN(int) git_patch_from_buffers(
|
||||
git_patch **out,
|
||||
const void *old_buffer,
|
||||
size_t old_len,
|
||||
const char *old_as_path,
|
||||
const char *new_buffer,
|
||||
size_t new_len,
|
||||
const char *new_as_path,
|
||||
const git_diff_options *opts);
|
||||
|
||||
/**
|
||||
* Free a git_patch object.
|
||||
*/
|
||||
|
@ -485,12 +485,14 @@ static void pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt
|
||||
git_blame__origin *sg_buf[16];
|
||||
git_blame__origin *porigin, **sg_origin = sg_buf;
|
||||
|
||||
GIT_UNUSED(opt);
|
||||
|
||||
num_parents = git_commit_parentcount(commit);
|
||||
if (!git_oid_cmp(git_commit_id(commit), &blame->options.oldest_commit))
|
||||
/* Stop at oldest specified commit */
|
||||
num_parents = 0;
|
||||
else if (opt & GIT_BLAME_FIRST_PARENT && num_parents > 1)
|
||||
/* Limit search to the first parent */
|
||||
num_parents = 1;
|
||||
|
||||
if (!num_parents) {
|
||||
git_oid_cpy(&blame->options.oldest_commit, git_commit_id(commit));
|
||||
goto finish;
|
||||
|
13
src/branch.c
13
src/branch.c
@ -58,6 +58,7 @@ int git_branch_create(
|
||||
const git_signature *signature,
|
||||
const char *log_message)
|
||||
{
|
||||
int is_head = 0;
|
||||
git_reference *branch = NULL;
|
||||
git_buf canonical_branch_name = GIT_BUF_INIT,
|
||||
log_message_buf = GIT_BUF_INIT;
|
||||
@ -65,7 +66,19 @@ int git_branch_create(
|
||||
|
||||
assert(branch_name && commit && ref_out);
|
||||
assert(git_object_owner((const git_object *)commit) == repository);
|
||||
if (git_branch_lookup(&branch, repository, branch_name, GIT_BRANCH_LOCAL) == 0) {
|
||||
if ((is_head = git_branch_is_head(branch)) < 0) {
|
||||
error = is_head;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_head && force) {
|
||||
giterr_set(GITERR_REFERENCE, "Cannot force update branch '%s' as it is "
|
||||
"the current HEAD of the repository.", git_reference_name(branch));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0)
|
||||
goto cleanup;
|
||||
|
||||
|
@ -127,57 +127,38 @@ int git_diff_file_content__init_from_diff(
|
||||
return diff_file_content_init_common(fc, &diff->opts);
|
||||
}
|
||||
|
||||
int git_diff_file_content__init_from_blob(
|
||||
int git_diff_file_content__init_from_src(
|
||||
git_diff_file_content *fc,
|
||||
git_repository *repo,
|
||||
const git_diff_options *opts,
|
||||
const git_blob *blob,
|
||||
const git_diff_file_content_src *src,
|
||||
git_diff_file *as_file)
|
||||
{
|
||||
memset(fc, 0, sizeof(*fc));
|
||||
fc->repo = repo;
|
||||
fc->file = as_file;
|
||||
fc->blob = blob;
|
||||
fc->blob = src->blob;
|
||||
|
||||
if (!blob) {
|
||||
if (!src->blob && !src->buf) {
|
||||
fc->flags |= GIT_DIFF_FLAG__NO_DATA;
|
||||
} else {
|
||||
fc->flags |= GIT_DIFF_FLAG__LOADED;
|
||||
fc->file->flags |= GIT_DIFF_FLAG_VALID_ID;
|
||||
fc->file->size = git_blob_rawsize(blob);
|
||||
fc->file->mode = GIT_FILEMODE_BLOB;
|
||||
git_oid_cpy(&fc->file->id, git_blob_id(blob));
|
||||
|
||||
fc->map.len = (size_t)fc->file->size;
|
||||
fc->map.data = (char *)git_blob_rawcontent(blob);
|
||||
}
|
||||
if (src->blob) {
|
||||
fc->file->size = git_blob_rawsize(src->blob);
|
||||
git_oid_cpy(&fc->file->id, git_blob_id(src->blob));
|
||||
|
||||
return diff_file_content_init_common(fc, opts);
|
||||
}
|
||||
fc->map.len = (size_t)fc->file->size;
|
||||
fc->map.data = (char *)git_blob_rawcontent(src->blob);
|
||||
} else {
|
||||
fc->file->size = src->buflen;
|
||||
git_odb_hash(&fc->file->id, src->buf, src->buflen, GIT_OBJ_BLOB);
|
||||
|
||||
int git_diff_file_content__init_from_raw(
|
||||
git_diff_file_content *fc,
|
||||
git_repository *repo,
|
||||
const git_diff_options *opts,
|
||||
const char *buf,
|
||||
size_t buflen,
|
||||
git_diff_file *as_file)
|
||||
{
|
||||
memset(fc, 0, sizeof(*fc));
|
||||
fc->repo = repo;
|
||||
fc->file = as_file;
|
||||
|
||||
if (!buf) {
|
||||
fc->flags |= GIT_DIFF_FLAG__NO_DATA;
|
||||
} else {
|
||||
fc->flags |= GIT_DIFF_FLAG__LOADED;
|
||||
fc->file->flags |= GIT_DIFF_FLAG_VALID_ID;
|
||||
fc->file->size = buflen;
|
||||
fc->file->mode = GIT_FILEMODE_BLOB;
|
||||
git_odb_hash(&fc->file->id, buf, buflen, GIT_OBJ_BLOB);
|
||||
|
||||
fc->map.len = buflen;
|
||||
fc->map.data = (char *)buf;
|
||||
fc->map.len = src->buflen;
|
||||
fc->map.data = (char *)src->buf;
|
||||
}
|
||||
}
|
||||
|
||||
return diff_file_content_init_common(fc, opts);
|
||||
|
@ -31,19 +31,21 @@ extern int git_diff_file_content__init_from_diff(
|
||||
size_t delta_index,
|
||||
bool use_old);
|
||||
|
||||
extern int git_diff_file_content__init_from_blob(
|
||||
git_diff_file_content *fc,
|
||||
git_repository *repo,
|
||||
const git_diff_options *opts,
|
||||
const git_blob *blob,
|
||||
git_diff_file *as_file);
|
||||
typedef struct {
|
||||
const git_blob *blob;
|
||||
const void *buf;
|
||||
size_t buflen;
|
||||
const char *as_path;
|
||||
} git_diff_file_content_src;
|
||||
|
||||
extern int git_diff_file_content__init_from_raw(
|
||||
#define GIT_DIFF_FILE_CONTENT_SRC__BLOB(BLOB,PATH) { (BLOB),NULL,0,(PATH) }
|
||||
#define GIT_DIFF_FILE_CONTENT_SRC__BUF(BUF,LEN,PATH) { NULL,(BUF),(LEN),(PATH) }
|
||||
|
||||
extern int git_diff_file_content__init_from_src(
|
||||
git_diff_file_content *fc,
|
||||
git_repository *repo,
|
||||
const git_diff_options *opts,
|
||||
const char *buf,
|
||||
size_t buflen,
|
||||
const git_diff_file_content_src *src,
|
||||
git_diff_file *as_file);
|
||||
|
||||
/* this loads the blob/file-on-disk as needed */
|
||||
|
266
src/diff_patch.c
266
src/diff_patch.c
@ -5,6 +5,7 @@
|
||||
* a Linking Exception. For full terms see the included COPYING file.
|
||||
*/
|
||||
#include "common.h"
|
||||
#include "git2/blob.h"
|
||||
#include "diff.h"
|
||||
#include "diff_file.h"
|
||||
#include "diff_driver.h"
|
||||
@ -334,38 +335,45 @@ static int diff_single_generate(diff_patch_with_delta *pd, git_xdiff_output *xo)
|
||||
return error;
|
||||
}
|
||||
|
||||
static int diff_patch_from_blobs(
|
||||
static int diff_patch_from_sources(
|
||||
diff_patch_with_delta *pd,
|
||||
git_xdiff_output *xo,
|
||||
const git_blob *old_blob,
|
||||
const char *old_path,
|
||||
const git_blob *new_blob,
|
||||
const char *new_path,
|
||||
git_diff_file_content_src *oldsrc,
|
||||
git_diff_file_content_src *newsrc,
|
||||
const git_diff_options *opts)
|
||||
{
|
||||
int error = 0;
|
||||
git_repository *repo =
|
||||
new_blob ? git_object_owner((const git_object *)new_blob) :
|
||||
old_blob ? git_object_owner((const git_object *)old_blob) : NULL;
|
||||
oldsrc->blob ? git_blob_owner(oldsrc->blob) :
|
||||
newsrc->blob ? git_blob_owner(newsrc->blob) : NULL;
|
||||
git_diff_file *lfile = &pd->delta.old_file, *rfile = &pd->delta.new_file;
|
||||
git_diff_file_content *ldata = &pd->patch.ofile, *rdata = &pd->patch.nfile;
|
||||
|
||||
GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options");
|
||||
|
||||
if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) {
|
||||
const git_blob *tmp_blob;
|
||||
const char *tmp_path;
|
||||
tmp_blob = old_blob; old_blob = new_blob; new_blob = tmp_blob;
|
||||
tmp_path = old_path; old_path = new_path; new_path = tmp_path;
|
||||
void *tmp = lfile; lfile = rfile; rfile = tmp;
|
||||
tmp = ldata; ldata = rdata; rdata = tmp;
|
||||
}
|
||||
|
||||
pd->patch.delta = &pd->delta;
|
||||
|
||||
pd->delta.old_file.path = old_path;
|
||||
pd->delta.new_file.path = new_path;
|
||||
if (!oldsrc->as_path) {
|
||||
if (newsrc->as_path)
|
||||
oldsrc->as_path = newsrc->as_path;
|
||||
else
|
||||
oldsrc->as_path = newsrc->as_path = "file";
|
||||
}
|
||||
else if (!newsrc->as_path)
|
||||
newsrc->as_path = oldsrc->as_path;
|
||||
|
||||
if ((error = git_diff_file_content__init_from_blob(
|
||||
&pd->patch.ofile, repo, opts, old_blob, &pd->delta.old_file)) < 0 ||
|
||||
(error = git_diff_file_content__init_from_blob(
|
||||
&pd->patch.nfile, repo, opts, new_blob, &pd->delta.new_file)) < 0)
|
||||
lfile->path = oldsrc->as_path;
|
||||
rfile->path = newsrc->as_path;
|
||||
|
||||
if ((error = git_diff_file_content__init_from_src(
|
||||
ldata, repo, opts, oldsrc, lfile)) < 0 ||
|
||||
(error = git_diff_file_content__init_from_src(
|
||||
rdata, repo, opts, newsrc, rfile)) < 0)
|
||||
return error;
|
||||
|
||||
return diff_single_generate(pd, xo);
|
||||
@ -400,11 +408,9 @@ static int diff_patch_with_delta_alloc(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_diff_blobs(
|
||||
const git_blob *old_blob,
|
||||
const char *old_path,
|
||||
const git_blob *new_blob,
|
||||
const char *new_path,
|
||||
static int diff_from_sources(
|
||||
git_diff_file_content_src *oldsrc,
|
||||
git_diff_file_content_src *newsrc,
|
||||
const git_diff_options *opts,
|
||||
git_diff_file_cb file_cb,
|
||||
git_diff_hunk_cb hunk_cb,
|
||||
@ -420,20 +426,63 @@ int git_diff_blobs(
|
||||
&xo.output, opts, file_cb, hunk_cb, data_cb, payload);
|
||||
git_xdiff_init(&xo, opts);
|
||||
|
||||
if (!old_path && new_path)
|
||||
old_path = new_path;
|
||||
else if (!new_path && old_path)
|
||||
new_path = old_path;
|
||||
|
||||
memset(&pd, 0, sizeof(pd));
|
||||
error = diff_patch_from_blobs(
|
||||
&pd, &xo, old_blob, old_path, new_blob, new_path, opts);
|
||||
|
||||
error = diff_patch_from_sources(&pd, &xo, oldsrc, newsrc, opts);
|
||||
|
||||
git_patch_free(&pd.patch);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int patch_from_sources(
|
||||
git_patch **out,
|
||||
git_diff_file_content_src *oldsrc,
|
||||
git_diff_file_content_src *newsrc,
|
||||
const git_diff_options *opts)
|
||||
{
|
||||
int error = 0;
|
||||
diff_patch_with_delta *pd;
|
||||
git_xdiff_output xo;
|
||||
|
||||
assert(out);
|
||||
*out = NULL;
|
||||
|
||||
if ((error = diff_patch_with_delta_alloc(
|
||||
&pd, &oldsrc->as_path, &newsrc->as_path)) < 0)
|
||||
return error;
|
||||
|
||||
memset(&xo, 0, sizeof(xo));
|
||||
diff_output_to_patch(&xo.output, &pd->patch);
|
||||
git_xdiff_init(&xo, opts);
|
||||
|
||||
if (!(error = diff_patch_from_sources(pd, &xo, oldsrc, newsrc, opts)))
|
||||
*out = (git_patch *)pd;
|
||||
else
|
||||
git_patch_free((git_patch *)pd);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_diff_blobs(
|
||||
const git_blob *old_blob,
|
||||
const char *old_path,
|
||||
const git_blob *new_blob,
|
||||
const char *new_path,
|
||||
const git_diff_options *opts,
|
||||
git_diff_file_cb file_cb,
|
||||
git_diff_hunk_cb hunk_cb,
|
||||
git_diff_line_cb data_cb,
|
||||
void *payload)
|
||||
{
|
||||
git_diff_file_content_src osrc =
|
||||
GIT_DIFF_FILE_CONTENT_SRC__BLOB(old_blob, old_path);
|
||||
git_diff_file_content_src nsrc =
|
||||
GIT_DIFF_FILE_CONTENT_SRC__BLOB(new_blob, new_path);
|
||||
return diff_from_sources(
|
||||
&osrc, &nsrc, opts, file_cb, hunk_cb, data_cb, payload);
|
||||
}
|
||||
|
||||
int git_patch_from_blobs(
|
||||
git_patch **out,
|
||||
const git_blob *old_blob,
|
||||
@ -442,71 +491,11 @@ int git_patch_from_blobs(
|
||||
const char *new_path,
|
||||
const git_diff_options *opts)
|
||||
{
|
||||
int error = 0;
|
||||
diff_patch_with_delta *pd;
|
||||
git_xdiff_output xo;
|
||||
|
||||
assert(out);
|
||||
*out = NULL;
|
||||
|
||||
if (diff_patch_with_delta_alloc(&pd, &old_path, &new_path) < 0)
|
||||
return -1;
|
||||
|
||||
memset(&xo, 0, sizeof(xo));
|
||||
diff_output_to_patch(&xo.output, &pd->patch);
|
||||
git_xdiff_init(&xo, opts);
|
||||
|
||||
error = diff_patch_from_blobs(
|
||||
pd, &xo, old_blob, old_path, new_blob, new_path, opts);
|
||||
|
||||
if (!error)
|
||||
*out = (git_patch *)pd;
|
||||
else
|
||||
git_patch_free((git_patch *)pd);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int diff_patch_from_blob_and_buffer(
|
||||
diff_patch_with_delta *pd,
|
||||
git_xdiff_output *xo,
|
||||
const git_blob *old_blob,
|
||||
const char *old_path,
|
||||
const char *buf,
|
||||
size_t buflen,
|
||||
const char *buf_path,
|
||||
const git_diff_options *opts)
|
||||
{
|
||||
int error = 0;
|
||||
git_repository *repo =
|
||||
old_blob ? git_object_owner((const git_object *)old_blob) : NULL;
|
||||
|
||||
GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options");
|
||||
|
||||
pd->patch.delta = &pd->delta;
|
||||
|
||||
if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) {
|
||||
pd->delta.old_file.path = buf_path;
|
||||
pd->delta.new_file.path = old_path;
|
||||
|
||||
if (!(error = git_diff_file_content__init_from_raw(
|
||||
&pd->patch.ofile, repo, opts, buf, buflen, &pd->delta.old_file)))
|
||||
error = git_diff_file_content__init_from_blob(
|
||||
&pd->patch.nfile, repo, opts, old_blob, &pd->delta.new_file);
|
||||
} else {
|
||||
pd->delta.old_file.path = old_path;
|
||||
pd->delta.new_file.path = buf_path;
|
||||
|
||||
if (!(error = git_diff_file_content__init_from_blob(
|
||||
&pd->patch.ofile, repo, opts, old_blob, &pd->delta.old_file)))
|
||||
error = git_diff_file_content__init_from_raw(
|
||||
&pd->patch.nfile, repo, opts, buf, buflen, &pd->delta.new_file);
|
||||
}
|
||||
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
return diff_single_generate(pd, xo);
|
||||
git_diff_file_content_src osrc =
|
||||
GIT_DIFF_FILE_CONTENT_SRC__BLOB(old_blob, old_path);
|
||||
git_diff_file_content_src nsrc =
|
||||
GIT_DIFF_FILE_CONTENT_SRC__BLOB(new_blob, new_path);
|
||||
return patch_from_sources(out, &osrc, &nsrc, opts);
|
||||
}
|
||||
|
||||
int git_diff_blob_to_buffer(
|
||||
@ -521,27 +510,12 @@ int git_diff_blob_to_buffer(
|
||||
git_diff_line_cb data_cb,
|
||||
void *payload)
|
||||
{
|
||||
int error = 0;
|
||||
diff_patch_with_delta pd;
|
||||
git_xdiff_output xo;
|
||||
|
||||
memset(&xo, 0, sizeof(xo));
|
||||
diff_output_init(
|
||||
&xo.output, opts, file_cb, hunk_cb, data_cb, payload);
|
||||
git_xdiff_init(&xo, opts);
|
||||
|
||||
if (!old_path && buf_path)
|
||||
old_path = buf_path;
|
||||
else if (!buf_path && old_path)
|
||||
buf_path = old_path;
|
||||
|
||||
memset(&pd, 0, sizeof(pd));
|
||||
error = diff_patch_from_blob_and_buffer(
|
||||
&pd, &xo, old_blob, old_path, buf, buflen, buf_path, opts);
|
||||
|
||||
git_patch_free(&pd.patch);
|
||||
|
||||
return error;
|
||||
git_diff_file_content_src osrc =
|
||||
GIT_DIFF_FILE_CONTENT_SRC__BLOB(old_blob, old_path);
|
||||
git_diff_file_content_src nsrc =
|
||||
GIT_DIFF_FILE_CONTENT_SRC__BUF(buf, buflen, buf_path);
|
||||
return diff_from_sources(
|
||||
&osrc, &nsrc, opts, file_cb, hunk_cb, data_cb, payload);
|
||||
}
|
||||
|
||||
int git_patch_from_blob_and_buffer(
|
||||
@ -553,29 +527,49 @@ int git_patch_from_blob_and_buffer(
|
||||
const char *buf_path,
|
||||
const git_diff_options *opts)
|
||||
{
|
||||
int error = 0;
|
||||
diff_patch_with_delta *pd;
|
||||
git_xdiff_output xo;
|
||||
git_diff_file_content_src osrc =
|
||||
GIT_DIFF_FILE_CONTENT_SRC__BLOB(old_blob, old_path);
|
||||
git_diff_file_content_src nsrc =
|
||||
GIT_DIFF_FILE_CONTENT_SRC__BUF(buf, buflen, buf_path);
|
||||
return patch_from_sources(out, &osrc, &nsrc, opts);
|
||||
}
|
||||
|
||||
assert(out);
|
||||
*out = NULL;
|
||||
int git_diff_buffers(
|
||||
const void *old_buf,
|
||||
size_t old_len,
|
||||
const char *old_path,
|
||||
const void *new_buf,
|
||||
size_t new_len,
|
||||
const char *new_path,
|
||||
const git_diff_options *opts,
|
||||
git_diff_file_cb file_cb,
|
||||
git_diff_hunk_cb hunk_cb,
|
||||
git_diff_line_cb data_cb,
|
||||
void *payload)
|
||||
{
|
||||
git_diff_file_content_src osrc =
|
||||
GIT_DIFF_FILE_CONTENT_SRC__BUF(old_buf, old_len, old_path);
|
||||
git_diff_file_content_src nsrc =
|
||||
GIT_DIFF_FILE_CONTENT_SRC__BUF(new_buf, new_len, new_path);
|
||||
return diff_from_sources(
|
||||
&osrc, &nsrc, opts, file_cb, hunk_cb, data_cb, payload);
|
||||
}
|
||||
|
||||
if (diff_patch_with_delta_alloc(&pd, &old_path, &buf_path) < 0)
|
||||
return -1;
|
||||
|
||||
memset(&xo, 0, sizeof(xo));
|
||||
diff_output_to_patch(&xo.output, &pd->patch);
|
||||
git_xdiff_init(&xo, opts);
|
||||
|
||||
error = diff_patch_from_blob_and_buffer(
|
||||
pd, &xo, old_blob, old_path, buf, buflen, buf_path, opts);
|
||||
|
||||
if (!error)
|
||||
*out = (git_patch *)pd;
|
||||
else
|
||||
git_patch_free((git_patch *)pd);
|
||||
|
||||
return error;
|
||||
int git_patch_from_buffers(
|
||||
git_patch **out,
|
||||
const void *old_buf,
|
||||
size_t old_len,
|
||||
const char *old_path,
|
||||
const char *new_buf,
|
||||
size_t new_len,
|
||||
const char *new_path,
|
||||
const git_diff_options *opts)
|
||||
{
|
||||
git_diff_file_content_src osrc =
|
||||
GIT_DIFF_FILE_CONTENT_SRC__BUF(old_buf, old_len, old_path);
|
||||
git_diff_file_content_src nsrc =
|
||||
GIT_DIFF_FILE_CONTENT_SRC__BUF(new_buf, new_len, new_path);
|
||||
return patch_from_sources(out, &osrc, &nsrc, opts);
|
||||
}
|
||||
|
||||
int git_patch_from_diff(
|
||||
|
@ -303,3 +303,18 @@ void test_blame_simple__can_restrict_to_newish_commits(void)
|
||||
check_blame_hunk_index(g_repo, g_blame, 0, 1, 1, 1, "be3563a", "branch_file.txt");
|
||||
check_blame_hunk_index(g_repo, g_blame, 1, 2, 1, 0, "a65fedf", "branch_file.txt");
|
||||
}
|
||||
|
||||
void test_blame_simple__can_restrict_to_first_parent_commits(void)
|
||||
{
|
||||
git_blame_options opts = GIT_BLAME_OPTIONS_INIT;
|
||||
opts.flags |= GIT_BLAME_FIRST_PARENT;
|
||||
|
||||
cl_git_pass(git_repository_open(&g_repo, cl_fixture("blametest.git")));
|
||||
|
||||
cl_git_pass(git_blame_file(&g_blame, g_repo, "b.txt", &opts));
|
||||
cl_assert_equal_i(4, git_blame_get_hunk_count(g_blame));
|
||||
check_blame_hunk_index(g_repo, g_blame, 0, 1, 4, 0, "da237394", "b.txt");
|
||||
check_blame_hunk_index(g_repo, g_blame, 1, 5, 1, 1, "b99f7ac0", "b.txt");
|
||||
check_blame_hunk_index(g_repo, g_blame, 2, 6, 5, 0, "63d671eb", "b.txt");
|
||||
check_blame_hunk_index(g_repo, g_blame, 3, 11, 5, 0, "bc7c5ac2", "b.txt");
|
||||
}
|
||||
|
@ -51,6 +51,20 @@ void test_diff_blob__cleanup(void)
|
||||
cl_git_sandbox_cleanup();
|
||||
}
|
||||
|
||||
static void assert_one_modified(
|
||||
int hunks, int lines, int ctxt, int adds, int dels, diff_expects *exp)
|
||||
{
|
||||
cl_assert_equal_i(1, exp->files);
|
||||
cl_assert_equal_i(1, exp->file_status[GIT_DELTA_MODIFIED]);
|
||||
cl_assert_equal_i(0, exp->files_binary);
|
||||
|
||||
cl_assert_equal_i(hunks, exp->hunks);
|
||||
cl_assert_equal_i(lines, exp->lines);
|
||||
cl_assert_equal_i(ctxt, exp->line_ctxt);
|
||||
cl_assert_equal_i(adds, exp->line_adds);
|
||||
cl_assert_equal_i(dels, exp->line_dels);
|
||||
}
|
||||
|
||||
void test_diff_blob__can_compare_text_blobs(void)
|
||||
{
|
||||
git_blob *a, *b, *c;
|
||||
@ -71,79 +85,81 @@ void test_diff_blob__can_compare_text_blobs(void)
|
||||
/* Doing the equivalent of a `git diff -U1` on these files */
|
||||
|
||||
/* diff on tests/resources/attr/root_test1 */
|
||||
memset(&expected, 0, sizeof(expected));
|
||||
cl_git_pass(git_diff_blobs(
|
||||
a, NULL, b, NULL, &opts,
|
||||
diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
|
||||
assert_one_modified(1, 6, 1, 5, 0, &expected);
|
||||
|
||||
cl_assert_equal_i(1, expected.files);
|
||||
cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]);
|
||||
cl_assert_equal_i(0, expected.files_binary);
|
||||
|
||||
cl_assert_equal_i(1, expected.hunks);
|
||||
cl_assert_equal_i(6, expected.lines);
|
||||
cl_assert_equal_i(1, expected.line_ctxt);
|
||||
cl_assert_equal_i(5, expected.line_adds);
|
||||
cl_assert_equal_i(0, expected.line_dels);
|
||||
/* same diff but use direct buffers */
|
||||
memset(&expected, 0, sizeof(expected));
|
||||
cl_git_pass(git_diff_buffers(
|
||||
git_blob_rawcontent(a), (size_t)git_blob_rawsize(a), NULL,
|
||||
git_blob_rawcontent(b), (size_t)git_blob_rawsize(b), NULL, &opts,
|
||||
diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
|
||||
assert_one_modified(1, 6, 1, 5, 0, &expected);
|
||||
|
||||
/* diff on tests/resources/attr/root_test2 */
|
||||
memset(&expected, 0, sizeof(expected));
|
||||
cl_git_pass(git_diff_blobs(
|
||||
b, NULL, c, NULL, &opts,
|
||||
diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
|
||||
|
||||
cl_assert_equal_i(1, expected.files);
|
||||
cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]);
|
||||
cl_assert_equal_i(0, expected.files_binary);
|
||||
|
||||
cl_assert_equal_i(1, expected.hunks);
|
||||
cl_assert_equal_i(15, expected.lines);
|
||||
cl_assert_equal_i(3, expected.line_ctxt);
|
||||
cl_assert_equal_i(9, expected.line_adds);
|
||||
cl_assert_equal_i(3, expected.line_dels);
|
||||
assert_one_modified(1, 15, 3, 9, 3, &expected);
|
||||
|
||||
/* diff on tests/resources/attr/root_test3 */
|
||||
memset(&expected, 0, sizeof(expected));
|
||||
cl_git_pass(git_diff_blobs(
|
||||
a, NULL, c, NULL, &opts,
|
||||
diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
|
||||
|
||||
cl_assert_equal_i(1, expected.files);
|
||||
cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]);
|
||||
cl_assert_equal_i(0, expected.files_binary);
|
||||
|
||||
cl_assert_equal_i(1, expected.hunks);
|
||||
cl_assert_equal_i(13, expected.lines);
|
||||
cl_assert_equal_i(0, expected.line_ctxt);
|
||||
cl_assert_equal_i(12, expected.line_adds);
|
||||
cl_assert_equal_i(1, expected.line_dels);
|
||||
assert_one_modified(1, 13, 0, 12, 1, &expected);
|
||||
|
||||
memset(&expected, 0, sizeof(expected));
|
||||
cl_git_pass(git_diff_blobs(
|
||||
c, NULL, d, NULL, &opts,
|
||||
diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
|
||||
|
||||
cl_assert_equal_i(1, expected.files);
|
||||
cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]);
|
||||
cl_assert_equal_i(0, expected.files_binary);
|
||||
|
||||
cl_assert_equal_i(2, expected.hunks);
|
||||
cl_assert_equal_i(14, expected.lines);
|
||||
cl_assert_equal_i(4, expected.line_ctxt);
|
||||
cl_assert_equal_i(6, expected.line_adds);
|
||||
cl_assert_equal_i(4, expected.line_dels);
|
||||
assert_one_modified(2, 14, 4, 6, 4, &expected);
|
||||
|
||||
git_blob_free(a);
|
||||
git_blob_free(b);
|
||||
git_blob_free(c);
|
||||
}
|
||||
|
||||
static void assert_patch_matches_blobs(
|
||||
git_patch *p, git_blob *a, git_blob *b,
|
||||
int hunks, int l0, int l1, int ctxt, int adds, int dels)
|
||||
{
|
||||
const git_diff_delta *delta;
|
||||
size_t tc, ta, td;
|
||||
|
||||
cl_assert(p != NULL);
|
||||
|
||||
delta = git_patch_get_delta(p);
|
||||
cl_assert(delta != NULL);
|
||||
|
||||
cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status);
|
||||
cl_assert(git_oid_equal(git_blob_id(a), &delta->old_file.id));
|
||||
cl_assert_equal_sz(git_blob_rawsize(a), delta->old_file.size);
|
||||
cl_assert(git_oid_equal(git_blob_id(b), &delta->new_file.id));
|
||||
cl_assert_equal_sz(git_blob_rawsize(b), delta->new_file.size);
|
||||
|
||||
cl_assert_equal_i(hunks, (int)git_patch_num_hunks(p));
|
||||
|
||||
if (hunks > 0)
|
||||
cl_assert_equal_i(l0, git_patch_num_lines_in_hunk(p, 0));
|
||||
if (hunks > 1)
|
||||
cl_assert_equal_i(l1, git_patch_num_lines_in_hunk(p, 1));
|
||||
|
||||
cl_git_pass(git_patch_line_stats(&tc, &ta, &td, p));
|
||||
cl_assert_equal_i(ctxt, (int)tc);
|
||||
cl_assert_equal_i(adds, (int)ta);
|
||||
cl_assert_equal_i(dels, (int)td);
|
||||
}
|
||||
|
||||
void test_diff_blob__can_compare_text_blobs_with_patch(void)
|
||||
{
|
||||
git_blob *a, *b, *c;
|
||||
git_oid a_oid, b_oid, c_oid;
|
||||
git_patch *p;
|
||||
const git_diff_delta *delta;
|
||||
size_t tc, ta, td;
|
||||
|
||||
/* tests/resources/attr/root_test1 */
|
||||
cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
|
||||
@ -161,92 +177,22 @@ void test_diff_blob__can_compare_text_blobs_with_patch(void)
|
||||
|
||||
/* diff on tests/resources/attr/root_test1 */
|
||||
cl_git_pass(git_patch_from_blobs(&p, a, NULL, b, NULL, &opts));
|
||||
|
||||
cl_assert(p != NULL);
|
||||
|
||||
delta = git_patch_get_delta(p);
|
||||
cl_assert(delta != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status);
|
||||
cl_assert(git_oid_equal(git_blob_id(a), &delta->old_file.id));
|
||||
cl_assert_equal_sz(git_blob_rawsize(a), delta->old_file.size);
|
||||
cl_assert(git_oid_equal(git_blob_id(b), &delta->new_file.id));
|
||||
cl_assert_equal_sz(git_blob_rawsize(b), delta->new_file.size);
|
||||
|
||||
cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
|
||||
cl_assert_equal_i(6, git_patch_num_lines_in_hunk(p, 0));
|
||||
|
||||
cl_git_pass(git_patch_line_stats(&tc, &ta, &td, p));
|
||||
cl_assert_equal_i(1, (int)tc);
|
||||
cl_assert_equal_i(5, (int)ta);
|
||||
cl_assert_equal_i(0, (int)td);
|
||||
|
||||
assert_patch_matches_blobs(p, a, b, 1, 6, 0, 1, 5, 0);
|
||||
git_patch_free(p);
|
||||
|
||||
/* diff on tests/resources/attr/root_test2 */
|
||||
cl_git_pass(git_patch_from_blobs(&p, b, NULL, c, NULL, &opts));
|
||||
|
||||
cl_assert(p != NULL);
|
||||
|
||||
delta = git_patch_get_delta(p);
|
||||
cl_assert(delta != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status);
|
||||
cl_assert(git_oid_equal(git_blob_id(b), &delta->old_file.id));
|
||||
cl_assert_equal_sz(git_blob_rawsize(b), delta->old_file.size);
|
||||
cl_assert(git_oid_equal(git_blob_id(c), &delta->new_file.id));
|
||||
cl_assert_equal_sz(git_blob_rawsize(c), delta->new_file.size);
|
||||
|
||||
cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
|
||||
cl_assert_equal_i(15, git_patch_num_lines_in_hunk(p, 0));
|
||||
|
||||
cl_git_pass(git_patch_line_stats(&tc, &ta, &td, p));
|
||||
cl_assert_equal_i(3, (int)tc);
|
||||
cl_assert_equal_i(9, (int)ta);
|
||||
cl_assert_equal_i(3, (int)td);
|
||||
|
||||
assert_patch_matches_blobs(p, b, c, 1, 15, 0, 3, 9, 3);
|
||||
git_patch_free(p);
|
||||
|
||||
/* diff on tests/resources/attr/root_test3 */
|
||||
cl_git_pass(git_patch_from_blobs(&p, a, NULL, c, NULL, &opts));
|
||||
|
||||
cl_assert(p != NULL);
|
||||
|
||||
delta = git_patch_get_delta(p);
|
||||
cl_assert(delta != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status);
|
||||
cl_assert(git_oid_equal(git_blob_id(a), &delta->old_file.id));
|
||||
cl_assert_equal_sz(git_blob_rawsize(a), delta->old_file.size);
|
||||
cl_assert(git_oid_equal(git_blob_id(c), &delta->new_file.id));
|
||||
cl_assert_equal_sz(git_blob_rawsize(c), delta->new_file.size);
|
||||
|
||||
cl_git_pass(git_patch_line_stats(&tc, &ta, &td, p));
|
||||
cl_assert_equal_i(0, (int)tc);
|
||||
cl_assert_equal_i(12, (int)ta);
|
||||
cl_assert_equal_i(1, (int)td);
|
||||
|
||||
assert_patch_matches_blobs(p, a, c, 1, 13, 0, 0, 12, 1);
|
||||
git_patch_free(p);
|
||||
|
||||
/* one more */
|
||||
cl_git_pass(git_patch_from_blobs(&p, c, NULL, d, NULL, &opts));
|
||||
|
||||
cl_assert(p != NULL);
|
||||
|
||||
delta = git_patch_get_delta(p);
|
||||
cl_assert(delta != NULL);
|
||||
cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status);
|
||||
cl_assert(git_oid_equal(git_blob_id(c), &delta->old_file.id));
|
||||
cl_assert_equal_sz(git_blob_rawsize(c), delta->old_file.size);
|
||||
cl_assert(git_oid_equal(git_blob_id(d), &delta->new_file.id));
|
||||
cl_assert_equal_sz(git_blob_rawsize(d), delta->new_file.size);
|
||||
|
||||
cl_assert_equal_i(2, (int)git_patch_num_hunks(p));
|
||||
cl_assert_equal_i(5, git_patch_num_lines_in_hunk(p, 0));
|
||||
cl_assert_equal_i(9, git_patch_num_lines_in_hunk(p, 1));
|
||||
|
||||
cl_git_pass(git_patch_line_stats(&tc, &ta, &td, p));
|
||||
cl_assert_equal_i(4, (int)tc);
|
||||
cl_assert_equal_i(6, (int)ta);
|
||||
cl_assert_equal_i(4, (int)td);
|
||||
|
||||
assert_patch_matches_blobs(p, c, d, 2, 5, 9, 4, 6, 4);
|
||||
git_patch_free(p);
|
||||
|
||||
git_blob_free(a);
|
||||
@ -656,14 +602,7 @@ void test_diff_blob__can_compare_blob_to_buffer(void)
|
||||
|
||||
/* diff from blob a to content of b */
|
||||
quick_diff_blob_to_str(a, NULL, b_content, 0, NULL);
|
||||
cl_assert_equal_i(1, expected.files);
|
||||
cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]);
|
||||
cl_assert_equal_i(0, expected.files_binary);
|
||||
cl_assert_equal_i(1, expected.hunks);
|
||||
cl_assert_equal_i(6, expected.lines);
|
||||
cl_assert_equal_i(1, expected.line_ctxt);
|
||||
cl_assert_equal_i(5, expected.line_adds);
|
||||
cl_assert_equal_i(0, expected.line_dels);
|
||||
assert_one_modified(1, 6, 1, 5, 0, &expected);
|
||||
|
||||
/* diff from blob a to content of a */
|
||||
opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;
|
||||
@ -910,14 +849,7 @@ void test_diff_blob__using_path_and_attributes(void)
|
||||
changed = "Hello from the root\nMore lines\nAnd more\nGo here\n";
|
||||
|
||||
quick_diff_blob_to_str(nonbin, NULL, changed, 0, NULL);
|
||||
cl_assert_equal_i(1, expected.files);
|
||||
cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]);
|
||||
cl_assert_equal_i(0, expected.files_binary);
|
||||
cl_assert_equal_i(1, expected.hunks);
|
||||
cl_assert_equal_i(3, expected.lines);
|
||||
cl_assert_equal_i(0, expected.line_ctxt);
|
||||
cl_assert_equal_i(3, expected.line_adds);
|
||||
cl_assert_equal_i(0, expected.line_dels);
|
||||
assert_one_modified(1, 3, 0, 3, 0, &expected);
|
||||
|
||||
quick_diff_blob_to_str(nonbin, "foo/bar.binary", changed, 0, NULL);
|
||||
cl_assert_equal_i(1, expected.files);
|
||||
@ -925,29 +857,12 @@ void test_diff_blob__using_path_and_attributes(void)
|
||||
cl_assert_equal_i(1, expected.files_binary);
|
||||
cl_assert_equal_i(0, expected.hunks);
|
||||
cl_assert_equal_i(0, expected.lines);
|
||||
cl_assert_equal_i(0, expected.line_ctxt);
|
||||
cl_assert_equal_i(0, expected.line_adds);
|
||||
cl_assert_equal_i(0, expected.line_dels);
|
||||
|
||||
quick_diff_blob_to_str(nonbin, "foo/bar.textary", changed, 0, NULL);
|
||||
cl_assert_equal_i(1, expected.files);
|
||||
cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]);
|
||||
cl_assert_equal_i(0, expected.files_binary);
|
||||
cl_assert_equal_i(1, expected.hunks);
|
||||
cl_assert_equal_i(3, expected.lines);
|
||||
cl_assert_equal_i(0, expected.line_ctxt);
|
||||
cl_assert_equal_i(3, expected.line_adds);
|
||||
cl_assert_equal_i(0, expected.line_dels);
|
||||
assert_one_modified(1, 3, 0, 3, 0, &expected);
|
||||
|
||||
quick_diff_blob_to_str(nonbin, "foo/bar.alphary", changed, 0, NULL);
|
||||
cl_assert_equal_i(1, expected.files);
|
||||
cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]);
|
||||
cl_assert_equal_i(0, expected.files_binary);
|
||||
cl_assert_equal_i(1, expected.hunks);
|
||||
cl_assert_equal_i(3, expected.lines);
|
||||
cl_assert_equal_i(0, expected.line_ctxt);
|
||||
cl_assert_equal_i(3, expected.line_adds);
|
||||
cl_assert_equal_i(0, expected.line_dels);
|
||||
assert_one_modified(1, 3, 0, 3, 0, &expected);
|
||||
|
||||
cl_git_pass(git_patch_from_blob_and_buffer(
|
||||
&p, nonbin, "zzz.normal", changed, strlen(changed), NULL, &opts));
|
||||
@ -1066,3 +981,28 @@ void test_diff_blob__using_path_and_attributes(void)
|
||||
git_blob_free(nonbin);
|
||||
git_blob_free(bin);
|
||||
}
|
||||
|
||||
void test_diff_blob__can_compare_buffer_to_buffer(void)
|
||||
{
|
||||
const char *a = "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\n";
|
||||
const char *b = "a\nB\nc\nd\nE\nF\nh\nj\nk\n";
|
||||
|
||||
opts.interhunk_lines = 0;
|
||||
opts.context_lines = 0;
|
||||
|
||||
memset(&expected, 0, sizeof(expected));
|
||||
|
||||
cl_git_pass(git_diff_buffers(
|
||||
a, strlen(a), NULL, b, strlen(b), NULL,
|
||||
&opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
|
||||
assert_one_modified(4, 9, 0, 4, 5, &expected);
|
||||
|
||||
opts.flags ^= GIT_DIFF_REVERSE;
|
||||
|
||||
memset(&expected, 0, sizeof(expected));
|
||||
|
||||
cl_git_pass(git_diff_buffers(
|
||||
a, strlen(a), NULL, b, strlen(b), NULL,
|
||||
&opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
|
||||
assert_one_modified(4, 9, 0, 5, 4, &expected);
|
||||
}
|
||||
|
@ -67,6 +67,25 @@ void test_refs_branches_create__can_force_create_over_an_existing_branch(void)
|
||||
cl_assert_equal_s("refs/heads/br2", git_reference_name(branch));
|
||||
}
|
||||
|
||||
void test_refs_branches_create__cannot_force_create_over_current_branch(void)
|
||||
{
|
||||
const git_oid *oid;
|
||||
git_reference *branch2;
|
||||
retrieve_known_commit(&target, repo);
|
||||
|
||||
cl_git_pass(git_branch_lookup(&branch2, repo, "master", GIT_BRANCH_LOCAL));
|
||||
cl_assert_equal_s("refs/heads/master", git_reference_name(branch2));
|
||||
cl_assert_equal_i(true, git_branch_is_head(branch2));
|
||||
oid = git_reference_target(branch2);
|
||||
|
||||
cl_git_fail_with(-1, git_branch_create(&branch, repo, "master", target, 1, NULL, NULL));
|
||||
branch = NULL;
|
||||
cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL));
|
||||
cl_assert_equal_s("refs/heads/master", git_reference_name(branch));
|
||||
cl_git_pass(git_oid_cmp(git_reference_target(branch), oid));
|
||||
git_reference_free(branch2);
|
||||
}
|
||||
|
||||
void test_refs_branches_create__creating_a_branch_with_an_invalid_name_returns_EINVALIDSPEC(void)
|
||||
{
|
||||
retrieve_known_commit(&target, repo);
|
||||
|
Loading…
Reference in New Issue
Block a user