Skip to content

Commit

Permalink
Merge branch 'jk/diff-blob'
Browse files Browse the repository at this point in the history
The result from "git diff" that compares two blobs, e.g. "git diff
$commit1:$path $commit2:$path", used to be shown with the full
object name as given on the command line, but it is more natural to
use the $path in the output and use it to look up .gitattributes.

* jk/diff-blob:
  diff: use blob path for blob/file diffs
  diff: use pending "path" if it is available
  diff: use the word "path" instead of "name" for blobs
  diff: pass whole pending entry in blobinfo
  handle_revision_arg: record paths for pending objects
  handle_revision_arg: record modes for "a..b" endpoints
  t4063: add tests of direct blob diffs
  get_sha1_with_context: dynamically allocate oc->path
  get_sha1_with_context: always initialize oc->symlink_path
  sha1_name: consistently refer to object_context as "oc"
  handle_revision_arg: add handle_dotdot() helper
  handle_revision_arg: hoist ".." check out of range parsing
  handle_revision_arg: stop using "dotdot" as a generic pointer
  handle_revision_arg: simplify commit reference lookups
  handle_revision_arg: reset "dotdot" consistently
  • Loading branch information
gitster committed Jun 2, 2017
2 parents f4fd99b + 30d005c commit 7ef0d04
Show file tree
Hide file tree
Showing 10 changed files with 301 additions and 147 deletions.
4 changes: 3 additions & 1 deletion builtin/cat-file.c
Expand Up @@ -61,7 +61,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
if (unknown_type)
flags |= LOOKUP_UNKNOWN_OBJECT;

if (get_sha1_with_context(obj_name, 0, oid.hash, &obj_context))
if (get_sha1_with_context(obj_name, GET_SHA1_RECORD_PATH,
oid.hash, &obj_context))
die("Not a valid object name %s", obj_name);

if (!path)
Expand Down Expand Up @@ -166,6 +167,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,

write_or_die(1, buf, size);
free(buf);
free(obj_context.path);
return 0;
}

Expand Down
60 changes: 29 additions & 31 deletions builtin/diff.c
Expand Up @@ -20,23 +20,22 @@
#define DIFF_NO_INDEX_EXPLICIT 1
#define DIFF_NO_INDEX_IMPLICIT 2

struct blobinfo {
struct object_id oid;
const char *name;
unsigned mode;
};

static const char builtin_diff_usage[] =
"git diff [<options>] [<commit> [<commit>]] [--] [<path>...]";

static const char *blob_path(struct object_array_entry *entry)
{
return entry->path ? entry->path : entry->name;
}

static void stuff_change(struct diff_options *opt,
unsigned old_mode, unsigned new_mode,
const struct object_id *old_oid,
const struct object_id *new_oid,
int old_oid_valid,
int new_oid_valid,
const char *old_name,
const char *new_name)
const char *old_path,
const char *new_path)
{
struct diff_filespec *one, *two;

Expand All @@ -47,16 +46,16 @@ static void stuff_change(struct diff_options *opt,
if (DIFF_OPT_TST(opt, REVERSE_DIFF)) {
SWAP(old_mode, new_mode);
SWAP(old_oid, new_oid);
SWAP(old_name, new_name);
SWAP(old_path, new_path);
}

if (opt->prefix &&
(strncmp(old_name, opt->prefix, opt->prefix_length) ||
strncmp(new_name, opt->prefix, opt->prefix_length)))
(strncmp(old_path, opt->prefix, opt->prefix_length) ||
strncmp(new_path, opt->prefix, opt->prefix_length)))
return;

one = alloc_filespec(old_name);
two = alloc_filespec(new_name);
one = alloc_filespec(old_path);
two = alloc_filespec(new_path);
fill_filespec(one, old_oid->hash, old_oid_valid, old_mode);
fill_filespec(two, new_oid->hash, new_oid_valid, new_mode);

Expand All @@ -65,7 +64,7 @@ static void stuff_change(struct diff_options *opt,

static int builtin_diff_b_f(struct rev_info *revs,
int argc, const char **argv,
struct blobinfo *blob)
struct object_array_entry **blob)
{
/* Blob vs file in the working tree*/
struct stat st;
Expand All @@ -84,39 +83,40 @@ static int builtin_diff_b_f(struct rev_info *revs,

diff_set_mnemonic_prefix(&revs->diffopt, "o/", "w/");

if (blob[0].mode == S_IFINVALID)
blob[0].mode = canon_mode(st.st_mode);
if (blob[0]->mode == S_IFINVALID)
blob[0]->mode = canon_mode(st.st_mode);

stuff_change(&revs->diffopt,
blob[0].mode, canon_mode(st.st_mode),
&blob[0].oid, &null_oid,
blob[0]->mode, canon_mode(st.st_mode),
&blob[0]->item->oid, &null_oid,
1, 0,
path, path);
blob[0]->path ? blob[0]->path : path,
path);
diffcore_std(&revs->diffopt);
diff_flush(&revs->diffopt);
return 0;
}

static int builtin_diff_blobs(struct rev_info *revs,
int argc, const char **argv,
struct blobinfo *blob)
struct object_array_entry **blob)
{
unsigned mode = canon_mode(S_IFREG | 0644);

if (argc > 1)
usage(builtin_diff_usage);

if (blob[0].mode == S_IFINVALID)
blob[0].mode = mode;
if (blob[0]->mode == S_IFINVALID)
blob[0]->mode = mode;

if (blob[1].mode == S_IFINVALID)
blob[1].mode = mode;
if (blob[1]->mode == S_IFINVALID)
blob[1]->mode = mode;

stuff_change(&revs->diffopt,
blob[0].mode, blob[1].mode,
&blob[0].oid, &blob[1].oid,
blob[0]->mode, blob[1]->mode,
&blob[0]->item->oid, &blob[1]->item->oid,
1, 1,
blob[0].name, blob[1].name);
blob_path(blob[0]), blob_path(blob[1]));
diffcore_std(&revs->diffopt);
diff_flush(&revs->diffopt);
return 0;
Expand Down Expand Up @@ -259,7 +259,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
struct rev_info rev;
struct object_array ent = OBJECT_ARRAY_INIT;
int blobs = 0, paths = 0;
struct blobinfo blob[2];
struct object_array_entry *blob[2];
int nongit = 0, no_index = 0;
int result = 0;

Expand Down Expand Up @@ -408,9 +408,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
} else if (obj->type == OBJ_BLOB) {
if (2 <= blobs)
die(_("more than two blobs given: '%s'"), name);
oidcpy(&blob[blobs].oid, &obj->oid);
blob[blobs].name = name;
blob[blobs].mode = entry->mode;
blob[blobs] = entry;
blobs++;

} else {
Expand Down
4 changes: 3 additions & 1 deletion builtin/grep.c
Expand Up @@ -1190,7 +1190,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
break;
}

if (get_sha1_with_context(arg, 0, oid.hash, &oc)) {
if (get_sha1_with_context(arg, GET_SHA1_RECORD_PATH,
oid.hash, &oc)) {
if (seen_dashdash)
die(_("unable to resolve revision: %s"), arg);
break;
Expand All @@ -1200,6 +1201,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
if (!seen_dashdash)
verify_non_filename(prefix, arg);
add_object_array_with_path(object, arg, &list, oc.mode, oc.path);
free(oc.path);
}

/*
Expand Down
10 changes: 7 additions & 3 deletions builtin/log.c
Expand Up @@ -483,16 +483,20 @@ static int show_blob_object(const struct object_id *oid, struct rev_info *rev, c
!DIFF_OPT_TST(&rev->diffopt, ALLOW_TEXTCONV))
return stream_blob_to_fd(1, oid, NULL, 0);

if (get_sha1_with_context(obj_name, 0, oidc.hash, &obj_context))
if (get_sha1_with_context(obj_name, GET_SHA1_RECORD_PATH,
oidc.hash, &obj_context))
die(_("Not a valid object name %s"), obj_name);
if (!obj_context.path[0] ||
!textconv_object(obj_context.path, obj_context.mode, &oidc, 1, &buf, &size))
if (!obj_context.path ||
!textconv_object(obj_context.path, obj_context.mode, &oidc, 1, &buf, &size)) {
free(obj_context.path);
return stream_blob_to_fd(1, oid, NULL, 0);
}

if (!buf)
die(_("git show %s: bad file"), obj_name);

write_or_die(1, buf, size);
free(obj_context.path);
return 0;
}

Expand Down
10 changes: 8 additions & 2 deletions cache.h
Expand Up @@ -1334,13 +1334,18 @@ static inline int hex2chr(const char *s)

struct object_context {
unsigned char tree[20];
char path[PATH_MAX];
unsigned mode;
/*
* symlink_path is only used by get_tree_entry_follow_symlinks,
* and only for symlinks that point outside the repository.
*/
struct strbuf symlink_path;
/*
* If GET_SHA1_RECORD_PATH is set, this will record path (if any)
* found when resolving the name. The caller is responsible for
* releasing the memory.
*/
char *path;
};

#define GET_SHA1_QUIETLY 01
Expand All @@ -1350,6 +1355,7 @@ struct object_context {
#define GET_SHA1_TREEISH 020
#define GET_SHA1_BLOB 040
#define GET_SHA1_FOLLOW_SYMLINKS 0100
#define GET_SHA1_RECORD_PATH 0200
#define GET_SHA1_ONLY_TO_DIE 04000

#define GET_SHA1_DISAMBIGUATORS \
Expand All @@ -1364,7 +1370,7 @@ extern int get_sha1_tree(const char *str, unsigned char *sha1);
extern int get_sha1_treeish(const char *str, unsigned char *sha1);
extern int get_sha1_blob(const char *str, unsigned char *sha1);
extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc);
extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *oc);

extern int get_oid(const char *str, struct object_id *oid);

Expand Down

0 comments on commit 7ef0d04

Please sign in to comment.