Merge branch 'js/patch' into next

* js/patch:
  t4014: add format-patch --ignore-if-in-upstream test
  format-patch: introduce "--ignore-if-in-upstream"
  add diff_flush_patch_id() to calculate the patch id
  Fix pkt-line.h to compile with a non-GCC compiler
  Solaris needs inclusion of signal.h for signal()
  correct documentation for git grep
This commit is contained in:
Junio C Hamano
2006-06-26 16:01:46 -07:00
8 changed files with 300 additions and 1 deletions

View File

@@ -16,7 +16,7 @@ SYNOPSIS
[-n] [-l | --files-with-matches] [-L | --files-without-match]
[-c | --count]
[-A <post-context>] [-B <pre-context>] [-C <context>]
[-f <file>] [-e <pattern>]
[-f <file>] [-e] <pattern>
[<tree>...]
[--] [<path>...]
@@ -71,6 +71,11 @@ OPTIONS
-f <file>::
Read patterns from <file>, one per line.
-e::
The next parameter is the pattern. This option has to be
used for patterns starting with - and should be used in
scripts passing user input to grep.
`<tree>...`::
Search blobs in the trees for specified patterns.

View File

@@ -160,6 +160,71 @@ static void reopen_stdout(struct commit *commit, int nr, int keep_subject)
freopen(filename, "w", stdout);
}
static void reset_all_objects_flags()
{
int i;
for (i = 0; i < obj_allocs; i++)
if (objs[i])
objs[i]->flags = 0;
}
static int get_patch_id(struct commit *commit, struct diff_options *options,
unsigned char *sha1)
{
diff_tree_sha1(commit->parents->item->object.sha1, commit->object.sha1,
"", options);
diffcore_std(options);
return diff_flush_patch_id(options, sha1);
}
static void get_patch_ids(struct rev_info *rev, struct diff_options *options)
{
struct rev_info check_rev;
struct commit *commit;
struct object *o1, *o2;
unsigned flags1, flags2;
unsigned char sha1[20];
if (rev->pending.nr != 2)
die("Need exactly one range.");
o1 = rev->pending.objects[0].item;
flags1 = o1->flags;
o2 = rev->pending.objects[1].item;
flags2 = o2->flags;
if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
die("Not a range.");
diff_setup(options);
options->recursive = 1;
if (diff_setup_done(options) < 0)
die("diff_setup_done failed");
/* given a range a..b get all patch ids for b..a */
init_revisions(&check_rev);
o1->flags ^= UNINTERESTING;
o2->flags ^= UNINTERESTING;
add_pending_object(&check_rev, o1, "o1");
add_pending_object(&check_rev, o2, "o2");
prepare_revision_walk(&check_rev);
while ((commit = get_revision(&check_rev)) != NULL) {
/* ignore merges */
if (commit->parents && commit->parents->next)
continue;
if (!get_patch_id(commit, options, sha1))
created_object(sha1, xcalloc(1, sizeof(struct object)));
}
/* reset for next revision walk */
reset_all_objects_flags();
o1->flags = flags1;
o2->flags = flags2;
}
int cmd_format_patch(int argc, const char **argv, char **envp)
{
struct commit *commit;
@@ -170,6 +235,8 @@ int cmd_format_patch(int argc, const char **argv, char **envp)
int numbered = 0;
int start_number = -1;
int keep_subject = 0;
int ignore_if_in_upstream = 0;
struct diff_options patch_id_opts;
char *add_signoff = NULL;
init_revisions(&rev);
@@ -235,6 +302,8 @@ int cmd_format_patch(int argc, const char **argv, char **envp)
rev.mime_boundary = git_version_string;
else if (!strncmp(argv[i], "--attach=", 9))
rev.mime_boundary = argv[i] + 9;
else if (!strcmp(argv[i], "--ignore-if-in-upstream"))
ignore_if_in_upstream = 1;
else
argv[j++] = argv[i];
}
@@ -262,14 +331,25 @@ int cmd_format_patch(int argc, const char **argv, char **envp)
add_head(&rev);
}
if (ignore_if_in_upstream)
get_patch_ids(&rev, &patch_id_opts);
if (!use_stdout)
realstdout = fdopen(dup(1), "w");
prepare_revision_walk(&rev);
while ((commit = get_revision(&rev)) != NULL) {
unsigned char sha1[20];
/* ignore merges */
if (commit->parents && commit->parents->next)
continue;
if (ignore_if_in_upstream &&
!get_patch_id(commit, &patch_id_opts, sha1) &&
lookup_object(sha1))
continue;
nr++;
list = realloc(list, nr * sizeof(list[0]));
list[nr - 1] = commit;

View File

@@ -8,6 +8,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
static char *server_capabilities = NULL;

139
diff.c
View File

@@ -2104,6 +2104,145 @@ static void diff_summary(struct diff_filepair *p)
}
}
struct patch_id_t {
struct xdiff_emit_state xm;
SHA_CTX *ctx;
int patchlen;
};
static int remove_space(char *line, int len)
{
int i;
char *dst = line;
unsigned char c;
for (i = 0; i < len; i++)
if (!isspace((c = line[i])))
*dst++ = c;
return dst - line;
}
static void patch_id_consume(void *priv, char *line, unsigned long len)
{
struct patch_id_t *data = priv;
int new_len;
/* Ignore line numbers when computing the SHA1 of the patch */
if (!strncmp(line, "@@ -", 4))
return;
new_len = remove_space(line, len);
SHA1_Update(data->ctx, line, new_len);
data->patchlen += new_len;
}
/* returns 0 upon success, and writes result into sha1 */
static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
{
struct diff_queue_struct *q = &diff_queued_diff;
int i;
SHA_CTX ctx;
struct patch_id_t data;
char buffer[PATH_MAX * 4 + 20];
SHA1_Init(&ctx);
memset(&data, 0, sizeof(struct patch_id_t));
data.ctx = &ctx;
data.xm.consume = patch_id_consume;
for (i = 0; i < q->nr; i++) {
xpparam_t xpp;
xdemitconf_t xecfg;
xdemitcb_t ecb;
mmfile_t mf1, mf2;
struct diff_filepair *p = q->queue[i];
int len1, len2;
if (p->status == 0)
return error("internal diff status error");
if (p->status == DIFF_STATUS_UNKNOWN)
continue;
if (diff_unmodified_pair(p))
continue;
if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
(DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
continue;
if (DIFF_PAIR_UNMERGED(p))
continue;
diff_fill_sha1_info(p->one);
diff_fill_sha1_info(p->two);
if (fill_mmfile(&mf1, p->one) < 0 ||
fill_mmfile(&mf2, p->two) < 0)
return error("unable to read files to diff");
/* Maybe hash p->two? into the patch id? */
if (mmfile_is_binary(&mf2))
continue;
len1 = remove_space(p->one->path, strlen(p->one->path));
len2 = remove_space(p->two->path, strlen(p->two->path));
if (p->one->mode == 0)
len1 = snprintf(buffer, sizeof(buffer),
"diff--gita/%.*sb/%.*s"
"newfilemode%06o"
"---/dev/null"
"+++b/%.*s",
len1, p->one->path,
len2, p->two->path,
p->two->mode,
len2, p->two->path);
else if (p->two->mode == 0)
len1 = snprintf(buffer, sizeof(buffer),
"diff--gita/%.*sb/%.*s"
"deletedfilemode%06o"
"---a/%.*s"
"+++/dev/null",
len1, p->one->path,
len2, p->two->path,
p->one->mode,
len1, p->one->path);
else
len1 = snprintf(buffer, sizeof(buffer),
"diff--gita/%.*sb/%.*s"
"---a/%.*s"
"+++b/%.*s",
len1, p->one->path,
len2, p->two->path,
len1, p->one->path,
len2, p->two->path);
SHA1_Update(&ctx, buffer, len1);
xpp.flags = XDF_NEED_MINIMAL;
xecfg.ctxlen = 3;
xecfg.flags = 3;
ecb.outf = xdiff_outf;
ecb.priv = &data;
xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
}
SHA1_Final(sha1, &ctx);
return 0;
}
int diff_flush_patch_id(struct diff_options *options, unsigned char *sha1)
{
struct diff_queue_struct *q = &diff_queued_diff;
int i;
int result = diff_get_patch_id(options, sha1);
for (i = 0; i < q->nr; i++)
diff_free_filepair(q->queue[i]);
free(q->queue);
q->queue = NULL;
q->nr = q->alloc = 0;
return result;
}
void diff_flush(struct diff_options *options)
{
struct diff_queue_struct *q = &diff_queued_diff;

2
diff.h
View File

@@ -184,4 +184,6 @@ extern int run_diff_files(struct rev_info *revs, int silent_on_removed);
extern int run_diff_index(struct rev_info *revs, int cached);
extern int diff_flush_patch_id(struct diff_options *, unsigned char *);
#endif /* DIFF_H */

View File

@@ -1,5 +1,6 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include "cache.h"

View File

@@ -1,6 +1,8 @@
#ifndef PKTLINE_H
#define PKTLINE_H
#include "git-compat-util.h"
/*
* Silly packetized line writing interface
*/

69
t/t4014-format-patch.sh Executable file
View File

@@ -0,0 +1,69 @@
#!/bin/sh
#
# Copyright (c) 2006 Junio C Hamano
#
test_description='Format-patch skipping already incorporated patches'
. ./test-lib.sh
test_expect_success setup '
for i in 1 2 3 4 5 6 7 8 9 10; do echo "$i"; done >file &&
git add file &&
git commit -m Initial &&
git checkout -b side &&
for i in 1 2 5 6 A B C 7 8 9 10; do echo "$i"; done >file &&
git update-index file &&
git commit -m "Side change #1" &&
for i in D E F; do echo "$i"; done >>file &&
git update-index file &&
git commit -m "Side change #2" &&
git tag C1 &&
for i in 5 6 1 2 3 A 4 B C 7 8 9 10 D E F; do echo "$i"; done >file &&
git update-index file &&
git commit -m "Side change #3" &&
git checkout master &&
git diff-tree -p C1 | git apply --index &&
git commit -m "Master accepts moral equivalent of #1"
'
test_expect_success "format-patch --ignore-if-in-upstream" '
git format-patch --stdout master..side >patch0 &&
cnt=`grep "^From " patch0 | wc -l` &&
test "$cnt" = 3
'
test_expect_success "format-patch --ignore-if-in-upstream" '
git format-patch --stdout \
--ignore-if-in-upstream master..side >patch1 &&
cnt=`grep "^From " patch1 | wc -l` &&
test "$cnt" = 2
'
test_expect_success "format-patch result applies" '
git checkout -b rebuild-0 master &&
git am -3 patch0 &&
cnt=`git rev-list master.. | wc -l` &&
test "$cnt" = 2
'
test_expect_success "format-patch --ignore-if-in-upstream result applies" '
git checkout -b rebuild-1 master &&
git am -3 patch1 &&
cnt=`git rev-list master.. | wc -l` &&
test "$cnt" = 2
'
test_done