Built-in cherry
This replaces the shell script git-cherry with a version written in C. The behaviour of the new version differs from the original in two points: it has no long help any more, and it is handling the (optional) third parameter a bit differently. Basically, it does the equivalent of ours=`git-rev-list $ours ^$limit ^$upstream` instead of ours=`git-rev-list $ours ^$limit` Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <junkio@cox.net>maint
parent
1259404c7e
commit
e827633a5d
4
Makefile
4
Makefile
|
@ -157,7 +157,7 @@ BASIC_LDFLAGS =
|
||||||
|
|
||||||
SCRIPT_SH = \
|
SCRIPT_SH = \
|
||||||
git-bisect.sh git-branch.sh git-checkout.sh \
|
git-bisect.sh git-branch.sh git-checkout.sh \
|
||||||
git-cherry.sh git-clean.sh git-clone.sh git-commit.sh \
|
git-clean.sh git-clone.sh git-commit.sh \
|
||||||
git-fetch.sh \
|
git-fetch.sh \
|
||||||
git-ls-remote.sh \
|
git-ls-remote.sh \
|
||||||
git-merge-one-file.sh git-parse-remote.sh \
|
git-merge-one-file.sh git-parse-remote.sh \
|
||||||
|
@ -210,7 +210,7 @@ PROGRAMS = \
|
||||||
EXTRA_PROGRAMS =
|
EXTRA_PROGRAMS =
|
||||||
|
|
||||||
BUILT_INS = \
|
BUILT_INS = \
|
||||||
git-format-patch$X git-show$X git-whatchanged$X \
|
git-format-patch$X git-show$X git-whatchanged$X git-cherry$X \
|
||||||
git-get-tar-commit-id$X \
|
git-get-tar-commit-id$X \
|
||||||
$(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
|
$(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
|
||||||
|
|
||||||
|
|
106
builtin-log.c
106
builtin-log.c
|
@ -437,3 +437,109 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
|
||||||
|
{
|
||||||
|
unsigned char sha1[20];
|
||||||
|
if (get_sha1(arg, sha1) == 0) {
|
||||||
|
struct commit *commit = lookup_commit_reference(sha1);
|
||||||
|
if (commit) {
|
||||||
|
commit->object.flags |= flags;
|
||||||
|
add_pending_object(revs, &commit->object, arg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char cherry_usage[] =
|
||||||
|
"git-cherry [-v] <upstream> [<head>] [<limit>]";
|
||||||
|
int cmd_cherry(int argc, const char **argv, const char *prefix)
|
||||||
|
{
|
||||||
|
struct rev_info revs;
|
||||||
|
struct diff_options patch_id_opts;
|
||||||
|
struct commit *commit;
|
||||||
|
struct commit_list *list = NULL;
|
||||||
|
const char *upstream;
|
||||||
|
const char *head = "HEAD";
|
||||||
|
const char *limit = NULL;
|
||||||
|
int verbose = 0;
|
||||||
|
|
||||||
|
if (argc > 1 && !strcmp(argv[1], "-v")) {
|
||||||
|
verbose = 1;
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (argc) {
|
||||||
|
case 4:
|
||||||
|
limit = argv[3];
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case 3:
|
||||||
|
head = argv[2];
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case 2:
|
||||||
|
upstream = argv[1];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage(cherry_usage);
|
||||||
|
}
|
||||||
|
|
||||||
|
init_revisions(&revs, prefix);
|
||||||
|
revs.diff = 1;
|
||||||
|
revs.combine_merges = 0;
|
||||||
|
revs.ignore_merges = 1;
|
||||||
|
revs.diffopt.recursive = 1;
|
||||||
|
|
||||||
|
if (add_pending_commit(head, &revs, 0))
|
||||||
|
die("Unknown commit %s", head);
|
||||||
|
if (add_pending_commit(upstream, &revs, UNINTERESTING))
|
||||||
|
die("Unknown commit %s", upstream);
|
||||||
|
|
||||||
|
/* Don't say anything if head and upstream are the same. */
|
||||||
|
if (revs.pending.nr == 2) {
|
||||||
|
struct object_array_entry *o = revs.pending.objects;
|
||||||
|
if (hashcmp(o[0].item->sha1, o[1].item->sha1) == 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_patch_ids(&revs, &patch_id_opts, prefix);
|
||||||
|
|
||||||
|
if (limit && add_pending_commit(limit, &revs, UNINTERESTING))
|
||||||
|
die("Unknown commit %s", limit);
|
||||||
|
|
||||||
|
/* reverse the list of commits */
|
||||||
|
prepare_revision_walk(&revs);
|
||||||
|
while ((commit = get_revision(&revs)) != NULL) {
|
||||||
|
/* ignore merges */
|
||||||
|
if (commit->parents && commit->parents->next)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
commit_list_insert(commit, &list);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (list) {
|
||||||
|
unsigned char sha1[20];
|
||||||
|
char sign = '+';
|
||||||
|
|
||||||
|
commit = list->item;
|
||||||
|
if (!get_patch_id(commit, &patch_id_opts, sha1) &&
|
||||||
|
lookup_object(sha1))
|
||||||
|
sign = '-';
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
static char buf[16384];
|
||||||
|
pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
|
||||||
|
buf, sizeof(buf), 0, NULL, NULL, 0);
|
||||||
|
printf("%c %s %s\n", sign,
|
||||||
|
sha1_to_hex(commit->object.sha1), buf);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("%c %s\n", sign,
|
||||||
|
sha1_to_hex(commit->object.sha1));
|
||||||
|
}
|
||||||
|
|
||||||
|
list = list->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ extern int cmd_archive(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_cat_file(int argc, const char **argv, const char *prefix);
|
extern int cmd_cat_file(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_checkout_index(int argc, const char **argv, const char *prefix);
|
extern int cmd_checkout_index(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
|
extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
|
||||||
|
extern int cmd_cherry(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
|
extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
|
extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
|
extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# Copyright (c) 2005 Junio C Hamano.
|
|
||||||
#
|
|
||||||
|
|
||||||
USAGE='[-v] <upstream> [<head>] [<limit>]'
|
|
||||||
LONG_USAGE=' __*__*__*__*__> <upstream>
|
|
||||||
/
|
|
||||||
fork-point
|
|
||||||
\__+__+__+__+__+__+__+__> <head>
|
|
||||||
|
|
||||||
Each commit between the fork-point (or <limit> if given) and <head> is
|
|
||||||
examined, and compared against the change each commit between the
|
|
||||||
fork-point and <upstream> introduces. If the change seems to be in
|
|
||||||
the upstream, it is shown on the standard output with prefix "+".
|
|
||||||
Otherwise it is shown with prefix "-".'
|
|
||||||
. git-sh-setup
|
|
||||||
|
|
||||||
case "$1" in -v) verbose=t; shift ;; esac
|
|
||||||
|
|
||||||
case "$#,$1" in
|
|
||||||
1,*..*)
|
|
||||||
upstream=$(expr "z$1" : 'z\(.*\)\.\.') ours=$(expr "z$1" : '.*\.\.\(.*\)$')
|
|
||||||
set x "$upstream" "$ours"
|
|
||||||
shift ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
case "$#" in
|
|
||||||
1) upstream=`git-rev-parse --verify "$1"` &&
|
|
||||||
ours=`git-rev-parse --verify HEAD` || exit
|
|
||||||
limit="$upstream"
|
|
||||||
;;
|
|
||||||
2) upstream=`git-rev-parse --verify "$1"` &&
|
|
||||||
ours=`git-rev-parse --verify "$2"` || exit
|
|
||||||
limit="$upstream"
|
|
||||||
;;
|
|
||||||
3) upstream=`git-rev-parse --verify "$1"` &&
|
|
||||||
ours=`git-rev-parse --verify "$2"` &&
|
|
||||||
limit=`git-rev-parse --verify "$3"` || exit
|
|
||||||
;;
|
|
||||||
*) usage ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Note that these list commits in reverse order;
|
|
||||||
# not that the order in inup matters...
|
|
||||||
inup=`git-rev-list ^$ours $upstream` &&
|
|
||||||
ours=`git-rev-list $ours ^$limit` || exit
|
|
||||||
|
|
||||||
tmp=.cherry-tmp$$
|
|
||||||
patch=$tmp-patch
|
|
||||||
mkdir $patch
|
|
||||||
trap "rm -rf $tmp-*" 0 1 2 3 15
|
|
||||||
|
|
||||||
for c in $inup
|
|
||||||
do
|
|
||||||
git-diff-tree -p $c
|
|
||||||
done | git-patch-id |
|
|
||||||
while read id name
|
|
||||||
do
|
|
||||||
echo $name >>$patch/$id
|
|
||||||
done
|
|
||||||
|
|
||||||
LF='
|
|
||||||
'
|
|
||||||
|
|
||||||
O=
|
|
||||||
for c in $ours
|
|
||||||
do
|
|
||||||
set x `git-diff-tree -p $c | git-patch-id`
|
|
||||||
if test "$2" != ""
|
|
||||||
then
|
|
||||||
if test -f "$patch/$2"
|
|
||||||
then
|
|
||||||
sign=-
|
|
||||||
else
|
|
||||||
sign=+
|
|
||||||
fi
|
|
||||||
case "$verbose" in
|
|
||||||
t)
|
|
||||||
c=$(git-rev-list --pretty=oneline --max-count=1 $c)
|
|
||||||
esac
|
|
||||||
case "$O" in
|
|
||||||
'') O="$sign $c" ;;
|
|
||||||
*) O="$sign $c$LF$O" ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
case "$O" in
|
|
||||||
'') ;;
|
|
||||||
*) echo "$O" ;;
|
|
||||||
esac
|
|
1
git.c
1
git.c
|
@ -224,6 +224,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
|
||||||
{ "cat-file", cmd_cat_file, RUN_SETUP },
|
{ "cat-file", cmd_cat_file, RUN_SETUP },
|
||||||
{ "checkout-index", cmd_checkout_index, RUN_SETUP },
|
{ "checkout-index", cmd_checkout_index, RUN_SETUP },
|
||||||
{ "check-ref-format", cmd_check_ref_format },
|
{ "check-ref-format", cmd_check_ref_format },
|
||||||
|
{ "cherry", cmd_cherry, RUN_SETUP },
|
||||||
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
|
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
|
||||||
{ "count-objects", cmd_count_objects, RUN_SETUP },
|
{ "count-objects", cmd_count_objects, RUN_SETUP },
|
||||||
{ "diff", cmd_diff, RUN_SETUP | USE_PAGER },
|
{ "diff", cmd_diff, RUN_SETUP | USE_PAGER },
|
||||||
|
|
Loading…
Reference in New Issue