Merge branches 'jc/apply', 'lt/ls-tree', 'lt/bisect' and 'lt/merge'
commit
5401f3040b
|
@ -21,6 +21,15 @@ OPTIONS
|
||||||
-------
|
-------
|
||||||
include::diff-options.txt[]
|
include::diff-options.txt[]
|
||||||
|
|
||||||
|
-1 -2 -3 or --base --ours --theirs, and -0::
|
||||||
|
Diff against the "base" version, "our branch" or "their
|
||||||
|
branch" respectively. With these options, diffs for
|
||||||
|
merged entries are not shown.
|
||||||
|
+
|
||||||
|
The default is to diff against our branch (-2) and the
|
||||||
|
cleanly resolved paths. The option -0 can be given to
|
||||||
|
omit diff output for unmerged entries and just show "Unmerged".
|
||||||
|
|
||||||
-q::
|
-q::
|
||||||
Remain silent even on nonexisting files
|
Remain silent even on nonexisting files
|
||||||
|
|
||||||
|
|
|
@ -898,9 +898,8 @@ file, which had no differences in the `mybranch` branch), and say:
|
||||||
fatal: Merge requires file-level merging
|
fatal: Merge requires file-level merging
|
||||||
Nope.
|
Nope.
|
||||||
...
|
...
|
||||||
merge: warning: conflicts during merge
|
Auto-merging hello
|
||||||
ERROR: Merge conflict in hello.
|
CONFLICT (content): Merge conflict in hello
|
||||||
fatal: merge program failed
|
|
||||||
Automatic merge failed/prevented; fix up by hand
|
Automatic merge failed/prevented; fix up by hand
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
@ -942,10 +941,10 @@ environment, is `git show-branch`.
|
||||||
|
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
$ git show-branch master mybranch
|
$ git show-branch master mybranch
|
||||||
* [master] Merged "mybranch" changes.
|
* [master] Merge work in mybranch
|
||||||
! [mybranch] Some work.
|
! [mybranch] Some work.
|
||||||
--
|
--
|
||||||
+ [master] Merged "mybranch" changes.
|
+ [master] Merge work in mybranch
|
||||||
++ [mybranch] Some work.
|
++ [mybranch] Some work.
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
|
@ -998,10 +997,10 @@ looks like, or run `show-branch`, which tells you this.
|
||||||
|
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
$ git show-branch master mybranch
|
$ git show-branch master mybranch
|
||||||
! [master] Merged "mybranch" changes.
|
! [master] Merge work in mybranch
|
||||||
* [mybranch] Merged "mybranch" changes.
|
* [mybranch] Merge work in mybranch
|
||||||
--
|
--
|
||||||
++ [master] Merged "mybranch" changes.
|
++ [master] Merge work in mybranch
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
43
diff-files.c
43
diff-files.c
|
@ -7,12 +7,12 @@
|
||||||
#include "diff.h"
|
#include "diff.h"
|
||||||
|
|
||||||
static const char diff_files_usage[] =
|
static const char diff_files_usage[] =
|
||||||
"git-diff-files [-q] "
|
"git-diff-files [-q] [-0/-1/2/3] [<common diff options>] [<path>...]"
|
||||||
"[<common diff options>] [<path>...]"
|
|
||||||
COMMON_DIFF_OPTIONS_HELP;
|
COMMON_DIFF_OPTIONS_HELP;
|
||||||
|
|
||||||
static struct diff_options diff_options;
|
static struct diff_options diff_options;
|
||||||
static int silent = 0;
|
static int silent = 0;
|
||||||
|
static int diff_unmerged_stage = 2;
|
||||||
|
|
||||||
static void show_unmerge(const char *path)
|
static void show_unmerge(const char *path)
|
||||||
{
|
{
|
||||||
|
@ -46,7 +46,21 @@ int main(int argc, const char **argv)
|
||||||
argc--;
|
argc--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!strcmp(argv[1], "-q"))
|
if (!strcmp(argv[1], "-0"))
|
||||||
|
diff_unmerged_stage = 0;
|
||||||
|
else if (!strcmp(argv[1], "-1"))
|
||||||
|
diff_unmerged_stage = 1;
|
||||||
|
else if (!strcmp(argv[1], "-2"))
|
||||||
|
diff_unmerged_stage = 2;
|
||||||
|
else if (!strcmp(argv[1], "-3"))
|
||||||
|
diff_unmerged_stage = 3;
|
||||||
|
else if (!strcmp(argv[1], "--base"))
|
||||||
|
diff_unmerged_stage = 1;
|
||||||
|
else if (!strcmp(argv[1], "--ours"))
|
||||||
|
diff_unmerged_stage = 2;
|
||||||
|
else if (!strcmp(argv[1], "--theirs"))
|
||||||
|
diff_unmerged_stage = 3;
|
||||||
|
else if (!strcmp(argv[1], "-q"))
|
||||||
silent = 1;
|
silent = 1;
|
||||||
else if (!strcmp(argv[1], "-r"))
|
else if (!strcmp(argv[1], "-r"))
|
||||||
; /* no-op */
|
; /* no-op */
|
||||||
|
@ -95,11 +109,26 @@ int main(int argc, const char **argv)
|
||||||
|
|
||||||
if (ce_stage(ce)) {
|
if (ce_stage(ce)) {
|
||||||
show_unmerge(ce->name);
|
show_unmerge(ce->name);
|
||||||
while (i < entries &&
|
while (i < entries) {
|
||||||
!strcmp(ce->name, active_cache[i]->name))
|
struct cache_entry *nce = active_cache[i];
|
||||||
|
|
||||||
|
if (strcmp(ce->name, nce->name))
|
||||||
|
break;
|
||||||
|
/* diff against the proper unmerged stage */
|
||||||
|
if (ce_stage(nce) == diff_unmerged_stage)
|
||||||
|
ce = nce;
|
||||||
i++;
|
i++;
|
||||||
i--; /* compensate for loop control increments */
|
}
|
||||||
continue;
|
/*
|
||||||
|
* Compensate for loop update
|
||||||
|
*/
|
||||||
|
i--;
|
||||||
|
/*
|
||||||
|
* Show the diff for the 'ce' if we found the one
|
||||||
|
* from the desired stage.
|
||||||
|
*/
|
||||||
|
if (ce_stage(ce) != diff_unmerged_stage)
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lstat(ce->name, &st) < 0) {
|
if (lstat(ce->name, &st) < 0) {
|
||||||
|
|
|
@ -33,7 +33,7 @@ do
|
||||||
-k) keep_subject=-k ;;
|
-k) keep_subject=-k ;;
|
||||||
-q) query_apply=t ;;
|
-q) query_apply=t ;;
|
||||||
-c) continue="$2"; resume=f; shift ;;
|
-c) continue="$2"; resume=f; shift ;;
|
||||||
-m) fallback_3way=t ;;
|
-m) fall_back_3way=t ;;
|
||||||
-*) usage ;;
|
-*) usage ;;
|
||||||
*) break ;;
|
*) break ;;
|
||||||
esac
|
esac
|
||||||
|
|
|
@ -120,26 +120,36 @@ git-apply --index "$PATCHFILE" || {
|
||||||
O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
|
O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
|
||||||
rm -fr .patch-merge-*
|
rm -fr .patch-merge-*
|
||||||
|
|
||||||
|
if git-apply -z --index-info "$PATCHFILE" \
|
||||||
|
>.patch-merge-index-info 2>/dev/null &&
|
||||||
|
GIT_INDEX_FILE=.patch-merge-tmp-index \
|
||||||
|
git-update-index -z --index-info <.patch-merge-index-info &&
|
||||||
|
GIT_INDEX_FILE=.patch-merge-tmp-index \
|
||||||
|
git-write-tree >.patch-merge-tmp-base &&
|
||||||
|
(
|
||||||
|
mkdir .patch-merge-tmp-dir &&
|
||||||
|
cd .patch-merge-tmp-dir &&
|
||||||
|
GIT_INDEX_FILE="../.patch-merge-tmp-index" \
|
||||||
|
GIT_OBJECT_DIRECTORY="$O_OBJECT" \
|
||||||
|
git-apply $binary --index
|
||||||
|
) <"$PATCHFILE"
|
||||||
|
then
|
||||||
|
echo Using index info to reconstruct a base tree...
|
||||||
|
mv .patch-merge-tmp-base .patch-merge-base
|
||||||
|
mv .patch-merge-tmp-index .patch-merge-index
|
||||||
|
else
|
||||||
(
|
(
|
||||||
N=10
|
N=10
|
||||||
|
|
||||||
# if the patch records the base tree...
|
# Otherwise, try nearby trees that can be used to apply the
|
||||||
sed -ne '
|
# patch.
|
||||||
/^diff /q
|
|
||||||
/^applies-to: \([0-9a-f]*\)$/{
|
|
||||||
s//\1/p
|
|
||||||
q
|
|
||||||
}
|
|
||||||
' "$PATCHFILE"
|
|
||||||
|
|
||||||
# or hoping the patch is against our recent commits...
|
|
||||||
git-rev-list --max-count=$N HEAD
|
git-rev-list --max-count=$N HEAD
|
||||||
|
|
||||||
# or hoping the patch is against known tags...
|
# or hoping the patch is against known tags...
|
||||||
git-ls-remote --tags .
|
git-ls-remote --tags .
|
||||||
) |
|
) |
|
||||||
while read base junk
|
while read base junk
|
||||||
do
|
do
|
||||||
# Try it if we have it as a tree.
|
# Try it if we have it as a tree.
|
||||||
git-cat-file tree "$base" >/dev/null 2>&1 || continue
|
git-cat-file tree "$base" >/dev/null 2>&1 || continue
|
||||||
|
|
||||||
|
@ -155,7 +165,8 @@ git-apply --index "$PATCHFILE" || {
|
||||||
mv ../.patch-merge-tmp-index ../.patch-merge-index &&
|
mv ../.patch-merge-tmp-index ../.patch-merge-index &&
|
||||||
echo "$base" >../.patch-merge-base
|
echo "$base" >../.patch-merge-base
|
||||||
) <"$PATCHFILE" 2>/dev/null && break
|
) <"$PATCHFILE" 2>/dev/null && break
|
||||||
done
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
test -f .patch-merge-index &&
|
test -f .patch-merge-index &&
|
||||||
his_tree=$(GIT_INDEX_FILE=.patch-merge-index git-write-tree) &&
|
his_tree=$(GIT_INDEX_FILE=.patch-merge-index git-write-tree) &&
|
||||||
|
|
|
@ -1,9 +1,19 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
. git-sh-setup
|
. git-sh-setup
|
||||||
|
|
||||||
|
sq() {
|
||||||
|
perl -e '
|
||||||
|
for (@ARGV) {
|
||||||
|
s/'\''/'\'\\\\\'\''/g;
|
||||||
|
print " '\''$_'\''";
|
||||||
|
}
|
||||||
|
print "\n";
|
||||||
|
' "$@"
|
||||||
|
}
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
echo >&2 'usage: git bisect [start|bad|good|next|reset|visualize]
|
echo >&2 'usage: git bisect [start|bad|good|next|reset|visualize]
|
||||||
git bisect start reset bisect state and start bisection.
|
git bisect start [<pathspec>] reset bisect state and start bisection.
|
||||||
git bisect bad [<rev>] mark <rev> a known-bad revision.
|
git bisect bad [<rev>] mark <rev> a known-bad revision.
|
||||||
git bisect good [<rev>...] mark <rev>... known-good revisions.
|
git bisect good [<rev>...] mark <rev>... known-good revisions.
|
||||||
git bisect next find next bisection to test and check it out.
|
git bisect next find next bisection to test and check it out.
|
||||||
|
@ -33,7 +43,6 @@ bisect_autostart() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bisect_start() {
|
bisect_start() {
|
||||||
case "$#" in 0) ;; *) usage ;; esac
|
|
||||||
#
|
#
|
||||||
# Verify HEAD. If we were bisecting before this, reset to the
|
# Verify HEAD. If we were bisecting before this, reset to the
|
||||||
# top-of-line master first!
|
# top-of-line master first!
|
||||||
|
@ -57,7 +66,11 @@ bisect_start() {
|
||||||
rm -f "$GIT_DIR/refs/heads/bisect"
|
rm -f "$GIT_DIR/refs/heads/bisect"
|
||||||
rm -rf "$GIT_DIR/refs/bisect/"
|
rm -rf "$GIT_DIR/refs/bisect/"
|
||||||
mkdir "$GIT_DIR/refs/bisect"
|
mkdir "$GIT_DIR/refs/bisect"
|
||||||
echo "git-bisect start" >"$GIT_DIR/BISECT_LOG"
|
{
|
||||||
|
echo -n "git-bisect start"
|
||||||
|
sq "$@"
|
||||||
|
} >"$GIT_DIR/BISECT_LOG"
|
||||||
|
sq "$@" >"$GIT_DIR/BISECT_NAMES"
|
||||||
}
|
}
|
||||||
|
|
||||||
bisect_bad() {
|
bisect_bad() {
|
||||||
|
@ -121,7 +134,7 @@ bisect_next() {
|
||||||
bad=$(git-rev-parse --verify refs/bisect/bad) &&
|
bad=$(git-rev-parse --verify refs/bisect/bad) &&
|
||||||
good=$(git-rev-parse --sq --revs-only --not \
|
good=$(git-rev-parse --sq --revs-only --not \
|
||||||
$(cd "$GIT_DIR" && ls refs/bisect/good-*)) &&
|
$(cd "$GIT_DIR" && ls refs/bisect/good-*)) &&
|
||||||
rev=$(eval "git-rev-list --bisect $good $bad") || exit
|
rev=$(eval "git-rev-list --bisect $good $bad -- $(cat $GIT_DIR/BISECT_NAMES)") || exit
|
||||||
if [ -z "$rev" ]; then
|
if [ -z "$rev" ]; then
|
||||||
echo "$bad was both good and bad"
|
echo "$bad was both good and bad"
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -131,7 +144,7 @@ bisect_next() {
|
||||||
git-diff-tree --pretty $rev
|
git-diff-tree --pretty $rev
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
nr=$(eval "git-rev-list $rev $good" | wc -l) || exit
|
nr=$(eval "git-rev-list $rev $good -- $(cat $GIT_DIR/BISECT_NAMES)" | wc -l) || exit
|
||||||
echo "Bisecting: $nr revisions left to test after this"
|
echo "Bisecting: $nr revisions left to test after this"
|
||||||
echo "$rev" > "$GIT_DIR/refs/heads/new-bisect"
|
echo "$rev" > "$GIT_DIR/refs/heads/new-bisect"
|
||||||
git checkout new-bisect || exit
|
git checkout new-bisect || exit
|
||||||
|
@ -142,7 +155,8 @@ bisect_next() {
|
||||||
|
|
||||||
bisect_visualize() {
|
bisect_visualize() {
|
||||||
bisect_next_check fail
|
bisect_next_check fail
|
||||||
gitk bisect/bad --not `cd "$GIT_DIR/refs" && echo bisect/good-*`
|
not=`cd "$GIT_DIR/refs" && echo bisect/good-*`
|
||||||
|
eval gitk bisect/bad --not $not -- $(cat "$GIT_DIR/BISECT_NAMES")
|
||||||
}
|
}
|
||||||
|
|
||||||
bisect_reset() {
|
bisect_reset() {
|
||||||
|
@ -173,7 +187,8 @@ bisect_replay () {
|
||||||
test "$bisect" = "git-bisect" || continue
|
test "$bisect" = "git-bisect" || continue
|
||||||
case "$command" in
|
case "$command" in
|
||||||
start)
|
start)
|
||||||
bisect_start
|
cmd="bisect_start $rev"
|
||||||
|
eval "$cmd"
|
||||||
;;
|
;;
|
||||||
good)
|
good)
|
||||||
echo "$rev" >"$GIT_DIR/refs/bisect/good-$rev"
|
echo "$rev" >"$GIT_DIR/refs/bisect/good-$rev"
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
|
|
||||||
. git-sh-setup
|
. git-sh-setup
|
||||||
|
|
||||||
|
# Force diff to run in C locale.
|
||||||
|
LANG=C LC_ALL=C
|
||||||
|
export LANG LC_ALL
|
||||||
|
|
||||||
usage () {
|
usage () {
|
||||||
echo >&2 "usage: $0"' [-n] [-o dir | --stdout] [--keep-subject] [--mbox]
|
echo >&2 "usage: $0"' [-n] [-o dir | --stdout] [--keep-subject] [--mbox]
|
||||||
[--check] [--signoff] [-<diff options>...]
|
[--check] [--signoff] [-<diff options>...]
|
||||||
|
@ -202,7 +206,7 @@ process_one () {
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
eval "$(LANG=C LC_ALL=C sed -ne "$whosepatchScript" $commsg)"
|
eval "$(sed -ne "$whosepatchScript" $commsg)"
|
||||||
test "$author,$au" = ",$me" || {
|
test "$author,$au" = ",$me" || {
|
||||||
mailScript="$mailScript"'
|
mailScript="$mailScript"'
|
||||||
a\
|
a\
|
||||||
|
@ -238,9 +242,8 @@ Date: '"$ad"
|
||||||
echo
|
echo
|
||||||
git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary
|
git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary
|
||||||
echo
|
echo
|
||||||
git-cat-file commit "$commit^" | sed -e 's/^tree /applies-to: /' -e q
|
|
||||||
git-diff-tree -p $diff_opts "$commit"
|
git-diff-tree -p $diff_opts "$commit"
|
||||||
echo "---"
|
echo "-- "
|
||||||
echo "@@GIT_VERSION@@"
|
echo "@@GIT_VERSION@@"
|
||||||
|
|
||||||
case "$mbox" in
|
case "$mbox" in
|
||||||
|
|
|
@ -79,11 +79,7 @@ case "${1:-.}${2:-.}${3:-.}" in
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# We reset the index to the first branch, making
|
merge "$4" "$orig" "$src2"
|
||||||
# git-diff-file useful
|
|
||||||
git-update-index --add --cacheinfo "$6" "$2" "$4"
|
|
||||||
git-checkout-index -u -f -- "$4" &&
|
|
||||||
merge "$4" "$orig" "$src2"
|
|
||||||
ret=$?
|
ret=$?
|
||||||
rm -f -- "$orig" "$src2"
|
rm -f -- "$orig" "$src2"
|
||||||
|
|
||||||
|
|
|
@ -828,8 +828,6 @@ def processEntry(entry, branch1Name, branch2Name):
|
||||||
if cacheOnly:
|
if cacheOnly:
|
||||||
updateFile(False, sha, mode, path)
|
updateFile(False, sha, mode, path)
|
||||||
else:
|
else:
|
||||||
updateFileExt(aSha, aMode, path,
|
|
||||||
updateCache=True, updateWd=False)
|
|
||||||
updateFileExt(sha, mode, path, updateCache=False, updateWd=True)
|
updateFileExt(sha, mode, path, updateCache=False, updateWd=True)
|
||||||
else:
|
else:
|
||||||
die("ERROR: Fatal merge failure, shouldn't happen.")
|
die("ERROR: Fatal merge failure, shouldn't happen.")
|
||||||
|
|
260
ls-tree.c
260
ls-tree.c
|
@ -12,218 +12,56 @@ static int line_termination = '\n';
|
||||||
#define LS_RECURSIVE 1
|
#define LS_RECURSIVE 1
|
||||||
#define LS_TREE_ONLY 2
|
#define LS_TREE_ONLY 2
|
||||||
static int ls_options = 0;
|
static int ls_options = 0;
|
||||||
|
const char **pathspec;
|
||||||
static struct tree_entry_list root_entry;
|
|
||||||
|
|
||||||
static void prepare_root(unsigned char *sha1)
|
|
||||||
{
|
|
||||||
unsigned char rsha[20];
|
|
||||||
unsigned long size;
|
|
||||||
void *buf;
|
|
||||||
struct tree *root_tree;
|
|
||||||
|
|
||||||
buf = read_object_with_reference(sha1, "tree", &size, rsha);
|
|
||||||
free(buf);
|
|
||||||
if (!buf)
|
|
||||||
die("Could not read %s", sha1_to_hex(sha1));
|
|
||||||
|
|
||||||
root_tree = lookup_tree(rsha);
|
|
||||||
if (!root_tree)
|
|
||||||
die("Could not read %s", sha1_to_hex(sha1));
|
|
||||||
|
|
||||||
/* Prepare a fake entry */
|
|
||||||
root_entry.directory = 1;
|
|
||||||
root_entry.executable = root_entry.symlink = 0;
|
|
||||||
root_entry.mode = S_IFDIR;
|
|
||||||
root_entry.name = "";
|
|
||||||
root_entry.item.tree = root_tree;
|
|
||||||
root_entry.parent = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int prepare_children(struct tree_entry_list *elem)
|
|
||||||
{
|
|
||||||
if (!elem->directory)
|
|
||||||
return -1;
|
|
||||||
if (!elem->item.tree->object.parsed) {
|
|
||||||
struct tree_entry_list *e;
|
|
||||||
if (parse_tree(elem->item.tree))
|
|
||||||
return -1;
|
|
||||||
/* Set up the parent link */
|
|
||||||
for (e = elem->item.tree->entries; e; e = e->next)
|
|
||||||
e->parent = elem;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct tree_entry_list *find_entry(const char *path, char *pathbuf)
|
|
||||||
{
|
|
||||||
const char *next, *slash;
|
|
||||||
int len;
|
|
||||||
struct tree_entry_list *elem = &root_entry, *oldelem = NULL;
|
|
||||||
|
|
||||||
*(pathbuf) = '\0';
|
|
||||||
|
|
||||||
/* Find tree element, descending from root, that
|
|
||||||
* corresponds to the named path, lazily expanding
|
|
||||||
* the tree if possible.
|
|
||||||
*/
|
|
||||||
|
|
||||||
while (path) {
|
|
||||||
/* The fact we still have path means that the caller
|
|
||||||
* wants us to make sure that elem at this point is a
|
|
||||||
* directory, and possibly descend into it. Even what
|
|
||||||
* is left is just trailing slashes, we loop back to
|
|
||||||
* here, and this call to prepare_children() will
|
|
||||||
* catch elem not being a tree. Nice.
|
|
||||||
*/
|
|
||||||
if (prepare_children(elem))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
slash = strchr(path, '/');
|
|
||||||
if (!slash) {
|
|
||||||
len = strlen(path);
|
|
||||||
next = NULL;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
next = slash + 1;
|
|
||||||
len = slash - path;
|
|
||||||
}
|
|
||||||
if (len) {
|
|
||||||
if (oldelem) {
|
|
||||||
pathbuf += sprintf(pathbuf, "%s/", oldelem->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (len == 0) if the original path was "drivers/char/"
|
|
||||||
* and we have run already two rounds, having elem
|
|
||||||
* pointing at the drivers/char directory.
|
|
||||||
*/
|
|
||||||
elem = elem->item.tree->entries;
|
|
||||||
while (elem) {
|
|
||||||
if ((strlen(elem->name) == len) &&
|
|
||||||
!strncmp(elem->name, path, len)) {
|
|
||||||
/* found */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
elem = elem->next;
|
|
||||||
}
|
|
||||||
if (!elem)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
oldelem = elem;
|
|
||||||
}
|
|
||||||
path = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return elem;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *entry_type(struct tree_entry_list *e)
|
|
||||||
{
|
|
||||||
return (e->directory ? "tree" : "blob");
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *entry_hex(struct tree_entry_list *e)
|
|
||||||
{
|
|
||||||
return sha1_to_hex(e->directory
|
|
||||||
? e->item.tree->object.sha1
|
|
||||||
: e->item.blob->object.sha1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* forward declaration for mutually recursive routines */
|
|
||||||
static int show_entry(struct tree_entry_list *, int, char *pathbuf);
|
|
||||||
|
|
||||||
static int show_children(struct tree_entry_list *e, int level, char *pathbuf)
|
|
||||||
{
|
|
||||||
int oldlen = strlen(pathbuf);
|
|
||||||
|
|
||||||
if (e != &root_entry)
|
|
||||||
sprintf(pathbuf + oldlen, "%s/", e->name);
|
|
||||||
|
|
||||||
if (prepare_children(e))
|
|
||||||
die("internal error: ls-tree show_children called with non tree");
|
|
||||||
e = e->item.tree->entries;
|
|
||||||
while (e) {
|
|
||||||
show_entry(e, level, pathbuf);
|
|
||||||
e = e->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
pathbuf[oldlen] = '\0';
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int show_entry(struct tree_entry_list *e, int level, char *pathbuf)
|
|
||||||
{
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (e != &root_entry) {
|
|
||||||
int pathlen = strlen(pathbuf);
|
|
||||||
printf("%06o %s %s ",
|
|
||||||
e->mode, entry_type(e), entry_hex(e));
|
|
||||||
write_name_quoted(pathbuf, pathlen, e->name,
|
|
||||||
line_termination, stdout);
|
|
||||||
putchar(line_termination);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e->directory) {
|
|
||||||
/* If this is a directory, we have the following cases:
|
|
||||||
* (1) This is the top-level request (explicit path from the
|
|
||||||
* command line, or "root" if there is no command line).
|
|
||||||
* a. Without any flag. We show direct children. We do not
|
|
||||||
* recurse into them.
|
|
||||||
* b. With -r. We do recurse into children.
|
|
||||||
* c. With -d. We do not recurse into children.
|
|
||||||
* (2) We came here because our caller is either (1-a) or
|
|
||||||
* (1-b).
|
|
||||||
* a. Without any flag. We do not show our children (which
|
|
||||||
* are grandchildren for the original request).
|
|
||||||
* b. With -r. We continue to recurse into our children.
|
|
||||||
* c. With -d. We should not have come here to begin with.
|
|
||||||
*/
|
|
||||||
if (level == 0 && !(ls_options & LS_TREE_ONLY))
|
|
||||||
/* case (1)-a and (1)-b */
|
|
||||||
err = err | show_children(e, level+1, pathbuf);
|
|
||||||
else if (level && ls_options & LS_RECURSIVE)
|
|
||||||
/* case (2)-b */
|
|
||||||
err = err | show_children(e, level+1, pathbuf);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int list_one(const char *path)
|
|
||||||
{
|
|
||||||
int err = 0;
|
|
||||||
char pathbuf[MAXPATHLEN + 1];
|
|
||||||
struct tree_entry_list *e = find_entry(path, pathbuf);
|
|
||||||
if (!e) {
|
|
||||||
/* traditionally ls-tree does not complain about
|
|
||||||
* missing path. We may change this later to match
|
|
||||||
* what "/bin/ls -a" does, which is to complain.
|
|
||||||
*/
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
err = err | show_entry(e, 0, pathbuf);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int list(char **path)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int err = 0;
|
|
||||||
for (i = 0; path[i]; i++)
|
|
||||||
err = err | list_one(path[i]);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char ls_tree_usage[] =
|
static const char ls_tree_usage[] =
|
||||||
"git-ls-tree [-d] [-r] [-z] <tree-ish> [path...]";
|
"git-ls-tree [-d] [-r] [-z] <tree-ish> [path...]";
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
static int show_tree(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
|
||||||
{
|
{
|
||||||
static char *path0[] = { "", NULL };
|
const char *type = "blob";
|
||||||
char **path;
|
|
||||||
unsigned char sha1[20];
|
|
||||||
|
|
||||||
|
if (S_ISDIR(mode)) {
|
||||||
|
const char **s;
|
||||||
|
if (ls_options & LS_RECURSIVE)
|
||||||
|
return READ_TREE_RECURSIVE;
|
||||||
|
s = pathspec;
|
||||||
|
if (s) {
|
||||||
|
for (;;) {
|
||||||
|
const char *spec = *s++;
|
||||||
|
int len, speclen;
|
||||||
|
|
||||||
|
if (!spec)
|
||||||
|
break;
|
||||||
|
if (strncmp(base, spec, baselen))
|
||||||
|
continue;
|
||||||
|
len = strlen(pathname);
|
||||||
|
spec += baselen;
|
||||||
|
speclen = strlen(spec);
|
||||||
|
if (speclen <= len)
|
||||||
|
continue;
|
||||||
|
if (memcmp(pathname, spec, len))
|
||||||
|
continue;
|
||||||
|
return READ_TREE_RECURSIVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type = "tree";
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%06o %s %s\t", mode, type, sha1_to_hex(sha1));
|
||||||
|
write_name_quoted(base, baselen, pathname, line_termination, stdout);
|
||||||
|
putchar(line_termination);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char **argv)
|
||||||
|
{
|
||||||
|
const char *prefix;
|
||||||
|
unsigned char sha1[20];
|
||||||
|
char *buf;
|
||||||
|
unsigned long size;
|
||||||
|
|
||||||
|
prefix = setup_git_directory();
|
||||||
while (1 < argc && argv[1][0] == '-') {
|
while (1 < argc && argv[1][0] == '-') {
|
||||||
switch (argv[1][1]) {
|
switch (argv[1][1]) {
|
||||||
case 'z':
|
case 'z':
|
||||||
|
@ -246,9 +84,11 @@ int main(int argc, char **argv)
|
||||||
if (get_sha1(argv[1], sha1) < 0)
|
if (get_sha1(argv[1], sha1) < 0)
|
||||||
usage(ls_tree_usage);
|
usage(ls_tree_usage);
|
||||||
|
|
||||||
path = (argc == 2) ? path0 : (argv + 2);
|
pathspec = get_pathspec(prefix, argv + 2);
|
||||||
prepare_root(sha1);
|
buf = read_object_with_reference(sha1, "tree", &size, NULL);
|
||||||
if (list(path) < 0)
|
if (!buf)
|
||||||
die("list failed");
|
die("not a tree object");
|
||||||
|
read_tree_recursive(buf, size, "", 0, 0, pathspec, show_tree);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
18
rev-list.c
18
rev-list.c
|
@ -350,7 +350,8 @@ static int count_distance(struct commit_list *entry)
|
||||||
|
|
||||||
if (commit->object.flags & (UNINTERESTING | COUNTED))
|
if (commit->object.flags & (UNINTERESTING | COUNTED))
|
||||||
break;
|
break;
|
||||||
nr++;
|
if (!paths || (commit->object.flags & TREECHANGE))
|
||||||
|
nr++;
|
||||||
commit->object.flags |= COUNTED;
|
commit->object.flags |= COUNTED;
|
||||||
p = commit->parents;
|
p = commit->parents;
|
||||||
entry = p;
|
entry = p;
|
||||||
|
@ -362,6 +363,7 @@ static int count_distance(struct commit_list *entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nr;
|
return nr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,15 +384,20 @@ static struct commit_list *find_bisection(struct commit_list *list)
|
||||||
nr = 0;
|
nr = 0;
|
||||||
p = list;
|
p = list;
|
||||||
while (p) {
|
while (p) {
|
||||||
nr++;
|
if (!paths || (p->item->object.flags & TREECHANGE))
|
||||||
|
nr++;
|
||||||
p = p->next;
|
p = p->next;
|
||||||
}
|
}
|
||||||
closest = 0;
|
closest = 0;
|
||||||
best = list;
|
best = list;
|
||||||
|
|
||||||
p = list;
|
for (p = list; p; p = p->next) {
|
||||||
while (p) {
|
int distance;
|
||||||
int distance = count_distance(p);
|
|
||||||
|
if (paths && !(p->item->object.flags & TREECHANGE))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
distance = count_distance(p);
|
||||||
clear_distance(list);
|
clear_distance(list);
|
||||||
if (nr - distance < distance)
|
if (nr - distance < distance)
|
||||||
distance = nr - distance;
|
distance = nr - distance;
|
||||||
|
@ -398,7 +405,6 @@ static struct commit_list *find_bisection(struct commit_list *list)
|
||||||
best = p;
|
best = p;
|
||||||
closest = distance;
|
closest = distance;
|
||||||
}
|
}
|
||||||
p = p->next;
|
|
||||||
}
|
}
|
||||||
if (best)
|
if (best)
|
||||||
best->next = NULL;
|
best->next = NULL;
|
||||||
|
|
|
@ -126,19 +126,18 @@ test_expect_success \
|
||||||
'git-ls-tree output for a known tree.' \
|
'git-ls-tree output for a known tree.' \
|
||||||
'diff current expected'
|
'diff current expected'
|
||||||
|
|
||||||
|
# This changed in ls-tree pathspec change -- recursive does
|
||||||
|
# not show tree nodes anymore.
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'showing tree with git-ls-tree -r' \
|
'showing tree with git-ls-tree -r' \
|
||||||
'git-ls-tree -r $tree >current'
|
'git-ls-tree -r $tree >current'
|
||||||
cat >expected <<\EOF
|
cat >expected <<\EOF
|
||||||
100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0
|
100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0
|
||||||
120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym
|
120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym
|
||||||
040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2
|
|
||||||
100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2
|
100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2
|
||||||
120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym
|
120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym
|
||||||
040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3
|
|
||||||
100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3
|
100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3
|
||||||
120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym
|
120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym
|
||||||
040000 tree 3c5e5399f3a333eddecce7a9b9465b63f65f51e2 path3/subp3
|
|
||||||
100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3
|
100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3
|
||||||
120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym
|
120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym
|
||||||
EOF
|
EOF
|
||||||
|
|
|
@ -54,8 +54,6 @@ test_expect_success \
|
||||||
cat >expected <<\EOF &&
|
cat >expected <<\EOF &&
|
||||||
100644 blob X path0
|
100644 blob X path0
|
||||||
120000 blob X path1
|
120000 blob X path1
|
||||||
040000 tree X path2
|
|
||||||
040000 tree X path2/baz
|
|
||||||
100644 blob X path2/baz/b
|
100644 blob X path2/baz/b
|
||||||
120000 blob X path2/bazbo
|
120000 blob X path2/bazbo
|
||||||
100644 blob X path2/foo
|
100644 blob X path2/foo
|
||||||
|
@ -70,12 +68,14 @@ EOF
|
||||||
test_output'
|
test_output'
|
||||||
|
|
||||||
|
|
||||||
|
# it used to be path1 and then path0, but with pathspec semantics
|
||||||
|
# they are shown in canonical order.
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'ls-tree filtered with path1 path0' \
|
'ls-tree filtered with path1 path0' \
|
||||||
'git-ls-tree $tree path1 path0 >current &&
|
'git-ls-tree $tree path1 path0 >current &&
|
||||||
cat >expected <<\EOF &&
|
cat >expected <<\EOF &&
|
||||||
120000 blob X path1
|
|
||||||
100644 blob X path0
|
100644 blob X path0
|
||||||
|
120000 blob X path1
|
||||||
EOF
|
EOF
|
||||||
test_output'
|
test_output'
|
||||||
|
|
||||||
|
@ -86,45 +86,34 @@ test_expect_success \
|
||||||
EOF
|
EOF
|
||||||
test_output'
|
test_output'
|
||||||
|
|
||||||
|
# It used to show path2 and its immediate children but
|
||||||
|
# with pathspec semantics it shows only path2
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'ls-tree filtered with path2' \
|
'ls-tree filtered with path2' \
|
||||||
'git-ls-tree $tree path2 >current &&
|
'git-ls-tree $tree path2 >current &&
|
||||||
cat >expected <<\EOF &&
|
cat >expected <<\EOF &&
|
||||||
040000 tree X path2
|
040000 tree X path2
|
||||||
|
EOF
|
||||||
|
test_output'
|
||||||
|
|
||||||
|
# ... and path2/ shows the children.
|
||||||
|
test_expect_success \
|
||||||
|
'ls-tree filtered with path2/' \
|
||||||
|
'git-ls-tree $tree path2/ >current &&
|
||||||
|
cat >expected <<\EOF &&
|
||||||
040000 tree X path2/baz
|
040000 tree X path2/baz
|
||||||
120000 blob X path2/bazbo
|
120000 blob X path2/bazbo
|
||||||
100644 blob X path2/foo
|
100644 blob X path2/foo
|
||||||
EOF
|
EOF
|
||||||
test_output'
|
test_output'
|
||||||
|
|
||||||
|
# The same change -- exact match does not show children of
|
||||||
|
# path2/baz
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'ls-tree filtered with path2/baz' \
|
'ls-tree filtered with path2/baz' \
|
||||||
'git-ls-tree $tree path2/baz >current &&
|
'git-ls-tree $tree path2/baz >current &&
|
||||||
cat >expected <<\EOF &&
|
cat >expected <<\EOF &&
|
||||||
040000 tree X path2/baz
|
040000 tree X path2/baz
|
||||||
100644 blob X path2/baz/b
|
|
||||||
EOF
|
|
||||||
test_output'
|
|
||||||
|
|
||||||
test_expect_success \
|
|
||||||
'ls-tree filtered with path2' \
|
|
||||||
'git-ls-tree $tree path2 >current &&
|
|
||||||
cat >expected <<\EOF &&
|
|
||||||
040000 tree X path2
|
|
||||||
040000 tree X path2/baz
|
|
||||||
120000 blob X path2/bazbo
|
|
||||||
100644 blob X path2/foo
|
|
||||||
EOF
|
|
||||||
test_output'
|
|
||||||
|
|
||||||
test_expect_success \
|
|
||||||
'ls-tree filtered with path2/' \
|
|
||||||
'git-ls-tree $tree path2/ >current &&
|
|
||||||
cat >expected <<\EOF &&
|
|
||||||
040000 tree X path2
|
|
||||||
040000 tree X path2/baz
|
|
||||||
120000 blob X path2/bazbo
|
|
||||||
100644 blob X path2/foo
|
|
||||||
EOF
|
EOF
|
||||||
test_output'
|
test_output'
|
||||||
|
|
||||||
|
|
|
@ -59,24 +59,16 @@ test_expect_success \
|
||||||
EOF
|
EOF
|
||||||
test_output'
|
test_output'
|
||||||
|
|
||||||
|
# Recursive does not show tree nodes anymore...
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'ls-tree recursive' \
|
'ls-tree recursive' \
|
||||||
'git-ls-tree -r $tree >current &&
|
'git-ls-tree -r $tree >current &&
|
||||||
cat >expected <<\EOF &&
|
cat >expected <<\EOF &&
|
||||||
100644 blob X 1.txt
|
100644 blob X 1.txt
|
||||||
100644 blob X 2.txt
|
100644 blob X 2.txt
|
||||||
040000 tree X path0
|
|
||||||
040000 tree X path0/a
|
|
||||||
040000 tree X path0/a/b
|
|
||||||
040000 tree X path0/a/b/c
|
|
||||||
100644 blob X path0/a/b/c/1.txt
|
100644 blob X path0/a/b/c/1.txt
|
||||||
040000 tree X path1
|
|
||||||
040000 tree X path1/b
|
|
||||||
040000 tree X path1/b/c
|
|
||||||
100644 blob X path1/b/c/1.txt
|
100644 blob X path1/b/c/1.txt
|
||||||
040000 tree X path2
|
|
||||||
100644 blob X path2/1.txt
|
100644 blob X path2/1.txt
|
||||||
040000 tree X path3
|
|
||||||
100644 blob X path3/1.txt
|
100644 blob X path3/1.txt
|
||||||
100644 blob X path3/2.txt
|
100644 blob X path3/2.txt
|
||||||
EOF
|
EOF
|
||||||
|
@ -110,41 +102,27 @@ test_expect_success \
|
||||||
EOF
|
EOF
|
||||||
test_output'
|
test_output'
|
||||||
|
|
||||||
|
# I am not so sure about this one after ls-tree doing pathspec match.
|
||||||
|
# Having both path0/a and path0/a/b/c makes path0/a redundant, and
|
||||||
|
# it behaves as if path0/a/b/c, path1/b/c, path2 and path3 are specified.
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'ls-tree filter directories' \
|
'ls-tree filter directories' \
|
||||||
'git-ls-tree $tree path3 path2 path0/a/b/c path1/b/c path0/a >current &&
|
'git-ls-tree $tree path3 path2 path0/a/b/c path1/b/c path0/a >current &&
|
||||||
cat >expected <<\EOF &&
|
cat >expected <<\EOF &&
|
||||||
040000 tree X path3
|
|
||||||
100644 blob X path3/1.txt
|
|
||||||
100644 blob X path3/2.txt
|
|
||||||
040000 tree X path2
|
|
||||||
100644 blob X path2/1.txt
|
|
||||||
040000 tree X path0/a/b/c
|
040000 tree X path0/a/b/c
|
||||||
100644 blob X path0/a/b/c/1.txt
|
|
||||||
040000 tree X path1/b/c
|
040000 tree X path1/b/c
|
||||||
100644 blob X path1/b/c/1.txt
|
040000 tree X path2
|
||||||
040000 tree X path0/a
|
040000 tree X path3
|
||||||
040000 tree X path0/a/b
|
|
||||||
EOF
|
EOF
|
||||||
test_output'
|
test_output'
|
||||||
|
|
||||||
|
# Again, duplicates are filtered away so this is equivalent to
|
||||||
|
# having 1.txt and path3
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'ls-tree filter odd names' \
|
'ls-tree filter odd names' \
|
||||||
'git-ls-tree $tree 1.txt /1.txt //1.txt path3/1.txt /path3/1.txt //path3//1.txt path3 /path3/ path3// >current &&
|
'git-ls-tree $tree 1.txt /1.txt //1.txt path3/1.txt /path3/1.txt //path3//1.txt path3 /path3/ path3// >current &&
|
||||||
cat >expected <<\EOF &&
|
cat >expected <<\EOF &&
|
||||||
100644 blob X 1.txt
|
100644 blob X 1.txt
|
||||||
100644 blob X 1.txt
|
|
||||||
100644 blob X 1.txt
|
|
||||||
100644 blob X path3/1.txt
|
|
||||||
100644 blob X path3/1.txt
|
|
||||||
100644 blob X path3/1.txt
|
|
||||||
040000 tree X path3
|
|
||||||
100644 blob X path3/1.txt
|
|
||||||
100644 blob X path3/2.txt
|
|
||||||
040000 tree X path3
|
|
||||||
100644 blob X path3/1.txt
|
|
||||||
100644 blob X path3/2.txt
|
|
||||||
040000 tree X path3
|
|
||||||
100644 blob X path3/1.txt
|
100644 blob X path3/1.txt
|
||||||
100644 blob X path3/2.txt
|
100644 blob X path3/2.txt
|
||||||
EOF
|
EOF
|
||||||
|
|
34
tree.c
34
tree.c
|
@ -9,9 +9,16 @@ const char *tree_type = "tree";
|
||||||
|
|
||||||
static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
|
static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
|
||||||
{
|
{
|
||||||
int len = strlen(pathname);
|
int len;
|
||||||
unsigned int size = cache_entry_size(baselen + len);
|
unsigned int size;
|
||||||
struct cache_entry *ce = xmalloc(size);
|
struct cache_entry *ce;
|
||||||
|
|
||||||
|
if (S_ISDIR(mode))
|
||||||
|
return READ_TREE_RECURSIVE;
|
||||||
|
|
||||||
|
len = strlen(pathname);
|
||||||
|
size = cache_entry_size(baselen + len);
|
||||||
|
ce = xmalloc(size);
|
||||||
|
|
||||||
memset(ce, 0, size);
|
memset(ce, 0, size);
|
||||||
|
|
||||||
|
@ -67,9 +74,10 @@ static int match_tree_entry(const char *base, int baselen, const char *path, uns
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_tree_recursive(void *buffer, unsigned long size,
|
int read_tree_recursive(void *buffer, unsigned long size,
|
||||||
const char *base, int baselen,
|
const char *base, int baselen,
|
||||||
int stage, const char **match)
|
int stage, const char **match,
|
||||||
|
read_tree_fn_t fn)
|
||||||
{
|
{
|
||||||
while (size) {
|
while (size) {
|
||||||
int len = strlen(buffer)+1;
|
int len = strlen(buffer)+1;
|
||||||
|
@ -86,6 +94,14 @@ static int read_tree_recursive(void *buffer, unsigned long size,
|
||||||
if (!match_tree_entry(base, baselen, path, mode, match))
|
if (!match_tree_entry(base, baselen, path, mode, match))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
switch (fn(sha1, base, baselen, path, mode, stage)) {
|
||||||
|
case 0:
|
||||||
|
continue;
|
||||||
|
case READ_TREE_RECURSIVE:
|
||||||
|
break;;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if (S_ISDIR(mode)) {
|
if (S_ISDIR(mode)) {
|
||||||
int retval;
|
int retval;
|
||||||
int pathlen = strlen(path);
|
int pathlen = strlen(path);
|
||||||
|
@ -106,22 +122,20 @@ static int read_tree_recursive(void *buffer, unsigned long size,
|
||||||
retval = read_tree_recursive(eltbuf, eltsize,
|
retval = read_tree_recursive(eltbuf, eltsize,
|
||||||
newbase,
|
newbase,
|
||||||
baselen + pathlen + 1,
|
baselen + pathlen + 1,
|
||||||
stage, match);
|
stage, match, fn);
|
||||||
free(eltbuf);
|
free(eltbuf);
|
||||||
free(newbase);
|
free(newbase);
|
||||||
if (retval)
|
if (retval)
|
||||||
return -1;
|
return -1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (read_one_entry(sha1, base, baselen, path, mode, stage) < 0)
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_tree(void *buffer, unsigned long size, int stage, const char **match)
|
int read_tree(void *buffer, unsigned long size, int stage, const char **match)
|
||||||
{
|
{
|
||||||
return read_tree_recursive(buffer, size, "", 0, stage, match);
|
return read_tree_recursive(buffer, size, "", 0, stage, match, read_one_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tree *lookup_tree(const unsigned char *sha1)
|
struct tree *lookup_tree(const unsigned char *sha1)
|
||||||
|
|
9
tree.h
9
tree.h
|
@ -35,4 +35,13 @@ int parse_tree(struct tree *tree);
|
||||||
/* Parses and returns the tree in the given ent, chasing tags and commits. */
|
/* Parses and returns the tree in the given ent, chasing tags and commits. */
|
||||||
struct tree *parse_tree_indirect(const unsigned char *sha1);
|
struct tree *parse_tree_indirect(const unsigned char *sha1);
|
||||||
|
|
||||||
|
#define READ_TREE_RECURSIVE 1
|
||||||
|
typedef int (*read_tree_fn_t)(unsigned char *, const char *, int, const char *, unsigned int, int);
|
||||||
|
|
||||||
|
extern int read_tree_recursive(void *buffer, unsigned long size,
|
||||||
|
const char *base, int baselen,
|
||||||
|
int stage, const char **match,
|
||||||
|
read_tree_fn_t fn);
|
||||||
|
|
||||||
|
|
||||||
#endif /* TREE_H */
|
#endif /* TREE_H */
|
||||||
|
|
Loading…
Reference in New Issue