diff options
327 files changed, 6376 insertions, 3130 deletions
diff --git a/.gitignore b/.gitignore index 3dd6ef7d25..c460c66766 100644 --- a/.gitignore +++ b/.gitignore @@ -170,6 +170,7 @@ /test-index-version /test-line-buffer /test-match-trees +/test-mktemp /test-obj-pool /test-parse-options /test-path-utils diff --git a/Documentation/RelNotes/1.7.5.txt b/Documentation/RelNotes/1.7.5.txt new file mode 100644 index 0000000000..bb0eb40af4 --- /dev/null +++ b/Documentation/RelNotes/1.7.5.txt @@ -0,0 +1,97 @@ +Git v1.7.5 Release Notes (draft) +======================== + +Updates since v1.7.4 +-------------------- + + * Various MinGW portability fixes. + + * Various git-p4 enhancements (in contrib). + + * Various vcs-svn enhancements. + + * Update to more modern HP-UX port. + + * "git apply -v" reports offset lines when the patch does not apply at + the exact location recorded in the diff output. + + * "git branch --track" (and "git checkout --track --branch") used to + allow setting up a random non-branch that does not make sense to follow + as the "upstream". The command correctly diagnoses it as an error. + + * "git config" used to be also known as "git repo-config", but the old + name is now officially deprecated. + + * "git checkout --detach <commit>" is a more user friendly synonym for + "git checkout <commit>^0". + + * "git checkout" performed on detached HEAD gives a warning and + advice when the commit being left behind will become unreachable from + any branch or tag. + + * "git cherry-pick" and "git revert" can be told to use a custom merge + strategy, similar to "git rebase". + + * "git cherry-pick" remembers which commit failed to apply when it is + stopped by conflicts, making it unnecessary to use "commit -c $commit" + to conclude it. + + * "git cvsimport" bails out immediately when the cvs server cannot be + reached, without spewing unnecessary error messages that complain about + the server response it never got. + + * "git grep --no-index" did not honor pathspecs correctly, returning + paths outside the specified area. + + * "git log" type commands now understand globbing pathspecs. You + can say "git log -- '*.txt'" for example. + + * "git rev-list --objects $revs -- $pathspec" now limits the objects listed + in its output properly with the pathspec, in preparation for narrow + clones. + + * "git push" with no parameters gives better advice messages when + "tracking" is used as the push.default semantics or there is no remote + configured yet. + + * "git rerere" learned a new subcommand "remaining" that is similar to + "status" and lists the paths that had conflicts which are known to + rerere, but excludes the paths that have already been marked as + resolved in the index from its output. "git mergetool" has been + updated to use this facility. + + * A possible value to the "push.default" configuration variable, + 'tracking', gained a synonym that more naturally describes what it + does, 'upstream'. + +Also contains various documentation updates. + + +Fixes since v1.7.4 +------------------ + +All of the fixes in the v1.7.4.X maintenance series are included in this +release, unless otherwise noted. + + * We used to keep one file descriptor open for each and every packfile + that we have a mmap window on it (read: "in use"), even when for very + tiny packfiles. We now close the file descriptor early when the entire + packfile fits inside one mmap window. + + * "git apply" used to confuse lines updated by previous hunks as lines + that existed before when applying a hunk, contributing misapplication + of patches with offsets. + + * "git checkout $other_branch" silently removed untracked symbolic links + in the working tree that are in the way in order to check out paths + under it from the named branch (js/checkout-untracked-symlink). + + * "git submodule update" used to honor the --merge/--rebase option (or + corresponding configuration variables) even for a newly cloned + subproject, which made no sense (so/submodule-no-update-first-time). + +--- +exec >/var/tmp/1 +O=v1.7.4.1-291-g01de349 +echo O=$(git describe 'master') +git shortlog --no-merges ^maint ^$O master diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt index a03448f923..7eebbefe7b 100644 --- a/Documentation/git-add.txt +++ b/Documentation/git-add.txt @@ -378,14 +378,6 @@ linkgit:git-mv[1] linkgit:git-commit[1] linkgit:git-update-index[1] -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt index 51297d09ec..621b720091 100644 --- a/Documentation/git-am.txt +++ b/Documentation/git-am.txt @@ -189,15 +189,6 @@ SEE ALSO -------- linkgit:git-apply[1]. - -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - -Documentation --------------- -Documentation by Petr Baudis, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-annotate.txt b/Documentation/git-annotate.txt index 0590eec056..9eb75c37da 100644 --- a/Documentation/git-annotate.txt +++ b/Documentation/git-annotate.txt @@ -27,10 +27,6 @@ SEE ALSO -------- linkgit:git-blame[1] -AUTHOR ------- -Written by Ryan Anderson <ryan@michonline.com>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt index 2dcfc097d3..afd2c9ae59 100644 --- a/Documentation/git-apply.txt +++ b/Documentation/git-apply.txt @@ -246,20 +246,10 @@ If `--index` is not specified, then the submodule commits in the patch are ignored and only the absence or presence of the corresponding subdirectory is checked and (if possible) updated. - SEE ALSO -------- linkgit:git-am[1]. - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Junio C Hamano - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-archimport.txt b/Documentation/git-archimport.txt index 2411ce5bfe..f4504ba9bf 100644 --- a/Documentation/git-archimport.txt +++ b/Documentation/git-archimport.txt @@ -107,14 +107,6 @@ OPTIONS Archive/branch identifier in a format that `tla log` understands. -Author ------- -Written by Martin Langhoff <martin@laptop.org>. - -Documentation --------------- -Documentation by Junio C Hamano, Martin Langhoff and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt index bf5037ab2a..f2b8684596 100644 --- a/Documentation/git-archive.txt +++ b/Documentation/git-archive.txt @@ -153,14 +153,6 @@ SEE ALSO -------- linkgit:gitattributes[5] -Author ------- -Written by Franck Bui-Huu and Rene Scharfe. - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt index 1701e42e4a..4b4b096ce5 100644 --- a/Documentation/git-bisect.txt +++ b/Documentation/git-bisect.txt @@ -327,14 +327,6 @@ $ git bisect run sh -c "make || exit 125; ~/check_test_case.sh" + Does the same as the previous example, but on a single line. -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation -------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - SEE ALSO -------- link:git-bisect-lk2009.html[Fighting regressions with git bisect], diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt index c71671b4f9..c4d1ff86c9 100644 --- a/Documentation/git-blame.txt +++ b/Documentation/git-blame.txt @@ -198,10 +198,6 @@ SEE ALSO -------- linkgit:git-annotate[1] -AUTHOR ------- -Written by Junio C Hamano <gitster@pobox.com> - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index 9106d38e40..c50f189827 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -232,14 +232,6 @@ linkgit:git-remote[1], link:user-manual.html#what-is-a-branch[``Understanding history: What is a branch?''] in the Git User's Manual. -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> and Junio C Hamano <gitster@pobox.com> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-bundle.txt b/Documentation/git-bundle.txt index 299007b206..92b01ec25d 100644 --- a/Documentation/git-bundle.txt +++ b/Documentation/git-bundle.txt @@ -201,10 +201,6 @@ You can also see what references it offers: $ git ls-remote mybundle ---------------- -Author ------- -Written by Mark Levedahl <mdl123@verizon.net> - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt index 544ba7ba21..2fb95bbd19 100644 --- a/Documentation/git-cat-file.txt +++ b/Documentation/git-cat-file.txt @@ -100,14 +100,6 @@ for each object specified on stdin that does not exist in the repository: <object> SP missing LF ------------ -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-check-attr.txt b/Documentation/git-check-attr.txt index 50824e3a2d..30eca6cee6 100644 --- a/Documentation/git-check-attr.txt +++ b/Documentation/git-check-attr.txt @@ -86,15 +86,6 @@ SEE ALSO -------- linkgit:gitattributes[5]. - -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - -Documentation --------------- -Documentation by James Bowes. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-checkout-index.txt b/Documentation/git-checkout-index.txt index 0c0a9c14bc..4d33e7be0f 100644 --- a/Documentation/git-checkout-index.txt +++ b/Documentation/git-checkout-index.txt @@ -172,18 +172,6 @@ $ git checkout-index --prefix=.merged- Makefile This will check out the currently cached copy of `Makefile` into the file `.merged-Makefile`. - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - - -Documentation --------------- -Documentation by David Greaves, -Junio C Hamano and the git-list <git@vger.kernel.org>. - - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 880763d391..1063f69023 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -9,6 +9,7 @@ SYNOPSIS -------- [verse] 'git checkout' [-q] [-f] [-m] [<branch>] +'git checkout' [-q] [-f] [-m] [--detach] [<commit>] 'git checkout' [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>] 'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>... 'git checkout' --patch [<tree-ish>] [--] [<paths>...] @@ -22,9 +23,10 @@ branch. 'git checkout' [<branch>]:: 'git checkout' -b|-B <new_branch> [<start point>]:: +'git checkout' [--detach] [<commit>]:: This form switches branches by updating the index, working - tree, and HEAD to reflect the specified branch. + tree, and HEAD to reflect the specified branch or commit. + If `-b` is given, a new branch is created as if linkgit:git-branch[1] were called and then checked out; in this case you can @@ -115,6 +117,13 @@ explicitly give a name with '-b' in such a case. Create the new branch's reflog; see linkgit:git-branch[1] for details. +--detach:: + Rather than checking out a branch to work on it, check out a + commit for inspection and discardable experiments. + This is the default behavior of "git checkout <commit>" when + <commit> is not a branch name. See the "DETACHED HEAD" section + below for details. + --orphan:: Create a new 'orphan' branch, named <new_branch>, started from <start_point> and switch to it. The first commit made on this @@ -204,42 +213,140 @@ leave out at most one of `A` and `B`, in which case it defaults to `HEAD`. -Detached HEAD +DETACHED HEAD ------------- +HEAD normally refers to a named branch (e.g. 'master'). Meanwhile, each +branch refers to a specific commit. Let's look at a repo with three +commits, one of them tagged, and with branch 'master' checked out: + +------------ + HEAD (refers to branch 'master') + | + v +a---b---c branch 'master' (refers to commit 'c') + ^ + | + tag 'v2.0' (refers to commit 'b') +------------ -It is sometimes useful to be able to 'checkout' a commit that is -not at the tip of one of your branches. The most obvious -example is to check out the commit at a tagged official release -point, like this: +When a commit is created in this state, the branch is updated to refer to +the new commit. Specifically, 'git commit' creates a new commit 'd', whose +parent is commit 'c', and then updates branch 'master' to refer to new +commit 'd'. HEAD still refers to branch 'master' and so indirectly now refers +to commit 'd': ------------ -$ git checkout v2.6.18 +$ edit; git add; git commit + + HEAD (refers to branch 'master') + | + v +a---b---c---d branch 'master' (refers to commit 'd') + ^ + | + tag 'v2.0' (refers to commit 'b') ------------ -Earlier versions of git did not allow this and asked you to -create a temporary branch using the `-b` option, but starting from -version 1.5.0, the above command 'detaches' your HEAD from the -current branch and directly points at the commit named by the tag -(`v2.6.18` in the example above). +It is sometimes useful to be able to checkout a commit that is not at +the tip of any named branch, or even to create a new commit that is not +referenced by a named branch. Let's look at what happens when we +checkout commit 'b' (here we show two ways this may be done): -You can use all git commands while in this state. You can use -`git reset --hard $othercommit` to further move around, for -example. You can make changes and create a new commit on top of -a detached HEAD. You can even create a merge by using `git -merge $othercommit`. +------------ +$ git checkout v2.0 # or +$ git checkout master^^ + + HEAD (refers to commit 'b') + | + v +a---b---c---d branch 'master' (refers to commit 'd') + ^ + | + tag 'v2.0' (refers to commit 'b') +------------ -The state you are in while your HEAD is detached is not recorded -by any branch (which is natural --- you are not on any branch). -What this means is that you can discard your temporary commits -and merges by switching back to an existing branch (e.g. `git -checkout master`), and a later `git prune` or `git gc` would -garbage-collect them. If you did this by mistake, you can ask -the reflog for HEAD where you were, e.g. +Notice that regardless of which checkout command we use, HEAD now refers +directly to commit 'b'. This is known as being in detached HEAD state. +It means simply that HEAD refers to a specific commit, as opposed to +referring to a named branch. Let's see what happens when we create a commit: ------------ -$ git log -g -2 HEAD +$ edit; git add; git commit + + HEAD (refers to commit 'e') + | + v + e + / +a---b---c---d branch 'master' (refers to commit 'd') + ^ + | + tag 'v2.0' (refers to commit 'b') +------------ + +There is now a new commit 'e', but it is referenced only by HEAD. We can +of course add yet another commit in this state: + +------------ +$ edit; git add; git commit + + HEAD (refers to commit 'f') + | + v + e---f + / +a---b---c---d branch 'master' (refers to commit 'd') + ^ + | + tag 'v2.0' (refers to commit 'b') +------------ + +In fact, we can perform all the normal git operations. But, let's look +at what happens when we then checkout master: + +------------ +$ git checkout master + + HEAD (refers to branch 'master') + e---f | + / v +a---b---c---d branch 'master' (refers to commit 'd') + ^ + | + tag 'v2.0' (refers to commit 'b') ------------ +It is important to realize that at this point nothing refers to commit +'f'. Eventually commit 'f' (and by extension commit 'e') will be deleted +by the routine git garbage collection process, unless we create a reference +before that happens. If we have not yet moved away from commit 'f', +any of these will create a reference to it: + +------------ +$ git checkout -b foo <1> +$ git branch foo <2> +$ git tag foo <3> +------------ + +<1> creates a new branch 'foo', which refers to commit 'f', and then +updates HEAD to refer to branch 'foo'. In other words, we'll no longer +be in detached HEAD state after this command. + +<2> similarly creates a new branch 'foo', which refers to commit 'f', +but leaves HEAD detached. + +<3> creates a new tag 'foo', which refers to commit 'f', +leaving HEAD detached. + +If we have moved away from commit 'f', then we must first recover its object +name (typically by using git reflog), and then we can create a reference to +it. For example, to see the last two commits to which HEAD referred, we +can use either of these commands: + +------------ +$ git reflog -2 HEAD # or +$ git log -g -2 HEAD +------------ EXAMPLES -------- @@ -315,15 +422,6 @@ $ edit frotz $ git add frotz ------------ - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt index 73008705eb..01db83039f 100644 --- a/Documentation/git-cherry-pick.txt +++ b/Documentation/git-cherry-pick.txt @@ -16,6 +16,25 @@ Given one or more existing commits, apply the change each one introduces, recording a new commit for each. This requires your working tree to be clean (no modifications from the HEAD commit). +When it is not obvious how to apply a change, the following +happens: + +1. The current branch and `HEAD` pointer stay at the last commit + successfully made. +2. The `CHERRY_PICK_HEAD` ref is set to point at the commit that + introduced the change that is difficult to apply. +3. Paths in which the change applied cleanly are updated both + in the index file and in your working tree. +4. For conflicting paths, the index file records up to three + versions, as described in the "TRUE MERGE" section of + linkgit:git-merge[1]. The working tree files will include + a description of the conflict bracketed by the usual + conflict markers `<<<<<<<` and `>>>>>>>`. +5. No other modifications are made. + +See linkgit:git-merge[1] for some hints on resolving such +conflicts. + OPTIONS ------- <commit>...:: @@ -79,6 +98,16 @@ effect to your index in a row. cherry-pick'ed commit, then a fast forward to this commit will be performed. +--strategy=<strategy>:: + Use the given merge strategy. Should only be used once. + See the MERGE STRATEGIES section in linkgit:git-merge[1] + for details. + +-X<option>:: +--strategy-option=<option>:: + Pass the merge strategy-specific option through to the + merge strategy. See linkgit:git-merge[1] for details. + EXAMPLES -------- git cherry-pick master:: @@ -120,13 +149,27 @@ git rev-list --reverse master \-- README | git cherry-pick -n --stdin:: so the result can be inspected and made into a single new commit if suitable. -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. +The following sequence attempts to backport a patch, bails out because +the code the patch applies to has changed too much, and then tries +again, this time exercising more care about matching up context lines. + +------------ +$ git cherry-pick topic^ <1> +$ git diff <2> +$ git reset --merge ORIG_HEAD <3> +$ git cherry-pick -Xpatience topic^ <4> +------------ +<1> apply the change that would be shown by `git show topic^`. +In this example, the patch does not apply cleanly, so +information about the conflict is written to the index and +working tree and no new commit results. +<2> summarize changes to be reconciled +<3> cancel the cherry-pick. In other words, return to the +pre-cherry-pick state, preserving any local modifications you had in +the working tree. +<4> try to apply the change introduced by `topic^` again, +spending extra time to avoid mistakes based on incorrectly matching +context lines. SEE ALSO -------- diff --git a/Documentation/git-cherry.txt b/Documentation/git-cherry.txt index fed115acd0..79448c505b 100644 --- a/Documentation/git-cherry.txt +++ b/Documentation/git-cherry.txt @@ -63,14 +63,6 @@ SEE ALSO -------- linkgit:git-patch-id[1] -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-citool.txt b/Documentation/git-citool.txt index fb2753c97e..6e5c8126f5 100644 --- a/Documentation/git-citool.txt +++ b/Documentation/git-citool.txt @@ -19,14 +19,6 @@ to the less interactive 'git commit' program. 'git citool' is actually a standard alias for `git gui citool`. See linkgit:git-gui[1] for more details. -Author ------- -Written by Shawn O. Pearce <spearce@spearce.org>. - -Documentation --------------- -Documentation by Shawn O. Pearce <spearce@spearce.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt index 60e38e6e27..974e04ef1a 100644 --- a/Documentation/git-clean.txt +++ b/Documentation/git-clean.txt @@ -61,12 +61,6 @@ OPTIONS Remove only files ignored by git. This may be useful to rebuild everything from scratch, but keep manually created files. - -Author ------- -Written by Pavel Roskin <proski@gnu.org> - - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index 42e7021215..8577480074 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -236,17 +236,6 @@ $ git clone --bare -l -s /pub/scm/.../torvalds/linux-2.6.git \ /pub/scm/.../me/subsys-2.6.git ------------ - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt index 5dcf4278fc..f524d76019 100644 --- a/Documentation/git-commit-tree.txt +++ b/Documentation/git-commit-tree.txt @@ -93,15 +93,6 @@ SEE ALSO -------- linkgit:git-write-tree[1] - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index 8f89f6f08c..d0534b8c05 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -84,9 +84,10 @@ OPTIONS linkgit:git-rebase[1] for details. --reset-author:: - When used with -C/-c/--amend options, declare that the - authorship of the resulting commit now belongs of the committer. - This also renews the author timestamp. + When used with -C/-c/--amend options, or when committing after a + a conflicting cherry-pick, declare that the authorship of the + resulting commit now belongs of the committer. This also renews + the author timestamp. --short:: When doing a dry-run, give the output in the short-format. See @@ -396,12 +397,6 @@ linkgit:git-mv[1], linkgit:git-merge[1], linkgit:git-commit-tree[1] -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> and -Junio C Hamano <gitster@pobox.com> - - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index 543dd64a46..8804de327f 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -336,15 +336,6 @@ echo "${WS}your whitespace color or blue reverse${RESET}" include::config.txt[] - -Author ------- -Written by Johannes Schindelin <Johannes.Schindelin@gmx.de> - -Documentation --------------- -Documentation by Johannes Schindelin, Petr Baudis and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-count-objects.txt b/Documentation/git-count-objects.txt index 6bc1c21e62..a73933a931 100644 --- a/Documentation/git-count-objects.txt +++ b/Documentation/git-count-objects.txt @@ -25,15 +25,6 @@ OPTIONS and number of objects that can be removed by running `git prune-packed`. - -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-cvsexportcommit.txt b/Documentation/git-cvsexportcommit.txt index d25661eb21..ad93a3e84e 100644 --- a/Documentation/git-cvsexportcommit.txt +++ b/Documentation/git-cvsexportcommit.txt @@ -112,14 +112,6 @@ $ cd ~/project_cvs_checkout $ git cherry cvshead myhead | sed -n 's/^+ //p' | xargs -l1 git cvsexportcommit -c -p -v ------------ -Author ------- -Written by Martin Langhoff <martin@laptop.org> and others. - -Documentation --------------- -Documentation by Martin Langhoff <martin@laptop.org> and others. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt index 608cd63fc3..6695ab3b4b 100644 --- a/Documentation/git-cvsimport.txt +++ b/Documentation/git-cvsimport.txt @@ -217,15 +217,6 @@ more stable in practice: * cvs2git (part of cvs2svn), `http://cvs2svn.tigris.org` * parsecvs, `http://cgit.freedesktop.org/~keithp/parsecvs` -Author ------- -Written by Matthias Urlichs <smurf@smurf.noris.de>, with help from -various participants of the git-list <git@vger.kernel.org>. - -Documentation --------------- -Documentation by Matthias Urlichs <smurf@smurf.noris.de>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt index 70cbb2cae7..88d814af0e 100644 --- a/Documentation/git-cvsserver.txt +++ b/Documentation/git-cvsserver.txt @@ -391,22 +391,6 @@ Dependencies ------------ 'git-cvsserver' depends on DBD::SQLite. -Copyright and Authors ---------------------- - -This program is copyright The Open University UK - 2006. - -Authors: - -- Martyn Smith <martyn@catalyst.net.nz> -- Martin Langhoff <martin@laptop.org> - -with ideas and patches from participants of the git-list <git@vger.kernel.org>. - -Documentation --------------- -Documentation by Martyn Smith <martyn@catalyst.net.nz>, Martin Langhoff <martin@laptop.org>, and Matthias Urlichs <smurf@smurf.noris.de>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt index d15cb6a845..ebd13be72e 100644 --- a/Documentation/git-daemon.txt +++ b/Documentation/git-daemon.txt @@ -279,17 +279,6 @@ that connected to it, if the IP address is available. REMOTE_ADDR will be available in the environment of hooks called when services are performed. - - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org>, YOSHIFUJI Hideaki -<yoshfuji@linux-ipv6.org> and the git-list <git@vger.kernel.org> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt index 02e015ad9c..039cce2e98 100644 --- a/Documentation/git-describe.txt +++ b/Documentation/git-describe.txt @@ -156,17 +156,6 @@ selected and output. Here fewest commits different is defined as the number of commits which would be shown by `git log tag..input` will be the smallest number of commits possible. - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org>, but somewhat -butchered by Junio C Hamano <gitster@pobox.com>. Later significantly -updated by Shawn Pearce <spearce@spearce.org>. - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-diff-files.txt b/Documentation/git-diff-files.txt index 9cd8ccef37..8d481948bd 100644 --- a/Documentation/git-diff-files.txt +++ b/Documentation/git-diff-files.txt @@ -46,15 +46,6 @@ omit diff output for unmerged entries and just show "Unmerged". include::diff-format.txt[] - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-diff-index.txt b/Documentation/git-diff-index.txt index 162cb741b3..6d18486402 100644 --- a/Documentation/git-diff-index.txt +++ b/Documentation/git-diff-index.txt @@ -116,15 +116,6 @@ tell which file is in which state, since the "has been updated" ones show a valid sha1, and the "not in sync with the index" ones will always have the special all-zero sha1. - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-diff-tree.txt b/Documentation/git-diff-tree.txt index a7e37b875f..4e5f127efa 100644 --- a/Documentation/git-diff-tree.txt +++ b/Documentation/git-diff-tree.txt @@ -162,15 +162,6 @@ in case you care). include::diff-format.txt[] - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt index 49105102db..f8d0819113 100644 --- a/Documentation/git-diff.txt +++ b/Documentation/git-diff.txt @@ -174,14 +174,6 @@ linkgit:gitdiffcore[7], linkgit:git-format-patch[1], linkgit:git-apply[1] -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt index db87f1d423..590f410abf 100644 --- a/Documentation/git-difftool.txt +++ b/Documentation/git-difftool.txt @@ -31,8 +31,8 @@ OPTIONS --tool=<tool>:: Use the diff tool specified by <tool>. Valid merge tools are: - kdiff3, kompare, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, - ecmerge, diffuse, opendiff, p4merge and araxis. + araxis, bc3, diffuse, emerge, ecmerge, gvimdiff, kdiff3, + kompare, meld, opendiff, p4merge, tkdiff, vimdiff and xxdiff. + If a diff tool is not specified, 'git difftool' will use the configuration variable `diff.tool`. If the @@ -109,15 +109,6 @@ linkgit:git-mergetool[1]:: linkgit:git-config[1]:: Get and set repository or global options - -AUTHOR ------- -Written by David Aguilar <davvid@gmail.com>. - -Documentation --------------- -Documentation by David Aguilar and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-fast-export.txt b/Documentation/git-fast-export.txt index e05b686b1e..781bd6edc3 100644 --- a/Documentation/git-fast-export.txt +++ b/Documentation/git-fast-export.txt @@ -135,15 +135,6 @@ Since 'git fast-import' cannot tag trees, you will not be able to export the linux-2.6.git repository completely, as it contains a tag referencing a tree instead of a commit. - -Author ------- -Written by Johannes E. Schindelin <johannes.schindelin@gmx.de>. - -Documentation --------------- -Documentation by Johannes E. Schindelin <johannes.schindelin@gmx.de>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt index 02bb49886c..2c2ea12c5c 100644 --- a/Documentation/git-fast-import.txt +++ b/Documentation/git-fast-import.txt @@ -78,6 +78,10 @@ OPTIONS set of marks. If a mark is defined to different values, the last file wins. +--import-marks-if-exists=<file>:: + Like --import-marks but instead of erroring out, silently + skips the file if it does not exist. + --relative-marks:: After specifying --relative-marks= the paths specified with --import-marks= and --export-marks= are relative @@ -192,7 +196,8 @@ especially when a higher level language such as Perl, Python or Ruby is being used. fast-import is very strict about its input. Where we say SP below we mean -*exactly* one space. Likewise LF means one (and only one) linefeed. +*exactly* one space. Likewise LF means one (and only one) linefeed +and HT one (and only one) horizontal tab. Supplying additional whitespace characters will cause unexpected results, such as branch names or file names with leading or trailing spaces in their name, or early termination of fast-import when it encounters @@ -330,6 +335,11 @@ and control the current import process. More detailed discussion format to the file descriptor set with `--cat-blob-fd` or `stdout` if unspecified. +`ls`:: + Causes fast-import to print a line describing a directory + entry in 'ls-tree' format to the file descriptor set with + `--cat-blob-fd` or `stdout` if unspecified. + `feature`:: Require that fast-import supports the specified feature, or abort if it does not. @@ -915,6 +925,55 @@ This command can be used anywhere in the stream that comments are accepted. In particular, the `cat-blob` command can be used in the middle of a commit but not in the middle of a `data` command. +`ls` +~~~~ +Prints information about the object at a path to a file descriptor +previously arranged with the `--cat-blob-fd` argument. This allows +printing a blob from the active commit (with `cat-blob`) or copying a +blob or tree from a previous commit for use in the current one (with +`filemodify`). + +The `ls` command can be used anywhere in the stream that comments are +accepted, including the middle of a commit. + +Reading from the active commit:: + This form can only be used in the middle of a `commit`. + The path names a directory entry within fast-import's + active commit. The path must be quoted in this case. ++ +.... + 'ls' SP <path> LF +.... + +Reading from a named tree:: + The `<dataref>` can be a mark reference (`:<idnum>`) or the + full 40-byte SHA-1 of a Git tag, commit, or tree object, + preexisting or waiting to be written. + The path is relative to the top level of the tree + named by `<dataref>`. ++ +.... + 'ls' SP <dataref> SP <path> LF +.... + +See `filemodify` above for a detailed description of `<path>`. + +Output uses the same format as `git ls-tree <tree> {litdd} <path>`: + +==== + <mode> SP ('blob' | 'tree' | 'commit') SP <dataref> HT <path> LF +==== + +The <dataref> represents the blob, tree, or commit object at <path> +and can be used in later 'cat-blob', 'filemodify', or 'ls' commands. + +If there is no file or subtree at that path, 'git fast-import' will +instead report + +==== + missing SP <path> LF +==== + `feature` ~~~~~~~~~ Require that fast-import supports the specified feature, or abort if @@ -942,8 +1001,10 @@ import-marks:: any "feature import-marks" command in the stream. cat-blob:: - Ignored. Versions of fast-import not supporting the - "cat-blob" command will exit with a message indicating so. +ls:: + Require that the backend support the 'cat-blob' or 'ls' command. + Versions of fast-import not supporting the specified command + will exit with a message indicating so. This lets the import error out early with a clear message, rather than wasting time on the early part of an import before the unsupported command is detected. @@ -1289,14 +1350,6 @@ operator can use this facility to peek at the objects and refs from an import in progress, at the cost of some added running time and worse compression. -Author ------- -Written by Shawn O. Pearce <spearce@spearce.org>. - -Documentation --------------- -Documentation by Shawn O. Pearce <spearce@spearce.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt index 4a8487c154..48d4bf6d68 100644 --- a/Documentation/git-fetch-pack.txt +++ b/Documentation/git-fetch-pack.txt @@ -90,15 +90,6 @@ OPTIONS $GIT_DIR (e.g. "HEAD", "refs/heads/master"). When unspecified, update from all heads the remote side has. - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Junio C Hamano. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt index c76e313923..7146f6ba0b 100644 --- a/Documentation/git-fetch.txt +++ b/Documentation/git-fetch.txt @@ -80,16 +80,6 @@ SEE ALSO -------- linkgit:git-pull[1] - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> and -Junio C Hamano <gitster@pobox.com> - -Documentation -------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt index 796e7489ff..03c76c717a 100644 --- a/Documentation/git-filter-branch.txt +++ b/Documentation/git-filter-branch.txt @@ -405,16 +405,6 @@ warned. (or if your git-gc is not new enough to support arguments to `\--prune`, use `git repack -ad; git prune` instead). - -Author ------- -Written by Petr "Pasky" Baudis <pasky@suse.cz>, -and the git list <git@vger.kernel.org> - -Documentation --------------- -Documentation by Petr Baudis and the git list. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-fmt-merge-msg.txt b/Documentation/git-fmt-merge-msg.txt index 75adf7a502..32aff954a2 100644 --- a/Documentation/git-fmt-merge-msg.txt +++ b/Documentation/git-fmt-merge-msg.txt @@ -67,15 +67,6 @@ SEE ALSO -------- linkgit:git-merge[1] - -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - -Documentation --------------- -Documentation by Petr Baudis, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index 9dcafc6d44..a5525e9aa8 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -278,15 +278,6 @@ SEE ALSO -------- linkgit:git-am[1], linkgit:git-send-email[1] - -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-fsck-objects.txt b/Documentation/git-fsck-objects.txt index 965a8279c1..90ebb8a594 100644 --- a/Documentation/git-fsck-objects.txt +++ b/Documentation/git-fsck-objects.txt @@ -15,3 +15,7 @@ DESCRIPTION This is a synonym for linkgit:git-fsck[1]. Please refer to the documentation of that command. + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Documentation/git-fsck.txt b/Documentation/git-fsck.txt index 86f9b2bf91..c9ede794b0 100644 --- a/Documentation/git-fsck.txt +++ b/Documentation/git-fsck.txt @@ -140,14 +140,6 @@ GIT_INDEX_FILE:: GIT_ALTERNATE_OBJECT_DIRECTORIES:: used to specify additional object database roots (usually unset) -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt index 26632414b2..4966cb5784 100644 --- a/Documentation/git-gc.txt +++ b/Documentation/git-gc.txt @@ -151,10 +151,6 @@ linkgit:git-reflog[1] linkgit:git-repack[1] linkgit:git-rerere[1] -Author ------- -Written by Shawn O. Pearce <spearce@spearce.org> - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-get-tar-commit-id.txt b/Documentation/git-get-tar-commit-id.txt index 790af9573b..8035736c96 100644 --- a/Documentation/git-get-tar-commit-id.txt +++ b/Documentation/git-get-tar-commit-id.txt @@ -22,15 +22,6 @@ return code of 1. This can happen if <tarfile> had not been created using 'git archive' or if the first parameter of 'git archive' had been a tree ID instead of a commit ID or tag. - -Author ------- -Written by Rene Scharfe <rene.scharfe@lsrfire.ath.cx> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index dab0a78fa8..d4d425ea30 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -203,16 +203,6 @@ git grep --all-match -e NODE -e Unexpected:: Looks for a line that has `NODE` or `Unexpected` in files that have lines that match both. -Author ------- -Originally written by Linus Torvalds <torvalds@osdl.org>, later -revamped by Junio C Hamano. - - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-gui.txt b/Documentation/git-gui.txt index 2563710b56..32a833e0ae 100644 --- a/Documentation/git-gui.txt +++ b/Documentation/git-gui.txt @@ -121,14 +121,6 @@ or or browsed online at http://repo.or.cz/w/git-gui.git/[]. -Author ------- -Written by Shawn O. Pearce <spearce@spearce.org>. - -Documentation --------------- -Documentation by Shawn O. Pearce <spearce@spearce.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-hash-object.txt b/Documentation/git-hash-object.txt index 51edeecbe5..4b0a502e8e 100644 --- a/Documentation/git-hash-object.txt +++ b/Documentation/git-hash-object.txt @@ -53,14 +53,6 @@ OPTIONS conversion. If the file is read from standard input then this is always implied, unless the --path option is given. -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-help.txt b/Documentation/git-help.txt index eccd0ffd38..42aa2b0c01 100644 --- a/Documentation/git-help.txt +++ b/Documentation/git-help.txt @@ -171,17 +171,6 @@ $ git config --global web.browser firefox as they are probably more user specific than repository specific. See linkgit:git-config[1] for more information about this. -Author ------- -Written by Junio C Hamano <gitster@pobox.com> and the git-list -<git@vger.kernel.org>. - -Documentation -------------- -Initial documentation was part of the linkgit:git[1] man page. -Christian Couder <chriscool@tuxfamily.org> extracted and rewrote it a -little. Maintenance is done by the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-http-fetch.txt b/Documentation/git-http-fetch.txt index d91cb7ff85..fefa752198 100644 --- a/Documentation/git-http-fetch.txt +++ b/Documentation/git-http-fetch.txt @@ -43,14 +43,6 @@ commit-id:: Verify that everything reachable from target is fetched. Used after an earlier fetch is interrupted. -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-http-push.txt b/Documentation/git-http-push.txt index ddf7a18dc4..82ae34b9b8 100644 --- a/Documentation/git-http-push.txt +++ b/Documentation/git-http-push.txt @@ -91,15 +91,6 @@ With '--force', the fast-forward check is disabled for all refs. Optionally, a <ref> parameter can be prefixed with a plus '+' sign to disable the fast-forward check only on that ref. - -Author ------- -Written by Nick Hengeveld <nickh@reactrix.com> - -Documentation --------------- -Documentation by Nick Hengeveld - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt index 57aba42e66..d3013d6a29 100644 --- a/Documentation/git-imap-send.txt +++ b/Documentation/git-imap-send.txt @@ -124,14 +124,6 @@ Thunderbird in particular is known to be problematic. Thunderbird users may wish to visit this web page for more information: http://kb.mozillazine.org/Plain_text_e-mail_-_Thunderbird#Completely_plain_email -Author ------- -Derived from isync 1.0.1 by Mike McCormack. - -Documentation --------------- -Documentation by Mike McCormack - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-index-pack.txt b/Documentation/git-index-pack.txt index c2bb81042c..909687fed4 100644 --- a/Documentation/git-index-pack.txt +++ b/Documentation/git-index-pack.txt @@ -85,15 +85,6 @@ new .keep file was successfully created. This is useful to remove a .keep file used as a lock to prevent the race with 'git repack' mentioned above. - -Author ------- -Written by Sergey Vlasov <vsu@altlinux.ru> - -Documentation -------------- -Documentation by Sergey Vlasov - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-init-db.txt b/Documentation/git-init-db.txt index eba3cb4998..2c4c716f33 100644 --- a/Documentation/git-init-db.txt +++ b/Documentation/git-init-db.txt @@ -16,3 +16,7 @@ DESCRIPTION This is a synonym for linkgit:git-init[1]. Please refer to the documentation of that command. + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Documentation/git-init.txt b/Documentation/git-init.txt index 00d4a124c9..593192555e 100644 --- a/Documentation/git-init.txt +++ b/Documentation/git-init.txt @@ -134,15 +134,6 @@ $ git add . <2> <1> prepare /path/to/my/codebase/.git directory <2> add all existing file to the index - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-instaweb.txt b/Documentation/git-instaweb.txt index 7477ce8fa8..08f85ba046 100644 --- a/Documentation/git-instaweb.txt +++ b/Documentation/git-instaweb.txt @@ -84,14 +84,6 @@ If the configuration variable 'instaweb.browser' is not set, 'web.browser' will be used instead if it is defined. See linkgit:git-web{litdd}browse[1] for more information about this. -Author ------- -Written by Eric Wong <normalperson@yhbt.net> - -Documentation --------------- -Documentation by Eric Wong <normalperson@yhbt.net>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt index ff41784c60..2c84028838 100644 --- a/Documentation/git-log.txt +++ b/Documentation/git-log.txt @@ -25,6 +25,7 @@ OPTIONS -<n>:: Limits the number of commits to show. + Note that this is a commit limiting option, see below. <since>..<until>:: Show only commits between the named two commits. When @@ -72,16 +73,16 @@ produced by --stat etc. to be prefixed with "\-- " to separate them from options or refnames. +include::rev-list-options.txt[] + +include::pretty-formats.txt[] + Common diff options -~~~~~~~~~~~~~~~~~~~ +------------------- :git-log: 1 include::diff-options.txt[] -include::rev-list-options.txt[] - -include::pretty-formats.txt[] - include::diff-generate-patch.txt[] Examples @@ -181,14 +182,6 @@ This setting can be disabled by the `--no-standard-notes` option, overridden by the 'GIT_NOTES_DISPLAY_REF' environment variable, and supplemented by the `--show-notes` option. -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-lost-found.txt b/Documentation/git-lost-found.txt index 602b8d5d4d..adf7e1c055 100644 --- a/Documentation/git-lost-found.txt +++ b/Documentation/git-lost-found.txt @@ -67,15 +67,6 @@ $ git rev-parse not-lost-anymore 1ef2b196d909eed523d4f3c9bf54b78cdd6843c6 ------------ -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt index 86abd13451..4b28292811 100644 --- a/Documentation/git-ls-files.txt +++ b/Documentation/git-ls-files.txt @@ -209,15 +209,6 @@ SEE ALSO -------- linkgit:git-read-tree[1], linkgit:gitignore[5] - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano, Josh Triplett, and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt index 3422765827..c3df8c0ebe 100644 --- a/Documentation/git-ls-remote.txt +++ b/Documentation/git-ls-remote.txt @@ -67,10 +67,6 @@ EXAMPLES c5db5456ae3b0873fc659c19fafdde22313cc441 refs/tags/v0.99.2 7ceca275d047c90c0c7d5afb13ab97efdf51bd6e refs/tags/v0.99.3 -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-ls-tree.txt b/Documentation/git-ls-tree.txt index 76ed625e7b..16e87fd6dd 100644 --- a/Documentation/git-ls-tree.txt +++ b/Documentation/git-ls-tree.txt @@ -95,18 +95,6 @@ Object size identified by <object> is given in bytes, and right-justified with minimum width of 7 characters. Object size is given only for blobs (file) entries; for other entries `-` character is used in place of size. - -Author ------- -Written by Petr Baudis <pasky@suse.cz> -Completely rewritten from scratch by Junio C Hamano <gitster@pobox.com>, -another major rewrite by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list -<git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-mailinfo.txt b/Documentation/git-mailinfo.txt index 3ea5aad56c..ed45662cc9 100644 --- a/Documentation/git-mailinfo.txt +++ b/Documentation/git-mailinfo.txt @@ -80,17 +80,6 @@ This can enabled by default with the configuration option mailinfo.scissors. <patch>:: The patch extracted from e-mail. - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> and -Junio C Hamano <gitster@pobox.com> - - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-mailsplit.txt b/Documentation/git-mailsplit.txt index 71912a19a4..9b2049d674 100644 --- a/Documentation/git-mailsplit.txt +++ b/Documentation/git-mailsplit.txt @@ -46,16 +46,6 @@ OPTIONS --keep-cr:: Do not remove `\r` from lines ending with `\r\n`. -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> -and Junio C Hamano <gitster@pobox.com> - - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-merge-base.txt b/Documentation/git-merge-base.txt index eedef1bb1a..ba36ec04f4 100644 --- a/Documentation/git-merge-base.txt +++ b/Documentation/git-merge-base.txt @@ -102,14 +102,6 @@ both '1' and '2' are merge-bases of A and B. Neither one is better than the other (both are 'best' merge bases). When the `--all` option is not given, it is unspecified which best one is output. -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - See also -------- linkgit:git-rev-list[1], diff --git a/Documentation/git-merge-file.txt b/Documentation/git-merge-file.txt index f334d694e0..635c66956e 100644 --- a/Documentation/git-merge-file.txt +++ b/Documentation/git-merge-file.txt @@ -86,17 +86,6 @@ git merge-file -L a -L b -L c tmp/a123 tmp/b234 tmp/c345:: merges tmp/a123 and tmp/c345 with the base tmp/b234, but uses labels `a` and `c` instead of `tmp/a123` and `tmp/c345`. - -Author ------- -Written by Johannes Schindelin <johannes.schindelin@gmx.de> - - -Documentation --------------- -Documentation by Johannes Schindelin and the git-list <git@vger.kernel.org>, -with parts copied from the original documentation of RCS 'merge'. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-merge-index.txt b/Documentation/git-merge-index.txt index 921b38f183..6ce54673b0 100644 --- a/Documentation/git-merge-index.txt +++ b/Documentation/git-merge-index.txt @@ -73,15 +73,6 @@ merge once anything has returned an error (i.e., `cat` returned an error for the AA file, because it didn't exist in the original, and thus 'git merge-index' didn't even try to merge the MM thing). -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> -One-shot merge by Petr Baudis <pasky@ucw.cz> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-merge-one-file.txt b/Documentation/git-merge-one-file.txt index a163cfca69..ee059def79 100644 --- a/Documentation/git-merge-one-file.txt +++ b/Documentation/git-merge-one-file.txt @@ -15,15 +15,6 @@ DESCRIPTION This is the standard helper program to use with 'git merge-index' to resolve a merge after the trivial merge done with 'git read-tree -m'. -Author ------- -Written by Linus Torvalds <torvalds@osdl.org>, -Junio C Hamano <gitster@pobox.com> and Petr Baudis <pasky@suse.cz>. - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt index f869a7f00f..3bfa7b4220 100644 --- a/Documentation/git-merge-tree.txt +++ b/Documentation/git-merge-tree.txt @@ -23,14 +23,6 @@ merge results outside of the index, and stuff the results back into the index. For this reason, the output from the command omits entries that match the <branch1> tree. -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt index c1efaaa5c5..fb4c05b83f 100644 --- a/Documentation/git-merge.txt +++ b/Documentation/git-merge.txt @@ -312,15 +312,6 @@ linkgit:git-diff[1], linkgit:git-ls-files[1], linkgit:git-add[1], linkgit:git-rm[1], linkgit:git-mergetool[1] -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-mergetool--lib.txt b/Documentation/git-mergetool--lib.txt index d8df55362c..63ededec1d 100644 --- a/Documentation/git-mergetool--lib.txt +++ b/Documentation/git-mergetool--lib.txt @@ -41,14 +41,6 @@ run_merge_tool:: '$MERGED', '$LOCAL', '$REMOTE', and '$BASE' must be defined for use by the merge tool. -Author ------- -Written by David Aguilar <davvid@gmail.com> - -Documentation --------------- -Documentation by David Aguilar and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt index 1f75a848ba..8c79ae8d2a 100644 --- a/Documentation/git-mergetool.txt +++ b/Documentation/git-mergetool.txt @@ -26,8 +26,8 @@ OPTIONS --tool=<tool>:: Use the merge resolution program specified by <tool>. Valid merge tools are: - kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, - diffuse, tortoisemerge, opendiff, p4merge and araxis. + araxis, bc3, diffuse, ecmerge, emerge, gvimdiff, kdiff3, + meld, opendiff, p4merge, tkdiff, tortoisemerge, vimdiff and xxdiff. + If a merge resolution program is not specified, 'git mergetool' will use the configuration variable `merge.tool`. If the @@ -82,14 +82,6 @@ Setting the `mergetool.keepBackup` configuration variable to `false` causes `git mergetool` to automatically remove the backup as files are successfully merged. -Author ------- -Written by Theodore Y Ts'o <tytso@mit.edu> - -Documentation --------------- -Documentation by Theodore Y Ts'o. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-mktag.txt b/Documentation/git-mktag.txt index 8bcc11443d..037ab1045d 100644 --- a/Documentation/git-mktag.txt +++ b/Documentation/git-mktag.txt @@ -32,15 +32,6 @@ exists, is separated by a blank line from the header. The message part may contain a signature that git itself doesn't care about, but that can be verified with gpg. - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-mktree.txt b/Documentation/git-mktree.txt index 81e3326772..afe21be64d 100644 --- a/Documentation/git-mktree.txt +++ b/Documentation/git-mktree.txt @@ -34,14 +34,6 @@ OPTIONS optional. Note - if the '-z' option is used, lines are terminated with NUL. -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-mv.txt b/Documentation/git-mv.txt index bdcb58526e..db0e030d69 100644 --- a/Documentation/git-mv.txt +++ b/Documentation/git-mv.txt @@ -39,17 +39,6 @@ OPTIONS --dry-run:: Do nothing; only show what would happen - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> -Rewritten by Ryan Anderson <ryan@michonline.com> -Move functionality added by Josef Weidendorfer <Josef.Weidendorfer@gmx.de> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-name-rev.txt b/Documentation/git-name-rev.txt index 2108237c36..ad1d1468c9 100644 --- a/Documentation/git-name-rev.txt +++ b/Documentation/git-name-rev.txt @@ -70,15 +70,6 @@ Another nice thing you can do is: % git log | git name-rev --stdin ------------ - -Author ------- -Written by Johannes Schindelin <Johannes.Schindelin@gmx.de> - -Documentation --------------- -Documentation by Johannes Schindelin. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.txt index 65eff66afe..a51071e524 100644 --- a/Documentation/git-pack-objects.txt +++ b/Documentation/git-pack-objects.txt @@ -219,15 +219,6 @@ self-contained. Use `git index-pack --fix-thin` With this option, parents that are hidden by grafts are packed nevertheless. - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation -------------- -Documentation by Junio C Hamano - SEE ALSO -------- linkgit:git-rev-list[1] diff --git a/Documentation/git-pack-redundant.txt b/Documentation/git-pack-redundant.txt index d0607879db..db9f0f7055 100644 --- a/Documentation/git-pack-redundant.txt +++ b/Documentation/git-pack-redundant.txt @@ -38,14 +38,6 @@ OPTIONS --verbose:: Outputs some statistics to stderr. Has a small performance penalty. -Author ------- -Written by Lukas Sandström <lukass@etek.chalmers.se> - -Documentation --------------- -Documentation by Lukas Sandström <lukass@etek.chalmers.se> - SEE ALSO -------- linkgit:git-pack-objects[1] diff --git a/Documentation/git-pack-refs.txt b/Documentation/git-pack-refs.txt index 1ee99c208c..54b92534ce 100644 --- a/Documentation/git-pack-refs.txt +++ b/Documentation/git-pack-refs.txt @@ -56,11 +56,6 @@ a repository with many branches of historical interests. The command usually removes loose refs under `$GIT_DIR/refs` hierarchy after packing them. This option tells it not to. - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-parse-remote.txt b/Documentation/git-parse-remote.txt index 39d9daa7e0..02217f6ba2 100644 --- a/Documentation/git-parse-remote.txt +++ b/Documentation/git-parse-remote.txt @@ -17,14 +17,6 @@ routines to parse files under $GIT_DIR/remotes/ and $GIT_DIR/branches/ and configuration variables that are related to fetching, pulling and pushing. -Author ------- -Written by Junio C Hamano. - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-patch-id.txt b/Documentation/git-patch-id.txt index 4dae1390a5..50e26f43c1 100644 --- a/Documentation/git-patch-id.txt +++ b/Documentation/git-patch-id.txt @@ -29,14 +29,6 @@ OPTIONS <patch>:: The diff to create the ID of. -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-peek-remote.txt b/Documentation/git-peek-remote.txt index 87dacd797f..a34d62f0da 100644 --- a/Documentation/git-peek-remote.txt +++ b/Documentation/git-peek-remote.txt @@ -37,14 +37,6 @@ OPTIONS The repository to sync from. -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - -Documentation --------------- -Documentation by Junio C Hamano. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-prune-packed.txt b/Documentation/git-prune-packed.txt index abfc6b6ead..9e6202cdff 100644 --- a/Documentation/git-prune-packed.txt +++ b/Documentation/git-prune-packed.txt @@ -36,14 +36,6 @@ OPTIONS --quiet:: Squelch the progress indicator. -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Ryan Anderson <ryan@michonline.com> - SEE ALSO -------- linkgit:git-pack-objects[1] diff --git a/Documentation/git-prune.txt b/Documentation/git-prune.txt index 4d673a5686..f616a739ef 100644 --- a/Documentation/git-prune.txt +++ b/Documentation/git-prune.txt @@ -78,14 +78,6 @@ linkgit:git-fsck[1], linkgit:git-gc[1], linkgit:git-reflog[1] -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt index b33e6be872..c2a7f103ee 100644 --- a/Documentation/git-pull.txt +++ b/Documentation/git-pull.txt @@ -224,18 +224,6 @@ SEE ALSO -------- linkgit:git-fetch[1], linkgit:git-merge[1], linkgit:git-config[1] - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> -and Junio C Hamano <gitster@pobox.com> - -Documentation --------------- -Documentation by Jon Loeliger, -David Greaves, -Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index e11660a2e6..88acfcd4cc 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -406,16 +406,6 @@ Commits A and B would no longer belong to a branch with a symbolic name, and so would be unreachable. As such, these commits would be removed by a `git gc` command on the origin repository. - -Author ------- -Written by Junio C Hamano <gitster@pobox.com>, later rewritten in C -by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-quiltimport.txt b/Documentation/git-quiltimport.txt index 579e8d2f3b..7f112f3dcd 100644 --- a/Documentation/git-quiltimport.txt +++ b/Documentation/git-quiltimport.txt @@ -49,14 +49,6 @@ The default for the patch directory is patches or the value of the $QUILT_PATCHES environment variable. -Author ------- -Written by Eric Biederman <ebiederm@lnxi.com> - -Documentation --------------- -Documentation by Eric Biederman <ebiederm@lnxi.com> - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt index 634423a69e..26fdadc642 100644 --- a/Documentation/git-read-tree.txt +++ b/Documentation/git-read-tree.txt @@ -421,15 +421,6 @@ SEE ALSO linkgit:git-write-tree[1]; linkgit:git-ls-files[1]; linkgit:gitignore[5] - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 96680c8456..620d50e71f 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -66,8 +66,9 @@ would be: D---E---F---G master ------------ -The latter form is just a short-hand of `git checkout topic` -followed by `git rebase master`. +*NOTE:* The latter form is just a short-hand of `git checkout topic` +followed by `git rebase master`. When rebase exits `topic` will +remain the checked-out branch. If the upstream branch already contains a change you have made (e.g., because you mailed a patch which was applied upstream), then that commit @@ -658,7 +659,6 @@ The ripple effect of a "hard case" recovery is especially bad: 'everyone' downstream from 'topic' will now have to perform a "hard case" recovery too! - BUGS ---- The todo list presented by `--preserve-merges --interactive` does not @@ -681,15 +681,6 @@ by moving the "pick 4" line will result in the following history: 1 --- 2 --- 4 --- 5 ------------ -Authors ------- -Written by Junio C Hamano <gitster@pobox.com> and -Johannes E. Schindelin <johannes.schindelin@gmx.de> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-receive-pack.txt b/Documentation/git-receive-pack.txt index 2790eebaff..f34e0ae1bd 100644 --- a/Documentation/git-receive-pack.txt +++ b/Documentation/git-receive-pack.txt @@ -151,15 +151,6 @@ SEE ALSO -------- linkgit:git-send-pack[1] - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Junio C Hamano. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-reflog.txt b/Documentation/git-reflog.txt index e50bd9b68d..09057bf90c 100644 --- a/Documentation/git-reflog.txt +++ b/Documentation/git-reflog.txt @@ -90,14 +90,6 @@ them. --verbose:: Print extra information on screen. -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-relink.txt b/Documentation/git-relink.txt index 8fc809f82b..9893376487 100644 --- a/Documentation/git-relink.txt +++ b/Documentation/git-relink.txt @@ -24,14 +24,6 @@ OPTIONS <dir>:: Directories containing a .git/objects/ subdirectory. -Author ------- -Written by Ryan Anderson <ryan@michonline.com> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-remote-helpers.txt b/Documentation/git-remote-helpers.txt index 51de895822..87cd11f2c4 100644 --- a/Documentation/git-remote-helpers.txt +++ b/Documentation/git-remote-helpers.txt @@ -239,10 +239,6 @@ SEE ALSO -------- linkgit:git-remote[1] -Documentation -------------- -Documentation by Daniel Barkalow and Ilari Liusvaara - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt index c258ea48db..37bd3e5388 100644 --- a/Documentation/git-remote.txt +++ b/Documentation/git-remote.txt @@ -214,16 +214,6 @@ linkgit:git-fetch[1] linkgit:git-branch[1] linkgit:git-config[1] -Author ------- -Written by Junio Hamano - - -Documentation --------------- -Documentation by J. Bruce Fields and the git-list <git@vger.kernel.org>. - - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt index 27f7865b06..0decee240b 100644 --- a/Documentation/git-repack.txt +++ b/Documentation/git-repack.txt @@ -123,15 +123,6 @@ need to set the configuration variable `repack.UseDeltaBaseOffset` to is unaffected by this option as the conversion is performed on the fly as needed in that case. - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Ryan Anderson <ryan@michonline.com> - SEE ALSO -------- linkgit:git-pack-objects[1] diff --git a/Documentation/git-replace.txt b/Documentation/git-replace.txt index fde2092582..17df525275 100644 --- a/Documentation/git-replace.txt +++ b/Documentation/git-replace.txt @@ -80,17 +80,6 @@ linkgit:git-tag[1] linkgit:git-branch[1] linkgit:git[1] -Author ------- -Written by Christian Couder <chriscool@tuxfamily.org> and Junio C -Hamano <gitster@pobox.com>, based on 'git tag' by Kristian Hogsberg -<krh@redhat.com> and Carlos Rica <jasampler@gmail.com>. - -Documentation --------------- -Documentation by Christian Couder <chriscool@tuxfamily.org> and the -git-list <git@vger.kernel.org>, based on 'git tag' documentation. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-repo-config.txt b/Documentation/git-repo-config.txt index e5bdb5533e..a0d1fa6594 100644 --- a/Documentation/git-repo-config.txt +++ b/Documentation/git-repo-config.txt @@ -16,3 +16,7 @@ DESCRIPTION This is a synonym for linkgit:git-config[1]. Please refer to the documentation of that command. + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Documentation/git-request-pull.txt b/Documentation/git-request-pull.txt index 400f61f6e2..3521d8e3c8 100644 --- a/Documentation/git-request-pull.txt +++ b/Documentation/git-request-pull.txt @@ -29,14 +29,6 @@ OPTIONS <end>:: Commit to end at; defaults to HEAD. -Author ------- -Written by Ryan Anderson <ryan@michonline.com> and Junio C Hamano <gitster@pobox.com> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-rerere.txt b/Documentation/git-rerere.txt index db99d4786e..52db1d80cf 100644 --- a/Documentation/git-rerere.txt +++ b/Documentation/git-rerere.txt @@ -7,7 +7,7 @@ git-rerere - Reuse recorded resolution of conflicted merges SYNOPSIS -------- -'git rerere' ['clear'|'forget' [<pathspec>]|'diff'|'status'|'gc'] +'git rerere' ['clear'|'forget' <pathspec>|'diff'|'status'|'gc'] DESCRIPTION ----------- @@ -43,7 +43,7 @@ will automatically invoke this command. 'forget' <pathspec>:: This resets the conflict resolutions which rerere has recorded for the current -conflict in <pathspec>. The <pathspec> is optional. +conflict in <pathspec>. 'diff':: @@ -205,11 +205,6 @@ would conflict the same way as the test merge you resolved earlier. 'git rerere' will be run by 'git rebase' to help you resolve this conflict. - -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt index 927ecee2f2..8481f9db74 100644 --- a/Documentation/git-reset.txt +++ b/Documentation/git-reset.txt @@ -397,15 +397,6 @@ entries: X means any state and U means an unmerged index. - -Author ------- -Written by Junio C Hamano <gitster@pobox.com> and Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index 8e1e32908c..5ce4d7fd0b 100644 --- a/Documentation/git-rev-list.txt +++ b/Documentation/git-rev-list.txt @@ -105,16 +105,6 @@ include::rev-list-options.txt[] include::pretty-formats.txt[] - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano, Jonas Fonseca -and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index ff23cb0219..02c44c999f 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -308,16 +308,6 @@ $ git rev-parse --default master --verify $REV + but if $REV is empty, the commit object name from master will be printed. - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> . -Junio C Hamano <gitster@pobox.com> and Pierre Habouzit <madcoder@debian.org> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt index 752fc88e76..ac10cfbb14 100644 --- a/Documentation/git-revert.txt +++ b/Documentation/git-revert.txt @@ -80,6 +80,16 @@ effect to your index in a row. --signoff:: Add Signed-off-by line at the end of the commit message. +--strategy=<strategy>:: + Use the given merge strategy. Should only be used once. + See the MERGE STRATEGIES section in linkgit:git-merge[1] + for details. + +-X<option>:: +--strategy-option=<option>:: + Pass the merge strategy-specific option through to the + merge strategy. See linkgit:git-merge[1] for details. + EXAMPLES -------- git revert HEAD~3:: @@ -95,14 +105,6 @@ git revert -n master{tilde}5..master{tilde}2:: changes. The revert only modifies the working tree and the index. -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - SEE ALSO -------- linkgit:git-cherry-pick[1] diff --git a/Documentation/git-rm.txt b/Documentation/git-rm.txt index 0adbe8b1f8..8c0554f971 100644 --- a/Documentation/git-rm.txt +++ b/Documentation/git-rm.txt @@ -153,14 +153,6 @@ SEE ALSO -------- linkgit:git-add[1] -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index 7ec9dabe68..ee14f74fd3 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -348,7 +348,6 @@ sendemail.confirm:: one of 'always', 'never', 'cc', 'compose', or 'auto'. See '--confirm' in the previous section for the meaning of these values. - Use gmail as the smtp server ---------------------------- @@ -363,20 +362,6 @@ Add the following section to the config file: Note: the following perl modules are required Net::SMTP::SSL, MIME::Base64 and Authen::SASL - -Author ------- -Written by Ryan Anderson <ryan@michonline.com> - -git-send-email is originally based upon -send_lots_of_email.pl by Greg Kroah-Hartman. - - -Documentation --------------- -Documentation by Ryan Anderson - - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt index deaa7d9654..17f8f55526 100644 --- a/Documentation/git-send-pack.txt +++ b/Documentation/git-send-pack.txt @@ -114,15 +114,6 @@ With '--force', the fast-forward check is disabled for all refs. Optionally, a <ref> parameter can be prefixed with a plus '+' sign to disable the fast-forward check only on that ref. - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Junio C Hamano. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-sh-setup.txt b/Documentation/git-sh-setup.txt index 3da241304b..053df505bc 100644 --- a/Documentation/git-sh-setup.txt +++ b/Documentation/git-sh-setup.txt @@ -66,15 +66,6 @@ get_author_ident_from_commit:: outputs code for use with eval to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL and GIT_AUTHOR_DATE variables for a given commit. - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-shell.txt b/Documentation/git-shell.txt index 6403126a02..d7d4b92894 100644 --- a/Documentation/git-shell.txt +++ b/Documentation/git-shell.txt @@ -28,14 +28,6 @@ read and execute permissions to the directory in order to execute the programs in it. The programs are executed with a cwd of $HOME, and <argument> is parsed as a command-line string. -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Petr Baudis and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt index 5cc3baf48d..ff3755b4c7 100644 --- a/Documentation/git-shortlog.txt +++ b/Documentation/git-shortlog.txt @@ -68,15 +68,6 @@ spelled differently. include::mailmap.txt[] - -Author ------- -Written by Jeff Garzik <jgarzik@pobox.com> - -Documentation --------------- -Documentation by Junio C Hamano. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt index 3b0c88271a..ee4559b6f2 100644 --- a/Documentation/git-show-branch.txt +++ b/Documentation/git-show-branch.txt @@ -200,17 +200,6 @@ shows 10 reflog entries going back from the tip as of 1 hour ago. Without `--list`, the output also shows how these tips are topologically related with each other. - -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - - -Documentation --------------- -Documentation by Junio C Hamano. - - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-show-index.txt b/Documentation/git-show-index.txt index 8382fbe0ec..c4d99f1028 100644 --- a/Documentation/git-show-index.txt +++ b/Documentation/git-show-index.txt @@ -20,15 +20,6 @@ The information it outputs is subset of what you can get from 'git verify-pack -v'; this command only shows the packfile offset and SHA1 of each object. - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Junio C Hamano - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt index be0ec189af..3c45895299 100644 --- a/Documentation/git-show-ref.txt +++ b/Documentation/git-show-ref.txt @@ -177,11 +177,6 @@ linkgit:git-ls-remote[1], linkgit:git-update-ref[1], linkgit:gitrepository-layout[5] -AUTHORS -------- -Written by Linus Torvalds <torvalds@osdl.org>. -Man page by Jonas Fonseca <fonseca@diku.dk>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-show.txt b/Documentation/git-show.txt index f0a8a1aff3..7f075e84f5 100644 --- a/Documentation/git-show.txt +++ b/Documentation/git-show.txt @@ -72,17 +72,6 @@ Discussion include::i18n.txt[] -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> and -Junio C Hamano <gitster@pobox.com>. Significantly enhanced by -Johannes Schindelin <Johannes.Schindelin@gmx.de>. - - -Documentation -------------- -Documentation by David Greaves, Petr Baudis and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-stage.txt b/Documentation/git-stage.txt index 7f251a5865..ba3fe0d7f5 100644 --- a/Documentation/git-stage.txt +++ b/Documentation/git-stage.txt @@ -17,3 +17,7 @@ DESCRIPTION This is a synonym for linkgit:git-add[1]. Please refer to the documentation of that command. + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt index 8728f7a514..79abc38e50 100644 --- a/Documentation/git-stash.txt +++ b/Documentation/git-stash.txt @@ -257,10 +257,6 @@ linkgit:git-commit[1], linkgit:git-reflog[1], linkgit:git-reset[1] -AUTHOR ------- -Written by Nanako Shiraishi <nanako3@bluebottle.com> - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index 5102a23f8e..00b699fef7 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -174,14 +174,6 @@ SEE ALSO -------- linkgit:gitignore[5] -Author ------- -Written by Junio C Hamano <gitster@pobox.com>. - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-stripspace.txt b/Documentation/git-stripspace.txt index 7508c0e42d..10509cc450 100644 --- a/Documentation/git-stripspace.txt +++ b/Documentation/git-stripspace.txt @@ -23,14 +23,6 @@ OPTIONS <stream>:: Byte stream to act on. -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index 1ed331c599..3a5aa01435 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -257,11 +257,6 @@ This file should be formatted in the same way as `$GIT_DIR/config`. The key to each submodule url is "submodule.$name.url". See linkgit:gitmodules[5] for details. - -AUTHOR ------- -Written by Lars Hjemli <hjemli@gmail.com> - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index e161a40a73..ea8fafd18a 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -878,10 +878,6 @@ SEE ALSO -------- linkgit:git-rebase[1] -Author ------- -Written by Eric Wong <normalperson@yhbt.net>. - -Documentation -------------- -Written by Eric Wong <normalperson@yhbt.net>. +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt index 33a1536294..d7795ed657 100644 --- a/Documentation/git-symbolic-ref.txt +++ b/Documentation/git-symbolic-ref.txt @@ -53,10 +53,6 @@ and symbolic refs are used by default. symbolic ref were printed correctly, with status 1 if the requested name is not a symbolic ref, or 128 if another error occurs. -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 65f76c5440..61263fa329 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -262,15 +262,6 @@ SEE ALSO -------- linkgit:git-check-ref-format[1]. -Author ------- -Written by Linus Torvalds <torvalds@osdl.org>, -Junio C Hamano <gitster@pobox.com> and Chris Wright <chrisw@osdl.org>. - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-tar-tree.txt b/Documentation/git-tar-tree.txt index 3c786bd283..5f15754257 100644 --- a/Documentation/git-tar-tree.txt +++ b/Documentation/git-tar-tree.txt @@ -76,14 +76,6 @@ git tar-tree HEAD:Documentation/ git-docs > git-1.4.0-docs.tar:: Put everything in the current head's Documentation/ directory into 'git-1.4.0-docs.tar', with the prefix 'git-docs/'. -Author ------- -Written by Rene Scharfe. - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-unpack-file.txt b/Documentation/git-unpack-file.txt index 995db9fead..c49d727f74 100644 --- a/Documentation/git-unpack-file.txt +++ b/Documentation/git-unpack-file.txt @@ -22,14 +22,6 @@ OPTIONS <blob>:: Must be a blob id -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-unpack-objects.txt b/Documentation/git-unpack-objects.txt index 36d1038056..dd7799095b 100644 --- a/Documentation/git-unpack-objects.txt +++ b/Documentation/git-unpack-objects.txt @@ -43,15 +43,6 @@ OPTIONS --strict:: Don't write objects with broken content or links. - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation -------------- -Documentation by Junio C Hamano - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt index 1ca56c85aa..d3931294d1 100644 --- a/Documentation/git-update-index.txt +++ b/Documentation/git-update-index.txt @@ -365,15 +365,6 @@ SEE ALSO linkgit:git-config[1], linkgit:git-add[1] - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.txt index 9639f705af..e25a65a80f 100644 --- a/Documentation/git-update-ref.txt +++ b/Documentation/git-update-ref.txt @@ -84,10 +84,6 @@ An update will fail (without changing <ref>) if the current user is unable to create a new log file, append to the existing log file or does not have committer information available. -Author ------- -Written by Linus Torvalds <torvalds@osdl.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-update-server-info.txt b/Documentation/git-update-server-info.txt index 035cc3018f..775024da3e 100644 --- a/Documentation/git-update-server-info.txt +++ b/Documentation/git-update-server-info.txt @@ -38,15 +38,6 @@ what they are for: * info/refs - -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - -Documentation --------------- -Documentation by Junio C Hamano. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-upload-archive.txt b/Documentation/git-upload-archive.txt index f5f2b3908b..acbf634f85 100644 --- a/Documentation/git-upload-archive.txt +++ b/Documentation/git-upload-archive.txt @@ -24,14 +24,6 @@ OPTIONS <directory>:: The repository to get a tar archive from. -Author ------- -Written by Franck Bui-Huu. - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-upload-pack.txt b/Documentation/git-upload-pack.txt index 71ca4ef442..4c0ca9ded2 100644 --- a/Documentation/git-upload-pack.txt +++ b/Documentation/git-upload-pack.txt @@ -33,14 +33,6 @@ OPTIONS <directory>:: The repository to sync from. -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by Junio C Hamano. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-var.txt b/Documentation/git-var.txt index 458f3e2755..6498f7cb69 100644 --- a/Documentation/git-var.txt +++ b/Documentation/git-var.txt @@ -65,14 +65,6 @@ linkgit:git-commit-tree[1] linkgit:git-tag[1] linkgit:git-config[1] -Author ------- -Written by Eric Biederman <ebiederm@xmission.com> - -Documentation --------------- -Documentation by Eric Biederman and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-verify-pack.txt b/Documentation/git-verify-pack.txt index 0f848de8b2..7c2428d569 100644 --- a/Documentation/git-verify-pack.txt +++ b/Documentation/git-verify-pack.txt @@ -47,14 +47,6 @@ for objects that are not deltified in the pack, and for objects that are deltified. -Author ------- -Written by Junio C Hamano <gitster@pobox.com> - -Documentation --------------- -Documentation by Junio C Hamano - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-verify-tag.txt b/Documentation/git-verify-tag.txt index 711219749c..8c9a71865b 100644 --- a/Documentation/git-verify-tag.txt +++ b/Documentation/git-verify-tag.txt @@ -22,14 +22,6 @@ OPTIONS <tag>...:: SHA1 identifiers of git tag objects. -Author ------- -Written by Jan Harkes <jaharkes@cs.cmu.edu> and Eric W. Biederman <ebiederm@xmission.com> - -Documentation --------------- -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-web--browse.txt b/Documentation/git-web--browse.txt index c0416e5e1a..69d92fa00e 100644 --- a/Documentation/git-web--browse.txt +++ b/Documentation/git-web--browse.txt @@ -116,16 +116,6 @@ $ git config --global web.browser firefox as they are probably more user specific than repository specific. See linkgit:git-config[1] for more information about this. -Author ------- -Written by Christian Couder <chriscool@tuxfamily.org> and the git-list -<git@vger.kernel.org>, based on 'git mergetool' by Theodore Y. Ts'o. - -Documentation -------------- -Documentation by Christian Couder <chriscool@tuxfamily.org> and the -git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-whatchanged.txt b/Documentation/git-whatchanged.txt index ea753cdafc..31f3663ae7 100644 --- a/Documentation/git-whatchanged.txt +++ b/Documentation/git-whatchanged.txt @@ -63,17 +63,6 @@ git whatchanged --since="2 weeks ago" \-- gitk:: The "--" is necessary to avoid confusion with the *branch* named 'gitk' - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> and -Junio C Hamano <gitster@pobox.com> - - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-write-tree.txt b/Documentation/git-write-tree.txt index bfceacacb3..e8c94c1352 100644 --- a/Documentation/git-write-tree.txt +++ b/Documentation/git-write-tree.txt @@ -36,15 +36,6 @@ OPTIONS `<prefix>`. This can be used to write the tree object for a subproject that is in the named subdirectory. - -Author ------- -Written by Linus Torvalds <torvalds@osdl.org> - -Documentation --------------- -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git.txt b/Documentation/git.txt index 0c32d45248..5e57f6995a 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -745,16 +745,12 @@ unmerged version of a file when a merge is in progress. Authors ------- -* git's founding father is Linus Torvalds <torvalds@osdl.org>. -* The current git nurse is Junio C Hamano <gitster@pobox.com>. -* The git potty was written by Andreas Ericsson <ae@op5.se>. -* General upbringing is handled by the git-list <git@vger.kernel.org>. - -Documentation --------------- -The documentation for git suite was started by David Greaves -<david@dgreaves.com>, and later enhanced greatly by the -contributors on the git-list <git@vger.kernel.org>. +Git was started by Linus Torvalds, and is currently maintained by Junio +C Hamano. Numerous contributions have come from the git mailing list +<git@vger.kernel.org>. For a more complete list of contributors, see +http://git-scm.com/about. If you have a clone of git.git itself, the +output of linkgit:git-shortlog[1] and linkgit:git-blame[1] can show you +the authors for specific parts of the project. Reporting Bugs -------------- diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt index 6928724a05..f734f97b8e 100644 --- a/Documentation/gitcli.txt +++ b/Documentation/gitcli.txt @@ -169,10 +169,6 @@ See also http://marc.info/?l=git&m=116563135620359 and http://marc.info/?l=git&m=119150393620273 for further information. -Documentation -------------- -Documentation by Pierre Habouzit and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt index 8416f3445a..2e7328b830 100644 --- a/Documentation/gitignore.txt +++ b/Documentation/gitignore.txt @@ -156,11 +156,6 @@ SEE ALSO linkgit:git-rm[1], linkgit:git-update-index[1], linkgit:gitrepository-layout[5] -Documentation -------------- -Documentation by David Greaves, Junio C Hamano, Josh Triplett, -Frank Lichtenheld, and the git-list <git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/gitk.txt b/Documentation/gitk.txt index e21bac4f3f..e10ac58cae 100644 --- a/Documentation/gitk.txt +++ b/Documentation/gitk.txt @@ -113,15 +113,6 @@ SEE ALSO A minimal repository browser and git tool output highlighter written in C using Ncurses. -Author ------- -Written by Paul Mackerras <paulus@samba.org>. - -Documentation --------------- -Documentation by Junio C Hamano, Jonas Fonseca, and the git-list -<git@vger.kernel.org>. - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt index 68977943e7..15a2186559 100644 --- a/Documentation/gitmodules.txt +++ b/Documentation/gitmodules.txt @@ -90,10 +90,6 @@ SEE ALSO -------- linkgit:git-submodule[1] linkgit:git-config[1] -DOCUMENTATION -------------- -Documentation by Lars Hjemli <hjemli@gmail.com> - GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt index f04b48ef0d..33716a31d0 100644 --- a/Documentation/glossary-content.txt +++ b/Documentation/glossary-content.txt @@ -273,6 +273,29 @@ This commit is referred to as a "merge commit", or sometimes just a <<def_pack,pack>>, to assist in efficiently accessing the contents of a pack. +[[def_pathspec]]pathspec:: + Pattern used to specify paths. ++ +Pathspecs are used on the command line of "git ls-files", "git +ls-tree", "git grep", "git checkout", and many other commands to +limit the scope of operations to some subset of the tree or +worktree. See the documentation of each command for whether +paths are relative to the current directory or toplevel. The +pathspec syntax is as follows: + +* any path matches itself +* the pathspec up to the last slash represents a + directory prefix. The scope of that pathspec is + limited to that subtree. +* the rest of the pathspec is a pattern for the remainder + of the pathname. Paths relative to the directory + prefix will be matched against that pattern using fnmatch(3); + in particular, '*' and '?' _can_ match directory separators. ++ +For example, Documentation/*.jpg will match all .jpg files +in the Documentation subtree, +including Documentation/chapter_1/figure_1.jpg. + [[def_parent]]parent:: A <<def_commit_object,commit object>> contains a (possibly empty) list of the logical predecessor(s) in the line of development, i.e. its diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 1e5c22c5e5..33bf74c334 100644 --- a/Documentation/merge-config.txt +++ b/Documentation/merge-config.txt @@ -33,10 +33,10 @@ merge.stat:: merge.tool:: Controls which merge resolution program is used by - linkgit:git-mergetool[1]. Valid built-in values are: "kdiff3", - "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", - "diffuse", "ecmerge", "tortoisemerge", "p4merge", "araxis" and - "opendiff". Any other value is treated is custom merge tool + linkgit:git-mergetool[1]. Valid built-in values are: "araxis", + "bc3", "diffuse", "ecmerge", "emerge", "gvimdiff", "kdiff3", "meld", + "opendiff", "p4merge", "tkdiff", "tortoisemerge", "vimdiff" + and "xxdiff". Any other value is treated is custom merge tool and there must be a corresponding mergetool.<tool>.cmd option. merge.verbosity:: diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt index e33e0f8e11..b613d4ed08 100644 --- a/Documentation/merge-options.txt +++ b/Documentation/merge-options.txt @@ -75,9 +75,17 @@ option can be used to override --squash. ifndef::git-pull[] -q:: --quiet:: - Operate quietly. + Operate quietly. Implies --no-progress. -v:: --verbose:: Be verbose. + +--progress:: +--no-progress:: + Turn progress on/off explicitly. If neither is specified, + progress is shown if standard error is connected to a terminal. + Note that not all merge strategies may support progress + reporting. + endif::git-pull[] diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index 9c47ad885b..09860de9c2 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -1,164 +1,10 @@ -Commit Formatting -~~~~~~~~~~~~~~~~~ - -ifdef::git-rev-list[] -Using these options, linkgit:git-rev-list[1] will act similar to the -more specialized family of commit log tools: linkgit:git-log[1], -linkgit:git-show[1], and linkgit:git-whatchanged[1] -endif::git-rev-list[] - -include::pretty-options.txt[] - ---relative-date:: - - Synonym for `--date=relative`. - ---date=(relative|local|default|iso|rfc|short|raw):: - - Only takes effect for dates shown in human-readable format, such - as when using "--pretty". `log.date` config variable sets a default - value for log command's --date option. -+ -`--date=relative` shows dates relative to the current time, -e.g. "2 hours ago". -+ -`--date=local` shows timestamps in user's local timezone. -+ -`--date=iso` (or `--date=iso8601`) shows timestamps in ISO 8601 format. -+ -`--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822 -format, often found in E-mail messages. -+ -`--date=short` shows only date but not time, in `YYYY-MM-DD` format. -+ -`--date=raw` shows the date in the internal raw git format `%s %z` format. -+ -`--date=default` shows timestamps in the original timezone -(either committer's or author's). - -ifdef::git-rev-list[] ---header:: - - Print the contents of the commit in raw-format; each record is - separated with a NUL character. -endif::git-rev-list[] - ---parents:: - - Print also the parents of the commit (in the form "commit parent..."). - Also enables parent rewriting, see 'History Simplification' below. - ---children:: - - Print also the children of the commit (in the form "commit child..."). - Also enables parent rewriting, see 'History Simplification' below. - -ifdef::git-rev-list[] ---timestamp:: - Print the raw commit timestamp. -endif::git-rev-list[] - ---left-right:: - - Mark which side of a symmetric diff a commit is reachable from. - Commits from the left side are prefixed with `<` and those from - the right with `>`. If combined with `--boundary`, those - commits are prefixed with `-`. -+ -For example, if you have this topology: -+ ------------------------------------------------------------------------ - y---b---b branch B - / \ / - / . - / / \ - o---x---a---a branch A ------------------------------------------------------------------------ -+ -you would get an output like this: -+ ------------------------------------------------------------------------ - $ git rev-list --left-right --boundary --pretty=oneline A...B - - >bbbbbbb... 3rd on b - >bbbbbbb... 2nd on b - <aaaaaaa... 3rd on a - <aaaaaaa... 2nd on a - -yyyyyyy... 1st on b - -xxxxxxx... 1st on a ------------------------------------------------------------------------ - ---graph:: - - Draw a text-based graphical representation of the commit history - on the left hand side of the output. This may cause extra lines - to be printed in between commits, in order for the graph history - to be drawn properly. -+ -This enables parent rewriting, see 'History Simplification' below. -+ -This implies the '--topo-order' option by default, but the -'--date-order' option may also be specified. - -ifdef::git-rev-list[] ---count:: - Print a number stating how many commits would have been - listed, and suppress all other output. When used together - with '--left-right', instead print the counts for left and - right commits, separated by a tab. -endif::git-rev-list[] - - -ifndef::git-rev-list[] -Diff Formatting -~~~~~~~~~~~~~~~ - -Below are listed options that control the formatting of diff output. -Some of them are specific to linkgit:git-rev-list[1], however other diff -options may be given. See linkgit:git-diff-files[1] for more options. - --c:: - - With this option, diff output for a merge commit - shows the differences from each of the parents to the merge result - simultaneously instead of showing pairwise diff between a parent - and the result one at a time. Furthermore, it lists only files - which were modified from all parents. - ---cc:: - - This flag implies the '-c' options and further compresses the - patch output by omitting uninteresting hunks whose contents in - the parents have only two variants and the merge result picks - one of them without modification. - --m:: - - This flag makes the merge commits show the full diff like - regular commits; for each merge parent, a separate log entry - and diff is generated. An exception is that only diff against - the first parent is shown when '--first-parent' option is given; - in that case, the output represents the changes the merge - brought _into_ the then-current branch. - --r:: - - Show recursive diffs. - --t:: - - Show the tree objects in the diff output. This implies '-r'. - --s:: - Suppress diff output. -endif::git-rev-list[] - Commit Limiting ~~~~~~~~~~~~~~~ Besides specifying a range of commits that should be listed using the special notations explained in the description, additional commit -limiting may be applied. +limiting may be applied. Note that they are applied before commit +ordering and formatting options, such as '--reverse'. -- @@ -735,3 +581,158 @@ These options are mostly targeted for packing of git repositories. --do-walk:: Overrides a previous --no-walk. + +Commit Formatting +~~~~~~~~~~~~~~~~~ + +ifdef::git-rev-list[] +Using these options, linkgit:git-rev-list[1] will act similar to the +more specialized family of commit log tools: linkgit:git-log[1], +linkgit:git-show[1], and linkgit:git-whatchanged[1] +endif::git-rev-list[] + +include::pretty-options.txt[] + +--relative-date:: + + Synonym for `--date=relative`. + +--date=(relative|local|default|iso|rfc|short|raw):: + + Only takes effect for dates shown in human-readable format, such + as when using "--pretty". `log.date` config variable sets a default + value for log command's --date option. ++ +`--date=relative` shows dates relative to the current time, +e.g. "2 hours ago". ++ +`--date=local` shows timestamps in user's local timezone. ++ +`--date=iso` (or `--date=iso8601`) shows timestamps in ISO 8601 format. ++ +`--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822 +format, often found in E-mail messages. ++ +`--date=short` shows only date but not time, in `YYYY-MM-DD` format. ++ +`--date=raw` shows the date in the internal raw git format `%s %z` format. ++ +`--date=default` shows timestamps in the original timezone +(either committer's or author's). + +ifdef::git-rev-list[] +--header:: + + Print the contents of the commit in raw-format; each record is + separated with a NUL character. +endif::git-rev-list[] + +--parents:: + + Print also the parents of the commit (in the form "commit parent..."). + Also enables parent rewriting, see 'History Simplification' below. + +--children:: + + Print also the children of the commit (in the form "commit child..."). + Also enables parent rewriting, see 'History Simplification' below. + +ifdef::git-rev-list[] +--timestamp:: + Print the raw commit timestamp. +endif::git-rev-list[] + +--left-right:: + + Mark which side of a symmetric diff a commit is reachable from. + Commits from the left side are prefixed with `<` and those from + the right with `>`. If combined with `--boundary`, those + commits are prefixed with `-`. ++ +For example, if you have this topology: ++ +----------------------------------------------------------------------- + y---b---b branch B + / \ / + / . + / / \ + o---x---a---a branch A +----------------------------------------------------------------------- ++ +you would get an output like this: ++ +----------------------------------------------------------------------- + $ git rev-list --left-right --boundary --pretty=oneline A...B + + >bbbbbbb... 3rd on b + >bbbbbbb... 2nd on b + <aaaaaaa... 3rd on a + <aaaaaaa... 2nd on a + -yyyyyyy... 1st on b + -xxxxxxx... 1st on a +----------------------------------------------------------------------- + +--graph:: + + Draw a text-based graphical representation of the commit history + on the left hand side of the output. This may cause extra lines + to be printed in between commits, in order for the graph history + to be drawn properly. ++ +This enables parent rewriting, see 'History Simplification' below. ++ +This implies the '--topo-order' option by default, but the +'--date-order' option may also be specified. + +ifdef::git-rev-list[] +--count:: + Print a number stating how many commits would have been + listed, and suppress all other output. When used together + with '--left-right', instead print the counts for left and + right commits, separated by a tab. +endif::git-rev-list[] + + +ifndef::git-rev-list[] +Diff Formatting +~~~~~~~~~~~~~~~ + +Below are listed options that control the formatting of diff output. +Some of them are specific to linkgit:git-rev-list[1], however other diff +options may be given. See linkgit:git-diff-files[1] for more options. + +-c:: + + With this option, diff output for a merge commit + shows the differences from each of the parents to the merge result + simultaneously instead of showing pairwise diff between a parent + and the result one at a time. Furthermore, it lists only files + which were modified from all parents. + +--cc:: + + This flag implies the '-c' options and further compresses the + patch output by omitting uninteresting hunks whose contents in + the parents have only two variants and the merge result picks + one of them without modification. + +-m:: + + This flag makes the merge commits show the full diff like + regular commits; for each merge parent, a separate log entry + and diff is generated. An exception is that only diff against + the first parent is shown when '--first-parent' option is given; + in that case, the output represents the changes the merge + brought _into_ the then-current branch. + +-r:: + + Show recursive diffs. + +-t:: + + Show the tree objects in the diff output. This implies '-r'. + +-s:: + Suppress diff output. +endif::git-rev-list[] diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt index 9e92734bc1..04fceee253 100644 --- a/Documentation/revisions.txt +++ b/Documentation/revisions.txt @@ -25,7 +25,8 @@ blobs contained in a commit. first match in the following rules: . if `$GIT_DIR/<name>` exists, that is what you mean (this is usually - useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD` and `MERGE_HEAD`); + useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD`, `MERGE_HEAD` + and `CHERRY_PICK_HEAD`); . otherwise, `refs/<name>` if exists; @@ -46,6 +47,8 @@ you can change the tip of the branch back to the state before you ran them easily. MERGE_HEAD records the commit(s) you are merging into your branch when you run 'git merge'. +CHERRY_PICK_HEAD records the commit you are cherry-picking +when you run 'git cherry-pick'. + Note that any of the `refs/*` cases above may come either from the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file. diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index d03e624a37..92fe7a59db 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.7.4.1 +DEF_VER=v1.7.4 LF=' ' @@ -216,6 +216,11 @@ all:: # # Define NO_REGEX if you have no or inferior regex support in your C library. # +# Define GETTEXT_POISON if you are debugging the choice of strings marked +# for translation. In a GETTEXT_POISON build, you can turn all strings marked +# for translation into gibberish by setting the GIT_GETTEXT_POISON variable +# (to any value) in your environment. +# # Define JSMIN to point to JavaScript minifier that functions as # a filter to have gitweb.js minified. # @@ -316,6 +321,7 @@ INSTALL = install RPMBUILD = rpmbuild TCL_PATH = tclsh TCLTK_PATH = wish +XGETTEXT = xgettext PTHREAD_LIBS = -lpthread PTHREAD_CFLAGS = GCOV = gcov @@ -515,6 +521,7 @@ LIB_H += diff.h LIB_H += dir.h LIB_H += exec_cmd.h LIB_H += fsck.h +LIB_H += gettext.h LIB_H += git-compat-util.h LIB_H += graph.h LIB_H += grep.h @@ -1370,6 +1377,10 @@ endif ifdef NO_SYMLINK_HEAD BASIC_CFLAGS += -DNO_SYMLINK_HEAD endif +ifdef GETTEXT_POISON + LIB_OBJS += gettext.o + BASIC_CFLAGS += -DGETTEXT_POISON +endif ifdef NO_STRCASESTR COMPAT_CFLAGS += -DNO_STRCASESTR COMPAT_OBJS += compat/strcasestr.o @@ -1581,6 +1592,7 @@ ifndef V QUIET_BUILT_IN = @echo ' ' BUILTIN $@; QUIET_GEN = @echo ' ' GEN $@; QUIET_LNCP = @echo ' ' LN/CP $@; + QUIET_XGETTEXT = @echo ' ' XGETTEXT $@; QUIET_GCOV = @echo ' ' GCOV $@; QUIET_SUBDIR0 = +@subdir= QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ @@ -2048,6 +2060,20 @@ info: pdf: $(MAKE) -C Documentation pdf +XGETTEXT_FLAGS = \ + --force-po \ + --add-comments \ + --msgid-bugs-address="Git Mailing List <git@vger.kernel.org>" \ + --from-code=UTF-8 +XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --keyword=_ --keyword=N_ --language=C +LOCALIZED_C := $(C_OBJ:o=c) + +po/git.pot: $(LOCALIZED_C) + $(QUIET_XGETTEXT)$(XGETTEXT) -o$@+ $(XGETTEXT_FLAGS_C) $(LOCALIZED_C) && \ + mv $@+ $@ + +pot: po/git.pot + $(ETAGS_TARGET): FORCE $(RM) $(ETAGS_TARGET) $(FIND) . -name '*.[hcS]' -print | xargs etags -a -o $(ETAGS_TARGET) @@ -2089,6 +2115,7 @@ endif ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT @echo GIT_TEST_CMP_USE_COPIED_CONTEXT=YesPlease >>$@ endif + @echo GETTEXT_POISON=\''$(subst ','\'',$(subst ','\'',$(GETTEXT_POISON)))'\' >>$@ ### Detect Tck/Tk interpreter path changes ifndef NO_TCLTK @@ -2314,6 +2341,7 @@ dist-doc: distclean: clean $(RM) configure + $(RM) po/git.pot clean: $(RM) *.o block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o vcs-svn/*.o \ @@ -1 +1 @@ -Documentation/RelNotes/1.7.4.2.txt
\ No newline at end of file +Documentation/RelNotes/1.7.5.txt
\ No newline at end of file @@ -14,7 +14,14 @@ int is_directory(const char *path) /* We allow "recursive" symbolic links. Only within reason, though. */ #define MAXDEPTH 5 -const char *make_absolute_path(const char *path) +/* + * Use this to get the real path, i.e. resolve links. If you want an + * absolute path but don't mind links, use absolute_path. + * + * If path is our buffer, then return path, as it's already what the + * user wants. + */ +const char *real_path(const char *path) { static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1]; char cwd[1024] = ""; @@ -104,7 +111,14 @@ static const char *get_pwd_cwd(void) return cwd; } -const char *make_nonrelative_path(const char *path) +/* + * Use this to get an absolute path from a relative one. If you want + * to resolve links, you should use real_path. + * + * If the path is already absolute, then return path. As the user is + * never meant to free the return value, we're safe. + */ +const char *absolute_path(const char *path) { static char buf[PATH_MAX + 1]; @@ -175,9 +175,14 @@ void create_branch(const char *head, die("Cannot setup tracking information; starting point is not a branch."); break; case 1: - /* Unique completion -- good, only if it is a real ref */ - if (explicit_tracking && !strcmp(real_ref, "HEAD")) - die("Cannot setup tracking information; starting point is not a branch."); + /* Unique completion -- good, only if it is a real branch */ + if (prefixcmp(real_ref, "refs/heads/") && + prefixcmp(real_ref, "refs/remotes/")) { + if (explicit_tracking) + die("Cannot setup tracking information; starting point is not a branch."); + else + real_ref = NULL; + } break; default: die("Ambiguous object name: '%s'.", start_name); @@ -217,6 +222,7 @@ void create_branch(const char *head, void remove_branch_state(void) { + unlink(git_path("CHERRY_PICK_HEAD")); unlink(git_path("MERGE_HEAD")); unlink(git_path("MERGE_RR")); unlink(git_path("MERGE_MSG")); @@ -57,6 +57,7 @@ extern int cmd_clone(int argc, const char **argv, const char *prefix); extern int cmd_clean(int argc, const char **argv, const char *prefix); extern int cmd_commit(int argc, const char **argv, const char *prefix); extern int cmd_commit_tree(int argc, const char **argv, const char *prefix); +extern int cmd_config(int argc, const char **argv, const char *prefix); extern int cmd_count_objects(int argc, const char **argv, const char *prefix); extern int cmd_describe(int argc, const char **argv, const char *prefix); extern int cmd_diff_files(int argc, const char **argv, const char *prefix); @@ -110,7 +111,7 @@ extern int cmd_reflog(int argc, const char **argv, const char *prefix); extern int cmd_remote(int argc, const char **argv, const char *prefix); extern int cmd_remote_ext(int argc, const char **argv, const char *prefix); extern int cmd_remote_fd(int argc, const char **argv, const char *prefix); -extern int cmd_config(int argc, const char **argv, const char *prefix); +extern int cmd_repo_config(int argc, const char **argv, const char *prefix); extern int cmd_rerere(int argc, const char **argv, const char *prefix); extern int cmd_reset(int argc, const char **argv, const char *prefix); extern int cmd_rev_list(int argc, const char **argv, const char *prefix); diff --git a/builtin/add.c b/builtin/add.c index 1d74763f58..e127d5a68b 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -85,7 +85,7 @@ int add_files_to_cache(const char *prefix, const char **pathspec, int flags) struct rev_info rev; init_revisions(&rev, prefix); setup_revisions(0, NULL, &rev, NULL); - rev.prune_data = pathspec; + init_pathspec(&rev.prune_data, pathspec); rev.diffopt.output_format = DIFF_FORMAT_CALLBACK; rev.diffopt.format_callback = update_callback; data.flags = flags; @@ -321,7 +321,7 @@ static struct option builtin_add_options[] = { OPT__FORCE(&ignored_too, "allow adding otherwise ignored files"), OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"), OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"), - OPT_BOOLEAN('A', "all", &addremove, "add all, noticing removal of tracked files"), + OPT_BOOLEAN('A', "all", &addremove, "add changes from all tracked and untracked files"), OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"), OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, "just skip files which cannot be added because of errors"), OPT_BOOLEAN( 0 , "ignore-missing", &ignore_missing, "check if - even missing - files are ignored in dry run"), diff --git a/builtin/apply.c b/builtin/apply.c index 14951daedf..36e150768b 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -204,6 +204,7 @@ struct line { unsigned hash : 24; unsigned flag : 8; #define LINE_COMMON 1 +#define LINE_PATCHED 2 }; /* @@ -2085,7 +2086,8 @@ static int match_fragment(struct image *img, /* Quick hash check */ for (i = 0; i < preimage_limit; i++) - if (preimage->line[i].hash != img->line[try_lno + i].hash) + if ((img->line[try_lno + i].flag & LINE_PATCHED) || + (preimage->line[i].hash != img->line[try_lno + i].hash)) return 0; if (preimage_limit == preimage->nr) { @@ -2428,11 +2430,15 @@ static void update_image(struct image *img, memcpy(img->line + applied_pos, postimage->line, postimage->nr * sizeof(*img->line)); + for (i = 0; i < postimage->nr; i++) + img->line[applied_pos + i].flag |= LINE_PATCHED; + img->nr = nr; } static int apply_one_fragment(struct image *img, struct fragment *frag, - int inaccurate_eof, unsigned ws_rule) + int inaccurate_eof, unsigned ws_rule, + int nth_fragment) { int match_beginning, match_end; const char *patch = frag->patch; @@ -2638,6 +2644,15 @@ static int apply_one_fragment(struct image *img, struct fragment *frag, apply = 0; } + if (apply_verbosely && applied_pos != pos) { + int offset = applied_pos - pos; + if (apply_in_reverse) + offset = 0 - offset; + fprintf(stderr, + "Hunk #%d succeeded at %d (offset %d lines).\n", + nth_fragment, applied_pos + 1, offset); + } + /* * Warn if it was necessary to reduce the number * of context lines. @@ -2785,12 +2800,14 @@ static int apply_fragments(struct image *img, struct patch *patch) const char *name = patch->old_name ? patch->old_name : patch->new_name; unsigned ws_rule = patch->ws_rule; unsigned inaccurate_eof = patch->inaccurate_eof; + int nth = 0; if (patch->is_binary) return apply_binary(img, patch); while (frag) { - if (apply_one_fragment(img, frag, inaccurate_eof, ws_rule)) { + nth++; + if (apply_one_fragment(img, frag, inaccurate_eof, ws_rule, nth)) { error("patch failed: %s:%ld", name, frag->oldpos); if (!apply_with_reject) return -1; diff --git a/builtin/checkout.c b/builtin/checkout.c index cd7f56e6c4..2bf02f2841 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -30,6 +30,7 @@ struct checkout_opts { int quiet; int merge; int force; + int force_detach; int writeout_stage; int writeout_error; @@ -297,7 +298,7 @@ static void show_local_changes(struct object *head, struct diff_options *opts) run_diff_index(&rev, 0); } -static void describe_detached_head(char *msg, struct commit *commit) +static void describe_detached_head(const char *msg, struct commit *commit) { struct strbuf sb = STRBUF_INIT; struct pretty_print_context ctx = {0}; @@ -541,7 +542,17 @@ static void update_refs_for_switch(struct checkout_opts *opts, strbuf_addf(&msg, "checkout: moving from %s to %s", old_desc ? old_desc : "(invalid)", new->name); - if (new->path) { + if (!strcmp(new->name, "HEAD") && !new->path && !opts->force_detach) { + /* Nothing to do. */ + } else if (opts->force_detach || !new->path) { /* No longer on any branch. */ + update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL, + REF_NODEREF, DIE_ON_ERR); + if (!opts->quiet) { + if (old->path && advice_detached_head) + detach_advice(old->path, new->name); + describe_detached_head("HEAD is now at", new->commit); + } + } else if (new->path) { /* Switch branches. */ create_symref("HEAD", new->path, msg.buf); if (!opts->quiet) { if (old->path && !strcmp(new->path, old->path)) @@ -563,21 +574,108 @@ static void update_refs_for_switch(struct checkout_opts *opts, if (!file_exists(ref_file) && file_exists(log_file)) remove_path(log_file); } - } else if (strcmp(new->name, "HEAD")) { - update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL, - REF_NODEREF, DIE_ON_ERR); - if (!opts->quiet) { - if (old->path && advice_detached_head) - detach_advice(old->path, new->name); - describe_detached_head("HEAD is now at", new->commit); - } } remove_branch_state(); strbuf_release(&msg); - if (!opts->quiet && (new->path || !strcmp(new->name, "HEAD"))) + if (!opts->quiet && + (new->path || (!opts->force_detach && !strcmp(new->name, "HEAD")))) report_tracking(new); } +struct rev_list_args { + int argc; + int alloc; + const char **argv; +}; + +static void add_one_rev_list_arg(struct rev_list_args *args, const char *s) +{ + ALLOC_GROW(args->argv, args->argc + 1, args->alloc); + args->argv[args->argc++] = s; +} + +static int add_one_ref_to_rev_list_arg(const char *refname, + const unsigned char *sha1, + int flags, + void *cb_data) +{ + add_one_rev_list_arg(cb_data, refname); + return 0; +} + + +static void describe_one_orphan(struct strbuf *sb, struct commit *commit) +{ + struct pretty_print_context ctx = { 0 }; + + parse_commit(commit); + strbuf_addstr(sb, " - "); + pretty_print_commit(CMIT_FMT_ONELINE, commit, sb, &ctx); + strbuf_addch(sb, '\n'); +} + +#define ORPHAN_CUTOFF 4 +static void suggest_reattach(struct commit *commit, struct rev_info *revs) +{ + struct commit *c, *last = NULL; + struct strbuf sb = STRBUF_INIT; + int lost = 0; + while ((c = get_revision(revs)) != NULL) { + if (lost < ORPHAN_CUTOFF) + describe_one_orphan(&sb, c); + last = c; + lost++; + } + if (ORPHAN_CUTOFF < lost) { + int more = lost - ORPHAN_CUTOFF; + if (more == 1) + describe_one_orphan(&sb, last); + else + strbuf_addf(&sb, " ... and %d more.\n", more); + } + + fprintf(stderr, + "Warning: you are leaving %d commit%s behind, " + "not connected to\n" + "any of your branches:\n\n" + "%s\n" + "If you want to keep them by creating a new branch, " + "this may be a good time\nto do so with:\n\n" + " git branch new_branch_name %s\n\n", + lost, ((1 < lost) ? "s" : ""), + sb.buf, + sha1_to_hex(commit->object.sha1)); + strbuf_release(&sb); +} + +/* + * We are about to leave commit that was at the tip of a detached + * HEAD. If it is not reachable from any ref, this is the last chance + * for the user to do so without resorting to reflog. + */ +static void orphaned_commit_warning(struct commit *commit) +{ + struct rev_list_args args = { 0, 0, NULL }; + struct rev_info revs; + + add_one_rev_list_arg(&args, "(internal)"); + add_one_rev_list_arg(&args, sha1_to_hex(commit->object.sha1)); + add_one_rev_list_arg(&args, "--not"); + for_each_ref(add_one_ref_to_rev_list_arg, &args); + add_one_rev_list_arg(&args, "--"); + add_one_rev_list_arg(&args, NULL); + + init_revisions(&revs, NULL); + if (setup_revisions(args.argc - 1, args.argv, &revs, NULL) != 1) + die("internal error: only -- alone should have been left"); + if (prepare_revision_walk(&revs)) + die("internal error in revision walk"); + if (!(commit->object.flags & UNINTERESTING)) + suggest_reattach(commit, &revs); + else + describe_detached_head("Previous HEAD position was", commit); +} + static int switch_branches(struct checkout_opts *opts, struct branch_info *new) { int ret = 0; @@ -605,13 +703,8 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new) if (ret) return ret; - /* - * If we were on a detached HEAD, but have now moved to - * a new commit, we want to mention the old commit once more - * to remind the user that it might be lost. - */ if (!opts->quiet && !old.path && old.commit && new->commit != old.commit) - describe_detached_head("Previous HEAD position was", old.commit); + orphaned_commit_warning(old.commit); update_refs_for_switch(opts, &old, new); @@ -675,11 +768,123 @@ static const char *unique_tracking_name(const char *name) return NULL; } +static int parse_branchname_arg(int argc, const char **argv, + int dwim_new_local_branch_ok, + struct branch_info *new, + struct tree **source_tree, + unsigned char rev[20], + const char **new_branch) +{ + int argcount = 0; + unsigned char branch_rev[20]; + const char *arg; + int has_dash_dash; + + /* + * case 1: git checkout <ref> -- [<paths>] + * + * <ref> must be a valid tree, everything after the '--' must be + * a path. + * + * case 2: git checkout -- [<paths>] + * + * everything after the '--' must be paths. + * + * case 3: git checkout <something> [<paths>] + * + * With no paths, if <something> is a commit, that is to + * switch to the branch or detach HEAD at it. As a special case, + * if <something> is A...B (missing A or B means HEAD but you can + * omit at most one side), and if there is a unique merge base + * between A and B, A...B names that merge base. + * + * With no paths, if <something> is _not_ a commit, no -t nor -b + * was given, and there is a tracking branch whose name is + * <something> in one and only one remote, then this is a short-hand + * to fork local <something> from that remote-tracking branch. + * + * Otherwise <something> shall not be ambiguous. + * - If it's *only* a reference, treat it like case (1). + * - If it's only a path, treat it like case (2). + * - else: fail. + * + */ + if (!argc) + return 0; + + if (!strcmp(argv[0], "--")) /* case (2) */ + return 1; + + arg = argv[0]; + has_dash_dash = (argc > 1) && !strcmp(argv[1], "--"); + + if (!strcmp(arg, "-")) + arg = "@{-1}"; + + if (get_sha1_mb(arg, rev)) { + if (has_dash_dash) /* case (1) */ + die("invalid reference: %s", arg); + if (dwim_new_local_branch_ok && + !check_filename(NULL, arg) && + argc == 1) { + const char *remote = unique_tracking_name(arg); + if (!remote || get_sha1(remote, rev)) + return argcount; + *new_branch = arg; + arg = remote; + /* DWIMmed to create local branch */ + } else { + return argcount; + } + } + + /* we can't end up being in (2) anymore, eat the argument */ + argcount++; + argv++; + argc--; + + new->name = arg; + setup_branch_path(new); + + if (check_ref_format(new->path) == CHECK_REF_FORMAT_OK && + resolve_ref(new->path, branch_rev, 1, NULL)) + hashcpy(rev, branch_rev); + else + new->path = NULL; /* not an existing branch */ + + new->commit = lookup_commit_reference_gently(rev, 1); + if (!new->commit) { + /* not a commit */ + *source_tree = parse_tree_indirect(rev); + } else { + parse_commit(new->commit); + *source_tree = new->commit->tree; + } + + if (!*source_tree) /* case (1): want a tree */ + die("reference is not a tree: %s", arg); + if (!has_dash_dash) {/* case (3 -> 1) */ + /* + * Do not complain the most common case + * git checkout branch + * even if there happen to be a file called 'branch'; + * it would be extremely annoying. + */ + if (argc) + verify_non_filename(NULL, arg); + } else { + argcount++; + argv++; + argc--; + } + + return argcount; +} + int cmd_checkout(int argc, const char **argv, const char *prefix) { struct checkout_opts opts; unsigned char rev[20]; - const char *arg; struct branch_info new; struct tree *source_tree = NULL; char *conflict_style = NULL; @@ -692,6 +897,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) OPT_STRING('B', NULL, &opts.new_branch_force, "branch", "create/reset and checkout a branch"), OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "create reflog for new branch"), + OPT_BOOLEAN(0, "detach", &opts.force_detach, "detach the HEAD at named commit"), OPT_SET_INT('t', "track", &opts.track, "set upstream info for new branch", BRANCH_TRACK_EXPLICIT), OPT_STRING(0, "orphan", &opts.new_orphan_branch, "new branch", "new unparented branch"), @@ -709,7 +915,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) PARSE_OPT_NOARG | PARSE_OPT_HIDDEN }, OPT_END(), }; - int has_dash_dash; memset(&opts, 0, sizeof(opts)); memset(&new, 0, sizeof(new)); @@ -731,9 +936,15 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) opts.new_branch = opts.new_branch_force; if (patch_mode && (opts.track > 0 || opts.new_branch - || opts.new_branch_log || opts.merge || opts.force)) + || opts.new_branch_log || opts.merge || opts.force + || opts.force_detach)) die ("--patch is incompatible with all other options"); + if (opts.force_detach && (opts.new_branch || opts.new_orphan_branch)) + die("--detach cannot be used with -b/-B/--orphan"); + if (opts.force_detach && 0 < opts.track) + die("--detach cannot be used with -t"); + /* --track without -b should DWIM */ if (0 < opts.track && !opts.new_branch) { const char *argv0 = argv[0]; @@ -766,105 +977,30 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) die("git checkout: -f and -m are incompatible"); /* - * case 1: git checkout <ref> -- [<paths>] - * - * <ref> must be a valid tree, everything after the '--' must be - * a path. - * - * case 2: git checkout -- [<paths>] - * - * everything after the '--' must be paths. - * - * case 3: git checkout <something> [<paths>] - * - * With no paths, if <something> is a commit, that is to - * switch to the branch or detach HEAD at it. As a special case, - * if <something> is A...B (missing A or B means HEAD but you can - * omit at most one side), and if there is a unique merge base - * between A and B, A...B names that merge base. + * Extract branch name from command line arguments, so + * all that is left is pathspecs. * - * With no paths, if <something> is _not_ a commit, no -t nor -b - * was given, and there is a remote-tracking branch whose name is - * <something> in one and only one remote, then this is a short-hand - * to fork local <something> from that remote-tracking branch. + * Handle * - * Otherwise <something> shall not be ambiguous. - * - If it's *only* a reference, treat it like case (1). - * - If it's only a path, treat it like case (2). - * - else: fail. + * 1) git checkout <tree> -- [<paths>] + * 2) git checkout -- [<paths>] + * 3) git checkout <something> [<paths>] * + * including "last branch" syntax and DWIM-ery for names of + * remote branches, erroring out for invalid or ambiguous cases. */ if (argc) { - if (!strcmp(argv[0], "--")) { /* case (2) */ - argv++; - argc--; - goto no_reference; - } - - arg = argv[0]; - has_dash_dash = (argc > 1) && !strcmp(argv[1], "--"); - - if (!strcmp(arg, "-")) - arg = "@{-1}"; - - if (get_sha1_mb(arg, rev)) { - if (has_dash_dash) /* case (1) */ - die("invalid reference: %s", arg); - if (!patch_mode && - dwim_new_local_branch && - opts.track == BRANCH_TRACK_UNSPECIFIED && - !opts.new_branch && - !check_filename(NULL, arg) && - argc == 1) { - const char *remote = unique_tracking_name(arg); - if (!remote || get_sha1(remote, rev)) - goto no_reference; - opts.new_branch = arg; - arg = remote; - /* DWIMmed to create local branch */ - } - else - goto no_reference; - } - - /* we can't end up being in (2) anymore, eat the argument */ - argv++; - argc--; - - new.name = arg; - if ((new.commit = lookup_commit_reference_gently(rev, 1))) { - setup_branch_path(&new); - - if ((check_ref_format(new.path) == CHECK_REF_FORMAT_OK) && - resolve_ref(new.path, rev, 1, NULL)) - ; - else - new.path = NULL; - parse_commit(new.commit); - source_tree = new.commit->tree; - } else - source_tree = parse_tree_indirect(rev); - - if (!source_tree) /* case (1): want a tree */ - die("reference is not a tree: %s", arg); - if (!has_dash_dash) {/* case (3 -> 1) */ - /* - * Do not complain the most common case - * git checkout branch - * even if there happen to be a file called 'branch'; - * it would be extremely annoying. - */ - if (argc) - verify_non_filename(NULL, arg); - } - else { - argv++; - argc--; - } + int dwim_ok = + !patch_mode && + dwim_new_local_branch && + opts.track == BRANCH_TRACK_UNSPECIFIED && + !opts.new_branch; + int n = parse_branchname_arg(argc, argv, dwim_ok, + &new, &source_tree, rev, &opts.new_branch); + argv += n; + argc -= n; } -no_reference: - if (opts.track == BRANCH_TRACK_UNSPECIFIED) opts.track = git_branch_track; @@ -886,6 +1022,9 @@ no_reference: } } + if (opts.force_detach) + die("git checkout: --detach does not take a path argument"); + if (1 < !!opts.writeout_stage + !!opts.force + !!opts.merge) die("git checkout: --ours/--theirs, --force and --merge are incompatible when\nchecking out of the index."); diff --git a/builtin/clone.c b/builtin/clone.c index 2ee1fa9846..02547adba5 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -100,7 +100,7 @@ static char *get_repo_path(const char *repo, int *is_bundle) path = mkpath("%s%s", repo, suffix[i]); if (is_directory(path)) { *is_bundle = 0; - return xstrdup(make_nonrelative_path(path)); + return xstrdup(absolute_path(path)); } } @@ -109,7 +109,7 @@ static char *get_repo_path(const char *repo, int *is_bundle) path = mkpath("%s%s", repo, bundle_suffix[i]); if (!stat(path, &st) && S_ISREG(st.st_mode)) { *is_bundle = 1; - return xstrdup(make_nonrelative_path(path)); + return xstrdup(absolute_path(path)); } } @@ -203,7 +203,7 @@ static void setup_reference(const char *repo) struct transport *transport; const struct ref *extra; - ref_git = make_absolute_path(option_reference); + ref_git = real_path(option_reference); if (is_directory(mkpath("%s/.git/objects", ref_git))) ref_git = mkpath("%s/.git", ref_git); @@ -383,6 +383,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) junk_pid = getpid(); + packet_trace_identity("clone"); argc = parse_options(argc, argv, prefix, builtin_clone_options, builtin_clone_usage, 0); @@ -411,7 +412,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) path = get_repo_path(repo_name, &is_bundle); if (path) - repo = xstrdup(make_nonrelative_path(repo_name)); + repo = xstrdup(absolute_path(repo_name)); else if (!strchr(repo_name, ':')) die("repository '%s' does not exist", repo_name); else @@ -466,7 +467,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (safe_create_leading_directories_const(git_dir) < 0) die("could not create leading directories of '%s'", git_dir); - set_git_dir(make_absolute_path(git_dir)); + set_git_dir(real_path(git_dir)); if (0 <= option_verbosity) printf("Cloning into %s%s...\n", diff --git a/builtin/commit.c b/builtin/commit.c index d71e1e0c9c..3979b823ef 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -54,9 +54,17 @@ static const char empty_amend_advice[] = "it empty. You can repeat your command with --allow-empty, or you can\n" "remove the commit entirely with \"git reset HEAD^\".\n"; +static const char empty_cherry_pick_advice[] = +"The previous cherry-pick is now empty, possibly due to conflict resolution.\n" +"If you wish to commit it anyway, use:\n" +"\n" +" git commit --allow-empty\n" +"\n" +"Otherwise, please use 'git reset'\n"; + static unsigned char head_sha1[20]; -static char *use_message_buffer; +static const char *use_message_buffer; static const char commit_editmsg[] = "COMMIT_EDITMSG"; static struct lock_file index_lock; /* real index */ static struct lock_file false_lock; /* used only for partial commits */ @@ -68,6 +76,11 @@ static enum { static const char *logfile, *force_author; static const char *template_file; +/* + * The _message variables are commit names from which to take + * the commit message and/or authorship. + */ +static const char *author_message, *author_message_buffer; static char *edit_message, *use_message; static char *fixup_message, *squash_message; static int all, edit_flag, also, interactive, only, amend, signoff; @@ -88,7 +101,8 @@ static enum { } cleanup_mode; static char *cleanup_arg; -static int use_editor = 1, initial_commit, in_merge, include_status = 1; +static enum commit_whence whence; +static int use_editor = 1, initial_commit, include_status = 1; static int show_ignored_in_status; static const char *only_include_assumed; static struct strbuf message; @@ -163,6 +177,36 @@ static struct option builtin_commit_options[] = { OPT_END() }; +static void determine_whence(struct wt_status *s) +{ + if (file_exists(git_path("MERGE_HEAD"))) + whence = FROM_MERGE; + else if (file_exists(git_path("CHERRY_PICK_HEAD"))) + whence = FROM_CHERRY_PICK; + else + whence = FROM_COMMIT; + if (s) + s->whence = whence; +} + +static const char *whence_s(void) +{ + char *s = ""; + + switch (whence) { + case FROM_COMMIT: + break; + case FROM_MERGE: + s = "merge"; + break; + case FROM_CHERRY_PICK: + s = "cherry-pick"; + break; + } + + return s; +} + static void rollback_index_files(void) { switch (commit_style) { @@ -378,8 +422,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int */ commit_style = COMMIT_PARTIAL; - if (in_merge) - die("cannot do a partial commit during a merge."); + if (whence != FROM_COMMIT) + die("cannot do a partial commit during a %s.", whence_s()); memset(&partial, 0, sizeof(partial)); partial.strdup_strings = 1; @@ -469,18 +513,18 @@ static void determine_author_info(struct strbuf *author_ident) email = getenv("GIT_AUTHOR_EMAIL"); date = getenv("GIT_AUTHOR_DATE"); - if (use_message && !renew_authorship) { + if (author_message) { const char *a, *lb, *rb, *eol; - a = strstr(use_message_buffer, "\nauthor "); + a = strstr(author_message_buffer, "\nauthor "); if (!a) - die("invalid commit: %s", use_message); + die("invalid commit: %s", author_message); lb = strchrnul(a + strlen("\nauthor "), '<'); rb = strchrnul(lb, '>'); eol = strchrnul(rb, '\n'); if (!*lb || !*rb || !*eol) - die("invalid commit: %s", use_message); + die("invalid commit: %s", author_message); if (lb == a + strlen("\nauthor ")) /* \nauthor <foo@example.com> */ @@ -568,7 +612,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix, int commitable, saved_color_setting; struct strbuf sb = STRBUF_INIT; char *buffer; - FILE *fp; const char *hook_arg1 = NULL; const char *hook_arg2 = NULL; int ident_shown = 0; @@ -641,11 +684,15 @@ static int prepare_to_commit(const char *index_file, const char *prefix, } /* - * This final case does not modify the template message, - * it just sets the argument to the prepare-commit-msg hook. + * The remaining cases don't modify the template message, but + * just set the argument(s) to the prepare-commit-msg hook. */ - else if (in_merge) + else if (whence == FROM_MERGE) hook_arg1 = "merge"; + else if (whence == FROM_CHERRY_PICK) { + hook_arg1 = "commit"; + hook_arg2 = "CHERRY_PICK_HEAD"; + } if (squash_message) { /* @@ -657,8 +704,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix, hook_arg2 = ""; } - fp = fopen(git_path(commit_editmsg), "w"); - if (fp == NULL) + s->fp = fopen(git_path(commit_editmsg), "w"); + if (s->fp == NULL) die_errno("could not open '%s'", git_path(commit_editmsg)); if (cleanup_mode != CLEANUP_NONE) @@ -682,7 +729,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, strbuf_release(&sob); } - if (fwrite(sb.buf, 1, sb.len, fp) < sb.len) + if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len) die_errno("could not write commit template"); strbuf_release(&sb); @@ -694,55 +741,59 @@ static int prepare_to_commit(const char *index_file, const char *prefix, strbuf_addstr(&committer_ident, git_committer_info(0)); if (use_editor && include_status) { char *ai_tmp, *ci_tmp; - if (in_merge) - fprintf(fp, - "#\n" - "# It looks like you may be committing a MERGE.\n" - "# If this is not correct, please remove the file\n" - "# %s\n" - "# and try again.\n" - "#\n", - git_path("MERGE_HEAD")); - - fprintf(fp, - "\n" - "# Please enter the commit message for your changes."); + if (whence != FROM_COMMIT) + status_printf_ln(s, GIT_COLOR_NORMAL, + "\n" + "It looks like you may be committing a %s.\n" + "If this is not correct, please remove the file\n" + " %s\n" + "and try again.\n" + "", + whence_s(), + git_path(whence == FROM_MERGE + ? "MERGE_HEAD" + : "CHERRY_PICK_HEAD")); + + fprintf(s->fp, "\n"); + status_printf(s, GIT_COLOR_NORMAL, + "Please enter the commit message for your changes."); if (cleanup_mode == CLEANUP_ALL) - fprintf(fp, + status_printf_more(s, GIT_COLOR_NORMAL, " Lines starting\n" - "# with '#' will be ignored, and an empty" + "with '#' will be ignored, and an empty" " message aborts the commit.\n"); else /* CLEANUP_SPACE, that is. */ - fprintf(fp, + status_printf_more(s, GIT_COLOR_NORMAL, " Lines starting\n" - "# with '#' will be kept; you may remove them" + "with '#' will be kept; you may remove them" " yourself if you want to.\n" - "# An empty message aborts the commit.\n"); + "An empty message aborts the commit.\n"); if (only_include_assumed) - fprintf(fp, "# %s\n", only_include_assumed); + status_printf_ln(s, GIT_COLOR_NORMAL, + "%s", only_include_assumed); ai_tmp = cut_ident_timestamp_part(author_ident->buf); ci_tmp = cut_ident_timestamp_part(committer_ident.buf); if (strcmp(author_ident->buf, committer_ident.buf)) - fprintf(fp, + status_printf_ln(s, GIT_COLOR_NORMAL, "%s" - "# Author: %s\n", - ident_shown++ ? "" : "#\n", + "Author: %s", + ident_shown++ ? "" : "\n", author_ident->buf); if (!user_ident_sufficiently_given()) - fprintf(fp, + status_printf_ln(s, GIT_COLOR_NORMAL, "%s" - "# Committer: %s\n", - ident_shown++ ? "" : "#\n", + "Committer: %s", + ident_shown++ ? "" : "\n", committer_ident.buf); if (ident_shown) - fprintf(fp, "#\n"); + status_printf_ln(s, GIT_COLOR_NORMAL, ""); saved_color_setting = s->use_color; s->use_color = 0; - commitable = run_status(fp, index_file, prefix, 1, s); + commitable = run_status(s->fp, index_file, prefix, 1, s); s->use_color = saved_color_setting; *ai_tmp = ' '; @@ -764,13 +815,20 @@ static int prepare_to_commit(const char *index_file, const char *prefix, } strbuf_release(&committer_ident); - fclose(fp); + fclose(s->fp); - if (!commitable && !in_merge && !allow_empty && + /* + * Reject an attempt to record a non-merge empty commit without + * explicit --allow-empty. In the cherry-pick case, it may be + * empty due to conflict resolution, which the user should okay. + */ + if (!commitable && whence != FROM_MERGE && !allow_empty && !(amend && is_a_merge(head_sha1))) { run_status(stdout, index_file, prefix, 0, s); if (amend) fputs(empty_amend_advice, stderr); + else if (whence == FROM_CHERRY_PICK) + fputs(empty_cherry_pick_advice, stderr); return 0; } @@ -898,6 +956,28 @@ static void handle_untracked_files_arg(struct wt_status *s) die("Invalid untracked files mode '%s'", untracked_files_arg); } +static const char *read_commit_message(const char *name) +{ + const char *out_enc, *out; + struct commit *commit; + + commit = lookup_commit_reference_by_name(name); + if (!commit) + die("could not lookup commit %s", name); + out_enc = get_commit_output_encoding(); + out = logmsg_reencode(commit, out_enc); + + /* + * If we failed to reencode the buffer, just copy it + * byte for byte so the user can try to fix it up. + * This also handles the case where input and output + * encodings are identical. + */ + if (out == NULL) + out = xstrdup(commit->buffer); + return out; +} + static int parse_and_validate_options(int argc, const char *argv[], const char * const usage[], const char *prefix, @@ -927,8 +1007,8 @@ static int parse_and_validate_options(int argc, const char *argv[], /* Sanity check options */ if (amend && initial_commit) die("You have nothing to amend."); - if (amend && in_merge) - die("You are in the middle of a merge -- cannot amend."); + if (amend && whence != FROM_COMMIT) + die("You are in the middle of a %s -- cannot amend.", whence_s()); if (fixup_message && squash_message) die("Options --squash and --fixup cannot be used together"); if (use_message) @@ -947,26 +1027,18 @@ static int parse_and_validate_options(int argc, const char *argv[], use_message = edit_message; if (amend && !use_message && !fixup_message) use_message = "HEAD"; - if (!use_message && renew_authorship) + if (!use_message && whence != FROM_CHERRY_PICK && renew_authorship) die("--reset-author can be used only with -C, -c or --amend."); if (use_message) { - const char *out_enc; - struct commit *commit; - - commit = lookup_commit_reference_by_name(use_message); - if (!commit) - die("could not lookup commit %s", use_message); - out_enc = get_commit_output_encoding(); - use_message_buffer = logmsg_reencode(commit, out_enc); - - /* - * If we failed to reencode the buffer, just copy it - * byte for byte so the user can try to fix it up. - * This also handles the case where input and output - * encodings are identical. - */ - if (use_message_buffer == NULL) - use_message_buffer = xstrdup(commit->buffer); + use_message_buffer = read_commit_message(use_message); + if (!renew_authorship) { + author_message = use_message; + author_message_buffer = use_message_buffer; + } + } + if (whence == FROM_CHERRY_PICK && !renew_authorship) { + author_message = "CHERRY_PICK_HEAD"; + author_message_buffer = read_commit_message(author_message); } if (!!also + !!only + !!all + !!interactive > 1) @@ -1117,7 +1189,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) wt_status_prepare(&s); gitmodules_config(); git_config(git_status_config, &s); - in_merge = file_exists(git_path("MERGE_HEAD")); + determine_whence(&s); argc = parse_options(argc, argv, prefix, builtin_status_options, builtin_status_usage, 0); @@ -1140,7 +1212,6 @@ int cmd_status(int argc, const char **argv, const char *prefix) } s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0; - s.in_merge = in_merge; s.ignore_submodule_arg = ignore_submodule_arg; wt_status_collect(&s); @@ -1215,7 +1286,6 @@ static void print_summary(const char *prefix, const unsigned char *sha1) get_commit_format(format.buf, &rev); rev.always_show_header = 0; rev.diffopt.detect_rename = 1; - rev.diffopt.rename_limit = 100; rev.diffopt.break_opt = 0; diff_setup_done(&rev.diffopt); @@ -1302,8 +1372,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) wt_status_prepare(&s); git_config(git_commit_config, &s); - in_merge = file_exists(git_path("MERGE_HEAD")); - s.in_merge = in_merge; + determine_whence(&s); if (s.use_color == -1) s.use_color = git_use_color_default; @@ -1340,7 +1409,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) for (c = commit->parents; c; c = c->next) pptr = &commit_list_insert(c->item, pptr)->next; - } else if (in_merge) { + } else if (whence == FROM_MERGE) { struct strbuf m = STRBUF_INIT; FILE *fp; @@ -1369,7 +1438,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix) parents = reduce_heads(parents); } else { if (!reflog_msg) - reflog_msg = "commit"; + reflog_msg = (whence == FROM_CHERRY_PICK) + ? "commit (cherry-pick)" + : "commit"; pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next; } @@ -1424,6 +1495,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) die("cannot update HEAD ref"); } + unlink(git_path("CHERRY_PICK_HEAD")); unlink(git_path("MERGE_HEAD")); unlink(git_path("MERGE_MSG")); unlink(git_path("MERGE_MODE")); diff --git a/builtin/config.c b/builtin/config.c index b8b18e3c94..76be0b786f 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -153,7 +153,6 @@ static int show_config(const char *key_, const char *value_, void *cb) static int get_value(const char *key_, const char *regex_) { int ret = -1; - char *tl; char *global = NULL, *repo_config = NULL; const char *system_wide = NULL, *local; @@ -167,18 +166,32 @@ static int get_value(const char *key_, const char *regex_) system_wide = git_etc_gitconfig(); } - key = xstrdup(key_); - for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl) - *tl = tolower(*tl); - for (tl=key; *tl && *tl != '.'; ++tl) - *tl = tolower(*tl); - if (use_key_regexp) { + char *tl; + + /* + * NEEDSWORK: this naive pattern lowercasing obviously does not + * work for more complex patterns like "^[^.]*Foo.*bar". + * Perhaps we should deprecate this altogether someday. + */ + + key = xstrdup(key_); + for (tl = key + strlen(key) - 1; + tl >= key && *tl != '.'; + tl--) + *tl = tolower(*tl); + for (tl = key; *tl && *tl != '.'; tl++) + *tl = tolower(*tl); + key_regexp = (regex_t*)xmalloc(sizeof(regex_t)); if (regcomp(key_regexp, key, REG_EXTENDED)) { fprintf(stderr, "Invalid key pattern: %s\n", key_); + free(key); goto free_strings; } + } else { + if (git_config_parse_key(key_, &key, NULL)) + goto free_strings; } if (regex_) { @@ -500,3 +513,9 @@ int cmd_config(int argc, const char **argv, const char *prefix) return 0; } + +int cmd_repo_config(int argc, const char **argv, const char *prefix) +{ + fprintf(stderr, "WARNING: git repo-config is deprecated in favor of git config.\n"); + return cmd_config(argc, argv, prefix); +} diff --git a/builtin/diff-files.c b/builtin/diff-files.c index 951c7c8994..46085f862f 100644 --- a/builtin/diff-files.c +++ b/builtin/diff-files.c @@ -61,7 +61,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix) (rev.diffopt.output_format & DIFF_FORMAT_PATCH)) rev.combine_merges = rev.dense_combined_merges = 1; - if (read_cache_preload(rev.diffopt.paths) < 0) { + if (read_cache_preload(rev.diffopt.pathspec.raw) < 0) { perror("read_cache_preload"); return -1; } diff --git a/builtin/diff.c b/builtin/diff.c index 42822cd537..4c9deb28ec 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -135,7 +135,7 @@ static int builtin_diff_index(struct rev_info *revs, revs->max_count != -1 || revs->min_age != -1 || revs->max_age != -1) usage(builtin_diff_usage); - if (read_cache_preload(revs->diffopt.paths) < 0) { + if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) { perror("read_cache_preload"); return -1; } @@ -237,7 +237,7 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv revs->combine_merges = revs->dense_combined_merges = 1; setup_work_tree(); - if (read_cache_preload(revs->diffopt.paths) < 0) { + if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) { perror("read_cache_preload"); return -1; } @@ -374,14 +374,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix) } die("unhandled object '%s' given.", name); } - if (rev.prune_data) { - const char **pathspec = rev.prune_data; - while (*pathspec) { - if (!path) - path = *pathspec; - paths++; - pathspec++; - } + if (rev.prune_data.nr) { + if (!path) + path = rev.prune_data.items[0].match; + paths += rev.prune_data.nr; } /* diff --git a/builtin/fast-export.c b/builtin/fast-export.c index b18fc85c4c..daf19451ba 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -651,7 +651,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) if (import_filename) import_marks(import_filename); - if (import_filename && revs.prune_data) + if (import_filename && revs.prune_data.nr) full_tree = 1; get_tags_and_duplicates(&revs.pending, &extra_refs); diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c index b999413934..272bc383d6 100644 --- a/builtin/fetch-pack.c +++ b/builtin/fetch-pack.c @@ -804,6 +804,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) char **pack_lockfile_ptr = NULL; struct child_process *conn; + packet_trace_identity("fetch-pack"); + nr_heads = 0; heads = NULL; for (i = 1; i < argc; i++) { diff --git a/builtin/fetch.c b/builtin/fetch.c index 7efecfe1cf..1b6d4be002 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -906,6 +906,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) struct remote *remote; int result = 0; + packet_trace_identity("fetch"); + /* Record the command line for the reflog */ strbuf_addstr(&default_rla, "fetch"); for (i = 1; i < argc; i++) diff --git a/builtin/grep.c b/builtin/grep.c index 34f9ae0304..0bf8c0116a 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -328,106 +328,6 @@ static int grep_config(const char *var, const char *value, void *cb) return 0; } -/* - * Return non-zero if max_depth is negative or path has no more then max_depth - * slashes. - */ -static int accept_subdir(const char *path, int max_depth) -{ - if (max_depth < 0) - return 1; - - while ((path = strchr(path, '/')) != NULL) { - max_depth--; - if (max_depth < 0) - return 0; - path++; - } - return 1; -} - -/* - * Return non-zero if name is a subdirectory of match and is not too deep. - */ -static int is_subdir(const char *name, int namelen, - const char *match, int matchlen, int max_depth) -{ - if (matchlen > namelen || strncmp(name, match, matchlen)) - return 0; - - if (name[matchlen] == '\0') /* exact match */ - return 1; - - if (!matchlen || match[matchlen-1] == '/' || name[matchlen] == '/') - return accept_subdir(name + matchlen + 1, max_depth); - - return 0; -} - -/* - * git grep pathspecs are somewhat different from diff-tree pathspecs; - * pathname wildcards are allowed. - */ -static int pathspec_matches(const char **paths, const char *name, int max_depth) -{ - int namelen, i; - if (!paths || !*paths) - return accept_subdir(name, max_depth); - namelen = strlen(name); - for (i = 0; paths[i]; i++) { - const char *match = paths[i]; - int matchlen = strlen(match); - const char *cp, *meta; - - if (is_subdir(name, namelen, match, matchlen, max_depth)) - return 1; - if (!fnmatch(match, name, 0)) - return 1; - if (name[namelen-1] != '/') - continue; - - /* We are being asked if the directory ("name") is worth - * descending into. - * - * Find the longest leading directory name that does - * not have metacharacter in the pathspec; the name - * we are looking at must overlap with that directory. - */ - for (cp = match, meta = NULL; cp - match < matchlen; cp++) { - char ch = *cp; - if (ch == '*' || ch == '[' || ch == '?') { - meta = cp; - break; - } - } - if (!meta) - meta = cp; /* fully literal */ - - if (namelen <= meta - match) { - /* Looking at "Documentation/" and - * the pattern says "Documentation/howto/", or - * "Documentation/diff*.txt". The name we - * have should match prefix. - */ - if (!memcmp(match, name, namelen)) - return 1; - continue; - } - - if (meta - match < namelen) { - /* Looking at "Documentation/howto/" and - * the pattern says "Documentation/h*"; - * match up to "Do.../h"; this avoids descending - * into "Documentation/technical/". - */ - if (!memcmp(match, name, meta - match)) - return 1; - continue; - } - } - return 0; -} - static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size) { void *data; @@ -580,7 +480,7 @@ static void run_pager(struct grep_opt *opt, const char *prefix) free(argv); } -static int grep_cache(struct grep_opt *opt, const char **paths, int cached) +static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int cached) { int hit = 0; int nr; @@ -590,7 +490,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) struct cache_entry *ce = active_cache[nr]; if (!S_ISREG(ce->ce_mode)) continue; - if (!pathspec_matches(paths, ce->name, opt->max_depth)) + if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL)) continue; /* * If CE_VALID is on, we assume worktree file and its cache entry @@ -617,44 +517,29 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) return hit; } -static int grep_tree(struct grep_opt *opt, const char **paths, - struct tree_desc *tree, - const char *tree_name, const char *base) +static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, + struct tree_desc *tree, struct strbuf *base, int tn_len) { - int len; - int hit = 0; + int hit = 0, matched = 0; struct name_entry entry; - char *down; - int tn_len = strlen(tree_name); - struct strbuf pathbuf; - - strbuf_init(&pathbuf, PATH_MAX + tn_len); - - if (tn_len) { - strbuf_add(&pathbuf, tree_name, tn_len); - strbuf_addch(&pathbuf, ':'); - tn_len = pathbuf.len; - } - strbuf_addstr(&pathbuf, base); - len = pathbuf.len; + int old_baselen = base->len; while (tree_entry(tree, &entry)) { int te_len = tree_entry_len(entry.path, entry.sha1); - pathbuf.len = len; - strbuf_add(&pathbuf, entry.path, te_len); - - if (S_ISDIR(entry.mode)) - /* Match "abc/" against pathspec to - * decide if we want to descend into "abc" - * directory. - */ - strbuf_addch(&pathbuf, '/'); - - down = pathbuf.buf + tn_len; - if (!pathspec_matches(paths, down, opt->max_depth)) - ; - else if (S_ISREG(entry.mode)) - hit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len); + + if (matched != 2) { + matched = tree_entry_interesting(&entry, base, tn_len, pathspec); + if (matched == -1) + break; /* no more matches */ + if (!matched) + continue; + } + + strbuf_add(base, entry.path, te_len); + + if (S_ISREG(entry.mode)) { + hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len); + } else if (S_ISDIR(entry.mode)) { enum object_type type; struct tree_desc sub; @@ -665,18 +550,21 @@ static int grep_tree(struct grep_opt *opt, const char **paths, if (!data) die("unable to read tree (%s)", sha1_to_hex(entry.sha1)); + + strbuf_addch(base, '/'); init_tree_desc(&sub, data, size); - hit |= grep_tree(opt, paths, &sub, tree_name, down); + hit |= grep_tree(opt, pathspec, &sub, base, tn_len); free(data); } + strbuf_setlen(base, old_baselen); + if (hit && opt->status_only) break; } - strbuf_release(&pathbuf); return hit; } -static int grep_object(struct grep_opt *opt, const char **paths, +static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, struct object *obj, const char *name) { if (obj->type == OBJ_BLOB) @@ -685,20 +573,30 @@ static int grep_object(struct grep_opt *opt, const char **paths, struct tree_desc tree; void *data; unsigned long size; - int hit; + struct strbuf base; + int hit, len; + data = read_object_with_reference(obj->sha1, tree_type, &size, NULL); if (!data) die("unable to read tree (%s)", sha1_to_hex(obj->sha1)); + + len = name ? strlen(name) : 0; + strbuf_init(&base, PATH_MAX + len + 1); + if (len) { + strbuf_add(&base, name, len); + strbuf_addch(&base, ':'); + } init_tree_desc(&tree, data, size); - hit = grep_tree(opt, paths, &tree, name, ""); + hit = grep_tree(opt, pathspec, &tree, &base, base.len); + strbuf_release(&base); free(data); return hit; } die("unable to grep from object of type %s", typename(obj->type)); } -static int grep_objects(struct grep_opt *opt, const char **paths, +static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec, const struct object_array *list) { unsigned int i; @@ -708,7 +606,7 @@ static int grep_objects(struct grep_opt *opt, const char **paths, for (i = 0; i < nr; i++) { struct object *real_obj; real_obj = deref_tag(list->objects[i].item, NULL, 0); - if (grep_object(opt, paths, real_obj, list->objects[i].name)) { + if (grep_object(opt, pathspec, real_obj, list->objects[i].name)) { hit = 1; if (opt->status_only) break; @@ -717,7 +615,7 @@ static int grep_objects(struct grep_opt *opt, const char **paths, return hit; } -static int grep_directory(struct grep_opt *opt, const char **paths) +static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec) { struct dir_struct dir; int i, hit = 0; @@ -725,8 +623,12 @@ static int grep_directory(struct grep_opt *opt, const char **paths) memset(&dir, 0, sizeof(dir)); setup_standard_excludes(&dir); - fill_directory(&dir, paths); + fill_directory(&dir, pathspec->raw); for (i = 0; i < dir.nr; i++) { + const char *name = dir.entries[i]->name; + int namelen = strlen(name); + if (!match_pathspec_depth(pathspec, name, namelen, 0, NULL)) + continue; hit |= grep_file(opt, dir.entries[i]->name); if (hit && opt->status_only) break; @@ -757,11 +659,12 @@ static int context_callback(const struct option *opt, const char *arg, static int file_callback(const struct option *opt, const char *arg, int unset) { struct grep_opt *grep_opt = opt->value; + int from_stdin = !strcmp(arg, "-"); FILE *patterns; int lno = 0; struct strbuf sb = STRBUF_INIT; - patterns = fopen(arg, "r"); + patterns = from_stdin ? stdin : fopen(arg, "r"); if (!patterns) die_errno("cannot open '%s'", arg); while (strbuf_getline(&sb, patterns, '\n') == 0) { @@ -775,7 +678,8 @@ static int file_callback(const struct option *opt, const char *arg, int unset) s = strbuf_detach(&sb, &len); append_grep_pat(grep_opt, s, len, arg, ++lno, GREP_PATTERN); } - fclose(patterns); + if (!from_stdin) + fclose(patterns); strbuf_release(&sb); return 0; } @@ -831,6 +735,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) struct grep_opt opt; struct object_array list = OBJECT_ARRAY_INIT; const char **paths = NULL; + struct pathspec pathspec; struct string_list path_list = STRING_LIST_INIT_NODUP; int i; int dummy; @@ -1058,6 +963,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) paths[0] = prefix; paths[1] = NULL; } + init_pathspec(&pathspec, paths); + pathspec.max_depth = opt.max_depth; + pathspec.recursive = 1; if (show_in_pager && (cached || list.nr)) die("--open-files-in-pager only works on the worktree"); @@ -1088,16 +996,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix) die("--cached cannot be used with --no-index."); if (list.nr) die("--no-index cannot be used with revs."); - hit = grep_directory(&opt, paths); + hit = grep_directory(&opt, &pathspec); } else if (!list.nr) { if (!cached) setup_work_tree(); - hit = grep_cache(&opt, paths, cached); + hit = grep_cache(&opt, &pathspec, cached); } else { if (cached) die("both --cached and trees are given."); - hit = grep_objects(&opt, paths, &list); + hit = grep_objects(&opt, &pathspec, &list); } if (use_threads) diff --git a/builtin/hash-object.c b/builtin/hash-object.c index 080af1a01b..c90acddcb2 100644 --- a/builtin/hash-object.c +++ b/builtin/hash-object.c @@ -15,7 +15,7 @@ static void hash_fd(int fd, const char *type, int write_object, const char *path struct stat st; unsigned char sha1[20]; if (fstat(fd, &st) < 0 || - index_fd(sha1, fd, &st, write_object, type_from_string(type), path)) + index_fd(sha1, fd, &st, write_object, type_from_string(type), path, 1)) die(write_object ? "Unable to add %s to database" : "Unable to hash %s", path); diff --git a/builtin/init-db.c b/builtin/init-db.c index fbeb380ee2..8f5cfd7122 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -501,7 +501,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) const char *git_dir_parent = strrchr(git_dir, '/'); if (git_dir_parent) { char *rel = xstrndup(git_dir, git_dir_parent - git_dir); - git_work_tree_cfg = xstrdup(make_absolute_path(rel)); + git_work_tree_cfg = xstrdup(real_path(rel)); free(rel); } if (!git_work_tree_cfg) { @@ -510,7 +510,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) die_errno ("Cannot access current working directory"); } if (work_tree) - set_git_work_tree(make_absolute_path(work_tree)); + set_git_work_tree(real_path(work_tree)); else set_git_work_tree(git_work_tree_cfg); if (access(get_git_work_tree(), X_OK)) @@ -519,10 +519,10 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) } else { if (work_tree) - set_git_work_tree(make_absolute_path(work_tree)); + set_git_work_tree(real_path(work_tree)); } - set_git_dir(make_absolute_path(git_dir)); + set_git_dir(real_path(git_dir)); return init_db(template_dir, flags); } diff --git a/builtin/log.c b/builtin/log.c index 0f43d2ec78..796e9e5746 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -89,7 +89,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, rev->always_show_header = 0; if (DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES)) { rev->always_show_header = 0; - if (rev->diffopt.nr_paths != 1) + if (rev->diffopt.pathspec.nr != 1) usage("git logs can only follow renames on one pathname at a time"); } for (i = 1; i < argc; i++) { @@ -263,7 +263,13 @@ static int cmd_log_walk(struct rev_info *rev) * retain that state information if replacing rev->diffopt in this loop */ while ((commit = get_revision(rev)) != NULL) { - log_tree_commit(rev, commit); + if (!log_tree_commit(rev, commit) && + rev->max_count >= 0) + /* + * We decremented max_count in get_revision, + * but we didn't actually show the commit. + */ + rev->max_count++; if (!rev->reflog_info) { /* we allow cycles in reflog ancestry */ free(commit->buffer); diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c index 97eed4012b..1a1ff87e8f 100644 --- a/builtin/ls-remote.c +++ b/builtin/ls-remote.c @@ -33,6 +33,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) int i; const char *dest = NULL; unsigned flags = 0; + int get_url = 0; int quiet = 0; const char *uploadpack = NULL; const char **pattern = NULL; @@ -69,6 +70,10 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) quiet = 1; continue; } + if (!strcmp("--get-url", arg)) { + get_url = 1; + continue; + } usage(ls_remote_usage); } dest = arg; @@ -94,6 +99,12 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) } if (!remote->url_nr) die("remote %s has no configured URL", dest); + + if (get_url) { + printf("%s\n", *remote->url); + return 0; + } + transport = transport_get(remote, NULL); if (uploadpack != NULL) transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack); diff --git a/builtin/merge.c b/builtin/merge.c index f9fb26dc33..aa3453c5e1 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -58,6 +58,7 @@ static int option_renormalize; static int verbosity; static int allow_rerere_auto; static int abort_current_merge; +static int show_progress = -1; static struct strategy all_strategy[] = { { "recursive", DEFAULT_TWOHEAD | NO_TRIVIAL }, @@ -200,6 +201,7 @@ static struct option builtin_merge_options[] = { OPT__VERBOSITY(&verbosity), OPT_BOOLEAN(0, "abort", &abort_current_merge, "abort the current in-progress merge"), + OPT_SET_INT(0, "progress", &show_progress, "force progress reporting", 1), OPT_END() }; @@ -582,7 +584,8 @@ static void write_tree_trivial(unsigned char *sha1) die("git write-tree failed to write a tree"); } -int try_merge_command(const char *strategy, struct commit_list *common, +int try_merge_command(const char *strategy, size_t xopts_nr, + const char **xopts, struct commit_list *common, const char *head_arg, struct commit_list *remotes) { const char **args; @@ -659,6 +662,8 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, o.subtree_shift = ""; o.renormalize = option_renormalize; + o.show_rename_progress = + show_progress == -1 ? isatty(2) : show_progress; for (x = 0; x < xopts_nr; x++) if (parse_merge_opt(&o, xopts[x])) @@ -680,7 +685,8 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, rollback_lock_file(lock); return clean ? 0 : 1; } else { - return try_merge_command(strategy, common, head_arg, remoteheads); + return try_merge_command(strategy, xopts_nr, xopts, + common, head_arg, remoteheads); } } @@ -972,6 +978,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, builtin_merge_options, builtin_merge_usage, 0); + if (verbosity < 0 && show_progress == -1) + show_progress = 0; + if (abort_current_merge) { int nargc = 2; const char *nargv[] = {"reset", "--merge", NULL}; @@ -997,6 +1006,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix) else die("You have not concluded your merge (MERGE_HEAD exists)."); } + if (file_exists(git_path("CHERRY_PICK_HEAD"))) { + if (advice_resolve_conflict) + die("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n" + "Please, commit your changes before you can merge."); + else + die("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."); + } resolve_undo_clear(); if (verbosity < 0) diff --git a/builtin/push.c b/builtin/push.c index 31da418cf4..6f6a66f986 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -64,14 +64,24 @@ static void set_refspecs(const char **refs, int nr) } } -static void setup_push_upstream(void) +static void setup_push_upstream(struct remote *remote) { struct strbuf refspec = STRBUF_INIT; struct branch *branch = branch_get(NULL); if (!branch) - die("You are not currently on a branch."); + die("You are not currently on a branch.\n" + "To push the history leading to the current (detached HEAD)\n" + "state now, use\n" + "\n" + " git push %s HEAD:<name-of-remote-branch>\n", + remote->name); if (!branch->merge_nr || !branch->merge) - die("The current branch %s has no upstream branch.", + die("The current branch %s has no upstream branch.\n" + "To push the current branch and set the remote as upstream, use\n" + "\n" + " git push --set-upstream %s %s\n", + branch->name, + remote->name, branch->name); if (branch->merge_nr != 1) die("The current branch %s has multiple upstream branches, " @@ -80,7 +90,7 @@ static void setup_push_upstream(void) add_refspec(refspec.buf); } -static void setup_default_push_refspecs(void) +static void setup_default_push_refspecs(struct remote *remote) { switch (push_default) { default: @@ -89,7 +99,7 @@ static void setup_default_push_refspecs(void) break; case PUSH_DEFAULT_UPSTREAM: - setup_push_upstream(); + setup_push_upstream(remote); break; case PUSH_DEFAULT_CURRENT: @@ -147,7 +157,14 @@ static int do_push(const char *repo, int flags) if (!remote) { if (repo) die("bad repository '%s'", repo); - die("No destination configured to push to."); + die("No configured push destination.\n" + "Either specify the URL from the command-line or configure a remote repository using\n" + "\n" + " git remote add <name> <url>\n" + "\n" + "and then push using the remote name\n" + "\n" + " git push <name>\n"); } if (remote->mirror) @@ -175,7 +192,7 @@ static int do_push(const char *repo, int flags) refspec = remote->push_refspec; refspec_nr = remote->push_refspec_nr; } else if (!(flags & TRANSPORT_PUSH_MIRROR)) - setup_default_push_refspecs(); + setup_default_push_refspecs(remote); } errs = 0; if (remote->pushurl_nr) { @@ -228,6 +245,7 @@ int cmd_push(int argc, const char **argv, const char *prefix) OPT_END() }; + packet_trace_identity("push"); git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, options, push_usage, 0); diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 760817dbd7..d8e2c5fca7 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -740,7 +740,7 @@ static int add_refs_from_alternate(struct alternate_object_database *e, void *un const struct ref *extra; e->name[-1] = '\0'; - other = xstrdup(make_absolute_path(e->base)); + other = xstrdup(real_path(e->base)); e->name[-1] = '/'; len = strlen(other); @@ -778,6 +778,8 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) char *dir = NULL; struct command *commands; + packet_trace_identity("receive-pack"); + argv++; for (i = 1; i < argc; i++) { const char *arg = *argv++; diff --git a/builtin/rerere.c b/builtin/rerere.c index 642bf35587..82358855d1 100644 --- a/builtin/rerere.c +++ b/builtin/rerere.c @@ -8,7 +8,7 @@ #include "xdiff-interface.h" static const char * const rerere_usage[] = { - "git rerere [clear | status | diff | gc]", + "git rerere [clear | forget path... | status | remaining | diff | gc]", NULL, }; @@ -136,7 +136,10 @@ int cmd_rerere(int argc, const char **argv, const char *prefix) return rerere(flags); if (!strcmp(argv[0], "forget")) { - const char **pathspec = get_pathspec(prefix, argv + 1); + const char **pathspec; + if (argc < 2) + warning("'git rerere forget' without paths is deprecated"); + pathspec = get_pathspec(prefix, argv + 1); return rerere_forget(pathspec); } @@ -156,7 +159,17 @@ int cmd_rerere(int argc, const char **argv, const char *prefix) else if (!strcmp(argv[0], "status")) for (i = 0; i < merge_rr.nr; i++) printf("%s\n", merge_rr.items[i].string); - else if (!strcmp(argv[0], "diff")) + else if (!strcmp(argv[0], "remaining")) { + rerere_remaining(&merge_rr); + for (i = 0; i < merge_rr.nr; i++) { + if (merge_rr.items[i].util != RERERE_RESOLVED) + printf("%s\n", merge_rr.items[i].string); + else + /* prepare for later call to + * string_list_clear() */ + merge_rr.items[i].util = NULL; + } + } else if (!strcmp(argv[0], "diff")) for (i = 0; i < merge_rr.nr; i++) { const char *path = merge_rr.items[i].string; const char *name = (const char *)merge_rr.items[i].util; diff --git a/builtin/revert.c b/builtin/revert.c index bb6e9e83b7..c57b872fe1 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -3,7 +3,6 @@ #include "object.h" #include "commit.h" #include "tag.h" -#include "wt-status.h" #include "run-command.h" #include "exec_cmd.h" #include "utf8.h" @@ -44,7 +43,11 @@ static const char **commit_argv; static int allow_rerere_auto; static const char *me; + +/* Merge strategy. */ static const char *strategy; +static const char **xopts; +static size_t xopts_nr, xopts_alloc; #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION" @@ -55,6 +58,17 @@ static const char * const *revert_or_cherry_pick_usage(void) return action == REVERT ? revert_usage : cherry_pick_usage; } +static int option_parse_x(const struct option *opt, + const char *arg, int unset) +{ + if (unset) + return 0; + + ALLOC_GROW(xopts, xopts_nr + 1, xopts_alloc); + xopts[xopts_nr++] = xstrdup(arg); + return 0; +} + static void parse_args(int argc, const char **argv) { const char * const * usage_str = revert_or_cherry_pick_usage(); @@ -67,6 +81,8 @@ static void parse_args(int argc, const char **argv) OPT_INTEGER('m', "mainline", &mainline, "parent number"), OPT_RERERE_AUTOUPDATE(&allow_rerere_auto), OPT_STRING(0, "strategy", &strategy, "strategy", "merge strategy"), + OPT_CALLBACK('X', "strategy-option", &xopts, "option", + "option for merge strategy", option_parse_x), OPT_END(), OPT_END(), OPT_END(), @@ -181,54 +197,20 @@ static void add_message_to_msg(struct strbuf *msgbuf, const char *message) strbuf_addstr(msgbuf, p); } -static void set_author_ident_env(const char *message) +static void write_cherry_pick_head(void) { - const char *p = message; - if (!p) - die ("Could not read commit message of %s", - sha1_to_hex(commit->object.sha1)); - while (*p && *p != '\n') { - const char *eol; - - for (eol = p; *eol && *eol != '\n'; eol++) - ; /* do nothing */ - if (!prefixcmp(p, "author ")) { - char *line, *pend, *email, *timestamp; - - p += 7; - line = xmemdupz(p, eol - p); - email = strchr(line, '<'); - if (!email) - die ("Could not extract author email from %s", - sha1_to_hex(commit->object.sha1)); - if (email == line) - pend = line; - else - for (pend = email; pend != line + 1 && - isspace(pend[-1]); pend--); - ; /* do nothing */ - *pend = '\0'; - email++; - timestamp = strchr(email, '>'); - if (!timestamp) - die ("Could not extract author time from %s", - sha1_to_hex(commit->object.sha1)); - *timestamp = '\0'; - for (timestamp++; *timestamp && isspace(*timestamp); - timestamp++) - ; /* do nothing */ - setenv("GIT_AUTHOR_NAME", line, 1); - setenv("GIT_AUTHOR_EMAIL", email, 1); - setenv("GIT_AUTHOR_DATE", timestamp, 1); - free(line); - return; - } - p = eol; - if (*p == '\n') - p++; - } - die ("No author information found in %s", - sha1_to_hex(commit->object.sha1)); + int fd; + struct strbuf buf = STRBUF_INIT; + + strbuf_addf(&buf, "%s\n", sha1_to_hex(commit->object.sha1)); + + fd = open(git_path("CHERRY_PICK_HEAD"), O_WRONLY | O_CREAT, 0666); + if (fd < 0) + die_errno("Could not open '%s' for writing", + git_path("CHERRY_PICK_HEAD")); + if (write_in_full(fd, buf.buf, buf.len) != buf.len || close(fd)) + die_errno("Could not write to '%s'", git_path("CHERRY_PICK_HEAD")); + strbuf_release(&buf); } static void advise(const char *advice, ...) @@ -246,15 +228,18 @@ static void print_advice(void) if (msg) { fprintf(stderr, "%s\n", msg); + /* + * A conflict has occured but the porcelain + * (typically rebase --interactive) wants to take care + * of the commit itself so remove CHERRY_PICK_HEAD + */ + unlink(git_path("CHERRY_PICK_HEAD")); return; } advise("after resolving the conflicts, mark the corrected paths"); advise("with 'git add <paths>' or 'git rm <paths>'"); - - if (action == CHERRY_PICK) - advise("and commit the result with 'git commit -c %s'", - find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV)); + advise("and commit the result with 'git commit'"); } static void write_message(struct strbuf *msgbuf, const char *filename) @@ -311,18 +296,13 @@ static int do_recursive_merge(struct commit *base, struct commit *next, struct merge_options o; struct tree *result, *next_tree, *base_tree, *head_tree; int clean, index_fd; + const char **xopt; static struct lock_file index_lock; index_fd = hold_locked_index(&index_lock, 1); read_cache(); - /* - * NEEDSWORK: cherry-picking between branches with - * different end-of-line normalization is a pain; - * plumb in an option to set o.renormalize? - * (or better: arbitrary -X options) - */ init_merge_options(&o); o.ancestor = base ? base_label : "(empty tree)"; o.branch1 = "HEAD"; @@ -332,6 +312,9 @@ static int do_recursive_merge(struct commit *base, struct commit *next, next_tree = next ? next->tree : empty_tree(); base_tree = base ? base->tree : empty_tree(); + for (xopt = xopts; xopt != xopts + xopts_nr; xopt++) + parse_merge_opt(&o, *xopt); + clean = merge_trees(&o, head_tree, next_tree, base_tree, &result); @@ -482,13 +465,14 @@ static int do_pick_commit(void) base_label = msg.parent_label; next = commit; next_label = msg.label; - set_author_ident_env(msg.message); add_message_to_msg(&msgbuf, msg.message); if (no_replay) { strbuf_addstr(&msgbuf, "(cherry picked from commit "); strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1)); strbuf_addstr(&msgbuf, ")\n"); } + if (!no_commit) + write_cherry_pick_head(); } if (!strategy || !strcmp(strategy, "recursive") || action == REVERT) { @@ -503,7 +487,7 @@ static int do_pick_commit(void) commit_list_insert(base, &common); commit_list_insert(next, &remotes); - res = try_merge_command(strategy, common, + res = try_merge_command(strategy, xopts_nr, xopts, common, sha1_to_hex(head), remotes); free_commit_list(common); free_commit_list(remotes); diff --git a/builtin/update-index.c b/builtin/update-index.c index 56baf27fb7..d7850c6309 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -546,7 +546,10 @@ static int do_reupdate(int ac, const char **av, */ int pos; int has_head = 1; - const char **pathspec = get_pathspec(prefix, av + 1); + const char **paths = get_pathspec(prefix, av + 1); + struct pathspec pathspec; + + init_pathspec(&pathspec, paths); if (read_ref("HEAD", head_sha1)) /* If there is no HEAD, that means it is an initial @@ -559,7 +562,7 @@ static int do_reupdate(int ac, const char **av, struct cache_entry *old = NULL; int save_nr; - if (ce_stage(ce) || !ce_path_match(ce, pathspec)) + if (ce_stage(ce) || !ce_path_match(ce, &pathspec)) continue; if (has_head) old = read_one_ent(NULL, head_sha1, @@ -578,6 +581,7 @@ static int do_reupdate(int ac, const char **av, if (save_nr != active_nr) goto redo; } + free_pathspec(&pathspec); return 0; } @@ -5,6 +5,7 @@ #include "strbuf.h" #include "hash.h" #include "advice.h" +#include "gettext.h" #include SHA1_HEADER #ifndef git_SHA_CTX @@ -500,8 +501,23 @@ extern int index_name_is_other(const struct index_state *, const char *, int); extern int ie_match_stat(const struct index_state *, struct cache_entry *, struct stat *, unsigned int); extern int ie_modified(const struct index_state *, struct cache_entry *, struct stat *, unsigned int); -extern int ce_path_match(const struct cache_entry *ce, const char **pathspec); -extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path); +struct pathspec { + const char **raw; /* get_pathspec() result, not freed by free_pathspec() */ + int nr; + unsigned int has_wildcard:1; + unsigned int recursive:1; + int max_depth; + struct pathspec_item { + const char *match; + int len; + unsigned int has_wildcard:1; + } *items; +}; + +extern int init_pathspec(struct pathspec *, const char **); +extern void free_pathspec(struct pathspec *); +extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec); +extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path, int format_check); extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object); extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); @@ -511,7 +527,7 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); #define REFRESH_IGNORE_MISSING 0x0008 /* ignore non-existent */ #define REFRESH_IGNORE_SUBMODULES 0x0010 /* ignore submodules */ #define REFRESH_IN_PORCELAIN 0x0020 /* user friendly output, not "needs update" */ -extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, char *header_msg); +extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, const char *header_msg); struct lock_file { struct lock_file *next; @@ -716,9 +732,9 @@ static inline int is_absolute_path(const char *path) return path[0] == '/' || has_dos_drive_prefix(path); } int is_directory(const char *); -const char *make_absolute_path(const char *path); -const char *make_nonrelative_path(const char *path); -const char *make_relative_path(const char *abs, const char *base); +const char *real_path(const char *path); +const char *absolute_path(const char *path); +const char *relative_path(const char *abs, const char *base); int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); char *strip_path_suffix(const char *path, const char *suffix); @@ -999,6 +1015,7 @@ extern int git_config_maybe_bool(const char *, const char *); extern int git_config_string(const char **, const char *, const char *); extern int git_config_pathname(const char **, const char *, const char *); extern int git_config_set(const char *, const char *); +extern int git_config_parse_key(const char *, char **, int *); extern int git_config_set_multivar(const char *, const char *, const char *, int); extern int git_config_rename_section(const char *, const char *); extern const char *git_etc_gitconfig(void); @@ -1067,9 +1084,14 @@ extern void alloc_report(void); /* trace.c */ __attribute__((format (printf, 1, 2))) extern void trace_printf(const char *format, ...); +extern void trace_vprintf(const char *key, const char *format, va_list ap); __attribute__((format (printf, 2, 3))) extern void trace_argv_printf(const char **argv, const char *format, ...); extern void trace_repo_setup(const char *prefix); +extern int trace_want(const char *key); +extern void trace_strbuf(const char *key, const struct strbuf *buf); + +void packet_trace_identity(const char *prog); /* convert.c */ /* returns 1 if *dst was used */ @@ -175,6 +175,15 @@ int git_color_default_config(const char *var, const char *value, void *cb) return git_default_config(var, value, cb); } +void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb) +{ + if (*color) + fprintf(fp, "%s", color); + fprintf(fp, "%s", sb->buf); + if (*color) + fprintf(fp, "%s", GIT_COLOR_RESET); +} + static int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args, const char *trail) { @@ -1,6 +1,8 @@ #ifndef COLOR_H #define COLOR_H +struct strbuf; + /* 2 + (2 * num_attrs) + 8 + 1 + 8 + 'm' + NUL */ /* "\033[1;2;4;5;7;38;5;2xx;48;5;2xxm\0" */ /* @@ -64,6 +66,7 @@ __attribute__((format (printf, 3, 4))) int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); __attribute__((format (printf, 3, 4))) int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); +void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb); int color_is_nil(const char *color); diff --git a/compat/mingw.c b/compat/mingw.c index bee6054419..878b1de97c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include <conio.h> #include "../strbuf.h" +#include "../run-command.h" + +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,165 @@ int err_win_to_posix(DWORD winerr) return error; } +static inline int is_file_in_use_error(DWORD errcode) +{ + switch (errcode) { + case ERROR_SHARING_VIOLATION: + case ERROR_ACCESS_DENIED: + return 1; + } + + return 0; +} + +static int read_yes_no_answer(void) +{ + char answer[1024]; + + if (fgets(answer, sizeof(answer), stdin)) { + size_t answer_len = strlen(answer); + int got_full_line = 0, c; + + /* remove the newline */ + if (answer_len >= 2 && answer[answer_len-2] == '\r') { + answer[answer_len-2] = '\0'; + got_full_line = 1; + } else if (answer_len >= 1 && answer[answer_len-1] == '\n') { + answer[answer_len-1] = '\0'; + got_full_line = 1; + } + /* flush the buffer in case we did not get the full line */ + if (!got_full_line) + while ((c = getchar()) != EOF && c != '\n') + ; + } else + /* we could not read, return the + * default answer which is no */ + return 0; + + if (tolower(answer[0]) == 'y' && !answer[1]) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (tolower(answer[0]) == 'n' && !answer[1]) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + + /* did not find an answer we understand */ + return -1; +} + +static int ask_yes_no_if_possible(const char *format, ...) +{ + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) + return 0; + + while (1) { + int answer; + fprintf(stderr, "%s (y/n) ", question); + + if ((answer = read_yes_no_answer()) >= 0) + return answer; + + fprintf(stderr, "Sorry, I did not understand your answer. " + "Please type 'y' or 'n'\n"); + } +} + +#undef unlink +int mingw_unlink(const char *pathname) +{ + int ret, tries = 0; + + /* read-only files cannot be removed */ + chmod(pathname, 0666); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (!is_file_in_use_error(GetLastError())) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && is_file_in_use_error(GetLastError()) && + ask_yes_no_if_possible("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); + return ret; +} + +static int is_dir_empty(const char *path) +{ + struct strbuf buf = STRBUF_INIT; + WIN32_FIND_DATAA findbuf; + HANDLE handle; + + strbuf_addf(&buf, "%s\\*", path); + handle = FindFirstFileA(buf.buf, &findbuf); + if (handle == INVALID_HANDLE_VALUE) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + + while (!strcmp(findbuf.cFileName, ".") || + !strcmp(findbuf.cFileName, "..")) + if (!FindNextFile(handle, &findbuf)) { + strbuf_release(&buf); + return GetLastError() == ERROR_NO_MORE_FILES; + } + FindClose(handle); + strbuf_release(&buf); + return 0; +} + +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (!is_file_in_use_error(GetLastError())) + break; + if (!is_dir_empty(pathname)) { + errno = ENOTEMPTY; + break; + } + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && is_file_in_use_error(GetLastError()) && + ask_yes_no_if_possible("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -1249,7 +1411,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. @@ -1291,6 +1452,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_yes_no_if_possible("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } diff --git a/compat/mingw.h b/compat/mingw.h index 14211c6214..62eccd3391 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int mingw_mkdir(const char *path, int mode) } #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - #define WNOHANG 1 pid_t waitpid(pid_t pid, int *status, unsigned options); @@ -174,6 +166,12 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open diff --git a/compat/msvc.h b/compat/msvc.h index 023aba0238..a33b01c032 100644 --- a/compat/msvc.h +++ b/compat/msvc.h @@ -9,7 +9,6 @@ #define inline __inline #define __inline__ __inline #define __attribute__(x) -#define va_copy(dst, src) ((dst) = (src)) #define strncasecmp _strnicmp #define ftruncate _chsize @@ -1093,6 +1093,75 @@ int git_config_set(const char *key, const char *value) } /* + * Auxiliary function to sanity-check and split the key into the section + * identifier and variable name. + * + * Returns 0 on success, -1 when there is an invalid character in the key and + * -2 if there is no section name in the key. + * + * store_key - pointer to char* which will hold a copy of the key with + * lowercase section and variable name + * baselen - pointer to int which will hold the length of the + * section + subsection part, can be NULL + */ +int git_config_parse_key(const char *key, char **store_key, int *baselen_) +{ + int i, dot, baselen; + const char *last_dot = strrchr(key, '.'); + + /* + * Since "key" actually contains the section name and the real + * key name separated by a dot, we have to know where the dot is. + */ + + if (last_dot == NULL || last_dot == key) { + error("key does not contain a section: %s", key); + return -2; + } + + if (!last_dot[1]) { + error("key does not contain variable name: %s", key); + return -2; + } + + baselen = last_dot - key; + if (baselen_) + *baselen_ = baselen; + + /* + * Validate the key and while at it, lower case it for matching. + */ + *store_key = xmalloc(strlen(key) + 1); + + dot = 0; + for (i = 0; key[i]; i++) { + unsigned char c = key[i]; + if (c == '.') + dot = 1; + /* Leave the extended basename untouched.. */ + if (!dot || i > baselen) { + if (!iskeychar(c) || + (i == baselen + 1 && !isalpha(c))) { + error("invalid key: %s", key); + goto out_free_ret_1; + } + c = tolower(c); + } else if (c == '\n') { + error("invalid key (newline): %s", key); + goto out_free_ret_1; + } + (*store_key)[i] = c; + } + (*store_key)[i] = 0; + + return 0; + +out_free_ret_1: + free(*store_key); + return -1; +} + +/* * If value==NULL, unset in (remove from) config, * if value_regex!=NULL, disregard key/value pairs where value does not match. * if multi_replace==0, nothing, or only one matching key/value is replaced, @@ -1118,59 +1187,23 @@ int git_config_set(const char *key, const char *value) int git_config_set_multivar(const char *key, const char *value, const char *value_regex, int multi_replace) { - int i, dot; int fd = -1, in_fd; int ret; char *config_filename; struct lock_file *lock = NULL; - const char *last_dot = strrchr(key, '.'); if (config_exclusive_filename) config_filename = xstrdup(config_exclusive_filename); else config_filename = git_pathdup("config"); - /* - * Since "key" actually contains the section name and the real - * key name separated by a dot, we have to know where the dot is. - */ - - if (last_dot == NULL) { - error("key does not contain a section: %s", key); - ret = 2; + /* parse-key returns negative; flip the sign to feed exit(3) */ + ret = 0 - git_config_parse_key(key, &store.key, &store.baselen); + if (ret) goto out_free; - } - store.baselen = last_dot - key; store.multi_replace = multi_replace; - /* - * Validate the key and while at it, lower case it for matching. - */ - store.key = xmalloc(strlen(key) + 1); - dot = 0; - for (i = 0; key[i]; i++) { - unsigned char c = key[i]; - if (c == '.') - dot = 1; - /* Leave the extended basename untouched.. */ - if (!dot || i > store.baselen) { - if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) { - error("invalid key: %s", key); - free(store.key); - ret = 1; - goto out_free; - } - c = tolower(c); - } else if (c == '\n') { - error("invalid key (newline): %s", key); - free(store.key); - ret = 1; - goto out_free; - } - store.key[i] = c; - } - store.key[i] = 0; /* * The lock serves a purpose in addition to locking: the new diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 893b7716ca..ccdc172a06 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -246,6 +246,8 @@ __git_ps1 () fi elif [ -f "$g/MERGE_HEAD" ]; then r="|MERGING" + elif [ -f "$g/CHERRY_PICK_HEAD" ]; then + r="|CHERRY-PICKING" elif [ -f "$g/BISECT_LOG" ]; then r="|BISECTING" fi @@ -1358,7 +1360,7 @@ _git_diff () } __git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff - tkdiff vimdiff gvimdiff xxdiff araxis p4merge + tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3 " _git_difftool () diff --git a/contrib/examples/git-revert.sh b/contrib/examples/git-revert.sh index 60a05a8b97..6bf155cbdb 100755 --- a/contrib/examples/git-revert.sh +++ b/contrib/examples/git-revert.sh @@ -26,6 +26,7 @@ require_work_tree cd_to_toplevel no_commit= +xopt= while case "$#" in 0) break ;; esac do case "$1" in @@ -44,6 +45,16 @@ do -x|--i-really-want-to-expose-my-private-commit-object-name) replay= ;; + -X?*) + xopt="$xopt$(git rev-parse --sq-quote "--${1#-X}")" + ;; + --strategy-option=*) + xopt="$xopt$(git rev-parse --sq-quote "--${1#--strategy-option=}")" + ;; + -X|--strategy-option) + shift + xopt="$xopt$(git rev-parse --sq-quote "--$1")" + ;; -*) usage ;; @@ -159,7 +170,7 @@ export GITHEAD_$head GITHEAD_$next # and $prev on top of us (when reverting), or the change between # $prev and $commit on top of us (when cherry-picking or replaying). -git-merge-recursive $base -- $head $next && +eval "git merge-recursive $xopt $base -- $head $next" && result=$(git-write-tree 2>/dev/null) || { mv -f .msg "$GIT_DIR/MERGE_MSG" { diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 04ce7e3b02..7cb479c5e1 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -543,13 +543,13 @@ class P4Submit(Command): self.options = [ optparse.make_option("--verbose", dest="verbose", action="store_true"), optparse.make_option("--origin", dest="origin"), - optparse.make_option("-M", dest="detectRename", action="store_true"), + optparse.make_option("-M", dest="detectRenames", action="store_true"), ] self.description = "Submit changes from git to the perforce depot." self.usage += " [name of git branch to submit into perforce depot]" self.interactive = True self.origin = "" - self.detectRename = False + self.detectRenames = False self.verbose = False self.isWindows = (platform.system() == "Windows") @@ -570,7 +570,7 @@ class P4Submit(Command): continue if inDescriptionSection: - if line.startswith("Files:"): + if line.startswith("Files:") or line.startswith("Jobs:"): inDescriptionSection = False else: continue @@ -613,7 +613,22 @@ class P4Submit(Command): def applyCommit(self, id): print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id)) - diffOpts = ("", "-M")[self.detectRename] + + if not self.detectRenames: + # If not explicitly set check the config variable + self.detectRenames = gitConfig("git-p4.detectRenames").lower() == "true" + + if self.detectRenames: + diffOpts = "-M" + else: + diffOpts = "" + + if gitConfig("git-p4.detectCopies").lower() == "true": + diffOpts += " -C" + + if gitConfig("git-p4.detectCopiesHarder").lower() == "true": + diffOpts += " --find-copies-harder" + diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (diffOpts, id, id)) filesToAdd = set() filesToDelete = set() @@ -637,11 +652,23 @@ class P4Submit(Command): filesToDelete.add(path) if path in filesToAdd: filesToAdd.remove(path) + elif modifier == "C": + src, dest = diff['src'], diff['dst'] + p4_system("integrate -Dt \"%s\" \"%s\"" % (src, dest)) + if diff['src_sha1'] != diff['dst_sha1']: + p4_system("edit \"%s\"" % (dest)) + if isModeExecChanged(diff['src_mode'], diff['dst_mode']): + p4_system("edit \"%s\"" % (dest)) + filesToChangeExecBit[dest] = diff['dst_mode'] + os.unlink(dest) + editedFiles.add(dest) elif modifier == "R": src, dest = diff['src'], diff['dst'] p4_system("integrate -Dt \"%s\" \"%s\"" % (src, dest)) - p4_system("edit \"%s\"" % (dest)) + if diff['src_sha1'] != diff['dst_sha1']: + p4_system("edit \"%s\"" % (dest)) if isModeExecChanged(diff['src_mode'], diff['dst_mode']): + p4_system("edit \"%s\"" % (dest)) filesToChangeExecBit[dest] = diff['dst_mode'] os.unlink(dest) editedFiles.add(dest) @@ -834,6 +861,8 @@ class P4Submit(Command): return True class P4Sync(Command): + delete_actions = ( "delete", "move/delete", "purge" ) + def __init__(self): Command.__init__(self) self.options = [ @@ -882,6 +911,23 @@ class P4Sync(Command): if gitConfig("git-p4.syncFromOrigin") == "false": self.syncWithOrigin = False + # + # P4 wildcards are not allowed in filenames. P4 complains + # if you simply add them, but you can force it with "-f", in + # which case it translates them into %xx encoding internally. + # Search for and fix just these four characters. Do % last so + # that fixing it does not inadvertently create new %-escapes. + # + def wildcard_decode(self, path): + # Cannot have * in a filename in windows; untested as to + # what p4 would do in such a case. + if not self.isWindows: + path = path.replace("%2A", "*") + path = path.replace("%23", "#") \ + .replace("%40", "@") \ + .replace("%25", "%") + return path + def extractFilesFromCommit(self, commit): self.cloneExclude = [re.sub(r"\.\.\.$", "", path) for path in self.cloneExclude] @@ -910,6 +956,22 @@ class P4Sync(Command): return files def stripRepoPath(self, path, prefixes): + if self.useClientSpec: + + # if using the client spec, we use the output directory + # specified in the client. For example, a view + # //depot/foo/branch/... //client/branch/foo/... + # will end up putting all foo/branch files into + # branch/foo/ + for val in self.clientSpecDirs: + if path.startswith(val[0]): + # replace the depot path with the client path + path = path.replace(val[0], val[1][1]) + # now strip out the client (//client/...) + path = re.sub("^(//[^/]+/)", '', path) + # the rest is all path + return path + if self.keepRepoPath: prefixes = [re.sub("^(//[^/]+/).*", r'\1', prefixes[0])] @@ -960,6 +1022,7 @@ class P4Sync(Command): return relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes) + relPath = self.wildcard_decode(relPath) if verbose: sys.stderr.write("%s\n" % relPath) @@ -1032,16 +1095,16 @@ class P4Sync(Command): includeFile = True for val in self.clientSpecDirs: if f['path'].startswith(val[0]): - if val[1] <= 0: + if val[1][0] <= 0: includeFile = False break if includeFile: filesForCommit.append(f) - if f['action'] not in ('delete', 'move/delete', 'purge'): - filesToRead.append(f) - else: + if f['action'] in self.delete_actions: filesToDelete.append(f) + else: + filesToRead.append(f) # deleted files... for f in filesToDelete: @@ -1127,7 +1190,7 @@ class P4Sync(Command): cleanedFiles = {} for info in files: - if info["action"] in ("delete", "purge"): + if info["action"] in self.delete_actions: continue cleanedFiles[info["depotFile"]] = info["rev"] @@ -1429,7 +1492,7 @@ class P4Sync(Command): print "Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), revision, self.branch) details = { "user" : "git perforce import user", "time" : int(time.time()) } - details["desc"] = ("Initial import of %s from the state at revision %s" + details["desc"] = ("Initial import of %s from the state at revision %s\n" % (' '.join(self.depotPaths), revision)) details["change"] = revision newestRevision = 0 @@ -1440,9 +1503,16 @@ class P4Sync(Command): % (p, revision) for p in self.depotPaths])): - if info['code'] == 'error': + if 'code' in info and info['code'] == 'error': sys.stderr.write("p4 returned an error: %s\n" % info['data']) + if info['data'].find("must refer to client") >= 0: + sys.stderr.write("This particular p4 error is misleading.\n") + sys.stderr.write("Perhaps the depot path was misspelled.\n"); + sys.stderr.write("Depot path: %s\n" % " ".join(self.depotPaths)) + sys.exit(1) + if 'p4ExitCode' in info: + sys.stderr.write("p4 exitcode: %s\n" % info['p4ExitCode']) sys.exit(1) @@ -1450,7 +1520,7 @@ class P4Sync(Command): if change > newestRevision: newestRevision = change - if info["action"] in ("delete", "purge"): + if info["action"] in self.delete_actions: # don't increase the file cnt, otherwise details["depotFile123"] will have gaps! #fileCnt = fileCnt + 1 continue @@ -1475,19 +1545,45 @@ class P4Sync(Command): for entry in specList: for k,v in entry.iteritems(): if k.startswith("View"): + + # p4 has these %%1 to %%9 arguments in specs to + # reorder paths; which we can't handle (yet :) + if re.match('%%\d', v) != None: + print "Sorry, can't handle %%n arguments in client specs" + sys.exit(1) + if v.startswith('"'): start = 1 else: start = 0 index = v.find("...") + + # save the "client view"; i.e the RHS of the view + # line that tells the client where to put the + # files for this view. + cv = v[index+3:].strip() # +3 to remove previous '...' + + # if the client view doesn't end with a + # ... wildcard, then we're going to mess up the + # output directory, so fail gracefully. + if not cv.endswith('...'): + print 'Sorry, client view in "%s" needs to end with wildcard' % (k) + sys.exit(1) + cv=cv[:-3] + + # now save the view; +index means included, -index + # means it should be filtered out. v = v[start:index] if v.startswith("-"): v = v[1:] - temp[v] = -len(v) + include = -len(v) else: - temp[v] = len(v) + include = len(v) + + temp[v] = (include, cv) + self.clientSpecDirs = temp.items() - self.clientSpecDirs.sort( lambda x, y: abs( y[1] ) - abs( x[1] ) ) + self.clientSpecDirs.sort( lambda x, y: abs( y[1][0] ) - abs( x[1][0] ) ) def run(self, args): self.depotPaths = [] @@ -1667,6 +1763,8 @@ class P4Sync(Command): changes.sort() else: + if not isinstance(self, P4Clone) and not self.p4BranchesInGit: + die("No remote p4 branches. Perhaps you never did \"git p4 clone\" in here."); if self.verbose: print "Getting p4 changes for %s...%s" % (', '.join(self.depotPaths), self.changeRange) @@ -1747,10 +1845,13 @@ class P4Clone(P4Sync): help="where to leave result of the clone"), optparse.make_option("-/", dest="cloneExclude", action="append", type="string", - help="exclude depot path") + help="exclude depot path"), + optparse.make_option("--bare", dest="cloneBare", + action="store_true", default=False), ] self.cloneDestination = None self.needsGit = False + self.cloneBare = False # This is required for the "append" cloneExclude action def ensure_value(self, attr, value): @@ -1790,11 +1891,16 @@ class P4Clone(P4Sync): self.cloneDestination = self.defaultDestination(args) print "Importing from %s into %s" % (', '.join(depotPaths), self.cloneDestination) + if not os.path.exists(self.cloneDestination): os.makedirs(self.cloneDestination) chdir(self.cloneDestination) - system("git init") - self.gitdir = os.getcwd() + "/.git" + + init_cmd = [ "git", "init" ] + if self.cloneBare: + init_cmd.append("--bare") + subprocess.check_call(init_cmd) + if not P4Sync.run(self, depotPaths): return False if self.branch != "master": @@ -1804,7 +1910,8 @@ class P4Clone(P4Sync): masterbranch = "refs/heads/p4/master" if gitBranchExists(masterbranch): system("git branch master %s" % masterbranch) - system("git checkout -f") + if not self.cloneBare: + system("git checkout -f") else: print "Could not detect main branch. No checkout/master branch created." diff --git a/contrib/fast-import/git-p4.txt b/contrib/fast-import/git-p4.txt index 49b335921a..e09da445b6 100644 --- a/contrib/fast-import/git-p4.txt +++ b/contrib/fast-import/git-p4.txt @@ -191,6 +191,11 @@ git-p4.useclientspec git config [--global] git-p4.useclientspec false +The P4CLIENT environment variable should be correctly set for p4 to be +able to find the relevant client. This client spec will be used to +both filter the files cloned by git and set the directory layout as +specified in the client (this implies --keep-path style semantics). + Implementation Details... ========================= diff --git a/contrib/svn-fe/svn-fe.c b/contrib/svn-fe/svn-fe.c index a2677b03e0..35db24f5ea 100644 --- a/contrib/svn-fe/svn-fe.c +++ b/contrib/svn-fe/svn-fe.c @@ -8,7 +8,8 @@ int main(int argc, char **argv) { - svndump_init(NULL); + if (svndump_init(NULL)) + return 1; svndump_read((argc > 1) ? argv[1] : NULL); svndump_deinit(); svndump_reset(); diff --git a/diff-lib.c b/diff-lib.c index 392ce2bef0..1e22992cb1 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -106,7 +106,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES)) break; - if (!ce_path_match(ce, revs->prune_data)) + if (!ce_path_match(ce, &revs->prune_data)) continue; if (ce_stage(ce)) { @@ -427,7 +427,7 @@ static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o) if (tree == o->df_conflict_entry) tree = NULL; - if (ce_path_match(idx ? idx : tree, revs->prune_data)) + if (ce_path_match(idx ? idx : tree, &revs->prune_data)) do_oneway_diff(o, idx, tree); return 0; @@ -501,7 +501,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt) active_nr = dst - active_cache; init_revisions(&revs, NULL); - revs.prune_data = opt->paths; + init_pathspec(&revs.prune_data, opt->pathspec.raw); tree = parse_tree_indirect(tree_sha1); if (!tree) die("bad tree object %s", sha1_to_hex(tree_sha1)); diff --git a/diff-no-index.c b/diff-no-index.c index ce9e783407..3a36144687 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -231,8 +231,9 @@ void diff_no_index(struct rev_info *revs, if (prefix) { int len = strlen(prefix); + const char *paths[3]; + memset(paths, 0, sizeof(paths)); - revs->diffopt.paths = xcalloc(2, sizeof(char *)); for (i = 0; i < 2; i++) { const char *p = argv[argc - 2 + i]; /* @@ -242,12 +243,12 @@ void diff_no_index(struct rev_info *revs, p = (strcmp(p, "-") ? xstrdup(prefix_filename(prefix, len, p)) : p); - revs->diffopt.paths[i] = p; + paths[i] = p; } + diff_tree_setup_paths(paths, &revs->diffopt); } else - revs->diffopt.paths = argv + argc - 2; - revs->diffopt.nr_paths = 2; + diff_tree_setup_paths(argv + argc - 2, &revs->diffopt); revs->diffopt.skip_stat_unmatch = 1; if (!revs->diffopt.output_format) revs->diffopt.output_format = DIFF_FORMAT_PATCH; @@ -259,8 +260,8 @@ void diff_no_index(struct rev_info *revs, if (diff_setup_done(&revs->diffopt) < 0) die("diff_setup_done failed"); - if (queue_diff(&revs->diffopt, revs->diffopt.paths[0], - revs->diffopt.paths[1])) + if (queue_diff(&revs->diffopt, revs->diffopt.pathspec.raw[0], + revs->diffopt.pathspec.raw[1])) exit(1); diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/"); diffcore_std(&revs->diffopt); @@ -23,7 +23,7 @@ #endif static int diff_detect_rename_default; -static int diff_rename_limit_default = 200; +static int diff_rename_limit_default = 400; static int diff_suppress_blank_empty; int diff_use_color_default = -1; static const char *diff_word_regex_cfg; @@ -110,7 +110,8 @@ struct diff_options { int pickaxe_opts; int rename_score; int rename_limit; - int warn_on_too_large_rename; + int needed_rename_limit; + int show_rename_progress; int dirstat_percent; int setup; int abbrev; @@ -133,9 +134,7 @@ struct diff_options { FILE *file; int close_file; - int nr_paths; - const char **paths; - int *pathlens; + struct pathspec pathspec; change_fn_t change; add_remove_fn_t add_remove; diff_format_fn_t format_callback; diff --git a/diffcore-rename.c b/diffcore-rename.c index 0cd4c1305b..d40e40a3ac 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -5,6 +5,7 @@ #include "diff.h" #include "diffcore.h" #include "hash.h" +#include "progress.h" /* Table of rename/copy destinations */ @@ -449,6 +450,7 @@ void diffcore_rename(struct diff_options *options) struct diff_score *mx; int i, j, rename_count; int num_create, num_src, dst_cnt; + struct progress *progress = NULL; if (!minimum_score) minimum_score = DEFAULT_RENAME_SCORE; @@ -518,15 +520,22 @@ void diffcore_rename(struct diff_options *options) * but handles the potential overflow case specially (and we * assume at least 32-bit integers) */ + options->needed_rename_limit = 0; if (rename_limit <= 0 || rename_limit > 32767) rename_limit = 32767; if ((num_create > rename_limit && num_src > rename_limit) || (num_create * num_src > rename_limit * rename_limit)) { - if (options->warn_on_too_large_rename) - warning("too many files (created: %d deleted: %d), skipping inexact rename detection", num_create, num_src); + options->needed_rename_limit = + num_src > num_create ? num_src : num_create; goto cleanup; } + if (options->show_rename_progress) { + progress = start_progress_delay( + "Performing inexact rename detection", + rename_dst_nr * rename_src_nr, 50, 1); + } + mx = xcalloc(num_create * NUM_CANDIDATE_PER_DST, sizeof(*mx)); for (dst_cnt = i = 0; i < rename_dst_nr; i++) { struct diff_filespec *two = rename_dst[i].two; @@ -556,7 +565,9 @@ void diffcore_rename(struct diff_options *options) diff_free_filespec_blob(two); } dst_cnt++; + display_progress(progress, (i+1)*rename_src_nr); } + stop_progress(&progress); /* cost matrix sorted by most to least similar pair */ qsort(mx, dst_cnt * NUM_CANDIDATE_PER_DST, sizeof(*mx), score_compare); @@ -87,6 +87,21 @@ int fill_directory(struct dir_struct *dir, const char **pathspec) return len; } +int within_depth(const char *name, int namelen, + int depth, int max_depth) +{ + const char *cp = name, *cpe = name + namelen; + + while (cp < cpe) { + if (*cp++ != '/') + continue; + depth++; + if (depth > max_depth) + return 0; + } + return 1; +} + /* * Does 'match' match the given name? * A match is found if @@ -184,6 +199,95 @@ int match_pathspec(const char **pathspec, const char *name, int namelen, return retval; } +/* + * Does 'match' match the given name? + * A match is found if + * + * (1) the 'match' string is leading directory of 'name', or + * (2) the 'match' string is a wildcard and matches 'name', or + * (3) the 'match' string is exactly the same as 'name'. + * + * and the return value tells which case it was. + * + * It returns 0 when there is no match. + */ +static int match_pathspec_item(const struct pathspec_item *item, int prefix, + const char *name, int namelen) +{ + /* name/namelen has prefix cut off by caller */ + const char *match = item->match + prefix; + int matchlen = item->len - prefix; + + /* If the match was just the prefix, we matched */ + if (!*match) + return MATCHED_RECURSIVELY; + + if (matchlen <= namelen && !strncmp(match, name, matchlen)) { + if (matchlen == namelen) + return MATCHED_EXACTLY; + + if (match[matchlen-1] == '/' || name[matchlen] == '/') + return MATCHED_RECURSIVELY; + } + + if (item->has_wildcard && !fnmatch(match, name, 0)) + return MATCHED_FNMATCH; + + return 0; +} + +/* + * Given a name and a list of pathspecs, see if the name matches + * any of the pathspecs. The caller is also interested in seeing + * all pathspec matches some names it calls this function with + * (otherwise the user could have mistyped the unmatched pathspec), + * and a mark is left in seen[] array for pathspec element that + * actually matched anything. + */ +int match_pathspec_depth(const struct pathspec *ps, + const char *name, int namelen, + int prefix, char *seen) +{ + int i, retval = 0; + + if (!ps->nr) { + if (!ps->recursive || ps->max_depth == -1) + return MATCHED_RECURSIVELY; + + if (within_depth(name, namelen, 0, ps->max_depth)) + return MATCHED_EXACTLY; + else + return 0; + } + + name += prefix; + namelen -= prefix; + + for (i = ps->nr - 1; i >= 0; i--) { + int how; + if (seen && seen[i] == MATCHED_EXACTLY) + continue; + how = match_pathspec_item(ps->items+i, prefix, name, namelen); + if (ps->recursive && ps->max_depth != -1 && + how && how != MATCHED_FNMATCH) { + int len = ps->items[i].len; + if (name[len] == '/') + len++; + if (within_depth(name+len, namelen-len, 0, ps->max_depth)) + how = MATCHED_EXACTLY; + else + how = 0; + } + if (how) { + if (retval < how) + retval = how; + if (seen && seen[i] < how) + seen[i] = how; + } + } + return retval; +} + static int no_wildcard(const char *string) { return string[strcspn(string, "*?[{\\")] == '\0'; @@ -1024,7 +1128,7 @@ char *get_relative_cwd(char *buffer, int size, const char *dir) die_errno("can't find the current directory"); if (!is_absolute_path(dir)) - dir = make_absolute_path(dir); + dir = real_path(dir); while (*dir && *dir == *cwd) { dir++; @@ -1151,3 +1255,50 @@ int remove_path(const char *name) return 0; } +static int pathspec_item_cmp(const void *a_, const void *b_) +{ + struct pathspec_item *a, *b; + + a = (struct pathspec_item *)a_; + b = (struct pathspec_item *)b_; + return strcmp(a->match, b->match); +} + +int init_pathspec(struct pathspec *pathspec, const char **paths) +{ + const char **p = paths; + int i; + + memset(pathspec, 0, sizeof(*pathspec)); + if (!p) + return 0; + while (*p) + p++; + pathspec->raw = paths; + pathspec->nr = p - paths; + if (!pathspec->nr) + return 0; + + pathspec->items = xmalloc(sizeof(struct pathspec_item)*pathspec->nr); + for (i = 0; i < pathspec->nr; i++) { + struct pathspec_item *item = pathspec->items+i; + const char *path = paths[i]; + + item->match = path; + item->len = strlen(path); + item->has_wildcard = !no_wildcard(path); + if (item->has_wildcard) + pathspec->has_wildcard = 1; + } + + qsort(pathspec->items, pathspec->nr, + sizeof(struct pathspec_item), pathspec_item_cmp); + + return 0; +} + +void free_pathspec(struct pathspec *pathspec) +{ + free(pathspec->items); + pathspec->items = NULL; +} @@ -65,6 +65,10 @@ struct dir_struct { #define MATCHED_FNMATCH 2 #define MATCHED_EXACTLY 3 extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen); +extern int match_pathspec_depth(const struct pathspec *pathspec, + const char *name, int namelen, + int prefix, char *seen); +extern int within_depth(const char *name, int namelen, int depth, int max_depth); extern int fill_directory(struct dir_struct *dir, const char **pathspec); extern int read_directory(struct dir_struct *, const char *path, int len, const char **pathspec); diff --git a/environment.c b/environment.c index c3efbb9608..cc670b1562 100644 --- a/environment.c +++ b/environment.c @@ -139,7 +139,7 @@ static int git_work_tree_initialized; void set_git_work_tree(const char *new_work_tree) { if (git_work_tree_initialized) { - new_work_tree = make_absolute_path(new_work_tree); + new_work_tree = real_path(new_work_tree); if (strcmp(new_work_tree, work_tree)) die("internal error: work tree has already been set\n" "Current worktree: %s\nNew worktree: %s", @@ -147,7 +147,7 @@ void set_git_work_tree(const char *new_work_tree) return; } git_work_tree_initialized = 1; - work_tree = xstrdup(make_absolute_path(new_work_tree)); + work_tree = xstrdup(real_path(new_work_tree)); } const char *get_git_work_tree(void) diff --git a/exec_cmd.c b/exec_cmd.c index 38545e8bfd..171e841531 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -89,7 +89,7 @@ static void add_path(struct strbuf *out, const char *path) if (is_absolute_path(path)) strbuf_addstr(out, path); else - strbuf_addstr(out, make_nonrelative_path(path)); + strbuf_addstr(out, absolute_path(path)); strbuf_addch(out, PATH_SEP); } diff --git a/fast-import.c b/fast-import.c index b3ba778924..d9f9a3f524 100644 --- a/fast-import.c +++ b/fast-import.c @@ -24,10 +24,12 @@ Format of STDIN stream: commit_msg ('from' sp committish lf)? ('merge' sp committish lf)* - file_change* + (file_change | ls)* lf?; commit_msg ::= data; + ls ::= 'ls' sp '"' quoted(path) '"' lf; + file_change ::= file_clr | file_del | file_rnm @@ -132,7 +134,7 @@ Format of STDIN stream: ts ::= # time since the epoch in seconds, ascii base10 notation; tz ::= # GIT style timezone; - # note: comments and cat requests may appear anywhere + # note: comments, ls and cat requests may appear anywhere # in the input, except within a data command. Any form # of the data command always escapes the related input # from comment processing. @@ -141,7 +143,9 @@ Format of STDIN stream: # must be the first character on that line (an lf # preceded it). # + cat_blob ::= 'cat-blob' sp (hexsha1 | idnum) lf; + ls_tree ::= 'ls' sp (hexsha1 | idnum) sp path_str lf; comment ::= '#' not_lf* lf; not_lf ::= # Any byte that is not ASCII newline (LF); @@ -315,6 +319,7 @@ static struct mark_set *marks; static const char *export_marks_file; static const char *import_marks_file; static int import_marks_file_from_stream; +static int import_marks_file_ignore_missing; static int relative_marks_paths; /* Our last blob */ @@ -359,6 +364,7 @@ static int cat_blob_fd = STDOUT_FILENO; static void parse_argv(void); static void parse_cat_blob(void); +static void parse_ls(struct branch *b); static void write_branch_report(FILE *rpt, struct branch *b) { @@ -1782,7 +1788,11 @@ static void read_marks(void) { char line[512]; FILE *f = fopen(import_marks_file, "r"); - if (!f) + if (f) + ; + else if (import_marks_file_ignore_missing && errno == ENOENT) + return; /* Marks file does not exist */ + else die_errno("cannot read '%s'", import_marks_file); while (fgets(line, sizeof(line), f)) { uintmax_t mark; @@ -2596,6 +2606,8 @@ static void parse_new_commit(void) note_change_n(b, prev_fanout); else if (!strcmp("deleteall", command_buf.buf)) file_change_deleteall(b); + else if (!prefixcmp(command_buf.buf, "ls ")) + parse_ls(b); else { unread_command_buf = 1; break; @@ -2819,6 +2831,153 @@ static void parse_cat_blob(void) cat_blob(oe, sha1); } +static struct object_entry *dereference(struct object_entry *oe, + unsigned char sha1[20]) +{ + unsigned long size; + char *buf = NULL; + if (!oe) { + enum object_type type = sha1_object_info(sha1, NULL); + if (type < 0) + die("object not found: %s", sha1_to_hex(sha1)); + /* cache it! */ + oe = insert_object(sha1); + oe->type = type; + oe->pack_id = MAX_PACK_ID; + oe->idx.offset = 1; + } + switch (oe->type) { + case OBJ_TREE: /* easy case. */ + return oe; + case OBJ_COMMIT: + case OBJ_TAG: + break; + default: + die("Not a treeish: %s", command_buf.buf); + } + + if (oe->pack_id != MAX_PACK_ID) { /* in a pack being written */ + buf = gfi_unpack_entry(oe, &size); + } else { + enum object_type unused; + buf = read_sha1_file(sha1, &unused, &size); + } + if (!buf) + die("Can't load object %s", sha1_to_hex(sha1)); + + /* Peel one layer. */ + switch (oe->type) { + case OBJ_TAG: + if (size < 40 + strlen("object ") || + get_sha1_hex(buf + strlen("object "), sha1)) + die("Invalid SHA1 in tag: %s", command_buf.buf); + break; + case OBJ_COMMIT: + if (size < 40 + strlen("tree ") || + get_sha1_hex(buf + strlen("tree "), sha1)) + die("Invalid SHA1 in commit: %s", command_buf.buf); + } + + free(buf); + return find_object(sha1); +} + +static struct object_entry *parse_treeish_dataref(const char **p) +{ + unsigned char sha1[20]; + struct object_entry *e; + + if (**p == ':') { /* <mark> */ + char *endptr; + e = find_mark(strtoumax(*p + 1, &endptr, 10)); + if (endptr == *p + 1) + die("Invalid mark: %s", command_buf.buf); + if (!e) + die("Unknown mark: %s", command_buf.buf); + *p = endptr; + hashcpy(sha1, e->idx.sha1); + } else { /* <sha1> */ + if (get_sha1_hex(*p, sha1)) + die("Invalid SHA1: %s", command_buf.buf); + e = find_object(sha1); + *p += 40; + } + + while (!e || e->type != OBJ_TREE) + e = dereference(e, sha1); + return e; +} + +static void print_ls(int mode, const unsigned char *sha1, const char *path) +{ + static struct strbuf line = STRBUF_INIT; + + /* See show_tree(). */ + const char *type = + S_ISGITLINK(mode) ? commit_type : + S_ISDIR(mode) ? tree_type : + blob_type; + + if (!mode) { + /* missing SP path LF */ + strbuf_reset(&line); + strbuf_addstr(&line, "missing "); + quote_c_style(path, &line, NULL, 0); + strbuf_addch(&line, '\n'); + } else { + /* mode SP type SP object_name TAB path LF */ + strbuf_reset(&line); + strbuf_addf(&line, "%06o %s %s\t", + mode, type, sha1_to_hex(sha1)); + quote_c_style(path, &line, NULL, 0); + strbuf_addch(&line, '\n'); + } + cat_blob_write(line.buf, line.len); +} + +static void parse_ls(struct branch *b) +{ + const char *p; + struct tree_entry *root = NULL; + struct tree_entry leaf = {0}; + + /* ls SP (<treeish> SP)? <path> */ + p = command_buf.buf + strlen("ls "); + if (*p == '"') { + if (!b) + die("Not in a commit: %s", command_buf.buf); + root = &b->branch_tree; + } else { + struct object_entry *e = parse_treeish_dataref(&p); + root = new_tree_entry(); + hashcpy(root->versions[1].sha1, e->idx.sha1); + load_tree(root); + if (*p++ != ' ') + die("Missing space after tree-ish: %s", command_buf.buf); + } + if (*p == '"') { + static struct strbuf uq = STRBUF_INIT; + const char *endp; + strbuf_reset(&uq); + if (unquote_c_style(&uq, p, &endp)) + die("Invalid path: %s", command_buf.buf); + if (*endp) + die("Garbage after path in: %s", command_buf.buf); + p = uq.buf; + } + tree_content_get(root, p, &leaf); + /* + * A directory in preparation would have a sha1 of zero + * until it is saved. Save, for simplicity. + */ + if (S_ISDIR(leaf.versions[1].mode)) + store_tree(&leaf); + + print_ls(leaf.versions[1].mode, leaf.versions[1].sha1, p); + if (!b || root != &b->branch_tree) + release_tree_entry(root); +} + static void checkpoint(void) { checkpoint_requested = 0; @@ -2854,7 +3013,8 @@ static char* make_fast_import_path(const char *path) return strbuf_detach(&abs_path, NULL); } -static void option_import_marks(const char *marks, int from_stream) +static void option_import_marks(const char *marks, + int from_stream, int ignore_missing) { if (import_marks_file) { if (from_stream) @@ -2868,6 +3028,7 @@ static void option_import_marks(const char *marks, int from_stream) import_marks_file = make_fast_import_path(marks); safe_create_leading_directories_const(import_marks_file); import_marks_file_from_stream = from_stream; + import_marks_file_ignore_missing = ignore_missing; } static void option_date_format(const char *fmt) @@ -2967,7 +3128,10 @@ static int parse_one_feature(const char *feature, int from_stream) if (!prefixcmp(feature, "date-format=")) { option_date_format(feature + 12); } else if (!prefixcmp(feature, "import-marks=")) { - option_import_marks(feature + 13, from_stream); + option_import_marks(feature + 13, from_stream, 0); + } else if (!prefixcmp(feature, "import-marks-if-exists=")) { + option_import_marks(feature + strlen("import-marks-if-exists="), + from_stream, 1); } else if (!prefixcmp(feature, "export-marks=")) { option_export_marks(feature + 13); } else if (!strcmp(feature, "cat-blob")) { @@ -2978,7 +3142,7 @@ static int parse_one_feature(const char *feature, int from_stream) relative_marks_paths = 0; } else if (!prefixcmp(feature, "force")) { force_update = 1; - } else if (!strcmp(feature, "notes")) { + } else if (!strcmp(feature, "notes") || !strcmp(feature, "ls")) { ; /* do nothing; we have the feature */ } else { return 0; @@ -3119,6 +3283,8 @@ int main(int argc, const char **argv) while (read_next_command() != EOF) { if (!strcmp("blob", command_buf.buf)) parse_new_blob(); + else if (!prefixcmp(command_buf.buf, "ls ")) + parse_ls(NULL); else if (!prefixcmp(command_buf.buf, "commit ")) parse_new_commit(); else if (!prefixcmp(command_buf.buf, "tag ")) @@ -347,26 +347,14 @@ int fsck_object(struct object *obj, int strict, fsck_error error_func) int fsck_error_function(struct object *obj, int type, const char *fmt, ...) { va_list ap; - int len; struct strbuf sb = STRBUF_INIT; strbuf_addf(&sb, "object %s:", obj->sha1?sha1_to_hex(obj->sha1):"(null)"); va_start(ap, fmt); - len = vsnprintf(sb.buf + sb.len, strbuf_avail(&sb), fmt, ap); + strbuf_vaddf(&sb, fmt, ap); va_end(ap); - if (len < 0) - len = 0; - if (len >= strbuf_avail(&sb)) { - strbuf_grow(&sb, len + 2); - va_start(ap, fmt); - len = vsnprintf(sb.buf + sb.len, strbuf_avail(&sb), fmt, ap); - va_end(ap); - if (len >= strbuf_avail(&sb)) - die("this should not happen, your snprintf is broken"); - } - error("%s", sb.buf); strbuf_release(&sb); return 1; diff --git a/gettext.c b/gettext.c new file mode 100644 index 0000000000..ae5394a496 --- /dev/null +++ b/gettext.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Ævar Arnfjörð Bjarmason + */ + +#include "git-compat-util.h" +#include "gettext.h" + +int use_gettext_poison(void) +{ + static int poison_requested = -1; + if (poison_requested == -1) + poison_requested = getenv("GIT_GETTEXT_POISON") ? 1 : 0; + return poison_requested; +} diff --git a/gettext.h b/gettext.h new file mode 100644 index 0000000000..1b253b7e76 --- /dev/null +++ b/gettext.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2010-2011 Ævar Arnfjörð Bjarmason + * + * This is a skeleton no-op implementation of gettext for Git. + * You can replace it with something that uses libintl.h and wraps + * gettext() to try out the translations. + */ + +#ifndef GETTEXT_H +#define GETTEXT_H + +#if defined(_) || defined(Q_) +#error "namespace conflict: '_' or 'Q_' is pre-defined?" +#endif + +#define FORMAT_PRESERVING(n) __attribute__((format_arg(n))) + +#ifdef GETTEXT_POISON +extern int use_gettext_poison(void); +#else +#define use_gettext_poison() 0 +#endif + +static inline FORMAT_PRESERVING(1) const char *_(const char *msgid) +{ + return use_gettext_poison() ? "# GETTEXT POISON #" : msgid; +} + +static inline FORMAT_PRESERVING(1) FORMAT_PRESERVING(2) +const char *Q_(const char *msgid, const char *plu, unsigned long n) +{ + if (use_gettext_poison()) + return "# GETTEXT POISON #"; + return n == 1 ? msgid : plu; +} + +/* Mark msgid for translation but do not translate it. */ +#define N_(msgid) (msgid) + +#endif diff --git a/git-compat-util.h b/git-compat-util.h index bf947b1ec3..49b50eec86 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -538,6 +538,19 @@ void git_qsort(void *base, size_t nmemb, size_t size, #define fstat_is_reliable() 1 #endif +#ifndef va_copy +/* + * Since an obvious implementation of va_list would be to make it a + * pointer into the stack frame, a simple assignment will work on + * many systems. But let's try to be more portable. + */ +#ifdef __va_copy +#define va_copy(dst, src) __va_copy(dst, src) +#else +#define va_copy(dst, src) ((dst) = (src)) +#endif +#endif + /* * Preserves errno, prints a message, but gives no warning for ENOENT. * Always returns the return value of unlink(2). diff --git a/git-cvsimport.perl b/git-cvsimport.perl index 8e683e5478..bbf327f3e8 100755 --- a/git-cvsimport.perl +++ b/git-cvsimport.perl @@ -366,7 +366,9 @@ sub conn { $self->{'socketo'}->write("valid-requests\n"); $self->{'socketo'}->flush(); - chomp(my $rep=$self->readline()); + my $rep=$self->readline(); + die "Failed to read from server" unless defined $rep; + chomp($rep); if ($rep !~ s/^Valid-requests\s*//) { $rep="<unknown>" unless $rep; die "Expected Valid-requests from server, but got: $rep\n"; diff --git a/git-instaweb.sh b/git-instaweb.sh index 10fcebb119..8bfa8a055c 100755 --- a/git-instaweb.sh +++ b/git-instaweb.sh @@ -558,12 +558,14 @@ my \$app = builder { # make it runnable as standalone app, # like it would be run via 'plackup' utility -if (__FILE__ eq \$0) { +if (caller) { + return \$app; +} else { require Plack::Runner; my \$runner = Plack::Runner->new(); \$runner->parse_options(qw(--env deployment --port $port), - "$local" ? qw(--host 127.0.0.1) : ()); + "$local" ? qw(--host 127.0.0.1) : ()); \$runner->run(\$app); } __END__ diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh index 78ce49e984..fb3f52ba25 100644 --- a/git-mergetool--lib.sh +++ b/git-mergetool--lib.sh @@ -10,17 +10,20 @@ merge_mode() { translate_merge_tool_path () { case "$1" in - vimdiff|vimdiff2) - echo vim + araxis) + echo compare ;; - gvimdiff|gvimdiff2) - echo gvim + bc3) + echo bcompare ;; emerge) echo emacs ;; - araxis) - echo compare + gvimdiff|gvimdiff2) + echo gvim + ;; + vimdiff|vimdiff2) + echo vim ;; *) echo "$1" @@ -46,17 +49,16 @@ check_unchanged () { valid_tool () { case "$1" in - kdiff3 | tkdiff | xxdiff | meld | opendiff | \ - vimdiff | gvimdiff | vimdiff2 | gvimdiff2 | \ - emerge | ecmerge | diffuse | araxis | p4merge) + araxis | bc3 | diffuse | ecmerge | emerge | gvimdiff | gvimdiff2 | \ + kdiff3 | meld | opendiff | p4merge | tkdiff | vimdiff | vimdiff2 | xxdiff) ;; # happy - tortoisemerge) - if ! merge_mode; then + kompare) + if ! diff_mode; then return 1 fi ;; - kompare) - if ! diff_mode; then + tortoisemerge) + if ! merge_mode; then return 1 fi ;; @@ -89,88 +91,91 @@ run_merge_tool () { status=0 case "$1" in - kdiff3) + araxis) if merge_mode; then + touch "$BACKUP" if $base_present; then - ("$merge_tool_path" --auto \ - --L1 "$MERGED (Base)" \ - --L2 "$MERGED (Local)" \ - --L3 "$MERGED (Remote)" \ - -o "$MERGED" \ - "$BASE" "$LOCAL" "$REMOTE" \ - > /dev/null 2>&1) + "$merge_tool_path" -wait -merge -3 -a1 \ + "$BASE" "$LOCAL" "$REMOTE" "$MERGED" \ + >/dev/null 2>&1 else - ("$merge_tool_path" --auto \ - --L1 "$MERGED (Local)" \ - --L2 "$MERGED (Remote)" \ - -o "$MERGED" \ - "$LOCAL" "$REMOTE" \ - > /dev/null 2>&1) + "$merge_tool_path" -wait -2 \ + "$LOCAL" "$REMOTE" "$MERGED" \ + >/dev/null 2>&1 fi - status=$? + check_unchanged else - ("$merge_tool_path" --auto \ - --L1 "$MERGED (A)" \ - --L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \ - > /dev/null 2>&1) + "$merge_tool_path" -wait -2 "$LOCAL" "$REMOTE" \ + >/dev/null 2>&1 fi ;; - kompare) - "$merge_tool_path" "$LOCAL" "$REMOTE" - ;; - tkdiff) + bc3) if merge_mode; then + touch "$BACKUP" if $base_present; then - "$merge_tool_path" -a "$BASE" \ - -o "$MERGED" "$LOCAL" "$REMOTE" + "$merge_tool_path" "$LOCAL" "$REMOTE" "$BASE" \ + -mergeoutput="$MERGED" else - "$merge_tool_path" \ - -o "$MERGED" "$LOCAL" "$REMOTE" + "$merge_tool_path" "$LOCAL" "$REMOTE" \ + -mergeoutput="$MERGED" fi - status=$? + check_unchanged else "$merge_tool_path" "$LOCAL" "$REMOTE" fi ;; - p4merge) + diffuse) if merge_mode; then - touch "$BACKUP" + touch "$BACKUP" if $base_present; then - "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED" + "$merge_tool_path" \ + "$LOCAL" "$MERGED" "$REMOTE" \ + "$BASE" | cat else - "$merge_tool_path" "$LOCAL" "$LOCAL" "$REMOTE" "$MERGED" + "$merge_tool_path" \ + "$LOCAL" "$MERGED" "$REMOTE" | cat fi check_unchanged else - "$merge_tool_path" "$LOCAL" "$REMOTE" + "$merge_tool_path" "$LOCAL" "$REMOTE" | cat fi ;; - meld) + ecmerge) if merge_mode; then touch "$BACKUP" - "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE" + if $base_present; then + "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" \ + --default --mode=merge3 --to="$MERGED" + else + "$merge_tool_path" "$LOCAL" "$REMOTE" \ + --default --mode=merge2 --to="$MERGED" + fi check_unchanged else - "$merge_tool_path" "$LOCAL" "$REMOTE" + "$merge_tool_path" --default --mode=diff2 \ + "$LOCAL" "$REMOTE" fi ;; - diffuse) + emerge) if merge_mode; then - touch "$BACKUP" if $base_present; then "$merge_tool_path" \ - "$LOCAL" "$MERGED" "$REMOTE" \ - "$BASE" | cat + -f emerge-files-with-ancestor-command \ + "$LOCAL" "$REMOTE" "$BASE" \ + "$(basename "$MERGED")" else "$merge_tool_path" \ - "$LOCAL" "$MERGED" "$REMOTE" | cat + -f emerge-files-command \ + "$LOCAL" "$REMOTE" \ + "$(basename "$MERGED")" fi - check_unchanged + status=$? else - "$merge_tool_path" "$LOCAL" "$REMOTE" | cat + "$merge_tool_path" -f emerge-files-command \ + "$LOCAL" "$REMOTE" fi ;; - vimdiff|gvimdiff) + gvimdiff|vimdiff) if merge_mode; then touch "$BACKUP" if $base_present; then @@ -186,7 +191,7 @@ run_merge_tool () { "$LOCAL" "$REMOTE" fi ;; - vimdiff2|gvimdiff2) + gvimdiff2|vimdiff2) if merge_mode; then touch "$BACKUP" "$merge_tool_path" -f -d -c "wincmd l" \ @@ -197,30 +202,42 @@ run_merge_tool () { "$LOCAL" "$REMOTE" fi ;; - xxdiff) + kdiff3) if merge_mode; then - touch "$BACKUP" if $base_present; then - "$merge_tool_path" -X --show-merged-pane \ - -R 'Accel.SaveAsMerged: "Ctrl-S"' \ - -R 'Accel.Search: "Ctrl+F"' \ - -R 'Accel.SearchForward: "Ctrl-G"' \ - --merged-file "$MERGED" \ - "$LOCAL" "$BASE" "$REMOTE" + ("$merge_tool_path" --auto \ + --L1 "$MERGED (Base)" \ + --L2 "$MERGED (Local)" \ + --L3 "$MERGED (Remote)" \ + -o "$MERGED" \ + "$BASE" "$LOCAL" "$REMOTE" \ + > /dev/null 2>&1) else - "$merge_tool_path" -X $extra \ - -R 'Accel.SaveAsMerged: "Ctrl-S"' \ - -R 'Accel.Search: "Ctrl+F"' \ - -R 'Accel.SearchForward: "Ctrl-G"' \ - --merged-file "$MERGED" \ - "$LOCAL" "$REMOTE" + ("$merge_tool_path" --auto \ + --L1 "$MERGED (Local)" \ + --L2 "$MERGED (Remote)" \ + -o "$MERGED" \ + "$LOCAL" "$REMOTE" \ + > /dev/null 2>&1) fi + status=$? + else + ("$merge_tool_path" --auto \ + --L1 "$MERGED (A)" \ + --L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \ + > /dev/null 2>&1) + fi + ;; + kompare) + "$merge_tool_path" "$LOCAL" "$REMOTE" + ;; + meld) + if merge_mode; then + touch "$BACKUP" + "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE" check_unchanged else - "$merge_tool_path" \ - -R 'Accel.Search: "Ctrl+F"' \ - -R 'Accel.SearchForward: "Ctrl-G"' \ - "$LOCAL" "$REMOTE" + "$merge_tool_path" "$LOCAL" "$REMOTE" fi ;; opendiff) @@ -239,39 +256,31 @@ run_merge_tool () { "$merge_tool_path" "$LOCAL" "$REMOTE" | cat fi ;; - ecmerge) + p4merge) if merge_mode; then - touch "$BACKUP" + touch "$BACKUP" if $base_present; then - "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" \ - --default --mode=merge3 --to="$MERGED" + "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED" else - "$merge_tool_path" "$LOCAL" "$REMOTE" \ - --default --mode=merge2 --to="$MERGED" + "$merge_tool_path" "$LOCAL" "$LOCAL" "$REMOTE" "$MERGED" fi check_unchanged else - "$merge_tool_path" --default --mode=diff2 \ - "$LOCAL" "$REMOTE" + "$merge_tool_path" "$LOCAL" "$REMOTE" fi ;; - emerge) + tkdiff) if merge_mode; then if $base_present; then - "$merge_tool_path" \ - -f emerge-files-with-ancestor-command \ - "$LOCAL" "$REMOTE" "$BASE" \ - "$(basename "$MERGED")" + "$merge_tool_path" -a "$BASE" \ + -o "$MERGED" "$LOCAL" "$REMOTE" else "$merge_tool_path" \ - -f emerge-files-command \ - "$LOCAL" "$REMOTE" \ - "$(basename "$MERGED")" + -o "$MERGED" "$LOCAL" "$REMOTE" fi status=$? else - "$merge_tool_path" -f emerge-files-command \ - "$LOCAL" "$REMOTE" + "$merge_tool_path" "$LOCAL" "$REMOTE" fi ;; tortoisemerge) @@ -286,22 +295,30 @@ run_merge_tool () { status=1 fi ;; - araxis) + xxdiff) if merge_mode; then touch "$BACKUP" if $base_present; then - "$merge_tool_path" -wait -merge -3 -a1 \ - "$BASE" "$LOCAL" "$REMOTE" "$MERGED" \ - >/dev/null 2>&1 + "$merge_tool_path" -X --show-merged-pane \ + -R 'Accel.SaveAsMerged: "Ctrl-S"' \ + -R 'Accel.Search: "Ctrl+F"' \ + -R 'Accel.SearchForward: "Ctrl-G"' \ + --merged-file "$MERGED" \ + "$LOCAL" "$BASE" "$REMOTE" else - "$merge_tool_path" -wait -2 \ - "$LOCAL" "$REMOTE" "$MERGED" \ - >/dev/null 2>&1 + "$merge_tool_path" -X $extra \ + -R 'Accel.SaveAsMerged: "Ctrl-S"' \ + -R 'Accel.Search: "Ctrl+F"' \ + -R 'Accel.SearchForward: "Ctrl-G"' \ + --merged-file "$MERGED" \ + "$LOCAL" "$REMOTE" fi check_unchanged else - "$merge_tool_path" -wait -2 "$LOCAL" "$REMOTE" \ - >/dev/null 2>&1 + "$merge_tool_path" \ + -R 'Accel.Search: "Ctrl+F"' \ + -R 'Accel.SearchForward: "Ctrl-G"' \ + "$LOCAL" "$REMOTE" fi ;; *) @@ -343,7 +360,7 @@ guess_merge_tool () { else tools="opendiff kdiff3 tkdiff xxdiff meld $tools" fi - tools="$tools gvimdiff diffuse ecmerge p4merge araxis" + tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3" fi case "${VISUAL:-$EDITOR}" in *vim*) diff --git a/git-mergetool.sh b/git-mergetool.sh index 2f8dc441c6..bacbda2bb7 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -269,7 +269,7 @@ rerere=false files_to_merge() { if test "$rerere" = true then - git rerere status + git rerere remaining else git ls-files -u | sed -e 's/^[^ ]* //' | sort -u fi diff --git a/git-parse-remote.sh b/git-parse-remote.sh index 1cc2ba6e09..e7013f7ba7 100644 --- a/git-parse-remote.sh +++ b/git-parse-remote.sh @@ -4,56 +4,6 @@ # this would fail in that case and would issue an error message. GIT_DIR=$(git rev-parse -q --git-dir) || :; -get_data_source () { - case "$1" in - */*) - echo '' - ;; - .) - echo self - ;; - *) - if test "$(git config --get "remote.$1.url")" - then - echo config - elif test -f "$GIT_DIR/remotes/$1" - then - echo remotes - elif test -f "$GIT_DIR/branches/$1" - then - echo branches - else - echo '' - fi ;; - esac -} - -get_remote_url () { - data_source=$(get_data_source "$1") - case "$data_source" in - '') - echo "$1" - ;; - self) - echo "$1" - ;; - config) - git config --get "remote.$1.url" - ;; - remotes) - sed -ne '/^URL: */{ - s///p - q - }' "$GIT_DIR/remotes/$1" - ;; - branches) - sed -e 's/#.*//' "$GIT_DIR/branches/$1" - ;; - *) - die "internal error: get-remote-url $1" ;; - esac -} - get_default_remote () { curr_branch=$(git symbolic-ref -q HEAD | sed -e 's|^refs/heads/||') origin=$(git config --get "branch.$curr_branch.remote") diff --git a/git-pull.sh b/git-pull.sh index f6b7b84048..63b063a7b2 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -53,6 +53,8 @@ do verbosity="$verbosity -v" ;; --progress) progress=--progress ;; + --no-progress) + progress=--no-progress ;; -n|--no-stat|--no-summary) diffstat=--no-stat ;; --stat|--summary) @@ -293,8 +295,8 @@ true) ;; *) eval="git-merge $diffstat $no_commit $squash $no_ff $ff_only" - eval="$eval $log_arg $strategy_args $merge_args" - eval="$eval \"\$merge_name\" HEAD $merge_head $verbosity" + eval="$eval $log_arg $strategy_args $merge_args $verbosity $progress" + eval="$eval \"\$merge_name\" HEAD $merge_head" ;; esac eval "exec $eval" diff --git a/git-request-pull.sh b/git-request-pull.sh index 6fdea397dd..fc080cc5e4 100755 --- a/git-request-pull.sh +++ b/git-request-pull.sh @@ -15,7 +15,6 @@ p show patch text as well ' . git-sh-setup -. git-parse-remote GIT_PAGER= export GIT_PAGER @@ -55,7 +54,7 @@ branch=$(git ls-remote "$url" \ p q }") -url=$(get_remote_url "$url") +url=$(git ls-remote --get-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 @@ -177,24 +177,24 @@ static int handle_alias(int *argcp, const char ***argv) alias_string = alias_lookup(alias_command); if (alias_string) { if (alias_string[0] == '!') { + const char **alias_argv; + int argc = *argcp, i; + commit_pager_choice(); - if (*argcp > 1) { - struct strbuf buf; - - strbuf_init(&buf, PATH_MAX); - strbuf_addstr(&buf, alias_string); - sq_quote_argv(&buf, (*argv) + 1, PATH_MAX); - free(alias_string); - alias_string = buf.buf; - } - trace_printf("trace: alias to shell cmd: %s => %s\n", - alias_command, alias_string + 1); - ret = system(alias_string + 1); - if (ret >= 0 && WIFEXITED(ret) && - WEXITSTATUS(ret) != 127) - exit(WEXITSTATUS(ret)); - die("Failed to run '%s' when expanding alias '%s'", - alias_string + 1, alias_command); + + /* build alias_argv */ + alias_argv = xmalloc(sizeof(*alias_argv) * (argc + 1)); + alias_argv[0] = alias_string + 1; + for (i = 1; i < argc; ++i) + alias_argv[i] = (*argv)[i]; + alias_argv[argc] = NULL; + + ret = run_command_v_opt(alias_argv, RUN_USING_SHELL); + if (ret >= 0) /* normal exit */ + exit(ret); + + die_errno("While expanding alias '%s': '%s'", + alias_command, alias_string + 1); } count = split_cmdline(alias_string, &new_argv); if (count < 0) @@ -313,7 +313,6 @@ static void handle_internal_command(int argc, const char **argv) const char *cmd = argv[0]; static struct cmd_struct commands[] = { { "add", cmd_add, RUN_SETUP | NEED_WORK_TREE }, - { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE }, { "annotate", cmd_annotate, RUN_SETUP }, { "apply", cmd_apply, RUN_SETUP_GENTLY }, { "archive", cmd_archive }, @@ -322,15 +321,15 @@ static void handle_internal_command(int argc, const char **argv) { "branch", cmd_branch, RUN_SETUP }, { "bundle", cmd_bundle, RUN_SETUP_GENTLY }, { "cat-file", cmd_cat_file, RUN_SETUP }, + { "check-attr", cmd_check_attr, RUN_SETUP }, + { "check-ref-format", cmd_check_ref_format }, { "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE }, { "checkout-index", cmd_checkout_index, RUN_SETUP | NEED_WORK_TREE}, - { "check-ref-format", cmd_check_ref_format }, - { "check-attr", cmd_check_attr, RUN_SETUP }, { "cherry", cmd_cherry, RUN_SETUP }, { "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE }, - { "clone", cmd_clone }, { "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE }, + { "clone", cmd_clone }, { "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE }, { "commit-tree", cmd_commit_tree, RUN_SETUP }, { "config", cmd_config, RUN_SETUP_GENTLY }, @@ -358,8 +357,8 @@ static void handle_internal_command(int argc, const char **argv) { "init-db", cmd_init_db }, { "log", cmd_log, RUN_SETUP }, { "ls-files", cmd_ls_files, RUN_SETUP }, - { "ls-tree", cmd_ls_tree, RUN_SETUP }, { "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY }, + { "ls-tree", cmd_ls_tree, RUN_SETUP }, { "mailinfo", cmd_mailinfo }, { "mailsplit", cmd_mailsplit }, { "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE }, @@ -379,6 +378,7 @@ static void handle_internal_command(int argc, const char **argv) { "notes", cmd_notes, RUN_SETUP }, { "pack-objects", cmd_pack_objects, RUN_SETUP }, { "pack-redundant", cmd_pack_redundant, RUN_SETUP }, + { "pack-refs", cmd_pack_refs, RUN_SETUP }, { "patch-id", cmd_patch_id }, { "peek-remote", cmd_ls_remote, RUN_SETUP_GENTLY }, { "pickaxe", cmd_blame, RUN_SETUP }, @@ -392,7 +392,7 @@ static void handle_internal_command(int argc, const char **argv) { "remote-ext", cmd_remote_ext }, { "remote-fd", cmd_remote_fd }, { "replace", cmd_replace, RUN_SETUP }, - { "repo-config", cmd_config, RUN_SETUP_GENTLY }, + { "repo-config", cmd_repo_config, RUN_SETUP_GENTLY }, { "rerere", cmd_rerere, RUN_SETUP }, { "reset", cmd_reset, RUN_SETUP }, { "rev-list", cmd_rev_list, RUN_SETUP }, @@ -401,8 +401,10 @@ static void handle_internal_command(int argc, const char **argv) { "rm", cmd_rm, RUN_SETUP }, { "send-pack", cmd_send_pack, RUN_SETUP }, { "shortlog", cmd_shortlog, RUN_SETUP_GENTLY | USE_PAGER }, - { "show-branch", cmd_show_branch, RUN_SETUP }, { "show", cmd_show, RUN_SETUP }, + { "show-branch", cmd_show_branch, RUN_SETUP }, + { "show-ref", cmd_show_ref, RUN_SETUP }, + { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE }, { "status", cmd_status, RUN_SETUP | NEED_WORK_TREE }, { "stripspace", cmd_stripspace }, { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP }, @@ -415,13 +417,11 @@ static void handle_internal_command(int argc, const char **argv) { "update-server-info", cmd_update_server_info, RUN_SETUP }, { "upload-archive", cmd_upload_archive }, { "var", cmd_var, RUN_SETUP_GENTLY }, + { "verify-pack", cmd_verify_pack }, { "verify-tag", cmd_verify_tag, RUN_SETUP }, { "version", cmd_version }, { "whatchanged", cmd_whatchanged, RUN_SETUP }, { "write-tree", cmd_write_tree, RUN_SETUP }, - { "verify-pack", cmd_verify_pack }, - { "show-ref", cmd_show_ref, RUN_SETUP }, - { "pack-refs", cmd_pack_refs, RUN_SETUP }, }; int i; static const char ext[] = STRIP_EXTENSION; diff --git a/list-objects.c b/list-objects.c index 8953548c07..61f6cc98d9 100644 --- a/list-objects.c +++ b/list-objects.c @@ -61,12 +61,15 @@ static void process_tree(struct rev_info *revs, struct tree *tree, show_object_fn show, struct name_path *path, + struct strbuf *base, const char *name) { struct object *obj = &tree->object; struct tree_desc desc; struct name_entry entry; struct name_path me; + int all_interesting = (revs->diffopt.pathspec.nr == 0); + int baselen = base->len; if (!revs->tree_objects) return; @@ -82,13 +85,32 @@ static void process_tree(struct rev_info *revs, me.elem = name; me.elem_len = strlen(name); + if (!all_interesting) { + strbuf_addstr(base, name); + if (base->len) + strbuf_addch(base, '/'); + } + init_tree_desc(&desc, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { + if (!all_interesting) { + int showit = tree_entry_interesting(&entry, + base, 0, + &revs->diffopt.pathspec); + + if (showit < 0) + break; + else if (!showit) + continue; + else if (showit == 2) + all_interesting = 1; + } + if (S_ISDIR(entry.mode)) process_tree(revs, lookup_tree(entry.sha1), - show, &me, entry.path); + show, &me, base, entry.path); else if (S_ISGITLINK(entry.mode)) process_gitlink(revs, entry.sha1, show, &me, entry.path); @@ -97,6 +119,7 @@ static void process_tree(struct rev_info *revs, lookup_blob(entry.sha1), show, &me, entry.path); } + strbuf_setlen(base, baselen); free(tree->buffer); tree->buffer = NULL; } @@ -146,7 +169,9 @@ void traverse_commit_list(struct rev_info *revs, { int i; struct commit *commit; + struct strbuf base; + strbuf_init(&base, PATH_MAX); while ((commit = get_revision(revs)) != NULL) { add_pending_tree(revs, commit->tree); show_commit(commit, data); @@ -164,7 +189,7 @@ void traverse_commit_list(struct rev_info *revs, } if (obj->type == OBJ_TREE) { process_tree(revs, (struct tree *)obj, show_object, - NULL, name); + NULL, &base, name); continue; } if (obj->type == OBJ_BLOB) { @@ -181,4 +206,5 @@ void traverse_commit_list(struct rev_info *revs, revs->pending.alloc = 0; revs->pending.objects = NULL; } + strbuf_release(&base); } diff --git a/lockfile.c b/lockfile.c index b0d74cddde..c6fb77b26f 100644 --- a/lockfile.c +++ b/lockfile.c @@ -164,10 +164,10 @@ static char *unable_to_lock_message(const char *path, int err) "If no other git process is currently running, this probably means a\n" "git process crashed in this repository earlier. Make sure no other git\n" "process is running and remove the file manually to continue.", - make_nonrelative_path(path), strerror(err)); + absolute_path(path), strerror(err)); } else strbuf_addf(&buf, "Unable to create '%s.lock': %s", - make_nonrelative_path(path), strerror(err)); + absolute_path(path), strerror(err)); return strbuf_detach(&buf, NULL); } diff --git a/merge-recursive.c b/merge-recursive.c index 42d52cb5bc..8e82a8b1a5 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -22,6 +22,11 @@ #include "dir.h" #include "submodule.h" +static const char rename_limit_advice[] = +"inexact rename detection was skipped because there were too many\n" +" files. You may want to set your merge.renamelimit variable to at least\n" +" %d and retry this merge."; + static struct tree *shift_tree_object(struct tree *one, struct tree *two, const char *subtree_shift) { @@ -135,7 +140,6 @@ static void flush_output(struct merge_options *o) __attribute__((format (printf, 3, 4))) static void output(struct merge_options *o, int v, const char *fmt, ...) { - int len; va_list ap; if (!show(o, v)) @@ -146,21 +150,9 @@ static void output(struct merge_options *o, int v, const char *fmt, ...) strbuf_setlen(&o->obuf, o->obuf.len + o->call_depth * 2); va_start(ap, fmt); - len = vsnprintf(o->obuf.buf + o->obuf.len, strbuf_avail(&o->obuf), fmt, ap); + strbuf_vaddf(&o->obuf, fmt, ap); va_end(ap); - if (len < 0) - len = 0; - if (len >= strbuf_avail(&o->obuf)) { - strbuf_grow(&o->obuf, len + 2); - va_start(ap, fmt); - len = vsnprintf(o->obuf.buf + o->obuf.len, strbuf_avail(&o->obuf), fmt, ap); - va_end(ap); - if (len >= strbuf_avail(&o->obuf)) { - die("this should not happen, your snprintf is broken"); - } - } - strbuf_setlen(&o->obuf, o->obuf.len + len); strbuf_add(&o->obuf, "\n", 1); if (!o->buffer_output) flush_output(o); @@ -431,14 +423,16 @@ static struct string_list *get_renames(struct merge_options *o, opts.detect_rename = DIFF_DETECT_RENAME; opts.rename_limit = o->merge_rename_limit >= 0 ? o->merge_rename_limit : o->diff_rename_limit >= 0 ? o->diff_rename_limit : - 500; + 1000; opts.rename_score = o->rename_score; - opts.warn_on_too_large_rename = 1; + opts.show_rename_progress = o->show_rename_progress; opts.output_format = DIFF_FORMAT_NO_OUTPUT; if (diff_setup_done(&opts) < 0) die("diff setup failed"); diff_tree_sha1(o_tree->object.sha1, tree->object.sha1, "", &opts); diffcore_std(&opts); + if (opts.needed_rename_limit > o->needed_rename_limit) + o->needed_rename_limit = opts.needed_rename_limit; for (i = 0; i < diff_queued_diff.nr; ++i) { struct string_list_item *item; struct rename *re; @@ -1662,6 +1656,8 @@ int merge_recursive(struct merge_options *o, commit_list_insert(h2, &(*result)->parents->next); } flush_output(o); + if (o->needed_rename_limit) + warning(rename_limit_advice, o->needed_rename_limit); return clean; } diff --git a/merge-recursive.h b/merge-recursive.h index c8135b0ec7..7e1e972b13 100644 --- a/merge-recursive.h +++ b/merge-recursive.h @@ -20,6 +20,8 @@ struct merge_options { int diff_rename_limit; int merge_rename_limit; int rename_score; + int needed_rename_limit; + int show_rename_progress; int call_depth; struct strbuf obuf; struct string_list current_file_set; @@ -57,6 +59,8 @@ struct tree *write_tree_from_memory(struct merge_options *o); int parse_merge_opt(struct merge_options *out, const char *s); /* builtin/merge.c */ -int try_merge_command(const char *strategy, struct commit_list *common, const char *head_arg, struct commit_list *remotes); +int try_merge_command(const char *strategy, size_t xopts_nr, + const char **xopts, struct commit_list *common, + const char *head_arg, struct commit_list *remotes); #endif @@ -6,11 +6,6 @@ struct object_list { struct object_list *next; }; -struct object_refs { - unsigned count; - struct object *ref[FLEX_ARRAY]; /* more */ -}; - struct object_array { unsigned int nr; unsigned int alloc; @@ -397,7 +397,7 @@ int set_shared_perm(const char *path, int mode) return 0; } -const char *make_relative_path(const char *abs, const char *base) +const char *relative_path(const char *abs, const char *base) { static char buf[PATH_MAX + 1]; int i = 0, j = 0; diff --git a/pkt-line.c b/pkt-line.c index 295ba2b16c..cd1bd26413 100644 --- a/pkt-line.c +++ b/pkt-line.c @@ -1,6 +1,51 @@ #include "cache.h" #include "pkt-line.h" +const char *packet_trace_prefix = "git"; +static const char trace_key[] = "GIT_TRACE_PACKET"; + +void packet_trace_identity(const char *prog) +{ + packet_trace_prefix = xstrdup(prog); +} + +static void packet_trace(const char *buf, unsigned int len, int write) +{ + int i; + struct strbuf out; + + if (!trace_want(trace_key)) + return; + + /* +32 is just a guess for header + quoting */ + strbuf_init(&out, len+32); + + strbuf_addf(&out, "packet: %12s%c ", + packet_trace_prefix, write ? '>' : '<'); + + if ((len >= 4 && !prefixcmp(buf, "PACK")) || + (len >= 5 && !prefixcmp(buf+1, "PACK"))) { + strbuf_addstr(&out, "PACK ..."); + unsetenv(trace_key); + } + else { + /* XXX we should really handle printable utf8 */ + for (i = 0; i < len; i++) { + /* suppress newlines */ + if (buf[i] == '\n') + continue; + if (buf[i] >= 0x20 && buf[i] <= 0x7e) + strbuf_addch(&out, buf[i]); + else + strbuf_addf(&out, "\\%o", buf[i]); + } + } + + strbuf_addch(&out, '\n'); + trace_strbuf(trace_key, &out); + strbuf_release(&out); +} + /* * Write a packetized stream, where each line is preceded by * its length (including the header) as a 4-byte hex number. @@ -39,11 +84,13 @@ ssize_t safe_write(int fd, const void *buf, ssize_t n) */ void packet_flush(int fd) { + packet_trace("0000", 4, 1); safe_write(fd, "0000", 4); } void packet_buf_flush(struct strbuf *buf) { + packet_trace("0000", 4, 1); strbuf_add(buf, "0000", 4); } @@ -62,6 +109,7 @@ static unsigned format_packet(const char *fmt, va_list args) buffer[1] = hex(n >> 8); buffer[2] = hex(n >> 4); buffer[3] = hex(n); + packet_trace(buffer+4, n-4, 1); return n; } @@ -130,13 +178,16 @@ int packet_read_line(int fd, char *buffer, unsigned size) len = packet_length(linelen); if (len < 0) die("protocol error: bad line length character: %.4s", linelen); - if (!len) + if (!len) { + packet_trace("0000", 4, 0); return 0; + } len -= 4; if (len >= size) die("protocol error: bad line length %d", len); safe_read(fd, buffer, len); buffer[len] = 0; + packet_trace(buffer, len, 0); return len; } @@ -153,6 +204,7 @@ int packet_get_line(struct strbuf *out, if (!len) { *src_buf += 4; *src_len -= 4; + packet_trace("0000", 4, 0); return 0; } if (*src_len < len) @@ -165,5 +217,6 @@ int packet_get_line(struct strbuf *out, strbuf_add(out, *src_buf, len); *src_buf += len; *src_len -= len; + packet_trace(out->buf, out->len, 0); return len; } diff --git a/po/.gitignore b/po/.gitignore new file mode 100644 index 0000000000..a242a86e93 --- /dev/null +++ b/po/.gitignore @@ -0,0 +1 @@ +/git.pot diff --git a/preload-index.c b/preload-index.c index e3d0bda31a..49cb08df96 100644 --- a/preload-index.c +++ b/preload-index.c @@ -35,7 +35,9 @@ static void *preload_thread(void *_data) struct index_state *index = p->index; struct cache_entry **cep = index->cache + p->offset; struct cache_def cache; + struct pathspec pathspec; + init_pathspec(&pathspec, p->pathspec); memset(&cache, 0, sizeof(cache)); nr = p->nr; if (nr + p->offset > index->cache_nr) @@ -51,7 +53,7 @@ static void *preload_thread(void *_data) continue; if (ce_uptodate(ce)) continue; - if (!ce_path_match(ce, p->pathspec)) + if (!ce_path_match(ce, &pathspec)) continue; if (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce))) continue; @@ -61,6 +63,7 @@ static void *preload_thread(void *_data) continue; ce_mark_uptodate(ce); } while (--nr > 0); + free_pathspec(&pathspec); return NULL; } @@ -216,36 +216,53 @@ static int is_rfc2047_special(char ch) static void add_rfc2047(struct strbuf *sb, const char *line, int len, const char *encoding) { - int i, last; + static const int max_length = 78; /* per rfc2822 */ + int i; + int line_len; + + /* How many bytes are already used on the current line? */ + for (i = sb->len - 1; i >= 0; i--) + if (sb->buf[i] == '\n') + break; + line_len = sb->len - (i+1); for (i = 0; i < len; i++) { int ch = line[i]; - if (non_ascii(ch)) + if (non_ascii(ch) || ch == '\n') goto needquote; if ((i + 1 < len) && (ch == '=' && line[i+1] == '?')) goto needquote; } - strbuf_add(sb, line, len); + strbuf_add_wrapped_bytes(sb, line, len, 0, 1, max_length - line_len); return; needquote: strbuf_grow(sb, len * 3 + strlen(encoding) + 100); strbuf_addf(sb, "=?%s?q?", encoding); - for (i = last = 0; i < len; i++) { + line_len += strlen(encoding) + 5; /* 5 for =??q? */ + for (i = 0; i < len; i++) { unsigned ch = line[i] & 0xFF; + + if (line_len >= max_length - 2) { + strbuf_addf(sb, "?=\n =?%s?q?", encoding); + line_len = strlen(encoding) + 5 + 1; /* =??q? plus SP */ + } + /* * We encode ' ' using '=20' even though rfc2047 * allows using '_' for readability. Unfortunately, * many programs do not understand this and just * leave the underscore in place. */ - if (is_rfc2047_special(ch) || ch == ' ') { - strbuf_add(sb, line + last, i - last); + if (is_rfc2047_special(ch) || ch == ' ' || ch == '\n') { strbuf_addf(sb, "=%02X", ch); - last = i + 1; + line_len += 3; + } + else { + strbuf_addch(sb, ch); + line_len++; } } - strbuf_add(sb, line + last, len - last); strbuf_addstr(sb, "?="); } @@ -1106,11 +1123,10 @@ void pp_title_line(enum cmit_fmt fmt, const char *encoding, int need_8bit_cte) { - const char *line_separator = (fmt == CMIT_FMT_EMAIL) ? "\n " : " "; struct strbuf title; strbuf_init(&title, 80); - *msg_p = format_subject(&title, *msg_p, line_separator); + *msg_p = format_subject(&title, *msg_p, " "); strbuf_grow(sb, title.len + 1024); if (subject) { diff --git a/read-cache.c b/read-cache.c index 4f2e890b01..98d526bd48 100644 --- a/read-cache.c +++ b/read-cache.c @@ -92,7 +92,7 @@ static int ce_compare_data(struct cache_entry *ce, struct stat *st) if (fd >= 0) { unsigned char sha1[20]; - if (!index_fd(sha1, fd, st, 0, OBJ_BLOB, ce->name)) + if (!index_fd(sha1, fd, st, 0, OBJ_BLOB, ce->name, 0)) match = hashcmp(sha1, ce->sha1); /* index_fd() closed the file descriptor already */ } @@ -706,30 +706,9 @@ int ce_same_name(struct cache_entry *a, struct cache_entry *b) return ce_namelen(b) == len && !memcmp(a->name, b->name, len); } -int ce_path_match(const struct cache_entry *ce, const char **pathspec) +int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec) { - const char *match, *name; - int len; - - if (!pathspec) - return 1; - - len = ce_namelen(ce); - name = ce->name; - while ((match = *pathspec++) != NULL) { - int matchlen = strlen(match); - if (matchlen > len) - continue; - if (memcmp(name, match, matchlen)) - continue; - if (matchlen && name[matchlen-1] == '/') - return 1; - if (name[matchlen] == '/' || !name[matchlen]) - return 1; - if (!matchlen) - return 1; - } - return 0; + return match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL); } /* @@ -1104,7 +1083,7 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate, } static void show_file(const char * fmt, const char * name, int in_porcelain, - int * first, char *header_msg) + int * first, const char *header_msg) { if (in_porcelain && *first && header_msg) { printf("%s\n", header_msg); @@ -1114,7 +1093,7 @@ static void show_file(const char * fmt, const char * name, int in_porcelain, } int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec, - char *seen, char *header_msg) + char *seen, const char *header_msg) { int i; int has_errors = 0; diff --git a/remote-curl.c b/remote-curl.c index 04d4813e41..775d614303 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -356,14 +356,59 @@ static size_t rpc_in(const void *ptr, size_t eltsize, return size; } +static int run_slot(struct active_request_slot *slot) +{ + int err = 0; + struct slot_results results; + + slot->results = &results; + slot->curl_result = curl_easy_perform(slot->curl); + finish_active_slot(slot); + + if (results.curl_result != CURLE_OK) { + err |= error("RPC failed; result=%d, HTTP code = %ld", + results.curl_result, results.http_code); + } + + return err; +} + +static int probe_rpc(struct rpc_state *rpc) +{ + struct active_request_slot *slot; + struct curl_slist *headers = NULL; + struct strbuf buf = STRBUF_INIT; + int err; + + slot = get_active_slot(); + + headers = curl_slist_append(headers, rpc->hdr_content_type); + headers = curl_slist_append(headers, rpc->hdr_accept); + + curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0); + curl_easy_setopt(slot->curl, CURLOPT_POST, 1); + curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url); + curl_easy_setopt(slot->curl, CURLOPT_ENCODING, ""); + curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, "0000"); + curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, 4); + curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); + curl_easy_setopt(slot->curl, CURLOPT_FILE, &buf); + + err = run_slot(slot); + + curl_slist_free_all(headers); + strbuf_release(&buf); + return err; +} + static int post_rpc(struct rpc_state *rpc) { struct active_request_slot *slot; - struct slot_results results; struct curl_slist *headers = NULL; int use_gzip = rpc->gzip_request; char *gzip_body = NULL; - int err = 0, large_request = 0; + int err, large_request = 0; /* Try to load the entire request, if we can fit it into the * allocated buffer space we can use HTTP/1.0 and avoid the @@ -386,8 +431,13 @@ static int post_rpc(struct rpc_state *rpc) rpc->len += n; } + if (large_request) { + err = probe_rpc(rpc); + if (err) + return err; + } + slot = get_active_slot(); - slot->results = &results; curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0); curl_easy_setopt(slot->curl, CURLOPT_POST, 1); @@ -396,12 +446,12 @@ static int post_rpc(struct rpc_state *rpc) headers = curl_slist_append(headers, rpc->hdr_content_type); headers = curl_slist_append(headers, rpc->hdr_accept); + headers = curl_slist_append(headers, "Expect:"); if (large_request) { /* The request body is large and the size cannot be predicted. * We must use chunked encoding to send it. */ - headers = curl_slist_append(headers, "Expect: 100-continue"); headers = curl_slist_append(headers, "Transfer-Encoding: chunked"); rpc->initial_buffer = 1; curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, rpc_out); @@ -475,13 +525,7 @@ static int post_rpc(struct rpc_state *rpc) curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, rpc_in); curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc); - slot->curl_result = curl_easy_perform(slot->curl); - finish_active_slot(slot); - - if (results.curl_result != CURLE_OK) { - err |= error("RPC failed; result=%d, HTTP code = %ld", - results.curl_result, results.http_code); - } + err = run_slot(slot); curl_slist_free_all(headers); free(gzip_body); @@ -7,6 +7,11 @@ #include "ll-merge.h" #include "attr.h" +#define RESOLVED 0 +#define PUNTED 1 +#define THREE_STAGED 2 +void *RERERE_RESOLVED = &RERERE_RESOLVED; + /* if rerere_enabled == -1, fall back to detection of .git/rr-cache */ static int rerere_enabled = -1; @@ -345,21 +350,74 @@ static int handle_cache(const char *path, unsigned char *sha1, const char *outpu return hunk_no; } -static int find_conflict(struct string_list *conflict) +static int check_one_conflict(int i, int *type) { - int i; - if (read_cache() < 0) - return error("Could not read index"); - for (i = 0; i+1 < active_nr; i++) { + struct cache_entry *e = active_cache[i]; + + if (!ce_stage(e)) { + *type = RESOLVED; + return i + 1; + } + + *type = PUNTED; + if (ce_stage(e) == 1) { + if (active_nr <= ++i) + return i + 1; + } + + /* Only handle regular files with both stages #2 and #3 */ + if (i + 1 < active_nr) { struct cache_entry *e2 = active_cache[i]; - struct cache_entry *e3 = active_cache[i+1]; + struct cache_entry *e3 = active_cache[i + 1]; if (ce_stage(e2) == 2 && ce_stage(e3) == 3 && - ce_same_name(e2, e3) && + ce_same_name(e, e3) && S_ISREG(e2->ce_mode) && - S_ISREG(e3->ce_mode)) { - string_list_insert(conflict, (const char *)e2->name); - i++; /* skip over both #2 and #3 */ + S_ISREG(e3->ce_mode)) + *type = THREE_STAGED; + } + + /* Skip the entries with the same name */ + while (i < active_nr && ce_same_name(e, active_cache[i])) + i++; + return i; +} + +static int find_conflict(struct string_list *conflict) +{ + int i; + if (read_cache() < 0) + return error("Could not read index"); + + for (i = 0; i < active_nr;) { + int conflict_type; + struct cache_entry *e = active_cache[i]; + i = check_one_conflict(i, &conflict_type); + if (conflict_type == THREE_STAGED) + string_list_insert(conflict, (const char *)e->name); + } + return 0; +} + +int rerere_remaining(struct string_list *merge_rr) +{ + int i; + if (read_cache() < 0) + return error("Could not read index"); + + for (i = 0; i < active_nr;) { + int conflict_type; + struct cache_entry *e = active_cache[i]; + i = check_one_conflict(i, &conflict_type); + if (conflict_type == PUNTED) + string_list_insert(merge_rr, (const char *)e->name); + else if (conflict_type == RESOLVED) { + struct string_list_item *it; + it = string_list_lookup(merge_rr, (const char *)e->name); + if (it != NULL) { + free(it->util); + it->util = RERERE_RESOLVED; + } } } return 0; @@ -6,11 +6,19 @@ #define RERERE_AUTOUPDATE 01 #define RERERE_NOAUTOUPDATE 02 +/* + * Marks paths that have been hand-resolved and added to the + * index. Set in the util field of such paths after calling + * rerere_remaining. + */ +extern void *RERERE_RESOLVED; + extern int setup_rerere(struct string_list *, int); extern int rerere(int); extern const char *rerere_path(const char *hex, const char *file); extern int has_rerere_resolution(const char *hex); extern int rerere_forget(const char **); +extern int rerere_remaining(struct string_list *); #define OPT_RERERE_AUTOUPDATE(v) OPT_UYN(0, "rerere-autoupdate", (v), \ "update the index with reused conflict resolution if possible") diff --git a/revision.c b/revision.c index 7b9eaefae4..86d2470489 100644 --- a/revision.c +++ b/revision.c @@ -323,7 +323,7 @@ static int rev_compare_tree(struct rev_info *revs, struct commit *parent, struct * tagged commit by specifying both --simplify-by-decoration * and pathspec. */ - if (!revs->prune_data) + if (!revs->prune_data.nr) return REV_TREE_SAME; } @@ -553,11 +553,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs) left_first = left_count < right_count; init_patch_ids(&ids); - if (revs->diffopt.nr_paths) { - ids.diffopts.nr_paths = revs->diffopt.nr_paths; - ids.diffopts.paths = revs->diffopt.paths; - ids.diffopts.pathlens = revs->diffopt.pathlens; - } + ids.diffopts.pathspec = revs->diffopt.pathspec; /* Compute patch-ids for one side */ for (p = list; p; p = p->next) { @@ -973,7 +969,7 @@ static void prepare_show_merge(struct rev_info *revs) struct cache_entry *ce = active_cache[i]; if (!ce_stage(ce)) continue; - if (ce_path_match(ce, revs->prune_data)) { + if (ce_path_match(ce, &revs->prune_data)) { prune_num++; prune = xrealloc(prune, sizeof(*prune) * prune_num); prune[prune_num-2] = ce->name; @@ -983,7 +979,8 @@ static void prepare_show_merge(struct rev_info *revs) ce_same_name(ce, active_cache[i+1])) i++; } - revs->prune_data = prune; + free_pathspec(&revs->prune_data); + init_pathspec(&revs->prune_data, prune); revs->limited = 1; } @@ -1620,7 +1617,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s } if (prune_data) - revs->prune_data = get_pathspec(revs->prefix, prune_data); + init_pathspec(&revs->prune_data, get_pathspec(revs->prefix, prune_data)); if (revs->def == NULL) revs->def = opt ? opt->def : NULL; @@ -1651,13 +1648,13 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s if (revs->topo_order) revs->limited = 1; - if (revs->prune_data) { - diff_tree_setup_paths(revs->prune_data, &revs->pruning); + if (revs->prune_data.nr) { + diff_tree_setup_paths(revs->prune_data.raw, &revs->pruning); /* Can't prune commits with rename following: the paths change.. */ if (!DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES)) revs->prune = 1; if (!revs->full_diff) - diff_tree_setup_paths(revs->prune_data, &revs->diffopt); + diff_tree_setup_paths(revs->prune_data.raw, &revs->diffopt); } if (revs->combine_merges) revs->ignore_merges = 0; diff --git a/revision.h b/revision.h index 05659c64ac..82509dd1d9 100644 --- a/revision.h +++ b/revision.h @@ -34,7 +34,7 @@ struct rev_info { /* Basic information */ const char *prefix; const char *def; - void *prune_data; + struct pathspec prune_data; unsigned int early_output; /* Traversal flags */ @@ -7,10 +7,13 @@ static int inside_work_tree = -1; char *prefix_path(const char *prefix, int len, const char *path) { const char *orig = path; - char *sanitized = xmalloc(len + strlen(path) + 1); - if (is_absolute_path(orig)) - strcpy(sanitized, path); - else { + char *sanitized; + if (is_absolute_path(orig)) { + const char *temp = real_path(path); + sanitized = xmalloc(len + strlen(temp) + 1); + strcpy(sanitized, temp); + } else { + sanitized = xmalloc(len + strlen(path) + 1); if (len) memcpy(sanitized, prefix, len); strcpy(sanitized + len, path); @@ -218,7 +221,7 @@ void setup_work_tree(void) work_tree = get_git_work_tree(); git_dir = get_git_dir(); if (!is_absolute_path(git_dir)) - git_dir = make_absolute_path(git_dir); + git_dir = real_path(get_git_dir()); if (!work_tree || chdir(work_tree)) die("This operation must be run in a work tree"); @@ -229,7 +232,7 @@ void setup_work_tree(void) if (getenv(GIT_WORK_TREE_ENVIRONMENT)) setenv(GIT_WORK_TREE_ENVIRONMENT, ".", 1); - set_git_dir(make_relative_path(git_dir, work_tree)); + set_git_dir(relative_path(git_dir, work_tree)); initialized = 1; } @@ -309,7 +312,7 @@ const char *read_gitfile_gently(const char *path) if (!is_git_directory(dir)) die("Not a git repository: %s", dir); - path = make_absolute_path(dir); + path = real_path(dir); free(buf); return path; @@ -389,7 +392,7 @@ static const char *setup_explicit_git_dir(const char *gitdirenv, if (!prefixcmp(cwd, worktree) && cwd[strlen(worktree)] == '/') { /* cwd inside worktree */ - set_git_dir(make_absolute_path(gitdirenv)); + set_git_dir(real_path(gitdirenv)); if (chdir(worktree)) die_errno("Could not chdir to '%s'", worktree); cwd[len++] = '/'; @@ -414,7 +417,7 @@ static const char *setup_discovered_git_dir(const char *gitdir, /* --work-tree is set without --git-dir; use discovered one */ if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) { if (offset != len && !is_absolute_path(gitdir)) - gitdir = xstrdup(make_absolute_path(gitdir)); + gitdir = xstrdup(real_path(gitdir)); if (chdir(cwd)) die_errno("Could not come back to cwd"); return setup_explicit_git_dir(gitdir, cwd, len, nongit_ok); @@ -422,7 +425,7 @@ static const char *setup_discovered_git_dir(const char *gitdir, /* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */ if (is_bare_repository_cfg > 0) { - set_git_dir(offset == len ? gitdir : make_absolute_path(gitdir)); + set_git_dir(offset == len ? gitdir : real_path(gitdir)); if (chdir(cwd)) die_errno("Could not come back to cwd"); return NULL; diff --git a/sha1_file.c b/sha1_file.c index e194f6a128..b4fcca8ffd 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -13,6 +13,7 @@ #include "commit.h" #include "tag.h" #include "tree.h" +#include "tree-walk.h" #include "refs.h" #include "pack-revindex.h" #include "sha1-lookup.h" @@ -2527,8 +2528,37 @@ int has_sha1_file(const unsigned char *sha1) return has_loose_object(sha1); } +static void check_tree(const void *buf, size_t size) +{ + struct tree_desc desc; + struct name_entry entry; + + init_tree_desc(&desc, buf, size); + while (tree_entry(&desc, &entry)) + /* do nothing + * tree_entry() will die() on malformed entries */ + ; +} + +static void check_commit(const void *buf, size_t size) +{ + struct commit c; + memset(&c, 0, sizeof(c)); + if (parse_commit_buffer(&c, buf, size)) + die("corrupt commit"); +} + +static void check_tag(const void *buf, size_t size) +{ + struct tag t; + memset(&t, 0, sizeof(t)); + if (parse_tag_buffer(&t, buf, size)) + die("corrupt tag"); +} + static int index_mem(unsigned char *sha1, void *buf, size_t size, - int write_object, enum object_type type, const char *path) + int write_object, enum object_type type, + const char *path, int format_check) { int ret, re_allocated = 0; @@ -2546,6 +2576,14 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size, re_allocated = 1; } } + if (format_check) { + if (type == OBJ_TREE) + check_tree(buf, size); + if (type == OBJ_COMMIT) + check_commit(buf, size); + if (type == OBJ_TAG) + check_tag(buf, size); + } if (write_object) ret = write_sha1_file(buf, size, typename(type), sha1); @@ -2559,7 +2597,7 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size, #define SMALL_FILE_SIZE (32*1024) int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, - enum object_type type, const char *path) + enum object_type type, const char *path, int format_check) { int ret; size_t size = xsize_t(st->st_size); @@ -2568,23 +2606,25 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, struct strbuf sbuf = STRBUF_INIT; if (strbuf_read(&sbuf, fd, 4096) >= 0) ret = index_mem(sha1, sbuf.buf, sbuf.len, write_object, - type, path); + type, path, format_check); else ret = -1; strbuf_release(&sbuf); } else if (!size) { - ret = index_mem(sha1, NULL, size, write_object, type, path); + ret = index_mem(sha1, NULL, size, write_object, type, path, + format_check); } else if (size <= SMALL_FILE_SIZE) { char *buf = xmalloc(size); if (size == read_in_full(fd, buf, size)) ret = index_mem(sha1, buf, size, write_object, type, - path); + path, format_check); else ret = error("short read %s", strerror(errno)); free(buf); } else { void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - ret = index_mem(sha1, buf, size, write_object, type, path); + ret = index_mem(sha1, buf, size, write_object, type, path, + format_check); munmap(buf, size); } close(fd); @@ -2602,7 +2642,7 @@ int index_path(unsigned char *sha1, const char *path, struct stat *st, int write if (fd < 0) return error("open(\"%s\"): %s", path, strerror(errno)); - if (index_fd(sha1, fd, st, write_object, OBJ_BLOB, path) < 0) + if (index_fd(sha1, fd, st, write_object, OBJ_BLOB, path, 0) < 0) return error("%s: failed to insert into database", path); break; @@ -195,24 +195,29 @@ void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len) void strbuf_addf(struct strbuf *sb, const char *fmt, ...) { - int len; va_list ap; + va_start(ap, fmt); + strbuf_vaddf(sb, fmt, ap); + va_end(ap); +} + +void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap) +{ + int len; + va_list cp; if (!strbuf_avail(sb)) strbuf_grow(sb, 64); - va_start(ap, fmt); - len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); - va_end(ap); + va_copy(cp, ap); + len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, cp); + va_end(cp); if (len < 0) - die("your vsnprintf is broken"); + die("BUG: your vsnprintf is broken (returned %d)", len); if (len > strbuf_avail(sb)) { strbuf_grow(sb, len); - va_start(ap, fmt); len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); - va_end(ap); - if (len > strbuf_avail(sb)) { - die("this should not happen, your snprintf is broken"); - } + if (len > strbuf_avail(sb)) + die("BUG: your vsnprintf is broken (insatiable)"); } strbuf_setlen(sb, sb->len + len); } @@ -120,6 +120,8 @@ extern void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf * __attribute__((format (printf,2,3))) extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...); +__attribute__((format (printf,2,0))) +extern void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap); extern size_t strbuf_fread(struct strbuf *, size_t, FILE *); /* XXX: if read fails, any partial read is undone */ diff --git a/symlinks.c b/symlinks.c index 3cacebd91a..034943bda0 100644 --- a/symlinks.c +++ b/symlinks.c @@ -223,7 +223,7 @@ int check_leading_path(const char *name, int len) int flags; int match_len = lstat_cache_matchlen(cache, name, len, &flags, FL_SYMLINK|FL_NOENT|FL_DIR, USE_ONLY_LSTAT); - if (flags & (FL_SYMLINK|FL_NOENT)) + if (flags & FL_NOENT) return 0; else if (flags & FL_DIR) return -1; @@ -79,6 +79,10 @@ appropriately before running "make". --debug:: This may help the person who is developing a new test. It causes the command defined with test_debug to run. + The "trash" directory (used to store all temporary data + during testing) is not deleted even if there are no + failed tests so that you can inspect its contents after + the test finished. --immediate:: This causes the test to immediately exit upon the first diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 8deec75c3a..f4e8f43bae 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -435,7 +435,7 @@ test_expect_success 'update-index D/F conflict' ' test $numpath0 = 1 ' -test_expect_success SYMLINKS 'absolute path works as expected' ' +test_expect_success SYMLINKS 'real path works as expected' ' mkdir first && ln -s ../.git first/.git && mkdir second && @@ -443,14 +443,14 @@ test_expect_success SYMLINKS 'absolute path works as expected' ' mkdir third && dir="$(cd .git; pwd -P)" && dir2=third/../second/other/.git && - test "$dir" = "$(test-path-utils make_absolute_path $dir2)" && + test "$dir" = "$(test-path-utils real_path $dir2)" && file="$dir"/index && - test "$file" = "$(test-path-utils make_absolute_path $dir2/index)" && + test "$file" = "$(test-path-utils real_path $dir2/index)" && basename=blub && - test "$dir/$basename" = "$(cd .git && test-path-utils make_absolute_path "$basename")" && + test "$dir/$basename" = "$(cd .git && test-path-utils real_path "$basename")" && ln -s ../first/file .git/syml && sym="$(cd first; pwd -P)"/file && - test "$sym" = "$(test-path-utils make_absolute_path "$dir2/syml")" + test "$sym" = "$(test-path-utils real_path "$dir2/syml")" ' test_expect_success 'very long name in the index handled sanely' ' diff --git a/t/t0080-vcs-svn.sh b/t/t0080-vcs-svn.sh index d3225ada68..99a314b080 100755 --- a/t/t0080-vcs-svn.sh +++ b/t/t0080-vcs-svn.sh @@ -76,60 +76,6 @@ test_expect_success 'obj pool: high-water mark' ' test_cmp expected actual ' -test_expect_success 'line buffer' ' - echo HELLO >expected1 && - printf "%s\n" "" HELLO >expected2 && - echo >expected3 && - printf "%s\n" "" Q | q_to_nul >expected4 && - printf "%s\n" foo "" >expected5 && - printf "%s\n" "" foo >expected6 && - - test-line-buffer <<-\EOF >actual1 && - 5 - HELLO - EOF - - test-line-buffer <<-\EOF >actual2 && - 0 - - 5 - HELLO - EOF - - q_to_nul <<-\EOF | - 1 - Q - EOF - test-line-buffer >actual3 && - - q_to_nul <<-\EOF | - 0 - - 1 - Q - EOF - test-line-buffer >actual4 && - - test-line-buffer <<-\EOF >actual5 && - 5 - foo - EOF - - test-line-buffer <<-\EOF >actual6 && - 0 - - 5 - foo - EOF - - test_cmp expected1 actual1 && - test_cmp expected2 actual2 && - test_cmp expected3 actual3 && - test_cmp expected4 actual4 && - test_cmp expected5 actual5 && - test_cmp expected6 actual6 -' - test_expect_success 'string pool' ' echo a does not equal b >expected.differ && echo a equals a >expected.match && diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh new file mode 100755 index 0000000000..550fad0823 --- /dev/null +++ b/t/t0081-line-buffer.sh @@ -0,0 +1,201 @@ +#!/bin/sh + +test_description="Test the svn importer's input handling routines. + +These tests exercise the line_buffer library, but their real purpose +is to check the assumptions that library makes of the platform's input +routines. Processes engaged in bi-directional communication would +hang if fread or fgets is too greedy. + +While at it, check that input of newlines and null bytes are handled +correctly. +" +. ./test-lib.sh + +test -n "$GIT_REMOTE_SVN_TEST_BIG_FILES" && test_set_prereq EXPENSIVE + +generate_tens_of_lines () { + tens=$1 && + line=$2 && + + i=0 && + while test $i -lt "$tens" + do + for j in a b c d e f g h i j + do + echo "$line" + done && + : $((i = $i + 1)) || + return + done +} + +long_read_test () { + : each line is 10 bytes, including newline && + line=abcdefghi && + echo "$line" >expect && + + if ! test_declared_prereq PIPE + then + echo >&4 "long_read_test: need to declare PIPE prerequisite" + return 127 + fi && + tens_of_lines=$(($1 / 100 + 1)) && + lines=$(($tens_of_lines * 10)) && + readsize=$((($lines - 1) * 10 + 3)) && + copysize=7 && + rm -f input && + mkfifo input && + { + { + generate_tens_of_lines $tens_of_lines "$line" && + sleep 100 + } >input & + } && + test-line-buffer input <<-EOF >output && + read $readsize + copy $copysize + EOF + kill $! && + test_line_count = $lines output && + tail -n 1 <output >actual && + test_cmp expect actual +} + +test_expect_success 'setup: have pipes?' ' + rm -f frob && + if mkfifo frob + then + test_set_prereq PIPE + fi +' + +test_expect_success 'hello world' ' + echo HELLO >expect && + test-line-buffer <<-\EOF >actual && + read 6 + HELLO + EOF + test_cmp expect actual +' + +test_expect_success PIPE '0-length read, no input available' ' + >expect && + rm -f input && + mkfifo input && + { + sleep 100 >input & + } && + test-line-buffer input <<-\EOF >actual && + read 0 + copy 0 + EOF + kill $! && + test_cmp expect actual +' + +test_expect_success '0-length read, send along greeting' ' + echo HELLO >expect && + test-line-buffer <<-\EOF >actual && + read 0 + copy 6 + HELLO + EOF + test_cmp expect actual +' + +test_expect_success PIPE '1-byte read, no input available' ' + printf "%s" ab >expect && + rm -f input && + mkfifo input && + { + { + printf "%s" a && + printf "%s" b && + sleep 100 + } >input & + } && + test-line-buffer input <<-\EOF >actual && + read 1 + copy 1 + EOF + kill $! && + test_cmp expect actual +' + +test_expect_success PIPE 'long read (around 8192 bytes)' ' + long_read_test 8192 +' + +test_expect_success PIPE,EXPENSIVE 'longer read (around 65536 bytes)' ' + long_read_test 65536 +' + +test_expect_success 'read from file descriptor' ' + rm -f input && + echo hello >expect && + echo hello >input && + echo copy 6 | + test-line-buffer "&4" 4<input >actual && + test_cmp expect actual +' + +test_expect_success 'buffer_read_string copes with null byte' ' + >expect && + q_to_nul <<-\EOF | test-line-buffer >actual && + read 2 + Q + EOF + test_cmp expect actual +' + +test_expect_success 'skip, copy null byte' ' + echo Q | q_to_nul >expect && + q_to_nul <<-\EOF | test-line-buffer >actual && + skip 2 + Q + copy 2 + Q + EOF + test_cmp expect actual +' + +test_expect_success 'read null byte' ' + echo ">QhelloQ" | q_to_nul >expect && + q_to_nul <<-\EOF | test-line-buffer >actual && + binary 8 + QhelloQ + EOF + test_cmp expect actual +' + +test_expect_success 'long reads are truncated' ' + echo foo >expect && + test-line-buffer <<-\EOF >actual && + read 5 + foo + EOF + test_cmp expect actual +' + +test_expect_success 'long copies are truncated' ' + printf "%s\n" "" foo >expect && + test-line-buffer <<-\EOF >actual && + read 1 + + copy 5 + foo + EOF + test_cmp expect actual +' + +test_expect_success 'long binary reads are truncated' ' + echo ">foo" >expect && + test-line-buffer <<-\EOF >actual && + binary 5 + foo + EOF + test_cmp expect actual +' + +test_done diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh index dd32432d62..6d52b824b1 100755 --- a/t/t1007-hash-object.sh +++ b/t/t1007-hash-object.sh @@ -188,4 +188,17 @@ for args in "-w --stdin-paths" "--stdin-paths -w"; do pop_repo done +test_expect_success 'corrupt tree' ' + echo abc >malformed-tree + test_must_fail git hash-object -t tree malformed-tree +' + +test_expect_success 'corrupt commit' ' + test_must_fail git hash-object -t commit --stdin </dev/null +' + +test_expect_success 'corrupt tag' ' + test_must_fail git hash-object -t tag --stdin </dev/null +' + test_done diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index d0e55465ff..53fb8228cf 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -876,11 +876,25 @@ test_expect_success 'check split_cmdline return' " " test_expect_success 'git -c "key=value" support' ' - test "z$(git -c name=value config name)" = zvalue && test "z$(git -c core.name=value config core.name)" = zvalue && - test "z$(git -c CamelCase=value config camelcase)" = zvalue && - test "z$(git -c flag config --bool flag)" = ztrue && - test_must_fail git -c core.name=value config name + test "z$(git -c foo.CamelCase=value config foo.camelcase)" = zvalue && + test "z$(git -c foo.flag config --bool foo.flag)" = ztrue && + test_must_fail git -c name=value config core.name +' + +test_expect_success 'key sanity-checking' ' + test_must_fail git config foo=bar && + test_must_fail git config foo=.bar && + test_must_fail git config foo.ba=r && + test_must_fail git config foo.1bar && + test_must_fail git config foo."ba + z".bar && + test_must_fail git config . false && + test_must_fail git config .foo false && + test_must_fail git config foo. false && + test_must_fail git config .foo. false && + git config foo.bar true && + git config foo."ba =z".bar false ' test_done diff --git a/t/t1510-repo-setup.sh b/t/t1510-repo-setup.sh index 15101d5e03..ec50a9ad70 100755 --- a/t/t1510-repo-setup.sh +++ b/t/t1510-repo-setup.sh @@ -57,7 +57,7 @@ test_repo () { export GIT_WORK_TREE fi && rm -f trace && - GIT_TRACE="$(pwd)/trace" git symbolic-ref HEAD >/dev/null && + GIT_TRACE_SETUP="$(pwd)/trace" git symbolic-ref HEAD >/dev/null && grep '^setup: ' trace >result && test_cmp expected result ) diff --git a/t/t2019-checkout-ambiguous-ref.sh b/t/t2019-checkout-ambiguous-ref.sh new file mode 100755 index 0000000000..943541d40d --- /dev/null +++ b/t/t2019-checkout-ambiguous-ref.sh @@ -0,0 +1,59 @@ +#!/bin/sh + +test_description='checkout handling of ambiguous (branch/tag) refs' +. ./test-lib.sh + +test_expect_success 'setup ambiguous refs' ' + test_commit branch file && + git branch ambiguity && + git branch vagueness && + test_commit tag file && + git tag ambiguity && + git tag vagueness HEAD:file && + test_commit other file +' + +test_expect_success 'checkout ambiguous ref succeeds' ' + git checkout ambiguity >stdout 2>stderr +' + +test_expect_success 'checkout produces ambiguity warning' ' + grep "warning.*ambiguous" stderr +' + +test_expect_success 'checkout chooses branch over tag' ' + echo refs/heads/ambiguity >expect && + git symbolic-ref HEAD >actual && + test_cmp expect actual && + echo branch >expect && + test_cmp expect file +' + +test_expect_success 'checkout reports switch to branch' ' + grep "Switched to branch" stderr && + ! grep "^HEAD is now at" stderr +' + +test_expect_success 'checkout vague ref succeeds' ' + git checkout vagueness >stdout 2>stderr && + test_set_prereq VAGUENESS_SUCCESS +' + +test_expect_success VAGUENESS_SUCCESS 'checkout produces ambiguity warning' ' + grep "warning.*ambiguous" stderr +' + +test_expect_success VAGUENESS_SUCCESS 'checkout chooses branch over tag' ' + echo refs/heads/vagueness >expect && + git symbolic-ref HEAD >actual && + test_cmp expect actual && + echo branch >expect && + test_cmp expect file +' + +test_expect_success VAGUENESS_SUCCESS 'checkout reports switch to branch' ' + grep "Switched to branch" stderr && + ! grep "^HEAD is now at" stderr +' + +test_done diff --git a/t/t2020-checkout-detach.sh b/t/t2020-checkout-detach.sh new file mode 100755 index 0000000000..00421453ba --- /dev/null +++ b/t/t2020-checkout-detach.sh @@ -0,0 +1,95 @@ +#!/bin/sh + +test_description='checkout into detached HEAD state' +. ./test-lib.sh + +check_detached () { + test_must_fail git symbolic-ref -q HEAD >/dev/null +} + +check_not_detached () { + git symbolic-ref -q HEAD >/dev/null +} + +reset () { + git checkout master && + check_not_detached +} + +test_expect_success 'setup' ' + test_commit one && + test_commit two && + git branch branch && + git tag tag +' + +test_expect_success 'checkout branch does not detach' ' + reset && + git checkout branch && + check_not_detached +' + +test_expect_success 'checkout tag detaches' ' + reset && + git checkout tag && + check_detached +' + +test_expect_success 'checkout branch by full name detaches' ' + reset && + git checkout refs/heads/branch && + check_detached +' + +test_expect_success 'checkout non-ref detaches' ' + reset && + git checkout branch^ && + check_detached +' + +test_expect_success 'checkout ref^0 detaches' ' + reset && + git checkout branch^0 && + check_detached +' + +test_expect_success 'checkout --detach detaches' ' + reset && + git checkout --detach branch && + check_detached +' + +test_expect_success 'checkout --detach without branch name' ' + reset && + git checkout --detach && + check_detached +' + +test_expect_success 'checkout --detach errors out for non-commit' ' + reset && + test_must_fail git checkout --detach one^{tree} && + check_not_detached +' + +test_expect_success 'checkout --detach errors out for extra argument' ' + reset && + git checkout master && + test_must_fail git checkout --detach tag one.t && + check_not_detached +' + +test_expect_success 'checkout --detached and -b are incompatible' ' + reset && + test_must_fail git checkout --detach -b newbranch tag && + check_not_detached +' + +test_expect_success 'checkout --detach moves HEAD' ' + reset && + git checkout one && + git checkout --detach two && + git diff --exit-code HEAD && + git diff --exit-code two +' + +test_done diff --git a/t/t2021-checkout-overwrite.sh b/t/t2021-checkout-overwrite.sh new file mode 100755 index 0000000000..27db2ad529 --- /dev/null +++ b/t/t2021-checkout-overwrite.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +test_description='checkout must not overwrite an untracked objects' +. ./test-lib.sh + +test_expect_success 'setup' ' + + mkdir -p a/b/c && + >a/b/c/d && + git add -A && + git commit -m base && + git tag start +' + +test_expect_success 'create a commit where dir a/b changed to file' ' + + git checkout -b file && + rm -rf a/b && + >a/b && + git add -A && + git commit -m "dir to file" +' + +test_expect_success 'checkout commit with dir must not remove untracked a/b' ' + + git rm --cached a/b && + git commit -m "un-track the file" && + test_must_fail git checkout start && + test -f a/b +' + +test_expect_success SYMLINKS 'create a commit where dir a/b changed to symlink' ' + + rm -rf a/b && # cleanup if previous test failed + git checkout -f -b symlink start && + rm -rf a/b && + ln -s foo a/b && + git add -A && + git commit -m "dir to symlink" +' + +test_expect_failure SYMLINKS 'checkout commit with dir must not remove untracked a/b' ' + + git rm --cached a/b && + git commit -m "un-track the symlink" && + test_must_fail git checkout start && + test -h a/b +' + +test_done diff --git a/t/t3032-merge-recursive-options.sh b/t/t3032-merge-recursive-options.sh index 44f5421be4..2b17311cb0 100755 --- a/t/t3032-merge-recursive-options.sh +++ b/t/t3032-merge-recursive-options.sh @@ -110,6 +110,20 @@ test_expect_success '--ignore-space-change makes merge succeed' ' git merge-recursive --ignore-space-change HEAD^ -- HEAD remote ' +test_expect_success 'naive cherry-pick fails' ' + git read-tree --reset -u HEAD && + test_must_fail git cherry-pick --no-commit remote && + git read-tree --reset -u HEAD && + test_must_fail git cherry-pick remote && + test_must_fail git update-index --refresh && + grep "<<<<<<" text.txt +' + +test_expect_success '-Xignore-space-change makes cherry-pick succeed' ' + git read-tree --reset -u HEAD && + git cherry-pick --no-commit -Xignore-space-change remote +' + test_expect_success '--ignore-space-change: our w/s-only change wins' ' q_to_cr <<-\EOF >expected && justice and holiness and is the nurse of his age and theQ diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index f308235f5d..78ce09f9d7 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -223,6 +223,11 @@ test_expect_success \ 'branch from non-branch HEAD w/--track causes failure' \ 'test_must_fail git branch --track my10 HEAD^' +test_expect_success \ + 'branch from tag w/--track causes failure' \ + 'git tag foobar && + test_must_fail git branch --track my11 foobar' + # Keep this test last, as it changes the current branch cat >expect <<EOF 0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master @@ -488,6 +493,15 @@ test_expect_success 'autosetuprebase always on an untracked remote branch' ' test "z$(git config branch.myr20.rebase)" = z ' +test_expect_success 'autosetuprebase always on detached HEAD' ' + git config branch.autosetupmerge always && + test_when_finished git checkout master && + git checkout HEAD^0 && + git branch my11 && + test -z "$(git config branch.my11.remote)" && + test -z "$(git config branch.my11.merge)" +' + test_expect_success 'detect misconfigured autosetuprebase (bad value)' ' git config branch.autosetuprebase garbage && test_must_fail git branch diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh index 607bf25d8f..95741801b0 100755 --- a/t/t3507-cherry-pick-conflict.sh +++ b/t/t3507-cherry-pick-conflict.sh @@ -11,6 +11,18 @@ test_description='test cherry-pick and revert with conflicts . ./test-lib.sh +test_cmp_rev () { + git rev-parse --verify "$1" >expect.rev && + git rev-parse --verify "$2" >actual.rev && + test_cmp expect.rev actual.rev +} + +pristine_detach () { + git checkout -f "$1^0" && + git read-tree -u --reset HEAD && + git clean -d -f -f -q -x +} + test_expect_success setup ' echo unrelated >unrelated && @@ -23,13 +35,7 @@ test_expect_success setup ' ' test_expect_success 'failed cherry-pick does not advance HEAD' ' - - git checkout -f initial^0 && - git read-tree -u --reset HEAD && - git clean -d -f -f -q -x && - - git update-index --refresh && - git diff-index --exit-code HEAD && + pristine_detach initial && head=$(git rev-parse HEAD) && test_must_fail git cherry-pick picked && @@ -39,33 +45,96 @@ test_expect_success 'failed cherry-pick does not advance HEAD' ' ' test_expect_success 'advice from failed cherry-pick' " - git checkout -f initial^0 && - git read-tree -u --reset HEAD && - git clean -d -f -f -q -x && - - git update-index --refresh && - git diff-index --exit-code HEAD && + pristine_detach initial && picked=\$(git rev-parse --short picked) && cat <<-EOF >expected && error: could not apply \$picked... picked hint: after resolving the conflicts, mark the corrected paths hint: with 'git add <paths>' or 'git rm <paths>' - hint: and commit the result with 'git commit -c \$picked' + hint: and commit the result with 'git commit' EOF test_must_fail git cherry-pick picked 2>actual && test_cmp expected actual " -test_expect_success 'failed cherry-pick produces dirty index' ' +test_expect_success 'failed cherry-pick sets CHERRY_PICK_HEAD' ' + pristine_detach initial && + test_must_fail git cherry-pick picked && + test_cmp_rev picked CHERRY_PICK_HEAD +' - git checkout -f initial^0 && - git read-tree -u --reset HEAD && - git clean -d -f -f -q -x && +test_expect_success 'successful cherry-pick does not set CHERRY_PICK_HEAD' ' + pristine_detach initial && + git cherry-pick base && + test_must_fail git rev-parse --verify CHERRY_PICK_HEAD +' + +test_expect_success 'cherry-pick --no-commit does not set CHERRY_PICK_HEAD' ' + pristine_detach initial && + git cherry-pick --no-commit base && + test_must_fail git rev-parse --verify CHERRY_PICK_HEAD +' + +test_expect_success 'GIT_CHERRY_PICK_HELP suppresses CHERRY_PICK_HEAD' ' + pristine_detach initial && + ( + GIT_CHERRY_PICK_HELP="and then do something else" && + export GIT_CHERRY_PICK_HELP && + test_must_fail git cherry-pick picked + ) && + test_must_fail git rev-parse --verify CHERRY_PICK_HEAD +' + +test_expect_success 'git reset clears CHERRY_PICK_HEAD' ' + pristine_detach initial && + + test_must_fail git cherry-pick picked && + git reset && + + test_must_fail git rev-parse --verify CHERRY_PICK_HEAD +' + +test_expect_success 'failed commit does not clear CHERRY_PICK_HEAD' ' + pristine_detach initial && + + test_must_fail git cherry-pick picked && + test_must_fail git commit && + + test_cmp_rev picked CHERRY_PICK_HEAD +' + +test_expect_success 'cancelled commit does not clear CHERRY_PICK_HEAD' ' + pristine_detach initial && - git update-index --refresh && - git diff-index --exit-code HEAD && + test_must_fail git cherry-pick picked && + echo resolved >foo && + git add foo && + git update-index --refresh -q && + test_must_fail git diff-index --exit-code HEAD && + ( + GIT_EDITOR=false && + export GIT_EDITOR && + test_must_fail git commit + ) && + + test_cmp_rev picked CHERRY_PICK_HEAD +' + +test_expect_success 'successful commit clears CHERRY_PICK_HEAD' ' + pristine_detach initial && + + test_must_fail git cherry-pick picked && + echo resolved >foo && + git add foo && + git commit && + + test_must_fail git rev-parse --verify CHERRY_PICK_HEAD +' + +test_expect_success 'failed cherry-pick produces dirty index' ' + pristine_detach initial && test_must_fail git cherry-pick picked && @@ -74,9 +143,7 @@ test_expect_success 'failed cherry-pick produces dirty index' ' ' test_expect_success 'failed cherry-pick registers participants in index' ' - - git read-tree -u --reset HEAD && - git clean -d -f -f -q -x && + pristine_detach initial && { git checkout base -- foo && git ls-files --stage foo && @@ -90,10 +157,7 @@ test_expect_success 'failed cherry-pick registers participants in index' ' 2 s/ 0 / 2 / 3 s/ 0 / 3 / " < stages > expected && - git checkout -f initial^0 && - - git update-index --refresh && - git diff-index --exit-code HEAD && + git read-tree -u --reset HEAD && test_must_fail git cherry-pick picked && git ls-files --stage --unmerged > actual && @@ -102,10 +166,7 @@ test_expect_success 'failed cherry-pick registers participants in index' ' ' test_expect_success 'failed cherry-pick describes conflict in work tree' ' - - git checkout -f initial^0 && - git read-tree -u --reset HEAD && - git clean -d -f -f -q -x && + pristine_detach initial && cat <<-EOF > expected && <<<<<<< HEAD a @@ -114,9 +175,6 @@ test_expect_success 'failed cherry-pick describes conflict in work tree' ' >>>>>>> objid picked EOF - git update-index --refresh && - git diff-index --exit-code HEAD && - test_must_fail git cherry-pick picked && sed "s/[a-f0-9]*\.\.\./objid/" foo > actual && @@ -124,11 +182,8 @@ test_expect_success 'failed cherry-pick describes conflict in work tree' ' ' test_expect_success 'diff3 -m style' ' - + pristine_detach initial && git config merge.conflictstyle diff3 && - git checkout -f initial^0 && - git read-tree -u --reset HEAD && - git clean -d -f -f -q -x && cat <<-EOF > expected && <<<<<<< HEAD a @@ -139,9 +194,6 @@ test_expect_success 'diff3 -m style' ' >>>>>>> objid picked EOF - git update-index --refresh && - git diff-index --exit-code HEAD && - test_must_fail git cherry-pick picked && sed "s/[a-f0-9]*\.\.\./objid/" foo > actual && @@ -149,10 +201,8 @@ test_expect_success 'diff3 -m style' ' ' test_expect_success 'revert also handles conflicts sanely' ' - git config --unset merge.conflictstyle && - git read-tree -u --reset HEAD && - git clean -d -f -f -q -x && + pristine_detach initial && cat <<-EOF > expected && <<<<<<< HEAD a @@ -173,10 +223,7 @@ test_expect_success 'revert also handles conflicts sanely' ' 2 s/ 0 / 2 / 3 s/ 0 / 3 / " < stages > expected-stages && - git checkout -f initial^0 && - - git update-index --refresh && - git diff-index --exit-code HEAD && + git read-tree -u --reset HEAD && head=$(git rev-parse HEAD) && test_must_fail git revert picked && @@ -192,10 +239,8 @@ test_expect_success 'revert also handles conflicts sanely' ' ' test_expect_success 'revert conflict, diff3 -m style' ' + pristine_detach initial && git config merge.conflictstyle diff3 && - git checkout -f initial^0 && - git read-tree -u --reset HEAD && - git clean -d -f -f -q -x && cat <<-EOF > expected && <<<<<<< HEAD a @@ -206,9 +251,6 @@ test_expect_success 'revert conflict, diff3 -m style' ' >>>>>>> parent of objid picked EOF - git update-index --refresh && - git diff-index --exit-code HEAD && - test_must_fail git revert picked && sed "s/[a-f0-9]*\.\.\./objid/" foo > actual && diff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh index 94df7ae53a..fbc8cd8f05 100755 --- a/t/t4010-diff-pathspec.sh +++ b/t/t4010-diff-pathspec.sh @@ -70,4 +70,36 @@ test_expect_success 'diff-tree pathspec' ' test_cmp expected current ' +EMPTY_TREE=4b825dc642cb6eb9a060e54bf8d69288fbee4904 + +test_expect_success 'diff-tree with wildcard shows dir also matches' ' + git diff-tree --name-only $EMPTY_TREE $tree -- "f*" >result && + echo file0 >expected && + test_cmp expected result +' + +test_expect_success 'diff-tree -r with wildcard' ' + git diff-tree -r --name-only $EMPTY_TREE $tree -- "*file1" >result && + echo path1/file1 >expected && + test_cmp expected result +' + +test_expect_success 'diff-tree with wildcard shows dir also matches' ' + git diff-tree --name-only $tree $tree2 -- "path1/f*" >result && + echo path1 >expected && + test_cmp expected result +' + +test_expect_success 'diff-tree -r with wildcard from beginning' ' + git diff-tree -r --name-only $tree $tree2 -- "path1/*file1" >result && + echo path1/file1 >expected && + test_cmp expected result +' + +test_expect_success 'diff-tree -r with wildcard' ' + git diff-tree -r --name-only $tree $tree2 -- "path1/f*" >result && + echo path1/file1 >expected && + test_cmp expected result +' + test_done diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index b8f81d07c3..5daa0f2a0c 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -210,6 +210,9 @@ log -m -p master log -SF master log -S F master log -SF -p master +log -SF master --max-count=0 +log -SF master --max-count=1 +log -SF master --max-count=2 log -GF master log -GF -p master log -GF -p --pickaxe-all master diff --git a/t/t4013/diff.log_-SF_master_--max-count=0 b/t/t4013/diff.log_-SF_master_--max-count=0 new file mode 100644 index 0000000000..c1fc6c8731 --- /dev/null +++ b/t/t4013/diff.log_-SF_master_--max-count=0 @@ -0,0 +1,2 @@ +$ git log -SF master --max-count=0 +$ diff --git a/t/t4013/diff.log_-SF_master_--max-count=1 b/t/t4013/diff.log_-SF_master_--max-count=1 new file mode 100644 index 0000000000..c981a03814 --- /dev/null +++ b/t/t4013/diff.log_-SF_master_--max-count=1 @@ -0,0 +1,7 @@ +$ git log -SF master --max-count=1 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 +Author: A U Thor <author@example.com> +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third +$ diff --git a/t/t4013/diff.log_-SF_master_--max-count=2 b/t/t4013/diff.log_-SF_master_--max-count=2 new file mode 100644 index 0000000000..a6c55fd482 --- /dev/null +++ b/t/t4013/diff.log_-SF_master_--max-count=2 @@ -0,0 +1,7 @@ +$ git log -SF master --max-count=2 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 +Author: A U Thor <author@example.com> +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third +$ diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 027c13d52c..9c663677df 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -709,4 +709,88 @@ test_expect_success TTY 'format-patch --stdout paginates' ' test_path_is_missing .git/pager_used ' +test_expect_success 'format-patch handles multi-line subjects' ' + rm -rf patches/ && + echo content >>file && + for i in one two three; do echo $i; done >msg && + git add file && + git commit -F msg && + git format-patch -o patches -1 && + grep ^Subject: patches/0001-one.patch >actual && + echo "Subject: [PATCH] one two three" >expect && + test_cmp expect actual +' + +test_expect_success 'format-patch handles multi-line encoded subjects' ' + rm -rf patches/ && + echo content >>file && + for i in en två tre; do echo $i; done >msg && + git add file && + git commit -F msg && + git format-patch -o patches -1 && + grep ^Subject: patches/0001-en.patch >actual && + echo "Subject: [PATCH] =?UTF-8?q?en=20tv=C3=A5=20tre?=" >expect && + test_cmp expect actual +' + +M8="foo bar " +M64=$M8$M8$M8$M8$M8$M8$M8$M8 +M512=$M64$M64$M64$M64$M64$M64$M64$M64 +cat >expect <<'EOF' +Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo + bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo + bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo + bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo + bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar +EOF +test_expect_success 'format-patch wraps extremely long headers (ascii)' ' + echo content >>file && + git add file && + git commit -m "$M512" && + git format-patch --stdout -1 >patch && + sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject && + test_cmp expect subject +' + +M8="föö bar " +M64=$M8$M8$M8$M8$M8$M8$M8$M8 +M512=$M64$M64$M64$M64$M64$M64$M64$M64 +cat >expect <<'EOF' +Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?= +EOF +test_expect_success 'format-patch wraps extremely long headers (rfc2047)' ' + rm -rf patches/ && + echo content >>file && + git add file && + git commit -m "$M512" && + git format-patch --stdout -1 >patch && + sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject && + test_cmp expect subject +' + test_done diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh index 8096d8a337..37aeab0d5c 100755 --- a/t/t4034-diff-words.sh +++ b/t/t4034-diff-words.sh @@ -4,331 +4,307 @@ test_description='word diff colors' . ./test-lib.sh -test_expect_success setup ' - - git config diff.color.old red && - git config diff.color.new green && - git config diff.color.func magenta +cat >pre.simple <<-\EOF + h(4) -' + a = b + c +EOF +cat >post.simple <<-\EOF + h(4),hh[44] -word_diff () { - test_must_fail git diff --no-index "$@" pre post > output && - test_decode_color <output >output.decrypted && - test_cmp expect output.decrypted -} + a = b + c -cat > pre <<\EOF -h(4) + aa = a -a = b + c + aeff = aeff * ( aaa ) EOF +cat >expect.letter-runs-are-words <<-\EOF + <BOLD>diff --git a/pre b/post<RESET> + <BOLD>index 330b04f..5ed8eff 100644<RESET> + <BOLD>--- a/pre<RESET> + <BOLD>+++ b/post<RESET> + <CYAN>@@ -1,3 +1,7 @@<RESET> + h(4),<GREEN>hh<RESET>[44] -cat > post <<\EOF -h(4),hh[44] - -a = b + c + a = b + c<RESET> -aa = a + <GREEN>aa = a<RESET> -aeff = aeff * ( aaa ) + <GREEN>aeff = aeff * ( aaa<RESET> ) EOF +cat >expect.non-whitespace-is-word <<-\EOF + <BOLD>diff --git a/pre b/post<RESET> + <BOLD>index 330b04f..5ed8eff 100644<RESET> + <BOLD>--- a/pre<RESET> + <BOLD>+++ b/post<RESET> + <CYAN>@@ -1,3 +1,7 @@<RESET> + h(4)<GREEN>,hh[44]<RESET> -cat > expect <<\EOF -<BOLD>diff --git a/pre b/post<RESET> -<BOLD>index 330b04f..5ed8eff 100644<RESET> -<BOLD>--- a/pre<RESET> -<BOLD>+++ b/post<RESET> -<CYAN>@@ -1,3 +1,7 @@<RESET> -<RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET> + a = b + c<RESET> -a = b + c<RESET> + <GREEN>aa = a<RESET> -<GREEN>aa = a<RESET> - -<GREEN>aeff = aeff * ( aaa )<RESET> + <GREEN>aeff = aeff * ( aaa )<RESET> EOF -test_expect_success 'word diff with runs of whitespace' ' +word_diff () { + test_must_fail git diff --no-index "$@" pre post >output && + test_decode_color <output >output.decrypted && + test_cmp expect output.decrypted +} - word_diff --color-words +test_language_driver () { + lang=$1 + test_expect_success "diff driver '$lang'" ' + cp "$TEST_DIRECTORY/t4034/'"$lang"'/pre" \ + "$TEST_DIRECTORY/t4034/'"$lang"'/post" \ + "$TEST_DIRECTORY/t4034/'"$lang"'/expect" . && + echo "* diff='"$lang"'" >.gitattributes && + word_diff --color-words + ' +} +test_expect_success setup ' + git config diff.color.old red && + git config diff.color.new green && + git config diff.color.func magenta ' -test_expect_success '--word-diff=color' ' - - word_diff --word-diff=color - +test_expect_success 'set up pre and post with runs of whitespace' ' + cp pre.simple pre && + cp post.simple post ' -test_expect_success '--color --word-diff=color' ' - +test_expect_success 'word diff with runs of whitespace' ' + cat >expect <<-\EOF && + <BOLD>diff --git a/pre b/post<RESET> + <BOLD>index 330b04f..5ed8eff 100644<RESET> + <BOLD>--- a/pre<RESET> + <BOLD>+++ b/post<RESET> + <CYAN>@@ -1,3 +1,7 @@<RESET> + <RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET> + + a = b + c<RESET> + + <GREEN>aa = a<RESET> + + <GREEN>aeff = aeff * ( aaa )<RESET> + EOF + word_diff --color-words && + word_diff --word-diff=color && word_diff --color --word-diff=color - ' -sed 's/#.*$//' > expect <<EOF -diff --git a/pre b/post -index 330b04f..5ed8eff 100644 ---- a/pre -+++ b/post -@@ -1,3 +1,7 @@ --h(4) -+h(4),hh[44] -~ - # significant space -~ - a = b + c -~ -~ -+aa = a -~ -~ -+aeff = aeff * ( aaa ) -~ -EOF - test_expect_success '--word-diff=porcelain' ' - + sed 's/#.*$//' >expect <<-\EOF && + diff --git a/pre b/post + index 330b04f..5ed8eff 100644 + --- a/pre + +++ b/post + @@ -1,3 +1,7 @@ + -h(4) + +h(4),hh[44] + ~ + # significant space + ~ + a = b + c + ~ + ~ + +aa = a + ~ + ~ + +aeff = aeff * ( aaa ) + ~ + EOF word_diff --word-diff=porcelain - ' -cat > expect <<EOF -diff --git a/pre b/post -index 330b04f..5ed8eff 100644 ---- a/pre -+++ b/post -@@ -1,3 +1,7 @@ -[-h(4)-]{+h(4),hh[44]+} - -a = b + c - -{+aa = a+} - -{+aeff = aeff * ( aaa )+} -EOF - test_expect_success '--word-diff=plain' ' + cat >expect <<-\EOF && + diff --git a/pre b/post + index 330b04f..5ed8eff 100644 + --- a/pre + +++ b/post + @@ -1,3 +1,7 @@ + [-h(4)-]{+h(4),hh[44]+} - word_diff --word-diff=plain - -' + a = b + c -test_expect_success '--word-diff=plain --no-color' ' + {+aa = a+} + {+aeff = aeff * ( aaa )+} + EOF + word_diff --word-diff=plain && word_diff --word-diff=plain --no-color - ' -cat > expect <<EOF -<BOLD>diff --git a/pre b/post<RESET> -<BOLD>index 330b04f..5ed8eff 100644<RESET> -<BOLD>--- a/pre<RESET> -<BOLD>+++ b/post<RESET> -<CYAN>@@ -1,3 +1,7 @@<RESET> -<RED>[-h(4)-]<RESET><GREEN>{+h(4),hh[44]+}<RESET> - -a = b + c<RESET> - -<GREEN>{+aa = a+}<RESET> +test_expect_success '--word-diff=plain --color' ' + cat >expect <<-\EOF && + <BOLD>diff --git a/pre b/post<RESET> + <BOLD>index 330b04f..5ed8eff 100644<RESET> + <BOLD>--- a/pre<RESET> + <BOLD>+++ b/post<RESET> + <CYAN>@@ -1,3 +1,7 @@<RESET> + <RED>[-h(4)-]<RESET><GREEN>{+h(4),hh[44]+}<RESET> -<GREEN>{+aeff = aeff * ( aaa )+}<RESET> -EOF + a = b + c<RESET> -test_expect_success '--word-diff=plain --color' ' + <GREEN>{+aa = a+}<RESET> + <GREEN>{+aeff = aeff * ( aaa )+}<RESET> + EOF word_diff --word-diff=plain --color - ' -cat > expect <<\EOF -<BOLD>diff --git a/pre b/post<RESET> -<BOLD>index 330b04f..5ed8eff 100644<RESET> -<BOLD>--- a/pre<RESET> -<BOLD>+++ b/post<RESET> -<CYAN>@@ -1 +1 @@<RESET> -<RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET> -<CYAN>@@ -3,0 +4,4 @@<RESET> <RESET><MAGENTA>a = b + c<RESET> - -<GREEN>aa = a<RESET> - -<GREEN>aeff = aeff * ( aaa )<RESET> -EOF - test_expect_success 'word diff without context' ' - + cat >expect <<-\EOF && + <BOLD>diff --git a/pre b/post<RESET> + <BOLD>index 330b04f..5ed8eff 100644<RESET> + <BOLD>--- a/pre<RESET> + <BOLD>+++ b/post<RESET> + <CYAN>@@ -1 +1 @@<RESET> + <RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET> + <CYAN>@@ -3,0 +4,4 @@<RESET> <RESET><MAGENTA>a = b + c<RESET> + + <GREEN>aa = a<RESET> + + <GREEN>aeff = aeff * ( aaa )<RESET> + EOF word_diff --color-words --unified=0 - ' -cat > expect <<\EOF -<BOLD>diff --git a/pre b/post<RESET> -<BOLD>index 330b04f..5ed8eff 100644<RESET> -<BOLD>--- a/pre<RESET> -<BOLD>+++ b/post<RESET> -<CYAN>@@ -1,3 +1,7 @@<RESET> -h(4),<GREEN>hh<RESET>[44] - -a = b + c<RESET> - -<GREEN>aa = a<RESET> - -<GREEN>aeff = aeff * ( aaa<RESET> ) -EOF -cp expect expect.letter-runs-are-words - test_expect_success 'word diff with a regular expression' ' - + cp expect.letter-runs-are-words expect && word_diff --color-words="[a-z]+" - ' -test_expect_success 'set a diff driver' ' +test_expect_success 'set up a diff driver' ' git config diff.testdriver.wordRegex "[^[:space:]]" && - cat <<EOF > .gitattributes -pre diff=testdriver -post diff=testdriver -EOF + cat <<-\EOF >.gitattributes + pre diff=testdriver + post diff=testdriver + EOF ' test_expect_success 'option overrides .gitattributes' ' - + cp expect.letter-runs-are-words expect && word_diff --color-words="[a-z]+" - ' -cat > expect <<\EOF -<BOLD>diff --git a/pre b/post<RESET> -<BOLD>index 330b04f..5ed8eff 100644<RESET> -<BOLD>--- a/pre<RESET> -<BOLD>+++ b/post<RESET> -<CYAN>@@ -1,3 +1,7 @@<RESET> -h(4)<GREEN>,hh[44]<RESET> - -a = b + c<RESET> - -<GREEN>aa = a<RESET> - -<GREEN>aeff = aeff * ( aaa )<RESET> -EOF -cp expect expect.non-whitespace-is-word - test_expect_success 'use regex supplied by driver' ' - + cp expect.non-whitespace-is-word expect && word_diff --color-words - ' -test_expect_success 'set diff.wordRegex option' ' +test_expect_success 'set up diff.wordRegex option' ' git config diff.wordRegex "[[:alnum:]]+" ' -cp expect.letter-runs-are-words expect - test_expect_success 'command-line overrides config' ' + cp expect.letter-runs-are-words expect && word_diff --color-words="[a-z]+" ' -cat > expect <<\EOF -<BOLD>diff --git a/pre b/post<RESET> -<BOLD>index 330b04f..5ed8eff 100644<RESET> -<BOLD>--- a/pre<RESET> -<BOLD>+++ b/post<RESET> -<CYAN>@@ -1,3 +1,7 @@<RESET> -h(4),<GREEN>{+hh+}<RESET>[44] - -a = b + c<RESET> +test_expect_success 'command-line overrides config: --word-diff-regex' ' + cat >expect <<-\EOF && + <BOLD>diff --git a/pre b/post<RESET> + <BOLD>index 330b04f..5ed8eff 100644<RESET> + <BOLD>--- a/pre<RESET> + <BOLD>+++ b/post<RESET> + <CYAN>@@ -1,3 +1,7 @@<RESET> + h(4),<GREEN>{+hh+}<RESET>[44] -<GREEN>{+aa = a+}<RESET> + a = b + c<RESET> -<GREEN>{+aeff = aeff * ( aaa+}<RESET> ) -EOF + <GREEN>{+aa = a+}<RESET> -test_expect_success 'command-line overrides config: --word-diff-regex' ' + <GREEN>{+aeff = aeff * ( aaa+}<RESET> ) + EOF word_diff --color --word-diff-regex="[a-z]+" ' -cp expect.non-whitespace-is-word expect - test_expect_success '.gitattributes override config' ' + cp expect.non-whitespace-is-word expect && word_diff --color-words ' -test_expect_success 'remove diff driver regex' ' - git config --unset diff.testdriver.wordRegex +test_expect_success 'setup: remove diff driver regex' ' + test_might_fail git config --unset diff.testdriver.wordRegex ' -cat > expect <<\EOF -<BOLD>diff --git a/pre b/post<RESET> -<BOLD>index 330b04f..5ed8eff 100644<RESET> -<BOLD>--- a/pre<RESET> -<BOLD>+++ b/post<RESET> -<CYAN>@@ -1,3 +1,7 @@<RESET> -h(4),<GREEN>hh[44<RESET>] - -a = b + c<RESET> +test_expect_success 'use configured regex' ' + cat >expect <<-\EOF && + <BOLD>diff --git a/pre b/post<RESET> + <BOLD>index 330b04f..5ed8eff 100644<RESET> + <BOLD>--- a/pre<RESET> + <BOLD>+++ b/post<RESET> + <CYAN>@@ -1,3 +1,7 @@<RESET> + h(4),<GREEN>hh[44<RESET>] -<GREEN>aa = a<RESET> + a = b + c<RESET> -<GREEN>aeff = aeff * ( aaa<RESET> ) -EOF + <GREEN>aa = a<RESET> -test_expect_success 'use configured regex' ' + <GREEN>aeff = aeff * ( aaa<RESET> ) + EOF word_diff --color-words ' -echo 'aaa (aaa)' > pre -echo 'aaa (aaa) aaa' > post - -cat > expect <<\EOF -<BOLD>diff --git a/pre b/post<RESET> -<BOLD>index c29453b..be22f37 100644<RESET> -<BOLD>--- a/pre<RESET> -<BOLD>+++ b/post<RESET> -<CYAN>@@ -1 +1 @@<RESET> -aaa (aaa) <GREEN>aaa<RESET> -EOF - test_expect_success 'test parsing words for newline' ' - + echo "aaa (aaa)" >pre && + echo "aaa (aaa) aaa" >post && + cat >expect <<-\EOF && + <BOLD>diff --git a/pre b/post<RESET> + <BOLD>index c29453b..be22f37 100644<RESET> + <BOLD>--- a/pre<RESET> + <BOLD>+++ b/post<RESET> + <CYAN>@@ -1 +1 @@<RESET> + aaa (aaa) <GREEN>aaa<RESET> + EOF word_diff --color-words="a+" - - ' -echo '(:' > pre -echo '(' > post - -cat > expect <<\EOF -<BOLD>diff --git a/pre b/post<RESET> -<BOLD>index 289cb9d..2d06f37 100644<RESET> -<BOLD>--- a/pre<RESET> -<BOLD>+++ b/post<RESET> -<CYAN>@@ -1 +1 @@<RESET> -(<RED>:<RESET> -EOF - test_expect_success 'test when words are only removed at the end' ' - + echo "(:" >pre && + echo "(" >post && + cat >expect <<-\EOF && + <BOLD>diff --git a/pre b/post<RESET> + <BOLD>index 289cb9d..2d06f37 100644<RESET> + <BOLD>--- a/pre<RESET> + <BOLD>+++ b/post<RESET> + <CYAN>@@ -1 +1 @@<RESET> + (<RED>:<RESET> + EOF word_diff --color-words=. - ' -cat > expect <<\EOF -diff --git a/pre b/post -index 289cb9d..2d06f37 100644 ---- a/pre -+++ b/post -@@ -1 +1 @@ --(: -+( -EOF - test_expect_success '--word-diff=none' ' - + echo "(:" >pre && + echo "(" >post && + cat >expect <<-\EOF && + diff --git a/pre b/post + index 289cb9d..2d06f37 100644 + --- a/pre + +++ b/post + @@ -1 +1 @@ + -(: + +( + EOF word_diff --word-diff=plain --word-diff=none - ' +test_language_driver bibtex +test_language_driver cpp +test_language_driver csharp +test_language_driver fortran +test_language_driver html +test_language_driver java +test_language_driver objc +test_language_driver pascal +test_language_driver perl +test_language_driver php +test_language_driver python +test_language_driver ruby +test_language_driver tex + test_done diff --git a/t/t4034/bibtex/expect b/t/t4034/bibtex/expect new file mode 100644 index 0000000000..a157774f9d --- /dev/null +++ b/t/t4034/bibtex/expect @@ -0,0 +1,15 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 95cd55b..ddcba9b 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,9 +1,10 @@<RESET> +@article{aldous1987uie,<RESET> + title={{Ultimate instability of exponential back-off protocol for acknowledgment-based transmission control of random access communication channels}},<RESET> + author={Aldous, <RED>D.<RESET><GREEN>David<RESET>}, + journal={Information Theory, IEEE Transactions on},<RESET> + volume={<RED>33<RESET><GREEN>Bogus.<RESET>}, + number={<RED>2<RESET><GREEN>4<RESET>}, + pages={219--223},<RESET> + year=<GREEN>1987,<RESET> +<GREEN> note={This is in fact a rather funny read since ethernet works well in practice. The<RESET> {<RED>1987<RESET><GREEN>\em pre} reference is the right one, however.<RESET>}<RED>,<RESET> +}<RESET> diff --git a/t/t4034/bibtex/post b/t/t4034/bibtex/post new file mode 100644 index 0000000000..ddcba9b2fc --- /dev/null +++ b/t/t4034/bibtex/post @@ -0,0 +1,10 @@ +@article{aldous1987uie, + title={{Ultimate instability of exponential back-off protocol for acknowledgment-based transmission control of random access communication channels}}, + author={Aldous, David}, + journal={Information Theory, IEEE Transactions on}, + volume={Bogus.}, + number={4}, + pages={219--223}, + year=1987, + note={This is in fact a rather funny read since ethernet works well in practice. The {\em pre} reference is the right one, however.} +} diff --git a/t/t4034/bibtex/pre b/t/t4034/bibtex/pre new file mode 100644 index 0000000000..95cd55bd7b --- /dev/null +++ b/t/t4034/bibtex/pre @@ -0,0 +1,9 @@ +@article{aldous1987uie, + title={{Ultimate instability of exponential back-off protocol for acknowledgment-based transmission control of random access communication channels}}, + author={Aldous, D.}, + journal={Information Theory, IEEE Transactions on}, + volume={33}, + number={2}, + pages={219--223}, + year={1987}, +} diff --git a/t/t4034/cpp/expect b/t/t4034/cpp/expect new file mode 100644 index 0000000000..37d1ea2587 --- /dev/null +++ b/t/t4034/cpp/expect @@ -0,0 +1,36 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 23d5c8a..7e8c026 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,19 +1,19 @@<RESET> +Foo() : x(0<RED>&&1<RESET><GREEN>&42<RESET>) { <GREEN>bar(x);<RESET> } +cout<<"Hello World<RED>!<RESET><GREEN>?<RESET>\n"<<endl; +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>' +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET> +!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>^<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>|<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>||<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z +<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>,y +<RED>a<RESET><GREEN>x<RESET>::<RED>b<RESET><GREEN>y<RESET> diff --git a/t/t4034/cpp/post b/t/t4034/cpp/post new file mode 100644 index 0000000000..7e8c026cef --- /dev/null +++ b/t/t4034/cpp/post @@ -0,0 +1,19 @@ +Foo() : x(0&42) { bar(x); } +cout<<"Hello World?\n"<<endl; +(1) (-1e10) (0xabcdef) 'y' +[x] x->y x.y +!x ~x x++ x-- x*y x&y +x*y x/y x%y +x+y x-y +x<<y x>>y +x<y x<=y x>y x>=y +x==y x!=y +x&y +x^y +x|y +x&&y +x||y +x?y:z +x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y +x,y +x::y diff --git a/t/t4034/cpp/pre b/t/t4034/cpp/pre new file mode 100644 index 0000000000..23d5c8adf5 --- /dev/null +++ b/t/t4034/cpp/pre @@ -0,0 +1,19 @@ +Foo():x(0&&1){} +cout<<"Hello World!\n"<<endl; +1 -1e10 0xabcdef 'x' +[a] a->b a.b +!a ~a a++ a-- a*b a&b +a*b a/b a%b +a+b a-b +a<<b a>>b +a<b a<=b a>b a>=b +a==b a!=b +a&b +a^b +a|b +a&&b +a||b +a?b:z +a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b +a,y +a::b diff --git a/t/t4034/csharp/expect b/t/t4034/csharp/expect new file mode 100644 index 0000000000..e5d1dd2b3d --- /dev/null +++ b/t/t4034/csharp/expect @@ -0,0 +1,35 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 9106d63..dd5f421 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,18 +1,18 @@<RESET> +Foo() : x(0<RED>&&1<RESET><GREEN>&42<RESET>) { <GREEN>bar(x);<RESET> } +cout<<"Hello World<RED>!<RESET><GREEN>?<RESET>\n"<<endl; +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>' +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET> +!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>^<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>|<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>||<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z +<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>,y diff --git a/t/t4034/csharp/post b/t/t4034/csharp/post new file mode 100644 index 0000000000..dd5f4218a6 --- /dev/null +++ b/t/t4034/csharp/post @@ -0,0 +1,18 @@ +Foo() : x(0&42) { bar(x); } +cout<<"Hello World?\n"<<endl; +(1) (-1e10) (0xabcdef) 'y' +[x] x->y x.y +!x ~x x++ x-- x*y x&y +x*y x/y x%y +x+y x-y +x<<y x>>y +x<y x<=y x>y x>=y +x==y x!=y +x&y +x^y +x|y +x&&y +x||y +x?y:z +x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y +x,y diff --git a/t/t4034/csharp/pre b/t/t4034/csharp/pre new file mode 100644 index 0000000000..9106d63e87 --- /dev/null +++ b/t/t4034/csharp/pre @@ -0,0 +1,18 @@ +Foo():x(0&&1){} +cout<<"Hello World!\n"<<endl; +1 -1e10 0xabcdef 'x' +[a] a->b a.b +!a ~a a++ a-- a*b a&b +a*b a/b a%b +a+b a-b +a<<b a>>b +a<b a<=b a>b a>=b +a==b a!=b +a&b +a^b +a|b +a&&b +a||b +a?b:z +a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b +a,y diff --git a/t/t4034/fortran/expect b/t/t4034/fortran/expect new file mode 100644 index 0000000000..b233dbd621 --- /dev/null +++ b/t/t4034/fortran/expect @@ -0,0 +1,10 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 87f0d0b..d308da2 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,5 +1,5 @@<RESET> +print *, "Hello World<RED>!<RESET><GREEN>?<RESET>" + +DO10I = 1,10<RESET> +<RED>DO10I<RESET><GREEN>DO 10 I<RESET> = 1,10 +<RED>DO10I<RESET><GREEN>DO 1 0 I<RESET> = 1,10 diff --git a/t/t4034/fortran/post b/t/t4034/fortran/post new file mode 100644 index 0000000000..d308da2ad2 --- /dev/null +++ b/t/t4034/fortran/post @@ -0,0 +1,5 @@ +print *, "Hello World?" + +DO10I = 1,10 +DO 10 I = 1,10 +DO 1 0 I = 1,10 diff --git a/t/t4034/fortran/pre b/t/t4034/fortran/pre new file mode 100644 index 0000000000..87f0d0b031 --- /dev/null +++ b/t/t4034/fortran/pre @@ -0,0 +1,5 @@ +print *, "Hello World!" + +DO10I = 1,10 +DO10I = 1,10 +DO10I = 1,10 diff --git a/t/t4034/html/expect b/t/t4034/html/expect new file mode 100644 index 0000000000..447b49ab6d --- /dev/null +++ b/t/t4034/html/expect @@ -0,0 +1,8 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 8ca4aea..46921e5 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,3 +1,3 @@<RESET> +<tag <GREEN>newattr="newvalue"<RESET>><GREEN>added<RESET> content</tag> +<tag attr=<RED>"value"<RESET><GREEN>"newvalue"<RESET>><RED>content<RESET><GREEN>changed<RESET></tag> +<<RED>tag<RESET><GREEN>newtag<RESET>>content <RED>&entity;<RESET><GREEN>&newentity;<RESET><<RED>/tag<RESET><GREEN>/newtag<RESET>> diff --git a/t/t4034/html/post b/t/t4034/html/post new file mode 100644 index 0000000000..46921e586c --- /dev/null +++ b/t/t4034/html/post @@ -0,0 +1,3 @@ +<tag newattr="newvalue">added content</tag> +<tag attr="newvalue">changed</tag> +<newtag>content &newentity;</newtag> diff --git a/t/t4034/html/pre b/t/t4034/html/pre new file mode 100644 index 0000000000..8ca4aeae83 --- /dev/null +++ b/t/t4034/html/pre @@ -0,0 +1,3 @@ +<tag>content</tag> +<tag attr="value">content</tag> +<tag>content &entity;</tag> diff --git a/t/t4034/java/expect b/t/t4034/java/expect new file mode 100644 index 0000000000..37d1ea2587 --- /dev/null +++ b/t/t4034/java/expect @@ -0,0 +1,36 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 23d5c8a..7e8c026 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,19 +1,19 @@<RESET> +Foo() : x(0<RED>&&1<RESET><GREEN>&42<RESET>) { <GREEN>bar(x);<RESET> } +cout<<"Hello World<RED>!<RESET><GREEN>?<RESET>\n"<<endl; +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>' +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET> +!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>^<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>|<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>||<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z +<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>,y +<RED>a<RESET><GREEN>x<RESET>::<RED>b<RESET><GREEN>y<RESET> diff --git a/t/t4034/java/post b/t/t4034/java/post new file mode 100644 index 0000000000..7e8c026cef --- /dev/null +++ b/t/t4034/java/post @@ -0,0 +1,19 @@ +Foo() : x(0&42) { bar(x); } +cout<<"Hello World?\n"<<endl; +(1) (-1e10) (0xabcdef) 'y' +[x] x->y x.y +!x ~x x++ x-- x*y x&y +x*y x/y x%y +x+y x-y +x<<y x>>y +x<y x<=y x>y x>=y +x==y x!=y +x&y +x^y +x|y +x&&y +x||y +x?y:z +x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y +x,y +x::y diff --git a/t/t4034/java/pre b/t/t4034/java/pre new file mode 100644 index 0000000000..23d5c8adf5 --- /dev/null +++ b/t/t4034/java/pre @@ -0,0 +1,19 @@ +Foo():x(0&&1){} +cout<<"Hello World!\n"<<endl; +1 -1e10 0xabcdef 'x' +[a] a->b a.b +!a ~a a++ a-- a*b a&b +a*b a/b a%b +a+b a-b +a<<b a>>b +a<b a<=b a>b a>=b +a==b a!=b +a&b +a^b +a|b +a&&b +a||b +a?b:z +a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b +a,y +a::b diff --git a/t/t4034/objc/expect b/t/t4034/objc/expect new file mode 100644 index 0000000000..e5d1dd2b3d --- /dev/null +++ b/t/t4034/objc/expect @@ -0,0 +1,35 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 9106d63..dd5f421 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,18 +1,18 @@<RESET> +Foo() : x(0<RED>&&1<RESET><GREEN>&42<RESET>) { <GREEN>bar(x);<RESET> } +cout<<"Hello World<RED>!<RESET><GREEN>?<RESET>\n"<<endl; +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>' +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET> +!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>^<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>|<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>||<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z +<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>,y diff --git a/t/t4034/objc/post b/t/t4034/objc/post new file mode 100644 index 0000000000..dd5f4218a6 --- /dev/null +++ b/t/t4034/objc/post @@ -0,0 +1,18 @@ +Foo() : x(0&42) { bar(x); } +cout<<"Hello World?\n"<<endl; +(1) (-1e10) (0xabcdef) 'y' +[x] x->y x.y +!x ~x x++ x-- x*y x&y +x*y x/y x%y +x+y x-y +x<<y x>>y +x<y x<=y x>y x>=y +x==y x!=y +x&y +x^y +x|y +x&&y +x||y +x?y:z +x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y +x,y diff --git a/t/t4034/objc/pre b/t/t4034/objc/pre new file mode 100644 index 0000000000..9106d63e87 --- /dev/null +++ b/t/t4034/objc/pre @@ -0,0 +1,18 @@ +Foo():x(0&&1){} +cout<<"Hello World!\n"<<endl; +1 -1e10 0xabcdef 'x' +[a] a->b a.b +!a ~a a++ a-- a*b a&b +a*b a/b a%b +a+b a-b +a<<b a>>b +a<b a<=b a>b a>=b +a==b a!=b +a&b +a^b +a|b +a&&b +a||b +a?b:z +a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b +a,y diff --git a/t/t4034/pascal/expect b/t/t4034/pascal/expect new file mode 100644 index 0000000000..2ce4230954 --- /dev/null +++ b/t/t4034/pascal/expect @@ -0,0 +1,35 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 077046c..8865e6b 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,18 +1,18 @@<RESET> +writeln("Hello World<RED>!<RESET><GREEN>?<RESET>"); +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>' +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET> +!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>^<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>|<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>||<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z +<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>,y +<RED>a<RESET><GREEN>x<RESET>::<RED>b<RESET><GREEN>y<RESET> diff --git a/t/t4034/pascal/post b/t/t4034/pascal/post new file mode 100644 index 0000000000..8865e6bddd --- /dev/null +++ b/t/t4034/pascal/post @@ -0,0 +1,18 @@ +writeln("Hello World?"); +(1) (-1e10) (0xabcdef) 'y' +[x] x->y x.y +!x ~x x++ x-- x*y x&y +x*y x/y x%y +x+y x-y +x<<y x>>y +x<y x<=y x>y x>=y +x==y x!=y +x&y +x^y +x|y +x&&y +x||y +x?y:z +x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y +x,y +x::y diff --git a/t/t4034/pascal/pre b/t/t4034/pascal/pre new file mode 100644 index 0000000000..077046c832 --- /dev/null +++ b/t/t4034/pascal/pre @@ -0,0 +1,18 @@ +writeln("Hello World!"); +1 -1e10 0xabcdef 'x' +[a] a->b a.b +!a ~a a++ a-- a*b a&b +a*b a/b a%b +a+b a-b +a<<b a>>b +a<b a<=b a>b a>=b +a==b a!=b +a&b +a^b +a|b +a&&b +a||b +a?b:z +a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b +a,y +a::b diff --git a/t/t4034/perl/expect b/t/t4034/perl/expect new file mode 100644 index 0000000000..a1deb6b6ad --- /dev/null +++ b/t/t4034/perl/expect @@ -0,0 +1,13 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index f6610d3..e8b72ef 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -4,8 +4,8 @@<RESET> + +package Frotz;<RESET> +sub new {<RESET> + my <GREEN>(<RESET>$class<GREEN>, %opts)<RESET> = <RED>shift<RESET><GREEN>@_<RESET>; + return bless { <GREEN>xyzzy => "nitfol", %opts<RESET> }, $class; +}<RESET> + +__END__<RESET> diff --git a/t/t4034/perl/post b/t/t4034/perl/post new file mode 100644 index 0000000000..e8b72ef5dc --- /dev/null +++ b/t/t4034/perl/post @@ -0,0 +1,22 @@ +#!/usr/bin/perl + +use strict; + +package Frotz; +sub new { + my ($class, %opts) = @_; + return bless { xyzzy => "nitfol", %opts }, $class; +} + +__END__ +=head1 NAME + +frotz - Frotz + +=head1 SYNOPSIS + + use frotz; + + $nitfol = new Frotz(); + +=cut diff --git a/t/t4034/perl/pre b/t/t4034/perl/pre new file mode 100644 index 0000000000..f6610d37b8 --- /dev/null +++ b/t/t4034/perl/pre @@ -0,0 +1,22 @@ +#!/usr/bin/perl + +use strict; + +package Frotz; +sub new { + my $class = shift; + return bless {}, $class; +} + +__END__ +=head1 NAME + +frotz - Frotz + +=head1 SYNOPSIS + + use frotz; + + $nitfol = new Frotz(); + +=cut diff --git a/t/t4034/php/expect b/t/t4034/php/expect new file mode 100644 index 0000000000..040440860a --- /dev/null +++ b/t/t4034/php/expect @@ -0,0 +1,35 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index cf6e06b..4420a49 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,18 +1,18 @@<RESET> +<GREEN>(<RESET>$var<GREEN>)<RESET> $ var +<?="Hello World<RED>!<RESET><GREEN>?<RESET>"?> +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>' +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET> +!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>^<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>|<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>||<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z +<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>,y diff --git a/t/t4034/php/post b/t/t4034/php/post new file mode 100644 index 0000000000..4420a49192 --- /dev/null +++ b/t/t4034/php/post @@ -0,0 +1,18 @@ +($var) $ var +<?="Hello World?"?> +(1) (-1e10) (0xabcdef) 'y' +[x] x->y x.y +!x ~x x++ x-- x*y x&y +x*y x/y x%y +x+y x-y +x<<y x>>y +x<y x<=y x>y x>=y +x==y x!=y +x&y +x^y +x|y +x&&y +x||y +x?y:z +x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y +x,y diff --git a/t/t4034/php/pre b/t/t4034/php/pre new file mode 100644 index 0000000000..cf6e06bc22 --- /dev/null +++ b/t/t4034/php/pre @@ -0,0 +1,18 @@ +$var $var +<?= "Hello World!" ?> +1 -1e10 0xabcdef 'x' +[a] a->b a.b +!a ~a a++ a-- a*b a&b +a*b a/b a%b +a+b a-b +a<<b a>>b +a<b a<=b a>b a>=b +a==b a!=b +a&b +a^b +a|b +a&&b +a||b +a?b:z +a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b +a,y diff --git a/t/t4034/python/expect b/t/t4034/python/expect new file mode 100644 index 0000000000..8abb8a48b4 --- /dev/null +++ b/t/t4034/python/expect @@ -0,0 +1,34 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 438f776..68baf34 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,17 +1,17 @@<RESET> +print<RED>u<RESET> "Hello World<RED>!<RESET><GREEN>?<RESET>\n"<GREEN>; print<RESET> +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>) u<RESET>'<RED>x<RESET><GREEN>y<RESET>' +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET> +!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>^<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>|<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>||<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z +<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>,y diff --git a/t/t4034/python/post b/t/t4034/python/post new file mode 100644 index 0000000000..68baf34f0e --- /dev/null +++ b/t/t4034/python/post @@ -0,0 +1,17 @@ +print "Hello World?\n"; print +(1) (-1e10) (0xabcdef) u'y' +[x] x->y x.y +!x ~x x++ x-- x*y x&y +x*y x/y x%y +x+y x-y +x<<y x>>y +x<y x<=y x>y x>=y +x==y x!=y +x&y +x^y +x|y +x&&y +x||y +x?y:z +x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y +x,y diff --git a/t/t4034/python/pre b/t/t4034/python/pre new file mode 100644 index 0000000000..438f776875 --- /dev/null +++ b/t/t4034/python/pre @@ -0,0 +1,17 @@ +print u"Hello World!\n" +1 -1e10 0xabcdef 'x' +[a] a->b a.b +!a ~a a++ a-- a*b a&b +a*b a/b a%b +a+b a-b +a<<b a>>b +a<b a<=b a>b a>=b +a==b a!=b +a&b +a^b +a|b +a&&b +a||b +a?b:z +a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b +a,y diff --git a/t/t4034/ruby/expect b/t/t4034/ruby/expect new file mode 100644 index 0000000000..16e1dd5674 --- /dev/null +++ b/t/t4034/ruby/expect @@ -0,0 +1,34 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 30ed9a1..7678f14 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,17 +1,17 @@<RESET> +10.downto(1) {|<RED>x<RESET><GREEN>y<RESET>| puts <RED>x<RESET><GREEN>y<RESET>} +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>' +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET> +!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>^<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>|<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>&&<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>||<RED>b<RESET> +<RED>a?b<RESET><GREEN>y<RESET> +<GREEN>x?y<RESET>:z +<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>,y diff --git a/t/t4034/ruby/post b/t/t4034/ruby/post new file mode 100644 index 0000000000..7678f14e14 --- /dev/null +++ b/t/t4034/ruby/post @@ -0,0 +1,17 @@ +10.downto(1) {|y| puts y} +(1) (-1e10) (0xabcdef) 'y' +[x] x->y x.y +!x ~x x++ x-- x*y x&y +x*y x/y x%y +x+y x-y +x<<y x>>y +x<y x<=y x>y x>=y +x==y x!=y +x&y +x^y +x|y +x&&y +x||y +x?y:z +x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y +x,y diff --git a/t/t4034/ruby/pre b/t/t4034/ruby/pre new file mode 100644 index 0000000000..30ed9a1595 --- /dev/null +++ b/t/t4034/ruby/pre @@ -0,0 +1,17 @@ +10.downto(1) {|x| puts x} +1 -1e10 0xabcdef 'x' +[a] a->b a.b +!a ~a a++ a-- a*b a&b +a*b a/b a%b +a+b a-b +a<<b a>>b +a<b a<=b a>b a>=b +a==b a!=b +a&b +a^b +a|b +a&&b +a||b +a?b:z +a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b +a,y diff --git a/t/t4034/tex/expect b/t/t4034/tex/expect new file mode 100644 index 0000000000..604969bcde --- /dev/null +++ b/t/t4034/tex/expect @@ -0,0 +1,9 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index 2b2dfcb..65cab61 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,4 +1,4 @@<RESET> +\section{Something <GREEN>new<RESET>} +<RED>\emph<RESET><GREEN>\textbf<RESET>{Macro style} +{<RED>\em<RESET><GREEN>\bfseries<RESET> State toggle style} +\\[<RED>1em<RESET><GREEN>1cm<RESET>] diff --git a/t/t4034/tex/post b/t/t4034/tex/post new file mode 100644 index 0000000000..65cab61a10 --- /dev/null +++ b/t/t4034/tex/post @@ -0,0 +1,4 @@ +\section{Something new} +\textbf{Macro style} +{\bfseries State toggle style} +\\[1cm] diff --git a/t/t4034/tex/pre b/t/t4034/tex/pre new file mode 100644 index 0000000000..2b2dfcb65c --- /dev/null +++ b/t/t4034/tex/pre @@ -0,0 +1,4 @@ +\section{Something} +\emph{Macro style} +{\em State toggle style} +\\[1em] diff --git a/t/t6000-rev-list-misc.sh b/t/t6000-rev-list-misc.sh new file mode 100755 index 0000000000..b10685af4e --- /dev/null +++ b/t/t6000-rev-list-misc.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +test_description='miscellaneous rev-list tests' + +. ./test-lib.sh + +test_expect_success setup ' + echo content1 >wanted_file && + echo content2 >unwanted_file && + git add wanted_file unwanted_file && + git commit -m one +' + +test_expect_success 'rev-list --objects heeds pathspecs' ' + git rev-list --objects HEAD -- wanted_file >output && + grep wanted_file output && + ! grep unwanted_file output +' + +test_expect_success 'rev-list --objects with pathspecs and deeper paths' ' + mkdir foo && + >foo/file && + git add foo/file && + git commit -m two && + + git rev-list --objects HEAD -- foo >output && + grep foo/file output && + + git rev-list --objects HEAD -- foo/file >output && + grep foo/file output && + ! grep unwanted_file output +' + +test_expect_success 'rev-list --objects with pathspecs and copied files' ' + git checkout --orphan junio-testcase && + git rm -rf . && + + mkdir two && + echo frotz >one && + cp one two/three && + git add one two/three && + test_tick && + git commit -m that && + + ONE=$(git rev-parse HEAD:one) + git rev-list --objects HEAD two >output && + grep "$ONE two/three" output && + ! grep one output +' + +test_done diff --git a/t/t6004-rev-list-path-optim.sh b/t/t6004-rev-list-path-optim.sh index 5dabf1c5e3..3e8c42ee0b 100755 --- a/t/t6004-rev-list-path-optim.sh +++ b/t/t6004-rev-list-path-optim.sh @@ -1,51 +1,96 @@ #!/bin/sh -test_description='git rev-list trivial path optimization test' +test_description='git rev-list trivial path optimization test + + d/z1 + b0 b1 + o------------------------*----o master + / / + o---------o----o----o----o side + a0 c0 c1 a1 c2 + d/f0 d/f1 + d/z0 + +' . ./test-lib.sh test_expect_success setup ' -echo Hello > a && -git add a && -git commit -m "Initial commit" a && -initial=$(git rev-parse --verify HEAD) + echo Hello >a && + mkdir d && + echo World >d/f && + echo World >d/z && + git add a d && + test_tick && + git commit -m "Initial commit" && + git rev-parse --verify HEAD && + git tag initial ' test_expect_success path-optimization ' - commit=$(echo "Unchanged tree" | git commit-tree "HEAD^{tree}" -p HEAD) && - test $(git rev-list $commit | wc -l) = 2 && - test $(git rev-list $commit -- . | wc -l) = 1 + test_tick && + commit=$(echo "Unchanged tree" | git commit-tree "HEAD^{tree}" -p HEAD) && + test $(git rev-list $commit | wc -l) = 2 && + test $(git rev-list $commit -- . | wc -l) = 1 ' test_expect_success 'further setup' ' git checkout -b side && echo Irrelevant >c && - git add c && + echo Irrelevant >d/f && + git add c d/f && + test_tick && git commit -m "Side makes an irrelevant commit" && + git tag side_c0 && echo "More Irrelevancy" >c && git add c && + test_tick && git commit -m "Side makes another irrelevant commit" && echo Bye >a && git add a && + test_tick && git commit -m "Side touches a" && - side=$(git rev-parse --verify HEAD) && + git tag side_a1 && echo "Yet more Irrelevancy" >c && git add c && + test_tick && git commit -m "Side makes yet another irrelevant commit" && git checkout master && echo Another >b && - git add b && + echo Munged >d/z && + git add b d/z && + test_tick && git commit -m "Master touches b" && + git tag master_b0 && git merge side && echo Touched >b && git add b && + test_tick && git commit -m "Master touches b again" ' test_expect_success 'path optimization 2' ' - ( echo "$side"; echo "$initial" ) >expected && + git rev-parse side_a1 initial >expected && git rev-list HEAD -- a >actual && test_cmp expected actual ' +test_expect_success 'pathspec with leading path' ' + git rev-parse master^ master_b0 side_c0 initial >expected && + git rev-list HEAD -- d >actual && + test_cmp expected actual +' + +test_expect_success 'pathspec with glob (1)' ' + git rev-parse master^ master_b0 side_c0 initial >expected && + git rev-list HEAD -- "d/*" >actual && + test_cmp expected actual +' + +test_expect_success 'pathspec with glob (2)' ' + git rev-parse side_c0 initial >expected && + git rev-list HEAD -- "d/[a-m]*" >actual && + test_cmp expected actual +' + test_done diff --git a/t/t6035-merge-dir-to-symlink.sh b/t/t6035-merge-dir-to-symlink.sh index 92e02d5d77..2599ae50eb 100755 --- a/t/t6035-merge-dir-to-symlink.sh +++ b/t/t6035-merge-dir-to-symlink.sh @@ -17,13 +17,21 @@ test_expect_success SYMLINKS 'create a commit where dir a/b changed to symlink' git commit -m "dir to symlink" ' -test_expect_success SYMLINKS 'keep a/b-2/c/d across checkout' ' +test_expect_success SYMLINKS 'checkout does not clobber untracked symlink' ' git checkout HEAD^0 && git reset --hard master && git rm --cached a/b && git commit -m "untracked symlink remains" && - git checkout start^0 && - test -f a/b-2/c/d + test_must_fail git checkout start^0 +' + +test_expect_success SYMLINKS 'a/b-2/c/d is kept when clobbering symlink b' ' + git checkout HEAD^0 && + git reset --hard master && + git rm --cached a/b && + git commit -m "untracked symlink remains" && + git checkout -f start^0 && + test -f a/b-2/c/d ' test_expect_success SYMLINKS 'checkout should not have deleted a/b-2/c/d' ' diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh index 1e0447f615..cb85132642 100755 --- a/t/t6040-tracking-info.sh +++ b/t/t6040-tracking-info.sh @@ -74,20 +74,20 @@ test_expect_success 'status' ' grep "have 1 and 1 different" actual ' -test_expect_success 'status when tracking lightweight tags' ' +test_expect_success 'fail to track lightweight tags' ' git checkout master && git tag light && - git branch --track lighttrack light >actual && - grep "set up to track" actual && - git checkout lighttrack + test_must_fail git branch --track lighttrack light >actual && + test_must_fail grep "set up to track" actual && + test_must_fail git checkout lighttrack ' -test_expect_success 'status when tracking annotated tags' ' +test_expect_success 'fail to track annotated tags' ' git checkout master && git tag -m heavy heavy && - git branch --track heavytrack heavy >actual && - grep "set up to track" actual && - git checkout heavytrack + test_must_fail git branch --track heavytrack heavy >actual && + test_must_fail grep "set up to track" actual && + test_must_fail git checkout heavytrack ' test_expect_success 'setup tracking with branch --set-upstream on existing branch' ' diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 1337fa5a22..0c002ab695 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -408,6 +408,15 @@ test_expect_success 'checkout w/--track from non-branch HEAD fails' ' test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)" ' +test_expect_success 'checkout w/--track from tag fails' ' + git checkout master^0 && + test_must_fail git symbolic-ref HEAD && + test_must_fail git checkout --track -b track frotz && + test_must_fail git rev-parse --verify track && + test_must_fail git symbolic-ref HEAD && + test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)" +' + test_expect_success 'detach a symbolic link HEAD' ' git checkout master && git config --bool core.prefersymlinkrefs yes && @@ -423,7 +432,6 @@ test_expect_success 'detach a symbolic link HEAD' ' test_expect_success \ 'checkout with --track fakes a sensible -b <name>' ' git update-ref refs/remotes/origin/koala/bear renamer && - git update-ref refs/new/koala/bear renamer && git checkout --track origin/koala/bear && test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" && @@ -439,12 +447,6 @@ test_expect_success \ git checkout --track remotes/origin/koala/bear && test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" && - test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" && - - git checkout master && git branch -D koala/bear && - - git checkout --track refs/new/koala/bear && - test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" && test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" ' diff --git a/t/t7509-commit.sh b/t/t7509-commit.sh index 77b6920029..b61fd3c3c4 100755 --- a/t/t7509-commit.sh +++ b/t/t7509-commit.sh @@ -157,4 +157,33 @@ test_expect_success '--reset-author should be rejected without -c/-C/--amend' ' test_must_fail git commit -a --reset-author -m done ' +test_expect_success 'commit respects CHERRY_PICK_HEAD and MERGE_MSG' ' + echo "cherry-pick 1a" >>foo && + test_tick && + git commit -am "cherry-pick 1" --author="Cherry <cherry@pick.er>" && + git tag cherry-pick-head && + git rev-parse cherry-pick-head >.git/CHERRY_PICK_HEAD && + echo "This is a MERGE_MSG" >.git/MERGE_MSG && + echo "cherry-pick 1b" >>foo && + test_tick && + git commit -a && + author_header cherry-pick-head >expect && + author_header HEAD >actual && + test_cmp expect actual && + + echo "This is a MERGE_MSG" >expect && + message_body HEAD >actual && + test_cmp expect actual +' + +test_expect_success '--reset-author with CHERRY_PICK_HEAD' ' + git rev-parse cherry-pick-head >.git/CHERRY_PICK_HEAD && + echo "cherry-pick 2" >>foo && + test_tick && + git commit -am "cherry-pick 2" --reset-author && + echo "author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE" >expect && + author_header HEAD >actual && + test_cmp expect actual +' + test_done diff --git a/t/t7607-merge-overwrite.sh b/t/t7607-merge-overwrite.sh index 4d5ce4e682..5f731a1177 100755 --- a/t/t7607-merge-overwrite.sh +++ b/t/t7607-merge-overwrite.sh @@ -156,4 +156,20 @@ test_expect_success 'will not overwrite untracked file on unborn branch' ' test_cmp important c0.c ' +test_expect_success 'set up unborn branch and content' ' + git symbolic-ref HEAD refs/heads/unborn && + rm -f .git/index && + echo foo > tracked-file && + git add tracked-file && + echo bar > untracked-file +' + +test_expect_failure 'will not clobber WT/index when merging into unborn' ' + git merge master && + grep foo tracked-file && + git show :tracked-file >expect && + grep foo expect && + grep bar untracked-file +' + test_done diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh index d78bdec330..dc838c93bc 100755 --- a/t/t7610-mergetool.sh +++ b/t/t7610-mergetool.sh @@ -16,23 +16,33 @@ Testing basic merge tool invocation' test_expect_success 'setup' ' git config rerere.enabled true && echo master >file1 && + echo master file11 >file11 && + echo master file12 >file12 && + echo master file13 >file13 && + echo master file14 >file14 && mkdir subdir && echo master sub >subdir/file3 && - git add file1 subdir/file3 && - git commit -m "added file1" && + git add file1 file1[1-4] subdir/file3 && + git commit -m "add initial versions" && git checkout -b branch1 master && echo branch1 change >file1 && echo branch1 newfile >file2 && + echo branch1 change file11 >file11 && + echo branch1 change file13 >file13 && echo branch1 sub >subdir/file3 && - git add file1 file2 subdir/file3 && + git add file1 file11 file13 file2 subdir/file3 && + git rm file12 && git commit -m "branch1 changes" && git checkout master && echo master updated >file1 && echo master new >file2 && + echo master updated file12 >file12 && + echo master updated file14 >file14 && echo master new sub >subdir/file3 && - git add file1 file2 subdir/file3 && + git add file1 file12 file14 file2 subdir/file3 && + git rm file11 && git commit -m "master updates" && git config merge.tool mytool && @@ -46,6 +56,8 @@ test_expect_success 'custom mergetool' ' ( yes "" | git mergetool file1 >/dev/null 2>&1 ) && ( yes "" | git mergetool file2 >/dev/null 2>&1 ) && ( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) && test "$(cat file1)" = "master updated" && test "$(cat file2)" = "master new" && test "$(cat subdir/file3)" = "master new sub" && @@ -59,6 +71,8 @@ test_expect_success 'mergetool crlf' ' ( yes "" | git mergetool file1 >/dev/null 2>&1 ) && ( yes "" | git mergetool file2 >/dev/null 2>&1 ) && ( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) && test "$(printf x | cat file1 -)" = "$(printf "master updated\r\nx")" && test "$(printf x | cat file2 -)" = "$(printf "master new\r\nx")" && test "$(printf x | cat subdir/file3 -)" = "$(printf "master new sub\r\nx")" && @@ -82,6 +96,8 @@ test_expect_success 'mergetool on file in parent dir' ' cd subdir && ( yes "" | git mergetool ../file1 >/dev/null 2>&1 ) && ( yes "" | git mergetool ../file2 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool ../file11 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool ../file12 >/dev/null 2>&1 ) && test "$(cat ../file1)" = "master updated" && test "$(cat ../file2)" = "master new" && git commit -m "branch1 resolved with mergetool - subdir" @@ -92,6 +108,8 @@ test_expect_success 'mergetool skips autoresolved' ' git checkout -b test4 branch1 && test_must_fail git merge master && test -n "$(git ls-files -u)" && + ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) && + ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) && output="$(git mergetool --no-prompt)" && test "$output" = "No files need merging" && git reset --hard @@ -102,13 +120,23 @@ test_expect_success 'mergetool merges all from subdir' ' cd subdir && git config rerere.enabled false && test_must_fail git merge master && - git mergetool --no-prompt && + ( yes "d" "d" | git mergetool --no-prompt ) && test "$(cat ../file1)" = "master updated" && test "$(cat ../file2)" = "master new" && test "$(cat file3)" = "master new sub" && - git add ../file1 ../file2 file3 && git commit -m "branch2 resolved by mergetool from subdir" ) ' +test_expect_success 'mergetool skips resolved paths when rerere is active' ' + git config rerere.enabled true && + rm -rf .git/rr-cache && + git checkout -b test5 branch1 + test_must_fail git merge master >/dev/null 2>&1 && + ( yes "d" "d" | git mergetool --no-prompt >/dev/null 2>&1 ) && + output="$(yes "n" | git mergetool --no-prompt)" && + test "$output" = "No files need merging" && + git reset --hard +' + test_done diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index c8777589ca..dbc6cd8a77 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -182,6 +182,24 @@ do test_cmp expected actual ' + test_expect_success "grep --max-depth 0 -- . t $L" ' + { + echo ${HC}t/v:1:vvv + echo ${HC}v:1:vvv + } >expected && + git grep --max-depth 0 -n -e vvv $H -- . t >actual && + test_cmp expected actual + ' + + test_expect_success "grep --max-depth 0 -- t . $L" ' + { + echo ${HC}t/v:1:vvv + echo ${HC}v:1:vvv + } >expected && + git grep --max-depth 0 -n -e vvv $H -- t . >actual && + test_cmp expected actual + ' + done cat >expected <<EOF @@ -285,6 +303,11 @@ test_expect_success 'grep -f, ignore empty lines' ' test_cmp expected actual ' +test_expect_success 'grep -f, ignore empty lines, read patterns from stdin' ' + git grep -f - <patterns >actual && + test_cmp expected actual +' + cat >expected <<EOF y:y yy -- diff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh index 88a9751dd3..5a6a4b9b7a 100755 --- a/t/t9010-svn-fe.sh +++ b/t/t9010-svn-fe.sh @@ -9,6 +9,30 @@ reinit_git () { git init } +properties () { + while test "$#" -ne 0 + do + property="$1" && + value="$2" && + printf "%s\n" "K ${#property}" && + printf "%s\n" "$property" && + printf "%s\n" "V ${#value}" && + printf "%s\n" "$value" && + shift 2 || + return 1 + done +} + +text_no_props () { + text="$1 +" && + printf "%s\n" "Prop-content-length: 10" && + printf "%s\n" "Text-content-length: ${#text}" && + printf "%s\n" "Content-length: $((${#text} + 10))" && + printf "%s\n" "" "PROPS-END" && + printf "%s\n" "$text" +} + >empty test_expect_success 'empty dump' ' @@ -18,13 +42,686 @@ test_expect_success 'empty dump' ' git fast-import <stream ' -test_expect_success 'v3 dumps not supported' ' +test_expect_success 'v4 dumps not supported' ' reinit_git && - echo "SVN-fs-dump-format-version: 3" >input && - test_must_fail test-svn-fe input >stream && + echo "SVN-fs-dump-format-version: 4" >v4.dump && + test_must_fail test-svn-fe v4.dump >stream && test_cmp empty stream ' +test_expect_failure 'empty revision' ' + reinit_git && + printf "rev <nobody, nobody@local>: %s\n" "" "" >expect && + cat >emptyrev.dump <<-\EOF && + SVN-fs-dump-format-version: 3 + + Revision-number: 1 + Prop-content-length: 0 + Content-length: 0 + + Revision-number: 2 + Prop-content-length: 0 + Content-length: 0 + + EOF + test-svn-fe emptyrev.dump >stream && + git fast-import <stream && + git log -p --format="rev <%an, %ae>: %s" HEAD >actual && + test_cmp expect actual +' + +test_expect_success 'empty properties' ' + reinit_git && + printf "rev <nobody, nobody@local>: %s\n" "" "" >expect && + cat >emptyprop.dump <<-\EOF && + SVN-fs-dump-format-version: 3 + + Revision-number: 1 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Revision-number: 2 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + EOF + test-svn-fe emptyprop.dump >stream && + git fast-import <stream && + git log -p --format="rev <%an, %ae>: %s" HEAD >actual && + test_cmp expect actual +' + +test_expect_success 'author name and commit message' ' + reinit_git && + echo "<author@example.com, author@example.com@local>" >expect.author && + cat >message <<-\EOF && + A concise summary of the change + + A detailed description of the change, why it is needed, what + was broken and why applying this is the best course of action. + + * file.c + Details pertaining to an individual file. + EOF + { + properties \ + svn:author author@example.com \ + svn:log "$(cat message)" && + echo PROPS-END + } >props && + { + echo "SVN-fs-dump-format-version: 3" && + echo && + echo "Revision-number: 1" && + echo Prop-content-length: $(wc -c <props) && + echo Content-length: $(wc -c <props) && + echo && + cat props + } >log.dump && + test-svn-fe log.dump >stream && + git fast-import <stream && + git log -p --format="%B" HEAD >actual.log && + git log --format="<%an, %ae>" >actual.author && + test_cmp message actual.log && + test_cmp expect.author actual.author +' + +test_expect_success 'unsupported properties are ignored' ' + reinit_git && + echo author >expect && + cat >extraprop.dump <<-\EOF && + SVN-fs-dump-format-version: 3 + + Revision-number: 1 + Prop-content-length: 56 + Content-length: 56 + + K 8 + nonsense + V 1 + y + K 10 + svn:author + V 6 + author + PROPS-END + EOF + test-svn-fe extraprop.dump >stream && + git fast-import <stream && + git log -p --format=%an HEAD >actual && + test_cmp expect actual +' + +test_expect_failure 'timestamp and empty file' ' + echo author@example.com >expect.author && + echo 1999-01-01 >expect.date && + echo file >expect.files && + reinit_git && + { + properties \ + svn:author author@example.com \ + svn:date "1999-01-01T00:01:002.000000Z" \ + svn:log "add empty file" && + echo PROPS-END + } >props && + { + cat <<-EOF && + SVN-fs-dump-format-version: 3 + + Revision-number: 1 + EOF + echo Prop-content-length: $(wc -c <props) && + echo Content-length: $(wc -c <props) && + echo && + cat props && + cat <<-\EOF + + Node-path: empty-file + Node-kind: file + Node-action: add + Content-length: 0 + + EOF + } >emptyfile.dump && + test-svn-fe emptyfile.dump >stream && + git fast-import <stream && + git log --format=%an HEAD >actual.author && + git log --date=short --format=%ad HEAD >actual.date && + git ls-tree -r --name-only HEAD >actual.files && + test_cmp expect.author actual.author && + test_cmp expect.date actual.date && + test_cmp expect.files actual.files && + git checkout HEAD empty-file && + test_cmp empty file +' + +test_expect_success 'directory with files' ' + reinit_git && + printf "%s\n" directory/file1 directory/file2 >expect.files && + echo hi >hi && + echo hello >hello && + { + properties \ + svn:author author@example.com \ + svn:date "1999-02-01T00:01:002.000000Z" \ + svn:log "add directory with some files in it" && + echo PROPS-END + } >props && + { + cat <<-EOF && + SVN-fs-dump-format-version: 3 + + Revision-number: 1 + EOF + echo Prop-content-length: $(wc -c <props) && + echo Content-length: $(wc -c <props) && + echo && + cat props && + cat <<-\EOF && + + Node-path: directory + Node-kind: dir + Node-action: add + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: directory/file1 + Node-kind: file + Node-action: add + EOF + text_no_props hello && + cat <<-\EOF && + Node-path: directory/file2 + Node-kind: file + Node-action: add + EOF + text_no_props hi + } >directory.dump && + test-svn-fe directory.dump >stream && + git fast-import <stream && + + git ls-tree -r --name-only HEAD >actual.files && + git checkout HEAD directory && + test_cmp expect.files actual.files && + test_cmp hello directory/file1 && + test_cmp hi directory/file2 +' + +test_expect_success 'node without action' ' + cat >inaction.dump <<-\EOF && + SVN-fs-dump-format-version: 3 + + Revision-number: 1 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: directory + Node-kind: dir + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + EOF + test_must_fail test-svn-fe inaction.dump +' + +test_expect_success 'action: add node without text' ' + cat >textless.dump <<-\EOF && + SVN-fs-dump-format-version: 3 + + Revision-number: 1 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: textless + Node-kind: file + Node-action: add + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + EOF + test_must_fail test-svn-fe textless.dump +' + +test_expect_failure 'change file mode but keep old content' ' + reinit_git && + cat >expect <<-\EOF && + OBJID + :120000 100644 OBJID OBJID T greeting + OBJID + :100644 120000 OBJID OBJID T greeting + OBJID + :000000 100644 OBJID OBJID A greeting + EOF + echo "link hello" >expect.blob && + echo hello >hello && + cat >filemode.dump <<-\EOF && + SVN-fs-dump-format-version: 3 + + Revision-number: 1 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: greeting + Node-kind: file + Node-action: add + Prop-content-length: 10 + Text-content-length: 11 + Content-length: 21 + + PROPS-END + link hello + + Revision-number: 2 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: greeting + Node-kind: file + Node-action: change + Prop-content-length: 33 + Content-length: 33 + + K 11 + svn:special + V 1 + * + PROPS-END + + Revision-number: 3 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: greeting + Node-kind: file + Node-action: change + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + EOF + test-svn-fe filemode.dump >stream && + git fast-import <stream && + { + git rev-list HEAD | + git diff-tree --root --stdin | + sed "s/$_x40/OBJID/g" + } >actual && + git show HEAD:greeting >actual.blob && + git show HEAD^:greeting >actual.target && + test_cmp expect actual && + test_cmp expect.blob actual.blob && + test_cmp hello actual.target +' + +test_expect_success 'change file mode and reiterate content' ' + reinit_git && + cat >expect <<-\EOF && + OBJID + :120000 100644 OBJID OBJID T greeting + OBJID + :100644 120000 OBJID OBJID T greeting + OBJID + :000000 100644 OBJID OBJID A greeting + EOF + echo "link hello" >expect.blob && + echo hello >hello && + cat >filemode.dump <<-\EOF && + SVN-fs-dump-format-version: 3 + + Revision-number: 1 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: greeting + Node-kind: file + Node-action: add + Prop-content-length: 10 + Text-content-length: 11 + Content-length: 21 + + PROPS-END + link hello + + Revision-number: 2 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: greeting + Node-kind: file + Node-action: change + Prop-content-length: 33 + Text-content-length: 11 + Content-length: 44 + + K 11 + svn:special + V 1 + * + PROPS-END + link hello + + Revision-number: 3 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: greeting + Node-kind: file + Node-action: change + Prop-content-length: 10 + Text-content-length: 11 + Content-length: 21 + + PROPS-END + link hello + EOF + test-svn-fe filemode.dump >stream && + git fast-import <stream && + { + git rev-list HEAD | + git diff-tree --root --stdin | + sed "s/$_x40/OBJID/g" + } >actual && + git show HEAD:greeting >actual.blob && + git show HEAD^:greeting >actual.target && + test_cmp expect actual && + test_cmp expect.blob actual.blob && + test_cmp hello actual.target +' + +test_expect_success 'deltas not supported' ' + { + # (old) h + (inline) ello + (old) \n + printf "SVNQ%b%b%s" "Q\003\006\005\004" "\001Q\0204\001\002" "ello" | + q_to_nul + } >delta && + { + properties \ + svn:author author@example.com \ + svn:date "1999-01-05T00:01:002.000000Z" \ + svn:log "add greeting" && + echo PROPS-END + } >props && + { + properties \ + svn:author author@example.com \ + svn:date "1999-01-06T00:01:002.000000Z" \ + svn:log "change it" && + echo PROPS-END + } >props2 && + { + echo SVN-fs-dump-format-version: 3 && + echo && + echo Revision-number: 1 && + echo Prop-content-length: $(wc -c <props) && + echo Content-length: $(wc -c <props) && + echo && + cat props && + cat <<-\EOF && + + Node-path: hello + Node-kind: file + Node-action: add + Prop-content-length: 10 + Text-content-length: 3 + Content-length: 13 + + PROPS-END + hi + + EOF + echo Revision-number: 2 && + echo Prop-content-length: $(wc -c <props2) && + echo Content-length: $(wc -c <props2) && + echo && + cat props2 && + cat <<-\EOF && + + Node-path: hello + Node-kind: file + Node-action: change + Text-delta: true + Prop-content-length: 10 + EOF + echo Text-content-length: $(wc -c <delta) && + echo Content-length: $((10 + $(wc -c <delta))) && + echo && + echo PROPS-END && + cat delta + } >delta.dump && + test_must_fail test-svn-fe delta.dump +' + +test_expect_success 'property deltas supported' ' + reinit_git && + cat >expect <<-\EOF && + OBJID + :100755 100644 OBJID OBJID M script.sh + EOF + { + properties \ + svn:author author@example.com \ + svn:date "1999-03-06T00:01:002.000000Z" \ + svn:log "make an executable, or chmod -x it" && + echo PROPS-END + } >revprops && + { + echo SVN-fs-dump-format-version: 3 && + echo && + echo Revision-number: 1 && + echo Prop-content-length: $(wc -c <revprops) && + echo Content-length: $(wc -c <revprops) && + echo && + cat revprops && + echo && + cat <<-\EOF && + Node-path: script.sh + Node-kind: file + Node-action: add + Text-content-length: 0 + Prop-content-length: 39 + Content-length: 39 + + K 14 + svn:executable + V 4 + true + PROPS-END + + EOF + echo Revision-number: 2 && + echo Prop-content-length: $(wc -c <revprops) && + echo Content-length: $(wc -c <revprops) && + echo && + cat revprops && + echo && + cat <<-\EOF + Node-path: script.sh + Node-kind: file + Node-action: change + Prop-delta: true + Prop-content-length: 30 + Content-length: 30 + + D 14 + svn:executable + PROPS-END + EOF + } >propdelta.dump && + test-svn-fe propdelta.dump >stream && + git fast-import <stream && + { + git rev-list HEAD | + git diff-tree --stdin | + sed "s/$_x40/OBJID/g" + } >actual && + test_cmp expect actual +' + +test_expect_success 'properties on /' ' + reinit_git && + cat <<-\EOF >expect && + OBJID + OBJID + :000000 100644 OBJID OBJID A greeting + EOF + sed -e "s/X$//" <<-\EOF >changeroot.dump && + SVN-fs-dump-format-version: 3 + + Revision-number: 1 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: greeting + Node-kind: file + Node-action: add + Text-content-length: 0 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Revision-number: 2 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: X + Node-kind: dir + Node-action: change + Prop-delta: true + Prop-content-length: 43 + Content-length: 43 + + K 10 + svn:ignore + V 11 + build-area + + PROPS-END + EOF + test-svn-fe changeroot.dump >stream && + git fast-import <stream && + { + git rev-list HEAD | + git diff-tree --root --always --stdin | + sed "s/$_x40/OBJID/g" + } >actual && + test_cmp expect actual +' + +test_expect_success 'deltas for typechange' ' + reinit_git && + cat >expect <<-\EOF && + OBJID + :120000 100644 OBJID OBJID T test-file + OBJID + :100755 120000 OBJID OBJID T test-file + OBJID + :000000 100755 OBJID OBJID A test-file + EOF + cat >deleteprop.dump <<-\EOF && + SVN-fs-dump-format-version: 3 + + Revision-number: 1 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: test-file + Node-kind: file + Node-action: add + Prop-delta: true + Prop-content-length: 35 + Text-content-length: 17 + Content-length: 52 + + K 14 + svn:executable + V 0 + + PROPS-END + link testing 123 + + Revision-number: 2 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: test-file + Node-kind: file + Node-action: change + Prop-delta: true + Prop-content-length: 53 + Text-content-length: 17 + Content-length: 70 + + K 11 + svn:special + V 1 + * + D 14 + svn:executable + PROPS-END + link testing 231 + + Revision-number: 3 + Prop-content-length: 10 + Content-length: 10 + + PROPS-END + + Node-path: test-file + Node-kind: file + Node-action: change + Prop-delta: true + Prop-content-length: 27 + Text-content-length: 17 + Content-length: 44 + + D 11 + svn:special + PROPS-END + link testing 321 + EOF + test-svn-fe deleteprop.dump >stream && + git fast-import <stream && + { + git rev-list HEAD | + git diff-tree --root --stdin | + sed "s/$_x40/OBJID/g" + } >actual && + test_cmp expect actual +' + + test_expect_success 'set up svn repo' ' svnconf=$PWD/svnconf && mkdir -p "$svnconf" && diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 986bc14d58..6b1ba6c858 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -42,6 +42,14 @@ echo "$@"' >empty +test_expect_success 'setup: have pipes?' ' + rm -f frob && + if mkfifo frob + then + test_set_prereq PIPE + fi +' + ### ### series A ### @@ -898,6 +906,77 @@ test_expect_success \ git diff-tree -C --find-copies-harder -r N4^ N4 >actual && compare_diff_raw expect actual' +test_expect_success PIPE 'N: read and copy directory' ' + cat >expect <<-\EOF + :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf file3/newf + :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100 file2/oldf file3/oldf + EOF + git update-ref -d refs/heads/N4 && + rm -f backflow && + mkfifo backflow && + ( + exec <backflow && + cat <<-EOF && + commit refs/heads/N4 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + copy by tree hash, part 2 + COMMIT + + from refs/heads/branch^0 + ls "file2" + EOF + read mode type tree filename && + echo "M 040000 $tree file3" + ) | + git fast-import --cat-blob-fd=3 3>backflow && + git diff-tree -C --find-copies-harder -r N4^ N4 >actual && + compare_diff_raw expect actual +' + +test_expect_success PIPE 'N: empty directory reads as missing' ' + cat <<-\EOF >expect && + OBJNAME + :000000 100644 OBJNAME OBJNAME A unrelated + EOF + echo "missing src" >expect.response && + git update-ref -d refs/heads/read-empty && + rm -f backflow && + mkfifo backflow && + ( + exec <backflow && + cat <<-EOF && + commit refs/heads/read-empty + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + read "empty" (missing) directory + COMMIT + + M 100644 inline src/greeting + data <<BLOB + hello + BLOB + C src/greeting dst1/non-greeting + C src/greeting unrelated + # leave behind "empty" src directory + D src/greeting + ls "src" + EOF + read -r line && + printf "%s\n" "$line" >response && + cat <<-\EOF + D dst1 + D dst2 + EOF + ) | + git fast-import --cat-blob-fd=3 3>backflow && + test_cmp expect.response response && + git rev-list read-empty | + git diff-tree -r --root --stdin | + sed "s/$_x40/OBJNAME/g" >actual && + test_cmp expect actual +' + test_expect_success \ 'N: copy root directory by tree hash' \ 'cat >expect <<-\EOF && @@ -1748,6 +1827,61 @@ test_expect_success \ 'cat input | git fast-import --export-marks=other.marks && grep :1 other.marks' +test_expect_success 'R: catch typo in marks file name' ' + test_must_fail git fast-import --import-marks=nonexistent.marks </dev/null && + echo "feature import-marks=nonexistent.marks" | + test_must_fail git fast-import +' + +test_expect_success 'R: import and output marks can be the same file' ' + rm -f io.marks && + blob=$(echo hi | git hash-object --stdin) && + cat >expect <<-EOF && + :1 $blob + :2 $blob + EOF + git fast-import --export-marks=io.marks <<-\EOF && + blob + mark :1 + data 3 + hi + + EOF + git fast-import --import-marks=io.marks --export-marks=io.marks <<-\EOF && + blob + mark :2 + data 3 + hi + + EOF + test_cmp expect io.marks +' + +test_expect_success 'R: --import-marks=foo --output-marks=foo to create foo fails' ' + rm -f io.marks && + test_must_fail git fast-import --import-marks=io.marks --export-marks=io.marks <<-\EOF + blob + mark :1 + data 3 + hi + + EOF +' + +test_expect_success 'R: --import-marks-if-exists' ' + rm -f io.marks && + blob=$(echo hi | git hash-object --stdin) && + echo ":1 $blob" >expect && + git fast-import --import-marks-if-exists=io.marks --export-marks=io.marks <<-\EOF && + blob + mark :1 + data 3 + hi + + EOF + test_cmp expect io.marks +' + cat >input << EOF feature import-marks=marks.out feature export-marks=marks.new @@ -1806,6 +1940,11 @@ test_expect_success 'R: feature no-relative-marks should be honoured' ' test_cmp marks.new non-relative.out ' +test_expect_success 'R: feature ls supported' ' + echo "feature ls" | + git fast-import +' + test_expect_success 'R: feature cat-blob supported' ' echo "feature cat-blob" | git fast-import @@ -1931,14 +2070,6 @@ test_expect_success 'R: print two blobs to stdout' ' test_cmp expect actual ' -test_expect_success 'setup: have pipes?' ' - rm -f frob && - if mkfifo frob - then - test_set_prereq PIPE - fi -' - test_expect_success PIPE 'R: copy using cat-file' ' expect_id=$(git hash-object big) && expect_len=$(wc -c <big) && diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 35c151d7ea..afac5b56a8 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -446,6 +446,8 @@ test_expect_success \ test_expect_success \ 'encode(commit): utf8' \ '. "$TEST_DIRECTORY"/t3901-utf8.txt && + test_when_finished "GIT_AUTHOR_NAME=\"A U Thor\"" && + test_when_finished "GIT_COMMITTER_NAME=\"C O Mitter\"" && echo "UTF-8" >> file && git add file && git commit -F "$TEST_DIRECTORY"/t3900/1-UTF-8.txt && @@ -454,11 +456,13 @@ test_expect_success \ test_expect_success \ 'encode(commit): iso-8859-1' \ '. "$TEST_DIRECTORY"/t3901-8859-1.txt && + test_when_finished "GIT_AUTHOR_NAME=\"A U Thor\"" && + test_when_finished "GIT_COMMITTER_NAME=\"C O Mitter\"" && echo "ISO-8859-1" >> file && git add file && git config i18n.commitencoding ISO-8859-1 && + test_when_finished "git config --unset i18n.commitencoding" && git commit -F "$TEST_DIRECTORY"/t3900/ISO8859-1.txt && - git config --unset i18n.commitencoding && gitweb_run "p=.git;a=commit"' test_expect_success \ diff --git a/t/t9800-git-p4.sh b/t/t9800-git-p4.sh new file mode 100755 index 0000000000..abe7c64ba9 --- /dev/null +++ b/t/t9800-git-p4.sh @@ -0,0 +1,116 @@ +#!/bin/sh + +test_description='git-p4 tests' + +. ./test-lib.sh + +( p4 -h && p4d -h ) >/dev/null 2>&1 || { + skip_all='skipping git-p4 tests; no p4 or p4d' + test_done +} + +GITP4=$GIT_BUILD_DIR/contrib/fast-import/git-p4 +P4DPORT=10669 + +db="$TRASH_DIRECTORY/db" +cli="$TRASH_DIRECTORY/cli" +git="$TRASH_DIRECTORY/git" + +test_debug 'echo p4d -q -d -r "$db" -p $P4DPORT' +test_expect_success setup ' + mkdir -p "$db" && + p4d -q -d -r "$db" -p $P4DPORT && + mkdir -p "$cli" && + mkdir -p "$git" && + export P4PORT=localhost:$P4DPORT +' + +test_expect_success 'add p4 files' ' + cd "$cli" && + p4 client -i <<-EOF && + Client: client + Description: client + Root: $cli + View: //depot/... //client/... + EOF + export P4CLIENT=client && + echo file1 >file1 && + p4 add file1 && + p4 submit -d "file1" && + echo file2 >file2 && + p4 add file2 && + p4 submit -d "file2" && + cd "$TRASH_DIRECTORY" +' + +test_expect_success 'basic git-p4 clone' ' + "$GITP4" clone --dest="$git" //depot && + cd "$git" && + git log --oneline >lines && + test_line_count = 1 lines && + cd .. && + rm -rf "$git" && mkdir "$git" +' + +test_expect_success 'git-p4 clone @all' ' + "$GITP4" clone --dest="$git" //depot@all && + cd "$git" && + git log --oneline >lines && + test_line_count = 2 lines && + cd .. && + rm -rf "$git" && mkdir "$git" +' + +test_expect_success 'exit when p4 fails to produce marshaled output' ' + badp4dir="$TRASH_DIRECTORY/badp4dir" && + mkdir -p "$badp4dir" && + cat >"$badp4dir"/p4 <<-EOF && + #!$SHELL_PATH + exit 1 + EOF + chmod 755 "$badp4dir"/p4 && + PATH="$badp4dir:$PATH" "$GITP4" clone --dest="$git" //depot >errs 2>&1 ; retval=$? && + test $retval -eq 1 && + test_must_fail grep -q Traceback errs +' + +test_expect_success 'add p4 files with wildcards in the names' ' + cd "$cli" && + echo file-wild-hash >file-wild#hash && + echo file-wild-star >file-wild\*star && + echo file-wild-at >file-wild@at && + echo file-wild-percent >file-wild%percent && + p4 add -f file-wild* && + p4 submit -d "file wildcards" && + cd "$TRASH_DIRECTORY" +' + +test_expect_success 'wildcard files git-p4 clone' ' + "$GITP4" clone --dest="$git" //depot && + cd "$git" && + test -f file-wild#hash && + test -f file-wild\*star && + test -f file-wild@at && + test -f file-wild%percent && + cd "$TRASH_DIRECTORY" && + rm -rf "$git" && mkdir "$git" +' + +test_expect_success 'clone bare' ' + "$GITP4" clone --dest="$git" --bare //depot && + cd "$git" && + test ! -d .git && + bare=`git config --get core.bare` && + test "$bare" = true && + cd "$TRASH_DIRECTORY" && + rm -rf "$git" && mkdir "$git" +' + +test_expect_success 'shutdown' ' + pid=`pgrep -f p4d` && + test -n "$pid" && + test_debug "ps wl `echo $pid`" && + kill $pid +' + +test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 0fdc541a7c..f4c1e04e4f 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1079,6 +1079,15 @@ esac test -z "$NO_PERL" && test_set_prereq PERL test -z "$NO_PYTHON" && test_set_prereq PYTHON +# Can we rely on git's output in the C locale? +if test -n "$GETTEXT_POISON" +then + GIT_GETTEXT_POISON=YesPlease + export GIT_GETTEXT_POISON +else + test_set_prereq C_LOCALE_OUTPUT +fi + # test whether the filesystem supports symbolic links ln -s x y 2>/dev/null && test -h y 2>/dev/null && test_set_prereq SYMLINKS rm -f y diff --git a/test-line-buffer.c b/test-line-buffer.c index c11bf7f967..25b20b93fd 100644 --- a/test-line-buffer.c +++ b/test-line-buffer.c @@ -1,14 +1,9 @@ /* * test-line-buffer.c: code to exercise the svn importer's input helper - * - * Input format: - * number NL - * (number bytes) NL - * number NL - * ... */ #include "git-compat-util.h" +#include "strbuf.h" #include "vcs-svn/line_buffer.h" static uint32_t strtouint32(const char *s) @@ -20,27 +15,84 @@ static uint32_t strtouint32(const char *s) return (uint32_t) n; } +static void handle_command(const char *command, const char *arg, struct line_buffer *buf) +{ + switch (*command) { + case 'b': + if (!prefixcmp(command, "binary ")) { + struct strbuf sb = STRBUF_INIT; + strbuf_addch(&sb, '>'); + buffer_read_binary(buf, &sb, strtouint32(arg)); + fwrite(sb.buf, 1, sb.len, stdout); + strbuf_release(&sb); + return; + } + case 'c': + if (!prefixcmp(command, "copy ")) { + buffer_copy_bytes(buf, strtouint32(arg)); + return; + } + case 'r': + if (!prefixcmp(command, "read ")) { + const char *s = buffer_read_string(buf, strtouint32(arg)); + fputs(s, stdout); + return; + } + case 's': + if (!prefixcmp(command, "skip ")) { + buffer_skip_bytes(buf, strtouint32(arg)); + return; + } + default: + die("unrecognized command: %s", command); + } +} + +static void handle_line(const char *line, struct line_buffer *stdin_buf) +{ + const char *arg = strchr(line, ' '); + if (!arg) + die("no argument in line: %s", line); + handle_command(line, arg + 1, stdin_buf); +} + int main(int argc, char *argv[]) { + struct line_buffer stdin_buf = LINE_BUFFER_INIT; + struct line_buffer file_buf = LINE_BUFFER_INIT; + struct line_buffer *input = &stdin_buf; + const char *filename; char *s; - if (argc != 1) - usage("test-line-buffer < input.txt"); - if (buffer_init(NULL)) + if (argc == 1) + filename = NULL; + else if (argc == 2) + filename = argv[1]; + else + usage("test-line-buffer [file | &fd] < script"); + + if (buffer_init(&stdin_buf, NULL)) die_errno("open error"); - while ((s = buffer_read_line())) { - s = buffer_read_string(strtouint32(s)); - fputs(s, stdout); - fputc('\n', stdout); - buffer_skip_bytes(1); - if (!(s = buffer_read_line())) - break; - buffer_copy_bytes(strtouint32(s) + 1); + if (filename) { + if (*filename == '&') { + if (buffer_fdinit(&file_buf, strtouint32(filename + 1))) + die_errno("error opening fd %s", filename + 1); + } else { + if (buffer_init(&file_buf, filename)) + die_errno("error opening %s", filename); + } + input = &file_buf; } - if (buffer_deinit()) + + while ((s = buffer_read_line(&stdin_buf))) + handle_line(s, input); + + if (filename && buffer_deinit(&file_buf)) + die("error reading from %s", filename); + if (buffer_deinit(&stdin_buf)) die("input error"); if (ferror(stdout)) die("output error"); - buffer_reset(); + buffer_reset(&stdin_buf); return 0; } diff --git a/test-path-utils.c b/test-path-utils.c index d261398d6c..e7671593df 100644 --- a/test-path-utils.c +++ b/test-path-utils.c @@ -11,9 +11,9 @@ int main(int argc, char **argv) return 0; } - if (argc >= 2 && !strcmp(argv[1], "make_absolute_path")) { + if (argc >= 2 && !strcmp(argv[1], "real_path")) { while (argc > 2) { - puts(make_absolute_path(argv[2])); + puts(real_path(argv[2])); argc--; argv++; } diff --git a/test-svn-fe.c b/test-svn-fe.c index 77cf78abcf..b42ba789b1 100644 --- a/test-svn-fe.c +++ b/test-svn-fe.c @@ -9,7 +9,8 @@ int main(int argc, char *argv[]) { if (argc != 2) usage("test-svn-fe <file>"); - svndump_init(argv[1]); + if (svndump_init(argv[1])) + return 1; svndump_read(NULL); svndump_deinit(); svndump_reset(); @@ -25,10 +25,10 @@ #include "cache.h" #include "quote.h" -/* Get a trace file descriptor from GIT_TRACE env variable. */ -static int get_trace_fd(int *need_close) +/* Get a trace file descriptor from "key" env variable. */ +static int get_trace_fd(const char *key, int *need_close) { - char *trace = getenv("GIT_TRACE"); + char *trace = getenv(key); if (!trace || !strcmp(trace, "") || !strcmp(trace, "0") || !strcasecmp(trace, "false")) @@ -50,10 +50,10 @@ static int get_trace_fd(int *need_close) return fd; } - fprintf(stderr, "What does '%s' for GIT_TRACE mean?\n", trace); + fprintf(stderr, "What does '%s' for %s mean?\n", trace, key); fprintf(stderr, "If you want to trace into a file, " - "then please set GIT_TRACE to an absolute pathname " - "(starting with /).\n"); + "then please set %s to an absolute pathname " + "(starting with /).\n", key); fprintf(stderr, "Defaulting to tracing on stderr...\n"); return STDERR_FILENO; @@ -62,33 +62,44 @@ static int get_trace_fd(int *need_close) static const char err_msg[] = "Could not trace into fd given by " "GIT_TRACE environment variable"; -void trace_printf(const char *fmt, ...) +void trace_vprintf(const char *key, const char *fmt, va_list ap) { - struct strbuf buf; - va_list ap; - int fd, len, need_close = 0; + struct strbuf buf = STRBUF_INIT; - fd = get_trace_fd(&need_close); - if (!fd) + if (!trace_want(key)) return; set_try_to_free_routine(NULL); /* is never reset */ - strbuf_init(&buf, 64); + strbuf_vaddf(&buf, fmt, ap); + trace_strbuf(key, &buf); + strbuf_release(&buf); +} + +void trace_printf_key(const char *key, const char *fmt, ...) +{ + va_list ap; va_start(ap, fmt); - len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap); + trace_vprintf(key, fmt, ap); va_end(ap); - if (len >= strbuf_avail(&buf)) { - strbuf_grow(&buf, len - strbuf_avail(&buf) + 128); - va_start(ap, fmt); - len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap); - va_end(ap); - if (len >= strbuf_avail(&buf)) - die("broken vsnprintf"); - } - strbuf_setlen(&buf, len); +} - write_or_whine_pipe(fd, buf.buf, buf.len, err_msg); - strbuf_release(&buf); +void trace_printf(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + trace_vprintf("GIT_TRACE", fmt, ap); + va_end(ap); +} + +void trace_strbuf(const char *key, const struct strbuf *buf) +{ + int fd, need_close = 0; + + fd = get_trace_fd(key, &need_close); + if (!fd) + return; + + write_or_whine_pipe(fd, buf->buf, buf->len, err_msg); if (need_close) close(fd); @@ -96,28 +107,18 @@ void trace_printf(const char *fmt, ...) void trace_argv_printf(const char **argv, const char *fmt, ...) { - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; va_list ap; - int fd, len, need_close = 0; + int fd, need_close = 0; - fd = get_trace_fd(&need_close); + fd = get_trace_fd("GIT_TRACE", &need_close); if (!fd) return; set_try_to_free_routine(NULL); /* is never reset */ - strbuf_init(&buf, 64); va_start(ap, fmt); - len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap); + strbuf_vaddf(&buf, fmt, ap); va_end(ap); - if (len >= strbuf_avail(&buf)) { - strbuf_grow(&buf, len - strbuf_avail(&buf) + 128); - va_start(ap, fmt); - len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap); - va_end(ap); - if (len >= strbuf_avail(&buf)) - die("broken vsnprintf"); - } - strbuf_setlen(&buf, len); sq_quote_argv(&buf, argv, 0); strbuf_addch(&buf, '\n'); @@ -154,12 +155,11 @@ static const char *quote_crnl(const char *path) /* FIXME: move prefix to startup_info struct and get rid of this arg */ void trace_repo_setup(const char *prefix) { + static const char *key = "GIT_TRACE_SETUP"; const char *git_work_tree; char cwd[PATH_MAX]; - char *trace = getenv("GIT_TRACE"); - if (!trace || !strcmp(trace, "") || - !strcmp(trace, "0") || !strcasecmp(trace, "false")) + if (!trace_want(key)) return; if (!getcwd(cwd, PATH_MAX)) @@ -171,8 +171,18 @@ void trace_repo_setup(const char *prefix) if (!prefix) prefix = "(null)"; - trace_printf("setup: git_dir: %s\n", quote_crnl(get_git_dir())); - trace_printf("setup: worktree: %s\n", quote_crnl(git_work_tree)); - trace_printf("setup: cwd: %s\n", quote_crnl(cwd)); - trace_printf("setup: prefix: %s\n", quote_crnl(prefix)); + trace_printf_key(key, "setup: git_dir: %s\n", quote_crnl(get_git_dir())); + trace_printf_key(key, "setup: worktree: %s\n", quote_crnl(git_work_tree)); + trace_printf_key(key, "setup: cwd: %s\n", quote_crnl(cwd)); + trace_printf_key(key, "setup: prefix: %s\n", quote_crnl(prefix)); +} + +int trace_want(const char *key) +{ + const char *trace = getenv(key); + + if (!trace || !strcmp(trace, "") || + !strcmp(trace, "0") || !strcasecmp(trace, "false")) + return 0; + return 1; } diff --git a/transport-helper.c b/transport-helper.c index 8866adf088..0c5b1bd994 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -972,7 +972,7 @@ static int udt_do_read(struct unidirectional_transfer *t) */ static int udt_do_write(struct unidirectional_transfer *t) { - size_t bytes; + ssize_t bytes; if (t->bufuse == 0) return 0; /* Nothing to write. */ diff --git a/tree-diff.c b/tree-diff.c index 12c9a88884..3954281f50 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -6,34 +6,18 @@ #include "diffcore.h" #include "tree.h" -static char *malloc_base(const char *base, int baselen, const char *path, int pathlen) -{ - char *newbase = xmalloc(baselen + pathlen + 2); - memcpy(newbase, base, baselen); - memcpy(newbase + baselen, path, pathlen); - memcpy(newbase + baselen + pathlen, "/", 2); - return newbase; -} +static void show_entry(struct diff_options *opt, const char *prefix, + struct tree_desc *desc, struct strbuf *base); -static char *malloc_fullname(const char *base, int baselen, const char *path, int pathlen) -{ - char *fullname = xmalloc(baselen + pathlen + 1); - memcpy(fullname, base, baselen); - memcpy(fullname + baselen, path, pathlen); - fullname[baselen + pathlen] = 0; - return fullname; -} - -static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc, - const char *base, int baselen); - -static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, int baselen, struct diff_options *opt) +static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, + struct strbuf *base, struct diff_options *opt) { unsigned mode1, mode2; const char *path1, *path2; const unsigned char *sha1, *sha2; int cmp, pathlen1, pathlen2; - char *fullname; + int old_baselen = base->len; + int retval = 0; sha1 = tree_entry_extract(t1, &path1, &mode1); sha2 = tree_entry_extract(t2, &path2, &mode2); @@ -42,11 +26,11 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const pathlen2 = tree_entry_len(path2, sha2); cmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2); if (cmp < 0) { - show_entry(opt, "-", t1, base, baselen); + show_entry(opt, "-", t1, base); return -1; } if (cmp > 0) { - show_entry(opt, "+", t2, base, baselen); + show_entry(opt, "+", t2, base); return 1; } if (!DIFF_OPT_TST(opt, FIND_COPIES_HARDER) && !hashcmp(sha1, sha2) && mode1 == mode2) @@ -57,149 +41,29 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const * file, we need to consider it a remove and an add. */ if (S_ISDIR(mode1) != S_ISDIR(mode2)) { - show_entry(opt, "-", t1, base, baselen); - show_entry(opt, "+", t2, base, baselen); + show_entry(opt, "-", t1, base); + show_entry(opt, "+", t2, base); return 0; } + strbuf_add(base, path1, pathlen1); if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode1)) { - int retval; - char *newbase = malloc_base(base, baselen, path1, pathlen1); if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) { - newbase[baselen + pathlen1] = 0; opt->change(opt, mode1, mode2, - sha1, sha2, newbase, 0, 0); - newbase[baselen + pathlen1] = '/'; + sha1, sha2, base->buf, 0, 0); } - retval = diff_tree_sha1(sha1, sha2, newbase, opt); - free(newbase); - return retval; + strbuf_addch(base, '/'); + retval = diff_tree_sha1(sha1, sha2, base->buf, opt); + } else { + opt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0); } - - fullname = malloc_fullname(base, baselen, path1, pathlen1); - opt->change(opt, mode1, mode2, sha1, sha2, fullname, 0, 0); - free(fullname); + strbuf_setlen(base, old_baselen); return 0; } -/* - * Is a tree entry interesting given the pathspec we have? - * - * Pre-condition: baselen == 0 || base[baselen-1] == '/' - * - * Return: - * - 2 for "yes, and all subsequent entries will be" - * - 1 for yes - * - zero for no - * - negative for "no, and no subsequent entries will be either" - */ -static int tree_entry_interesting(struct tree_desc *desc, const char *base, int baselen, struct diff_options *opt) -{ - const char *path; - const unsigned char *sha1; - unsigned mode; - int i; - int pathlen; - int never_interesting = -1; - - if (!opt->nr_paths) - return 2; - - sha1 = tree_entry_extract(desc, &path, &mode); - - pathlen = tree_entry_len(path, sha1); - - for (i = 0; i < opt->nr_paths; i++) { - const char *match = opt->paths[i]; - int matchlen = opt->pathlens[i]; - int m = -1; /* signals that we haven't called strncmp() */ - - if (baselen >= matchlen) { - /* If it doesn't match, move along... */ - if (strncmp(base, match, matchlen)) - continue; - - /* - * If the base is a subdirectory of a path which - * was specified, all of them are interesting. - */ - if (!matchlen || - base[matchlen] == '/' || - match[matchlen - 1] == '/') - return 2; - - /* Just a random prefix match */ - continue; - } - - /* Does the base match? */ - if (strncmp(base, match, baselen)) - continue; - - match += baselen; - matchlen -= baselen; - - if (never_interesting) { - /* - * We have not seen any match that sorts later - * than the current path. - */ - - /* - * Does match sort strictly earlier than path - * with their common parts? - */ - m = strncmp(match, path, - (matchlen < pathlen) ? matchlen : pathlen); - if (m < 0) - continue; - - /* - * If we come here even once, that means there is at - * least one pathspec that would sort equal to or - * later than the path we are currently looking at. - * In other words, if we have never reached this point - * after iterating all pathspecs, it means all - * pathspecs are either outside of base, or inside the - * base but sorts strictly earlier than the current - * one. In either case, they will never match the - * subsequent entries. In such a case, we initialized - * the variable to -1 and that is what will be - * returned, allowing the caller to terminate early. - */ - never_interesting = 0; - } - - if (pathlen > matchlen) - continue; - - if (matchlen > pathlen) { - if (match[pathlen] != '/') - continue; - if (!S_ISDIR(mode)) - continue; - } - - if (m == -1) - /* - * we cheated and did not do strncmp(), so we do - * that here. - */ - m = strncmp(match, path, pathlen); - - /* - * If common part matched earlier then it is a hit, - * because we rejected the case where path is not a - * leading directory and is shorter than match. - */ - if (!m) - return 1; - } - return never_interesting; /* No matches */ -} - /* A whole sub-tree went away or appeared */ -static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base, int baselen) +static void show_tree(struct diff_options *opt, const char *prefix, + struct tree_desc *desc, struct strbuf *base) { int all_interesting = 0; while (desc->size) { @@ -208,31 +72,32 @@ static void show_tree(struct diff_options *opt, const char *prefix, struct tree_ if (all_interesting) show = 1; else { - show = tree_entry_interesting(desc, base, baselen, - opt); + show = tree_entry_interesting(&desc->entry, base, 0, + &opt->pathspec); if (show == 2) all_interesting = 1; } if (show < 0) break; if (show) - show_entry(opt, prefix, desc, base, baselen); + show_entry(opt, prefix, desc, base); update_tree_entry(desc); } } /* A file entry went away or appeared */ -static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc, - const char *base, int baselen) +static void show_entry(struct diff_options *opt, const char *prefix, + struct tree_desc *desc, struct strbuf *base) { unsigned mode; const char *path; const unsigned char *sha1 = tree_entry_extract(desc, &path, &mode); int pathlen = tree_entry_len(path, sha1); + int old_baselen = base->len; + strbuf_add(base, path, pathlen); if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode)) { enum object_type type; - char *newbase = malloc_base(base, baselen, path, pathlen); struct tree_desc inner; void *tree; unsigned long size; @@ -241,28 +106,25 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree if (!tree || type != OBJ_TREE) die("corrupt tree sha %s", sha1_to_hex(sha1)); - if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) { - newbase[baselen + pathlen] = 0; - opt->add_remove(opt, *prefix, mode, sha1, newbase, 0); - newbase[baselen + pathlen] = '/'; - } + if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) + opt->add_remove(opt, *prefix, mode, sha1, base->buf, 0); - init_tree_desc(&inner, tree, size); - show_tree(opt, prefix, &inner, newbase, baselen + 1 + pathlen); + strbuf_addch(base, '/'); + init_tree_desc(&inner, tree, size); + show_tree(opt, prefix, &inner, base); free(tree); - free(newbase); - } else { - char *fullname = malloc_fullname(base, baselen, path, pathlen); - opt->add_remove(opt, prefix[0], mode, sha1, fullname, 0); - free(fullname); - } + } else + opt->add_remove(opt, prefix[0], mode, sha1, base->buf, 0); + + strbuf_setlen(base, old_baselen); } -static void skip_uninteresting(struct tree_desc *t, const char *base, int baselen, struct diff_options *opt, int *all_interesting) +static void skip_uninteresting(struct tree_desc *t, struct strbuf *base, + struct diff_options *opt, int *all_interesting) { while (t->size) { - int show = tree_entry_interesting(t, base, baselen, opt); + int show = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec); if (show == 2) *all_interesting = 1; if (!show) { @@ -276,37 +138,44 @@ static void skip_uninteresting(struct tree_desc *t, const char *base, int basele } } -int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt) +int diff_tree(struct tree_desc *t1, struct tree_desc *t2, + const char *base_str, struct diff_options *opt) { - int baselen = strlen(base); + struct strbuf base; + int baselen = strlen(base_str); int all_t1_interesting = 0; int all_t2_interesting = 0; + /* Enable recursion indefinitely */ + opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE); + opt->pathspec.max_depth = -1; + + strbuf_init(&base, PATH_MAX); + strbuf_add(&base, base_str, baselen); + for (;;) { if (DIFF_OPT_TST(opt, QUICK) && DIFF_OPT_TST(opt, HAS_CHANGES)) break; - if (opt->nr_paths) { + if (opt->pathspec.nr) { if (!all_t1_interesting) - skip_uninteresting(t1, base, baselen, opt, - &all_t1_interesting); + skip_uninteresting(t1, &base, opt, &all_t1_interesting); if (!all_t2_interesting) - skip_uninteresting(t2, base, baselen, opt, - &all_t2_interesting); + skip_uninteresting(t2, &base, opt, &all_t2_interesting); } if (!t1->size) { if (!t2->size) break; - show_entry(opt, "+", t2, base, baselen); + show_entry(opt, "+", t2, &base); update_tree_entry(t2); continue; } if (!t2->size) { - show_entry(opt, "-", t1, base, baselen); + show_entry(opt, "-", t1, &base); update_tree_entry(t1); continue; } - switch (compare_tree_entry(t1, t2, base, baselen, opt)) { + switch (compare_tree_entry(t1, t2, &base, opt)) { case -1: update_tree_entry(t1); continue; @@ -319,6 +188,8 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru } die("git diff-tree: internal error"); } + + strbuf_release(&base); return 0; } @@ -349,7 +220,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co DIFF_OPT_SET(&diff_opts, RECURSIVE); DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER); diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; - diff_opts.single_follow = opt->paths[0]; + diff_opts.single_follow = opt->pathspec.raw[0]; diff_opts.break_opt = opt->break_opt; paths[0] = NULL; diff_tree_setup_paths(paths, &diff_opts); @@ -369,15 +240,16 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co * diff_queued_diff, we will also use that as the path in * the future! */ - if ((p->status == 'R' || p->status == 'C') && !strcmp(p->two->path, opt->paths[0])) { + if ((p->status == 'R' || p->status == 'C') && + !strcmp(p->two->path, opt->pathspec.raw[0])) { /* Switch the file-pairs around */ q->queue[i] = choice; choice = p; /* Update the path we use from now on.. */ diff_tree_release_paths(opt); - opt->paths[0] = xstrdup(p->one->path); - diff_tree_setup_paths(opt->paths, opt); + opt->pathspec.raw[0] = xstrdup(p->one->path); + diff_tree_setup_paths(opt->pathspec.raw, opt); /* * The caller expects us to return a set of vanilla @@ -452,36 +324,12 @@ int diff_root_tree_sha1(const unsigned char *new, const char *base, struct diff_ return retval; } -static int count_paths(const char **paths) -{ - int i = 0; - while (*paths++) - i++; - return i; -} - void diff_tree_release_paths(struct diff_options *opt) { - free(opt->pathlens); + free_pathspec(&opt->pathspec); } void diff_tree_setup_paths(const char **p, struct diff_options *opt) { - opt->nr_paths = 0; - opt->pathlens = NULL; - opt->paths = NULL; - - if (p) { - int i; - - opt->paths = p; - opt->nr_paths = count_paths(p); - if (opt->nr_paths == 0) { - opt->pathlens = NULL; - return; - } - opt->pathlens = xmalloc(opt->nr_paths * sizeof(int)); - for (i=0; i < opt->nr_paths; i++) - opt->pathlens[i] = strlen(p[i]); - } + init_pathspec(&opt->pathspec, p); } diff --git a/tree-walk.c b/tree-walk.c index a9bbf4e235..322becc3b4 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -1,6 +1,7 @@ #include "cache.h" #include "tree-walk.h" #include "unpack-trees.h" +#include "dir.h" #include "tree.h" static const char *get_mode(const char *str, unsigned int *modep) @@ -455,3 +456,186 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch free(tree); return retval; } + +static int match_entry(const struct name_entry *entry, int pathlen, + const char *match, int matchlen, + int *never_interesting) +{ + int m = -1; /* signals that we haven't called strncmp() */ + + if (*never_interesting) { + /* + * We have not seen any match that sorts later + * than the current path. + */ + + /* + * Does match sort strictly earlier than path + * with their common parts? + */ + m = strncmp(match, entry->path, + (matchlen < pathlen) ? matchlen : pathlen); + if (m < 0) + return 0; + + /* + * If we come here even once, that means there is at + * least one pathspec that would sort equal to or + * later than the path we are currently looking at. + * In other words, if we have never reached this point + * after iterating all pathspecs, it means all + * pathspecs are either outside of base, or inside the + * base but sorts strictly earlier than the current + * one. In either case, they will never match the + * subsequent entries. In such a case, we initialized + * the variable to -1 and that is what will be + * returned, allowing the caller to terminate early. + */ + *never_interesting = 0; + } + + if (pathlen > matchlen) + return 0; + + if (matchlen > pathlen) { + if (match[pathlen] != '/') + return 0; + if (!S_ISDIR(entry->mode)) + return 0; + } + + if (m == -1) + /* + * we cheated and did not do strncmp(), so we do + * that here. + */ + m = strncmp(match, entry->path, pathlen); + + /* + * If common part matched earlier then it is a hit, + * because we rejected the case where path is not a + * leading directory and is shorter than match. + */ + if (!m) + return 1; + + return 0; +} + +static int match_dir_prefix(const char *base, int baselen, + const char *match, int matchlen) +{ + if (strncmp(base, match, matchlen)) + return 0; + + /* + * If the base is a subdirectory of a path which + * was specified, all of them are interesting. + */ + if (!matchlen || + base[matchlen] == '/' || + match[matchlen - 1] == '/') + return 1; + + /* Just a random prefix match */ + return 0; +} + +/* + * Is a tree entry interesting given the pathspec we have? + * + * Pre-condition: either baselen == base_offset (i.e. empty path) + * or base[baselen-1] == '/' (i.e. with trailing slash). + * + * Return: + * - 2 for "yes, and all subsequent entries will be" + * - 1 for yes + * - zero for no + * - negative for "no, and no subsequent entries will be either" + */ +int tree_entry_interesting(const struct name_entry *entry, + struct strbuf *base, int base_offset, + const struct pathspec *ps) +{ + int i; + int pathlen, baselen = base->len - base_offset; + int never_interesting = ps->has_wildcard ? 0 : -1; + + if (!ps->nr) { + if (!ps->recursive || ps->max_depth == -1) + return 2; + return !!within_depth(base->buf + base_offset, baselen, + !!S_ISDIR(entry->mode), + ps->max_depth); + } + + pathlen = tree_entry_len(entry->path, entry->sha1); + + for (i = ps->nr - 1; i >= 0; i--) { + const struct pathspec_item *item = ps->items+i; + const char *match = item->match; + const char *base_str = base->buf + base_offset; + int matchlen = item->len; + + if (baselen >= matchlen) { + /* If it doesn't match, move along... */ + if (!match_dir_prefix(base_str, baselen, match, matchlen)) + goto match_wildcards; + + if (!ps->recursive || ps->max_depth == -1) + return 2; + + return !!within_depth(base_str + matchlen + 1, + baselen - matchlen - 1, + !!S_ISDIR(entry->mode), + ps->max_depth); + } + + /* Does the base match? */ + if (!strncmp(base_str, match, baselen)) { + if (match_entry(entry, pathlen, + match + baselen, matchlen - baselen, + &never_interesting)) + return 1; + + if (ps->items[i].has_wildcard) { + if (!fnmatch(match + baselen, entry->path, 0)) + return 1; + + /* + * Match all directories. We'll try to + * match files later on. + */ + if (ps->recursive && S_ISDIR(entry->mode)) + return 1; + } + + continue; + } + +match_wildcards: + if (!ps->items[i].has_wildcard) + continue; + + /* + * Concatenate base and entry->path into one and do + * fnmatch() on it. + */ + + strbuf_add(base, entry->path, pathlen); + + if (!fnmatch(match, base->buf + base_offset, 0)) { + strbuf_setlen(base, base_offset + baselen); + return 1; + } + strbuf_setlen(base, base_offset + baselen); + + /* + * Match all directories. We'll try to match files + * later on. + */ + if (ps->recursive && S_ISDIR(entry->mode)) + return 1; + } + return never_interesting; /* No matches */ +} diff --git a/tree-walk.h b/tree-walk.h index 7e3e0b5ad1..39524b7dba 100644 --- a/tree-walk.h +++ b/tree-walk.h @@ -60,4 +60,6 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru return info->pathlen + tree_entry_len(n->path, n->sha1); } +extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, int, const struct pathspec *ps); + #endif diff --git a/unpack-trees.c b/unpack-trees.c index 1ca41b1a69..b68ec820dd 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -381,7 +381,7 @@ static void add_same_unmerged(struct cache_entry *ce, static int unpack_index_entry(struct cache_entry *ce, struct unpack_trees_options *o) { - struct cache_entry *src[5] = { NULL }; + struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, }; int ret; src[0] = ce; @@ -427,7 +427,10 @@ static int switch_cache_bottom(struct traverse_info *info) return ret; } -static int traverse_trees_recursive(int n, unsigned long dirmask, unsigned long df_conflicts, struct name_entry *names, struct traverse_info *info) +static int traverse_trees_recursive(int n, unsigned long dirmask, + unsigned long df_conflicts, + struct name_entry *names, + struct traverse_info *info) { int i, ret, bottom; struct tree_desc t[MAX_UNPACK_TREES]; @@ -1105,6 +1108,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options } if (o->result.cache_nr && empty_worktree) { + /* dubious---why should this fail??? */ ret = unpack_failed(o, "Sparse checkout leaves no entry on working directory"); goto done; } @@ -1374,16 +1378,22 @@ static int verify_absent_1(struct cache_entry *ce, char path[PATH_MAX + 1]; memcpy(path, ce->name, len); path[len] = 0; - lstat(path, &st); + if (lstat(path, &st)) + return error("cannot stat '%s': %s", path, + strerror(errno)); return check_ok_to_remove(path, len, DT_UNKNOWN, NULL, &st, error_type, o); - } else if (!lstat(ce->name, &st)) + } else if (lstat(ce->name, &st)) { + if (errno != ENOENT) + return error("cannot stat '%s': %s", ce->name, + strerror(errno)); + return 0; + } else { return check_ok_to_remove(ce->name, ce_namelen(ce), - ce_to_dtype(ce), ce, &st, - error_type, o); - - return 0; + ce_to_dtype(ce), ce, &st, + error_type, o); + } } static int verify_absent(struct cache_entry *ce, diff --git a/upload-pack.c b/upload-pack.c index b40a43f27d..0c87bc00f0 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -682,6 +682,7 @@ int main(int argc, char **argv) int i; int strict = 0; + packet_trace_identity("upload-pack"); git_extract_argv0_path(argv[0]); read_replace_refs = 0; diff --git a/userdiff.c b/userdiff.c index 9ebf231ea5..1ff47977d5 100644 --- a/userdiff.c +++ b/userdiff.c @@ -8,9 +8,11 @@ static int ndrivers; static int drivers_alloc; #define PATTERNS(name, pattern, word_regex) \ - { name, NULL, -1, { pattern, REG_EXTENDED }, word_regex } + { name, NULL, -1, { pattern, REG_EXTENDED }, \ + word_regex "|[^[:space:]]|[\xc0-\xff][\x80-\xbf]+" } #define IPATTERN(name, pattern, word_regex) \ - { name, NULL, -1, { pattern, REG_EXTENDED | REG_ICASE }, word_regex } + { name, NULL, -1, { pattern, REG_EXTENDED | REG_ICASE }, \ + word_regex "|[^[:space:]]|[\xc0-\xff][\x80-\xbf]+" } static struct userdiff_driver builtin_drivers[] = { IPATTERN("fortran", "!^([C*]|[ \t]*!)\n" @@ -24,10 +26,9 @@ IPATTERN("fortran", * Don't worry about format statements without leading digits since * they would have been matched above as a variable anyway. */ "|[-+]?[0-9.]+([AaIiDdEeFfLlTtXx][Ss]?[-+]?[0-9.]*)?(_[a-zA-Z0-9][a-zA-Z0-9_]*)?" - "|//|\\*\\*|::|[/<>=]=" - "|[^[:space:]]|[\x80-\xff]+"), + "|//|\\*\\*|::|[/<>=]="), PATTERNS("html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$", - "[^<>= \t]+|[^[:space:]]|[\x80-\xff]+"), + "[^<>= \t]+"), PATTERNS("java", "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n" "^[ \t]*(([A-Za-z_][A-Za-z_0-9]*[ \t]+)+[A-Za-z_][A-Za-z_0-9]*[ \t]*\\([^;]*)$", @@ -35,8 +36,7 @@ PATTERNS("java", "[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?" "|[-+*/<>%&^|=!]=" - "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|" - "|[^[:space:]]|[\x80-\xff]+"), + "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"), PATTERNS("objc", /* Negate C statements that can look like functions */ "!^[ \t]*(do|for|if|else|return|switch|while)\n" @@ -49,8 +49,7 @@ PATTERNS("objc", /* -- */ "[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?" - "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->" - "|[^[:space:]]|[\x80-\xff]+"), + "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"), PATTERNS("pascal", "^(((class[ \t]+)?(procedure|function)|constructor|destructor|interface|" "implementation|initialization|finalization)[ \t]*.*)$" @@ -59,8 +58,7 @@ PATTERNS("pascal", /* -- */ "[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+" - "|<>|<=|>=|:=|\\.\\." - "|[^[:space:]]|[\x80-\xff]+"), + "|<>|<=|>=|:=|\\.\\."), PATTERNS("perl", "^[ \t]*package .*;\n" "^[ \t]*sub .* \\{\n" @@ -76,33 +74,29 @@ PATTERNS("perl", "|&&|\\|\\||//|\\+\\+|--|\\*\\*|\\.\\.\\.?" "|[-+*/%.^&<>=!|]=" "|=~|!~" - "|<<|<>|<=>|>>" - "|[^[:space:]]"), + "|<<|<>|<=>|>>"), PATTERNS("php", "^[\t ]*(((public|protected|private|static)[\t ]+)*function.*)$\n" "^[\t ]*(class.*)$", /* -- */ "[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+" - "|[-+*/<>%&^|=!.]=|--|\\+\\+|<<=?|>>=?|===|&&|\\|\\||::|->" - "|[^[:space:]]|[\x80-\xff]+"), + "|[-+*/<>%&^|=!.]=|--|\\+\\+|<<=?|>>=?|===|&&|\\|\\||::|->"), PATTERNS("python", "^[ \t]*((class|def)[ \t].*)$", /* -- */ "[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+[jJlL]?|0[xX]?[0-9a-fA-F]+[lL]?" - "|[-+*/<>%&^|=!]=|//=?|<<=?|>>=?|\\*\\*=?" - "|[^[:space:]]|[\x80-\xff]+"), + "|[-+*/<>%&^|=!]=|//=?|<<=?|>>=?|\\*\\*=?"), /* -- */ PATTERNS("ruby", "^[ \t]*((class|module|def)[ \t].*)$", /* -- */ "(@|@@|\\$)?[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+|\\?(\\\\C-)?(\\\\M-)?." - "|//=?|[-+*/<>%&^|=!]=|<<=?|>>=?|===|\\.{1,3}|::|[!=]~" - "|[^[:space:]]|[\x80-\xff]+"), + "|//=?|[-+*/<>%&^|=!]=|<<=?|>>=?|===|\\.{1,3}|::|[!=]~"), PATTERNS("bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$", "[={}\"]|[^={}\" \t]+"), PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$", - "\\\\[a-zA-Z@]+|\\\\.|[a-zA-Z0-9\x80-\xff]+|[^[:space:]]"), + "\\\\[a-zA-Z@]+|\\\\.|[a-zA-Z0-9\x80-\xff]+"), PATTERNS("cpp", /* Jump targets or access declarations */ "!^[ \t]*[A-Za-z_][A-Za-z_0-9]*:.*$\n" @@ -113,8 +107,7 @@ PATTERNS("cpp", /* -- */ "[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?" - "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->" - "|[^[:space:]]|[\x80-\xff]+"), + "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"), PATTERNS("csharp", /* Keywords */ "!^[ \t]*(do|while|for|if|else|instanceof|new|return|switch|case|throw|catch|using)\n" @@ -129,8 +122,7 @@ PATTERNS("csharp", /* -- */ "[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?" - "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->" - "|[^[:space:]]|[\x80-\xff]+"), + "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"), { "default", NULL, -1, { NULL, 0 } }, }; #undef PATTERNS @@ -405,6 +405,15 @@ new_line: } } +int strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len, + int indent, int indent2, int width) +{ + char *tmp = xstrndup(data, len); + int r = strbuf_add_wrapped_text(buf, tmp, indent, indent2, width); + free(tmp); + return r; +} + int is_encoding_utf8(const char *name) { if (!name) @@ -10,6 +10,8 @@ int is_encoding_utf8(const char *name); int strbuf_add_wrapped_text(struct strbuf *buf, const char *text, int indent, int indent2, int width); +int strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len, + int indent, int indent2, int width); #ifndef NO_ICONV char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding); diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c index 6cfa256a37..260cf50e77 100644 --- a/vcs-svn/fast_export.c +++ b/vcs-svn/fast_export.c @@ -63,14 +63,14 @@ void fast_export_commit(uint32_t revision, uint32_t author, char *log, printf("progress Imported commit %"PRIu32".\n\n", revision); } -void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len) +void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len, struct line_buffer *input) { if (mode == REPO_MODE_LNK) { /* svn symlink blobs start with "link " */ - buffer_skip_bytes(5); + buffer_skip_bytes(input, 5); len -= 5; } printf("blob\nmark :%"PRIu32"\ndata %"PRIu32"\n", mark, len); - buffer_copy_bytes(len); + buffer_copy_bytes(input, len); fputc('\n', stdout); } diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h index 2aaaea53d5..054e7d5eb1 100644 --- a/vcs-svn/fast_export.h +++ b/vcs-svn/fast_export.h @@ -1,11 +1,14 @@ #ifndef FAST_EXPORT_H_ #define FAST_EXPORT_H_ +#include "line_buffer.h" + void fast_export_delete(uint32_t depth, uint32_t *path); void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode, uint32_t mark); void fast_export_commit(uint32_t revision, uint32_t author, char *log, uint32_t uuid, uint32_t url, unsigned long timestamp); -void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len); +void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len, + struct line_buffer *input); #endif diff --git a/vcs-svn/line_buffer.c b/vcs-svn/line_buffer.c index 1543567093..aedf105b70 100644 --- a/vcs-svn/line_buffer.c +++ b/vcs-svn/line_buffer.c @@ -5,47 +5,76 @@ #include "git-compat-util.h" #include "line_buffer.h" -#include "obj_pool.h" +#include "strbuf.h" -#define LINE_BUFFER_LEN 10000 #define COPY_BUFFER_LEN 4096 -/* Create memory pool for char sequence of known length */ -obj_pool_gen(blob, char, 4096) +int buffer_init(struct line_buffer *buf, const char *filename) +{ + buf->infile = filename ? fopen(filename, "r") : stdin; + if (!buf->infile) + return -1; + return 0; +} -static char line_buffer[LINE_BUFFER_LEN]; -static char byte_buffer[COPY_BUFFER_LEN]; -static FILE *infile; +int buffer_fdinit(struct line_buffer *buf, int fd) +{ + buf->infile = fdopen(fd, "r"); + if (!buf->infile) + return -1; + return 0; +} -int buffer_init(const char *filename) +int buffer_tmpfile_init(struct line_buffer *buf) { - infile = filename ? fopen(filename, "r") : stdin; - if (!infile) + buf->infile = tmpfile(); + if (!buf->infile) return -1; return 0; } -int buffer_deinit(void) +int buffer_deinit(struct line_buffer *buf) { int err; - if (infile == stdin) - return ferror(infile); - err = ferror(infile); - err |= fclose(infile); + if (buf->infile == stdin) + return ferror(buf->infile); + err = ferror(buf->infile); + err |= fclose(buf->infile); return err; } +FILE *buffer_tmpfile_rewind(struct line_buffer *buf) +{ + rewind(buf->infile); + return buf->infile; +} + +long buffer_tmpfile_prepare_to_read(struct line_buffer *buf) +{ + long pos = ftell(buf->infile); + if (pos < 0) + return error("ftell error: %s", strerror(errno)); + if (fseek(buf->infile, 0, SEEK_SET)) + return error("seek error: %s", strerror(errno)); + return pos; +} + +int buffer_read_char(struct line_buffer *buf) +{ + return fgetc(buf->infile); +} + /* Read a line without trailing newline. */ -char *buffer_read_line(void) +char *buffer_read_line(struct line_buffer *buf) { char *end; - if (!fgets(line_buffer, sizeof(line_buffer), infile)) + if (!fgets(buf->line_buffer, sizeof(buf->line_buffer), buf->infile)) /* Error or data exhausted. */ return NULL; - end = line_buffer + strlen(line_buffer); + end = buf->line_buffer + strlen(buf->line_buffer); if (end[-1] == '\n') end[-1] = '\0'; - else if (feof(infile)) + else if (feof(buf->infile)) ; /* No newline at end of file. That's fine. */ else /* @@ -54,44 +83,50 @@ char *buffer_read_line(void) * but for now let's return an error. */ return NULL; - return line_buffer; + return buf->line_buffer; +} + +char *buffer_read_string(struct line_buffer *buf, uint32_t len) +{ + strbuf_reset(&buf->blob_buffer); + strbuf_fread(&buf->blob_buffer, len, buf->infile); + return ferror(buf->infile) ? NULL : buf->blob_buffer.buf; } -char *buffer_read_string(uint32_t len) +void buffer_read_binary(struct line_buffer *buf, + struct strbuf *sb, uint32_t size) { - char *s; - blob_free(blob_pool.size); - s = blob_pointer(blob_alloc(len + 1)); - s[fread(s, 1, len, infile)] = '\0'; - return ferror(infile) ? NULL : s; + strbuf_fread(sb, size, buf->infile); } -void buffer_copy_bytes(uint32_t len) +void buffer_copy_bytes(struct line_buffer *buf, uint32_t len) { + char byte_buffer[COPY_BUFFER_LEN]; uint32_t in; - while (len > 0 && !feof(infile) && !ferror(infile)) { + while (len > 0 && !feof(buf->infile) && !ferror(buf->infile)) { in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN; - in = fread(byte_buffer, 1, in, infile); + in = fread(byte_buffer, 1, in, buf->infile); len -= in; fwrite(byte_buffer, 1, in, stdout); if (ferror(stdout)) { - buffer_skip_bytes(len); + buffer_skip_bytes(buf, len); return; } } } -void buffer_skip_bytes(uint32_t len) +void buffer_skip_bytes(struct line_buffer *buf, uint32_t len) { + char byte_buffer[COPY_BUFFER_LEN]; uint32_t in; - while (len > 0 && !feof(infile) && !ferror(infile)) { + while (len > 0 && !feof(buf->infile) && !ferror(buf->infile)) { in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN; - in = fread(byte_buffer, 1, in, infile); + in = fread(byte_buffer, 1, in, buf->infile); len -= in; } } -void buffer_reset(void) +void buffer_reset(struct line_buffer *buf) { - blob_reset(); + strbuf_release(&buf->blob_buffer); } diff --git a/vcs-svn/line_buffer.h b/vcs-svn/line_buffer.h index 9c78ae11a1..96ce966a22 100644 --- a/vcs-svn/line_buffer.h +++ b/vcs-svn/line_buffer.h @@ -1,12 +1,31 @@ #ifndef LINE_BUFFER_H_ #define LINE_BUFFER_H_ -int buffer_init(const char *filename); -int buffer_deinit(void); -char *buffer_read_line(void); -char *buffer_read_string(uint32_t len); -void buffer_copy_bytes(uint32_t len); -void buffer_skip_bytes(uint32_t len); -void buffer_reset(void); +#include "strbuf.h" + +#define LINE_BUFFER_LEN 10000 + +struct line_buffer { + char line_buffer[LINE_BUFFER_LEN]; + struct strbuf blob_buffer; + FILE *infile; +}; +#define LINE_BUFFER_INIT {"", STRBUF_INIT, NULL} + +int buffer_init(struct line_buffer *buf, const char *filename); +int buffer_fdinit(struct line_buffer *buf, int fd); +int buffer_deinit(struct line_buffer *buf); +void buffer_reset(struct line_buffer *buf); + +int buffer_tmpfile_init(struct line_buffer *buf); +FILE *buffer_tmpfile_rewind(struct line_buffer *buf); /* prepare to write. */ +long buffer_tmpfile_prepare_to_read(struct line_buffer *buf); + +char *buffer_read_line(struct line_buffer *buf); +char *buffer_read_string(struct line_buffer *buf, uint32_t len); +int buffer_read_char(struct line_buffer *buf); +void buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, uint32_t len); +void buffer_copy_bytes(struct line_buffer *buf, uint32_t len); +void buffer_skip_bytes(struct line_buffer *buf, uint32_t len); #endif diff --git a/vcs-svn/line_buffer.txt b/vcs-svn/line_buffer.txt index 8906fb1f50..e89cc41d56 100644 --- a/vcs-svn/line_buffer.txt +++ b/vcs-svn/line_buffer.txt @@ -14,22 +14,46 @@ Calling sequence The calling program: + - initializes a `struct line_buffer` to LINE_BUFFER_INIT - specifies a file to read with `buffer_init` - processes input with `buffer_read_line`, `buffer_read_string`, `buffer_skip_bytes`, and `buffer_copy_bytes` - closes the file with `buffer_deinit`, perhaps to start over and read another file. -Before exiting, the caller can use `buffer_reset` to deallocate -resources for the benefit of profiling tools. +When finished, the caller can use `buffer_reset` to deallocate +resources. + +Using temporary files +--------------------- + +Temporary files provide a place to store data that should not outlive +the calling program. A program + + - initializes a `struct line_buffer` to LINE_BUFFER_INIT + - requests a temporary file with `buffer_tmpfile_init` + - acquires an output handle by calling `buffer_tmpfile_rewind` + - uses standard I/O functions like `fprintf` and `fwrite` to fill + the temporary file + - declares writing is over with `buffer_tmpfile_prepare_to_read` + - can re-read what was written with `buffer_read_line`, + `buffer_read_string`, and so on + - can reuse the temporary file by calling `buffer_tmpfile_rewind` + again + - removes the temporary file with `buffer_deinit`, perhaps to + reuse the line_buffer for some other file. + +When finished, the calling program can use `buffer_reset` to deallocate +resources. Functions --------- -`buffer_init`:: - Open the named file for input. If filename is NULL, - start reading from stdin. On failure, returns -1 (with - errno indicating the nature of the failure). +`buffer_init`, `buffer_fdinit`:: + Open the named file or file descriptor for input. + buffer_init(buf, NULL) prepares to read from stdin. + On failure, returns -1 (with errno indicating the nature + of the failure). `buffer_deinit`:: Stop reading from the current file (closing it unless diff --git a/vcs-svn/repo_tree.c b/vcs-svn/repo_tree.c index e3d1fa3544..207ffc3a83 100644 --- a/vcs-svn/repo_tree.c +++ b/vcs-svn/repo_tree.c @@ -38,7 +38,7 @@ static uint32_t mark; static int repo_dirent_name_cmp(const void *a, const void *b); /* Treap for directory entries */ -trp_gen(static, dent_, struct repo_dirent, children, dent, repo_dirent_name_cmp); +trp_gen(static, dent_, struct repo_dirent, children, dent, repo_dirent_name_cmp) uint32_t next_blob_mark(void) { @@ -175,25 +175,18 @@ void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark) repo_write_dirent(path, mode, blob_mark, 0); } -uint32_t repo_replace(uint32_t *path, uint32_t blob_mark) +uint32_t repo_modify_path(uint32_t *path, uint32_t mode, uint32_t blob_mark) { - uint32_t mode = 0; struct repo_dirent *src_dent; src_dent = repo_read_dirent(active_commit, path); - if (src_dent != NULL) { - mode = src_dent->mode; - repo_write_dirent(path, mode, blob_mark, 0); - } - return mode; -} - -void repo_modify(uint32_t *path, uint32_t mode, uint32_t blob_mark) -{ - struct repo_dirent *src_dent; - src_dent = repo_read_dirent(active_commit, path); - if (src_dent != NULL && blob_mark == 0) + if (!src_dent) + return 0; + if (!blob_mark) blob_mark = src_dent->content_offset; + if (!mode) + mode = src_dent->mode; repo_write_dirent(path, mode, blob_mark, 0); + return mode; } void repo_delete(uint32_t *path) diff --git a/vcs-svn/repo_tree.h b/vcs-svn/repo_tree.h index 5476175922..68baeb582f 100644 --- a/vcs-svn/repo_tree.h +++ b/vcs-svn/repo_tree.h @@ -14,8 +14,7 @@ uint32_t next_blob_mark(void); uint32_t repo_copy(uint32_t revision, uint32_t *src, uint32_t *dst); void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark); -uint32_t repo_replace(uint32_t *path, uint32_t blob_mark); -void repo_modify(uint32_t *path, uint32_t mode, uint32_t blob_mark); +uint32_t repo_modify_path(uint32_t *path, uint32_t mode, uint32_t blob_mark); void repo_delete(uint32_t *path); void repo_commit(uint32_t revision, uint32_t author, char *log, uint32_t uuid, uint32_t url, long unsigned timestamp); diff --git a/vcs-svn/string_pool.c b/vcs-svn/string_pool.c index f5b1da836e..8af8d54d6e 100644 --- a/vcs-svn/string_pool.c +++ b/vcs-svn/string_pool.c @@ -30,7 +30,7 @@ static int node_cmp(struct node *a, struct node *b) } /* Build a Treap from the node structure (a trp_node w/ offset) */ -trp_gen(static, tree_, struct node, children, node, node_cmp); +trp_gen(static, tree_, struct node, children, node, node_cmp) const char *pool_fetch(uint32_t entry) { diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c index 2ad2c307dd..ee7c0bb2ea 100644 --- a/vcs-svn/svndump.c +++ b/vcs-svn/svndump.c @@ -30,7 +30,9 @@ /* Create memory pool for log messages */ obj_pool_gen(log, char, 4096) -static char* log_copy(uint32_t length, char *log) +static struct line_buffer input = LINE_BUFFER_INIT; + +static char *log_copy(uint32_t length, const char *log) { char *buffer; log_free(log_pool.size); @@ -40,8 +42,9 @@ static char* log_copy(uint32_t length, char *log) } static struct { - uint32_t action, propLength, textLength, srcRev, srcMode, mark, type; + uint32_t action, propLength, textLength, srcRev, type; uint32_t src[REPO_MAX_PATH_DEPTH], dst[REPO_MAX_PATH_DEPTH]; + uint32_t text_delta, prop_delta; } node_ctx; static struct { @@ -58,7 +61,9 @@ static struct { uint32_t svn_log, svn_author, svn_date, svn_executable, svn_special, uuid, revision_number, node_path, node_kind, node_action, node_copyfrom_path, node_copyfrom_rev, text_content_length, - prop_content_length, content_length, svn_fs_dump_format_version; + prop_content_length, content_length, svn_fs_dump_format_version, + /* version 3 format */ + text_delta, prop_delta; } keys; static void reset_node_ctx(char *fname) @@ -69,9 +74,9 @@ static void reset_node_ctx(char *fname) node_ctx.textLength = LENGTH_UNKNOWN; node_ctx.src[0] = ~0; node_ctx.srcRev = 0; - node_ctx.srcMode = 0; pool_tok_seq(REPO_MAX_PATH_DEPTH, node_ctx.dst, "/", fname); - node_ctx.mark = 0; + node_ctx.text_delta = 0; + node_ctx.prop_delta = 0; } static void reset_rev_ctx(uint32_t revision) @@ -107,81 +112,148 @@ static void init_keys(void) keys.prop_content_length = pool_intern("Prop-content-length"); keys.content_length = pool_intern("Content-length"); keys.svn_fs_dump_format_version = pool_intern("SVN-fs-dump-format-version"); + /* version 3 format (Subversion 1.1.0) */ + keys.text_delta = pool_intern("Text-delta"); + keys.prop_delta = pool_intern("Prop-delta"); +} + +static void handle_property(uint32_t key, const char *val, uint32_t len, + uint32_t *type_set) +{ + if (key == keys.svn_log) { + if (!val) + die("invalid dump: unsets svn:log"); + /* Value length excludes terminating nul. */ + rev_ctx.log = log_copy(len + 1, val); + } else if (key == keys.svn_author) { + rev_ctx.author = pool_intern(val); + } else if (key == keys.svn_date) { + if (!val) + die("invalid dump: unsets svn:date"); + if (parse_date_basic(val, &rev_ctx.timestamp, NULL)) + warning("invalid timestamp: %s", val); + } else if (key == keys.svn_executable || key == keys.svn_special) { + if (*type_set) { + if (!val) + return; + die("invalid dump: sets type twice"); + } + if (!val) { + node_ctx.type = REPO_MODE_BLB; + return; + } + *type_set = 1; + node_ctx.type = key == keys.svn_executable ? + REPO_MODE_EXE : + REPO_MODE_LNK; + } } static void read_props(void) { - uint32_t len; uint32_t key = ~0; - char *val = NULL; - char *t; - while ((t = buffer_read_line()) && strcmp(t, "PROPS-END")) { - if (!strncmp(t, "K ", 2)) { - len = atoi(&t[2]); - key = pool_intern(buffer_read_string(len)); - buffer_read_line(); - } else if (!strncmp(t, "V ", 2)) { - len = atoi(&t[2]); - val = buffer_read_string(len); - if (key == keys.svn_log) { - /* Value length excludes terminating nul. */ - rev_ctx.log = log_copy(len + 1, val); - } else if (key == keys.svn_author) { - rev_ctx.author = pool_intern(val); - } else if (key == keys.svn_date) { - if (parse_date_basic(val, &rev_ctx.timestamp, NULL)) - fprintf(stderr, "Invalid timestamp: %s\n", val); - } else if (key == keys.svn_executable) { - node_ctx.type = REPO_MODE_EXE; - } else if (key == keys.svn_special) { - node_ctx.type = REPO_MODE_LNK; - } + const char *t; + /* + * NEEDSWORK: to support simple mode changes like + * K 11 + * svn:special + * V 1 + * * + * D 14 + * svn:executable + * we keep track of whether a mode has been set and reset to + * plain file only if not. We should be keeping track of the + * symlink and executable bits separately instead. + */ + uint32_t type_set = 0; + while ((t = buffer_read_line(&input)) && strcmp(t, "PROPS-END")) { + uint32_t len; + const char *val; + const char type = t[0]; + + if (!type || t[1] != ' ') + die("invalid property line: %s\n", t); + len = atoi(&t[2]); + val = buffer_read_string(&input, len); + buffer_skip_bytes(&input, 1); /* Discard trailing newline. */ + + switch (type) { + case 'K': + key = pool_intern(val); + continue; + case 'D': + key = pool_intern(val); + val = NULL; + len = 0; + /* fall through */ + case 'V': + handle_property(key, val, len, &type_set); key = ~0; - buffer_read_line(); + continue; + default: + die("invalid property line: %s\n", t); } } } static void handle_node(void) { - if (node_ctx.propLength != LENGTH_UNKNOWN && node_ctx.propLength) - read_props(); - - if (node_ctx.srcRev) - node_ctx.srcMode = repo_copy(node_ctx.srcRev, node_ctx.src, node_ctx.dst); - - if (node_ctx.textLength != LENGTH_UNKNOWN && - node_ctx.type != REPO_MODE_DIR) - node_ctx.mark = next_blob_mark(); + uint32_t mark = 0; + const uint32_t type = node_ctx.type; + const int have_props = node_ctx.propLength != LENGTH_UNKNOWN; + if (node_ctx.text_delta) + die("text deltas not supported"); + if (node_ctx.textLength != LENGTH_UNKNOWN) + mark = next_blob_mark(); if (node_ctx.action == NODEACT_DELETE) { + if (mark || have_props || node_ctx.srcRev) + die("invalid dump: deletion node has " + "copyfrom info, text, or properties"); + return repo_delete(node_ctx.dst); + } + if (node_ctx.action == NODEACT_REPLACE) { repo_delete(node_ctx.dst); - } else if (node_ctx.action == NODEACT_CHANGE || - node_ctx.action == NODEACT_REPLACE) { - if (node_ctx.action == NODEACT_REPLACE && - node_ctx.type == REPO_MODE_DIR) - repo_replace(node_ctx.dst, node_ctx.mark); - else if (node_ctx.propLength != LENGTH_UNKNOWN) - repo_modify(node_ctx.dst, node_ctx.type, node_ctx.mark); - else if (node_ctx.textLength != LENGTH_UNKNOWN) - node_ctx.srcMode = repo_replace(node_ctx.dst, node_ctx.mark); + node_ctx.action = NODEACT_ADD; + } + if (node_ctx.srcRev) { + repo_copy(node_ctx.srcRev, node_ctx.src, node_ctx.dst); + if (node_ctx.action == NODEACT_ADD) + node_ctx.action = NODEACT_CHANGE; + } + if (mark && type == REPO_MODE_DIR) + die("invalid dump: directories cannot have text attached"); + if (node_ctx.action == NODEACT_CHANGE && !~*node_ctx.dst) { + if (type != REPO_MODE_DIR) + die("invalid dump: root of tree is not a regular file"); + } else if (node_ctx.action == NODEACT_CHANGE) { + uint32_t mode = repo_modify_path(node_ctx.dst, 0, mark); + if (!mode) + die("invalid dump: path to be modified is missing"); + if (mode == REPO_MODE_DIR && type != REPO_MODE_DIR) + die("invalid dump: cannot modify a directory into a file"); + if (mode != REPO_MODE_DIR && type == REPO_MODE_DIR) + die("invalid dump: cannot modify a file into a directory"); + node_ctx.type = mode; } else if (node_ctx.action == NODEACT_ADD) { - if (node_ctx.srcRev && node_ctx.propLength != LENGTH_UNKNOWN) - repo_modify(node_ctx.dst, node_ctx.type, node_ctx.mark); - else if (node_ctx.srcRev && node_ctx.textLength != LENGTH_UNKNOWN) - node_ctx.srcMode = repo_replace(node_ctx.dst, node_ctx.mark); - else if ((node_ctx.type == REPO_MODE_DIR && !node_ctx.srcRev) || - node_ctx.textLength != LENGTH_UNKNOWN) - repo_add(node_ctx.dst, node_ctx.type, node_ctx.mark); + if (!mark && type != REPO_MODE_DIR) + die("invalid dump: adds node without text"); + repo_add(node_ctx.dst, type, mark); + } else { + die("invalid dump: Node-path block lacks Node-action"); } - - if (node_ctx.propLength == LENGTH_UNKNOWN && node_ctx.srcMode) - node_ctx.type = node_ctx.srcMode; - - if (node_ctx.mark) - fast_export_blob(node_ctx.type, node_ctx.mark, node_ctx.textLength); - else if (node_ctx.textLength != LENGTH_UNKNOWN) - buffer_skip_bytes(node_ctx.textLength); + if (have_props) { + const uint32_t old_mode = node_ctx.type; + if (!node_ctx.prop_delta) + node_ctx.type = type; + if (node_ctx.propLength) + read_props(); + if (node_ctx.type != old_mode) + repo_modify_path(node_ctx.dst, node_ctx.type, mark); + } + if (mark) + fast_export_blob(node_ctx.type, mark, + node_ctx.textLength, &input); } static void handle_revision(void) @@ -200,7 +272,7 @@ void svndump_read(const char *url) uint32_t key; reset_dump_ctx(pool_intern(url)); - while ((t = buffer_read_line())) { + while ((t = buffer_read_line(&input))) { val = strstr(t, ": "); if (!val) continue; @@ -210,8 +282,8 @@ void svndump_read(const char *url) if (key == keys.svn_fs_dump_format_version) { dump_ctx.version = atoi(val); - if (dump_ctx.version > 2) - die("expected svn dump format version <= 2, found %"PRIu32, + if (dump_ctx.version > 3) + die("expected svn dump format version <= 3, found %"PRIu32, dump_ctx.version); } else if (key == keys.uuid) { dump_ctx.uuid = pool_intern(val); @@ -255,9 +327,13 @@ void svndump_read(const char *url) node_ctx.textLength = atoi(val); } else if (key == keys.prop_content_length) { node_ctx.propLength = atoi(val); + } else if (key == keys.text_delta) { + node_ctx.text_delta = !strcmp(val, "true"); + } else if (key == keys.prop_delta) { + node_ctx.prop_delta = !strcmp(val, "true"); } else if (key == keys.content_length) { len = atoi(val); - buffer_read_line(); + buffer_read_line(&input); if (active_ctx == REV_CTX) { read_props(); } else if (active_ctx == NODE_CTX) { @@ -265,7 +341,7 @@ void svndump_read(const char *url) active_ctx = REV_CTX; } else { fprintf(stderr, "Unexpected content length header: %"PRIu32"\n", len); - buffer_skip_bytes(len); + buffer_skip_bytes(&input, len); } } } @@ -275,14 +351,16 @@ void svndump_read(const char *url) handle_revision(); } -void svndump_init(const char *filename) +int svndump_init(const char *filename) { - buffer_init(filename); + if (buffer_init(&input, filename)) + return error("cannot open %s: %s", filename, strerror(errno)); repo_init(); reset_dump_ctx(~0); reset_rev_ctx(0); reset_node_ctx(NULL); init_keys(); + return 0; } void svndump_deinit(void) @@ -292,7 +370,7 @@ void svndump_deinit(void) reset_dump_ctx(~0); reset_rev_ctx(0); reset_node_ctx(NULL); - if (buffer_deinit()) + if (buffer_deinit(&input)) fprintf(stderr, "Input error\n"); if (ferror(stdout)) fprintf(stderr, "Output error\n"); @@ -301,7 +379,7 @@ void svndump_deinit(void) void svndump_reset(void) { log_reset(); - buffer_reset(); + buffer_reset(&input); repo_reset(); reset_dump_ctx(~0); reset_rev_ctx(0); diff --git a/vcs-svn/svndump.h b/vcs-svn/svndump.h index 93c412f14a..df9ceb0e8d 100644 --- a/vcs-svn/svndump.h +++ b/vcs-svn/svndump.h @@ -1,7 +1,7 @@ #ifndef SVNDUMP_H_ #define SVNDUMP_H_ -void svndump_init(const char *filename); +int svndump_init(const char *filename); void svndump_read(const char *url); void svndump_deinit(void); void svndump_reset(void); @@ -209,7 +209,7 @@ int xmkstemp(char *template) if (!template[0]) template = origtemplate; - nonrelative_template = make_nonrelative_path(template); + nonrelative_template = absolute_path(template); errno = saved_errno; die_errno("Unable to create temporary file '%s'", nonrelative_template); @@ -344,7 +344,7 @@ int xmkstemp_mode(char *template, int mode) if (!template[0]) template = origtemplate; - nonrelative_template = make_nonrelative_path(template); + nonrelative_template = absolute_path(template); errno = saved_errno; die_errno("Unable to create temporary file '%s'", nonrelative_template); diff --git a/wt-status.c b/wt-status.c index 123582b6cb..53558d7e5f 100644 --- a/wt-status.c +++ b/wt-status.c @@ -32,6 +32,80 @@ static const char *color(int slot, struct wt_status *s) return c; } +static void status_vprintf(struct wt_status *s, int at_bol, const char *color, + const char *fmt, va_list ap, const char *trail) +{ + struct strbuf sb = STRBUF_INIT; + struct strbuf linebuf = STRBUF_INIT; + const char *line, *eol; + + strbuf_vaddf(&sb, fmt, ap); + if (!sb.len) { + strbuf_addch(&sb, '#'); + if (!trail) + strbuf_addch(&sb, ' '); + color_print_strbuf(s->fp, color, &sb); + if (trail) + fprintf(s->fp, "%s", trail); + strbuf_release(&sb); + return; + } + for (line = sb.buf; *line; line = eol + 1) { + eol = strchr(line, '\n'); + + strbuf_reset(&linebuf); + if (at_bol) { + strbuf_addch(&linebuf, '#'); + if (*line != '\n' && *line != '\t') + strbuf_addch(&linebuf, ' '); + } + if (eol) + strbuf_add(&linebuf, line, eol - line); + else + strbuf_addstr(&linebuf, line); + color_print_strbuf(s->fp, color, &linebuf); + if (eol) + fprintf(s->fp, "\n"); + else + break; + at_bol = 1; + } + if (trail) + fprintf(s->fp, "%s", trail); + strbuf_release(&linebuf); + strbuf_release(&sb); +} + +void status_printf_ln(struct wt_status *s, const char *color, + const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + status_vprintf(s, 1, color, fmt, ap, "\n"); + va_end(ap); +} + +void status_printf(struct wt_status *s, const char *color, + const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + status_vprintf(s, 1, color, fmt, ap, NULL); + va_end(ap); +} + +void status_printf_more(struct wt_status *s, const char *color, + const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + status_vprintf(s, 0, color, fmt, ap, NULL); + va_end(ap); +} + void wt_status_prepare(struct wt_status *s) { unsigned char sha1[20]; @@ -57,33 +131,33 @@ static void wt_status_print_unmerged_header(struct wt_status *s) { const char *c = color(WT_STATUS_HEADER, s); - color_fprintf_ln(s->fp, c, "# Unmerged paths:"); + status_printf_ln(s, c, "Unmerged paths:"); if (!advice_status_hints) return; - if (s->in_merge) + if (s->whence != FROM_COMMIT) ; else if (!s->is_initial) - color_fprintf_ln(s->fp, c, "# (use \"git reset %s <file>...\" to unstage)", s->reference); + status_printf_ln(s, c, " (use \"git reset %s <file>...\" to unstage)", s->reference); else - color_fprintf_ln(s->fp, c, "# (use \"git rm --cached <file>...\" to unstage)"); - color_fprintf_ln(s->fp, c, "# (use \"git add/rm <file>...\" as appropriate to mark resolution)"); - color_fprintf_ln(s->fp, c, "#"); + status_printf_ln(s, c, " (use \"git rm --cached <file>...\" to unstage)"); + status_printf_ln(s, c, " (use \"git add/rm <file>...\" as appropriate to mark resolution)"); + status_printf_ln(s, c, ""); } static void wt_status_print_cached_header(struct wt_status *s) { const char *c = color(WT_STATUS_HEADER, s); - color_fprintf_ln(s->fp, c, "# Changes to be committed:"); + status_printf_ln(s, c, "Changes to be committed:"); if (!advice_status_hints) return; - if (s->in_merge) + if (s->whence != FROM_COMMIT) ; /* NEEDSWORK: use "git reset --unresolve"??? */ else if (!s->is_initial) - color_fprintf_ln(s->fp, c, "# (use \"git reset %s <file>...\" to unstage)", s->reference); + status_printf_ln(s, c, " (use \"git reset %s <file>...\" to unstage)", s->reference); else - color_fprintf_ln(s->fp, c, "# (use \"git rm --cached <file>...\" to unstage)"); - color_fprintf_ln(s->fp, c, "#"); + status_printf_ln(s, c, " (use \"git rm --cached <file>...\" to unstage)"); + status_printf_ln(s, c, ""); } static void wt_status_print_dirty_header(struct wt_status *s, @@ -92,17 +166,17 @@ static void wt_status_print_dirty_header(struct wt_status *s, { const char *c = color(WT_STATUS_HEADER, s); - color_fprintf_ln(s->fp, c, "# Changes not staged for commit:"); + status_printf_ln(s, c, "Changes not staged for commit:"); if (!advice_status_hints) return; if (!has_deleted) - color_fprintf_ln(s->fp, c, "# (use \"git add <file>...\" to update what will be committed)"); + status_printf_ln(s, c, " (use \"git add <file>...\" to update what will be committed)"); else - color_fprintf_ln(s->fp, c, "# (use \"git add/rm <file>...\" to update what will be committed)"); - color_fprintf_ln(s->fp, c, "# (use \"git checkout -- <file>...\" to discard changes in working directory)"); + status_printf_ln(s, c, " (use \"git add/rm <file>...\" to update what will be committed)"); + status_printf_ln(s, c, " (use \"git checkout -- <file>...\" to discard changes in working directory)"); if (has_dirty_submodules) - color_fprintf_ln(s->fp, c, "# (commit or discard the untracked or modified content in submodules)"); - color_fprintf_ln(s->fp, c, "#"); + status_printf_ln(s, c, " (commit or discard the untracked or modified content in submodules)"); + status_printf_ln(s, c, ""); } static void wt_status_print_other_header(struct wt_status *s, @@ -110,16 +184,16 @@ static void wt_status_print_other_header(struct wt_status *s, const char *how) { const char *c = color(WT_STATUS_HEADER, s); - color_fprintf_ln(s->fp, c, "# %s files:", what); + status_printf_ln(s, c, "%s files:", what); if (!advice_status_hints) return; - color_fprintf_ln(s->fp, c, "# (use \"git %s <file>...\" to include in what will be committed)", how); - color_fprintf_ln(s->fp, c, "#"); + status_printf_ln(s, c, " (use \"git %s <file>...\" to include in what will be committed)", how); + status_printf_ln(s, c, ""); } static void wt_status_print_trailer(struct wt_status *s) { - color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#"); + status_printf_ln(s, color(WT_STATUS_HEADER, s), ""); } #define quote_path quote_path_relative @@ -133,7 +207,7 @@ static void wt_status_print_unmerged_data(struct wt_status *s, const char *one, *how = "bug"; one = quote_path(it->string, -1, &onebuf, s->prefix); - color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t"); + status_printf(s, color(WT_STATUS_HEADER, s), "\t"); switch (d->stagemask) { case 1: how = "both deleted:"; break; case 2: how = "added by us:"; break; @@ -143,7 +217,7 @@ static void wt_status_print_unmerged_data(struct wt_status *s, case 6: how = "both added:"; break; case 7: how = "both modified:"; break; } - color_fprintf(s->fp, c, "%-20s%s\n", how, one); + status_printf_more(s, c, "%-20s%s\n", how, one); strbuf_release(&onebuf); } @@ -186,40 +260,40 @@ static void wt_status_print_change_data(struct wt_status *s, one = quote_path(one_name, -1, &onebuf, s->prefix); two = quote_path(two_name, -1, &twobuf, s->prefix); - color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t"); + status_printf(s, color(WT_STATUS_HEADER, s), "\t"); switch (status) { case DIFF_STATUS_ADDED: - color_fprintf(s->fp, c, "new file: %s", one); + status_printf_more(s, c, "new file: %s", one); break; case DIFF_STATUS_COPIED: - color_fprintf(s->fp, c, "copied: %s -> %s", one, two); + status_printf_more(s, c, "copied: %s -> %s", one, two); break; case DIFF_STATUS_DELETED: - color_fprintf(s->fp, c, "deleted: %s", one); + status_printf_more(s, c, "deleted: %s", one); break; case DIFF_STATUS_MODIFIED: - color_fprintf(s->fp, c, "modified: %s", one); + status_printf_more(s, c, "modified: %s", one); break; case DIFF_STATUS_RENAMED: - color_fprintf(s->fp, c, "renamed: %s -> %s", one, two); + status_printf_more(s, c, "renamed: %s -> %s", one, two); break; case DIFF_STATUS_TYPE_CHANGED: - color_fprintf(s->fp, c, "typechange: %s", one); + status_printf_more(s, c, "typechange: %s", one); break; case DIFF_STATUS_UNKNOWN: - color_fprintf(s->fp, c, "unknown: %s", one); + status_printf_more(s, c, "unknown: %s", one); break; case DIFF_STATUS_UNMERGED: - color_fprintf(s->fp, c, "unmerged: %s", one); + status_printf_more(s, c, "unmerged: %s", one); break; default: die("bug: unhandled diff status %c", status); } if (extra.len) { - color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "%s", extra.buf); + status_printf_more(s, color(WT_STATUS_HEADER, s), "%s", extra.buf); strbuf_release(&extra); } - fprintf(s->fp, "\n"); + status_printf_more(s, GIT_COLOR_NORMAL, "\n"); strbuf_release(&onebuf); strbuf_release(&twobuf); } @@ -323,7 +397,7 @@ static void wt_status_collect_changes_worktree(struct wt_status *s) } rev.diffopt.format_callback = wt_status_collect_changed_cb; rev.diffopt.format_callback_data = s; - rev.prune_data = s->pathspec; + init_pathspec(&rev.prune_data, s->pathspec); run_diff_files(&rev, 0); } @@ -348,20 +422,22 @@ static void wt_status_collect_changes_index(struct wt_status *s) rev.diffopt.detect_rename = 1; rev.diffopt.rename_limit = 200; rev.diffopt.break_opt = 0; - rev.prune_data = s->pathspec; + init_pathspec(&rev.prune_data, s->pathspec); run_diff_index(&rev, 1); } static void wt_status_collect_changes_initial(struct wt_status *s) { + struct pathspec pathspec; int i; + init_pathspec(&pathspec, s->pathspec); for (i = 0; i < active_nr; i++) { struct string_list_item *it; struct wt_status_change_data *d; struct cache_entry *ce = active_cache[i]; - if (!ce_path_match(ce, s->pathspec)) + if (!ce_path_match(ce, &pathspec)) continue; it = string_list_insert(&s->change, ce->name); d = it->util; @@ -376,6 +452,7 @@ static void wt_status_collect_changes_initial(struct wt_status *s) else d->index_status = DIFF_STATUS_ADDED; } + free_pathspec(&pathspec); } static void wt_status_collect_untracked(struct wt_status *s) @@ -573,9 +650,9 @@ static void wt_status_print_other(struct wt_status *s, for (i = 0; i < l->nr; i++) { struct string_list_item *it; it = &(l->items[i]); - color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t"); - color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED, s), "%s", - quote_path(it->string, strlen(it->string), + status_printf(s, color(WT_STATUS_HEADER, s), "\t"); + status_printf_more(s, color(WT_STATUS_UNTRACKED, s), + "%s\n", quote_path(it->string, strlen(it->string), &buf, s->prefix)); } strbuf_release(&buf); @@ -642,17 +719,17 @@ void wt_status_print(struct wt_status *s) branch_status_color = color(WT_STATUS_NOBRANCH, s); on_what = "Not currently on any branch."; } - color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "# "); - color_fprintf(s->fp, branch_status_color, "%s", on_what); - color_fprintf_ln(s->fp, branch_color, "%s", branch_name); + status_printf(s, color(WT_STATUS_HEADER, s), ""); + status_printf_more(s, branch_status_color, "%s", on_what); + status_printf_more(s, branch_color, "%s\n", branch_name); if (!s->is_initial) wt_status_print_tracking(s); } if (s->is_initial) { - color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#"); - color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "# Initial commit"); - color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#"); + status_printf_ln(s, color(WT_STATUS_HEADER, s), ""); + status_printf_ln(s, color(WT_STATUS_HEADER, s), "Initial commit"); + status_printf_ln(s, color(WT_STATUS_HEADER, s), ""); } wt_status_print_updated(s); @@ -669,7 +746,7 @@ void wt_status_print(struct wt_status *s) if (s->show_ignored_files) wt_status_print_other(s, &s->ignored, "Ignored", "add -f"); } else if (s->commitable) - fprintf(s->fp, "# Untracked files not listed%s\n", + status_printf_ln(s, GIT_COLOR_NORMAL, "Untracked files not listed%s", advice_status_hints ? " (use -u option to show untracked files)" : ""); @@ -677,7 +754,7 @@ void wt_status_print(struct wt_status *s) wt_status_print_verbose(s); if (!s->commitable) { if (s->amend) - fprintf(s->fp, "# No changes\n"); + status_printf_ln(s, GIT_COLOR_NORMAL, "No changes"); else if (s->nowarn) ; /* nothing */ else if (s->workdir_dirty) diff --git a/wt-status.h b/wt-status.h index 20b17cf439..682b4c8f7d 100644 --- a/wt-status.h +++ b/wt-status.h @@ -24,6 +24,13 @@ enum untracked_status_type { SHOW_ALL_UNTRACKED_FILES }; +/* from where does this commit originate */ +enum commit_whence { + FROM_COMMIT, /* normal */ + FROM_MERGE, /* commit came from merge */ + FROM_CHERRY_PICK /* commit came from cherry-pick */ +}; + struct wt_status_change_data { int worktree_status; int index_status; @@ -40,7 +47,7 @@ struct wt_status { const char **pathspec; int verbose; int amend; - int in_merge; + enum commit_whence whence; int nowarn; int use_color; int relative_paths; @@ -68,4 +75,11 @@ void wt_status_collect(struct wt_status *s); void wt_shortstatus_print(struct wt_status *s, int null_termination, int show_branch); void wt_porcelain_print(struct wt_status *s, int null_termination); +void status_printf_ln(struct wt_status *s, const char *color, const char *fmt, ...) + ; +void status_printf(struct wt_status *s, const char *color, const char *fmt, ...) + ; +void status_printf_more(struct wt_status *s, const char *color, const char *fmt, ...) + __attribute__((format(printf, 3, 4))); + #endif /* STATUS_H */ |