Merge fixes up to GIT 1.0.5
authorJunio C Hamano <junkio@cox.net>
Tue, 27 Dec 2005 02:45:30 +0000 (18:45 -0800)
committerJunio C Hamano <junkio@cox.net>
Tue, 27 Dec 2005 02:45:30 +0000 (18:45 -0800)
19 files changed:
Documentation/git-clone.txt
Documentation/git-rev-parse.txt
Documentation/tutorial.txt
Makefile
cache.h
connect.c
debian/changelog
environment.c
git-checkout.sh
git-clone.sh
git-merge-recursive.py
git-whatchanged.sh
init-db.c
ls-tree.c
pack-redundant.c
rev-parse.c
setup.c
sha1_file.c
t/t6022-merge-rename.sh

index 8410a6d..f943f26 100644 (file)
@@ -8,7 +8,7 @@ git-clone - Clones a repository.
 
 SYNOPSIS
 --------
-'git-clone' [-l [-s]] [-q] [-n] [-u <upload-pack>] <repository> [<directory>]
+'git-clone' [-l [-s]] [-q] [-n] [-o <name>] [-u <upload-pack>] <repository> [<directory>]
 
 DESCRIPTION
 -----------
@@ -56,6 +56,13 @@ OPTIONS
 -n::
        No checkout of HEAD is performed after the clone is complete.
 
+-o <name>::
+       Instead of using the branch name 'origin' to keep track
+       of the upstream repository, use <name> instead.  Note
+       that the shorthand name stored in `remotes/origin` is
+       not affected, but the local branch name to pull the
+       remote `master` branch into is.
+
 --upload-pack <upload-pack>::
 -u <upload-pack>::
        When given, and the repository to clone from is handled
index 431b8f6..d638bfc 100644 (file)
@@ -68,10 +68,15 @@ OPTIONS
        Show all refs found in `$GIT_DIR/refs`.
 
 --show-prefix::
-       When the command is invoked from a directory show the
+       When the command is invoked from a subdirectory, show the
        path of the current directory relative to the top-level
        directory.
 
+--show-cdup::
+       When the command is invoked from a subdirectory, show the
+       path of the top-level directory relative to the current
+       directory (typically a sequence of "../", or an empty string).
+
 --since=datestring, --after=datestring::
        Parses the date string, and outputs corresponding
        --max-age= parameter for git-rev-list command.
index 3a5c56e..edd91cb 100644 (file)
@@ -1695,6 +1695,24 @@ You still need to create UNIX user accounts for each developer,
 and put them in the same group.  Make sure that the repository
 shared among these developers is writable by that group.
 
+. Initializing the shared repository with `git-init-db --shared`
+helps somewhat.
+
+. Run the following in the shared repository:
++
+------------
+$ chgrp -R $group repo.git
+$ find repo.git -type d -print | xargs chmod ug+rwx,g+s
+$ GIT_DIR=repo.git git repo-config core.sharedrepository true
+------------
+
+The above measures make sure that directories lazily created in
+`$GIT_DIR` are writable by group members.  You, as the
+repository administrator, are still responsible to make sure
+your developers belong to that shared repository group and set
+their umask to a value no stricter than 027 (i.e. at least allow
+reading and searching by group members).
+
 You can implement finer grained branch policies using update
 hooks.  There is a document ("control access to branches") in
 Documentation/howto by Carl Baldwin and JC outlining how to (1)
index a5ca5db..3395a9e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -55,7 +55,7 @@ all:
 # 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 = 1.0.5
+GIT_VERSION = 1.0.GIT
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
diff --git a/cache.h b/cache.h
index cb87bec..a99fb3c 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -159,6 +159,7 @@ extern void rollback_index_file(struct cache_file *);
 extern int trust_executable_bit;
 extern int only_use_symrefs;
 extern int diff_rename_limit_default;
+extern int shared_repository;
 
 #define GIT_REPO_VERSION 0
 extern int repository_format_version;
@@ -183,6 +184,7 @@ extern const unsigned char null_sha1[20];
 
 int git_mkstemp(char *path, size_t n, const char *template);
 
+int adjust_shared_perm(const char *path);
 int safe_create_leading_directories(char *path);
 char *safe_strncpy(char *, const char *, size_t);
 char *enter_repo(char *path, int strict);
index 93f6f80..6b6d613 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -561,7 +561,8 @@ int git_connect(int fd[2], char *url, const char *prog)
 {
        char command[1024];
        char *host, *path = url;
-       char *colon = NULL;
+       char *end;
+       int c;
        int pipefd[2][2];
        pid_t pid;
        enum protocol protocol = PROTO_LOCAL;
@@ -571,15 +572,30 @@ int git_connect(int fd[2], char *url, const char *prog)
                *host = '\0';
                protocol = get_protocol(url);
                host += 3;
-               path = strchr(host, '/');
-       }
-       else {
+               c = '/';
+       } else {
                host = url;
-               if ((colon = strchr(host, ':'))) {
+               c = ':';
+       }
+
+       if (host[0] == '[') {
+               end = strchr(host + 1, ']');
+               if (end) {
+                       *end = 0;
+                       end++;
+                       host++;
+               } else
+                       end = host;
+       } else
+               end = host;
+
+       path = strchr(end, c);
+       if (c == ':') {
+               if (path) {
                        protocol = PROTO_SSH;
-                       *colon = '\0';
-                       path = colon + 1;
-               }
+                       *path++ = '\0';
+               } else
+                       path = host;
        }
 
        if (!path || !*path)
index 88e5755..d7f7591 100644 (file)
@@ -1,3 +1,15 @@
+git-core (1.0.GIT-0) unstable; urgency=low
+
+  * Post GIT 1.0 development track.
+
+ -- Junio C Hamano <junkio@cox.net>  Wed, 21 Dec 2005 22:28:33 -0800
+
+git-core (1.0.0.GIT-0) unstable; urgency=low
+
+  * Post GIT 1.0.0 development track.
+
+ -- Junio C Hamano <junkio@cox.net>  Wed, 21 Dec 2005 12:12:05 -0800
+
 git-core (1.0.4-0) unstable; urgency=low
 
   * GIT 1.0.4.
index 0886ad3..0596fc6 100644 (file)
@@ -15,6 +15,7 @@ int trust_executable_bit = 1;
 int only_use_symrefs = 0;
 int repository_format_version = 0;
 char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
+int shared_repository = 0;
 
 static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
        *git_graft_file;
index 36308d2..3bbd111 100755 (executable)
@@ -1,6 +1,7 @@
 #!/bin/sh
 
 USAGE='[-f] [-b <new_branch>] [<branch>] [<paths>...]'
+SUBDIRECTORY_OK=Sometimes
 . git-sh-setup
 
 old=$(git-rev-parse HEAD)
@@ -79,7 +80,7 @@ then
                # from a specific tree-ish; note that this is for
                # rescuing paths and is never meant to remove what
                # is not in the named tree-ish.
-               git-ls-tree -r "$new" "$@" |
+               git-ls-tree --full-name -r "$new" "$@" |
                git-update-index --index-info || exit $?
        fi
        git-checkout-index -f -u -- "$@"
@@ -95,6 +96,14 @@ else
        fi
 fi
 
+# We are switching branches and checking out trees, so
+# we *NEED* to be at the toplevel.
+cdup=$(git-rev-parse --show-cdup)
+if test ! -z "$cdup"
+then
+       cd "$cdup"
+fi
+
 [ -z "$new" ] && new=$old
 
 # If we don't have an old branch that we're switching to,
index 280cc2e..377d59e 100755 (executable)
@@ -9,7 +9,7 @@
 unset CDPATH
 
 usage() {
-       echo >&2 "Usage: $0 [-l [-s]] [-q] [-u <upload-pack>] [-n] <repo> [<dir>]"
+       echo >&2 "Usage: $0 [-l [-s]] [-q] [-u <upload-pack>] [-o <name>] [-n] <repo> [<dir>]"
        exit 1
 }
 
@@ -31,25 +31,11 @@ clone_dumb_http () {
        cd "$2" &&
        clone_tmp='.git/clone-tmp' &&
        mkdir -p "$clone_tmp" || exit 1
-       http_fetch "$1/info/refs" "$clone_tmp/refs" &&
-       http_fetch "$1/objects/info/packs" "$clone_tmp/packs" || {
+       http_fetch "$1/info/refs" "$clone_tmp/refs" || {
                echo >&2 "Cannot get remote repository information.
 Perhaps git-update-server-info needs to be run there?"
                exit 1;
        }
-       while read type name
-       do
-               case "$type" in
-               P) ;;
-               *) continue ;;
-               esac &&
-
-               idx=`expr "$name" : '\(.*\)\.pack'`.idx
-               http_fetch "$1/objects/pack/$name" ".git/objects/pack/$name" &&
-               http_fetch "$1/objects/pack/$idx" ".git/objects/pack/$idx" &&
-               git-verify-pack ".git/objects/pack/$idx" || exit 1
-       done <"$clone_tmp/packs"
-
        while read sha1 refname
        do
                name=`expr "$refname" : 'refs/\(.*\)'` &&
@@ -67,6 +53,7 @@ use_local=no
 local_shared=no
 no_checkout=
 upload_pack=
+origin=origin
 while
        case "$#,$1" in
        0,*) break ;;
@@ -75,6 +62,14 @@ while
         *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared) 
           local_shared=yes; use_local=yes ;;
        *,-q|*,--quiet) quiet=-q ;;
+       1,-o) usage;;
+       *,-o)
+               git-check-ref-format "$2" || {
+                   echo >&2 "'$2' is not suitable for a branch name"
+                   exit 1
+               }
+               origin="$2"; shift
+               ;;
        1,-u|1,--upload-pack) usage ;;
        *,-u|*,--upload-pack)
                shift
@@ -208,14 +203,14 @@ then
                mkdir -p .git/remotes &&
                echo >.git/remotes/origin \
                "URL: $repo
-Pull: $head_points_at:origin" &&
-               cp ".git/refs/heads/$head_points_at" .git/refs/heads/origin &&
+Pull: $head_points_at:$origin" &&
+               git-update-ref "refs/heads/$origin" $(git-rev-parse HEAD) &&
                find .git/refs/heads -type f -print |
                while read ref
                do
                        head=`expr "$ref" : '.git/refs/heads/\(.*\)'` &&
                        test "$head_points_at" = "$head" ||
-                       test "origin" = "$head" ||
+                       test "$origin" = "$head" ||
                        echo "Pull: ${head}:${head}"
                done >>.git/remotes/origin
        esac
index f1320a6..56c3641 100755 (executable)
@@ -283,12 +283,20 @@ def updateFileExt(sha, mode, path, updateCache, updateWd):
 def setIndexStages(path,
                    oSHA1, oMode,
                    aSHA1, aMode,
-                   bSHA1, bMode):
+                   bSHA1, bMode,
+                   clear=True):
+    istring = []
+    if clear:
+        istring.append("0 " + ("0" * 40) + "\t" + path + "\0")
+    if oMode:
+        istring.append("%o %s %d\t%s\0" % (oMode, oSHA1, 1, path))
+    if aMode:
+        istring.append("%o %s %d\t%s\0" % (aMode, aSHA1, 2, path))
+    if bMode:
+        istring.append("%o %s %d\t%s\0" % (bMode, bSHA1, 3, path))
+
     runProgram(['git-update-index', '-z', '--index-info'],
-               input="0 " + ("0" * 40) + "\t" + path + "\0" + \
-               "%o %s %d\t%s\0" % (oMode, oSHA1, 1, path) + \
-               "%o %s %d\t%s\0" % (aMode, aSHA1, 2, path) + \
-               "%o %s %d\t%s\0" % (bMode, bSHA1, 3, path))
+               input="".join(istring))
 
 def removeFile(clean, path):
     updateCache = cacheOnly or clean
@@ -570,7 +578,7 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
             continue
 
         ren1.processed = True
-        removeFile(True, ren1.srcName)
+
         if ren2:
             # Renamed in 1 and renamed in 2
             assert(ren1.srcName == ren2.srcName)
@@ -598,13 +606,19 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
                            'adding as', dstName2, 'instead.')
                     removeFile(False, ren2.dstName)
                 else:
-                    dstName2 = ren1.dstName
+                    dstName2 = ren2.dstName
+                setIndexStages(dstName1,
+                               None, None,
+                               ren1.dstSha, ren1.dstMode,
+                              None, None)
+                setIndexStages(dstName2,
+                               None, None,
+                               None, None,
+                               ren2.dstSha, ren2.dstMode)
 
-                # NEEDSWORK: place dstNameA at stage 2 and dstNameB at stage 3
-                # What about other stages???
-                updateFile(False, ren1.dstSha, ren1.dstMode, dstName1)
-                updateFile(False, ren2.dstSha, ren2.dstMode, dstName2)
             else:
+                removeFile(True, ren1.srcName)
+
                 [resSha, resMode, clean, merge] = \
                          mergeFile(ren1.srcName, ren1.srcSha, ren1.srcMode,
                                    ren1.dstName, ren1.dstSha, ren1.dstMode,
@@ -630,6 +644,8 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
 
                 updateFile(clean, resSha, resMode, ren1.dstName)
         else:
+            removeFile(True, ren1.srcName)
+
             # Renamed in 1, maybe changed in 2
             if renamesA == renames1:
                 stage = 3
index b170f74..80e2500 100755 (executable)
@@ -4,9 +4,15 @@ USAGE='[-p] [--max-count=<n>] [<since>..<limit>] [--pretty=<format>] [-m] [git-d
 SUBDIRECTORY_OK='Yes'
 . git-sh-setup
 
+diff_tree_flags=$(git-rev-parse --sq --no-revs --flags "$@")
+test -z "$diff_tree_flags" &&
+       diff_tree_flags=$(git-repo-config --get whatchanged.difftree)
+test -z "$diff_tree_flags" &&
+       diff_tree_flags='-M --abbrev'
+
 rev_list_args=$(git-rev-parse --sq --default HEAD --revs-only "$@") &&
-diff_tree_args=$(git-rev-parse --sq --no-revs "$@") &&
+diff_tree_args=$(git-rev-parse --sq --no-revs --no-flags "$@") &&
 
 eval "git-rev-list $rev_list_args" |
-eval "git-diff-tree --stdin --pretty -r $diff_tree_args" |
+eval "git-diff-tree --stdin --pretty -r $diff_tree_flags $diff_tree_args" |
 LESS="$LESS -S" ${PAGER:-less}
index ead37b5..ff29496 100644 (file)
--- a/init-db.c
+++ b/init-db.c
@@ -9,7 +9,7 @@
 #define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates/"
 #endif
 
-static void safe_create_dir(const char *dir)
+static void safe_create_dir(const char *dir, int share)
 {
        if (mkdir(dir, 0777) < 0) {
                if (errno != EEXIST) {
@@ -17,6 +17,8 @@ static void safe_create_dir(const char *dir)
                        exit(1);
                }
        }
+       else if (share && adjust_shared_perm(dir))
+               die("Could not make %s writable by group\n", dir);
 }
 
 static int copy_file(const char *dst, const char *src, int mode)
@@ -32,6 +34,10 @@ static int copy_file(const char *dst, const char *src, int mode)
        }
        status = copy_fd(fdi, fdo);
        close(fdo);
+
+       if (!status && adjust_shared_perm(dst))
+               return -1;
+
        return status;
 }
 
@@ -48,7 +54,7 @@ static void copy_templates_1(char *path, int baselen,
         * with the way the namespace under .git/ is organized, should
         * be really carefully chosen.
         */
-       safe_create_dir(path);
+       safe_create_dir(path, 1);
        while ((de = readdir(dir)) != NULL) {
                struct stat st_git, st_template;
                int namelen;
@@ -176,11 +182,11 @@ static void create_default_files(const char *git_dir, char *template_path)
         * Create .git/refs/{heads,tags}
         */
        strcpy(path + len, "refs");
-       safe_create_dir(path);
+       safe_create_dir(path, 1);
        strcpy(path + len, "refs/heads");
-       safe_create_dir(path);
+       safe_create_dir(path, 1);
        strcpy(path + len, "refs/tags");
-       safe_create_dir(path);
+       safe_create_dir(path, 1);
 
        /* First copy the templates -- we might have the default
         * config file there, in which case we would want to read
@@ -220,7 +226,7 @@ static void create_default_files(const char *git_dir, char *template_path)
 }
 
 static const char init_db_usage[] =
-"git-init-db [--template=<template-directory>]";
+"git-init-db [--template=<template-directory>] [--shared]";
 
 /*
  * If you want to, you can share the DB area with any number of branches.
@@ -239,6 +245,8 @@ int main(int argc, char **argv)
                char *arg = argv[1];
                if (!strncmp(arg, "--template=", 11))
                        template_dir = arg+11;
+               else if (!strcmp(arg, "--shared"))
+                       shared_repository = 1;
                else
                        die(init_db_usage);
        }
@@ -251,7 +259,7 @@ int main(int argc, char **argv)
                git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
                fprintf(stderr, "defaulting to local storage area\n");
        }
-       safe_create_dir(git_dir);
+       safe_create_dir(git_dir, 0);
 
        /* Check to see if the repository version is right.
         * Note that a newly created repository does not have
@@ -270,10 +278,14 @@ int main(int argc, char **argv)
        path = xmalloc(len + 40);
        memcpy(path, sha1_dir, len);
 
-       safe_create_dir(sha1_dir);
+       safe_create_dir(sha1_dir, 1);
        strcpy(path+len, "/pack");
-       safe_create_dir(path);
+       safe_create_dir(path, 1);
        strcpy(path+len, "/info");
-       safe_create_dir(path);
+       safe_create_dir(path, 1);
+
+       if (shared_repository)
+               git_config_set("core.sharedRepository", "true");
+
        return 0;
 }
index dae377d..d585b6f 100644 (file)
--- a/ls-tree.c
+++ b/ls-tree.c
@@ -15,9 +15,11 @@ static int line_termination = '\n';
 #define LS_NAME_ONLY 8
 static int ls_options = 0;
 const char **pathspec;
+static int chomp_prefix = 0;
+static const char *prefix;
 
 static const char ls_tree_usage[] =
-       "git-ls-tree [-d] [-r] [-t] [-z] [--name-only] [--name-status] <tree-ish> [path...]";
+       "git-ls-tree [-d] [-r] [-t] [-z] [--name-only] [--name-status] [--full-name] <tree-ish> [path...]";
 
 static int show_recursive(const char *base, int baselen, const char *pathname)
 {
@@ -49,7 +51,8 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
        }
 }
 
-static int show_tree(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
+static int show_tree(unsigned char *sha1, const char *base, int baselen,
+                    const char *pathname, unsigned mode, int stage)
 {
        int retval = 0;
        const char *type = "blob";
@@ -65,21 +68,28 @@ static int show_tree(unsigned char *sha1, const char *base, int baselen, const c
        else if (ls_options & LS_TREE_ONLY)
                return 0;
 
+       if (chomp_prefix &&
+           (baselen < chomp_prefix || memcmp(prefix, base, chomp_prefix)))
+               return 0;
+
        if (!(ls_options & LS_NAME_ONLY))
                printf("%06o %s %s\t", mode, type, sha1_to_hex(sha1));
-       write_name_quoted(base, baselen, pathname, line_termination, stdout);
+       write_name_quoted(base + chomp_prefix, baselen - chomp_prefix,
+                         pathname,
+                         line_termination, stdout);
        putchar(line_termination);
        return retval;
 }
 
 int main(int argc, const char **argv)
 {
-       const char *prefix;
        unsigned char sha1[20];
        char *buf;
        unsigned long size;
 
        prefix = setup_git_directory();
+       if (prefix && *prefix)
+               chomp_prefix = strlen(prefix);
        while (1 < argc && argv[1][0] == '-') {
                switch (argv[1][1]) {
                case 'z':
@@ -100,6 +110,10 @@ int main(int argc, const char **argv)
                                ls_options |= LS_NAME_ONLY;
                                break;
                        }
+                       if (!strcmp(argv[1]+2, "full-name")) {
+                               chomp_prefix = 0;
+                               break;
+                       }
                        /* otherwise fallthru */
                default:
                        usage(ls_tree_usage);
index 0a43278..1869b38 100644 (file)
@@ -8,6 +8,8 @@
 
 #include "cache.h"
 
+#define BLKSIZE 512
+
 static const char pack_redundant_usage[] =
 "git-pack-redundant [ --verbose ] [ --alt-odb ] < --all | <.pack filename> ...>";
 
@@ -33,29 +35,32 @@ static struct pack_list {
 struct pll {
        struct pll *next;
        struct pack_list *pl;
-       size_t pl_size;
 };
 
 static struct llist_item *free_nodes = NULL;
 
+static inline void llist_item_put(struct llist_item *item)
+{
+       item->next = free_nodes;
+       free_nodes = item;
+}
+
 static inline struct llist_item *llist_item_get()
 {
        struct llist_item *new;
        if ( free_nodes ) {
                new = free_nodes;
                free_nodes = free_nodes->next;
-       } else
-               new = xmalloc(sizeof(struct llist_item));
-
+       } else {
+               int i = 1;
+               new = xmalloc(sizeof(struct llist_item) * BLKSIZE);
+               for(;i < BLKSIZE; i++) {
+                       llist_item_put(&new[i]);
+               }
+       }
        return new;
 }
 
-static inline void llist_item_put(struct llist_item *item)
-{
-       item->next = free_nodes;
-       free_nodes = item;
-}
-
 static void llist_free(struct llist *list)
 {
        while((list->back = list->front)) {
@@ -270,77 +275,58 @@ static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
        }
 }
 
-static void pll_insert(struct pll **pll, struct pll **hint_table)
+void pll_free(struct pll *l)
 {
-       struct pll *prev;
-       int i = (*pll)->pl_size - 1;
-
-       if (hint_table[i] == NULL) {
-               hint_table[i--] = *pll;
-               for (; i >= 0; --i) {
-                       if (hint_table[i] != NULL)
-                               break;
+       struct pll *old;
+       struct pack_list *opl;
+
+       while (l) {
+               old = l;
+               while (l->pl) {
+                       opl = l->pl;
+                       l->pl = opl->next;
+                       free(opl);
                }
-               if (hint_table[i] == NULL) /* no elements in list */
-                       die("Why did this happen?");
+               l = l->next;
+               free(old);
        }
-
-       prev = hint_table[i];
-       while (prev->next && prev->next->pl_size < (*pll)->pl_size)
-               prev = prev->next;
-
-       (*pll)->next = prev->next;
-       prev->next = *pll;
 }
 
 /* all the permutations have to be free()d at the same time,
  * since they refer to each other
  */
-static struct pll * get_all_permutations(struct pack_list *list)
+static struct pll * get_permutations(struct pack_list *list, int n)
 {
-       struct pll *subset, *pll, *new_pll = NULL; /*silence warning*/
-       static struct pll **hint = NULL;
-       if (hint == NULL)
-               hint = xcalloc(pack_list_size(list), sizeof(struct pll *));
-               
-       if (list == NULL)
+       struct pll *subset, *ret = NULL, *new_pll = NULL, *pll;
+
+       if (list == NULL || pack_list_size(list) < n || n == 0)
                return NULL;
 
-       if (list->next == NULL) {
-               new_pll = xmalloc(sizeof(struct pll));
-               hint[0] = new_pll;
-               new_pll->next = NULL;
-               new_pll->pl = list;
-               new_pll->pl_size = 1;
-               return new_pll;
+       if (n == 1) {
+               while (list) {
+                       new_pll = xmalloc(sizeof(pll));
+                       new_pll->pl = NULL;
+                       pack_list_insert(&new_pll->pl, list);
+                       new_pll->next = ret;
+                       ret = new_pll;
+                       list = list->next;
+               }
+               return ret;
        }
 
-       pll = subset = get_all_permutations(list->next);
-       while (pll) {
-               if (pll->pl->pack == list->pack) {
-                       pll = pll->next;
-                       continue;
+       while (list->next) {
+               subset = get_permutations(list->next, n - 1);
+               while (subset) {
+                       new_pll = xmalloc(sizeof(pll));
+                       new_pll->pl = subset->pl;
+                       pack_list_insert(&new_pll->pl, list);
+                       new_pll->next = ret;
+                       ret = new_pll;
+                       subset = subset->next;
                }
-               new_pll = xmalloc(sizeof(struct pll));
-
-               new_pll->pl = xmalloc(sizeof(struct pack_list));
-               memcpy(new_pll->pl, list, sizeof(struct pack_list));
-               new_pll->pl->next = pll->pl;
-               new_pll->pl_size = pll->pl_size + 1;
-               
-               pll_insert(&new_pll, hint);
-
-               pll = pll->next;
-       }
-       /* add ourself */
-       new_pll = xmalloc(sizeof(struct pll));
-       new_pll->pl = xmalloc(sizeof(struct pack_list));
-       memcpy(new_pll->pl, list, sizeof(struct pack_list));
-       new_pll->pl->next = NULL;
-       new_pll->pl_size = 1;
-       pll_insert(&new_pll, hint);
-
-       return hint[0];
+               list = list->next;
+       }
+       return ret;
 }
 
 static int is_superset(struct pack_list *pl, struct llist *list)
@@ -428,6 +414,7 @@ static void minimize(struct pack_list **min)
        struct pll *perm, *perm_all, *perm_ok = NULL, *new_perm;
        struct llist *missing;
        size_t min_perm_size = (size_t)-1, perm_size;
+       int n;
 
        pl = local_packs;
        while (pl) {
@@ -441,8 +428,7 @@ static void minimize(struct pack_list **min)
        missing = llist_copy(all_objects);
        pl = unique;
        while (pl) {
-               llist_sorted_difference_inplace(missing,
-                                               pl->all_objects);
+               llist_sorted_difference_inplace(missing, pl->all_objects);
                pl = pl->next;
        }
 
@@ -453,19 +439,21 @@ static void minimize(struct pack_list **min)
        }
 
        /* find the permutations which contain all missing objects */
-       perm_all = perm = get_all_permutations(non_unique);
-       while (perm) {
-               if (perm_ok && perm->pl_size > perm_ok->pl_size)
-                       break; /* ignore all larger permutations */
-               if (is_superset(perm->pl, missing)) {
-                       new_perm = xmalloc(sizeof(struct pll));
-                       memcpy(new_perm, perm, sizeof(struct pll));
-                       new_perm->next = perm_ok;
-                       perm_ok = new_perm;
+       for (n = 1; n <= pack_list_size(non_unique) && !perm_ok; n++) {
+               perm_all = perm = get_permutations(non_unique, n);
+               while (perm) {
+                       if (is_superset(perm->pl, missing)) {
+                               new_perm = xmalloc(sizeof(struct pll));
+                               memcpy(new_perm, perm, sizeof(struct pll));
+                               new_perm->next = perm_ok;
+                               perm_ok = new_perm;
+                       }
+                       perm = perm->next;
                }
-               perm = perm->next;
+               if (perm_ok)
+                       break;
+               pll_free(perm_all);
        }
-       
        if (perm_ok == NULL)
                die("Internal error: No complete sets found!\n");
 
@@ -537,6 +525,7 @@ static void scan_alt_odb_packs(void)
                                                        alt->all_objects);
                        local = local->next;
                }
+               llist_sorted_difference_inplace(all_objects, alt->all_objects);
                alt = alt->next;
        }
 }
index bb4949a..0c951af 100644 (file)
@@ -216,6 +216,18 @@ int main(int argc, char **argv)
                                        puts(prefix);
                                continue;
                        }
+                       if (!strcmp(arg, "--show-cdup")) {
+                               const char *pfx = prefix;
+                               while (pfx) {
+                                       pfx = strchr(pfx, '/');
+                                       if (pfx) {
+                                               pfx++;
+                                               printf("../");
+                                       }
+                               }
+                               putchar('\n');
+                               continue;
+                       }
                        if (!strcmp(arg, "--git-dir")) {
                                const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
                                static char cwd[PATH_MAX];
diff --git a/setup.c b/setup.c
index d3556ed..36ede3d 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -180,6 +180,8 @@ int check_repository_format_version(const char *var, const char *value)
 {
        if (strcmp(var, "core.repositoryformatversion") == 0)
                repository_format_version = git_config_int(var, value);
+       else if (strcmp(var, "core.sharedrepository") == 0)
+               shared_repository = git_config_bool(var, value);
        return 0;
 }
 
index 6b7577d..8bebbb2 100644 (file)
@@ -48,6 +48,29 @@ int get_sha1_hex(const char *hex, unsigned char *sha1)
        return 0;
 }
 
+int adjust_shared_perm(const char *path)
+{
+       struct stat st;
+       int mode;
+
+       if (!shared_repository)
+               return 0;
+       if (lstat(path, &st) < 0)
+               return -1;
+       mode = st.st_mode;
+       if (mode & S_IRUSR)
+               mode |= S_IRGRP;
+       if (mode & S_IWUSR)
+               mode |= S_IWGRP;
+       if (mode & S_IXUSR)
+               mode |= S_IXGRP;
+       if (S_ISDIR(mode))
+               mode |= S_ISGID;
+       if (chmod(path, mode) < 0)
+               return -2;
+       return 0;
+}
+
 int safe_create_leading_directories(char *path)
 {
        char *pos = path;
@@ -59,11 +82,16 @@ int safe_create_leading_directories(char *path)
                if (!pos)
                        break;
                *pos = 0;
-               if (mkdir(path, 0777) < 0)
+               if (mkdir(path, 0777) < 0) {
                        if (errno != EEXIST) {
                                *pos = '/';
                                return -1;
                        }
+               }
+               else if (adjust_shared_perm(path)) {
+                       *pos = '/';
+                       return -2;
+               }
                *pos++ = '/';
        }
        return 0;
@@ -1255,6 +1283,8 @@ static int link_temp_to_file(const char *tmpfile, char *filename)
                if (dir) {
                        *dir = 0;
                        mkdir(filename, 0777);
+                       if (adjust_shared_perm(filename))
+                               return -2;
                        *dir = '/';
                        if (!link(tmpfile, filename))
                                return 0;
index 153b9e4..1292caf 100755 (executable)
@@ -161,4 +161,41 @@ test_expect_success 'pull unrenaming branch into renaming one' \
        }
 '
 
+test_expect_success 'pull conflicting renames' \
+'
+       git reset --hard
+       git show-branch
+       git pull . blue && {
+               echo "BAD: should have conflicted"
+               exit 1
+       }
+       test "$(git ls-files -u A | wc -l)" -eq 1 || {
+               echo "BAD: should have left a stage"
+               exit 1  
+       }
+       test "$(git ls-files -u B | wc -l)" -eq 1 || {
+               echo "BAD: should have left a stage"
+               exit 1  
+       }
+       test "$(git ls-files -u C | wc -l)" -eq 1 || {
+               echo "BAD: should have left a stage"
+               exit 1  
+       }
+       test "$(git ls-files -s N | wc -l)" -eq 1 || {
+               echo "BAD: should have merged N"
+               exit 1  
+       }
+       sed -ne "/^g/{
+       p
+       q
+       }" B | grep red || {
+               echo "BAD: should have listed our change first"
+               exit 1
+       }
+       test "$(git diff white N | wc -l)" -eq 0 || {
+               echo "BAD: should have taken colored branch"
+               exit 1
+       }
+'
+
 test_done