diff options
122 files changed, 3786 insertions, 377 deletions
diff --git a/Documentation/Makefile b/Documentation/Makefile index 7a8037f586..06b0c57b95 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -84,7 +84,7 @@ endif # ifdef ASCIIDOC8 -ASCIIDOC_EXTRA += -a asciidoc7compatible +ASCIIDOC_EXTRA += -a asciidoc7compatible -a no-inline-literal endif ifdef DOCBOOK_XSL_172 ASCIIDOC_EXTRA += -a git-asciidoc-no-roff diff --git a/Documentation/RelNotes-1.6.3.4.txt b/Documentation/RelNotes-1.6.3.4.txt new file mode 100644 index 0000000000..cad461bc76 --- /dev/null +++ b/Documentation/RelNotes-1.6.3.4.txt @@ -0,0 +1,36 @@ +GIT v1.6.3.4 Release Notes +========================== + +Fixes since v1.6.3.3 +-------------------- + + * "git add --no-ignore-errors" did not override configured + add.ignore-errors configuration. + + * "git apply --whitespace=fix" did not fix trailing whitespace on an + incomplete line. + + * "git branch" opened too many commit objects unnecessarily. + + * "git checkout -f $commit" with a path that is a file (or a symlink) in + the work tree to a commit that has a directory at the path issued an + unnecessary error message. + + * "git diff -c/--cc" was very inefficient in coalescing the removed lines + shared between parents. + + * "git diff -c/--cc" showed removed lines at the beginning of a file + incorrectly. + + * "git remote show nickname" did not honor configured + remote.nickname.uploadpack when inspecting the branches at the remote. + + * "git request-pull" when talking to the terminal for a preview + showed some of the output in the pager. + + * "git request-pull start nickname [end]" did not honor configured + remote.nickname.uploadpack when it ran git-ls-remote against the remote + repository to learn the current tip of branches. + +Includes other documentation updates and minor fixes. + diff --git a/Documentation/RelNotes-1.6.4.txt b/Documentation/RelNotes-1.6.4.txt index af68297af5..7a904419f7 100644 --- a/Documentation/RelNotes-1.6.4.txt +++ b/Documentation/RelNotes-1.6.4.txt @@ -22,13 +22,6 @@ branch pointed at by its HEAD, gets a large warning. You can choose what should happen upon such a push by setting the configuration variable receive.denyDeleteCurrent in the receiving repository. -When the user does not tell "git push" what to push, it has always -pushed matching refs. For some people it is unexpected, and a new -configuration variable push.default has been introduced to allow -changing a different default behaviour. To advertise the new feature, -a big warning is issued if this is not configured and a git push without -arguments is attempted. - Updates since v1.6.3 -------------------- @@ -38,26 +31,67 @@ Updates since v1.6.3 * gitweb Perl style clean-up. * git-svn updates, including a new --authors-prog option to map author - names by invoking an external program. + names by invoking an external program, 'git svn reset' to unwind + 'git svn fetch', support for more than one branches, documenting + of the useful --minimize-url feature, new "git svn gc" command, etc. (portability) * We feed iconv with "UTF-8" instead of "utf8"; the former is - understood more widely. + understood more widely. Similarly updated test scripts to use + encoding names more widely understood (e.g. use "ISO8859-1" instead + of "ISO-8859-1"). + + * Various portability fixes/workarounds for different vintages of + SunOS, IRIX, and Windows. + + * Git-over-ssh transport on Windows supports PuTTY plink and TortoisePlink. (performance) + * Many repeated use of lstat() are optimized out in "checkout" codepath. + + * git-status (and underlying git-diff-index --cached) are optimized + to take advantage of cache-tree information in the index. + (usability, bells and whistles) * "git add --edit" lets users edit the whole patch text to fine-tune what is added to the index. - * "git log --graph" draws graphs more compactly by using horizonal lines + * "git am" accepts StGIT series file as its input. + + * "git bisect skip" skips to a more randomly chosen place in the hope + to avoid testing a commit that is too close to a commit that is + already known to be untestable. + + * "git cvsexportcommit" learned -k option to stop CVS keywords expansion + + * "git fast-export" learned to handle history simplification more + gracefully. + + * "git fast-export" learned an option --tag-of-filtered-object to handle + dangling tags resulting from history simplification more usefully. + + * "git grep" learned -p option to show the location of the match using the + same context hunk marker "git diff" uses. + + * https transport can optionally be told that the used client + certificate is password protected, in which case it asks the + password only once. + + * "git imap-send" is IPv6 aware. + + * "git log --graph" draws graphs more compactly by using horizontal lines when able. * "git log --decorate" shows shorter refnames by stripping well-known refs/* prefix. + * "git push $name" honors remote.$name.pushurl if present before + using remote.$name.url. In other words, the URL used for fetching + and pushing can be different. + * "git send-email" understands quoted aliases in .mailrc files (might have to be backported to 1.6.3.X). @@ -69,10 +103,17 @@ Updates since v1.6.3 * "add" and "update" subcommands to "git submodule" learned --reference option to use local clone with references. + * "git submodule update" learned --rebase option to update checked + out submodules by rebasing the local changes. + + * "gitweb" can optionally use gravatar to adorn author/committer names. + (developers) * A major part of the "git bisect" wrapper has moved to C. + * Formatting with the new version of AsciiDoc 8.4.1 is now supported. + Fixes since v1.6.3 ------------------ @@ -82,12 +123,25 @@ release, unless otherwise noted. Here are fixes that this release has, but have not been backported to v1.6.3.X series. + * "git diff-tree -r -t" used to omit new or removed directories from + the output. df533f3 (diff-tree -r -t: include added/removed + directories in the output, 2009-06-13) may need to be cherry-picked + to backport this fix. + * The way Git.pm sets up a Repository object was not friendly to callers that chdir around. It now internally records the repository location as an absolute path when autodetected. ---- -exec >/var/tmp/1 -echo O=$(git describe master) -O=v1.6.3.1-168-g23807fa -git shortlog --no-merges $O..master ^maint + * Removing a section with "git config --remove-section", when its + section header has a variable definition on the same line, lost + that variable definition. + + * "git rebase -p --onto" used to always leave side branches of a merge + intact, even when both branches are subject to rewriting. + + * "git repack" used to faithfully follow grafts and considered true + parents recorded in the commit object unreachable from the commit. + After such a repacking, you cannot remove grafts without corrupting + the repository. + + * "git send-email" did not detect erroneous loops in alias expansion. diff --git a/Documentation/RelNotes-1.6.5.txt b/Documentation/RelNotes-1.6.5.txt new file mode 100644 index 0000000000..856047d16f --- /dev/null +++ b/Documentation/RelNotes-1.6.5.txt @@ -0,0 +1,51 @@ +GIT v1.6.5 Release Notes +======================== + +In git 1.7.0, which is planned to be the release after 1.6.5, "git push" +into a branch that is currently checked out will be refused by default. + +You can choose what should happen upon such a push by setting the +configuration variable receive.denyCurrentBranch in the receiving +repository. + +Also, "git push $there :$killed" to delete the branch $killed in a remote +repository $there, when $killed branch is the current branch pointed at by +its HEAD, will be refused by default. + +You can choose what should happen upon such a push by setting the +configuration variable receive.denyDeleteCurrent in the receiving +repository. + +To ease the transition plan, the receiving repository of such a +push running this release will issue a big warning when the +configuration variable is missing. Please refer to: + + http://git.or.cz/gitwiki/GitFaq#non-bare + http://thread.gmane.org/gmane.comp.version-control.git/107758/focus=108007 + +for more details on the reason why this change is needed and the +transition plan. + +Updates since v1.6.4 +-------------------- + +(subsystems) + +(portability) + +(performance) + +(usability, bells and whistles) + +(developers) + +Fixes since v1.6.4 +------------------ + +# All of the fixes in v1.6.4.X maintenance series are included in this +# release, unless otherwise noted. + +# Here are fixes that this release has, but have not been backported to +# v1.6.4.X series. + + diff --git a/Documentation/config.txt b/Documentation/config.txt index cb6832b4e8..c6f09f801a 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -49,7 +49,8 @@ There is also a case insensitive alternative `[section.subsection]` syntax. In this syntax, subsection names follow the same restrictions as for section names. -All the other lines are recognized as setting variables, in the form +All the other lines (and the remainder of the line after the section +header) are recognized as setting variables, in the form 'name = value'. If there is no equal sign on the line, the entire line is taken as 'name' and the variable is recognized as boolean "true". The variable names are case-insensitive and only alphanumeric @@ -1387,6 +1388,50 @@ rerere.enabled:: default enabled if you create `rr-cache` directory under `$GIT_DIR`, but can be disabled by setting this option to false. +sendemail.identity:: + A configuration identity. When given, causes values in the + 'sendemail.<identity>' subsection to take precedence over + values in the 'sendemail' section. The default identity is + the value of 'sendemail.identity'. + +sendemail.smtpencryption:: + See linkgit:git-send-email[1] for description. Note that this + setting is not subject to the 'identity' mechanism. + +sendemail.smtpssl:: + Deprecated alias for 'sendemail.smtpencryption = ssl'. + +sendemail.<identity>.*:: + Identity-specific versions of the 'sendemail.*' parameters + found below, taking precedence over those when the this + identity is selected, through command-line or + 'sendemail.identity'. + +sendemail.aliasesfile:: +sendemail.aliasfiletype:: +sendemail.bcc:: +sendemail.cc:: +sendemail.cccmd:: +sendemail.chainreplyto:: +sendemail.confirm:: +sendemail.envelopesender:: +sendemail.from:: +sendemail.multiedit:: +sendemail.signedoffbycc:: +sendemail.smtppass:: +sendemail.suppresscc:: +sendemail.suppressfrom:: +sendemail.to:: +sendemail.smtpserver:: +sendemail.smtpserverport:: +sendemail.smtpuser:: +sendemail.thread:: +sendemail.validate:: + See linkgit:git-send-email[1] for description. + +sendemail.signedoffcc:: + Deprecated alias for 'sendemail.signedoffbycc'. + showbranch.default:: The default set of branches for linkgit:git-show-branch[1]. See linkgit:git-show-branch[1]. diff --git a/Documentation/diff-format.txt b/Documentation/diff-format.txt index 1eeb1c7683..b71712473e 100644 --- a/Documentation/diff-format.txt +++ b/Documentation/diff-format.txt @@ -1,4 +1,7 @@ -The output format from "git-diff-index", "git-diff-tree", +Raw output format +----------------- + +The raw output format from "git-diff-index", "git-diff-tree", "git-diff-files" and "git diff --raw" are very similar. These commands all compare two sets of things; what is @@ -16,6 +19,9 @@ git-diff-tree [-r] <tree-ish-1> <tree-ish-2> [<pattern>...]:: git-diff-files [<pattern>...]:: compares the index and the files on the filesystem. +The "git-diff-tree" command begins its ouput by printing the hash of +what is being compared. After that, all the commands print one output +line per changed file. An output line is formatted this way: diff --git a/Documentation/git-diff-files.txt b/Documentation/git-diff-files.txt index c526141564..4ef03578eb 100644 --- a/Documentation/git-diff-files.txt +++ b/Documentation/git-diff-files.txt @@ -43,8 +43,7 @@ omit diff output for unmerged entries and just show "Unmerged". -q:: Remain silent even on nonexistent files -Output format -------------- + include::diff-format.txt[] diff --git a/Documentation/git-diff-index.txt b/Documentation/git-diff-index.txt index 26920d4f63..8b9ed29299 100644 --- a/Documentation/git-diff-index.txt +++ b/Documentation/git-diff-index.txt @@ -34,8 +34,6 @@ include::diff-options.txt[] 'git-diff-index' say that all non-checked-out files are up to date. -Output format -------------- include::diff-format.txt[] Operating Modes diff --git a/Documentation/git-diff-tree.txt b/Documentation/git-diff-tree.txt index 23b7abd3c6..f2cef1260b 100644 --- a/Documentation/git-diff-tree.txt +++ b/Documentation/git-diff-tree.txt @@ -159,8 +159,7 @@ HEAD commits it finds, which is even more interesting. in case you care). -Output format -------------- + include::diff-format.txt[] diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt index a2f192fb75..0ac711230e 100644 --- a/Documentation/git-diff.txt +++ b/Documentation/git-diff.txt @@ -84,8 +84,7 @@ include::diff-options.txt[] the diff to the named paths (you can give directory names and get diff for all files under them). -Output format -------------- + include::diff-format.txt[] EXAMPLES diff --git a/Documentation/git-fast-export.txt b/Documentation/git-fast-export.txt index 0c9eb567cb..75b06f33e7 100644 --- a/Documentation/git-fast-export.txt +++ b/Documentation/git-fast-export.txt @@ -36,6 +36,17 @@ when encountering a signed tag. With 'strip', the tags will be made unsigned, with 'verbatim', they will be silently exported and with 'warn', they will be exported, but you will see a warning. +--tag-of-filtered-object=(abort|drop|rewrite):: + Specify how to handle tags whose tagged objectis filtered out. + Since revisions and files to export can be limited by path, + tagged objects may be filtered completely. ++ +When asking to 'abort' (which is the default), this program will die +when encountering such a tag. With 'drop' it will omit such tags from +the output. With 'rewrite', if the tagged object is a commit, it will +rewrite the tag to tag an ancestor commit (via parent rewriting; see +linkgit:git-rev-list[1]) + -M:: -C:: Perform move and/or copy detection, as described in the @@ -71,6 +82,20 @@ marks the same across runs. allow that. So fake a tagger to be able to fast-import the output. +--no-data:: + Skip output of blob objects and instead refer to blobs via + their original SHA-1 hash. This is useful when rewriting the + directory structure or history of a repository without + touching the contents of individual files. Note that the + resulting stream can only be used by a repository which + already contains the necessary objects. + +[git-rev-list-args...]:: + A list of arguments, acceptable to 'git-rev-parse' and + 'git-rev-list', that specifies the specific objects and references + to export. For example, `master\~10..master` causes the + current master reference to be exported along with all objects + added since its 10th ancestor commit. EXAMPLES -------- diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index 6f1fc80119..687e667598 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -10,7 +10,7 @@ SYNOPSIS -------- [verse] 'git format-patch' [-k] [(-o|--output-directory) <dir> | --stdout] - [--thread[=<style>]] + [--no-thread | --thread[=<style>]] [(--attach|--inline)[=<boundary>] | --no-attach] [-s | --signoff] [-n | --numbered | -N | --no-numbered] @@ -124,17 +124,25 @@ include::diff-options.txt[] second part, with "Content-Disposition: inline". --thread[=<style>]:: - Add In-Reply-To and References headers to make the second and - subsequent mails appear as replies to the first. Also generates - the Message-Id header to reference. +--no-thread:: + Controls addition of In-Reply-To and References headers to + make the second and subsequent mails appear as replies to the + first. Also controls generation of the Message-Id header to + reference. + The optional <style> argument can be either `shallow` or `deep`. 'shallow' threading makes every mail a reply to the head of the series, where the head is chosen from the cover letter, the `\--in-reply-to`, and the first patch mail, in this order. 'deep' -threading makes every mail a reply to the previous one. If not -specified, defaults to the 'format.thread' configuration, or `shallow` -if that is not set. +threading makes every mail a reply to the previous one. ++ +The default is --no-thread, unless the 'format.thread' configuration +is set. If --thread is specified without a style, it defaults to the +style specified by 'format.thread' if any, or else `shallow`. ++ +Beware that the default for 'git send-email' is to thread emails +itself. If you want 'git format-patch' to take care of hreading, you +will want to ensure that threading is disabled for 'git send-email'. --in-reply-to=Message-Id:: Make the first mail (or all the mails with --no-thread) appear as a diff --git a/Documentation/git-merge-base.txt b/Documentation/git-merge-base.txt index 767486c770..ce5b369985 100644 --- a/Documentation/git-merge-base.txt +++ b/Documentation/git-merge-base.txt @@ -8,12 +8,12 @@ git-merge-base - Find as good common ancestors as possible for a merge SYNOPSIS -------- -'git merge-base' [--all] <commit> <commit>... +'git merge-base' [-a|--all] <commit> <commit>... DESCRIPTION ----------- -'git-merge-base' finds best common ancestor(s) between two commits to use +'git merge-base' finds best common ancestor(s) between two commits to use in a three-way merge. One common ancestor is 'better' than another common ancestor if the latter is an ancestor of the former. A common ancestor that does not have any better common ancestor is a 'best common @@ -27,8 +27,13 @@ commits on the command line. As the most common special case, specifying only two commits on the command line means computing the merge base between the given two commits. +As a consequence, the 'merge base' is not necessarily contained in each of the +commit arguments if more than two commits are specified. This is different +from linkgit:git-show-branch[1] when used with the `--merge-base` option. + OPTIONS ------- +-a:: --all:: Output all merge bases for the commits, instead of just one. diff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.txt index 7d4c1a7556..2e4992970e 100644 --- a/Documentation/git-pack-objects.txt +++ b/Documentation/git-pack-objects.txt @@ -11,7 +11,8 @@ SYNOPSIS [verse] 'git pack-objects' [-q] [--no-reuse-delta] [--delta-base-offset] [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] [--all-progress] - [--revs [--unpacked | --all]*] [--stdout | base-name] < object-list + [--revs [--unpacked | --all]*] [--stdout | base-name] + [--keep-true-parents] < object-list DESCRIPTION @@ -197,6 +198,10 @@ base-name:: to force the version for the generated pack index, and to force 64-bit index entries on objects located above the given offset. +--keep-true-parents:: + With this option, parents that are hidden by grafts are packed + nevertheless. + Author ------ diff --git a/Documentation/git-rerere.txt b/Documentation/git-rerere.txt index a53c3cd35b..7dd515b8cc 100644 --- a/Documentation/git-rerere.txt +++ b/Documentation/git-rerere.txt @@ -23,7 +23,7 @@ on the initial manual merge, and applying previously recorded hand resolutions to their corresponding automerge results. [NOTE] -You need to set the configuration variable rerere.enabled to +You need to set the configuration variable rerere.enabled in order to enable this command. diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index 1c9cc28895..a765cfa4d2 100644 --- a/Documentation/git-rev-list.txt +++ b/Documentation/git-rev-list.txt @@ -14,6 +14,7 @@ SYNOPSIS [ \--max-age=timestamp ] [ \--min-age=timestamp ] [ \--sparse ] + [ \--merges ] [ \--no-merges ] [ \--first-parent ] [ \--remove-empty ] diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index fbde2d3be5..767cf4d4bd 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -142,8 +142,9 @@ user is prompted for a password while the input is masked for privacy. --smtp-server-port=<port>:: Specifies a port different from the default port (SMTP - servers typically listen to smtp port 25 and ssmtp port - 465); symbolic port names (e.g. "submission" instead of 465) + servers typically listen to smtp port 25, but may also listen to + submission port 587, or the common SSL smtp port 465); + symbolic port names (e.g. "submission" instead of 587) are also accepted. The port can also be set with the 'sendemail.smtpserverport' configuration variable. @@ -212,11 +213,22 @@ specified, as well as 'body' if --no-signed-off-cc is specified. value; if that is unspecified, default to --no-suppress-from. --[no-]thread:: - If this is set, the In-Reply-To header will be set on each email sent. - If disabled with "--no-thread", no emails will have the In-Reply-To - header set, unless specified with --in-reply-to. - Default is the value of the 'sendemail.thread' configuration - value; if that is unspecified, default to --thread. + If this is set, the In-Reply-To and References headers will be + added to each email sent. Whether each mail refers to the + previous email (`deep` threading per 'git format-patch' + wording) or to the first email (`shallow` threading) is + governed by "--[no-]chain-reply-to". ++ +If disabled with "--no-thread", those headers will not be added +(unless specified with --in-reply-to). Default is the value of the +'sendemail.thread' configuration value; if that is unspecified, +default to --thread. ++ +It is up to the user to ensure that no In-Reply-To header already +exists when 'git send-email' is asked to add it (especially note that +'git format-patch' can be configured to do the threading itself). +Failure to do so may not produce the expected result in the +recipient's MUA. Administering diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt index 89ec5364ec..734336119c 100644 --- a/Documentation/git-show-branch.txt +++ b/Documentation/git-show-branch.txt @@ -8,11 +8,12 @@ git-show-branch - Show branches and their commits SYNOPSIS -------- [verse] -'git show-branch' [--all] [--remotes] [--topo-order | --date-order] - [--current] [--color | --no-color] +'git show-branch' [-a|--all] [-r|--remotes] [--topo-order | --date-order] + [--current] [--color | --no-color] [--sparse] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [--topics] [<rev> | <glob>]... + 'git show-branch' (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>] DESCRIPTION @@ -81,9 +82,11 @@ OPTIONS Synonym to `--more=-1` --merge-base:: - Instead of showing the commit list, just act like the - 'git-merge-base -a' command, except that it can accept - more than two heads. + Instead of showing the commit list, determine possible + merge bases for the specified commits. All merge bases + will be contained in all specified commits. This is + different from how linkgit:git-merge-base[1] handles + the case of three or more commits. --independent:: Among the <reference>s given, display only the ones that diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index 683ba1a1eb..7dd73ae14e 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -14,8 +14,8 @@ SYNOPSIS 'git submodule' [--quiet] status [--cached] [--] [<path>...] 'git submodule' [--quiet] init [--] [<path>...] 'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase] - [--reference <repository>] [--] [<path>...] -'git submodule' [--quiet] summary [--summary-limit <n>] [commit] [--] [<path>...] + [--reference <repository>] [--merge] [--] [<path>...] +'git submodule' [--quiet] summary [--cached] [--summary-limit <n>] [commit] [--] [<path>...] 'git submodule' [--quiet] foreach <command> 'git submodule' [--quiet] sync [--] [<path>...] diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index 10af599b44..22a0389f1e 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -80,6 +80,17 @@ COMMANDS When passed to 'init' or 'clone' this regular expression will be preserved as a config key. See 'fetch' for a description of '--ignore-paths'. +--no-minimize-url;; + When tracking multiple directories (using --stdlayout, + --branches, or --tags options), git svn will attempt to connect + to the root (or highest allowed level) of the Subversion + repository. This default allows better tracking of history if + entire projects are moved within a repository, but may cause + issues on repositories where read access restrictions are in + place. Passing '--no-minimize-url' will allow git svn to + accept URLs as-is without attempting to connect to a higher + level directory. This option is off by default when only + one URL/branch is tracked (it would do little good). 'fetch':: Fetch unfetched revisions from the Subversion remote we are @@ -338,6 +349,10 @@ Any other arguments are passed directly to 'git log' Shows the Subversion externals. Use -r/--revision to specify a specific revision. +'gc':: + Compress $GIT_DIR/svn/<refname>/unhandled.log files in .git/svn + and remove $GIT_DIR/svn/<refname>index files in .git/svn. + 'reset':: Undoes the effects of 'fetch' back to the specified revision. This allows you to re-'fetch' an SVN revision. Normally the diff --git a/Documentation/git.txt b/Documentation/git.txt index 6fa0310e05..5fd5953e29 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,15 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.6.3.3/git.html[documentation for release 1.6.3.3] +* link:v1.6.4/git.html[documentation for release 1.6.4] * release notes for + link:RelNotes-1.6.4.txt[1.6.4]. + +* link:v1.6.3.4/git.html[documentation for release 1.6.3.4] + +* release notes for + link:RelNotes-1.6.3.4.txt[1.6.3.4], link:RelNotes-1.6.3.3.txt[1.6.3.3], link:RelNotes-1.6.3.2.txt[1.6.3.2], link:RelNotes-1.6.3.1.txt[1.6.3.1], diff --git a/Documentation/pt_BR/gittutorial.txt b/Documentation/pt_BR/gittutorial.txt new file mode 100644 index 0000000000..81e7ad7df4 --- /dev/null +++ b/Documentation/pt_BR/gittutorial.txt @@ -0,0 +1,675 @@ +gittutorial(7) +============== + +NAME +---- +gittutorial - Um tutorial de introdução ao git (para versão 1.5.1 ou mais nova) + +SYNOPSIS +-------- +git * + +DESCRIPTION +----------- + +Este tutorial explica como importar um novo projeto para o git, +adicionar mudanças a ele, e compartilhar mudanças com outros +desenvolvedores. + +Se, ao invés disso, você está interessado primariamente em usar git para +obter um projeto, por exemplo, para testar a última versão, você pode +preferir começar com os primeiros dois capÃtulos de +link:user-manual.html[O Manual do Usuário Git]. + +Primeiro, note que você pode obter documentação para um comando como +`git log --graph` com: + +------------------------------------------------ +$ man git-log +------------------------------------------------ + +ou: + +------------------------------------------------ +$ git help log +------------------------------------------------ + +Com a última forma, você pode usar o visualizador de manual de sua +escolha; veja linkgit:git-help[1] para maior informação. + +É uma boa idéia informar ao git seu nome e endereço público de email +antes de fazer qualquer operação. A maneira mais fácil de fazê-lo é: + +------------------------------------------------ +$ git config --global user.name "Seu Nome Vem Aqui" +$ git config --global user.email voce@seudominio.exemplo.com +------------------------------------------------ + + +Importando um novo projeto +----------------------- + +Assuma que você tem um tarball project.tar.gz com seu trabalho inicial. +Você pode colocá-lo sob controle de revisão git da seguinte forma: + +------------------------------------------------ +$ tar xzf project.tar.gz +$ cd project +$ git init +------------------------------------------------ + +Git irá responder + +------------------------------------------------ +Initialized empty Git repository in .git/ +------------------------------------------------ + +Você agora iniciou seu diretório de trabalho--você deve ter notado um +novo diretório criado, com o nome de ".git". + +A seguir, diga ao git para gravar um instantâneo do conteúdo de todos os +arquivos sob o diretório corrente (note o '.'), com 'git-add': + +------------------------------------------------ +$ git add . +------------------------------------------------ + +Este instantâneo está agora armazenado em uma área temporária que o git +chama de "index" ou Ãndice. Você pode armazenar permanentemente o +conteúdo do Ãndice no repositório com 'git-commit': + +------------------------------------------------ +$ git commit +------------------------------------------------ + +Isto vai te pedir por uma mensagem de commit. Você agora gravou sua +primeira versão de seu projeto no git. + +Fazendo mudanças +-------------- + +Modifique alguns arquivos, e, então, adicione seu conteúdo atualizado ao +Ãndice: + +------------------------------------------------ +$ git add file1 file2 file3 +------------------------------------------------ + +Você está agora pronto para fazer o commit. Você pode ver o que está +para ser gravado usando 'git-diff' com a opção --cached: + +------------------------------------------------ +$ git diff --cached +------------------------------------------------ + +(Sem --cached, o comando 'git-diff' irá te mostrar quaisquer mudanças +que você tenha feito mas ainda não adicionou ao Ãndice.) Você também +pode obter um breve sumário da situação com 'git-status': + +------------------------------------------------ +$ git status +# On branch master +# Changes to be committed: +# (use "git reset HEAD <file>..." to unstage) +# +# modified: file1 +# modified: file2 +# modified: file3 +# +------------------------------------------------ + +Se você precisar fazer qualquer outro ajuste, faça-o agora, e, então, +adicione qualquer conteúdo modificado ao Ãndice. Finalmente, grave suas +mudanças com: + +------------------------------------------------ +$ git commit +------------------------------------------------ + +Isto irá novamente te pedir por uma mensagem descrevendo a mudança, e, +então, gravar a nova versão do projeto. + +Alternativamente, ao invés de executar 'git-add' antes, você pode usar + +------------------------------------------------ +$ git commit -a +------------------------------------------------ + +o que irá automaticamente notar quaisquer arquivos modificados (mas não +novos), adicioná-los ao Ãndices, e gravar, tudo em um único passo. + +Uma nota em mensagens de commit: Apesar de não ser exigido, é uma boa +idéia começar a mensagem com uma simples e curta (menos de 50 +caracteres) linha sumarizando a mudança, seguida de uma linha em branco +e, então, uma descrição mais detalhada. Ferramentas que transformam +commits em email, por exemplo, usam a primeira linha no campo de +cabeçalho Subject: e o resto no corpo. + +Git rastreia conteúdo, não arquivos +---------------------------- + +Muitos sistemas de controle de revisão provêem um comando `add` que diz +ao sistema para começar a rastrear mudanças em um novo arquivo. O +comando `add` do git faz algo mais simples e mais poderoso: 'git-add' é +usado tanto para arquivos novos e arquivos recentemente modificados, e +em ambos os casos, ele tira o instantâneo dos arquivos dados e armazena +o conteúdo no Ãndice, pronto para inclusão do próximo commit. + +Visualizando história do projeto +----------------------- + +Em qualquer ponto você pode visualizar a história das suas mudanças +usando + +------------------------------------------------ +$ git log +------------------------------------------------ + +Se você também quer ver a diferença completa a cada passo, use + +------------------------------------------------ +$ git log -p +------------------------------------------------ + +Geralmente, uma visão geral da mudança é útil para ter a sensação de +cada passo + +------------------------------------------------ +$ git log --stat --summary +------------------------------------------------ + +Gerenciando "branches"/ramos +----------------- + +Um simples repositório git pode manter múltiplos ramos de +desenvolvimento. Para criar um novo ramo chamado "experimental", use + +------------------------------------------------ +$ git branch experimental +------------------------------------------------ + +Se você executar agora + +------------------------------------------------ +$ git branch +------------------------------------------------ + +você vai obter uma lista de todos os ramos existentes: + +------------------------------------------------ + experimental +* master +------------------------------------------------ + +O ramo "experimental" é o que você acaba de criar, e o ramo "master" é o +ramo padrão que foi criado pra você automaticamente. O asterisco marca +o ramo em que você está atualmente; digite + +------------------------------------------------ +$ git checkout experimental +------------------------------------------------ + +para mudar para o ramo experimental. Agora edite um arquivo, grave a +mudança, e mude de volta para o ramo master: + +------------------------------------------------ +(edita arquivo) +$ git commit -a +$ git checkout master +------------------------------------------------ + +Verifique que a mudança que você fez não está mais visÃvel, já que ela +foi feita no ramo experimental e você está de volta ao ramo master. + +Você pode fazer uma mudança diferente no ramo master: + +------------------------------------------------ +(edit file) +$ git commit -a +------------------------------------------------ + +neste ponto, os dois ramos divergiram, com diferentes mudanças feitas em +cada um. Para unificar as mudanças feitas no experimental para o +master, execute + +------------------------------------------------ +$ git merge experimental +------------------------------------------------ + +Se as mudanças não conflitarem, estará pronto. Se existirem conflitos, +marcadores serão deixados nos arquivos problemáticos exibindo o +conflito; + +------------------------------------------------ +$ git diff +------------------------------------------------ + +vai exibir isto. Após você editar os arquivos para resolver os +conflitos, + +------------------------------------------------ +$ git commit -a +------------------------------------------------ + +irá gravar o resultado da unificação. Finalmente, + +------------------------------------------------ +$ gitk +------------------------------------------------ + +vai mostrar uma bela representação gráfica da história resultante. + +Neste ponto você pode remover seu ramo experimental com + +------------------------------------------------ +$ git branch -d experimental +------------------------------------------------ + +Este comando garante que as mudanças no ramo experimental já estão no +ramo atual. + +Se você desenvolve em um ramo ideia-louca, e se arrepende, você pode +sempre remover o ramo com + +------------------------------------- +$ git branch -D ideia-louca +------------------------------------- + +Ramos são baratos e fáceis, então isto é uma boa maneira de experimentar +alguma coisa. + +Usando git para colaboração +--------------------------- + +Suponha que Alice começou um novo projeto com um repositório git em +/home/alice/project, e que Bob, que tem um diretório home na mesma +máquina, quer contribuir. + +Bob começa com: + +------------------------------------------------ +bob$ git clone /home/alice/project myrepo +------------------------------------------------ + +Isso cria um novo diretório "myrepo" contendo um clone do repositório de +Alice. O clone está no mesmo pé que o projeto original, possuindo sua +própria cópia da história do projeto original. + +Bob então faz algumas mudanças e as grava: + +------------------------------------------------ +(editar arquivos) +bob$ git commit -a +(repetir conforme necessário) +------------------------------------------------ + +Quanto está pronto, ele diz a Alice para puxar as mudanças do +repositório em /home/bob/myrepo. Ela o faz com: + +------------------------------------------------ +alice$ cd /home/alice/project +alice$ git pull /home/bob/myrepo master +------------------------------------------------ + +Isto unifica as mudanças do ramo "master" do Bob ao ramo atual de Alice. +Se Alice fez suas próprias mudanças no intervalo, ela, então, pode +precisar corrigir manualmente quaisquer conflitos. (Note que o argumento +"master" no comando acima é, de fato, desnecessário, já que é o padrão.) + +O comando "pull" executa, então, duas operações: ele obtém mudanças de +um ramo remoto, e, então, as unifica no ramo atual. + +Note que, em geral, Alice gostaria que suas mudanças locais fossem +gravadas antes de iniciar este "pull". Se o trabalho de Bob conflita +com o que Alice fez desde que suas histórias se ramificaram, Alice irá +usar seu diretório de trabalho e o Ãndice para resolver conflitos, e +mudanças locais existentes irão interferir com o processo de resolução +de conflitos (git ainda irá realizar a obtenção mas irá se recusar a +unificar --- Alice terá que se livrar de suas mudanças locais de alguma +forma e puxar de novo quando isso acontecer). + +Alice pode espiar o que Bob fez sem unificar primeiro, usando o comando +"fetch"; isto permite Alice inspecionar o que Bob fez, usando um sÃmbolo +especial "FETCH_HEAD", com o fim de determinar se ele tem alguma coisa +que vale puxar, assim: + +------------------------------------------------ +alice$ git fetch /home/bob/myrepo master +alice$ git log -p HEAD..FETCH_HEAD +------------------------------------------------ + +Esta operação é segura mesmo se Alice tem mudanças locais não gravadas. +A notação de intervalo "HEAD..FETCH_HEAD" significa mostrar tudo que é +alcançável de FETCH_HEAD mas exclua tudo o que é alcançável de HEAD. +Alice já sabe tudo que leva a seu estado atual (HEAD), e revisa o que Bob +tem em seu estado (FETCH_HEAD) que ela ainda não viu com esse comando. + +Se Alice quer visualizar o que Bob fez desde que suas histórias se +ramificaram, ela pode disparar o seguinte comando: + +------------------------------------------------ +$ gitk HEAD..FETCH_HEAD +------------------------------------------------ + +Isto usa a mesma notação de intervalo que vimos antes com 'git log'. + +Alice pode querer ver o que ambos fizeram desde que ramificaram. Ela +pode usar a forma com três pontos ao invés da forma com dois pontos: + +------------------------------------------------ +$ gitk HEAD...FETCH_HEAD +------------------------------------------------ + +Isto significa "mostre tudo que é alcançável de qualquer um deles, mas +exclua tudo que é alcançável a partir de ambos". + +Por favor, note que essas notações de intervalo podem ser usadas tanto +com gitk quanto com "git log". + +Após inspecionar o que Bob fez, se não há nada urgente, Alice pode +decidir continuar trabalhando sem puxar de Bob. Se a história de Bob +tem alguma coisa que Alice precisa imediatamente, Alice pode optar por +separar seu trabalho em progresso primeiro, fazer um "pull", e, então, +finalmente, retomar seu trabalho em progresso em cima da história +resultante. + +Quando você está trabalhando em um pequeno grupo unido, não é incomum +interagir com o mesmo repositório várias e várias vezes. Definindo um +repositório remoto antes de tudo, você pode fazê-lo mais facilmente: + +------------------------------------------------ +alice$ git remote add bob /home/bob/myrepo +------------------------------------------------ + +Com isso, Alice pode executar a primeira parte da operação "pull" usando +o comando 'git-fetch' sem unificar suas mudanças com seu próprio ramo, +usando: + +------------------------------------- +alice$ git fetch bob +------------------------------------- + +Diferente da forma longa, quando Alice obteve de Bob usando um +repositório remoto antes definido com 'git-remote', o que foi obtido é +armazenado em um ramo remoto, neste caso `bob/master`. Então, após isso: + +------------------------------------- +alice$ git log -p master..bob/master +------------------------------------- + +mostra uma lista de todas as mudanças que Bob fez desde que ramificou do +ramo master de Alice. + +Após examinar essas mudanças, Alice pode unificá-las em seu ramo master: + +------------------------------------- +alice$ git merge bob/master +------------------------------------- + +Esse `merge` pode também ser feito puxando de seu próprio ramo remoto, +assim: + +------------------------------------- +alice$ git pull . remotes/bob/master +------------------------------------- + +Note que 'git pull' sempre unifica ao ramo atual, independente do que +mais foi passado na linha de comando. + +Depois, Bob pode atualizar seu repositório com as últimas mudanças de +Alice, usando + +------------------------------------- +bob$ git pull +------------------------------------- + +Note que ele não precisa dar o caminho do repositório de Alice; quando +Bob clonou seu repositório, o git armazenou a localização de seu +repositório na configuração do mesmo, e essa localização é usada +para puxar: + +------------------------------------- +bob$ git config --get remote.origin.url +/home/alice/project +------------------------------------- + +(A configuração completa criada por 'git-clone' é visÃvel usando `git +config -l`, e a página de manual linkgit:git-config[1] explica o +significado de cada opção.) + +Git também mantém uma cópia limpa do ramo master de Alice sob o nome +"origin/master": + +------------------------------------- +bob$ git branch -r + origin/master +------------------------------------- + +Se Bob decidir depois em trabalhar em um host diferente, ele ainda pode +executar clones e puxar usando o protocolo ssh: + +------------------------------------- +bob$ git clone alice.org:/home/alice/project myrepo +------------------------------------- + +Alternativamente, o git tem um protocolo nativo, ou pode usar rsync ou +http; veja linkgit:git-pull[1] para detalhes. + +Git pode também ser usado em um modo parecido com CVS, com um +repositório central para o qual vários usuários empurram modificações; +veja linkgit:git-push[1] e linkgit:gitcvs-migration[7]. + +Explorando história +----------------- + +A história no git é representada como uma série de commits +interrelacionados. Nós já vimos que o comando 'git-log' pode listar +esses commits. Note que a primeira linha de cada entrada no log também +dá o nome para o commit: + +------------------------------------- +$ git log +commit c82a22c39cbc32576f64f5c6b3f24b99ea8149c7 +Author: Junio C Hamano <junkio@cox.net> +Date: Tue May 16 17:18:22 2006 -0700 + + merge-base: Clarify the comments on post processing. +------------------------------------- + +Nós podemos dar este nome ao 'git-show' para ver os detalhes sobre este +commit. + +------------------------------------- +$ git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7 +------------------------------------- + +Mas há outras formas de se referir aos commits. Você pode usar qualquer +parte inicial do nome que seja longo o bastante para identificar +unicamente o commit: + +------------------------------------- +$ git show c82a22c39c # os primeiros caracteres do nome são o bastante + # usualmente +$ git show HEAD # a ponta do ramo atual +$ git show experimental # a ponta do ramo "experimental" +------------------------------------- + +Todo commit normalmente tem um commit "pai" que aponta para o estado +anterior do projeto: + +------------------------------------- +$ git show HEAD^ # para ver o pai de HEAD +$ git show HEAD^^ # para ver o avô de HEAD +$ git show HEAD~4 # para ver o trisavô de HEAD +------------------------------------- + +Note que commits de unificação podem ter mais de um pai: + +------------------------------------- +$ git show HEAD^1 # mostra o primeiro pai de HEAD (o mesmo que HEAD^) +$ git show HEAD^2 # mostra o segundo pai de HEAD +------------------------------------- + +Você também pode dar aos commits nomes à sua escolha; após executar + +------------------------------------- +$ git tag v2.5 1b2e1d63ff +------------------------------------- + +você pode se referir a 1b2e1d63ff pelo nome "v2.5". Se você pretende +compartilhar esse nome com outras pessoas (por exemplo, para identificar +uma versão de lançamento), você deveria criar um objeto "tag", e talvez +assiná-lo; veja linkgit:git-tag[1] para detalhes. + +Qualquer comando git que precise conhecer um commit pode receber +quaisquer desses nomes. Por exemplo: + +------------------------------------- +$ git diff v2.5 HEAD # compara o HEAD atual com v2.5 +$ git branch stable v2.5 # inicia um novo ramo chamado "stable" baseado + # em v2.5 +$ git reset --hard HEAD^ # reseta seu ramo atual e seu diretório de + # trabalho a seu estado em HEAD^ +------------------------------------- + +Seja cuidadoso com o último comando: além de perder quaisquer mudanças +em seu diretório de trabalho, ele também remove todos os commits +posteriores desse ramo. Se esse ramo é o único ramo contendo esses +commits, eles serão perdidos. Também, não use 'git-reset' num ramo +publicamente visÃvel de onde outros desenvolvedores puxam, já que vai +forçar unificações desnecessárias para que outros desenvolvedores limpem +a história. Se você precisa desfazer mudanças que você empurrou, use +'git-revert' no lugar. + +O comando 'git-grep' pode buscar strings em qualquer versão de seu +projeto, então + +------------------------------------- +$ git grep "hello" v2.5 +------------------------------------- + +procura por todas as ocorrências de "hello" em v2.5. + +Se você deixar de fora o nome do commit, 'git-grep' irá procurar +quaisquer dos arquivos que ele gerencia no diretório corrente. Então + +------------------------------------- +$ git grep "hello" +------------------------------------- + +é uma forma rápida de buscar somente os arquivos que são rastreados pelo +git. + +Muitos comandos git também recebem um conjunto de commits, o que pode +ser especificado de várias formas. Aqui estão alguns exemplos com 'git-log': + +------------------------------------- +$ git log v2.5..v2.6 # commits entre v2.5 e v2.6 +$ git log v2.5.. # commits desde v2.5 +$ git log --since="2 weeks ago" # commits das últimas 2 semanas +$ git log v2.5.. Makefile # commits desde v2.5 que modificam + # Makefile +------------------------------------- + +Você também pode dar ao 'git-log' um "intervalo" de commits onde o +primeiro não é necessariamente um ancestral do segundo; por exemplo, se +as pontas dos ramos "stable" e "master" divergiram de um commit +comum algum tempo atrás, então + +------------------------------------- +$ git log stable..master +------------------------------------- + +irá listar os commits feitos no ramo "master" mas não no ramo +"stable", enquanto + +------------------------------------- +$ git log master..stable +------------------------------------- + +irá listar a lista de commits feitos no ramo "stable" mas não no ramo +"master". + +O comando 'git-log' tem uma fraqueza: ele precisa mostrar os commits em +uma lista. Quando a história tem linhas de desenvolvimento que +divergiram e então foram unificadas novamente, a ordem em que 'git-log' +apresenta essas mudanças é irrelevante. + +A maioria dos projetos com múltiplos contribuidores (como o kernel +Linux, ou o próprio git) tem unificações frequentes, e 'gitk' faz um +trabalho melhor de visualizar sua história. Por exemplo, + +------------------------------------- +$ gitk --since="2 weeks ago" drivers/ +------------------------------------- + +permite a você navegar em quaisquer commits desde as últimas duas semanas +de commits que modificaram arquivos sob o diretório "drivers". (Nota: +você pode ajustar as fontes do gitk segurando a tecla control enquanto +pressiona "-" ou "+".) + +Finalmente, a maioria dos comandos que recebem nomes de arquivo permitirão +também, opcionalmente, preceder qualquer nome de arquivo por um +commit, para especificar uma versão particular do arquivo: + +------------------------------------- +$ git diff v2.5:Makefile HEAD:Makefile.in +------------------------------------- + +Você pode usar 'git-show' para ver tal arquivo: + +------------------------------------- +$ git show v2.5:Makefile +------------------------------------- + +Próximos passos +---------- + +Este tutorial deve ser o bastante para operar controle de revisão +distribuÃdo básico para seus projetos. No entanto, para entender +plenamente a profundidade e o poder do git você precisa entender duas +idéias simples nas quais ele se baseia: + + * A base de objetos é um sistema bem elegante usado para armazenar a + história de seu projeto--arquivos, diretórios, e commits. + + * O arquivo de Ãndice é um cache do estado de uma árvore de diretório, + usado para criar commits, restaurar diretórios de trabalho, e + armazenar as várias árvores envolvidas em uma unificação. + +A parte dois deste tutorial explica a base de objetos, o arquivo de +Ãndice, e algumas outras coisinhas que você vai precisar pra usar o +máximo do git. Você pode encontrá-la em linkgit:gittutorial-2[7]. + +Se você não quiser continuar com o tutorial agora nesse momento, algumas +outras digressões que podem ser interessantes neste ponto são: + + * linkgit:git-format-patch[1], linkgit:git-am[1]: Estes convertem + séries de commits em patches para email, e vice-versa, úteis para + projetos como o kernel Linux que dependem fortemente de patches + enviados por email. + + * linkgit:git-bisect[1]: Quando há uma regressão em seu projeto, uma + forma de rastrear um bug é procurando pela história para encontrar o + commit culpado. Git bisect pode ajudar a executar uma busca binária + por esse commit. Ele é inteligente o bastante para executar uma + busca próxima da ótima mesmo no caso de uma história complexa + não-linear com muitos ramos unificados. + + * link:everyday.html[GIT diariamente com 20 e tantos comandos] + + * linkgit:gitcvs-migration[7]: Git para usuários de CVS. + +VEJA TAMBÉM +-------- +linkgit:gittutorial-2[7], +linkgit:gitcvs-migration[7], +linkgit:gitcore-tutorial[7], +linkgit:gitglossary[7], +linkgit:git-help[1], +link:everyday.html[git diariamente], +link:user-manual.html[O Manual do Usuário git] + +GIT +--- +Parte da suite linkgit:git[1]. diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index 11eec941df..bf66116d61 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -201,6 +201,10 @@ endif::git-rev-list[] Stop when a given path disappears from the tree. +--merges:: + + Print only merge commits. + --no-merges:: Do not print commits with more than one parent. diff --git a/Documentation/technical/api-tree-walking.txt b/Documentation/technical/api-tree-walking.txt index e3ddf91284..55b728632c 100644 --- a/Documentation/technical/api-tree-walking.txt +++ b/Documentation/technical/api-tree-walking.txt @@ -1,12 +1,145 @@ tree walking API ================ -Talk about <tree-walk.h>, things like +The tree walking API is used to traverse and inspect trees. -* struct tree_desc -* init_tree_desc -* tree_entry_extract -* update_tree_entry -* get_tree_entry +Data Structures +--------------- -(JC, Linus) +`struct name_entry`:: + + An entry in a tree. Each entry has a sha1 identifier, pathname, and + mode. + +`struct tree_desc`:: + + A semi-opaque data structure used to maintain the current state of the + walk. ++ +* `buffer` is a pointer into the memory representation of the tree. It always +points at the current entry being visited. + +* `size` counts the number of bytes left in the `buffer`. + +* `entry` points to the current entry being visited. + +`struct traverse_info`:: + + A structure used to maintain the state of a traversal. ++ +* `prev` points to the traverse_info which was used to descend into the +current tree. If this is the top-level tree `prev` will point to +a dummy traverse_info. + +* `name` is the entry for the current tree (if the tree is a subtree). + +* `pathlen` is the length of the full path for the current tree. + +* `conflicts` can be used by callbacks to maintain directory-file conflicts. + +* `fn` is a callback called for each entry in the tree. See Traversing for more +information. + +* `data` can be anything the `fn` callback would want to use. + +Initializing +------------ + +`init_tree_desc`:: + + Initialize a `tree_desc` and decode its first entry. The buffer and + size parameters are assumed to be the same as the buffer and size + members of `struct tree`. + +`fill_tree_descriptor`:: + + Initialize a `tree_desc` and decode its first entry given the sha1 of + a tree. Returns the `buffer` member if the sha1 is a valid tree + identifier and NULL otherwise. + +`setup_traverse_info`:: + + Initialize a `traverse_info` given the pathname of the tree to start + traversing from. The `base` argument is assumed to be the `path` + member of the `name_entry` being recursed into unless the tree is a + top-level tree in which case the empty string ("") is used. + +Walking +------- + +`tree_entry`:: + + Visit the next entry in a tree. Returns 1 when there are more entries + left to visit and 0 when all entries have been visited. This is + commonly used in the test of a while loop. + +`tree_entry_len`:: + + Calculate the length of a tree entry's pathname. This utilizes the + memory structure of a tree entry to avoid the overhead of using a + generic strlen(). + +`update_tree_entry`:: + + Walk to the next entry in a tree. This is commonly used in conjunction + with `tree_entry_extract` to inspect the current entry. + +`tree_entry_extract`:: + + Decode the entry currently being visited (the one pointed to by + `tree_desc's` `entry` member) and return the sha1 of the entry. The + `pathp` and `modep` arguments are set to the entry's pathname and mode + respectively. + +`get_tree_entry`:: + + Find an entry in a tree given a pathname and the sha1 of a tree to + search. Returns 0 if the entry is found and -1 otherwise. The third + and fourth parameters are set to the entry's sha1 and mode + respectively. + +Traversing +---------- + +`traverse_trees`:: + + Traverse `n` number of trees in parallel. The `fn` callback member of + `traverse_info` is called once for each tree entry. + +`traverse_callback_t`:: + The arguments passed to the traverse callback are as follows: ++ +* `n` counts the number of trees being traversed. + +* `mask` has its nth bit set if something exists in the nth entry. + +* `dirmask` has its nth bit set if the nth tree's entry is a directory. + +* `entry` is an array of size `n` where the nth entry is from the nth tree. + +* `info` maintains the state of the traversal. + ++ +Returning a negative value will terminate the traversal. Otherwise the +return value is treated as an update mask. If the nth bit is set the nth tree +will be updated and if the bit is not set the nth tree entry will be the +same in the next callback invocation. + +`make_traverse_path`:: + + Generate the full pathname of a tree entry based from the root of the + traversal. For example, if the traversal has recursed into another + tree named "bar" the pathname of an entry "baz" in the "bar" + tree would be "bar/baz". + +`traverse_path_len`:: + + Calculate the length of a pathname returned by `make_traverse_path`. + This utilizes the memory structure of a tree entry to avoid the + overhead of using a generic strlen(). + +Authors +------- + +Written by Junio C Hamano <gitster@pobox.com> and Linus Torvalds +<torvalds@linux-foundation.org> diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 39cde784c9..d7d9a9a063 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.6.3.GIT +DEF_VER=v1.6.4.GIT LF=' ' @@ -728,6 +728,7 @@ ifeq ($(uname_S),SunOS) NO_MKDTEMP = YesPlease NO_MKSTEMPS = YesPlease NO_REGEX = YesPlease + NO_EXTERNAL_GREP = YesPlease ifeq ($(uname_R),5.7) NEEDS_RESOLV = YesPlease NO_IPV6 = YesPlease @@ -1 +1 @@ -Documentation/RelNotes-1.6.4.txt
\ No newline at end of file +Documentation/RelNotes-1.6.5.txt
\ No newline at end of file diff --git a/builtin-branch.c b/builtin-branch.c index 5687d6042c..1a03d5f356 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -191,7 +191,7 @@ struct ref_item { struct ref_list { struct rev_info revs; - int index, alloc, maxwidth; + int index, alloc, maxwidth, verbose, abbrev; struct ref_item *list; struct commit_list *with_commit; int kinds; @@ -240,21 +240,24 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, if (ARRAY_SIZE(ref_kind) <= i) return 0; - commit = lookup_commit_reference_gently(sha1, 1); - if (!commit) - return error("branch '%s' does not point at a commit", refname); - - /* Filter with with_commit if specified */ - if (!is_descendant_of(commit, ref_list->with_commit)) - return 0; - /* Don't add types the caller doesn't want */ if ((kind & ref_list->kinds) == 0) return 0; - if (merge_filter != NO_FILTER) - add_pending_object(&ref_list->revs, - (struct object *)commit, refname); + commit = NULL; + if (ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER) { + commit = lookup_commit_reference_gently(sha1, 1); + if (!commit) + return error("branch '%s' does not point at a commit", refname); + + /* Filter with with_commit if specified */ + if (!is_descendant_of(commit, ref_list->with_commit)) + return 0; + + if (merge_filter != NO_FILTER) + add_pending_object(&ref_list->revs, + (struct object *)commit, refname); + } /* Resize buffer */ if (ref_list->index >= ref_list->alloc) { @@ -415,18 +418,38 @@ static int calc_maxwidth(struct ref_list *refs) return w; } + +static void show_detached(struct ref_list *ref_list) +{ + struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1); + + if (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) { + struct ref_item item; + item.name = xstrdup("(no branch)"); + item.len = strlen(item.name); + item.kind = REF_LOCAL_BRANCH; + item.dest = NULL; + item.commit = head_commit; + if (item.len > ref_list->maxwidth) + ref_list->maxwidth = item.len; + print_ref_item(&item, ref_list->maxwidth, ref_list->verbose, ref_list->abbrev, 1, ""); + free(item.name); + } +} + static void print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit) { int i; struct ref_list ref_list; - struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1); memset(&ref_list, 0, sizeof(ref_list)); ref_list.kinds = kinds; + ref_list.verbose = verbose; + ref_list.abbrev = abbrev; ref_list.with_commit = with_commit; if (merge_filter != NO_FILTER) init_revisions(&ref_list.revs, NULL); - for_each_ref(append_ref, &ref_list); + for_each_rawref(append_ref, &ref_list); if (merge_filter != NO_FILTER) { struct commit *filter; filter = lookup_commit_reference_gently(merge_filter_ref, 0); @@ -442,19 +465,8 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp); detached = (detached && (kinds & REF_LOCAL_BRANCH)); - if (detached && head_commit && - is_descendant_of(head_commit, with_commit)) { - struct ref_item item; - item.name = xstrdup("(no branch)"); - item.len = strlen(item.name); - item.kind = REF_LOCAL_BRANCH; - item.dest = NULL; - item.commit = head_commit; - if (item.len > ref_list.maxwidth) - ref_list.maxwidth = item.len; - print_ref_item(&item, ref_list.maxwidth, verbose, abbrev, 1, ""); - free(item.name); - } + if (detached) + show_detached(&ref_list); for (i = 0; i < ref_list.index; i++) { int current = !detached && diff --git a/builtin-fast-export.c b/builtin-fast-export.c index 9a8a6fc6b1..b0a4029c94 100644 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -23,8 +23,10 @@ static const char *fast_export_usage[] = { }; static int progress; -static enum { VERBATIM, WARN, STRIP, ABORT } signed_tag_mode = ABORT; +static enum { ABORT, VERBATIM, WARN, STRIP } signed_tag_mode = ABORT; +static enum { ERROR, DROP, REWRITE } tag_of_filtered_mode = ABORT; static int fake_missing_tagger; +static int no_data; static int parse_opt_signed_tag_mode(const struct option *opt, const char *arg, int unset) @@ -42,6 +44,20 @@ static int parse_opt_signed_tag_mode(const struct option *opt, return 0; } +static int parse_opt_tag_of_filtered_mode(const struct option *opt, + const char *arg, int unset) +{ + if (unset || !strcmp(arg, "abort")) + tag_of_filtered_mode = ABORT; + else if (!strcmp(arg, "drop")) + tag_of_filtered_mode = DROP; + else if (!strcmp(arg, "rewrite")) + tag_of_filtered_mode = REWRITE; + else + return error("Unknown tag-of-filtered mode: %s", arg); + return 0; +} + static struct decoration idnums; static uint32_t last_idnum; @@ -101,6 +117,9 @@ static void handle_object(const unsigned char *sha1) char *buf; struct object *object; + if (no_data) + return; + if (is_null_sha1(sha1)) return; @@ -158,7 +177,7 @@ static void show_filemodify(struct diff_queue_struct *q, * Links refer to objects in another repositories; * output the SHA-1 verbatim. */ - if (S_ISGITLINK(spec->mode)) + if (no_data || S_ISGITLINK(spec->mode)) printf("M %06o %s %s\n", spec->mode, sha1_to_hex(spec->sha1), spec->path); else { @@ -289,6 +308,23 @@ static void handle_tag(const char *name, struct tag *tag) char *buf; const char *tagger, *tagger_end, *message; size_t message_size = 0; + struct object *tagged; + int tagged_mark; + struct commit *p; + + /* Trees have no identifer in fast-export output, thus we have no way + * to output tags of trees, tags of tags of trees, etc. Simply omit + * such tags. + */ + tagged = tag->tagged; + while (tagged->type == OBJ_TAG) { + tagged = ((struct tag *)tagged)->tagged; + } + if (tagged->type == OBJ_TREE) { + warning("Omitting tag %s,\nsince tags of trees (or tags of tags of trees, etc.) are not supported.", + sha1_to_hex(tag->object.sha1)); + return; + } buf = read_sha1_file(tag->object.sha1, &type, &size); if (!buf) @@ -333,10 +369,45 @@ static void handle_tag(const char *name, struct tag *tag) } } + /* handle tag->tagged having been filtered out due to paths specified */ + tagged = tag->tagged; + tagged_mark = get_object_mark(tagged); + if (!tagged_mark) { + switch(tag_of_filtered_mode) { + case ABORT: + die ("Tag %s tags unexported object; use " + "--tag-of-filtered-object=<mode> to handle it.", + sha1_to_hex(tag->object.sha1)); + case DROP: + /* Ignore this tag altogether */ + return; + case REWRITE: + if (tagged->type != OBJ_COMMIT) { + die ("Tag %s tags unexported %s!", + sha1_to_hex(tag->object.sha1), + typename(tagged->type)); + } + p = (struct commit *)tagged; + for (;;) { + if (p->parents && p->parents->next) + break; + if (p->object.flags & UNINTERESTING) + break; + if (!(p->object.flags & TREESAME)) + break; + if (!p->parents) + die ("Can't find replacement commit for tag %s\n", + sha1_to_hex(tag->object.sha1)); + p = p->parents->item; + } + tagged_mark = get_object_mark(&p->object); + } + } + if (!prefixcmp(name, "refs/tags/")) name += 10; printf("tag %s\nfrom :%d\n%.*s%sdata %d\n%.*s\n", - name, get_object_mark(tag->tagged), + name, tagged_mark, (int)(tagger_end - tagger), tagger, tagger == tagger_end ? "" : "\n", (int)message_size, (int)message_size, message ? message : ""); @@ -428,21 +499,27 @@ static void export_marks(char *file) uint32_t mark; struct object_decoration *deco = idnums.hash; FILE *f; + int e = 0; f = fopen(file, "w"); if (!f) - error("Unable to open marks file %s for writing", file); + error("Unable to open marks file %s for writing.", file); for (i = 0; i < idnums.size; i++) { if (deco->base && deco->base->type == 1) { mark = ptr_to_mark(deco->decoration); - fprintf(f, ":%"PRIu32" %s\n", mark, - sha1_to_hex(deco->base->sha1)); + if (fprintf(f, ":%"PRIu32" %s\n", mark, + sha1_to_hex(deco->base->sha1)) < 0) { + e = 1; + break; + } } deco++; } - if (ferror(f) || fclose(f)) + e |= ferror(f); + e |= fclose(f); + if (e) error("Unable to write marks file %s.", file); } @@ -498,12 +575,18 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) OPT_CALLBACK(0, "signed-tags", &signed_tag_mode, "mode", "select handling of signed tags", parse_opt_signed_tag_mode), + OPT_CALLBACK(0, "tag-of-filtered-object", &tag_of_filtered_mode, "mode", + "select handling of tags that tag filtered objects", + parse_opt_tag_of_filtered_mode), OPT_STRING(0, "export-marks", &export_filename, "FILE", "Dump marks to this file"), OPT_STRING(0, "import-marks", &import_filename, "FILE", "Import marks from this file"), OPT_BOOLEAN(0, "fake-missing-tagger", &fake_missing_tagger, "Fake a tagger when tags lack one"), + { OPTION_NEGBIT, 0, "data", &no_data, NULL, + "Skip output of blob data", + PARSE_OPT_NOARG | PARSE_OPT_NEGHELP, NULL, 1 }, OPT_END() }; @@ -514,6 +597,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) git_config(git_default_config, NULL); init_revisions(&revs, prefix); + revs.topo_order = 1; + revs.show_source = 1; + revs.rewrite_parents = 1; argc = setup_revisions(argc, argv, &revs, NULL); argc = parse_options(argc, argv, prefix, options, fast_export_usage, 0); if (argc > 1) @@ -524,18 +610,13 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) get_tags_and_duplicates(&revs.pending, &extra_refs); - revs.topo_order = 1; if (prepare_revision_walk(&revs)) die("revision walk setup failed"); revs.diffopt.format_callback = show_filemodify; DIFF_OPT_SET(&revs.diffopt, RECURSIVE); while ((commit = get_revision(&revs))) { if (has_unshown_parent(commit)) { - struct commit_list *parent = commit->parents; add_object_array(&commit->object, NULL, &commits); - for (; parent; parent = parent->next) - if (!parent->item->util) - parent->item->util = commit->util; } else { handle_commit(commit, &revs); diff --git a/builtin-log.c b/builtin-log.c index 0c2fa0ae2d..30358166e6 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -257,7 +257,7 @@ static void show_tagger(char *buf, int len, struct rev_info *rev) pp_user_info("Tagger", rev->commit_format, &out, buf, rev->date_mode, git_log_output_encoding ? git_log_output_encoding: git_commit_encoding); - printf("%s\n", out.buf); + printf("%s", out.buf); strbuf_release(&out); } @@ -329,11 +329,14 @@ int cmd_show(int argc, const char **argv, const char *prefix) case OBJ_TAG: { struct tag *t = (struct tag *)o; + if (rev.shown_one) + putchar('\n'); printf("%stag %s%s\n", diff_get_color_opt(&rev.diffopt, DIFF_COMMIT), t->tag, diff_get_color_opt(&rev.diffopt, DIFF_RESET)); ret = show_object(o->sha1, 1, &rev); + rev.shown_one = 1; if (ret) break; o = parse_object(t->tagged->sha1); @@ -345,12 +348,15 @@ int cmd_show(int argc, const char **argv, const char *prefix) break; } case OBJ_TREE: + if (rev.shown_one) + putchar('\n'); printf("%stree %s%s\n\n", diff_get_color_opt(&rev.diffopt, DIFF_COMMIT), name, diff_get_color_opt(&rev.diffopt, DIFF_RESET)); read_tree_recursive((struct tree *)o, "", 0, 0, NULL, show_tree_object, NULL); + rev.shown_one = 1; break; case OBJ_COMMIT: rev.pending.nr = rev.pending.alloc = 0; diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c index fb5ad70f3f..92637ac0ba 100644 --- a/builtin-mailinfo.c +++ b/builtin-mailinfo.c @@ -221,8 +221,6 @@ static void cleanup_subject(struct strbuf *subject) { char *pos; size_t remove; - int brackets_removed = 0; - while (subject->len) { switch (*subject->buf) { case 'r': case 'R': @@ -237,15 +235,10 @@ static void cleanup_subject(struct strbuf *subject) strbuf_remove(subject, 0, 1); continue; case '[': - /* remove only one set of square brackets */ - if (brackets_removed) - break; - if ((pos = strchr(subject->buf, ']'))) { remove = pos - subject->buf; if (remove <= (subject->len - remove) * 2) { strbuf_remove(subject, 0, remove + 1); - brackets_removed = 1; continue; } } else diff --git a/builtin-merge-base.c b/builtin-merge-base.c index a6ec2f7ab7..54e7ec2237 100644 --- a/builtin-merge-base.c +++ b/builtin-merge-base.c @@ -23,7 +23,7 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all) } static const char * const merge_base_usage[] = { - "git merge-base [--all] <commit-id> <commit-id>...", + "git merge-base [-a|--all] <commit> <commit>...", NULL }; diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index a27c2f6277..ef4bf6bc14 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -2255,6 +2255,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) die("bad %s", arg); continue; } + if (!strcmp(arg, "--keep-true-parents")) { + grafts_replace_parents = 0; + continue; + } usage(pack_usage); } diff --git a/builtin-push.c b/builtin-push.c index 0a0297f981..1d92e22f0a 100644 --- a/builtin-push.c +++ b/builtin-push.c @@ -64,36 +64,11 @@ static void setup_push_tracking(void) add_refspec(refspec.buf); } -static const char *warn_unconfigured_push_msg[] = { - "You did not specify any refspecs to push, and the current remote", - "has not configured any push refspecs. The default action in this", - "case is to push all matching refspecs, that is, all branches", - "that exist both locally and remotely will be updated. This may", - "not necessarily be what you want to happen.", - "", - "You can specify what action you want to take in this case, and", - "avoid seeing this message again, by configuring 'push.default' to:", - " 'nothing' : Do not push anything", - " 'matching' : Push all matching branches (default)", - " 'tracking' : Push the current branch to whatever it is tracking", - " 'current' : Push the current branch" -}; - -static void warn_unconfigured_push(void) -{ - int i; - for (i = 0; i < ARRAY_SIZE(warn_unconfigured_push_msg); i++) - warning("%s", warn_unconfigured_push_msg[i]); -} - static void setup_default_push_refspecs(void) { git_config(git_default_config, NULL); switch (push_default) { - case PUSH_DEFAULT_UNSPECIFIED: - warn_unconfigured_push(); - /* fallthrough */ - + default: case PUSH_DEFAULT_MATCHING: add_refspec(":"); break; diff --git a/builtin-reflog.c b/builtin-reflog.c index ddfdf5a3cb..95198c5de4 100644 --- a/builtin-reflog.c +++ b/builtin-reflog.c @@ -694,7 +694,7 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix) */ static const char reflog_usage[] = -"git reflog (expire | ...)"; +"git reflog [ show | expire | delete ]"; int cmd_reflog(int argc, const char **argv, const char *prefix) { diff --git a/builtin-show-branch.c b/builtin-show-branch.c index 01bea3b583..3510a86e38 100644 --- a/builtin-show-branch.c +++ b/builtin-show-branch.c @@ -6,8 +6,8 @@ #include "parse-options.h" static const char* show_branch_usage[] = { - "git show-branch [--sparse] [--current] [--all] [--remotes] [--topo-order] [--more=count | --list | --independent | --merge-base] [--topics] [--color] [<refs>...]", - "--reflog[=n[,b]] [--list] [--color] <branch>", + "git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--current] [--color | --no-color] [--sparse] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [--topics] [<rev> | <glob>]...", + "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]", NULL }; @@ -665,7 +665,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) OPT_BOOLEAN(0, "sha1-name", &sha1_name, "name commits with their object names"), OPT_BOOLEAN(0, "merge-base", &merge_base, - "act like git merge-base -a"), + "show possible merge bases"), OPT_BOOLEAN(0, "independent", &independent, "show refs unreachable from any other ref"), OPT_BOOLEAN(0, "topo-order", &lifo, diff --git a/cache-tree.c b/cache-tree.c index 16a65dfac1..d91743775d 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -329,7 +329,8 @@ static int update_one(struct cache_tree *it, entlen = pathlen - baselen; } if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) - return error("invalid object %s", sha1_to_hex(sha1)); + return error("invalid object %06o %s for '%.*s'", + mode, sha1_to_hex(sha1), entlen+baselen, path); if (ce->ce_flags & CE_REMOVE) continue; /* entry being removed */ @@ -543,7 +543,6 @@ enum rebase_setup_type { }; enum push_default_type { - PUSH_DEFAULT_UNSPECIFIED = -1, PUSH_DEFAULT_NOTHING = 0, PUSH_DEFAULT_MATCHING, PUSH_DEFAULT_TRACKING, @@ -561,6 +560,8 @@ enum object_creation_mode { extern enum object_creation_mode object_creation_mode; +extern int grafts_replace_parents; + #define GIT_REPO_VERSION 0 extern int repository_format_version; extern int check_repository_format(void); diff --git a/combine-diff.c b/combine-diff.c index bbf74fc42e..5b63af1eeb 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -80,6 +80,7 @@ struct lline { /* Lines surviving in the merge result */ struct sline { struct lline *lost_head, **lost_tail; + struct lline *next_lost; char *bol; int len; /* bit 0 up to (N-1) are on if the parent has this line (i.e. @@ -121,18 +122,12 @@ static void append_lost(struct sline *sline, int n, const char *line, int len) /* Check to see if we can squash things */ if (sline->lost_head) { - struct lline *last_one = NULL; - /* We cannot squash it with earlier one */ - for (lline = sline->lost_head; - lline; - lline = lline->next) - if (lline->parent_map & this_mask) - last_one = lline; - lline = last_one ? last_one->next : sline->lost_head; + lline = sline->next_lost; while (lline) { if (lline->len == len && !memcmp(lline->line, line, len)) { lline->parent_map |= this_mask; + sline->next_lost = lline->next; return; } lline = lline->next; @@ -147,6 +142,7 @@ static void append_lost(struct sline *sline, int n, const char *line, int len) lline->line[len] = 0; *sline->lost_tail = lline; sline->lost_tail = &lline->next; + sline->next_lost = NULL; } struct combine_diff_state { @@ -168,25 +164,28 @@ static void consume_line(void *state_, char *line, unsigned long len) &state->nb, &state->nn)) return; state->lno = state->nb; - if (!state->nb) - /* @@ -1,2 +0,0 @@ to remove the - * first two lines... - */ - state->nb = 1; - if (state->nn == 0) + if (state->nn == 0) { /* @@ -X,Y +N,0 @@ removed Y lines * that would have come *after* line N * in the result. Our lost buckets hang * to the line after the removed lines, + * + * Note that this is correct even when N == 0, + * in which case the hunk removes the first + * line in the file. */ state->lost_bucket = &state->sline[state->nb]; - else + if (!state->nb) + state->nb = 1; + } else { state->lost_bucket = &state->sline[state->nb-1]; + } if (!state->sline[state->nb-1].p_lno) state->sline[state->nb-1].p_lno = xcalloc(state->num_parent, sizeof(unsigned long)); state->sline[state->nb-1].p_lno[state->n] = state->ob; + state->lost_bucket->next_lost = state->lost_bucket->lost_head; return; } if (!state->lost_bucket) @@ -262,7 +262,11 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size) bufptr[47] != '\n') return error("bad parents in commit %s", sha1_to_hex(item->object.sha1)); bufptr += 48; - if (graft) + /* + * The clone is shallow if nr_parent < 0, and we must + * not traverse its real parents even when we unhide them. + */ + if (graft && (graft->nr_parent < 0 || grafts_replace_parents)) continue; new_parent = lookup_commit(parent); if (new_parent) @@ -62,7 +62,8 @@ static char *parse_value(void) if (comment) continue; if (isspace(c) && !quote) { - space = 1; + if (len) + space++; continue; } if (!quote) { @@ -71,11 +72,8 @@ static char *parse_value(void) continue; } } - if (space) { - if (len) - value[len++] = ' '; - space = 0; - } + for (; space; space--) + value[len++] = ' '; if (c == '\\') { c = get_next_char(); switch (c) { @@ -1174,7 +1172,9 @@ write_err_out: static int section_name_match (const char *buf, const char *name) { int i = 0, j = 0, dot = 0; - for (; buf[i] && buf[i] != ']'; i++) { + if (buf[i] != '[') + return 0; + for (i = 1; buf[i] && buf[i] != ']'; i++) { if (!dot && isspace(buf[i])) { dot = 1; if (name[j++] != '.') @@ -1195,7 +1195,17 @@ static int section_name_match (const char *buf, const char *name) if (buf[i] != name[j++]) break; } - return (buf[i] == ']' && name[j] == 0); + if (buf[i] == ']' && name[j] == 0) { + /* + * We match, now just find the right length offset by + * gobbling up any whitespace after it, as well + */ + i++; + for (; buf[i] && isspace(buf[i]); i++) + ; /* do nothing */ + return i; + } + return 0; } /* if new_name == NULL, the section is removed instead */ @@ -1225,11 +1235,13 @@ int git_config_rename_section(const char *old_name, const char *new_name) while (fgets(buf, sizeof(buf), config_file)) { int i; int length; + char *output = buf; for (i = 0; buf[i] && isspace(buf[i]); i++) ; /* do nothing */ if (buf[i] == '[') { /* it's a section */ - if (section_name_match (&buf[i+1], old_name)) { + int offset = section_name_match(&buf[i], old_name); + if (offset > 0) { ret++; if (new_name == NULL) { remove = 1; @@ -1240,14 +1252,29 @@ int git_config_rename_section(const char *old_name, const char *new_name) ret = write_error(lock->filename); goto out; } - continue; + /* + * We wrote out the new section, with + * a newline, now skip the old + * section's length + */ + output += offset + i; + if (strlen(output) > 0) { + /* + * More content means there's + * a declaration to put on the + * next line; indent with a + * tab + */ + output -= 1; + output[0] = '\t'; + } } remove = 0; } if (remove) continue; - length = strlen(buf); - if (write_in_full(out_fd, buf, length) != length) { + length = strlen(output); + if (write_in_full(out_fd, output, length) != length) { ret = write_error(lock->filename); goto out; } diff --git a/config.mak.in b/config.mak.in index dd60451318..67b12f73a1 100644 --- a/config.mak.in +++ b/config.mak.in @@ -34,6 +34,7 @@ NO_LIBGEN_H=@NO_LIBGEN_H@ NEEDS_LIBICONV=@NEEDS_LIBICONV@ NEEDS_SOCKET=@NEEDS_SOCKET@ NEEDS_RESOLV=@NEEDS_RESOLV@ +NEEDS_LIBGEN=@NEEDS_LIBGEN@ NO_SYS_SELECT_H=@NO_SYS_SELECT_H@ NO_D_INO_IN_DIRENT=@NO_D_INO_IN_DIRENT@ NO_D_TYPE_IN_DIRENT=@NO_D_TYPE_IN_DIRENT@ diff --git a/configure.ac b/configure.ac index 74d0af52a5..3f1922d0bf 100644 --- a/configure.ac +++ b/configure.ac @@ -342,9 +342,8 @@ GIT_STASH_FLAGS($OPENSSLDIR) AC_CHECK_LIB([crypto], [SHA1_Init], [NEEDS_SSL_WITH_CRYPTO=], [AC_CHECK_LIB([ssl], [SHA1_Init], - [NEEDS_SSL_WITH_CRYPTO=YesPlease - NEEDS_SSL_WITH_CRYPTO=], - [NO_OPENSSL=YesPlease])]) + [NEEDS_SSL_WITH_CRYPTO=YesPlease], + [NEEDS_SSL_WITH_CRYPTO= NO_OPENSSL=YesPlease])]) GIT_UNSTASH_FLAGS($OPENSSLDIR) @@ -479,13 +478,13 @@ test -n "$NEEDS_SOCKET" && LIBS="$LIBS -lsocket" # Define NEEDS_RESOLV if linking with -lnsl and/or -lsocket is not enough. # Notably on Solaris hstrerror resides in libresolv and on Solaris 7 # inet_ntop and inet_pton additionally reside there. -AC_CHECK_LIB([resolv], [hstrerror], +AC_CHECK_LIB([c], [hstrerror], [NEEDS_RESOLV=], [NEEDS_RESOLV=YesPlease]) AC_SUBST(NEEDS_RESOLV) test -n "$NEEDS_RESOLV" && LIBS="$LIBS -lresolv" -AC_CHECK_LIB([gen], [basename], +AC_CHECK_LIB([c], [basename], [NEEDS_LIBGEN=], [NEEDS_LIBGEN=YesPlease]) AC_SUBST(NEEDS_LIBGEN) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 9c488646d0..745b5fb78b 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -44,6 +44,10 @@ # GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed, # then a '$' will be shown next to the branch name. # +# If you would like to see if there're untracked files, then you can +# set GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're +# untracked files, then a '%' will be shown next to the branch name. +# # To submit patches: # # *) Read Documentation/SubmittingPatches @@ -132,6 +136,7 @@ __git_ps1 () local w local i local s + local u local c if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then @@ -156,12 +161,18 @@ __git_ps1 () if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$" fi + + if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then + if [ -n "$(git ls-files --others --exclude-standard)" ]; then + u="%" + fi + fi fi if [ -n "${1-}" ]; then - printf "$1" "$c${b##refs/heads/}$w$i$s$r" + printf "$1" "$c${b##refs/heads/}$w$i$s$u$r" else - printf " (%s)" "$c${b##refs/heads/}$w$i$s$r" + printf " (%s)" "$c${b##refs/heads/}$w$i$s$u$r" fi fi } @@ -1114,7 +1125,7 @@ _git_ls_tree () __git_log_common_options=" --not --all --branches --tags --remotes - --first-parent --no-merges + --first-parent --merges --no-merges --max-count= --max-age= --since= --after= --min-age= --until= --before= diff --git a/contrib/hg-to-git/hg-to-git.py b/contrib/hg-to-git/hg-to-git.py index 7b03204ed1..2a6839d81e 100755 --- a/contrib/hg-to-git/hg-to-git.py +++ b/contrib/hg-to-git/hg-to-git.py @@ -20,7 +20,7 @@ """ import os, os.path, sys -import tempfile, popen2, pickle, getopt +import tempfile, pickle, getopt import re # Maps hg version -> git version diff --git a/environment.c b/environment.c index 801a005ef1..8f5eaa7dd8 100644 --- a/environment.c +++ b/environment.c @@ -42,11 +42,12 @@ enum safe_crlf safe_crlf = SAFE_CRLF_WARN; unsigned whitespace_rule_cfg = WS_DEFAULT_RULE; enum branch_track git_branch_track = BRANCH_TRACK_REMOTE; enum rebase_setup_type autorebase = AUTOREBASE_NEVER; -enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED; +enum push_default_type push_default = PUSH_DEFAULT_MATCHING; #ifndef OBJECT_CREATION_MODE #define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS #endif enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; +int grafts_replace_parents = 1; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index 913f41a42c..9f941e42b1 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -26,6 +26,7 @@ #endif #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) +#define bitsizeof(x) (CHAR_BIT * sizeof(x)) #ifdef __GNUC__ #define TYPEOF(x) (__typeof__(x)) @@ -33,9 +34,11 @@ #define TYPEOF(x) #endif -#define MSB(x, bits) ((x) & TYPEOF(x)(~0ULL << (sizeof(x) * 8 - (bits)))) +#define MSB(x, bits) ((x) & TYPEOF(x)(~0ULL << (bitsizeof(x) - (bits)))) #define HAS_MULTI_BITS(i) ((i) & ((i) - 1)) /* checks if an integer has more than 1 bit set */ +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) + /* Approximation of the length of the decimal representation of this type. */ #define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) diff --git a/git-instaweb.sh b/git-instaweb.sh index 5f4419b69b..32f6496b0d 100755 --- a/git-instaweb.sh +++ b/git-instaweb.sh @@ -256,7 +256,7 @@ apache2_conf () { mkdir -p "$GIT_DIR/gitweb/logs" bind= test x"$local" = xtrue && bind='127.0.0.1:' - echo 'text/css css' > $fqgitdir/mime.types + echo 'text/css css' > "$fqgitdir/mime.types" cat > "$conf" <<EOF ServerName "git-instaweb" ServerRoot "$fqgitdir/gitweb" @@ -272,7 +272,7 @@ EOF fi done cat >> "$conf" <<EOF -TypesConfig $fqgitdir/mime.types +TypesConfig "$fqgitdir/mime.types" DirectoryIndex gitweb.cgi EOF diff --git a/git-pull.sh b/git-pull.sh index 4b78a0cd37..0f24182974 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -124,10 +124,18 @@ test true = "$rebase" && { git diff-index --ignore-submodules --cached --quiet HEAD -- || die "refusing to pull with rebase: your working tree is not up-to-date" + oldremoteref= && . git-parse-remote && - reflist="$(get_remote_merge_branch "$@" 2>/dev/null)" && - oldremoteref="$(git rev-parse -q --verify \ - "$reflist")" + remoteref="$(get_remote_merge_branch "$@" 2>/dev/null)" && + oldremoteref="$(git rev-parse -q --verify "$remoteref")" && + for reflog in $(git rev-list -g $remoteref 2>/dev/null) + do + if test "$reflog" = "$(git merge-base $reflog $curr_branch)" + then + oldremoteref="$reflog" + break + fi + done } orig_head=$(git rev-parse -q --verify HEAD) git fetch $verbosity --update-head-ok "$@" || exit 1 diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index f96d887d23..23ded48322 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -703,7 +703,7 @@ first and then run 'git rebase --continue' again." preserve=t for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-) do - if test -f "$REWRITTEN"/$p -a \( $p != $UPSTREAM -o $sha1 = $first_after_upstream \) + if test -f "$REWRITTEN"/$p -a \( $p != $ONTO -o $sha1 = $first_after_upstream \) then preserve=f fi diff --git a/git-repack.sh b/git-repack.sh index 1bf239499c..1eb3bca352 100755 --- a/git-repack.sh +++ b/git-repack.sh @@ -81,7 +81,7 @@ case ",$all_into_one," in esac args="$args $local ${GIT_QUIET:+-q} $no_reuse$extra" -names=$(git pack-objects --honor-pack-keep --non-empty --all --reflog $args </dev/null "$PACKTMP") || +names=$(git pack-objects --keep-true-parents --honor-pack-keep --non-empty --all --reflog $args </dev/null "$PACKTMP") || exit 1 if [ -z "$names" ]; then say Nothing new to pack. diff --git a/git-request-pull.sh b/git-request-pull.sh index 5917773240..630ceddf03 100755 --- a/git-request-pull.sh +++ b/git-request-pull.sh @@ -8,13 +8,33 @@ USAGE='<start> <url> [<end>]' LONG_USAGE='Summarizes the changes between two commits to the standard output, and includes the given URL in the generated summary.' SUBDIRECTORY_OK='Yes' -OPTIONS_SPEC= +OPTIONS_SPEC='git request-pull [options] start url [end] +-- +p show patch text as well +' + . git-sh-setup . git-parse-remote GIT_PAGER= export GIT_PAGER +patch= +while case "$#" in 0) break ;; esac +do + case "$1" in + -p) + patch=-p ;; + --) + shift; break ;; + -*) + usage ;; + *) + break ;; + esac + shift +done + base=$1 url=$2 head=${3-HEAD} @@ -28,13 +48,13 @@ headrev=`git rev-parse --verify "$head"^0` || exit merge_base=`git merge-base $baserev $headrev` || die "fatal: No commits in common between $base and $head" -url=$(get_remote_url "$url") branch=$(git ls-remote "$url" \ | sed -n -e "/^$headrev refs.heads./{ s/^.* refs.heads.// p q }") +url=$(get_remote_url "$url") if [ -z "$branch" ]; then echo "warn: No branch of $url is at:" >&2 git log --max-count=1 --pretty='tformat:warn: %h: %s' $headrev >&2 @@ -54,5 +74,5 @@ echo " $url $branch" echo git shortlog ^$baserev $headrev -git diff -M --stat --summary $merge_base $headrev +git diff -M --stat --summary $patch $merge_base..$headrev exit $status diff --git a/git-send-email.perl b/git-send-email.perl index 8ce6f1fe57..0700d80afc 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -450,7 +450,6 @@ sub check_file_rev_conflict($) { try { $repo->command('rev-parse', '--verify', '--quiet', $f); if (defined($format_patch)) { - print "foo\n"; return $format_patch; } die(<<EOF); @@ -654,13 +653,17 @@ if (!@to) { } sub expand_aliases { - my @cur = @_; - my @last; - do { - @last = @cur; - @cur = map { $aliases{$_} ? @{$aliases{$_}} : $_ } @last; - } while (join(',',@cur) ne join(',',@last)); - return @cur; + return map { expand_one_alias($_) } @_; +} + +my %EXPANDED_ALIASES; +sub expand_one_alias { + my $alias = shift; + if ($EXPANDED_ALIASES{$alias}) { + die "fatal: alias '$alias' expands to itself\n"; + } + local $EXPANDED_ALIASES{$alias} = 1; + return $aliases{$alias} ? expand_aliases(@{$aliases{$alias}}) : $alias; } @to = expand_aliases(@to); diff --git a/git-stash.sh b/git-stash.sh index 531c7c31ac..03e589f764 100755 --- a/git-stash.sh +++ b/git-stash.sh @@ -203,7 +203,7 @@ apply_stash () { git diff-tree --binary $s^2^..$s^2 | git apply --cached test $? -ne 0 && die 'Conflicts in index. Try without --index.' - unstashed_index_tree=$(git-write-tree) || + unstashed_index_tree=$(git write-tree) || die 'Could not save index tree' git reset fi @@ -219,7 +219,7 @@ apply_stash () { then export GIT_MERGE_VERBOSITY=0 fi - if git-merge-recursive $b_tree -- $c_tree $w_tree + if git merge-recursive $b_tree -- $c_tree $w_tree then # No conflict if test -n "$unstashed_index_tree" @@ -297,7 +297,7 @@ apply_to_branch () { fi stash=$2 - git-checkout -b $branch $stash^ && + git checkout -b $branch $stash^ && apply_stash --index $stash && drop_stash $stash } diff --git a/git-svn.perl b/git-svn.perl index d1af1a3d2f..d075810724 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -19,6 +19,7 @@ $ENV{GIT_DIR} ||= '.git'; $Git::SVN::default_repo_id = 'svn'; $Git::SVN::default_ref_id = $ENV{GIT_SVN_ID} || 'git-svn'; $Git::SVN::Ra::_log_window_size = 100; +$Git::SVN::_minimize_url = 'unset'; $Git::SVN::Log::TZ = $ENV{TZ}; $ENV{TZ} = 'UTC'; @@ -31,6 +32,7 @@ require SVN::Delta; if ($SVN::Core::VERSION lt '1.1.0') { fatal "Need SVN::Core 1.1.0 or better (got $SVN::Core::VERSION)"; } +my $can_compress = eval { require Compress::Zlib; 1}; push @Git::SVN::Ra::ISA, 'SVN::Ra'; push @SVN::Git::Editor::ISA, 'SVN::Delta::Editor'; push @SVN::Git::Fetcher::ISA, 'SVN::Delta::Editor'; @@ -40,6 +42,7 @@ use IO::File qw//; use File::Basename qw/dirname basename/; use File::Path qw/mkpath/; use File::Spec; +use File::Find; use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/; use IPC::Open3; use Git; @@ -98,7 +101,7 @@ my %init_opts = ( 'template=s' => \$_template, 'shared:s' => \$_shared, 'trunk|T=s' => \$_trunk, 'tags|t=s@' => \@_tags, 'branches|b=s@' => \@_branches, 'prefix=s' => \$_prefix, 'stdlayout|s' => \$_stdlayout, - 'minimize-url|m' => \$Git::SVN::_minimize_url, + 'minimize-url|m!' => \$Git::SVN::_minimize_url, 'no-metadata' => sub { $icv{noMetadata} = 1 }, 'use-svm-props' => sub { $icv{useSvmProps} = 1 }, 'use-svnsync-props' => sub { $icv{useSvnsyncProps} = 1 }, @@ -217,6 +220,10 @@ my %cmd = ( "Undo fetches back to the specified SVN revision", { 'revision|r=s' => \$_revision, 'parent|p' => \$_fetch_parent } ], + 'gc' => [ \&cmd_gc, + "Compress unhandled.log files in .git/svn and remove " . + "index files in .git/svn", + {} ], ); my $cmd; @@ -393,6 +400,10 @@ sub cmd_init { init_subdir(@_); do_git_init_db(); + if ($Git::SVN::_minimize_url eq 'unset') { + $Git::SVN::_minimize_url = 0; + } + Git::SVN->init($url); } @@ -655,9 +666,22 @@ sub cmd_branch { } } unless (defined $glob) { - die "Unknown ", - $_tag ? "tag" : "branch", - " destination $_branch_dest\n"; + my $dest_re = qr/\b\Q$_branch_dest\E\b/; + foreach my $g (@{$allglobs}) { + $g->{path}->{left} =~ /$dest_re/ or next; + if (defined $glob) { + die "Ambiguous destination: ", + $_branch_dest, "\nmatches both '", + $glob->{path}->{left}, "' and '", + $g->{path}->{left}, "'\n"; + } + $glob = $g; + } + unless (defined $glob) { + die "Unknown ", + $_tag ? "tag" : "branch", + " destination $_branch_dest\n"; + } } } my ($lft, $rgt) = @{ $glob->{path} }{qw/left right/}; @@ -876,10 +900,6 @@ sub cmd_multi_init { usage(1); } - # there are currently some bugs that prevent multi-init/multi-fetch - # setups from working well without this. - $Git::SVN::_minimize_url = 1; - $_prefix = '' unless defined $_prefix; if (defined $url) { $url = canonicalize_url($url); @@ -1111,6 +1131,14 @@ sub cmd_reset { print "r$r = $c ($gs->{ref_id})\n"; } +sub cmd_gc { + if (!$can_compress) { + warn "Compress::Zlib could not be found; unhandled.log " . + "files will not be compressed.\n"; + } + find({ wanted => \&gc_directory, no_chdir => 1}, "$ENV{GIT_DIR}/svn"); +} + ########################### utility functions ######################### sub rebase_cmd { @@ -1180,7 +1208,7 @@ sub complete_url_ls_init { "wanted to set to: $gs->{url}\n"; } command_oneline('config', $k, $gs->{url}) unless $orig_url; - my $remote_path = "$ra->{svn_path}/$repo_path"; + my $remote_path = "$gs->{path}/$repo_path"; $remote_path =~ s#/+#/#g; $remote_path =~ s#^/##g; $remote_path .= "/*" if $remote_path !~ /\*/; @@ -1363,11 +1391,11 @@ sub read_repo_config { sub extract_metadata { my $id = shift or return (undef, undef, undef); my ($url, $rev, $uuid) = ($id =~ /^\s*git-svn-id:\s+(.*)\@(\d+) - \s([a-f\d\-]+)$/x); + \s([a-f\d\-]+)$/ix); if (!defined $rev || !$uuid || !$url) { # some of the original repositories I made had # identifiers like this: - ($rev, $uuid) = ($id =~/^\s*git-svn-id:\s(\d+)\@([a-f\d\-]+)/); + ($rev, $uuid) = ($id =~/^\s*git-svn-id:\s(\d+)\@([a-f\d\-]+)/i); } return ($url, $rev, $uuid); } @@ -1531,6 +1559,25 @@ sub md5sum { return $md5->hexdigest(); } +sub gc_directory { + if ($can_compress && -f $_ && basename($_) eq "unhandled.log") { + my $out_filename = $_ . ".gz"; + open my $in_fh, "<", $_ or die "Unable to open $_: $!\n"; + binmode $in_fh; + my $gz = Compress::Zlib::gzopen($out_filename, "ab") or + die "Unable to open $out_filename: $!\n"; + + my $res; + while ($res = sysread($in_fh, my $str, 1024)) { + $gz->gzwrite($str) or + die "Unable to write: ".$gz->gzerror()."!\n"; + } + unlink $_ or die "unlink $File::Find::name: $!\n"; + } elsif (-f $_ && basename($_) eq "index") { + unlink $_ or die "unlink $_: $!\n"; + } +} + package Git::SVN; use strict; use warnings; @@ -1651,6 +1698,7 @@ sub fetch_all { my $ra = Git::SVN::Ra->new($url); my $uuid = $ra->get_uuid; my $head = $ra->get_latest_revnum; + $ra->get_log("", $head, 0, 1, 0, 1, sub { $head = $_[1] }); my $base = defined $fetch ? $head : 0; # read the max revs for wildcard expansion (branches/*, tags/*) @@ -2014,7 +2062,7 @@ sub _set_svm_vars { chomp($src, $uuid); - $uuid =~ m{^[0-9a-f\-]{30,}$} + $uuid =~ m{^[0-9a-f\-]{30,}$}i or die "doesn't look right - svm:uuid is '$uuid'\n"; # the '!' is used to mark the repos_root!/relative/path @@ -2100,7 +2148,7 @@ sub svnsync { die "doesn't look right - svn:sync-from-url is '$url'\n"; my $uuid = tmp_config('--get', "$section.svnsync-uuid"); - ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}) or + ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or die "doesn't look right - svn:sync-from-uuid is '$uuid'\n"; $svnsync = { url => $url, uuid => $uuid } @@ -2118,7 +2166,7 @@ sub svnsync { die "doesn't look right - svn:sync-from-url is '$url'\n"; my $uuid = $rp->{'svn:sync-from-uuid'} or die $err . "uuid\n"; - ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}) or + ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or die "doesn't look right - svn:sync-from-uuid is '$uuid'\n"; my $section = "svn-remote.$self->{repo_id}"; @@ -2134,7 +2182,7 @@ sub ra_uuid { unless ($self->{ra_uuid}) { my $key = "svn-remote.$self->{repo_id}.uuid"; my $uuid = eval { tmp_config('--get', $key) }; - if (!$@ && $uuid && $uuid =~ /^([a-f\d\-]{30,})$/) { + if (!$@ && $uuid && $uuid =~ /^([a-f\d\-]{30,})$/i) { $self->{ra_uuid} = $uuid; } else { die "ra_uuid called without URL\n" unless $self->{url}; @@ -2177,16 +2225,6 @@ sub ra { $ra; } -sub rel_path { - my ($self) = @_; - my $repos_root = $self->ra->{repos_root}; - return $self->{path} if ($self->{url} eq $repos_root); - my $url = $self->{url} . - (length $self->{path} ? "/$self->{path}" : $self->{path}); - $url =~ s!^\Q$repos_root\E(?:/+|$)!!g; - $url; -} - # prop_walk(PATH, REV, SUB) # ------------------------- # Recursively traverse PATH at revision REV and invoke SUB for each @@ -2512,10 +2550,7 @@ sub match_paths { if (my $path = $paths->{"/$self->{path}"}) { return ($path->{action} eq 'D') ? 0 : 1; } - my $repos_root = $self->ra->{repos_root}; - my $extended_path = $self->{url} . '/' . $self->{path}; - $extended_path =~ s#^\Q$repos_root\E(/|$)##; - $self->{path_regex} ||= qr/^\/\Q$extended_path\E\//; + $self->{path_regex} ||= qr/^\/\Q$self->{path}\E\//; if (grep /$self->{path_regex}/, keys %$paths) { return 1; } @@ -2538,15 +2573,14 @@ sub find_parent_branch { unless (defined $paths) { my $err_handler = $SVN::Error::handler; $SVN::Error::handler = \&Git::SVN::Ra::skip_unknown_revs; - $self->ra->get_log([$self->{path}], $rev, $rev, 0, 1, 1, sub { - $paths = - Git::SVN::Ra::dup_changed_paths($_[0]) }); + $self->ra->get_log([$self->{path}], $rev, $rev, 0, 1, 1, + sub { $paths = $_[0] }); $SVN::Error::handler = $err_handler; } return undef unless defined $paths; # look for a parent from another branch: - my @b_path_components = split m#/#, $self->rel_path; + my @b_path_components = split m#/#, $self->{path}; my @a_path_components; my $i; while (@b_path_components) { @@ -2564,11 +2598,11 @@ sub find_parent_branch { my $r = $i->{copyfrom_rev}; my $repos_root = $self->ra->{repos_root}; my $url = $self->ra->{url}; - my $new_url = $repos_root . $branch_from; + my $new_url = $url . $branch_from; print STDERR "Found possible branch point: ", "$new_url => ", $self->full_url, ", $r\n"; $branch_from =~ s#^/##; - my $gs = $self->other_gs($new_url, $url, $repos_root, + my $gs = $self->other_gs($new_url, $url, $branch_from, $r, $self->{ref_id}); my ($r0, $parent) = $gs->find_rev_before($r, 1); { @@ -2753,9 +2787,9 @@ sub parse_svn_date { } sub other_gs { - my ($self, $new_url, $url, $repos_root, + my ($self, $new_url, $url, $branch_from, $r, $old_ref_id) = @_; - my $gs = Git::SVN->find_by_url($new_url, $repos_root, $branch_from); + my $gs = Git::SVN->find_by_url($new_url, $url, $branch_from); unless ($gs) { my $ref_id = $old_ref_id; $ref_id =~ s/\@\d+$//; @@ -2866,7 +2900,7 @@ sub make_log_entry { die "Can't have both 'useSvmProps' and 'rewriteRoot' ", "options set!\n"; } - my ($uuid, $r) = $headrev =~ m{^([a-f\d\-]{30,}):(\d+)$}; + my ($uuid, $r) = $headrev =~ m{^([a-f\d\-]{30,}):(\d+)$}i; # we don't want "SVM: initializing mirror for junk" ... return undef if $r == 0; my $svm = $self->svm; @@ -3971,7 +4005,7 @@ sub repo_path { sub url_path { my ($self, $path) = @_; if ($self->{url} =~ m#^https?://#) { - $path =~ s/([^~a-zA-Z0-9_.-])/uc sprintf("%%%02x",ord($1))/eg; + $path =~ s!([^~a-zA-Z0-9_./-])!uc sprintf("%%%02x",ord($1))!eg; } $self->{url} . '/' . $self->repo_path($path); } @@ -4431,6 +4465,34 @@ sub get_log { my ($self, @args) = @_; my $pool = SVN::Pool->new; + # svn_log_changed_path_t objects passed to get_log are likely to be + # overwritten even if only the refs are copied to an external variable, + # so we should dup the structures in their entirety. Using an + # externally passed pool (instead of our temporary and quickly cleared + # pool in Git::SVN::Ra) does not help matters at all... + my $receiver = pop @args; + my $prefix = "/".$self->{svn_path}; + $prefix =~ s#/+($)##; + my $prefix_regex = qr#^\Q$prefix\E#; + push(@args, sub { + my ($paths) = $_[0]; + return &$receiver(@_) unless $paths; + $_[0] = (); + foreach my $p (keys %$paths) { + my $i = $paths->{$p}; + # Make path relative to our url, not repos_root + $p =~ s/$prefix_regex//; + my %s = map { $_ => $i->$_; } + qw/copyfrom_path copyfrom_rev action/; + if ($s{'copyfrom_path'}) { + $s{'copyfrom_path'} =~ s/$prefix_regex//; + } + $_[0]{$p} = \%s; + } + &$receiver(@_); + }); + + # the limit parameter was not supported in SVN 1.1.x, so we # drop it. Therefore, the receiver callback passed to it # is made aware of this limitation by being wrapped if @@ -4515,10 +4577,12 @@ sub gs_do_switch { my $full_url = $self->{url}; my $old_url = $full_url; - $full_url .= '/' . escape_uri_only($path) if length $path; + $full_url .= '/' . $path if length $path; my ($ra, $reparented); - if ($old_url =~ m#^svn(\+ssh)?://#) { + if ($old_url =~ m#^svn(\+ssh)?://# || + ($full_url =~ m#^https?://# && + escape_url($full_url) ne $full_url)) { $_[0] = undef; $self = undef; $RA = undef; @@ -4600,7 +4664,7 @@ sub gs_fetch_loop_common { }; sub _cb { my ($paths, $r, $author, $date, $log) = @_; - [ dup_changed_paths($paths), + [ $paths, { author => $author, date => $date, log => $log } ]; } $self->get_log([$longest_path], $min, $max, 0, 1, 1, @@ -4767,7 +4831,11 @@ sub minimize_url { my $c = ''; do { $url .= "/$c" if length $c; - eval { (ref $self)->new($url)->get_latest_revnum }; + eval { + my $ra = (ref $self)->new($url); + my $latest = $ra->get_latest_revnum; + $ra->get_log("", $latest, 0, 1, 0, 1, sub {}); + }; } while ($@ && ($c = shift @components)); $url; } @@ -4823,24 +4891,6 @@ sub skip_unknown_revs { die "Error from SVN, ($errno): ", $err->expanded_message,"\n"; } -# svn_log_changed_path_t objects passed to get_log are likely to be -# overwritten even if only the refs are copied to an external variable, -# so we should dup the structures in their entirety. Using an externally -# passed pool (instead of our temporary and quickly cleared pool in -# Git::SVN::Ra) does not help matters at all... -sub dup_changed_paths { - my ($paths) = @_; - return undef unless $paths; - my %ret; - foreach my $p (keys %$paths) { - my $i = $paths->{$p}; - my %s = map { $_ => $i->$_ } - qw/copyfrom_path copyfrom_rev action/; - $ret{$p} = \%s; - } - \%ret; -} - package Git::SVN::Log; use strict; use warnings; diff --git a/gitweb/README b/gitweb/README index 9056d1e090..66c6a9391d 100644 --- a/gitweb/README +++ b/gitweb/README @@ -165,6 +165,12 @@ not include variables usually directly set during build): Full URL and absolute URL of gitweb script; in earlier versions of gitweb you might have need to set those variables, now there should be no need to do it. + * $base_url + Base URL for relative URLs in pages generated by gitweb, + (e.g. $logo, $favicon, @stylesheets if they are relative URLs), + needed and used only for URLs with nonempty PATH_INFO via + <base href="$base_url>. Usually gitweb sets its value correctly, + and there is no need to set this variable, e.g. to $my_uri or "/". * $home_link Target of the home link on top of all pages (the first part of view "breadcrumbs"). By default set to absolute URI of a page ($my_uri). diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 6a1b5b5b49..37120a3e60 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -94,7 +94,7 @@ our $favicon = "++GITWEB_FAVICON++"; # URI and label (title) of GIT logo link #our $logo_url = "http://www.kernel.org/pub/software/scm/git/docs/"; #our $logo_label = "git documentation"; -our $logo_url = "http://git.or.cz/"; +our $logo_url = "http://git-scm.com/"; our $logo_label = "git homepage"; # source of projects list @@ -940,10 +940,13 @@ sub href { if (defined $params{'hash_parent_base'}) { $href .= esc_url($params{'hash_parent_base'}); # skip the file_parent if it's the same as the file_name - delete $params{'file_parent'} if $params{'file_parent'} eq $params{'file_name'}; - if (defined $params{'file_parent'} && $params{'file_parent'} !~ /\.\./) { - $href .= ":/".esc_url($params{'file_parent'}); - delete $params{'file_parent'}; + if (defined $params{'file_parent'}) { + if (defined $params{'file_name'} && $params{'file_parent'} eq $params{'file_name'}) { + delete $params{'file_parent'}; + } elsif ($params{'file_parent'} !~ /\.\./) { + $href .= ":/".esc_url($params{'file_parent'}); + delete $params{'file_parent'}; + } } $href .= ".."; delete $params{'hash_parent'}; @@ -893,7 +893,7 @@ static struct column *find_new_column_by_commit(struct git_graph *graph, if (graph->new_columns[i].commit == commit) return &graph->new_columns[i]; } - return 0; + return NULL; } static void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb) @@ -100,7 +100,7 @@ static void pretty_print_string_list(struct cmdnames *cmds, int longest) if (space < max_cols) cols = max_cols / space; - rows = (cmds->cnt + cols - 1) / cols; + rows = DIV_ROUND_UP(cmds->cnt, cols); for (i = 0; i < rows; i++) { printf(" "); diff --git a/pack-revindex.c b/pack-revindex.c index 1de53c8934..77a0465be6 100644 --- a/pack-revindex.c +++ b/pack-revindex.c @@ -149,8 +149,7 @@ void discard_revindex(void) if (pack_revindex_hashsz) { int i; for (i = 0; i < pack_revindex_hashsz; i++) - if (pack_revindex[i].revindex) - free(pack_revindex[i].revindex); + free(pack_revindex[i].revindex); free(pack_revindex); pack_revindex_hashsz = 0; } diff --git a/parse-options.c b/parse-options.c index f7ce523a61..3b71fbb541 100644 --- a/parse-options.c +++ b/parse-options.c @@ -511,7 +511,7 @@ static int usage_with_options_internal(const char * const *usagestr, continue; pos = fprintf(stderr, " "); - if (opts->short_name) { + if (opts->short_name && !(opts->flags & PARSE_OPT_NEGHELP)) { if (opts->flags & PARSE_OPT_NODASH) pos += fprintf(stderr, "%c", opts->short_name); else @@ -520,7 +520,9 @@ static int usage_with_options_internal(const char * const *usagestr, if (opts->long_name && opts->short_name) pos += fprintf(stderr, ", "); if (opts->long_name) - pos += fprintf(stderr, "--%s", opts->long_name); + pos += fprintf(stderr, "--%s%s", + (opts->flags & PARSE_OPT_NEGHELP) ? "no-" : "", + opts->long_name); if (opts->type == OPTION_NUMBER) pos += fprintf(stderr, "-NUM"); diff --git a/parse-options.h b/parse-options.h index aba30671dc..b32587ad7c 100644 --- a/parse-options.h +++ b/parse-options.h @@ -36,6 +36,7 @@ enum parse_opt_option_flags { PARSE_OPT_LASTARG_DEFAULT = 16, PARSE_OPT_NODASH = 32, PARSE_OPT_LITERAL_ARGHELP = 64, + PARSE_OPT_NEGHELP = 128, }; struct option; @@ -80,6 +81,9 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset); * PARSE_OPT_LITERAL_ARGHELP: says that argh shouldn't be enclosed in brackets * (i.e. '<argh>') in the help message. * Useful for options with multiple parameters. + * PARSE_OPT_NEGHELP: says that the long option should always be shown with + * the --no prefix in the usage message. Sometimes + * useful for users of OPTION_NEGBIT. * * `callback`:: * pointer to the callback to use for OPTION_CALLBACK. diff --git a/preload-index.c b/preload-index.c index 14d5281183..92899333c2 100644 --- a/preload-index.c +++ b/preload-index.c @@ -76,7 +76,7 @@ static void preload_index(struct index_state *index, const char **pathspec) if (threads > MAX_PARALLEL) threads = MAX_PARALLEL; offset = 0; - work = (index->cache_nr + threads - 1) / threads; + work = DIV_ROUND_UP(index->cache_nr, threads); for (i = 0; i < threads; i++) { struct thread_data *p = data+i; p->index = index; @@ -531,9 +531,10 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim, { if (strncmp(base, entry->name, trim)) return 0; + /* Is this a "negative ref" that represents a deleted ref? */ + if (is_null_sha1(entry->sha1)) + return 0; if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN)) { - if (is_null_sha1(entry->sha1)) - return 0; if (!has_sha1_file(entry->sha1)) { error("%s does not point to a valid object!", entry->name); return 0; @@ -1525,8 +1526,10 @@ int for_each_recent_reflog_ent(const char *ref, each_reflog_ent_fn fn, long ofs, if (fstat(fileno(logfp), &statbuf) || statbuf.st_size < ofs || fseek(logfp, -ofs, SEEK_END) || - fgets(buf, sizeof(buf), logfp)) + fgets(buf, sizeof(buf), logfp)) { + fclose(logfp); return -1; + } } while (fgets(buf, sizeof(buf), logfp)) { diff --git a/revision.c b/revision.c index a31434bdc8..9f5dac5f1d 100644 --- a/revision.c +++ b/revision.c @@ -133,7 +133,7 @@ void mark_parents_uninteresting(struct commit *commit) static void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode) { if (revs->no_walk && (obj->flags & UNINTERESTING)) - die("object ranges do not make sense when not walking revisions"); + revs->no_walk = 0; if (revs->reflog_info && obj->type == OBJ_COMMIT && add_reflog_for_walk(revs->reflog_info, (struct commit *)obj, name)) diff --git a/sha1_file.c b/sha1_file.c index 4576ff77f3..1d996a1990 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -1170,7 +1170,7 @@ unsigned long unpack_object_header_buffer(const unsigned char *buf, size = c & 15; shift = 4; while (c & 0x80) { - if (len <= used || sizeof(long) * 8 <= shift) { + if (len <= used || bitsizeof(long) <= shift) { error("bad object header"); return 0; } diff --git a/sha1_name.c b/sha1_name.c index 904bcd96a5..44bb62d270 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -777,8 +777,6 @@ int interpret_branch_name(const char *name, struct strbuf *buf) for_each_recent_reflog_ent("HEAD", grab_nth_branch_switch, 40960, &cb); if (cb.cnt < nth) { cb.cnt = 0; - for (i = 0; i < nth; i++) - strbuf_release(&cb.buf[i]); for_each_reflog_ent("HEAD", grab_nth_branch_switch, &cb); } if (cb.cnt < nth) diff --git a/t/lib-cvs.sh b/t/lib-cvs.sh new file mode 100644 index 0000000000..4b3b793730 --- /dev/null +++ b/t/lib-cvs.sh @@ -0,0 +1,75 @@ +#!/bin/sh + +. ./test-lib.sh + +unset CVS_SERVER +# for clean cvsps cache +HOME=$(pwd) +export HOME + +if ! type cvs >/dev/null 2>&1 +then + say 'skipping cvsimport tests, cvs not found' + test_done +fi + +CVS="cvs -f" +export CVS + +cvsps_version=`cvsps -h 2>&1 | sed -ne 's/cvsps version //p'` +case "$cvsps_version" in +2.1 | 2.2*) + ;; +'') + say 'skipping cvsimport tests, cvsps not found' + test_done + ;; +*) + say 'skipping cvsimport tests, unsupported cvsps version' + test_done + ;; +esac + +test_cvs_co () { + # Usage: test_cvs_co BRANCH_NAME + rm -rf module-cvs-"$1" + if [ "$1" = "master" ] + then + $CVS co -P -d module-cvs-"$1" -A module + else + $CVS co -P -d module-cvs-"$1" -r "$1" module + fi +} + +test_git_co () { + # Usage: test_git_co BRANCH_NAME + (cd module-git && git checkout "$1") +} + +test_cmp_branch_file () { + # Usage: test_cmp_branch_file BRANCH_NAME PATH + # The branch must already be checked out of CVS and git. + test_cmp module-cvs-"$1"/"$2" module-git/"$2" +} + +test_cmp_branch_tree () { + # Usage: test_cmp_branch_tree BRANCH_NAME + # Check BRANCH_NAME out of CVS and git and make sure that all + # of the files and directories are identical. + + test_cvs_co "$1" && + test_git_co "$1" && + ( + cd module-cvs-"$1" + find . -type d -name CVS -prune -o -type f -print + ) | sort >module-cvs-"$1".list && + ( + cd module-git + find . -type d -name .git -prune -o -type f -print + ) | sort >module-git-"$1".list && + test_cmp module-cvs-"$1".list module-git-"$1".list && + cat module-cvs-"$1".list | while read f + do + test_cmp_branch_file "$1" "$f" || return 1 + done +} diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 43ea283242..83b7294010 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -460,6 +460,28 @@ EOF test_expect_success "rename succeeded" "test_cmp expect .git/config" cat >> .git/config << EOF +[branch "vier"] z = 1 +EOF + +test_expect_success "rename a section with a var on the same line" \ + 'git config --rename-section branch.vier branch.zwei' + +cat > expect << EOF +# Hallo + #Bello +[branch "zwei"] + x = 1 +[branch "zwei"] + y = 1 +[branch "drei"] +weird +[branch "zwei"] + z = 1 +EOF + +test_expect_success "rename succeeded" "test_cmp expect .git/config" + +cat >> .git/config << EOF [branch "zwei"] a = 1 [branch "vier"] EOF @@ -733,6 +755,11 @@ echo >>result test_expect_success '--null --get-regexp' 'cmp result expect' +test_expect_success 'inner whitespace kept verbatim' ' + git config section.val "foo bar" && + test "z$(git config section.val)" = "zfoo bar" +' + test_expect_success SYMLINKS 'symlinked configuration' ' ln -s notyet myconfig && diff --git a/t/t3414-rebase-preserve-onto.sh b/t/t3414-rebase-preserve-onto.sh new file mode 100755 index 0000000000..80019ee072 --- /dev/null +++ b/t/t3414-rebase-preserve-onto.sh @@ -0,0 +1,80 @@ +#!/bin/sh +# +# Copyright (c) 2009 Greg Price +# + +test_description='git rebase -p should respect --onto + +In a rebase with --onto, we should rewrite all the commits that +aren'"'"'t on top of $ONTO, even if they are on top of $UPSTREAM. +' +. ./test-lib.sh + +. ../lib-rebase.sh + +# Set up branches like this: +# A1---B1---E1---F1---G1 +# \ \ / +# \ \--C1---D1--/ +# H1 + +test_expect_success 'setup' ' + test_commit A1 && + test_commit B1 && + test_commit C1 && + test_commit D1 && + git reset --hard B1 && + test_commit E1 && + test_commit F1 && + test_merge G1 D1 && + git reset --hard A1 && + test_commit H1 +' + +# Now rebase merge G1 from both branches' base B1, both should move: +# A1---B1---E1---F1---G1 +# \ \ / +# \ \--C1---D1--/ +# \ +# H1---E2---F2---G2 +# \ / +# \--C2---D2--/ + +test_expect_success 'rebase from B1 onto H1' ' + git checkout G1 && + git rebase -p --onto H1 B1 && + test "$(git rev-parse HEAD^1^1^1)" = "$(git rev-parse H1)" && + test "$(git rev-parse HEAD^2^1^1)" = "$(git rev-parse H1)" +' + +# On the other hand if rebase from E1 which is within one branch, +# then the other branch stays: +# A1---B1---E1---F1---G1 +# \ \ / +# \ \--C1---D1--/ +# \ \ +# H1-----F3-----G3 + +test_expect_success 'rebase from E1 onto H1' ' + git checkout G1 && + git rebase -p --onto H1 E1 && + test "$(git rev-parse HEAD^1^1)" = "$(git rev-parse H1)" && + test "$(git rev-parse HEAD^2)" = "$(git rev-parse D1)" +' + +# And the same if we rebase from a commit in the second-parent branch. +# A1---B1---E1---F1----G1 +# \ \ \ / +# \ \--C1---D1-\-/ +# \ \ +# H1------D3------G4 + +test_expect_success 'rebase from C1 onto H1' ' + git checkout G1 && + git rev-list --first-parent --pretty=oneline C1..G1 && + git rebase -p --onto H1 C1 && + test "$(git rev-parse HEAD^2^1)" = "$(git rev-parse H1)" && + test "$(git rev-parse HEAD^1)" = "$(git rev-parse F1)" +' + +test_done diff --git a/t/t4038-diff-combined.sh b/t/t4038-diff-combined.sh new file mode 100755 index 0000000000..2cf7e01ac2 --- /dev/null +++ b/t/t4038-diff-combined.sh @@ -0,0 +1,84 @@ +#!/bin/sh + +test_description='combined diff' + +. ./test-lib.sh + +setup_helper () { + one=$1 branch=$2 side=$3 && + + git branch $side $branch && + for l in $one two three fyra + do + echo $l + done >file && + git add file && + test_tick && + git commit -m $branch && + git checkout $side && + for l in $one two three quatro + do + echo $l + done >file && + git add file && + test_tick && + git commit -m $side && + test_must_fail git merge $branch && + for l in $one three four + do + echo $l + done >file && + git add file && + test_tick && + git commit -m "merge $branch into $side" +} + +verify_helper () { + it=$1 && + + # Ignore lines that were removed only from the other parent + sed -e ' + 1,/^@@@/d + /^ -/d + s/^\(.\)./\1/ + ' "$it" >"$it.actual.1" && + sed -e ' + 1,/^@@@/d + /^- /d + s/^.\(.\)/\1/ + ' "$it" >"$it.actual.2" && + + git diff "$it^" "$it" -- | sed -e '1,/^@@/d' >"$it.expect.1" && + test_cmp "$it.expect.1" "$it.actual.1" && + + git diff "$it^2" "$it" -- | sed -e '1,/^@@/d' >"$it.expect.2" && + test_cmp "$it.expect.2" "$it.actual.2" +} + +test_expect_success setup ' + >file && + git add file && + test_tick && + git commit -m initial && + + git branch withone && + git branch sansone && + + git checkout withone && + setup_helper one withone sidewithone && + + git checkout sansone && + setup_helper "" sansone sidesansone +' + +test_expect_success 'check combined output (1)' ' + git show sidewithone -- >sidewithone && + verify_helper sidewithone +' + +test_expect_failure 'check combined output (2)' ' + git show sidesansone -- >sidesansone && + verify_helper sidesansone +' + +test_done diff --git a/t/t4124-apply-ws-rule.sh b/t/t4124-apply-ws-rule.sh index f83322e513..fac2093d7f 100755 --- a/t/t4124-apply-ws-rule.sh +++ b/t/t4124-apply-ws-rule.sh @@ -148,4 +148,26 @@ do done done +create_patch () { + sed -e "s/_/ /" <<-\EOF + diff --git a/target b/target + index e69de29..8bd6648 100644 + --- a/target + +++ b/target + @@ -0,0 +1,3 @@ + +An empty line follows + + + +A line with trailing whitespace and no newline_ + \ No newline at end of file + EOF +} + +test_expect_success 'trailing whitespace & no newline at the end of file' ' + >target && + create_patch >patch-file && + git apply --whitespace=fix patch-file && + grep "newline$" target && + grep "^$" target +' + test_done diff --git a/t/t4202-log.sh b/t/t4202-log.sh index aad3894ad4..48e0088b47 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -149,6 +149,26 @@ test_expect_success 'git log --follow' ' ' +cat > expect << EOF +804a787 sixth +394ef78 fifth +5d31159 fourth +EOF +test_expect_success 'git log --no-walk <commits> sorts by commit time' ' + git log --no-walk --oneline 5d31159 804a787 394ef78 > actual && + test_cmp expect actual +' + +cat > expect << EOF +5d31159 fourth +804a787 sixth +394ef78 fifth +EOF +test_expect_success 'git show <commits> leaves list of commits as given' ' + git show --oneline -s 5d31159 804a787 394ef78 > actual && + test_cmp expect actual +' + test_expect_success 'setup case sensitivity tests' ' echo case >one && test_tick && diff --git a/t/t5100/info0012 b/t/t5100/info0012 index 9cd1415d25..ac1216ff75 100644 --- a/t/t5100/info0012 +++ b/t/t5100/info0012 @@ -1,5 +1,5 @@ Author: Dmitriy Blinov Email: bda@mnsspb.ru -Subject: [Navy-patches] Изменён ÑпиÑок пакетов необходимых Ð´Ð»Ñ Ñборки +Subject: Изменён ÑпиÑок пакетов необходимых Ð´Ð»Ñ Ñборки Date: Wed, 12 Nov 2008 17:54:41 +0300 diff --git a/t/t5100/sample.mbox b/t/t5100/sample.mbox index 3a757d7d8f..c3074ac573 100644 --- a/t/t5100/sample.mbox +++ b/t/t5100/sample.mbox @@ -514,7 +514,7 @@ MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit -Subject: [PATCH] [Navy-patches] +Subject: [Navy-patches] [PATCH] =?utf-8?b?0JjQt9C80LXQvdGR0L0g0YHQv9C40YHQvtC6INC/0LA=?= =?utf-8?b?0LrQtdGC0L7QsiDQvdC10L7QsdGF0L7QtNC40LzRi9GFINC00LvRjyA=?= =?utf-8?b?0YHQsdC+0YDQutC4?= diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh index c5a2e66a09..e78d40242a 100755 --- a/t/t5520-pull.sh +++ b/t/t5520-pull.sh @@ -117,6 +117,19 @@ test_expect_success '--rebase with rebased default upstream' ' ' +test_expect_success 'rebased upstream + fetch + pull --rebase' ' + + git update-ref refs/remotes/me/copy copy-orig && + git reset --hard to-rebase-orig && + git checkout --track -b to-rebase3 me/copy && + git reset --hard to-rebase-orig && + git fetch && + git pull --rebase && + test "conflicting modification" = "$(cat file)" && + test file = "$(cat file2)" + +' + test_expect_success 'pull --rebase dies early with dirty working directory' ' git checkout to-rebase && diff --git a/t/t5530-upload-pack-error.sh b/t/t5530-upload-pack-error.sh index f5102b902a..757cc19ecc 100755 --- a/t/t5530-upload-pack-error.sh +++ b/t/t5530-upload-pack-error.sh @@ -30,11 +30,12 @@ test_expect_success 'fsck fails' ' test_must_fail git fsck ' -test_expect_success 'upload-pack fails due to error in pack-objects' ' +test_expect_success 'upload-pack fails due to error in pack-objects packing' ' ! echo "0032want $(git rev-parse HEAD) 00000009done 0000" | git upload-pack . > /dev/null 2> output.err && + grep "unable to read" output.err && grep "pack-objects died" output.err ' @@ -51,11 +52,20 @@ test_expect_success 'fsck fails' ' test_expect_success 'upload-pack fails due to error in rev-list' ' ! echo "0032want $(git rev-parse HEAD) -00000009done +0034shallow $(git rev-parse HEAD^)00000009done 0000" | git upload-pack . > /dev/null 2> output.err && grep "waitpid (async) failed" output.err ' +test_expect_success 'upload-pack fails due to error in pack-objects enumeration' ' + + ! echo "0032want $(git rev-parse HEAD) +00000009done +0000" | git upload-pack . > /dev/null 2> output.err && + grep "bad tree object" output.err && + grep "pack-objects died" output.err +' + test_expect_success 'create empty repository' ' mkdir foo && diff --git a/t/t6010-merge-base.sh b/t/t6010-merge-base.sh index 04e4b7c5c2..0144d9e858 100755 --- a/t/t6010-merge-base.sh +++ b/t/t6010-merge-base.sh @@ -110,6 +110,18 @@ test_expect_success 'compute merge-base (all)' \ # Another set to demonstrate base between one commit and a merge # in the documentation. +# +# * C (MMC) * B (MMB) * A (MMA) +# * o * o * o +# * o * o * o +# * o * o * o +# * o | _______/ +# | |/ +# | * 1 (MM1) +# | _______/ +# |/ +# * root (MMR) + test_expect_success 'merge-base for octopus-step (setup)' ' test_tick && git commit --allow-empty -m root && git tag MMR && @@ -137,6 +149,12 @@ test_expect_success 'merge-base A B C' ' test "$MM1" = "$MB" ' +test_expect_success 'merge-base A B C using show-branch' ' + MB=$(git show-branch --merge-base MMA MMB MMC) && + MMR=$(git rev-parse --verify MMR) && + test "$MMR" = "$MB" +' + test_expect_success 'criss-cross merge-base for octopus-step (setup)' ' git reset --hard MMR && test_tick && git commit --allow-empty -m 1 && git tag CC1 && diff --git a/t/t6020-merge-df.sh b/t/t6020-merge-df.sh index a19d49de28..e71c687f2b 100755 --- a/t/t6020-merge-df.sh +++ b/t/t6020-merge-df.sh @@ -22,4 +22,27 @@ git commit -m "File: dir"' test_expect_code 1 'Merge with d/f conflicts' 'git merge "merge msg" B master' +test_expect_failure 'F/D conflict' ' + git reset --hard && + git checkout master && + rm .git/index && + + mkdir before && + echo FILE >before/one && + echo FILE >after && + git add . && + git commit -m first && + + rm -f after && + git mv before after && + git commit -m move && + + git checkout -b para HEAD^ && + echo COMPLETELY ANOTHER FILE >another && + git add . && + git commit -m para && + + git merge master +' + test_done diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh index 87c9b0e121..f4aa054750 100755 --- a/t/t7700-repack.sh +++ b/t/t7700-repack.sh @@ -149,5 +149,17 @@ test_expect_success 'local packed unreachable obs that exist in alternate ODB ar test_must_fail git show $csha1 ' +test_expect_success 'objects made unreachable by grafts only are kept' ' + test_tick && + git commit --allow-empty -m "commit 4" && + H0=$(git rev-parse HEAD) && + H1=$(git rev-parse HEAD^) && + H2=$(git rev-parse HEAD^^) && + echo "$H0 $H2" > .git/info/grafts && + git reflog expire --expire=now --expire-unreachable=now --all && + git repack -a -d && + git cat-file -t $H1 + ' + test_done diff --git a/t/t8005-blame-i18n.sh b/t/t8005-blame-i18n.sh index 9cca14d080..cb390559f9 100755 --- a/t/t8005-blame-i18n.sh +++ b/t/t8005-blame-i18n.sh @@ -4,7 +4,7 @@ test_description='git blame encoding conversion' . ./test-lib.sh . "$TEST_DIRECTORY"/t8005/utf8.txt -. "$TEST_DIRECTORY"/t8005/iso8859-5.txt +. "$TEST_DIRECTORY"/t8005/euc-japan.txt . "$TEST_DIRECTORY"/t8005/sjis.txt test_expect_success 'setup the repository' ' @@ -13,10 +13,10 @@ test_expect_success 'setup the repository' ' git add file && git commit --author "$UTF8_NAME <utf8@localhost>" -m "$UTF8_MSG" && - echo "ISO-8859-5 LINE" >> file && + echo "EUC-JAPAN LINE" >> file && git add file && - git config i18n.commitencoding ISO8859-5 && - git commit --author "$ISO8859_5_NAME <iso8859-5@localhost>" -m "$ISO8859_5_MSG" && + git config i18n.commitencoding eucJP && + git commit --author "$EUC_JAPAN_NAME <euc-japan@localhost>" -m "$EUC_JAPAN_MSG" && echo "SJIS LINE" >> file && git add file && @@ -41,17 +41,17 @@ test_expect_success \ ' cat >expected <<EOF -author $ISO8859_5_NAME -summary $ISO8859_5_MSG -author $ISO8859_5_NAME -summary $ISO8859_5_MSG -author $ISO8859_5_NAME -summary $ISO8859_5_MSG +author $EUC_JAPAN_NAME +summary $EUC_JAPAN_MSG +author $EUC_JAPAN_NAME +summary $EUC_JAPAN_MSG +author $EUC_JAPAN_NAME +summary $EUC_JAPAN_MSG EOF test_expect_success \ 'blame respects i18n.logoutputencoding' ' - git config i18n.logoutputencoding ISO8859-5 && + git config i18n.logoutputencoding eucJP && git blame --incremental file | \ egrep "^(author|summary) " > actual && test_cmp actual expected @@ -76,8 +76,8 @@ test_expect_success \ cat >expected <<EOF author $SJIS_NAME summary $SJIS_MSG -author $ISO8859_5_NAME -summary $ISO8859_5_MSG +author $EUC_JAPAN_NAME +summary $EUC_JAPAN_MSG author $UTF8_NAME summary $UTF8_MSG EOF diff --git a/t/t8005/euc-japan.txt b/t/t8005/euc-japan.txt new file mode 100644 index 0000000000..288f040c99 --- /dev/null +++ b/t/t8005/euc-japan.txt @@ -0,0 +1,2 @@ +EUC_JAPAN_NAME="»³ÅÄ ÂÀϺ" +EUC_JAPAN_MSG="¥Ö¥ì¡¼¥à¤Î¥Æ¥¹¥È¤Ç¤¹¡£" diff --git a/t/t8005/sjis.txt b/t/t8005/sjis.txt index 2ccfbad207..bbdefeaced 100644 --- a/t/t8005/sjis.txt +++ b/t/t8005/sjis.txt @@ -1,2 +1,2 @@ -SJIS_NAME="„I„r„p„~ „P„u„„„‚„€„r„y„‰ „R„y„t„€„‚„€„r" -SJIS_MSG="„S„u„ƒ„„„€„r„€„u „ƒ„€„€„q„‹„u„~„y„u" +SJIS_NAME="ŽR“c ‘¾˜Y" +SJIS_MSG="ƒuƒŒ[ƒ€‚̃eƒXƒg‚Å‚·B" diff --git a/t/t8005/utf8.txt b/t/t8005/utf8.txt index f46cfc56d8..4d00dbea76 100644 --- a/t/t8005/utf8.txt +++ b/t/t8005/utf8.txt @@ -1,2 +1,2 @@ -UTF8_NAME="Иван Петрович Сидоров" -UTF8_MSG="ТеÑтовое Ñообщение" +UTF8_NAME="山田 太郎" +UTF8_MSG="ブレームã®ãƒ†ã‚¹ãƒˆã§ã™ã€‚" diff --git a/t/t9139-git-svn-reset.sh b/t/t9140-git-svn-reset.sh index 0735526d4b..0735526d4b 100755 --- a/t/t9139-git-svn-reset.sh +++ b/t/t9140-git-svn-reset.sh diff --git a/t/t9138-git-svn-multiple-branches.sh b/t/t9141-git-svn-multiple-branches.sh index cb9a6d229d..3cd06718eb 100755 --- a/t/t9138-git-svn-multiple-branches.sh +++ b/t/t9141-git-svn-multiple-branches.sh @@ -99,22 +99,22 @@ test_expect_success 'Multiple branch or tag paths require -d' ' test_expect_success 'create new branches and tags' ' ( cd git_project && - git svn branch -m "New branch 1" -d project/b_one New1 ) && + git svn branch -m "New branch 1" -d b_one New1 ) && ( cd svn_project && svn_cmd up && test -e b_one/New1/a.file ) && ( cd git_project && - git svn branch -m "New branch 2" -d project/b_two New2 ) && + git svn branch -m "New branch 2" -d b_two New2 ) && ( cd svn_project && svn_cmd up && test -e b_two/New2/a.file ) && ( cd git_project && - git svn branch -t -m "New tag 1" -d project/tags_A Tag1 ) && + git svn branch -t -m "New tag 1" -d tags_A Tag1 ) && ( cd svn_project && svn_cmd up && test -e tags_A/Tag1/a.file ) && ( cd git_project && - git svn tag -m "New tag 2" -d project/tags_B Tag2 ) && + git svn tag -m "New tag 2" -d tags_B Tag2 ) && ( cd svn_project && svn_cmd up && test -e tags_B/Tag2/a.file ) ' diff --git a/t/t9142-git-svn-shallow-clone.sh b/t/t9142-git-svn-shallow-clone.sh new file mode 100755 index 0000000000..1236accd99 --- /dev/null +++ b/t/t9142-git-svn-shallow-clone.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# +# Copyright (c) 2009 Eric Wong +# + +test_description='git svn shallow clone' +. ./lib-git-svn.sh + +test_expect_success 'setup test repository' ' + svn_cmd mkdir -m "create standard layout" \ + "$svnrepo"/trunk "$svnrepo"/branches "$svnrepo"/tags && + svn_cmd cp -m "branch off trunk" \ + "$svnrepo"/trunk "$svnrepo"/branches/a && + svn_cmd co "$svnrepo"/branches/a && + ( + cd a && + > foo && + svn_cmd add foo && + svn_cmd commit -m "add foo" + ) +' + +start_httpd + +test_expect_success 'clone trunk with "-r HEAD"' ' + git svn clone -r HEAD "$svnrepo/trunk" g && + ( cd g && git rev-parse --symbolic --verify HEAD ) +' + +stop_httpd + +test_done diff --git a/t/t9143-git-svn-gc.sh b/t/t9143-git-svn-gc.sh new file mode 100755 index 0000000000..f2ba2d1da3 --- /dev/null +++ b/t/t9143-git-svn-gc.sh @@ -0,0 +1,53 @@ +#!/bin/sh +# +# Copyright (c) 2009 Robert Allan Zeh + +test_description='git svn gc basic tests' + +. ./lib-git-svn.sh + +test_expect_success 'setup directories and test repo' ' + mkdir import && + mkdir tmp && + echo "Sample text for Subversion repository." > import/test.txt && + svn_cmd import -m "import for git svn" import "$svnrepo" > /dev/null + ' + +test_expect_success 'checkout working copy from svn' \ + 'svn_cmd co "$svnrepo" test_wc' + +test_expect_success 'set some properties to create an unhandled.log file' ' + ( + cd test_wc && + svn_cmd propset foo bar test.txt && + svn_cmd commit -m "property set" + )' + +test_expect_success 'Setup repo' 'git svn init "$svnrepo"' + +test_expect_success 'Fetch repo' 'git svn fetch' + +test_expect_success 'make backup copy of unhandled.log' ' + cp .git/svn/git-svn/unhandled.log tmp + ' + +test_expect_success 'create leftover index' '> .git/svn/git-svn/index' + +test_expect_success 'git svn gc runs' 'git svn gc' + +test_expect_success 'git svn index removed' '! test -f .git/svn/git-svn/index' + +if perl -MCompress::Zlib -e 0 2>/dev/null +then + test_expect_success 'git svn gc produces a valid gzip file' ' + gunzip .git/svn/git-svn/unhandled.log.gz + ' +else + say "Perl Compress::Zlib unavailable, skipping gunzip test" +fi + +test_expect_success 'git svn gc does not change unhandled.log files' ' + test_cmp .git/svn/git-svn/unhandled.log tmp/unhandled.log + ' + +test_done diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index ef1f8d22f6..fc3795dc98 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -288,6 +288,27 @@ test_expect_success 'check files before directories' ' ' +test_expect_success 're-commit a removed filename which remains in CVS attic' ' + + (cd "$CVSWORK" && + echo >attic_gremlin && + cvs -Q add attic_gremlin && + cvs -Q ci -m "added attic_gremlin" && + rm attic_gremlin && + cvs -Q rm attic_gremlin && + cvs -Q ci -m "removed attic_gremlin") && + + echo > attic_gremlin && + git add attic_gremlin && + git commit -m "Added attic_gremlin" && + git cvsexportcommit -w "$CVSWORK" -c HEAD && + (cd "$CVSWORK"; cvs -Q update -d) && + test -f "$CVSWORK/attic_gremlin" +' + +# the state of the CVS sandbox may be indeterminate for ' space' +# after this test on some platforms / with some versions of CVS +# consider adding new tests above this point test_expect_success 'commit a file with leading spaces in the name' ' echo space > " space" && @@ -295,7 +316,7 @@ test_expect_success 'commit a file with leading spaces in the name' ' git commit -m "Add a file with a leading space" && id=$(git rev-parse HEAD) && git cvsexportcommit -w "$CVSWORK" -c $id && - check_entries "$CVSWORK" " space/1.1/|DS/1.1/|release-notes/1.2/" && + check_entries "$CVSWORK" " space/1.1/|DS/1.1/|attic_gremlin/1.3/|release-notes/1.2/" && test_cmp "$CVSWORK/ space" " space" ' @@ -317,22 +338,4 @@ test_expect_success 'use the same checkout for Git and CVS' ' ' -test_expect_success 're-commit a removed filename which remains in CVS attic' ' - - (cd "$CVSWORK" && - echo >attic_gremlin && - cvs -Q add attic_gremlin && - cvs -Q ci -m "added attic_gremlin" && - rm attic_gremlin && - cvs -Q rm attic_gremlin && - cvs -Q ci -m "removed attic_gremlin") && - - echo > attic_gremlin && - git add attic_gremlin && - git commit -m "Added attic_gremlin" && - git cvsexportcommit -w "$CVSWORK" -c HEAD && - (cd "$CVSWORK"; cvs -Q update -d) && - test -f "$CVSWORK/attic_gremlin" -' - test_done diff --git a/t/t9301-fast-export.sh b/t/t9301-fast-export.sh index 8c8a9e63c2..356964e53a 100755 --- a/t/t9301-fast-export.sh +++ b/t/t9301-fast-export.sh @@ -262,6 +262,94 @@ test_expect_success 'cope with tagger-less tags' ' ' +test_expect_success 'setup for limiting exports by PATH' ' + mkdir limit-by-paths && + cd limit-by-paths && + git init && + echo hi > there && + git add there && + git commit -m "First file" && + echo foo > bar && + git add bar && + git commit -m "Second file" && + git tag -a -m msg mytag && + echo morefoo >> bar && + git add bar && + git commit -m "Change to second file" && + cd .. +' + +cat > limit-by-paths/expected << EOF +blob +mark :1 +data 3 +hi + +reset refs/tags/mytag +commit refs/tags/mytag +mark :2 +author A U Thor <author@example.com> 1112912713 -0700 +committer C O Mitter <committer@example.com> 1112912713 -0700 +data 11 +First file +M 100644 :1 there + +EOF + +test_expect_success 'dropping tag of filtered out object' ' + cd limit-by-paths && + git fast-export --tag-of-filtered-object=drop mytag -- there > output && + test_cmp output expected && + cd .. +' + +cat >> limit-by-paths/expected << EOF +tag mytag +from :2 +tagger C O Mitter <committer@example.com> 1112912713 -0700 +data 4 +msg + +EOF + +test_expect_success 'rewriting tag of filtered out object' ' + cd limit-by-paths && + git fast-export --tag-of-filtered-object=rewrite mytag -- there > output && + test_cmp output expected && + cd .. +' + +cat > limit-by-paths/expected << EOF +blob +mark :1 +data 4 +foo + +blob +mark :2 +data 3 +hi + +reset refs/heads/master +commit refs/heads/master +mark :3 +author A U Thor <author@example.com> 1112912713 -0700 +committer C O Mitter <committer@example.com> 1112912713 -0700 +data 12 +Second file +M 100644 :1 bar +M 100644 :2 there + +EOF + +test_expect_failure 'no exact-ref revisions included' ' + cd limit-by-paths && + git fast-export master~2..master~1 > output && + test_cmp output expected && + cd .. +' + + test_expect_success 'set-up a few more tags for tag export tests' ' git checkout -f master && HEAD_TREE=`git show -s --pretty=raw HEAD | grep tree | sed "s/tree //"` && @@ -271,8 +359,14 @@ test_expect_success 'set-up a few more tags for tag export tests' ' git tag -a tag-obj_tag-obj -m "tagging a tag" tree_tag-obj ' +test_expect_success 'tree_tag' ' + mkdir result && + (cd result && git init) && + git fast-export tree_tag > fe-stream && + (cd result && git fast-import < ../fe-stream) +' + # NEEDSWORK: not just check return status, but validate the output -test_expect_success 'tree_tag' 'git fast-export tree_tag' test_expect_success 'tree_tag-obj' 'git fast-export tree_tag-obj' test_expect_success 'tag-obj_tag' 'git fast-export tag-obj_tag' test_expect_success 'tag-obj_tag-obj' 'git fast-export tag-obj_tag-obj' diff --git a/t/t9600-cvsimport.sh b/t/t9600-cvsimport.sh index 4322a0c1ed..363345faef 100755 --- a/t/t9600-cvsimport.sh +++ b/t/t9600-cvsimport.sh @@ -1,7 +1,7 @@ #!/bin/sh test_description='git cvsimport basic tests' -. ./test-lib.sh +. ./lib-cvs.sh if ! test_have_prereq PERL; then say 'skipping git cvsimport tests, perl not available' @@ -10,37 +10,13 @@ fi CVSROOT=$(pwd)/cvsroot export CVSROOT -unset CVS_SERVER -# for clean cvsps cache -HOME=$(pwd) -export HOME - -if ! type cvs >/dev/null 2>&1 -then - say 'skipping cvsimport tests, cvs not found' - test_done -fi - -cvsps_version=`cvsps -h 2>&1 | sed -ne 's/cvsps version //p'` -case "$cvsps_version" in -2.1 | 2.2*) - ;; -'') - say 'skipping cvsimport tests, cvsps not found' - test_done - ;; -*) - say 'skipping cvsimport tests, unsupported cvsps version' - test_done - ;; -esac -test_expect_success 'setup cvsroot' 'cvs init' +test_expect_success 'setup cvsroot' '$CVS init' test_expect_success 'setup a cvs module' ' mkdir "$CVSROOT/module" && - cvs co -d module-cvs module && + $CVS co -d module-cvs module && cd module-cvs && cat <<EOF >o_fortuna && O Fortuna @@ -59,13 +35,13 @@ egestatem, potestatem dissolvit ut glaciem. EOF - cvs add o_fortuna && + $CVS add o_fortuna && cat <<EOF >message && add "O Fortuna" lyrics These public domain lyrics make an excellent sample text. EOF - cvs commit -F message && + $CVS commit -F message && cd .. ' @@ -103,7 +79,7 @@ translate to English My Latin is terrible. EOF - cvs commit -F message && + $CVS commit -F message && cd .. ' @@ -121,8 +97,8 @@ test_expect_success 'update cvs module' ' cd module-cvs && echo 1 >tick && - cvs add tick && - cvs commit -m 1 + $CVS add tick && + $CVS commit -m 1 cd .. ' @@ -140,7 +116,7 @@ test_expect_success 'cvsimport.module config works' ' test_expect_success 'import from a CVS working tree' ' - cvs co -d import-from-wt module && + $CVS co -d import-from-wt module && cd import-from-wt && git cvsimport -a -z0 && echo 1 >expect && @@ -150,4 +126,6 @@ test_expect_success 'import from a CVS working tree' ' ' +test_expect_success 'test entire HEAD' 'test_cmp_branch_tree master' + test_done diff --git a/t/t9601-cvsimport-vendor-branch.sh b/t/t9601-cvsimport-vendor-branch.sh new file mode 100755 index 0000000000..3afaf56526 --- /dev/null +++ b/t/t9601-cvsimport-vendor-branch.sh @@ -0,0 +1,86 @@ +#!/bin/sh + +# Description of the files in the repository: +# +# imported-once.txt: +# +# Imported once. 1.1 and 1.1.1.1 should be identical. +# +# imported-twice.txt: +# +# Imported twice. HEAD should reflect the contents of the +# second import (i.e., have the same contents as 1.1.1.2). +# +# imported-modified.txt: +# +# Imported, then modified on HEAD. HEAD should reflect the +# modification. +# +# imported-modified-imported.txt: +# +# Imported, then modified on HEAD, then imported again. +# +# added-imported.txt,v: +# +# Added with 'cvs add' to create 1.1, then imported with +# completely different contents to create 1.1.1.1, therefore the +# vendor branch was never the default branch. +# +# imported-anonymously.txt: +# +# Like imported-twice.txt, but with a vendor branch whose branch +# tag has been removed. + +test_description='git cvsimport handling of vendor branches' +. ./lib-cvs.sh + +CVSROOT="$TEST_DIRECTORY"/t9601/cvsroot +export CVSROOT + +test_expect_success 'import a module with a vendor branch' ' + + git cvsimport -C module-git module + +' + +test_expect_success 'check HEAD out of cvs repository' 'test_cvs_co master' + +test_expect_success 'check master out of git repository' 'test_git_co master' + +test_expect_success 'check a file that was imported once' ' + + test_cmp_branch_file master imported-once.txt + +' + +test_expect_failure 'check a file that was imported twice' ' + + test_cmp_branch_file master imported-twice.txt + +' + +test_expect_success 'check a file that was imported then modified on HEAD' ' + + test_cmp_branch_file master imported-modified.txt + +' + +test_expect_success 'check a file that was imported, modified, then imported again' ' + + test_cmp_branch_file master imported-modified-imported.txt + +' + +test_expect_success 'check a file that was added to HEAD then imported' ' + + test_cmp_branch_file master added-imported.txt + +' + +test_expect_success 'a vendor branch whose tag has been removed' ' + + test_cmp_branch_file master imported-anonymously.txt + +' + +test_done diff --git a/t/t9601/cvsroot/.gitattributes b/t/t9601/cvsroot/.gitattributes new file mode 100644 index 0000000000..562b12e16e --- /dev/null +++ b/t/t9601/cvsroot/.gitattributes @@ -0,0 +1 @@ +* -whitespace diff --git a/t/t9601/cvsroot/CVSROOT/.gitignore b/t/t9601/cvsroot/CVSROOT/.gitignore new file mode 100644 index 0000000000..3bb9b34173 --- /dev/null +++ b/t/t9601/cvsroot/CVSROOT/.gitignore @@ -0,0 +1,2 @@ +history +val-tags diff --git a/t/t9601/cvsroot/module/added-imported.txt,v b/t/t9601/cvsroot/module/added-imported.txt,v new file mode 100644 index 0000000000..5f83072ea4 --- /dev/null +++ b/t/t9601/cvsroot/module/added-imported.txt,v @@ -0,0 +1,44 @@ +head 1.1; +access; +symbols + vtag-4:1.1.1.1 + vbranchA:1.1.1; +locks; strict; +comment @# @; + + +1.1 +date 2004.02.09.15.43.15; author kfogel; state Exp; +branches + 1.1.1.1; +next ; + +1.1.1.1 +date 2004.02.09.15.43.16; author kfogel; state Exp; +branches; +next ; + + +desc +@@ + + +1.1 +log +@Add a file to the working copy. +@ +text +@Adding this file, before importing it with different contents. +@ + + +1.1.1.1 +log +@Import (vbranchA, vtag-4). +@ +text +@d1 1 +a1 1 +This is vtag-4 (on vbranchA) of added-then-imported.txt. +@ + diff --git a/t/t9601/cvsroot/module/imported-anonymously.txt,v b/t/t9601/cvsroot/module/imported-anonymously.txt,v new file mode 100644 index 0000000000..55e1b0ca5d --- /dev/null +++ b/t/t9601/cvsroot/module/imported-anonymously.txt,v @@ -0,0 +1,42 @@ +head 1.1; +branch 1.1.1; +access; +symbols + vtag-1:1.1.1.1; +locks; strict; +comment @# @; + + +1.1 +date 2004.02.09.15.43.13; author kfogel; state Exp; +branches + 1.1.1.1; +next ; + +1.1.1.1 +date 2004.02.09.15.43.13; author kfogel; state Exp; +branches; +next ; + + +desc +@@ + + +1.1 +log +@Initial revision +@ +text +@This is vtag-1 (on vbranchA) of imported-anonymously.txt. +@ + + +1.1.1.1 +log +@Import (vbranchA, vtag-1). +@ +text +@@ + + diff --git a/t/t9601/cvsroot/module/imported-modified-imported.txt,v b/t/t9601/cvsroot/module/imported-modified-imported.txt,v new file mode 100644 index 0000000000..e5830aeb37 --- /dev/null +++ b/t/t9601/cvsroot/module/imported-modified-imported.txt,v @@ -0,0 +1,76 @@ +head 1.2; +access; +symbols + vtag-2:1.1.1.2 + vtag-1:1.1.1.1 + vbranchA:1.1.1; +locks; strict; +comment @# @; + + +1.2 +date 2004.02.09.15.43.14; author kfogel; state Exp; +branches; +next 1.1; + +1.1 +date 2004.02.09.15.43.13; author kfogel; state Exp; +branches + 1.1.1.1; +next ; + +1.1.1.1 +date 2004.02.09.15.43.13; author kfogel; state Exp; +branches; +next 1.1.1.2; + +1.1.1.2 +date 2004.02.09.15.43.13; author kfogel; state Exp; +branches; +next ; + + +desc +@@ + + +1.2 +log +@First regular commit, to imported-modified-imported.txt, on HEAD. +@ +text +@This is a modification of imported-modified-imported.txt on HEAD. +It should supersede the version from the vendor branch. +@ + + +1.1 +log +@Initial revision +@ +text +@d1 2 +a2 1 +This is vtag-1 (on vbranchA) of imported-modified-imported.txt. +@ + + +1.1.1.1 +log +@Import (vbranchA, vtag-1). +@ +text +@@ + + +1.1.1.2 +log +@Import (vbranchA, vtag-2). +@ +text +@d1 1 +a1 1 +This is vtag-2 (on vbranchA) of imported-modified-imported.txt. +@ + + diff --git a/t/t9601/cvsroot/module/imported-modified.txt,v b/t/t9601/cvsroot/module/imported-modified.txt,v new file mode 100644 index 0000000000..bbcfe447b9 --- /dev/null +++ b/t/t9601/cvsroot/module/imported-modified.txt,v @@ -0,0 +1,59 @@ +head 1.2; +access; +symbols + vtag-1:1.1.1.1 + vbranchA:1.1.1; +locks; strict; +comment @# @; + + +1.2 +date 2004.02.09.15.43.14; author kfogel; state Exp; +branches; +next 1.1; + +1.1 +date 2004.02.09.15.43.13; author kfogel; state Exp; +branches + 1.1.1.1; +next ; + +1.1.1.1 +date 2004.02.09.15.43.13; author kfogel; state Exp; +branches; +next ; + + +desc +@@ + + +1.2 +log +@Commit on HEAD. +@ +text +@This is a modification of imported-modified.txt on HEAD. +It should supersede the version from the vendor branch. +@ + + +1.1 +log +@Initial revision +@ +text +@d1 2 +a2 1 +This is vtag-1 (on vbranchA) of imported-modified.txt. +@ + + +1.1.1.1 +log +@Import (vbranchA, vtag-1). +@ +text +@@ + + diff --git a/t/t9601/cvsroot/module/imported-once.txt,v b/t/t9601/cvsroot/module/imported-once.txt,v new file mode 100644 index 0000000000..c5dd82b12d --- /dev/null +++ b/t/t9601/cvsroot/module/imported-once.txt,v @@ -0,0 +1,43 @@ +head 1.1; +branch 1.1.1; +access; +symbols + vtag-1:1.1.1.1 + vbranchA:1.1.1; +locks; strict; +comment @# @; + + +1.1 +date 2004.02.09.15.43.13; author kfogel; state Exp; +branches + 1.1.1.1; +next ; + +1.1.1.1 +date 2004.02.09.15.43.13; author kfogel; state Exp; +branches; +next ; + + +desc +@@ + + +1.1 +log +@Initial revision +@ +text +@This is vtag-1 (on vbranchA) of imported-once.txt. +@ + + +1.1.1.1 +log +@Import (vbranchA, vtag-1). +@ +text +@@ + + diff --git a/t/t9601/cvsroot/module/imported-twice.txt,v b/t/t9601/cvsroot/module/imported-twice.txt,v new file mode 100644 index 0000000000..d1f3f1b344 --- /dev/null +++ b/t/t9601/cvsroot/module/imported-twice.txt,v @@ -0,0 +1,60 @@ +head 1.1; +branch 1.1.1; +access; +symbols + vtag-2:1.1.1.2 + vtag-1:1.1.1.1 + vbranchA:1.1.1; +locks; strict; +comment @# @; + + +1.1 +date 2004.02.09.15.43.13; author kfogel; state Exp; +branches + 1.1.1.1; +next ; + +1.1.1.1 +date 2004.02.09.15.43.13; author kfogel; state Exp; +branches; +next 1.1.1.2; + +1.1.1.2 +date 2004.02.09.15.43.13; author kfogel; state Exp; +branches; +next ; + + +desc +@@ + + +1.1 +log +@Initial revision +@ +text +@This is vtag-1 (on vbranchA) of imported-twice.txt. +@ + + +1.1.1.1 +log +@Import (vbranchA, vtag-1). +@ +text +@@ + + +1.1.1.2 +log +@Import (vbranchA, vtag-2). +@ +text +@d1 1 +a1 1 +This is vtag-2 (on vbranchA) of imported-twice.txt. +@ + + diff --git a/t/t9602-cvsimport-branches-tags.sh b/t/t9602-cvsimport-branches-tags.sh new file mode 100755 index 0000000000..67878b2d0c --- /dev/null +++ b/t/t9602-cvsimport-branches-tags.sh @@ -0,0 +1,79 @@ +#!/bin/sh + +# A description of the repository used for this test can be found in +# t9602/README. + +test_description='git cvsimport handling of branches and tags' +. ./lib-cvs.sh + +CVSROOT="$TEST_DIRECTORY"/t9602/cvsroot +export CVSROOT + +test_expect_success 'import module' ' + + git cvsimport -C module-git module + +' + +test_expect_success 'test branch master' ' + + test_cmp_branch_tree master + +' + +test_expect_success 'test branch vendorbranch' ' + + test_cmp_branch_tree vendorbranch + +' + +test_expect_failure 'test branch B_FROM_INITIALS' ' + + test_cmp_branch_tree B_FROM_INITIALS + +' + +test_expect_failure 'test branch B_FROM_INITIALS_BUT_ONE' ' + + test_cmp_branch_tree B_FROM_INITIALS_BUT_ONE + +' + +test_expect_failure 'test branch B_MIXED' ' + + test_cmp_branch_tree B_MIXED + +' + +test_expect_success 'test branch B_SPLIT' ' + + test_cmp_branch_tree B_SPLIT + +' + +test_expect_failure 'test tag vendortag' ' + + test_cmp_branch_tree vendortag + +' + +test_expect_success 'test tag T_ALL_INITIAL_FILES' ' + + test_cmp_branch_tree T_ALL_INITIAL_FILES + +' + +test_expect_failure 'test tag T_ALL_INITIAL_FILES_BUT_ONE' ' + + test_cmp_branch_tree T_ALL_INITIAL_FILES_BUT_ONE + +' + +test_expect_failure 'test tag T_MIXED' ' + + test_cmp_branch_tree T_MIXED + +' + + +test_done diff --git a/t/t9602/README b/t/t9602/README new file mode 100644 index 0000000000..c231e0f26f --- /dev/null +++ b/t/t9602/README @@ -0,0 +1,62 @@ +This repository is for testing the ability to group revisions +correctly along tags and branches. Here is its history: + + 1. The initial import (revision 1.1 of everybody) created a + directory structure with a file named `default' in each dir: + + ./ + default + sub1/default + subsubA/default + subsubB/default + sub2/default + subsubA/default + sub3/default + + 2. Then tagged everyone with T_ALL_INITIAL_FILES. + + 3. Then tagged everyone except sub1/subsubB/default with + T_ALL_INITIAL_FILES_BUT_ONE. + + 4. Then created branch B_FROM_INITIALS on everyone. + + 5. Then created branch B_FROM_INITIALS_BUT_ONE on everyone except + /sub1/subsubB/default. + + 6. Then committed modifications to two files: sub3/default, and + sub1/subsubA/default. + + 7. Then committed a modification to all 7 files. + + 8. Then backdated sub3/default to revision 1.2, and + sub2/subsubA/default to revision 1.1, and tagged with T_MIXED. + + 9. Same as 8, but tagged with -b to create branch B_MIXED. + + 10. Switched the working copy to B_MIXED, and added + sub2/branch_B_MIXED_only. (That's why the RCS file is in + sub2/Attic/ -- it never existed on trunk.) + + 11. In one commit, modified default, sub1/default, and + sub2/subsubA/default, on branch B_MIXED. + + 12. Did "cvs up -A" on sub2/default, then in one commit, made a + change to sub2/default and sub2/branch_B_MIXED_only. So this + commit should be spread between the branch and the trunk. + + 13. Do "cvs up -A" to get everyone back to trunk, then make a new + branch B_SPLIT on everyone except sub1/subsubB/default,v. + + 14. Switch to branch B_SPLIT (see sub1/subsubB/default disappear) + and commit a change that affects everyone except sub3/default. + + 15. An hour or so later, "cvs up -A" to get sub1/subsubB/default + back, then commit a change on that file, on trunk. (It's + important that this change happened after the previous commits + on B_SPLIT.) + + 16. Branch sub1/subsubB/default to B_SPLIT, then "cvs up -r B_SPLIT" + to switch the whole working copy to the branch. + + 17. Commit a change on B_SPLIT, to sub1/subsubB/default and + sub3/default. diff --git a/t/t9602/cvsroot/.gitattributes b/t/t9602/cvsroot/.gitattributes new file mode 100644 index 0000000000..562b12e16e --- /dev/null +++ b/t/t9602/cvsroot/.gitattributes @@ -0,0 +1 @@ +* -whitespace diff --git a/t/t9602/cvsroot/CVSROOT/.gitignore b/t/t9602/cvsroot/CVSROOT/.gitignore new file mode 100644 index 0000000000..3bb9b34173 --- /dev/null +++ b/t/t9602/cvsroot/CVSROOT/.gitignore @@ -0,0 +1,2 @@ +history +val-tags diff --git a/t/t9602/cvsroot/module/default,v b/t/t9602/cvsroot/module/default,v new file mode 100644 index 0000000000..3b68382a3b --- /dev/null +++ b/t/t9602/cvsroot/module/default,v @@ -0,0 +1,102 @@ +head 1.2; +access; +symbols + B_SPLIT:1.2.0.4 + B_MIXED:1.2.0.2 + T_MIXED:1.2 + B_FROM_INITIALS_BUT_ONE:1.1.1.1.0.4 + B_FROM_INITIALS:1.1.1.1.0.2 + T_ALL_INITIAL_FILES_BUT_ONE:1.1.1.1 + T_ALL_INITIAL_FILES:1.1.1.1 + vendortag:1.1.1.1 + vendorbranch:1.1.1; +locks; strict; +comment @# @; + + +1.2 +date 2003.05.23.00.17.53; author jrandom; state Exp; +branches + 1.2.2.1 + 1.2.4.1; +next 1.1; + +1.1 +date 2003.05.22.23.20.19; author jrandom; state Exp; +branches + 1.1.1.1; +next ; + +1.1.1.1 +date 2003.05.22.23.20.19; author jrandom; state Exp; +branches; +next ; + +1.2.2.1 +date 2003.05.23.00.31.36; author jrandom; state Exp; +branches; +next ; + +1.2.4.1 +date 2003.06.03.03.20.31; author jrandom; state Exp; +branches; +next ; + + +desc +@@ + + +1.2 +log +@Second commit to proj, affecting all 7 files. +@ +text +@This is the file `default' in the top level of the project. + +Every directory in the `proj' project has a file named `default'. + +This line was added in the second commit (affecting all 7 files). +@ + + +1.2.4.1 +log +@First change on branch B_SPLIT. + +This change excludes sub3/default, because it was not part of this +commit, and sub1/subsubB/default, which is not even on the branch yet. +@ +text +@a5 2 + +First change on branch B_SPLIT. +@ + + +1.2.2.1 +log +@Modify three files, on branch B_MIXED. +@ +text +@a5 2 + +This line was added on branch B_MIXED only (affecting 3 files). +@ + + +1.1 +log +@Initial revision +@ +text +@d4 2 +@ + + +1.1.1.1 +log +@Initial import. +@ +text +@@ diff --git a/t/t9602/cvsroot/module/sub1/default,v b/t/t9602/cvsroot/module/sub1/default,v new file mode 100644 index 0000000000..b7fdccdfdf --- /dev/null +++ b/t/t9602/cvsroot/module/sub1/default,v @@ -0,0 +1,102 @@ +head 1.2; +access; +symbols + B_SPLIT:1.2.0.4 + B_MIXED:1.2.0.2 + T_MIXED:1.2 + B_FROM_INITIALS_BUT_ONE:1.1.1.1.0.4 + B_FROM_INITIALS:1.1.1.1.0.2 + T_ALL_INITIAL_FILES_BUT_ONE:1.1.1.1 + T_ALL_INITIAL_FILES:1.1.1.1 + vendortag:1.1.1.1 + vendorbranch:1.1.1; +locks; strict; +comment @# @; + + +1.2 +date 2003.05.23.00.17.53; author jrandom; state Exp; +branches + 1.2.2.1 + 1.2.4.1; +next 1.1; + +1.1 +date 2003.05.22.23.20.19; author jrandom; state Exp; +branches + 1.1.1.1; +next ; + +1.1.1.1 +date 2003.05.22.23.20.19; author jrandom; state Exp; +branches; +next ; + +1.2.2.1 +date 2003.05.23.00.31.36; author jrandom; state Exp; +branches; +next ; + +1.2.4.1 +date 2003.06.03.03.20.31; author jrandom; state Exp; +branches; +next ; + + +desc +@@ + + +1.2 +log +@Second commit to proj, affecting all 7 files. +@ +text +@This is sub1/default. + +Every directory in the `proj' project has a file named `default'. + +This line was added in the second commit (affecting all 7 files). +@ + + +1.2.4.1 +log +@First change on branch B_SPLIT. + +This change excludes sub3/default, because it was not part of this +commit, and sub1/subsubB/default, which is not even on the branch yet. +@ +text +@a5 2 + +First change on branch B_SPLIT. +@ + + +1.2.2.1 +log +@Modify three files, on branch B_MIXED. +@ +text +@a5 2 + +This line was added on branch B_MIXED only (affecting 3 files). +@ + + +1.1 +log +@Initial revision +@ +text +@d4 2 +@ + + +1.1.1.1 +log +@Initial import. +@ +text +@@ diff --git a/t/t9602/cvsroot/module/sub1/subsubA/default,v b/t/t9602/cvsroot/module/sub1/subsubA/default,v new file mode 100644 index 0000000000..472b7b2bd9 --- /dev/null +++ b/t/t9602/cvsroot/module/sub1/subsubA/default,v @@ -0,0 +1,101 @@ +head 1.3; +access; +symbols + B_SPLIT:1.3.0.4 + B_MIXED:1.3.0.2 + T_MIXED:1.3 + B_FROM_INITIALS_BUT_ONE:1.1.1.1.0.4 + B_FROM_INITIALS:1.1.1.1.0.2 + T_ALL_INITIAL_FILES_BUT_ONE:1.1.1.1 + T_ALL_INITIAL_FILES:1.1.1.1 + vendortag:1.1.1.1 + vendorbranch:1.1.1; +locks; strict; +comment @# @; + + +1.3 +date 2003.05.23.00.17.53; author jrandom; state Exp; +branches + 1.3.4.1; +next 1.2; + +1.2 +date 2003.05.23.00.15.26; author jrandom; state Exp; +branches; +next 1.1; + +1.1 +date 2003.05.22.23.20.19; author jrandom; state Exp; +branches + 1.1.1.1; +next ; + +1.1.1.1 +date 2003.05.22.23.20.19; author jrandom; state Exp; +branches; +next ; + +1.3.4.1 +date 2003.06.03.03.20.31; author jrandom; state Exp; +branches; +next ; + + +desc +@@ + + +1.3 +log +@Second commit to proj, affecting all 7 files. +@ +text +@This is sub1/subsubA/default. + +Every directory in the `proj' project has a file named `default'. + +This line was added by the first commit (affecting two files). + +This line was added in the second commit (affecting all 7 files). +@ + + +1.3.4.1 +log +@First change on branch B_SPLIT. + +This change excludes sub3/default, because it was not part of this +commit, and sub1/subsubB/default, which is not even on the branch yet. +@ +text +@a7 2 + +First change on branch B_SPLIT. +@ + + +1.2 +log +@First commit to proj, affecting two files. +@ +text +@d6 2 +@ + + +1.1 +log +@Initial revision +@ +text +@d4 2 +@ + + +1.1.1.1 +log +@Initial import. +@ +text +@@ diff --git a/t/t9602/cvsroot/module/sub1/subsubB/default,v b/t/t9602/cvsroot/module/sub1/subsubB/default,v new file mode 100644 index 0000000000..fe6efa4554 --- /dev/null +++ b/t/t9602/cvsroot/module/sub1/subsubB/default,v @@ -0,0 +1,107 @@ +head 1.3; +access; +symbols + B_SPLIT:1.3.0.2 + B_MIXED:1.2.0.2 + T_MIXED:1.2 + B_FROM_INITIALS:1.1.1.1.0.2 + T_ALL_INITIAL_FILES:1.1.1.1 + vendortag:1.1.1.1 + vendorbranch:1.1.1; +locks; strict; +comment @# @; + + +1.3 +date 2003.06.03.04.29.14; author jrandom; state Exp; +branches + 1.3.2.1; +next 1.2; + +1.2 +date 2003.05.23.00.17.53; author jrandom; state Exp; +branches; +next 1.1; + +1.1 +date 2003.05.22.23.20.19; author jrandom; state Exp; +branches + 1.1.1.1; +next ; + +1.1.1.1 +date 2003.05.22.23.20.19; author jrandom; state Exp; +branches; +next ; + +1.3.2.1 +date 2003.06.03.04.33.13; author jrandom; state Exp; +branches; +next ; + + +desc +@@ + + +1.3 +log +@A trunk change to sub1/subsubB/default. This was committed about an +hour after an earlier change that affected most files on branch +B_SPLIT. This file is not on that branch yet, but after this commit, +we'll branch to B_SPLIT, albeit rooted in a revision that didn't exist +at the time the rest of B_SPLIT was created. +@ +text +@This is sub1/subsubB/default. + +Every directory in the `proj' project has a file named `default'. + +This line was added in the second commit (affecting all 7 files). + +This bit was committed on trunk about an hour after an earlier change +to everyone else on branch B_SPLIT. Afterwards, we'll finally branch +this file to B_SPLIT, but rooted in a revision that didn't exist at +the time the rest of B_SPLIT was created. +@ + + +1.3.2.1 +log +@This change affects sub3/default and sub1/subsubB/default, on branch +B_SPLIT. Note that the latter file did not even exist on this branch +until after some other files had had revisions committed on B_SPLIT. +@ +text +@a10 4 + +This change affects sub3/default and sub1/subsubB/default, on branch +B_SPLIT. Note that the latter file did not even exist on this branch +until after some other files had had revisions committed on B_SPLIT. +@ + + +1.2 +log +@Second commit to proj, affecting all 7 files. +@ +text +@d6 5 +@ + + +1.1 +log +@Initial revision +@ +text +@d4 2 +@ + + +1.1.1.1 +log +@Initial import. +@ +text +@@ diff --git a/t/t9602/cvsroot/module/sub2/Attic/branch_B_MIXED_only,v b/t/t9602/cvsroot/module/sub2/Attic/branch_B_MIXED_only,v new file mode 100644 index 0000000000..34c9789f2f --- /dev/null +++ b/t/t9602/cvsroot/module/sub2/Attic/branch_B_MIXED_only,v @@ -0,0 +1,59 @@ +head 1.1; +access; +symbols + B_MIXED:1.1.0.2; +locks; strict; +comment @# @; + + +1.1 +date 2003.05.23.00.25.26; author jrandom; state dead; +branches + 1.1.2.1; +next ; + +1.1.2.1 +date 2003.05.23.00.25.26; author jrandom; state Exp; +branches; +next 1.1.2.2; + +1.1.2.2 +date 2003.05.23.00.48.51; author jrandom; state Exp; +branches; +next ; + + +desc +@@ + + +1.1 +log +@file branch_B_MIXED_only was initially added on branch B_MIXED. +@ +text +@@ + + +1.1.2.1 +log +@Add a file on branch B_MIXED. +@ +text +@a0 1 +This file was added on branch B_MIXED. It never existed on trunk. +@ + + +1.1.2.2 +log +@A single commit affecting one file on branch B_MIXED and one on trunk. +@ +text +@a1 3 + +The same commit added these two lines here on branch B_MIXED, and two +similar lines to ./default on trunk. +@ + + diff --git a/t/t9602/cvsroot/module/sub2/default,v b/t/t9602/cvsroot/module/sub2/default,v new file mode 100644 index 0000000000..018f7f8ece --- /dev/null +++ b/t/t9602/cvsroot/module/sub2/default,v @@ -0,0 +1,102 @@ +head 1.3; +access; +symbols + B_SPLIT:1.3.0.2 + B_MIXED:1.2.0.2 + T_MIXED:1.2 + B_FROM_INITIALS_BUT_ONE:1.1.1.1.0.4 + B_FROM_INITIALS:1.1.1.1.0.2 + T_ALL_INITIAL_FILES_BUT_ONE:1.1.1.1 + T_ALL_INITIAL_FILES:1.1.1.1 + vendortag:1.1.1.1 + vendorbranch:1.1.1; +locks; strict; +comment @# @; + + +1.3 +date 2003.05.23.00.48.51; author jrandom; state Exp; +branches + 1.3.2.1; +next 1.2; + +1.2 +date 2003.05.23.00.17.53; author jrandom; state Exp; +branches; +next 1.1; + +1.1 +date 2003.05.22.23.20.19; author jrandom; state Exp; +branches + 1.1.1.1; +next ; + +1.1.1.1 +date 2003.05.22.23.20.19; author jrandom; state Exp; +branches; +next ; + +1.3.2.1 +date 2003.06.03.03.20.31; author jrandom; state Exp; +branches; +next ; + + +desc +@@ + + +1.3 +log +@A single commit affecting one file on branch B_MIXED and one on trunk. +@ +text +@This is sub2/default. + +Every directory in the `proj' project has a file named `default'. + +This line was added in the second commit (affecting all 7 files). + +The same commit added these two lines here on trunk, and two similar +lines to ./branch_B_MIXED_only on branch B_MIXED. +@ + + +1.3.2.1 +log +@First change on branch B_SPLIT. + +This change excludes sub3/default, because it was not part of this +commit, and sub1/subsubB/default, which is not even on the branch yet. +@ +text +@a8 2 + +First change on branch B_SPLIT. +@ + + +1.2 +log +@Second commit to proj, affecting all 7 files. +@ +text +@d6 3 +@ + + +1.1 +log +@Initial revision +@ +text +@d4 2 +@ + + +1.1.1.1 +log +@Initial import. +@ +text +@@ diff --git a/t/t9602/cvsroot/module/sub2/subsubA/default,v b/t/t9602/cvsroot/module/sub2/subsubA/default,v new file mode 100644 index 0000000000..d13242cb09 --- /dev/null +++ b/t/t9602/cvsroot/module/sub2/subsubA/default,v @@ -0,0 +1,102 @@ +head 1.2; +access; +symbols + B_SPLIT:1.2.0.2 + B_MIXED:1.1.0.2 + T_MIXED:1.1 + B_FROM_INITIALS_BUT_ONE:1.1.1.1.0.4 + B_FROM_INITIALS:1.1.1.1.0.2 + T_ALL_INITIAL_FILES_BUT_ONE:1.1.1.1 + T_ALL_INITIAL_FILES:1.1.1.1 + vendortag:1.1.1.1 + vendorbranch:1.1.1; +locks; strict; +comment @# @; + + +1.2 +date 2003.05.23.00.17.53; author jrandom; state Exp; +branches + 1.2.2.1; +next 1.1; + +1.1 +date 2003.05.22.23.20.19; author jrandom; state Exp; +branches + 1.1.1.1 + 1.1.2.1; +next ; + +1.1.1.1 +date 2003.05.22.23.20.19; author jrandom; state Exp; +branches; +next ; + +1.1.2.1 +date 2003.05.23.00.31.36; author jrandom; state Exp; +branches; +next ; + +1.2.2.1 +date 2003.06.03.03.20.31; author jrandom; state Exp; +branches; +next ; + + +desc +@@ + + +1.2 +log +@Second commit to proj, affecting all 7 files. +@ +text +@This is sub2/subsub2/default. + +Every directory in the `proj' project has a file named `default'. + +This line was added in the second commit (affecting all 7 files). +@ + + +1.2.2.1 +log +@First change on branch B_SPLIT. + +This change excludes sub3/default, because it was not part of this +commit, and sub1/subsubB/default, which is not even on the branch yet. +@ +text +@a5 2 + +First change on branch B_SPLIT. +@ + + +1.1 +log +@Initial revision +@ +text +@d4 2 +@ + + +1.1.2.1 +log +@Modify three files, on branch B_MIXED. +@ +text +@a3 2 + +This line was added on branch B_MIXED only (affecting 3 files). +@ + + +1.1.1.1 +log +@Initial import. +@ +text +@@ diff --git a/t/t9602/cvsroot/module/sub3/default,v b/t/t9602/cvsroot/module/sub3/default,v new file mode 100644 index 0000000000..88e4567434 --- /dev/null +++ b/t/t9602/cvsroot/module/sub3/default,v @@ -0,0 +1,102 @@ +head 1.3; +access; +symbols + B_SPLIT:1.3.0.2 + B_MIXED:1.2.0.2 + T_MIXED:1.2 + B_FROM_INITIALS_BUT_ONE:1.1.1.1.0.4 + B_FROM_INITIALS:1.1.1.1.0.2 + T_ALL_INITIAL_FILES_BUT_ONE:1.1.1.1 + T_ALL_INITIAL_FILES:1.1.1.1 + vendortag:1.1.1.1 + vendorbranch:1.1.1; +locks; strict; +comment @# @; + + +1.3 +date 2003.05.23.00.17.53; author jrandom; state Exp; +branches + 1.3.2.1; +next 1.2; + +1.2 +date 2003.05.23.00.15.26; author jrandom; state Exp; +branches; +next 1.1; + +1.1 +date 2003.05.22.23.20.19; author jrandom; state Exp; +branches + 1.1.1.1; +next ; + +1.1.1.1 +date 2003.05.22.23.20.19; author jrandom; state Exp; +branches; +next ; + +1.3.2.1 +date 2003.06.03.04.33.13; author jrandom; state Exp; +branches; +next ; + + +desc +@@ + + +1.3 +log +@Second commit to proj, affecting all 7 files. +@ +text +@This is sub3/default. + +Every directory in the `proj' project has a file named `default'. + +This line was added by the first commit (affecting two files). + +This line was added in the second commit (affecting all 7 files). +@ + + +1.3.2.1 +log +@This change affects sub3/default and sub1/subsubB/default, on branch +B_SPLIT. Note that the latter file did not even exist on this branch +until after some other files had had revisions committed on B_SPLIT. +@ +text +@a7 4 + +This change affects sub3/default and sub1/subsubB/default, on branch +B_SPLIT. Note that the latter file did not even exist on this branch +until after some other files had had revisions committed on B_SPLIT. +@ + + +1.2 +log +@First commit to proj, affecting two files. +@ +text +@d6 2 +@ + + +1.1 +log +@Initial revision +@ +text +@d4 2 +@ + + +1.1.1.1 +log +@Initial import. +@ +text +@@ diff --git a/t/t9603-cvsimport-patchsets.sh b/t/t9603-cvsimport-patchsets.sh new file mode 100755 index 0000000000..958bdce4dd --- /dev/null +++ b/t/t9603-cvsimport-patchsets.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +# Structure of the test cvs repository +# +# Message File:Content Commit Time +# Rev 1 a: 1.1 2009-02-21 19:11:43 +0100 +# Rev 2 a: 1.2 b: 1.1 2009-02-21 19:11:14 +0100 +# Rev 3 b: 1.2 2009-02-21 19:11:43 +0100 +# +# As you can see the commit of Rev 3 has the same time as +# Rev 1 this leads to a broken import because of a cvsps +# bug. + +test_description='git cvsimport testing for correct patchset estimation' +. ./lib-cvs.sh + +CVSROOT="$TEST_DIRECTORY"/t9603/cvsroot +export CVSROOT + +test_expect_failure 'import with criss cross times on revisions' ' + + git cvsimport -p"-x" -C module-git module && + cd module-git && + git log --pretty=format:%s > ../actual-master && + git log A~2..A --pretty="format:%s %ad" -- > ../actual-A && + echo "" >> ../actual-master && + echo "" >> ../actual-A && + cd .. && + echo "Rev 4 +Rev 3 +Rev 2 +Rev 1" > expect-master && + test_cmp actual-master expect-master && + + echo "Rev 5 Branch A Wed Mar 11 19:09:10 2009 +0000 +Rev 4 Branch A Wed Mar 11 19:03:52 2009 +0000" > expect-A && + test_cmp actual-A expect-A +' + +test_done diff --git a/t/t9603/cvsroot/.gitattributes b/t/t9603/cvsroot/.gitattributes new file mode 100644 index 0000000000..562b12e16e --- /dev/null +++ b/t/t9603/cvsroot/.gitattributes @@ -0,0 +1 @@ +* -whitespace diff --git a/t/t9603/cvsroot/CVSROOT/.gitignore b/t/t9603/cvsroot/CVSROOT/.gitignore new file mode 100644 index 0000000000..3bb9b34173 --- /dev/null +++ b/t/t9603/cvsroot/CVSROOT/.gitignore @@ -0,0 +1,2 @@ +history +val-tags diff --git a/t/t9603/cvsroot/module/a,v b/t/t9603/cvsroot/module/a,v new file mode 100644 index 0000000000..ba8fd5af23 --- /dev/null +++ b/t/t9603/cvsroot/module/a,v @@ -0,0 +1,74 @@ +head 1.2; +access; +symbols + A:1.2.0.2; +locks; strict; +comment @# @; + + +1.2 +date 2009.02.21.18.11.14; author tester; state Exp; +branches + 1.2.2.1; +next 1.1; + +1.1 +date 2009.02.21.18.11.43; author tester; state Exp; +branches; +next ; + +1.2.2.1 +date 2009.03.11.19.03.52; author tester; state Exp; +branches; +next 1.2.2.2; + +1.2.2.2 +date 2009.03.11.19.09.10; author tester; state Exp; +branches; +next ; + + +desc +@@ + + +1.2 +log +@Rev 2 +@ +text +@1.2 +@ + + +1.2.2.1 +log +@Rev 4 Branch A +@ +text +@d1 1 +a1 1 +1.2.2.1 +@ + + +1.2.2.2 +log +@Rev 5 Branch A +@ +text +@d1 1 +a1 1 +1.2.2.2 +@ + + +1.1 +log +@Rev 1 +@ +text +@d1 1 +a1 1 +1.1 +@ diff --git a/t/t9603/cvsroot/module/b,v b/t/t9603/cvsroot/module/b,v new file mode 100644 index 0000000000..d26885518a --- /dev/null +++ b/t/t9603/cvsroot/module/b,v @@ -0,0 +1,90 @@ +head 1.3; +access; +symbols + A:1.2.0.2; +locks; strict; +comment @# @; + + +1.3 +date 2009.03.11.19.05.08; author tester; state Exp; +branches; +next 1.2; + +1.2 +date 2009.02.21.18.11.43; author tester; state Exp; +branches + 1.2.2.1; +next 1.1; + +1.1 +date 2009.02.21.18.11.14; author tester; state Exp; +branches; +next ; + +1.2.2.1 +date 2009.03.11.19.03.52; author tester; state Exp; +branches; +next 1.2.2.2; + +1.2.2.2 +date 2009.03.11.19.09.10; author tester; state Exp; +branches; +next ; + + +desc +@@ + + +1.3 +log +@Rev 4 +@ +text +@1.3 +@ + + +1.2 +log +@Rev 3 +@ +text +@d1 1 +a1 1 +1.2 +@ + + +1.2.2.1 +log +@Rev 4 Branch A +@ +text +@d1 1 +a1 1 +1.2.2.1 +@ + + +1.2.2.2 +log +@Rev 5 Branch A +@ +text +@d1 1 +a1 1 +1.2 +@ + + +1.1 +log +@Rev 2 +@ +text +@d1 1 +a1 1 +1.1 +@ diff --git a/unpack-trees.c b/unpack-trees.c index f9d12aafba..720f7a1616 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -999,12 +999,12 @@ int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o) return error("Cannot do a oneway merge of %d trees", o->merge_size); - if (!a) + if (!a || a == o->df_conflict_entry) return deleted_entry(old, old, o); if (old && same(old, a)) { int update = 0; - if (o->reset) { + if (o->reset && !ce_uptodate(old)) { struct stat st; if (lstat(old->name, &st) || ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID)) diff --git a/upload-pack.c b/upload-pack.c index 841ebb534a..f7d308a411 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -29,6 +29,7 @@ static unsigned long oldest_have; static int multi_ack, nr_our_refs; static int use_thin_pack, use_ofs_delta, use_include_tag; static int no_progress, daemon_mode; +static int shallow_nr; static struct object_array have_obj; static struct object_array want_obj; static unsigned int timeout; @@ -107,8 +108,6 @@ static int do_rev_list(int fd, void *create_full_pack) struct rev_info revs; pack_pipe = fdopen(fd, "w"); - if (create_full_pack) - use_thin_pack = 0; /* no point doing it */ init_revisions(&revs, NULL); revs.tag_objects = 1; revs.tree_objects = 1; @@ -155,13 +154,21 @@ static void create_pack_file(void) const char *argv[10]; int arg = 0; - rev_list.proc = do_rev_list; - /* .data is just a boolean: any non-NULL value will do */ - rev_list.data = create_full_pack ? &rev_list : NULL; - if (start_async(&rev_list)) - die("git upload-pack: unable to fork git-rev-list"); + if (shallow_nr) { + rev_list.proc = do_rev_list; + rev_list.data = 0; + if (start_async(&rev_list)) + die("git upload-pack: unable to fork git-rev-list"); + argv[arg++] = "pack-objects"; + } else { + argv[arg++] = "pack-objects"; + argv[arg++] = "--revs"; + if (create_full_pack) + argv[arg++] = "--all"; + else if (use_thin_pack) + argv[arg++] = "--thin"; + } - argv[arg++] = "pack-objects"; argv[arg++] = "--stdout"; if (!no_progress) argv[arg++] = "--progress"; @@ -172,7 +179,7 @@ static void create_pack_file(void) argv[arg++] = NULL; memset(&pack_objects, 0, sizeof(pack_objects)); - pack_objects.in = rev_list.out; /* start_command closes it */ + pack_objects.in = shallow_nr ? rev_list.out : -1; pack_objects.out = -1; pack_objects.err = -1; pack_objects.git_cmd = 1; @@ -181,6 +188,24 @@ static void create_pack_file(void) if (start_command(&pack_objects)) die("git upload-pack: unable to fork git-pack-objects"); + /* pass on revisions we (don't) want */ + if (!shallow_nr) { + FILE *pipe_fd = fdopen(pack_objects.in, "w"); + if (!create_full_pack) { + int i; + for (i = 0; i < want_obj.nr; i++) + fprintf(pipe_fd, "%s\n", sha1_to_hex(want_obj.objects[i].item->sha1)); + fprintf(pipe_fd, "--not\n"); + for (i = 0; i < have_obj.nr; i++) + fprintf(pipe_fd, "%s\n", sha1_to_hex(have_obj.objects[i].item->sha1)); + } + + fprintf(pipe_fd, "\n"); + fflush(pipe_fd); + fclose(pipe_fd); + } + + /* We read from pack_objects.err to capture stderr output for * progress bar, and pack_objects.out to capture the pack data. */ @@ -276,7 +301,7 @@ static void create_pack_file(void) error("git upload-pack: git-pack-objects died with error."); goto fail; } - if (finish_async(&rev_list)) + if (shallow_nr && finish_async(&rev_list)) goto fail; /* error was already reported */ /* flush the data */ @@ -451,6 +476,7 @@ static void receive_needs(void) static char line[1000]; int len, depth = 0; + shallow_nr = 0; if (debug_fd) write_in_full(debug_fd, "#S\n", 3); for (;;) { @@ -538,6 +564,7 @@ static void receive_needs(void) packet_write(1, "shallow %s", sha1_to_hex(object->sha1)); register_shallow(object->sha1); + shallow_nr++; } result = result->next; } @@ -571,6 +598,8 @@ static void receive_needs(void) for (i = 0; i < shallows.nr; i++) register_shallow(shallows.objects[i].item->sha1); } + + shallow_nr += shallows.nr; free(shallows.objects); } @@ -245,7 +245,7 @@ void walker_targets_free(int targets, char **target, const char **write_ref) { while (targets--) { free(target[targets]); - if (write_ref && write_ref[targets]) + if (write_ref) free((char *) write_ref[targets]); } } @@ -261,12 +261,11 @@ int ws_fix_copy(char *dst, const char *src, int len, unsigned ws_rule, int *erro /* * Strip trailing whitespace */ - if ((ws_rule & WS_TRAILING_SPACE) && - (2 <= len && isspace(src[len-2]))) { - if (src[len - 1] == '\n') { + if (ws_rule & WS_TRAILING_SPACE) { + if (0 < len && src[len - 1] == '\n') { add_nl_to_tail = 1; len--; - if (1 < len && src[len - 1] == '\r') { + if (0 < len && src[len - 1] == '\r') { add_cr_to_tail = !!(ws_rule & WS_CR_AT_EOL); len--; } diff --git a/xdiff/xdiffi.c b/xdiff/xdiffi.c index 1ebab687f7..da67c04357 100644 --- a/xdiff/xdiffi.c +++ b/xdiff/xdiffi.c @@ -26,7 +26,7 @@ #define XDL_MAX_COST_MIN 256 #define XDL_HEUR_MIN_COST 256 -#define XDL_LINE_MAX (long)((1UL << (8 * sizeof(long) - 1)) - 1) +#define XDL_LINE_MAX (long)((1UL << (CHAR_BIT * sizeof(long) - 1)) - 1) #define XDL_SNAKE_CNT 20 #define XDL_K_HEUR 4 |