diff options
-rw-r--r-- | Documentation/config.txt | 24 | ||||
-rw-r--r-- | Documentation/git-branch.txt | 9 | ||||
-rw-r--r-- | Documentation/git-clone.txt | 6 | ||||
-rw-r--r-- | Documentation/git-svn.txt | 87 | ||||
-rw-r--r-- | Documentation/git-svnimport.txt | 10 | ||||
-rw-r--r-- | Documentation/git-tag.txt | 7 | ||||
-rw-r--r-- | Documentation/tutorial.txt | 51 | ||||
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | archive-tar.c | 7 | ||||
-rw-r--r-- | builtin-branch.c | 85 | ||||
-rw-r--r-- | builtin-prune.c | 2 | ||||
-rw-r--r-- | builtin-rerere.c | 7 | ||||
-rw-r--r-- | cache.h | 1 | ||||
-rw-r--r-- | commit.c | 5 | ||||
-rw-r--r-- | contrib/emacs/git.el | 21 | ||||
-rw-r--r-- | diff-lib.c | 9 | ||||
-rw-r--r-- | diff.c | 6 | ||||
-rw-r--r-- | diff.h | 4 | ||||
-rw-r--r-- | diffcore.h | 4 | ||||
-rwxr-xr-x | generate-cmdlist.sh | 1 | ||||
-rwxr-xr-x | git-clean.sh | 4 | ||||
-rwxr-xr-x | git-instaweb.sh | 3 | ||||
-rwxr-xr-x | git-remote.perl | 277 | ||||
-rwxr-xr-x | git-reset.sh | 6 | ||||
-rwxr-xr-x | git-svn.perl | 90 | ||||
-rwxr-xr-x | git-svnimport.perl | 36 | ||||
-rwxr-xr-x | git-tag.sh | 11 | ||||
-rwxr-xr-x | git-verify-tag.sh | 3 | ||||
-rwxr-xr-x | gitweb/gitweb.perl | 41 | ||||
-rw-r--r-- | lockfile.c | 9 | ||||
-rw-r--r-- | pack-check.c | 20 | ||||
-rw-r--r-- | refs.c | 1 | ||||
-rwxr-xr-x | t/test-lib.sh | 6 | ||||
-rw-r--r-- | tree-walk.c | 1 |
34 files changed, 646 insertions, 212 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt index 2f4fc25258..4318bf9334 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -145,6 +145,21 @@ branch.<name>.merge:: this option, `git pull` defaults to merge the first refspec fetched. Specify multiple values to get an octopus merge. +color.branch:: + A boolean to enable/disable color in the output of + gitlink:git-branch[1]. May be set to `true` (or `always`), + `false` (or `never`) or `auto`, in which case colors are used + only when the output is to a terminal. Defaults to false. + +color.branch.<slot>:: + Use customized color for branch coloration. `<slot>` is one of + `current` (the current branch), `local` (a local branch), + `remote` (a tracking branch in refs/remotes/), `plain` (other + refs), or `reset` (the normal terminal color). The value for + these configuration variables can be one of: `normal`, `bold`, + `dim`, `ul`, `blink`, `reverse`, `reset`, `black`, `red`, + `green`, `yellow`, `blue`, `magenta`, `cyan`, or `white`. + color.diff:: When true (or `always`), always use colors in patch. When false (or `never`), never. When set to `auto`, use @@ -155,11 +170,8 @@ color.diff.<slot>:: specifies which part of the patch to use the specified color, and is one of `plain` (context text), `meta` (metainformation), `frag` (hunk header), `old` (removed - lines), or `new` (added lines). The value for these - configuration variables can be one of: `normal`, `bold`, - `dim`, `ul`, `blink`, `reverse`, `reset`, `black`, - `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, or - `white`. + lines), or `new` (added lines). The values of these + variables may be specified as in color.branch.<slot>. color.pager:: A boolean to enable/disable colored output when the pager is in @@ -177,7 +189,7 @@ color.status.<slot>:: `added` or `updated` (files which are added but not committed), `changed` (files which are changed but not added in the index), or `untracked` (files which are not tracked by git). The values of - these variables may be specified as in color.diff.<slot>. + these variables may be specified as in color.branch.<slot>. diff.renameLimit:: The number of files to consider when performing the copy/rename diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index c464bd2fda..e872fc89fc 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -8,7 +8,7 @@ git-branch - List, create, or delete branches. SYNOPSIS -------- [verse] -'git-branch' [-r | -a] [-v [--abbrev=<length>]] +'git-branch' [--color | --no-color] [-r | -a] [-v [--abbrev=<length>]] 'git-branch' [-l] [-f] <branchname> [<start-point>] 'git-branch' (-m | -M) [<oldbranch>] <newbranch> 'git-branch' (-d | -D) [-r] <branchname>... @@ -60,6 +60,13 @@ OPTIONS -M:: Move/rename a branch even if the new branchname already exists. +--color:: + Color branches to highlight current, local, and remote branches. + +--no-color:: + Turn off branch colors, even when the configuration file gives the + default to color output. + -r:: List or delete (if used with -d) the remote-tracking branches. diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index e7085fdf5f..a78207461d 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -18,13 +18,13 @@ DESCRIPTION Clones a repository into a newly created directory, creates remote-tracking branches for each branch in the cloned repository -(visible using `git branch -r`), and creates and checks out a master -branch equal to the cloned repository's master branch. +(visible using `git branch -r`), and creates and checks out an initial +branch equal to the cloned repository's currently active branch. After the clone, a plain `git fetch` without arguments will update all the remote-tracking branches, and a `git pull` without arguments will in addition merge the remote master branch into the -current branch. +current master branch, if any. This default configuration is achieved by creating references to the remote branch heads under `$GIT_DIR/refs/remotes/origin` and diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index f5f57e8f87..ce63defffd 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -3,7 +3,7 @@ git-svn(1) NAME ---- -git-svn - bidirectional operation between a single Subversion branch and git +git-svn - bidirectional operation between Subversion and git SYNOPSIS -------- @@ -11,24 +11,20 @@ SYNOPSIS DESCRIPTION ----------- -git-svn is a simple conduit for changesets between a single Subversion -branch and git. It is not to be confused with gitlink:git-svnimport[1]. -They were designed with very different goals in mind. +git-svn is a simple conduit for changesets between Subversion and git. +It is not to be confused with gitlink:git-svnimport[1], which is +read-only and geared towards tracking multiple branches. -git-svn is designed for an individual developer who wants a +git-svn was originally designed for an individual developer who wants a bidirectional flow of changesets between a single branch in Subversion -and an arbitrary number of branches in git. git-svnimport is designed -for read-only operation on repositories that match a particular layout -(albeit the recommended one by SVN developers). +and an arbitrary number of branches in git. Since its inception, +git-svn has gained the ability to track multiple branches in a manner +similar to git-svnimport; but it cannot (yet) automatically detect new +branches and tags like git-svnimport does. -For importing svn, git-svnimport is potentially more powerful when -operating on repositories organized under the recommended -trunk/branch/tags structure, and should be faster, too. - -git-svn mostly ignores the very limited view of branching that -Subversion has. This allows git-svn to be much easier to use, -especially on repositories that are not organized in a manner that -git-svnimport is designed for. +git-svn is especially useful when it comes to tracking repositories +not organized in the way Subversion developers recommend (trunk, +branches, tags directories). COMMANDS -------- @@ -57,11 +53,13 @@ See '<<fetch-args,Additional Fetch Arguments>>' if you are interested in manually joining branches on commit. 'dcommit':: - Commit all diffs from a specified head directly to the SVN + Commit each diff from a specified head directly to the SVN repository, and then rebase or reset (depending on whether or - not there is a diff between SVN and head). It is recommended - that you run git-svn fetch and rebase (not pull) your commits - against the latest changes in the SVN repository. + not there is a diff between SVN and head). This will create + a revision in SVN for each commit in git. + It is recommended that you run git-svn fetch and rebase (not + pull or merge) your commits against the latest changes in the + SVN repository. An optional command-line argument may be specified as an alternative to HEAD. This is advantageous over 'set-tree' (below) because it produces @@ -370,7 +368,7 @@ SVN was very wrong. Basic Examples ~~~~~~~~~~~~~~ -Tracking and contributing to a Subversion-managed project: +Tracking and contributing to a the trunk of a Subversion-managed project: ------------------------------------------------------------------------ # Initialize a repo (like git init-db): @@ -388,19 +386,44 @@ Tracking and contributing to a Subversion-managed project: git-svn show-ignore >> .git/info/exclude ------------------------------------------------------------------------ -REBASE VS. PULL ---------------- +Tracking and contributing to an entire Subversion-managed project +(complete with a trunk, tags and branches): +See also: +'<<tracking-multiple-repos,Tracking Multiple Repositories or Branches>>' + +------------------------------------------------------------------------ +# Initialize a repo (like git init-db): + git-svn multi-init http://svn.foo.org/project \ + -T trunk -b branches -t tags +# Fetch remote revisions: + git-svn multi-fetch +# Create your own branch of trunk to hack on: + git checkout -b my-trunk remotes/trunk +# Do some work, and then commit your new changes to SVN, as well as +# automatically updating your working HEAD: + git-svn dcommit -i trunk +# Something has been committed to trunk, rebase the latest into your branch: + git-svn multi-fetch && git rebase remotes/trunk +# Append svn:ignore settings of trunk to the default git exclude file: + git-svn show-ignore -i trunk >> .git/info/exclude +# Check for new branches and tags (no arguments are needed): + git-svn multi-init +------------------------------------------------------------------------ + +REBASE VS. PULL/MERGE +--------------------- Originally, git-svn recommended that the remotes/git-svn branch be -pulled from. This is because the author favored 'git-svn set-tree B' -to commit a single head rather than the 'git-svn set-tree A..B' notation -to commit multiple commits. - -If you use 'git-svn set-tree A..B' to commit several diffs and you do not -have the latest remotes/git-svn merged into my-branch, you should use -'git rebase' to update your work branch instead of 'git pull'. 'pull' -can cause non-linear history to be flattened when committing into SVN, -which can lead to merge commits reversing previous commits in SVN. +pulled or merged from. This is because the author favored +'git-svn set-tree B' to commit a single head rather than the +'git-svn set-tree A..B' notation to commit multiple commits. + +If you use 'git-svn set-tree A..B' to commit several diffs and you do +not have the latest remotes/git-svn merged into my-branch, you should +use 'git rebase' to update your work branch instead of 'git pull' or +'git merge'. 'pull/merge' can cause non-linear history to be flattened +when committing into SVN, which can lead to merge commits reversing +previous commits in SVN. DESIGN PHILOSOPHY ----------------- diff --git a/Documentation/git-svnimport.txt b/Documentation/git-svnimport.txt index 2c7c7dad54..b166cf3327 100644 --- a/Documentation/git-svnimport.txt +++ b/Documentation/git-svnimport.txt @@ -15,7 +15,7 @@ SYNOPSIS [ -b branch_subdir ] [ -T trunk_subdir ] [ -t tag_subdir ] [ -s start_chg ] [ -m ] [ -r ] [ -M regex ] [ -I <ignorefile_name> ] [ -A <author_file> ] - [ -P <path_from_trunk> ] + [ -R <repack_each_revs>] [ -P <path_from_trunk> ] <SVN_repository_URL> [ <path> ] @@ -108,6 +108,14 @@ repository without -A. Formerly, this option controlled how many revisions to pull, due to SVN memory leaks. (These have been worked around.) +-R <repack_each_revs>:: + Specify how often git repository should be repacked. ++ +The default value is 1000. git-svnimport will do import in chunks of 1000 +revisions, after each chunk git repository will be repacked. To disable +this behavior specify some big value here which is mote than number of +revisions to import. + -P <path_from_trunk>:: Partial import of the SVN tree. + diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 48b82b86f8..80bece0775 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -9,7 +9,7 @@ git-tag - Create a tag object signed with GPG SYNOPSIS -------- [verse] -'git-tag' [-a | -s | -u <key-id>] [-f | -d] [-m <msg> | -F <file>] +'git-tag' [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg> | -F <file>] <name> [<head>] 'git-tag' -l [<pattern>] @@ -35,6 +35,8 @@ GnuPG key for signing. `-d <tag>` deletes the tag. +`-v <tag>` verifies the gpg signature of the tag. + `-l <pattern>` lists tags that match the given pattern (or all if no pattern is given). @@ -55,6 +57,9 @@ OPTIONS -d:: Delete an existing tag with the given name +-v:: + Verify the gpg signature of given the tag + -l <pattern>:: List tags that match the given pattern (or all if no pattern is given). diff --git a/Documentation/tutorial.txt b/Documentation/tutorial.txt index d043e844d2..01d4a47a97 100644 --- a/Documentation/tutorial.txt +++ b/Documentation/tutorial.txt @@ -43,8 +43,7 @@ Initialized empty Git repository in .git/ You've now initialized the working directory--you may notice a new directory created, named ".git". Tell git that you want it to track -every file under the current directory with (notice the dot '.' -that means the current directory): +every file under the current directory (note the '.') with: ------------------------------------------------ $ git add . @@ -59,32 +58,40 @@ $ git commit will prompt you for a commit message, then record the current state of all the files to the repository. +Making changes +-------------- + Try modifying some files, then run ------------------------------------------------ $ git diff ------------------------------------------------ -to review your changes. When you're done, +to review your changes. When you're done, tell git that you +want the updated contents of these files in the commit and then +make a commit, like this: ------------------------------------------------ -$ git commit file1 file2... +$ git add file1 file2 file3 +$ git commit ------------------------------------------------ -will again prompt your for a message describing the change, and then -record the new versions of the files you listed. It is cumbersome -to list all files and you can say `-a` (which stands for 'all') -instead. +This will again prompt your for a message describing the change, and then +record the new versions of the files you listed. + +Alternatively, instead of running `git add` beforehand, you can use ------------------------------------------------ $ git commit -a ------------------------------------------------ +which will automatically notice modified (but not new) files. + A note on commit messages: Though not required, it's a good idea to begin the commit message with a single short (less than 50 character) line summarizing the change, followed by a blank line and then a more thorough description. Tools that turn commits into email, for -example, use the first line on the Subject line and the rest of the +example, use the first line on the Subject: line and the rest of the commit in the body. @@ -142,6 +149,13 @@ If you also want to see complete diffs at each step, use $ git log -p ------------------------------------------------ +Often the overview of the change is useful to get a feel of +each step + +------------------------------------------------ +$ git log --stat --summary +------------------------------------------------ + Managing branches ----------------- @@ -222,6 +236,15 @@ $ gitk will show a nice graphical representation of the resulting history. +At this point you could delete the experimental branch with + +------------------------------------------------ +$ git branch -d experimental +------------------------------------------------ + +This command ensures that the changes in the experimental branch are +already in the current branch. + If you develop on a branch crazy-idea, then regret it, you can always delete the branch with @@ -381,7 +404,7 @@ commit. $ git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7 ------------------------------------- -But there other ways to refer to commits. You can use any initial +But there are other ways to refer to commits. You can use any initial part of the name that is long enough to uniquely identify the commit: ------------------------------------- @@ -391,8 +414,8 @@ $ git show HEAD # the tip of the current branch $ git show experimental # the tip of the "experimental" branch ------------------------------------- -Every commit has at least one "parent" commit, which points to the -previous state of the project: +Every commit usually has one "parent" commit +which points to the previous state of the project: ------------------------------------- $ git show HEAD^ # to see the parent of HEAD @@ -510,10 +533,10 @@ of the file: $ git diff v2.5:Makefile HEAD:Makefile.in ------------------------------------- -You can also use "git cat-file -p" to see any such file: +You can also use "git show" to see any such file: ------------------------------------- -$ git cat-file -p v2.5:Makefile +$ git show v2.5:Makefile ------------------------------------- Next Steps @@ -179,7 +179,7 @@ SCRIPT_SH = \ SCRIPT_PERL = \ git-add--interactive.perl \ git-archimport.perl git-cvsimport.perl git-relink.perl \ - git-cvsserver.perl \ + git-cvsserver.perl git-remote.perl \ git-svnimport.perl git-cvsexportcommit.perl \ git-send-email.perl git-svn.perl @@ -818,7 +818,7 @@ test-sha1$X: test-sha1.o $(GITLIBS) check-sha1:: test-sha1$X ./test-sha1.sh -check: +check: common-cmds.h for i in *.c; do sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; done diff --git a/archive-tar.c b/archive-tar.c index af47fdc955..7d52a061f4 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -15,7 +15,7 @@ static char block[BLOCKSIZE]; static unsigned long offset; static time_t archive_time; -static int tar_umask; +static int tar_umask = 002; static int verbose; /* writes out the whole block, but only if it is full */ @@ -210,11 +210,10 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path, sprintf(header.size, "%011lo", S_ISREG(mode) ? size : 0); sprintf(header.mtime, "%011lo", archive_time); - /* XXX: should we provide more meaningful info here? */ sprintf(header.uid, "%07o", 0); sprintf(header.gid, "%07o", 0); - strlcpy(header.uname, "git", sizeof(header.uname)); - strlcpy(header.gname, "git", sizeof(header.gname)); + strlcpy(header.uname, "root", sizeof(header.uname)); + strlcpy(header.gname, "root", sizeof(header.gname)); sprintf(header.devmajor, "%07o", 0); sprintf(header.devminor, "%07o", 0); diff --git a/builtin-branch.c b/builtin-branch.c index 745ee04d6e..d3df5a57f1 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -12,7 +12,7 @@ #include "builtin.h" static const char builtin_branch_usage[] = - "git-branch [-r] (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [-r | -a] [-v [--abbrev=<length>]]"; + "git-branch [-r] (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length>]]"; #define REF_UNKNOWN_TYPE 0x00 #define REF_LOCAL_BRANCH 0x01 @@ -231,29 +231,54 @@ static int ref_cmp(const void *r1, const void *r2) return strcmp(c1->name, c2->name); } -static void print_ref_info(const unsigned char *sha1, int abbrev) +static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, + int abbrev, int current) { + char c; + int color; struct commit *commit; char subject[256]; + switch (item->kind) { + case REF_LOCAL_BRANCH: + color = COLOR_BRANCH_LOCAL; + break; + case REF_REMOTE_BRANCH: + color = COLOR_BRANCH_REMOTE; + break; + default: + color = COLOR_BRANCH_PLAIN; + break; + } - commit = lookup_commit(sha1); - if (commit && !parse_commit(commit)) - pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0, - subject, sizeof(subject), 0, - NULL, NULL, 0); - else - strcpy(subject, " **** invalid ref ****"); + c = ' '; + if (current) { + c = '*'; + color = COLOR_BRANCH_CURRENT; + } - printf(" %s %s\n", find_unique_abbrev(sha1, abbrev), subject); + if (verbose) { + commit = lookup_commit(item->sha1); + if (commit && !parse_commit(commit)) + pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0, + subject, sizeof(subject), 0, + NULL, NULL, 0); + else + strcpy(subject, " **** invalid ref ****"); + printf("%c %s%-*s%s %s %s\n", c, branch_get_color(color), + maxwidth, item->name, + branch_get_color(COLOR_BRANCH_RESET), + find_unique_abbrev(item->sha1, abbrev), subject); + } else { + printf("%c %s%s%s\n", c, branch_get_color(color), item->name, + branch_get_color(COLOR_BRANCH_RESET)); + } } static void print_ref_list(int kinds, int verbose, int abbrev) { int i; - char c; struct ref_list ref_list; - int color; memset(&ref_list, 0, sizeof(ref_list)); ref_list.kinds = kinds; @@ -262,38 +287,10 @@ static void print_ref_list(int kinds, int verbose, int abbrev) qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp); for (i = 0; i < ref_list.index; i++) { - switch( ref_list.list[i].kind ) { - case REF_LOCAL_BRANCH: - color = COLOR_BRANCH_LOCAL; - break; - case REF_REMOTE_BRANCH: - color = COLOR_BRANCH_REMOTE; - break; - default: - color = COLOR_BRANCH_PLAIN; - break; - } - - c = ' '; - if (ref_list.list[i].kind == REF_LOCAL_BRANCH && - !strcmp(ref_list.list[i].name, head)) { - c = '*'; - color = COLOR_BRANCH_CURRENT; - } - - if (verbose) { - printf("%c %s%-*s%s", c, - branch_get_color(color), - ref_list.maxwidth, - ref_list.list[i].name, - branch_get_color(COLOR_BRANCH_RESET)); - print_ref_info(ref_list.list[i].sha1, abbrev); - } - else - printf("%c %s%s%s\n", c, - branch_get_color(color), - ref_list.list[i].name, - branch_get_color(COLOR_BRANCH_RESET)); + int current = (ref_list.list[i].kind == REF_LOCAL_BRANCH) && + !strcmp(ref_list.list[i].name, head); + print_ref_item(&ref_list.list[i], ref_list.maxwidth, verbose, + abbrev, current); } free_ref_list(&ref_list); diff --git a/builtin-prune.c b/builtin-prune.c index 00a53b3647..b469c43bc5 100644 --- a/builtin-prune.c +++ b/builtin-prune.c @@ -253,6 +253,8 @@ int cmd_prune(int argc, const char **argv, const char *prefix) usage(prune_usage); } + save_commit_buffer = 0; + /* * Set up revision parsing, and mark us as being interested * in all object types, not just commits. diff --git a/builtin-rerere.c b/builtin-rerere.c index 7442498dee..079c0bdf36 100644 --- a/builtin-rerere.c +++ b/builtin-rerere.c @@ -350,11 +350,10 @@ static int do_plain_rerere(struct path_list *rr, int fd) fprintf(stderr, "Recorded resolution for '%s'.\n", path); copy_file(path, rr_path(name, "postimage")); tail_optimization: - if (i < rr->nr - 1) { + if (i < rr->nr - 1) memmove(rr->items + i, - rr->items + i + 1, - rr->nr - i - 1); - } + rr->items + i + 1, + sizeof(rr->items[0]) * (rr->nr - i - 1)); rr->nr--; i--; } @@ -179,6 +179,7 @@ extern int refresh_cache(unsigned int flags); struct lock_file { struct lock_file *next; + char on_list; char filename[PATH_MAX]; }; extern int hold_lock_file_for_update(struct lock_file *, const char *path, int); @@ -703,7 +703,7 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const char *after_subject, int relative_date) { - int hdr = 1, body = 0; + int hdr = 1, body = 0, seen_title = 0; unsigned long offset = 0; int indent = 4; int parents_shown = 0; @@ -809,6 +809,8 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, body = 1; if (is_empty_line(line, &linelen)) { + if (!seen_title) + continue; if (!body) continue; if (subject) @@ -817,6 +819,7 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, break; } + seen_title = 1; if (subject) { int slen = strlen(subject); memcpy(buf + offset, subject, slen); diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el index 972c402ea0..ede3ab2bd8 100644 --- a/contrib/emacs/git.el +++ b/contrib/emacs/git.el @@ -49,6 +49,7 @@ (eval-when-compile (require 'cl)) (require 'ewoc) +(require 'log-edit) ;;;; Customizations @@ -147,6 +148,13 @@ if there is already one that displays the same directory." (defconst git-log-msg-separator "--- log message follows this line ---") +(defvar git-log-edit-font-lock-keywords + `(("^\\(Author:\\|Date:\\|Parent:\\|Signed-off-by:\\)\\(.*\\)$" + (1 font-lock-keyword-face) + (2 font-lock-function-name-face)) + (,(concat "^\\(" (regexp-quote git-log-msg-separator) "\\)$") + (1 font-lock-comment-face)))) + (defun git-get-env-strings (env) "Build a list of NAME=VALUE strings from a list of environment strings." (mapcar (lambda (entry) (concat (car entry) "=" (cdr entry))) env)) @@ -777,7 +785,7 @@ and returns the process output as a string." (interactive) (let ((files (git-marked-files-state 'unmerged))) (when files - (apply #'git-run-command nil nil "update-index" "--info-only" "--" (git-get-filenames files)) + (apply #'git-run-command nil nil "update-index" "--" (git-get-filenames files)) (git-set-files-state files 'modified) (git-refresh-files)))) @@ -894,14 +902,9 @@ and returns the process output as a string." (sign-off (insert (format "\n\nSigned-off-by: %s <%s>\n" (git-get-committer-name) (git-get-committer-email))))))) - (let ((log-edit-font-lock-keywords - `(("^\\(Author:\\|Date:\\|Parent:\\|Signed-off-by:\\)\\(.*\\)" - (1 font-lock-keyword-face) - (2 font-lock-function-name-face)) - (,(concat "^\\(" (regexp-quote git-log-msg-separator) "\\)$") - (1 font-lock-comment-face))))) - (log-edit #'git-do-commit nil #'git-log-edit-files buffer) - (re-search-forward (regexp-quote (concat git-log-msg-separator "\n")) nil t)))) + (log-edit #'git-do-commit nil #'git-log-edit-files buffer) + (setq font-lock-keywords (font-lock-compile-keywords git-log-edit-font-lock-keywords)) + (re-search-forward (regexp-quote (concat git-log-msg-separator "\n")) nil t))) (defun git-find-file () "Visit the current file in its own buffer." diff --git a/diff-lib.c b/diff-lib.c index fc69fb92a5..2c9be60ed9 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -97,7 +97,7 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed) * Show the diff for the 'ce' if we found the one * from the desired stage. */ - diff_unmerge(&revs->diffopt, ce->name); + diff_unmerge(&revs->diffopt, ce->name, 0, null_sha1); if (ce_stage(ce) != diff_unmerged_stage) continue; } @@ -297,9 +297,12 @@ static int diff_cache(struct rev_info *revs, !show_modified(revs, ce, ac[1], 0, cached, match_missing)) break; - /* fallthru */ + diff_unmerge(&revs->diffopt, ce->name, + ntohl(ce->ce_mode), ce->sha1); + break; case 3: - diff_unmerge(&revs->diffopt, ce->name); + diff_unmerge(&revs->diffopt, ce->name, + 0, null_sha1); break; default: @@ -2875,10 +2875,12 @@ void diff_change(struct diff_options *options, } void diff_unmerge(struct diff_options *options, - const char *path) + const char *path, + unsigned mode, const unsigned char *sha1) { struct diff_filespec *one, *two; one = alloc_filespec(path); two = alloc_filespec(path); - diff_queue(&diff_queued_diff, one, two); + fill_filespec(one, sha1, mode); + diff_queue(&diff_queued_diff, one, two)->is_unmerged = 1; } @@ -144,7 +144,9 @@ extern void diff_change(struct diff_options *, const char *base, const char *path); extern void diff_unmerge(struct diff_options *, - const char *path); + const char *path, + unsigned mode, + const unsigned char *sha1); extern int diff_scoreopt_parse(const char *opt); diff --git a/diffcore.h b/diffcore.h index 2249bc2c05..1ea80671e3 100644 --- a/diffcore.h +++ b/diffcore.h @@ -54,9 +54,9 @@ struct diff_filepair { unsigned source_stays : 1; /* all of R/C are copies */ unsigned broken_pair : 1; unsigned renamed_pair : 1; + unsigned is_unmerged : 1; }; -#define DIFF_PAIR_UNMERGED(p) \ - (!DIFF_FILE_VALID((p)->one) && !DIFF_FILE_VALID((p)->two)) +#define DIFF_PAIR_UNMERGED(p) ((p)->is_unmerged) #define DIFF_PAIR_RENAME(p) ((p)->renamed_pair) diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh index 06c42b042d..1de14ea82f 100755 --- a/generate-cmdlist.sh +++ b/generate-cmdlist.sh @@ -37,7 +37,6 @@ show show-branch status tag -verify-tag EOF while read cmd do diff --git a/git-clean.sh b/git-clean.sh index 3834323bcf..071b974f49 100755 --- a/git-clean.sh +++ b/git-clean.sh @@ -18,7 +18,6 @@ SUBDIRECTORY_OK=Yes ignored= ignoredonly= cleandir= -quiet= rmf="rm -f --" rmrf="rm -rf --" rm_refuse="echo Not removing" @@ -31,14 +30,13 @@ do cleandir=1 ;; -n) - quiet=1 rmf="echo Would remove" rmrf="echo Would remove" rm_refuse="echo Would not remove" echo1=":" ;; -q) - quiet=1 + echo1=":" ;; -x) ignored=1 diff --git a/git-instaweb.sh b/git-instaweb.sh index 08362f43c0..80adc8307b 100755 --- a/git-instaweb.sh +++ b/git-instaweb.sh @@ -53,6 +53,9 @@ start_httpd () { return fi done + echo "$httpd_only not found. Install $httpd_only or use" \ + "--httpd to specify another http daemon." + exit 1 fi if test $? != 0; then echo "Could not execute http daemon $httpd." diff --git a/git-remote.perl b/git-remote.perl new file mode 100755 index 0000000000..059c141b68 --- /dev/null +++ b/git-remote.perl @@ -0,0 +1,277 @@ +#!/usr/bin/perl -w + +use Git; +my $git = Git->repository(); + +sub add_remote_config { + my ($hash, $name, $what, $value) = @_; + if ($what eq 'url') { + if (exists $hash->{$name}{'URL'}) { + print STDERR "Warning: more than one remote.$name.url\n"; + } + $hash->{$name}{'URL'} = $value; + } + elsif ($what eq 'fetch') { + $hash->{$name}{'FETCH'} ||= []; + push @{$hash->{$name}{'FETCH'}}, $value; + } + if (!exists $hash->{$name}{'SOURCE'}) { + $hash->{$name}{'SOURCE'} = 'config'; + } +} + +sub add_remote_remotes { + my ($hash, $file, $name) = @_; + + if (exists $hash->{$name}) { + $hash->{$name}{'WARNING'} = 'ignored due to config'; + return; + } + + my $fh; + if (!open($fh, '<', $file)) { + print STDERR "Warning: cannot open $file\n"; + return; + } + my $it = { 'SOURCE' => 'remotes' }; + $hash->{$name} = $it; + while (<$fh>) { + chomp; + if (/^URL:\s*(.*)$/) { + # Having more than one is Ok -- it is used for push. + if (! exists $it->{'URL'}) { + $it->{'URL'} = $1; + } + } + elsif (/^Push:\s*(.*)$/) { + ; # later + } + elsif (/^Pull:\s*(.*)$/) { + $it->{'FETCH'} ||= []; + push @{$it->{'FETCH'}}, $1; + } + elsif (/^\#/) { + ; # ignore + } + else { + print STDERR "Warning: funny line in $file: $_\n"; + } + } + close($fh); +} + +sub list_remote { + my ($git) = @_; + my %seen = (); + my @remotes = eval { + $git->command(qw(repo-config --get-regexp), '^remote\.'); + }; + for (@remotes) { + if (/^remote\.([^.]*)\.(\S*)\s+(.*)$/) { + add_remote_config(\%seen, $1, $2, $3); + } + } + + my $dir = $git->repo_path() . "/remotes"; + if (opendir(my $dh, $dir)) { + local $_; + while ($_ = readdir($dh)) { + chomp; + next if (! -f "$dir/$_" || ! -r _); + add_remote_remotes(\%seen, "$dir/$_", $_); + } + } + + return \%seen; +} + +sub add_branch_config { + my ($hash, $name, $what, $value) = @_; + if ($what eq 'remote') { + if (exists $hash->{$name}{'REMOTE'}) { + print STDERR "Warning: more than one branch.$name.remote\n"; + } + $hash->{$name}{'REMOTE'} = $value; + } + elsif ($what eq 'merge') { + $hash->{$name}{'MERGE'} ||= []; + push @{$hash->{$name}{'MERGE'}}, $value; + } +} + +sub list_branch { + my ($git) = @_; + my %seen = (); + my @branches = eval { + $git->command(qw(repo-config --get-regexp), '^branch\.'); + }; + for (@branches) { + if (/^branch\.([^.]*)\.(\S*)\s+(.*)$/) { + add_branch_config(\%seen, $1, $2, $3); + } + } + + return \%seen; +} + +my $remote = list_remote($git); +my $branch = list_branch($git); + +sub update_ls_remote { + my ($harder, $info) = @_; + + return if (($harder == 0) || + (($harder == 1) && exists $info->{'LS_REMOTE'})); + + my @ref = map { + s|^[0-9a-f]{40}\s+refs/heads/||; + $_; + } $git->command(qw(ls-remote --heads), $info->{'URL'}); + $info->{'LS_REMOTE'} = \@ref; +} + +sub show_wildcard_mapping { + my ($forced, $ours, $ls) = @_; + my %refs; + for (@$ls) { + $refs{$_} = 01; # bit #0 to say "they have" + } + for ($git->command('for-each-ref', "refs/remotes/$ours")) { + chomp; + next unless (s|^[0-9a-f]{40}\s[a-z]+\srefs/remotes/$ours/||); + next if ($_ eq 'HEAD'); + $refs{$_} ||= 0; + $refs{$_} |= 02; # bit #1 to say "we have" + } + my (@new, @stale, @tracked); + for (sort keys %refs) { + my $have = $refs{$_}; + if ($have == 1) { + push @new, $_; + } + elsif ($have == 2) { + push @stale, $_; + } + elsif ($have == 3) { + push @tracked, $_; + } + } + if (@new) { + print " New remote branches (next fetch will store in remotes/$ours)\n"; + print " @new\n"; + } + if (@stale) { + print " Stale tracking branches in remotes/$ours (you'd better remove them)\n"; + print " @stale\n"; + } + if (@tracked) { + print " Tracked remote branches\n"; + print " @tracked\n"; + } +} + +sub show_mapping { + my ($name, $info) = @_; + my $fetch = $info->{'FETCH'}; + my $ls = $info->{'LS_REMOTE'}; + my (@stale, @tracked); + + for (@$fetch) { + next unless (/(\+)?([^:]+):(.*)/); + my ($forced, $theirs, $ours) = ($1, $2, $3); + if ($theirs eq 'refs/heads/*' && + $ours =~ /^refs\/remotes\/(.*)\/\*$/) { + # wildcard mapping + show_wildcard_mapping($forced, $1, $ls); + } + elsif ($theirs =~ /\*/ || $ours =~ /\*/) { + print STDERR "Warning: unrecognized mapping in remotes.$name.fetch: $_\n"; + } + elsif ($theirs =~ s|^refs/heads/||) { + if (!grep { $_ eq $theirs } @$ls) { + push @stale, $theirs; + } + elsif ($ours ne '') { + push @tracked, $theirs; + } + } + } + if (@stale) { + print " Stale tracking branches in remotes/$name (you'd better remove them)\n"; + print " @stale\n"; + } + if (@tracked) { + print " Tracked remote branches\n"; + print " @tracked\n"; + } +} + +sub show_remote { + my ($name, $ls_remote) = @_; + if (!exists $remote->{$name}) { + print STDERR "No such remote $name\n"; + return; + } + my $info = $remote->{$name}; + update_ls_remote($ls_remote, $info); + + print "* remote $name\n"; + print " URL: $info->{'URL'}\n"; + for my $branchname (sort keys %$branch) { + next if ($branch->{$branchname}{'REMOTE'} ne $name); + my @merged = map { + s|^refs/heads/||; + $_; + } split(' ',"@{$branch->{$branchname}{'MERGE'}}"); + next unless (@merged); + print " Remote branch(es) merged with 'git pull' while on branch $branchname\n"; + print " @merged\n"; + } + if ($info->{'LS_REMOTE'}) { + show_mapping($name, $info); + } +} + +sub add_remote { + my ($name, $url) = @_; + if (exists $remote->{$name}) { + print STDERR "remote $name already exists.\n"; + exit(1); + } + $git->command('repo-config', "remote.$name.url", $url); + $git->command('repo-config', "remote.$name.fetch", + "+refs/heads/*:refs/remotes/$name/*"); +} + +if (!@ARGV) { + for (sort keys %$remote) { + print "$_\n"; + } +} +elsif ($ARGV[0] eq 'show') { + my $ls_remote = 1; + my $i; + for ($i = 1; $i < @ARGV; $i++) { + if ($ARGV[$i] eq '-n') { + $ls_remote = 0; + } + else { + last; + } + } + if ($i >= @ARGV) { + print STDERR "Usage: git remote show <remote>\n"; + exit(1); + } + for (; $i < @ARGV; $i++) { + show_remote($ARGV[$i], $ls_remote); + } +} +elsif ($ARGV[0] eq 'add') { + if (@ARGV != 3) { + print STDERR "Usage: git remote add <name> <url>\n"; + exit(1); + } + add_remote($ARGV[1], $ARGV[2]); +} + diff --git a/git-reset.sh b/git-reset.sh index a9693701a3..76c8a818d4 100755 --- a/git-reset.sh +++ b/git-reset.sh @@ -44,8 +44,10 @@ if test $# != 0 then test "$reset_type" == "--mixed" || die "Cannot do partial $reset_type reset." - git ls-tree -r --full-name $rev -- "$@" | - git update-index --add --index-info || exit + + git-diff-index --cached $rev -- "$@" | + sed -e 's/^:\([0-7][0-7]*\) [0-7][0-7]* \([0-9a-f][0-9a-f]*\) [0-9a-f][0-9a-f]* [A-Z] \(.*\)$/\1 \2 \3/' | + git update-index --add --remove --index-info || exit git update-index --refresh exit fi diff --git a/git-svn.perl b/git-svn.perl index b28c5bbc72..1da31fdc7c 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -102,7 +102,7 @@ my %cmt_opts = ( 'edit|e' => \$_edit, ); my %cmd = ( - fetch => [ \&fetch, "Download new revisions from SVN", + fetch => [ \&cmd_fetch, "Download new revisions from SVN", { 'revision|r=s' => \$_revision, %fc_opts } ], init => [ \&init, "Initialize a repo for tracking" . " (requires URL argument)", @@ -293,6 +293,10 @@ sub init { setup_git_svn(); } +sub cmd_fetch { + fetch_child_id($GIT_SVN, @_); +} + sub fetch { check_upgrade_needed(); $SVN_URL ||= file_to_s("$GIT_SVN_DIR/info/url"); @@ -532,7 +536,7 @@ sub show_ignore { my $repo; $SVN ||= libsvn_connect($SVN_URL); my $r = defined $_revision ? $_revision : $SVN->get_latest_revnum; - libsvn_traverse_ignore(\*STDOUT, $SVN->{svn_path}, $r); + libsvn_traverse_ignore(\*STDOUT, '', $r); } sub graft_branches { @@ -571,28 +575,25 @@ sub graft_branches { sub multi_init { my $url = shift; - $_trunk ||= 'trunk'; - $_trunk =~ s#/+$##; - $url =~ s#/+$## if $url; - if ($_trunk !~ m#^[a-z\+]+://#) { - $_trunk = '/' . $_trunk if ($_trunk !~ m#^/#); - unless ($url) { - print STDERR "E: '$_trunk' is not a complete URL ", - "and a separate URL is not specified\n"; - exit 1; - } - $_trunk = $url . $_trunk; + unless (defined $_trunk || defined $_branches || defined $_tags) { + usage(1); } - my $ch_id; - if ($GIT_SVN eq 'git-svn') { - $ch_id = 1; - $GIT_SVN = $ENV{GIT_SVN_ID} = 'trunk'; - } - init_vars(); - unless (-d $GIT_SVN_DIR) { - print "GIT_SVN_ID set to 'trunk' for $_trunk\n" if $ch_id; - init($_trunk); - command_noisy('repo-config', 'svn.trunk', $_trunk); + if (defined $_trunk) { + my $trunk_url = complete_svn_url($url, $_trunk); + my $ch_id; + if ($GIT_SVN eq 'git-svn') { + $ch_id = 1; + $GIT_SVN = $ENV{GIT_SVN_ID} = 'trunk'; + } + init_vars(); + unless (-d $GIT_SVN_DIR) { + if ($ch_id) { + print "GIT_SVN_ID set to 'trunk' for ", + "$trunk_url ($_trunk)\n"; + } + init($trunk_url); + command_noisy('repo-config', 'svn.trunk', $trunk_url); + } } complete_url_ls_init($url, $_branches, '--branches/-b', ''); complete_url_ls_init($url, $_tags, '--tags/-t', 'tags/'); @@ -839,7 +840,6 @@ sub fetch_child_id { my $ref = "$GIT_DIR/refs/remotes/$id"; defined(my $pid = open my $fh, '-|') or croak $!; if (!$pid) { - $_repack = undef; $GIT_SVN = $ENV{GIT_SVN_ID} = $id; init_vars(); fetch(@_); @@ -847,7 +847,7 @@ sub fetch_child_id { } while (<$fh>) { print $_; - check_repack() if (/^r\d+ = $sha1/); + check_repack() if (/^r\d+ = $sha1/o); } close $fh or croak $?; } @@ -872,29 +872,34 @@ sub rec_fetch { } } +sub complete_svn_url { + my ($url, $path) = @_; + $path =~ s#/+$##; + $url =~ s#/+$## if $url; + if ($path !~ m#^[a-z\+]+://#) { + $path = '/' . $path if ($path !~ m#^/#); + if (!defined $url || $url !~ m#^[a-z\+]+://#) { + fatal("E: '$path' is not a complete URL ", + "and a separate URL is not specified\n"); + } + $path = $url . $path; + } + return $path; +} + sub complete_url_ls_init { - my ($url, $var, $switch, $pfx) = @_; - unless ($var) { + my ($url, $path, $switch, $pfx) = @_; + unless ($path) { print STDERR "W: $switch not specified\n"; return; } - $var =~ s#/+$##; - if ($var !~ m#^[a-z\+]+://#) { - $var = '/' . $var if ($var !~ m#^/#); - unless ($url) { - print STDERR "E: '$var' is not a complete URL ", - "and a separate URL is not specified\n"; - exit 1; - } - $var = $url . $var; - } - my @ls = libsvn_ls_fullurl($var); - my $old = $GIT_SVN; + my $full_url = complete_svn_url($url, $path); + my @ls = libsvn_ls_fullurl($full_url); defined(my $pid = fork) or croak $!; if (!$pid) { - foreach my $u (map { "$var/$_" } (grep m!/$!, @ls)) { + foreach my $u (map { "$full_url/$_" } (grep m!/$!, @ls)) { $u =~ s#/+$##; - if ($u !~ m!\Q$var\E/(.+)$!) { + if ($u !~ m!\Q$full_url\E/(.+)$!) { print STDERR "W: Unrecognized URL: $u\n"; die "This should never happen\n"; } @@ -912,7 +917,7 @@ sub complete_url_ls_init { waitpid $pid, 0; croak $? if $?; my ($n) = ($switch =~ /^--(\w+)/); - command_noisy('repo-config', "svn.$n", $var); + command_noisy('repo-config', "svn.$n", $full_url); } sub common_prefix { @@ -1405,7 +1410,6 @@ sub git_commit { # this output is read via pipe, do not change: print "r$log_msg->{revision} = $commit\n"; - check_repack(); return $commit; } diff --git a/git-svnimport.perl b/git-svnimport.perl index cbaa8ab37c..afbbe63c62 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -31,12 +31,13 @@ $SIG{'PIPE'}="IGNORE"; $ENV{'TZ'}="UTC"; our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T, - $opt_b,$opt_r,$opt_I,$opt_A,$opt_s,$opt_l,$opt_d,$opt_D,$opt_S,$opt_F,$opt_P); + $opt_b,$opt_r,$opt_I,$opt_A,$opt_s,$opt_l,$opt_d,$opt_D,$opt_S,$opt_F, + $opt_P,$opt_R); sub usage() { print STDERR <<END; Usage: ${\basename $0} # fetch/update GIT from SVN - [-o branch-for-HEAD] [-h] [-v] [-l max_rev] + [-o branch-for-HEAD] [-h] [-v] [-l max_rev] [-R repack_each_revs] [-C GIT_repository] [-t tagname] [-T trunkname] [-b branchname] [-d|-D] [-i] [-u] [-r] [-I ignorefilename] [-s start_chg] [-m] [-M regex] [-A author_file] [-S] [-F] [-P project_name] [SVN_URL] @@ -44,7 +45,7 @@ END exit(1); } -getopts("A:b:C:dDFhiI:l:mM:o:rs:t:T:SP:uv") or usage(); +getopts("A:b:C:dDFhiI:l:mM:o:rs:t:T:SP:R:uv") or usage(); usage if $opt_h; my $tag_name = $opt_t || "tags"; @@ -52,6 +53,7 @@ my $trunk_name = $opt_T || "trunk"; my $branch_name = $opt_b || "branches"; my $project_name = $opt_P || ""; $project_name = "/" . $project_name if ($project_name); +my $repack_after = $opt_R || 1000; @ARGV == 1 or @ARGV == 2 or usage(); @@ -146,6 +148,7 @@ sub file { print "... $rev $path ...\n" if $opt_v; my (undef, $properties); my $pool = SVN::Pool->new(); + $path =~ s#^/*##; eval { (undef, $properties) = $self->{'svn'}->get_file($path,$rev,$fh,$pool); }; $pool->clear; @@ -181,6 +184,7 @@ sub ignore { my($self,$path,$rev) = @_; print "... $rev $path ...\n" if $opt_v; + $path =~ s#^/*##; my (undef,undef,$properties) = $self->{'svn'}->get_dir($path,$rev,undef); if (exists $properties->{'svn:ignore'}) { @@ -197,6 +201,7 @@ sub ignore { sub dir_list { my($self,$path,$rev) = @_; + $path =~ s#^/*##; my ($dirents,undef,$properties) = $self->{'svn'}->get_dir($path,$rev,undef); return $dirents; @@ -354,6 +359,7 @@ open BRANCHES,">>", "$git_dir/svn2git"; sub node_kind($$) { my ($svnpath, $revision) = @_; my $pool=SVN::Pool->new; + $svnpath =~ s#^/*##; my $kind = $svn->{'svn'}->check_path($svnpath,$revision,$pool); $pool->clear; return $kind; @@ -934,11 +940,27 @@ if ($opt_l < $current_rev) { exit; } -print "Fetching from $current_rev to $opt_l ...\n" if $opt_v; +print "Processing from $current_rev to $opt_l ...\n" if $opt_v; -my $pool=SVN::Pool->new; -$svn->{'svn'}->get_log("/",$current_rev,$opt_l,0,1,1,\&commit_all,$pool); -$pool->clear; +my $from_rev; +my $to_rev = $current_rev; + +while ($to_rev < $opt_l) { + $from_rev = $to_rev; + $to_rev = $from_rev + $repack_after; + $to_rev = $opt_l if $opt_l < $to_rev; + print "Fetching from $from_rev to $to_rev ...\n" if $opt_v; + my $pool=SVN::Pool->new; + $svn->{'svn'}->get_log("/",$from_rev,$to_rev,0,1,1,\&commit_all,$pool); + $pool->clear; + my $pid = fork(); + die "Fork: $!\n" unless defined $pid; + unless($pid) { + exec("git-repack", "-d") + or die "Cannot repack: $!\n"; + } + waitpid($pid, 0); +} unlink($git_index); diff --git a/git-tag.sh b/git-tag.sh index e1bfa82f1e..ecb9100e4b 100755 --- a/git-tag.sh +++ b/git-tag.sh @@ -1,7 +1,7 @@ #!/bin/sh # Copyright (c) 2005 Linus Torvalds -USAGE='-l [<pattern>] | [-a | -s | -u <key-id>] [-f | -d] [-m <msg>] <tagname> [<head>]' +USAGE='-l [<pattern>] | [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg>] <tagname> [<head>]' SUBDIRECTORY_OK='Yes' . git-sh-setup @@ -12,6 +12,7 @@ force= message= username= list= +verify= while case "$#" in 0) break ;; esac do case "$1" in @@ -69,6 +70,14 @@ do echo "Deleted tag $tag_name." exit $? ;; + -v) + shift + tag_name="$1" + tag=$(git-show-ref --verify --hash -- "refs/tags/$tag_name") || + die "Seriously, what tag are you talking about?" + git-verify-tag -v "$tag" + exit $? + ;; -*) usage ;; diff --git a/git-verify-tag.sh b/git-verify-tag.sh index 36f171b302..8db7dd0b7d 100755 --- a/git-verify-tag.sh +++ b/git-verify-tag.sh @@ -34,7 +34,10 @@ t) ;; esac +trap 'rm -f "$GIT_DIR/.tmp-vtag"' 0 + git-cat-file tag "$1" >"$GIT_DIR/.tmp-vtag" || exit 1 + cat "$GIT_DIR/.tmp-vtag" | sed '/-----BEGIN PGP/Q' | gpg --verify "$GIT_DIR/.tmp-vtag" - || exit 1 diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index d845e91e20..f46a42296d 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2274,7 +2274,7 @@ sub git_difftree_body { my $mode_chnge = ""; if ($diff{'from_mode'} != $diff{'to_mode'}) { $mode_chnge = "<span class=\"file_status mode_chnge\">[changed"; - if ($from_file_type != $to_file_type) { + if ($from_file_type ne $to_file_type) { $mode_chnge .= " from $from_file_type to $to_file_type"; } if (($from_mode_oct & 0777) != ($to_mode_oct & 0777)) { @@ -2378,7 +2378,6 @@ sub git_patchset_body { my $patch_line; my $diffinfo; my (%from, %to); - my ($from_id, $to_id); print "<div class=\"patchset\">\n"; @@ -2392,6 +2391,7 @@ sub git_patchset_body { PATCH: while ($patch_line) { my @diff_header; + my ($from_id, $to_id); # git diff header #assert($patch_line =~ m/^diff /) if DEBUG; @@ -2403,7 +2403,7 @@ sub git_patchset_body { while ($patch_line = <$fd>) { chomp $patch_line; - last EXTENDED_HEADER if ($patch_line =~ m/^--- /); + last EXTENDED_HEADER if ($patch_line =~ m/^--- |^diff /); if ($patch_line =~ m/^index ([0-9a-fA-F]{40})..([0-9a-fA-F]{40})/) { $from_id = $1; @@ -2439,11 +2439,15 @@ sub git_patchset_body { $from{'href'} = href(action=>"blob", hash_base=>$hash_parent, hash=>$diffinfo->{'from_id'}, file_name=>$from{'file'}); + } else { + delete $from{'href'}; } if ($diffinfo->{'status'} ne "D") { # not deleted file $to{'href'} = href(action=>"blob", hash_base=>$hash, hash=>$diffinfo->{'to_id'}, file_name=>$to{'file'}); + } else { + delete $to{'href'}; } # this is first patch for raw difftree line with $patch_idx index # we index @$difftree array from 0, but number patches from 1 @@ -2475,11 +2479,11 @@ sub git_patchset_body { # match <path> if ($patch_line =~ s!^((copy|rename) from ).*$!$1! && $from{'href'}) { $patch_line .= $cgi->a({-href=>$from{'href'}, -class=>"path"}, - esc_path($from{'file'})); + esc_path($from{'file'})); } if ($patch_line =~ s!^((copy|rename) to ).*$!$1! && $to{'href'}) { - $patch_line = $cgi->a({-href=>$to{'href'}, -class=>"path"}, - esc_path($to{'file'})); + $patch_line .= $cgi->a({-href=>$to{'href'}, -class=>"path"}, + esc_path($to{'file'})); } # match <mode> if ($patch_line =~ m/\s(\d{6})$/) { @@ -2518,8 +2522,10 @@ sub git_patchset_body { # from-file/to-file diff header $patch_line = $last_patch_line; + last PATCH unless $patch_line; + next PATCH if ($patch_line =~ m/^diff /); #assert($patch_line =~ m/^---/) if DEBUG; - if ($from{'href'}) { + if ($from{'href'} && $patch_line =~ m!^--- "?a/!) { $patch_line = '--- a/' . $cgi->a({-href=>$from{'href'}, -class=>"path"}, esc_path($from{'file'})); @@ -2531,7 +2537,7 @@ sub git_patchset_body { chomp $patch_line; #assert($patch_line =~ m/^+++/) if DEBUG; - if ($to{'href'}) { + if ($to{'href'} && $patch_line =~ m!^\+\+\+ "?b/!) { $patch_line = '+++ b/' . $cgi->a({-href=>$to{'href'}, -class=>"path"}, esc_path($to{'file'})); @@ -2813,8 +2819,12 @@ sub git_tags_body { print "<tr class=\"light\">\n"; } $alternate ^= 1; - print "<td><i>$tag{'age'}</i></td>\n" . - "<td>" . + if (defined $tag{'age'}) { + print "<td><i>$tag{'age'}</i></td>\n"; + } else { + print "<td></td>\n"; + } + print "<td>" . $cgi->a({-href => href(action=>$tag{'reftype'}, hash=>$tag{'refid'}), -class => "list name"}, esc_html($tag{'name'})) . "</td>\n" . @@ -2995,7 +3005,7 @@ sub git_project_index { foreach my $pr (@projects) { if (!exists $pr->{'owner'}) { - $pr->{'owner'} = get_file_owner("$projectroot/$project"); + $pr->{'owner'} = get_file_owner("$projectroot/$pr->{'path'}"); } my ($path, $owner) = ($pr->{'path'}, $pr->{'owner'}); @@ -3208,9 +3218,14 @@ HTML esc_html($rev)); print "</td>\n"; } + open (my $dd, "-|", git_cmd(), "rev-parse", "$full_rev^") + or die_error("could not open git-rev-parse"); + my $parent_commit = <$dd>; + close $dd; + chomp($parent_commit); my $blamed = href(action => 'blame', file_name => $meta->{'filename'}, - hash_base => $full_rev); + hash_base => $parent_commit); print "<td class=\"linenr\">"; print $cgi->a({ -href => "$blamed#l$orig_lineno", -id => "l$lineno", @@ -4423,7 +4438,7 @@ sub git_shortlog { } my $refs = git_get_references(); - my @commitlist = parse_commits($head, 101, (100 * $page)); + my @commitlist = parse_commits($hash, 101, (100 * $page)); my $paging_nav = format_paging_nav('shortlog', $hash, $head, $page, (100 * ($page+1))); my $next_link = ''; diff --git a/lockfile.c b/lockfile.c index 261baff049..4824f4dc02 100644 --- a/lockfile.c +++ b/lockfile.c @@ -27,9 +27,12 @@ static int lock_file(struct lock_file *lk, const char *path) sprintf(lk->filename, "%s.lock", path); fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); if (0 <= fd) { - if (!lk->next) { + if (!lk->on_list) { lk->next = lock_file_list; lock_file_list = lk; + lk->on_list = 1; + } + if (lock_file_list) { signal(SIGINT, remove_lock_file_on_signal); atexit(remove_lock_file); } @@ -37,6 +40,8 @@ static int lock_file(struct lock_file *lk, const char *path) return error("cannot fix permission bits on %s", lk->filename); } + else + lk->filename[0] = 0; return fd; } @@ -44,7 +49,7 @@ int hold_lock_file_for_update(struct lock_file *lk, const char *path, int die_on { int fd = lock_file(lk, path); if (fd < 0 && die_on_error) - die("unable to create '%s': %s", path, strerror(errno)); + die("unable to create '%s.lock': %s", path, strerror(errno)); return fd; } diff --git a/pack-check.c b/pack-check.c index c0caaee093..8e123b71ed 100644 --- a/pack-check.c +++ b/pack-check.c @@ -1,16 +1,18 @@ #include "cache.h" #include "pack.h" +#define BATCH (1u<<20) + static int verify_packfile(struct packed_git *p) { unsigned long index_size = p->index_size; void *index_base = p->index_base; SHA_CTX ctx; unsigned char sha1[20]; - unsigned long pack_size = p->pack_size; - void *pack_base; struct pack_header *hdr; int nr_objects, err, i; + unsigned char *packdata; + unsigned long datasize; /* Header consistency check */ hdr = p->pack_base; @@ -25,11 +27,19 @@ static int verify_packfile(struct packed_git *p) "while idx size expects %d", nr_objects, num_packed_objects(p)); + /* Check integrity of pack data with its SHA-1 checksum */ SHA1_Init(&ctx); - pack_base = p->pack_base; - SHA1_Update(&ctx, pack_base, pack_size - 20); + packdata = p->pack_base; + datasize = p->pack_size - 20; + while (datasize) { + unsigned long batch = (datasize < BATCH) ? datasize : BATCH; + SHA1_Update(&ctx, packdata, batch); + datasize -= batch; + packdata += batch; + } SHA1_Final(sha1, &ctx); - if (hashcmp(sha1, (unsigned char *)pack_base + pack_size - 20)) + + if (hashcmp(sha1, (unsigned char *)(p->pack_base) + p->pack_size - 20)) return error("Packfile %s SHA1 mismatch with itself", p->pack_name); if (hashcmp(sha1, (unsigned char *)index_base + index_size - 40)) @@ -726,7 +726,6 @@ static int repack_without_ref(const char *refname) } if (!found) return 0; - memset(&packlock, 0, sizeof(packlock)); fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0); if (fd < 0) return error("cannot delete '%s' from packed refs", refname); diff --git a/t/test-lib.sh b/t/test-lib.sh index bf108d4226..72ea2b2598 100755 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -99,12 +99,12 @@ trap 'echo >&5 "FATAL: Unexpected exit with code $?"; exit 1' exit test_tick () { if test -z "${test_tick+set}" then - test_tick=432630000 + test_tick=1112911993 else test_tick=$(($test_tick + 60)) fi - GIT_COMMITTER_DATE=$test_tick - GIT_AUTHOR_DATE=$test_tick + GIT_COMMITTER_DATE="$test_tick -0700" + GIT_AUTHOR_DATE="$test_tick -0700" export GIT_COMMITTER_DATE GIT_AUTHOR_DATE } diff --git a/tree-walk.c b/tree-walk.c index 14cc5aea6c..22f4550b6c 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -113,7 +113,6 @@ void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callb struct name_entry *entry = xmalloc(n*sizeof(*entry)); for (;;) { - struct name_entry entry[3]; unsigned long mask = 0; int i, last; |