diff options
131 files changed, 3174 insertions, 961 deletions
diff --git a/Documentation/RelNotes/2.0.1.txt b/Documentation/RelNotes/2.0.1.txt new file mode 100644 index 0000000000..ce5579db3e --- /dev/null +++ b/Documentation/RelNotes/2.0.1.txt @@ -0,0 +1,115 @@ +Git v2.0.1 Release Notes +======================== + + * We used to unconditionally disable the pager in the pager process + we spawn to feed out output, but that prevented people who want to + run "less" within "less" from doing so. + + * Tools that read diagnostic output in our standard error stream do + not want to see terminal control sequence (e.g. erase-to-eol). + Detect them by checking if the standard error stream is connected + to a tty. + * Reworded the error message given upon a failure to open an existing + loose object file due to e.g. permission issues; it was reported as + the object being corrupt, but that is not quite true. + + * "git log -2master" is a common typo that shows two commits starting + from whichever random branch that is not 'master' that happens to + be checked out currently. + + * The "%<(10,trunc)%s" pretty format specifier in the log family of + commands is used to truncate the string to a given length (e.g. 10 + in the example) with padding to column-align the output, but did + not take into account that number of bytes and number of display + columns are different. + + * The "mailmap.file" configuration option did not support the tilde + expansion (i.e. ~user/path and ~/path). + + * The completion scripts (in contrib/) did not know about quite a few + options that are common between "git merge" and "git pull", and a + couple of options unique to "git merge". + + * "--ignore-space-change" option of "git apply" ignored the spaces + at the beginning of line too aggressively, which is inconsistent + with the option of the same name "diff" and "git diff" have. + + * "git blame" miscounted number of columns needed to show localized + timestamps, resulting in jaggy left-side-edge of the source code + lines in its output. + + * "git blame" assigned the blame to the copy in the working-tree if + the repository is set to core.autocrlf=input and the file used CRLF + line endings. + + * "git commit --allow-empty-message -C $commit" did not work when the + commit did not have any log message. + + * "git diff --find-copies-harder" sometimes pretended as if the mode + bits have changed for paths that are marked with assume-unchanged + bit. + + * "git format-patch" did not enforce the rule that the "--follow" + option from the log/diff family of commands must be used with + exactly one pathspec. + + * "git gc --auto" was recently changed to run in the background to + give control back early to the end-user sitting in front of the + terminal, but it forgot that housekeeping involving reflogs should + be done without other processes competing for accesses to the refs. + + * "git grep -O" to show the lines that hit in the pager did not work + well with case insensitive search. We now spawn "less" with its + "-I" option when it is used as the pager (which is the default). + + * We used to disable threaded "git index-pack" on platforms without + thread-safe pread(); use a different workaround for such + platforms to allow threaded "git index-pack". + + * The error reporting from "git index-pack" has been improved to + distinguish missing objects from type errors. + + * "git mailinfo" used to read beyond the end of header string while + parsing an incoming e-mail message to extract the patch. + + * On a case insensitive filesystem, merge-recursive incorrectly + deleted the file that is to be renamed to a name that is the same + except for case differences. + + * "git pack-objects" unnecessarily copied the previous contents when + extending the hashtable, even though it will populate the table + from scratch anyway. + + * "git rerere forget" did not work well when merge.conflictstyle + was set to a non-default value. + + * "git remote rm" and "git remote prune" can involve removing many + refs at once, which is not a very efficient thing to do when very + many refs exist in the packed-refs file. + + * "git log --exclude=<glob> --all | git shortlog" worked as expected, + but "git shortlog --exclude=<glob> --all", which is supposed to be + identical to the above pipeline, was not accepted at the command + line argument parser level. + + * The autostash mode of "git rebase -i" did not restore the dirty + working tree state if the user aborted the interactive rebase by + emptying the insn sheet. + + * "git show -s" (i.e. show log message only) used to incorrectly emit + an extra blank line after a merge commit. + + * "git status", even though it is a read-only operation, tries to + update the index with refreshed lstat(2) info to optimize future + accesses to the working tree opportunistically, but this could + race with a "read-write" operation that modify the index while it + is running. Detect such a race and avoid overwriting the index. + + * "git status" (and "git commit") behaved as if changes in a modified + submodule are not there if submodule.*.ignore configuration is set, + which was misleading. The configuration is only to unclutter diff + output during the course of development, and should not to hide + changes in the "status" output to cause the users forget to commit + them. + + * The mode to run tests with HTTP server tests disabled was broken. diff --git a/Documentation/RelNotes/2.1.0.txt b/Documentation/RelNotes/2.1.0.txt index 17360e5d53..828a439dc1 100644 --- a/Documentation/RelNotes/2.1.0.txt +++ b/Documentation/RelNotes/2.1.0.txt @@ -37,11 +37,14 @@ UI, Workflows & Features shorter than a page). * The logic and data used to compute the display width needed for - UTF-8 strings have been updated to match Unicode 6.3 better. + UTF-8 strings have been updated to match Unicode 7.0 better. * HTTP-based transports learned to propagate the error messages from the webserver better to the client coming over the HTTP transport. + * The completion script for bash (in contrib/) has been updated to + handle aliases that define complex sequence of commands better. + * The "core.preloadindex" configuration variable is by default enabled, allowing modern platforms to take advantage of the multiple cores they have. @@ -92,6 +95,10 @@ UI, Workflows & Features * "git replace" learned the "--edit" subcommand. + * "git send-email" learned "--to-cover" and "--cc-cover" options, to + tell it to copy To: and Cc: headers found in the first input file + when emitting later input files. + * "git svn" learned to cope with malformed timestamps with only one digit in the hour part, e.g. 2014-01-07T5:01:02.048176Z, emitted by some broken subversion server implementations. @@ -147,13 +154,18 @@ notes for details). * Mishandling of patterns in .gitignore that has trailing SPs quoted with backslashes (e.g. ones that end with "\ ") have been corrected. - (merge e61a6c1 pb/trim-trailing-spaces later to maint). + (merge 97c1364be6b pb/trim-trailing-spaces later to maint). * Reworded the error message given upon a failure to open an existing loose object file due to e.g. permission issues; it was reported as the object being corrupt, but that is not quite true. (merge d6c8a05 jk/report-fail-to-read-objects-better later to maint). + * "git log -2master" is a common typo that shows two commits starting + from whichever random branch that is not 'master' that happens to + be checked out currently. + (merge e3fa568 jc/revision-dash-count-parsing later to maint). + * The "%<(10,trunc)%s" pretty format specifier in the log family of commands is used to truncate the string to a given length (e.g. 10 in the example) with padding to column-align the output, but did @@ -233,6 +245,11 @@ notes for details). from scratch anyway. (merge fb79947 rs/pack-objects-no-unnecessary-realloc later to maint). + * Recent updates to "git repack" started to duplicate objects that + are in packfiles marked with .keep flag into the new packfile by + mistake. + (merge d078d85 jk/repack-pack-keep-objects later to maint). + * "git rerere forget" did not work well when merge.conflictstyle was set to a non-default value. (merge de3d8bb fc/rerere-conflict-style later to maint). @@ -272,6 +289,10 @@ notes for details). them. (merge c215d3d jl/status-added-submodule-is-never-ignored later to maint). + * Documentation for "git submodule sync" forgot to say that the subcommand + can take the "--recursive" option. + (merge 9393ae7 mc/doc-submodule-sync-recurse later to maint). + * "git update-index --cacheinfo" in 2.0 release crashed on a malformed command line. (merge c8e1ee4 jc/rev-parse-argh-dashed-multi-words later to maint). diff --git a/Documentation/config.txt b/Documentation/config.txt index 9f467d3820..1d718bdb96 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1905,12 +1905,7 @@ pack.useBitmaps:: you are debugging pack bitmaps. pack.writebitmaps:: - When true, git will write a bitmap index when packing all - objects to disk (e.g., when `git repack -a` is run). This - index can speed up the "counting objects" phase of subsequent - packs created for clones and fetches, at the cost of some disk - space and extra time spent on the initial repack. Defaults to - false. + This is a deprecated synonym for `repack.writeBitmaps`. pack.writeBitmapHashCache:: When true, git will include a "hash cache" section in the bitmap @@ -2187,7 +2182,15 @@ repack.packKeptObjects:: `--pack-kept-objects` was passed. See linkgit:git-repack[1] for details. Defaults to `false` normally, but `true` if a bitmap index is being written (either via `--write-bitmap-index` or - `pack.writeBitmaps`). + `repack.writeBitmaps`). + +repack.writeBitmaps:: + When true, git will write a bitmap index when packing all + objects to disk (e.g., when `git repack -a` is run). This + index can speed up the "counting objects" phase of subsequent + packs created for clones and fetches, at the cost of some disk + space and extra time spent on the initial repack. Defaults to + false. rerere.autoupdate:: When set to true, `git-rerere` updates the index with the diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt index 92c68c3fda..b09a783ee3 100644 --- a/Documentation/fetch-options.txt +++ b/Documentation/fetch-options.txt @@ -72,6 +72,14 @@ endif::git-pull[] setting. See linkgit:git-config[1]. ifndef::git-pull[] +--refmap=<refspec>:: + When fetching refs listed on the command line, use the + specified refspec (can be given more than once) to map the + refs to remote-tracking branches, instead of the values of + `remote.*.fetch` configuration variables for the remote + repository. See section on "Configured Remote-tracking + Branches" for details. + -t:: --tags:: Fetch all tags from the remote (i.e., fetch remote tags diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt index 5809aa4eb9..8deb61469d 100644 --- a/Documentation/git-fetch.txt +++ b/Documentation/git-fetch.txt @@ -17,22 +17,20 @@ SYNOPSIS DESCRIPTION ----------- -Fetches named heads or tags from one or more other repositories, -along with the objects necessary to complete them. +Fetch branches and/or tags (collectively, "refs") from one or more +other repositories, along with the objects necessary to complete their +histories. Remote-tracking branches are updated (see the description +of <refspec> below for ways to control this behavior). -The ref names and their object names of fetched refs are stored -in `.git/FETCH_HEAD`. This information is left for a later merge -operation done by 'git merge'. - -By default, tags are auto-followed. This means that when fetching -from a remote, any tags on the remote that point to objects that exist -in the local repository are fetched. The effect is to fetch tags that +By default, any tag that points into the histories being fetched is +also fetched; the effect is to fetch tags that point at branches that you are interested in. This default behavior -can be changed by using the --tags or --no-tags options, by -configuring remote.<name>.tagopt, or by using a refspec that fetches -tags explicitly. +can be changed by using the --tags or --no-tags options or by +configuring remote.<name>.tagopt. By using a refspec that fetches tags +explicitly, you can fetch tags that do not point into branches you +are interested in as well. -'git fetch' can fetch from either a single named repository, +'git fetch' can fetch from either a single named repository or URL, or from several repositories at once if <group> is given and there is a remotes.<group> entry in the configuration file. (See linkgit:git-config[1]). @@ -40,6 +38,10 @@ there is a remotes.<group> entry in the configuration file. When no remote is specified, by default the `origin` remote will be used, unless there's an upstream branch configured for the current branch. +The names of refs that are fetched, together with the object names +they point at, are written to `.git/FETCH_HEAD`. This information +may be used by scripts or other git commands, such as linkgit:git-pull[1]. + OPTIONS ------- include::fetch-options.txt[] @@ -49,6 +51,55 @@ include::pull-fetch-param.txt[] include::urls-remotes.txt[] +CONFIGURED REMOTE-TRACKING BRANCHES[[CRTB]] +------------------------------------------- + +You often interact with the same remote repository by +regularly and repeatedly fetching from it. In order to keep track +of the progress of such a remote repository, `git fetch` allows you +to configure `remote.<repository>.fetch` configuration variables. + +Typically such a variable may look like this: + +------------------------------------------------ +[remote "origin"] + fetch = +refs/heads/*:refs/remotes/origin/* +------------------------------------------------ + +This configuration is used in two ways: + +* When `git fetch` is run without specifying what branches + and/or tags to fetch on the command line, e.g. `git fetch origin` + or `git fetch`, `remote.<repository>.fetch` values are used as + the refspecs---they specify which refs to fetch and which local refs + to update. The example above will fetch + all branches that exist in the `origin` (i.e. any ref that matches + the left-hand side of the value, `refs/heads/*`) and update the + corresponding remote-tracking branches in the `refs/remotes/origin/*` + hierarchy. + +* When `git fetch` is run with explicit branches and/or tags + to fetch on the command line, e.g. `git fetch origin master`, the + <refspec>s given on the command line determine what are to be + fetched (e.g. `master` in the example, + which is a short-hand for `master:`, which in turn means + "fetch the 'master' branch but I do not explicitly say what + remote-tracking branch to update with it from the command line"), + and the example command will + fetch _only_ the 'master' branch. The `remote.<repository>.fetch` + values determine which + remote-tracking branch, if any, is updated. When used in this + way, the `remote.<repository>.fetch` values do not have any + effect in deciding _what_ gets fetched (i.e. the values are not + used as refspecs when the command-line lists refspecs); they are + only used to decide _where_ the refs that are fetched are stored + by acting as a mapping. + +The latter use of the `remote.<repository>.fetch` values can be +overridden by giving the `--refmap=<refspec>` parameter(s) on the +command line. + + EXAMPLES -------- @@ -76,6 +127,19 @@ the local repository by fetching from the branches (respectively) The `pu` branch will be updated even if it is does not fast-forward, because it is prefixed with a plus sign; `tmp` will not be. +* Peek at a remote's branch, without configuring the remote in your local +repository: ++ +------------------------------------------------ +$ git fetch git://git.kernel.org/pub/scm/git/git.git maint +$ git log FETCH_HEAD +------------------------------------------------ ++ +The first command fetches the `maint` branch from the repository at +`git://git.kernel.org/pub/scm/git/git.git` and the second command uses +`FETCH_HEAD` to examine the branch with linkgit:git-log[1]. The fetched +objects will eventually be removed by git's built-in housekeeping (see +linkgit:git-gc[1]). BUGS ---- diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index d0fa18aaa8..a60776eb57 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -248,6 +248,18 @@ Automating cc list. Default is the value of 'sendemail.signedoffbycc' configuration value; if that is unspecified, default to --signed-off-by-cc. +--[no-]cc-cover:: + If this is set, emails found in Cc: headers in the first patch of + the series (typically the cover letter) are added to the cc list + for each email set. Default is the value of 'sendemail.cccover' + configuration value; if that is unspecified, default to --no-cc-cover. + +--[no-]to-cover:: + If this is set, emails found in To: headers in the first patch of + the series (typically the cover letter) are added to the to list + for each email set. Default is the value of 'sendemail.tocover' + configuration value; if that is unspecified, default to --no-to-cover. + --suppress-cc=<category>:: Specify an additional category of recipients to suppress the auto-cc of: diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index 89c4d3e394..8e6af65da0 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -20,7 +20,7 @@ SYNOPSIS 'git submodule' [--quiet] summary [--cached|--files] [(-n|--summary-limit) <n>] [commit] [--] [<path>...] 'git submodule' [--quiet] foreach [--recursive] <command> -'git submodule' [--quiet] sync [--] [<path>...] +'git submodule' [--quiet] sync [--recursive] [--] [<path>...] DESCRIPTION diff --git a/Documentation/git.txt b/Documentation/git.txt index 3bd68b0167..7924209671 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,10 @@ unreleased) version of Git, that is available from the 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v2.0.0/git.html[documentation for release 2.0] +* link:v2.0.1/git.html[documentation for release 2.0.1] * release notes for + link:RelNotes/2.0.1.txt[2.0.1], link:RelNotes/2.0.0.txt[2.0.0]. * link:v1.9.4/git.html[documentation for release 1.9.4] diff --git a/Documentation/pull-fetch-param.txt b/Documentation/pull-fetch-param.txt index 18cffc25b8..1ebbf1d738 100644 --- a/Documentation/pull-fetch-param.txt +++ b/Documentation/pull-fetch-param.txt @@ -12,9 +12,23 @@ ifndef::git-pull[] endif::git-pull[] <refspec>:: - The format of a <refspec> parameter is an optional plus - `+`, followed by the source ref <src>, followed - by a colon `:`, followed by the destination ref <dst>. + Specifies which refs to fetch and which local refs to update. + When no <refspec>s appear on the command line, the refs to fetch + are read from `remote.<repository>.fetch` variables instead +ifndef::git-pull[] + (see <<CRTB,CONFIGURED REMOTE-TRACKING BRANCHES>> below). +endif::git-pull[] +ifdef::git-pull[] + (see linkgit:git-fetch[1]). +endif::git-pull[] ++ +The format of a <refspec> parameter is an optional plus +`+`, followed by the source ref <src>, followed +by a colon `:`, followed by the destination ref <dst>. +The colon can be omitted when <dst> is empty. ++ +`tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`; +it requests fetching everything up to the given tag. + The remote ref that matches <src> is fetched, and if <dst> is not empty string, the local @@ -24,55 +38,34 @@ is updated even if it does not result in a fast-forward update. + [NOTE] -If the remote branch from which you want to pull is -modified in non-linear ways such as being rewound and -rebased frequently, then a pull will attempt a merge with -an older version of itself, likely conflict, and fail. -It is under these conditions that you would want to use -the `+` sign to indicate non-fast-forward updates will -be needed. There is currently no easy way to determine -or declare that a branch will be made available in a -repository with this behavior; the pulling user simply +When the remote branch you want to fetch is known to +be rewound and rebased regularly, it is expected that +its new tip will not be descendant of its previous tip +(as stored in your remote-tracking branch the last time +you fetched). You would want +to use the `+` sign to indicate non-fast-forward updates +will be needed for such branches. There is no way to +determine or declare that a branch will be made available +in a repository with this behavior; the pulling user simply must know this is the expected usage pattern for a branch. -+ -[NOTE] -You never do your own development on branches that appear -on the right hand side of a <refspec> colon on `Pull:` lines; -they are to be updated by 'git fetch'. If you intend to do -development derived from a remote branch `B`, have a `Pull:` -line to track it (i.e. `Pull: B:remote-B`), and have a separate -branch `my-B` to do your development on top of it. The latter -is created by `git branch my-B remote-B` (or its equivalent `git -checkout -b my-B remote-B`). Run `git fetch` to keep track of -the progress of the remote side, and when you see something new -on the remote branch, merge it into your development branch with -`git pull . remote-B`, while you are on `my-B` branch. +ifdef::git-pull[] + [NOTE] There is a difference between listing multiple <refspec> directly on 'git pull' command line and having multiple -`Pull:` <refspec> lines for a <repository> and running +`remote.<repository>.fetch` entries in your configuration +for a <repository> and running a 'git pull' command without any explicit <refspec> parameters. -<refspec> listed explicitly on the command line are always +<refspec>s listed explicitly on the command line are always merged into the current branch after fetching. In other words, -if you list more than one remote refs, you would be making -an Octopus. While 'git pull' run without any explicit <refspec> -parameter takes default <refspec>s from `Pull:` lines, it -merges only the first <refspec> found into the current branch, -after fetching all the remote refs. This is because making an +if you list more than one remote ref, 'git pull' will create +an Octopus merge. On the other hand, if you do not list any +explicit <refspec> parameter on the command line, 'git pull' +will fetch all the <refspec>s it finds in the +`remote.<repository>.fetch` configuration and merge +only the first <refspec> found into the current branch. +This is because making an Octopus from remote refs is rarely done, while keeping track of multiple remote heads in one-go by fetching more than one is often useful. -+ -Some short-cut notations are also supported. -+ -* `tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`; - it requests fetching everything up to the given tag. -ifndef::git-pull[] -* A parameter <ref> without a colon fetches that ref into FETCH_HEAD, -endif::git-pull[] -ifdef::git-pull[] -* A parameter <ref> without a colon merges <ref> into the current - branch, endif::git-pull[] - and updates the remote-tracking branches (if any). diff --git a/Documentation/technical/api-strbuf.txt b/Documentation/technical/api-strbuf.txt index 077a7096a4..f9c06a7573 100644 --- a/Documentation/technical/api-strbuf.txt +++ b/Documentation/technical/api-strbuf.txt @@ -7,10 +7,10 @@ use the mem* functions than a str* one (memchr vs. strchr e.g.). Though, one has to be careful about the fact that str* functions often stop on NULs and that strbufs may have embedded NULs. -An strbuf is NUL terminated for convenience, but no function in the +A strbuf is NUL terminated for convenience, but no function in the strbuf API actually relies on the string being free of NULs. -strbufs has some invariants that are very important to keep in mind: +strbufs have some invariants that are very important to keep in mind: . The `buf` member is never NULL, so it can be used in any usual C string operations safely. strbuf's _have_ to be initialized either by @@ -56,8 +56,8 @@ Data structures * `struct strbuf` This is the string buffer structure. The `len` member can be used to -determine the current length of the string, and `buf` member provides access to -the string itself. +determine the current length of the string, and `buf` member provides +access to the string itself. Functions --------- @@ -202,7 +202,7 @@ strbuf_addstr(sb, "immediate string"); `strbuf_addbuf`:: - Copy the contents of an other buffer at the end of the current one. + Copy the contents of another buffer at the end of the current one. `strbuf_adddup`:: diff --git a/Documentation/technical/http-protocol.txt b/Documentation/technical/http-protocol.txt index 59be59b0eb..229f845dfa 100644 --- a/Documentation/technical/http-protocol.txt +++ b/Documentation/technical/http-protocol.txt @@ -60,7 +60,7 @@ Because Git repositories are accessed by standard path components server administrators MAY use directory based permissions within their HTTP server to control repository access. -Clients SHOULD support Basic authentication as described by RFC 2616. +Clients SHOULD support Basic authentication as described by RFC 2617. Servers SHOULD support Basic authentication by relying upon the HTTP server placed in front of the Git server software. @@ -61,9 +61,12 @@ void advise(const char *advice, ...) int git_default_advice_config(const char *var, const char *value) { - const char *k = skip_prefix(var, "advice."); + const char *k; int i; + if (!skip_prefix(var, "advice.", &k)) + return 0; + for (i = 0; i < ARRAY_SIZE(advice_config); i++) { if (strcmp(k, advice_config[i].name)) continue; @@ -5,7 +5,8 @@ static char *alias_val; static int alias_lookup_cb(const char *k, const char *v, void *cb) { - if (starts_with(k, "alias.") && !strcmp(k + 6, alias_key)) { + const char *name; + if (skip_prefix(k, "alias.", &name) && !strcmp(name, alias_key)) { if (!v) return config_error_nonbool(k); alias_val = xstrdup(v); @@ -47,23 +47,32 @@ union any_object { DEFINE_ALLOCATOR(blob, struct blob) DEFINE_ALLOCATOR(tree, struct tree) -DEFINE_ALLOCATOR(commit, struct commit) +DEFINE_ALLOCATOR(raw_commit, struct commit) DEFINE_ALLOCATOR(tag, struct tag) DEFINE_ALLOCATOR(object, union any_object) +void *alloc_commit_node(void) +{ + static int commit_count; + struct commit *c = alloc_raw_commit_node(); + c->index = commit_count++; + return c; +} + static void report(const char *name, unsigned int count, size_t size) { fprintf(stderr, "%10s: %8u (%"PRIuMAX" kB)\n", name, count, (uintmax_t) size); } -#define REPORT(name) \ - report(#name, name##_allocs, name##_allocs * sizeof(struct name) >> 10) +#define REPORT(name, type) \ + report(#name, name##_allocs, name##_allocs * sizeof(type) >> 10) void alloc_report(void) { - REPORT(blob); - REPORT(tree); - REPORT(commit); - REPORT(tag); + REPORT(blob, struct blob); + REPORT(tree, struct tree); + REPORT(raw_commit, struct commit); + REPORT(tag, struct tag); + REPORT(object, union any_object); } @@ -50,11 +50,11 @@ static int should_setup_rebase(const char *origin) void install_branch_config(int flag, const char *local, const char *origin, const char *remote) { - const char *shortname = skip_prefix(remote, "refs/heads/"); + const char *shortname = NULL; struct strbuf key = STRBUF_INIT; int rebasing = should_setup_rebase(origin); - if (shortname + if (skip_prefix(remote, "refs/heads/", &shortname) && !strcmp(local, shortname) && !origin) { warning(_("Not setting branch %s as its own upstream."), diff --git a/builtin/apply.c b/builtin/apply.c index b79691053f..16cc93587f 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -3845,9 +3845,10 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned ce->ce_flags = create_ce_flags(0); ce->ce_namelen = namelen; if (S_ISGITLINK(mode)) { - const char *s = buf; + const char *s; - if (get_sha1_hex(s + strlen("Subproject commit "), ce->sha1)) + if (!skip_prefix(buf, "Subproject commit ", &s) || + get_sha1_hex(s, ce->sha1)) die(_("corrupt patch for submodule %s"), path); } else { if (!cached) { diff --git a/builtin/blame.c b/builtin/blame.c index a52a279144..d3b256e545 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -1655,7 +1655,7 @@ static void get_commit_info(struct commit *commit, { int len; const char *subject, *encoding; - char *message; + const char *message; commit_info_init(ret); @@ -1666,7 +1666,7 @@ static void get_commit_info(struct commit *commit, &ret->author_time, &ret->author_tz); if (!detailed) { - logmsg_free(message, commit); + unuse_commit_buffer(commit, message); return; } @@ -1680,7 +1680,7 @@ static void get_commit_info(struct commit *commit, else strbuf_addf(&ret->summary, "(%s)", sha1_to_hex(commit->object.sha1)); - logmsg_free(message, commit); + unuse_commit_buffer(commit, message); } /* @@ -2008,6 +2008,12 @@ static void output(struct scoreboard *sb, int option) } } +static const char *get_next_line(const char *start, const char *end) +{ + const char *nl = memchr(start, '\n', end - start); + return nl ? nl + 1 : end; +} + /* * To allow quick access to the contents of nth line in the * final image, prepare an index in the scoreboard. @@ -2019,39 +2025,19 @@ static int prepare_lines(struct scoreboard *sb) const char *end = buf + len; const char *p; int *lineno; - int num = 0, incomplete = 0; + int num = 0; - for (p = buf;;) { - p = memchr(p, '\n', end - p); - if (p) { - p++; - num++; - continue; - } - break; - } + for (p = buf; p < end; p = get_next_line(p, end)) + num++; - if (len && end[-1] != '\n') - incomplete++; /* incomplete line at the end */ + sb->lineno = lineno = xmalloc(sizeof(*sb->lineno) * (num + 1)); - sb->lineno = xmalloc(sizeof(*sb->lineno) * (num + incomplete + 1)); - lineno = sb->lineno; + for (p = buf; p < end; p = get_next_line(p, end)) + *lineno++ = p - buf; - *lineno++ = 0; - for (p = buf;;) { - p = memchr(p, '\n', end - p); - if (p) { - p++; - *lineno++ = p - buf; - continue; - } - break; - } + *lineno = len; - if (incomplete) - *lineno++ = len; - - sb->num_lines = num + incomplete; + sb->num_lines = num; return sb->num_lines; } @@ -2266,6 +2252,18 @@ static void append_merge_parents(struct commit_list **tail) } /* + * This isn't as simple as passing sb->buf and sb->len, because we + * want to transfer ownership of the buffer to the commit (so we + * must use detach). + */ +static void set_commit_buffer_from_strbuf(struct commit *c, struct strbuf *sb) +{ + size_t len; + void *buf = strbuf_detach(sb, &len); + set_commit_buffer(c, buf, len); +} + +/* * Prepare a dummy commit that represents the work tree (or staged) item. * Note that annotating work tree item never works in the reverse. */ @@ -2286,7 +2284,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, struct strbuf msg = STRBUF_INIT; time(&now); - commit = xcalloc(1, sizeof(*commit)); + commit = alloc_commit_node(); commit->object.parsed = 1; commit->date = now; commit->object.type = OBJ_COMMIT; @@ -2313,7 +2311,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, ident, ident, path, (!contents_from ? path : (!strcmp(contents_from, "-") ? "standard input" : contents_from))); - commit->buffer = strbuf_detach(&msg, NULL); + set_commit_buffer_from_strbuf(commit, &msg); if (!contents_from || strcmp("-", contents_from)) { struct stat st; diff --git a/builtin/branch.c b/builtin/branch.c index 652b1d2d14..0591b22a48 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -294,13 +294,13 @@ static char *resolve_symref(const char *src, const char *prefix) { unsigned char sha1[20]; int flag; - const char *dst, *cp; + const char *dst; dst = resolve_ref_unsafe(src, sha1, 0, &flag); if (!(dst && (flag & REF_ISSYMREF))) return NULL; - if (prefix && (cp = skip_prefix(dst, prefix))) - dst = cp; + if (prefix) + skip_prefix(dst, prefix, &dst); return xstrdup(dst); } diff --git a/builtin/checkout.c b/builtin/checkout.c index f1dc56e55f..463cfeea50 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -776,8 +776,8 @@ static int switch_branches(const struct checkout_opts *opts, if (!(flag & REF_ISSYMREF)) old.path = NULL; - if (old.path && starts_with(old.path, "refs/heads/")) - old.name = old.path + strlen("refs/heads/"); + if (old.path) + skip_prefix(old.path, "refs/heads/", &old.name); if (!new->name) { new->name = "HEAD"; diff --git a/builtin/clean.c b/builtin/clean.c index 9a9151575d..27701d222c 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -48,7 +48,7 @@ enum color_clean { CLEAN_COLOR_PROMPT = 2, CLEAN_COLOR_HEADER = 3, CLEAN_COLOR_HELP = 4, - CLEAN_COLOR_ERROR = 5, + CLEAN_COLOR_ERROR = 5 }; #define MENU_OPTS_SINGLETON 01 diff --git a/builtin/clone.c b/builtin/clone.c index b12989d1ca..a5b2d9db36 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -584,11 +584,11 @@ static void update_remote_refs(const struct ref *refs, static void update_head(const struct ref *our, const struct ref *remote, const char *msg) { - if (our && starts_with(our->name, "refs/heads/")) { + const char *head; + if (our && skip_prefix(our->name, "refs/heads/", &head)) { /* Local default branch link */ create_symref("HEAD", our->name, NULL); if (!option_bare) { - const char *head = skip_prefix(our->name, "refs/heads/"); update_ref(msg, "HEAD", our->old_sha1, NULL, 0, UPDATE_REFS_DIE_ON_ERR); install_branch_config(0, head, option_origin, our->name); @@ -703,9 +703,12 @@ static void write_refspec_config(const char* src_ref_prefix, strbuf_addf(&value, "+%s:%s%s", our_head_points_at->name, branch_top->buf, option_branch); } else if (remote_head_points_at) { + const char *head = remote_head_points_at->name; + if (!skip_prefix(head, "refs/heads/", &head)) + die("BUG: remote HEAD points at non-head?"); + strbuf_addf(&value, "+%s:%s%s", remote_head_points_at->name, - branch_top->buf, - skip_prefix(remote_head_points_at->name, "refs/heads/")); + branch_top->buf, head); } /* * otherwise, the next "git fetch" will diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c index 987a4c3d73..8a66c74e0f 100644 --- a/builtin/commit-tree.c +++ b/builtin/commit-tree.c @@ -123,8 +123,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) die_errno("git commit-tree: failed to read"); } - if (commit_tree(&buffer, tree_sha1, parents, commit_sha1, - NULL, sign_commit)) { + if (commit_tree(buffer.buf, buffer.len, tree_sha1, parents, + commit_sha1, NULL, sign_commit)) { strbuf_release(&buffer); return 1; } diff --git a/builtin/commit.c b/builtin/commit.c index 5e2221c8e8..461c3b1cad 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -1020,7 +1020,7 @@ static int message_is_empty(struct strbuf *sb) static int template_untouched(struct strbuf *sb) { struct strbuf tmpl = STRBUF_INIT; - char *start; + const char *start; if (cleanup_mode == CLEANUP_NONE && sb->len) return 0; @@ -1029,8 +1029,7 @@ static int template_untouched(struct strbuf *sb) return 0; stripspace(&tmpl, cleanup_mode == CLEANUP_ALL); - start = (char *)skip_prefix(sb->buf, tmpl.buf); - if (!start) + if (!skip_prefix(sb->buf, tmpl.buf, &start)) start = sb->buf; strbuf_release(&tmpl); return rest_is_empty(sb, start - sb->buf); @@ -1745,8 +1744,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) append_merge_tag_headers(parents, &tail); } - if (commit_tree_extended(&sb, active_cache_tree->sha1, parents, sha1, - author_ident.buf, sign_commit, extra)) { + if (commit_tree_extended(sb.buf, sb.len, active_cache_tree->sha1, + parents, sha1, author_ident.buf, sign_commit, extra)) { rollback_index_files(); die(_("failed to write commit object")); } diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c index be6417d166..ce0e019e0c 100644 --- a/builtin/diff-tree.c +++ b/builtin/diff-tree.c @@ -22,14 +22,10 @@ static int stdin_diff_commit(struct commit *commit, char *line, int len) if (isspace(line[40]) && !get_sha1_hex(line+41, sha1)) { /* Graft the fake parents locally to the commit */ int pos = 41; - struct commit_list **pptr, *parents; + struct commit_list **pptr; /* Free the real parent list */ - for (parents = commit->parents; parents; ) { - struct commit_list *tmp = parents->next; - free(parents); - parents = tmp; - } + free_commit_list(commit->parents); commit->parents = NULL; pptr = &(commit->parents); while (line[pos] && !get_sha1_hex(line + pos, sha1)) { diff --git a/builtin/fast-export.c b/builtin/fast-export.c index ef4481615f..92b4624a4b 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -282,6 +282,7 @@ static const char *find_encoding(const char *begin, const char *end) static void handle_commit(struct commit *commit, struct rev_info *rev) { int saved_output_format = rev->diffopt.output_format; + const char *commit_buffer; const char *author, *author_end, *committer, *committer_end; const char *encoding, *message; char *reencoded = NULL; @@ -291,7 +292,8 @@ static void handle_commit(struct commit *commit, struct rev_info *rev) rev->diffopt.output_format = DIFF_FORMAT_CALLBACK; parse_commit_or_die(commit); - author = strstr(commit->buffer, "\nauthor "); + commit_buffer = get_commit_buffer(commit, NULL); + author = strstr(commit_buffer, "\nauthor "); if (!author) die ("Could not find author in commit %s", sha1_to_hex(commit->object.sha1)); @@ -338,6 +340,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev) ? strlen(message) : 0), reencoded ? reencoded : message ? message : ""); free(reencoded); + unuse_commit_buffer(commit, commit_buffer); for (i = 0, p = commit->parents; p; p = p->next) { int mark = get_object_mark(&p->item->object); diff --git a/builtin/fetch.c b/builtin/fetch.c index 40d989f9ff..e8d0cca3e4 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -45,6 +45,8 @@ static struct transport *gsecondary; static const char *submodule_prefix = ""; static const char *recurse_submodules_default; static int shown_url = 0; +static int refmap_alloc, refmap_nr; +static const char **refmap_array; static int option_parse_recurse_submodules(const struct option *opt, const char *arg, int unset) @@ -69,6 +71,19 @@ static int git_fetch_config(const char *k, const char *v, void *cb) return 0; } +static int parse_refmap_arg(const struct option *opt, const char *arg, int unset) +{ + ALLOC_GROW(refmap_array, refmap_nr + 1, refmap_alloc); + + /* + * "git fetch --refmap='' origin foo" + * can be used to tell the command not to store anywhere + */ + if (*arg) + refmap_array[refmap_nr++] = arg; + return 0; +} + static struct option builtin_fetch_options[] = { OPT__VERBOSITY(&verbosity), OPT_BOOL(0, "all", &all, @@ -107,6 +122,8 @@ static struct option builtin_fetch_options[] = { N_("default mode for recursion"), PARSE_OPT_HIDDEN }, OPT_BOOL(0, "update-shallow", &update_shallow, N_("accept refs that update .git/shallow")), + { OPTION_CALLBACK, 0, "refmap", NULL, N_("refmap"), + N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg }, OPT_END() }; @@ -278,6 +295,9 @@ static struct ref *get_ref_map(struct transport *transport, const struct ref *remote_refs = transport_get_remote_refs(transport); if (refspec_count) { + struct refspec *fetch_refspec; + int fetch_refspec_nr; + for (i = 0; i < refspec_count; i++) { get_fetch_map(remote_refs, &refspecs[i], &tail, 0); if (refspecs[i].dst && refspecs[i].dst[0]) @@ -307,12 +327,21 @@ static struct ref *get_ref_map(struct transport *transport, * by ref_remove_duplicates() in favor of one of these * opportunistic entries with FETCH_HEAD_IGNORE. */ - for (i = 0; i < transport->remote->fetch_refspec_nr; i++) - get_fetch_map(ref_map, &transport->remote->fetch[i], - &oref_tail, 1); + if (refmap_array) { + fetch_refspec = parse_fetch_refspec(refmap_nr, refmap_array); + fetch_refspec_nr = refmap_nr; + } else { + fetch_refspec = transport->remote->fetch; + fetch_refspec_nr = transport->remote->fetch_refspec_nr; + } + + for (i = 0; i < fetch_refspec_nr; i++) + get_fetch_map(ref_map, &fetch_refspec[i], &oref_tail, 1); if (tags == TAGS_SET) get_fetch_map(remote_refs, tag_refspec, &tail, 0); + } else if (refmap_array) { + die("--refmap option is only meaningful with command-line refspec(s)."); } else { /* Use the defaults */ struct remote *remote = transport->remote; diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index c462e19e23..79df05ef52 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -100,7 +100,8 @@ static int handle_line(char *line, struct merge_parents *merge_parents) { int i, len = strlen(line); struct origin_data *origin_data; - char *src, *origin; + char *src; + const char *origin; struct src_data *src_data; struct string_list_item *item; int pulling_head = 0; @@ -164,8 +165,7 @@ static int handle_line(char *line, struct merge_parents *merge_parents) origin = line; string_list_append(&src_data->tag, origin + 4); src_data->head_status |= 2; - } else if (starts_with(line, "remote-tracking branch ")) { - origin = line + strlen("remote-tracking branch "); + } else if (skip_prefix(line, "remote-tracking branch ", &origin)) { string_list_append(&src_data->r_branch, origin); src_data->head_status |= 2; } else { @@ -227,12 +227,14 @@ static void add_branch_desc(struct strbuf *out, const char *name) static void record_person(int which, struct string_list *people, struct commit *commit) { + const char *buffer; char *name_buf, *name, *name_end; struct string_list_item *elem; const char *field; field = (which == 'a') ? "\nauthor " : "\ncommitter "; - name = strstr(commit->buffer, field); + buffer = get_commit_buffer(commit, NULL); + name = strstr(buffer, field); if (!name) return; name += strlen(field); @@ -244,6 +246,7 @@ static void record_person(int which, struct string_list *people, if (name_end < name) return; name_buf = xmemdupz(name, name_end - name + 1); + unuse_commit_buffer(commit, buffer); elem = string_list_lookup(people, name_buf); if (!elem) { @@ -294,8 +297,8 @@ static void credit_people(struct strbuf *out, if (!them->nr || (them->nr == 1 && me && - (me = skip_prefix(me, them->items->string)) != NULL && - skip_prefix(me, " <"))) + skip_prefix(me, them->items->string, &me) && + starts_with(me, " <"))) return; strbuf_addf(out, "\n%c %s ", comment_line_char, label); add_people_count(out, them); diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 3e1d5c3334..4135980f20 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -193,7 +193,7 @@ static int verify_format(const char *format) at = parse_atom(sp + 2, ep); cp = ep + 1; - if (!memcmp(used_atom[at], "color:", 6)) + if (starts_with(used_atom[at], "color:")) need_color_reset_at_eol = !!strcmp(used_atom[at], color_reset); } return 0; diff --git a/builtin/fsck.c b/builtin/fsck.c index fc150c8821..8aadca160e 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -310,8 +310,7 @@ static int fsck_obj(struct object *obj) if (obj->type == OBJ_COMMIT) { struct commit *commit = (struct commit *) obj; - free(commit->buffer); - commit->buffer = NULL; + free_commit_buffer(commit); if (!commit->parents && show_root) printf("root %s\n", sha1_to_hex(commit->object.sha1)); diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 18f57de58b..8b3bd29dbc 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -786,7 +786,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, } if (obj->type == OBJ_COMMIT) { struct commit *commit = (struct commit *) obj; - commit->buffer = NULL; + if (detach_commit_buffer(commit, NULL) != data) + die("BUG: parse_object_buffer transmogrified our buffer"); } obj->flags |= FLAG_CHECKED; } diff --git a/builtin/log.c b/builtin/log.c index a7ba211731..27c1b65db4 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -347,8 +347,7 @@ static int cmd_log_walk(struct rev_info *rev) rev->max_count++; if (!rev->reflog_info) { /* we allow cycles in reflog ancestry */ - free(commit->buffer); - commit->buffer = NULL; + free_commit_buffer(commit); } free_commit_list(commit->parents); commit->parents = NULL; @@ -872,7 +871,7 @@ static char *find_branch_name(struct rev_info *rev) int i, positive = -1; unsigned char branch_sha1[20]; const unsigned char *tip_sha1; - const char *ref; + const char *ref, *v; char *full_ref, *branch = NULL; for (i = 0; i < rev->cmdline.nr; i++) { @@ -888,9 +887,9 @@ static char *find_branch_name(struct rev_info *rev) ref = rev->cmdline.rev[positive].name; tip_sha1 = rev->cmdline.rev[positive].item->sha1; if (dwim_ref(ref, strlen(ref), branch_sha1, &full_ref) && - starts_with(full_ref, "refs/heads/") && + skip_prefix(full_ref, "refs/heads/", &v) && !hashcmp(tip_sha1, branch_sha1)) - branch = xstrdup(full_ref + strlen("refs/heads/")); + branch = xstrdup(v); free(full_ref); return branch; } @@ -925,9 +924,12 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, log_write_email_headers(rev, head, &pp.subject, &pp.after_subject, &need_8bit_cte); - for (i = 0; !need_8bit_cte && i < nr; i++) - if (has_non_ascii(list[i]->buffer)) + for (i = 0; !need_8bit_cte && i < nr; i++) { + const char *buf = get_commit_buffer(list[i], NULL); + if (has_non_ascii(buf)) need_8bit_cte = 1; + unuse_commit_buffer(list[i], buf); + } if (!branch_name) branch_name = find_branch_name(rev); @@ -1394,10 +1396,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (check_head) { unsigned char sha1[20]; - const char *ref; + const char *ref, *v; ref = resolve_ref_unsafe("HEAD", sha1, 1, NULL); - if (ref && starts_with(ref, "refs/heads/")) - branch_name = xstrdup(ref + strlen("refs/heads/")); + if (ref && skip_prefix(ref, "refs/heads/", &v)) + branch_name = xstrdup(v); else branch_name = xstrdup(""); /* no branch */ } @@ -1528,8 +1530,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) reopen_stdout(rev.numbered_files ? NULL : commit, NULL, &rev, quiet)) die(_("Failed to create output files")); shown = log_tree_commit(&rev, commit); - free(commit->buffer); - commit->buffer = NULL; + free_commit_buffer(commit); /* We put one extra blank line between formatted * patches and this flag is used by log-tree code diff --git a/builtin/merge.c b/builtin/merge.c index 428ca247bd..b49c310866 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -852,8 +852,8 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads) parent->next->item = remoteheads->item; parent->next->next = NULL; prepare_to_commit(remoteheads); - if (commit_tree(&merge_msg, result_tree, parent, result_commit, NULL, - sign_commit)) + if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parent, + result_commit, NULL, sign_commit)) die(_("failed to write commit object")); finish(head, remoteheads, result_commit, "In-index merge"); drop_save(); @@ -877,8 +877,8 @@ static int finish_automerge(struct commit *head, commit_list_insert(head, &parents); strbuf_addch(&merge_msg, '\n'); prepare_to_commit(remoteheads); - if (commit_tree(&merge_msg, result_tree, parents, result_commit, - NULL, sign_commit)) + if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents, + result_commit, NULL, sign_commit)) die(_("failed to write commit object")); strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy); finish(head, remoteheads, result_commit, buf.buf); diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index de36c60ca1..238b5021eb 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -2214,10 +2214,6 @@ static int git_pack_config(const char *k, const char *v, void *cb) cache_max_small_delta_size = git_config_int(k, v); return 0; } - if (!strcmp(k, "pack.writebitmaps")) { - write_bitmap_index = git_config_bool(k, v); - return 0; - } if (!strcmp(k, "pack.writebitmaphashcache")) { if (git_config_bool(k, v)) write_bitmap_options |= BITMAP_OPT_HASH_CACHE; diff --git a/builtin/push.c b/builtin/push.c index f8dfea41e1..f50e3d5e77 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -127,11 +127,10 @@ static NORETURN int die_push_simple(struct branch *branch, struct remote *remote * them the big ugly fully qualified ref. */ const char *advice_maybe = ""; - const char *short_upstream = - skip_prefix(branch->merge[0]->src, "refs/heads/"); + const char *short_upstream = branch->merge[0]->src; + + skip_prefix(short_upstream, "refs/heads/", &short_upstream); - if (!short_upstream) - short_upstream = branch->merge[0]->src; /* * Don't show advice for people who explicitly set * push.default. diff --git a/builtin/remote.c b/builtin/remote.c index c9102e8fe9..a8efe3da4d 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -250,9 +250,7 @@ static struct string_list branch_list; static const char *abbrev_ref(const char *name, const char *prefix) { - const char *abbrev = skip_prefix(name, prefix); - if (abbrev) - return abbrev; + skip_prefix(name, prefix, &name); return name; } #define abbrev_branch(name) abbrev_ref((name), "refs/heads/") diff --git a/builtin/repack.c b/builtin/repack.c index 6b0b62dcb2..ff2216a7aa 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -10,6 +10,7 @@ static int delta_base_offset = 1; static int pack_kept_objects = -1; +static int write_bitmaps; static char *packdir, *packtmp; static const char *const git_repack_usage[] = { @@ -27,6 +28,11 @@ static int repack_config(const char *var, const char *value, void *cb) pack_kept_objects = git_config_bool(var, value); return 0; } + if (!strcmp(var, "repack.writebitmaps") || + !strcmp(var, "pack.writebitmaps")) { + write_bitmaps = git_config_bool(var, value); + return 0; + } return git_default_config(var, value, cb); } @@ -149,7 +155,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix) int no_update_server_info = 0; int quiet = 0; int local = 0; - int write_bitmap = -1; struct option builtin_repack_options[] = { OPT_BIT('a', NULL, &pack_everything, @@ -168,7 +173,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix) OPT__QUIET(&quiet, N_("be quiet")), OPT_BOOL('l', "local", &local, N_("pass --local to git-pack-objects")), - OPT_BOOL('b', "write-bitmap-index", &write_bitmap, + OPT_BOOL('b', "write-bitmap-index", &write_bitmaps, N_("write bitmap index")), OPT_STRING(0, "unpack-unreachable", &unpack_unreachable, N_("approxidate"), N_("with -A, do not loosen objects older than this")), @@ -191,7 +196,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix) git_repack_usage, 0); if (pack_kept_objects < 0) - pack_kept_objects = write_bitmap; + pack_kept_objects = write_bitmaps; packdir = mkpathdup("%s/pack", get_object_directory()); packtmp = mkpathdup("%s/.tmp-%d-pack", packdir, (int)getpid()); @@ -217,9 +222,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix) argv_array_pushf(&cmd_args, "--no-reuse-delta"); if (no_reuse_object) argv_array_pushf(&cmd_args, "--no-reuse-object"); - if (write_bitmap >= 0) - argv_array_pushf(&cmd_args, "--%swrite-bitmap-index", - write_bitmap ? "" : "no-"); + if (write_bitmaps) + argv_array_push(&cmd_args, "--write-bitmap-index"); if (pack_everything & ALL_INTO_ONE) { get_non_kept_pack_filenames(&existing_packs); diff --git a/builtin/reset.c b/builtin/reset.c index f368266762..850d53229a 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -93,7 +93,7 @@ static int reset_index(const unsigned char *sha1, int reset_type, int quiet) static void print_new_head_line(struct commit *commit) { const char *hex, *body; - char *msg; + const char *msg; hex = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV); printf(_("HEAD is now at %s"), hex); @@ -109,7 +109,7 @@ static void print_new_head_line(struct commit *commit) } else printf("\n"); - logmsg_free(msg, commit); + unuse_commit_buffer(commit, msg); } static void update_index_from_diff(struct diff_queue_struct *q, diff --git a/builtin/rev-list.c b/builtin/rev-list.c index 9f92905379..ff84a825ff 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -106,7 +106,7 @@ static void show_commit(struct commit *commit, void *data) else putchar('\n'); - if (revs->verbose_header && commit->buffer) { + if (revs->verbose_header && get_cached_commit_buffer(commit, NULL)) { struct strbuf buf = STRBUF_INIT; struct pretty_print_context ctx = {0}; ctx.abbrev = revs->abbrev; @@ -173,8 +173,7 @@ static void finish_commit(struct commit *commit, void *data) free_commit_list(commit->parents); commit->parents = NULL; } - free(commit->buffer); - commit->buffer = NULL; + free_commit_buffer(commit); } static void finish_object(struct object *obj, diff --git a/builtin/tag.c b/builtin/tag.c index c6e8a71127..ef76556338 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -83,7 +83,7 @@ static int in_commit_list(const struct commit_list *want, struct commit *c) enum contains_result { CONTAINS_UNKNOWN = -1, CONTAINS_NO = 0, - CONTAINS_YES = 1, + CONTAINS_YES = 1 }; /* @@ -999,7 +999,7 @@ extern int validate_headref(const char *ref); extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2); extern int df_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2); -extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2); +extern int name_compare(const char *name1, size_t len1, const char *name2, size_t len2); extern int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2); extern void *read_object_with_reference(const unsigned char *sha1, diff --git a/check_bindir b/check_bindir index a1c4c3e8d8..623eadcbb7 100755 --- a/check_bindir +++ b/check_bindir @@ -2,7 +2,7 @@ bindir="$1" gitexecdir="$2" gitcmd="$3" -if test "$bindir" != "$gitexecdir" -a -x "$gitcmd" +if test "$bindir" != "$gitexecdir" && test -x "$gitcmd" then echo echo "!! You have installed git-* commands to new gitexecdir." @@ -336,8 +336,9 @@ static int column_config(const char *var, const char *value, int git_column_config(const char *var, const char *value, const char *command, unsigned int *colopts) { - const char *it = skip_prefix(var, "column."); - if (!it) + const char *it; + + if (!skip_prefix(var, "column.", &it)) return 0; if (!strcmp(it, "ui")) diff --git a/commit-slab.h b/commit-slab.h index cc114b53b0..375c9c751a 100644 --- a/commit-slab.h +++ b/commit-slab.h @@ -117,4 +117,16 @@ static int stat_ ##slabname## realloc * catch because GCC silently parses it by default. */ +/* + * Statically initialize a commit slab named "var". Note that this + * evaluates "stride" multiple times! Example: + * + * struct indegree indegrees = COMMIT_SLAB_INIT(1, indegrees); + * + */ +#define COMMIT_SLAB_INIT(stride, var) { \ + COMMIT_SLAB_SIZE / sizeof(**((var).slab)) / (stride), \ + (stride), 0, NULL \ +} + #endif /* COMMIT_SLAB_H */ @@ -17,7 +17,6 @@ static struct commit_extra_header *read_commit_extra_header_lines(const char *bu int save_commit_buffer = 1; const char *commit_type = "commit"; -static int commit_count; static struct commit *check_commit(struct object *obj, const unsigned char *sha1, @@ -64,7 +63,6 @@ struct commit *lookup_commit(const unsigned char *sha1) struct object *obj = lookup_object(sha1); if (!obj) { struct commit *c = alloc_commit_node(); - c->index = commit_count++; return create_object(sha1, OBJ_COMMIT, c); } if (!obj->type) @@ -247,6 +245,76 @@ int unregister_shallow(const unsigned char *sha1) return 0; } +struct commit_buffer { + void *buffer; + unsigned long size; +}; +define_commit_slab(buffer_slab, struct commit_buffer); +static struct buffer_slab buffer_slab = COMMIT_SLAB_INIT(1, buffer_slab); + +void set_commit_buffer(struct commit *commit, void *buffer, unsigned long size) +{ + struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); + v->buffer = buffer; + v->size = size; +} + +const void *get_cached_commit_buffer(const struct commit *commit, unsigned long *sizep) +{ + struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); + if (sizep) + *sizep = v->size; + return v->buffer; +} + +const void *get_commit_buffer(const struct commit *commit, unsigned long *sizep) +{ + const void *ret = get_cached_commit_buffer(commit, sizep); + if (!ret) { + enum object_type type; + unsigned long size; + ret = read_sha1_file(commit->object.sha1, &type, &size); + if (!ret) + die("cannot read commit object %s", + sha1_to_hex(commit->object.sha1)); + if (type != OBJ_COMMIT) + die("expected commit for %s, got %s", + sha1_to_hex(commit->object.sha1), typename(type)); + if (sizep) + *sizep = size; + } + return ret; +} + +void unuse_commit_buffer(const struct commit *commit, const void *buffer) +{ + struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); + if (v->buffer != buffer) + free((void *)buffer); +} + +void free_commit_buffer(struct commit *commit) +{ + struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); + free(v->buffer); + v->buffer = NULL; + v->size = 0; +} + +const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep) +{ + struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit); + void *ret; + + ret = v->buffer; + if (sizep) + *sizep = v->size; + + v->buffer = NULL; + v->size = 0; + return ret; +} + int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size) { const char *tail = buffer; @@ -324,7 +392,7 @@ int parse_commit(struct commit *item) } ret = parse_commit_buffer(item, buffer, size); if (save_commit_buffer && !ret) { - item->buffer = buffer; + set_commit_buffer(item, buffer, size); return 0; } free(buffer); @@ -539,25 +607,14 @@ static void record_author_date(struct author_date_slab *author_date, struct commit *commit) { const char *buf, *line_end, *ident_line; - char *buffer = NULL; + const char *buffer = get_commit_buffer(commit, NULL); struct ident_split ident; char *date_end; unsigned long date; - if (!commit->buffer) { - unsigned long size; - enum object_type type; - buffer = read_sha1_file(commit->object.sha1, &type, &size); - if (!buffer) - return; - } - - for (buf = commit->buffer ? commit->buffer : buffer; - buf; - buf = line_end + 1) { + for (buf = buffer; buf; buf = line_end + 1) { line_end = strchrnul(buf, '\n'); - ident_line = skip_prefix(buf, "author "); - if (!ident_line) { + if (!skip_prefix(buf, "author ", &ident_line)) { if (!line_end[0] || line_end[1] == '\n') return; /* end of header */ continue; @@ -575,7 +632,7 @@ static void record_author_date(struct author_date_slab *author_date, *(author_date_slab_at(author_date, commit)) = date; fail_exit: - free(buffer); + unuse_commit_buffer(commit, buffer); } static int compare_commits_by_author_date(const void *a_, const void *b_, @@ -1080,17 +1137,14 @@ static int do_sign_commit(struct strbuf *buf, const char *keyid) return 0; } -int parse_signed_commit(const unsigned char *sha1, +int parse_signed_commit(const struct commit *commit, struct strbuf *payload, struct strbuf *signature) { + unsigned long size; - enum object_type type; - char *buffer = read_sha1_file(sha1, &type, &size); + const char *buffer = get_commit_buffer(commit, &size); int in_signature, saw_signature = -1; - char *line, *tail; - - if (!buffer || type != OBJ_COMMIT) - goto cleanup; + const char *line, *tail; line = buffer; tail = buffer + size; @@ -1098,7 +1152,7 @@ int parse_signed_commit(const unsigned char *sha1, saw_signature = 0; while (line < tail) { const char *sig = NULL; - char *next = memchr(line, '\n', tail - line); + const char *next = memchr(line, '\n', tail - line); next = next ? next + 1 : tail; if (in_signature && line[0] == ' ') @@ -1119,8 +1173,7 @@ int parse_signed_commit(const unsigned char *sha1, } line = next; } - cleanup: - free(buffer); + unuse_commit_buffer(commit, buffer); return saw_signature; } @@ -1183,8 +1236,7 @@ static void parse_gpg_output(struct signature_check *sigc) for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) { const char *found, *next; - found = skip_prefix(buf, sigcheck_gpg_status[i].check + 1); - if (!found) { + if (!skip_prefix(buf, sigcheck_gpg_status[i].check + 1, &found)) { found = strstr(buf, sigcheck_gpg_status[i].check); if (!found) continue; @@ -1211,8 +1263,7 @@ void check_commit_signature(const struct commit* commit, struct signature_check sigc->result = 'N'; - if (parse_signed_commit(commit->object.sha1, - &payload, &signature) <= 0) + if (parse_signed_commit(commit, &payload, &signature) <= 0) goto out; status = verify_signed_buffer(payload.buf, payload.len, signature.buf, signature.len, @@ -1257,11 +1308,9 @@ struct commit_extra_header *read_commit_extra_headers(struct commit *commit, { struct commit_extra_header *extra = NULL; unsigned long size; - enum object_type type; - char *buffer = read_sha1_file(commit->object.sha1, &type, &size); - if (buffer && type == OBJ_COMMIT) - extra = read_commit_extra_header_lines(buffer, size, exclude); - free(buffer); + const char *buffer = get_commit_buffer(commit, &size); + extra = read_commit_extra_header_lines(buffer, size, exclude); + unuse_commit_buffer(commit, buffer); return extra; } @@ -1344,7 +1393,8 @@ void free_commit_extra_headers(struct commit_extra_header *extra) } } -int commit_tree(const struct strbuf *msg, const unsigned char *tree, +int commit_tree(const char *msg, size_t msg_len, + const unsigned char *tree, struct commit_list *parents, unsigned char *ret, const char *author, const char *sign_commit) { @@ -1352,7 +1402,7 @@ int commit_tree(const struct strbuf *msg, const unsigned char *tree, int result; append_merge_tag_headers(parents, &tail); - result = commit_tree_extended(msg, tree, parents, ret, + result = commit_tree_extended(msg, msg_len, tree, parents, ret, author, sign_commit, extra); free_commit_extra_headers(extra); return result; @@ -1473,7 +1523,8 @@ static const char commit_utf8_warn[] = "You may want to amend it after fixing the message, or set the config\n" "variable i18n.commitencoding to the encoding your project uses.\n"; -int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree, +int commit_tree_extended(const char *msg, size_t msg_len, + const unsigned char *tree, struct commit_list *parents, unsigned char *ret, const char *author, const char *sign_commit, struct commit_extra_header *extra) @@ -1484,7 +1535,7 @@ int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree, assert_sha1_type(tree, OBJ_TREE); - if (memchr(msg->buf, '\0', msg->len)) + if (memchr(msg, '\0', msg_len)) return error("a NUL byte in commit log message not allowed."); /* Not having i18n.commitencoding is the same as having utf-8 */ @@ -1523,7 +1574,7 @@ int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree, strbuf_addch(&buffer, '\n'); /* And add the comment */ - strbuf_addbuf(&buffer, msg); + strbuf_add(&buffer, msg, msg_len); /* And check the encoding */ if (encoding_is_utf8 && !verify_utf8(&buffer)) @@ -20,7 +20,6 @@ struct commit { unsigned long date; struct commit_list *parents; struct tree *tree; - char *buffer; }; extern int save_commit_buffer; @@ -51,6 +50,44 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s int parse_commit(struct commit *item); void parse_commit_or_die(struct commit *item); +/* + * Associate an object buffer with the commit. The ownership of the + * memory is handed over to the commit, and must be free()-able. + */ +void set_commit_buffer(struct commit *, void *buffer, unsigned long size); + +/* + * Get any cached object buffer associated with the commit. Returns NULL + * if none. The resulting memory should not be freed. + */ +const void *get_cached_commit_buffer(const struct commit *, unsigned long *size); + +/* + * Get the commit's object contents, either from cache or by reading the object + * from disk. The resulting memory should not be modified, and must be given + * to unuse_commit_buffer when the caller is done. + */ +const void *get_commit_buffer(const struct commit *, unsigned long *size); + +/* + * Tell the commit subsytem that we are done with a particular commit buffer. + * The commit and buffer should be the input and return value, respectively, + * from an earlier call to get_commit_buffer. The buffer may or may not be + * freed by this call; callers should not access the memory afterwards. + */ +void unuse_commit_buffer(const struct commit *, const void *buffer); + +/* + * Free any cached object buffer associated with the commit. + */ +void free_commit_buffer(struct commit *); + +/* + * Disassociate any cached object buffer from the commit, but do not free it. + * The buffer (or NULL, if none) is returned. + */ +const void *detach_commit_buffer(struct commit *, unsigned long *sizep); + /* Find beginning and length of commit subject. */ int find_commit_subject(const char *commit_buffer, const char **subject); @@ -115,10 +152,9 @@ struct userformat_want { extern int has_non_ascii(const char *text); struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */ -extern char *logmsg_reencode(const struct commit *commit, - char **commit_encoding, - const char *output_encoding); -extern void logmsg_free(char *msg, const struct commit *commit); +extern const char *logmsg_reencode(const struct commit *commit, + char **commit_encoding, + const char *output_encoding); extern void get_commit_format(const char *arg, struct rev_info *); extern const char *format_subject(struct strbuf *sb, const char *msg, const char *line_separator); @@ -261,11 +297,13 @@ struct commit_extra_header { extern void append_merge_tag_headers(struct commit_list *parents, struct commit_extra_header ***tail); -extern int commit_tree(const struct strbuf *msg, const unsigned char *tree, +extern int commit_tree(const char *msg, size_t msg_len, + const unsigned char *tree, struct commit_list *parents, unsigned char *ret, const char *author, const char *sign_commit); -extern int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree, +extern int commit_tree_extended(const char *msg, size_t msg_len, + const unsigned char *tree, struct commit_list *parents, unsigned char *ret, const char *author, const char *sign_commit, struct commit_extra_header *); @@ -287,7 +325,7 @@ struct merge_remote_desc { */ struct commit *get_merge_parent(const char *name); -extern int parse_signed_commit(const unsigned char *sha1, +extern int parse_signed_commit(const struct commit *commit, struct strbuf *message, struct strbuf *signature); extern void print_commit_list(struct commit_list *list, const char *format_cur, @@ -138,8 +138,7 @@ int git_config_include(const char *var, const char *value, void *data) if (ret < 0) return ret; - type = skip_prefix(var, "include."); - if (!type) + if (!skip_prefix(var, "include.", &type)) return ret; if (!strcmp(type, "path")) @@ -129,6 +129,7 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len, char *name; int len, name_len; char *buffer = packet_buffer; + const char *arg; len = packet_read(in, &src_buf, &src_len, packet_buffer, sizeof(packet_buffer), @@ -140,12 +141,12 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len, if (!len) break; - if (len > 4 && starts_with(buffer, "ERR ")) - die("remote error: %s", buffer + 4); + if (len > 4 && skip_prefix(buffer, "ERR ", &arg)) + die("remote error: %s", arg); - if (len == 48 && starts_with(buffer, "shallow ")) { - if (get_sha1_hex(buffer + 8, old_sha1)) - die("protocol error: expected shallow sha-1, got '%s'", buffer + 8); + if (len == 48 && skip_prefix(buffer, "shallow ", &arg)) { + if (get_sha1_hex(arg, old_sha1)) + die("protocol error: expected shallow sha-1, got '%s'", arg); if (!shallow_points) die("repository on the other end cannot be shallow"); sha1_array_append(shallow_points, old_sha1); diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 019026efcb..7a6e1d797a 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -21,6 +21,12 @@ # source ~/.git-completion.sh # 3) Consider changing your PS1 to also show the current branch, # see git-prompt.sh for details. +# +# If you use complex aliases of form '!f() { ... }; f', you can use the null +# command ':' as the first command in the function body to declare the desired +# completion style. For example '!f() { : git commit ; ... }; f' will +# tell the completion to use commit completion. This also works with aliases +# of form "!sh -c '...'". For example, "!sh -c ': git commit ; ... '". case "$COMP_WORDBREAKS" in *:*) : great ;; @@ -781,6 +787,10 @@ __git_aliased_command () -*) : option ;; *=*) : setting env ;; git) : git itself ;; + \(\)) : skip parens of shell function definition ;; + {) : skip start of shell helper function ;; + :) : skip null command ;; + \'*) : skip opening quote after sh -c ;; *) echo "$word" return diff --git a/contrib/examples/git-clone.sh b/contrib/examples/git-clone.sh index b4c9376a2c..08cf246bbb 100755 --- a/contrib/examples/git-clone.sh +++ b/contrib/examples/git-clone.sh @@ -516,7 +516,7 @@ then case "$no_checkout" in '') - test "z$quiet" = z -a "z$no_progress" = z && v=-v || v= + test "z$quiet" = z && test "z$no_progress" = z && v=-v || v= git read-tree -m -u $v HEAD HEAD esac fi diff --git a/contrib/examples/git-commit.sh b/contrib/examples/git-commit.sh index 5cafe2eb77..934505bab9 100755 --- a/contrib/examples/git-commit.sh +++ b/contrib/examples/git-commit.sh @@ -51,7 +51,7 @@ run_status () { export GIT_INDEX_FILE fi - if test "$status_only" = "t" -o "$use_status_color" = "t"; then + if test "$status_only" = "t" || test "$use_status_color" = "t"; then color= else color=--nocolor @@ -296,7 +296,7 @@ t,,,[1-9]*) die "No paths with -i does not make sense." ;; esac -if test ! -z "$templatefile" -a -z "$log_given" +if test ! -z "$templatefile" && test -z "$log_given" then if test ! -f "$templatefile" then diff --git a/contrib/examples/git-merge.sh b/contrib/examples/git-merge.sh index 7e40f40c78..52f2aafb9d 100755 --- a/contrib/examples/git-merge.sh +++ b/contrib/examples/git-merge.sh @@ -161,7 +161,7 @@ merge_name () { return fi fi - if test "$remote" = "FETCH_HEAD" -a -r "$GIT_DIR/FETCH_HEAD" + if test "$remote" = "FETCH_HEAD" && test -r "$GIT_DIR/FETCH_HEAD" then sed -e 's/ not-for-merge / /' -e 1q \ "$GIT_DIR/FETCH_HEAD" @@ -527,7 +527,7 @@ do git diff-files --name-only git ls-files --unmerged } | wc -l` - if test $best_cnt -le 0 -o $cnt -le $best_cnt + if test $best_cnt -le 0 || test $cnt -le $best_cnt then best_strategy=$strategy best_cnt=$cnt diff --git a/contrib/examples/git-repack.sh b/contrib/examples/git-repack.sh index f312405a25..96e3fed326 100755 --- a/contrib/examples/git-repack.sh +++ b/contrib/examples/git-repack.sh @@ -76,8 +76,8 @@ case ",$all_into_one," in existing="$existing $e" fi done - if test -n "$existing" -a -n "$unpack_unreachable" -a \ - -n "$remove_redundant" + if test -n "$existing" && test -n "$unpack_unreachable" && \ + test -n "$remove_redundant" then # This may have arbitrary user arguments, so we # have to protect it against whitespace splitting diff --git a/contrib/examples/git-resolve.sh b/contrib/examples/git-resolve.sh index 48d0fc971f..70fdc27b72 100755 --- a/contrib/examples/git-resolve.sh +++ b/contrib/examples/git-resolve.sh @@ -76,7 +76,7 @@ case "$common" in 2>/dev/null || continue # Count the paths that are unmerged. cnt=$(GIT_INDEX_FILE=$G git ls-files --unmerged | wc -l) - if test $best_cnt -le 0 -o $cnt -le $best_cnt + if test $best_cnt -le 0 || test $cnt -le $best_cnt then best=$c best_cnt=$cnt @@ -1121,9 +1121,9 @@ static int is_foreign_ident(const char *str) { int i; - if (!starts_with(str, "$Id: ")) + if (!skip_prefix(str, "$Id: ", &str)) return 0; - for (i = 5; str[i]; i++) { + for (i = 0; str[i]; i++) { if (isspace(str[i]) && str[i+1] != '$') return 1; } diff --git a/credential-cache--daemon.c b/credential-cache--daemon.c index 390f194252..3b370ca5e5 100644 --- a/credential-cache--daemon.c +++ b/credential-cache--daemon.c @@ -109,14 +109,12 @@ static int read_request(FILE *fh, struct credential *c, const char *p; strbuf_getline(&item, fh, '\n'); - p = skip_prefix(item.buf, "action="); - if (!p) + if (!skip_prefix(item.buf, "action=", &p)) return error("client sent bogus action line: %s", item.buf); strbuf_addstr(action, p); strbuf_getline(&item, fh, '\n'); - p = skip_prefix(item.buf, "timeout="); - if (!p) + if (!skip_prefix(item.buf, "timeout=", &p)) return error("client sent bogus timeout line: %s", item.buf); *timeout = atoi(p); diff --git a/credential.c b/credential.c index e54753c75d..4d79d320f8 100644 --- a/credential.c +++ b/credential.c @@ -40,8 +40,7 @@ static int credential_config_callback(const char *var, const char *value, struct credential *c = data; const char *key, *dot; - key = skip_prefix(var, "credential."); - if (!key) + if (!skip_prefix(var, "credential.", &key)) return 0; if (!value) @@ -39,8 +39,8 @@ static int strict_paths; static int export_all_trees; /* Take all paths relative to this one if non-NULL */ -static char *base_path; -static char *interpolated_path; +static const char *base_path; +static const char *interpolated_path; static int base_path_relaxed; /* Flag indicating client sent extra args. */ @@ -106,12 +106,12 @@ static void NORETURN daemon_die(const char *err, va_list params) exit(1); } -static const char *path_ok(char *directory) +static const char *path_ok(const char *directory) { static char rpath[PATH_MAX]; static char interp_path[PATH_MAX]; const char *path; - char *dir; + const char *dir; dir = directory; @@ -131,7 +131,7 @@ static const char *path_ok(char *directory) * "~alice/%s/foo". */ int namlen, restlen = strlen(dir); - char *slash = strchr(dir, '/'); + const char *slash = strchr(dir, '/'); if (!slash) slash = dir + restlen; namlen = slash - dir; @@ -235,8 +235,10 @@ static int service_enabled; static int git_daemon_config(const char *var, const char *value, void *cb) { - if (starts_with(var, "daemon.") && - !strcmp(var + 7, service_looking_at->config_name)) { + const char *service; + + if (skip_prefix(var, "daemon.", &service) && + !strcmp(service, service_looking_at->config_name)) { service_enabled = git_config_bool(var, value); return 0; } @@ -253,7 +255,7 @@ static int daemon_error(const char *dir, const char *msg) return -1; } -static char *access_hook; +static const char *access_hook; static int run_access_hook(struct daemon_service *service, const char *dir, const char *path) { @@ -318,7 +320,7 @@ error_return: return -1; } -static int run_service(char *dir, struct daemon_service *service) +static int run_service(const char *dir, struct daemon_service *service) { const char *path; int enabled = service->enabled; @@ -624,15 +626,16 @@ static int execute(void) for (i = 0; i < ARRAY_SIZE(daemon_service); i++) { struct daemon_service *s = &(daemon_service[i]); - int namelen = strlen(s->name); - if (starts_with(line, "git-") && - !strncmp(s->name, line + 4, namelen) && - line[namelen + 4] == ' ') { + const char *arg; + + if (skip_prefix(line, "git-", &arg) && + skip_prefix(arg, s->name, &arg) && + *arg++ == ' ') { /* * Note: The directory here is probably context sensitive, * and might depend on the actual service being performed. */ - return run_service(line + namelen + 5, s); + return run_service(arg, s); } } @@ -1133,16 +1136,17 @@ int main(int argc, char **argv) for (i = 1; i < argc; i++) { char *arg = argv[i]; + const char *v; - if (starts_with(arg, "--listen=")) { - string_list_append(&listen_addr, xstrdup_tolower(arg + 9)); + if (skip_prefix(arg, "--listen=", &v)) { + string_list_append(&listen_addr, xstrdup_tolower(v)); continue; } - if (starts_with(arg, "--port=")) { + if (skip_prefix(arg, "--port=", &v)) { char *end; unsigned long n; - n = strtoul(arg+7, &end, 0); - if (arg[7] && !*end) { + n = strtoul(v, &end, 0); + if (*v && !*end) { listen_port = n; continue; } @@ -1168,20 +1172,20 @@ int main(int argc, char **argv) export_all_trees = 1; continue; } - if (starts_with(arg, "--access-hook=")) { - access_hook = arg + 14; + if (skip_prefix(arg, "--access-hook=", &v)) { + access_hook = v; continue; } - if (starts_with(arg, "--timeout=")) { - timeout = atoi(arg+10); + if (skip_prefix(arg, "--timeout=", &v)) { + timeout = atoi(v); continue; } - if (starts_with(arg, "--init-timeout=")) { - init_timeout = atoi(arg+15); + if (skip_prefix(arg, "--init-timeout=", &v)) { + init_timeout = atoi(v); continue; } - if (starts_with(arg, "--max-connections=")) { - max_connections = atoi(arg+18); + if (skip_prefix(arg, "--max-connections=", &v)) { + max_connections = atoi(v); if (max_connections < 0) max_connections = 0; /* unlimited */ continue; @@ -1190,16 +1194,16 @@ int main(int argc, char **argv) strict_paths = 1; continue; } - if (starts_with(arg, "--base-path=")) { - base_path = arg+12; + if (skip_prefix(arg, "--base-path=", &v)) { + base_path = v; continue; } if (!strcmp(arg, "--base-path-relaxed")) { base_path_relaxed = 1; continue; } - if (starts_with(arg, "--interpolated-path=")) { - interpolated_path = arg+20; + if (skip_prefix(arg, "--interpolated-path=", &v)) { + interpolated_path = v; continue; } if (!strcmp(arg, "--reuseaddr")) { @@ -1210,12 +1214,12 @@ int main(int argc, char **argv) user_path = ""; continue; } - if (starts_with(arg, "--user-path=")) { - user_path = arg + 12; + if (skip_prefix(arg, "--user-path=", &v)) { + user_path = v; continue; } - if (starts_with(arg, "--pid-file=")) { - pid_file = arg + 11; + if (skip_prefix(arg, "--pid-file=", &v)) { + pid_file = v; continue; } if (!strcmp(arg, "--detach")) { @@ -1223,28 +1227,28 @@ int main(int argc, char **argv) log_syslog = 1; continue; } - if (starts_with(arg, "--user=")) { - user_name = arg + 7; + if (skip_prefix(arg, "--user=", &v)) { + user_name = v; continue; } - if (starts_with(arg, "--group=")) { - group_name = arg + 8; + if (skip_prefix(arg, "--group=", &v)) { + group_name = v; continue; } - if (starts_with(arg, "--enable=")) { - enable_service(arg + 9, 1); + if (skip_prefix(arg, "--enable=", &v)) { + enable_service(v, 1); continue; } - if (starts_with(arg, "--disable=")) { - enable_service(arg + 10, 0); + if (skip_prefix(arg, "--disable=", &v)) { + enable_service(v, 0); continue; } - if (starts_with(arg, "--allow-override=")) { - make_service_overridable(arg + 17, 1); + if (skip_prefix(arg, "--allow-override=", &v)) { + make_service_overridable(v, 1); continue; } - if (starts_with(arg, "--forbid-override=")) { - make_service_overridable(arg + 18, 0); + if (skip_prefix(arg, "--forbid-override=", &v)) { + make_service_overridable(v, 0); continue; } if (!strcmp(arg, "--informative-errors")) { @@ -52,23 +52,23 @@ static char diff_colors[][COLOR_MAXLEN] = { GIT_COLOR_NORMAL, /* FUNCINFO */ }; -static int parse_diff_color_slot(const char *var, int ofs) +static int parse_diff_color_slot(const char *var) { - if (!strcasecmp(var+ofs, "plain")) + if (!strcasecmp(var, "plain")) return DIFF_PLAIN; - if (!strcasecmp(var+ofs, "meta")) + if (!strcasecmp(var, "meta")) return DIFF_METAINFO; - if (!strcasecmp(var+ofs, "frag")) + if (!strcasecmp(var, "frag")) return DIFF_FRAGINFO; - if (!strcasecmp(var+ofs, "old")) + if (!strcasecmp(var, "old")) return DIFF_FILE_OLD; - if (!strcasecmp(var+ofs, "new")) + if (!strcasecmp(var, "new")) return DIFF_FILE_NEW; - if (!strcasecmp(var+ofs, "commit")) + if (!strcasecmp(var, "commit")) return DIFF_COMMIT; - if (!strcasecmp(var+ofs, "whitespace")) + if (!strcasecmp(var, "whitespace")) return DIFF_WHITESPACE; - if (!strcasecmp(var+ofs, "func")) + if (!strcasecmp(var, "func")) return DIFF_FUNCINFO; return -1; } @@ -231,6 +231,8 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) int git_diff_basic_config(const char *var, const char *value, void *cb) { + const char *name; + if (!strcmp(var, "diff.renamelimit")) { diff_rename_limit_default = git_config_int(var, value); return 0; @@ -239,8 +241,9 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) if (userdiff_config(var, value) < 0) return -1; - if (starts_with(var, "diff.color.") || starts_with(var, "color.diff.")) { - int slot = parse_diff_color_slot(var, 11); + if (skip_prefix(var, "diff.color.", &name) || + skip_prefix(var, "color.diff.", &name)) { + int slot = parse_diff_color_slot(name); if (slot < 0) return 0; if (!value) @@ -2341,6 +2344,7 @@ static void builtin_diff(const char *name_a, } else { /* Crazy xdl interfaces.. */ const char *diffopts = getenv("GIT_DIFF_OPTS"); + const char *v; xpparam_t xpp; xdemitconf_t xecfg; struct emit_callback ecbdata; @@ -2379,10 +2383,10 @@ static void builtin_diff(const char *name_a, xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags); if (!diffopts) ; - else if (starts_with(diffopts, "--unified=")) - xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10); - else if (starts_with(diffopts, "-u")) - xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10); + else if (skip_prefix(diffopts, "--unified=", &v)) + xecfg.ctxlen = strtoul(v, NULL, 10); + else if (skip_prefix(diffopts, "-u", &v)) + xecfg.ctxlen = strtoul(v, NULL, 10); if (o->word_diff) init_diff_words_data(&ecbdata, o, one, two); xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata, @@ -3391,12 +3395,10 @@ int parse_long_opt(const char *opt, const char **argv, const char **optarg) { const char *arg = argv[0]; - if (arg[0] != '-' || arg[1] != '-') + if (!skip_prefix(arg, "--", &arg)) return 0; - arg += strlen("--"); - if (!starts_with(arg, opt)) + if (!skip_prefix(arg, opt, &arg)) return 0; - arg += strlen(opt); if (*arg == '=') { /* stuck form: --option=value */ *optarg = arg + 1; return 1; @@ -3420,13 +3422,13 @@ static int stat_opt(struct diff_options *options, const char **av) int count = options->stat_count; int argcount = 1; - arg += strlen("--stat"); + if (!skip_prefix(arg, "--stat", &arg)) + die("BUG: stat option does not begin with --stat: %s", arg); end = (char *)arg; switch (*arg) { case '-': - if (starts_with(arg, "-width")) { - arg += strlen("-width"); + if (skip_prefix(arg, "-width", &arg)) { if (*arg == '=') width = strtoul(arg + 1, &end, 10); else if (!*arg && !av[1]) @@ -3435,8 +3437,7 @@ static int stat_opt(struct diff_options *options, const char **av) width = strtoul(av[1], &end, 10); argcount = 2; } - } else if (starts_with(arg, "-name-width")) { - arg += strlen("-name-width"); + } else if (skip_prefix(arg, "-name-width", &arg)) { if (*arg == '=') name_width = strtoul(arg + 1, &end, 10); else if (!*arg && !av[1]) @@ -3445,8 +3446,7 @@ static int stat_opt(struct diff_options *options, const char **av) name_width = strtoul(av[1], &end, 10); argcount = 2; } - } else if (starts_with(arg, "-graph-width")) { - arg += strlen("-graph-width"); + } else if (skip_prefix(arg, "-graph-width", &arg)) { if (*arg == '=') graph_width = strtoul(arg + 1, &end, 10); else if (!*arg && !av[1]) @@ -3455,8 +3455,7 @@ static int stat_opt(struct diff_options *options, const char **av) graph_width = strtoul(av[1], &end, 10); argcount = 2; } - } else if (starts_with(arg, "-count")) { - arg += strlen("-count"); + } else if (skip_prefix(arg, "-count", &arg)) { if (*arg == '=') count = strtoul(arg + 1, &end, 10); else if (!*arg && !av[1]) @@ -3609,17 +3608,17 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) options->output_format |= DIFF_FORMAT_SHORTSTAT; else if (!strcmp(arg, "-X") || !strcmp(arg, "--dirstat")) return parse_dirstat_opt(options, ""); - else if (starts_with(arg, "-X")) - return parse_dirstat_opt(options, arg + 2); - else if (starts_with(arg, "--dirstat=")) - return parse_dirstat_opt(options, arg + 10); + else if (skip_prefix(arg, "-X", &arg)) + return parse_dirstat_opt(options, arg); + else if (skip_prefix(arg, "--dirstat=", &arg)) + return parse_dirstat_opt(options, arg); else if (!strcmp(arg, "--cumulative")) return parse_dirstat_opt(options, "cumulative"); else if (!strcmp(arg, "--dirstat-by-file")) return parse_dirstat_opt(options, "files"); - else if (starts_with(arg, "--dirstat-by-file=")) { + else if (skip_prefix(arg, "--dirstat-by-file=", &arg)) { parse_dirstat_opt(options, "files"); - return parse_dirstat_opt(options, arg + 18); + return parse_dirstat_opt(options, arg); } else if (!strcmp(arg, "--check")) options->output_format |= DIFF_FORMAT_CHECKDIFF; @@ -3669,9 +3668,9 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) DIFF_OPT_CLR(options, RENAME_EMPTY); else if (!strcmp(arg, "--relative")) DIFF_OPT_SET(options, RELATIVE_NAME); - else if (starts_with(arg, "--relative=")) { + else if (skip_prefix(arg, "--relative=", &arg)) { DIFF_OPT_SET(options, RELATIVE_NAME); - options->prefix = arg + 11; + options->prefix = arg; } /* xdiff options */ @@ -3722,8 +3721,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) DIFF_OPT_CLR(options, FOLLOW_RENAMES); else if (!strcmp(arg, "--color")) options->use_color = 1; - else if (starts_with(arg, "--color=")) { - int value = git_config_colorbool(NULL, arg+8); + else if (skip_prefix(arg, "--color=", &arg)) { + int value = git_config_colorbool(NULL, arg); if (value < 0) return error("option `color' expects \"always\", \"auto\", or \"never\""); options->use_color = value; @@ -3734,29 +3733,28 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) options->use_color = 1; options->word_diff = DIFF_WORDS_COLOR; } - else if (starts_with(arg, "--color-words=")) { + else if (skip_prefix(arg, "--color-words=", &arg)) { options->use_color = 1; options->word_diff = DIFF_WORDS_COLOR; - options->word_regex = arg + 14; + options->word_regex = arg; } else if (!strcmp(arg, "--word-diff")) { if (options->word_diff == DIFF_WORDS_NONE) options->word_diff = DIFF_WORDS_PLAIN; } - else if (starts_with(arg, "--word-diff=")) { - const char *type = arg + 12; - if (!strcmp(type, "plain")) + else if (skip_prefix(arg, "--word-diff=", &arg)) { + if (!strcmp(arg, "plain")) options->word_diff = DIFF_WORDS_PLAIN; - else if (!strcmp(type, "color")) { + else if (!strcmp(arg, "color")) { options->use_color = 1; options->word_diff = DIFF_WORDS_COLOR; } - else if (!strcmp(type, "porcelain")) + else if (!strcmp(arg, "porcelain")) options->word_diff = DIFF_WORDS_PORCELAIN; - else if (!strcmp(type, "none")) + else if (!strcmp(arg, "none")) options->word_diff = DIFF_WORDS_NONE; else - die("bad --word-diff argument: %s", type); + die("bad --word-diff argument: %s", arg); } else if ((argcount = parse_long_opt("word-diff-regex", av, &optarg))) { if (options->word_diff == DIFF_WORDS_NONE) @@ -3779,13 +3777,13 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) else if (!strcmp(arg, "--ignore-submodules")) { DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG); handle_ignore_submodules_arg(options, "all"); - } else if (starts_with(arg, "--ignore-submodules=")) { + } else if (skip_prefix(arg, "--ignore-submodules=", &arg)) { DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG); - handle_ignore_submodules_arg(options, arg + 20); + handle_ignore_submodules_arg(options, arg); } else if (!strcmp(arg, "--submodule")) DIFF_OPT_SET(options, SUBMODULE_LOG); - else if (starts_with(arg, "--submodule=")) - return parse_submodule_opt(options, arg + 12); + else if (skip_prefix(arg, "--submodule=", &arg)) + return parse_submodule_opt(options, arg); /* misc options */ else if (!strcmp(arg, "-z")) @@ -3820,8 +3818,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) } else if (!strcmp(arg, "--abbrev")) options->abbrev = DEFAULT_ABBREV; - else if (starts_with(arg, "--abbrev=")) { - options->abbrev = strtoul(arg + 9, NULL, 10); + else if (skip_prefix(arg, "--abbrev=", &arg)) { + options->abbrev = strtoul(arg, NULL, 10); if (options->abbrev < MINIMUM_ABBREV) options->abbrev = MINIMUM_ABBREV; else if (40 < options->abbrev) @@ -3902,16 +3900,13 @@ static int diff_scoreopt_parse(const char *opt) cmd = *opt++; if (cmd == '-') { /* convert the long-form arguments into short-form versions */ - if (starts_with(opt, "break-rewrites")) { - opt += strlen("break-rewrites"); + if (skip_prefix(opt, "break-rewrites", &opt)) { if (*opt == 0 || *opt++ == '=') cmd = 'B'; - } else if (starts_with(opt, "find-copies")) { - opt += strlen("find-copies"); + } else if (skip_prefix(opt, "find-copies", &opt)) { if (*opt == 0 || *opt++ == '=') cmd = 'C'; - } else if (starts_with(opt, "find-renames")) { - opt += strlen("find-renames"); + } else if (skip_prefix(opt, "find-renames", &opt)) { if (*opt == 0 || *opt++ == '=') cmd = 'M'; } @@ -1354,8 +1354,7 @@ static int cmp_name(const void *p1, const void *p2) const struct dir_entry *e1 = *(const struct dir_entry **)p1; const struct dir_entry *e2 = *(const struct dir_entry **)p2; - return cache_name_compare(e1->name, e1->len, - e2->name, e2->len); + return name_compare(e1->name, e1->len, e2->name, e2->len); } static struct path_simplify *create_simplify(const char **pathspec) diff --git a/fast-import.c b/fast-import.c index 6707a66471..fa635f75c3 100644 --- a/fast-import.c +++ b/fast-import.c @@ -371,8 +371,8 @@ static volatile sig_atomic_t checkpoint_requested; static int cat_blob_fd = STDOUT_FILENO; static void parse_argv(void); -static void parse_cat_blob(void); -static void parse_ls(struct branch *b); +static void parse_cat_blob(const char *p); +static void parse_ls(const char *p, struct branch *b); static void write_branch_report(FILE *rpt, struct branch *b) { @@ -1861,6 +1861,8 @@ static int read_next_command(void) } for (;;) { + const char *p; + if (unread_command_buf) { unread_command_buf = 0; } else { @@ -1893,8 +1895,8 @@ static int read_next_command(void) rc->prev->next = rc; cmd_tail = rc; } - if (starts_with(command_buf.buf, "cat-blob ")) { - parse_cat_blob(); + if (skip_prefix(command_buf.buf, "cat-blob ", &p)) { + parse_cat_blob(p); continue; } if (command_buf.buf[0] == '#') @@ -1912,8 +1914,9 @@ static void skip_optional_lf(void) static void parse_mark(void) { - if (starts_with(command_buf.buf, "mark :")) { - next_mark = strtoumax(command_buf.buf + 6, NULL, 10); + const char *v; + if (skip_prefix(command_buf.buf, "mark :", &v)) { + next_mark = strtoumax(v, NULL, 10); read_next_command(); } else @@ -1922,14 +1925,15 @@ static void parse_mark(void) static int parse_data(struct strbuf *sb, uintmax_t limit, uintmax_t *len_res) { + const char *data; strbuf_reset(sb); - if (!starts_with(command_buf.buf, "data ")) + if (!skip_prefix(command_buf.buf, "data ", &data)) die("Expected 'data n' command, found: %s", command_buf.buf); - if (starts_with(command_buf.buf + 5, "<<")) { - char *term = xstrdup(command_buf.buf + 5 + 2); - size_t term_len = command_buf.len - 5 - 2; + if (skip_prefix(data, "<<", &data)) { + char *term = xstrdup(data); + size_t term_len = command_buf.len - (data - command_buf.buf); strbuf_detach(&command_buf, NULL); for (;;) { @@ -1944,7 +1948,7 @@ static int parse_data(struct strbuf *sb, uintmax_t limit, uintmax_t *len_res) free(term); } else { - uintmax_t len = strtoumax(command_buf.buf + 5, NULL, 10); + uintmax_t len = strtoumax(data, NULL, 10); size_t n = 0, length = (size_t)len; if (limit && limit < len) { @@ -2265,15 +2269,14 @@ static uintmax_t parse_mark_ref_space(const char **p) char *end; mark = parse_mark_ref(*p, &end); - if (*end != ' ') + if (*end++ != ' ') die("Missing space after mark: %s", command_buf.buf); *p = end; return mark; } -static void file_change_m(struct branch *b) +static void file_change_m(const char *p, struct branch *b) { - const char *p = command_buf.buf + 2; static struct strbuf uq = STRBUF_INIT; const char *endp; struct object_entry *oe; @@ -2301,20 +2304,17 @@ static void file_change_m(struct branch *b) if (*p == ':') { oe = find_mark(parse_mark_ref_space(&p)); hashcpy(sha1, oe->idx.sha1); - } else if (starts_with(p, "inline ")) { + } else if (skip_prefix(p, "inline ", &p)) { inline_data = 1; oe = NULL; /* not used with inline_data, but makes gcc happy */ - p += strlen("inline"); /* advance to space */ } else { if (get_sha1_hex(p, sha1)) die("Invalid dataref: %s", command_buf.buf); oe = find_object(sha1); p += 40; - if (*p != ' ') + if (*p++ != ' ') die("Missing space after SHA1: %s", command_buf.buf); } - assert(*p == ' '); - p++; /* skip space */ strbuf_reset(&uq); if (!unquote_c_style(&uq, p, &endp)) { @@ -2374,9 +2374,8 @@ static void file_change_m(struct branch *b) tree_content_set(&b->branch_tree, p, sha1, mode, NULL); } -static void file_change_d(struct branch *b) +static void file_change_d(const char *p, struct branch *b) { - const char *p = command_buf.buf + 2; static struct strbuf uq = STRBUF_INIT; const char *endp; @@ -2389,15 +2388,14 @@ static void file_change_d(struct branch *b) tree_content_remove(&b->branch_tree, p, NULL, 1); } -static void file_change_cr(struct branch *b, int rename) +static void file_change_cr(const char *s, struct branch *b, int rename) { - const char *s, *d; + const char *d; static struct strbuf s_uq = STRBUF_INIT; static struct strbuf d_uq = STRBUF_INIT; const char *endp; struct tree_entry leaf; - s = command_buf.buf + 2; strbuf_reset(&s_uq); if (!unquote_c_style(&s_uq, s, &endp)) { if (*endp != ' ') @@ -2442,9 +2440,8 @@ static void file_change_cr(struct branch *b, int rename) leaf.tree); } -static void note_change_n(struct branch *b, unsigned char *old_fanout) +static void note_change_n(const char *p, struct branch *b, unsigned char *old_fanout) { - const char *p = command_buf.buf + 2; static struct strbuf uq = STRBUF_INIT; struct object_entry *oe; struct branch *s; @@ -2474,20 +2471,17 @@ static void note_change_n(struct branch *b, unsigned char *old_fanout) if (*p == ':') { oe = find_mark(parse_mark_ref_space(&p)); hashcpy(sha1, oe->idx.sha1); - } else if (starts_with(p, "inline ")) { + } else if (skip_prefix(p, "inline ", &p)) { inline_data = 1; oe = NULL; /* not used with inline_data, but makes gcc happy */ - p += strlen("inline"); /* advance to space */ } else { if (get_sha1_hex(p, sha1)) die("Invalid dataref: %s", command_buf.buf); oe = find_object(sha1); p += 40; - if (*p != ' ') + if (*p++ != ' ') die("Missing space after SHA1: %s", command_buf.buf); } - assert(*p == ' '); - p++; /* skip space */ /* <commit-ish> */ s = lookup_branch(p); @@ -2585,7 +2579,7 @@ static int parse_from(struct branch *b) const char *from; struct branch *s; - if (!starts_with(command_buf.buf, "from ")) + if (!skip_prefix(command_buf.buf, "from ", &from)) return 0; if (b->branch_tree.tree) { @@ -2593,7 +2587,6 @@ static int parse_from(struct branch *b) b->branch_tree.tree = NULL; } - from = strchr(command_buf.buf, ' ') + 1; s = lookup_branch(from); if (b == s) die("Can't create a branch from itself: %s", b->name); @@ -2634,8 +2627,7 @@ static struct hash_list *parse_merge(unsigned int *count) struct branch *s; *count = 0; - while (starts_with(command_buf.buf, "merge ")) { - from = strchr(command_buf.buf, ' ') + 1; + while (skip_prefix(command_buf.buf, "merge ", &from)) { n = xmalloc(sizeof(*n)); s = lookup_branch(from); if (s) @@ -2666,31 +2658,29 @@ static struct hash_list *parse_merge(unsigned int *count) return list; } -static void parse_new_commit(void) +static void parse_new_commit(const char *arg) { static struct strbuf msg = STRBUF_INIT; struct branch *b; - char *sp; char *author = NULL; char *committer = NULL; struct hash_list *merge_list = NULL; unsigned int merge_count; unsigned char prev_fanout, new_fanout; + const char *v; - /* Obtain the branch name from the rest of our command */ - sp = strchr(command_buf.buf, ' ') + 1; - b = lookup_branch(sp); + b = lookup_branch(arg); if (!b) - b = new_branch(sp); + b = new_branch(arg); read_next_command(); parse_mark(); - if (starts_with(command_buf.buf, "author ")) { - author = parse_ident(command_buf.buf + 7); + if (skip_prefix(command_buf.buf, "author ", &v)) { + author = parse_ident(v); read_next_command(); } - if (starts_with(command_buf.buf, "committer ")) { - committer = parse_ident(command_buf.buf + 10); + if (skip_prefix(command_buf.buf, "committer ", &v)) { + committer = parse_ident(v); read_next_command(); } if (!committer) @@ -2710,20 +2700,20 @@ static void parse_new_commit(void) /* file_change* */ while (command_buf.len > 0) { - if (starts_with(command_buf.buf, "M ")) - file_change_m(b); - else if (starts_with(command_buf.buf, "D ")) - file_change_d(b); - else if (starts_with(command_buf.buf, "R ")) - file_change_cr(b, 1); - else if (starts_with(command_buf.buf, "C ")) - file_change_cr(b, 0); - else if (starts_with(command_buf.buf, "N ")) - note_change_n(b, &prev_fanout); + if (skip_prefix(command_buf.buf, "M ", &v)) + file_change_m(v, b); + else if (skip_prefix(command_buf.buf, "D ", &v)) + file_change_d(v, b); + else if (skip_prefix(command_buf.buf, "R ", &v)) + file_change_cr(v, b, 1); + else if (skip_prefix(command_buf.buf, "C ", &v)) + file_change_cr(v, b, 0); + else if (skip_prefix(command_buf.buf, "N ", &v)) + note_change_n(v, b, &prev_fanout); else if (!strcmp("deleteall", command_buf.buf)) file_change_deleteall(b); - else if (starts_with(command_buf.buf, "ls ")) - parse_ls(b); + else if (skip_prefix(command_buf.buf, "ls ", &v)) + parse_ls(v, b); else { unread_command_buf = 1; break; @@ -2766,10 +2756,9 @@ static void parse_new_commit(void) b->last_commit = object_count_by_type[OBJ_COMMIT]; } -static void parse_new_tag(void) +static void parse_new_tag(const char *arg) { static struct strbuf msg = STRBUF_INIT; - char *sp; const char *from; char *tagger; struct branch *s; @@ -2777,12 +2766,11 @@ static void parse_new_tag(void) uintmax_t from_mark = 0; unsigned char sha1[20]; enum object_type type; + const char *v; - /* Obtain the new tag name from the rest of our command */ - sp = strchr(command_buf.buf, ' ') + 1; t = pool_alloc(sizeof(struct tag)); memset(t, 0, sizeof(struct tag)); - t->name = pool_strdup(sp); + t->name = pool_strdup(arg); if (last_tag) last_tag->next_tag = t; else @@ -2791,9 +2779,8 @@ static void parse_new_tag(void) read_next_command(); /* from ... */ - if (!starts_with(command_buf.buf, "from ")) + if (!skip_prefix(command_buf.buf, "from ", &from)) die("Expected from command, got %s", command_buf.buf); - from = strchr(command_buf.buf, ' ') + 1; s = lookup_branch(from); if (s) { if (is_null_sha1(s->sha1)) @@ -2819,8 +2806,8 @@ static void parse_new_tag(void) read_next_command(); /* tagger ... */ - if (starts_with(command_buf.buf, "tagger ")) { - tagger = parse_ident(command_buf.buf + 7); + if (skip_prefix(command_buf.buf, "tagger ", &v)) { + tagger = parse_ident(v); read_next_command(); } else tagger = NULL; @@ -2849,14 +2836,11 @@ static void parse_new_tag(void) t->pack_id = pack_id; } -static void parse_reset_branch(void) +static void parse_reset_branch(const char *arg) { struct branch *b; - char *sp; - /* Obtain the branch name from the rest of our command */ - sp = strchr(command_buf.buf, ' ') + 1; - b = lookup_branch(sp); + b = lookup_branch(arg); if (b) { hashclr(b->sha1); hashclr(b->branch_tree.versions[0].sha1); @@ -2867,7 +2851,7 @@ static void parse_reset_branch(void) } } else - b = new_branch(sp); + b = new_branch(arg); read_next_command(); parse_from(b); if (command_buf.len > 0) @@ -2925,14 +2909,12 @@ static void cat_blob(struct object_entry *oe, unsigned char sha1[20]) free(buf); } -static void parse_cat_blob(void) +static void parse_cat_blob(const char *p) { - const char *p; struct object_entry *oe = oe; unsigned char sha1[20]; /* cat-blob SP <object> LF */ - p = command_buf.buf + strlen("cat-blob "); if (*p == ':') { oe = find_mark(parse_mark_ref_eol(p)); if (!oe) @@ -3015,6 +2997,8 @@ static struct object_entry *parse_treeish_dataref(const char **p) die("Invalid dataref: %s", command_buf.buf); e = find_object(sha1); *p += 40; + if (*(*p)++ != ' ') + die("Missing space after tree-ish: %s", command_buf.buf); } while (!e || e->type != OBJ_TREE) @@ -3049,14 +3033,12 @@ static void print_ls(int mode, const unsigned char *sha1, const char *path) cat_blob_write(line.buf, line.len); } -static void parse_ls(struct branch *b) +static void parse_ls(const char *p, struct branch *b) { - const char *p; struct tree_entry *root = NULL; struct tree_entry leaf = {NULL}; /* ls SP (<tree-ish> SP)? <path> */ - p = command_buf.buf + strlen("ls "); if (*p == '"') { if (!b) die("Not in a commit: %s", command_buf.buf); @@ -3068,8 +3050,6 @@ static void parse_ls(struct branch *b) if (!is_null_sha1(root->versions[1].sha1)) root->versions[1].mode = S_IFDIR; load_tree(root); - if (*p++ != ' ') - die("Missing space after tree-ish: %s", command_buf.buf); } if (*p == '"') { static struct strbuf uq = STRBUF_INIT; @@ -3207,9 +3187,9 @@ static void option_export_pack_edges(const char *edges) static int parse_one_option(const char *option) { - if (starts_with(option, "max-pack-size=")) { + if (skip_prefix(option, "max-pack-size=", &option)) { unsigned long v; - if (!git_parse_ulong(option + 14, &v)) + if (!git_parse_ulong(option, &v)) return 0; if (v < 8192) { warning("max-pack-size is now in bytes, assuming --max-pack-size=%lum", v); @@ -3219,17 +3199,17 @@ static int parse_one_option(const char *option) v = 1024 * 1024; } max_packsize = v; - } else if (starts_with(option, "big-file-threshold=")) { + } else if (skip_prefix(option, "big-file-threshold=", &option)) { unsigned long v; - if (!git_parse_ulong(option + 19, &v)) + if (!git_parse_ulong(option, &v)) return 0; big_file_threshold = v; - } else if (starts_with(option, "depth=")) { - option_depth(option + 6); - } else if (starts_with(option, "active-branches=")) { - option_active_branches(option + 16); - } else if (starts_with(option, "export-pack-edges=")) { - option_export_pack_edges(option + 18); + } else if (skip_prefix(option, "depth=", &option)) { + option_depth(option); + } else if (skip_prefix(option, "active-branches=", &option)) { + option_active_branches(option); + } else if (skip_prefix(option, "export-pack-edges=", &option)) { + option_export_pack_edges(option); } else if (starts_with(option, "quiet")) { show_stats = 0; } else if (starts_with(option, "stats")) { @@ -3243,15 +3223,16 @@ static int parse_one_option(const char *option) static int parse_one_feature(const char *feature, int from_stream) { - if (starts_with(feature, "date-format=")) { - option_date_format(feature + 12); - } else if (starts_with(feature, "import-marks=")) { - option_import_marks(feature + 13, from_stream, 0); - } else if (starts_with(feature, "import-marks-if-exists=")) { - option_import_marks(feature + strlen("import-marks-if-exists="), - from_stream, 1); - } else if (starts_with(feature, "export-marks=")) { - option_export_marks(feature + 13); + const char *arg; + + if (skip_prefix(feature, "date-format=", &arg)) { + option_date_format(arg); + } else if (skip_prefix(feature, "import-marks=", &arg)) { + option_import_marks(arg, from_stream, 0); + } else if (skip_prefix(feature, "import-marks-if-exists=", &arg)) { + option_import_marks(arg, from_stream, 1); + } else if (skip_prefix(feature, "export-marks=", &arg)) { + option_export_marks(arg); } else if (!strcmp(feature, "cat-blob")) { ; /* Don't die - this feature is supported */ } else if (!strcmp(feature, "relative-marks")) { @@ -3271,10 +3252,8 @@ static int parse_one_feature(const char *feature, int from_stream) return 1; } -static void parse_feature(void) +static void parse_feature(const char *feature) { - char *feature = command_buf.buf + 8; - if (seen_data_command) die("Got feature command '%s' after data command", feature); @@ -3284,10 +3263,8 @@ static void parse_feature(void) die("This version of fast-import does not support feature %s.", feature); } -static void parse_option(void) +static void parse_option(const char *option) { - char *option = command_buf.buf + 11; - if (seen_data_command) die("Got option command '%s' after data command", option); @@ -3342,18 +3319,21 @@ static void parse_argv(void) if (*a != '-' || !strcmp(a, "--")) break; - if (parse_one_option(a + 2)) + if (!skip_prefix(a, "--", &a)) + die("unknown option %s", a); + + if (parse_one_option(a)) continue; - if (parse_one_feature(a + 2, 0)) + if (parse_one_feature(a, 0)) continue; - if (starts_with(a + 2, "cat-blob-fd=")) { - option_cat_blob_fd(a + 2 + strlen("cat-blob-fd=")); + if (skip_prefix(a, "cat-blob-fd=", &a)) { + option_cat_blob_fd(a); continue; } - die("unknown option %s", a); + die("unknown option --%s", a); } if (i != global_argc) usage(fast_import_usage); @@ -3400,26 +3380,27 @@ int main(int argc, char **argv) set_die_routine(die_nicely); set_checkpoint_signal(); while (read_next_command() != EOF) { + const char *v; if (!strcmp("blob", command_buf.buf)) parse_new_blob(); - else if (starts_with(command_buf.buf, "ls ")) - parse_ls(NULL); - else if (starts_with(command_buf.buf, "commit ")) - parse_new_commit(); - else if (starts_with(command_buf.buf, "tag ")) - parse_new_tag(); - else if (starts_with(command_buf.buf, "reset ")) - parse_reset_branch(); + else if (skip_prefix(command_buf.buf, "ls ", &v)) + parse_ls(v, NULL); + else if (skip_prefix(command_buf.buf, "commit ", &v)) + parse_new_commit(v); + else if (skip_prefix(command_buf.buf, "tag ", &v)) + parse_new_tag(v); + else if (skip_prefix(command_buf.buf, "reset ", &v)) + parse_reset_branch(v); else if (!strcmp("checkpoint", command_buf.buf)) parse_checkpoint(); else if (!strcmp("done", command_buf.buf)) break; else if (starts_with(command_buf.buf, "progress ")) parse_progress(); - else if (starts_with(command_buf.buf, "feature ")) - parse_feature(); - else if (starts_with(command_buf.buf, "option git ")) - parse_option(); + else if (skip_prefix(command_buf.buf, "feature ", &v)) + parse_feature(v); + else if (skip_prefix(command_buf.buf, "option git ", &v)) + parse_option(v); else if (starts_with(command_buf.buf, "option ")) /* ignore non-git options*/; else diff --git a/fetch-pack.c b/fetch-pack.c index eeee2bb7e0..b8a58fa7a5 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -189,20 +189,23 @@ static enum ack_type get_ack(int fd, unsigned char *result_sha1) { int len; char *line = packet_read_line(fd, &len); + const char *arg; if (!len) die("git fetch-pack: expected ACK/NAK, got EOF"); if (!strcmp(line, "NAK")) return NAK; - if (starts_with(line, "ACK ")) { - if (!get_sha1_hex(line+4, result_sha1)) { - if (len < 45) + if (skip_prefix(line, "ACK ", &arg)) { + if (!get_sha1_hex(arg, result_sha1)) { + arg += 40; + len -= arg - line; + if (len < 1) return ACK; - if (strstr(line+45, "continue")) + if (strstr(arg, "continue")) return ACK_continue; - if (strstr(line+45, "common")) + if (strstr(arg, "common")) return ACK_common; - if (strstr(line+45, "ready")) + if (strstr(arg, "ready")) return ACK_ready; return ACK; } @@ -319,18 +322,19 @@ static int find_common(struct fetch_pack_args *args, if (args->depth > 0) { char *line; + const char *arg; unsigned char sha1[20]; send_request(args, fd[1], &req_buf); while ((line = packet_read_line(fd[0], NULL))) { - if (starts_with(line, "shallow ")) { - if (get_sha1_hex(line + 8, sha1)) + if (skip_prefix(line, "shallow ", &arg)) { + if (get_sha1_hex(arg, sha1)) die("invalid shallow line: %s", line); register_shallow(sha1); continue; } - if (starts_with(line, "unshallow ")) { - if (get_sha1_hex(line + 10, sha1)) + if (skip_prefix(line, "unshallow ", &arg)) { + if (get_sha1_hex(arg, sha1)) die("invalid unshallow line: %s", line); if (!lookup_object(sha1)) die("object not found: %s", line); @@ -507,7 +511,7 @@ static void filter_refs(struct fetch_pack_args *args, int keep = 0; next = ref->next; - if (!memcmp(ref->name, "refs/", 5) && + if (starts_with(ref->name, "refs/") && check_refname_format(ref->name, 0)) ; /* trash */ else { @@ -276,22 +276,20 @@ static int fsck_ident(const char **ident, struct object *obj, fsck_error error_f return 0; } -static int fsck_commit(struct commit *commit, fsck_error error_func) +static int fsck_commit_buffer(struct commit *commit, const char *buffer, + fsck_error error_func) { - const char *buffer = commit->buffer, *tmp; unsigned char tree_sha1[20], sha1[20]; struct commit_graft *graft; int parents = 0; int err; - buffer = skip_prefix(buffer, "tree "); - if (!buffer) + if (!skip_prefix(buffer, "tree ", &buffer)) return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'tree' line"); if (get_sha1_hex(buffer, tree_sha1) || buffer[40] != '\n') return error_func(&commit->object, FSCK_ERROR, "invalid 'tree' line format - bad sha1"); buffer += 41; - while ((tmp = skip_prefix(buffer, "parent "))) { - buffer = tmp; + while (skip_prefix(buffer, "parent ", &buffer)) { if (get_sha1_hex(buffer, sha1) || buffer[40] != '\n') return error_func(&commit->object, FSCK_ERROR, "invalid 'parent' line format - bad sha1"); buffer += 41; @@ -318,14 +316,12 @@ static int fsck_commit(struct commit *commit, fsck_error error_func) if (p || parents) return error_func(&commit->object, FSCK_ERROR, "parent objects missing"); } - buffer = skip_prefix(buffer, "author "); - if (!buffer) + if (!skip_prefix(buffer, "author ", &buffer)) return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'author' line"); err = fsck_ident(&buffer, &commit->object, error_func); if (err) return err; - buffer = skip_prefix(buffer, "committer "); - if (!buffer) + if (!skip_prefix(buffer, "committer ", &buffer)) return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'committer' line"); err = fsck_ident(&buffer, &commit->object, error_func); if (err) @@ -336,6 +332,14 @@ static int fsck_commit(struct commit *commit, fsck_error error_func) return 0; } +static int fsck_commit(struct commit *commit, fsck_error error_func) +{ + const char *buffer = get_commit_buffer(commit, NULL); + int ret = fsck_commit_buffer(commit, buffer, error_func); + unuse_commit_buffer(commit, buffer); + return ret; +} + static int fsck_tag(struct tag *tag, fsck_error error_func) { struct object *tagged = tag->tagged; diff --git a/git-bisect.sh b/git-bisect.sh index af4d04c3be..1e0d602f4b 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -408,7 +408,7 @@ bisect_replay () { bisect_reset while read git bisect command rev do - test "$git $bisect" = "git bisect" -o "$git" = "git-bisect" || continue + test "$git $bisect" = "git bisect" || test "$git" = "git-bisect" || continue if test "$git" = "git-bisect" then rev="$command" diff --git a/git-compat-util.h b/git-compat-util.h index b6f03b36dc..9de3180710 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -349,13 +349,32 @@ extern void set_die_is_recursing_routine(int (*routine)(void)); extern int starts_with(const char *str, const char *prefix); extern int ends_with(const char *str, const char *suffix); -static inline const char *skip_prefix(const char *str, const char *prefix) +/* + * If the string "str" begins with the string found in "prefix", return 1. + * The "out" parameter is set to "str + strlen(prefix)" (i.e., to the point in + * the string right after the prefix). + * + * Otherwise, return 0 and leave "out" untouched. + * + * Examples: + * + * [extract branch name, fail if not a branch] + * if (!skip_prefix(ref, "refs/heads/", &branch) + * return -1; + * + * [skip prefix if present, otherwise use whole string] + * skip_prefix(name, "refs/heads/", &name); + */ +static inline int skip_prefix(const char *str, const char *prefix, + const char **out) { do { - if (!*prefix) - return str; + if (!*prefix) { + *out = str; + return 1; + } } while (*str++ == *prefix++); - return NULL; + return 0; } #if defined(NO_MMAP) || defined(USE_WIN32_MMAP) @@ -685,6 +704,17 @@ void git_qsort(void *base, size_t nmemb, size_t size, #endif #endif +#if defined(__GNUC__) && defined(__x86_64__) +#include <emmintrin.h> +/* + * This is the system memory page size; it's used so that we can read + * outside the bounds of an allocation without segfaulting. + */ +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif +#endif + #ifdef UNRELIABLE_FSTAT #define fstat_is_reliable() 0 #else diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 6a8907e7b3..b186329d28 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1558,7 +1558,11 @@ proc rescan_stage2 {fd after} { set rescan_active 2 ui_status [mc "Scanning for modified files ..."] - set fd_di [git_read diff-index --cached -z [PARENT]] + if {[git-version >= "1.7.2"]} { + set fd_di [git_read diff-index --cached --ignore-submodules=dirty -z [PARENT]] + } else { + set fd_di [git_read diff-index --cached -z [PARENT]] + } set fd_df [git_read diff-files -z] fconfigure $fd_di -blocking 0 -translation binary -encoding binary diff --git a/git-gui/lib/diff.tcl b/git-gui/lib/diff.tcl index 30d9a79776..b0a5180af7 100644 --- a/git-gui/lib/diff.tcl +++ b/git-gui/lib/diff.tcl @@ -287,6 +287,9 @@ proc start_show_diff {cont_info {add_opts {}}} { if {$w eq $ui_index} { lappend cmd diff-index lappend cmd --cached + if {[git-version >= "1.7.2"]} { + lappend cmd --ignore-submodules=dirty + } } elseif {$w eq $ui_workdir} { if {[string first {U} $m] >= 0} { lappend cmd diff diff --git a/git-mergetool.sh b/git-mergetool.sh index d08dc92589..9a046b75d1 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -205,7 +205,7 @@ checkout_staged_file () { "$(git checkout-index --temp --stage="$1" "$2" 2>/dev/null)" \ : '\([^ ]*\) ') - if test $? -eq 0 -a -n "$tmpfile" + if test $? -eq 0 && test -n "$tmpfile" then mv -- "$(git rev-parse --show-cdup)$tmpfile" "$3" else @@ -256,7 +256,7 @@ merge_file () { checkout_staged_file 2 "$MERGED" "$LOCAL" checkout_staged_file 3 "$MERGED" "$REMOTE" - if test -z "$local_mode" -o -z "$remote_mode" + if test -z "$local_mode" || test -z "$remote_mode" then echo "Deleted merge conflict for '$MERGED':" describe_file "$local_mode" "local" "$LOCAL" @@ -1238,7 +1238,7 @@ class P4Submit(Command, P4UserMap): if response == 'n': return False - def get_diff_description(self, editedFiles): + def get_diff_description(self, editedFiles, filesToAdd): # diff if os.environ.has_key("P4DIFF"): del(os.environ["P4DIFF"]) @@ -1258,7 +1258,7 @@ class P4Submit(Command, P4UserMap): newdiff += "+" + line f.close() - return diff + newdiff + return (diff + newdiff).replace('\r\n', '\n') def applyCommit(self, id): """Apply one commit, return True if it succeeded.""" @@ -1422,10 +1422,10 @@ class P4Submit(Command, P4UserMap): separatorLine = "######## everything below this line is just the diff #######\n" if not self.prepare_p4_only: submitTemplate += separatorLine - submitTemplate += self.get_diff_description(editedFiles) + submitTemplate += self.get_diff_description(editedFiles, filesToAdd) (handle, fileName) = tempfile.mkstemp() - tmpFile = os.fdopen(handle, "w+") + tmpFile = os.fdopen(handle, "w+b") if self.isWindows: submitTemplate = submitTemplate.replace("\n", "\r\n") tmpFile.write(submitTemplate) @@ -1475,9 +1475,9 @@ class P4Submit(Command, P4UserMap): tmpFile = open(fileName, "rb") message = tmpFile.read() tmpFile.close() - submitTemplate = message[:message.index(separatorLine)] if self.isWindows: - submitTemplate = submitTemplate.replace("\r\n", "\n") + message = message.replace("\r\n", "\n") + submitTemplate = message[:message.index(separatorLine)] p4_write_pipe(['submit', '-i'], submitTemplate) if self.preserveUser: diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index f267d8b6c3..7e1eda0088 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -1013,7 +1013,7 @@ then git rev-list $revisions | while read rev do - if test -f "$rewritten"/$rev -a "$(sane_grep "$rev" "$state_dir"/not-cherry-picks)" = "" + if test -f "$rewritten"/$rev && test "$(sane_grep "$rev" "$state_dir"/not-cherry-picks)" = "" then # Use -f2 because if rev-list is telling us this commit is # not worthwhile, we don't want to track its multiple heads, diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh index 6d77b3ca91..d3fb67d75b 100644 --- a/git-rebase--merge.sh +++ b/git-rebase--merge.sh @@ -53,11 +53,12 @@ continue_merge () { } call_merge () { - cmt="$(cat "$state_dir/cmt.$1")" + msgnum="$1" + echo "$msgnum" >"$state_dir/msgnum" + cmt="$(cat "$state_dir/cmt.$msgnum")" echo "$cmt" > "$state_dir/current" hd=$(git rev-parse --verify HEAD) cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD) - msgnum=$(cat "$state_dir/msgnum") eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"' eval GITHEAD_$hd='$onto_name' export GITHEAD_$cmt GITHEAD_$hd diff --git a/git-send-email.perl b/git-send-email.perl index abd62b484c..9949db01e1 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -80,6 +80,8 @@ git send-email [options] <file | directory | rev-list options > --to-cmd <str> * Email To: via `<str> \$patch_path` --cc-cmd <str> * Email Cc: via `<str> \$patch_path` --suppress-cc <str> * author, self, sob, cc, cccmd, body, bodycc, all. + --[no-]cc-cover * Email Cc: addresses in the cover letter. + --[no-]to-cover * Email To: addresses in the cover letter. --[no-]signed-off-by-cc * Send to Signed-off-by: addresses. Default on. --[no-]suppress-from * Send to self. Default off. --[no-]chain-reply-to * Chain In-Reply-To: fields. Default off. @@ -195,6 +197,7 @@ sub do_edit { # Variables with corresponding config settings my ($thread, $chain_reply_to, $suppress_from, $signed_off_by_cc); +my ($cover_cc, $cover_to); my ($to_cmd, $cc_cmd); my ($smtp_server, $smtp_server_port, @smtp_server_options); my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path); @@ -211,6 +214,8 @@ my %config_bool_settings = ( "chainreplyto" => [\$chain_reply_to, 0], "suppressfrom" => [\$suppress_from, undef], "signedoffbycc" => [\$signed_off_by_cc, undef], + "cccover" => [\$cover_cc, undef], + "tocover" => [\$cover_to, undef], "signedoffcc" => [\$signed_off_by_cc, undef], # Deprecated "validate" => [\$validate, 1], "multiedit" => [\$multiedit, undef], @@ -302,6 +307,8 @@ my $rc = GetOptions("h" => \$help, "suppress-from!" => \$suppress_from, "suppress-cc=s" => \@suppress_cc, "signed-off-cc|signed-off-by-cc!" => \$signed_off_by_cc, + "cc-cover|cc-cover!" => \$cover_cc, + "to-cover|to-cover!" => \$cover_to, "confirm=s" => \$confirm, "dry-run" => \$dry_run, "envelope-sender=s" => \$envelope_sender, @@ -1481,6 +1488,15 @@ foreach my $t (@files) { @to = (@initial_to, @to); @cc = (@initial_cc, @cc); + if ($message_num == 1) { + if (defined $cover_cc and $cover_cc) { + @initial_cc = @cc; + } + if (defined $cover_to and $cover_to) { + @initial_to = @to; + } + } + my $message_was_sent = send_message(); # set up for the next message diff --git a/git-submodule.sh b/git-submodule.sh index e146b833d1..9245abfd42 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -235,7 +235,7 @@ module_name() sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' ) test -z "$name" && die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$sm_path'")" - echo "$name" + printf '%s\n' "$name" } # @@ -305,10 +305,10 @@ module_clone() b=${b%/} # Turn each leading "*/" component into "../" - rel=$(echo $b | sed -e 's|[^/][^/]*|..|g') - echo "gitdir: $rel/$a" >"$sm_path/.git" + rel=$(printf '%s\n' "$b" | sed -e 's|[^/][^/]*|..|g') + printf '%s\n' "gitdir: $rel/$a" >"$sm_path/.git" - rel=$(echo $a | sed -e 's|[^/][^/]*|..|g') + rel=$(printf '%s\n' "$a" | sed -e 's|[^/][^/]*|..|g') (clear_local_git_env; cd "$sm_path" && GIT_WORK_TREE=. git config core.worktree "$rel/$b") } @@ -389,11 +389,11 @@ cmd_add() sm_path=$2 if test -z "$sm_path"; then - sm_path=$(echo "$repo" | + sm_path=$(printf '%s\n' "$repo" | sed -e 's|/$||' -e 's|:*/*\.git$||' -e 's|.*[/:]||g') fi - if test -z "$repo" -o -z "$sm_path"; then + if test -z "$repo" || test -z "$sm_path"; then usage fi @@ -450,7 +450,7 @@ Use -f if you really want to add it." >&2 # perhaps the path exists and is already a git repo, else clone it if test -e "$sm_path" then - if test -d "$sm_path"/.git -o -f "$sm_path"/.git + if test -d "$sm_path"/.git || test -f "$sm_path"/.git then eval_gettextln "Adding existing repo at '\$sm_path' to the index" else @@ -832,7 +832,7 @@ Maybe you want to use 'update --init'?")" continue fi - if ! test -d "$sm_path"/.git -o -f "$sm_path"/.git + if ! test -d "$sm_path"/.git && ! test -f "$sm_path"/.git then module_clone "$sm_path" "$name" "$url" "$reference" "$depth" || exit cloned_modules="$cloned_modules;$name" @@ -857,11 +857,11 @@ Maybe you want to use 'update --init'?")" die "$(eval_gettext "Unable to find current ${remote_name}/${branch} revision in submodule path '\$sm_path'")" fi - if test "$subsha1" != "$sha1" -o -n "$force" + if test "$subsha1" != "$sha1" || test -n "$force" then subforce=$force # If we don't already have a -f flag and the submodule has never been checked out - if test -z "$subsha1" -a -z "$force" + if test -z "$subsha1" && test -z "$force" then subforce="-f" fi @@ -1031,7 +1031,7 @@ cmd_summary() { then head=$rev test $# = 0 || shift - elif test -z "$1" -o "$1" = "HEAD" + elif test -z "$1" || test "$1" = "HEAD" then # before the first commit: compare with an empty tree head=$(git hash-object -w -t tree --stdin </dev/null) @@ -1056,17 +1056,21 @@ cmd_summary() { while read mod_src mod_dst sha1_src sha1_dst status sm_path do # Always show modules deleted or type-changed (blob<->module) - test $status = D -o $status = T && echo "$sm_path" && continue + if test "$status" = D || test "$status" = T + then + printf '%s\n' "$sm_path" + continue + fi # Respect the ignore setting for --for-status. if test -n "$for_status" then name=$(module_name "$sm_path") ignore_config=$(get_submodule_config "$name" ignore none) - test $status != A -a $ignore_config = all && continue + test $status != A && test $ignore_config = all && continue fi # Also show added or modified modules which are checked out GIT_DIR="$sm_path/.git" git-rev-parse --git-dir >/dev/null 2>&1 && - echo "$sm_path" + printf '%s\n' "$sm_path" done ) @@ -1122,7 +1126,7 @@ cmd_summary() { *) errmsg= total_commits=$( - if test $mod_src = 160000 -a $mod_dst = 160000 + if test $mod_src = 160000 && test $mod_dst = 160000 then range="$sha1_src...$sha1_dst" elif test $mod_src = 160000 @@ -1159,7 +1163,7 @@ cmd_summary() { # i.e. deleted or changed to blob test $mod_dst = 160000 && echo "$errmsg" else - if test $mod_src = 160000 -a $mod_dst = 160000 + if test $mod_src = 160000 && test $mod_dst = 160000 then limit= test $summary_limit -gt 0 && limit="-$summary_limit" @@ -1230,7 +1234,11 @@ cmd_status() say "U$sha1 $displaypath" continue fi - if test -z "$url" || ! test -d "$sm_path"/.git -o -f "$sm_path"/.git + if test -z "$url" || + { + ! test -d "$sm_path"/.git && + ! test -f "$sm_path"/.git + } then say "-$sha1 $displaypath" continue; @@ -1303,7 +1311,7 @@ cmd_sync() ./*|../*) # rewrite foo/bar as ../.. to find path from # submodule work tree to superproject work tree - up_path="$(echo "$sm_path" | sed "s/[^/][^/]*/../g")" && + up_path="$(printf '%s\n' "$sm_path" | sed "s/[^/][^/]*/../g")" && # guarantee a trailing / up_path=${up_path%/}/ && # path from submodule work tree to submodule origin repo @@ -1399,7 +1407,7 @@ then fi # "--cached" is accepted only by "status" and "summary" -if test -n "$cached" && test "$command" != status -a "$command" != summary +if test -n "$cached" && test "$command" != status && test "$command" != summary then usage fi @@ -20,6 +20,43 @@ const char git_more_info_string[] = static struct startup_info git_startup_info; static int use_pager = -1; +static char orig_cwd[PATH_MAX]; +static const char *env_names[] = { + GIT_DIR_ENVIRONMENT, + GIT_WORK_TREE_ENVIRONMENT, + GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, + GIT_PREFIX_ENVIRONMENT +}; +static char *orig_env[4]; +static int saved_environment; + +static void save_env(void) +{ + int i; + if (saved_environment) + return; + saved_environment = 1; + if (!getcwd(orig_cwd, sizeof(orig_cwd))) + die_errno("cannot getcwd"); + for (i = 0; i < ARRAY_SIZE(env_names); i++) { + orig_env[i] = getenv(env_names[i]); + if (orig_env[i]) + orig_env[i] = xstrdup(orig_env[i]); + } +} + +static void restore_env(void) +{ + int i; + if (*orig_cwd && chdir(orig_cwd)) + die_errno("could not move to %s", orig_cwd); + for (i = 0; i < ARRAY_SIZE(env_names); i++) { + if (orig_env[i]) + setenv(env_names[i], orig_env[i], 1); + else + unsetenv(env_names[i]); + } +} static void commit_pager_choice(void) { switch (use_pager) { @@ -54,8 +91,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) /* * Check remaining flags. */ - if (starts_with(cmd, "--exec-path")) { - cmd += 11; + if (skip_prefix(cmd, "--exec-path", &cmd)) { if (*cmd == '=') git_set_argv_exec_path(cmd + 1); else { @@ -92,8 +128,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) *envchanged = 1; (*argv)++; (*argc)--; - } else if (starts_with(cmd, "--git-dir=")) { - setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1); + } else if (skip_prefix(cmd, "--git-dir=", &cmd)) { + setenv(GIT_DIR_ENVIRONMENT, cmd, 1); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--namespace")) { @@ -106,8 +142,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) *envchanged = 1; (*argv)++; (*argc)--; - } else if (starts_with(cmd, "--namespace=")) { - setenv(GIT_NAMESPACE_ENVIRONMENT, cmd + 12, 1); + } else if (skip_prefix(cmd, "--namespace=", &cmd)) { + setenv(GIT_NAMESPACE_ENVIRONMENT, cmd, 1); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--work-tree")) { @@ -120,8 +156,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) *envchanged = 1; (*argv)++; (*argc)--; - } else if (starts_with(cmd, "--work-tree=")) { - setenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1); + } else if (skip_prefix(cmd, "--work-tree=", &cmd)) { + setenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--bare")) { @@ -272,6 +308,7 @@ static int handle_alias(int *argcp, const char ***argv) * RUN_SETUP for reading from the configuration file. */ #define NEED_WORK_TREE (1<<3) +#define NO_SETUP (1<<4) struct cmd_struct { const char *cmd; @@ -352,7 +389,7 @@ static struct cmd_struct commands[] = { { "cherry", cmd_cherry, RUN_SETUP }, { "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE }, { "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE }, - { "clone", cmd_clone }, + { "clone", cmd_clone, NO_SETUP }, { "column", cmd_column, RUN_SETUP_GENTLY }, { "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE }, { "commit-tree", cmd_commit_tree, RUN_SETUP }, @@ -378,8 +415,8 @@ static struct cmd_struct commands[] = { { "hash-object", cmd_hash_object }, { "help", cmd_help }, { "index-pack", cmd_index_pack, RUN_SETUP_GENTLY }, - { "init", cmd_init_db }, - { "init-db", cmd_init_db }, + { "init", cmd_init_db, NO_SETUP }, + { "init-db", cmd_init_db, NO_SETUP }, { "log", cmd_log, RUN_SETUP }, { "ls-files", cmd_ls_files, RUN_SETUP }, { "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY }, @@ -484,6 +521,10 @@ static void handle_builtin(int argc, const char **argv) struct cmd_struct *p = commands+i; if (strcmp(p->cmd, cmd)) continue; + if (saved_environment && (p->option & NO_SETUP)) { + restore_env(); + break; + } exit(run_builtin(p, argc, argv)); } } @@ -539,7 +580,10 @@ static int run_argv(int *argcp, const char ***argv) * of overriding "git log" with "git show" by having * alias.log = show */ - if (done_alias || !handle_alias(argcp, argv)) + if (done_alias) + break; + save_env(); + if (!handle_alias(argcp, argv)) break; done_alias = 1; } @@ -578,8 +622,7 @@ int main(int argc, char **av) * So we just directly call the builtin handler, and die if * that one cannot handle it. */ - if (starts_with(cmd, "git-")) { - cmd += 4; + if (skip_prefix(cmd, "git-", &cmd)) { argv[0] = cmd; handle_builtin(argc, argv); die("cannot handle %s as a builtin", cmd); @@ -590,8 +633,8 @@ int main(int argc, char **av) argc--; handle_options(&argv, &argc, NULL); if (argc > 0) { - if (starts_with(argv[0], "--")) - argv[0] += 2; + /* translate --help and --version into commands */ + skip_prefix(argv[0], "--", &argv[0]); } else { /* The user didn't specify a command; give them help */ commit_pager_choice(); diff --git a/gitk-git/gitk b/gitk-git/gitk index 90764e8948..c8df35dee5 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -2585,6 +2585,7 @@ proc makewindow {} { bind $fstring <Key-Return> {dofind 1 1} bind $sha1entry <Key-Return> {gotocommit; break} bind $sha1entry <<PasteSelection>> clearsha1 + bind $sha1entry <<Paste>> clearsha1 bind $cflist <1> {sel_flist %W %x %y; break} bind $cflist <B1-Motion> {sel_flist %W %x %y; break} bind $cflist <ButtonRelease-1> {treeclick %W %x %y} @@ -2786,7 +2787,7 @@ proc savestuff {w} { global mainheadcirclecolor workingfilescirclecolor indexcirclecolor global linkfgcolor circleoutlinecolor global autoselect autosellen extdifftool perfile_attrs markbgcolor use_ttk - global hideremotes want_ttk maxrefs + global hideremotes want_ttk maxrefs visiblerefs global config_file config_file_tmp if {$stuffsaved} return @@ -2812,6 +2813,7 @@ proc savestuff {w} { puts $f [list set autosellen $autosellen] puts $f [list set showneartags $showneartags] puts $f [list set maxrefs $maxrefs] + puts $f [list set visiblerefs $visiblerefs] puts $f [list set hideremotes $hideremotes] puts $f [list set showlocalchanges $showlocalchanges] puts $f [list set datetimeformat $datetimeformat] @@ -3492,10 +3494,20 @@ proc flist_hl {only} { } proc gitknewtmpdir {} { - global diffnum gitktmpdir gitdir + global diffnum gitktmpdir gitdir env if {![info exists gitktmpdir]} { - set gitktmpdir [file join $gitdir [format ".gitk-tmp.%s" [pid]]] + if {[info exists env(GITK_TMPDIR)]} { + set tmpdir $env(GITK_TMPDIR) + } elseif {[info exists env(TMPDIR)]} { + set tmpdir $env(TMPDIR) + } else { + set tmpdir $gitdir + } + set gitktmpformat [file join $tmpdir ".gitk-tmp.XXXXXX"] + if {[catch {set gitktmpdir [exec mktemp -d $gitktmpformat]}]} { + set gitktmpdir [file join $gitdir [format ".gitk-tmp.%s" [pid]]] + } if {[catch {file mkdir $gitktmpdir} err]} { error_popup "[mc "Error creating temporary directory %s:" $gitktmpdir] $err" unset gitktmpdir @@ -3870,7 +3882,7 @@ proc read_line_source {fd inst} { set id $nullid2 } if {[commitinview $id $curview]} { - selectline [rowofcommit $id] 1 [list $fname $lnum] + selectline [rowofcommit $id] 1 [list $fname $lnum] 1 } else { error_popup [mc "That line comes from commit %s, \ which is not in this view" [shortids $id]] @@ -5205,11 +5217,15 @@ proc dohidelocalchanges {} { # spawn off a process to do git diff-index --cached HEAD proc dodiffindex {} { global lserial showlocalchanges vfilelimit curview - global hasworktree + global hasworktree git_version if {!$showlocalchanges || !$hasworktree} return incr lserial - set cmd "|git diff-index --cached HEAD" + if {[package vcompare $git_version "1.7.2"] >= 0} { + set cmd "|git diff-index --cached --ignore-submodules=dirty HEAD" + } else { + set cmd "|git diff-index --cached HEAD" + } if {$vfilelimit($curview) ne {}} { set cmd [concat $cmd -- $vfilelimit($curview)] } @@ -7020,7 +7036,7 @@ proc viewnextline {dir} { # add a list of tag or branch names at position pos # returns the number of names inserted proc appendrefs {pos ids var} { - global ctext linknum curview $var maxrefs mainheadid + global ctext linknum curview $var maxrefs visiblerefs mainheadid if {[catch {$ctext index $pos}]} { return 0 @@ -7041,14 +7057,14 @@ proc appendrefs {pos ids var} { if {[llength $tags] > $maxrefs} { # If we are displaying heads, and there are too many, # see if there are some important heads to display. - # Currently this means "master" and the current head. + # Currently that are the current head and heads listed in $visiblerefs option set itags {} if {$var eq "idheads"} { set utags {} foreach ti $tags { set hname [lindex $ti 0] set id [lindex $ti 1] - if {($hname eq "master" || $id eq $mainheadid) && + if {([lsearch -exact $visiblerefs $hname] != -1 || $id eq $mainheadid) && [llength $itags] < $maxrefs} { lappend itags $ti } else { @@ -7161,7 +7177,7 @@ proc make_idmark {id} { $canv raise $t } -proc selectline {l isnew {desired_loc {}}} { +proc selectline {l isnew {desired_loc {}} {switch_to_patch 0}} { global canv ctext commitinfo selectedline global canvy0 linespc parents children curview global currentid sha1entry @@ -7187,6 +7203,10 @@ proc selectline {l isnew {desired_loc {}}} { setcanvscroll } + if {$cmitmode ne "patch" && $switch_to_patch} { + set cmitmode "patch" + } + set y [expr {$canvy0 + $l * $linespc}] set ymax [lindex [$canv cget -scrollregion] 3] set ytop [expr {$y - $linespc - 1}] @@ -7705,7 +7725,7 @@ proc addtocflist {ids} { } proc diffcmd {ids flags} { - global log_showroot nullid nullid2 + global log_showroot nullid nullid2 git_version set i [lsearch -exact $ids $nullid] set j [lsearch -exact $ids $nullid2] @@ -7726,6 +7746,9 @@ proc diffcmd {ids flags} { } } } elseif {$j >= 0} { + if {[package vcompare $git_version "1.7.2"] >= 0} { + set flags "$flags --ignore-submodules=dirty" + } set cmd [concat | git diff-index --cached $flags] if {[llength $ids] > 1} { # comparing index with specific revision @@ -11575,7 +11598,29 @@ proc prefsok {} { proc formatdate {d} { global datetimeformat if {$d ne {}} { - set d [clock format [lindex $d 0] -format $datetimeformat] + # If $datetimeformat includes a timezone, display in the + # timezone of the argument. Otherwise, display in local time. + if {[string match {*%[zZ]*} $datetimeformat]} { + if {[catch {set d [clock format [lindex $d 0] -timezone [lindex $d 1] -format $datetimeformat]}]} { + # Tcl < 8.5 does not support -timezone. Emulate it by + # setting TZ (e.g. TZ=<-0430>+04:30). + global env + if {[info exists env(TZ)]} { + set savedTZ $env(TZ) + } + set zone [lindex $d 1] + set sign [string map {+ - - +} [string index $zone 0]] + set env(TZ) <$zone>$sign[string range $zone 1 2]:[string range $zone 3 4] + set d [clock format [lindex $d 0] -format $datetimeformat] + if {[info exists savedTZ]} { + set env(TZ) $savedTZ + } else { + unset env(TZ) + } + } + } else { + set d [clock format [lindex $d 0] -format $datetimeformat] + } } return $d } @@ -12001,6 +12046,7 @@ set wrapcomment "none" set showneartags 1 set hideremotes 0 set maxrefs 20 +set visiblerefs {"master"} set maxlinelen 200 set showlocalchanges 1 set limitdiffs 1 diff --git a/gitk-git/po/vi.po b/gitk-git/po/vi.po new file mode 100644 index 0000000000..4dfe125a69 --- /dev/null +++ b/gitk-git/po/vi.po @@ -0,0 +1,1351 @@ +# Vietnamese translations for gitk package. +# Bản dịch tiếng Việt cho gói gitk. +# This file is distributed under the same license as the gitk package. +# Trần Ngọc Quân <vnwildman@gmail.com>, 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: gitk @@GIT_VERSION@@\n" +"Report-Msgid-Bugs-To: Paul Mackerras <paulus@samba.org>\n" +"POT-Creation-Date: 2013-12-14 09:24+0700\n" +"PO-Revision-Date: 2013-12-14 14:40+0700\n" +"Last-Translator: Trần Ngọc Quân <vnwildman@gmail.com>\n" +"Language-Team: Vietnamese <translation-team-vi@lists.sourceforge.net>\n" +"Language: vi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: gitk:140 +msgid "Couldn't get list of unmerged files:" +msgstr "Không thể lấy danh sách các tập-tin chưa được hòa trộn:" + +#: gitk:212 gitk:2353 +msgid "Color words" +msgstr "Tô màu chữ" + +#: gitk:217 gitk:2353 gitk:8103 gitk:8136 +msgid "Markup words" +msgstr "Đánh dấu chữ" + +#: gitk:322 +msgid "Error parsing revisions:" +msgstr "Gặp lỗi khi phân tích điểm xét duyệt:" + +#: gitk:378 +msgid "Error executing --argscmd command:" +msgstr "Gặp lỗi khi thực hiện lệnh --argscmd:" + +#: gitk:391 +msgid "No files selected: --merge specified but no files are unmerged." +msgstr "" +"Chưa chọn tập tin: --merge đã chỉ định nhưng không có tập tin chưa hòa trộn." + +#: gitk:394 +msgid "" +"No files selected: --merge specified but no unmerged files are within file " +"limit." +msgstr "" +"Chưa chọn tập tin: --merge đã chỉ định nhưng không có tập tin chưa hòa trộn " +"trong giới hạn tập tin." + +#: gitk:416 gitk:564 +msgid "Error executing git log:" +msgstr "Gặp lỗi khi thực hiện lệnh git log:" + +#: gitk:434 gitk:580 +msgid "Reading" +msgstr "Đang đọc" + +#: gitk:494 gitk:4429 +msgid "Reading commits..." +msgstr "Đang đọc các lần chuyển giao..." + +#: gitk:497 gitk:1635 gitk:4432 +msgid "No commits selected" +msgstr "Chưa chọn các lần chuyển giao" + +#: gitk:1509 +msgid "Can't parse git log output:" +msgstr "Không thể phân tích kết xuất từ lệnh git log:" + +#: gitk:1738 +msgid "No commit information available" +msgstr "Không có thông tin về lần chuyển giao nào" + +#: gitk:1895 +msgid "mc" +msgstr "mc" + +#: gitk:1930 gitk:4222 gitk:9552 gitk:11122 gitk:11401 +msgid "OK" +msgstr "Đồng ý" + +#: gitk:1932 gitk:4224 gitk:9079 gitk:9158 gitk:9274 gitk:9323 gitk:9554 +#: gitk:11123 gitk:11402 +msgid "Cancel" +msgstr "Thôi" + +#: gitk:2067 +msgid "Update" +msgstr "Cập nhật" + +#: gitk:2068 +msgid "Reload" +msgstr "Tải lại" + +#: gitk:2069 +msgid "Reread references" +msgstr "Đọc lại tham chiếu" + +#: gitk:2070 +msgid "List references" +msgstr "Liệt kê các tham chiếu" + +#: gitk:2072 +msgid "Start git gui" +msgstr "Khởi chạy git gui" + +#: gitk:2074 +msgid "Quit" +msgstr "Thoát" + +#: gitk:2066 +msgid "File" +msgstr "Chính" + +#: gitk:2078 +msgid "Preferences" +msgstr "Cá nhân hóa" + +#: gitk:2077 +msgid "Edit" +msgstr "Chỉnh sửa" + +#: gitk:2082 +msgid "New view..." +msgstr "Thêm trình bày mới..." + +#: gitk:2083 +msgid "Edit view..." +msgstr "Sửa cách trình bày..." + +#: gitk:2084 +msgid "Delete view" +msgstr "Xóa cách trình bày" + +#: gitk:2086 +msgid "All files" +msgstr "Mọi tập tin" + +#: gitk:2081 gitk:3975 +msgid "View" +msgstr "Trình bày" + +#: gitk:2091 gitk:2101 gitk:2945 +msgid "About gitk" +msgstr "Giới thiệu về gitk" + +#: gitk:2092 gitk:2106 +msgid "Key bindings" +msgstr "Tổ hợp phím" + +#: gitk:2090 gitk:2105 +msgid "Help" +msgstr "Trợ giúp" + +#: gitk:2183 gitk:8535 +msgid "SHA1 ID:" +msgstr "SHA1 ID:" + +#: gitk:2227 +msgid "Row" +msgstr "Hàng" + +#: gitk:2265 +msgid "Find" +msgstr "Tìm" + +#: gitk:2266 +msgid "next" +msgstr "tiếp" + +#: gitk:2267 +msgid "prev" +msgstr "trước" + +#: gitk:2268 +msgid "commit" +msgstr "lần chuyển giao" + +#: gitk:2271 gitk:2273 gitk:4590 gitk:4613 gitk:4637 gitk:6653 gitk:6725 +#: gitk:6810 +msgid "containing:" +msgstr "có chứa:" + +#: gitk:2274 gitk:3457 gitk:3462 gitk:4666 +msgid "touching paths:" +msgstr "đang chạm đường dẫn:" + +#: gitk:2275 gitk:4680 +msgid "adding/removing string:" +msgstr "thêm/gỡ bỏ chuỗi:" + +#: gitk:2276 gitk:4682 +msgid "changing lines matching:" +msgstr "những dòng thay đổi khớp mẫu:" + +#: gitk:2285 gitk:2287 gitk:4669 +msgid "Exact" +msgstr "Chính xác" + +#: gitk:2287 gitk:4757 gitk:6621 +msgid "IgnCase" +msgstr "BquaHt" + +#: gitk:2287 gitk:4639 gitk:4755 gitk:6617 +msgid "Regexp" +msgstr "BTCQ" + +#: gitk:2289 gitk:2290 gitk:4777 gitk:4807 gitk:4814 gitk:6746 gitk:6814 +msgid "All fields" +msgstr "Mọi trường" + +#: gitk:2290 gitk:4774 gitk:4807 gitk:6684 +msgid "Headline" +msgstr "Nội dung chính" + +#: gitk:2291 gitk:4774 gitk:6684 gitk:6814 gitk:7283 +msgid "Comments" +msgstr "Ghi chú" + +#: gitk:2291 gitk:4774 gitk:4779 gitk:4814 gitk:6684 gitk:7218 gitk:8713 +#: gitk:8728 +msgid "Author" +msgstr "Tác giả" + +#: gitk:2291 gitk:4774 gitk:6684 gitk:7220 +msgid "Committer" +msgstr "Người chuyển giao" + +#: gitk:2322 +msgid "Search" +msgstr "Tìm kiếm" + +#: gitk:2330 +msgid "Diff" +msgstr "So sánh" + +#: gitk:2332 +msgid "Old version" +msgstr "Phiên bản cũ" + +#: gitk:2334 +msgid "New version" +msgstr "Phiên bản mới" + +#: gitk:2336 +msgid "Lines of context" +msgstr "Các dòng của nội dung" + +#: gitk:2346 +msgid "Ignore space change" +msgstr "Không xét đến thay đổi do khoảng trắng" + +#: gitk:2350 gitk:2352 gitk:7842 gitk:8089 +msgid "Line diff" +msgstr "Khác biệt theo dòng" + +#: gitk:2417 +msgid "Patch" +msgstr "Vá" + +#: gitk:2419 +msgid "Tree" +msgstr "Cây" + +#: gitk:2577 gitk:2597 +msgid "Diff this -> selected" +msgstr "So sánh cái này -> cái đã chọn" + +#: gitk:2578 gitk:2598 +msgid "Diff selected -> this" +msgstr "So sánh cái đã chọn -> cái này" + +#: gitk:2579 gitk:2599 +msgid "Make patch" +msgstr "Tạo miếng vá" + +#: gitk:2580 gitk:9137 +msgid "Create tag" +msgstr "Tạo thẻ" + +#: gitk:2581 gitk:9254 +msgid "Write commit to file" +msgstr "Ghi lần chuyển giao ra tập tin" + +#: gitk:2582 gitk:9311 +msgid "Create new branch" +msgstr "Tạo nhánh mới" + +#: gitk:2583 +msgid "Cherry-pick this commit" +msgstr "Cherry-pick lần chuyển giao này" + +#: gitk:2584 +msgid "Reset HEAD branch to here" +msgstr "Đặt lại HEAD của nhánh vào đây" + +#: gitk:2585 +msgid "Mark this commit" +msgstr "Đánh dấu lần chuyển giao này" + +#: gitk:2586 +msgid "Return to mark" +msgstr "Quay lại vị trí dấu" + +#: gitk:2587 +msgid "Find descendant of this and mark" +msgstr "Tìm con cháu của cái này và cái đã đánh dấu" + +#: gitk:2588 +msgid "Compare with marked commit" +msgstr "So sánh với lần chuyển giao đã đánh dấu" + +#: gitk:2589 gitk:2600 +msgid "Diff this -> marked commit" +msgstr "So sánh cái này -> lần chuyển giao đã đánh dấu" + +#: gitk:2590 gitk:2601 +msgid "Diff marked commit -> this" +msgstr "So sánh lần chuyển giao đã đánh dấu -> cái này" + +#: gitk:2591 +msgid "Revert this commit" +msgstr "Hoàn lại lần chuyển giao này" + +#: gitk:2607 +msgid "Check out this branch" +msgstr "Checkout nhánh này" + +#: gitk:2608 +msgid "Remove this branch" +msgstr "Gỡ bỏ nhánh này" + +#: gitk:2615 +msgid "Highlight this too" +msgstr "Cũng tô sáng nó" + +#: gitk:2616 +msgid "Highlight this only" +msgstr "Chỉ tô sáng cái này" + +#: gitk:2617 +msgid "External diff" +msgstr "diff từ bên ngoài" + +#: gitk:2618 +msgid "Blame parent commit" +msgstr "Xem công trạng lần chuyển giao cha mẹ" + +#: gitk:2625 +msgid "Show origin of this line" +msgstr "Hiển thị nguyên gốc của dòng này" + +#: gitk:2626 +msgid "Run git gui blame on this line" +msgstr "Chạy lệnh git gui blame cho dòng này" + +#: gitk:2947 +msgid "" +"\n" +"Gitk - a commit viewer for git\n" +"\n" +"Copyright © 2005-2011 Paul Mackerras\n" +"\n" +"Use and redistribute under the terms of the GNU General Public License" +msgstr "" +"\n" +"Gitk - phần mềm xem các lần chuyển giao dành cho git\n" +"\n" +"Bản quyền © 2005-2011 Paul Mackerras\n" +"\n" +"Dùng và phân phối lại phần mềm này theo các điều khoản của Giấy Phép Công GNU" + +#: gitk:2955 gitk:3020 gitk:9738 +msgid "Close" +msgstr "Đóng" + +#: gitk:2976 +msgid "Gitk key bindings" +msgstr "Tổ hợp phím gitk" + +#: gitk:2979 +msgid "Gitk key bindings:" +msgstr "Tổ hợp phím gitk:" + +#: gitk:2981 +#, tcl-format +msgid "<%s-Q>\t\tQuit" +msgstr "<%s-Q>\t\tThoát" + +#: gitk:2982 +#, tcl-format +msgid "<%s-W>\t\tClose window" +msgstr "<%s-W>\t\tĐóng cửa sổ" + +#: gitk:2983 +msgid "<Home>\t\tMove to first commit" +msgstr "<Home>\t\tChuyển đến lần chuyển giao đầu tiên" + +#: gitk:2984 +msgid "<End>\t\tMove to last commit" +msgstr "<End>\t\tChuyển đến lần chuyển giao cuối" + +#: gitk:2985 +msgid "<Up>, p, k\tMove up one commit" +msgstr "<Up>, p, k\tDi chuyển lên một lần chuyển giao" + +#: gitk:2986 +msgid "<Down>, n, j\tMove down one commit" +msgstr "<Down>, n, j\tDi chuyển xuống một lần chuyển giao" + +#: gitk:2987 +msgid "<Left>, z, h\tGo back in history list" +msgstr "<Left>, z, h\tQuay trở lại danh sách lịch sử" + +#: gitk:2988 +msgid "<Right>, x, l\tGo forward in history list" +msgstr "<Right>, x, l\tDi chuyển tiếp trong danh sách lịch sử" + +#: gitk:2989 +msgid "<PageUp>\tMove up one page in commit list" +msgstr "<PageUp>\tDi chuyển lên một trang trong danh sách lần chuyển giao" + +#: gitk:2990 +msgid "<PageDown>\tMove down one page in commit list" +msgstr "<PageDown>\tDi chuyển xuống một trang trong danh sách lần chuyển giao" + +#: gitk:2991 +#, tcl-format +msgid "<%s-Home>\tScroll to top of commit list" +msgstr "<%s-Home>\tCuộn lên trên cùng của danh sách lần chuyển giao" + +#: gitk:2992 +#, tcl-format +msgid "<%s-End>\tScroll to bottom of commit list" +msgstr "<%s-End>\tCuộn xuống dưới cùng của danh sách lần chuyển giao" + +#: gitk:2993 +#, tcl-format +msgid "<%s-Up>\tScroll commit list up one line" +msgstr "<%s-Up>\tCuộn danh sách lần chuyển giao lên một dòng" + +#: gitk:2994 +#, tcl-format +msgid "<%s-Down>\tScroll commit list down one line" +msgstr "<%s-Down>\tCuộn danh sách lần chuyển giao xuống một dòng" + +#: gitk:2995 +#, tcl-format +msgid "<%s-PageUp>\tScroll commit list up one page" +msgstr "<%s-PageUp>\tCuộn danh sách lần chuyển giao lên một trang" + +#: gitk:2996 +#, tcl-format +msgid "<%s-PageDown>\tScroll commit list down one page" +msgstr "<%s-PageDown>\tCuộn danh sách lần chuyển giao xuống một trang" + +#: gitk:2997 +msgid "<Shift-Up>\tFind backwards (upwards, later commits)" +msgstr "<Shift-Up>\tTìm về phía sau (hướng lên trên, lần chuyển giao sau này)" + +#: gitk:2998 +msgid "<Shift-Down>\tFind forwards (downwards, earlier commits)" +msgstr "" +"<Shift-Down>\tTìm về phía trước (hướng xuống dưới, lần chuyển giao trước đây)" + +#: gitk:2999 +msgid "<Delete>, b\tScroll diff view up one page" +msgstr "<Delete>, b\tCuộn phần trình bày diff lên một trang" + +#: gitk:3000 +msgid "<Backspace>\tScroll diff view up one page" +msgstr "<Backspace>\tCuộn phần trình bày diff lên một trang" + +#: gitk:3001 +msgid "<Space>\t\tScroll diff view down one page" +msgstr "<Space>\t\tCuộn phần trình bày diff xuống một trang" + +#: gitk:3002 +msgid "u\t\tScroll diff view up 18 lines" +msgstr "u\t\tCuộn phần trình bày diff lên 18 dòng" + +#: gitk:3003 +msgid "d\t\tScroll diff view down 18 lines" +msgstr "d\t\tCuộn phần trình bày diff xuống 18 dòng" + +#: gitk:3004 +#, tcl-format +msgid "<%s-F>\t\tFind" +msgstr "<%s-F>\t\tTìm kiếm" + +#: gitk:3005 +#, tcl-format +msgid "<%s-G>\t\tMove to next find hit" +msgstr "<%s-G>\t\tDi chuyển đến chỗ gặp kế tiếp" + +#: gitk:3006 +msgid "<Return>\tMove to next find hit" +msgstr "<Return>\t\tDi chuyển đến chỗ gặp kế tiếp" + +#: gitk:3007 +msgid "/\t\tFocus the search box" +msgstr "/\t\tĐưa con trỏ chuột vào ô tìm kiếm" + +#: gitk:3008 +msgid "?\t\tMove to previous find hit" +msgstr "?\t\tDi chuyển đến chỗ gặp kế trước" + +#: gitk:3009 +msgid "f\t\tScroll diff view to next file" +msgstr "f\t\tCuộn phần trình bày diff sang tập-tin kế" + +#: gitk:3010 +#, tcl-format +msgid "<%s-S>\t\tSearch for next hit in diff view" +msgstr "<%s-S>\t\tTìm đến chỗ khác biệt kế tiếp" + +#: gitk:3011 +#, tcl-format +msgid "<%s-R>\t\tSearch for previous hit in diff view" +msgstr "<%s-R>\t\tTìm đến chỗ khác biệt kế trước" + +#: gitk:3012 +#, tcl-format +msgid "<%s-KP+>\tIncrease font size" +msgstr "<%s-KP+>\tTăng cỡ chữ" + +#: gitk:3013 +#, tcl-format +msgid "<%s-plus>\tIncrease font size" +msgstr "<%s-plus>\tTăng cỡ chữ" + +#: gitk:3014 +#, tcl-format +msgid "<%s-KP->\tDecrease font size" +msgstr "<%s-KP->\tGiảm cỡ chữ" + +#: gitk:3015 +#, tcl-format +msgid "<%s-minus>\tDecrease font size" +msgstr "<%s-minus>\tGiảm cỡ chữ" + +#: gitk:3016 +msgid "<F5>\t\tUpdate" +msgstr "<F5>\t\tCập nhật" + +#: gitk:3471 gitk:3480 +#, tcl-format +msgid "Error creating temporary directory %s:" +msgstr "Gặp lỗi khi tạo thư mục tạm %s:" + +#: gitk:3493 +#, tcl-format +msgid "Error getting \"%s\" from %s:" +msgstr "Lỗi chào hỏi \"%s\" từ %s:" + +#: gitk:3556 +msgid "command failed:" +msgstr "lệnh gặp lỗi:" + +#: gitk:3705 +msgid "No such commit" +msgstr "Không có lần chuyển giao như vậy" + +#: gitk:3719 +msgid "git gui blame: command failed:" +msgstr "git gui blame: lệnh gặp lỗi:" + +#: gitk:3750 +#, tcl-format +msgid "Couldn't read merge head: %s" +msgstr "Không thể độc đầu của hòa trộn: %s" + +# tcl-format +#: gitk:3758 +#, tcl-format +msgid "Error reading index: %s" +msgstr "Gặp lỗi khi đọc chỉ mục: %s" + +#: gitk:3783 +#, tcl-format +msgid "Couldn't start git blame: %s" +msgstr "Không thể khởi chạy git blame: %s" + +#: gitk:3786 gitk:6652 +msgid "Searching" +msgstr "Đang tìm kiếm" + +#: gitk:3818 +#, tcl-format +msgid "Error running git blame: %s" +msgstr "Gặp lỗi khi chạy git blame: %s" + +#: gitk:3846 +#, tcl-format +msgid "That line comes from commit %s, which is not in this view" +msgstr "Dòng đến từ lần chuyển giao %s, cái mà không trong trình bày này" + +#: gitk:3860 +msgid "External diff viewer failed:" +msgstr "Bộ trình bày diff từ bên ngoài gặp lỗi:" + +#: gitk:3978 +msgid "Gitk view definition" +msgstr "Định nghĩa cách trình bày gitk" + +#: gitk:3982 +msgid "Remember this view" +msgstr "Nhớ cách trình bày này" + +#: gitk:3983 +msgid "References (space separated list):" +msgstr "Tham chiếu (danh sách ngăn cách bằng dấu cách):" + +#: gitk:3984 +msgid "Branches & tags:" +msgstr "Nhánh & thẻ:" + +#: gitk:3985 +msgid "All refs" +msgstr "Mọi tham chiếu" + +#: gitk:3986 +msgid "All (local) branches" +msgstr "Mọi nhánh (nội bộ)" + +#: gitk:3987 +msgid "All tags" +msgstr "Mọi thẻ" + +#: gitk:3988 +msgid "All remote-tracking branches" +msgstr "Mọi nhánh remote-tracking" + +#: gitk:3989 +msgid "Commit Info (regular expressions):" +msgstr "Thông tin chuyển giao (biểu thức chính quy):" + +#: gitk:3990 +msgid "Author:" +msgstr "Tác giả:" + +#: gitk:3991 +msgid "Committer:" +msgstr "Người chuyển giao:" + +#: gitk:3992 +msgid "Commit Message:" +msgstr "Chú thích của lần chuyển giao:" + +#: gitk:3993 +msgid "Matches all Commit Info criteria" +msgstr "Khớp mọi điều kiện Thông tin Chuyển giao" + +#: gitk:3994 +msgid "Changes to Files:" +msgstr "Đổi thành Tập tin:" + +#: gitk:3995 +msgid "Fixed String" +msgstr "Chuỗi cố định" + +#: gitk:3996 +msgid "Regular Expression" +msgstr "Biểu thức chính quy" + +#: gitk:3997 +msgid "Search string:" +msgstr "Chuỗi tìm kiếm:" + +#: gitk:3998 +msgid "" +"Commit Dates (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 " +"15:27:38\"):" +msgstr "" +"Ngày chuyển giao (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 " +"15:27:38\"):" + +#: gitk:3999 +msgid "Since:" +msgstr "Kể từ:" + +#: gitk:4000 +msgid "Until:" +msgstr "Đến:" + +#: gitk:4001 +msgid "Limit and/or skip a number of revisions (positive integer):" +msgstr "Giới hạn và/hoặc bỏ số của điểm xét (số nguyên âm):" + +#: gitk:4002 +msgid "Number to show:" +msgstr "Số lượng hiển thị:" + +#: gitk:4003 +msgid "Number to skip:" +msgstr "Số lượng sẽ bỏ qua:" + +#: gitk:4004 +msgid "Miscellaneous options:" +msgstr "Tuỳ chọn hỗn hợp:" + +#: gitk:4005 +msgid "Strictly sort by date" +msgstr "Sắp xếp chặt chẽ theo ngày" + +#: gitk:4006 +msgid "Mark branch sides" +msgstr "Đánh dấu các cạnh nhánh" + +#: gitk:4007 +msgid "Limit to first parent" +msgstr "Giới hạn thành cha mẹ đầu tiên" + +#: gitk:4008 +msgid "Simple history" +msgstr "Lịch sử dạng đơn giản" + +#: gitk:4009 +msgid "Additional arguments to git log:" +msgstr "Đối số bổ xung cho lệnh git log:" + +#: gitk:4010 +msgid "Enter files and directories to include, one per line:" +msgstr "Nhập vào các tập tin và thư mục bao gồm, mỗi dòng một cái:" + +#: gitk:4011 +msgid "Command to generate more commits to include:" +msgstr "Lệnh tạo ra nhiều lần chuyển giao hơn bao gồm:" + +#: gitk:4135 +msgid "Gitk: edit view" +msgstr "Gitk: sửa cách trình bày" + +#: gitk:4143 +msgid "-- criteria for selecting revisions" +msgstr "-- tiêu chuẩn chọn điểm xét duyệt" + +#: gitk:4148 +msgid "View Name" +msgstr "Tên cách trình bày" + +#: gitk:4223 +msgid "Apply (F5)" +msgstr "Áp dụng (F5)" + +#: gitk:4261 +msgid "Error in commit selection arguments:" +msgstr "Lỗi trong các đối số chọn chuyển giao:" + +#: gitk:4314 gitk:4366 gitk:4827 gitk:4841 gitk:6107 gitk:12184 gitk:12185 +msgid "None" +msgstr "Không" + +#: gitk:4924 gitk:4929 +msgid "Descendant" +msgstr "Con cháu" + +#: gitk:4925 +msgid "Not descendant" +msgstr "Không có con cháu" + +#: gitk:4932 gitk:4937 +msgid "Ancestor" +msgstr "Tổ tiên chung" + +#: gitk:4933 +msgid "Not ancestor" +msgstr "Không có chung tổ tiên" + +#: gitk:5223 +msgid "Local changes checked in to index but not committed" +msgstr "" +"Có thay đổi nội bộ đã được đưa vào bảng mục lục, nhưng chưa được chuyển giao" + +#: gitk:5259 +msgid "Local uncommitted changes, not checked in to index" +msgstr "Có thay đổi nội bộ, nhưng chưa được đưa vào bảng mục lục" + +#: gitk:7032 +msgid "and many more" +msgstr "và nhiều nữa" + +#: gitk:7035 +msgid "many" +msgstr "nhiều" + +#: gitk:7222 +msgid "Tags:" +msgstr "Thẻ:" + +#: gitk:7239 gitk:7245 gitk:8708 +msgid "Parent" +msgstr "Cha" + +#: gitk:7250 +msgid "Child" +msgstr "Con" + +#: gitk:7259 +msgid "Branch" +msgstr "Nhánh" + +#: gitk:7262 +msgid "Follows" +msgstr "Đứng sau" + +#: gitk:7265 +msgid "Precedes" +msgstr "Đứng trước" + +# tcl-format +#: gitk:7849 +#, tcl-format +msgid "Error getting diffs: %s" +msgstr "Lỗi lấy diff: %s" + +#: gitk:8533 +msgid "Goto:" +msgstr "Nhảy tới:" + +#: gitk:8554 +#, tcl-format +msgid "Short SHA1 id %s is ambiguous" +msgstr "Định danh SHA1 dạng ngắn %s là chưa đủ rõ ràng" + +#: gitk:8561 +#, tcl-format +msgid "Revision %s is not known" +msgstr "Không hiểu điểm xét duyệt %s" + +#: gitk:8571 +#, tcl-format +msgid "SHA1 id %s is not known" +msgstr "Không hiểu định danh SHA1 %s" + +#: gitk:8573 +#, tcl-format +msgid "Revision %s is not in the current view" +msgstr "Điểm %s không ở trong phần hiển thị hiện tại" + +#: gitk:8715 gitk:8730 +msgid "Date" +msgstr "Ngày" + +#: gitk:8718 +msgid "Children" +msgstr "Con cháu" + +#: gitk:8781 +#, tcl-format +msgid "Reset %s branch to here" +msgstr "Đặt lại nhánh %s tại đây" + +#: gitk:8783 +msgid "Detached head: can't reset" +msgstr "Head đã bị tách rời: không thể đặt lại" + +#: gitk:8888 gitk:8894 +msgid "Skipping merge commit " +msgstr "Bỏ qua lần chuyển giao hòa trộn " + +#: gitk:8903 gitk:8908 +msgid "Error getting patch ID for " +msgstr "Gặp lỗi khi lấy ID miếng vá cho " + +#: gitk:8904 gitk:8909 +msgid " - stopping\n" +msgstr " - dừng\n" + +#: gitk:8914 gitk:8917 gitk:8925 gitk:8939 gitk:8948 +msgid "Commit " +msgstr "Commit " + +#: gitk:8918 +msgid "" +" is the same patch as\n" +" " +msgstr "" +" là cùng một miếng vá với\n" +" " + +#: gitk:8926 +msgid "" +" differs from\n" +" " +msgstr "" +" khác biệt từ\n" +" " + +#: gitk:8928 +msgid "" +"Diff of commits:\n" +"\n" +msgstr "" +"Khác biệt của lần chuyển giao (commit):\n" +"\n" + +#: gitk:8940 gitk:8949 +#, tcl-format +msgid " has %s children - stopping\n" +msgstr " có %s con - dừng\n" + +#: gitk:8968 +#, tcl-format +msgid "Error writing commit to file: %s" +msgstr "Gặp lỗi trong quá trình ghi lần chuyển giao vào tập tin: %s" + +#: gitk:8974 +#, tcl-format +msgid "Error diffing commits: %s" +msgstr "Gặp lỗi khi so sánh sự khác biệt giữa các lần chuyển giao: %s" + +#: gitk:9020 +msgid "Top" +msgstr "Đỉnh" + +#: gitk:9021 +msgid "From" +msgstr "Từ" + +#: gitk:9026 +msgid "To" +msgstr "Đến" + +#: gitk:9050 +msgid "Generate patch" +msgstr "Tạo miếng vá" + +#: gitk:9052 +msgid "From:" +msgstr "Từ:" + +#: gitk:9061 +msgid "To:" +msgstr "Đến:" + +#: gitk:9070 +msgid "Reverse" +msgstr "Đảo ngược" + +#: gitk:9072 gitk:9268 +msgid "Output file:" +msgstr "Tập tin kết xuất:" + +#: gitk:9078 +msgid "Generate" +msgstr "Tạo" + +#: gitk:9116 +msgid "Error creating patch:" +msgstr "Gặp lỗi khi tạo miếng vá:" + +#: gitk:9139 gitk:9256 gitk:9313 +msgid "ID:" +msgstr "ID:" + +#: gitk:9148 +msgid "Tag name:" +msgstr "Tên thẻ:" + +#: gitk:9151 +msgid "Tag message is optional" +msgstr "Ghi chú thẻ chỉ là tùy chọn" + +#: gitk:9153 +msgid "Tag message:" +msgstr "Ghi chú cho thẻ:" + +#: gitk:9157 gitk:9322 +msgid "Create" +msgstr "Tạo" + +#: gitk:9175 +msgid "No tag name specified" +msgstr "Chưa chỉ ra tên của thẻ" + +#: gitk:9179 +#, tcl-format +msgid "Tag \"%s\" already exists" +msgstr "Thẻ “%s” đã có sẵn rồi" + +#: gitk:9189 +msgid "Error creating tag:" +msgstr "Gặp lỗi khi tạo thẻ:" + +#: gitk:9265 +msgid "Command:" +msgstr "Lệnh:" + +#: gitk:9273 +msgid "Write" +msgstr "Ghi" + +#: gitk:9291 +msgid "Error writing commit:" +msgstr "Gặp lỗi trong quá trình ghi chuyển giao:" + +#: gitk:9318 +msgid "Name:" +msgstr "Tên:" + +#: gitk:9341 +msgid "Please specify a name for the new branch" +msgstr "Vui lòng chỉ định tên cho nhánh mới" + +#: gitk:9346 +#, tcl-format +msgid "Branch '%s' already exists. Overwrite?" +msgstr "Nhánh “%s” đã có từ trước rồi. Ghi đè?" + +#: gitk:9413 +#, tcl-format +msgid "Commit %s is already included in branch %s -- really re-apply it?" +msgstr "" +"Lần chuyển giao %s đã sẵn được bao gồm trong nhánh %s -- bạn có thực sự muốn " +"áp dụng lại nó không?" + +#: gitk:9418 +msgid "Cherry-picking" +msgstr "Đang cherry-pick" + +#: gitk:9427 +#, tcl-format +msgid "" +"Cherry-pick failed because of local changes to file '%s'.\n" +"Please commit, reset or stash your changes and try again." +msgstr "" +"Cherry-pick gặp lỗi bởi vì các thay đổi nội bộ tập tin “%s”.\n" +"Xin hãy chuyển giao, reset hay stash các thay đổi của bạn sau đó thử lại." + +#: gitk:9433 +msgid "" +"Cherry-pick failed because of merge conflict.\n" +"Do you wish to run git citool to resolve it?" +msgstr "" +"Cherry-pick gặp lỗi bởi vì xung đột trong hòa trộn.\n" +"Bạn có muốn chạy lệnh “git citool” để giải quyết vấn đề này không?" + +#: gitk:9449 gitk:9507 +msgid "No changes committed" +msgstr "Không có thay đổi nào cần chuyển giao" + +#: gitk:9476 +#, tcl-format +msgid "Commit %s is not included in branch %s -- really revert it?" +msgstr "" +"Lần chuyển giao %s không được bao gồm trong nhánh %s -- bạn có thực sự muốn " +"“revert” nó không?" + +#: gitk:9481 +msgid "Reverting" +msgstr "Đang hoàn tác" + +#: gitk:9489 +#, tcl-format +msgid "" +"Revert failed because of local changes to the following files:%s Please " +"commit, reset or stash your changes and try again." +msgstr "" +"Revert gặp lỗi bởi vì tập tin sau đã được thay đổi nội bộ:%s\n" +"Xin hãy chạy lệnh “commit”, “reset” hoặc “stash” rồi thử lại." + +#: gitk:9493 +msgid "" +"Revert failed because of merge conflict.\n" +" Do you wish to run git citool to resolve it?" +msgstr "" +"Revert gặp lỗi bởi vì xung đột hòa trộn.\n" +" Bạn có muốn chạy lệnh “git citool” để phân giải nó không?" + +#: gitk:9536 +msgid "Confirm reset" +msgstr "Xác nhật đặt lại" + +#: gitk:9538 +#, tcl-format +msgid "Reset branch %s to %s?" +msgstr "Đặt lại nhánh “%s” thành “%s”?" + +#: gitk:9540 +msgid "Reset type:" +msgstr "Kiểu đặt lại:" + +#: gitk:9543 +msgid "Soft: Leave working tree and index untouched" +msgstr "Mềm: Không động đến thư mục làm việc và bảng mục lục" + +#: gitk:9546 +msgid "Mixed: Leave working tree untouched, reset index" +msgstr "" +"Pha trộn: Không động chạm đến thư mục làm việc nhưng đặt lại bảng mục lục" + +#: gitk:9549 +msgid "" +"Hard: Reset working tree and index\n" +"(discard ALL local changes)" +msgstr "" +"Hard: Đặt lại cây làm việc và mục lục\n" +"(hủy bỏ MỌI thay đổi nội bộ)" + +#: gitk:9566 +msgid "Resetting" +msgstr "Đang đặt lại" + +#: gitk:9626 +msgid "Checking out" +msgstr "Đang checkout" + +#: gitk:9679 +msgid "Cannot delete the currently checked-out branch" +msgstr "Không thể xóa nhánh hiện tại đang được lấy ra" + +#: gitk:9685 +#, tcl-format +msgid "" +"The commits on branch %s aren't on any other branch.\n" +"Really delete branch %s?" +msgstr "" +"Các lần chuyển giao trên nhánh %s không ở trên nhánh khác.\n" +"Thực sự muốn xóa nhánh %s?" + +#: gitk:9716 +#, tcl-format +msgid "Tags and heads: %s" +msgstr "Thẻ và Đầu: %s" + +#: gitk:9731 +msgid "Filter" +msgstr "Bộ lọc" + +#: gitk:10027 +msgid "" +"Error reading commit topology information; branch and preceding/following " +"tag information will be incomplete." +msgstr "" +"Gặp lỗi khi đọc thông tin hình học lần chuyển giao; thông tin nhánh và thẻ " +"trước/sau sẽ không hoàn thiện." + +#: gitk:11004 +msgid "Tag" +msgstr "Thẻ" + +#: gitk:11008 +msgid "Id" +msgstr "Id" + +#: gitk:11091 +msgid "Gitk font chooser" +msgstr "Hộp thoại chọn phông Gitk" + +#: gitk:11108 +msgid "B" +msgstr "B" + +#: gitk:11111 +msgid "I" +msgstr "I" + +#: gitk:11229 +msgid "Commit list display options" +msgstr "Các tùy chọn về hiển thị danh sách lần chuyển giao" + +#: gitk:11232 +msgid "Maximum graph width (lines)" +msgstr "Độ rộng biểu đồ tối đa (dòng)" + +#: gitk:11235 +#, tcl-format +msgid "Maximum graph width (% of pane)" +msgstr "Độ rộng biểu đồ tối đa (% của bảng)" + +#: gitk:11238 +msgid "Show local changes" +msgstr "Hiển thị các thay đổi nội bộ" + +#: gitk:11241 +msgid "Auto-select SHA1 (length)" +msgstr "Tự chọn SHA1 (độ dài)" + +#: gitk:11245 +msgid "Hide remote refs" +msgstr "Ẩn tham chiếu đến máy chủ" + +#: gitk:11249 +msgid "Diff display options" +msgstr "Các tùy chọn trình bày các khác biệt" + +#: gitk:11251 +msgid "Tab spacing" +msgstr "Khoảng cách tab" + +#: gitk:11254 +msgid "Display nearby tags/heads" +msgstr "Hiển thị các thẻ/đầu xung quanh" + +#: gitk:11257 +msgid "Maximum # tags/heads to show" +msgstr "Số lượng thẻ/đầu tối đa sẽ hiển thị" + +#: gitk:11260 +msgid "Limit diffs to listed paths" +msgstr "Giới hạn các khác biệt cho đường dẫn đã liệt kê" + +#: gitk:11263 +msgid "Support per-file encodings" +msgstr "Hỗ trợ mã hóa mỗi-dòng" + +#: gitk:11269 gitk:11416 +msgid "External diff tool" +msgstr "Công cụ so sánh từ bên ngoài" + +#: gitk:11270 +msgid "Choose..." +msgstr "Chọn..." + +#: gitk:11275 +msgid "General options" +msgstr "Các tùy chọn chung" + +#: gitk:11278 +msgid "Use themed widgets" +msgstr "Dùng các widget chủ đề" + +#: gitk:11280 +msgid "(change requires restart)" +msgstr "(để thay đổi cần khởi động lại)" + +#: gitk:11282 +msgid "(currently unavailable)" +msgstr "(hiện tại không sẵn sàng)" + +#: gitk:11293 +msgid "Colors: press to choose" +msgstr "Màu sắc: bấm vào nút phía dưới để chọn màu" + +#: gitk:11296 +msgid "Interface" +msgstr "Giao diện" + +#: gitk:11297 +msgid "interface" +msgstr "giao diện" + +#: gitk:11300 +msgid "Background" +msgstr "Nền" + +#: gitk:11301 gitk:11331 +msgid "background" +msgstr "nền" + +#: gitk:11304 +msgid "Foreground" +msgstr "Tiền cảnh" + +#: gitk:11305 +msgid "foreground" +msgstr "tiền cảnh" + +#: gitk:11308 +msgid "Diff: old lines" +msgstr "So sánh: dòng cũ" + +#: gitk:11309 +msgid "diff old lines" +msgstr "diff dòng cũ" + +#: gitk:11313 +msgid "Diff: new lines" +msgstr "So sánh: dòng mới" + +#: gitk:11314 +msgid "diff new lines" +msgstr "màu dòng mới" + +#: gitk:11318 +msgid "Diff: hunk header" +msgstr "So sánh: phần đầu của đoạn" + +#: gitk:11320 +msgid "diff hunk header" +msgstr "màu của phần đầu của đoạn khi so sánh" + +#: gitk:11324 +msgid "Marked line bg" +msgstr "Nền dòng đánh dấu" + +#: gitk:11326 +msgid "marked line background" +msgstr "nền dòng được đánh dấu" + +#: gitk:11330 +msgid "Select bg" +msgstr "Màu nền" + +#: gitk:11339 +msgid "Fonts: press to choose" +msgstr "Phông chữ: bấm vào các nút ở dưới để chọn" + +#: gitk:11341 +msgid "Main font" +msgstr "Phông chữ chính" + +#: gitk:11342 +msgid "Diff display font" +msgstr "Phông chữ dùng khi so sánh" + +#: gitk:11343 +msgid "User interface font" +msgstr "Phông chữ giao diện" + +#: gitk:11365 +msgid "Gitk preferences" +msgstr "Cá nhân hóa các cài đặt cho Gitk" + +#: gitk:11374 +msgid "General" +msgstr "Chung" + +#: gitk:11375 +msgid "Colors" +msgstr "Màu sắc" + +#: gitk:11376 +msgid "Fonts" +msgstr "Phông chữ" + +#: gitk:11426 +#, tcl-format +msgid "Gitk: choose color for %s" +msgstr "Gitk: chọn màu cho %s" + +#: gitk:12080 +msgid "Cannot find a git repository here." +msgstr "Không thể tìm thấy kho git ở đây." + +#: gitk:12127 +#, tcl-format +msgid "Ambiguous argument '%s': both revision and filename" +msgstr "Đối số “%s” chưa rõ ràng: vừa là điểm xét duyệt vừa là tên tập tin" + +#: gitk:12139 +msgid "Bad arguments to gitk:" +msgstr "Đối số không hợp lệ cho gitk:" + +#: gitk:12242 +msgid "Command line" +msgstr "Dòng lệnh" @@ -129,7 +129,6 @@ static void list_commands_in_dir(struct cmdnames *cmds, const char *path, const char *prefix) { - int prefix_len; DIR *dir = opendir(path); struct dirent *de; struct strbuf buf = STRBUF_INIT; @@ -139,15 +138,15 @@ static void list_commands_in_dir(struct cmdnames *cmds, return; if (!prefix) prefix = "git-"; - prefix_len = strlen(prefix); strbuf_addf(&buf, "%s/", path); len = buf.len; while ((de = readdir(dir)) != NULL) { + const char *ent; int entlen; - if (!starts_with(de->d_name, prefix)) + if (!skip_prefix(de->d_name, prefix, &ent)) continue; strbuf_setlen(&buf, len); @@ -155,11 +154,11 @@ static void list_commands_in_dir(struct cmdnames *cmds, if (!is_executable(buf.buf)) continue; - entlen = strlen(de->d_name) - prefix_len; - if (has_extension(de->d_name, ".exe")) + entlen = strlen(ent); + if (has_extension(ent, ".exe")) entlen -= 4; - add_cmdname(cmds, de->d_name + prefix_len, entlen); + add_cmdname(cmds, ent, entlen); } closedir(dir); strbuf_release(&buf); @@ -251,11 +250,13 @@ static struct cmdnames aliases; static int git_unknown_cmd_config(const char *var, const char *value, void *cb) { + const char *p; + if (!strcmp(var, "help.autocorrect")) autocorrect = git_config_int(var,value); /* Also use aliases for command lookup */ - if (starts_with(var, "alias.")) - add_cmdname(&aliases, var + 6, strlen(var + 6)); + if (skip_prefix(var, "alias.", &p)) + add_cmdname(&aliases, p, strlen(p)); return git_default_config(var, value, cb); } @@ -412,11 +413,12 @@ static int append_similar_ref(const char *refname, const unsigned char *sha1, { struct similar_ref_cb *cb = (struct similar_ref_cb *)(cb_data); char *branch = strrchr(refname, '/') + 1; + const char *remote; + /* A remote branch of the same name is deemed similar */ - if (starts_with(refname, "refs/remotes/") && + if (skip_prefix(refname, "refs/remotes/", &remote) && !strcmp(branch, cb->base_ref)) - string_list_append(cb->similar_refs, - refname + strlen("refs/remotes/")); + string_list_append(cb->similar_refs, remote); return 0; } diff --git a/http-backend.c b/http-backend.c index d2c0a625ce..57290d9bda 100644 --- a/http-backend.c +++ b/http-backend.c @@ -221,17 +221,19 @@ static void get_idx_file(char *name) static int http_config(const char *var, const char *value, void *cb) { + const char *p; + if (!strcmp(var, "http.getanyfile")) { getanyfile = git_config_bool(var, value); return 0; } - if (starts_with(var, "http.")) { + if (skip_prefix(var, "http.", &p)) { int i; for (i = 0; i < ARRAY_SIZE(rpc_service); i++) { struct rpc_service *svc = &rpc_service[i]; - if (!strcmp(var + 5, svc->config_name)) { + if (!strcmp(p, svc->config_name)) { svc->enabled = git_config_bool(var, value); return 0; } @@ -244,15 +246,16 @@ static int http_config(const char *var, const char *value, void *cb) static struct rpc_service *select_service(const char *name) { + const char *svc_name; struct rpc_service *svc = NULL; int i; - if (!starts_with(name, "git-")) + if (!skip_prefix(name, "git-", &svc_name)) forbidden("Unsupported service: '%s'", name); for (i = 0; i < ARRAY_SIZE(rpc_service); i++) { struct rpc_service *s = &rpc_service[i]; - if (!strcmp(s->name, name + 4)) { + if (!strcmp(s->name, svc_name)) { svc = s; break; } diff --git a/http-push.c b/http-push.c index 390f74c97b..6c3cc1725a 100644 --- a/http-push.c +++ b/http-push.c @@ -719,14 +719,10 @@ static int fetch_indices(void) return ret; } -static void one_remote_object(const char *hex) +static void one_remote_object(const unsigned char *sha1) { - unsigned char sha1[20]; struct object *obj; - if (get_sha1_hex(hex, sha1) != 0) - return; - obj = lookup_object(sha1); if (!obj) obj = parse_object(sha1); @@ -769,9 +765,9 @@ static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed) if (!strcmp(ctx->name, DAV_ACTIVELOCK_OWNER)) { lock->owner = xstrdup(ctx->cdata); } else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TIMEOUT)) { - if (starts_with(ctx->cdata, "Second-")) - lock->timeout = - strtol(ctx->cdata + 7, NULL, 10); + const char *arg; + if (skip_prefix(ctx->cdata, "Second-", &arg)) + lock->timeout = strtol(arg, NULL, 10); } else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TOKEN)) { lock->token = xstrdup(ctx->cdata); @@ -1017,26 +1013,38 @@ static void remote_ls(const char *path, int flags, void (*userFunc)(struct remote_ls_ctx *ls), void *userData); +/* extract hex from sharded "xx/x{40}" filename */ +static int get_sha1_hex_from_objpath(const char *path, unsigned char *sha1) +{ + char hex[40]; + + if (strlen(path) != 41) + return -1; + + memcpy(hex, path, 2); + path += 2; + path++; /* skip '/' */ + memcpy(hex, path, 38); + + return get_sha1_hex(hex, sha1); +} + static void process_ls_object(struct remote_ls_ctx *ls) { unsigned int *parent = (unsigned int *)ls->userData; - char *path = ls->dentry_name; - char *obj_hex; + const char *path = ls->dentry_name; + unsigned char sha1[20]; if (!strcmp(ls->path, ls->dentry_name) && (ls->flags & IS_DIR)) { remote_dir_exists[*parent] = 1; return; } - if (strlen(path) != 49) + if (!skip_prefix(path, "objects/", &path) || + get_sha1_hex_from_objpath(path, sha1)) return; - path += 8; - obj_hex = xmalloc(strlen(path)); - /* NB: path is not null-terminated, can not use strlcpy here */ - memcpy(obj_hex, path, 2); - strcpy(obj_hex + 2, path + 3); - one_remote_object(obj_hex); - free(obj_hex); + + one_remote_object(sha1); } static void process_ls_ref(struct remote_ls_ctx *ls) @@ -1555,6 +1563,7 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1) { char *url = xstrfmt("%s%s", repo->url, path); struct strbuf buffer = STRBUF_INIT; + const char *name; if (http_get_strbuf(url, &buffer, NULL) != HTTP_OK) die("Couldn't get %s for remote symref\n%s", url, @@ -1569,8 +1578,8 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1) return; /* If it's a symref, set the refname; otherwise try for a sha1 */ - if (starts_with((char *)buffer.buf, "ref: ")) { - *symref = xmemdupz((char *)buffer.buf + 5, buffer.len - 6); + if (skip_prefix(buffer.buf, "ref: ", &name)) { + *symref = xmemdupz(name, buffer.len - (name - buffer.buf)); } else { get_sha1_hex(buffer.buf, sha1); } @@ -927,7 +927,7 @@ static int extract_param(const char *raw, const char *name, return -1; raw++; - while (*raw && !isspace(*raw)) + while (*raw && !isspace(*raw) && *raw != ';') strbuf_addch(out, *raw++); return 0; } @@ -971,7 +971,7 @@ static void extract_content_type(struct strbuf *raw, struct strbuf *type, strbuf_reset(charset); while (*p) { - while (isspace(*p)) + while (isspace(*p) || *p == ';') p++; if (!extract_param(p, "charset", charset)) return; @@ -1087,11 +1087,10 @@ static int update_url_from_redirect(struct strbuf *base, if (!strcmp(asked, got->buf)) return 0; - if (!starts_with(asked, base->buf)) + if (!skip_prefix(asked, base->buf, &tail)) die("BUG: update_url_from_redirect: %s is not a superset of %s", asked, base->buf); - tail = asked + base->len; tail_len = strlen(tail); if (got->len < tail_len || diff --git a/imap-send.c b/imap-send.c index 83a6ed2ac3..524fbabc96 100644 --- a/imap-send.c +++ b/imap-send.c @@ -1328,13 +1328,9 @@ static char *imap_folder; static int git_imap_config(const char *key, const char *val, void *cb) { - char imap_key[] = "imap."; - - if (strncmp(key, imap_key, sizeof imap_key - 1)) + if (!skip_prefix(key, "imap.", &key)) return 0; - key += sizeof imap_key - 1; - /* check booleans first, and barf on others */ if (!strcmp("sslverify", key)) server.ssl_verify = git_config_bool(key, val); diff --git a/line-log.c b/line-log.c index 1500101058..afcc98db93 100644 --- a/line-log.c +++ b/line-log.c @@ -1174,9 +1174,7 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm */ add_line_range(rev, parents[i], cand[i]); clear_commit_line_range(rev, commit); - commit->parents = xmalloc(sizeof(struct commit_list)); - commit->parents->item = parents[i]; - commit->parents->next = NULL; + commit_list_append(parents[i], &commit->parents); free(parents); free(cand); free_diffqueues(nparents, diffqueues); diff --git a/log-tree.c b/log-tree.c index cf2f86c866..10e68442b3 100644 --- a/log-tree.c +++ b/log-tree.c @@ -376,7 +376,7 @@ static void show_signature(struct rev_info *opt, struct commit *commit) struct strbuf gpg_output = STRBUF_INIT; int status; - if (parse_signed_commit(commit->object.sha1, &payload, &signature) <= 0) + if (parse_signed_commit(commit, &payload, &signature) <= 0) goto out; status = verify_signed_buffer(payload.buf, payload.len, @@ -588,7 +588,7 @@ void show_log(struct rev_info *opt) show_mergetag(opt, commit); } - if (!commit->buffer) + if (!get_cached_commit_buffer(commit, NULL)) return; if (opt->show_notes) { diff --git a/merge-recursive.c b/merge-recursive.c index 398a734f3f..b5c3c5314f 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -40,7 +40,7 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two, static struct commit *make_virtual_commit(struct tree *tree, const char *comment) { - struct commit *commit = xcalloc(1, sizeof(struct commit)); + struct commit *commit = alloc_commit_node(); struct merge_remote_desc *desc = xmalloc(sizeof(*desc)); desc->name = comment; @@ -190,9 +190,11 @@ static void output_commit_title(struct merge_options *o, struct commit *commit) printf(_("(bad commit)\n")); else { const char *title; - int len = find_commit_subject(commit->buffer, &title); + const char *msg = get_commit_buffer(commit, NULL); + int len = find_commit_subject(msg, &title); if (len) printf("%.*s\n", len, title); + unuse_commit_buffer(commit, msg); } } } @@ -2070,6 +2072,8 @@ void init_merge_options(struct merge_options *o) int parse_merge_opt(struct merge_options *o, const char *s) { + const char *arg; + if (!s || !*s) return -1; if (!strcmp(s, "ours")) @@ -2078,14 +2082,14 @@ int parse_merge_opt(struct merge_options *o, const char *s) o->recursive_variant = MERGE_RECURSIVE_THEIRS; else if (!strcmp(s, "subtree")) o->subtree_shift = ""; - else if (starts_with(s, "subtree=")) - o->subtree_shift = s + strlen("subtree="); + else if (skip_prefix(s, "subtree=", &arg)) + o->subtree_shift = arg; else if (!strcmp(s, "patience")) o->xdl_opts = DIFF_WITH_ALG(o, PATIENCE_DIFF); else if (!strcmp(s, "histogram")) o->xdl_opts = DIFF_WITH_ALG(o, HISTOGRAM_DIFF); - else if (starts_with(s, "diff-algorithm=")) { - long value = parse_algorithm_value(s + strlen("diff-algorithm=")); + else if (skip_prefix(s, "diff-algorithm=", &arg)) { + long value = parse_algorithm_value(arg); if (value < 0) return -1; /* clear out previous settings */ @@ -2103,9 +2107,8 @@ int parse_merge_opt(struct merge_options *o, const char *s) o->renormalize = 1; else if (!strcmp(s, "no-renormalize")) o->renormalize = 0; - else if (starts_with(s, "rename-threshold=")) { - const char *score = s + strlen("rename-threshold="); - if ((o->rename_score = parse_rename_score(&score)) == -1 || *score != 0) + else if (skip_prefix(s, "rename-threshold=", &arg)) { + if ((o->rename_score = parse_rename_score(&arg)) == -1 || *arg != 0) return -1; } else diff --git a/name-hash.c b/name-hash.c index 97444d0201..49fd508317 100644 --- a/name-hash.c +++ b/name-hash.c @@ -179,7 +179,7 @@ static int same_name(const struct cache_entry *ce, const char *name, int namelen * Always do exact compare, even if we want a case-ignoring comparison; * we do the quick exact one first, because it will be the common case. */ - if (len == namelen && !cache_name_compare(name, namelen, ce->name, len)) + if (len == namelen && !memcmp(name, ce->name, len)) return 1; if (!icase) diff --git a/notes-cache.c b/notes-cache.c index 97dfd63c9b..c4e9bb7f6c 100644 --- a/notes-cache.c +++ b/notes-cache.c @@ -48,7 +48,6 @@ int notes_cache_write(struct notes_cache *c) { unsigned char tree_sha1[20]; unsigned char commit_sha1[20]; - struct strbuf msg = STRBUF_INIT; if (!c || !c->tree.initialized || !c->tree.ref || !*c->tree.ref) return -1; @@ -57,9 +56,8 @@ int notes_cache_write(struct notes_cache *c) if (write_notes_tree(&c->tree, tree_sha1)) return -1; - strbuf_attach(&msg, c->validity, - strlen(c->validity), strlen(c->validity) + 1); - if (commit_tree(&msg, tree_sha1, NULL, commit_sha1, NULL, NULL) < 0) + if (commit_tree(c->validity, strlen(c->validity), tree_sha1, NULL, + commit_sha1, NULL, NULL) < 0) return -1; if (update_ref("update notes cache", c->tree.ref, commit_sha1, NULL, 0, UPDATE_REFS_QUIET_ON_ERR) < 0) diff --git a/notes-merge.c b/notes-merge.c index 94a1a8ae46..fd5fae255d 100644 --- a/notes-merge.c +++ b/notes-merge.c @@ -644,7 +644,8 @@ int notes_merge(struct notes_merge_options *o, struct commit_list *parents = NULL; commit_list_insert(remote, &parents); /* LIFO order */ commit_list_insert(local, &parents); - create_notes_commit(local_tree, parents, &o->commit_msg, + create_notes_commit(local_tree, parents, + o->commit_msg.buf, o->commit_msg.len, result_sha1); } @@ -671,8 +672,8 @@ int notes_merge_commit(struct notes_merge_options *o, DIR *dir; struct dirent *e; struct strbuf path = STRBUF_INIT; - char *msg = strstr(partial_commit->buffer, "\n\n"); - struct strbuf sb_msg = STRBUF_INIT; + const char *buffer = get_commit_buffer(partial_commit, NULL); + const char *msg = strstr(buffer, "\n\n"); int baselen; strbuf_addstr(&path, git_path(NOTES_MERGE_WORKTREE)); @@ -719,9 +720,9 @@ int notes_merge_commit(struct notes_merge_options *o, strbuf_setlen(&path, baselen); } - strbuf_attach(&sb_msg, msg, strlen(msg), strlen(msg) + 1); - create_notes_commit(partial_tree, partial_commit->parents, &sb_msg, - result_sha1); + create_notes_commit(partial_tree, partial_commit->parents, + msg, strlen(msg), result_sha1); + unuse_commit_buffer(partial_commit, buffer); if (o->verbosity >= 4) printf("Finalized notes merge commit: %s\n", sha1_to_hex(result_sha1)); diff --git a/notes-utils.c b/notes-utils.c index a0b1d7be98..b64dc1b021 100644 --- a/notes-utils.c +++ b/notes-utils.c @@ -4,7 +4,8 @@ #include "notes-utils.h" void create_notes_commit(struct notes_tree *t, struct commit_list *parents, - const struct strbuf *msg, unsigned char *result_sha1) + const char *msg, size_t msg_len, + unsigned char *result_sha1) { unsigned char tree_sha1[20]; @@ -25,7 +26,7 @@ void create_notes_commit(struct notes_tree *t, struct commit_list *parents, /* else: t->ref points to nothing, assume root/orphan commit */ } - if (commit_tree(msg, tree_sha1, parents, result_sha1, NULL, NULL)) + if (commit_tree(msg, msg_len, tree_sha1, parents, result_sha1, NULL, NULL)) die("Failed to commit notes tree to database"); } @@ -46,7 +47,7 @@ void commit_notes(struct notes_tree *t, const char *msg) if (buf.buf[buf.len - 1] != '\n') strbuf_addch(&buf, '\n'); /* Make sure msg ends with newline */ - create_notes_commit(t, NULL, &buf, commit_sha1); + create_notes_commit(t, NULL, buf.buf, buf.len, commit_sha1); strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */ update_ref(buf.buf, t->ref, commit_sha1, NULL, 0, UPDATE_REFS_DIE_ON_ERR); diff --git a/notes-utils.h b/notes-utils.h index 564e30cccd..890ddb33e1 100644 --- a/notes-utils.h +++ b/notes-utils.h @@ -15,7 +15,7 @@ * The resulting commit SHA1 is stored in result_sha1. */ void create_notes_commit(struct notes_tree *t, struct commit_list *parents, - const struct strbuf *msg, unsigned char *result_sha1); + const char *msg, size_t msg_len, unsigned char *result_sha1); void commit_notes(struct notes_tree *t, const char *msg); @@ -197,8 +197,8 @@ struct object *parse_object_buffer(const unsigned char *sha1, enum object_type t if (commit) { if (parse_commit_buffer(commit, buffer, size)) return NULL; - if (!commit->buffer) { - commit->buffer = buffer; + if (!get_cached_commit_buffer(commit, NULL)) { + set_commit_buffer(commit, buffer, size); *eaten_p = 1; } obj = &commit->object; diff --git a/parse-options.c b/parse-options.c index b536896f26..e7dafa80d5 100644 --- a/parse-options.c +++ b/parse-options.c @@ -231,7 +231,8 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, continue; again: - rest = skip_prefix(arg, long_name); + if (!skip_prefix(arg, long_name, &rest)) + rest = NULL; if (options->type == OPTION_ARGUMENT) { if (!rest) continue; @@ -280,12 +281,13 @@ is_abbreviated: continue; } flags |= OPT_UNSET; - rest = skip_prefix(arg + 3, long_name); - /* abbreviated and negated? */ - if (!rest && starts_with(long_name, arg + 3)) - goto is_abbreviated; - if (!rest) - continue; + if (!skip_prefix(arg + 3, long_name, &rest)) { + /* abbreviated and negated? */ + if (starts_with(long_name, arg + 3)) + goto is_abbreviated; + else + continue; + } } if (*rest) { if (*rest != '=') @@ -40,10 +40,9 @@ static int git_pretty_formats_config(const char *var, const char *value, void *c const char *fmt; int i; - if (!starts_with(var, "pretty.")) + if (!skip_prefix(var, "pretty.", &name)) return 0; - name = var + strlen("pretty."); for (i = 0; i < builtin_formats_len; i++) { if (!strcmp(commit_formats[i].name, name)) return 0; @@ -274,7 +273,7 @@ static void add_rfc822_quoted(struct strbuf *out, const char *s, int len) enum rfc2047_type { RFC2047_SUBJECT, - RFC2047_ADDRESS, + RFC2047_ADDRESS }; static int is_rfc2047_special(char ch, enum rfc2047_type type) @@ -606,29 +605,16 @@ static char *replace_encoding_header(char *buf, const char *encoding) return strbuf_detach(&tmp, NULL); } -char *logmsg_reencode(const struct commit *commit, - char **commit_encoding, - const char *output_encoding) +const char *logmsg_reencode(const struct commit *commit, + char **commit_encoding, + const char *output_encoding) { static const char *utf8 = "UTF-8"; const char *use_encoding; char *encoding; - char *msg = commit->buffer; + const char *msg = get_commit_buffer(commit, NULL); char *out; - if (!msg) { - enum object_type type; - unsigned long size; - - msg = read_sha1_file(commit->object.sha1, &type, &size); - if (!msg) - die("Cannot read commit object %s", - sha1_to_hex(commit->object.sha1)); - if (type != OBJ_COMMIT) - die("Expected commit for '%s', got %s", - sha1_to_hex(commit->object.sha1), typename(type)); - } - if (!output_encoding || !*output_encoding) { if (commit_encoding) *commit_encoding = @@ -652,12 +638,13 @@ char *logmsg_reencode(const struct commit *commit, * Otherwise, we still want to munge the encoding header in the * result, which will be done by modifying the buffer. If we * are using a fresh copy, we can reuse it. But if we are using - * the cached copy from commit->buffer, we need to duplicate it - * to avoid munging commit->buffer. + * the cached copy from get_commit_buffer, we need to duplicate it + * to avoid munging the cached copy. */ - out = msg; - if (out == commit->buffer) - out = xstrdup(out); + if (msg == get_cached_commit_buffer(commit, NULL)) + out = xstrdup(msg); + else + out = (char *)msg; } else { /* @@ -667,8 +654,8 @@ char *logmsg_reencode(const struct commit *commit, * copy, we can free it. */ out = reencode_string(msg, output_encoding, use_encoding); - if (out && msg != commit->buffer) - free(msg); + if (out) + unuse_commit_buffer(commit, msg); } /* @@ -687,12 +674,6 @@ char *logmsg_reencode(const struct commit *commit, return out ? out : msg; } -void logmsg_free(char *msg, const struct commit *commit) -{ - if (msg != commit->buffer) - free(msg); -} - static int mailmap_name(const char **email, size_t *email_len, const char **name, size_t *name_len) { @@ -796,7 +777,7 @@ struct format_commit_context { struct signature_check signature_check; enum flush_type flush_type; enum trunc_type truncate; - char *message; + const char *message; char *commit_encoding; size_t width, indent1, indent2; int auto_color; @@ -1536,7 +1517,7 @@ void format_commit_message(const struct commit *commit, } free(context.commit_encoding); - logmsg_free(context.message, commit); + unuse_commit_buffer(commit, context.message); free(context.signature_check.gpg_output); free(context.signature_check.signer); } @@ -1705,7 +1686,7 @@ void pretty_print_commit(struct pretty_print_context *pp, unsigned long beginning_of_body; int indent = 4; const char *msg; - char *reencoded; + const char *reencoded; const char *encoding; int need_8bit_cte = pp->need_8bit_cte; @@ -1772,7 +1753,7 @@ void pretty_print_commit(struct pretty_print_context *pp, if (pp->fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body) strbuf_addch(sb, '\n'); - logmsg_free(reencoded, commit); + unuse_commit_buffer(commit, reencoded); } void pp_commit_easy(enum cmit_fmt fmt, const struct commit *commit, diff --git a/read-cache.c b/read-cache.c index 7f5645e745..6a45966ec4 100644 --- a/read-cache.c +++ b/read-cache.c @@ -422,18 +422,26 @@ int df_name_compare(const char *name1, int len1, int mode1, return c1 - c2; } -int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2) +int name_compare(const char *name1, size_t len1, const char *name2, size_t len2) { - int len = len1 < len2 ? len1 : len2; - int cmp; - - cmp = memcmp(name1, name2, len); + size_t min_len = (len1 < len2) ? len1 : len2; + int cmp = memcmp(name1, name2, min_len); if (cmp) return cmp; if (len1 < len2) return -1; if (len1 > len2) return 1; + return 0; +} + +int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2) +{ + int cmp; + + cmp = name_compare(name1, len1, name2, len2); + if (cmp) + return cmp; if (stage1 < stage2) return -1; @@ -442,11 +450,6 @@ int cache_name_stage_compare(const char *name1, int len1, int stage1, const char return 0; } -int cache_name_compare(const char *name1, int len1, const char *name2, int len2) -{ - return cache_name_stage_compare(name1, len1, 0, name2, len2, 0); -} - static int index_name_stage_pos(const struct index_state *istate, const char *name, int namelen, int stage) { int first, last; @@ -7,21 +7,27 @@ /* * How to handle various characters in refnames: + * This table is used by both the SIMD and non-SIMD code. It has + * some cases that are only useful for the SIMD; these are handled + * equivalently to the listed disposition in the non-SIMD code. * 0: An acceptable character for refs - * 1: End-of-component - * 2: ., look for a preceding . to reject .. in refs - * 3: {, look for a preceding @ to reject @{ in refs - * 4: A bad character: ASCII control characters, "~", "^", ":" or SP + * 1: @, look for a following { to reject @{ in refs (SIMD or = 0) + * 2: \0: End-of-component and string + * 3: /: End-of-component (SIMD or = 2) + * 4: ., look for a preceding . to reject .. in refs + * 5: {, look for a preceding @ to reject @{ in refs + * 6: *, usually a bad character except, once as a wildcard (SIMD or = 7) + * 7: A bad character except * (see check_refname_component below) */ static unsigned char refname_disposition[256] = { - 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 2, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 4, + 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 4, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 7, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 4, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 4 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 7, 7 }; /* @@ -33,8 +39,9 @@ static unsigned char refname_disposition[256] = { * - any path component of it begins with ".", or * - it has double dots "..", or * - it has ASCII control character, "~", "^", ":" or SP, anywhere, or - * - it ends with a "/". - * - it ends with ".lock" + * - it has pattern-matching notation "*", "?", "[", anywhere, or + * - it ends with a "/", or + * - it ends with ".lock", or * - it contains a "\" (backslash) */ static int check_refname_component(const char *refname, int flags) @@ -46,17 +53,19 @@ static int check_refname_component(const char *refname, int flags) int ch = *cp & 255; unsigned char disp = refname_disposition[ch]; switch (disp) { - case 1: + case 2: /* fall-through */ + case 3: goto out; - case 2: + case 4: if (last == '.') return -1; /* Refname contains "..". */ break; - case 3: + case 5: if (last == '@') return -1; /* Refname contains "@{". */ break; - case 4: + case 6: /* fall-through */ + case 7: return -1; } last = ch; @@ -79,7 +88,7 @@ out: return cp - refname; } -int check_refname_format(const char *refname, int flags) +static int check_refname_format_bytewise(const char *refname, int flags) { int component_len, component_count = 0; @@ -115,6 +124,195 @@ int check_refname_format(const char *refname, int flags) return 0; } +#if defined(__GNUC__) && defined(__x86_64__) +#define SSE_VECTOR_BYTES 16 + +/* Vectorized version of check_refname_format. */ +int check_refname_format(const char *refname, int flags) +{ + const char *cp = refname; + + const __m128i dot = _mm_set1_epi8('.'); + const __m128i at = _mm_set1_epi8('@'); + const __m128i curly = _mm_set1_epi8('{'); + const __m128i slash = _mm_set1_epi8('/'); + const __m128i zero = _mm_set1_epi8('\000'); + const __m128i el = _mm_set1_epi8('l'); + + /* below '*', all characters are forbidden or rare */ + const __m128i star_ub = _mm_set1_epi8('*' + 1); + + const __m128i colon = _mm_set1_epi8(':'); + const __m128i question = _mm_set1_epi8('?'); + + /* '['..'^' contains 4 characters: 3 forbidden and 1 rare */ + const __m128i bracket_lb = _mm_set1_epi8('[' - 1); + const __m128i caret_ub = _mm_set1_epi8('^' + 1); + + /* '~' and above are forbidden */ + const __m128i tilde_lb = _mm_set1_epi8('~' - 1); + + int component_count = 0; + + if (refname[0] == 0 || refname[0] == '/') { + /* entirely empty ref or initial ref component */ + return -1; + } + + /* + * Initial ref component of '.'; below we look for /. so we'll + * miss this. + */ + if (refname[0] == '.') { + if (refname[1] == '/' || refname[1] == '\0') + return -1; + if (!(flags & REFNAME_DOT_COMPONENT)) + return -1; + } + while(1) { + __m128i tmp, tmp1, result; + uint64_t mask; + + if ((uintptr_t) cp % PAGE_SIZE > PAGE_SIZE - SSE_VECTOR_BYTES - 1) + /* + * End-of-page; fall back to slow method for + * this entire ref. + */ + return check_refname_format_bytewise(refname, flags); + + tmp = _mm_loadu_si128((__m128i *)cp); + tmp1 = _mm_loadu_si128((__m128i *)(cp + 1)); + + /* + * This range (note the lt) contains some + * permissible-but-rare characters (including all + * characters >= 128), which we handle later. It also + * includes \000. + */ + result = _mm_cmplt_epi8(tmp, star_ub); + + result = _mm_or_si128(result, _mm_cmpeq_epi8(tmp, question)); + result = _mm_or_si128(result, _mm_cmpeq_epi8(tmp, colon)); + + /* This range contains the permissible ] as bycatch */ + result = _mm_or_si128(result, _mm_and_si128( + _mm_cmpgt_epi8(tmp, bracket_lb), + _mm_cmplt_epi8(tmp, caret_ub))); + + result = _mm_or_si128(result, _mm_cmpgt_epi8(tmp, tilde_lb)); + + /* .. */ + result = _mm_or_si128(result, _mm_and_si128( + _mm_cmpeq_epi8(tmp, dot), + _mm_cmpeq_epi8(tmp1, dot))); + /* @{ */ + result = _mm_or_si128(result, _mm_and_si128( + _mm_cmpeq_epi8(tmp, at), + _mm_cmpeq_epi8(tmp1, curly))); + /* // */ + result = _mm_or_si128(result, _mm_and_si128( + _mm_cmpeq_epi8(tmp, slash), + _mm_cmpeq_epi8(tmp1, slash))); + /* trailing / */ + result = _mm_or_si128(result, _mm_and_si128( + _mm_cmpeq_epi8(tmp, slash), + _mm_cmpeq_epi8(tmp1, zero))); + /* .l, beginning of .lock */ + result = _mm_or_si128(result, _mm_and_si128( + _mm_cmpeq_epi8(tmp, dot), + _mm_cmpeq_epi8(tmp1, el))); + /* + * Even though /. is not necessarily an error, we flag + * it anyway. If we find it, we'll check if it's valid + * and if so we'll advance just past it. + */ + result = _mm_or_si128(result, _mm_and_si128( + _mm_cmpeq_epi8(tmp, slash), + _mm_cmpeq_epi8(tmp1, dot))); + + mask = _mm_movemask_epi8(result); + if (mask) { + /* + * We've found either end-of-string, or some + * probably-bad character or substring. + */ + int i = __builtin_ctz(mask); + switch (refname_disposition[cp[i] & 255]) { + case 0: /* fall-through */ + case 5: + /* + * bycatch: a good character that's in + * one of the ranges of mostly-forbidden + * characters + */ + cp += i + 1; + break; + case 1: + if (cp[i + 1] == '{') + return -1; + cp += i + 1; + break; + case 2: + if (!(flags & REFNAME_ALLOW_ONELEVEL) + && !component_count && !strchr(refname, '/')) + /* Refname has only one component. */ + return -1; + return 0; + case 3: + component_count ++; + /* + * Even if leading dots are allowed, don't + * allow "." as a component (".." is + * prevented by case 4 below). + */ + if (cp[i + 1] == '.') { + if (cp[i + 2] == '\0') + return -1; + if (flags & REFNAME_DOT_COMPONENT) { + /* skip to just after the /. */ + cp += i + 2; + break; + } + return -1; + } else if (cp[i + 1] == '/' || cp[i + 1] == '\0') + return -1; + break; + case 4: + if (cp[i + 1] == '.' || cp[i + 1] == '\0') + return -1; + /* .lock as end-of-component or end-of-string */ + if ((!strncmp(cp + i, ".lock", 5)) + && (cp[i + 5] == '/' || cp[i + 5] == 0)) + return -1; + cp += 1; + break; + case 6: + if (((cp == refname + i) || cp[i - 1] == '/') + && (cp[i + 1] == '/' || cp[i + 1] == 0)) + if (flags & REFNAME_REFSPEC_PATTERN) { + flags &= ~REFNAME_REFSPEC_PATTERN; + /* restart after the * */ + cp += i + 1; + continue; + } + /* fall-through */ + case 7: + return -1; + } + } else + cp += SSE_VECTOR_BYTES; + } +} + +#else + +int check_refname_format (const char *refname, int flags) +{ + return check_refname_format_bytewise(refname, flags); +} + +#endif + struct ref_entry; /* diff --git a/remote-curl.c b/remote-curl.c index 4493b389de..cdcca2903b 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -791,9 +791,9 @@ static void parse_fetch(struct strbuf *buf) int alloc_heads = 0, nr_heads = 0; do { - if (starts_with(buf->buf, "fetch ")) { - char *p = buf->buf + strlen("fetch "); - char *name; + const char *p; + if (skip_prefix(buf->buf, "fetch ", &p)) { + const char *name; struct ref *ref; unsigned char old_sha1[20]; @@ -968,6 +968,8 @@ int main(int argc, const char **argv) http_init(remote, url.buf, 0); do { + const char *arg; + if (strbuf_getline(&buf, stdin, '\n') == EOF) { if (ferror(stdin)) fprintf(stderr, "Error reading command stream\n"); @@ -989,9 +991,8 @@ int main(int argc, const char **argv) } else if (starts_with(buf.buf, "push ")) { parse_push(&buf); - } else if (starts_with(buf.buf, "option ")) { - char *name = buf.buf + strlen("option "); - char *value = strchr(name, ' '); + } else if (skip_prefix(buf.buf, "option ", &arg)) { + char *value = strchr(arg, ' '); int result; if (value) @@ -999,7 +1000,7 @@ int main(int argc, const char **argv) else value = "true"; - result = set_option(name, value); + result = set_option(arg, value); if (!result) printf("ok\n"); else if (result < 0) @@ -484,9 +484,8 @@ static void read_config(void) current_branch = NULL; head_ref = resolve_ref_unsafe("HEAD", sha1, 0, &flag); if (head_ref && (flag & REF_ISSYMREF) && - starts_with(head_ref, "refs/heads/")) { - current_branch = - make_branch(head_ref + strlen("refs/heads/"), 0); + skip_prefix(head_ref, "refs/heads/", &head_ref)) { + current_branch = make_branch(head_ref, 0); } git_config(handle_config, NULL); if (branch_pushremote_name) { @@ -1190,7 +1189,7 @@ static int match_explicit(struct ref *src, struct ref *dst, case 1: break; case 0: - if (!memcmp(dst_value, "refs/", 5)) + if (starts_with(dst_value, "refs/")) matched_dst = make_linked_ref(dst_value, dst_tail); else if (is_null_sha1(matched_src->new_sha1)) error("unable to delete '%s': remote ref does not exist", diff --git a/revision.c b/revision.c index 3818b4628d..2571ada6bf 100644 --- a/revision.c +++ b/revision.c @@ -1649,8 +1649,10 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->skip_count = atoi(optarg); return argcount; } else if ((*arg == '-') && isdigit(arg[1])) { - /* accept -<digit>, like traditional "head" */ - revs->max_count = atoi(arg + 1); + /* accept -<digit>, like traditional "head" */ + if (strtol_i(arg + 1, 10, &revs->max_count) < 0 || + revs->max_count < 0) + die("'%s': not a non-negative integer", arg + 1); revs->no_walk = 0; } else if (!strcmp(arg, "-n")) { if (argc <= 1) @@ -2789,7 +2791,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt) { int retval; const char *encoding; - char *message; + const char *message; struct strbuf buf = STRBUF_INIT; if (!opt->grep_filter.pattern_list && !opt->grep_filter.header_list) @@ -2831,14 +2833,21 @@ static int commit_match(struct commit *commit, struct rev_info *opt) format_display_notes(commit->object.sha1, &buf, encoding, 1); } - /* Find either in the original commit message, or in the temporary */ + /* + * Find either in the original commit message, or in the temporary. + * Note that we cast away the constness of "message" here. It is + * const because it may come from the cached commit buffer. That's OK, + * because we know that it is modifiable heap memory, and that while + * grep_buffer may modify it for speed, it will restore any + * changes before returning. + */ if (buf.len) retval = grep_buffer(&opt->grep_filter, buf.buf, buf.len); else retval = grep_buffer(&opt->grep_filter, - message, strlen(message)); + (char *)message, strlen(message)); strbuf_release(&buf); - logmsg_free(message, commit); + unuse_commit_buffer(commit, message); return retval; } diff --git a/sequencer.c b/sequencer.c index 2fea824349..cdd30c0737 100644 --- a/sequencer.c +++ b/sequencer.c @@ -116,39 +116,23 @@ static const char *action_name(const struct replay_opts *opts) return opts->action == REPLAY_REVERT ? "revert" : "cherry-pick"; } -static char *get_encoding(const char *message); - struct commit_message { char *parent_label; const char *label; const char *subject; - char *reencoded_message; const char *message; }; static int get_message(struct commit *commit, struct commit_message *out) { - const char *encoding; const char *abbrev, *subject; int abbrev_len, subject_len; char *q; - if (!commit->buffer) - return -1; - encoding = get_encoding(commit->buffer); - if (!encoding) - encoding = "UTF-8"; if (!git_commit_encoding) git_commit_encoding = "UTF-8"; - out->reencoded_message = NULL; - out->message = commit->buffer; - if (same_encoding(encoding, git_commit_encoding)) - out->reencoded_message = reencode_string(commit->buffer, - git_commit_encoding, encoding); - if (out->reencoded_message) - out->message = out->reencoded_message; - + out->message = logmsg_reencode(commit, NULL, git_commit_encoding); abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV); abbrev_len = strlen(abbrev); @@ -167,29 +151,10 @@ static int get_message(struct commit *commit, struct commit_message *out) return 0; } -static void free_message(struct commit_message *msg) +static void free_message(struct commit *commit, struct commit_message *msg) { free(msg->parent_label); - free(msg->reencoded_message); -} - -static char *get_encoding(const char *message) -{ - const char *p = message, *eol; - - while (*p && *p != '\n') { - for (eol = p + 1; *eol && *eol != '\n'; eol++) - ; /* do nothing */ - if (starts_with(p, "encoding ")) { - char *result = xmalloc(eol - 8 - p); - strlcpy(result, p + 9, eol - 8 - p); - return result; - } - p = eol; - if (*p == '\n') - p++; - } - return NULL; + unuse_commit_buffer(commit, msg->message); } static void write_cherry_pick_head(struct commit *commit, const char *pseudoref) @@ -278,7 +243,7 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from, read_cache(); if (checkout_fast_forward(from, to, 1)) - exit(1); /* the callee should have complained already */ + exit(128); /* the callee should have complained already */ ref_lock = lock_any_ref_for_update("HEAD", unborn ? null_sha1 : from, 0, NULL); if (!ref_lock) @@ -484,7 +449,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts) unsigned char head[20]; struct commit *base, *next, *parent; const char *base_label, *next_label; - struct commit_message msg = { NULL, NULL, NULL, NULL, NULL }; + struct commit_message msg = { NULL, NULL, NULL, NULL }; char *defmsg = NULL; struct strbuf msgbuf = STRBUF_INIT; int res, unborn = 0, allow; @@ -649,7 +614,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts) res = run_git_commit(defmsg, opts, allow); leave: - free_message(&msg); + free_message(commit, &msg); free(defmsg); return res; @@ -696,10 +661,12 @@ static int format_todo(struct strbuf *buf, struct commit_list *todo_list, int subject_len; for (cur = todo_list; cur; cur = cur->next) { + const char *commit_buffer = get_commit_buffer(cur->item, NULL); sha1_abbrev = find_unique_abbrev(cur->item->object.sha1, DEFAULT_ABBREV); - subject_len = find_commit_subject(cur->item->buffer, &subject); + subject_len = find_commit_subject(commit_buffer, &subject); strbuf_addf(buf, "%s %s %.*s\n", action_str, sha1_abbrev, subject_len, subject); + unuse_commit_buffer(cur->item, commit_buffer); } return 0; } diff --git a/sha1_name.c b/sha1_name.c index 5e956904b6..5bfa841699 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -862,27 +862,17 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1, commit_list_insert(l->item, &backup); } while (list) { - char *p, *to_free = NULL; + const char *p, *buf; struct commit *commit; - enum object_type type; - unsigned long size; int matches; commit = pop_most_recent_commit(&list, ONELINE_SEEN); if (!parse_object(commit->object.sha1)) continue; - if (commit->buffer) - p = commit->buffer; - else { - p = read_sha1_file(commit->object.sha1, &type, &size); - if (!p) - continue; - to_free = p; - } - - p = strstr(p, "\n\n"); + buf = get_commit_buffer(commit, NULL); + p = strstr(buf, "\n\n"); matches = p && !regexec(®ex, p + 2, 0, NULL, 0); - free(to_free); + unuse_commit_buffer(commit, buf); if (matches) { hashcpy(sha1, commit->object.sha1); @@ -911,10 +901,8 @@ static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1, const char *match = NULL, *target = NULL; size_t len; - if (starts_with(message, "checkout: moving from ")) { - match = message + strlen("checkout: moving from "); + if (skip_prefix(message, "checkout: moving from ", &match)) target = strstr(match, " to "); - } if (!match || !target) return 0; diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh index 272fceef96..fd53b57187 100644 --- a/t/lib-httpd.sh +++ b/t/lib-httpd.sh @@ -142,7 +142,7 @@ prepare_httpd() { HTTPD_URL_USER=$HTTPD_PROTO://user%40host@$HTTPD_DEST HTTPD_URL_USER_PASS=$HTTPD_PROTO://user%40host:pass%40host@$HTTPD_DEST - if test -n "$LIB_HTTPD_DAV" -o -n "$LIB_HTTPD_SVN" + if test -n "$LIB_HTTPD_DAV" || test -n "$LIB_HTTPD_SVN" then HTTPD_PARA="$HTTPD_PARA -DDAV" diff --git a/t/lib-httpd/error.sh b/t/lib-httpd/error.sh index eafc9d2d90..a77b8e5469 100755 --- a/t/lib-httpd/error.sh +++ b/t/lib-httpd/error.sh @@ -19,6 +19,10 @@ case "$PATH_INFO" in printf "text/plain; charset=utf-16" charset=utf-16 ;; +*odd-spacing*) + printf "text/plain; foo=bar ;charset=utf-16; other=nonsense" + charset=utf-16 + ;; esac printf "\n" diff --git a/t/perf/p5310-pack-bitmaps.sh b/t/perf/p5310-pack-bitmaps.sh index 685d46f8b7..f8ed8573b7 100755 --- a/t/perf/p5310-pack-bitmaps.sh +++ b/t/perf/p5310-pack-bitmaps.sh @@ -8,6 +8,9 @@ test_perf_large_repo # note that we do everything through config, # since we want to be able to compare bitmap-aware # git versus non-bitmap git +# +# We intentionally use the deprecated pack.writebitmaps +# config so that we can test against older versions of git. test_expect_success 'setup bitmap config' ' git config pack.writebitmaps true && git config pack.writebitmaphashcache true diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 2f3020342a..e62c0ffbc2 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -56,7 +56,7 @@ test_expect_success 'plain through aliased command, outside any git repo' ' check_config plain-aliased/.git false unset ' -test_expect_failure 'plain nested through aliased command' ' +test_expect_success 'plain nested through aliased command' ' ( git init plain-ancestor-aliased && cd plain-ancestor-aliased && @@ -68,7 +68,7 @@ test_expect_failure 'plain nested through aliased command' ' check_config plain-ancestor-aliased/plain-nested/.git false unset ' -test_expect_failure 'plain nested in bare through aliased command' ' +test_expect_success 'plain nested in bare through aliased command' ' ( git init --bare bare-ancestor-aliased.git && cd bare-ancestor-aliased.git && diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh index 5ef5ad3db4..39e55a13c8 100755 --- a/t/t0008-ignores.sh +++ b/t/t0008-ignores.sh @@ -816,12 +816,14 @@ test_expect_success NOT_MINGW,NOT_CYGWIN 'correct handling of backslashes' ' >"whitespace/trailing 5 \\ \\ " && >"whitespace/trailing 6 \\a\\" && >whitespace/untracked && - echo "whitespace/trailing 1 \\ " >ignore && - echo "whitespace/trailing 2 \\\\\\\\\\\\\\\\" >>ignore && - echo "whitespace/trailing 3 \\\\\\\\\\\\\\\\ " >>ignore && - echo "whitespace/trailing 4 \\\\\\\\\\\\ " >>ignore && - echo "whitespace/trailing 5 \\\\\\\\ \\\\\\\\\\\\ " >>ignore && - echo "whitespace/trailing 6 \\\\\\\\a\\\\\\\\" >>ignore && + sed -e "s/Z$//" >ignore <<-\EOF && + whitespace/trailing 1 \ Z + whitespace/trailing 2 \\\\Z + whitespace/trailing 3 \\\\ Z + whitespace/trailing 4 \\\ Z + whitespace/trailing 5 \\ \\\ Z + whitespace/trailing 6 \\a\\Z + EOF echo whitespace/untracked >expect && >err.expect && git ls-files -o -X ignore whitespace >actual 2>err && diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh index b92e6cb046..f890c54d13 100755 --- a/t/t0021-conversion.sh +++ b/t/t0021-conversion.sh @@ -190,8 +190,6 @@ test_expect_success 'required filter clean failure' ' test_must_fail git add test.fc ' -test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE - test_expect_success EXPENSIVE 'filter large file' ' git config filter.largefile.smudge cat && git config filter.largefile.clean cat && diff --git a/t/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh index b0e5694ebd..28102de1a0 100755 --- a/t/t0025-crlf-auto.sh +++ b/t/t0025-crlf-auto.sh @@ -36,7 +36,7 @@ test_expect_success 'default settings cause no changes' ' onediff=$(git diff one) && twodiff=$(git diff two) && threediff=$(git diff three) && - test -z "$onediff" -a -z "$twodiff" -a -z "$threediff" + test -z "$onediff" && test -z "$twodiff" && test -z "$threediff" ' test_expect_success 'crlf=true causes a CRLF file to be normalized' ' @@ -111,7 +111,7 @@ test_expect_success 'autocrlf=true does not normalize CRLF files' ' onediff=$(git diff one) && twodiff=$(git diff two) && threediff=$(git diff three) && - test -z "$onediff" -a -z "$twodiff" -a -z "$threediff" + test -z "$onediff" && test -z "$twodiff" && test -z "$threediff" ' test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' ' @@ -126,7 +126,7 @@ test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' ' onediff=$(git diff one) && twodiff=$(git diff two) && threediff=$(git diff three) && - test -z "$onediff" -a -n "$twodiff" -a -z "$threediff" + test -z "$onediff" && test -n "$twodiff" && test -z "$threediff" ' test_expect_success 'text=auto, autocrlf=true does not normalize binary files' ' diff --git a/t/t0026-eol-config.sh b/t/t0026-eol-config.sh index e1126aa7cc..4807b0f015 100755 --- a/t/t0026-eol-config.sh +++ b/t/t0026-eol-config.sh @@ -36,7 +36,7 @@ test_expect_success 'eol=lf puts LFs in normalized file' ' ! has_cr two && onediff=$(git diff one) && twodiff=$(git diff two) && - test -z "$onediff" -a -z "$twodiff" + test -z "$onediff" && test -z "$twodiff" ' test_expect_success 'eol=crlf puts CRLFs in normalized file' ' @@ -49,7 +49,7 @@ test_expect_success 'eol=crlf puts CRLFs in normalized file' ' ! has_cr two && onediff=$(git diff one) && twodiff=$(git diff two) && - test -z "$onediff" -a -z "$twodiff" + test -z "$onediff" && test -z "$twodiff" ' test_expect_success 'autocrlf=true overrides eol=lf' ' @@ -63,7 +63,7 @@ test_expect_success 'autocrlf=true overrides eol=lf' ' has_cr two && onediff=$(git diff one) && twodiff=$(git diff two) && - test -z "$onediff" -a -z "$twodiff" + test -z "$onediff" && test -z "$twodiff" ' test_expect_success 'autocrlf=true overrides unset eol' ' @@ -77,7 +77,7 @@ test_expect_success 'autocrlf=true overrides unset eol' ' has_cr two && onediff=$(git diff one) && twodiff=$(git diff two) && - test -z "$onediff" -a -z "$twodiff" + test -z "$onediff" && test -z "$twodiff" ' test_done diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh index 1a5a5f39fd..9aeb352b3d 100755 --- a/t/t1402-check-ref-format.sh +++ b/t/t1402-check-ref-format.sh @@ -64,6 +64,7 @@ valid_ref "$(printf 'heads/fu\303\237')" invalid_ref 'heads/*foo/bar' --refspec-pattern invalid_ref 'heads/foo*/bar' --refspec-pattern invalid_ref 'heads/f*o/bar' --refspec-pattern +invalid_ref 'heads/foo*//bar' --refspec-pattern ref='foo' invalid_ref "$ref" @@ -128,6 +129,20 @@ valid_ref NOT_MINGW "$ref" '--allow-onelevel --normalize' invalid_ref NOT_MINGW "$ref" '--refspec-pattern --normalize' valid_ref NOT_MINGW "$ref" '--refspec-pattern --allow-onelevel --normalize' + +valid_ref 'refs/heads/a-very-long-refname' +invalid_ref 'refs/heads/.a-very-long-refname' +invalid_ref 'refs/heads/abcdefgh0123..' +invalid_ref 'refs/heads/abcdefgh01234..' +invalid_ref 'refs/heads/abcdefgh012345..' +invalid_ref 'refs/heads/abcdefgh0123456..' +invalid_ref 'refs/heads/abcdefgh01234567..' +valid_ref 'refs/heads/abcdefgh0123.a' +valid_ref 'refs/heads/abcdefgh01234.a' +valid_ref 'refs/heads/abcdefgh012345.a' +valid_ref 'refs/heads/abcdefgh0123456.a' +valid_ref 'refs/heads/abcdefgh01234567.a' + test_expect_success "check-ref-format --branch @{-1}" ' T=$(git write-tree) && sha1=$(echo A | git commit-tree $T) && diff --git a/t/t3302-notes-index-expensive.sh b/t/t3302-notes-index-expensive.sh index e35d7811ac..8d44e04354 100755 --- a/t/t3302-notes-index-expensive.sh +++ b/t/t3302-notes-index-expensive.sh @@ -7,9 +7,7 @@ test_description='Test commit notes index (expensive!)' . ./test-lib.sh -test_set_prereq NOT_EXPENSIVE test -n "$GIT_NOTES_TIMING_TESTS" && test_set_prereq EXPENSIVE -test -x /usr/bin/time && test_set_prereq USR_BIN_TIME create_repo () { number_of_commits=$1 @@ -17,43 +15,43 @@ create_repo () { test -d .git || { git init && ( - while [ $nr -lt $number_of_commits ]; do + while test $nr -lt $number_of_commits + do nr=$(($nr+1)) mark=$(($nr+$nr)) notemark=$(($mark+1)) test_tick && - cat <<INPUT_END && -commit refs/heads/master -mark :$mark -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -commit #$nr -COMMIT - -M 644 inline file -data <<EOF -file in commit #$nr -EOF - -blob -mark :$notemark -data <<EOF -note for commit #$nr -EOF - -INPUT_END - - echo "N :$notemark :$mark" >> note_commit + cat <<-INPUT_END && + commit refs/heads/master + mark :$mark + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + commit #$nr + COMMIT + + M 644 inline file + data <<EOF + file in commit #$nr + EOF + + blob + mark :$notemark + data <<EOF + note for commit #$nr + EOF + + INPUT_END + echo "N :$notemark :$mark" >>note_commit done && test_tick && - cat <<INPUT_END && -commit refs/notes/commits -committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE -data <<COMMIT -notes -COMMIT + cat <<-INPUT_END && + commit refs/notes/commits + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + notes + COMMIT -INPUT_END + INPUT_END cat note_commit ) | @@ -65,62 +63,74 @@ INPUT_END test_notes () { count=$1 && git config core.notesRef refs/notes/commits && - git log | grep "^ " > output && + git log | grep "^ " >output && i=$count && - while [ $i -gt 0 ]; do + while test $i -gt 0 + do echo " commit #$i" && echo " note for commit #$i" && - i=$(($i-1)); - done > expect && + i=$(($i-1)) + done >expect && test_cmp expect output } -cat > time_notes << \EOF +write_script time_notes <<\EOF mode=$1 i=1 - while [ $i -lt $2 ]; do + while test $i -lt $2 + do case $1 in no-notes) - GIT_NOTES_REF=non-existing; export GIT_NOTES_REF - ;; + GIT_NOTES_REF=non-existing + export GIT_NOTES_REF + ;; notes) unset GIT_NOTES_REF - ;; + ;; esac - git log >/dev/null + git log i=$(($i+1)) - done + done >/dev/null EOF time_notes () { for mode in no-notes notes do echo $mode - /usr/bin/time "$SHELL_PATH" ../time_notes $mode $1 + /usr/bin/time ../time_notes $mode $1 done } do_tests () { - pr=$1 - count=$2 - - test_expect_success $pr 'setup / mkdir' ' - mkdir $count && - cd $count + count=$1 pr=${2-} + + test_expect_success $pr "setup $count" ' + mkdir "$count" && + ( + cd "$count" && + create_repo "$count" + ) ' - test_expect_success $pr "setup $count" "create_repo $count" - - test_expect_success $pr 'notes work' "test_notes $count" - - test_expect_success USR_BIN_TIME,$pr 'notes timing with /usr/bin/time' "time_notes 100" + test_expect_success $pr 'notes work' ' + ( + cd "$count" && + test_notes "$count" + ) + ' - test_expect_success $pr 'teardown / cd ..' 'cd ..' + test_expect_success "USR_BIN_TIME${pr:+,$pr}" 'notes timing with /usr/bin/time' ' + ( + cd "$count" && + time_notes 100 + ) + ' } -do_tests NOT_EXPENSIVE 10 -for count in 100 1000 10000; do - do_tests EXPENSIVE $count +do_tests 10 +for count in 100 1000 10000 +do + do_tests "$count" EXPENSIVE done test_done diff --git a/t/t3402-rebase-merge.sh b/t/t3402-rebase-merge.sh index be8c1d5ef9..5a27ec9b5e 100755 --- a/t/t3402-rebase-merge.sh +++ b/t/t3402-rebase-merge.sh @@ -33,6 +33,7 @@ test_expect_success setup ' tr "[a-z]" "[A-Z]" <original >newfile && git add newfile && git commit -a -m"side edits further." && + git branch second-side && tr "[a-m]" "[A-M]" <original >newfile && rm -f original && @@ -41,6 +42,7 @@ test_expect_success setup ' git branch test-rebase side && git branch test-rebase-pick side && git branch test-reference-pick side && + git branch test-conflicts side && git checkout -b test-merge side ' @@ -138,4 +140,17 @@ test_expect_success 'rebase -s funny -Xopt' ' test -f funny.was.run ' +test_expect_success 'rebase --skip works with two conflicts in a row' ' + git checkout second-side && + tr "[A-Z]" "[a-z]" <newfile >tmp && + mv tmp newfile && + git commit -a -m"edit conflicting with side" && + tr "[d-f]" "[D-F]" <newfile >tmp && + mv tmp newfile && + git commit -a -m"another edit conflicting with side" && + test_must_fail git rebase --merge test-conflicts && + test_must_fail git rebase --skip && + git rebase --skip +' + test_done diff --git a/t/t3419-rebase-patch-id.sh b/t/t3419-rebase-patch-id.sh index e70ac10a0c..9292b499f3 100755 --- a/t/t3419-rebase-patch-id.sh +++ b/t/t3419-rebase-patch-id.sh @@ -4,12 +4,9 @@ test_description='git rebase - test patch id computation' . ./test-lib.sh -test_set_prereq NOT_EXPENSIVE test -n "$GIT_PATCHID_TIMING_TESTS" && test_set_prereq EXPENSIVE -test -x /usr/bin/time && test_set_prereq USR_BIN_TIME -count() -{ +count () { i=0 while test $i -lt $1 do @@ -18,8 +15,7 @@ count() done } -scramble() -{ +scramble () { i=0 while read x do @@ -28,12 +24,11 @@ scramble() echo "$x" fi i=$((($i+1) % 10)) - done < "$1" > "$1.new" + done <"$1" >"$1.new" mv -f "$1.new" "$1" } -run() -{ +run () { echo \$ "$@" /usr/bin/time "$@" >/dev/null } @@ -43,10 +38,8 @@ test_expect_success 'setup' ' git tag root ' -do_tests() -{ - pr=$1 - nlines=$2 +do_tests () { + nlines=$1 pr=${2-} test_expect_success $pr "setup: $nlines lines" " rm -f .gitattributes && @@ -103,7 +96,7 @@ do_tests() " } -do_tests NOT_EXPENSIVE 500 -do_tests EXPENSIVE 50000 +do_tests 500 +do_tests 50000 EXPENSIVE test_done diff --git a/t/t4102-apply-rename.sh b/t/t4102-apply-rename.sh index 49e2d6c349..fae305979a 100755 --- a/t/t4102-apply-rename.sh +++ b/t/t4102-apply-rename.sh @@ -52,6 +52,6 @@ EOF test_expect_success 'apply copy' \ 'git apply --index --stat --summary --apply test-patch && - test "$(cat bar)" = "This is bar" -a "$(cat foo)" = "This is foo"' + test "$(cat bar)" = "This is bar" && test "$(cat foo)" = "This is foo"' test_done diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index bad84a36e8..899c1c5bbc 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -72,7 +72,7 @@ check_tar() { for header in *.paxheader do data=${header%.paxheader}.data && - if test -h $data -o -e $data + if test -h $data || test -e $data then path=$(get_pax_header $header path) && if test -n "$path" diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh index f4f02ba918..0580258c91 100755 --- a/t/t5310-pack-bitmaps.sh +++ b/t/t5310-pack-bitmaps.sh @@ -18,7 +18,7 @@ test_expect_success 'setup repo with moderate-sized history' ' git checkout master && blob=$(echo tagged-blob | git hash-object -w --stdin) && git tag tagged-blob $blob && - git config pack.writebitmaps true && + git config repack.writebitmaps true && git config pack.writebitmaphashcache true ' diff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh index 1753ef2b91..fc898c9eac 100755 --- a/t/t5403-post-checkout-hook.sh +++ b/t/t5403-post-checkout-hook.sh @@ -39,7 +39,7 @@ test_expect_success 'post-checkout receives the right arguments with HEAD unchan old=$(awk "{print \$1}" clone1/.git/post-checkout.args) && new=$(awk "{print \$2}" clone1/.git/post-checkout.args) && flag=$(awk "{print \$3}" clone1/.git/post-checkout.args) && - test $old = $new -a $flag = 1 + test $old = $new && test $flag = 1 ' test_expect_success 'post-checkout runs as expected ' ' @@ -52,7 +52,7 @@ test_expect_success 'post-checkout args are correct with git checkout -b ' ' old=$(awk "{print \$1}" clone1/.git/post-checkout.args) && new=$(awk "{print \$2}" clone1/.git/post-checkout.args) && flag=$(awk "{print \$3}" clone1/.git/post-checkout.args) && - test $old = $new -a $flag = 1 + test $old = $new && test $flag = 1 ' test_expect_success 'post-checkout receives the right args with HEAD changed ' ' @@ -60,7 +60,7 @@ test_expect_success 'post-checkout receives the right args with HEAD changed ' ' old=$(awk "{print \$1}" clone2/.git/post-checkout.args) && new=$(awk "{print \$2}" clone2/.git/post-checkout.args) && flag=$(awk "{print \$3}" clone2/.git/post-checkout.args) && - test $old != $new -a $flag = 1 + test $old != $new && test $flag = 1 ' test_expect_success 'post-checkout receives the right args when not switching branches ' ' @@ -68,7 +68,7 @@ test_expect_success 'post-checkout receives the right args when not switching br old=$(awk "{print \$1}" clone2/.git/post-checkout.args) && new=$(awk "{print \$2}" clone2/.git/post-checkout.args) && flag=$(awk "{print \$3}" clone2/.git/post-checkout.args) && - test $old = $new -a $flag = 0 + test $old = $new && test $flag = 0 ' if test "$(git config --bool core.filemode)" = true; then diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 29d59ef9fa..d78f3201f4 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -447,6 +447,43 @@ test_expect_success 'explicit pull should update tracking' ' ) ' +test_expect_success 'explicit --refmap is allowed only with command-line refspec' ' + cd "$D" && + ( + cd three && + test_must_fail git fetch --refmap="*:refs/remotes/none/*" + ) +' + +test_expect_success 'explicit --refmap option overrides remote.*.fetch' ' + cd "$D" && + git branch -f side && + ( + cd three && + git update-ref refs/remotes/origin/master base-origin-master && + o=$(git rev-parse --verify refs/remotes/origin/master) && + git fetch --refmap="refs/heads/*:refs/remotes/other/*" origin master && + n=$(git rev-parse --verify refs/remotes/origin/master) && + test "$o" = "$n" && + test_must_fail git rev-parse --verify refs/remotes/origin/side && + git rev-parse --verify refs/remotes/other/master + ) +' + +test_expect_success 'explicitly empty --refmap option disables remote.*.fetch' ' + cd "$D" && + git branch -f side && + ( + cd three && + git update-ref refs/remotes/origin/master base-origin-master && + o=$(git rev-parse --verify refs/remotes/origin/master) && + git fetch --refmap="" origin master && + n=$(git rev-parse --verify refs/remotes/origin/master) && + test "$o" = "$n" && + test_must_fail git rev-parse --verify refs/remotes/origin/side + ) +' + test_expect_success 'configured fetch updates tracking' ' cd "$D" && diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh index 01b8aae2ed..ac71418a1b 100755 --- a/t/t5550-http-fetch-dumb.sh +++ b/t/t5550-http-fetch-dumb.sh @@ -191,5 +191,10 @@ test_expect_success 'http error messages are reencoded' ' grep "this is the error message" stderr ' +test_expect_success 'reencoding is robust to whitespace oddities' ' + test_must_fail git clone "$HTTPD_URL/error/odd-spacing" 2>stderr && + grep "this is the error message" stderr +' + stop_httpd test_done diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh index e07eaf35f1..6cbc12d9a7 100755 --- a/t/t5551-http-fetch-smart.sh +++ b/t/t5551-http-fetch-smart.sh @@ -213,8 +213,6 @@ test_expect_success 'cookies stored in http.cookiefile when http.savecookies set test_cmp expect_cookies.txt cookies_tail.txt ' -test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE - test_expect_success EXPENSIVE 'create 50,000 tags in the repo' ' ( cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && @@ -240,8 +238,7 @@ test_expect_success EXPENSIVE 'create 50,000 tags in the repo' ' ' test_expect_success EXPENSIVE 'clone the 50,000 tag repo to check OS command line overflow' ' - git clone $HTTPD_URL/smart/repo.git too-many-refs 2>err && - test_line_count = 0 err && + git clone $HTTPD_URL/smart/repo.git too-many-refs && ( cd too-many-refs && test $(git for-each-ref refs/tags | wc -l) = 50000 diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index 74de814aec..04118ad75b 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -426,10 +426,10 @@ test_expect_success SANITY 'removal failure' ' mkdir foo && touch foo/bar && + test_when_finished "chmod 755 foo" && (exec <foo/bar && chmod 0 foo && - test_must_fail git clean -f -d && - chmod 755 foo) + test_must_fail git clean -f -d) ' test_expect_success 'nested git work tree' ' diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh index 284018e3cd..021c5479bd 100755 --- a/t/t7700-repack.sh +++ b/t/t7700-repack.sh @@ -21,7 +21,7 @@ test_expect_success 'objects in packs marked .keep are not repacked' ' objsha1=$(git verify-pack -v pack-$packsha1.idx | head -n 1 | sed -e "s/^\([0-9a-f]\{40\}\).*/\1/") && mv pack-* .git/objects/pack/ && - git repack --no-pack-kept-objects -A -d -l && + git repack -A -d -l && git prune-packed && for p in .git/objects/pack/*.idx; do idx=$(basename $p) @@ -35,9 +35,25 @@ test_expect_success 'objects in packs marked .keep are not repacked' ' test -z "$found_duplicate_object" ' -test_expect_success 'writing bitmaps can duplicate .keep objects' ' +test_expect_success 'writing bitmaps via command-line can duplicate .keep objects' ' # build on $objsha1, $packsha1, and .keep state from previous - git repack -Adl && + git repack -Adbl && + test_when_finished "found_duplicate_object=" && + for p in .git/objects/pack/*.idx; do + idx=$(basename $p) + test "pack-$packsha1.idx" = "$idx" && continue + if git verify-pack -v $p | egrep "^$objsha1"; then + found_duplicate_object=1 + echo "DUPLICATE OBJECT FOUND" + break + fi + done && + test "$found_duplicate_object" = 1 +' + +test_expect_success 'writing bitmaps via config can duplicate .keep objects' ' + # build on $objsha1, $packsha1, and .keep state from previous + git -c repack.writebitmaps=true repack -Adl && test_when_finished "found_duplicate_object=" && for p in .git/objects/pack/*.idx; do idx=$(basename $p) diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 1ecdacb6fd..19a3ced600 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -1334,6 +1334,51 @@ test_expect_success $PREREQ '--force sends cover letter template anyway' ' test -n "$(ls msgtxt*)" ' +test_cover_addresses () { + header="$1" + shift + clean_fake_sendmail && + rm -fr outdir && + git format-patch --cover-letter -2 -o outdir && + cover=`echo outdir/0000-*.patch` && + mv $cover cover-to-edit.patch && + perl -pe "s/^From:/$header: extra\@address.com\nFrom:/" cover-to-edit.patch >"$cover" && + git send-email \ + --force \ + --from="Example <nobody@example.com>" \ + --no-to --no-cc \ + "$@" \ + --smtp-server="$(pwd)/fake.sendmail" \ + outdir/0000-*.patch \ + outdir/0001-*.patch \ + outdir/0002-*.patch \ + 2>errors >out && + grep "^$header: extra@address.com" msgtxt1 >to1 && + grep "^$header: extra@address.com" msgtxt2 >to2 && + grep "^$header: extra@address.com" msgtxt3 >to3 && + test_line_count = 1 to1 && + test_line_count = 1 to2 && + test_line_count = 1 to3 +} + +test_expect_success $PREREQ 'to-cover adds To to all mail' ' + test_cover_addresses "To" --to-cover +' + +test_expect_success $PREREQ 'cc-cover adds Cc to all mail' ' + test_cover_addresses "Cc" --cc-cover +' + +test_expect_success $PREREQ 'tocover adds To to all mail' ' + test_config sendemail.tocover true && + test_cover_addresses "To" +' + +test_expect_success $PREREQ 'cccover adds Cc to all mail' ' + test_config sendemail.cccover true && + test_cover_addresses "Cc" +' + test_expect_success $PREREQ 'sendemail.aliasfiletype=mailrc' ' clean_fake_sendmail && echo "alias sbd somebody@example.org" >.mailrc && diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh index be802e0e16..1fc1f5f2af 100755 --- a/t/t9814-git-p4-rename.sh +++ b/t/t9814-git-p4-rename.sh @@ -177,7 +177,7 @@ test_expect_success 'detect copies' ' level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") && test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 && src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && - test "$src" = file10 -o "$src" = file11 && + test "$src" = file10 || test "$src" = file11 && git config git-p4.detectCopies $(($level + 2)) && git p4 submit && p4 filelog //depot/file12 && @@ -191,7 +191,7 @@ test_expect_success 'detect copies' ' level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") && test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 && src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && - test "$src" = file10 -o "$src" = file11 -o "$src" = file12 && + test "$src" = file10 || test "$src" = file11 || test "$src" = file12 && git config git-p4.detectCopies $(($level - 2)) && git p4 submit && p4 filelog //depot/file13 && diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 2d4beb5e50..1d1c1063a3 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -550,6 +550,33 @@ test_expect_success 'complete files' ' test_completion "git add mom" "momified" ' +test_expect_success "completion uses <cmd> completion for alias: !sh -c 'git <cmd> ...'" ' + test_config alias.co "!sh -c '"'"'git checkout ...'"'"'" && + test_completion "git co m" <<-\EOF + master Z + mybranch Z + mytag Z + EOF +' + +test_expect_success 'completion uses <cmd> completion for alias: !f () { VAR=val git <cmd> ... }' ' + test_config alias.co "!f () { VAR=val git checkout ... ; } f" && + test_completion "git co m" <<-\EOF + master Z + mybranch Z + mytag Z + EOF +' + +test_expect_success 'completion used <cmd> completion for alias: !f() { : git <cmd> ; ... }' ' + test_config alias.co "!f() { : git checkout ; if ... } f" && + test_completion "git co m" <<-\EOF + master Z + mybranch Z + mytag Z + EOF +' + test_expect_failure 'complete with tilde expansion' ' git init tmp && cd tmp && test_when_finished "cd .. && rm -rf tmp" && diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index c617c826db..0377d3e296 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -542,7 +542,7 @@ test_must_fail () { if test $exit_code = 0; then echo >&2 "test_must_fail: command succeeded: $*" return 1 - elif test $exit_code -gt 129 -a $exit_code -le 192; then + elif test $exit_code -gt 129 && test $exit_code -le 192; then echo >&2 "test_must_fail: died by signal: $*" return 1 elif test $exit_code = 127; then @@ -569,7 +569,7 @@ test_must_fail () { test_might_fail () { "$@" exit_code=$? - if test $exit_code -gt 129 -a $exit_code -le 192; then + if test $exit_code -gt 129 && test $exit_code -le 192; then echo >&2 "test_might_fail: died by signal: $*" return 1 elif test $exit_code = 127; then diff --git a/t/test-lib.sh b/t/test-lib.sh index 81394c8c7c..a4795373a6 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -976,6 +976,14 @@ test_lazy_prereq AUTOIDENT ' git var GIT_AUTHOR_IDENT ' +test_lazy_prereq EXPENSIVE ' + test -n "$GIT_TEST_LONG" +' + +test_lazy_prereq USR_BIN_TIME ' + test -x /usr/bin/time +' + # When the tests are run as root, permission tests will report that # things are writable when they shouldn't be. test -w / || test_set_prereq SANITY diff --git a/t/valgrind/default.supp b/t/valgrind/default.supp index 0a6724fcc4..332ab1a3b3 100644 --- a/t/valgrind/default.supp +++ b/t/valgrind/default.supp @@ -49,3 +49,11 @@ Memcheck:Addr4 fun:copy_ref } +{ + ignore-sse-check_refname_format + Memcheck:Addr8 + fun:check_refname_format + fun:cmd_check_ref_format + fun:handle_builtin + fun:main +} diff --git a/transport-helper.c b/transport-helper.c index 84c616f180..3d8fe7d801 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -153,7 +153,7 @@ static struct child_process *get_helper(struct transport *transport) write_constant(helper->in, "capabilities\n"); while (1) { - const char *capname; + const char *capname, *arg; int mandatory = 0; if (recvline(data, &buf)) exit(128); @@ -183,19 +183,19 @@ static struct child_process *get_helper(struct transport *transport) data->export = 1; else if (!strcmp(capname, "check-connectivity")) data->check_connectivity = 1; - else if (!data->refspecs && starts_with(capname, "refspec ")) { + else if (!data->refspecs && skip_prefix(capname, "refspec ", &arg)) { ALLOC_GROW(refspecs, refspec_nr + 1, refspec_alloc); - refspecs[refspec_nr++] = xstrdup(capname + strlen("refspec ")); + refspecs[refspec_nr++] = xstrdup(arg); } else if (!strcmp(capname, "connect")) { data->connect = 1; } else if (!strcmp(capname, "signed-tags")) { data->signed_tags = 1; - } else if (starts_with(capname, "export-marks ")) { - data->export_marks = xstrdup(capname + strlen("export-marks ")); - } else if (starts_with(capname, "import-marks")) { - data->import_marks = xstrdup(capname + strlen("import-marks ")); + } else if (skip_prefix(capname, "export-marks ", &arg)) { + data->export_marks = xstrdup(arg); + } else if (skip_prefix(capname, "import-marks ", &arg)) { + data->import_marks = xstrdup(arg); } else if (starts_with(capname, "no-private-update")) { data->no_private_update = 1; } else if (mandatory) { diff --git a/transport.c b/transport.c index 325f03e1ee..59c9727d8d 100644 --- a/transport.c +++ b/transport.c @@ -192,7 +192,9 @@ static void set_upstreams(struct transport *transport, struct ref *refs, static const char *rsync_url(const char *url) { - return !starts_with(url, "rsync://") ? skip_prefix(url, "rsync:") : url; + if (!starts_with(url, "rsync://")) + skip_prefix(url, "rsync:", &url); + return url; } static struct ref *get_refs_via_rsync(struct transport *transport, int for_push) diff --git a/tree-walk.c b/tree-walk.c index 4dc86c7fe5..5dd9a71804 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -144,16 +144,6 @@ struct tree_desc_x { struct tree_desc_skip *skip; }; -static int name_compare(const char *a, int a_len, - const char *b, int b_len) -{ - int len = (a_len < b_len) ? a_len : b_len; - int cmp = memcmp(a, b, len); - if (cmp) - return cmp; - return (a_len - b_len); -} - static int check_entry_match(const char *a, int a_len, const char *b, int b_len) { /* diff --git a/unicode_width.h b/unicode_width.h index 4db78038e4..47cdd2369d 100644 --- a/unicode_width.h +++ b/unicode_width.h @@ -6,7 +6,7 @@ static const struct interval zero_width[] = { { 0x05C1, 0x05C2 }, { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, -{ 0x0600, 0x0604 }, +{ 0x0600, 0x0605 }, { 0x0610, 0x061A }, { 0x061C, 0x061C }, { 0x064B, 0x065F }, @@ -25,8 +25,7 @@ static const struct interval zero_width[] = { { 0x0825, 0x0827 }, { 0x0829, 0x082D }, { 0x0859, 0x085B }, -{ 0x08E4, 0x08FE }, -{ 0x0900, 0x0902 }, +{ 0x08E4, 0x0902 }, { 0x093A, 0x093A }, { 0x093C, 0x093C }, { 0x0941, 0x0948 }, @@ -62,16 +61,19 @@ static const struct interval zero_width[] = { { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, +{ 0x0C00, 0x0C00 }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0C62, 0x0C63 }, +{ 0x0C81, 0x0C81 }, { 0x0CBC, 0x0CBC }, { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, { 0x0CE2, 0x0CE3 }, +{ 0x0D01, 0x0D01 }, { 0x0D41, 0x0D44 }, { 0x0D4D, 0x0D4D }, { 0x0D62, 0x0D63 }, @@ -132,6 +134,7 @@ static const struct interval zero_width[] = { { 0x1A65, 0x1A6C }, { 0x1A73, 0x1A7C }, { 0x1A7F, 0x1A7F }, +{ 0x1AB0, 0x1ABE }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 }, { 0x1B36, 0x1B3A }, @@ -141,7 +144,7 @@ static const struct interval zero_width[] = { { 0x1B80, 0x1B81 }, { 0x1BA2, 0x1BA5 }, { 0x1BA8, 0x1BA9 }, -{ 0x1BAB, 0x1BAB }, +{ 0x1BAB, 0x1BAD }, { 0x1BE6, 0x1BE6 }, { 0x1BE8, 0x1BE9 }, { 0x1BED, 0x1BED }, @@ -153,7 +156,8 @@ static const struct interval zero_width[] = { { 0x1CE2, 0x1CE8 }, { 0x1CED, 0x1CED }, { 0x1CF4, 0x1CF4 }, -{ 0x1DC0, 0x1DE6 }, +{ 0x1CF8, 0x1CF9 }, +{ 0x1DC0, 0x1DF5 }, { 0x1DFC, 0x1DFF }, { 0x200B, 0x200F }, { 0x202A, 0x202E }, @@ -181,11 +185,13 @@ static const struct interval zero_width[] = { { 0xA9B3, 0xA9B3 }, { 0xA9B6, 0xA9B9 }, { 0xA9BC, 0xA9BC }, +{ 0xA9E5, 0xA9E5 }, { 0xAA29, 0xAA2E }, { 0xAA31, 0xAA32 }, { 0xAA35, 0xAA36 }, { 0xAA43, 0xAA43 }, { 0xAA4C, 0xAA4C }, +{ 0xAA7C, 0xAA7C }, { 0xAAB0, 0xAAB0 }, { 0xAAB2, 0xAAB4 }, { 0xAAB7, 0xAAB8 }, @@ -198,36 +204,65 @@ static const struct interval zero_width[] = { { 0xABED, 0xABED }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, -{ 0xFE20, 0xFE26 }, +{ 0xFE20, 0xFE2D }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }, { 0x101FD, 0x101FD }, +{ 0x102E0, 0x102E0 }, +{ 0x10376, 0x1037A }, { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F }, { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, +{ 0x10AE5, 0x10AE6 }, { 0x11001, 0x11001 }, { 0x11038, 0x11046 }, -{ 0x11080, 0x11081 }, +{ 0x1107F, 0x11081 }, { 0x110B3, 0x110B6 }, { 0x110B9, 0x110BA }, { 0x110BD, 0x110BD }, { 0x11100, 0x11102 }, { 0x11127, 0x1112B }, { 0x1112D, 0x11134 }, +{ 0x11173, 0x11173 }, { 0x11180, 0x11181 }, { 0x111B6, 0x111BE }, +{ 0x1122F, 0x11231 }, +{ 0x11234, 0x11234 }, +{ 0x11236, 0x11237 }, +{ 0x112DF, 0x112DF }, +{ 0x112E3, 0x112EA }, +{ 0x11301, 0x11301 }, +{ 0x1133C, 0x1133C }, +{ 0x11340, 0x11340 }, +{ 0x11366, 0x1136C }, +{ 0x11370, 0x11374 }, +{ 0x114B3, 0x114B8 }, +{ 0x114BA, 0x114BA }, +{ 0x114BF, 0x114C0 }, +{ 0x114C2, 0x114C3 }, +{ 0x115B2, 0x115B5 }, +{ 0x115BC, 0x115BD }, +{ 0x115BF, 0x115C0 }, +{ 0x11633, 0x1163A }, +{ 0x1163D, 0x1163D }, +{ 0x1163F, 0x11640 }, { 0x116AB, 0x116AB }, { 0x116AD, 0x116AD }, { 0x116B0, 0x116B5 }, { 0x116B7, 0x116B7 }, +{ 0x16AF0, 0x16AF4 }, +{ 0x16B30, 0x16B36 }, { 0x16F8F, 0x16F92 }, +{ 0x1BC9D, 0x1BC9E }, +{ 0x1BCA0, 0x1BCA3 }, { 0x1D167, 0x1D169 }, { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD }, { 0x1D242, 0x1D244 }, +{ 0x1E8D0, 0x1E8D6 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F }, { 0xE0100, 0xE01EF } diff --git a/unpack-trees.c b/unpack-trees.c index c237370b1f..0ac39e93a0 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -617,17 +617,6 @@ static int unpack_failed(struct unpack_trees_options *o, const char *message) return -1; } -/* NEEDSWORK: give this a better name and share with tree-walk.c */ -static int name_compare(const char *a, int a_len, - const char *b, int b_len) -{ - int len = (a_len < b_len) ? a_len : b_len; - int cmp = memcmp(a, b, len); - if (cmp) - return cmp; - return (a_len - b_len); -} - /* * The tree traversal is looking at name p. If we have a matching entry, * return it. If name p is a directory in the index, do not return diff --git a/urlmatch.c b/urlmatch.c index ec87cba750..3d4c54b5cd 100644 --- a/urlmatch.c +++ b/urlmatch.c @@ -483,8 +483,7 @@ int urlmatch_config_entry(const char *var, const char *value, void *cb) int user_matched = 0; int retval; - key = skip_prefix(var, collect->section); - if (!key || *(key++) != '.') { + if (!skip_prefix(var, collect->section, &key) || *(key++) != '.') { if (collect->cascade_fn) return collect->cascade_fn(var, value, cb); return 0; /* not interested */ |