diff options
95 files changed, 2453 insertions, 1039 deletions
diff --git a/.gitignore b/.gitignore index 0eaba0a278..27797d1491 100644 --- a/.gitignore +++ b/.gitignore @@ -75,6 +75,7 @@ git-merge-ours git-merge-recursive git-merge-resolve git-merge-stupid +git-mergetool git-mktag git-mktree git-name-rev diff --git a/Documentation/cmd-list.perl b/Documentation/cmd-list.perl index f61c77aa7c..b54382b2bf 100755 --- a/Documentation/cmd-list.perl +++ b/Documentation/cmd-list.perl @@ -124,6 +124,7 @@ git-merge-index plumbingmanipulators git-merge mainporcelain git-merge-one-file purehelpers git-merge-tree ancillaryinterrogators +git-mergetool ancillarymanipulators git-mktag plumbingmanipulators git-mktree plumbingmanipulators git-mv mainporcelain diff --git a/Documentation/config.txt b/Documentation/config.txt index 5408dd67d3..aaae9ac305 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -453,6 +453,11 @@ merge.summary:: Whether to include summaries of merged commits in newly created merge commit messages. False by default. +merge.tool:: + Controls which merge resolution program is used by + gitlink:git-mergetool[l]. Valid values are: "kdiff3", "tkdiff", + "meld", "xxdiff", "emerge" + merge.verbosity:: Controls the amount of output shown by the recursive merge strategy. Level 0 outputs nothing except a final error diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index 3ea3b80635..603f87f3b5 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -10,7 +10,7 @@ SYNOPSIS [verse] 'git-branch' [--color | --no-color] [-r | -a] [-v [--abbrev=<length> | --no-abbrev]] -'git-branch' [-l] [-f] <branchname> [<start-point>] +'git-branch' [--track | --no-track] [-l] [-f] <branchname> [<start-point>] 'git-branch' (-m | -M) [<oldbranch>] <newbranch> 'git-branch' (-d | -D) [-r] <branchname>... @@ -26,6 +26,13 @@ It will start out with a head equal to the one given as <start-point>. If no <start-point> is given, the branch will be created with a head equal to that of the currently checked out branch. +When a local branch is started off a remote branch, git can setup the +branch so that gitlink:git-pull[1] will appropriately merge from that +remote branch. If this behavior is desired, it is possible to make it +the default using the global `branch.autosetupmerge` configuration +flag. Otherwise, it can be chosen per-branch using the `--track` +and `--no-track` options. + With a '-m' or '-M' option, <oldbranch> will be renamed to <newbranch>. If <oldbranch> had a corresponding reflog, it is renamed to match <newbranch>, and a reflog entry is created to remember the branch diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 1ae77be450..f5b2d5017b 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -8,7 +8,7 @@ git-checkout - Checkout and switch to a branch SYNOPSIS -------- [verse] -'git-checkout' [-q] [-f] [-b <new_branch> [-l]] [-m] [<branch>] +'git-checkout' [-q] [-f] [-b [--track | --no-track] <new_branch> [-l]] [-m] [<branch>] 'git-checkout' [<tree-ish>] <paths>... DESCRIPTION @@ -18,7 +18,8 @@ When <paths> are not given, this command switches branches by updating the index and working tree to reflect the specified branch, <branch>, and updating HEAD to be <branch> or, if specified, <new_branch>. Using -b will cause <new_branch> to -be created. +be created; in this case you can use the --track or --no-track +options, which will be passed to `git branch`. When <paths> are given, this command does *not* switch branches. It updates the named paths in the working tree from @@ -45,6 +46,16 @@ OPTIONS by gitlink:git-check-ref-format[1]. Some of these checks may restrict the characters allowed in a branch name. +--track:: + When -b is given and a branch is created off a remote branch, + setup so that git-pull will automatically retrieve data from + the remote branch. + +--no-track:: + When -b is given and a branch is created off a remote branch, + force that git-pull will automatically retrieve data from + the remote branch independent of the configuration settings. + -l:: Create the new branch's ref log. This activates recording of all changes to made the branch ref, enabling use of date diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index 2187eee416..53a7bb0895 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -8,8 +8,9 @@ git-commit - Record changes to the repository SYNOPSIS -------- [verse] -'git-commit' [-a] [-s] [-v] [(-c | -C) <commit> | -F <file> | -m <msg> | - --amend] [--no-verify] [-e] [--author <author>] +'git-commit' [-a | --interactive] [-s] [-v] + [(-c | -C) <commit> | -F <file> | -m <msg> | --amend] + [--no-verify] [-e] [--author <author>] [--] [[-i | -o ]<file>...] DESCRIPTION @@ -35,6 +36,10 @@ methods: before, and to automatically "rm" files that have been removed from the working tree, and perform the actual commit. +5. by using the --interactive switch with the 'commit' command to decide one + by one which files should be part of the commit, before finalizing the + operation. Currently, this is done by invoking `git-add --interactive`. + The gitlink:git-status[1] command can be used to obtain a summary of what is included by any of the above for the next commit by giving the same set of parameters you would give to diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt index e328db3797..1c6f6a7e27 100644 --- a/Documentation/git-cvsserver.txt +++ b/Documentation/git-cvsserver.txt @@ -121,10 +121,10 @@ so that calling 'cvs' effectively calls git-cvsserver. Clients known to work --------------------- -CVS 1.12.9 on Debian -CVS 1.11.17 on MacOSX (from Fink package) -Eclipse 3.0, 3.1.2 on MacOSX (see Eclipse CVS Client Notes) -TortoiseCVS +- CVS 1.12.9 on Debian +- CVS 1.11.17 on MacOSX (from Fink package) +- Eclipse 3.0, 3.1.2 on MacOSX (see Eclipse CVS Client Notes) +- TortoiseCVS Operations supported -------------------- @@ -148,13 +148,16 @@ Copyright and Authors This program is copyright The Open University UK - 2006. -Authors: Martyn Smith <martyn@catalyst.net.nz> - Martin Langhoff <martin@catalyst.net.nz> - with ideas and patches from participants of the git-list <git@vger.kernel.org>. +Authors: + +- Martyn Smith <martyn@catalyst.net.nz> +- Martin Langhoff <martin@catalyst.net.nz> + +with ideas and patches from participants of the git-list <git@vger.kernel.org>. Documentation -------------- -Documentation by Martyn Smith <martyn@catalyst.net.nz> and Martin Langhoff <martin@catalyst.net.nz> Matthias Urlichs <smurf@smurf.noris.de>. +Documentation by Martyn Smith <martyn@catalyst.net.nz>, Martin Langhoff <martin@catalyst.net.nz>, and Matthias Urlichs <smurf@smurf.noris.de>. GIT --- diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt index 7e3d2b1a96..eaba6fd4c1 100644 --- a/Documentation/git-fast-import.txt +++ b/Documentation/git-fast-import.txt @@ -462,7 +462,7 @@ in octal. Git only supports the following modes: In both formats `<path>` is the complete path of the file to be added (if not already existing) or modified (if already existing). -A `<path>` string must use UNIX-style directory seperators (forward +A `<path>` string must use UNIX-style directory separators (forward slash `/`), may contain any byte other than `LF`, and must not start with double quote (`"`). @@ -472,8 +472,8 @@ quoting should be used, e.g. `"path/with\n and \" in it"`. The value of `<path>` must be in canoncial form. That is it must not: * contain an empty directory component (e.g. `foo//bar` is invalid), -* end with a directory seperator (e.g. `foo/` is invalid), -* start with a directory seperator (e.g. `/foo` is invalid), +* end with a directory separator (e.g. `foo/` is invalid), +* start with a directory separator (e.g. `/foo` is invalid), * contain the special component `.` or `..` (e.g. `foo/./bar` and `foo/../bar` are invalid). diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index 84eabebe0b..111d7c60bf 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -9,8 +9,9 @@ git-format-patch - Prepare patches for e-mail submission SYNOPSIS -------- [verse] -'git-format-patch' [<common diff options>] [-n | -k] [-o <dir> | --stdout] - [--attach] [--thread] [-s | --signoff] [--start-number <n>] +'git-format-patch' [-n | -k] [-o <dir> | --stdout] [--thread] + [--attach[=<boundary>] | --inline[=<boundary>]] + [-s | --signoff] [<common diff options>] [--start-number <n>] [--in-reply-to=Message-Id] [--suffix=.<sfx>] [--ignore-if-in-upstream] <since>[..<until>] @@ -70,8 +71,15 @@ include::diff-options.txt[] Print all commits to the standard output in mbox format, instead of creating a file for each one. ---attach:: - Create attachments instead of inlining patches. +--attach[=<boundary>]:: + Create multipart/mixed attachment, the first part of + which is the commit message and the patch itself in the + second part, with "Content-Disposition: attachment". + +--inline[=<boundary>]:: + Create multipart/mixed attachment, the first part of + which is the commit message and the patch itself in the + second part, with "Content-Disposition: inline". --thread:: Add In-Reply-To and References headers to make the second and diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt new file mode 100644 index 0000000000..ae69a0eb83 --- /dev/null +++ b/Documentation/git-mergetool.txt @@ -0,0 +1,46 @@ +git-mergetool(1) +================ + +NAME +---- +git-mergetool - Run merge conflict resolution tools to resolve merge conflicts + +SYNOPSIS +-------- +'git-mergetool' [--tool=<tool>] [<file>]... + +DESCRIPTION +----------- + +Use 'git mergetool' to run one of several merge utilities to resolve +merge conflicts. It is typically run after gitlink:git-merge[1]. + +If one or more <file> parameters are given, the merge tool program will +be run to resolve differences on each file. If no <file> names are +specified, 'git mergetool' will run the merge tool program on every file +with merge conflicts. + +OPTIONS +------- +-t or --tool=<tool>:: + Use the merge resolution program specified by <tool>. + Valid merge tools are: + kdiff3, tkdiff, meld, xxdiff, and emerge. + + If a merge resolution program is not specified, 'git mergetool' + will use the configuration variable merge.tool. If the + configuration variable merge.tool is not set, 'git mergetool' + will pick a suitable default. + +Author +------ +Written by Theodore Y Ts'o <tytso@mit.edu> + +Documentation +-------------- +Documentation by Theodore Y Ts'o. + +GIT +--- +Part of the gitlink:git[7] suite + diff --git a/Documentation/git-receive-pack.txt b/Documentation/git-receive-pack.txt index 3cf55111cc..6914aa59c3 100644 --- a/Documentation/git-receive-pack.txt +++ b/Documentation/git-receive-pack.txt @@ -40,13 +40,13 @@ OPTIONS pre-receive Hook ---------------- Before any ref is updated, if $GIT_DIR/hooks/pre-receive file exists -and is executable, it will be invoked once, with three parameters -per ref to be updated: +and is executable, it will be invoked once with no parameters. The +standard input of the hook will be one line per ref to be updated: - $GIT_DIR/hooks/pre-receive (refname sha1-old sha1-new)+ + sha1-old SP sha1-new SP refname LF -The refname parameter is relative to $GIT_DIR; e.g. for the master -head this is "refs/heads/master". The two sha1 arguments after +The refname value is relative to $GIT_DIR; e.g. for the master +head this is "refs/heads/master". The two sha1 values before each refname are the object names for the refname before and after the update. Refs to be created will have sha1-old equal to 0{40}, while refs to be deleted will have sha1-new equal to 0{40}, otherwise @@ -86,13 +86,14 @@ post-receive Hook ----------------- After all refs were updated (or attempted to be updated), if any ref update was successful, and if $GIT_DIR/hooks/post-receive -file exists and is executable, it will be invoke once with three -parameters for each successfully updated ref: +file exists and is executable, it will be invoke once with no +parameters. The standard input of the hook will be one line +for each successfully updated ref: - $GIT_DIR/hooks/post-receive (refname sha1-old sha1-new)+ + sha1-old SP sha1-new SP refname LF -The refname parameter is relative to $GIT_DIR; e.g. for the master -head this is "refs/heads/master". The two sha1 arguments after +The refname value is relative to $GIT_DIR; e.g. for the master +head this is "refs/heads/master". The two sha1 values before each refname are the object names for the refname before and after the update. Refs that were created will have sha1-old equal to 0{40}, while refs that were deleted will have sha1-new equal to @@ -105,18 +106,17 @@ ref listing the commits pushed to the repository: #!/bin/sh # mail out commit update information. - while test $# -gt 0 + while read oval nval ref do - if expr "$2" : '0*$' >/dev/null + if expr "$oval" : '0*$' >/dev/null then echo "Created a new ref, with the following commits:" - git-rev-list --pretty "$2" + git-rev-list --pretty "$nval" else echo "New commits:" - git-rev-list --pretty "$3" "^$2" + git-rev-list --pretty "$nval" "^$oval" fi | - mail -s "Changes to ref $1" commit-list@mydomain - shift; shift; shift; # discard this ref's args + mail -s "Changes to ref $ref" commit-list@mydomain done exit 0 diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index 35b0104e4a..9b3aabb6fe 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -40,7 +40,8 @@ The --cc option must be repeated for each user you want on the cc list. the first will be sent as replies to the first email sent. When using this, it is recommended that the first file given be an overview of the entire patch series. - Default is --chain-reply-to + Default is the value of the 'sendemail.chainreplyto' configuration + value; if that is unspecified, default to --chain-reply-to. --compose:: Use $EDITOR to edit an introductory message for the @@ -91,6 +92,26 @@ The --cc option must be repeated for each user you want on the cc list. The --to option must be repeated for each user you want on the to list. +CONFIGURATION +------------- +sendemail.aliasesfile:: + To avoid typing long email addresses, point this to one or more + email aliases files. You must also supply 'sendemail.aliasfiletype'. + +sendemail.aliasfiletype:: + Format of the file(s) specified in sendemail.aliasesfile. Must be + one of 'mutt', 'mailrc', 'pine', or 'gnus'. + +sendemail.bcc:: + Email address (or alias) to always bcc. + +sendemail.chainreplyto:: + Boolean value specifying the default to the '--chain_reply_to' + parameter. + +sendemail.smtpserver:: + Default smtp server to use. + Author ------ Written by Ryan Anderson <ryan@michonline.com> diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index 9b5a3d6196..a0d34e0058 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -104,6 +104,14 @@ accepts. However '--fetch-all' only fetches from the current Like 'git-rebase'; this requires that the working tree be clean and have no uncommitted changes. ++ +-- +-l;; +--local;; + Do not fetch remotely; only run 'git-rebase' against the + last fetched commit from the upstream SVN. +-- ++ 'dcommit':: Commit each diff from a specified head directly to the SVN diff --git a/Documentation/install-webdoc.sh b/Documentation/install-webdoc.sh index b3981936e3..cd3a18eb7f 100755 --- a/Documentation/install-webdoc.sh +++ b/Documentation/install-webdoc.sh @@ -2,7 +2,7 @@ T="$1" -for h in *.html *.txt howto/*.txt howto/*.html RelNotes-*.txt +for h in *.html *.txt howto/*.txt howto/*.html RelNotes-*.txt *.css do if test -f "$T/$h" && diff -u -I'Last updated [0-9][0-9]-[A-Z][a-z][a-z]-' "$T/$h" "$h" diff --git a/Documentation/sort_glossary.pl b/Documentation/sort_glossary.pl index e0bc552a64..05dc7b2c7b 100644 --- a/Documentation/sort_glossary.pl +++ b/Documentation/sort_glossary.pl @@ -48,7 +48,7 @@ This list is sorted alphabetically: '; @keys=sort {uc($a) cmp uc($b)} keys %terms; -$pattern='(\b(?<!link:git-)'.join('\b|\b(?<!link:git-)',reverse @keys).'\b)'; +$pattern='(\b(?<!link:git-)'.join('\b|\b(?<!-)',reverse @keys).'\b)'; foreach $key (@keys) { $terms{$key}=~s/$pattern/sprintf "<<ref_".no_spaces($1).",$1>>";/eg; print '[[ref_'.no_spaces($key).']]'.$key."::\n" diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt index ffd673ec33..d7b227e647 100644 --- a/Documentation/user-manual.txt +++ b/Documentation/user-manual.txt @@ -437,11 +437,14 @@ We will sometimes represent git history using diagrams like the one below. Commits are shown as "o", and the links between them with lines drawn with - / and \. Time goes left to right: + +................................................ o--o--o <-- Branch A / o--o--o <-- master \ o--o--o <-- Branch B +................................................ If we need to talk about a particular commit, the character "o" may be replaced with another letter or number. @@ -601,8 +604,8 @@ a new stanza: $ cat .git/config ... [remote "linux-nfs"] - url = git://linux-nfs.org/~bfields/git.git - fetch = +refs/heads/*:refs/remotes/linux-nfs-read/* + url = git://linux-nfs.org/pub/nfs-2.6.git + fetch = +refs/heads/*:refs/remotes/linux-nfs/* ... ------------------------------------------------- @@ -1133,17 +1136,9 @@ modified in two different ways in the remote branch and the local branch--then you are warned; the output may look something like this: ------------------------------------------------- -$ git pull . next -Trying really trivial in-index merge... -fatal: Merge requires file-level merging -Nope. -Merging HEAD with 77976da35a11db4580b80ae27e8d65caf5208086 -Merging: -15e2162 world -77976da goodbye -found 1 common ancestor(s): -d122ed4 initial -Auto-merging file.txt +$ git merge next + 100% (4/4) done +Auto-merged file.txt CONFLICT (content): Merge conflict in file.txt Automatic merge failed; fix conflicts and then commit the result. ------------------------------------------------- @@ -1439,7 +1434,7 @@ modifying the working directory, you can do that with gitlink:git-show[1]: ------------------------------------------------- -$ git show HEAD^ path/to/file +$ git show HEAD^:path/to/file ------------------------------------------------- which will display the given version of the file. @@ -1936,25 +1931,29 @@ $ git commit You have performed no merges into mywork, so it is just a simple linear sequence of patches on top of "origin": - +................................................ o--o--o <-- origin \ o--o--o <-- mywork +................................................ Some more interesting work has been done in the upstream project, and "origin" has advanced: +................................................ o--o--O--o--o--o <-- origin \ a--b--c <-- mywork +................................................ At this point, you could use "pull" to merge your changes back in; the result would create a new merge commit, like this: - +................................................ o--o--O--o--o--o <-- origin \ \ a--b--c--m <-- mywork +................................................ However, if you prefer to keep the history in mywork a simple series of commits without any merges, you may instead choose to use @@ -1971,9 +1970,11 @@ point at the latest version of origin, then apply each of the saved patches to the new mywork. The result will look like: +................................................ o--o--O--o--o--o <-- origin \ a'--b'--c' <-- mywork +................................................ In the process, it may discover conflicts. In that case it will stop and allow you to fix the conflicts; after fixing conflicts, use "git @@ -2081,24 +2082,30 @@ The primary problem with rewriting the history of a branch has to do with merging. Suppose somebody fetches your branch and merges it into their branch, with a result something like this: +................................................ o--o--O--o--o--o <-- origin \ \ t--t--t--m <-- their branch: +................................................ Then suppose you modify the last three commits: +................................................ o--o--o <-- new head of origin / o--o--O--o--o--o <-- old head of origin +................................................ If we examined all this history together in one repository, it will look like: +................................................ o--o--o <-- new head of origin / o--o--O--o--o--o <-- old head of origin \ \ t--t--t--m <-- their branch: +................................................ Git has no way of knowing that the new head is an updated version of the old head; it treats this situation exactly the same as it would if @@ -2159,9 +2166,11 @@ commit. Git calls this process a "fast forward". A fast forward looks something like this: +................................................ o--o--o--o <-- old head of the branch \ o--o--o <-- new head of the branch +................................................ In some cases it is possible that the new head will *not* actually be @@ -2169,11 +2178,11 @@ a descendant of the old head. For example, the developer may have realized she made a serious mistake, and decided to backtrack, resulting in a situation like: +................................................ o--o--o--o--a--b <-- old head of the branch \ o--o--o <-- new head of the branch - - +................................................ In this case, "git fetch" will fail, and print out a warning. @@ -1,6 +1,8 @@ # The default target of this Makefile is... all:: +# Define V=1 to have a more verbose compile. +# # Define NO_OPENSSL environment variable if you do not have OpenSSL. # This also implies MOZILLA_SHA1. # @@ -177,10 +179,10 @@ SCRIPT_SH = \ git-clean.sh git-clone.sh git-commit.sh \ git-fetch.sh git-gc.sh \ git-ls-remote.sh \ - git-merge-one-file.sh git-parse-remote.sh \ + git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \ git-pull.sh git-rebase.sh \ git-repack.sh git-request-pull.sh git-reset.sh \ - git-revert.sh git-sh-setup.sh \ + git-sh-setup.sh \ git-tag.sh git-verify-tag.sh \ git-applymbox.sh git-applypatch.sh git-am.sh \ git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \ @@ -196,7 +198,7 @@ SCRIPT_PERL = \ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \ $(patsubst %.perl,%,$(SCRIPT_PERL)) \ - git-cherry-pick git-status git-instaweb + git-status git-instaweb # ... and all the rest that could be moved out of bindir to gitexecdir PROGRAMS = \ @@ -223,7 +225,7 @@ EXTRA_PROGRAMS = BUILT_INS = \ git-format-patch$X git-show$X git-whatchanged$X git-cherry$X \ git-get-tar-commit-id$X git-init$X git-repo-config$X \ - git-fsck-objects$X \ + git-fsck-objects$X git-cherry-pick$X \ $(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS)) # what 'all' will build and 'install' will install, in gitexecdir @@ -315,6 +317,7 @@ BUILTIN_OBJS = \ builtin-rerere.o \ builtin-rev-list.o \ builtin-rev-parse.o \ + builtin-revert.o \ builtin-rm.o \ builtin-runstatus.o \ builtin-shortlog.o \ @@ -603,6 +606,31 @@ ifdef NO_PERL_MAKEMAKER export NO_PERL_MAKEMAKER endif +QUIET_SUBDIR0 = $(MAKE) -C # space to separate -C and subdir +QUIET_SUBDIR1 = + +ifneq ($(findstring $(MAKEFLAGS),w),w) +PRINT_DIR = --no-print-directory +else # "make -w" +NO_SUBDIR = : +endif + +ifneq ($(findstring $(MAKEFLAGS),s),s) +ifndef V + QUIET_CC = @echo ' ' CC $@; + QUIET_AR = @echo ' ' AR $@; + QUIET_LINK = @echo ' ' LINK $@; + QUIET_BUILT_IN = @echo ' ' BUILTIN $@; + QUIET_GEN = @echo ' ' GEN $@; + QUIET_SUBDIR0 = @subdir= + QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ + $(MAKE) $(PRINT_DIR) -C $$subdir + export V + export QUIET_GEN + export QUIET_BUILT_IN +endif +endif + # Shell quote (do not use $(call) to accommodate ancient setups); SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER)) @@ -637,44 +665,43 @@ ifneq (,$X) endif all:: - $(MAKE) -C git-gui all - $(MAKE) -C perl PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all - $(MAKE) -C templates + $(QUIET_SUBDIR0)git-gui $(QUIET_SUBDIR1) all + $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all + $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) strip: $(PROGRAMS) git$X $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS) GIT-CFLAGS - $(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \ + $(QUIET_LINK)$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \ $(ALL_CFLAGS) -o $@ $(filter %.c,$^) \ $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS) help.o: common-cmds.h $(BUILT_INS): git$X - rm -f $@ && ln git$X $@ + $(QUIET_BUILT_IN)rm -f $@ && ln git$X $@ common-cmds.h: Documentation/git-*.txt - ./generate-cmdlist.sh > $@+ - mv $@+ $@ + $(QUIET_GEN)./generate-cmdlist.sh > $@+ && mv $@+ $@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh - rm -f $@ $@+ + $(QUIET_GEN)rm -f $@ $@+ && \ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ - $@.sh >$@+ - chmod +x $@+ + $@.sh >$@+ && \ + chmod +x $@+ && \ mv $@+ $@ $(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak perl/perl.mak: GIT-CFLAGS - $(MAKE) -C perl PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F) + $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F) $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl - rm -f $@ $@+ + $(QUIET_GEN)rm -f $@ $@+ && \ INSTLIBDIR=`$(MAKE) -C perl -s --no-print-directory instlibdir` && \ sed -e '1{' \ -e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \ @@ -685,20 +712,15 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl -e '}' \ -e 's|@@INSTLIBDIR@@|'"$$INSTLIBDIR"'|g' \ -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ - $@.perl >$@+ - chmod +x $@+ - mv $@+ $@ - -git-cherry-pick: git-revert - cp $< $@+ + $@.perl >$@+ && \ + chmod +x $@+ && \ mv $@+ $@ git-status: git-commit - cp $< $@+ - mv $@+ $@ + $(QUIET_GEN)cp $< $@+ && mv $@+ $@ gitweb/gitweb.cgi: gitweb/gitweb.perl - rm -f $@ $@+ + $(QUIET_GEN)rm -f $@ $@+ && \ sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \ -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \ -e 's|++GIT_BINDIR++|$(bindir)|g' \ @@ -716,12 +738,12 @@ gitweb/gitweb.cgi: gitweb/gitweb.perl -e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \ -e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \ -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \ - $< >$@+ - chmod +x $@+ + $< >$@+ && \ + chmod +x $@+ && \ mv $@+ $@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css - rm -f $@ $@+ + $(QUIET_GEN)rm -f $@ $@+ && \ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ @@ -729,15 +751,15 @@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css -e '/@@GITWEB_CGI@@/d' \ -e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \ -e '/@@GITWEB_CSS@@/d' \ - $@.sh > $@+ - chmod +x $@+ + $@.sh > $@+ && \ + chmod +x $@+ && \ mv $@+ $@ configure: configure.ac - rm -f $@ $<+ + $(QUIET_GEN)rm -f $@ $<+ && \ sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ - $< > $<+ - autoconf -o $@ $<+ + $< > $<+ && \ + autoconf -o $@ $<+ && \ rm -f $<+ # These can record GIT_VERSION @@ -747,25 +769,25 @@ git$X git.spec \ : GIT-VERSION-FILE %.o: %.c GIT-CFLAGS - $(CC) -o $*.o -c $(ALL_CFLAGS) $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< %.o: %.S - $(CC) -o $*.o -c $(ALL_CFLAGS) $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< exec_cmd.o: exec_cmd.c GIT-CFLAGS - $(CC) -o $*.o -c $(ALL_CFLAGS) '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' $< builtin-init-db.o: builtin-init-db.c GIT-CFLAGS - $(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $< http.o: http.c GIT-CFLAGS - $(CC) -o $*.o -c $(ALL_CFLAGS) -DGIT_USER_AGENT='"git/$(GIT_VERSION)"' $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DGIT_USER_AGENT='"git/$(GIT_VERSION)"' $< ifdef NO_EXPAT http-fetch.o: http-fetch.c http.h GIT-CFLAGS - $(CC) -o $*.o -c $(ALL_CFLAGS) -DNO_EXPAT $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DNO_EXPAT $< endif git-%$X: %.o $(GITLIBS) - $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) + $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) ssh-pull.o: ssh-fetch.c ssh-push.o: ssh-upload.c @@ -779,11 +801,11 @@ git-imap-send$X: imap-send.o $(LIB_FILE) http.o http-fetch.o http-push.o: http.h git-http-fetch$X: fetch.o http.o http-fetch.o $(GITLIBS) - $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ + $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) git-http-push$X: revision.o http.o http-push.o $(GITLIBS) - $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ + $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIB_OBJS) $(BUILTIN_OBJS) fetch.o: $(LIB_H) @@ -791,7 +813,7 @@ $(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) $(DIFF_OBJS): diffcore.h $(LIB_FILE): $(LIB_OBJS) - rm -f $@ && $(AR) rcs $@ $(LIB_OBJS) + $(QUIET_AR)rm -f $@ && $(AR) rcs $@ $(LIB_OBJS) XDIFF_OBJS=xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \ xdiff/xmerge.o @@ -799,7 +821,7 @@ $(XDIFF_OBJS): xdiff/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \ xdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h $(XDIFF_LIB): $(XDIFF_OBJS) - rm -f $@ && $(AR) rcs $@ $(XDIFF_OBJS) + $(QUIET_AR)rm -f $@ && $(AR) rcs $@ $(XDIFF_OBJS) perl/Makefile: perl/Git.pm perl/Makefile.PL GIT-CFLAGS @@ -909,8 +931,7 @@ dist: git.spec git-archive $(TAR) rf $(GIT_TARNAME).tar \ $(GIT_TARNAME)/git.spec \ $(GIT_TARNAME)/version \ - $(GIT_TARNAME)/git-gui/version \ - $(GIT_TARNAME)/git-gui/credits + $(GIT_TARNAME)/git-gui/version @rm -rf $(GIT_TARNAME) gzip -f -9 $(GIT_TARNAME).tar diff --git a/builtin-branch.c b/builtin-branch.c index 06d8a8ce04..42b1ff129e 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -12,7 +12,7 @@ #include "builtin.h" static const char builtin_branch_usage[] = - "git-branch [-r] (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length> | --no-abbrev]]"; + "git-branch [-r] (-d | -D) <branchname> | [--track | --no-track] [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length> | --no-abbrev]]"; #define REF_UNKNOWN_TYPE 0x00 #define REF_LOCAL_BRANCH 0x01 @@ -22,6 +22,8 @@ static const char builtin_branch_usage[] = static const char *head; static unsigned char head_sha1[20]; +static int branch_track_remotes; + static int branch_use_color; static char branch_colors[][COLOR_MAXLEN] = { "\033[m", /* reset */ @@ -64,6 +66,9 @@ int git_branch_config(const char *var, const char *value) color_parse(value, var, branch_colors[slot]); return 0; } + if (!strcmp(var, "branch.autosetupmerge")) + branch_track_remotes = git_config_bool(var, value); + return git_default_config(var, value); } @@ -309,14 +314,108 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev) free_ref_list(&ref_list); } +static char *config_repo; +static char *config_remote; +static const char *start_ref; +static int start_len; +static int base_len; + +static int get_remote_branch_name(const char *value) +{ + const char *colon; + const char *end; + + if (*value == '+') + value++; + + colon = strchr(value, ':'); + if (!colon) + return 0; + + end = value + strlen(value); + + /* Try an exact match first. */ + if (!strcmp(colon + 1, start_ref)) { + /* Truncate the value before the colon. */ + nfasprintf(&config_repo, "%.*s", colon - value, value); + return 1; + } + + /* Try with a wildcard match now. */ + if (end - value > 2 && end[-2] == '/' && end[-1] == '*' && + colon - value > 2 && colon[-2] == '/' && colon[-1] == '*' && + (end - 2) - (colon + 1) == base_len && + !strncmp(colon + 1, start_ref, base_len)) { + /* Replace the star with the remote branch name. */ + nfasprintf(&config_repo, "%.*s%s", + (colon - 2) - value, value, + start_ref + base_len); + return 1; + } + + return 0; +} + +static int get_remote_config(const char *key, const char *value) +{ + const char *var; + if (prefixcmp(key, "remote.")) + return 0; + + var = strrchr(key, '.'); + if (var == key + 6) + return 0; + + if (!strcmp(var, ".fetch") && get_remote_branch_name(value)) + nfasprintf(&config_remote, "%.*s", var - (key + 7), key + 7); + + return 0; +} + +static void set_branch_defaults(const char *name, const char *real_ref) +{ + char key[1024]; + const char *slash = strrchr(real_ref, '/'); + + if (!slash) + return; + + start_ref = real_ref; + start_len = strlen(real_ref); + base_len = slash - real_ref; + git_config(get_remote_config); + + if (config_repo && config_remote) { + if (sizeof(key) <= + snprintf(key, sizeof(key), "branch.%s.remote", name)) + die("what a long branch name you have!"); + git_config_set(key, config_remote); + + /* + * We do not have to check if we have enough space for + * the 'merge' key, since it's shorter than the + * previous 'remote' key, which we already checked. + */ + snprintf(key, sizeof(key), "branch.%s.merge", name); + git_config_set(key, config_repo); + + printf("Branch %s set up to track remote branch %s.\n", + name, real_ref); + } + + if (config_repo) + free(config_repo); + if (config_remote) + free(config_remote); +} + static void create_branch(const char *name, const char *start_name, - unsigned char *start_sha1, - int force, int reflog) + int force, int reflog, int track) { struct ref_lock *lock; struct commit *commit; unsigned char sha1[20]; - char ref[PATH_MAX], msg[PATH_MAX + 20]; + char *real_ref, ref[PATH_MAX], msg[PATH_MAX + 20]; int forcing = 0; snprintf(ref, sizeof ref, "refs/heads/%s", name); @@ -331,12 +430,23 @@ static void create_branch(const char *name, const char *start_name, forcing = 1; } - if (start_sha1) - /* detached HEAD */ - hashcpy(sha1, start_sha1); - else if (get_sha1(start_name, sha1)) + real_ref = NULL; + if (get_sha1(start_name, sha1)) die("Not a valid object name: '%s'.", start_name); + switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) { + case 0: + /* Not branching from any existing branch */ + real_ref = NULL; + break; + case 1: + /* Unique completion -- good */ + break; + default: + die("Ambiguous object name: '%s'.", start_name); + break; + } + if ((commit = lookup_commit_reference(sha1)) == NULL) die("Not a valid branch point: '%s'.", start_name); hashcpy(sha1, commit->object.sha1); @@ -355,8 +465,17 @@ static void create_branch(const char *name, const char *start_name, snprintf(msg, sizeof msg, "branch: Created from %s", start_name); + /* When branching off a remote branch, set up so that git-pull + automatically merges from there. So far, this is only done for + remotes registered via .git/config. */ + if (real_ref && track) + set_branch_defaults(name, real_ref); + if (write_ref_sha1(lock, sha1, msg) < 0) die("Failed to write ref: %s.", strerror(errno)); + + if (real_ref) + free(real_ref); } static void rename_branch(const char *oldname, const char *newname, int force) @@ -398,11 +517,12 @@ int cmd_branch(int argc, const char **argv, const char *prefix) int delete = 0, force_delete = 0, force_create = 0; int rename = 0, force_rename = 0; int verbose = 0, abbrev = DEFAULT_ABBREV, detached = 0; - int reflog = 0; + int reflog = 0, track; int kinds = REF_LOCAL_BRANCH; int i; git_config(git_branch_config); + track = branch_track_remotes; for (i = 1; i < argc; i++) { const char *arg = argv[i]; @@ -413,6 +533,14 @@ int cmd_branch(int argc, const char **argv, const char *prefix) i++; break; } + if (!strcmp(arg, "--track")) { + track = 1; + continue; + } + if (!strcmp(arg, "--no-track")) { + track = 0; + continue; + } if (!strcmp(arg, "-d")) { delete = 1; continue; @@ -498,10 +626,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix) rename_branch(head, argv[i], force_rename); else if (rename && (i == argc - 2)) rename_branch(argv[i], argv[i + 1], force_rename); - else if (i == argc - 1) - create_branch(argv[i], head, head_sha1, force_create, reflog); - else if (i == argc - 2) - create_branch(argv[i], argv[i+1], NULL, force_create, reflog); + else if (i == argc - 1 || i == argc - 2) + create_branch(argv[i], (i == argc - 2) ? argv[i+1] : head, + force_create, reflog, track); else usage(builtin_branch_usage); diff --git a/builtin-bundle.c b/builtin-bundle.c index 279b8f8e58..786808081b 100644 --- a/builtin-bundle.c +++ b/builtin-bundle.c @@ -160,7 +160,28 @@ static int fork_with_pipe(const char **argv, int *in, int *out) return pid; } -static int verify_bundle(struct bundle_header *header) +static int list_refs(struct ref_list *r, int argc, const char **argv) +{ + int i; + + for (i = 0; i < r->nr; i++) { + if (argc > 1) { + int j; + for (j = 1; j < argc; j++) + if (!strcmp(r->list[i].name, argv[j])) + break; + if (j == argc) + continue; + } + printf("%s %s\n", sha1_to_hex(r->list[i].sha1), + r->list[i].name); + } + return 0; +} + +#define PREREQ_MARK (1u<<16) + +static int verify_bundle(struct bundle_header *header, int verbose) { /* * Do fast check, then if any prereqs are missing then go line by line @@ -179,7 +200,7 @@ static int verify_bundle(struct bundle_header *header) struct ref_list_entry *e = p->list + i; struct object *o = parse_object(e->sha1); if (o) { - o->flags |= BOUNDARY_SHOW; + o->flags |= PREREQ_MARK; add_pending_object(&revs, o, e->name); continue; } @@ -187,7 +208,7 @@ static int verify_bundle(struct bundle_header *header) error(message); error("%s %s", sha1_to_hex(e->sha1), e->name); } - if (revs.pending.nr == 0) + if (revs.pending.nr != p->nr) return ret; req_nr = revs.pending.nr; setup_revisions(2, argv, &revs, NULL); @@ -202,7 +223,7 @@ static int verify_bundle(struct bundle_header *header) i = req_nr; while (i && (commit = get_revision(&revs))) - if (commit->object.flags & BOUNDARY_SHOW) + if (commit->object.flags & PREREQ_MARK) i--; for (i = 0; i < req_nr; i++) @@ -216,56 +237,24 @@ static int verify_bundle(struct bundle_header *header) for (i = 0; i < refs.nr; i++) clear_commit_marks((struct commit *)refs.objects[i].item, -1); + if (verbose) { + struct ref_list *r; + + r = &header->references; + printf("The bundle contains %d ref%s\n", + r->nr, (1 < r->nr) ? "s" : ""); + list_refs(r, 0, NULL); + r = &header->prerequisites; + printf("The bundle requires these %d ref%s\n", + r->nr, (1 < r->nr) ? "s" : ""); + list_refs(r, 0, NULL); + } return ret; } static int list_heads(struct bundle_header *header, int argc, const char **argv) { - int i; - struct ref_list *r = &header->references; - - for (i = 0; i < r->nr; i++) { - if (argc > 1) { - int j; - for (j = 1; j < argc; j++) - if (!strcmp(r->list[i].name, argv[j])) - break; - if (j == argc) - continue; - } - printf("%s %s\n", sha1_to_hex(r->list[i].sha1), - r->list[i].name); - } - return 0; -} - -static void show_commit(struct commit *commit) -{ - write_or_die(1, sha1_to_hex(commit->object.sha1), 40); - write_or_die(1, "\n", 1); - if (commit->parents) { - free_commit_list(commit->parents); - commit->parents = NULL; - } -} - -static void show_object(struct object_array_entry *p) -{ - /* An object with name "foo\n0000000..." can be used to - * confuse downstream git-pack-objects very badly. - */ - const char *ep = strchr(p->name, '\n'); - int len = ep ? ep - p->name : strlen(p->name); - write_or_die(1, sha1_to_hex(p->item->sha1), 40); - write_or_die(1, " ", 1); - if (len) - write_or_die(1, p->name, len); - write_or_die(1, "\n", 1); -} - -static void show_edge(struct commit *commit) -{ - ; /* nothing to do */ + return list_refs(&header->references, argc, argv); } static int create_bundle(struct bundle_header *header, const char *path, @@ -273,19 +262,23 @@ static int create_bundle(struct bundle_header *header, const char *path, { int bundle_fd = -1; const char **argv_boundary = xmalloc((argc + 4) * sizeof(const char *)); - const char **argv_pack = xmalloc(4 * sizeof(const char *)); - int pid, in, out, i, status; + const char **argv_pack = xmalloc(5 * sizeof(const char *)); + int pid, in, out, i, status, ref_count = 0; char buffer[1024]; struct rev_info revs; bundle_fd = (!strcmp(path, "-") ? 1 : - open(path, O_CREAT | O_WRONLY, 0666)); + open(path, O_CREAT | O_EXCL | O_WRONLY, 0666)); if (bundle_fd < 0) - return error("Could not write to '%s'", path); + return error("Could not create '%s': %s", path, strerror(errno)); /* write signature */ write_or_die(bundle_fd, bundle_signature, strlen(bundle_signature)); + /* init revs to list objects for pack-objects later */ + save_commit_buffer = 0; + init_revisions(&revs, NULL); + /* write prerequisites */ memcpy(argv_boundary + 3, argv + 1, argc * sizeof(const char *)); argv_boundary[0] = "rev-list"; @@ -296,9 +289,20 @@ static int create_bundle(struct bundle_header *header, const char *path, pid = fork_with_pipe(argv_boundary, NULL, &out); if (pid < 0) return -1; - while ((i = read_string(out, buffer, sizeof(buffer))) > 0) - if (buffer[0] == '-') + while ((i = read_string(out, buffer, sizeof(buffer))) > 0) { + unsigned char sha1[20]; + if (buffer[0] == '-') { write_or_die(bundle_fd, buffer, i); + if (!get_sha1_hex(buffer + 1, sha1)) { + struct object *object = parse_object(sha1); + object->flags |= UNINTERESTING; + add_pending_object(&revs, object, buffer); + } + } else if (!get_sha1_hex(buffer, sha1)) { + struct object *object = parse_object(sha1); + object->flags |= SHOWN; + } + } while ((i = waitpid(pid, &status, 0)) < 0) if (errno != EINTR) return error("rev-list died"); @@ -306,28 +310,38 @@ static int create_bundle(struct bundle_header *header, const char *path, return error("rev-list died %d", WEXITSTATUS(status)); /* write references */ - save_commit_buffer = 0; - init_revisions(&revs, NULL); - revs.tag_objects = 1; - revs.tree_objects = 1; - revs.blob_objects = 1; argc = setup_revisions(argc, argv, &revs, NULL); if (argc > 1) return error("unrecognized argument: %s'", argv[1]); + for (i = 0; i < revs.pending.nr; i++) { struct object_array_entry *e = revs.pending.objects + i; - if (!(e->item->flags & UNINTERESTING)) { - unsigned char sha1[20]; - char *ref; - if (dwim_ref(e->name, strlen(e->name), sha1, &ref) != 1) - continue; - write_or_die(bundle_fd, sha1_to_hex(e->item->sha1), 40); - write_or_die(bundle_fd, " ", 1); - write_or_die(bundle_fd, ref, strlen(ref)); - write_or_die(bundle_fd, "\n", 1); - free(ref); + unsigned char sha1[20]; + char *ref; + + if (e->item->flags & UNINTERESTING) + continue; + if (dwim_ref(e->name, strlen(e->name), sha1, &ref) != 1) + continue; + /* + * Make sure the refs we wrote out is correct; --max-count and + * other limiting options could have prevented all the tips + * from getting output. + */ + if (!(e->item->flags & SHOWN)) { + warn("ref '%s' is excluded by the rev-list options", + e->name); + continue; } + ref_count++; + write_or_die(bundle_fd, sha1_to_hex(e->item->sha1), 40); + write_or_die(bundle_fd, " ", 1); + write_or_die(bundle_fd, ref, strlen(ref)); + write_or_die(bundle_fd, "\n", 1); + free(ref); } + if (!ref_count) + die ("Refusing to create empty bundle."); /* end header */ write_or_die(bundle_fd, "\n", 1); @@ -336,36 +350,42 @@ static int create_bundle(struct bundle_header *header, const char *path, argv_pack[0] = "pack-objects"; argv_pack[1] = "--all-progress"; argv_pack[2] = "--stdout"; - argv_pack[3] = NULL; + argv_pack[3] = "--thin"; + argv_pack[4] = NULL; in = -1; out = bundle_fd; pid = fork_with_pipe(argv_pack, &in, &out); if (pid < 0) return error("Could not spawn pack-objects"); - close(1); - dup2(in, 1); + for (i = 0; i < revs.pending.nr; i++) { + struct object *object = revs.pending.objects[i].item; + if (object->flags & UNINTERESTING) + write(in, "^", 1); + write(in, sha1_to_hex(object->sha1), 40); + write(in, "\n", 1); + } close(in); - prepare_revision_walk(&revs); - mark_edges_uninteresting(revs.commits, &revs, show_edge); - traverse_commit_list(&revs, show_commit, show_object); - close(1); while (waitpid(pid, &status, 0) < 0) if (errno != EINTR) return -1; if (!WIFEXITED(status) || WEXITSTATUS(status)) return error ("pack-objects died"); - return 0; + + return status; } static int unbundle(struct bundle_header *header, int bundle_fd, int argc, const char **argv) { - const char *argv_index_pack[] = {"index-pack", "--stdin", NULL}; + const char *argv_index_pack[] = {"index-pack", + "--fix-thin", "--stdin", NULL}; int pid, status, dev_null; - if (verify_bundle(header)) + if (verify_bundle(header, 0)) return -1; dev_null = open("/dev/null", O_WRONLY); + if (dev_null < 0) + return error("Could not open /dev/null"); pid = fork_with_pipe(argv_index_pack, &bundle_fd, &dev_null); if (pid < 0) return error("Could not spawn index-pack"); @@ -402,12 +422,12 @@ int cmd_bundle(int argc, const char **argv, const char *prefix) memset(&header, 0, sizeof(header)); if (strcmp(cmd, "create") && - !(bundle_fd = read_header(bundle_file, &header))) + (bundle_fd = read_header(bundle_file, &header)) < 0) return 1; if (!strcmp(cmd, "verify")) { close(bundle_fd); - if (verify_bundle(&header)) + if (verify_bundle(&header, 1)) return 1; fprintf(stderr, "%s is okay\n", bundle_file); return 0; @@ -427,4 +447,3 @@ int cmd_bundle(int argc, const char **argv, const char *prefix) } else usage(bundle_usage); } - diff --git a/builtin-fsck.c b/builtin-fsck.c index 39cfc32818..b8e71b640b 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -18,6 +18,9 @@ static int check_full; static int check_strict; static int keep_cache_objects; static unsigned char head_sha1[20]; +static int errors_found; +#define ERROR_OBJECT 01 +#define ERROR_REACHABLE 02 #ifdef NO_D_INO_IN_DIRENT #define SORT_DIRENT 0 @@ -40,6 +43,7 @@ static int objerror(struct object *obj, const char *err, ...) { va_list params; va_start(params, err); + errors_found |= ERROR_OBJECT; objreport(obj, "error", err, params); va_end(params); return -1; @@ -67,9 +71,10 @@ static void check_reachable_object(struct object *obj) * do a full fsck */ if (!obj->parsed) { - if (has_sha1_file(obj->sha1)) + if (has_sha1_pack(obj->sha1, NULL)) return; /* it is in pack - forget about it */ printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1)); + errors_found |= ERROR_REACHABLE; return; } @@ -88,6 +93,7 @@ static void check_reachable_object(struct object *obj) typename(obj->type), sha1_to_hex(obj->sha1)); printf(" to %7s %s\n", typename(ref->type), sha1_to_hex(ref->sha1)); + errors_found |= ERROR_REACHABLE; } } } @@ -346,8 +352,11 @@ static int fsck_tag(struct tag *tag) static int fsck_sha1(unsigned char *sha1) { struct object *obj = parse_object(sha1); - if (!obj) - return error("%s: object corrupt or missing", sha1_to_hex(sha1)); + if (!obj) { + errors_found |= ERROR_OBJECT; + return error("%s: object corrupt or missing", + sha1_to_hex(sha1)); + } if (obj->flags & SEEN) return 0; obj->flags |= SEEN; @@ -359,8 +368,10 @@ static int fsck_sha1(unsigned char *sha1) return fsck_commit((struct commit *) obj); if (obj->type == OBJ_TAG) return fsck_tag((struct tag *) obj); + /* By now, parse_object() would've returned NULL instead. */ - return objerror(obj, "unknown type '%d' (internal fsck error)", obj->type); + return objerror(obj, "unknown type '%d' (internal fsck error)", + obj->type); } /* @@ -576,11 +587,16 @@ static int fsck_cache_tree(struct cache_tree *it) return err; } +static const char fsck_usage[] = +"git-fsck [--tags] [--root] [[--unreachable] [--cache] [--full] " +"[--strict] <head-sha1>*]"; + int cmd_fsck(int argc, char **argv, const char *prefix) { int i, heads; track_object_refs = 1; + errors_found = 0; for (i = 1; i < argc; i++) { const char *arg = argv[i]; @@ -610,7 +626,7 @@ int cmd_fsck(int argc, char **argv, const char *prefix) continue; } if (*arg == '-') - usage("git-fsck [--tags] [--root] [[--unreachable] [--cache] [--full] [--strict] <head-sha1>*]"); + usage(fsck_usage); } fsck_head_link(); @@ -690,5 +706,5 @@ int cmd_fsck(int argc, char **argv, const char *prefix) } check_connectivity(); - return 0; + return errors_found; } diff --git a/builtin-grep.c b/builtin-grep.c index 694da5ba09..4510d35324 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -431,6 +431,19 @@ static const char emsg_missing_context_len[] = static const char emsg_missing_argument[] = "option requires an argument -%s"; +static int strtoul_ui(char const *s, unsigned int *result) +{ + unsigned long ul; + char *p; + + errno = 0; + ul = strtoul(s, &p, 10); + if (errno || *p || p == s || (unsigned int) ul != ul) + return -1; + *result = ul; + return 0; +} + int cmd_grep(int argc, const char **argv, const char *prefix) { int hit = 0; @@ -553,7 +566,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) scan = arg + 1; break; } - if (sscanf(scan, "%u", &num) != 1) + if (strtoul_ui(scan, &num)) die(emsg_invalid_context_len, scan); switch (arg[1]) { case 'A': diff --git a/builtin-log.c b/builtin-log.c index 1c9f7d02a8..865832c85e 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -482,10 +482,22 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) memcpy(add_signoff, committer, endpos - committer + 1); add_signoff[endpos - committer + 1] = 0; } - else if (!strcmp(argv[i], "--attach")) + else if (!strcmp(argv[i], "--attach")) { rev.mime_boundary = git_version_string; - else if (!prefixcmp(argv[i], "--attach=")) + rev.no_inline = 1; + } + else if (!prefixcmp(argv[i], "--attach=")) { + rev.mime_boundary = argv[i] + 9; + rev.no_inline = 1; + } + else if (!strcmp(argv[i], "--inline")) { + rev.mime_boundary = git_version_string; + rev.no_inline = 0; + } + else if (!prefixcmp(argv[i], "--inline=")) { rev.mime_boundary = argv[i] + 9; + rev.no_inline = 0; + } else if (!strcmp(argv[i], "--ignore-if-in-upstream")) ignore_if_in_upstream = 1; else if (!strcmp(argv[i], "--thread")) diff --git a/builtin-push.c b/builtin-push.c index 979efcc45f..6ab9a28e8c 100644 --- a/builtin-push.c +++ b/builtin-push.c @@ -336,7 +336,7 @@ static int do_push(const char *repo) argv[dest_argc] = NULL; if (verbose) fprintf(stderr, "Pushing to %s\n", dest); - err = run_command_v(argv); + err = run_command_v_opt(argv, 0); if (!err) continue; switch (err) { diff --git a/builtin-revert.c b/builtin-revert.c new file mode 100644 index 0000000000..652eece5ad --- /dev/null +++ b/builtin-revert.c @@ -0,0 +1,404 @@ +#include "cache.h" +#include "builtin.h" +#include "object.h" +#include "commit.h" +#include "tag.h" +#include "wt-status.h" +#include "run-command.h" +#include "exec_cmd.h" +#include "utf8.h" + +/* + * This implements the builtins revert and cherry-pick. + * + * Copyright (c) 2007 Johannes E. Schindelin + * + * Based on git-revert.sh, which is + * + * Copyright (c) 2005 Linus Torvalds + * Copyright (c) 2005 Junio C Hamano + */ + +static const char *revert_usage = "git-revert [--edit | --no-edit] [-n] <commit-ish>"; + +static const char *cherry_pick_usage = "git-cherry-pick [--edit] [-n] [-r] [-x] <commit-ish>"; + +static int edit; +static int replay; +enum { REVERT, CHERRY_PICK } action; +static int no_commit; +static struct commit *commit; +static int needed_deref; + +static const char *me; + +#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION" + +static void parse_options(int argc, const char **argv) +{ + const char *usage_str = action == REVERT ? + revert_usage : cherry_pick_usage; + unsigned char sha1[20]; + const char *arg; + int i; + + if (argc < 2) + usage(usage_str); + + for (i = 1; i < argc - 1; i++) { + arg = argv[i]; + if (!strcmp(arg, "-n") || !strcmp(arg, "--no-commit")) + no_commit = 1; + else if (!strcmp(arg, "-e") || !strcmp(arg, "--edit")) + edit = 1; + else if (!strcmp(arg, "--no-edit")) + edit = 0; + else if (!strcmp(arg, "-x") || !strcmp(arg, "--i-really-want-" + "to-expose-my-private-commit-object-name")) + replay = 0; + else if (strcmp(arg, "-r")) + usage(usage_str); + } + + arg = argv[argc - 1]; + if (get_sha1(arg, sha1)) + die ("Cannot find '%s'", arg); + commit = (struct commit *)parse_object(sha1); + if (!commit) + die ("Could not find %s", sha1_to_hex(sha1)); + if (commit->object.type == OBJ_TAG) { + commit = (struct commit *) + deref_tag((struct object *)commit, arg, strlen(arg)); + needed_deref = 1; + } + if (commit->object.type != OBJ_COMMIT) + die ("'%s' does not point to a commit", arg); +} + +static char *get_oneline(const char *message) +{ + char *result; + const char *p = message, *abbrev, *eol; + int abbrev_len, oneline_len; + + if (!p) + die ("Could not read commit message of %s", + sha1_to_hex(commit->object.sha1)); + while (*p && (*p != '\n' || p[1] != '\n')) + p++; + + if (*p) { + p += 2; + for (eol = p + 1; *eol && *eol != '\n'; eol++) + ; /* do nothing */ + } else + eol = p; + abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV); + abbrev_len = strlen(abbrev); + oneline_len = eol - p; + result = xmalloc(abbrev_len + 5 + oneline_len); + memcpy(result, abbrev, abbrev_len); + memcpy(result + abbrev_len, "... ", 4); + memcpy(result + abbrev_len + 4, p, oneline_len); + result[abbrev_len + 4 + oneline_len] = '\0'; + return result; +} + +char *get_encoding(const char *message) +{ + const char *p = message, *eol; + + if (!p) + die ("Could not read commit message of %s", + sha1_to_hex(commit->object.sha1)); + while (*p && *p != '\n') { + for (eol = p + 1; *eol && *eol != '\n'; eol++) + ; /* do nothing */ + if (!prefixcmp(p, "encoding ")) { + char *result = xmalloc(eol - 8 - p); + strlcpy(result, p + 9, eol - 8 - p); + return result; + } + p = eol; + if (*p == '\n') + p++; + } + return NULL; +} + +struct lock_file msg_file; +static int msg_fd; + +static void add_to_msg(const char *string) +{ + int len = strlen(string); + if (write_in_full(msg_fd, string, len) < 0) + die ("Could not write to .msg"); +} + +static void add_message_to_msg(const char *message) +{ + const char *p = message; + while (*p && (*p != '\n' || p[1] != '\n')) + p++; + + if (!*p) + add_to_msg(sha1_to_hex(commit->object.sha1)); + + p += 2; + add_to_msg(p); + return; +} + +static void set_author_ident_env(const char *message) +{ + 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 = xmalloc(eol + 1 - p); + memcpy(line, p, eol - p); + line[eol - p] = '\0'; + 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 email 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)); +} + +static int merge_recursive(const char *base_sha1, + const char *head_sha1, const char *head_name, + const char *next_sha1, const char *next_name) +{ + char buffer[256]; + const char *argv[6]; + + sprintf(buffer, "GITHEAD_%s", head_sha1); + setenv(buffer, head_name, 1); + sprintf(buffer, "GITHEAD_%s", next_sha1); + setenv(buffer, next_name, 1); + + /* + * This three way merge is an interesting one. We are at + * $head, and would want to apply the change between $commit + * and $prev on top of us (when reverting), or the change between + * $prev and $commit on top of us (when cherry-picking or replaying). + */ + argv[0] = "merge-recursive"; + argv[1] = base_sha1; + argv[2] = "--"; + argv[3] = head_sha1; + argv[4] = next_sha1; + argv[5] = NULL; + + return run_command_v_opt(argv, RUN_COMMAND_NO_STDIN | RUN_GIT_CMD); +} + +static int revert_or_cherry_pick(int argc, const char **argv) +{ + unsigned char head[20]; + struct commit *base, *next; + int i; + char *oneline, *encoding, *reencoded_message = NULL; + const char *message; + + git_config(git_default_config); + me = action == REVERT ? "revert" : "cherry-pick"; + setenv(GIT_REFLOG_ACTION, me, 0); + parse_options(argc, argv); + + /* this is copied from the shell script, but it's never triggered... */ + if (action == REVERT && replay) + die("revert is incompatible with replay"); + + if (no_commit) { + /* + * We do not intend to commit immediately. We just want to + * merge the differences in. + */ + if (write_tree(head, 0, NULL)) + die ("Your index file is unmerged."); + } else { + struct wt_status s; + + if (get_sha1("HEAD", head)) + die ("You do not have a valid HEAD"); + wt_status_prepare(&s); + if (s.commitable || s.workdir_dirty) + die ("Dirty index: cannot %s", me); + discard_cache(); + } + + if (!commit->parents) + die ("Cannot %s a root commit", me); + if (commit->parents->next) + die ("Cannot %s a multi-parent commit.", me); + if (!(message = commit->buffer)) + die ("Cannot get commit message for %s", + sha1_to_hex(commit->object.sha1)); + + /* + * "commit" is an existing commit. We would want to apply + * the difference it introduces since its first parent "prev" + * on top of the current HEAD if we are cherry-pick. Or the + * reverse of it if we are revert. + */ + + msg_fd = hold_lock_file_for_update(&msg_file, ".msg", 1); + + encoding = get_encoding(message); + if (!encoding) + encoding = "utf-8"; + if (!git_commit_encoding) + git_commit_encoding = "utf-8"; + if ((reencoded_message = reencode_string(message, + git_commit_encoding, encoding))) + message = reencoded_message; + + oneline = get_oneline(message); + + if (action == REVERT) { + base = commit; + next = commit->parents->item; + add_to_msg("Revert "); + add_to_msg(find_unique_abbrev(commit->object.sha1, + DEFAULT_ABBREV)); + add_to_msg(oneline); + add_to_msg("\nThis reverts commit "); + add_to_msg(sha1_to_hex(commit->object.sha1)); + add_to_msg(".\n"); + } else { + base = commit->parents->item; + next = commit; + set_author_ident_env(message); + add_message_to_msg(message); + if (!replay) { + add_to_msg("(cherry picked from commit "); + add_to_msg(sha1_to_hex(commit->object.sha1)); + add_to_msg(")\n"); + } + } + if (needed_deref) { + add_to_msg("(original 'git "); + add_to_msg(me); + add_to_msg("' arguments: "); + for (i = 0; i < argc; i++) { + if (i) + add_to_msg(" "); + add_to_msg(argv[i]); + } + add_to_msg(")\n"); + } + + if (merge_recursive(sha1_to_hex(base->object.sha1), + sha1_to_hex(head), "HEAD", + sha1_to_hex(next->object.sha1), oneline) || + write_tree(head, 0, NULL)) { + const char *target = git_path("MERGE_MSG"); + add_to_msg("\nConflicts:\n\n"); + read_cache(); + for (i = 0; i < active_nr;) { + struct cache_entry *ce = active_cache[i++]; + if (ce_stage(ce)) { + add_to_msg("\t"); + add_to_msg(ce->name); + add_to_msg("\n"); + while (i < active_nr && !strcmp(ce->name, + active_cache[i]->name)) + i++; + } + } + if (close(msg_fd) || commit_lock_file(&msg_file) < 0) + die ("Error wrapping up .msg"); + unlink(target); + if (rename(".msg", target)) + die ("Could not move .msg to %s", target); + fprintf(stderr, "Automatic %s failed. " + "After resolving the conflicts,\n" + "mark the corrected paths with 'git-add <paths>'\n" + "and commit the result.\n", me); + if (action == CHERRY_PICK) { + fprintf(stderr, "When commiting, use the option " + "'-c %s' to retain authorship and message.\n", + find_unique_abbrev(commit->object.sha1, + DEFAULT_ABBREV)); + } + exit(1); + } + if (close(msg_fd) || commit_lock_file(&msg_file) < 0) + die ("Error wrapping up .msg"); + fprintf(stderr, "Finished one %s.\n", me); + + /* + * + * If we are cherry-pick, and if the merge did not result in + * hand-editing, we will hit this commit and inherit the original + * author date and name. + * If we are revert, or if our cherry-pick results in a hand merge, + * we had better say that the current user is responsible for that. + */ + + if (!no_commit) { + if (edit) + return execl_git_cmd("commit", "-n", "-F", ".msg", + "-e", NULL); + else + return execl_git_cmd("commit", "-n", "-F", ".msg", + NULL); + } + if (reencoded_message) + free(reencoded_message); + + return 0; +} + +int cmd_revert(int argc, const char **argv, const char *prefix) +{ + if (isatty(0)) + edit = 1; + action = REVERT; + return revert_or_cherry_pick(argc, argv); +} + +int cmd_cherry_pick(int argc, const char **argv, const char *prefix) +{ + replay = 1; + action = CHERRY_PICK; + return revert_or_cherry_pick(argc, argv); +} diff --git a/builtin-shortlog.c b/builtin-shortlog.c index 2d7726e8b9..29343aefc8 100644 --- a/builtin-shortlog.c +++ b/builtin-shortlog.c @@ -304,8 +304,11 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix) if (!access(".mailmap", R_OK)) read_mailmap(".mailmap"); - if (rev.pending.nr == 0) + if (rev.pending.nr == 0) { + if (isatty(0)) + fprintf(stderr, "(reading log to summarize from standard input)\n"); read_from_stdin(&list); + } else get_from_rev(&rev, &list); @@ -24,6 +24,7 @@ extern int cmd_cat_file(int argc, const char **argv, const char *prefix); extern int cmd_checkout_index(int argc, const char **argv, const char *prefix); extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix); extern int cmd_cherry(int argc, const char **argv, const char *prefix); +extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix); extern int cmd_commit_tree(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); @@ -60,6 +61,7 @@ extern int cmd_config(int argc, const char **argv, const char *prefix); extern int cmd_rerere(int argc, const char **argv, const char *prefix); extern int cmd_rev_list(int argc, const char **argv, const char *prefix); extern int cmd_rev_parse(int argc, const char **argv, const char *prefix); +extern int cmd_revert(int argc, const char **argv, const char *prefix); extern int cmd_rm(int argc, const char **argv, const char *prefix); extern int cmd_runstatus(int argc, const char **argv, const char *prefix); extern int cmd_shortlog(int argc, const char **argv, const char *prefix); @@ -281,7 +281,6 @@ char *enter_repo(char *path, int strict); /* Read and unpack a sha1 file into memory, write memory to a sha1 file */ extern int sha1_object_info(const unsigned char *, unsigned long *); -extern void * unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size); extern void * read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size); extern int hash_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *sha1); extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1); @@ -481,6 +480,7 @@ extern struct tag *alloc_tag_node(void); extern void alloc_report(void); /* trace.c */ +extern int nfasprintf(char **str, const char *fmt, ...); extern int nfvasprintf(char **str, const char *fmt, va_list va); extern void trace_printf(const char *format, ...); extern void trace_argv_printf(const char **argv, int count, const char *format, ...); diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el index 13d198229b..db87a37895 100644 --- a/contrib/emacs/git.el +++ b/contrib/emacs/git.el @@ -891,36 +891,77 @@ and returns the process output as a string." (with-current-buffer log-edit-parent-buffer (git-get-filenames (git-marked-files-state 'added 'deleted 'modified)))) +(defun git-append-sign-off (name email) + "Append a Signed-off-by entry to the current buffer, avoiding duplicates." + (let ((sign-off (format "Signed-off-by: %s <%s>" name email)) + (case-fold-search t)) + (goto-char (point-min)) + (unless (re-search-forward (concat "^" (regexp-quote sign-off)) nil t) + (goto-char (point-min)) + (unless (re-search-forward "^Signed-off-by: " nil t) + (setq sign-off (concat "\n" sign-off))) + (goto-char (point-max)) + (insert sign-off "\n")))) + +(defun git-setup-log-buffer (buffer &optional author-name author-email subject date msg) + "Setup the log buffer for a commit." + (unless git-status (error "Not in git-status buffer.")) + (let ((merge-heads (git-get-merge-heads)) + (dir default-directory) + (committer-name (git-get-committer-name)) + (committer-email (git-get-committer-email)) + (sign-off git-append-signed-off-by)) + (with-current-buffer buffer + (cd dir) + (erase-buffer) + (insert + (propertize + (format "Author: %s <%s>\n%s%s" + (or author-name committer-name) + (or author-email committer-email) + (if date (format "Date: %s\n" date) "") + (if merge-heads + (format "Parent: %s\n%s\n" + (git-rev-parse "HEAD") + (mapconcat (lambda (str) (concat "Parent: " str)) merge-heads "\n")) + "")) + 'face 'git-header-face) + (propertize git-log-msg-separator 'face 'git-separator-face) + "\n") + (when subject (insert subject "\n\n")) + (cond (msg (insert msg "\n")) + ((file-readable-p ".dotest/msg") + (insert-file-contents ".dotest/msg")) + ((file-readable-p ".git/MERGE_MSG") + (insert-file-contents ".git/MERGE_MSG"))) + ; delete empty lines at end + (goto-char (point-min)) + (when (re-search-forward "\n+\\'" nil t) + (replace-match "\n" t t)) + (when sign-off (git-append-sign-off committer-name committer-email))))) + (defun git-commit-file () "Commit the marked file(s), asking for a commit message." (interactive) (unless git-status (error "Not in git-status buffer.")) (let ((buffer (get-buffer-create "*git-commit*")) - (merge-heads (git-get-merge-heads)) - (dir default-directory) (coding-system (git-get-commits-coding-system)) - (sign-off git-append-signed-off-by)) - (with-current-buffer buffer - (when (eq 0 (buffer-size)) - (cd dir) - (erase-buffer) - (insert - (propertize - (format "Author: %s <%s>\n%s" - (git-get-committer-name) (git-get-committer-email) - (if merge-heads - (format "Parent: %s\n%s\n" - (git-rev-parse "HEAD") - (mapconcat (lambda (str) (concat "Parent: " str)) merge-heads "\n")) - "")) - 'face 'git-header-face) - (propertize git-log-msg-separator 'face 'git-separator-face) - "\n") - (cond ((file-readable-p ".git/MERGE_MSG") - (insert-file-contents ".git/MERGE_MSG")) - (sign-off - (insert (format "\n\nSigned-off-by: %s <%s>\n" - (git-get-committer-name) (git-get-committer-email))))))) + author-name author-email subject date) + (when (eq 0 (buffer-size buffer)) + (when (file-readable-p ".dotest/info") + (with-temp-buffer + (insert-file-contents ".dotest/info") + (goto-char (point-min)) + (when (re-search-forward "^Author: \\(.*\\)\nEmail: \\(.*\\)$" nil t) + (setq author-name (match-string 1)) + (setq author-email (match-string 2))) + (goto-char (point-min)) + (when (re-search-forward "^Subject: \\(.*\\)$" nil t) + (setq subject (match-string 1))) + (goto-char (point-min)) + (when (re-search-forward "^Date: \\(.*\\)$" nil t) + (setq date (match-string 1))))) + (git-setup-log-buffer buffer author-name author-email subject date)) (log-edit #'git-do-commit nil #'git-log-edit-files buffer) (setq font-lock-keywords (font-lock-compile-keywords git-log-edit-font-lock-keywords)) (setq buffer-file-coding-system coding-system) diff --git a/diff-lib.c b/diff-lib.c index 778cf58244..6abb981534 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -30,22 +30,28 @@ static int read_directory(const char *path, struct path_list *list) return 0; } +static int get_mode(const char *path, int *mode) +{ + struct stat st; + + if (!path || !strcmp(path, "/dev/null")) + *mode = 0; + else if (!strcmp(path, "-")) + *mode = ntohl(create_ce_mode(0666)); + else if (stat(path, &st)) + return error("Could not access '%s'", path); + else + *mode = st.st_mode; + return 0; +} + static int queue_diff(struct diff_options *o, const char *name1, const char *name2) { - struct stat st; int mode1 = 0, mode2 = 0; - if (name1) { - if (stat(name1, &st)) - return error("Could not access '%s'", name1); - mode1 = st.st_mode; - } - if (name2) { - if (stat(name2, &st)) - return error("Could not access '%s'", name2); - mode2 = st.st_mode; - } + if (get_mode(name1, &mode1) || get_mode(name2, &mode2)) + return -1; if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2)) return error("file/directory conflict: %s, %s", name1, name2); @@ -224,7 +230,7 @@ int setup_diff_no_index(struct rev_info *revs, { int i; for (i = 1; i < argc; i++) - if (argv[i][0] != '-') + if (argv[i][0] != '-' || argv[i][1] == '\0') break; else if (!strcmp(argv[i], "--")) { i++; @@ -254,9 +260,15 @@ int setup_diff_no_index(struct rev_info *revs, revs->diffopt.paths = xcalloc(2, sizeof(char*)); for (i = 0; i < 2; i++) { - const char *p; - p = prefix_filename(prefix, len, argv[argc - 2 + i]); - revs->diffopt.paths[i] = xstrdup(p); + const char *p = argv[argc - 2 + i]; + /* + * stdin should be spelled as '-'; if you have + * path that is '-', spell it as ./-. + */ + p = (strcmp(p, "-") + ? xstrdup(prefix_filename(prefix, len, p)) + : p); + revs->diffopt.paths[i] = p; } } else @@ -1364,6 +1364,32 @@ static struct sha1_size_cache *locate_size_cache(unsigned char *sha1, return e; } +static int populate_from_stdin(struct diff_filespec *s) +{ +#define INCREMENT 1024 + char *buf; + unsigned long size; + int got; + + size = 0; + buf = NULL; + while (1) { + buf = xrealloc(buf, size + INCREMENT); + got = xread(0, buf + size, INCREMENT); + if (!got) + break; /* EOF */ + if (got < 0) + return error("error while reading from stdin %s", + strerror(errno)); + size += got; + } + s->should_munmap = 0; + s->data = buf; + s->size = size; + s->should_free = 1; + return 0; +} + /* * While doing rename detection and pickaxe operation, we may need to * grab the data for the blob (or file) for our own in-core comparison. @@ -1389,6 +1415,9 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only) char *buf; unsigned long size; + if (!strcmp(s->path, "-")) + return populate_from_stdin(s); + if (lstat(s->path, &st) < 0) { if (errno == ENOENT) { err_empty: @@ -1690,6 +1719,10 @@ static void diff_fill_sha1_info(struct diff_filespec *one) if (DIFF_FILE_VALID(one)) { if (!one->sha1_valid) { struct stat st; + if (!strcmp(one->path, "-")) { + hashcpy(one->sha1, null_sha1); + return; + } if (lstat(one->path, &st) < 0) die("stat %s", one->path); if (index_path(one->sha1, one->path, &st, 0)) diff --git a/fast-import.c b/fast-import.c index 726f5ba7d2..55ffae4fa6 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1058,7 +1058,7 @@ static void load_tree(struct tree_entry *root) struct tree_entry *e = new_tree_entry(); if (t->entry_count == t->entry_capacity) - root->tree = t = grow_tree_content(t, 8); + root->tree = t = grow_tree_content(t, t->entry_count); t->entries[t->entry_count++] = e; e->tree = NULL; @@ -1066,7 +1066,7 @@ static void load_tree(struct tree_entry *root) if (!c) die("Corrupt mode in %s", sha1_to_hex(sha1)); e->versions[0].mode = e->versions[1].mode; - e->name = to_atom(c, (unsigned short)strlen(c)); + e->name = to_atom(c, strlen(c)); c += e->name->str_len + 1; hashcpy(e->versions[0].sha1, (unsigned char*)c); hashcpy(e->versions[1].sha1, (unsigned char*)c); @@ -1225,9 +1225,9 @@ static int tree_content_set( } if (t->entry_count == t->entry_capacity) - root->tree = t = grow_tree_content(t, 8); + root->tree = t = grow_tree_content(t, t->entry_count); e = new_tree_entry(); - e->name = to_atom(p, (unsigned short)n); + e->name = to_atom(p, n); e->versions[0].mode = 0; hashclr(e->versions[0].sha1); t->entries[t->entry_count++] = e; diff --git a/git-checkout.sh b/git-checkout.sh index 14835a4aa9..6caa9fdcc6 100755 --- a/git-checkout.sh +++ b/git-checkout.sh @@ -12,6 +12,7 @@ new= new_name= force= branch= +track= newbranch= newbranch_log= merge= @@ -33,7 +34,10 @@ while [ "$#" != "0" ]; do die "git checkout: we do not like '$newbranch' as a branch name." ;; "-l") - newbranch_log=1 + newbranch_log=-l + ;; + "--track"|"--no-track") + track="$arg" ;; "-f") force=1 @@ -85,6 +89,11 @@ while [ "$#" != "0" ]; do esac done +case "$new_branch,$track" in +,--*) + die "git checkout: --track and --no-track require -b" +esac + case "$force$merge" in 11) die "git checkout: -f and -m are incompatible" @@ -235,11 +244,7 @@ fi # if [ "$?" -eq 0 ]; then if [ "$newbranch" ]; then - if [ "$newbranch_log" ]; then - mkdir -p $(dirname "$GIT_DIR/logs/refs/heads/$newbranch") - touch "$GIT_DIR/logs/refs/heads/$newbranch" - fi - git-update-ref -m "checkout: Created from $new_name" "refs/heads/$newbranch" $new || exit + git-branch $track $newbranch_log "$newbranch" "$new_name" || exit branch="$newbranch" fi if test -n "$branch" diff --git a/git-commit.sh b/git-commit.sh index b8c00b8236..3656d607d5 100755 --- a/git-commit.sh +++ b/git-commit.sh @@ -3,7 +3,7 @@ # Copyright (c) 2005 Linus Torvalds # Copyright (c) 2006 Junio C Hamano -USAGE='[-a] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [[-i | -o] <path>...]' +USAGE='[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [[-i | -o] <path>...]' SUBDIRECTORY_OK=Yes . git-sh-setup require_work_tree @@ -71,6 +71,7 @@ trap ' all= also= +interactive= only= logfile= use_commit= @@ -131,6 +132,11 @@ do also=t shift ;; + --int|--inte|--inter|--intera|--interac|--interact|--interacti|\ + --interactiv|--interactive) + interactive=t + shift + ;; -o|--o|--on|--onl|--only) only=t shift @@ -304,12 +310,14 @@ case "$#,$also,$only,$amend" in ;; esac unset only -case "$all,$also,$#" in -t,t,*) - die "Cannot use -a and -i at the same time." ;; +case "$all,$interactive,$also,$#" in +*t,*t,*) + die "Cannot use -a, --interactive or -i at the same time." ;; t,,[1-9]*) die "Paths with -a does not make sense." ;; -,t,0) +,t,[1-9]*) + die "Paths with --interactive does not make sense." ;; +,,t,0) die "No paths with -i does not make sense." ;; esac @@ -344,6 +352,9 @@ t,) ) || exit ;; ,) + if test "$interactive" = t; then + git add --interactive || exit + fi case "$#" in 0) ;; # commit as-is diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 1bf892e4c1..65fcc84049 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -957,12 +957,12 @@ sub req_update { $log->info("Merged successfully"); print "M M $filename\n"; - $log->debug("Update-existing $dirpart"); + $log->debug("Merged $dirpart"); # Don't want to actually _DO_ the update if -n specified unless ( $state->{globaloptions}{-n} ) { - print "Update-existing $dirpart\n"; + print "Merged $dirpart\n"; $log->debug($state->{CVSROOT} . "/$state->{module}/$filename"); print $state->{CVSROOT} . "/$state->{module}/$filename\n"; my $kopts = kopts_from_path($filepart); @@ -978,7 +978,7 @@ sub req_update # Don't want to actually _DO_ the update if -n specified unless ( $state->{globaloptions}{-n} ) { - print "Update-existing $dirpart\n"; + print "Merged $dirpart\n"; print $state->{CVSROOT} . "/$state->{module}/$filename\n"; my $kopts = kopts_from_path($filepart); print "/$filepart/1.$meta->{revision}/+/$kopts/\n"; diff --git a/git-gui/.gitignore b/git-gui/.gitignore index 805ca2e1c7..c714d382e8 100644 --- a/git-gui/.gitignore +++ b/git-gui/.gitignore @@ -1,4 +1,3 @@ -CREDITS-FILE GIT-VERSION-FILE git-citool git-gui diff --git a/git-gui/CREDITS-GEN b/git-gui/CREDITS-GEN deleted file mode 100755 index d1b0f86355..0000000000 --- a/git-gui/CREDITS-GEN +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/sh - -CF=CREDITS-FILE -tip= - -tree_search () -{ - head=$1 - tree=$2 - for p in $(git rev-list --parents --max-count=1 $head 2>/dev/null) - do - test $tree = $(git rev-parse $p^{tree} 2>/dev/null) && - vn=$(git describe --abbrev=4 $p 2>/dev/null) && - case "$vn" in - gitgui-[0-9]*) echo $p; break;; - esac - done -} - -generate_credits () -{ - tip=$1 && - rm -f "$2" && - git shortlog -n -s $tip | sed 's/: .*$//' >"$2" || exit -} - -# Always use the tarball credits file if found, just -# in case we are somehow contained in a larger git -# repository that doesn't actually track our state. -# (At least one package manager is doing this.) -# -# We may be a subproject, so try looking for the merge -# commit that supplied this directory content if we are -# not at the toplevel. We probably will always be the -# second parent in the commit, but we shouldn't rely on -# that fact. -# - -credits_tmp=/var/tmp/gitgui-credits-$$ -trap 'rm -f "$credits_tmp"' 0 - -orig="$credits_tmp" - -if test -f credits -then - orig=credits -elif prefix="$(git rev-parse --show-prefix 2>/dev/null)" && - test -n "$prefix" && - head=$(git rev-list --max-count=1 HEAD -- . 2>/dev/null) && - tree=$(git rev-parse --verify "HEAD:$prefix" 2>/dev/null) && - tip=$(tree_search $head $tree) && - test -n "$tip" -then - generate_credits $tip "$orig" || exit -elif tip="$(git rev-parse --verify HEAD 2>/dev/null)" && - test -n "$tip" -then - generate_credits $tip "$orig" || exit -else - echo "error: Cannot locate authorship information." >&2 - exit 1 -fi - -if test -f "$orig" && cmp -s "$orig" "$CF" -then - : noop -else - rm -f "$CF" && - cat "$orig" >"$CF" -fi - diff --git a/git-gui/Makefile b/git-gui/Makefile index e486e8f984..b82789ead6 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -7,8 +7,9 @@ GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE @$(SHELL_PATH) ./GIT-VERSION-GEN -include GIT-VERSION-FILE +SCRIPT_SH = git-gui.sh GITGUI_BUILT_INS = git-citool -ALL_PROGRAMS = git-gui $(GITGUI_BUILT_INS) +ALL_PROGRAMS = $(GITGUI_BUILT_INS) $(patsubst %.sh,%,$(SCRIPT_SH)) ifndef SHELL_PATH SHELL_PATH = /bin/sh @@ -27,28 +28,29 @@ ifndef V QUIET_BUILT_IN = @echo ' ' BUILTIN $@; endif +ifeq ($(findstring $(MAKEFLAGS),s),s) +QUIET_GEN = +QUIET_BUILT_IN = +endif + DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) gitexecdir_SQ = $(subst ','\'',$(gitexecdir)) SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) -git-gui: git-gui.sh GIT-VERSION-FILE CREDITS-FILE +$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh $(QUIET_GEN)rm -f $@ $@+ && \ - sed -n \ - -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ + sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's/@@GITGUI_VERSION@@/$(GITGUI_VERSION)/g' \ - -e '1,/^set gitgui_credits /p' \ $@.sh >$@+ && \ - cat CREDITS-FILE >>$@+ && \ - sed -e '1,/^set gitgui_credits /d' $@.sh >>$@+ && \ chmod +x $@+ && \ mv $@+ $@ -CREDITS-FILE: CREDITS-GEN .FORCE-CREDITS-FILE - $(QUIET_GEN)$(SHELL_PATH) ./CREDITS-GEN - $(GITGUI_BUILT_INS): git-gui $(QUIET_BUILT_IN)rm -f $@ && ln git-gui $@ +# These can record GITGUI_VERSION +$(patsubst %.sh,%,$(SCRIPT_SH)): GIT-VERSION-FILE + all:: $(ALL_PROGRAMS) install: all @@ -56,14 +58,12 @@ install: all $(INSTALL) git-gui '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(foreach p,$(GITGUI_BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;) -dist-version: CREDITS-FILE +dist-version: @mkdir -p $(TARDIR) @echo $(GITGUI_VERSION) > $(TARDIR)/version - @cat CREDITS-FILE > $(TARDIR)/credits clean:: - rm -f $(ALL_PROGRAMS) GIT-VERSION-FILE CREDITS-FILE + rm -f $(ALL_PROGRAMS) GIT-VERSION-FILE .PHONY: all install dist-version clean .PHONY: .FORCE-GIT-VERSION-FILE -.PHONY: .FORCE-CREDITS-FILE diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 1981827a8e..60e79ca1b0 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -19,9 +19,6 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA} -set gitgui_credits { -Paul Mackerras -} ###################################################################### ## @@ -302,6 +299,11 @@ proc ask_popup {msg} { ## ## version check +if {{--version} eq $argv || {version} eq $argv} { + puts "git-gui version $appvers" + exit +} + set req_maj 1 set req_min 5 @@ -1171,7 +1173,7 @@ File [short_path $path] cannot be committed by this program. } } } - if {!$files_ready} { + if {!$files_ready && ![string match *merge $curType]} { info_popup {No changes to commit. You must add at least 1 file before you can commit. @@ -4492,61 +4494,6 @@ proc do_commit {} { commit_tree } -proc do_credits {} { - global gitgui_credits - - set w .credits_dialog - - toplevel $w - wm geometry $w "+[winfo rootx .]+[winfo rooty .]" - - label $w.header -text {git-gui Contributors} -font font_uibold - pack $w.header -side top -fill x - - frame $w.buttons - button $w.buttons.close -text {Close} \ - -font font_ui \ - -command [list destroy $w] - pack $w.buttons.close -side right - pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - - frame $w.credits - text $w.credits.t \ - -background [$w.header cget -background] \ - -yscrollcommand [list $w.credits.sby set] \ - -width 20 \ - -height 10 \ - -wrap none \ - -borderwidth 1 \ - -relief solid \ - -padx 5 -pady 5 \ - -font font_ui - scrollbar $w.credits.sby -command [list $w.credits.t yview] - pack $w.credits.sby -side right -fill y - pack $w.credits.t -fill both -expand 1 - pack $w.credits -side top -fill both -expand 1 -padx 5 -pady 5 - - label $w.desc \ - -text "All portions are copyrighted by their respective authors -and are distributed under the GNU General Public License." \ - -padx 5 -pady 5 \ - -justify left \ - -anchor w \ - -borderwidth 1 \ - -relief solid \ - -font font_ui - pack $w.desc -side top -fill x -padx 5 -pady 5 - - $w.credits.t insert end "[string trim $gitgui_credits]\n" - $w.credits.t conf -state disabled - $w.credits.t see 1.0 - - bind $w <Visibility> "grab $w; focus $w" - bind $w <Key-Escape> [list destroy $w] - wm title $w [$w.header cget -text] - tkwait window $w -} - proc do_about {} { global appvers copyright global tcl_patchLevel tk_patchLevel @@ -4563,10 +4510,6 @@ proc do_about {} { button $w.buttons.close -text {Close} \ -font font_ui \ -command [list destroy $w] - button $w.buttons.credits -text {Contributors} \ - -font font_ui \ - -command do_credits - pack $w.buttons.credits -side left pack $w.buttons.close -side right pack $w.buttons -side bottom -fill x -pady 10 -padx 10 @@ -5116,8 +5059,6 @@ enable_option branch enable_option transport switch -- $subcommand { ---version - -version - browser - blame { disable_option multicommit @@ -5488,11 +5429,6 @@ bind all <$M1B-Key-W> {destroy [winfo toplevel %W]} # -- Not a normal commit type invocation? Do that instead! # switch -- $subcommand { ---version - -version { - puts "git-gui version $appvers" - exit -} browser { if {[llength $argv] != 1} { puts stderr "usage: $argv0 browser commit" diff --git a/git-merge.sh b/git-merge.sh index 4afcd95316..6ce62c860a 100755 --- a/git-merge.sh +++ b/git-merge.sh @@ -294,7 +294,12 @@ f,*) git-update-index --refresh 2>/dev/null new_head=$(git-rev-parse --verify "$1^0") && git-read-tree -v -m -u --exclude-per-directory=.gitignore $head "$new_head" && - finish "$new_head" "Fast forward" || exit + msg="Fast forward" + if test -n "$have_message" + then + msg="$msg (no commit created; -m option ignored)" + fi + finish "$new_head" "$msg" || exit dropsave exit 0 ;; diff --git a/git-mergetool.sh b/git-mergetool.sh new file mode 100755 index 0000000000..52386a5443 --- /dev/null +++ b/git-mergetool.sh @@ -0,0 +1,352 @@ +#!/bin/sh +# +# This program resolves merge conflicts in git +# +# Copyright (c) 2006 Theodore Y. Ts'o +# +# This file is licensed under the GPL v2, or a later version +# at the discretion of Junio C Hammano. +# + +USAGE='[--tool=tool] [file to merge] ...' +SUBDIRECTORY_OK=Yes +. git-sh-setup +require_work_tree + +# Returns true if the mode reflects a symlink +function is_symlink () { + test "$1" = 120000 +} + +function local_present () { + test -n "$local_mode" +} + +function remote_present () { + test -n "$remote_mode" +} + +function base_present () { + test -n "$base_mode" +} + +cleanup_temp_files () { + if test "$1" = --save-backup ; then + mv -- "$BACKUP" "$path.orig" + rm -f -- "$LOCAL" "$REMOTE" "$BASE" + else + rm -f -- "$LOCAL" "$REMOTE" "$BASE" "$BACKUP" + fi +} + +function describe_file () { + mode="$1" + branch="$2" + file="$3" + + echo -n " " + if test -z "$mode"; then + echo -n "'$path' was deleted" + elif is_symlink "$mode" ; then + echo -n "'$path' is a symlink containing '" + cat "$file" + echo -n "'" + else + if base_present; then + echo -n "'$path' was created" + else + echo -n "'$path' was modified" + fi + fi + echo " in the $branch branch" +} + + +resolve_symlink_merge () { + while /bin/true; do + echo -n "Use (r)emote or (l)ocal, or (a)bort? " + read ans + case "$ans" in + [lL]*) + git-checkout-index -f --stage=2 -- "$path" + git-add -- "$path" + cleanup_temp_files --save-backup + return + ;; + [rR]*) + git-checkout-index -f --stage=3 -- "$path" + git-add -- "$path" + cleanup_temp_files --save-backup + return + ;; + [qQ]*) + exit 1 + ;; + esac + done +} + +resolve_deleted_merge () { + while /bin/true; do + echo -n "Use (m)odified or (d)eleted file, or (a)bort? " + read ans + case "$ans" in + [mM]*) + git-add -- "$path" + cleanup_temp_files --save-backup + return + ;; + [dD]*) + git-rm -- "$path" + cleanup_temp_files + return + ;; + [qQ]*) + exit 1 + ;; + esac + done +} + +merge_file () { + path="$1" + + if test ! -f "$path" ; then + echo "$path: file not found" + exit 1 + fi + + f=`git-ls-files -u -- "$path"` + if test -z "$f" ; then + echo "$path: file does not need merging" + exit 1 + fi + + BACKUP="$path.BACKUP.$$" + LOCAL="$path.LOCAL.$$" + REMOTE="$path.REMOTE.$$" + BASE="$path.BASE.$$" + + mv -- "$path" "$BACKUP" + cp -- "$BACKUP" "$path" + + base_mode=`git ls-files -u -- "$path" | awk '{if ($3==1) print $1;}'` + local_mode=`git ls-files -u -- "$path" | awk '{if ($3==2) print $1;}'` + remote_mode=`git ls-files -u -- "$path" | awk '{if ($3==3) print $1;}'` + + base_present && git cat-file blob ":1:$path" > "$BASE" 2>/dev/null + local_present && git cat-file blob ":2:$path" > "$LOCAL" 2>/dev/null + remote_present && git cat-file blob ":3:$path" > "$REMOTE" 2>/dev/null + + if test -z "$local_mode" -o -z "$remote_mode"; then + echo "Deleted merge conflict for $path:" + describe_file "$local_mode" "local" "$LOCAL" + describe_file "$remote_mode" "remote" "$REMOTE" + resolve_deleted_merge + return + fi + + if is_symlink "$local_mode" || is_symlink "$remote_mode"; then + echo "Symlink merge conflict for $path:" + describe_file "$local_mode" "local" "$LOCAL" + describe_file "$remote_mode" "remote" "$REMOTE" + resolve_symlink_merge + return + fi + + echo "Normal merge conflict for $path:" + describe_file "$local_mode" "local" "$LOCAL" + describe_file "$remote_mode" "remote" "$REMOTE" + echo -n "Hit return to start merge resolution tool ($merge_tool): " + read ans + + case "$merge_tool" in + kdiff3) + if base_present ; then + (kdiff3 --auto --L1 "$path (Base)" -L2 "$path (Local)" --L3 "$path (Remote)" \ + -o "$path" -- "$BASE" "$LOCAL" "$REMOTE" > /dev/null 2>&1) + else + (kdiff3 --auto -L1 "$path (Local)" --L2 "$path (Remote)" \ + -o "$path" -- "$LOCAL" "$REMOTE" > /dev/null 2>&1) + fi + status=$? + if test "$status" -eq 0; then + rm "$BACKUP" + fi + ;; + tkdiff) + if base_present ; then + tkdiff -a "$BASE" -o "$path" -- "$LOCAL" "$REMOTE" + else + tkdiff -o "$path" -- "$LOCAL" "$REMOTE" + fi + status=$? + if test "$status" -eq 0; then + mv -- "$BACKUP" "$path.orig" + fi + ;; + meld) + touch "$BACKUP" + meld -- "$LOCAL" "$path" "$REMOTE" + if test "$path" -nt "$BACKUP" ; then + status=0; + else + while true; do + echo "$path seems unchanged." + echo -n "Was the merge successful? [y/n] " + read answer < /dev/tty + case "$answer" in + y*|Y*) status=0; break ;; + n*|N*) status=1; break ;; + esac + done + fi + if test "$status" -eq 0; then + mv -- "$BACKUP" "$path.orig" + fi + ;; + xxdiff) + touch "$BACKUP" + if base_present ; then + xxdiff -X --show-merged-pane \ + -R 'Accel.SaveAsMerged: "Ctrl-S"' \ + -R 'Accel.Search: "Ctrl+F"' \ + -R 'Accel.SearchForward: "Ctrl-G"' \ + --merged-file "$path" -- "$LOCAL" "$BASE" "$REMOTE" + else + xxdiff -X --show-merged-pane \ + -R 'Accel.SaveAsMerged: "Ctrl-S"' \ + -R 'Accel.Search: "Ctrl+F"' \ + -R 'Accel.SearchForward: "Ctrl-G"' \ + --merged-file "$path" -- "$LOCAL" "$REMOTE" + fi + if test "$path" -nt "$BACKUP" ; then + status=0; + else + while true; do + echo "$path seems unchanged." + echo -n "Was the merge successful? [y/n] " + read answer < /dev/tty + case "$answer" in + y*|Y*) status=0; break ;; + n*|N*) status=1; break ;; + esac + done + fi + if test "$status" -eq 0; then + mv -- "$BACKUP" "$path.orig" + fi + ;; + emerge) + if base_present ; then + emacs -f emerge-files-with-ancestor-command "$LOCAL" "$REMOTE" "$BASE" "$path" + else + emacs -f emerge-files-command "$LOCAL" "$REMOTE" "$path" + fi + status=$? + if test "$status" -eq 0; then + mv -- "$BACKUP" "$path.orig" + fi + ;; + esac + if test "$status" -ne 0; then + echo "merge of $path failed" 1>&2 + mv -- "$BACKUP" "$path" + exit 1 + fi + git add -- "$path" + cleanup_temp_files +} + +while case $# in 0) break ;; esac +do + case "$1" in + -t|--tool*) + case "$#,$1" in + *,*=*) + merge_tool=`expr "z$1" : 'z-[^=]*=\(.*\)'` + ;; + 1,*) + usage ;; + *) + merge_tool="$2" + shift ;; + esac + ;; + --) + break + ;; + -*) + usage + ;; + *) + break + ;; + esac + shift +done + +if test -z "$merge_tool"; then + merge_tool=`git-config merge.tool` + if test $merge_tool = kdiff3 -o $merge_tool = tkdiff -o \ + $merge_tool = xxdiff -o $merge_tool = meld ; then + unset merge_tool + fi +fi + +if test -z "$merge_tool" ; then + if type kdiff3 >/dev/null 2>&1 && test -n "$DISPLAY"; then + merge_tool="kdiff3"; + elif type tkdiff >/dev/null 2>&1 && test -n "$DISPLAY"; then + merge_tool=tkdiff + elif type xxdiff >/dev/null 2>&1 && test -n "$DISPLAY"; then + merge_tool=xxdiff + elif type meld >/dev/null 2>&1 && test -n "$DISPLAY"; then + merge_tool=meld + elif type emacs >/dev/null 2>&1; then + merge_tool=emerge + else + echo "No available merge resolution programs available." + exit 1 + fi +fi + +case "$merge_tool" in + kdiff3|tkdiff|meld|xxdiff) + if ! type "$merge_tool" > /dev/null 2>&1; then + echo "The merge tool $merge_tool is not available" + exit 1 + fi + ;; + emerge) + if ! type "emacs" > /dev/null 2>&1; then + echo "Emacs is not available" + exit 1 + fi + ;; + *) + echo "Unknown merge tool: $merge_tool" + exit 1 + ;; +esac + +if test $# -eq 0 ; then + files=`git ls-files -u | sed -e 's/^[^ ]* //' | sort -u` + if test -z "$files" ; then + echo "No files need merging" + exit 0 + fi + echo Merging the files: $files + git ls-files -u | sed -e 's/^[^ ]* //' | sort -u | while read i + do + echo "" + merge_file "$i" < /dev/tty > /dev/tty + done +else + while test $# -gt 0; do + echo "" + merge_file "$1" + shift + done +fi +exit 0 diff --git a/git-revert.sh b/git-revert.sh deleted file mode 100755 index 49f00321b2..0000000000 --- a/git-revert.sh +++ /dev/null @@ -1,197 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2005 Linus Torvalds -# Copyright (c) 2005 Junio C Hamano -# - -case "$0" in -*-revert* ) - test -t 0 && edit=-e - replay= - me=revert - USAGE='[--edit | --no-edit] [-n] <commit-ish>' ;; -*-cherry-pick* ) - replay=t - edit= - me=cherry-pick - USAGE='[--edit] [-n] [-r] [-x] <commit-ish>' ;; -* ) - echo >&2 "What are you talking about?" - exit 1 ;; -esac - -SUBDIRECTORY_OK=Yes ;# we will cd up -. git-sh-setup -require_work_tree -cd_to_toplevel - -no_commit= -while case "$#" in 0) break ;; esac -do - case "$1" in - -n|--n|--no|--no-|--no-c|--no-co|--no-com|--no-comm|\ - --no-commi|--no-commit) - no_commit=t - ;; - -e|--e|--ed|--edi|--edit) - edit=-e - ;; - --n|--no|--no-|--no-e|--no-ed|--no-edi|--no-edit) - edit= - ;; - -r) - : no-op ;; - -x|--i-really-want-to-expose-my-private-commit-object-name) - replay= - ;; - -*) - usage - ;; - *) - break - ;; - esac - shift -done - -set_reflog_action "$me" - -test "$me,$replay" = "revert,t" && usage - -case "$no_commit" in -t) - # We do not intend to commit immediately. We just want to - # merge the differences in. - head=$(git-write-tree) || - die "Your index file is unmerged." - ;; -*) - head=$(git-rev-parse --verify HEAD) || - die "You do not have a valid HEAD" - files=$(git-diff-index --cached --name-only $head) || exit - if [ "$files" ]; then - die "Dirty index: cannot $me (dirty: $files)" - fi - ;; -esac - -rev=$(git-rev-parse --verify "$@") && -commit=$(git-rev-parse --verify "$rev^0") || - die "Not a single commit $@" -prev=$(git-rev-parse --verify "$commit^1" 2>/dev/null) || - die "Cannot run $me a root commit" -git-rev-parse --verify "$commit^2" >/dev/null 2>&1 && - die "Cannot run $me a multi-parent commit." - -encoding=$(git config i18n.commitencoding || echo UTF-8) - -# "commit" is an existing commit. We would want to apply -# the difference it introduces since its first parent "prev" -# on top of the current HEAD if we are cherry-pick. Or the -# reverse of it if we are revert. - -case "$me" in -revert) - git show -s --pretty=oneline --encoding="$encoding" $commit | - sed -e ' - s/^[^ ]* /Revert "/ - s/$/"/ - ' - echo - echo "This reverts commit $commit." - test "$rev" = "$commit" || - echo "(original 'git revert' arguments: $@)" - base=$commit next=$prev - ;; - -cherry-pick) - pick_author_script=' - /^author /{ - s/'\''/'\''\\'\'\''/g - h - s/^author \([^<]*\) <[^>]*> .*$/\1/ - s/'\''/'\''\'\'\''/g - s/.*/GIT_AUTHOR_NAME='\''&'\''/p - - g - s/^author [^<]* <\([^>]*\)> .*$/\1/ - s/'\''/'\''\'\'\''/g - s/.*/GIT_AUTHOR_EMAIL='\''&'\''/p - - g - s/^author [^<]* <[^>]*> \(.*\)$/\1/ - s/'\''/'\''\'\'\''/g - s/.*/GIT_AUTHOR_DATE='\''&'\''/p - - q - }' - - logmsg=`git show -s --pretty=raw --encoding="$encoding" "$commit"` - set_author_env=`echo "$logmsg" | - LANG=C LC_ALL=C sed -ne "$pick_author_script"` - eval "$set_author_env" - export GIT_AUTHOR_NAME - export GIT_AUTHOR_EMAIL - export GIT_AUTHOR_DATE - - echo "$logmsg" | - sed -e '1,/^$/d' -e 's/^ //' - case "$replay" in - '') - echo "(cherry picked from commit $commit)" - test "$rev" = "$commit" || - echo "(original 'git cherry-pick' arguments: $@)" - ;; - esac - base=$prev next=$commit - ;; - -esac >.msg - -eval GITHEAD_$head=HEAD -eval GITHEAD_$next='`git show -s \ - --pretty=oneline --encoding="$encoding" "$commit" | - sed -e "s/^[^ ]* //"`' -export GITHEAD_$head GITHEAD_$next - -# This three way merge is an interesting one. We are at -# $head, and would want to apply the change between $commit -# 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 && -result=$(git-write-tree 2>/dev/null) || { - mv -f .msg "$GIT_DIR/MERGE_MSG" - { - echo ' -Conflicts: -' - git ls-files --unmerged | - sed -e 's/^[^ ]* / /' | - uniq - } >>"$GIT_DIR/MERGE_MSG" - echo >&2 "Automatic $me failed. After resolving the conflicts," - echo >&2 "mark the corrected paths with 'git-add <paths>'" - echo >&2 "and commit the result." - case "$me" in - cherry-pick) - echo >&2 "You may choose to use the following when making" - echo >&2 "the commit:" - echo >&2 "$set_author_env" - esac - exit 1 -} -echo >&2 "Finished one $me." - -# If we are cherry-pick, and if the merge did not result in -# hand-editing, we will hit this commit and inherit the original -# author date and name. -# If we are revert, or if our cherry-pick results in a hand merge, -# we had better say that the current user is responsible for that. - -case "$no_commit" in -'') - git-commit -n -F .msg $edit - rm -f .msg - ;; -esac diff --git a/git-send-email.perl b/git-send-email.perl index a71a192e4d..6989c0260f 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -149,6 +149,16 @@ if ($@) { $term = new FakeTerm "$@: going non-interactive"; } +my $def_chain = $repo->config_boolean('sendemail.chainreplyto'); +if ($def_chain and $def_chain eq 'false') { + $chain_reply_to = 0; +} + +@bcclist = $repo->config('sendemail.bcc'); +if (!@bcclist or !$bcclist[0]) { + @bcclist = (); +} + # Begin by accumulating all the variables (defined above), that we will end up # needing, first, from the command line: diff --git a/git-svn.perl b/git-svn.perl index 326e89fe03..e8457893db 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -56,7 +56,7 @@ my ($_stdin, $_help, $_edit, $_message, $_file, $_template, $_shared, $_version, $_fetch_all, - $_merge, $_strategy, $_dry_run, + $_merge, $_strategy, $_dry_run, $_local, $_prefix, $_no_checkout, $_verbose); $Git::SVN::_follow_parent = 1; my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username, @@ -145,6 +145,7 @@ my %cmd = ( { 'merge|m|M' => \$_merge, 'verbose|v' => \$_verbose, 'strategy|s=s' => \$_strategy, + 'local|l' => \$_local, 'fetch-all|all' => \$_fetch_all, %fc_opts } ], 'commit-diff' => [ \&cmd_commit_diff, @@ -439,7 +440,9 @@ sub cmd_rebase { command_noisy('status'); exit 1; } - $_fetch_all ? $gs->fetch_all : $gs->fetch; + unless ($_local) { + $_fetch_all ? $gs->fetch_all : $gs->fetch; + } command_noisy(rebase_cmd(), $gs->refname); } @@ -234,6 +234,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp) { "checkout-index", cmd_checkout_index, RUN_SETUP }, { "check-ref-format", cmd_check_ref_format }, { "cherry", cmd_cherry, RUN_SETUP }, + { "cherry-pick", cmd_cherry_pick, RUN_SETUP | NOT_BARE }, { "commit-tree", cmd_commit_tree, RUN_SETUP }, { "config", cmd_config }, { "count-objects", cmd_count_objects, RUN_SETUP }, @@ -272,6 +273,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp) { "rerere", cmd_rerere, RUN_SETUP }, { "rev-list", cmd_rev_list, RUN_SETUP }, { "rev-parse", cmd_rev_parse, RUN_SETUP }, + { "revert", cmd_revert, RUN_SETUP | NOT_BARE }, { "rm", cmd_rm, RUN_SETUP | NOT_BARE }, { "runstatus", cmd_runstatus, RUN_SETUP | NOT_BARE }, { "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER }, diff --git a/log-tree.c b/log-tree.c index 6ce239d8f9..8797aa14c4 100644 --- a/log-tree.c +++ b/log-tree.c @@ -186,7 +186,7 @@ void show_log(struct rev_info *opt, const char *sep) snprintf(subject_buffer, sizeof(subject_buffer) - 1, "%s" "MIME-Version: 1.0\n" - "Content-Type: multipart/mixed;\n" + "Content-Type: multipart/mixed;" " boundary=\"%s%s\"\n" "\n" "This is a multi-part message in MIME " @@ -202,13 +202,15 @@ void show_log(struct rev_info *opt, const char *sep) snprintf(buffer, sizeof(buffer) - 1, "--%s%s\n" - "Content-Type: text/x-patch;\n" + "Content-Type: text/x-patch;" " name=\"%s.diff\"\n" "Content-Transfer-Encoding: 8bit\n" - "Content-Disposition: inline;\n" + "Content-Disposition: %s;" " filename=\"%s.diff\"\n\n", mime_boundary_leader, opt->mime_boundary, - sha1, sha1); + sha1, + opt->no_inline ? "attachment" : "inline", + sha1); opt->diffopt.stat_sep = buffer; } } else if (opt->commit_format != CMIT_FMT_USERFORMAT) { diff --git a/perl/Makefile b/perl/Makefile index 099beda873..17d004e5a0 100644 --- a/perl/Makefile +++ b/perl/Makefile @@ -6,11 +6,15 @@ makfile:=perl.mak PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) prefix_SQ = $(subst ','\'',$(prefix)) +ifndef V + QUIET = @ +endif + all install instlibdir: $(makfile) - $(MAKE) -f $(makfile) $@ + $(QUIET)$(MAKE) -f $(makfile) $@ clean: - test -f $(makfile) && $(MAKE) -f $(makfile) $@ || exit 0 + $(QUIET)test -f $(makfile) && $(MAKE) -f $(makfile) $@ || exit 0 $(RM) ppport.h $(RM) $(makfile) $(RM) $(makfile).old diff --git a/receive-pack.c b/receive-pack.c index 675c88f492..7cf58782e3 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -67,47 +67,11 @@ struct command { static struct command *commands; -static const char update_hook[] = "hooks/update"; static const char pre_receive_hook[] = "hooks/pre-receive"; static const char post_receive_hook[] = "hooks/post-receive"; -static int run_hook(const char *hook_name, - struct command *first_cmd, - int single) +static int hook_status(int code, const char *hook_name) { - struct command *cmd; - int argc, code; - const char **argv; - - for (argc = 0, cmd = first_cmd; cmd; cmd = cmd->next) { - if (!cmd->error_string) - argc += 3; - if (single) - break; - } - - if (!argc || access(hook_name, X_OK) < 0) - return 0; - - argv = xmalloc(sizeof(*argv) * (2 + argc)); - argv[0] = hook_name; - for (argc = 1, cmd = first_cmd; cmd; cmd = cmd->next) { - if (!cmd->error_string) { - argv[argc++] = xstrdup(cmd->ref_name); - argv[argc++] = xstrdup(sha1_to_hex(cmd->old_sha1)); - argv[argc++] = xstrdup(sha1_to_hex(cmd->new_sha1)); - } - if (single) - break; - } - argv[argc] = NULL; - - code = run_command_v_opt(argv, - RUN_COMMAND_NO_STDIN | RUN_COMMAND_STDOUT_TO_STDERR); - while (--argc > 0) - free((char*)argv[argc]); - free(argv); - switch (code) { case 0: return 0; @@ -115,6 +79,8 @@ static int run_hook(const char *hook_name, return error("hook fork failed"); case -ERR_RUN_COMMAND_EXEC: return error("hook execute failed"); + case -ERR_RUN_COMMAND_PIPE: + return error("hook pipe failed"); case -ERR_RUN_COMMAND_WAITPID: return error("waitpid failed"); case -ERR_RUN_COMMAND_WAITPID_WRONG_PID: @@ -129,6 +95,69 @@ static int run_hook(const char *hook_name, } } +static int run_hook(const char *hook_name) +{ + static char buf[sizeof(commands->old_sha1) * 2 + PATH_MAX + 4]; + struct command *cmd; + struct child_process proc; + const char *argv[2]; + int have_input = 0, code; + + for (cmd = commands; !have_input && cmd; cmd = cmd->next) { + if (!cmd->error_string) + have_input = 1; + } + + if (!have_input || access(hook_name, X_OK) < 0) + return 0; + + argv[0] = hook_name; + argv[1] = NULL; + + memset(&proc, 0, sizeof(proc)); + proc.argv = argv; + proc.in = -1; + proc.stdout_to_stderr = 1; + + code = start_command(&proc); + if (code) + return hook_status(code, hook_name); + for (cmd = commands; cmd; cmd = cmd->next) { + if (!cmd->error_string) { + size_t n = snprintf(buf, sizeof(buf), "%s %s %s\n", + sha1_to_hex(cmd->old_sha1), + sha1_to_hex(cmd->new_sha1), + cmd->ref_name); + if (write_in_full(proc.in, buf, n) != n) + break; + } + } + return hook_status(finish_command(&proc), hook_name); +} + +static int run_update_hook(struct command *cmd) +{ + static const char update_hook[] = "hooks/update"; + struct child_process proc; + const char *argv[5]; + + if (access(update_hook, X_OK) < 0) + return 0; + + argv[0] = update_hook; + argv[1] = cmd->ref_name; + argv[2] = sha1_to_hex(cmd->old_sha1); + argv[3] = sha1_to_hex(cmd->new_sha1); + argv[4] = NULL; + + memset(&proc, 0, sizeof(proc)); + proc.argv = argv; + proc.no_stdin = 1; + proc.stdout_to_stderr = 1; + + return hook_status(run_command(&proc), update_hook); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -165,7 +194,7 @@ static const char *update(struct command *cmd) return "non-fast forward"; } } - if (run_hook(update_hook, cmd, 1)) { + if (run_update_hook(cmd)) { error("hook declined to update %s", name); return "hook declined"; } @@ -238,7 +267,7 @@ static void execute_commands(const char *unpacker_error) return; } - if (run_hook(pre_receive_hook, commands, 0)) { + if (run_hook(pre_receive_hook)) { while (cmd) { cmd->error_string = "pre-receive hook declined"; cmd = cmd->next; @@ -493,7 +522,7 @@ int main(int argc, char **argv) unlink(pack_lockfile); if (report_status) report(unpack_status); - run_hook(post_receive_hook, commands, 0); + run_hook(post_receive_hook); run_update_post_hook(commands); } return 0; @@ -921,6 +921,8 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1, log_file, strerror(errno)); } + adjust_shared_perm(log_file); + msglen = 0; if (msg) { /* clean up the message and make sure it is a single line */ diff --git a/revision.c b/revision.c index f5b8ae4f03..3c2eb125e6 100644 --- a/revision.c +++ b/revision.c @@ -437,36 +437,6 @@ static void limit_list(struct rev_info *revs) continue; p = &commit_list_insert(commit, p)->next; } - if (revs->boundary) { - /* mark the ones that are on the result list first */ - for (list = newlist; list; list = list->next) { - struct commit *commit = list->item; - commit->object.flags |= TMP_MARK; - } - for (list = newlist; list; list = list->next) { - struct commit *commit = list->item; - struct object *obj = &commit->object; - struct commit_list *parent; - if (obj->flags & UNINTERESTING) - continue; - for (parent = commit->parents; - parent; - parent = parent->next) { - struct commit *pcommit = parent->item; - if (!(pcommit->object.flags & UNINTERESTING)) - continue; - pcommit->object.flags |= BOUNDARY; - if (pcommit->object.flags & TMP_MARK) - continue; - pcommit->object.flags |= TMP_MARK; - p = &commit_list_insert(pcommit, p)->next; - } - } - for (list = newlist; list; list = list->next) { - struct commit *commit = list->item; - commit->object.flags &= ~TMP_MARK; - } - } revs->commits = newlist; } @@ -1193,17 +1163,6 @@ static void rewrite_parents(struct rev_info *revs, struct commit *commit) } } -static void mark_boundary_to_show(struct commit *commit) -{ - struct commit_list *p = commit->parents; - while (p) { - commit = p->item; - p = p->next; - if (commit->object.flags & BOUNDARY) - commit->object.flags |= BOUNDARY_SHOW; - } -} - static int commit_match(struct commit *commit, struct rev_info *opt) { if (!opt->grep_filter) @@ -1235,15 +1194,9 @@ static struct commit *get_revision_1(struct rev_info *revs) */ if (!revs->limited) { if (revs->max_age != -1 && - (commit->date < revs->max_age)) { - if (revs->boundary) - commit->object.flags |= - BOUNDARY_SHOW | BOUNDARY; - else - continue; - } else - add_parents_to_list(revs, commit, - &revs->commits); + (commit->date < revs->max_age)) + continue; + add_parents_to_list(revs, commit, &revs->commits); } if (commit->object.flags & SHOWN) continue; @@ -1252,18 +1205,6 @@ static struct commit *get_revision_1(struct rev_info *revs) revs->ignore_packed)) continue; - /* We want to show boundary commits only when their - * children are shown. When path-limiter is in effect, - * rewrite_parents() drops some commits from getting shown, - * and there is no point showing boundary parents that - * are not shown. After rewrite_parents() rewrites the - * parents of a commit that is shown, we mark the boundary - * parents with BOUNDARY_SHOW. - */ - if (commit->object.flags & BOUNDARY_SHOW) { - commit->object.flags |= SHOWN; - return commit; - } if (commit->object.flags & UNINTERESTING) continue; if (revs->min_age != -1 && (commit->date > revs->min_age)) @@ -1286,80 +1227,136 @@ static struct commit *get_revision_1(struct rev_info *revs) if (revs->parents) rewrite_parents(revs, commit); } - if (revs->boundary) - mark_boundary_to_show(commit); - commit->object.flags |= SHOWN; return commit; } while (revs->commits); return NULL; } +static void gc_boundary(struct object_array *array) +{ + unsigned nr = array->nr; + unsigned alloc = array->alloc; + struct object_array_entry *objects = array->objects; + + if (alloc <= nr) { + unsigned i, j; + for (i = j = 0; i < nr; i++) { + if (objects[i].item->flags & SHOWN) + continue; + if (i != j) + objects[j] = objects[i]; + j++; + } + for (i = j; i < nr; i++) + objects[i].item = NULL; + array->nr = j; + } +} + struct commit *get_revision(struct rev_info *revs) { struct commit *c = NULL; + struct commit_list *l; + + if (revs->boundary == 2) { + unsigned i; + struct object_array *array = &revs->boundary_commits; + struct object_array_entry *objects = array->objects; + for (i = 0; i < array->nr; i++) { + c = (struct commit *)(objects[i].item); + if (!c) + continue; + if (!(c->object.flags & CHILD_SHOWN)) + continue; + if (!(c->object.flags & SHOWN)) + break; + } + if (array->nr <= i) + return NULL; - if (revs->reverse) { - struct commit_list *list; + c->object.flags |= SHOWN | BOUNDARY; + return c; + } - /* - * rev_info.reverse is used to note the fact that we - * want to output the list of revisions in reverse - * order. To accomplish this goal, reverse can have - * different values: - * - * 0 do nothing - * 1 reverse the list - * 2 internal use: we have already obtained and - * reversed the list, now we only need to yield - * its items. - */ + if (revs->reverse) { + int limit = -1; - if (revs->reverse == 1) { - revs->reverse = 0; - list = NULL; - while ((c = get_revision(revs))) - commit_list_insert(c, &list); - revs->commits = list; - revs->reverse = 2; + if (0 <= revs->max_count) { + limit = revs->max_count; + if (0 < revs->skip_count) + limit += revs->skip_count; } - - if (!revs->commits) - return NULL; - c = revs->commits->item; - list = revs->commits->next; - free(revs->commits); - revs->commits = list; - return c; + l = NULL; + while ((c = get_revision_1(revs))) { + commit_list_insert(c, &l); + if ((0 < limit) && !--limit) + break; + } + revs->commits = l; + revs->reverse = 0; + revs->max_count = -1; + c = NULL; } - if (0 < revs->skip_count) { - while ((c = get_revision_1(revs)) != NULL) { - if (revs->skip_count-- <= 0) + /* + * Now pick up what they want to give us + */ + c = get_revision_1(revs); + if (c) { + while (0 < revs->skip_count) { + revs->skip_count--; + c = get_revision_1(revs); + if (!c) break; } } - /* Check the max_count ... */ + /* + * Check the max_count. + */ switch (revs->max_count) { case -1: break; case 0: - if (revs->boundary) { - struct commit_list *list = revs->commits; - while (list) { - list->item->object.flags |= - BOUNDARY_SHOW | BOUNDARY; - list = list->next; - } - /* all remaining commits are boundary commits */ - revs->max_count = -1; - revs->limited = 1; - } else - return NULL; + c = NULL; + break; default: revs->max_count--; } + if (c) + c->object.flags |= SHOWN; + + if (!revs->boundary) { return c; - return get_revision_1(revs); + } + + if (!c) { + /* + * get_revision_1() runs out the commits, and + * we are done computing the boundaries. + * switch to boundary commits output mode. + */ + revs->boundary = 2; + return get_revision(revs); + } + + /* + * boundary commits are the commits that are parents of the + * ones we got from get_revision_1() but they themselves are + * not returned from get_revision_1(). Before returning + * 'c', we need to mark its parents that they could be boundaries. + */ + + for (l = c->parents; l; l = l->next) { + struct object *p; + p = &(l->item->object); + if (p->flags & (CHILD_SHOWN | SHOWN)) + continue; + p->flags |= CHILD_SHOWN; + gc_boundary(&revs->boundary_commits); + add_object_array(p, NULL, &revs->boundary_commits); + } + + return c; } diff --git a/revision.h b/revision.h index 5fec1846f3..6ae39e6bec 100644 --- a/revision.h +++ b/revision.h @@ -7,7 +7,7 @@ #define SHOWN (1u<<3) #define TMP_MARK (1u<<4) /* for isolated cases; clean after use */ #define BOUNDARY (1u<<5) -#define BOUNDARY_SHOW (1u<<6) +#define CHILD_SHOWN (1u<<6) #define ADDED (1u<<7) /* Parents already parsed and added? */ #define SYMMETRIC_LEFT (1u<<8) @@ -21,6 +21,9 @@ struct rev_info { struct commit_list *commits; struct object_array pending; + /* Parents of shown commits */ + struct object_array boundary_commits; + /* Basic information */ const char *prefix; void *prune_data; @@ -40,10 +43,10 @@ struct rev_info { edge_hint:1, limited:1, unpacked:1, /* see also ignore_packed below */ - boundary:1, + boundary:2, left_right:1, parents:1, - reverse:2; + reverse:1; /* Diff flags */ unsigned int diff:1, @@ -74,6 +77,7 @@ struct rev_info { const char *add_signoff; const char *extra_headers; const char *log_reencode; + int no_inline; /* Filter by commit log message */ struct grep_opt *grep_filter; diff --git a/run-command.c b/run-command.c index cfbad74d14..bef9775e08 100644 --- a/run-command.c +++ b/run-command.c @@ -2,30 +2,70 @@ #include "run-command.h" #include "exec_cmd.h" -int run_command_v_opt(const char **argv, int flags) +static inline void close_pair(int fd[2]) { - pid_t pid = fork(); + close(fd[0]); + close(fd[1]); +} + +int start_command(struct child_process *cmd) +{ + int need_in = !cmd->no_stdin && cmd->in < 0; + int fdin[2]; - if (pid < 0) + if (need_in) { + if (pipe(fdin) < 0) + return -ERR_RUN_COMMAND_PIPE; + cmd->in = fdin[1]; + cmd->close_in = 1; + } + + cmd->pid = fork(); + if (cmd->pid < 0) { + if (need_in) + close_pair(fdin); return -ERR_RUN_COMMAND_FORK; - if (!pid) { - if (flags & RUN_COMMAND_NO_STDIN) { + } + + if (!cmd->pid) { + if (cmd->no_stdin) { int fd = open("/dev/null", O_RDWR); dup2(fd, 0); close(fd); + } else if (need_in) { + dup2(fdin[0], 0); + close_pair(fdin); + } else if (cmd->in) { + dup2(cmd->in, 0); + close(cmd->in); } - if (flags & RUN_COMMAND_STDOUT_TO_STDERR) + + if (cmd->stdout_to_stderr) dup2(2, 1); - if (flags & RUN_GIT_CMD) { - execv_git_cmd(argv); + if (cmd->git_cmd) { + execv_git_cmd(cmd->argv); } else { - execvp(argv[0], (char *const*) argv); + execvp(cmd->argv[0], (char *const*) cmd->argv); } - die("exec %s failed.", argv[0]); + die("exec %s failed.", cmd->argv[0]); } + + if (need_in) + close(fdin[0]); + else if (cmd->in) + close(cmd->in); + + return 0; +} + +int finish_command(struct child_process *cmd) +{ + if (cmd->close_in) + close(cmd->in); + for (;;) { int status, code; - pid_t waiting = waitpid(pid, &status, 0); + pid_t waiting = waitpid(cmd->pid, &status, 0); if (waiting < 0) { if (errno == EINTR) @@ -33,7 +73,7 @@ int run_command_v_opt(const char **argv, int flags) error("waitpid failed (%s)", strerror(errno)); return -ERR_RUN_COMMAND_WAITPID; } - if (waiting != pid) + if (waiting != cmd->pid) return -ERR_RUN_COMMAND_WAITPID_WRONG_PID; if (WIFSIGNALED(status)) return -ERR_RUN_COMMAND_WAITPID_SIGNAL; @@ -47,47 +87,21 @@ int run_command_v_opt(const char **argv, int flags) } } -int run_command_v(const char **argv) -{ - return run_command_v_opt(argv, 0); -} - -static int run_command_va_opt(int opt, const char *cmd, va_list param) -{ - int argc; - const char *argv[MAX_RUN_COMMAND_ARGS]; - const char *arg; - - argv[0] = (char*) cmd; - argc = 1; - while (argc < MAX_RUN_COMMAND_ARGS) { - arg = argv[argc++] = va_arg(param, char *); - if (!arg) - break; - } - if (MAX_RUN_COMMAND_ARGS <= argc) - return error("too many args to run %s", cmd); - return run_command_v_opt(argv, opt); -} - -int run_command_opt(int opt, const char *cmd, ...) +int run_command(struct child_process *cmd) { - va_list params; - int r; - - va_start(params, cmd); - r = run_command_va_opt(opt, cmd, params); - va_end(params); - return r; + int code = start_command(cmd); + if (code) + return code; + return finish_command(cmd); } -int run_command(const char *cmd, ...) +int run_command_v_opt(const char **argv, int opt) { - va_list params; - int r; - - va_start(params, cmd); - r = run_command_va_opt(0, cmd, params); - va_end(params); - return r; + struct child_process cmd; + memset(&cmd, 0, sizeof(cmd)); + cmd.argv = argv; + cmd.no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0; + cmd.git_cmd = opt & RUN_GIT_CMD ? 1 : 0; + cmd.stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0; + return run_command(&cmd); } diff --git a/run-command.h b/run-command.h index 59c4476ced..ff090679a6 100644 --- a/run-command.h +++ b/run-command.h @@ -1,22 +1,33 @@ #ifndef RUN_COMMAND_H #define RUN_COMMAND_H -#define MAX_RUN_COMMAND_ARGS 256 enum { ERR_RUN_COMMAND_FORK = 10000, ERR_RUN_COMMAND_EXEC, + ERR_RUN_COMMAND_PIPE, ERR_RUN_COMMAND_WAITPID, ERR_RUN_COMMAND_WAITPID_WRONG_PID, ERR_RUN_COMMAND_WAITPID_SIGNAL, ERR_RUN_COMMAND_WAITPID_NOEXIT, }; +struct child_process { + const char **argv; + pid_t pid; + int in; + unsigned close_in:1; + unsigned no_stdin:1; + unsigned git_cmd:1; /* if this is to be git sub-command */ + unsigned stdout_to_stderr:1; +}; + +int start_command(struct child_process *); +int finish_command(struct child_process *); +int run_command(struct child_process *); + #define RUN_COMMAND_NO_STDIN 1 #define RUN_GIT_CMD 2 /*If this is to be git sub-command */ #define RUN_COMMAND_STDOUT_TO_STDERR 4 int run_command_v_opt(const char **argv, int opt); -int run_command_v(const char **argv); -int run_command_opt(int opt, const char *cmd, ...); -int run_command(const char *cmd, ...); #endif @@ -216,7 +216,7 @@ const char *setup_git_directory_gently(int *nongit_ok) die("Not a git repository: '%s'", gitdirenv); } - if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/') + if (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/') die("Unable to read current working directory"); offset = len = strlen(cwd); diff --git a/sha1_file.c b/sha1_file.c index 219a10f403..7faa8bcd50 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -967,11 +967,12 @@ static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned lon return 0; } -static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size) +static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size, const unsigned char *sha1) { int bytes = strlen(buffer) + 1; unsigned char *buf = xmalloc(1+size); unsigned long n; + int status = Z_OK; n = stream->total_out - bytes; if (n > size) @@ -981,12 +982,22 @@ static void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size if (bytes < size) { stream->next_out = buf + bytes; stream->avail_out = size - bytes; - while (inflate(stream, Z_FINISH) == Z_OK) - /* nothing */; + while (status == Z_OK) + status = inflate(stream, Z_FINISH); } buf[size] = 0; - inflateEnd(stream); - return buf; + if ((status == Z_OK || status == Z_STREAM_END) && !stream->avail_in) { + inflateEnd(stream); + return buf; + } + + if (status < 0) + error("corrupt loose object '%s'", sha1_to_hex(sha1)); + else if (stream->avail_in) + error("garbage at end of loose object '%s'", + sha1_to_hex(sha1)); + free(buf); + return NULL; } /* @@ -1040,7 +1051,7 @@ static int parse_sha1_header(const char *hdr, unsigned long *sizep) return *hdr ? -1 : type_from_string(type); } -void * unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size) +static void *unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size, const unsigned char *sha1) { int ret; z_stream stream; @@ -1050,7 +1061,7 @@ void * unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type if (ret < Z_OK || (*type = parse_sha1_header(hdr, size)) < 0) return NULL; - return unpack_sha1_rest(&stream, hdr, *size); + return unpack_sha1_rest(&stream, hdr, *size, sha1); } static off_t get_delta_base(struct packed_git *p, @@ -1571,7 +1582,7 @@ void *read_sha1_file(const unsigned char *sha1, enum object_type *type, return buf; map = map_sha1_file(sha1, &mapsize); if (map) { - buf = unpack_sha1_file(map, mapsize, type, size); + buf = unpack_sha1_file(map, mapsize, type, size, sha1); munmap(map, mapsize); return buf; } diff --git a/sha1_name.c b/sha1_name.c index 31812d3d26..bede0e5b06 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -602,10 +602,10 @@ static int handle_one_ref(const char *path, */ #define ONELINE_SEEN (1u<<20) -int get_sha1_oneline(const char *prefix, unsigned char *sha1) +static int get_sha1_oneline(const char *prefix, unsigned char *sha1) { struct commit_list *list = NULL, *backup = NULL, *l; - struct commit *commit; + int retval = -1; if (prefix[0] == '!') { if (prefix[1] != '!') @@ -617,20 +617,24 @@ int get_sha1_oneline(const char *prefix, unsigned char *sha1) for_each_ref(handle_one_ref, &list); for (l = list; l; l = l->next) commit_list_insert(l->item, &backup); - while ((commit = pop_most_recent_commit(&list, ONELINE_SEEN))) { + while (list) { char *p; + struct commit *commit; + + commit = pop_most_recent_commit(&list, ONELINE_SEEN); parse_object(commit->object.sha1); if (!commit->buffer || !(p = strstr(commit->buffer, "\n\n"))) continue; if (!prefixcmp(p + 2, prefix)) { hashcpy(sha1, commit->object.sha1); + retval = 0; break; } } free_commit_list(list); for (l = backup; l; l = l->next) clear_commit_marks(l->item, ONELINE_SEEN); - return commit == NULL; + return retval; } /* diff --git a/t/diff-lib.sh b/t/diff-lib.sh index 745a1b0311..4624fe654c 100755 --- a/t/diff-lib.sh +++ b/t/diff-lib.sh @@ -11,7 +11,7 @@ compare_diff_raw () { sed -e "$sanitize_diff_raw" <"$1" >.tmp-1 sed -e "$sanitize_diff_raw" <"$2" >.tmp-2 - diff -u .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2 + git diff .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2 } sanitize_diff_raw_z='/^:/s/ '"$_x40"' '"$_x40"' \([A-Z]\)[0-9]*$/ X X \1#/' @@ -23,7 +23,7 @@ compare_diff_raw_z () { tr '\0' '\012' <"$1" | sed -e "$sanitize_diff_raw_z" >.tmp-1 tr '\0' '\012' <"$2" | sed -e "$sanitize_diff_raw_z" >.tmp-2 - diff -u .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2 + git diff .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2 } compare_diff_patch () { @@ -37,5 +37,5 @@ compare_diff_patch () { /^[dis]*imilarity index [0-9]*%$/d /^index [0-9a-f]*\.\.[0-9a-f]/d ' <"$2" >.tmp-2 - diff -u .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2 + git diff .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2 } diff --git a/t/t1000-read-tree-m-3way.sh b/t/t1000-read-tree-m-3way.sh index d0af8c3d52..e26a36cf0f 100755 --- a/t/t1000-read-tree-m-3way.sh +++ b/t/t1000-read-tree-m-3way.sh @@ -131,7 +131,7 @@ _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" check_result () { git-ls-files --stage | sed -e 's/ '"$_x40"' / X /' >current && - diff -u expected current + git diff expected current } # This is done on an empty work directory, which is the normal diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh index 75e4c9a886..030226bbfb 100755 --- a/t/t1001-read-tree-m-2way.sh +++ b/t/t1001-read-tree-m-2way.sh @@ -33,7 +33,7 @@ compare_change () { -e '/^--- /d; /^+++ /d; /^@@ /d;' \ -e 's/^\([-+][0-7][0-7][0-7][0-7][0-7][0-7]\) '"$_x40"' /\1 X /p' \ "$1" - diff -u expected current + git diff expected current } check_cache_at () { @@ -86,7 +86,7 @@ test_expect_success \ 'rm -f .git/index && read_tree_twoway $treeH $treeM && git-ls-files --stage >1-3.out && - diff -u M.out 1-3.out && + git diff M.out 1-3.out && check_cache_at bozbar dirty && check_cache_at frotz dirty && check_cache_at nitfol dirty' @@ -101,7 +101,7 @@ test_expect_success \ git-update-index --add yomin && read_tree_twoway $treeH $treeM && git-ls-files --stage >4.out || return 1 - diff -u M.out 4.out >4diff.out + git diff M.out 4.out >4diff.out compare_change 4diff.out expected && check_cache_at yomin clean' @@ -115,7 +115,7 @@ test_expect_success \ echo yomin yomin >yomin && read_tree_twoway $treeH $treeM && git-ls-files --stage >5.out || return 1 - diff -u M.out 5.out >5diff.out + git diff M.out 5.out >5diff.out compare_change 5diff.out expected && check_cache_at yomin dirty' @@ -127,7 +127,7 @@ test_expect_success \ git-update-index --add frotz && read_tree_twoway $treeH $treeM && git-ls-files --stage >6.out && - diff -u M.out 6.out && + git diff M.out 6.out && check_cache_at frotz clean' test_expect_success \ @@ -140,7 +140,7 @@ test_expect_success \ echo frotz frotz >frotz && read_tree_twoway $treeH $treeM && git-ls-files --stage >7.out && - diff -u M.out 7.out && + git diff M.out 7.out && check_cache_at frotz dirty' test_expect_success \ @@ -171,7 +171,7 @@ test_expect_success \ git-update-index --add rezrov && read_tree_twoway $treeH $treeM && git-ls-files --stage >10.out && - diff -u M.out 10.out' + git diff M.out 10.out' test_expect_success \ '11 - dirty path removed.' \ @@ -216,7 +216,7 @@ test_expect_success \ git-update-index --add nitfol && read_tree_twoway $treeH $treeM && git-ls-files --stage >14.out || return 1 - diff -u M.out 14.out >14diff.out + git diff M.out 14.out >14diff.out compare_change 14diff.out expected && check_cache_at nitfol clean' @@ -230,7 +230,7 @@ test_expect_success \ echo nitfol nitfol nitfol >nitfol && read_tree_twoway $treeH $treeM && git-ls-files --stage >15.out || return 1 - diff -u M.out 15.out >15diff.out + git diff M.out 15.out >15diff.out compare_change 15diff.out expected && check_cache_at nitfol dirty' @@ -262,7 +262,7 @@ test_expect_success \ git-update-index --add bozbar && read_tree_twoway $treeH $treeM && git-ls-files --stage >18.out && - diff -u M.out 18.out && + git diff M.out 18.out && check_cache_at bozbar clean' test_expect_success \ @@ -275,7 +275,7 @@ test_expect_success \ echo gnusto gnusto >bozbar && read_tree_twoway $treeH $treeM && git-ls-files --stage >19.out && - diff -u M.out 19.out && + git diff M.out 19.out && check_cache_at bozbar dirty' test_expect_success \ @@ -287,7 +287,7 @@ test_expect_success \ git-update-index --add bozbar && read_tree_twoway $treeH $treeM && git-ls-files --stage >20.out && - diff -u M.out 20.out && + git diff M.out 20.out && check_cache_at bozbar dirty' test_expect_success \ @@ -337,7 +337,7 @@ test_expect_success \ git-update-index --add DF && read_tree_twoway $treeDF $treeDFDF && git-ls-files --stage >DFDFcheck.out && - diff -u DFDF.out DFDFcheck.out && + git diff DFDF.out DFDFcheck.out && check_cache_at DF/DF dirty && :' diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh index da3c81357b..87fe993f59 100755 --- a/t/t1002-read-tree-m-u-2way.sh +++ b/t/t1002-read-tree-m-u-2way.sh @@ -16,7 +16,7 @@ compare_change () { sed >current \ -e '/^--- /d; /^+++ /d; /^@@ /d;' \ -e 's/^\(.[0-7][0-7][0-7][0-7][0-7][0-7]\) '"$_x40"' /\1 X /' "$1" - diff -u expected current + git diff expected current } check_cache_at () { diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index ee386cfbf3..78c2e0864f 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -368,12 +368,12 @@ cat > expect << EOF weird EOF -test_expect_success "rename succeeded" "diff -u expect .git/config" +test_expect_success "rename succeeded" "git diff expect .git/config" test_expect_failure "rename non-existing section" \ 'git-config --rename-section branch."world domination" branch.drei' -test_expect_success "rename succeeded" "diff -u expect .git/config" +test_expect_success "rename succeeded" "git diff expect .git/config" test_expect_success "rename another section" \ 'git-config --rename-section branch."1 234 blabl/a" branch.drei' @@ -389,7 +389,7 @@ cat > expect << EOF weird EOF -test_expect_success "rename succeeded" "diff -u expect .git/config" +test_expect_success "rename succeeded" "git diff expect .git/config" cat >> .git/config << EOF [branch "zwei"] a = 1 [branch "vier"] @@ -405,7 +405,7 @@ weird EOF test_expect_success "section was removed properly" \ - "diff -u expect .git/config" + "git diff -u expect .git/config" test_expect_success numbers ' diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh index 6979b7c1c0..db7a847a5d 100755 --- a/t/t3001-ls-files-others-exclude.sh +++ b/t/t3001-ls-files-others-exclude.sh @@ -65,7 +65,7 @@ test_expect_success \ --exclude-per-directory=.gitignore \ --exclude-from=.git/ignore \ >output && - diff -u expect output' + git diff expect output' # Test \r\n (MSDOS-like systems) printf '*.1\r\n/*.3\r\n!*.6\r\n' >.gitignore @@ -77,6 +77,6 @@ test_expect_success \ --exclude-per-directory=.gitignore \ --exclude-from=.git/ignore \ >output && - diff -u expect output' + git diff expect output' test_done diff --git a/t/t3002-ls-files-dashpath.sh b/t/t3002-ls-files-dashpath.sh index b42f1382bc..cc8967d76b 100755 --- a/t/t3002-ls-files-dashpath.sh +++ b/t/t3002-ls-files-dashpath.sh @@ -23,7 +23,7 @@ test_expect_success \ test_expect_success \ 'git-ls-files without path restriction.' \ 'git-ls-files --others >output && - diff -u output - <<EOF + git diff output - <<EOF -- -foo output @@ -34,7 +34,7 @@ EOF test_expect_success \ 'git-ls-files with path restriction.' \ 'git-ls-files --others path0 >output && - diff -u output - <<EOF + git diff output - <<EOF path0 EOF ' @@ -42,7 +42,7 @@ EOF test_expect_success \ 'git-ls-files with path restriction with --.' \ 'git-ls-files --others -- path0 >output && - diff -u output - <<EOF + git diff output - <<EOF path0 EOF ' @@ -50,7 +50,7 @@ EOF test_expect_success \ 'git-ls-files with path restriction with -- --.' \ 'git-ls-files --others -- -- >output && - diff -u output - <<EOF + git diff output - <<EOF -- EOF ' @@ -58,7 +58,7 @@ EOF test_expect_success \ 'git-ls-files with no path restriction.' \ 'git-ls-files --others -- >output && - diff -u output - <<EOF + git diff output - <<EOF -- -foo output diff --git a/t/t3100-ls-tree-restrict.sh b/t/t3100-ls-tree-restrict.sh index 2ec06d3d39..e10749245b 100755 --- a/t/t3100-ls-tree-restrict.sh +++ b/t/t3100-ls-tree-restrict.sh @@ -35,7 +35,7 @@ _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" test_output () { sed -e "s/ $_x40 / X /" <current >check - diff -u expected check + git diff expected check } test_expect_success \ diff --git a/t/t3101-ls-tree-dirname.sh b/t/t3101-ls-tree-dirname.sh index d78deb1e71..087929a4bf 100755 --- a/t/t3101-ls-tree-dirname.sh +++ b/t/t3101-ls-tree-dirname.sh @@ -43,7 +43,7 @@ _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" test_output () { sed -e "s/ $_x40 / X /" <current >check - diff -u expected check + git diff expected check } test_expect_success \ diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 5565c27033..75c000a968 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -47,17 +47,6 @@ test_expect_success \ test ! -f .git/refs/heads/d/e/f && test ! -f .git/logs/refs/heads/d/e/f' -cat >expect <<EOF -0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 checkout: Created from master -EOF -test_expect_success \ - 'git checkout -b g/h/i -l should create a branch and a log' \ - 'GIT_COMMITTER_DATE="2005-05-26 23:30" \ - git-checkout -b g/h/i -l master && - test -f .git/refs/heads/g/h/i && - test -f .git/logs/refs/heads/g/h/i && - diff expect .git/logs/refs/heads/g/h/i' - test_expect_success \ 'git branch j/k should work after branch j has been deleted' \ 'git-branch j && @@ -117,4 +106,58 @@ test_expect_failure \ ln -s real-u .git/logs/refs/heads/u && git-branch -m u v' +test_expect_success 'test tracking setup via --track' \ + 'git-config remote.local.url . && + git-config remote.local.fetch refs/heads/*:refs/remotes/local/* && + (git-show-ref -q refs/remotes/local/master || git-fetch local) && + git-branch --track my1 local/master && + test $(git-config branch.my1.remote) = local && + test $(git-config branch.my1.merge) = refs/heads/master' + +test_expect_success 'test tracking setup (non-wildcard, matching)' \ + 'git-config remote.local.url . && + git-config remote.local.fetch refs/heads/master:refs/remotes/local/master && + (git-show-ref -q refs/remotes/local/master || git-fetch local) && + git-branch --track my4 local/master && + test $(git-config branch.my4.remote) = local && + test $(git-config branch.my4.merge) = refs/heads/master' + +test_expect_success 'test tracking setup (non-wildcard, not matching)' \ + 'git-config remote.local.url . && + git-config remote.local.fetch refs/heads/s:refs/remotes/local/s && + (git-show-ref -q refs/remotes/local/master || git-fetch local) && + git-branch --track my5 local/master && + ! test $(git-config branch.my5.remote) = local && + ! test $(git-config branch.my5.merge) = refs/heads/master' + +test_expect_success 'test tracking setup via config' \ + 'git-config branch.autosetupmerge true && + git-config remote.local.url . && + git-config remote.local.fetch refs/heads/*:refs/remotes/local/* && + (git-show-ref -q refs/remotes/local/master || git-fetch local) && + git-branch my3 local/master && + test $(git-config branch.my3.remote) = local && + test $(git-config branch.my3.merge) = refs/heads/master' + +test_expect_success 'test overriding tracking setup via --no-track' \ + 'git-config branch.autosetupmerge true && + git-config remote.local.url . && + git-config remote.local.fetch refs/heads/*:refs/remotes/local/* && + (git-show-ref -q refs/remotes/local/master || git-fetch local) && + git-branch --no-track my2 local/master && + ! test $(git-config branch.my2.remote) = local && + ! test $(git-config branch.my2.merge) = refs/heads/master' + +# 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 +EOF +test_expect_success \ + 'git checkout -b g/h/i -l should create a branch and a log' \ + 'GIT_COMMITTER_DATE="2005-05-26 23:30" \ + git-checkout -b g/h/i -l master && + test -f .git/refs/heads/g/h/i && + test -f .git/logs/refs/heads/g/h/i && + diff expect .git/logs/refs/heads/g/h/i' + test_done diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh index c12270efab..b5a1400e18 100755 --- a/t/t3300-funny-names.sh +++ b/t/t3300-funny-names.sh @@ -35,7 +35,7 @@ no-funny' >expected test_expect_success 'git-ls-files no-funny' \ 'git-update-index --add "$p0" "$p2" && git-ls-files >current && - diff -u expected current' + git diff expected current' t0=`git-write-tree` echo "$t0" >t0 @@ -48,14 +48,14 @@ EOF test_expect_success 'git-ls-files with-funny' \ 'git-update-index --add "$p1" && git-ls-files >current && - diff -u expected current' + git diff expected current' echo 'just space no-funny tabs ," (dq) and spaces' >expected test_expect_success 'git-ls-files -z with-funny' \ 'git-ls-files -z | tr \\0 \\012 >current && - diff -u expected current' + git diff expected current' t1=`git-write-tree` echo "$t1" >t1 @@ -67,28 +67,28 @@ no-funny EOF test_expect_success 'git-ls-tree with funny' \ 'git-ls-tree -r $t1 | sed -e "s/^[^ ]* //" >current && - diff -u expected current' + git diff expected current' cat > expected <<\EOF A "tabs\t,\" (dq) and spaces" EOF test_expect_success 'git-diff-index with-funny' \ 'git-diff-index --name-status $t0 >current && - diff -u expected current' + git diff expected current' test_expect_success 'git-diff-tree with-funny' \ 'git-diff-tree --name-status $t0 $t1 >current && - diff -u expected current' + git diff expected current' echo 'A tabs ," (dq) and spaces' >expected test_expect_success 'git-diff-index -z with-funny' \ 'git-diff-index -z --name-status $t0 | tr \\0 \\012 >current && - diff -u expected current' + git diff expected current' test_expect_success 'git-diff-tree -z with-funny' \ 'git-diff-tree -z --name-status $t0 $t1 | tr \\0 \\012 >current && - diff -u expected current' + git diff expected current' cat > expected <<\EOF CNUM no-funny "tabs\t,\" (dq) and spaces" @@ -96,7 +96,7 @@ EOF test_expect_success 'git-diff-tree -C with-funny' \ 'git-diff-tree -C --find-copies-harder --name-status \ $t0 $t1 | sed -e 's/^C[0-9]*/CNUM/' >current && - diff -u expected current' + git diff expected current' cat > expected <<\EOF RNUM no-funny "tabs\t,\" (dq) and spaces" @@ -105,7 +105,7 @@ test_expect_success 'git-diff-tree delete with-funny' \ 'git-update-index --force-remove "$p0" && git-diff-index -M --name-status \ $t0 | sed -e 's/^R[0-9]*/RNUM/' >current && - diff -u expected current' + git diff expected current' cat > expected <<\EOF diff --git a/no-funny "b/tabs\t,\" (dq) and spaces" @@ -116,7 +116,7 @@ EOF test_expect_success 'git-diff-tree delete with-funny' \ 'git-diff-index -M -p $t0 | sed -e "s/index [0-9]*%/index NUM%/" >current && - diff -u expected current' + git diff expected current' chmod +x "$p1" cat > expected <<\EOF @@ -130,7 +130,7 @@ EOF test_expect_success 'git-diff-tree delete with-funny' \ 'git-diff-index -M -p $t0 | sed -e "s/index [0-9]*%/index NUM%/" >current && - diff -u expected current' + git diff expected current' cat >expected <<\EOF "tabs\t,\" (dq) and spaces" @@ -139,7 +139,7 @@ EOF test_expect_success 'git-diff-tree rename with-funny applied' \ 'git-diff-index -M -p $t0 | git-apply --stat | sed -e "s/|.*//" -e "s/ *\$//" >current && - diff -u expected current' + git diff expected current' cat > expected <<\EOF no-funny @@ -149,12 +149,12 @@ EOF test_expect_success 'git-diff-tree delete with-funny applied' \ 'git-diff-index -p $t0 | git-apply --stat | sed -e "s/|.*//" -e "s/ *\$//" >current && - diff -u expected current' + git diff expected current' test_expect_success 'git-apply non-git diff' \ 'git-diff-index -p $t0 | sed -ne "/^[-+@]/p" | git-apply --stat | sed -e "s/|.*//" -e "s/ *\$//" >current && - diff -u expected current' + git diff expected current' test_done diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index e54fe0f401..ffddb68db3 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -9,7 +9,7 @@ test_description='commit and log output encodings' compare_with () { git-show -s $1 | sed -e '1,/^$/d' -e 's/^ //' -e '$d' >current && - diff -u current "$2" + git diff current "$2" } test_expect_success setup ' diff --git a/t/t4006-diff-mode.sh b/t/t4006-diff-mode.sh index ca342f48a1..e72c6fd1b4 100755 --- a/t/t4006-diff-mode.sh +++ b/t/t4006-diff-mode.sh @@ -38,7 +38,7 @@ echo ":100644 100755 X X M rezrov" >expected test_expect_success \ 'verify' \ - 'diff -u expected check' + 'git diff expected check' test_done diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 3d85ceaae9..488e075c16 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -106,12 +106,12 @@ do echo "\$ git $cmd" git $cmd | sed -e "s/^\\(-*\\)$V\\(-*\\)\$/\\1g-i-t--v-e-r-s-i-o-n\2/" \ - -e "s/^\\( *boundary=\"-*\\)$V\\(-*\\)\"\$/\\1g-i-t--v-e-r-s-i-o-n\2\"/" + -e "s/^\\(.*mixed; boundary=\"-*\\)$V\\(-*\\)\"\$/\\1g-i-t--v-e-r-s-i-o-n\2\"/" echo "\$" } >"$actual" && if test -f "$expect" then - diff -u "$expect" "$actual" && + git diff "$expect" "$actual" && rm -f "$actual" else # this is to help developing new tests. @@ -238,6 +238,9 @@ format-patch --stdout initial..master format-patch --attach --stdout initial..side format-patch --attach --stdout initial..master^ format-patch --attach --stdout initial..master +format-patch --inline --stdout initial..side +format-patch --inline --stdout initial..master^ +format-patch --inline --stdout initial..master diff --abbrev initial..side diff -r initial..side diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master b/t/t4013/diff.format-patch_--attach_--stdout_initial..master index e5ddd6fcbb..cf6891f748 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master @@ -4,8 +4,7 @@ From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:01:00 +0000 Subject: [PATCH] Second MIME-Version: 1.0 -Content-Type: multipart/mixed; - boundary="------------g-i-t--v-e-r-s-i-o-n" +Content-Type: multipart/mixed; boundary="------------g-i-t--v-e-r-s-i-o-n" This is a multi-part message in MIME format. --------------g-i-t--v-e-r-s-i-o-n @@ -21,11 +20,9 @@ This is the second commit. 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; - name="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" +Content-Type: text/x-patch; name="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" Content-Transfer-Encoding: 8bit -Content-Disposition: inline; - filename="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" +Content-Disposition: attachment; filename="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 @@ -66,8 +63,7 @@ From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:02:00 +0000 Subject: [PATCH] Third MIME-Version: 1.0 -Content-Type: multipart/mixed; - boundary="------------g-i-t--v-e-r-s-i-o-n" +Content-Type: multipart/mixed; boundary="------------g-i-t--v-e-r-s-i-o-n" This is a multi-part message in MIME format. --------------g-i-t--v-e-r-s-i-o-n @@ -80,11 +76,9 @@ Content-Transfer-Encoding: 8bit 2 files changed, 5 insertions(+), 0 deletions(-) create mode 100644 file1 --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; - name="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" +Content-Type: text/x-patch; name="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" Content-Transfer-Encoding: 8bit -Content-Disposition: inline; - filename="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" +Content-Disposition: attachment; filename="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 @@ -115,8 +109,7 @@ From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:03:00 +0000 Subject: [PATCH] Side MIME-Version: 1.0 -Content-Type: multipart/mixed; - boundary="------------g-i-t--v-e-r-s-i-o-n" +Content-Type: multipart/mixed; boundary="------------g-i-t--v-e-r-s-i-o-n" This is a multi-part message in MIME format. --------------g-i-t--v-e-r-s-i-o-n @@ -130,11 +123,9 @@ Content-Transfer-Encoding: 8bit 3 files changed, 9 insertions(+), 0 deletions(-) create mode 100644 file3 --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; - name="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" +Content-Type: text/x-patch; name="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" Content-Transfer-Encoding: 8bit -Content-Disposition: inline; - filename="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" +Content-Disposition: attachment; filename="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ index d0dd19b623..fe0258720c 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ @@ -4,8 +4,7 @@ From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:01:00 +0000 Subject: [PATCH] Second MIME-Version: 1.0 -Content-Type: multipart/mixed; - boundary="------------g-i-t--v-e-r-s-i-o-n" +Content-Type: multipart/mixed; boundary="------------g-i-t--v-e-r-s-i-o-n" This is a multi-part message in MIME format. --------------g-i-t--v-e-r-s-i-o-n @@ -21,11 +20,9 @@ This is the second commit. 3 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 file2 --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; - name="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" +Content-Type: text/x-patch; name="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" Content-Transfer-Encoding: 8bit -Content-Disposition: inline; - filename="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" +Content-Disposition: attachment; filename="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 @@ -66,8 +63,7 @@ From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:02:00 +0000 Subject: [PATCH] Third MIME-Version: 1.0 -Content-Type: multipart/mixed; - boundary="------------g-i-t--v-e-r-s-i-o-n" +Content-Type: multipart/mixed; boundary="------------g-i-t--v-e-r-s-i-o-n" This is a multi-part message in MIME format. --------------g-i-t--v-e-r-s-i-o-n @@ -80,11 +76,9 @@ Content-Transfer-Encoding: 8bit 2 files changed, 5 insertions(+), 0 deletions(-) create mode 100644 file1 --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; - name="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" +Content-Type: text/x-patch; name="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" Content-Transfer-Encoding: 8bit -Content-Disposition: inline; - filename="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" +Content-Disposition: attachment; filename="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..side b/t/t4013/diff.format-patch_--attach_--stdout_initial..side index 67a95c5cba..9ff828ee9d 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..side +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..side @@ -4,8 +4,7 @@ From: A U Thor <author@example.com> Date: Mon, 26 Jun 2006 00:03:00 +0000 Subject: [PATCH] Side MIME-Version: 1.0 -Content-Type: multipart/mixed; - boundary="------------g-i-t--v-e-r-s-i-o-n" +Content-Type: multipart/mixed; boundary="------------g-i-t--v-e-r-s-i-o-n" This is a multi-part message in MIME format. --------------g-i-t--v-e-r-s-i-o-n @@ -19,11 +18,9 @@ Content-Transfer-Encoding: 8bit 3 files changed, 9 insertions(+), 0 deletions(-) create mode 100644 file3 --------------g-i-t--v-e-r-s-i-o-n -Content-Type: text/x-patch; - name="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" +Content-Type: text/x-patch; name="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" Content-Transfer-Encoding: 8bit -Content-Disposition: inline; - filename="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" +Content-Disposition: attachment; filename="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_initial..master new file mode 100644 index 0000000000..aa110c0e7f --- /dev/null +++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master @@ -0,0 +1,164 @@ +$ git format-patch --inline --stdout initial..master +From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 +From: A U Thor <author@example.com> +Date: Mon, 26 Jun 2006 00:01:00 +0000 +Subject: [PATCH] Second +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="------------g-i-t--v-e-r-s-i-o-n" + +This is a multi-part message in MIME format. +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit + + +This is the second commit. +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) + delete mode 100644 file2 +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/x-patch; name="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" +Content-Transfer-Encoding: 8bit +Content-Disposition: inline; filename="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 + +--------------g-i-t--v-e-r-s-i-o-n-- + + + +From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001 +From: A U Thor <author@example.com> +Date: Mon, 26 Jun 2006 00:02:00 +0000 +Subject: [PATCH] Third +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="------------g-i-t--v-e-r-s-i-o-n" + +This is a multi-part message in MIME format. +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit + +--- + dir/sub | 2 ++ + file1 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + create mode 100644 file1 +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/x-patch; name="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" +Content-Transfer-Encoding: 8bit +Content-Disposition: inline; filename="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +--------------g-i-t--v-e-r-s-i-o-n-- + + + +From c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Mon Sep 17 00:00:00 2001 +From: A U Thor <author@example.com> +Date: Mon, 26 Jun 2006 00:03:00 +0000 +Subject: [PATCH] Side +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="------------g-i-t--v-e-r-s-i-o-n" + +This is a multi-part message in MIME format. +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit + +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + create mode 100644 file3 +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/x-patch; name="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" +Content-Transfer-Encoding: 8bit +Content-Disposition: inline; filename="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +--------------g-i-t--v-e-r-s-i-o-n-- + + +$ diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ new file mode 100644 index 0000000000..95e9ea4c59 --- /dev/null +++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ @@ -0,0 +1,106 @@ +$ git format-patch --inline --stdout initial..master^ +From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 +From: A U Thor <author@example.com> +Date: Mon, 26 Jun 2006 00:01:00 +0000 +Subject: [PATCH] Second +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="------------g-i-t--v-e-r-s-i-o-n" + +This is a multi-part message in MIME format. +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit + + +This is the second commit. +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) + delete mode 100644 file2 +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/x-patch; name="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" +Content-Transfer-Encoding: 8bit +Content-Disposition: inline; filename="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 + +--------------g-i-t--v-e-r-s-i-o-n-- + + + +From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001 +From: A U Thor <author@example.com> +Date: Mon, 26 Jun 2006 00:02:00 +0000 +Subject: [PATCH] Third +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="------------g-i-t--v-e-r-s-i-o-n" + +This is a multi-part message in MIME format. +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit + +--- + dir/sub | 2 ++ + file1 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + create mode 100644 file1 +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/x-patch; name="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" +Content-Transfer-Encoding: 8bit +Content-Disposition: inline; filename="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +--------------g-i-t--v-e-r-s-i-o-n-- + + +$ diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..side b/t/t4013/diff.format-patch_--inline_--stdout_initial..side new file mode 100644 index 0000000000..86ae923d71 --- /dev/null +++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..side @@ -0,0 +1,59 @@ +$ git format-patch --inline --stdout initial..side +From c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Mon Sep 17 00:00:00 2001 +From: A U Thor <author@example.com> +Date: Mon, 26 Jun 2006 00:03:00 +0000 +Subject: [PATCH] Side +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="------------g-i-t--v-e-r-s-i-o-n" + +This is a multi-part message in MIME format. +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit + +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + create mode 100644 file3 +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/x-patch; name="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" +Content-Transfer-Encoding: 8bit +Content-Disposition: inline; filename="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +--------------g-i-t--v-e-r-s-i-o-n-- + + +$ diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index adf4993bac..930e209d31 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -43,13 +43,13 @@ index adf3937..6edc172 100644 EOF git-diff > out -test_expect_success "Ray's example without options" 'diff -u expect out' +test_expect_success "Ray's example without options" 'git diff expect out' git-diff -w > out -test_expect_success "Ray's example with -w" 'diff -u expect out' +test_expect_success "Ray's example with -w" 'git diff expect out' git-diff -b > out -test_expect_success "Ray's example with -b" 'diff -u expect out' +test_expect_success "Ray's example with -b" 'git diff expect out' tr 'Q' '\015' << EOF > x whitespace at beginning @@ -90,14 +90,14 @@ index d99af23..8b32fb5 100644 +CR at end EOF git-diff > out -test_expect_success 'another test, without options' 'diff -u expect out' +test_expect_success 'another test, without options' 'git diff expect out' cat << EOF > expect diff --git a/x b/x index d99af23..8b32fb5 100644 EOF git-diff -w > out -test_expect_success 'another test, with -w' 'diff -u expect out' +test_expect_success 'another test, with -w' 'git diff expect out' tr 'Q' '\015' << EOF > expect diff --git a/x b/x @@ -115,6 +115,6 @@ index d99af23..8b32fb5 100644 CR at endQ EOF git-diff -b > out -test_expect_success 'another test, with -b' 'diff -u expect out' +test_expect_success 'another test, with -b' 'git diff expect out' test_done diff --git a/t/t4016-diff-quote.sh b/t/t4016-diff-quote.sh index 2e7cd5f255..5dbdc0c9fa 100755 --- a/t/t4016-diff-quote.sh +++ b/t/t4016-diff-quote.sh @@ -49,7 +49,7 @@ cat >expect <<\EOF EOF test_expect_success 'git diff --summary -M HEAD' ' git diff --summary -M HEAD >actual && - diff -u expect actual + git diff expect actual ' cat >expect <<\EOF @@ -64,7 +64,7 @@ cat >expect <<\EOF EOF test_expect_success 'git diff --stat -M HEAD' ' git diff --stat -M HEAD >actual && - diff -u expect actual + git diff expect actual ' test_done diff --git a/t/t4100-apply-stat.sh b/t/t4100-apply-stat.sh index 6579f06b05..7b81c32e57 100755 --- a/t/t4100-apply-stat.sh +++ b/t/t4100-apply-stat.sh @@ -11,37 +11,37 @@ test_description='git-apply --stat --summary test. test_expect_success \ 'rename' \ 'git-apply --stat --summary <../t4100/t-apply-1.patch >current && - diff -u ../t4100/t-apply-1.expect current' + git diff ../t4100/t-apply-1.expect current' test_expect_success \ 'copy' \ 'git-apply --stat --summary <../t4100/t-apply-2.patch >current && - diff -u ../t4100/t-apply-2.expect current' + git diff ../t4100/t-apply-2.expect current' test_expect_success \ 'rewrite' \ 'git-apply --stat --summary <../t4100/t-apply-3.patch >current && - diff -u ../t4100/t-apply-3.expect current' + git diff ../t4100/t-apply-3.expect current' test_expect_success \ 'mode' \ 'git-apply --stat --summary <../t4100/t-apply-4.patch >current && - diff -u ../t4100/t-apply-4.expect current' + git diff ../t4100/t-apply-4.expect current' test_expect_success \ 'non git' \ 'git-apply --stat --summary <../t4100/t-apply-5.patch >current && - diff -u ../t4100/t-apply-5.expect current' + git diff ../t4100/t-apply-5.expect current' test_expect_success \ 'non git' \ 'git-apply --stat --summary <../t4100/t-apply-6.patch >current && - diff -u ../t4100/t-apply-6.expect current' + git diff ../t4100/t-apply-6.expect current' test_expect_success \ 'non git' \ 'git-apply --stat --summary <../t4100/t-apply-7.patch >current && - diff -u ../t4100/t-apply-7.expect current' + git diff ../t4100/t-apply-7.expect current' test_done diff --git a/t/t4104-apply-boundary.sh b/t/t4104-apply-boundary.sh index 2ff800c23f..a5fb3ea40e 100755 --- a/t/t4104-apply-boundary.sh +++ b/t/t4104-apply-boundary.sh @@ -90,7 +90,7 @@ do cat '"$kind-patch.$with"' (exit 1) } && - diff -u '"$kind"'-expect victim + git diff '"$kind"'-expect victim ' done done @@ -108,7 +108,7 @@ do cat '"$kind-ng.without"' (exit 1) } && - diff -u '"$kind"'-expect victim + git diff '"$kind"'-expect victim ' done diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh index d5f2cfb186..b947ed83bb 100755 --- a/t/t4115-apply-symlink.sh +++ b/t/t4115-apply-symlink.sh @@ -33,7 +33,7 @@ test_expect_success 'apply symlink patch' ' git checkout side && git apply patch && git diff-files -p >patched && - diff -u patch patched + git diff patch patched ' @@ -42,7 +42,7 @@ test_expect_success 'apply --index symlink patch' ' git checkout -f side && git apply --index patch && git diff-index --cached -p HEAD >patched && - diff -u patch patched + git diff patch patched ' diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh index aa2c869e0e..2685b22630 100755 --- a/t/t4116-apply-reverse.sh +++ b/t/t4116-apply-reverse.sh @@ -42,7 +42,7 @@ test_expect_success 'apply in reverse' ' git reset --hard second && git apply --reverse --binary --index patch && git diff >diff && - diff -u /dev/null diff + git diff /dev/null diff ' diff --git a/t/t4117-apply-reject.sh b/t/t4117-apply-reject.sh index b4de075a3e..91931f0e3f 100755 --- a/t/t4117-apply-reject.sh +++ b/t/t4117-apply-reject.sh @@ -54,7 +54,7 @@ test_expect_success 'apply without --reject should fail' ' exit 1 fi - diff -u file1 saved.file1 + git diff file1 saved.file1 ' test_expect_success 'apply without --reject should fail' ' @@ -65,7 +65,7 @@ test_expect_success 'apply without --reject should fail' ' exit 1 fi - diff -u file1 saved.file1 + git diff file1 saved.file1 ' test_expect_success 'apply with --reject should fail but update the file' ' @@ -79,7 +79,7 @@ test_expect_success 'apply with --reject should fail but update the file' ' exit 1 fi - diff -u file1 expected && + git diff file1 expected && cat file1.rej && @@ -105,7 +105,7 @@ test_expect_success 'apply with --reject should fail but update the file' ' echo "file1 still exists?" exit 1 } - diff -u file2 expected && + git diff file2 expected && cat file2.rej && @@ -132,7 +132,7 @@ test_expect_success 'the same test with --verbose' ' echo "file1 still exists?" exit 1 } - diff -u file2 expected && + git diff file2 expected && cat file2.rej && @@ -151,7 +151,7 @@ test_expect_success 'apply cleanly with --verbose' ' git apply --verbose patch.1 && - diff -u file1 clean + git diff file1 clean ' test_done diff --git a/t/t4118-apply-empty-context.sh b/t/t4118-apply-empty-context.sh index 7309422fe5..690a182003 100755 --- a/t/t4118-apply-empty-context.sh +++ b/t/t4118-apply-empty-context.sh @@ -37,7 +37,7 @@ test_expect_success 'apply --numstat' ' echo "0 1 file1" && echo "0 1 file2" } >expect && - diff -u expect actual + git diff expect actual ' @@ -47,8 +47,8 @@ test_expect_success 'apply --apply' ' cat file2.orig >file2 && git update-index file1 file2 && git apply --index diff.output && - diff -u file1.mods file1 && - diff -u file2.mods file2 + git diff file1.mods file1 && + git diff file2.mods file2 ' test_done diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh index 639d45fcec..e081b32aff 100755 --- a/t/t4200-rerere.sh +++ b/t/t4200-rerere.sh @@ -70,7 +70,7 @@ EOF git rerere diff > out -test_expect_success 'rerere diff' 'diff -u expect out' +test_expect_success 'rerere diff' 'git diff expect out' cat > expect << EOF a1 @@ -78,7 +78,7 @@ EOF git rerere status > out -test_expect_success 'rerere status' 'diff -u expect out' +test_expect_success 'rerere status' 'git diff expect out' test_expect_success 'commit succeeds' \ "git commit -q -a -m 'prefer first over second'" @@ -94,7 +94,7 @@ test_expect_failure 'another conflicting merge' 'git pull . first' git show first:a1 | sed 's/To die: t/To die! T/' > expect test_expect_success 'rerere kicked in' "! grep ======= a1" -test_expect_success 'rerere prefers first change' 'diff -u a1 expect' +test_expect_success 'rerere prefers first change' 'git diff a1 expect' rm $rr/postimage echo "$sha1 a1" | tr '\012' '\0' > .git/rr-cache/MERGE_RR diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh index b1c97b0dfb..477b267599 100755 --- a/t/t5400-send-pack.sh +++ b/t/t5400-send-pack.sh @@ -110,7 +110,7 @@ test_expect_success \ cd .. && git-update-ref refs/heads/master master^ || return 1 git-send-pack --force ./victim/.git/ master && return 1 - ! diff .git/refs/heads/master victim/.git/refs/heads/master + ! git diff .git/refs/heads/master victim/.git/refs/heads/master ' test_done diff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh index 0c0034e34c..f1c7ff0c0a 100755 --- a/t/t5401-update-hooks.sh +++ b/t/t5401-update-hooks.sh @@ -25,8 +25,8 @@ test_expect_success setup ' cat >victim/.git/hooks/pre-receive <<'EOF' #!/bin/sh -echo "$@" >>$GIT_DIR/pre-receive.args -read x; printf "$x" >$GIT_DIR/pre-receive.stdin +printf "$@" >>$GIT_DIR/pre-receive.args +cat - >$GIT_DIR/pre-receive.stdin echo STDOUT pre-receive echo STDERR pre-receive >&2 EOF @@ -44,8 +44,8 @@ chmod u+x victim/.git/hooks/update cat >victim/.git/hooks/post-receive <<'EOF' #!/bin/sh -echo "$@" >>$GIT_DIR/post-receive.args -read x; printf "$x" >$GIT_DIR/post-receive.stdin +printf "$@" >>$GIT_DIR/post-receive.args +cat - >$GIT_DIR/post-receive.stdin echo STDOUT post-receive echo STDERR post-receive >&2 EOF @@ -80,36 +80,38 @@ test_expect_success 'hooks ran' ' test -f victim/.git/post-update.stdin ' -test_expect_success 'pre-receive hook arguments' ' - echo \ - refs/heads/master $commit0 $commit1 \ - refs/heads/tofail $commit1 $commit0 \ - | diff - victim/.git/pre-receive.args +test_expect_success 'pre-receive hook input' ' + (echo $commit0 $commit1 refs/heads/master; + echo $commit1 $commit0 refs/heads/tofail + ) | git diff - victim/.git/pre-receive.stdin ' test_expect_success 'update hook arguments' ' (echo refs/heads/master $commit0 $commit1; echo refs/heads/tofail $commit1 $commit0 - ) | diff - victim/.git/update.args + ) | git diff - victim/.git/update.args ' -test_expect_success 'post-receive hook arguments' ' - echo refs/heads/master $commit0 $commit1 | - diff - victim/.git/post-receive.args +test_expect_success 'post-receive hook input' ' + echo $commit0 $commit1 refs/heads/master | + git diff - victim/.git/post-receive.stdin ' test_expect_success 'post-update hook arguments' ' echo refs/heads/master | - diff -u - victim/.git/post-update.args + git diff - victim/.git/post-update.args ' test_expect_success 'all hook stdin is /dev/null' ' - ! test -s victim/.git/pre-receive.stdin && ! test -s victim/.git/update.stdin && - ! test -s victim/.git/post-receive.stdin && ! test -s victim/.git/post-update.stdin ' +test_expect_success 'all *-receive hook args are empty' ' + ! test -s victim/.git/pre-receive.args && + ! test -s victim/.git/post-receive.args +' + test_expect_failure 'send-pack produced no output' ' test -s send.out ' @@ -128,7 +130,7 @@ STDERR post-update EOF test_expect_success 'send-pack stderr contains hook messages' ' egrep ^STD send.err >actual && - diff - actual <expect + git diff - actual <expect ' test_done diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index fa76662dce..426017e1d0 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -90,6 +90,13 @@ test_expect_success 'create bundle 1' ' git bundle create bundle1 master^..master ' +test_expect_success 'header of bundle looks right' ' + head -n 1 "$D"/bundle1 | grep "^#" && + head -n 2 "$D"/bundle1 | grep "^-[0-9a-f]\{40\} " && + head -n 3 "$D"/bundle1 | grep "^[0-9a-f]\{40\} " && + head -n 4 "$D"/bundle1 | grep "^$" +' + test_expect_success 'create bundle 2' ' cd "$D" && git bundle create bundle2 master~2..master @@ -101,10 +108,41 @@ test_expect_failure 'unbundle 1' ' git fetch "$D/bundle1" master:master ' +test_expect_success 'bundle 1 has only 3 files ' ' + cd "$D" && + ( + while read x && test -n "$x" + do + :; + done + cat + ) <bundle1 >bundle.pack && + git index-pack bundle.pack && + verify=$(git verify-pack -v bundle.pack) && + test 4 = $(echo "$verify" | wc -l) +' + test_expect_success 'unbundle 2' ' cd "$D/bundle" && git fetch ../bundle2 master:master && test "tip" = "$(git log -1 --pretty=oneline master | cut -b42-)" ' +test_expect_success 'bundle does not prerequisite objects' ' + cd "$D" && + touch file2 && + git add file2 && + git commit -m add.file2 file2 && + git bundle create bundle3 -1 HEAD && + ( + while read x && test -n "$x" + do + :; + done + cat + ) <bundle3 >bundle.pack && + git index-pack bundle.pack && + test 4 = $(git verify-pack -v bundle.pack | wc -l) +' + test_done diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh index 0b600bb429..6c9cc67508 100755 --- a/t/t5515-fetch-merge-logic.sh +++ b/t/t5515-fetch-merge-logic.sh @@ -149,7 +149,7 @@ do } >"$actual" && if test -f "$expect" then - diff -u "$expect" "$actual" && + git diff -u "$expect" "$actual" && rm -f "$actual" else # this is to help developing new tests. diff --git a/t/t6023-merge-file.sh b/t/t6023-merge-file.sh index f3cd3dba4d..c76fccfb5a 100644 --- a/t/t6023-merge-file.sh +++ b/t/t6023-merge-file.sh @@ -63,7 +63,7 @@ test_expect_success "merge without conflict (missing LF at EOF)" \ "git-merge-file test2.txt orig.txt new2.txt" test_expect_success "merge result added missing LF" \ - "diff -u test.txt test2.txt" + "git diff test.txt test2.txt" cp test.txt backup.txt test_expect_failure "merge with conflicts" \ @@ -86,7 +86,7 @@ non timebo mala, quoniam tu mecum es: virga tua et baculus tuus ipsa me consolata sunt. EOF -test_expect_success "expected conflict markers" "diff -u test.txt expect.txt" +test_expect_success "expected conflict markers" "git diff test.txt expect.txt" cp backup.txt test.txt test_expect_failure "merge with conflicts, using -L" \ @@ -110,7 +110,7 @@ virga tua et baculus tuus ipsa me consolata sunt. EOF test_expect_success "expected conflict markers, with -L" \ - "diff -u test.txt expect.txt" + "git diff test.txt expect.txt" sed "s/ tu / TU /" < new1.txt > new5.txt test_expect_failure "conflict in removed tail" \ @@ -132,7 +132,7 @@ virga tua et baculus tuus ipsa me consolata sunt. >>>>>>> new5.txt EOF -test_expect_success "expected conflict markers" "diff -u expect out" +test_expect_success "expected conflict markers" "git diff expect out" test_done diff --git a/t/t6024-recursive-merge.sh b/t/t6024-recursive-merge.sh index 31b96257b4..a398556137 100644 --- a/t/t6024-recursive-merge.sh +++ b/t/t6024-recursive-merge.sh @@ -70,7 +70,7 @@ G >>>>>>> G:a1 EOF -test_expect_success "result contains a conflict" "diff -u expect a1" +test_expect_success "result contains a conflict" "git diff expect a1" git ls-files --stage > out cat > expect << EOF @@ -79,6 +79,6 @@ cat > expect << EOF 100644 fd7923529855d0b274795ae3349c5e0438333979 3 a1 EOF -test_expect_success "virtual trees were processed" "diff -u expect out" +test_expect_success "virtual trees were processed" "git diff expect out" test_done diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh index ea14023616..526d7d1c44 100755 --- a/t/t6200-fmt-merge-msg.sh +++ b/t/t6200-fmt-merge-msg.sh @@ -79,7 +79,7 @@ test_expect_success 'merge-msg test #1' ' git fetch . left && git fmt-merge-msg <.git/FETCH_HEAD >actual && - diff -u actual expected + git diff actual expected ' cat >expected <<\EOF @@ -92,7 +92,7 @@ test_expect_success 'merge-msg test #2' ' git fetch ../trash left && git fmt-merge-msg <.git/FETCH_HEAD >actual && - diff -u actual expected + git diff actual expected ' cat >expected <<\EOF @@ -115,7 +115,7 @@ test_expect_success 'merge-msg test #3' ' git fetch . left && git fmt-merge-msg <.git/FETCH_HEAD >actual && - diff -u actual expected + git diff actual expected ' cat >expected <<\EOF @@ -145,7 +145,7 @@ test_expect_success 'merge-msg test #4' ' git fetch . left right && git fmt-merge-msg <.git/FETCH_HEAD >actual && - diff -u actual expected + git diff actual expected ' test_expect_success 'merge-msg test #5' ' @@ -157,7 +157,7 @@ test_expect_success 'merge-msg test #5' ' git fetch . left right && git fmt-merge-msg <.git/FETCH_HEAD >actual && - diff -u actual expected + git diff actual expected ' test_done diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh index 7dcfc7e7db..eb628fe075 100755 --- a/t/t9100-git-svn-basic.sh +++ b/t/t9100-git-svn-basic.sh @@ -169,7 +169,7 @@ test_expect_success "$name" " svn up '$SVN_TREE' && test -f '$SVN_TREE'/exec-2.sh && test ! -L '$SVN_TREE'/exec-2.sh && - diff -u help $SVN_TREE/exec-2.sh" + git diff help $SVN_TREE/exec-2.sh" if test "$have_utf8" = t then @@ -193,7 +193,7 @@ test_expect_success "$name" \ "git-svn init $svnrepo && git-svn fetch && git-rev-list --pretty=raw remotes/git-svn | grep ^tree | uniq > a && git-rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b && - diff -u a b" + git diff a b" name='check imported tree checksums expected tree checksums' rm -f expected @@ -211,7 +211,7 @@ tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e tree 8f51f74cf0163afc9ad68a4b1537288c4558b5a4 EOF -test_expect_success "$name" "diff -u a expected" +test_expect_success "$name" "git diff a expected" test_expect_failure 'exit if remote refs are ambigious' " git-config --add svn-remote.svn.fetch \ diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 2e1a09ff2d..8e958da536 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -74,7 +74,7 @@ EOF test_expect_success \ 'A: verify commit' \ 'git-cat-file commit master | sed 1d >actual && - diff -u expect actual' + git diff expect actual' cat >expect <<EOF 100644 blob file2 @@ -84,22 +84,22 @@ EOF test_expect_success \ 'A: verify tree' \ 'git-cat-file -p master^{tree} | sed "s/ [0-9a-f]* / /" >actual && - diff -u expect actual' + git diff expect actual' echo "$file2_data" >expect test_expect_success \ 'A: verify file2' \ - 'git-cat-file blob master:file2 >actual && diff -u expect actual' + 'git-cat-file blob master:file2 >actual && git diff expect actual' echo "$file3_data" >expect test_expect_success \ 'A: verify file3' \ - 'git-cat-file blob master:file3 >actual && diff -u expect actual' + 'git-cat-file blob master:file3 >actual && git diff expect actual' printf "$file4_data" >expect test_expect_success \ 'A: verify file4' \ - 'git-cat-file blob master:file4 >actual && diff -u expect actual' + 'git-cat-file blob master:file4 >actual && git diff expect actual' cat >expect <<EOF :2 `git-rev-parse --verify master:file2` @@ -109,7 +109,7 @@ cat >expect <<EOF EOF test_expect_success \ 'A: verify marks output' \ - 'diff -u expect marks.out' + 'git diff expect marks.out' test_expect_success \ 'A: verify marks import' \ @@ -117,7 +117,7 @@ test_expect_success \ --import-marks=marks.out \ --export-marks=marks.new \ </dev/null && - diff -u expect marks.new' + git diff -u expect marks.new' ### ### series B @@ -183,7 +183,7 @@ EOF test_expect_success \ 'C: verify commit' \ 'git-cat-file commit branch | sed 1d >actual && - diff -u expect actual' + git diff expect actual' cat >expect <<EOF :000000 100755 0000000000000000000000000000000000000000 f1fb5da718392694d0076d677d6d0e364c79b0bc A file2/newf @@ -240,13 +240,13 @@ echo "$file5_data" >expect test_expect_success \ 'D: verify file5' \ 'git-cat-file blob branch:newdir/interesting >actual && - diff -u expect actual' + git diff expect actual' echo "$file6_data" >expect test_expect_success \ 'D: verify file6' \ 'git-cat-file blob branch:newdir/exec.sh >actual && - diff -u expect actual' + git diff expect actual' ### ### series E @@ -282,7 +282,7 @@ EOF test_expect_success \ 'E: verify commit' \ 'git-cat-file commit branch | sed 1,2d >actual && - diff -u expect actual' + git diff expect actual' ### ### series F @@ -335,7 +335,7 @@ EOF test_expect_success \ 'F: verify other commit' \ 'git-cat-file commit other >actual && - diff -u expect actual' + git diff expect actual' ### ### series G @@ -413,7 +413,7 @@ echo "$file5_data" >expect test_expect_success \ 'H: verify file' \ 'git-cat-file blob H:h/e/l/lo >actual && - diff -u expect actual' + git diff expect actual' ### ### series I @@ -439,7 +439,7 @@ EOF test_expect_success \ 'I: verify edge list' \ 'sed -e s/pack-.*pack/pack-.pack/ edges.list >actual && - diff -u expect actual' + git diff expect actual' ### ### series J @@ -501,4 +501,54 @@ test_expect_success \ 'test `git-rev-parse --verify branch^1` \ = `git-rev-parse --verify K^1`' +### +### series L +### + +cat >input <<INPUT_END +blob +mark :1 +data <<EOF +some data +EOF + +blob +mark :2 +data <<EOF +other data +EOF + +commit refs/heads/L +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data <<COMMIT +create L +COMMIT + +M 644 :1 b. +M 644 :1 b/other +M 644 :1 ba + +commit refs/heads/L +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data <<COMMIT +update L +COMMIT + +M 644 :2 b. +M 644 :2 b/other +M 644 :2 ba +INPUT_END + +cat >expect <<EXPECT_END +:100644 100644 4268632... 55d3a52... M b. +:040000 040000 0ae5cac... 443c768... M b +:100644 100644 4268632... 55d3a52... M ba +EXPECT_END + +test_expect_success \ + 'L: verify internal tree sorting' \ + 'git-fast-import <input && + git-diff --raw L^ L >output && + git diff expect output' + test_done diff --git a/templates/Makefile b/templates/Makefile index 0eeee43feb..b8352e731b 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -1,5 +1,9 @@ # make and install sample templates +ifndef V + QUIET = @ +endif + INSTALL ?= install TAR ?= tar prefix ?= $(HOME) @@ -18,7 +22,7 @@ all: boilerplates.made custom bpsrc = $(filter-out %~,$(wildcard *--*)) boilerplates.made : $(bpsrc) - ls *--* 2>/dev/null | \ + $(QUIET)ls *--* 2>/dev/null | \ while read boilerplate; \ do \ case "$$boilerplate" in *~) continue ;; esac && \ @@ -29,13 +33,13 @@ boilerplates.made : $(bpsrc) *--) ;; \ *) cp $$boilerplate blt/$$dst ;; \ esac || exit; \ - done || exit + done && \ date >$@ # If you need build-tailored templates, build them into blt/ # directory yourself here. custom: - : no custom templates yet + $(QUIET): no custom templates yet clean: rm -rf blt boilerplates.made @@ -26,14 +26,14 @@ #include "quote.h" /* Stolen from "imap-send.c". */ -static int git_vasprintf(char **strp, const char *fmt, va_list ap) +int nfvasprintf(char **strp, const char *fmt, va_list ap) { int len; char tmp[1024]; if ((len = vsnprintf(tmp, sizeof(tmp), fmt, ap)) < 0 || !(*strp = xmalloc(len + 1))) - return -1; + die("Fatal: Out of memory\n"); if (len >= (int)sizeof(tmp)) vsprintf(*strp, fmt, ap); else @@ -41,13 +41,15 @@ static int git_vasprintf(char **strp, const char *fmt, va_list ap) return len; } -/* Stolen from "imap-send.c". */ -int nfvasprintf(char **str, const char *fmt, va_list va) +int nfasprintf(char **str, const char *fmt, ...) { - int ret = git_vasprintf(str, fmt, va); - if (ret < 0) - die("Fatal: Out of memory\n"); - return ret; + int rc; + va_list args; + + va_start(args, fmt); + rc = nfvasprintf(str, fmt, args); + va_end(args); + return rc; } /* Get a trace file descriptor from GIT_TRACE env variable. */ |