Merge branch 'master' into js/merge
* master: (42 commits) git-svn: correctly handle packed-refs in refs/remotes/ add test case for recursive merge git-svn: correctly display fatal() error messages git-svn: allow dcommit to take an alternate head git-svn: enable logging of information not supported by git Clarify fetch error for missing objects. Move Fink and Ports check to after config file shortlog: fix segfault on empty authorname shortlog: remove "[PATCH]" prefix from shortlog output Make sure the empty tree exists when needed in merge-recursive. Don't use memcpy when source and dest. buffers may overlap no need to install manpages as executable Documentation: simpler shared repository creation shortlog: fix segfault on empty authorname Add branch.*.merge warning and documentation update Fix perl/ build. git-svn: use do_switch for --follow-parent if the SVN library supports it Fix documentation copy&paste typo git-svn: extra error check to ensure we open a file correctly Documentation: update git-clone man page with new behavior ...maint
commit
8042ed1ceb
|
@ -56,8 +56,8 @@ man7: $(DOC_MAN7)
|
|||
|
||||
install: man
|
||||
$(INSTALL) -d -m755 $(DESTDIR)$(man1dir) $(DESTDIR)$(man7dir)
|
||||
$(INSTALL) $(DOC_MAN1) $(DESTDIR)$(man1dir)
|
||||
$(INSTALL) $(DOC_MAN7) $(DESTDIR)$(man7dir)
|
||||
$(INSTALL) -m644 $(DOC_MAN1) $(DESTDIR)$(man1dir)
|
||||
$(INSTALL) -m644 $(DOC_MAN7) $(DESTDIR)$(man7dir)
|
||||
|
||||
|
||||
#
|
||||
|
|
|
@ -125,10 +125,17 @@ apply.whitespace::
|
|||
|
||||
branch.<name>.remote::
|
||||
When in branch <name>, it tells `git fetch` which remote to fetch.
|
||||
If this option is not given, `git fetch` defaults to remote "origin".
|
||||
|
||||
branch.<name>.merge::
|
||||
When in branch <name>, it tells `git fetch` the default remote branch
|
||||
to be merged.
|
||||
When in branch <name>, it tells `git fetch` the default refspec to
|
||||
be marked for merging in FETCH_HEAD. The value has exactly to match
|
||||
a remote part of one of the refspecs which are fetched from the remote
|
||||
given by "branch.<name>.remote".
|
||||
The merge information is used by `git pull` (which at first calls
|
||||
`git fetch`) to lookup the default branch for merging. Without
|
||||
this option, `git pull` defaults to merge the first refspec fetched.
|
||||
Specify multiple values to get an octopus merge.
|
||||
|
||||
pager.color::
|
||||
A boolean to enable/disable colored output when the pager is in
|
||||
|
|
|
@ -1,43 +1,122 @@
|
|||
git for CVS users
|
||||
=================
|
||||
|
||||
So you're a CVS user. That's OK, it's a treatable condition. The job of
|
||||
this document is to put you on the road to recovery, by helping you
|
||||
convert an existing cvs repository to git, and by showing you how to use a
|
||||
git repository in a cvs-like fashion.
|
||||
Git differs from CVS in that every working tree contains a repository with
|
||||
a full copy of the project history, and no repository is inherently more
|
||||
important than any other. However, you can emulate the CVS model by
|
||||
designating a single shared repository which people can synchronize with;
|
||||
this document explains how to do that.
|
||||
|
||||
Some basic familiarity with git is required. This
|
||||
link:tutorial.html[tutorial introduction to git] should be sufficient.
|
||||
|
||||
First, note some ways that git differs from CVS:
|
||||
Developing against a shared repository
|
||||
--------------------------------------
|
||||
|
||||
* Commits are atomic and project-wide, not per-file as in CVS.
|
||||
Suppose a shared repository is set up in /pub/repo.git on the host
|
||||
foo.com. Then as an individual committer you can clone the shared
|
||||
repository over ssh with:
|
||||
|
||||
* Offline work is supported: you can make multiple commits locally,
|
||||
then submit them when you're ready.
|
||||
------------------------------------------------
|
||||
$ git clone foo.com:/pub/repo.git/ my-project
|
||||
$ cd my-project
|
||||
------------------------------------------------
|
||||
|
||||
* Branching is fast and easy.
|
||||
and hack away. The equivalent of `cvs update` is
|
||||
|
||||
* Every working tree contains a repository with a full copy of the
|
||||
project history, and no repository is inherently more important than
|
||||
any other. However, you can emulate the CVS model by designating a
|
||||
single shared repository which people can synchronize with; see below
|
||||
for details.
|
||||
------------------------------------------------
|
||||
$ git pull origin
|
||||
------------------------------------------------
|
||||
|
||||
which merges in any work that others might have done since the clone
|
||||
operation. If there are uncommitted changes in your working tree, commit
|
||||
them first before running git pull.
|
||||
|
||||
[NOTE]
|
||||
================================
|
||||
The first `git clone` places the following in the
|
||||
`my-project/.git/remotes/origin` file, and that's why the previous step
|
||||
and the next step both work.
|
||||
------------
|
||||
URL: foo.com:/pub/project.git/
|
||||
Pull: refs/heads/master:refs/remotes/origin/master
|
||||
------------
|
||||
================================
|
||||
|
||||
You can update the shared repository with your changes by first committing
|
||||
your changes, and then using the gitlink:git-push[1] command:
|
||||
|
||||
------------------------------------------------
|
||||
$ git push origin master
|
||||
------------------------------------------------
|
||||
|
||||
to "push" those commits to the shared repository. If someone else has
|
||||
updated the repository more recently, `git push`, like `cvs commit`, will
|
||||
complain, in which case you must pull any changes before attempting the
|
||||
push again.
|
||||
|
||||
In the `git push` command above we specify the name of the remote branch
|
||||
to update (`master`). If we leave that out, `git push` tries to update
|
||||
any branches in the remote repository that have the same name as a branch
|
||||
in the local repository. So the last `push` can be done with either of:
|
||||
|
||||
------------
|
||||
$ git push origin
|
||||
$ git push foo.com:/pub/project.git/
|
||||
------------
|
||||
|
||||
as long as the shared repository does not have any branches
|
||||
other than `master`.
|
||||
|
||||
Setting Up a Shared Repository
|
||||
------------------------------
|
||||
|
||||
We assume you have already created a git repository for your project,
|
||||
possibly created from scratch or from a tarball (see the
|
||||
link:tutorial.html[tutorial]), or imported from an already existing CVS
|
||||
repository (see the next section).
|
||||
|
||||
Assume your existing repo is at /home/alice/myproject. Create a new "bare"
|
||||
repository (a repository without a working tree) and fetch your project into
|
||||
it:
|
||||
|
||||
------------------------------------------------
|
||||
$ mkdir /pub/my-repo.git
|
||||
$ cd /pub/my-repo.git
|
||||
$ git --bare init-db --shared
|
||||
$ git --bare fetch /home/alice/myproject master:master
|
||||
------------------------------------------------
|
||||
|
||||
Next, give every team member read/write access to this repository. One
|
||||
easy way to do this is to give all the team members ssh access to the
|
||||
machine where the repository is hosted. If you don't want to give them a
|
||||
full shell on the machine, there is a restricted shell which only allows
|
||||
users to do git pushes and pulls; see gitlink:git-shell[1].
|
||||
|
||||
Put all the committers in the same group, and make the repository
|
||||
writable by that group:
|
||||
|
||||
------------------------------------------------
|
||||
$ chgrp -R $group /pub/my-repo.git
|
||||
------------------------------------------------
|
||||
|
||||
Make sure committers have a umask of at most 027, so that the directories
|
||||
they create are writable and searchable by other group members.
|
||||
|
||||
Importing a CVS archive
|
||||
-----------------------
|
||||
|
||||
First, install version 2.1 or higher of cvsps from
|
||||
link:http://www.cobite.com/cvsps/[http://www.cobite.com/cvsps/] and make
|
||||
sure it is in your path. The magic command line is then
|
||||
sure it is in your path. Then cd to a checked out CVS working directory
|
||||
of the project you are interested in and run gitlink:git-cvsimport[1]:
|
||||
|
||||
-------------------------------------------
|
||||
$ git cvsimport -v -d <cvsroot> -C <destination> <module>
|
||||
$ git cvsimport -C <destination>
|
||||
-------------------------------------------
|
||||
|
||||
This puts a git archive of the named CVS module in the directory
|
||||
<destination>, which will be created if necessary. The -v option makes
|
||||
the conversion script very chatty.
|
||||
<destination>, which will be created if necessary.
|
||||
|
||||
The import checks out from CVS every revision of every file. Reportedly
|
||||
cvsimport can average some twenty revisions per second, so for a
|
||||
|
@ -55,14 +134,32 @@ work, you must not modify the imported branches; instead, create new
|
|||
branches for your own changes, and merge in the imported branches as
|
||||
necessary.
|
||||
|
||||
Development Models
|
||||
------------------
|
||||
Advanced Shared Repository Management
|
||||
-------------------------------------
|
||||
|
||||
Git allows you to specify scripts called "hooks" to be run at certain
|
||||
points. You can use these, for example, to send all commits to the shared
|
||||
repository to a mailing list. See link:hooks.html[Hooks used by git].
|
||||
|
||||
You can enforce finer grained permissions using update hooks. See
|
||||
link:howto/update-hook-example.txt[Controlling access to branches using
|
||||
update hooks].
|
||||
|
||||
Providing CVS Access to a git Repository
|
||||
----------------------------------------
|
||||
|
||||
It is also possible to provide true CVS access to a git repository, so
|
||||
that developers can still use CVS; see gitlink:git-cvsserver[1] for
|
||||
details.
|
||||
|
||||
Alternative Development Models
|
||||
------------------------------
|
||||
|
||||
CVS users are accustomed to giving a group of developers commit access to
|
||||
a common repository. In the next section we'll explain how to do this
|
||||
with git. However, the distributed nature of git allows other development
|
||||
models, and you may want to first consider whether one of them might be a
|
||||
better fit for your project.
|
||||
a common repository. As we've seen, this is also possible with git.
|
||||
However, the distributed nature of git allows other development models,
|
||||
and you may want to first consider whether one of them might be a better
|
||||
fit for your project.
|
||||
|
||||
For example, you can choose a single person to maintain the project's
|
||||
primary public repository. Other developers then clone this repository
|
||||
|
@ -75,230 +172,3 @@ variants of this model.
|
|||
|
||||
With a small group, developers may just pull changes from each other's
|
||||
repositories without the need for a central maintainer.
|
||||
|
||||
Emulating the CVS Development Model
|
||||
-----------------------------------
|
||||
|
||||
Start with an ordinary git working directory containing the project, and
|
||||
remove the checked-out files, keeping just the bare .git directory:
|
||||
|
||||
------------------------------------------------
|
||||
$ mv project/.git /pub/repo.git
|
||||
$ rm -r project/
|
||||
------------------------------------------------
|
||||
|
||||
Next, give every team member read/write access to this repository. One
|
||||
easy way to do this is to give all the team members ssh access to the
|
||||
machine where the repository is hosted. If you don't want to give them a
|
||||
full shell on the machine, there is a restricted shell which only allows
|
||||
users to do git pushes and pulls; see gitlink:git-shell[1].
|
||||
|
||||
Put all the committers in the same group, and make the repository
|
||||
writable by that group:
|
||||
|
||||
------------------------------------------------
|
||||
$ chgrp -R $group repo.git
|
||||
$ find repo.git -mindepth 1 -type d |xargs chmod ug+rwx,g+s
|
||||
$ GIT_DIR=repo.git git repo-config core.sharedrepository true
|
||||
------------------------------------------------
|
||||
|
||||
Make sure committers have a umask of at most 027, so that the directories
|
||||
they create are writable and searchable by other group members.
|
||||
|
||||
Suppose this repository is now set up in /pub/repo.git on the host
|
||||
foo.com. Then as an individual committer you can clone the shared
|
||||
repository:
|
||||
|
||||
------------------------------------------------
|
||||
$ git clone foo.com:/pub/repo.git/ my-project
|
||||
$ cd my-project
|
||||
------------------------------------------------
|
||||
|
||||
and hack away. The equivalent of `cvs update` is
|
||||
|
||||
------------------------------------------------
|
||||
$ git pull origin
|
||||
------------------------------------------------
|
||||
|
||||
which merges in any work that others might have done since the clone
|
||||
operation.
|
||||
|
||||
[NOTE]
|
||||
================================
|
||||
The first `git clone` places the following in the
|
||||
`my-project/.git/remotes/origin` file, and that's why the previous step
|
||||
and the next step both work.
|
||||
------------
|
||||
URL: foo.com:/pub/project.git/ my-project
|
||||
Pull: master:origin
|
||||
------------
|
||||
================================
|
||||
|
||||
You can update the shared repository with your changes using:
|
||||
|
||||
------------------------------------------------
|
||||
$ git push origin master
|
||||
------------------------------------------------
|
||||
|
||||
If someone else has updated the repository more recently, `git push`, like
|
||||
`cvs commit`, will complain, in which case you must pull any changes
|
||||
before attempting the push again.
|
||||
|
||||
In the `git push` command above we specify the name of the remote branch
|
||||
to update (`master`). If we leave that out, `git push` tries to update
|
||||
any branches in the remote repository that have the same name as a branch
|
||||
in the local repository. So the last `push` can be done with either of:
|
||||
|
||||
------------
|
||||
$ git push origin
|
||||
$ git push repo.shared.xz:/pub/scm/project.git/
|
||||
------------
|
||||
|
||||
as long as the shared repository does not have any branches
|
||||
other than `master`.
|
||||
|
||||
[NOTE]
|
||||
============
|
||||
Because of this behavior, if the shared repository and the developer's
|
||||
repository both have branches named `origin`, then a push like the above
|
||||
attempts to update the `origin` branch in the shared repository from the
|
||||
developer's `origin` branch. The results may be unexpected, so it's
|
||||
usually best to remove any branch named `origin` from the shared
|
||||
repository.
|
||||
============
|
||||
|
||||
Advanced Shared Repository Management
|
||||
-------------------------------------
|
||||
|
||||
Git allows you to specify scripts called "hooks" to be run at certain
|
||||
points. You can use these, for example, to send all commits to the shared
|
||||
repository to a mailing list. See link:hooks.html[Hooks used by git].
|
||||
|
||||
You can enforce finer grained permissions using update hooks. See
|
||||
link:howto/update-hook-example.txt[Controlling access to branches using
|
||||
update hooks].
|
||||
|
||||
CVS annotate
|
||||
------------
|
||||
|
||||
So, something has gone wrong, and you don't know whom to blame, and
|
||||
you're an ex-CVS user and used to do "cvs annotate" to see who caused
|
||||
the breakage. You're looking for the "git annotate", and it's just
|
||||
claiming not to find such a script. You're annoyed.
|
||||
|
||||
Yes, that's right. Core git doesn't do "annotate", although it's
|
||||
technically possible, and there are at least two specialized scripts out
|
||||
there that can be used to get equivalent information (see the git
|
||||
mailing list archives for details).
|
||||
|
||||
git has a couple of alternatives, though, that you may find sufficient
|
||||
or even superior depending on your use. One is called "git-whatchanged"
|
||||
(for obvious reasons) and the other one is called "pickaxe" ("a tool for
|
||||
the software archaeologist").
|
||||
|
||||
The "git-whatchanged" script is a truly trivial script that can give you
|
||||
a good overview of what has changed in a file or a directory (or an
|
||||
arbitrary list of files or directories). The "pickaxe" support is an
|
||||
additional layer that can be used to further specify exactly what you're
|
||||
looking for, if you already know the specific area that changed.
|
||||
|
||||
Let's step back a bit and think about the reason why you would
|
||||
want to do "cvs annotate a-file.c" to begin with.
|
||||
|
||||
You would use "cvs annotate" on a file when you have trouble
|
||||
with a function (or even a single "if" statement in a function)
|
||||
that happens to be defined in the file, which does not do what
|
||||
you want it to do. And you would want to find out why it was
|
||||
written that way, because you are about to modify it to suit
|
||||
your needs, and at the same time you do not want to break its
|
||||
current callers. For that, you are trying to find out why the
|
||||
original author did things that way in the original context.
|
||||
|
||||
Many times, it may be enough to see the commit log messages of
|
||||
commits that touch the file in question, possibly along with the
|
||||
patches themselves, like this:
|
||||
|
||||
$ git-whatchanged -p a-file.c
|
||||
|
||||
This will show log messages and patches for each commit that
|
||||
touches a-file.
|
||||
|
||||
This, however, may not be very useful when this file has many
|
||||
modifications that are not related to the piece of code you are
|
||||
interested in. You would see many log messages and patches that
|
||||
do not have anything to do with the piece of code you are
|
||||
interested in. As an example, assuming that you have this piece
|
||||
of code that you are interested in in the HEAD version:
|
||||
|
||||
if (frotz) {
|
||||
nitfol();
|
||||
}
|
||||
|
||||
you would use git-rev-list and git-diff-tree like this:
|
||||
|
||||
$ git-rev-list HEAD |
|
||||
git-diff-tree --stdin -v -p -S'if (frotz) {
|
||||
nitfol();
|
||||
}'
|
||||
|
||||
We have already talked about the "\--stdin" form of git-diff-tree
|
||||
command that reads the list of commits and compares each commit
|
||||
with its parents (otherwise you should go back and read the tutorial).
|
||||
The git-whatchanged command internally runs
|
||||
the equivalent of the above command, and can be used like this:
|
||||
|
||||
$ git-whatchanged -p -S'if (frotz) {
|
||||
nitfol();
|
||||
}'
|
||||
|
||||
When the -S option is used, git-diff-tree command outputs
|
||||
differences between two commits only if one tree has the
|
||||
specified string in a file and the corresponding file in the
|
||||
other tree does not. The above example looks for a commit that
|
||||
has the "if" statement in it in a file, but its parent commit
|
||||
does not have it in the same shape in the corresponding file (or
|
||||
the other way around, where the parent has it and the commit
|
||||
does not), and the differences between them are shown, along
|
||||
with the commit message (thanks to the -v flag). It does not
|
||||
show anything for commits that do not touch this "if" statement.
|
||||
|
||||
Also, in the original context, the same statement might have
|
||||
appeared at first in a different file and later the file was
|
||||
renamed to "a-file.c". CVS annotate would not help you to go
|
||||
back across such a rename, but git would still help you in such
|
||||
a situation. For that, you can give the -C flag to
|
||||
git-diff-tree, like this:
|
||||
|
||||
$ git-whatchanged -p -C -S'if (frotz) {
|
||||
nitfol();
|
||||
}'
|
||||
|
||||
When the -C flag is used, file renames and copies are followed.
|
||||
So if the "if" statement in question happens to be in "a-file.c"
|
||||
in the current HEAD commit, even if the file was originally
|
||||
called "o-file.c" and then renamed in an earlier commit, or if
|
||||
the file was created by copying an existing "o-file.c" in an
|
||||
earlier commit, you will not lose track. If the "if" statement
|
||||
did not change across such a rename or copy, then the commit that
|
||||
does rename or copy would not show in the output, and if the
|
||||
"if" statement was modified while the file was still called
|
||||
"o-file.c", it would find the commit that changed the statement
|
||||
when it was in "o-file.c".
|
||||
|
||||
NOTE: The current version of "git-diff-tree -C" is not eager
|
||||
enough to find copies, and it will miss the fact that a-file.c
|
||||
was created by copying o-file.c unless o-file.c was somehow
|
||||
changed in the same commit.
|
||||
|
||||
You can use the --pickaxe-all flag in addition to the -S flag.
|
||||
This causes the differences from all the files contained in
|
||||
those two commits, not just the differences between the files
|
||||
that contain this changed "if" statement:
|
||||
|
||||
$ git-whatchanged -p -C -S'if (frotz) {
|
||||
nitfol();
|
||||
}' --pickaxe-all
|
||||
|
||||
NOTE: This option is called "--pickaxe-all" because -S
|
||||
option is internally called "pickaxe", a tool for software
|
||||
archaeologists.
|
||||
|
|
|
@ -129,5 +129,21 @@
|
|||
-a::
|
||||
Shorthand for "--text".
|
||||
|
||||
--ignore-space-change::
|
||||
Ignore changes in amount of white space. This ignores white
|
||||
space at line end, and consider all other sequences of one or
|
||||
more white space characters to be equivalent.
|
||||
|
||||
-b::
|
||||
Shorthand for "--ignore-space-change".
|
||||
|
||||
--ignore-all-space::
|
||||
Ignore white space when comparing lines. This ignores
|
||||
difference even if one line has white space where the other
|
||||
line has none.
|
||||
|
||||
-w::
|
||||
Shorthand for "--ignore-all-space".
|
||||
|
||||
For more detailed explanation on these common options, see also
|
||||
link:diffcore.html[diffcore documentation].
|
||||
|
|
|
@ -11,27 +11,26 @@ SYNOPSIS
|
|||
[verse]
|
||||
'git-clone' [--template=<template_directory>] [-l [-s]] [-q] [-n] [--bare]
|
||||
[-o <name>] [-u <upload-pack>] [--reference <repository>]
|
||||
[--use-separate-remote | --use-immingled-remote] <repository>
|
||||
[--use-separate-remote | --no-separate-remote] <repository>
|
||||
[<directory>]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Clones a repository into a newly created directory. All remote
|
||||
branch heads are copied under `$GIT_DIR/refs/heads/`, except
|
||||
that the remote `master` is also copied to `origin` branch.
|
||||
|
||||
In addition, `$GIT_DIR/remotes/origin` file is set up to have
|
||||
this line:
|
||||
Clones a repository into a newly created directory, creates
|
||||
remote-tracking branches for each branch in the cloned repository
|
||||
(visible using `git branch -r`), and creates and checks out a master
|
||||
branch equal to the cloned repository's master branch.
|
||||
|
||||
Pull: master:origin
|
||||
|
||||
This is to help the typical workflow of working off of the
|
||||
remote `master` branch. Every time `git pull` without argument
|
||||
is run, the progress on the remote `master` branch is tracked by
|
||||
copying it into the local `origin` branch, and merged into the
|
||||
branch you are currently working on. Remote branches other than
|
||||
`master` are also added there to be tracked.
|
||||
After the clone, a plain `git fetch` without arguments will update
|
||||
all the remote-tracking branches, and a `git pull` without
|
||||
arguments will in addition merge the remote master branch into the
|
||||
current branch.
|
||||
|
||||
This default configuration is achieved by creating references to
|
||||
the remote branch heads under `$GIT_DIR/refs/remotes/origin` and
|
||||
by initializing `remote.origin.url` and `remote.origin.fetch`
|
||||
configuration variables.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
@ -105,7 +104,7 @@ OPTIONS
|
|||
of `$GIT_DIR/refs/heads/`. Only the local master branch is
|
||||
saved in the latter. This is the default.
|
||||
|
||||
--use-immingled-remote::
|
||||
--no-separate-remote::
|
||||
Save remotes heads in the same namespace as the local
|
||||
heads, `$GIT_DIR/refs/heads/'. In regular repositories,
|
||||
this is a legacy setup git-clone created by default in
|
||||
|
|
|
@ -57,11 +57,13 @@ See '<<fetch-args,Additional Fetch Arguments>>' if you are interested in
|
|||
manually joining branches on commit.
|
||||
|
||||
'dcommit'::
|
||||
Commit all diffs from the current HEAD directly to the SVN
|
||||
Commit all diffs from a specified head directly to the SVN
|
||||
repository, and then rebase or reset (depending on whether or
|
||||
not there is a diff between SVN and HEAD). It is recommended
|
||||
not there is a diff between SVN and head). It is recommended
|
||||
that you run git-svn fetch and rebase (not pull) your commits
|
||||
against the latest changes in the SVN repository.
|
||||
An optional command-line argument may be specified as an
|
||||
alternative to HEAD.
|
||||
This is advantageous over 'commit' (below) because it produces
|
||||
cleaner, more linear history.
|
||||
|
||||
|
|
49
Makefile
49
Makefile
|
@ -91,6 +91,10 @@ all:
|
|||
#
|
||||
# Define USE_STDEV below if you want git to care about the underlying device
|
||||
# change being considered an inode change from the update-cache perspective.
|
||||
#
|
||||
# Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
|
||||
# MakeMaker (e.g. using ActiveState under Cygwin).
|
||||
#
|
||||
|
||||
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
||||
@$(SHELL_PATH) ./GIT-VERSION-GEN
|
||||
|
@ -323,18 +327,6 @@ ifeq ($(uname_S),Darwin)
|
|||
NEEDS_SSL_WITH_CRYPTO = YesPlease
|
||||
NEEDS_LIBICONV = YesPlease
|
||||
NO_STRLCPY = YesPlease
|
||||
ifndef NO_FINK
|
||||
ifeq ($(shell test -d /sw/lib && echo y),y)
|
||||
BASIC_CFLAGS += -I/sw/include
|
||||
BASIC_LDFLAGS += -L/sw/lib
|
||||
endif
|
||||
endif
|
||||
ifndef NO_DARWIN_PORTS
|
||||
ifeq ($(shell test -d /opt/local/lib && echo y),y)
|
||||
BASIC_CFLAGS += -I/opt/local/include
|
||||
BASIC_LDFLAGS += -L/opt/local/lib
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
ifeq ($(uname_S),SunOS)
|
||||
NEEDS_SOCKET = YesPlease
|
||||
|
@ -412,6 +404,21 @@ endif
|
|||
-include config.mak.autogen
|
||||
-include config.mak
|
||||
|
||||
ifeq ($(uname_S),Darwin)
|
||||
ifndef NO_FINK
|
||||
ifeq ($(shell test -d /sw/lib && echo y),y)
|
||||
BASIC_CFLAGS += -I/sw/include
|
||||
BASIC_LDFLAGS += -L/sw/lib
|
||||
endif
|
||||
endif
|
||||
ifndef NO_DARWIN_PORTS
|
||||
ifeq ($(shell test -d /opt/local/lib && echo y),y)
|
||||
BASIC_CFLAGS += -I/opt/local/include
|
||||
BASIC_LDFLAGS += -L/opt/local/lib
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef NO_CURL
|
||||
ifdef CURLDIR
|
||||
# This is still problematic -- gcc does not always want -R.
|
||||
|
@ -540,6 +547,9 @@ endif
|
|||
ifdef NO_ACCURATE_DIFF
|
||||
BASIC_CFLAGS += -DNO_ACCURATE_DIFF
|
||||
endif
|
||||
ifdef NO_PERL_MAKEMAKER
|
||||
export NO_PERL_MAKEMAKER
|
||||
endif
|
||||
|
||||
# Shell quote (do not use $(call) to accommodate ancient setups);
|
||||
|
||||
|
@ -569,8 +579,8 @@ export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
|
|||
|
||||
all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi
|
||||
|
||||
all: perl/Makefile
|
||||
$(MAKE) -C perl
|
||||
all:
|
||||
$(MAKE) -C perl PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all
|
||||
$(MAKE) -C templates
|
||||
|
||||
strip: $(PROGRAMS) git$X
|
||||
|
@ -603,7 +613,11 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
|
|||
chmod +x $@+
|
||||
mv $@+ $@
|
||||
|
||||
$(patsubst %.perl,%,$(SCRIPT_PERL)): perl/Makefile
|
||||
$(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak
|
||||
|
||||
perl/perl.mak: GIT-CFLAGS
|
||||
$(MAKE) -C perl PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F)
|
||||
|
||||
$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
|
||||
rm -f $@ $@+
|
||||
INSTLIBDIR=`$(MAKE) -C perl -s --no-print-directory instlibdir` && \
|
||||
|
@ -798,7 +812,7 @@ install: all
|
|||
$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
|
||||
$(INSTALL) git$X gitk '$(DESTDIR_SQ)$(bindir_SQ)'
|
||||
$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
|
||||
$(MAKE) -C perl install
|
||||
$(MAKE) -C perl prefix='$(prefix_SQ)' install
|
||||
if test 'z$(bindir_SQ)' != 'z$(gitexecdir_SQ)'; \
|
||||
then \
|
||||
ln -f '$(DESTDIR_SQ)$(bindir_SQ)/git$X' \
|
||||
|
@ -868,8 +882,7 @@ clean:
|
|||
rm -f $(htmldocs).tar.gz $(manpages).tar.gz
|
||||
rm -f gitweb/gitweb.cgi
|
||||
$(MAKE) -C Documentation/ clean
|
||||
[ ! -f perl/Makefile ] || $(MAKE) -C perl/ clean || $(MAKE) -C perl/ clean
|
||||
rm -f perl/ppport.h perl/Makefile.old
|
||||
$(MAKE) -C perl clean
|
||||
$(MAKE) -C templates/ clean
|
||||
$(MAKE) -C t/ clean
|
||||
rm -f GIT-VERSION-FILE GIT-CFLAGS
|
||||
|
|
11
builtin-mv.c
11
builtin-mv.c
|
@ -146,21 +146,24 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
|||
&& lstat(dst, &st) == 0)
|
||||
bad = "cannot move directory over file";
|
||||
else if (src_is_dir) {
|
||||
const char *src_w_slash = add_slash(src);
|
||||
int len_w_slash = length + 1;
|
||||
int first, last;
|
||||
|
||||
modes[i] = WORKING_DIRECTORY;
|
||||
|
||||
first = cache_name_pos(src, length);
|
||||
first = cache_name_pos(src_w_slash, len_w_slash);
|
||||
if (first >= 0)
|
||||
die ("Huh? %s/ is in index?", src);
|
||||
die ("Huh? %.*s is in index?",
|
||||
len_w_slash, src_w_slash);
|
||||
|
||||
first = -1 - first;
|
||||
for (last = first; last < active_nr; last++) {
|
||||
const char *path = active_cache[last]->name;
|
||||
if (strncmp(path, src, length)
|
||||
|| path[length] != '/')
|
||||
if (strncmp(path, src_w_slash, len_w_slash))
|
||||
break;
|
||||
}
|
||||
free((char *)src_w_slash);
|
||||
|
||||
if (last - first < 1)
|
||||
bad = "source directory is empty";
|
||||
|
|
|
@ -188,18 +188,25 @@ static void read_from_stdin(struct path_list *list)
|
|||
bob = buffer + strlen(buffer);
|
||||
else {
|
||||
offset = 8;
|
||||
while (isspace(bob[-1]))
|
||||
while (buffer + offset < bob &&
|
||||
isspace(bob[-1]))
|
||||
bob--;
|
||||
}
|
||||
|
||||
while (fgets(buffer2, sizeof(buffer2), stdin) &&
|
||||
buffer2[0] != '\n')
|
||||
; /* chomp input */
|
||||
if (fgets(buffer2, sizeof(buffer2), stdin))
|
||||
if (fgets(buffer2, sizeof(buffer2), stdin)) {
|
||||
int l2 = strlen(buffer2);
|
||||
int i;
|
||||
for (i = 0; i < l2; i++)
|
||||
if (!isspace(buffer2[i]))
|
||||
break;
|
||||
insert_author_oneline(list,
|
||||
buffer + offset,
|
||||
bob - buffer - offset,
|
||||
buffer2, strlen(buffer2));
|
||||
buffer2 + i, l2 - i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -236,7 +243,7 @@ static void get_from_rev(struct rev_info *rev, struct path_list *list)
|
|||
author = scratch;
|
||||
authorlen = strlen(scratch);
|
||||
} else {
|
||||
while (bracket[-1] == ' ')
|
||||
if (bracket[-1] == ' ')
|
||||
bracket--;
|
||||
|
||||
author = buffer + 7;
|
||||
|
|
15
fetch.c
15
fetch.c
|
@ -22,14 +22,15 @@ void pull_say(const char *fmt, const char *hex)
|
|||
fprintf(stderr, fmt, hex);
|
||||
}
|
||||
|
||||
static void report_missing(const char *what, const unsigned char *missing)
|
||||
static void report_missing(const struct object *obj)
|
||||
{
|
||||
char missing_hex[41];
|
||||
|
||||
strcpy(missing_hex, sha1_to_hex(missing));;
|
||||
fprintf(stderr,
|
||||
"Cannot obtain needed %s %s\nwhile processing commit %s.\n",
|
||||
what, missing_hex, sha1_to_hex(current_commit_sha1));
|
||||
strcpy(missing_hex, sha1_to_hex(obj->sha1));;
|
||||
fprintf(stderr, "Cannot obtain needed %s %s\n",
|
||||
obj->type ? typename(obj->type): "object", missing_hex);
|
||||
if (!is_null_sha1(current_commit_sha1))
|
||||
fprintf(stderr, "while processing commit %s.\n",
|
||||
sha1_to_hex(current_commit_sha1));
|
||||
}
|
||||
|
||||
static int process(struct object *obj);
|
||||
|
@ -177,7 +178,7 @@ static int loop(void)
|
|||
*/
|
||||
if (! (obj->flags & TO_SCAN)) {
|
||||
if (fetch(obj->sha1)) {
|
||||
report_missing(typename(obj->type), obj->sha1);
|
||||
report_missing(obj);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
16
git-clone.sh
16
git-clone.sh
|
@ -14,7 +14,7 @@ die() {
|
|||
}
|
||||
|
||||
usage() {
|
||||
die "Usage: $0 [--template=<template_directory>] [--use-immingled-remote] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [-n] <repo> [<dir>]"
|
||||
die "Usage: $0 [--template=<template_directory>] [--no-separate-remote] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [-n] <repo> [<dir>]"
|
||||
}
|
||||
|
||||
get_repo_base() {
|
||||
|
@ -140,7 +140,7 @@ while
|
|||
*,--use-separate-remote)
|
||||
# default
|
||||
use_separate_remote=t ;;
|
||||
*,--use-immingled-remote)
|
||||
*,--no-separate-remote)
|
||||
use_separate_remote= ;;
|
||||
1,--reference) usage ;;
|
||||
*,--reference)
|
||||
|
@ -176,7 +176,7 @@ repo="$1"
|
|||
test -n "$repo" ||
|
||||
die 'you must specify a repository to clone.'
|
||||
|
||||
# --bare implies --no-checkout and --use-immingled-remote
|
||||
# --bare implies --no-checkout and --no-separate-remote
|
||||
if test yes = "$bare"
|
||||
then
|
||||
if test yes = "$origin_override"
|
||||
|
@ -377,9 +377,9 @@ then
|
|||
*) origin_track="$remote_top/$origin"
|
||||
git-update-ref "refs/heads/$origin" "$head_sha1" ;;
|
||||
esac &&
|
||||
echo >"$GIT_DIR/remotes/$origin" \
|
||||
"URL: $repo
|
||||
Pull: refs/heads/$head_points_at:$origin_track" &&
|
||||
git-repo-config remote."$origin".url "$repo" &&
|
||||
git-repo-config remote."$origin".fetch \
|
||||
"refs/heads/$head_points_at:$origin_track" &&
|
||||
(cd "$GIT_DIR/$remote_top" && find . -type f -print) |
|
||||
while read dotslref
|
||||
do
|
||||
|
@ -393,8 +393,8 @@ Pull: refs/heads/$head_points_at:$origin_track" &&
|
|||
then
|
||||
continue
|
||||
fi
|
||||
echo "Pull: refs/heads/${name}:$remote_top/${name}"
|
||||
done >>"$GIT_DIR/remotes/$origin" &&
|
||||
git-repo-config remote."$origin".fetch "refs/heads/${name}:$remote_top/${name}" '^$'
|
||||
done &&
|
||||
case "$use_separate_remote" in
|
||||
t)
|
||||
rm -f "refs/remotes/$origin/HEAD"
|
||||
|
|
|
@ -116,6 +116,7 @@ if ($opt_a) {
|
|||
close MSG;
|
||||
|
||||
my (@afiles, @dfiles, @mfiles, @dirs);
|
||||
my %amodes;
|
||||
my @files = safe_pipe_capture('git-diff-tree', '-r', $parent, $commit);
|
||||
#print @files;
|
||||
$? && die "Error in git-diff-tree";
|
||||
|
@ -124,6 +125,7 @@ foreach my $f (@files) {
|
|||
my @fields = split(m!\s+!, $f);
|
||||
if ($fields[4] eq 'A') {
|
||||
my $path = $fields[5];
|
||||
$amodes{$path} = $fields[1];
|
||||
push @afiles, $path;
|
||||
# add any needed parent directories
|
||||
$path = dirname $path;
|
||||
|
@ -268,6 +270,7 @@ if (($? >> 8) == 2) {
|
|||
}
|
||||
|
||||
foreach my $f (@afiles) {
|
||||
set_new_file_permissions($f, $amodes{$f});
|
||||
if (grep { $_ eq $f } @bfiles) {
|
||||
system('cvs', 'add','-kb',$f);
|
||||
} else {
|
||||
|
@ -342,3 +345,13 @@ sub safe_pipe_capture {
|
|||
}
|
||||
return wantarray ? @output : join('',@output);
|
||||
}
|
||||
|
||||
# For any file we want to add to cvs, we must first set its permissions
|
||||
# properly, *before* the "cvs add ..." command. Otherwise, it is impossible
|
||||
# to change the permission of the file in the CVS repository using only cvs
|
||||
# commands. This should be fixed in cvs-1.12.14.
|
||||
sub set_new_file_permissions {
|
||||
my ($file, $perm) = @_;
|
||||
chmod oct($perm), $file
|
||||
or die "failed to set permissions of \"$file\": $!\n";
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
use strict;
|
||||
use warnings;
|
||||
use bytes;
|
||||
|
||||
use Fcntl;
|
||||
use File::Temp qw/tempdir tempfile/;
|
||||
|
|
|
@ -188,8 +188,9 @@ else
|
|||
# in this loop.
|
||||
merge_name=$(for remote
|
||||
do
|
||||
rh=$(git-rev-parse --verify "$remote"^0 2>/dev/null) &&
|
||||
bh=$(git show-ref -s --verify "refs/heads/$remote") &&
|
||||
rh=$(git-rev-parse --verify "$remote"^0 2>/dev/null) ||
|
||||
continue ;# not something we can merge
|
||||
bh=$(git show-ref -s --verify "refs/heads/$remote" 2>/dev/null)
|
||||
if test "$rh" = "$bh"
|
||||
then
|
||||
echo "$rh branch '$remote' of ."
|
||||
|
|
|
@ -116,7 +116,7 @@ expand_refs_wildcard () {
|
|||
while read sha1 name
|
||||
do
|
||||
mapped=${name#"$from"}
|
||||
if test "z$name" != "z${name#'^{}'}" ||
|
||||
if test "z$name" != "z${name%'^{}'}" ||
|
||||
test "z$name" = "z$mapped"
|
||||
then
|
||||
continue
|
||||
|
@ -134,6 +134,8 @@ canon_refs_list_for_fetch () {
|
|||
# or the first one otherwise; add prefix . to the rest
|
||||
# to prevent the secondary branches to be merged by default.
|
||||
merge_branches=
|
||||
found_mergeref=
|
||||
curr_branch=
|
||||
if test "$1" = "-d"
|
||||
then
|
||||
shift ; remote="$1" ; shift
|
||||
|
@ -171,6 +173,10 @@ canon_refs_list_for_fetch () {
|
|||
dot_prefix= && break
|
||||
done
|
||||
fi
|
||||
if test -z $dot_prefix
|
||||
then
|
||||
found_mergeref=true
|
||||
fi
|
||||
case "$remote" in
|
||||
'') remote=HEAD ;;
|
||||
refs/heads/* | refs/tags/* | refs/remotes/*) ;;
|
||||
|
@ -191,6 +197,11 @@ canon_refs_list_for_fetch () {
|
|||
fi
|
||||
echo "${dot_prefix}${force}${remote}:${local}"
|
||||
done
|
||||
if test -z "$found_mergeref" -a "$curr_branch"
|
||||
then
|
||||
echo >&2 "Warning: No merge candidate found because value of config option
|
||||
\"branch.${curr_branch}.merge\" does not match any remote branch fetched."
|
||||
fi
|
||||
}
|
||||
|
||||
# Returns list of src: (no store), or src:dst (store)
|
||||
|
|
|
@ -30,4 +30,4 @@ echo " $url"
|
|||
echo
|
||||
|
||||
git log $baserev..$headrev | git-shortlog ;
|
||||
git diff --stat --summary $baserev..$headrev
|
||||
git diff -M --stat --summary $baserev..$headrev
|
||||
|
|
|
@ -63,6 +63,7 @@ case "$reset_type" in
|
|||
;;
|
||||
esac
|
||||
|
||||
rm -f "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/rr-cache/MERGE_RR" "$GIT_DIR/SQUASH_MSG"
|
||||
rm -f "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/rr-cache/MERGE_RR" \
|
||||
"$GIT_DIR/SQUASH_MSG" "$GIT_DIR/MERGE_MSG"
|
||||
|
||||
exit $update_ref_status
|
||||
|
|
275
git-svn.perl
275
git-svn.perl
|
@ -21,7 +21,17 @@ $ENV{TZ} = 'UTC';
|
|||
$ENV{LC_ALL} = 'C';
|
||||
$| = 1; # unbuffer STDOUT
|
||||
|
||||
sub fatal (@) { print STDERR $@; exit 1 }
|
||||
# properties that we do not log:
|
||||
my %SKIP = ( 'svn:wc:ra_dav:version-url' => 1,
|
||||
'svn:special' => 1,
|
||||
'svn:executable' => 1,
|
||||
'svn:entry:committed-rev' => 1,
|
||||
'svn:entry:last-author' => 1,
|
||||
'svn:entry:uuid' => 1,
|
||||
'svn:entry:committed-date' => 1,
|
||||
);
|
||||
|
||||
sub fatal (@) { print STDERR @_; exit 1 }
|
||||
# If SVN:: library support is added, please make the dependencies
|
||||
# optional and preserve the capability to use the command-line client.
|
||||
# use eval { require SVN::... } to make it lazy load
|
||||
|
@ -72,7 +82,7 @@ my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit,
|
|||
$_username, $_config_dir, $_no_auth_cache, $_xfer_delta,
|
||||
$_pager, $_color);
|
||||
my (@_branch_from, %tree_map, %users, %rusers, %equiv);
|
||||
my ($_svn_co_url_revs, $_svn_pg_peg_revs);
|
||||
my ($_svn_co_url_revs, $_svn_pg_peg_revs, $_svn_can_do_switch);
|
||||
my @repo_path_split_cache;
|
||||
|
||||
my %fc_opts = ( 'no-ignore-externals' => \$_no_ignore_ext,
|
||||
|
@ -459,6 +469,7 @@ sub fetch_lib {
|
|||
$min = $max + 1;
|
||||
$max += $inc;
|
||||
$max = $head if ($max > $head);
|
||||
$SVN = libsvn_connect($SVN_URL);
|
||||
}
|
||||
restore_index($index);
|
||||
return { revision => $last_rev, commit => $last_commit };
|
||||
|
@ -593,8 +604,9 @@ sub commit_lib {
|
|||
}
|
||||
|
||||
sub dcommit {
|
||||
my $head = shift || 'HEAD';
|
||||
my $gs = "refs/remotes/$GIT_SVN";
|
||||
chomp(my @refs = safe_qx(qw/git-rev-list --no-merges/, "$gs..HEAD"));
|
||||
chomp(my @refs = safe_qx(qw/git-rev-list --no-merges/, "$gs..$head"));
|
||||
my $last_rev;
|
||||
foreach my $d (reverse @refs) {
|
||||
if (quiet_run('git-rev-parse','--verify',"$d~1") != 0) {
|
||||
|
@ -621,16 +633,16 @@ sub dcommit {
|
|||
}
|
||||
return if $_dry_run;
|
||||
fetch();
|
||||
my @diff = safe_qx(qw/git-diff-tree HEAD/, $gs);
|
||||
my @diff = safe_qx('git-diff-tree', $head, $gs);
|
||||
my @finish;
|
||||
if (@diff) {
|
||||
@finish = qw/rebase/;
|
||||
push @finish, qw/--merge/ if $_merge;
|
||||
push @finish, "--strategy=$_strategy" if $_strategy;
|
||||
print STDERR "W: HEAD and $gs differ, using @finish:\n", @diff;
|
||||
print STDERR "W: $head and $gs differ, using @finish:\n", @diff;
|
||||
} else {
|
||||
print "No changes between current HEAD and $gs\n",
|
||||
"Hard resetting to the latest $gs\n";
|
||||
print "No changes between current $head and $gs\n",
|
||||
"Resetting to the latest $gs\n";
|
||||
@finish = qw/reset --mixed/;
|
||||
}
|
||||
sys('git', @finish, $gs);
|
||||
|
@ -2015,9 +2027,17 @@ sub git_commit {
|
|||
|
||||
# just in case we clobber the existing ref, we still want that ref
|
||||
# as our parent:
|
||||
if (my $cur = eval { file_to_s("$GIT_DIR/refs/remotes/$GIT_SVN") }) {
|
||||
open my $null, '>', '/dev/null' or croak $!;
|
||||
open my $stderr, '>&', \*STDERR or croak $!;
|
||||
open STDERR, '>&', $null or croak $!;
|
||||
if (my $cur = eval { safe_qx('git-rev-parse',
|
||||
"refs/remotes/$GIT_SVN^0") }) {
|
||||
chomp $cur;
|
||||
push @tmp_parents, $cur;
|
||||
}
|
||||
open STDERR, '>&', $stderr or croak $!;
|
||||
close $stderr or croak $!;
|
||||
close $null or croak $!;
|
||||
|
||||
if (exists $tree_map{$tree}) {
|
||||
foreach my $p (@{$tree_map{$tree}}) {
|
||||
|
@ -2876,6 +2896,24 @@ sub libsvn_connect {
|
|||
return $ra;
|
||||
}
|
||||
|
||||
sub libsvn_can_do_switch {
|
||||
unless (defined $_svn_can_do_switch) {
|
||||
my $pool = SVN::Pool->new;
|
||||
my $rep = eval {
|
||||
$SVN->do_switch(1, '', 0, $SVN->{url},
|
||||
SVN::Delta::Editor->new, $pool);
|
||||
};
|
||||
if ($@) {
|
||||
$_svn_can_do_switch = 0;
|
||||
} else {
|
||||
$rep->abort_report($pool);
|
||||
$_svn_can_do_switch = 1;
|
||||
}
|
||||
$pool->clear;
|
||||
}
|
||||
$_svn_can_do_switch;
|
||||
}
|
||||
|
||||
sub libsvn_dup_ra {
|
||||
my ($ra) = @_;
|
||||
SVN::Ra->new(map { $_ => $ra->{$_} } qw/config url
|
||||
|
@ -2883,7 +2921,7 @@ sub libsvn_dup_ra {
|
|||
}
|
||||
|
||||
sub libsvn_get_file {
|
||||
my ($gui, $f, $rev, $chg) = @_;
|
||||
my ($gui, $f, $rev, $chg, $untracked) = @_;
|
||||
$f =~ s#^/##;
|
||||
print "\t$chg\t$f\n" unless $_q;
|
||||
|
||||
|
@ -2921,11 +2959,25 @@ sub libsvn_get_file {
|
|||
waitpid $pid, 0;
|
||||
$hash =~ /^$sha1$/o or die "not a sha1: $hash\n";
|
||||
}
|
||||
%{$untracked->{file_prop}->{$f}} = %$props;
|
||||
print $gui $mode,' ',$hash,"\t",$f,"\0" or croak $!;
|
||||
}
|
||||
|
||||
sub uri_encode {
|
||||
my ($f) = @_;
|
||||
$f =~ s#([^a-zA-Z0-9\*!\:_\./\-])#uc sprintf("%%%02x",ord($1))#eg;
|
||||
$f
|
||||
}
|
||||
|
||||
sub uri_decode {
|
||||
my ($f) = @_;
|
||||
$f =~ tr/+/ /;
|
||||
$f =~ s/%([A-F0-9]{2})/chr hex($1)/ge;
|
||||
$f
|
||||
}
|
||||
|
||||
sub libsvn_log_entry {
|
||||
my ($rev, $author, $date, $msg, $parents) = @_;
|
||||
my ($rev, $author, $date, $msg, $parents, $untracked) = @_;
|
||||
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 die "Unable to parse date: $date\n";
|
||||
|
@ -2933,8 +2985,65 @@ sub libsvn_log_entry {
|
|||
die "Author: $author not defined in $_authors file\n";
|
||||
}
|
||||
$msg = '' if ($rev == 0 && !defined $msg);
|
||||
return { revision => $rev, date => "+0000 $Y-$m-$d $H:$M:$S",
|
||||
author => $author, msg => $msg."\n", parents => $parents || [] }
|
||||
|
||||
open my $un, '>>', "$GIT_SVN_DIR/unhandled.log" or croak $!;
|
||||
my $h;
|
||||
print $un "r$rev\n" or croak $!;
|
||||
$h = $untracked->{empty};
|
||||
foreach (sort keys %$h) {
|
||||
my $act = $h->{$_} ? '+empty_dir' : '-empty_dir';
|
||||
print $un " $act: ", uri_encode($_), "\n" or croak $!;
|
||||
warn "W: $act: $_\n";
|
||||
}
|
||||
foreach my $t (qw/dir_prop file_prop/) {
|
||||
$h = $untracked->{$t} or next;
|
||||
foreach my $path (sort keys %$h) {
|
||||
my $ppath = $path eq '' ? '.' : $path;
|
||||
foreach my $prop (sort keys %{$h->{$path}}) {
|
||||
next if $SKIP{$prop};
|
||||
my $v = $h->{$path}->{$prop};
|
||||
if (defined $v) {
|
||||
print $un " +$t: ",
|
||||
uri_encode($ppath), ' ',
|
||||
uri_encode($prop), ' ',
|
||||
uri_encode($v), "\n"
|
||||
or croak $!;
|
||||
} else {
|
||||
print $un " -$t: ",
|
||||
uri_encode($ppath), ' ',
|
||||
uri_encode($prop), "\n"
|
||||
or croak $!;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach my $t (qw/absent_file absent_directory/) {
|
||||
$h = $untracked->{$t} or next;
|
||||
foreach my $parent (sort keys %$h) {
|
||||
foreach my $path (sort @{$h->{$parent}}) {
|
||||
print $un " $t: ",
|
||||
uri_encode("$parent/$path"), "\n"
|
||||
or croak $!;
|
||||
warn "W: $t: $parent/$path ",
|
||||
"Insufficient permissions?\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# revprops (make this optional? it's an extra network trip...)
|
||||
my $pool = SVN::Pool->new;
|
||||
my $rp = $SVN->rev_proplist($rev, $pool);
|
||||
foreach (sort keys %$rp) {
|
||||
next if /^svn:(?:author|date|log)$/;
|
||||
print $un " rev_prop: ", uri_encode($_), ' ',
|
||||
uri_encode($rp->{$_}), "\n";
|
||||
}
|
||||
$pool->clear;
|
||||
close $un or croak $!;
|
||||
|
||||
{ revision => $rev, date => "+0000 $Y-$m-$d $H:$M:$S",
|
||||
author => $author, msg => $msg."\n", parents => $parents || [],
|
||||
revprops => $rp }
|
||||
}
|
||||
|
||||
sub process_rm {
|
||||
|
@ -2953,9 +3062,11 @@ sub process_rm {
|
|||
}
|
||||
print "\tD\t$f/\n" unless $q;
|
||||
close $ls or croak $?;
|
||||
return $SVN::Node::dir;
|
||||
} else {
|
||||
print $gui '0 ',0 x 40,"\t",$f,"\0" or croak $!;
|
||||
print "\tD\t$f\n" unless $q;
|
||||
return $SVN::Node::file;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2976,13 +3087,14 @@ sub libsvn_fetch_delta {
|
|||
unless ($ed->{git_commit_ok}) {
|
||||
die "SVN connection failed somewhere...\n";
|
||||
}
|
||||
libsvn_log_entry($rev, $author, $date, $msg, [$last_commit]);
|
||||
libsvn_log_entry($rev, $author, $date, $msg, [$last_commit], $ed);
|
||||
}
|
||||
|
||||
sub libsvn_fetch_full {
|
||||
my ($last_commit, $paths, $rev, $author, $date, $msg) = @_;
|
||||
open my $gui, '| git-update-index -z --index-info' or croak $!;
|
||||
my %amr;
|
||||
my $ut = { empty => {}, dir_prop => {}, file_prop => {} };
|
||||
my $p = $SVN->{svn_path};
|
||||
foreach my $f (keys %$paths) {
|
||||
my $m = $paths->{$f}->action();
|
||||
|
@ -2993,8 +3105,11 @@ sub libsvn_fetch_full {
|
|||
$f =~ s#^/##;
|
||||
}
|
||||
if ($m =~ /^[DR]$/) {
|
||||
process_rm($gui, $last_commit, $f, $_q);
|
||||
next if $m eq 'D';
|
||||
my $t = process_rm($gui, $last_commit, $f, $_q);
|
||||
if ($m eq 'D') {
|
||||
$ut->{empty}->{$f} = 0 if $t == $SVN::Node::dir;
|
||||
next;
|
||||
}
|
||||
# 'R' can be file replacements, too, right?
|
||||
}
|
||||
my $pool = SVN::Pool->new;
|
||||
|
@ -3007,18 +3122,32 @@ sub libsvn_fetch_full {
|
|||
}
|
||||
} elsif ($t == $SVN::Node::dir && $m =~ /^[AR]$/) {
|
||||
my @traversed = ();
|
||||
libsvn_traverse($gui, '', $f, $rev, \@traversed);
|
||||
foreach (@traversed) {
|
||||
$amr{$_} = $m;
|
||||
libsvn_traverse($gui, '', $f, $rev, \@traversed, $ut);
|
||||
if (@traversed) {
|
||||
foreach (@traversed) {
|
||||
$amr{$_} = $m;
|
||||
}
|
||||
} else {
|
||||
my ($dir, $file) = ($f =~ m#^(.*?)/?([^/]+)$#);
|
||||
delete $ut->{empty}->{$dir};
|
||||
$ut->{empty}->{$f} = 1;
|
||||
}
|
||||
}
|
||||
$pool->clear;
|
||||
}
|
||||
foreach (keys %amr) {
|
||||
libsvn_get_file($gui, $_, $rev, $amr{$_});
|
||||
libsvn_get_file($gui, $_, $rev, $amr{$_}, $ut);
|
||||
my ($d) = ($_ =~ m#^(.*?)/?(?:[^/]+)$#);
|
||||
delete $ut->{empty}->{$d};
|
||||
}
|
||||
unless (exists $ut->{dir_prop}->{''}) {
|
||||
my $pool = SVN::Pool->new;
|
||||
my (undef, undef, $props) = $SVN->get_dir('', $rev, $pool);
|
||||
%{$ut->{dir_prop}->{''}} = %$props;
|
||||
$pool->clear;
|
||||
}
|
||||
close $gui or croak $?;
|
||||
return libsvn_log_entry($rev, $author, $date, $msg, [$last_commit]);
|
||||
libsvn_log_entry($rev, $author, $date, $msg, [$last_commit], $ut);
|
||||
}
|
||||
|
||||
sub svn_grab_base_rev {
|
||||
|
@ -3079,25 +3208,38 @@ sub libsvn_parse_revision {
|
|||
}
|
||||
|
||||
sub libsvn_traverse {
|
||||
my ($gui, $pfx, $path, $rev, $files) = @_;
|
||||
my ($gui, $pfx, $path, $rev, $files, $untracked) = @_;
|
||||
my $cwd = length $pfx ? "$pfx/$path" : $path;
|
||||
my $pool = SVN::Pool->new;
|
||||
$cwd =~ s#^\Q$SVN->{svn_path}\E##;
|
||||
my $nr = 0;
|
||||
my ($dirent, $r, $props) = $SVN->get_dir($cwd, $rev, $pool);
|
||||
%{$untracked->{dir_prop}->{$cwd}} = %$props;
|
||||
foreach my $d (keys %$dirent) {
|
||||
my $t = $dirent->{$d}->kind;
|
||||
if ($t == $SVN::Node::dir) {
|
||||
libsvn_traverse($gui, $cwd, $d, $rev, $files);
|
||||
my $i = libsvn_traverse($gui, $cwd, $d, $rev,
|
||||
$files, $untracked);
|
||||
if ($i) {
|
||||
$nr += $i;
|
||||
} else {
|
||||
$untracked->{empty}->{"$cwd/$d"} = 1;
|
||||
}
|
||||
} elsif ($t == $SVN::Node::file) {
|
||||
$nr++;
|
||||
my $file = "$cwd/$d";
|
||||
if (defined $files) {
|
||||
push @$files, $file;
|
||||
} else {
|
||||
libsvn_get_file($gui, $file, $rev, 'A');
|
||||
libsvn_get_file($gui, $file, $rev, 'A',
|
||||
$untracked);
|
||||
my ($dir) = ($file =~ m#^(.*?)/?(?:[^/]+)$#);
|
||||
delete $untracked->{empty}->{$dir};
|
||||
}
|
||||
}
|
||||
}
|
||||
$pool->clear;
|
||||
$nr;
|
||||
}
|
||||
|
||||
sub libsvn_traverse_ignore {
|
||||
|
@ -3197,12 +3339,26 @@ sub libsvn_find_parent_branch {
|
|||
unlink $GIT_SVN_INDEX;
|
||||
print STDERR "Found branch parent: ($GIT_SVN) $parent\n";
|
||||
sys(qw/git-read-tree/, $parent);
|
||||
# I can't seem to get do_switch() to work correctly with
|
||||
# the SWIG interface (TypeError when passing switch_url...),
|
||||
# so we'll unconditionally bypass the delta interface here
|
||||
# for now
|
||||
return libsvn_fetch_full($parent, $paths, $rev,
|
||||
$author, $date, $msg);
|
||||
unless (libsvn_can_do_switch()) {
|
||||
return libsvn_fetch_full($parent, $paths, $rev,
|
||||
$author, $date, $msg);
|
||||
}
|
||||
# do_switch works with svn/trunk >= r22312, but that is not
|
||||
# included with SVN 1.4.2 (the latest version at the moment),
|
||||
# so we can't rely on it.
|
||||
my $ra = libsvn_connect("$url/$branch_from");
|
||||
my $ed = SVN::Git::Fetcher->new({c => $parent, q => $_q});
|
||||
my $pool = SVN::Pool->new;
|
||||
my $reporter = $ra->do_switch($rev, '', 1, $SVN->{url},
|
||||
$ed, $pool);
|
||||
my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef) : ();
|
||||
$reporter->set_path('', $r0, 0, @lock, $pool);
|
||||
$reporter->finish_report($pool);
|
||||
$pool->clear;
|
||||
unless ($ed->{git_commit_ok}) {
|
||||
die "SVN connection failed somewhere...\n";
|
||||
}
|
||||
return libsvn_log_entry($rev, $author, $date, $msg, [$parent]);
|
||||
}
|
||||
print STDERR "Nope, branch point not imported or unknown\n";
|
||||
return undef;
|
||||
|
@ -3222,6 +3378,7 @@ sub libsvn_new_tree {
|
|||
return $log_entry;
|
||||
}
|
||||
my ($paths, $rev, $author, $date, $msg) = @_;
|
||||
my $ut;
|
||||
if ($_xfer_delta) {
|
||||
my $pool = SVN::Pool->new;
|
||||
my $ed = SVN::Git::Fetcher->new({q => $_q});
|
||||
|
@ -3233,12 +3390,14 @@ sub libsvn_new_tree {
|
|||
unless ($ed->{git_commit_ok}) {
|
||||
die "SVN connection failed somewhere...\n";
|
||||
}
|
||||
$ut = $ed;
|
||||
} else {
|
||||
$ut = { empty => {}, dir_prop => {}, file_prop => {} };
|
||||
open my $gui, '| git-update-index -z --index-info' or croak $!;
|
||||
libsvn_traverse($gui, '', $SVN->{svn_path}, $rev);
|
||||
libsvn_traverse($gui, '', $SVN->{svn_path}, $rev, undef, $ut);
|
||||
close $gui or croak $?;
|
||||
}
|
||||
return libsvn_log_entry($rev, $author, $date, $msg);
|
||||
libsvn_log_entry($rev, $author, $date, $msg, [], $ut);
|
||||
}
|
||||
|
||||
sub find_graft_path_commit {
|
||||
|
@ -3423,13 +3582,28 @@ sub new {
|
|||
$self->{gui} = $gui;
|
||||
$self->{c} = $git_svn->{c} if exists $git_svn->{c};
|
||||
$self->{q} = $git_svn->{q};
|
||||
$self->{empty} = {};
|
||||
$self->{dir_prop} = {};
|
||||
$self->{file_prop} = {};
|
||||
$self->{absent_dir} = {};
|
||||
$self->{absent_file} = {};
|
||||
require Digest::MD5;
|
||||
$self;
|
||||
}
|
||||
|
||||
sub open_root {
|
||||
{ path => '' };
|
||||
}
|
||||
|
||||
sub open_directory {
|
||||
my ($self, $path, $pb, $rev) = @_;
|
||||
{ path => $path };
|
||||
}
|
||||
|
||||
sub delete_entry {
|
||||
my ($self, $path, $rev, $pb) = @_;
|
||||
process_rm($self->{gui}, $self->{c}, $path, $self->{q});
|
||||
my $t = process_rm($self->{gui}, $self->{c}, $path, $self->{q});
|
||||
$self->{empty}->{$path} = 0 if $t == $SVN::Node::dir;
|
||||
undef;
|
||||
}
|
||||
|
||||
|
@ -3437,16 +3611,50 @@ sub open_file {
|
|||
my ($self, $path, $pb, $rev) = @_;
|
||||
my ($mode, $blob) = (safe_qx('git-ls-tree',$self->{c},'--',$path)
|
||||
=~ /^(\d{6}) blob ([a-f\d]{40})\t/);
|
||||
unless (defined $mode && defined $blob) {
|
||||
die "$path was not found in commit $self->{c} (r$rev)\n";
|
||||
}
|
||||
{ path => $path, mode_a => $mode, mode_b => $mode, blob => $blob,
|
||||
pool => SVN::Pool->new, action => 'M' };
|
||||
}
|
||||
|
||||
sub add_file {
|
||||
my ($self, $path, $pb, $cp_path, $cp_rev) = @_;
|
||||
my ($dir, $file) = ($path =~ m#^(.*?)/?([^/]+)$#);
|
||||
delete $self->{empty}->{$dir};
|
||||
{ path => $path, mode_a => 100644, mode_b => 100644,
|
||||
pool => SVN::Pool->new, action => 'A' };
|
||||
}
|
||||
|
||||
sub add_directory {
|
||||
my ($self, $path, $cp_path, $cp_rev) = @_;
|
||||
my ($dir, $file) = ($path =~ m#^(.*?)/?([^/]+)$#);
|
||||
delete $self->{empty}->{$dir};
|
||||
$self->{empty}->{$path} = 1;
|
||||
{ path => $path };
|
||||
}
|
||||
|
||||
sub change_dir_prop {
|
||||
my ($self, $db, $prop, $value) = @_;
|
||||
$self->{dir_prop}->{$db->{path}} ||= {};
|
||||
$self->{dir_prop}->{$db->{path}}->{$prop} = $value;
|
||||
undef;
|
||||
}
|
||||
|
||||
sub absent_directory {
|
||||
my ($self, $path, $pb) = @_;
|
||||
$self->{absent_dir}->{$pb->{path}} ||= [];
|
||||
push @{$self->{absent_dir}->{$pb->{path}}}, $path;
|
||||
undef;
|
||||
}
|
||||
|
||||
sub absent_file {
|
||||
my ($self, $path, $pb) = @_;
|
||||
$self->{absent_file}->{$pb->{path}} ||= [];
|
||||
push @{$self->{absent_file}->{$pb->{path}}}, $path;
|
||||
undef;
|
||||
}
|
||||
|
||||
sub change_file_prop {
|
||||
my ($self, $fb, $prop, $value) = @_;
|
||||
if ($prop eq 'svn:executable') {
|
||||
|
@ -3455,6 +3663,9 @@ sub change_file_prop {
|
|||
}
|
||||
} elsif ($prop eq 'svn:special') {
|
||||
$fb->{mode_b} = defined $value ? 120000 : 100644;
|
||||
} else {
|
||||
$self->{file_prop}->{$fb->{path}} ||= {};
|
||||
$self->{file_prop}->{$fb->{path}}->{$prop} = $value;
|
||||
}
|
||||
undef;
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ our %feature = (
|
|||
# To disable system wide have in $GITWEB_CONFIG
|
||||
# $feature{'snapshot'}{'default'} = [undef];
|
||||
# To have project specific config enable override in $GITWEB_CONFIG
|
||||
# $feature{'blame'}{'override'} = 1;
|
||||
# $feature{'snapshot'}{'override'} = 1;
|
||||
# and in project config gitweb.snapshot = none|gzip|bzip2;
|
||||
'snapshot' => {
|
||||
'sub' => \&feature_snapshot,
|
||||
|
@ -3229,10 +3229,13 @@ sub git_blob {
|
|||
open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
|
||||
or die_error(undef, "Couldn't cat $file_name, $hash");
|
||||
my $mimetype = blob_mimetype($fd, $file_name);
|
||||
if ($mimetype !~ m/^text\//) {
|
||||
if ($mimetype !~ m!^(?:text/|image/(?:gif|png|jpeg)$)!) {
|
||||
close $fd;
|
||||
return git_blob_plain($mimetype);
|
||||
}
|
||||
# we can have blame only for text/* mimetype
|
||||
$have_blame &&= ($mimetype =~ m!^text/!);
|
||||
|
||||
git_header_html(undef, $expires);
|
||||
my $formats_nav = '';
|
||||
if (defined $hash_base && (my %co = parse_commit($hash_base))) {
|
||||
|
@ -3269,13 +3272,24 @@ sub git_blob {
|
|||
}
|
||||
git_print_page_path($file_name, "blob", $hash_base);
|
||||
print "<div class=\"page_body\">\n";
|
||||
my $nr;
|
||||
while (my $line = <$fd>) {
|
||||
chomp $line;
|
||||
$nr++;
|
||||
$line = untabify($line);
|
||||
printf "<div class=\"pre\"><a id=\"l%i\" href=\"#l%i\" class=\"linenr\">%4i</a> %s</div>\n",
|
||||
$nr, $nr, $nr, esc_html($line, -nbsp=>1);
|
||||
if ($mimetype =~ m!^text/!) {
|
||||
my $nr;
|
||||
while (my $line = <$fd>) {
|
||||
chomp $line;
|
||||
$nr++;
|
||||
$line = untabify($line);
|
||||
printf "<div class=\"pre\"><a id=\"l%i\" href=\"#l%i\" class=\"linenr\">%4i</a> %s</div>\n",
|
||||
$nr, $nr, $nr, esc_html($line, -nbsp=>1);
|
||||
}
|
||||
} elsif ($mimetype =~ m!^image/!) {
|
||||
print qq!<img type="$mimetype"!;
|
||||
if ($file_name) {
|
||||
print qq! alt="$file_name" title="$file_name"!;
|
||||
}
|
||||
print qq! src="! .
|
||||
href(action=>"blob_plain", hash=>$hash,
|
||||
hash_base=>$hash_base, file_name=>$file_name) .
|
||||
qq!" />\n!;
|
||||
}
|
||||
close $fd
|
||||
or print "Reading blob failed.\n";
|
||||
|
@ -4282,7 +4296,7 @@ XML
|
|||
}
|
||||
if (defined $logo_url) {
|
||||
# not twice as wide as tall: 72 x 27 pixels
|
||||
print "<logo>" . esc_url($logo_url) . "</logo>\n";
|
||||
print "<logo>" . esc_url($logo) . "</logo>\n";
|
||||
}
|
||||
if (! %latest_date) {
|
||||
# dummy date to keep the feed valid until commits trickle in:
|
||||
|
|
|
@ -96,7 +96,7 @@ static void flush(void)
|
|||
if (output_fd >= 0)
|
||||
write_or_die(output_fd, input_buffer, input_offset);
|
||||
SHA1_Update(&input_ctx, input_buffer, input_offset);
|
||||
memcpy(input_buffer, input_buffer + input_offset, input_len);
|
||||
memmove(input_buffer, input_buffer + input_offset, input_len);
|
||||
input_offset = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1222,7 +1222,7 @@ static int merge(struct commit *h1,
|
|||
|
||||
tree->object.parsed = 1;
|
||||
tree->object.type = OBJ_TREE;
|
||||
hash_sha1_file(NULL, 0, tree_type, tree->object.sha1);
|
||||
write_sha1_file(NULL, 0, tree_type, tree->object.sha1);
|
||||
merged_common_ancestors = make_virtual_commit(tree, "ancestor");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
Makefile
|
||||
perl.mak
|
||||
perl.mak.old
|
||||
blib
|
||||
blibdirs
|
||||
pm_to_blib
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
#
|
||||
# Makefile for perl support modules and routine
|
||||
#
|
||||
makfile:=perl.mak
|
||||
|
||||
PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
|
||||
prefix_SQ = $(subst ','\'',$(prefix))
|
||||
|
||||
all install instlibdir: $(makfile)
|
||||
$(MAKE) -f $(makfile) $@
|
||||
|
||||
clean:
|
||||
test -f $(makfile) && $(MAKE) -f $(makfile) $@ || exit 0
|
||||
$(RM) ppport.h
|
||||
$(RM) $(makfile)
|
||||
$(RM) $(makfile).old
|
||||
|
||||
ifdef NO_PERL_MAKEMAKER
|
||||
instdir_SQ = $(subst ','\'',$(prefix)/lib)
|
||||
$(makfile): ../GIT-CFLAGS Makefile
|
||||
echo all: > $@
|
||||
echo ' :' >> $@
|
||||
echo install: >> $@
|
||||
echo ' mkdir -p $(instdir_SQ)' >> $@
|
||||
echo ' $(RM) $(instdir_SQ)/Git.pm; cp Git.pm $(instdir_SQ)' >> $@
|
||||
echo ' $(RM) $(instdir_SQ)/Error.pm; \
|
||||
cp private-Error.pm $(instdir_SQ)/Error.pm' >> $@
|
||||
echo instlibdir: >> $@
|
||||
echo ' echo $(instdir_SQ)' >> $@
|
||||
else
|
||||
$(makfile): Makefile.PL ../GIT-CFLAGS
|
||||
'$(PERL_PATH_SQ)' $< PREFIX='$(prefix_SQ)'
|
||||
endif
|
||||
|
||||
# this is just added comfort for calling make directly in perl dir
|
||||
# (even though GIT-CFLAGS aren't used yet. If ever)
|
||||
../GIT-CFLAGS:
|
||||
$(MAKE) -C .. GIT-CFLAGS
|
||||
|
|
@ -24,5 +24,6 @@ WriteMakefile(
|
|||
NAME => 'Git',
|
||||
VERSION_FROM => 'Git.pm',
|
||||
PM => \%pm,
|
||||
MAKEFILE => 'perl.mak',
|
||||
%extra
|
||||
);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
|
||||
|
||||
static int deny_non_fast_forwards = 0;
|
||||
static int unpack_limit = 5000;
|
||||
static int unpack_limit = 100;
|
||||
static int report_status;
|
||||
|
||||
static char capabilities[] = " report-status delete-refs ";
|
||||
|
@ -120,7 +120,8 @@ static int update(struct command *cmd)
|
|||
"but I can't find it!", new_hex);
|
||||
}
|
||||
if (deny_non_fast_forwards && !is_null_sha1(new_sha1) &&
|
||||
!is_null_sha1(old_sha1)) {
|
||||
!is_null_sha1(old_sha1) &&
|
||||
!strncmp(name, "refs/heads/", 11)) {
|
||||
struct commit *old_commit, *new_commit;
|
||||
struct commit_list *bases, *ent;
|
||||
|
||||
|
|
|
@ -109,12 +109,10 @@ index d99af23..8b32fb5 100644
|
|||
+ whitespace at beginning
|
||||
whitespace change
|
||||
-whitespace in the middle
|
||||
-whitespace at end
|
||||
+white space in the middle
|
||||
+whitespace at end
|
||||
whitespace at end
|
||||
unchanged line
|
||||
-CR at endQ
|
||||
+CR at end
|
||||
CR at endQ
|
||||
EOF
|
||||
git-diff -b > out
|
||||
test_expect_success 'another test, with -b' 'diff -u expect out'
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
#!/bin/sh
|
||||
|
||||
test_description='Test merge without common ancestors'
|
||||
. ./test-lib.sh
|
||||
|
||||
# This scenario is based on a real-world repository of Shawn Pearce.
|
||||
|
||||
# 1 - A - D - F
|
||||
# \ X /
|
||||
# B X
|
||||
# X \
|
||||
# 2 - C - E - G
|
||||
|
||||
export GIT_COMMITTER_DATE="2006-12-12 23:28:00 +0100"
|
||||
echo 1 > a1
|
||||
git add a1
|
||||
GIT_AUTHOR_DATE="2006-12-12 23:00:00" git commit -m 1 a1
|
||||
|
||||
git checkout -b A master
|
||||
echo A > a1
|
||||
GIT_AUTHOR_DATE="2006-12-12 23:00:01" git commit -m A a1
|
||||
|
||||
git checkout -b B master
|
||||
echo B > a1
|
||||
GIT_AUTHOR_DATE="2006-12-12 23:00:02" git commit -m B a1
|
||||
|
||||
git checkout -b D A
|
||||
git-rev-parse B > .git/MERGE_HEAD
|
||||
echo D > a1
|
||||
git update-index a1
|
||||
GIT_AUTHOR_DATE="2006-12-12 23:00:03" git commit -m D
|
||||
|
||||
git symbolic-ref HEAD refs/heads/other
|
||||
echo 2 > a1
|
||||
GIT_AUTHOR_DATE="2006-12-12 23:00:04" git commit -m 2 a1
|
||||
|
||||
git checkout -b C
|
||||
echo C > a1
|
||||
GIT_AUTHOR_DATE="2006-12-12 23:00:05" git commit -m C a1
|
||||
|
||||
git checkout -b E C
|
||||
git-rev-parse B > .git/MERGE_HEAD
|
||||
echo E > a1
|
||||
git update-index a1
|
||||
GIT_AUTHOR_DATE="2006-12-12 23:00:06" git commit -m E
|
||||
|
||||
git checkout -b G E
|
||||
git-rev-parse A > .git/MERGE_HEAD
|
||||
echo G > a1
|
||||
git update-index a1
|
||||
GIT_AUTHOR_DATE="2006-12-12 23:00:07" git commit -m G
|
||||
|
||||
git checkout -b F D
|
||||
git-rev-parse C > .git/MERGE_HEAD
|
||||
echo F > a1
|
||||
git update-index a1
|
||||
GIT_AUTHOR_DATE="2006-12-12 23:00:08" git commit -m F
|
||||
|
||||
test_expect_failure "combined merge conflicts" "git merge -m final G"
|
||||
|
||||
git ls-files --stage > out
|
||||
cat > expect << EOF
|
||||
100644 f70f10e4db19068f79bc43844b49f3eece45c4e8 1 a1
|
||||
100644 cf84443e49e1b366fac938711ddf4be2d4d1d9e9 2 a1
|
||||
100644 fd7923529855d0b274795ae3349c5e0438333979 3 a1
|
||||
EOF
|
||||
|
||||
test_expect_success "virtual trees were processed" "diff -u expect out"
|
||||
|
||||
test_done
|
|
@ -105,4 +105,17 @@ test_expect_success "Michael Cassar's test case" '
|
|||
}
|
||||
'
|
||||
|
||||
rm -fr papers partA path?
|
||||
|
||||
test_expect_success "Sergey Vlasov's test case" '
|
||||
rm -fr .git &&
|
||||
git init-db &&
|
||||
mkdir ab &&
|
||||
date >ab.c &&
|
||||
date >ab/d &&
|
||||
git add ab.c ab &&
|
||||
git commit -m 'initial' &&
|
||||
git mv ab a
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
@ -142,4 +142,20 @@ test_expect_success \
|
|||
diff F/newfile6.png ../F/newfile6.png
|
||||
)'
|
||||
|
||||
test_expect_success 'Retain execute bit' '
|
||||
mkdir G &&
|
||||
echo executeon >G/on &&
|
||||
chmod +x G/on &&
|
||||
echo executeoff >G/off &&
|
||||
git add G/on &&
|
||||
git add G/off &&
|
||||
git commit -a -m "Execute test" &&
|
||||
(
|
||||
cd "$CVSWORK" &&
|
||||
git-cvsexportcommit -c HEAD
|
||||
test -x G/on &&
|
||||
! test -x G/off
|
||||
)
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
@ -370,7 +370,7 @@ int unpack_trees(struct object_list *trees, struct unpack_trees_options *o)
|
|||
int i;
|
||||
struct object_list *posn = trees;
|
||||
struct tree_entry_list df_conflict_list;
|
||||
struct cache_entry df_conflict_entry;
|
||||
static struct cache_entry *dfc;
|
||||
|
||||
memset(&df_conflict_list, 0, sizeof(df_conflict_list));
|
||||
df_conflict_list.next = &df_conflict_list;
|
||||
|
@ -381,8 +381,10 @@ int unpack_trees(struct object_list *trees, struct unpack_trees_options *o)
|
|||
state.refresh_cache = 1;
|
||||
|
||||
o->merge_size = len;
|
||||
memset(&df_conflict_entry, 0, sizeof(df_conflict_entry));
|
||||
o->df_conflict_entry = &df_conflict_entry;
|
||||
|
||||
if (!dfc)
|
||||
dfc = xcalloc(1, sizeof(struct cache_entry) + 1);
|
||||
o->df_conflict_entry = dfc;
|
||||
|
||||
if (len) {
|
||||
posns = xmalloc(len * sizeof(struct tree_entry_list *));
|
||||
|
|
|
@ -230,7 +230,8 @@ unsigned long xdl_hash_record(char const **data, char const *top, long flags) {
|
|||
while (ptr + 1 < top && isspace(ptr[1])
|
||||
&& ptr[1] != '\n')
|
||||
ptr++;
|
||||
if (flags & XDF_IGNORE_WHITESPACE_CHANGE) {
|
||||
if (flags & XDF_IGNORE_WHITESPACE_CHANGE
|
||||
&& ptr[1] != '\n') {
|
||||
ha += (ha << 5);
|
||||
ha ^= (unsigned long) ' ';
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue