mirror of
https://github.com/git/git.git
synced 2026-03-13 10:23:30 +01:00
Merge commit '402fa75eed29c104ae5392ce88560f6bffc64ce7'
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -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
|
||||
|
||||
1
Documentation/.gitignore
vendored
1
Documentation/.gitignore
vendored
@@ -2,6 +2,7 @@
|
||||
*.html
|
||||
*.1
|
||||
*.7
|
||||
*.made
|
||||
howto-index.txt
|
||||
doc.dep
|
||||
cmds-*.txt
|
||||
|
||||
@@ -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 $@+ $@
|
||||
|
||||
61
Documentation/RelNotes-1.5.1.1.txt
Normal file
61
Documentation/RelNotes-1.5.1.1.txt
Normal 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.
|
||||
76
Documentation/RelNotes-1.5.2.txt
Normal file
76
Documentation/RelNotes-1.5.2.txt
Normal 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
|
||||
@@ -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:
|
||||
|
||||
|
||||
67
Documentation/blame-options.txt
Normal file
67
Documentation/blame-options.txt
Normal 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.
|
||||
@@ -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__
|
||||
|
||||
@@ -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).
|
||||
|
||||
|
||||
@@ -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
|
||||
----------
|
||||
|
||||
|
||||
@@ -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
|
||||
--------
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
--------------------
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
----------
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=v1.5.1.GIT
|
||||
DEF_VER=v1.5.1.1.GIT
|
||||
|
||||
LF='
|
||||
'
|
||||
|
||||
19
Makefile
19
Makefile
@@ -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) $<
|
||||
|
||||
|
||||
4
base85.c
4
base85.c
@@ -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();
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
15
builtin-rm.c
15
builtin-rm.c
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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
12
cache.h
@@ -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 */
|
||||
|
||||
16
commit.c
16
commit.c
@@ -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;
|
||||
|
||||
@@ -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++;
|
||||
|
||||
34
diff-lib.c
34
diff-lib.c
@@ -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,
|
||||
|
||||
193
git-bisect.sh
193
git-bisect.sh
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = ();
|
||||
|
||||
@@ -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");
|
||||
|
||||
14
git-fetch.sh
14
git-fetch.sh
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
3
git-rebase.sh
Executable file → Normal 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"
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
52
git-svn.perl
52
git-svn.perl
@@ -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
1
git.c
@@ -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
52
gitk
@@ -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} {
|
||||
|
||||
@@ -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
16
ident.c
@@ -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.. */
|
||||
|
||||
22
lockfile.c
22
lockfile.c
@@ -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]) {
|
||||
|
||||
14
log-tree.c
14
log-tree.c
@@ -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
304
match-trees.c
Normal 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);
|
||||
}
|
||||
|
||||
@@ -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
192
patch-ids.c
Normal 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
21
patch-ids.h
Normal 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 */
|
||||
40
read-cache.c
40
read-cache.c
@@ -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
10
refs.c
@@ -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:
|
||||
|
||||
89
revision.c
89
revision.c
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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--
|
||||
|
||||
|
||||
$
|
||||
@@ -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' \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
#
|
||||
#
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
24
test-match-trees.c
Normal 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);
|
||||
}
|
||||
153
unpack-trees.c
153
unpack-trees.c
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user