-------
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::
Remain silent even on nonexisting files
fatal: Merge requires file-level merging
Nope.
...
- merge: warning: conflicts during merge
- ERROR: Merge conflict in hello.
- fatal: merge program failed
+ Auto-merging hello
+ CONFLICT (content): Merge conflict in hello
Automatic merge failed/prevented; fix up by hand
----------------
------------------------------------------------
$ git show-branch master mybranch
-* [master] Merged "mybranch" changes.
+* [master] Merge work in mybranch
! [mybranch] Some work.
--
-+ [master] Merged "mybranch" changes.
++ [master] Merge work in mybranch
++ [mybranch] Some work.
------------------------------------------------
------------------------------------------------
$ git show-branch master mybranch
-! [master] Merged "mybranch" changes.
- * [mybranch] Merged "mybranch" changes.
+! [master] Merge work in mybranch
+ * [mybranch] Merge work in mybranch
--
-++ [master] Merged "mybranch" changes.
+++ [master] Merge work in mybranch
------------------------------------------------
#include "diff.h"
static const char diff_files_usage[] =
-"git-diff-files [-q] "
-"[<common diff options>] [<path>...]"
+"git-diff-files [-q] [-0/-1/2/3] [<common diff options>] [<path>...]"
COMMON_DIFF_OPTIONS_HELP;
static struct diff_options diff_options;
static int silent = 0;
+static int diff_unmerged_stage = 2;
static void show_unmerge(const char *path)
{
argc--;
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;
else if (!strcmp(argv[1], "-r"))
; /* no-op */
if (ce_stage(ce)) {
show_unmerge(ce->name);
- while (i < entries &&
- !strcmp(ce->name, active_cache[i]->name))
+ while (i < entries) {
+ 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--; /* 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) {
#!/bin/sh
. git-sh-setup
+sq() {
+ perl -e '
+ for (@ARGV) {
+ s/'\''/'\'\\\\\'\''/g;
+ print " '\''$_'\''";
+ }
+ print "\n";
+ ' "$@"
+}
+
usage() {
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 good [<rev>...] mark <rev>... known-good revisions.
git bisect next find next bisection to test and check it out.
}
bisect_start() {
- case "$#" in 0) ;; *) usage ;; esac
#
# Verify HEAD. If we were bisecting before this, reset to the
# top-of-line master first!
rm -f "$GIT_DIR/refs/heads/bisect"
rm -rf "$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() {
bad=$(git-rev-parse --verify refs/bisect/bad) &&
good=$(git-rev-parse --sq --revs-only --not \
$(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
echo "$bad was both good and bad"
exit 1
git-diff-tree --pretty $rev
exit 0
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 "$rev" > "$GIT_DIR/refs/heads/new-bisect"
git checkout new-bisect || exit
bisect_visualize() {
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() {
test "$bisect" = "git-bisect" || continue
case "$command" in
start)
- bisect_start
+ cmd="bisect_start $rev"
+ eval "$cmd"
;;
good)
echo "$rev" >"$GIT_DIR/refs/bisect/good-$rev"
flags=$(git-rev-parse --no-revs --flags --sq "$@")
files=$(git-rev-parse --no-revs --no-flags --sq "$@")
-: ${flags:="'-M' '-p'"}
-
# I often say 'git diff --cached -p' and get scolded by git-diff-files, but
# obviously I mean 'git diff --cached -p HEAD' in that case.
case "$rev" in
esac
esac
+# If we do not have --name-status, --name-only nor -r, default to -p.
+# If we do not have -B nor -C, default to -M.
+case " $flags " in
+*" '--name-status' "* | *" '--name-only' "* | *" '-r' "* )
+ ;;
+*)
+ flags="$flags'-p' " ;;
+esac
+case " $flags " in
+*" '-"[BCM]* | *" '--find-copies-harder' "*)
+ ;; # something like -M50.
+*)
+ flags="$flags'-M' " ;;
+esac
+
case "$rev" in
?*' '?*' '?*)
echo >&2 "I don't understand"
;;
esac
- # We reset the index to the first branch, making
- # git-diff-file useful
- git-update-index --add --cacheinfo "$6" "$2" "$4"
- git-checkout-index -u -f -- "$4" &&
- merge "$4" "$orig" "$src2"
+ merge "$4" "$orig" "$src2"
ret=$?
rm -f -- "$orig" "$src2"
if cacheOnly:
updateFile(False, sha, mode, path)
else:
- updateFileExt(aSha, aMode, path,
- updateCache=True, updateWd=False)
updateFileExt(sha, mode, path, updateCache=False, updateWd=True)
else:
die("ERROR: Fatal merge failure, shouldn't happen.")
exit(1);
}
-# Sanity checks:
-my $GIT_DIR = $ENV{'GIT_DIR'} || ".git";
-
-unless ( -d $GIT_DIR && -d $GIT_DIR . "/objects" &&
- -d $GIT_DIR . "/objects/" && -d $GIT_DIR . "/refs") {
- print "Error: git repository not found.";
- exit(1);
-}
-
+my $GIT_DIR = `git rev-parse --git-dir`;
+exit 1 if $?; # rev-parse would have given "not a git dir" message.
+chomp($GIT_DIR);
our ($opt_n, $opt_f, $opt_h, $opt_k, $opt_v);
getopts("hnfkv") || usage;
global findtype findtypemenu findloc findstring fstring geometry
global entries sha1entry sha1string sha1but
global maincursor textcursor curtextcursor
- global rowctxmenu gaudydiff mergemax
+ global rowctxmenu mergemax
menu .bar
.bar add cascade -label "File" -menu .bar.file
menu .bar.file
.bar.file add command -label "Reread references" -command rereadrefs
.bar.file add command -label "Quit" -command doquit
+ menu .bar.edit
+ .bar add cascade -label "Edit" -menu .bar.edit
+ .bar.edit add command -label "Preferences" -command doprefs
menu .bar.help
.bar add cascade -label "Help" -menu .bar.help
.bar.help add command -label "About gitk" -command about
.ctop.cdet add .ctop.cdet.left
$ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
- if {$gaudydiff} {
- $ctext tag conf hunksep -back blue -fore white
- $ctext tag conf d0 -back "#ff8080"
- $ctext tag conf d1 -back green
- } else {
- $ctext tag conf hunksep -fore blue
- $ctext tag conf d0 -fore red
- $ctext tag conf d1 -fore "#00a000"
- $ctext tag conf m0 -fore red
- $ctext tag conf m1 -fore blue
- $ctext tag conf m2 -fore green
- $ctext tag conf m3 -fore purple
- $ctext tag conf m4 -fore brown
- $ctext tag conf mmax -fore darkgrey
- set mergemax 5
- $ctext tag conf mresult -font [concat $textfont bold]
- $ctext tag conf msep -font [concat $textfont bold]
- $ctext tag conf found -back yellow
- }
+ $ctext tag conf hunksep -fore blue
+ $ctext tag conf d0 -fore red
+ $ctext tag conf d1 -fore "#00a000"
+ $ctext tag conf m0 -fore red
+ $ctext tag conf m1 -fore blue
+ $ctext tag conf m2 -fore green
+ $ctext tag conf m3 -fore purple
+ $ctext tag conf m4 -fore brown
+ $ctext tag conf mmax -fore darkgrey
+ set mergemax 5
+ $ctext tag conf mresult -font [concat $textfont bold]
+ $ctext tag conf msep -font [concat $textfont bold]
+ $ctext tag conf found -back yellow
frame .ctop.cdet.right
set cflist .ctop.cdet.right.cfiles
proc savestuff {w} {
global canv canv2 canv3 ctext cflist mainfont textfont
- global stuffsaved findmergefiles gaudydiff maxgraphpct
+ global stuffsaved findmergefiles maxgraphpct
global maxwidth
if {$stuffsaved} return
puts $f [list set mainfont $mainfont]
puts $f [list set textfont $textfont]
puts $f [list set findmergefiles $findmergefiles]
- puts $f [list set gaudydiff $gaudydiff]
puts $f [list set maxgraphpct $maxgraphpct]
puts $f [list set maxwidth $maxwidth]
puts $f "set geometry(width) [winfo width .ctop]"
global diffids blobdifffd ctext curdifftag curtagstart
global diffnexthead diffnextnote difffilestart
global nextupdate diffinhdr treediffs
- global gaudydiff
set n [gets $bdf line]
if {$n < 0} {
set diffinhdr 0
} elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
$line match f1l f1c f2l f2c rest]} {
- if {$gaudydiff} {
- $ctext insert end "\t" hunksep
- $ctext insert end " $f1l " d0 " $f2l " d1
- $ctext insert end " $rest \n" hunksep
- } else {
- $ctext insert end "$line\n" hunksep
- }
+ $ctext insert end "$line\n" hunksep
set diffinhdr 0
} else {
set x [string range $line 0 0]
if {$x == "-" || $x == "+"} {
set tag [expr {$x == "+"}]
- if {$gaudydiff} {
- set line [string range $line 1 end]
- }
$ctext insert end "$line\n" d$tag
} elseif {$x == " "} {
- if {$gaudydiff} {
- set line [string range $line 1 end]
- }
$ctext insert end "$line\n"
} elseif {$diffinhdr || $x == "\\"} {
# e.g. "\ No newline at end of file"
destroy .
}
-proc formatdate {d} {
- global hours nhours tfd fastdate
+proc doprefs {} {
+ global maxwidth maxgraphpct diffopts findmergefiles
+ global oldprefs prefstop
- if {!$fastdate} {
- return [clock format $d -format "%Y-%m-%d %H:%M:%S"]
+ set top .gitkprefs
+ set prefstop $top
+ if {[winfo exists $top]} {
+ raise $top
+ return
}
- set hr [expr {$d / 3600}]
- set ms [expr {$d % 3600}]
- if {![info exists hours($hr)]} {
- set hours($hr) [clock format $d -format "%Y-%m-%d %H"]
- set nhours($hr) 0
+ foreach v {maxwidth maxgraphpct diffopts findmergefiles} {
+ set oldprefs($v) [set $v]
}
- incr nhours($hr)
- set minsec [format "%.2d:%.2d" [expr {$ms/60}] [expr {$ms%60}]]
- return "$hours($hr):$minsec"
+ toplevel $top
+ wm title $top "Gitk preferences"
+ label $top.ldisp -text "Commit list display options"
+ grid $top.ldisp - -sticky w -pady 10
+ label $top.spacer -text " "
+ label $top.maxwidthl -text "Maximum graph width (lines)" \
+ -font optionfont
+ spinbox $top.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
+ grid $top.spacer $top.maxwidthl $top.maxwidth -sticky w
+ label $top.maxpctl -text "Maximum graph width (% of pane)" \
+ -font optionfont
+ spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
+ grid x $top.maxpctl $top.maxpct -sticky w
+ checkbutton $top.findm -variable findmergefiles
+ label $top.findml -text "Include merges for \"Find\" in \"Files\"" \
+ -font optionfont
+ grid $top.findm $top.findml - -sticky w
+ label $top.ddisp -text "Diff display options"
+ grid $top.ddisp - -sticky w -pady 10
+ label $top.diffoptl -text "Options for diff program" \
+ -font optionfont
+ entry $top.diffopt -width 20 -textvariable diffopts
+ grid x $top.diffoptl $top.diffopt -sticky w
+ frame $top.buts
+ button $top.buts.ok -text "OK" -command prefsok
+ button $top.buts.can -text "Cancel" -command prefscan
+ grid $top.buts.ok $top.buts.can
+ grid columnconfigure $top.buts 0 -weight 1 -uniform a
+ grid columnconfigure $top.buts 1 -weight 1 -uniform a
+ grid $top.buts - - -pady 10 -sticky ew
+}
+
+proc prefscan {} {
+ global maxwidth maxgraphpct diffopts findmergefiles
+ global oldprefs prefstop
+
+ foreach v {maxwidth maxgraphpct diffopts findmergefiles} {
+ set $v $oldprefs($v)
+ }
+ catch {destroy $prefstop}
+ unset prefstop
+}
+
+proc prefsok {} {
+ global maxwidth maxgraphpct
+ global oldprefs prefstop
+
+ catch {destroy $prefstop}
+ unset prefstop
+ if {$maxwidth != $oldprefs(maxwidth)
+ || $maxgraphpct != $oldprefs(maxgraphpct)} {
+ redisplay
+ }
+}
+
+proc formatdate {d} {
+ return [clock format $d -format "%Y-%m-%d %H:%M:%S"]
}
# defaults...
set datemode 0
-set boldnames 0
set diffopts "-U 5 -p"
set wrcomcmd "git-diff-tree --stdin -p --pretty"
set mainfont {Helvetica 9}
set textfont {Courier 9}
set findmergefiles 0
-set gaudydiff 0
set maxgraphpct 50
set maxwidth 16
set revlistorder 0
catch {source ~/.gitk}
set namefont $mainfont
-if {$boldnames} {
- lappend namefont bold
-}
+
+font create optionfont -family sans-serif -size -12
set revtreeargs {}
foreach arg $argv {
switch -regexp -- $arg {
"^$" { }
- "^-b" { set boldnames 1 }
"^-d" { set datemode 1 }
"^-r" { set revlistorder 1 }
default {
#define LS_RECURSIVE 1
#define LS_TREE_ONLY 2
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 const char ls_tree_usage[] =
+ "git-ls-tree [-d] [-r] [-z] <tree-ish> [path...]";
-static struct tree_entry_list *find_entry(const char *path, char *pathbuf)
+static int show_tree(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
{
- 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 */
+ const char *type = "blob";
+
+ 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;
- }
- elem = elem->next;
+ 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;
}
- if (!elem)
- return NULL;
-
- oldelem = elem;
}
- path = next;
+ type = "tree";
}
- 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';
-
+ 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;
}
-static int show_entry(struct tree_entry_list *e, int level, char *pathbuf)
+int main(int argc, const char **argv)
{
- 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[] =
- "git-ls-tree [-d] [-r] [-z] <tree-ish> [path...]";
-
-int main(int argc, char **argv)
-{
- static char *path0[] = { "", NULL };
- char **path;
+ const char *prefix;
unsigned char sha1[20];
+ char *buf;
+ unsigned long size;
+ prefix = setup_git_directory();
while (1 < argc && argv[1][0] == '-') {
switch (argv[1][1]) {
case 'z':
if (get_sha1(argv[1], sha1) < 0)
usage(ls_tree_usage);
- path = (argc == 2) ? path0 : (argv + 2);
- prepare_root(sha1);
- if (list(path) < 0)
- die("list failed");
+ pathspec = get_pathspec(prefix, argv + 2);
+ buf = read_object_with_reference(sha1, "tree", &size, NULL);
+ if (!buf)
+ die("not a tree object");
+ read_tree_recursive(buf, size, "", 0, 0, pathspec, show_tree);
+
return 0;
}
if (commit->object.flags & (UNINTERESTING | COUNTED))
break;
- nr++;
+ if (!paths || (commit->object.flags & TREECHANGE))
+ nr++;
commit->object.flags |= COUNTED;
p = commit->parents;
entry = p;
}
}
}
+
return nr;
}
nr = 0;
p = list;
while (p) {
- nr++;
+ if (!paths || (p->item->object.flags & TREECHANGE))
+ nr++;
p = p->next;
}
closest = 0;
best = list;
- p = list;
- while (p) {
- int distance = count_distance(p);
+ for (p = list; p; p = p->next) {
+ int distance;
+
+ if (paths && !(p->item->object.flags & TREECHANGE))
+ continue;
+
+ distance = count_distance(p);
clear_distance(list);
if (nr - distance < distance)
distance = nr - distance;
best = p;
closest = distance;
}
- p = p->next;
}
if (best)
best->next = NULL;
if (validate_symref(path))
goto bad_dir_environ;
if (getenv(DB_ENVIRONMENT)) {
- if (access(DB_ENVIRONMENT, X_OK))
+ if (access(getenv(DB_ENVIRONMENT), X_OK))
goto bad_dir_environ;
}
else {
'git-ls-tree output for a known tree.' \
'diff current expected'
+# This changed in ls-tree pathspec change -- recursive does
+# not show tree nodes anymore.
test_expect_success \
'showing tree with git-ls-tree -r' \
'git-ls-tree -r $tree >current'
cat >expected <<\EOF
100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0
120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym
-040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2
100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2
120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym
-040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3
100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3
120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym
-040000 tree 3c5e5399f3a333eddecce7a9b9465b63f65f51e2 path3/subp3
100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3
120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym
EOF
cat >expected <<\EOF &&
100644 blob X path0
120000 blob X path1
-040000 tree X path2
-040000 tree X path2/baz
100644 blob X path2/baz/b
120000 blob X path2/bazbo
100644 blob X path2/foo
test_output'
+# it used to be path1 and then path0, but with pathspec semantics
+# they are shown in canonical order.
test_expect_success \
'ls-tree filtered with path1 path0' \
'git-ls-tree $tree path1 path0 >current &&
cat >expected <<\EOF &&
-120000 blob X path1
100644 blob X path0
+120000 blob X path1
EOF
test_output'
EOF
test_output'
+# It used to show path2 and its immediate children but
+# with pathspec semantics it shows only path2
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/baz' \
- 'git-ls-tree $tree path2/baz >current &&
- cat >expected <<\EOF &&
-040000 tree X path2/baz
-100644 blob X path2/baz/b
EOF
test_output'
+# ... and path2/ shows the children.
test_expect_success \
- 'ls-tree filtered with path2' \
- 'git-ls-tree $tree path2 >current &&
+ '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'
+# The same change -- exact match does not show children of
+# path2/baz
test_expect_success \
- 'ls-tree filtered with path2/' \
- 'git-ls-tree $tree path2/ >current &&
+ 'ls-tree filtered with path2/baz' \
+ 'git-ls-tree $tree path2/baz >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'
EOF
test_output'
+# Recursive does not show tree nodes anymore...
test_expect_success \
'ls-tree recursive' \
'git-ls-tree -r $tree >current &&
cat >expected <<\EOF &&
100644 blob X 1.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
-040000 tree X path1
-040000 tree X path1/b
-040000 tree X path1/b/c
100644 blob X path1/b/c/1.txt
-040000 tree X path2
100644 blob X path2/1.txt
-040000 tree X path3
100644 blob X path3/1.txt
100644 blob X path3/2.txt
EOF
EOF
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 \
'ls-tree filter directories' \
'git-ls-tree $tree path3 path2 path0/a/b/c path1/b/c path0/a >current &&
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
-100644 blob X path0/a/b/c/1.txt
040000 tree X path1/b/c
-100644 blob X path1/b/c/1.txt
-040000 tree X path0/a
-040000 tree X path0/a/b
+040000 tree X path2
+040000 tree X path3
EOF
test_output'
+# Again, duplicates are filtered away so this is equivalent to
+# having 1.txt and path3
test_expect_success \
'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 &&
cat >expected <<\EOF &&
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/2.txt
EOF
--- /dev/null
+#!/bin/sh
+
+test_description='git-mv in subdirs'
+. ./test-lib.sh
+
+test_expect_success \
+ 'prepare reference tree' \
+ 'mkdir path0 path1 &&
+ cp ../../COPYING path0/COPYING &&
+ git-add path0/COPYING &&
+ git-commit -m add -a'
+
+test_expect_success \
+ 'moving the file' \
+ 'cd path0 && git-mv COPYING ../path1/COPYING'
+
+# in path0 currently
+test_expect_success \
+ 'commiting the change' \
+ 'cd .. && git-commit -m move -a'
+
+test_expect_success \
+ 'checking the commit' \
+ 'git-diff-tree -r -M --name-status HEAD^ HEAD | \
+ grep -E "^R100.+path0/COPYING.+path1/COPYING"'
+
+test_done
static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
{
- int len = strlen(pathname);
- unsigned int size = cache_entry_size(baselen + len);
- struct cache_entry *ce = xmalloc(size);
+ int len;
+ unsigned int 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);
return 0;
}
-static int read_tree_recursive(void *buffer, unsigned long size,
- const char *base, int baselen,
- int stage, const char **match)
+int read_tree_recursive(void *buffer, unsigned long size,
+ const char *base, int baselen,
+ int stage, const char **match,
+ read_tree_fn_t fn)
{
while (size) {
int len = strlen(buffer)+1;
if (!match_tree_entry(base, baselen, path, mode, match))
continue;
+ switch (fn(sha1, base, baselen, path, mode, stage)) {
+ case 0:
+ continue;
+ case READ_TREE_RECURSIVE:
+ break;;
+ default:
+ return -1;
+ }
if (S_ISDIR(mode)) {
int retval;
int pathlen = strlen(path);
retval = read_tree_recursive(eltbuf, eltsize,
newbase,
baselen + pathlen + 1,
- stage, match);
+ stage, match, fn);
free(eltbuf);
free(newbase);
if (retval)
return -1;
continue;
}
- if (read_one_entry(sha1, base, baselen, path, mode, stage) < 0)
- return -1;
}
return 0;
}
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)
/* Parses and returns the tree in the given ent, chasing tags and commits. */
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 */