diff --git a/Documentation/cvs-migration.txt b/Documentation/cvs-migration.txt index 7c4dbef008..4361278dab 100644 --- a/Documentation/cvs-migration.txt +++ b/Documentation/cvs-migration.txt @@ -24,7 +24,7 @@ The good news is that most people don't do that, and in fact most sane people think it's a bug in CVS that makes it tag (and check in changes) one file at a time. So most projects you'll ever see will use CVS 'as if' it was sane. In which case you'll find it very easy indeed to -move over to Git. +move over to git. First off: this is not a git tutorial. See link:tutorial.html[Documentation/tutorial.txt] for how git @@ -229,7 +229,7 @@ does rename or copy would not show in the output, and if the "o-file.c", it would find the commit that changed the statement when it was in "o-file.c". -NOTE: The current versions of "git-diff-tree -C" is not eager +NOTE: The current version of "git-diff-tree -C" is not eager enough to find copies, and it will miss the fact that a-file.c was created by copying o-file.c unless o-file.c was somehow changed in the same commit. diff --git a/Documentation/diff-format.txt b/Documentation/diff-format.txt index 6e9fa8cdb7..dacd8fb534 100644 --- a/Documentation/diff-format.txt +++ b/Documentation/diff-format.txt @@ -1,8 +1,8 @@ The output format from "git-diff-index", "git-diff-tree" and "git-diff-files" are very similar. -These commands all compare two sets of things; what are -compared are different: +These commands all compare two sets of things; what is +compared differs: git-diff-index :: compares the and the files on the filesystem. @@ -46,7 +46,7 @@ That is, from the left to the right: . path for "dst"; only exists for C or R. . an LF or a NUL when '-z' option is used, to terminate the record. - is shown as all 0's if new is a file on the filesystem + is shown as all 0's if a file is new on the filesystem and it is out of sync with the cache. Example: @@ -91,7 +91,7 @@ For a path that is added, removed, or modified, where: -file:: are files GIT_EXTERNAL_DIFF can use to read the - contents of , + contents of , -hex:: are the 40-hexdigit SHA1 hashes, -mode:: are the octal representation of the file modes. @@ -121,12 +121,11 @@ The `a/` and `b/` filenames are the same unless rename/copy is involved. Especially, even for a creation or a deletion, `/dev/null` is _not_ used in place of `a/` or `b/` filenames. + -When rename/copy is involved, `file1` and `file2` shows the +When rename/copy is involved, `file1` and `file2` show the name of the source file of the rename/copy and the name of the file that rename/copy produces, respectively. -2. It is followed by extended header lines that are one or - more of: +2. It is followed by one or more extended header lines: old mode new mode diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 613a60d601..06500d04b7 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -5,9 +5,8 @@ Synonym for "-p". -r:: - Look recursively in subdirectories; this flag does not - mean anything to commands other than "git-diff-tree"; - other diff commands always look at all the subdirectories. + Look recursively in subdirectories; only used by "git-diff-tree"; + other diff commands always work recursively. -z:: \0 line termination on output @@ -28,26 +27,26 @@ Detect copies as well as renames. --find-copies-harder:: - By default, -C option finds copies only if the original - file of the copy was modified in the same changeset for - performance reasons. This flag makes the command + For performance reasons, by default, -C option finds copies only + if the original file of the copy was modified in the same + changeset. This flag makes the command inspect unmodified files as candidates for the source of copy. This is a very expensive operation for large projects, so use it with caution. -l:: -M and -C options require O(n^2) processing time where n - in the number of potential rename/copy targets. This + is the number of potential rename/copy targets. This option prevents rename/copy detection from running if - the number of rename/copy targets exceed the specified + the number of rename/copy targets exceeds the specified number. -S:: - Look for differences that contains the change in . + Look for differences that contain the change in . --pickaxe-all:: When -S finds a change, show all the changes in that - changeset, not just the files that contains the change + changeset, not just the files that contain the change in . -O:: diff --git a/Documentation/diffcore.txt b/Documentation/diffcore.txt index a1f03df8f1..9d20a4ff19 100644 --- a/Documentation/diffcore.txt +++ b/Documentation/diffcore.txt @@ -177,7 +177,7 @@ diffcore-merge-broken --------------------- This transformation is used to merge filepairs broken by -diffcore-break, and were not transformed into rename/copy by +diffcore-break, and not transformed into rename/copy by diffcore-rename, back into a single modification. This always runs when diffcore-break is used. @@ -206,10 +206,10 @@ like these: * -B/60 (the same as above, since diffcore-break defaults to 50%). Note that earlier implementation left a broken pair as a separate -creation and deletion patches. This was unnecessary hack and +creation and deletion patches. This was an unnecessary hack and the latest implementation always merges all the broken pairs back into modifications, but the resulting patch output is -formatted differently to still let the reviewing easier for such +formatted differently for easier review in case of such a complete rewrite by showing the entire contents of old version prefixed with '-', followed by the entire contents of new version prefixed with '+'. diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt index ae1ea762f5..4a03b4cfc6 100644 --- a/Documentation/git-add.txt +++ b/Documentation/git-add.txt @@ -11,7 +11,7 @@ SYNOPSIS DESCRIPTION ----------- -A simple wrapper to git-update-index to add files to the cache for people used +A simple wrapper for git-update-index to add files to the cache for people used to do "cvs add". OPTIONS diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt index 4f7e1195de..8cbbb4b853 100644 --- a/Documentation/git-apply.txt +++ b/Documentation/git-apply.txt @@ -13,7 +13,7 @@ SYNOPSIS DESCRIPTION ----------- -Reads supplied diff output and applies it on a GIT index file +Reads supplied diff output and applies it on a git index file and a work tree. OPTIONS diff --git a/Documentation/git-applymbox.txt b/Documentation/git-applymbox.txt index 5022643ad1..bb543788c0 100644 --- a/Documentation/git-applymbox.txt +++ b/Documentation/git-applymbox.txt @@ -22,7 +22,7 @@ OPTIONS -q:: Apply patches interactively. The user will be given opportunity to edit the log message and the patch before - attempting to apply patch in each e-mail message. + attempting to apply it. -k:: Usually the program 'cleans up' the Subject: header line diff --git a/Documentation/git-archimport.txt b/Documentation/git-archimport.txt index 6054731741..b6793cf55e 100644 --- a/Documentation/git-archimport.txt +++ b/Documentation/git-archimport.txt @@ -20,20 +20,23 @@ it will just import it as a regular commit. If it can find it, it will mark it as a merge whenever possible (see discussion below). The script expects you to provide the key roots where it can start the import -from an 'initial import' or 'tag' type of Arch commit. It will follow and import -new branches within the provided roots. +from an 'initial import' or 'tag' type of Arch commit. It will follow and +import new branches within the provided roots. It expects to be dealing with one project only. If it sees -branches that have different roots, it will refuse to run. In that case, edit your - parameters to define clearly the scope of the import. +branches that have different roots, it will refuse to run. In that case, +edit your parameters to define clearly the scope of the +import. -`git-archimport` uses `tla` extensively in the background to access the Arch repository. +`git-archimport` uses `tla` extensively in the background to access the +Arch repository. Make sure you have a recent version of `tla` available in the path. `tla` must know about the repositories you pass to `git-archimport`. For the initial import `git-archimport` expects to find itself in an empty directory. To follow the development of a project that uses Arch, rerun -`git-archimport` with the same parameters as the initial import to perform incremental imports. +`git-archimport` with the same parameters as the initial import to perform +incremental imports. MERGES ------ diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt index ede06dac36..39fa665d9d 100644 --- a/Documentation/git-bisect.txt +++ b/Documentation/git-bisect.txt @@ -76,7 +76,7 @@ During the bisection process, you can say to see the currently remaining suspects in `gitk`. -The good/bad you told the command is logged, and `git bisect +The good/bad input is logged, and `git bisect log` shows what you have done so far. You can truncate its output somewhere and save it in a file, and run diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index a2a0cfb7be..a7121a4c63 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -23,7 +23,7 @@ OPTIONS The name of the branch to create. start-point:: - Where to make the branch; defaults to HEAD. + Where to create the branch; defaults to HEAD. Author ------ diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt index 44983b692d..f21a6e06aa 100644 --- a/Documentation/git-cat-file.txt +++ b/Documentation/git-cat-file.txt @@ -32,7 +32,7 @@ OPTIONS :: Typically this matches the real type of but asking - for a type that can trivially dereferenced from the given + for a type that can trivially be dereferenced from the given is also permitted. An example is to ask for a "tree" with being a commit object that contains it, or to ask for a "blob" with being a tag object that diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt index cd5b97d62c..8462e06853 100644 --- a/Documentation/git-cherry-pick.txt +++ b/Documentation/git-cherry-pick.txt @@ -22,7 +22,7 @@ OPTIONS Commit to cherry-pick. -r:: - Usuall the command appends which commit was + Usually the command appends which commit was cherry-picked after the original commit message when making a commit. This option, '--replay', causes it to use the original commit message intact. This is useful diff --git a/Documentation/git-clone-pack.txt b/Documentation/git-clone-pack.txt index 83d17a055f..a7868e53d7 100644 --- a/Documentation/git-clone-pack.txt +++ b/Documentation/git-clone-pack.txt @@ -26,8 +26,8 @@ OPTIONS --exec=:: Use this to specify the path to 'git-upload-pack' on the - remote side, if is not found on your $PATH. - Installations of sshd ignores the user's environment + remote side, if it is not found on your $PATH. + Installations of sshd ignore the user's environment setup scripts for login shells (e.g. .bash_profile) and your privately installed GIT may not be found on the system default $PATH. Another workaround suggested is to set diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt index 895f733648..9aba868fa4 100644 --- a/Documentation/git-commit-tree.txt +++ b/Documentation/git-commit-tree.txt @@ -36,7 +36,7 @@ OPTIONS An existing tree object -p :: - Each '-p' indicates a the id of a parent commit object. + Each '-p' indicates the id of a parent commit object. Commit Information diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt new file mode 100644 index 0000000000..a851ae24c4 --- /dev/null +++ b/Documentation/git-symbolic-ref.txt @@ -0,0 +1,52 @@ +git-symbolic-ref(1) +=================== + +NAME +---- +git-symbolic-ref - read and modify symbolic refs + +SYNOPSIS +-------- +'git-symbolic-ref' [] + +DESCRIPTION +----------- +Given one argument, reads which branch head the given symbolic +ref refers to and outputs its path, relative to the `.git/` +directory. Typically you would give `HEAD` as the +argument to see on which branch your working tree is on. + +Give two arguments, create or update a symbolic ref to +point at the given branch . + +Traditionally, `.git/HEAD` is a symlink pointing at +`refs/heads/master`. When we want to switch to another branch, +we did `ln -sf refs/heads/newbranch .git/HEAD`, and when we want +to find out which branch we are on, we did `readlink .git/HEAD`. +This was fine, and internally that is what still happens by +default, but on platforms that does not have working symlinks, +or that does not have the `readlink(1)` command, this was a bit +cumbersome. On some platforms, `ln -sf` does not even work as +advertised (horrors). + +A symbolic ref can be a regular file that stores a string that +begins with `ref: refs/`. For example, your `.git/HEAD` *can* +be a regular file whose contents is `ref: refs/heads/master`. +This can be used on a filesystem that does not support symbolic +links. Instead of doing `readlink .git/HEAD`, `git-symbolic-ref +HEAD` can be used to find out which branch we are on. To point +the HEAD to `newbranch`, instead of `ln -sf refs/heads/newbranch +.git/HEAD`, `git-symbolic-ref HEAD refs/heads/newbranch` can be +used. + +Currently, .git/HEAD uses a regular file symbolic ref on Cygwin, +and everywhere else it is implemented as a symlink. This can be +changed at compilation time. + +Author +------ +Written by Junio C Hamano + +GIT +--- +Part of the gitlink:git[7] suite diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.txt new file mode 100644 index 0000000000..69715aa061 --- /dev/null +++ b/Documentation/git-update-ref.txt @@ -0,0 +1,58 @@ +git-update-ref(1) +================= + +NAME +---- +git-update-ref - update the object name stored in a ref safely + +SYNOPSIS +-------- +`git-update-ref` [] + +DESCRIPTION +----------- +Given two arguments, stores the in the , possibly +dereferencing the symbolic refs. E.g. `git-update-ref HEAD +` updates the current branch head to the new object. + +Given three arguments, stores the in the , +possibly dereferencing the symbolic refs, after verifying that +the current value of the matches . +E.g. `git-update-ref refs/heads/master ` +updates the master branch head to only if its current +value is . + +It also allows a "ref" file to be a symbolic pointer to another +ref file by starting with the four-byte header sequence of +"ref:". + +More importantly, it allows the update of a ref file to follow +these symbolic pointers, whether they are symlinks or these +"regular file symbolic refs". It follows *real* symlinks only +if they start with "refs/": otherwise it will just try to read +them and update them as a regular file (i.e. it will allow the +filesystem to follow them, but will overwrite such a symlink to +somewhere else with a regular filename). + +In general, using + + git-update-ref HEAD "$head" + +should be a _lot_ safer than doing + + echo "$head" > "$GIT_DIR/HEAD" + +both from a symlink following standpoint *and* an error checking +standpoint. The "refs/" rule for symlinks means that symlinks +that point to "outside" the tree are safe: they'll be followed +for reading but not for writing (so we'll never write through a +ref symlink to some other tree, if you have copied a whole +archive by creating a symlink tree). + +Author +------ +Written by Linus Torvalds . + +GIT +--- +Part of the gitlink:git[7] suite diff --git a/clone-pack.c b/clone-pack.c index 49820c6579..c102ca885b 100644 --- a/clone-pack.c +++ b/clone-pack.c @@ -51,6 +51,7 @@ static void write_refs(struct ref *ref) struct ref *head = NULL, *head_ptr, *master_ref; char *head_path; + /* Upload-pack must report HEAD first */ if (!strcmp(ref->name, "HEAD")) { head = ref; ref = ref->next; @@ -60,17 +61,21 @@ static void write_refs(struct ref *ref) while (ref) { if (is_master(ref)) master_ref = ref; - if (head && !memcmp(ref->old_sha1, head->old_sha1, 20)) { - if (!head_ptr || ref == master_ref) - head_ptr = ref; - } + if (head && + !memcmp(ref->old_sha1, head->old_sha1, 20) && + !strncmp(ref->name, "refs/heads/",11) && + (!head_ptr || ref == master_ref)) + head_ptr = ref; + write_one_ref(ref); ref = ref->next; } - if (!head) + if (!head) { + fprintf(stderr, "No HEAD in remote.\n"); return; + } - head_path = git_path("HEAD"); + head_path = strdup(git_path("HEAD")); if (!head_ptr) { /* * If we had a master ref, and it wasn't HEAD, we need to undo the @@ -82,6 +87,7 @@ static void write_refs(struct ref *ref) unlink(head_path); } write_one_ref(head); + free(head_path); return; } @@ -89,13 +95,15 @@ static void write_refs(struct ref *ref) if (master_ref) return; + fprintf(stderr, "Setting HEAD to %s\n", head_ptr->name); + /* * Uhhuh. Other end didn't have master. We start HEAD off with * the first branch with the same value. */ - unlink(head_path); - if (symlink(head_ptr->name, head_path) < 0) + if (create_symref(head_path, head_ptr->name) < 0) die("unable to link HEAD to %s", head_ptr->name); + free(head_path); } static int clone_pack(int fd[2], int nr_match, char **match) diff --git a/diff.h b/diff.h index 7f4079c871..2f4a7b463b 100644 --- a/diff.h +++ b/diff.h @@ -103,7 +103,7 @@ extern void diff_flush(struct diff_options*); /* these are not diff-raw status letters proper, but used by * diffcore-filter insn to specify additional restrictions. */ -#define DIFF_STATUS_FILTER_AON 'A' +#define DIFF_STATUS_FILTER_AON '*' #define DIFF_STATUS_FILTER_BROKEN 'B' #endif /* DIFF_H */ diff --git a/git-commit.sh b/git-commit.sh index 1206c20c2e..591fcdceb1 100755 --- a/git-commit.sh +++ b/git-commit.sh @@ -133,10 +133,13 @@ fi | git-stripspace >.editmsg case "$signoff" in t) - git-var GIT_COMMITTER_IDENT | sed -e ' - s/>.*/>/ - s/^/Signed-off-by: / - ' >>.editmsg + { + echo + git-var GIT_COMMITTER_IDENT | sed -e ' + s/>.*/>/ + s/^/Signed-off-by: / + ' + } >>.editmsg ;; esac @@ -195,7 +198,7 @@ else PARENTS="" fi git-status >>.editmsg -if [ "$?" != "0" -a ! -f $GIT_DIR/MERGE_HEAD ] +if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" ] then rm -f .editmsg git-status diff --git a/git-external-diff-script b/git-external-diff-script deleted file mode 100755 index 137280ac72..0000000000 --- a/git-external-diff-script +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/sh -# Copyright (C) 2005 Junio C Hamano -# -# This script is designed to emulate what the built-in diff driver -# does when set as GIT_EXTERNAL_SCRIPT. - -case "$#" in -1) - echo "* Unmerged path $1" - exit 0 ;; -*) - name1="$1" tmp1="$2" hex1="$3" mode1="$4" tmp2="$5" hex2="$6" mode2="$7" - case "$#" in - 7) - name2="$name1" ;; - 9) - name2="$8" xfrm_msg="$9" ;; - esac ;; -esac - -show_create () { - name_="$1" tmp_="$2" hex_="$3" mode_="$4" - echo "diff --git a/$name_ b/$name_" - echo "new file mode $mode_" - diff ${GIT_DIFF_OPTS-'-pu'} -L /dev/null -L "b/$name_" /dev/null "$tmp_" -} - -show_delete () { - name_="$1" tmp_="$2" hex_="$3" mode_="$4" - echo "diff --git a/$name_ b/$name_" - echo "deleted file mode $mode_" - diff ${GIT_DIFF_OPTS-'-pu'} -L "a/$name_" -L /dev/null "$tmp_" /dev/null -} - -case "$mode1" in -120*) type1=l ;; -100*) type1=f ;; -.) show_create "$name2" "$tmp2" "$hex2" "$mode2" - exit 0 ;; -esac -case "$mode2" in -120*) type2=l ;; -100*) type2=f ;; -.) show_delete "$name1" "$tmp1" "$hex1" "$mode1" - exit 0 ;; -esac - -if test "$type1" != "$type2" -then - show_delete "$name1" "$tmp1" "$hex1" "$mode1" - show_create "$name2" "$tmp2" "$hex2" "$mode2" - exit 0 -fi - -echo diff --git "a/$name1" "b/$name2" -if test "$mode1" != "$mode2" -then - echo "old mode $mode1" - echo "new mode $mode2" - if test "$xfrm_msg" != "" - then - echo "$xfrm_msg" - fi -fi -diff ${GIT_DIFF_OPTS-'-pu'} -L "a/$name1" -L "b/$name2" "$tmp1" "$tmp2" -exit 0 - diff --git a/git-fetch.sh b/git-fetch.sh index 61da6a9e31..d3988660ff 100755 --- a/git-fetch.sh +++ b/git-fetch.sh @@ -49,7 +49,7 @@ rsync_slurped_objects= if test "" = "$append" then - : >$GIT_DIR/FETCH_HEAD + : >"$GIT_DIR/FETCH_HEAD" fi append_fetch_head () { @@ -86,11 +86,11 @@ append_fetch_head () { if git-cat-file commit "$head_" >/dev/null 2>&1 then headc_=$(git-rev-parse --verify "$head_^0") || exit - echo "$headc_ $not_for_merge_ $note_" >>$GIT_DIR/FETCH_HEAD + echo "$headc_ $not_for_merge_ $note_" >>"$GIT_DIR/FETCH_HEAD" echo >&2 "* committish: $head_" echo >&2 " $note_" else - echo "$head_ not-for-merge $note_" >>$GIT_DIR/FETCH_HEAD + echo "$head_ not-for-merge $note_" >>"$GIT_DIR/FETCH_HEAD" echo >&2 "* non-commit: $head_" echo >&2 " $note_" fi diff --git a/git-format-patch.sh b/git-format-patch.sh index 525a2f2212..2844799535 100755 --- a/git-format-patch.sh +++ b/git-format-patch.sh @@ -128,10 +128,6 @@ whosepatchScript=' q }' -_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' -_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" -stripCommitHead='/^'"$_x40"' (from '"$_x40"')$/d' - git-cherry -v "$rev1" "$rev2" | while read sign rev comment do @@ -216,7 +212,7 @@ Date: '"$ad" echo git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary echo - git-diff-tree -p $diff_opts "$commit" | sed -e "$stripCommitHead" + git-diff-tree -p $diff_opts "$commit" case "$mbox" in t) diff --git a/index.c b/index.c index bdde65f75c..ad0eafedc2 100644 --- a/index.c +++ b/index.c @@ -22,14 +22,16 @@ static void remove_lock_file_on_signal(int signo) int hold_index_file_for_update(struct cache_file *cf, const char *path) { + int fd; sprintf(cf->lockfile, "%s.lock", path); - cf->next = cache_file_list; - cache_file_list = cf; - if (!cf->next) { + fd = open(cf->lockfile, O_RDWR | O_CREAT | O_EXCL, 0666); + if (fd >=0 && !cf->next) { + cf->next = cache_file_list; + cache_file_list = cf; signal(SIGINT, remove_lock_file_on_signal); atexit(remove_lock_file); } - return open(cf->lockfile, O_RDWR | O_CREAT | O_EXCL, 0666); + return fd; } int commit_index_file(struct cache_file *cf) diff --git a/refs.c b/refs.c index 2aac90ca54..5a8cbd4ef3 100644 --- a/refs.c +++ b/refs.c @@ -46,7 +46,7 @@ int validate_symref(const char *path) len -= 4; while (len && isspace(*buf)) buf++, len--; - if (len >= 5 && !memcmp("refs/", buffer, 5)) + if (len >= 5 && !memcmp("refs/", buf, 5)) return 0; return -1; } diff --git a/rev-list.c b/rev-list.c index 5ec9ccb603..c60aa72957 100644 --- a/rev-list.c +++ b/rev-list.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "refs.h" #include "tag.h" #include "commit.h" #include "tree.h" @@ -489,6 +490,22 @@ static void handle_one_commit(struct commit *com, struct commit_list **lst) commit_list_insert(com, lst); } +/* for_each_ref() callback does not allow user data -- Yuck. */ +static struct commit_list **global_lst; + +static int include_one_commit(const char *path, const unsigned char *sha1) +{ + struct commit *com = get_commit_reference(path, 0); + handle_one_commit(com, global_lst); + return 0; +} + +static void handle_all(struct commit_list **lst) +{ + global_lst = lst; + for_each_ref(include_one_commit); + global_lst = NULL; +} int main(int argc, char **argv) { @@ -542,6 +559,10 @@ int main(int argc, char **argv) bisect_list = 1; continue; } + if (!strcmp(arg, "--all")) { + handle_all(&list); + continue; + } if (!strcmp(arg, "--objects")) { tag_objects = 1; tree_objects = 1; diff --git a/rev-parse.c b/rev-parse.c index 507b531dce..41b9dae429 100644 --- a/rev-parse.c +++ b/rev-parse.c @@ -32,6 +32,7 @@ static int revs_count = 0; static int is_rev_argument(const char *arg) { static const char *rev_args[] = { + "--all", "--bisect", "--header", "--max-age=", diff --git a/upload-pack.c b/upload-pack.c index da10742c44..83f5a35d26 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -30,10 +30,18 @@ static void create_pack_file(void) if (!pid) { int i; - int args = nr_has + nr_needs + 5; - char **argv = xmalloc(args * sizeof(char *)); - char *buf = xmalloc(args * 45); - char **p = argv; + int args; + char **argv; + char *buf; + char **p; + + if (MAX_NEEDS <= nr_needs) + args = nr_has + 10; + else + args = nr_has + nr_needs + 5; + argv = xmalloc(args * sizeof(char *)); + buf = xmalloc(args * 45); + p = argv; dup2(fd[1], 1); close(0); @@ -41,10 +49,14 @@ static void create_pack_file(void) close(fd[1]); *p++ = "git-rev-list"; *p++ = "--objects"; - for (i = 0; i < nr_needs; i++) { - *p++ = buf; - memcpy(buf, sha1_to_hex(needs_sha1[i]), 41); - buf += 41; + if (MAX_NEEDS <= nr_needs) + *p++ = "--all"; + else { + for (i = 0; i < nr_needs; i++) { + *p++ = buf; + memcpy(buf, sha1_to_hex(needs_sha1[i]), 41); + buf += 41; + } } for (i = 0; i < nr_has; i++) { *p++ = buf; @@ -129,18 +141,24 @@ static int receive_needs(void) needs = 0; for (;;) { + unsigned char dummy[20], *sha1_buf; len = packet_read_line(0, line, sizeof(line)); if (!len) return needs; - /* - * This is purely theoretical right now: git-fetch-pack only - * ever asks for a single HEAD - */ - if (needs >= MAX_NEEDS) - die("I'm only doing a max of %d requests", MAX_NEEDS); - if (strncmp("want ", line, 5) || get_sha1_hex(line+5, needs_sha1[needs])) - die("git-upload-pack: protocol error, expected to get sha, not '%s'", line); + sha1_buf = dummy; + if (needs == MAX_NEEDS) { + fprintf(stderr, + "warning: supporting only a max of %d requests. " + "sending everything instead.\n", + MAX_NEEDS); + } + else if (needs < MAX_NEEDS) + sha1_buf = needs_sha1[needs]; + + if (strncmp("want ", line, 5) || get_sha1_hex(line+5, sha1_buf)) + die("git-upload-pack: protocol error, " + "expected to get sha, not '%s'", line); needs++; } }