mac: Remove Git from the source tree, add instructions on how to add it
This commit is contained in:
parent
570fe54927
commit
6271216e1b
|
@ -25,6 +25,15 @@ Install <tt>git</tt>, <tt>automake</tt>, <tt>libtool</tt> and <tt>intltool</tt>
|
||||||
$ sudo port install git-core automake intltool libtool
|
$ sudo port install git-core automake intltool libtool
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Get a Git install, and place both the `bin` and `libexec` directories in `SparkleShare/Mac/git`.
|
||||||
|
The exact commands depend on where you installed/have Git. Assuming it's in `/usr/local`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ mkdir SparkleShare/Mac/git
|
||||||
|
$ cp -R /usr/local/git/bin SparkleShare/Mac/git
|
||||||
|
$ cp -R /usr/local/git/libexec SparkleShare/Mac/git
|
||||||
|
```
|
||||||
|
|
||||||
Start the first part of the build:
|
Start the first part of the build:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
@ -1,370 +0,0 @@
|
||||||
From https://github.com/gitster/git:
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
GIT - the stupid content tracker
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
"git" can mean anything, depending on your mood.
|
|
||||||
|
|
||||||
- random three-letter combination that is pronounceable, and not
|
|
||||||
actually used by any common UNIX command. The fact that it is a
|
|
||||||
mispronunciation of "get" may or may not be relevant.
|
|
||||||
- stupid. contemptible and despicable. simple. Take your pick from the
|
|
||||||
dictionary of slang.
|
|
||||||
- "global information tracker": you're in a good mood, and it actually
|
|
||||||
works for you. Angels sing, and a light suddenly fills the room.
|
|
||||||
- "goddamn idiotic truckload of sh*t": when it breaks
|
|
||||||
|
|
||||||
Git is a fast, scalable, distributed revision control system with an
|
|
||||||
unusually rich command set that provides both high-level operations
|
|
||||||
and full access to internals.
|
|
||||||
|
|
||||||
Git is an Open Source project covered by the GNU General Public License.
|
|
||||||
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.
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 2, June 1991
|
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
|
||||||
License is intended to guarantee your freedom to share and change free
|
|
||||||
software--to make sure the software is free for all its users. This
|
|
||||||
General Public License applies to most of the Free Software
|
|
||||||
Foundation's software and to any other program whose authors commit to
|
|
||||||
using it. (Some other Free Software Foundation software is covered by
|
|
||||||
the GNU Lesser General Public License instead.) You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
this service if you wish), that you receive source code or can get it
|
|
||||||
if you want it, that you can change the software or use pieces of it
|
|
||||||
in new free programs; and that you know you can do these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
|
||||||
anyone to deny you these rights or to ask you to surrender the rights.
|
|
||||||
These restrictions translate to certain responsibilities for you if you
|
|
||||||
distribute copies of the software, or if you modify it.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
|
||||||
gratis or for a fee, you must give the recipients all the rights that
|
|
||||||
you have. You must make sure that they, too, receive or can get the
|
|
||||||
source code. And you must show them these terms so they know their
|
|
||||||
rights.
|
|
||||||
|
|
||||||
We protect your rights with two steps: (1) copyright the software, and
|
|
||||||
(2) offer you this license which gives you legal permission to copy,
|
|
||||||
distribute and/or modify the software.
|
|
||||||
|
|
||||||
Also, for each author's protection and ours, we want to make certain
|
|
||||||
that everyone understands that there is no warranty for this free
|
|
||||||
software. If the software is modified by someone else and passed on, we
|
|
||||||
want its recipients to know that what they have is not the original, so
|
|
||||||
that any problems introduced by others will not reflect on the original
|
|
||||||
authors' reputations.
|
|
||||||
|
|
||||||
Finally, any free program is threatened constantly by software
|
|
||||||
patents. We wish to avoid the danger that redistributors of a free
|
|
||||||
program will individually obtain patent licenses, in effect making the
|
|
||||||
program proprietary. To prevent this, we have made it clear that any
|
|
||||||
patent must be licensed for everyone's free use or not licensed at all.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. This License applies to any program or other work which contains
|
|
||||||
a notice placed by the copyright holder saying it may be distributed
|
|
||||||
under the terms of this General Public License. The "Program", below,
|
|
||||||
refers to any such program or work, and a "work based on the Program"
|
|
||||||
means either the Program or any derivative work under copyright law:
|
|
||||||
that is to say, a work containing the Program or a portion of it,
|
|
||||||
either verbatim or with modifications and/or translated into another
|
|
||||||
language. (Hereinafter, translation is included without limitation in
|
|
||||||
the term "modification".) Each licensee is addressed as "you".
|
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
|
||||||
covered by this License; they are outside its scope. The act of
|
|
||||||
running the Program is not restricted, and the output from the Program
|
|
||||||
is covered only if its contents constitute a work based on the
|
|
||||||
Program (independent of having been made by running the Program).
|
|
||||||
Whether that is true depends on what the Program does.
|
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Program's
|
|
||||||
source code as you receive it, in any medium, provided that you
|
|
||||||
conspicuously and appropriately publish on each copy an appropriate
|
|
||||||
copyright notice and disclaimer of warranty; keep intact all the
|
|
||||||
notices that refer to this License and to the absence of any warranty;
|
|
||||||
and give any other recipients of the Program a copy of this License
|
|
||||||
along with the Program.
|
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy, and
|
|
||||||
you may at your option offer warranty protection in exchange for a fee.
|
|
||||||
|
|
||||||
2. You may modify your copy or copies of the Program or any portion
|
|
||||||
of it, thus forming a work based on the Program, and copy and
|
|
||||||
distribute such modifications or work under the terms of Section 1
|
|
||||||
above, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) You must cause the modified files to carry prominent notices
|
|
||||||
stating that you changed the files and the date of any change.
|
|
||||||
|
|
||||||
b) You must cause any work that you distribute or publish, that in
|
|
||||||
whole or in part contains or is derived from the Program or any
|
|
||||||
part thereof, to be licensed as a whole at no charge to all third
|
|
||||||
parties under the terms of this License.
|
|
||||||
|
|
||||||
c) If the modified program normally reads commands interactively
|
|
||||||
when run, you must cause it, when started running for such
|
|
||||||
interactive use in the most ordinary way, to print or display an
|
|
||||||
announcement including an appropriate copyright notice and a
|
|
||||||
notice that there is no warranty (or else, saying that you provide
|
|
||||||
a warranty) and that users may redistribute the program under
|
|
||||||
these conditions, and telling the user how to view a copy of this
|
|
||||||
License. (Exception: if the Program itself is interactive but
|
|
||||||
does not normally print such an announcement, your work based on
|
|
||||||
the Program is not required to print an announcement.)
|
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
|
||||||
identifiable sections of that work are not derived from the Program,
|
|
||||||
and can be reasonably considered independent and separate works in
|
|
||||||
themselves, then this License, and its terms, do not apply to those
|
|
||||||
sections when you distribute them as separate works. But when you
|
|
||||||
distribute the same sections as part of a whole which is a work based
|
|
||||||
on the Program, the distribution of the whole must be on the terms of
|
|
||||||
this License, whose permissions for other licensees extend to the
|
|
||||||
entire whole, and thus to each and every part regardless of who wrote it.
|
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
|
||||||
your rights to work written entirely by you; rather, the intent is to
|
|
||||||
exercise the right to control the distribution of derivative or
|
|
||||||
collective works based on the Program.
|
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Program
|
|
||||||
with the Program (or with a work based on the Program) on a volume of
|
|
||||||
a storage or distribution medium does not bring the other work under
|
|
||||||
the scope of this License.
|
|
||||||
|
|
||||||
3. You may copy and distribute the Program (or a work based on it,
|
|
||||||
under Section 2) in object code or executable form under the terms of
|
|
||||||
Sections 1 and 2 above provided that you also do one of the following:
|
|
||||||
|
|
||||||
a) Accompany it with the complete corresponding machine-readable
|
|
||||||
source code, which must be distributed under the terms of Sections
|
|
||||||
1 and 2 above on a medium customarily used for software interchange; or,
|
|
||||||
|
|
||||||
b) Accompany it with a written offer, valid for at least three
|
|
||||||
years, to give any third party, for a charge no more than your
|
|
||||||
cost of physically performing source distribution, a complete
|
|
||||||
machine-readable copy of the corresponding source code, to be
|
|
||||||
distributed under the terms of Sections 1 and 2 above on a medium
|
|
||||||
customarily used for software interchange; or,
|
|
||||||
|
|
||||||
c) Accompany it with the information you received as to the offer
|
|
||||||
to distribute corresponding source code. (This alternative is
|
|
||||||
allowed only for noncommercial distribution and only if you
|
|
||||||
received the program in object code or executable form with such
|
|
||||||
an offer, in accord with Subsection b above.)
|
|
||||||
|
|
||||||
The source code for a work means the preferred form of the work for
|
|
||||||
making modifications to it. For an executable work, complete source
|
|
||||||
code means all the source code for all modules it contains, plus any
|
|
||||||
associated interface definition files, plus the scripts used to
|
|
||||||
control compilation and installation of the executable. However, as a
|
|
||||||
special exception, the source code distributed need not include
|
|
||||||
anything that is normally distributed (in either source or binary
|
|
||||||
form) with the major components (compiler, kernel, and so on) of the
|
|
||||||
operating system on which the executable runs, unless that component
|
|
||||||
itself accompanies the executable.
|
|
||||||
|
|
||||||
If distribution of executable or object code is made by offering
|
|
||||||
access to copy from a designated place, then offering equivalent
|
|
||||||
access to copy the source code from the same place counts as
|
|
||||||
distribution of the source code, even though third parties are not
|
|
||||||
compelled to copy the source along with the object code.
|
|
||||||
|
|
||||||
4. You may not copy, modify, sublicense, or distribute the Program
|
|
||||||
except as expressly provided under this License. Any attempt
|
|
||||||
otherwise to copy, modify, sublicense or distribute the Program is
|
|
||||||
void, and will automatically terminate your rights under this License.
|
|
||||||
However, parties who have received copies, or rights, from you under
|
|
||||||
this License will not have their licenses terminated so long as such
|
|
||||||
parties remain in full compliance.
|
|
||||||
|
|
||||||
5. You are not required to accept this License, since you have not
|
|
||||||
signed it. However, nothing else grants you permission to modify or
|
|
||||||
distribute the Program or its derivative works. These actions are
|
|
||||||
prohibited by law if you do not accept this License. Therefore, by
|
|
||||||
modifying or distributing the Program (or any work based on the
|
|
||||||
Program), you indicate your acceptance of this License to do so, and
|
|
||||||
all its terms and conditions for copying, distributing or modifying
|
|
||||||
the Program or works based on it.
|
|
||||||
|
|
||||||
6. Each time you redistribute the Program (or any work based on the
|
|
||||||
Program), the recipient automatically receives a license from the
|
|
||||||
original licensor to copy, distribute or modify the Program subject to
|
|
||||||
these terms and conditions. You may not impose any further
|
|
||||||
restrictions on the recipients' exercise of the rights granted herein.
|
|
||||||
You are not responsible for enforcing compliance by third parties to
|
|
||||||
this License.
|
|
||||||
|
|
||||||
7. If, as a consequence of a court judgment or allegation of patent
|
|
||||||
infringement or for any other reason (not limited to patent issues),
|
|
||||||
conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot
|
|
||||||
distribute so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you
|
|
||||||
may not distribute the Program at all. For example, if a patent
|
|
||||||
license would not permit royalty-free redistribution of the Program by
|
|
||||||
all those who receive copies directly or indirectly through you, then
|
|
||||||
the only way you could satisfy both it and this License would be to
|
|
||||||
refrain entirely from distribution of the Program.
|
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under
|
|
||||||
any particular circumstance, the balance of the section is intended to
|
|
||||||
apply and the section as a whole is intended to apply in other
|
|
||||||
circumstances.
|
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
|
||||||
patents or other property right claims or to contest validity of any
|
|
||||||
such claims; this section has the sole purpose of protecting the
|
|
||||||
integrity of the free software distribution system, which is
|
|
||||||
implemented by public license practices. Many people have made
|
|
||||||
generous contributions to the wide range of software distributed
|
|
||||||
through that system in reliance on consistent application of that
|
|
||||||
system; it is up to the author/donor to decide if he or she is willing
|
|
||||||
to distribute software through any other system and a licensee cannot
|
|
||||||
impose that choice.
|
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
|
||||||
be a consequence of the rest of this License.
|
|
||||||
|
|
||||||
8. If the distribution and/or use of the Program is restricted in
|
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
|
||||||
original copyright holder who places the Program under this License
|
|
||||||
may add an explicit geographical distribution limitation excluding
|
|
||||||
those countries, so that distribution is permitted only in or among
|
|
||||||
countries not thus excluded. In such case, this License incorporates
|
|
||||||
the limitation as if written in the body of this License.
|
|
||||||
|
|
||||||
9. The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the General Public License from time to time. Such new versions will
|
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Program
|
|
||||||
specifies a version number of this License which applies to it and "any
|
|
||||||
later version", you have the option of following the terms and conditions
|
|
||||||
either of that version or of any later version published by the Free
|
|
||||||
Software Foundation. If the Program does not specify a version number of
|
|
||||||
this License, you may choose any version ever published by the Free Software
|
|
||||||
Foundation.
|
|
||||||
|
|
||||||
10. If you wish to incorporate parts of the Program into other free
|
|
||||||
programs whose distribution conditions are different, write to the author
|
|
||||||
to ask for permission. For software which is copyrighted by the Free
|
|
||||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
|
||||||
make exceptions for this. Our decision will be guided by the two goals
|
|
||||||
of preserving the free status of all derivatives of our free software and
|
|
||||||
of promoting the sharing and reuse of software generally.
|
|
||||||
|
|
||||||
NO WARRANTY
|
|
||||||
|
|
||||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
|
||||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
|
||||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
|
||||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
|
||||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
|
||||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
|
||||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
|
||||||
REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
|
||||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
|
||||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
|
||||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
|
||||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
|
||||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
|
||||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGES.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
convey the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
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.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If the program is interactive, make it output a short notice like this
|
|
||||||
when it starts in an interactive mode:
|
|
||||||
|
|
||||||
Gnomovision version 69, Copyright (C) year name of author
|
|
||||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
||||||
This is free software, and you are welcome to redistribute it
|
|
||||||
under certain conditions; type `show c' for details.
|
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, the commands you use may
|
|
||||||
be called something other than `show w' and `show c'; they could even be
|
|
||||||
mouse-clicks or menu items--whatever suits your program.
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or your
|
|
||||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
|
||||||
necessary. Here is a sample; alter the names:
|
|
||||||
|
|
||||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
|
||||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
|
||||||
|
|
||||||
<signature of Ty Coon>, 1 April 1989
|
|
||||||
Ty Coon, President of Vice
|
|
||||||
|
|
||||||
This General Public License does not permit incorporating your program into
|
|
||||||
proprietary programs. If your program is a subroutine library, you may
|
|
||||||
consider it more useful to permit linking proprietary applications with the
|
|
||||||
library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License.
|
|
||||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
@ -1 +0,0 @@
|
||||||
git
|
|
Binary file not shown.
|
@ -1 +0,0 @@
|
||||||
git
|
|
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,843 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# Copyright (c) 2005, 2006 Junio C Hamano
|
|
||||||
|
|
||||||
SUBDIRECTORY_OK=Yes
|
|
||||||
OPTIONS_KEEPDASHDASH=
|
|
||||||
OPTIONS_SPEC="\
|
|
||||||
git am [options] [(<mbox>|<Maildir>)...]
|
|
||||||
git am [options] (--resolved | --skip | --abort)
|
|
||||||
--
|
|
||||||
i,interactive run interactively
|
|
||||||
b,binary* (historical option -- no-op)
|
|
||||||
3,3way allow fall back on 3way merging if needed
|
|
||||||
q,quiet be quiet
|
|
||||||
s,signoff add a Signed-off-by line to the commit message
|
|
||||||
u,utf8 recode into utf8 (default)
|
|
||||||
k,keep pass -k flag to git-mailinfo
|
|
||||||
keep-cr pass --keep-cr flag to git-mailsplit for mbox format
|
|
||||||
no-keep-cr do not pass --keep-cr flag to git-mailsplit independent of am.keepcr
|
|
||||||
c,scissors strip everything before a scissors line
|
|
||||||
whitespace= pass it through git-apply
|
|
||||||
ignore-space-change pass it through git-apply
|
|
||||||
ignore-whitespace pass it through git-apply
|
|
||||||
directory= pass it through git-apply
|
|
||||||
C= pass it through git-apply
|
|
||||||
p= pass it through git-apply
|
|
||||||
patch-format= format the patch(es) are in
|
|
||||||
reject pass it through git-apply
|
|
||||||
resolvemsg= override error message when patch failure occurs
|
|
||||||
continue continue applying patches after resolving a conflict
|
|
||||||
r,resolved synonyms for --continue
|
|
||||||
skip skip the current patch
|
|
||||||
abort restore the original branch and abort the patching operation.
|
|
||||||
committer-date-is-author-date lie about committer date
|
|
||||||
ignore-date use current timestamp for author date
|
|
||||||
rerere-autoupdate update the index with reused conflict resolution if possible
|
|
||||||
rebasing* (internal use for git-rebase)"
|
|
||||||
|
|
||||||
. git-sh-setup
|
|
||||||
prefix=$(git rev-parse --show-prefix)
|
|
||||||
set_reflog_action am
|
|
||||||
require_work_tree
|
|
||||||
cd_to_toplevel
|
|
||||||
|
|
||||||
git var GIT_COMMITTER_IDENT >/dev/null ||
|
|
||||||
die "You need to set your committer info first"
|
|
||||||
|
|
||||||
if git rev-parse --verify -q HEAD >/dev/null
|
|
||||||
then
|
|
||||||
HAS_HEAD=yes
|
|
||||||
else
|
|
||||||
HAS_HEAD=
|
|
||||||
fi
|
|
||||||
|
|
||||||
cmdline="git am"
|
|
||||||
if test '' != "$interactive"
|
|
||||||
then
|
|
||||||
cmdline="$cmdline -i"
|
|
||||||
fi
|
|
||||||
if test '' != "$threeway"
|
|
||||||
then
|
|
||||||
cmdline="$cmdline -3"
|
|
||||||
fi
|
|
||||||
|
|
||||||
sq () {
|
|
||||||
git rev-parse --sq-quote "$@"
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_here () {
|
|
||||||
echo "$1" >"$dotest/next"
|
|
||||||
git rev-parse --verify -q HEAD >"$dotest/abort-safety"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
safe_to_abort () {
|
|
||||||
if test -f "$dotest/dirtyindex"
|
|
||||||
then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! test -s "$dotest/abort-safety"
|
|
||||||
then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
abort_safety=$(cat "$dotest/abort-safety")
|
|
||||||
if test "z$(git rev-parse --verify -q HEAD)" = "z$abort_safety"
|
|
||||||
then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
echo >&2 "You seem to have moved HEAD since the last 'am' failure."
|
|
||||||
echo >&2 "Not rewinding to ORIG_HEAD"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_here_user_resolve () {
|
|
||||||
if [ -n "$resolvemsg" ]; then
|
|
||||||
printf '%s\n' "$resolvemsg"
|
|
||||||
stop_here $1
|
|
||||||
fi
|
|
||||||
echo "When you have resolved this problem run \"$cmdline --resolved\"."
|
|
||||||
echo "If you would prefer to skip this patch, instead run \"$cmdline --skip\"."
|
|
||||||
echo "To restore the original branch and stop patching run \"$cmdline --abort\"."
|
|
||||||
|
|
||||||
stop_here $1
|
|
||||||
}
|
|
||||||
|
|
||||||
go_next () {
|
|
||||||
rm -f "$dotest/$msgnum" "$dotest/msg" "$dotest/msg-clean" \
|
|
||||||
"$dotest/patch" "$dotest/info"
|
|
||||||
echo "$next" >"$dotest/next"
|
|
||||||
this=$next
|
|
||||||
}
|
|
||||||
|
|
||||||
cannot_fallback () {
|
|
||||||
echo "$1"
|
|
||||||
echo "Cannot fall back to three-way merge."
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
fall_back_3way () {
|
|
||||||
O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
|
|
||||||
|
|
||||||
rm -fr "$dotest"/patch-merge-*
|
|
||||||
mkdir "$dotest/patch-merge-tmp-dir"
|
|
||||||
|
|
||||||
# First see if the patch records the index info that we can use.
|
|
||||||
git apply --build-fake-ancestor "$dotest/patch-merge-tmp-index" \
|
|
||||||
"$dotest/patch" &&
|
|
||||||
GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
|
|
||||||
git write-tree >"$dotest/patch-merge-base+" ||
|
|
||||||
cannot_fallback "Repository lacks necessary blobs to fall back on 3-way merge."
|
|
||||||
|
|
||||||
say Using index info to reconstruct a base tree...
|
|
||||||
if GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
|
|
||||||
git apply --cached <"$dotest/patch"
|
|
||||||
then
|
|
||||||
mv "$dotest/patch-merge-base+" "$dotest/patch-merge-base"
|
|
||||||
mv "$dotest/patch-merge-tmp-index" "$dotest/patch-merge-index"
|
|
||||||
else
|
|
||||||
cannot_fallback "Did you hand edit your patch?
|
|
||||||
It does not apply to blobs recorded in its index."
|
|
||||||
fi
|
|
||||||
|
|
||||||
test -f "$dotest/patch-merge-index" &&
|
|
||||||
his_tree=$(GIT_INDEX_FILE="$dotest/patch-merge-index" git write-tree) &&
|
|
||||||
orig_tree=$(cat "$dotest/patch-merge-base") &&
|
|
||||||
rm -fr "$dotest"/patch-merge-* || exit 1
|
|
||||||
|
|
||||||
say Falling back to patching base and 3-way merge...
|
|
||||||
|
|
||||||
# This is not so wrong. Depending on which base we picked,
|
|
||||||
# orig_tree may be wildly different from ours, but his_tree
|
|
||||||
# has the same set of wildly different changes in parts the
|
|
||||||
# patch did not touch, so recursive ends up canceling them,
|
|
||||||
# saying that we reverted all those changes.
|
|
||||||
|
|
||||||
eval GITHEAD_$his_tree='"$FIRSTLINE"'
|
|
||||||
export GITHEAD_$his_tree
|
|
||||||
if test -n "$GIT_QUIET"
|
|
||||||
then
|
|
||||||
GIT_MERGE_VERBOSITY=0 && export GIT_MERGE_VERBOSITY
|
|
||||||
fi
|
|
||||||
git-merge-recursive $orig_tree -- HEAD $his_tree || {
|
|
||||||
git rerere $allow_rerere_autoupdate
|
|
||||||
echo Failed to merge in the changes.
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
unset GITHEAD_$his_tree
|
|
||||||
}
|
|
||||||
|
|
||||||
clean_abort () {
|
|
||||||
test $# = 0 || echo >&2 "$@"
|
|
||||||
rm -fr "$dotest"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
patch_format=
|
|
||||||
|
|
||||||
check_patch_format () {
|
|
||||||
# early return if patch_format was set from the command line
|
|
||||||
if test -n "$patch_format"
|
|
||||||
then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# we default to mbox format if input is from stdin and for
|
|
||||||
# directories
|
|
||||||
if test $# = 0 || test "x$1" = "x-" || test -d "$1"
|
|
||||||
then
|
|
||||||
patch_format=mbox
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# otherwise, check the first few lines of the first patch to try
|
|
||||||
# to detect its format
|
|
||||||
{
|
|
||||||
read l1
|
|
||||||
read l2
|
|
||||||
read l3
|
|
||||||
case "$l1" in
|
|
||||||
"From "* | "From: "*)
|
|
||||||
patch_format=mbox
|
|
||||||
;;
|
|
||||||
'# This series applies on GIT commit'*)
|
|
||||||
patch_format=stgit-series
|
|
||||||
;;
|
|
||||||
"# HG changeset patch")
|
|
||||||
patch_format=hg
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
# if the second line is empty and the third is
|
|
||||||
# a From, Author or Date entry, this is very
|
|
||||||
# likely an StGIT patch
|
|
||||||
case "$l2,$l3" in
|
|
||||||
,"From: "* | ,"Author: "* | ,"Date: "*)
|
|
||||||
patch_format=stgit
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
if test -z "$patch_format" &&
|
|
||||||
test -n "$l1" &&
|
|
||||||
test -n "$l2" &&
|
|
||||||
test -n "$l3"
|
|
||||||
then
|
|
||||||
# This begins with three non-empty lines. Is this a
|
|
||||||
# piece of e-mail a-la RFC2822? Grab all the headers,
|
|
||||||
# discarding the indented remainder of folded lines,
|
|
||||||
# and see if it looks like that they all begin with the
|
|
||||||
# header field names...
|
|
||||||
tr -d '\015' <"$1" |
|
|
||||||
sed -n -e '/^$/q' -e '/^[ ]/d' -e p |
|
|
||||||
sane_egrep -v '^[!-9;-~]+:' >/dev/null ||
|
|
||||||
patch_format=mbox
|
|
||||||
fi
|
|
||||||
} < "$1" || clean_abort
|
|
||||||
}
|
|
||||||
|
|
||||||
split_patches () {
|
|
||||||
case "$patch_format" in
|
|
||||||
mbox)
|
|
||||||
if test -n "$rebasing" || test t = "$keepcr"
|
|
||||||
then
|
|
||||||
keep_cr=--keep-cr
|
|
||||||
else
|
|
||||||
keep_cr=
|
|
||||||
fi
|
|
||||||
git mailsplit -d"$prec" -o"$dotest" -b $keep_cr -- "$@" > "$dotest/last" ||
|
|
||||||
clean_abort
|
|
||||||
;;
|
|
||||||
stgit-series)
|
|
||||||
if test $# -ne 1
|
|
||||||
then
|
|
||||||
clean_abort "Only one StGIT patch series can be applied at once"
|
|
||||||
fi
|
|
||||||
series_dir=`dirname "$1"`
|
|
||||||
series_file="$1"
|
|
||||||
shift
|
|
||||||
{
|
|
||||||
set x
|
|
||||||
while read filename
|
|
||||||
do
|
|
||||||
set "$@" "$series_dir/$filename"
|
|
||||||
done
|
|
||||||
# remove the safety x
|
|
||||||
shift
|
|
||||||
# remove the arg coming from the first-line comment
|
|
||||||
shift
|
|
||||||
} < "$series_file" || clean_abort
|
|
||||||
# set the patch format appropriately
|
|
||||||
patch_format=stgit
|
|
||||||
# now handle the actual StGIT patches
|
|
||||||
split_patches "$@"
|
|
||||||
;;
|
|
||||||
stgit)
|
|
||||||
this=0
|
|
||||||
for stgit in "$@"
|
|
||||||
do
|
|
||||||
this=`expr "$this" + 1`
|
|
||||||
msgnum=`printf "%0${prec}d" $this`
|
|
||||||
# Perl version of StGIT parse_patch. The first nonemptyline
|
|
||||||
# not starting with Author, From or Date is the
|
|
||||||
# subject, and the body starts with the next nonempty
|
|
||||||
# line not starting with Author, From or Date
|
|
||||||
perl -ne 'BEGIN { $subject = 0 }
|
|
||||||
if ($subject > 1) { print ; }
|
|
||||||
elsif (/^\s+$/) { next ; }
|
|
||||||
elsif (/^Author:/) { print s/Author/From/ ; }
|
|
||||||
elsif (/^(From|Date)/) { print ; }
|
|
||||||
elsif ($subject) {
|
|
||||||
$subject = 2 ;
|
|
||||||
print "\n" ;
|
|
||||||
print ;
|
|
||||||
} else {
|
|
||||||
print "Subject: ", $_ ;
|
|
||||||
$subject = 1;
|
|
||||||
}
|
|
||||||
' < "$stgit" > "$dotest/$msgnum" || clean_abort
|
|
||||||
done
|
|
||||||
echo "$this" > "$dotest/last"
|
|
||||||
this=
|
|
||||||
msgnum=
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
if test -n "$parse_patch" ; then
|
|
||||||
clean_abort "Patch format $patch_format is not supported."
|
|
||||||
else
|
|
||||||
clean_abort "Patch format detection failed."
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
prec=4
|
|
||||||
dotest="$GIT_DIR/rebase-apply"
|
|
||||||
sign= utf8=t keep= keepcr= skip= interactive= resolved= rebasing= abort=
|
|
||||||
resolvemsg= resume= scissors= no_inbody_headers=
|
|
||||||
git_apply_opt=
|
|
||||||
committer_date_is_author_date=
|
|
||||||
ignore_date=
|
|
||||||
allow_rerere_autoupdate=
|
|
||||||
|
|
||||||
if test "$(git config --bool --get am.keepcr)" = true
|
|
||||||
then
|
|
||||||
keepcr=t
|
|
||||||
fi
|
|
||||||
|
|
||||||
while test $# != 0
|
|
||||||
do
|
|
||||||
case "$1" in
|
|
||||||
-i|--interactive)
|
|
||||||
interactive=t ;;
|
|
||||||
-b|--binary)
|
|
||||||
: ;;
|
|
||||||
-3|--3way)
|
|
||||||
threeway=t ;;
|
|
||||||
-s|--signoff)
|
|
||||||
sign=t ;;
|
|
||||||
-u|--utf8)
|
|
||||||
utf8=t ;; # this is now default
|
|
||||||
--no-utf8)
|
|
||||||
utf8= ;;
|
|
||||||
-k|--keep)
|
|
||||||
keep=t ;;
|
|
||||||
-c|--scissors)
|
|
||||||
scissors=t ;;
|
|
||||||
--no-scissors)
|
|
||||||
scissors=f ;;
|
|
||||||
-r|--resolved|--continue)
|
|
||||||
resolved=t ;;
|
|
||||||
--skip)
|
|
||||||
skip=t ;;
|
|
||||||
--abort)
|
|
||||||
abort=t ;;
|
|
||||||
--rebasing)
|
|
||||||
rebasing=t threeway=t keep=t scissors=f no_inbody_headers=t ;;
|
|
||||||
-d|--dotest)
|
|
||||||
die "-d option is no longer supported. Do not use."
|
|
||||||
;;
|
|
||||||
--resolvemsg)
|
|
||||||
shift; resolvemsg=$1 ;;
|
|
||||||
--whitespace|--directory)
|
|
||||||
git_apply_opt="$git_apply_opt $(sq "$1=$2")"; shift ;;
|
|
||||||
-C|-p)
|
|
||||||
git_apply_opt="$git_apply_opt $(sq "$1$2")"; shift ;;
|
|
||||||
--patch-format)
|
|
||||||
shift ; patch_format="$1" ;;
|
|
||||||
--reject|--ignore-whitespace|--ignore-space-change)
|
|
||||||
git_apply_opt="$git_apply_opt $1" ;;
|
|
||||||
--committer-date-is-author-date)
|
|
||||||
committer_date_is_author_date=t ;;
|
|
||||||
--ignore-date)
|
|
||||||
ignore_date=t ;;
|
|
||||||
--rerere-autoupdate|--no-rerere-autoupdate)
|
|
||||||
allow_rerere_autoupdate="$1" ;;
|
|
||||||
-q|--quiet)
|
|
||||||
GIT_QUIET=t ;;
|
|
||||||
--keep-cr)
|
|
||||||
keepcr=t ;;
|
|
||||||
--no-keep-cr)
|
|
||||||
keepcr=f ;;
|
|
||||||
--)
|
|
||||||
shift; break ;;
|
|
||||||
*)
|
|
||||||
usage ;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
# If the dotest directory exists, but we have finished applying all the
|
|
||||||
# patches in them, clear it out.
|
|
||||||
if test -d "$dotest" &&
|
|
||||||
last=$(cat "$dotest/last") &&
|
|
||||||
next=$(cat "$dotest/next") &&
|
|
||||||
test $# != 0 &&
|
|
||||||
test "$next" -gt "$last"
|
|
||||||
then
|
|
||||||
rm -fr "$dotest"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -d "$dotest"
|
|
||||||
then
|
|
||||||
case "$#,$skip$resolved$abort" in
|
|
||||||
0,*t*)
|
|
||||||
# Explicit resume command and we do not have file, so
|
|
||||||
# we are happy.
|
|
||||||
: ;;
|
|
||||||
0,)
|
|
||||||
# No file input but without resume parameters; catch
|
|
||||||
# user error to feed us a patch from standard input
|
|
||||||
# when there is already $dotest. This is somewhat
|
|
||||||
# unreliable -- stdin could be /dev/null for example
|
|
||||||
# and the caller did not intend to feed us a patch but
|
|
||||||
# wanted to continue unattended.
|
|
||||||
test -t 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
false
|
|
||||||
;;
|
|
||||||
esac ||
|
|
||||||
die "previous rebase directory $dotest still exists but mbox given."
|
|
||||||
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
|
|
||||||
orig_head=$(cat "$GIT_DIR/ORIG_HEAD")
|
|
||||||
git reset HEAD
|
|
||||||
git update-ref ORIG_HEAD $orig_head
|
|
||||||
;;
|
|
||||||
,t)
|
|
||||||
if test -f "$dotest/rebasing"
|
|
||||||
then
|
|
||||||
exec git rebase --abort
|
|
||||||
fi
|
|
||||||
git rerere clear
|
|
||||||
if safe_to_abort
|
|
||||||
then
|
|
||||||
git read-tree --reset -u HEAD ORIG_HEAD
|
|
||||||
git reset ORIG_HEAD
|
|
||||||
fi
|
|
||||||
rm -fr "$dotest"
|
|
||||||
exit ;;
|
|
||||||
esac
|
|
||||||
rm -f "$dotest/dirtyindex"
|
|
||||||
else
|
|
||||||
# Make sure we are not given --skip, --resolved, nor --abort
|
|
||||||
test "$skip$resolved$abort" = "" ||
|
|
||||||
die "Resolve operation not in progress, we are not resuming."
|
|
||||||
|
|
||||||
# Start afresh.
|
|
||||||
mkdir -p "$dotest" || exit
|
|
||||||
|
|
||||||
if test -n "$prefix" && test $# != 0
|
|
||||||
then
|
|
||||||
first=t
|
|
||||||
for arg
|
|
||||||
do
|
|
||||||
test -n "$first" && {
|
|
||||||
set x
|
|
||||||
first=
|
|
||||||
}
|
|
||||||
if is_absolute_path "$arg"
|
|
||||||
then
|
|
||||||
set "$@" "$arg"
|
|
||||||
else
|
|
||||||
set "$@" "$prefix$arg"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
|
|
||||||
check_patch_format "$@"
|
|
||||||
|
|
||||||
split_patches "$@"
|
|
||||||
|
|
||||||
# -i can and must be given when resuming; everything
|
|
||||||
# else is kept
|
|
||||||
echo " $git_apply_opt" >"$dotest/apply-opt"
|
|
||||||
echo "$threeway" >"$dotest/threeway"
|
|
||||||
echo "$sign" >"$dotest/sign"
|
|
||||||
echo "$utf8" >"$dotest/utf8"
|
|
||||||
echo "$keep" >"$dotest/keep"
|
|
||||||
echo "$keepcr" >"$dotest/keepcr"
|
|
||||||
echo "$scissors" >"$dotest/scissors"
|
|
||||||
echo "$no_inbody_headers" >"$dotest/no_inbody_headers"
|
|
||||||
echo "$GIT_QUIET" >"$dotest/quiet"
|
|
||||||
echo 1 >"$dotest/next"
|
|
||||||
if test -n "$rebasing"
|
|
||||||
then
|
|
||||||
: >"$dotest/rebasing"
|
|
||||||
else
|
|
||||||
: >"$dotest/applying"
|
|
||||||
if test -n "$HAS_HEAD"
|
|
||||||
then
|
|
||||||
git update-ref ORIG_HEAD HEAD
|
|
||||||
else
|
|
||||||
git update-ref -d ORIG_HEAD >/dev/null 2>&1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
git update-index -q --refresh
|
|
||||||
|
|
||||||
case "$resolved" in
|
|
||||||
'')
|
|
||||||
case "$HAS_HEAD" in
|
|
||||||
'')
|
|
||||||
files=$(git ls-files) ;;
|
|
||||||
?*)
|
|
||||||
files=$(git diff-index --cached --name-only HEAD --) ;;
|
|
||||||
esac || exit
|
|
||||||
if test "$files"
|
|
||||||
then
|
|
||||||
test -n "$HAS_HEAD" && : >"$dotest/dirtyindex"
|
|
||||||
die "Dirty index: cannot apply patches (dirty: $files)"
|
|
||||||
fi
|
|
||||||
esac
|
|
||||||
|
|
||||||
if test "$(cat "$dotest/utf8")" = t
|
|
||||||
then
|
|
||||||
utf8=-u
|
|
||||||
else
|
|
||||||
utf8=-n
|
|
||||||
fi
|
|
||||||
if test "$(cat "$dotest/keep")" = t
|
|
||||||
then
|
|
||||||
keep=-k
|
|
||||||
fi
|
|
||||||
case "$(cat "$dotest/keepcr")" in
|
|
||||||
t)
|
|
||||||
keepcr=--keep-cr ;;
|
|
||||||
f)
|
|
||||||
keepcr=--no-keep-cr ;;
|
|
||||||
esac
|
|
||||||
case "$(cat "$dotest/scissors")" in
|
|
||||||
t)
|
|
||||||
scissors=--scissors ;;
|
|
||||||
f)
|
|
||||||
scissors=--no-scissors ;;
|
|
||||||
esac
|
|
||||||
if test "$(cat "$dotest/no_inbody_headers")" = t
|
|
||||||
then
|
|
||||||
no_inbody_headers=--no-inbody-headers
|
|
||||||
else
|
|
||||||
no_inbody_headers=
|
|
||||||
fi
|
|
||||||
if test "$(cat "$dotest/quiet")" = t
|
|
||||||
then
|
|
||||||
GIT_QUIET=t
|
|
||||||
fi
|
|
||||||
if test "$(cat "$dotest/threeway")" = t
|
|
||||||
then
|
|
||||||
threeway=t
|
|
||||||
fi
|
|
||||||
git_apply_opt=$(cat "$dotest/apply-opt")
|
|
||||||
if test "$(cat "$dotest/sign")" = t
|
|
||||||
then
|
|
||||||
SIGNOFF=`git var GIT_COMMITTER_IDENT | sed -e '
|
|
||||||
s/>.*/>/
|
|
||||||
s/^/Signed-off-by: /'
|
|
||||||
`
|
|
||||||
else
|
|
||||||
SIGNOFF=
|
|
||||||
fi
|
|
||||||
|
|
||||||
last=`cat "$dotest/last"`
|
|
||||||
this=`cat "$dotest/next"`
|
|
||||||
if test "$skip" = t
|
|
||||||
then
|
|
||||||
this=`expr "$this" + 1`
|
|
||||||
resume=
|
|
||||||
fi
|
|
||||||
|
|
||||||
while test "$this" -le "$last"
|
|
||||||
do
|
|
||||||
msgnum=`printf "%0${prec}d" $this`
|
|
||||||
next=`expr "$this" + 1`
|
|
||||||
test -f "$dotest/$msgnum" || {
|
|
||||||
resume=
|
|
||||||
go_next
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
# If we are not resuming, parse and extract the patch information
|
|
||||||
# into separate files:
|
|
||||||
# - info records the authorship and title
|
|
||||||
# - msg is the rest of commit log message
|
|
||||||
# - patch is the patch body.
|
|
||||||
#
|
|
||||||
# When we are resuming, these files are either already prepared
|
|
||||||
# by the user, or the user can tell us to do so by --resolved flag.
|
|
||||||
case "$resume" in
|
|
||||||
'')
|
|
||||||
git mailinfo $keep $no_inbody_headers $scissors $utf8 "$dotest/msg" "$dotest/patch" \
|
|
||||||
<"$dotest/$msgnum" >"$dotest/info" ||
|
|
||||||
stop_here $this
|
|
||||||
|
|
||||||
# skip pine's internal folder data
|
|
||||||
sane_grep '^Author: Mail System Internal Data$' \
|
|
||||||
<"$dotest"/info >/dev/null &&
|
|
||||||
go_next && continue
|
|
||||||
|
|
||||||
test -s "$dotest/patch" || {
|
|
||||||
echo "Patch is empty. Was it split wrong?"
|
|
||||||
echo "If you would prefer to skip this patch, instead run \"$cmdline --skip\"."
|
|
||||||
echo "To restore the original branch and stop patching run \"$cmdline --abort\"."
|
|
||||||
stop_here $this
|
|
||||||
}
|
|
||||||
rm -f "$dotest/original-commit" "$dotest/author-script"
|
|
||||||
if test -f "$dotest/rebasing" &&
|
|
||||||
commit=$(sed -e 's/^From \([0-9a-f]*\) .*/\1/' \
|
|
||||||
-e q "$dotest/$msgnum") &&
|
|
||||||
test "$(git cat-file -t "$commit")" = commit
|
|
||||||
then
|
|
||||||
git cat-file commit "$commit" |
|
|
||||||
sed -e '1,/^$/d' >"$dotest/msg-clean"
|
|
||||||
echo "$commit" > "$dotest/original-commit"
|
|
||||||
get_author_ident_from_commit "$commit" > "$dotest/author-script"
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sed -n '/^Subject/ s/Subject: //p' "$dotest/info"
|
|
||||||
echo
|
|
||||||
cat "$dotest/msg"
|
|
||||||
} |
|
|
||||||
git stripspace > "$dotest/msg-clean"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if test -f "$dotest/author-script"
|
|
||||||
then
|
|
||||||
eval $(cat "$dotest/author-script")
|
|
||||||
else
|
|
||||||
GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$dotest/info")"
|
|
||||||
GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$dotest/info")"
|
|
||||||
GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$dotest/info")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -z "$GIT_AUTHOR_EMAIL"
|
|
||||||
then
|
|
||||||
echo "Patch does not have a valid e-mail address."
|
|
||||||
stop_here $this
|
|
||||||
fi
|
|
||||||
|
|
||||||
export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
|
|
||||||
|
|
||||||
case "$resume" in
|
|
||||||
'')
|
|
||||||
if test '' != "$SIGNOFF"
|
|
||||||
then
|
|
||||||
LAST_SIGNED_OFF_BY=`
|
|
||||||
sed -ne '/^Signed-off-by: /p' \
|
|
||||||
"$dotest/msg-clean" |
|
|
||||||
sed -ne '$p'
|
|
||||||
`
|
|
||||||
ADD_SIGNOFF=`
|
|
||||||
test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || {
|
|
||||||
test '' = "$LAST_SIGNED_OFF_BY" && echo
|
|
||||||
echo "$SIGNOFF"
|
|
||||||
}`
|
|
||||||
else
|
|
||||||
ADD_SIGNOFF=
|
|
||||||
fi
|
|
||||||
{
|
|
||||||
if test -s "$dotest/msg-clean"
|
|
||||||
then
|
|
||||||
cat "$dotest/msg-clean"
|
|
||||||
fi
|
|
||||||
if test '' != "$ADD_SIGNOFF"
|
|
||||||
then
|
|
||||||
echo "$ADD_SIGNOFF"
|
|
||||||
fi
|
|
||||||
} >"$dotest/final-commit"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
case "$resolved$interactive" in
|
|
||||||
tt)
|
|
||||||
# This is used only for interactive view option.
|
|
||||||
git diff-index -p --cached HEAD -- >"$dotest/patch"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
esac
|
|
||||||
|
|
||||||
resume=
|
|
||||||
if test "$interactive" = t
|
|
||||||
then
|
|
||||||
test -t 0 ||
|
|
||||||
die "cannot be interactive without stdin connected to a terminal."
|
|
||||||
action=again
|
|
||||||
while test "$action" = again
|
|
||||||
do
|
|
||||||
echo "Commit Body is:"
|
|
||||||
echo "--------------------------"
|
|
||||||
cat "$dotest/final-commit"
|
|
||||||
echo "--------------------------"
|
|
||||||
printf "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
|
|
||||||
read reply
|
|
||||||
case "$reply" in
|
|
||||||
[yY]*) action=yes ;;
|
|
||||||
[aA]*) action=yes interactive= ;;
|
|
||||||
[nN]*) action=skip ;;
|
|
||||||
[eE]*) git_editor "$dotest/final-commit"
|
|
||||||
action=again ;;
|
|
||||||
[vV]*) action=again
|
|
||||||
git_pager "$dotest/patch" ;;
|
|
||||||
*) action=again ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
else
|
|
||||||
action=yes
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -f "$dotest/final-commit"
|
|
||||||
then
|
|
||||||
FIRSTLINE=$(sed 1q "$dotest/final-commit")
|
|
||||||
else
|
|
||||||
FIRSTLINE=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test $action = skip
|
|
||||||
then
|
|
||||||
go_next
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -x "$GIT_DIR"/hooks/applypatch-msg
|
|
||||||
then
|
|
||||||
"$GIT_DIR"/hooks/applypatch-msg "$dotest/final-commit" ||
|
|
||||||
stop_here $this
|
|
||||||
fi
|
|
||||||
|
|
||||||
say "Applying: $FIRSTLINE"
|
|
||||||
|
|
||||||
case "$resolved" in
|
|
||||||
'')
|
|
||||||
# When we are allowed to fall back to 3-way later, don't give
|
|
||||||
# false errors during the initial attempt.
|
|
||||||
squelch=
|
|
||||||
if test "$threeway" = t
|
|
||||||
then
|
|
||||||
squelch='>/dev/null 2>&1 '
|
|
||||||
fi
|
|
||||||
eval "git apply $squelch$git_apply_opt"' --index "$dotest/patch"'
|
|
||||||
apply_status=$?
|
|
||||||
;;
|
|
||||||
t)
|
|
||||||
# Resolved means the user did all the hard work, and
|
|
||||||
# we do not have to do any patch application. Just
|
|
||||||
# trust what the user has in the index file and the
|
|
||||||
# working tree.
|
|
||||||
resolved=
|
|
||||||
git diff-index --quiet --cached HEAD -- && {
|
|
||||||
echo "No changes - did you forget to use 'git add'?"
|
|
||||||
echo "If there is nothing left to stage, chances are that something else"
|
|
||||||
echo "already introduced the same changes; you might want to skip this patch."
|
|
||||||
stop_here_user_resolve $this
|
|
||||||
}
|
|
||||||
unmerged=$(git ls-files -u)
|
|
||||||
if test -n "$unmerged"
|
|
||||||
then
|
|
||||||
echo "You still have unmerged paths in your index"
|
|
||||||
echo "did you forget to use 'git add'?"
|
|
||||||
stop_here_user_resolve $this
|
|
||||||
fi
|
|
||||||
apply_status=0
|
|
||||||
git rerere
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if test $apply_status != 0 && test "$threeway" = t
|
|
||||||
then
|
|
||||||
if (fall_back_3way)
|
|
||||||
then
|
|
||||||
# Applying the patch to an earlier tree and merging the
|
|
||||||
# result may have produced the same tree as ours.
|
|
||||||
git diff-index --quiet --cached HEAD -- && {
|
|
||||||
say No changes -- Patch already applied.
|
|
||||||
go_next
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
# clear apply_status -- we have successfully merged.
|
|
||||||
apply_status=0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
if test $apply_status != 0
|
|
||||||
then
|
|
||||||
printf 'Patch failed at %s %s\n' "$msgnum" "$FIRSTLINE"
|
|
||||||
stop_here_user_resolve $this
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -x "$GIT_DIR"/hooks/pre-applypatch
|
|
||||||
then
|
|
||||||
"$GIT_DIR"/hooks/pre-applypatch || stop_here $this
|
|
||||||
fi
|
|
||||||
|
|
||||||
tree=$(git write-tree) &&
|
|
||||||
commit=$(
|
|
||||||
if test -n "$ignore_date"
|
|
||||||
then
|
|
||||||
GIT_AUTHOR_DATE=
|
|
||||||
fi
|
|
||||||
parent=$(git rev-parse --verify -q HEAD) ||
|
|
||||||
say >&2 "applying to an empty history"
|
|
||||||
|
|
||||||
if test -n "$committer_date_is_author_date"
|
|
||||||
then
|
|
||||||
GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
|
|
||||||
export GIT_COMMITTER_DATE
|
|
||||||
fi &&
|
|
||||||
git commit-tree $tree ${parent:+-p} $parent <"$dotest/final-commit"
|
|
||||||
) &&
|
|
||||||
git update-ref -m "$GIT_REFLOG_ACTION: $FIRSTLINE" HEAD $commit $parent ||
|
|
||||||
stop_here $this
|
|
||||||
|
|
||||||
if test -f "$dotest/original-commit"; then
|
|
||||||
echo "$(cat "$dotest/original-commit") $commit" >> "$dotest/rewritten"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -x "$GIT_DIR"/hooks/post-applypatch
|
|
||||||
then
|
|
||||||
"$GIT_DIR"/hooks/post-applypatch
|
|
||||||
fi
|
|
||||||
|
|
||||||
go_next
|
|
||||||
done
|
|
||||||
|
|
||||||
if test -s "$dotest"/rewritten; then
|
|
||||||
git notes copy --for-rewrite=rebase < "$dotest"/rewritten
|
|
||||||
if test -x "$GIT_DIR"/hooks/post-rewrite; then
|
|
||||||
"$GIT_DIR"/hooks/post-rewrite rebase < "$dotest"/rewritten
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -fr "$dotest"
|
|
||||||
git gc --auto
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
File diff suppressed because it is too large
Load diff
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1,459 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
USAGE='[help|start|bad|good|skip|next|reset|visualize|replay|log|run]'
|
|
||||||
LONG_USAGE='git bisect help
|
|
||||||
print this long help message.
|
|
||||||
git bisect start [<bad> [<good>...]] [--] [<pathspec>...]
|
|
||||||
reset bisect state and start bisection.
|
|
||||||
git bisect bad [<rev>]
|
|
||||||
mark <rev> a known-bad revision.
|
|
||||||
git bisect good [<rev>...]
|
|
||||||
mark <rev>... known-good revisions.
|
|
||||||
git bisect skip [(<rev>|<range>)...]
|
|
||||||
mark <rev>... untestable revisions.
|
|
||||||
git bisect next
|
|
||||||
find next bisection to test and check it out.
|
|
||||||
git bisect reset [<commit>]
|
|
||||||
finish bisection search and go back to commit.
|
|
||||||
git bisect visualize
|
|
||||||
show bisect status in gitk.
|
|
||||||
git bisect replay <logfile>
|
|
||||||
replay bisection log.
|
|
||||||
git bisect log
|
|
||||||
show bisect log.
|
|
||||||
git bisect run <cmd>...
|
|
||||||
use <cmd>... to automatically bisect.
|
|
||||||
|
|
||||||
Please use "git help bisect" to get the full man page.'
|
|
||||||
|
|
||||||
OPTIONS_SPEC=
|
|
||||||
. git-sh-setup
|
|
||||||
require_work_tree
|
|
||||||
|
|
||||||
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
|
|
||||||
_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
|
|
||||||
|
|
||||||
bisect_autostart() {
|
|
||||||
test -s "$GIT_DIR/BISECT_START" || {
|
|
||||||
echo >&2 'You need to start by "git bisect start"'
|
|
||||||
if test -t 0
|
|
||||||
then
|
|
||||||
echo >&2 -n 'Do you want me to do it for you [Y/n]? '
|
|
||||||
read yesno
|
|
||||||
case "$yesno" in
|
|
||||||
[Nn]*)
|
|
||||||
exit ;;
|
|
||||||
esac
|
|
||||||
bisect_start
|
|
||||||
else
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bisect_start() {
|
|
||||||
#
|
|
||||||
# Verify HEAD.
|
|
||||||
#
|
|
||||||
head=$(GIT_DIR="$GIT_DIR" git symbolic-ref -q HEAD) ||
|
|
||||||
head=$(GIT_DIR="$GIT_DIR" git rev-parse --verify HEAD) ||
|
|
||||||
die "Bad HEAD - I need a HEAD"
|
|
||||||
|
|
||||||
#
|
|
||||||
# Check if we are bisecting.
|
|
||||||
#
|
|
||||||
start_head=''
|
|
||||||
if test -s "$GIT_DIR/BISECT_START"
|
|
||||||
then
|
|
||||||
# Reset to the rev from where we started.
|
|
||||||
start_head=$(cat "$GIT_DIR/BISECT_START")
|
|
||||||
git checkout "$start_head" -- || exit
|
|
||||||
else
|
|
||||||
# Get rev from where we start.
|
|
||||||
case "$head" in
|
|
||||||
refs/heads/*|$_x40)
|
|
||||||
# This error message should only be triggered by
|
|
||||||
# cogito usage, and cogito users should understand
|
|
||||||
# it relates to cg-seek.
|
|
||||||
[ -s "$GIT_DIR/head-name" ] &&
|
|
||||||
die "won't bisect on seeked tree"
|
|
||||||
start_head="${head#refs/heads/}"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
die "Bad HEAD - strange symbolic ref"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
#
|
|
||||||
# Get rid of any old bisect state.
|
|
||||||
#
|
|
||||||
bisect_clean_state || exit
|
|
||||||
|
|
||||||
#
|
|
||||||
# Check for one bad and then some good revisions.
|
|
||||||
#
|
|
||||||
has_double_dash=0
|
|
||||||
for arg; do
|
|
||||||
case "$arg" in --) has_double_dash=1; break ;; esac
|
|
||||||
done
|
|
||||||
orig_args=$(git rev-parse --sq-quote "$@")
|
|
||||||
bad_seen=0
|
|
||||||
eval=''
|
|
||||||
while [ $# -gt 0 ]; do
|
|
||||||
arg="$1"
|
|
||||||
case "$arg" in
|
|
||||||
--)
|
|
||||||
shift
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
rev=$(git rev-parse -q --verify "$arg^{commit}") || {
|
|
||||||
test $has_double_dash -eq 1 &&
|
|
||||||
die "'$arg' does not appear to be a valid revision"
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case $bad_seen in
|
|
||||||
0) state='bad' ; bad_seen=1 ;;
|
|
||||||
*) state='good' ;;
|
|
||||||
esac
|
|
||||||
eval="$eval bisect_write '$state' '$rev' 'nolog'; "
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
#
|
|
||||||
# Change state.
|
|
||||||
# In case of mistaken revs or checkout error, or signals received,
|
|
||||||
# "bisect_auto_next" below may exit or misbehave.
|
|
||||||
# We have to trap this to be able to clean up using
|
|
||||||
# "bisect_clean_state".
|
|
||||||
#
|
|
||||||
trap 'bisect_clean_state' 0
|
|
||||||
trap 'exit 255' 1 2 3 15
|
|
||||||
|
|
||||||
#
|
|
||||||
# Write new start state.
|
|
||||||
#
|
|
||||||
echo "$start_head" >"$GIT_DIR/BISECT_START" &&
|
|
||||||
git rev-parse --sq-quote "$@" >"$GIT_DIR/BISECT_NAMES" &&
|
|
||||||
eval "$eval" &&
|
|
||||||
echo "git bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit
|
|
||||||
#
|
|
||||||
# Check if we can proceed to the next bisect state.
|
|
||||||
#
|
|
||||||
bisect_auto_next
|
|
||||||
|
|
||||||
trap '-' 0
|
|
||||||
}
|
|
||||||
|
|
||||||
bisect_write() {
|
|
||||||
state="$1"
|
|
||||||
rev="$2"
|
|
||||||
nolog="$3"
|
|
||||||
case "$state" in
|
|
||||||
bad) tag="$state" ;;
|
|
||||||
good|skip) tag="$state"-"$rev" ;;
|
|
||||||
*) die "Bad bisect_write argument: $state" ;;
|
|
||||||
esac
|
|
||||||
git update-ref "refs/bisect/$tag" "$rev" || exit
|
|
||||||
echo "# $state: $(git show-branch $rev)" >>"$GIT_DIR/BISECT_LOG"
|
|
||||||
test -n "$nolog" || echo "git bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
|
|
||||||
}
|
|
||||||
|
|
||||||
is_expected_rev() {
|
|
||||||
test -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
|
|
||||||
test "$1" = $(cat "$GIT_DIR/BISECT_EXPECTED_REV")
|
|
||||||
}
|
|
||||||
|
|
||||||
check_expected_revs() {
|
|
||||||
for _rev in "$@"; do
|
|
||||||
if ! is_expected_rev "$_rev"; then
|
|
||||||
rm -f "$GIT_DIR/BISECT_ANCESTORS_OK"
|
|
||||||
rm -f "$GIT_DIR/BISECT_EXPECTED_REV"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
bisect_skip() {
|
|
||||||
all=''
|
|
||||||
for arg in "$@"
|
|
||||||
do
|
|
||||||
case "$arg" in
|
|
||||||
*..*)
|
|
||||||
revs=$(git rev-list "$arg") || die "Bad rev input: $arg" ;;
|
|
||||||
*)
|
|
||||||
revs=$(git rev-parse --sq-quote "$arg") ;;
|
|
||||||
esac
|
|
||||||
all="$all $revs"
|
|
||||||
done
|
|
||||||
eval bisect_state 'skip' $all
|
|
||||||
}
|
|
||||||
|
|
||||||
bisect_state() {
|
|
||||||
bisect_autostart
|
|
||||||
state=$1
|
|
||||||
case "$#,$state" in
|
|
||||||
0,*)
|
|
||||||
die "Please call 'bisect_state' with at least one argument." ;;
|
|
||||||
1,bad|1,good|1,skip)
|
|
||||||
rev=$(git rev-parse --verify HEAD) ||
|
|
||||||
die "Bad rev input: HEAD"
|
|
||||||
bisect_write "$state" "$rev"
|
|
||||||
check_expected_revs "$rev" ;;
|
|
||||||
2,bad|*,good|*,skip)
|
|
||||||
shift
|
|
||||||
eval=''
|
|
||||||
for rev in "$@"
|
|
||||||
do
|
|
||||||
sha=$(git rev-parse --verify "$rev^{commit}") ||
|
|
||||||
die "Bad rev input: $rev"
|
|
||||||
eval="$eval bisect_write '$state' '$sha'; "
|
|
||||||
done
|
|
||||||
eval "$eval"
|
|
||||||
check_expected_revs "$@" ;;
|
|
||||||
*,bad)
|
|
||||||
die "'git bisect bad' can take only one argument." ;;
|
|
||||||
*)
|
|
||||||
usage ;;
|
|
||||||
esac
|
|
||||||
bisect_auto_next
|
|
||||||
}
|
|
||||||
|
|
||||||
bisect_next_check() {
|
|
||||||
missing_good= missing_bad=
|
|
||||||
git show-ref -q --verify refs/bisect/bad || missing_bad=t
|
|
||||||
test -n "$(git for-each-ref "refs/bisect/good-*")" || missing_good=t
|
|
||||||
|
|
||||||
case "$missing_good,$missing_bad,$1" in
|
|
||||||
,,*)
|
|
||||||
: have both good and bad - ok
|
|
||||||
;;
|
|
||||||
*,)
|
|
||||||
# do not have both but not asked to fail - just report.
|
|
||||||
false
|
|
||||||
;;
|
|
||||||
t,,good)
|
|
||||||
# have bad but not good. we could bisect although
|
|
||||||
# this is less optimum.
|
|
||||||
echo >&2 'Warning: bisecting only with a bad commit.'
|
|
||||||
if test -t 0
|
|
||||||
then
|
|
||||||
printf >&2 'Are you sure [Y/n]? '
|
|
||||||
read yesno
|
|
||||||
case "$yesno" in [Nn]*) exit 1 ;; esac
|
|
||||||
fi
|
|
||||||
: bisect without good...
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
THEN=''
|
|
||||||
test -s "$GIT_DIR/BISECT_START" || {
|
|
||||||
echo >&2 'You need to start by "git bisect start".'
|
|
||||||
THEN='then '
|
|
||||||
}
|
|
||||||
echo >&2 'You '$THEN'need to give me at least one good' \
|
|
||||||
'and one bad revisions.'
|
|
||||||
echo >&2 '(You can use "git bisect bad" and' \
|
|
||||||
'"git bisect good" for that.)'
|
|
||||||
exit 1 ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
bisect_auto_next() {
|
|
||||||
bisect_next_check && bisect_next || :
|
|
||||||
}
|
|
||||||
|
|
||||||
bisect_next() {
|
|
||||||
case "$#" in 0) ;; *) usage ;; esac
|
|
||||||
bisect_autostart
|
|
||||||
bisect_next_check good
|
|
||||||
|
|
||||||
# Perform all bisection computation, display and checkout
|
|
||||||
git bisect--helper --next-all
|
|
||||||
res=$?
|
|
||||||
|
|
||||||
# Check if we should exit because bisection is finished
|
|
||||||
test $res -eq 10 && exit 0
|
|
||||||
|
|
||||||
# Check for an error in the bisection process
|
|
||||||
test $res -ne 0 && exit $res
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
bisect_visualize() {
|
|
||||||
bisect_next_check fail
|
|
||||||
|
|
||||||
if test $# = 0
|
|
||||||
then
|
|
||||||
if test -n "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" &&
|
|
||||||
type gitk >/dev/null 2>&1; then
|
|
||||||
set gitk
|
|
||||||
else
|
|
||||||
set git log
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
case "$1" in
|
|
||||||
git*|tig) ;;
|
|
||||||
-*) set git log "$@" ;;
|
|
||||||
*) set git "$@" ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
eval '"$@"' --bisect -- $(cat "$GIT_DIR/BISECT_NAMES")
|
|
||||||
}
|
|
||||||
|
|
||||||
bisect_reset() {
|
|
||||||
test -s "$GIT_DIR/BISECT_START" || {
|
|
||||||
echo "We are not bisecting."
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case "$#" in
|
|
||||||
0) branch=$(cat "$GIT_DIR/BISECT_START") ;;
|
|
||||||
1) git rev-parse --quiet --verify "$1^{commit}" > /dev/null ||
|
|
||||||
die "'$1' is not a valid commit"
|
|
||||||
branch="$1" ;;
|
|
||||||
*)
|
|
||||||
usage ;;
|
|
||||||
esac
|
|
||||||
if git checkout "$branch" -- ; then
|
|
||||||
bisect_clean_state
|
|
||||||
else
|
|
||||||
die "Could not check out original HEAD '$branch'." \
|
|
||||||
"Try 'git bisect reset <commit>'."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
bisect_clean_state() {
|
|
||||||
# There may be some refs packed during bisection.
|
|
||||||
git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* |
|
|
||||||
while read ref hash
|
|
||||||
do
|
|
||||||
git update-ref -d $ref $hash || exit
|
|
||||||
done
|
|
||||||
rm -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
|
|
||||||
rm -f "$GIT_DIR/BISECT_ANCESTORS_OK" &&
|
|
||||||
rm -f "$GIT_DIR/BISECT_LOG" &&
|
|
||||||
rm -f "$GIT_DIR/BISECT_NAMES" &&
|
|
||||||
rm -f "$GIT_DIR/BISECT_RUN" &&
|
|
||||||
# Cleanup head-name if it got left by an old version of git-bisect
|
|
||||||
rm -f "$GIT_DIR/head-name" &&
|
|
||||||
|
|
||||||
rm -f "$GIT_DIR/BISECT_START"
|
|
||||||
}
|
|
||||||
|
|
||||||
bisect_replay () {
|
|
||||||
test "$#" -eq 1 || die "No logfile given"
|
|
||||||
test -r "$1" || die "cannot read $1 for replaying"
|
|
||||||
bisect_reset
|
|
||||||
while read git bisect command rev
|
|
||||||
do
|
|
||||||
test "$git $bisect" = "git bisect" -o "$git" = "git-bisect" || continue
|
|
||||||
if test "$git" = "git-bisect"; then
|
|
||||||
rev="$command"
|
|
||||||
command="$bisect"
|
|
||||||
fi
|
|
||||||
case "$command" in
|
|
||||||
start)
|
|
||||||
cmd="bisect_start $rev"
|
|
||||||
eval "$cmd" ;;
|
|
||||||
good|bad|skip)
|
|
||||||
bisect_write "$command" "$rev" ;;
|
|
||||||
*)
|
|
||||||
die "?? what are you talking about?" ;;
|
|
||||||
esac
|
|
||||||
done <"$1"
|
|
||||||
bisect_auto_next
|
|
||||||
}
|
|
||||||
|
|
||||||
bisect_run () {
|
|
||||||
bisect_next_check fail
|
|
||||||
|
|
||||||
while true
|
|
||||||
do
|
|
||||||
echo "running $@"
|
|
||||||
"$@"
|
|
||||||
res=$?
|
|
||||||
|
|
||||||
# Check for really bad run error.
|
|
||||||
if [ $res -lt 0 -o $res -ge 128 ]; then
|
|
||||||
echo >&2 "bisect run failed:"
|
|
||||||
echo >&2 "exit code $res from '$@' is < 0 or >= 128"
|
|
||||||
exit $res
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Find current state depending on run success or failure.
|
|
||||||
# A special exit code of 125 means cannot test.
|
|
||||||
if [ $res -eq 125 ]; then
|
|
||||||
state='skip'
|
|
||||||
elif [ $res -gt 0 ]; then
|
|
||||||
state='bad'
|
|
||||||
else
|
|
||||||
state='good'
|
|
||||||
fi
|
|
||||||
|
|
||||||
# We have to use a subshell because "bisect_state" can exit.
|
|
||||||
( bisect_state $state > "$GIT_DIR/BISECT_RUN" )
|
|
||||||
res=$?
|
|
||||||
|
|
||||||
cat "$GIT_DIR/BISECT_RUN"
|
|
||||||
|
|
||||||
if sane_grep "first bad commit could be any of" "$GIT_DIR/BISECT_RUN" \
|
|
||||||
> /dev/null; then
|
|
||||||
echo >&2 "bisect run cannot continue any more"
|
|
||||||
exit $res
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $res -ne 0 ]; then
|
|
||||||
echo >&2 "bisect run failed:"
|
|
||||||
echo >&2 "'bisect_state $state' exited with error code $res"
|
|
||||||
exit $res
|
|
||||||
fi
|
|
||||||
|
|
||||||
if sane_grep "is the first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null; then
|
|
||||||
echo "bisect run success"
|
|
||||||
exit 0;
|
|
||||||
fi
|
|
||||||
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
bisect_log () {
|
|
||||||
test -s "$GIT_DIR/BISECT_LOG" || die "We are not bisecting."
|
|
||||||
cat "$GIT_DIR/BISECT_LOG"
|
|
||||||
}
|
|
||||||
|
|
||||||
case "$#" in
|
|
||||||
0)
|
|
||||||
usage ;;
|
|
||||||
*)
|
|
||||||
cmd="$1"
|
|
||||||
shift
|
|
||||||
case "$cmd" in
|
|
||||||
help)
|
|
||||||
git bisect -h ;;
|
|
||||||
start)
|
|
||||||
bisect_start "$@" ;;
|
|
||||||
bad|good)
|
|
||||||
bisect_state "$cmd" "$@" ;;
|
|
||||||
skip)
|
|
||||||
bisect_skip "$@" ;;
|
|
||||||
next)
|
|
||||||
# Not sure we want "next" at the UI level anymore.
|
|
||||||
bisect_next "$@" ;;
|
|
||||||
visualize|view)
|
|
||||||
bisect_visualize "$@" ;;
|
|
||||||
reset)
|
|
||||||
bisect_reset "$@" ;;
|
|
||||||
replay)
|
|
||||||
bisect_replay "$@" ;;
|
|
||||||
log)
|
|
||||||
bisect_log ;;
|
|
||||||
run)
|
|
||||||
bisect_run "$@" ;;
|
|
||||||
*)
|
|
||||||
usage ;;
|
|
||||||
esac
|
|
||||||
esac
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1,8 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
if test "z$*" = zversion ||
|
|
||||||
test "z$*" = z--version
|
|
||||||
then
|
|
||||||
echo 'git-gui version 0.14.0-dirty'
|
|
||||||
else
|
|
||||||
exec '/usr/local/git/share/git-gui/lib/Git Gui.app/Contents/MacOS/Wish' "$0" "$@"
|
|
||||||
fi
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1,456 +0,0 @@
|
||||||
#!/usr/bin/perl
|
|
||||||
use lib (split(/:/, $ENV{GITPERLLIB} || "/usr/local/git/lib/perl5/site_perl"));
|
|
||||||
|
|
||||||
use 5.008;
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
use Getopt::Std;
|
|
||||||
use File::Temp qw(tempdir);
|
|
||||||
use Data::Dumper;
|
|
||||||
use File::Basename qw(basename dirname);
|
|
||||||
use File::Spec;
|
|
||||||
use Git;
|
|
||||||
|
|
||||||
our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d, $opt_u, $opt_w, $opt_W, $opt_k);
|
|
||||||
|
|
||||||
getopts('uhPpvcfkam:d:w:W');
|
|
||||||
|
|
||||||
$opt_h && usage();
|
|
||||||
|
|
||||||
die "Need at least one commit identifier!" unless @ARGV;
|
|
||||||
|
|
||||||
# Get git-config settings
|
|
||||||
my $repo = Git->repository();
|
|
||||||
$opt_w = $repo->config('cvsexportcommit.cvsdir') unless defined $opt_w;
|
|
||||||
|
|
||||||
if ($opt_w || $opt_W) {
|
|
||||||
# Remember where GIT_DIR is before changing to CVS checkout
|
|
||||||
unless ($ENV{GIT_DIR}) {
|
|
||||||
# No GIT_DIR set. Figure it out for ourselves
|
|
||||||
my $gd =`git-rev-parse --git-dir`;
|
|
||||||
chomp($gd);
|
|
||||||
$ENV{GIT_DIR} = $gd;
|
|
||||||
}
|
|
||||||
# Make sure GIT_DIR is absolute
|
|
||||||
$ENV{GIT_DIR} = File::Spec->rel2abs($ENV{GIT_DIR});
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($opt_w) {
|
|
||||||
if (! -d $opt_w."/CVS" ) {
|
|
||||||
die "$opt_w is not a CVS checkout";
|
|
||||||
}
|
|
||||||
chdir $opt_w or die "Cannot change to CVS checkout at $opt_w";
|
|
||||||
}
|
|
||||||
unless ($ENV{GIT_DIR} && -r $ENV{GIT_DIR}){
|
|
||||||
die "GIT_DIR is not defined or is unreadable";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
my @cvs;
|
|
||||||
if ($opt_d) {
|
|
||||||
@cvs = ('cvs', '-d', $opt_d);
|
|
||||||
} else {
|
|
||||||
@cvs = ('cvs');
|
|
||||||
}
|
|
||||||
|
|
||||||
# resolve target commit
|
|
||||||
my $commit;
|
|
||||||
$commit = pop @ARGV;
|
|
||||||
$commit = safe_pipe_capture('git-rev-parse', '--verify', "$commit^0");
|
|
||||||
chomp $commit;
|
|
||||||
if ($?) {
|
|
||||||
die "The commit reference $commit did not resolve!";
|
|
||||||
}
|
|
||||||
|
|
||||||
# resolve what parent we want
|
|
||||||
my $parent;
|
|
||||||
if (@ARGV) {
|
|
||||||
$parent = pop @ARGV;
|
|
||||||
$parent = safe_pipe_capture('git-rev-parse', '--verify', "$parent^0");
|
|
||||||
chomp $parent;
|
|
||||||
if ($?) {
|
|
||||||
die "The parent reference did not resolve!";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# find parents from the commit itself
|
|
||||||
my @commit = safe_pipe_capture('git-cat-file', 'commit', $commit);
|
|
||||||
my @parents;
|
|
||||||
my $committer;
|
|
||||||
my $author;
|
|
||||||
my $stage = 'headers'; # headers, msg
|
|
||||||
my $title;
|
|
||||||
my $msg = '';
|
|
||||||
|
|
||||||
foreach my $line (@commit) {
|
|
||||||
chomp $line;
|
|
||||||
if ($stage eq 'headers' && $line eq '') {
|
|
||||||
$stage = 'msg';
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($stage eq 'headers') {
|
|
||||||
if ($line =~ m/^parent (\w{40})$/) { # found a parent
|
|
||||||
push @parents, $1;
|
|
||||||
} elsif ($line =~ m/^author (.+) \d+ [-+]\d+$/) {
|
|
||||||
$author = $1;
|
|
||||||
} elsif ($line =~ m/^committer (.+) \d+ [-+]\d+$/) {
|
|
||||||
$committer = $1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$msg .= $line . "\n";
|
|
||||||
unless ($title) {
|
|
||||||
$title = $line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
my $noparent = "0000000000000000000000000000000000000000";
|
|
||||||
if ($parent) {
|
|
||||||
my $found;
|
|
||||||
# double check that it's a valid parent
|
|
||||||
foreach my $p (@parents) {
|
|
||||||
if ($p eq $parent) {
|
|
||||||
$found = 1;
|
|
||||||
last;
|
|
||||||
}; # found it
|
|
||||||
}
|
|
||||||
die "Did not find $parent in the parents for this commit!" if !$found and !$opt_P;
|
|
||||||
} else { # we don't have a parent from the cmdline...
|
|
||||||
if (@parents == 1) { # it's safe to get it from the commit
|
|
||||||
$parent = $parents[0];
|
|
||||||
} elsif (@parents == 0) { # there is no parent
|
|
||||||
$parent = $noparent;
|
|
||||||
} else { # cannot choose automatically from multiple parents
|
|
||||||
die "This commit has more than one parent -- please name the parent you want to use explicitly";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
my $go_back_to = 0;
|
|
||||||
|
|
||||||
if ($opt_W) {
|
|
||||||
$opt_v && print "Resetting to $parent\n";
|
|
||||||
$go_back_to = `git symbolic-ref HEAD 2> /dev/null ||
|
|
||||||
git rev-parse HEAD` || die "Could not determine current branch";
|
|
||||||
system("git checkout -q $parent^0") && die "Could not check out $parent^0";
|
|
||||||
}
|
|
||||||
|
|
||||||
$opt_v && print "Applying to CVS commit $commit from parent $parent\n";
|
|
||||||
|
|
||||||
# grab the commit message
|
|
||||||
open(MSG, ">.msg") or die "Cannot open .msg for writing";
|
|
||||||
if ($opt_m) {
|
|
||||||
print MSG $opt_m;
|
|
||||||
}
|
|
||||||
print MSG $msg;
|
|
||||||
if ($opt_a) {
|
|
||||||
print MSG "\n\nAuthor: $author\n";
|
|
||||||
if ($author ne $committer) {
|
|
||||||
print MSG "Committer: $committer\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close MSG;
|
|
||||||
|
|
||||||
if ($parent eq $noparent) {
|
|
||||||
`git-diff-tree --binary -p --root $commit >.cvsexportcommit.diff`;# || die "Cannot diff";
|
|
||||||
} else {
|
|
||||||
`git-diff-tree --binary -p $parent $commit >.cvsexportcommit.diff`;# || die "Cannot diff";
|
|
||||||
}
|
|
||||||
|
|
||||||
## apply non-binary changes
|
|
||||||
|
|
||||||
# In pedantic mode require all lines of context to match. In normal
|
|
||||||
# mode, be compatible with diff/patch: assume 3 lines of context and
|
|
||||||
# require at least one line match, i.e. ignore at most 2 lines of
|
|
||||||
# context, like diff/patch do by default.
|
|
||||||
my $context = $opt_p ? '' : '-C1';
|
|
||||||
|
|
||||||
print "Checking if patch will apply\n";
|
|
||||||
|
|
||||||
my @stat;
|
|
||||||
open APPLY, "GIT_DIR= git-apply $context --summary --numstat<.cvsexportcommit.diff|" || die "cannot patch";
|
|
||||||
@stat=<APPLY>;
|
|
||||||
close APPLY || die "Cannot patch";
|
|
||||||
my (@bfiles,@files,@afiles,@dfiles);
|
|
||||||
chomp @stat;
|
|
||||||
foreach (@stat) {
|
|
||||||
push (@bfiles,$1) if m/^-\t-\t(.*)$/;
|
|
||||||
push (@files, $1) if m/^-\t-\t(.*)$/;
|
|
||||||
push (@files, $1) if m/^\d+\t\d+\t(.*)$/;
|
|
||||||
push (@afiles,$1) if m/^ create mode [0-7]+ (.*)$/;
|
|
||||||
push (@dfiles,$1) if m/^ delete mode [0-7]+ (.*)$/;
|
|
||||||
}
|
|
||||||
map { s/^"(.*)"$/$1/g } @bfiles,@files;
|
|
||||||
map { s/\\([0-7]{3})/sprintf('%c',oct $1)/eg } @bfiles,@files;
|
|
||||||
|
|
||||||
# check that the files are clean and up to date according to cvs
|
|
||||||
my $dirty;
|
|
||||||
my @dirs;
|
|
||||||
foreach my $p (@afiles) {
|
|
||||||
my $path = dirname $p;
|
|
||||||
while (!-d $path and ! grep { $_ eq $path } @dirs) {
|
|
||||||
unshift @dirs, $path;
|
|
||||||
$path = dirname $path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# ... check dirs,
|
|
||||||
foreach my $d (@dirs) {
|
|
||||||
if (-e $d) {
|
|
||||||
$dirty = 1;
|
|
||||||
warn "$d exists and is not a directory!\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# ... query status of all files that we have a directory for and parse output of 'cvs status' to %cvsstat.
|
|
||||||
my @canstatusfiles;
|
|
||||||
foreach my $f (@files) {
|
|
||||||
my $path = dirname $f;
|
|
||||||
next if (grep { $_ eq $path } @dirs);
|
|
||||||
push @canstatusfiles, $f;
|
|
||||||
}
|
|
||||||
|
|
||||||
my %cvsstat;
|
|
||||||
if (@canstatusfiles) {
|
|
||||||
if ($opt_u) {
|
|
||||||
my @updated = xargs_safe_pipe_capture([@cvs, 'update'], @canstatusfiles);
|
|
||||||
print @updated;
|
|
||||||
}
|
|
||||||
# "cvs status" reorders the parameters, notably when there are multiple
|
|
||||||
# arguments with the same basename. So be precise here.
|
|
||||||
|
|
||||||
my %added = map { $_ => 1 } @afiles;
|
|
||||||
my %todo = map { $_ => 1 } @canstatusfiles;
|
|
||||||
|
|
||||||
while (%todo) {
|
|
||||||
my @canstatusfiles2 = ();
|
|
||||||
my %fullname = ();
|
|
||||||
foreach my $name (keys %todo) {
|
|
||||||
my $basename = basename($name);
|
|
||||||
|
|
||||||
# CVS reports files that don't exist in the current revision as
|
|
||||||
# "no file $basename" in its "status" output, so we should
|
|
||||||
# anticipate that. Totally unknown files will have a status
|
|
||||||
# "Unknown". However, if they exist in the Attic, their status
|
|
||||||
# will be "Up-to-date" (this means they were added once but have
|
|
||||||
# been removed).
|
|
||||||
$basename = "no file $basename" if $added{$basename};
|
|
||||||
|
|
||||||
$basename =~ s/^\s+//;
|
|
||||||
$basename =~ s/\s+$//;
|
|
||||||
|
|
||||||
if (!exists($fullname{$basename})) {
|
|
||||||
$fullname{$basename} = $name;
|
|
||||||
push (@canstatusfiles2, $name);
|
|
||||||
delete($todo{$name});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
my @cvsoutput;
|
|
||||||
@cvsoutput = xargs_safe_pipe_capture([@cvs, 'status'], @canstatusfiles2);
|
|
||||||
foreach my $l (@cvsoutput) {
|
|
||||||
chomp $l;
|
|
||||||
next unless
|
|
||||||
my ($file, $status) = $l =~ /^File:\s+(.*\S)\s+Status: (.*)$/;
|
|
||||||
|
|
||||||
my $fullname = $fullname{$file};
|
|
||||||
print STDERR "Huh? Status '$status' reported for unexpected file '$file'\n"
|
|
||||||
unless defined $fullname;
|
|
||||||
|
|
||||||
# This response means the file does not exist except in
|
|
||||||
# CVS's attic, so set the status accordingly
|
|
||||||
$status = "In-attic"
|
|
||||||
if $file =~ /^no file /
|
|
||||||
&& $status eq 'Up-to-date';
|
|
||||||
|
|
||||||
$cvsstat{$fullname{$file}} = $status
|
|
||||||
if defined $fullname{$file};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# ... Validate that new files have the correct status
|
|
||||||
foreach my $f (@afiles) {
|
|
||||||
next unless defined(my $stat = $cvsstat{$f});
|
|
||||||
|
|
||||||
# This means the file has never been seen before
|
|
||||||
next if $stat eq 'Unknown';
|
|
||||||
|
|
||||||
# This means the file has been seen before but was removed
|
|
||||||
next if $stat eq 'In-attic';
|
|
||||||
|
|
||||||
$dirty = 1;
|
|
||||||
warn "File $f is already known in your CVS checkout -- perhaps it has been added by another user. Or this may indicate that it exists on a different branch. If this is the case, use -f to force the merge.\n";
|
|
||||||
warn "Status was: $cvsstat{$f}\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
# ... validate known files.
|
|
||||||
foreach my $f (@files) {
|
|
||||||
next if grep { $_ eq $f } @afiles;
|
|
||||||
# TODO:we need to handle removed in cvs
|
|
||||||
unless (defined ($cvsstat{$f}) and $cvsstat{$f} eq "Up-to-date") {
|
|
||||||
$dirty = 1;
|
|
||||||
warn "File $f not up to date but has status '$cvsstat{$f}' in your CVS checkout!\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
# Depending on how your GIT tree got imported from CVS you may
|
|
||||||
# have a conflict between expanded keywords in your CVS tree and
|
|
||||||
# unexpanded keywords in the patch about to be applied.
|
|
||||||
if ($opt_k) {
|
|
||||||
my $orig_file ="$f.orig";
|
|
||||||
rename $f, $orig_file;
|
|
||||||
open(FILTER_IN, "<$orig_file") or die "Cannot open $orig_file\n";
|
|
||||||
open(FILTER_OUT, ">$f") or die "Cannot open $f\n";
|
|
||||||
while (<FILTER_IN>)
|
|
||||||
{
|
|
||||||
my $line = $_;
|
|
||||||
$line =~ s/\$([A-Z][a-z]+):[^\$]+\$/\$$1\$/g;
|
|
||||||
print FILTER_OUT $line;
|
|
||||||
}
|
|
||||||
close FILTER_IN;
|
|
||||||
close FILTER_OUT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($dirty) {
|
|
||||||
if ($opt_f) { warn "The tree is not clean -- forced merge\n";
|
|
||||||
$dirty = 0;
|
|
||||||
} else {
|
|
||||||
die "Exiting: your CVS tree is not clean for this merge.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
print "Applying\n";
|
|
||||||
if ($opt_W) {
|
|
||||||
system("git checkout -q $commit^0") && die "cannot patch";
|
|
||||||
} else {
|
|
||||||
`GIT_DIR= git-apply $context --summary --numstat --apply <.cvsexportcommit.diff` || die "cannot patch";
|
|
||||||
}
|
|
||||||
|
|
||||||
print "Patch applied successfully. Adding new files and directories to CVS\n";
|
|
||||||
my $dirtypatch = 0;
|
|
||||||
|
|
||||||
#
|
|
||||||
# We have to add the directories in order otherwise we will have
|
|
||||||
# problems when we try and add the sub-directory of a directory we
|
|
||||||
# have not added yet.
|
|
||||||
#
|
|
||||||
# Luckily this is easy to deal with by sorting the directories and
|
|
||||||
# dealing with the shortest ones first.
|
|
||||||
#
|
|
||||||
@dirs = sort { length $a <=> length $b} @dirs;
|
|
||||||
|
|
||||||
foreach my $d (@dirs) {
|
|
||||||
if (system(@cvs,'add',$d)) {
|
|
||||||
$dirtypatch = 1;
|
|
||||||
warn "Failed to cvs add directory $d -- you may need to do it manually";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach my $f (@afiles) {
|
|
||||||
if (grep { $_ eq $f } @bfiles) {
|
|
||||||
system(@cvs, 'add','-kb',$f);
|
|
||||||
} else {
|
|
||||||
system(@cvs, 'add', $f);
|
|
||||||
}
|
|
||||||
if ($?) {
|
|
||||||
$dirtypatch = 1;
|
|
||||||
warn "Failed to cvs add $f -- you may need to do it manually";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach my $f (@dfiles) {
|
|
||||||
system(@cvs, 'rm', '-f', $f);
|
|
||||||
if ($?) {
|
|
||||||
$dirtypatch = 1;
|
|
||||||
warn "Failed to cvs rm -f $f -- you may need to do it manually";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
print "Commit to CVS\n";
|
|
||||||
print "Patch title (first comment line): $title\n";
|
|
||||||
my @commitfiles = map { unless (m/\s/) { '\''.$_.'\''; } else { $_; }; } (@files);
|
|
||||||
my $cmd = join(' ', @cvs)." commit -F .msg @commitfiles";
|
|
||||||
|
|
||||||
if ($dirtypatch) {
|
|
||||||
print "NOTE: One or more hunks failed to apply cleanly.\n";
|
|
||||||
print "You'll need to apply the patch in .cvsexportcommit.diff manually\n";
|
|
||||||
print "using a patch program. After applying the patch and resolving the\n";
|
|
||||||
print "problems you may commit using:";
|
|
||||||
print "\n cd \"$opt_w\"" if $opt_w;
|
|
||||||
print "\n $cmd\n";
|
|
||||||
print "\n git checkout $go_back_to\n" if $go_back_to;
|
|
||||||
print "\n";
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($opt_c) {
|
|
||||||
print "Autocommit\n $cmd\n";
|
|
||||||
print xargs_safe_pipe_capture([@cvs, 'commit', '-F', '.msg'], @files);
|
|
||||||
if ($?) {
|
|
||||||
die "Exiting: The commit did not succeed";
|
|
||||||
}
|
|
||||||
print "Committed successfully to CVS\n";
|
|
||||||
# clean up
|
|
||||||
unlink(".msg");
|
|
||||||
} else {
|
|
||||||
print "Ready for you to commit, just run:\n\n $cmd\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
# clean up
|
|
||||||
unlink(".cvsexportcommit.diff");
|
|
||||||
|
|
||||||
if ($opt_W) {
|
|
||||||
system("git checkout $go_back_to") && die "cannot move back to $go_back_to";
|
|
||||||
if (!($go_back_to =~ /^[0-9a-fA-F]{40}$/)) {
|
|
||||||
system("git symbolic-ref HEAD $go_back_to") &&
|
|
||||||
die "cannot move back to $go_back_to";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# CVS version 1.11.x and 1.12.x sleeps the wrong way to ensure the timestamp
|
|
||||||
# used by CVS and the one set by subsequence file modifications are different.
|
|
||||||
# If they are not different CVS will not detect changes.
|
|
||||||
sleep(1);
|
|
||||||
|
|
||||||
sub usage {
|
|
||||||
print STDERR <<END;
|
|
||||||
Usage: GIT_DIR=/path/to/.git git cvsexportcommit [-h] [-p] [-v] [-c] [-f] [-u] [-k] [-w cvsworkdir] [-m msgprefix] [ parent ] commit
|
|
||||||
END
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
# An alternative to `command` that allows input to be passed as an array
|
|
||||||
# to work around shell problems with weird characters in arguments
|
|
||||||
# if the exec returns non-zero we die
|
|
||||||
sub safe_pipe_capture {
|
|
||||||
my @output;
|
|
||||||
if (my $pid = open my $child, '-|') {
|
|
||||||
@output = (<$child>);
|
|
||||||
close $child or die join(' ',@_).": $! $?";
|
|
||||||
} else {
|
|
||||||
exec(@_) or die "$! $?"; # exec() can fail the executable can't be found
|
|
||||||
}
|
|
||||||
return wantarray ? @output : join('',@output);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub xargs_safe_pipe_capture {
|
|
||||||
my $MAX_ARG_LENGTH = 65536;
|
|
||||||
my $cmd = shift;
|
|
||||||
my @output;
|
|
||||||
my $output;
|
|
||||||
while(@_) {
|
|
||||||
my @args;
|
|
||||||
my $length = 0;
|
|
||||||
while(@_ && $length < $MAX_ARG_LENGTH) {
|
|
||||||
push @args, shift;
|
|
||||||
$length += length($args[$#args]);
|
|
||||||
}
|
|
||||||
if (wantarray) {
|
|
||||||
push @output, safe_pipe_capture(@$cmd, @args);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$output .= safe_pipe_capture(@$cmd, @args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return wantarray ? @output : $output;
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1,122 +0,0 @@
|
||||||
#!/usr/bin/perl
|
|
||||||
use lib (split(/:/, $ENV{GITPERLLIB} || "/usr/local/git/lib/perl5/site_perl"));
|
|
||||||
# Copyright (c) 2009, 2010 David Aguilar
|
|
||||||
#
|
|
||||||
# This is a wrapper around the GIT_EXTERNAL_DIFF-compatible
|
|
||||||
# git-difftool--helper script.
|
|
||||||
#
|
|
||||||
# This script exports GIT_EXTERNAL_DIFF and GIT_PAGER for use by git.
|
|
||||||
# GIT_DIFFTOOL_NO_PROMPT, GIT_DIFFTOOL_PROMPT, and GIT_DIFF_TOOL
|
|
||||||
# are exported for use by git-difftool--helper.
|
|
||||||
#
|
|
||||||
# Any arguments that are unknown to this script are forwarded to 'git diff'.
|
|
||||||
|
|
||||||
use 5.008;
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
use Cwd qw(abs_path);
|
|
||||||
use File::Basename qw(dirname);
|
|
||||||
|
|
||||||
require Git;
|
|
||||||
|
|
||||||
my $DIR = abs_path(dirname($0));
|
|
||||||
|
|
||||||
|
|
||||||
sub usage
|
|
||||||
{
|
|
||||||
print << 'USAGE';
|
|
||||||
usage: git difftool [-t|--tool=<tool>] [-x|--extcmd=<cmd>]
|
|
||||||
[-y|--no-prompt] [-g|--gui]
|
|
||||||
['git diff' options]
|
|
||||||
USAGE
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub setup_environment
|
|
||||||
{
|
|
||||||
$ENV{PATH} = "$DIR:$ENV{PATH}";
|
|
||||||
$ENV{GIT_PAGER} = '';
|
|
||||||
$ENV{GIT_EXTERNAL_DIFF} = 'git-difftool--helper';
|
|
||||||
}
|
|
||||||
|
|
||||||
sub exe
|
|
||||||
{
|
|
||||||
my $exe = shift;
|
|
||||||
if ($^O eq 'MSWin32' || $^O eq 'msys') {
|
|
||||||
return "$exe.exe";
|
|
||||||
}
|
|
||||||
return $exe;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub generate_command
|
|
||||||
{
|
|
||||||
my @command = (exe('git'), 'diff');
|
|
||||||
my $skip_next = 0;
|
|
||||||
my $idx = -1;
|
|
||||||
my $prompt = '';
|
|
||||||
for my $arg (@ARGV) {
|
|
||||||
$idx++;
|
|
||||||
if ($skip_next) {
|
|
||||||
$skip_next = 0;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
if ($arg eq '-t' || $arg eq '--tool') {
|
|
||||||
usage() if $#ARGV <= $idx;
|
|
||||||
$ENV{GIT_DIFF_TOOL} = $ARGV[$idx + 1];
|
|
||||||
$skip_next = 1;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
if ($arg =~ /^--tool=/) {
|
|
||||||
$ENV{GIT_DIFF_TOOL} = substr($arg, 7);
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
if ($arg eq '-x' || $arg eq '--extcmd') {
|
|
||||||
usage() if $#ARGV <= $idx;
|
|
||||||
$ENV{GIT_DIFFTOOL_EXTCMD} = $ARGV[$idx + 1];
|
|
||||||
$skip_next = 1;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
if ($arg =~ /^--extcmd=/) {
|
|
||||||
$ENV{GIT_DIFFTOOL_EXTCMD} = substr($arg, 9);
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
if ($arg eq '-g' || $arg eq '--gui') {
|
|
||||||
eval {
|
|
||||||
my $tool = Git::command_oneline('config',
|
|
||||||
'diff.guitool');
|
|
||||||
if (length($tool)) {
|
|
||||||
$ENV{GIT_DIFF_TOOL} = $tool;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
if ($arg eq '-y' || $arg eq '--no-prompt') {
|
|
||||||
$prompt = 'no';
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
if ($arg eq '--prompt') {
|
|
||||||
$prompt = 'yes';
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
if ($arg eq '-h' || $arg eq '--help') {
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
push @command, $arg;
|
|
||||||
}
|
|
||||||
if ($prompt eq 'yes') {
|
|
||||||
$ENV{GIT_DIFFTOOL_PROMPT} = 'true';
|
|
||||||
} elsif ($prompt eq 'no') {
|
|
||||||
$ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true';
|
|
||||||
}
|
|
||||||
return @command
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_environment();
|
|
||||||
|
|
||||||
# ActiveState Perl for Win32 does not implement POSIX semantics of
|
|
||||||
# exec* system call. It just spawns the given executable and finishes
|
|
||||||
# the starting program, exiting with code 0.
|
|
||||||
# system will at least catch the errors returned by git diff,
|
|
||||||
# allowing the caller of git difftool better handling of failures.
|
|
||||||
my $rc = system(generate_command());
|
|
||||||
exit($rc | ($rc >> 8));
|
|
|
@ -1,72 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
# git-difftool--helper is a GIT_EXTERNAL_DIFF-compatible diff tool launcher.
|
|
||||||
# This script is typically launched by using the 'git difftool'
|
|
||||||
# convenience command.
|
|
||||||
#
|
|
||||||
# Copyright (c) 2009, 2010 David Aguilar
|
|
||||||
|
|
||||||
TOOL_MODE=diff
|
|
||||||
. git-mergetool--lib
|
|
||||||
|
|
||||||
# difftool.prompt controls the default prompt/no-prompt behavior
|
|
||||||
# and is overridden with $GIT_DIFFTOOL*_PROMPT.
|
|
||||||
should_prompt () {
|
|
||||||
prompt_merge=$(git config --bool mergetool.prompt || echo true)
|
|
||||||
prompt=$(git config --bool difftool.prompt || echo $prompt_merge)
|
|
||||||
if test "$prompt" = true; then
|
|
||||||
test -z "$GIT_DIFFTOOL_NO_PROMPT"
|
|
||||||
else
|
|
||||||
test -n "$GIT_DIFFTOOL_PROMPT"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Indicates that --extcmd=... was specified
|
|
||||||
use_ext_cmd () {
|
|
||||||
test -n "$GIT_DIFFTOOL_EXTCMD"
|
|
||||||
}
|
|
||||||
|
|
||||||
launch_merge_tool () {
|
|
||||||
# Merged is the filename as it appears in the work tree
|
|
||||||
# Local is the contents of a/filename
|
|
||||||
# Remote is the contents of b/filename
|
|
||||||
# Custom merge tool commands might use $BASE so we provide it
|
|
||||||
MERGED="$1"
|
|
||||||
LOCAL="$2"
|
|
||||||
REMOTE="$3"
|
|
||||||
BASE="$1"
|
|
||||||
|
|
||||||
# $LOCAL and $REMOTE are temporary files so prompt
|
|
||||||
# the user with the real $MERGED name before launching $merge_tool.
|
|
||||||
if should_prompt; then
|
|
||||||
printf "\nViewing: '$MERGED'\n"
|
|
||||||
if use_ext_cmd; then
|
|
||||||
printf "Hit return to launch '%s': " \
|
|
||||||
"$GIT_DIFFTOOL_EXTCMD"
|
|
||||||
else
|
|
||||||
printf "Hit return to launch '%s': " "$merge_tool"
|
|
||||||
fi
|
|
||||||
read ans
|
|
||||||
fi
|
|
||||||
|
|
||||||
if use_ext_cmd; then
|
|
||||||
export BASE
|
|
||||||
eval $GIT_DIFFTOOL_EXTCMD '"$LOCAL"' '"$REMOTE"'
|
|
||||||
else
|
|
||||||
run_merge_tool "$merge_tool"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
if ! use_ext_cmd; then
|
|
||||||
if test -n "$GIT_DIFF_TOOL"; then
|
|
||||||
merge_tool="$GIT_DIFF_TOOL"
|
|
||||||
else
|
|
||||||
merge_tool="$(get_merge_tool)" || exit
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Launch the merge tool on each path provided by 'git diff'
|
|
||||||
while test $# -gt 6
|
|
||||||
do
|
|
||||||
launch_merge_tool "$1" "$2" "$5"
|
|
||||||
shift 7
|
|
||||||
done
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
Binary file not shown.
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1,516 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# Rewrite revision history
|
|
||||||
# Copyright (c) Petr Baudis, 2006
|
|
||||||
# Minimal changes to "port" it to core-git (c) Johannes Schindelin, 2007
|
|
||||||
#
|
|
||||||
# Lets you rewrite the revision history of the current branch, creating
|
|
||||||
# a new branch. You can specify a number of filters to modify the commits,
|
|
||||||
# files and trees.
|
|
||||||
|
|
||||||
# The following functions will also be available in the commit filter:
|
|
||||||
|
|
||||||
functions=$(cat << \EOF
|
|
||||||
warn () {
|
|
||||||
echo "$*" >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
map()
|
|
||||||
{
|
|
||||||
# if it was not rewritten, take the original
|
|
||||||
if test -r "$workdir/../map/$1"
|
|
||||||
then
|
|
||||||
cat "$workdir/../map/$1"
|
|
||||||
else
|
|
||||||
echo "$1"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# if you run 'skip_commit "$@"' in a commit filter, it will print
|
|
||||||
# the (mapped) parents, effectively skipping the commit.
|
|
||||||
|
|
||||||
skip_commit()
|
|
||||||
{
|
|
||||||
shift;
|
|
||||||
while [ -n "$1" ];
|
|
||||||
do
|
|
||||||
shift;
|
|
||||||
map "$1";
|
|
||||||
shift;
|
|
||||||
done;
|
|
||||||
}
|
|
||||||
|
|
||||||
# if you run 'git_commit_non_empty_tree "$@"' in a commit filter,
|
|
||||||
# it will skip commits that leave the tree untouched, commit the other.
|
|
||||||
git_commit_non_empty_tree()
|
|
||||||
{
|
|
||||||
if test $# = 3 && test "$1" = $(git rev-parse "$3^{tree}"); then
|
|
||||||
map "$3"
|
|
||||||
else
|
|
||||||
git commit-tree "$@"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
# override die(): this version puts in an extra line break, so that
|
|
||||||
# the progress is still visible
|
|
||||||
|
|
||||||
die()
|
|
||||||
{
|
|
||||||
echo >&2
|
|
||||||
echo "$*" >&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
eval "$functions"
|
|
||||||
|
|
||||||
# When piped a commit, output a script to set the ident of either
|
|
||||||
# "author" or "committer
|
|
||||||
|
|
||||||
set_ident () {
|
|
||||||
lid="$(echo "$1" | tr "[A-Z]" "[a-z]")"
|
|
||||||
uid="$(echo "$1" | tr "[a-z]" "[A-Z]")"
|
|
||||||
pick_id_script='
|
|
||||||
/^'$lid' /{
|
|
||||||
s/'\''/'\''\\'\'\''/g
|
|
||||||
h
|
|
||||||
s/^'$lid' \([^<]*\) <[^>]*> .*$/\1/
|
|
||||||
s/'\''/'\''\'\'\''/g
|
|
||||||
s/.*/GIT_'$uid'_NAME='\''&'\''; export GIT_'$uid'_NAME/p
|
|
||||||
|
|
||||||
g
|
|
||||||
s/^'$lid' [^<]* <\([^>]*\)> .*$/\1/
|
|
||||||
s/'\''/'\''\'\'\''/g
|
|
||||||
s/.*/GIT_'$uid'_EMAIL='\''&'\''; export GIT_'$uid'_EMAIL/p
|
|
||||||
|
|
||||||
g
|
|
||||||
s/^'$lid' [^<]* <[^>]*> \(.*\)$/\1/
|
|
||||||
s/'\''/'\''\'\'\''/g
|
|
||||||
s/.*/GIT_'$uid'_DATE='\''&'\''; export GIT_'$uid'_DATE/p
|
|
||||||
|
|
||||||
q
|
|
||||||
}
|
|
||||||
'
|
|
||||||
|
|
||||||
LANG=C LC_ALL=C sed -ne "$pick_id_script"
|
|
||||||
# Ensure non-empty id name.
|
|
||||||
echo "case \"\$GIT_${uid}_NAME\" in \"\") GIT_${uid}_NAME=\"\${GIT_${uid}_EMAIL%%@*}\" && export GIT_${uid}_NAME;; esac"
|
|
||||||
}
|
|
||||||
|
|
||||||
USAGE="[--env-filter <command>] [--tree-filter <command>]
|
|
||||||
[--index-filter <command>] [--parent-filter <command>]
|
|
||||||
[--msg-filter <command>] [--commit-filter <command>]
|
|
||||||
[--tag-name-filter <command>] [--subdirectory-filter <directory>]
|
|
||||||
[--original <namespace>] [-d <directory>] [-f | --force]
|
|
||||||
[<rev-list options>...]"
|
|
||||||
|
|
||||||
OPTIONS_SPEC=
|
|
||||||
. git-sh-setup
|
|
||||||
|
|
||||||
if [ "$(is_bare_repository)" = false ]; then
|
|
||||||
git diff-files --ignore-submodules --quiet &&
|
|
||||||
git diff-index --cached --quiet HEAD -- ||
|
|
||||||
die "Cannot rewrite branch(es) with a dirty working directory."
|
|
||||||
fi
|
|
||||||
|
|
||||||
tempdir=.git-rewrite
|
|
||||||
filter_env=
|
|
||||||
filter_tree=
|
|
||||||
filter_index=
|
|
||||||
filter_parent=
|
|
||||||
filter_msg=cat
|
|
||||||
filter_commit=
|
|
||||||
filter_tag_name=
|
|
||||||
filter_subdir=
|
|
||||||
orig_namespace=refs/original/
|
|
||||||
force=
|
|
||||||
prune_empty=
|
|
||||||
remap_to_ancestor=
|
|
||||||
while :
|
|
||||||
do
|
|
||||||
case "$1" in
|
|
||||||
--)
|
|
||||||
shift
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
--force|-f)
|
|
||||||
shift
|
|
||||||
force=t
|
|
||||||
continue
|
|
||||||
;;
|
|
||||||
--remap-to-ancestor)
|
|
||||||
# deprecated ($remap_to_ancestor is set now automatically)
|
|
||||||
shift
|
|
||||||
remap_to_ancestor=t
|
|
||||||
continue
|
|
||||||
;;
|
|
||||||
--prune-empty)
|
|
||||||
shift
|
|
||||||
prune_empty=t
|
|
||||||
continue
|
|
||||||
;;
|
|
||||||
-*)
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
break;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# all switches take one argument
|
|
||||||
ARG="$1"
|
|
||||||
case "$#" in 1) usage ;; esac
|
|
||||||
shift
|
|
||||||
OPTARG="$1"
|
|
||||||
shift
|
|
||||||
|
|
||||||
case "$ARG" in
|
|
||||||
-d)
|
|
||||||
tempdir="$OPTARG"
|
|
||||||
;;
|
|
||||||
--env-filter)
|
|
||||||
filter_env="$OPTARG"
|
|
||||||
;;
|
|
||||||
--tree-filter)
|
|
||||||
filter_tree="$OPTARG"
|
|
||||||
;;
|
|
||||||
--index-filter)
|
|
||||||
filter_index="$OPTARG"
|
|
||||||
;;
|
|
||||||
--parent-filter)
|
|
||||||
filter_parent="$OPTARG"
|
|
||||||
;;
|
|
||||||
--msg-filter)
|
|
||||||
filter_msg="$OPTARG"
|
|
||||||
;;
|
|
||||||
--commit-filter)
|
|
||||||
filter_commit="$functions; $OPTARG"
|
|
||||||
;;
|
|
||||||
--tag-name-filter)
|
|
||||||
filter_tag_name="$OPTARG"
|
|
||||||
;;
|
|
||||||
--subdirectory-filter)
|
|
||||||
filter_subdir="$OPTARG"
|
|
||||||
remap_to_ancestor=t
|
|
||||||
;;
|
|
||||||
--original)
|
|
||||||
orig_namespace=$(expr "$OPTARG/" : '\(.*[^/]\)/*$')/
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
usage
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
case "$prune_empty,$filter_commit" in
|
|
||||||
,)
|
|
||||||
filter_commit='git commit-tree "$@"';;
|
|
||||||
t,)
|
|
||||||
filter_commit="$functions;"' git_commit_non_empty_tree "$@"';;
|
|
||||||
,*)
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
die "Cannot set --prune-empty and --commit-filter at the same time"
|
|
||||||
esac
|
|
||||||
|
|
||||||
case "$force" in
|
|
||||||
t)
|
|
||||||
rm -rf "$tempdir"
|
|
||||||
;;
|
|
||||||
'')
|
|
||||||
test -d "$tempdir" &&
|
|
||||||
die "$tempdir already exists, please remove it"
|
|
||||||
esac
|
|
||||||
mkdir -p "$tempdir/t" &&
|
|
||||||
tempdir="$(cd "$tempdir"; pwd)" &&
|
|
||||||
cd "$tempdir/t" &&
|
|
||||||
workdir="$(pwd)" ||
|
|
||||||
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 || exit
|
|
||||||
while read sha1 type name
|
|
||||||
do
|
|
||||||
case "$force,$name" in
|
|
||||||
,$orig_namespace*)
|
|
||||||
die "Cannot create a new backup.
|
|
||||||
A previous backup already exists in $orig_namespace
|
|
||||||
Force overwriting the backup with -f"
|
|
||||||
;;
|
|
||||||
t,$orig_namespace*)
|
|
||||||
git update-ref -d "$name" $sha1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done < "$tempdir"/backup-refs
|
|
||||||
|
|
||||||
# The refs should be updated if their heads were rewritten
|
|
||||||
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?"
|
|
||||||
|
|
||||||
GIT_INDEX_FILE="$(pwd)/../index"
|
|
||||||
export GIT_INDEX_FILE
|
|
||||||
|
|
||||||
# map old->new commit ids for rewriting parents
|
|
||||||
mkdir ../map || die "Could not create map/ directory"
|
|
||||||
|
|
||||||
# we need "--" only if there are no path arguments in $@
|
|
||||||
nonrevs=$(git rev-parse --no-revs "$@") || exit
|
|
||||||
if test -z "$nonrevs"
|
|
||||||
then
|
|
||||||
dashdash=--
|
|
||||||
else
|
|
||||||
dashdash=
|
|
||||||
remap_to_ancestor=t
|
|
||||||
fi
|
|
||||||
|
|
||||||
rev_args=$(git rev-parse --revs-only "$@")
|
|
||||||
|
|
||||||
case "$filter_subdir" in
|
|
||||||
"")
|
|
||||||
eval set -- "$(git rev-parse --sq --no-revs "$@")"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
eval set -- "$(git rev-parse --sq --no-revs "$@" $dashdash \
|
|
||||||
"$filter_subdir")"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
git rev-list --reverse --topo-order --default HEAD \
|
|
||||||
--parents --simplify-merges $rev_args "$@" > ../revs ||
|
|
||||||
die "Could not get the commits"
|
|
||||||
commits=$(wc -l <../revs | tr -d " ")
|
|
||||||
|
|
||||||
test $commits -eq 0 && die "Found nothing to rewrite"
|
|
||||||
|
|
||||||
# Rewrite the commits
|
|
||||||
|
|
||||||
git_filter_branch__commit_count=0
|
|
||||||
while read commit parents; do
|
|
||||||
git_filter_branch__commit_count=$(($git_filter_branch__commit_count+1))
|
|
||||||
printf "\rRewrite $commit ($git_filter_branch__commit_count/$commits)"
|
|
||||||
|
|
||||||
case "$filter_subdir" in
|
|
||||||
"")
|
|
||||||
git read-tree -i -m $commit
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
# The commit may not have the subdirectory at all
|
|
||||||
err=$(git read-tree -i -m $commit:"$filter_subdir" 2>&1) || {
|
|
||||||
if ! git rev-parse -q --verify $commit:"$filter_subdir"
|
|
||||||
then
|
|
||||||
rm -f "$GIT_INDEX_FILE"
|
|
||||||
else
|
|
||||||
echo >&2 "$err"
|
|
||||||
false
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
esac || die "Could not initialize the index"
|
|
||||||
|
|
||||||
GIT_COMMIT=$commit
|
|
||||||
export GIT_COMMIT
|
|
||||||
git cat-file commit "$commit" >../commit ||
|
|
||||||
die "Cannot read commit $commit"
|
|
||||||
|
|
||||||
eval "$(set_ident AUTHOR <../commit)" ||
|
|
||||||
die "setting author failed for commit $commit"
|
|
||||||
eval "$(set_ident COMMITTER <../commit)" ||
|
|
||||||
die "setting committer failed for commit $commit"
|
|
||||||
eval "$filter_env" < /dev/null ||
|
|
||||||
die "env filter failed: $filter_env"
|
|
||||||
|
|
||||||
if [ "$filter_tree" ]; then
|
|
||||||
git checkout-index -f -u -a ||
|
|
||||||
die "Could not checkout the index"
|
|
||||||
# files that $commit removed are now still in the working tree;
|
|
||||||
# remove them, else they would be added again
|
|
||||||
git clean -d -q -f -x
|
|
||||||
eval "$filter_tree" < /dev/null ||
|
|
||||||
die "tree filter failed: $filter_tree"
|
|
||||||
|
|
||||||
(
|
|
||||||
git diff-index -r --name-only --ignore-submodules $commit &&
|
|
||||||
git ls-files --others
|
|
||||||
) > "$tempdir"/tree-state || exit
|
|
||||||
git update-index --add --replace --remove --stdin \
|
|
||||||
< "$tempdir"/tree-state || exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
eval "$filter_index" < /dev/null ||
|
|
||||||
die "index filter failed: $filter_index"
|
|
||||||
|
|
||||||
parentstr=
|
|
||||||
for parent in $parents; do
|
|
||||||
for reparent in $(map "$parent"); do
|
|
||||||
parentstr="$parentstr -p $reparent"
|
|
||||||
done
|
|
||||||
done
|
|
||||||
if [ "$filter_parent" ]; then
|
|
||||||
parentstr="$(echo "$parentstr" | eval "$filter_parent")" ||
|
|
||||||
die "parent filter failed: $filter_parent"
|
|
||||||
fi
|
|
||||||
|
|
||||||
sed -e '1,/^$/d' <../commit | \
|
|
||||||
eval "$filter_msg" > ../message ||
|
|
||||||
die "msg filter failed: $filter_msg"
|
|
||||||
workdir=$workdir /bin/sh -c "$filter_commit" "git commit-tree" \
|
|
||||||
$(git write-tree) $parentstr < ../message > ../map/$commit ||
|
|
||||||
die "could not write rewritten commit"
|
|
||||||
done <../revs
|
|
||||||
|
|
||||||
# If we are filtering for paths, as in the case of a subdirectory
|
|
||||||
# filter, it is possible that a specified head is not in the set of
|
|
||||||
# rewritten commits, because it was pruned by the revision walker.
|
|
||||||
# Ancestor remapping fixes this by mapping these heads to the unique
|
|
||||||
# nearest ancestor that survived the pruning.
|
|
||||||
|
|
||||||
if test "$remap_to_ancestor" = t
|
|
||||||
then
|
|
||||||
while read ref
|
|
||||||
do
|
|
||||||
sha1=$(git rev-parse "$ref"^0)
|
|
||||||
test -f "$workdir"/../map/$sha1 && continue
|
|
||||||
ancestor=$(git rev-list --simplify-merges -1 "$ref" "$@")
|
|
||||||
test "$ancestor" && echo $(map $ancestor) >> "$workdir"/../map/$sha1
|
|
||||||
done < "$tempdir"/heads
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Finally update the refs
|
|
||||||
|
|
||||||
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
|
|
||||||
_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
|
|
||||||
echo
|
|
||||||
while read ref
|
|
||||||
do
|
|
||||||
# avoid rewriting a ref twice
|
|
||||||
test -f "$orig_namespace$ref" && continue
|
|
||||||
|
|
||||||
sha1=$(git rev-parse "$ref"^0)
|
|
||||||
rewritten=$(map $sha1)
|
|
||||||
|
|
||||||
test $sha1 = "$rewritten" &&
|
|
||||||
warn "WARNING: Ref '$ref' is unchanged" &&
|
|
||||||
continue
|
|
||||||
|
|
||||||
case "$rewritten" in
|
|
||||||
'')
|
|
||||||
echo "Ref '$ref' was deleted"
|
|
||||||
git update-ref -m "filter-branch: delete" -d "$ref" $sha1 ||
|
|
||||||
die "Could not delete $ref"
|
|
||||||
;;
|
|
||||||
$_x40)
|
|
||||||
echo "Ref '$ref' was rewritten"
|
|
||||||
if ! git update-ref -m "filter-branch: rewrite" \
|
|
||||||
"$ref" $rewritten $sha1 2>/dev/null; then
|
|
||||||
if test $(git cat-file -t "$ref") = tag; then
|
|
||||||
if test -z "$filter_tag_name"; then
|
|
||||||
warn "WARNING: You said to rewrite tagged commits, but not the corresponding tag."
|
|
||||||
warn "WARNING: Perhaps use '--tag-name-filter cat' to rewrite the tag."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
die "Could not rewrite $ref"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
# NEEDSWORK: possibly add -Werror, making this an error
|
|
||||||
warn "WARNING: '$ref' was rewritten into multiple commits:"
|
|
||||||
warn "$rewritten"
|
|
||||||
warn "WARNING: Ref '$ref' points to the first one now."
|
|
||||||
rewritten=$(echo "$rewritten" | head -n 1)
|
|
||||||
git update-ref -m "filter-branch: rewrite to first" \
|
|
||||||
"$ref" $rewritten $sha1 ||
|
|
||||||
die "Could not rewrite $ref"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
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
|
|
||||||
# refs are updated, and their original heads stored in refs/original/
|
|
||||||
# Filter tags
|
|
||||||
|
|
||||||
if [ "$filter_tag_name" ]; then
|
|
||||||
git for-each-ref --format='%(objectname) %(objecttype) %(refname)' refs/tags |
|
|
||||||
while read sha1 type ref; do
|
|
||||||
ref="${ref#refs/tags/}"
|
|
||||||
# XXX: Rewrite tagged trees as well?
|
|
||||||
if [ "$type" != "commit" -a "$type" != "tag" ]; then
|
|
||||||
continue;
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$type" = "tag" ]; then
|
|
||||||
# Dereference to a commit
|
|
||||||
sha1t="$sha1"
|
|
||||||
sha1="$(git rev-parse -q "$sha1"^{commit})" || continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
[ -f "../map/$sha1" ] || continue
|
|
||||||
new_sha1="$(cat "../map/$sha1")"
|
|
||||||
GIT_COMMIT="$sha1"
|
|
||||||
export GIT_COMMIT
|
|
||||||
new_ref="$(echo "$ref" | eval "$filter_tag_name")" ||
|
|
||||||
die "tag name filter failed: $filter_tag_name"
|
|
||||||
|
|
||||||
echo "$ref -> $new_ref ($sha1 -> $new_sha1)"
|
|
||||||
|
|
||||||
if [ "$type" = "tag" ]; then
|
|
||||||
new_sha1=$( ( printf 'object %s\ntype commit\ntag %s\n' \
|
|
||||||
"$new_sha1" "$new_ref"
|
|
||||||
git cat-file tag "$ref" |
|
|
||||||
sed -n \
|
|
||||||
-e '1,/^$/{
|
|
||||||
/^object /d
|
|
||||||
/^type /d
|
|
||||||
/^tag /d
|
|
||||||
}' \
|
|
||||||
-e '/^-----BEGIN PGP SIGNATURE-----/q' \
|
|
||||||
-e 'p' ) |
|
|
||||||
git mktag) ||
|
|
||||||
die "Could not create new tag object for $ref"
|
|
||||||
if git cat-file tag "$ref" | \
|
|
||||||
sane_grep '^-----BEGIN PGP SIGNATURE-----' >/dev/null 2>&1
|
|
||||||
then
|
|
||||||
warn "gpg signature stripped from tag object $sha1t"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
git update-ref "refs/tags/$new_ref" "$new_sha1" ||
|
|
||||||
die "Could not write tag $new_ref"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd ../..
|
|
||||||
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
|
|
||||||
git read-tree -u -m HEAD || exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit 0
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1,8 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
if test "z$*" = zversion ||
|
|
||||||
test "z$*" = z--version
|
|
||||||
then
|
|
||||||
echo 'git-gui version 0.14.0-dirty'
|
|
||||||
else
|
|
||||||
exec '/usr/local/git/share/git-gui/lib/Git Gui.app/Contents/MacOS/Wish' "$0" "$@"
|
|
||||||
fi
|
|
|
@ -1,66 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
# Tcl ignores the next line -*- tcl -*- \
|
|
||||||
exec wish "$0" -- "$@"
|
|
||||||
|
|
||||||
# This is a trivial implementation of an SSH_ASKPASS handler.
|
|
||||||
# Git-gui uses this script if none are already configured.
|
|
||||||
|
|
||||||
package require Tk
|
|
||||||
|
|
||||||
set answer {}
|
|
||||||
set yesno 0
|
|
||||||
set rc 255
|
|
||||||
|
|
||||||
if {$argc < 1} {
|
|
||||||
set prompt "Enter your OpenSSH passphrase:"
|
|
||||||
} else {
|
|
||||||
set prompt [join $argv " "]
|
|
||||||
if {[regexp -nocase {\(yes\/no\)\?\s*$} $prompt]} {
|
|
||||||
set yesno 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message .m -text $prompt -justify center -aspect 4000
|
|
||||||
pack .m -side top -fill x -padx 20 -pady 20 -expand 1
|
|
||||||
|
|
||||||
entry .e -textvariable answer -width 50
|
|
||||||
pack .e -side top -fill x -padx 10 -pady 10
|
|
||||||
|
|
||||||
if {!$yesno} {
|
|
||||||
.e configure -show "*"
|
|
||||||
}
|
|
||||||
|
|
||||||
frame .b
|
|
||||||
button .b.ok -text OK -command finish
|
|
||||||
button .b.cancel -text Cancel -command cancel
|
|
||||||
|
|
||||||
pack .b.ok -side left -expand 1
|
|
||||||
pack .b.cancel -side right -expand 1
|
|
||||||
pack .b -side bottom -fill x -padx 10 -pady 10
|
|
||||||
|
|
||||||
bind . <Visibility> {focus -force .e}
|
|
||||||
bind . <Key-Return> [list .b.ok invoke]
|
|
||||||
bind . <Key-Escape> [list .b.cancel invoke]
|
|
||||||
bind . <Destroy> {set rc $rc}
|
|
||||||
|
|
||||||
proc cancel {} {
|
|
||||||
set ::rc 255
|
|
||||||
}
|
|
||||||
|
|
||||||
proc finish {} {
|
|
||||||
if {$::yesno} {
|
|
||||||
if {$::answer ne "yes" && $::answer ne "no"} {
|
|
||||||
tk_messageBox -icon error -title "Error" -type ok \
|
|
||||||
-message "Only 'yes' or 'no' input allowed."
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
puts $::answer
|
|
||||||
set ::rc 0
|
|
||||||
}
|
|
||||||
|
|
||||||
wm title . "OpenSSH"
|
|
||||||
tk::PlaceWindow .
|
|
||||||
vwait rc
|
|
||||||
exit $rc
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1,624 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# Copyright (c) 2006 Eric Wong
|
|
||||||
#
|
|
||||||
|
|
||||||
PERL='/usr/bin/perl'
|
|
||||||
OPTIONS_KEEPDASHDASH=
|
|
||||||
OPTIONS_SPEC="\
|
|
||||||
git instaweb [options] (--start | --stop | --restart)
|
|
||||||
--
|
|
||||||
l,local only bind on 127.0.0.1
|
|
||||||
p,port= the port to bind to
|
|
||||||
d,httpd= the command to launch
|
|
||||||
b,browser= the browser to launch
|
|
||||||
m,module-path= the module path (only needed for apache2)
|
|
||||||
Action
|
|
||||||
stop stop the web server
|
|
||||||
start start the web server
|
|
||||||
restart restart the web server
|
|
||||||
"
|
|
||||||
|
|
||||||
. git-sh-setup
|
|
||||||
|
|
||||||
fqgitdir="$GIT_DIR"
|
|
||||||
local="$(git config --bool --get instaweb.local)"
|
|
||||||
httpd="$(git config --get instaweb.httpd)"
|
|
||||||
root="$(git config --get instaweb.gitwebdir)"
|
|
||||||
port=$(git config --get instaweb.port)
|
|
||||||
module_path="$(git config --get instaweb.modulepath)"
|
|
||||||
|
|
||||||
conf="$GIT_DIR/gitweb/httpd.conf"
|
|
||||||
|
|
||||||
# Defaults:
|
|
||||||
|
|
||||||
# if installed, it doesn't need further configuration (module_path)
|
|
||||||
test -z "$httpd" && httpd='lighttpd -f'
|
|
||||||
|
|
||||||
# Default is /usr/local/git/share/gitweb
|
|
||||||
test -z "$root" && root='/usr/local/git/share/gitweb'
|
|
||||||
|
|
||||||
# any untaken local port will do...
|
|
||||||
test -z "$port" && port=1234
|
|
||||||
|
|
||||||
resolve_full_httpd () {
|
|
||||||
case "$httpd" in
|
|
||||||
*apache2*|*lighttpd*|*httpd*)
|
|
||||||
# yes, *httpd* covers *lighttpd* above, but it is there for clarity
|
|
||||||
# ensure that the apache2/lighttpd command ends with "-f"
|
|
||||||
if ! echo "$httpd" | sane_grep -- '-f *$' >/dev/null 2>&1
|
|
||||||
then
|
|
||||||
httpd="$httpd -f"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*plackup*)
|
|
||||||
# server is started by running via generated gitweb.psgi in $fqgitdir/gitweb
|
|
||||||
full_httpd="$fqgitdir/gitweb/gitweb.psgi"
|
|
||||||
httpd_only="${httpd%% *}" # cut on first space
|
|
||||||
return
|
|
||||||
;;
|
|
||||||
*webrick*)
|
|
||||||
# server is started by running via generated webrick.rb in
|
|
||||||
# $fqgitdir/gitweb
|
|
||||||
full_httpd="$fqgitdir/gitweb/webrick.rb"
|
|
||||||
httpd_only="${httpd%% *}" # cut on first space
|
|
||||||
return
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
httpd_only="$(echo $httpd | cut -f1 -d' ')"
|
|
||||||
if case "$httpd_only" in /*) : ;; *) which $httpd_only >/dev/null 2>&1;; esac
|
|
||||||
then
|
|
||||||
full_httpd=$httpd
|
|
||||||
else
|
|
||||||
# many httpds are installed in /usr/sbin or /usr/local/sbin
|
|
||||||
# these days and those are not in most users $PATHs
|
|
||||||
# in addition, we may have generated a server script
|
|
||||||
# in $fqgitdir/gitweb.
|
|
||||||
for i in /usr/local/sbin /usr/sbin "$root" "$fqgitdir/gitweb"
|
|
||||||
do
|
|
||||||
if test -x "$i/$httpd_only"
|
|
||||||
then
|
|
||||||
full_httpd=$i/$httpd
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo >&2 "$httpd_only not found. Install $httpd_only or use" \
|
|
||||||
"--httpd to specify another httpd daemon."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
start_httpd () {
|
|
||||||
if test -f "$fqgitdir/pid"; then
|
|
||||||
say "Instance already running. Restarting..."
|
|
||||||
stop_httpd
|
|
||||||
fi
|
|
||||||
|
|
||||||
# here $httpd should have a meaningful value
|
|
||||||
resolve_full_httpd
|
|
||||||
|
|
||||||
# don't quote $full_httpd, there can be arguments to it (-f)
|
|
||||||
case "$httpd" in
|
|
||||||
*mongoose*|*plackup*)
|
|
||||||
#These servers don't have a daemon mode so we'll have to fork it
|
|
||||||
$full_httpd "$fqgitdir/gitweb/httpd.conf" &
|
|
||||||
#Save the pid before doing anything else (we'll print it later)
|
|
||||||
pid=$!
|
|
||||||
|
|
||||||
if test $? != 0; then
|
|
||||||
echo "Could not execute http daemon $httpd."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat > "$fqgitdir/pid" <<EOF
|
|
||||||
$pid
|
|
||||||
EOF
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
$full_httpd "$fqgitdir/gitweb/httpd.conf"
|
|
||||||
if test $? != 0; then
|
|
||||||
echo "Could not execute http daemon $httpd."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_httpd () {
|
|
||||||
test -f "$fqgitdir/pid" && kill $(cat "$fqgitdir/pid")
|
|
||||||
rm -f "$fqgitdir/pid"
|
|
||||||
}
|
|
||||||
|
|
||||||
httpd_is_ready () {
|
|
||||||
"$PERL" -MIO::Socket::INET -e "
|
|
||||||
local \$| = 1; # turn on autoflush
|
|
||||||
exit if (IO::Socket::INET->new('127.0.0.1:$port'));
|
|
||||||
print 'Waiting for \'$httpd\' to start ..';
|
|
||||||
do {
|
|
||||||
print '.';
|
|
||||||
sleep(1);
|
|
||||||
} until (IO::Socket::INET->new('127.0.0.1:$port'));
|
|
||||||
print qq! (done)\n!;
|
|
||||||
"
|
|
||||||
}
|
|
||||||
|
|
||||||
while test $# != 0
|
|
||||||
do
|
|
||||||
case "$1" in
|
|
||||||
--stop|stop)
|
|
||||||
stop_httpd
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
--start|start)
|
|
||||||
start_httpd
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
--restart|restart)
|
|
||||||
stop_httpd
|
|
||||||
start_httpd
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
-l|--local)
|
|
||||||
local=true
|
|
||||||
;;
|
|
||||||
-d|--httpd)
|
|
||||||
shift
|
|
||||||
httpd="$1"
|
|
||||||
;;
|
|
||||||
-b|--browser)
|
|
||||||
shift
|
|
||||||
browser="$1"
|
|
||||||
;;
|
|
||||||
-p|--port)
|
|
||||||
shift
|
|
||||||
port="$1"
|
|
||||||
;;
|
|
||||||
-m|--module-path)
|
|
||||||
shift
|
|
||||||
module_path="$1"
|
|
||||||
;;
|
|
||||||
--)
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
usage
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
mkdir -p "$GIT_DIR/gitweb/tmp"
|
|
||||||
GIT_EXEC_PATH="$(git --exec-path)"
|
|
||||||
GIT_DIR="$fqgitdir"
|
|
||||||
GITWEB_CONFIG="$fqgitdir/gitweb/gitweb_config.perl"
|
|
||||||
export GIT_EXEC_PATH GIT_DIR GITWEB_CONFIG
|
|
||||||
|
|
||||||
webrick_conf () {
|
|
||||||
# webrick seems to have no way of passing arbitrary environment
|
|
||||||
# variables to the underlying CGI executable, so we wrap the
|
|
||||||
# actual gitweb.cgi using a shell script to force it
|
|
||||||
wrapper="$fqgitdir/gitweb/$httpd/wrapper.sh"
|
|
||||||
cat > "$wrapper" <<EOF
|
|
||||||
#!/bin/sh
|
|
||||||
# we use this shell script wrapper around the real gitweb.cgi since
|
|
||||||
# there appears to be no other way to pass arbitrary environment variables
|
|
||||||
# into the CGI process
|
|
||||||
GIT_EXEC_PATH=$GIT_EXEC_PATH GIT_DIR=$GIT_DIR GITWEB_CONFIG=$GITWEB_CONFIG
|
|
||||||
export GIT_EXEC_PATH GIT_DIR GITWEB_CONFIG
|
|
||||||
exec $root/gitweb.cgi
|
|
||||||
EOF
|
|
||||||
chmod +x "$wrapper"
|
|
||||||
|
|
||||||
# This assumes _ruby_ is in the user's $PATH. that's _one_
|
|
||||||
# portable way to run ruby, which could be installed anywhere, really.
|
|
||||||
# generate a standalone server script in $fqgitdir/gitweb.
|
|
||||||
cat >"$fqgitdir/gitweb/$httpd.rb" <<EOF
|
|
||||||
#!/usr/bin/env ruby
|
|
||||||
require 'webrick'
|
|
||||||
require 'logger'
|
|
||||||
options = {
|
|
||||||
:Port => $port,
|
|
||||||
:DocumentRoot => "$root",
|
|
||||||
:Logger => Logger.new('$fqgitdir/gitweb/error.log'),
|
|
||||||
:AccessLog => [
|
|
||||||
[ Logger.new('$fqgitdir/gitweb/access.log'),
|
|
||||||
WEBrick::AccessLog::COMBINED_LOG_FORMAT ]
|
|
||||||
],
|
|
||||||
:DirectoryIndex => ["gitweb.cgi"],
|
|
||||||
:CGIInterpreter => "$wrapper",
|
|
||||||
:StartCallback => lambda do
|
|
||||||
File.open("$fqgitdir/pid", "w") { |f| f.puts Process.pid }
|
|
||||||
end,
|
|
||||||
:ServerType => WEBrick::Daemon,
|
|
||||||
}
|
|
||||||
options[:BindAddress] = '127.0.0.1' if "$local" == "true"
|
|
||||||
server = WEBrick::HTTPServer.new(options)
|
|
||||||
['INT', 'TERM'].each do |signal|
|
|
||||||
trap(signal) {server.shutdown}
|
|
||||||
end
|
|
||||||
server.start
|
|
||||||
EOF
|
|
||||||
chmod +x "$fqgitdir/gitweb/$httpd.rb"
|
|
||||||
# configuration is embedded in server script file, webrick.rb
|
|
||||||
rm -f "$conf"
|
|
||||||
}
|
|
||||||
|
|
||||||
lighttpd_conf () {
|
|
||||||
cat > "$conf" <<EOF
|
|
||||||
server.document-root = "$root"
|
|
||||||
server.port = $port
|
|
||||||
server.modules = ( "mod_setenv", "mod_cgi" )
|
|
||||||
server.indexfiles = ( "gitweb.cgi" )
|
|
||||||
server.pid-file = "$fqgitdir/pid"
|
|
||||||
server.errorlog = "$fqgitdir/gitweb/$httpd_only/error.log"
|
|
||||||
|
|
||||||
# to enable, add "mod_access", "mod_accesslog" to server.modules
|
|
||||||
# variable above and uncomment this
|
|
||||||
#accesslog.filename = "$fqgitdir/gitweb/$httpd_only/access.log"
|
|
||||||
|
|
||||||
setenv.add-environment = ( "PATH" => env.PATH, "GITWEB_CONFIG" => env.GITWEB_CONFIG )
|
|
||||||
|
|
||||||
cgi.assign = ( ".cgi" => "" )
|
|
||||||
|
|
||||||
# mimetype mapping
|
|
||||||
mimetype.assign = (
|
|
||||||
".pdf" => "application/pdf",
|
|
||||||
".sig" => "application/pgp-signature",
|
|
||||||
".spl" => "application/futuresplash",
|
|
||||||
".class" => "application/octet-stream",
|
|
||||||
".ps" => "application/postscript",
|
|
||||||
".torrent" => "application/x-bittorrent",
|
|
||||||
".dvi" => "application/x-dvi",
|
|
||||||
".gz" => "application/x-gzip",
|
|
||||||
".pac" => "application/x-ns-proxy-autoconfig",
|
|
||||||
".swf" => "application/x-shockwave-flash",
|
|
||||||
".tar.gz" => "application/x-tgz",
|
|
||||||
".tgz" => "application/x-tgz",
|
|
||||||
".tar" => "application/x-tar",
|
|
||||||
".zip" => "application/zip",
|
|
||||||
".mp3" => "audio/mpeg",
|
|
||||||
".m3u" => "audio/x-mpegurl",
|
|
||||||
".wma" => "audio/x-ms-wma",
|
|
||||||
".wax" => "audio/x-ms-wax",
|
|
||||||
".ogg" => "application/ogg",
|
|
||||||
".wav" => "audio/x-wav",
|
|
||||||
".gif" => "image/gif",
|
|
||||||
".jpg" => "image/jpeg",
|
|
||||||
".jpeg" => "image/jpeg",
|
|
||||||
".png" => "image/png",
|
|
||||||
".xbm" => "image/x-xbitmap",
|
|
||||||
".xpm" => "image/x-xpixmap",
|
|
||||||
".xwd" => "image/x-xwindowdump",
|
|
||||||
".css" => "text/css",
|
|
||||||
".html" => "text/html",
|
|
||||||
".htm" => "text/html",
|
|
||||||
".js" => "text/javascript",
|
|
||||||
".asc" => "text/plain",
|
|
||||||
".c" => "text/plain",
|
|
||||||
".cpp" => "text/plain",
|
|
||||||
".log" => "text/plain",
|
|
||||||
".conf" => "text/plain",
|
|
||||||
".text" => "text/plain",
|
|
||||||
".txt" => "text/plain",
|
|
||||||
".dtd" => "text/xml",
|
|
||||||
".xml" => "text/xml",
|
|
||||||
".mpeg" => "video/mpeg",
|
|
||||||
".mpg" => "video/mpeg",
|
|
||||||
".mov" => "video/quicktime",
|
|
||||||
".qt" => "video/quicktime",
|
|
||||||
".avi" => "video/x-msvideo",
|
|
||||||
".asf" => "video/x-ms-asf",
|
|
||||||
".asx" => "video/x-ms-asf",
|
|
||||||
".wmv" => "video/x-ms-wmv",
|
|
||||||
".bz2" => "application/x-bzip",
|
|
||||||
".tbz" => "application/x-bzip-compressed-tar",
|
|
||||||
".tar.bz2" => "application/x-bzip-compressed-tar",
|
|
||||||
"" => "text/plain"
|
|
||||||
)
|
|
||||||
EOF
|
|
||||||
test x"$local" = xtrue && echo 'server.bind = "127.0.0.1"' >> "$conf"
|
|
||||||
}
|
|
||||||
|
|
||||||
apache2_conf () {
|
|
||||||
if test -z "$module_path"
|
|
||||||
then
|
|
||||||
test -d "/usr/lib/httpd/modules" &&
|
|
||||||
module_path="/usr/lib/httpd/modules"
|
|
||||||
test -d "/usr/lib/apache2/modules" &&
|
|
||||||
module_path="/usr/lib/apache2/modules"
|
|
||||||
fi
|
|
||||||
bind=
|
|
||||||
test x"$local" = xtrue && bind='127.0.0.1:'
|
|
||||||
echo 'text/css css' > "$fqgitdir/mime.types"
|
|
||||||
cat > "$conf" <<EOF
|
|
||||||
ServerName "git-instaweb"
|
|
||||||
ServerRoot "$root"
|
|
||||||
DocumentRoot "$root"
|
|
||||||
ErrorLog "$fqgitdir/gitweb/$httpd_only/error.log"
|
|
||||||
CustomLog "$fqgitdir/gitweb/$httpd_only/access.log" combined
|
|
||||||
PidFile "$fqgitdir/pid"
|
|
||||||
Listen $bind$port
|
|
||||||
EOF
|
|
||||||
|
|
||||||
for mod in mime dir env log_config
|
|
||||||
do
|
|
||||||
if test -e $module_path/mod_${mod}.so
|
|
||||||
then
|
|
||||||
echo "LoadModule ${mod}_module " \
|
|
||||||
"$module_path/mod_${mod}.so" >> "$conf"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
cat >> "$conf" <<EOF
|
|
||||||
TypesConfig "$fqgitdir/mime.types"
|
|
||||||
DirectoryIndex gitweb.cgi
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# check to see if Dennis Stosberg's mod_perl compatibility patch
|
|
||||||
# (<20060621130708.Gcbc6e5c@leonov.stosberg.net>) has been applied
|
|
||||||
if test -f "$module_path/mod_perl.so" &&
|
|
||||||
sane_grep 'MOD_PERL' "$root/gitweb.cgi" >/dev/null
|
|
||||||
then
|
|
||||||
# favor mod_perl if available
|
|
||||||
cat >> "$conf" <<EOF
|
|
||||||
LoadModule perl_module $module_path/mod_perl.so
|
|
||||||
PerlPassEnv GIT_DIR
|
|
||||||
PerlPassEnv GIT_EXEC_PATH
|
|
||||||
PerlPassEnv GITWEB_CONFIG
|
|
||||||
<Location /gitweb.cgi>
|
|
||||||
SetHandler perl-script
|
|
||||||
PerlResponseHandler ModPerl::Registry
|
|
||||||
PerlOptions +ParseHeaders
|
|
||||||
Options +ExecCGI
|
|
||||||
</Location>
|
|
||||||
EOF
|
|
||||||
else
|
|
||||||
# plain-old CGI
|
|
||||||
resolve_full_httpd
|
|
||||||
list_mods=$(echo "$full_httpd" | sed 's/-f$/-l/')
|
|
||||||
$list_mods | sane_grep 'mod_cgi\.c' >/dev/null 2>&1 || \
|
|
||||||
if test -f "$module_path/mod_cgi.so"
|
|
||||||
then
|
|
||||||
echo "LoadModule cgi_module $module_path/mod_cgi.so" >> "$conf"
|
|
||||||
else
|
|
||||||
$list_mods | grep 'mod_cgid\.c' >/dev/null 2>&1 || \
|
|
||||||
if test -f "$module_path/mod_cgid.so"
|
|
||||||
then
|
|
||||||
echo "LoadModule cgid_module $module_path/mod_cgid.so" \
|
|
||||||
>> "$conf"
|
|
||||||
else
|
|
||||||
echo "You have no CGI support!"
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
echo "ScriptSock logs/gitweb.sock" >> "$conf"
|
|
||||||
fi
|
|
||||||
cat >> "$conf" <<EOF
|
|
||||||
PassEnv GIT_DIR
|
|
||||||
PassEnv GIT_EXEC_PATH
|
|
||||||
PassEnv GITWEB_CONFIG
|
|
||||||
AddHandler cgi-script .cgi
|
|
||||||
<Location /gitweb.cgi>
|
|
||||||
Options +ExecCGI
|
|
||||||
</Location>
|
|
||||||
EOF
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
mongoose_conf() {
|
|
||||||
cat > "$conf" <<EOF
|
|
||||||
# Mongoose web server configuration file.
|
|
||||||
# Lines starting with '#' and empty lines are ignored.
|
|
||||||
# For detailed description of every option, visit
|
|
||||||
# http://code.google.com/p/mongoose/wiki/MongooseManual
|
|
||||||
|
|
||||||
root $root
|
|
||||||
ports $port
|
|
||||||
index_files gitweb.cgi
|
|
||||||
#ssl_cert $fqgitdir/gitweb/ssl_cert.pem
|
|
||||||
error_log $fqgitdir/gitweb/$httpd_only/error.log
|
|
||||||
access_log $fqgitdir/gitweb/$httpd_only/access.log
|
|
||||||
|
|
||||||
#cgi setup
|
|
||||||
cgi_env PATH=$PATH,GIT_DIR=$GIT_DIR,GIT_EXEC_PATH=$GIT_EXEC_PATH,GITWEB_CONFIG=$GITWEB_CONFIG
|
|
||||||
cgi_interp $PERL
|
|
||||||
cgi_ext cgi,pl
|
|
||||||
|
|
||||||
# mimetype mapping
|
|
||||||
mime_types .gz=application/x-gzip,.tar.gz=application/x-tgz,.tgz=application/x-tgz,.tar=application/x-tar,.zip=application/zip,.gif=image/gif,.jpg=image/jpeg,.jpeg=image/jpeg,.png=image/png,.css=text/css,.html=text/html,.htm=text/html,.js=text/javascript,.c=text/plain,.cpp=text/plain,.log=text/plain,.conf=text/plain,.text=text/plain,.txt=text/plain,.dtd=text/xml,.bz2=application/x-bzip,.tbz=application/x-bzip-compressed-tar,.tar.bz2=application/x-bzip-compressed-tar
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
plackup_conf () {
|
|
||||||
# generate a standalone 'plackup' server script in $fqgitdir/gitweb
|
|
||||||
# with embedded configuration; it does not use "$conf" file
|
|
||||||
cat > "$fqgitdir/gitweb/gitweb.psgi" <<EOF
|
|
||||||
#!$PERL
|
|
||||||
|
|
||||||
# gitweb - simple web interface to track changes in git repositories
|
|
||||||
# PSGI wrapper and server starter (see http://plackperl.org)
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
use IO::Handle;
|
|
||||||
use Plack::MIME;
|
|
||||||
use Plack::Builder;
|
|
||||||
use Plack::App::WrapCGI;
|
|
||||||
use CGI::Emulate::PSGI 0.07; # minimum version required to work with gitweb
|
|
||||||
|
|
||||||
# mimetype mapping (from lighttpd_conf)
|
|
||||||
Plack::MIME->add_type(
|
|
||||||
".pdf" => "application/pdf",
|
|
||||||
".sig" => "application/pgp-signature",
|
|
||||||
".spl" => "application/futuresplash",
|
|
||||||
".class" => "application/octet-stream",
|
|
||||||
".ps" => "application/postscript",
|
|
||||||
".torrent" => "application/x-bittorrent",
|
|
||||||
".dvi" => "application/x-dvi",
|
|
||||||
".gz" => "application/x-gzip",
|
|
||||||
".pac" => "application/x-ns-proxy-autoconfig",
|
|
||||||
".swf" => "application/x-shockwave-flash",
|
|
||||||
".tar.gz" => "application/x-tgz",
|
|
||||||
".tgz" => "application/x-tgz",
|
|
||||||
".tar" => "application/x-tar",
|
|
||||||
".zip" => "application/zip",
|
|
||||||
".mp3" => "audio/mpeg",
|
|
||||||
".m3u" => "audio/x-mpegurl",
|
|
||||||
".wma" => "audio/x-ms-wma",
|
|
||||||
".wax" => "audio/x-ms-wax",
|
|
||||||
".ogg" => "application/ogg",
|
|
||||||
".wav" => "audio/x-wav",
|
|
||||||
".gif" => "image/gif",
|
|
||||||
".jpg" => "image/jpeg",
|
|
||||||
".jpeg" => "image/jpeg",
|
|
||||||
".png" => "image/png",
|
|
||||||
".xbm" => "image/x-xbitmap",
|
|
||||||
".xpm" => "image/x-xpixmap",
|
|
||||||
".xwd" => "image/x-xwindowdump",
|
|
||||||
".css" => "text/css",
|
|
||||||
".html" => "text/html",
|
|
||||||
".htm" => "text/html",
|
|
||||||
".js" => "text/javascript",
|
|
||||||
".asc" => "text/plain",
|
|
||||||
".c" => "text/plain",
|
|
||||||
".cpp" => "text/plain",
|
|
||||||
".log" => "text/plain",
|
|
||||||
".conf" => "text/plain",
|
|
||||||
".text" => "text/plain",
|
|
||||||
".txt" => "text/plain",
|
|
||||||
".dtd" => "text/xml",
|
|
||||||
".xml" => "text/xml",
|
|
||||||
".mpeg" => "video/mpeg",
|
|
||||||
".mpg" => "video/mpeg",
|
|
||||||
".mov" => "video/quicktime",
|
|
||||||
".qt" => "video/quicktime",
|
|
||||||
".avi" => "video/x-msvideo",
|
|
||||||
".asf" => "video/x-ms-asf",
|
|
||||||
".asx" => "video/x-ms-asf",
|
|
||||||
".wmv" => "video/x-ms-wmv",
|
|
||||||
".bz2" => "application/x-bzip",
|
|
||||||
".tbz" => "application/x-bzip-compressed-tar",
|
|
||||||
".tar.bz2" => "application/x-bzip-compressed-tar",
|
|
||||||
"" => "text/plain"
|
|
||||||
);
|
|
||||||
|
|
||||||
my \$app = builder {
|
|
||||||
# to be able to override \$SIG{__WARN__} to log build time warnings
|
|
||||||
use CGI::Carp; # it sets \$SIG{__WARN__} itself
|
|
||||||
|
|
||||||
my \$logdir = "$fqgitdir/gitweb/$httpd_only";
|
|
||||||
open my \$access_log_fh, '>>', "\$logdir/access.log"
|
|
||||||
or die "Couldn't open access log '\$logdir/access.log': \$!";
|
|
||||||
open my \$error_log_fh, '>>', "\$logdir/error.log"
|
|
||||||
or die "Couldn't open error log '\$logdir/error.log': \$!";
|
|
||||||
|
|
||||||
\$access_log_fh->autoflush(1);
|
|
||||||
\$error_log_fh->autoflush(1);
|
|
||||||
|
|
||||||
# redirect build time warnings to error.log
|
|
||||||
\$SIG{'__WARN__'} = sub {
|
|
||||||
my \$msg = shift;
|
|
||||||
# timestamp warning like in CGI::Carp::warn
|
|
||||||
my \$stamp = CGI::Carp::stamp();
|
|
||||||
\$msg =~ s/^/\$stamp/gm;
|
|
||||||
print \$error_log_fh \$msg;
|
|
||||||
};
|
|
||||||
|
|
||||||
# write errors to error.log, access to access.log
|
|
||||||
enable 'AccessLog',
|
|
||||||
format => "combined",
|
|
||||||
logger => sub { print \$access_log_fh @_; };
|
|
||||||
enable sub {
|
|
||||||
my \$app = shift;
|
|
||||||
sub {
|
|
||||||
my \$env = shift;
|
|
||||||
\$env->{'psgi.errors'} = \$error_log_fh;
|
|
||||||
\$app->(\$env);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
# gitweb currently doesn't work with $SIG{CHLD} set to 'IGNORE',
|
|
||||||
# because it uses 'close $fd or die...' on piped filehandle $fh
|
|
||||||
# (which causes the parent process to wait for child to finish).
|
|
||||||
enable_if { \$SIG{'CHLD'} eq 'IGNORE' } sub {
|
|
||||||
my \$app = shift;
|
|
||||||
sub {
|
|
||||||
my \$env = shift;
|
|
||||||
local \$SIG{'CHLD'} = 'DEFAULT';
|
|
||||||
local \$SIG{'CLD'} = 'DEFAULT';
|
|
||||||
\$app->(\$env);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
# serve static files, i.e. stylesheet, images, script
|
|
||||||
enable 'Static',
|
|
||||||
path => sub { m!\.(js|css|png)\$! && s!^/gitweb/!! },
|
|
||||||
root => "$root/",
|
|
||||||
encoding => 'utf-8'; # encoding for 'text/plain' files
|
|
||||||
# convert CGI application to PSGI app
|
|
||||||
Plack::App::WrapCGI->new(script => "$root/gitweb.cgi")->to_app;
|
|
||||||
};
|
|
||||||
|
|
||||||
# make it runnable as standalone app,
|
|
||||||
# like it would be run via 'plackup' utility
|
|
||||||
if (caller) {
|
|
||||||
return \$app;
|
|
||||||
} else {
|
|
||||||
require Plack::Runner;
|
|
||||||
|
|
||||||
my \$runner = Plack::Runner->new();
|
|
||||||
\$runner->parse_options(qw(--env deployment --port $port),
|
|
||||||
"$local" ? qw(--host 127.0.0.1) : ());
|
|
||||||
\$runner->run(\$app);
|
|
||||||
}
|
|
||||||
__END__
|
|
||||||
EOF
|
|
||||||
|
|
||||||
chmod a+x "$fqgitdir/gitweb/gitweb.psgi"
|
|
||||||
# configuration is embedded in server script file, gitweb.psgi
|
|
||||||
rm -f "$conf"
|
|
||||||
}
|
|
||||||
|
|
||||||
gitweb_conf() {
|
|
||||||
cat > "$fqgitdir/gitweb/gitweb_config.perl" <<EOF
|
|
||||||
#!/usr/bin/perl
|
|
||||||
our \$projectroot = "$(dirname "$fqgitdir")";
|
|
||||||
our \$git_temp = "$fqgitdir/gitweb/tmp";
|
|
||||||
our \$projects_list = \$projectroot;
|
|
||||||
|
|
||||||
\$feature{'remote_heads'}{'default'} = [1];
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
gitweb_conf
|
|
||||||
|
|
||||||
resolve_full_httpd
|
|
||||||
mkdir -p "$fqgitdir/gitweb/$httpd_only"
|
|
||||||
|
|
||||||
case "$httpd" in
|
|
||||||
*lighttpd*)
|
|
||||||
lighttpd_conf
|
|
||||||
;;
|
|
||||||
*apache2*|*httpd*)
|
|
||||||
apache2_conf
|
|
||||||
;;
|
|
||||||
webrick)
|
|
||||||
webrick_conf
|
|
||||||
;;
|
|
||||||
*mongoose*)
|
|
||||||
mongoose_conf
|
|
||||||
;;
|
|
||||||
*plackup*)
|
|
||||||
plackup_conf
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unknown httpd specified: $httpd"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
start_httpd
|
|
||||||
url=http://127.0.0.1:$port
|
|
||||||
|
|
||||||
if test -n "$browser"; then
|
|
||||||
httpd_is_ready && git web--browse -b "$browser" $url || echo $url
|
|
||||||
else
|
|
||||||
httpd_is_ready && git web--browse -c "instaweb.browser" $url || echo $url
|
|
||||||
fi
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1,33 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
USAGE=''
|
|
||||||
SUBDIRECTORY_OK='Yes'
|
|
||||||
OPTIONS_SPEC=
|
|
||||||
. git-sh-setup
|
|
||||||
|
|
||||||
echo "WARNING: '$0' is deprecated in favor of 'git fsck --lost-found'" >&2
|
|
||||||
|
|
||||||
if [ "$#" != "0" ]
|
|
||||||
then
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
|
|
||||||
laf="$GIT_DIR/lost-found"
|
|
||||||
rm -fr "$laf" && mkdir -p "$laf/commit" "$laf/other" || exit
|
|
||||||
|
|
||||||
git fsck --full --no-reflogs |
|
|
||||||
while read dangling type sha1
|
|
||||||
do
|
|
||||||
case "$dangling" in
|
|
||||||
dangling)
|
|
||||||
if git rev-parse -q --verify "$sha1^0" >/dev/null
|
|
||||||
then
|
|
||||||
dir="$laf/commit"
|
|
||||||
git show-branch "$sha1"
|
|
||||||
else
|
|
||||||
dir="$laf/other"
|
|
||||||
fi
|
|
||||||
echo "$sha1" >"$dir/$sha1"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1,109 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# Copyright (c) 2005 Junio C Hamano
|
|
||||||
#
|
|
||||||
# Resolve two or more trees.
|
|
||||||
#
|
|
||||||
|
|
||||||
LF='
|
|
||||||
'
|
|
||||||
|
|
||||||
die () {
|
|
||||||
echo >&2 "$*"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# The first parameters up to -- are merge bases; the rest are heads.
|
|
||||||
bases= head= remotes= sep_seen=
|
|
||||||
for arg
|
|
||||||
do
|
|
||||||
case ",$sep_seen,$head,$arg," in
|
|
||||||
*,--,)
|
|
||||||
sep_seen=yes
|
|
||||||
;;
|
|
||||||
,yes,,*)
|
|
||||||
head=$arg
|
|
||||||
;;
|
|
||||||
,yes,*)
|
|
||||||
remotes="$remotes$arg "
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
bases="$bases$arg "
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# Reject if this is not an Octopus -- resolve should be used instead.
|
|
||||||
case "$remotes" in
|
|
||||||
?*' '?*)
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
exit 2 ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# MRC is the current "merge reference commit"
|
|
||||||
# MRT is the current "merge result tree"
|
|
||||||
|
|
||||||
MRC=$(git rev-parse --verify -q $head)
|
|
||||||
MRT=$(git write-tree)
|
|
||||||
NON_FF_MERGE=0
|
|
||||||
OCTOPUS_FAILURE=0
|
|
||||||
for SHA1 in $remotes
|
|
||||||
do
|
|
||||||
case "$OCTOPUS_FAILURE" in
|
|
||||||
1)
|
|
||||||
# We allow only last one to have a hand-resolvable
|
|
||||||
# conflicts. Last round failed and we still had
|
|
||||||
# a head to merge.
|
|
||||||
echo "Automated merge did not work."
|
|
||||||
echo "Should not be doing an Octopus."
|
|
||||||
exit 2
|
|
||||||
esac
|
|
||||||
|
|
||||||
eval pretty_name=\${GITHEAD_$SHA1:-$SHA1}
|
|
||||||
if test "$SHA1" = "$pretty_name"
|
|
||||||
then
|
|
||||||
SHA1_UP="$(echo "$SHA1" | tr a-z A-Z)"
|
|
||||||
eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name}
|
|
||||||
fi
|
|
||||||
common=$(git merge-base --all $SHA1 $MRC) ||
|
|
||||||
die "Unable to find common commit with $pretty_name"
|
|
||||||
|
|
||||||
case "$LF$common$LF" in
|
|
||||||
*"$LF$SHA1$LF"*)
|
|
||||||
echo "Already up-to-date with $pretty_name"
|
|
||||||
continue
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if test "$common,$NON_FF_MERGE" = "$MRC,0"
|
|
||||||
then
|
|
||||||
# The first head being merged was a fast-forward.
|
|
||||||
# Advance MRC to the head being merged, and use that
|
|
||||||
# tree as the intermediate result of the merge.
|
|
||||||
# We still need to count this as part of the parent set.
|
|
||||||
|
|
||||||
echo "Fast-forwarding to: $pretty_name"
|
|
||||||
git read-tree -u -m $head $SHA1 || exit
|
|
||||||
MRC=$SHA1 MRT=$(git write-tree)
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
NON_FF_MERGE=1
|
|
||||||
|
|
||||||
echo "Trying simple merge with $pretty_name"
|
|
||||||
git read-tree -u -m --aggressive $common $MRT $SHA1 || exit 2
|
|
||||||
next=$(git write-tree 2>/dev/null)
|
|
||||||
if test $? -ne 0
|
|
||||||
then
|
|
||||||
echo "Simple merge did not work, trying automatic merge."
|
|
||||||
git-merge-index -o git-merge-one-file -a ||
|
|
||||||
OCTOPUS_FAILURE=1
|
|
||||||
next=$(git write-tree 2>/dev/null)
|
|
||||||
fi
|
|
||||||
|
|
||||||
MRC="$MRC $SHA1"
|
|
||||||
MRT=$next
|
|
||||||
done
|
|
||||||
|
|
||||||
exit "$OCTOPUS_FAILURE"
|
|
|
@ -1,165 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# Copyright (c) Linus Torvalds, 2005
|
|
||||||
#
|
|
||||||
# This is the git per-file merge script, called with
|
|
||||||
#
|
|
||||||
# $1 - original file SHA1 (or empty)
|
|
||||||
# $2 - file in branch1 SHA1 (or empty)
|
|
||||||
# $3 - file in branch2 SHA1 (or empty)
|
|
||||||
# $4 - pathname in repository
|
|
||||||
# $5 - original file mode (or empty)
|
|
||||||
# $6 - file in branch1 mode (or empty)
|
|
||||||
# $7 - file in branch2 mode (or empty)
|
|
||||||
#
|
|
||||||
# Handle some trivial cases.. The _really_ trivial cases have
|
|
||||||
# been handled already by git read-tree, but that one doesn't
|
|
||||||
# do any merges that might change the tree layout.
|
|
||||||
|
|
||||||
USAGE='<orig blob> <our blob> <their blob> <path>'
|
|
||||||
USAGE="$USAGE <orig mode> <our mode> <their mode>"
|
|
||||||
LONG_USAGE="Usage: git merge-one-file $USAGE
|
|
||||||
|
|
||||||
Blob ids and modes should be empty for missing files."
|
|
||||||
|
|
||||||
SUBDIRECTORY_OK=Yes
|
|
||||||
. git-sh-setup
|
|
||||||
cd_to_toplevel
|
|
||||||
require_work_tree
|
|
||||||
|
|
||||||
if ! test "$#" -eq 7
|
|
||||||
then
|
|
||||||
echo "$LONG_USAGE"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "${1:-.}${2:-.}${3:-.}" in
|
|
||||||
#
|
|
||||||
# Deleted in both or deleted in one and unchanged in the other
|
|
||||||
#
|
|
||||||
"$1.." | "$1.$1" | "$1$1.")
|
|
||||||
if [ "$2" ]; then
|
|
||||||
echo "Removing $4"
|
|
||||||
else
|
|
||||||
# read-tree checked that index matches HEAD already,
|
|
||||||
# so we know we do not have this path tracked.
|
|
||||||
# there may be an unrelated working tree file here,
|
|
||||||
# which we should just leave unmolested. Make sure
|
|
||||||
# we do not have it in the index, though.
|
|
||||||
exec git update-index --remove -- "$4"
|
|
||||||
fi
|
|
||||||
if test -f "$4"; then
|
|
||||||
rm -f -- "$4" &&
|
|
||||||
rmdir -p "$(expr "z$4" : 'z\(.*\)/')" 2>/dev/null || :
|
|
||||||
fi &&
|
|
||||||
exec git update-index --remove -- "$4"
|
|
||||||
;;
|
|
||||||
|
|
||||||
#
|
|
||||||
# Added in one.
|
|
||||||
#
|
|
||||||
".$2.")
|
|
||||||
# the other side did not add and we added so there is nothing
|
|
||||||
# to be done, except making the path merged.
|
|
||||||
exec git update-index --add --cacheinfo "$6" "$2" "$4"
|
|
||||||
;;
|
|
||||||
"..$3")
|
|
||||||
echo "Adding $4"
|
|
||||||
if test -f "$4"
|
|
||||||
then
|
|
||||||
echo "ERROR: untracked $4 is overwritten by the merge."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
git update-index --add --cacheinfo "$7" "$3" "$4" &&
|
|
||||||
exec git checkout-index -u -f -- "$4"
|
|
||||||
;;
|
|
||||||
|
|
||||||
#
|
|
||||||
# Added in both, identically (check for same permissions).
|
|
||||||
#
|
|
||||||
".$3$2")
|
|
||||||
if [ "$6" != "$7" ]; then
|
|
||||||
echo "ERROR: File $4 added identically in both branches,"
|
|
||||||
echo "ERROR: but permissions conflict $6->$7."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "Adding $4"
|
|
||||||
git update-index --add --cacheinfo "$6" "$2" "$4" &&
|
|
||||||
exec git checkout-index -u -f -- "$4"
|
|
||||||
;;
|
|
||||||
|
|
||||||
#
|
|
||||||
# Modified in both, but differently.
|
|
||||||
#
|
|
||||||
"$1$2$3" | ".$2$3")
|
|
||||||
|
|
||||||
case ",$6,$7," in
|
|
||||||
*,120000,*)
|
|
||||||
echo "ERROR: $4: Not merging symbolic link changes."
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
*,160000,*)
|
|
||||||
echo "ERROR: $4: Not merging conflicting submodule changes."
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
src2=`git-unpack-file $3`
|
|
||||||
case "$1" in
|
|
||||||
'')
|
|
||||||
echo "Added $4 in both, but differently."
|
|
||||||
# This extracts OUR file in $orig, and uses git apply to
|
|
||||||
# remove lines that are unique to ours.
|
|
||||||
orig=`git-unpack-file $2`
|
|
||||||
sz0=`wc -c <"$orig"`
|
|
||||||
diff -u -La/$orig -Lb/$orig $orig $src2 | git apply --no-add
|
|
||||||
sz1=`wc -c <"$orig"`
|
|
||||||
|
|
||||||
# If we do not have enough common material, it is not
|
|
||||||
# worth trying two-file merge using common subsections.
|
|
||||||
expr "$sz0" \< "$sz1" \* 2 >/dev/null || : >$orig
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Auto-merging $4"
|
|
||||||
orig=`git-unpack-file $1`
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Be careful for funny filename such as "-L" in "$4", which
|
|
||||||
# would confuse "merge" greatly.
|
|
||||||
src1=`git-unpack-file $2`
|
|
||||||
git merge-file "$src1" "$orig" "$src2"
|
|
||||||
ret=$?
|
|
||||||
msg=
|
|
||||||
if [ $ret -ne 0 ]; then
|
|
||||||
msg='content conflict'
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create the working tree file, using "our tree" version from the
|
|
||||||
# index, and then store the result of the merge.
|
|
||||||
git checkout-index -f --stage=2 -- "$4" && cat "$src1" >"$4" || exit 1
|
|
||||||
rm -f -- "$orig" "$src1" "$src2"
|
|
||||||
|
|
||||||
if [ "$6" != "$7" ]; then
|
|
||||||
if [ -n "$msg" ]; then
|
|
||||||
msg="$msg, "
|
|
||||||
fi
|
|
||||||
msg="${msg}permissions conflict: $5->$6,$7"
|
|
||||||
ret=1
|
|
||||||
fi
|
|
||||||
if [ "$1" = '' ]; then
|
|
||||||
ret=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $ret -ne 0 ]; then
|
|
||||||
echo "ERROR: $msg in $4"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
exec git update-index -- "$4"
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
echo "ERROR: $4: Not handling case $1 -> $2 -> $3"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
exit 1
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1,54 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# Copyright (c) 2005 Linus Torvalds
|
|
||||||
# Copyright (c) 2005 Junio C Hamano
|
|
||||||
#
|
|
||||||
# Resolve two trees, using enhanced multi-base read-tree.
|
|
||||||
|
|
||||||
# The first parameters up to -- are merge bases; the rest are heads.
|
|
||||||
bases= head= remotes= sep_seen=
|
|
||||||
for arg
|
|
||||||
do
|
|
||||||
case ",$sep_seen,$head,$arg," in
|
|
||||||
*,--,)
|
|
||||||
sep_seen=yes
|
|
||||||
;;
|
|
||||||
,yes,,*)
|
|
||||||
head=$arg
|
|
||||||
;;
|
|
||||||
,yes,*)
|
|
||||||
remotes="$remotes$arg "
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
bases="$bases$arg "
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# Give up if we are given two or more remotes -- not handling octopus.
|
|
||||||
case "$remotes" in
|
|
||||||
?*' '?*)
|
|
||||||
exit 2 ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Give up if this is a baseless merge.
|
|
||||||
if test '' = "$bases"
|
|
||||||
then
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
git update-index -q --refresh
|
|
||||||
git read-tree -u -m --aggressive $bases $head $remotes || exit 2
|
|
||||||
echo "Trying simple merge."
|
|
||||||
if result_tree=$(git write-tree 2>/dev/null)
|
|
||||||
then
|
|
||||||
exit 0
|
|
||||||
else
|
|
||||||
echo "Simple merge failed, trying Automatic merge."
|
|
||||||
if git-merge-index -o git-merge-one-file -a
|
|
||||||
then
|
|
||||||
exit 0
|
|
||||||
else
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1,405 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# This program resolves merge conflicts in git
|
|
||||||
#
|
|
||||||
# Copyright (c) 2006 Theodore Y. Ts'o
|
|
||||||
#
|
|
||||||
# This file is licensed under the GPL v2, or a later version
|
|
||||||
# at the discretion of Junio C Hamano.
|
|
||||||
#
|
|
||||||
|
|
||||||
USAGE='[--tool=tool] [-y|--no-prompt|--prompt] [file to merge] ...'
|
|
||||||
SUBDIRECTORY_OK=Yes
|
|
||||||
OPTIONS_SPEC=
|
|
||||||
TOOL_MODE=merge
|
|
||||||
. git-sh-setup
|
|
||||||
. git-mergetool--lib
|
|
||||||
require_work_tree
|
|
||||||
|
|
||||||
# Returns true if the mode reflects a symlink
|
|
||||||
is_symlink () {
|
|
||||||
test "$1" = 120000
|
|
||||||
}
|
|
||||||
|
|
||||||
is_submodule () {
|
|
||||||
test "$1" = 160000
|
|
||||||
}
|
|
||||||
|
|
||||||
local_present () {
|
|
||||||
test -n "$local_mode"
|
|
||||||
}
|
|
||||||
|
|
||||||
remote_present () {
|
|
||||||
test -n "$remote_mode"
|
|
||||||
}
|
|
||||||
|
|
||||||
base_present () {
|
|
||||||
test -n "$base_mode"
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup_temp_files () {
|
|
||||||
if test "$1" = --save-backup ; then
|
|
||||||
rm -rf -- "$MERGED.orig"
|
|
||||||
test -e "$BACKUP" && mv -- "$BACKUP" "$MERGED.orig"
|
|
||||||
rm -f -- "$LOCAL" "$REMOTE" "$BASE"
|
|
||||||
else
|
|
||||||
rm -f -- "$LOCAL" "$REMOTE" "$BASE" "$BACKUP"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
describe_file () {
|
|
||||||
mode="$1"
|
|
||||||
branch="$2"
|
|
||||||
file="$3"
|
|
||||||
|
|
||||||
printf " {%s}: " "$branch"
|
|
||||||
if test -z "$mode"; then
|
|
||||||
echo "deleted"
|
|
||||||
elif is_symlink "$mode" ; then
|
|
||||||
echo "a symbolic link -> '$(cat "$file")'"
|
|
||||||
elif is_submodule "$mode" ; then
|
|
||||||
echo "submodule commit $file"
|
|
||||||
else
|
|
||||||
if base_present; then
|
|
||||||
echo "modified file"
|
|
||||||
else
|
|
||||||
echo "created file"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
resolve_symlink_merge () {
|
|
||||||
while true; do
|
|
||||||
printf "Use (l)ocal or (r)emote, or (a)bort? "
|
|
||||||
read ans
|
|
||||||
case "$ans" in
|
|
||||||
[lL]*)
|
|
||||||
git checkout-index -f --stage=2 -- "$MERGED"
|
|
||||||
git add -- "$MERGED"
|
|
||||||
cleanup_temp_files --save-backup
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
[rR]*)
|
|
||||||
git checkout-index -f --stage=3 -- "$MERGED"
|
|
||||||
git add -- "$MERGED"
|
|
||||||
cleanup_temp_files --save-backup
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
[aA]*)
|
|
||||||
return 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve_deleted_merge () {
|
|
||||||
while true; do
|
|
||||||
if base_present; then
|
|
||||||
printf "Use (m)odified or (d)eleted file, or (a)bort? "
|
|
||||||
else
|
|
||||||
printf "Use (c)reated or (d)eleted file, or (a)bort? "
|
|
||||||
fi
|
|
||||||
read ans
|
|
||||||
case "$ans" in
|
|
||||||
[mMcC]*)
|
|
||||||
git add -- "$MERGED"
|
|
||||||
cleanup_temp_files --save-backup
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
[dD]*)
|
|
||||||
git rm -- "$MERGED" > /dev/null
|
|
||||||
cleanup_temp_files
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
[aA]*)
|
|
||||||
return 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve_submodule_merge () {
|
|
||||||
while true; do
|
|
||||||
printf "Use (l)ocal or (r)emote, or (a)bort? "
|
|
||||||
read ans
|
|
||||||
case "$ans" in
|
|
||||||
[lL]*)
|
|
||||||
if ! local_present; then
|
|
||||||
if test -n "$(git ls-tree HEAD -- "$MERGED")"; then
|
|
||||||
# Local isn't present, but it's a subdirectory
|
|
||||||
git ls-tree --full-name -r HEAD -- "$MERGED" | git update-index --index-info || exit $?
|
|
||||||
else
|
|
||||||
test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
|
|
||||||
git update-index --force-remove "$MERGED"
|
|
||||||
cleanup_temp_files --save-backup
|
|
||||||
fi
|
|
||||||
elif is_submodule "$local_mode"; then
|
|
||||||
stage_submodule "$MERGED" "$local_sha1"
|
|
||||||
else
|
|
||||||
git checkout-index -f --stage=2 -- "$MERGED"
|
|
||||||
git add -- "$MERGED"
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
[rR]*)
|
|
||||||
if ! remote_present; then
|
|
||||||
if test -n "$(git ls-tree MERGE_HEAD -- "$MERGED")"; then
|
|
||||||
# Remote isn't present, but it's a subdirectory
|
|
||||||
git ls-tree --full-name -r MERGE_HEAD -- "$MERGED" | git update-index --index-info || exit $?
|
|
||||||
else
|
|
||||||
test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
|
|
||||||
git update-index --force-remove "$MERGED"
|
|
||||||
fi
|
|
||||||
elif is_submodule "$remote_mode"; then
|
|
||||||
! is_submodule "$local_mode" && test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
|
|
||||||
stage_submodule "$MERGED" "$remote_sha1"
|
|
||||||
else
|
|
||||||
test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
|
|
||||||
git checkout-index -f --stage=3 -- "$MERGED"
|
|
||||||
git add -- "$MERGED"
|
|
||||||
fi
|
|
||||||
cleanup_temp_files --save-backup
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
[aA]*)
|
|
||||||
return 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
stage_submodule () {
|
|
||||||
path="$1"
|
|
||||||
submodule_sha1="$2"
|
|
||||||
mkdir -p "$path" || die "fatal: unable to create directory for module at $path"
|
|
||||||
# Find $path relative to work tree
|
|
||||||
work_tree_root=$(cd_to_toplevel && pwd)
|
|
||||||
work_rel_path=$(cd "$path" && GIT_WORK_TREE="${work_tree_root}" git rev-parse --show-prefix)
|
|
||||||
test -n "$work_rel_path" || die "fatal: unable to get path of module $path relative to work tree"
|
|
||||||
git update-index --add --replace --cacheinfo 160000 "$submodule_sha1" "${work_rel_path%/}" || die
|
|
||||||
}
|
|
||||||
|
|
||||||
checkout_staged_file () {
|
|
||||||
tmpfile=$(expr "$(git checkout-index --temp --stage="$1" "$2")" : '\([^ ]*\) ')
|
|
||||||
|
|
||||||
if test $? -eq 0 -a -n "$tmpfile" ; then
|
|
||||||
mv -- "$(git rev-parse --show-cdup)$tmpfile" "$3"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
merge_file () {
|
|
||||||
MERGED="$1"
|
|
||||||
|
|
||||||
f=$(git ls-files -u -- "$MERGED")
|
|
||||||
if test -z "$f" ; then
|
|
||||||
if test ! -f "$MERGED" ; then
|
|
||||||
echo "$MERGED: file not found"
|
|
||||||
else
|
|
||||||
echo "$MERGED: file does not need merging"
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
ext="$$$(expr "$MERGED" : '.*\(\.[^/]*\)$')"
|
|
||||||
BACKUP="./$MERGED.BACKUP.$ext"
|
|
||||||
LOCAL="./$MERGED.LOCAL.$ext"
|
|
||||||
REMOTE="./$MERGED.REMOTE.$ext"
|
|
||||||
BASE="./$MERGED.BASE.$ext"
|
|
||||||
|
|
||||||
base_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}')
|
|
||||||
local_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}')
|
|
||||||
remote_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}')
|
|
||||||
|
|
||||||
if is_submodule "$local_mode" || is_submodule "$remote_mode"; then
|
|
||||||
echo "Submodule merge conflict for '$MERGED':"
|
|
||||||
local_sha1=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $2;}')
|
|
||||||
remote_sha1=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $2;}')
|
|
||||||
describe_file "$local_mode" "local" "$local_sha1"
|
|
||||||
describe_file "$remote_mode" "remote" "$remote_sha1"
|
|
||||||
resolve_submodule_merge
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
mv -- "$MERGED" "$BACKUP"
|
|
||||||
cp -- "$BACKUP" "$MERGED"
|
|
||||||
|
|
||||||
base_present && checkout_staged_file 1 "$MERGED" "$BASE"
|
|
||||||
local_present && checkout_staged_file 2 "$MERGED" "$LOCAL"
|
|
||||||
remote_present && checkout_staged_file 3 "$MERGED" "$REMOTE"
|
|
||||||
|
|
||||||
if test -z "$local_mode" -o -z "$remote_mode"; then
|
|
||||||
echo "Deleted merge conflict for '$MERGED':"
|
|
||||||
describe_file "$local_mode" "local" "$LOCAL"
|
|
||||||
describe_file "$remote_mode" "remote" "$REMOTE"
|
|
||||||
resolve_deleted_merge
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
if is_symlink "$local_mode" || is_symlink "$remote_mode"; then
|
|
||||||
echo "Symbolic link merge conflict for '$MERGED':"
|
|
||||||
describe_file "$local_mode" "local" "$LOCAL"
|
|
||||||
describe_file "$remote_mode" "remote" "$REMOTE"
|
|
||||||
resolve_symlink_merge
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Normal merge conflict for '$MERGED':"
|
|
||||||
describe_file "$local_mode" "local" "$LOCAL"
|
|
||||||
describe_file "$remote_mode" "remote" "$REMOTE"
|
|
||||||
if "$prompt" = true; then
|
|
||||||
printf "Hit return to start merge resolution tool (%s): " "$merge_tool"
|
|
||||||
read ans
|
|
||||||
fi
|
|
||||||
|
|
||||||
if base_present; then
|
|
||||||
present=true
|
|
||||||
else
|
|
||||||
present=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! run_merge_tool "$merge_tool" "$present"; then
|
|
||||||
echo "merge of $MERGED failed" 1>&2
|
|
||||||
mv -- "$BACKUP" "$MERGED"
|
|
||||||
|
|
||||||
if test "$merge_keep_temporaries" = "false"; then
|
|
||||||
cleanup_temp_files
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$merge_keep_backup" = "true"; then
|
|
||||||
mv -- "$BACKUP" "$MERGED.orig"
|
|
||||||
else
|
|
||||||
rm -- "$BACKUP"
|
|
||||||
fi
|
|
||||||
|
|
||||||
git add -- "$MERGED"
|
|
||||||
cleanup_temp_files
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
prompt=$(git config --bool mergetool.prompt || echo true)
|
|
||||||
|
|
||||||
while test $# != 0
|
|
||||||
do
|
|
||||||
case "$1" in
|
|
||||||
-t|--tool*)
|
|
||||||
case "$#,$1" in
|
|
||||||
*,*=*)
|
|
||||||
merge_tool=$(expr "z$1" : 'z-[^=]*=\(.*\)')
|
|
||||||
;;
|
|
||||||
1,*)
|
|
||||||
usage ;;
|
|
||||||
*)
|
|
||||||
merge_tool="$2"
|
|
||||||
shift ;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
-y|--no-prompt)
|
|
||||||
prompt=false
|
|
||||||
;;
|
|
||||||
--prompt)
|
|
||||||
prompt=true
|
|
||||||
;;
|
|
||||||
--)
|
|
||||||
shift
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
-*)
|
|
||||||
usage
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
prompt_after_failed_merge() {
|
|
||||||
while true; do
|
|
||||||
printf "Continue merging other unresolved paths (y/n) ? "
|
|
||||||
read ans
|
|
||||||
case "$ans" in
|
|
||||||
|
|
||||||
[yY]*)
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
|
|
||||||
[nN]*)
|
|
||||||
return 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
if test -z "$merge_tool"; then
|
|
||||||
merge_tool=$(get_merge_tool "$merge_tool") || exit
|
|
||||||
fi
|
|
||||||
merge_keep_backup="$(git config --bool mergetool.keepBackup || echo true)"
|
|
||||||
merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)"
|
|
||||||
|
|
||||||
last_status=0
|
|
||||||
rollup_status=0
|
|
||||||
rerere=false
|
|
||||||
|
|
||||||
files_to_merge() {
|
|
||||||
if test "$rerere" = true
|
|
||||||
then
|
|
||||||
git rerere remaining
|
|
||||||
else
|
|
||||||
git ls-files -u | sed -e 's/^[^ ]* //' | sort -u
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if test $# -eq 0 ; then
|
|
||||||
cd_to_toplevel
|
|
||||||
|
|
||||||
if test -e "$GIT_DIR/MERGE_RR"
|
|
||||||
then
|
|
||||||
rerere=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
files=$(files_to_merge)
|
|
||||||
if test -z "$files" ; then
|
|
||||||
echo "No files need merging"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Save original stdin
|
|
||||||
exec 3<&0
|
|
||||||
|
|
||||||
printf "Merging:\n"
|
|
||||||
printf "$files\n"
|
|
||||||
|
|
||||||
files_to_merge |
|
|
||||||
while IFS= read i
|
|
||||||
do
|
|
||||||
if test $last_status -ne 0; then
|
|
||||||
prompt_after_failed_merge <&3 || exit 1
|
|
||||||
fi
|
|
||||||
printf "\n"
|
|
||||||
merge_file "$i" <&3
|
|
||||||
last_status=$?
|
|
||||||
if test $last_status -ne 0; then
|
|
||||||
rollup_status=1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
else
|
|
||||||
while test $# -gt 0; do
|
|
||||||
if test $last_status -ne 0; then
|
|
||||||
prompt_after_failed_merge || exit 1
|
|
||||||
fi
|
|
||||||
printf "\n"
|
|
||||||
merge_file "$1"
|
|
||||||
last_status=$?
|
|
||||||
if test $last_status -ne 0; then
|
|
||||||
rollup_status=1
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit $rollup_status
|
|
|
@ -1,439 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
# git-mergetool--lib is a library for common merge tool functions
|
|
||||||
diff_mode() {
|
|
||||||
test "$TOOL_MODE" = diff
|
|
||||||
}
|
|
||||||
|
|
||||||
merge_mode() {
|
|
||||||
test "$TOOL_MODE" = merge
|
|
||||||
}
|
|
||||||
|
|
||||||
translate_merge_tool_path () {
|
|
||||||
case "$1" in
|
|
||||||
araxis)
|
|
||||||
echo compare
|
|
||||||
;;
|
|
||||||
bc3)
|
|
||||||
echo bcompare
|
|
||||||
;;
|
|
||||||
emerge)
|
|
||||||
echo emacs
|
|
||||||
;;
|
|
||||||
gvimdiff|gvimdiff2)
|
|
||||||
echo gvim
|
|
||||||
;;
|
|
||||||
vimdiff|vimdiff2)
|
|
||||||
echo vim
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "$1"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
check_unchanged () {
|
|
||||||
if test "$MERGED" -nt "$BACKUP"; then
|
|
||||||
status=0
|
|
||||||
else
|
|
||||||
while true; do
|
|
||||||
echo "$MERGED seems unchanged."
|
|
||||||
printf "Was the merge successful? [y/n] "
|
|
||||||
read answer
|
|
||||||
case "$answer" in
|
|
||||||
y*|Y*) status=0; break ;;
|
|
||||||
n*|N*) status=1; break ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
valid_tool () {
|
|
||||||
case "$1" in
|
|
||||||
araxis | bc3 | diffuse | ecmerge | emerge | gvimdiff | gvimdiff2 | \
|
|
||||||
kdiff3 | meld | opendiff | p4merge | tkdiff | vimdiff | vimdiff2 | xxdiff)
|
|
||||||
;; # happy
|
|
||||||
kompare)
|
|
||||||
if ! diff_mode; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
tortoisemerge)
|
|
||||||
if ! merge_mode; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
if test -z "$(get_merge_tool_cmd "$1")"; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
get_merge_tool_cmd () {
|
|
||||||
# Prints the custom command for a merge tool
|
|
||||||
if test -n "$1"; then
|
|
||||||
merge_tool="$1"
|
|
||||||
else
|
|
||||||
merge_tool="$(get_merge_tool)"
|
|
||||||
fi
|
|
||||||
if diff_mode; then
|
|
||||||
echo "$(git config difftool.$merge_tool.cmd ||
|
|
||||||
git config mergetool.$merge_tool.cmd)"
|
|
||||||
else
|
|
||||||
echo "$(git config mergetool.$merge_tool.cmd)"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
run_merge_tool () {
|
|
||||||
merge_tool_path="$(get_merge_tool_path "$1")" || exit
|
|
||||||
base_present="$2"
|
|
||||||
status=0
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
araxis)
|
|
||||||
if merge_mode; then
|
|
||||||
touch "$BACKUP"
|
|
||||||
if $base_present; then
|
|
||||||
"$merge_tool_path" -wait -merge -3 -a1 \
|
|
||||||
"$BASE" "$LOCAL" "$REMOTE" "$MERGED" \
|
|
||||||
>/dev/null 2>&1
|
|
||||||
else
|
|
||||||
"$merge_tool_path" -wait -2 \
|
|
||||||
"$LOCAL" "$REMOTE" "$MERGED" \
|
|
||||||
>/dev/null 2>&1
|
|
||||||
fi
|
|
||||||
check_unchanged
|
|
||||||
else
|
|
||||||
"$merge_tool_path" -wait -2 "$LOCAL" "$REMOTE" \
|
|
||||||
>/dev/null 2>&1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
bc3)
|
|
||||||
if merge_mode; then
|
|
||||||
touch "$BACKUP"
|
|
||||||
if $base_present; then
|
|
||||||
"$merge_tool_path" "$LOCAL" "$REMOTE" "$BASE" \
|
|
||||||
-mergeoutput="$MERGED"
|
|
||||||
else
|
|
||||||
"$merge_tool_path" "$LOCAL" "$REMOTE" \
|
|
||||||
-mergeoutput="$MERGED"
|
|
||||||
fi
|
|
||||||
check_unchanged
|
|
||||||
else
|
|
||||||
"$merge_tool_path" "$LOCAL" "$REMOTE"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
diffuse)
|
|
||||||
if merge_mode; then
|
|
||||||
touch "$BACKUP"
|
|
||||||
if $base_present; then
|
|
||||||
"$merge_tool_path" \
|
|
||||||
"$LOCAL" "$MERGED" "$REMOTE" \
|
|
||||||
"$BASE" | cat
|
|
||||||
else
|
|
||||||
"$merge_tool_path" \
|
|
||||||
"$LOCAL" "$MERGED" "$REMOTE" | cat
|
|
||||||
fi
|
|
||||||
check_unchanged
|
|
||||||
else
|
|
||||||
"$merge_tool_path" "$LOCAL" "$REMOTE" | cat
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
ecmerge)
|
|
||||||
if merge_mode; then
|
|
||||||
touch "$BACKUP"
|
|
||||||
if $base_present; then
|
|
||||||
"$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" \
|
|
||||||
--default --mode=merge3 --to="$MERGED"
|
|
||||||
else
|
|
||||||
"$merge_tool_path" "$LOCAL" "$REMOTE" \
|
|
||||||
--default --mode=merge2 --to="$MERGED"
|
|
||||||
fi
|
|
||||||
check_unchanged
|
|
||||||
else
|
|
||||||
"$merge_tool_path" --default --mode=diff2 \
|
|
||||||
"$LOCAL" "$REMOTE"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
emerge)
|
|
||||||
if merge_mode; then
|
|
||||||
if $base_present; then
|
|
||||||
"$merge_tool_path" \
|
|
||||||
-f emerge-files-with-ancestor-command \
|
|
||||||
"$LOCAL" "$REMOTE" "$BASE" \
|
|
||||||
"$(basename "$MERGED")"
|
|
||||||
else
|
|
||||||
"$merge_tool_path" \
|
|
||||||
-f emerge-files-command \
|
|
||||||
"$LOCAL" "$REMOTE" \
|
|
||||||
"$(basename "$MERGED")"
|
|
||||||
fi
|
|
||||||
status=$?
|
|
||||||
else
|
|
||||||
"$merge_tool_path" -f emerge-files-command \
|
|
||||||
"$LOCAL" "$REMOTE"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
gvimdiff|vimdiff)
|
|
||||||
if merge_mode; then
|
|
||||||
touch "$BACKUP"
|
|
||||||
if $base_present; then
|
|
||||||
"$merge_tool_path" -f -d -c "wincmd J" \
|
|
||||||
"$MERGED" "$LOCAL" "$BASE" "$REMOTE"
|
|
||||||
else
|
|
||||||
"$merge_tool_path" -f -d -c "wincmd l" \
|
|
||||||
"$LOCAL" "$MERGED" "$REMOTE"
|
|
||||||
fi
|
|
||||||
check_unchanged
|
|
||||||
else
|
|
||||||
"$merge_tool_path" -R -f -d -c "wincmd l" \
|
|
||||||
"$LOCAL" "$REMOTE"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
gvimdiff2|vimdiff2)
|
|
||||||
if merge_mode; then
|
|
||||||
touch "$BACKUP"
|
|
||||||
"$merge_tool_path" -f -d -c "wincmd l" \
|
|
||||||
"$LOCAL" "$MERGED" "$REMOTE"
|
|
||||||
check_unchanged
|
|
||||||
else
|
|
||||||
"$merge_tool_path" -R -f -d -c "wincmd l" \
|
|
||||||
"$LOCAL" "$REMOTE"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
kdiff3)
|
|
||||||
if merge_mode; then
|
|
||||||
if $base_present; then
|
|
||||||
("$merge_tool_path" --auto \
|
|
||||||
--L1 "$MERGED (Base)" \
|
|
||||||
--L2 "$MERGED (Local)" \
|
|
||||||
--L3 "$MERGED (Remote)" \
|
|
||||||
-o "$MERGED" \
|
|
||||||
"$BASE" "$LOCAL" "$REMOTE" \
|
|
||||||
> /dev/null 2>&1)
|
|
||||||
else
|
|
||||||
("$merge_tool_path" --auto \
|
|
||||||
--L1 "$MERGED (Local)" \
|
|
||||||
--L2 "$MERGED (Remote)" \
|
|
||||||
-o "$MERGED" \
|
|
||||||
"$LOCAL" "$REMOTE" \
|
|
||||||
> /dev/null 2>&1)
|
|
||||||
fi
|
|
||||||
status=$?
|
|
||||||
else
|
|
||||||
("$merge_tool_path" --auto \
|
|
||||||
--L1 "$MERGED (A)" \
|
|
||||||
--L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \
|
|
||||||
> /dev/null 2>&1)
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
kompare)
|
|
||||||
"$merge_tool_path" "$LOCAL" "$REMOTE"
|
|
||||||
;;
|
|
||||||
meld)
|
|
||||||
if merge_mode; then
|
|
||||||
touch "$BACKUP"
|
|
||||||
"$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"
|
|
||||||
check_unchanged
|
|
||||||
else
|
|
||||||
"$merge_tool_path" "$LOCAL" "$REMOTE"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
opendiff)
|
|
||||||
if merge_mode; then
|
|
||||||
touch "$BACKUP"
|
|
||||||
if $base_present; then
|
|
||||||
"$merge_tool_path" "$LOCAL" "$REMOTE" \
|
|
||||||
-ancestor "$BASE" \
|
|
||||||
-merge "$MERGED" | cat
|
|
||||||
else
|
|
||||||
"$merge_tool_path" "$LOCAL" "$REMOTE" \
|
|
||||||
-merge "$MERGED" | cat
|
|
||||||
fi
|
|
||||||
check_unchanged
|
|
||||||
else
|
|
||||||
"$merge_tool_path" "$LOCAL" "$REMOTE" | cat
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
p4merge)
|
|
||||||
if merge_mode; then
|
|
||||||
touch "$BACKUP"
|
|
||||||
$base_present || >"$BASE"
|
|
||||||
"$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
|
|
||||||
check_unchanged
|
|
||||||
else
|
|
||||||
"$merge_tool_path" "$LOCAL" "$REMOTE"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
tkdiff)
|
|
||||||
if merge_mode; then
|
|
||||||
if $base_present; then
|
|
||||||
"$merge_tool_path" -a "$BASE" \
|
|
||||||
-o "$MERGED" "$LOCAL" "$REMOTE"
|
|
||||||
else
|
|
||||||
"$merge_tool_path" \
|
|
||||||
-o "$MERGED" "$LOCAL" "$REMOTE"
|
|
||||||
fi
|
|
||||||
status=$?
|
|
||||||
else
|
|
||||||
"$merge_tool_path" "$LOCAL" "$REMOTE"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
tortoisemerge)
|
|
||||||
if $base_present; then
|
|
||||||
touch "$BACKUP"
|
|
||||||
"$merge_tool_path" \
|
|
||||||
-base:"$BASE" -mine:"$LOCAL" \
|
|
||||||
-theirs:"$REMOTE" -merged:"$MERGED"
|
|
||||||
check_unchanged
|
|
||||||
else
|
|
||||||
echo "TortoiseMerge cannot be used without a base" 1>&2
|
|
||||||
status=1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
xxdiff)
|
|
||||||
if merge_mode; then
|
|
||||||
touch "$BACKUP"
|
|
||||||
if $base_present; then
|
|
||||||
"$merge_tool_path" -X --show-merged-pane \
|
|
||||||
-R 'Accel.SaveAsMerged: "Ctrl-S"' \
|
|
||||||
-R 'Accel.Search: "Ctrl+F"' \
|
|
||||||
-R 'Accel.SearchForward: "Ctrl-G"' \
|
|
||||||
--merged-file "$MERGED" \
|
|
||||||
"$LOCAL" "$BASE" "$REMOTE"
|
|
||||||
else
|
|
||||||
"$merge_tool_path" -X $extra \
|
|
||||||
-R 'Accel.SaveAsMerged: "Ctrl-S"' \
|
|
||||||
-R 'Accel.Search: "Ctrl+F"' \
|
|
||||||
-R 'Accel.SearchForward: "Ctrl-G"' \
|
|
||||||
--merged-file "$MERGED" \
|
|
||||||
"$LOCAL" "$REMOTE"
|
|
||||||
fi
|
|
||||||
check_unchanged
|
|
||||||
else
|
|
||||||
"$merge_tool_path" \
|
|
||||||
-R 'Accel.Search: "Ctrl+F"' \
|
|
||||||
-R 'Accel.SearchForward: "Ctrl-G"' \
|
|
||||||
"$LOCAL" "$REMOTE"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
merge_tool_cmd="$(get_merge_tool_cmd "$1")"
|
|
||||||
if test -z "$merge_tool_cmd"; then
|
|
||||||
if merge_mode; then
|
|
||||||
status=1
|
|
||||||
fi
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
if merge_mode; then
|
|
||||||
trust_exit_code="$(git config --bool \
|
|
||||||
mergetool."$1".trustExitCode || echo false)"
|
|
||||||
if test "$trust_exit_code" = "false"; then
|
|
||||||
touch "$BACKUP"
|
|
||||||
( eval $merge_tool_cmd )
|
|
||||||
check_unchanged
|
|
||||||
else
|
|
||||||
( eval $merge_tool_cmd )
|
|
||||||
status=$?
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
( eval $merge_tool_cmd )
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
return $status
|
|
||||||
}
|
|
||||||
|
|
||||||
guess_merge_tool () {
|
|
||||||
if merge_mode; then
|
|
||||||
tools="tortoisemerge"
|
|
||||||
else
|
|
||||||
tools="kompare"
|
|
||||||
fi
|
|
||||||
if test -n "$DISPLAY"; then
|
|
||||||
if test -n "$GNOME_DESKTOP_SESSION_ID" ; then
|
|
||||||
tools="meld opendiff kdiff3 tkdiff xxdiff $tools"
|
|
||||||
else
|
|
||||||
tools="opendiff kdiff3 tkdiff xxdiff meld $tools"
|
|
||||||
fi
|
|
||||||
tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3"
|
|
||||||
fi
|
|
||||||
case "${VISUAL:-$EDITOR}" in
|
|
||||||
*vim*)
|
|
||||||
tools="$tools vimdiff emerge"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
tools="$tools emerge vimdiff"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
echo >&2 "merge tool candidates: $tools"
|
|
||||||
|
|
||||||
# Loop over each candidate and stop when a valid merge tool is found.
|
|
||||||
for i in $tools
|
|
||||||
do
|
|
||||||
merge_tool_path="$(translate_merge_tool_path "$i")"
|
|
||||||
if type "$merge_tool_path" > /dev/null 2>&1; then
|
|
||||||
echo "$i"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo >&2 "No known merge resolution program available."
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
get_configured_merge_tool () {
|
|
||||||
# Diff mode first tries diff.tool and falls back to merge.tool.
|
|
||||||
# Merge mode only checks merge.tool
|
|
||||||
if diff_mode; then
|
|
||||||
merge_tool=$(git config diff.tool || git config merge.tool)
|
|
||||||
else
|
|
||||||
merge_tool=$(git config merge.tool)
|
|
||||||
fi
|
|
||||||
if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then
|
|
||||||
echo >&2 "git config option $TOOL_MODE.tool set to unknown tool: $merge_tool"
|
|
||||||
echo >&2 "Resetting to default..."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
echo "$merge_tool"
|
|
||||||
}
|
|
||||||
|
|
||||||
get_merge_tool_path () {
|
|
||||||
# A merge tool has been set, so verify that it's valid.
|
|
||||||
if test -n "$1"; then
|
|
||||||
merge_tool="$1"
|
|
||||||
else
|
|
||||||
merge_tool="$(get_merge_tool)"
|
|
||||||
fi
|
|
||||||
if ! valid_tool "$merge_tool"; then
|
|
||||||
echo >&2 "Unknown merge tool $merge_tool"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if diff_mode; then
|
|
||||||
merge_tool_path=$(git config difftool."$merge_tool".path ||
|
|
||||||
git config mergetool."$merge_tool".path)
|
|
||||||
else
|
|
||||||
merge_tool_path=$(git config mergetool."$merge_tool".path)
|
|
||||||
fi
|
|
||||||
if test -z "$merge_tool_path"; then
|
|
||||||
merge_tool_path="$(translate_merge_tool_path "$merge_tool")"
|
|
||||||
fi
|
|
||||||
if test -z "$(get_merge_tool_cmd "$merge_tool")" &&
|
|
||||||
! type "$merge_tool_path" > /dev/null 2>&1; then
|
|
||||||
echo >&2 "The $TOOL_MODE tool $merge_tool is not available as"\
|
|
||||||
"'$merge_tool_path'"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "$merge_tool_path"
|
|
||||||
}
|
|
||||||
|
|
||||||
get_merge_tool () {
|
|
||||||
# Check if a merge tool has been configured
|
|
||||||
merge_tool=$(get_configured_merge_tool)
|
|
||||||
# Try to guess an appropriate merge tool if no tool has been set.
|
|
||||||
if test -z "$merge_tool"; then
|
|
||||||
merge_tool="$(guess_merge_tool)" || exit
|
|
||||||
fi
|
|
||||||
echo "$merge_tool"
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
|
@ -1 +0,0 @@
|
||||||
../../bin/git
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue