mirror of
https://github.com/git/git
synced 2024-08-27 11:39:22 +00:00
Merge master into aw/mirror-push
This commit is contained in:
commit
0d9d89f61c
112
Documentation/CodingGuidelines
Normal file
112
Documentation/CodingGuidelines
Normal file
|
@ -0,0 +1,112 @@
|
|||
Like other projects, we also have some guidelines to keep to the
|
||||
code. For git in general, three rough rules are:
|
||||
|
||||
- Most importantly, we never say "It's in POSIX; we'll happily
|
||||
ignore your needs should your system not conform to it."
|
||||
We live in the real world.
|
||||
|
||||
- However, we often say "Let's stay away from that construct,
|
||||
it's not even in POSIX".
|
||||
|
||||
- In spite of the above two rules, we sometimes say "Although
|
||||
this is not in POSIX, it (is so convenient | makes the code
|
||||
much more readable | has other good characteristics) and
|
||||
practically all the platforms we care about support it, so
|
||||
let's use it".
|
||||
|
||||
Again, we live in the real world, and it is sometimes a
|
||||
judgement call, the decision based more on real world
|
||||
constraints people face than what the paper standard says.
|
||||
|
||||
|
||||
As for more concrete guidelines, just imitate the existing code
|
||||
(this is a good guideline, no matter which project you are
|
||||
contributing to). But if you must have a list of rules,
|
||||
here they are.
|
||||
|
||||
For shell scripts specifically (not exhaustive):
|
||||
|
||||
- We prefer $( ... ) for command substitution; unlike ``, it
|
||||
properly nests. It should have been the way Bourne spelled
|
||||
it from day one, but unfortunately isn't.
|
||||
|
||||
- We use ${parameter-word} and its [-=?+] siblings, and their
|
||||
colon'ed "unset or null" form.
|
||||
|
||||
- We use ${parameter#word} and its [#%] siblings, and their
|
||||
doubled "longest matching" form.
|
||||
|
||||
- We use Arithmetic Expansion $(( ... )).
|
||||
|
||||
- No "Substring Expansion" ${parameter:offset:length}.
|
||||
|
||||
- No shell arrays.
|
||||
|
||||
- No strlen ${#parameter}.
|
||||
|
||||
- No regexp ${parameter/pattern/string}.
|
||||
|
||||
- We do not use Process Substitution <(list) or >(list).
|
||||
|
||||
- We prefer "test" over "[ ... ]".
|
||||
|
||||
- We do not write the noiseword "function" in front of shell
|
||||
functions.
|
||||
|
||||
For C programs:
|
||||
|
||||
- We use tabs to indent, and interpret tabs as taking up to
|
||||
8 spaces.
|
||||
|
||||
- We try to keep to at most 80 characters per line.
|
||||
|
||||
- When declaring pointers, the star sides with the variable
|
||||
name, i.e. "char *string", not "char* string" or
|
||||
"char * string". This makes it easier to understand code
|
||||
like "char *string, c;".
|
||||
|
||||
- We avoid using braces unnecessarily. I.e.
|
||||
|
||||
if (bla) {
|
||||
x = 1;
|
||||
}
|
||||
|
||||
is frowned upon. A gray area is when the statement extends
|
||||
over a few lines, and/or you have a lengthy comment atop of
|
||||
it. Also, like in the Linux kernel, if there is a long list
|
||||
of "else if" statements, it can make sense to add braces to
|
||||
single line blocks.
|
||||
|
||||
- Try to make your code understandable. You may put comments
|
||||
in, but comments invariably tend to stale out when the code
|
||||
they were describing changes. Often splitting a function
|
||||
into two makes the intention of the code much clearer.
|
||||
|
||||
- Double negation is often harder to understand than no negation
|
||||
at all.
|
||||
|
||||
- Some clever tricks, like using the !! operator with arithmetic
|
||||
constructs, can be extremely confusing to others. Avoid them,
|
||||
unless there is a compelling reason to use them.
|
||||
|
||||
- Use the API. No, really. We have a strbuf (variable length
|
||||
string), several arrays with the ALLOC_GROW() macro, a
|
||||
path_list for sorted string lists, a hash map (mapping struct
|
||||
objects) named "struct decorate", amongst other things.
|
||||
|
||||
- When you come up with an API, document it.
|
||||
|
||||
- The first #include in C files, except in platform specific
|
||||
compat/ implementations, should be git-compat-util.h or another
|
||||
header file that includes it, such as cache.h or builtin.h.
|
||||
|
||||
- If you are planning a new command, consider writing it in shell
|
||||
or perl first, so that changes in semantics can be easily
|
||||
changed and discussed. Many git commands started out like
|
||||
that, and a few are still scripts.
|
||||
|
||||
- Avoid introducing a new dependency into git. This means you
|
||||
usually should stay away from scripting languages not already
|
||||
used in the git core command set (unless your command is clearly
|
||||
separate from it, such as an importer to convert random-scm-X
|
||||
repositories to git).
|
|
@ -63,8 +63,8 @@ Fixes since v1.5.3.4
|
|||
|
||||
* Git segfaulted when reading an invalid .gitattributes file. Fixed.
|
||||
|
||||
* post-receive-email example hook fixed was fixed for
|
||||
non-fast-forward updates.
|
||||
* post-receive-email example hook was fixed for non-fast-forward
|
||||
updates.
|
||||
|
||||
* Documentation updates for supported (but previously undocumented)
|
||||
options of "git-archive" and "git-reflog".
|
||||
|
@ -90,5 +90,5 @@ Fixes since v1.5.3.4
|
|||
* "git-send-pack $remote frotz" segfaulted when there is nothing
|
||||
named 'frotz' on the local end.
|
||||
|
||||
* "git-rebase -interactive" did not handle its "--strategy" option
|
||||
* "git-rebase --interactive" did not handle its "--strategy" option
|
||||
properly.
|
||||
|
|
21
Documentation/RelNotes-1.5.3.6.txt
Normal file
21
Documentation/RelNotes-1.5.3.6.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
GIT v1.5.3.6 Release Notes
|
||||
==========================
|
||||
|
||||
Fixes since v1.5.3.5
|
||||
--------------------
|
||||
|
||||
* git-cvsexportcommit handles root commits better;
|
||||
|
||||
* git-svn dcommit used to clobber when sending a series of
|
||||
patches;
|
||||
|
||||
* git-grep sometimes refused to work when your index was
|
||||
unmerged;
|
||||
|
||||
* Quite a lot of documentation clarifications.
|
||||
|
||||
--
|
||||
exec >/var/tmp/1
|
||||
O=v1.5.3.5-32-gcb6c162
|
||||
echo O=`git describe refs/heads/maint`
|
||||
git shortlog --no-merges $O..refs/heads/maint
|
|
@ -6,7 +6,10 @@ Updates since v1.5.3
|
|||
|
||||
* Comes with much improved gitk.
|
||||
|
||||
* git-reset is now built-in.
|
||||
* "progress display" from many commands are a lot nicer to the
|
||||
eye. Transfer commands show throughput data.
|
||||
|
||||
* git-reset is now built-in and its output can be squelched with -q.
|
||||
|
||||
* git-send-email can optionally talk over ssmtp and use SMTP-AUTH.
|
||||
|
||||
|
@ -46,6 +49,28 @@ Updates since v1.5.3
|
|||
|
||||
* Various Perforce importer updates.
|
||||
|
||||
* git-lost-found was deprecated in favor of git-fsck's --lost-found
|
||||
option.
|
||||
|
||||
* git-svnimport was removed in favor of git-svn.
|
||||
|
||||
* git-bisect learned "skip" action to mark untestable commits.
|
||||
|
||||
* rename detection diff family, while detecting exact matches,
|
||||
has been greatly optimized.
|
||||
|
||||
* Example update and post-receive hooks have been improved.
|
||||
|
||||
* In addition there are quite a few internal clean-ups. Notably
|
||||
|
||||
- many fork/exec have been replaced with run-command API,
|
||||
brought from the msysgit effort.
|
||||
|
||||
- introduction and more use of the option parser API.
|
||||
|
||||
- enhancement and more use of the strbuf API.
|
||||
|
||||
|
||||
Fixes since v1.5.3
|
||||
------------------
|
||||
|
||||
|
@ -54,6 +79,6 @@ this release, unless otherwise noted.
|
|||
|
||||
--
|
||||
exec >/var/tmp/1
|
||||
O=v1.5.3.4-450-g952a9e5
|
||||
O=v1.5.3.5-618-g5d4138a
|
||||
echo O=`git describe refs/heads/master`
|
||||
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
|
||||
|
|
|
@ -20,9 +20,6 @@ Checklist (and a short version for the impatient):
|
|||
Patch:
|
||||
|
||||
- use "git format-patch -M" to create the patch
|
||||
- send your patch to <git@vger.kernel.org>. If you use
|
||||
git-send-email(1), please test it first by sending
|
||||
email to yourself.
|
||||
- do not PGP sign your patch
|
||||
- do not attach your patch, but read in the mail
|
||||
body, unless you cannot teach your mailer to
|
||||
|
@ -31,13 +28,15 @@ Checklist (and a short version for the impatient):
|
|||
corrupt whitespaces.
|
||||
- provide additional information (which is unsuitable for
|
||||
the commit message) between the "---" and the diffstat
|
||||
- send the patch to the list (git@vger.kernel.org) and the
|
||||
maintainer (gitster@pobox.com).
|
||||
- if you change, add, or remove a command line option or
|
||||
make some other user interface change, the associated
|
||||
documentation should be updated as well.
|
||||
- if your name is not writable in ASCII, make sure that
|
||||
you send off a message in the correct encoding.
|
||||
- send the patch to the list (git@vger.kernel.org) and the
|
||||
maintainer (gitster@pobox.com). If you use
|
||||
git-send-email(1), please test it first by sending
|
||||
email to yourself.
|
||||
|
||||
Long version:
|
||||
|
||||
|
|
|
@ -345,8 +345,8 @@ branch.<name>.mergeoptions::
|
|||
supported.
|
||||
|
||||
clean.requireForce::
|
||||
A boolean to make git-clean do nothing unless given -f or -n. Defaults
|
||||
to false.
|
||||
A boolean to make git-clean do nothing unless given -f
|
||||
or -n. Defaults to true.
|
||||
|
||||
color.branch::
|
||||
A boolean to enable/disable color in the output of
|
||||
|
@ -661,6 +661,15 @@ pack.threads::
|
|||
machines. The required amount of memory for the delta search window
|
||||
is however multiplied by the number of threads.
|
||||
|
||||
pack.indexVersion::
|
||||
Specify the default pack index version. Valid values are 1 for
|
||||
legacy pack index used by Git versions prior to 1.5.2, and 2 for
|
||||
the new pack index with capabilities for packs larger than 4 GB
|
||||
as well as proper protection against the repacking of corrupted
|
||||
packs. Version 2 is selected and this config option ignored
|
||||
whenever the corresponding pack is larger than 2 GB. Otherwise
|
||||
the default is 1.
|
||||
|
||||
pull.octopus::
|
||||
The default merge strategy to use when pulling multiple branches
|
||||
at once.
|
||||
|
|
|
@ -7,7 +7,7 @@ git-cherry-pick - Apply the change introduced by an existing commit
|
|||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-cherry-pick' [--edit] [-n] [-x] <commit>
|
||||
'git-cherry-pick' [--edit] [-n] [-m parent-number] [-x] <commit>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
@ -44,6 +44,13 @@ OPTIONS
|
|||
described above, and `-r` was to disable it. Now the
|
||||
default is not to do `-x` so this option is a no-op.
|
||||
|
||||
-m parent-number|--mainline parent-number::
|
||||
Usually you cannot revert a merge because you do not know which
|
||||
side of the merge should be considered the mainline. This
|
||||
option specifies the parent number (starting from 1) of
|
||||
the mainline and allows cherry-pick to replay the change
|
||||
relative to the specified parent.
|
||||
|
||||
-n|--no-commit::
|
||||
Usually the command automatically creates a commit with
|
||||
a commit log message stating which commit was
|
||||
|
|
|
@ -12,7 +12,7 @@ SYNOPSIS
|
|||
'git-clone' [--template=<template_directory>]
|
||||
[-l] [-s] [--no-hardlinks] [-q] [-n] [--bare]
|
||||
[-o <name>] [-u <upload-pack>] [--reference <repository>]
|
||||
[--depth <depth>] <repository> [<directory>]
|
||||
[--depth <depth>] [--] <repository> [<directory>]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
|
|
@ -11,6 +11,10 @@ SYNOPSIS
|
|||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
*NOTE*: this command is deprecated. Use gitlink:git-fsck[1] with
|
||||
the option '--lost-found' instead.
|
||||
|
||||
Finds dangling commits and tags from the object database, and
|
||||
creates refs to them in the .git/lost-found/ directory. Commits and
|
||||
tags that dereference to commits are stored in .git/lost-found/commit,
|
||||
|
|
|
@ -8,8 +8,8 @@ git-reset - Reset current HEAD to the specified state
|
|||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-reset' [--mixed | --soft | --hard] [<commit>]
|
||||
'git-reset' [--mixed] <commit> [--] <paths>...
|
||||
'git-reset' [--mixed | --soft | --hard] [-q] [<commit>]
|
||||
'git-reset' [--mixed] [-q] <commit> [--] <paths>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
@ -45,6 +45,9 @@ OPTIONS
|
|||
switched to. Any changes to tracked files in the working tree
|
||||
since <commit> are lost.
|
||||
|
||||
-q::
|
||||
Be quiet, only report errors.
|
||||
|
||||
<commit>::
|
||||
Commit to make the current HEAD.
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ git-revert - Revert an existing commit
|
|||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-revert' [--edit | --no-edit] [-n] <commit>
|
||||
'git-revert' [--edit | --no-edit] [-n] [-m parent-number] <commit>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
@ -27,6 +27,13 @@ OPTIONS
|
|||
message prior committing the revert. This is the default if
|
||||
you run the command from a terminal.
|
||||
|
||||
-m parent-number|--mainline parent-number::
|
||||
Usually you cannot revert a merge because you do not know which
|
||||
side of the merge should be considered the mainline. This
|
||||
option specifies the parent number (starting from 1) of
|
||||
the mainline and allows revert to reverse the change
|
||||
relative to the specified parent.
|
||||
|
||||
--no-edit::
|
||||
With this option, `git-revert` will not start the commit
|
||||
message editor.
|
||||
|
|
|
@ -113,8 +113,7 @@ The --cc option must be repeated for each user you want on the cc list.
|
|||
is not set, this will be prompted for.
|
||||
|
||||
--suppress-from, --no-suppress-from::
|
||||
If this is set, do not add the From: address to the cc: list, if it
|
||||
shows up in a From: line.
|
||||
If this is set, do not add the From: address to the cc: list.
|
||||
Default is the value of 'sendemail.suppressfrom' configuration value;
|
||||
if that is unspecified, default to --no-suppress-from.
|
||||
|
||||
|
|
9
Makefile
9
Makefile
|
@ -98,6 +98,8 @@ all::
|
|||
# Define OLD_ICONV if your library has an old iconv(), where the second
|
||||
# (input buffer pointer) parameter is declared with type (const char **).
|
||||
#
|
||||
# Define NO_DEFLATE_BOUND if your zlib does not have deflateBound.
|
||||
#
|
||||
# Define NO_R_TO_GCC_LINKER if your gcc does not like "-R/path/lib"
|
||||
# that tells runtime paths to dynamic libraries;
|
||||
# "-Wl,-rpath=/path/lib" is used instead.
|
||||
|
@ -298,7 +300,7 @@ DIFF_OBJS = \
|
|||
LIB_OBJS = \
|
||||
blob.o commit.o connect.o csum-file.o cache-tree.o base85.o \
|
||||
date.o diff-delta.o entry.o exec_cmd.o ident.o \
|
||||
interpolate.o hash.o \
|
||||
pretty.o interpolate.o hash.o \
|
||||
lockfile.o \
|
||||
patch-ids.o \
|
||||
object.o pack-check.o pack-write.o patch-delta.o path.o pkt-line.o \
|
||||
|
@ -662,6 +664,10 @@ ifdef OLD_ICONV
|
|||
BASIC_CFLAGS += -DOLD_ICONV
|
||||
endif
|
||||
|
||||
ifdef NO_DEFLATE_BOUND
|
||||
BASIC_CFLAGS += -DNO_DEFLATE_BOUND
|
||||
endif
|
||||
|
||||
ifdef PPC_SHA1
|
||||
SHA1_HEADER = "ppc/sha1.h"
|
||||
LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
|
||||
|
@ -917,6 +923,7 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS)
|
|||
|
||||
$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
|
||||
$(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
|
||||
builtin-revert.o builtin-runstatus.o wt-status.o: wt-status.h
|
||||
|
||||
$(LIB_FILE): $(LIB_OBJS)
|
||||
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
|
||||
|
|
|
@ -2215,9 +2215,6 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
|||
argv[unk++] = arg;
|
||||
}
|
||||
|
||||
if (!incremental)
|
||||
setup_pager();
|
||||
|
||||
if (!blame_move_score)
|
||||
blame_move_score = BLAME_DEFAULT_MOVE_SCORE;
|
||||
if (!blame_copy_score)
|
||||
|
@ -2345,6 +2342,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
|||
* do not default to HEAD, but use the working tree
|
||||
* or "--contents".
|
||||
*/
|
||||
setup_work_tree();
|
||||
sb.final = fake_working_tree_commit(path, contents_from);
|
||||
add_pending_object(&revs, &(sb.final->object), ":");
|
||||
}
|
||||
|
@ -2411,6 +2409,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
|||
|
||||
read_mailmap(&mailmap, ".mailmap", NULL);
|
||||
|
||||
if (!incremental)
|
||||
setup_pager();
|
||||
|
||||
assign_blame(&sb, &revs, opt);
|
||||
|
||||
if (incremental)
|
||||
|
|
|
@ -148,7 +148,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
|
|||
|
||||
if (!force &&
|
||||
!in_merge_bases(rev, &head_rev, 1)) {
|
||||
error("The branch '%s' is not a strict subset of "
|
||||
error("The branch '%s' is not an ancestor of "
|
||||
"your current HEAD.\n"
|
||||
"If you are sure you want to delete it, "
|
||||
"run 'git branch -D %s'.", argv[i], argv[i]);
|
||||
|
@ -282,7 +282,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
|
|||
commit = lookup_commit(item->sha1);
|
||||
if (commit && !parse_commit(commit)) {
|
||||
pretty_print_commit(CMIT_FMT_ONELINE, commit,
|
||||
&subject, 0, NULL, NULL, 0);
|
||||
&subject, 0, NULL, NULL, 0, 0);
|
||||
sub = subject.buf;
|
||||
}
|
||||
printf("%c %s%-*s%s %s %s\n", c, branch_get_color(color),
|
||||
|
|
|
@ -200,15 +200,11 @@ static void refresh_index_quietly(void)
|
|||
discard_cache();
|
||||
read_cache();
|
||||
refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED);
|
||||
if (active_cache_changed) {
|
||||
if (write_cache(fd, active_cache, active_nr) ||
|
||||
close(fd) ||
|
||||
commit_locked_index(lock_file))
|
||||
; /*
|
||||
* silently ignore it -- we haven't mucked
|
||||
* with the real index.
|
||||
*/
|
||||
}
|
||||
|
||||
if (active_cache_changed &&
|
||||
!write_cache(fd, active_cache, active_nr) && !close(fd))
|
||||
commit_locked_index(lock_file);
|
||||
|
||||
rollback_lock_file(lock_file);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ static const char fetch_pack_usage[] =
|
|||
#define MAX_IN_VAIN 256
|
||||
|
||||
static struct commit_list *rev_list;
|
||||
static int non_common_revs, multi_ack, use_thin_pack, use_sideband;
|
||||
static int non_common_revs, multi_ack, use_sideband;
|
||||
|
||||
static void rev_list_push(struct commit *commit, int mark)
|
||||
{
|
||||
|
@ -178,7 +178,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
|
|||
(multi_ack ? " multi_ack" : ""),
|
||||
(use_sideband == 2 ? " side-band-64k" : ""),
|
||||
(use_sideband == 1 ? " side-band" : ""),
|
||||
(use_thin_pack ? " thin-pack" : ""),
|
||||
(args.use_thin_pack ? " thin-pack" : ""),
|
||||
(args.no_progress ? " no-progress" : ""),
|
||||
" ofs-delta");
|
||||
else
|
||||
|
|
116
builtin-fetch.c
116
builtin-fetch.c
|
@ -131,12 +131,6 @@ static struct ref *get_ref_map(struct transport *transport,
|
|||
return ref_map;
|
||||
}
|
||||
|
||||
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 s_update_ref(const char *action,
|
||||
struct ref *ref,
|
||||
int check_old)
|
||||
|
@ -157,34 +151,38 @@ static int s_update_ref(const char *action,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
|
||||
|
||||
static int update_local_ref(struct ref *ref,
|
||||
const char *note,
|
||||
int verbose)
|
||||
const char *remote,
|
||||
int verbose,
|
||||
char *display)
|
||||
{
|
||||
char oldh[41], newh[41];
|
||||
struct commit *current = NULL, *updated;
|
||||
enum object_type type;
|
||||
struct branch *current_branch = branch_get(NULL);
|
||||
const char *pretty_ref = ref->name + (
|
||||
!prefixcmp(ref->name, "refs/heads/") ? 11 :
|
||||
!prefixcmp(ref->name, "refs/tags/") ? 10 :
|
||||
!prefixcmp(ref->name, "refs/remotes/") ? 13 :
|
||||
0);
|
||||
|
||||
*display = 0;
|
||||
type = sha1_object_info(ref->new_sha1, NULL);
|
||||
if (type < 0)
|
||||
die("object %s not found", sha1_to_hex(ref->new_sha1));
|
||||
|
||||
if (!*ref->name) {
|
||||
/* Not storing */
|
||||
if (verbose) {
|
||||
fprintf(stderr, "* fetched %s\n", note);
|
||||
show_new(type, ref->new_sha1);
|
||||
}
|
||||
if (verbose)
|
||||
sprintf(display, "* branch %s -> FETCH_HEAD", remote);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!hashcmp(ref->old_sha1, ref->new_sha1)) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "* %s: same as %s\n",
|
||||
ref->name, note);
|
||||
show_new(type, ref->new_sha1);
|
||||
}
|
||||
if (verbose)
|
||||
sprintf(display, "= %-*s %s -> %s", SUMMARY_WIDTH,
|
||||
"[up to date]", remote, pretty_ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -196,63 +194,65 @@ static int update_local_ref(struct ref *ref,
|
|||
* If this is the head, and it's not okay to update
|
||||
* the head, and the old value of the head isn't empty...
|
||||
*/
|
||||
fprintf(stderr,
|
||||
" * %s: Cannot fetch into the current branch.\n",
|
||||
ref->name);
|
||||
sprintf(display, "! %-*s %s -> %s (can't fetch in current branch)",
|
||||
SUMMARY_WIDTH, "[rejected]", remote, pretty_ref);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!is_null_sha1(ref->old_sha1) &&
|
||||
!prefixcmp(ref->name, "refs/tags/")) {
|
||||
fprintf(stderr, "* %s: updating with %s\n",
|
||||
ref->name, note);
|
||||
show_new(type, ref->new_sha1);
|
||||
sprintf(display, "- %-*s %s -> %s",
|
||||
SUMMARY_WIDTH, "[tag update]", remote, pretty_ref);
|
||||
return s_update_ref("updating tag", ref, 0);
|
||||
}
|
||||
|
||||
current = lookup_commit_reference_gently(ref->old_sha1, 1);
|
||||
updated = lookup_commit_reference_gently(ref->new_sha1, 1);
|
||||
if (!current || !updated) {
|
||||
char *msg;
|
||||
if (!strncmp(ref->name, "refs/tags/", 10))
|
||||
const char *msg;
|
||||
const char *what;
|
||||
if (!strncmp(ref->name, "refs/tags/", 10)) {
|
||||
msg = "storing tag";
|
||||
else
|
||||
what = "[new tag]";
|
||||
}
|
||||
else {
|
||||
msg = "storing head";
|
||||
fprintf(stderr, "* %s: storing %s\n",
|
||||
ref->name, note);
|
||||
show_new(type, ref->new_sha1);
|
||||
what = "[new branch]";
|
||||
}
|
||||
|
||||
sprintf(display, "* %-*s %s -> %s",
|
||||
SUMMARY_WIDTH, what, remote, pretty_ref);
|
||||
return s_update_ref(msg, ref, 0);
|
||||
}
|
||||
|
||||
strcpy(oldh, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
|
||||
strcpy(newh, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
|
||||
|
||||
if (in_merge_bases(current, &updated, 1)) {
|
||||
fprintf(stderr, "* %s: fast forward to %s\n",
|
||||
ref->name, note);
|
||||
fprintf(stderr, " old..new: %s..%s\n", oldh, newh);
|
||||
char quickref[83];
|
||||
strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
|
||||
strcat(quickref, "..");
|
||||
strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
|
||||
sprintf(display, " %-*s %s -> %s (fast forward)",
|
||||
SUMMARY_WIDTH, quickref, remote, pretty_ref);
|
||||
return s_update_ref("fast forward", ref, 1);
|
||||
}
|
||||
if (!force && !ref->force) {
|
||||
fprintf(stderr,
|
||||
"* %s: not updating to non-fast forward %s\n",
|
||||
ref->name, note);
|
||||
fprintf(stderr,
|
||||
" old...new: %s...%s\n", oldh, newh);
|
||||
} else if (force || ref->force) {
|
||||
char quickref[84];
|
||||
strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
|
||||
strcat(quickref, "...");
|
||||
strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
|
||||
sprintf(display, "+ %-*s %s -> %s (forced update)",
|
||||
SUMMARY_WIDTH, quickref, remote, pretty_ref);
|
||||
return s_update_ref("forced-update", ref, 1);
|
||||
} else {
|
||||
sprintf(display, "! %-*s %s -> %s (non fast forward)",
|
||||
SUMMARY_WIDTH, "[rejected]", remote, pretty_ref);
|
||||
return 1;
|
||||
}
|
||||
fprintf(stderr,
|
||||
"* %s: forcing update to non-fast forward %s\n",
|
||||
ref->name, note);
|
||||
fprintf(stderr, " old...new: %s...%s\n", oldh, newh);
|
||||
return s_update_ref("forced-update", ref, 1);
|
||||
}
|
||||
|
||||
static void store_updated_refs(const char *url, struct ref *ref_map)
|
||||
{
|
||||
FILE *fp;
|
||||
struct commit *commit;
|
||||
int url_len, i, note_len;
|
||||
int url_len, i, note_len, shown_url = 0;
|
||||
char note[1024];
|
||||
const char *what, *kind;
|
||||
struct ref *rm;
|
||||
|
@ -315,8 +315,17 @@ static void store_updated_refs(const char *url, struct ref *ref_map)
|
|||
rm->merge ? "" : "not-for-merge",
|
||||
note);
|
||||
|
||||
if (ref)
|
||||
update_local_ref(ref, note, verbose);
|
||||
if (ref) {
|
||||
update_local_ref(ref, what, verbose, note);
|
||||
if (*note) {
|
||||
if (!shown_url) {
|
||||
fprintf(stderr, "From %.*s\n",
|
||||
url_len, url);
|
||||
shown_url = 1;
|
||||
}
|
||||
fprintf(stderr, " %s\n", note);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
@ -376,9 +385,6 @@ static struct ref *find_non_local_tags(struct transport *transport,
|
|||
if (!path_list_has_path(&existing_refs, ref_name) &&
|
||||
!path_list_has_path(&new_refs, ref_name) &&
|
||||
lookup_object(ref->old_sha1)) {
|
||||
fprintf(stderr, "Auto-following %s\n",
|
||||
ref_name);
|
||||
|
||||
path_list_insert(ref_name, &new_refs);
|
||||
|
||||
rm = alloc_ref(strlen(ref_name) + 1);
|
||||
|
@ -517,7 +523,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
|
|||
depth = argv[i];
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--quiet")) {
|
||||
if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) {
|
||||
quiet = 1;
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -175,7 +175,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
|
|||
char buf[80];
|
||||
|
||||
struct option builtin_gc_options[] = {
|
||||
OPT_BOOLEAN(0, "prune", &prune, "prune unreferenced loose objects"),
|
||||
OPT_BOOLEAN(0, "prune", &prune, "prune unreferenced objects"),
|
||||
OPT_BOOLEAN(0, "aggressive", &aggressive, "be more thorough (increased runtime)"),
|
||||
OPT_BOOLEAN(0, "auto", &auto_gc, "enable auto-gc mode"),
|
||||
OPT_END()
|
||||
|
|
|
@ -343,7 +343,7 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
|
|||
memcpy(name + 2, ce->name, len + 1);
|
||||
}
|
||||
argv[argc++] = name;
|
||||
if (argc < MAXARGS && !ce_stage(ce))
|
||||
if (argc < MAXARGS)
|
||||
continue;
|
||||
status = flush_grep(opt, argc, nr, argv, &kept);
|
||||
if (0 < status)
|
||||
|
|
|
@ -787,7 +787,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
|
|||
struct strbuf buf;
|
||||
strbuf_init(&buf, 0);
|
||||
pretty_print_commit(CMIT_FMT_ONELINE, commit,
|
||||
&buf, 0, NULL, NULL, 0);
|
||||
&buf, 0, NULL, NULL, 0, 0);
|
||||
printf("%c %s %s\n", sign,
|
||||
sha1_to_hex(commit->object.sha1), buf.buf);
|
||||
strbuf_release(&buf);
|
||||
|
|
|
@ -525,11 +525,8 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
|
|||
break;
|
||||
}
|
||||
|
||||
if (require_work_tree && !is_inside_work_tree()) {
|
||||
const char *work_tree = get_git_work_tree();
|
||||
if (!work_tree || chdir(work_tree))
|
||||
die("This operation must be run in a work tree");
|
||||
}
|
||||
if (require_work_tree && !is_inside_work_tree())
|
||||
setup_work_tree();
|
||||
|
||||
pathspec = get_pathspec(prefix, argv + i);
|
||||
|
||||
|
|
|
@ -915,6 +915,7 @@ static void handle_info(void)
|
|||
static int mailinfo(FILE *in, FILE *out, int ks, const char *encoding,
|
||||
const char *msg, const char *patch)
|
||||
{
|
||||
int peek;
|
||||
keep_subject = ks;
|
||||
metainfo_charset = encoding;
|
||||
fin = in;
|
||||
|
@ -935,6 +936,11 @@ static int mailinfo(FILE *in, FILE *out, int ks, const char *encoding,
|
|||
p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(char *));
|
||||
s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(char *));
|
||||
|
||||
do {
|
||||
peek = fgetc(in);
|
||||
} while (isspace(peek));
|
||||
ungetc(peek, in);
|
||||
|
||||
/* process the email header */
|
||||
while (read_one_header_line(line, sizeof(line), fin))
|
||||
check_header(line, sizeof(line), p_hdr_data, 1);
|
||||
|
|
|
@ -101,20 +101,29 @@ static int populate_maildir_list(struct path_list *list, const char *path)
|
|||
{
|
||||
DIR *dir;
|
||||
struct dirent *dent;
|
||||
char name[PATH_MAX];
|
||||
char *subs[] = { "cur", "new", NULL };
|
||||
char **sub;
|
||||
|
||||
if ((dir = opendir(path)) == NULL) {
|
||||
error("cannot opendir %s (%s)", path, strerror(errno));
|
||||
return -1;
|
||||
for (sub = subs; *sub; ++sub) {
|
||||
snprintf(name, sizeof(name), "%s/%s", path, *sub);
|
||||
if ((dir = opendir(name)) == NULL) {
|
||||
if (errno == ENOENT)
|
||||
continue;
|
||||
error("cannot opendir %s (%s)", name, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((dent = readdir(dir)) != NULL) {
|
||||
if (dent->d_name[0] == '.')
|
||||
continue;
|
||||
snprintf(name, sizeof(name), "%s/%s", *sub, dent->d_name);
|
||||
path_list_insert(name, list);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
while ((dent = readdir(dir)) != NULL) {
|
||||
if (dent->d_name[0] == '.')
|
||||
continue;
|
||||
path_list_insert(dent->d_name, list);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -122,19 +131,17 @@ static int split_maildir(const char *maildir, const char *dir,
|
|||
int nr_prec, int skip)
|
||||
{
|
||||
char file[PATH_MAX];
|
||||
char curdir[PATH_MAX];
|
||||
char name[PATH_MAX];
|
||||
int ret = -1;
|
||||
int i;
|
||||
struct path_list list = {NULL, 0, 0, 1};
|
||||
|
||||
snprintf(curdir, sizeof(curdir), "%s/cur", maildir);
|
||||
if (populate_maildir_list(&list, curdir) < 0)
|
||||
if (populate_maildir_list(&list, maildir) < 0)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < list.nr; i++) {
|
||||
FILE *f;
|
||||
snprintf(file, sizeof(file), "%s/%s", curdir, list.items[i].path);
|
||||
snprintf(file, sizeof(file), "%s/%s", maildir, list.items[i].path);
|
||||
f = fopen(file, "r");
|
||||
if (!f) {
|
||||
error("cannot open mail %s (%s)", file, strerror(errno));
|
||||
|
@ -152,10 +159,9 @@ static int split_maildir(const char *maildir, const char *dir,
|
|||
fclose(f);
|
||||
}
|
||||
|
||||
path_list_clear(&list, 1);
|
||||
|
||||
ret = skip;
|
||||
out:
|
||||
path_list_clear(&list, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -164,6 +170,7 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
|
|||
{
|
||||
char name[PATH_MAX];
|
||||
int ret = -1;
|
||||
int peek;
|
||||
|
||||
FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r");
|
||||
int file_done = 0;
|
||||
|
@ -173,6 +180,11 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
|
|||
goto out;
|
||||
}
|
||||
|
||||
do {
|
||||
peek = fgetc(f);
|
||||
} while (isspace(peek));
|
||||
ungetc(peek, f);
|
||||
|
||||
if (fgets(buf, sizeof(buf), f) == NULL) {
|
||||
/* empty stdin is OK */
|
||||
if (f != stdin) {
|
||||
|
|
|
@ -57,7 +57,7 @@ struct object_entry {
|
|||
* nice "minimum seek" order.
|
||||
*/
|
||||
static struct object_entry *objects;
|
||||
static struct object_entry **written_list;
|
||||
static struct pack_idx_entry **written_list;
|
||||
static uint32_t nr_objects, nr_alloc, nr_result, nr_written;
|
||||
|
||||
static int non_empty;
|
||||
|
@ -577,7 +577,7 @@ static off_t write_one(struct sha1file *f,
|
|||
e->idx.offset = 0;
|
||||
return 0;
|
||||
}
|
||||
written_list[nr_written++] = e;
|
||||
written_list[nr_written++] = &e->idx;
|
||||
|
||||
/* make sure off_t is sufficiently large not to wrap */
|
||||
if (offset > offset + size)
|
||||
|
@ -599,7 +599,7 @@ static void write_pack_file(void)
|
|||
|
||||
if (do_progress)
|
||||
progress_state = start_progress("Writing objects", nr_result);
|
||||
written_list = xmalloc(nr_objects * sizeof(struct object_entry *));
|
||||
written_list = xmalloc(nr_objects * sizeof(*written_list));
|
||||
|
||||
do {
|
||||
unsigned char sha1[20];
|
||||
|
@ -651,9 +651,8 @@ static void write_pack_file(void)
|
|||
umask(mode);
|
||||
mode = 0444 & ~mode;
|
||||
|
||||
idx_tmp_name = write_idx_file(NULL,
|
||||
(struct pack_idx_entry **) written_list,
|
||||
nr_written, sha1);
|
||||
idx_tmp_name = write_idx_file(NULL, written_list,
|
||||
nr_written, sha1);
|
||||
snprintf(tmpname, sizeof(tmpname), "%s-%s.pack",
|
||||
base_name, sha1_to_hex(sha1));
|
||||
if (adjust_perm(pack_tmp_name, mode))
|
||||
|
@ -677,7 +676,7 @@ static void write_pack_file(void)
|
|||
|
||||
/* mark written objects as written to previous pack */
|
||||
for (j = 0; j < nr_written; j++) {
|
||||
written_list[j]->idx.offset = (off_t)-1;
|
||||
written_list[j]->offset = (off_t)-1;
|
||||
}
|
||||
nr_remaining -= nr_written;
|
||||
} while (nr_remaining && i < nr_objects);
|
||||
|
@ -1768,6 +1767,12 @@ static int git_pack_config(const char *k, const char *v)
|
|||
#endif
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(k, "pack.indexversion")) {
|
||||
pack_idx_default_version = git_config_int(k, v);
|
||||
if (pack_idx_default_version > 2)
|
||||
die("bad pack.indexversion=%d", pack_idx_default_version);
|
||||
return 0;
|
||||
}
|
||||
return git_default_config(k, v);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,12 @@
|
|||
#include "builtin.h"
|
||||
#include "remote.h"
|
||||
#include "transport.h"
|
||||
#include "parse-options.h"
|
||||
|
||||
static const char push_usage[] = "git-push [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
|
||||
static const char * const push_usage[] = {
|
||||
"git-push [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static int thin, verbose;
|
||||
static const char *receivepack;
|
||||
|
@ -85,63 +89,43 @@ static int do_push(const char *repo, int flags)
|
|||
|
||||
int cmd_push(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
int flags = 0;
|
||||
int all = 0;
|
||||
int dry_run = 0;
|
||||
int force = 0;
|
||||
int tags = 0;
|
||||
const char *repo = NULL; /* default repository */
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
struct option options[] = {
|
||||
OPT__VERBOSE(&verbose),
|
||||
OPT_STRING( 0 , "repo", &repo, "repository", "repository"),
|
||||
OPT_BOOLEAN( 0 , "all", &all, "push all refs"),
|
||||
OPT_BOOLEAN( 0 , "tags", &tags, "push tags"),
|
||||
OPT_BOOLEAN( 0 , "dry-run", &dry_run, "dry run"),
|
||||
OPT_BOOLEAN('f', "force", &force, "force updates"),
|
||||
OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
|
||||
OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
|
||||
OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
if (arg[0] != '-') {
|
||||
repo = arg;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
if (!strcmp(arg, "-v")) {
|
||||
verbose=1;
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "--repo=")) {
|
||||
repo = arg+7;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--all")) {
|
||||
flags |= TRANSPORT_PUSH_ALL;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--dry-run")) {
|
||||
flags |= TRANSPORT_PUSH_DRY_RUN;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--tags")) {
|
||||
add_refspec("refs/tags/*");
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) {
|
||||
flags |= TRANSPORT_PUSH_FORCE;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--thin")) {
|
||||
thin = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--no-thin")) {
|
||||
thin = 0;
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "--receive-pack=")) {
|
||||
receivepack = arg + 15;
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "--exec=")) {
|
||||
receivepack = arg + 7;
|
||||
continue;
|
||||
}
|
||||
usage(push_usage);
|
||||
argc = parse_options(argc, argv, options, push_usage, 0);
|
||||
|
||||
if (force)
|
||||
flags |= TRANSPORT_PUSH_FORCE;
|
||||
if (dry_run)
|
||||
flags |= TRANSPORT_PUSH_DRY_RUN;
|
||||
if (tags)
|
||||
add_refspec("refs/tags/*");
|
||||
if (all)
|
||||
flags |= TRANSPORT_PUSH_ALL;
|
||||
|
||||
if (argc > 0) {
|
||||
repo = argv[0];
|
||||
set_refspecs(argv + 1, argc - 1);
|
||||
}
|
||||
set_refspecs(argv + i, argc - i);
|
||||
if ((flags & TRANSPORT_PUSH_ALL) && refspec)
|
||||
usage(push_usage);
|
||||
usage_with_options(push_usage, options);
|
||||
|
||||
return do_push(repo, flags);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include "tree.h"
|
||||
|
||||
static const char builtin_reset_usage[] =
|
||||
"git-reset [--mixed | --soft | --hard] [<commit-ish>] [ [--] <paths>...]";
|
||||
"git-reset [--mixed | --soft | --hard] [-q] [<commit-ish>] [ [--] <paths>...]";
|
||||
|
||||
static char *args_to_str(const char **argv)
|
||||
{
|
||||
|
@ -113,10 +113,17 @@ static int update_index_refresh(void)
|
|||
return run_command_v_opt(argv_update_index, RUN_GIT_CMD);
|
||||
}
|
||||
|
||||
struct update_cb_data {
|
||||
int index_fd;
|
||||
struct lock_file *lock;
|
||||
int exit_code;
|
||||
};
|
||||
|
||||
static void update_index_from_diff(struct diff_queue_struct *q,
|
||||
struct diff_options *opt, void *data)
|
||||
{
|
||||
int i;
|
||||
struct update_cb_data *cb = data;
|
||||
|
||||
/* do_diff_cache() mangled the index */
|
||||
discard_cache();
|
||||
|
@ -133,29 +140,34 @@ static void update_index_from_diff(struct diff_queue_struct *q,
|
|||
} else
|
||||
remove_file_from_cache(one->path);
|
||||
}
|
||||
|
||||
cb->exit_code = write_cache(cb->index_fd, active_cache, active_nr) ||
|
||||
close(cb->index_fd) ||
|
||||
commit_locked_index(cb->lock);
|
||||
}
|
||||
|
||||
static int read_from_tree(const char *prefix, const char **argv,
|
||||
unsigned char *tree_sha1)
|
||||
{
|
||||
struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
|
||||
int index_fd;
|
||||
struct diff_options opt;
|
||||
struct update_cb_data cb;
|
||||
|
||||
memset(&opt, 0, sizeof(opt));
|
||||
diff_tree_setup_paths(get_pathspec(prefix, (const char **)argv), &opt);
|
||||
opt.output_format = DIFF_FORMAT_CALLBACK;
|
||||
opt.format_callback = update_index_from_diff;
|
||||
opt.format_callback_data = &cb;
|
||||
|
||||
index_fd = hold_locked_index(lock, 1);
|
||||
cb.lock = xcalloc(1, sizeof(struct lock_file));
|
||||
cb.index_fd = hold_locked_index(cb.lock, 1);
|
||||
cb.exit_code = 0;
|
||||
read_cache();
|
||||
if (do_diff_cache(tree_sha1, &opt))
|
||||
return 1;
|
||||
diffcore_std(&opt);
|
||||
diff_flush(&opt);
|
||||
return write_cache(index_fd, active_cache, active_nr) ||
|
||||
close(index_fd) ||
|
||||
commit_locked_index(lock);
|
||||
|
||||
return cb.exit_code;
|
||||
}
|
||||
|
||||
static void prepend_reflog_action(const char *action, char *buf, size_t size)
|
||||
|
@ -173,7 +185,7 @@ static const char *reset_type_names[] = { "mixed", "soft", "hard", NULL };
|
|||
|
||||
int cmd_reset(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i = 1, reset_type = NONE, update_ref_status = 0;
|
||||
int i = 1, reset_type = NONE, update_ref_status = 0, quiet = 0;
|
||||
const char *rev = "HEAD";
|
||||
unsigned char sha1[20], *orig = NULL, sha1_orig[20],
|
||||
*old_orig = NULL, sha1_old_orig[20];
|
||||
|
@ -185,7 +197,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
|||
reflog_action = args_to_str(argv);
|
||||
setenv("GIT_REFLOG_ACTION", reflog_action, 0);
|
||||
|
||||
if (i < argc) {
|
||||
while (i < argc) {
|
||||
if (!strcmp(argv[i], "--mixed")) {
|
||||
reset_type = MIXED;
|
||||
i++;
|
||||
|
@ -198,6 +210,12 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
|||
reset_type = HARD;
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-q")) {
|
||||
quiet = 1;
|
||||
i++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < argc && argv[i][0] != '-')
|
||||
|
@ -258,7 +276,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
|||
|
||||
switch (reset_type) {
|
||||
case HARD:
|
||||
if (!update_ref_status)
|
||||
if (!update_ref_status && !quiet)
|
||||
print_new_head_line(commit);
|
||||
break;
|
||||
case SOFT: /* Nothing else to do. */
|
||||
|
|
|
@ -86,7 +86,8 @@ static void show_commit(struct commit *commit)
|
|||
struct strbuf buf;
|
||||
strbuf_init(&buf, 0);
|
||||
pretty_print_commit(revs.commit_format, commit,
|
||||
&buf, revs.abbrev, NULL, NULL, revs.date_mode);
|
||||
&buf, revs.abbrev, NULL, NULL,
|
||||
revs.date_mode, 0);
|
||||
if (buf.len)
|
||||
printf("%s%c", buf.buf, hdr_termination);
|
||||
strbuf_release(&buf);
|
||||
|
|
|
@ -30,7 +30,7 @@ static const char * const cherry_pick_usage[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static int edit, no_replay, no_commit, needed_deref;
|
||||
static int edit, no_replay, no_commit, needed_deref, mainline;
|
||||
static enum { REVERT, CHERRY_PICK } action;
|
||||
static struct commit *commit;
|
||||
|
||||
|
@ -50,12 +50,14 @@ static void parse_args(int argc, const char **argv)
|
|||
OPT_BOOLEAN('e', "edit", &edit, "edit the commit message"),
|
||||
OPT_BOOLEAN('x', NULL, &no_replay, "append commit name when cherry-picking"),
|
||||
OPT_BOOLEAN('r', NULL, &noop, "no-op (backward compatibility)"),
|
||||
OPT_INTEGER('m', "mainline", &mainline, "parent number"),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
if (parse_options(argc, argv, options, usage_str, 0) != 1)
|
||||
usage_with_options(usage_str, options);
|
||||
arg = argv[0];
|
||||
|
||||
if (get_sha1(arg, sha1))
|
||||
die ("Cannot find '%s'", arg);
|
||||
commit = (struct commit *)parse_object(sha1);
|
||||
|
@ -226,7 +228,7 @@ static int merge_recursive(const char *base_sha1,
|
|||
static int revert_or_cherry_pick(int argc, const char **argv)
|
||||
{
|
||||
unsigned char head[20];
|
||||
struct commit *base, *next;
|
||||
struct commit *base, *next, *parent;
|
||||
int i;
|
||||
char *oneline, *reencoded_message = NULL;
|
||||
const char *message, *encoding;
|
||||
|
@ -261,8 +263,29 @@ static int revert_or_cherry_pick(int argc, const char **argv)
|
|||
|
||||
if (!commit->parents)
|
||||
die ("Cannot %s a root commit", me);
|
||||
if (commit->parents->next)
|
||||
die ("Cannot %s a multi-parent commit.", me);
|
||||
if (commit->parents->next) {
|
||||
/* Reverting or cherry-picking a merge commit */
|
||||
int cnt;
|
||||
struct commit_list *p;
|
||||
|
||||
if (!mainline)
|
||||
die("Commit %s is a merge but no -m option was given.",
|
||||
sha1_to_hex(commit->object.sha1));
|
||||
|
||||
for (cnt = 1, p = commit->parents;
|
||||
cnt != mainline && p;
|
||||
cnt++)
|
||||
p = p->next;
|
||||
if (cnt != mainline || !p)
|
||||
die("Commit %s does not have parent %d",
|
||||
sha1_to_hex(commit->object.sha1), mainline);
|
||||
parent = p->item;
|
||||
} else if (0 < mainline)
|
||||
die("Mainline was specified but commit %s is not a merge.",
|
||||
sha1_to_hex(commit->object.sha1));
|
||||
else
|
||||
parent = commit->parents->item;
|
||||
|
||||
if (!(message = commit->buffer))
|
||||
die ("Cannot get commit message for %s",
|
||||
sha1_to_hex(commit->object.sha1));
|
||||
|
@ -291,14 +314,14 @@ static int revert_or_cherry_pick(int argc, const char **argv)
|
|||
char *oneline_body = strchr(oneline, ' ');
|
||||
|
||||
base = commit;
|
||||
next = commit->parents->item;
|
||||
next = parent;
|
||||
add_to_msg("Revert \"");
|
||||
add_to_msg(oneline_body + 1);
|
||||
add_to_msg("\"\n\nThis reverts commit ");
|
||||
add_to_msg(sha1_to_hex(commit->object.sha1));
|
||||
add_to_msg(".\n");
|
||||
} else {
|
||||
base = commit->parents->item;
|
||||
base = parent;
|
||||
next = commit;
|
||||
set_author_ident_env(message);
|
||||
add_message_to_msg(message);
|
||||
|
|
|
@ -155,6 +155,9 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
|
|||
if (!argc)
|
||||
usage_with_options(builtin_rm_usage, builtin_rm_options);
|
||||
|
||||
if (!index_only)
|
||||
setup_work_tree();
|
||||
|
||||
pathspec = get_pathspec(prefix, argv);
|
||||
seen = NULL;
|
||||
for (i = 0; pathspec[i] ; i++)
|
||||
|
|
|
@ -266,7 +266,7 @@ static void show_one_commit(struct commit *commit, int no_name)
|
|||
strbuf_init(&pretty, 0);
|
||||
if (commit->object.parsed) {
|
||||
pretty_print_commit(CMIT_FMT_ONELINE, commit,
|
||||
&pretty, 0, NULL, NULL, 0);
|
||||
&pretty, 0, NULL, NULL, 0, 0);
|
||||
pretty_str = pretty.buf;
|
||||
}
|
||||
if (!prefixcmp(pretty_str, "[PATCH] "))
|
||||
|
|
|
@ -81,17 +81,16 @@ static int show_reference(const char *refname, const unsigned char *sha1,
|
|||
}
|
||||
printf("%-15s ", refname);
|
||||
|
||||
sp = buf = read_sha1_file(sha1, &type, &size);
|
||||
if (!buf)
|
||||
buf = read_sha1_file(sha1, &type, &size);
|
||||
if (!buf || !size)
|
||||
return 0;
|
||||
if (!size) {
|
||||
|
||||
/* skip header */
|
||||
sp = strstr(buf, "\n\n");
|
||||
if (!sp) {
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
/* skip header */
|
||||
while (sp + 1 < buf + size &&
|
||||
!(sp[0] == '\n' && sp[1] == '\n'))
|
||||
sp++;
|
||||
/* only take up to "lines" lines, and strip the signature */
|
||||
for (i = 0, sp += 2;
|
||||
i < filter->lines && sp < buf + size &&
|
||||
|
|
3
bundle.c
3
bundle.c
|
@ -23,7 +23,8 @@ static void add_to_ref_list(const unsigned char *sha1, const char *name,
|
|||
}
|
||||
|
||||
/* returns an fd */
|
||||
int read_bundle_header(const char *path, struct bundle_header *header) {
|
||||
int read_bundle_header(const char *path, struct bundle_header *header)
|
||||
{
|
||||
char buffer[1024];
|
||||
int fd;
|
||||
long fpos;
|
||||
|
|
3
cache.h
3
cache.h
|
@ -7,7 +7,7 @@
|
|||
#include SHA1_HEADER
|
||||
#include <zlib.h>
|
||||
|
||||
#if ZLIB_VERNUM < 0x1200
|
||||
#if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200
|
||||
#define deflateBound(c,s) ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
|
||||
#endif
|
||||
|
||||
|
@ -222,6 +222,7 @@ extern const char *get_git_work_tree(void);
|
|||
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
|
||||
|
||||
extern const char **get_pathspec(const char *prefix, const char **pathspec);
|
||||
extern void setup_work_tree(void);
|
||||
extern const char *setup_git_directory_gently(int *);
|
||||
extern const char *setup_git_directory(void);
|
||||
extern const char *prefix_path(const char *prefix, int len, const char *path);
|
||||
|
|
719
commit.c
719
commit.c
|
@ -3,7 +3,6 @@
|
|||
#include "commit.h"
|
||||
#include "pkt-line.h"
|
||||
#include "utf8.h"
|
||||
#include "interpolate.h"
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
|
||||
|
@ -27,46 +26,6 @@ struct sort_node
|
|||
|
||||
const char *commit_type = "commit";
|
||||
|
||||
static struct cmt_fmt_map {
|
||||
const char *n;
|
||||
size_t cmp_len;
|
||||
enum cmit_fmt v;
|
||||
} cmt_fmts[] = {
|
||||
{ "raw", 1, CMIT_FMT_RAW },
|
||||
{ "medium", 1, CMIT_FMT_MEDIUM },
|
||||
{ "short", 1, CMIT_FMT_SHORT },
|
||||
{ "email", 1, CMIT_FMT_EMAIL },
|
||||
{ "full", 5, CMIT_FMT_FULL },
|
||||
{ "fuller", 5, CMIT_FMT_FULLER },
|
||||
{ "oneline", 1, CMIT_FMT_ONELINE },
|
||||
{ "format:", 7, CMIT_FMT_USERFORMAT},
|
||||
};
|
||||
|
||||
static char *user_format;
|
||||
|
||||
enum cmit_fmt get_commit_format(const char *arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!arg || !*arg)
|
||||
return CMIT_FMT_DEFAULT;
|
||||
if (*arg == '=')
|
||||
arg++;
|
||||
if (!prefixcmp(arg, "format:")) {
|
||||
if (user_format)
|
||||
free(user_format);
|
||||
user_format = xstrdup(arg + 7);
|
||||
return CMIT_FMT_USERFORMAT;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) {
|
||||
if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len) &&
|
||||
!strncmp(arg, cmt_fmts[i].n, strlen(arg)))
|
||||
return cmt_fmts[i].v;
|
||||
}
|
||||
|
||||
die("invalid --pretty format: %s", arg);
|
||||
}
|
||||
|
||||
static struct commit *check_commit(struct object *obj,
|
||||
const unsigned char *sha1,
|
||||
int quiet)
|
||||
|
@ -460,684 +419,6 @@ void clear_commit_marks(struct commit *commit, unsigned int mark)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic support for pretty-printing the header
|
||||
*/
|
||||
static int get_one_line(const char *msg)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
for (;;) {
|
||||
char c = *msg++;
|
||||
if (!c)
|
||||
break;
|
||||
ret++;
|
||||
if (c == '\n')
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* High bit set, or ISO-2022-INT */
|
||||
static int non_ascii(int ch)
|
||||
{
|
||||
ch = (ch & 0xff);
|
||||
return ((ch & 0x80) || (ch == 0x1b));
|
||||
}
|
||||
|
||||
static int is_rfc2047_special(char ch)
|
||||
{
|
||||
return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_'));
|
||||
}
|
||||
|
||||
static void add_rfc2047(struct strbuf *sb, const char *line, int len,
|
||||
const char *encoding)
|
||||
{
|
||||
int i, last;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int ch = line[i];
|
||||
if (non_ascii(ch))
|
||||
goto needquote;
|
||||
if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
|
||||
goto needquote;
|
||||
}
|
||||
strbuf_add(sb, line, len);
|
||||
return;
|
||||
|
||||
needquote:
|
||||
strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
|
||||
strbuf_addf(sb, "=?%s?q?", encoding);
|
||||
for (i = last = 0; i < len; i++) {
|
||||
unsigned ch = line[i] & 0xFF;
|
||||
/*
|
||||
* We encode ' ' using '=20' even though rfc2047
|
||||
* allows using '_' for readability. Unfortunately,
|
||||
* many programs do not understand this and just
|
||||
* leave the underscore in place.
|
||||
*/
|
||||
if (is_rfc2047_special(ch) || ch == ' ') {
|
||||
strbuf_add(sb, line + last, i - last);
|
||||
strbuf_addf(sb, "=%02X", ch);
|
||||
last = i + 1;
|
||||
}
|
||||
}
|
||||
strbuf_add(sb, line + last, len - last);
|
||||
strbuf_addstr(sb, "?=");
|
||||
}
|
||||
|
||||
static void add_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
|
||||
const char *line, enum date_mode dmode,
|
||||
const char *encoding)
|
||||
{
|
||||
char *date;
|
||||
int namelen;
|
||||
unsigned long time;
|
||||
int tz;
|
||||
const char *filler = " ";
|
||||
|
||||
if (fmt == CMIT_FMT_ONELINE)
|
||||
return;
|
||||
date = strchr(line, '>');
|
||||
if (!date)
|
||||
return;
|
||||
namelen = ++date - line;
|
||||
time = strtoul(date, &date, 10);
|
||||
tz = strtol(date, NULL, 10);
|
||||
|
||||
if (fmt == CMIT_FMT_EMAIL) {
|
||||
char *name_tail = strchr(line, '<');
|
||||
int display_name_length;
|
||||
if (!name_tail)
|
||||
return;
|
||||
while (line < name_tail && isspace(name_tail[-1]))
|
||||
name_tail--;
|
||||
display_name_length = name_tail - line;
|
||||
filler = "";
|
||||
strbuf_addstr(sb, "From: ");
|
||||
add_rfc2047(sb, line, display_name_length, encoding);
|
||||
strbuf_add(sb, name_tail, namelen - display_name_length);
|
||||
strbuf_addch(sb, '\n');
|
||||
} else {
|
||||
strbuf_addf(sb, "%s: %.*s%.*s\n", what,
|
||||
(fmt == CMIT_FMT_FULLER) ? 4 : 0,
|
||||
filler, namelen, line);
|
||||
}
|
||||
switch (fmt) {
|
||||
case CMIT_FMT_MEDIUM:
|
||||
strbuf_addf(sb, "Date: %s\n", show_date(time, tz, dmode));
|
||||
break;
|
||||
case CMIT_FMT_EMAIL:
|
||||
strbuf_addf(sb, "Date: %s\n", show_date(time, tz, DATE_RFC2822));
|
||||
break;
|
||||
case CMIT_FMT_FULLER:
|
||||
strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, dmode));
|
||||
break;
|
||||
default:
|
||||
/* notin' */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int is_empty_line(const char *line, int *len_p)
|
||||
{
|
||||
int len = *len_p;
|
||||
while (len && isspace(line[len-1]))
|
||||
len--;
|
||||
*len_p = len;
|
||||
return !len;
|
||||
}
|
||||
|
||||
static void add_merge_info(enum cmit_fmt fmt, struct strbuf *sb,
|
||||
const struct commit *commit, int abbrev)
|
||||
{
|
||||
struct commit_list *parent = commit->parents;
|
||||
|
||||
if ((fmt == CMIT_FMT_ONELINE) || (fmt == CMIT_FMT_EMAIL) ||
|
||||
!parent || !parent->next)
|
||||
return;
|
||||
|
||||
strbuf_addstr(sb, "Merge:");
|
||||
|
||||
while (parent) {
|
||||
struct commit *p = parent->item;
|
||||
const char *hex = NULL;
|
||||
const char *dots;
|
||||
if (abbrev)
|
||||
hex = find_unique_abbrev(p->object.sha1, abbrev);
|
||||
if (!hex)
|
||||
hex = sha1_to_hex(p->object.sha1);
|
||||
dots = (abbrev && strlen(hex) != 40) ? "..." : "";
|
||||
parent = parent->next;
|
||||
|
||||
strbuf_addf(sb, " %s%s", hex, dots);
|
||||
}
|
||||
strbuf_addch(sb, '\n');
|
||||
}
|
||||
|
||||
static char *get_header(const struct commit *commit, const char *key)
|
||||
{
|
||||
int key_len = strlen(key);
|
||||
const char *line = commit->buffer;
|
||||
|
||||
for (;;) {
|
||||
const char *eol = strchr(line, '\n'), *next;
|
||||
|
||||
if (line == eol)
|
||||
return NULL;
|
||||
if (!eol) {
|
||||
eol = line + strlen(line);
|
||||
next = NULL;
|
||||
} else
|
||||
next = eol + 1;
|
||||
if (eol - line > key_len &&
|
||||
!strncmp(line, key, key_len) &&
|
||||
line[key_len] == ' ') {
|
||||
return xmemdupz(line + key_len + 1, eol - line - key_len - 1);
|
||||
}
|
||||
line = next;
|
||||
}
|
||||
}
|
||||
|
||||
static char *replace_encoding_header(char *buf, const char *encoding)
|
||||
{
|
||||
struct strbuf tmp;
|
||||
size_t start, len;
|
||||
char *cp = buf;
|
||||
|
||||
/* guess if there is an encoding header before a \n\n */
|
||||
while (strncmp(cp, "encoding ", strlen("encoding "))) {
|
||||
cp = strchr(cp, '\n');
|
||||
if (!cp || *++cp == '\n')
|
||||
return buf;
|
||||
}
|
||||
start = cp - buf;
|
||||
cp = strchr(cp, '\n');
|
||||
if (!cp)
|
||||
return buf; /* should not happen but be defensive */
|
||||
len = cp + 1 - (buf + start);
|
||||
|
||||
strbuf_init(&tmp, 0);
|
||||
strbuf_attach(&tmp, buf, strlen(buf), strlen(buf) + 1);
|
||||
if (is_encoding_utf8(encoding)) {
|
||||
/* we have re-coded to UTF-8; drop the header */
|
||||
strbuf_remove(&tmp, start, len);
|
||||
} else {
|
||||
/* just replaces XXXX in 'encoding XXXX\n' */
|
||||
strbuf_splice(&tmp, start + strlen("encoding "),
|
||||
len - strlen("encoding \n"),
|
||||
encoding, strlen(encoding));
|
||||
}
|
||||
return strbuf_detach(&tmp, NULL);
|
||||
}
|
||||
|
||||
static char *logmsg_reencode(const struct commit *commit,
|
||||
const char *output_encoding)
|
||||
{
|
||||
static const char *utf8 = "utf-8";
|
||||
const char *use_encoding;
|
||||
char *encoding;
|
||||
char *out;
|
||||
|
||||
if (!*output_encoding)
|
||||
return NULL;
|
||||
encoding = get_header(commit, "encoding");
|
||||
use_encoding = encoding ? encoding : utf8;
|
||||
if (!strcmp(use_encoding, output_encoding))
|
||||
if (encoding) /* we'll strip encoding header later */
|
||||
out = xstrdup(commit->buffer);
|
||||
else
|
||||
return NULL; /* nothing to do */
|
||||
else
|
||||
out = reencode_string(commit->buffer,
|
||||
output_encoding, use_encoding);
|
||||
if (out)
|
||||
out = replace_encoding_header(out, output_encoding);
|
||||
|
||||
free(encoding);
|
||||
return out;
|
||||
}
|
||||
|
||||
static void fill_person(struct interp *table, const char *msg, int len)
|
||||
{
|
||||
int start, end, tz = 0;
|
||||
unsigned long date;
|
||||
char *ep;
|
||||
|
||||
/* parse name */
|
||||
for (end = 0; end < len && msg[end] != '<'; end++)
|
||||
; /* do nothing */
|
||||
start = end + 1;
|
||||
while (end > 0 && isspace(msg[end - 1]))
|
||||
end--;
|
||||
table[0].value = xmemdupz(msg, end);
|
||||
|
||||
if (start >= len)
|
||||
return;
|
||||
|
||||
/* parse email */
|
||||
for (end = start + 1; end < len && msg[end] != '>'; end++)
|
||||
; /* do nothing */
|
||||
|
||||
if (end >= len)
|
||||
return;
|
||||
|
||||
table[1].value = xmemdupz(msg + start, end - start);
|
||||
|
||||
/* parse date */
|
||||
for (start = end + 1; start < len && isspace(msg[start]); start++)
|
||||
; /* do nothing */
|
||||
if (start >= len)
|
||||
return;
|
||||
date = strtoul(msg + start, &ep, 10);
|
||||
if (msg + start == ep)
|
||||
return;
|
||||
|
||||
table[5].value = xmemdupz(msg + start, ep - (msg + start));
|
||||
|
||||
/* parse tz */
|
||||
for (start = ep - msg + 1; start < len && isspace(msg[start]); start++)
|
||||
; /* do nothing */
|
||||
if (start + 1 < len) {
|
||||
tz = strtoul(msg + start + 1, NULL, 10);
|
||||
if (msg[start] == '-')
|
||||
tz = -tz;
|
||||
}
|
||||
|
||||
interp_set_entry(table, 2, show_date(date, tz, DATE_NORMAL));
|
||||
interp_set_entry(table, 3, show_date(date, tz, DATE_RFC2822));
|
||||
interp_set_entry(table, 4, show_date(date, tz, DATE_RELATIVE));
|
||||
interp_set_entry(table, 6, show_date(date, tz, DATE_ISO8601));
|
||||
}
|
||||
|
||||
void format_commit_message(const struct commit *commit,
|
||||
const void *format, struct strbuf *sb)
|
||||
{
|
||||
struct interp table[] = {
|
||||
{ "%H" }, /* commit hash */
|
||||
{ "%h" }, /* abbreviated commit hash */
|
||||
{ "%T" }, /* tree hash */
|
||||
{ "%t" }, /* abbreviated tree hash */
|
||||
{ "%P" }, /* parent hashes */
|
||||
{ "%p" }, /* abbreviated parent hashes */
|
||||
{ "%an" }, /* author name */
|
||||
{ "%ae" }, /* author email */
|
||||
{ "%ad" }, /* author date */
|
||||
{ "%aD" }, /* author date, RFC2822 style */
|
||||
{ "%ar" }, /* author date, relative */
|
||||
{ "%at" }, /* author date, UNIX timestamp */
|
||||
{ "%ai" }, /* author date, ISO 8601 */
|
||||
{ "%cn" }, /* committer name */
|
||||
{ "%ce" }, /* committer email */
|
||||
{ "%cd" }, /* committer date */
|
||||
{ "%cD" }, /* committer date, RFC2822 style */
|
||||
{ "%cr" }, /* committer date, relative */
|
||||
{ "%ct" }, /* committer date, UNIX timestamp */
|
||||
{ "%ci" }, /* committer date, ISO 8601 */
|
||||
{ "%e" }, /* encoding */
|
||||
{ "%s" }, /* subject */
|
||||
{ "%b" }, /* body */
|
||||
{ "%Cred" }, /* red */
|
||||
{ "%Cgreen" }, /* green */
|
||||
{ "%Cblue" }, /* blue */
|
||||
{ "%Creset" }, /* reset color */
|
||||
{ "%n" }, /* newline */
|
||||
{ "%m" }, /* left/right/bottom */
|
||||
};
|
||||
enum interp_index {
|
||||
IHASH = 0, IHASH_ABBREV,
|
||||
ITREE, ITREE_ABBREV,
|
||||
IPARENTS, IPARENTS_ABBREV,
|
||||
IAUTHOR_NAME, IAUTHOR_EMAIL,
|
||||
IAUTHOR_DATE, IAUTHOR_DATE_RFC2822, IAUTHOR_DATE_RELATIVE,
|
||||
IAUTHOR_TIMESTAMP, IAUTHOR_ISO8601,
|
||||
ICOMMITTER_NAME, ICOMMITTER_EMAIL,
|
||||
ICOMMITTER_DATE, ICOMMITTER_DATE_RFC2822,
|
||||
ICOMMITTER_DATE_RELATIVE, ICOMMITTER_TIMESTAMP,
|
||||
ICOMMITTER_ISO8601,
|
||||
IENCODING,
|
||||
ISUBJECT,
|
||||
IBODY,
|
||||
IRED, IGREEN, IBLUE, IRESET_COLOR,
|
||||
INEWLINE,
|
||||
ILEFT_RIGHT,
|
||||
};
|
||||
struct commit_list *p;
|
||||
char parents[1024];
|
||||
unsigned long len;
|
||||
int i;
|
||||
enum { HEADER, SUBJECT, BODY } state;
|
||||
const char *msg = commit->buffer;
|
||||
|
||||
if (ILEFT_RIGHT + 1 != ARRAY_SIZE(table))
|
||||
die("invalid interp table!");
|
||||
|
||||
/* these are independent of the commit */
|
||||
interp_set_entry(table, IRED, "\033[31m");
|
||||
interp_set_entry(table, IGREEN, "\033[32m");
|
||||
interp_set_entry(table, IBLUE, "\033[34m");
|
||||
interp_set_entry(table, IRESET_COLOR, "\033[m");
|
||||
interp_set_entry(table, INEWLINE, "\n");
|
||||
|
||||
/* these depend on the commit */
|
||||
if (!commit->object.parsed)
|
||||
parse_object(commit->object.sha1);
|
||||
interp_set_entry(table, IHASH, sha1_to_hex(commit->object.sha1));
|
||||
interp_set_entry(table, IHASH_ABBREV,
|
||||
find_unique_abbrev(commit->object.sha1,
|
||||
DEFAULT_ABBREV));
|
||||
interp_set_entry(table, ITREE, sha1_to_hex(commit->tree->object.sha1));
|
||||
interp_set_entry(table, ITREE_ABBREV,
|
||||
find_unique_abbrev(commit->tree->object.sha1,
|
||||
DEFAULT_ABBREV));
|
||||
interp_set_entry(table, ILEFT_RIGHT,
|
||||
(commit->object.flags & BOUNDARY)
|
||||
? "-"
|
||||
: (commit->object.flags & SYMMETRIC_LEFT)
|
||||
? "<"
|
||||
: ">");
|
||||
|
||||
parents[1] = 0;
|
||||
for (i = 0, p = commit->parents;
|
||||
p && i < sizeof(parents) - 1;
|
||||
p = p->next)
|
||||
i += snprintf(parents + i, sizeof(parents) - i - 1, " %s",
|
||||
sha1_to_hex(p->item->object.sha1));
|
||||
interp_set_entry(table, IPARENTS, parents + 1);
|
||||
|
||||
parents[1] = 0;
|
||||
for (i = 0, p = commit->parents;
|
||||
p && i < sizeof(parents) - 1;
|
||||
p = p->next)
|
||||
i += snprintf(parents + i, sizeof(parents) - i - 1, " %s",
|
||||
find_unique_abbrev(p->item->object.sha1,
|
||||
DEFAULT_ABBREV));
|
||||
interp_set_entry(table, IPARENTS_ABBREV, parents + 1);
|
||||
|
||||
for (i = 0, state = HEADER; msg[i] && state < BODY; i++) {
|
||||
int eol;
|
||||
for (eol = i; msg[eol] && msg[eol] != '\n'; eol++)
|
||||
; /* do nothing */
|
||||
|
||||
if (state == SUBJECT) {
|
||||
table[ISUBJECT].value = xmemdupz(msg + i, eol - i);
|
||||
i = eol;
|
||||
}
|
||||
if (i == eol) {
|
||||
state++;
|
||||
/* strip empty lines */
|
||||
while (msg[eol + 1] == '\n')
|
||||
eol++;
|
||||
} else if (!prefixcmp(msg + i, "author "))
|
||||
fill_person(table + IAUTHOR_NAME,
|
||||
msg + i + 7, eol - i - 7);
|
||||
else if (!prefixcmp(msg + i, "committer "))
|
||||
fill_person(table + ICOMMITTER_NAME,
|
||||
msg + i + 10, eol - i - 10);
|
||||
else if (!prefixcmp(msg + i, "encoding "))
|
||||
table[IENCODING].value =
|
||||
xmemdupz(msg + i + 9, eol - i - 9);
|
||||
i = eol;
|
||||
}
|
||||
if (msg[i])
|
||||
table[IBODY].value = xstrdup(msg + i);
|
||||
|
||||
len = interpolate(sb->buf + sb->len, strbuf_avail(sb),
|
||||
format, table, ARRAY_SIZE(table));
|
||||
if (len > strbuf_avail(sb)) {
|
||||
strbuf_grow(sb, len);
|
||||
interpolate(sb->buf + sb->len, strbuf_avail(sb) + 1,
|
||||
format, table, ARRAY_SIZE(table));
|
||||
}
|
||||
strbuf_setlen(sb, sb->len + len);
|
||||
interp_clear_table(table, ARRAY_SIZE(table));
|
||||
}
|
||||
|
||||
static void pp_header(enum cmit_fmt fmt,
|
||||
int abbrev,
|
||||
enum date_mode dmode,
|
||||
const char *encoding,
|
||||
const struct commit *commit,
|
||||
const char **msg_p,
|
||||
struct strbuf *sb)
|
||||
{
|
||||
int parents_shown = 0;
|
||||
|
||||
for (;;) {
|
||||
const char *line = *msg_p;
|
||||
int linelen = get_one_line(*msg_p);
|
||||
|
||||
if (!linelen)
|
||||
return;
|
||||
*msg_p += linelen;
|
||||
|
||||
if (linelen == 1)
|
||||
/* End of header */
|
||||
return;
|
||||
|
||||
if (fmt == CMIT_FMT_RAW) {
|
||||
strbuf_add(sb, line, linelen);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!memcmp(line, "parent ", 7)) {
|
||||
if (linelen != 48)
|
||||
die("bad parent line in commit");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!parents_shown) {
|
||||
struct commit_list *parent;
|
||||
int num;
|
||||
for (parent = commit->parents, num = 0;
|
||||
parent;
|
||||
parent = parent->next, num++)
|
||||
;
|
||||
/* with enough slop */
|
||||
strbuf_grow(sb, num * 50 + 20);
|
||||
add_merge_info(fmt, sb, commit, abbrev);
|
||||
parents_shown = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* MEDIUM == DEFAULT shows only author with dates.
|
||||
* FULL shows both authors but not dates.
|
||||
* FULLER shows both authors and dates.
|
||||
*/
|
||||
if (!memcmp(line, "author ", 7)) {
|
||||
strbuf_grow(sb, linelen + 80);
|
||||
add_user_info("Author", fmt, sb, line + 7, dmode, encoding);
|
||||
}
|
||||
if (!memcmp(line, "committer ", 10) &&
|
||||
(fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) {
|
||||
strbuf_grow(sb, linelen + 80);
|
||||
add_user_info("Commit", fmt, sb, line + 10, dmode, encoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pp_title_line(enum cmit_fmt fmt,
|
||||
const char **msg_p,
|
||||
struct strbuf *sb,
|
||||
const char *subject,
|
||||
const char *after_subject,
|
||||
const char *encoding,
|
||||
int plain_non_ascii)
|
||||
{
|
||||
struct strbuf title;
|
||||
|
||||
strbuf_init(&title, 80);
|
||||
|
||||
for (;;) {
|
||||
const char *line = *msg_p;
|
||||
int linelen = get_one_line(line);
|
||||
|
||||
*msg_p += linelen;
|
||||
if (!linelen || is_empty_line(line, &linelen))
|
||||
break;
|
||||
|
||||
strbuf_grow(&title, linelen + 2);
|
||||
if (title.len) {
|
||||
if (fmt == CMIT_FMT_EMAIL) {
|
||||
strbuf_addch(&title, '\n');
|
||||
}
|
||||
strbuf_addch(&title, ' ');
|
||||
}
|
||||
strbuf_add(&title, line, linelen);
|
||||
}
|
||||
|
||||
strbuf_grow(sb, title.len + 1024);
|
||||
if (subject) {
|
||||
strbuf_addstr(sb, subject);
|
||||
add_rfc2047(sb, title.buf, title.len, encoding);
|
||||
} else {
|
||||
strbuf_addbuf(sb, &title);
|
||||
}
|
||||
strbuf_addch(sb, '\n');
|
||||
|
||||
if (plain_non_ascii) {
|
||||
const char *header_fmt =
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=%s\n"
|
||||
"Content-Transfer-Encoding: 8bit\n";
|
||||
strbuf_addf(sb, header_fmt, encoding);
|
||||
}
|
||||
if (after_subject) {
|
||||
strbuf_addstr(sb, after_subject);
|
||||
}
|
||||
if (fmt == CMIT_FMT_EMAIL) {
|
||||
strbuf_addch(sb, '\n');
|
||||
}
|
||||
strbuf_release(&title);
|
||||
}
|
||||
|
||||
static void pp_remainder(enum cmit_fmt fmt,
|
||||
const char **msg_p,
|
||||
struct strbuf *sb,
|
||||
int indent)
|
||||
{
|
||||
int first = 1;
|
||||
for (;;) {
|
||||
const char *line = *msg_p;
|
||||
int linelen = get_one_line(line);
|
||||
*msg_p += linelen;
|
||||
|
||||
if (!linelen)
|
||||
break;
|
||||
|
||||
if (is_empty_line(line, &linelen)) {
|
||||
if (first)
|
||||
continue;
|
||||
if (fmt == CMIT_FMT_SHORT)
|
||||
break;
|
||||
}
|
||||
first = 0;
|
||||
|
||||
strbuf_grow(sb, linelen + indent + 20);
|
||||
if (indent) {
|
||||
memset(sb->buf + sb->len, ' ', indent);
|
||||
strbuf_setlen(sb, sb->len + indent);
|
||||
}
|
||||
strbuf_add(sb, line, linelen);
|
||||
strbuf_addch(sb, '\n');
|
||||
}
|
||||
}
|
||||
|
||||
void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
|
||||
struct strbuf *sb, int abbrev,
|
||||
const char *subject, const char *after_subject,
|
||||
enum date_mode dmode)
|
||||
{
|
||||
unsigned long beginning_of_body;
|
||||
int indent = 4;
|
||||
const char *msg = commit->buffer;
|
||||
int plain_non_ascii = 0;
|
||||
char *reencoded;
|
||||
const char *encoding;
|
||||
|
||||
if (fmt == CMIT_FMT_USERFORMAT) {
|
||||
format_commit_message(commit, user_format, sb);
|
||||
return;
|
||||
}
|
||||
|
||||
encoding = (git_log_output_encoding
|
||||
? git_log_output_encoding
|
||||
: git_commit_encoding);
|
||||
if (!encoding)
|
||||
encoding = "utf-8";
|
||||
reencoded = logmsg_reencode(commit, encoding);
|
||||
if (reencoded) {
|
||||
msg = reencoded;
|
||||
}
|
||||
|
||||
if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
|
||||
indent = 0;
|
||||
|
||||
/* After-subject is used to pass in Content-Type: multipart
|
||||
* MIME header; in that case we do not have to do the
|
||||
* plaintext content type even if the commit message has
|
||||
* non 7-bit ASCII character. Otherwise, check if we need
|
||||
* to say this is not a 7-bit ASCII.
|
||||
*/
|
||||
if (fmt == CMIT_FMT_EMAIL && !after_subject) {
|
||||
int i, ch, in_body;
|
||||
|
||||
for (in_body = i = 0; (ch = msg[i]); i++) {
|
||||
if (!in_body) {
|
||||
/* author could be non 7-bit ASCII but
|
||||
* the log may be so; skip over the
|
||||
* header part first.
|
||||
*/
|
||||
if (ch == '\n' && msg[i+1] == '\n')
|
||||
in_body = 1;
|
||||
}
|
||||
else if (non_ascii(ch)) {
|
||||
plain_non_ascii = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pp_header(fmt, abbrev, dmode, encoding, commit, &msg, sb);
|
||||
if (fmt != CMIT_FMT_ONELINE && !subject) {
|
||||
strbuf_addch(sb, '\n');
|
||||
}
|
||||
|
||||
/* Skip excess blank lines at the beginning of body, if any... */
|
||||
for (;;) {
|
||||
int linelen = get_one_line(msg);
|
||||
int ll = linelen;
|
||||
if (!linelen)
|
||||
break;
|
||||
if (!is_empty_line(msg, &ll))
|
||||
break;
|
||||
msg += linelen;
|
||||
}
|
||||
|
||||
/* These formats treat the title line specially. */
|
||||
if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
|
||||
pp_title_line(fmt, &msg, sb, subject,
|
||||
after_subject, encoding, plain_non_ascii);
|
||||
|
||||
beginning_of_body = sb->len;
|
||||
if (fmt != CMIT_FMT_ONELINE)
|
||||
pp_remainder(fmt, &msg, sb, indent);
|
||||
strbuf_rtrim(sb);
|
||||
|
||||
/* Make sure there is an EOLN for the non-oneline case */
|
||||
if (fmt != CMIT_FMT_ONELINE)
|
||||
strbuf_addch(sb, '\n');
|
||||
|
||||
/*
|
||||
* The caller may append additional body text in e-mail
|
||||
* format. Make sure we did not strip the blank line
|
||||
* between the header and the body.
|
||||
*/
|
||||
if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
|
||||
strbuf_addch(sb, '\n');
|
||||
free(reencoded);
|
||||
}
|
||||
|
||||
struct commit *pop_commit(struct commit_list **stack)
|
||||
{
|
||||
struct commit_list *top = *stack;
|
||||
|
|
4
commit.h
4
commit.h
|
@ -61,13 +61,15 @@ enum cmit_fmt {
|
|||
CMIT_FMT_UNSPECIFIED,
|
||||
};
|
||||
|
||||
extern int non_ascii(int);
|
||||
extern enum cmit_fmt get_commit_format(const char *arg);
|
||||
extern void format_commit_message(const struct commit *commit,
|
||||
const void *format, struct strbuf *sb);
|
||||
extern void pretty_print_commit(enum cmit_fmt fmt, const struct commit*,
|
||||
struct strbuf *,
|
||||
int abbrev, const char *subject,
|
||||
const char *after_subject, enum date_mode);
|
||||
const char *after_subject, enum date_mode,
|
||||
int non_ascii_present);
|
||||
|
||||
/** Removes the first commit from a list sorted by date, and adds all
|
||||
* of its parents.
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
|
|
|
@ -38,3 +38,4 @@ NO_STRCASESTR=@NO_STRCASESTR@
|
|||
NO_STRLCPY=@NO_STRLCPY@
|
||||
NO_SETENV=@NO_SETENV@
|
||||
NO_ICONV=@NO_ICONV@
|
||||
NO_DEFLATE_BOUND=@NO_DEFLATE_BOUND@
|
||||
|
|
26
configure.ac
26
configure.ac
|
@ -73,7 +73,7 @@ fi \
|
|||
AC_ARG_WITH([lib],
|
||||
[AS_HELP_STRING([--with-lib=ARG],
|
||||
[ARG specifies alternative name for lib directory])],
|
||||
[if test "$withval" = "no" -o "$withval" = "yes"; then \
|
||||
[if test "$withval" = "no" || test "$withval" = "yes"; then \
|
||||
AC_MSG_WARN([You should provide name for --with-lib=ARG]); \
|
||||
else \
|
||||
GIT_CONF_APPEND_LINE(lib=$withval); \
|
||||
|
@ -182,6 +182,26 @@ AC_SUBST(NEEDS_LIBICONV)
|
|||
AC_SUBST(NO_ICONV)
|
||||
test -n "$NEEDS_LIBICONV" && LIBS="$LIBS -liconv"
|
||||
#
|
||||
# Define NO_DEFLATE_BOUND if deflateBound is missing from zlib.
|
||||
AC_DEFUN([ZLIBTEST_SRC], [
|
||||
#include <zlib.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
deflateBound(0, 0);
|
||||
return 0;
|
||||
}
|
||||
])
|
||||
AC_MSG_CHECKING([for deflateBound in -lz])
|
||||
old_LIBS="$LIBS"
|
||||
LIBS="$LIBS -lz"
|
||||
AC_LINK_IFELSE(ZLIBTEST_SRC,
|
||||
[AC_MSG_RESULT([yes])],
|
||||
[AC_MSG_RESULT([no])
|
||||
NO_DEFLATE_BOUND=yes])
|
||||
LIBS="$old_LIBS"
|
||||
AC_SUBST(NO_DEFLATE_BOUND)
|
||||
#
|
||||
# Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
|
||||
# Patrick Mauritz).
|
||||
AC_CHECK_LIB([c], [socket],
|
||||
|
@ -245,9 +265,9 @@ AC_RUN_IFELSE(
|
|||
[AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
|
||||
[[char buf[64];
|
||||
if (sprintf(buf, "%lld%hhd%jd%zd%td", (long long int)1, (char)2, (intmax_t)3, (size_t)4, (ptrdiff_t)5) != 5)
|
||||
exit(1);
|
||||
return 1;
|
||||
else if (strcmp(buf, "12345"))
|
||||
exit(2);]])],
|
||||
return 2;]])],
|
||||
[ac_cv_c_c99_format=yes],
|
||||
[ac_cv_c_c99_format=no])
|
||||
])
|
||||
|
|
|
@ -71,6 +71,79 @@ def isP4Exec(kind):
|
|||
a plus sign, it is also executable"""
|
||||
return (re.search(r"(^[cku]?x)|\+.*x", kind) != None)
|
||||
|
||||
def setP4ExecBit(file, mode):
|
||||
# Reopens an already open file and changes the execute bit to match
|
||||
# the execute bit setting in the passed in mode.
|
||||
|
||||
p4Type = "+x"
|
||||
|
||||
if not isModeExec(mode):
|
||||
p4Type = getP4OpenedType(file)
|
||||
p4Type = re.sub('^([cku]?)x(.*)', '\\1\\2', p4Type)
|
||||
p4Type = re.sub('(.*?\+.*?)x(.*?)', '\\1\\2', p4Type)
|
||||
if p4Type[-1] == "+":
|
||||
p4Type = p4Type[0:-1]
|
||||
|
||||
system("p4 reopen -t %s %s" % (p4Type, file))
|
||||
|
||||
def getP4OpenedType(file):
|
||||
# Returns the perforce file type for the given file.
|
||||
|
||||
result = read_pipe("p4 opened %s" % file)
|
||||
match = re.match(".*\((.+)\)$", result)
|
||||
if match:
|
||||
return match.group(1)
|
||||
else:
|
||||
die("Could not determine file type for %s" % file)
|
||||
|
||||
def diffTreePattern():
|
||||
# This is a simple generator for the diff tree regex pattern. This could be
|
||||
# a class variable if this and parseDiffTreeEntry were a part of a class.
|
||||
pattern = re.compile(':(\d+) (\d+) (\w+) (\w+) ([A-Z])(\d+)?\t(.*?)((\t(.*))|$)')
|
||||
while True:
|
||||
yield pattern
|
||||
|
||||
def parseDiffTreeEntry(entry):
|
||||
"""Parses a single diff tree entry into its component elements.
|
||||
|
||||
See git-diff-tree(1) manpage for details about the format of the diff
|
||||
output. This method returns a dictionary with the following elements:
|
||||
|
||||
src_mode - The mode of the source file
|
||||
dst_mode - The mode of the destination file
|
||||
src_sha1 - The sha1 for the source file
|
||||
dst_sha1 - The sha1 fr the destination file
|
||||
status - The one letter status of the diff (i.e. 'A', 'M', 'D', etc)
|
||||
status_score - The score for the status (applicable for 'C' and 'R'
|
||||
statuses). This is None if there is no score.
|
||||
src - The path for the source file.
|
||||
dst - The path for the destination file. This is only present for
|
||||
copy or renames. If it is not present, this is None.
|
||||
|
||||
If the pattern is not matched, None is returned."""
|
||||
|
||||
match = diffTreePattern().next().match(entry)
|
||||
if match:
|
||||
return {
|
||||
'src_mode': match.group(1),
|
||||
'dst_mode': match.group(2),
|
||||
'src_sha1': match.group(3),
|
||||
'dst_sha1': match.group(4),
|
||||
'status': match.group(5),
|
||||
'status_score': match.group(6),
|
||||
'src': match.group(7),
|
||||
'dst': match.group(10)
|
||||
}
|
||||
return None
|
||||
|
||||
def isModeExec(mode):
|
||||
# Returns True if the given git mode represents an executable file,
|
||||
# otherwise False.
|
||||
return mode[-3:] == "755"
|
||||
|
||||
def isModeExecChanged(src_mode, dst_mode):
|
||||
return isModeExec(src_mode) != isModeExec(dst_mode)
|
||||
|
||||
def p4CmdList(cmd, stdin=None, stdin_mode='w+b'):
|
||||
cmd = "p4 -G %s" % cmd
|
||||
if verbose:
|
||||
|
@ -494,18 +567,23 @@ class P4Submit(Command):
|
|||
else:
|
||||
print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id))
|
||||
diffOpts = ("", "-M")[self.detectRename]
|
||||
diff = read_pipe_lines("git diff-tree -r --name-status %s \"%s^\" \"%s\"" % (diffOpts, id, id))
|
||||
diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (diffOpts, id, id))
|
||||
filesToAdd = set()
|
||||
filesToDelete = set()
|
||||
editedFiles = set()
|
||||
filesToChangeExecBit = {}
|
||||
for line in diff:
|
||||
modifier = line[0]
|
||||
path = line[1:].strip()
|
||||
diff = parseDiffTreeEntry(line)
|
||||
modifier = diff['status']
|
||||
path = diff['src']
|
||||
if modifier == "M":
|
||||
system("p4 edit \"%s\"" % path)
|
||||
if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
|
||||
filesToChangeExecBit[path] = diff['dst_mode']
|
||||
editedFiles.add(path)
|
||||
elif modifier == "A":
|
||||
filesToAdd.add(path)
|
||||
filesToChangeExecBit[path] = diff['dst_mode']
|
||||
if path in filesToDelete:
|
||||
filesToDelete.remove(path)
|
||||
elif modifier == "D":
|
||||
|
@ -513,9 +591,11 @@ class P4Submit(Command):
|
|||
if path in filesToAdd:
|
||||
filesToAdd.remove(path)
|
||||
elif modifier == "R":
|
||||
src, dest = line.strip().split("\t")[1:3]
|
||||
src, dest = diff['src'], diff['dst']
|
||||
system("p4 integrate -Dt \"%s\" \"%s\"" % (src, dest))
|
||||
system("p4 edit \"%s\"" % (dest))
|
||||
if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
|
||||
filesToChangeExecBit[dest] = diff['dst_mode']
|
||||
os.unlink(dest)
|
||||
editedFiles.add(dest)
|
||||
filesToDelete.add(src)
|
||||
|
@ -568,6 +648,11 @@ class P4Submit(Command):
|
|||
system("p4 revert \"%s\"" % f)
|
||||
system("p4 delete \"%s\"" % f)
|
||||
|
||||
# Set/clear executable bits
|
||||
for f in filesToChangeExecBit.keys():
|
||||
mode = filesToChangeExecBit[f]
|
||||
setP4ExecBit(f, mode)
|
||||
|
||||
logMessage = ""
|
||||
if not self.directSubmit:
|
||||
logMessage = extractLogMessageFromGitCommit(id)
|
||||
|
|
|
@ -2,24 +2,26 @@
|
|||
#
|
||||
# Copyright (c) 2007 Andy Parkins
|
||||
#
|
||||
# An example hook script to mail out commit update information. This hook sends emails
|
||||
# listing new revisions to the repository introduced by the change being reported. The
|
||||
# rule is that (for branch updates) each commit will appear on one email and one email
|
||||
# only.
|
||||
# An example hook script to mail out commit update information. This hook
|
||||
# sends emails listing new revisions to the repository introduced by the
|
||||
# change being reported. The rule is that (for branch updates) each commit
|
||||
# will appear on one email and one email only.
|
||||
#
|
||||
# This hook is stored in the contrib/hooks directory. Your distribution will have put
|
||||
# this somewhere standard. You should make this script executable then link to it in
|
||||
# the repository you would like to use it in. For example, on debian the hook is stored
|
||||
# in /usr/share/doc/git-core/contrib/hooks/post-receive-email:
|
||||
# This hook is stored in the contrib/hooks directory. Your distribution
|
||||
# will have put this somewhere standard. You should make this script
|
||||
# executable then link to it in the repository you would like to use it in.
|
||||
# For example, on debian the hook is stored in
|
||||
# /usr/share/doc/git-core/contrib/hooks/post-receive-email:
|
||||
#
|
||||
# chmod a+x post-receive-email
|
||||
# cd /path/to/your/repository.git
|
||||
# ln -sf /usr/share/doc/git-core/contrib/hooks/post-receive-email hooks/post-receive
|
||||
#
|
||||
# This hook script assumes it is enabled on the central repository of a project, with
|
||||
# all users pushing only to it and not between each other. It will still work if you
|
||||
# don't operate in that style, but it would become possible for the email to be from
|
||||
# someone other than the person doing the push.
|
||||
# This hook script assumes it is enabled on the central repository of a
|
||||
# project, with all users pushing only to it and not between each other. It
|
||||
# will still work if you don't operate in that style, but it would become
|
||||
# possible for the email to be from someone other than the person doing the
|
||||
# push.
|
||||
#
|
||||
# Config
|
||||
# ------
|
||||
|
@ -28,15 +30,17 @@
|
|||
# emails for every ref update.
|
||||
# hooks.announcelist
|
||||
# This is the list that all pushes of annotated tags will go to. Leave it
|
||||
# blank to default to the mailinglist field. The announce emails lists the
|
||||
# short log summary of the changes since the last annotated tag.
|
||||
# hook.envelopesender
|
||||
# If set then the -f option is passed to sendmail to allow the envelope sender
|
||||
# address to be set
|
||||
# blank to default to the mailinglist field. The announce emails lists
|
||||
# the short log summary of the changes since the last annotated tag.
|
||||
# hooks.envelopesender
|
||||
# If set then the -f option is passed to sendmail to allow the envelope
|
||||
# sender address to be set
|
||||
# hooks.emailprefix
|
||||
# All emails have their subjects prefixed with this prefix, or "[SCM]"
|
||||
# if emailprefix is unset, to aid filtering
|
||||
#
|
||||
# Notes
|
||||
# -----
|
||||
# All emails have their subjects prefixed with "[SCM]" to aid filtering.
|
||||
# All emails include the headers "X-Git-Refname", "X-Git-Oldrev",
|
||||
# "X-Git-Newrev", and "X-Git-Reftype" to enable fine tuned filtering and
|
||||
# give information for debugging.
|
||||
|
@ -49,8 +53,8 @@
|
|||
# this is and calls the appropriate body-generation routine after outputting
|
||||
# the common header
|
||||
#
|
||||
# Note this function doesn't actually generate any email output, that is taken
|
||||
# care of by the functions it calls:
|
||||
# Note this function doesn't actually generate any email output, that is
|
||||
# taken care of by the functions it calls:
|
||||
# - generate_email_header
|
||||
# - generate_create_XXXX_email
|
||||
# - generate_update_XXXX_email
|
||||
|
@ -152,10 +156,6 @@ generate_email()
|
|||
fi
|
||||
|
||||
# Email parameters
|
||||
# The committer will be obtained from the latest existing rev; so
|
||||
# for a deletion it will be the oldrev, for the others, then newrev
|
||||
committer=$(git show --pretty=full -s $rev | sed -ne "s/^Commit: //p" |
|
||||
sed -ne 's/\(.*\) </"\1" </p')
|
||||
# The email subject will contain the best description of the ref
|
||||
# that we can build from the parameters
|
||||
describe=$(git describe $rev 2>/dev/null)
|
||||
|
@ -186,7 +186,7 @@ generate_email_header()
|
|||
# Generate header
|
||||
cat <<-EOF
|
||||
To: $recipients
|
||||
Subject: ${EMAILPREFIX}$projectdesc $refname_type, $short_refname, ${change_type}d. $describe
|
||||
Subject: ${emailprefix}$projectdesc $refname_type, $short_refname, ${change_type}d. $describe
|
||||
X-Git-Refname: $refname
|
||||
X-Git-Reftype: $refname_type
|
||||
X-Git-Oldrev: $oldrev
|
||||
|
@ -225,8 +225,9 @@ generate_create_branch_email()
|
|||
echo $LOGBEGIN
|
||||
# This shows all log entries that are not already covered by
|
||||
# another ref - i.e. commits that are now accessible from this
|
||||
# ref that were previously not accessible (see generate_update_branch_email
|
||||
# for the explanation of this command)
|
||||
# ref that were previously not accessible
|
||||
# (see generate_update_branch_email for the explanation of this
|
||||
# command)
|
||||
git rev-parse --not --branches | grep -v $(git rev-parse $refname) |
|
||||
git rev-list --pretty --stdin $newrev
|
||||
echo $LOGEND
|
||||
|
@ -254,9 +255,10 @@ generate_update_branch_email()
|
|||
#
|
||||
# git-rev-list N ^O ^X ^N
|
||||
#
|
||||
# So, we need to build up the list more carefully. git-rev-parse will
|
||||
# generate a list of revs that may be fed into git-rev-list. We can get
|
||||
# it to make the "--not --all" part and then filter out the "^N" with:
|
||||
# So, we need to build up the list more carefully. git-rev-parse
|
||||
# will generate a list of revs that may be fed into git-rev-list.
|
||||
# We can get it to make the "--not --all" part and then filter out
|
||||
# the "^N" with:
|
||||
#
|
||||
# git-rev-parse --not --all | grep -v N
|
||||
#
|
||||
|
@ -266,16 +268,17 @@ generate_update_branch_email()
|
|||
# git-rev-list N ^O ^X
|
||||
#
|
||||
# This leaves a problem when someone else updates the repository
|
||||
# while this script is running. Their new value of the ref we're working
|
||||
# on would be included in the "--not --all" output; and as our $newrev
|
||||
# would be an ancestor of that commit, it would exclude all of our
|
||||
# commits. What we really want is to exclude the current value of
|
||||
# $refname from the --not list, rather than N itself. So:
|
||||
# while this script is running. Their new value of the ref we're
|
||||
# working on would be included in the "--not --all" output; and as
|
||||
# our $newrev would be an ancestor of that commit, it would exclude
|
||||
# all of our commits. What we really want is to exclude the current
|
||||
# value of $refname from the --not list, rather than N itself. So:
|
||||
#
|
||||
# git-rev-parse --not --all | grep -v $(git-rev-parse $refname)
|
||||
#
|
||||
# Get's us to something pretty safe (apart from the small time between
|
||||
# refname being read, and git-rev-parse running - for that, I give up)
|
||||
# Get's us to something pretty safe (apart from the small time
|
||||
# between refname being read, and git-rev-parse running - for that,
|
||||
# I give up)
|
||||
#
|
||||
#
|
||||
# Next problem, consider this:
|
||||
|
@ -283,18 +286,18 @@ generate_update_branch_email()
|
|||
# \
|
||||
# * --- X --- * --- N ($newrev)
|
||||
#
|
||||
# That is to say, there is no guarantee that oldrev is a strict subset of
|
||||
# newrev (it would have required a --force, but that's allowed). So, we
|
||||
# can't simply say rev-list $oldrev..$newrev. Instead we find the common
|
||||
# base of the two revs and list from there.
|
||||
# That is to say, there is no guarantee that oldrev is a strict
|
||||
# subset of newrev (it would have required a --force, but that's
|
||||
# allowed). So, we can't simply say rev-list $oldrev..$newrev.
|
||||
# Instead we find the common base of the two revs and list from
|
||||
# there.
|
||||
#
|
||||
# As above, we need to take into account the presence of X; if another
|
||||
# branch is already in the repository and points at some of the revisions
|
||||
# that we are about to output - we don't want them. The solution is as
|
||||
# before: git-rev-parse output filtered.
|
||||
# As above, we need to take into account the presence of X; if
|
||||
# another branch is already in the repository and points at some of
|
||||
# the revisions that we are about to output - we don't want them.
|
||||
# The solution is as before: git-rev-parse output filtered.
|
||||
#
|
||||
# Finally, tags:
|
||||
# 1 --- 2 --- O --- T --- 3 --- 4 --- N
|
||||
# Finally, tags: 1 --- 2 --- O --- T --- 3 --- 4 --- N
|
||||
#
|
||||
# Tags pushed into the repository generate nice shortlog emails that
|
||||
# summarise the commits between them and the previous tag. However,
|
||||
|
@ -302,13 +305,14 @@ generate_update_branch_email()
|
|||
# for a branch update. Therefore we still want to output revisions
|
||||
# that have been output on a tag email.
|
||||
#
|
||||
# Luckily, git-rev-parse includes just the tool. Instead of using "--all"
|
||||
# we use "--branches"; this has the added benefit that "remotes/" will
|
||||
# be ignored as well.
|
||||
# Luckily, git-rev-parse includes just the tool. Instead of using
|
||||
# "--all" we use "--branches"; this has the added benefit that
|
||||
# "remotes/" will be ignored as well.
|
||||
|
||||
# List all of the revisions that were removed by this update, in a fast forward
|
||||
# update, this list will be empty, because rev-list O ^N is empty. For a non
|
||||
# fast forward, O ^N is the list of removed revisions
|
||||
# List all of the revisions that were removed by this update, in a
|
||||
# fast forward update, this list will be empty, because rev-list O
|
||||
# ^N is empty. For a non fast forward, O ^N is the list of removed
|
||||
# revisions
|
||||
fast_forward=""
|
||||
rev=""
|
||||
for rev in $(git rev-list $newrev..$oldrev)
|
||||
|
@ -321,10 +325,10 @@ generate_update_branch_email()
|
|||
fi
|
||||
|
||||
# List all the revisions from baserev to newrev in a kind of
|
||||
# "table-of-contents"; note this list can include revisions that have
|
||||
# already had notification emails and is present to show the full detail
|
||||
# of the change from rolling back the old revision to the base revision and
|
||||
# then forward to the new revision
|
||||
# "table-of-contents"; note this list can include revisions that
|
||||
# have already had notification emails and is present to show the
|
||||
# full detail of the change from rolling back the old revision to
|
||||
# the base revision and then forward to the new revision
|
||||
for rev in $(git rev-list $oldrev..$newrev)
|
||||
do
|
||||
revtype=$(git cat-file -t "$rev")
|
||||
|
@ -334,19 +338,20 @@ generate_update_branch_email()
|
|||
if [ "$fast_forward" ]; then
|
||||
echo " from $oldrev ($oldrev_type)"
|
||||
else
|
||||
# 1. Existing revisions were removed. In this case newrev is a
|
||||
# subset of oldrev - this is the reverse of a fast-forward,
|
||||
# a rewind
|
||||
# 2. New revisions were added on top of an old revision, this is
|
||||
# a rewind and addition.
|
||||
# 1. Existing revisions were removed. In this case newrev
|
||||
# is a subset of oldrev - this is the reverse of a
|
||||
# fast-forward, a rewind
|
||||
# 2. New revisions were added on top of an old revision,
|
||||
# this is a rewind and addition.
|
||||
|
||||
# (1) certainly happened, (2) possibly. When (2) hasn't happened,
|
||||
# we set a flag to indicate that no log printout is required.
|
||||
# (1) certainly happened, (2) possibly. When (2) hasn't
|
||||
# happened, we set a flag to indicate that no log printout
|
||||
# is required.
|
||||
|
||||
echo ""
|
||||
|
||||
# Find the common ancestor of the old and new revisions and compare
|
||||
# it with newrev
|
||||
# Find the common ancestor of the old and new revisions and
|
||||
# compare it with newrev
|
||||
baserev=$(git merge-base $oldrev $newrev)
|
||||
rewind_only=""
|
||||
if [ "$baserev" = "$newrev" ]; then
|
||||
|
@ -387,21 +392,22 @@ generate_update_branch_email()
|
|||
git rev-parse --not --branches | grep -v $(git rev-parse $refname) |
|
||||
git rev-list --pretty --stdin $oldrev..$newrev
|
||||
|
||||
# XXX: Need a way of detecting whether git rev-list actually outputted
|
||||
# anything, so that we can issue a "no new revisions added by this
|
||||
# update" message
|
||||
# XXX: Need a way of detecting whether git rev-list actually
|
||||
# outputted anything, so that we can issue a "no new
|
||||
# revisions added by this update" message
|
||||
|
||||
echo $LOGEND
|
||||
else
|
||||
echo "No new revisions were added by this update."
|
||||
fi
|
||||
|
||||
# The diffstat is shown from the old revision to the new revision. This
|
||||
# is to show the truth of what happened in this change. There's no point
|
||||
# showing the stat from the base to the new revision because the base
|
||||
# is effectively a random revision at this point - the user will be
|
||||
# interested in what this revision changed - including the undoing of
|
||||
# previous revisions in the case of non-fast forward updates.
|
||||
# The diffstat is shown from the old revision to the new revision.
|
||||
# This is to show the truth of what happened in this change.
|
||||
# There's no point showing the stat from the base to the new
|
||||
# revision because the base is effectively a random revision at this
|
||||
# point - the user will be interested in what this revision changed
|
||||
# - including the undoing of previous revisions in the case of
|
||||
# non-fast forward updates.
|
||||
echo ""
|
||||
echo "Summary of changes:"
|
||||
git diff-tree --stat --summary --find-copies-harder $oldrev..$newrev
|
||||
|
@ -448,7 +454,8 @@ generate_update_atag_email()
|
|||
#
|
||||
generate_atag_email()
|
||||
{
|
||||
# Use git-for-each-ref to pull out the individual fields from the tag
|
||||
# Use git-for-each-ref to pull out the individual fields from the
|
||||
# tag
|
||||
eval $(git for-each-ref --shell --format='
|
||||
tagobject=%(*objectname)
|
||||
tagtype=%(*objecttype)
|
||||
|
@ -459,8 +466,10 @@ generate_atag_email()
|
|||
echo " tagging $tagobject ($tagtype)"
|
||||
case "$tagtype" in
|
||||
commit)
|
||||
|
||||
# If the tagged object is a commit, then we assume this is a
|
||||
# release, and so we calculate which tag this tag is replacing
|
||||
# release, and so we calculate which tag this tag is
|
||||
# replacing
|
||||
prevtag=$(git describe --abbrev=0 $newrev^ 2>/dev/null)
|
||||
|
||||
if [ -n "$prevtag" ]; then
|
||||
|
@ -477,25 +486,27 @@ generate_atag_email()
|
|||
echo ""
|
||||
echo $LOGBEGIN
|
||||
|
||||
# Show the content of the tag message; this might contain a change log
|
||||
# or release notes so is worth displaying.
|
||||
# Show the content of the tag message; this might contain a change
|
||||
# log or release notes so is worth displaying.
|
||||
git cat-file tag $newrev | sed -e '1,/^$/d'
|
||||
|
||||
echo ""
|
||||
case "$tagtype" in
|
||||
commit)
|
||||
# Only commit tags make sense to have rev-list operations performed
|
||||
# on them
|
||||
# Only commit tags make sense to have rev-list operations
|
||||
# performed on them
|
||||
if [ -n "$prevtag" ]; then
|
||||
# Show changes since the previous release
|
||||
git rev-list --pretty=short "$prevtag..$newrev" | git shortlog
|
||||
else
|
||||
# No previous tag, show all the changes since time began
|
||||
# No previous tag, show all the changes since time
|
||||
# began
|
||||
git rev-list --pretty=short $newrev | git shortlog
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# XXX: Is there anything useful we can do for non-commit objects?
|
||||
# XXX: Is there anything useful we can do for non-commit
|
||||
# objects?
|
||||
;;
|
||||
esac
|
||||
|
||||
|
@ -544,13 +555,14 @@ generate_update_general_email()
|
|||
#
|
||||
generate_general_email()
|
||||
{
|
||||
# Unannotated tags are more about marking a point than releasing a version;
|
||||
# therefore we don't do the shortlog summary that we do for annotated tags
|
||||
# above - we simply show that the point has been marked, and print the log
|
||||
# message for the marked point for reference purposes
|
||||
# Unannotated tags are more about marking a point than releasing a
|
||||
# version; therefore we don't do the shortlog summary that we do for
|
||||
# annotated tags above - we simply show that the point has been
|
||||
# marked, and print the log message for the marked point for
|
||||
# reference purposes
|
||||
#
|
||||
# Note this section also catches any other reference type (although there
|
||||
# aren't any) and deals with them in the same way.
|
||||
# Note this section also catches any other reference type (although
|
||||
# there aren't any) and deals with them in the same way.
|
||||
|
||||
echo ""
|
||||
if [ "$newrev_type" = "commit" ]; then
|
||||
|
@ -558,10 +570,10 @@ generate_general_email()
|
|||
git show --no-color --root -s $newrev
|
||||
echo $LOGEND
|
||||
else
|
||||
# What can we do here? The tag marks an object that is not a commit,
|
||||
# so there is no log for us to display. It's probably not wise to
|
||||
# output git-cat-file as it could be a binary blob. We'll just say how
|
||||
# big it is
|
||||
# What can we do here? The tag marks an object that is not
|
||||
# a commit, so there is no log for us to display. It's
|
||||
# probably not wise to output git-cat-file as it could be a
|
||||
# binary blob. We'll just say how big it is
|
||||
echo "$newrev is a $newrev_type, and is $(git cat-file -s $newrev) bytes long."
|
||||
fi
|
||||
}
|
||||
|
@ -590,7 +602,6 @@ send_mail()
|
|||
# ---------------------------- main()
|
||||
|
||||
# --- Constants
|
||||
EMAILPREFIX="[SCM] "
|
||||
LOGBEGIN="- Log -----------------------------------------------------------------"
|
||||
LOGEND="-----------------------------------------------------------------------"
|
||||
|
||||
|
@ -604,8 +615,8 @@ if [ -z "$GIT_DIR" ]; then
|
|||
fi
|
||||
|
||||
projectdesc=$(sed -ne '1p' "$GIT_DIR/description")
|
||||
# Check if the description is unchanged from it's default, and shorten it to a
|
||||
# more manageable length if it is
|
||||
# Check if the description is unchanged from it's default, and shorten it to
|
||||
# a more manageable length if it is
|
||||
if expr "$projectdesc" : "Unnamed repository.*$" >/dev/null
|
||||
then
|
||||
projectdesc="UNNAMED PROJECT"
|
||||
|
@ -614,13 +625,15 @@ fi
|
|||
recipients=$(git repo-config hooks.mailinglist)
|
||||
announcerecipients=$(git repo-config hooks.announcelist)
|
||||
envelopesender=$(git-repo-config hooks.envelopesender)
|
||||
emailprefix=$(git-repo-config hooks.emailprefix || echo '[SCM] ')
|
||||
|
||||
# --- Main loop
|
||||
# Allow dual mode: run from the command line just like the update hook, or if
|
||||
# no arguments are given then run as a hook script
|
||||
# Allow dual mode: run from the command line just like the update hook, or
|
||||
# if no arguments are given then run as a hook script
|
||||
if [ -n "$1" -a -n "$2" -a -n "$3" ]; then
|
||||
# Output to the terminal in command line mode - if someone wanted to
|
||||
# resend an email; they could redirect the output to sendmail themselves
|
||||
# resend an email; they could redirect the output to sendmail
|
||||
# themselves
|
||||
PAGER= generate_email $2 $3 $1
|
||||
else
|
||||
while read oldrev newrev refname
|
||||
|
|
10
daemon.c
10
daemon.c
|
@ -406,7 +406,8 @@ static struct daemon_service daemon_service[] = {
|
|||
{ "receive-pack", "receivepack", receive_pack, 0, 1 },
|
||||
};
|
||||
|
||||
static void enable_service(const char *name, int ena) {
|
||||
static void enable_service(const char *name, int ena)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(daemon_service); i++) {
|
||||
if (!strcmp(daemon_service[i].name, name)) {
|
||||
|
@ -417,7 +418,8 @@ static void enable_service(const char *name, int ena) {
|
|||
die("No such service %s", name);
|
||||
}
|
||||
|
||||
static void make_service_overridable(const char *name, int ena) {
|
||||
static void make_service_overridable(const char *name, int ena)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(daemon_service); i++) {
|
||||
if (!strcmp(daemon_service[i].name, name)) {
|
||||
|
@ -540,7 +542,7 @@ static int execute(struct sockaddr *addr)
|
|||
if (addr->sa_family == AF_INET) {
|
||||
struct sockaddr_in *sin_addr = (void *) addr;
|
||||
inet_ntop(addr->sa_family, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf));
|
||||
port = sin_addr->sin_port;
|
||||
port = ntohs(sin_addr->sin_port);
|
||||
#ifndef NO_IPV6
|
||||
} else if (addr && addr->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sin6_addr = (void *) addr;
|
||||
|
@ -550,7 +552,7 @@ static int execute(struct sockaddr *addr)
|
|||
inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(addrbuf) - 1);
|
||||
strcat(buf, "]");
|
||||
|
||||
port = sin6_addr->sin6_port;
|
||||
port = ntohs(sin6_addr->sin6_port);
|
||||
#endif
|
||||
}
|
||||
loginfo("Connection from %s:%d", addrbuf, port);
|
||||
|
|
3
dir.c
3
dir.c
|
@ -298,7 +298,8 @@ int excluded(struct dir_struct *dir, const char *pathname)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct dir_entry *dir_entry_new(const char *pathname, int len) {
|
||||
static struct dir_entry *dir_entry_new(const char *pathname, int len)
|
||||
{
|
||||
struct dir_entry *ent;
|
||||
|
||||
ent = xmalloc(sizeof(*ent) + len + 1);
|
||||
|
|
|
@ -275,7 +275,8 @@ exit_if_skipped_commits () {
|
|||
if expr "$_tried" : ".*[|].*" > /dev/null ; then
|
||||
echo "There are only 'skip'ped commit left to test."
|
||||
echo "The first bad commit could be any of:"
|
||||
echo "$_tried" | sed -e 's/[|]/\n/g'
|
||||
echo "$_tried" | sed -e 's/[|]/\
|
||||
/g'
|
||||
echo "We cannot bisect more!"
|
||||
exit 2
|
||||
fi
|
||||
|
|
|
@ -20,12 +20,16 @@ require_work_tree
|
|||
ignored=
|
||||
ignoredonly=
|
||||
cleandir=
|
||||
disabled="`git config --bool clean.requireForce`"
|
||||
rmf="rm -f --"
|
||||
rmrf="rm -rf --"
|
||||
rm_refuse="echo Not removing"
|
||||
echo1="echo"
|
||||
|
||||
# requireForce used to default to false but now it defaults to true.
|
||||
# IOW, lack of explicit "clean.requireForce = false" is taken as
|
||||
# "clean.requireForce = true".
|
||||
disabled=$(git config --bool clean.requireForce || echo true)
|
||||
|
||||
while test $# != 0
|
||||
do
|
||||
case "$1" in
|
||||
|
|
|
@ -14,7 +14,7 @@ die() {
|
|||
}
|
||||
|
||||
usage() {
|
||||
die "Usage: $0 [--template=<template_directory>] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [--depth <n>] [-n] <repo> [<dir>]"
|
||||
die "Usage: $0 [--template=<template_directory>] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [--depth <n>] [-n] [--] <repo> [<dir>]"
|
||||
}
|
||||
|
||||
get_repo_base() {
|
||||
|
@ -160,6 +160,9 @@ while
|
|||
*,--depth)
|
||||
shift
|
||||
depth="--depth=$1";;
|
||||
*,--)
|
||||
shift
|
||||
break ;;
|
||||
*,-*) usage ;;
|
||||
*) break ;;
|
||||
esac
|
||||
|
|
|
@ -381,4 +381,17 @@ static inline int strtoul_ui(char const *s, int base, unsigned int *result)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int strtol_i(char const *s, int base, int *result)
|
||||
{
|
||||
long ul;
|
||||
char *p;
|
||||
|
||||
errno = 0;
|
||||
ul = strtol(s, &p, base);
|
||||
if (errno || *p || p == s || (int) ul != ul)
|
||||
return -1;
|
||||
*result = ul;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -818,6 +818,7 @@ sub commit {
|
|||
$state = 4;
|
||||
} elsif ($state == 4 and s/^Branch:\s+//) {
|
||||
s/\s+$//;
|
||||
tr/_/\./ if ( $opt_u );
|
||||
s/[\/]/$opt_s/g;
|
||||
$branch = $_;
|
||||
$state = 5;
|
||||
|
|
|
@ -15,7 +15,7 @@ browser="`git config --get instaweb.browser`"
|
|||
port=`git config --get instaweb.port`
|
||||
module_path="`git config --get instaweb.modulepath`"
|
||||
|
||||
conf=$GIT_DIR/gitweb/httpd.conf
|
||||
conf="$GIT_DIR/gitweb/httpd.conf"
|
||||
|
||||
# Defaults:
|
||||
|
||||
|
@ -32,7 +32,7 @@ start_httpd () {
|
|||
httpd_only="`echo $httpd | cut -f1 -d' '`"
|
||||
if case "$httpd_only" in /*) : ;; *) which $httpd_only >/dev/null;; esac
|
||||
then
|
||||
$httpd $fqgitdir/gitweb/httpd.conf
|
||||
$httpd "$fqgitdir/gitweb/httpd.conf"
|
||||
else
|
||||
# many httpds are installed in /usr/sbin or /usr/local/sbin
|
||||
# these days and those are not in most users $PATHs
|
||||
|
@ -185,14 +185,14 @@ server.pid-file = "$fqgitdir/pid"
|
|||
cgi.assign = ( ".cgi" => "" )
|
||||
mimetype.assign = ( ".css" => "text/css" )
|
||||
EOF
|
||||
test "$local" = true && echo 'server.bind = "127.0.0.1"' >> "$conf"
|
||||
test x"$local" = xtrue && echo 'server.bind = "127.0.0.1"' >> "$conf"
|
||||
}
|
||||
|
||||
apache2_conf () {
|
||||
test -z "$module_path" && module_path=/usr/lib/apache2/modules
|
||||
mkdir -p "$GIT_DIR/gitweb/logs"
|
||||
bind=
|
||||
test "$local" = true && bind='127.0.0.1:'
|
||||
test x"$local" = xtrue && bind='127.0.0.1:'
|
||||
echo 'text/css css' > $fqgitdir/mime.types
|
||||
cat > "$conf" <<EOF
|
||||
ServerName "git-instaweb"
|
||||
|
@ -245,7 +245,7 @@ EOF
|
|||
}
|
||||
|
||||
script='
|
||||
s#^\(my\|our\) $projectroot =.*#\1 $projectroot = "'`dirname $fqgitdir`'";#
|
||||
s#^\(my\|our\) $projectroot =.*#\1 $projectroot = "'$(dirname "$fqgitdir")'";#
|
||||
s#\(my\|our\) $gitbin =.*#\1 $gitbin = "'$GIT_EXEC_PATH'";#
|
||||
s#\(my\|our\) $projects_list =.*#\1 $projects_list = $projectroot;#
|
||||
s#\(my\|our\) $git_temp =.*#\1 $git_temp = "'$fqgitdir/gitweb/tmp'";#'
|
||||
|
@ -265,8 +265,8 @@ gitweb_css () {
|
|||
EOFGITWEB
|
||||
}
|
||||
|
||||
gitweb_cgi $GIT_DIR/gitweb/gitweb.cgi
|
||||
gitweb_css $GIT_DIR/gitweb/gitweb.css
|
||||
gitweb_cgi "$GIT_DIR/gitweb/gitweb.cgi"
|
||||
gitweb_css "$GIT_DIR/gitweb/gitweb.css"
|
||||
|
||||
case "$httpd" in
|
||||
*lighttpd*)
|
||||
|
@ -285,6 +285,5 @@ webrick)
|
|||
esac
|
||||
|
||||
start_httpd
|
||||
test -z "$browser" && browser=echo
|
||||
url=http://127.0.0.1:$port
|
||||
$browser $url || echo $url
|
||||
"$browser" $url || echo $url
|
||||
|
|
|
@ -4,6 +4,8 @@ USAGE=''
|
|||
SUBDIRECTORY_OK='Yes'
|
||||
. git-sh-setup
|
||||
|
||||
echo "WARNING: '$0' is deprecated in favor of 'git fsck --lost-found'" >&2
|
||||
|
||||
if [ "$#" != "0" ]
|
||||
then
|
||||
usage
|
||||
|
|
|
@ -391,7 +391,7 @@ do
|
|||
-s|--strategy)
|
||||
case "$#,$1" in
|
||||
*,*=*)
|
||||
STRATEGY="-s `expr "z$1" : 'z-[^=]*=\(.*\)'`" ;;
|
||||
STRATEGY="-s "$(expr "z$1" : 'z-[^=]*=\(.*\)') ;;
|
||||
1,*)
|
||||
usage ;;
|
||||
*)
|
||||
|
|
|
@ -24,13 +24,13 @@ headrev=`git rev-parse --verify "$head"^0` || exit
|
|||
merge_base=`git merge-base $baserev $headrev` ||
|
||||
die "fatal: No commits in common between $base and $head"
|
||||
|
||||
url="`get_remote_url "$url"`"
|
||||
branch=`git peek-remote "$url" \
|
||||
url=$(get_remote_url "$url")
|
||||
branch=$(git peek-remote "$url" \
|
||||
| sed -n -e "/^$headrev refs.heads./{
|
||||
s/^.* refs.heads.//
|
||||
p
|
||||
q
|
||||
}"`
|
||||
}")
|
||||
if [ -z "$branch" ]; then
|
||||
echo "warn: No branch of $url is at:" >&2
|
||||
git log --max-count=1 --pretty='format:warn: %h: %s' $headrev >&2
|
||||
|
|
|
@ -88,8 +88,7 @@ sub usage {
|
|||
|
||||
--smtp-ssl If set, connects to the SMTP server using SSL.
|
||||
|
||||
--suppress-from Suppress sending emails to yourself if your address
|
||||
appears in a From: line. Defaults to off.
|
||||
--suppress-from Suppress sending emails to yourself. Defaults to off.
|
||||
|
||||
--thread Specify that the "In-Reply-To:" header should be set on all
|
||||
emails. Defaults to on.
|
||||
|
@ -353,7 +352,7 @@ sub expand_aliases {
|
|||
|
||||
if (!defined $initial_subject && $compose) {
|
||||
do {
|
||||
$_ = $term->readline("What subject should the emails start with? ",
|
||||
$_ = $term->readline("What subject should the initial email start with? ",
|
||||
$initial_subject);
|
||||
} while (!defined $_);
|
||||
$initial_subject = $_;
|
||||
|
@ -730,6 +729,7 @@ sub send_message
|
|||
if (/^(Signed-off-by|Cc): (.*)$/i && $signed_off_cc) {
|
||||
my $c = $2;
|
||||
chomp $c;
|
||||
next if ($c eq $sender and $suppress_from);
|
||||
push @cc, $c;
|
||||
printf("(sob) Adding cc: %s from line '%s'\n",
|
||||
$c, $_) unless $quiet;
|
||||
|
@ -745,6 +745,7 @@ sub send_message
|
|||
my $c = $_;
|
||||
$c =~ s/^\s*//g;
|
||||
$c =~ s/\n$//g;
|
||||
next if ($c eq $sender and $suppress_from);
|
||||
push @cc, $c;
|
||||
printf("(cc-cmd) Adding cc: %s from: '%s'\n",
|
||||
$c, $cc_cmd) unless $quiet;
|
||||
|
|
|
@ -73,7 +73,7 @@ resolve_relative_url ()
|
|||
module_name()
|
||||
{
|
||||
# Do we have "submodule.<something>.path = $1" defined in .gitmodules file?
|
||||
re=$(printf '%s' "$1" | sed -e 's/\([^a-zA-Z0-9_]\)/\\\1/g')
|
||||
re=$(printf '%s' "$1" | sed -e 's/[].[^$\\*]/\\&/g')
|
||||
name=$( GIT_CONFIG=.gitmodules \
|
||||
git config --get-regexp '^submodule\..*\.path$' |
|
||||
sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' )
|
||||
|
|
50
git-svn.perl
50
git-svn.perl
|
@ -252,7 +252,7 @@ sub usage {
|
|||
next if $cmd && $cmd ne $_;
|
||||
next if /^multi-/; # don't show deprecated commands
|
||||
print $fd ' ',pack('A17',$_),$cmd{$_}->[1],"\n";
|
||||
foreach (keys %{$cmd{$_}->[2]}) {
|
||||
foreach (sort keys %{$cmd{$_}->[2]}) {
|
||||
# mixed-case options are for .git/config only
|
||||
next if /[A-Z]/ && /^[a-z]+$/i;
|
||||
# prints out arguments as they should be passed:
|
||||
|
@ -406,7 +406,8 @@ sub cmd_dcommit {
|
|||
"If these changes depend on each other, re-running ",
|
||||
"without --no-rebase will be required."
|
||||
}
|
||||
foreach my $d (@$linear_refs) {
|
||||
while (1) {
|
||||
my $d = shift @$linear_refs or last;
|
||||
unless (defined $last_rev) {
|
||||
(undef, $last_rev, undef) = cmt_metadata("$d~1");
|
||||
unless (defined $last_rev) {
|
||||
|
@ -439,14 +440,14 @@ sub cmd_dcommit {
|
|||
|
||||
# we always want to rebase against the current HEAD,
|
||||
# not any head that was passed to us
|
||||
my @diff = command('diff-tree', 'HEAD',
|
||||
my @diff = command('diff-tree', $d,
|
||||
$gs->refname, '--');
|
||||
my @finish;
|
||||
if (@diff) {
|
||||
@finish = rebase_cmd();
|
||||
print STDERR "W: HEAD and ", $gs->refname,
|
||||
print STDERR "W: $d and ", $gs->refname,
|
||||
" differ, using @finish:\n",
|
||||
"@diff";
|
||||
join("\n", @diff), "\n";
|
||||
} else {
|
||||
print "No changes between current HEAD and ",
|
||||
$gs->refname,
|
||||
|
@ -455,6 +456,45 @@ sub cmd_dcommit {
|
|||
@finish = qw/reset --mixed/;
|
||||
}
|
||||
command_noisy(@finish, $gs->refname);
|
||||
if (@diff) {
|
||||
@refs = ();
|
||||
my ($url_, $rev_, $uuid_, $gs_) =
|
||||
working_head_info($head, \@refs);
|
||||
my ($linear_refs_, $parents_) =
|
||||
linearize_history($gs_, \@refs);
|
||||
if (scalar(@$linear_refs) !=
|
||||
scalar(@$linear_refs_)) {
|
||||
fatal "# of revisions changed ",
|
||||
"\nbefore:\n",
|
||||
join("\n", @$linear_refs),
|
||||
"\n\nafter:\n",
|
||||
join("\n", @$linear_refs_), "\n",
|
||||
'If you are attempting to commit ',
|
||||
"merges, try running:\n\t",
|
||||
'git rebase --interactive',
|
||||
'--preserve-merges ',
|
||||
$gs->refname,
|
||||
"\nBefore dcommitting";
|
||||
}
|
||||
if ($url_ ne $url) {
|
||||
fatal "URL mismatch after rebase: ",
|
||||
"$url_ != $url";
|
||||
}
|
||||
if ($uuid_ ne $uuid) {
|
||||
fatal "uuid mismatch after rebase: ",
|
||||
"$uuid_ != $uuid";
|
||||
}
|
||||
# remap parents
|
||||
my (%p, @l, $i);
|
||||
for ($i = 0; $i < scalar @$linear_refs; $i++) {
|
||||
my $new = $linear_refs_->[$i] or next;
|
||||
$p{$new} =
|
||||
$parents->{$linear_refs->[$i]};
|
||||
push @l, $new;
|
||||
}
|
||||
$parents = \%p;
|
||||
$linear_refs = \@l;
|
||||
}
|
||||
$last_rev = $cmt_rev;
|
||||
}
|
||||
}
|
||||
|
|
13
git.c
13
git.c
|
@ -249,14 +249,9 @@ static int run_command(struct cmd_struct *p, int argc, const char **argv)
|
|||
prefix = setup_git_directory();
|
||||
if (p->option & USE_PAGER)
|
||||
setup_pager();
|
||||
if (p->option & NEED_WORK_TREE) {
|
||||
const char *work_tree = get_git_work_tree();
|
||||
const char *git_dir = get_git_dir();
|
||||
if (!is_absolute_path(git_dir))
|
||||
set_git_dir(make_absolute_path(git_dir));
|
||||
if (!work_tree || chdir(work_tree))
|
||||
die("%s must be run in a work tree", p->cmd);
|
||||
}
|
||||
if (p->option & NEED_WORK_TREE)
|
||||
setup_work_tree();
|
||||
|
||||
trace_argv_printf(argv, argc, "trace: built-in: git");
|
||||
|
||||
status = p->fn(argc, argv, prefix);
|
||||
|
@ -347,7 +342,7 @@ static void handle_internal_command(int argc, const char **argv)
|
|||
{ "rev-list", cmd_rev_list, RUN_SETUP },
|
||||
{ "rev-parse", cmd_rev_parse, RUN_SETUP },
|
||||
{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
|
||||
{ "rm", cmd_rm, RUN_SETUP | NEED_WORK_TREE },
|
||||
{ "rm", cmd_rm, RUN_SETUP },
|
||||
{ "runstatus", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE },
|
||||
{ "send-pack", cmd_send_pack, RUN_SETUP },
|
||||
{ "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
|
||||
|
|
|
@ -611,6 +611,15 @@ (%)
|
|||
);
|
||||
my %mapping = @mapping;
|
||||
|
||||
if ($params{-replay}) {
|
||||
while (my ($name, $symbol) = each %mapping) {
|
||||
if (!exists $params{$name}) {
|
||||
# to allow for multivalued params we use arrayref form
|
||||
$params{$name} = [ $cgi->param($symbol) ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$params{'project'} = $project unless exists $params{'project'};
|
||||
|
||||
my ($use_pathinfo) = gitweb_check_feature('pathinfo');
|
||||
|
@ -1423,20 +1432,121 @@ sub git_get_type {
|
|||
return $type;
|
||||
}
|
||||
|
||||
# repository configuration
|
||||
our $config_file = '';
|
||||
our %config;
|
||||
|
||||
# store multiple values for single key as anonymous array reference
|
||||
# single values stored directly in the hash, not as [ <value> ]
|
||||
sub hash_set_multi {
|
||||
my ($hash, $key, $value) = @_;
|
||||
|
||||
if (!exists $hash->{$key}) {
|
||||
$hash->{$key} = $value;
|
||||
} elsif (!ref $hash->{$key}) {
|
||||
$hash->{$key} = [ $hash->{$key}, $value ];
|
||||
} else {
|
||||
push @{$hash->{$key}}, $value;
|
||||
}
|
||||
}
|
||||
|
||||
# return hash of git project configuration
|
||||
# optionally limited to some section, e.g. 'gitweb'
|
||||
sub git_parse_project_config {
|
||||
my $section_regexp = shift;
|
||||
my %config;
|
||||
|
||||
local $/ = "\0";
|
||||
|
||||
open my $fh, "-|", git_cmd(), "config", '-z', '-l',
|
||||
or return;
|
||||
|
||||
while (my $keyval = <$fh>) {
|
||||
chomp $keyval;
|
||||
my ($key, $value) = split(/\n/, $keyval, 2);
|
||||
|
||||
hash_set_multi(\%config, $key, $value)
|
||||
if (!defined $section_regexp || $key =~ /^(?:$section_regexp)\./o);
|
||||
}
|
||||
close $fh;
|
||||
|
||||
return %config;
|
||||
}
|
||||
|
||||
# convert config value to boolean, 'true' or 'false'
|
||||
# no value, number > 0, 'true' and 'yes' values are true
|
||||
# rest of values are treated as false (never as error)
|
||||
sub config_to_bool {
|
||||
my $val = shift;
|
||||
|
||||
# strip leading and trailing whitespace
|
||||
$val =~ s/^\s+//;
|
||||
$val =~ s/\s+$//;
|
||||
|
||||
return (!defined $val || # section.key
|
||||
($val =~ /^\d+$/ && $val) || # section.key = 1
|
||||
($val =~ /^(?:true|yes)$/i)); # section.key = true
|
||||
}
|
||||
|
||||
# convert config value to simple decimal number
|
||||
# an optional value suffix of 'k', 'm', or 'g' will cause the value
|
||||
# to be multiplied by 1024, 1048576, or 1073741824
|
||||
sub config_to_int {
|
||||
my $val = shift;
|
||||
|
||||
# strip leading and trailing whitespace
|
||||
$val =~ s/^\s+//;
|
||||
$val =~ s/\s+$//;
|
||||
|
||||
if (my ($num, $unit) = ($val =~ /^([0-9]*)([kmg])$/i)) {
|
||||
$unit = lc($unit);
|
||||
# unknown unit is treated as 1
|
||||
return $num * ($unit eq 'g' ? 1073741824 :
|
||||
$unit eq 'm' ? 1048576 :
|
||||
$unit eq 'k' ? 1024 : 1);
|
||||
}
|
||||
return $val;
|
||||
}
|
||||
|
||||
# convert config value to array reference, if needed
|
||||
sub config_to_multi {
|
||||
my $val = shift;
|
||||
|
||||
return ref($val) ? $val : [ $val ];
|
||||
}
|
||||
|
||||
sub git_get_project_config {
|
||||
my ($key, $type) = @_;
|
||||
|
||||
# key sanity check
|
||||
return unless ($key);
|
||||
$key =~ s/^gitweb\.//;
|
||||
return if ($key =~ m/\W/);
|
||||
|
||||
my @x = (git_cmd(), 'config');
|
||||
if (defined $type) { push @x, $type; }
|
||||
push @x, "--get";
|
||||
push @x, "gitweb.$key";
|
||||
my $val = qx(@x);
|
||||
chomp $val;
|
||||
return ($val);
|
||||
# type sanity check
|
||||
if (defined $type) {
|
||||
$type =~ s/^--//;
|
||||
$type = undef
|
||||
unless ($type eq 'bool' || $type eq 'int');
|
||||
}
|
||||
|
||||
# get config
|
||||
if (!defined $config_file ||
|
||||
$config_file ne "$git_dir/config") {
|
||||
%config = git_parse_project_config('gitweb');
|
||||
$config_file = "$git_dir/config";
|
||||
}
|
||||
|
||||
# ensure given type
|
||||
if (!defined $type) {
|
||||
return $config{"gitweb.$key"};
|
||||
} elsif ($type eq 'bool') {
|
||||
# backward compatibility: 'git config --bool' returns true/false
|
||||
return config_to_bool($config{"gitweb.$key"}) ? 'true' : 'false';
|
||||
} elsif ($type eq 'int') {
|
||||
return config_to_int($config{"gitweb.$key"});
|
||||
}
|
||||
return $config{"gitweb.$key"};
|
||||
}
|
||||
|
||||
# get hash of given path at given ref
|
||||
|
@ -1496,7 +1606,9 @@ sub git_get_path_by_hash {
|
|||
sub git_get_project_description {
|
||||
my $path = shift;
|
||||
|
||||
open my $fd, "$projectroot/$path/description" or return undef;
|
||||
$git_dir = "$projectroot/$path";
|
||||
open my $fd, "$projectroot/$path/description"
|
||||
or return git_get_project_config('description');
|
||||
my $descr = <$fd>;
|
||||
close $fd;
|
||||
if (defined $descr) {
|
||||
|
@ -1508,7 +1620,11 @@ sub git_get_project_description {
|
|||
sub git_get_project_url_list {
|
||||
my $path = shift;
|
||||
|
||||
open my $fd, "$projectroot/$path/cloneurl" or return;
|
||||
$git_dir = "$projectroot/$path";
|
||||
open my $fd, "$projectroot/$path/cloneurl"
|
||||
or return wantarray ?
|
||||
@{ config_to_multi(git_get_project_config('url')) } :
|
||||
config_to_multi(git_get_project_config('url'));
|
||||
my @git_project_url_list = map { chomp; $_ } <$fd>;
|
||||
close $fd;
|
||||
|
||||
|
@ -1990,12 +2106,12 @@ sub parse_difftree_raw_line {
|
|||
$res{'to_mode'} = $2;
|
||||
$res{'from_id'} = $3;
|
||||
$res{'to_id'} = $4;
|
||||
$res{'status'} = $5;
|
||||
$res{'status'} = $res{'status_str'} = $5;
|
||||
$res{'similarity'} = $6;
|
||||
if ($res{'status'} eq 'R' || $res{'status'} eq 'C') { # renamed or copied
|
||||
($res{'from_file'}, $res{'to_file'}) = map { unquote($_) } split("\t", $7);
|
||||
} else {
|
||||
$res{'file'} = unquote($7);
|
||||
$res{'from_file'} = $res{'to_file'} = $res{'file'} = unquote($7);
|
||||
}
|
||||
}
|
||||
# '::100755 100755 100755 60e79ca1b01bc8b057abe17ddab484699a7f5fdb 94067cc5f73388f33722d52ae02f44692bc07490 94067cc5f73388f33722d52ae02f44692bc07490 MR git-gui/git-gui.sh'
|
||||
|
@ -2006,6 +2122,7 @@ sub parse_difftree_raw_line {
|
|||
$res{'to_mode'} = pop @{$res{'from_mode'}};
|
||||
$res{'from_id'} = [ split(' ', $3) ];
|
||||
$res{'to_id'} = pop @{$res{'from_id'}};
|
||||
$res{'status_str'} = $4;
|
||||
$res{'status'} = [ split('', $4) ];
|
||||
$res{'to_file'} = unquote($5);
|
||||
}
|
||||
|
@ -2062,7 +2179,10 @@ sub parse_from_to_diffinfo {
|
|||
fill_from_file_info($diffinfo, @parents)
|
||||
unless exists $diffinfo->{'from_file'};
|
||||
for (my $i = 0; $i < $diffinfo->{'nparents'}; $i++) {
|
||||
$from->{'file'}[$i] = $diffinfo->{'from_file'}[$i] || $diffinfo->{'to_file'};
|
||||
$from->{'file'}[$i] =
|
||||
defined $diffinfo->{'from_file'}[$i] ?
|
||||
$diffinfo->{'from_file'}[$i] :
|
||||
$diffinfo->{'to_file'};
|
||||
if ($diffinfo->{'status'}[$i] ne "A") { # not new (added) file
|
||||
$from->{'href'}[$i] = href(action=>"blob",
|
||||
hash_base=>$parents[$i],
|
||||
|
@ -2074,7 +2194,7 @@ sub parse_from_to_diffinfo {
|
|||
}
|
||||
} else {
|
||||
# ordinary (not combined) diff
|
||||
$from->{'file'} = $diffinfo->{'from_file'} || $diffinfo->{'file'};
|
||||
$from->{'file'} = $diffinfo->{'from_file'};
|
||||
if ($diffinfo->{'status'} ne "A") { # not new (added) file
|
||||
$from->{'href'} = href(action=>"blob", hash_base=>$hash_parent,
|
||||
hash=>$diffinfo->{'from_id'},
|
||||
|
@ -2084,7 +2204,7 @@ sub parse_from_to_diffinfo {
|
|||
}
|
||||
}
|
||||
|
||||
$to->{'file'} = $diffinfo->{'to_file'} || $diffinfo->{'file'};
|
||||
$to->{'file'} = $diffinfo->{'to_file'};
|
||||
if (!is_deleted($diffinfo)) { # file exists in result
|
||||
$to->{'href'} = href(action=>"blob", hash_base=>$hash,
|
||||
hash=>$diffinfo->{'to_id'},
|
||||
|
@ -2505,7 +2625,7 @@ sub format_paging_nav {
|
|||
|
||||
if ($page > 0) {
|
||||
$paging_nav .= " ⋅ " .
|
||||
$cgi->a({-href => href(action=>$action, hash=>$hash, page=>$page-1),
|
||||
$cgi->a({-href => href(-replay=>1, page=>$page-1),
|
||||
-accesskey => "p", -title => "Alt-p"}, "prev");
|
||||
} else {
|
||||
$paging_nav .= " ⋅ prev";
|
||||
|
@ -2513,7 +2633,7 @@ sub format_paging_nav {
|
|||
|
||||
if ($nrevs >= (100 * ($page+1)-1)) {
|
||||
$paging_nav .= " ⋅ " .
|
||||
$cgi->a({-href => href(action=>$action, hash=>$hash, page=>$page+1),
|
||||
$cgi->a({-href => href(-replay=>1, page=>$page+1),
|
||||
-accesskey => "n", -title => "Alt-n"}, "next");
|
||||
} else {
|
||||
$paging_nav .= " ⋅ next";
|
||||
|
@ -2818,7 +2938,7 @@ sub fill_from_file_info {
|
|||
sub is_deleted {
|
||||
my $diffinfo = shift;
|
||||
|
||||
return $diffinfo->{'to_id'} eq ('0' x 40);
|
||||
return $diffinfo->{'status_str'} =~ /D/;
|
||||
}
|
||||
|
||||
# does patch correspond to [previous] difftree raw line
|
||||
|
@ -2829,7 +2949,7 @@ sub is_patch_split {
|
|||
my ($diffinfo, $patchinfo) = @_;
|
||||
|
||||
return defined $diffinfo && defined $patchinfo
|
||||
&& ($diffinfo->{'to_file'} || $diffinfo->{'file'}) eq $patchinfo->{'to_file'};
|
||||
&& $diffinfo->{'to_file'} eq $patchinfo->{'to_file'};
|
||||
}
|
||||
|
||||
|
||||
|
@ -3898,11 +4018,11 @@ sub git_blame2 {
|
|||
or die_error(undef, "Open git-blame failed");
|
||||
git_header_html();
|
||||
my $formats_nav =
|
||||
$cgi->a({-href => href(action=>"blob", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)},
|
||||
$cgi->a({-href => href(action=>"blob", -replay=>1)},
|
||||
"blob") .
|
||||
" | " .
|
||||
$cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)},
|
||||
"history") .
|
||||
$cgi->a({-href => href(action=>"history", -replay=>1)},
|
||||
"history") .
|
||||
" | " .
|
||||
$cgi->a({-href => href(action=>"blame", file_name=>$file_name)},
|
||||
"HEAD");
|
||||
|
@ -4178,18 +4298,15 @@ sub git_blob {
|
|||
if (defined $file_name) {
|
||||
if ($have_blame) {
|
||||
$formats_nav .=
|
||||
$cgi->a({-href => href(action=>"blame", hash_base=>$hash_base,
|
||||
hash=>$hash, file_name=>$file_name)},
|
||||
$cgi->a({-href => href(action=>"blame", -replay=>1)},
|
||||
"blame") .
|
||||
" | ";
|
||||
}
|
||||
$formats_nav .=
|
||||
$cgi->a({-href => href(action=>"history", hash_base=>$hash_base,
|
||||
hash=>$hash, file_name=>$file_name)},
|
||||
$cgi->a({-href => href(action=>"history", -replay=>1)},
|
||||
"history") .
|
||||
" | " .
|
||||
$cgi->a({-href => href(action=>"blob_plain",
|
||||
hash=>$hash, file_name=>$file_name)},
|
||||
$cgi->a({-href => href(action=>"blob_plain", -replay=>1)},
|
||||
"raw") .
|
||||
" | " .
|
||||
$cgi->a({-href => href(action=>"blob",
|
||||
|
@ -4197,7 +4314,8 @@ sub git_blob {
|
|||
"HEAD");
|
||||
} else {
|
||||
$formats_nav .=
|
||||
$cgi->a({-href => href(action=>"blob_plain", hash=>$hash)}, "raw");
|
||||
$cgi->a({-href => href(action=>"blob_plain", -replay=>1)},
|
||||
"raw");
|
||||
}
|
||||
git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
|
||||
git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
|
||||
|
@ -4260,8 +4378,7 @@ sub git_tree {
|
|||
my @views_nav = ();
|
||||
if (defined $file_name) {
|
||||
push @views_nav,
|
||||
$cgi->a({-href => href(action=>"history", hash_base=>$hash_base,
|
||||
hash=>$hash, file_name=>$file_name)},
|
||||
$cgi->a({-href => href(action=>"history", -replay=>1)},
|
||||
"history"),
|
||||
$cgi->a({-href => href(action=>"tree",
|
||||
hash_base=>"HEAD", file_name=>$file_name)},
|
||||
|
@ -4435,7 +4552,7 @@ sub git_log {
|
|||
}
|
||||
if ($#commitlist >= 100) {
|
||||
print "<div class=\"page_nav\">\n";
|
||||
print $cgi->a({-href => href(action=>"log", hash=>$hash, page=>$page+1),
|
||||
print $cgi->a({-href => href(-replay=>1, page=>$page+1),
|
||||
-accesskey => "n", -title => "Alt-n"}, "next");
|
||||
print "</div>\n";
|
||||
}
|
||||
|
@ -4667,8 +4784,8 @@ sub git_blobdiff {
|
|||
}
|
||||
|
||||
%diffinfo = parse_difftree_raw_line($difftree[0]);
|
||||
$file_parent ||= $diffinfo{'from_file'} || $file_name || $diffinfo{'file'};
|
||||
$file_name ||= $diffinfo{'to_file'} || $diffinfo{'file'};
|
||||
$file_parent ||= $diffinfo{'from_file'} || $file_name;
|
||||
$file_name ||= $diffinfo{'to_file'};
|
||||
|
||||
$hash_parent ||= $diffinfo{'from_id'};
|
||||
$hash ||= $diffinfo{'to_id'};
|
||||
|
@ -4729,10 +4846,7 @@ sub git_blobdiff {
|
|||
# header
|
||||
if ($format eq 'html') {
|
||||
my $formats_nav =
|
||||
$cgi->a({-href => href(action=>"blobdiff_plain",
|
||||
hash=>$hash, hash_parent=>$hash_parent,
|
||||
hash_base=>$hash_base, hash_parent_base=>$hash_parent_base,
|
||||
file_name=>$file_name, file_parent=>$file_parent)},
|
||||
$cgi->a({-href => href(action=>"blobdiff_plain", -replay=>1)},
|
||||
"raw");
|
||||
git_header_html(undef, $expires);
|
||||
if (defined $hash_base && (my %co = parse_commit($hash_base))) {
|
||||
|
@ -4806,8 +4920,7 @@ sub git_commitdiff {
|
|||
my $formats_nav;
|
||||
if ($format eq 'html') {
|
||||
$formats_nav =
|
||||
$cgi->a({-href => href(action=>"commitdiff_plain",
|
||||
hash=>$hash, hash_parent=>$hash_parent)},
|
||||
$cgi->a({-href => href(action=>"commitdiff_plain", -replay=>1)},
|
||||
"raw");
|
||||
|
||||
if (defined $hash_parent &&
|
||||
|
@ -5002,27 +5115,20 @@ sub git_history {
|
|||
file_name=>$file_name)},
|
||||
"first");
|
||||
$paging_nav .= " ⋅ " .
|
||||
$cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base,
|
||||
file_name=>$file_name, page=>$page-1),
|
||||
$cgi->a({-href => href(-replay=>1, page=>$page-1),
|
||||
-accesskey => "p", -title => "Alt-p"}, "prev");
|
||||
} else {
|
||||
$paging_nav .= "first";
|
||||
$paging_nav .= " ⋅ prev";
|
||||
}
|
||||
if ($#commitlist >= 100) {
|
||||
$paging_nav .= " ⋅ " .
|
||||
$cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base,
|
||||
file_name=>$file_name, page=>$page+1),
|
||||
-accesskey => "n", -title => "Alt-n"}, "next");
|
||||
} else {
|
||||
$paging_nav .= " ⋅ next";
|
||||
}
|
||||
my $next_link = '';
|
||||
if ($#commitlist >= 100) {
|
||||
$next_link =
|
||||
$cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base,
|
||||
file_name=>$file_name, page=>$page+1),
|
||||
$cgi->a({-href => href(-replay=>1, page=>$page+1),
|
||||
-accesskey => "n", -title => "Alt-n"}, "next");
|
||||
$paging_nav .= " ⋅ $next_link";
|
||||
} else {
|
||||
$paging_nav .= " ⋅ next";
|
||||
}
|
||||
|
||||
git_header_html();
|
||||
|
@ -5092,30 +5198,23 @@ sub git_search {
|
|||
searchtext=>$searchtext, searchtype=>$searchtype)},
|
||||
"first");
|
||||
$paging_nav .= " ⋅ " .
|
||||
$cgi->a({-href => href(action=>"search", hash=>$hash,
|
||||
searchtext=>$searchtext, searchtype=>$searchtype,
|
||||
page=>$page-1),
|
||||
$cgi->a({-href => href(-replay=>1, page=>$page-1),
|
||||
-accesskey => "p", -title => "Alt-p"}, "prev");
|
||||
} else {
|
||||
$paging_nav .= "first";
|
||||
$paging_nav .= " ⋅ prev";
|
||||
}
|
||||
if ($#commitlist >= 100) {
|
||||
$paging_nav .= " ⋅ " .
|
||||
$cgi->a({-href => href(action=>"search", hash=>$hash,
|
||||
searchtext=>$searchtext, searchtype=>$searchtype,
|
||||
page=>$page+1),
|
||||
-accesskey => "n", -title => "Alt-n"}, "next");
|
||||
} else {
|
||||
$paging_nav .= " ⋅ next";
|
||||
}
|
||||
my $next_link = '';
|
||||
if ($#commitlist >= 100) {
|
||||
$next_link =
|
||||
$cgi->a({-href => href(action=>"search", hash=>$hash,
|
||||
searchtext=>$searchtext, searchtype=>$searchtype,
|
||||
page=>$page+1),
|
||||
$cgi->a({-href => href(-replay=>1, page=>$page+1),
|
||||
-accesskey => "n", -title => "Alt-n"}, "next");
|
||||
$paging_nav .= " ⋅ $next_link";
|
||||
} else {
|
||||
$paging_nav .= " ⋅ next";
|
||||
}
|
||||
|
||||
if ($#commitlist >= 100) {
|
||||
}
|
||||
|
||||
git_print_page_nav('','', $hash,$co{'tree'},$hash, $paging_nav);
|
||||
|
@ -5314,7 +5413,7 @@ sub git_shortlog {
|
|||
my $next_link = '';
|
||||
if ($#commitlist >= 100) {
|
||||
$next_link =
|
||||
$cgi->a({-href => href(action=>"shortlog", hash=>$hash, page=>$page+1),
|
||||
$cgi->a({-href => href(-replay=>1, page=>$page+1),
|
||||
-accesskey => "n", -title => "Alt-n"}, "next");
|
||||
}
|
||||
|
||||
|
|
3
help.c
3
help.c
|
@ -79,7 +79,8 @@ static void uniq(struct cmdnames *cmds)
|
|||
cmds->cnt = j;
|
||||
}
|
||||
|
||||
static void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes) {
|
||||
static void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
|
||||
{
|
||||
int ci, cj, ei;
|
||||
int cmp;
|
||||
|
||||
|
|
15
http-push.c
15
http-push.c
|
@ -2241,7 +2241,11 @@ static int delete_remote_branch(char *pattern, int force)
|
|||
|
||||
/* Remote branch must be an ancestor of remote HEAD */
|
||||
if (!verify_merge_base(head_sha1, remote_ref->old_sha1)) {
|
||||
return error("The branch '%s' is not a strict subset of your current HEAD.\nIf you are sure you want to delete it, run:\n\t'git http-push -D %s %s'", remote_ref->name, remote->url, pattern);
|
||||
return error("The branch '%s' is not an ancestor "
|
||||
"of your current HEAD.\n"
|
||||
"If you are sure you want to delete it,"
|
||||
" run:\n\t'git http-push -D %s %s'",
|
||||
remote_ref->name, remote->url, pattern);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2417,16 +2421,17 @@ int main(int argc, char **argv)
|
|||
if (!has_sha1_file(ref->old_sha1) ||
|
||||
!ref_newer(ref->peer_ref->new_sha1,
|
||||
ref->old_sha1)) {
|
||||
/* We do not have the remote ref, or
|
||||
/*
|
||||
* We do not have the remote ref, or
|
||||
* we know that the remote ref is not
|
||||
* an ancestor of what we are trying to
|
||||
* push. Either way this can be losing
|
||||
* commits at the remote end and likely
|
||||
* we were not up to date to begin with.
|
||||
*/
|
||||
error("remote '%s' is not a strict "
|
||||
"subset of local ref '%s'. "
|
||||
"maybe you are not up-to-date and "
|
||||
error("remote '%s' is not an ancestor of\n"
|
||||
"local '%s'.\n"
|
||||
"Maybe you are not up-to-date and "
|
||||
"need to pull first?",
|
||||
ref->name,
|
||||
ref->peer_ref->name);
|
||||
|
|
13
index-pack.c
13
index-pack.c
|
@ -683,6 +683,17 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
|
|||
}
|
||||
}
|
||||
|
||||
static int git_index_pack_config(const char *k, const char *v)
|
||||
{
|
||||
if (!strcmp(k, "pack.indexversion")) {
|
||||
pack_idx_default_version = git_config_int(k, v);
|
||||
if (pack_idx_default_version > 2)
|
||||
die("bad pack.indexversion=%d", pack_idx_default_version);
|
||||
return 0;
|
||||
}
|
||||
return git_default_config(k, v);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, fix_thin_pack = 0;
|
||||
|
@ -693,6 +704,8 @@ int main(int argc, char **argv)
|
|||
struct pack_idx_entry **idx_objects;
|
||||
unsigned char sha1[20];
|
||||
|
||||
git_config(git_index_pack_config);
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
char *arg = argv[i];
|
||||
|
||||
|
|
15
log-tree.c
15
log-tree.c
|
@ -125,6 +125,18 @@ static unsigned int digits_in_number(unsigned int number)
|
|||
return result;
|
||||
}
|
||||
|
||||
static int has_non_ascii(const char *s)
|
||||
{
|
||||
int ch;
|
||||
if (!s)
|
||||
return 0;
|
||||
while ((ch = *s++) != '\0') {
|
||||
if (non_ascii(ch))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void show_log(struct rev_info *opt, const char *sep)
|
||||
{
|
||||
struct strbuf msgbuf;
|
||||
|
@ -273,7 +285,8 @@ void show_log(struct rev_info *opt, const char *sep)
|
|||
*/
|
||||
strbuf_init(&msgbuf, 0);
|
||||
pretty_print_commit(opt->commit_format, commit, &msgbuf,
|
||||
abbrev, subject, extra_headers, opt->date_mode);
|
||||
abbrev, subject, extra_headers, opt->date_mode,
|
||||
has_non_ascii(opt->add_signoff));
|
||||
|
||||
if (opt->add_signoff)
|
||||
append_signoff(&msgbuf, opt->add_signoff);
|
||||
|
|
|
@ -22,6 +22,41 @@ enum parse_opt_option_flags {
|
|||
struct option;
|
||||
typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
|
||||
|
||||
/*
|
||||
* `type`::
|
||||
* holds the type of the option, you must have an OPTION_END last in your
|
||||
* array.
|
||||
*
|
||||
* `short_name`::
|
||||
* the character to use as a short option name, '\0' if none.
|
||||
*
|
||||
* `long_name`::
|
||||
* the long option name, without the leading dashes, NULL if none.
|
||||
*
|
||||
* `value`::
|
||||
* stores pointers to the values to be filled.
|
||||
*
|
||||
* `argh`::
|
||||
* token to explain the kind of argument this option wants. Keep it
|
||||
* homogenous across the repository.
|
||||
*
|
||||
* `help`::
|
||||
* the short help associated to what the option does.
|
||||
* Must never be NULL (except for OPTION_END).
|
||||
* OPTION_GROUP uses this pointer to store the group header.
|
||||
*
|
||||
* `flags`::
|
||||
* mask of parse_opt_option_flags.
|
||||
* PARSE_OPT_OPTARG: says that the argument is optionnal (not for BOOLEANs)
|
||||
* PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs
|
||||
*
|
||||
* `callback`::
|
||||
* pointer to the callback to use for OPTION_CALLBACK.
|
||||
*
|
||||
* `defval`::
|
||||
* default value to fill (*->value) with for PARSE_OPT_OPTARG.
|
||||
* CALLBACKS can use it like they want.
|
||||
*/
|
||||
struct option {
|
||||
enum parse_opt_type type;
|
||||
int short_name;
|
||||
|
@ -32,8 +67,6 @@ struct option {
|
|||
|
||||
int flags;
|
||||
parse_opt_cb *callback;
|
||||
/* holds default value for PARSE_OPT_OPTARG,
|
||||
though callbacks can use it like they want */
|
||||
intptr_t defval;
|
||||
};
|
||||
|
||||
|
|
|
@ -812,7 +812,7 @@ sub _cmd_exec {
|
|||
$self->wc_subdir() and chdir($self->wc_subdir());
|
||||
}
|
||||
_execv_git_cmd(@args);
|
||||
die "exec failed: $!";
|
||||
die qq[exec "@args" failed: $!];
|
||||
}
|
||||
|
||||
# Execute the given Git command ($_[0]) with arguments ($_[1..])
|
||||
|
|
723
pretty.c
Normal file
723
pretty.c
Normal file
|
@ -0,0 +1,723 @@
|
|||
#include "cache.h"
|
||||
#include "commit.h"
|
||||
#include "interpolate.h"
|
||||
#include "utf8.h"
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
|
||||
static struct cmt_fmt_map {
|
||||
const char *n;
|
||||
size_t cmp_len;
|
||||
enum cmit_fmt v;
|
||||
} cmt_fmts[] = {
|
||||
{ "raw", 1, CMIT_FMT_RAW },
|
||||
{ "medium", 1, CMIT_FMT_MEDIUM },
|
||||
{ "short", 1, CMIT_FMT_SHORT },
|
||||
{ "email", 1, CMIT_FMT_EMAIL },
|
||||
{ "full", 5, CMIT_FMT_FULL },
|
||||
{ "fuller", 5, CMIT_FMT_FULLER },
|
||||
{ "oneline", 1, CMIT_FMT_ONELINE },
|
||||
{ "format:", 7, CMIT_FMT_USERFORMAT},
|
||||
};
|
||||
|
||||
static char *user_format;
|
||||
|
||||
enum cmit_fmt get_commit_format(const char *arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!arg || !*arg)
|
||||
return CMIT_FMT_DEFAULT;
|
||||
if (*arg == '=')
|
||||
arg++;
|
||||
if (!prefixcmp(arg, "format:")) {
|
||||
if (user_format)
|
||||
free(user_format);
|
||||
user_format = xstrdup(arg + 7);
|
||||
return CMIT_FMT_USERFORMAT;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) {
|
||||
if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len) &&
|
||||
!strncmp(arg, cmt_fmts[i].n, strlen(arg)))
|
||||
return cmt_fmts[i].v;
|
||||
}
|
||||
|
||||
die("invalid --pretty format: %s", arg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic support for pretty-printing the header
|
||||
*/
|
||||
static int get_one_line(const char *msg)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
for (;;) {
|
||||
char c = *msg++;
|
||||
if (!c)
|
||||
break;
|
||||
ret++;
|
||||
if (c == '\n')
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* High bit set, or ISO-2022-INT */
|
||||
int non_ascii(int ch)
|
||||
{
|
||||
ch = (ch & 0xff);
|
||||
return ((ch & 0x80) || (ch == 0x1b));
|
||||
}
|
||||
|
||||
static int is_rfc2047_special(char ch)
|
||||
{
|
||||
return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_'));
|
||||
}
|
||||
|
||||
static void add_rfc2047(struct strbuf *sb, const char *line, int len,
|
||||
const char *encoding)
|
||||
{
|
||||
int i, last;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int ch = line[i];
|
||||
if (non_ascii(ch))
|
||||
goto needquote;
|
||||
if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
|
||||
goto needquote;
|
||||
}
|
||||
strbuf_add(sb, line, len);
|
||||
return;
|
||||
|
||||
needquote:
|
||||
strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
|
||||
strbuf_addf(sb, "=?%s?q?", encoding);
|
||||
for (i = last = 0; i < len; i++) {
|
||||
unsigned ch = line[i] & 0xFF;
|
||||
/*
|
||||
* We encode ' ' using '=20' even though rfc2047
|
||||
* allows using '_' for readability. Unfortunately,
|
||||
* many programs do not understand this and just
|
||||
* leave the underscore in place.
|
||||
*/
|
||||
if (is_rfc2047_special(ch) || ch == ' ') {
|
||||
strbuf_add(sb, line + last, i - last);
|
||||
strbuf_addf(sb, "=%02X", ch);
|
||||
last = i + 1;
|
||||
}
|
||||
}
|
||||
strbuf_add(sb, line + last, len - last);
|
||||
strbuf_addstr(sb, "?=");
|
||||
}
|
||||
|
||||
static void add_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
|
||||
const char *line, enum date_mode dmode,
|
||||
const char *encoding)
|
||||
{
|
||||
char *date;
|
||||
int namelen;
|
||||
unsigned long time;
|
||||
int tz;
|
||||
const char *filler = " ";
|
||||
|
||||
if (fmt == CMIT_FMT_ONELINE)
|
||||
return;
|
||||
date = strchr(line, '>');
|
||||
if (!date)
|
||||
return;
|
||||
namelen = ++date - line;
|
||||
time = strtoul(date, &date, 10);
|
||||
tz = strtol(date, NULL, 10);
|
||||
|
||||
if (fmt == CMIT_FMT_EMAIL) {
|
||||
char *name_tail = strchr(line, '<');
|
||||
int display_name_length;
|
||||
if (!name_tail)
|
||||
return;
|
||||
while (line < name_tail && isspace(name_tail[-1]))
|
||||
name_tail--;
|
||||
display_name_length = name_tail - line;
|
||||
filler = "";
|
||||
strbuf_addstr(sb, "From: ");
|
||||
add_rfc2047(sb, line, display_name_length, encoding);
|
||||
strbuf_add(sb, name_tail, namelen - display_name_length);
|
||||
strbuf_addch(sb, '\n');
|
||||
} else {
|
||||
strbuf_addf(sb, "%s: %.*s%.*s\n", what,
|
||||
(fmt == CMIT_FMT_FULLER) ? 4 : 0,
|
||||
filler, namelen, line);
|
||||
}
|
||||
switch (fmt) {
|
||||
case CMIT_FMT_MEDIUM:
|
||||
strbuf_addf(sb, "Date: %s\n", show_date(time, tz, dmode));
|
||||
break;
|
||||
case CMIT_FMT_EMAIL:
|
||||
strbuf_addf(sb, "Date: %s\n", show_date(time, tz, DATE_RFC2822));
|
||||
break;
|
||||
case CMIT_FMT_FULLER:
|
||||
strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, dmode));
|
||||
break;
|
||||
default:
|
||||
/* notin' */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int is_empty_line(const char *line, int *len_p)
|
||||
{
|
||||
int len = *len_p;
|
||||
while (len && isspace(line[len-1]))
|
||||
len--;
|
||||
*len_p = len;
|
||||
return !len;
|
||||
}
|
||||
|
||||
static void add_merge_info(enum cmit_fmt fmt, struct strbuf *sb,
|
||||
const struct commit *commit, int abbrev)
|
||||
{
|
||||
struct commit_list *parent = commit->parents;
|
||||
|
||||
if ((fmt == CMIT_FMT_ONELINE) || (fmt == CMIT_FMT_EMAIL) ||
|
||||
!parent || !parent->next)
|
||||
return;
|
||||
|
||||
strbuf_addstr(sb, "Merge:");
|
||||
|
||||
while (parent) {
|
||||
struct commit *p = parent->item;
|
||||
const char *hex = NULL;
|
||||
const char *dots;
|
||||
if (abbrev)
|
||||
hex = find_unique_abbrev(p->object.sha1, abbrev);
|
||||
if (!hex)
|
||||
hex = sha1_to_hex(p->object.sha1);
|
||||
dots = (abbrev && strlen(hex) != 40) ? "..." : "";
|
||||
parent = parent->next;
|
||||
|
||||
strbuf_addf(sb, " %s%s", hex, dots);
|
||||
}
|
||||
strbuf_addch(sb, '\n');
|
||||
}
|
||||
|
||||
static char *get_header(const struct commit *commit, const char *key)
|
||||
{
|
||||
int key_len = strlen(key);
|
||||
const char *line = commit->buffer;
|
||||
|
||||
for (;;) {
|
||||
const char *eol = strchr(line, '\n'), *next;
|
||||
|
||||
if (line == eol)
|
||||
return NULL;
|
||||
if (!eol) {
|
||||
eol = line + strlen(line);
|
||||
next = NULL;
|
||||
} else
|
||||
next = eol + 1;
|
||||
if (eol - line > key_len &&
|
||||
!strncmp(line, key, key_len) &&
|
||||
line[key_len] == ' ') {
|
||||
return xmemdupz(line + key_len + 1, eol - line - key_len - 1);
|
||||
}
|
||||
line = next;
|
||||
}
|
||||
}
|
||||
|
||||
static char *replace_encoding_header(char *buf, const char *encoding)
|
||||
{
|
||||
struct strbuf tmp;
|
||||
size_t start, len;
|
||||
char *cp = buf;
|
||||
|
||||
/* guess if there is an encoding header before a \n\n */
|
||||
while (strncmp(cp, "encoding ", strlen("encoding "))) {
|
||||
cp = strchr(cp, '\n');
|
||||
if (!cp || *++cp == '\n')
|
||||
return buf;
|
||||
}
|
||||
start = cp - buf;
|
||||
cp = strchr(cp, '\n');
|
||||
if (!cp)
|
||||
return buf; /* should not happen but be defensive */
|
||||
len = cp + 1 - (buf + start);
|
||||
|
||||
strbuf_init(&tmp, 0);
|
||||
strbuf_attach(&tmp, buf, strlen(buf), strlen(buf) + 1);
|
||||
if (is_encoding_utf8(encoding)) {
|
||||
/* we have re-coded to UTF-8; drop the header */
|
||||
strbuf_remove(&tmp, start, len);
|
||||
} else {
|
||||
/* just replaces XXXX in 'encoding XXXX\n' */
|
||||
strbuf_splice(&tmp, start + strlen("encoding "),
|
||||
len - strlen("encoding \n"),
|
||||
encoding, strlen(encoding));
|
||||
}
|
||||
return strbuf_detach(&tmp, NULL);
|
||||
}
|
||||
|
||||
static char *logmsg_reencode(const struct commit *commit,
|
||||
const char *output_encoding)
|
||||
{
|
||||
static const char *utf8 = "utf-8";
|
||||
const char *use_encoding;
|
||||
char *encoding;
|
||||
char *out;
|
||||
|
||||
if (!*output_encoding)
|
||||
return NULL;
|
||||
encoding = get_header(commit, "encoding");
|
||||
use_encoding = encoding ? encoding : utf8;
|
||||
if (!strcmp(use_encoding, output_encoding))
|
||||
if (encoding) /* we'll strip encoding header later */
|
||||
out = xstrdup(commit->buffer);
|
||||
else
|
||||
return NULL; /* nothing to do */
|
||||
else
|
||||
out = reencode_string(commit->buffer,
|
||||
output_encoding, use_encoding);
|
||||
if (out)
|
||||
out = replace_encoding_header(out, output_encoding);
|
||||
|
||||
free(encoding);
|
||||
return out;
|
||||
}
|
||||
|
||||
static void fill_person(struct interp *table, const char *msg, int len)
|
||||
{
|
||||
int start, end, tz = 0;
|
||||
unsigned long date;
|
||||
char *ep;
|
||||
|
||||
/* parse name */
|
||||
for (end = 0; end < len && msg[end] != '<'; end++)
|
||||
; /* do nothing */
|
||||
start = end + 1;
|
||||
while (end > 0 && isspace(msg[end - 1]))
|
||||
end--;
|
||||
table[0].value = xmemdupz(msg, end);
|
||||
|
||||
if (start >= len)
|
||||
return;
|
||||
|
||||
/* parse email */
|
||||
for (end = start + 1; end < len && msg[end] != '>'; end++)
|
||||
; /* do nothing */
|
||||
|
||||
if (end >= len)
|
||||
return;
|
||||
|
||||
table[1].value = xmemdupz(msg + start, end - start);
|
||||
|
||||
/* parse date */
|
||||
for (start = end + 1; start < len && isspace(msg[start]); start++)
|
||||
; /* do nothing */
|
||||
if (start >= len)
|
||||
return;
|
||||
date = strtoul(msg + start, &ep, 10);
|
||||
if (msg + start == ep)
|
||||
return;
|
||||
|
||||
table[5].value = xmemdupz(msg + start, ep - (msg + start));
|
||||
|
||||
/* parse tz */
|
||||
for (start = ep - msg + 1; start < len && isspace(msg[start]); start++)
|
||||
; /* do nothing */
|
||||
if (start + 1 < len) {
|
||||
tz = strtoul(msg + start + 1, NULL, 10);
|
||||
if (msg[start] == '-')
|
||||
tz = -tz;
|
||||
}
|
||||
|
||||
interp_set_entry(table, 2, show_date(date, tz, DATE_NORMAL));
|
||||
interp_set_entry(table, 3, show_date(date, tz, DATE_RFC2822));
|
||||
interp_set_entry(table, 4, show_date(date, tz, DATE_RELATIVE));
|
||||
interp_set_entry(table, 6, show_date(date, tz, DATE_ISO8601));
|
||||
}
|
||||
|
||||
void format_commit_message(const struct commit *commit,
|
||||
const void *format, struct strbuf *sb)
|
||||
{
|
||||
struct interp table[] = {
|
||||
{ "%H" }, /* commit hash */
|
||||
{ "%h" }, /* abbreviated commit hash */
|
||||
{ "%T" }, /* tree hash */
|
||||
{ "%t" }, /* abbreviated tree hash */
|
||||
{ "%P" }, /* parent hashes */
|
||||
{ "%p" }, /* abbreviated parent hashes */
|
||||
{ "%an" }, /* author name */
|
||||
{ "%ae" }, /* author email */
|
||||
{ "%ad" }, /* author date */
|
||||
{ "%aD" }, /* author date, RFC2822 style */
|
||||
{ "%ar" }, /* author date, relative */
|
||||
{ "%at" }, /* author date, UNIX timestamp */
|
||||
{ "%ai" }, /* author date, ISO 8601 */
|
||||
{ "%cn" }, /* committer name */
|
||||
{ "%ce" }, /* committer email */
|
||||
{ "%cd" }, /* committer date */
|
||||
{ "%cD" }, /* committer date, RFC2822 style */
|
||||
{ "%cr" }, /* committer date, relative */
|
||||
{ "%ct" }, /* committer date, UNIX timestamp */
|
||||
{ "%ci" }, /* committer date, ISO 8601 */
|
||||
{ "%e" }, /* encoding */
|
||||
{ "%s" }, /* subject */
|
||||
{ "%b" }, /* body */
|
||||
{ "%Cred" }, /* red */
|
||||
{ "%Cgreen" }, /* green */
|
||||
{ "%Cblue" }, /* blue */
|
||||
{ "%Creset" }, /* reset color */
|
||||
{ "%n" }, /* newline */
|
||||
{ "%m" }, /* left/right/bottom */
|
||||
};
|
||||
enum interp_index {
|
||||
IHASH = 0, IHASH_ABBREV,
|
||||
ITREE, ITREE_ABBREV,
|
||||
IPARENTS, IPARENTS_ABBREV,
|
||||
IAUTHOR_NAME, IAUTHOR_EMAIL,
|
||||
IAUTHOR_DATE, IAUTHOR_DATE_RFC2822, IAUTHOR_DATE_RELATIVE,
|
||||
IAUTHOR_TIMESTAMP, IAUTHOR_ISO8601,
|
||||
ICOMMITTER_NAME, ICOMMITTER_EMAIL,
|
||||
ICOMMITTER_DATE, ICOMMITTER_DATE_RFC2822,
|
||||
ICOMMITTER_DATE_RELATIVE, ICOMMITTER_TIMESTAMP,
|
||||
ICOMMITTER_ISO8601,
|
||||
IENCODING,
|
||||
ISUBJECT,
|
||||
IBODY,
|
||||
IRED, IGREEN, IBLUE, IRESET_COLOR,
|
||||
INEWLINE,
|
||||
ILEFT_RIGHT,
|
||||
};
|
||||
struct commit_list *p;
|
||||
char parents[1024];
|
||||
unsigned long len;
|
||||
int i;
|
||||
enum { HEADER, SUBJECT, BODY } state;
|
||||
const char *msg = commit->buffer;
|
||||
|
||||
if (ILEFT_RIGHT + 1 != ARRAY_SIZE(table))
|
||||
die("invalid interp table!");
|
||||
|
||||
/* these are independent of the commit */
|
||||
interp_set_entry(table, IRED, "\033[31m");
|
||||
interp_set_entry(table, IGREEN, "\033[32m");
|
||||
interp_set_entry(table, IBLUE, "\033[34m");
|
||||
interp_set_entry(table, IRESET_COLOR, "\033[m");
|
||||
interp_set_entry(table, INEWLINE, "\n");
|
||||
|
||||
/* these depend on the commit */
|
||||
if (!commit->object.parsed)
|
||||
parse_object(commit->object.sha1);
|
||||
interp_set_entry(table, IHASH, sha1_to_hex(commit->object.sha1));
|
||||
interp_set_entry(table, IHASH_ABBREV,
|
||||
find_unique_abbrev(commit->object.sha1,
|
||||
DEFAULT_ABBREV));
|
||||
interp_set_entry(table, ITREE, sha1_to_hex(commit->tree->object.sha1));
|
||||
interp_set_entry(table, ITREE_ABBREV,
|
||||
find_unique_abbrev(commit->tree->object.sha1,
|
||||
DEFAULT_ABBREV));
|
||||
interp_set_entry(table, ILEFT_RIGHT,
|
||||
(commit->object.flags & BOUNDARY)
|
||||
? "-"
|
||||
: (commit->object.flags & SYMMETRIC_LEFT)
|
||||
? "<"
|
||||
: ">");
|
||||
|
||||
parents[1] = 0;
|
||||
for (i = 0, p = commit->parents;
|
||||
p && i < sizeof(parents) - 1;
|
||||
p = p->next)
|
||||
i += snprintf(parents + i, sizeof(parents) - i - 1, " %s",
|
||||
sha1_to_hex(p->item->object.sha1));
|
||||
interp_set_entry(table, IPARENTS, parents + 1);
|
||||
|
||||
parents[1] = 0;
|
||||
for (i = 0, p = commit->parents;
|
||||
p && i < sizeof(parents) - 1;
|
||||
p = p->next)
|
||||
i += snprintf(parents + i, sizeof(parents) - i - 1, " %s",
|
||||
find_unique_abbrev(p->item->object.sha1,
|
||||
DEFAULT_ABBREV));
|
||||
interp_set_entry(table, IPARENTS_ABBREV, parents + 1);
|
||||
|
||||
for (i = 0, state = HEADER; msg[i] && state < BODY; i++) {
|
||||
int eol;
|
||||
for (eol = i; msg[eol] && msg[eol] != '\n'; eol++)
|
||||
; /* do nothing */
|
||||
|
||||
if (state == SUBJECT) {
|
||||
table[ISUBJECT].value = xmemdupz(msg + i, eol - i);
|
||||
i = eol;
|
||||
}
|
||||
if (i == eol) {
|
||||
state++;
|
||||
/* strip empty lines */
|
||||
while (msg[eol + 1] == '\n')
|
||||
eol++;
|
||||
} else if (!prefixcmp(msg + i, "author "))
|
||||
fill_person(table + IAUTHOR_NAME,
|
||||
msg + i + 7, eol - i - 7);
|
||||
else if (!prefixcmp(msg + i, "committer "))
|
||||
fill_person(table + ICOMMITTER_NAME,
|
||||
msg + i + 10, eol - i - 10);
|
||||
else if (!prefixcmp(msg + i, "encoding "))
|
||||
table[IENCODING].value =
|
||||
xmemdupz(msg + i + 9, eol - i - 9);
|
||||
i = eol;
|
||||
}
|
||||
if (msg[i])
|
||||
table[IBODY].value = xstrdup(msg + i);
|
||||
|
||||
len = interpolate(sb->buf + sb->len, strbuf_avail(sb),
|
||||
format, table, ARRAY_SIZE(table));
|
||||
if (len > strbuf_avail(sb)) {
|
||||
strbuf_grow(sb, len);
|
||||
interpolate(sb->buf + sb->len, strbuf_avail(sb) + 1,
|
||||
format, table, ARRAY_SIZE(table));
|
||||
}
|
||||
strbuf_setlen(sb, sb->len + len);
|
||||
interp_clear_table(table, ARRAY_SIZE(table));
|
||||
}
|
||||
|
||||
static void pp_header(enum cmit_fmt fmt,
|
||||
int abbrev,
|
||||
enum date_mode dmode,
|
||||
const char *encoding,
|
||||
const struct commit *commit,
|
||||
const char **msg_p,
|
||||
struct strbuf *sb)
|
||||
{
|
||||
int parents_shown = 0;
|
||||
|
||||
for (;;) {
|
||||
const char *line = *msg_p;
|
||||
int linelen = get_one_line(*msg_p);
|
||||
|
||||
if (!linelen)
|
||||
return;
|
||||
*msg_p += linelen;
|
||||
|
||||
if (linelen == 1)
|
||||
/* End of header */
|
||||
return;
|
||||
|
||||
if (fmt == CMIT_FMT_RAW) {
|
||||
strbuf_add(sb, line, linelen);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!memcmp(line, "parent ", 7)) {
|
||||
if (linelen != 48)
|
||||
die("bad parent line in commit");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!parents_shown) {
|
||||
struct commit_list *parent;
|
||||
int num;
|
||||
for (parent = commit->parents, num = 0;
|
||||
parent;
|
||||
parent = parent->next, num++)
|
||||
;
|
||||
/* with enough slop */
|
||||
strbuf_grow(sb, num * 50 + 20);
|
||||
add_merge_info(fmt, sb, commit, abbrev);
|
||||
parents_shown = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* MEDIUM == DEFAULT shows only author with dates.
|
||||
* FULL shows both authors but not dates.
|
||||
* FULLER shows both authors and dates.
|
||||
*/
|
||||
if (!memcmp(line, "author ", 7)) {
|
||||
strbuf_grow(sb, linelen + 80);
|
||||
add_user_info("Author", fmt, sb, line + 7, dmode, encoding);
|
||||
}
|
||||
if (!memcmp(line, "committer ", 10) &&
|
||||
(fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) {
|
||||
strbuf_grow(sb, linelen + 80);
|
||||
add_user_info("Commit", fmt, sb, line + 10, dmode, encoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pp_title_line(enum cmit_fmt fmt,
|
||||
const char **msg_p,
|
||||
struct strbuf *sb,
|
||||
const char *subject,
|
||||
const char *after_subject,
|
||||
const char *encoding,
|
||||
int plain_non_ascii)
|
||||
{
|
||||
struct strbuf title;
|
||||
|
||||
strbuf_init(&title, 80);
|
||||
|
||||
for (;;) {
|
||||
const char *line = *msg_p;
|
||||
int linelen = get_one_line(line);
|
||||
|
||||
*msg_p += linelen;
|
||||
if (!linelen || is_empty_line(line, &linelen))
|
||||
break;
|
||||
|
||||
strbuf_grow(&title, linelen + 2);
|
||||
if (title.len) {
|
||||
if (fmt == CMIT_FMT_EMAIL) {
|
||||
strbuf_addch(&title, '\n');
|
||||
}
|
||||
strbuf_addch(&title, ' ');
|
||||
}
|
||||
strbuf_add(&title, line, linelen);
|
||||
}
|
||||
|
||||
strbuf_grow(sb, title.len + 1024);
|
||||
if (subject) {
|
||||
strbuf_addstr(sb, subject);
|
||||
add_rfc2047(sb, title.buf, title.len, encoding);
|
||||
} else {
|
||||
strbuf_addbuf(sb, &title);
|
||||
}
|
||||
strbuf_addch(sb, '\n');
|
||||
|
||||
if (plain_non_ascii) {
|
||||
const char *header_fmt =
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=%s\n"
|
||||
"Content-Transfer-Encoding: 8bit\n";
|
||||
strbuf_addf(sb, header_fmt, encoding);
|
||||
}
|
||||
if (after_subject) {
|
||||
strbuf_addstr(sb, after_subject);
|
||||
}
|
||||
if (fmt == CMIT_FMT_EMAIL) {
|
||||
strbuf_addch(sb, '\n');
|
||||
}
|
||||
strbuf_release(&title);
|
||||
}
|
||||
|
||||
static void pp_remainder(enum cmit_fmt fmt,
|
||||
const char **msg_p,
|
||||
struct strbuf *sb,
|
||||
int indent)
|
||||
{
|
||||
int first = 1;
|
||||
for (;;) {
|
||||
const char *line = *msg_p;
|
||||
int linelen = get_one_line(line);
|
||||
*msg_p += linelen;
|
||||
|
||||
if (!linelen)
|
||||
break;
|
||||
|
||||
if (is_empty_line(line, &linelen)) {
|
||||
if (first)
|
||||
continue;
|
||||
if (fmt == CMIT_FMT_SHORT)
|
||||
break;
|
||||
}
|
||||
first = 0;
|
||||
|
||||
strbuf_grow(sb, linelen + indent + 20);
|
||||
if (indent) {
|
||||
memset(sb->buf + sb->len, ' ', indent);
|
||||
strbuf_setlen(sb, sb->len + indent);
|
||||
}
|
||||
strbuf_add(sb, line, linelen);
|
||||
strbuf_addch(sb, '\n');
|
||||
}
|
||||
}
|
||||
|
||||
void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
|
||||
struct strbuf *sb, int abbrev,
|
||||
const char *subject, const char *after_subject,
|
||||
enum date_mode dmode, int plain_non_ascii)
|
||||
{
|
||||
unsigned long beginning_of_body;
|
||||
int indent = 4;
|
||||
const char *msg = commit->buffer;
|
||||
char *reencoded;
|
||||
const char *encoding;
|
||||
|
||||
if (fmt == CMIT_FMT_USERFORMAT) {
|
||||
format_commit_message(commit, user_format, sb);
|
||||
return;
|
||||
}
|
||||
|
||||
encoding = (git_log_output_encoding
|
||||
? git_log_output_encoding
|
||||
: git_commit_encoding);
|
||||
if (!encoding)
|
||||
encoding = "utf-8";
|
||||
reencoded = logmsg_reencode(commit, encoding);
|
||||
if (reencoded) {
|
||||
msg = reencoded;
|
||||
}
|
||||
|
||||
if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
|
||||
indent = 0;
|
||||
|
||||
/* After-subject is used to pass in Content-Type: multipart
|
||||
* MIME header; in that case we do not have to do the
|
||||
* plaintext content type even if the commit message has
|
||||
* non 7-bit ASCII character. Otherwise, check if we need
|
||||
* to say this is not a 7-bit ASCII.
|
||||
*/
|
||||
if (fmt == CMIT_FMT_EMAIL && !after_subject) {
|
||||
int i, ch, in_body;
|
||||
|
||||
for (in_body = i = 0; (ch = msg[i]); i++) {
|
||||
if (!in_body) {
|
||||
/* author could be non 7-bit ASCII but
|
||||
* the log may be so; skip over the
|
||||
* header part first.
|
||||
*/
|
||||
if (ch == '\n' && msg[i+1] == '\n')
|
||||
in_body = 1;
|
||||
}
|
||||
else if (non_ascii(ch)) {
|
||||
plain_non_ascii = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pp_header(fmt, abbrev, dmode, encoding, commit, &msg, sb);
|
||||
if (fmt != CMIT_FMT_ONELINE && !subject) {
|
||||
strbuf_addch(sb, '\n');
|
||||
}
|
||||
|
||||
/* Skip excess blank lines at the beginning of body, if any... */
|
||||
for (;;) {
|
||||
int linelen = get_one_line(msg);
|
||||
int ll = linelen;
|
||||
if (!linelen)
|
||||
break;
|
||||
if (!is_empty_line(msg, &ll))
|
||||
break;
|
||||
msg += linelen;
|
||||
}
|
||||
|
||||
/* These formats treat the title line specially. */
|
||||
if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
|
||||
pp_title_line(fmt, &msg, sb, subject,
|
||||
after_subject, encoding, plain_non_ascii);
|
||||
|
||||
beginning_of_body = sb->len;
|
||||
if (fmt != CMIT_FMT_ONELINE)
|
||||
pp_remainder(fmt, &msg, sb, indent);
|
||||
strbuf_rtrim(sb);
|
||||
|
||||
/* Make sure there is an EOLN for the non-oneline case */
|
||||
if (fmt != CMIT_FMT_ONELINE)
|
||||
strbuf_addch(sb, '\n');
|
||||
|
||||
/*
|
||||
* The caller may append additional body text in e-mail
|
||||
* format. Make sure we did not strip the blank line
|
||||
* between the header and the body.
|
||||
*/
|
||||
if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
|
||||
strbuf_addch(sb, '\n');
|
||||
free(reencoded);
|
||||
}
|
5
quote.c
5
quote.c
|
@ -26,7 +26,7 @@ void sq_quote_buf(struct strbuf *dst, const char *src)
|
|||
|
||||
strbuf_addch(dst, '\'');
|
||||
while (*src) {
|
||||
size_t len = strcspn(src, "'\\");
|
||||
size_t len = strcspn(src, "'!");
|
||||
strbuf_add(dst, src, len);
|
||||
src += len;
|
||||
while (need_bs_quote(*src)) {
|
||||
|
@ -131,7 +131,8 @@ static signed char const sq_lookup[256] = {
|
|||
/* 0x80 */ /* set to 0 */
|
||||
};
|
||||
|
||||
static inline int sq_must_quote(char c) {
|
||||
static inline int sq_must_quote(char c)
|
||||
{
|
||||
return sq_lookup[(unsigned char)c] + quote_path_fully > 0;
|
||||
}
|
||||
|
||||
|
|
10
setup.c
10
setup.c
|
@ -206,6 +206,16 @@ static const char *set_work_tree(const char *dir)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void setup_work_tree(void)
|
||||
{
|
||||
const char *work_tree = get_git_work_tree();
|
||||
const char *git_dir = get_git_dir();
|
||||
if (!is_absolute_path(git_dir))
|
||||
set_git_dir(make_absolute_path(git_dir));
|
||||
if (!work_tree || chdir(work_tree))
|
||||
die("This operation must be run in a work tree");
|
||||
}
|
||||
|
||||
/*
|
||||
* We cannot decide in this function whether we are in the work tree or
|
||||
* not, since the config can only be read _after_ this function was called.
|
||||
|
|
8
strbuf.h
8
strbuf.h
|
@ -23,12 +23,12 @@
|
|||
* that way:
|
||||
*
|
||||
* strbuf_grow(sb, SOME_SIZE);
|
||||
* // ... here the memory areay starting at sb->buf, and of length
|
||||
* // sb_avail(sb) is all yours, and you are sure that sb_avail(sb) is at
|
||||
* // least SOME_SIZE
|
||||
* ... Here, the memory array starting at sb->buf, and of length
|
||||
* ... strbuf_avail(sb) is all yours, and you are sure that
|
||||
* ... strbuf_avail(sb) is at least SOME_SIZE.
|
||||
* strbuf_setlen(sb, sb->len + SOME_OTHER_SIZE);
|
||||
*
|
||||
* Of course, SOME_OTHER_SIZE must be smaller or equal to sb_avail(sb).
|
||||
* Of course, SOME_OTHER_SIZE must be smaller or equal to strbuf_avail(sb).
|
||||
*
|
||||
* Doing so is safe, though if it has to be done in many places, adding the
|
||||
* missing API to the strbuf module is the way to go.
|
||||
|
|
|
@ -205,7 +205,7 @@ test_expect_success \
|
|||
echo $h_TEST >.git/MERGE_HEAD &&
|
||||
GIT_AUTHOR_DATE="2005-05-26 23:45" \
|
||||
GIT_COMMITTER_DATE="2005-05-26 23:45" git-commit -F M &&
|
||||
h_MERGED=$(git rev-parse --verify HEAD)
|
||||
h_MERGED=$(git rev-parse --verify HEAD) &&
|
||||
rm -f M'
|
||||
|
||||
cat >expect <<EOF
|
||||
|
|
123
t/t3502-cherry-pick-merge.sh
Executable file
123
t/t3502-cherry-pick-merge.sh
Executable file
|
@ -0,0 +1,123 @@
|
|||
#!/bin/sh
|
||||
|
||||
test_description='cherry picking and reverting a merge
|
||||
|
||||
b---c
|
||||
/ /
|
||||
initial---a
|
||||
|
||||
'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success setup '
|
||||
|
||||
>A &&
|
||||
>B &&
|
||||
git add A B &&
|
||||
git commit -m "Initial" &&
|
||||
git tag initial &&
|
||||
git branch side &&
|
||||
echo new line >A &&
|
||||
git commit -m "add line to A" A &&
|
||||
git tag a &&
|
||||
git checkout side &&
|
||||
echo new line >B &&
|
||||
git commit -m "add line to B" B &&
|
||||
git tag b &&
|
||||
git checkout master &&
|
||||
git merge side &&
|
||||
git tag c
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'cherry-pick a non-merge with -m should fail' '
|
||||
|
||||
git reset --hard &&
|
||||
git checkout a^0 &&
|
||||
! git cherry-pick -m 1 b &&
|
||||
git diff --exit-code a --
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'cherry pick a merge without -m should fail' '
|
||||
|
||||
git reset --hard &&
|
||||
git checkout a^0 &&
|
||||
! git cherry-pick c &&
|
||||
git diff --exit-code a --
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'cherry pick a merge (1)' '
|
||||
|
||||
git reset --hard &&
|
||||
git checkout a^0 &&
|
||||
git cherry-pick -m 1 c &&
|
||||
git diff --exit-code c
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'cherry pick a merge (2)' '
|
||||
|
||||
git reset --hard &&
|
||||
git checkout b^0 &&
|
||||
git cherry-pick -m 2 c &&
|
||||
git diff --exit-code c
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'cherry pick a merge relative to nonexistent parent should fail' '
|
||||
|
||||
git reset --hard &&
|
||||
git checkout b^0 &&
|
||||
! git cherry-pick -m 3 c
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'revert a non-merge with -m should fail' '
|
||||
|
||||
git reset --hard &&
|
||||
git checkout c^0 &&
|
||||
! git revert -m 1 b &&
|
||||
git diff --exit-code c
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'revert a merge without -m should fail' '
|
||||
|
||||
git reset --hard &&
|
||||
git checkout c^0 &&
|
||||
! git revert c &&
|
||||
git diff --exit-code c
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'revert a merge (1)' '
|
||||
|
||||
git reset --hard &&
|
||||
git checkout c^0 &&
|
||||
git revert -m 1 c &&
|
||||
git diff --exit-code a --
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'revert a merge (2)' '
|
||||
|
||||
git reset --hard &&
|
||||
git checkout c^0 &&
|
||||
git revert -m 2 c &&
|
||||
git diff --exit-code b --
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'revert a merge relative to nonexistent parent should fail' '
|
||||
|
||||
git reset --hard &&
|
||||
git checkout c^0 &&
|
||||
! git revert -m 3 c &&
|
||||
git diff --exit-code c
|
||||
|
||||
'
|
||||
|
||||
test_done
|
42
t/t4021-format-patch-signer-mime.sh
Executable file
42
t/t4021-format-patch-signer-mime.sh
Executable file
|
@ -0,0 +1,42 @@
|
|||
#!/bin/sh
|
||||
|
||||
test_description='format-patch -s should force MIME encoding as needed'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success setup '
|
||||
|
||||
>F &&
|
||||
git add F &&
|
||||
git commit -m initial &&
|
||||
echo new line >F &&
|
||||
|
||||
test_tick &&
|
||||
git commit -m "This adds some lines to F" F
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'format normally' '
|
||||
|
||||
git format-patch --stdout -1 >output &&
|
||||
! grep Content-Type output
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'format with signoff without funny signer name' '
|
||||
|
||||
git format-patch -s --stdout -1 >output &&
|
||||
! grep Content-Type output
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'format with non ASCII signer name' '
|
||||
|
||||
GIT_COMMITTER_NAME="$B$O$^$N(B $B$U$K$*$&(B" \
|
||||
git format-patch -s --stdout -1 >output &&
|
||||
grep Content-Type output
|
||||
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
@ -1,3 +1,6 @@
|
|||
|
||||
|
||||
|
||||
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
|
||||
|
|
|
@ -208,4 +208,11 @@ test_expect_success 'fetch with a non-applying branch.<name>.merge' '
|
|||
git fetch blub
|
||||
'
|
||||
|
||||
# the strange name is: a\!'b
|
||||
test_expect_success 'quoting of a strangely named repo' '
|
||||
! git fetch "a\\!'\''b" > result 2>&1 &&
|
||||
cat result &&
|
||||
grep "fatal: '\''a\\\\!'\''b'\''" result
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
@ -402,4 +402,11 @@ test_expect_success 'test resetting the index at give paths' '
|
|||
|
||||
'
|
||||
|
||||
test_expect_success 'resetting an unmodified path is a no-op' '
|
||||
git reset --hard &&
|
||||
git reset -- file1 &&
|
||||
git diff-files --exit-code &&
|
||||
git diff-index --cached --exit-code HEAD
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
@ -77,7 +77,7 @@ test_expect_success "checkout with dirty tree without -m" '
|
|||
test_expect_success "checkout -m with dirty tree" '
|
||||
|
||||
git checkout -f master &&
|
||||
git clean &&
|
||||
git clean -f &&
|
||||
|
||||
fill 0 1 2 3 4 5 6 7 8 >one &&
|
||||
git checkout -m side &&
|
||||
|
@ -99,7 +99,7 @@ test_expect_success "checkout -m with dirty tree" '
|
|||
|
||||
test_expect_success "checkout -m with dirty tree, renamed" '
|
||||
|
||||
git checkout -f master && git clean &&
|
||||
git checkout -f master && git clean -f &&
|
||||
|
||||
fill 1 2 3 4 5 7 8 >one &&
|
||||
if git checkout renamer
|
||||
|
@ -121,7 +121,7 @@ test_expect_success "checkout -m with dirty tree, renamed" '
|
|||
|
||||
test_expect_success 'checkout -m with merge conflict' '
|
||||
|
||||
git checkout -f master && git clean &&
|
||||
git checkout -f master && git clean -f &&
|
||||
|
||||
fill 1 T 3 4 5 6 S 8 >one &&
|
||||
if git checkout renamer
|
||||
|
@ -144,7 +144,7 @@ test_expect_success 'checkout -m with merge conflict' '
|
|||
|
||||
test_expect_success 'checkout to detach HEAD' '
|
||||
|
||||
git checkout -f renamer && git clean &&
|
||||
git checkout -f renamer && git clean -f &&
|
||||
git checkout renamer^ &&
|
||||
H=$(git rev-parse --verify HEAD) &&
|
||||
M=$(git show-ref -s --verify refs/heads/master) &&
|
||||
|
@ -160,7 +160,7 @@ test_expect_success 'checkout to detach HEAD' '
|
|||
|
||||
test_expect_success 'checkout to detach HEAD with branchname^' '
|
||||
|
||||
git checkout -f master && git clean &&
|
||||
git checkout -f master && git clean -f &&
|
||||
git checkout renamer^ &&
|
||||
H=$(git rev-parse --verify HEAD) &&
|
||||
M=$(git show-ref -s --verify refs/heads/master) &&
|
||||
|
@ -176,7 +176,7 @@ test_expect_success 'checkout to detach HEAD with branchname^' '
|
|||
|
||||
test_expect_success 'checkout to detach HEAD with HEAD^0' '
|
||||
|
||||
git checkout -f master && git clean &&
|
||||
git checkout -f master && git clean -f &&
|
||||
git checkout HEAD^0 &&
|
||||
H=$(git rev-parse --verify HEAD) &&
|
||||
M=$(git show-ref -s --verify refs/heads/master) &&
|
||||
|
|
114
t/t7300-clean.sh
114
t/t7300-clean.sh
|
@ -7,6 +7,8 @@ test_description='git-clean basic tests'
|
|||
|
||||
. ./test-lib.sh
|
||||
|
||||
git config clean.requireForce no
|
||||
|
||||
test_expect_success 'setup' '
|
||||
|
||||
mkdir -p src &&
|
||||
|
@ -37,6 +39,93 @@ test_expect_success 'git-clean' '
|
|||
|
||||
'
|
||||
|
||||
test_expect_success 'git-clean src/' '
|
||||
|
||||
mkdir -p build docs &&
|
||||
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
|
||||
git-clean src/ &&
|
||||
test -f Makefile &&
|
||||
test -f README &&
|
||||
test -f src/part1.c &&
|
||||
test -f src/part2.c &&
|
||||
test -f a.out &&
|
||||
test ! -f src/part3.c &&
|
||||
test -f docs/manual.txt &&
|
||||
test -f obj.o &&
|
||||
test -f build/lib.so
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'git-clean src/ src/' '
|
||||
|
||||
mkdir -p build docs &&
|
||||
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
|
||||
git-clean src/ src/ &&
|
||||
test -f Makefile &&
|
||||
test -f README &&
|
||||
test -f src/part1.c &&
|
||||
test -f src/part2.c &&
|
||||
test -f a.out &&
|
||||
test ! -f src/part3.c &&
|
||||
test -f docs/manual.txt &&
|
||||
test -f obj.o &&
|
||||
test -f build/lib.so
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'git-clean with prefix' '
|
||||
|
||||
mkdir -p build docs &&
|
||||
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
|
||||
(cd src/ && git-clean) &&
|
||||
test -f Makefile &&
|
||||
test -f README &&
|
||||
test -f src/part1.c &&
|
||||
test -f src/part2.c &&
|
||||
test -f a.out &&
|
||||
test ! -f src/part3.c &&
|
||||
test -f docs/manual.txt &&
|
||||
test -f obj.o &&
|
||||
test -f build/lib.so
|
||||
|
||||
'
|
||||
test_expect_success 'git-clean -d with prefix and path' '
|
||||
|
||||
mkdir -p build docs src/feature &&
|
||||
touch a.out src/part3.c src/feature/file.c docs/manual.txt obj.o build/lib.so &&
|
||||
(cd src/ && git-clean -d feature/) &&
|
||||
test -f Makefile &&
|
||||
test -f README &&
|
||||
test -f src/part1.c &&
|
||||
test -f src/part2.c &&
|
||||
test -f a.out &&
|
||||
test -f src/part3.c &&
|
||||
test ! -f src/feature/file.c &&
|
||||
test -f docs/manual.txt &&
|
||||
test -f obj.o &&
|
||||
test -f build/lib.so
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'git-clean symbolic link' '
|
||||
|
||||
mkdir -p build docs &&
|
||||
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
|
||||
ln -s docs/manual.txt src/part4.c
|
||||
git-clean &&
|
||||
test -f Makefile &&
|
||||
test -f README &&
|
||||
test -f src/part1.c &&
|
||||
test -f src/part2.c &&
|
||||
test ! -f a.out &&
|
||||
test ! -f src/part3.c &&
|
||||
test ! -f src/part4.c &&
|
||||
test -f docs/manual.txt &&
|
||||
test -f obj.o &&
|
||||
test -f build/lib.so
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'git-clean -n' '
|
||||
|
||||
mkdir -p build docs &&
|
||||
|
@ -71,6 +160,24 @@ test_expect_success 'git-clean -d' '
|
|||
|
||||
'
|
||||
|
||||
test_expect_success 'git-clean -d src/ examples/' '
|
||||
|
||||
mkdir -p build docs examples &&
|
||||
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so examples/1.c &&
|
||||
git-clean -d src/ examples/ &&
|
||||
test -f Makefile &&
|
||||
test -f README &&
|
||||
test -f src/part1.c &&
|
||||
test -f src/part2.c &&
|
||||
test -f a.out &&
|
||||
test ! -f src/part3.c &&
|
||||
test ! -f examples/1.c &&
|
||||
test -f docs/manual.txt &&
|
||||
test -f obj.o &&
|
||||
test -f build/lib.so
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'git-clean -x' '
|
||||
|
||||
mkdir -p build docs &&
|
||||
|
@ -139,6 +246,13 @@ test_expect_success 'git-clean -d -X' '
|
|||
|
||||
'
|
||||
|
||||
test_expect_success 'clean.requireForce defaults to true' '
|
||||
|
||||
git config --unset clean.requireForce &&
|
||||
! git-clean
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'clean.requireForce' '
|
||||
|
||||
git config clean.requireForce true &&
|
||||
|
|
56
t/t9106-git-svn-dcommit-clobber-series.sh
Executable file
56
t/t9106-git-svn-dcommit-clobber-series.sh
Executable file
|
@ -0,0 +1,56 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2007 Eric Wong
|
||||
test_description='git-svn dcommit clobber series'
|
||||
. ./lib-git-svn.sh
|
||||
|
||||
test_expect_success 'initialize repo' "
|
||||
mkdir import &&
|
||||
cd import &&
|
||||
awk 'BEGIN { for (i = 1; i < 64; i++) { print i } }' > file
|
||||
svn import -m 'initial' . $svnrepo &&
|
||||
cd .. &&
|
||||
git svn init $svnrepo &&
|
||||
git svn fetch &&
|
||||
test -e file
|
||||
"
|
||||
|
||||
test_expect_success '(supposedly) non-conflicting change from SVN' "
|
||||
test x\"\`sed -n -e 58p < file\`\" = x58 &&
|
||||
test x\"\`sed -n -e 61p < file\`\" = x61 &&
|
||||
svn co $svnrepo tmp &&
|
||||
cd tmp &&
|
||||
perl -i -p -e 's/^58\$/5588/' file &&
|
||||
perl -i -p -e 's/^61\$/6611/' file &&
|
||||
test x\"\`sed -n -e 58p < file\`\" = x5588 &&
|
||||
test x\"\`sed -n -e 61p < file\`\" = x6611 &&
|
||||
svn commit -m '58 => 5588, 61 => 6611' &&
|
||||
cd ..
|
||||
"
|
||||
|
||||
test_expect_success 'some unrelated changes to git' "
|
||||
echo hi > life &&
|
||||
git update-index --add life &&
|
||||
git commit -m hi-life &&
|
||||
echo bye >> life &&
|
||||
git commit -m bye-life life
|
||||
"
|
||||
|
||||
test_expect_success 'change file but in unrelated area' "
|
||||
test x\"\`sed -n -e 4p < file\`\" = x4 &&
|
||||
test x\"\`sed -n -e 7p < file\`\" = x7 &&
|
||||
perl -i -p -e 's/^4\$/4444/' file &&
|
||||
perl -i -p -e 's/^7\$/7777/' file &&
|
||||
test x\"\`sed -n -e 4p < file\`\" = x4444 &&
|
||||
test x\"\`sed -n -e 7p < file\`\" = x7777 &&
|
||||
git commit -m '4 => 4444, 7 => 7777' file &&
|
||||
git svn dcommit &&
|
||||
svn up tmp &&
|
||||
cd tmp &&
|
||||
test x\"\`sed -n -e 4p < file\`\" = x4444 &&
|
||||
test x\"\`sed -n -e 7p < file\`\" = x7777 &&
|
||||
test x\"\`sed -n -e 58p < file\`\" = x5588 &&
|
||||
test x\"\`sed -n -e 61p < file\`\" = x6611
|
||||
"
|
||||
|
||||
test_done
|
|
@ -86,4 +86,9 @@ test_expect_success 'verify post-merge ancestry' "
|
|||
git cat-file commit refs/heads/svn^ | grep '^friend$'
|
||||
"
|
||||
|
||||
test_expect_success 'verify merge commit message' "
|
||||
git rev-list --pretty=raw -1 refs/heads/svn | \
|
||||
grep \" Merge branch 'merge' into svn\"
|
||||
"
|
||||
|
||||
test_done
|
||||
|
|
|
@ -31,7 +31,6 @@ our \$projects_list = "";
|
|||
our \$export_ok = "";
|
||||
our \$strict_export = "";
|
||||
|
||||
CGI::Carp::set_programname("gitweb/gitweb.cgi");
|
||||
EOF
|
||||
|
||||
cat >.git/description <<EOF
|
||||
|
@ -558,4 +557,27 @@ test_expect_success \
|
|||
'gitweb_run "p=.git;a=tree;opt=--no-merges"'
|
||||
test_debug 'cat gitweb.log'
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# gitweb config and repo config
|
||||
|
||||
cat >>gitweb_config.perl <<EOF
|
||||
|
||||
\$feature{'blame'}{'override'} = 1;
|
||||
\$feature{'snapshot'}{'override'} = 1;
|
||||
EOF
|
||||
|
||||
test_expect_success \
|
||||
'config override: tree view, features disabled in repo config' \
|
||||
'git config gitweb.blame no &&
|
||||
git config gitweb.snapshot none &&
|
||||
gitweb_run "p=.git;a=tree"'
|
||||
test_debug 'cat gitweb.log'
|
||||
|
||||
test_expect_success \
|
||||
'config override: tree view, features enabled in repo config' \
|
||||
'git config gitweb.blame yes &&
|
||||
git config gitweb.snapshot "zip,tgz, tbz2" &&
|
||||
gitweb_run "p=.git;a=tree"'
|
||||
test_debug 'cat gitweb.log'
|
||||
|
||||
test_done
|
||||
|
|
|
@ -10,6 +10,12 @@
|
|||
# hooks.allowunannotated
|
||||
# This boolean sets whether unannotated tags will be allowed into the
|
||||
# repository. By default they won't be.
|
||||
# hooks.allowdeletetag
|
||||
# This boolean sets whether deleting tags will be allowed in the
|
||||
# repository. By default they won't be.
|
||||
# hooks.allowdeletebranch
|
||||
# This boolean sets whether deleting branches will be allowed in the
|
||||
# repository. By default they won't be.
|
||||
#
|
||||
|
||||
# --- Command line
|
||||
|
@ -32,18 +38,20 @@ fi
|
|||
|
||||
# --- Config
|
||||
allowunannotated=$(git-repo-config --bool hooks.allowunannotated)
|
||||
allowdeletebranch=$(git-repo-config --bool hooks.allowdeletebranch)
|
||||
allowdeletetag=$(git-repo-config --bool hooks.allowdeletetag)
|
||||
|
||||
# check for no description
|
||||
projectdesc=$(sed -e '1p' "$GIT_DIR/description")
|
||||
if [ -z "$projectdesc" -o "$projectdesc" = "Unnamed repository; edit this file to name it for gitweb" ]; then
|
||||
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
|
||||
if [ -z "$projectdesc" -o "$projectdesc" = "Unnamed repository; edit this file to name it for gitweb." ]; then
|
||||
echo "*** Project description file hasn't been set" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Check types
|
||||
# if $newrev is 0000...0000, it's a commit to delete a branch
|
||||
# if $newrev is 0000...0000, it's a commit to delete a ref.
|
||||
if [ "$newrev" = "0000000000000000000000000000000000000000" ]; then
|
||||
newrev_type=commit
|
||||
newrev_type=delete
|
||||
else
|
||||
newrev_type=$(git-cat-file -t $newrev)
|
||||
fi
|
||||
|
@ -58,15 +66,36 @@ case "$refname","$newrev_type" in
|
|||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/tags/*,delete)
|
||||
# delete tag
|
||||
if [ "$allowdeletetag" != "true" ]; then
|
||||
echo "*** Deleting a tag is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/tags/*,tag)
|
||||
# annotated tag
|
||||
;;
|
||||
refs/heads/*,commit)
|
||||
# branch
|
||||
;;
|
||||
refs/heads/*,delete)
|
||||
# delete branch
|
||||
if [ "$allowdeletebranch" != "true" ]; then
|
||||
echo "*** Deleting a branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/remotes/*,commit)
|
||||
# tracking branch
|
||||
;;
|
||||
refs/remotes/*,delete)
|
||||
# delete tracking branch
|
||||
if [ "$allowdeletebranch" != "true" ]; then
|
||||
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# Anything else (is there anything else?)
|
||||
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
|
||||
|
|
|
@ -381,7 +381,8 @@ static int disconnect_walker(struct transport *transport)
|
|||
}
|
||||
|
||||
#ifndef NO_CURL
|
||||
static int curl_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) {
|
||||
static int curl_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags)
|
||||
{
|
||||
const char **argv;
|
||||
int argc;
|
||||
int err;
|
||||
|
@ -647,7 +648,8 @@ static int fetch_refs_via_pack(struct transport *transport,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int git_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) {
|
||||
static int git_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags)
|
||||
{
|
||||
struct git_transport_data *data = transport->data;
|
||||
struct send_pack_args args;
|
||||
|
||||
|
|
Loading…
Reference in a new issue