GIT 1.0.0
Signed-off-by: Junio C Hamano <junkio@cox.net>
diff --git a/.gitignore b/.gitignore
index 8a6bd02..6bd508e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -60,7 +60,6 @@
git-mktag
git-name-rev
git-mv
-git-octopus
git-pack-redundant
git-pack-objects
git-parse-remote
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 6b496ed..9e574a0 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -18,6 +18,14 @@
object name of pre- and post-image blob on the "index"
line when generating a patch format output.
+--abbrev[=<n>]::
+ Instead of showing the full 40-byte hexadecimal object
+ name in diff-raw format output and diff-tree header
+ lines, show only handful dhexigits prefix. This is
+ independent of --full-index option above, which controls
+ the diff-patch output format. Non default number of
+ digits can be specified with --abbrev=<n>.
+
-B::
Break complete rewrite changes into pairs of delete and create.
diff --git a/Documentation/everyday.txt b/Documentation/everyday.txt
index d8d7a64..3ab9b91 100644
--- a/Documentation/everyday.txt
+++ b/Documentation/everyday.txt
@@ -211,10 +211,12 @@
<1> repeat as needed.
<2> extract patches from your branch for e-mail submission.
-<3> "pull" fetches from "origin" by default and merges.
-<4> look at the changes since last time we checked, only in the
+<3> "pull" fetches from "origin" by default and merges into the
+current branch.
+<4> immediately after pulling, look at the changes done upstream
+since last time we checked, only in the
area we are interested in.
-<5> fetch from a specific branch from a specific repository and and merge.
+<5> fetch from a specific branch from a specific repository and merge.
<6> revert the pull.
<7> garbage collect leftover objects from reverted pull.
<8> from time to time, obtain official tags from the "origin"
@@ -330,16 +332,18 @@
<8> and bundle topic branches still cooking.
<9> backport a critical fix.
<10> create a signed tag.
-<11> make sure I did not accidentally rewound master beyond what I
+<11> make sure I did not accidentally rewind master beyond what I
already pushed out. "ko" shorthand points at the repository I have
at kernel.org, and looks like this:
-$ cat .git/remotes/ko
-URL: kernel.org:/pub/scm/git/git.git
-Pull: master:refs/tags/ko-master
-Pull: maint:refs/tags/ko-maint
-Push: master
-Push: +pu
-Push: maint
+ $ cat .git/remotes/ko
+ URL: kernel.org:/pub/scm/git/git.git
+ Pull: master:refs/tags/ko-master
+ Pull: maint:refs/tags/ko-maint
+ Push: master
+ Push: +pu
+ Push: maint
+In the output from "git show-branch", "master" should have
+everything "ko-master" has.
<12> push out the bleeding edge.
<13> push the tag out, too.
------------
@@ -357,8 +361,8 @@
* gitlink:git-shell[1] can be used as a 'restricted login shell'
for shared central repository users.
- * link:howto/update-hook-example.txt[update hook howto] has a
- good example of managing a shared central repository.
+link:howto/update-hook-example.txt[update hook howto] has a good
+example of managing a shared central repository.
Examples
@@ -424,3 +428,14 @@
david is the release manager and is the only person who can
create and push version tags.
------------
+
+HTTP server to support dumb protocol transfer.::
++
+------------
+dev$ git update-server-info <1>
+dev$ ftp user@isp.example.com <2>
+ftp> cp -r .git /home/user/myproject.git
+
+<1> make sure your info/refs and objects/info/packs are up-to-date
+<2> upload to public HTTP server hosted by your ISP.
+------------
diff --git a/Documentation/git-archimport.txt b/Documentation/git-archimport.txt
index fcda012..a2bd788 100644
--- a/Documentation/git-archimport.txt
+++ b/Documentation/git-archimport.txt
@@ -8,7 +8,8 @@
SYNOPSIS
--------
-`git-archimport` [ -h ] [ -v ] [ -T ] [ -t tempdir ]
+`git-archimport` [ -h ] [ -v ] [ -o ] [ -a ] [ -f ] [ -T ]
+ [ -D depth ] [ -t tempdir ]
<archive/branch> [ <archive/branch> ]
DESCRIPTION
@@ -63,6 +64,26 @@
Many tags. Will create a tag for every commit, reflecting the commit
name in the Arch repository.
+-f::
+ Use the fast patchset import strategy. This can be significantly
+ faster for large trees, but cannot handle directory renames or
+ permissions changes. The default strategy is slow and safe.
+
+-o::
+ Use this for compatibility with old-style branch names used by
+ earlier versions of git-archimport. Old-style branch names
+ were category--branch, whereas new-style branch names are
+ archive,category--branch--version.
+
+-D <depth>::
+ Follow merge ancestry and attempt to import trees that have been
+ merged from. Specify a depth greater than 1 if patch logs have been
+ pruned.
+
+-a::
+ Attempt to auto-register archives at http://mirrors.sourcecontrol.net
+ This is particularly useful with the -D option.
+
-t <tmpdir>::
Override the default tempdir.
diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt
index 636e951..f7f84c6 100644
--- a/Documentation/git-check-ref-format.txt
+++ b/Documentation/git-check-ref-format.txt
@@ -26,13 +26,15 @@
. It cannot have ASCII control character (i.e. bytes whose
values are lower than \040, or \177 `DEL`), space, tilde `~`,
- caret `{caret}`, or colon `:` anywhere;
+ caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`,
+ or open bracket `[` anywhere;
. It cannot end with a slash `/`.
These rules makes it easy for shell script based tools to parse
-refnames, and also avoids ambiguities in certain refname
-expressions (see gitlink:git-rev-parse[1]). Namely:
+refnames, pathname expansion by the shell when a refname is used
+unquoted (by mistake), and also avoids ambiguities in certain
+refname expressions (see gitlink:git-rev-parse[1]). Namely:
. double-dot `..` are often used as in `ref1..ref2`, and in some
context this notation means `{caret}ref1 ref2` (i.e. not in
diff --git a/Documentation/git-clone-pack.txt b/Documentation/git-clone-pack.txt
index cfc7b62..39906fc 100644
--- a/Documentation/git-clone-pack.txt
+++ b/Documentation/git-clone-pack.txt
@@ -43,7 +43,11 @@
The heads to update. This is relative to $GIT_DIR
(e.g. "HEAD", "refs/heads/master"). When unspecified,
all heads are updated to match the remote repository.
-
++
+Usually all the refs from existing repository are stored
+under the same name in the new repository. Giving explicit
+<head> arguments instead writes the object names and refs to
+the standard output, just like get-fetch-pack does.
Author
------
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index b92cf48..8b91f22 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -66,6 +66,10 @@
Update specified paths in the index file before committing.
+If you make a commit and then found a mistake immediately after
+that, you can recover from it with gitlink:git-reset[1].
+
+
Author
------
Written by Linus Torvalds <torvalds@osdl.org> and
diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt
index ea6faab..b507e9b 100644
--- a/Documentation/git-fetch-pack.txt
+++ b/Documentation/git-fetch-pack.txt
@@ -8,7 +8,7 @@
SYNOPSIS
--------
-git-fetch-pack [-q] [--exec=<git-upload-pack>] [<host>:]<directory> [<refs>...]
+git-fetch-pack [-q] [-k] [--exec=<git-upload-pack>] [<host>:]<directory> [<refs>...]
DESCRIPTION
-----------
@@ -29,6 +29,11 @@
Pass '-q' flag to 'git-unpack-objects'; this makes the
cloning process less verbose.
+-k::
+ Do not invoke 'git-unpack-objects' on received data, but
+ create a single packfile out of it instead, and store it
+ in the object database.
+
--exec=<git-upload-pack>::
Use this to specify the path to 'git-upload-pack' on the
remote side, if is not found on your $PATH.
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index 0cac563..4ce799b 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -37,6 +37,11 @@
include::merge-strategies.txt[]
+If you tried a merge which resulted in a complex conflicts and
+would want to start over, you can recover with
+gitlink:git-reset[1].
+
+
HOW MERGE WORKS
---------------
diff --git a/Documentation/git-octopus.txt b/Documentation/git-octopus.txt
deleted file mode 100644
index 6e32ea3..0000000
--- a/Documentation/git-octopus.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-git-octopus(1)
-==============
-
-NAME
-----
-git-octopus - Merge more than two commits.
-
-
-SYNOPSIS
---------
-'git-octopus'
-
-DESCRIPTION
------------
-After running 'git fetch', $GIT_DIR/FETCH_HEAD contains the
-following information, one line per remote ref:
-
-------------------------------------------------
-<object name> <ref name> from <repository>
-------------------------------------------------
-
-Using this information, create and commit an Octopus merge on
-top of the current HEAD.
-
-
-Author
-------
-Written by Junio C Hamano <junkio@cox.net>
-
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
-GIT
----
-Part of the gitlink:git[7] suite
-
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index c65ca9a..3a7d385 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -104,6 +104,11 @@
local `master` branch.
+If you tried a pull which resulted in a complex conflicts and
+would want to start over, you can recover with
+gitlink:git-reset[1].
+
+
SEE ALSO
--------
gitlink:git-fetch[1], gitlink:git-merge[1]
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt
index 0204891..c6a269b 100644
--- a/Documentation/git-reset.txt
+++ b/Documentation/git-reset.txt
@@ -111,6 +111,39 @@
changes still in the working tree.
------------
+Undo a merge or pull::
++
+------------
+$ git pull <1>
+Trying really trivial in-index merge...
+fatal: Merge requires file-level merging
+Nope.
+...
+Auto-merging nitfol
+CONFLICT (content): Merge conflict in nitfol
+Automatic merge failed/prevented; fix up by hand
+$ git reset --hard <2>
+
+<1> try to update from the upstream resulted in a lot of
+conflicts; you were not ready to spend a lot of time merging
+right now, so you decide to do that later.
+<2> "pull" has not made merge commit, so "git reset --hard"
+which is a synonym for "git reset --hard HEAD" clears the mess
+from the index file and the working tree.
+
+$ git pull . topic/branch <3>
+Updating from 41223... to 13134...
+Fast forward
+$ git reset --hard ORIG_HEAD <4>
+
+<3> merge a topic branch into the current branch, which resulted
+in a fast forward.
+<4> but you decided that the topic branch is not ready for public
+consumption yet. "pull" or "merge" always leaves the original
+tip of the current branch in ORIG_HEAD, so resetting hard to it
+brings your index file and the working tree back to that state,
+and resets the tip of the branch to that commit.
+------------
Author
------
diff --git a/Documentation/git-update-server-info.txt b/Documentation/git-update-server-info.txt
index 527fb30..88a03c7 100644
--- a/Documentation/git-update-server-info.txt
+++ b/Documentation/git-update-server-info.txt
@@ -12,11 +12,11 @@
DESCRIPTION
-----------
-A dumb server that does not do on-the-fly pack generations can
+A dumb server that does not do on-the-fly pack generations must
have some auxiliary information files in $GIT_DIR/info and
$GIT_OBJECT_DIRECTORY/info directories to help clients discover
-what references and packs the server has and make optimized
-pull decisions. This command generates such auxiliary files.
+what references and packs the server has. This command
+generates such auxiliary files.
OPTIONS
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 482eba7..5f068c2 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -297,9 +297,6 @@
gitlink:git-mv[1]::
Move or rename a file, a directory, or a symlink.
-gitlink:git-octopus[1]::
- Merge more than two commits.
-
gitlink:git-pull[1]::
Fetch from and merge with a remote repository.
diff --git a/Documentation/hooks.txt b/Documentation/hooks.txt
index 7ee3571..4ad1920 100644
--- a/Documentation/hooks.txt
+++ b/Documentation/hooks.txt
@@ -111,6 +111,10 @@
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
+want to report something to the git-send-pack on the other end,
+you can redirect your output to your stderr.
+
post-update
-----------
@@ -125,3 +129,7 @@
The default post-update hook, when enabled, runs
`git-update-server-info` to keep the information used by dumb
transport up-to-date.
+
+The standard output of this hook is sent to /dev/null; if you
+want to report something to the git-send-pack on the other end,
+you can redirect your output to your stderr.
diff --git a/Documentation/howto/rebuild-from-update-hook.txt b/Documentation/howto/rebuild-from-update-hook.txt
index ebd025d..02621b5 100644
--- a/Documentation/howto/rebuild-from-update-hook.txt
+++ b/Documentation/howto/rebuild-from-update-hook.txt
@@ -10,7 +10,7 @@
are built from Documentation/ directory of the git.git project
and needed to be kept up-to-date. The www.kernel.org/ servers
are mirrored and I was told that the origin of the mirror is on
-the machine master.kernel.org, on which I was given an account
+the machine $some.kernel.org, on which I was given an account
when I took over git maintainership from Linus.
The directories relevant to this how-to are these two:
@@ -63,7 +63,7 @@
EOF
$ chmod +x /pub/scm/git/git.git/hooks/post-update
-There are three things worth mentioning:
+There are four things worth mentioning:
- The update-hook is run after the repository accepts a "git
push", under my user privilege. It is given the full names
@@ -77,6 +77,10 @@
pull" it does into $HOME/doc-git/docgen/ repository would not
work correctly.
+ - The stdout of update hook script is not connected to git
+ push; I run the heavy part of the command inside "at", to
+ receive the execution report via e-mail.
+
- This is still crude and does not protect against simultaneous
make invocations stomping on each other. I would need to add
some locking mechanism for this.
diff --git a/Documentation/howto/using-topic-branches.txt b/Documentation/howto/using-topic-branches.txt
index 4944297..b3d592f 100644
--- a/Documentation/howto/using-topic-branches.txt
+++ b/Documentation/howto/using-topic-branches.txt
@@ -42,8 +42,7 @@
First create your work tree by cloning Linus's public tree:
- $ git clone \
- master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6.git work
+ $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git work
Change directory into the cloned tree you just created
@@ -53,7 +52,7 @@
branch into a local branch named "linus":
$ cat > .git/remotes/linus
- URL: master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
+ URL: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Pull: master:linus
^D
diff --git a/Documentation/tutorial.txt b/Documentation/tutorial.txt
index a61b824..3a5c56e 100644
--- a/Documentation/tutorial.txt
+++ b/Documentation/tutorial.txt
@@ -27,6 +27,12 @@
[NOTE]
And those "too deep" descriptions are often marked as Note.
+[NOTE]
+If you are already familiar with another version control system,
+like CVS, you may want to take a look at
+link:everyday.html[Everyday GIT in 20 commands or so] first
+before reading this.
+
Creating a git repository
-------------------------
@@ -1085,9 +1091,10 @@
HTTP(S)::
`http://remote.machine/path/to/repo.git/`
+
-HTTP and HTTPS transport are used only for downloading. They
-first obtain the topmost commit object name from the remote site
-by looking at `repo.git/info/refs` file, tries to obtain the
+Downloader from http and https URL
+first obtains the topmost commit object name from the remote site
+by looking at the specified refname under `repo.git/refs/` directory,
+and then tries to obtain the
commit object by downloading from `repo.git/objects/xx/xxx\...`
using the object name of that commit object. Then it reads the
commit object to find out its parent commits and the associate
@@ -1098,7 +1105,9 @@
The 'commit walkers' are sometimes also called 'dumb
transports', because they do not require any git aware smart
server like git Native transport does. Any stock HTTP server
-would suffice.
+that does not even support directory index would suffice. But
+you must prepare your repository with `git-update-server-info`
+to help dumb transport downloaders.
+
There are (confusingly enough) `git-ssh-fetch` and `git-ssh-upload`
programs, which are 'commit walkers'; they outlived their
@@ -1511,12 +1520,13 @@
2. Prepare a public repository accessible to others.
+
If other people are pulling from your repository over dumb
-transport protocols, you need to keep this repository 'dumb
-transport friendly'. After `git init-db`,
+transport protocols (HTTP), you need to keep this repository
+'dumb transport friendly'. After `git init-db`,
`$GIT_DIR/hooks/post-update` copied from the standard templates
would contain a call to `git-update-server-info` but the
`post-update` hook itself is disabled by default -- enable it
-with `chmod +x post-update`.
+with `chmod +x post-update`. This makes sure `git-update-server-info`
+keeps the necessary files up-to-date.
3. Push into the public repository from your primary
repository.
@@ -1615,7 +1625,9 @@
For this, set up a public repository on a machine that is
reachable via SSH by people with "commit privileges". Put the
committers in the same user group and make the repository
-writable by that group.
+writable by that group. Make sure their umasks are set up to
+allow group members to write into directories other members
+have created.
You, as an individual committer, then:
diff --git a/Makefile b/Makefile
index 92cfee4..e9bf860 100644
--- a/Makefile
+++ b/Makefile
@@ -55,7 +55,7 @@
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-cache perspective.
-GIT_VERSION = 0.99.9n
+GIT_VERSION = 1.0.0
# CFLAGS and LDFLAGS are for the users to override from the command line.
@@ -89,7 +89,7 @@
git-cherry.sh git-clone.sh git-commit.sh \
git-count-objects.sh git-diff.sh git-fetch.sh \
git-format-patch.sh git-log.sh git-ls-remote.sh \
- git-merge-one-file.sh git-octopus.sh git-parse-remote.sh \
+ git-merge-one-file.sh git-parse-remote.sh \
git-prune.sh git-pull.sh git-push.sh git-rebase.sh \
git-repack.sh git-request-pull.sh git-reset.sh \
git-resolve.sh git-revert.sh git-sh-setup.sh git-status.sh \
@@ -175,6 +175,7 @@
quote.o read-cache.o refs.o run-command.o \
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
+ fetch-clone.o \
$(DIFF_OBJS)
LIBS = $(LIB_FILE)
@@ -497,7 +498,7 @@
rm -f *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o $(LIB_FILE)
rm -f $(PROGRAMS) $(SIMPLE_PROGRAMS) git$X
rm -f $(filter-out gitk,$(SCRIPTS))
- rm -f *.spec *.pyc *.pyo
+ rm -f *.spec *.pyc *.pyo */*.pyc */*.pyo
rm -rf $(GIT_TARNAME)
rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
rm -f git-core_$(GIT_VERSION)-*.dsc
@@ -505,3 +506,4 @@
$(MAKE) -C Documentation/ clean
$(MAKE) -C templates clean
$(MAKE) -C t/ clean
+
diff --git a/apply.c b/apply.c
index 1742ab2..d5e7bfd 100644
--- a/apply.c
+++ b/apply.c
@@ -84,14 +84,11 @@
buffer = xrealloc(buffer, alloc);
nr = alloc - size;
}
- nr = read(fd, buffer + size, nr);
+ nr = xread(fd, buffer + size, nr);
if (!nr)
break;
- if (nr < 0) {
- if (errno == EAGAIN)
- continue;
+ if (nr < 0)
die("git-apply: read returned %s", strerror(errno));
- }
size += nr;
}
*sizep = size;
@@ -1006,13 +1003,8 @@
return error("unable to open %s", path);
got = 0;
for (;;) {
- int ret = read(fd, buf + got, size - got);
- if (ret < 0) {
- if (errno == EAGAIN)
- continue;
- break;
- }
- if (!ret)
+ int ret = xread(fd, buf + got, size - got);
+ if (ret <= 0)
break;
got += ret;
}
@@ -1600,12 +1592,9 @@
if (fd < 0)
return -1;
while (size) {
- int written = write(fd, buf, size);
- if (written < 0) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
+ int written = xwrite(fd, buf, size);
+ if (written < 0)
die("writing file %s: %s", path, strerror(errno));
- }
if (!written)
die("out of space writing file %s", path);
buf += written;
diff --git a/cache.h b/cache.h
index c78d8ae..cb87bec 100644
--- a/cache.h
+++ b/cache.h
@@ -338,4 +338,9 @@
extern char git_commit_encoding[MAX_ENCODING_LENGTH];
extern int copy_fd(int ifd, int ofd);
+
+/* Finish off pack transfer receiving end */
+extern int receive_unpack_pack(int fd[2], const char *me, int quiet);
+extern int receive_keep_pack(int fd[2], const char *me);
+
#endif /* CACHE_H */
diff --git a/cat-file.c b/cat-file.c
index 7594108..96d66b4 100644
--- a/cat-file.c
+++ b/cat-file.c
@@ -55,10 +55,8 @@
die("git-cat-file %s: bad file", argv[2]);
while (size > 0) {
- long ret = write(1, buf, size);
+ long ret = xwrite(1, buf, size);
if (ret < 0) {
- if (errno == EAGAIN)
- continue;
/* Ignore epipe */
if (errno == EPIPE)
break;
diff --git a/clone-pack.c b/clone-pack.c
index a99a95c..f634431 100644
--- a/clone-pack.c
+++ b/clone-pack.c
@@ -1,7 +1,6 @@
#include "cache.h"
#include "refs.h"
#include "pkt-line.h"
-#include <sys/wait.h>
static const char clone_pack_usage[] =
"git-clone-pack [--exec=<git-upload-pack>] [<host>:]<directory> [<heads>]*";
@@ -112,139 +111,6 @@
free(head_path);
}
-static int finish_pack(const char *pack_tmp_name)
-{
- int pipe_fd[2];
- pid_t pid;
- char idx[PATH_MAX];
- char final[PATH_MAX];
- char hash[41];
- unsigned char sha1[20];
- char *cp;
- int err = 0;
-
- if (pipe(pipe_fd) < 0)
- die("git-clone-pack: unable to set up pipe");
-
- strcpy(idx, pack_tmp_name); /* ".git/objects/pack-XXXXXX" */
- cp = strrchr(idx, '/');
- memcpy(cp, "/pidx", 5);
-
- pid = fork();
- if (pid < 0)
- die("git-clone-pack: unable to fork off git-index-pack");
- if (!pid) {
- close(0);
- dup2(pipe_fd[1], 1);
- close(pipe_fd[0]);
- close(pipe_fd[1]);
- execlp("git-index-pack","git-index-pack",
- "-o", idx, pack_tmp_name, NULL);
- error("cannot exec git-index-pack <%s> <%s>",
- idx, pack_tmp_name);
- exit(1);
- }
- close(pipe_fd[1]);
- if (read(pipe_fd[0], hash, 40) != 40) {
- error("git-clone-pack: unable to read from git-index-pack");
- err = 1;
- }
- close(pipe_fd[0]);
-
- for (;;) {
- int status, code;
- int retval = waitpid(pid, &status, 0);
-
- if (retval < 0) {
- if (errno == EINTR)
- continue;
- error("waitpid failed (%s)", strerror(retval));
- goto error_die;
- }
- if (WIFSIGNALED(status)) {
- int sig = WTERMSIG(status);
- error("git-index-pack died of signal %d", sig);
- goto error_die;
- }
- if (!WIFEXITED(status)) {
- error("git-index-pack died of unnatural causes %d",
- status);
- goto error_die;
- }
- code = WEXITSTATUS(status);
- if (code) {
- error("git-index-pack died with error code %d", code);
- goto error_die;
- }
- if (err)
- goto error_die;
- break;
- }
- hash[40] = 0;
- if (get_sha1_hex(hash, sha1)) {
- error("git-index-pack reported nonsense '%s'", hash);
- goto error_die;
- }
- /* Now we have pack in pack_tmp_name[], and
- * idx in idx[]; rename them to their final names.
- */
- snprintf(final, sizeof(final),
- "%s/pack/pack-%s.pack", get_object_directory(), hash);
- move_temp_to_file(pack_tmp_name, final);
- chmod(final, 0444);
- snprintf(final, sizeof(final),
- "%s/pack/pack-%s.idx", get_object_directory(), hash);
- move_temp_to_file(idx, final);
- chmod(final, 0444);
- return 0;
-
- error_die:
- unlink(idx);
- unlink(pack_tmp_name);
- exit(1);
-}
-
-static int clone_without_unpack(int fd[2])
-{
- char tmpfile[PATH_MAX];
- int ofd, ifd;
-
- ifd = fd[0];
- snprintf(tmpfile, sizeof(tmpfile),
- "%s/pack/tmp-XXXXXX", get_object_directory());
- ofd = mkstemp(tmpfile);
- if (ofd < 0)
- return error("unable to create temporary file %s", tmpfile);
-
- while (1) {
- char buf[8192];
- ssize_t sz, wsz, pos;
- sz = read(ifd, buf, sizeof(buf));
- if (sz == 0)
- break;
- if (sz < 0) {
- error("error reading pack (%s)", strerror(errno));
- close(ofd);
- unlink(tmpfile);
- return -1;
- }
- pos = 0;
- while (pos < sz) {
- wsz = write(ofd, buf + pos, sz - pos);
- if (wsz < 0) {
- error("error writing pack (%s)",
- strerror(errno));
- close(ofd);
- unlink(tmpfile);
- return -1;
- }
- pos += wsz;
- }
- }
- close(ofd);
- return finish_pack(tmpfile);
-}
-
static int clone_pack(int fd[2], int nr_match, char **match)
{
struct ref *refs;
@@ -257,10 +123,19 @@
}
clone_handshake(fd, refs);
- status = clone_without_unpack(fd);
+ status = receive_keep_pack(fd, "git-clone-pack");
- if (!status)
- write_refs(refs);
+ if (!status) {
+ if (nr_match == 0)
+ write_refs(refs);
+ else
+ while (refs) {
+ printf("%s %s\n",
+ sha1_to_hex(refs->old_sha1),
+ refs->name);
+ refs = refs->next;
+ }
+ }
return status;
}
@@ -285,8 +160,6 @@
exec = arg + 7;
continue;
}
- if (!strcmp("--keep", arg))
- continue;
usage(clone_pack_usage);
}
dest = arg;
diff --git a/cmd-rename.sh b/cmd-rename.sh
deleted file mode 100755
index 992493d..0000000
--- a/cmd-rename.sh
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/bin/sh
-#
-# If you installed git by hand previously, you may find this
-# script useful to remove the symbolic links that we shipped
-# for backward compatibility.
-#
-# Running this script with the previous installation directory
-# like this:
-#
-# $ cmd-rename.sh /usr/local/bin/
-#
-# would clean them.
-
-d="$1"
-test -d "$d" || exit
-while read old new
-do
- rm -f "$d/$old"
-done <<\EOF
-git-add-script git-add
-git-archimport-script git-archimport
-git-bisect-script git-bisect
-git-branch-script git-branch
-git-checkout-script git-checkout
-git-cherry-pick-script git-cherry-pick
-git-clone-script git-clone
-git-commit-script git-commit
-git-count-objects-script git-count-objects
-git-cvsimport-script git-cvsimport
-git-diff-script git-diff
-git-send-email-script git-send-email
-git-fetch-script git-fetch
-git-format-patch-script git-format-patch
-git-log-script git-log
-git-ls-remote-script git-ls-remote
-git-merge-one-file-script git-merge-one-file
-git-octopus-script git-octopus
-git-parse-remote-script git-parse-remote
-git-prune-script git-prune
-git-pull-script git-pull
-git-push-script git-push
-git-rebase-script git-rebase
-git-relink-script git-relink
-git-rename-script git-rename
-git-repack-script git-repack
-git-request-pull-script git-request-pull
-git-reset-script git-reset
-git-resolve-script git-resolve
-git-revert-script git-revert
-git-sh-setup-script git-sh-setup
-git-status-script git-status
-git-tag-script git-tag
-git-verify-tag-script git-verify-tag
-git-http-pull git-http-fetch
-git-local-pull git-local-fetch
-git-checkout-cache git-checkout-index
-git-diff-cache git-diff-index
-git-merge-cache git-merge-index
-git-update-cache git-update-index
-git-convert-cache git-convert-objects
-git-fsck-cache git-fsck-objects
-EOF
diff --git a/copy.c b/copy.c
index e1cd5d0..7100eed 100644
--- a/copy.c
+++ b/copy.c
@@ -6,32 +6,27 @@
int len;
char buffer[8192];
char *buf = buffer;
- len = read(ifd, buffer, sizeof(buffer));
+ len = xread(ifd, buffer, sizeof(buffer));
if (!len)
break;
if (len < 0) {
int read_error;
- if (errno == EAGAIN)
- continue;
read_error = errno;
close(ifd);
return error("copy-fd: read returned %s",
strerror(read_error));
}
- while (1) {
- int written = write(ofd, buf, len);
+ while (len) {
+ int written = xwrite(ofd, buf, len);
if (written > 0) {
buf += written;
len -= written;
- if (!len)
- break;
}
- if (!written)
+ else if (!written)
return error("copy-fd: write returned 0");
- if (errno == EAGAIN || errno == EINTR)
- continue;
- return error("copy-fd: write returned %s",
- strerror(errno));
+ else
+ return error("copy-fd: write returned %s",
+ strerror(errno));
}
}
close(ifd);
diff --git a/csum-file.c b/csum-file.c
index c66b9eb..5f9249a 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -15,7 +15,7 @@
void *buf = f->buffer;
for (;;) {
- int ret = write(f->fd, buf, count);
+ int ret = xwrite(f->fd, buf, count);
if (ret > 0) {
buf += ret;
count -= ret;
@@ -25,8 +25,6 @@
}
if (!ret)
die("sha1 file '%s' write error. Out of diskspace", f->name);
- if (errno == EAGAIN || errno == EINTR)
- continue;
die("sha1 file '%s' write error (%s)", f->name, strerror(errno));
}
}
diff --git a/debian/changelog b/debian/changelog
index d36904c..4fa6c16 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+git-core (1.0.0-0) unstable; urgency=low
+
+ * GIT 1.0.0
+
+ -- Junio C Hamano <junkio@cox.net> Wed, 21 Dec 2005 00:01:00 -0800
+
git-core (0.99.9n-0) unstable; urgency=low
* GIT 0.99.9n aka 1.0rc6
diff --git a/diff-delta.c b/diff-delta.c
index b2ae7b5..890986e 100644
--- a/diff-delta.c
+++ b/diff-delta.c
@@ -84,20 +84,15 @@
} chanode_t;
typedef struct s_chastore {
- chanode_t *head, *tail;
int isize, nsize;
chanode_t *ancur;
- chanode_t *sncur;
- int scurr;
} chastore_t;
static void cha_init(chastore_t *cha, int isize, int icount)
{
- cha->head = cha->tail = NULL;
cha->isize = isize;
cha->nsize = icount * isize;
- cha->ancur = cha->sncur = NULL;
- cha->scurr = 0;
+ cha->ancur = NULL;
}
static void *cha_alloc(chastore_t *cha)
@@ -111,12 +106,7 @@
if (!ancur)
return NULL;
ancur->icurr = 0;
- ancur->next = NULL;
- if (cha->tail)
- cha->tail->next = ancur;
- if (!cha->head)
- cha->head = ancur;
- cha->tail = ancur;
+ ancur->next = cha->ancur;
cha->ancur = ancur;
}
@@ -127,7 +117,7 @@
static void cha_free(chastore_t *cha)
{
- chanode_t *cur = cha->head;
+ chanode_t *cur = cha->ancur;
while (cur) {
chanode_t *tmp = cur;
cur = cur->next;
@@ -142,7 +132,6 @@
} bdrecord_t;
typedef struct s_bdfile {
- const unsigned char *data, *top;
chastore_t cha;
unsigned int fphbits;
bdrecord_t **fphash;
@@ -152,7 +141,7 @@
{
unsigned int fphbits;
int i, hsize;
- const unsigned char *base, *data, *top;
+ const unsigned char *data, *top;
bdrecord_t *brec;
bdrecord_t **fphash;
@@ -165,13 +154,12 @@
fphash[i] = NULL;
cha_init(&bdf->cha, sizeof(bdrecord_t), hsize / 4 + 1);
- bdf->data = data = base = buf;
- bdf->top = top = buf + bufsize;
- data += (bufsize / BLK_SIZE) * BLK_SIZE;
+ top = buf + bufsize;
+ data = buf + (bufsize / BLK_SIZE) * BLK_SIZE;
if (data == top)
data -= BLK_SIZE;
- for ( ; data >= base; data -= BLK_SIZE) {
+ for ( ; data >= buf; data -= BLK_SIZE) {
brec = cha_alloc(&bdf->cha);
if (!brec) {
cha_free(&bdf->cha);
@@ -208,7 +196,7 @@
{
int i, outpos, outsize, inscnt, csize, msize, moff;
unsigned int fp;
- const unsigned char *data, *top, *ptr1, *ptr2;
+ const unsigned char *ref_data, *ref_top, *data, *top, *ptr1, *ptr2;
unsigned char *out, *orig;
bdrecord_t *brec;
bdfile_t bdf;
@@ -224,6 +212,8 @@
return NULL;
}
+ ref_data = from_buf;
+ ref_top = from_buf + from_size;
data = to_buf;
top = to_buf + to_size;
@@ -253,7 +243,7 @@
i = HASH(fp, bdf.fphbits);
for (brec = bdf.fphash[i]; brec; brec = brec->next) {
if (brec->fp == fp) {
- csize = bdf.top - brec->ptr;
+ csize = ref_top - brec->ptr;
if (csize > top - data)
csize = top - data;
for (ptr1 = brec->ptr, ptr2 = data;
@@ -262,7 +252,7 @@
csize = ptr1 - brec->ptr;
if (csize > msize) {
- moff = brec->ptr - bdf.data;
+ moff = brec->ptr - ref_data;
msize = csize;
if (msize >= 0x10000) {
msize = 0x10000;
diff --git a/diff-tree.c b/diff-tree.c
index d56d921..efa2b94 100644
--- a/diff-tree.c
+++ b/diff-tree.c
@@ -14,11 +14,6 @@
static struct diff_options diff_options;
-static void call_diff_setup_done(void)
-{
- diff_setup_done(&diff_options);
-}
-
static int call_diff_flush(void)
{
diffcore_std(&diff_options);
@@ -43,7 +38,6 @@
{
int ret;
- call_diff_setup_done();
ret = diff_tree_sha1(old, new, base, &diff_options);
call_diff_flush();
return ret;
@@ -55,7 +49,6 @@
void *tree;
struct tree_desc empty, real;
- call_diff_setup_done();
tree = read_object_with_reference(new, "tree", &real.size, NULL);
if (!tree)
die("unable to read root tree (%s)", sha1_to_hex(new));
@@ -69,18 +62,29 @@
return retval;
}
-static const char *generate_header(const char *commit, const char *parent, const char *msg)
+static const char *generate_header(const unsigned char *commit_sha1,
+ const unsigned char *parent_sha1,
+ const char *msg)
{
static char this_header[16384];
int offset;
unsigned long len;
+ int abbrev = diff_options.abbrev;
if (!verbose_header)
- return commit;
+ return sha1_to_hex(commit_sha1);
len = strlen(msg);
- offset = sprintf(this_header, "%s%s (from %s)\n", header_prefix, commit, parent);
- offset += pretty_print_commit(commit_format, msg, len, this_header + offset, sizeof(this_header) - offset);
+
+ offset = sprintf(this_header, "%s%s ",
+ header_prefix,
+ diff_unique_abbrev(commit_sha1, abbrev));
+ offset += sprintf(this_header + offset, "(from %s)\n",
+ parent_sha1 ?
+ diff_unique_abbrev(parent_sha1, abbrev) : "root");
+ offset += pretty_print_commit(commit_format, msg, len,
+ this_header + offset,
+ sizeof(this_header) - offset);
return this_header;
}
@@ -99,18 +103,18 @@
/* Root commit? */
if (show_root_diff && !commit->parents) {
- header = generate_header(name, "root", commit->buffer);
+ header = generate_header(sha1, NULL, commit->buffer);
diff_root_tree(commit_sha1, "");
}
/* More than one parent? */
if (ignore_merges && commit->parents && commit->parents->next)
- return 0;
+ return 0;
for (parents = commit->parents; parents; parents = parents->next) {
struct commit *parent = parents->item;
- header = generate_header(name,
- sha1_to_hex(parent->object.sha1),
+ header = generate_header(sha1,
+ parent->object.sha1,
commit->buffer);
diff_tree_sha1_top(parent->object.sha1, commit_sha1, "");
if (!header && verbose_header) {
@@ -129,6 +133,7 @@
int len = strlen(line);
unsigned char commit[20], parent[20];
static char this_header[1000];
+ int abbrev = diff_options.abbrev;
if (!len || line[len-1] != '\n')
return -1;
@@ -138,7 +143,9 @@
if (isspace(line[40]) && !get_sha1_hex(line+41, parent)) {
line[40] = 0;
line[81] = 0;
- sprintf(this_header, "%s (from %s)\n", line, line+41);
+ sprintf(this_header, "%s (from %s)\n",
+ diff_unique_abbrev(commit, abbrev),
+ diff_unique_abbrev(parent, abbrev));
header = this_header;
return diff_tree_sha1_top(parent, commit, "");
}
@@ -239,6 +246,7 @@
diff_options.recursive = 1;
diff_tree_setup_paths(get_pathspec(prefix, argv));
+ diff_setup_done(&diff_options);
switch (nr_sha1) {
case 0:
diff --git a/diff.c b/diff.c
index 2e0797b..c815918 100644
--- a/diff.c
+++ b/diff.c
@@ -723,11 +723,13 @@
if (memcmp(one->sha1, two->sha1, 20)) {
char one_sha1[41];
- const char *index_fmt = o->full_index ? "index %s..%s" : "index %.7s..%.7s";
+ int abbrev = o->full_index ? 40 : DIFF_DEFAULT_INDEX_ABBREV;
memcpy(one_sha1, sha1_to_hex(one->sha1), 41);
len += snprintf(msg + len, sizeof(msg) - len,
- index_fmt, one_sha1, sha1_to_hex(two->sha1));
+ "index %.*s..%.*s",
+ abbrev, one_sha1, abbrev,
+ sha1_to_hex(two->sha1));
if (one->mode == two->mode)
len += snprintf(msg + len, sizeof(msg) - len,
" %06o", one->mode);
@@ -791,6 +793,8 @@
}
if (options->setup & DIFF_SETUP_USE_SIZE_CACHE)
use_size_cache = 1;
+ if (options->abbrev <= 0 || 40 < options->abbrev)
+ options->abbrev = 40; /* full */
return 0;
}
@@ -841,6 +845,10 @@
}
else if (!strcmp(arg, "--find-copies-harder"))
options->find_copies_harder = 1;
+ else if (!strcmp(arg, "--abbrev"))
+ options->abbrev = DIFF_DEFAULT_ABBREV;
+ else if (!strncmp(arg, "--abbrev=", 9))
+ options->abbrev = strtoul(arg + 9, NULL, 10);
else
return 0;
return 1;
@@ -947,14 +955,49 @@
free(p);
}
+/* This is different from find_unique_abbrev() in that
+ * it needs to deal with 0{40} SHA1.
+ */
+const char *diff_unique_abbrev(const unsigned char *sha1, int len)
+{
+ int abblen;
+ const char *abbrev;
+ if (len == 40)
+ return sha1_to_hex(sha1);
+
+ abbrev = find_unique_abbrev(sha1, len);
+ if (!abbrev) {
+ if (!memcmp(sha1, null_sha1, 20)) {
+ char *buf = sha1_to_hex(null_sha1);
+ if (len < 37)
+ strcpy(buf + len, "...");
+ return buf;
+ }
+ else
+ return sha1_to_hex(sha1);
+ }
+ abblen = strlen(abbrev);
+ if (abblen < 37) {
+ static char hex[41];
+ if (len < abblen && abblen <= len + 2)
+ sprintf(hex, "%s%.*s", abbrev, len+3-abblen, "..");
+ else
+ sprintf(hex, "%s...", abbrev);
+ return hex;
+ }
+ return sha1_to_hex(sha1);
+}
+
static void diff_flush_raw(struct diff_filepair *p,
int line_termination,
int inter_name_termination,
- int output_format)
+ struct diff_options *options)
{
int two_paths;
char status[10];
+ int abbrev = options->abbrev;
const char *path_one, *path_two;
+ int output_format = options->output_format;
path_one = p->one->path;
path_two = p->two->path;
@@ -985,8 +1028,10 @@
}
if (output_format != DIFF_FORMAT_NAME_STATUS) {
printf(":%06o %06o %s ",
- p->one->mode, p->two->mode, sha1_to_hex(p->one->sha1));
- printf("%s ", sha1_to_hex(p->two->sha1));
+ p->one->mode, p->two->mode,
+ diff_unique_abbrev(p->one->sha1, abbrev));
+ printf("%s ",
+ diff_unique_abbrev(p->two->sha1, abbrev));
}
printf("%s%c%s", status, inter_name_termination, path_one);
if (two_paths)
@@ -1194,7 +1239,7 @@
case DIFF_FORMAT_NAME_STATUS:
diff_flush_raw(p, line_termination,
inter_name_termination,
- diff_output_format);
+ options);
break;
case DIFF_FORMAT_NAME:
diff_flush_name(p,
diff --git a/diff.h b/diff.h
index 32b4780..5696f2a 100644
--- a/diff.h
+++ b/diff.h
@@ -44,6 +44,7 @@
int reverse_diff;
int rename_limit;
int setup;
+ int abbrev;
change_fn_t change;
add_remove_fn_t add_remove;
@@ -87,6 +88,9 @@
#define DIFF_PICKAXE_ALL 1
+#define DIFF_DEFAULT_INDEX_ABBREV 7 /* hex digits */
+#define DIFF_DEFAULT_ABBREV 7 /* hex digits */
+
extern void diffcore_std(struct diff_options *);
extern void diffcore_std_no_resolve(struct diff_options *);
@@ -98,7 +102,8 @@
" -u synonym for -p.\n" \
" --name-only show only names of changed files.\n" \
" --name-status show names and status of changed files.\n" \
-" --full-index show full object name on index ines.\n" \
+" --full-index show full object name on index lines.\n" \
+" --abbrev=<n> abbreviate object names in diff-tree header and diff-raw.\n" \
" -R swap input file pairs.\n" \
" -B detect complete rewrites.\n" \
" -M detect renames.\n" \
@@ -137,4 +142,6 @@
#define DIFF_STATUS_FILTER_AON '*'
#define DIFF_STATUS_FILTER_BROKEN 'B'
+extern const char *diff_unique_abbrev(const unsigned char *, int);
+
#endif /* DIFF_H */
diff --git a/fetch-clone.c b/fetch-clone.c
new file mode 100644
index 0000000..2b2aa15
--- /dev/null
+++ b/fetch-clone.c
@@ -0,0 +1,172 @@
+#include "cache.h"
+#include <sys/wait.h>
+
+static int finish_pack(const char *pack_tmp_name, const char *me)
+{
+ int pipe_fd[2];
+ pid_t pid;
+ char idx[PATH_MAX];
+ char final[PATH_MAX];
+ char hash[41];
+ unsigned char sha1[20];
+ char *cp;
+ int err = 0;
+
+ if (pipe(pipe_fd) < 0)
+ die("%s: unable to set up pipe", me);
+
+ strcpy(idx, pack_tmp_name); /* ".git/objects/pack-XXXXXX" */
+ cp = strrchr(idx, '/');
+ memcpy(cp, "/pidx", 5);
+
+ pid = fork();
+ if (pid < 0)
+ die("git-clone-pack: unable to fork off git-index-pack");
+ if (!pid) {
+ close(0);
+ dup2(pipe_fd[1], 1);
+ close(pipe_fd[0]);
+ close(pipe_fd[1]);
+ execlp("git-index-pack","git-index-pack",
+ "-o", idx, pack_tmp_name, NULL);
+ error("cannot exec git-index-pack <%s> <%s>",
+ idx, pack_tmp_name);
+ exit(1);
+ }
+ close(pipe_fd[1]);
+ if (read(pipe_fd[0], hash, 40) != 40) {
+ error("%s: unable to read from git-index-pack", me);
+ err = 1;
+ }
+ close(pipe_fd[0]);
+
+ for (;;) {
+ int status, code;
+ int retval = waitpid(pid, &status, 0);
+
+ if (retval < 0) {
+ if (errno == EINTR)
+ continue;
+ error("waitpid failed (%s)", strerror(retval));
+ goto error_die;
+ }
+ if (WIFSIGNALED(status)) {
+ int sig = WTERMSIG(status);
+ error("git-index-pack died of signal %d", sig);
+ goto error_die;
+ }
+ if (!WIFEXITED(status)) {
+ error("git-index-pack died of unnatural causes %d",
+ status);
+ goto error_die;
+ }
+ code = WEXITSTATUS(status);
+ if (code) {
+ error("git-index-pack died with error code %d", code);
+ goto error_die;
+ }
+ if (err)
+ goto error_die;
+ break;
+ }
+ hash[40] = 0;
+ if (get_sha1_hex(hash, sha1)) {
+ error("git-index-pack reported nonsense '%s'", hash);
+ goto error_die;
+ }
+ /* Now we have pack in pack_tmp_name[], and
+ * idx in idx[]; rename them to their final names.
+ */
+ snprintf(final, sizeof(final),
+ "%s/pack/pack-%s.pack", get_object_directory(), hash);
+ move_temp_to_file(pack_tmp_name, final);
+ chmod(final, 0444);
+ snprintf(final, sizeof(final),
+ "%s/pack/pack-%s.idx", get_object_directory(), hash);
+ move_temp_to_file(idx, final);
+ chmod(final, 0444);
+ return 0;
+
+ error_die:
+ unlink(idx);
+ unlink(pack_tmp_name);
+ exit(1);
+}
+
+int receive_unpack_pack(int fd[2], const char *me, int quiet)
+{
+ int status;
+ pid_t pid;
+
+ pid = fork();
+ if (pid < 0)
+ die("%s: unable to fork off git-unpack-objects", me);
+ if (!pid) {
+ dup2(fd[0], 0);
+ close(fd[0]);
+ close(fd[1]);
+ execlp("git-unpack-objects", "git-unpack-objects",
+ quiet ? "-q" : NULL, NULL);
+ die("git-unpack-objects exec failed");
+ }
+ close(fd[0]);
+ close(fd[1]);
+ while (waitpid(pid, &status, 0) < 0) {
+ if (errno != EINTR)
+ die("waiting for git-unpack-objects: %s",
+ strerror(errno));
+ }
+ if (WIFEXITED(status)) {
+ int code = WEXITSTATUS(status);
+ if (code)
+ die("git-unpack-objects died with error code %d",
+ code);
+ return 0;
+ }
+ if (WIFSIGNALED(status)) {
+ int sig = WTERMSIG(status);
+ die("git-unpack-objects died of signal %d", sig);
+ }
+ die("git-unpack-objects died of unnatural causes %d", status);
+}
+
+int receive_keep_pack(int fd[2], const char *me)
+{
+ char tmpfile[PATH_MAX];
+ int ofd, ifd;
+
+ ifd = fd[0];
+ snprintf(tmpfile, sizeof(tmpfile),
+ "%s/pack/tmp-XXXXXX", get_object_directory());
+ ofd = mkstemp(tmpfile);
+ if (ofd < 0)
+ return error("unable to create temporary file %s", tmpfile);
+
+ while (1) {
+ char buf[8192];
+ ssize_t sz, wsz, pos;
+ sz = read(ifd, buf, sizeof(buf));
+ if (sz == 0)
+ break;
+ if (sz < 0) {
+ error("error reading pack (%s)", strerror(errno));
+ close(ofd);
+ unlink(tmpfile);
+ return -1;
+ }
+ pos = 0;
+ while (pos < sz) {
+ wsz = write(ofd, buf + pos, sz - pos);
+ if (wsz < 0) {
+ error("error writing pack (%s)",
+ strerror(errno));
+ close(ofd);
+ unlink(tmpfile);
+ return -1;
+ }
+ pos += wsz;
+ }
+ }
+ close(ofd);
+ return finish_pack(tmpfile, me);
+}
diff --git a/fetch-pack.c b/fetch-pack.c
index 58ba209..d34f322 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -3,13 +3,12 @@
#include "pkt-line.h"
#include "commit.h"
#include "tag.h"
-#include <time.h>
-#include <sys/wait.h>
+static int keep_pack;
static int quiet;
static int verbose;
static const char fetch_pack_usage[] =
-"git-fetch-pack [-q] [-v] [--exec=upload-pack] [host:]directory <refs>...";
+"git-fetch-pack [-q] [-v] [-k] [--exec=upload-pack] [host:]directory <refs>...";
static const char *exec = "git-upload-pack";
#define COMPLETE (1U << 0)
@@ -363,7 +362,6 @@
struct ref *ref;
unsigned char sha1[20];
int status;
- pid_t pid;
get_remote_heads(fd[0], &ref, 0, NULL, 0);
if (server_supports("multi_ack")) {
@@ -381,40 +379,22 @@
}
if (find_common(fd, sha1, ref) < 0)
fprintf(stderr, "warning: no common commits\n");
- pid = fork();
- if (pid < 0)
- die("git-fetch-pack: unable to fork off git-unpack-objects");
- if (!pid) {
- dup2(fd[0], 0);
- close(fd[0]);
- close(fd[1]);
- execlp("git-unpack-objects", "git-unpack-objects",
- quiet ? "-q" : NULL, NULL);
- die("git-unpack-objects exec failed");
+
+ if (keep_pack)
+ status = receive_keep_pack(fd, "git-fetch-pack");
+ else
+ status = receive_unpack_pack(fd, "git-fetch-pack", quiet);
+
+ if (status)
+ die("git-fetch-pack: fetch failed.");
+
+ all_done:
+ while (ref) {
+ printf("%s %s\n",
+ sha1_to_hex(ref->old_sha1), ref->name);
+ ref = ref->next;
}
- close(fd[0]);
- close(fd[1]);
- while (waitpid(pid, &status, 0) < 0) {
- if (errno != EINTR)
- die("waiting for git-unpack-objects: %s", strerror(errno));
- }
- if (WIFEXITED(status)) {
- int code = WEXITSTATUS(status);
- if (code)
- die("git-unpack-objects died with error code %d", code);
-all_done:
- while (ref) {
- printf("%s %s\n",
- sha1_to_hex(ref->old_sha1), ref->name);
- ref = ref->next;
- }
- return 0;
- }
- if (WIFSIGNALED(status)) {
- int sig = WTERMSIG(status);
- die("git-unpack-objects died of signal %d", sig);
- }
- die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status);
+ return 0;
}
int main(int argc, char **argv)
@@ -436,10 +416,14 @@
exec = arg + 7;
continue;
}
- if (!strcmp("-q", arg)) {
+ if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) {
quiet = 1;
continue;
}
+ if (!strcmp("--keep", arg) || !strcmp("-k", arg)) {
+ keep_pack = 1;
+ continue;
+ }
if (!strcmp("-v", arg)) {
verbose = 1;
continue;
diff --git a/git-am.sh b/git-am.sh
index 1a114bc..731ab1ff 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -211,6 +211,7 @@
if test "$skip" = t
then
this=`expr "$this" + 1`
+ resume=
fi
if test "$this" -gt "$last"
@@ -225,6 +226,7 @@
msgnum=`printf "%0${prec}d" $this`
next=`expr "$this" + 1`
test -f "$dotest/$msgnum" || {
+ resume=
go_next
continue
}
diff --git a/git-applypatch.sh b/git-applypatch.sh
index e8ba34a..12cab1e 100755
--- a/git-applypatch.sh
+++ b/git-applypatch.sh
@@ -14,7 +14,7 @@
USAGE='<msg> <patch> <info> [<signoff>]'
. git-sh-setup
-case "$#" in 3|4) usage ;; esac
+case "$#" in 3|4) ;; *) usage ;; esac
final=.dotest/final-commit
##
diff --git a/git-archimport.perl b/git-archimport.perl
index aab4e38..841738d 100755
--- a/git-archimport.perl
+++ b/git-archimport.perl
@@ -9,7 +9,8 @@
=head1 Invocation
- git-archimport [ -h ] [ -v ] [ -T ] [ -t tempdir ] <archive>/<branch> [ <archive>/<branch> ]
+ git-archimport [ -h ] [ -v ] [ -o ] [ -a ] [ -f ] [ -T ]
+ [ -D depth] [ -t tempdir ] <archive>/<branch> [ <archive>/<branch> ]
Imports a project from one or more Arch repositories. It will follow branches
and repositories within the namespaces defined by the <archive/branch>
@@ -74,7 +75,7 @@
sub usage() {
print STDERR <<END;
Usage: ${\basename $0} # fetch/update GIT from Arch
- [ -f ] [ -o ] [ -h ] [ -v ] [ -T ] [ -a ] [ -D depth ] [ -t tempdir ]
+ [ -h ] [ -v ] [ -o ] [ -a ] [ -f ] [ -T ] [ -D depth ] [ -t tempdir ]
repository/arch-branch [ repository/arch-branch] ...
END
exit(1);
diff --git a/git-branch.sh b/git-branch.sh
index 0266f462..b0e54ed 100755
--- a/git-branch.sh
+++ b/git-branch.sh
@@ -32,11 +32,11 @@
case " $mbs " in
*' '$branch' '*)
# the merge base of branch and HEAD contains branch --
- # which means that the HEAD contains everything in the HEAD.
+ # which means that the HEAD contains everything in both.
;;
*)
echo >&2 "The branch '$branch_name' is not a strict subset of your current HEAD.
- If you are sure you want to delete it, run 'git branch -D $branch_name'."
+If you are sure you want to delete it, run 'git branch -D $branch_name'."
exit 1
;;
esac
diff --git a/git-checkout.sh b/git-checkout.sh
index f241d4b..36308d2 100755
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -116,7 +116,7 @@
fi
#
-# Switch the HEAD pointer to the new branch if it we
+# Switch the HEAD pointer to the new branch if we
# checked out a branch head, and remove any potential
# old MERGE_HEAD's (subsequent commits will clearly not
# be based on them, since we re-set the index)
diff --git a/git-compat-util.h b/git-compat-util.h
index ead0ede..0c98c99 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -84,6 +84,28 @@
return ret;
}
+static inline ssize_t xread(int fd, void *buf, size_t len)
+{
+ ssize_t nr;
+ while (1) {
+ nr = read(fd, buf, len);
+ if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
+ continue;
+ return nr;
+ }
+}
+
+static inline ssize_t xwrite(int fd, const void *buf, size_t len)
+{
+ ssize_t nr;
+ while (1) {
+ nr = write(fd, buf, len);
+ if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
+ continue;
+ return nr;
+ }
+}
+
/* Sane ctype - no locale, and works with signed chars */
#undef isspace
#undef isdigit
diff --git a/git-diff.sh b/git-diff.sh
index b62e583..4812ae4 100755
--- a/git-diff.sh
+++ b/git-diff.sh
@@ -3,15 +3,14 @@
# Copyright (c) 2005 Linus Torvalds
# Copyright (c) 2005 Junio C Hamano
+USAGE='[ --diff-options ] <ent>{0,2} [<path>...]'
+SUBDIRECTORY_OK='Yes'
+. git-sh-setup
+
rev=$(git-rev-parse --revs-only --no-flags --sq "$@") || exit
flags=$(git-rev-parse --no-revs --flags --sq "$@")
files=$(git-rev-parse --no-revs --no-flags --sq "$@")
-die () {
- echo >&2 "$*"
- exit 1
-}
-
# I often say 'git diff --cached -p' and get scolded by git-diff-files, but
# obviously I mean 'git diff --cached -p HEAD' in that case.
case "$rev" in
@@ -40,8 +39,7 @@
case "$rev" in
?*' '?*' '?*)
- echo >&2 "I don't understand"
- exit 1
+ usage
;;
?*' '^?*)
begin=$(expr "$rev" : '.*^.\([0-9a-f]*\).*') &&
@@ -58,7 +56,7 @@
cmd="git-diff-files $flags -- $files"
;;
*)
- die "I don't understand $*"
+ usage
;;
esac
diff --git a/git-format-patch.sh b/git-format-patch.sh
index 01508e3..daa3cae 100755
--- a/git-format-patch.sh
+++ b/git-format-patch.sh
@@ -210,6 +210,8 @@
}
mailScript="$mailScript"'
+ a\
+
: body
p
n
diff --git a/git-log.sh b/git-log.sh
index b36c4e9..c2ea71c 100755
--- a/git-log.sh
+++ b/git-log.sh
@@ -3,13 +3,13 @@
# Copyright (c) 2005 Linus Torvalds
#
-# This one uses only subdirectory-aware commands, so no need to
-# include sh-setup-script.
+USAGE='[--max-count=<n>] [<since>..<limit>] [--pretty=<format>] [git-rev-list options]'
+SUBDIRECTORY_OK='Yes'
+. git-sh-setup
revs=$(git-rev-parse --revs-only --no-flags --default HEAD "$@") || exit
[ "$revs" ] || {
- echo >&2 "No HEAD ref"
- exit 1
+ die "No HEAD ref"
}
git-rev-list --pretty $(git-rev-parse --default HEAD "$@") |
LESS=-S ${PAGER:-less}
diff --git a/git-octopus.sh b/git-octopus.sh
deleted file mode 100755
index 2edbf52..0000000
--- a/git-octopus.sh
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2005 Junio C Hamano
-#
-# Resolve two or more trees recorded in $GIT_DIR/FETCH_HEAD.
-#
-. git-sh-setup
-
-usage () {
- die "usage: git octopus"
-}
-
-# Sanity check the heads early.
-while read SHA1 REPO
-do
- test $(git-cat-file -t $SHA1) = "commit" ||
- die "$REPO given to octopus is not a commit"
-done <"$GIT_DIR/FETCH_HEAD"
-
-head=$(git-rev-parse --verify HEAD) || exit
-
-git-update-index --refresh ||
- die "Your working tree is dirty."
-test "$(git-diff-index --cached "$head")" = "" ||
- die "Your working tree does not match HEAD."
-
-# MRC is the current "merge reference commit"
-# MRT is the current "merge result tree"
-
-MRC=$head PARENT="-p $head"
-MRT=$(git-write-tree)
-CNT=1 ;# counting our head
-NON_FF_MERGE=0
-while read SHA1 REPO
-do
- common=$(git-merge-base $MRC $SHA1) ||
- die "Unable to find common commit with $SHA1 from $REPO"
-
- if test "$common" = $SHA1
- then
- echo "Already up-to-date: $REPO"
- continue
- fi
-
- CNT=`expr $CNT + 1`
- PARENT="$PARENT -p $SHA1"
-
- if test "$common,$NON_FF_MERGE" = "$MRC,0"
- then
- # The first head being merged was a fast-forward.
- # Advance MRC to the head being merged, and use that
- # tree as the intermediate result of the merge.
- # We still need to count this as part of the parent set.
-
- echo "Fast forwarding to: $REPO"
- git-read-tree -u -m $head $SHA1 || exit
- MRC=$SHA1 MRT=$(git-write-tree)
- continue
- fi
-
- NON_FF_MERGE=1
-
- echo "Trying simple merge with $REPO"
- git-read-tree -u -m $common $MRT $SHA1 || exit
- next=$(git-write-tree 2>/dev/null)
- if test $? -ne 0
- then
- echo "Simple merge did not work, trying automatic merge."
- git-merge-index -o git-merge-one-file -a || {
- git-read-tree --reset "$head"
- git-checkout-index -f -q -u -a
- die "Automatic merge failed; should not be doing Octopus"
- }
- next=$(git-write-tree 2>/dev/null)
- fi
- MRC=$common
- MRT=$next
-done <"$GIT_DIR/FETCH_HEAD"
-
-# Just to be careful in case the user feeds nonsense to us.
-case "$CNT" in
-1)
- echo "No changes."
- exit 0 ;;
-esac
-result_commit=$(git-fmt-merge-msg <"$GIT_DIR/FETCH_HEAD" |
- git-commit-tree $MRT $PARENT)
-echo "Committed merge $result_commit"
-git-update-ref HEAD $result_commit $head
-git-diff-tree -p $head $result_commit | git-apply --stat
diff --git a/git-svnimport.perl b/git-svnimport.perl
index 65868a9..cb241d1 100755
--- a/git-svnimport.perl
+++ b/git-svnimport.perl
@@ -736,6 +736,13 @@
}
$opt_l = $svn->{'maxrev'} if not defined $opt_l or $opt_l > $svn->{'maxrev'};
+
+if ($svn->{'maxrev'} < $current_rev) {
+ print "Up to date: no new revisions to fetch!\n" if $opt_v;
+ unlink("$git_dir/SVN2GIT_HEAD");
+ exit;
+}
+
print "Fetching from $current_rev to $opt_l ...\n" if $opt_v;
my $pool=SVN::Pool->new;
diff --git a/git-whatchanged.sh b/git-whatchanged.sh
index 85a49fc..b170f74 100755
--- a/git-whatchanged.sh
+++ b/git-whatchanged.sh
@@ -1,4 +1,9 @@
#!/bin/sh
+
+USAGE='[-p] [--max-count=<n>] [<since>..<limit>] [--pretty=<format>] [-m] [git-diff-tree options] [git-rev-list options]'
+SUBDIRECTORY_OK='Yes'
+. git-sh-setup
+
rev_list_args=$(git-rev-parse --sq --default HEAD --revs-only "$@") &&
diff_tree_args=$(git-rev-parse --sq --no-revs "$@") &&
diff --git a/git.c b/git.c
index c26cac6..0fd95bf 100644
--- a/git.c
+++ b/git.c
@@ -8,6 +8,7 @@
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
+#include <sys/ioctl.h>
#include "git-compat-util.h"
#ifndef PATH_MAX
@@ -26,6 +27,16 @@
if (col_string && (n_cols = atoi(col_string)) > 0)
return n_cols;
+#ifdef TIOCGWINSZ
+ {
+ struct winsize ws;
+ if (!ioctl(1, TIOCGWINSZ, &ws)) {
+ if (ws.ws_col)
+ return ws.ws_col;
+ }
+ }
+#endif
+
return 80;
}
@@ -74,25 +85,28 @@
static void pretty_print_string_list(struct cmdname **cmdname, int longest)
{
- int cols = 1;
+ int cols = 1, rows;
int space = longest + 1; /* min 1 SP between words */
int max_cols = term_columns() - 1; /* don't print *on* the edge */
- int i;
+ int i, j;
if (space < max_cols)
cols = max_cols / space;
+ rows = (cmdname_cnt + cols - 1) / cols;
qsort(cmdname, cmdname_cnt, sizeof(*cmdname), cmdname_compare);
- for (i = 0; i < cmdname_cnt; ) {
- int c;
+ for (i = 0; i < rows; i++) {
printf(" ");
- for (c = cols; c && i < cmdname_cnt; i++) {
- printf("%s", cmdname[i]->name);
-
- if (--c)
- mput_char(' ', space - cmdname[i]->len);
+ for (j = 0; j < cols; j++) {
+ int n = j * rows + i;
+ int size = space;
+ if (n >= cmdname_cnt)
+ break;
+ if (j == cols-1 || n + rows >= cmdname_cnt)
+ size = 1;
+ printf("%-*s", size, cmdname[n]->name);
}
putchar('\n');
}
diff --git a/mktag.c b/mktag.c
index 97e270a..fc6a9bf 100644
--- a/mktag.c
+++ b/mktag.c
@@ -116,14 +116,9 @@
// Read the signature
size = 0;
for (;;) {
- int ret = read(0, buffer + size, MAXSIZE - size);
- if (!ret)
+ int ret = xread(0, buffer + size, MAXSIZE - size);
+ if (ret <= 0)
break;
- if (ret < 0) {
- if (errno == EAGAIN)
- continue;
- break;
- }
size += ret;
}
diff --git a/pkt-line.c b/pkt-line.c
index 6947304..bb3bab0 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -19,7 +19,7 @@
static void safe_write(int fd, const void *buf, unsigned n)
{
while (n) {
- int ret = write(fd, buf, n);
+ int ret = xwrite(fd, buf, n);
if (ret > 0) {
buf += ret;
n -= ret;
@@ -27,8 +27,6 @@
}
if (!ret)
die("write error (disk full?)");
- if (errno == EAGAIN || errno == EINTR)
- continue;
die("write error (%s)", strerror(errno));
}
}
@@ -68,12 +66,9 @@
int n = 0;
while (n < size) {
- int ret = read(fd, buffer + n, size - n);
- if (ret < 0) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
+ int ret = xread(fd, buffer + n, size - n);
+ if (ret < 0)
die("read error (%s)", strerror(errno));
- }
if (!ret)
die("unexpected EOF");
n += ret;
diff --git a/read-cache.c b/read-cache.c
index 6932736..c5474d4 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -6,6 +6,7 @@
#include "cache.h"
struct cache_entry **active_cache = NULL;
+static time_t index_file_timestamp;
unsigned int active_nr = 0, active_alloc = 0, active_cache_changed = 0;
/*
@@ -28,7 +29,65 @@
ce->ce_size = htonl(st->st_size);
}
-int ce_match_stat(struct cache_entry *ce, struct stat *st)
+static int ce_compare_data(struct cache_entry *ce, struct stat *st)
+{
+ int match = -1;
+ int fd = open(ce->name, O_RDONLY);
+
+ if (fd >= 0) {
+ unsigned char sha1[20];
+ if (!index_fd(sha1, fd, st, 0, NULL))
+ match = memcmp(sha1, ce->sha1, 20);
+ close(fd);
+ }
+ return match;
+}
+
+static int ce_compare_link(struct cache_entry *ce, unsigned long expected_size)
+{
+ int match = -1;
+ char *target;
+ void *buffer;
+ unsigned long size;
+ char type[10];
+ int len;
+
+ target = xmalloc(expected_size);
+ len = readlink(ce->name, target, expected_size);
+ if (len != expected_size) {
+ free(target);
+ return -1;
+ }
+ buffer = read_sha1_file(ce->sha1, type, &size);
+ if (!buffer) {
+ free(target);
+ return -1;
+ }
+ if (size == expected_size)
+ match = memcmp(buffer, target, size);
+ free(buffer);
+ free(target);
+ return match;
+}
+
+static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st)
+{
+ switch (st->st_mode & S_IFMT) {
+ case S_IFREG:
+ if (ce_compare_data(ce, st))
+ return DATA_CHANGED;
+ break;
+ case S_IFLNK:
+ if (ce_compare_link(ce, st->st_size))
+ return DATA_CHANGED;
+ break;
+ default:
+ return TYPE_CHANGED;
+ }
+ return 0;
+}
+
+static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
{
unsigned int changed = 0;
@@ -83,57 +142,44 @@
if (ce->ce_size != htonl(st->st_size))
changed |= DATA_CHANGED;
+
return changed;
}
-static int ce_compare_data(struct cache_entry *ce, struct stat *st)
+int ce_match_stat(struct cache_entry *ce, struct stat *st)
{
- int match = -1;
- int fd = open(ce->name, O_RDONLY);
+ unsigned int changed = ce_match_stat_basic(ce, st);
- if (fd >= 0) {
- unsigned char sha1[20];
- if (!index_fd(sha1, fd, st, 0, NULL))
- match = memcmp(sha1, ce->sha1, 20);
- close(fd);
- }
- return match;
-}
+ /*
+ * Within 1 second of this sequence:
+ * echo xyzzy >file && git-update-index --add file
+ * running this command:
+ * echo frotz >file
+ * would give a falsely clean cache entry. The mtime and
+ * length match the cache, and other stat fields do not change.
+ *
+ * We could detect this at update-index time (the cache entry
+ * being registered/updated records the same time as "now")
+ * and delay the return from git-update-index, but that would
+ * effectively mean we can make at most one commit per second,
+ * which is not acceptable. Instead, we check cache entries
+ * whose mtime are the same as the index file timestamp more
+ * careful than others.
+ */
+ if (!changed &&
+ index_file_timestamp &&
+ index_file_timestamp <= ntohl(ce->ce_mtime.sec))
+ changed |= ce_modified_check_fs(ce, st);
-static int ce_compare_link(struct cache_entry *ce, unsigned long expected_size)
-{
- int match = -1;
- char *target;
- void *buffer;
- unsigned long size;
- char type[10];
- int len;
-
- target = xmalloc(expected_size);
- len = readlink(ce->name, target, expected_size);
- if (len != expected_size) {
- free(target);
- return -1;
- }
- buffer = read_sha1_file(ce->sha1, type, &size);
- if (!buffer) {
- free(target);
- return -1;
- }
- if (size == expected_size)
- match = memcmp(buffer, target, size);
- free(buffer);
- free(target);
- return match;
+ return changed;
}
int ce_modified(struct cache_entry *ce, struct stat *st)
{
- int changed;
+ int changed, changed_fs;
changed = ce_match_stat(ce, st);
if (!changed)
return 0;
-
/*
* If the mode or type has changed, there's no point in trying
* to refresh the entry - it's not going to match
@@ -148,18 +194,9 @@
if ((changed & DATA_CHANGED) && ce->ce_size != htonl(0))
return changed;
- switch (st->st_mode & S_IFMT) {
- case S_IFREG:
- if (ce_compare_data(ce, st))
- return changed | DATA_CHANGED;
- break;
- case S_IFLNK:
- if (ce_compare_link(ce, st->st_size))
- return changed | DATA_CHANGED;
- break;
- default:
- return changed | TYPE_CHANGED;
- }
+ changed_fs = ce_modified_check_fs(ce, st);
+ if (changed_fs)
+ return changed | changed_fs;
return 0;
}
@@ -471,6 +508,7 @@
return active_nr;
errno = ENOENT;
+ index_file_timestamp = 0;
fd = open(get_index_file(), O_RDONLY);
if (fd < 0) {
if (errno == ENOENT)
@@ -504,6 +542,7 @@
offset = offset + ce_size(ce);
active_cache[i] = ce;
}
+ index_file_timestamp = st.st_mtime;
return active_nr;
unmap:
@@ -562,6 +601,50 @@
return 0;
}
+static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
+{
+ /*
+ * The only thing we care about in this function is to smudge the
+ * falsely clean entry due to touch-update-touch race, so we leave
+ * everything else as they are. We are called for entries whose
+ * ce_mtime match the index file mtime.
+ */
+ struct stat st;
+
+ if (lstat(ce->name, &st) < 0)
+ return;
+ if (ce_match_stat_basic(ce, &st))
+ return;
+ if (ce_modified_check_fs(ce, &st)) {
+ /* This is "racily clean"; smudge it. Note that this
+ * is a tricky code. At first glance, it may appear
+ * that it can break with this sequence:
+ *
+ * $ echo xyzzy >frotz
+ * $ git-update-index --add frotz
+ * $ : >frotz
+ * $ sleep 3
+ * $ echo filfre >nitfol
+ * $ git-update-index --add nitfol
+ *
+ * but it does not. Whe the second update-index runs,
+ * it notices that the entry "frotz" has the same timestamp
+ * as index, and if we were to smudge it by resetting its
+ * size to zero here, then the object name recorded
+ * in index is the 6-byte file but the cached stat information
+ * becomes zero --- which would then match what we would
+ * obtain from the filesystem next time we stat("frotz").
+ *
+ * However, the second update-index, before calling
+ * this function, notices that the cached size is 6
+ * bytes and what is on the filesystem is an empty
+ * file, and never calls us, so the cached size information
+ * for "frotz" stays 6 which does not match the filesystem.
+ */
+ ce->ce_size = htonl(0);
+ }
+}
+
int write_cache(int newfd, struct cache_entry **cache, int entries)
{
SHA_CTX c;
@@ -584,6 +667,9 @@
struct cache_entry *ce = cache[i];
if (!ce->ce_mode)
continue;
+ if (index_file_timestamp &&
+ index_file_timestamp <= ntohl(ce->ce_mtime.sec))
+ ce_smudge_racily_clean_entry(ce);
if (ce_write(&c, newfd, ce, ce_size(ce)) < 0)
return -1;
}
diff --git a/refs.c b/refs.c
index d2aec73..c33729c 100644
--- a/refs.c
+++ b/refs.c
@@ -313,7 +313,9 @@
static inline int bad_ref_char(int ch)
{
return (((unsigned) ch) <= ' ' ||
- ch == '~' || ch == '^' || ch == ':');
+ ch == '~' || ch == '^' || ch == ':' ||
+ /* 2.13 Pattern Matching Notation */
+ ch == '?' || ch == '*' || ch == '[');
}
int check_ref_format(const char *ref)
diff --git a/rev-list.c b/rev-list.c
index 8020d97..d060966 100644
--- a/rev-list.c
+++ b/rev-list.c
@@ -850,7 +850,8 @@
handle_one_commit(commit, &list);
}
- if (!list)
+ if (!list &&
+ (!(tag_objects||tree_objects||blob_objects) && !pending_objects))
usage(rev_list_usage);
paths = get_pathspec(prefix, argv + i);
diff --git a/send-pack.c b/send-pack.c
index 6ce0d9f..a41bbe5 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -8,6 +8,7 @@
"git-send-pack [--all] [--exec=git-receive-pack] <remote> [<head>...]\n"
" --all and explicit <head> specification are mutually exclusive.";
static const char *exec = "git-receive-pack";
+static int verbose = 0;
static int send_all = 0;
static int force_update = 0;
@@ -206,7 +207,8 @@
if (!ref->peer_ref)
continue;
if (!memcmp(ref->old_sha1, ref->peer_ref->new_sha1, 20)) {
- fprintf(stderr, "'%s': up-to-date\n", ref->name);
+ if (verbose)
+ fprintf(stderr, "'%s': up-to-date\n", ref->name);
continue;
}
@@ -270,6 +272,8 @@
packet_flush(out);
if (new_refs)
pack_objects(out, remote_refs);
+ else
+ fprintf(stderr, "Everything up-to-date\n");
close(out);
return ret;
}
@@ -301,6 +305,10 @@
force_update = 1;
continue;
}
+ if (!strcmp(arg, "--verbose")) {
+ verbose = 1;
+ continue;
+ }
usage(send_pack_usage);
}
if (!dest) {
diff --git a/sha1_name.c b/sha1_name.c
index faac158..b13ed78 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -188,7 +188,10 @@
{
int status;
static char hex[41];
+
memcpy(hex, sha1_to_hex(sha1), 40);
+ if (len == 40)
+ return hex;
while (len < 40) {
unsigned char sha1_ret[20];
status = get_short_sha1(hex, len, sha1_ret, 1);
@@ -203,11 +206,12 @@
return NULL;
}
-static int ambiguous_path(const char *path)
+static int ambiguous_path(const char *path, int len)
{
int slash = 1;
+ int cnt;
- for (;;) {
+ for (cnt = 0; cnt < len; cnt++) {
switch (*path++) {
case '\0':
break;
@@ -222,8 +226,9 @@
slash = 0;
continue;
}
- return slash;
+ break;
}
+ return slash;
}
static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
@@ -236,31 +241,19 @@
NULL
};
const char **p;
- int found = 0;
if (len == 40 && !get_sha1_hex(str, sha1))
return 0;
/* Accept only unambiguous ref paths. */
- if (ambiguous_path(str))
+ if (ambiguous_path(str, len))
return -1;
for (p = prefix; *p; p++) {
char *pathname = git_path("%s/%.*s", *p, len, str);
- if (!read_ref(pathname, sha1)) {
- /* Must be unique; i.e. when heads/foo and
- * tags/foo are both present, reject "foo".
- * Note that read_ref() eventually calls
- * get_sha1_hex() which can smudge initial
- * part of the buffer even if what is read
- * is found to be invalid halfway.
- */
- if (1 < found++)
- return -1;
- }
+ if (!read_ref(pathname, sha1))
+ return 0;
}
- if (found == 1)
- return 0;
return -1;
}
diff --git a/show-branch.c b/show-branch.c
index ab158eb..c742246 100644
--- a/show-branch.c
+++ b/show-branch.c
@@ -450,6 +450,8 @@
if (saved_matches == ref_name_cnt &&
ref_name_cnt < MAX_REVS)
error("no matching refs with %s", av);
+ if (saved_matches + 1 < ref_name_cnt)
+ sort_ref_range(saved_matches, ref_name_cnt);
return;
}
die("bad sha1 reference %s", av);
diff --git a/t/t0010-racy-git.sh b/t/t0010-racy-git.sh
new file mode 100755
index 0000000..e45a9e4
--- /dev/null
+++ b/t/t0010-racy-git.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+test_description='racy GIT'
+
+. ./test-lib.sh
+
+# This test can give false success if your machine is sufficiently
+# slow or your trial happened to happen on second boundary.
+
+for trial in 0 1 2 3 4
+do
+ rm -f .git/index
+ echo frotz >infocom
+ git update-index --add infocom
+ echo xyzzy >infocom
+
+ files=`git diff-files -p`
+ test_expect_success \
+ "Racy GIT trial #$trial part A" \
+ 'test "" != "$files"'
+
+ sleep 1
+ echo xyzzy >cornerstone
+ git update-index --add cornerstone
+
+ files=`git diff-files -p`
+ test_expect_success \
+ "Racy GIT trial #$trial part B" \
+ 'test "" != "$files"'
+
+done
+
+test_done
diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh
old mode 100644
new mode 100755
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
old mode 100644
new mode 100755
diff --git a/t/t3101-ls-tree-dirname.sh b/t/t3101-ls-tree-dirname.sh
old mode 100644
new mode 100755
diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh
old mode 100644
new mode 100755
diff --git a/t/t4109-apply-multifrag.sh b/t/t4109-apply-multifrag.sh
old mode 100644
new mode 100755
diff --git a/t/t4110-apply-scan.sh b/t/t4110-apply-scan.sh
old mode 100644
new mode 100755
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
old mode 100644
new mode 100755
diff --git a/t/t6101-rev-parse-parents.sh b/t/t6101-rev-parse-parents.sh
old mode 100644
new mode 100755
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 2819bef..a97d259 100755
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -18,6 +18,7 @@
unset GIT_AUTHOR_DATE
unset GIT_AUTHOR_EMAIL
unset GIT_AUTHOR_NAME
+unset GIT_COMMITTER_DATE
unset GIT_COMMITTER_EMAIL
unset GIT_COMMITTER_NAME
unset GIT_DIFF_OPTS
diff --git a/tar-tree.c b/tar-tree.c
index bacb23a..96bd143 100644
--- a/tar-tree.c
+++ b/tar-tree.c
@@ -34,10 +34,8 @@
static void reliable_write(void *buf, unsigned long size)
{
while (size > 0) {
- long ret = write(1, buf, size);
+ long ret = xwrite(1, buf, size);
if (ret < 0) {
- if (errno == EAGAIN)
- continue;
if (errno == EPIPE)
exit(0);
die("git-tar-tree: %s", strerror(errno));
diff --git a/unpack-objects.c b/unpack-objects.c
index cfd61ae..5c5cb12 100644
--- a/unpack-objects.c
+++ b/unpack-objects.c
@@ -31,12 +31,10 @@
offset = 0;
}
do {
- int ret = read(0, buffer + len, sizeof(buffer) - len);
+ int ret = xread(0, buffer + len, sizeof(buffer) - len);
if (ret <= 0) {
if (!ret)
die("early EOF");
- if (errno == EAGAIN || errno == EINTR)
- continue;
die("read error on input: %s", strerror(errno));
}
len += ret;
@@ -299,14 +297,9 @@
/* Write the last part of the buffer to stdout */
while (len) {
- int ret = write(1, buffer + offset, len);
- if (!ret)
+ int ret = xwrite(1, buffer + offset, len);
+ if (ret <= 0)
break;
- if (ret < 0) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- break;
- }
len -= ret;
offset += ret;
}