Merge branch 'tg/range-diff-output-update'
"git range-diff" output has been tweaked for easier identification of which part of what file the patch shown is about. * tg/range-diff-output-update: range-diff: add headers to the outer hunk header range-diff: add filename to inner diff range-diff: add section header instead of diff header range-diff: suppress line count in outer diff range-diff: don't remove funcname from inner diff range-diff: split lines manually range-diff: fix function parameter indentation apply: make parse_git_diff_header public apply: only pass required data to gitdiff_* functions apply: only pass required data to find_name_* apply: only pass required data to check_header_line apply: only pass required data to git_header_name apply: only pass required data to skip_tree_prefix apply: replace marc.info link with public-inbox
This commit is contained in:
commit
43ba21cb57
186
apply.c
186
apply.c
@ -22,6 +22,12 @@
|
|||||||
#include "rerere.h"
|
#include "rerere.h"
|
||||||
#include "apply.h"
|
#include "apply.h"
|
||||||
|
|
||||||
|
struct gitdiff_data {
|
||||||
|
struct strbuf *root;
|
||||||
|
int linenr;
|
||||||
|
int p_value;
|
||||||
|
};
|
||||||
|
|
||||||
static void git_apply_config(void)
|
static void git_apply_config(void)
|
||||||
{
|
{
|
||||||
git_config_get_string_const("apply.whitespace", &apply_default_whitespace);
|
git_config_get_string_const("apply.whitespace", &apply_default_whitespace);
|
||||||
@ -201,40 +207,6 @@ struct fragment {
|
|||||||
#define BINARY_DELTA_DEFLATED 1
|
#define BINARY_DELTA_DEFLATED 1
|
||||||
#define BINARY_LITERAL_DEFLATED 2
|
#define BINARY_LITERAL_DEFLATED 2
|
||||||
|
|
||||||
/*
|
|
||||||
* This represents a "patch" to a file, both metainfo changes
|
|
||||||
* such as creation/deletion, filemode and content changes represented
|
|
||||||
* as a series of fragments.
|
|
||||||
*/
|
|
||||||
struct patch {
|
|
||||||
char *new_name, *old_name, *def_name;
|
|
||||||
unsigned int old_mode, new_mode;
|
|
||||||
int is_new, is_delete; /* -1 = unknown, 0 = false, 1 = true */
|
|
||||||
int rejected;
|
|
||||||
unsigned ws_rule;
|
|
||||||
int lines_added, lines_deleted;
|
|
||||||
int score;
|
|
||||||
int extension_linenr; /* first line specifying delete/new/rename/copy */
|
|
||||||
unsigned int is_toplevel_relative:1;
|
|
||||||
unsigned int inaccurate_eof:1;
|
|
||||||
unsigned int is_binary:1;
|
|
||||||
unsigned int is_copy:1;
|
|
||||||
unsigned int is_rename:1;
|
|
||||||
unsigned int recount:1;
|
|
||||||
unsigned int conflicted_threeway:1;
|
|
||||||
unsigned int direct_to_threeway:1;
|
|
||||||
unsigned int crlf_in_old:1;
|
|
||||||
struct fragment *fragments;
|
|
||||||
char *result;
|
|
||||||
size_t resultsize;
|
|
||||||
char old_oid_prefix[GIT_MAX_HEXSZ + 1];
|
|
||||||
char new_oid_prefix[GIT_MAX_HEXSZ + 1];
|
|
||||||
struct patch *next;
|
|
||||||
|
|
||||||
/* three-way fallback result */
|
|
||||||
struct object_id threeway_stage[3];
|
|
||||||
};
|
|
||||||
|
|
||||||
static void free_fragment_list(struct fragment *list)
|
static void free_fragment_list(struct fragment *list)
|
||||||
{
|
{
|
||||||
while (list) {
|
while (list) {
|
||||||
@ -469,7 +441,7 @@ static char *squash_slash(char *name)
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *find_name_gnu(struct apply_state *state,
|
static char *find_name_gnu(struct strbuf *root,
|
||||||
const char *line,
|
const char *line,
|
||||||
int p_value)
|
int p_value)
|
||||||
{
|
{
|
||||||
@ -478,7 +450,7 @@ static char *find_name_gnu(struct apply_state *state,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Proposed "new-style" GNU patch/diff format; see
|
* Proposed "new-style" GNU patch/diff format; see
|
||||||
* http://marc.info/?l=git&m=112927316408690&w=2
|
* https://public-inbox.org/git/7vll0wvb2a.fsf@assigned-by-dhcp.cox.net/
|
||||||
*/
|
*/
|
||||||
if (unquote_c_style(&name, line, NULL)) {
|
if (unquote_c_style(&name, line, NULL)) {
|
||||||
strbuf_release(&name);
|
strbuf_release(&name);
|
||||||
@ -495,8 +467,8 @@ static char *find_name_gnu(struct apply_state *state,
|
|||||||
}
|
}
|
||||||
|
|
||||||
strbuf_remove(&name, 0, cp - name.buf);
|
strbuf_remove(&name, 0, cp - name.buf);
|
||||||
if (state->root.len)
|
if (root->len)
|
||||||
strbuf_insert(&name, 0, state->root.buf, state->root.len);
|
strbuf_insert(&name, 0, root->buf, root->len);
|
||||||
return squash_slash(strbuf_detach(&name, NULL));
|
return squash_slash(strbuf_detach(&name, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -659,7 +631,7 @@ static size_t diff_timestamp_len(const char *line, size_t len)
|
|||||||
return line + len - end;
|
return line + len - end;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *find_name_common(struct apply_state *state,
|
static char *find_name_common(struct strbuf *root,
|
||||||
const char *line,
|
const char *line,
|
||||||
const char *def,
|
const char *def,
|
||||||
int p_value,
|
int p_value,
|
||||||
@ -702,30 +674,30 @@ static char *find_name_common(struct apply_state *state,
|
|||||||
return squash_slash(xstrdup(def));
|
return squash_slash(xstrdup(def));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->root.len) {
|
if (root->len) {
|
||||||
char *ret = xstrfmt("%s%.*s", state->root.buf, len, start);
|
char *ret = xstrfmt("%s%.*s", root->buf, len, start);
|
||||||
return squash_slash(ret);
|
return squash_slash(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return squash_slash(xmemdupz(start, len));
|
return squash_slash(xmemdupz(start, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *find_name(struct apply_state *state,
|
static char *find_name(struct strbuf *root,
|
||||||
const char *line,
|
const char *line,
|
||||||
char *def,
|
char *def,
|
||||||
int p_value,
|
int p_value,
|
||||||
int terminate)
|
int terminate)
|
||||||
{
|
{
|
||||||
if (*line == '"') {
|
if (*line == '"') {
|
||||||
char *name = find_name_gnu(state, line, p_value);
|
char *name = find_name_gnu(root, line, p_value);
|
||||||
if (name)
|
if (name)
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return find_name_common(state, line, def, p_value, NULL, terminate);
|
return find_name_common(root, line, def, p_value, NULL, terminate);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *find_name_traditional(struct apply_state *state,
|
static char *find_name_traditional(struct strbuf *root,
|
||||||
const char *line,
|
const char *line,
|
||||||
char *def,
|
char *def,
|
||||||
int p_value)
|
int p_value)
|
||||||
@ -734,7 +706,7 @@ static char *find_name_traditional(struct apply_state *state,
|
|||||||
size_t date_len;
|
size_t date_len;
|
||||||
|
|
||||||
if (*line == '"') {
|
if (*line == '"') {
|
||||||
char *name = find_name_gnu(state, line, p_value);
|
char *name = find_name_gnu(root, line, p_value);
|
||||||
if (name)
|
if (name)
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@ -742,10 +714,10 @@ static char *find_name_traditional(struct apply_state *state,
|
|||||||
len = strchrnul(line, '\n') - line;
|
len = strchrnul(line, '\n') - line;
|
||||||
date_len = diff_timestamp_len(line, len);
|
date_len = diff_timestamp_len(line, len);
|
||||||
if (!date_len)
|
if (!date_len)
|
||||||
return find_name_common(state, line, def, p_value, NULL, TERM_TAB);
|
return find_name_common(root, line, def, p_value, NULL, TERM_TAB);
|
||||||
len -= date_len;
|
len -= date_len;
|
||||||
|
|
||||||
return find_name_common(state, line, def, p_value, line + len, 0);
|
return find_name_common(root, line, def, p_value, line + len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -759,7 +731,7 @@ static int guess_p_value(struct apply_state *state, const char *nameline)
|
|||||||
|
|
||||||
if (is_dev_null(nameline))
|
if (is_dev_null(nameline))
|
||||||
return -1;
|
return -1;
|
||||||
name = find_name_traditional(state, nameline, NULL, 0);
|
name = find_name_traditional(&state->root, nameline, NULL, 0);
|
||||||
if (!name)
|
if (!name)
|
||||||
return -1;
|
return -1;
|
||||||
cp = strchr(name, '/');
|
cp = strchr(name, '/');
|
||||||
@ -883,17 +855,17 @@ static int parse_traditional_patch(struct apply_state *state,
|
|||||||
if (is_dev_null(first)) {
|
if (is_dev_null(first)) {
|
||||||
patch->is_new = 1;
|
patch->is_new = 1;
|
||||||
patch->is_delete = 0;
|
patch->is_delete = 0;
|
||||||
name = find_name_traditional(state, second, NULL, state->p_value);
|
name = find_name_traditional(&state->root, second, NULL, state->p_value);
|
||||||
patch->new_name = name;
|
patch->new_name = name;
|
||||||
} else if (is_dev_null(second)) {
|
} else if (is_dev_null(second)) {
|
||||||
patch->is_new = 0;
|
patch->is_new = 0;
|
||||||
patch->is_delete = 1;
|
patch->is_delete = 1;
|
||||||
name = find_name_traditional(state, first, NULL, state->p_value);
|
name = find_name_traditional(&state->root, first, NULL, state->p_value);
|
||||||
patch->old_name = name;
|
patch->old_name = name;
|
||||||
} else {
|
} else {
|
||||||
char *first_name;
|
char *first_name;
|
||||||
first_name = find_name_traditional(state, first, NULL, state->p_value);
|
first_name = find_name_traditional(&state->root, first, NULL, state->p_value);
|
||||||
name = find_name_traditional(state, second, first_name, state->p_value);
|
name = find_name_traditional(&state->root, second, first_name, state->p_value);
|
||||||
free(first_name);
|
free(first_name);
|
||||||
if (has_epoch_timestamp(first)) {
|
if (has_epoch_timestamp(first)) {
|
||||||
patch->is_new = 1;
|
patch->is_new = 1;
|
||||||
@ -914,7 +886,7 @@ static int parse_traditional_patch(struct apply_state *state,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gitdiff_hdrend(struct apply_state *state,
|
static int gitdiff_hdrend(struct gitdiff_data *state,
|
||||||
const char *line,
|
const char *line,
|
||||||
struct patch *patch)
|
struct patch *patch)
|
||||||
{
|
{
|
||||||
@ -933,14 +905,14 @@ static int gitdiff_hdrend(struct apply_state *state,
|
|||||||
#define DIFF_OLD_NAME 0
|
#define DIFF_OLD_NAME 0
|
||||||
#define DIFF_NEW_NAME 1
|
#define DIFF_NEW_NAME 1
|
||||||
|
|
||||||
static int gitdiff_verify_name(struct apply_state *state,
|
static int gitdiff_verify_name(struct gitdiff_data *state,
|
||||||
const char *line,
|
const char *line,
|
||||||
int isnull,
|
int isnull,
|
||||||
char **name,
|
char **name,
|
||||||
int side)
|
int side)
|
||||||
{
|
{
|
||||||
if (!*name && !isnull) {
|
if (!*name && !isnull) {
|
||||||
*name = find_name(state, line, NULL, state->p_value, TERM_TAB);
|
*name = find_name(state->root, line, NULL, state->p_value, TERM_TAB);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -949,7 +921,7 @@ static int gitdiff_verify_name(struct apply_state *state,
|
|||||||
if (isnull)
|
if (isnull)
|
||||||
return error(_("git apply: bad git-diff - expected /dev/null, got %s on line %d"),
|
return error(_("git apply: bad git-diff - expected /dev/null, got %s on line %d"),
|
||||||
*name, state->linenr);
|
*name, state->linenr);
|
||||||
another = find_name(state, line, NULL, state->p_value, TERM_TAB);
|
another = find_name(state->root, line, NULL, state->p_value, TERM_TAB);
|
||||||
if (!another || strcmp(another, *name)) {
|
if (!another || strcmp(another, *name)) {
|
||||||
free(another);
|
free(another);
|
||||||
return error((side == DIFF_NEW_NAME) ?
|
return error((side == DIFF_NEW_NAME) ?
|
||||||
@ -965,7 +937,7 @@ static int gitdiff_verify_name(struct apply_state *state,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gitdiff_oldname(struct apply_state *state,
|
static int gitdiff_oldname(struct gitdiff_data *state,
|
||||||
const char *line,
|
const char *line,
|
||||||
struct patch *patch)
|
struct patch *patch)
|
||||||
{
|
{
|
||||||
@ -974,7 +946,7 @@ static int gitdiff_oldname(struct apply_state *state,
|
|||||||
DIFF_OLD_NAME);
|
DIFF_OLD_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gitdiff_newname(struct apply_state *state,
|
static int gitdiff_newname(struct gitdiff_data *state,
|
||||||
const char *line,
|
const char *line,
|
||||||
struct patch *patch)
|
struct patch *patch)
|
||||||
{
|
{
|
||||||
@ -992,21 +964,21 @@ static int parse_mode_line(const char *line, int linenr, unsigned int *mode)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gitdiff_oldmode(struct apply_state *state,
|
static int gitdiff_oldmode(struct gitdiff_data *state,
|
||||||
const char *line,
|
const char *line,
|
||||||
struct patch *patch)
|
struct patch *patch)
|
||||||
{
|
{
|
||||||
return parse_mode_line(line, state->linenr, &patch->old_mode);
|
return parse_mode_line(line, state->linenr, &patch->old_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gitdiff_newmode(struct apply_state *state,
|
static int gitdiff_newmode(struct gitdiff_data *state,
|
||||||
const char *line,
|
const char *line,
|
||||||
struct patch *patch)
|
struct patch *patch)
|
||||||
{
|
{
|
||||||
return parse_mode_line(line, state->linenr, &patch->new_mode);
|
return parse_mode_line(line, state->linenr, &patch->new_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gitdiff_delete(struct apply_state *state,
|
static int gitdiff_delete(struct gitdiff_data *state,
|
||||||
const char *line,
|
const char *line,
|
||||||
struct patch *patch)
|
struct patch *patch)
|
||||||
{
|
{
|
||||||
@ -1016,7 +988,7 @@ static int gitdiff_delete(struct apply_state *state,
|
|||||||
return gitdiff_oldmode(state, line, patch);
|
return gitdiff_oldmode(state, line, patch);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gitdiff_newfile(struct apply_state *state,
|
static int gitdiff_newfile(struct gitdiff_data *state,
|
||||||
const char *line,
|
const char *line,
|
||||||
struct patch *patch)
|
struct patch *patch)
|
||||||
{
|
{
|
||||||
@ -1026,47 +998,47 @@ static int gitdiff_newfile(struct apply_state *state,
|
|||||||
return gitdiff_newmode(state, line, patch);
|
return gitdiff_newmode(state, line, patch);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gitdiff_copysrc(struct apply_state *state,
|
static int gitdiff_copysrc(struct gitdiff_data *state,
|
||||||
const char *line,
|
const char *line,
|
||||||
struct patch *patch)
|
struct patch *patch)
|
||||||
{
|
{
|
||||||
patch->is_copy = 1;
|
patch->is_copy = 1;
|
||||||
free(patch->old_name);
|
free(patch->old_name);
|
||||||
patch->old_name = find_name(state, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
|
patch->old_name = find_name(state->root, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gitdiff_copydst(struct apply_state *state,
|
static int gitdiff_copydst(struct gitdiff_data *state,
|
||||||
const char *line,
|
const char *line,
|
||||||
struct patch *patch)
|
struct patch *patch)
|
||||||
{
|
{
|
||||||
patch->is_copy = 1;
|
patch->is_copy = 1;
|
||||||
free(patch->new_name);
|
free(patch->new_name);
|
||||||
patch->new_name = find_name(state, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
|
patch->new_name = find_name(state->root, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gitdiff_renamesrc(struct apply_state *state,
|
static int gitdiff_renamesrc(struct gitdiff_data *state,
|
||||||
const char *line,
|
const char *line,
|
||||||
struct patch *patch)
|
struct patch *patch)
|
||||||
{
|
{
|
||||||
patch->is_rename = 1;
|
patch->is_rename = 1;
|
||||||
free(patch->old_name);
|
free(patch->old_name);
|
||||||
patch->old_name = find_name(state, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
|
patch->old_name = find_name(state->root, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gitdiff_renamedst(struct apply_state *state,
|
static int gitdiff_renamedst(struct gitdiff_data *state,
|
||||||
const char *line,
|
const char *line,
|
||||||
struct patch *patch)
|
struct patch *patch)
|
||||||
{
|
{
|
||||||
patch->is_rename = 1;
|
patch->is_rename = 1;
|
||||||
free(patch->new_name);
|
free(patch->new_name);
|
||||||
patch->new_name = find_name(state, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
|
patch->new_name = find_name(state->root, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gitdiff_similarity(struct apply_state *state,
|
static int gitdiff_similarity(struct gitdiff_data *state,
|
||||||
const char *line,
|
const char *line,
|
||||||
struct patch *patch)
|
struct patch *patch)
|
||||||
{
|
{
|
||||||
@ -1076,7 +1048,7 @@ static int gitdiff_similarity(struct apply_state *state,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gitdiff_dissimilarity(struct apply_state *state,
|
static int gitdiff_dissimilarity(struct gitdiff_data *state,
|
||||||
const char *line,
|
const char *line,
|
||||||
struct patch *patch)
|
struct patch *patch)
|
||||||
{
|
{
|
||||||
@ -1086,7 +1058,7 @@ static int gitdiff_dissimilarity(struct apply_state *state,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gitdiff_index(struct apply_state *state,
|
static int gitdiff_index(struct gitdiff_data *state,
|
||||||
const char *line,
|
const char *line,
|
||||||
struct patch *patch)
|
struct patch *patch)
|
||||||
{
|
{
|
||||||
@ -1126,7 +1098,7 @@ static int gitdiff_index(struct apply_state *state,
|
|||||||
* This is normal for a diff that doesn't change anything: we'll fall through
|
* This is normal for a diff that doesn't change anything: we'll fall through
|
||||||
* into the next diff. Tell the parser to break out.
|
* into the next diff. Tell the parser to break out.
|
||||||
*/
|
*/
|
||||||
static int gitdiff_unrecognized(struct apply_state *state,
|
static int gitdiff_unrecognized(struct gitdiff_data *state,
|
||||||
const char *line,
|
const char *line,
|
||||||
struct patch *patch)
|
struct patch *patch)
|
||||||
{
|
{
|
||||||
@ -1137,17 +1109,17 @@ static int gitdiff_unrecognized(struct apply_state *state,
|
|||||||
* Skip p_value leading components from "line"; as we do not accept
|
* Skip p_value leading components from "line"; as we do not accept
|
||||||
* absolute paths, return NULL in that case.
|
* absolute paths, return NULL in that case.
|
||||||
*/
|
*/
|
||||||
static const char *skip_tree_prefix(struct apply_state *state,
|
static const char *skip_tree_prefix(int p_value,
|
||||||
const char *line,
|
const char *line,
|
||||||
int llen)
|
int llen)
|
||||||
{
|
{
|
||||||
int nslash;
|
int nslash;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!state->p_value)
|
if (!p_value)
|
||||||
return (llen && line[0] == '/') ? NULL : line;
|
return (llen && line[0] == '/') ? NULL : line;
|
||||||
|
|
||||||
nslash = state->p_value;
|
nslash = p_value;
|
||||||
for (i = 0; i < llen; i++) {
|
for (i = 0; i < llen; i++) {
|
||||||
int ch = line[i];
|
int ch = line[i];
|
||||||
if (ch == '/' && --nslash <= 0)
|
if (ch == '/' && --nslash <= 0)
|
||||||
@ -1164,7 +1136,7 @@ static const char *skip_tree_prefix(struct apply_state *state,
|
|||||||
* creation or deletion of an empty file. In any of these cases,
|
* creation or deletion of an empty file. In any of these cases,
|
||||||
* both sides are the same name under a/ and b/ respectively.
|
* both sides are the same name under a/ and b/ respectively.
|
||||||
*/
|
*/
|
||||||
static char *git_header_name(struct apply_state *state,
|
static char *git_header_name(int p_value,
|
||||||
const char *line,
|
const char *line,
|
||||||
int llen)
|
int llen)
|
||||||
{
|
{
|
||||||
@ -1184,7 +1156,7 @@ static char *git_header_name(struct apply_state *state,
|
|||||||
goto free_and_fail1;
|
goto free_and_fail1;
|
||||||
|
|
||||||
/* strip the a/b prefix including trailing slash */
|
/* strip the a/b prefix including trailing slash */
|
||||||
cp = skip_tree_prefix(state, first.buf, first.len);
|
cp = skip_tree_prefix(p_value, first.buf, first.len);
|
||||||
if (!cp)
|
if (!cp)
|
||||||
goto free_and_fail1;
|
goto free_and_fail1;
|
||||||
strbuf_remove(&first, 0, cp - first.buf);
|
strbuf_remove(&first, 0, cp - first.buf);
|
||||||
@ -1201,7 +1173,7 @@ static char *git_header_name(struct apply_state *state,
|
|||||||
if (*second == '"') {
|
if (*second == '"') {
|
||||||
if (unquote_c_style(&sp, second, NULL))
|
if (unquote_c_style(&sp, second, NULL))
|
||||||
goto free_and_fail1;
|
goto free_and_fail1;
|
||||||
cp = skip_tree_prefix(state, sp.buf, sp.len);
|
cp = skip_tree_prefix(p_value, sp.buf, sp.len);
|
||||||
if (!cp)
|
if (!cp)
|
||||||
goto free_and_fail1;
|
goto free_and_fail1;
|
||||||
/* They must match, otherwise ignore */
|
/* They must match, otherwise ignore */
|
||||||
@ -1212,7 +1184,7 @@ static char *git_header_name(struct apply_state *state,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* unquoted second */
|
/* unquoted second */
|
||||||
cp = skip_tree_prefix(state, second, line + llen - second);
|
cp = skip_tree_prefix(p_value, second, line + llen - second);
|
||||||
if (!cp)
|
if (!cp)
|
||||||
goto free_and_fail1;
|
goto free_and_fail1;
|
||||||
if (line + llen - cp != first.len ||
|
if (line + llen - cp != first.len ||
|
||||||
@ -1227,7 +1199,7 @@ static char *git_header_name(struct apply_state *state,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* unquoted first name */
|
/* unquoted first name */
|
||||||
name = skip_tree_prefix(state, line, llen);
|
name = skip_tree_prefix(p_value, line, llen);
|
||||||
if (!name)
|
if (!name)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -1243,7 +1215,7 @@ static char *git_header_name(struct apply_state *state,
|
|||||||
if (unquote_c_style(&sp, second, NULL))
|
if (unquote_c_style(&sp, second, NULL))
|
||||||
goto free_and_fail2;
|
goto free_and_fail2;
|
||||||
|
|
||||||
np = skip_tree_prefix(state, sp.buf, sp.len);
|
np = skip_tree_prefix(p_value, sp.buf, sp.len);
|
||||||
if (!np)
|
if (!np)
|
||||||
goto free_and_fail2;
|
goto free_and_fail2;
|
||||||
|
|
||||||
@ -1287,7 +1259,7 @@ static char *git_header_name(struct apply_state *state,
|
|||||||
*/
|
*/
|
||||||
if (!name[len + 1])
|
if (!name[len + 1])
|
||||||
return NULL; /* no postimage name */
|
return NULL; /* no postimage name */
|
||||||
second = skip_tree_prefix(state, name + len + 1,
|
second = skip_tree_prefix(p_value, name + len + 1,
|
||||||
line_len - (len + 1));
|
line_len - (len + 1));
|
||||||
if (!second)
|
if (!second)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1302,26 +1274,28 @@ static char *git_header_name(struct apply_state *state,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int check_header_line(struct apply_state *state, struct patch *patch)
|
static int check_header_line(int linenr, struct patch *patch)
|
||||||
{
|
{
|
||||||
int extensions = (patch->is_delete == 1) + (patch->is_new == 1) +
|
int extensions = (patch->is_delete == 1) + (patch->is_new == 1) +
|
||||||
(patch->is_rename == 1) + (patch->is_copy == 1);
|
(patch->is_rename == 1) + (patch->is_copy == 1);
|
||||||
if (extensions > 1)
|
if (extensions > 1)
|
||||||
return error(_("inconsistent header lines %d and %d"),
|
return error(_("inconsistent header lines %d and %d"),
|
||||||
patch->extension_linenr, state->linenr);
|
patch->extension_linenr, linenr);
|
||||||
if (extensions && !patch->extension_linenr)
|
if (extensions && !patch->extension_linenr)
|
||||||
patch->extension_linenr = state->linenr;
|
patch->extension_linenr = linenr;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Verify that we recognize the lines following a git header */
|
int parse_git_diff_header(struct strbuf *root,
|
||||||
static int parse_git_header(struct apply_state *state,
|
int *linenr,
|
||||||
const char *line,
|
int p_value,
|
||||||
int len,
|
const char *line,
|
||||||
unsigned int size,
|
int len,
|
||||||
struct patch *patch)
|
unsigned int size,
|
||||||
|
struct patch *patch)
|
||||||
{
|
{
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
|
struct gitdiff_data parse_hdr_state;
|
||||||
|
|
||||||
/* A git diff has explicit new/delete information, so we don't guess */
|
/* A git diff has explicit new/delete information, so we don't guess */
|
||||||
patch->is_new = 0;
|
patch->is_new = 0;
|
||||||
@ -1333,20 +1307,24 @@ static int parse_git_header(struct apply_state *state,
|
|||||||
* or removing or adding empty files), so we get
|
* or removing or adding empty files), so we get
|
||||||
* the default name from the header.
|
* the default name from the header.
|
||||||
*/
|
*/
|
||||||
patch->def_name = git_header_name(state, line, len);
|
patch->def_name = git_header_name(p_value, line, len);
|
||||||
if (patch->def_name && state->root.len) {
|
if (patch->def_name && root->len) {
|
||||||
char *s = xstrfmt("%s%s", state->root.buf, patch->def_name);
|
char *s = xstrfmt("%s%s", root->buf, patch->def_name);
|
||||||
free(patch->def_name);
|
free(patch->def_name);
|
||||||
patch->def_name = s;
|
patch->def_name = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
line += len;
|
line += len;
|
||||||
size -= len;
|
size -= len;
|
||||||
state->linenr++;
|
(*linenr)++;
|
||||||
for (offset = len ; size > 0 ; offset += len, size -= len, line += len, state->linenr++) {
|
parse_hdr_state.root = root;
|
||||||
|
parse_hdr_state.linenr = *linenr;
|
||||||
|
parse_hdr_state.p_value = p_value;
|
||||||
|
|
||||||
|
for (offset = len ; size > 0 ; offset += len, size -= len, line += len, (*linenr)++) {
|
||||||
static const struct opentry {
|
static const struct opentry {
|
||||||
const char *str;
|
const char *str;
|
||||||
int (*fn)(struct apply_state *, const char *, struct patch *);
|
int (*fn)(struct gitdiff_data *, const char *, struct patch *);
|
||||||
} optable[] = {
|
} optable[] = {
|
||||||
{ "@@ -", gitdiff_hdrend },
|
{ "@@ -", gitdiff_hdrend },
|
||||||
{ "--- ", gitdiff_oldname },
|
{ "--- ", gitdiff_oldname },
|
||||||
@ -1377,10 +1355,10 @@ static int parse_git_header(struct apply_state *state,
|
|||||||
int res;
|
int res;
|
||||||
if (len < oplen || memcmp(p->str, line, oplen))
|
if (len < oplen || memcmp(p->str, line, oplen))
|
||||||
continue;
|
continue;
|
||||||
res = p->fn(state, line + oplen, patch);
|
res = p->fn(&parse_hdr_state, line + oplen, patch);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (check_header_line(state, patch))
|
if (check_header_line(*linenr, patch))
|
||||||
return -1;
|
return -1;
|
||||||
if (res > 0)
|
if (res > 0)
|
||||||
return offset;
|
return offset;
|
||||||
@ -1561,7 +1539,9 @@ static int find_header(struct apply_state *state,
|
|||||||
* or mode change, so we handle that specially
|
* or mode change, so we handle that specially
|
||||||
*/
|
*/
|
||||||
if (!memcmp("diff --git ", line, 11)) {
|
if (!memcmp("diff --git ", line, 11)) {
|
||||||
int git_hdr_len = parse_git_header(state, line, len, size, patch);
|
int git_hdr_len = parse_git_diff_header(&state->root, &state->linenr,
|
||||||
|
state->p_value, line, len,
|
||||||
|
size, patch);
|
||||||
if (git_hdr_len < 0)
|
if (git_hdr_len < 0)
|
||||||
return -128;
|
return -128;
|
||||||
if (git_hdr_len <= len)
|
if (git_hdr_len <= len)
|
||||||
|
48
apply.h
48
apply.h
@ -117,6 +117,40 @@ struct apply_state {
|
|||||||
int applied_after_fixing_ws;
|
int applied_after_fixing_ws;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This represents a "patch" to a file, both metainfo changes
|
||||||
|
* such as creation/deletion, filemode and content changes represented
|
||||||
|
* as a series of fragments.
|
||||||
|
*/
|
||||||
|
struct patch {
|
||||||
|
char *new_name, *old_name, *def_name;
|
||||||
|
unsigned int old_mode, new_mode;
|
||||||
|
int is_new, is_delete; /* -1 = unknown, 0 = false, 1 = true */
|
||||||
|
int rejected;
|
||||||
|
unsigned ws_rule;
|
||||||
|
int lines_added, lines_deleted;
|
||||||
|
int score;
|
||||||
|
int extension_linenr; /* first line specifying delete/new/rename/copy */
|
||||||
|
unsigned int is_toplevel_relative:1;
|
||||||
|
unsigned int inaccurate_eof:1;
|
||||||
|
unsigned int is_binary:1;
|
||||||
|
unsigned int is_copy:1;
|
||||||
|
unsigned int is_rename:1;
|
||||||
|
unsigned int recount:1;
|
||||||
|
unsigned int conflicted_threeway:1;
|
||||||
|
unsigned int direct_to_threeway:1;
|
||||||
|
unsigned int crlf_in_old:1;
|
||||||
|
struct fragment *fragments;
|
||||||
|
char *result;
|
||||||
|
size_t resultsize;
|
||||||
|
char old_oid_prefix[GIT_MAX_HEXSZ + 1];
|
||||||
|
char new_oid_prefix[GIT_MAX_HEXSZ + 1];
|
||||||
|
struct patch *next;
|
||||||
|
|
||||||
|
/* three-way fallback result */
|
||||||
|
struct object_id threeway_stage[3];
|
||||||
|
};
|
||||||
|
|
||||||
int apply_parse_options(int argc, const char **argv,
|
int apply_parse_options(int argc, const char **argv,
|
||||||
struct apply_state *state,
|
struct apply_state *state,
|
||||||
int *force_apply, int *options,
|
int *force_apply, int *options,
|
||||||
@ -127,6 +161,20 @@ int init_apply_state(struct apply_state *state,
|
|||||||
void clear_apply_state(struct apply_state *state);
|
void clear_apply_state(struct apply_state *state);
|
||||||
int check_apply_state(struct apply_state *state, int force_apply);
|
int check_apply_state(struct apply_state *state, int force_apply);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse a git diff header, starting at line. Fills the relevant
|
||||||
|
* metadata information in 'struct patch'.
|
||||||
|
*
|
||||||
|
* Returns -1 on failure, the length of the parsed header otherwise.
|
||||||
|
*/
|
||||||
|
int parse_git_diff_header(struct strbuf *root,
|
||||||
|
int *linenr,
|
||||||
|
int p_value,
|
||||||
|
const char *line,
|
||||||
|
int len,
|
||||||
|
unsigned int size,
|
||||||
|
struct patch *patch);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some aspects of the apply behavior are controlled by the following
|
* Some aspects of the apply behavior are controlled by the following
|
||||||
* bits in the "options" parameter passed to apply_all_patches().
|
* bits in the "options" parameter passed to apply_all_patches().
|
||||||
|
5
diff.c
5
diff.c
@ -1673,7 +1673,10 @@ static void emit_hunk_header(struct emit_callback *ecbdata,
|
|||||||
if (ecbdata->opt->flags.dual_color_diffed_diffs)
|
if (ecbdata->opt->flags.dual_color_diffed_diffs)
|
||||||
strbuf_addstr(&msgbuf, reverse);
|
strbuf_addstr(&msgbuf, reverse);
|
||||||
strbuf_addstr(&msgbuf, frag);
|
strbuf_addstr(&msgbuf, frag);
|
||||||
strbuf_add(&msgbuf, line, ep - line);
|
if (ecbdata->opt->flags.suppress_hunk_header_line_count)
|
||||||
|
strbuf_add(&msgbuf, atat, sizeof(atat));
|
||||||
|
else
|
||||||
|
strbuf_add(&msgbuf, line, ep - line);
|
||||||
strbuf_addstr(&msgbuf, reset);
|
strbuf_addstr(&msgbuf, reset);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
1
diff.h
1
diff.h
@ -98,6 +98,7 @@ struct diff_flags {
|
|||||||
unsigned stat_with_summary;
|
unsigned stat_with_summary;
|
||||||
unsigned suppress_diff_headers;
|
unsigned suppress_diff_headers;
|
||||||
unsigned dual_color_diffed_diffs;
|
unsigned dual_color_diffed_diffs;
|
||||||
|
unsigned suppress_hunk_header_line_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void diff_flags_or(struct diff_flags *a,
|
static inline void diff_flags_or(struct diff_flags *a,
|
||||||
|
124
range-diff.c
124
range-diff.c
@ -10,6 +10,7 @@
|
|||||||
#include "commit.h"
|
#include "commit.h"
|
||||||
#include "pretty.h"
|
#include "pretty.h"
|
||||||
#include "userdiff.h"
|
#include "userdiff.h"
|
||||||
|
#include "apply.h"
|
||||||
|
|
||||||
struct patch_util {
|
struct patch_util {
|
||||||
/* For the search for an exact match */
|
/* For the search for an exact match */
|
||||||
@ -24,6 +25,17 @@ struct patch_util {
|
|||||||
struct object_id oid;
|
struct object_id oid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static size_t find_end_of_line(char *buffer, unsigned long size)
|
||||||
|
{
|
||||||
|
char *eol = memchr(buffer, '\n', size);
|
||||||
|
|
||||||
|
if (!eol)
|
||||||
|
return size;
|
||||||
|
|
||||||
|
*eol = '\0';
|
||||||
|
return eol + 1 - buffer;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reads the patches into a string list, with the `util` field being populated
|
* Reads the patches into a string list, with the `util` field being populated
|
||||||
* as struct object_id (will need to be free()d).
|
* as struct object_id (will need to be free()d).
|
||||||
@ -31,10 +43,12 @@ struct patch_util {
|
|||||||
static int read_patches(const char *range, struct string_list *list)
|
static int read_patches(const char *range, struct string_list *list)
|
||||||
{
|
{
|
||||||
struct child_process cp = CHILD_PROCESS_INIT;
|
struct child_process cp = CHILD_PROCESS_INIT;
|
||||||
FILE *in;
|
struct strbuf buf = STRBUF_INIT, contents = STRBUF_INIT;
|
||||||
struct strbuf buf = STRBUF_INIT, line = STRBUF_INIT;
|
|
||||||
struct patch_util *util = NULL;
|
struct patch_util *util = NULL;
|
||||||
int in_header = 1;
|
int in_header = 1;
|
||||||
|
char *line, *current_filename = NULL;
|
||||||
|
int offset, len;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
argv_array_pushl(&cp.args, "log", "--no-color", "-p", "--no-merges",
|
argv_array_pushl(&cp.args, "log", "--no-color", "-p", "--no-merges",
|
||||||
"--reverse", "--date-order", "--decorate=no",
|
"--reverse", "--date-order", "--decorate=no",
|
||||||
@ -54,17 +68,20 @@ static int read_patches(const char *range, struct string_list *list)
|
|||||||
|
|
||||||
if (start_command(&cp))
|
if (start_command(&cp))
|
||||||
return error_errno(_("could not start `log`"));
|
return error_errno(_("could not start `log`"));
|
||||||
in = fdopen(cp.out, "r");
|
if (strbuf_read(&contents, cp.out, 0) < 0) {
|
||||||
if (!in) {
|
|
||||||
error_errno(_("could not read `log` output"));
|
error_errno(_("could not read `log` output"));
|
||||||
finish_command(&cp);
|
finish_command(&cp);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (strbuf_getline(&line, in) != EOF) {
|
line = contents.buf;
|
||||||
|
size = contents.len;
|
||||||
|
for (offset = 0; size > 0; offset += len, size -= len, line += len) {
|
||||||
const char *p;
|
const char *p;
|
||||||
|
|
||||||
if (skip_prefix(line.buf, "commit ", &p)) {
|
len = find_end_of_line(line, size);
|
||||||
|
line[len - 1] = '\0';
|
||||||
|
if (skip_prefix(line, "commit ", &p)) {
|
||||||
if (util) {
|
if (util) {
|
||||||
string_list_append(list, buf.buf)->util = util;
|
string_list_append(list, buf.buf)->util = util;
|
||||||
strbuf_reset(&buf);
|
strbuf_reset(&buf);
|
||||||
@ -75,8 +92,7 @@ static int read_patches(const char *range, struct string_list *list)
|
|||||||
free(util);
|
free(util);
|
||||||
string_list_clear(list, 1);
|
string_list_clear(list, 1);
|
||||||
strbuf_release(&buf);
|
strbuf_release(&buf);
|
||||||
strbuf_release(&line);
|
strbuf_release(&contents);
|
||||||
fclose(in);
|
|
||||||
finish_command(&cp);
|
finish_command(&cp);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -85,61 +101,95 @@ static int read_patches(const char *range, struct string_list *list)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (starts_with(line.buf, "diff --git")) {
|
if (starts_with(line, "diff --git")) {
|
||||||
|
struct patch patch = { 0 };
|
||||||
|
struct strbuf root = STRBUF_INIT;
|
||||||
|
int linenr = 0;
|
||||||
|
|
||||||
in_header = 0;
|
in_header = 0;
|
||||||
strbuf_addch(&buf, '\n');
|
strbuf_addch(&buf, '\n');
|
||||||
if (!util->diff_offset)
|
if (!util->diff_offset)
|
||||||
util->diff_offset = buf.len;
|
util->diff_offset = buf.len;
|
||||||
strbuf_addch(&buf, ' ');
|
line[len - 1] = '\n';
|
||||||
strbuf_addbuf(&buf, &line);
|
len = parse_git_diff_header(&root, &linenr, 1, line,
|
||||||
|
len, size, &patch);
|
||||||
|
if (len < 0)
|
||||||
|
die(_("could not parse git header '%.*s'"), (int)len, line);
|
||||||
|
strbuf_addstr(&buf, " ## ");
|
||||||
|
if (patch.is_new > 0)
|
||||||
|
strbuf_addf(&buf, "%s (new)", patch.new_name);
|
||||||
|
else if (patch.is_delete > 0)
|
||||||
|
strbuf_addf(&buf, "%s (deleted)", patch.old_name);
|
||||||
|
else if (patch.is_rename)
|
||||||
|
strbuf_addf(&buf, "%s => %s", patch.old_name, patch.new_name);
|
||||||
|
else
|
||||||
|
strbuf_addstr(&buf, patch.new_name);
|
||||||
|
|
||||||
|
free(current_filename);
|
||||||
|
if (patch.is_delete > 0)
|
||||||
|
current_filename = xstrdup(patch.old_name);
|
||||||
|
else
|
||||||
|
current_filename = xstrdup(patch.new_name);
|
||||||
|
|
||||||
|
if (patch.new_mode && patch.old_mode &&
|
||||||
|
patch.old_mode != patch.new_mode)
|
||||||
|
strbuf_addf(&buf, " (mode change %06o => %06o)",
|
||||||
|
patch.old_mode, patch.new_mode);
|
||||||
|
|
||||||
|
strbuf_addstr(&buf, " ##");
|
||||||
} else if (in_header) {
|
} else if (in_header) {
|
||||||
if (starts_with(line.buf, "Author: ")) {
|
if (starts_with(line, "Author: ")) {
|
||||||
strbuf_addbuf(&buf, &line);
|
strbuf_addstr(&buf, " ## Metadata ##\n");
|
||||||
|
strbuf_addstr(&buf, line);
|
||||||
strbuf_addstr(&buf, "\n\n");
|
strbuf_addstr(&buf, "\n\n");
|
||||||
} else if (starts_with(line.buf, " ")) {
|
strbuf_addstr(&buf, " ## Commit message ##\n");
|
||||||
strbuf_rtrim(&line);
|
} else if (starts_with(line, " ")) {
|
||||||
strbuf_addbuf(&buf, &line);
|
p = line + len - 2;
|
||||||
|
while (isspace(*p) && p >= line)
|
||||||
|
p--;
|
||||||
|
strbuf_add(&buf, line, p - line + 1);
|
||||||
strbuf_addch(&buf, '\n');
|
strbuf_addch(&buf, '\n');
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
} else if (starts_with(line.buf, "@@ "))
|
} else if (skip_prefix(line, "@@ ", &p)) {
|
||||||
|
p = strstr(p, "@@");
|
||||||
strbuf_addstr(&buf, "@@");
|
strbuf_addstr(&buf, "@@");
|
||||||
else if (!line.buf[0] || starts_with(line.buf, "index "))
|
if (current_filename && p[2])
|
||||||
|
strbuf_addf(&buf, " %s:", current_filename);
|
||||||
|
if (p)
|
||||||
|
strbuf_addstr(&buf, p + 2);
|
||||||
|
} else if (!line[0])
|
||||||
/*
|
/*
|
||||||
* A completely blank (not ' \n', which is context)
|
* A completely blank (not ' \n', which is context)
|
||||||
* line is not valid in a diff. We skip it
|
* line is not valid in a diff. We skip it
|
||||||
* silently, because this neatly handles the blank
|
* silently, because this neatly handles the blank
|
||||||
* separator line between commits in git-log
|
* separator line between commits in git-log
|
||||||
* output.
|
* output.
|
||||||
*
|
|
||||||
* We also want to ignore the diff's `index` lines
|
|
||||||
* because they contain exact blob hashes in which
|
|
||||||
* we are not interested.
|
|
||||||
*/
|
*/
|
||||||
continue;
|
continue;
|
||||||
else if (line.buf[0] == '>') {
|
else if (line[0] == '>') {
|
||||||
strbuf_addch(&buf, '+');
|
strbuf_addch(&buf, '+');
|
||||||
strbuf_add(&buf, line.buf + 1, line.len - 1);
|
strbuf_addstr(&buf, line + 1);
|
||||||
} else if (line.buf[0] == '<') {
|
} else if (line[0] == '<') {
|
||||||
strbuf_addch(&buf, '-');
|
strbuf_addch(&buf, '-');
|
||||||
strbuf_add(&buf, line.buf + 1, line.len - 1);
|
strbuf_addstr(&buf, line + 1);
|
||||||
} else if (line.buf[0] == '#') {
|
} else if (line[0] == '#') {
|
||||||
strbuf_addch(&buf, ' ');
|
strbuf_addch(&buf, ' ');
|
||||||
strbuf_add(&buf, line.buf + 1, line.len - 1);
|
strbuf_addstr(&buf, line + 1);
|
||||||
} else {
|
} else {
|
||||||
strbuf_addch(&buf, ' ');
|
strbuf_addch(&buf, ' ');
|
||||||
strbuf_addbuf(&buf, &line);
|
strbuf_addstr(&buf, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
strbuf_addch(&buf, '\n');
|
strbuf_addch(&buf, '\n');
|
||||||
util->diffsize++;
|
util->diffsize++;
|
||||||
}
|
}
|
||||||
fclose(in);
|
strbuf_release(&contents);
|
||||||
strbuf_release(&line);
|
|
||||||
|
|
||||||
if (util)
|
if (util)
|
||||||
string_list_append(list, buf.buf)->util = util;
|
string_list_append(list, buf.buf)->util = util;
|
||||||
strbuf_release(&buf);
|
strbuf_release(&buf);
|
||||||
|
free(current_filename);
|
||||||
|
|
||||||
if (finish_command(&cp))
|
if (finish_command(&cp))
|
||||||
return -1;
|
return -1;
|
||||||
@ -148,7 +198,7 @@ static int read_patches(const char *range, struct string_list *list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int patch_util_cmp(const void *dummy, const struct patch_util *a,
|
static int patch_util_cmp(const void *dummy, const struct patch_util *a,
|
||||||
const struct patch_util *b, const char *keydata)
|
const struct patch_util *b, const char *keydata)
|
||||||
{
|
{
|
||||||
return strcmp(a->diff, keydata ? keydata : b->diff);
|
return strcmp(a->diff, keydata ? keydata : b->diff);
|
||||||
}
|
}
|
||||||
@ -354,8 +404,9 @@ static void output_pair_header(struct diff_options *diffopt,
|
|||||||
fwrite(buf->buf, buf->len, 1, diffopt->file);
|
fwrite(buf->buf, buf->len, 1, diffopt->file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct userdiff_driver no_func_name = {
|
static struct userdiff_driver section_headers = {
|
||||||
.funcname = { "$^", 0 }
|
.funcname = { "^ ## (.*) ##$\n"
|
||||||
|
"^.?@@ (.*)$", REG_EXTENDED }
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct diff_filespec *get_filespec(const char *name, const char *p)
|
static struct diff_filespec *get_filespec(const char *name, const char *p)
|
||||||
@ -367,13 +418,13 @@ static struct diff_filespec *get_filespec(const char *name, const char *p)
|
|||||||
spec->size = strlen(p);
|
spec->size = strlen(p);
|
||||||
spec->should_munmap = 0;
|
spec->should_munmap = 0;
|
||||||
spec->is_stdin = 1;
|
spec->is_stdin = 1;
|
||||||
spec->driver = &no_func_name;
|
spec->driver = §ion_headers;
|
||||||
|
|
||||||
return spec;
|
return spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void patch_diff(const char *a, const char *b,
|
static void patch_diff(const char *a, const char *b,
|
||||||
struct diff_options *diffopt)
|
struct diff_options *diffopt)
|
||||||
{
|
{
|
||||||
diff_queue(&diff_queued_diff,
|
diff_queue(&diff_queued_diff,
|
||||||
get_filespec("a", a), get_filespec("b", b));
|
get_filespec("a", a), get_filespec("b", b));
|
||||||
@ -469,6 +520,7 @@ int show_range_diff(const char *range1, const char *range2,
|
|||||||
opts.output_format = DIFF_FORMAT_PATCH;
|
opts.output_format = DIFF_FORMAT_PATCH;
|
||||||
opts.flags.suppress_diff_headers = 1;
|
opts.flags.suppress_diff_headers = 1;
|
||||||
opts.flags.dual_color_diffed_diffs = dual_color;
|
opts.flags.dual_color_diffed_diffs = dual_color;
|
||||||
|
opts.flags.suppress_hunk_header_line_count = 1;
|
||||||
opts.output_prefix = output_prefix_cb;
|
opts.output_prefix = output_prefix_cb;
|
||||||
strbuf_addstr(&indent, " ");
|
strbuf_addstr(&indent, " ");
|
||||||
opts.output_prefix_data = &indent;
|
opts.output_prefix_data = &indent;
|
||||||
|
@ -99,7 +99,7 @@ test_expect_success 'changed commit' '
|
|||||||
1: 4de457d = 1: a4b3333 s/5/A/
|
1: 4de457d = 1: a4b3333 s/5/A/
|
||||||
2: fccce22 = 2: f51d370 s/4/A/
|
2: fccce22 = 2: f51d370 s/4/A/
|
||||||
3: 147e64e ! 3: 0559556 s/11/B/
|
3: 147e64e ! 3: 0559556 s/11/B/
|
||||||
@@ -10,7 +10,7 @@
|
@@ file: A
|
||||||
9
|
9
|
||||||
10
|
10
|
||||||
-11
|
-11
|
||||||
@ -109,8 +109,8 @@ test_expect_success 'changed commit' '
|
|||||||
13
|
13
|
||||||
14
|
14
|
||||||
4: a63e992 ! 4: d966c5c s/12/B/
|
4: a63e992 ! 4: d966c5c s/12/B/
|
||||||
@@ -8,7 +8,7 @@
|
@@ file
|
||||||
@@
|
@@ file: A
|
||||||
9
|
9
|
||||||
10
|
10
|
||||||
- B
|
- B
|
||||||
@ -158,7 +158,7 @@ test_expect_success 'changed commit with sm config' '
|
|||||||
1: 4de457d = 1: a4b3333 s/5/A/
|
1: 4de457d = 1: a4b3333 s/5/A/
|
||||||
2: fccce22 = 2: f51d370 s/4/A/
|
2: fccce22 = 2: f51d370 s/4/A/
|
||||||
3: 147e64e ! 3: 0559556 s/11/B/
|
3: 147e64e ! 3: 0559556 s/11/B/
|
||||||
@@ -10,7 +10,7 @@
|
@@ file: A
|
||||||
9
|
9
|
||||||
10
|
10
|
||||||
-11
|
-11
|
||||||
@ -168,8 +168,8 @@ test_expect_success 'changed commit with sm config' '
|
|||||||
13
|
13
|
||||||
14
|
14
|
||||||
4: a63e992 ! 4: d966c5c s/12/B/
|
4: a63e992 ! 4: d966c5c s/12/B/
|
||||||
@@ -8,7 +8,7 @@
|
@@ file
|
||||||
@@
|
@@ file: A
|
||||||
9
|
9
|
||||||
10
|
10
|
||||||
- B
|
- B
|
||||||
@ -181,6 +181,92 @@ test_expect_success 'changed commit with sm config' '
|
|||||||
test_cmp expected actual
|
test_cmp expected actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'renamed file' '
|
||||||
|
git range-diff --no-color --submodule=log topic...renamed-file >actual &&
|
||||||
|
sed s/Z/\ /g >expected <<-EOF &&
|
||||||
|
1: 4de457d = 1: f258d75 s/5/A/
|
||||||
|
2: fccce22 ! 2: 017b62d s/4/A/
|
||||||
|
@@ Metadata
|
||||||
|
ZAuthor: Thomas Rast <trast@inf.ethz.ch>
|
||||||
|
Z
|
||||||
|
Z ## Commit message ##
|
||||||
|
- s/4/A/
|
||||||
|
+ s/4/A/ + rename file
|
||||||
|
Z
|
||||||
|
- ## file ##
|
||||||
|
+ ## file => renamed-file ##
|
||||||
|
Z@@
|
||||||
|
Z 1
|
||||||
|
Z 2
|
||||||
|
3: 147e64e ! 3: 3ce7af6 s/11/B/
|
||||||
|
@@ Metadata
|
||||||
|
Z ## Commit message ##
|
||||||
|
Z s/11/B/
|
||||||
|
Z
|
||||||
|
- ## file ##
|
||||||
|
-@@ file: A
|
||||||
|
+ ## renamed-file ##
|
||||||
|
+@@ renamed-file: A
|
||||||
|
Z 8
|
||||||
|
Z 9
|
||||||
|
Z 10
|
||||||
|
4: a63e992 ! 4: 1e6226b s/12/B/
|
||||||
|
@@ Metadata
|
||||||
|
Z ## Commit message ##
|
||||||
|
Z s/12/B/
|
||||||
|
Z
|
||||||
|
- ## file ##
|
||||||
|
-@@ file: A
|
||||||
|
+ ## renamed-file ##
|
||||||
|
+@@ renamed-file: A
|
||||||
|
Z 9
|
||||||
|
Z 10
|
||||||
|
Z B
|
||||||
|
EOF
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'file added and later removed' '
|
||||||
|
git range-diff --no-color --submodule=log topic...added-removed >actual &&
|
||||||
|
sed s/Z/\ /g >expected <<-EOF &&
|
||||||
|
1: 4de457d = 1: 096b1ba s/5/A/
|
||||||
|
2: fccce22 ! 2: d92e698 s/4/A/
|
||||||
|
@@ Metadata
|
||||||
|
ZAuthor: Thomas Rast <trast@inf.ethz.ch>
|
||||||
|
Z
|
||||||
|
Z ## Commit message ##
|
||||||
|
- s/4/A/
|
||||||
|
+ s/4/A/ + new-file
|
||||||
|
Z
|
||||||
|
Z ## file ##
|
||||||
|
Z@@
|
||||||
|
@@ file
|
||||||
|
Z A
|
||||||
|
Z 6
|
||||||
|
Z 7
|
||||||
|
+
|
||||||
|
+ ## new-file (new) ##
|
||||||
|
3: 147e64e ! 3: 9a1db4d s/11/B/
|
||||||
|
@@ Metadata
|
||||||
|
ZAuthor: Thomas Rast <trast@inf.ethz.ch>
|
||||||
|
Z
|
||||||
|
Z ## Commit message ##
|
||||||
|
- s/11/B/
|
||||||
|
+ s/11/B/ + remove file
|
||||||
|
Z
|
||||||
|
Z ## file ##
|
||||||
|
Z@@ file: A
|
||||||
|
@@ file: A
|
||||||
|
Z 12
|
||||||
|
Z 13
|
||||||
|
Z 14
|
||||||
|
+
|
||||||
|
+ ## new-file (deleted) ##
|
||||||
|
4: a63e992 = 4: fea3b5c s/12/B/
|
||||||
|
EOF
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'no commits on one side' '
|
test_expect_success 'no commits on one side' '
|
||||||
git commit --amend -m "new message" &&
|
git commit --amend -m "new message" &&
|
||||||
git range-diff master HEAD@{1} HEAD
|
git range-diff master HEAD@{1} HEAD
|
||||||
@ -191,15 +277,15 @@ test_expect_success 'changed message' '
|
|||||||
sed s/Z/\ /g >expected <<-EOF &&
|
sed s/Z/\ /g >expected <<-EOF &&
|
||||||
1: 4de457d = 1: f686024 s/5/A/
|
1: 4de457d = 1: f686024 s/5/A/
|
||||||
2: fccce22 ! 2: 4ab067d s/4/A/
|
2: fccce22 ! 2: 4ab067d s/4/A/
|
||||||
@@ -2,6 +2,8 @@
|
@@ Metadata
|
||||||
Z
|
Z ## Commit message ##
|
||||||
Z s/4/A/
|
Z s/4/A/
|
||||||
Z
|
Z
|
||||||
+ Also a silly comment here!
|
+ Also a silly comment here!
|
||||||
+
|
+
|
||||||
Z diff --git a/file b/file
|
Z ## file ##
|
||||||
Z --- a/file
|
Z@@
|
||||||
Z +++ b/file
|
Z 1
|
||||||
3: 147e64e = 3: b9cb956 s/11/B/
|
3: 147e64e = 3: b9cb956 s/11/B/
|
||||||
4: a63e992 = 4: 8add5f1 s/12/B/
|
4: a63e992 = 4: 8add5f1 s/12/B/
|
||||||
EOF
|
EOF
|
||||||
@ -210,17 +296,17 @@ test_expect_success 'dual-coloring' '
|
|||||||
sed -e "s|^:||" >expect <<-\EOF &&
|
sed -e "s|^:||" >expect <<-\EOF &&
|
||||||
:<YELLOW>1: a4b3333 = 1: f686024 s/5/A/<RESET>
|
:<YELLOW>1: a4b3333 = 1: f686024 s/5/A/<RESET>
|
||||||
:<RED>2: f51d370 <RESET><YELLOW>!<RESET><GREEN> 2: 4ab067d<RESET><YELLOW> s/4/A/<RESET>
|
:<RED>2: f51d370 <RESET><YELLOW>!<RESET><GREEN> 2: 4ab067d<RESET><YELLOW> s/4/A/<RESET>
|
||||||
: <REVERSE><CYAN>@@ -2,6 +2,8 @@<RESET>
|
: <REVERSE><CYAN>@@<RESET> <RESET>Metadata<RESET>
|
||||||
: <RESET>
|
: ## Commit message ##<RESET>
|
||||||
: s/4/A/<RESET>
|
: s/4/A/<RESET>
|
||||||
: <RESET>
|
: <RESET>
|
||||||
: <REVERSE><GREEN>+<RESET><BOLD> Also a silly comment here!<RESET>
|
: <REVERSE><GREEN>+<RESET><BOLD> Also a silly comment here!<RESET>
|
||||||
: <REVERSE><GREEN>+<RESET>
|
: <REVERSE><GREEN>+<RESET>
|
||||||
: diff --git a/file b/file<RESET>
|
: ## file ##<RESET>
|
||||||
: --- a/file<RESET>
|
: <CYAN> @@<RESET>
|
||||||
: +++ b/file<RESET>
|
: 1<RESET>
|
||||||
:<RED>3: 0559556 <RESET><YELLOW>!<RESET><GREEN> 3: b9cb956<RESET><YELLOW> s/11/B/<RESET>
|
:<RED>3: 0559556 <RESET><YELLOW>!<RESET><GREEN> 3: b9cb956<RESET><YELLOW> s/11/B/<RESET>
|
||||||
: <REVERSE><CYAN>@@ -10,7 +10,7 @@<RESET>
|
: <REVERSE><CYAN>@@<RESET> <RESET>file: A<RESET>
|
||||||
: 9<RESET>
|
: 9<RESET>
|
||||||
: 10<RESET>
|
: 10<RESET>
|
||||||
: <RED> -11<RESET>
|
: <RED> -11<RESET>
|
||||||
@ -230,8 +316,8 @@ test_expect_success 'dual-coloring' '
|
|||||||
: 13<RESET>
|
: 13<RESET>
|
||||||
: 14<RESET>
|
: 14<RESET>
|
||||||
:<RED>4: d966c5c <RESET><YELLOW>!<RESET><GREEN> 4: 8add5f1<RESET><YELLOW> s/12/B/<RESET>
|
:<RED>4: d966c5c <RESET><YELLOW>!<RESET><GREEN> 4: 8add5f1<RESET><YELLOW> s/12/B/<RESET>
|
||||||
: <REVERSE><CYAN>@@ -8,7 +8,7 @@<RESET>
|
: <REVERSE><CYAN>@@<RESET> <RESET>file<RESET>
|
||||||
: <CYAN> @@<RESET>
|
: <CYAN> @@ file: A<RESET>
|
||||||
: 9<RESET>
|
: 9<RESET>
|
||||||
: 10<RESET>
|
: 10<RESET>
|
||||||
: <REVERSE><RED>-<RESET><FAINT> BB<RESET>
|
: <REVERSE><RED>-<RESET><FAINT> BB<RESET>
|
||||||
|
@ -22,8 +22,8 @@ data 51
|
|||||||
19
|
19
|
||||||
20
|
20
|
||||||
|
|
||||||
reset refs/heads/removed
|
reset refs/heads/renamed-file
|
||||||
commit refs/heads/removed
|
commit refs/heads/renamed-file
|
||||||
mark :2
|
mark :2
|
||||||
author Thomas Rast <trast@inf.ethz.ch> 1374424921 +0200
|
author Thomas Rast <trast@inf.ethz.ch> 1374424921 +0200
|
||||||
committer Thomas Rast <trast@inf.ethz.ch> 1374484724 +0200
|
committer Thomas Rast <trast@inf.ethz.ch> 1374484724 +0200
|
||||||
@ -599,6 +599,82 @@ s/12/B/
|
|||||||
from :46
|
from :46
|
||||||
M 100644 :28 file
|
M 100644 :28 file
|
||||||
|
|
||||||
reset refs/heads/removed
|
commit refs/heads/added-removed
|
||||||
from :47
|
mark :48
|
||||||
|
author Thomas Rast <trast@inf.ethz.ch> 1374485014 +0200
|
||||||
|
committer Thomas Gummerer <t.gummerer@gmail.com> 1556574151 +0100
|
||||||
|
data 7
|
||||||
|
s/5/A/
|
||||||
|
from :2
|
||||||
|
M 100644 :3 file
|
||||||
|
|
||||||
|
blob
|
||||||
|
mark :49
|
||||||
|
data 0
|
||||||
|
|
||||||
|
commit refs/heads/added-removed
|
||||||
|
mark :50
|
||||||
|
author Thomas Rast <trast@inf.ethz.ch> 1374485024 +0200
|
||||||
|
committer Thomas Gummerer <t.gummerer@gmail.com> 1556574177 +0100
|
||||||
|
data 18
|
||||||
|
s/4/A/ + new-file
|
||||||
|
from :48
|
||||||
|
M 100644 :5 file
|
||||||
|
M 100644 :49 new-file
|
||||||
|
|
||||||
|
commit refs/heads/added-removed
|
||||||
|
mark :51
|
||||||
|
author Thomas Rast <trast@inf.ethz.ch> 1374485036 +0200
|
||||||
|
committer Thomas Gummerer <t.gummerer@gmail.com> 1556574177 +0100
|
||||||
|
data 22
|
||||||
|
s/11/B/ + remove file
|
||||||
|
from :50
|
||||||
|
M 100644 :7 file
|
||||||
|
D new-file
|
||||||
|
|
||||||
|
commit refs/heads/added-removed
|
||||||
|
mark :52
|
||||||
|
author Thomas Rast <trast@inf.ethz.ch> 1374485044 +0200
|
||||||
|
committer Thomas Gummerer <t.gummerer@gmail.com> 1556574177 +0100
|
||||||
|
data 8
|
||||||
|
s/12/B/
|
||||||
|
from :51
|
||||||
|
M 100644 :9 file
|
||||||
|
|
||||||
|
commit refs/heads/renamed-file
|
||||||
|
mark :53
|
||||||
|
author Thomas Rast <trast@inf.ethz.ch> 1374485014 +0200
|
||||||
|
committer Thomas Gummerer <t.gummerer@gmail.com> 1556574309 +0100
|
||||||
|
data 7
|
||||||
|
s/5/A/
|
||||||
|
from :2
|
||||||
|
M 100644 :3 file
|
||||||
|
|
||||||
|
commit refs/heads/renamed-file
|
||||||
|
mark :54
|
||||||
|
author Thomas Rast <trast@inf.ethz.ch> 1374485024 +0200
|
||||||
|
committer Thomas Gummerer <t.gummerer@gmail.com> 1556574312 +0100
|
||||||
|
data 21
|
||||||
|
s/4/A/ + rename file
|
||||||
|
from :53
|
||||||
|
D file
|
||||||
|
M 100644 :5 renamed-file
|
||||||
|
|
||||||
|
commit refs/heads/renamed-file
|
||||||
|
mark :55
|
||||||
|
author Thomas Rast <trast@inf.ethz.ch> 1374485036 +0200
|
||||||
|
committer Thomas Gummerer <t.gummerer@gmail.com> 1556574319 +0100
|
||||||
|
data 8
|
||||||
|
s/11/B/
|
||||||
|
from :54
|
||||||
|
M 100644 :7 renamed-file
|
||||||
|
|
||||||
|
commit refs/heads/renamed-file
|
||||||
|
mark :56
|
||||||
|
author Thomas Rast <trast@inf.ethz.ch> 1374485044 +0200
|
||||||
|
committer Thomas Gummerer <t.gummerer@gmail.com> 1556574319 +0100
|
||||||
|
data 8
|
||||||
|
s/12/B/
|
||||||
|
from :55
|
||||||
|
M 100644 :9 renamed-file
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user