Merge branch 'master' of git://repo.or.cz/git/mingw into devel

Conflicts:
	t/t5505-remote.sh
	test-path-utils.c

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
Johannes Schindelin
2009-03-05 18:37:12 +01:00
172 changed files with 3210 additions and 1704 deletions

1
.gitignore vendored
View File

@@ -82,7 +82,6 @@ git-mktag
git-mktree
git-name-rev
git-mv
git-notes
git-pack-redundant
git-pack-objects
git-pack-refs

View File

@@ -45,7 +45,7 @@ Fixes since v1.5.2.1
correctly when the branch name had slash in it.
- The email address of the user specified with user.email
configuration was overriden by EMAIL environment variable.
configuration was overridden by EMAIL environment variable.
- The tree parser did not warn about tree entries with
nonsense file modes, and assumed they must be blobs.

View File

@@ -7,7 +7,7 @@ Fixes since v1.6.0.1
* Installation on platforms that needs .exe suffix to git-* programs were
broken in 1.6.0.1.
* Installation on filesystems without symbolic links support did nto
* Installation on filesystems without symbolic links support did not
work well.
* In-tree documentations and test scripts now use "git foo" form to set a

View File

@@ -41,11 +41,11 @@ Fixes since v1.6.1
work tree upon delete/modify conflict.
* "git merge -s recursive" didn't leave the index unmerged for entries with
rename/delete conflictd.
rename/delete conflicts.
* "git merge -s recursive" clobbered untracked files in the work tree.
* "git mv -k" with more than one errorneous paths misbehaved.
* "git mv -k" with more than one erroneous paths misbehaved.
* "git read-tree -m -u" hence branch switching incorrectly lost a
subdirectory in rare cases.

View File

@@ -4,8 +4,8 @@ GIT v1.6.1.2 Release Notes
Fixes since v1.6.1.1
--------------------
* The logic for rename detectin in internal diff used by commands like
"git diff" and "git blame" have been optimized to avoid loading the same
* The logic for rename detection in internal diff used by commands like
"git diff" and "git blame" has been optimized to avoid loading the same
blob repeatedly.
* We did not allow writing out a blob that is larger than 2GB for no good

View File

@@ -0,0 +1,32 @@
GIT v1.6.1.3 Release Notes
==========================
Fixes since v1.6.1.2
--------------------
* "git diff --binary | git apply" pipeline did not work well when
a binary blob is changed to a symbolic link.
* Some combinations of -b/-w/--ignore-space-at-eol to "git diff" did
not work as expected.
* "git grep" did not pass the -I (ignore binary) option when
calling out an external grep program.
* "git log" and friends include HEAD to the set of starting points
when --all is given. This makes a difference when you are not
on any branch.
* "git mv" to move an untracked file to overwrite a tracked
contents misbehaved.
* "git merge -s octopus" with many potential merge bases did not
work correctly.
* RPM binary package installed the html manpages in a wrong place.
Also includes minor documentation fixes and updates.
--
git shortlog --no-merges v1.6.1.2-33-gc789350..

View File

@@ -0,0 +1,19 @@
GIT v1.6.1.4 Release Notes
==========================
Fixes since v1.6.1.3
--------------------
* "git fast-export" produced wrong output with some parents missing from
commits, when the history is clock-skewed.
* "git fast-import" sometimes failed to read back objects it just wrote
out and aborted, because it failed to flush stale cached data.
* "git repack" did not error out when necessary object was missing in the
repository.
Also includes minor documentation fixes and updates.
--
git shortlog --no-merges v1.6.1.3..

View File

@@ -1,6 +1,28 @@
GIT v1.6.2 Release Notes
========================
With the next major release, "git push" into a branch that is
currently checked out will be refused by default. You can choose
what should happen upon such a push by setting the configuration
variable receive.denyCurrentBranch in the receiving repository.
To ease the transition plan, the receiving repository of such a
push running this release will issue a big warning when the
configuration variable is missing. Please refer to:
http://git.or.cz/gitwiki/GitFaq#non-bare
http://thread.gmane.org/gmane.comp.version-control.git/107758/focus=108007
for more details on the reason why this change is needed and the
transition plan.
For a similar reason, "git push $there :$killed" to delete the branch
$killed in a remote repository $there, if $killed branch is the current
branch pointed at by its HEAD, gets a large warning. You can choose what
should happen upon such a push by setting the configuration variable
receive.denyDeleteCurrent in the receiving repository.
Updates since v1.6.1
--------------------
@@ -11,7 +33,9 @@ Updates since v1.6.1
* gitweb updates, including a new patch view and RSS/Atom feed
improvements.
(portability)
* (contrib/emacs) git.el now has commands for checking out a branch,
creating a branch, cherry-picking and reverting commits; vc-git.el
is not shipped with git anymore (it is part of official Emacs).
(performance)
@@ -24,17 +48,36 @@ Updates since v1.6.1
* @{-1} is a way to refer to the last branch you were on. This is
accepted not only where an object name is expected, but anywhere
a branch name is expected. E.g. "git branch --track mybranch @{-1}"
"git rev-parse --symbolic-full-name @{-1}".
a branch name is expected and acts as if you typed the branch name.
E.g. "git branch --track mybranch @{-1}", "git merge @{-1}", and
"git rev-parse --symbolic-full-name @{-1}" would work as expected.
* When refs/remotes/origin/HEAD points at a remote tracking branch that
has been pruned away, many git operations issued warning when they
internally enumerated the refs. We now warn only when you say "origin"
to refer to that pruned branch.
* The location of .mailmap file can be configured, and its file format was
enhanced to allow mapping an incorrect e-mail field as well.
* "git add -p" learned 'g'oto action to jump directly to a hunk.
* "git add -p" learned to find a hunk with given text with '/'.
* "git add -p" optionally can be told to work with just the command letter
without Enter.
* when "git am" stops upon a patch that does not apply, it shows the
title of the offending patch.
* "git am --directory=<dir>" and "git am --reject" passes these options
to underlying "git apply".
* "git am" learned --ignore-date option.
* "git blame" aligns author names better when they are spelled in
non US-ASCII encoding.
* "git clone" now makes its best effort when cloning from an empty
repository to set up configuration variables to refer to the remote
repository.
@@ -48,6 +91,9 @@ Updates since v1.6.1
the commit log message it serves via gitcvs.commitmsgannotation
configuration.
* "git cvsserver" learned to handle 'noop' command some CVS clients seem
to expect to work.
* "git diff" learned a new option --inter-hunk-context to coalesce close
hunks together and show context between them.
@@ -56,21 +102,17 @@ Updates since v1.6.1
* "git diff" learned --patience to run "patience diff" algorithm.
* Some combinations of -b/-w/--ignore-space-at-eol to "git diff" did
not work as expected.
* "git filter-branch" learned --prune-empty option that discards commits
that do not change the contents.
* "git fsck" now checks loose objects in alternate object stores, instead
of misreporting them as missing.
* "git gc --prune" was resurrected to allow "git gc --no-prune" and
giving non-default expiration period e.g. "git gc --prune=now".
* "git grep -w" and "git grep" for fixed strings have been optimized.
* "git log" and friends include HEAD to the set of starting points
when --all is given. This makes a difference when you are not on
any branch.
* "git ls-tree" learned --full-tree option that shows the path in full
regardless of where in the work tree hierarchy the command was started.
* "git mergetool" learned -y(--no-prompt) option to disable prompting.
* "git rebase -i" can transplant a history down to root to elsewhere
@@ -80,7 +122,10 @@ Updates since v1.6.1
"git checkout" switches branches, taking the local changes while
switching to another commit.
(internal)
* "git submodule update" learned --no-fetch option.
* "git tag" learned --contains that works the same way as the same option
from "git branch".
Fixes since v1.6.1
@@ -89,18 +134,31 @@ Fixes since v1.6.1
All of the fixes in v1.6.1.X maintenance series are included in this
release, unless otherwise noted.
Here are fixes that this release has, but have not been backported to
v1.6.1.X series.
* "git-add sub/file" when sub is a submodule incorrectly added the path to
the superproject.
* git-bundle did not exclude annotated tags even when a range given from the
command line wanted to.
* "git bundle" did not exclude annotated tags even when a range given
from the command line wanted to.
* "git filter-branch" unnecessarily refused to work when you had
checked out a different commit from what is recorded in the superproject
index in a submodule.
* "git filter-branch" incorrectly tried to update a nonexistent work tree
at the end when it is run in a bare repository.
* "git gc" did not work if your repository was created with an ancient git
and never had any pack files in it before.
* "git mergetool" used to ignore autocrlf and other attributes
based content rewriting.
* branch switching and merges had a silly bug that did not validate
the correct directory when making sure an existing subdirectory is
clean.
--
exec >/var/tmp/1
O=v1.6.1.2-252-g8c95d3c
echo O=$(git describe master)
git shortlog --no-merges $O..master ^maint
* "git -p cmd" when cmd is not a built-in one left the display in funny state
when killed in the middle.

View File

@@ -376,9 +376,36 @@ Thunderbird
(A Large Angry SCM)
By default, Thunderbird will both wrap emails as well as flag them as
being 'format=flowed', both of which will make the resulting email unusable
by git.
Here are some hints on how to successfully submit patches inline using
Thunderbird.
There are two different approaches. One approach is to configure
Thunderbird to not mangle patches. The second approach is to use
an external editor to keep Thunderbird from mangling the patches.
Approach #1 (configuration):
This recipe is current as of Thunderbird 2.0.0.19. Three steps:
1. Configure your mail server composition as plain text
Edit...Account Settings...Composition & Addressing,
uncheck 'Compose Messages in HTML'.
2. Configure your general composition window to not wrap
Edit..Preferences..Composition, wrap plain text messages at 0
3. Disable the use of format=flowed
Edit..Preferences..Advanced..Config Editor. Search for:
mailnews.send_plaintext_flowed
toggle it to make sure it is set to 'false'.
After that is done, you should be able to compose email as you
otherwise would (cut + paste, git-format-patch | git-imap-send, etc),
and the patches should not be mangled.
Approach #2 (external editor):
This recipe appears to work with the current [*1*] Thunderbird from Suse.
The following Thunderbird extensions are needed:

View File

@@ -41,6 +41,13 @@ of lines before or after the line given by <start>.
-S <revs-file>::
Use revs from revs-file instead of calling linkgit:git-rev-list[1].
--reverse::
Walk history forward instead of backward. Instead of showing
the revision in which a line appeared, this shows the last
revision in which a line has existed. This requires a range of
revision like START..END where the path to blame exists in
START.
-p::
--porcelain::
Show in a format designed for machine consumption.
@@ -67,7 +74,7 @@ of lines before or after the line given by <start>.
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
then A), the 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
@@ -83,8 +90,8 @@ commit.
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.
the command additionally looks for copies from all other
files in the parent for the commit that creates the file.
+
<num> is optional but it is the lower bound on the number of
alphanumeric characters that git must detect as moving

View File

@@ -422,19 +422,6 @@ relatively high IO latencies. With this set to 'true', git will do the
index comparison to the filesystem data in parallel, allowing
overlapping IO's.
core.notesRef::
When showing commit messages, also show notes which are stored in
the given ref. This ref is expected to contain files named
after the full SHA-1 of the commit they annotate.
+
If such a file exists in the given ref, the referenced blob is read, and
appended to the commit message, separated by a "Notes:" line. If the
given ref itself does not exist, it is not an error, but means that no
notes should be printed.
+
This setting defaults to "refs/notes/commits", and can be overridden by
the `GIT_NOTES_REF` environment variable.
alias.*::
Command aliases for the linkgit:git[1] command wrapper - e.g.
after defining "alias.last = cat-file commit HEAD", the invocation
@@ -569,8 +556,8 @@ color.interactive::
color.interactive.<slot>::
Use customized color for 'git-add --interactive'
output. `<slot>` may be `prompt`, `header`, or `help`, for
three distinct types of normal output from interactive
output. `<slot>` may be `prompt`, `header`, `help` or `error`, for
four distinct types of normal output from interactive
programs. The values of these variables may be specified as
in color.branch.<slot>.
@@ -1013,6 +1000,13 @@ instaweb.port::
The port number to bind the gitweb httpd to. See
linkgit:git-instaweb[1].
interactive.singlekey::
In interactive programs, allow the user to provide one-letter
input with a single key (i.e., without hitting enter).
Currently this is used only by the `\--patch` mode of
linkgit:git-add[1]. Note that this setting is silently
ignored if portable keystroke input is not available.
log.date::
Set default date-time mode for the log command. Setting log.date
value is similar to using 'git-log'\'s --date option. The value is one of the
@@ -1025,6 +1019,14 @@ log.showroot::
Tools like linkgit:git-log[1] or linkgit:git-whatchanged[1], which
normally hide the root commit will now show it. True by default.
mailmap.file::
The location of an augmenting mailmap file. The default
mailmap, located in the root of the repository, is loaded
first, then the mailmap file pointed to by this variable.
The location of the mailmap file may be in a repository
subdirectory, or somewhere outside of the repository itself.
See linkgit:git-shortlog[1] and linkgit:git-blame[1].
man.viewer::
Specify the programs that may be used to display help in the
'man' format. See linkgit:git-help[1].

View File

@@ -136,7 +136,7 @@ $ git add Documentation/\\*.txt
------------
+
Note that the asterisk `\*` is quoted from the shell in this
example; this lets the command to include the files from
example; this lets the command include the files from
subdirectories of `Documentation/` directory.
* Considers adding content from all git-*.sh scripts:
@@ -145,7 +145,7 @@ subdirectories of `Documentation/` directory.
$ git add git-*.sh
------------
+
Because this example lets shell expand the asterisk (i.e. you are
Because this example lets the shell expand the asterisk (i.e. you are
listing the files explicitly), it does not consider
`subdir/git-foo.sh`.
@@ -198,8 +198,8 @@ one deletion).
update::
This shows the status information and gives prompt
"Update>>". When the prompt ends with double '>>', you can
This shows the status information and issues an "Update>>"
prompt. When the prompt ends with double '>>', you can
make more than one selection, concatenated with whitespace or
comma. Also you can say ranges. E.g. "2-5 7,9" to choose
2,3,4,5,7,9 from the list. If the second number in a range is
@@ -238,8 +238,8 @@ add untracked::
patch::
This lets you choose one path out of 'status' like selection.
After choosing the path, it presents diff between the index
This lets you choose one path out of a 'status' like selection.
After choosing the path, it presents the diff between the index
and the working tree file and asks you if you want to stage
the change of each hunk. You can say:

View File

@@ -27,8 +27,8 @@ OPTIONS
-------
<mbox>|<Maildir>...::
The list of mailbox files to read patches from. If you do not
supply this argument, reads from the standard input. If you supply
directories, they'll be treated as Maildirs.
supply this argument, the command reads from the standard input.
If you supply directories, they will be treated as Maildirs.
-s::
--signoff::
@@ -48,7 +48,7 @@ OPTIONS
preferred encoding if it is not UTF-8).
+
This was optional in prior versions of git, but now it is the
default. You could use `--no-utf8` to override this.
default. You can use `--no-utf8` to override this.
--no-utf8::
Pass `-n` flag to 'git-mailinfo' (see
@@ -57,8 +57,8 @@ default. You could use `--no-utf8` to override this.
-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
3-way merge if the patch records the identity of blobs
it is supposed to apply to and we have those blobs
available locally.
--whitespace=<option>::
@@ -121,18 +121,18 @@ the commit, after stripping common prefix "[PATCH <anything>]".
It is supposed to describe what the commit is about concisely as
a one line text.
The body of the message (iow, after a blank line that terminates
RFC2822 headers) can begin with "Subject: " and "From: " lines
that are different from those of the mail header, to override
the values of these fields.
The body of the message (the rest of the message after the blank line
that terminates the RFC2822 headers) can begin with "Subject: " and
"From: " lines that are different from those of the mail header,
to override the values of these fields.
The commit message is formed by the title taken from the
"Subject: ", a blank line and the body of the message up to
where the patch begins. Excess whitespaces at the end of the
where the patch begins. Excess whitespace characters at the end of the
lines are automatically stripped.
The patch is expected to be inline, directly following the
message. Any line that is of form:
message. Any line that is of the form:
* three-dashes and end-of-line, or
* a line that begins with "diff -", or
@@ -141,18 +141,18 @@ message. Any line that is of form:
is taken as the beginning of a patch, and the commit log message
is terminated before the first occurrence of such a line.
When initially invoking it, you give it names of the mailboxes
to crunch. Upon seeing the first patch that does not apply, it
aborts in the middle,. You can recover from this in one of two ways:
When initially invoking it, you give it the names of the mailboxes
to process. Upon seeing the first patch that does not apply, it
aborts in the middle. You can recover from this in one of two ways:
. skip the current patch by re-running the command with '--skip'
. skip the current patch by re-running the command with the '--skip'
option.
. hand resolve the conflict in the working directory, and update
the index file to bring it in a state that the patch should
have produced. Then run the command with '--resolved' option.
the index file to bring it into a state that the patch should
have produced. Then run the command with the '--resolved' option.
The command refuses to process new mailboxes while `.git/rebase-apply`
The command refuses to process new mailboxes while the `.git/rebase-apply`
directory exists, so if you decide to start over from scratch,
run `rm -f -r .git/rebase-apply` before running the command with mailbox
names.

View File

@@ -3,7 +3,7 @@ git-annotate(1)
NAME
----
git-annotate - Annotate file lines with commit info
git-annotate - Annotate file lines with commit information
SYNOPSIS
--------
@@ -12,11 +12,11 @@ SYNOPSIS
DESCRIPTION
-----------
Annotates each line in the given file with information from the commit
which introduced the line. Optionally annotate from a given revision.
which introduced the line. Optionally annotates from a given revision.
The only difference between this command and linkgit:git-blame[1] is that
they use slightly different output formats, and this command exists only
for backward compatibility to support existing scripts, and provide more
for backward compatibility to support existing scripts, and provide a more
familiar command name for people coming from other SCM systems.
OPTIONS

View File

@@ -25,7 +25,7 @@ and a work tree.
OPTIONS
-------
<patch>...::
The files to read patch from. '-' can be used to read
The files to read the patch from. '-' can be used to read
from the standard input.
--stat::
@@ -33,8 +33,8 @@ OPTIONS
input. Turns off "apply".
--numstat::
Similar to \--stat, but shows number of added and
deleted lines in decimal notation and pathname without
Similar to \--stat, but shows the number of added and
deleted lines in decimal notation and the pathname without
abbreviation, to make it more machine friendly. For
binary files, outputs two `-` instead of saying
`0 0`. Turns off "apply".
@@ -60,15 +60,15 @@ OPTIONS
causes the index file to be updated.
--cached::
Apply a patch without touching the working tree. Instead, take the
cached data, apply the patch, and store the result in the index,
Apply a patch without touching the working tree. Instead take the
cached data, apply the patch, and store the result in the index
without using the working tree. This implies '--index'.
--build-fake-ancestor=<file>::
Newer 'git-diff' output has embedded 'index information'
for each blob to help identify the original version that
the patch applies to. When this flag is given, and if
the original versions of the blobs is available locally,
the original versions of the blobs are available locally,
builds a temporary index containing those blobs.
+
When a pure mode change is encountered (which has no index information),
@@ -109,13 +109,13 @@ the information is read from the current index instead.
applying a diff generated with --unified=0. To bypass these
checks use '--unidiff-zero'.
+
Note, for the reasons stated above usage of context-free patches are
Note, for the reasons stated above usage of context-free patches is
discouraged.
--apply::
If you use any of the options marked "Turns off
'apply'" above, 'git-apply' reads and outputs the
information you asked without actually applying the
requested information without actually applying the
patch. Give this flag after those flags to also apply
the patch.
@@ -124,7 +124,7 @@ discouraged.
patch. This can be used to extract the common part between
two files by first running 'diff' on them and applying
the result with this option, which would apply the
deletion part but not addition part.
deletion part but not the addition part.
--allow-binary-replacement::
--binary::
@@ -159,10 +159,10 @@ on the command line, and ignored if there is any include pattern.
considered whitespace errors.
+
By default, the command outputs warning messages but applies the patch.
When `git-apply is used for statistics and not applying a
When `git-apply` is used for statistics and not applying a
patch, it defaults to `nowarn`.
+
You can use different `<action>` to control this
You can use different `<action>` values to control this
behavior:
+
* `nowarn` turns off the trailing whitespace warning.
@@ -170,7 +170,7 @@ behavior:
patch as-is (default).
* `fix` outputs warnings for a few such errors, and applies the
patch after fixing them (`strip` is a synonym --- the tool
used to consider only trailing whitespaces as errors, and the
used to consider only trailing whitespace characters as errors, and the
fix involved 'stripping' them, but modern gits do more).
* `error` outputs warnings for a few such errors, and refuses
to apply the patch.
@@ -195,7 +195,7 @@ behavior:
adjusting the hunk headers appropriately).
--directory=<root>::
Prepend <root> to all filenames. If a "-p" argument was passed, too,
Prepend <root> to all filenames. If a "-p" argument was also passed,
it is applied before prepending the new root.
+
For example, a patch that talks about updating `a/git-gui.sh` to `b/git-gui.sh`
@@ -221,7 +221,7 @@ ignored, i.e., they are not required to be up-to-date or clean and they
are not updated.
If --index is not specified, then the submodule commits in the patch
are ignored and only the absence of presence of the corresponding
are ignored and only the absence or presence of the corresponding
subdirectory is checked and (if possible) updated.
Author

View File

@@ -88,6 +88,18 @@ tar.umask::
archiving user's umask will be used instead. See umask(2) for
details.
ATTRIBUTES
----------
export-ignore::
Files and directories with the attribute export-ignore won't be
added to archive files. See linkgit:gitattributes[5] for details.
export-subst::
If the attribute export-subst is set for a file then git will
expand several placeholders when adding this file to an archive.
See linkgit:gitattributes[5] for details.
EXAMPLES
--------
git archive --format=tar --prefix=junk/ HEAD | (cd /var/tmp/ && tar xf -)::
@@ -110,6 +122,11 @@ git archive --format=zip --prefix=git-docs/ HEAD:Documentation/ > git-1.4.0-docs
Put everything in the current head's Documentation/ directory
into 'git-1.4.0-docs.zip', with the prefix 'git-docs/'.
SEE ALSO
--------
linkgit:gitattributes[5]
Author
------
Written by Franck Bui-Huu and Rene Scharfe.

View File

@@ -10,7 +10,7 @@ SYNOPSIS
[verse]
'git blame' [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-p] [-w] [--incremental] [-L n,m]
[-S <revs-file>] [-M] [-C] [-C] [--since=<date>]
[<rev> | --contents <file>] [--] <file>
[<rev> | --contents <file> | --reverse <rev>] [--] <file>
DESCRIPTION
-----------
@@ -184,6 +184,12 @@ there is ever added information (like the commit encoding or extended
commit commentary), a blame viewer won't ever care.
MAPPING AUTHORS
---------------
include::mailmap.txt[]
SEE ALSO
--------
linkgit:git-annotate[1]

View File

@@ -107,17 +107,17 @@ incremental bundle,
----------------
machineA$ cd R1
machineA$ git bundle create file.bdl master
machineA$ git bundle create file.bundle master
machineA$ git tag -f lastR2bundle master
----------------
Then you sneakernet file.bdl to the target machine B. Because you don't
Then you sneakernet file.bundle to the target machine B. Because you don't
have to have any object to extract objects from such a bundle, not only
you can fetch/pull from a bundle, you can clone from it as if it was a
remote repository.
----------------
machineB$ git clone /home/me/tmp/file.bdl R2
machineB$ git clone /home/me/tmp/file.bundle R2
----------------
This will define a remote called "origin" in the resulting repository that
@@ -126,12 +126,12 @@ have an entry like this:
------------------------
[remote "origin"]
url = /home/me/tmp/file.bdl
url = /home/me/tmp/file.bundle
fetch = refs/heads/*:refs/remotes/origin/*
------------------------
You can fetch/pull to update the resulting mine.git repository after
replacing the bundle you store at /home/me/tmp/file.bdl with incremental
replacing the bundle you store at /home/me/tmp/file.bundle with incremental
updates from here on.
After working more in the original repository, you can create an
@@ -139,11 +139,11 @@ incremental bundle to update the other:
----------------
machineA$ cd R1
machineA$ git bundle create file.bdl lastR2bundle..master
machineA$ git bundle create file.bundle lastR2bundle..master
machineA$ git tag -f lastR2bundle master
----------------
and sneakernet it to the other machine to replace /home/me/tmp/file.bdl,
and sneakernet it to the other machine to replace /home/me/tmp/file.bundle,
and pull from it.
----------------

View File

@@ -212,6 +212,11 @@ git filter-branch --index-filter 'git rm --cached filename' HEAD
Now, you will get the rewritten history saved in HEAD.
As with using `rm filename`, `git rm --cached filename` will fail
if the file is absent from the tree of a commit. If it is not important
whether the file is already absent from the tree, you can use
`git rm --cached --ignore-unmatch filename` instead.
To rewrite the repository to look as if `foodir/` had been its project
root, and discard all other history:
@@ -334,6 +339,47 @@ git filter-branch --index-filter \
---------------------------------------------------------------
Checklist for Shrinking a Repository
------------------------------------
git-filter-branch is often used to get rid of a subset of files,
usually with some combination of `\--index-filter` and
`\--subdirectory-filter`. People expect the resulting repository to
be smaller than the original, but you need a few more steps to
actually make it smaller, because git tries hard not to lose your
objects until you tell it to. First make sure that:
* You really removed all variants of a filename, if a blob was moved
over its lifetime. `git log \--name-only \--follow \--all \--
filename` can help you find renames.
* You really filtered all refs: use `\--tag-name-filter cat \--
\--all` when calling git-filter-branch.
Then there are two ways to get a smaller repository. A safer way is
to clone, that keeps your original intact.
* Clone it with `git clone +++file:///path/to/repo+++`. The clone
will not have the removed objects. See linkgit:git-clone[1]. (Note
that cloning with a plain path just hardlinks everything!)
If you really don't want to clone it, for whatever reasons, check the
following points instead (in this order). This is a very destructive
approach, so *make a backup* or go back to cloning it. You have been
warned.
* Remove the original refs backed up by git-filter-branch: say `git
for-each-ref \--format="%(refname)" refs/original/ | xargs -n 1 git
update-ref -d`.
* Expire all reflogs with `git reflog expire \--expire=now \--all`.
* Garbage collect all unreferenced objects with `git gc \--prune=now`
(or if your git-gc is not new enough to support arguments to
`\--prune`, use `git repack -ad; git prune` instead).
Author
------
Written by Petr "Pasky" Baudis <pasky@suse.cz>,

View File

@@ -8,7 +8,7 @@ git-gc - Cleanup unnecessary files and optimize the local repository
SYNOPSIS
--------
'git gc' [--aggressive] [--auto] [--quiet]
'git gc' [--aggressive] [--auto] [--quiet] [--prune=<date> | --no-prune]
DESCRIPTION
-----------
@@ -59,6 +59,14 @@ are consolidated into a single pack by using the `-A` option of
'git-repack'. Setting `gc.autopacklimit` to 0 disables
automatic consolidation of packs.
--prune=<date>::
Prune loose objects older than date (default is 2 weeks ago,
overrideable by the config variable `gc.pruneExpire`). This
option is on by default.
--no-prune::
Do not prune any loose objects.
--quiet::
Suppress all progress reports.

View File

@@ -98,6 +98,20 @@ Using direct mode with SSL:
..........................
CAUTION
-------
It is still your responsibility to make sure that the email message
sent by your email program meets the standards of your project.
Many projects do not like patches to be attached. Some mail
agents will transform patches (e.g. wrap lines, send them as
format=flowed) in ways that make them fail. You will get angry
flames ridiculing you if you don't check this.
Thunderbird in particular is known to be problematic. Thunderbird
users may wish to visit this web page for more information:
http://kb.mozillazine.org/Plain_text_e-mail_-_Thunderbird#Completely_plain_email
BUGS
----
Doesn't handle lines starting with "From " in the message body.

View File

@@ -1,46 +0,0 @@
git-notes(1)
============
NAME
----
git-notes - Add/inspect commit notes
SYNOPSIS
--------
[verse]
'git-notes' (edit | show) [commit]
DESCRIPTION
-----------
This command allows you to add notes to commit messages, without
changing the commit. To discern these notes from the message stored
in the commit object, the notes are indented like the message, after
an unindented line saying "Notes:".
To disable commit notes, you have to set the config variable
core.notesRef to the empty string. Alternatively, you can set it
to a different ref, something like "refs/notes/bugzilla". This setting
can be overridden by the environment variable "GIT_NOTES_REF".
SUBCOMMANDS
-----------
edit::
Edit the notes for a given commit (defaults to HEAD).
show::
Show the notes for a given commit (defaults to HEAD).
Author
------
Written by Johannes Schindelin <johannes.schindelin@gmx.de>
Documentation
-------------
Documentation by Johannes Schindelin
GIT
---
Part of the gitlink:git[7] suite

View File

@@ -9,7 +9,7 @@ git-push - Update remote refs along with associated objects
SYNOPSIS
--------
[verse]
'git push' [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>]
'git push' [--all | --mirror | --tags] [--dry-run] [--receive-pack=<git-receive-pack>]
[--repo=<repository>] [-f | --force] [-v | --verbose]
[<repository> <refspec>...]
@@ -48,17 +48,19 @@ push. Arbitrary expressions cannot be used here, an actual ref must
be named. If `:`<dst> is omitted, the same ref as <src> will be
updated.
+
The object referenced by <src> is used to fast forward the ref <dst>
on the remote side. If the optional leading plus `{plus}` is used, the
remote ref is updated even if it does not result in a fast forward
update.
The object referenced by <src> is used to update the <dst> reference
on the remote side, but by default this is only allowed if the
update can fast forward <dst>. By having the optional leading `{plus}`,
you can tell git to update the <dst> ref even when the update is not a
fast forward. This does *not* attempt to merge <src> into <dst>. See
EXAMPLES below for details.
+
`tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.
+
Pushing an empty <src> allows you to delete the <dst> ref from
the remote repository.
+
The special refspec `:` (or `+:` to allow non-fast forward updates)
The special refspec `:` (or `{plus}:` to allow non-fast forward updates)
directs git to push "matching" branches: for every branch that exists on
the local side, the remote side is updated if a branch of the same name
already exists on the remote side. This is the default operation mode
@@ -218,6 +220,30 @@ git push origin :experimental::
Find a ref that matches `experimental` in the `origin` repository
(e.g. `refs/heads/experimental`), and delete it.
git push origin {plus}dev:master::
Update the origin repository's master branch with the dev branch,
allowing non-fast forward updates. *This can leave unreferenced
commits dangling in the origin repository.* Consider the
following situation, where a fast forward is not possible:
+
----
o---o---o---A---B origin/master
\
X---Y---Z dev
----
+
The above command would change the origin repository to
+
----
A---B (unnamed branch)
/
o---o---o---X---Y---Z master
----
+
Commits A and B would no longer belong to a branch with a symbolic name,
and so would be unreachable. As such, these commits would be removed by
a `git gc` command on the origin repository.
Author
------

View File

@@ -243,9 +243,10 @@ OPTIONS
context exist they all must match. By default no context is
ever ignored.
--whitespace=<nowarn|warn|error|error-all|strip>::
--whitespace=<option>::
This flag is passed to the 'git-apply' program
(see linkgit:git-apply[1]) that applies the patch.
Incompatible with the --interactive option.
-i::
--interactive::

View File

@@ -19,6 +19,19 @@ The header of the email is configurable by command line options. If not
specified on the command line, the user will be prompted with a ReadLine
enabled interface to provide the necessary information.
There are two formats accepted for patch files:
1. mbox format files
+
This is what linkgit:git-format-patch[1] generates. Most headers and MIME
formatting are ignored.
2. The original format used by Greg Kroah-Hartman's 'send_lots_of_email.pl'
script
+
This format expects the first line of the file to contain the "Cc:" value
and the "Subject:" of the message as the second line.
OPTIONS
-------

View File

@@ -45,45 +45,16 @@ OPTIONS
and subsequent lines are indented by `indent2` spaces. `width`,
`indent1`, and `indent2` default to 76, 6 and 9 respectively.
FILES
-----
If a file `.mailmap` exists at the toplevel of the repository,
it is used to map an author email address to a canonical real name. This
can be used to coalesce together commits by the same person where their
name was spelled differently (whether with the same email address or
not).
MAPPING AUTHORS
---------------
Each line in the file consists, in this order, of the canonical real name
of an author, whitespace, and an email address (enclosed by '<' and '>')
to map to the name. Use hash '#' for comments, either on their own line,
or after the email address.
The `.mailmap` feature is used to coalesce together commits by the same
person in the shortlog, where their name and/or email address was
spelled differently.
A canonical name may appear in more than one line, associated with
different email addresses, but it doesn't make sense for a given address
to appear more than once (if that happens, a later line overrides the
earlier ones).
include::mailmap.txt[]
So, for example, if your history contains commits by two authors, Jane
and Joe, whose names appear in the repository under several forms:
------------
Joe Developer <joe@example.com>
Joe R. Developer <joe@example.com>
Jane Doe <jane@example.com>
Jane Doe <jane@laptop.(none)>
Jane D. <jane@desktop.(none)>
------------
Then, supposing Joe wants his middle name initial used, and Jane prefers
her family name fully spelled out, a proper `.mailmap` file would look like:
------------
# Note how we don't need an entry for <jane@laptop.(none)>, because the
# real name of that author is correct already, and coalesced directly.
Jane Doe <jane@desktop.(none)>
Joe R. Developer <joe@example.com>
------------
Author
------

View File

@@ -12,7 +12,7 @@ SYNOPSIS
'git submodule' [--quiet] add [-b branch] [--] <repository> <path>
'git submodule' [--quiet] status [--cached] [--] [<path>...]
'git submodule' [--quiet] init [--] [<path>...]
'git submodule' [--quiet] update [--init] [--] [<path>...]
'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--] [<path>...]
'git submodule' [--quiet] summary [--summary-limit <n>] [commit] [--] [<path>...]
'git submodule' [--quiet] foreach <command>
'git submodule' [--quiet] sync [--] [<path>...]
@@ -172,6 +172,11 @@ OPTIONS
(the default). This limit only applies to modified submodules. The
size is always limited to 1 for added/deleted/typechanged submodules.
-N::
--no-fetch::
This option is only valid for the update command.
Don't fetch new objects from the remote site.
<path>...::
Paths to submodule(s). When specified this will restrict the command
to only operate on the submodules found at the specified paths.

View File

@@ -169,6 +169,10 @@ and have no uncommitted changes.
reused if a user is later given access to an alternate transport
method (e.g. `svn+ssh://` or `https://`) for commit.
config key: svn-remote.<name>.commiturl
config key: svn.commiturl (overwrites all svn-remote.<name>.commiturl options)
Using this option for any other purpose (don't ask)
is very strongly discouraged.
--
@@ -499,6 +503,14 @@ svn-remote.<name>.rewriteRoot::
the repository with a public http:// or svn:// URL in the
metadata so users of it will see the public URL.
svn.brokenSymlinkWorkaround::
This disables potentially expensive checks to workaround broken symlinks
checked into SVN by broken clients. Set this option to "false" if you
track a SVN repository with many empty blobs that are not symlinks.
This option may be changed while "git-svn" is running and take effect on
the next revision fetched. If unset, git-svn assumes this option to be
"true".
--
Since the noMetadata, rewriteRoot, useSvnsyncProps and useSvmProps

View File

@@ -43,9 +43,16 @@ unreleased) version of git, that is available from 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
* link:v1.6.1.1/git.html[documentation for release 1.6.1.1]
* link:v1.6.2/git.html[documentation for release 1.6.2]
* release notes for
link:RelNotes-1.6.2.txt[1.6.2].
* link:v1.6.1.3/git.html[documentation for release 1.6.1.3]
* release notes for
link:RelNotes-1.6.1.3.txt[1.6.1.3],
link:RelNotes-1.6.1.2.txt[1.6.1.2],
link:RelNotes-1.6.1.1.txt[1.6.1.1],
link:RelNotes-1.6.1.txt[1.6.1].

View File

@@ -18,10 +18,10 @@ A `gitattributes` file is a simple text file that gives
Each line in `gitattributes` file is of form:
glob attr1 attr2 ...
pattern attr1 attr2 ...
That is, a glob pattern followed by an attributes list,
separated by whitespaces. When the glob pattern matches the
That is, a pattern followed by an attributes list,
separated by whitespaces. When the pattern matches the
path in question, the attributes listed on the line are given to
the path.
@@ -48,13 +48,14 @@ Set to a value::
Unspecified::
No glob pattern matches the path, and nothing says if
No pattern matches the path, and nothing says if
the path has or does not have the attribute, the
attribute for the path is said to be Unspecified.
When more than one glob pattern matches the path, a later line
When more than one pattern matches the path, a later line
overrides an earlier line. This overriding is done per
attribute.
attribute. The rules how the pattern matches paths are the
same as in `.gitignore` files; see linkgit:gitignore[5].
When deciding what attributes are assigned to a path, git
consults `$GIT_DIR/info/attributes` file (which has the highest

View File

@@ -47,7 +47,8 @@ frequently used options.
After an attempt to merge stops with conflicts, show the commits on
the history between two branches (i.e. the HEAD and the MERGE_HEAD)
that modify the conflicted files.
that modify the conflicted files and do not exist on all the heads
being merged.
--argscmd=<command>::
Command to be run each time gitk has to determine the list of
@@ -73,7 +74,7 @@ frequently used options.
<path>...::
Limit commits to the ones touching files in the given paths. Note, to
avoid ambiguity wrt. revision names use "--" to separate the paths
avoid ambiguity with respect to revision names use "--" to separate the paths
from any preceding options.
Examples

View File

@@ -39,7 +39,7 @@ Such a "revert" of a merge can be made with:
$ git revert -m 1 M
After the develpers of the side branch fixes their mistakes, the history
After the developers of the side branch fix their mistakes, the history
may look like this:
---o---o---o---M---x---x---W---x
@@ -116,7 +116,7 @@ If you reverted the revert in such a case as in the previous example:
/ \ /
---A---B A'--B'--C'
where Y is the revert of W, A' and B'are rerolled A and B, and there may
where Y is the revert of W, A' and B' are rerolled A and B, and there may
also be a further fix-up C' on the side branch. "diff Y^..Y" is similar
to "diff -R W^..W" (which in turn means it is similar to "diff M^..M"),
and "diff A'^..C'" by definition would be similar but different from that,

View File

@@ -143,7 +143,7 @@ Then, add something like this to your httpd.conf
Require valid-user
</Location>
Debian automatically reads all files under /etc/apach2/conf.d.
Debian automatically reads all files under /etc/apache2/conf.d.
The password file can be somewhere else, but it has to be readable by
Apache and preferably not readable by the world.

75
Documentation/mailmap.txt Normal file
View File

@@ -0,0 +1,75 @@
If the file `.mailmap` exists at the toplevel of the repository, or at
the location pointed to by the mailmap.file configuration option, it
is used to map author and committer names and email addresses to
canonical real names and email addresses.
In the simple form, each line in the file consists of the canonical
real name of an author, whitespace, and an email address used in the
commit (enclosed by '<' and '>') to map to the name. Thus, looks like
this
--
Proper Name <commit@email.xx>
--
The more complex forms are
--
<proper@email.xx> <commit@email.xx>
--
which allows mailmap to replace only the email part of a commit, and
--
Proper Name <proper@email.xx> <commit@email.xx>
--
which allows mailmap to replace both the name and the email of a
commit matching the specified commit email address, and
--
Proper Name <proper@email.xx> Commit Name <commit@email.xx>
--
which allows mailmap to replace both the name and the email of a
commit matching both the specified commit name and email address.
Example 1: Your history contains commits by two authors, Jane
and Joe, whose names appear in the repository under several forms:
------------
Joe Developer <joe@example.com>
Joe R. Developer <joe@example.com>
Jane Doe <jane@example.com>
Jane Doe <jane@laptop.(none)>
Jane D. <jane@desktop.(none)>
------------
Now suppose that Joe wants his middle name initial used, and Jane
prefers her family name fully spelled out. A proper `.mailmap` file
would look like:
------------
Jane Doe <jane@desktop.(none)>
Joe R. Developer <joe@example.com>
------------
Note how we don't need an entry for <jane@laptop.(none)>, because the
real name of that author is correct already.
Example 2: Your repository contains commits from the following
authors:
------------
nick1 <bugs@company.xx>
nick2 <bugs@company.xx>
nick2 <nick2@company.xx>
santa <me@company.xx>
claus <me@company.xx>
CTO <cto@coompany.xx>
------------
Then, you might want a `.mailmap` file looking like:
------------
<cto@company.xx> <cto@coompany.xx>
Some Dude <some@dude.xx> nick1 <bugs@company.xx>
Other Author <other@author.xx> nick2 <bugs@company.xx>
Other Author <other@author.xx> <nick2@company.xx>
Santa Claus <santa.claus@northpole.xx> <me@company.xx>
------------
Use hash '#' for comments that are either on their own line, or after
the email address.

View File

@@ -101,16 +101,18 @@ The placeholders are:
- '%P': parent hashes
- '%p': abbreviated parent hashes
- '%an': author name
- '%aN': author name (respecting .mailmap)
- '%aN': author name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
- '%ae': author email
- '%aE': author email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
- '%ad': author date (format respects --date= option)
- '%aD': author date, RFC2822 style
- '%ar': author date, relative
- '%at': author date, UNIX timestamp
- '%ai': author date, ISO 8601 format
- '%cn': committer name
- '%cN': committer name (respecting .mailmap)
- '%cN': committer name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
- '%ce': committer email
- '%cE': committer email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
- '%cd': committer date
- '%cD': committer date, RFC2822 style
- '%cr': committer date, relative

View File

@@ -13,7 +13,7 @@ include::pretty-options.txt[]
Synonym for `--date=relative`.
--date={relative,local,default,iso,rfc,short}::
--date={relative,local,default,iso,rfc,short,raw}::
Only takes effect for dates shown in human-readable format, such
as when using "--pretty". `log.date` config variable sets a default
@@ -31,6 +31,8 @@ format, often found in E-mail messages.
+
`--date=short` shows only date but not time, in `YYYY-MM-DD` format.
+
`--date=raw` shows the date in the internal raw git format `%s %z` format.
+
`--date=default` shows timestamps in the original timezone
(either committer's or author's).

View File

@@ -222,7 +222,7 @@ which can be used by the programmer of the callback as she sees fit.
Read a given size of data from a FILE* pointer to the buffer.
+
NOTE: The buffer is rewinded if the read fails. If -1 is returned,
NOTE: The buffer is rewound if the read fails. If -1 is returned,
`errno` must be consulted, like you would do for `read(3)`.
`strbuf_read()`, `strbuf_read_file()` and `strbuf_getline()` has the
same behaviour as well.

View File

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

View File

@@ -228,7 +228,7 @@ GITWEB_FAVICON = git-favicon.png
GITWEB_SITE_HEADER =
GITWEB_SITE_FOOTER =
export prefix bindir sharedir htmldir sysconfdir
export prefix bindir sharedir sysconfdir
CC = gcc
AR = ar
@@ -265,7 +265,6 @@ SCRIPT_SH += git-merge-octopus.sh
SCRIPT_SH += git-merge-one-file.sh
SCRIPT_SH += git-merge-resolve.sh
SCRIPT_SH += git-mergetool.sh
SCRIPT_SH += git-notes.sh
SCRIPT_SH += git-parse-remote.sh
SCRIPT_SH += git-pull.sh
SCRIPT_SH += git-quiltimport.sh
@@ -318,8 +317,8 @@ PROGRAMS += git-var$X
# builtin-$C.o but is linked in as part of some other command.
BUILT_INS += $(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
BUILT_INS += git-cherry-pick$X
BUILT_INS += git-cherry$X
BUILT_INS += git-cherry-pick$X
BUILT_INS += git-format-patch$X
BUILT_INS += git-fsck-objects$X
BUILT_INS += git-get-tar-commit-id$X
@@ -358,8 +357,8 @@ LIB_H += builtin.h
LIB_H += cache.h
LIB_H += cache-tree.h
LIB_H += commit.h
LIB_H += compat/mingw.h
LIB_H += compat/cygwin.h
LIB_H += compat/mingw.h
LIB_H += csum-file.h
LIB_H += decorate.h
LIB_H += delta.h
@@ -378,14 +377,12 @@ LIB_H += ll-merge.h
LIB_H += log-tree.h
LIB_H += mailmap.h
LIB_H += merge-recursive.h
LIB_H += notes.h
LIB_H += object.h
LIB_H += pack.h
LIB_H += pack-refs.h
LIB_H += pack-revindex.h
LIB_H += parse-options.h
LIB_H += patch-ids.h
LIB_H += string-list.h
LIB_H += pkt-line.h
LIB_H += progress.h
LIB_H += quote.h
@@ -399,6 +396,7 @@ LIB_H += sha1-lookup.h
LIB_H += sideband.h
LIB_H += sigchain.h
LIB_H += strbuf.h
LIB_H += string-list.h
LIB_H += tag.h
LIB_H += transport.h
LIB_H += tree.h
@@ -437,8 +435,8 @@ LIB_OBJS += diffcore-order.o
LIB_OBJS += diffcore-pickaxe.o
LIB_OBJS += diffcore-rename.o
LIB_OBJS += diff-delta.o
LIB_OBJS += diff-no-index.o
LIB_OBJS += diff-lib.o
LIB_OBJS += diff-no-index.o
LIB_OBJS += diff.o
LIB_OBJS += dir.o
LIB_OBJS += editor.o
@@ -461,7 +459,6 @@ LIB_OBJS += match-trees.o
LIB_OBJS += merge-file.o
LIB_OBJS += merge-recursive.o
LIB_OBJS += name-hash.o
LIB_OBJS += notes.o
LIB_OBJS += object.o
LIB_OBJS += pack-check.o
LIB_OBJS += pack-refs.o
@@ -471,9 +468,9 @@ LIB_OBJS += pager.o
LIB_OBJS += parse-options.o
LIB_OBJS += patch-delta.o
LIB_OBJS += patch-ids.o
LIB_OBJS += string-list.o
LIB_OBJS += path.o
LIB_OBJS += pkt-line.o
LIB_OBJS += preload-index.o
LIB_OBJS += pretty.o
LIB_OBJS += progress.o
LIB_OBJS += quote.o
@@ -487,13 +484,14 @@ LIB_OBJS += revision.o
LIB_OBJS += run-command.o
LIB_OBJS += server-info.o
LIB_OBJS += setup.o
LIB_OBJS += sha1_file.o
LIB_OBJS += sha1-lookup.o
LIB_OBJS += sha1_file.o
LIB_OBJS += sha1_name.o
LIB_OBJS += shallow.o
LIB_OBJS += sideband.o
LIB_OBJS += sigchain.o
LIB_OBJS += strbuf.o
LIB_OBJS += string-list.o
LIB_OBJS += symlinks.o
LIB_OBJS += tag.o
LIB_OBJS += trace.o
@@ -502,8 +500,8 @@ LIB_OBJS += tree-diff.o
LIB_OBJS += tree.o
LIB_OBJS += tree-walk.o
LIB_OBJS += unpack-trees.o
LIB_OBJS += userdiff.o
LIB_OBJS += usage.o
LIB_OBJS += userdiff.o
LIB_OBJS += utf8.o
LIB_OBJS += walker.o
LIB_OBJS += wrapper.o
@@ -511,7 +509,6 @@ LIB_OBJS += write_or_die.o
LIB_OBJS += ws.o
LIB_OBJS += wt-status.o
LIB_OBJS += xdiff-interface.o
LIB_OBJS += preload-index.o
BUILTIN_OBJS += builtin-add.o
BUILTIN_OBJS += builtin-annotate.o
@@ -1476,8 +1473,8 @@ endif
bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \
execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \
{ $(RM) "$$execdir/git-add$X" && \
ln git-add$X "$$execdir/git-add$X" 2>/dev/null || \
cp git-add$X "$$execdir/git-add$X"; } && \
ln "$$bindir/git$X" "$$execdir/git-add$X" 2>/dev/null || \
cp "$$bindir/git$X" "$$execdir/git-add$X"; } && \
{ for p in $(filter-out git-add$X,$(BUILT_INS)); do \
$(RM) "$$execdir/$$p" && \
ln "$$execdir/git-add$X" "$$execdir/$$p" 2>/dev/null || \

14
README
View File

@@ -24,10 +24,18 @@ It was originally written by Linus Torvalds with help of a group of
hackers around the net. It is currently maintained by Junio C Hamano.
Please read the file INSTALL for installation instructions.
See Documentation/gittutorial.txt to get started, then see
Documentation/everyday.txt for a useful minimum set of commands,
and "man git-commandname" for documentation of each command.
CVS users may also want to read Documentation/cvs-migration.txt.
Documentation/everyday.txt for a useful minimum set of commands, and
Documentation/git-commandname.txt for documentation of each command.
If git has been correctly installed, then the tutorial can also be
read with "man gittutorial" or "git help tutorial", and the
documentation of each command with "man git-commandname" or "git help
commandname".
CVS users may also want to read Documentation/gitcvs-migration.txt
("man gitcvs-migration" or "git help cvs-migration" if git is
installed).
Many Git online resources are accessible from http://git.or.cz/
including full documentation and Git related tools.

View File

@@ -132,7 +132,7 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
err = write_entry(args, sha1, path.buf, path.len, mode, NULL, 0);
if (err)
return err;
return READ_TREE_RECURSIVE;
return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
}
buffer = sha1_file_to_archive(path_without_prefix, sha1, mode,

View File

@@ -103,14 +103,22 @@ void create_branch(const char *head,
struct ref_lock *lock;
struct commit *commit;
unsigned char sha1[20];
char *real_ref, ref[PATH_MAX], msg[PATH_MAX + 20];
char *real_ref, msg[PATH_MAX + 20];
struct strbuf ref = STRBUF_INIT;
int forcing = 0;
int len;
snprintf(ref, sizeof ref, "refs/heads/%s", name);
if (check_ref_format(ref))
len = strlen(name);
if (interpret_nth_last_branch(name, &ref) != len) {
strbuf_reset(&ref);
strbuf_add(&ref, name, len);
}
strbuf_splice(&ref, 0, 0, "refs/heads/", 11);
if (check_ref_format(ref.buf))
die("'%s' is not a valid branch name.", name);
if (resolve_ref(ref, sha1, 1, NULL)) {
if (resolve_ref(ref.buf, sha1, 1, NULL)) {
if (!force)
die("A branch named '%s' already exists.", name);
else if (!is_bare_repository() && !strcmp(head, name))
@@ -142,7 +150,7 @@ void create_branch(const char *head,
die("Not a valid branch point: '%s'.", start_name);
hashcpy(sha1, commit->object.sha1);
lock = lock_any_ref_for_update(ref, NULL, 0);
lock = lock_any_ref_for_update(ref.buf, NULL, 0);
if (!lock)
die("Failed to lock ref for update: %s.", strerror(errno));
@@ -162,6 +170,7 @@ void create_branch(const char *head,
if (write_ref_sha1(lock, sha1, msg) < 0)
die("Failed to write ref: %s.", strerror(errno));
strbuf_release(&ref);
free(real_ref);
}

View File

@@ -15,7 +15,7 @@ static const char * const builtin_add_usage[] = {
"git add [options] [--] <filepattern>...",
NULL
};
static int patch_interactive = 0, add_interactive = 0;
static int patch_interactive, add_interactive;
static int take_worktree_changes;
static void fill_pathspec_matches(const char **pathspec, char *seen, int specs)

View File

@@ -1264,11 +1264,12 @@ struct commit_info
* Parse author/committer line in the commit object buffer
*/
static void get_ac_line(const char *inbuf, const char *what,
int bufsz, char *person, const char **mail,
int person_len, char *person,
int mail_len, char *mail,
unsigned long *time, const char **tz)
{
int len, tzlen, maillen;
char *tmp, *endp, *timepos;
char *tmp, *endp, *timepos, *mailpos;
tmp = strstr(inbuf, what);
if (!tmp)
@@ -1279,10 +1280,11 @@ static void get_ac_line(const char *inbuf, const char *what,
len = strlen(tmp);
else
len = endp - tmp;
if (bufsz <= len) {
if (person_len <= len) {
error_out:
/* Ugh */
*mail = *tz = "(unknown)";
*tz = "(unknown)";
strcpy(mail, *tz);
*time = 0;
return;
}
@@ -1305,9 +1307,10 @@ static void get_ac_line(const char *inbuf, const char *what,
*tmp = 0;
while (*tmp != ' ')
tmp--;
*mail = tmp + 1;
mailpos = tmp + 1;
*tmp = 0;
maillen = timepos - tmp;
memcpy(mail, mailpos, maillen);
if (!mailmap.nr)
return;
@@ -1316,20 +1319,23 @@ static void get_ac_line(const char *inbuf, const char *what,
* mailmap expansion may make the name longer.
* make room by pushing stuff down.
*/
tmp = person + bufsz - (tzlen + 1);
tmp = person + person_len - (tzlen + 1);
memmove(tmp, *tz, tzlen);
tmp[tzlen] = 0;
*tz = tmp;
tmp = tmp - (maillen + 1);
memmove(tmp, *mail, maillen);
tmp[maillen] = 0;
*mail = tmp;
/*
* Now, convert e-mail using mailmap
* Now, convert both name and e-mail using mailmap
*/
map_email(&mailmap, tmp + 1, person, tmp-person-1);
if(map_user(&mailmap, mail+1, mail_len-1, person, tmp-person-1)) {
/* Add a trailing '>' to email, since map_user returns plain emails
Note: It already has '<', since we replace from mail+1 */
mailpos = memchr(mail, '\0', mail_len);
if (mailpos && mailpos-mail < mail_len - 1) {
*mailpos = '>';
*(mailpos+1) = '\0';
}
}
}
static void get_commit_info(struct commit *commit,
@@ -1338,8 +1344,10 @@ static void get_commit_info(struct commit *commit,
{
int len;
char *tmp, *endp, *reencoded, *message;
static char author_buf[1024];
static char committer_buf[1024];
static char author_name[1024];
static char author_mail[1024];
static char committer_name[1024];
static char committer_mail[1024];
static char summary_buf[1024];
/*
@@ -1357,9 +1365,11 @@ static void get_commit_info(struct commit *commit,
}
reencoded = reencode_commit_message(commit, NULL);
message = reencoded ? reencoded : commit->buffer;
ret->author = author_buf;
ret->author = author_name;
ret->author_mail = author_mail;
get_ac_line(message, "\nauthor ",
sizeof(author_buf), author_buf, &ret->author_mail,
sizeof(author_name), author_name,
sizeof(author_mail), author_mail,
&ret->author_time, &ret->author_tz);
if (!detailed) {
@@ -1367,9 +1377,11 @@ static void get_commit_info(struct commit *commit,
return;
}
ret->committer = committer_buf;
ret->committer = committer_name;
ret->committer_mail = committer_mail;
get_ac_line(message, "\ncommitter ",
sizeof(committer_buf), committer_buf, &ret->committer_mail,
sizeof(committer_name), committer_name,
sizeof(committer_mail), committer_mail,
&ret->committer_time, &ret->committer_tz);
ret->summary = summary_buf;
@@ -2396,7 +2408,7 @@ parse_done:
die("reading graft file %s failed: %s",
revs_file, strerror(errno));
read_mailmap(&mailmap, ".mailmap", NULL);
read_mailmap(&mailmap, NULL);
if (!incremental)
setup_pager();

View File

@@ -99,6 +99,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
const char *fmt, *remote;
int i;
int ret = 0;
struct strbuf bname = STRBUF_INIT;
switch (kinds) {
case REF_REMOTE_BRANCH:
@@ -119,20 +120,25 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
if (!head_rev)
die("Couldn't look up commit object for HEAD");
}
for (i = 0; i < argc; i++) {
if (kinds == REF_LOCAL_BRANCH && !strcmp(head, argv[i])) {
for (i = 0; i < argc; i++, strbuf_release(&bname)) {
int len = strlen(argv[i]);
if (interpret_nth_last_branch(argv[i], &bname) != len)
strbuf_add(&bname, argv[i], len);
if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
error("Cannot delete the branch '%s' "
"which you are currently on.", argv[i]);
"which you are currently on.", bname.buf);
ret = 1;
continue;
}
free(name);
name = xstrdup(mkpath(fmt, argv[i]));
name = xstrdup(mkpath(fmt, bname.buf));
if (!resolve_ref(name, sha1, 1, NULL)) {
error("%sbranch '%s' not found.",
remote, argv[i]);
remote, bname.buf);
ret = 1;
continue;
}
@@ -152,22 +158,23 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
if (!force &&
!in_merge_bases(rev, &head_rev, 1)) {
error("The branch '%s' is not an ancestor of "
"your current HEAD.\n"
"If you are sure you want to delete it, "
"run 'git branch -D %s'.", argv[i], argv[i]);
"your current HEAD.\n"
"If you are sure you want to delete it, "
"run 'git branch -D %s'.", bname.buf, bname.buf);
ret = 1;
continue;
}
if (delete_ref(name, sha1, 0)) {
error("Error deleting %sbranch '%s'", remote,
argv[i]);
bname.buf);
ret = 1;
} else {
struct strbuf buf = STRBUF_INIT;
printf("Deleted %sbranch %s (%s).\n", remote, argv[i],
find_unique_abbrev(sha1, DEFAULT_ABBREV));
strbuf_addf(&buf, "branch.%s", argv[i]);
printf("Deleted %sbranch %s (%s).\n", remote,
bname.buf,
find_unique_abbrev(sha1, DEFAULT_ABBREV));
strbuf_addf(&buf, "branch.%s", bname.buf);
if (git_config_rename_section(buf.buf, NULL) < 0)
warning("Update of config-file failed");
strbuf_release(&buf);

View File

@@ -350,6 +350,19 @@ static struct ref *write_remote_refs(const struct ref *refs,
return local_refs;
}
static void install_branch_config(const char *local,
const char *origin,
const char *remote)
{
struct strbuf key = STRBUF_INIT;
strbuf_addf(&key, "branch.%s.remote", local);
git_config_set(key.buf, origin);
strbuf_reset(&key);
strbuf_addf(&key, "branch.%s.merge", local);
git_config_set(key.buf, remote);
strbuf_release(&key);
}
int cmd_clone(int argc, const char **argv, const char *prefix)
{
int use_local_hardlinks = 1;
@@ -539,6 +552,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
head_points_at = NULL;
remote_head = NULL;
option_no_checkout = 1;
if (!option_bare)
install_branch_config("master", option_origin,
"refs/heads/master");
}
if (head_points_at) {
@@ -567,11 +583,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
head_points_at->peer_ref->name,
reflog_msg.buf);
strbuf_addf(&key, "branch.%s.remote", head);
git_config_set(key.buf, option_origin);
strbuf_reset(&key);
strbuf_addf(&key, "branch.%s.merge", head);
git_config_set(key.buf, head_points_at->name);
install_branch_config(head, option_origin,
head_points_at->name);
}
} else if (remote_head) {
/* Source had detached HEAD pointing somewhere. */

View File

@@ -561,7 +561,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
commitable = run_status(fp, index_file, prefix, 1);
wt_status_use_color = saved_color_setting;
} else {
struct rev_info rev;
unsigned char sha1[20];
const char *parent = "HEAD";
@@ -573,16 +572,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
if (get_sha1(parent, sha1))
commitable = !!active_nr;
else {
init_revisions(&rev, "");
rev.abbrev = 0;
setup_revisions(0, NULL, &rev, parent);
DIFF_OPT_SET(&rev.diffopt, QUIET);
DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);
run_diff_index(&rev, 1 /* cached */);
commitable = !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES);
}
else
commitable = index_differs_from(parent, 0);
}
fclose(fp);

View File

@@ -514,6 +514,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
get_tags_and_duplicates(&revs.pending, &extra_refs);
revs.topo_order = 1;
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
revs.diffopt.format_callback = show_filemodify;

View File

@@ -161,7 +161,8 @@ static int need_to_gc(void)
*/
if (too_many_packs())
append_option(argv_repack,
!strcmp(prune_expire, "now") ? "-a" : "-A",
prune_expire && !strcmp(prune_expire, "now") ?
"-a" : "-A",
MAX_ADD);
else if (!too_many_loose_objects())
return 0;
@@ -173,14 +174,15 @@ static int need_to_gc(void)
int cmd_gc(int argc, const char **argv, const char *prefix)
{
int prune = 0;
int aggressive = 0;
int auto_gc = 0;
int quiet = 0;
char buf[80];
struct option builtin_gc_options[] = {
OPT_BOOLEAN(0, "prune", &prune, "prune unreferenced objects (deprecated)"),
{ OPTION_STRING, 0, "prune", &prune_expire, "date",
"prune unreferenced objects",
PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
OPT_BOOLEAN(0, "aggressive", &aggressive, "be more thorough (increased runtime)"),
OPT_BOOLEAN(0, "auto", &auto_gc, "enable auto-gc mode"),
OPT_BOOLEAN('q', "quiet", &quiet, "suppress progress reports"),
@@ -218,7 +220,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
"\"git help gc\" for more information.\n");
} else
append_option(argv_repack,
!strcmp(prune_expire, "now") ? "-a" : "-A",
prune_expire && !strcmp(prune_expire, "now")
? "-a" : "-A",
MAX_ADD);
if (pack_refs && run_command_v_opt(argv_pack_refs, RUN_GIT_CMD))
@@ -230,9 +233,11 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (run_command_v_opt(argv_repack, RUN_GIT_CMD))
return error(FAILED_RUN, argv_repack[0]);
argv_prune[2] = prune_expire;
if (run_command_v_opt(argv_prune, RUN_GIT_CMD))
return error(FAILED_RUN, argv_prune[0]);
if (prune_expire) {
argv_prune[2] = prune_expire;
if (run_command_v_opt(argv_prune, RUN_GIT_CMD))
return error(FAILED_RUN, argv_prune[0]);
}
if (run_command_v_opt(argv_rerere, RUN_GIT_CMD))
return error(FAILED_RUN, argv_rerere[0]);

View File

@@ -262,6 +262,21 @@ static const char *verify_pathspec(const char *prefix)
return max ? xmemdupz(prev, max) : NULL;
}
static void strip_trailing_slash_from_submodules(void)
{
const char **p;
for (p = pathspec; *p != NULL; p++) {
int len = strlen(*p), pos;
if (len < 1 || (*p)[len - 1] != '/')
continue;
pos = cache_name_pos(*p, len - 1);
if (pos >= 0 && S_ISGITLINK(active_cache[pos]->ce_mode))
*p = xstrndup(*p, len - 1);
}
}
/*
* Read the tree specified with --with-tree option
* (typically, HEAD) into stage #1 and then
@@ -510,6 +525,11 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
pathspec = get_pathspec(prefix, argv + i);
/* be nice with submodule patsh ending in a slash */
read_cache();
if (pathspec)
strip_trailing_slash_from_submodules();
/* Verify that the pathspec matches the prefix */
if (pathspec)
prefix = verify_pathspec(prefix);
@@ -533,7 +553,6 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
show_killed | show_modified))
show_cached = 1;
read_cache();
if (prefix)
prune_cache(prefix);
if (with_tree) {

View File

@@ -68,13 +68,8 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
*
* Something similar to this incomplete example:
*
if (show_subprojects(base, baselen, pathname)) {
struct child_process ls_tree;
ls_tree.dir = base;
ls_tree.argv = ls-tree;
start_command(&ls_tree);
}
if (show_subprojects(base, baselen, pathname))
retval = READ_TREE_RECURSIVE;
*
*/
type = commit_type;

View File

@@ -356,9 +356,14 @@ static void merge_name(const char *remote, struct strbuf *msg)
struct object *remote_head;
unsigned char branch_head[20], buf_sha[20];
struct strbuf buf = STRBUF_INIT;
struct strbuf bname = STRBUF_INIT;
const char *ptr;
int len, early;
len = strlen(remote);
if (interpret_nth_last_branch(remote, &bname) == len)
remote = bname.buf;
memset(branch_head, 0, sizeof(branch_head));
remote_head = peel_to_type(remote, 0, NULL, OBJ_COMMIT);
if (!remote_head)
@@ -371,7 +376,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
if (!hashcmp(remote_head->sha1, branch_head)) {
strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
sha1_to_hex(branch_head), remote);
return;
goto cleanup;
}
/* See if remote matches <name>^^^.. or <name>~<number> */
@@ -411,7 +416,8 @@ static void merge_name(const char *remote, struct strbuf *msg)
sha1_to_hex(remote_head->sha1),
truname.buf + 11,
(early ? " (early part)" : ""));
return;
strbuf_release(&truname);
goto cleanup;
}
}
@@ -432,10 +438,13 @@ static void merge_name(const char *remote, struct strbuf *msg)
strbuf_remove(&line, ptr-line.buf+1, 13);
strbuf_addbuf(msg, &line);
strbuf_release(&line);
return;
goto cleanup;
}
strbuf_addf(msg, "%s\t\tcommit '%s'\n",
sha1_to_hex(remote_head->sha1), remote);
cleanup:
strbuf_release(&buf);
strbuf_release(&bname);
}
static int git_merge_config(const char *k, const char *v, void *cb)

View File

@@ -488,9 +488,8 @@ static void write_pack_file(void)
} else {
char tmpname[PATH_MAX];
int fd;
snprintf(tmpname, sizeof(tmpname),
"%s/pack/tmp_pack_XXXXXX", get_object_directory());
fd = xmkstemp(tmpname);
fd = odb_mkstemp(tmpname, sizeof(tmpname),
"pack/tmp_pack_XXXXXX");
pack_tmp_name = xstrdup(tmpname);
f = sha1fd(fd, pack_tmp_name);
}

View File

@@ -18,14 +18,16 @@ enum deny_action {
DENY_REFUSE,
};
static int deny_deletes = 0;
static int deny_non_fast_forwards = 0;
static int deny_deletes;
static int deny_non_fast_forwards;
static enum deny_action deny_current_branch = DENY_UNCONFIGURED;
static enum deny_action deny_delete_current = DENY_UNCONFIGURED;
static int receive_fsck_objects;
static int receive_unpack_limit = -1;
static int transfer_unpack_limit = -1;
static int unpack_limit = 100;
static int report_status;
static const char *head_name;
static char capabilities[] = " report-status delete-refs ";
static int capabilities_sent;
@@ -77,6 +79,11 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
return 0;
}
if (strcmp(var, "receive.denydeletecurrent") == 0) {
deny_delete_current = parse_deny_action(var, value);
return 0;
}
return git_default_config(var, value, cb);
}
@@ -203,16 +210,12 @@ static int run_update_hook(struct command *cmd)
static int is_ref_checked_out(const char *ref)
{
unsigned char sha1[20];
const char *head;
if (is_bare_repository())
return 0;
head = resolve_ref("HEAD", sha1, 0, NULL);
if (!head)
if (!head_name)
return 0;
return !strcmp(head, ref);
return !strcmp(head_name, ref);
}
static char *warn_unconfigured_deny_msg[] = {
@@ -241,7 +244,33 @@ static void warn_unconfigured_deny(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(warn_unconfigured_deny_msg); i++)
warning(warn_unconfigured_deny_msg[i]);
warning("%s", warn_unconfigured_deny_msg[i]);
}
static char *warn_unconfigured_deny_delete_current_msg[] = {
"Deleting the current branch can cause confusion by making the next",
"'git clone' not check out any file.",
"",
"You can set 'receive.denyDeleteCurrent' configuration variable to",
"'refuse' in the remote repository to disallow deleting the current",
"branch.",
"",
"You can set it to 'ignore' to allow such a delete without a warning.",
"",
"To make this warning message less loud, you can set it to 'warn'.",
"",
"Note that the default will change in a future version of git",
"to refuse deleting the current branch unless you have the",
"configuration variable set to either 'ignore' or 'warn'."
};
static void warn_unconfigured_deny_delete_current(void)
{
int i;
for (i = 0;
i < ARRAY_SIZE(warn_unconfigured_deny_delete_current_msg);
i++)
warning("%s", warn_unconfigured_deny_delete_current_msg[i]);
}
static const char *update(struct command *cmd)
@@ -278,12 +307,30 @@ static const char *update(struct command *cmd)
"but I can't find it!", sha1_to_hex(new_sha1));
return "bad pack";
}
if (deny_deletes && is_null_sha1(new_sha1) &&
!is_null_sha1(old_sha1) &&
!prefixcmp(name, "refs/heads/")) {
error("denying ref deletion for %s", name);
return "deletion prohibited";
if (!is_null_sha1(old_sha1) && is_null_sha1(new_sha1)) {
if (deny_deletes && !prefixcmp(name, "refs/heads/")) {
error("denying ref deletion for %s", name);
return "deletion prohibited";
}
if (!strcmp(name, head_name)) {
switch (deny_delete_current) {
case DENY_IGNORE:
break;
case DENY_WARN:
case DENY_UNCONFIGURED:
if (deny_delete_current == DENY_UNCONFIGURED)
warn_unconfigured_deny_delete_current();
warning("deleting the current branch");
break;
case DENY_REFUSE:
error("refusing to delete the current branch: %s", name);
return "deletion of the current branch prohibited";
}
}
}
if (deny_non_fast_forwards && !is_null_sha1(new_sha1) &&
!is_null_sha1(old_sha1) &&
!prefixcmp(name, "refs/heads/")) {
@@ -377,6 +424,7 @@ static void run_update_post_hook(struct command *cmd)
static void execute_commands(const char *unpacker_error)
{
struct command *cmd = commands;
unsigned char sha1[20];
if (unpacker_error) {
while (cmd) {
@@ -394,6 +442,8 @@ static void execute_commands(const char *unpacker_error)
return;
}
head_name = resolve_ref("HEAD", sha1, 0, NULL);
while (cmd) {
cmd->error_string = update(cmd);
cmd = cmd->next;

View File

@@ -756,12 +756,17 @@ static int prune(int argc, const char **argv)
OPT_END()
};
struct ref_states states;
const char *dangling_msg;
argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
if (argc < 1)
usage_with_options(builtin_remote_usage, options);
dangling_msg = (dry_run
? " %s will become dangling!\n"
: " %s has become dangling!\n");
memset(&states, 0, sizeof(states));
for (; argc; argc--, argv++) {
int i;
@@ -784,6 +789,7 @@ static int prune(int argc, const char **argv)
printf(" * [%s] %s\n", dry_run ? "would prune" : "pruned",
abbrev_ref(refname, "refs/remotes/"));
warn_dangling_symref(dangling_msg, refname);
}
/* NEEDSWORK: free remote */

View File

@@ -608,6 +608,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (!strcmp(arg, "--bisect-all")) {
bisect_list = 1;
bisect_find_all = 1;
revs.show_decorations = 1;
continue;
}
if (!strcmp(arg, "--bisect-vars")) {

View File

@@ -223,17 +223,6 @@ static char *help_msg(const unsigned char *sha1)
return helpbuf;
}
static int index_is_dirty(void)
{
struct rev_info rev;
init_revisions(&rev, NULL);
setup_revisions(0, NULL, &rev, "HEAD");
DIFF_OPT_SET(&rev.diffopt, QUIET);
DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);
run_diff_index(&rev, 1);
return !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES);
}
static struct tree *empty_tree(void)
{
struct tree *tree = xcalloc(1, sizeof(struct tree));
@@ -279,7 +268,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)
} else {
if (get_sha1("HEAD", head))
die ("You do not have a valid HEAD");
if (index_is_dirty())
if (index_differs_from("HEAD", 0))
die ("Dirty index: cannot %s", me);
}
discard_cache();

View File

@@ -40,6 +40,7 @@ static void insert_one_record(struct shortlog *log,
char *buffer, *p;
struct string_list_item *item;
char namebuf[1024];
char emailbuf[1024];
size_t len;
const char *eol;
const char *boemail, *eoemail;
@@ -51,7 +52,19 @@ static void insert_one_record(struct shortlog *log,
eoemail = strchr(boemail, '>');
if (!eoemail)
return;
if (!map_email(&log->mailmap, boemail+1, namebuf, sizeof(namebuf))) {
/* copy author name to namebuf, to support matching on both name and email */
memcpy(namebuf, author, boemail - author);
len = boemail - author;
while(len > 0 && isspace(namebuf[len-1]))
len--;
namebuf[len] = 0;
/* copy email name to emailbuf, to allow email replacement as well */
memcpy(emailbuf, boemail+1, eoemail - boemail);
emailbuf[eoemail - boemail - 1] = 0;
if (!map_user(&log->mailmap, emailbuf, sizeof(emailbuf), namebuf, sizeof(namebuf))) {
while (author < boemail && isspace(*author))
author++;
for (len = 0;
@@ -67,8 +80,8 @@ static void insert_one_record(struct shortlog *log,
if (log->email) {
size_t room = sizeof(namebuf) - len - 1;
int maillen = eoemail - boemail + 1;
snprintf(namebuf + len, room, " %.*s", maillen, boemail);
int maillen = strlen(emailbuf);
snprintf(namebuf + len, room, " <%.*s>", maillen, emailbuf);
}
item = string_list_insert(namebuf, &log->list);
@@ -219,7 +232,7 @@ void shortlog_init(struct shortlog *log)
{
memset(log, 0, sizeof(*log));
read_mailmap(&log->mailmap, ".mailmap", &log->common_repo_prefix);
read_mailmap(&log->mailmap, &log->common_repo_prefix);
log->list.strdup_strings = 1;
log->wrap = DEFAULT_WRAPLEN;
@@ -248,6 +261,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
struct parse_opt_ctx_t ctx;
prefix = setup_git_directory_gently(&nongit);
git_config(git_default_config, NULL);
shortlog_init(&log);
init_revisions(&rev, prefix);
parse_options_start(&ctx, argc, argv, PARSE_OPT_KEEP_DASHDASH |
@@ -320,6 +334,5 @@ void shortlog_output(struct shortlog *log)
log->list.strdup_strings = 1;
string_list_clear(&log->list, 1);
log->mailmap.strdup_strings = 1;
string_list_clear(&log->mailmap, 1);
clear_mailmap(&log->mailmap);
}

View File

@@ -45,8 +45,8 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
break;
case 2:
if (!strcmp(argv[0], "HEAD") &&
prefixcmp(argv[1], "refs/heads/"))
die("Refusing to point HEAD outside of refs/heads/");
prefixcmp(argv[1], "refs/"))
die("Refusing to point HEAD outside of refs/");
create_symref(argv[0], argv[1], msg);
break;
default:

View File

@@ -742,8 +742,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
if (newfd < 0) {
if (refresh_flags & REFRESH_QUIET)
exit(128);
die("unable to create '%s.lock': %s",
get_index_file(), strerror(lock_error));
unable_to_lock_index_die(get_index_file(), lock_error);
}
if (write_cache(newfd, active_cache, active_nr) ||
commit_locked_index(lock_file))

11
cache.h
View File

@@ -371,8 +371,6 @@ static inline enum object_type object_type(unsigned int mode)
#define GITATTRIBUTES_FILE ".gitattributes"
#define INFOATTRIBUTES_FILE "info/attributes"
#define ATTRIBUTE_MACRO_PREFIX "[attr]"
#define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
#define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
extern int is_bare_repository_cfg;
extern int is_bare_repository(void);
@@ -486,6 +484,7 @@ struct lock_file {
};
#define LOCK_DIE_ON_ERROR 1
#define LOCK_NODEREF 2
extern NORETURN void unable_to_lock_index_die(const char *path, int err);
extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
extern int hold_lock_file_for_append(struct lock_file *, const char *path, int);
extern int commit_lock_file(struct lock_file *);
@@ -544,7 +543,6 @@ enum rebase_setup_type {
extern enum branch_track git_branch_track;
extern enum rebase_setup_type autorebase;
extern char *notes_ref_name;
#define GIT_REPO_VERSION 0
extern int repository_format_version;
@@ -627,7 +625,7 @@ int is_directory(const char *);
const char *make_absolute_path(const char *path);
const char *make_nonrelative_path(const char *path);
const char *make_relative_path(const char *abs, const char *base);
int normalize_absolute_path(char *buf, const char *path);
int normalize_path_copy(char *dst, const char *src);
int longest_ancestor_length(const char *path, const char *prefix_list);
char *strip_path_suffix(const char *path, const char *suffix);
@@ -698,7 +696,8 @@ enum date_mode {
DATE_SHORT,
DATE_LOCAL,
DATE_ISO8601,
DATE_RFC2822
DATE_RFC2822,
DATE_RAW
};
const char *show_date(unsigned long time, int timezone, enum date_mode mode);
@@ -831,6 +830,7 @@ extern unsigned char* use_pack(struct packed_git *, struct pack_window **, off_t
extern void close_pack_windows(struct packed_git *);
extern void unuse_pack(struct pack_window **);
extern void free_pack_by_name(const char *);
extern void clear_delta_base_cache(void);
extern struct packed_git *add_packed_git(const char *, int, int);
extern const unsigned char *nth_packed_object_sha1(struct packed_git *, uint32_t);
extern off_t nth_packed_object_offset(const struct packed_git *, uint32_t);
@@ -871,6 +871,7 @@ extern int user_ident_explicitly_given;
extern const char *git_commit_encoding;
extern const char *git_log_output_encoding;
extern const char *git_mailmap_file;
/* IO helper functions */
extern void maybe_flush_or_die(FILE *, const char *);

View File

@@ -73,7 +73,6 @@ git-mktag plumbingmanipulators
git-mktree plumbingmanipulators
git-mv mainporcelain common
git-name-rev plumbinginterrogators
git-notes mainporcelain
git-pack-objects plumbingmanipulators
git-pack-redundant plumbinginterrogators
git-pack-refs ancillarymanipulators

View File

@@ -5,7 +5,6 @@
#include "utf8.h"
#include "diff.h"
#include "revision.h"
#include "notes.h"
int save_commit_buffer = 1;

View File

@@ -469,11 +469,6 @@ static int git_default_core_config(const char *var, const char *value)
return 0;
}
if (!strcmp(var, "core.notesref")) {
notes_ref_name = xstrdup(value);
return 0;
}
if (!strcmp(var, "core.pager"))
return git_config_string(&pager_program, var, value);
@@ -570,6 +565,15 @@ static int git_default_branch_config(const char *var, const char *value)
return 0;
}
static int git_default_mailmap_config(const char *var, const char *value)
{
if (!strcmp(var, "mailmap.file"))
return git_config_string(&git_mailmap_file, var, value);
/* Add other config variables here and to Documentation/config.txt. */
return 0;
}
int git_default_config(const char *var, const char *value, void *dummy)
{
if (!prefixcmp(var, "core."))
@@ -584,6 +588,9 @@ int git_default_config(const char *var, const char *value, void *dummy)
if (!prefixcmp(var, "branch."))
return git_default_branch_config(var, value);
if (!prefixcmp(var, "mailmap."))
return git_default_mailmap_config(var, value);
if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
pager_use_color = git_config_bool(var,value);
return 0;

View File

@@ -34,11 +34,11 @@
# are currently in a git repository. The %s token will be
# the name of the current branch.
#
# In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty
# value, unstaged (*) and staged (+) changes will be shown next
# to the branch name. You can configure this per-repository
# with the bash.showDirtyState variable, which defaults to true
# once GIT_PS1_SHOWDIRTYSTATE is enabled.
# In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty
# value, unstaged (*) and staged (+) changes will be shown next
# to the branch name. You can configure this per-repository
# with the bash.showDirtyState variable, which defaults to true
# once GIT_PS1_SHOWDIRTYSTATE is enabled.
#
# To submit patches:
#
@@ -125,7 +125,7 @@ __git_ps1 ()
local w
local i
if test -n "$GIT_PS1_SHOWDIRTYSTATE"; then
if test -n "${GIT_PS1_SHOWDIRTYSTATE-}"; then
if test "$(git config --bool bash.showDirtyState)" != "false"; then
git diff --no-ext-diff --ignore-submodules \
--quiet --exit-code || w="*"
@@ -975,6 +975,27 @@ _git_ls_tree ()
__git_complete_file
}
# Options that go well for log, shortlog and gitk
__git_log_common_options="
--not --all
--branches --tags --remotes
--first-parent --no-merges
--max-count=
--max-age= --since= --after=
--min-age= --until= --before=
"
# Options that go well for log and gitk (not shortlog)
__git_log_gitk_options="
--dense --sparse --full-history
--simplify-merges --simplify-by-decoration
--left-right
"
# Options that go well for log and shortlog (not gitk)
__git_log_shortlog_options="
--author= --committer= --grep=
--all-match
"
__git_log_pretty_formats="oneline short medium full fuller email raw format:"
_git_log ()
@@ -982,6 +1003,11 @@ _git_log ()
__git_has_doubledash && return
local cur="${COMP_WORDS[COMP_CWORD]}"
local g="$(git rev-parse --git-dir 2>/dev/null)"
local merge=""
if [ -f $g/MERGE_HEAD ]; then
merge="--merge"
fi
case "$cur" in
--pretty=*)
__gitcomp "$__git_log_pretty_formats
@@ -996,22 +1022,20 @@ _git_log ()
;;
--*)
__gitcomp "
--max-count= --max-age= --since= --after=
--min-age= --before= --until=
$__git_log_common_options
$__git_log_shortlog_options
$__git_log_gitk_options
--root --topo-order --date-order --reverse
--no-merges --follow
--follow
--abbrev-commit --abbrev=
--relative-date --date=
--author= --committer= --grep=
--all-match
--pretty=
--not --all
--left-right --cherry-pick
--cherry-pick
--graph
--decorate
--walk-reflogs
--parents --children --full-history
--merge
--parents --children
$merge
$__git_diff_common_options
--pickaxe-all --pickaxe-regex
"
@@ -1037,6 +1061,7 @@ _git_merge ()
--*)
__gitcomp "
--no-commit --no-stat --log --no-log --squash --strategy
--commit --stat --no-squash --ff --no-ff
"
return
esac
@@ -1196,10 +1221,14 @@ _git_config ()
__gitcomp "$(__git_merge_strategies)"
return
;;
color.branch|color.diff|color.status)
color.branch|color.diff|color.interactive|color.status|color.ui)
__gitcomp "always never auto"
return
;;
color.pager)
__gitcomp "false true"
return
;;
color.*.*)
__gitcomp "
normal black red green yellow blue magenta cyan white
@@ -1491,12 +1520,8 @@ _git_shortlog ()
case "$cur" in
--*)
__gitcomp "
--max-count= --max-age= --since= --after=
--min-age= --before= --until=
--no-merges
--author= --committer= --grep=
--all-match
--not --all
$__git_log_common_options
$__git_log_shortlog_options
--numbered --summary
"
return
@@ -1595,7 +1620,8 @@ _git_svn ()
local subcommands="
init fetch clone rebase dcommit log find-rev
set-tree commit-diff info create-ignore propget
proplist show-ignore show-externals
proplist show-ignore show-externals branch tag blame
migrate
"
local subcommand="$(__git_find_subcommand "$subcommands")"
if [ -z "$subcommand" ]; then
@@ -1606,13 +1632,15 @@ _git_svn ()
--follow-parent --authors-file= --repack=
--no-metadata --use-svm-props --use-svnsync-props
--log-window-size= --no-checkout --quiet
--repack-flags --user-log-author --localtime $remote_opts
--repack-flags --use-log-author --localtime
--ignore-paths= $remote_opts
"
local init_opts="
--template= --shared= --trunk= --tags=
--branches= --stdlayout --minimize-url
--no-metadata --use-svm-props --use-svnsync-props
--rewrite-root= $remote_opts
--rewrite-root= --prefix= --use-log-author
--add-author-from $remote_opts
"
local cmt_opts="
--edit --rmdir --find-copies-harder --copy-similarity=
@@ -1632,7 +1660,8 @@ _git_svn ()
dcommit,--*)
__gitcomp "
--merge --strategy= --verbose --dry-run
--fetch-all --no-rebase $cmt_opts $fc_opts
--fetch-all --no-rebase --commit-url
--revision $cmt_opts $fc_opts
"
;;
set-tree,--*)
@@ -1646,13 +1675,13 @@ _git_svn ()
__gitcomp "
--limit= --revision= --verbose --incremental
--oneline --show-commit --non-recursive
--authors-file=
--authors-file= --color
"
;;
rebase,--*)
__gitcomp "
--merge --verbose --strategy= --local
--fetch-all $fc_opts
--fetch-all --dry-run $fc_opts
"
;;
commit-diff,--*)
@@ -1661,6 +1690,21 @@ _git_svn ()
info,--*)
__gitcomp "--url"
;;
branch,--*)
__gitcomp "--dry-run --message --tag"
;;
tag,--*)
__gitcomp "--dry-run --message"
;;
blame,--*)
__gitcomp "--git-format"
;;
migrate,--*)
__gitcomp "
--config-dir= --ignore-paths= --minimize
--no-auth-cache --username=
"
;;
*)
COMPREPLY=()
;;
@@ -1804,7 +1848,11 @@ _gitk ()
fi
case "$cur" in
--*)
__gitcomp "--not --all $merge"
__gitcomp "
$__git_log_common_options
$__git_log_gitk_options
$merge
"
return
;;
esac

View File

@@ -2,7 +2,7 @@
EMACS = emacs
ELC = git.elc vc-git.elc git-blame.elc
ELC = git.elc git-blame.elc
INSTALL ?= install
INSTALL_ELC = $(INSTALL) -m 644
prefix ?= $(HOME)

39
contrib/emacs/README Normal file
View File

@@ -0,0 +1,39 @@
This directory contains various modules for Emacs support.
To make the modules available to Emacs, you should add this directory
to your load-path, and then require the modules you want. This can be
done by adding to your .emacs something like this:
(add-to-list 'load-path ".../git/contrib/emacs")
(require 'git)
(require 'git-blame)
The following modules are available:
* git.el:
Status manager that displays the state of all the files of the
project, and provides easy access to the most frequently used git
commands. The user interface is as far as possible compatible with
the pcl-cvs mode. It can be started with `M-x git-status'.
* git-blame.el:
Emacs implementation of incremental git-blame. When you turn it on
while viewing a file, the editor buffer will be updated by setting
the background of individual lines to a color that reflects which
commit it comes from. And when you move around the buffer, a
one-line summary will be shown in the echo area.
* vc-git.el:
This file used to contain the VC-mode backend for git, but it is no
longer distributed with git. It is now maintained as part of Emacs
and included in standard Emacs distributions starting from version
22.2.
If you have an earlier Emacs version, upgrading to Emacs 22 is
recommended, since the VC mode in older Emacs is not generic enough
to be able to support git in a reasonable manner, and no attempt has
been made to backport vc-git.el.

View File

@@ -1,6 +1,6 @@
;;; git.el --- A user interface for git
;; Copyright (C) 2005, 2006, 2007 Alexandre Julliard <julliard@winehq.org>
;; Copyright (C) 2005, 2006, 2007, 2008, 2009 Alexandre Julliard <julliard@winehq.org>
;; Version: 1.0
@@ -34,15 +34,21 @@
;; To start: `M-x git-status'
;;
;; TODO
;; - portability to XEmacs
;; - diff against other branch
;; - renaming files from the status buffer
;; - creating tags
;; - fetch/pull
;; - switching branches
;; - revlist browser
;; - git-show-branch browser
;; - menus
;;
;;; Compatibility:
;;
;; This file works on GNU Emacs 21 or later. It may work on older
;; versions but this is not guaranteed.
;;
;; It may work on XEmacs 21, provided that you first install the ewoc
;; and log-edit packages.
;;
(eval-when-compile (require 'cl))
@@ -222,7 +228,7 @@ the process output as a string, or nil if the git command failed."
(with-current-buffer buffer
(cd dir)
(apply #'call-process-region start end program
nil (list output-buffer nil) nil args))))
nil (list output-buffer t) nil args))))
(defun git-run-command-buffer (buffer-name &rest args)
"Run a git command, sending the output to a buffer named BUFFER-NAME."
@@ -239,13 +245,15 @@ the process output as a string, or nil if the git command failed."
(defun git-run-command-region (buffer start end env &rest args)
"Run a git command with specified buffer region as input."
(unless (eq 0 (if env
(git-run-process-region
buffer start end "env"
(append (git-get-env-strings env) (list "git") args))
(with-temp-buffer
(if (eq 0 (if env
(git-run-process-region
buffer start end "git" args)))
(error "Failed to run \"git %s\":\n%s" (mapconcat (lambda (x) x) args " ") (buffer-string))))
buffer start end "env"
(append (git-get-env-strings env) (list "git") args))
(git-run-process-region buffer start end "git" args)))
(buffer-string)
(display-message-or-buffer (current-buffer))
nil)))
(defun git-run-hook (hook env &rest args)
"Run a git hook and display its output if any."
@@ -397,6 +405,17 @@ the process output as a string, or nil if the git command failed."
(unless newval (push "-d" args))
(apply 'git-call-process-display-error "update-ref" args)))
(defun git-for-each-ref (&rest specs)
"Return a list of refs using git-for-each-ref.
Each entry is a cons of (SHORT-NAME . FULL-NAME)."
(let (refs)
(with-temp-buffer
(apply #'git-call-process t "for-each-ref" "--format=%(refname)" specs)
(goto-char (point-min))
(while (re-search-forward "^[^/\n]+/[^/\n]+/\\(.+\\)$" nil t)
(push (cons (match-string 1) (match-string 0)) refs)))
(nreverse refs)))
(defun git-read-tree (tree &optional index-file)
"Read a tree into the index file."
(let ((process-environment
@@ -447,18 +466,16 @@ the process output as a string, or nil if the git command failed."
(setq coding-system-for-write buffer-file-coding-system))
(let ((commit
(git-get-string-sha1
(with-output-to-string
(with-current-buffer standard-output
(let ((env `(("GIT_AUTHOR_NAME" . ,author-name)
("GIT_AUTHOR_EMAIL" . ,author-email)
("GIT_COMMITTER_NAME" . ,(git-get-committer-name))
("GIT_COMMITTER_EMAIL" . ,(git-get-committer-email)))))
(when author-date (push `("GIT_AUTHOR_DATE" . ,author-date) env))
(apply #'git-run-command-region
buffer log-start log-end env
"commit-tree" tree (nreverse args))))))))
(and (git-update-ref "HEAD" commit head subject)
commit))))
(let ((env `(("GIT_AUTHOR_NAME" . ,author-name)
("GIT_AUTHOR_EMAIL" . ,author-email)
("GIT_COMMITTER_NAME" . ,(git-get-committer-name))
("GIT_COMMITTER_EMAIL" . ,(git-get-committer-email)))))
(when author-date (push `("GIT_AUTHOR_DATE" . ,author-date) env))
(apply #'git-run-command-region
buffer log-start log-end env
"commit-tree" tree (nreverse args))))))
(when commit (git-update-ref "HEAD" commit head subject))
commit)))
(defun git-empty-db-p ()
"Check if the git db is empty (no commit done yet)."
@@ -513,9 +530,9 @@ the process output as a string, or nil if the git command failed."
(git-fileinfo->needs-refresh info) t)))
(defun git-status-filenames-map (status func files &rest args)
"Apply FUNC to the status files names in the FILES list."
"Apply FUNC to the status files names in the FILES list.
The list must be sorted."
(when files
(setq files (sort files #'string-lessp))
(let ((file (pop files))
(node (ewoc-nth status 0)))
(while (and file node)
@@ -528,7 +545,7 @@ the process output as a string, or nil if the git command failed."
(setq file (pop files))))))))
(defun git-set-filenames-state (status files state)
"Set the state of a list of named files."
"Set the state of a list of named files. The list must be sorted"
(when files
(git-status-filenames-map status #'git-set-fileinfo-state files state)
(unless state ;; delete files whose state has been set to nil
@@ -562,29 +579,29 @@ the process output as a string, or nil if the git command failed."
(let* ((old-type (lsh (or old-perm 0) -9))
(new-type (lsh (or new-perm 0) -9))
(str (case new-type
(?\100 ;; file
(64 ;; file
(case old-type
(?\100 nil)
(?\120 " (type change symlink -> file)")
(?\160 " (type change subproject -> file)")))
(?\120 ;; symlink
(64 nil)
(80 " (type change symlink -> file)")
(112 " (type change subproject -> file)")))
(80 ;; symlink
(case old-type
(?\100 " (type change file -> symlink)")
(?\160 " (type change subproject -> symlink)")
(64 " (type change file -> symlink)")
(112 " (type change subproject -> symlink)")
(t " (symlink)")))
(?\160 ;; subproject
(112 ;; subproject
(case old-type
(?\100 " (type change file -> subproject)")
(?\120 " (type change symlink -> subproject)")
(64 " (type change file -> subproject)")
(80 " (type change symlink -> subproject)")
(t " (subproject)")))
(?\110 nil) ;; directory (internal, not a real git state)
(?\000 ;; deleted or unknown
(72 nil) ;; directory (internal, not a real git state)
(0 ;; deleted or unknown
(case old-type
(?\120 " (symlink)")
(?\160 " (subproject)")))
(80 " (symlink)")
(112 " (subproject)")))
(t (format " (unknown type %o)" new-type)))))
(cond (str (propertize str 'face 'git-status-face))
((eq new-type ?\110) "/")
((eq new-type 72) "/")
(t ""))))
(defun git-rename-as-string (info)
@@ -733,6 +750,7 @@ Return the list of files that haven't been handled."
(let (unmerged-files)
(while (re-search-forward "[0-7]\\{6\\} [0-9a-f]\\{40\\} [123]\t\\([^\0]+\\)\0" nil t)
(push (match-string 1) unmerged-files))
(setq unmerged-files (nreverse unmerged-files)) ;; assume it is sorted already
(git-set-filenames-state status unmerged-files 'unmerged))))
(defun git-get-exclude-files ()
@@ -753,17 +771,18 @@ Return the list of files that haven't been handled."
(append options (mapcar (lambda (f) (concat "--exclude-from=" f)) exclude-files)))))
(defun git-update-status-files (&optional files mark-files)
"Update the status of FILES from the index."
"Update the status of FILES from the index.
The FILES list must be sorted."
(unless git-status (error "Not in git-status buffer."))
;; set the needs-update flag on existing files
(if (setq files (sort files #'string-lessp))
(if files
(git-status-filenames-map
git-status (lambda (info) (setf (git-fileinfo->needs-update info) t)) files)
(ewoc-map (lambda (info) (setf (git-fileinfo->needs-update info) t) nil) git-status)
(git-call-process nil "update-index" "--refresh")
(when git-show-uptodate
(git-run-ls-files-cached git-status nil 'uptodate)))
(let* ((remaining-files
(let ((remaining-files
(if (git-empty-db-p) ; we need some special handling for an empty db
(git-run-ls-files-cached git-status files 'added)
(git-run-diff-index git-status files))))
@@ -808,13 +827,13 @@ Return the list of files that haven't been handled."
(list (ewoc-data (ewoc-locate git-status)))))
(defun git-marked-files-state (&rest states)
"Return marked files that are in the specified states."
"Return a sorted list of marked files that are in the specified states."
(let ((files (git-marked-files))
result)
(dolist (info files)
(when (memq (git-fileinfo->state info) states)
(push info result)))
result))
(nreverse result)))
(defun git-refresh-files ()
"Refresh all files that need it and clear the needs-refresh flag."
@@ -1049,7 +1068,9 @@ Return the list of files that haven't been handled."
(unless files
(push (file-relative-name (read-file-name "File to remove: " nil nil t)) files))
(if (yes-or-no-p
(format "Remove %d file%s? " (length files) (if (> (length files) 1) "s" "")))
(if (cdr files)
(format "Remove %d files? " (length files))
(format "Remove %s? " (car files))))
(progn
(dolist (name files)
(ignore-errors
@@ -1068,7 +1089,9 @@ Return the list of files that haven't been handled."
added modified)
(when (and files
(yes-or-no-p
(format "Revert %d file%s? " (length files) (if (> (length files) 1) "s" ""))))
(if (cdr files)
(format "Revert %d files? " (length files))
(format "Revert %s? " (git-fileinfo->name (car files))))))
(dolist (info files)
(case (git-fileinfo->state info)
('added (push (git-fileinfo->name info) added))
@@ -1084,13 +1107,14 @@ Return the list of files that haven't been handled."
(or (not added)
(apply 'git-call-process-display-error "update-index" "--force-remove" "--" added))
(or (not modified)
(apply 'git-call-process-display-error "checkout" "HEAD" modified)))))
(git-update-status-files (append added modified))
(apply 'git-call-process-display-error "checkout" "HEAD" modified))))
(names (git-get-filenames files)))
(git-update-status-files names)
(when ok
(dolist (file modified)
(let ((buffer (get-file-buffer file)))
(when buffer (with-current-buffer buffer (revert-buffer t t t)))))
(git-success-message "Reverted" (git-get-filenames files)))))))
(git-success-message "Reverted" names))))))
(defun git-resolve-file ()
"Resolve conflicts in marked file(s)."
@@ -1320,6 +1344,7 @@ Return the list of files that haven't been handled."
(log-edit-diff-function . git-log-edit-diff)) buffer)
(log-edit 'git-do-commit nil 'git-log-edit-files buffer))
(setq font-lock-keywords (font-lock-compile-keywords git-log-edit-font-lock-keywords))
(setq paragraph-separate (concat (regexp-quote git-log-msg-separator) "$\\|Author: \\|Date: \\|Merge: \\|Signed-off-by: \\|\f\\|[ ]*$"))
(setq buffer-file-coding-system coding-system)
(re-search-forward (regexp-quote (concat git-log-msg-separator "\n")) nil t))))
@@ -1347,14 +1372,44 @@ Return the list of files that haven't been handled."
(mapconcat #'identity msg "\n"))))
(defun git-get-commit-files (commit)
"Retrieve the list of files modified by COMMIT."
"Retrieve a sorted list of files modified by COMMIT."
(let (files)
(with-temp-buffer
(git-call-process t "diff-tree" "-m" "-r" "-z" "--name-only" "--no-commit-id" "--root" commit)
(goto-char (point-min))
(while (re-search-forward "\\([^\0]*\\)\0" nil t 1)
(push (match-string 1) files)))
files))
(sort files #'string-lessp)))
(defun git-read-commit-name (prompt &optional default)
"Ask for a commit name, with completion for local branch, remote branch and tag."
(completing-read prompt
(list* "HEAD" "ORIG_HEAD" "FETCH_HEAD" (mapcar #'car (git-for-each-ref)))
nil nil nil nil default))
(defun git-checkout (branch &optional merge)
"Checkout a branch, tag, or any commit.
Use a prefix arg if git should merge while checking out."
(interactive
(list (git-read-commit-name "Checkout: ")
current-prefix-arg))
(unless git-status (error "Not in git-status buffer."))
(let ((args (list branch "--")))
(when merge (push "-m" args))
(when (apply #'git-call-process-display-error "checkout" args)
(git-update-status-files))))
(defun git-branch (branch)
"Create a branch from the current HEAD and switch to it."
(interactive (list (git-read-commit-name "Branch: ")))
(unless git-status (error "Not in git-status buffer."))
(if (git-rev-parse (concat "refs/heads/" branch))
(if (yes-or-no-p (format "Branch %s already exists, replace it? " branch))
(and (git-call-process-display-error "branch" "-f" branch)
(git-call-process-display-error "checkout" branch))
(message "Canceled."))
(git-call-process-display-error "checkout" "-b" branch))
(git-refresh-ewoc-hf git-status))
(defun git-amend-commit ()
"Undo the last commit on HEAD, and set things up to commit an
@@ -1372,6 +1427,44 @@ amended version of it."
(git-setup-commit-buffer commit)
(git-commit-file))))
(defun git-cherry-pick-commit (arg)
"Cherry-pick a commit."
(interactive (list (git-read-commit-name "Cherry-pick commit: ")))
(unless git-status (error "Not in git-status buffer."))
(let ((commit (git-rev-parse (concat arg "^0"))))
(unless commit (error "Not a valid commit '%s'." arg))
(when (git-rev-parse (concat commit "^2"))
(error "Cannot cherry-pick a merge commit."))
(let ((files (git-get-commit-files commit))
(ok (git-call-process-display-error "cherry-pick" "-n" commit)))
(git-update-status-files files ok)
(with-current-buffer (git-setup-commit-buffer commit)
(goto-char (point-min))
(if (re-search-forward "^\n*Signed-off-by:" nil t 1)
(goto-char (match-beginning 0))
(goto-char (point-max)))
(insert "(cherry picked from commit " commit ")\n"))
(when ok (git-commit-file)))))
(defun git-revert-commit (arg)
"Revert a commit."
(interactive (list (git-read-commit-name "Revert commit: ")))
(unless git-status (error "Not in git-status buffer."))
(let ((commit (git-rev-parse (concat arg "^0"))))
(unless commit (error "Not a valid commit '%s'." arg))
(when (git-rev-parse (concat commit "^2"))
(error "Cannot revert a merge commit."))
(let ((files (git-get-commit-files commit))
(subject (git-get-commit-description commit))
(ok (git-call-process-display-error "revert" "-n" commit)))
(git-update-status-files files ok)
(when (string-match "^[0-9a-f]+ - \\(.*\\)$" subject)
(setq subject (match-string 1 subject)))
(git-setup-log-buffer (get-buffer-create "*git-commit*")
(git-get-merge-heads) nil nil (format "Revert \"%s\"" subject) nil
(format "This reverts commit %s.\n" commit))
(when ok (git-commit-file)))))
(defun git-find-file ()
"Visit the current file in its own buffer."
(interactive)
@@ -1471,6 +1564,10 @@ amended version of it."
(define-key map "\M-\C-?" 'git-unmark-all)
; the commit submap
(define-key commit-map "\C-a" 'git-amend-commit)
(define-key commit-map "\C-b" 'git-branch)
(define-key commit-map "\C-o" 'git-checkout)
(define-key commit-map "\C-p" 'git-cherry-pick-commit)
(define-key commit-map "\C-v" 'git-revert-commit)
; the diff submap
(define-key diff-map "b" 'git-diff-file-base)
(define-key diff-map "c" 'git-diff-file-combined)
@@ -1491,6 +1588,10 @@ amended version of it."
`("Git"
["Refresh" git-refresh-status t]
["Commit" git-commit-file t]
["Checkout..." git-checkout t]
["New Branch..." git-branch t]
["Cherry-pick Commit..." git-cherry-pick-commit t]
["Revert Commit..." git-revert-commit t]
("Merge"
["Next Unmerged File" git-next-unmerged-file t]
["Prev Unmerged File" git-prev-unmerged-file t]

View File

@@ -1,216 +0,0 @@
;;; vc-git.el --- VC backend for the git version control system
;; Copyright (C) 2006 Alexandre Julliard
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation; either version 2 of
;; the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be
;; useful, but WITHOUT ANY WARRANTY; without even the implied
;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
;; PURPOSE. See the GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public
;; License along with this program; if not, write to the Free
;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
;; MA 02111-1307 USA
;;; Commentary:
;; This file contains a VC backend for the git version control
;; system.
;;
;; To install: put this file on the load-path and add GIT to the list
;; of supported backends in `vc-handled-backends'; the following line,
;; placed in your ~/.emacs, will accomplish this:
;;
;; (add-to-list 'vc-handled-backends 'GIT)
;;
;; TODO
;; - changelog generation
;; - working with revisions other than HEAD
;;
(eval-when-compile (require 'cl))
(defvar git-commits-coding-system 'utf-8
"Default coding system for git commits.")
(defun vc-git--run-command-string (file &rest args)
"Run a git command on FILE and return its output as string."
(let* ((ok t)
(str (with-output-to-string
(with-current-buffer standard-output
(unless (eq 0 (apply #'call-process "git" nil '(t nil) nil
(append args (list (file-relative-name file)))))
(setq ok nil))))))
(and ok str)))
(defun vc-git--run-command (file &rest args)
"Run a git command on FILE, discarding any output."
(let ((name (file-relative-name file)))
(eq 0 (apply #'call-process "git" nil (get-buffer "*Messages") nil (append args (list name))))))
(defun vc-git-registered (file)
"Check whether FILE is registered with git."
(with-temp-buffer
(let* ((dir (file-name-directory file))
(name (file-relative-name file dir)))
(and (ignore-errors
(when dir (cd dir))
(eq 0 (call-process "git" nil '(t nil) nil "ls-files" "-c" "-z" "--" name)))
(let ((str (buffer-string)))
(and (> (length str) (length name))
(string= (substring str 0 (1+ (length name))) (concat name "\0"))))))))
(defun vc-git-state (file)
"git-specific version of `vc-state'."
(let ((diff (vc-git--run-command-string file "diff-index" "-z" "HEAD" "--")))
(if (and diff (string-match ":[0-7]\\{6\\} [0-7]\\{6\\} [0-9a-f]\\{40\\} [0-9a-f]\\{40\\} [ADMU]\0[^\0]+\0" diff))
'edited
'up-to-date)))
(defun vc-git-workfile-version (file)
"git-specific version of `vc-workfile-version'."
(let ((str (with-output-to-string
(with-current-buffer standard-output
(call-process "git" nil '(t nil) nil "symbolic-ref" "HEAD")))))
(if (string-match "^\\(refs/heads/\\)?\\(.+\\)$" str)
(match-string 2 str)
str)))
(defun vc-git-symbolic-commit (commit)
"Translate COMMIT string into symbolic form.
Returns nil if not possible."
(and commit
(with-temp-buffer
(and
(zerop
(call-process "git" nil '(t nil) nil "name-rev"
"--name-only" "--tags"
commit))
(goto-char (point-min))
(= (forward-line 2) 1)
(bolp)
(buffer-substring-no-properties (point-min) (1- (point-max)))))))
(defun vc-git-previous-version (file rev)
"git-specific version of `vc-previous-version'."
(let ((default-directory (file-name-directory (expand-file-name file)))
(file (file-name-nondirectory file)))
(vc-git-symbolic-commit
(with-temp-buffer
(and
(zerop
(call-process "git" nil '(t nil) nil "rev-list"
"-2" rev "--" file))
(goto-char (point-max))
(bolp)
(zerop (forward-line -1))
(not (bobp))
(buffer-substring-no-properties
(point)
(1- (point-max))))))))
(defun vc-git-next-version (file rev)
"git-specific version of `vc-next-version'."
(let* ((default-directory (file-name-directory
(expand-file-name file)))
(file (file-name-nondirectory file))
(current-rev
(with-temp-buffer
(and
(zerop
(call-process "git" nil '(t nil) nil "rev-list"
"-1" rev "--" file))
(goto-char (point-max))
(bolp)
(zerop (forward-line -1))
(bobp)
(buffer-substring-no-properties
(point)
(1- (point-max)))))))
(and current-rev
(vc-git-symbolic-commit
(with-temp-buffer
(and
(zerop
(call-process "git" nil '(t nil) nil "rev-list"
"HEAD" "--" file))
(goto-char (point-min))
(search-forward current-rev nil t)
(zerop (forward-line -1))
(buffer-substring-no-properties
(point)
(progn (forward-line 1) (1- (point))))))))))
(defun vc-git-revert (file &optional contents-done)
"Revert FILE to the version stored in the git repository."
(if contents-done
(vc-git--run-command file "update-index" "--")
(vc-git--run-command file "checkout" "HEAD")))
(defun vc-git-checkout-model (file)
'implicit)
(defun vc-git-workfile-unchanged-p (file)
(let ((sha1 (vc-git--run-command-string file "hash-object" "--"))
(head (vc-git--run-command-string file "ls-tree" "-z" "HEAD" "--")))
(and head
(string-match "[0-7]\\{6\\} blob \\([0-9a-f]\\{40\\}\\)\t[^\0]+\0" head)
(string= (car (split-string sha1 "\n")) (match-string 1 head)))))
(defun vc-git-register (file &optional rev comment)
"Register FILE into the git version-control system."
(vc-git--run-command file "update-index" "--add" "--"))
(defun vc-git-print-log (file &optional buffer)
(let ((name (file-relative-name file))
(coding-system-for-read git-commits-coding-system))
(vc-do-command buffer 'async "git" name "rev-list" "--pretty" "HEAD" "--")))
(defun vc-git-diff (file &optional rev1 rev2 buffer)
(let ((name (file-relative-name file))
(buf (or buffer "*vc-diff*")))
(if (and rev1 rev2)
(vc-do-command buf 0 "git" name "diff-tree" "-p" rev1 rev2 "--")
(vc-do-command buf 0 "git" name "diff-index" "-p" (or rev1 "HEAD") "--"))
; git-diff-index doesn't set exit status like diff does
(if (vc-git-workfile-unchanged-p file) 0 1)))
(defun vc-git-checkin (file rev comment)
(let ((coding-system-for-write git-commits-coding-system))
(vc-git--run-command file "commit" "-m" comment "--only" "--")))
(defun vc-git-checkout (file &optional editable rev destfile)
(if destfile
(let ((fullname (substring
(vc-git--run-command-string file "ls-files" "-z" "--full-name" "--")
0 -1))
(coding-system-for-read 'no-conversion)
(coding-system-for-write 'no-conversion))
(with-temp-file destfile
(eq 0 (call-process "git" nil t nil "cat-file" "blob"
(concat (or rev "HEAD") ":" fullname)))))
(vc-git--run-command file "checkout" (or rev "HEAD"))))
(defun vc-git-annotate-command (file buf &optional rev)
; FIXME: rev is ignored
(let ((name (file-relative-name file)))
(call-process "git" nil buf nil "blame" name)))
(defun vc-git-annotate-time ()
(and (re-search-forward "[0-9a-f]+ (.* \\([0-9]+\\)-\\([0-9]+\\)-\\([0-9]+\\) \\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\) \\([-+0-9]+\\) +[0-9]+)" nil t)
(vc-annotate-convert-time
(apply #'encode-time (mapcar (lambda (match) (string-to-number (match-string match))) '(6 5 4 3 2 1 7))))))
;; Not really useful since we can't do anything with the revision yet
;;(defun vc-annotate-extract-revision-at-line ()
;; (save-excursion
;; (move-beginning-of-line 1)
;; (and (looking-at "[0-9a-f]+")
;; (buffer-substring (match-beginning 0) (match-end 0)))))
(provide 'vc-git)

View File

@@ -287,9 +287,9 @@ my $last_rev = "";
my $last_branch;
my $current_rev = $opt_s || 1;
unless(-d $git_dir) {
system("git-init");
system("git init");
die "Cannot init the GIT db at $git_tree: $?\n" if $?;
system("git-read-tree");
system("git read-tree");
die "Cannot init an empty tree: $?\n" if $?;
$last_branch = $opt_o;
@@ -303,7 +303,7 @@ unless(-d $git_dir) {
-f "$git_dir/svn2git"
or die "'$git_dir/svn2git' does not exist.\n".
"You need that file for incremental imports.\n";
open(F, "git-symbolic-ref HEAD |") or
open(F, "git symbolic-ref HEAD |") or
die "Cannot run git-symbolic-ref: $!\n";
chomp ($last_branch = <F>);
$last_branch = basename($last_branch);
@@ -331,7 +331,7 @@ EOM
"$git_dir/refs/heads/$opt_o") == 0;
# populate index
system('git-read-tree', $last_rev);
system('git', 'read-tree', $last_rev);
die "read-tree failed: $?\n" if $?;
# Get the last import timestamps
@@ -399,7 +399,7 @@ sub get_file($$$) {
my $pid = open(my $F, '-|');
die $! unless defined $pid;
if (!$pid) {
exec("git-hash-object", "-w", $name)
exec("git", "hash-object", "-w", $name)
or die "Cannot create object: $!\n";
}
my $sha = <$F>;
@@ -423,7 +423,7 @@ sub get_ignore($$$$$) {
my $pid = open(my $F, '-|');
die $! unless defined $pid;
if (!$pid) {
exec("git-hash-object", "-w", $name)
exec("git", "hash-object", "-w", $name)
or die "Cannot create object: $!\n";
}
my $sha = <$F>;
@@ -547,7 +547,7 @@ sub copy_path($$$$$$$$) {
my $pid = open my $f,'-|';
die $! unless defined $pid;
if (!$pid) {
exec("git-ls-tree","-r","-z",$gitrev,$srcpath)
exec("git","ls-tree","-r","-z",$gitrev,$srcpath)
or die $!;
}
local $/ = "\0";
@@ -634,7 +634,7 @@ sub commit {
my $rev;
if($revision > $opt_s and defined $parent) {
open(H,'-|',"git-rev-parse","--verify",$parent);
open(H,'-|',"git","rev-parse","--verify",$parent);
$rev = <H>;
close(H) or do {
print STDERR "$revision: cannot find commit '$parent'!\n";
@@ -671,7 +671,7 @@ sub commit {
unlink($git_index);
} elsif ($rev ne $last_rev) {
print "Switching from $last_rev to $rev ($branch)\n" if $opt_v;
system("git-read-tree", $rev);
system("git", "read-tree", $rev);
die "read-tree failed for $rev: $?\n" if $?;
$last_rev = $rev;
}
@@ -740,7 +740,7 @@ sub commit {
my $pid = open my $F, "-|";
die "$!" unless defined $pid;
if (!$pid) {
exec("git-ls-files", "-z", @o1) or die $!;
exec("git", "ls-files", "-z", @o1) or die $!;
}
@o1 = ();
local $/ = "\0";
@@ -758,7 +758,7 @@ sub commit {
@o2 = @o1;
@o1 = ();
}
system("git-update-index","--force-remove","--",@o2);
system("git","update-index","--force-remove","--",@o2);
die "Cannot remove files: $?\n" if $?;
}
}
@@ -770,7 +770,7 @@ sub commit {
@n2 = @new;
@new = ();
}
system("git-update-index","--add",
system("git","update-index","--add",
(map { ('--cacheinfo', @$_) } @n2));
die "Cannot add files: $?\n" if $?;
}
@@ -778,7 +778,7 @@ sub commit {
my $pid = open(C,"-|");
die "Cannot fork: $!" unless defined $pid;
unless($pid) {
exec("git-write-tree");
exec("git","write-tree");
die "Cannot exec git-write-tree: $!\n";
}
chomp(my $tree = <C>);
@@ -830,7 +830,7 @@ sub commit {
"GIT_COMMITTER_NAME=$committer_name",
"GIT_COMMITTER_EMAIL=$committer_email",
"GIT_COMMITTER_DATE=".strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date)),
"git-commit-tree", $tree,@par);
"git", "commit-tree", $tree,@par);
die "Cannot exec git-commit-tree: $!\n";
}
$pw->writer();
@@ -874,7 +874,7 @@ sub commit {
$dest =~ tr/_/\./ if $opt_u;
system('git-tag', '-f', $dest, $cid) == 0
system('git', 'tag', '-f', $dest, $cid) == 0
or die "Cannot create tag $dest: $!\n";
print "Created tag '$dest' on '$branch'\n" if $opt_v;
@@ -937,7 +937,7 @@ while ($to_rev < $opt_l) {
my $pid = fork();
die "Fork: $!\n" unless defined $pid;
unless($pid) {
exec("git-repack", "-d")
exec("git", "repack", "-d")
or die "Cannot repack: $!\n";
}
waitpid($pid, 0);
@@ -958,7 +958,7 @@ if($orig_branch) {
system("cp","$git_dir/refs/heads/$opt_o","$git_dir/refs/heads/master")
if $forward_master;
unless ($opt_i) {
system('git-read-tree', '-m', '-u', 'SVN2GIT_HEAD', 'HEAD');
system('git', 'read-tree', '-m', '-u', 'SVN2GIT_HEAD', 'HEAD');
die "read-tree failed: $?\n" if $?;
}
} else {
@@ -966,7 +966,7 @@ if($orig_branch) {
print "DONE; creating $orig_branch branch\n" if $opt_v and (not defined $opt_l or $opt_l > 0);
system("cp","$git_dir/refs/heads/$opt_o","$git_dir/refs/heads/master")
unless -f "$git_dir/refs/heads/master";
system('git-update-ref', 'HEAD', "$orig_branch");
system('git', 'update-ref', 'HEAD', "$orig_branch");
unless ($opt_i) {
system('git checkout');
die "checkout failed: $?\n" if $?;

View File

@@ -114,9 +114,9 @@ due to SVN memory leaks. (These have been worked around.)
-R <repack_each_revs>::
Specify how often git repository should be repacked.
+
The default value is 1000. git-svnimport will do import in chunks of 1000
revisions, after each chunk git repository will be repacked. To disable
this behavior specify some big value here which is mote than number of
The default value is 1000. git-svnimport will do imports in chunks of 1000
revisions, after each chunk the git repository will be repacked. To disable
this behavior specify some large value here which is greater than the number of
revisions to import.
-P <path_from_trunk>::

View File

@@ -442,13 +442,14 @@ def p4ChangesForPaths(depotPaths, changeRange):
output = p4_read_pipe_lines("changes " + ' '.join (["%s...%s" % (p, changeRange)
for p in depotPaths]))
changes = []
changes = {}
for line in output:
changeNum = line.split(" ")[1]
changes.append(int(changeNum))
changeNum = int(line.split(" ")[1])
changes[changeNum] = True
changes.sort()
return changes
changelist = changes.keys()
changelist.sort()
return changelist
class Command:
def __init__(self):

View File

@@ -615,7 +615,9 @@ show_new_revisions()
revspec=$oldrev..$newrev
fi
git rev-parse --not --branches | grep -v $(git rev-parse $refname) |
other_branches=$(git for-each-ref --format='%(refname)' refs/heads/ |
grep -F -v $refname)
git rev-parse --not $other_branches |
if [ -z "$custom_showrev" ]
then
git rev-list --pretty --stdin $revspec

7
date.c
View File

@@ -89,6 +89,11 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)
struct tm *tm;
static char timebuf[200];
if (mode == DATE_RAW) {
snprintf(timebuf, sizeof(timebuf), "%lu %+05d", time, tz);
return timebuf;
}
if (mode == DATE_RELATIVE) {
unsigned long diff;
struct timeval now;
@@ -615,6 +620,8 @@ enum date_mode parse_date_format(const char *format)
return DATE_LOCAL;
else if (!strcmp(format, "default"))
return DATE_NORMAL;
else if (!strcmp(format, "raw"))
return DATE_RAW;
else
die("unknown date format %s", format);
}

View File

@@ -513,3 +513,18 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
exit(128);
return 0;
}
int index_differs_from(const char *def, int diff_flags)
{
struct rev_info rev;
init_revisions(&rev, NULL);
setup_revisions(0, NULL, &rev, def);
DIFF_OPT_SET(&rev.diffopt, QUIET);
DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);
rev.diffopt.flags |= diff_flags;
run_diff_index(&rev, 1);
if (rev.pending.alloc)
free(rev.pending.objects);
return (DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0);
}

View File

@@ -247,6 +247,7 @@ void diff_no_index(struct rev_info *revs,
else
revs->diffopt.paths = argv + argc - 2;
revs->diffopt.nr_paths = 2;
revs->diffopt.skip_stat_unmatch = 1;
DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
DIFF_OPT_SET(&revs->diffopt, NO_INDEX);

11
diff.c
View File

@@ -184,11 +184,11 @@ static int remove_tempfile_installed;
static void remove_tempfile(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(diff_temp); i++)
if (diff_temp[i].name == diff_temp[i].tmp_path) {
for (i = 0; i < ARRAY_SIZE(diff_temp); i++) {
if (diff_temp[i].name == diff_temp[i].tmp_path)
unlink(diff_temp[i].name);
diff_temp[i].name = NULL;
}
diff_temp[i].name = NULL;
}
}
static void remove_tempfile_on_signal(int signo)
@@ -2326,15 +2326,12 @@ void diff_setup(struct diff_options *options)
options->break_opt = -1;
options->rename_limit = -1;
options->dirstat_percent = 3;
DIFF_OPT_CLR(options, DIRSTAT_CUMULATIVE);
options->context = 3;
options->change = diff_change;
options->add_remove = diff_addremove;
if (diff_use_color_default > 0)
DIFF_OPT_SET(options, COLOR_DIFF);
else
DIFF_OPT_CLR(options, COLOR_DIFF);
options->detect_rename = diff_detect_rename_default;
if (!diff_mnemonic_prefix) {

2
diff.h
View File

@@ -265,4 +265,6 @@ extern int diff_result_code(struct diff_options *, int);
extern void diff_no_index(struct rev_info *, int, const char **, int, const char *);
extern int index_differs_from(const char *def, int diff_flags);
#endif /* DIFF_H */

View File

@@ -45,7 +45,6 @@ enum rebase_setup_type autorebase = AUTOREBASE_NEVER;
/* Parallel index stat data preload? */
int core_preload_index = 0;
char *notes_ref_name;
/* This is set by setup_git_dir_gently() and/or git_default_config() */
char *git_work_tree_cfg;

View File

@@ -817,9 +817,8 @@ static void start_packfile(void)
struct pack_header hdr;
int pack_fd;
snprintf(tmpfile, sizeof(tmpfile),
"%s/pack/tmp_pack_XXXXXX", get_object_directory());
pack_fd = xmkstemp(tmpfile);
pack_fd = odb_mkstemp(tmpfile, sizeof(tmpfile),
"pack/tmp_pack_XXXXXX");
p = xcalloc(1, sizeof(*p) + strlen(tmpfile) + 2);
strcpy(p->pack_name, tmpfile);
p->pack_fd = pack_fd;
@@ -869,7 +868,7 @@ static char *create_index(void)
/* Generate the fan-out array. */
c = idx;
for (i = 0; i < 256; i++) {
struct object_entry **next = c;;
struct object_entry **next = c;
while (next < last) {
if ((*next)->sha1[0] != i)
break;
@@ -879,9 +878,8 @@ static char *create_index(void)
c = next;
}
snprintf(tmpfile, sizeof(tmpfile),
"%s/pack/tmp_idx_XXXXXX", get_object_directory());
idx_fd = xmkstemp(tmpfile);
idx_fd = odb_mkstemp(tmpfile, sizeof(tmpfile),
"pack/tmp_idx_XXXXXX");
f = sha1fd(idx_fd, tmpfile);
sha1write(f, array, 256 * sizeof(int));
git_SHA1_Init(&ctx);
@@ -907,9 +905,7 @@ static char *keep_pack(char *curr_index_name)
chmod(pack_data->pack_name, 0444);
chmod(curr_index_name, 0444);
snprintf(name, sizeof(name), "%s/pack/pack-%s.keep",
get_object_directory(), sha1_to_hex(pack_data->sha1));
keep_fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
keep_fd = odb_pack_keep(name, sizeof(name), pack_data->sha1);
if (keep_fd < 0)
die("cannot create keep file");
write_or_die(keep_fd, keep_msg, strlen(keep_msg));
@@ -945,6 +941,7 @@ static void end_packfile(void)
{
struct packed_git *old_p = pack_data, *new_p;
clear_delta_base_cache();
if (object_count) {
char *idx_name;
int i;

View File

@@ -12,6 +12,13 @@ my ($prompt_color, $header_color, $help_color) =
$repo->get_color('color.interactive.header', 'bold'),
$repo->get_color('color.interactive.help', 'red bold'),
) : ();
my $error_color = ();
if ($menu_use_color) {
my $help_color_spec = ($repo->config('color.interactive.help') or
'red bold');
$error_color = $repo->get_color('color.interactive.error',
$help_color_spec);
}
my $diff_use_color = $repo->get_colorbool('color.diff');
my ($fraginfo_color) =
@@ -33,6 +40,17 @@ my ($diff_new_color) =
my $normal_color = $repo->get_color("", "reset");
my $use_readkey = 0;
sub ReadMode;
sub ReadKey;
if ($repo->config_bool("interactive.singlekey")) {
eval {
require Term::ReadKey;
Term::ReadKey->import;
$use_readkey = 1;
};
}
sub colored {
my $color = shift;
my $string = join("", @_);
@@ -325,6 +343,10 @@ sub highlight_prefix {
return "$prompt_color$prefix$normal_color$remainder";
}
sub error_msg {
print STDERR colored $error_color, @_;
}
sub list_and_choose {
my ($opts, @stuff) = @_;
my (@chosen, @return);
@@ -420,12 +442,12 @@ sub list_and_choose {
else {
$bottom = $top = find_unique($choice, @stuff);
if (!defined $bottom) {
print "Huh ($choice)?\n";
error_msg "Huh ($choice)?\n";
next TOPLOOP;
}
}
if ($opts->{SINGLETON} && $bottom != $top) {
print "Huh ($choice)?\n";
error_msg "Huh ($choice)?\n";
next TOPLOOP;
}
for ($i = $bottom-1; $i <= $top-1; $i++) {
@@ -758,11 +780,32 @@ sub diff_applies {
return close $fh;
}
sub _restore_terminal_and_die {
ReadMode 'restore';
print "\n";
exit 1;
}
sub prompt_single_character {
if ($use_readkey) {
local $SIG{TERM} = \&_restore_terminal_and_die;
local $SIG{INT} = \&_restore_terminal_and_die;
ReadMode 'cbreak';
my $key = ReadKey 0;
ReadMode 'restore';
print "$key" if defined $key;
print "\n";
return $key;
} else {
return <STDIN>;
}
}
sub prompt_yesno {
my ($prompt) = @_;
while (1) {
print colored $prompt_color, $prompt;
my $line = <STDIN>;
my $line = prompt_single_character;
return 0 if $line =~ /^n/i;
return 1 if $line =~ /^y/i;
}
@@ -893,7 +936,7 @@ sub patch_update_file {
print @{$mode->{DISPLAY}};
print colored $prompt_color,
"Stage mode change [y/n/a/d/?]? ";
my $line = <STDIN>;
my $line = prompt_single_character;
if ($line =~ /^y/i) {
$mode->{USE} = 1;
last;
@@ -966,7 +1009,7 @@ sub patch_update_file {
print;
}
print colored $prompt_color, "Stage this hunk [y,n,a,d,/$other,?]? ";
my $line = <STDIN>;
my $line = prompt_single_character;
if ($line) {
if ($line =~ /^y/i) {
$hunk[$ix]{USE} = 1;
@@ -1000,11 +1043,11 @@ sub patch_update_file {
chomp $response;
}
if ($response !~ /^\s*\d+\s*$/) {
print STDERR "Invalid number: '$response'\n";
error_msg "Invalid number: '$response'\n";
} elsif (0 < $response && $response <= $num) {
$ix = $response - 1;
} else {
print STDERR "Sorry, only $num hunks available.\n";
error_msg "Sorry, only $num hunks available.\n";
}
next;
}
@@ -1018,14 +1061,22 @@ sub patch_update_file {
next;
}
elsif ($line =~ m|^/(.*)|) {
my $regex = $1;
if ($1 eq "") {
print colored $prompt_color, "search for regex? ";
$regex = <STDIN>;
if (defined $regex) {
chomp $regex;
}
}
my $search_string;
eval {
$search_string = qr{$1}m;
$search_string = qr{$regex}m;
};
if ($@) {
my ($err,$exp) = ($@, $1);
$err =~ s/ at .*git-add--interactive line \d+, <STDIN> line \d+.*$//;
print STDERR "Malformed search regexp $exp: $err\n";
error_msg "Malformed search regexp $exp: $err\n";
next;
}
my $iy = $ix;
@@ -1035,7 +1086,7 @@ sub patch_update_file {
$iy++;
$iy = 0 if ($iy >= $num);
if ($ix == $iy) {
print STDERR "No hunk matches the given pattern\n";
error_msg "No hunk matches the given pattern\n";
last;
}
}
@@ -1047,7 +1098,7 @@ sub patch_update_file {
$ix--;
}
else {
print STDERR "No previous hunk\n";
error_msg "No previous hunk\n";
}
next;
}
@@ -1056,7 +1107,7 @@ sub patch_update_file {
$ix++;
}
else {
print STDERR "No next hunk\n";
error_msg "No next hunk\n";
}
next;
}
@@ -1069,13 +1120,13 @@ sub patch_update_file {
}
}
else {
print STDERR "No previous hunk\n";
error_msg "No previous hunk\n";
}
next;
}
elsif ($line =~ /^j/) {
if ($other !~ /j/) {
print STDERR "No next hunk\n";
error_msg "No next hunk\n";
next;
}
}

View File

@@ -221,6 +221,9 @@ then
resume=yes
case "$skip,$abort" in
t,t)
die "Please make up your mind. --skip or --abort?"
;;
t,)
git rerere clear
git read-tree --reset -u HEAD HEAD
@@ -229,12 +232,19 @@ then
git update-ref ORIG_HEAD $orig_head
;;
,t)
if test -f "$dotest/rebasing"
then
exec git rebase --abort
fi
git rerere clear
git read-tree --reset -u HEAD ORIG_HEAD
git reset ORIG_HEAD
test -f "$dotest/dirtyindex" || {
git read-tree --reset -u HEAD ORIG_HEAD
git reset ORIG_HEAD
}
rm -fr "$dotest"
exit ;;
esac
rm -f "$dotest/dirtyindex"
else
# Make sure we are not given --skip, --resolved, nor --abort
test "$skip$resolved$abort" = "" ||
@@ -287,7 +297,11 @@ fi
case "$resolved" in
'')
files=$(git diff-index --cached --name-only HEAD --) || exit
test "$files" && die "Dirty index: cannot apply patches (dirty: $files)"
if test "$files"
then
: >"$dotest/dirtyindex"
die "Dirty index: cannot apply patches (dirty: $files)"
fi
esac
if test "$(cat "$dotest/utf8")" = t

View File

@@ -284,62 +284,74 @@ filter_skipped() {
_skip="$2"
if [ -z "$_skip" ]; then
eval "$_eval"
eval "$_eval" | {
while read line
do
echo "$line &&"
done
echo ':'
}
return
fi
# Let's parse the output of:
# "git rev-list --bisect-vars --bisect-all ..."
eval "$_eval" | while read hash line
do
case "$VARS,$FOUND,$TRIED,$hash" in
# We display some vars.
1,*,*,*) echo "$hash $line" ;;
# Split line.
,*,*,---*) ;;
# We had nothing to search.
eval "$_eval" | {
VARS= FOUND= TRIED=
while read hash line
do
case "$VARS,$FOUND,$TRIED,$hash" in
1,*,*,*)
# "bisect_foo=bar" read from rev-list output.
echo "$hash &&"
;;
,*,*,---*)
# Separator
;;
,,,bisect_rev*)
echo "bisect_rev="
# We had nothing to search.
echo "bisect_rev= &&"
VARS=1
;;
# We did not find a good bisect rev.
# This should happen only if the "bad"
# commit is also a "skip" commit.
,,*,bisect_rev*)
echo "bisect_rev=$TRIED"
# We did not find a good bisect rev.
# This should happen only if the "bad"
# commit is also a "skip" commit.
echo "bisect_rev='$TRIED' &&"
VARS=1
;;
# We are searching.
,,*,*)
# We are searching.
TRIED="${TRIED:+$TRIED|}$hash"
case "$_skip" in
*$hash*) ;;
*)
echo "bisect_rev=$hash"
echo "bisect_tried=\"$TRIED\""
echo "bisect_rev=$hash &&"
echo "bisect_tried='$TRIED' &&"
FOUND=1
;;
esac
;;
# We have already found a rev to be tested.
,1,*,bisect_rev*) VARS=1 ;;
,1,*,*) ;;
# ???
*) die "filter_skipped error " \
"VARS: '$VARS' " \
"FOUND: '$FOUND' " \
"TRIED: '$TRIED' " \
"hash: '$hash' " \
"line: '$line'"
;;
esac
done
,1,*,bisect_rev*)
# We have already found a rev to be tested.
VARS=1
;;
,1,*,*)
;;
*)
# Unexpected input
echo "die 'filter_skipped error'"
die "filter_skipped error " \
"VARS: '$VARS' " \
"FOUND: '$FOUND' " \
"TRIED: '$TRIED' " \
"hash: '$hash' " \
"line: '$line'"
;;
esac
done
echo ':'
}
}
exit_if_skipped_commits () {

View File

@@ -303,6 +303,8 @@ extern ssize_t xwrite(int fd, const void *buf, size_t len);
extern int xdup(int fd);
extern FILE *xfdopen(int fd, const char *mode);
extern int xmkstemp(char *template);
extern int odb_mkstemp(char *template, size_t limit, const char *pattern);
extern int odb_pack_keep(char *name, size_t namesz, unsigned char *sha1);
static inline size_t xsize_t(off_t len)
{

View File

@@ -108,7 +108,7 @@ OPTIONS_SPEC=
. git-sh-setup
if [ "$(is_bare_repository)" = false ]; then
git diff-files --quiet &&
git diff-files --ignore-submodules --quiet &&
git diff-index --cached --quiet HEAD -- ||
die "Cannot rewrite branch(es) with a dirty working directory."
fi
@@ -220,8 +220,14 @@ die ""
# Remove tempdir on exit
trap 'cd ../..; rm -rf "$tempdir"' 0
ORIG_GIT_DIR="$GIT_DIR"
ORIG_GIT_WORK_TREE="$GIT_WORK_TREE"
ORIG_GIT_INDEX_FILE="$GIT_INDEX_FILE"
GIT_WORK_TREE=.
export GIT_DIR GIT_WORK_TREE
# Make sure refs/original is empty
git for-each-ref > "$tempdir"/backup-refs
git for-each-ref > "$tempdir"/backup-refs || exit
while read sha1 type name
do
case "$force,$name" in
@@ -234,15 +240,10 @@ do
esac
done < "$tempdir"/backup-refs
ORIG_GIT_DIR="$GIT_DIR"
ORIG_GIT_WORK_TREE="$GIT_WORK_TREE"
ORIG_GIT_INDEX_FILE="$GIT_INDEX_FILE"
GIT_WORK_TREE=.
export GIT_DIR GIT_WORK_TREE
# The refs should be updated if their heads were rewritten
git rev-parse --no-flags --revs-only --symbolic-full-name --default HEAD "$@" |
sed -e '/^^/d' >"$tempdir"/heads
git rev-parse --no-flags --revs-only --symbolic-full-name \
--default HEAD "$@" > "$tempdir"/raw-heads || exit
sed -e '/^^/d' "$tempdir"/raw-heads >"$tempdir"/heads
test -s "$tempdir"/heads ||
die "Which ref do you want to rewrite?"
@@ -251,8 +252,6 @@ GIT_INDEX_FILE="$(pwd)/../index"
export GIT_INDEX_FILE
git read-tree || die "Could not seed the index"
ret=0
# map old->new commit ids for rewriting parents
mkdir ../map || die "Could not create map/ directory"
@@ -315,10 +314,11 @@ while read commit parents; do
die "tree filter failed: $filter_tree"
(
git diff-index -r --name-only $commit
git diff-index -r --name-only $commit &&
git ls-files --others
) |
git update-index --add --replace --remove --stdin
) > "$tempdir"/tree-state || exit
git update-index --add --replace --remove --stdin \
< "$tempdir"/tree-state || exit
fi
eval "$filter_index" < /dev/null ||
@@ -339,7 +339,8 @@ while read commit parents; do
eval "$filter_msg" > ../message ||
die "msg filter failed: $filter_msg"
@SHELL_PATH@ -c "$filter_commit" "git commit-tree" \
$(git write-tree) $parentstr < ../message > ../map/$commit
$(git write-tree) $parentstr < ../message > ../map/$commit ||
die "could not write rewritten commit"
done <../revs
# In case of a subdirectory filter, it is possible that a specified head
@@ -407,7 +408,8 @@ do
die "Could not rewrite $ref"
;;
esac
git update-ref -m "filter-branch: backup" "$orig_namespace$ref" $sha1
git update-ref -m "filter-branch: backup" "$orig_namespace$ref" $sha1 ||
exit
done < "$tempdir"/heads
# TODO: This should possibly go, with the semantics that all positive given
@@ -469,20 +471,21 @@ rm -rf "$tempdir"
trap - 0
unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE
test -z "$ORIG_GIT_DIR" || {
GIT_DIR="$ORIG_GIT_DIR" && export GIT_DIR
}
test -z "$ORIG_GIT_WORK_TREE" || {
GIT_WORK_TREE="$ORIG_GIT_WORK_TREE" &&
export GIT_WORK_TREE
}
test -z "$ORIG_GIT_INDEX_FILE" || {
GIT_INDEX_FILE="$ORIG_GIT_INDEX_FILE" &&
export GIT_INDEX_FILE
}
if [ "$(is_bare_repository)" = false ]; then
unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE
test -z "$ORIG_GIT_DIR" || {
GIT_DIR="$ORIG_GIT_DIR" && export GIT_DIR
}
test -z "$ORIG_GIT_WORK_TREE" || {
GIT_WORK_TREE="$ORIG_GIT_WORK_TREE" &&
export GIT_WORK_TREE
}
test -z "$ORIG_GIT_INDEX_FILE" || {
GIT_INDEX_FILE="$ORIG_GIT_INDEX_FILE" &&
export GIT_INDEX_FILE
}
git read-tree -u -m HEAD
git read-tree -u -m HEAD || exit
fi
exit $ret
exit 0

View File

@@ -1,65 +0,0 @@
#!/bin/sh
USAGE="(edit | show) [commit]"
. git-sh-setup
test -n "$3" && usage
test -z "$1" && usage
ACTION="$1"; shift
test -z "$GIT_NOTES_REF" && GIT_NOTES_REF="$(git config core.notesref)"
test -z "$GIT_NOTES_REF" && GIT_NOTES_REF="refs/notes/commits"
COMMIT=$(git rev-parse --verify --default HEAD "$@") ||
die "Invalid commit: $@"
MESSAGE="$GIT_DIR"/new-notes-$COMMIT
trap '
test -f "$MESSAGE" && rm "$MESSAGE"
' 0
case "$ACTION" in
edit)
GIT_NOTES_REF= git log -1 $COMMIT | sed "s/^/#/" > "$MESSAGE"
GIT_INDEX_FILE="$MESSAGE".idx
export GIT_INDEX_FILE
CURRENT_HEAD=$(git show-ref "$GIT_NOTES_REF" | cut -f 1 -d ' ')
if [ -z "$CURRENT_HEAD" ]; then
PARENT=
else
PARENT="-p $CURRENT_HEAD"
git read-tree "$GIT_NOTES_REF" || die "Could not read index"
git cat-file blob :$COMMIT >> "$MESSAGE" 2> /dev/null
fi
${VISUAL:-${EDITOR:-vi}} "$MESSAGE"
grep -v ^# < "$MESSAGE" | git stripspace > "$MESSAGE".processed
mv "$MESSAGE".processed "$MESSAGE"
if [ -s "$MESSAGE" ]; then
BLOB=$(git hash-object -w "$MESSAGE") ||
die "Could not write into object database"
git update-index --add --cacheinfo 0644 $BLOB $COMMIT ||
die "Could not write index"
else
test -z "$CURRENT_HEAD" &&
die "Will not initialise with empty tree"
git update-index --force-remove $COMMIT ||
die "Could not update index"
fi
TREE=$(git write-tree) || die "Could not write tree"
NEW_HEAD=$(echo Annotate $COMMIT | git commit-tree $TREE $PARENT) ||
die "Could not annotate"
git update-ref -m "Annotate $COMMIT" \
"$GIT_NOTES_REF" $NEW_HEAD $CURRENT_HEAD
;;
show)
git show "$GIT_NOTES_REF":$COMMIT
;;
*)
usage
esac

View File

@@ -171,6 +171,11 @@ case "$merge_head" in
echo >&2 "Cannot merge multiple branches into empty head"
exit 1
fi
if test true = "$rebase"
then
echo >&2 "Cannot rebase onto multiple branches"
exit 1
fi
;;
esac

View File

@@ -63,7 +63,7 @@ tmp_info="$tmp_dir/info"
commit=$(git rev-parse HEAD)
mkdir $tmp_dir || exit 2
while read patch_name level garbage
while read patch_name level garbage <&3
do
case "$patch_name" in ''|'#'*) continue;; esac
case "$level" in
@@ -134,5 +134,5 @@ do
commit=$( (echo "$SUBJECT"; echo; cat "$tmp_msg") | git commit-tree $tree -p $commit) &&
git update-ref -m "quiltimport: $patch_name" HEAD $commit || exit 4
fi
done <"$QUILT_PATCHES/series"
done 3<"$QUILT_PATCHES/series"
rm -rf $tmp_dir || exit 5

View File

@@ -310,6 +310,7 @@ do
esac
shift
done
test $# -gt 2 && usage
# Make sure we do not have $GIT_DIR/rebase-apply
if test -z "$do_merge"

View File

@@ -88,32 +88,79 @@ if [ -z "$names" ]; then
echo Nothing new to pack.
fi
fi
for name in $names ; do
# Ok we have prepared all new packfiles.
mkdir -p "$PACKDIR" || exit
# First see if there are packs of the same name and if so
# if we can move them out of the way (this can happen if we
# repacked immediately after packing fully.
rollback=
failed=
for name in $names
do
for sfx in pack idx
do
file=pack-$name.$sfx
test -f "$PACKDIR/$file" || continue
rm -f "$PACKDIR/old-$file" &&
mv "$PACKDIR/$file" "$PACKDIR/old-$file" || {
failed=t
break
}
rollback="$rollback $file"
done
test -z "$failed" || break
done
# If renaming failed for any of them, roll the ones we have
# already renamed back to their original names.
if test -n "$failed"
then
rollback_failure=
for file in $rollback
do
mv "$PACKDIR/old-$file" "$PACKDIR/$file" ||
rollback_failure="$rollback_failure $file"
done
if test -n "$rollback_failure"
then
echo >&2 "WARNING: Some packs in use have been renamed by"
echo >&2 "WARNING: prefixing old- to their name, in order to"
echo >&2 "WARNING: replace them with the new version of the"
echo >&2 "WARNING: file. But the operation failed, and"
echo >&2 "WARNING: attempt to rename them back to their"
echo >&2 "WARNING: original names also failed."
echo >&2 "WARNING: Please rename them in $PACKDIR manually:"
for file in $rollback_failure
do
echo >&2 "WARNING: old-$file -> $file"
done
fi
exit 1
fi
# Now the ones with the same name are out of the way...
fullbases=
for name in $names
do
fullbases="$fullbases pack-$name"
chmod a-w "$PACKTMP-$name.pack"
chmod a-w "$PACKTMP-$name.idx"
mkdir -p "$PACKDIR" || exit
for sfx in pack idx
do
if test -f "$PACKDIR/pack-$name.$sfx"
then
mv -f "$PACKDIR/pack-$name.$sfx" \
"$PACKDIR/old-pack-$name.$sfx"
fi
done &&
mv -f "$PACKTMP-$name.pack" "$PACKDIR/pack-$name.pack" &&
mv -f "$PACKTMP-$name.idx" "$PACKDIR/pack-$name.idx" &&
test -f "$PACKDIR/pack-$name.pack" &&
test -f "$PACKDIR/pack-$name.idx" || {
echo >&2 "Couldn't replace the existing pack with updated one."
echo >&2 "The original set of packs have been saved as"
echo >&2 "old-pack-$name.{pack,idx} in $PACKDIR."
exit 1
}
rm -f "$PACKDIR/old-pack-$name.pack" "$PACKDIR/old-pack-$name.idx"
mv -f "$PACKTMP-$name.idx" "$PACKDIR/pack-$name.idx" ||
exit
done
# Remove the "old-" files
for name in $names
do
rm -f "$PACKDIR/old-pack-$name.idx"
rm -f "$PACKDIR/old-pack-$name.pack"
done
# End of pack replacement.
if test "$remove_redundant" = t
then
# We know $existing are all redundant.

View File

@@ -85,27 +85,14 @@ cd_to_toplevel () {
cdup=$(git rev-parse --show-cdup)
if test ! -z "$cdup"
then
case "$cdup" in
/*)
# Not quite the same as if we did "cd -P '$cdup'" when
# $cdup contains ".." after symlink path components.
# Don't fix that case at least until Git switches to
# "cd -P" across the board.
phys="$cdup"
;;
..|../*|*/..|*/../*)
# Interpret $cdup relative to the physical, not logical, cwd.
# Probably /bin/pwd is more portable than passing -P to cd or pwd.
phys="$(unset PWD; /bin/pwd)/$cdup"
;;
*)
# There's no "..", so no need to make things absolute.
phys="$cdup"
;;
esac
cd "$phys" || {
echo >&2 "Cannot chdir to $phys, the toplevel of the working tree"
# The "-P" option says to follow "physical" directory
# structure instead of following symbolic links. When cdup is
# "../", this means following the ".." entry in the current
# directory instead textually removing a symlink path element
# from the PWD shell variable. The "-P" behavior is more
# consistent with the C-style chdir used by most of Git.
cd -P "$cdup" || {
echo >&2 "Cannot chdir to $cdup, the toplevel of the working tree"
exit 1
}
fi

View File

@@ -5,7 +5,7 @@
# Copyright (c) 2007 Lars Hjemli
USAGE="[--quiet] [--cached] \
[add <repo> [-b branch] <path>]|[status|init|update [-i|--init]|summary [-n|--summary-limit <n>] [<commit>]] \
[add <repo> [-b branch] <path>]|[status|init|update [-i|--init] [-N|--no-fetch]|summary [-n|--summary-limit <n>] [<commit>]] \
[--] [<path>...]|[foreach <command>]|[sync [--] [<path>...]]"
OPTIONS_SPEC=
. git-sh-setup
@@ -16,6 +16,7 @@ command=
branch=
quiet=
cached=
nofetch=
#
# print stuff on stdout unless -q was specified
@@ -59,7 +60,7 @@ resolve_relative_url ()
#
module_list()
{
git ls-files --stage -- "$@" | grep '^160000 '
git ls-files --error-unmatch --stage -- "$@" | grep '^160000 '
}
#
@@ -300,6 +301,10 @@ cmd_update()
shift
cmd_init "$@" || return
;;
-N|--no-fetch)
shift
nofetch=1
;;
--)
shift
break
@@ -345,8 +350,16 @@ cmd_update()
then
force="-f"
fi
(unset GIT_DIR; cd "$path" && git-fetch &&
git-checkout $force -q "$sha1") ||
if test -z "$nofetch"
then
(unset GIT_DIR; cd "$path" &&
git-fetch) ||
die "Unable to fetch in submodule path '$path'"
fi
(unset GIT_DIR; cd "$path" &&
git-checkout $force -q "$sha1") ||
die "Unable to checkout '$sha1' in submodule path '$path'"
say "Submodule path '$path': checked out '$sha1'"

View File

@@ -438,7 +438,17 @@ sub cmd_dcommit {
die "Unable to determine upstream SVN information from ",
"$head history.\nPerhaps the repository is empty.";
}
$url = defined $_commit_url ? $_commit_url : $gs->full_url;
if (defined $_commit_url) {
$url = $_commit_url;
} else {
$url = eval { command_oneline('config', '--get',
"svn-remote.$gs->{repo_id}.commiturl") };
if (!$url) {
$url = $gs->full_url
}
}
my $last_rev = $_revision if defined $_revision;
if ($url) {
print "Committing to $url ...\n";
@@ -670,7 +680,11 @@ sub cmd_create_ignore {
$gs->prop_walk($gs->{path}, $r, sub {
my ($gs, $path, $props) = @_;
# $path is of the form /path/to/dir/
my $ignore = '.' . $path . '.gitignore';
$path = '.' . $path;
# SVN can have attributes on empty directories,
# which git won't track
mkpath([$path]) unless -d $path;
my $ignore = $path . '.gitignore';
my $s = $props->{'svn:ignore'} or return;
open(GITIGNORE, '>', $ignore)
or fatal("Failed to open `$ignore' for writing: $!");
@@ -1693,6 +1707,7 @@ sub find_by_url { # repos_root and, path are optional
my $prefix = '';
if ($rwr) {
$z = $rwr;
remove_username($z);
} elsif (defined $svm) {
$z = $svm->{source};
$prefix = $svm->{replace};
@@ -2389,22 +2404,8 @@ sub find_parent_branch {
print STDERR "Found possible branch point: ",
"$new_url => ", $self->full_url, ", $r\n";
$branch_from =~ s#^/##;
my $gs = Git::SVN->find_by_url($new_url, $repos_root, $branch_from);
unless ($gs) {
my $ref_id = $self->{ref_id};
$ref_id =~ s/\@\d+$//;
$ref_id .= "\@$r";
# just grow a tail if we're not unique enough :x
$ref_id .= '-' while find_ref($ref_id);
print STDERR "Initializing parent: $ref_id\n";
my ($u, $p, $repo_id) = ($new_url, '', $ref_id);
if ($u =~ s#^\Q$url\E(/|$)##) {
$p = $u;
$u = $url;
$repo_id = $self->{repo_id};
}
$gs = Git::SVN->init($u, $p, $repo_id, $ref_id, 1);
}
my $gs = $self->other_gs($new_url, $url, $repos_root,
$branch_from, $r, $self->{ref_id});
my ($r0, $parent) = $gs->find_rev_before($r, 1);
{
my ($base, $head);
@@ -2430,8 +2431,9 @@ sub find_parent_branch {
# do_switch works with svn/trunk >= r22312, but that
# is not included with SVN 1.4.3 (the latest version
# at the moment), so we can't rely on it
$self->{last_rev} = $r0;
$self->{last_commit} = $parent;
$ed = SVN::Git::Fetcher->new($self);
$ed = SVN::Git::Fetcher->new($self, $gs->{path});
$gs->ra->gs_do_switch($r0, $rev, $gs,
$self->full_url, $ed)
or die "SVN connection failed somewhere...\n";
@@ -2539,7 +2541,7 @@ sub get_untracked {
sub parse_svn_date {
my $date = shift || return '+0000 1970-01-01 00:00:00';
my ($Y,$m,$d,$H,$M,$S) = ($date =~ /^(\d{4})\-(\d\d)\-(\d\d)T
(\d\d)\:(\d\d)\:(\d\d).\d+Z$/x) or
(\d\d)\:(\d\d)\:(\d\d)\.\d*Z$/x) or
croak "Unable to parse date: $date\n";
my $parsed_date; # Set next.
@@ -2586,6 +2588,28 @@ sub parse_svn_date {
return $parsed_date;
}
sub other_gs {
my ($self, $new_url, $url, $repos_root,
$branch_from, $r, $old_ref_id) = @_;
my $gs = Git::SVN->find_by_url($new_url, $repos_root, $branch_from);
unless ($gs) {
my $ref_id = $old_ref_id;
$ref_id =~ s/\@\d+$//;
$ref_id .= "\@$r";
# just grow a tail if we're not unique enough :x
$ref_id .= '-' while find_ref($ref_id);
print STDERR "Initializing parent: $ref_id\n";
my ($u, $p, $repo_id) = ($new_url, '', $ref_id);
if ($u =~ s#^\Q$url\E(/|$)##) {
$p = $u;
$u = $url;
$repo_id = $self->{repo_id};
}
$gs = Git::SVN->init($u, $p, $repo_id, $ref_id, 1);
}
$gs
}
sub check_author {
my ($author) = @_;
if (!defined $author || length $author == 0) {
@@ -3250,12 +3274,13 @@ use vars qw/$_ignore_regex/;
# file baton members: path, mode_a, mode_b, pool, fh, blob, base
sub new {
my ($class, $git_svn) = @_;
my ($class, $git_svn, $switch_path) = @_;
my $self = SVN::Delta::Editor->new;
bless $self, $class;
if (exists $git_svn->{last_commit}) {
$self->{c} = $git_svn->{last_commit};
$self->{empty_symlinks} = _mark_empty_symlinks($git_svn);
$self->{empty_symlinks} =
_mark_empty_symlinks($git_svn, $switch_path);
}
$self->{empty} = {};
$self->{dir_prop} = {};
@@ -3270,19 +3295,39 @@ sub new {
# not inside them (when the Git::SVN::Fetcher object is passed) to
# do_{switch,update}
sub _mark_empty_symlinks {
my ($git_svn) = @_;
my ($git_svn, $switch_path) = @_;
my $bool = Git::config_bool('svn.brokenSymlinkWorkaround');
return {} if (!defined($bool)) || (defined($bool) && ! $bool);
my %ret;
my ($rev, $cmt) = $git_svn->last_rev_commit;
return {} unless ($rev && $cmt);
# allow the warning to be printed for each revision we fetch to
# ensure the user sees it. The user can also disable the workaround
# on the repository even while git svn is running and the next
# revision fetched will skip this expensive function.
my $printed_warning;
chomp(my $empty_blob = `git hash-object -t blob --stdin < /dev/null`);
my ($ls, $ctx) = command_output_pipe(qw/ls-tree -r -z/, $cmt);
local $/ = "\0";
my $pfx = $git_svn->{path};
my $pfx = defined($switch_path) ? $switch_path : $git_svn->{path};
$pfx .= '/' if length($pfx);
while (<$ls>) {
chomp;
s/\A100644 blob $empty_blob\t//o or next;
unless ($printed_warning) {
print STDERR "Scanning for empty symlinks, ",
"this may take a while if you have ",
"many empty files\n",
"You may disable this with `",
"git config svn.brokenSymlinkWorkaround ",
"false'.\n",
"This may be done in a different ",
"terminal without restarting ",
"git svn\n";
$printed_warning = 1;
}
my $path = $_;
my (undef, $props) =
$git_svn->ra->get_file($pfx.$path, $rev, undef);
@@ -4348,6 +4393,9 @@ sub gs_fetch_loop_common {
}
$self->get_log([$longest_path], $min, $max, 0, 1, 1,
sub { $revs{$_[1]} = _cb(@_) });
if ($err) {
print "Checked through r$max\r";
}
if ($err && $max >= $head) {
print STDERR "Path '$longest_path' ",
"was probably deleted:\n",
@@ -4582,6 +4630,7 @@ package Git::SVN::Log;
use strict;
use warnings;
use POSIX qw/strftime/;
use Time::Local;
use constant commit_log_separator => ('-' x 72) . "\n";
use vars qw/$TZ $limit $color $pager $non_recursive $verbose $oneline
%rusers $show_commit $incremental/;
@@ -4688,7 +4737,12 @@ sub run_pager {
}
sub format_svn_date {
return strftime("%Y-%m-%d %H:%M:%S %z (%a, %d %b %Y)", localtime(shift));
# some systmes don't handle or mishandle %z, so be creative.
my $t = shift || time;
my $gm = timelocal(gmtime($t));
my $sign = qw( + + - )[ $t <=> $gm ];
my $gmoff = sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]);
return strftime("%Y-%m-%d %H:%M:%S $gmoff (%a, %d %b %Y)", localtime($t));
}
sub parse_git_date {

View File

@@ -115,7 +115,7 @@ if test -z "$browser" ; then
browser_candidates="open $browser_candidates"
fi
# /bin/start indicates MinGW
if test -n /bin/start; then
if test -x /bin/start; then
browser_candidates="start $browser_candidates"
fi

View File

@@ -701,16 +701,17 @@ proc newvarc {view id} {
}
proc splitvarc {p v} {
global varcid varcstart varccommits varctok
global varcid varcstart varccommits varctok vtokmod
global vupptr vdownptr vleftptr vbackptr varcix varcrow vlastins
set oa $varcid($v,$p)
set otok [lindex $varctok($v) $oa]
set ac $varccommits($v,$oa)
set i [lsearch -exact $varccommits($v,$oa) $p]
if {$i <= 0} return
set na [llength $varctok($v)]
# "%" sorts before "0"...
set tok "[lindex $varctok($v) $oa]%[strrep $i]"
set tok "$otok%[strrep $i]"
lappend varctok($v) $tok
lappend varcrow($v) {}
lappend varcix($v) {}
@@ -730,6 +731,9 @@ proc splitvarc {p v} {
for {set b [lindex $vdownptr($v) $na]} {$b != 0} {set b [lindex $vleftptr($v) $b]} {
lset vupptr($v) $b $na
}
if {[string compare $otok $vtokmod($v)] <= 0} {
modify_arc $v $oa
}
}
proc renumbervarc {a v} {
@@ -3364,7 +3368,6 @@ proc external_blame {parent_idx {line {}}} {
# being given an absolute path...
set f [make_relative $f]
lappend cmdline $base_commit $f
puts "cmdline={$cmdline}"
if {[catch {eval exec $cmdline &} err]} {
error_popup "[mc "git gui blame: command failed:"] $err"
}
@@ -5732,7 +5735,6 @@ proc drawcommits {row {endrow {}}} {
optimize_rows $ro1 0 $r2
if {$need_redisplay || $nrows_drawn > 2000} {
clear_display
drawvisible
}
# make the lines join to already-drawn rows either side

View File

@@ -212,6 +212,11 @@ not include variables usually directly set during build):
Rename detection options for git-diff and git-diff-tree. By default
('-M'); set it to ('-C') or ('-C', '-C') to also detect copies, or
set it to () if you don't want to have renames detection.
* $prevent_xss
If true, some gitweb features are disabled to prevent content in
repositories from launching cross-site scripting (XSS) attacks. Set this
to true if you don't trust the content of your repositories. The default
is false.
Projects list file format
@@ -258,7 +263,9 @@ You can use the following files in repository:
A .html file (HTML fragment) which is included on the gitweb project
summary page inside <div> block element. You can use it for longer
description of a project, to provide links (for example to project's
homepage), etc.
homepage), etc. This is recognized only if XSS prevention is off
($prevent_xss is false); a way to include a readme safely when XSS
prevention is on may be worked out in the future.
* description (or gitweb.description)
Short (shortened by default to 25 characters in the projects list page)
single line description of a project (of a repository). Plain text file;

View File

@@ -27,13 +27,29 @@ our $version = "++GIT_VERSION++";
our $my_url = $cgi->url();
our $my_uri = $cgi->url(-absolute => 1);
# if we're called with PATH_INFO, we have to strip that
# from the URL to find our real URL
# we make $path_info global because it's also used later on
# Base URL for relative URLs in gitweb ($logo, $favicon, ...),
# needed and used only for URLs with nonempty PATH_INFO
our $base_url = $my_url;
# When the script is used as DirectoryIndex, the URL does not contain the name
# of the script file itself, and $cgi->url() fails to strip PATH_INFO, so we
# have to do it ourselves. We make $path_info global because it's also used
# later on.
#
# Another issue with the script being the DirectoryIndex is that the resulting
# $my_url data is not the full script URL: this is good, because we want
# generated links to keep implying the script name if it wasn't explicitly
# indicated in the URL we're handling, but it means that $my_url cannot be used
# as base URL.
# Therefore, if we needed to strip PATH_INFO, then we know that we have
# to build the base URL ourselves:
our $path_info = $ENV{"PATH_INFO"};
if ($path_info) {
$my_url =~ s,\Q$path_info\E$,,;
$my_uri =~ s,\Q$path_info\E$,,;
if ($my_url =~ s,\Q$path_info\E$,, &&
$my_uri =~ s,\Q$path_info\E$,, &&
defined $ENV{'SCRIPT_NAME'}) {
$base_url = $cgi->url(-base => 1) . $ENV{'SCRIPT_NAME'};
}
}
# core git executable to use
@@ -132,6 +148,10 @@ our $fallback_encoding = 'latin1';
# - one might want to include '-B' option, e.g. '-B', '-M'
our @diff_opts = ('-M'); # taken from git_commit
# Disables features that would allow repository owners to inject script into
# the gitweb domain.
our $prevent_xss = 0;
# information about snapshot formats that gitweb is capable of serving
our %known_snapshot_formats = (
# name => {
@@ -382,13 +402,13 @@ sub feature_bool {
my $key = shift;
my ($val) = git_get_project_config($key, '--bool');
if ($val eq 'true') {
if (!defined $val) {
return ($_[0]);
} elsif ($val eq 'true') {
return (1);
} elsif ($val eq 'false') {
return (0);
}
return ($_[0]);
}
sub feature_snapshot {
@@ -1364,13 +1384,11 @@ sub format_log_line_html {
my $line = shift;
$line = esc_html($line, -nbsp=>1);
if ($line =~ m/([0-9a-fA-F]{8,40})/) {
my $hash_text = $1;
my $link =
$cgi->a({-href => href(action=>"object", hash=>$hash_text),
-class => "text"}, $hash_text);
$line =~ s/$hash_text/$link/;
}
$line =~ s{\b([0-9a-fA-F]{8,40})\b}{
$cgi->a({-href => href(action=>"object", hash=>$1),
-class => "text"}, $1);
}eg;
return $line;
}
@@ -1894,18 +1912,19 @@ sub git_parse_project_config {
return %config;
}
# convert config value to boolean, 'true' or 'false'
# convert config value to boolean: 'true' or 'false'
# no value, number > 0, 'true' and 'yes' values are true
# rest of values are treated as false (never as error)
sub config_to_bool {
my $val = shift;
return 1 if !defined $val; # section.key
# strip leading and trailing whitespace
$val =~ s/^\s+//;
$val =~ s/\s+$//;
return (!defined $val || # section.key
($val =~ /^\d+$/ && $val) || # section.key = 1
return (($val =~ /^\d+$/ && $val) || # section.key = 1
($val =~ /^(?:true|yes)$/i)); # section.key = true
}
@@ -1958,6 +1977,9 @@ sub git_get_project_config {
$config_file = "$git_dir/config";
}
# check if config variable (key) exists
return unless exists $config{"gitweb.$key"};
# ensure given type
if (!defined $type) {
return $config{"gitweb.$key"};
@@ -2904,7 +2926,7 @@ EOF
# the stylesheet, favicon etc urls won't work correctly with path_info
# unless we set the appropriate base URL
if ($ENV{'PATH_INFO'}) {
print '<base href="'.esc_url($my_url).'" />\n';
print "<base href=\"".esc_url($base_url)."\" />\n";
}
# print out each stylesheet that exist, providing backwards capability
# for those people who defined $stylesheet in a config file
@@ -4503,7 +4525,9 @@ sub git_summary {
print "</table>\n";
if (-s "$projectroot/$project/README.html") {
# If XSS prevention is on, we don't include README.html.
# TODO: Allow a readme in some safe format.
if (!$prevent_xss && -s "$projectroot/$project/README.html") {
print "<div class=\"title\">readme</div>\n" .
"<div class=\"readme\">\n";
insert_file("$projectroot/$project/README.html");
@@ -4764,10 +4788,21 @@ sub git_blob_plain {
$save_as .= '.txt';
}
# With XSS prevention on, blobs of all types except a few known safe
# ones are served with "Content-Disposition: attachment" to make sure
# they don't run in our security domain. For certain image types,
# blob view writes an <img> tag referring to blob_plain view, and we
# want to be sure not to break that by serving the image as an
# attachment (though Firefox 3 doesn't seem to care).
my $sandbox = $prevent_xss &&
$type !~ m!^(?:text/plain|image/(?:gif|png|jpeg))$!;
print $cgi->header(
-type => $type,
-expires => $expires,
-content_disposition => 'inline; filename="' . $save_as . '"');
-content_disposition =>
($sandbox ? 'attachment' : 'inline')
. '; filename="' . $save_as . '"');
undef $/;
binmode STDOUT, ':raw';
print <$fd>;

View File

@@ -153,6 +153,7 @@ struct remote_lock
char *url;
char *owner;
char *token;
char tmpfile_suffix[41];
time_t start_time;
long timeout;
int refreshing;
@@ -557,8 +558,7 @@ static void start_put(struct transfer_request *request)
request->dest = strbuf_detach(&buf, NULL);
append_remote_object_url(&buf, remote->url, hex, 0);
strbuf_addstr(&buf, "_");
strbuf_addstr(&buf, request->lock->token);
strbuf_add(&buf, request->lock->tmpfile_suffix, 41);
request->url = strbuf_detach(&buf, NULL);
slot = get_active_slot();
@@ -1130,6 +1130,8 @@ static void handle_lockprop_ctx(struct xml_ctx *ctx, int tag_closed)
static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed)
{
struct remote_lock *lock = (struct remote_lock *)ctx->userData;
git_SHA_CTX sha_ctx;
unsigned char lock_token_sha1[20];
if (tag_closed && ctx->cdata) {
if (!strcmp(ctx->name, DAV_ACTIVELOCK_OWNER)) {
@@ -1142,6 +1144,13 @@ static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed)
} else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TOKEN)) {
lock->token = xmalloc(strlen(ctx->cdata) + 1);
strcpy(lock->token, ctx->cdata);
git_SHA1_Init(&sha_ctx);
git_SHA1_Update(&sha_ctx, lock->token, strlen(lock->token));
git_SHA1_Final(lock_token_sha1, &sha_ctx);
lock->tmpfile_suffix[0] = '_';
memcpy(lock->tmpfile_suffix + 1, sha1_to_hex(lock_token_sha1), 40);
}
}
}

View File

@@ -172,9 +172,8 @@ static char *open_pack_file(char *pack_name)
input_fd = 0;
if (!pack_name) {
static char tmpfile[PATH_MAX];
snprintf(tmpfile, sizeof(tmpfile),
"%s/pack/tmp_pack_XXXXXX", get_object_directory());
output_fd = xmkstemp(tmpfile);
output_fd = odb_mkstemp(tmpfile, sizeof(tmpfile),
"pack/tmp_pack_XXXXXX");
pack_name = xstrdup(tmpfile);
} else
output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600);
@@ -794,22 +793,24 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
if (keep_msg) {
int keep_fd, keep_msg_len = strlen(keep_msg);
if (!keep_name) {
snprintf(name, sizeof(name), "%s/pack/pack-%s.keep",
get_object_directory(), sha1_to_hex(sha1));
keep_name = name;
}
keep_fd = open(keep_name, O_RDWR|O_CREAT|O_EXCL, 0600);
if (!keep_name)
keep_fd = odb_pack_keep(name, sizeof(name), sha1);
else
keep_fd = open(keep_name, O_RDWR|O_CREAT|O_EXCL, 0600);
if (keep_fd < 0) {
if (errno != EEXIST)
die("cannot write keep file");
die("cannot write keep file '%s' (%s)",
keep_name, strerror(errno));
} else {
if (keep_msg_len > 0) {
write_or_die(keep_fd, keep_msg, keep_msg_len);
write_or_die(keep_fd, "\n", 1);
}
if (close(keep_fd) != 0)
die("cannot write keep file");
die("cannot close written keep file '%s' (%s)",
keep_name, strerror(errno));
report = "keep";
}
}

View File

@@ -155,11 +155,25 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
return lk->fd;
}
NORETURN void unable_to_lock_index_die(const char *path, int err)
{
if (errno == EEXIST) {
die("Unable to create '%s.lock': %s.\n\n"
"If no other git process is currently running, this probably means a\n"
"git process crashed in this repository earlier. Make sure no other git\n"
"process is running and remove the file manually to continue.",
path, strerror(err));
} else {
die("Unable to create '%s.lock': %s", path, strerror(err));
}
}
int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
{
int fd = lock_file(lk, path, flags);
if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
die("unable to create '%s.lock': %s", path, strerror(errno));
unable_to_lock_index_die(path, errno);
return fd;
}

Some files were not shown because too many files have changed in this diff Show More