mirror of
https://github.com/git/git.git
synced 2026-03-13 10:23:30 +01:00
Merge commit 'e8760cde01299817daae26c9ad074b776bbd8f88'
This commit is contained in:
@@ -59,3 +59,7 @@ Fixes since v1.5.1
|
||||
|
||||
- git-svn dcommit and rebase was confused by patches that were
|
||||
merged from another branch that is managed by git-svn.
|
||||
|
||||
- git-svn used to get confused when globbing remote branch/tag
|
||||
spec (e.g. "branches = proj/branches/*:refs/remotes/origin/*")
|
||||
is used and there was a plain file that matched the glob.
|
||||
|
||||
50
Documentation/RelNotes-1.5.1.2.txt
Normal file
50
Documentation/RelNotes-1.5.1.2.txt
Normal file
@@ -0,0 +1,50 @@
|
||||
GIT v1.5.1.2 Release Notes
|
||||
==========================
|
||||
|
||||
Fixes since v1.5.1.1
|
||||
--------------------
|
||||
|
||||
* Bugfixes
|
||||
|
||||
- "git clone" over http from a repository that has lost the
|
||||
loose refs by running "git pack-refs" were broken (a code to
|
||||
deal with this was added to "git fetch" in v1.5.0, but it
|
||||
was missing from "git clone").
|
||||
|
||||
- "git diff a/ b/" incorrectly fell in "diff between two
|
||||
filesystem objects" codepath, when the user most likely
|
||||
wanted to limit the extent of output to two tracked
|
||||
directories.
|
||||
|
||||
- git-quiltimport had the same bug as we fixed for
|
||||
git-applymbox in v1.5.1.1 -- it gave an alarming "did not
|
||||
have any patch" message (but did not actually fail and was
|
||||
harmless).
|
||||
|
||||
- various git-svn fixes.
|
||||
|
||||
- Sample update hook incorrectly always refused requests to
|
||||
delete branches through push.
|
||||
|
||||
- git-blame on a very long working tree path had buffer
|
||||
overrun problem.
|
||||
|
||||
- git-apply did not like to be fed two patches in a row that created
|
||||
and then modified the same file.
|
||||
|
||||
- git-svn was confused when a non-project was stored directly under
|
||||
trunk/, branches/ and tags/.
|
||||
|
||||
- git-svn wants the Error.pm module that was at least as new
|
||||
as what we ship as part of git; install ours in our private
|
||||
installation location if the one on the system is older.
|
||||
|
||||
- An earlier update to command line integer parameter parser was
|
||||
botched and made 'update-index --cacheinfo' completely useless.
|
||||
|
||||
|
||||
* Documentation updates
|
||||
|
||||
- Various documentation updates from J. Bruce Fields, Frank
|
||||
Lichtenheld, Alex Riesen and others. Andrew Ruder started a
|
||||
war on undocumented options.
|
||||
@@ -9,6 +9,14 @@ Updates since v1.5.1
|
||||
- "git bisect start" can optionally take a single bad commit and
|
||||
zero or more good commits on the command line.
|
||||
|
||||
- "git shortlog" can optionally be told to wrap its output.
|
||||
|
||||
- "subtree" merge strategy allows another project to be merged in as
|
||||
your subdirectory.
|
||||
|
||||
- "git format-patch" learned a new --subject-prefix=<string>
|
||||
option, to override the built-in "[PATCH]".
|
||||
|
||||
* Updated behavior of existing commands.
|
||||
|
||||
- "git diff --stat" shows size of preimage and postimage blobs
|
||||
@@ -27,6 +35,12 @@ Updates since v1.5.1
|
||||
the root commit). We used to refuse to operate without a
|
||||
good and a bad commit.
|
||||
|
||||
- "git push", when pushing into more than one repository, does
|
||||
not stop at the first error.
|
||||
|
||||
- "git archive" does not insist you to give --format parameter
|
||||
anymore; it defaults to "tar".
|
||||
|
||||
* Builds
|
||||
|
||||
- git-p4import has never been installed; now there is an
|
||||
@@ -55,8 +69,30 @@ The following are all in v1.5.1.x series, unless otherwise noted.
|
||||
|
||||
* Documentation updates
|
||||
|
||||
- Various documentation updates from J. Bruce Fields, Frank
|
||||
Lichtenheld, Alex Riesen and others. Andrew Ruder started a
|
||||
war on undocumented options.
|
||||
|
||||
* Bugfixes
|
||||
|
||||
- "git diff a/ b/" incorrectly fell in "diff between two
|
||||
filesystem objects" codepath, when the user most likely
|
||||
wanted to limit the extent of output to two tracked
|
||||
directories.
|
||||
|
||||
- git-quiltimport had the same bug as we fixed for
|
||||
git-applymbox in v1.5.1.1 -- it gave an alarming "did not
|
||||
have any patch" message (but did not actually fail and was
|
||||
harmless).
|
||||
|
||||
- various git-svn fixes.
|
||||
|
||||
- Sample update hook incorrectly always refused requests to
|
||||
delete branches through push.
|
||||
|
||||
- git-blame on a very long working tree path had buffer
|
||||
overrun problem.
|
||||
|
||||
- Switching branches with "git checkout" refused to work when
|
||||
a path changes from a file to a directory between the
|
||||
current branch and the new branch, in order not to lose
|
||||
@@ -67,10 +103,17 @@ The following are all in v1.5.1.x series, unless otherwise noted.
|
||||
been backported to 1.5.1.x series, as it is rather an
|
||||
intrusive change.
|
||||
|
||||
- Merging branches that have a file in one and a directory in
|
||||
another at the same path used to get quite confused. We
|
||||
handle such a case a bit more carefully, even though that is
|
||||
still left as a conflict for the user to sort out. This
|
||||
will not be backported to 1.5.1.x series, as it is rather an
|
||||
intrusive change.
|
||||
|
||||
* Performance Tweaks
|
||||
|
||||
--
|
||||
exec >/var/tmp/1
|
||||
O=v1.5.1-91-g640ee0d
|
||||
O=v1.5.1.1-158-g86da9de
|
||||
echo O=`git describe refs/heads/master`
|
||||
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
|
||||
|
||||
@@ -423,8 +423,34 @@ gitcvs.allbinary::
|
||||
causes the client to treat all files as binary files which suppresses
|
||||
any newline munging it otherwise might do. A work-around for the
|
||||
fact that there is no way yet to set single files to mode '-kb'.
|
||||
|
||||
gitcvs.dbname::
|
||||
Database used by git-cvsserver to cache revision information
|
||||
derived from the git repository. The exact meaning depends on the
|
||||
used database driver, for SQLite (which is the default driver) this
|
||||
is a filename. Supports variable substitution (see
|
||||
gitlink:git-cvsserver[1] for details). May not contain semicolons (`;`).
|
||||
Default: '%Ggitcvs.%m.sqlite'
|
||||
|
||||
gitcvs.dbdriver::
|
||||
Used Perl DBI driver. You can specify any available driver
|
||||
for this here, but it might not work. git-cvsserver is tested
|
||||
with 'DBD::SQLite', reported to work with 'DBD::Pg', and
|
||||
reported *not* to work with 'DBD::mysql'. Experimental feature.
|
||||
May not contain double colons (`:`). Default: 'SQLite'.
|
||||
See gitlink:git-cvsserver[1].
|
||||
|
||||
gitcvs.dbuser, gitcvs.dbpass::
|
||||
Database user and password. Only useful if setting 'gitcvs.dbdriver',
|
||||
since SQLite has no concept of database users and/or passwords.
|
||||
'gitcvs.dbuser' supports variable substitution (see
|
||||
gitlink:git-cvsserver[1] for details).
|
||||
|
||||
All gitcvs variables except for 'gitcvs.allbinary' can also specifed
|
||||
as 'gitcvs.<access_method>.<varname>' (where 'access_method' is one
|
||||
of "ext" and "pserver") to make them apply only for the given access
|
||||
method.
|
||||
|
||||
http.sslVerify::
|
||||
Whether to verify the SSL certificate when fetching or pushing
|
||||
over HTTPS. Can be overridden by the 'GIT_SSL_NO_VERIFY' environment
|
||||
|
||||
@@ -33,9 +33,12 @@ OPTIONS
|
||||
Format of the resulting archive: 'tar', 'zip'... The default
|
||||
is 'tar'.
|
||||
|
||||
--list::
|
||||
--list, -l::
|
||||
Show all available formats.
|
||||
|
||||
--verbose, -v::
|
||||
Report progress to stderr.
|
||||
|
||||
--prefix=<prefix>/::
|
||||
Prepend <prefix>/ to each filename in the archive.
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ OPTIONS
|
||||
development branch), adding this information can be
|
||||
useful.
|
||||
|
||||
-r|--replay::
|
||||
-r::
|
||||
It used to be that the command defaulted to do `-x`
|
||||
described above, and `-r` was to disable it. Now the
|
||||
default is not to do `-x` so this option is a no-op.
|
||||
|
||||
@@ -9,16 +9,16 @@ git-config - Get and set repository or global options
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-config' [--global] [type] name [value [value_regex]]
|
||||
'git-config' [--global] [type] --add name value
|
||||
'git-config' [--global] [type] --replace-all name [value [value_regex]]
|
||||
'git-config' [--global] [type] --get name [value_regex]
|
||||
'git-config' [--global] [type] --get-all name [value_regex]
|
||||
'git-config' [--global] [type] --unset name [value_regex]
|
||||
'git-config' [--global] [type] --unset-all name [value_regex]
|
||||
'git-config' [--global] [type] --rename-section old_name new_name
|
||||
'git-config' [--global] [type] --remove-section name
|
||||
'git-config' [--global] -l | --list
|
||||
'git-config' [--system | --global] [type] name [value [value_regex]]
|
||||
'git-config' [--system | --global] [type] --add name value
|
||||
'git-config' [--system | --global] [type] --replace-all name [value [value_regex]]
|
||||
'git-config' [--system | --global] [type] --get name [value_regex]
|
||||
'git-config' [--system | --global] [type] --get-all name [value_regex]
|
||||
'git-config' [--system | --global] [type] --unset name [value_regex]
|
||||
'git-config' [--system | --global] [type] --unset-all name [value_regex]
|
||||
'git-config' [--system | --global] [type] --rename-section old_name new_name
|
||||
'git-config' [--system | --global] [type] --remove-section name
|
||||
'git-config' [--system | --global] -l | --list
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -76,6 +76,10 @@ OPTIONS
|
||||
--global::
|
||||
Use global ~/.gitconfig file rather than the repository .git/config.
|
||||
|
||||
--system::
|
||||
Use system-wide $(prefix)/etc/gitconfig rather than the repository
|
||||
.git/config.
|
||||
|
||||
--remove-section::
|
||||
Remove the given section from the configuration file.
|
||||
|
||||
|
||||
@@ -31,6 +31,10 @@ over pserver for anonymous CVS access.
|
||||
|
||||
CVS clients cannot tag, branch or perform GIT merges.
|
||||
|
||||
git-cvsserver maps GIT branches to CVS modules. This is very different
|
||||
from what most CVS users would expect since in CVS modules usually represent
|
||||
one or more directories.
|
||||
|
||||
INSTALLATION
|
||||
------------
|
||||
|
||||
@@ -65,9 +69,22 @@ env variable, you can rename git-cvsserver to cvs.
|
||||
|
||||
------
|
||||
Note: you need to ensure each user that is going to invoke git-cvsserver has
|
||||
write access to the log file and to the git repository. When offering anon
|
||||
access via pserver, this means that the nobody user should have write access
|
||||
to at least the sqlite database at the root of the repository.
|
||||
write access to the log file and to the database (see
|
||||
<<dbbackend,Database Backend>>. If you want to offer write access over
|
||||
SSH, the users of course also need write access to the git repository itself.
|
||||
|
||||
[[configaccessmethod]]
|
||||
All configuration variables can also be overriden for a specific method of
|
||||
access. Valid method names are "ext" (for SSH access) and "pserver". The
|
||||
following example configuration would disable pserver access while still
|
||||
allowing access over SSH.
|
||||
------
|
||||
[gitcvs]
|
||||
enabled=0
|
||||
|
||||
[gitcvs "ext"]
|
||||
enabled=1
|
||||
------
|
||||
--
|
||||
3. On the client machine you need to set the following variables.
|
||||
CVSROOT should be set as per normal, but the directory should point at the
|
||||
@@ -93,6 +110,90 @@ Example:
|
||||
cvs co -d project-master master
|
||||
------
|
||||
|
||||
[[dbbackend]]
|
||||
Database Backend
|
||||
----------------
|
||||
|
||||
git-cvsserver uses one database per git head (i.e. CVS module) to
|
||||
store information about the repository for faster access. The
|
||||
database doesn't contain any persitent data and can be completly
|
||||
regenerated from the git repository at any time. The database
|
||||
needs to be updated (i.e. written to) after every commit.
|
||||
|
||||
If the commit is done directly by using git (as opposed to
|
||||
using git-cvsserver) the update will need to happen on the
|
||||
next repository access by git-cvsserver, independent of
|
||||
access method and requested operation.
|
||||
|
||||
That means that even if you offer only read access (e.g. by using
|
||||
the pserver method), git-cvsserver should have write access to
|
||||
the database to work reliably (otherwise you need to make sure
|
||||
that the database if up-to-date all the time git-cvsserver is run).
|
||||
|
||||
By default it uses SQLite databases in the git directory, named
|
||||
`gitcvs.<module_name>.sqlite`. Note that the SQLite backend creates
|
||||
temporary files in the same directory as the database file on
|
||||
write so it might not be enough to grant the users using
|
||||
git-cvsserver write access to the database file without granting
|
||||
them write access to the directory, too.
|
||||
|
||||
You can configure the database backend with the following
|
||||
configuration variables:
|
||||
|
||||
Configuring database backend
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
git-cvsserver uses the Perl DBI module. Please also read
|
||||
its documentation if changing these variables, especially
|
||||
about `DBI->connect()`.
|
||||
|
||||
gitcvs.dbname::
|
||||
Database name. The exact meaning depends on the
|
||||
used database driver, for SQLite this is a filename.
|
||||
Supports variable substitution (see below). May
|
||||
not contain semicolons (`;`).
|
||||
Default: '%Ggitcvs.%m.sqlite'
|
||||
|
||||
gitcvs.dbdriver::
|
||||
Used DBI driver. You can specify any available driver
|
||||
for this here, but it might not work. cvsserver is tested
|
||||
with 'DBD::SQLite', reported to work with
|
||||
'DBD::Pg', and reported *not* to work with 'DBD::mysql'.
|
||||
Please regard this as an experimental feature. May not
|
||||
contain double colons (`:`).
|
||||
Default: 'SQLite'
|
||||
|
||||
gitcvs.dbuser::
|
||||
Database user. Only useful if setting `dbdriver`, since
|
||||
SQLite has no concept of database users. Supports variable
|
||||
substitution (see below).
|
||||
|
||||
gitcvs.dbpass::
|
||||
Database password. Only useful if setting `dbdriver`, since
|
||||
SQLite has no concept of database passwords.
|
||||
|
||||
All variables can also be set per access method, see <<configaccessmethod,above>>.
|
||||
|
||||
Variable substitution
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
In `dbdriver` and `dbuser` you can use the following variables:
|
||||
|
||||
%G::
|
||||
git directory name
|
||||
%g::
|
||||
git directory name, where all characters except for
|
||||
alpha-numeric ones, `.`, and `-` are replaced with
|
||||
`_` (this should make it easier to use the directory
|
||||
name in a filename if wanted)
|
||||
%m::
|
||||
CVS module/git head name
|
||||
%a::
|
||||
access method (one of "ext" or "pserver")
|
||||
%u::
|
||||
Name of the user running git-cvsserver.
|
||||
If no name can be determined, the
|
||||
numeric uid is used.
|
||||
|
||||
Eclipse CVS Client Notes
|
||||
------------------------
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ git-rm - Remove files from the working tree and from the index
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-rm' [-f] [-n] [-r] [--cached] [--] <file>...
|
||||
'git-rm' [-f] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] <file>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -47,6 +47,9 @@ OPTIONS
|
||||
the paths only from the index, leaving working tree
|
||||
files.
|
||||
|
||||
\--ignore-unmatch::
|
||||
Exit with a zero status even if no files matched.
|
||||
|
||||
\--quiet::
|
||||
git-rm normally outputs one line (in the form of an "rm" command)
|
||||
for each file removed. This option suppresses that output.
|
||||
|
||||
@@ -7,6 +7,7 @@ git-shortlog - Summarize 'git log' output
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
git-log --pretty=short | 'git-shortlog' [-h] [-n] [-s]
|
||||
git-shortlog [-n|--number] [-s|--summary] [<committish>...]
|
||||
|
||||
@@ -33,7 +34,8 @@ OPTIONS
|
||||
|
||||
FILES
|
||||
-----
|
||||
'.mailmap'::
|
||||
|
||||
.mailmap::
|
||||
If this file exists, it will be used for mapping author email
|
||||
addresses to a real author name. One mapping per line, first
|
||||
the author name followed by the email address enclosed by
|
||||
|
||||
@@ -13,7 +13,7 @@ SYNOPSIS
|
||||
DESCRIPTION
|
||||
-----------
|
||||
THIS COMMAND IS DEPRECATED. Use `git-archive` with `--format=tar`
|
||||
option instead.
|
||||
option instead (and move the <base> argument to `--prefix=base/`).
|
||||
|
||||
Creates a tar archive containing the tree structure for the named tree.
|
||||
When <base> is specified it is added as a leading path to the files in the
|
||||
|
||||
@@ -111,7 +111,7 @@ make it real.
|
||||
Note: don't forget to 'add' a file again if you modified it after the
|
||||
first 'add' and before 'commit'. Otherwise only the previous added
|
||||
state of that file will be committed. This is because git tracks
|
||||
content, so what you're really 'add'ing to the commit is the *content*
|
||||
content, so what you're really 'adding' to the commit is the *content*
|
||||
of the file in the state it is in when you 'add' it.
|
||||
|
||||
2) By using 'git commit -a' directly
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=v1.5.1.1.GIT
|
||||
DEF_VER=v1.5.1.2.GIT
|
||||
|
||||
LF='
|
||||
'
|
||||
|
||||
4
Makefile
4
Makefile
@@ -283,7 +283,7 @@ LIB_H = \
|
||||
run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
|
||||
tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \
|
||||
spawn-pipe.h \
|
||||
utf8.h reflog-walk.h patch-ids.h
|
||||
utf8.h reflog-walk.h patch-ids.h decorate.h
|
||||
|
||||
DIFF_OBJS = \
|
||||
diff.o diff-lib.o diffcore-break.o diffcore-order.o \
|
||||
@@ -306,7 +306,7 @@ LIB_OBJS = \
|
||||
write_or_die.o trace.o list-objects.o grep.o match-trees.o \
|
||||
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
|
||||
color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
|
||||
convert.o
|
||||
convert.o decorate.o
|
||||
|
||||
BUILTIN_OBJS = \
|
||||
builtin-add.o \
|
||||
|
||||
@@ -2416,8 +2416,7 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned
|
||||
* used to be.
|
||||
*/
|
||||
struct stat st;
|
||||
errno = 0;
|
||||
if (!lstat(path, &st) && S_ISDIR(st.st_mode) && !rmdir(path))
|
||||
if (!lstat(path, &st) && (!S_ISDIR(st.st_mode) || !rmdir(path)))
|
||||
errno = EEXIST;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "cache.h"
|
||||
|
||||
static const char git_config_set_usage[] =
|
||||
"git-config [ --global ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list";
|
||||
"git-config [ --global | --system ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list";
|
||||
|
||||
static char *key;
|
||||
static regex_t *key_regexp;
|
||||
|
||||
@@ -13,16 +13,43 @@
|
||||
#include "tag.h"
|
||||
#include "reflog-walk.h"
|
||||
#include "patch-ids.h"
|
||||
#include "refs.h"
|
||||
|
||||
static int default_show_root = 1;
|
||||
|
||||
/* this is in builtin-diff.c */
|
||||
void add_head(struct rev_info *revs);
|
||||
|
||||
static void add_name_decoration(const char *prefix, const char *name, struct object *obj)
|
||||
{
|
||||
int plen = strlen(prefix);
|
||||
int nlen = strlen(name);
|
||||
struct name_decoration *res = xmalloc(sizeof(struct name_decoration) + plen + nlen);
|
||||
memcpy(res->name, prefix, plen);
|
||||
memcpy(res->name + plen, name, nlen + 1);
|
||||
res->next = add_decoration(&name_decoration, obj, res);
|
||||
}
|
||||
|
||||
static int add_ref_decoration(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
|
||||
{
|
||||
struct object *obj = parse_object(sha1);
|
||||
if (!obj)
|
||||
return 0;
|
||||
add_name_decoration("", refname, obj);
|
||||
while (obj->type == OBJ_TAG) {
|
||||
obj = ((struct tag *)obj)->tagged;
|
||||
if (!obj)
|
||||
break;
|
||||
add_name_decoration("tag: ", refname, obj);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cmd_log_init(int argc, const char **argv, const char *prefix,
|
||||
struct rev_info *rev)
|
||||
{
|
||||
int i;
|
||||
int decorate = 0;
|
||||
|
||||
rev->abbrev = DEFAULT_ABBREV;
|
||||
rev->commit_format = CMIT_FMT_DEFAULT;
|
||||
@@ -39,8 +66,11 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
|
||||
git_log_output_encoding = xstrdup(arg);
|
||||
else
|
||||
git_log_output_encoding = "";
|
||||
}
|
||||
else
|
||||
} else if (!strcmp(arg, "--decorate")) {
|
||||
if (!decorate)
|
||||
for_each_ref(add_ref_decoration, NULL);
|
||||
decorate = 1;
|
||||
} else
|
||||
die("unrecognized argument: %s", arg);
|
||||
}
|
||||
}
|
||||
|
||||
21
builtin-rm.c
21
builtin-rm.c
@@ -10,7 +10,7 @@
|
||||
#include "tree-walk.h"
|
||||
|
||||
static const char builtin_rm_usage[] =
|
||||
"git-rm [-f] [-n] [-r] [--cached] [--quiet] [--] <file>...";
|
||||
"git-rm [-f] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] <file>...";
|
||||
|
||||
static struct {
|
||||
int nr, alloc;
|
||||
@@ -105,6 +105,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i, newfd;
|
||||
int show_only = 0, force = 0, index_only = 0, recursive = 0, quiet = 0;
|
||||
int ignore_unmatch = 0;
|
||||
const char **pathspec;
|
||||
char *seen;
|
||||
|
||||
@@ -134,6 +135,8 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
|
||||
recursive = 1;
|
||||
else if (!strcmp(arg, "--quiet"))
|
||||
quiet = 1;
|
||||
else if (!strcmp(arg, "--ignore-unmatch"))
|
||||
ignore_unmatch = 1;
|
||||
else
|
||||
usage(builtin_rm_usage);
|
||||
}
|
||||
@@ -155,14 +158,24 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
|
||||
|
||||
if (pathspec) {
|
||||
const char *match;
|
||||
int seen_any = 0;
|
||||
for (i = 0; (match = pathspec[i]) != NULL ; i++) {
|
||||
if (!seen[i])
|
||||
die("pathspec '%s' did not match any files",
|
||||
match);
|
||||
if (!seen[i]) {
|
||||
if (!ignore_unmatch) {
|
||||
die("pathspec '%s' did not match any files",
|
||||
match);
|
||||
}
|
||||
}
|
||||
else {
|
||||
seen_any = 1;
|
||||
}
|
||||
if (!recursive && seen[i] == MATCHED_RECURSIVELY)
|
||||
die("not removing '%s' recursively without -r",
|
||||
*match ? match : ".");
|
||||
}
|
||||
|
||||
if (! seen_any)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "diff.h"
|
||||
#include "path-list.h"
|
||||
#include "revision.h"
|
||||
#include "utf8.h"
|
||||
|
||||
static const char shortlog_usage[] =
|
||||
"git-shortlog [-n] [-s] [<commit-id>... ]";
|
||||
@@ -276,11 +277,64 @@ static void get_from_rev(struct rev_info *rev, struct path_list *list)
|
||||
|
||||
}
|
||||
|
||||
static int parse_uint(char const **arg, int comma)
|
||||
{
|
||||
unsigned long ul;
|
||||
int ret;
|
||||
char *endp;
|
||||
|
||||
ul = strtoul(*arg, &endp, 10);
|
||||
if (endp != *arg && *endp && *endp != comma)
|
||||
return -1;
|
||||
ret = (int) ul;
|
||||
if (ret != ul)
|
||||
return -1;
|
||||
*arg = endp;
|
||||
if (**arg)
|
||||
(*arg)++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char wrap_arg_usage[] = "-w[<width>[,<indent1>[,<indent2>]]]";
|
||||
#define DEFAULT_WRAPLEN 76
|
||||
#define DEFAULT_INDENT1 6
|
||||
#define DEFAULT_INDENT2 9
|
||||
|
||||
static void parse_wrap_args(const char *arg, int *in1, int *in2, int *wrap)
|
||||
{
|
||||
arg += 2; /* skip -w */
|
||||
|
||||
*wrap = parse_uint(&arg, ',');
|
||||
if (*wrap < 0)
|
||||
die(wrap_arg_usage);
|
||||
*in1 = parse_uint(&arg, ',');
|
||||
if (*in1 < 0)
|
||||
die(wrap_arg_usage);
|
||||
*in2 = parse_uint(&arg, '\0');
|
||||
if (*in2 < 0)
|
||||
die(wrap_arg_usage);
|
||||
|
||||
if (!*wrap)
|
||||
*wrap = DEFAULT_WRAPLEN;
|
||||
if (!*in1)
|
||||
*in1 = DEFAULT_INDENT1;
|
||||
if (!*in2)
|
||||
*in2 = DEFAULT_INDENT2;
|
||||
if (*wrap &&
|
||||
((*in1 && *wrap <= *in1) ||
|
||||
(*in2 && *wrap <= *in2)))
|
||||
die(wrap_arg_usage);
|
||||
}
|
||||
|
||||
int cmd_shortlog(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct rev_info rev;
|
||||
struct path_list list = { NULL, 0, 0, 1 };
|
||||
int i, j, sort_by_number = 0, summary = 0;
|
||||
int wrap_lines = 0;
|
||||
int wrap = DEFAULT_WRAPLEN;
|
||||
int in1 = DEFAULT_INDENT1;
|
||||
int in2 = DEFAULT_INDENT2;
|
||||
|
||||
/* since -n is a shadowed rev argument, parse our args first */
|
||||
while (argc > 1) {
|
||||
@@ -289,6 +343,10 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
|
||||
else if (!strcmp(argv[1], "-s") ||
|
||||
!strcmp(argv[1], "--summary"))
|
||||
summary = 1;
|
||||
else if (!prefixcmp(argv[1], "-w")) {
|
||||
wrap_lines = 1;
|
||||
parse_wrap_args(argv[1], &in1, &in2, &wrap);
|
||||
}
|
||||
else if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
|
||||
usage(shortlog_usage);
|
||||
else
|
||||
@@ -323,9 +381,18 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
|
||||
printf("%s: %d\n", list.items[i].path, onelines->nr);
|
||||
} else {
|
||||
printf("%s (%d):\n", list.items[i].path, onelines->nr);
|
||||
for (j = onelines->nr - 1; j >= 0; j--)
|
||||
printf(" %s\n", onelines->items[j].path);
|
||||
printf("\n");
|
||||
for (j = onelines->nr - 1; j >= 0; j--) {
|
||||
const char *msg = onelines->items[j].path;
|
||||
|
||||
if (wrap_lines) {
|
||||
int col = print_wrapped_text(msg, in1, in2, wrap);
|
||||
if (col != wrap)
|
||||
putchar('\n');
|
||||
}
|
||||
else
|
||||
printf(" %s\n", msg);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
onelines->strdup_paths = 1;
|
||||
|
||||
@@ -551,7 +551,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
|
||||
if (i+3 >= argc)
|
||||
die("git-update-index: --cacheinfo <mode> <sha1> <path>");
|
||||
|
||||
if ((strtoul_ui(argv[i+1], 8, &mode) != 1) ||
|
||||
if (strtoul_ui(argv[i+1], 8, &mode) ||
|
||||
get_sha1_hex(argv[i+2], sha1) ||
|
||||
add_cacheinfo(mode, sha1, argv[i+3], 0))
|
||||
die("git-update-index: --cacheinfo"
|
||||
|
||||
2
cache.h
2
cache.h
@@ -218,7 +218,7 @@ extern int commit_locked_index(struct lock_file *);
|
||||
extern void set_alternate_index_output(const char *);
|
||||
|
||||
extern void rollback_lock_file(struct lock_file *);
|
||||
extern int delete_ref(const char *, unsigned char *sha1);
|
||||
extern int delete_ref(const char *, const unsigned char *sha1);
|
||||
|
||||
/* Environment bits from configuration mechanism */
|
||||
extern int use_legacy_headers;
|
||||
|
||||
8
commit.h
8
commit.h
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "object.h"
|
||||
#include "tree.h"
|
||||
#include "decorate.h"
|
||||
|
||||
struct commit_list {
|
||||
struct commit *item;
|
||||
@@ -21,6 +22,13 @@ struct commit {
|
||||
extern int save_commit_buffer;
|
||||
extern const char *commit_type;
|
||||
|
||||
/* While we can decorate any object with a name, it's only used for commits.. */
|
||||
extern struct decoration name_decoration;
|
||||
struct name_decoration {
|
||||
struct name_decoration *next;
|
||||
char name[1];
|
||||
};
|
||||
|
||||
struct commit *lookup_commit(const unsigned char *sha1);
|
||||
struct commit *lookup_commit_reference(const unsigned char *sha1);
|
||||
struct commit *lookup_commit_reference_gently(const unsigned char *sha1,
|
||||
|
||||
@@ -345,9 +345,15 @@ and returns the process output as a string."
|
||||
(let ((str (git-call-process-env-string nil "symbolic-ref" ref)))
|
||||
(and str (car (split-string str "\n")))))
|
||||
|
||||
(defun git-update-ref (ref val &optional oldval)
|
||||
(defun git-update-ref (ref newval &optional oldval reason)
|
||||
"Update a reference by calling git-update-ref."
|
||||
(apply #'git-call-process-env nil nil "update-ref" ref val (if oldval (list oldval))))
|
||||
(let ((args (and oldval (list oldval))))
|
||||
(push newval args)
|
||||
(push ref args)
|
||||
(when reason
|
||||
(push reason args)
|
||||
(push "-m" args))
|
||||
(eq 0 (apply #'git-call-process-env nil nil "update-ref" args))))
|
||||
|
||||
(defun git-read-tree (tree &optional index-file)
|
||||
"Read a tree into the index file."
|
||||
@@ -364,8 +370,10 @@ and returns the process output as a string."
|
||||
"Call git-commit-tree with buffer as input and return the resulting commit SHA1."
|
||||
(let ((author-name (git-get-committer-name))
|
||||
(author-email (git-get-committer-email))
|
||||
(subject "commit (initial): ")
|
||||
author-date log-start log-end args coding-system-for-write)
|
||||
(when head
|
||||
(setq subject "commit: ")
|
||||
(push "-p" args)
|
||||
(push head args))
|
||||
(with-current-buffer buffer
|
||||
@@ -384,22 +392,29 @@ and returns the process output as a string."
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "^Parent: +\\([0-9a-f]+\\)" nil t)
|
||||
(unless (string-equal head (match-string 1))
|
||||
(setq subject "commit (merge): ")
|
||||
(push "-p" args)
|
||||
(push (match-string 1) args))))
|
||||
(setq log-start (point-min)))
|
||||
(setq log-end (point-max))
|
||||
(goto-char log-start)
|
||||
(when (re-search-forward ".*$" nil t)
|
||||
(setq subject (concat subject (match-string 0))))
|
||||
(setq coding-system-for-write buffer-file-coding-system))
|
||||
(git-get-string-sha1
|
||||
(with-output-to-string
|
||||
(with-current-buffer standard-output
|
||||
(let ((env `(("GIT_AUTHOR_NAME" . ,author-name)
|
||||
("GIT_AUTHOR_EMAIL" . ,author-email)
|
||||
("GIT_COMMITTER_NAME" . ,(git-get-committer-name))
|
||||
("GIT_COMMITTER_EMAIL" . ,(git-get-committer-email)))))
|
||||
(when author-date (push `("GIT_AUTHOR_DATE" . ,author-date) env))
|
||||
(apply #'git-run-command-region
|
||||
buffer log-start log-end env
|
||||
"commit-tree" tree (nreverse args))))))))
|
||||
(let ((commit
|
||||
(git-get-string-sha1
|
||||
(with-output-to-string
|
||||
(with-current-buffer standard-output
|
||||
(let ((env `(("GIT_AUTHOR_NAME" . ,author-name)
|
||||
("GIT_AUTHOR_EMAIL" . ,author-email)
|
||||
("GIT_COMMITTER_NAME" . ,(git-get-committer-name))
|
||||
("GIT_COMMITTER_EMAIL" . ,(git-get-committer-email)))))
|
||||
(when author-date (push `("GIT_AUTHOR_DATE" . ,author-date) env))
|
||||
(apply #'git-run-command-region
|
||||
buffer log-start log-end env
|
||||
"commit-tree" tree (nreverse args))))))))
|
||||
(and (git-update-ref "HEAD" commit head subject)
|
||||
commit))))
|
||||
|
||||
(defun git-empty-db-p ()
|
||||
"Check if the git db is empty (no commit done yet)."
|
||||
@@ -662,7 +677,6 @@ and returns the process output as a string."
|
||||
(if (or (not (string-equal tree head-tree))
|
||||
(yes-or-no-p "The tree was not modified, do you really want to perform an empty commit? "))
|
||||
(let ((commit (git-commit-tree buffer tree head)))
|
||||
(git-update-ref "HEAD" commit head)
|
||||
(condition-case nil (delete-file ".git/MERGE_HEAD") (error nil))
|
||||
(condition-case nil (delete-file ".git/MERGE_MSG") (error nil))
|
||||
(with-current-buffer buffer (erase-buffer))
|
||||
|
||||
@@ -10,7 +10,8 @@ GUI browser for git repository
|
||||
This program is based on bzrk by Scott James Remnant <scott@ubuntu.com>
|
||||
"""
|
||||
__copyright__ = "Copyright (C) 2006 Hewlett-Packard Development Company, L.P."
|
||||
__author__ = "Aneesh Kumar K.V <aneesh.kumar@hp.com>"
|
||||
__copyright__ = "Copyright (C) 2007 Aneesh Kumar K.V <aneesh.kumar@gmail.com"
|
||||
__author__ = "Aneesh Kumar K.V <aneesh.kumar@gmail.com>"
|
||||
|
||||
|
||||
import sys
|
||||
@@ -24,6 +25,7 @@ import gobject
|
||||
import cairo
|
||||
import math
|
||||
import string
|
||||
import fcntl
|
||||
|
||||
try:
|
||||
import gtksourceview
|
||||
@@ -337,6 +339,186 @@ class Commit:
|
||||
fp.close()
|
||||
return diff
|
||||
|
||||
class AnnotateWindow:
|
||||
"""Annotate window.
|
||||
This object represents and manages a single window containing the
|
||||
annotate information of the file
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
self.window.set_border_width(0)
|
||||
self.window.set_title("Git repository browser annotation window")
|
||||
|
||||
# Use two thirds of the screen by default
|
||||
screen = self.window.get_screen()
|
||||
monitor = screen.get_monitor_geometry(0)
|
||||
width = int(monitor.width * 0.66)
|
||||
height = int(monitor.height * 0.66)
|
||||
self.window.set_default_size(width, height)
|
||||
|
||||
def add_file_data(self, filename, commit_sha1, line_num):
|
||||
fp = os.popen("git cat-file blob " + commit_sha1 +":"+filename)
|
||||
i = 1;
|
||||
for line in fp.readlines():
|
||||
line = string.rstrip(line)
|
||||
self.model.append(None, ["HEAD", filename, line, i])
|
||||
i = i+1
|
||||
fp.close()
|
||||
|
||||
# now set the cursor position
|
||||
self.treeview.set_cursor(line_num-1)
|
||||
self.treeview.grab_focus()
|
||||
|
||||
def _treeview_cursor_cb(self, *args):
|
||||
"""Callback for when the treeview cursor changes."""
|
||||
(path, col) = self.treeview.get_cursor()
|
||||
commit_sha1 = self.model[path][0]
|
||||
commit_msg = ""
|
||||
fp = os.popen("git cat-file commit " + commit_sha1)
|
||||
for line in fp.readlines():
|
||||
commit_msg = commit_msg + line
|
||||
fp.close()
|
||||
|
||||
self.commit_buffer.set_text(commit_msg)
|
||||
|
||||
def _treeview_row_activated(self, *args):
|
||||
"""Callback for when the treeview row gets selected."""
|
||||
(path, col) = self.treeview.get_cursor()
|
||||
commit_sha1 = self.model[path][0]
|
||||
filename = self.model[path][1]
|
||||
line_num = self.model[path][3]
|
||||
|
||||
window = AnnotateWindow();
|
||||
fp = os.popen("git rev-parse "+ commit_sha1 + "~1")
|
||||
commit_sha1 = string.strip(fp.readline())
|
||||
fp.close()
|
||||
window.annotate(filename, commit_sha1, line_num)
|
||||
|
||||
def data_ready(self, source, condition):
|
||||
while (1):
|
||||
try :
|
||||
buffer = source.read(8192)
|
||||
except:
|
||||
# resource temporary not available
|
||||
return True
|
||||
|
||||
if (len(buffer) == 0):
|
||||
gobject.source_remove(self.io_watch_tag)
|
||||
source.close()
|
||||
return False
|
||||
|
||||
for buff in buffer.split("\n"):
|
||||
annotate_line = re.compile('^([0-9a-f]{40}) (.+) (.+) (.+)$')
|
||||
m = annotate_line.match(buff)
|
||||
if not m:
|
||||
annotate_line = re.compile('^(filename) (.+)$')
|
||||
m = annotate_line.match(buff)
|
||||
if not m:
|
||||
continue
|
||||
filename = m.group(2)
|
||||
else:
|
||||
self.commit_sha1 = m.group(1)
|
||||
self.source_line = int(m.group(2))
|
||||
self.result_line = int(m.group(3))
|
||||
self.count = int(m.group(4))
|
||||
#set the details only when we have the file name
|
||||
continue
|
||||
|
||||
while (self.count > 0):
|
||||
# set at result_line + count-1 the sha1 as commit_sha1
|
||||
self.count = self.count - 1
|
||||
iter = self.model.iter_nth_child(None, self.result_line + self.count-1)
|
||||
self.model.set(iter, 0, self.commit_sha1, 1, filename, 3, self.source_line)
|
||||
|
||||
|
||||
def annotate(self, filename, commit_sha1, line_num):
|
||||
# verify the commit_sha1 specified has this filename
|
||||
|
||||
fp = os.popen("git ls-tree "+ commit_sha1 + " -- " + filename)
|
||||
line = string.strip(fp.readline())
|
||||
if line == '':
|
||||
# pop up the message the file is not there as a part of the commit
|
||||
fp.close()
|
||||
dialog = gtk.MessageDialog(parent=None, flags=0,
|
||||
type=gtk.MESSAGE_WARNING, buttons=gtk.BUTTONS_CLOSE,
|
||||
message_format=None)
|
||||
dialog.set_markup("The file %s is not present in the parent commit %s" % (filename, commit_sha1))
|
||||
dialog.run()
|
||||
dialog.destroy()
|
||||
return
|
||||
|
||||
fp.close()
|
||||
|
||||
vpan = gtk.VPaned();
|
||||
self.window.add(vpan);
|
||||
vpan.show()
|
||||
|
||||
scrollwin = gtk.ScrolledWindow()
|
||||
scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
scrollwin.set_shadow_type(gtk.SHADOW_IN)
|
||||
vpan.pack1(scrollwin, True, True);
|
||||
scrollwin.show()
|
||||
|
||||
self.model = gtk.TreeStore(str, str, str, int)
|
||||
self.treeview = gtk.TreeView(self.model)
|
||||
self.treeview.set_rules_hint(True)
|
||||
self.treeview.set_search_column(0)
|
||||
self.treeview.connect("cursor-changed", self._treeview_cursor_cb)
|
||||
self.treeview.connect("row-activated", self._treeview_row_activated)
|
||||
scrollwin.add(self.treeview)
|
||||
self.treeview.show()
|
||||
|
||||
cell = gtk.CellRendererText()
|
||||
cell.set_property("width-chars", 10)
|
||||
cell.set_property("ellipsize", pango.ELLIPSIZE_END)
|
||||
column = gtk.TreeViewColumn("Commit")
|
||||
column.set_resizable(True)
|
||||
column.pack_start(cell, expand=True)
|
||||
column.add_attribute(cell, "text", 0)
|
||||
self.treeview.append_column(column)
|
||||
|
||||
cell = gtk.CellRendererText()
|
||||
cell.set_property("width-chars", 20)
|
||||
cell.set_property("ellipsize", pango.ELLIPSIZE_END)
|
||||
column = gtk.TreeViewColumn("File Name")
|
||||
column.set_resizable(True)
|
||||
column.pack_start(cell, expand=True)
|
||||
column.add_attribute(cell, "text", 1)
|
||||
self.treeview.append_column(column)
|
||||
|
||||
cell = gtk.CellRendererText()
|
||||
cell.set_property("width-chars", 20)
|
||||
cell.set_property("ellipsize", pango.ELLIPSIZE_END)
|
||||
column = gtk.TreeViewColumn("Data")
|
||||
column.set_resizable(True)
|
||||
column.pack_start(cell, expand=True)
|
||||
column.add_attribute(cell, "text", 2)
|
||||
self.treeview.append_column(column)
|
||||
|
||||
# The commit message window
|
||||
scrollwin = gtk.ScrolledWindow()
|
||||
scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
scrollwin.set_shadow_type(gtk.SHADOW_IN)
|
||||
vpan.pack2(scrollwin, True, True);
|
||||
scrollwin.show()
|
||||
|
||||
commit_text = gtk.TextView()
|
||||
self.commit_buffer = gtk.TextBuffer()
|
||||
commit_text.set_buffer(self.commit_buffer)
|
||||
scrollwin.add(commit_text)
|
||||
commit_text.show()
|
||||
|
||||
self.window.show()
|
||||
|
||||
self.add_file_data(filename, commit_sha1, line_num)
|
||||
|
||||
fp = os.popen("git blame --incremental -- " + filename + " " + commit_sha1)
|
||||
flags = fcntl.fcntl(fp.fileno(), fcntl.F_GETFL)
|
||||
fcntl.fcntl(fp.fileno(), fcntl.F_SETFL, flags | os.O_NONBLOCK)
|
||||
self.io_watch_tag = gobject.io_add_watch(fp, gobject.IO_IN, self.data_ready)
|
||||
|
||||
|
||||
class DiffWindow:
|
||||
"""Diff window.
|
||||
This object represents and manages a single window containing the
|
||||
@@ -355,6 +537,7 @@ class DiffWindow:
|
||||
height = int(monitor.height * 0.66)
|
||||
self.window.set_default_size(width, height)
|
||||
|
||||
|
||||
self.construct()
|
||||
|
||||
def construct(self):
|
||||
@@ -371,10 +554,12 @@ class DiffWindow:
|
||||
vbox.pack_start(menu_bar, expand=False, fill=True)
|
||||
menu_bar.show()
|
||||
|
||||
hpan = gtk.HPaned()
|
||||
|
||||
scrollwin = gtk.ScrolledWindow()
|
||||
scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
scrollwin.set_shadow_type(gtk.SHADOW_IN)
|
||||
vbox.pack_start(scrollwin, expand=True, fill=True)
|
||||
hpan.pack1(scrollwin, True, True)
|
||||
scrollwin.show()
|
||||
|
||||
if have_gtksourceview:
|
||||
@@ -388,11 +573,77 @@ class DiffWindow:
|
||||
self.buffer = gtk.TextBuffer()
|
||||
sourceview = gtk.TextView(self.buffer)
|
||||
|
||||
|
||||
sourceview.set_editable(False)
|
||||
sourceview.modify_font(pango.FontDescription("Monospace"))
|
||||
scrollwin.add(sourceview)
|
||||
sourceview.show()
|
||||
|
||||
# The file hierarchy: a scrollable treeview
|
||||
scrollwin = gtk.ScrolledWindow()
|
||||
scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
scrollwin.set_shadow_type(gtk.SHADOW_IN)
|
||||
scrollwin.set_size_request(20, -1)
|
||||
hpan.pack2(scrollwin, True, True)
|
||||
scrollwin.show()
|
||||
|
||||
self.model = gtk.TreeStore(str, str, str)
|
||||
self.treeview = gtk.TreeView(self.model)
|
||||
self.treeview.set_search_column(1)
|
||||
self.treeview.connect("cursor-changed", self._treeview_clicked)
|
||||
scrollwin.add(self.treeview)
|
||||
self.treeview.show()
|
||||
|
||||
cell = gtk.CellRendererText()
|
||||
cell.set_property("width-chars", 20)
|
||||
column = gtk.TreeViewColumn("Select to annotate")
|
||||
column.pack_start(cell, expand=True)
|
||||
column.add_attribute(cell, "text", 0)
|
||||
self.treeview.append_column(column)
|
||||
|
||||
vbox.pack_start(hpan, expand=True, fill=True)
|
||||
hpan.show()
|
||||
|
||||
def _treeview_clicked(self, *args):
|
||||
"""Callback for when the treeview cursor changes."""
|
||||
(path, col) = self.treeview.get_cursor()
|
||||
specific_file = self.model[path][1]
|
||||
commit_sha1 = self.model[path][2]
|
||||
if specific_file == None :
|
||||
return
|
||||
elif specific_file == "" :
|
||||
specific_file = None
|
||||
|
||||
window = AnnotateWindow();
|
||||
window.annotate(specific_file, commit_sha1, 1)
|
||||
|
||||
|
||||
def commit_files(self, commit_sha1, parent_sha1):
|
||||
self.model.clear()
|
||||
add = self.model.append(None, [ "Added", None, None])
|
||||
dele = self.model.append(None, [ "Deleted", None, None])
|
||||
mod = self.model.append(None, [ "Modified", None, None])
|
||||
diff_tree = re.compile('^(:.{6}) (.{6}) (.{40}) (.{40}) (A|D|M)\s(.+)$')
|
||||
fp = os.popen("git diff-tree -r --no-commit-id " + parent_sha1 + " " + commit_sha1)
|
||||
while 1:
|
||||
line = string.strip(fp.readline())
|
||||
if line == '':
|
||||
break
|
||||
m = diff_tree.match(line)
|
||||
if not m:
|
||||
continue
|
||||
|
||||
attr = m.group(5)
|
||||
filename = m.group(6)
|
||||
if attr == "A":
|
||||
self.model.append(add, [filename, filename, commit_sha1])
|
||||
elif attr == "D":
|
||||
self.model.append(dele, [filename, filename, commit_sha1])
|
||||
elif attr == "M":
|
||||
self.model.append(mod, [filename, filename, commit_sha1])
|
||||
fp.close()
|
||||
|
||||
self.treeview.expand_all()
|
||||
|
||||
def set_diff(self, commit_sha1, parent_sha1, encoding):
|
||||
"""Set the differences showed by this window.
|
||||
@@ -406,6 +657,7 @@ class DiffWindow:
|
||||
fp = os.popen("git diff-tree -p " + parent_sha1 + " " + commit_sha1)
|
||||
self.buffer.set_text(unicode(fp.read(), encoding).encode('utf-8'))
|
||||
fp.close()
|
||||
self.commit_files(commit_sha1, parent_sha1)
|
||||
self.window.show()
|
||||
|
||||
def save_menu_response(self, widget, string):
|
||||
@@ -425,7 +677,7 @@ class DiffWindow:
|
||||
class GitView:
|
||||
""" This is the main class
|
||||
"""
|
||||
version = "0.8"
|
||||
version = "0.9"
|
||||
|
||||
def __init__(self, with_diff=0):
|
||||
self.with_diff = with_diff
|
||||
@@ -590,7 +842,7 @@ class GitView:
|
||||
dialog = gtk.AboutDialog()
|
||||
dialog.set_name("Gitview")
|
||||
dialog.set_version(GitView.version)
|
||||
dialog.set_authors(["Aneesh Kumar K.V <aneesh.kumar@hp.com>"])
|
||||
dialog.set_authors(["Aneesh Kumar K.V <aneesh.kumar@gmail.com>"])
|
||||
dialog.set_website("http://www.kernel.org/pub/software/scm/git/")
|
||||
dialog.set_copyright("Use and distribute under the terms of the GNU General Public License")
|
||||
dialog.set_wrap_license(True)
|
||||
|
||||
284
contrib/hooks/update-paranoid
Normal file
284
contrib/hooks/update-paranoid
Normal file
@@ -0,0 +1,284 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use File::Spec;
|
||||
|
||||
$ENV{PATH} = '/opt/git/bin';
|
||||
my $acl_git = '/vcs/acls.git';
|
||||
my $acl_branch = 'refs/heads/master';
|
||||
my $debug = 0;
|
||||
|
||||
=doc
|
||||
Invoked as: update refname old-sha1 new-sha1
|
||||
|
||||
This script is run by git-receive-pack once for each ref that the
|
||||
client is trying to modify. If we exit with a non-zero exit value
|
||||
then the update for that particular ref is denied, but updates for
|
||||
other refs in the same run of receive-pack may still be allowed.
|
||||
|
||||
We are run after the objects have been uploaded, but before the
|
||||
ref is actually modified. We take advantage of that fact when we
|
||||
look for "new" commits and tags (the new objects won't show up in
|
||||
`rev-list --all`).
|
||||
|
||||
This script loads and parses the content of the config file
|
||||
"users/$this_user.acl" from the $acl_branch commit of $acl_git ODB.
|
||||
The acl file is a git-config style file, but uses a slightly more
|
||||
restricted syntax as the Perl parser contained within this script
|
||||
is not nearly as permissive as git-config.
|
||||
|
||||
Example:
|
||||
|
||||
[user]
|
||||
committer = John Doe <john.doe@example.com>
|
||||
committer = John R. Doe <john.doe@example.com>
|
||||
|
||||
[repository "acls"]
|
||||
allow = heads/master
|
||||
allow = CDUR for heads/jd/
|
||||
allow = C for ^tags/v\\d+$
|
||||
|
||||
For all new commit or tag objects the committer (or tagger) line
|
||||
within the object must exactly match one of the user.committer
|
||||
values listed in the acl file ("HEAD:users/$this_user.acl").
|
||||
|
||||
For a branch to be modified an allow line within the matching
|
||||
repository section must be matched for both the refname and the
|
||||
opcode.
|
||||
|
||||
Repository sections are matched on the basename of the repository
|
||||
(after removing the .git suffix).
|
||||
|
||||
The opcode abbrevations are:
|
||||
|
||||
C: create new ref
|
||||
D: delete existing ref
|
||||
U: fast-forward existing ref (no commit loss)
|
||||
R: rewind/rebase existing ref (commit loss)
|
||||
|
||||
if no opcodes are listed before the "for" keyword then "U" (for
|
||||
fast-forward update only) is assumed as this is the most common
|
||||
usage.
|
||||
|
||||
Refnames are matched by always assuming a prefix of "refs/".
|
||||
This hook forbids pushing or deleting anything not under "refs/".
|
||||
|
||||
Refnames that start with ^ are Perl regular expressions, and the ^
|
||||
is kept as part of the regexp. \\ is needed to get just one \, so
|
||||
\\d expands to \d in Perl. The 3rd allow line above is an example.
|
||||
|
||||
Refnames that don't start with ^ but that end with / are prefix
|
||||
matches (2nd allow line above); all other refnames are strict
|
||||
equality matches (1st allow line).
|
||||
|
||||
Anything pushed to "heads/" (ok, really "refs/heads/") must be
|
||||
a commit. Tags are not permitted here.
|
||||
|
||||
Anything pushed to "tags/" (err, really "refs/tags/") must be an
|
||||
annotated tag. Commits, blobs, trees, etc. are not permitted here.
|
||||
Annotated tag signatures aren't checked, nor are they required.
|
||||
|
||||
The special subrepository of 'info/new-commit-check' can
|
||||
be created and used to allow users to push new commits and
|
||||
tags from another local repository to this one, even if they
|
||||
aren't the committer/tagger of those objects. In a nut shell
|
||||
the info/new-commit-check directory is a Git repository whose
|
||||
objects/info/alternates file lists this repository and all other
|
||||
possible sources, and whose refs subdirectory contains symlinks
|
||||
to this repository's refs subdirectory, and to all other possible
|
||||
sources refs subdirectories. Yes, this means that you cannot
|
||||
use packed-refs in those repositories as they won't be resolved
|
||||
correctly.
|
||||
|
||||
=cut
|
||||
|
||||
my $git_dir = $ENV{GIT_DIR};
|
||||
my $new_commit_check = "$git_dir/info/new-commit-check";
|
||||
my $ref = $ARGV[0];
|
||||
my $old = $ARGV[1];
|
||||
my $new = $ARGV[2];
|
||||
my $new_type;
|
||||
my ($this_user) = getpwuid $<; # REAL_USER_ID
|
||||
my $repository_name;
|
||||
my %user_committer;
|
||||
my @allow_rules;
|
||||
|
||||
sub deny ($) {
|
||||
print STDERR "-Deny- $_[0]\n" if $debug;
|
||||
print STDERR "\ndenied: $_[0]\n\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
sub grant ($) {
|
||||
print STDERR "-Grant- $_[0]\n" if $debug;
|
||||
exit 0;
|
||||
}
|
||||
|
||||
sub info ($) {
|
||||
print STDERR "-Info- $_[0]\n" if $debug;
|
||||
}
|
||||
|
||||
sub parse_config ($$) {
|
||||
my ($data, $fn) = @_;
|
||||
info "Loading $fn";
|
||||
open(I,'-|','git',"--git-dir=$acl_git",'cat-file','blob',$fn);
|
||||
my $section = '';
|
||||
while (<I>) {
|
||||
chomp;
|
||||
if (/^\s*$/ || /^\s*#/) {
|
||||
} elsif (/^\[([a-z]+)\]$/i) {
|
||||
$section = $1;
|
||||
} elsif (/^\[([a-z]+)\s+"(.*)"\]$/i) {
|
||||
$section = "$1.$2";
|
||||
} elsif (/^\s*([a-z][a-z0-9]+)\s*=\s*(.*?)\s*$/i) {
|
||||
push @{$data->{"$section.$1"}}, $2;
|
||||
} else {
|
||||
deny "bad config file line $. in $fn";
|
||||
}
|
||||
}
|
||||
close I;
|
||||
}
|
||||
|
||||
sub all_new_committers () {
|
||||
local $ENV{GIT_DIR} = $git_dir;
|
||||
$ENV{GIT_DIR} = $new_commit_check if -d $new_commit_check;
|
||||
|
||||
info "Getting committers of new commits.";
|
||||
my %used;
|
||||
open(T,'-|','git','rev-list','--pretty=raw',$new,'--not','--all');
|
||||
while (<T>) {
|
||||
next unless s/^committer //;
|
||||
chop;
|
||||
s/>.*$/>/;
|
||||
info "Found $_." unless $used{$_}++;
|
||||
}
|
||||
close T;
|
||||
info "No new commits." unless %used;
|
||||
keys %used;
|
||||
}
|
||||
|
||||
sub all_new_taggers () {
|
||||
my %exists;
|
||||
open(T,'-|','git','for-each-ref','--format=%(objectname)','refs/tags');
|
||||
while (<T>) {
|
||||
chop;
|
||||
$exists{$_} = 1;
|
||||
}
|
||||
close T;
|
||||
|
||||
info "Getting taggers of new tags.";
|
||||
my %used;
|
||||
my $obj = $new;
|
||||
my $obj_type = $new_type;
|
||||
while ($obj_type eq 'tag') {
|
||||
last if $exists{$obj};
|
||||
$obj_type = '';
|
||||
open(T,'-|','git','cat-file','tag',$obj);
|
||||
while (<T>) {
|
||||
chop;
|
||||
if (/^object ([a-z0-9]{40})$/) {
|
||||
$obj = $1;
|
||||
} elsif (/^type (.+)$/) {
|
||||
$obj_type = $1;
|
||||
} elsif (s/^tagger //) {
|
||||
s/>.*$/>/;
|
||||
info "Found $_." unless $used{$_}++;
|
||||
last;
|
||||
}
|
||||
}
|
||||
close T;
|
||||
}
|
||||
info "No new tags." unless %used;
|
||||
keys %used;
|
||||
}
|
||||
|
||||
sub check_committers (@) {
|
||||
my @bad;
|
||||
foreach (@_) { push @bad, $_ unless $user_committer{$_}; }
|
||||
if (@bad) {
|
||||
print STDERR "\n";
|
||||
print STDERR "You are not $_.\n" foreach (sort @bad);
|
||||
deny "You cannot push changes not committed by you.";
|
||||
}
|
||||
}
|
||||
|
||||
sub git_value (@) {
|
||||
open(T,'-|','git',@_); local $_ = <T>; chop; close T;
|
||||
$_;
|
||||
}
|
||||
|
||||
deny "No GIT_DIR inherited from caller" unless $git_dir;
|
||||
deny "Need a ref name" unless $ref;
|
||||
deny "Refusing funny ref $ref" unless $ref =~ s,^refs/,,;
|
||||
deny "Bad old value $old" unless $old =~ /^[a-z0-9]{40}$/;
|
||||
deny "Bad new value $new" unless $new =~ /^[a-z0-9]{40}$/;
|
||||
deny "Cannot determine who you are." unless $this_user;
|
||||
|
||||
$repository_name = File::Spec->rel2abs($git_dir);
|
||||
$repository_name =~ m,/([^/]+)(?:\.git|/\.git)$,;
|
||||
$repository_name = $1;
|
||||
info "Updating in '$repository_name'.";
|
||||
|
||||
my $op;
|
||||
if ($old =~ /^0{40}$/) { $op = 'C'; }
|
||||
elsif ($new =~ /^0{40}$/) { $op = 'D'; }
|
||||
else { $op = 'R'; }
|
||||
|
||||
# This is really an update (fast-forward) if the
|
||||
# merge base of $old and $new is $old.
|
||||
#
|
||||
$op = 'U' if ($op eq 'R'
|
||||
&& $ref =~ m,^heads/,
|
||||
&& $old eq git_value('merge-base',$old,$new));
|
||||
|
||||
# Load the user's ACL file.
|
||||
{
|
||||
my %data = ('user.committer' => []);
|
||||
parse_config(\%data, "$acl_branch:users/$this_user.acl");
|
||||
%user_committer = map {$_ => $_} @{$data{'user.committer'}};
|
||||
my $rules = $data{"repository.$repository_name.allow"} || [];
|
||||
foreach (@$rules) {
|
||||
if (/^([CDRU ]+)\s+for\s+([^\s]+)$/) {
|
||||
my $ops = $1;
|
||||
my $ref = $2;
|
||||
$ops =~ s/ //g;
|
||||
$ref =~ s/\\\\/\\/g;
|
||||
push @allow_rules, [$ops, $ref];
|
||||
} elsif (/^for\s+([^\s]+)$/) {
|
||||
# Mentioned, but nothing granted?
|
||||
} elsif (/^[^\s]+$/) {
|
||||
s/\\\\/\\/g;
|
||||
push @allow_rules, ['U', $_];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($op ne 'D') {
|
||||
$new_type = git_value('cat-file','-t',$new);
|
||||
|
||||
if ($ref =~ m,^heads/,) {
|
||||
deny "$ref must be a commit." unless $new_type eq 'commit';
|
||||
} elsif ($ref =~ m,^tags/,) {
|
||||
deny "$ref must be an annotated tag." unless $new_type eq 'tag';
|
||||
}
|
||||
|
||||
check_committers (all_new_committers);
|
||||
check_committers (all_new_taggers) if $new_type eq 'tag';
|
||||
}
|
||||
|
||||
info "$this_user wants $op for $ref";
|
||||
foreach my $acl_entry (@allow_rules) {
|
||||
my ($acl_ops, $acl_n) = @$acl_entry;
|
||||
next unless $acl_ops =~ /^[CDRU]+$/; # Uhh.... shouldn't happen.
|
||||
next unless $acl_n;
|
||||
next unless $op =~ /^[$acl_ops]$/;
|
||||
|
||||
grant "Allowed by: $acl_ops for $acl_n"
|
||||
if (
|
||||
($acl_n eq $ref)
|
||||
|| ($acl_n =~ m,/$, && substr($ref,0,length $acl_n) eq $acl_n)
|
||||
|| ($acl_n =~ m,^\^, && $ref =~ m:$acl_n:)
|
||||
);
|
||||
}
|
||||
close A;
|
||||
deny "You are not permitted to $op $ref";
|
||||
@@ -88,7 +88,7 @@ static int write_subdirectory(void *buffer, unsigned long size, const char *base
|
||||
unsigned int mode;
|
||||
char *slash, *origpath;
|
||||
|
||||
if (!path || strtoul_ui(buffer, 8, &mode) != 1)
|
||||
if (!path || strtoul_ui(buffer, 8, &mode))
|
||||
die("bad tree conversion");
|
||||
mode = convert_mode(mode);
|
||||
path++;
|
||||
|
||||
88
decorate.c
Normal file
88
decorate.c
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* decorate.c - decorate a git object with some arbitrary
|
||||
* data.
|
||||
*/
|
||||
#include "cache.h"
|
||||
#include "object.h"
|
||||
#include "decorate.h"
|
||||
|
||||
static unsigned int hash_obj(struct object *obj, unsigned int n)
|
||||
{
|
||||
unsigned int hash = *(unsigned int *)obj->sha1;
|
||||
return hash % n;
|
||||
}
|
||||
|
||||
static void *insert_decoration(struct decoration *n, struct object *base, void *decoration)
|
||||
{
|
||||
int size = n->size;
|
||||
struct object_decoration *hash = n->hash;
|
||||
int j = hash_obj(base, size);
|
||||
|
||||
while (hash[j].base) {
|
||||
if (hash[j].base == base) {
|
||||
void *old = hash[j].decoration;
|
||||
hash[j].decoration = decoration;
|
||||
return old;
|
||||
}
|
||||
if (++j >= size)
|
||||
j = 0;
|
||||
}
|
||||
hash[j].base = base;
|
||||
hash[j].decoration = decoration;
|
||||
n->nr++;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void grow_decoration(struct decoration *n)
|
||||
{
|
||||
int i;
|
||||
int old_size = n->size;
|
||||
struct object_decoration *old_hash;
|
||||
|
||||
old_size = n->size;
|
||||
old_hash = n->hash;
|
||||
|
||||
n->size = (old_size + 1000) * 3 / 2;
|
||||
n->hash = xcalloc(n->size, sizeof(struct object_decoration));
|
||||
n->nr = 0;
|
||||
|
||||
for (i = 0; i < old_size; i++) {
|
||||
struct object *base = old_hash[i].base;
|
||||
void *decoration = old_hash[i].decoration;
|
||||
|
||||
if (!base)
|
||||
continue;
|
||||
insert_decoration(n, base, decoration);
|
||||
}
|
||||
free(old_hash);
|
||||
}
|
||||
|
||||
/* Add a decoration pointer, return any old one */
|
||||
void *add_decoration(struct decoration *n, struct object *obj, void *decoration)
|
||||
{
|
||||
int nr = n->nr + 1;
|
||||
|
||||
if (nr > n->size * 2 / 3)
|
||||
grow_decoration(n);
|
||||
return insert_decoration(n, obj, decoration);
|
||||
}
|
||||
|
||||
/* Lookup a decoration pointer */
|
||||
void *lookup_decoration(struct decoration *n, struct object *obj)
|
||||
{
|
||||
int j;
|
||||
|
||||
/* nothing to lookup */
|
||||
if (!n->size)
|
||||
return NULL;
|
||||
j = hash_obj(obj, n->size);
|
||||
for (;;) {
|
||||
struct object_decoration *ref = n->hash + j;
|
||||
if (ref->base == obj)
|
||||
return ref->decoration;
|
||||
if (!ref->base)
|
||||
return NULL;
|
||||
if (++j == n->size)
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
18
decorate.h
Normal file
18
decorate.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef DECORATE_H
|
||||
#define DECORATE_H
|
||||
|
||||
struct object_decoration {
|
||||
struct object *base;
|
||||
void *decoration;
|
||||
};
|
||||
|
||||
struct decoration {
|
||||
const char *name;
|
||||
unsigned int size, nr;
|
||||
struct object_decoration *hash;
|
||||
};
|
||||
|
||||
extern void *add_decoration(struct decoration *n, struct object *obj, void *decoration);
|
||||
extern void *lookup_decoration(struct decoration *n, struct object *obj);
|
||||
|
||||
#endif
|
||||
@@ -116,10 +116,7 @@ bisect_start() {
|
||||
done
|
||||
|
||||
sq "$@" >"$GIT_DIR/BISECT_NAMES"
|
||||
{
|
||||
printf "git-bisect start"
|
||||
echo "$orig_args"
|
||||
} >>"$GIT_DIR/BISECT_LOG"
|
||||
echo "git-bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG"
|
||||
bisect_auto_next
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ Perhaps git-update-server-info needs to be run there?"
|
||||
else
|
||||
tname=$name
|
||||
fi
|
||||
git-http-fetch $v -a -w "$tname" "$name" "$1" || exit 1
|
||||
git-http-fetch $v -a -w "$tname" "$sha1" "$1" || exit 1
|
||||
done <"$clone_tmp/refs"
|
||||
rm -fr "$clone_tmp"
|
||||
http_fetch "$1/HEAD" "$GIT_DIR/REMOTE_HEAD" ||
|
||||
|
||||
@@ -91,7 +91,9 @@ $log->debug("Temporary directory is '$TEMP_DIR'");
|
||||
# if we are called with a pserver argument,
|
||||
# deal with the authentication cat before entering the
|
||||
# main loop
|
||||
$state->{method} = 'ext';
|
||||
if (@ARGV && $ARGV[0] eq 'pserver') {
|
||||
$state->{method} = 'pserver';
|
||||
my $line = <STDIN>; chomp $line;
|
||||
unless( $line eq 'BEGIN AUTH REQUEST') {
|
||||
die "E Do not understand $line - expecting BEGIN AUTH REQUEST\n";
|
||||
@@ -181,11 +183,18 @@ sub req_Root
|
||||
}
|
||||
foreach my $line ( @gitvars )
|
||||
{
|
||||
next unless ( $line =~ /^(.*?)\.(.*?)=(.*)$/ );
|
||||
$cfg->{$1}{$2} = $3;
|
||||
next unless ( $line =~ /^(.*?)\.(.*?)(?:\.(.*?))?=(.*)$/ );
|
||||
unless ($3) {
|
||||
$cfg->{$1}{$2} = $4;
|
||||
} else {
|
||||
$cfg->{$1}{$2}{$3} = $4;
|
||||
}
|
||||
}
|
||||
|
||||
unless ( defined ( $cfg->{gitcvs}{enabled} ) and $cfg->{gitcvs}{enabled} =~ /^\s*(1|true|yes)\s*$/i )
|
||||
unless ( ($cfg->{gitcvs}{$state->{method}}{enabled}
|
||||
and $cfg->{gitcvs}{$state->{method}}{enabled} =~ /^\s*(1|true|yes)\s*$/i)
|
||||
or ($cfg->{gitcvs}{enabled}
|
||||
and $cfg->{gitcvs}{enabled} =~ /^\s*(1|true|yes)\s*$/i) )
|
||||
{
|
||||
print "E GITCVS emulation needs to be enabled on this repo\n";
|
||||
print "E the repo config file needs a [gitcvs] section added, and the parameter 'enabled' set to 1\n";
|
||||
@@ -194,9 +203,10 @@ sub req_Root
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( defined ( $cfg->{gitcvs}{logfile} ) )
|
||||
my $logfile = $cfg->{gitcvs}{$state->{method}}{logfile} || $cfg->{gitcvs}{logfile};
|
||||
if ( $logfile )
|
||||
{
|
||||
$log->setfile($cfg->{gitcvs}{logfile});
|
||||
$log->setfile($logfile);
|
||||
} else {
|
||||
$log->nofile();
|
||||
}
|
||||
@@ -350,12 +360,52 @@ sub req_add
|
||||
|
||||
argsplit("add");
|
||||
|
||||
my $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log);
|
||||
$updater->update();
|
||||
|
||||
argsfromdir($updater);
|
||||
|
||||
my $addcount = 0;
|
||||
|
||||
foreach my $filename ( @{$state->{args}} )
|
||||
{
|
||||
$filename = filecleanup($filename);
|
||||
|
||||
my $meta = $updater->getmeta($filename);
|
||||
my $wrev = revparse($filename);
|
||||
|
||||
if ($wrev && $meta && ($wrev < 0))
|
||||
{
|
||||
# previously removed file, add back
|
||||
$log->info("added file $filename was previously removed, send 1.$meta->{revision}");
|
||||
|
||||
print "MT +updated\n";
|
||||
print "MT text U \n";
|
||||
print "MT fname $filename\n";
|
||||
print "MT newline\n";
|
||||
print "MT -updated\n";
|
||||
|
||||
unless ( $state->{globaloptions}{-n} )
|
||||
{
|
||||
my ( $filepart, $dirpart ) = filenamesplit($filename,1);
|
||||
|
||||
print "Created $dirpart\n";
|
||||
print $state->{CVSROOT} . "/$state->{module}/$filename\n";
|
||||
|
||||
# this is an "entries" line
|
||||
my $kopts = kopts_from_path($filepart);
|
||||
$log->debug("/$filepart/1.$meta->{revision}//$kopts/");
|
||||
print "/$filepart/1.$meta->{revision}//$kopts/\n";
|
||||
# permissions
|
||||
$log->debug("SEND : u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}");
|
||||
print "u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}\n";
|
||||
# transmit file
|
||||
transmitfile($meta->{filehash});
|
||||
}
|
||||
|
||||
next;
|
||||
}
|
||||
|
||||
unless ( defined ( $state->{entries}{$filename}{modified_filename} ) )
|
||||
{
|
||||
print "E cvs add: nothing known about `$filename'\n";
|
||||
@@ -1027,7 +1077,7 @@ sub req_ci
|
||||
|
||||
$log->info("req_ci : " . ( defined($data) ? $data : "[NULL]" ));
|
||||
|
||||
if ( @ARGV && $ARGV[0] eq 'pserver')
|
||||
if ( $state->{method} eq 'pserver')
|
||||
{
|
||||
print "error 1 pserver access cannot commit\n";
|
||||
exit;
|
||||
@@ -2132,25 +2182,40 @@ sub new
|
||||
|
||||
bless $self, $class;
|
||||
|
||||
$self->{dbdir} = $config . "/";
|
||||
die "Database dir '$self->{dbdir}' isn't a directory" unless ( defined($self->{dbdir}) and -d $self->{dbdir} );
|
||||
|
||||
$self->{module} = $module;
|
||||
$self->{file} = $self->{dbdir} . "/gitcvs.$module.sqlite";
|
||||
|
||||
$self->{git_path} = $config . "/";
|
||||
|
||||
$self->{log} = $log;
|
||||
|
||||
die "Git repo '$self->{git_path}' doesn't exist" unless ( -d $self->{git_path} );
|
||||
|
||||
$self->{dbh} = DBI->connect("dbi:SQLite:dbname=" . $self->{file},"","");
|
||||
$self->{dbdriver} = $cfg->{gitcvs}{$state->{method}}{dbdriver} ||
|
||||
$cfg->{gitcvs}{dbdriver} || "SQLite";
|
||||
$self->{dbname} = $cfg->{gitcvs}{$state->{method}}{dbname} ||
|
||||
$cfg->{gitcvs}{dbname} || "%Ggitcvs.%m.sqlite";
|
||||
$self->{dbuser} = $cfg->{gitcvs}{$state->{method}}{dbuser} ||
|
||||
$cfg->{gitcvs}{dbuser} || "";
|
||||
$self->{dbpass} = $cfg->{gitcvs}{$state->{method}}{dbpass} ||
|
||||
$cfg->{gitcvs}{dbpass} || "";
|
||||
my %mapping = ( m => $module,
|
||||
a => $state->{method},
|
||||
u => getlogin || getpwuid($<) || $<,
|
||||
G => $self->{git_path},
|
||||
g => mangle_dirname($self->{git_path}),
|
||||
);
|
||||
$self->{dbname} =~ s/%([mauGg])/$mapping{$1}/eg;
|
||||
$self->{dbuser} =~ s/%([mauGg])/$mapping{$1}/eg;
|
||||
|
||||
die "Invalid char ':' in dbdriver" if $self->{dbdriver} =~ /:/;
|
||||
die "Invalid char ';' in dbname" if $self->{dbname} =~ /;/;
|
||||
$self->{dbh} = DBI->connect("dbi:$self->{dbdriver}:dbname=$self->{dbname}",
|
||||
$self->{dbuser},
|
||||
$self->{dbpass});
|
||||
die "Error connecting to database\n" unless defined $self->{dbh};
|
||||
|
||||
$self->{tables} = {};
|
||||
foreach my $table ( $self->{dbh}->tables )
|
||||
foreach my $table ( keys %{$self->{dbh}->table_info(undef,undef,undef,'TABLE')->fetchall_hashref('TABLE_NAME')} )
|
||||
{
|
||||
$table =~ s/^"//;
|
||||
$table =~ s/"$//;
|
||||
$self->{tables}{$table} = 1;
|
||||
}
|
||||
|
||||
@@ -2848,5 +2913,19 @@ sub safe_pipe_capture {
|
||||
return wantarray ? @output : join('',@output);
|
||||
}
|
||||
|
||||
=head2 mangle_dirname
|
||||
|
||||
create a string from a directory name that is suitable to use as
|
||||
part of a filename, mainly by converting all chars except \w.- to _
|
||||
|
||||
=cut
|
||||
sub mangle_dirname {
|
||||
my $dirname = shift;
|
||||
return unless defined $dirname;
|
||||
|
||||
$dirname =~ s/[^\w.-]/_/g;
|
||||
|
||||
return $dirname;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
@@ -28,6 +28,8 @@ ifndef V
|
||||
QUIET_BUILT_IN = @echo ' ' BUILTIN $@;
|
||||
endif
|
||||
|
||||
TCLTK_PATH ?= wish
|
||||
|
||||
ifeq ($(findstring $(MAKEFLAGS),s),s)
|
||||
QUIET_GEN =
|
||||
QUIET_BUILT_IN =
|
||||
@@ -36,10 +38,12 @@ endif
|
||||
DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
|
||||
gitexecdir_SQ = $(subst ','\'',$(gitexecdir))
|
||||
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
|
||||
TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH))
|
||||
|
||||
$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
|
||||
$(QUIET_GEN)rm -f $@ $@+ && \
|
||||
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
|
||||
-e 's|^exec wish "$$0"|exec $(subst |,'\|',$(TCLTK_PATH_SQ)) "$$0"|' \
|
||||
-e 's/@@GITGUI_VERSION@@/$(GITGUI_VERSION)/g' \
|
||||
$@.sh >$@+ && \
|
||||
chmod +x $@+ && \
|
||||
|
||||
158
git-gui/git-gui.sh
Executable file → Normal file
158
git-gui/git-gui.sh
Executable file → Normal file
@@ -242,6 +242,8 @@ proc error_popup {msg} {
|
||||
if {[reponame] ne {}} {
|
||||
append title " ([reponame])"
|
||||
}
|
||||
option add *Dialog.msg.font font_ui
|
||||
option add *Button.font font_ui
|
||||
set cmd [list tk_messageBox \
|
||||
-icon error \
|
||||
-type ok \
|
||||
@@ -258,6 +260,8 @@ proc warn_popup {msg} {
|
||||
if {[reponame] ne {}} {
|
||||
append title " ([reponame])"
|
||||
}
|
||||
option add *Dialog.msg.font font_ui
|
||||
option add *Button.font font_ui
|
||||
set cmd [list tk_messageBox \
|
||||
-icon warning \
|
||||
-type ok \
|
||||
@@ -274,6 +278,8 @@ proc info_popup {msg {parent .}} {
|
||||
if {[reponame] ne {}} {
|
||||
append title " ([reponame])"
|
||||
}
|
||||
option add *Dialog.msg.font font_ui
|
||||
option add *Button.font font_ui
|
||||
tk_messageBox \
|
||||
-parent $parent \
|
||||
-icon info \
|
||||
@@ -287,6 +293,8 @@ proc ask_popup {msg} {
|
||||
if {[reponame] ne {}} {
|
||||
append title " ([reponame])"
|
||||
}
|
||||
option add *Dialog.msg.font font_ui
|
||||
option add *Button.font font_ui
|
||||
return [tk_messageBox \
|
||||
-parent . \
|
||||
-icon question \
|
||||
@@ -727,12 +735,9 @@ proc handle_empty_diff {} {
|
||||
|
||||
[short_path $path] has no changes.
|
||||
|
||||
The modification date of this file was updated
|
||||
by another application, but the content within
|
||||
the file was not changed.
|
||||
The modification date of this file was updated by another application, but the content within the file was not changed.
|
||||
|
||||
A rescan will be automatically started to find
|
||||
other files which may have the same state."
|
||||
A rescan will be automatically started to find other files which may have the same state."
|
||||
|
||||
clear_diff
|
||||
display_file $path __
|
||||
@@ -1033,8 +1038,7 @@ proc load_last_commit {} {
|
||||
if {[llength $PARENT] == 0} {
|
||||
error_popup {There is nothing to amend.
|
||||
|
||||
You are about to create the initial commit.
|
||||
There is no commit before this to amend.
|
||||
You are about to create the initial commit. There is no commit before this to amend.
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1043,10 +1047,7 @@ There is no commit before this to amend.
|
||||
if {$curType eq {merge}} {
|
||||
error_popup {Cannot amend while merging.
|
||||
|
||||
You are currently in the middle of a merge that
|
||||
has not been fully completed. You cannot amend
|
||||
the prior commit unless you first abort the
|
||||
current merge activity.
|
||||
You are currently in the middle of a merge that has not been fully completed. You cannot amend the prior commit unless you first abort the current merge activity.
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1136,9 +1137,7 @@ proc commit_tree {} {
|
||||
} elseif {$commit_type ne $curType || $HEAD ne $curHEAD} {
|
||||
info_popup {Last scanned state does not match repository state.
|
||||
|
||||
Another Git program has modified this repository
|
||||
since the last scan. A rescan must be performed
|
||||
before another commit can be created.
|
||||
Another Git program has modified this repository since the last scan. A rescan must be performed before another commit can be created.
|
||||
|
||||
The rescan will be automatically started now.
|
||||
}
|
||||
@@ -1159,8 +1158,7 @@ The rescan will be automatically started now.
|
||||
U? {
|
||||
error_popup "Unmerged files cannot be committed.
|
||||
|
||||
File [short_path $path] has merge conflicts.
|
||||
You must resolve them and add the file before committing.
|
||||
File [short_path $path] has merge conflicts. You must resolve them and add the file before committing.
|
||||
"
|
||||
unlock_index
|
||||
return
|
||||
@@ -2098,7 +2096,10 @@ proc do_create_branch {} {
|
||||
-value head \
|
||||
-variable create_branch_revtype \
|
||||
-font font_ui
|
||||
eval tk_optionMenu $w.from.head_m create_branch_head $all_heads
|
||||
set lbranchm [eval tk_optionMenu $w.from.head_m create_branch_head \
|
||||
$all_heads]
|
||||
$lbranchm configure -font font_ui
|
||||
$w.from.head_m configure -font font_ui
|
||||
grid $w.from.head_r $w.from.head_m -sticky w
|
||||
set all_trackings [all_tracking_branches]
|
||||
if {$all_trackings ne {}} {
|
||||
@@ -2108,9 +2109,11 @@ proc do_create_branch {} {
|
||||
-value tracking \
|
||||
-variable create_branch_revtype \
|
||||
-font font_ui
|
||||
eval tk_optionMenu $w.from.tracking_m \
|
||||
set tbranchm [eval tk_optionMenu $w.from.tracking_m \
|
||||
create_branch_trackinghead \
|
||||
$all_trackings
|
||||
$all_trackings]
|
||||
$tbranchm configure -font font_ui
|
||||
$w.from.tracking_m configure -font font_ui
|
||||
grid $w.from.tracking_r $w.from.tracking_m -sticky w
|
||||
}
|
||||
set all_tags [load_all_tags]
|
||||
@@ -2121,9 +2124,11 @@ proc do_create_branch {} {
|
||||
-value tag \
|
||||
-variable create_branch_revtype \
|
||||
-font font_ui
|
||||
eval tk_optionMenu $w.from.tag_m \
|
||||
set tagsm [eval tk_optionMenu $w.from.tag_m \
|
||||
create_branch_tag \
|
||||
$all_tags
|
||||
$all_tags]
|
||||
$tagsm configure -font font_ui
|
||||
$w.from.tag_m configure -font font_ui
|
||||
grid $w.from.tag_r $w.from.tag_m -sticky w
|
||||
}
|
||||
radiobutton $w.from.exp_r \
|
||||
@@ -2317,7 +2322,11 @@ proc do_delete_branch {} {
|
||||
-value head \
|
||||
-variable delete_branch_checktype \
|
||||
-font font_ui
|
||||
eval tk_optionMenu $w.validate.head_m delete_branch_head $all_heads
|
||||
set mergedlocalm [eval tk_optionMenu $w.validate.head_m \
|
||||
delete_branch_head \
|
||||
$all_heads]
|
||||
$mergedlocalm configure -font font_ui
|
||||
$w.validate.head_m configure -font font_ui
|
||||
grid $w.validate.head_r $w.validate.head_m -sticky w
|
||||
set all_trackings [all_tracking_branches]
|
||||
if {$all_trackings ne {}} {
|
||||
@@ -2327,9 +2336,11 @@ proc do_delete_branch {} {
|
||||
-value tracking \
|
||||
-variable delete_branch_checktype \
|
||||
-font font_ui
|
||||
eval tk_optionMenu $w.validate.tracking_m \
|
||||
set mergedtrackm [eval tk_optionMenu $w.validate.tracking_m \
|
||||
delete_branch_trackinghead \
|
||||
$all_trackings
|
||||
$all_trackings]
|
||||
$mergedtrackm configure -font font_ui
|
||||
$w.validate.tracking_m configure -font font_ui
|
||||
grid $w.validate.tracking_r $w.validate.tracking_m -sticky w
|
||||
}
|
||||
radiobutton $w.validate.always_r \
|
||||
@@ -2364,9 +2375,7 @@ proc switch_branch {new_branch} {
|
||||
} elseif {$commit_type ne $curType || $HEAD ne $curHEAD} {
|
||||
info_popup {Last scanned state does not match repository state.
|
||||
|
||||
Another Git program has modified this repository
|
||||
since the last scan. A rescan must be performed
|
||||
before the current branch can be changed.
|
||||
Another Git program has modified this repository since the last scan. A rescan must be performed before the current branch can be changed.
|
||||
|
||||
The rescan will be automatically started now.
|
||||
}
|
||||
@@ -2457,12 +2466,9 @@ Staying on branch '$current_branch'."
|
||||
if {[catch {git symbolic-ref HEAD "refs/heads/$new_branch"} err]} {
|
||||
error_popup "Failed to set current branch.
|
||||
|
||||
This working directory is only partially switched.
|
||||
We successfully updated your files, but failed to
|
||||
update an internal Git file.
|
||||
This working directory is only partially switched. We successfully updated your files, but failed to update an internal Git file.
|
||||
|
||||
This should not have occurred. [appname] will now
|
||||
close and give up.
|
||||
This should not have occurred. [appname] will now close and give up.
|
||||
|
||||
$err"
|
||||
do_quit
|
||||
@@ -2666,10 +2672,12 @@ proc do_push_anywhere {} {
|
||||
frame $w.buttons
|
||||
button $w.buttons.create -text Push \
|
||||
-font font_ui \
|
||||
-default active \
|
||||
-command [list start_push_anywhere_action $w]
|
||||
pack $w.buttons.create -side right
|
||||
button $w.buttons.cancel -text {Cancel} \
|
||||
-font font_ui \
|
||||
-default normal \
|
||||
-command [list destroy $w]
|
||||
pack $w.buttons.cancel -side right -padx 5
|
||||
pack $w.buttons -side bottom -fill x -pady 10 -padx 10
|
||||
@@ -2703,7 +2711,10 @@ proc do_push_anywhere {} {
|
||||
-value remote \
|
||||
-variable push_urltype \
|
||||
-font font_ui
|
||||
eval tk_optionMenu $w.dest.remote_m push_remote $all_remotes
|
||||
set remmenu [eval tk_optionMenu $w.dest.remote_m push_remote \
|
||||
$all_remotes]
|
||||
$remmenu configure -font font_ui
|
||||
$w.dest.remote_m configure -font font_ui
|
||||
grid $w.dest.remote_r $w.dest.remote_m -sticky w
|
||||
if {[lsearch -sorted -exact $all_remotes origin] != -1} {
|
||||
set push_remote origin
|
||||
@@ -2757,8 +2768,9 @@ proc do_push_anywhere {} {
|
||||
set push_thin 0
|
||||
set push_tags 0
|
||||
|
||||
bind $w <Visibility> "grab $w"
|
||||
bind $w <Visibility> "grab $w; focus $w.buttons.create"
|
||||
bind $w <Key-Escape> "destroy $w"
|
||||
bind $w <Key-Return> [list start_push_anywhere_action $w]
|
||||
wm title $w "[appname] ([reponame]): Push"
|
||||
tkwait window $w
|
||||
}
|
||||
@@ -2773,8 +2785,7 @@ proc can_merge {} {
|
||||
if {[string match amend* $commit_type]} {
|
||||
info_popup {Cannot merge while amending.
|
||||
|
||||
You must finish amending this commit before
|
||||
starting any type of merge.
|
||||
You must finish amending this commit before starting any type of merge.
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -2788,9 +2799,7 @@ starting any type of merge.
|
||||
if {$commit_type ne $curType || $HEAD ne $curHEAD} {
|
||||
info_popup {Last scanned state does not match repository state.
|
||||
|
||||
Another Git program has modified this repository
|
||||
since the last scan. A rescan must be performed
|
||||
before a merge can be performed.
|
||||
Another Git program has modified this repository since the last scan. A rescan must be performed before a merge can be performed.
|
||||
|
||||
The rescan will be automatically started now.
|
||||
}
|
||||
@@ -2809,9 +2818,7 @@ The rescan will be automatically started now.
|
||||
|
||||
File [short_path $path] has merge conflicts.
|
||||
|
||||
You must resolve them, add the file, and commit to
|
||||
complete the current merge. Only then can you
|
||||
begin another merge.
|
||||
You must resolve them, add the file, and commit to complete the current merge. Only then can you begin another merge.
|
||||
"
|
||||
unlock_index
|
||||
return 0
|
||||
@@ -2821,9 +2828,7 @@ begin another merge.
|
||||
|
||||
File [short_path $path] is modified.
|
||||
|
||||
You should complete the current commit before
|
||||
starting a merge. Doing so will help you abort
|
||||
a failed merge, should the need arise.
|
||||
You should complete the current commit before starting a merge. Doing so will help you abort a failed merge, should the need arise.
|
||||
"
|
||||
unlock_index
|
||||
return 0
|
||||
@@ -2899,13 +2904,11 @@ proc finish_merge {revcnt w ok} {
|
||||
|
||||
Your merge of $revcnt branches has failed.
|
||||
|
||||
There are file-level conflicts between the
|
||||
branches which must be resolved manually.
|
||||
There are file-level conflicts between the branches which must be resolved manually.
|
||||
|
||||
The working directory will now be reset.
|
||||
|
||||
You can attempt this merge again
|
||||
by merging only one branch at a time." $w
|
||||
You can attempt this merge again by merging only one branch at a time." $w
|
||||
|
||||
set fd [open "| git read-tree --reset -u HEAD" r]
|
||||
fconfigure $fd -blocking 0 -translation binary
|
||||
@@ -3018,8 +3021,7 @@ You must finish amending this commit.
|
||||
|
||||
if {[ask_popup "Abort $op?
|
||||
|
||||
Aborting the current $op will cause
|
||||
*ALL* uncommitted changes to be lost.
|
||||
Aborting the current $op will cause *ALL* uncommitted changes to be lost.
|
||||
|
||||
Continue with aborting the current $op?"] eq {yes}} {
|
||||
set fd [open "| git read-tree --reset -u HEAD" r]
|
||||
@@ -3586,12 +3588,14 @@ proc read_blame_incremental {fd w w_load w_cmit w_line w_file} {
|
||||
proc blame_incremental_status {w} {
|
||||
global blame_status blame_data
|
||||
|
||||
set have $blame_data($w,blame_lines)
|
||||
set total $blame_data($w,total_lines)
|
||||
set pdone 0
|
||||
if {$total} {set pdone [expr {100 * $have / $total}]}
|
||||
|
||||
set blame_status($w) [format \
|
||||
"Loading annotations... %i of %i lines annotated (%2i%%)" \
|
||||
$blame_data($w,blame_lines) \
|
||||
$blame_data($w,total_lines) \
|
||||
[expr {100 * $blame_data($w,blame_lines)
|
||||
/ $blame_data($w,total_lines)}]]
|
||||
$have $total $pdone]
|
||||
}
|
||||
|
||||
proc blame_click {w w_cmit w_line w_file cur_w pos} {
|
||||
@@ -4089,6 +4093,7 @@ proc console_done {args} {
|
||||
if {[winfo exists $w]} {
|
||||
$w.m.s conf -background green -text {Success}
|
||||
$w.ok conf -state normal
|
||||
focus $w.ok
|
||||
}
|
||||
} else {
|
||||
if {![winfo exists $w]} {
|
||||
@@ -4096,6 +4101,7 @@ proc console_done {args} {
|
||||
}
|
||||
$w.m.s conf -background red -text {Error: Command Failed}
|
||||
$w.ok conf -state normal
|
||||
focus $w.ok
|
||||
}
|
||||
|
||||
array unset console_cr $w
|
||||
@@ -4163,9 +4169,11 @@ proc do_stats {} {
|
||||
frame $w.buttons -border 1
|
||||
button $w.buttons.close -text Close \
|
||||
-font font_ui \
|
||||
-default active \
|
||||
-command [list destroy $w]
|
||||
button $w.buttons.gc -text {Compress Database} \
|
||||
-font font_ui \
|
||||
-default normal \
|
||||
-command "destroy $w;do_gc"
|
||||
pack $w.buttons.close -side right
|
||||
pack $w.buttons.gc -side left
|
||||
@@ -4194,7 +4202,7 @@ proc do_stats {} {
|
||||
}
|
||||
pack $w.stat -pady 10 -padx 10
|
||||
|
||||
bind $w <Visibility> "grab $w; focus $w"
|
||||
bind $w <Visibility> "grab $w; focus $w.buttons.close"
|
||||
bind $w <Key-Escape> [list destroy $w]
|
||||
bind $w <Key-Return> [list destroy $w]
|
||||
wm title $w "[appname] ([reponame]): Database Statistics"
|
||||
@@ -4491,6 +4499,7 @@ proc do_about {} {
|
||||
frame $w.buttons
|
||||
button $w.buttons.close -text {Close} \
|
||||
-font font_ui \
|
||||
-default active \
|
||||
-command [list destroy $w]
|
||||
pack $w.buttons.close -side right
|
||||
pack $w.buttons -side bottom -fill x -pady 10 -padx 10
|
||||
@@ -4536,8 +4545,9 @@ $copyright" \
|
||||
clipboard append -format STRING -type STRING -- \[$w.vers cget -text\]
|
||||
"
|
||||
|
||||
bind $w <Visibility> "grab $w; focus $w"
|
||||
bind $w <Visibility> "grab $w; focus $w.buttons.close"
|
||||
bind $w <Key-Escape> "destroy $w"
|
||||
bind $w <Key-Return> "destroy $w"
|
||||
bind_button3 $w.vers "tk_popup $w.ctxm %X %Y; grab $w; focus $w"
|
||||
wm title $w "About [appname]"
|
||||
tkwait window $w
|
||||
@@ -4574,14 +4584,17 @@ proc do_options {} {
|
||||
frame $w.buttons
|
||||
button $w.buttons.restore -text {Restore Defaults} \
|
||||
-font font_ui \
|
||||
-default normal \
|
||||
-command do_restore_defaults
|
||||
pack $w.buttons.restore -side left
|
||||
button $w.buttons.save -text Save \
|
||||
-font font_ui \
|
||||
-default active \
|
||||
-command [list do_save_config $w]
|
||||
pack $w.buttons.save -side right
|
||||
button $w.buttons.cancel -text {Cancel} \
|
||||
-font font_ui \
|
||||
-default normal \
|
||||
-command [list destroy $w]
|
||||
pack $w.buttons.cancel -side right -padx 5
|
||||
pack $w.buttons -side bottom -fill x -pady 10 -padx 10
|
||||
@@ -4668,9 +4681,11 @@ proc do_options {} {
|
||||
frame $w.global.$name
|
||||
label $w.global.$name.l -text "$text:" -font font_ui
|
||||
pack $w.global.$name.l -side left -anchor w -fill x
|
||||
eval tk_optionMenu $w.global.$name.family \
|
||||
set fontmenu [eval tk_optionMenu $w.global.$name.family \
|
||||
global_config_new(gui.$font^^family) \
|
||||
$all_fonts
|
||||
$all_fonts]
|
||||
$w.global.$name.family configure -font font_ui
|
||||
$fontmenu configure -font font_ui
|
||||
spinbox $w.global.$name.size \
|
||||
-textvariable global_config_new(gui.$font^^size) \
|
||||
-from 2 -to 80 -increment 1 \
|
||||
@@ -4682,8 +4697,9 @@ proc do_options {} {
|
||||
pack $w.global.$name -side top -anchor w -fill x
|
||||
}
|
||||
|
||||
bind $w <Visibility> "grab $w; focus $w"
|
||||
bind $w <Visibility> "grab $w; focus $w.buttons.save"
|
||||
bind $w <Key-Escape> "destroy $w"
|
||||
bind $w <Key-Return> [list do_save_config $w]
|
||||
wm title $w "[appname] ([reponame]): Options"
|
||||
tkwait window $w
|
||||
}
|
||||
@@ -5065,18 +5081,18 @@ set ui_comm {}
|
||||
# -- Menu Bar
|
||||
#
|
||||
menu .mbar -tearoff 0
|
||||
.mbar add cascade -label Repository -menu .mbar.repository
|
||||
.mbar add cascade -label Edit -menu .mbar.edit
|
||||
.mbar add cascade -label Repository -menu .mbar.repository -font font_ui
|
||||
.mbar add cascade -label Edit -menu .mbar.edit -font font_ui
|
||||
if {[is_enabled branch]} {
|
||||
.mbar add cascade -label Branch -menu .mbar.branch
|
||||
.mbar add cascade -label Branch -menu .mbar.branch -font font_ui
|
||||
}
|
||||
if {[is_enabled multicommit] || [is_enabled singlecommit]} {
|
||||
.mbar add cascade -label Commit -menu .mbar.commit
|
||||
.mbar add cascade -label Commit -menu .mbar.commit -font font_ui
|
||||
}
|
||||
if {[is_enabled transport]} {
|
||||
.mbar add cascade -label Merge -menu .mbar.merge
|
||||
.mbar add cascade -label Fetch -menu .mbar.fetch
|
||||
.mbar add cascade -label Push -menu .mbar.push
|
||||
.mbar add cascade -label Merge -menu .mbar.merge -font font_ui
|
||||
.mbar add cascade -label Fetch -menu .mbar.fetch -font font_ui
|
||||
.mbar add cascade -label Push -menu .mbar.push -font font_ui
|
||||
}
|
||||
. configure -menu .mbar
|
||||
|
||||
@@ -5352,7 +5368,7 @@ if {[is_MacOSX]} {
|
||||
|
||||
# -- Help Menu
|
||||
#
|
||||
.mbar add cascade -label Help -menu .mbar.help
|
||||
.mbar add cascade -label Help -menu .mbar.help -font font_ui
|
||||
menu .mbar.help
|
||||
|
||||
if {![is_MacOSX]} {
|
||||
@@ -5935,7 +5951,7 @@ unset i
|
||||
set file_lists($ui_index) [list]
|
||||
set file_lists($ui_workdir) [list]
|
||||
|
||||
wm title . "[appname] ([file normalize [file dirname [gitdir]]])"
|
||||
wm title . "[appname] ([reponame]) [file normalize [file dirname [gitdir]]]"
|
||||
focus -force $ui_comm
|
||||
|
||||
# -- Warn the user about environmental problems. Cygwin's Tcl
|
||||
@@ -6014,9 +6030,7 @@ if {[is_enabled multicommit]} {
|
||||
if {[ask_popup \
|
||||
"This repository currently has $objects_current loose objects.
|
||||
|
||||
To maintain optimal performance it is strongly
|
||||
recommended that you compress the database
|
||||
when more than $object_limit loose objects exist.
|
||||
To maintain optimal performance it is strongly recommended that you compress the database when more than $object_limit loose objects exist.
|
||||
|
||||
Compress the database now?"] eq yes} {
|
||||
do_gc
|
||||
|
||||
@@ -446,9 +446,12 @@ sub send_message
|
||||
my ($name, $addr) = ($from =~ /^(.*?)(\s+<.*)/);
|
||||
$from = "\"$name\"$addr";
|
||||
}
|
||||
my $ccline = "";
|
||||
if ($cc ne '') {
|
||||
$ccline = "\nCc: $cc";
|
||||
}
|
||||
my $header = "From: $from
|
||||
To: $to
|
||||
Cc: $cc
|
||||
To: $to${ccline}
|
||||
Subject: $subject
|
||||
Date: $date
|
||||
Message-Id: $message_id
|
||||
|
||||
11
git-svn.perl
11
git-svn.perl
@@ -168,14 +168,14 @@ for (my $i = 0; $i < @ARGV; $i++) {
|
||||
my %opts = %{$cmd{$cmd}->[2]} if (defined $cmd);
|
||||
|
||||
read_repo_config(\%opts);
|
||||
Getopt::Long::Configure('pass_through') if $cmd eq 'log';
|
||||
Getopt::Long::Configure('pass_through') if ($cmd && $cmd eq 'log');
|
||||
my $rv = GetOptions(%opts, 'help|H|h' => \$_help, 'version|V' => \$_version,
|
||||
'minimize-connections' => \$Git::SVN::Migration::_minimize,
|
||||
'id|i=s' => \$Git::SVN::default_ref_id,
|
||||
'svn-remote|remote|R=s' => sub {
|
||||
$Git::SVN::no_reuse_existing = 1;
|
||||
$Git::SVN::default_repo_id = $_[1] });
|
||||
exit 1 if (!$rv && $cmd ne 'log');
|
||||
exit 1 if (!$rv && $cmd && $cmd ne 'log');
|
||||
|
||||
usage(0) if $_help;
|
||||
version() if $_version;
|
||||
@@ -1682,7 +1682,10 @@ sub find_parent_branch {
|
||||
}
|
||||
my ($r0, $parent) = $gs->find_rev_before($r, 1);
|
||||
if (!defined $r0 || !defined $parent) {
|
||||
$gs->fetch(0, $r);
|
||||
my ($base, $head) = parse_revision_argument(0, $r);
|
||||
if ($base <= $r) {
|
||||
$gs->fetch($base, $r);
|
||||
}
|
||||
($r0, $parent) = $gs->last_rev_commit;
|
||||
}
|
||||
if (defined $r0 && defined $parent) {
|
||||
@@ -3159,6 +3162,8 @@ sub match_globs {
|
||||
my $p = $1;
|
||||
my $pathname = $g->{path}->full_path($p);
|
||||
next if $exists->{$pathname};
|
||||
next if ($self->check_path($pathname, $r) !=
|
||||
$SVN::Node::dir);
|
||||
$exists->{$pathname} = Git::SVN->init(
|
||||
$self->{url}, $pathname, undef,
|
||||
$g->{ref}->full_path($p), 1);
|
||||
|
||||
21
log-tree.c
21
log-tree.c
@@ -4,6 +4,8 @@
|
||||
#include "log-tree.h"
|
||||
#include "reflog-walk.h"
|
||||
|
||||
struct decoration name_decoration = { "object names" };
|
||||
|
||||
static void show_parents(struct commit *commit, int abbrev)
|
||||
{
|
||||
struct commit_list *p;
|
||||
@@ -13,6 +15,23 @@ static void show_parents(struct commit *commit, int abbrev)
|
||||
}
|
||||
}
|
||||
|
||||
static void show_decorations(struct commit *commit)
|
||||
{
|
||||
const char *prefix;
|
||||
struct name_decoration *decoration;
|
||||
|
||||
decoration = lookup_decoration(&name_decoration, &commit->object);
|
||||
if (!decoration)
|
||||
return;
|
||||
prefix = " (";
|
||||
while (decoration) {
|
||||
printf("%s%s", prefix, decoration->name);
|
||||
prefix = ", ";
|
||||
decoration = decoration->next;
|
||||
}
|
||||
putchar(')');
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for "^[-A-Za-z]+: [^@]+@" pattern. It usually matches
|
||||
* Signed-off-by: and Acked-by: lines.
|
||||
@@ -136,6 +155,7 @@ void show_log(struct rev_info *opt, const char *sep)
|
||||
fputs(diff_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);
|
||||
if (opt->parents)
|
||||
show_parents(commit, abbrev_commit);
|
||||
show_decorations(commit);
|
||||
putchar(opt->diffopt.line_termination);
|
||||
return;
|
||||
}
|
||||
@@ -240,6 +260,7 @@ void show_log(struct rev_info *opt, const char *sep)
|
||||
printf(" (from %s)",
|
||||
diff_unique_abbrev(parent->object.sha1,
|
||||
abbrev_commit));
|
||||
show_decorations(commit);
|
||||
printf("%s",
|
||||
diff_get_color(opt->diffopt.color_diff, DIFF_RESET));
|
||||
putchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\n');
|
||||
|
||||
@@ -95,11 +95,6 @@ static struct path_list current_directory_set = {NULL, 0, 0, 1};
|
||||
static int call_depth = 0;
|
||||
static int verbosity = 2;
|
||||
static int buffer_output = 1;
|
||||
static int do_progress = 1;
|
||||
static unsigned last_percent;
|
||||
static unsigned merged_cnt;
|
||||
static unsigned total_cnt;
|
||||
static volatile sig_atomic_t progress_update;
|
||||
static struct output_buffer *output_list, *output_end;
|
||||
|
||||
static int show (int v)
|
||||
@@ -174,39 +169,6 @@ static void output_commit_title(struct commit *commit)
|
||||
}
|
||||
}
|
||||
|
||||
static void progress_interval(int signum)
|
||||
{
|
||||
progress_update = 1;
|
||||
}
|
||||
|
||||
static void setup_progress_signal(void)
|
||||
{
|
||||
struct sigaction sa;
|
||||
struct itimerval v;
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = progress_interval;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sigaction(SIGALRM, &sa, NULL);
|
||||
|
||||
v.it_interval.tv_sec = 1;
|
||||
v.it_interval.tv_usec = 0;
|
||||
v.it_value = v.it_interval;
|
||||
setitimer(ITIMER_REAL, &v, NULL);
|
||||
}
|
||||
|
||||
static void display_progress()
|
||||
{
|
||||
unsigned percent = total_cnt ? merged_cnt * 100 / total_cnt : 0;
|
||||
if (progress_update || percent != last_percent) {
|
||||
fprintf(stderr, "%4u%% (%u/%u) done\r",
|
||||
percent, merged_cnt, total_cnt);
|
||||
progress_update = 0;
|
||||
last_percent = percent;
|
||||
}
|
||||
}
|
||||
|
||||
static struct cache_entry *make_cache_entry(unsigned int mode,
|
||||
const unsigned char *sha1, const char *path, int stage, int refresh)
|
||||
{
|
||||
@@ -377,14 +339,11 @@ static struct path_list *get_unmerged(void)
|
||||
int i;
|
||||
|
||||
unmerged->strdup_paths = 1;
|
||||
total_cnt += active_nr;
|
||||
|
||||
for (i = 0; i < active_nr; i++, merged_cnt++) {
|
||||
for (i = 0; i < active_nr; i++) {
|
||||
struct path_list_item *item;
|
||||
struct stage_data *e;
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
if (do_progress)
|
||||
display_progress();
|
||||
if (!ce_stage(ce))
|
||||
continue;
|
||||
|
||||
@@ -574,6 +533,31 @@ static void flush_buffer(int fd, const char *buf, unsigned long size)
|
||||
}
|
||||
}
|
||||
|
||||
static int make_room_for_path(const char *path)
|
||||
{
|
||||
int status;
|
||||
const char *msg = "failed to create path '%s'%s";
|
||||
|
||||
status = mkdir_p(path, 0777);
|
||||
if (status) {
|
||||
if (status == -3) {
|
||||
/* something else exists */
|
||||
error(msg, path, ": perhaps a D/F conflict?");
|
||||
return -1;
|
||||
}
|
||||
die(msg, path, "");
|
||||
}
|
||||
|
||||
/* Successful unlink is good.. */
|
||||
if (!unlink(path))
|
||||
return 0;
|
||||
/* .. and so is no existing file */
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
/* .. but not some other error (who really cares what?) */
|
||||
return error(msg, path, ": perhaps a D/F conflict?");
|
||||
}
|
||||
|
||||
static void update_file_flags(const unsigned char *sha,
|
||||
unsigned mode,
|
||||
const char *path,
|
||||
@@ -594,11 +578,12 @@ static void update_file_flags(const unsigned char *sha,
|
||||
if (type != OBJ_BLOB)
|
||||
die("blob expected for %s '%s'", sha1_to_hex(sha), path);
|
||||
|
||||
if (make_room_for_path(path) < 0) {
|
||||
update_wd = 0;
|
||||
goto update_index;
|
||||
}
|
||||
if (S_ISREG(mode) || (!has_symlinks && S_ISLNK(mode))) {
|
||||
int fd;
|
||||
if (mkdir_p(path, 0777))
|
||||
die("failed to create path %s: %s", path, strerror(errno));
|
||||
unlink(path);
|
||||
if (mode & 0100)
|
||||
mode = 0777;
|
||||
else
|
||||
@@ -620,6 +605,7 @@ static void update_file_flags(const unsigned char *sha,
|
||||
die("do not know what to do with %06o %s '%s'",
|
||||
mode, sha1_to_hex(sha), path);
|
||||
}
|
||||
update_index:
|
||||
if (update_cache)
|
||||
add_cacheinfo(mode, sha, path, 0, update_wd, ADD_CACHE_OK_TO_ADD);
|
||||
}
|
||||
@@ -1018,9 +1004,9 @@ static int process_renames(struct path_list *a_renames,
|
||||
return clean_merge;
|
||||
}
|
||||
|
||||
static unsigned char *has_sha(const unsigned char *sha)
|
||||
static unsigned char *stage_sha(const unsigned char *sha, unsigned mode)
|
||||
{
|
||||
return is_null_sha1(sha) ? NULL: (unsigned char *)sha;
|
||||
return (is_null_sha1(sha) || mode == 0) ? NULL: (unsigned char *)sha;
|
||||
}
|
||||
|
||||
/* Per entry merge function */
|
||||
@@ -1033,12 +1019,12 @@ static int process_entry(const char *path, struct stage_data *entry,
|
||||
print_index_entry("\tpath: ", entry);
|
||||
*/
|
||||
int clean_merge = 1;
|
||||
unsigned char *o_sha = has_sha(entry->stages[1].sha);
|
||||
unsigned char *a_sha = has_sha(entry->stages[2].sha);
|
||||
unsigned char *b_sha = has_sha(entry->stages[3].sha);
|
||||
unsigned o_mode = entry->stages[1].mode;
|
||||
unsigned a_mode = entry->stages[2].mode;
|
||||
unsigned b_mode = entry->stages[3].mode;
|
||||
unsigned char *o_sha = stage_sha(entry->stages[1].sha, o_mode);
|
||||
unsigned char *a_sha = stage_sha(entry->stages[2].sha, a_mode);
|
||||
unsigned char *b_sha = stage_sha(entry->stages[3].sha, b_mode);
|
||||
|
||||
if (o_sha && (!a_sha || !b_sha)) {
|
||||
/* Case A: Deleted in one */
|
||||
@@ -1139,6 +1125,12 @@ static int process_entry(const char *path, struct stage_data *entry,
|
||||
update_file_flags(mfi.sha, mfi.mode, path,
|
||||
0 /* update_cache */, 1 /* update_working_directory */);
|
||||
}
|
||||
} else if (!o_sha && !a_sha && !b_sha) {
|
||||
/*
|
||||
* this entry was deleted altogether. a_mode == 0 means
|
||||
* we had that path and want to actively remove it.
|
||||
*/
|
||||
remove_file(1, path, !a_mode);
|
||||
} else
|
||||
die("Fatal merge failure, shouldn't happen.");
|
||||
|
||||
@@ -1185,15 +1177,12 @@ static int merge_trees(struct tree *head,
|
||||
re_merge = get_renames(merge, common, head, merge, entries);
|
||||
clean = process_renames(re_head, re_merge,
|
||||
branch1, branch2);
|
||||
total_cnt += entries->nr;
|
||||
for (i = 0; i < entries->nr; i++, merged_cnt++) {
|
||||
for (i = 0; i < entries->nr; i++) {
|
||||
const char *path = entries->items[i].path;
|
||||
struct stage_data *e = entries->items[i].util;
|
||||
if (!e->processed
|
||||
&& !process_entry(path, e, branch1, branch2))
|
||||
clean = 0;
|
||||
if (do_progress)
|
||||
display_progress();
|
||||
}
|
||||
|
||||
path_list_clear(re_merge, 0);
|
||||
@@ -1301,15 +1290,6 @@ static int merge(struct commit *h1,
|
||||
commit_list_insert(h1, &(*result)->parents);
|
||||
commit_list_insert(h2, &(*result)->parents->next);
|
||||
}
|
||||
if (!call_depth && do_progress) {
|
||||
/* Make sure we end at 100% */
|
||||
if (!total_cnt)
|
||||
total_cnt = 1;
|
||||
merged_cnt = total_cnt;
|
||||
progress_update = 1;
|
||||
display_progress();
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
flush_output();
|
||||
return clean;
|
||||
}
|
||||
@@ -1386,12 +1366,8 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
if (argc - i != 3) /* "--" "<head>" "<remote>" */
|
||||
die("Not handling anything other than two heads merge.");
|
||||
if (verbosity >= 5) {
|
||||
if (verbosity >= 5)
|
||||
buffer_output = 0;
|
||||
do_progress = 0;
|
||||
}
|
||||
else
|
||||
do_progress = isatty(1);
|
||||
|
||||
branch1 = argv[++i];
|
||||
branch2 = argv[++i];
|
||||
@@ -1402,8 +1378,6 @@ int main(int argc, char *argv[])
|
||||
branch1 = better_branch_name(branch1);
|
||||
branch2 = better_branch_name(branch2);
|
||||
|
||||
if (do_progress)
|
||||
setup_progress_signal();
|
||||
if (show(3))
|
||||
printf("Merging %s with %s\n", branch1, branch2);
|
||||
|
||||
|
||||
@@ -1,75 +1,20 @@
|
||||
#include "cache.h"
|
||||
#include "object.h"
|
||||
#include "decorate.h"
|
||||
|
||||
int track_object_refs = 0;
|
||||
|
||||
static unsigned int refs_hash_size, nr_object_refs;
|
||||
static struct object_refs **refs_hash;
|
||||
static struct decoration ref_decorate;
|
||||
|
||||
static unsigned int hash_obj(struct object *obj, unsigned int n)
|
||||
struct object_refs *lookup_object_refs(struct object *base)
|
||||
{
|
||||
unsigned int hash = *(unsigned int *)obj->sha1;
|
||||
return hash % n;
|
||||
return lookup_decoration(&ref_decorate, base);
|
||||
}
|
||||
|
||||
static void insert_ref_hash(struct object_refs *ref, struct object_refs **hash, unsigned int size)
|
||||
static void add_object_refs(struct object *obj, struct object_refs *refs)
|
||||
{
|
||||
int j = hash_obj(ref->base, size);
|
||||
|
||||
while (hash[j]) {
|
||||
j++;
|
||||
if (j >= size)
|
||||
j = 0;
|
||||
}
|
||||
hash[j] = ref;
|
||||
}
|
||||
|
||||
static void grow_refs_hash(void)
|
||||
{
|
||||
int i;
|
||||
int new_hash_size = (refs_hash_size + 1000) * 3 / 2;
|
||||
struct object_refs **new_hash;
|
||||
|
||||
new_hash = xcalloc(new_hash_size, sizeof(struct object_refs *));
|
||||
for (i = 0; i < refs_hash_size; i++) {
|
||||
struct object_refs *ref = refs_hash[i];
|
||||
if (!ref)
|
||||
continue;
|
||||
insert_ref_hash(ref, new_hash, new_hash_size);
|
||||
}
|
||||
free(refs_hash);
|
||||
refs_hash = new_hash;
|
||||
refs_hash_size = new_hash_size;
|
||||
}
|
||||
|
||||
static void add_object_refs(struct object *obj, struct object_refs *ref)
|
||||
{
|
||||
int nr = nr_object_refs + 1;
|
||||
|
||||
if (nr > refs_hash_size * 2 / 3)
|
||||
grow_refs_hash();
|
||||
ref->base = obj;
|
||||
insert_ref_hash(ref, refs_hash, refs_hash_size);
|
||||
nr_object_refs = nr;
|
||||
}
|
||||
|
||||
struct object_refs *lookup_object_refs(struct object *obj)
|
||||
{
|
||||
struct object_refs *ref;
|
||||
int j;
|
||||
|
||||
/* nothing to lookup */
|
||||
if (!refs_hash_size)
|
||||
return NULL;
|
||||
j = hash_obj(obj, refs_hash_size);
|
||||
while ((ref = refs_hash[j]) != NULL) {
|
||||
if (ref->base == obj)
|
||||
break;
|
||||
j++;
|
||||
if (j >= refs_hash_size)
|
||||
j = 0;
|
||||
}
|
||||
return ref;
|
||||
if (add_decoration(&ref_decorate, obj, refs))
|
||||
die("object %s tried to add refs twice!", sha1_to_hex(obj->sha1));
|
||||
}
|
||||
|
||||
struct object_refs *alloc_object_refs(unsigned count)
|
||||
|
||||
1
object.h
1
object.h
@@ -8,7 +8,6 @@ struct object_list {
|
||||
|
||||
struct object_refs {
|
||||
unsigned count;
|
||||
struct object *base;
|
||||
struct object *ref[FLEX_ARRAY]; /* more */
|
||||
};
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ my %pm = ('Git.pm' => '$(INST_LIBDIR)/Git.pm');
|
||||
# We come with our own bundled Error.pm. It's not in the set of default
|
||||
# Perl modules so install it if it's not available on the system yet.
|
||||
eval { require Error };
|
||||
if ($@) {
|
||||
if ($@ || $Error::VERSION < 0.15009) {
|
||||
$pm{'private-Error.pm'} = '$(INST_LIBDIR)/Error.pm';
|
||||
}
|
||||
|
||||
|
||||
2
refs.c
2
refs.c
@@ -705,7 +705,7 @@ static int repack_without_ref(const char *refname)
|
||||
return commit_lock_file(&packlock);
|
||||
}
|
||||
|
||||
int delete_ref(const char *refname, unsigned char *sha1)
|
||||
int delete_ref(const char *refname, const unsigned char *sha1)
|
||||
{
|
||||
struct ref_lock *lock;
|
||||
int err, i, ret = 0, flag = 0;
|
||||
|
||||
0
t/diff-lib.sh
Executable file → Normal file
0
t/diff-lib.sh
Executable file → Normal file
0
t/lib-read-tree-m-3way.sh
Executable file → Normal file
0
t/lib-read-tree-m-3way.sh
Executable file → Normal file
@@ -184,7 +184,7 @@ checked.
|
||||
9 exists O!=A missing no merge must match A and be
|
||||
up-to-date, if exists.
|
||||
------------------------------------------------------------------
|
||||
10 exists O==A missing remove ditto
|
||||
10 exists O==A missing no merge must match A
|
||||
------------------------------------------------------------------
|
||||
11 exists O!=A O!=B no merge must match A and be
|
||||
A!=B up-to-date, if exists.
|
||||
|
||||
528
t/t3030-merge-recursive.sh
Executable file
528
t/t3030-merge-recursive.sh
Executable file
@@ -0,0 +1,528 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='merge-recursive backend test'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'setup 1' '
|
||||
|
||||
echo hello >a &&
|
||||
o0=$(git hash-object a) &&
|
||||
cp a b &&
|
||||
cp a c &&
|
||||
mkdir d &&
|
||||
cp a d/e &&
|
||||
|
||||
test_tick &&
|
||||
git add a b c d/e &&
|
||||
git commit -m initial &&
|
||||
c0=$(git rev-parse --verify HEAD) &&
|
||||
git branch side &&
|
||||
git branch df-1 &&
|
||||
git branch df-2 &&
|
||||
git branch df-3 &&
|
||||
git branch remove &&
|
||||
|
||||
echo hello >>a &&
|
||||
cp a d/e &&
|
||||
o1=$(git hash-object a) &&
|
||||
|
||||
git add a d/e &&
|
||||
|
||||
test_tick &&
|
||||
git commit -m "master modifies a and d/e" &&
|
||||
c1=$(git rev-parse --verify HEAD) &&
|
||||
( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
|
||||
(
|
||||
echo "100644 blob $o1 a"
|
||||
echo "100644 blob $o0 b"
|
||||
echo "100644 blob $o0 c"
|
||||
echo "100644 blob $o1 d/e"
|
||||
echo "100644 $o1 0 a"
|
||||
echo "100644 $o0 0 b"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o1 0 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'setup 2' '
|
||||
|
||||
rm -rf [abcd] &&
|
||||
git checkout side &&
|
||||
( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
|
||||
(
|
||||
echo "100644 blob $o0 a"
|
||||
echo "100644 blob $o0 b"
|
||||
echo "100644 blob $o0 c"
|
||||
echo "100644 blob $o0 d/e"
|
||||
echo "100644 $o0 0 a"
|
||||
echo "100644 $o0 0 b"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o0 0 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual &&
|
||||
|
||||
echo goodbye >>a &&
|
||||
o2=$(git hash-object a) &&
|
||||
|
||||
git add a &&
|
||||
|
||||
test_tick &&
|
||||
git commit -m "side modifies a" &&
|
||||
c2=$(git rev-parse --verify HEAD) &&
|
||||
( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
|
||||
(
|
||||
echo "100644 blob $o2 a"
|
||||
echo "100644 blob $o0 b"
|
||||
echo "100644 blob $o0 c"
|
||||
echo "100644 blob $o0 d/e"
|
||||
echo "100644 $o2 0 a"
|
||||
echo "100644 $o0 0 b"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o0 0 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'setup 3' '
|
||||
|
||||
rm -rf [abcd] &&
|
||||
git checkout df-1 &&
|
||||
( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
|
||||
(
|
||||
echo "100644 blob $o0 a"
|
||||
echo "100644 blob $o0 b"
|
||||
echo "100644 blob $o0 c"
|
||||
echo "100644 blob $o0 d/e"
|
||||
echo "100644 $o0 0 a"
|
||||
echo "100644 $o0 0 b"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o0 0 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual &&
|
||||
|
||||
rm -f b && mkdir b && echo df-1 >b/c && git add b/c &&
|
||||
o3=$(git hash-object b/c) &&
|
||||
|
||||
test_tick &&
|
||||
git commit -m "df-1 makes b/c" &&
|
||||
c3=$(git rev-parse --verify HEAD) &&
|
||||
( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
|
||||
(
|
||||
echo "100644 blob $o0 a"
|
||||
echo "100644 blob $o3 b/c"
|
||||
echo "100644 blob $o0 c"
|
||||
echo "100644 blob $o0 d/e"
|
||||
echo "100644 $o0 0 a"
|
||||
echo "100644 $o3 0 b/c"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o0 0 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'setup 4' '
|
||||
|
||||
rm -rf [abcd] &&
|
||||
git checkout df-2 &&
|
||||
( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
|
||||
(
|
||||
echo "100644 blob $o0 a"
|
||||
echo "100644 blob $o0 b"
|
||||
echo "100644 blob $o0 c"
|
||||
echo "100644 blob $o0 d/e"
|
||||
echo "100644 $o0 0 a"
|
||||
echo "100644 $o0 0 b"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o0 0 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual &&
|
||||
|
||||
rm -f a && mkdir a && echo df-2 >a/c && git add a/c &&
|
||||
o4=$(git hash-object a/c) &&
|
||||
|
||||
test_tick &&
|
||||
git commit -m "df-2 makes a/c" &&
|
||||
c4=$(git rev-parse --verify HEAD) &&
|
||||
( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
|
||||
(
|
||||
echo "100644 blob $o4 a/c"
|
||||
echo "100644 blob $o0 b"
|
||||
echo "100644 blob $o0 c"
|
||||
echo "100644 blob $o0 d/e"
|
||||
echo "100644 $o4 0 a/c"
|
||||
echo "100644 $o0 0 b"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o0 0 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'setup 5' '
|
||||
|
||||
rm -rf [abcd] &&
|
||||
git checkout remove &&
|
||||
( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
|
||||
(
|
||||
echo "100644 blob $o0 a"
|
||||
echo "100644 blob $o0 b"
|
||||
echo "100644 blob $o0 c"
|
||||
echo "100644 blob $o0 d/e"
|
||||
echo "100644 $o0 0 a"
|
||||
echo "100644 $o0 0 b"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o0 0 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual &&
|
||||
|
||||
rm -f b &&
|
||||
echo remove-conflict >a &&
|
||||
|
||||
git add a &&
|
||||
git rm b &&
|
||||
o5=$(git hash-object a) &&
|
||||
|
||||
test_tick &&
|
||||
git commit -m "remove removes b and modifies a" &&
|
||||
c5=$(git rev-parse --verify HEAD) &&
|
||||
( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
|
||||
(
|
||||
echo "100644 blob $o5 a"
|
||||
echo "100644 blob $o0 c"
|
||||
echo "100644 blob $o0 d/e"
|
||||
echo "100644 $o5 0 a"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o0 0 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'setup 6' '
|
||||
|
||||
rm -rf [abcd] &&
|
||||
git checkout df-3 &&
|
||||
( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
|
||||
(
|
||||
echo "100644 blob $o0 a"
|
||||
echo "100644 blob $o0 b"
|
||||
echo "100644 blob $o0 c"
|
||||
echo "100644 blob $o0 d/e"
|
||||
echo "100644 $o0 0 a"
|
||||
echo "100644 $o0 0 b"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o0 0 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual &&
|
||||
|
||||
rm -fr d && echo df-3 >d && git add d &&
|
||||
o6=$(git hash-object d) &&
|
||||
|
||||
test_tick &&
|
||||
git commit -m "df-3 makes d" &&
|
||||
c6=$(git rev-parse --verify HEAD) &&
|
||||
( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
|
||||
(
|
||||
echo "100644 blob $o0 a"
|
||||
echo "100644 blob $o0 b"
|
||||
echo "100644 blob $o0 c"
|
||||
echo "100644 blob $o6 d"
|
||||
echo "100644 $o0 0 a"
|
||||
echo "100644 $o0 0 b"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o6 0 d"
|
||||
) >expected &&
|
||||
git diff -u expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'merge-recursive simple' '
|
||||
|
||||
rm -fr [abcd] &&
|
||||
git checkout -f "$c2" &&
|
||||
|
||||
git-merge-recursive "$c0" -- "$c2" "$c1"
|
||||
status=$?
|
||||
case "$status" in
|
||||
1)
|
||||
: happy
|
||||
;;
|
||||
*)
|
||||
echo >&2 "why status $status!!!"
|
||||
false
|
||||
;;
|
||||
esac
|
||||
'
|
||||
|
||||
test_expect_success 'merge-recursive result' '
|
||||
|
||||
git ls-files -s >actual &&
|
||||
(
|
||||
echo "100644 $o0 1 a"
|
||||
echo "100644 $o2 2 a"
|
||||
echo "100644 $o1 3 a"
|
||||
echo "100644 $o0 0 b"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o1 0 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'merge-recursive remove conflict' '
|
||||
|
||||
rm -fr [abcd] &&
|
||||
git checkout -f "$c1" &&
|
||||
|
||||
git-merge-recursive "$c0" -- "$c1" "$c5"
|
||||
status=$?
|
||||
case "$status" in
|
||||
1)
|
||||
: happy
|
||||
;;
|
||||
*)
|
||||
echo >&2 "why status $status!!!"
|
||||
false
|
||||
;;
|
||||
esac
|
||||
'
|
||||
|
||||
test_expect_success 'merge-recursive remove conflict' '
|
||||
|
||||
git ls-files -s >actual &&
|
||||
(
|
||||
echo "100644 $o0 1 a"
|
||||
echo "100644 $o1 2 a"
|
||||
echo "100644 $o5 3 a"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o1 0 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'merge-recursive d/f simple' '
|
||||
rm -fr [abcd] &&
|
||||
git reset --hard &&
|
||||
git checkout -f "$c1" &&
|
||||
|
||||
git-merge-recursive "$c0" -- "$c1" "$c3"
|
||||
'
|
||||
|
||||
test_expect_success 'merge-recursive result' '
|
||||
|
||||
git ls-files -s >actual &&
|
||||
(
|
||||
echo "100644 $o1 0 a"
|
||||
echo "100644 $o3 0 b/c"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o1 0 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'merge-recursive d/f conflict' '
|
||||
|
||||
rm -fr [abcd] &&
|
||||
git reset --hard &&
|
||||
git checkout -f "$c1" &&
|
||||
|
||||
git-merge-recursive "$c0" -- "$c1" "$c4"
|
||||
status=$?
|
||||
case "$status" in
|
||||
1)
|
||||
: happy
|
||||
;;
|
||||
*)
|
||||
echo >&2 "why status $status!!!"
|
||||
false
|
||||
;;
|
||||
esac
|
||||
'
|
||||
|
||||
test_expect_success 'merge-recursive d/f conflict result' '
|
||||
|
||||
git ls-files -s >actual &&
|
||||
(
|
||||
echo "100644 $o0 1 a"
|
||||
echo "100644 $o1 2 a"
|
||||
echo "100644 $o4 0 a/c"
|
||||
echo "100644 $o0 0 b"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o1 0 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'merge-recursive d/f conflict the other way' '
|
||||
|
||||
rm -fr [abcd] &&
|
||||
git reset --hard &&
|
||||
git checkout -f "$c4" &&
|
||||
|
||||
git-merge-recursive "$c0" -- "$c4" "$c1"
|
||||
status=$?
|
||||
case "$status" in
|
||||
1)
|
||||
: happy
|
||||
;;
|
||||
*)
|
||||
echo >&2 "why status $status!!!"
|
||||
false
|
||||
;;
|
||||
esac
|
||||
'
|
||||
|
||||
test_expect_success 'merge-recursive d/f conflict result the other way' '
|
||||
|
||||
git ls-files -s >actual &&
|
||||
(
|
||||
echo "100644 $o0 1 a"
|
||||
echo "100644 $o1 3 a"
|
||||
echo "100644 $o4 0 a/c"
|
||||
echo "100644 $o0 0 b"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o1 0 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'merge-recursive d/f conflict' '
|
||||
|
||||
rm -fr [abcd] &&
|
||||
git reset --hard &&
|
||||
git checkout -f "$c1" &&
|
||||
|
||||
git-merge-recursive "$c0" -- "$c1" "$c6"
|
||||
status=$?
|
||||
case "$status" in
|
||||
1)
|
||||
: happy
|
||||
;;
|
||||
*)
|
||||
echo >&2 "why status $status!!!"
|
||||
false
|
||||
;;
|
||||
esac
|
||||
'
|
||||
|
||||
test_expect_success 'merge-recursive d/f conflict result' '
|
||||
|
||||
git ls-files -s >actual &&
|
||||
(
|
||||
echo "100644 $o1 0 a"
|
||||
echo "100644 $o0 0 b"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o6 3 d"
|
||||
echo "100644 $o0 1 d/e"
|
||||
echo "100644 $o1 2 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'merge-recursive d/f conflict' '
|
||||
|
||||
rm -fr [abcd] &&
|
||||
git reset --hard &&
|
||||
git checkout -f "$c6" &&
|
||||
|
||||
git-merge-recursive "$c0" -- "$c6" "$c1"
|
||||
status=$?
|
||||
case "$status" in
|
||||
1)
|
||||
: happy
|
||||
;;
|
||||
*)
|
||||
echo >&2 "why status $status!!!"
|
||||
false
|
||||
;;
|
||||
esac
|
||||
'
|
||||
|
||||
test_expect_success 'merge-recursive d/f conflict result' '
|
||||
|
||||
git ls-files -s >actual &&
|
||||
(
|
||||
echo "100644 $o1 0 a"
|
||||
echo "100644 $o0 0 b"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o6 2 d"
|
||||
echo "100644 $o0 1 d/e"
|
||||
echo "100644 $o1 3 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'reset and 3-way merge' '
|
||||
|
||||
git reset --hard "$c2" &&
|
||||
git read-tree -m "$c0" "$c2" "$c1"
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'reset and bind merge' '
|
||||
|
||||
git reset --hard master &&
|
||||
git read-tree --prefix=M/ master &&
|
||||
git ls-files -s >actual &&
|
||||
(
|
||||
echo "100644 $o1 0 M/a"
|
||||
echo "100644 $o0 0 M/b"
|
||||
echo "100644 $o0 0 M/c"
|
||||
echo "100644 $o1 0 M/d/e"
|
||||
echo "100644 $o1 0 a"
|
||||
echo "100644 $o0 0 b"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o1 0 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual &&
|
||||
|
||||
git read-tree --prefix=a1/ master &&
|
||||
git ls-files -s >actual &&
|
||||
(
|
||||
echo "100644 $o1 0 M/a"
|
||||
echo "100644 $o0 0 M/b"
|
||||
echo "100644 $o0 0 M/c"
|
||||
echo "100644 $o1 0 M/d/e"
|
||||
echo "100644 $o1 0 a"
|
||||
echo "100644 $o1 0 a1/a"
|
||||
echo "100644 $o0 0 a1/b"
|
||||
echo "100644 $o0 0 a1/c"
|
||||
echo "100644 $o1 0 a1/d/e"
|
||||
echo "100644 $o0 0 b"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o1 0 d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual
|
||||
|
||||
git read-tree --prefix=z/ master &&
|
||||
git ls-files -s >actual &&
|
||||
(
|
||||
echo "100644 $o1 0 M/a"
|
||||
echo "100644 $o0 0 M/b"
|
||||
echo "100644 $o0 0 M/c"
|
||||
echo "100644 $o1 0 M/d/e"
|
||||
echo "100644 $o1 0 a"
|
||||
echo "100644 $o1 0 a1/a"
|
||||
echo "100644 $o0 0 a1/b"
|
||||
echo "100644 $o0 0 a1/c"
|
||||
echo "100644 $o1 0 a1/d/e"
|
||||
echo "100644 $o0 0 b"
|
||||
echo "100644 $o0 0 c"
|
||||
echo "100644 $o1 0 d/e"
|
||||
echo "100644 $o1 0 z/a"
|
||||
echo "100644 $o0 0 z/b"
|
||||
echo "100644 $o0 0 z/c"
|
||||
echo "100644 $o1 0 z/d/e"
|
||||
) >expected &&
|
||||
git diff -u expected actual
|
||||
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -84,6 +84,10 @@ test_expect_success \
|
||||
'When the rm in "git-rm -f" fails, it should not remove the file from the index' \
|
||||
'git-ls-files --error-unmatch baz'
|
||||
|
||||
test_expect_success 'Remove nonexistent file with --ignore-unmatch' '
|
||||
git rm --ignore-unmatch nonexistent
|
||||
'
|
||||
|
||||
test_expect_success '"rm" command printed' '
|
||||
echo frotz > test-file &&
|
||||
git add test-file &&
|
||||
|
||||
33
t/t4121-apply-diffs.sh
Executable file
33
t/t4121-apply-diffs.sh
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='git-apply for contextually independent diffs'
|
||||
. ./test-lib.sh
|
||||
|
||||
echo '1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8' >file
|
||||
|
||||
test_expect_success 'setup' \
|
||||
'git add file &&
|
||||
git commit -q -m 1 &&
|
||||
git checkout -b test &&
|
||||
mv file file.tmp &&
|
||||
echo 0 >file &&
|
||||
cat file.tmp >>file &&
|
||||
rm file.tmp &&
|
||||
git commit -a -q -m 2 &&
|
||||
echo 9 >>file &&
|
||||
git commit -a -q -m 3 &&
|
||||
git checkout master'
|
||||
|
||||
test_expect_success \
|
||||
'check if contextually independent diffs for the same file apply' \
|
||||
'( git diff test~2 test~1; git diff test~1 test~0 )| git apply'
|
||||
|
||||
test_done
|
||||
|
||||
50
t/t4201-shortlog.sh
Executable file
50
t/t4201-shortlog.sh
Executable file
@@ -0,0 +1,50 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2006 Johannes E. Schindelin
|
||||
#
|
||||
|
||||
test_description='git-shortlog
|
||||
'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
echo 1 > a1
|
||||
git add a1
|
||||
tree=$(git write-tree)
|
||||
commit=$( (echo "Test"; echo) | git commit-tree $tree )
|
||||
git update-ref HEAD $commit
|
||||
|
||||
echo 2 > a1
|
||||
git commit -m "This is a very, very long first line for the commit message to see if it is wrapped correctly" a1
|
||||
|
||||
# test if the wrapping is still valid when replacing all i's by treble clefs.
|
||||
echo 3 > a1
|
||||
git commit -m "$(echo "This is a very, very long first line for the commit message to see if it is wrapped correctly" | sed "s/i/1234/g" | tr 1234 '\360\235\204\236')" a1
|
||||
|
||||
# now fsck up the utf8
|
||||
git repo-config i18n.commitencoding non-utf-8
|
||||
echo 4 > a1
|
||||
git commit -m "$(echo "This is a very, very long first line for the commit message to see if it is wrapped correctly" | sed "s/i/1234/g" | tr 1234 '\370\235\204\236')" a1
|
||||
|
||||
echo 5 > a1
|
||||
git commit -m "a 12 34 56 78" a1
|
||||
|
||||
git shortlog -w HEAD > out
|
||||
|
||||
cat > expect << EOF
|
||||
A U Thor (5):
|
||||
Test
|
||||
This is a very, very long first line for the commit message to see if
|
||||
it is wrapped correctly
|
||||
Th𝄞s 𝄞s a very, very long f𝄞rst l𝄞ne for the comm𝄞t message to see 𝄞f
|
||||
𝄞t 𝄞s wrapped correctly
|
||||
Th<54><68><EFBFBD><EFBFBD>s <20><><EFBFBD><EFBFBD>s a very, very long f<><66><EFBFBD><EFBFBD>rst l<><6C><EFBFBD><EFBFBD>ne for the comm<6D><6D><EFBFBD><EFBFBD>t
|
||||
message to see <20><><EFBFBD><EFBFBD>f <20><><EFBFBD><EFBFBD>t <20><><EFBFBD><EFBFBD>s wrapped correctly
|
||||
a 12 34
|
||||
56 78
|
||||
|
||||
EOF
|
||||
|
||||
test_expect_success 'shortlog wrapping' 'diff -u expect out'
|
||||
|
||||
test_done
|
||||
0
t/t6023-merge-file.sh
Normal file → Executable file
0
t/t6023-merge-file.sh
Normal file → Executable file
0
t/t6024-recursive-merge.sh
Normal file → Executable file
0
t/t6024-recursive-merge.sh
Normal file → Executable file
0
t/t6025-merge-symlinks.sh
Normal file → Executable file
0
t/t6025-merge-symlinks.sh
Normal file → Executable file
@@ -46,7 +46,7 @@ test_expect_success 'bisect starts with only one bad' '
|
||||
git bisect next
|
||||
'
|
||||
|
||||
test_expect_success 'bisect starts with only one good' '
|
||||
test_expect_success 'bisect does not start with only one good' '
|
||||
git bisect reset &&
|
||||
git bisect start &&
|
||||
git bisect good $HASH1 || return 1
|
||||
0
t/test-lib.sh
Executable file → Normal file
0
t/test-lib.sh
Executable file → Normal file
@@ -665,7 +665,6 @@ int threeway_merge(struct cache_entry **stages,
|
||||
int count;
|
||||
int head_match = 0;
|
||||
int remote_match = 0;
|
||||
const char *path = NULL;
|
||||
|
||||
int df_conflict_head = 0;
|
||||
int df_conflict_remote = 0;
|
||||
@@ -675,13 +674,10 @@ int threeway_merge(struct cache_entry **stages,
|
||||
int i;
|
||||
|
||||
for (i = 1; i < o->head_idx; i++) {
|
||||
if (!stages[i])
|
||||
if (!stages[i] || stages[i] == o->df_conflict_entry)
|
||||
any_anc_missing = 1;
|
||||
else {
|
||||
if (!path)
|
||||
path = stages[i]->name;
|
||||
else
|
||||
no_anc_exists = 0;
|
||||
}
|
||||
}
|
||||
|
||||
index = stages[0];
|
||||
@@ -697,13 +693,6 @@ int threeway_merge(struct cache_entry **stages,
|
||||
remote = NULL;
|
||||
}
|
||||
|
||||
if (!path && index)
|
||||
path = index->name;
|
||||
if (!path && head)
|
||||
path = head->name;
|
||||
if (!path && remote)
|
||||
path = remote->name;
|
||||
|
||||
/* First, if there's a #16 situation, note that to prevent #13
|
||||
* and #14.
|
||||
*/
|
||||
@@ -755,6 +744,23 @@ int threeway_merge(struct cache_entry **stages,
|
||||
if (o->aggressive) {
|
||||
int head_deleted = !head && !df_conflict_head;
|
||||
int remote_deleted = !remote && !df_conflict_remote;
|
||||
const char *path = NULL;
|
||||
|
||||
if (index)
|
||||
path = index->name;
|
||||
else if (head)
|
||||
path = head->name;
|
||||
else if (remote)
|
||||
path = remote->name;
|
||||
else {
|
||||
for (i = 1; i < o->head_idx; i++) {
|
||||
if (stages[i] && stages[i] != o->df_conflict_entry) {
|
||||
path = stages[i]->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Deleted in both.
|
||||
* Deleted in one and unchanged in the other.
|
||||
@@ -786,11 +792,11 @@ int threeway_merge(struct cache_entry **stages,
|
||||
|
||||
o->nontrivial_merge = 1;
|
||||
|
||||
/* #2, #3, #4, #6, #7, #9, #11. */
|
||||
/* #2, #3, #4, #6, #7, #9, #10, #11. */
|
||||
count = 0;
|
||||
if (!head_match || !remote_match) {
|
||||
for (i = 1; i < o->head_idx; i++) {
|
||||
if (stages[i]) {
|
||||
if (stages[i] && stages[i] != o->df_conflict_entry) {
|
||||
keep_entry(stages[i], o);
|
||||
count++;
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user