mirror of
https://github.com/git/git.git
synced 2026-03-15 03:00:07 +01:00
Merge git://repo.or.cz/alt-git.git
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -38,6 +38,7 @@ git-diff-tree
|
||||
git-describe
|
||||
git-fast-import
|
||||
git-fetch
|
||||
git-fetch--tool
|
||||
git-fetch-pack
|
||||
git-findtags
|
||||
git-fmt-merge-msg
|
||||
@@ -75,6 +76,7 @@ git-merge-ours
|
||||
git-merge-recursive
|
||||
git-merge-resolve
|
||||
git-merge-stupid
|
||||
git-mergetool
|
||||
git-mktag
|
||||
git-mktree
|
||||
git-name-rev
|
||||
|
||||
24
Documentation/RelNotes-1.5.0.4.txt
Normal file
24
Documentation/RelNotes-1.5.0.4.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
GIT v1.5.0.4 Release Notes
|
||||
==========================
|
||||
|
||||
Fixes since v1.5.0.3
|
||||
--------------------
|
||||
|
||||
* Bugfixes
|
||||
|
||||
- git.el does not add duplicate sign-off lines.
|
||||
|
||||
- git-commit shows the full stat of the resulting commit, not
|
||||
just about the files in the current directory, when run from
|
||||
a subdirectory.
|
||||
|
||||
- "git-checkout -m '@{8 hours ago}'" had a funny failure from
|
||||
eval; fixed.
|
||||
|
||||
- git-gui updates.
|
||||
|
||||
* Documentation updates
|
||||
|
||||
* User manual updates
|
||||
|
||||
|
||||
@@ -124,6 +124,7 @@ git-merge-index plumbingmanipulators
|
||||
git-merge mainporcelain
|
||||
git-merge-one-file purehelpers
|
||||
git-merge-tree ancillaryinterrogators
|
||||
git-mergetool ancillarymanipulators
|
||||
git-mktag plumbingmanipulators
|
||||
git-mktree plumbingmanipulators
|
||||
git-mv mainporcelain
|
||||
|
||||
@@ -453,6 +453,11 @@ merge.summary::
|
||||
Whether to include summaries of merged commits in newly created
|
||||
merge commit messages. False by default.
|
||||
|
||||
merge.tool::
|
||||
Controls which merge resolution program is used by
|
||||
gitlink:git-mergetool[l]. Valid values are: "kdiff3", "tkdiff",
|
||||
"meld", "xxdiff", "emerge"
|
||||
|
||||
merge.verbosity::
|
||||
Controls the amount of output shown by the recursive merge
|
||||
strategy. Level 0 outputs nothing except a final error
|
||||
|
||||
@@ -10,7 +10,7 @@ SYNOPSIS
|
||||
[verse]
|
||||
'git-branch' [--color | --no-color] [-r | -a]
|
||||
[-v [--abbrev=<length> | --no-abbrev]]
|
||||
'git-branch' [-l] [-f] <branchname> [<start-point>]
|
||||
'git-branch' [--track | --no-track] [-l] [-f] <branchname> [<start-point>]
|
||||
'git-branch' (-m | -M) [<oldbranch>] <newbranch>
|
||||
'git-branch' (-d | -D) [-r] <branchname>...
|
||||
|
||||
@@ -26,6 +26,13 @@ It will start out with a head equal to the one given as <start-point>.
|
||||
If no <start-point> is given, the branch will be created with a head
|
||||
equal to that of the currently checked out branch.
|
||||
|
||||
When a local branch is started off a remote branch, git can setup the
|
||||
branch so that gitlink:git-pull[1] will appropriately merge from that
|
||||
remote branch. If this behavior is desired, it is possible to make it
|
||||
the default using the global `branch.autosetupmerge` configuration
|
||||
flag. Otherwise, it can be chosen per-branch using the `--track`
|
||||
and `--no-track` options.
|
||||
|
||||
With a '-m' or '-M' option, <oldbranch> will be renamed to <newbranch>.
|
||||
If <oldbranch> had a corresponding reflog, it is renamed to match
|
||||
<newbranch>, and a reflog entry is created to remember the branch
|
||||
|
||||
@@ -8,7 +8,7 @@ git-checkout - Checkout and switch to a branch
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-checkout' [-q] [-f] [-b <new_branch> [-l]] [-m] [<branch>]
|
||||
'git-checkout' [-q] [-f] [-b [--track | --no-track] <new_branch> [-l]] [-m] [<branch>]
|
||||
'git-checkout' [<tree-ish>] <paths>...
|
||||
|
||||
DESCRIPTION
|
||||
@@ -18,7 +18,8 @@ When <paths> are not given, this command switches branches by
|
||||
updating the index and working tree to reflect the specified
|
||||
branch, <branch>, and updating HEAD to be <branch> or, if
|
||||
specified, <new_branch>. Using -b will cause <new_branch> to
|
||||
be created.
|
||||
be created; in this case you can use the --track or --no-track
|
||||
options, which will be passed to `git branch`.
|
||||
|
||||
When <paths> are given, this command does *not* switch
|
||||
branches. It updates the named paths in the working tree from
|
||||
@@ -45,6 +46,16 @@ OPTIONS
|
||||
by gitlink:git-check-ref-format[1]. Some of these checks
|
||||
may restrict the characters allowed in a branch name.
|
||||
|
||||
--track::
|
||||
When -b is given and a branch is created off a remote branch,
|
||||
setup so that git-pull will automatically retrieve data from
|
||||
the remote branch.
|
||||
|
||||
--no-track::
|
||||
When -b is given and a branch is created off a remote branch,
|
||||
force that git-pull will automatically retrieve data from
|
||||
the remote branch independent of the configuration settings.
|
||||
|
||||
-l::
|
||||
Create the new branch's ref log. This activates recording of
|
||||
all changes to made the branch ref, enabling use of date
|
||||
|
||||
@@ -86,7 +86,7 @@ OPTIONS
|
||||
Remove the line matching the key from config file.
|
||||
|
||||
--unset-all::
|
||||
Remove all matching lines from config file.
|
||||
Remove all lines matching the key from config file.
|
||||
|
||||
-l, --list::
|
||||
List all variables set in config file.
|
||||
|
||||
@@ -121,10 +121,10 @@ so that calling 'cvs' effectively calls git-cvsserver.
|
||||
Clients known to work
|
||||
---------------------
|
||||
|
||||
CVS 1.12.9 on Debian
|
||||
CVS 1.11.17 on MacOSX (from Fink package)
|
||||
Eclipse 3.0, 3.1.2 on MacOSX (see Eclipse CVS Client Notes)
|
||||
TortoiseCVS
|
||||
- CVS 1.12.9 on Debian
|
||||
- CVS 1.11.17 on MacOSX (from Fink package)
|
||||
- Eclipse 3.0, 3.1.2 on MacOSX (see Eclipse CVS Client Notes)
|
||||
- TortoiseCVS
|
||||
|
||||
Operations supported
|
||||
--------------------
|
||||
@@ -148,13 +148,16 @@ Copyright and Authors
|
||||
|
||||
This program is copyright The Open University UK - 2006.
|
||||
|
||||
Authors: Martyn Smith <martyn@catalyst.net.nz>
|
||||
Martin Langhoff <martin@catalyst.net.nz>
|
||||
with ideas and patches from participants of the git-list <git@vger.kernel.org>.
|
||||
Authors:
|
||||
|
||||
- Martyn Smith <martyn@catalyst.net.nz>
|
||||
- Martin Langhoff <martin@catalyst.net.nz>
|
||||
|
||||
with ideas and patches from participants of the git-list <git@vger.kernel.org>.
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
Documentation by Martyn Smith <martyn@catalyst.net.nz> and Martin Langhoff <martin@catalyst.net.nz> Matthias Urlichs <smurf@smurf.noris.de>.
|
||||
Documentation by Martyn Smith <martyn@catalyst.net.nz>, Martin Langhoff <martin@catalyst.net.nz>, and Matthias Urlichs <smurf@smurf.noris.de>.
|
||||
|
||||
GIT
|
||||
---
|
||||
|
||||
46
Documentation/git-mergetool.txt
Normal file
46
Documentation/git-mergetool.txt
Normal file
@@ -0,0 +1,46 @@
|
||||
git-mergetool(1)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
git-mergetool - Run merge conflict resolution tools to resolve merge conflicts
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-mergetool' [--tool=<tool>] [<file>]...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
Use 'git mergetool' to run one of several merge utilities to resolve
|
||||
merge conflicts. It is typically run after gitlink:git-merge[1].
|
||||
|
||||
If one or more <file> parameters are given, the merge tool program will
|
||||
be run to resolve differences on each file. If no <file> names are
|
||||
specified, 'git mergetool' will run the merge tool program on every file
|
||||
with merge conflicts.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
-t or --tool=<tool>::
|
||||
Use the merge resolution program specified by <tool>.
|
||||
Valid merge tools are:
|
||||
kdiff3, tkdiff, meld, xxdiff, and emerge.
|
||||
|
||||
If a merge resolution program is not specified, 'git mergetool'
|
||||
will use the configuration variable merge.tool. If the
|
||||
configuration variable merge.tool is not set, 'git mergetool'
|
||||
will pick a suitable default.
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Theodore Y Ts'o <tytso@mit.edu>
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
Documentation by Theodore Y Ts'o.
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the gitlink:git[7] suite
|
||||
|
||||
@@ -40,13 +40,13 @@ OPTIONS
|
||||
pre-receive Hook
|
||||
----------------
|
||||
Before any ref is updated, if $GIT_DIR/hooks/pre-receive file exists
|
||||
and is executable, it will be invoked once, with three parameters
|
||||
per ref to be updated:
|
||||
and is executable, it will be invoked once with no parameters. The
|
||||
standard input of the hook will be one line per ref to be updated:
|
||||
|
||||
$GIT_DIR/hooks/pre-receive (refname sha1-old sha1-new)+
|
||||
sha1-old SP sha1-new SP refname LF
|
||||
|
||||
The refname parameter is relative to $GIT_DIR; e.g. for the master
|
||||
head this is "refs/heads/master". The two sha1 arguments after
|
||||
The refname value is relative to $GIT_DIR; e.g. for the master
|
||||
head this is "refs/heads/master". The two sha1 values before
|
||||
each refname are the object names for the refname before and after
|
||||
the update. Refs to be created will have sha1-old equal to 0{40},
|
||||
while refs to be deleted will have sha1-new equal to 0{40}, otherwise
|
||||
@@ -86,13 +86,14 @@ post-receive Hook
|
||||
-----------------
|
||||
After all refs were updated (or attempted to be updated), if any
|
||||
ref update was successful, and if $GIT_DIR/hooks/post-receive
|
||||
file exists and is executable, it will be invoke once with three
|
||||
parameters for each successfully updated ref:
|
||||
file exists and is executable, it will be invoke once with no
|
||||
parameters. The standard input of the hook will be one line
|
||||
for each successfully updated ref:
|
||||
|
||||
$GIT_DIR/hooks/post-receive (refname sha1-old sha1-new)+
|
||||
sha1-old SP sha1-new SP refname LF
|
||||
|
||||
The refname parameter is relative to $GIT_DIR; e.g. for the master
|
||||
head this is "refs/heads/master". The two sha1 arguments after
|
||||
The refname value is relative to $GIT_DIR; e.g. for the master
|
||||
head this is "refs/heads/master". The two sha1 values before
|
||||
each refname are the object names for the refname before and after
|
||||
the update. Refs that were created will have sha1-old equal to
|
||||
0{40}, while refs that were deleted will have sha1-new equal to
|
||||
@@ -105,18 +106,17 @@ ref listing the commits pushed to the repository:
|
||||
|
||||
#!/bin/sh
|
||||
# mail out commit update information.
|
||||
while test $# -gt 0
|
||||
while read oval nval ref
|
||||
do
|
||||
if expr "$2" : '0*$' >/dev/null
|
||||
if expr "$oval" : '0*$' >/dev/null
|
||||
then
|
||||
echo "Created a new ref, with the following commits:"
|
||||
git-rev-list --pretty "$2"
|
||||
git-rev-list --pretty "$nval"
|
||||
else
|
||||
echo "New commits:"
|
||||
git-rev-list --pretty "$3" "^$2"
|
||||
git-rev-list --pretty "$nval" "^$oval"
|
||||
fi |
|
||||
mail -s "Changes to ref $1" commit-list@mydomain
|
||||
shift; shift; shift; # discard this ref's args
|
||||
mail -s "Changes to ref $ref" commit-list@mydomain
|
||||
done
|
||||
exit 0
|
||||
|
||||
|
||||
@@ -40,7 +40,8 @@ The --cc option must be repeated for each user you want on the cc list.
|
||||
the first will be sent as replies to the first email sent. When using
|
||||
this, it is recommended that the first file given be an overview of the
|
||||
entire patch series.
|
||||
Default is --chain-reply-to
|
||||
Default is the value of the 'sendemail.chainreplyto' configuration
|
||||
value; if that is unspecified, default to --chain-reply-to.
|
||||
|
||||
--compose::
|
||||
Use $EDITOR to edit an introductory message for the
|
||||
@@ -91,6 +92,26 @@ The --cc option must be repeated for each user you want on the cc list.
|
||||
The --to option must be repeated for each user you want on the to list.
|
||||
|
||||
|
||||
CONFIGURATION
|
||||
-------------
|
||||
sendemail.aliasesfile::
|
||||
To avoid typing long email addresses, point this to one or more
|
||||
email aliases files. You must also supply 'sendemail.aliasfiletype'.
|
||||
|
||||
sendemail.aliasfiletype::
|
||||
Format of the file(s) specified in sendemail.aliasesfile. Must be
|
||||
one of 'mutt', 'mailrc', 'pine', or 'gnus'.
|
||||
|
||||
sendemail.bcc::
|
||||
Email address (or alias) to always bcc.
|
||||
|
||||
sendemail.chainreplyto::
|
||||
Boolean value specifying the default to the '--chain_reply_to'
|
||||
parameter.
|
||||
|
||||
sendemail.smtpserver::
|
||||
Default smtp server to use.
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Ryan Anderson <ryan@michonline.com>
|
||||
|
||||
@@ -104,6 +104,14 @@ accepts. However '--fetch-all' only fetches from the current
|
||||
|
||||
Like 'git-rebase'; this requires that the working tree be clean
|
||||
and have no uncommitted changes.
|
||||
+
|
||||
--
|
||||
-l;;
|
||||
--local;;
|
||||
Do not fetch remotely; only run 'git-rebase' against the
|
||||
last fetched commit from the upstream SVN.
|
||||
--
|
||||
+
|
||||
|
||||
'dcommit'::
|
||||
Commit each diff from a specified head directly to the SVN
|
||||
|
||||
6
Makefile
6
Makefile
@@ -179,7 +179,7 @@ SCRIPT_SH = \
|
||||
git-clean.sh git-clone.sh git-commit.sh \
|
||||
git-fetch.sh git-gc.sh \
|
||||
git-ls-remote.sh \
|
||||
git-merge-one-file.sh git-parse-remote.sh \
|
||||
git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \
|
||||
git-pull.sh git-rebase.sh \
|
||||
git-repack.sh git-request-pull.sh git-reset.sh \
|
||||
git-sh-setup.sh \
|
||||
@@ -293,6 +293,7 @@ BUILTIN_OBJS = \
|
||||
builtin-diff-files.o \
|
||||
builtin-diff-index.o \
|
||||
builtin-diff-tree.o \
|
||||
builtin-fetch--tool.o \
|
||||
builtin-fmt-merge-msg.o \
|
||||
builtin-for-each-ref.o \
|
||||
builtin-fsck.o \
|
||||
@@ -952,8 +953,7 @@ dist: git.spec git-archive
|
||||
$(TAR) rf $(GIT_TARNAME).tar \
|
||||
$(GIT_TARNAME)/git.spec \
|
||||
$(GIT_TARNAME)/version \
|
||||
$(GIT_TARNAME)/git-gui/version \
|
||||
$(GIT_TARNAME)/git-gui/credits
|
||||
$(GIT_TARNAME)/git-gui/version
|
||||
@rm -rf $(GIT_TARNAME)
|
||||
gzip -f -9 $(GIT_TARNAME).tar
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
static const char builtin_add_usage[] =
|
||||
"git-add [-n] [-v] [-f] [--interactive | -i] [--] <filepattern>...";
|
||||
|
||||
static const char *excludes_file;
|
||||
|
||||
static void prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)
|
||||
{
|
||||
char *seen;
|
||||
@@ -67,6 +69,8 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec)
|
||||
path = git_path("info/exclude");
|
||||
if (!access(path, R_OK))
|
||||
add_excludes_from_file(dir, path);
|
||||
if (!access(excludes_file, R_OK))
|
||||
add_excludes_from_file(dir, excludes_file);
|
||||
|
||||
/*
|
||||
* Calculate common prefix for the pathspec, and
|
||||
@@ -88,6 +92,18 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec)
|
||||
prune_directory(dir, pathspec, baselen);
|
||||
}
|
||||
|
||||
static int git_add_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "core.excludesfile")) {
|
||||
if (!value)
|
||||
die("core.excludesfile without value");
|
||||
excludes_file = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
|
||||
static struct lock_file lock_file;
|
||||
|
||||
static const char ignore_warning[] =
|
||||
@@ -115,7 +131,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
git_config(git_default_config);
|
||||
git_config(git_add_config);
|
||||
|
||||
newfd = hold_lock_file_for_update(&lock_file, get_index_file(), 1);
|
||||
|
||||
|
||||
153
builtin-branch.c
153
builtin-branch.c
@@ -12,7 +12,7 @@
|
||||
#include "builtin.h"
|
||||
|
||||
static const char builtin_branch_usage[] =
|
||||
"git-branch [-r] (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length> | --no-abbrev]]";
|
||||
"git-branch [-r] (-d | -D) <branchname> | [--track | --no-track] [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length> | --no-abbrev]]";
|
||||
|
||||
#define REF_UNKNOWN_TYPE 0x00
|
||||
#define REF_LOCAL_BRANCH 0x01
|
||||
@@ -22,6 +22,8 @@ static const char builtin_branch_usage[] =
|
||||
static const char *head;
|
||||
static unsigned char head_sha1[20];
|
||||
|
||||
static int branch_track_remotes;
|
||||
|
||||
static int branch_use_color;
|
||||
static char branch_colors[][COLOR_MAXLEN] = {
|
||||
"\033[m", /* reset */
|
||||
@@ -64,6 +66,9 @@ int git_branch_config(const char *var, const char *value)
|
||||
color_parse(value, var, branch_colors[slot]);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "branch.autosetupmerge"))
|
||||
branch_track_remotes = git_config_bool(var, value);
|
||||
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
|
||||
@@ -309,14 +314,108 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev)
|
||||
free_ref_list(&ref_list);
|
||||
}
|
||||
|
||||
static char *config_repo;
|
||||
static char *config_remote;
|
||||
static const char *start_ref;
|
||||
static int start_len;
|
||||
static int base_len;
|
||||
|
||||
static int get_remote_branch_name(const char *value)
|
||||
{
|
||||
const char *colon;
|
||||
const char *end;
|
||||
|
||||
if (*value == '+')
|
||||
value++;
|
||||
|
||||
colon = strchr(value, ':');
|
||||
if (!colon)
|
||||
return 0;
|
||||
|
||||
end = value + strlen(value);
|
||||
|
||||
/* Try an exact match first. */
|
||||
if (!strcmp(colon + 1, start_ref)) {
|
||||
/* Truncate the value before the colon. */
|
||||
nfasprintf(&config_repo, "%.*s", colon - value, value);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Try with a wildcard match now. */
|
||||
if (end - value > 2 && end[-2] == '/' && end[-1] == '*' &&
|
||||
colon - value > 2 && colon[-2] == '/' && colon[-1] == '*' &&
|
||||
(end - 2) - (colon + 1) == base_len &&
|
||||
!strncmp(colon + 1, start_ref, base_len)) {
|
||||
/* Replace the star with the remote branch name. */
|
||||
nfasprintf(&config_repo, "%.*s%s",
|
||||
(colon - 2) - value, value,
|
||||
start_ref + base_len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_remote_config(const char *key, const char *value)
|
||||
{
|
||||
const char *var;
|
||||
if (prefixcmp(key, "remote."))
|
||||
return 0;
|
||||
|
||||
var = strrchr(key, '.');
|
||||
if (var == key + 6)
|
||||
return 0;
|
||||
|
||||
if (!strcmp(var, ".fetch") && get_remote_branch_name(value))
|
||||
nfasprintf(&config_remote, "%.*s", var - (key + 7), key + 7);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_branch_defaults(const char *name, const char *real_ref)
|
||||
{
|
||||
char key[1024];
|
||||
const char *slash = strrchr(real_ref, '/');
|
||||
|
||||
if (!slash)
|
||||
return;
|
||||
|
||||
start_ref = real_ref;
|
||||
start_len = strlen(real_ref);
|
||||
base_len = slash - real_ref;
|
||||
git_config(get_remote_config);
|
||||
|
||||
if (config_repo && config_remote) {
|
||||
if (sizeof(key) <=
|
||||
snprintf(key, sizeof(key), "branch.%s.remote", name))
|
||||
die("what a long branch name you have!");
|
||||
git_config_set(key, config_remote);
|
||||
|
||||
/*
|
||||
* We do not have to check if we have enough space for
|
||||
* the 'merge' key, since it's shorter than the
|
||||
* previous 'remote' key, which we already checked.
|
||||
*/
|
||||
snprintf(key, sizeof(key), "branch.%s.merge", name);
|
||||
git_config_set(key, config_repo);
|
||||
|
||||
printf("Branch %s set up to track remote branch %s.\n",
|
||||
name, real_ref);
|
||||
}
|
||||
|
||||
if (config_repo)
|
||||
free(config_repo);
|
||||
if (config_remote)
|
||||
free(config_remote);
|
||||
}
|
||||
|
||||
static void create_branch(const char *name, const char *start_name,
|
||||
unsigned char *start_sha1,
|
||||
int force, int reflog)
|
||||
int force, int reflog, int track)
|
||||
{
|
||||
struct ref_lock *lock;
|
||||
struct commit *commit;
|
||||
unsigned char sha1[20];
|
||||
char ref[PATH_MAX], msg[PATH_MAX + 20];
|
||||
char *real_ref, ref[PATH_MAX], msg[PATH_MAX + 20];
|
||||
int forcing = 0;
|
||||
|
||||
snprintf(ref, sizeof ref, "refs/heads/%s", name);
|
||||
@@ -331,12 +430,23 @@ static void create_branch(const char *name, const char *start_name,
|
||||
forcing = 1;
|
||||
}
|
||||
|
||||
if (start_sha1)
|
||||
/* detached HEAD */
|
||||
hashcpy(sha1, start_sha1);
|
||||
else if (get_sha1(start_name, sha1))
|
||||
real_ref = NULL;
|
||||
if (get_sha1(start_name, sha1))
|
||||
die("Not a valid object name: '%s'.", start_name);
|
||||
|
||||
switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) {
|
||||
case 0:
|
||||
/* Not branching from any existing branch */
|
||||
real_ref = NULL;
|
||||
break;
|
||||
case 1:
|
||||
/* Unique completion -- good */
|
||||
break;
|
||||
default:
|
||||
die("Ambiguous object name: '%s'.", start_name);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((commit = lookup_commit_reference(sha1)) == NULL)
|
||||
die("Not a valid branch point: '%s'.", start_name);
|
||||
hashcpy(sha1, commit->object.sha1);
|
||||
@@ -355,8 +465,17 @@ static void create_branch(const char *name, const char *start_name,
|
||||
snprintf(msg, sizeof msg, "branch: Created from %s",
|
||||
start_name);
|
||||
|
||||
/* When branching off a remote branch, set up so that git-pull
|
||||
automatically merges from there. So far, this is only done for
|
||||
remotes registered via .git/config. */
|
||||
if (real_ref && track)
|
||||
set_branch_defaults(name, real_ref);
|
||||
|
||||
if (write_ref_sha1(lock, sha1, msg) < 0)
|
||||
die("Failed to write ref: %s.", strerror(errno));
|
||||
|
||||
if (real_ref)
|
||||
free(real_ref);
|
||||
}
|
||||
|
||||
static void rename_branch(const char *oldname, const char *newname, int force)
|
||||
@@ -398,11 +517,12 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
int delete = 0, force_delete = 0, force_create = 0;
|
||||
int rename = 0, force_rename = 0;
|
||||
int verbose = 0, abbrev = DEFAULT_ABBREV, detached = 0;
|
||||
int reflog = 0;
|
||||
int reflog = 0, track;
|
||||
int kinds = REF_LOCAL_BRANCH;
|
||||
int i;
|
||||
|
||||
git_config(git_branch_config);
|
||||
track = branch_track_remotes;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
@@ -413,6 +533,14 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
if (!strcmp(arg, "--track")) {
|
||||
track = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--no-track")) {
|
||||
track = 0;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-d")) {
|
||||
delete = 1;
|
||||
continue;
|
||||
@@ -498,10 +626,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
rename_branch(head, argv[i], force_rename);
|
||||
else if (rename && (i == argc - 2))
|
||||
rename_branch(argv[i], argv[i + 1], force_rename);
|
||||
else if (i == argc - 1)
|
||||
create_branch(argv[i], head, head_sha1, force_create, reflog);
|
||||
else if (i == argc - 2)
|
||||
create_branch(argv[i], argv[i+1], NULL, force_create, reflog);
|
||||
else if (i == argc - 1 || i == argc - 2)
|
||||
create_branch(argv[i], (i == argc - 2) ? argv[i+1] : head,
|
||||
force_create, reflog, track);
|
||||
else
|
||||
usage(builtin_branch_usage);
|
||||
|
||||
|
||||
185
builtin-bundle.c
185
builtin-bundle.c
@@ -160,7 +160,28 @@ static int fork_with_pipe(const char **argv, int *in, int *out)
|
||||
return pid;
|
||||
}
|
||||
|
||||
static int verify_bundle(struct bundle_header *header)
|
||||
static int list_refs(struct ref_list *r, int argc, const char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < r->nr; i++) {
|
||||
if (argc > 1) {
|
||||
int j;
|
||||
for (j = 1; j < argc; j++)
|
||||
if (!strcmp(r->list[i].name, argv[j]))
|
||||
break;
|
||||
if (j == argc)
|
||||
continue;
|
||||
}
|
||||
printf("%s %s\n", sha1_to_hex(r->list[i].sha1),
|
||||
r->list[i].name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PREREQ_MARK (1u<<16)
|
||||
|
||||
static int verify_bundle(struct bundle_header *header, int verbose)
|
||||
{
|
||||
/*
|
||||
* Do fast check, then if any prereqs are missing then go line by line
|
||||
@@ -179,7 +200,7 @@ static int verify_bundle(struct bundle_header *header)
|
||||
struct ref_list_entry *e = p->list + i;
|
||||
struct object *o = parse_object(e->sha1);
|
||||
if (o) {
|
||||
o->flags |= BOUNDARY_SHOW;
|
||||
o->flags |= PREREQ_MARK;
|
||||
add_pending_object(&revs, o, e->name);
|
||||
continue;
|
||||
}
|
||||
@@ -187,7 +208,7 @@ static int verify_bundle(struct bundle_header *header)
|
||||
error(message);
|
||||
error("%s %s", sha1_to_hex(e->sha1), e->name);
|
||||
}
|
||||
if (revs.pending.nr == 0)
|
||||
if (revs.pending.nr != p->nr)
|
||||
return ret;
|
||||
req_nr = revs.pending.nr;
|
||||
setup_revisions(2, argv, &revs, NULL);
|
||||
@@ -202,7 +223,7 @@ static int verify_bundle(struct bundle_header *header)
|
||||
|
||||
i = req_nr;
|
||||
while (i && (commit = get_revision(&revs)))
|
||||
if (commit->object.flags & BOUNDARY_SHOW)
|
||||
if (commit->object.flags & PREREQ_MARK)
|
||||
i--;
|
||||
|
||||
for (i = 0; i < req_nr; i++)
|
||||
@@ -216,56 +237,24 @@ static int verify_bundle(struct bundle_header *header)
|
||||
for (i = 0; i < refs.nr; i++)
|
||||
clear_commit_marks((struct commit *)refs.objects[i].item, -1);
|
||||
|
||||
if (verbose) {
|
||||
struct ref_list *r;
|
||||
|
||||
r = &header->references;
|
||||
printf("The bundle contains %d ref%s\n",
|
||||
r->nr, (1 < r->nr) ? "s" : "");
|
||||
list_refs(r, 0, NULL);
|
||||
r = &header->prerequisites;
|
||||
printf("The bundle requires these %d ref%s\n",
|
||||
r->nr, (1 < r->nr) ? "s" : "");
|
||||
list_refs(r, 0, NULL);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int list_heads(struct bundle_header *header, int argc, const char **argv)
|
||||
{
|
||||
int i;
|
||||
struct ref_list *r = &header->references;
|
||||
|
||||
for (i = 0; i < r->nr; i++) {
|
||||
if (argc > 1) {
|
||||
int j;
|
||||
for (j = 1; j < argc; j++)
|
||||
if (!strcmp(r->list[i].name, argv[j]))
|
||||
break;
|
||||
if (j == argc)
|
||||
continue;
|
||||
}
|
||||
printf("%s %s\n", sha1_to_hex(r->list[i].sha1),
|
||||
r->list[i].name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void show_commit(struct commit *commit)
|
||||
{
|
||||
write_or_die(1, sha1_to_hex(commit->object.sha1), 40);
|
||||
write_or_die(1, "\n", 1);
|
||||
if (commit->parents) {
|
||||
free_commit_list(commit->parents);
|
||||
commit->parents = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void show_object(struct object_array_entry *p)
|
||||
{
|
||||
/* An object with name "foo\n0000000..." can be used to
|
||||
* confuse downstream git-pack-objects very badly.
|
||||
*/
|
||||
const char *ep = strchr(p->name, '\n');
|
||||
int len = ep ? ep - p->name : strlen(p->name);
|
||||
write_or_die(1, sha1_to_hex(p->item->sha1), 40);
|
||||
write_or_die(1, " ", 1);
|
||||
if (len)
|
||||
write_or_die(1, p->name, len);
|
||||
write_or_die(1, "\n", 1);
|
||||
}
|
||||
|
||||
static void show_edge(struct commit *commit)
|
||||
{
|
||||
; /* nothing to do */
|
||||
return list_refs(&header->references, argc, argv);
|
||||
}
|
||||
|
||||
static int create_bundle(struct bundle_header *header, const char *path,
|
||||
@@ -273,19 +262,23 @@ static int create_bundle(struct bundle_header *header, const char *path,
|
||||
{
|
||||
int bundle_fd = -1;
|
||||
const char **argv_boundary = xmalloc((argc + 4) * sizeof(const char *));
|
||||
const char **argv_pack = xmalloc(4 * sizeof(const char *));
|
||||
int pid, in, out, i, status;
|
||||
const char **argv_pack = xmalloc(5 * sizeof(const char *));
|
||||
int pid, in, out, i, status, ref_count = 0;
|
||||
char buffer[1024];
|
||||
struct rev_info revs;
|
||||
|
||||
bundle_fd = (!strcmp(path, "-") ? 1 :
|
||||
open(path, O_CREAT | O_WRONLY, 0666));
|
||||
open(path, O_CREAT | O_EXCL | O_WRONLY, 0666));
|
||||
if (bundle_fd < 0)
|
||||
return error("Could not write to '%s'", path);
|
||||
return error("Could not create '%s': %s", path, strerror(errno));
|
||||
|
||||
/* write signature */
|
||||
write_or_die(bundle_fd, bundle_signature, strlen(bundle_signature));
|
||||
|
||||
/* init revs to list objects for pack-objects later */
|
||||
save_commit_buffer = 0;
|
||||
init_revisions(&revs, NULL);
|
||||
|
||||
/* write prerequisites */
|
||||
memcpy(argv_boundary + 3, argv + 1, argc * sizeof(const char *));
|
||||
argv_boundary[0] = "rev-list";
|
||||
@@ -296,9 +289,20 @@ static int create_bundle(struct bundle_header *header, const char *path,
|
||||
pid = fork_with_pipe(argv_boundary, NULL, &out);
|
||||
if (pid < 0)
|
||||
return -1;
|
||||
while ((i = read_string(out, buffer, sizeof(buffer))) > 0)
|
||||
if (buffer[0] == '-')
|
||||
while ((i = read_string(out, buffer, sizeof(buffer))) > 0) {
|
||||
unsigned char sha1[20];
|
||||
if (buffer[0] == '-') {
|
||||
write_or_die(bundle_fd, buffer, i);
|
||||
if (!get_sha1_hex(buffer + 1, sha1)) {
|
||||
struct object *object = parse_object(sha1);
|
||||
object->flags |= UNINTERESTING;
|
||||
add_pending_object(&revs, object, buffer);
|
||||
}
|
||||
} else if (!get_sha1_hex(buffer, sha1)) {
|
||||
struct object *object = parse_object(sha1);
|
||||
object->flags |= SHOWN;
|
||||
}
|
||||
}
|
||||
while ((i = waitpid(pid, &status, 0)) < 0)
|
||||
if (errno != EINTR)
|
||||
return error("rev-list died");
|
||||
@@ -306,28 +310,38 @@ static int create_bundle(struct bundle_header *header, const char *path,
|
||||
return error("rev-list died %d", WEXITSTATUS(status));
|
||||
|
||||
/* write references */
|
||||
save_commit_buffer = 0;
|
||||
init_revisions(&revs, NULL);
|
||||
revs.tag_objects = 1;
|
||||
revs.tree_objects = 1;
|
||||
revs.blob_objects = 1;
|
||||
argc = setup_revisions(argc, argv, &revs, NULL);
|
||||
if (argc > 1)
|
||||
return error("unrecognized argument: %s'", argv[1]);
|
||||
|
||||
for (i = 0; i < revs.pending.nr; i++) {
|
||||
struct object_array_entry *e = revs.pending.objects + i;
|
||||
if (!(e->item->flags & UNINTERESTING)) {
|
||||
unsigned char sha1[20];
|
||||
char *ref;
|
||||
if (dwim_ref(e->name, strlen(e->name), sha1, &ref) != 1)
|
||||
continue;
|
||||
write_or_die(bundle_fd, sha1_to_hex(e->item->sha1), 40);
|
||||
write_or_die(bundle_fd, " ", 1);
|
||||
write_or_die(bundle_fd, ref, strlen(ref));
|
||||
write_or_die(bundle_fd, "\n", 1);
|
||||
free(ref);
|
||||
unsigned char sha1[20];
|
||||
char *ref;
|
||||
|
||||
if (e->item->flags & UNINTERESTING)
|
||||
continue;
|
||||
if (dwim_ref(e->name, strlen(e->name), sha1, &ref) != 1)
|
||||
continue;
|
||||
/*
|
||||
* Make sure the refs we wrote out is correct; --max-count and
|
||||
* other limiting options could have prevented all the tips
|
||||
* from getting output.
|
||||
*/
|
||||
if (!(e->item->flags & SHOWN)) {
|
||||
warn("ref '%s' is excluded by the rev-list options",
|
||||
e->name);
|
||||
continue;
|
||||
}
|
||||
ref_count++;
|
||||
write_or_die(bundle_fd, sha1_to_hex(e->item->sha1), 40);
|
||||
write_or_die(bundle_fd, " ", 1);
|
||||
write_or_die(bundle_fd, ref, strlen(ref));
|
||||
write_or_die(bundle_fd, "\n", 1);
|
||||
free(ref);
|
||||
}
|
||||
if (!ref_count)
|
||||
die ("Refusing to create empty bundle.");
|
||||
|
||||
/* end header */
|
||||
write_or_die(bundle_fd, "\n", 1);
|
||||
@@ -336,36 +350,42 @@ static int create_bundle(struct bundle_header *header, const char *path,
|
||||
argv_pack[0] = "pack-objects";
|
||||
argv_pack[1] = "--all-progress";
|
||||
argv_pack[2] = "--stdout";
|
||||
argv_pack[3] = NULL;
|
||||
argv_pack[3] = "--thin";
|
||||
argv_pack[4] = NULL;
|
||||
in = -1;
|
||||
out = bundle_fd;
|
||||
pid = fork_with_pipe(argv_pack, &in, &out);
|
||||
if (pid < 0)
|
||||
return error("Could not spawn pack-objects");
|
||||
close(1);
|
||||
dup2(in, 1);
|
||||
for (i = 0; i < revs.pending.nr; i++) {
|
||||
struct object *object = revs.pending.objects[i].item;
|
||||
if (object->flags & UNINTERESTING)
|
||||
write(in, "^", 1);
|
||||
write(in, sha1_to_hex(object->sha1), 40);
|
||||
write(in, "\n", 1);
|
||||
}
|
||||
close(in);
|
||||
prepare_revision_walk(&revs);
|
||||
mark_edges_uninteresting(revs.commits, &revs, show_edge);
|
||||
traverse_commit_list(&revs, show_commit, show_object);
|
||||
close(1);
|
||||
while (waitpid(pid, &status, 0) < 0)
|
||||
if (errno != EINTR)
|
||||
return -1;
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status))
|
||||
return error ("pack-objects died");
|
||||
return 0;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int unbundle(struct bundle_header *header, int bundle_fd,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
const char *argv_index_pack[] = {"index-pack", "--stdin", NULL};
|
||||
const char *argv_index_pack[] = {"index-pack",
|
||||
"--fix-thin", "--stdin", NULL};
|
||||
int pid, status, dev_null;
|
||||
|
||||
if (verify_bundle(header))
|
||||
if (verify_bundle(header, 0))
|
||||
return -1;
|
||||
dev_null = open("/dev/null", O_WRONLY);
|
||||
if (dev_null < 0)
|
||||
return error("Could not open /dev/null");
|
||||
pid = fork_with_pipe(argv_index_pack, &bundle_fd, &dev_null);
|
||||
if (pid < 0)
|
||||
return error("Could not spawn index-pack");
|
||||
@@ -402,12 +422,12 @@ int cmd_bundle(int argc, const char **argv, const char *prefix)
|
||||
|
||||
memset(&header, 0, sizeof(header));
|
||||
if (strcmp(cmd, "create") &&
|
||||
!(bundle_fd = read_header(bundle_file, &header)))
|
||||
(bundle_fd = read_header(bundle_file, &header)) < 0)
|
||||
return 1;
|
||||
|
||||
if (!strcmp(cmd, "verify")) {
|
||||
close(bundle_fd);
|
||||
if (verify_bundle(&header))
|
||||
if (verify_bundle(&header, 1))
|
||||
return 1;
|
||||
fprintf(stderr, "%s is okay\n", bundle_file);
|
||||
return 0;
|
||||
@@ -427,4 +447,3 @@ int cmd_bundle(int argc, const char **argv, const char *prefix)
|
||||
} else
|
||||
usage(bundle_usage);
|
||||
}
|
||||
|
||||
|
||||
505
builtin-fetch--tool.c
Normal file
505
builtin-fetch--tool.c
Normal file
@@ -0,0 +1,505 @@
|
||||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
#include "commit.h"
|
||||
|
||||
#define CHUNK_SIZE 1024
|
||||
|
||||
static char *get_stdin(void)
|
||||
{
|
||||
int offset = 0;
|
||||
char *data = xmalloc(CHUNK_SIZE);
|
||||
|
||||
while (1) {
|
||||
int cnt = xread(0, data + offset, CHUNK_SIZE);
|
||||
if (cnt < 0)
|
||||
die("error reading standard input: %s",
|
||||
strerror(errno));
|
||||
if (cnt == 0) {
|
||||
data[offset] = 0;
|
||||
break;
|
||||
}
|
||||
offset += cnt;
|
||||
data = xrealloc(data, offset + CHUNK_SIZE);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static void show_new(enum object_type type, unsigned char *sha1_new)
|
||||
{
|
||||
fprintf(stderr, " %s: %s\n", typename(type),
|
||||
find_unique_abbrev(sha1_new, DEFAULT_ABBREV));
|
||||
}
|
||||
|
||||
static int update_ref(const char *action,
|
||||
const char *refname,
|
||||
unsigned char *sha1,
|
||||
unsigned char *oldval)
|
||||
{
|
||||
int len;
|
||||
char msg[1024];
|
||||
char *rla = getenv("GIT_REFLOG_ACTION");
|
||||
static struct ref_lock *lock;
|
||||
|
||||
if (!rla)
|
||||
rla = "(reflog update)";
|
||||
len = snprintf(msg, sizeof(msg), "%s: %s", rla, action);
|
||||
if (sizeof(msg) <= len)
|
||||
die("insanely long action");
|
||||
lock = lock_any_ref_for_update(refname, oldval);
|
||||
if (!lock)
|
||||
return 1;
|
||||
if (write_ref_sha1(lock, sha1, msg) < 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int update_local_ref(const char *name,
|
||||
const char *new_head,
|
||||
const char *note,
|
||||
int verbose, int force)
|
||||
{
|
||||
unsigned char sha1_old[20], sha1_new[20];
|
||||
char oldh[41], newh[41];
|
||||
struct commit *current, *updated;
|
||||
enum object_type type;
|
||||
|
||||
if (get_sha1_hex(new_head, sha1_new))
|
||||
die("malformed object name %s", new_head);
|
||||
|
||||
type = sha1_object_info(sha1_new, NULL);
|
||||
if (type < 0)
|
||||
die("object %s not found", new_head);
|
||||
|
||||
if (!*name) {
|
||||
/* Not storing */
|
||||
if (verbose) {
|
||||
fprintf(stderr, "* fetched %s\n", note);
|
||||
show_new(type, sha1_new);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (get_sha1(name, sha1_old)) {
|
||||
char *msg;
|
||||
just_store:
|
||||
/* new ref */
|
||||
if (!strncmp(name, "refs/tags/", 10))
|
||||
msg = "storing tag";
|
||||
else
|
||||
msg = "storing head";
|
||||
fprintf(stderr, "* %s: storing %s\n",
|
||||
name, note);
|
||||
show_new(type, sha1_new);
|
||||
return update_ref(msg, name, sha1_new, NULL);
|
||||
}
|
||||
|
||||
if (!hashcmp(sha1_old, sha1_new)) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "* %s: same as %s\n", name, note);
|
||||
show_new(type, sha1_new);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strncmp(name, "refs/tags/", 10)) {
|
||||
fprintf(stderr, "* %s: updating with %s\n", name, note);
|
||||
show_new(type, sha1_new);
|
||||
return update_ref("updating tag", name, sha1_new, NULL);
|
||||
}
|
||||
|
||||
current = lookup_commit_reference(sha1_old);
|
||||
updated = lookup_commit_reference(sha1_new);
|
||||
if (!current || !updated)
|
||||
goto just_store;
|
||||
|
||||
strcpy(oldh, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
|
||||
strcpy(newh, find_unique_abbrev(sha1_new, DEFAULT_ABBREV));
|
||||
|
||||
if (in_merge_bases(current, &updated, 1)) {
|
||||
fprintf(stderr, "* %s: fast forward to %s\n",
|
||||
name, note);
|
||||
fprintf(stderr, " old..new: %s..%s\n", oldh, newh);
|
||||
return update_ref("fast forward", name, sha1_new, sha1_old);
|
||||
}
|
||||
if (!force) {
|
||||
fprintf(stderr,
|
||||
"* %s: not updating to non-fast forward %s\n",
|
||||
name, note);
|
||||
fprintf(stderr,
|
||||
" old...new: %s...%s\n", oldh, newh);
|
||||
return 1;
|
||||
}
|
||||
fprintf(stderr,
|
||||
"* %s: forcing update to non-fast forward %s\n",
|
||||
name, note);
|
||||
fprintf(stderr, " old...new: %s...%s\n", oldh, newh);
|
||||
return update_ref("forced-update", name, sha1_new, sha1_old);
|
||||
}
|
||||
|
||||
static int append_fetch_head(FILE *fp,
|
||||
const char *head, const char *remote,
|
||||
const char *remote_name, const char *remote_nick,
|
||||
const char *local_name, int not_for_merge,
|
||||
int verbose, int force)
|
||||
{
|
||||
struct commit *commit;
|
||||
int remote_len, i, note_len;
|
||||
unsigned char sha1[20];
|
||||
char note[1024];
|
||||
const char *what, *kind;
|
||||
|
||||
if (get_sha1(head, sha1))
|
||||
return error("Not a valid object name: %s", head);
|
||||
commit = lookup_commit_reference(sha1);
|
||||
if (!commit)
|
||||
not_for_merge = 1;
|
||||
|
||||
if (!strcmp(remote_name, "HEAD")) {
|
||||
kind = "";
|
||||
what = "";
|
||||
}
|
||||
else if (!strncmp(remote_name, "refs/heads/", 11)) {
|
||||
kind = "branch";
|
||||
what = remote_name + 11;
|
||||
}
|
||||
else if (!strncmp(remote_name, "refs/tags/", 10)) {
|
||||
kind = "tag";
|
||||
what = remote_name + 10;
|
||||
}
|
||||
else if (!strncmp(remote_name, "refs/remotes/", 13)) {
|
||||
kind = "remote branch";
|
||||
what = remote_name + 13;
|
||||
}
|
||||
else {
|
||||
kind = "";
|
||||
what = remote_name;
|
||||
}
|
||||
|
||||
remote_len = strlen(remote);
|
||||
for (i = remote_len - 1; remote[i] == '/' && 0 <= i; i--)
|
||||
;
|
||||
remote_len = i + 1;
|
||||
if (4 < i && !strncmp(".git", remote + i - 3, 4))
|
||||
remote_len = i - 3;
|
||||
|
||||
note_len = 0;
|
||||
if (*what) {
|
||||
if (*kind)
|
||||
note_len += sprintf(note + note_len, "%s ", kind);
|
||||
note_len += sprintf(note + note_len, "'%s' of ", what);
|
||||
}
|
||||
note_len += sprintf(note + note_len, "%.*s", remote_len, remote);
|
||||
fprintf(fp, "%s\t%s\t%s\n",
|
||||
sha1_to_hex(commit ? commit->object.sha1 : sha1),
|
||||
not_for_merge ? "not-for-merge" : "",
|
||||
note);
|
||||
return update_local_ref(local_name, head, note, verbose, force);
|
||||
}
|
||||
|
||||
static char *keep;
|
||||
static void remove_keep(void)
|
||||
{
|
||||
if (keep && *keep)
|
||||
unlink(keep);
|
||||
}
|
||||
|
||||
static void remove_keep_on_signal(int signo)
|
||||
{
|
||||
remove_keep();
|
||||
signal(SIGINT, SIG_DFL);
|
||||
raise(signo);
|
||||
}
|
||||
|
||||
static char *find_local_name(const char *remote_name, const char *refs,
|
||||
int *force_p, int *not_for_merge_p)
|
||||
{
|
||||
const char *ref = refs;
|
||||
int len = strlen(remote_name);
|
||||
|
||||
while (ref) {
|
||||
const char *next;
|
||||
int single_force, not_for_merge;
|
||||
|
||||
while (*ref == '\n')
|
||||
ref++;
|
||||
if (!*ref)
|
||||
break;
|
||||
next = strchr(ref, '\n');
|
||||
|
||||
single_force = not_for_merge = 0;
|
||||
if (*ref == '+') {
|
||||
single_force = 1;
|
||||
ref++;
|
||||
}
|
||||
if (*ref == '.') {
|
||||
not_for_merge = 1;
|
||||
ref++;
|
||||
if (*ref == '+') {
|
||||
single_force = 1;
|
||||
ref++;
|
||||
}
|
||||
}
|
||||
if (!strncmp(remote_name, ref, len) && ref[len] == ':') {
|
||||
const char *local_part = ref + len + 1;
|
||||
char *ret;
|
||||
int retlen;
|
||||
|
||||
if (!next)
|
||||
retlen = strlen(local_part);
|
||||
else
|
||||
retlen = next - local_part;
|
||||
ret = xmalloc(retlen + 1);
|
||||
memcpy(ret, local_part, retlen);
|
||||
ret[retlen] = 0;
|
||||
*force_p = single_force;
|
||||
*not_for_merge_p = not_for_merge;
|
||||
return ret;
|
||||
}
|
||||
ref = next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int fetch_native_store(FILE *fp,
|
||||
const char *remote,
|
||||
const char *remote_nick,
|
||||
const char *refs,
|
||||
int verbose, int force)
|
||||
{
|
||||
char buffer[1024];
|
||||
int err = 0;
|
||||
|
||||
signal(SIGINT, remove_keep_on_signal);
|
||||
atexit(remove_keep);
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), stdin)) {
|
||||
int len;
|
||||
char *cp;
|
||||
char *local_name;
|
||||
int single_force, not_for_merge;
|
||||
|
||||
for (cp = buffer; *cp && !isspace(*cp); cp++)
|
||||
;
|
||||
if (*cp)
|
||||
*cp++ = 0;
|
||||
len = strlen(cp);
|
||||
if (len && cp[len-1] == '\n')
|
||||
cp[--len] = 0;
|
||||
if (!strcmp(buffer, "failed"))
|
||||
die("Fetch failure: %s", remote);
|
||||
if (!strcmp(buffer, "pack"))
|
||||
continue;
|
||||
if (!strcmp(buffer, "keep")) {
|
||||
char *od = get_object_directory();
|
||||
int len = strlen(od) + strlen(cp) + 50;
|
||||
keep = xmalloc(len);
|
||||
sprintf(keep, "%s/pack/pack-%s.keep", od, cp);
|
||||
continue;
|
||||
}
|
||||
|
||||
local_name = find_local_name(cp, refs,
|
||||
&single_force, ¬_for_merge);
|
||||
if (!local_name)
|
||||
continue;
|
||||
err |= append_fetch_head(fp,
|
||||
buffer, remote, cp, remote_nick,
|
||||
local_name, not_for_merge,
|
||||
verbose, force || single_force);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int parse_reflist(const char *reflist)
|
||||
{
|
||||
const char *ref;
|
||||
|
||||
printf("refs='");
|
||||
for (ref = reflist; ref; ) {
|
||||
const char *next;
|
||||
while (*ref && isspace(*ref))
|
||||
ref++;
|
||||
if (!*ref)
|
||||
break;
|
||||
for (next = ref; *next && !isspace(*next); next++)
|
||||
;
|
||||
printf("\n%.*s", (int)(next - ref), ref);
|
||||
ref = next;
|
||||
}
|
||||
printf("'\n");
|
||||
|
||||
printf("rref='");
|
||||
for (ref = reflist; ref; ) {
|
||||
const char *next, *colon;
|
||||
while (*ref && isspace(*ref))
|
||||
ref++;
|
||||
if (!*ref)
|
||||
break;
|
||||
for (next = ref; *next && !isspace(*next); next++)
|
||||
;
|
||||
if (*ref == '.')
|
||||
ref++;
|
||||
if (*ref == '+')
|
||||
ref++;
|
||||
colon = strchr(ref, ':');
|
||||
putchar('\n');
|
||||
printf("%.*s", (int)((colon ? colon : next) - ref), ref);
|
||||
ref = next;
|
||||
}
|
||||
printf("'\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int expand_refs_wildcard(const char *ls_remote_result, int numrefs,
|
||||
const char **refs)
|
||||
{
|
||||
int i, matchlen, replacelen;
|
||||
int found_one = 0;
|
||||
const char *remote = *refs++;
|
||||
numrefs--;
|
||||
|
||||
if (numrefs == 0) {
|
||||
fprintf(stderr, "Nothing specified for fetching with remote.%s.fetch\n",
|
||||
remote);
|
||||
printf("empty\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < numrefs; i++) {
|
||||
const char *ref = refs[i];
|
||||
const char *lref = ref;
|
||||
const char *colon;
|
||||
const char *tail;
|
||||
const char *ls;
|
||||
const char *next;
|
||||
|
||||
if (*lref == '+')
|
||||
lref++;
|
||||
colon = strchr(lref, ':');
|
||||
tail = lref + strlen(lref);
|
||||
if (!(colon &&
|
||||
2 < colon - lref &&
|
||||
colon[-1] == '*' &&
|
||||
colon[-2] == '/' &&
|
||||
2 < tail - (colon + 1) &&
|
||||
tail[-1] == '*' &&
|
||||
tail[-2] == '/')) {
|
||||
/* not a glob */
|
||||
if (!found_one++)
|
||||
printf("explicit\n");
|
||||
printf("%s\n", ref);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* glob */
|
||||
if (!found_one++)
|
||||
printf("glob\n");
|
||||
|
||||
/* lref to colon-2 is remote hierarchy name;
|
||||
* colon+1 to tail-2 is local.
|
||||
*/
|
||||
matchlen = (colon-1) - lref;
|
||||
replacelen = (tail-1) - (colon+1);
|
||||
for (ls = ls_remote_result; ls; ls = next) {
|
||||
const char *eol;
|
||||
unsigned char sha1[20];
|
||||
int namelen;
|
||||
|
||||
while (*ls && isspace(*ls))
|
||||
ls++;
|
||||
next = strchr(ls, '\n');
|
||||
eol = !next ? (ls + strlen(ls)) : next;
|
||||
if (!memcmp("^{}", eol-3, 3))
|
||||
continue;
|
||||
if (eol - ls < 40)
|
||||
continue;
|
||||
if (get_sha1_hex(ls, sha1))
|
||||
continue;
|
||||
ls += 40;
|
||||
while (ls < eol && isspace(*ls))
|
||||
ls++;
|
||||
/* ls to next (or eol) is the name.
|
||||
* is it identical to lref to colon-2?
|
||||
*/
|
||||
if ((eol - ls) <= matchlen ||
|
||||
strncmp(ls, lref, matchlen))
|
||||
continue;
|
||||
|
||||
/* Yes, it is a match */
|
||||
namelen = eol - ls;
|
||||
if (lref != ref)
|
||||
putchar('+');
|
||||
printf("%.*s:%.*s%.*s\n",
|
||||
namelen, ls,
|
||||
replacelen, colon + 1,
|
||||
namelen - matchlen, ls + matchlen);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_fetch__tool(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int verbose = 0;
|
||||
int force = 0;
|
||||
|
||||
while (1 < argc) {
|
||||
const char *arg = argv[1];
|
||||
if (!strcmp("-v", arg))
|
||||
verbose = 1;
|
||||
else if (!strcmp("-f", arg))
|
||||
force = 1;
|
||||
else
|
||||
break;
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (argc <= 1)
|
||||
return error("Missing subcommand");
|
||||
|
||||
if (!strcmp("append-fetch-head", argv[1])) {
|
||||
int result;
|
||||
FILE *fp;
|
||||
|
||||
if (argc != 8)
|
||||
return error("append-fetch-head takes 6 args");
|
||||
fp = fopen(git_path("FETCH_HEAD"), "a");
|
||||
result = append_fetch_head(fp, argv[2], argv[3],
|
||||
argv[4], argv[5],
|
||||
argv[6], !!argv[7][0],
|
||||
verbose, force);
|
||||
fclose(fp);
|
||||
return result;
|
||||
}
|
||||
if (!strcmp("native-store", argv[1])) {
|
||||
int result;
|
||||
FILE *fp;
|
||||
|
||||
if (argc != 5)
|
||||
return error("fetch-native-store takes 3 args");
|
||||
fp = fopen(git_path("FETCH_HEAD"), "a");
|
||||
result = fetch_native_store(fp, argv[2], argv[3], argv[4],
|
||||
verbose, force);
|
||||
fclose(fp);
|
||||
return result;
|
||||
}
|
||||
if (!strcmp("parse-reflist", argv[1])) {
|
||||
const char *reflist;
|
||||
if (argc != 3)
|
||||
return error("parse-reflist takes 1 arg");
|
||||
reflist = argv[2];
|
||||
if (!strcmp(reflist, "-"))
|
||||
reflist = get_stdin();
|
||||
return parse_reflist(reflist);
|
||||
}
|
||||
if (!strcmp("expand-refs-wildcard", argv[1])) {
|
||||
const char *reflist;
|
||||
if (argc < 4)
|
||||
return error("expand-refs-wildcard takes at least 2 args");
|
||||
reflist = argv[2];
|
||||
if (!strcmp(reflist, "-"))
|
||||
reflist = get_stdin();
|
||||
return expand_refs_wildcard(reflist, argc - 3, argv + 3);
|
||||
}
|
||||
|
||||
return error("Unknown subcommand: %s", argv[1]);
|
||||
}
|
||||
@@ -431,6 +431,19 @@ static const char emsg_missing_context_len[] =
|
||||
static const char emsg_missing_argument[] =
|
||||
"option requires an argument -%s";
|
||||
|
||||
static int strtoul_ui(char const *s, unsigned int *result)
|
||||
{
|
||||
unsigned long ul;
|
||||
char *p;
|
||||
|
||||
errno = 0;
|
||||
ul = strtoul(s, &p, 10);
|
||||
if (errno || *p || p == s || (unsigned int) ul != ul)
|
||||
return -1;
|
||||
*result = ul;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_grep(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int hit = 0;
|
||||
@@ -553,7 +566,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
|
||||
scan = arg + 1;
|
||||
break;
|
||||
}
|
||||
if (sscanf(scan, "%u", &num) != 1)
|
||||
if (strtoul_ui(scan, &num))
|
||||
die(emsg_invalid_context_len, scan);
|
||||
switch (arg[1]) {
|
||||
case 'A':
|
||||
|
||||
@@ -11,19 +11,22 @@ static FILE *cmitmsg, *patchfile, *fin, *fout;
|
||||
static int keep_subject;
|
||||
static const char *metainfo_charset;
|
||||
static char line[1000];
|
||||
static char date[1000];
|
||||
static char name[1000];
|
||||
static char email[1000];
|
||||
static char subject[1000];
|
||||
|
||||
static enum {
|
||||
TE_DONTCARE, TE_QP, TE_BASE64,
|
||||
} transfer_encoding;
|
||||
static char charset[256];
|
||||
static enum {
|
||||
TYPE_TEXT, TYPE_OTHER,
|
||||
} message_type;
|
||||
|
||||
static char multipart_boundary[1000];
|
||||
static int multipart_boundary_len;
|
||||
static char charset[256];
|
||||
static int patch_lines;
|
||||
static char **p_hdr_data, **s_hdr_data;
|
||||
|
||||
#define MAX_HDR_PARSED 10
|
||||
#define MAX_BOUNDARIES 5
|
||||
|
||||
static char *sanity_check(char *name, char *email)
|
||||
{
|
||||
@@ -137,15 +140,13 @@ static int handle_from(char *in_line)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_date(char *line)
|
||||
static int handle_header(char *line, char *data, int ofs)
|
||||
{
|
||||
strcpy(date, line);
|
||||
return 0;
|
||||
}
|
||||
if (!line || !data)
|
||||
return 1;
|
||||
|
||||
strcpy(data, line+ofs);
|
||||
|
||||
static int handle_subject(char *line)
|
||||
{
|
||||
strcpy(subject, line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -177,17 +178,32 @@ static int slurp_attr(const char *line, const char *name, char *attr)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_subcontent_type(char *line)
|
||||
struct content_type {
|
||||
char *boundary;
|
||||
int boundary_len;
|
||||
};
|
||||
|
||||
static struct content_type content[MAX_BOUNDARIES];
|
||||
|
||||
static struct content_type *content_top = content;
|
||||
|
||||
static int handle_content_type(char *line)
|
||||
{
|
||||
/* We do not want to mess with boundary. Note that we do not
|
||||
* handle nested multipart.
|
||||
*/
|
||||
if (strcasestr(line, "boundary=")) {
|
||||
fprintf(stderr, "Not handling nested multipart message.\n");
|
||||
exit(1);
|
||||
char boundary[256];
|
||||
|
||||
if (strcasestr(line, "text/") == NULL)
|
||||
message_type = TYPE_OTHER;
|
||||
if (slurp_attr(line, "boundary=", boundary + 2)) {
|
||||
memcpy(boundary, "--", 2);
|
||||
if (content_top++ >= &content[MAX_BOUNDARIES]) {
|
||||
fprintf(stderr, "Too many boundaries to handle\n");
|
||||
exit(1);
|
||||
}
|
||||
content_top->boundary_len = strlen(boundary);
|
||||
content_top->boundary = xmalloc(content_top->boundary_len+1);
|
||||
strcpy(content_top->boundary, boundary);
|
||||
}
|
||||
slurp_attr(line, "charset=", charset);
|
||||
if (*charset) {
|
||||
if (slurp_attr(line, "charset=", charset)) {
|
||||
int i, c;
|
||||
for (i = 0; (c = charset[i]) != 0; i++)
|
||||
charset[i] = tolower(c);
|
||||
@@ -195,17 +211,6 @@ static int handle_subcontent_type(char *line)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_content_type(char *line)
|
||||
{
|
||||
*multipart_boundary = 0;
|
||||
if (slurp_attr(line, "boundary=", multipart_boundary + 2)) {
|
||||
memcpy(multipart_boundary, "--", 2);
|
||||
multipart_boundary_len = strlen(multipart_boundary);
|
||||
}
|
||||
slurp_attr(line, "charset=", charset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_content_transfer_encoding(char *line)
|
||||
{
|
||||
if (strcasestr(line, "base64"))
|
||||
@@ -219,7 +224,7 @@ static int handle_content_transfer_encoding(char *line)
|
||||
|
||||
static int is_multipart_boundary(const char *line)
|
||||
{
|
||||
return (!memcmp(line, multipart_boundary, multipart_boundary_len));
|
||||
return (!memcmp(line, content_top->boundary, content_top->boundary_len));
|
||||
}
|
||||
|
||||
static int eatspace(char *line)
|
||||
@@ -230,62 +235,6 @@ static int eatspace(char *line)
|
||||
return len;
|
||||
}
|
||||
|
||||
#define SEEN_FROM 01
|
||||
#define SEEN_DATE 02
|
||||
#define SEEN_SUBJECT 04
|
||||
#define SEEN_BOGUS_UNIX_FROM 010
|
||||
#define SEEN_PREFIX 020
|
||||
|
||||
/* First lines of body can have From:, Date:, and Subject: or empty */
|
||||
static void handle_inbody_header(int *seen, char *line)
|
||||
{
|
||||
if (*seen & SEEN_PREFIX)
|
||||
return;
|
||||
if (isspace(*line)) {
|
||||
char *cp;
|
||||
for (cp = line + 1; *cp; cp++) {
|
||||
if (!isspace(*cp))
|
||||
break;
|
||||
}
|
||||
if (!*cp)
|
||||
return;
|
||||
}
|
||||
if (!memcmp(">From", line, 5) && isspace(line[5])) {
|
||||
if (!(*seen & SEEN_BOGUS_UNIX_FROM)) {
|
||||
*seen |= SEEN_BOGUS_UNIX_FROM;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!memcmp("From:", line, 5) && isspace(line[5])) {
|
||||
if (!(*seen & SEEN_FROM) && handle_from(line+6)) {
|
||||
*seen |= SEEN_FROM;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!memcmp("Date:", line, 5) && isspace(line[5])) {
|
||||
if (!(*seen & SEEN_DATE)) {
|
||||
handle_date(line+6);
|
||||
*seen |= SEEN_DATE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!memcmp("Subject:", line, 8) && isspace(line[8])) {
|
||||
if (!(*seen & SEEN_SUBJECT)) {
|
||||
handle_subject(line+9);
|
||||
*seen |= SEEN_SUBJECT;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!memcmp("[PATCH]", line, 7) && isspace(line[7])) {
|
||||
if (!(*seen & SEEN_SUBJECT)) {
|
||||
handle_subject(line);
|
||||
*seen |= SEEN_SUBJECT;
|
||||
return;
|
||||
}
|
||||
}
|
||||
*seen |= SEEN_PREFIX;
|
||||
}
|
||||
|
||||
static char *cleanup_subject(char *subject)
|
||||
{
|
||||
if (keep_subject)
|
||||
@@ -296,7 +245,7 @@ static char *cleanup_subject(char *subject)
|
||||
switch (*subject) {
|
||||
case 'r': case 'R':
|
||||
if (!memcmp("e:", subject+1, 2)) {
|
||||
subject +=3;
|
||||
subject += 3;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@@ -341,57 +290,62 @@ static void cleanup_space(char *buf)
|
||||
}
|
||||
|
||||
static void decode_header(char *it);
|
||||
typedef int (*header_fn_t)(char *);
|
||||
struct header_def {
|
||||
const char *name;
|
||||
header_fn_t func;
|
||||
int namelen;
|
||||
static char *header[MAX_HDR_PARSED] = {
|
||||
"From","Subject","Date",
|
||||
};
|
||||
|
||||
static void check_header(char *line, struct header_def *header)
|
||||
static int check_header(char *line, char **hdr_data)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (header[0].namelen <= 0) {
|
||||
for (i = 0; header[i].name; i++)
|
||||
header[i].namelen = strlen(header[i].name);
|
||||
}
|
||||
for (i = 0; header[i].name; i++) {
|
||||
int len = header[i].namelen;
|
||||
if (!strncasecmp(line, header[i].name, len) &&
|
||||
/* search for the interesting parts */
|
||||
for (i = 0; header[i]; i++) {
|
||||
int len = strlen(header[i]);
|
||||
if (!hdr_data[i] &&
|
||||
!strncasecmp(line, header[i], len) &&
|
||||
line[len] == ':' && isspace(line[len + 1])) {
|
||||
/* Unwrap inline B and Q encoding, and optionally
|
||||
* normalize the meta information to utf8.
|
||||
*/
|
||||
decode_header(line + len + 2);
|
||||
header[i].func(line + len + 2);
|
||||
break;
|
||||
hdr_data[i] = xmalloc(1000 * sizeof(char));
|
||||
if (! handle_header(line, hdr_data[i], len + 2)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void check_subheader_line(char *line)
|
||||
{
|
||||
static struct header_def header[] = {
|
||||
{ "Content-Type", handle_subcontent_type },
|
||||
{ "Content-Transfer-Encoding",
|
||||
handle_content_transfer_encoding },
|
||||
{ NULL },
|
||||
};
|
||||
check_header(line, header);
|
||||
}
|
||||
static void check_header_line(char *line)
|
||||
{
|
||||
static struct header_def header[] = {
|
||||
{ "From", handle_from },
|
||||
{ "Date", handle_date },
|
||||
{ "Subject", handle_subject },
|
||||
{ "Content-Type", handle_content_type },
|
||||
{ "Content-Transfer-Encoding",
|
||||
handle_content_transfer_encoding },
|
||||
{ NULL },
|
||||
};
|
||||
check_header(line, header);
|
||||
/* Content stuff */
|
||||
if (!strncasecmp(line, "Content-Type", 12) &&
|
||||
line[12] == ':' && isspace(line[12 + 1])) {
|
||||
decode_header(line + 12 + 2);
|
||||
if (! handle_content_type(line)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (!strncasecmp(line, "Content-Transfer-Encoding", 25) &&
|
||||
line[25] == ':' && isspace(line[25 + 1])) {
|
||||
decode_header(line + 25 + 2);
|
||||
if (! handle_content_transfer_encoding(line)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* for inbody stuff */
|
||||
if (!memcmp(">From", line, 5) && isspace(line[5]))
|
||||
return 1;
|
||||
if (!memcmp("[PATCH]", line, 7) && isspace(line[7])) {
|
||||
for (i = 0; header[i]; i++) {
|
||||
if (!memcmp("Subject: ", header[i], 9)) {
|
||||
if (! handle_header(line, hdr_data[i], 0)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* no match */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_rfc2822_header(char *line)
|
||||
@@ -647,39 +601,170 @@ static void decode_transfer_encoding(char *line)
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_info(void)
|
||||
static int handle_filter(char *line);
|
||||
|
||||
static int find_boundary(void)
|
||||
{
|
||||
char *sub;
|
||||
|
||||
sub = cleanup_subject(subject);
|
||||
cleanup_space(name);
|
||||
cleanup_space(date);
|
||||
cleanup_space(email);
|
||||
cleanup_space(sub);
|
||||
|
||||
fprintf(fout, "Author: %s\nEmail: %s\nSubject: %s\nDate: %s\n\n",
|
||||
name, email, sub, date);
|
||||
while(fgets(line, sizeof(line), fin) != NULL) {
|
||||
if (is_multipart_boundary(line))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We are inside message body and have read line[] already.
|
||||
* Spit out the commit log.
|
||||
*/
|
||||
static int handle_commit_msg(int *seen)
|
||||
static int handle_boundary(void)
|
||||
{
|
||||
again:
|
||||
if (!memcmp(line+content_top->boundary_len, "--", 2)) {
|
||||
/* we hit an end boundary */
|
||||
/* pop the current boundary off the stack */
|
||||
free(content_top->boundary);
|
||||
|
||||
/* technically won't happen as is_multipart_boundary()
|
||||
will fail first. But just in case..
|
||||
*/
|
||||
if (content_top-- < content) {
|
||||
fprintf(stderr, "Detected mismatched boundaries, "
|
||||
"can't recover\n");
|
||||
exit(1);
|
||||
}
|
||||
handle_filter("\n");
|
||||
|
||||
/* skip to the next boundary */
|
||||
if (!find_boundary())
|
||||
return 0;
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* set some defaults */
|
||||
transfer_encoding = TE_DONTCARE;
|
||||
charset[0] = 0;
|
||||
message_type = TYPE_TEXT;
|
||||
|
||||
/* slurp in this section's info */
|
||||
while (read_one_header_line(line, sizeof(line), fin))
|
||||
check_header(line, p_hdr_data);
|
||||
|
||||
/* eat the blank line after section info */
|
||||
return (fgets(line, sizeof(line), fin) != NULL);
|
||||
}
|
||||
|
||||
static inline int patchbreak(const char *line)
|
||||
{
|
||||
/* Beginning of a "diff -" header? */
|
||||
if (!memcmp("diff -", line, 6))
|
||||
return 1;
|
||||
|
||||
/* CVS "Index: " line? */
|
||||
if (!memcmp("Index: ", line, 7))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* "--- <filename>" starts patches without headers
|
||||
* "---<sp>*" is a manual separator
|
||||
*/
|
||||
if (!memcmp("---", line, 3)) {
|
||||
line += 3;
|
||||
/* space followed by a filename? */
|
||||
if (line[0] == ' ' && !isspace(line[1]))
|
||||
return 1;
|
||||
/* Just whitespace? */
|
||||
for (;;) {
|
||||
unsigned char c = *line++;
|
||||
if (c == '\n')
|
||||
return 1;
|
||||
if (!isspace(c))
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int handle_commit_msg(char *line)
|
||||
{
|
||||
static int still_looking = 1;
|
||||
|
||||
if (!cmitmsg)
|
||||
return 0;
|
||||
do {
|
||||
if (!memcmp("diff -", line, 6) ||
|
||||
!memcmp("---", line, 3) ||
|
||||
!memcmp("Index: ", line, 7))
|
||||
|
||||
if (still_looking) {
|
||||
char *cp = line;
|
||||
if (isspace(*line)) {
|
||||
for (cp = line + 1; *cp; cp++) {
|
||||
if (!isspace(*cp))
|
||||
break;
|
||||
}
|
||||
if (!*cp)
|
||||
return 0;
|
||||
}
|
||||
if ((still_looking = check_header(cp, s_hdr_data)) != 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (patchbreak(line)) {
|
||||
fclose(cmitmsg);
|
||||
cmitmsg = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
fputs(line, cmitmsg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_patch(char *line)
|
||||
{
|
||||
fputs(line, patchfile);
|
||||
patch_lines++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_filter(char *line)
|
||||
{
|
||||
static int filter = 0;
|
||||
|
||||
/* filter tells us which part we left off on
|
||||
* a non-zero return indicates we hit a filter point
|
||||
*/
|
||||
switch (filter) {
|
||||
case 0:
|
||||
if (!handle_commit_msg(line))
|
||||
break;
|
||||
if ((multipart_boundary[0] && is_multipart_boundary(line))) {
|
||||
/* We come here when the first part had only
|
||||
* the commit message without any patch. We
|
||||
* pretend we have not seen this line yet, and
|
||||
* go back to the loop.
|
||||
*/
|
||||
return 1;
|
||||
filter++;
|
||||
case 1:
|
||||
if (!handle_patch(line))
|
||||
break;
|
||||
filter++;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handle_body(void)
|
||||
{
|
||||
int rc = 0;
|
||||
static char newline[2000];
|
||||
static char *np = newline;
|
||||
|
||||
/* Skip up to the first boundary */
|
||||
if (content_top->boundary) {
|
||||
if (!find_boundary())
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
/* process any boundary lines */
|
||||
if (content_top->boundary && is_multipart_boundary(line)) {
|
||||
/* flush any leftover */
|
||||
if ((transfer_encoding == TE_BASE64) &&
|
||||
(np != newline)) {
|
||||
handle_filter(newline);
|
||||
}
|
||||
if (!handle_boundary())
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unwrap transfer encoding and optionally
|
||||
@@ -689,105 +774,80 @@ static int handle_commit_msg(int *seen)
|
||||
if (metainfo_charset)
|
||||
convert_to_utf8(line, charset);
|
||||
|
||||
handle_inbody_header(seen, line);
|
||||
if (!(*seen & SEEN_PREFIX))
|
||||
switch (transfer_encoding) {
|
||||
case TE_BASE64:
|
||||
{
|
||||
char *op = line;
|
||||
|
||||
/* binary data most likely doesn't have newlines */
|
||||
if (message_type != TYPE_TEXT) {
|
||||
rc = handle_filter(line);
|
||||
break;
|
||||
}
|
||||
|
||||
/* this is a decoded line that may contain
|
||||
* multiple new lines. Pass only one chunk
|
||||
* at a time to handle_filter()
|
||||
*/
|
||||
|
||||
do {
|
||||
while (*op != '\n' && *op != 0)
|
||||
*np++ = *op++;
|
||||
*np = *op;
|
||||
if (*np != 0) {
|
||||
/* should be sitting on a new line */
|
||||
*(++np) = 0;
|
||||
op++;
|
||||
rc = handle_filter(newline);
|
||||
np = newline;
|
||||
}
|
||||
} while (*op != 0);
|
||||
/* the partial chunk is saved in newline and
|
||||
* will be appended by the next iteration of fgets
|
||||
*/
|
||||
break;
|
||||
}
|
||||
default:
|
||||
rc = handle_filter(line);
|
||||
}
|
||||
if (rc)
|
||||
/* nothing left to filter */
|
||||
break;
|
||||
} while (fgets(line, sizeof(line), fin));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void handle_info(void)
|
||||
{
|
||||
char *sub;
|
||||
char *hdr;
|
||||
int i;
|
||||
|
||||
for (i = 0; header[i]; i++) {
|
||||
|
||||
/* only print inbody headers if we output a patch file */
|
||||
if (patch_lines && s_hdr_data[i])
|
||||
hdr = s_hdr_data[i];
|
||||
else if (p_hdr_data[i])
|
||||
hdr = p_hdr_data[i];
|
||||
else
|
||||
continue;
|
||||
|
||||
fputs(line, cmitmsg);
|
||||
} while (fgets(line, sizeof(line), fin) != NULL);
|
||||
fclose(cmitmsg);
|
||||
cmitmsg = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We have done the commit message and have the first
|
||||
* line of the patch in line[].
|
||||
*/
|
||||
static void handle_patch(void)
|
||||
{
|
||||
do {
|
||||
if (multipart_boundary[0] && is_multipart_boundary(line))
|
||||
break;
|
||||
/* Only unwrap transfer encoding but otherwise do not
|
||||
* do anything. We do *NOT* want UTF-8 conversion
|
||||
* here; we are dealing with the user payload.
|
||||
*/
|
||||
decode_transfer_encoding(line);
|
||||
fputs(line, patchfile);
|
||||
patch_lines++;
|
||||
} while (fgets(line, sizeof(line), fin) != NULL);
|
||||
}
|
||||
|
||||
/* multipart boundary and transfer encoding are set up for us, and we
|
||||
* are at the end of the sub header. do equivalent of handle_body up
|
||||
* to the next boundary without closing patchfile --- we will expect
|
||||
* that the first part to contain commit message and a patch, and
|
||||
* handle other parts as pure patches.
|
||||
*/
|
||||
static int handle_multipart_one_part(int *seen)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
while (fgets(line, sizeof(line), fin) != NULL) {
|
||||
again:
|
||||
n++;
|
||||
if (is_multipart_boundary(line))
|
||||
break;
|
||||
if (handle_commit_msg(seen))
|
||||
goto again;
|
||||
handle_patch();
|
||||
break;
|
||||
}
|
||||
if (n == 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handle_multipart_body(void)
|
||||
{
|
||||
int seen = 0;
|
||||
int part_num = 0;
|
||||
|
||||
/* Skip up to the first boundary */
|
||||
while (fgets(line, sizeof(line), fin) != NULL)
|
||||
if (is_multipart_boundary(line)) {
|
||||
part_num = 1;
|
||||
break;
|
||||
if (!memcmp(header[i], "Subject", 7)) {
|
||||
sub = cleanup_subject(hdr);
|
||||
cleanup_space(sub);
|
||||
fprintf(fout, "Subject: %s\n", sub);
|
||||
} else if (!memcmp(header[i], "From", 4)) {
|
||||
handle_from(hdr);
|
||||
fprintf(fout, "Author: %s\n", name);
|
||||
fprintf(fout, "Email: %s\n", email);
|
||||
} else {
|
||||
cleanup_space(hdr);
|
||||
fprintf(fout, "%s: %s\n", header[i], hdr);
|
||||
}
|
||||
if (!part_num)
|
||||
return;
|
||||
/* We are on boundary line. Start slurping the subhead. */
|
||||
while (1) {
|
||||
int hdr = read_one_header_line(line, sizeof(line), fin);
|
||||
if (!hdr) {
|
||||
if (handle_multipart_one_part(&seen) < 0)
|
||||
return;
|
||||
/* Reset per part headers */
|
||||
transfer_encoding = TE_DONTCARE;
|
||||
charset[0] = 0;
|
||||
}
|
||||
else
|
||||
check_subheader_line(line);
|
||||
}
|
||||
fclose(patchfile);
|
||||
if (!patch_lines) {
|
||||
fprintf(stderr, "No patch found\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Non multipart message */
|
||||
static void handle_body(void)
|
||||
{
|
||||
int seen = 0;
|
||||
|
||||
handle_commit_msg(&seen);
|
||||
handle_patch();
|
||||
fclose(patchfile);
|
||||
if (!patch_lines) {
|
||||
fprintf(stderr, "No patch found\n");
|
||||
exit(1);
|
||||
}
|
||||
fprintf(fout, "\n");
|
||||
}
|
||||
|
||||
int mailinfo(FILE *in, FILE *out, int ks, const char *encoding,
|
||||
@@ -809,18 +869,16 @@ int mailinfo(FILE *in, FILE *out, int ks, const char *encoding,
|
||||
fclose(cmitmsg);
|
||||
return -1;
|
||||
}
|
||||
while (1) {
|
||||
int hdr = read_one_header_line(line, sizeof(line), fin);
|
||||
if (!hdr) {
|
||||
if (multipart_boundary[0])
|
||||
handle_multipart_body();
|
||||
else
|
||||
handle_body();
|
||||
handle_info();
|
||||
break;
|
||||
}
|
||||
check_header_line(line);
|
||||
}
|
||||
|
||||
p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(char *));
|
||||
s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(char *));
|
||||
|
||||
/* process the email header */
|
||||
while (read_one_header_line(line, sizeof(line), fin))
|
||||
check_header(line, p_hdr_data);
|
||||
|
||||
handle_body();
|
||||
handle_info();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -304,8 +304,11 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
|
||||
if (!access(".mailmap", R_OK))
|
||||
read_mailmap(".mailmap");
|
||||
|
||||
if (rev.pending.nr == 0)
|
||||
if (rev.pending.nr == 0) {
|
||||
if (isatty(0))
|
||||
fprintf(stderr, "(reading log to summarize from standard input)\n");
|
||||
read_from_stdin(&list);
|
||||
}
|
||||
else
|
||||
get_from_rev(&rev, &list);
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_diff_index(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_diff(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_diff_tree(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_fetch__tool(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_for_each_ref(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_format_patch(int argc, const char **argv, const char *prefix);
|
||||
|
||||
2
cache.h
2
cache.h
@@ -373,6 +373,7 @@ extern struct packed_git {
|
||||
struct packed_git *next;
|
||||
struct pack_window *windows;
|
||||
uint32_t *index_base;
|
||||
time_t mtime;
|
||||
off_t index_size;
|
||||
off_t pack_size;
|
||||
int pack_fd;
|
||||
@@ -481,6 +482,7 @@ extern struct tag *alloc_tag_node(void);
|
||||
extern void alloc_report(void);
|
||||
|
||||
/* trace.c */
|
||||
extern int nfasprintf(char **str, const char *fmt, ...);
|
||||
extern int nfvasprintf(char **str, const char *fmt, va_list va);
|
||||
extern void trace_printf(const char *format, ...);
|
||||
extern void trace_argv_printf(const char **argv, int count, const char *format, ...);
|
||||
|
||||
@@ -1058,7 +1058,7 @@ static void load_tree(struct tree_entry *root)
|
||||
struct tree_entry *e = new_tree_entry();
|
||||
|
||||
if (t->entry_count == t->entry_capacity)
|
||||
root->tree = t = grow_tree_content(t, 8);
|
||||
root->tree = t = grow_tree_content(t, t->entry_count);
|
||||
t->entries[t->entry_count++] = e;
|
||||
|
||||
e->tree = NULL;
|
||||
@@ -1066,7 +1066,7 @@ static void load_tree(struct tree_entry *root)
|
||||
if (!c)
|
||||
die("Corrupt mode in %s", sha1_to_hex(sha1));
|
||||
e->versions[0].mode = e->versions[1].mode;
|
||||
e->name = to_atom(c, (unsigned short)strlen(c));
|
||||
e->name = to_atom(c, strlen(c));
|
||||
c += e->name->str_len + 1;
|
||||
hashcpy(e->versions[0].sha1, (unsigned char*)c);
|
||||
hashcpy(e->versions[1].sha1, (unsigned char*)c);
|
||||
@@ -1225,9 +1225,9 @@ static int tree_content_set(
|
||||
}
|
||||
|
||||
if (t->entry_count == t->entry_capacity)
|
||||
root->tree = t = grow_tree_content(t, 8);
|
||||
root->tree = t = grow_tree_content(t, t->entry_count);
|
||||
e = new_tree_entry();
|
||||
e->name = to_atom(p, (unsigned short)n);
|
||||
e->name = to_atom(p, n);
|
||||
e->versions[0].mode = 0;
|
||||
hashclr(e->versions[0].sha1);
|
||||
t->entries[t->entry_count++] = e;
|
||||
|
||||
@@ -290,6 +290,10 @@ do
|
||||
git-mailinfo $keep $utf8 "$dotest/msg" "$dotest/patch" \
|
||||
<"$dotest/$msgnum" >"$dotest/info" ||
|
||||
stop_here $this
|
||||
test -s $dotest/patch || {
|
||||
echo "Patch is empty. Was is split wrong?"
|
||||
stop_here $this
|
||||
}
|
||||
git-stripspace < "$dotest/msg" > "$dotest/msg-clean"
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -77,6 +77,10 @@ do
|
||||
*)
|
||||
git-mailinfo $keep_subject $utf8 \
|
||||
.dotest/msg .dotest/patch <$i >.dotest/info || exit 1
|
||||
test -s $dotest/patch || {
|
||||
echo "Patch is empty. Was is split wrong?"
|
||||
stop_here $this
|
||||
}
|
||||
git-stripspace < .dotest/msg > .dotest/msg-clean
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -12,6 +12,7 @@ new=
|
||||
new_name=
|
||||
force=
|
||||
branch=
|
||||
track=
|
||||
newbranch=
|
||||
newbranch_log=
|
||||
merge=
|
||||
@@ -33,7 +34,10 @@ while [ "$#" != "0" ]; do
|
||||
die "git checkout: we do not like '$newbranch' as a branch name."
|
||||
;;
|
||||
"-l")
|
||||
newbranch_log=1
|
||||
newbranch_log=-l
|
||||
;;
|
||||
"--track"|"--no-track")
|
||||
track="$arg"
|
||||
;;
|
||||
"-f")
|
||||
force=1
|
||||
@@ -85,6 +89,11 @@ while [ "$#" != "0" ]; do
|
||||
esac
|
||||
done
|
||||
|
||||
case "$new_branch,$track" in
|
||||
,--*)
|
||||
die "git checkout: --track and --no-track require -b"
|
||||
esac
|
||||
|
||||
case "$force$merge" in
|
||||
11)
|
||||
die "git checkout: -f and -m are incompatible"
|
||||
@@ -199,7 +208,7 @@ else
|
||||
work=`git write-tree` &&
|
||||
git read-tree --reset -u $new || exit
|
||||
|
||||
eval GITHEAD_$new=${new_name:-${branch:-$new}} &&
|
||||
eval GITHEAD_$new='${new_name:-${branch:-$new}}' &&
|
||||
eval GITHEAD_$work=local &&
|
||||
export GITHEAD_$new GITHEAD_$work &&
|
||||
git merge-recursive $old -- $new $work
|
||||
@@ -242,11 +251,7 @@ fi
|
||||
#
|
||||
if [ "$?" -eq 0 ]; then
|
||||
if [ "$newbranch" ]; then
|
||||
if [ "$newbranch_log" ]; then
|
||||
mkdir -p $(dirname "$GIT_DIR/logs/refs/heads/$newbranch")
|
||||
touch "$GIT_DIR/logs/refs/heads/$newbranch"
|
||||
fi
|
||||
git-update-ref -m "checkout: Created from $new_name" "refs/heads/$newbranch" $new || exit
|
||||
git-branch $track $newbranch_log "$newbranch" "$new_name" || exit
|
||||
branch="$newbranch"
|
||||
fi
|
||||
if test -n "$branch"
|
||||
|
||||
251
git-fetch.sh
251
git-fetch.sh
@@ -109,133 +109,11 @@ ls_remote_result=$(git ls-remote $exec "$remote") ||
|
||||
die "Cannot get the repository state from $remote"
|
||||
|
||||
append_fetch_head () {
|
||||
head_="$1"
|
||||
remote_="$2"
|
||||
remote_name_="$3"
|
||||
remote_nick_="$4"
|
||||
local_name_="$5"
|
||||
case "$6" in
|
||||
t) not_for_merge_='not-for-merge' ;;
|
||||
'') not_for_merge_= ;;
|
||||
esac
|
||||
|
||||
# remote-nick is the URL given on the command line (or a shorthand)
|
||||
# remote-name is the $GIT_DIR relative refs/ path we computed
|
||||
# for this refspec.
|
||||
|
||||
# the $note_ variable will be fed to git-fmt-merge-msg for further
|
||||
# processing.
|
||||
case "$remote_name_" in
|
||||
HEAD)
|
||||
note_= ;;
|
||||
refs/heads/*)
|
||||
note_="$(expr "$remote_name_" : 'refs/heads/\(.*\)')"
|
||||
note_="branch '$note_' of " ;;
|
||||
refs/tags/*)
|
||||
note_="$(expr "$remote_name_" : 'refs/tags/\(.*\)')"
|
||||
note_="tag '$note_' of " ;;
|
||||
refs/remotes/*)
|
||||
note_="$(expr "$remote_name_" : 'refs/remotes/\(.*\)')"
|
||||
note_="remote branch '$note_' of " ;;
|
||||
*)
|
||||
note_="$remote_name of " ;;
|
||||
esac
|
||||
remote_1_=$(expr "z$remote_" : 'z\(.*\)\.git/*$') &&
|
||||
remote_="$remote_1_"
|
||||
note_="$note_$remote_"
|
||||
|
||||
# 2.6.11-tree tag would not be happy to be fed to resolve.
|
||||
if git-cat-file commit "$head_" >/dev/null 2>&1
|
||||
then
|
||||
headc_=$(git-rev-parse --verify "$head_^0") || exit
|
||||
echo "$headc_ $not_for_merge_ $note_" >>"$GIT_DIR/FETCH_HEAD"
|
||||
else
|
||||
echo "$head_ not-for-merge $note_" >>"$GIT_DIR/FETCH_HEAD"
|
||||
fi
|
||||
|
||||
update_local_ref "$local_name_" "$head_" "$note_"
|
||||
}
|
||||
|
||||
update_local_ref () {
|
||||
# If we are storing the head locally make sure that it is
|
||||
# a fast forward (aka "reverse push").
|
||||
|
||||
label_=$(git-cat-file -t $2)
|
||||
newshort_=$(git-rev-parse --short $2)
|
||||
if test -z "$1" ; then
|
||||
[ "$verbose" ] && echo >&2 "* fetched $3"
|
||||
[ "$verbose" ] && echo >&2 " $label_: $newshort_"
|
||||
return 0
|
||||
fi
|
||||
oldshort_=$(git show-ref --hash --abbrev "$1" 2>/dev/null)
|
||||
|
||||
case "$1" in
|
||||
refs/tags/*)
|
||||
# Tags need not be pointing at commits so there
|
||||
# is no way to guarantee "fast-forward" anyway.
|
||||
if test -n "$oldshort_"
|
||||
then
|
||||
if now_=$(git show-ref --hash "$1") && test "$now_" = "$2"
|
||||
then
|
||||
[ "$verbose" ] && echo >&2 "* $1: same as $3"
|
||||
[ "$verbose" ] && echo >&2 " $label_: $newshort_" ||:
|
||||
else
|
||||
echo >&2 "* $1: updating with $3"
|
||||
echo >&2 " $label_: $newshort_"
|
||||
git-update-ref -m "$GIT_REFLOG_ACTION: updating tag" "$1" "$2"
|
||||
fi
|
||||
else
|
||||
echo >&2 "* $1: storing $3"
|
||||
echo >&2 " $label_: $newshort_"
|
||||
git-update-ref -m "$GIT_REFLOG_ACTION: storing tag" "$1" "$2"
|
||||
fi
|
||||
;;
|
||||
|
||||
refs/heads/* | refs/remotes/*)
|
||||
# $1 is the ref being updated.
|
||||
# $2 is the new value for the ref.
|
||||
local=$(git-rev-parse --verify "$1^0" 2>/dev/null)
|
||||
if test "$local"
|
||||
then
|
||||
# Require fast-forward.
|
||||
mb=$(git-merge-base "$local" "$2") &&
|
||||
case "$2,$mb" in
|
||||
$local,*)
|
||||
if test -n "$verbose"
|
||||
then
|
||||
echo >&2 "* $1: same as $3"
|
||||
echo >&2 " $label_: $newshort_"
|
||||
fi
|
||||
;;
|
||||
*,$local)
|
||||
echo >&2 "* $1: fast forward to $3"
|
||||
echo >&2 " old..new: $oldshort_..$newshort_"
|
||||
git-update-ref -m "$GIT_REFLOG_ACTION: fast-forward" "$1" "$2" "$local"
|
||||
;;
|
||||
*)
|
||||
false
|
||||
;;
|
||||
esac || {
|
||||
case ",$force,$single_force," in
|
||||
*,t,*)
|
||||
echo >&2 "* $1: forcing update to non-fast forward $3"
|
||||
echo >&2 " old...new: $oldshort_...$newshort_"
|
||||
git-update-ref -m "$GIT_REFLOG_ACTION: forced-update" "$1" "$2" "$local"
|
||||
;;
|
||||
*)
|
||||
echo >&2 "* $1: not updating to non-fast forward $3"
|
||||
echo >&2 " old...new: $oldshort_...$newshort_"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
else
|
||||
echo >&2 "* $1: storing $3"
|
||||
echo >&2 " $label_: $newshort_"
|
||||
git-update-ref -m "$GIT_REFLOG_ACTION: storing head" "$1" "$2"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
flags=
|
||||
test -n "$verbose" && flags="$flags -v"
|
||||
test -n "$force" && flags="$flags -f"
|
||||
GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION" \
|
||||
git-fetch--tool $flags append-fetch-head "$@"
|
||||
}
|
||||
|
||||
# updating the current HEAD with git-fetch in a bare
|
||||
@@ -279,7 +157,38 @@ then
|
||||
fi
|
||||
fi
|
||||
|
||||
fetch_main () {
|
||||
fetch_native () {
|
||||
|
||||
eval=$(echo "$1" | git-fetch--tool parse-reflist "-")
|
||||
eval "$eval"
|
||||
|
||||
( : subshell because we muck with IFS
|
||||
IFS=" $LF"
|
||||
(
|
||||
if test -f "$remote" ; then
|
||||
test -n "$shallow_depth" &&
|
||||
die "shallow clone with bundle is not supported"
|
||||
git-bundle unbundle "$remote" $rref ||
|
||||
echo failed "$remote"
|
||||
else
|
||||
git-fetch-pack --thin $exec $keep $shallow_depth $no_progress \
|
||||
"$remote" $rref ||
|
||||
echo failed "$remote"
|
||||
fi
|
||||
) |
|
||||
(
|
||||
flags=
|
||||
test -n "$verbose" && flags="$flags -v"
|
||||
test -n "$force" && flags="$flags -f"
|
||||
GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION" \
|
||||
git-fetch--tool $flags native-store \
|
||||
"$remote" "$remote_nick" "$refs"
|
||||
)
|
||||
) || exit
|
||||
|
||||
}
|
||||
|
||||
fetch_dumb () {
|
||||
reflist="$1"
|
||||
refs=
|
||||
rref=
|
||||
@@ -371,9 +280,6 @@ fetch_main () {
|
||||
rsync_slurped_objects=t
|
||||
}
|
||||
;;
|
||||
*)
|
||||
# We will do git native transport with just one call later.
|
||||
continue ;;
|
||||
esac
|
||||
|
||||
append_fetch_head "$head" "$remote" \
|
||||
@@ -381,80 +287,17 @@ fetch_main () {
|
||||
|
||||
done
|
||||
|
||||
case "$remote" in
|
||||
http://* | https://* | ftp://* | rsync://* )
|
||||
;; # we are already done.
|
||||
*)
|
||||
( : subshell because we muck with IFS
|
||||
IFS=" $LF"
|
||||
(
|
||||
if test -f "$remote" ; then
|
||||
test -n "$shallow_depth" &&
|
||||
die "shallow clone with bundle is not supported"
|
||||
git-bundle unbundle "$remote" $rref ||
|
||||
echo failed "$remote"
|
||||
else
|
||||
git-fetch-pack --thin $exec $keep $shallow_depth $no_progress \
|
||||
"$remote" $rref ||
|
||||
echo failed "$remote"
|
||||
fi
|
||||
) |
|
||||
(
|
||||
trap '
|
||||
if test -n "$keepfile" && test -f "$keepfile"
|
||||
then
|
||||
rm -f "$keepfile"
|
||||
fi
|
||||
' 0
|
||||
|
||||
keepfile=
|
||||
while read sha1 remote_name
|
||||
do
|
||||
case "$sha1" in
|
||||
failed)
|
||||
echo >&2 "Fetch failure: $remote"
|
||||
exit 1 ;;
|
||||
# special line coming from index-pack with the pack name
|
||||
pack)
|
||||
continue ;;
|
||||
keep)
|
||||
keepfile="$GIT_OBJECT_DIRECTORY/pack/pack-$remote_name.keep"
|
||||
continue ;;
|
||||
esac
|
||||
found=
|
||||
single_force=
|
||||
for ref in $refs
|
||||
do
|
||||
case "$ref" in
|
||||
+$remote_name:*)
|
||||
single_force=t
|
||||
not_for_merge=
|
||||
found="$ref"
|
||||
break ;;
|
||||
.+$remote_name:*)
|
||||
single_force=t
|
||||
not_for_merge=t
|
||||
found="$ref"
|
||||
break ;;
|
||||
.$remote_name:*)
|
||||
not_for_merge=t
|
||||
found="$ref"
|
||||
break ;;
|
||||
$remote_name:*)
|
||||
not_for_merge=
|
||||
found="$ref"
|
||||
break ;;
|
||||
esac
|
||||
done
|
||||
local_name=$(expr "z$found" : 'z[^:]*:\(.*\)')
|
||||
append_fetch_head "$sha1" "$remote" \
|
||||
"$remote_name" "$remote_nick" "$local_name" \
|
||||
"$not_for_merge" || exit
|
||||
done
|
||||
)
|
||||
) || exit ;;
|
||||
esac
|
||||
}
|
||||
|
||||
fetch_main () {
|
||||
case "$remote" in
|
||||
http://* | https://* | ftp://* | rsync://* )
|
||||
fetch_dumb "$@"
|
||||
;;
|
||||
*)
|
||||
fetch_native "$@"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
fetch_main "$reflist" || exit
|
||||
|
||||
1
git-gui/.gitignore
vendored
1
git-gui/.gitignore
vendored
@@ -1,4 +1,3 @@
|
||||
CREDITS-FILE
|
||||
GIT-VERSION-FILE
|
||||
git-citool
|
||||
git-gui
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
CF=CREDITS-FILE
|
||||
tip=
|
||||
|
||||
tree_search ()
|
||||
{
|
||||
head=$1
|
||||
tree=$2
|
||||
for p in $(git rev-list --parents --max-count=1 $head 2>/dev/null)
|
||||
do
|
||||
test $tree = $(git rev-parse $p^{tree} 2>/dev/null) &&
|
||||
vn=$(git describe --abbrev=4 $p 2>/dev/null) &&
|
||||
case "$vn" in
|
||||
gitgui-[0-9]*) echo $p; break;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
generate_credits ()
|
||||
{
|
||||
tip=$1 &&
|
||||
rm -f "$2" &&
|
||||
git shortlog -n -s $tip | sed 's/: .*$//' >"$2" || exit
|
||||
}
|
||||
|
||||
# Always use the tarball credits file if found, just
|
||||
# in case we are somehow contained in a larger git
|
||||
# repository that doesn't actually track our state.
|
||||
# (At least one package manager is doing this.)
|
||||
#
|
||||
# We may be a subproject, so try looking for the merge
|
||||
# commit that supplied this directory content if we are
|
||||
# not at the toplevel. We probably will always be the
|
||||
# second parent in the commit, but we shouldn't rely on
|
||||
# that fact.
|
||||
#
|
||||
|
||||
credits_tmp=/tmp/gitgui-credits-$$
|
||||
trap 'rm -f "$credits_tmp"' 0
|
||||
|
||||
orig="$credits_tmp"
|
||||
|
||||
if test -f credits
|
||||
then
|
||||
orig=credits
|
||||
elif prefix="$(git rev-parse --show-prefix 2>/dev/null)" &&
|
||||
test -n "$prefix" &&
|
||||
head=$(git rev-list --max-count=1 HEAD -- . 2>/dev/null) &&
|
||||
tree=$(git rev-parse --verify "HEAD:$prefix" 2>/dev/null) &&
|
||||
tip=$(tree_search $head $tree) &&
|
||||
test -n "$tip"
|
||||
then
|
||||
generate_credits $tip "$orig" || exit
|
||||
elif tip="$(git rev-parse --verify HEAD 2>/dev/null)" &&
|
||||
test -n "$tip"
|
||||
then
|
||||
generate_credits $tip "$orig" || exit
|
||||
else
|
||||
echo "error: Cannot locate authorship information." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -f "$orig" && cmp -s "$orig" "$CF"
|
||||
then
|
||||
: noop
|
||||
else
|
||||
rm -f "$CF" &&
|
||||
cat "$orig" >"$CF"
|
||||
fi
|
||||
|
||||
@@ -7,8 +7,9 @@ GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
||||
@$(SHELL_PATH) ./GIT-VERSION-GEN
|
||||
-include GIT-VERSION-FILE
|
||||
|
||||
SCRIPT_SH = git-gui.sh
|
||||
GITGUI_BUILT_INS = git-citool
|
||||
ALL_PROGRAMS = git-gui $(GITGUI_BUILT_INS)
|
||||
ALL_PROGRAMS = $(GITGUI_BUILT_INS) $(patsubst %.sh,%,$(SCRIPT_SH))
|
||||
|
||||
ifndef SHELL_PATH
|
||||
SHELL_PATH = /bin/sh
|
||||
@@ -27,28 +28,29 @@ ifndef V
|
||||
QUIET_BUILT_IN = @echo ' ' BUILTIN $@;
|
||||
endif
|
||||
|
||||
ifeq ($(findstring $(MAKEFLAGS),s),s)
|
||||
QUIET_GEN =
|
||||
QUIET_BUILT_IN =
|
||||
endif
|
||||
|
||||
DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
|
||||
gitexecdir_SQ = $(subst ','\'',$(gitexecdir))
|
||||
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
|
||||
|
||||
git-gui: git-gui.sh GIT-VERSION-FILE CREDITS-FILE
|
||||
$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
|
||||
$(QUIET_GEN)rm -f $@ $@+ && \
|
||||
sed -n \
|
||||
-e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
|
||||
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
|
||||
-e 's/@@GITGUI_VERSION@@/$(GITGUI_VERSION)/g' \
|
||||
-e '1,/^set gitgui_credits /p' \
|
||||
$@.sh >$@+ && \
|
||||
cat CREDITS-FILE >>$@+ && \
|
||||
sed -e '1,/^set gitgui_credits /d' $@.sh >>$@+ && \
|
||||
chmod +x $@+ && \
|
||||
mv $@+ $@
|
||||
|
||||
CREDITS-FILE: CREDITS-GEN .FORCE-CREDITS-FILE
|
||||
$(QUIET_GEN)$(SHELL_PATH) ./CREDITS-GEN
|
||||
|
||||
$(GITGUI_BUILT_INS): git-gui
|
||||
$(QUIET_BUILT_IN)rm -f $@ && ln git-gui $@
|
||||
|
||||
# These can record GITGUI_VERSION
|
||||
$(patsubst %.sh,%,$(SCRIPT_SH)): GIT-VERSION-FILE
|
||||
|
||||
all:: $(ALL_PROGRAMS)
|
||||
|
||||
install: all
|
||||
@@ -56,14 +58,12 @@ install: all
|
||||
$(INSTALL) git-gui '$(DESTDIR_SQ)$(gitexecdir_SQ)'
|
||||
$(foreach p,$(GITGUI_BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;)
|
||||
|
||||
dist-version: CREDITS-FILE
|
||||
dist-version:
|
||||
@mkdir -p $(TARDIR)
|
||||
@echo $(GITGUI_VERSION) > $(TARDIR)/version
|
||||
@cat CREDITS-FILE > $(TARDIR)/credits
|
||||
|
||||
clean::
|
||||
rm -f $(ALL_PROGRAMS) GIT-VERSION-FILE CREDITS-FILE
|
||||
rm -f $(ALL_PROGRAMS) GIT-VERSION-FILE
|
||||
|
||||
.PHONY: all install dist-version clean
|
||||
.PHONY: .FORCE-GIT-VERSION-FILE
|
||||
.PHONY: .FORCE-CREDITS-FILE
|
||||
|
||||
@@ -19,9 +19,6 @@ GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA}
|
||||
set gitgui_credits {
|
||||
Paul Mackerras
|
||||
}
|
||||
|
||||
######################################################################
|
||||
##
|
||||
@@ -302,6 +299,11 @@ proc ask_popup {msg} {
|
||||
##
|
||||
## version check
|
||||
|
||||
if {{--version} eq $argv || {version} eq $argv} {
|
||||
puts "git-gui version $appvers"
|
||||
exit
|
||||
}
|
||||
|
||||
set req_maj 1
|
||||
set req_min 5
|
||||
|
||||
@@ -1171,7 +1173,7 @@ File [short_path $path] cannot be committed by this program.
|
||||
}
|
||||
}
|
||||
}
|
||||
if {!$files_ready} {
|
||||
if {!$files_ready && ![string match *merge $curType]} {
|
||||
info_popup {No changes to commit.
|
||||
|
||||
You must add at least 1 file before you can commit.
|
||||
@@ -4492,61 +4494,6 @@ proc do_commit {} {
|
||||
commit_tree
|
||||
}
|
||||
|
||||
proc do_credits {} {
|
||||
global gitgui_credits
|
||||
|
||||
set w .credits_dialog
|
||||
|
||||
toplevel $w
|
||||
wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
|
||||
|
||||
label $w.header -text {git-gui Contributors} -font font_uibold
|
||||
pack $w.header -side top -fill x
|
||||
|
||||
frame $w.buttons
|
||||
button $w.buttons.close -text {Close} \
|
||||
-font font_ui \
|
||||
-command [list destroy $w]
|
||||
pack $w.buttons.close -side right
|
||||
pack $w.buttons -side bottom -fill x -pady 10 -padx 10
|
||||
|
||||
frame $w.credits
|
||||
text $w.credits.t \
|
||||
-background [$w.header cget -background] \
|
||||
-yscrollcommand [list $w.credits.sby set] \
|
||||
-width 20 \
|
||||
-height 10 \
|
||||
-wrap none \
|
||||
-borderwidth 1 \
|
||||
-relief solid \
|
||||
-padx 5 -pady 5 \
|
||||
-font font_ui
|
||||
scrollbar $w.credits.sby -command [list $w.credits.t yview]
|
||||
pack $w.credits.sby -side right -fill y
|
||||
pack $w.credits.t -fill both -expand 1
|
||||
pack $w.credits -side top -fill both -expand 1 -padx 5 -pady 5
|
||||
|
||||
label $w.desc \
|
||||
-text "All portions are copyrighted by their respective authors
|
||||
and are distributed under the GNU General Public License." \
|
||||
-padx 5 -pady 5 \
|
||||
-justify left \
|
||||
-anchor w \
|
||||
-borderwidth 1 \
|
||||
-relief solid \
|
||||
-font font_ui
|
||||
pack $w.desc -side top -fill x -padx 5 -pady 5
|
||||
|
||||
$w.credits.t insert end "[string trim $gitgui_credits]\n"
|
||||
$w.credits.t conf -state disabled
|
||||
$w.credits.t see 1.0
|
||||
|
||||
bind $w <Visibility> "grab $w; focus $w"
|
||||
bind $w <Key-Escape> [list destroy $w]
|
||||
wm title $w [$w.header cget -text]
|
||||
tkwait window $w
|
||||
}
|
||||
|
||||
proc do_about {} {
|
||||
global appvers copyright
|
||||
global tcl_patchLevel tk_patchLevel
|
||||
@@ -4563,10 +4510,6 @@ proc do_about {} {
|
||||
button $w.buttons.close -text {Close} \
|
||||
-font font_ui \
|
||||
-command [list destroy $w]
|
||||
button $w.buttons.credits -text {Contributors} \
|
||||
-font font_ui \
|
||||
-command do_credits
|
||||
pack $w.buttons.credits -side left
|
||||
pack $w.buttons.close -side right
|
||||
pack $w.buttons -side bottom -fill x -pady 10 -padx 10
|
||||
|
||||
@@ -5116,8 +5059,6 @@ enable_option branch
|
||||
enable_option transport
|
||||
|
||||
switch -- $subcommand {
|
||||
--version -
|
||||
version -
|
||||
browser -
|
||||
blame {
|
||||
disable_option multicommit
|
||||
@@ -5488,11 +5429,6 @@ bind all <$M1B-Key-W> {destroy [winfo toplevel %W]}
|
||||
# -- Not a normal commit type invocation? Do that instead!
|
||||
#
|
||||
switch -- $subcommand {
|
||||
--version -
|
||||
version {
|
||||
puts "git-gui version $appvers"
|
||||
exit
|
||||
}
|
||||
browser {
|
||||
if {[llength $argv] != 1} {
|
||||
puts stderr "usage: $argv0 browser commit"
|
||||
|
||||
7
git-merge.sh
Executable file → Normal file
7
git-merge.sh
Executable file → Normal file
@@ -339,7 +339,12 @@ f,*)
|
||||
git-update-index --refresh 2>/dev/null
|
||||
new_head=$(git-rev-parse --verify "$1^0") &&
|
||||
merge_local_changes $head $new_head &&
|
||||
finish "$new_head" "Fast forward" || exit
|
||||
msg="Fast forward"
|
||||
if test -n "$have_message"
|
||||
then
|
||||
msg="$msg (no commit created; -m option ignored)"
|
||||
fi
|
||||
finish "$new_head" "$msg" || exit
|
||||
dropsave
|
||||
exit 0
|
||||
;;
|
||||
|
||||
352
git-mergetool.sh
Executable file
352
git-mergetool.sh
Executable file
@@ -0,0 +1,352 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# This program resolves merge conflicts in git
|
||||
#
|
||||
# Copyright (c) 2006 Theodore Y. Ts'o
|
||||
#
|
||||
# This file is licensed under the GPL v2, or a later version
|
||||
# at the discretion of Junio C Hammano.
|
||||
#
|
||||
|
||||
USAGE='[--tool=tool] [file to merge] ...'
|
||||
SUBDIRECTORY_OK=Yes
|
||||
. git-sh-setup
|
||||
require_work_tree
|
||||
|
||||
# Returns true if the mode reflects a symlink
|
||||
function is_symlink () {
|
||||
test "$1" = 120000
|
||||
}
|
||||
|
||||
function local_present () {
|
||||
test -n "$local_mode"
|
||||
}
|
||||
|
||||
function remote_present () {
|
||||
test -n "$remote_mode"
|
||||
}
|
||||
|
||||
function base_present () {
|
||||
test -n "$base_mode"
|
||||
}
|
||||
|
||||
cleanup_temp_files () {
|
||||
if test "$1" = --save-backup ; then
|
||||
mv -- "$BACKUP" "$path.orig"
|
||||
rm -f -- "$LOCAL" "$REMOTE" "$BASE"
|
||||
else
|
||||
rm -f -- "$LOCAL" "$REMOTE" "$BASE" "$BACKUP"
|
||||
fi
|
||||
}
|
||||
|
||||
function describe_file () {
|
||||
mode="$1"
|
||||
branch="$2"
|
||||
file="$3"
|
||||
|
||||
echo -n " "
|
||||
if test -z "$mode"; then
|
||||
echo -n "'$path' was deleted"
|
||||
elif is_symlink "$mode" ; then
|
||||
echo -n "'$path' is a symlink containing '"
|
||||
cat "$file"
|
||||
echo -n "'"
|
||||
else
|
||||
if base_present; then
|
||||
echo -n "'$path' was created"
|
||||
else
|
||||
echo -n "'$path' was modified"
|
||||
fi
|
||||
fi
|
||||
echo " in the $branch branch"
|
||||
}
|
||||
|
||||
|
||||
resolve_symlink_merge () {
|
||||
while /bin/true; do
|
||||
echo -n "Use (r)emote or (l)ocal, or (a)bort? "
|
||||
read ans
|
||||
case "$ans" in
|
||||
[lL]*)
|
||||
git-checkout-index -f --stage=2 -- "$path"
|
||||
git-add -- "$path"
|
||||
cleanup_temp_files --save-backup
|
||||
return
|
||||
;;
|
||||
[rR]*)
|
||||
git-checkout-index -f --stage=3 -- "$path"
|
||||
git-add -- "$path"
|
||||
cleanup_temp_files --save-backup
|
||||
return
|
||||
;;
|
||||
[qQ]*)
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
resolve_deleted_merge () {
|
||||
while /bin/true; do
|
||||
echo -n "Use (m)odified or (d)eleted file, or (a)bort? "
|
||||
read ans
|
||||
case "$ans" in
|
||||
[mM]*)
|
||||
git-add -- "$path"
|
||||
cleanup_temp_files --save-backup
|
||||
return
|
||||
;;
|
||||
[dD]*)
|
||||
git-rm -- "$path"
|
||||
cleanup_temp_files
|
||||
return
|
||||
;;
|
||||
[qQ]*)
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
merge_file () {
|
||||
path="$1"
|
||||
|
||||
if test ! -f "$path" ; then
|
||||
echo "$path: file not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
f=`git-ls-files -u -- "$path"`
|
||||
if test -z "$f" ; then
|
||||
echo "$path: file does not need merging"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BACKUP="$path.BACKUP.$$"
|
||||
LOCAL="$path.LOCAL.$$"
|
||||
REMOTE="$path.REMOTE.$$"
|
||||
BASE="$path.BASE.$$"
|
||||
|
||||
mv -- "$path" "$BACKUP"
|
||||
cp -- "$BACKUP" "$path"
|
||||
|
||||
base_mode=`git ls-files -u -- "$path" | awk '{if ($3==1) print $1;}'`
|
||||
local_mode=`git ls-files -u -- "$path" | awk '{if ($3==2) print $1;}'`
|
||||
remote_mode=`git ls-files -u -- "$path" | awk '{if ($3==3) print $1;}'`
|
||||
|
||||
base_present && git cat-file blob ":1:$path" > "$BASE" 2>/dev/null
|
||||
local_present && git cat-file blob ":2:$path" > "$LOCAL" 2>/dev/null
|
||||
remote_present && git cat-file blob ":3:$path" > "$REMOTE" 2>/dev/null
|
||||
|
||||
if test -z "$local_mode" -o -z "$remote_mode"; then
|
||||
echo "Deleted merge conflict for $path:"
|
||||
describe_file "$local_mode" "local" "$LOCAL"
|
||||
describe_file "$remote_mode" "remote" "$REMOTE"
|
||||
resolve_deleted_merge
|
||||
return
|
||||
fi
|
||||
|
||||
if is_symlink "$local_mode" || is_symlink "$remote_mode"; then
|
||||
echo "Symlink merge conflict for $path:"
|
||||
describe_file "$local_mode" "local" "$LOCAL"
|
||||
describe_file "$remote_mode" "remote" "$REMOTE"
|
||||
resolve_symlink_merge
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Normal merge conflict for $path:"
|
||||
describe_file "$local_mode" "local" "$LOCAL"
|
||||
describe_file "$remote_mode" "remote" "$REMOTE"
|
||||
echo -n "Hit return to start merge resolution tool ($merge_tool): "
|
||||
read ans
|
||||
|
||||
case "$merge_tool" in
|
||||
kdiff3)
|
||||
if base_present ; then
|
||||
(kdiff3 --auto --L1 "$path (Base)" -L2 "$path (Local)" --L3 "$path (Remote)" \
|
||||
-o "$path" -- "$BASE" "$LOCAL" "$REMOTE" > /dev/null 2>&1)
|
||||
else
|
||||
(kdiff3 --auto -L1 "$path (Local)" --L2 "$path (Remote)" \
|
||||
-o "$path" -- "$LOCAL" "$REMOTE" > /dev/null 2>&1)
|
||||
fi
|
||||
status=$?
|
||||
if test "$status" -eq 0; then
|
||||
rm "$BACKUP"
|
||||
fi
|
||||
;;
|
||||
tkdiff)
|
||||
if base_present ; then
|
||||
tkdiff -a "$BASE" -o "$path" -- "$LOCAL" "$REMOTE"
|
||||
else
|
||||
tkdiff -o "$path" -- "$LOCAL" "$REMOTE"
|
||||
fi
|
||||
status=$?
|
||||
if test "$status" -eq 0; then
|
||||
mv -- "$BACKUP" "$path.orig"
|
||||
fi
|
||||
;;
|
||||
meld)
|
||||
touch "$BACKUP"
|
||||
meld -- "$LOCAL" "$path" "$REMOTE"
|
||||
if test "$path" -nt "$BACKUP" ; then
|
||||
status=0;
|
||||
else
|
||||
while true; do
|
||||
echo "$path seems unchanged."
|
||||
echo -n "Was the merge successful? [y/n] "
|
||||
read answer < /dev/tty
|
||||
case "$answer" in
|
||||
y*|Y*) status=0; break ;;
|
||||
n*|N*) status=1; break ;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
if test "$status" -eq 0; then
|
||||
mv -- "$BACKUP" "$path.orig"
|
||||
fi
|
||||
;;
|
||||
xxdiff)
|
||||
touch "$BACKUP"
|
||||
if base_present ; then
|
||||
xxdiff -X --show-merged-pane \
|
||||
-R 'Accel.SaveAsMerged: "Ctrl-S"' \
|
||||
-R 'Accel.Search: "Ctrl+F"' \
|
||||
-R 'Accel.SearchForward: "Ctrl-G"' \
|
||||
--merged-file "$path" -- "$LOCAL" "$BASE" "$REMOTE"
|
||||
else
|
||||
xxdiff -X --show-merged-pane \
|
||||
-R 'Accel.SaveAsMerged: "Ctrl-S"' \
|
||||
-R 'Accel.Search: "Ctrl+F"' \
|
||||
-R 'Accel.SearchForward: "Ctrl-G"' \
|
||||
--merged-file "$path" -- "$LOCAL" "$REMOTE"
|
||||
fi
|
||||
if test "$path" -nt "$BACKUP" ; then
|
||||
status=0;
|
||||
else
|
||||
while true; do
|
||||
echo "$path seems unchanged."
|
||||
echo -n "Was the merge successful? [y/n] "
|
||||
read answer < /dev/tty
|
||||
case "$answer" in
|
||||
y*|Y*) status=0; break ;;
|
||||
n*|N*) status=1; break ;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
if test "$status" -eq 0; then
|
||||
mv -- "$BACKUP" "$path.orig"
|
||||
fi
|
||||
;;
|
||||
emerge)
|
||||
if base_present ; then
|
||||
emacs -f emerge-files-with-ancestor-command "$LOCAL" "$REMOTE" "$BASE" "$path"
|
||||
else
|
||||
emacs -f emerge-files-command "$LOCAL" "$REMOTE" "$path"
|
||||
fi
|
||||
status=$?
|
||||
if test "$status" -eq 0; then
|
||||
mv -- "$BACKUP" "$path.orig"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
if test "$status" -ne 0; then
|
||||
echo "merge of $path failed" 1>&2
|
||||
mv -- "$BACKUP" "$path"
|
||||
exit 1
|
||||
fi
|
||||
git add -- "$path"
|
||||
cleanup_temp_files
|
||||
}
|
||||
|
||||
while case $# in 0) break ;; esac
|
||||
do
|
||||
case "$1" in
|
||||
-t|--tool*)
|
||||
case "$#,$1" in
|
||||
*,*=*)
|
||||
merge_tool=`expr "z$1" : 'z-[^=]*=\(.*\)'`
|
||||
;;
|
||||
1,*)
|
||||
usage ;;
|
||||
*)
|
||||
merge_tool="$2"
|
||||
shift ;;
|
||||
esac
|
||||
;;
|
||||
--)
|
||||
break
|
||||
;;
|
||||
-*)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if test -z "$merge_tool"; then
|
||||
merge_tool=`git-config merge.tool`
|
||||
if test $merge_tool = kdiff3 -o $merge_tool = tkdiff -o \
|
||||
$merge_tool = xxdiff -o $merge_tool = meld ; then
|
||||
unset merge_tool
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$merge_tool" ; then
|
||||
if type kdiff3 >/dev/null 2>&1 && test -n "$DISPLAY"; then
|
||||
merge_tool="kdiff3";
|
||||
elif type tkdiff >/dev/null 2>&1 && test -n "$DISPLAY"; then
|
||||
merge_tool=tkdiff
|
||||
elif type xxdiff >/dev/null 2>&1 && test -n "$DISPLAY"; then
|
||||
merge_tool=xxdiff
|
||||
elif type meld >/dev/null 2>&1 && test -n "$DISPLAY"; then
|
||||
merge_tool=meld
|
||||
elif type emacs >/dev/null 2>&1; then
|
||||
merge_tool=emerge
|
||||
else
|
||||
echo "No available merge resolution programs available."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
case "$merge_tool" in
|
||||
kdiff3|tkdiff|meld|xxdiff)
|
||||
if ! type "$merge_tool" > /dev/null 2>&1; then
|
||||
echo "The merge tool $merge_tool is not available"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
emerge)
|
||||
if ! type "emacs" > /dev/null 2>&1; then
|
||||
echo "Emacs is not available"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Unknown merge tool: $merge_tool"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if test $# -eq 0 ; then
|
||||
files=`git ls-files -u | sed -e 's/^[^ ]* //' | sort -u`
|
||||
if test -z "$files" ; then
|
||||
echo "No files need merging"
|
||||
exit 0
|
||||
fi
|
||||
echo Merging the files: $files
|
||||
git ls-files -u | sed -e 's/^[^ ]* //' | sort -u | while read i
|
||||
do
|
||||
echo ""
|
||||
merge_file "$i" < /dev/tty > /dev/tty
|
||||
done
|
||||
else
|
||||
while test $# -gt 0; do
|
||||
echo ""
|
||||
merge_file "$1"
|
||||
shift
|
||||
done
|
||||
fi
|
||||
exit 0
|
||||
@@ -81,51 +81,8 @@ get_remote_default_refs_for_push () {
|
||||
# is to help prevent randomly "globbed" ref from being chosen as
|
||||
# a merge candidate
|
||||
expand_refs_wildcard () {
|
||||
remote="$1"
|
||||
shift
|
||||
first_one=yes
|
||||
if test "$#" = 0
|
||||
then
|
||||
echo empty
|
||||
echo >&2 "Nothing specified for fetching with remote.$remote.fetch"
|
||||
fi
|
||||
for ref
|
||||
do
|
||||
lref=${ref#'+'}
|
||||
# a non glob pattern is given back as-is.
|
||||
expr "z$lref" : 'zrefs/.*/\*:refs/.*/\*$' >/dev/null || {
|
||||
if test -n "$first_one"
|
||||
then
|
||||
echo "explicit"
|
||||
first_one=
|
||||
fi
|
||||
echo "$ref"
|
||||
continue
|
||||
}
|
||||
|
||||
# glob
|
||||
if test -n "$first_one"
|
||||
then
|
||||
echo "glob"
|
||||
first_one=
|
||||
fi
|
||||
from=`expr "z$lref" : 'z\(refs/.*/\)\*:refs/.*/\*$'`
|
||||
to=`expr "z$lref" : 'zrefs/.*/\*:\(refs/.*/\)\*$'`
|
||||
local_force=
|
||||
test "z$lref" = "z$ref" || local_force='+'
|
||||
echo "$ls_remote_result" |
|
||||
sed -e '/\^{}$/d' |
|
||||
(
|
||||
IFS=' '
|
||||
while read sha1 name
|
||||
do
|
||||
# ignore the ones that do not start with $from
|
||||
mapped=${name#"$from"}
|
||||
test "z$name" = "z$mapped" && continue
|
||||
echo "${local_force}${name}:${to}${mapped}"
|
||||
done
|
||||
)
|
||||
done
|
||||
echo "$ls_remote_result" |
|
||||
git fetch--tool expand-refs-wildcard "-" "$@"
|
||||
}
|
||||
|
||||
# Subroutine to canonicalize remote:local notation.
|
||||
|
||||
@@ -73,6 +73,10 @@ mkdir $tmp_dir || exit 2
|
||||
for patch_name in $(cat "$QUILT_PATCHES/series" | grep -v '^#'); do
|
||||
echo $patch_name
|
||||
(cat $QUILT_PATCHES/$patch_name | git-mailinfo "$tmp_msg" "$tmp_patch" > "$tmp_info") || exit 3
|
||||
test -s $dotest/patch || {
|
||||
echo "Patch is empty. Was is split wrong?"
|
||||
stop_here $this
|
||||
}
|
||||
|
||||
# Parse the author information
|
||||
export GIT_AUTHOR_NAME=$(sed -ne 's/Author: //p' "$tmp_info")
|
||||
|
||||
@@ -149,6 +149,16 @@ if ($@) {
|
||||
$term = new FakeTerm "$@: going non-interactive";
|
||||
}
|
||||
|
||||
my $def_chain = $repo->config_boolean('sendemail.chainreplyto');
|
||||
if ($def_chain and $def_chain eq 'false') {
|
||||
$chain_reply_to = 0;
|
||||
}
|
||||
|
||||
@bcclist = $repo->config('sendemail.bcc');
|
||||
if (!@bcclist or !$bcclist[0]) {
|
||||
@bcclist = ();
|
||||
}
|
||||
|
||||
# Begin by accumulating all the variables (defined above), that we will end up
|
||||
# needing, first, from the command line:
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ my ($_stdin, $_help, $_edit,
|
||||
$_message, $_file,
|
||||
$_template, $_shared,
|
||||
$_version, $_fetch_all,
|
||||
$_merge, $_strategy, $_dry_run,
|
||||
$_merge, $_strategy, $_dry_run, $_local,
|
||||
$_prefix, $_no_checkout, $_verbose);
|
||||
$Git::SVN::_follow_parent = 1;
|
||||
my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
|
||||
@@ -145,6 +145,7 @@ my %cmd = (
|
||||
{ 'merge|m|M' => \$_merge,
|
||||
'verbose|v' => \$_verbose,
|
||||
'strategy|s=s' => \$_strategy,
|
||||
'local|l' => \$_local,
|
||||
'fetch-all|all' => \$_fetch_all,
|
||||
%fc_opts } ],
|
||||
'commit-diff' => [ \&cmd_commit_diff,
|
||||
@@ -439,7 +440,9 @@ sub cmd_rebase {
|
||||
command_noisy('status');
|
||||
exit 1;
|
||||
}
|
||||
$_fetch_all ? $gs->fetch_all : $gs->fetch;
|
||||
unless ($_local) {
|
||||
$_fetch_all ? $gs->fetch_all : $gs->fetch;
|
||||
}
|
||||
command_noisy(rebase_cmd(), $gs->refname);
|
||||
}
|
||||
|
||||
|
||||
1
git.c
1
git.c
@@ -247,6 +247,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
|
||||
{ "diff-files", cmd_diff_files },
|
||||
{ "diff-index", cmd_diff_index, RUN_SETUP },
|
||||
{ "diff-tree", cmd_diff_tree, RUN_SETUP },
|
||||
{ "fetch--tool", cmd_fetch__tool, RUN_SETUP },
|
||||
{ "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
|
||||
{ "for-each-ref", cmd_for_each_ref, RUN_SETUP },
|
||||
{ "format-patch", cmd_format_patch, RUN_SETUP },
|
||||
|
||||
@@ -37,7 +37,7 @@ $(makfile): ../GIT-CFLAGS Makefile
|
||||
echo ' echo $(instdir_SQ)' >> $@
|
||||
else
|
||||
$(makfile): Makefile.PL ../GIT-CFLAGS
|
||||
$(QUIET_GEN)'$(PERL_PATH_SQ)' $< PREFIX='$(prefix_SQ)'
|
||||
'$(PERL_PATH_SQ)' $< PREFIX='$(prefix_SQ)'
|
||||
endif
|
||||
|
||||
# this is just added comfort for calling make directly in perl dir
|
||||
|
||||
109
receive-pack.c
109
receive-pack.c
@@ -67,47 +67,11 @@ struct command {
|
||||
|
||||
static struct command *commands;
|
||||
|
||||
static const char update_hook[] = "hooks/update";
|
||||
static const char pre_receive_hook[] = "hooks/pre-receive";
|
||||
static const char post_receive_hook[] = "hooks/post-receive";
|
||||
|
||||
static int run_hook(const char *hook_name,
|
||||
struct command *first_cmd,
|
||||
int single)
|
||||
static int hook_status(int code, const char *hook_name)
|
||||
{
|
||||
struct command *cmd;
|
||||
int argc, code;
|
||||
const char **argv;
|
||||
|
||||
for (argc = 0, cmd = first_cmd; cmd; cmd = cmd->next) {
|
||||
if (!cmd->error_string)
|
||||
argc += 3;
|
||||
if (single)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!argc || access(hook_name, X_OK) < 0)
|
||||
return 0;
|
||||
|
||||
argv = xmalloc(sizeof(*argv) * (2 + argc));
|
||||
argv[0] = hook_name;
|
||||
for (argc = 1, cmd = first_cmd; cmd; cmd = cmd->next) {
|
||||
if (!cmd->error_string) {
|
||||
argv[argc++] = xstrdup(cmd->ref_name);
|
||||
argv[argc++] = xstrdup(sha1_to_hex(cmd->old_sha1));
|
||||
argv[argc++] = xstrdup(sha1_to_hex(cmd->new_sha1));
|
||||
}
|
||||
if (single)
|
||||
break;
|
||||
}
|
||||
argv[argc] = NULL;
|
||||
|
||||
code = run_command_v_opt(argv,
|
||||
RUN_COMMAND_NO_STDIN | RUN_COMMAND_STDOUT_TO_STDERR);
|
||||
while (--argc > 0)
|
||||
free((char*)argv[argc]);
|
||||
free(argv);
|
||||
|
||||
switch (code) {
|
||||
case 0:
|
||||
return 0;
|
||||
@@ -115,6 +79,8 @@ static int run_hook(const char *hook_name,
|
||||
return error("hook fork failed");
|
||||
case -ERR_RUN_COMMAND_EXEC:
|
||||
return error("hook execute failed");
|
||||
case -ERR_RUN_COMMAND_PIPE:
|
||||
return error("hook pipe failed");
|
||||
case -ERR_RUN_COMMAND_WAITPID:
|
||||
return error("waitpid failed");
|
||||
case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
|
||||
@@ -129,6 +95,69 @@ static int run_hook(const char *hook_name,
|
||||
}
|
||||
}
|
||||
|
||||
static int run_hook(const char *hook_name)
|
||||
{
|
||||
static char buf[sizeof(commands->old_sha1) * 2 + PATH_MAX + 4];
|
||||
struct command *cmd;
|
||||
struct child_process proc;
|
||||
const char *argv[2];
|
||||
int have_input = 0, code;
|
||||
|
||||
for (cmd = commands; !have_input && cmd; cmd = cmd->next) {
|
||||
if (!cmd->error_string)
|
||||
have_input = 1;
|
||||
}
|
||||
|
||||
if (!have_input || access(hook_name, X_OK) < 0)
|
||||
return 0;
|
||||
|
||||
argv[0] = hook_name;
|
||||
argv[1] = NULL;
|
||||
|
||||
memset(&proc, 0, sizeof(proc));
|
||||
proc.argv = argv;
|
||||
proc.in = -1;
|
||||
proc.stdout_to_stderr = 1;
|
||||
|
||||
code = start_command(&proc);
|
||||
if (code)
|
||||
return hook_status(code, hook_name);
|
||||
for (cmd = commands; cmd; cmd = cmd->next) {
|
||||
if (!cmd->error_string) {
|
||||
size_t n = snprintf(buf, sizeof(buf), "%s %s %s\n",
|
||||
sha1_to_hex(cmd->old_sha1),
|
||||
sha1_to_hex(cmd->new_sha1),
|
||||
cmd->ref_name);
|
||||
if (write_in_full(proc.in, buf, n) != n)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return hook_status(finish_command(&proc), hook_name);
|
||||
}
|
||||
|
||||
static int run_update_hook(struct command *cmd)
|
||||
{
|
||||
static const char update_hook[] = "hooks/update";
|
||||
struct child_process proc;
|
||||
const char *argv[5];
|
||||
|
||||
if (access(update_hook, X_OK) < 0)
|
||||
return 0;
|
||||
|
||||
argv[0] = update_hook;
|
||||
argv[1] = cmd->ref_name;
|
||||
argv[2] = sha1_to_hex(cmd->old_sha1);
|
||||
argv[3] = sha1_to_hex(cmd->new_sha1);
|
||||
argv[4] = NULL;
|
||||
|
||||
memset(&proc, 0, sizeof(proc));
|
||||
proc.argv = argv;
|
||||
proc.no_stdin = 1;
|
||||
proc.stdout_to_stderr = 1;
|
||||
|
||||
return hook_status(run_command(&proc), update_hook);
|
||||
}
|
||||
|
||||
static const char *update(struct command *cmd)
|
||||
{
|
||||
const char *name = cmd->ref_name;
|
||||
@@ -165,7 +194,7 @@ static const char *update(struct command *cmd)
|
||||
return "non-fast forward";
|
||||
}
|
||||
}
|
||||
if (run_hook(update_hook, cmd, 1)) {
|
||||
if (run_update_hook(cmd)) {
|
||||
error("hook declined to update %s", name);
|
||||
return "hook declined";
|
||||
}
|
||||
@@ -238,7 +267,7 @@ static void execute_commands(const char *unpacker_error)
|
||||
return;
|
||||
}
|
||||
|
||||
if (run_hook(pre_receive_hook, commands, 0)) {
|
||||
if (run_hook(pre_receive_hook)) {
|
||||
while (cmd) {
|
||||
cmd->error_string = "pre-receive hook declined";
|
||||
cmd = cmd->next;
|
||||
@@ -485,7 +514,7 @@ int main(int argc, char **argv)
|
||||
unlink(pack_lockfile);
|
||||
if (report_status)
|
||||
report(unpack_status);
|
||||
run_hook(post_receive_hook, commands, 0);
|
||||
run_hook(post_receive_hook);
|
||||
run_update_post_hook(commands);
|
||||
}
|
||||
return 0;
|
||||
|
||||
219
revision.c
219
revision.c
@@ -437,36 +437,6 @@ static void limit_list(struct rev_info *revs)
|
||||
continue;
|
||||
p = &commit_list_insert(commit, p)->next;
|
||||
}
|
||||
if (revs->boundary) {
|
||||
/* mark the ones that are on the result list first */
|
||||
for (list = newlist; list; list = list->next) {
|
||||
struct commit *commit = list->item;
|
||||
commit->object.flags |= TMP_MARK;
|
||||
}
|
||||
for (list = newlist; list; list = list->next) {
|
||||
struct commit *commit = list->item;
|
||||
struct object *obj = &commit->object;
|
||||
struct commit_list *parent;
|
||||
if (obj->flags & UNINTERESTING)
|
||||
continue;
|
||||
for (parent = commit->parents;
|
||||
parent;
|
||||
parent = parent->next) {
|
||||
struct commit *pcommit = parent->item;
|
||||
if (!(pcommit->object.flags & UNINTERESTING))
|
||||
continue;
|
||||
pcommit->object.flags |= BOUNDARY;
|
||||
if (pcommit->object.flags & TMP_MARK)
|
||||
continue;
|
||||
pcommit->object.flags |= TMP_MARK;
|
||||
p = &commit_list_insert(pcommit, p)->next;
|
||||
}
|
||||
}
|
||||
for (list = newlist; list; list = list->next) {
|
||||
struct commit *commit = list->item;
|
||||
commit->object.flags &= ~TMP_MARK;
|
||||
}
|
||||
}
|
||||
revs->commits = newlist;
|
||||
}
|
||||
|
||||
@@ -1193,17 +1163,6 @@ static void rewrite_parents(struct rev_info *revs, struct commit *commit)
|
||||
}
|
||||
}
|
||||
|
||||
static void mark_boundary_to_show(struct commit *commit)
|
||||
{
|
||||
struct commit_list *p = commit->parents;
|
||||
while (p) {
|
||||
commit = p->item;
|
||||
p = p->next;
|
||||
if (commit->object.flags & BOUNDARY)
|
||||
commit->object.flags |= BOUNDARY_SHOW;
|
||||
}
|
||||
}
|
||||
|
||||
static int commit_match(struct commit *commit, struct rev_info *opt)
|
||||
{
|
||||
if (!opt->grep_filter)
|
||||
@@ -1235,15 +1194,9 @@ static struct commit *get_revision_1(struct rev_info *revs)
|
||||
*/
|
||||
if (!revs->limited) {
|
||||
if (revs->max_age != -1 &&
|
||||
(commit->date < revs->max_age)) {
|
||||
if (revs->boundary)
|
||||
commit->object.flags |=
|
||||
BOUNDARY_SHOW | BOUNDARY;
|
||||
else
|
||||
continue;
|
||||
} else
|
||||
add_parents_to_list(revs, commit,
|
||||
&revs->commits);
|
||||
(commit->date < revs->max_age))
|
||||
continue;
|
||||
add_parents_to_list(revs, commit, &revs->commits);
|
||||
}
|
||||
if (commit->object.flags & SHOWN)
|
||||
continue;
|
||||
@@ -1252,18 +1205,6 @@ static struct commit *get_revision_1(struct rev_info *revs)
|
||||
revs->ignore_packed))
|
||||
continue;
|
||||
|
||||
/* We want to show boundary commits only when their
|
||||
* children are shown. When path-limiter is in effect,
|
||||
* rewrite_parents() drops some commits from getting shown,
|
||||
* and there is no point showing boundary parents that
|
||||
* are not shown. After rewrite_parents() rewrites the
|
||||
* parents of a commit that is shown, we mark the boundary
|
||||
* parents with BOUNDARY_SHOW.
|
||||
*/
|
||||
if (commit->object.flags & BOUNDARY_SHOW) {
|
||||
commit->object.flags |= SHOWN;
|
||||
return commit;
|
||||
}
|
||||
if (commit->object.flags & UNINTERESTING)
|
||||
continue;
|
||||
if (revs->min_age != -1 && (commit->date > revs->min_age))
|
||||
@@ -1286,80 +1227,136 @@ static struct commit *get_revision_1(struct rev_info *revs)
|
||||
if (revs->parents)
|
||||
rewrite_parents(revs, commit);
|
||||
}
|
||||
if (revs->boundary)
|
||||
mark_boundary_to_show(commit);
|
||||
commit->object.flags |= SHOWN;
|
||||
return commit;
|
||||
} while (revs->commits);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void gc_boundary(struct object_array *array)
|
||||
{
|
||||
unsigned nr = array->nr;
|
||||
unsigned alloc = array->alloc;
|
||||
struct object_array_entry *objects = array->objects;
|
||||
|
||||
if (alloc <= nr) {
|
||||
unsigned i, j;
|
||||
for (i = j = 0; i < nr; i++) {
|
||||
if (objects[i].item->flags & SHOWN)
|
||||
continue;
|
||||
if (i != j)
|
||||
objects[j] = objects[i];
|
||||
j++;
|
||||
}
|
||||
for (i = j; i < nr; i++)
|
||||
objects[i].item = NULL;
|
||||
array->nr = j;
|
||||
}
|
||||
}
|
||||
|
||||
struct commit *get_revision(struct rev_info *revs)
|
||||
{
|
||||
struct commit *c = NULL;
|
||||
struct commit_list *l;
|
||||
|
||||
if (revs->reverse) {
|
||||
struct commit_list *list;
|
||||
|
||||
/*
|
||||
* rev_info.reverse is used to note the fact that we
|
||||
* want to output the list of revisions in reverse
|
||||
* order. To accomplish this goal, reverse can have
|
||||
* different values:
|
||||
*
|
||||
* 0 do nothing
|
||||
* 1 reverse the list
|
||||
* 2 internal use: we have already obtained and
|
||||
* reversed the list, now we only need to yield
|
||||
* its items.
|
||||
*/
|
||||
|
||||
if (revs->reverse == 1) {
|
||||
revs->reverse = 0;
|
||||
list = NULL;
|
||||
while ((c = get_revision(revs)))
|
||||
commit_list_insert(c, &list);
|
||||
revs->commits = list;
|
||||
revs->reverse = 2;
|
||||
if (revs->boundary == 2) {
|
||||
unsigned i;
|
||||
struct object_array *array = &revs->boundary_commits;
|
||||
struct object_array_entry *objects = array->objects;
|
||||
for (i = 0; i < array->nr; i++) {
|
||||
c = (struct commit *)(objects[i].item);
|
||||
if (!c)
|
||||
continue;
|
||||
if (!(c->object.flags & CHILD_SHOWN))
|
||||
continue;
|
||||
if (!(c->object.flags & SHOWN))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!revs->commits)
|
||||
if (array->nr <= i)
|
||||
return NULL;
|
||||
c = revs->commits->item;
|
||||
list = revs->commits->next;
|
||||
free(revs->commits);
|
||||
revs->commits = list;
|
||||
|
||||
c->object.flags |= SHOWN | BOUNDARY;
|
||||
return c;
|
||||
}
|
||||
|
||||
if (0 < revs->skip_count) {
|
||||
while ((c = get_revision_1(revs)) != NULL) {
|
||||
if (revs->skip_count-- <= 0)
|
||||
if (revs->reverse) {
|
||||
int limit = -1;
|
||||
|
||||
if (0 <= revs->max_count) {
|
||||
limit = revs->max_count;
|
||||
if (0 < revs->skip_count)
|
||||
limit += revs->skip_count;
|
||||
}
|
||||
l = NULL;
|
||||
while ((c = get_revision_1(revs))) {
|
||||
commit_list_insert(c, &l);
|
||||
if ((0 < limit) && !--limit)
|
||||
break;
|
||||
}
|
||||
revs->commits = l;
|
||||
revs->reverse = 0;
|
||||
revs->max_count = -1;
|
||||
c = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now pick up what they want to give us
|
||||
*/
|
||||
c = get_revision_1(revs);
|
||||
if (c) {
|
||||
while (0 < revs->skip_count) {
|
||||
revs->skip_count--;
|
||||
c = get_revision_1(revs);
|
||||
if (!c)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check the max_count ... */
|
||||
/*
|
||||
* Check the max_count.
|
||||
*/
|
||||
switch (revs->max_count) {
|
||||
case -1:
|
||||
break;
|
||||
case 0:
|
||||
if (revs->boundary) {
|
||||
struct commit_list *list = revs->commits;
|
||||
while (list) {
|
||||
list->item->object.flags |=
|
||||
BOUNDARY_SHOW | BOUNDARY;
|
||||
list = list->next;
|
||||
}
|
||||
/* all remaining commits are boundary commits */
|
||||
revs->max_count = -1;
|
||||
revs->limited = 1;
|
||||
} else
|
||||
return NULL;
|
||||
c = NULL;
|
||||
break;
|
||||
default:
|
||||
revs->max_count--;
|
||||
}
|
||||
|
||||
if (c)
|
||||
c->object.flags |= SHOWN;
|
||||
|
||||
if (!revs->boundary) {
|
||||
return c;
|
||||
return get_revision_1(revs);
|
||||
}
|
||||
|
||||
if (!c) {
|
||||
/*
|
||||
* get_revision_1() runs out the commits, and
|
||||
* we are done computing the boundaries.
|
||||
* switch to boundary commits output mode.
|
||||
*/
|
||||
revs->boundary = 2;
|
||||
return get_revision(revs);
|
||||
}
|
||||
|
||||
/*
|
||||
* boundary commits are the commits that are parents of the
|
||||
* ones we got from get_revision_1() but they themselves are
|
||||
* not returned from get_revision_1(). Before returning
|
||||
* 'c', we need to mark its parents that they could be boundaries.
|
||||
*/
|
||||
|
||||
for (l = c->parents; l; l = l->next) {
|
||||
struct object *p;
|
||||
p = &(l->item->object);
|
||||
if (p->flags & (CHILD_SHOWN | SHOWN))
|
||||
continue;
|
||||
p->flags |= CHILD_SHOWN;
|
||||
gc_boundary(&revs->boundary_commits);
|
||||
add_object_array(p, NULL, &revs->boundary_commits);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#define SHOWN (1u<<3)
|
||||
#define TMP_MARK (1u<<4) /* for isolated cases; clean after use */
|
||||
#define BOUNDARY (1u<<5)
|
||||
#define BOUNDARY_SHOW (1u<<6)
|
||||
#define CHILD_SHOWN (1u<<6)
|
||||
#define ADDED (1u<<7) /* Parents already parsed and added? */
|
||||
#define SYMMETRIC_LEFT (1u<<8)
|
||||
|
||||
@@ -21,6 +21,9 @@ struct rev_info {
|
||||
struct commit_list *commits;
|
||||
struct object_array pending;
|
||||
|
||||
/* Parents of shown commits */
|
||||
struct object_array boundary_commits;
|
||||
|
||||
/* Basic information */
|
||||
const char *prefix;
|
||||
void *prune_data;
|
||||
@@ -40,10 +43,10 @@ struct rev_info {
|
||||
edge_hint:1,
|
||||
limited:1,
|
||||
unpacked:1, /* see also ignore_packed below */
|
||||
boundary:1,
|
||||
boundary:2,
|
||||
left_right:1,
|
||||
parents:1,
|
||||
reverse:2;
|
||||
reverse:1;
|
||||
|
||||
/* Diff flags */
|
||||
unsigned int diff:1,
|
||||
|
||||
@@ -3,29 +3,60 @@
|
||||
#include "exec_cmd.h"
|
||||
#include "spawn-pipe.h"
|
||||
|
||||
int run_command_v_opt(const char **argv, int flags)
|
||||
static inline void close_pair(int fd[2])
|
||||
{
|
||||
pid_t pid;
|
||||
int fd_i[2] = { -1, -1 };
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
}
|
||||
|
||||
int start_command(struct child_process *cmd)
|
||||
{
|
||||
int need_in = !cmd->no_stdin && cmd->in < 0;
|
||||
int fdin[2] = { -1, -1 };
|
||||
int fd_o[2] = { -1, -1 };
|
||||
|
||||
if (need_in) {
|
||||
if (pipe(fdin) < 0)
|
||||
return -ERR_RUN_COMMAND_PIPE;
|
||||
cmd->in = fdin[1];
|
||||
cmd->close_in = 1;
|
||||
}
|
||||
|
||||
{
|
||||
if (flags & RUN_COMMAND_NO_STDIN) {
|
||||
fd_i[0] = open("/dev/null", O_RDWR);
|
||||
if (cmd->no_stdin) {
|
||||
fdin[0] = open("/dev/null", O_RDWR);
|
||||
} else if (need_in) {
|
||||
/* nothing */
|
||||
} else if (cmd->in) {
|
||||
fdin[0] = cmd->in;
|
||||
}
|
||||
if (flags & RUN_COMMAND_STDOUT_TO_STDERR)
|
||||
|
||||
if (cmd->stdout_to_stderr)
|
||||
fd_o[1] = dup(2);
|
||||
if (flags & RUN_GIT_CMD) {
|
||||
pid = spawnv_git_cmd(argv, fd_i, fd_o);
|
||||
if (cmd->git_cmd) {
|
||||
cmd->pid = spawnv_git_cmd(cmd->argv, fdin, fd_o);
|
||||
} else {
|
||||
pid = spawnvpe_pipe(argv[0], argv, environ, fd_i, fd_o);
|
||||
cmd->pid = spawnvpe_pipe(cmd->argv[0], cmd->argv, environ, fdin, fd_o);
|
||||
}
|
||||
}
|
||||
if (pid < 0)
|
||||
if (cmd->pid < 0) {
|
||||
if (need_in) {
|
||||
close_pair(fdin);
|
||||
}
|
||||
return -ERR_RUN_COMMAND_FORK;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int finish_command(struct child_process *cmd)
|
||||
{
|
||||
if (cmd->close_in)
|
||||
close(cmd->in);
|
||||
|
||||
for (;;) {
|
||||
int status, code;
|
||||
pid_t waiting = waitpid(pid, &status, 0);
|
||||
pid_t waiting = waitpid(cmd->pid, &status, 0);
|
||||
|
||||
if (waiting < 0) {
|
||||
if (errno == EINTR)
|
||||
@@ -33,7 +64,7 @@ int run_command_v_opt(const char **argv, int flags)
|
||||
error("waitpid failed (%s)", strerror(errno));
|
||||
return -ERR_RUN_COMMAND_WAITPID;
|
||||
}
|
||||
if (waiting != pid)
|
||||
if (waiting != cmd->pid)
|
||||
return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
|
||||
if (WIFSIGNALED(status))
|
||||
return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
|
||||
@@ -46,3 +77,22 @@ int run_command_v_opt(const char **argv, int flags)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int run_command(struct child_process *cmd)
|
||||
{
|
||||
int code = start_command(cmd);
|
||||
if (code)
|
||||
return code;
|
||||
return finish_command(cmd);
|
||||
}
|
||||
|
||||
int run_command_v_opt(const char **argv, int opt)
|
||||
{
|
||||
struct child_process cmd;
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.argv = argv;
|
||||
cmd.no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
|
||||
cmd.git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
|
||||
cmd.stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
|
||||
return run_command(&cmd);
|
||||
}
|
||||
|
||||
@@ -4,12 +4,27 @@
|
||||
enum {
|
||||
ERR_RUN_COMMAND_FORK = 10000,
|
||||
ERR_RUN_COMMAND_EXEC,
|
||||
ERR_RUN_COMMAND_PIPE,
|
||||
ERR_RUN_COMMAND_WAITPID,
|
||||
ERR_RUN_COMMAND_WAITPID_WRONG_PID,
|
||||
ERR_RUN_COMMAND_WAITPID_SIGNAL,
|
||||
ERR_RUN_COMMAND_WAITPID_NOEXIT,
|
||||
};
|
||||
|
||||
struct child_process {
|
||||
const char **argv;
|
||||
pid_t pid;
|
||||
int in;
|
||||
unsigned close_in:1;
|
||||
unsigned no_stdin:1;
|
||||
unsigned git_cmd:1; /* if this is to be git sub-command */
|
||||
unsigned stdout_to_stderr:1;
|
||||
};
|
||||
|
||||
int start_command(struct child_process *);
|
||||
int finish_command(struct child_process *);
|
||||
int run_command(struct child_process *);
|
||||
|
||||
#define RUN_COMMAND_NO_STDIN 1
|
||||
#define RUN_GIT_CMD 2 /*If this is to be git sub-command */
|
||||
#define RUN_COMMAND_STDOUT_TO_STDERR 4
|
||||
|
||||
56
sha1_file.c
56
sha1_file.c
@@ -749,6 +749,7 @@ struct packed_git *add_packed_git(char *path, int path_len, int local)
|
||||
p->windows = NULL;
|
||||
p->pack_fd = -1;
|
||||
p->pack_local = local;
|
||||
p->mtime = st.st_mtime;
|
||||
if ((path_len > 44) && !get_sha1_hex(path + path_len - 44, sha1))
|
||||
hashcpy(p->sha1, sha1);
|
||||
return p;
|
||||
@@ -833,6 +834,60 @@ static void prepare_packed_git_one(char *objdir, int local)
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
static int sort_pack(const void *a_, const void *b_)
|
||||
{
|
||||
struct packed_git *a = *((struct packed_git **)a_);
|
||||
struct packed_git *b = *((struct packed_git **)b_);
|
||||
int st;
|
||||
|
||||
/*
|
||||
* Local packs tend to contain objects specific to our
|
||||
* variant of the project than remote ones. In addition,
|
||||
* remote ones could be on a network mounted filesystem.
|
||||
* Favor local ones for these reasons.
|
||||
*/
|
||||
st = a->pack_local - b->pack_local;
|
||||
if (st)
|
||||
return -st;
|
||||
|
||||
/*
|
||||
* Younger packs tend to contain more recent objects,
|
||||
* and more recent objects tend to get accessed more
|
||||
* often.
|
||||
*/
|
||||
if (a->mtime < b->mtime)
|
||||
return 1;
|
||||
else if (a->mtime == b->mtime)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void rearrange_packed_git(void)
|
||||
{
|
||||
struct packed_git **ary, *p;
|
||||
int i, n;
|
||||
|
||||
for (n = 0, p = packed_git; p; p = p->next)
|
||||
n++;
|
||||
if (n < 2)
|
||||
return;
|
||||
|
||||
/* prepare an array of packed_git for easier sorting */
|
||||
ary = xcalloc(n, sizeof(struct packed_git *));
|
||||
for (n = 0, p = packed_git; p; p = p->next)
|
||||
ary[n++] = p;
|
||||
|
||||
qsort(ary, n, sizeof(struct packed_git *), sort_pack);
|
||||
|
||||
/* link them back again */
|
||||
for (i = 0; i < n - 1; i++)
|
||||
ary[i]->next = ary[i + 1];
|
||||
ary[n - 1]->next = NULL;
|
||||
packed_git = ary[0];
|
||||
|
||||
free(ary);
|
||||
}
|
||||
|
||||
static int prepare_packed_git_run_once = 0;
|
||||
void prepare_packed_git(void)
|
||||
{
|
||||
@@ -847,6 +902,7 @@ void prepare_packed_git(void)
|
||||
prepare_packed_git_one(alt->base, 0);
|
||||
alt->name[-1] = '/';
|
||||
}
|
||||
rearrange_packed_git();
|
||||
prepare_packed_git_run_once = 1;
|
||||
}
|
||||
|
||||
|
||||
10
sha1_name.c
10
sha1_name.c
@@ -602,10 +602,10 @@ static int handle_one_ref(const char *path,
|
||||
*/
|
||||
|
||||
#define ONELINE_SEEN (1u<<20)
|
||||
int get_sha1_oneline(const char *prefix, unsigned char *sha1)
|
||||
static int get_sha1_oneline(const char *prefix, unsigned char *sha1)
|
||||
{
|
||||
struct commit_list *list = NULL, *backup = NULL, *l;
|
||||
struct commit *commit = NULL;
|
||||
int retval = -1;
|
||||
|
||||
if (prefix[0] == '!') {
|
||||
if (prefix[1] != '!')
|
||||
@@ -619,22 +619,22 @@ int get_sha1_oneline(const char *prefix, unsigned char *sha1)
|
||||
commit_list_insert(l->item, &backup);
|
||||
while (list) {
|
||||
char *p;
|
||||
struct commit *commit;
|
||||
|
||||
commit = pop_most_recent_commit(&list, ONELINE_SEEN);
|
||||
if (!commit)
|
||||
break;
|
||||
parse_object(commit->object.sha1);
|
||||
if (!commit->buffer || !(p = strstr(commit->buffer, "\n\n")))
|
||||
continue;
|
||||
if (!prefixcmp(p + 2, prefix)) {
|
||||
hashcpy(sha1, commit->object.sha1);
|
||||
retval = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free_commit_list(list);
|
||||
for (l = backup; l; l = l->next)
|
||||
clear_commit_marks(l->item, ONELINE_SEEN);
|
||||
return commit == NULL;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -47,17 +47,6 @@ test_expect_success \
|
||||
test ! -f .git/refs/heads/d/e/f &&
|
||||
test ! -f .git/logs/refs/heads/d/e/f'
|
||||
|
||||
cat >expect <<EOF
|
||||
0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 checkout: Created from master
|
||||
EOF
|
||||
test_expect_success \
|
||||
'git checkout -b g/h/i -l should create a branch and a log' \
|
||||
'GIT_COMMITTER_DATE="2005-05-26 23:30" \
|
||||
git-checkout -b g/h/i -l master &&
|
||||
test -f .git/refs/heads/g/h/i &&
|
||||
test -f .git/logs/refs/heads/g/h/i &&
|
||||
diff expect .git/logs/refs/heads/g/h/i'
|
||||
|
||||
test_expect_success \
|
||||
'git branch j/k should work after branch j has been deleted' \
|
||||
'git-branch j &&
|
||||
@@ -119,4 +108,58 @@ test_expect_failure \
|
||||
git-branch -m u v'
|
||||
}
|
||||
|
||||
test_expect_success 'test tracking setup via --track' \
|
||||
'git-config remote.local.url . &&
|
||||
git-config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
|
||||
(git-show-ref -q refs/remotes/local/master || git-fetch local) &&
|
||||
git-branch --track my1 local/master &&
|
||||
test $(git-config branch.my1.remote) = local &&
|
||||
test $(git-config branch.my1.merge) = refs/heads/master'
|
||||
|
||||
test_expect_success 'test tracking setup (non-wildcard, matching)' \
|
||||
'git-config remote.local.url . &&
|
||||
git-config remote.local.fetch refs/heads/master:refs/remotes/local/master &&
|
||||
(git-show-ref -q refs/remotes/local/master || git-fetch local) &&
|
||||
git-branch --track my4 local/master &&
|
||||
test $(git-config branch.my4.remote) = local &&
|
||||
test $(git-config branch.my4.merge) = refs/heads/master'
|
||||
|
||||
test_expect_success 'test tracking setup (non-wildcard, not matching)' \
|
||||
'git-config remote.local.url . &&
|
||||
git-config remote.local.fetch refs/heads/s:refs/remotes/local/s &&
|
||||
(git-show-ref -q refs/remotes/local/master || git-fetch local) &&
|
||||
git-branch --track my5 local/master &&
|
||||
! test $(git-config branch.my5.remote) = local &&
|
||||
! test $(git-config branch.my5.merge) = refs/heads/master'
|
||||
|
||||
test_expect_success 'test tracking setup via config' \
|
||||
'git-config branch.autosetupmerge true &&
|
||||
git-config remote.local.url . &&
|
||||
git-config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
|
||||
(git-show-ref -q refs/remotes/local/master || git-fetch local) &&
|
||||
git-branch my3 local/master &&
|
||||
test $(git-config branch.my3.remote) = local &&
|
||||
test $(git-config branch.my3.merge) = refs/heads/master'
|
||||
|
||||
test_expect_success 'test overriding tracking setup via --no-track' \
|
||||
'git-config branch.autosetupmerge true &&
|
||||
git-config remote.local.url . &&
|
||||
git-config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
|
||||
(git-show-ref -q refs/remotes/local/master || git-fetch local) &&
|
||||
git-branch --no-track my2 local/master &&
|
||||
! test $(git-config branch.my2.remote) = local &&
|
||||
! test $(git-config branch.my2.merge) = refs/heads/master'
|
||||
|
||||
# Keep this test last, as it changes the current branch
|
||||
cat >expect <<EOF
|
||||
0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master
|
||||
EOF
|
||||
test_expect_success \
|
||||
'git checkout -b g/h/i -l should create a branch and a log' \
|
||||
'GIT_COMMITTER_DATE="2005-05-26 23:30" \
|
||||
git-checkout -b g/h/i -l master &&
|
||||
test -f .git/refs/heads/g/h/i &&
|
||||
test -f .git/logs/refs/heads/g/h/i &&
|
||||
diff expect .git/logs/refs/heads/g/h/i'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -11,7 +11,7 @@ test_expect_success 'split sample box' \
|
||||
'git-mailsplit -o. ../t5100/sample.mbox >last &&
|
||||
last=`cat last` &&
|
||||
echo total is $last &&
|
||||
test `cat last` = 6'
|
||||
test `cat last` = 8'
|
||||
|
||||
for mail in `echo 00*`
|
||||
do
|
||||
|
||||
5
t/t5100/info0007
Normal file
5
t/t5100/info0007
Normal file
@@ -0,0 +1,5 @@
|
||||
Author: A U Thor
|
||||
Email: a.u.thor@example.com
|
||||
Subject: another patch
|
||||
Date: Fri, 9 Jun 2006 00:44:16 -0700
|
||||
|
||||
5
t/t5100/info0008
Normal file
5
t/t5100/info0008
Normal file
@@ -0,0 +1,5 @@
|
||||
Author: Junio C Hamano
|
||||
Email: junio@kernel.org
|
||||
Subject: another patch
|
||||
Date: Fri, 9 Jun 2006 00:44:16 -0700
|
||||
|
||||
2
t/t5100/msg0007
Normal file
2
t/t5100/msg0007
Normal file
@@ -0,0 +1,2 @@
|
||||
Here is an empty patch from A U Thor.
|
||||
|
||||
4
t/t5100/msg0008
Normal file
4
t/t5100/msg0008
Normal file
@@ -0,0 +1,4 @@
|
||||
>Here is an empty patch from A U Thor.
|
||||
|
||||
Hey you forgot the patch!
|
||||
|
||||
@@ -61,7 +61,7 @@ diff --git a/git-cvsimport-script b/git-cvsimport-script
|
||||
push(@old,$fn);
|
||||
|
||||
--
|
||||
David K<EFBFBD>gedal
|
||||
David Kågedal
|
||||
-
|
||||
To unsubscribe from this list: send the line "unsubscribe git" in
|
||||
the body of a message to majordomo@vger.kernel.org
|
||||
|
||||
0
t/t5100/patch0007
Normal file
0
t/t5100/patch0007
Normal file
0
t/t5100/patch0008
Normal file
0
t/t5100/patch0008
Normal file
@@ -386,3 +386,21 @@ index 9123cdc..918dcf8 100644
|
||||
--
|
||||
1.4.0.g6f2b
|
||||
|
||||
From nobody Mon Sep 17 00:00:00 2001
|
||||
From: A U Thor <a.u.thor@example.com>
|
||||
Date: Fri, 9 Jun 2006 00:44:16 -0700
|
||||
Subject: [PATCH] another patch
|
||||
|
||||
Here is an empty patch from A U Thor.
|
||||
|
||||
From nobody Mon Sep 17 00:00:00 2001
|
||||
From: Junio C Hamano <junio@kernel.org>
|
||||
Date: Fri, 9 Jun 2006 00:44:16 -0700
|
||||
Subject: re: [PATCH] another patch
|
||||
|
||||
From: A U Thor <a.u.thor@example.com>
|
||||
Subject: [PATCH] another patch
|
||||
>Here is an empty patch from A U Thor.
|
||||
|
||||
Hey you forgot the patch!
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ test_expect_success setup '
|
||||
|
||||
cat >victim/.git/hooks/pre-receive <<'EOF'
|
||||
#!/bin/sh
|
||||
echo "$@" >>$GIT_DIR/pre-receive.args
|
||||
read x; printf "$x" >$GIT_DIR/pre-receive.stdin
|
||||
printf "$@" >>$GIT_DIR/pre-receive.args
|
||||
cat - >$GIT_DIR/pre-receive.stdin
|
||||
echo STDOUT pre-receive
|
||||
echo STDERR pre-receive >&2
|
||||
EOF
|
||||
@@ -44,8 +44,8 @@ chmod u+x victim/.git/hooks/update
|
||||
|
||||
cat >victim/.git/hooks/post-receive <<'EOF'
|
||||
#!/bin/sh
|
||||
echo "$@" >>$GIT_DIR/post-receive.args
|
||||
read x; printf "$x" >$GIT_DIR/post-receive.stdin
|
||||
printf "$@" >>$GIT_DIR/post-receive.args
|
||||
cat - >$GIT_DIR/post-receive.stdin
|
||||
echo STDOUT post-receive
|
||||
echo STDERR post-receive >&2
|
||||
EOF
|
||||
@@ -80,11 +80,10 @@ test_expect_success 'hooks ran' '
|
||||
test -f victim/.git/post-update.stdin
|
||||
'
|
||||
|
||||
test_expect_success 'pre-receive hook arguments' '
|
||||
echo \
|
||||
refs/heads/master $commit0 $commit1 \
|
||||
refs/heads/tofail $commit1 $commit0 \
|
||||
| git diff - victim/.git/pre-receive.args
|
||||
test_expect_success 'pre-receive hook input' '
|
||||
(echo $commit0 $commit1 refs/heads/master;
|
||||
echo $commit1 $commit0 refs/heads/tofail
|
||||
) | git diff - victim/.git/pre-receive.stdin
|
||||
'
|
||||
|
||||
test_expect_success 'update hook arguments' '
|
||||
@@ -93,9 +92,9 @@ test_expect_success 'update hook arguments' '
|
||||
) | git diff - victim/.git/update.args
|
||||
'
|
||||
|
||||
test_expect_success 'post-receive hook arguments' '
|
||||
echo refs/heads/master $commit0 $commit1 |
|
||||
git diff - victim/.git/post-receive.args
|
||||
test_expect_success 'post-receive hook input' '
|
||||
echo $commit0 $commit1 refs/heads/master |
|
||||
git diff - victim/.git/post-receive.stdin
|
||||
'
|
||||
|
||||
test_expect_success 'post-update hook arguments' '
|
||||
@@ -104,12 +103,15 @@ test_expect_success 'post-update hook arguments' '
|
||||
'
|
||||
|
||||
test_expect_success 'all hook stdin is /dev/null' '
|
||||
! test -s victim/.git/pre-receive.stdin &&
|
||||
! test -s victim/.git/update.stdin &&
|
||||
! test -s victim/.git/post-receive.stdin &&
|
||||
! test -s victim/.git/post-update.stdin
|
||||
'
|
||||
|
||||
test_expect_success 'all *-receive hook args are empty' '
|
||||
! test -s victim/.git/pre-receive.args &&
|
||||
! test -s victim/.git/post-receive.args
|
||||
'
|
||||
|
||||
test_expect_failure 'send-pack produced no output' '
|
||||
test -s send.out
|
||||
'
|
||||
|
||||
@@ -90,6 +90,13 @@ test_expect_success 'create bundle 1' '
|
||||
git bundle create bundle1 master^..master
|
||||
'
|
||||
|
||||
test_expect_success 'header of bundle looks right' '
|
||||
head -n 1 "$D"/bundle1 | grep "^#" &&
|
||||
head -n 2 "$D"/bundle1 | grep "^-[0-9a-f]\{40\} " &&
|
||||
head -n 3 "$D"/bundle1 | grep "^[0-9a-f]\{40\} " &&
|
||||
head -n 4 "$D"/bundle1 | grep "^$"
|
||||
'
|
||||
|
||||
test_expect_success 'create bundle 2' '
|
||||
cd "$D" &&
|
||||
git bundle create bundle2 master~2..master
|
||||
@@ -101,10 +108,41 @@ test_expect_failure 'unbundle 1' '
|
||||
git fetch "$D/bundle1" master:master
|
||||
'
|
||||
|
||||
test_expect_success 'bundle 1 has only 3 files ' '
|
||||
cd "$D" &&
|
||||
(
|
||||
while read x && test -n "$x"
|
||||
do
|
||||
:;
|
||||
done
|
||||
cat
|
||||
) <bundle1 >bundle.pack &&
|
||||
git index-pack bundle.pack &&
|
||||
verify=$(git verify-pack -v bundle.pack) &&
|
||||
test 4 = $(echo "$verify" | wc -l)
|
||||
'
|
||||
|
||||
test_expect_success 'unbundle 2' '
|
||||
cd "$D/bundle" &&
|
||||
git fetch ../bundle2 master:master &&
|
||||
test "tip" = "$(git log -1 --pretty=oneline master | cut -b42-)"
|
||||
'
|
||||
|
||||
test_expect_success 'bundle does not prerequisite objects' '
|
||||
cd "$D" &&
|
||||
touch file2 &&
|
||||
git add file2 &&
|
||||
git commit -m add.file2 file2 &&
|
||||
git bundle create bundle3 -1 HEAD &&
|
||||
(
|
||||
while read x && test -n "$x"
|
||||
do
|
||||
:;
|
||||
done
|
||||
cat
|
||||
) <bundle3 >bundle.pack &&
|
||||
git index-pack bundle.pack &&
|
||||
test 4 = $(git verify-pack -v bundle.pack | wc -l)
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -501,4 +501,54 @@ test_expect_success \
|
||||
'test `git-rev-parse --verify branch^1` \
|
||||
= `git-rev-parse --verify K^1`'
|
||||
|
||||
###
|
||||
### series L
|
||||
###
|
||||
|
||||
cat >input <<INPUT_END
|
||||
blob
|
||||
mark :1
|
||||
data <<EOF
|
||||
some data
|
||||
EOF
|
||||
|
||||
blob
|
||||
mark :2
|
||||
data <<EOF
|
||||
other data
|
||||
EOF
|
||||
|
||||
commit refs/heads/L
|
||||
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
||||
data <<COMMIT
|
||||
create L
|
||||
COMMIT
|
||||
|
||||
M 644 :1 b.
|
||||
M 644 :1 b/other
|
||||
M 644 :1 ba
|
||||
|
||||
commit refs/heads/L
|
||||
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
||||
data <<COMMIT
|
||||
update L
|
||||
COMMIT
|
||||
|
||||
M 644 :2 b.
|
||||
M 644 :2 b/other
|
||||
M 644 :2 ba
|
||||
INPUT_END
|
||||
|
||||
cat >expect <<EXPECT_END
|
||||
:100644 100644 4268632... 55d3a52... M b.
|
||||
:040000 040000 0ae5cac... 443c768... M b
|
||||
:100644 100644 4268632... 55d3a52... M ba
|
||||
EXPECT_END
|
||||
|
||||
test_expect_success \
|
||||
'L: verify internal tree sorting' \
|
||||
'git-fast-import <input &&
|
||||
git-diff --raw L^ L >output &&
|
||||
git diff expect output'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -210,7 +210,7 @@ case "$refname_type" in
|
||||
fi
|
||||
|
||||
# If this tag succeeds another, then show which tag it replaces
|
||||
prevtag=$(git describe $newrev^ 2>/dev/null | sed 's/-g.*//')
|
||||
prevtag=$(git describe --abbrev=0 $newrev^ 2>/dev/null)
|
||||
if [ -n "$prevtag" ]; then
|
||||
echo " replaces $prevtag"
|
||||
fi
|
||||
|
||||
18
trace.c
18
trace.c
@@ -26,14 +26,14 @@
|
||||
#include "quote.h"
|
||||
|
||||
/* Stolen from "imap-send.c". */
|
||||
static int git_vasprintf(char **strp, const char *fmt, va_list ap)
|
||||
int nfvasprintf(char **strp, const char *fmt, va_list ap)
|
||||
{
|
||||
int len;
|
||||
char tmp[1024];
|
||||
|
||||
if ((len = vsnprintf(tmp, sizeof(tmp), fmt, ap)) < 0 ||
|
||||
!(*strp = xmalloc(len + 1)))
|
||||
return -1;
|
||||
die("Fatal: Out of memory\n");
|
||||
if (len >= (int)sizeof(tmp))
|
||||
vsprintf(*strp, fmt, ap);
|
||||
else
|
||||
@@ -41,13 +41,15 @@ static int git_vasprintf(char **strp, const char *fmt, va_list ap)
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Stolen from "imap-send.c". */
|
||||
int nfvasprintf(char **str, const char *fmt, va_list va)
|
||||
int nfasprintf(char **str, const char *fmt, ...)
|
||||
{
|
||||
int ret = git_vasprintf(str, fmt, va);
|
||||
if (ret < 0)
|
||||
die("Fatal: Out of memory\n");
|
||||
return ret;
|
||||
int rc;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
rc = nfvasprintf(str, fmt, args);
|
||||
va_end(args);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Get a trace file descriptor from GIT_TRACE env variable. */
|
||||
|
||||
Reference in New Issue
Block a user