Merge commit '402fa75eed29c104ae5392ce88560f6bffc64ce7'

This commit is contained in:
Johannes Sixt
2007-05-19 22:38:56 +02:00
90 changed files with 2175 additions and 513 deletions

2
.gitignore vendored
View File

@@ -77,6 +77,7 @@ git-merge-ours
git-merge-recursive
git-merge-resolve
git-merge-stupid
git-merge-subtree
git-mergetool
git-mktag
git-mktree
@@ -148,6 +149,7 @@ test-chmtime
test-date
test-delta
test-dump-cache-tree
test-match-trees
common-cmds.h
*.tar.gz
*.dsc

View File

@@ -2,6 +2,7 @@
*.html
*.1
*.7
*.made
howto-index.txt
doc.dep
cmds-*.txt

View File

@@ -90,14 +90,17 @@ cmds_txt = cmds-ancillaryinterrogators.txt \
cmds-purehelpers.txt \
cmds-foreignscminterface.txt
$(cmds_txt): cmd-list.perl $(MAN1_TXT)
$(cmds_txt): cmd-list.made
cmd-list.made: cmd-list.perl $(MAN1_TXT)
perl ./cmd-list.perl
date >$@
git.7 git.html: git.txt core-intro.txt
clean:
rm -f *.xml *.xml+ *.html *.html+ *.1 *.7 howto-index.txt howto/*.html doc.dep
rm -f $(cmds_txt)
rm -f $(cmds_txt) *.made
%.html : %.txt
rm -f $@+ $@

View File

@@ -0,0 +1,61 @@
GIT v1.5.1.1 Release Notes
==========================
Fixes since v1.5.1
------------------
* Documentation updates
- The --left-right option of rev-list and friends is documented.
- The documentation for cvsimport has been majorly improved.
- "git-show-ref --exclude-existing" was documented.
* Bugfixes
- The implementation of -p option in "git cvsexportcommit" had
the meaning of -C (context reduction) option wrong, and
loosened the context requirements when it was told to be
strict.
- "git cvsserver" did not behave like the real cvsserver when
client side removed a file from the working tree without
doing anything else on the path. In such a case, it should
restore it from the checked out revision.
- "git fsck" issued an alarming error message on detached
HEAD. It is not an error since at least 1.5.0.
- "git send-email" produced of References header of unbounded length;
fixed this with line-folding.
- "git archive" to download from remote site should not
require you to be in a git repository, but it incorrectly
did.
- "git apply" ignored -p<n> for "diff --git" formatted
patches.
- "git rerere" recorded a conflict that had one side empty
(the other side adds) incorrectly; this made merging in the
other direction fail to use previously recorded resolution.
- t4200 test was broken where "wc -l" pads its output with
spaces.
- "git branch -m old new" to rename branch did not work
without a configuration file in ".git/config".
- The sample hook for notification e-mail was misnamed.
- gitweb did not show type-changing patch correctly in the
blobdiff view.
- git-svn did not error out with incorrect command line options.
- git-svn fell into an infinite loop when insanely long commit
message was found.
- git-svn dcommit and rebase was confused by patches that were
merged from another branch that is managed by git-svn.

View File

@@ -0,0 +1,76 @@
GIT v1.5.2 Release Notes (draft)
========================
Updates since v1.5.1
--------------------
* New commands and options.
- "git bisect start" can optionally take a single bad commit and
zero or more good commits on the command line.
* Updated behavior of existing commands.
- "git diff --stat" shows size of preimage and postimage blobs
for binary contents. Earlier it only said "Bin".
- "git lost-found" shows stuff that are unreachable except
from reflogs.
- "git checkout branch^0" now detaches HEAD at the tip commit
on the named branch, instead of just switching to the
branch (use "git checkout branch" to switch to the branch,
as before).
- "git bisect next" can be used after giving only a bad commit
without giving a good one (this starts bisection half-way to
the root commit). We used to refuse to operate without a
good and a bad commit.
* Builds
- git-p4import has never been installed; now there is an
installation option to do so.
- gitk and git-gui can be configured out.
- Generated documentation pages automatically get version
information from GIT_VERSION
- Parallel build with "make -j" descending into subdirectory
was fixed.
* Performance Tweaks
- optimized "git-rev-list --bisect" (hence "git-bisect").
- optimized "git-add $path" in a large directory, most of
whose contents are ignored.
Fixes since v1.5.1
------------------
The following are all in v1.5.1.x series, unless otherwise noted.
* Documentation updates
* Bugfixes
- Switching branches with "git checkout" refused to work when
a path changes from a file to a directory between the
current branch and the new branch, in order not to lose
possible local changes in the directory that is being turned
into a file with the switch. We now allow such a branch
switch after making sure that there is no locally modified
file nor un-ignored file in the directory. This has not
been backported to 1.5.1.x series, as it is rather an
intrusive change.
* Performance Tweaks
--
exec >/var/tmp/1
O=v1.5.1-91-g640ee0d
echo O=`git describe refs/heads/master`
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint

View File

@@ -22,6 +22,9 @@ Checklist (and a short version for the impatient):
- provide additional information (which is unsuitable for
the commit message) between the "---" and the diffstat
- send the patch to the list _and_ the maintainer
- if you change, add, or remove a command line option or
make some other user interface change, the associated
documentation should be updated as well.
Long version:

View File

@@ -0,0 +1,67 @@
-b::
Show blank SHA-1 for boundary commits. This can also
be controlled via the `blame.blankboundary` config option.
--root::
Do not treat root commits as boundaries. This can also be
controlled via the `blame.showroot` config option.
--show-stats::
Include additional statistics at the end of blame output.
-L n,m::
Annotate only the specified line range (lines count from 1).
-l::
Show long rev (Default: off).
-t::
Show raw timestamp (Default: off).
-S <revs-file>::
Use revs from revs-file instead of calling gitlink:git-rev-list[1].
-p, --porcelain::
Show in a format designed for machine consumption.
--incremental::
Show the result incrementally in a format designed for
machine consumption.
--contents <file>::
When <rev> is not specified, the command annotates the
changes starting backwards from the working tree copy.
This flag makes the command pretend as if the working
tree copy has the contents of he named file (specify
`-` to make the command read from the standard input).
-M|<num>|::
Detect moving lines in the file as well. When a commit
moves a block of lines in a file (e.g. the original file
has A and then B, and the commit changes it to B and
then A), traditional 'blame' algorithm typically blames
the lines that were moved up (i.e. B) to the parent and
assigns blame to the lines that were moved down (i.e. A)
to the child commit. With this option, both groups of lines
are blamed on the parent.
<num> is optional but it is the lower bound on the number of
alphanumeric characters that git must detect as moving
within a file for it to associate those lines with the parent
commit.
-C|<num>|::
In addition to `-M`, detect lines copied from other
files that were modified in the same commit. This is
useful when you reorganize your program and move code
around across files. When this option is given twice,
the command looks for copies from all other files in the
parent for the commit that creates the file in addition.
<num> is optional but it is the lower bound on the number of
alphanumeric characters that git must detect as moving
between files for it to associate those lines with the parent
commit.
-h, --help::
Show help message.

View File

@@ -1,8 +1,11 @@
#
#!/usr/bin/perl -w
use File::Compare qw(compare);
sub format_one {
my ($out, $name) = @_;
my ($state, $description);
$state = 0;
open I, '<', "$name.txt" or die "No such file $name.txt";
while (<I>) {
if (/^NAME$/) {
@@ -55,7 +58,14 @@ for my $cat (qw(ancillaryinterrogators
format_one(\*O, $_);
}
close O;
rename "$out+", "$out";
if (-f "$out" && compare("$out", "$out+") == 0) {
unlink "$out+";
}
else {
print STDERR "$out\n";
rename "$out+", "$out";
}
}
__DATA__

View File

@@ -117,6 +117,16 @@ core.fileMode::
the working copy are ignored; useful on broken filesystems like FAT.
See gitlink:git-update-index[1]. True by default.
core.autocrlf::
If true, makes git convert `CRLF` at the end of lines in text files to
`LF` when reading from the filesystem, and convert in reverse when
writing to the filesystem. The variable can be set to
'input', in which case the conversion happens only while
reading from the filesystem but files are written out with
`LF` at the end of lines. Currently, which paths to consider
"text" (i.e. be subjected to the autocrlf mechanism) is
decided purely based on the contents.
core.symlinks::
If false, symbolic links are checked out as small plain files that
contain the link text. gitlink:git-update-index[1] and
@@ -401,13 +411,20 @@ gc.rerereunresolved::
The default is 15 days. See gitlink:git-rerere[1].
gitcvs.enabled::
Whether the cvs pserver interface is enabled for this repository.
Whether the cvs server interface is enabled for this repository.
See gitlink:git-cvsserver[1].
gitcvs.logfile::
Path to a log file where the cvs pserver interface well... logs
Path to a log file where the cvs server interface well... logs
various stuff. See gitlink:git-cvsserver[1].
gitcvs.allbinary::
If true, all files are sent to the client in mode '-kb'. This
causes the client to treat all files as binary files which suppresses
any newline munging it otherwise might do. A work-around for the
fact that there is no way yet to set single files to mode '-kb'.
See gitlink:git-cvsserver[1].
http.sslVerify::
Whether to verify the SSL certificate when fetching or pushing
over HTTPS. Can be overridden by the 'GIT_SSL_NO_VERIFY' environment
@@ -445,7 +462,7 @@ http.lowSpeedLimit, http.lowSpeedTime::
http.noEPSV::
A boolean which disables using of EPSV ftp command by curl.
This can helpful with some "poor" ftp servers which doesn't
This can helpful with some "poor" ftp servers which don't
support EPSV mode. Can be overridden by the 'GIT_CURL_FTP_NO_EPSV'
environment variable. Default is false (curl will use EPSV).

View File

@@ -26,18 +26,18 @@ OPTIONS
The list of mailbox files to read patches from. If you do not
supply this argument, reads from the standard input.
--signoff::
-s, --signoff::
Add `Signed-off-by:` line to the commit message, using
the committer identity of yourself.
--dotest=<dir>::
-d=<dir>, --dotest=<dir>::
Instead of `.dotest` directory, use <dir> as a working
area to store extracted patches.
--keep::
-k, --keep::
Pass `-k` flag to `git-mailinfo` (see gitlink:git-mailinfo[1]).
--utf8::
-u, --utf8::
Pass `-u` flag to `git-mailinfo` (see gitlink:git-mailinfo[1]).
The proposed commit log message taken from the e-mail
are re-coded into UTF-8 encoding (configuration variable
@@ -48,14 +48,14 @@ This was optional in prior versions of git, but now it is the
default. You could use `--no-utf8` to override this.
--no-utf8::
Do not pass `-u` flag to `git-mailinfo` (see
Pass `-n` flag to `git-mailinfo` (see
gitlink:git-mailinfo[1]).
--binary::
-b, --binary::
Pass `--allow-binary-replacement` flag to `git-apply`
(see gitlink:git-apply[1]).
--3way::
-3, --3way::
When the patch does not apply cleanly, fall back on
3-way merge, if the patch records the identity of blobs
it is supposed to apply to, and we have those blobs
@@ -73,10 +73,10 @@ default. You could use `--no-utf8` to override this.
These flags are passed to the `git-apply` program that applies
the patch.
--interactive::
-i, --interactive::
Run interactively, just like git-applymbox.
--resolved::
-r, --resolved::
After a patch failure (e.g. attempting to apply
conflicting patch), the user has applied it by hand and
the index file stores the result of the application.
@@ -84,6 +84,13 @@ default. You could use `--no-utf8` to override this.
extracted from the e-mail message and the current index
file, and continue.
--resolvemsg=<msg>::
When a patch failure occurs, <msg> will be printed
to the screen before exiting. This overrides the
standard message informing you to use `--resolved`
or `--skip` to handle the failure. This is solely
for internal use between `git-rebase` and `git-am`.
DISCUSSION
----------

View File

@@ -16,20 +16,7 @@ which introduced the line. Optionally annotate from a given revision.
OPTIONS
-------
-l, --long::
Show long rev (Defaults off).
-t, --time::
Show raw timestamp (Defaults off).
-r, --rename::
Follow renames (Defaults on).
-S, --rev-file <revs-file>::
Use revs from revs-file instead of calling git-rev-list.
-h, --help::
Show help message.
include::blame-options.txt[]
SEE ALSO
--------

View File

@@ -9,11 +9,12 @@ git-apply - Apply a patch on a git index file and a working tree
SYNOPSIS
--------
[verse]
'git-apply' [--stat] [--numstat] [--summary] [--check] [--index] [--apply]
[--no-add] [--index-info] [--allow-binary-replacement | --binary]
[-R | --reverse] [--reject] [-z] [-pNUM] [-CNUM] [--inaccurate-eof]
[--whitespace=<nowarn|warn|error|error-all|strip>] [--exclude=PATH]
[--cached] [--verbose] [<patch>...]
'git-apply' [--stat] [--numstat] [--summary] [--check] [--index]
[--apply] [--no-add] [--index-info] [-R | --reverse]
[--allow-binary-replacement | --binary] [--reject] [-z]
[-pNUM] [-CNUM] [--inaccurate-eof] [--cached]
[--whitespace=<nowarn|warn|error|error-all|strip>]
[--exclude=PATH] [--verbose] [<patch>...]
DESCRIPTION
-----------
@@ -158,7 +159,7 @@ discouraged.
correctly. This option adds support for applying such patches by
working around this bug.
--verbose::
-v, --verbose::
Report progress to stderr. By default, only a message about the
current patch being applied will be printed. This option will cause
additional information to be reported.

View File

@@ -42,14 +42,20 @@ OPTIONS
and the current tree.
-u::
The commit log message, author name and author email are
taken from the e-mail, and after minimally decoding MIME
transfer encoding, re-coded in UTF-8 by transliterating
them. This used to be optional but now it is the default.
Pass `-u` flag to `git-mailinfo` (see gitlink:git-mailinfo[1]).
The proposed commit log message taken from the e-mail
are re-coded into UTF-8 encoding (configuration variable
`i18n.commitencoding` can be used to specify project's
preferred encoding if it is not UTF-8). This used to be
optional but now it is the default.
+
Note that the patch is always used as-is without charset
conversion, even with this flag.
-n::
Pass `-n` flag to `git-mailinfo` (see
gitlink:git-mailinfo[1]).
-c .dotest/<num>::
When the patch contained in an e-mail does not cleanly
apply, the command exits with an error message. The

View File

@@ -30,7 +30,8 @@ OPTIONS
-------
--format=<fmt>::
Format of the resulting archive: 'tar', 'zip'...
Format of the resulting archive: 'tar', 'zip'... The default
is 'tar'.
--list::
Show all available formats.

View File

@@ -15,7 +15,7 @@ DESCRIPTION
The command takes various subcommands, and different options depending
on the subcommand:
git bisect start [<paths>...]
git bisect start [<bad> [<good>...]] [--] [<paths>...]
git bisect bad <rev>
git bisect good <rev>
git bisect reset [<branch>]
@@ -134,15 +134,26 @@ $ git reset --hard HEAD~3 # try 3 revs before what
Then compile and test the one you chose to try. After that, tell
bisect what the result was as usual.
Cutting down bisection by giving path parameter to bisect start
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Cutting down bisection by giving more parameters to bisect start
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can further cut down the number of trials if you know what part of
the tree is involved in the problem you are tracking down, by giving
paths parameters when you say `bisect start`, like this:
------------
$ git bisect start arch/i386 include/asm-i386
$ git bisect start -- arch/i386 include/asm-i386
------------
If you know beforehand more than one good commits, you can narrow the
bisect space down without doing the whole tree checkout every time you
give good commits. You give the bad revision immediately after `start`
and then you give all the good revisions you have:
------------
$ git bisect start v2.6.20-rc6 v2.6.20-rc4 v2.6.20-rc1 --
# v2.6.20-rc6 is bad
# v2.6.20-rc4 and v2.6.20-rc1 are good
------------
Bisect run

View File

@@ -8,8 +8,9 @@ git-blame - Show what revision and author last modified each line of a file
SYNOPSIS
--------
[verse]
'git-blame' [-c] [-l] [-t] [-f] [-n] [-p] [--incremental] [-L n,m] [-S <revs-file>]
[-M] [-C] [-C] [--since=<date>] [<rev> | --contents <file>] [--] <file>
'git-blame' [-c] [-l] [-t] [-f] [-n] [-p] [--incremental] [-L n,m]
[-S <revs-file>] [-M] [-C] [-C] [--since=<date>]
[<rev> | --contents <file>] [--] <file>
DESCRIPTION
-----------
@@ -37,20 +38,19 @@ ea4c7f9bf69e781dd0cd88d2bccb2bf5cc15c9a7 git-blame: Make the output
OPTIONS
-------
-c, --compatibility::
include::blame-options.txt[]
-c::
Use the same output mode as gitlink:git-annotate[1] (Default: off).
-L n,m::
Annotate only the specified line range (lines count from 1).
-l, --long::
Show long rev (Default: off).
-t, --time::
Show raw timestamp (Default: off).
-S, --rev-file <revs-file>::
Use revs from revs-file instead of calling gitlink:git-rev-list[1].
--score-debug::
Include debugging information related to the movement of
lines between files (see `-C`) and lines moved within a
file (see `-M`). The first number listed is the score.
This is the number of alphanumeric characters detected
to be moved between or within files. This must be above
a certain threshold for git-blame to consider those lines
of code to have been moved.
-f, --show-name::
Show filename in the original commit. By default
@@ -60,42 +60,6 @@ OPTIONS
-n, --show-number::
Show line number in the original commit (Default: off).
-p, --porcelain::
Show in a format designed for machine consumption.
--incremental::
Show the result incrementally in a format designed for
machine consumption.
--contents <file>::
When <rev> is not specified, the command annotates the
changes starting backwards from the working tree copy.
This flag makes the command pretend as if the working
tree copy has the contents of he named file (specify
`-` to make the command read from the standard input).
-M::
Detect moving lines in the file as well. When a commit
moves a block of lines in a file (e.g. the original file
has A and then B, and the commit changes it to B and
then A), traditional 'blame' algorithm typically blames
the lines that were moved up (i.e. B) to the parent and
assigns blame to the lines that were moved down (i.e. A)
to the child commit. With this option, both groups of
lines are blamed on the parent.
-C::
In addition to `-M`, detect lines copied from other
files that were modified in the same commit. This is
useful when you reorganize your program and move code
around across files. When this option is given twice,
the command looks for copies from all other files in the
parent for the commit that creates the file in addition.
-h, --help::
Show help message.
THE PORCELAIN FORMAT
--------------------

View File

@@ -23,9 +23,9 @@ 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
the index file (i.e. it runs `git-checkout-index -f -u`), or a
named commit. In
this case, `-f` and `-b` options are meaningless and giving
the index file (i.e. it runs `git-checkout-index -f -u`), or
from a named commit. In
this case, the `-f` and `-b` options are meaningless and giving
either of them results in an error. <tree-ish> argument can be
used to specify a specific tree-ish (i.e. commit, tag or tree)
to update the index for the given paths before updating the
@@ -38,7 +38,8 @@ OPTIONS
Quiet, supress feedback messages.
-f::
Force a re-read of everything.
Proceed even if the index or the working tree differs
from HEAD. This is used to throw away local changes.
-b::
Create a new branch named <new_branch> and start it at
@@ -48,13 +49,17 @@ OPTIONS
--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.
set up configuration so that git-pull will automatically
retrieve data from the remote branch. Set the
branch.autosetupmerge configuration variable to true if you
want git-checkout and git-branch to always behave as if
'--track' were given.
--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.
set up configuration so that git-pull will not retrieve data
from the remote branch, ignoring the branch.autosetupmerge
configuration variable.
-l::
Create the new branch's ref log. This activates recording of

View File

@@ -9,9 +9,11 @@ git-cvsimport - Salvage your data out of another SCM people love to hate
SYNOPSIS
--------
[verse]
'git-cvsimport' [-o <branch-for-HEAD>] [-h] [-v] [-d <CVSROOT>] [-s <subst>]
[-p <options-for-cvsps>] [-C <git_repository>] [-i] [-P <file>]
[-m] [-M regex] [<CVS_module>]
'git-cvsimport' [-o <branch-for-HEAD>] [-h] [-v] [-d <CVSROOT>]
[-A <author-conv-file>] [-p <options-for-cvsps>] [-P <file>]
[-C <git_repository>] [-z <fuzz>] [-i] [-k] [-u] [-s <subst>]
[-a] [-m] [-M <regex>] [-S <regex>] [-L <commitlimit>]
[<CVS_module>]
DESCRIPTION
@@ -30,28 +32,25 @@ any CVS branches, yourself.
OPTIONS
-------
-v::
Verbosity: let 'cvsimport' report what it is doing.
-d <CVSROOT>::
The root of the CVS archive. May be local (a simple path) or remote;
currently, only the :local:, :ext: and :pserver: access methods
are supported.
are supported. If not given, git-cvsimport will try to read it
from `CVS/Root`. If no such file exists, it checks for the
`CVSROOT` environment variable.
<CVS_module>::
The CVS module you want to import. Relative to <CVSROOT>.
If not given, git-cvsimport tries to read it from
`CVS/Repository`.
-C <target-dir>::
The git repository to import to. If the directory doesn't
exist, it will be created. Default is the current directory.
-i::
Import-only: don't perform a checkout after importing. This option
ensures the working directory and index remain untouched and will
not create them if they do not exist.
-k::
Kill keywords: will extract files with -kk from the CVS archive
to avoid noisy changesets. Highly recommended, but off by default
to preserve compatibility with early imported trees.
-u::
Convert underscores in tag and branch names to dots.
-o <branch-for-HEAD>::
The 'HEAD' branch from CVS is imported to the 'origin' branch within
the git repository, as 'HEAD' already has a special meaning for git.
@@ -60,12 +59,32 @@ OPTIONS
Use '-o master' for continuing an import that was initially done by
the old cvs2git tool.
-i::
Import-only: don't perform a checkout after importing. This option
ensures the working directory and index remain untouched and will
not create them if they do not exist.
-k::
Kill keywords: will extract files with '-kk' from the CVS archive
to avoid noisy changesets. Highly recommended, but off by default
to preserve compatibility with early imported trees.
-u::
Convert underscores in tag and branch names to dots.
-s <subst>::
Substitute the character "/" in branch names with <subst>
-p <options-for-cvsps>::
Additional options for cvsps.
The options '-u' and '-A' are implicit and should not be used here.
+
If you need to pass multiple options, separate them with a comma.
-z <fuzz>::
Pass the timestamp fuzz factor to cvsps, in seconds. If unset,
cvsps defaults to 300s.
-P <cvsps-output-file>::
Instead of calling cvsps, read the provided cvsps output file. Useful
for debugging or when cvsps is being handled outside cvsimport.
@@ -77,32 +96,16 @@ If you need to pass multiple options, separate them with a comma.
-M <regex>::
Attempt to detect merges based on the commit message with a custom
regex. It can be used with -m to also see the default regexes.
regex. It can be used with '-m' to also see the default regexes.
You must escape forward slashes.
-v::
Verbosity: let 'cvsimport' report what it is doing.
<CVS_module>::
The CVS module you want to import. Relative to <CVSROOT>.
-h::
Print a short usage message and exit.
-z <fuzz>::
Pass the timestamp fuzz factor to cvsps, in seconds. If unset,
cvsps defaults to 300s.
-s <subst>::
Substitute the character "/" in branch names with <subst>
-S <regex>::
Skip paths matching the regex.
-a::
Import all commits, including recent ones. cvsimport by default
skips commits that have a timestamp less than 10 minutes ago.
-S <regex>::
Skip paths matching the regex.
-L <limit>::
Limit the number of commits imported. Workaround for cases where
cvsimport leaks memory.
@@ -122,14 +125,17 @@ git-cvsimport will make it appear as those authors had
their GIT_AUTHOR_NAME and GIT_AUTHOR_EMAIL set properly
all along.
+
For convenience, this data is saved to $GIT_DIR/cvs-authors
each time the -A option is provided and read from that same
For convenience, this data is saved to `$GIT_DIR/cvs-authors`
each time the '-A' option is provided and read from that same
file each time git-cvsimport is run.
+
It is not recommended to use this feature if you intend to
export changes back to CVS again later with
gitlink:git-cvsexportcommit[1].
-h::
Print a short usage message and exit.
OUTPUT
------
If '-v' is specified, the script reports what it is doing.

View File

@@ -110,12 +110,12 @@ To get a checkout with the Eclipse CVS client:
Protocol notes: If you are using anonymous access via pserver, just select that.
Those using SSH access should choose the 'ext' protocol, and configure 'ext'
access on the Preferences->Team->CVS->ExtConnection pane. Set CVS_SERVER to
'git-cvsserver'. Not that password support is not good when using 'ext',
'git-cvsserver'. Note that password support is not good when using 'ext',
you will definitely want to have SSH keys setup.
Alternatively, you can just use the non-standard extssh protocol that Eclipse
offer. In that case CVS_SERVER is ignored, and you will have to replace
the cvs utility on the server with git-cvsserver or manipulate your .bashrc
the cvs utility on the server with git-cvsserver or manipulate your `.bashrc`
so that calling 'cvs' effectively calls git-cvsserver.
Clients known to work
@@ -134,9 +134,9 @@ checkout, diff, status, update, log, add, remove, commit.
Legacy monitoring operations are not supported (edit, watch and related).
Exports and tagging (tags and branches) are not supported at this stage.
The server should set the -k mode to binary when relevant, however,
The server should set the '-k' mode to binary when relevant, however,
this is not really implemented yet. For now, you can force the server
to set `-kb` for all files by setting the `gitcvs.allbinary` config
to set '-kb' for all files by setting the `gitcvs.allbinary` config
variable. In proper GIT tradition, the contents of the files are
always respected. No keyword expansion or newline munging is supported.

View File

@@ -10,11 +10,12 @@ SYNOPSIS
--------
[verse]
'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>]
[--attach[=<boundary>] | --inline[=<boundary>]]
[-s | --signoff] [<common diff options>] [--start-number <n>]
[--in-reply-to=Message-Id] [--suffix=.<sfx>]
[--ignore-if-in-upstream]
[--subject-prefix=Subject-Prefix]
<since>[..<until>]
DESCRIPTION
-----------
@@ -98,6 +99,12 @@ include::diff-options.txt[]
patches being generated, and any patch that matches is
ignored.
--subject-prefix=<Subject-Prefix>::
Instead of the standard '[PATCH]' prefix in the subject
line, instead use '[<Subject-Prefix>]'. This
allows for useful naming of a patch series, and can be
combined with the --numbered option.
--suffix=.<sfx>::
Instead of using `.patch` as the suffix for generated
filenames, use specifed suffix. A common alternative is

View File

@@ -46,6 +46,11 @@ include::pretty-formats.txt[]
-p::
Show the change the commit introduces in a patch form.
-g, \--walk-reflogs::
Show commits as they were recorded in the reflog. The log contains
a record about how the tip of a reference was changed.
See also gitlink:git-reflog[1].
<paths>...::
Show only commits that affect the specified paths.

View File

@@ -12,23 +12,22 @@ SYNOPSIS
DESCRIPTION
-----------
Finds dangling commits and tags from the object database, and
creates refs to them in .git/lost-found/ directory. Commits and
tags that dereference to commits go to .git/lost-found/commit
and others are stored in .git/lost-found/other directory.
creates refs to them in the .git/lost-found/ directory. Commits and
tags that dereference to commits are stored in .git/lost-found/commit,
and other objects are stored in .git/lost-found/other.
OUTPUT
------
One line description from the commit and tag found along with
their object name are printed on the standard output.
Prints to standard output the object names and one-line descriptions
of any commits or tags found.
EXAMPLE
-------
Suppose you run 'git tag -f' and mistyped the tag to overwrite.
Suppose you run 'git tag -f' and mistype the tag to overwrite.
The ref to your tag is overwritten, but until you run 'git
prune', it is still there.
prune', the tag itself is still there.
------------
$ git lost-found
@@ -36,15 +35,15 @@ $ git lost-found
...
------------
Also you can use gitk to browse how they relate to each other
and existing (probably old) tags.
Also you can use gitk to browse how any tags found relate to each
other.
------------
$ gitk $(cd .git/lost-found/commit && echo ??*)
------------
After making sure that it is the object you are looking for, you
can reconnect it to your regular .git/refs hierarchy.
After making sure you know which the object is the tag you are looking
for, you can reconnect it to your regular .git/refs hierarchy.
------------
$ git cat-file -t 1ef2b196

View File

@@ -8,7 +8,7 @@ git-read-tree - Reads tree information into the index
SYNOPSIS
--------
'git-read-tree' (<tree-ish> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] <tree-ish1> [<tree-ish2> [<tree-ish3>]])
'git-read-tree' (<tree-ish> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <tree-ish1> [<tree-ish2> [<tree-ish3>]])
DESCRIPTION
@@ -86,6 +86,18 @@ OPTIONS
file (usually '.gitignore') and allows such an untracked
but explicitly ignored file to be overwritten.
--index-output=<file>::
Instead of writing the results out to `$GIT_INDEX_FILE`,
write the resulting index in the named file. While the
command is operating, the original index file is locked
with the same mechanism as usual. The file must allow
to be rename(2)ed into from a temporary file that is
created next to the usual index file; typically this
means it needs to be on the same filesystem as the index
file itself, and you need write permission to the
directories the index file and index output file are
located in.
<tree-ish#>::
The id of the tree object(s) to be read/merged.

View File

@@ -22,6 +22,7 @@ SYNOPSIS
[ \--topo-order ]
[ \--parents ]
[ \--left-right ]
[ \--cherry-pick ]
[ \--encoding[=<encoding>] ]
[ \--(author|committer|grep)=<pattern> ]
[ [\--objects | \--objects-edge] [ \--unpacked ] ]
@@ -224,6 +225,20 @@ limiting may be applied.
In addition to the '<commit>' listed on the command
line, read them from the standard input.
--cherry-pick::
Omit any commit that introduces the same change as
another commit on the "other side" when the set of
commits are limited with symmetric difference.
+
For example, if you have two branches, `A` and `B`, a usual way
to list all commits on only one side of them is with
`--left-right`, like the example above in the description of
that option. It however shows the commits that were cherry-picked
from the other branch (for example, "3rd on b" may be cherry-picked
from branch A). With this option, such pairs of commits are
excluded from the output.
-g, --walk-reflogs::
Instead of walking the commit ancestry chain, walk

View File

@@ -47,6 +47,10 @@ OPTIONS
the paths only from the index, leaving working tree
files.
\--quiet::
git-rm normally outputs one line (in the form of an "rm" command)
for each file removed. This option suppresses that output.
DISCUSSION
----------

View File

@@ -10,6 +10,7 @@ SYNOPSIS
[verse]
'git-show-ref' [-q|--quiet] [--verify] [-h|--head] [-d|--dereference]
[-s|--hash] [--abbrev] [--tags] [--heads] [--] <pattern>...
'git-show-ref' --exclude-existing[=pattern]
DESCRIPTION
-----------
@@ -19,6 +20,9 @@ commit IDs. Results can be filtered using a pattern and tags can be
dereferenced into object IDs. Additionally, it can be used to test whether a
particular ref exists.
The --exclude-existing form is a filter that does the inverse, it shows the
refs from stdin that don't exist in the local repository.
Use of this utility is encouraged in favor of directly accessing files under
in the `.git` directory.
@@ -61,6 +65,18 @@ OPTIONS
Do not print any results to stdout. When combined with '--verify' this
can be used to silently check if a reference exists.
--exclude-existing, --exclude-existing=pattern::
Make git-show-ref act as a filter that reads refs from stdin of the
form "^(?:<anything>\s)?<refname>(?:\^\{\})?$" and performs the
following actions on each:
(1) strip "^{}" at the end of line if any;
(2) ignore if pattern is provided and does not head-match refname;
(3) warn if refname is not a well-formed refname and skip;
(4) ignore if refname is a ref that exists in the local repository;
(5) otherwise output the line.
<pattern>::
Show references matching one or more patterns.

View File

@@ -117,6 +117,7 @@ The placeholders are:
- '%Cgreen': switch color to green
- '%Cblue': switch color to blue
- '%Creset': reset color
- '%m': left, right or boundary mark
- '%n': newline

View File

@@ -298,9 +298,9 @@ $ git branch
* master
------------------------------------------------
A freshly cloned repository contains a single branch head, named
"master", and working directory is initialized to the state of
the project referred to by "master".
A freshly cloned repository contains a single branch head, by default
named "master", with the working directory initialized to the state of
the project referred to by that branch head.
Most projects also use <<def_tag,tags>>. Tags, like heads, are
references into the project's history, and can be listed using the
@@ -495,8 +495,49 @@ git checkout -b <new> <start-point>::
create a new branch <new> referencing <start-point>, and
check it out.
It is also useful to know that the special symbol "HEAD" can always
be used to refer to the current branch.
The special symbol "HEAD" can always be used to refer to the current
branch. In fact, git uses a file named "HEAD" in the .git directory to
remember which branch is current:
------------------------------------------------
$ cat .git/HEAD
ref: refs/heads/master
------------------------------------------------
[[detached-head]]
Examining an old version without creating a new branch
------------------------------------------------------
The git-checkout command normally expects a branch head, but will also
accept an arbitrary commit; for example, you can check out the commit
referenced by a tag:
------------------------------------------------
$ git checkout v2.6.17
Note: moving to "v2.6.17" which isn't a local branch
If you want to create a new branch from this checkout, you may do so
(now or later) by using -b with the checkout command again. Example:
git checkout -b <new_branch_name>
HEAD is now at 427abfa... Linux v2.6.17
------------------------------------------------
The HEAD then refers to the SHA1 of the commit instead of to a branch,
and git branch shows that you are no longer on a branch:
------------------------------------------------
$ cat .git/HEAD
427abfa28afedffadfca9dd8b067eb6d36bac53f
git branch
* (no branch)
master
------------------------------------------------
In this case we say that the HEAD is "detached".
This can be an easy way to check out a particular version without having
to make up a name for a new branch. However, keep in mind that when you
switch away from the (for example, by checking out something else), you
can lose track of what the HEAD used to point to.
Examining branches from a remote repository
-------------------------------------------
@@ -1015,7 +1056,7 @@ $ git commit
-------------------------------------------------
[[how-to-make-a-commit]]
how to make a commit
How to make a commit
--------------------
Creating a new commit takes three steps:
@@ -1109,7 +1150,7 @@ $ git diff # difference between the index file and your
$ git status # a brief per-file summary of the above.
-------------------------------------------------
creating good commit messages
Creating good commit messages
-----------------------------
Though not required, it's a good idea to begin the commit message
@@ -1119,7 +1160,7 @@ description. Tools that turn commits into email, for example, use
the first line on the Subject line and the rest of the commit in the
body.
how to merge
How to merge
------------
You can rejoin two diverging branches of development using
@@ -1298,7 +1339,7 @@ the different stages of that file will be "collapsed", after which
git-diff will (by default) no longer show diffs for that file.
[[undoing-a-merge]]
undoing a merge
Undoing a merge
---------------
If you get stuck and decide to just give up and throw the whole mess
@@ -2015,22 +2056,22 @@ $ git tag bad mywork~5
(Either gitk or git-log may be useful for finding the commit.)
Then check out a new branch at that commit, edit it, and rebase the rest of
the series on top of it:
Then check out that commit, edit it, and rebase the rest of the series
on top of it (note that we could check out the commit on a temporary
branch, but instead we're using a <<detached-head,detached head>>):
-------------------------------------------------
$ git checkout -b TMP bad
$ git checkout bad
$ # make changes here and update the index
$ git commit --amend
$ git rebase --onto TMP bad mywork
$ git rebase --onto HEAD bad mywork
-------------------------------------------------
When you're done, you'll be left with mywork checked out, with the top patches
on mywork reapplied on top of the modified commit you created in TMP. You can
When you're done, you'll be left with mywork checked out, with the top
patches on mywork reapplied on top of your modified commit. You can
then clean up with
-------------------------------------------------
$ git branch -d TMP
$ git tag -d bad
-------------------------------------------------
@@ -2275,8 +2316,8 @@ options mentioned above.
Git internals
=============
There are two object abstractions: the "object database", and the
"current directory cache" aka "index".
Git depends on two fundamental abstractions: the "object database", and
the "current directory cache" aka "index".
The Object Database
-------------------
@@ -2291,22 +2332,23 @@ All objects have a statically determined "type" aka "tag", which is
determined at object creation time, and which identifies the format of
the object (i.e. how it is used, and how it can refer to other
objects). There are currently four different object types: "blob",
"tree", "commit" and "tag".
"tree", "commit", and "tag".
A "blob" object cannot refer to any other object, and is, like the type
implies, a pure storage object containing some user data. It is used to
actually store the file data, i.e. a blob object is associated with some
particular version of some file.
A <<def_blob_object,"blob" object>> cannot refer to any other object,
and is, as the name implies, a pure storage object containing some
user data. It is used to actually store the file data, i.e. a blob
object is associated with some particular version of some file.
A "tree" object is an object that ties one or more "blob" objects into a
directory structure. In addition, a tree object can refer to other tree
objects, thus creating a directory hierarchy.
A <<def_tree_object,"tree" object>> is an object that ties one or more
"blob" objects into a directory structure. In addition, a tree object
can refer to other tree objects, thus creating a directory hierarchy.
A "commit" object ties such directory hierarchies together into
a DAG of revisions - each "commit" is associated with exactly one tree
(the directory hierarchy at the time of the commit). In addition, a
"commit" refers to one or more "parent" commit objects that describe the
history of how we arrived at that directory hierarchy.
A <<def_commit_object,"commit" object>> ties such directory hierarchies
together into a <<def_DAG,directed acyclic graph>> of revisions - each
"commit" is associated with exactly one tree (the directory hierarchy at
the time of the commit). In addition, a "commit" refers to one or more
"parent" commit objects that describe the history of how we arrived at
that directory hierarchy.
As a special case, a commit object with no parents is called the "root"
object, and is the point of an initial project commit. Each project
@@ -2316,9 +2358,10 @@ has two or more separate roots as its ultimate parents, that's probably
just going to confuse people. So aim for the notion of "one root object
per project", even if git itself does not enforce that.
A "tag" object symbolically identifies and can be used to sign other
objects. It contains the identifier and type of another object, a
symbolic name (of course!) and, optionally, a signature.
A <<def_tag_object,"tag" object>> symbolically identifies and can be
used to sign other objects. It contains the identifier and type of
another object, a symbolic name (of course!) and, optionally, a
signature.
Regardless of object type, all objects share the following
characteristics: they are all deflated with zlib, and have a header

View File

@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
DEF_VER=v1.5.1.GIT
DEF_VER=v1.5.1.1.GIT
LF='
'

View File

@@ -250,6 +250,8 @@ BUILT_INS = \
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
ALL_PROGRAMS += git-merge-subtree$X
# what 'all' will build but not install in gitexecdir
OTHER_PROGRAMS = git$X gitweb/gitweb.cgi
ifndef NO_TCLTK
@@ -280,7 +282,8 @@ LIB_H = \
diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \
run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \
spawn-pipe.h utf8.h reflog-walk.h
spawn-pipe.h \
utf8.h reflog-walk.h patch-ids.h
DIFF_OBJS = \
diff.o diff-lib.o diffcore-break.o diffcore-order.o \
@@ -293,13 +296,14 @@ LIB_OBJS = \
interpolate.o \
lockfile.o \
spawn-pipe.o \
patch-ids.o \
object.o pack-check.o patch-delta.o path.o pkt-line.o sideband.o \
reachable.o reflog-walk.o \
quote.o read-cache.o refs.o run-command.o dir.o object-refs.o \
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
revision.o pager.o tree-walk.o xdiff-interface.o \
write_or_die.o trace.o list-objects.o grep.o \
write_or_die.o trace.o list-objects.o grep.o match-trees.o \
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
convert.o
@@ -385,6 +389,7 @@ endif
ifeq ($(uname_S),Darwin)
NEEDS_SSL_WITH_CRYPTO = YesPlease
NEEDS_LIBICONV = YesPlease
OLD_ICONV = UnfortunatelyYes
NO_STRLCPY = YesPlease
endif
ifeq ($(uname_S),SunOS)
@@ -668,7 +673,7 @@ ifeq ($(TCLTK_PATH),)
NO_TCLTK=NoThanks
endif
QUIET_SUBDIR0 = $(MAKE) -C # space to separate -C and subdir
QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
QUIET_SUBDIR1 =
ifneq ($(findstring $(MAKEFLAGS),w),w)
@@ -684,7 +689,7 @@ ifndef V
QUIET_LINK = @echo ' ' LINK $@;
QUIET_BUILT_IN = @echo ' ' BUILTIN $@;
QUIET_GEN = @echo ' ' GEN $@;
QUIET_SUBDIR0 = @subdir=
QUIET_SUBDIR0 = +@subdir=
QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
$(MAKE) $(PRINT_DIR) -C $$subdir
export V
@@ -748,6 +753,9 @@ git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS) GIT-CFLAGS
help.o: common-cmds.h
git-merge-subtree$X: git-merge-recursive$X
$(QUIET_BUILT_IN)rm -f $@ && ln git-merge-recursive$X $@
$(BUILT_INS): git$X
$(QUIET_BUILT_IN)rm -f $@ && ln git$X $@
@@ -966,6 +974,9 @@ test-dump-cache-tree$X: dump-cache-tree.o $(GITLIBS)
test-sha1$X: test-sha1.o $(GITLIBS)
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
test-match-trees$X: test-match-trees.o $(GITLIBS)
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
test-chmtime$X: test-chmtime.c
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $<

View File

@@ -1 +1 @@
Documentation/RelNotes-1.5.1.txt
Documentation/RelNotes-1.5.2.txt

View File

@@ -37,7 +37,7 @@ static void prep_base85(void)
}
}
int decode_85(char *dst, char *buffer, int len)
int decode_85(char *dst, const char *buffer, int len)
{
prep_base85();
@@ -82,7 +82,7 @@ int decode_85(char *dst, char *buffer, int len)
return 0;
}
void encode_85(char *buf, unsigned char *data, int bytes)
void encode_85(char *buf, const unsigned char *data, int bytes)
{
prep_base85();

View File

@@ -133,7 +133,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
git_config(git_add_config);
newfd = hold_lock_file_for_update(&lock_file, get_index_file(), 1);
newfd = hold_locked_index(&lock_file, 1);
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
@@ -209,7 +209,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (active_cache_changed) {
if (write_cache(newfd, active_cache, active_nr) ||
close(newfd) || commit_lock_file(&lock_file))
close(newfd) || commit_locked_index(&lock_file))
die("Unable to write new index file");
}

View File

@@ -2664,8 +2664,8 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
update_index = check_index && apply;
if (update_index && newfd < 0)
newfd = hold_lock_file_for_update(&lock_file,
get_index_file(), 1);
newfd = hold_locked_index(&lock_file, 1);
if (check_index) {
if (read_cache() < 0)
die("unable to read index file");
@@ -2872,7 +2872,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
if (update_index) {
if (write_cache(newfd, active_cache, active_nr) ||
close(newfd) || commit_lock_file(&lock_file))
close(newfd) || commit_locked_index(&lock_file))
die("Unable to write new index file");
}

View File

@@ -149,7 +149,7 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)
{
const char *extra_argv[MAX_EXTRA_ARGS];
int extra_argc = 0;
const char *format = NULL; /* might want to default to "tar" */
const char *format = "tar";
const char *base = "";
int verbose = 0;
int i;
@@ -190,8 +190,6 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)
/* We need at least one parameter -- tree-ish */
if (argc - 1 < i)
usage(archive_usage);
if (!format)
die("You must specify an archive format");
if (init_archiver(format, ar) < 0)
die("Unknown archive format '%s'", format);

View File

@@ -19,11 +19,11 @@
static char blame_usage[] =
"git-blame [-c] [-l] [-t] [-f] [-n] [-p] [-L n,m] [-S <revs-file>] [-M] [-C] [-C] [--contents <filename>] [--incremental] [commit] [--] file\n"
" -c, --compatibility Use the same output mode as git-annotate (Default: off)\n"
" -c Use the same output mode as git-annotate (Default: off)\n"
" -b Show blank SHA-1 for boundary commits (Default: off)\n"
" -l, --long Show long commit SHA1 (Default: off)\n"
" -l Show long commit SHA1 (Default: off)\n"
" --root Do not treat root commits as boundaries (Default: off)\n"
" -t, --time Show raw timestamp (Default: off)\n"
" -t Show raw timestamp (Default: off)\n"
" -f, --show-name Show original filename (Default: auto)\n"
" -n, --show-number Show original linenumber (Default: off)\n"
" -p, --porcelain Show in a format designed for machine consumption\n"
@@ -2041,7 +2041,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
commit->buffer = xmalloc(400);
ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0);
sprintf(commit->buffer,
snprintf(commit->buffer, 400,
"tree 0000000000000000000000000000000000000000\n"
"parent %s\n"
"author %s\n"

View File

@@ -493,6 +493,7 @@ static void rename_branch(const char *oldname, const char *newname, int force)
{
char oldref[PATH_MAX], newref[PATH_MAX], logmsg[PATH_MAX*2 + 100];
unsigned char sha1[20];
char oldsection[PATH_MAX], newsection[PATH_MAX];
if (!oldname)
die("cannot rename the current branch while not on any.");
@@ -521,6 +522,11 @@ static void rename_branch(const char *oldname, const char *newname, int force)
/* no need to pass logmsg here as HEAD didn't really move */
if (!strcmp(oldname, head) && create_symref("HEAD", newref, NULL))
die("Branch renamed to %s, but HEAD is not updated!", newname);
snprintf(oldsection, sizeof(oldsection), "branch.%s", oldref + 11);
snprintf(newsection, sizeof(newsection), "branch.%s", newref + 11);
if (git_config_rename_section(oldsection, newsection) < 0)
die("Branch is renamed, but update of config-file failed");
}
int cmd_branch(int argc, const char **argv, const char *prefix)

View File

@@ -202,10 +202,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
if (!strcmp(arg, "-u") || !strcmp(arg, "--index")) {
state.refresh_cache = 1;
if (newfd < 0)
newfd = hold_lock_file_for_update
(&lock_file, get_index_file(), 1);
if (newfd < 0)
die("cannot open index.lock file.");
newfd = hold_locked_index(&lock_file, 1);
continue;
}
if (!strcmp(arg, "-z")) {
@@ -302,7 +299,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
if (0 <= newfd &&
(write_cache(newfd, active_cache, active_nr) ||
close(newfd) || commit_lock_file(&lock_file)))
close(newfd) || commit_locked_index(&lock_file)))
die("Unable to write new index file");
return 0;
}

View File

@@ -534,7 +534,7 @@ static void get_default_heads(void)
* "show_unreachable" flag.
*/
if (!default_refs) {
error("No default references");
fprintf(stderr, "notice: No default references\n");
show_unreachable = 0;
}
}
@@ -554,15 +554,23 @@ static int fsck_head_link(void)
{
unsigned char sha1[20];
int flag;
const char *head_points_at = resolve_ref("HEAD", sha1, 1, &flag);
int null_is_error = 0;
const char *head_points_at = resolve_ref("HEAD", sha1, 0, &flag);
if (!head_points_at || !(flag & REF_ISSYMREF))
return error("HEAD is not a symbolic ref");
if (prefixcmp(head_points_at, "refs/heads/"))
if (!head_points_at)
return error("Invalid HEAD");
if (!strcmp(head_points_at, "HEAD"))
/* detached HEAD */
null_is_error = 1;
else if (prefixcmp(head_points_at, "refs/heads/"))
return error("HEAD points to something strange (%s)",
head_points_at);
if (is_null_sha1(sha1))
return error("HEAD: not a valid git pointer");
if (is_null_sha1(sha1)) {
if (null_is_error)
return error("HEAD: detached HEAD points at nothing");
fprintf(stderr, "notice: HEAD points to an unborn branch (%s)\n",
head_points_at + 11);
}
return 0;
}

View File

@@ -434,19 +434,6 @@ 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;
@@ -569,7 +556,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
scan = arg + 1;
break;
}
if (strtoul_ui(scan, &num))
if (strtoul_ui(scan, 10, &num))
die(emsg_invalid_context_len, scan);
switch (arg[1]) {
case 'A':

View File

@@ -12,6 +12,7 @@
#include "builtin.h"
#include "tag.h"
#include "reflog-walk.h"
#include "patch-ids.h"
static int default_show_root = 1;
@@ -333,25 +334,12 @@ static int reopen_stdout(struct commit *commit, int nr, int keep_subject)
}
static int get_patch_id(struct commit *commit, struct diff_options *options,
unsigned char *sha1)
{
if (commit->parents)
diff_tree_sha1(commit->parents->item->object.sha1,
commit->object.sha1, "", options);
else
diff_root_tree_sha1(commit->object.sha1, "", options);
diffcore_std(options);
return diff_flush_patch_id(options, sha1);
}
static void get_patch_ids(struct rev_info *rev, struct diff_options *options, const char *prefix)
static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const char *prefix)
{
struct rev_info check_rev;
struct commit *commit;
struct object *o1, *o2;
unsigned flags1, flags2;
unsigned char sha1[20];
if (rev->pending.nr != 2)
die("Need exactly one range.");
@@ -364,10 +352,7 @@ static void get_patch_ids(struct rev_info *rev, struct diff_options *options, co
if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
die("Not a range.");
diff_setup(options);
options->recursive = 1;
if (diff_setup_done(options) < 0)
die("diff_setup_done failed");
init_patch_ids(ids);
/* given a range a..b get all patch ids for b..a */
init_revisions(&check_rev, prefix);
@@ -382,8 +367,7 @@ static void get_patch_ids(struct rev_info *rev, struct diff_options *options, co
if (commit->parents && commit->parents->next)
continue;
if (!get_patch_id(commit, options, sha1))
created_object(sha1, xcalloc(1, sizeof(struct object)));
add_commit_patch_id(commit, ids);
}
/* reset for next revision walk */
@@ -417,10 +401,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
int numbered = 0;
int start_number = -1;
int keep_subject = 0;
int subject_prefix = 0;
int ignore_if_in_upstream = 0;
int thread = 0;
const char *in_reply_to = NULL;
struct diff_options patch_id_opts;
struct patch_ids ids;
char *add_signoff = NULL;
char message_id[1024];
char ref_message_id[1024];
@@ -509,8 +494,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (i == argc)
die("Need a Message-Id for --in-reply-to");
in_reply_to = argv[i];
}
else if (!prefixcmp(argv[i], "--suffix="))
} else if (!prefixcmp(argv[i], "--subject-prefix=")) {
subject_prefix = 1;
rev.subject_prefix = argv[i] + 17;
} else if (!prefixcmp(argv[i], "--suffix="))
fmt_patch_suffix = argv[i] + 9;
else
argv[j++] = argv[i];
@@ -521,6 +508,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
start_number = 1;
if (numbered && keep_subject)
die ("-n and -k are mutually exclusive.");
if (keep_subject && subject_prefix)
die ("--subject-prefix and -k are mutually exclusive.");
argc = setup_revisions(argc, argv, &rev, "HEAD");
if (argc > 1)
@@ -554,22 +543,19 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
}
if (ignore_if_in_upstream)
get_patch_ids(&rev, &patch_id_opts, prefix);
get_patch_ids(&rev, &ids, prefix);
if (!use_stdout)
realstdout = fdopen(dup(1), "w");
prepare_revision_walk(&rev);
while ((commit = get_revision(&rev)) != NULL) {
unsigned char sha1[20];
/* ignore merges */
if (commit->parents && commit->parents->next)
continue;
if (ignore_if_in_upstream &&
!get_patch_id(commit, &patch_id_opts, sha1) &&
lookup_object(sha1))
has_commit_patch_id(commit, &ids))
continue;
nr++;
@@ -624,6 +610,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
fclose(stdout);
}
free(list);
if (ignore_if_in_upstream)
free_patch_ids(&ids);
return 0;
}
@@ -646,7 +634,7 @@ static const char cherry_usage[] =
int cmd_cherry(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
struct diff_options patch_id_opts;
struct patch_ids ids;
struct commit *commit;
struct commit_list *list = NULL;
const char *upstream;
@@ -692,7 +680,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
return 0;
}
get_patch_ids(&revs, &patch_id_opts, prefix);
get_patch_ids(&revs, &ids, prefix);
if (limit && add_pending_commit(limit, &revs, UNINTERESTING))
die("Unknown commit %s", limit);
@@ -708,12 +696,10 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
}
while (list) {
unsigned char sha1[20];
char sign = '+';
commit = list->item;
if (!get_patch_id(commit, &patch_id_opts, sha1) &&
lookup_object(sha1))
if (has_commit_patch_id(commit, &ids))
sign = '-';
if (verbose) {
@@ -731,5 +717,6 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
list = list->next;
}
free_patch_ids(&ids);
return 0;
}

View File

@@ -77,7 +77,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
git_config(git_default_config);
newfd = hold_lock_file_for_update(&lock_file, get_index_file(), 1);
newfd = hold_locked_index(&lock_file, 1);
if (read_cache() < 0)
die("index file corrupt");
@@ -285,7 +285,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
if (active_cache_changed) {
if (write_cache(newfd, active_cache, active_nr) ||
close(newfd) ||
commit_lock_file(&lock_file))
commit_locked_index(&lock_file))
die("Unable to write new index file");
}
}

View File

@@ -297,7 +297,7 @@ static int read_config(const char *repo, const char *uri[MAX_URI])
static int do_push(const char *repo)
{
const char *uri[MAX_URI];
int i, n;
int i, n, errs;
int common_argc;
const char **argv;
int argc;
@@ -317,6 +317,7 @@ static int do_push(const char *repo)
argv[argc++] = receivepack;
common_argc = argc;
errs = 0;
for (i = 0; i < n; i++) {
int err;
int dest_argc = common_argc;
@@ -339,21 +340,23 @@ static int do_push(const char *repo)
err = run_command_v_opt(argv, RUN_GIT_CMD);
if (!err)
continue;
error("failed to push to '%s'", uri[i]);
switch (err) {
case -ERR_RUN_COMMAND_FORK:
die("unable to fork for %s", sender);
error("unable to fork for %s", sender);
case -ERR_RUN_COMMAND_EXEC:
die("unable to exec %s", sender);
error("unable to exec %s", sender);
break;
case -ERR_RUN_COMMAND_WAITPID:
case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
die("%s died with strange error", sender);
default:
return -err;
error("%s died with strange error", sender);
}
errs++;
}
return 0;
return !!errs;
}
int cmd_push(int argc, const char **argv, const char *prefix)

View File

@@ -84,7 +84,7 @@ static void prime_cache_tree(void)
}
static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] <sha1> [<sha2> [<sha3>]])";
static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])";
static struct lock_file lock_file;
@@ -100,7 +100,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
setup_git_directory();
git_config(git_default_config);
newfd = hold_lock_file_for_update(&lock_file, get_index_file(), 1);
newfd = hold_locked_index(&lock_file, 1);
git_config(git_default_config);
@@ -128,6 +128,11 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
continue;
}
if (!prefixcmp(arg, "--index-output=")) {
set_alternate_index_output(arg + 15);
continue;
}
/* "--prefix=<subdirectory>/" means keep the current index
* entries and put the entries from the tree under the
* given subdirectory.
@@ -228,6 +233,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
if (0 <= pos)
die("file '%.*s' already exists.",
pfxlen-1, opts.prefix);
opts.pos = -1 - pos;
}
if (opts.merge) {
@@ -267,7 +273,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
}
if (write_cache(newfd, active_cache, active_nr) ||
close(newfd) || commit_lock_file(&lock_file))
close(newfd) || commit_locked_index(&lock_file))
die("unable to write new index file");
return 0;
}

View File

@@ -10,7 +10,7 @@
#include "tree-walk.h"
static const char builtin_rm_usage[] =
"git-rm [-f] [-n] [-r] [--cached] [--] <file>...";
"git-rm [-f] [-n] [-r] [--cached] [--quiet] [--] <file>...";
static struct {
int nr, alloc;
@@ -104,13 +104,13 @@ static struct lock_file lock_file;
int cmd_rm(int argc, const char **argv, const char *prefix)
{
int i, newfd;
int show_only = 0, force = 0, index_only = 0, recursive = 0;
int show_only = 0, force = 0, index_only = 0, recursive = 0, quiet = 0;
const char **pathspec;
char *seen;
git_config(git_default_config);
newfd = hold_lock_file_for_update(&lock_file, get_index_file(), 1);
newfd = hold_locked_index(&lock_file, 1);
if (read_cache() < 0)
die("index file corrupt");
@@ -132,6 +132,8 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
force = 1;
else if (!strcmp(arg, "-r"))
recursive = 1;
else if (!strcmp(arg, "--quiet"))
quiet = 1;
else
usage(builtin_rm_usage);
}
@@ -168,7 +170,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
* must match; but the file can already been removed, since
* this sequence is a natural "novice" way:
*
* rm F; git fm F
* rm F; git rm F
*
* Further, if HEAD commit exists, "diff-index --cached" must
* report no changes unless forced.
@@ -187,7 +189,8 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
*/
for (i = 0; i < list.nr; i++) {
const char *path = list.name[i];
printf("rm '%s'\n", path);
if (!quiet)
printf("rm '%s'\n", path);
if (remove_file_from_cache(path))
die("git-rm: unable to remove %s", path);
@@ -220,7 +223,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
if (active_cache_changed) {
if (write_cache(newfd, active_cache, active_nr) ||
close(newfd) || commit_lock_file(&lock_file))
close(newfd) || commit_locked_index(&lock_file))
die("Unable to write new index file");
}

View File

@@ -227,6 +227,7 @@ static void read_index_info(int line_termination)
char *path_name;
unsigned char sha1[20];
unsigned int mode;
unsigned long ul;
int stage;
/* This reads lines formatted in one of three formats:
@@ -249,9 +250,12 @@ static void read_index_info(int line_termination)
if (buf.eof)
break;
mode = strtoul(buf.buf, &ptr, 8);
if (ptr == buf.buf || *ptr != ' ')
errno = 0;
ul = strtoul(buf.buf, &ptr, 8);
if (ptr == buf.buf || *ptr != ' '
|| errno || (unsigned int) ul != ul)
goto bad_line;
mode = ul;
tab = strchr(ptr, '\t');
if (!tab || tab - ptr < 41)
@@ -495,7 +499,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
/* We can't free this memory, it becomes part of a linked list parsed atexit() */
lock_file = xcalloc(1, sizeof(struct lock_file));
newfd = hold_lock_file_for_update(lock_file, get_index_file(), 0);
newfd = hold_locked_index(lock_file, 0);
if (newfd < 0)
lock_error = errno;
@@ -547,7 +551,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
if (i+3 >= argc)
die("git-update-index: --cacheinfo <mode> <sha1> <path>");
if ((sscanf(argv[i+1], "%o", &mode) != 1) ||
if ((strtoul_ui(argv[i+1], 8, &mode) != 1) ||
get_sha1_hex(argv[i+2], sha1) ||
add_cacheinfo(mode, sha1, argv[i+3], 0))
die("git-update-index: --cacheinfo"
@@ -661,7 +665,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
get_index_file(), strerror(lock_error));
}
if (write_cache(newfd, active_cache, active_nr) ||
close(newfd) || commit_lock_file(lock_file))
close(newfd) || commit_locked_index(lock_file))
die("Unable to write new index file");
}

View File

@@ -18,7 +18,7 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
/* We can't free this memory, it becomes part of a linked list parsed atexit() */
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
newfd = hold_lock_file_for_update(lock_file, get_index_file(), 0);
newfd = hold_locked_index(lock_file, 1);
entries = read_cache();
if (entries < 0)

12
cache.h
View File

@@ -212,6 +212,11 @@ struct lock_file {
};
extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
extern int commit_lock_file(struct lock_file *);
extern int hold_locked_index(struct lock_file *, int);
extern int commit_locked_index(struct lock_file *);
extern void set_alternate_index_output(const char *);
extern void rollback_lock_file(struct lock_file *);
extern int delete_ref(const char *, unsigned char *sha1);
@@ -468,8 +473,8 @@ extern int pager_in_use;
extern int pager_use_color;
/* base85 */
int decode_85(char *dst, char *line, int linelen);
void encode_85(char *buf, unsigned char *data, int bytes);
int decode_85(char *dst, const char *line, int linelen);
void encode_85(char *buf, const unsigned char *data, int bytes);
/* alloc.c */
struct blob;
@@ -492,4 +497,7 @@ extern void trace_argv_printf(const char **argv, int count, const char *format,
extern int convert_to_git(const char *path, char **bufp, unsigned long *sizep);
extern int convert_to_working_tree(const char *path, char **bufp, unsigned long *sizep);
/* match-trees.c */
void shift_tree(const unsigned char *, const unsigned char *, unsigned char *, int);
#endif /* CACHE_H */

View File

@@ -4,6 +4,8 @@
#include "pkt-line.h"
#include "utf8.h"
#include "interpolate.h"
#include "diff.h"
#include "revision.h"
int save_commit_buffer = 1;
@@ -808,7 +810,8 @@ static long format_commit_message(const struct commit *commit,
{ "%Cgreen" }, /* green */
{ "%Cblue" }, /* blue */
{ "%Creset" }, /* reset color */
{ "%n" } /* newline */
{ "%n" }, /* newline */
{ "%m" }, /* left/right/bottom */
};
enum interp_index {
IHASH = 0, IHASH_ABBREV,
@@ -824,14 +827,15 @@ static long format_commit_message(const struct commit *commit,
ISUBJECT,
IBODY,
IRED, IGREEN, IBLUE, IRESET_COLOR,
INEWLINE
INEWLINE,
ILEFT_RIGHT,
};
struct commit_list *p;
char parents[1024];
int i;
enum { HEADER, SUBJECT, BODY } state;
if (INEWLINE + 1 != ARRAY_SIZE(table))
if (ILEFT_RIGHT + 1 != ARRAY_SIZE(table))
die("invalid interp table!");
/* these are independent of the commit */
@@ -852,6 +856,12 @@ static long format_commit_message(const struct commit *commit,
interp_set_entry(table, ITREE_ABBREV,
find_unique_abbrev(commit->tree->object.sha1,
DEFAULT_ABBREV));
interp_set_entry(table, ILEFT_RIGHT,
(commit->object.flags & BOUNDARY)
? "-"
: (commit->object.flags & SYMMETRIC_LEFT)
? "<"
: ">");
parents[1] = 0;
for (i = 0, p = commit->parents;

View File

@@ -88,7 +88,7 @@ static int write_subdirectory(void *buffer, unsigned long size, const char *base
unsigned int mode;
char *slash, *origpath;
if (!path || sscanf(buffer, "%o", &mode) != 1)
if (!path || strtoul_ui(buffer, 8, &mode) != 1)
die("bad tree conversion");
mode = convert_mode(mode);
path++;

View File

@@ -142,18 +142,34 @@ static int queue_diff(struct diff_options *o,
}
}
/*
* Does the path name a blob in the working tree, or a directory
* in the working tree?
*/
static int is_in_index(const char *path)
{
int len = strlen(path);
int pos = cache_name_pos(path, len);
char c;
int len, pos;
struct cache_entry *ce;
if (pos < 0)
return 0;
if (strncmp(active_cache[pos]->name, path, len))
return 0;
c = active_cache[pos]->name[len];
return c == '\0' || c == '/';
len = strlen(path);
while (path[len-1] == '/')
len--;
if (!len)
return 1; /* "." */
pos = cache_name_pos(path, len);
if (0 <= pos)
return 1;
pos = -1 - pos;
while (pos < active_nr) {
ce = active_cache[pos++];
if (ce_namelen(ce) <= len ||
strncmp(ce->name, path, len) ||
(ce->name[len] > '/'))
break; /* path cannot be a prefix */
if (ce->name[len] == '/')
return 1;
}
return 0;
}
static int handle_diff_files_args(struct rev_info *revs,

View File

@@ -1,15 +1,24 @@
#!/bin/sh
USAGE='[start|bad|good|next|reset|visualize|replay|log|run]'
LONG_USAGE='git bisect start [<pathspec>] reset bisect state and start bisection.
git bisect bad [<rev>] mark <rev> a known-bad revision.
git bisect good [<rev>...] mark <rev>... known-good revisions.
git bisect next find next bisection to test and check it out.
git bisect reset [<branch>] finish bisection search and go back to branch.
git bisect visualize show bisect status in gitk.
git bisect replay <logfile> replay bisection log.
git bisect log show bisect log.
git bisect run <cmd>... use <cmd>... to automatically bisect.'
LONG_USAGE='git bisect start [<bad> [<good>...]] [--] [<pathspec>...]
reset bisect state and start bisection.
git bisect bad [<rev>]
mark <rev> a known-bad revision.
git bisect good [<rev>...]
mark <rev>... known-good revisions.
git bisect next
find next bisection to test and check it out.
git bisect reset [<branch>]
finish bisection search and go back to branch.
git bisect visualize
show bisect status in gitk.
git bisect replay <logfile>
replay bisection log.
git bisect log
show bisect log.
git bisect run <cmd>...
use <cmd>... to automatically bisect.'
. git-sh-setup
require_work_tree
@@ -70,14 +79,48 @@ bisect_start() {
#
# Get rid of any old bisect state
#
rm -f "$GIT_DIR/refs/heads/bisect"
rm -rf "$GIT_DIR/refs/bisect/"
bisect_clean_state
mkdir "$GIT_DIR/refs/bisect"
#
# Check for one bad and then some good revisions.
#
has_double_dash=0
for arg; do
case "$arg" in --) has_double_dash=1; break ;; esac
done
orig_args=$(sq "$@")
bad_seen=0
while [ $# -gt 0 ]; do
arg="$1"
case "$arg" in
--)
shift
break
;;
*)
rev=$(git-rev-parse --verify "$arg^{commit}" 2>/dev/null) || {
test $has_double_dash -eq 1 &&
die "'$arg' does not appear to be a valid revision"
break
}
if [ $bad_seen -eq 0 ]; then
bad_seen=1
bisect_write_bad "$rev"
else
bisect_write_good "$rev"
fi
shift
;;
esac
done
sq "$@" >"$GIT_DIR/BISECT_NAMES"
{
printf "git-bisect start"
sq "$@"
} >"$GIT_DIR/BISECT_LOG"
sq "$@" >"$GIT_DIR/BISECT_NAMES"
echo "$orig_args"
} >>"$GIT_DIR/BISECT_LOG"
bisect_auto_next
}
bisect_bad() {
@@ -90,12 +133,17 @@ bisect_bad() {
*)
usage ;;
esac || exit
echo "$rev" >"$GIT_DIR/refs/bisect/bad"
echo "# bad: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
bisect_write_bad "$rev"
echo "git-bisect bad $rev" >>"$GIT_DIR/BISECT_LOG"
bisect_auto_next
}
bisect_write_bad() {
rev="$1"
echo "$rev" >"$GIT_DIR/refs/bisect/bad"
echo "# bad: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
}
bisect_good() {
bisect_autostart
case "$#" in
@@ -106,35 +154,54 @@ bisect_good() {
for rev in $revs
do
rev=$(git-rev-parse --verify "$rev^{commit}") || exit
echo "$rev" >"$GIT_DIR/refs/bisect/good-$rev"
echo "# good: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
bisect_write_good "$rev"
echo "git-bisect good $rev" >>"$GIT_DIR/BISECT_LOG"
done
bisect_auto_next
}
bisect_write_good() {
rev="$1"
echo "$rev" >"$GIT_DIR/refs/bisect/good-$rev"
echo "# good: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
}
bisect_next_check() {
next_ok=no
test -f "$GIT_DIR/refs/bisect/bad" &&
case "$(cd "$GIT_DIR" && echo refs/bisect/good-*)" in
refs/bisect/good-\*) ;;
*) next_ok=yes ;;
esac
case "$next_ok,$1" in
no,) false ;;
no,fail)
THEN=''
test -d "$GIT_DIR/refs/bisect" || {
echo >&2 'You need to start by "git bisect start".'
THEN='then '
}
echo >&2 'You '$THEN'need to give me at least one good' \
'and one bad revisions.'
echo >&2 '(You can use "git bisect bad" and' \
'"git bisect good" for that.)'
exit 1 ;;
missing_good= missing_bad=
git show-ref -q --verify refs/bisect/bad || missing_bad=t
test -n "$(git for-each-ref "refs/bisect/good-*")" || missing_good=t
case "$missing_good,$missing_bad,$1" in
,,*)
: have both good and bad - ok
;;
*,)
# do not have both but not asked to fail - just report.
false
;;
t,,good)
# have bad but not good. we could bisect although
# this is less optimum.
echo >&2 'Warning: bisecting only with a bad commit.'
if test -t 0
then
printf >&2 'Are you sure [Y/n]? '
case "$(read yesno)" in [Nn]*) exit 1 ;; esac
fi
: bisect without good...
;;
*)
true ;;
THEN=''
test -d "$GIT_DIR/refs/bisect" || {
echo >&2 'You need to start by "git bisect start".'
THEN='then '
}
echo >&2 'You '$THEN'need to give me at least one good' \
'and one bad revisions.'
echo >&2 '(You can use "git bisect bad" and' \
'"git bisect good" for that.)'
exit 1 ;;
esac
}
@@ -145,27 +212,32 @@ bisect_auto_next() {
bisect_next() {
case "$#" in 0) ;; *) usage ;; esac
bisect_autostart
bisect_next_check fail
bisect_next_check good
bad=$(git-rev-parse --verify refs/bisect/bad) &&
good=$(git-rev-parse --sq --revs-only --not \
$(cd "$GIT_DIR" && ls refs/bisect/good-*)) &&
rev=$(eval "git-rev-list --bisect $good $bad -- $(cat "$GIT_DIR/BISECT_NAMES")") || exit
if [ -z "$rev" ]; then
echo "$bad was both good and bad"
exit 1
good=$(git for-each-ref --format='^%(objectname)' \
"refs/bisect/good-*" | tr '[\012]' ' ') &&
eval="git-rev-list --bisect-vars $good $bad --" &&
eval="$eval $(cat "$GIT_DIR/BISECT_NAMES")" &&
eval=$(eval "$eval") &&
eval "$eval" || exit
if [ -z "$bisect_rev" ]; then
echo "$bad was both good and bad"
exit 1
fi
if [ "$rev" = "$bad" ]; then
echo "$rev is first bad commit"
git-diff-tree --pretty $rev
exit 0
if [ "$bisect_rev" = "$bad" ]; then
echo "$bisect_rev is first bad commit"
git-diff-tree --pretty $bisect_rev
exit 0
fi
nr=$(eval "git-rev-list $rev $good -- $(cat $GIT_DIR/BISECT_NAMES)" | wc -l) || exit
echo "Bisecting: $nr revisions left to test after this"
echo "$rev" > "$GIT_DIR/refs/heads/new-bisect"
echo "Bisecting: $bisect_nr revisions left to test after this"
echo "$bisect_rev" >"$GIT_DIR/refs/heads/new-bisect"
git checkout -q new-bisect || exit
mv "$GIT_DIR/refs/heads/new-bisect" "$GIT_DIR/refs/heads/bisect" &&
GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD refs/heads/bisect
git-show-branch "$rev"
git-show-branch "$bisect_rev"
}
bisect_visualize() {
@@ -190,14 +262,19 @@ bisect_reset() {
usage ;;
esac
if git checkout "$branch"; then
rm -fr "$GIT_DIR/refs/bisect"
rm -f "$GIT_DIR/refs/heads/bisect" "$GIT_DIR/head-name"
rm -f "$GIT_DIR/BISECT_LOG"
rm -f "$GIT_DIR/BISECT_NAMES"
rm -f "$GIT_DIR/BISECT_RUN"
rm -f "$GIT_DIR/head-name"
bisect_clean_state
fi
}
bisect_clean_state() {
rm -fr "$GIT_DIR/refs/bisect"
rm -f "$GIT_DIR/refs/heads/bisect"
rm -f "$GIT_DIR/BISECT_LOG"
rm -f "$GIT_DIR/BISECT_NAMES"
rm -f "$GIT_DIR/BISECT_RUN"
}
bisect_replay () {
test -r "$1" || {
echo >&2 "cannot read $1 for replaying"

View File

@@ -170,7 +170,7 @@ describe_detached_head () {
}
}
if test -z "$branch$newbranch" && test "$new" != "$old"
if test -z "$branch$newbranch" && test "$new_name" != "$old_name"
then
detached="$new"
if test -n "$oldbranch" && test -z "$quiet"
@@ -180,7 +180,7 @@ If you want to create a new branch from this checkout, you may do so
(now or later) by using -b with the checkout command again. Example:
git checkout -b <new_branch_name>"
fi
elif test -z "$oldbranch"
elif test -z "$oldbranch" && test "$new" != "$old"
then
describe_detached_head 'Previous HEAD position was' "$old"
fi

View File

@@ -370,8 +370,8 @@ t,)
# the same way.
if test -z "$initial_commit"
then
cp "$THIS_INDEX" "$TMP_INDEX"
GIT_INDEX_FILE="$TMP_INDEX" git-read-tree -i -m HEAD
GIT_INDEX_FILE="$THIS_INDEX" \
git-read-tree --index-output="$TMP_INDEX" -i -m HEAD
else
rm -f "$TMP_INDEX"
fi || exit
@@ -649,8 +649,9 @@ then
fi
if test -z "$quiet"
then
commit=`git-diff-tree --always --shortstat --pretty="format:%h: %s"\
--summary --root HEAD --`
echo "Created${initial_commit:+ initial} commit $commit"
git-diff-tree --shortstat --summary --root --no-commit-id HEAD --
fi
fi

View File

@@ -308,6 +308,19 @@ static inline int prefixcmp(const char *str, const char *prefix)
return strncmp(str, prefix, strlen(prefix));
}
static inline int strtoul_ui(char const *s, int base, unsigned int *result)
{
unsigned long ul;
char *p;
errno = 0;
ul = strtoul(s, &p, base);
if (errno || *p || p == s || (unsigned int) ul != ul)
return -1;
*result = ul;
return 0;
}
// MinGW
#ifndef S_ISLNK

View File

@@ -124,12 +124,17 @@ close MSG;
`git-diff-tree --binary -p $parent $commit >.cvsexportcommit.diff`;# || die "Cannot diff";
## apply non-binary changes
my $fuzz = $opt_p ? 0 : 2;
# In pedantic mode require all lines of context to match. In normal
# mode, be compatible with diff/patch: assume 3 lines of context and
# require at least one line match, i.e. ignore at most 2 lines of
# context, like diff/patch do by default.
my $context = $opt_p ? '' : '-C1';
print "Checking if patch will apply\n";
my @stat;
open APPLY, "GIT_DIR= git-apply -C$fuzz --binary --summary --numstat<.cvsexportcommit.diff|" || die "cannot patch";
open APPLY, "GIT_DIR= git-apply $context --binary --summary --numstat<.cvsexportcommit.diff|" || die "cannot patch";
@stat=<APPLY>;
close APPLY || die "Cannot patch";
my (@bfiles,@files,@afiles,@dfiles);
@@ -196,7 +201,7 @@ if ($dirty) {
}
print "Applying\n";
`GIT_DIR= git-apply -C$fuzz --binary --summary --numstat --apply <.cvsexportcommit.diff` || die "cannot patch";
`GIT_DIR= git-apply $context --binary --summary --numstat --apply <.cvsexportcommit.diff` || die "cannot patch";
print "Patch applied successfully. Adding new files and directories to CVS\n";
my $dirtypatch = 0;

View File

@@ -32,12 +32,15 @@ $ENV{'TZ'}="UTC";
our ($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,$opt_M,$opt_A,$opt_S,$opt_L, $opt_a);
my (%conv_author_name, %conv_author_email);
sub usage() {
sub usage(;$) {
my $msg = shift;
print(STDERR "Error: $msg\n") if $msg;
print STDERR <<END;
Usage: ${\basename $0} # fetch/update GIT from CVS
[-o branch-for-HEAD] [-h] [-v] [-d CVSROOT] [-A author-conv-file]
[-p opts-for-cvsps] [-C GIT_repository] [-z fuzz] [-i] [-k] [-u]
[-s subst] [-a] [-m] [-M regex] [-S regex] [CVS_module]
[-p opts-for-cvsps] [-P file] [-C GIT_repository] [-z fuzz] [-i] [-k]
[-u] [-s subst] [-a] [-m] [-M regex] [-S regex] [-L commitlimit]
[CVS_module]
END
exit(1);
}
@@ -116,7 +119,7 @@ read_repo_config($opts);
getopts($opts) or usage();
usage if $opt_h;
@ARGV <= 1 or usage();
@ARGV <= 1 or usage("You can't specify more than one CVS module");
if ($opt_d) {
$ENV{"CVSROOT"} = $opt_d;
@@ -129,7 +132,7 @@ if ($opt_d) {
} elsif ($ENV{"CVSROOT"}) {
$opt_d = $ENV{"CVSROOT"};
} else {
die "CVSROOT needs to be set";
usage("CVSROOT needs to be set");
}
$opt_o ||= "origin";
$opt_s ||= "-";
@@ -148,7 +151,7 @@ if ($#ARGV == 0) {
chomp $cvs_tree;
close $f;
} else {
usage();
usage("CVS module has to be specified");
}
our @mergerx = ();

View File

@@ -843,6 +843,7 @@ sub req_update
if ( defined ( $wrev )
and defined($meta->{revision})
and $wrev == $meta->{revision}
and defined($state->{entries}{$filename}{modified_hash})
and not exists ( $state->{opt}{C} ) )
{
$log->info("Tell the client the file is modified");

View File

@@ -26,6 +26,7 @@ keep=
shallow_depth=
no_progress=
test -t 1 || no_progress=--no-progress
quiet=
while case "$#" in 0) break ;; esac
do
case "$1" in
@@ -56,6 +57,9 @@ do
--update-head-o|--update-head-ok)
update_head_ok=t
;;
-q|--q|--qu|--qui|--quie|--quiet)
quiet=--quiet
;;
-v|--verbose)
verbose=Yes
;;
@@ -173,8 +177,8 @@ fetch_all_at_once () {
git-bundle unbundle "$remote" $rref ||
echo failed "$remote"
else
git-fetch-pack --thin $exec $keep $shallow_depth $no_progress \
"$remote" $rref ||
git-fetch-pack --thin $exec $keep $shallow_depth \
$quiet $no_progress "$remote" $rref ||
echo failed "$remote"
fi
) |
@@ -248,7 +252,8 @@ fetch_per_ref () {
expr "z$head" : "z$_x40\$" >/dev/null ||
die "No such ref $remote_name at $remote"
echo >&2 "Fetching $remote_name from $remote using $proto"
git-http-fetch -v -a "$head" "$remote" || exit
case "$quiet" in '') v=-v ;; *) v= ;; esac
git-http-fetch $v -a "$head" "$remote" || exit
;;
rsync://*)
test -n "$shallow_depth" &&
@@ -257,8 +262,9 @@ fetch_per_ref () {
rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1
head=$(git-rev-parse --verify TMP_HEAD)
rm -f "$TMP_HEAD"
case "$quiet" in '') v=-v ;; *) v= ;; esac
test "$rsync_slurped_objects" || {
rsync -av --ignore-existing --exclude info \
rsync -a $v --ignore-existing --exclude info \
"$remote/objects/" "$GIT_OBJECT_DIRECTORY/" || exit
# Look at objects/info/alternates for rsync -- http will

View File

@@ -16,10 +16,10 @@ test -z "$(git ls-files -u)" ||
LF='
'
all_strategies='recur recursive octopus resolve stupid ours'
all_strategies='recur recursive octopus resolve stupid ours subtree'
default_twohead_strategies='recursive'
default_octopus_strategies='octopus'
no_trivial_merge_strategies='ours'
no_trivial_merge_strategies='ours subtree'
use_strategies=
index_merge=t

View File

@@ -73,9 +73,9 @@ mkdir $tmp_dir || exit 2
for patch_name in $(cat "$QUILT_PATCHES/series" | grep -v '^#'); do
echo $patch_name
(cat $QUILT_PATCHES/$patch_name | git-mailinfo "$tmp_msg" "$tmp_patch" > "$tmp_info") || exit 3
test -s $dotest/patch || {
test -s .dotest/patch || {
echo "Patch is empty. Was is split wrong?"
stop_here $this
exit 1
}
# Parse the author information

3
git-rebase.sh Executable file → Normal file
View File

@@ -339,8 +339,7 @@ prev_head=`git-rev-parse HEAD^0`
echo "$prev_head" > "$dotest/prev_head"
msgnum=0
for cmt in `git-rev-list --no-merges "$upstream"..ORIG_HEAD \
| sed -ne '1!G;$p;h'`
for cmt in `git-rev-list --reverse --no-merges "$upstream"..ORIG_HEAD`
do
msgnum=$(($msgnum + 1))
echo "$cmt" > "$dotest/cmt.$msgnum"

View File

@@ -595,7 +595,7 @@ foreach my $t (@files) {
if ($chain_reply_to || !defined $reply_to || length($reply_to) == 0) {
$reply_to = $message_id;
if (length $references > 0) {
$references .= " $message_id";
$references .= "\n $message_id";
} else {
$references = "$message_id";
}

View File

@@ -363,13 +363,12 @@ sub cmd_dcommit {
my $head = shift;
$head ||= 'HEAD';
my @refs;
my ($url, $rev, $uuid) = working_head_info($head, \@refs);
my $c = $refs[-1];
unless (defined $url && defined $rev && defined $uuid) {
my ($url, $rev, $uuid, $gs) = working_head_info($head, \@refs);
unless ($gs) {
die "Unable to determine upstream SVN information from ",
"$head history\n";
}
my $gs = Git::SVN->find_by_url($url);
my $c = $refs[-1];
my $last_rev;
foreach my $d (@refs) {
if (!verify_ref("$d~1")) {
@@ -431,16 +430,11 @@ sub cmd_dcommit {
sub cmd_rebase {
command_noisy(qw/update-index --refresh/);
my $url = (working_head_info('HEAD'))[0];
if (!defined $url) {
my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
unless ($gs) {
die "Unable to determine upstream SVN information from ",
"working tree history\n";
}
my $gs = Git::SVN->find_by_url($url);
unless ($gs) {
die "Unable to determine remote information from URL: $url\n";
}
if (command(qw/diff-index HEAD --/)) {
print STDERR "Cannot rebase with uncommited changes:\n";
command_noisy('status');
@@ -453,8 +447,8 @@ sub cmd_rebase {
}
sub cmd_show_ignore {
my $url = (::working_head_info('HEAD'))[0];
my $gs = Git::SVN->find_by_url($url) || Git::SVN->new;
my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
$gs ||= Git::SVN->new;
my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);
$gs->traverse_ignore(\*STDOUT, $gs->{path}, $r);
}
@@ -776,16 +770,23 @@ sub cmt_metadata {
sub working_head_info {
my ($head, $refs) = @_;
my ($url, $rev, $uuid);
my ($fh, $ctx) = command_output_pipe('rev-list', $head);
while (<$fh>) {
chomp;
($url, $rev, $uuid) = cmt_metadata($_);
last if (defined $url && defined $rev && defined $uuid);
my ($url, $rev, $uuid) = cmt_metadata($_);
if (defined $url && defined $rev) {
if (my $gs = Git::SVN->find_by_url($url)) {
my $c = $gs->rev_db_get($rev);
if ($c && $c eq $_) {
close $fh; # break the pipe
return ($url, $rev, $uuid, $gs);
}
}
}
unshift @$refs, $_ if $refs;
}
close $fh; # break the pipe
($url, $rev, $uuid);
command_close_pipe($fh, $ctx);
(undef, undef, undef, undef);
}
package Git::SVN;
@@ -3262,12 +3263,19 @@ my $l_fmt;
sub cmt_showable {
my ($c) = @_;
return 1 if defined $c->{r};
# big commit message got truncated by the 16k pretty buffer in rev-list
if ($c->{l} && $c->{l}->[-1] eq "...\n" &&
$c->{a_raw} =~ /\@([a-f\d\-]+)>$/) {
@{$c->{l}} = ();
my @log = command(qw/cat-file commit/, $c->{c});
shift @log while ($log[0] ne "\n");
# shift off the headers
shift @log while ($log[0] ne '');
shift @log;
@{$c->{l}} = grep !/^git-svn-id: /, @log;
# TODO: make $c->{l} not have a trailing newline in the future
@{$c->{l}} = map { "$_\n" } grep !/^git-svn-id: /, @log;
(undef, $c->{r}, undef) = ::extract_metadata(
(grep(/^git-svn-id: /, @log))[-1]);
@@ -3321,8 +3329,8 @@ sub git_svn_log_cmd {
last;
}
my $url = (::working_head_info($head))[0];
my $gs = Git::SVN->find_by_url($url) || Git::SVN->_new;
my ($url, $rev, $uuid, $gs) = ::working_head_info($head);
$gs ||= Git::SVN->_new;
my @cmd = (qw/log --abbrev-commit --pretty=raw --default/,
$gs->refname);
push @cmd, '-r' unless $non_recursive;

1
git.c
View File

@@ -70,6 +70,7 @@ static int handle_options(const char*** argv, int* argc)
setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1);
(*argv)++;
(*argc)--;
handled++;
} else if (!prefixcmp(cmd, "--git-dir=")) {
setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
} else if (!strcmp(cmd, "--bare")) {

52
gitk
View File

@@ -648,8 +648,10 @@ proc makewindow {} {
frame .bright.mode
radiobutton .bright.mode.patch -text "Patch" \
-command reselectline -variable cmitmode -value "patch"
.bright.mode.patch configure -font $uifont
radiobutton .bright.mode.tree -text "Tree" \
-command reselectline -variable cmitmode -value "tree"
.bright.mode.tree configure -font $uifont
grid .bright.mode.patch .bright.mode.tree -sticky ew
pack .bright.mode -side top -fill x
set cflist .bright.cfiles
@@ -923,6 +925,7 @@ proc bindall {event action} {
}
proc about {} {
global uifont
set w .about
if {[winfo exists $w]} {
raise $w
@@ -936,13 +939,19 @@ Gitk - a commit viewer for git
Copyright <20> 2005-2006 Paul Mackerras
Use and redistribute under the terms of the GNU General Public License} \
-justify center -aspect 400
pack $w.m -side top -fill x -padx 20 -pady 20
button $w.ok -text Close -command "destroy $w"
-justify center -aspect 400 -border 2 -bg white -relief groove
pack $w.m -side top -fill x -padx 2 -pady 2
$w.m configure -font $uifont
button $w.ok -text Close -command "destroy $w" -default active
pack $w.ok -side bottom
$w.ok configure -font $uifont
bind $w <Visibility> "focus $w.ok"
bind $w <Key-Escape> "destroy $w"
bind $w <Key-Return> "destroy $w"
}
proc keys {} {
global uifont
set w .keys
if {[winfo exists $w]} {
raise $w
@@ -989,10 +998,15 @@ f Scroll diff view to next file
<Ctrl-minus> Decrease font size
<F5> Update
} \
-justify left -bg white -border 2 -relief sunken
pack $w.m -side top -fill both
button $w.ok -text Close -command "destroy $w"
-justify left -bg white -border 2 -relief groove
pack $w.m -side top -fill both -padx 2 -pady 2
$w.m configure -font $uifont
button $w.ok -text Close -command "destroy $w" -default active
pack $w.ok -side bottom
$w.ok configure -font $uifont
bind $w <Visibility> "focus $w.ok"
bind $w <Key-Escape> "destroy $w"
bind $w <Key-Return> "destroy $w"
}
# Procedures for manipulating the file list window at the
@@ -1458,20 +1472,21 @@ proc vieweditor {top n title} {
toplevel $top
wm title $top $title
label $top.nl -text "Name" -font $uifont
entry $top.name -width 20 -textvariable newviewname($n)
entry $top.name -width 20 -textvariable newviewname($n) -font $uifont
grid $top.nl $top.name -sticky w -pady 5
checkbutton $top.perm -text "Remember this view" -variable newviewperm($n)
checkbutton $top.perm -text "Remember this view" -variable newviewperm($n) \
-font $uifont
grid $top.perm - -pady 5 -sticky w
message $top.al -aspect 1000 -font $uifont \
-text "Commits to include (arguments to git rev-list):"
grid $top.al - -sticky w -pady 5
entry $top.args -width 50 -textvariable newviewargs($n) \
-background white
-background white -font $uifont
grid $top.args - -sticky ew -padx 5
message $top.l -aspect 1000 -font $uifont \
-text "Enter files and directories to include, one per line:"
grid $top.l - -sticky w
text $top.t -width 40 -height 10 -background white
text $top.t -width 40 -height 10 -background white -font $uifont
if {[info exists viewfiles($n)]} {
foreach f $viewfiles($n) {
$top.t insert end $f
@@ -1482,8 +1497,10 @@ proc vieweditor {top n title} {
}
grid $top.t - -sticky ew -padx 5
frame $top.buts
button $top.buts.ok -text "OK" -command [list newviewok $top $n]
button $top.buts.can -text "Cancel" -command [list destroy $top]
button $top.buts.ok -text "OK" -command [list newviewok $top $n] \
-font $uifont
button $top.buts.can -text "Cancel" -command [list destroy $top] \
-font $uifont
grid $top.buts.ok $top.buts.can
grid columnconfigure $top.buts 0 -weight 1 -uniform a
grid columnconfigure $top.buts 1 -weight 1 -uniform a
@@ -5814,6 +5831,7 @@ proc doprefs {} {
global maxwidth maxgraphpct diffopts
global oldprefs prefstop showneartags
global bgcolor fgcolor ctext diffcolors
global uifont
set top .gitkprefs
set prefstop $top
@@ -5827,6 +5845,7 @@ proc doprefs {} {
toplevel $top
wm title $top "Gitk preferences"
label $top.ldisp -text "Commit list display options"
$top.ldisp configure -font $uifont
grid $top.ldisp - -sticky w -pady 10
label $top.spacer -text " "
label $top.maxwidthl -text "Maximum graph width (lines)" \
@@ -5839,6 +5858,7 @@ proc doprefs {} {
grid x $top.maxpctl $top.maxpct -sticky w
label $top.ddisp -text "Diff display options"
$top.ddisp configure -font $uifont
grid $top.ddisp - -sticky w -pady 10
label $top.diffoptl -text "Options for diff program" \
-font optionfont
@@ -5851,6 +5871,7 @@ proc doprefs {} {
grid x $top.ntag -sticky w
label $top.cdisp -text "Colors: press to choose"
$top.cdisp configure -font $uifont
grid $top.cdisp - -sticky w -pady 10
label $top.bg -padx 40 -relief sunk -background $bgcolor
button $top.bgbut -text "Background" -font optionfont \
@@ -5878,12 +5899,15 @@ proc doprefs {} {
grid x $top.hunksepbut $top.hunksep -sticky w
frame $top.buts
button $top.buts.ok -text "OK" -command prefsok
button $top.buts.can -text "Cancel" -command prefscan
button $top.buts.ok -text "OK" -command prefsok -default active
$top.buts.ok configure -font $uifont
button $top.buts.can -text "Cancel" -command prefscan -default normal
$top.buts.can configure -font $uifont
grid $top.buts.ok $top.buts.can
grid columnconfigure $top.buts 0 -weight 1 -uniform a
grid columnconfigure $top.buts 1 -weight 1 -uniform a
grid $top.buts - - -pady 10 -sticky ew
bind $top <Visibility> "focus $top.buts.ok"
}
proc choosecolor {v vi w x cmd} {

View File

@@ -71,6 +71,10 @@ our $logo_label = "git homepage";
# source of projects list
our $projects_list = "++GITWEB_LIST++";
# default order of projects list
# valid values are none, project, descr, owner, and age
our $default_projects_order = "project";
# show repository only if this file exists
# (only effective if this variable evaluates to true)
our $export_ok = "++GITWEB_EXPORT_OK++";
@@ -176,8 +180,8 @@ our %feature = (
# projects matching $projname/*.git will not be shown in the main
# projects list, instead a '+' mark will be added to $projname
# there and a 'forks' view will be enabled for the project, listing
# all the forks. This feature is supported only if project list
# is taken from a directory, not file.
# all the forks. If project list is taken from a file, forks have
# to be listed after the main project.
# To enable system wide have in $GITWEB_CONFIG
# $feature{'forks'}{'default'} = [1];
@@ -1047,6 +1051,8 @@ sub git_get_projects_list {
$filter ||= '';
$filter =~ s/\.git$//;
my ($check_forks) = gitweb_check_feature('forks');
if (-d $projects_list) {
# search in directory
my $dir = $projects_list . ($filter ? "/$filter" : '');
@@ -1054,8 +1060,6 @@ sub git_get_projects_list {
$dir =~ s!/+$!!;
my $pfxlen = length("$dir");
my ($check_forks) = gitweb_check_feature('forks');
File::Find::find({
follow_fast => 1, # follow symbolic links
dangling_symlinks => 0, # ignore dangling symlinks, silently
@@ -1081,7 +1085,9 @@ sub git_get_projects_list {
# 'git%2Fgit.git Linus+Torvalds'
# 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin'
# 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman'
my %paths;
open my ($fd), $projects_list or return;
PROJECT:
while (my $line = <$fd>) {
chomp $line;
my ($path, $owner) = split ' ', $line;
@@ -1094,11 +1100,27 @@ sub git_get_projects_list {
# looking for forks;
my $pfx = substr($path, 0, length($filter));
if ($pfx ne $filter) {
next;
next PROJECT;
}
my $sfx = substr($path, length($filter));
if ($sfx !~ /^\/.*\.git$/) {
next;
next PROJECT;
}
} elsif ($check_forks) {
PATH:
foreach my $filter (keys %paths) {
# looking for forks;
my $pfx = substr($path, 0, length($filter));
if ($pfx ne $filter) {
next PATH;
}
my $sfx = substr($path, length($filter));
if ($sfx !~ /^\/.*\.git$/) {
next PATH;
}
# is a fork, don't include it in
# the list
next PROJECT;
}
}
if (check_export_ok("$projectroot/$path")) {
@@ -1106,12 +1128,13 @@ sub git_get_projects_list {
path => $path,
owner => to_utf8($owner),
};
push @list, $pr
push @list, $pr;
(my $forks_path = $path) =~ s/\.git$//;
$paths{$forks_path}++;
}
}
close $fd;
}
@list = sort {$a->{'path'} cmp $b->{'path'}} @list;
return @list;
}
@@ -2598,7 +2621,7 @@ sub git_project_list_body {
push @projects, $pr;
}
$order ||= "project";
$order ||= $default_projects_order;
$from = 0 unless defined $from;
$to = $#projects if (!defined $to || $#projects < $to);
@@ -2957,7 +2980,7 @@ sub git_search_grep_body {
sub git_project_list {
my $order = $cgi->param('o');
if (defined $order && $order !~ m/project|descr|owner|age/) {
if (defined $order && $order !~ m/none|project|descr|owner|age/) {
die_error(undef, "Unknown order parameter");
}
@@ -2980,7 +3003,7 @@ sub git_project_list {
sub git_forks {
my $order = $cgi->param('o');
if (defined $order && $order !~ m/project|descr|owner|age/) {
if (defined $order && $order !~ m/none|project|descr|owner|age/) {
die_error(undef, "Unknown order parameter");
}

16
ident.c
View File

@@ -11,10 +11,10 @@ static char git_default_date[50];
#ifndef NO_ETC_PASSWD
static void copy_gecos(struct passwd *w, char *name, int sz)
static void copy_gecos(const struct passwd *w, char *name, size_t sz)
{
char *src, *dst;
int len, nlen;
size_t len, nlen;
nlen = strlen(w->pw_name);
@@ -45,13 +45,13 @@ static void copy_gecos(struct passwd *w, char *name, int sz)
}
static void copy_email(struct passwd *pw)
static void copy_email(const struct passwd *pw)
{
/*
* Make up a fake email address
* (name + '@' + hostname [+ '.' + domainname])
*/
int len = strlen(pw->pw_name);
size_t len = strlen(pw->pw_name);
if (len > sizeof(git_default_email)/2)
die("Your sysadmin must hate you!");
memcpy(git_default_email, pw->pw_name, len);
@@ -101,9 +101,9 @@ static void setup_ident(void)
datestamp(git_default_date, sizeof(git_default_date));
}
static int add_raw(char *buf, int size, int offset, const char *str)
static int add_raw(char *buf, size_t size, int offset, const char *str)
{
int len = strlen(str);
size_t len = strlen(str);
if (offset + len > size)
return size;
memcpy(buf + offset, str, len);
@@ -137,9 +137,9 @@ static int crud(unsigned char c)
* Copy over a string to the destination, but avoid special
* characters ('\n', '<' and '>') and remove crud at the end
*/
static int copy(char *buf, int size, int offset, const char *src)
static int copy(char *buf, size_t size, int offset, const char *src)
{
int i, len;
size_t i, len;
unsigned char c;
/* Remove crud from the beginning.. */

View File

@@ -4,6 +4,7 @@
#include "cache.h"
static struct lock_file *lock_file_list;
static const char *alternate_index_output;
static void remove_lock_file(void)
{
@@ -68,6 +69,27 @@ int commit_lock_file(struct lock_file *lk)
return i;
}
int hold_locked_index(struct lock_file *lk, int die_on_error)
{
return hold_lock_file_for_update(lk, get_index_file(), die_on_error);
}
void set_alternate_index_output(const char *name)
{
alternate_index_output = name;
}
int commit_locked_index(struct lock_file *lk)
{
if (alternate_index_output) {
int result = rename(lk->filename, alternate_index_output);
lk->filename[0] = 0;
return result;
}
else
return commit_lock_file(lk);
}
void rollback_lock_file(struct lock_file *lk)
{
if (lk->filename[0]) {

View File

@@ -165,14 +165,20 @@ void show_log(struct rev_info *opt, const char *sep)
if (opt->total > 0) {
static char buffer[64];
snprintf(buffer, sizeof(buffer),
"Subject: [PATCH %0*d/%d] ",
"Subject: [%s %0*d/%d] ",
opt->subject_prefix,
digits_in_number(opt->total),
opt->nr, opt->total);
subject = buffer;
} else if (opt->total == 0)
subject = "Subject: [PATCH] ";
else
} else if (opt->total == 0) {
static char buffer[256];
snprintf(buffer, sizeof(buffer),
"Subject: [%s] ",
opt->subject_prefix);
subject = buffer;
} else {
subject = "Subject: ";
}
printf("From %s Mon Sep 17 00:00:00 2001\n", sha1);
if (opt->message_id)

304
match-trees.c Normal file
View File

@@ -0,0 +1,304 @@
#include "cache.h"
#include "tree.h"
#include "tree-walk.h"
static int score_missing(unsigned mode, const char *path)
{
int score;
if (S_ISDIR(mode))
score = -1000;
else if (S_ISLNK(mode))
score = -500;
else
score = -50;
return score;
}
static int score_differs(unsigned mode1, unsigned mode2, const char *path)
{
int score;
if (S_ISDIR(mode1) != S_ISDIR(mode2))
score = -100;
else if (S_ISLNK(mode1) != S_ISLNK(mode2))
score = -50;
else
score = -5;
return score;
}
static int score_matches(unsigned mode1, unsigned mode2, const char *path)
{
int score;
/* Heh, we found SHA-1 collisions between different kind of objects */
if (S_ISDIR(mode1) != S_ISDIR(mode2))
score = -100;
else if (S_ISLNK(mode1) != S_ISLNK(mode2))
score = -50;
else if (S_ISDIR(mode1))
score = 1000;
else if (S_ISLNK(mode1))
score = 500;
else
score = 250;
return score;
}
/*
* Inspect two trees, and give a score that tells how similar they are.
*/
static int score_trees(const unsigned char *hash1, const unsigned char *hash2)
{
struct tree_desc one;
struct tree_desc two;
void *one_buf, *two_buf;
int score = 0;
enum object_type type;
unsigned long size;
one_buf = read_sha1_file(hash1, &type, &size);
if (!one_buf)
die("unable to read tree (%s)", sha1_to_hex(hash1));
if (type != OBJ_TREE)
die("%s is not a tree", sha1_to_hex(hash1));
init_tree_desc(&one, one_buf, size);
two_buf = read_sha1_file(hash2, &type, &size);
if (!two_buf)
die("unable to read tree (%s)", sha1_to_hex(hash2));
if (type != OBJ_TREE)
die("%s is not a tree", sha1_to_hex(hash2));
init_tree_desc(&two, two_buf, size);
while (one.size | two.size) {
const unsigned char *elem1 = elem1;
const unsigned char *elem2 = elem2;
const char *path1 = path1;
const char *path2 = path2;
unsigned mode1 = mode1;
unsigned mode2 = mode2;
int cmp;
if (one.size)
elem1 = tree_entry_extract(&one, &path1, &mode1);
if (two.size)
elem2 = tree_entry_extract(&two, &path2, &mode2);
if (!one.size) {
/* two has more entries */
score += score_missing(mode2, path2);
update_tree_entry(&two);
continue;
}
if (!two.size) {
/* two lacks this entry */
score += score_missing(mode1, path1);
update_tree_entry(&one);
continue;
}
cmp = base_name_compare(path1, strlen(path1), mode1,
path2, strlen(path2), mode2);
if (cmp < 0) {
/* path1 does not appear in two */
score += score_missing(mode1, path1);
update_tree_entry(&one);
continue;
}
else if (cmp > 0) {
/* path2 does not appear in one */
score += score_missing(mode2, path2);
update_tree_entry(&two);
continue;
}
else if (hashcmp(elem1, elem2))
/* they are different */
score += score_differs(mode1, mode2, path1);
else
/* same subtree or blob */
score += score_matches(mode1, mode2, path1);
update_tree_entry(&one);
update_tree_entry(&two);
}
free(one_buf);
free(two_buf);
return score;
}
/*
* Match one itself and its subtrees with two and pick the best match.
*/
static void match_trees(const unsigned char *hash1,
const unsigned char *hash2,
int *best_score,
char **best_match,
char *base,
int recurse_limit)
{
struct tree_desc one;
void *one_buf;
enum object_type type;
unsigned long size;
one_buf = read_sha1_file(hash1, &type, &size);
if (!one_buf)
die("unable to read tree (%s)", sha1_to_hex(hash1));
if (type != OBJ_TREE)
die("%s is not a tree", sha1_to_hex(hash1));
init_tree_desc(&one, one_buf, size);
while (one.size) {
const char *path;
const unsigned char *elem;
unsigned mode;
int score;
elem = tree_entry_extract(&one, &path, &mode);
if (!S_ISDIR(mode))
goto next;
score = score_trees(elem, hash2);
if (*best_score < score) {
char *newpath;
newpath = xmalloc(strlen(base) + strlen(path) + 1);
sprintf(newpath, "%s%s", base, path);
free(*best_match);
*best_match = newpath;
*best_score = score;
}
if (recurse_limit) {
char *newbase;
newbase = xmalloc(strlen(base) + strlen(path) + 2);
sprintf(newbase, "%s%s/", base, path);
match_trees(elem, hash2, best_score, best_match,
newbase, recurse_limit - 1);
free(newbase);
}
next:
update_tree_entry(&one);
}
free(one_buf);
}
/*
* A tree "hash1" has a subdirectory at "prefix". Come up with a
* tree object by replacing it with another tree "hash2".
*/
static int splice_tree(const unsigned char *hash1,
char *prefix,
const unsigned char *hash2,
unsigned char *result)
{
char *subpath;
int toplen;
char *buf;
unsigned long sz;
struct tree_desc desc;
unsigned char *rewrite_here;
const unsigned char *rewrite_with;
unsigned char subtree[20];
enum object_type type;
int status;
subpath = strchr(prefix, '/');
if (!subpath)
toplen = strlen(prefix);
else {
toplen = subpath - prefix;
subpath++;
}
buf = read_sha1_file(hash1, &type, &sz);
if (!buf)
die("cannot read tree %s", sha1_to_hex(hash1));
init_tree_desc(&desc, buf, sz);
rewrite_here = NULL;
while (desc.size) {
const char *name;
unsigned mode;
const unsigned char *sha1;
sha1 = tree_entry_extract(&desc, &name, &mode);
if (strlen(name) == toplen &&
!memcmp(name, prefix, toplen)) {
if (!S_ISDIR(mode))
die("entry %s in tree %s is not a tree",
name, sha1_to_hex(hash1));
rewrite_here = (unsigned char *) sha1;
break;
}
update_tree_entry(&desc);
}
if (!rewrite_here)
die("entry %.*s not found in tree %s",
toplen, prefix, sha1_to_hex(hash1));
if (subpath) {
status = splice_tree(rewrite_here, subpath, hash2, subtree);
if (status)
return status;
rewrite_with = subtree;
}
else
rewrite_with = hash2;
hashcpy(rewrite_here, rewrite_with);
status = write_sha1_file(buf, sz, tree_type, result);
free(buf);
return status;
}
/*
* We are trying to come up with a merge between one and two that
* results in a tree shape similar to one. The tree two might
* correspond to a subtree of one, in which case it needs to be
* shifted down by prefixing otherwise empty directories. On the
* other hand, it could cover tree one and we might need to pick a
* subtree of it.
*/
void shift_tree(const unsigned char *hash1,
const unsigned char *hash2,
unsigned char *shifted,
int depth_limit)
{
char *add_prefix;
char *del_prefix;
int add_score, del_score;
add_score = del_score = score_trees(hash1, hash2);
add_prefix = xcalloc(1, 1);
del_prefix = xcalloc(1, 1);
/*
* See if one's subtree resembles two; if so we need to prefix
* two with a few fake trees to match the prefix.
*/
match_trees(hash1, hash2, &add_score, &add_prefix, "", depth_limit);
/*
* See if two's subtree resembles one; if so we need to
* pick only subtree of two.
*/
match_trees(hash2, hash1, &del_score, &del_prefix, "", depth_limit);
/* Assume we do not have to do any shifting */
hashcpy(shifted, hash2);
if (add_score < del_score) {
/* We need to pick a subtree of two */
unsigned mode;
if (!*del_prefix)
return;
if (get_tree_entry(hash2, del_prefix, shifted, &mode))
die("cannot find path %s in tree %s",
del_prefix, sha1_to_hex(hash2));
return;
}
if (!*add_prefix)
return;
splice_tree(hash1, add_prefix, hash2, shifted);
}

View File

@@ -16,6 +16,22 @@
#include "path-list.h"
#include "xdiff-interface.h"
static int subtree_merge;
static struct tree *shift_tree_object(struct tree *one, struct tree *two)
{
unsigned char shifted[20];
/*
* NEEDSWORK: this limits the recursion depth to hardcoded
* value '2' to avoid excessive overhead.
*/
shift_tree(one->object.sha1, two->object.sha1, shifted, 2);
if (!hashcmp(two->object.sha1, shifted))
return two;
return lookup_tree(shifted);
}
/*
* A virtual commit has
* - (const char *)commit->util set to the name, and
@@ -1137,6 +1153,12 @@ static int merge_trees(struct tree *head,
struct tree **result)
{
int code, clean;
if (subtree_merge) {
merge = shift_tree_object(head, merge);
common = shift_tree_object(head, common);
}
if (sha_eq(common->object.sha1, merge->object.sha1)) {
output(0, "Already uptodate!");
*result = head;
@@ -1342,6 +1364,13 @@ int main(int argc, char *argv[])
struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
int index_fd;
if (argv[0]) {
int namelen = strlen(argv[0]);
if (8 < namelen &&
!strcmp(argv[0] + namelen - 8, "-subtree"))
subtree_merge = 1;
}
git_config(merge_config);
if (getenv("GIT_MERGE_VERBOSITY"))
verbosity = strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10);
@@ -1378,7 +1407,7 @@ int main(int argc, char *argv[])
if (show(3))
printf("Merging %s with %s\n", branch1, branch2);
index_fd = hold_lock_file_for_update(lock, get_index_file(), 1);
index_fd = hold_locked_index(lock, 1);
for (i = 0; i < bases_count; i++) {
struct commit *ancestor = get_ref(bases[i]);
@@ -1388,7 +1417,7 @@ int main(int argc, char *argv[])
if (active_cache_changed &&
(write_cache(index_fd, active_cache, active_nr) ||
close(index_fd) || commit_lock_file(lock)))
close(index_fd) || commit_locked_index(lock)))
die ("unable to write %s", get_index_file());
return clean ? 0: 1;

192
patch-ids.c Normal file
View File

@@ -0,0 +1,192 @@
#include "cache.h"
#include "diff.h"
#include "commit.h"
#include "patch-ids.h"
static int commit_patch_id(struct commit *commit, struct diff_options *options,
unsigned char *sha1)
{
if (commit->parents)
diff_tree_sha1(commit->parents->item->object.sha1,
commit->object.sha1, "", options);
else
diff_root_tree_sha1(commit->object.sha1, "", options);
diffcore_std(options);
return diff_flush_patch_id(options, sha1);
}
static uint32_t take2(const unsigned char *id)
{
return ((id[0] << 8) | id[1]);
}
/*
* Conventional binary search loop looks like this:
*
* do {
* int mi = (lo + hi) / 2;
* int cmp = "entry pointed at by mi" minus "target";
* if (!cmp)
* return (mi is the wanted one)
* if (cmp > 0)
* hi = mi; "mi is larger than target"
* else
* lo = mi+1; "mi is smaller than target"
* } while (lo < hi);
*
* The invariants are:
*
* - When entering the loop, lo points at a slot that is never
* above the target (it could be at the target), hi points at a
* slot that is guaranteed to be above the target (it can never
* be at the target).
*
* - We find a point 'mi' between lo and hi (mi could be the same
* as lo, but never can be the same as hi), and check if it hits
* the target. There are three cases:
*
* - if it is a hit, we are happy.
*
* - if it is strictly higher than the target, we update hi with
* it.
*
* - if it is strictly lower than the target, we update lo to be
* one slot after it, because we allow lo to be at the target.
*
* When choosing 'mi', we do not have to take the "middle" but
* anywhere in between lo and hi, as long as lo <= mi < hi is
* satisfied. When we somehow know that the distance between the
* target and lo is much shorter than the target and hi, we could
* pick mi that is much closer to lo than the midway.
*/
static int patch_pos(struct patch_id **table, int nr, const unsigned char *id)
{
int hi = nr;
int lo = 0;
int mi = 0;
if (!nr)
return -1;
if (nr != 1) {
unsigned lov, hiv, miv, ofs;
for (ofs = 0; ofs < 18; ofs += 2) {
lov = take2(table[0]->patch_id + ofs);
hiv = take2(table[nr-1]->patch_id + ofs);
miv = take2(id + ofs);
if (miv < lov)
return -1;
if (hiv < miv)
return -1 - nr;
if (lov != hiv) {
/*
* At this point miv could be equal
* to hiv (but id could still be higher);
* the invariant of (mi < hi) should be
* kept.
*/
mi = (nr-1) * (miv - lov) / (hiv - lov);
if (lo <= mi && mi < hi)
break;
die("oops");
}
}
if (18 <= ofs)
die("cannot happen -- lo and hi are identical");
}
do {
int cmp;
cmp = hashcmp(table[mi]->patch_id, id);
if (!cmp)
return mi;
if (cmp > 0)
hi = mi;
else
lo = mi + 1;
mi = (hi + lo) / 2;
} while (lo < hi);
return -lo-1;
}
#define BUCKET_SIZE 190 /* 190 * 21 = 3990, with slop close enough to 4K */
struct patch_id_bucket {
struct patch_id_bucket *next;
int nr;
struct patch_id bucket[BUCKET_SIZE];
};
int init_patch_ids(struct patch_ids *ids)
{
memset(ids, 0, sizeof(*ids));
diff_setup(&ids->diffopts);
ids->diffopts.recursive = 1;
if (diff_setup_done(&ids->diffopts) < 0)
return error("diff_setup_done failed");
return 0;
}
int free_patch_ids(struct patch_ids *ids)
{
struct patch_id_bucket *next, *patches;
free(ids->table);
for (patches = ids->patches; patches; patches = next) {
next = patches->next;
free(patches);
}
return 0;
}
static struct patch_id *add_commit(struct commit *commit,
struct patch_ids *ids,
int no_add)
{
struct patch_id_bucket *bucket;
struct patch_id *ent;
unsigned char sha1[20];
int pos;
if (commit_patch_id(commit, &ids->diffopts, sha1))
return NULL;
pos = patch_pos(ids->table, ids->nr, sha1);
if (0 <= pos)
return ids->table[pos];
if (no_add)
return NULL;
pos = -1 - pos;
bucket = ids->patches;
if (!bucket || (BUCKET_SIZE <= bucket->nr)) {
bucket = xcalloc(1, sizeof(*bucket));
bucket->next = ids->patches;
ids->patches = bucket;
}
ent = &bucket->bucket[bucket->nr++];
hashcpy(ent->patch_id, sha1);
if (ids->alloc <= ids->nr) {
ids->alloc = alloc_nr(ids->nr);
ids->table = xrealloc(ids->table, sizeof(ent) * ids->alloc);
}
if (pos < ids->nr)
memmove(ids->table + pos + 1, ids->table + pos,
sizeof(ent) * (ids->nr - pos));
ids->nr++;
ids->table[pos] = ent;
return ids->table[pos];
}
struct patch_id *has_commit_patch_id(struct commit *commit,
struct patch_ids *ids)
{
return add_commit(commit, ids, 1);
}
struct patch_id *add_commit_patch_id(struct commit *commit,
struct patch_ids *ids)
{
return add_commit(commit, ids, 0);
}

21
patch-ids.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef PATCH_IDS_H
#define PATCH_IDS_H
struct patch_id {
unsigned char patch_id[20];
char seen;
};
struct patch_ids {
struct diff_options diffopts;
int nr, alloc;
struct patch_id **table;
struct patch_id_bucket *patches;
};
int init_patch_ids(struct patch_ids *);
int free_patch_ids(struct patch_ids *);
struct patch_id *add_commit_patch_id(struct commit *, struct patch_ids *);
struct patch_id *has_commit_patch_id(struct commit *, struct patch_ids *);
#endif /* PATCH_IDS_H */

View File

@@ -485,6 +485,8 @@ static int has_file_name(const struct cache_entry *ce, int pos, int ok_to_replac
continue;
if (p->name[len] != '/')
continue;
if (!ce_stage(p) && !p->ce_mode)
continue;
retval = -1;
if (!ok_to_replace)
break;
@@ -517,26 +519,37 @@ static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace
pos = cache_name_pos(name, ntohs(create_ce_flags(len, stage)));
if (pos >= 0) {
retval = -1;
if (!ok_to_replace)
break;
remove_cache_entry_at(pos);
continue;
/*
* Found one, but not so fast. This could
* be a marker that says "I was here, but
* I am being removed". Such an entry is
* not a part of the resulting tree, and
* it is Ok to have a directory at the same
* path.
*/
if (stage || active_cache[pos]->ce_mode) {
retval = -1;
if (!ok_to_replace)
break;
remove_cache_entry_at(pos);
continue;
}
}
else
pos = -pos-1;
/*
* Trivial optimization: if we find an entry that
* already matches the sub-directory, then we know
* we're ok, and we can exit.
*/
pos = -pos-1;
while (pos < active_nr) {
struct cache_entry *p = active_cache[pos];
if ((ce_namelen(p) <= len) ||
(p->name[len] != '/') ||
memcmp(p->name, name, len))
break; /* not our subdirectory */
if (ce_stage(p) == stage)
if (ce_stage(p) == stage && (stage || p->ce_mode))
/* p is at the same stage as our entry, and
* is a subdirectory of what we are looking
* at, so we cannot have conflicts at our
@@ -560,12 +573,21 @@ static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace
*/
static int check_file_directory_conflict(const struct cache_entry *ce, int pos, int ok_to_replace)
{
int retval;
/*
* When ce is an "I am going away" entry, we allow it to be added
*/
if (!ce_stage(ce) && !ce->ce_mode)
return 0;
/*
* We check if the path is a sub-path of a subsequent pathname
* first, since removing those will not change the position
* in the array
* in the array.
*/
int retval = has_file_name(ce, pos, ok_to_replace);
retval = has_file_name(ce, pos, ok_to_replace);
/*
* Then check if the path might have a clashing sub-directory
* before it.

10
refs.c
View File

@@ -837,16 +837,6 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
goto rollback;
}
if (!prefixcmp(oldref, "refs/heads/") &&
!prefixcmp(newref, "refs/heads/")) {
char oldsection[1024], newsection[1024];
snprintf(oldsection, 1024, "branch.%s", oldref + 11);
snprintf(newsection, 1024, "branch.%s", newref + 11);
if (git_config_rename_section(oldsection, newsection) < 0)
return 1;
}
return 0;
rollback:

View File

@@ -8,6 +8,7 @@
#include "revision.h"
#include "grep.h"
#include "reflog-walk.h"
#include "patch-ids.h"
static char *path_name(struct name_path *path, const char *name)
{
@@ -422,6 +423,86 @@ static void add_parents_to_list(struct rev_info *revs, struct commit *commit, st
}
}
static void cherry_pick_list(struct commit_list *list)
{
struct commit_list *p;
int left_count = 0, right_count = 0;
int left_first;
struct patch_ids ids;
/* First count the commits on the left and on the right */
for (p = list; p; p = p->next) {
struct commit *commit = p->item;
unsigned flags = commit->object.flags;
if (flags & BOUNDARY)
;
else if (flags & SYMMETRIC_LEFT)
left_count++;
else
right_count++;
}
left_first = left_count < right_count;
init_patch_ids(&ids);
/* Compute patch-ids for one side */
for (p = list; p; p = p->next) {
struct commit *commit = p->item;
unsigned flags = commit->object.flags;
if (flags & BOUNDARY)
continue;
/*
* If we have fewer left, left_first is set and we omit
* commits on the right branch in this loop. If we have
* fewer right, we skip the left ones.
*/
if (left_first != !!(flags & SYMMETRIC_LEFT))
continue;
commit->util = add_commit_patch_id(commit, &ids);
}
/* Check the other side */
for (p = list; p; p = p->next) {
struct commit *commit = p->item;
struct patch_id *id;
unsigned flags = commit->object.flags;
if (flags & BOUNDARY)
continue;
/*
* If we have fewer left, left_first is set and we omit
* commits on the left branch in this loop.
*/
if (left_first == !!(flags & SYMMETRIC_LEFT))
continue;
/*
* Have we seen the same patch id?
*/
id = has_commit_patch_id(commit, &ids);
if (!id)
continue;
id->seen = 1;
commit->object.flags |= SHOWN;
}
/* Now check the original side for seen ones */
for (p = list; p; p = p->next) {
struct commit *commit = p->item;
struct patch_id *ent;
ent = commit->util;
if (!ent)
continue;
if (ent->seen)
commit->object.flags |= SHOWN;
commit->util = NULL;
}
free_patch_ids(&ids);
}
static void limit_list(struct rev_info *revs)
{
struct commit_list *list = revs->commits;
@@ -449,6 +530,9 @@ static void limit_list(struct rev_info *revs)
continue;
p = &commit_list_insert(commit, p)->next;
}
if (revs->cherry_pick)
cherry_pick_list(newlist);
revs->commits = newlist;
}
@@ -567,6 +651,7 @@ void init_revisions(struct rev_info *revs, const char *prefix)
revs->min_age = -1;
revs->skip_count = -1;
revs->max_count = -1;
revs->subject_prefix = "PATCH";
revs->prune_fn = NULL;
revs->prune_data = NULL;
@@ -913,6 +998,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
revs->left_right = 1;
continue;
}
if (!strcmp(arg, "--cherry-pick")) {
revs->cherry_pick = 1;
continue;
}
if (!strcmp(arg, "--objects")) {
revs->tag_objects = 1;
revs->tree_objects = 1;

View File

@@ -47,6 +47,7 @@ struct rev_info {
left_right:1,
parents:1,
reverse:1,
cherry_pick:1,
first_parent_only:1;
/* Diff flags */
@@ -78,6 +79,7 @@ struct rev_info {
const char *add_signoff;
const char *extra_headers;
const char *log_reencode;
const char *subject_prefix;
int no_inline;
/* Filter by commit log message */

View File

@@ -11,7 +11,7 @@ handled. Specifically, that a bogus branch is not created.
. ./test-lib.sh
test_expect_success \
'prepare an trivial repository' \
'prepare a trivial repository' \
'echo Hello > A &&
git-update-index --add A &&
git-commit -m "Initial commit." &&
@@ -85,9 +85,9 @@ test_expect_failure \
mv .git/config .git/config-saved
test_expect_success 'git branch -m q Q without config should succeed' '
git-branch -m q Q &&
git-branch -m Q q
test_expect_success 'git branch -m q q2 without config should succeed' '
git-branch -m q q2 &&
git-branch -m q2 q
'
mv .git/config-saved .git/config

View File

@@ -84,6 +84,26 @@ test_expect_success \
'When the rm in "git-rm -f" fails, it should not remove the file from the index' \
'git-ls-files --error-unmatch baz'
test_expect_success '"rm" command printed' '
echo frotz > test-file &&
git add test-file &&
git commit -m "add file for rm test" &&
git rm test-file > rm-output &&
test `egrep "^rm " rm-output | wc -l` = 1 &&
rm -f test-file rm-output &&
git commit -m "remove file from rm test"
'
test_expect_success '"rm" command suppressed with --quiet' '
echo frotz > test-file &&
git add test-file &&
git commit -m "add file for rm --quiet test" &&
git rm --quiet test-file > rm-output &&
test `wc -l < rm-output` = 0 &&
rm -f test-file rm-output &&
git commit -m "remove file from rm --quiet test"
'
# Now, failure cases.
test_expect_success 'Re-add foo and baz' '
git add foo baz &&
@@ -154,4 +174,8 @@ test_expect_success 'Recursive with -r -f' '
! test -d frotz
'
test_expect_failure 'Remove nonexistent file returns nonzero exit status' '
git rm nonexistent
'
test_done

View File

@@ -241,6 +241,7 @@ format-patch --attach --stdout initial..master
format-patch --inline --stdout initial..side
format-patch --inline --stdout initial..master^
format-patch --inline --stdout initial..master
format-patch --inline --stdout --subject-prefix=TESTCASE initial..master
diff --abbrev initial..side
diff -r initial..side

View File

@@ -0,0 +1,164 @@
$ git format-patch --inline --stdout --subject-prefix=TESTCASE 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: [TESTCASE] 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: [TESTCASE] 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: [TESTCASE] 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--
$

View File

@@ -56,9 +56,17 @@ test_expect_success \
git-update-ref HEAD $(TZ=GMT GIT_COMMITTER_DATE="2005-05-27 22:00:00" \
git-commit-tree $treeid </dev/null)'
test_expect_success \
'git-archive' \
'git-archive HEAD >b.tar'
test_expect_success \
'git-tar-tree' \
'git-tar-tree HEAD >b.tar'
'git-tar-tree HEAD >b2.tar'
test_expect_success \
'git-archive vs. git-tar-tree' \
'diff b.tar b2.tar'
test_expect_success \
'validate file modification time' \

View File

@@ -145,11 +145,12 @@ test_expect_success \
done'
cd "$TRASH"
test_expect_success \
'compare delta flavors' \
'size_2=`stat -c "%s" test-2-${packname_2}.pack` &&
size_3=`stat -c "%s" test-3-${packname_3}.pack` &&
test $size_2 -gt $size_3'
test_expect_success 'compare delta flavors' '
perl -e '\''
defined($_ = -s $_) or die for @ARGV;
exit 1 if $ARGV[0] <= $ARGV[1];
'\'' test-2-$packname_2.pack test-3-$packname_3.pack
'
rm -fr .git2
mkdir .git2

View File

@@ -2,7 +2,9 @@
#
# Copyright (c) 2007 Christian Couder
#
test_description='Tests git-bisect run functionality'
test_description='Tests git-bisect functionality'
exec </dev/null
. ./test-lib.sh
@@ -37,11 +39,40 @@ test_expect_success \
HASH3=$(git rev-list HEAD | head -2 | tail -1) &&
HASH4=$(git rev-list HEAD | head -1)'
test_expect_success 'bisect starts with only one bad' '
git bisect reset &&
git bisect start &&
git bisect bad $HASH4 &&
git bisect next
'
test_expect_success 'bisect starts with only one good' '
git bisect reset &&
git bisect start &&
git bisect good $HASH1 || return 1
if git bisect next
then
echo Oops, should have failed.
false
else
:
fi
'
test_expect_success 'bisect start with one bad and good' '
git bisect reset &&
git bisect start &&
git bisect good $HASH1 &&
git bisect bad $HASH4 &&
git bisect next
'
# We want to automatically find the commit that
# introduced "Another" into hello.
test_expect_success \
'git bisect run simple case' \
'echo "#!/bin/sh" > test_script.sh &&
'"git bisect run" simple case' \
'echo "#"\!"/bin/sh" > test_script.sh &&
echo "grep Another hello > /dev/null" >> test_script.sh &&
echo "test \$? -ne 0" >> test_script.sh &&
chmod +x test_script.sh &&
@@ -49,7 +80,21 @@ test_expect_success \
git bisect good $HASH1 &&
git bisect bad $HASH4 &&
git bisect run ./test_script.sh > my_bisect_log.txt &&
grep "$HASH3 is first bad commit" my_bisect_log.txt'
grep "$HASH3 is first bad commit" my_bisect_log.txt &&
git bisect reset'
# We want to automatically find the commit that
# introduced "Ciao" into hello.
test_expect_success \
'"git bisect run" with more complex "git bisect start"' \
'echo "#"\!"/bin/sh" > test_script.sh &&
echo "grep Ciao hello > /dev/null" >> test_script.sh &&
echo "test \$? -ne 0" >> test_script.sh &&
chmod +x test_script.sh &&
git bisect start $HASH4 $HASH1 &&
git bisect run ./test_script.sh > my_bisect_log.txt &&
grep "$HASH4 is first bad commit" my_bisect_log.txt &&
git bisect reset'
#
#

View File

@@ -3,7 +3,20 @@
# Copyright (c) 2006 Junio C Hamano
#
test_description='git-checkout tests.'
test_description='git-checkout tests.
Creates master, forks renamer and side branches from it.
Test switching across them.
! [master] Initial A one, A two
* [renamer] Renamer R one->uno, M two
! [side] Side M one, D two, A three
---
+ [side] Side M one, D two, A three
* [renamer] Renamer R one->uno, M two
+*+ [master] Initial A one, A two
'
. ./test-lib.sh
@@ -129,4 +142,52 @@ test_expect_success 'checkout -m with merge conflict' '
! test -s current
'
test_expect_success 'checkout to detach HEAD' '
git checkout -f renamer && git clean &&
git checkout renamer^ &&
H=$(git rev-parse --verify HEAD) &&
M=$(git show-ref -s --verify refs/heads/master) &&
test "z$H" = "z$M" &&
if git symbolic-ref HEAD >/dev/null 2>&1
then
echo "OOPS, HEAD is still symbolic???"
false
else
: happy
fi
'
test_expect_success 'checkout to detach HEAD with branchname^' '
git checkout -f master && git clean &&
git checkout renamer^ &&
H=$(git rev-parse --verify HEAD) &&
M=$(git show-ref -s --verify refs/heads/master) &&
test "z$H" = "z$M" &&
if git symbolic-ref HEAD >/dev/null 2>&1
then
echo "OOPS, HEAD is still symbolic???"
false
else
: happy
fi
'
test_expect_success 'checkout to detach HEAD with HEAD^0' '
git checkout -f master && git clean &&
git checkout HEAD^0 &&
H=$(git rev-parse --verify HEAD) &&
M=$(git show-ref -s --verify refs/heads/master) &&
test "z$H" = "z$M" &&
if git symbolic-ref HEAD >/dev/null 2>&1
then
echo "OOPS, HEAD is still symbolic???"
false
else
: happy
fi
'
test_done

View File

@@ -34,13 +34,19 @@ fi
allowunannotated=$(git-repo-config --bool hooks.allowunannotated)
# check for no description
projectdesc=$(sed -e '1p' "$GIT_DIR/description")
if [ -z "$projectdesc" -o "$projectdesc" = "Unnamed repository; edit this file to name it for gitweb" ]; then
echo "*** Project description file hasn't been set" >&2
exit 1
fi
# --- Check types
newrev_type=$(git-cat-file -t $newrev)
# if $newrev is 0000...0000, it's a commit to delete a branch
if [ -z "${newrev##0*}" ]; then
newrev_type=commit
else
newrev_type=$(git-cat-file -t $newrev)
fi
case "$refname","$newrev_type" in
refs/tags/*,commit)

24
test-match-trees.c Normal file
View File

@@ -0,0 +1,24 @@
#include "cache.h"
#include "tree.h"
int main(int ac, char **av)
{
unsigned char hash1[20], hash2[20], shifted[20];
struct tree *one, *two;
if (get_sha1(av[1], hash1))
die("cannot parse %s as an object name", av[1]);
if (get_sha1(av[2], hash2))
die("cannot parse %s as an object name", av[2]);
one = parse_tree_indirect(hash1);
if (!one)
die("not a treeish %s", av[1]);
two = parse_tree_indirect(hash2);
if (!two)
die("not a treeish %s", av[2]);
shift_tree(one->object.sha1, two->object.sha1, shifted, -1);
printf("shifted: %s\n", sha1_to_hex(shifted));
exit(0);
}

View File

@@ -70,7 +70,6 @@ static int entcmp(const char *name1, int dir1, const char *name2, int dir2)
static int unpack_trees_rec(struct tree_entry_list **posns, int len,
const char *base, struct unpack_trees_options *o,
int *indpos,
struct tree_entry_list *df_conflict_list)
{
int baselen = strlen(base);
@@ -100,7 +99,7 @@ static int unpack_trees_rec(struct tree_entry_list **posns, int len,
cache_name = NULL;
/* Check the cache */
if (o->merge && *indpos < active_nr) {
if (o->merge && o->pos < active_nr) {
/* This is a bit tricky: */
/* If the index has a subdirectory (with
* contents) as the first name, it'll get a
@@ -118,7 +117,7 @@ static int unpack_trees_rec(struct tree_entry_list **posns, int len,
* file case.
*/
cache_name = active_cache[*indpos]->name;
cache_name = active_cache[o->pos]->name;
if (strlen(cache_name) > baselen &&
!memcmp(cache_name, base, baselen)) {
cache_name += baselen;
@@ -158,8 +157,8 @@ static int unpack_trees_rec(struct tree_entry_list **posns, int len,
if (cache_name && !strcmp(cache_name, first)) {
any_files = 1;
src[0] = active_cache[*indpos];
remove_cache_entry_at(*indpos);
src[0] = active_cache[o->pos];
remove_cache_entry_at(o->pos);
}
for (i = 0; i < len; i++) {
@@ -228,7 +227,7 @@ static int unpack_trees_rec(struct tree_entry_list **posns, int len,
#if DBRT_DEBUG > 1
printf("Added %d entries\n", ret);
#endif
*indpos += ret;
o->pos += ret;
} else {
for (i = 0; i < src_size; i++) {
if (src[i]) {
@@ -244,7 +243,7 @@ static int unpack_trees_rec(struct tree_entry_list **posns, int len,
newbase[baselen + pathlen] = '/';
newbase[baselen + pathlen + 1] = '\0';
if (unpack_trees_rec(subposns, len, newbase, o,
indpos, df_conflict_list)) {
df_conflict_list)) {
retval = -1;
goto leave_directory;
}
@@ -375,7 +374,6 @@ static void check_updates(struct cache_entry **src, int nr,
int unpack_trees(struct object_list *trees, struct unpack_trees_options *o)
{
int indpos = 0;
unsigned len = object_list_length(trees);
struct tree_entry_list **posns;
int i;
@@ -404,7 +402,7 @@ int unpack_trees(struct object_list *trees, struct unpack_trees_options *o)
posn = posn->next;
}
if (unpack_trees_rec(posns, len, o->prefix ? o->prefix : "",
o, &indpos, &df_conflict_list))
o, &df_conflict_list))
return -1;
}
@@ -467,6 +465,64 @@ static void invalidate_ce_path(struct cache_entry *ce)
cache_tree_invalidate_path(active_cache_tree, ce->name);
}
static int verify_clean_subdirectory(const char *path, const char *action,
struct unpack_trees_options *o)
{
/*
* we are about to extract "path"; we would not want to lose
* anything in the existing directory there.
*/
int namelen;
int pos, i;
struct dir_struct d;
char *pathbuf;
int cnt = 0;
/*
* First let's make sure we do not have a local modification
* in that directory.
*/
namelen = strlen(path);
pos = cache_name_pos(path, namelen);
if (0 <= pos)
return cnt; /* we have it as nondirectory */
pos = -pos - 1;
for (i = pos; i < active_nr; i++) {
struct cache_entry *ce = active_cache[i];
int len = ce_namelen(ce);
if (len < namelen ||
strncmp(path, ce->name, namelen) ||
ce->name[namelen] != '/')
break;
/*
* ce->name is an entry in the subdirectory.
*/
if (!ce_stage(ce)) {
verify_uptodate(ce, o);
ce->ce_mode = 0;
}
cnt++;
}
/*
* Then we need to make sure that we do not lose a locally
* present file that is not ignored.
*/
pathbuf = xmalloc(namelen + 2);
memcpy(pathbuf, path, namelen);
strcpy(pathbuf+namelen, "/");
memset(&d, 0, sizeof(d));
if (o->dir)
d.exclude_per_dir = o->dir->exclude_per_dir;
i = read_directory(&d, path, pathbuf, namelen+1, NULL);
if (i)
die("Updating '%s' would lose untracked files in it",
path);
free(pathbuf);
return cnt;
}
/*
* We do not want to remove or overwrite a working tree file that
* is not tracked, unless it is ignored.
@@ -478,9 +534,62 @@ static void verify_absent(const char *path, const char *action,
if (o->index_only || o->reset || !o->update)
return;
if (!lstat(path, &st) && !(o->dir && excluded(o->dir, path)))
if (!lstat(path, &st)) {
int cnt;
if (o->dir && excluded(o->dir, path))
/*
* path is explicitly excluded, so it is Ok to
* overwrite it.
*/
return;
if (S_ISDIR(st.st_mode)) {
/*
* We are checking out path "foo" and
* found "foo/." in the working tree.
* This is tricky -- if we have modified
* files that are in "foo/" we would lose
* it.
*/
cnt = verify_clean_subdirectory(path, action, o);
/*
* If this removed entries from the index,
* what that means is:
*
* (1) the caller unpack_trees_rec() saw path/foo
* in the index, and it has not removed it because
* it thinks it is handling 'path' as blob with
* D/F conflict;
* (2) we will return "ok, we placed a merged entry
* in the index" which would cause o->pos to be
* incremented by one;
* (3) however, original o->pos now has 'path/foo'
* marked with "to be removed".
*
* We need to increment it by the number of
* deleted entries here.
*/
o->pos += cnt;
return;
}
/*
* The previous round may already have decided to
* delete this path, which is in a subdirectory that
* is being replaced with a blob.
*/
cnt = cache_name_pos(path, strlen(path));
if (0 <= cnt) {
struct cache_entry *ce = active_cache[cnt];
if (!ce_stage(ce) && !ce->ce_mode)
return;
}
die("Untracked working tree file '%s' "
"would be %s by merge.", path, action);
}
}
static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
@@ -525,7 +634,7 @@ static int deleted_entry(struct cache_entry *ce, struct cache_entry *old,
return 1;
}
static int keep_entry(struct cache_entry *ce)
static int keep_entry(struct cache_entry *ce, struct unpack_trees_options *o)
{
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD);
return 1;
@@ -682,7 +791,7 @@ int threeway_merge(struct cache_entry **stages,
if (!head_match || !remote_match) {
for (i = 1; i < o->head_idx; i++) {
if (stages[i]) {
keep_entry(stages[i]);
keep_entry(stages[i], o);
count++;
break;
}
@@ -695,8 +804,8 @@ int threeway_merge(struct cache_entry **stages,
show_stage_entry(stderr, "remote ", stages[remote_match]);
}
#endif
if (head) { count += keep_entry(head); }
if (remote) { count += keep_entry(remote); }
if (head) { count += keep_entry(head, o); }
if (remote) { count += keep_entry(remote, o); }
return count;
}
@@ -713,12 +822,18 @@ int twoway_merge(struct cache_entry **src,
struct unpack_trees_options *o)
{
struct cache_entry *current = src[0];
struct cache_entry *oldtree = src[1], *newtree = src[2];
struct cache_entry *oldtree = src[1];
struct cache_entry *newtree = src[2];
if (o->merge_size != 2)
return error("Cannot do a twoway merge of %d trees",
o->merge_size);
if (oldtree == o->df_conflict_entry)
oldtree = NULL;
if (newtree == o->df_conflict_entry)
newtree = NULL;
if (current) {
if ((!oldtree && !newtree) || /* 4 and 5 */
(!oldtree && newtree &&
@@ -726,9 +841,9 @@ int twoway_merge(struct cache_entry **src,
(oldtree && newtree &&
same(oldtree, newtree)) || /* 14 and 15 */
(oldtree && newtree &&
!same(oldtree, newtree) && /* 18 and 19*/
!same(oldtree, newtree) && /* 18 and 19 */
same(current, newtree))) {
return keep_entry(current);
return keep_entry(current, o);
}
else if (oldtree && !newtree && same(current, oldtree)) {
/* 10 or 11 */
@@ -774,7 +889,7 @@ int bind_merge(struct cache_entry **src,
if (a && old)
die("Entry '%s' overlaps. Cannot bind.", a->name);
if (!a)
return keep_entry(old);
return keep_entry(old, o);
else
return merged_entry(a, NULL, o);
}
@@ -804,7 +919,7 @@ int oneway_merge(struct cache_entry **src,
ce_match_stat(old, &st, 1))
old->ce_flags |= htons(CE_UPDATE);
}
return keep_entry(old);
return keep_entry(old, o);
}
return merged_entry(a, old, o);
}

View File

@@ -16,6 +16,7 @@ struct unpack_trees_options {
int verbose_update;
int aggressive;
const char *prefix;
int pos;
struct dir_struct *dir;
merge_fn_t fn;