Merge branch 'sp/merge' (early part)
authorJunio C Hamano <junkio@cox.net>
Mon, 1 Jan 2007 22:40:37 +0000 (14:40 -0800)
committerJunio C Hamano <junkio@cox.net>
Mon, 1 Jan 2007 22:40:37 +0000 (14:40 -0800)
* 'sp/merge' (early part):
Use merge-recursive in git-am -3.
Allow merging bare trees in merge-recursive.
Move better_branch_name above get_ref in merge-recursive.

54 files changed:
Documentation/config.txt
Documentation/cvs-migration.txt
Documentation/git-clone.txt
Documentation/git-commit-tree.txt
Documentation/git-commit.txt
Documentation/git-log.txt
Documentation/git-pull.txt
Documentation/git-repo-config.txt
Documentation/git-rev-list.txt
Documentation/git-show.txt
Documentation/glossary.txt
Documentation/hooks.txt
Documentation/i18n.txt [new file with mode: 0644]
Documentation/pretty-formats.txt
Documentation/pull-fetch-param.txt
Documentation/technical/send-pack-pipeline.txt [new file with mode: 0644]
Documentation/tutorial.txt
Documentation/urls.txt
Makefile
builtin-add.c
builtin-commit-tree.c
builtin-init-db.c
builtin-push.c
commit.c
config.c
dir.c
dir.h
git-fetch.sh
git-merge.sh
git-parse-remote.sh
git-pull.sh
git.c
http.h
receive-pack.c
revision.c
run-command.c
run-command.h
send-pack.c
setup.c
t/README
t/lib-git-svn.sh
t/t1300-repo-config.sh
t/t3700-add.sh
t/t3900-i18n-commit.sh
t/t5400-send-pack.sh
t/t5401-update-hooks.sh [new file with mode: 0755]
t/t9100-git-svn-basic.sh
t/t9101-git-svn-props.sh
t/t9103-git-svn-graft-branches.sh
t/t9104-git-svn-follow-parent.sh
t/test-lib.sh
utf8.c
utf8.h
xdiff/xmerge.c
index 178e0e1e209e066ad220d6ba95be0728c2db5e99..2f4fc252589017b13fff74445b85c951362a6236 100644 (file)
@@ -82,13 +82,13 @@ core.logAllRefUpdates::
        only when the file exists.  If this configuration
        variable is set to true, missing "$GIT_DIR/logs/<ref>"
        file is automatically created for branch heads.
-
-       This information can be used to determine what commit
-       was the tip of a branch "2 days ago".
-
-       This value is true by default in a repository that has
-       a working directory associated with it, and false by
-       default in a bare repository.
++
+This information can be used to determine what commit
+was the tip of a branch "2 days ago".
++
+This value is true by default in a repository that has
+a working directory associated with it, and false by
+default in a bare repository.
 
 core.repositoryFormatVersion::
        Internal variable identifying the repository format and layout
index b657f4589f95257547b646ef22d3201fefbae6d6..8e09beaa799dbff462b258e5593fd5c79c91312a 100644 (file)
@@ -34,13 +34,10 @@ them first before running git pull.
 
 [NOTE]
 ================================
-The first `git clone` places the following in the
-`my-project/.git/remotes/origin` file, and that's why the previous step
-and the next step both work.
-------------
-URL: foo.com:/pub/project.git/
-Pull: refs/heads/master:refs/remotes/origin/master
-------------
+The `pull` command knows where to get updates from because of certain
+configuration variables that were set by the first `git clone`
+command; see `git repo-config -l` and the gitlink:git-repo-config[1] man
+page for details.
 ================================
 
 You can update the shared repository with your changes by first committing
index 874934a33243106544181ffeae2fee8b03ff5e8d..96523204ddda292bb01a55f042f249515f821613 100644 (file)
@@ -75,16 +75,13 @@ OPTIONS
        Also the branch heads at the remote are copied directly
        to corresponding local branch heads, without mapping
        them to `refs/remotes/origin/`.  When this option is
-       used, neither the `origin` branch nor the default
-       `remotes/origin` file is created.
+       used, neither remote-tracking branches nor the related
+       configuration variables are created.
 
 --origin <name>::
 -o <name>::
-       Instead of using the branch name 'origin' to keep track
-       of the upstream repository, use <name> instead.  Note
-       that the shorthand name stored in `remotes/origin` is
-       not affected, but the local branch name to pull the
-       remote `master` branch into is.
+       Instead of using the remote name 'origin' to keep track
+       of the upstream repository, use <name> instead.
 
 --upload-pack <upload-pack>::
 -u <upload-pack>::
index 41d1a1c4b340b17a545feebe9877def8b009933f..77ba96ed8a4820354ef6d2ff4265660385289f3d 100644 (file)
@@ -81,6 +81,11 @@ Your parents must have hated you!::
 Your sysadmin must hate you!::
     The password(5) name field is longer than a giant static buffer.
 
+Discussion
+----------
+
+include::i18n.txt[]
+
 See Also
 --------
 gitlink:git-write-tree[1]
index 0b74cd708ecaa63ccc19d2db40790b315539ce8b..a7adf24fa5a601f372099988c1fedfb929ceaab1 100644 (file)
@@ -223,6 +223,11 @@ should be recorded as a single commit.  In fact, the command
 refuses to run when given pathnames (but see `-i` option).
 
 
+DISCUSSION
+----------
+
+include::i18n.txt[]
+
 ENVIRONMENT VARIABLES
 ---------------------
 The command specified by either the VISUAL or EDITOR environment
index 79643ac928b05b4a97a09a5adfb67b1b4a2b832c..e9f746bbd4cebde9d8f5b90dd8fea6a2a610b140 100644 (file)
@@ -31,7 +31,9 @@ include::pretty-formats.txt[]
        Limits the number of commits to show.
 
 <since>..<until>::
-       Show only commits between the named two commits.
+       Show only commits between the named two commits.  When
+       either <since> or <until> is omitted, it defaults to
+       `HEAD`, i.e. the tip of the current branch.
 
 -p::
        Show the change the commit introduces in a patch form.
@@ -63,6 +65,12 @@ git log -r --name-status release..test::
        in the "release" branch, along with the list of paths
        each commit modifies.
 
+Discussion
+----------
+
+include::i18n.txt[]
+
+
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>
index 2a5aea73bafedd62f20cecb1fbf5069b515022bd..13be992006d8252ca737e37dd21ed8f2d1e13412 100644 (file)
@@ -37,17 +37,27 @@ EXAMPLES
 --------
 
 git pull, git pull origin::
-       Fetch the default head from the repository you cloned
-       from and merge it into your current branch.
-
-git pull -s ours . obsolete::
-       Merge local branch `obsolete` into the current branch,
-       using `ours` merge strategy.
+       Update the remote-tracking branches for the repository
+       you cloned from, then merge one of them into your
+       current branch.  Normally the branch merged in is
+       the HEAD of the remote repository, but the choice is
+       determined by the branch.<name>.remote and
+       branch.<name>.merge options; see gitlink:git-repo-config[1]
+       for details.
+
+git pull origin next::
+       Merge into the current branch the remote branch `next`;
+       leaves a copy of `next` temporarily in FETCH_HEAD, but
+       does not update any remote-tracking branches.
 
 git pull . fixes enhancements::
        Bundle local branch `fixes` and `enhancements` on top of
        the current branch, making an Octopus merge.
 
+git pull -s ours . obsolete::
+       Merge local branch `obsolete` into the current branch,
+       using `ours` merge strategy.
+
 git pull --no-commit . maint::
        Merge local branch `maint` into the current branch, but
        do not make a commit automatically.  This can be used
@@ -61,48 +71,19 @@ release/version name would be acceptable.
 Command line pull of multiple branches from one repository::
 +
 ------------------------------------------------
-$ cat .git/remotes/origin
-URL: git://git.kernel.org/pub/scm/git/git.git
-Pull: master:origin
-
 $ git checkout master
-$ git fetch origin master:origin +pu:pu maint:maint
-$ git pull . origin
+$ git fetch origin +pu:pu maint:tmp
+$ git pull . tmp
 ------------------------------------------------
 +
-Here, a typical `.git/remotes/origin` file from a
-`git-clone` operation is used in combination with
-command line options to `git-fetch` to first update
-multiple branches of the local repository and then
-to merge the remote `origin` branch into the local
-`master` branch.  The local `pu` branch is updated
-even if it does not result in a fast forward update.
-Here, the pull can obtain its objects from the local
-repository using `.`, as the previous `git-fetch` is
-known to have already obtained and made available
-all the necessary objects.
-
-
-Pull of multiple branches from one repository using `.git/remotes` file::
+This updates (or creates, as necessary) branches `pu` and `tmp`
+in the local repository by fetching from the branches
+(respectively) `pu` and `maint` from the remote repository.
 +
-------------------------------------------------
-$ cat .git/remotes/origin
-URL: git://git.kernel.org/pub/scm/git/git.git
-Pull: master:origin
-Pull: +pu:pu
-Pull: maint:maint
-
-$ git checkout master
-$ git pull origin
-------------------------------------------------
+The `pu` branch will be updated even if it is does not
+fast-forward; the others will not be.
 +
-Here, a typical `.git/remotes/origin` file from a
-`git-clone` operation has been hand-modified to include
-the branch-mapping of additional remote and local
-heads directly.  A single `git-pull` operation while
-in the `master` branch will fetch multiple heads and
-merge the remote `origin` head into the current,
-local `master` branch.
+The final command then merges the newly fetched `tmp` into master.
 
 
 If you tried a pull which resulted in a complex conflicts and
@@ -112,7 +93,7 @@ gitlink:git-reset[1].
 
 SEE ALSO
 --------
-gitlink:git-fetch[1], gitlink:git-merge[1]
+gitlink:git-fetch[1], gitlink:git-merge[1], gitlink:git-repo-config[1]
 
 
 Author
index b379ec5075981347e75d0795e44e57620d89399b..c55a8ba0dcfc63110920bf6b5e8db91732d11853 100644 (file)
@@ -87,7 +87,10 @@ OPTIONS
        git-repo-config will ensure that the output is "true" or "false"
 
 --int::
-       git-repo-config will ensure that the output is a simple decimal number
+       git-repo-config will ensure that the output is a simple
+       decimal number.  An optional value suffix of 'k', 'm', or 'g'
+       in the config file will cause the value to be multiplied
+       by 1024, 1048576, or 1073741824 prior to output.
 
 
 ENVIRONMENT
index 9e0dcf8d3fef2495da4940ce662a46cc8a2bf621..86c94e7dfd257f5a7eff5c9d5aa4540a41128864 100644 (file)
@@ -21,6 +21,7 @@ SYNOPSIS
             [ \--stdin ]
             [ \--topo-order ]
             [ \--parents ]
+            [ \--encoding[=<encoding>] ]
             [ \--(author|committer|grep)=<pattern> ]
             [ [\--objects | \--objects-edge] [ \--unpacked ] ]
             [ \--pretty | \--header ]
index 98dea6125da78fa74800925b57dad2f002b1d6f6..c210b9af6bb4ce09d061e24715b07cd64887d54c 100644 (file)
@@ -30,8 +30,8 @@ This manual page describes only the most frequently used options.
 
 OPTIONS
 -------
-<commitid>::
-       ID of the commit to show.
+<object>::
+       The name of the object to show.
 
 include::pretty-formats.txt[]
 
@@ -40,7 +40,8 @@ EXAMPLES
 --------
 
 git show v1.0.0::
-       Shows the tag `v1.0.0`.
+       Shows the tag `v1.0.0`, along with the object the tags
+       points at.
 
 git show v1.0.0^{tree}::
        Shows the tree pointed to by the tag `v1.0.0`.
@@ -54,10 +55,16 @@ git show master:Makefile master:t/Makefile
        Concatenates the contents of said Makefiles in the head
        of the branch `master`.
 
+Discussion
+----------
+
+include::i18n.txt[]
+
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org> and
-Junio C Hamano <junkio@cox.net>
+Junio C Hamano <junkio@cox.net>.  Significantly enhanced by
+Johannes Schindelin <Johannes.Schindelin@gmx.de>.
 
 
 Documentation
index 894883d7b60c4c79263323fc007406c4f3720bac..7c1a6592c112a76c23c2833537a13f40337c261c 100644 (file)
@@ -188,11 +188,12 @@ octopus::
        predator.
 
 origin::
-       The default upstream tracking branch. Most projects have at
+       The default upstream repository. Most projects have at
        least one upstream project which they track. By default
        'origin' is used for that purpose.  New upstream updates
-       will be fetched into this branch; you should never commit
-       to it yourself.
+       will be fetched into remote tracking branches named
+       origin/name-of-upstream-branch, which you can see using
+       "git branch -r".
 
 pack::
        A set of objects which have been compressed into one file (to save
index 517f49b5cc5016a20b171789b89f48cb6ef0ecd5..161123f142ff231bc8153242d7f6507c54b09e2b 100644 (file)
@@ -126,9 +126,9 @@ Another use suggested on the mailing list is to use this hook to
 implement access control which is finer grained than the one
 based on filesystem group.
 
-The standard output of this hook is sent to `/dev/null`; if you
+The standard output of this hook is sent to `stderr`, so if you
 want to report something to the `git-send-pack` on the other end,
-you can redirect your output to your `stderr`.
+you can simply `echo` your messages.
 
 
 post-update
diff --git a/Documentation/i18n.txt b/Documentation/i18n.txt
new file mode 100644 (file)
index 0000000..b4cbb38
--- /dev/null
@@ -0,0 +1,57 @@
+At the core level, git is character encoding agnostic.
+
+ - The pathnames recorded in the index and in the tree objects
+   are treated as uninterpreted sequences of non-NUL bytes.
+   What readdir(2) returns are what are recorded and compared
+   with the data git keeps track of, which in turn are expected
+   to be what lstat(2) and creat(2) accepts.  There is no such
+   thing as pathname encoding translation.
+
+ - The contents of the blob objects are uninterpreted sequence
+   of bytes.  There is no encoding translation at the core
+   level.
+
+ - The commit log messages are uninterpreted sequence of non-NUL
+   bytes.
+
+Although we encourage that the commit log messages are encoded
+in UTF-8, both the core and git Porcelain are designed not to
+force UTF-8 on projects.  If all participants of a particular
+project find it more convenient to use legacy encodings, git
+does not forbid it.  However, there are a few things to keep in
+mind.
+
+. `git-commit-tree` (hence, `git-commit` which uses it) issues
+  an warning if the commit log message given to it does not look
+  like a valid UTF-8 string, unless you explicitly say your
+  project uses a legacy encoding.  The way to say this is to
+  have core.commitencoding in `.git/config` file, like this:
++
+------------
+[core]
+       commitencoding = ISO-8859-1
+------------
++
+Commit objects created with the above setting record the value
+of `core.commitencoding` in its `encoding` header.  This is to
+help other people who look at them later.  Lack of this header
+implies that the commit log message is encoded in UTF-8.
+
+. `git-log`, `git-show` and friends looks at the `encoding`
+  header of a commit object, and tries to re-code the log
+  message into UTF-8 unless otherwise specified.  You can
+  specify the desired output encoding with
+  `core.logoutputencoding` in `.git/config` file, like this:
++
+------------
+[core]
+       logoutputencoding = ISO-8859-1
+------------
++
+If you do not have this configuration variable, the value of
+`core.commitencoding` is used instead.
+
+Note that we deliberately chose not to re-code the commit log
+message when a commit is made to force UTF-8 at the commit
+object level, because re-coding to UTF-8 is not necessarily a
+reversible operation.
index 996f6289031a4535a29579f3111998856eb31bfd..fb0b0b95829e0fc1aa98019554ce12e9b45d1f63 100644 (file)
@@ -76,3 +76,10 @@ displayed in full, regardless of whether --abbrev or
 --no-abbrev are used, and 'parents' information show the
 true parent commits, without taking grafts nor history
 simplification into account.
+
+--encoding[=<encoding>]::
+       The commit objects record the encoding used for the log message
+       in their encoding header; this option can be used to tell the
+       command to re-code the commit log message in the encoding
+       preferred by the user.  For non plumbing commands this
+       defaults to UTF-8.
index e852f41a322933aa010bdf79247508e42ee3f661..8d4e950abc65c233268d785dcbfee67ab0522f4c 100644 (file)
@@ -39,10 +39,6 @@ checkout -b my-B remote-B`).  Run `git fetch` to keep track of
 the progress of the remote side, and when you see something new
 on the remote branch, merge it into your development branch with
 `git pull . remote-B`, while you are on `my-B` branch.
-The common `Pull: master:origin` mapping of a remote `master`
-branch to a local `origin` branch, which is then merged to a
-local development branch, again typically named `master`, is made
-when you run `git clone` for you to follow this pattern.
 +
 [NOTE]
 There is a difference between listing multiple <refspec>
diff --git a/Documentation/technical/send-pack-pipeline.txt b/Documentation/technical/send-pack-pipeline.txt
new file mode 100644 (file)
index 0000000..681efe4
--- /dev/null
@@ -0,0 +1,63 @@
+git-send-pack
+=============
+
+Overall operation
+-----------------
+
+. Connects to the remote side and invokes git-receive-pack.
+
+. Learns what refs the remote has and what commit they point at.
+  Matches them to the refspecs we are pushing.
+
+. Checks if there are non-fast-forwards.  Unlike fetch-pack,
+  the repository send-pack runs in is supposed to be a superset
+  of the recipient in fast-forward cases, so there is no need
+  for want/have exchanges, and fast-forward check can be done
+  locally.  Tell the result to the other end.
+
+. Calls pack_objects() which generates a packfile and sends it
+  over to the other end.
+
+. If the remote side is new enough (v1.1.0 or later), wait for
+  the unpack and hook status from the other end.
+
+. Exit with appropriate error codes.
+
+
+Pack_objects pipeline
+---------------------
+
+This function gets one file descriptor (`fd`) which is either a
+socket (over the network) or a pipe (local).  What's written to
+this fd goes to git-receive-pack to be unpacked.
+
+    send-pack ---> fd ---> receive-pack
+
+The function pack_objects creates a pipe and then forks.  The
+forked child execs pack-objects with --revs to receive revision
+parameters from its standard input. This process will write the
+packfile to the other end.
+
+    send-pack
+       |
+       pack_objects() ---> fd ---> receive-pack
+          | ^ (pipe)
+         v |
+         (child)
+
+The child dup2's to arrange its standard output to go back to
+the other end, and read its standard input to come from the
+pipe.  After that it exec's pack-objects.  On the other hand,
+the parent process, before starting to feed the child pipeline,
+closes the reading side of the pipe and fd to receive-pack.
+
+    send-pack
+       |
+       pack_objects(parent)
+          |
+         v [0]
+         pack-objects [0] ---> receive-pack
+
+
+[jc: the pipeline was much more complex and needed documentation before
+ I understood an earlier bug, but now it is trivial and straightforward.]
index cb808d924be51e111b3e57b1b6e007cdf9f451bb..d043e844d2303d6c1c79eec50a2cd7621469c5b8 100644 (file)
@@ -323,20 +323,25 @@ $ git pull
 
 Note that he doesn't need to give the path to Alice's repository;
 when Bob cloned Alice's repository, git stored the location of her
-repository in the file .git/remotes/origin, and that location is used
-as the default for pulls.
-
-Bob may also notice a branch in his repository that he didn't create:
+repository in the repository configuration, and that location is
+used for pulls:
 
 -------------------------------------
-$ git branch
-* master
-  origin
+$ git repo-config --get remote.origin.url
+/home/bob/myrepo
 -------------------------------------
 
-The "origin" branch, which was created automatically by "git clone",
-is a pristine copy of Alice's master branch; Bob should never commit
-to it.
+(The complete configuration created by git-clone is visible using
+"git repo-config -l", and the gitlink:git-repo-config[1] man page
+explains the meaning of each option.)
+
+Git also keeps a pristine copy of Alice's master branch under the
+name "origin/master":
+
+-------------------------------------
+$ git branch -r
+  origin/master
+-------------------------------------
 
 If Bob later decides to work from a different host, he can still
 perform clones and pulls using the ssh protocol:
index 670827c323fe276124ba1a84d59386771db868f1..745f9677d005b522f52496339abd5afc4267a815 100644 (file)
@@ -40,10 +40,13 @@ In addition to the above, as a short-hand, the name of a
 file in `$GIT_DIR/remotes` directory can be given; the
 named file should be in the following format:
 
+------------
        URL: one of the above URL format
        Push: <refspec>
        Pull: <refspec>
 
+------------
+
 Then such a short-hand is specified in place of
 <repository> without <refspec> parameters on the command
 line, <refspec> specified on `Push:` lines or `Pull:`
@@ -54,10 +57,13 @@ be specified for additional branch mappings.
 Or, equivalently, in the `$GIT_DIR/config` (note the use
 of `fetch` instead of `Pull:`):
 
-[remote "<remote>"]
-       url = <url>
-       push = <refspec>
-       fetch = <refspec>
+------------
+       [remote "<remote>"]
+               url = <url>
+               push = <refspec>
+               fetch = <refspec>
+
+------------
 
 The name of a file in `$GIT_DIR/branches` directory can be
 specified as an older notation short-hand; the named
@@ -68,10 +74,15 @@ name of remote head (URL fragment notation).
 without the fragment is equivalent to have this in the
 corresponding file in the `$GIT_DIR/remotes/` directory.
 
+------------
        URL: <url>
        Pull: refs/heads/master:<remote>
 
+------------
+
 while having `<url>#<head>` is equivalent to
 
+------------
        URL: <url>
        Pull: refs/heads/<head>:<remote>
+------------
index 93dc4948d3cd6b655c2e0c630892e67b9ae656eb..fa1a02289c06630274eebbed25b022c4cfeea28b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -72,6 +72,9 @@ all:
 # Define NO_FAST_WORKING_DIRECTORY if accessing objects in pack files is
 # generally faster on your platform than accessing the working directory.
 #
+# Define NO_TRUSTABLE_FILEMODE if your filesystem may claim to support
+# the executable mode bit, but doesn't really do so.
+#
 # Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
 #
 # Define NO_SOCKADDR_STORAGE if your platform does not have struct
@@ -361,6 +364,7 @@ ifeq ($(uname_O),Cygwin)
        NEEDS_LIBICONV = YesPlease
        NO_C99_FORMAT = YesPlease
        NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
+       NO_TRUSTABLE_FILEMODE = UnfortunatelyYes
        # There are conflicting reports about this.
        # On some boxes NO_MMAP is needed, and not so elsewhere.
        # Try commenting this out if you suspect MMAP is more efficient
@@ -521,6 +525,9 @@ endif
 ifdef NO_FAST_WORKING_DIRECTORY
        BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
 endif
+ifdef NO_TRUSTABLE_FILEMODE
+       BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE
+endif
 ifdef NO_IPV6
        BASIC_CFLAGS += -DNO_IPV6
 endif
index 8ed4a6a9f32b9cd0f71289af2296cacf79864448..e7a1b4d9ab43cbb7de48b099c3afb721903f516b 100644 (file)
@@ -26,18 +26,9 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p
        i = dir->nr;
        while (--i >= 0) {
                struct dir_entry *entry = *src++;
-               int how = match_pathspec(pathspec, entry->name, entry->len,
-                                        prefix, seen);
-               /*
-                * ignored entries can be added with exact match,
-                * but not with glob nor recursive.
-                */
-               if (!how ||
-                   (entry->ignored_entry && how != MATCHED_EXACTLY)) {
-                       free(entry);
-                       continue;
-               }
-               *dst++ = entry;
+               if (match_pathspec(pathspec, entry->name, entry->len,
+                                  prefix, seen))
+                       *dst++ = entry;
        }
        dir->nr = dst - dir->entries;
 
@@ -47,10 +38,20 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p
                if (seen[i])
                        continue;
 
-               /* Existing file? We must have ignored it */
                match = pathspec[i];
-               if (!match[0] || !lstat(match, &st))
+               if (!match[0])
                        continue;
+
+               /* Existing file? We must have ignored it */
+               if (!lstat(match, &st)) {
+                       struct dir_entry *ent;
+
+                       ent = dir_add_name(dir, match, strlen(match));
+                       ent->ignored = 1;
+                       if (S_ISDIR(st.st_mode))
+                               ent->ignored_dir = 1;
+                       continue;
+               }
                die("pathspec '%s' did not match any files", match);
        }
 }
@@ -62,8 +63,6 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec)
 
        /* Set up the default git porcelain excludes */
        memset(dir, 0, sizeof(*dir));
-       if (pathspec)
-               dir->show_both = 1;
        dir->exclude_per_dir = ".gitignore";
        path = git_path("info/exclude");
        if (!access(path, R_OK))
@@ -154,7 +153,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
        if (show_only) {
                const char *sep = "", *eof = "";
                for (i = 0; i < dir.nr; i++) {
-                       if (!ignored_too && dir.entries[i]->ignored_entry)
+                       if (!ignored_too && dir.entries[i]->ignored)
                                continue;
                        printf("%s%s", sep, dir.entries[i]->name);
                        sep = " ";
@@ -168,16 +167,19 @@ int cmd_add(int argc, const char **argv, const char *prefix)
                die("index file corrupt");
 
        if (!ignored_too) {
-               int has_ignored = -1;
-               for (i = 0; has_ignored < 0 && i < dir.nr; i++)
-                       if (dir.entries[i]->ignored_entry)
-                               has_ignored = i;
-               if (0 <= has_ignored) {
+               int has_ignored = 0;
+               for (i = 0; i < dir.nr; i++)
+                       if (dir.entries[i]->ignored)
+                               has_ignored = 1;
+               if (has_ignored) {
                        fprintf(stderr, ignore_warning);
-                       for (i = has_ignored; i < dir.nr; i++) {
-                               if (!dir.entries[i]->ignored_entry)
+                       for (i = 0; i < dir.nr; i++) {
+                               if (!dir.entries[i]->ignored)
                                        continue;
-                               fprintf(stderr, "%s\n", dir.entries[i]->name);
+                               fprintf(stderr, "%s", dir.entries[i]->name);
+                               if (dir.entries[i]->ignored_dir)
+                                       fprintf(stderr, " (directory)");
+                               fputc('\n', stderr);
                        }
                        fprintf(stderr,
                                "Use -f if you really want to add them.\n");
index 146aaffd282987454c0910477cfe7a047f478e94..0651e5927e836d22246d84020576ccb3069b6c5d 100644 (file)
@@ -119,8 +119,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
        }
 
        /* Not having i18n.commitencoding is the same as having utf-8 */
-       encoding_is_utf8 = (!git_commit_encoding ||
-                           !strcmp(git_commit_encoding, "utf-8"));
+       encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
 
        init_buffer(&buffer, &size);
        add_buffer(&buffer, &size, "tree %s\n", sha1_to_hex(tree_sha1));
index 01f366ad0bf5860aaf9123ef5d5653c612871a9f..97fd82ff0664aa9a79cf1ace20dac1a5c0064743 100644 (file)
 #define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates/"
 #endif
 
+#ifdef NO_TRUSTABLE_FILEMODE
+#define TEST_FILEMODE 0
+#else
+#define TEST_FILEMODE 1
+#endif
+
 static void safe_create_dir(const char *dir, int share)
 {
        if (mkdir(dir, 0777) < 0) {
@@ -175,6 +181,7 @@ static int create_default_files(const char *git_dir, const char *template_path)
        struct stat st1;
        char repo_version_string[10];
        int reinit;
+       int filemode;
 
        if (len > sizeof(path)-50)
                die("insane git directory %s", git_dir);
@@ -236,14 +243,14 @@ static int create_default_files(const char *git_dir, const char *template_path)
        strcpy(path + len, "config");
 
        /* Check filemode trustability */
-       if (!lstat(path, &st1)) {
+       filemode = TEST_FILEMODE;
+       if (TEST_FILEMODE && !lstat(path, &st1)) {
                struct stat st2;
-               int filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&
+               filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&
                                !lstat(path, &st2) &&
                                st1.st_mode != st2.st_mode);
-               git_config_set("core.filemode",
-                              filemode ? "true" : "false");
        }
+       git_config_set("core.filemode", filemode ? "true" : "false");
 
        /* Enable logAllRefUpdates if a working tree is attached */
        if (!is_bare_git_dir(git_dir))
index b7412e82937a240776cdda07da05797b0b2acb0b..7a3d2bb06416219a41cf6a0757cf3d03a56ef0da 100644 (file)
@@ -275,7 +275,7 @@ static int do_push(const char *repo)
                argv[dest_argc] = NULL;
                if (verbose)
                        fprintf(stderr, "Pushing to %s\n", dest);
-               err = run_command_v(argc, argv);
+               err = run_command_v(argv);
                if (!err)
                        continue;
                switch (err) {
index eb06afbbe0f00ac4f553e37c50eca290418a7907..544e42629e3213a9927134273899d48c6cbe3161 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -624,6 +624,48 @@ static char *get_header(const struct commit *commit, const char *key)
        }
 }
 
+static char *replace_encoding_header(char *buf, char *encoding)
+{
+       char *encoding_header = strstr(buf, "\nencoding ");
+       char *end_of_encoding_header;
+       int encoding_header_pos;
+       int encoding_header_len;
+       int new_len;
+       int need_len;
+       int buflen = strlen(buf) + 1;
+
+       if (!encoding_header)
+               return buf; /* should not happen but be defensive */
+       encoding_header++;
+       end_of_encoding_header = strchr(encoding_header, '\n');
+       if (!end_of_encoding_header)
+               return buf; /* should not happen but be defensive */
+       end_of_encoding_header++;
+
+       encoding_header_len = end_of_encoding_header - encoding_header;
+       encoding_header_pos = encoding_header - buf;
+
+       if (is_encoding_utf8(encoding)) {
+               /* we have re-coded to UTF-8; drop the header */
+               memmove(encoding_header, end_of_encoding_header,
+                       buflen - (encoding_header_pos + encoding_header_len));
+               return buf;
+       }
+       new_len = strlen(encoding);
+       need_len = new_len + strlen("encoding \n");
+       if (encoding_header_len < need_len) {
+               buf = xrealloc(buf, buflen + (need_len - encoding_header_len));
+               encoding_header = buf + encoding_header_pos;
+               end_of_encoding_header = encoding_header + encoding_header_len;
+       }
+       memmove(end_of_encoding_header + (need_len - encoding_header_len),
+               end_of_encoding_header,
+               buflen - (encoding_header_pos + encoding_header_len));
+       memcpy(encoding_header + 9, encoding, strlen(encoding));
+       encoding_header[9 + new_len] = '\n';
+       return buf;
+}
+
 static char *logmsg_reencode(const struct commit *commit)
 {
        char *encoding;
@@ -633,13 +675,20 @@ static char *logmsg_reencode(const struct commit *commit)
                                 : git_commit_encoding);
 
        if (!output_encoding)
+               output_encoding = "utf-8";
+       else if (!*output_encoding)
                return NULL;
        encoding = get_header(commit, "encoding");
-       if (!encoding || !strcmp(encoding, output_encoding)) {
-               free(encoding);
+       if (!encoding)
                return NULL;
-       }
-       out = reencode_string(commit->buffer, output_encoding, encoding);
+       if (!strcmp(encoding, output_encoding))
+               out = strdup(commit->buffer);
+       else
+               out = reencode_string(commit->buffer,
+                                     output_encoding, encoding);
+       if (out)
+               out = replace_encoding_header(out, output_encoding);
+
        free(encoding);
        if (!out)
                return NULL;
index fcccf7e2a4f3b7487af10d4f7b505c7ef492b9e8..458ae512f3b644979ddc1f6bb581fee2907dbc2f 100644 (file)
--- a/config.c
+++ b/config.c
@@ -238,6 +238,12 @@ int git_config_int(const char *name, const char *value)
                int val = strtol(value, &end, 0);
                if (!*end)
                        return val;
+               if (!strcasecmp(end, "k"))
+                       return val * 1024;
+               if (!strcasecmp(end, "m"))
+                       return val * 1024 * 1024;
+               if (!strcasecmp(end, "g"))
+                       return val * 1024 * 1024 * 1024;
        }
        die("bad config value for '%s' in %s", name, config_file_name);
 }
diff --git a/dir.c b/dir.c
index dd188a8c56c02e1bbe2c8fc0cfb9ce67cdeb948d..0338d6c4e0ab4409d6023db96f5298d292692099 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -260,13 +260,12 @@ int excluded(struct dir_struct *dir, const char *pathname)
        return 0;
 }
 
-static void add_name(struct dir_struct *dir, const char *pathname, int len,
-                    int ignored_entry)
+struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)
 {
        struct dir_entry *ent;
 
        if (cache_name_pos(pathname, len) >= 0)
-               return;
+               return NULL;
 
        if (dir->nr == dir->alloc) {
                int alloc = alloc_nr(dir->alloc);
@@ -274,11 +273,12 @@ static void add_name(struct dir_struct *dir, const char *pathname, int len,
                dir->entries = xrealloc(dir->entries, alloc*sizeof(ent));
        }
        ent = xmalloc(sizeof(*ent) + len + 1);
-       ent->ignored_entry = ignored_entry;
+       ent->ignored = ent->ignored_dir = 0;
        ent->len = len;
        memcpy(ent->name, pathname, len);
        ent->name[len] = 0;
        dir->entries[dir->nr++] = ent;
+       return ent;
 }
 
 static int dir_exists(const char *dirname, int len)
@@ -316,7 +316,6 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
 
                while ((de = readdir(fdir)) != NULL) {
                        int len;
-                       int ignored_entry;
 
                        if ((de->d_name[0] == '.') &&
                            (de->d_name[1] == 0 ||
@@ -325,12 +324,11 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
                                continue;
                        len = strlen(de->d_name);
                        memcpy(fullname + baselen, de->d_name, len+1);
-                       ignored_entry = excluded(dir, fullname);
-
-                       if (!dir->show_both &&
-                           (ignored_entry != dir->show_ignored) &&
-                           (!dir->show_ignored || DTYPE(de) != DT_DIR))
-                               continue;
+                       if (excluded(dir, fullname) != dir->show_ignored) {
+                               if (!dir->show_ignored || DTYPE(de) != DT_DIR) {
+                                       continue;
+                               }
+                       }
 
                        switch (DTYPE(de)) {
                        struct stat st;
@@ -368,8 +366,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
                        if (check_only)
                                goto exit_early;
                        else
-                               add_name(dir, fullname, baselen + len,
-                                        ignored_entry);
+                               dir_add_name(dir, fullname, baselen + len);
                }
 exit_early:
                closedir(fdir);
diff --git a/dir.h b/dir.h
index 08c634547229fc1353fd092fb226293ed07368c3..7233d65bbd393f1d34d75538dd0e39e4a86383f2 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -13,8 +13,9 @@
 
 
 struct dir_entry {
-       unsigned ignored_entry : 1;
-       unsigned int len : 15;
+       unsigned int ignored : 1;
+       unsigned int ignored_dir : 1;
+       unsigned int len : 30;
        char name[FLEX_ARRAY]; /* more */
 };
 
@@ -30,8 +31,7 @@ struct exclude_list {
 
 struct dir_struct {
        int nr, alloc;
-       unsigned int show_both: 1,
-                    show_ignored:1,
+       unsigned int show_ignored:1,
                     show_other_directories:1,
                     hide_empty_directories:1;
        struct dir_entry **entries;
@@ -57,5 +57,6 @@ extern void add_excludes_from_file(struct dir_struct *, const char *fname);
 extern void add_exclude(const char *string, const char *base,
                        int baselen, struct exclude_list *which);
 extern int file_exists(const char *);
+extern struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len);
 
 #endif
index 8bd11f8b60c0ffec8a67f59bc7e12e1f63adfc91..466fe59e35e03a6f9955f78e4238d9e0a60b8dc0 100755 (executable)
@@ -382,13 +382,22 @@ fetch_main () {
       ;; # we are already done.
   *)
     ( : subshell because we muck with IFS
-      pack_lockfile=
       IFS="    $LF"
       (
-         git-fetch-pack --thin $exec $keep $shallow_depth "$remote" $rref || echo failed "$remote"
+         git-fetch-pack --thin $exec $keep $shallow_depth "$remote" $rref ||
+         echo failed "$remote"
       ) |
-      while read sha1 remote_name
-      do
+      (
+       trap '
+               if test -n "$keepfile" && test -f "$keepfile"
+               then
+                       rm -f "$keepfile"
+               fi
+       ' 0
+
+        keepfile=
+       while read sha1 remote_name
+       do
          case "$sha1" in
          failed)
                  echo >&2 "Fetch failure: $remote"
@@ -397,7 +406,7 @@ fetch_main () {
          pack)
                  continue ;;
          keep)
-                 pack_lockfile="$GIT_OBJECT_DIRECTORY/pack/pack-$remote_name.keep"
+                 keepfile="$GIT_OBJECT_DIRECTORY/pack/pack-$remote_name.keep"
                  continue ;;
          esac
          found=
@@ -429,8 +438,8 @@ fetch_main () {
          append_fetch_head "$sha1" "$remote" \
                  "$remote_name" "$remote_nick" "$local_name" \
                  "$not_for_merge" || exit
-      done &&
-      if [ "$pack_lockfile" ]; then rm -f "$pack_lockfile"; fi
+        done
+      )
     ) || exit ;;
   esac
 
index ba42260426296b63070a1fbdc22a9b77ea5ac412..477002910ede7f6bc6bcb9a79f6ddebd248f6bd2 100755 (executable)
@@ -8,6 +8,9 @@ USAGE='[-n] [--no-commit] [--squash] [-s <strategy>] [-m=<merge-message>] <commi
 . git-sh-setup
 set_reflog_action "merge $*"
 
+test -z "$(git ls-files -u)" ||
+       die "You are in a middle of conflicted merge."
+
 LF='
 '
 
index 144f1701553a1e2f4204a2df15e66437e0670123..d2e4c2b9aede8310879cea9c47bd3cee323f11af 100755 (executable)
@@ -76,16 +76,32 @@ get_remote_default_refs_for_push () {
 # from get_remote_refs_for_fetch when it deals with refspecs
 # supplied on the command line.  $ls_remote_result has the list
 # of refs available at remote.
+#
+# The first token returned is either "explicit" or "glob"; this
+# is to help prevent randomly "globbed" ref from being chosen as
+# a merge candidate
 expand_refs_wildcard () {
+       first_one=yes
        for ref
        do
                lref=${ref#'+'}
                # a non glob pattern is given back as-is.
                expr "z$lref" : 'zrefs/.*/\*:refs/.*/\*$' >/dev/null || {
+                       if test -n "$first_one"
+                       then
+                               echo "explicit"
+                               first_one=
+                       fi
                        echo "$ref"
                        continue
                }
 
+               # glob
+               if test -n "$first_one"
+               then
+                       echo "glob"
+                       first_one=
+               fi
                from=`expr "z$lref" : 'z\(refs/.*/\)\*:refs/.*/\*$'`
                to=`expr "z$lref" : 'zrefs/.*/\*:\(refs/.*/\)\*$'`
                local_force=
@@ -116,7 +132,8 @@ canon_refs_list_for_fetch () {
        if test "$1" = "-d"
        then
                shift ; remote="$1" ; shift
-               set x $(expand_refs_wildcard "$@")
+               set $(expand_refs_wildcard "$@")
+               is_explicit="$1"
                shift
                if test "$remote" = "$(get_default_remote)"
                then
@@ -125,6 +142,10 @@ canon_refs_list_for_fetch () {
                        merge_branches=$(git-repo-config \
                            --get-all "branch.${curr_branch}.merge")
                fi
+               if test -z "$merge_branches" && test $is_explicit != explicit
+               then
+                       merge_branches=..this.will.never.match.any.ref..
+               fi
        fi
        for ref
        do
index 28d08195f0c84b7f3a89a5c5cff9945bb64ddfb3..c184fb81a4dab622d79120bcc986c3bf2b07df7f 100755 (executable)
@@ -9,6 +9,9 @@ LONG_USAGE='Fetch one or more remote refs and merge it/them into the current HEA
 . git-sh-setup
 set_reflog_action "pull $*"
 
+test -z "$(git ls-files -u)" ||
+       die "You are in a middle of conflicted merge."
+
 strategy_args= no_summary= no_commit= squash=
 while case "$#,$1" in 0) break ;; *,-*) ;; *) break ;; esac
 do
diff --git a/git.c b/git.c
index 50ebd869ad47cb2803a5a1e581442d7e72842034..c82ca458e47186cd926dc83030cb7a6c8a697e8d 100644 (file)
--- a/git.c
+++ b/git.c
@@ -63,14 +63,14 @@ static int handle_options(const char*** argv, int* argc)
                                fprintf(stderr, "No directory given for --git-dir.\n" );
                                usage(git_usage_string);
                        }
-                       setenv("GIT_DIR", (*argv)[1], 1);
+                       setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1);
                        (*argv)++;
                        (*argc)--;
                } else if (!strncmp(cmd, "--git-dir=", 10)) {
-                       setenv("GIT_DIR", cmd + 10, 1);
+                       setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
                } else if (!strcmp(cmd, "--bare")) {
-                       static char git_dir[1024];
-                       setenv("GIT_DIR", getcwd(git_dir, 1024), 1);
+                       static char git_dir[PATH_MAX+1];
+                       setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 1);
                } else {
                        fprintf(stderr, "Unknown option: %s\n", cmd);
                        usage(git_usage_string);
diff --git a/http.h b/http.h
index 6e12e416889503553ae502be31b2e9ed9e7dc4dd..324fcf4f5482dc67c3f68df0be30fb0aa210401e 100644 (file)
--- a/http.h
+++ b/http.h
@@ -18,7 +18,7 @@
 #define curl_global_init(a) do { /* nothing */ } while(0)
 #endif
 
-#if LIBCURL_VERSION_NUM < 0x070c04
+#if (LIBCURL_VERSION_NUM < 0x070c04) || (LIBCURL_VERSION_NUM == 0x071000)
 #define NO_CURL_EASY_DUPHANDLE
 #endif
 
index 59b682c03af53fbfe600d063fa832f874440493c..c176d8fd008ad858a1e60e19e7bf3ea14d735eb5 100644 (file)
@@ -73,7 +73,9 @@ static int run_update_hook(const char *refname,
 
        if (access(update_hook, X_OK) < 0)
                return 0;
-       code = run_command(update_hook, refname, old_hex, new_hex, NULL);
+       code = run_command_opt(RUN_COMMAND_NO_STDIN
+               | RUN_COMMAND_STDOUT_TO_STDERR,
+               update_hook, refname, old_hex, new_hex, NULL);
        switch (code) {
        case 0:
                return 0;
@@ -187,7 +189,8 @@ static void run_update_post_hook(struct command *cmd)
                argc++;
        }
        argv[argc] = NULL;
-       run_command_v_opt(argc, argv, RUN_COMMAND_NO_STDIO);
+       run_command_v_opt(argv, RUN_COMMAND_NO_STDIN
+               | RUN_COMMAND_STDOUT_TO_STDERR);
 }
 
 /*
@@ -283,7 +286,7 @@ static const char *unpack(void)
                unpacker[0] = "unpack-objects";
                unpacker[1] = hdr_arg;
                unpacker[2] = NULL;
-               code = run_command_v_opt(1, unpacker, RUN_GIT_CMD);
+               code = run_command_v_opt(unpacker, RUN_GIT_CMD);
                switch (code) {
                case 0:
                        return NULL;
index af9f87418c6ed342e0a3d751b8f8e59fe5e8aeed..6e4ec463024a3e6cc4199ea1937f3b11e0a0dace 100644 (file)
@@ -1039,6 +1039,14 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
                                all_match = 1;
                                continue;
                        }
+                       if (!strncmp(arg, "--encoding=", 11)) {
+                               arg += 11;
+                               if (strcmp(arg, "none"))
+                                       git_log_output_encoding = strdup(arg);
+                               else
+                                       git_log_output_encoding = "";
+                               continue;
+                       }
 
                        opts = diff_opt_parse(&revs->diffopt, argv+i, argc-i);
                        if (opts > 0) {
index 492ad3e64ce5d2435c029ab032f1221347f37c19..cfbad74d145145944352c568064cc2f8c0d4c5cb 100644 (file)
@@ -2,19 +2,20 @@
 #include "run-command.h"
 #include "exec_cmd.h"
 
-int run_command_v_opt(int argc, const char **argv, int flags)
+int run_command_v_opt(const char **argv, int flags)
 {
        pid_t pid = fork();
 
        if (pid < 0)
                return -ERR_RUN_COMMAND_FORK;
        if (!pid) {
-               if (flags & RUN_COMMAND_NO_STDIO) {
+               if (flags & RUN_COMMAND_NO_STDIN) {
                        int fd = open("/dev/null", O_RDWR);
                        dup2(fd, 0);
-                       dup2(fd, 1);
                        close(fd);
                }
+               if (flags & RUN_COMMAND_STDOUT_TO_STDERR)
+                       dup2(2, 1);
                if (flags & RUN_GIT_CMD) {
                        execv_git_cmd(argv);
                } else {
@@ -46,19 +47,17 @@ int run_command_v_opt(int argc, const char **argv, int flags)
        }
 }
 
-int run_command_v(int argc, const char **argv)
+int run_command_v(const char **argv)
 {
-       return run_command_v_opt(argc, argv, 0);
+       return run_command_v_opt(argv, 0);
 }
 
-int run_command(const char *cmd, ...)
+static int run_command_va_opt(int opt, const char *cmd, va_list param)
 {
        int argc;
        const char *argv[MAX_RUN_COMMAND_ARGS];
        const char *arg;
-       va_list param;
 
-       va_start(param, cmd);
        argv[0] = (char*) cmd;
        argc = 1;
        while (argc < MAX_RUN_COMMAND_ARGS) {
@@ -66,8 +65,29 @@ int run_command(const char *cmd, ...)
                if (!arg)
                        break;
        }
-       va_end(param);
        if (MAX_RUN_COMMAND_ARGS <= argc)
                return error("too many args to run %s", cmd);
-       return run_command_v_opt(argc, argv, 0);
+       return run_command_v_opt(argv, opt);
+}
+
+int run_command_opt(int opt, const char *cmd, ...)
+{
+       va_list params;
+       int r;
+
+       va_start(params, cmd);
+       r = run_command_va_opt(opt, cmd, params);
+       va_end(params);
+       return r;
+}
+
+int run_command(const char *cmd, ...)
+{
+       va_list params;
+       int r;
+
+       va_start(params, cmd);
+       r = run_command_va_opt(0, cmd, params);
+       va_end(params);
+       return r;
 }
index 70b477a7483ce3a4997b20ee02223eeb483bde6c..59c4476ced789441eea3f68bfc7377e7e15e9b14 100644 (file)
@@ -11,10 +11,12 @@ enum {
        ERR_RUN_COMMAND_WAITPID_NOEXIT,
 };
 
-#define RUN_COMMAND_NO_STDIO 1
+#define RUN_COMMAND_NO_STDIN 1
 #define RUN_GIT_CMD         2  /*If this is to be git sub-command */
-int run_command_v_opt(int argc, const char **argv, int opt);
-int run_command_v(int argc, const char **argv);
+#define RUN_COMMAND_STDOUT_TO_STDERR 4
+int run_command_v_opt(const char **argv, int opt);
+int run_command_v(const char **argv);
+int run_command_opt(int opt, const char *cmd, ...);
 int run_command(const char *cmd, ...);
 
 #endif
index cc884f3b2debbaadfc3c42cda20074257fa48a65..eaa6efbc0c844de78510d3c65a3bd6a83d9cdcef 100644 (file)
@@ -14,114 +14,49 @@ static int send_all;
 static int force_update;
 static int use_thin_pack;
 
-static int is_zero_sha1(const unsigned char *sha1)
-{
-       int i;
-
-       for (i = 0; i < 20; i++) {
-               if (*sha1++)
-                       return 0;
-       }
-       return 1;
-}
-
-static void exec_pack_objects(void)
-{
-       static const char *args[] = {
-               "pack-objects",
-               "--all-progress",
-               "--stdout",
-               NULL
-       };
-       execv_git_cmd(args);
-       die("git-pack-objects exec failed (%s)", strerror(errno));
-}
-
-static void exec_rev_list(struct ref *refs)
-{
-       static const char *args[4];
-       int i = 0;
-
-       args[i++] = "rev-list"; /* 0 */
-       if (use_thin_pack)      /* 1 */
-               args[i++] = "--objects-edge";
-       else
-               args[i++] = "--objects";
-
-       args[i++] = "--stdin";
-
-       args[i] = NULL;
-       execv_git_cmd(args);
-       die("git-rev-list exec failed (%s)", strerror(errno));
-}
-
-/*
- * Run "rev-list --stdin | pack-objects" pipe.
- */
-static void rev_list(int fd, struct ref *refs)
-{
-       int pipe_fd[2];
-       pid_t pack_objects_pid;
-
-       if (pipe(pipe_fd) < 0)
-               die("rev-list setup: pipe failed");
-       pack_objects_pid = fork();
-       if (!pack_objects_pid) {
-               /* The child becomes pack-objects; reads from pipe
-                * and writes to the original fd
-                */
-               dup2(pipe_fd[0], 0);
-               dup2(fd, 1);
-               close(pipe_fd[0]);
-               close(pipe_fd[1]);
-               close(fd);
-               exec_pack_objects();
-               die("pack-objects setup failed");
-       }
-       if (pack_objects_pid < 0)
-               die("pack-objects fork failed");
-
-       /* We become rev-list --stdin; output goes to pipe. */
-       dup2(pipe_fd[1], 1);
-       close(pipe_fd[0]);
-       close(pipe_fd[1]);
-       close(fd);
-       exec_rev_list(refs);
-}
-
 /*
- * Create "rev-list --stdin | pack-objects" pipe and feed
- * the refs into the pipeline.
+ * Make a pack stream and spit it out into file descriptor fd
  */
-static void rev_list_generate(int fd, struct ref *refs)
+static int pack_objects(int fd, struct ref *refs)
 {
        int pipe_fd[2];
-       pid_t rev_list_generate_pid;
+       pid_t pid;
 
        if (pipe(pipe_fd) < 0)
-               die("rev-list-generate setup: pipe failed");
-       rev_list_generate_pid = fork();
-       if (!rev_list_generate_pid) {
-               /* The child becomes the "rev-list | pack-objects"
-                * pipeline.  It takes input from us, and its output
-                * goes to fd.
+               return error("send-pack: pipe failed");
+       pid = fork();
+       if (!pid) {
+               /*
+                * The child becomes pack-objects --revs; we feed
+                * the revision parameters to it via its stdin and
+                * let its stdout go back to the other end.
                 */
+               static const char *args[] = {
+                       "pack-objects",
+                       "--all-progress",
+                       "--revs",
+                       "--stdout",
+                       NULL,
+                       NULL,
+               };
+               if (use_thin_pack)
+                       args[4] = "--thin";
                dup2(pipe_fd[0], 0);
                dup2(fd, 1);
                close(pipe_fd[0]);
                close(pipe_fd[1]);
                close(fd);
-               rev_list(fd, refs);
-               die("rev-list setup failed");
+               execv_git_cmd(args);
+               die("git-pack-objects exec failed (%s)", strerror(errno));
        }
-       if (rev_list_generate_pid < 0)
-               die("rev-list-generate fork failed");
 
-       /* We feed the rev parameters to them.  We do not write into
-        * fd nor read from the pipe.
+       /*
+        * We feed the pack-objects we just spawned with revision
+        * parameters by writing to the pipe.
         */
        close(pipe_fd[0]);
        close(fd);
+
        while (refs) {
                char buf[42];
 
@@ -140,28 +75,24 @@ static void rev_list_generate(int fd, struct ref *refs)
                refs = refs->next;
        }
        close(pipe_fd[1]);
-       // waitpid(rev_list_generate_pid);
-       exit(0);
-}
 
-/*
- * Make a pack stream and spit it out into file descriptor fd
- */
-static void pack_objects(int fd, struct ref *refs)
-{
-       pid_t rev_list_pid;
+       for (;;) {
+               int status, code;
+               pid_t waiting = waitpid(pid, &status, 0);
 
-       rev_list_pid = fork();
-       if (!rev_list_pid) {
-               rev_list_generate(fd, refs);
-               die("rev-list setup failed");
+               if (waiting < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       return error("waitpid failed (%s)", strerror(errno));
+               }
+               if ((waiting != pid) || WIFSIGNALED(status) ||
+                   !WIFEXITED(status))
+                       return error("pack-objects died with strange error");
+               code = WEXITSTATUS(status);
+               if (code)
+                       return -code;
+               return 0;
        }
-       if (rev_list_pid < 0)
-               die("rev-list fork failed");
-       /*
-        * We don't wait for the rev-list pipeline in the parent:
-        * we end up waiting for the other end instead
-        */
 }
 
 static void unmark_and_free(struct commit_list *list, unsigned int mark)
@@ -341,7 +272,7 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec)
 
                if (!force_update &&
                    !delete_ref &&
-                   !is_zero_sha1(ref->old_sha1) &&
+                   !is_null_sha1(ref->old_sha1) &&
                    !ref->force) {
                        if (!has_sha1_file(ref->old_sha1) ||
                            !ref_newer(ref->peer_ref->new_sha1,
@@ -393,7 +324,7 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec)
 
        packet_flush(out);
        if (new_refs)
-               pack_objects(out, remote_refs);
+               ret = pack_objects(out, remote_refs);
        close(out);
 
        if (expect_status_report) {
diff --git a/setup.c b/setup.c
index 2afdba414a073705440f887593a1b5daa1023758..2ae57f7c94e304ef3468a27cd245c314a08046ed 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -131,28 +131,46 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
 }
 
 /*
- * Test if it looks like we're at the top level git directory.
+ * Test if it looks like we're at a git directory.
  * We want to see:
  *
- *  - either a .git/objects/ directory _or_ the proper
+ *  - either a objects/ directory _or_ the proper
  *    GIT_OBJECT_DIRECTORY environment variable
- *  - a refs/ directory under ".git"
+ *  - a refs/ directory
  *  - either a HEAD symlink or a HEAD file that is formatted as
  *    a proper "ref:".
  */
-static int is_toplevel_directory(void)
+static int is_git_directory(const char *suspect)
 {
-       if (access(".git/refs/", X_OK) ||
-           access(getenv(DB_ENVIRONMENT) ?
-                  getenv(DB_ENVIRONMENT) : ".git/objects/", X_OK) ||
-           validate_symref(".git/HEAD"))
+       char path[PATH_MAX];
+       size_t len = strlen(suspect);
+
+       strcpy(path, suspect);
+       if (getenv(DB_ENVIRONMENT)) {
+               if (access(getenv(DB_ENVIRONMENT), X_OK))
+                       return 0;
+       }
+       else {
+               strcpy(path + len, "/objects");
+               if (access(path, X_OK))
+                       return 0;
+       }
+
+       strcpy(path + len, "/refs");
+       if (access(path, X_OK))
                return 0;
+
+       strcpy(path + len, "/HEAD");
+       if (validate_symref(path))
+               return 0;
+
        return 1;
 }
 
 const char *setup_git_directory_gently(int *nongit_ok)
 {
        static char cwd[PATH_MAX+1];
+       const char *gitdirenv;
        int len, offset;
 
        /*
@@ -160,36 +178,17 @@ const char *setup_git_directory_gently(int *nongit_ok)
         * to do any discovery, but we still do repository
         * validation.
         */
-       if (getenv(GIT_DIR_ENVIRONMENT)) {
-               char path[PATH_MAX];
-               int len = strlen(getenv(GIT_DIR_ENVIRONMENT));
-               if (sizeof(path) - 40 < len)
+       gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
+       if (gitdirenv) {
+               if (PATH_MAX - 40 < strlen(gitdirenv))
                        die("'$%s' too big", GIT_DIR_ENVIRONMENT);
-               memcpy(path, getenv(GIT_DIR_ENVIRONMENT), len);
-               
-               strcpy(path + len, "/refs");
-               if (access(path, X_OK))
-                       goto bad_dir_environ;
-               strcpy(path + len, "/HEAD");
-               if (validate_symref(path))
-                       goto bad_dir_environ;
-               if (getenv(DB_ENVIRONMENT)) {
-                       if (access(getenv(DB_ENVIRONMENT), X_OK))
-                               goto bad_dir_environ;
-               }
-               else {
-                       strcpy(path + len, "/objects");
-                       if (access(path, X_OK))
-                               goto bad_dir_environ;
-               }
-               return NULL;
-       bad_dir_environ:
+               if (is_git_directory(gitdirenv))
+                       return NULL;
                if (nongit_ok) {
                        *nongit_ok = 1;
                        return NULL;
                }
-               path[len] = 0;
-               die("Not a git repository: '%s'", path);
+               die("Not a git repository: '%s'", gitdirenv);
        }
 
        if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')
@@ -197,11 +196,17 @@ const char *setup_git_directory_gently(int *nongit_ok)
 
        offset = len = strlen(cwd);
        for (;;) {
-               if (is_toplevel_directory())
+               if (is_git_directory(".git"))
                        break;
                chdir("..");
                do {
                        if (!offset) {
+                               if (is_git_directory(cwd)) {
+                                       if (chdir(cwd))
+                                               die("Cannot come back to cwd");
+                                       setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
+                                       return NULL;
+                               }
                                if (nongit_ok) {
                                        if (chdir(cwd))
                                                die("Cannot come back to cwd");
index c5db5804df767bb55d5c9972b18faf4dc35e899c..7abab1dafe83527a5ff84808824057f549a08080 100644 (file)
--- a/t/README
+++ b/t/README
@@ -74,6 +74,8 @@ First digit tells the family:
        5 - the pull and exporting commands
        6 - the revision tree commands (even e.g. merge-base)
        7 - the porcelainish commands concerning the working tree
+       8 - the porcelainish commands concerning forensics
+       9 - the git tools
 
 Second digit tells the particular command we are testing.
 
index 99ada71349c7eaa0536bba1d622f7f7ffa56110e..af42ccc8d157e54b97de435194d22e5ed895ab4b 100644 (file)
@@ -7,26 +7,10 @@ then
        exit
 fi
 
-perl -e 'use SVN::Core; $SVN::Core::VERSION gt "1.1.0" or die' >/dev/null 2>&1
-if test $? -ne 0
-then
-       test_expect_success 'Perl SVN libraries not found, skipping test' :
-       test_done
-       exit
-fi
-
 GIT_DIR=$PWD/.git
 GIT_SVN_DIR=$GIT_DIR/svn/git-svn
 SVN_TREE=$GIT_SVN_DIR/svn-tree
 
-svnadmin >/dev/null 2>&1
-if test $? -ne 1
-then
-    test_expect_success 'skipping git-svn tests, svnadmin not found' :
-    test_done
-    exit
-fi
-
 svn >/dev/null 2>&1
 if test $? -ne 1
 then
@@ -37,13 +21,24 @@ fi
 
 svnrepo=$PWD/svnrepo
 
-set -e
-
-if svnadmin create --help | grep fs-type >/dev/null
+perl -w -e "
+use SVN::Core;
+use SVN::Repos;
+\$SVN::Core::VERSION gt '1.1.0' or exit(42);
+SVN::Repos::create('$svnrepo', undef, undef, undef,
+                           { 'fs-config' => 'fsfs'});
+"
+x=$?
+if test $x -ne 0
 then
-       svnadmin create --fs-type fsfs "$svnrepo"
-else
-       svnadmin create "$svnrepo"
+       if test $x -eq 42; then
+               err='Perl SVN libraries must be >= 1.1.0'
+       else
+               err='Perl SVN libraries not found or unusable, skipping test'
+       fi
+       test_expect_success "$err" :
+       test_done
+       exit
 fi
 
 svnrepo="file://$svnrepo"
index e48a4ecdcf7129da1431928bdb942eae8c3e6515..a29caa06dc6545b7fc23b3446a713b75f49cd146 100755 (executable)
@@ -391,5 +391,15 @@ EOF
 
 test_expect_success "rename succeeded" "diff -u expect .git/config"
 
+test_expect_success numbers '
+
+       git-repo-config kilo.gram 1k &&
+       git-repo-config mega.ton 1m &&
+       k=$(git-repo-config --int --get kilo.gram) &&
+       test z1024 = "z$k" &&
+       m=$(git-repo-config --int --get mega.ton) &&
+       test z1048576 = "z$m"
+'
+
 test_done
 
index c09c53f20bbc04f36d26ff37f060f42233a1c0db..e98786de32ca3139b2587fd5fca29a9f400c81d7 100755 (executable)
@@ -51,4 +51,37 @@ test_expect_success \
         *) echo fail; git-ls-files --stage xfoo3; (exit 1);;
         esac'
 
+test_expect_success '.gitignore test setup' '
+       echo "*.ig" >.gitignore &&
+       mkdir c.if d.ig &&
+       >a.ig && >b.if &&
+       >c.if/c.if && >c.if/c.ig &&
+       >d.ig/d.if && >d.ig/d.ig
+'
+
+test_expect_success '.gitignore is honored' '
+       git-add . &&
+       ! git-ls-files | grep "\\.ig"
+'
+
+test_expect_success 'error out when attempting to add ignored ones without -f' '
+       ! git-add a.?? &&
+       ! git-ls-files | grep "\\.ig"
+'
+
+test_expect_success 'error out when attempting to add ignored ones without -f' '
+       ! git-add d.?? &&
+       ! git-ls-files | grep "\\.ig"
+'
+
+test_expect_success 'add ignored ones with -f' '
+       git-add -f a.?? &&
+       git-ls-files --error-unmatch a.ig
+'
+
+test_expect_success 'add ignored ones with -f' '
+       git-add -f d.??/* &&
+       git-ls-files --error-unmatch d.ig/d.if d.ig/d.ig
+'
+
 test_done
index 46fd47cb0fedea8831d155d04651deb2b21d2e7c..6714b0dd6e6164eb17174465be536ee3a07d88e1 100755 (executable)
@@ -8,7 +8,7 @@ test_description='commit and log output encodings'
 . ./test-lib.sh
 
 compare_with () {
-       git-show -s "$1" | sed -e '1,/^$/d' -e 's/^    //' -e '$d' >current &&
+       git-show -s $1 | sed -e '1,/^$/d' -e 's/^    //' -e '$d' >current &&
        diff -u current "$2"
 }
 
@@ -112,4 +112,11 @@ do
        done
 done
 
+for H in ISO-8859-1 EUCJP ISO-2022-JP
+do
+       test_expect_success "No conversion with $H" '
+               compare_with "--encoding=none '$H'" ../t3900/'$H'.txt
+       '
+done
+
 test_done
index 28744b35e10602cf5076fbf5c62b3e767a847c0c..2c151912a3bcf2c91cfafcbc22f11bc71fedd34d 100755 (executable)
@@ -8,38 +8,63 @@ test_description='See why rewinding head breaks send-pack
 '
 . ./test-lib.sh
 
-touch cpio-test
-test_expect_success 'working cpio' 'echo cpio-test | cpio -o > /dev/null'
-
-cnt='1'
+cnt=64
 test_expect_success setup '
+       test_tick &&
+       mkdir mozart mozart/is &&
+       echo "Commit #0" >mozart/is/pink &&
+       git-update-index --add mozart/is/pink &&
        tree=$(git-write-tree) &&
        commit=$(echo "Commit #0" | git-commit-tree $tree) &&
        zero=$commit &&
        parent=$zero &&
-       for i in $cnt
+       i=0 &&
+       while test $i -le $cnt
        do
-           sleep 1 &&
+           i=$(($i+1)) &&
+           test_tick &&
+           echo "Commit #$i" >mozart/is/pink &&
+           git-update-index --add mozart/is/pink &&
+           tree=$(git-write-tree) &&
            commit=$(echo "Commit #$i" | git-commit-tree $tree -p $parent) &&
+           git-update-ref refs/tags/commit$i $commit &&
            parent=$commit || return 1
        done &&
        git-update-ref HEAD "$commit" &&
-       git-clone -l ./. victim &&
+       git-clone ./. victim &&
        cd victim &&
        git-log &&
        cd .. &&
        git-update-ref HEAD "$zero" &&
        parent=$zero &&
-       for i in $cnt
+       i=0 &&
+       while test $i -le $cnt
        do
-           sleep 1 &&
+           i=$(($i+1)) &&
+           test_tick &&
+           echo "Rebase #$i" >mozart/is/pink &&
+           git-update-index --add mozart/is/pink &&
+           tree=$(git-write-tree) &&
            commit=$(echo "Rebase #$i" | git-commit-tree $tree -p $parent) &&
+           git-update-ref refs/tags/rebase$i $commit &&
            parent=$commit || return 1
        done &&
        git-update-ref HEAD "$commit" &&
        echo Rebase &&
        git-log'
 
+test_expect_success 'pack the source repository' '
+       git repack -a -d &&
+       git prune
+'
+
+test_expect_success 'pack the destination repository' '
+       cd victim &&
+       git repack -a -d &&
+       git prune &&
+       cd ..
+'
+
 test_expect_success \
         'pushing rewound head should not barf but require --force' ' 
        # should not fail but refuse to update.
diff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh
new file mode 100755 (executable)
index 0000000..cd8cee6
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Shawn O. Pearce
+#
+
+test_description='Test the update hook infrastructure.'
+. ./test-lib.sh
+
+test_expect_success setup '
+       echo This is a test. >a &&
+       git-update-index --add a &&
+       tree0=$(git-write-tree) &&
+       commit0=$(echo setup | git-commit-tree $tree0) &&
+       git-update-ref HEAD $commit0 &&
+       git-clone ./. victim &&
+       echo We hope it works. >a &&
+       git-update-index a &&
+       tree1=$(git-write-tree) &&
+       commit1=$(echo modify | git-commit-tree $tree1 -p $commit0) &&
+       git-update-ref HEAD $commit1
+'
+
+cat >victim/.git/hooks/update <<'EOF'
+#!/bin/sh
+echo "$@" >$GIT_DIR/update.args
+read x; echo -n "$x" >$GIT_DIR/update.stdin
+echo STDOUT update
+echo STDERR update >&2
+EOF
+chmod u+x victim/.git/hooks/update
+
+cat >victim/.git/hooks/post-update <<'EOF'
+#!/bin/sh
+echo "$@" >$GIT_DIR/post-update.args
+read x; echo -n "$x" >$GIT_DIR/post-update.stdin
+echo STDOUT post-update
+echo STDERR post-update >&2
+EOF
+chmod u+x victim/.git/hooks/post-update
+
+test_expect_success push '
+       git-send-pack ./victim/.git/ master >send.out 2>send.err
+'
+
+test_expect_success 'hooks ran' '
+       test -f victim/.git/update.args &&
+       test -f victim/.git/update.stdin &&
+       test -f victim/.git/post-update.args &&
+       test -f victim/.git/post-update.stdin
+'
+
+test_expect_success 'update hook arguments' '
+       echo refs/heads/master $commit0 $commit1 |
+       diff -u - victim/.git/update.args
+'
+
+test_expect_success 'post-update hook arguments' '
+       echo refs/heads/master |
+       diff -u - victim/.git/post-update.args
+'
+
+test_expect_failure 'update hook stdin is /dev/null' '
+       test -s victim/.git/update.stdin
+'
+
+test_expect_failure 'post-update hook stdin is /dev/null' '
+       test -s victim/.git/post-update.stdin
+'
+
+test_expect_failure 'send-pack produced no output' '
+       test -s send.out
+'
+
+test_expect_success 'send-pack stderr contains hook messages' '
+       grep "STDOUT update" send.err &&
+       grep "STDERR update" send.err &&
+       grep "STDOUT post-update" send.err &&
+       grep "STDERR post-update" send.err
+'
+
+test_done
index c22fe47213a8fccbb954aef4b175d2ea1a920e16..040da92756787371d584f33b53b54a3fc84f55b1 100755 (executable)
@@ -24,10 +24,7 @@ test_expect_success \
        mkdir import &&
        cd import &&
        echo foo > foo &&
-       if test -z '$NO_SYMLINK'
-       then
-               ln -s foo foo.link
-       fi
+       ln -s foo foo.link
        mkdir -p dir/a/b/c/d/e &&
        echo 'deep dir' > dir/a/b/c/d/e/file &&
        mkdir bar &&
@@ -136,48 +133,43 @@ test_expect_success "$name" "
        test -x '$SVN_TREE'/exec.sh"
 
 
-if test -z "$NO_SYMLINK"
-then
-       name='executable file becomes a symlink to bar/zzz (file)'
-
-       test_expect_success "$name" "
-               rm exec.sh &&
-               ln -s bar/zzz exec.sh &&
-               git update-index exec.sh &&
-               git commit -m '$name' &&
-               git-svn set-tree --find-copies-harder --rmdir \
-                       remotes/git-svn..mybranch5 &&
-               svn up '$SVN_TREE' &&
-               test -L '$SVN_TREE'/exec.sh"
+name='executable file becomes a symlink to bar/zzz (file)'
+test_expect_success "$name" "
+       rm exec.sh &&
+       ln -s bar/zzz exec.sh &&
+       git update-index exec.sh &&
+       git commit -m '$name' &&
+       git-svn set-tree --find-copies-harder --rmdir \
+               remotes/git-svn..mybranch5 &&
+       svn up '$SVN_TREE' &&
+       test -L '$SVN_TREE'/exec.sh"
 
-       name='new symlink is added to a file that was also just made executable'
+name='new symlink is added to a file that was also just made executable'
 
-       test_expect_success "$name" "
-               chmod +x bar/zzz &&
-               ln -s bar/zzz exec-2.sh &&
-               git update-index --add bar/zzz exec-2.sh &&
-               git commit -m '$name' &&
-               git-svn set-tree --find-copies-harder --rmdir \
-                       remotes/git-svn..mybranch5 &&
-               svn up '$SVN_TREE' &&
-               test -x '$SVN_TREE'/bar/zzz &&
-               test -L '$SVN_TREE'/exec-2.sh"
-
-       name='modify a symlink to become a file'
-       test_expect_success "$name" "
-               echo git help > help || true &&
-               rm exec-2.sh &&
-               cp help exec-2.sh &&
-               git update-index exec-2.sh &&
-               git commit -m '$name' &&
-               git-svn set-tree --find-copies-harder --rmdir \
-                       remotes/git-svn..mybranch5 &&
-               svn up '$SVN_TREE' &&
-               test -f '$SVN_TREE'/exec-2.sh &&
-               test ! -L '$SVN_TREE'/exec-2.sh &&
-               diff -u help $SVN_TREE/exec-2.sh"
-fi
+test_expect_success "$name" "
+       chmod +x bar/zzz &&
+       ln -s bar/zzz exec-2.sh &&
+       git update-index --add bar/zzz exec-2.sh &&
+       git commit -m '$name' &&
+       git-svn set-tree --find-copies-harder --rmdir \
+               remotes/git-svn..mybranch5 &&
+       svn up '$SVN_TREE' &&
+       test -x '$SVN_TREE'/bar/zzz &&
+       test -L '$SVN_TREE'/exec-2.sh"
 
+name='modify a symlink to become a file'
+test_expect_success "$name" "
+       echo git help > help || true &&
+       rm exec-2.sh &&
+       cp help exec-2.sh &&
+       git update-index exec-2.sh &&
+       git commit -m '$name' &&
+       git-svn set-tree --find-copies-harder --rmdir \
+               remotes/git-svn..mybranch5 &&
+       svn up '$SVN_TREE' &&
+       test -f '$SVN_TREE'/exec-2.sh &&
+       test ! -L '$SVN_TREE'/exec-2.sh &&
+       diff -u help $SVN_TREE/exec-2.sh"
 
 if test "$have_utf8" = t
 then
@@ -203,12 +195,6 @@ test_expect_success "$name" \
      git-rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b &&
      diff -u a b"
 
-if test -n "$NO_SYMLINK"
-then
-       test_done
-       exit 0
-fi
-
 name='check imported tree checksums expected tree checksums'
 rm -f expected
 if test "$have_utf8" = t
index 5543b07f16d54bb5aa6fab6ab9cde79837a3e68b..46fcec50a5271d80464d7f37e5d402b1a3c0b6d0 100755 (executable)
@@ -57,13 +57,10 @@ test_expect_success 'setup some commits to svn' \
        'cd test_wc &&
                echo Greetings >> kw.c &&
                svn commit -m "Not yet an Id" &&
-               svn up &&
                echo Hello world >> kw.c &&
                svn commit -m "Modified file, but still not yet an Id" &&
-               svn up &&
                svn propset svn:keywords Id kw.c &&
-               svn commit -m "Propset Id" &&
-               svn up &&
+               svn commit -m "Propset Id"
        cd ..'
 
 test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
@@ -86,8 +83,7 @@ test_expect_success "propset CR on crlf files" \
                svn propset svn:eol-style CR empty &&
                svn propset svn:eol-style CR crlf &&
                svn propset svn:eol-style CR ne_crlf &&
-               svn commit -m "propset CR on crlf files" &&
-               svn up &&
+               svn commit -m "propset CR on crlf files"
         cd ..'
 
 test_expect_success 'fetch and pull latest from svn and checkout a new wc' \
@@ -111,8 +107,7 @@ cd test_wc
         svn propset svn:eol-style CRLF ne_cr &&
         svn propset svn:keywords Id cr &&
         svn propset svn:keywords Id ne_cr &&
-        svn commit -m "propset CRLF on cr files" &&
-        svn up'
+        svn commit -m "propset CRLF on cr files"'
 cd ..
 test_expect_success 'fetch and pull latest from svn' \
        'git-svn fetch && git pull . remotes/git-svn'
index 293b98f92850375aa3223b6af85461a22cd151ea..b5f76770213a99f22a66441aebdc94fcd85070a7 100755 (executable)
@@ -16,25 +16,19 @@ test_expect_success 'initialize repo' "
        cd wc &&
        echo feedme >> branches/a/readme &&
        svn commit -m hungry &&
-       svn up &&
        cd trunk &&
        svn merge -r3:4 $svnrepo/branches/a &&
        svn commit -m 'merge with a' &&
        cd ../.. &&
-       svn log -v $svnrepo &&
-       git-svn init -i trunk $svnrepo/trunk &&
-       git-svn init -i a $svnrepo/branches/a &&
-       git-svn init -i tags/a $svnrepo/tags/a &&
-       git-svn fetch -i tags/a &&
-       git-svn fetch -i a &&
-       git-svn fetch -i trunk
+       git-svn multi-init $svnrepo -T trunk -b branches -t tags &&
+       git-svn multi-fetch
        "
 
 r1=`git-rev-list remotes/trunk | tail -n1`
 r2=`git-rev-list remotes/tags/a | tail -n1`
 r3=`git-rev-list remotes/a | tail -n1`
-r4=`git-rev-list remotes/a | head -n1`
-r5=`git-rev-list remotes/trunk | head -n1`
+r4=`git-rev-parse remotes/a`
+r5=`git-rev-parse remotes/trunk`
 
 test_expect_success 'test graft-branches regexes and copies' "
        test -n "$r1" &&
index 8d2e2fec395a328f4bf6a65af3c7eba5a98cc133..400c21cd49b6307eeef6d4d25cb34e612b1d0a71 100755 (executable)
@@ -17,7 +17,6 @@ test_expect_success 'initialize repo' "
        cd wc &&
        echo world >> trunk/readme &&
        svn commit -m 'another commit' &&
-       svn up &&
        svn mv -m 'rename to thunk' trunk thunk &&
        svn up &&
        echo goodbye >> thunk/readme &&
index 98f69d89f395bfba8c77ab5a09f345f968f0ef4f..bf108d4226fabf847f42420547471dfb3cef8a8e 100755 (executable)
@@ -96,6 +96,17 @@ test_count=0
 
 trap 'echo >&5 "FATAL: Unexpected exit with code $?"; exit 1' exit
 
+test_tick () {
+       if test -z "${test_tick+set}"
+       then
+               test_tick=432630000
+       else
+               test_tick=$(($test_tick + 60))
+       fi
+       GIT_COMMITTER_DATE=$test_tick
+       GIT_AUTHOR_DATE=$test_tick
+       export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
+}
 
 # You are not expected to call test_ok_ and test_failure_ directly, use
 # the text_expect_* functions instead.
diff --git a/utf8.c b/utf8.c
index 1eedd8b61aeed9867366df0b70ac849cdef985b9..7c80eeccb4537ab6d4387941c6262c89cab30d33 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -277,6 +277,15 @@ void print_wrapped_text(const char *text, int indent, int indent2, int width)
        }
 }
 
+int is_encoding_utf8(const char *name)
+{
+       if (!name)
+               return 1;
+       if (!strcasecmp(name, "utf-8") || !strcasecmp(name, "utf8"))
+               return 1;
+       return 0;
+}
+
 /*
  * Given a buffer and its encoding, return it re-encoded
  * with iconv.  If the conversion fails, returns NULL.
diff --git a/utf8.h b/utf8.h
index cae2a8e665c2cbe7bf31a49deed84250eaa37a33..a07c5a88af63d41ae963f230510a33d78b68a525 100644 (file)
--- a/utf8.h
+++ b/utf8.h
@@ -3,6 +3,8 @@
 
 int utf8_width(const char **start);
 int is_utf8(const char *text);
+int is_encoding_utf8(const char *name);
+
 void print_wrapped_text(const char *text, int indent, int indent2, int len);
 
 #ifndef NO_ICONV
index 294450b89916180ab603d566e7d3f281773a3b92..b83b3348cc3aab66b13cb565a0a0fabaef4b689b 100644 (file)
@@ -166,6 +166,8 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
                        size += xdl_recs_copy(xe2, m->i2 - m->i1 + i1,
                                        m->i1 + m->chg2 - i1, 0,
                                        dest ? dest + size : NULL);
+               else
+                       continue;
                i1 = m->i1 + m->chg1;
        }
        size += xdl_recs_copy(xe1, i1, xe1->xdf2.nrec - i1, 0,
@@ -213,9 +215,10 @@ static int xdl_refine_conflicts(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m,
                        return -1;
                }
                if (!xscr) {
-                       /* If this happens, it's a bug. */
+                       /* If this happens, the changes are identical. */
                        xdl_free_env(&xe);
-                       return -2;
+                       m->mode = 4;
+                       continue;
                }
                x = xscr;
                m->i1 = xscr->i1 + i1;