Merge branch 'jk/help-plug-memleak'
authorJunio C Hamano <gitster@pobox.com>
Sat, 28 Jul 2012 04:16:45 +0000 (21:16 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 28 Jul 2012 04:16:45 +0000 (21:16 -0700)
Plug a few trivial memory leaks.

* jk/help-plug-memleak:
help.c::exclude_cmds(): plug a leak
help.c::uniq: plug a leak

Documentation/revisions.txt
attr.c
builtin/checkout.c
dir.c
git-rebase--interactive.sh
git-submodule.sh
t/t1306-xdg-files.sh
t/t3404-rebase-interactive.sh
t/t7409-submodule-detached-worktree.sh [new file with mode: 0644]
t/test-lib.sh
index 1725661837ad666dc1a06b19162a43f10fe6e13a..dc0070bcb7ec2f4e6773066ffb745967d9df6fb3 100644 (file)
@@ -24,22 +24,22 @@ blobs contained in a commit.
   object referenced by 'refs/heads/master'.  If you
   happen to have both 'heads/master' and 'tags/master', you can
   explicitly say 'heads/master' to tell git which one you mean.
-  When ambiguous, a '<name>' is disambiguated by taking the
+  When ambiguous, a '<refname>' is disambiguated by taking the
   first match in the following rules:
 
-  . If '$GIT_DIR/<name>' exists, that is what you mean (this is usually
+  . If '$GIT_DIR/<refname>' exists, that is what you mean (this is usually
     useful only for 'HEAD', 'FETCH_HEAD', 'ORIG_HEAD', 'MERGE_HEAD'
     and 'CHERRY_PICK_HEAD');
 
-  . otherwise, 'refs/<name>' if it exists;
+  . otherwise, 'refs/<refname>' if it exists;
 
   . otherwise, 'refs/tags/<refname>' if it exists;
 
-  . otherwise, 'refs/heads/<name>' if it exists;
+  . otherwise, 'refs/heads/<refname>' if it exists;
 
-  . otherwise, 'refs/remotes/<name>' if it exists;
+  . otherwise, 'refs/remotes/<refname>' if it exists;
 
-  . otherwise, 'refs/remotes/<name>/HEAD' if it exists.
+  . otherwise, 'refs/remotes/<refname>/HEAD' if it exists.
 +
 'HEAD' names the commit on which you based the changes in the working tree.
 'FETCH_HEAD' records the branch which you fetched from a remote repository
@@ -218,13 +218,44 @@ and its parent commits exist.  The 'r1{caret}@' notation means all
 parents of 'r1'.  'r1{caret}!' includes commit 'r1' but excludes
 all of its parents.
 
+To summarize:
+
+'<rev>'::
+       Include commits that are reachable from (i.e. ancestors of)
+       <rev>.
+
+'{caret}<rev>'::
+       Exclude commits that are reachable from (i.e. ancestors of)
+       <rev>.
+
+'<rev1>..<rev2>'::
+       Include commits that are reachable from <rev2> but exclude
+       those that are reachable from <rev1>.
+
+'<rev1>\...<rev2>'::
+       Include commits that are reachable from either <rev1> or
+       <rev2> but exclude those that are reachable from both.
+
+'<rev>{caret}@', e.g. 'HEAD{caret}@'::
+  A suffix '{caret}' followed by an at sign is the same as listing
+  all parents of '<rev>' (meaning, include anything reachable from
+  its parents, but not the commit itself).
+
+'<rev>{caret}!', e.g. 'HEAD{caret}!'::
+  A suffix '{caret}' followed by an exclamation mark is the same
+  as giving commit '<rev>' and then all its parents prefixed with
+  '{caret}' to exclude them (and their ancestors).
+
 Here are a handful of examples:
 
    D                G H D
    D F              G H I J D F
    ^G D             H D
    ^D B             E I J F B
+   B..C             C
    B...C            G H D E B C
    ^D B C           E I J F B C
+   C                I J F C
    C^@              I J F
+   C^!              C
    F^! D            G H D F
diff --git a/attr.c b/attr.c
index aef93d896f7e72ec534c0c2c576e418bedc5cb30..b52efb55a036be10618d531d66697d7f7220c524 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -520,11 +520,13 @@ static void bootstrap_attr_stack(void)
                home_config_paths(NULL, &xdg_attributes_file, "attributes");
                git_attributes_file = xdg_attributes_file;
        }
-       elem = read_attr_from_file(git_attributes_file, 1);
-       if (elem) {
-               elem->origin = NULL;
-               elem->prev = attr_stack;
-               attr_stack = elem;
+       if (git_attributes_file) {
+               elem = read_attr_from_file(git_attributes_file, 1);
+               if (elem) {
+                       elem->origin = NULL;
+                       elem->prev = attr_stack;
+                       attr_stack = elem;
+               }
        }
 
        if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
index 6acca75f4740e9412c418124ce791c00f7b4ba4b..d812219b30247795b6db7487329605a088057db1 100644 (file)
@@ -606,7 +606,7 @@ static int add_pending_uninteresting_ref(const char *refname,
                                         const unsigned char *sha1,
                                         int flags, void *cb_data)
 {
-       add_pending_sha1(cb_data, refname, sha1, flags | UNINTERESTING);
+       add_pending_sha1(cb_data, refname, sha1, UNINTERESTING);
        return 0;
 }
 
diff --git a/dir.c b/dir.c
index a772c6dc6c2bf4dc40f46f0bb5d0899312f3ffd4..240bf0c49c9654b7cef56959786613e17113c3a0 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -1313,7 +1313,7 @@ void setup_standard_excludes(struct dir_struct *dir)
        }
        if (!access(path, R_OK))
                add_excludes_from_file(dir, path);
-       if (!access(excludes_file, R_OK))
+       if (excludes_file && !access(excludes_file, R_OK))
                add_excludes_from_file(dir, excludes_file);
 }
 
index bef7bc0444bab7b7e511c6e29417ce6db44b77ef..0d2056f027cbd6811faee3c45088a11b24d86102 100644 (file)
@@ -493,25 +493,28 @@ do_next () {
                author_script_content=$(get_author_ident_from_commit HEAD)
                echo "$author_script_content" > "$author_script"
                eval "$author_script_content"
-               output git reset --soft HEAD^
-               pick_one -n $sha1 || die_failed_squash $sha1 "$rest"
+               if ! pick_one -n $sha1
+               then
+                       git rev-parse --verify HEAD >"$amend"
+                       die_failed_squash $sha1 "$rest"
+               fi
                case "$(peek_next_command)" in
                squash|s|fixup|f)
                        # This is an intermediate commit; its message will only be
                        # used in case of trouble.  So use the long version:
-                       do_with_author output git commit --no-verify -F "$squash_msg" ||
+                       do_with_author output git commit --amend --no-verify -F "$squash_msg" ||
                                die_failed_squash $sha1 "$rest"
                        ;;
                *)
                        # This is the final command of this squash/fixup group
                        if test -f "$fixup_msg"
                        then
-                               do_with_author git commit --no-verify -F "$fixup_msg" ||
+                               do_with_author git commit --amend --no-verify -F "$fixup_msg" ||
                                        die_failed_squash $sha1 "$rest"
                        else
                                cp "$squash_msg" "$GIT_DIR"/SQUASH_MSG || exit
                                rm -f "$GIT_DIR"/MERGE_MSG
-                               do_with_author git commit --no-verify -e ||
+                               do_with_author git commit --amend --no-verify -F "$GIT_DIR"/SQUASH_MSG -e ||
                                        die_failed_squash $sha1 "$rest"
                        fi
                        rm -f "$squash_msg" "$fixup_msg"
@@ -748,7 +751,6 @@ In both case, once you're done, continue with:
                fi
                . "$author_script" ||
                        die "Error trying to find the author identity to amend commit"
-               current_head=
                if test -f "$amend"
                then
                        current_head=$(git rev-parse --verify HEAD)
@@ -756,13 +758,12 @@ In both case, once you're done, continue with:
                        die "\
 You have uncommitted changes in your working tree. Please, commit them
 first and then run 'git rebase --continue' again."
-                       git reset --soft HEAD^ ||
-                       die "Cannot rewind the HEAD"
+                       do_with_author git commit --amend --no-verify -F "$msg" -e ||
+                               die "Could not commit staged changes."
+               else
+                       do_with_author git commit --no-verify -F "$msg" -e ||
+                               die "Could not commit staged changes."
                fi
-               do_with_author git commit --no-verify -F "$msg" -e || {
-                       test -n "$current_head" && git reset --soft $current_head
-                       die "Could not commit staged changes."
-               }
        fi
 
        record_in_rewritten "$(cat "$state_dir"/stopped-sha)"
index dba4d39e1fd3e971336e0d85f24c114c29c4d1fd..9210f3af564356be7cccf02307b2045084b4357a 100755 (executable)
@@ -181,8 +181,11 @@ module_clone()
                rm -f "$gitdir/index"
        else
                mkdir -p "$gitdir_base"
-               git clone $quiet -n ${reference:+"$reference"} \
-                       --separate-git-dir "$gitdir" "$url" "$sm_path" ||
+               (
+                       clear_local_git_env
+                       git clone $quiet -n ${reference:+"$reference"} \
+                               --separate-git-dir "$gitdir" "$url" "$sm_path"
+               ) ||
                die "$(eval_gettext "Clone of '\$url' into submodule path '\$sm_path' failed")"
        fi
 
index 3c75c3f2e7e8f980a83fa05db24cf64e7b1cd5a3..8b14ab187c5e01a27bbc4964e3ac9d89e2eb8934 100755 (executable)
@@ -38,6 +38,13 @@ test_expect_success 'read with --get: xdg file exists and ~/.gitconfig doesn'\''
        test_cmp expected actual
 '
 
+test_expect_success '"$XDG_CONFIG_HOME overrides $HOME/.config/git' '
+       mkdir -p "$HOME"/xdg/git &&
+       echo "[user]name = in_xdg" >"$HOME"/xdg/git/config &&
+       echo in_xdg >expected &&
+       XDG_CONFIG_HOME="$HOME"/xdg git config --get-all user.name >actual &&
+       test_cmp expected actual
+'
 
 test_expect_success 'read with --get: xdg file exists and ~/.gitconfig exists' '
        >.gitconfig &&
@@ -80,6 +87,17 @@ test_expect_success 'Exclusion of a file in the XDG ignore file' '
        test_must_fail git add to_be_excluded
 '
 
+test_expect_success '$XDG_CONFIG_HOME overrides $HOME/.config/git/ignore' '
+       mkdir -p "$HOME"/xdg/git &&
+       echo content >excluded_by_xdg_only &&
+       echo excluded_by_xdg_only >"$HOME"/xdg/git/ignore &&
+       test_when_finished "git read-tree --empty" &&
+       (XDG_CONFIG_HOME="$HOME/xdg" &&
+        export XDG_CONFIG_HOME &&
+        git add to_be_excluded &&
+        test_must_fail git add excluded_by_xdg_only
+       )
+'
 
 test_expect_success 'Exclusion in both XDG and local ignore files' '
        echo to_be_excluded >.gitignore &&
@@ -95,6 +113,13 @@ test_expect_success 'Exclusion in a non-XDG global ignore file' '
        test_must_fail git add to_be_excluded
 '
 
+test_expect_success 'Checking XDG ignore file when HOME is unset' '
+       >expected &&
+       (sane_unset HOME &&
+        git config --unset core.excludesfile &&
+        git ls-files --exclude-standard --ignored >actual) &&
+       test_cmp expected actual
+'
 
 test_expect_success 'Checking attributes in the XDG attributes file' '
        echo foo >f &&
@@ -106,6 +131,20 @@ test_expect_success 'Checking attributes in the XDG attributes file' '
        test_cmp expected actual
 '
 
+test_expect_success 'Checking XDG attributes when HOME is unset' '
+       >expected &&
+       (sane_unset HOME &&
+        git check-attr -a f >actual) &&
+       test_cmp expected actual
+'
+
+test_expect_success '$XDG_CONFIG_HOME overrides $HOME/.config/git/attributes' '
+       mkdir -p "$HOME"/xdg/git &&
+       echo "f attr_f=xdg" >"$HOME"/xdg/git/attributes &&
+       echo "f: attr_f: xdg" >expected &&
+       XDG_CONFIG_HOME="$HOME/xdg" git check-attr -a f >actual &&
+       test_cmp expected actual
+'
 
 test_expect_success 'Checking attributes in both XDG and local attributes files' '
        echo "f -attr_f" >.gitattributes &&
index 8078db6856ba4428e9d6b13f5e02076da7963b09..3f75d328de8ee08e0d27b3eb589d9c247182d435 100755 (executable)
@@ -903,4 +903,12 @@ test_expect_success 'rebase -i --root temporary sentinel commit' '
        git rebase --abort
 '
 
+test_expect_success 'rebase -i --root fixup root commit' '
+       git checkout B &&
+       FAKE_LINES="1 fixup 2" git rebase -i --root &&
+       test A = $(git cat-file commit HEAD | sed -ne \$p) &&
+       test B = $(git show HEAD:file1) &&
+       test 0 = $(git cat-file commit HEAD | grep -c ^parent\ )
+'
+
 test_done
diff --git a/t/t7409-submodule-detached-worktree.sh b/t/t7409-submodule-detached-worktree.sh
new file mode 100644 (file)
index 0000000..db75642
--- /dev/null
@@ -0,0 +1,61 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Daniel GraƱa
+#
+
+test_description='Test submodules on detached working tree
+
+This test verifies that "git submodule" initialization, update and addition works
+on detahced working trees
+'
+
+TEST_NO_CREATE_REPO=1
+. ./test-lib.sh
+
+test_expect_success 'submodule on detached working tree' '
+       git init --bare remote &&
+       test_create_repo bundle1 &&
+       (cd bundle1 && test_commit "shoot") &&
+       mkdir home &&
+       (
+               cd home &&
+               export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" &&
+               git clone --bare ../remote .dotfiles &&
+               git submodule add ../bundle1 .vim/bundle/sogood &&
+               test_commit "sogood" &&
+               git push origin master
+       ) &&
+       mkdir home2 &&
+       (
+               cd home2 &&
+               export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" &&
+               git clone --bare ../remote .dotfiles &&
+               git submodule update --init
+       )
+'
+
+test_expect_success 'submodule on detached working pointed by core.worktree' '
+       mkdir home3 &&
+       (
+               cd home3 &&
+               export GIT_DIR="$(pwd)/.dotfiles" &&
+               git clone --bare ../remote "$GIT_DIR" &&
+               git config core.bare false &&
+               git config core.worktree .. &&
+               git submodule add ../bundle1 .vim/bundle/dupe &&
+               test_commit "dupe" &&
+               git push origin master
+       ) &&
+       (
+               cd home &&
+               export GIT_DIR="$(pwd)/.dotfiles" &&
+               git config core.bare false &&
+               git config core.worktree .. &&
+               git pull &&
+               git submodule update &&
+               git submodule status &&
+               test -d .vim/bundle/dupe
+       )
+'
+
+test_done
index acda33d177197c4288e8b7a33385f11c63c44698..bb4f8865b2628665f4adbf9ceef03d5a9081e244 100644 (file)
@@ -34,6 +34,26 @@ esac
 # Keep the original TERM for say_color
 ORIGINAL_TERM=$TERM
 
+# Test the binaries we have just built.  The tests are kept in
+# t/ subdirectory and are run in 'trash directory' subdirectory.
+if test -z "$TEST_DIRECTORY"
+then
+       # We allow tests to override this, in case they want to run tests
+       # outside of t/, e.g. for running tests on the test library
+       # itself.
+       TEST_DIRECTORY=$(pwd)
+fi
+if test -z "$TEST_OUTPUT_DIRECTORY"
+then
+       # Similarly, override this to store the test-results subdir
+       # elsewhere
+       TEST_OUTPUT_DIRECTORY=$TEST_DIRECTORY
+fi
+GIT_BUILD_DIR="$TEST_DIRECTORY"/..
+
+. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS
+export PERL_PATH SHELL_PATH
+
 # For repeatability, reset the environment to known value.
 LANG=C
 LC_ALL=C
@@ -46,7 +66,7 @@ EDITOR=:
 # /usr/xpg4/bin/sh and /bin/ksh to bail out.  So keep the unsets
 # deriving from the command substitution clustered with the other
 # ones.
-unset VISUAL EMAIL LANGUAGE COLUMNS $(perl -e '
+unset VISUAL EMAIL LANGUAGE COLUMNS $("$PERL_PATH" -e '
        my @env = keys %ENV;
        my $ok = join("|", qw(
                TRACE
@@ -61,6 +81,7 @@ unset VISUAL EMAIL LANGUAGE COLUMNS $(perl -e '
        my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
        print join("\n", @vars);
 ')
+unset XDG_CONFIG_HOME
 GIT_AUTHOR_EMAIL=author@example.com
 GIT_AUTHOR_NAME='A U Thor'
 GIT_COMMITTER_EMAIL=committer@example.com
@@ -229,7 +250,7 @@ trap 'die' EXIT
 
 # The user-facing functions are loaded from a separate file so that
 # test_perf subshells can have them too
-. "${TEST_DIRECTORY:-.}"/test-lib-functions.sh
+. "$TEST_DIRECTORY/test-lib-functions.sh"
 
 # You are not expected to call test_ok_ and test_failure_ directly, use
 # the text_expect_* functions instead.
@@ -380,23 +401,6 @@ test_done () {
        esac
 }
 
-# Test the binaries we have just built.  The tests are kept in
-# t/ subdirectory and are run in 'trash directory' subdirectory.
-if test -z "$TEST_DIRECTORY"
-then
-       # We allow tests to override this, in case they want to run tests
-       # outside of t/, e.g. for running tests on the test library
-       # itself.
-       TEST_DIRECTORY=$(pwd)
-fi
-if test -z "$TEST_OUTPUT_DIRECTORY"
-then
-       # Similarly, override this to store the test-results subdir
-       # elsewhere
-       TEST_OUTPUT_DIRECTORY=$TEST_DIRECTORY
-fi
-GIT_BUILD_DIR="$TEST_DIRECTORY"/..
-
 if test -n "$valgrind"
 then
        make_symlink () {
@@ -492,10 +496,6 @@ GIT_CONFIG_NOSYSTEM=1
 GIT_ATTR_NOSYSTEM=1
 export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM
 
-. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS
-
-export PERL_PATH
-
 if test -z "$GIT_TEST_CMP"
 then
        if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT"