diff --git a/.gitignore b/.gitignore index 927c89cbac..3edf6b41af 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,7 @@ git-merge-base git-merge-index git-merge-octopus git-merge-one-file +git-merge-ours git-merge-recursive git-merge-resolve git-merge-stupid diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index 099db294f4..431b8f6e06 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -72,6 +72,14 @@ OPTIONS path of the current directory relative to the top-level directory. +--since=datestring, --after=datestring:: + Parses the date string, and outputs corresponding + --max-age= parameter for git-rev-list command. + +--until=datestring, --before=datestring:: + Parses the date string, and outputs corresponding + --min-age= parameter for git-rev-list command. + ...:: Flags and parameters to be parsed. @@ -124,6 +132,32 @@ which is passed to 'git-rev-list'. Two revision parameters concatenated with '..' is a short-hand for writing a range between them. I.e. 'r1..r2' is equivalent to saying '{caret}r1 r2' +Here is an illustration, by Jon Loeliger. Both node B and C are +a commit parents of commit node A. Parent commits are ordered +left-to-right. + + G H I J + \ / \ / + D E F + \ | / + \ | / + \|/ + B C + \ / + \ / + A + + A = = A^0 + B = A^ = A^1 = A~1 + C = A^2 = A^2 + D = A^^ = A^1^1 = A~2 + E = B^2 = A^^2 + F = B^3 = A^^3 + G = A^^^ = A^1^1^1 = A~3 + H = D^2 = B^^2 = A^^^2 = A~2^2 + I = F^ = B^3^ = A^^3^ + J = F^2 = B^3^2 = A^^3^2 + Author ------ diff --git a/Documentation/tutorial.txt b/Documentation/tutorial.txt index 20a4cb1df4..214673db06 100644 --- a/Documentation/tutorial.txt +++ b/Documentation/tutorial.txt @@ -455,6 +455,41 @@ the same diff that we've already seen several times, we can now do (again, `-p` means to show the difference as a human-readable patch), and it will show what the last commit (in `HEAD`) actually changed. +[NOTE] +============ +Here is an ASCII art by Jon Loeliger that illustrates how +various diff-\* commands compare things. + + diff-tree + +----+ + | | + | | + V V + +-----------+ + | Object DB | + | Backing | + | Store | + +-----------+ + ^ ^ + | | + | | diff-index --cached + | | + diff-index | V + | +-----------+ + | | Index | + | | "cache" | + | +-----------+ + | ^ + | | + | | diff-files + | | + V V + +-----------+ + | Working | + | Directory | + +-----------+ +============ + More interestingly, you can also give `git-diff-tree` the `-v` flag, which tells it to also show the commit message and author and date of the commit, and you can tell it to show a whole series of diffs. diff --git a/Makefile b/Makefile index 5606c83160..f96da67822 100644 --- a/Makefile +++ b/Makefile @@ -52,7 +52,7 @@ # DEFINES += -DUSE_STDEV -GIT_VERSION = 0.99.9b +GIT_VERSION = 0.99.9c CFLAGS = -g -O2 -Wall ALL_CFLAGS = $(CFLAGS) $(PLATFORM_DEFINES) $(DEFINES) @@ -89,7 +89,7 @@ SCRIPT_SH = \ git-tag.sh git-verify-tag.sh git-whatchanged.sh git.sh \ git-applymbox.sh git-applypatch.sh git-am.sh \ git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \ - git-merge-resolve.sh git-grep.sh + git-merge-resolve.sh git-merge-ours.sh git-grep.sh SCRIPT_PERL = \ git-archimport.perl git-cvsimport.perl git-relink.perl \ @@ -189,9 +189,9 @@ endif ifeq ($(uname_S),SunOS) NEEDS_SOCKET = YesPlease NEEDS_NSL = YesPlease + NEEDS_LIBICONV = YesPlease SHELL_PATH = /bin/bash NO_STRCASESTR = YesPlease - CURLDIR = /opt/sfw INSTALL = ginstall TAR = gtar PLATFORM_DEFINES += -D__EXTENSIONS__ @@ -397,8 +397,8 @@ doc: test: all $(MAKE) -C t/ all -test-date$X: test-date.c date.o - $(CC) $(ALL_CFLAGS) -o $@ test-date.c date.o +test-date$X: test-date.c date.o ctype.o + $(CC) $(ALL_CFLAGS) -o $@ test-date.c date.o ctype.o test-delta$X: test-delta.c diff-delta.o patch-delta.o $(CC) $(ALL_CFLAGS) -o $@ $^ diff --git a/README b/README index 0ee49d4898..4a2616ba57 100644 --- a/README +++ b/README @@ -399,6 +399,46 @@ save the note about that state, in practice we tend to just write the result to the file `.git/HEAD`, so that we can always see what the last committed state was. +Here is an ASCII art by Jon Loeliger that illustrates how +various pieces fit together. + +------------ + + commit-tree + commit obj + +----+ + | | + | | + V V + +-----------+ + | Object DB | + | Backing | + | Store | + +-----------+ + ^ + write-tree | | + tree obj | | + | | read-tree + | | tree obj + V + +-----------+ + | Index | + | "cache" | + +-----------+ + update-index ^ + blob obj | | + | | + checkout-index -u | | checkout-index + stat | | blob obj + V + +-----------+ + | Working | + | Directory | + +-----------+ + +------------ + + 6) Examining the data ~~~~~~~~~~~~~~~~~~~~~ diff --git a/commit.c b/commit.c index 8f403180e5..a8c9bfc8ba 100644 --- a/commit.c +++ b/commit.c @@ -55,7 +55,7 @@ static struct commit *check_commit(struct object *obj, struct commit *lookup_commit_reference_gently(const unsigned char *sha1, int quiet) { - struct object *obj = deref_tag(parse_object(sha1)); + struct object *obj = deref_tag(parse_object(sha1), NULL, 0); if (!obj) return NULL; diff --git a/config.c b/config.c index 519fecfee4..e89bab26c9 100644 --- a/config.c +++ b/config.c @@ -13,6 +13,14 @@ static int get_next_char(void) c = '\n'; if ((f = config_file) != NULL) { c = fgetc(f); + if (c == '\r') { + /* DOS like systems */ + c = fgetc(f); + if (c != '\n') { + ungetc(c, f); + c = '\r'; + } + } if (c == '\n') config_linenr++; if (c == EOF) { diff --git a/debian/changelog b/debian/changelog index ee68af5020..cc97660185 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +git-core (0.99.9c-0) unstable; urgency=low + + * GIT 0.99.9c + + -- Junio C Hamano Thu, 3 Nov 2005 15:44:54 -0800 + git-core (0.99.9b-0) unstable; urgency=low * GIT 0.99.9b diff --git a/fetch-pack.c b/fetch-pack.c index 3df991100b..cb2171523c 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -38,9 +38,9 @@ static void rev_list_push(struct commit *commit, int mark) static int rev_list_insert_ref(const char *path, const unsigned char *sha1) { - struct object *o = deref_tag(parse_object(sha1)); + struct object *o = deref_tag(parse_object(sha1), path, 0); - if (o->type == commit_type) + if (o && o->type == commit_type) rev_list_push((struct commit *)o, SEEN); return 0; @@ -317,7 +317,8 @@ static int everything_local(struct ref **refs, int nr_match, char **match) * Don't mark them common yet; the server has to be told so first. */ for (ref = *refs; ref; ref = ref->next) { - struct object *o = deref_tag(lookup_object(ref->old_sha1)); + struct object *o = deref_tag(lookup_object(ref->old_sha1), + NULL, 0); if (!o || o->type != commit_type || !(o->flags & COMPLETE)) continue; diff --git a/git-branch.sh b/git-branch.sh index e2db9063d4..67f113acb9 100755 --- a/git-branch.sh +++ b/git-branch.sh @@ -102,4 +102,6 @@ rev=$(git-rev-parse --verify "$head") || exit git-check-ref-format "heads/$branchname" || die "we do not like '$branchname' as a branch name." +leading=`expr "refs/heads/$branchname" : '\(.*\)/'` && +mkdir -p "$GIT_DIR/$leading" && echo $rev > "$GIT_DIR/refs/heads/$branchname" diff --git a/git-checkout.sh b/git-checkout.sh index cb33fdc7e2..4c08f36b59 100755 --- a/git-checkout.sh +++ b/git-checkout.sh @@ -126,7 +126,9 @@ fi # if [ "$?" -eq 0 ]; then if [ "$newbranch" ]; then - echo $new > "$GIT_DIR/refs/heads/$newbranch" + leading=`expr "refs/heads/$newbranch" : '\(.*\)/'` && + mkdir -p "$GIT_DIR/$leading" && + echo $new >"$GIT_DIR/refs/heads/$newbranch" || exit branch="$newbranch" fi [ "$branch" ] && diff --git a/git-clone.sh b/git-clone.sh index 18e692a67b..c27a913b1d 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -196,10 +196,17 @@ cd $D || exit if test -f ".git/HEAD" then - mkdir -p .git/remotes || exit - echo >.git/remotes/origin \ - "URL: $repo -Pull: master:origin" + head_points_at=`git-symbolic-ref HEAD` + case "$head_points_at" in + refs/heads/*) + head_points_at=`expr "$head_points_at" : 'refs/heads/\(.*\)'` + mkdir -p .git/remotes && + echo >.git/remotes/origin \ + "URL: $repo +Pull: $head_points_at:origin" + cp ".git/refs/heads/$head_points_at" .git/refs/heads/origin + esac + case "$no_checkout" in '') git checkout diff --git a/git-commit.sh b/git-commit.sh index 10651d87d0..daf90f1e58 100755 --- a/git-commit.sh +++ b/git-commit.sh @@ -129,6 +129,9 @@ then elif test "$use_commit" != "" then git-cat-file commit "$use_commit" | sed -e '1,/^$/d' +elif test -f "$GIT_DIR/MERGE_HEAD" && test -f "$GIT_DIR/MERGE_MSG" +then + cat "$GIT_DIR/MERGE_MSG" fi | git-stripspace >"$GIT_DIR"/COMMIT_EDITMSG case "$signoff" in @@ -144,9 +147,6 @@ t) esac if [ -f "$GIT_DIR/MERGE_HEAD" ]; then - - test -f "$GIT_DIR/MERGE_MSG" && cat "$GIT_DIR/MERGE_MSG" - echo "#" echo "# It looks like your may be committing a MERGE." echo "# If this is not correct, please remove the file" diff --git a/git-merge-ours.sh b/git-merge-ours.sh new file mode 100755 index 0000000000..4f3d053889 --- /dev/null +++ b/git-merge-ours.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# +# Copyright (c) 2005 Junio C Hamano +# +# Pretend we resolved the heads, but declare our tree trumps everybody else. +# + +# We need to exit with 2 if the index does not match our HEAD tree, +# because the current index is what we will be committing as the +# merge result. + +test "$(git-diff-index --cached --name-status HEAD)" = "" || exit 2 + +exit 0 diff --git a/git-merge.sh b/git-merge.sh index 6ad96ebfbb..b810fceaf8 100755 --- a/git-merge.sh +++ b/git-merge.sh @@ -9,12 +9,12 @@ LF=' ' usage () { - die "git-merge [-n] [-s ]... +" + die "git-merge [-n] [--no-commit] [-s ]... +" } # all_strategies='resolve recursive stupid octopus' -all_strategies='recursive octopus resolve stupid' +all_strategies='recursive octopus resolve stupid ours' default_strategies='resolve octopus' use_strategies= @@ -63,6 +63,8 @@ do -n|--n|--no|--no-|--no-s|--no-su|--no-sum|--no-summ|\ --no-summa|--no-summar|--no-summary) no_summary=t ;; + --no-c|--no-co|--no-com|--no-comm|--no-commi|--no-commit) + no_commit=t ;; -s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\ --strateg=*|--strategy=*|\ -s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy) @@ -111,18 +113,18 @@ done common=$(git-show-branch --merge-base $head "$@") echo "$head" >"$GIT_DIR/ORIG_HEAD" -case "$#,$common" in -*,'') +case "$#,$common,$no_commit" in +*,'',*) # No common ancestors found. We need a real merge. ;; -1,"$1") +1,"$1",*) # If head can reach all the merge then we are up to date. # but first the most common case of merging one remote echo "Already up-to-date." dropsave exit 0 ;; -1,"$head") +1,"$head",*) # Again the most common case of merging one remote. echo "Updating from $head to $1." git-update-index --refresh 2>/dev/null @@ -132,11 +134,11 @@ case "$#,$common" in dropsave exit 0 ;; -1,?*"$LF"?*) +1,?*"$LF"?*,*) # We are not doing octopus and not fast forward. Need a # real merge. ;; -1,*) +1,*,) # We are not doing octopus, not fast forward, and have only # one common. See if it is really trivial. echo "Trying really trivial in-index merge..." @@ -210,12 +212,18 @@ do # Remember which strategy left the state in the working tree wt_strategy=$strategy - git-merge-$strategy $common -- "$head_arg" "$@" || { + git-merge-$strategy $common -- "$head_arg" "$@" + exit=$? + if test "$no_commit" = t && test "$exit" = 0 + then + exit=1 ;# pretend it left conflicts. + fi + + test "$exit" = 0 || { # The backend exits with 1 when conflicts are left to be resolved, # with 2 when it does not handle the given merge at all. - exit=$? if test "$exit" -eq 1 then cnt=`{ @@ -272,4 +280,4 @@ do done >"$GIT_DIR/MERGE_HEAD" echo $merge_msg >"$GIT_DIR/MERGE_MSG" -die "Automatic merge failed; fix up by hand" +die "Automatic merge failed/prevented; fix up by hand" diff --git a/git-pull.sh b/git-pull.sh index d4765188b4..96016270b4 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -10,13 +10,15 @@ usage () { die "git pull [-n] [-s strategy]... ..." } -strategy_args= no_summary= +strategy_args= no_summary= no_commit= while case "$#,$1" in 0) break ;; *,-*) ;; *) break ;; esac do case "$1" in -n|--n|--no|--no-|--no-s|--no-su|--no-sum|--no-summ|\ --no-summa|--no-summar|--no-summary) no_summary=-n ;; + --no-c|--no-co|--no-com|--no-comm|--no-commi|--no-commit) + no_commit=--no-commit ;; -s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\ --strateg=*|--strategy=*|\ -s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy) @@ -81,4 +83,4 @@ case "$strategy_args" in esac merge_name=$(git-fmt-merge-msg <"$GIT_DIR/FETCH_HEAD") -git-merge $no_summary $strategy_args "$merge_name" HEAD $merge_head +git-merge $no_summary $no_commit $strategy_args "$merge_name" HEAD $merge_head diff --git a/ls-files.c b/ls-files.c index 3085b2fc8c..d9c8b215f1 100644 --- a/ls-files.c +++ b/ls-files.c @@ -97,7 +97,7 @@ static int add_excludes_from_file_1(const char *fname, for (i = 0; i < size; i++) { if (buf[i] == '\n') { if (entry != buf + i && entry[0] != '#') { - buf[i] = 0; + buf[i - (i && buf[i-1] == '\r')] = 0; add_exclude(entry, base, baselen, which); } entry = buf + i + 1; diff --git a/name-rev.c b/name-rev.c index 21fecdf542..59194f1349 100644 --- a/name-rev.c +++ b/name-rev.c @@ -164,7 +164,7 @@ int main(int argc, char **argv) continue; } - o = deref_tag(parse_object(sha1)); + o = deref_tag(parse_object(sha1), *argv, 0); if (!o || o->type != commit_type) { fprintf(stderr, "Could not get commit for %s. Skipping.\n", *argv); diff --git a/send-pack.c b/send-pack.c index 9f9a6e70b8..3eeb18f7c7 100644 --- a/send-pack.c +++ b/send-pack.c @@ -126,12 +126,12 @@ static int ref_newer(const unsigned char *new_sha1, /* Both new and old must be commit-ish and new is descendant of * old. Otherwise we require --force. */ - o = deref_tag(parse_object(old_sha1)); + o = deref_tag(parse_object(old_sha1), NULL, 0); if (!o || o->type != commit_type) return 0; old = (struct commit *) o; - o = deref_tag(parse_object(new_sha1)); + o = deref_tag(parse_object(new_sha1), NULL, 0); if (!o || o->type != commit_type) return 0; new = (struct commit *) o; diff --git a/server-info.c b/server-info.c index ba5359108d..0cba8e19f7 100644 --- a/server-info.c +++ b/server-info.c @@ -13,9 +13,10 @@ static int add_info_ref(const char *path, const unsigned char *sha1) fprintf(info_ref_fp, "%s %s\n", sha1_to_hex(sha1), path); if (o->type == tag_type) { - o = deref_tag(o); - fprintf(info_ref_fp, "%s %s^{}\n", - sha1_to_hex(o->sha1), path); + o = deref_tag(o, path, 0); + if (o) + fprintf(info_ref_fp, "%s %s^{}\n", + sha1_to_hex(o->sha1), path); } return 0; } diff --git a/sha1_name.c b/sha1_name.c index fe409fbce4..be1755a70b 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -349,7 +349,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1) if (!o) return -1; if (!type_string) { - o = deref_tag(o); + o = deref_tag(o, name, sp - name - 2); if (!o || (!o->parsed && !parse_object(o->sha1))) return -1; memcpy(sha1, o->sha1, 20); diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh index 5beaaa3375..fde2bb25fa 100755 --- a/t/t3001-ls-files-others-exclude.sh +++ b/t/t3001-ls-files-others-exclude.sh @@ -67,4 +67,16 @@ test_expect_success \ >output && diff -u expect output' +# Test \r\n (MSDOS-like systems) +echo -ne '*.1\r\n/*.3\r\n!*.6\r\n' >.gitignore + +test_expect_success \ + 'git-ls-files --others with \r\n line endings.' \ + 'git-ls-files --others \ + --exclude=\*.6 \ + --exclude-per-directory=.gitignore \ + --exclude-from=.git/ignore \ + >output && + diff -u expect output' + test_done diff --git a/tag.c b/tag.c index b1ab75ff01..e574c4b7a4 100644 --- a/tag.c +++ b/tag.c @@ -3,10 +3,15 @@ const char *tag_type = "tag"; -struct object *deref_tag(struct object *o) +struct object *deref_tag(struct object *o, const char *warn, int warnlen) { while (o && o->type == tag_type) o = parse_object(((struct tag *)o)->tagged->sha1); + if (!o && warn) { + if (!warnlen) + warnlen = strlen(warn); + error("missing object referenced by '%.*s'", warnlen, warn); + } return o; } diff --git a/tag.h b/tag.h index 36e532401f..7a0cb0070d 100644 --- a/tag.h +++ b/tag.h @@ -15,6 +15,6 @@ struct tag { extern struct tag *lookup_tag(const unsigned char *sha1); extern int parse_tag_buffer(struct tag *item, void *data, unsigned long size); extern int parse_tag(struct tag *item); -extern struct object *deref_tag(struct object *); +extern struct object *deref_tag(struct object *, const char *, int); #endif /* TAG_H */ diff --git a/upload-pack.c b/upload-pack.c index c5eff21363..be63132804 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -226,7 +226,7 @@ static int send_ref(const char *refname, const unsigned char *sha1) nr_our_refs++; } if (o->type == tag_type) { - o = deref_tag(o); + o = deref_tag(o, refname, 0); packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname); } return 0;