summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/technical/racy-git.txt193
-rw-r--r--Makefile13
-rw-r--r--blame.c11
-rw-r--r--builtin-apply.c265
-rw-r--r--builtin-cat-file.c9
-rw-r--r--builtin-checkout-index.c3
-rw-r--r--builtin-diff.c3
-rw-r--r--builtin-fmt-merge-msg.c2
-rw-r--r--builtin-grep.c61
-rw-r--r--builtin-ls-files.c27
-rw-r--r--builtin-ls-tree.c6
-rw-r--r--builtin-mailinfo.c6
-rw-r--r--builtin-mv.c24
-rw-r--r--builtin-name-rev.c2
-rw-r--r--builtin-pack-objects.c28
-rw-r--r--builtin-prune.c2
-rw-r--r--builtin-push.c14
-rw-r--r--builtin-read-tree.c2
-rw-r--r--builtin-repo-config.c16
-rw-r--r--builtin-rev-list.c6
-rw-r--r--builtin-rev-parse.c10
-rw-r--r--builtin-show-branch.c6
-rw-r--r--builtin-update-index.c2
-rw-r--r--cache.h4
-rw-r--r--check-racy.c28
-rw-r--r--combine-diff.c15
-rw-r--r--commit.c6
-rw-r--r--configure.ac7
-rw-r--r--connect.c17
-rw-r--r--contrib/emacs/vc-git.el2
-rw-r--r--csum-file.c4
-rw-r--r--daemon.c20
-rw-r--r--describe.c6
-rw-r--r--diff.c10
-rw-r--r--environment.c10
-rw-r--r--exec_cmd.c2
-rw-r--r--fetch-clone.c3
-rw-r--r--fetch-pack.c6
-rw-r--r--fsck-objects.c21
-rw-r--r--git.c2
-rw-r--r--gitweb/gitweb.css28
-rwxr-xr-xgitweb/gitweb.perl953
-rw-r--r--help.c2
-rw-r--r--http-fetch.c8
-rw-r--r--http-push.c21
-rw-r--r--local-fetch.c8
-rw-r--r--merge-base.c2
-rw-r--r--merge-index.c5
-rw-r--r--mktree.c1
-rw-r--r--pack-redundant.c4
-rw-r--r--read-cache.c91
-rw-r--r--receive-pack.c6
-rw-r--r--run-command.c8
-rw-r--r--send-pack.c11
-rw-r--r--sha1_file.c2
-rw-r--r--sha1_name.c2
-rw-r--r--ssh-fetch.c8
-rw-r--r--ssh-upload.c4
-rwxr-xr-xt/t4116-apply-reverse.sh46
-rwxr-xr-xt/t7001-mv.sh4
-rw-r--r--tree-diff.c12
-rw-r--r--tree.c3
-rw-r--r--unpack-trees.c2
-rw-r--r--upload-pack.c19
64 files changed, 1274 insertions, 850 deletions
diff --git a/Documentation/technical/racy-git.txt b/Documentation/technical/racy-git.txt
new file mode 100644
index 0000000000..7597d04142
--- /dev/null
+++ b/Documentation/technical/racy-git.txt
@@ -0,0 +1,193 @@
+Use of index and Racy git problem
+=================================
+
+Background
+----------
+
+The index is one of the most important data structure in git.
+It represents a virtual working tree state by recording list of
+paths and their object names and serves as a staging area to
+write out the next tree object to be committed. The state is
+"virtual" in the sense that it does not necessarily have to, and
+often does not, match the files in the working tree.
+
+There are cases git needs to examine the differences between the
+virtual working tree state in the index and the files in the
+working tree. The most obvious case is when the user asks `git
+diff` (or its low level implementation, `git diff-files`) or
+`git-ls-files --modified`. In addition, git internally checks
+if the files in the working tree is different from what are
+recorded in the index to avoid stomping on local changes in them
+during patch application, switching branches, and merging.
+
+In order to speed up this comparison between the files in the
+working tree and the index entries, the index entries record the
+information obtained from the filesystem via `lstat(2)` system
+call when they were last updated. When checking if they differ,
+git first runs `lstat(2)` on the files and compare the result
+with this information (this is what was originally done by the
+`ce_match_stat()` function, which the current code does in
+`ce_match_stat_basic()` function). If some of these "cached
+stat information" fields do not match, git can tell that the
+files are modified without even looking at their contents.
+
+Note: not all members in `struct stat` obtained via `lstat(2)`
+are used for this comparison. For example, `st_atime` obviously
+is not useful. Currently, git compares the file type (regular
+files vs symbolic links) and executable bits (only for regular
+files) from `st_mode` member, `st_mtime` and `st_ctime`
+timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members.
+With a `USE_STDEV` compile-time option, `st_dev` is also
+compared, but this is not enabled by default because this member
+is not stable on network filesystems. With `USE_NSEC`
+compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`
+members are also compared, but this is not enabled by default
+because the value of this member becomes meaningless once the
+inode is evicted from the inode cache on filesystems that do not
+store it on disk.
+
+
+Racy git
+--------
+
+There is one slight problem with the optimization based on the
+cached stat information. Consider this sequence:
+
+ $ git update-index 'foo'
+ : modify 'foo' in-place without changing its size
+
+The first `update-index` computes the object name of the
+contents of file `foo` and updates the index entry for `foo`
+along with the `struct stat` information. If the modification
+that follows it happens very fast so that the file's `st_mtime`
+timestamp does not change, after this sequence, the cached stat
+information the index entry records still exactly match what you
+can obtain from the filesystem, but the file `foo` is modified.
+This way, git can incorrectly think files in the working tree
+are unmodified even though they actually are. This is called
+the "racy git" problem (discovered by Pasky), and the entries
+that appear clean when they may not be because of this problem
+are called "racily clean".
+
+To avoid this problem, git does two things:
+
+. When the cached stat information says the file has not been
+ modified, and the `st_mtime` is the same as (or newer than)
+ the timestamp of the index file itself (which is the time `git
+ update-index foo` finished running in the above example), it
+ also compares the contents with the object registered in the
+ index entry to make sure they match.
+
+. When the index file is updated that contains racily clean
+ entries, cached `st_size` information is truncated to zero
+ before writing a new version of the index file.
+
+Because the index file itself is written after collecting all
+the stat information from updated paths, `st_mtime` timestamp of
+it is usually the same as or newer than any of the paths the
+index contains. And no matter how quick the modification that
+follows `git update-index foo` finishes, the resulting
+`st_mtime` timestamp on `foo` cannot get the timestamp earlier
+than the index file. Therefore, index entries that can be
+racily clean are limited to the ones that have the same
+timestamp as the index file itself.
+
+The callers that want to check if an index entry matches the
+corresponding file in the working tree continue to call
+`ce_match_stat()`, but with this change, `ce_match_stat()` uses
+`ce_modified_check_fs()` to see if racily clean ones are
+actually clean after comparing the cached stat information using
+`ce_match_stat_basic()`.
+
+The problem the latter solves is this sequence:
+
+ $ git update-index 'foo'
+ : modify 'foo' in-place without changing its size
+ : wait for enough time
+ $ git update-index 'bar'
+
+Without the latter, the timestamp of the index file gets a newer
+value, and falsely clean entry `foo` would not be caught by the
+timestamp comparison check done with the former logic anymore.
+The latter makes sure that the cached stat information for `foo`
+would never match with the file in the working tree, so later
+checks by `ce_match_stat_basic()` would report the index entry
+does not match the file and git does not have to fall back on more
+expensive `ce_modified_check_fs()`.
+
+
+Runtime penalty
+---------------
+
+The runtime penalty of falling back to `ce_modified_check_fs()`
+from `ce_match_stat()` can be very expensive when there are many
+racily clean entries. An obvious way to artificially create
+this situation is to give the same timestamp to all the files in
+the working tree in a large project, run `git update-index` on
+them, and give the same timestamp to the index file:
+
+ $ date >.datestamp
+ $ git ls-files | xargs touch -r .datestamp
+ $ git ls-files | git update-index --stdin
+ $ touch -r .datestamp .git/index
+
+This will make all index entries racily clean. The linux-2.6
+project, for example, there are over 20,000 files in the working
+tree. On my Athron 64X2 3800+, after the above:
+
+ $ /usr/bin/time git diff-files
+ 1.68user 0.54system 0:02.22elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k
+ 0inputs+0outputs (0major+67111minor)pagefaults 0swaps
+ $ git update-index MAINTAINERS
+ $ /usr/bin/time git diff-files
+ 0.02user 0.12system 0:00.14elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k
+ 0inputs+0outputs (0major+935minor)pagefaults 0swaps
+
+Running `git update-index` in the middle checked the racily
+clean entries, and left the cached `st_mtime` for all the paths
+intact because they were actually clean (so this step took about
+the same amount of time as the first `git diff-files`). After
+that, they are not racily clean anymore but are truly clean, so
+the second invocation of `git diff-files` fully took advantage
+of the cached stat information.
+
+
+Avoiding runtime penalty
+------------------------
+
+In order to avoid the above runtime penalty, the recent "master"
+branch (post 1.4.2) has a code that makes sure the index file
+gets timestamp newer than the youngest files in the index when
+there are many young files with the same timestamp as the
+resulting index file would otherwise would have by waiting
+before finishing writing the index file out.
+
+I suspect that in practice the situation where many paths in the
+index are all racily clean is quite rare. The only code paths
+that can record recent timestamp for large number of paths I
+know of are:
+
+. Initial `git add .` of a large project.
+
+. `git checkout` of a large project from an empty index into an
+ unpopulated working tree.
+
+Note: switching branches with `git checkout` keeps the cached
+stat information of existing working tree files that are the
+same between the current branch and the new branch, which are
+all older than the resulting index file, and they will not
+become racily clean. Only the files that are actually checked
+out can become racily clean.
+
+In a large project where raciness avoidance cost really matters,
+however, the initial computation of all object names in the
+index takes more than one second, and the index file is written
+out after all that happens. Therefore the timestamp of the
+index file will be more than one seconds later than the the
+youngest file in the working tree. This means that in these
+cases there actually will not be any racily clean entry in
+the resulting index.
+
+So in summary I think we should not worry about avoiding the
+runtime penalty and get rid of the "wait before finishing
+writing" code out.
diff --git a/Makefile b/Makefile
index a538710ed6..23cd8a017b 100644
--- a/Makefile
+++ b/Makefile
@@ -123,8 +123,10 @@ GIT_PYTHON_DIR = $(prefix)/share/git-core/python
# default configuration for gitweb
GITWEB_CONFIG = gitweb_config.perl
+GITWEB_HOME_LINK_STR = projects
GITWEB_SITENAME =
GITWEB_PROJECTROOT = /pub/git
+GITWEB_BASE_URL =
GITWEB_LIST =
GITWEB_HOMETEXT = indextext.html
GITWEB_CSS = gitweb.css
@@ -193,7 +195,11 @@ PROGRAMS = \
git-update-server-info$X \
git-upload-pack$X git-verify-pack$X \
git-pack-redundant$X git-var$X \
- git-describe$X git-merge-tree$X git-blame$X git-imap-send$X
+ git-describe$X git-merge-tree$X git-blame$X git-imap-send$X \
+ $(EXTRA_PROGRAMS)
+
+# Empty...
+EXTRA_PROGRAMS =
BUILT_INS = \
git-format-patch$X git-show$X git-whatchanged$X \
@@ -326,15 +332,16 @@ ifeq ($(uname_S),SunOS)
NEEDS_NSL = YesPlease
SHELL_PATH = /bin/bash
NO_STRCASESTR = YesPlease
- NO_STRLCPY = YesPlease
ifeq ($(uname_R),5.8)
NEEDS_LIBICONV = YesPlease
NO_UNSETENV = YesPlease
NO_SETENV = YesPlease
+ NO_C99_FORMAT = YesPlease
endif
ifeq ($(uname_R),5.9)
NO_UNSETENV = YesPlease
NO_SETENV = YesPlease
+ NO_C99_FORMAT = YesPlease
endif
INSTALL = ginstall
TAR = gtar
@@ -617,8 +624,10 @@ gitweb/gitweb.cgi: gitweb/gitweb.perl
-e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
-e 's|++GIT_BINDIR++|$(bindir)|g' \
-e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \
+ -e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \
-e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \
-e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \
+ -e 's|++GITWEB_BASE_URL++|$(GITWEB_BASE_URL)|g' \
-e 's|++GITWEB_LIST++|$(GITWEB_LIST)|g' \
-e 's|++GITWEB_HOMETEXT++|$(GITWEB_HOMETEXT)|g' \
-e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \
diff --git a/blame.c b/blame.c
index 7099b53c72..c253b9ca45 100644
--- a/blame.c
+++ b/blame.c
@@ -56,9 +56,9 @@ struct patch {
static void get_blob(struct commit *commit);
/* Only used for statistics */
-static int num_get_patch = 0;
-static int num_commits = 0;
-static int patch_time = 0;
+static int num_get_patch;
+static int num_commits;
+static int patch_time;
struct blame_diff_state {
struct xdiff_emit_state xm;
@@ -351,10 +351,7 @@ static int fill_util_info(struct commit *commit)
assert(util);
assert(util->pathname);
- if (get_blob_sha1(commit->tree, util->pathname, util->sha1))
- return 1;
- else
- return 0;
+ return !!get_blob_sha1(commit->tree, util->pathname, util->sha1);
}
static void alloc_line_map(struct commit *commit)
diff --git a/builtin-apply.c b/builtin-apply.c
index 9cf477c701..4f0eef0ac3 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -28,17 +28,18 @@ static int prefix_length = -1;
static int newfd = -1;
static int p_value = 1;
-static int allow_binary_replacement = 0;
-static int check_index = 0;
-static int write_index = 0;
-static int cached = 0;
-static int diffstat = 0;
-static int numstat = 0;
-static int summary = 0;
-static int check = 0;
+static int allow_binary_replacement;
+static int check_index;
+static int write_index;
+static int cached;
+static int diffstat;
+static int numstat;
+static int summary;
+static int check;
static int apply = 1;
-static int no_add = 0;
-static int show_index_info = 0;
+static int apply_in_reverse;
+static int no_add;
+static int show_index_info;
static int line_termination = '\n';
static unsigned long p_context = -1;
static const char apply_usage[] =
@@ -50,10 +51,10 @@ static enum whitespace_eol {
error_on_whitespace,
strip_whitespace,
} new_whitespace = warn_on_whitespace;
-static int whitespace_error = 0;
+static int whitespace_error;
static int squelch_whitespace_errors = 5;
-static int applied_after_stripping = 0;
-static const char *patch_input_file = NULL;
+static int applied_after_stripping;
+static const char *patch_input_file;
static void parse_whitespace_option(const char *option)
{
@@ -108,6 +109,13 @@ static int max_change, max_len;
*/
static int linenr = 1;
+/*
+ * This represents one "hunk" from a patch, starting with
+ * "@@ -oldpos,oldlines +newpos,newlines @@" marker. The
+ * patch text is pointed at by patch, and its byte length
+ * is stored in size. leading and trailing are the number
+ * of context lines.
+ */
struct fragment {
unsigned long leading, trailing;
unsigned long oldpos, oldlines;
@@ -117,12 +125,19 @@ struct fragment {
struct fragment *next;
};
+/*
+ * When dealing with a binary patch, we reuse "leading" field
+ * to store the type of the binary hunk, either deflated "delta"
+ * or deflated "literal".
+ */
+#define binary_patch_method leading
+#define BINARY_DELTA_DEFLATED 1
+#define BINARY_LITERAL_DEFLATED 2
+
struct patch {
char *new_name, *old_name, *def_name;
unsigned int old_mode, new_mode;
- int is_rename, is_copy, is_new, is_delete, is_binary, is_reverse;
-#define BINARY_DELTA_DEFLATED 1
-#define BINARY_LITERAL_DEFLATED 2
+ int is_rename, is_copy, is_new, is_delete, is_binary;
unsigned long deflate_origlen;
int lines_added, lines_deleted;
int score;
@@ -978,43 +993,70 @@ static inline int metadata_changes(struct patch *patch)
patch->old_mode != patch->new_mode);
}
-static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
+static char *inflate_it(const void *data, unsigned long size,
+ unsigned long inflated_size)
{
- /* We have read "GIT binary patch\n"; what follows is a line
- * that says the patch method (currently, either "deflated
- * literal" or "deflated delta") and the length of data before
- * deflating; a sequence of 'length-byte' followed by base-85
- * encoded data follows.
+ z_stream stream;
+ void *out;
+ int st;
+
+ memset(&stream, 0, sizeof(stream));
+
+ stream.next_in = (unsigned char *)data;
+ stream.avail_in = size;
+ stream.next_out = out = xmalloc(inflated_size);
+ stream.avail_out = inflated_size;
+ inflateInit(&stream);
+ st = inflate(&stream, Z_FINISH);
+ if ((st != Z_STREAM_END) || stream.total_out != inflated_size) {
+ free(out);
+ return NULL;
+ }
+ return out;
+}
+
+static struct fragment *parse_binary_hunk(char **buf_p,
+ unsigned long *sz_p,
+ int *status_p,
+ int *used_p)
+{
+ /* Expect a line that begins with binary patch method ("literal"
+ * or "delta"), followed by the length of data before deflating.
+ * a sequence of 'length-byte' followed by base-85 encoded data
+ * should follow, terminated by a newline.
*
* Each 5-byte sequence of base-85 encodes up to 4 bytes,
* and we would limit the patch line to 66 characters,
* so one line can fit up to 13 groups that would decode
* to 52 bytes max. The length byte 'A'-'Z' corresponds
* to 1-26 bytes, and 'a'-'z' corresponds to 27-52 bytes.
- * The end of binary is signaled with an empty line.
*/
int llen, used;
- struct fragment *fragment;
+ unsigned long size = *sz_p;
+ char *buffer = *buf_p;
+ int patch_method;
+ unsigned long origlen;
char *data = NULL;
+ int hunk_size = 0;
+ struct fragment *frag;
- patch->fragments = fragment = xcalloc(1, sizeof(*fragment));
-
- /* Grab the type of patch */
llen = linelen(buffer, size);
used = llen;
- linenr++;
+
+ *status_p = 0;
if (!strncmp(buffer, "delta ", 6)) {
- patch->is_binary = BINARY_DELTA_DEFLATED;
- patch->deflate_origlen = strtoul(buffer + 6, NULL, 10);
+ patch_method = BINARY_DELTA_DEFLATED;
+ origlen = strtoul(buffer + 6, NULL, 10);
}
else if (!strncmp(buffer, "literal ", 8)) {
- patch->is_binary = BINARY_LITERAL_DEFLATED;
- patch->deflate_origlen = strtoul(buffer + 8, NULL, 10);
+ patch_method = BINARY_LITERAL_DEFLATED;
+ origlen = strtoul(buffer + 8, NULL, 10);
}
else
- return error("unrecognized binary patch at line %d: %.*s",
- linenr-1, llen-1, buffer);
+ return NULL;
+
+ linenr++;
buffer += llen;
while (1) {
int byte_length, max_byte_length, newsize;
@@ -1043,21 +1085,79 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
if (max_byte_length < byte_length ||
byte_length <= max_byte_length - 4)
goto corrupt;
- newsize = fragment->size + byte_length;
+ newsize = hunk_size + byte_length;
data = xrealloc(data, newsize);
- if (decode_85(data + fragment->size,
- buffer + 1,
- byte_length))
+ if (decode_85(data + hunk_size, buffer + 1, byte_length))
goto corrupt;
- fragment->size = newsize;
+ hunk_size = newsize;
buffer += llen;
size -= llen;
}
- fragment->patch = data;
- return used;
+
+ frag = xcalloc(1, sizeof(*frag));
+ frag->patch = inflate_it(data, hunk_size, origlen);
+ if (!frag->patch)
+ goto corrupt;
+ free(data);
+ frag->size = origlen;
+ *buf_p = buffer;
+ *sz_p = size;
+ *used_p = used;
+ frag->binary_patch_method = patch_method;
+ return frag;
+
corrupt:
- return error("corrupt binary patch at line %d: %.*s",
- linenr-1, llen-1, buffer);
+ if (data)
+ free(data);
+ *status_p = -1;
+ error("corrupt binary patch at line %d: %.*s",
+ linenr-1, llen-1, buffer);
+ return NULL;
+}
+
+static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
+{
+ /* We have read "GIT binary patch\n"; what follows is a line
+ * that says the patch method (currently, either "literal" or
+ * "delta") and the length of data before deflating; a
+ * sequence of 'length-byte' followed by base-85 encoded data
+ * follows.
+ *
+ * When a binary patch is reversible, there is another binary
+ * hunk in the same format, starting with patch method (either
+ * "literal" or "delta") with the length of data, and a sequence
+ * of length-byte + base-85 encoded data, terminated with another
+ * empty line. This data, when applied to the postimage, produces
+ * the preimage.
+ */
+ struct fragment *forward;
+ struct fragment *reverse;
+ int status;
+ int used, used_1;
+
+ forward = parse_binary_hunk(&buffer, &size, &status, &used);
+ if (!forward && !status)
+ /* there has to be one hunk (forward hunk) */
+ return error("unrecognized binary patch at line %d", linenr-1);
+ if (status)
+ /* otherwise we already gave an error message */
+ return status;
+
+ reverse = parse_binary_hunk(&buffer, &size, &status, &used_1);
+ if (reverse)
+ used += used_1;
+ else if (status) {
+ /* not having reverse hunk is not an error, but having
+ * a corrupt reverse hunk is.
+ */
+ free((void*) forward->patch);
+ free(forward);
+ return status;
+ }
+ forward->next = reverse;
+ patch->fragments = forward;
+ patch->is_binary = 1;
+ return used;
}
static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
@@ -1143,7 +1243,6 @@ static void reverse_patches(struct patch *p)
swap(frag->newpos, frag->oldpos);
swap(frag->newlines, frag->oldlines);
}
- p->is_reverse = !p->is_reverse;
}
}
@@ -1363,8 +1462,7 @@ static int apply_line(char *output, const char *patch, int plen)
return plen;
}
-static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,
- int reverse, int inaccurate_eof)
+static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, int inaccurate_eof)
{
int match_beginning, match_end;
char *buf = desc->buffer;
@@ -1396,7 +1494,7 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,
if (len < size && patch[len] == '\\')
plen--;
first = *patch;
- if (reverse) {
+ if (apply_in_reverse) {
if (first == '-')
first = '+';
else if (first == '+')
@@ -1506,28 +1604,6 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,
return offset;
}
-static char *inflate_it(const void *data, unsigned long size,
- unsigned long inflated_size)
-{
- z_stream stream;
- void *out;
- int st;
-
- memset(&stream, 0, sizeof(stream));
-
- stream.next_in = (unsigned char *)data;
- stream.avail_in = size;
- stream.next_out = out = xmalloc(inflated_size);
- stream.avail_out = inflated_size;
- inflateInit(&stream);
- st = inflate(&stream, Z_FINISH);
- if ((st != Z_STREAM_END) || stream.total_out != inflated_size) {
- free(out);
- return NULL;
- }
- return out;
-}
-
static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch)
{
unsigned long dst_size;
@@ -1535,30 +1611,29 @@ static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch)
void *data;
void *result;
- /* Binary patch is irreversible */
- if (patch->is_reverse)
- return error("cannot reverse-apply a binary patch to '%s'",
- patch->new_name
- ? patch->new_name : patch->old_name);
-
- data = inflate_it(fragment->patch, fragment->size,
- patch->deflate_origlen);
- if (!data)
- return error("corrupt patch data");
- switch (patch->is_binary) {
+ /* Binary patch is irreversible without the optional second hunk */
+ if (apply_in_reverse) {
+ if (!fragment->next)
+ return error("cannot reverse-apply a binary patch "
+ "without the reverse hunk to '%s'",
+ patch->new_name
+ ? patch->new_name : patch->old_name);
+ fragment = fragment;
+ }
+ data = (void*) fragment->patch;
+ switch (fragment->binary_patch_method) {
case BINARY_DELTA_DEFLATED:
result = patch_delta(desc->buffer, desc->size,
data,
- patch->deflate_origlen,
+ fragment->size,
&dst_size);
free(desc->buffer);
desc->buffer = result;
- free(data);
break;
case BINARY_LITERAL_DEFLATED:
free(desc->buffer);
desc->buffer = data;
- dst_size = patch->deflate_origlen;
+ dst_size = fragment->size;
break;
}
if (!desc->buffer)
@@ -1609,7 +1684,7 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
}
get_sha1_hex(patch->new_sha1_prefix, sha1);
- if (!memcmp(sha1, null_sha1, 20)) {
+ if (is_null_sha1(sha1)) {
free(desc->buffer);
desc->alloc = desc->size = 0;
desc->buffer = NULL;
@@ -1657,8 +1732,7 @@ static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
return apply_binary(desc, patch);
while (frag) {
- if (apply_one_fragment(desc, frag, patch->is_reverse,
- patch->inaccurate_eof) < 0)
+ if (apply_one_fragment(desc, frag, patch->inaccurate_eof) < 0)
return error("patch failed: %s:%ld",
name, frag->oldpos);
frag = frag->next;
@@ -1842,11 +1916,6 @@ static int check_patch_list(struct patch *patch)
return error;
}
-static inline int is_null_sha1(const unsigned char *sha1)
-{
- return !memcmp(sha1, null_sha1, 20);
-}
-
static void show_index_list(struct patch *list)
{
struct patch *patch;
@@ -2194,8 +2263,7 @@ static int use_patch(struct patch *p)
return 1;
}
-static int apply_patch(int fd, const char *filename,
- int reverse, int inaccurate_eof)
+static int apply_patch(int fd, const char *filename, int inaccurate_eof)
{
unsigned long offset, size;
char *buffer = read_patch_file(fd, &size);
@@ -2215,7 +2283,7 @@ static int apply_patch(int fd, const char *filename,
nr = parse_chunk(buffer + offset, size, patch);
if (nr < 0)
break;
- if (reverse)
+ if (apply_in_reverse)
reverse_patches(patch);
if (use_patch(patch)) {
patch_stats(patch);
@@ -2278,7 +2346,6 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
{
int i;
int read_stdin = 1;
- int reverse = 0;
int inaccurate_eof = 0;
const char *whitespace_option = NULL;
@@ -2289,7 +2356,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
int fd;
if (!strcmp(arg, "-")) {
- apply_patch(0, "<stdin>", reverse, inaccurate_eof);
+ apply_patch(0, "<stdin>", inaccurate_eof);
read_stdin = 0;
continue;
}
@@ -2367,7 +2434,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "-R") || !strcmp(arg, "--reverse")) {
- reverse = 1;
+ apply_in_reverse = 1;
continue;
}
if (!strcmp(arg, "--inaccurate-eof")) {
@@ -2390,12 +2457,12 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
usage(apply_usage);
read_stdin = 0;
set_default_whitespace_mode(whitespace_option);
- apply_patch(fd, arg, reverse, inaccurate_eof);
+ apply_patch(fd, arg, inaccurate_eof);
close(fd);
}
set_default_whitespace_mode(whitespace_option);
if (read_stdin)
- apply_patch(0, "<stdin>", reverse, inaccurate_eof);
+ apply_patch(0, "<stdin>", inaccurate_eof);
if (whitespace_error) {
if (squelch_whitespace_errors &&
squelch_whitespace_errors < whitespace_error) {
diff --git a/builtin-cat-file.c b/builtin-cat-file.c
index 814fb0743f..df009ade7a 100644
--- a/builtin-cat-file.c
+++ b/builtin-cat-file.c
@@ -26,7 +26,7 @@ static void flush_buffer(const char *buf, unsigned long size)
}
}
-static int pprint_tag(const unsigned char *sha1, const char *buf, unsigned long size)
+static void pprint_tag(const unsigned char *sha1, const char *buf, unsigned long size)
{
/* the parser in tag.c is useless here. */
const char *endp = buf + size;
@@ -91,7 +91,6 @@ static int pprint_tag(const unsigned char *sha1, const char *buf, unsigned long
*/
if (cp < endp)
flush_buffer(cp, endp - cp);
- return 0;
}
int cmd_cat_file(int argc, const char **argv, const char *prefix)
@@ -145,8 +144,10 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
buf = read_sha1_file(sha1, type, &size);
if (!buf)
die("Cannot read object %s", argv[2]);
- if (!strcmp(type, tag_type))
- return pprint_tag(sha1, buf, size);
+ if (!strcmp(type, tag_type)) {
+ pprint_tag(sha1, buf, size);
+ return 0;
+ }
/* otherwise just spit out the data */
break;
diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c
index 8d0dbad49e..6b55f931cb 100644
--- a/builtin-checkout-index.c
+++ b/builtin-checkout-index.c
@@ -122,7 +122,7 @@ static int checkout_file(const char *name, int prefix_length)
return -1;
}
-static int checkout_all(const char *prefix, int prefix_length)
+static void checkout_all(const char *prefix, int prefix_length)
{
int i, errs = 0;
struct cache_entry* last_ce = NULL;
@@ -153,7 +153,6 @@ static int checkout_all(const char *prefix, int prefix_length)
* exit with the same code as die().
*/
exit(128);
- return 0;
}
static const char checkout_cache_usage[] =
diff --git a/builtin-diff.c b/builtin-diff.c
index 82afce782d..40e5c96f30 100644
--- a/builtin-diff.c
+++ b/builtin-diff.c
@@ -68,8 +68,7 @@ static void stuff_change(struct diff_options *opt,
{
struct diff_filespec *one, *two;
- if (memcmp(null_sha1, old_sha1, 20) &&
- memcmp(null_sha1, new_sha1, 20) &&
+ if (!is_null_sha1(old_sha1) && !is_null_sha1(new_sha1) &&
!memcmp(old_sha1, new_sha1, 20))
return;
diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c
index 485ede7cad..28b5dfd054 100644
--- a/builtin-fmt-merge-msg.c
+++ b/builtin-fmt-merge-msg.c
@@ -8,7 +8,7 @@
static const char *fmt_merge_msg_usage =
"git-fmt-merge-msg [--summary] [--no-summary] [--file <file>]";
-static int merge_summary = 0;
+static int merge_summary;
static int fmt_merge_msg_config(const char *key, const char *value)
{
diff --git a/builtin-grep.c b/builtin-grep.c
index a561612e7e..0bd517b264 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -175,61 +175,12 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)
}
}
-#if DEBUG
-static inline void indent(int in)
-{
- int i;
- for (i = 0; i < in; i++) putchar(' ');
-}
-
-static void dump_pattern_exp(struct grep_expr *x, int in)
-{
- switch (x->node) {
- case GREP_NODE_ATOM:
- indent(in);
- puts(x->u.atom->pattern);
- break;
- case GREP_NODE_NOT:
- indent(in);
- puts("--not");
- dump_pattern_exp(x->u.unary, in+1);
- break;
- case GREP_NODE_AND:
- dump_pattern_exp(x->u.binary.left, in+1);
- indent(in);
- puts("--and");
- dump_pattern_exp(x->u.binary.right, in+1);
- break;
- case GREP_NODE_OR:
- dump_pattern_exp(x->u.binary.left, in+1);
- indent(in);
- puts("--or");
- dump_pattern_exp(x->u.binary.right, in+1);
- break;
- }
-}
-
-static void looking_at(const char *msg, struct grep_pat **list)
-{
- struct grep_pat *p = *list;
- fprintf(stderr, "%s: looking at ", msg);
- if (!p)
- fprintf(stderr, "empty\n");
- else
- fprintf(stderr, "<%s>\n", p->pattern);
-}
-#else
-#define looking_at(a,b) do {} while(0)
-#endif
-
static struct grep_expr *compile_pattern_expr(struct grep_pat **);
static struct grep_expr *compile_pattern_atom(struct grep_pat **list)
{
struct grep_pat *p;
struct grep_expr *x;
- looking_at("atom", list);
-
p = *list;
switch (p->token) {
case GREP_PATTERN: /* atom */
@@ -257,8 +208,6 @@ static struct grep_expr *compile_pattern_not(struct grep_pat **list)
struct grep_pat *p;
struct grep_expr *x;
- looking_at("not", list);
-
p = *list;
switch (p->token) {
case GREP_NOT:
@@ -281,8 +230,6 @@ static struct grep_expr *compile_pattern_and(struct grep_pat **list)
struct grep_pat *p;
struct grep_expr *x, *y, *z;
- looking_at("and", list);
-
x = compile_pattern_not(list);
p = *list;
if (p && p->token == GREP_AND) {
@@ -306,8 +253,6 @@ static struct grep_expr *compile_pattern_or(struct grep_pat **list)
struct grep_pat *p;
struct grep_expr *x, *y, *z;
- looking_at("or", list);
-
x = compile_pattern_and(list);
p = *list;
if (x && p && p->token != GREP_CLOSE_PAREN) {
@@ -325,8 +270,6 @@ static struct grep_expr *compile_pattern_or(struct grep_pat **list)
static struct grep_expr *compile_pattern_expr(struct grep_pat **list)
{
- looking_at("expr", list);
-
return compile_pattern_or(list);
}
@@ -390,9 +333,7 @@ static int buffer_is_binary(const char *ptr, unsigned long size)
{
if (FIRST_FEW_BYTES < size)
size = FIRST_FEW_BYTES;
- if (memchr(ptr, 0, size))
- return 1;
- return 0;
+ return !!memchr(ptr, 0, size);
}
static int fixmatch(const char *pattern, char *line, regmatch_t *match)
diff --git a/builtin-ls-files.c b/builtin-ls-files.c
index 11386c432b..ad8c41e731 100644
--- a/builtin-ls-files.c
+++ b/builtin-ls-files.c
@@ -12,21 +12,22 @@
#include "dir.h"
#include "builtin.h"
-static int abbrev = 0;
-static int show_deleted = 0;
-static int show_cached = 0;
-static int show_others = 0;
-static int show_stage = 0;
-static int show_unmerged = 0;
-static int show_modified = 0;
-static int show_killed = 0;
-static int show_valid_bit = 0;
+static int abbrev;
+static int show_deleted;
+static int show_cached;
+static int show_others;
+static int show_stage;
+static int show_unmerged;
+static int show_modified;
+static int show_killed;
+static int show_valid_bit;
static int line_terminator = '\n';
-static int prefix_len = 0, prefix_offset = 0;
-static const char **pathspec = NULL;
-static int error_unmatch = 0;
-static char *ps_matched = NULL;
+static int prefix_len;
+static int prefix_offset;
+static const char **pathspec;
+static int error_unmatch;
+static char *ps_matched;
static const char *tag_cached = "";
static const char *tag_unmerged = "";
diff --git a/builtin-ls-tree.c b/builtin-ls-tree.c
index 261147fdbe..201defd934 100644
--- a/builtin-ls-tree.c
+++ b/builtin-ls-tree.c
@@ -14,10 +14,10 @@ static int line_termination = '\n';
#define LS_TREE_ONLY 2
#define LS_SHOW_TREES 4
#define LS_NAME_ONLY 8
-static int abbrev = 0;
-static int ls_options = 0;
+static int abbrev;
+static int ls_options;
static const char **pathspec;
-static int chomp_prefix = 0;
+static int chomp_prefix;
static const char *ls_tree_prefix;
static const char ls_tree_usage[] =
diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
index 24a4fc63b3..0c65f93145 100644
--- a/builtin-mailinfo.c
+++ b/builtin-mailinfo.c
@@ -16,8 +16,8 @@
static FILE *cmitmsg, *patchfile, *fin, *fout;
-static int keep_subject = 0;
-static const char *metainfo_charset = NULL;
+static int keep_subject;
+static const char *metainfo_charset;
static char line[1000];
static char date[1000];
static char name[1000];
@@ -31,7 +31,7 @@ static char charset[256];
static char multipart_boundary[1000];
static int multipart_boundary_len;
-static int patch_lines = 0;
+static int patch_lines;
static char *sanity_check(char *name, char *email)
{
diff --git a/builtin-mv.c b/builtin-mv.c
index a731f8d9cf..c0c8764f7f 100644
--- a/builtin-mv.c
+++ b/builtin-mv.c
@@ -17,12 +17,19 @@ static const char builtin_mv_usage[] =
static const char **copy_pathspec(const char *prefix, const char **pathspec,
int count, int base_name)
{
+ int i;
const char **result = xmalloc((count + 1) * sizeof(const char *));
memcpy(result, pathspec, count * sizeof(const char *));
result[count] = NULL;
- if (base_name) {
- int i;
- for (i = 0; i < count; i++) {
+ for (i = 0; i < count; i++) {
+ int length = strlen(result[i]);
+ if (length > 0 && result[i][length - 1] == '/') {
+ char *without_slash = xmalloc(length);
+ memcpy(without_slash, result[i], length - 1);
+ without_slash[length] = '\0';
+ result[i] = without_slash;
+ }
+ if (base_name) {
const char *last_slash = strrchr(result[i], '/');
if (last_slash)
result[i] = last_slash + 1;
@@ -119,6 +126,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
/* Checking */
for (i = 0; i < count; i++) {
+ int length;
const char *bad = NULL;
if (show_only)
@@ -128,6 +136,12 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
if (lstat(source[i], &st) < 0)
bad = "bad source";
+ if (!bad &&
+ (length = strlen(source[i])) >= 0 &&
+ !strncmp(destination[i], source[i], length) &&
+ (destination[i][length] == 0 || destination[i][length] == '/'))
+ bad = "can not move directory into itself";
+
if (S_ISDIR(st.st_mode)) {
const char *dir = source[i], *dest_dir = destination[i];
int first, last, len = strlen(dir);
@@ -203,10 +217,6 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
}
}
- if (!bad &&
- !strncmp(destination[i], source[i], strlen(source[i])))
- bad = "can not move directory into itself";
-
if (!bad && cache_name_pos(source[i], strlen(source[i])) < 0)
bad = "not under version control";
diff --git a/builtin-name-rev.c b/builtin-name-rev.c
index 571bba4817..d44e782c99 100644
--- a/builtin-name-rev.c
+++ b/builtin-name-rev.c
@@ -75,7 +75,7 @@ copy_data:
}
}
-static int tags_only = 0;
+static int tags_only;
static int name_ref(const char *path, const unsigned char *sha1)
{
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 2f9921224d..448461bc48 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -53,17 +53,17 @@ struct object_entry {
*/
static unsigned char object_list_sha1[20];
-static int non_empty = 0;
-static int no_reuse_delta = 0;
-static int local = 0;
-static int incremental = 0;
+static int non_empty;
+static int no_reuse_delta;
+static int local;
+static int incremental;
static struct object_entry **sorted_by_sha, **sorted_by_type;
-static struct object_entry *objects = NULL;
-static int nr_objects = 0, nr_alloc = 0, nr_result = 0;
+static struct object_entry *objects;
+static int nr_objects, nr_alloc, nr_result;
static const char *base_name;
static unsigned char pack_file_sha1[20];
static int progress = 1;
-static volatile sig_atomic_t progress_update = 0;
+static volatile sig_atomic_t progress_update;
static int window = 10;
/*
@@ -72,8 +72,8 @@ static int window = 10;
* sorted_by_sha is also possible but this was easier to code and faster.
* This hashtable is built after all the objects are seen.
*/
-static int *object_ix = NULL;
-static int object_ix_hashsz = 0;
+static int *object_ix;
+static int object_ix_hashsz;
/*
* Pack index for existing packs give us easy access to the offsets into
@@ -90,15 +90,15 @@ struct pack_revindex {
struct packed_git *p;
unsigned long *revindex;
} *pack_revindex = NULL;
-static int pack_revindex_hashsz = 0;
+static int pack_revindex_hashsz;
/*
* stats
*/
-static int written = 0;
-static int written_delta = 0;
-static int reused = 0;
-static int reused_delta = 0;
+static int written;
+static int written_delta;
+static int reused;
+static int reused_delta;
static int pack_revindex_ix(struct packed_git *p)
{
diff --git a/builtin-prune.c b/builtin-prune.c
index 89ec7f1426..fc885ce55b 100644
--- a/builtin-prune.c
+++ b/builtin-prune.c
@@ -11,7 +11,7 @@
#include "cache-tree.h"
static const char prune_usage[] = "git-prune [-n]";
-static int show_only = 0;
+static int show_only;
static struct rev_info revs;
static int prune_object(char *path, const char *filename, const unsigned char *sha1)
diff --git a/builtin-push.c b/builtin-push.c
index 53bc378f73..2b5e6fa9ed 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -10,14 +10,14 @@
static const char push_usage[] = "git-push [--all] [--tags] [-f | --force] <repository> [<refspec>...]";
-static int all = 0, tags = 0, force = 0, thin = 1;
-static const char *execute = NULL;
+static int all, tags, force, thin = 1;
+static const char *execute;
#define BUF_SIZE (2084)
static char buffer[BUF_SIZE];
-static const char **refspec = NULL;
-static int refspec_nr = 0;
+static const char **refspec;
+static int refspec_nr;
static void add_refspec(const char *ref)
{
@@ -32,10 +32,8 @@ static int expand_one_ref(const char *ref, const unsigned char *sha1)
/* Ignore the "refs/" at the beginning of the refname */
ref += 5;
- if (strncmp(ref, "tags/", 5))
- return 0;
-
- add_refspec(strdup(ref));
+ if (!strncmp(ref, "tags/", 5))
+ add_refspec(strdup(ref));
return 0;
}
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index 8da8acbb0a..53087faf7a 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -12,7 +12,7 @@
#include "unpack-trees.h"
#include "builtin.h"
-static struct object_list *trees = NULL;
+static struct object_list *trees;
static int list_tree(unsigned char *sha1)
{
diff --git a/builtin-repo-config.c b/builtin-repo-config.c
index c821e22717..c416480208 100644
--- a/builtin-repo-config.c
+++ b/builtin-repo-config.c
@@ -5,14 +5,14 @@
static const char git_config_set_usage[] =
"git-repo-config [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --unset | --unset-all] name [value [value_regex]] | --list";
-static char* key = NULL;
-static regex_t* key_regexp = NULL;
-static regex_t* regexp = NULL;
-static int show_keys = 0;
-static int use_key_regexp = 0;
-static int do_all = 0;
-static int do_not_match = 0;
-static int seen = 0;
+static char *key;
+static regex_t *key_regexp;
+static regex_t *regexp;
+static int show_keys;
+static int use_key_regexp;
+static int do_all;
+static int do_not_match;
+static int seen;
static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;
static int show_all_config(const char *key_, const char *value_)
diff --git a/builtin-rev-list.c b/builtin-rev-list.c
index 0dee1734a3..bc48a3e230 100644
--- a/builtin-rev-list.c
+++ b/builtin-rev-list.c
@@ -39,9 +39,9 @@ static const char rev_list_usage[] =
static struct rev_info revs;
-static int bisect_list = 0;
-static int show_timestamp = 0;
-static int hdr_termination = 0;
+static int bisect_list;
+static int show_timestamp;
+static int hdr_termination;
static const char *header_prefix;
static void show_commit(struct commit *commit)
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index aca4a36032..fd3ccc8546 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -15,16 +15,16 @@
#define DO_NONFLAGS 8
static int filter = ~0;
-static const char *def = NULL;
+static const char *def;
#define NORMAL 0
#define REVERSED 1
static int show_type = NORMAL;
-static int symbolic = 0;
-static int abbrev = 0;
-static int output_sq = 0;
+static int symbolic;
+static int abbrev;
+static int output_sq;
-static int revs_count = 0;
+static int revs_count;
/*
* Some arguments are relevant "revision" arguments,
diff --git a/builtin-show-branch.c b/builtin-show-branch.c
index 2a1b848f6c..95fbf77fad 100644
--- a/builtin-show-branch.c
+++ b/builtin-show-branch.c
@@ -8,9 +8,9 @@
static const char show_branch_usage[] =
"git-show-branch [--sparse] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...]";
-static int default_num = 0;
-static int default_alloc = 0;
-static const char **default_arg = NULL;
+static int default_num;
+static int default_alloc;
+static const char **default_arg;
#define UNINTERESTING 01
diff --git a/builtin-update-index.c b/builtin-update-index.c
index d2556f376b..9f0cf28ba2 100644
--- a/builtin-update-index.c
+++ b/builtin-update-index.c
@@ -23,7 +23,7 @@ static int allow_replace;
static int info_only;
static int force_remove;
static int verbose;
-static int mark_valid_only = 0;
+static int mark_valid_only;
#define MARK_VALID 1
#define UNMARK_VALID 2
diff --git a/cache.h b/cache.h
index af7740258d..c7382996f6 100644
--- a/cache.h
+++ b/cache.h
@@ -210,6 +210,10 @@ extern char *sha1_pack_name(const unsigned char *sha1);
extern char *sha1_pack_index_name(const unsigned char *sha1);
extern const char *find_unique_abbrev(const unsigned char *sha1, int);
extern const unsigned char null_sha1[20];
+static inline int is_null_sha1(const unsigned char *sha1)
+{
+ return !memcmp(sha1, null_sha1, 20);
+}
int git_mkstemp(char *path, size_t n, const char *template);
diff --git a/check-racy.c b/check-racy.c
new file mode 100644
index 0000000000..d6a08b4a55
--- /dev/null
+++ b/check-racy.c
@@ -0,0 +1,28 @@
+#include "cache.h"
+
+int main(int ac, char **av)
+{
+ int i;
+ int dirty, clean, racy;
+
+ dirty = clean = racy = 0;
+ read_cache();
+ for (i = 0; i < active_nr; i++) {
+ struct cache_entry *ce = active_cache[i];
+ struct stat st;
+
+ if (lstat(ce->name, &st)) {
+ error("lstat(%s): %s", ce->name, strerror(errno));
+ continue;
+ }
+
+ if (ce_match_stat(ce, &st, 0))
+ dirty++;
+ else if (ce_match_stat(ce, &st, 2))
+ racy++;
+ else
+ clean++;
+ }
+ printf("dirty %d, clean %d, racy %d\n", dirty, clean, racy);
+ return 0;
+}
diff --git a/combine-diff.c b/combine-diff.c
index f2f3806477..ce063b4ffa 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -7,13 +7,6 @@
#include "xdiff-interface.h"
#include "log-tree.h"
-static int uninteresting(struct diff_filepair *p)
-{
- if (diff_unmodified_pair(p))
- return 1;
- return 0;
-}
-
static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent)
{
struct diff_queue_struct *q = &diff_queued_diff;
@@ -25,7 +18,7 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
for (i = 0; i < q->nr; i++) {
int len;
const char *path;
- if (uninteresting(q->queue[i]))
+ if (diff_unmodified_pair(q->queue[i]))
continue;
path = q->queue[i]->two->path;
len = strlen(path);
@@ -57,7 +50,7 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
const char *path;
int len;
- if (uninteresting(q->queue[i]))
+ if (diff_unmodified_pair(q->queue[i]))
continue;
path = q->queue[i]->two->path;
len = strlen(path);
@@ -101,7 +94,7 @@ static char *grab_blob(const unsigned char *sha1, unsigned long *size)
{
char *blob;
char type[20];
- if (!memcmp(sha1, null_sha1, 20)) {
+ if (is_null_sha1(sha1)) {
/* deleted blob */
*size = 0;
return xcalloc(1, 1);
@@ -618,7 +611,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
struct sline *sline; /* survived lines */
int mode_differs = 0;
int i, show_hunks;
- int working_tree_file = !memcmp(elem->sha1, null_sha1, 20);
+ int working_tree_file = is_null_sha1(elem->sha1);
int abbrev = opt->full_index ? 40 : DEFAULT_ABBREV;
mmfile_t result_file;
diff --git a/commit.c b/commit.c
index 77f0ca175c..972d1b70c0 100644
--- a/commit.c
+++ b/commit.c
@@ -727,10 +727,10 @@ struct commit *pop_commit(struct commit_list **stack)
int count_parents(struct commit * commit)
{
- int count = 0;
+ int count;
struct commit_list * parents = commit->parents;
- for (count=0;parents; parents=parents->next,count++)
- ;
+ for (count = 0; parents; parents = parents->next,count++)
+ ;
return count;
}
diff --git a/configure.ac b/configure.ac
index e890131c46..36f9cd94d8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -154,6 +154,7 @@ AC_CHECK_LIB([c], [socket],
[NEEDS_SOCKET=],
[NEEDS_SOCKET=YesPlease])
AC_SUBST(NEEDS_SOCKET)
+test -n "$NEEDS_SOCKET" && LIBS="$LIBS -lsocket"
## Checks for header files.
@@ -181,8 +182,10 @@ AC_SUBST(NO_D_TYPE_IN_DIRENT)
# sockaddr_storage.
AC_CHECK_TYPE(struct sockaddr_storage,
[NO_SOCKADDR_STORAGE=],
-[NO_SOCKADDR_STORAGE=YesPlease],
-[#include <netinet/in.h>])
+[NO_SOCKADDR_STORAGE=YesPlease],[
+#include <sys/types.h>
+#include <sys/socket.h>
+])
AC_SUBST(NO_SOCKADDR_STORAGE)
#
# Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
diff --git a/connect.c b/connect.c
index 4422a0d8d3..7a6a73f2a3 100644
--- a/connect.c
+++ b/connect.c
@@ -10,7 +10,7 @@
#include <netdb.h>
#include <signal.h>
-static char *server_capabilities = NULL;
+static char *server_capabilities;
static int check_ref(const char *name, int len, unsigned int flags)
{
@@ -493,8 +493,8 @@ static void git_tcp_connect(int fd[2], char *host)
}
-static char *git_proxy_command = NULL;
-static const char *rhost_name = NULL;
+static char *git_proxy_command;
+static const char *rhost_name;
static int rhost_len;
static int git_proxy_command_options(const char *var, const char *value)
@@ -737,14 +737,9 @@ int git_connect(int fd[2], char *url, const char *prog)
int finish_connect(pid_t pid)
{
- int ret;
-
- for (;;) {
- ret = waitpid(pid, NULL, 0);
- if (!ret)
- break;
+ while (waitpid(pid, NULL, 0) < 0) {
if (errno != EINTR)
- break;
+ return -1;
}
- return ret;
+ return 0;
}
diff --git a/contrib/emacs/vc-git.el b/contrib/emacs/vc-git.el
index 3f6ed699f0..4a8f79092d 100644
--- a/contrib/emacs/vc-git.el
+++ b/contrib/emacs/vc-git.el
@@ -54,7 +54,7 @@
(let* ((dir (file-name-directory file))
(name (file-relative-name file dir)))
(when dir (cd dir))
- (and (eq 0 (call-process "git" nil '(t nil) nil "ls-files" "-c" "-z" "--" name))
+ (and (ignore-errors (eq 0 (call-process "git" nil '(t nil) nil "ls-files" "-c" "-z" "--" name)))
(let ((str (buffer-string)))
(and (> (length str) (length name))
(string= (substring str 0 (1+ (length name))) (concat name "\0"))))))))
diff --git a/csum-file.c b/csum-file.c
index 6a7b40fd09..e2278897d0 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -10,7 +10,7 @@
#include "cache.h"
#include "csum-file.h"
-static int sha1flush(struct sha1file *f, unsigned int count)
+static void sha1flush(struct sha1file *f, unsigned int count)
{
void *buf = f->buffer;
@@ -21,7 +21,7 @@ static int sha1flush(struct sha1file *f, unsigned int count)
count -= ret;
if (count)
continue;
- return 0;
+ return;
}
if (!ret)
die("sha1 file '%s' write error. Out of diskspace", f->name);
diff --git a/daemon.c b/daemon.c
index 810837f0c4..012936f3bd 100644
--- a/daemon.c
+++ b/daemon.c
@@ -22,24 +22,24 @@ static const char daemon_usage[] =
" [--reuseaddr] [--detach] [--pid-file=file] [directory...]";
/* List of acceptable pathname prefixes */
-static char **ok_paths = NULL;
-static int strict_paths = 0;
+static char **ok_paths;
+static int strict_paths;
/* If this is set, git-daemon-export-ok is not required */
-static int export_all_trees = 0;
+static int export_all_trees;
/* Take all paths relative to this one if non-NULL */
-static char *base_path = NULL;
+static char *base_path;
/* If defined, ~user notation is allowed and the string is inserted
* after ~user/. E.g. a request to git://host/~alice/frotz would
* go to /home/alice/pub_git/frotz with --user-path=pub_git.
*/
-static const char *user_path = NULL;
+static const char *user_path;
/* Timeout, and initial timeout */
-static unsigned int timeout = 0;
-static unsigned int init_timeout = 0;
+static unsigned int timeout;
+static unsigned int init_timeout;
static void logreport(int priority, const char *err, va_list params)
{
@@ -333,12 +333,12 @@ static int execute(struct sockaddr *addr)
static int max_connections = 25;
/* These are updated by the signal handler */
-static volatile unsigned int children_reaped = 0;
+static volatile unsigned int children_reaped;
static pid_t dead_child[MAX_CHILDREN];
/* These are updated by the main loop */
-static unsigned int children_spawned = 0;
-static unsigned int children_deleted = 0;
+static unsigned int children_spawned;
+static unsigned int children_deleted;
static struct child {
pid_t pid;
diff --git a/describe.c b/describe.c
index 324ca8965b..2b9301fc12 100644
--- a/describe.c
+++ b/describe.c
@@ -8,12 +8,12 @@
static const char describe_usage[] =
"git-describe [--all] [--tags] [--abbrev=<n>] <committish>*";
-static int all = 0; /* Default to annotated tags only */
-static int tags = 0; /* But allow any tags if --tags is specified */
+static int all; /* Default to annotated tags only */
+static int tags; /* But allow any tags if --tags is specified */
static int abbrev = DEFAULT_ABBREV;
-static int names = 0, allocs = 0;
+static int names, allocs;
static struct commit_name {
const struct commit *commit;
int prio; /* annotated tag = 2, tag = 1, head = 0 */
diff --git a/diff.c b/diff.c
index 8861b853e7..7a238d0233 100644
--- a/diff.c
+++ b/diff.c
@@ -13,9 +13,9 @@
static int use_size_cache;
-static int diff_detect_rename_default = 0;
+static int diff_detect_rename_default;
static int diff_rename_limit_default = -1;
-static int diff_use_color_default = 0;
+static int diff_use_color_default;
/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
static char diff_colors[][24] = {
@@ -904,9 +904,7 @@ static int mmfile_is_binary(mmfile_t *mf)
long sz = mf->size;
if (FIRST_FEW_BYTES < sz)
sz = FIRST_FEW_BYTES;
- if (memchr(mf->ptr, 0, sz))
- return 1;
- return 0;
+ return !!memchr(mf->ptr, 0, sz);
}
static void builtin_diff(const char *name_a,
@@ -1104,7 +1102,7 @@ void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
if (mode) {
spec->mode = canon_mode(mode);
memcpy(spec->sha1, sha1, 20);
- spec->sha1_valid = !!memcmp(sha1, null_sha1, 20);
+ spec->sha1_valid = !is_null_sha1(sha1);
}
}
diff --git a/environment.c b/environment.c
index 87162b2572..e6bd0033b4 100644
--- a/environment.c
+++ b/environment.c
@@ -13,14 +13,14 @@ char git_default_email[MAX_GITNAME];
char git_default_name[MAX_GITNAME];
int use_legacy_headers = 1;
int trust_executable_bit = 1;
-int assume_unchanged = 0;
-int prefer_symlink_refs = 0;
-int log_all_ref_updates = 0;
+int assume_unchanged;
+int prefer_symlink_refs;
+int log_all_ref_updates;
int warn_ambiguous_refs = 1;
-int repository_format_version = 0;
+int repository_format_version;
char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
int shared_repository = PERM_UMASK;
-const char *apply_default_whitespace = NULL;
+const char *apply_default_whitespace;
int zlib_compression_level = Z_DEFAULT_COMPRESSION;
int pager_in_use;
int pager_use_color = 1;
diff --git a/exec_cmd.c b/exec_cmd.c
index 62f51fcd6e..e30936d72c 100644
--- a/exec_cmd.c
+++ b/exec_cmd.c
@@ -5,7 +5,7 @@
extern char **environ;
static const char *builtin_exec_path = GIT_EXEC_PATH;
-static const char *current_exec_path = NULL;
+static const char *current_exec_path;
void git_set_exec_path(const char *exec_path)
{
diff --git a/fetch-clone.c b/fetch-clone.c
index 5e84c4620f..c5cf4776fa 100644
--- a/fetch-clone.c
+++ b/fetch-clone.c
@@ -44,9 +44,8 @@ static int finish_pack(const char *pack_tmp_name, const char *me)
for (;;) {
int status, code;
- int retval = waitpid(pid, &status, 0);
- if (retval < 0) {
+ if (waitpid(pid, &status, 0) < 0) {
if (errno == EINTR)
continue;
error("waitpid failed (%s)", strerror(errno));
diff --git a/fetch-pack.c b/fetch-pack.c
index b7824dbed4..e18c1489a1 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -24,8 +24,8 @@ static const char *exec = "git-upload-pack";
*/
#define MAX_IN_VAIN 256
-static struct commit_list *rev_list = NULL;
-static int non_common_revs = 0, multi_ack = 0, use_thin_pack = 0, use_sideband;
+static struct commit_list *rev_list;
+static int non_common_revs, multi_ack, use_thin_pack, use_sideband;
static void rev_list_push(struct commit *commit, int mark)
{
@@ -250,7 +250,7 @@ done:
return retval;
}
-static struct commit_list *complete = NULL;
+static struct commit_list *complete;
static int mark_complete(const char *path, const unsigned char *sha1)
{
diff --git a/fsck-objects.c b/fsck-objects.c
index e167f4105f..31e00d84b3 100644
--- a/fsck-objects.c
+++ b/fsck-objects.c
@@ -14,12 +14,12 @@
#define REACHABLE 0x0001
#define SEEN 0x0002
-static int show_root = 0;
-static int show_tags = 0;
-static int show_unreachable = 0;
-static int check_full = 0;
-static int check_strict = 0;
-static int keep_cache_objects = 0;
+static int show_root;
+static int show_tags;
+static int show_unreachable;
+static int check_full;
+static int check_strict;
+static int keep_cache_objects;
static unsigned char head_sha1[20];
#ifdef NO_D_INO_IN_DIRENT
@@ -366,13 +366,13 @@ static void add_sha1_list(unsigned char *sha1, unsigned long ino)
sha1_list.nr = ++nr;
}
-static int fsck_dir(int i, char *path)
+static void fsck_dir(int i, char *path)
{
DIR *dir = opendir(path);
struct dirent *de;
if (!dir)
- return 0;
+ return;
while ((de = readdir(dir)) != NULL) {
char name[100];
@@ -398,10 +398,9 @@ static int fsck_dir(int i, char *path)
fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
}
closedir(dir);
- return 0;
}
-static int default_refs = 0;
+static int default_refs;
static int fsck_handle_ref(const char *refname, const unsigned char *sha1)
{
@@ -453,7 +452,7 @@ static int fsck_head_link(void)
if (strncmp(git_refs_heads_master + pfxlen, "refs/heads/", 11))
return error("HEAD points to something strange (%s)",
git_refs_heads_master + pfxlen);
- if (!memcmp(null_sha1, sha1, 20))
+ if (is_null_sha1(sha1))
return error("HEAD: not a valid git pointer");
return 0;
}
diff --git a/git.c b/git.c
index 5da7787d86..930998bbe5 100644
--- a/git.c
+++ b/git.c
@@ -92,7 +92,7 @@ static int handle_options(const char*** argv, int* argc)
}
static const char *alias_command;
-static char *alias_string = NULL;
+static char *alias_string;
static int git_alias_config(const char *var, const char *value)
{
diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css
index 47c1ade87e..9013895857 100644
--- a/gitweb/gitweb.css
+++ b/gitweb/gitweb.css
@@ -117,9 +117,14 @@ div.list_head {
a.list {
text-decoration: none;
+ font-weight: bold;
color: #000000;
}
+table.tags a.list {
+ font-weight: normal;
+}
+
a.list:hover {
text-decoration: underline;
color: #880000;
@@ -221,6 +226,10 @@ table.diff_tree span.file_status.mode_chnge {
color: #777777;
}
+table.diff_tree span.file_status.copied {
+ color: #70a070;
+}
+
/* age2: 60*60*24*2 <= age */
table.project_list td.age2, table.blame td.age2 {
font-style: italic;
@@ -321,15 +330,30 @@ a.rss_logo:hover {
background-color: #ee5500;
}
-span.tag {
+span.refs span {
padding: 0px 4px;
font-size: 10px;
font-weight: normal;
- background-color: #ffffaa;
border: 1px solid;
+ background-color: #ffaaff;
+ border-color: #ffccff #ff00ee #ff00ee #ffccff;
+}
+
+span.refs span.ref {
+ background-color: #aaaaff;
+ border-color: #ccccff #0033cc #0033cc #ccccff;
+}
+
+span.refs span.tag {
+ background-color: #ffffaa;
border-color: #ffffcc #ffee00 #ffee00 #ffffcc;
}
+span.refs span.head {
+ background-color: #aaffaa;
+ border-color: #ccffcc #00cc33 #00cc33 #ccffcc;
+}
+
span.atnight {
color: #cc0000;
}
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 626fcc9201..7c92ac30ce 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -36,6 +36,9 @@ our $git_temp = "/tmp/gitweb";
# target of the home link on top of all pages
our $home_link = $my_uri;
+# string of the home link on top of all pages
+our $home_link_str = "++GITWEB_HOME_LINK_STR++";
+
# name of your site or organization to appear in page titles
# replace this with something more descriptive for clearer bookmarks
our $site_name = "++GITWEB_SITENAME++" || $ENV{'SERVER_NAME'} || "Untitled";
@@ -51,6 +54,10 @@ our $logo = "++GITWEB_LOGO++";
# source of projects list
our $projects_list = "++GITWEB_LIST++";
+# list of git base URLs used for URL to where fetch project from,
+# i.e. full URL is "$git_base_url/$project"
+our @git_base_url_list = ("++GITWEB_BASE_URL++");
+
# default blob_plain mimetype and default charset for text/plain blob
our $default_blob_plain_mimetype = 'text/plain';
our $default_text_plain_charset = undef;
@@ -178,6 +185,33 @@ $actions{$action}->();
exit;
## ======================================================================
+## action links
+
+sub href(%) {
+ my %mapping = (
+ action => "a",
+ project => "p",
+ file_name => "f",
+ hash => "h",
+ hash_parent => "hp",
+ hash_base => "hb",
+ page => "pg",
+ searchtext => "s",
+ );
+
+ my %params = @_;
+ $params{"project"} ||= $project;
+
+ my $href = "$my_uri?";
+ $href .= esc_param( join(";",
+ map { "$mapping{$_}=$params{$_}" } keys %params
+ ) );
+
+ return $href;
+}
+
+
+## ======================================================================
## validation, quoting/unquoting and escaping
sub validate_input {
@@ -354,7 +388,7 @@ sub format_log_line_html {
if ($line =~ m/([0-9a-fA-F]{40})/) {
my $hash_text = $1;
if (git_get_type($hash_text) eq "commit") {
- my $link = $cgi->a({-class => "text", -href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_text")}, $hash_text);
+ my $link = $cgi->a({-class => "text", -href => href(action=>"commit", hash=>$hash_text)}, $hash_text);
$line =~ s/$hash_text/$link/;
}
}
@@ -362,21 +396,53 @@ sub format_log_line_html {
}
# format marker of refs pointing to given object
-sub git_get_referencing {
+sub format_ref_marker {
my ($refs, $id) = @_;
+ my $markers = '';
if (defined $refs->{$id}) {
- return ' <span class="tag">' . esc_html($refs->{$id}) . '</span>';
+ foreach my $ref (@{$refs->{$id}}) {
+ my ($type, $name) = qw();
+ # e.g. tags/v2.6.11 or heads/next
+ if ($ref =~ m!^(.*?)s?/(.*)$!) {
+ $type = $1;
+ $name = $2;
+ } else {
+ $type = "ref";
+ $name = $ref;
+ }
+
+ $markers .= " <span class=\"$type\">" . esc_html($name) . "</span>";
+ }
+ }
+
+ if ($markers) {
+ return ' <span class="refs">'. $markers . '</span>';
} else {
return "";
}
}
+# format, perhaps shortened and with markers, title line
+sub format_subject_html {
+ my ($long, $short, $href, $extra) = @_;
+ $extra = '' unless defined($extra);
+
+ if (length($short) < length($long)) {
+ return $cgi->a({-href => $href, -class => "list",
+ -title => $long},
+ esc_html($short) . $extra);
+ } else {
+ return $cgi->a({-href => $href, -class => "list"},
+ esc_html($long) . $extra);
+ }
+}
+
## ----------------------------------------------------------------------
## git utility subroutines, invoking git commands
# get HEAD ref of given project as hash
-sub git_read_head {
+sub git_get_head_hash {
my $project = shift;
my $oENV = $ENV{'GIT_DIR'};
my $retval = undef;
@@ -445,7 +511,7 @@ sub git_get_hash_by_path {
## git utility functions, directly accessing git repository
# assumes that PATH is not symref
-sub git_read_hash {
+sub git_get_hash_by_ref {
my $path = shift;
open my $fd, "$projectroot/$path" or return undef;
@@ -457,7 +523,7 @@ sub git_read_hash {
}
}
-sub git_read_description {
+sub git_get_project_description {
my $path = shift;
open my $fd, "$projectroot/$path/description" or return undef;
@@ -467,7 +533,17 @@ sub git_read_description {
return $descr;
}
-sub git_read_projects {
+sub git_get_project_url_list {
+ my $path = shift;
+
+ open my $fd, "$projectroot/$path/cloneurl" or return undef;
+ my @git_project_url_list = map { chomp; $_ } <$fd>;
+ close $fd;
+
+ return wantarray ? @git_project_url_list : \@git_project_url_list;
+}
+
+sub git_get_projects_list {
my @list;
if (-d $projects_list) {
@@ -511,21 +587,58 @@ sub git_read_projects {
return @list;
}
-sub read_info_ref {
+sub git_get_project_owner {
+ my $project = shift;
+ my $owner;
+
+ return undef unless $project;
+
+ # read from file (url-encoded):
+ # 'git%2Fgit.git Linus+Torvalds'
+ # 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin'
+ # 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman'
+ if (-f $projects_list) {
+ open (my $fd , $projects_list);
+ while (my $line = <$fd>) {
+ chomp $line;
+ my ($pr, $ow) = split ' ', $line;
+ $pr = unescape($pr);
+ $ow = unescape($ow);
+ if ($pr eq $project) {
+ $owner = decode("utf8", $ow, Encode::FB_DEFAULT);
+ last;
+ }
+ }
+ close $fd;
+ }
+ if (!defined $owner) {
+ $owner = get_file_owner("$projectroot/$project");
+ }
+
+ return $owner;
+}
+
+sub git_get_references {
my $type = shift || "";
my %refs;
+ my $fd;
# 5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c refs/tags/v2.6.11
# c39ae07f393806ccf406ef966e9a15afc43cc36a refs/tags/v2.6.11^{}
- open my $fd, "$projectroot/$project/info/refs" or return;
+ if (-f "$projectroot/$project/info/refs") {
+ open $fd, "$projectroot/$project/info/refs"
+ or return;
+ } else {
+ open $fd, "-|", $GIT, "ls-remote", "."
+ or return;
+ }
+
while (my $line = <$fd>) {
chomp $line;
- # attention: for $type == "" it saves only last path part of ref name
- # e.g. from 'refs/heads/jn/gitweb' it would leave only 'gitweb'
- if ($line =~ m/^([0-9a-fA-F]{40})\t.*$type\/([^\^]+)/) {
+ if ($line =~ m/^([0-9a-fA-F]{40})\trefs\/($type\/?[^\^]+)/) {
if (defined $refs{$1}) {
- $refs{$1} .= " / $2";
+ push @{$refs{$1}}, $2;
} else {
- $refs{$1} = $2;
+ $refs{$1} = [ $2 ];
}
}
}
@@ -536,7 +649,7 @@ sub read_info_ref {
## ----------------------------------------------------------------------
## parse to hash functions
-sub date_str {
+sub parse_date {
my $epoch = shift;
my $tz = shift || "-0000";
@@ -561,7 +674,7 @@ sub date_str {
return %date;
}
-sub git_read_tag {
+sub parse_tag {
my $tag_id = shift;
my %tag;
my @comment;
@@ -596,7 +709,7 @@ sub git_read_tag {
return %tag
}
-sub git_read_commit {
+sub parse_commit {
my $commit_id = shift;
my $commit_text = shift;
@@ -690,10 +803,53 @@ sub git_read_commit {
return %co;
}
+# parse ref from ref_file, given by ref_id, with given type
+sub parse_ref {
+ my $ref_file = shift;
+ my $ref_id = shift;
+ my $type = shift || git_get_type($ref_id);
+ my %ref_item;
+
+ $ref_item{'type'} = $type;
+ $ref_item{'id'} = $ref_id;
+ $ref_item{'epoch'} = 0;
+ $ref_item{'age'} = "unknown";
+ if ($type eq "tag") {
+ my %tag = parse_tag($ref_id);
+ $ref_item{'comment'} = $tag{'comment'};
+ if ($tag{'type'} eq "commit") {
+ my %co = parse_commit($tag{'object'});
+ $ref_item{'epoch'} = $co{'committer_epoch'};
+ $ref_item{'age'} = $co{'age_string'};
+ } elsif (defined($tag{'epoch'})) {
+ my $age = time - $tag{'epoch'};
+ $ref_item{'epoch'} = $tag{'epoch'};
+ $ref_item{'age'} = age_string($age);
+ }
+ $ref_item{'reftype'} = $tag{'type'};
+ $ref_item{'name'} = $tag{'name'};
+ $ref_item{'refid'} = $tag{'object'};
+ } elsif ($type eq "commit"){
+ my %co = parse_commit($ref_id);
+ $ref_item{'reftype'} = "commit";
+ $ref_item{'name'} = $ref_file;
+ $ref_item{'title'} = $co{'title'};
+ $ref_item{'refid'} = $ref_id;
+ $ref_item{'epoch'} = $co{'committer_epoch'};
+ $ref_item{'age'} = $co{'age_string'};
+ } else {
+ $ref_item{'reftype'} = $type;
+ $ref_item{'name'} = $ref_file;
+ $ref_item{'refid'} = $ref_id;
+ }
+
+ return %ref_item;
+}
+
## ......................................................................
## parse to array of hashes functions
-sub git_read_refs {
+sub git_get_refs_list {
my $ref_dir = shift;
my @reflist;
@@ -707,46 +863,13 @@ sub git_read_refs {
}, "$projectroot/$project/$ref_dir");
foreach my $ref_file (@refs) {
- my $ref_id = git_read_hash("$project/$ref_dir/$ref_file");
+ my $ref_id = git_get_hash_by_ref("$project/$ref_dir/$ref_file");
my $type = git_get_type($ref_id) || next;
- my %ref_item;
- my %co;
- $ref_item{'type'} = $type;
- $ref_item{'id'} = $ref_id;
- $ref_item{'epoch'} = 0;
- $ref_item{'age'} = "unknown";
- if ($type eq "tag") {
- my %tag = git_read_tag($ref_id);
- $ref_item{'comment'} = $tag{'comment'};
- if ($tag{'type'} eq "commit") {
- %co = git_read_commit($tag{'object'});
- $ref_item{'epoch'} = $co{'committer_epoch'};
- $ref_item{'age'} = $co{'age_string'};
- } elsif (defined($tag{'epoch'})) {
- my $age = time - $tag{'epoch'};
- $ref_item{'epoch'} = $tag{'epoch'};
- $ref_item{'age'} = age_string($age);
- }
- $ref_item{'reftype'} = $tag{'type'};
- $ref_item{'name'} = $tag{'name'};
- $ref_item{'refid'} = $tag{'object'};
- } elsif ($type eq "commit"){
- %co = git_read_commit($ref_id);
- $ref_item{'reftype'} = "commit";
- $ref_item{'name'} = $ref_file;
- $ref_item{'title'} = $co{'title'};
- $ref_item{'refid'} = $ref_id;
- $ref_item{'epoch'} = $co{'committer_epoch'};
- $ref_item{'age'} = $co{'age_string'};
- } else {
- $ref_item{'reftype'} = $type;
- $ref_item{'name'} = $ref_file;
- $ref_item{'refid'} = $ref_id;
- }
+ my %ref_item = parse_ref($ref_file, $ref_id, $type);
push @reflist, \%ref_item;
}
- # sort tags by age
+ # sort refs by age
@reflist = sort {$b->{'epoch'} <=> $a->{'epoch'}} @reflist;
return \@reflist;
}
@@ -778,6 +901,7 @@ sub mimetype_guess_file {
my %mimemap;
open(MIME, $mimemap) or return undef;
while (<MIME>) {
+ next if m/^#/; # skip comments
my ($mime, $exts) = split(/\t+/);
if (defined $exts) {
my @exts = split(/\s+/, $exts);
@@ -799,14 +923,17 @@ sub mimetype_guess {
if ($mimetypes_file) {
my $file = $mimetypes_file;
- #$file =~ m#^/# or $file = "$projectroot/$path/$file";
+ if ($file !~ m!^/!) { # if it is relative path
+ # it is relative to project
+ $file = "$projectroot/$project/$file";
+ }
$mime = mimetype_guess_file($filename, $file);
}
$mime ||= mimetype_guess_file($filename, '/etc/mime.types');
return $mime;
}
-sub git_blob_plain_mimetype {
+sub blob_mimetype {
my $fd = shift;
my $filename = shift;
@@ -880,8 +1007,7 @@ EOF
if (defined $project) {
printf('<link rel="alternate" title="%s log" '.
'href="%s" type="application/rss+xml"/>'."\n",
- esc_param($project),
- esc_param("$my_uri?p=$project;a=rss"));
+ esc_param($project), href(action=>"rss"));
}
print "</head>\n" .
@@ -890,9 +1016,9 @@ EOF
"<a href=\"http://www.kernel.org/pub/software/scm/git/docs/\" title=\"git documentation\">" .
"<img src=\"$logo\" width=\"72\" height=\"27\" alt=\"git\" style=\"float:right; border-width:0px;\"/>" .
"</a>\n";
- print $cgi->a({-href => esc_param($home_link)}, "projects") . " / ";
+ print $cgi->a({-href => esc_param($home_link)}, $home_link_str) . " / ";
if (defined $project) {
- print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, esc_html($project));
+ print $cgi->a({-href => href(action=>"summary")}, esc_html($project));
if (defined $action) {
print " / $action";
}
@@ -925,11 +1051,11 @@ EOF
sub git_footer_html {
print "<div class=\"page_footer\">\n";
if (defined $project) {
- my $descr = git_read_description($project);
+ my $descr = git_get_project_description($project);
if (defined $descr) {
print "<div class=\"page_footer_text\">" . esc_html($descr) . "</div>\n";
}
- print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=rss"), -class => "rss_logo"}, "RSS") . "\n";
+ print $cgi->a({-href => href(action=>"rss"), -class => "rss_logo"}, "RSS") . "\n";
} else {
print $cgi->a({-href => "$my_uri?" . esc_param("a=opml"), -class => "rss_logo"}, "OPML") . "\n";
}
@@ -955,7 +1081,7 @@ sub die_error {
## ----------------------------------------------------------------------
## functions printing or outputting HTML: navigation
-sub git_page_nav {
+sub git_print_page_nav {
my ($current, $suppress, $head, $treehead, $treebase, $extra) = @_;
$extra = '' if !defined $extra; # pager or formats
@@ -964,45 +1090,43 @@ sub git_page_nav {
@navs = grep { $_ ne $suppress } @navs;
}
- my %arg = map { $_, ''} @navs;
+ my %arg = map { $_ => {action=>$_} } @navs;
if (defined $head) {
for (qw(commit commitdiff)) {
- $arg{$_} = ";h=$head";
+ $arg{$_}{hash} = $head;
}
if ($current =~ m/^(tree | log | shortlog | commit | commitdiff | search)$/x) {
for (qw(shortlog log)) {
- $arg{$_} = ";h=$head";
+ $arg{$_}{hash} = $head;
}
}
}
- $arg{tree} .= ";h=$treehead" if defined $treehead;
- $arg{tree} .= ";hb=$treebase" if defined $treebase;
+ $arg{tree}{hash} = $treehead if defined $treehead;
+ $arg{tree}{hash_base} = $treebase if defined $treebase;
print "<div class=\"page_nav\">\n" .
(join " | ",
- map { $_ eq $current
- ? $_
- : $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$_$arg{$_}")}, "$_")
- }
- @navs);
+ map { $_ eq $current ?
+ $_ : $cgi->a({-href => href(%{$arg{$_}})}, "$_")
+ } @navs);
print "<br/>\n$extra<br/>\n" .
"</div>\n";
}
-sub git_get_paging_nav {
+sub format_paging_nav {
my ($action, $hash, $head, $page, $nrevs) = @_;
my $paging_nav;
if ($hash ne $head || $page) {
- $paging_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action")}, "HEAD");
+ $paging_nav .= $cgi->a({-href => href(action=>$action)}, "HEAD");
} else {
$paging_nav .= "HEAD";
}
if ($page > 0) {
$paging_nav .= " &sdot; " .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action;h=$hash;pg=" . ($page-1)),
+ $cgi->a({-href => href(action=>$action, hash=>$hash, page=>$page-1),
-accesskey => "p", -title => "Alt-p"}, "prev");
} else {
$paging_nav .= " &sdot; prev";
@@ -1010,7 +1134,7 @@ sub git_get_paging_nav {
if ($nrevs >= (100 * ($page+1)-1)) {
$paging_nav .= " &sdot; " .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action;h=$hash;pg=" . ($page+1)),
+ $cgi->a({-href => href(action=>$action, hash=>$hash, page=>$page+1),
-accesskey => "n", -title => "Alt-n"}, "next");
} else {
$paging_nav .= " &sdot; next";
@@ -1022,17 +1146,18 @@ sub git_get_paging_nav {
## ......................................................................
## functions printing or outputting HTML: div
-sub git_header_div {
+sub git_print_header_div {
my ($action, $title, $hash, $hash_base) = @_;
- my $rest = '';
+ my %args = ();
- $rest .= ";h=$hash" if $hash;
- $rest .= ";hb=$hash_base" if $hash_base;
+ $args{action} = $action;
+ $args{hash} = $hash if $hash;
+ $args{hash_base} = $hash_base if $hash_base;
print "<div class=\"header\">\n" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action$rest"),
- -class => "title"}, $title ? $title : $action) . "\n" .
- "</div>\n";
+ $cgi->a({-href => href(%args), -class => "title"},
+ $title ? $title : $action) .
+ "\n</div>\n";
}
sub git_print_page_path {
@@ -1043,7 +1168,7 @@ sub git_print_page_path {
print "<div class=\"page_path\"><b>/</b></div>\n";
} elsif (defined $type && $type eq 'blob') {
print "<div class=\"page_path\"><b>" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;f=$file_name")}, esc_html($name)) . "</b><br/></div>\n";
+ $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name)}, esc_html($name)) . "</b><br/></div>\n";
} else {
print "<div class=\"page_path\"><b>" . esc_html($name) . "</b><br/></div>\n";
}
@@ -1052,6 +1177,145 @@ sub git_print_page_path {
## ......................................................................
## functions printing large fragments of HTML
+sub git_difftree_body {
+ my ($difftree, $parent) = @_;
+
+ print "<div class=\"list_head\">\n";
+ if ($#{$difftree} > 10) {
+ print(($#{$difftree} + 1) . " files changed:\n");
+ }
+ print "</div>\n";
+
+ print "<table class=\"diff_tree\">\n";
+ my $alternate = 0;
+ foreach my $line (@{$difftree}) {
+ # ':100644 100644 03b218260e99b78c6df0ed378e59ed9205ccc96d 3b93d5e7cc7f7dd4ebed13a5cc1a4ad976fc94d8 M ls-files.c'
+ # ':100644 100644 7f9281985086971d3877aca27704f2aaf9c448ce bc190ebc71bbd923f2b728e505408f5e54bd073a M rev-tree.c'
+ if ($line !~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\t(.*)$/) {
+ next;
+ }
+ my $from_mode = $1;
+ my $to_mode = $2;
+ my $from_id = $3;
+ my $to_id = $4;
+ my $status = $5;
+ my $similarity = $6; # score
+ my $file = validate_input(unquote($7));
+
+ if ($alternate) {
+ print "<tr class=\"dark\">\n";
+ } else {
+ print "<tr class=\"light\">\n";
+ }
+ $alternate ^= 1;
+
+ if ($status eq "A") { # created
+ my $mode_chng = "";
+ if (S_ISREG(oct $to_mode)) {
+ $mode_chng = sprintf(" with mode: %04o", (oct $to_mode) & 0777);
+ }
+ print "<td>" .
+ $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$file),
+ -class => "list"}, esc_html($file)) .
+ "</td>\n" .
+ "<td><span class=\"file_status new\">[new " . file_type($to_mode) . "$mode_chng]</span></td>\n" .
+ "<td class=\"link\">" .
+ $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$file)}, "blob") .
+ "</td>\n";
+
+ } elsif ($status eq "D") { # deleted
+ print "<td>" .
+ $cgi->a({-href => href(action=>"blob", hash=>$from_id, hash_base=>$parent, file_name=>$file),
+ -class => "list"}, esc_html($file)) . "</td>\n" .
+ "<td><span class=\"file_status deleted\">[deleted " . file_type($from_mode). "]</span></td>\n" .
+ "<td class=\"link\">" .
+ $cgi->a({-href => href(action=>"blob", hash=>$from_id, hash_base=>$parent, file_name=>$file)}, "blob") . " | " .
+ $cgi->a({-href => href(action=>"history", hash_base=>$parent, file_name=>$file)}, "history") .
+ "</td>\n"
+
+ } elsif ($status eq "M" || $status eq "T") { # modified, or type changed
+ my $mode_chnge = "";
+ if ($from_mode != $to_mode) {
+ $mode_chnge = " <span class=\"file_status mode_chnge\">[changed";
+ if (((oct $from_mode) & S_IFMT) != ((oct $to_mode) & S_IFMT)) {
+ $mode_chnge .= " from " . file_type($from_mode) . " to " . file_type($to_mode);
+ }
+ if (((oct $from_mode) & 0777) != ((oct $to_mode) & 0777)) {
+ if (S_ISREG($from_mode) && S_ISREG($to_mode)) {
+ $mode_chnge .= sprintf(" mode: %04o->%04o", (oct $from_mode) & 0777, (oct $to_mode) & 0777);
+ } elsif (S_ISREG($to_mode)) {
+ $mode_chnge .= sprintf(" mode: %04o", (oct $to_mode) & 0777);
+ }
+ }
+ $mode_chnge .= "]</span>\n";
+ }
+ print "<td>";
+ if ($to_id ne $from_id) { # modified
+ print $cgi->a({-href => href(action=>"blobdiff", hash=>$to_id, hash_parent=>$from_id, hash_base=>$hash, file_name=>$file),
+ -class => "list"}, esc_html($file));
+ } else { # mode changed
+ print $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$file),
+ -class => "list"}, esc_html($file));
+ }
+ print "</td>\n" .
+ "<td>$mode_chnge</td>\n" .
+ "<td class=\"link\">" .
+ $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$file)}, "blob");
+ if ($to_id ne $from_id) { # modified
+ print $cgi->a({-href => href(action=>"blobdiff", hash=>$to_id, hash_parent=>$from_id, hash_base=>$hash, file_name=>$file)}, "diff");
+ }
+ print " | " . $cgi->a({-href => href(action=>"history", hash_base=>$hash, file_name=>$file)}, "history") . "\n";
+ print "</td>\n";
+
+ } elsif ($status eq "R") { # renamed
+ my ($from_file, $to_file) = split "\t", $file;
+ my $mode_chng = "";
+ if ($from_mode != $to_mode) {
+ $mode_chng = sprintf(", mode: %04o", (oct $to_mode) & 0777);
+ }
+ print "<td>" .
+ $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$to_file),
+ -class => "list"}, esc_html($to_file)) . "</td>\n" .
+ "<td><span class=\"file_status moved\">[moved from " .
+ $cgi->a({-href => href(action=>"blob", hash=>$from_id, hash_base=>$parent, file_name=>$from_file),
+ -class => "list"}, esc_html($from_file)) .
+ " with " . (int $similarity) . "% similarity$mode_chng]</span></td>\n" .
+ "<td class=\"link\">" .
+ $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$to_file)}, "blob");
+ if ($to_id ne $from_id) {
+ print " | " .
+ $cgi->a({-href => "$my_uri?" .
+ esc_param("p=$project;a=blobdiff;h=$to_id;hp=$from_id;hb=$hash;f=$to_file;fp=$from_file")}, "diff");
+ }
+ print "</td>\n";
+
+ } elsif ($status eq "C") { # copied
+ my ($from_file, $to_file) = split "\t", $file;
+ my $mode_chng = "";
+ if ($from_mode != $to_mode) {
+ $mode_chng = sprintf(", mode: %04o", (oct $to_mode) & 0777);
+ }
+ print "<td>" .
+ $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$to_file),
+ -class => "list"}, esc_html($to_file)) . "</td>\n" .
+ "<td><span class=\"file_status copied\">[copied from " .
+ $cgi->a({-href => href(action=>"blob", hash=>$from_id, hash_base=>$parent, file_name=>$from_file),
+ -class => "list"}, esc_html($from_file)) .
+ " with " . (int $similarity) . "% similarity$mode_chng]</span></td>\n" .
+ "<td class=\"link\">" .
+ $cgi->a({-href => href(action=>"blob", hash=>$to_id, hash_base=>$hash, file_name=>$to_file)}, "blob");
+ if ($to_id ne $from_id) {
+ print " | " .
+ $cgi->a({-href => "$my_uri?" .
+ esc_param("p=$project;a=blobdiff;h=$to_id;hp=$from_id;hb=$hash;f=$to_file;fp=$from_file")}, "diff");
+ }
+ print "</td>\n";
+ } # we should not encounter Unmerged (U) or Unknown (X) status
+ print "</tr>\n";
+ }
+ print "</table>\n";
+}
+
sub git_shortlog_body {
# uses global variable $project
my ($revlist, $from, $to, $refs, $extra) = @_;
@@ -1062,9 +1326,9 @@ sub git_shortlog_body {
my $alternate = 0;
for (my $i = $from; $i <= $to; $i++) {
my $commit = $revlist->[$i];
- #my $ref = defined $refs ? git_get_referencing($refs, $commit) : '';
- my $ref = git_get_referencing($refs, $commit);
- my %co = git_read_commit($commit);
+ #my $ref = defined $refs ? format_ref_marker($refs, $commit) : '';
+ my $ref = format_ref_marker($refs, $commit);
+ my %co = parse_commit($commit);
if ($alternate) {
print "<tr class=\"dark\">\n";
} else {
@@ -1075,20 +1339,70 @@ sub git_shortlog_body {
print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
"<td><i>" . esc_html(chop_str($co{'author_name'}, 10)) . "</i></td>\n" .
"<td>";
- if (length($co{'title_short'}) < length($co{'title'})) {
- print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit"),
- -class => "list", -title => "$co{'title'}"},
- "<b>" . esc_html($co{'title_short'}) . "$ref</b>");
+ print format_subject_html($co{'title'}, $co{'title_short'}, href(action=>"commit", hash=>$commit), $ref);
+ print "</td>\n" .
+ "<td class=\"link\">" .
+ $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " .
+ $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") .
+ "</td>\n" .
+ "</tr>\n";
+ }
+ if (defined $extra) {
+ print "<tr>\n" .
+ "<td colspan=\"4\">$extra</td>\n" .
+ "</tr>\n";
+ }
+ print "</table>\n";
+}
+
+sub git_history_body {
+ # Warning: assumes constant type (blob or tree) during history
+ my ($fd, $refs, $hash_base, $ftype, $extra) = @_;
+
+ print "<table class=\"history\" cellspacing=\"0\">\n";
+ my $alternate = 0;
+ while (my $line = <$fd>) {
+ if ($line !~ m/^([0-9a-fA-F]{40})/) {
+ next;
+ }
+
+ my $commit = $1;
+ my %co = parse_commit($commit);
+ if (!%co) {
+ next;
+ }
+
+ my $ref = format_ref_marker($refs, $commit);
+
+ if ($alternate) {
+ print "<tr class=\"dark\">\n";
} else {
- print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit"),
- -class => "list"},
- "<b>" . esc_html($co{'title'}) . "$ref</b>");
+ print "<tr class=\"light\">\n";
}
+ $alternate ^= 1;
+ print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
+ # shortlog uses chop_str($co{'author_name'}, 10)
+ "<td><i>" . esc_html(chop_str($co{'author_name'}, 15, 3)) . "</i></td>\n" .
+ "<td>";
+ # originally git_history used chop_str($co{'title'}, 50)
+ print format_subject_html($co{'title'}, $co{'title_short'}, href(action=>"commit", hash=>$commit), $ref);
print "</td>\n" .
"<td class=\"link\">" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit")}, "commit") . " | " .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$commit")}, "commitdiff") .
- "</td>\n" .
+ $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " .
+ $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " .
+ $cgi->a({-href => href(action=>$ftype, hash_base=>$commit, file_name=>$file_name)}, $ftype);
+
+ if ($ftype eq 'blob') {
+ my $blob_current = git_get_hash_by_path($hash_base, $file_name);
+ my $blob_parent = git_get_hash_by_path($commit, $file_name);
+ if (defined $blob_current && defined $blob_parent &&
+ $blob_current ne $blob_parent) {
+ print " | " .
+ $cgi->a({-href => href(action=>"blobdiff", hash=>$blob_current, hash_parent=>$blob_parent, hash_base=>$commit, file_name=>$file_name)},
+ "diff to current");
+ }
+ }
+ print "</td>\n" .
"</tr>\n";
}
if (defined $extra) {
@@ -1124,34 +1438,28 @@ sub git_tags_body {
$alternate ^= 1;
print "<td><i>$tag{'age'}</i></td>\n" .
"<td>" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$tag{'reftype'};h=$tag{'refid'}"),
+ $cgi->a({-href => href(action=>$tag{'reftype'}, hash=>$tag{'refid'}),
-class => "list"}, "<b>" . esc_html($tag{'name'}) . "</b>") .
"</td>\n" .
"<td>";
if (defined $comment) {
- if (length($comment_short) < length($comment)) {
- print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}"),
- -class => "list", -title => $comment}, $comment_short);
- } else {
- print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}"),
- -class => "list"}, $comment);
- }
+ print format_subject_html($comment, $comment_short, href(action=>"tag", hash=>$tag{'id'}));
}
print "</td>\n" .
"<td class=\"selflink\">";
if ($tag{'type'} eq "tag") {
- print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}")}, "tag");
+ print $cgi->a({-href => href(action=>"tag", hash=>$tag{'id'})}, "tag");
} else {
print "&nbsp;";
}
print "</td>\n" .
"<td class=\"link\">" . " | " .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$tag{'reftype'};h=$tag{'refid'}")}, $tag{'reftype'});
+ $cgi->a({-href => href(action=>$tag{'reftype'}, hash=>$tag{'refid'})}, $tag{'reftype'});
if ($tag{'reftype'} eq "commit") {
- print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}")}, "shortlog") .
- " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$tag{'refid'}")}, "log");
+ print " | " . $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") .
+ " | " . $cgi->a({-href => href(action=>"log", hash=>$tag{'refid'})}, "log");
} elsif ($tag{'reftype'} eq "blob") {
- print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$tag{'refid'}")}, "raw");
+ print " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$tag{'refid'})}, "raw");
}
print "</td>\n" .
"</tr>";
@@ -1184,12 +1492,12 @@ sub git_heads_body {
$alternate ^= 1;
print "<td><i>$tag{'age'}</i></td>\n" .
($tag{'id'} eq $head ? "<td class=\"current_head\">" : "<td>") .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}"),
+ $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'}),
-class => "list"}, "<b>" . esc_html($tag{'name'}) . "</b>") .
"</td>\n" .
"<td class=\"link\">" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}")}, "shortlog") . " | " .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$tag{'name'}")}, "log") .
+ $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") . " | " .
+ $cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log") .
"</td>\n" .
"</tr>";
}
@@ -1282,24 +1590,24 @@ sub git_project_list {
die_error(undef, "Unknown order parameter");
}
- my @list = git_read_projects();
+ my @list = git_get_projects_list();
my @projects;
if (!@list) {
die_error(undef, "No projects found");
}
foreach my $pr (@list) {
- my $head = git_read_head($pr->{'path'});
+ my $head = git_get_head_hash($pr->{'path'});
if (!defined $head) {
next;
}
$ENV{'GIT_DIR'} = "$projectroot/$pr->{'path'}";
- my %co = git_read_commit($head);
+ my %co = parse_commit($head);
if (!%co) {
next;
}
$pr->{'commit'} = \%co;
if (!defined $pr->{'descr'}) {
- my $descr = git_read_description($pr->{'path'}) || "";
+ my $descr = git_get_project_description($pr->{'path'}) || "";
$pr->{'descr'} = chop_str($descr, 25, 5);
}
if (!defined $pr->{'owner'}) {
@@ -1383,81 +1691,74 @@ sub git_project_list {
}
sub git_summary {
- my $descr = git_read_description($project) || "none";
- my $head = git_read_head($project);
- my %co = git_read_commit($head);
- my %cd = date_str($co{'committer_epoch'}, $co{'committer_tz'});
+ my $descr = git_get_project_description($project) || "none";
+ my $head = git_get_head_hash($project);
+ my %co = parse_commit($head);
+ my %cd = parse_date($co{'committer_epoch'}, $co{'committer_tz'});
- my $owner;
- if (-f $projects_list) {
- open (my $fd , $projects_list);
- while (my $line = <$fd>) {
- chomp $line;
- my ($pr, $ow) = split ' ', $line;
- $pr = unescape($pr);
- $ow = unescape($ow);
- if ($pr eq $project) {
- $owner = decode("utf8", $ow, Encode::FB_DEFAULT);
- last;
- }
- }
- close $fd;
- }
- if (!defined $owner) {
- $owner = get_file_owner("$projectroot/$project");
- }
+ my $owner = git_get_project_owner($project);
- my $refs = read_info_ref();
+ my $refs = git_get_references();
git_header_html();
- git_page_nav('summary','', $head);
+ git_print_page_nav('summary','', $head);
print "<div class=\"title\">&nbsp;</div>\n";
print "<table cellspacing=\"0\">\n" .
"<tr><td>description</td><td>" . esc_html($descr) . "</td></tr>\n" .
"<tr><td>owner</td><td>$owner</td></tr>\n" .
- "<tr><td>last change</td><td>$cd{'rfc2822'}</td></tr>\n" .
- "</table>\n";
+ "<tr><td>last change</td><td>$cd{'rfc2822'}</td></tr>\n";
+ # use per project git URL list in $projectroot/$project/cloneurl
+ # or make project git URL from git base URL and project name
+ my $url_tag = "URL";
+ my @url_list = git_get_project_url_list($project);
+ @url_list = map { "$_/$project" } @git_base_url_list unless @url_list;
+ foreach my $git_url (@url_list) {
+ next unless $git_url;
+ print "<tr><td>$url_tag</td><td>$git_url</td></tr>\n";
+ $url_tag = "";
+ }
+ print "</table>\n";
- open my $fd, "-|", $GIT, "rev-list", "--max-count=17", git_read_head($project)
+ open my $fd, "-|", $GIT, "rev-list", "--max-count=17", git_get_head_hash($project)
or die_error(undef, "Open git-rev-list failed");
my @revlist = map { chomp; $_ } <$fd>;
close $fd;
- git_header_div('shortlog');
+ git_print_header_div('shortlog');
git_shortlog_body(\@revlist, 0, 15, $refs,
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "..."));
+ $cgi->a({-href => href(action=>"shortlog")}, "..."));
- my $taglist = git_read_refs("refs/tags");
+ my $taglist = git_get_refs_list("refs/tags");
if (defined @$taglist) {
- git_header_div('tags');
+ git_print_header_div('tags');
git_tags_body($taglist, 0, 15,
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tags")}, "..."));
+ $cgi->a({-href => href(action=>"tags")}, "..."));
}
- my $headlist = git_read_refs("refs/heads");
+ my $headlist = git_get_refs_list("refs/heads");
if (defined @$headlist) {
- git_header_div('heads');
+ git_print_header_div('heads');
git_heads_body($headlist, $head, 0, 15,
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=heads")}, "..."));
+ $cgi->a({-href => href(action=>"heads")}, "..."));
}
git_footer_html();
}
sub git_tag {
- my $head = git_read_head($project);
+ my $head = git_get_head_hash($project);
git_header_html();
- git_page_nav('','', $head,undef,$head);
- my %tag = git_read_tag($hash);
- git_header_div('commit', esc_html($tag{'name'}), $hash);
+ git_print_page_nav('','', $head,undef,$head);
+ my %tag = parse_tag($hash);
+ git_print_header_div('commit', esc_html($tag{'name'}), $hash);
print "<div class=\"title_text\">\n" .
"<table cellspacing=\"0\">\n" .
"<tr>\n" .
"<td>object</td>\n" .
- "<td>" . $cgi->a({-class => "list", -href => "$my_uri?" . esc_param("p=$project;a=$tag{'type'};h=$tag{'object'}")}, $tag{'object'}) . "</td>\n" .
- "<td class=\"link\">" . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$tag{'type'};h=$tag{'object'}")}, $tag{'type'}) . "</td>\n" .
+ "<td>" . $cgi->a({-class => "list", -href => href(action=>$tag{'type'}, hash=>$tag{'object'})}, $tag{'object'}) . "</td>\n" .
+ "<td class=\"link\">" . $cgi->a({-href => href(action=>$tag{'type'}, hash=>$tag{'object'})}, $tag{'type'}) . "</td>\n" .
"</tr>\n";
if (defined($tag{'author'})) {
- my %ad = date_str($tag{'epoch'}, $tag{'tz'});
+ my %ad = parse_date($tag{'epoch'}, $tag{'tz'});
print "<tr><td>author</td><td>" . esc_html($tag{'author'}) . "</td></tr>\n";
print "<tr><td></td><td>" . $ad{'rfc2822'} . sprintf(" (%02d:%02d %s)", $ad{'hour_local'}, $ad{'minute_local'}, $ad{'tz_local'}) . "</td></tr>\n";
}
@@ -1477,9 +1778,9 @@ sub git_blame2 {
my $ftype;
die_error(undef, "Permission denied") if (!git_get_project_config_bool ('blame'));
die_error('404 Not Found', "File name not defined") if (!$file_name);
- $hash_base ||= git_read_head($project);
+ $hash_base ||= git_get_head_hash($project);
die_error(undef, "Couldn't find base commit") unless ($hash_base);
- my %co = git_read_commit($hash_base)
+ my %co = parse_commit($hash_base)
or die_error(undef, "Reading commit failed");
if (!defined $hash) {
$hash = git_get_hash_by_path($hash_base, $file_name, "blob")
@@ -1493,10 +1794,10 @@ sub git_blame2 {
or die_error(undef, "Open git-blame failed");
git_header_html();
my $formats_nav =
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$hash;hb=$hash_base;f=$file_name")}, "blob") .
- " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;f=$file_name")}, "head");
- git_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
- git_header_div('commit', esc_html($co{'title'}), $hash_base);
+ $cgi->a({-href => href(action=>"blobl", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, "blob") .
+ " | " . $cgi->a({-href => href(action=>"blame", file_name=>$file_name)}, "head");
+ git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
+ git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
git_print_page_path($file_name, $ftype);
my @rev_color = (qw(light2 dark2));
my $num_colors = scalar(@rev_color);
@@ -1520,7 +1821,7 @@ sub git_blame2 {
}
print "<tr class=\"$rev_color[$current_color]\">\n";
print "<td class=\"sha1\">" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$full_rev;f=$file_name")}, esc_html($rev)) . "</td>\n";
+ $cgi->a({-href => href(action=>"commit", hash=>$full_rev, file_name=>$file_name)}, esc_html($rev)) . "</td>\n";
print "<td class=\"linenr\"><a id=\"l$lineno\" href=\"#l$lineno\" class=\"linenr\">" . esc_html($lineno) . "</a></td>\n";
print "<td class=\"pre\">" . esc_html($data) . "</td>\n";
print "</tr>\n";
@@ -1535,9 +1836,9 @@ sub git_blame {
my $fd;
die_error('403 Permission denied', "Permission denied") if (!git_get_project_config_bool ('blame'));
die_error('404 Not Found', "File name not defined") if (!$file_name);
- $hash_base ||= git_read_head($project);
+ $hash_base ||= git_get_head_hash($project);
die_error(undef, "Couldn't find base commit") unless ($hash_base);
- my %co = git_read_commit($hash_base)
+ my %co = parse_commit($hash_base)
or die_error(undef, "Reading commit failed");
if (!defined $hash) {
$hash = git_get_hash_by_path($hash_base, $file_name, "blob")
@@ -1547,10 +1848,10 @@ sub git_blame {
or die_error(undef, "Open git-annotate failed");
git_header_html();
my $formats_nav =
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$hash;hb=$hash_base;f=$file_name")}, "blob") .
- " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;f=$file_name")}, "head");
- git_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
- git_header_div('commit', esc_html($co{'title'}), $hash_base);
+ $cgi->a({-href => href(action=>"blobl", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, "blob") .
+ " | " . $cgi->a({-href => href(action=>"blame", file_name=>$file_name)}, "head");
+ git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
+ git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
git_print_page_path($file_name, 'blob');
print "<div class=\"page_body\">\n";
print <<HTML;
@@ -1603,7 +1904,7 @@ HTML
print <<HTML;
<tr class="$line_class[$line_class_num]">
- <td class="sha1"><a href="$my_uri?${\esc_param ("p=$project;a=commit;h=$long_rev")}" class="text">$short_rev..</a></td>
+ <td class="sha1"><a href="${\href (action=>"commit", hash=>$long_rev)}" class="text">$short_rev..</a></td>
<td class="$age_class">$age_str</td>
<td>$author</td>
<td class="linenr"><a id="$lineno" href="#$lineno" class="linenr">$lineno</a></td>
@@ -1618,12 +1919,12 @@ HTML
}
sub git_tags {
- my $head = git_read_head($project);
+ my $head = git_get_head_hash($project);
git_header_html();
- git_page_nav('','', $head,undef,$head);
- git_header_div('summary', $project);
+ git_print_page_nav('','', $head,undef,$head);
+ git_print_header_div('summary', $project);
- my $taglist = git_read_refs("refs/tags");
+ my $taglist = git_get_refs_list("refs/tags");
if (defined @$taglist) {
git_tags_body($taglist);
}
@@ -1631,12 +1932,12 @@ sub git_tags {
}
sub git_heads {
- my $head = git_read_head($project);
+ my $head = git_get_head_hash($project);
git_header_html();
- git_page_nav('','', $head,undef,$head);
- git_header_div('summary', $project);
+ git_print_page_nav('','', $head,undef,$head);
+ git_print_header_div('summary', $project);
- my $taglist = git_read_refs("refs/heads");
+ my $taglist = git_get_refs_list("refs/heads");
if (defined @$taglist) {
git_heads_body($taglist, $head);
}
@@ -1646,7 +1947,7 @@ sub git_heads {
sub git_blob_plain {
if (!defined $hash) {
if (defined $file_name) {
- my $base = $hash_base || git_read_head($project);
+ my $base = $hash_base || git_get_head_hash($project);
$hash = git_get_hash_by_path($base, $file_name, "blob")
or die_error(undef, "Error lookup file");
} else {
@@ -1657,7 +1958,7 @@ sub git_blob_plain {
open my $fd, "-|", $GIT, "cat-file", "blob", $hash
or die_error(undef, "Couldn't cat $file_name, $hash");
- $type ||= git_blob_plain_mimetype($fd, $file_name);
+ $type ||= blob_mimetype($fd, $file_name);
# save as filename, even when no $file_name is given
my $save_as = "$hash";
@@ -1679,7 +1980,7 @@ sub git_blob_plain {
sub git_blob {
if (!defined $hash) {
if (defined $file_name) {
- my $base = $hash_base || git_read_head($project);
+ my $base = $hash_base || git_get_head_hash($project);
$hash = git_get_hash_by_path($base, $file_name, "blob")
or die_error(undef, "Error lookup file");
} else {
@@ -1689,26 +1990,26 @@ sub git_blob {
my $have_blame = git_get_project_config_bool ('blame');
open my $fd, "-|", $GIT, "cat-file", "blob", $hash
or die_error(undef, "Couldn't cat $file_name, $hash");
- my $mimetype = git_blob_plain_mimetype($fd, $file_name);
+ my $mimetype = blob_mimetype($fd, $file_name);
if ($mimetype !~ m/^text\//) {
close $fd;
return git_blob_plain($mimetype);
}
git_header_html();
my $formats_nav = '';
- if (defined $hash_base && (my %co = git_read_commit($hash_base))) {
+ if (defined $hash_base && (my %co = parse_commit($hash_base))) {
if (defined $file_name) {
if ($have_blame) {
- $formats_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;h=$hash;hb=$hash_base;f=$file_name")}, "blame") . " | ";
+ $formats_nav .= $cgi->a({-href => href(action=>"blame", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, "blame") . " | ";
}
$formats_nav .=
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$hash;f=$file_name")}, "plain") .
- " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;hb=HEAD;f=$file_name")}, "head");
+ $cgi->a({-href => href(action=>"blob_plain", hash=>$hash, file_name=>$file_name)}, "plain") .
+ " | " . $cgi->a({-href => href(action=>"blob", hash_base=>"HEAD", file_name=>$file_name)}, "head");
} else {
- $formats_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$hash")}, "plain");
+ $formats_nav .= $cgi->a({-href => href(action=>"blob_plain", hash=>$hash)}, "plain");
}
- git_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
- git_header_div('commit', esc_html($co{'title'}), $hash_base);
+ git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
+ git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
} else {
print "<div class=\"page_nav\">\n" .
"<br/><br/></div>\n" .
@@ -1730,7 +2031,7 @@ sub git_blob {
sub git_tree {
if (!defined $hash) {
- $hash = git_read_head($project);
+ $hash = git_get_head_hash($project);
if (defined $file_name) {
my $base = $hash_base || $hash;
$hash = git_get_hash_by_path($base, $file_name, "tree");
@@ -1746,16 +2047,16 @@ sub git_tree {
close $fd or die_error(undef, "Reading tree failed");
$/ = "\n";
- my $refs = read_info_ref();
- my $ref = git_get_referencing($refs, $hash_base);
+ my $refs = git_get_references();
+ my $ref = format_ref_marker($refs, $hash_base);
git_header_html();
my $base_key = "";
my $base = "";
my $have_blame = git_get_project_config_bool ('blame');
- if (defined $hash_base && (my %co = git_read_commit($hash_base))) {
+ if (defined $hash_base && (my %co = parse_commit($hash_base))) {
$base_key = ";hb=$hash_base";
- git_page_nav('tree','', $hash_base);
- git_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base);
+ git_print_page_nav('tree','', $hash_base);
+ git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base);
} else {
print "<div class=\"page_nav\">\n";
print "<br/><br/></div>\n";
@@ -1811,14 +2112,14 @@ sub git_tree {
}
sub git_log {
- my $head = git_read_head($project);
+ my $head = git_get_head_hash($project);
if (!defined $hash) {
$hash = $head;
}
if (!defined $page) {
$page = 0;
}
- my $refs = read_info_ref();
+ my $refs = git_get_references();
my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
open my $fd, "-|", $GIT, "rev-list", $limit, $hash
@@ -1826,31 +2127,31 @@ sub git_log {
my @revlist = map { chomp; $_ } <$fd>;
close $fd;
- my $paging_nav = git_get_paging_nav('log', $hash, $head, $page, $#revlist);
+ my $paging_nav = format_paging_nav('log', $hash, $head, $page, $#revlist);
git_header_html();
- git_page_nav('log','', $hash,undef,undef, $paging_nav);
+ git_print_page_nav('log','', $hash,undef,undef, $paging_nav);
if (!@revlist) {
- my %co = git_read_commit($hash);
+ my %co = parse_commit($hash);
- git_header_div('summary', $project);
+ git_print_header_div('summary', $project);
print "<div class=\"page_body\"> Last change $co{'age_string'}.<br/><br/></div>\n";
}
for (my $i = ($page * 100); $i <= $#revlist; $i++) {
my $commit = $revlist[$i];
- my $ref = git_get_referencing($refs, $commit);
- my %co = git_read_commit($commit);
+ my $ref = format_ref_marker($refs, $commit);
+ my %co = parse_commit($commit);
next if !%co;
- my %ad = date_str($co{'author_epoch'});
- git_header_div('commit',
+ my %ad = parse_date($co{'author_epoch'});
+ git_print_header_div('commit',
"<span class=\"age\">$co{'age_string'}</span>" .
esc_html($co{'title'}) . $ref,
$commit);
print "<div class=\"title_text\">\n" .
"<div class=\"log_link\">\n" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit")}, "commit") .
- " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$commit")}, "commitdiff") .
+ $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") .
+ " | " . $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") .
"<br/>\n" .
"</div>\n" .
"<i>" . esc_html($co{'author_name'}) . " [$ad{'rfc2822'}]</i><br/>\n" .
@@ -1881,12 +2182,12 @@ sub git_log {
}
sub git_commit {
- my %co = git_read_commit($hash);
+ my %co = parse_commit($hash);
if (!%co) {
die_error(undef, "Unknown commit object");
}
- my %ad = date_str($co{'author_epoch'}, $co{'author_tz'});
- my %cd = date_str($co{'committer_epoch'}, $co{'committer_tz'});
+ my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'});
+ my %cd = parse_date($co{'committer_epoch'}, $co{'committer_tz'});
my $parent = $co{'parent'};
if (!defined $parent) {
@@ -1902,22 +2203,22 @@ sub git_commit {
if ($hash =~ m/^[0-9a-fA-F]{40}$/) {
$expires = "+1d";
}
- my $refs = read_info_ref();
- my $ref = git_get_referencing($refs, $co{'id'});
+ my $refs = git_get_references();
+ my $ref = format_ref_marker($refs, $co{'id'});
my $formats_nav = '';
if (defined $file_name && defined $co{'parent'}) {
my $parent = $co{'parent'};
- $formats_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;hb=$parent;f=$file_name")}, "blame");
+ $formats_nav .= $cgi->a({-href => href(action=>"blame", hash_parent=>$parent, file_name=>$file_name)}, "blame");
}
git_header_html(undef, $expires);
- git_page_nav('commit', defined $co{'parent'} ? '' : 'commitdiff',
+ git_print_page_nav('commit', defined $co{'parent'} ? '' : 'commitdiff',
$hash, $co{'tree'}, $hash,
$formats_nav);
if (defined $co{'parent'}) {
- git_header_div('commitdiff', esc_html($co{'title'}) . $ref, $hash);
+ git_print_header_div('commitdiff', esc_html($co{'title'}) . $ref, $hash);
} else {
- git_header_div('tree', esc_html($co{'title'}) . $ref, $co{'tree'}, $hash);
+ git_print_header_div('tree', esc_html($co{'title'}) . $ref, $co{'tree'}, $hash);
}
print "<div class=\"title_text\">\n" .
"<table cellspacing=\"0\">\n";
@@ -1937,19 +2238,19 @@ sub git_commit {
print "<tr>" .
"<td>tree</td>" .
"<td class=\"sha1\">" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash"), class => "list"}, $co{'tree'}) .
+ $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash), class => "list"}, $co{'tree'}) .
"</td>" .
- "<td class=\"link\">" . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash")}, "tree") .
+ "<td class=\"link\">" . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash)}, "tree") .
"</td>" .
"</tr>\n";
my $parents = $co{'parents'};
foreach my $par (@$parents) {
print "<tr>" .
"<td>parent</td>" .
- "<td class=\"sha1\">" . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$par"), class => "list"}, $par) . "</td>" .
+ "<td class=\"sha1\">" . $cgi->a({-href => href(action=>"commit", hash=>$par), class => "list"}, $par) . "</td>" .
"<td class=\"link\">" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$par")}, "commit") .
- " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash;hp=$par")}, "commitdiff") .
+ $cgi->a({-href => href(action=>"commit", hash=>$par)}, "commit") .
+ " | " . $cgi->a({-href => href(action=>"commitdiff", hash=>$hash, hash_parent=>$par)}, "commitdiff") .
"</td>" .
"</tr>\n";
}
@@ -1978,112 +2279,20 @@ sub git_commit {
}
}
print "</div>\n";
- print "<div class=\"list_head\">\n";
- if ($#difftree > 10) {
- print(($#difftree + 1) . " files changed:\n");
- }
- print "</div>\n";
- print "<table class=\"diff_tree\">\n";
- my $alternate = 0;
- foreach my $line (@difftree) {
- # ':100644 100644 03b218260e99b78c6df0ed378e59ed9205ccc96d 3b93d5e7cc7f7dd4ebed13a5cc1a4ad976fc94d8 M ls-files.c'
- # ':100644 100644 7f9281985086971d3877aca27704f2aaf9c448ce bc190ebc71bbd923f2b728e505408f5e54bd073a M rev-tree.c'
- if ($line !~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\t(.*)$/) {
- next;
- }
- my $from_mode = $1;
- my $to_mode = $2;
- my $from_id = $3;
- my $to_id = $4;
- my $status = $5;
- my $similarity = $6;
- my $file = validate_input(unquote($7));
- if ($alternate) {
- print "<tr class=\"dark\">\n";
- } else {
- print "<tr class=\"light\">\n";
- }
- $alternate ^= 1;
- if ($status eq "A") {
- my $mode_chng = "";
- if (S_ISREG(oct $to_mode)) {
- $mode_chng = sprintf(" with mode: %04o", (oct $to_mode) & 0777);
- }
- print "<td>" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$to_id;hb=$hash;f=$file"), -class => "list"}, esc_html($file)) . "</td>\n" .
- "<td><span class=\"file_status new\">[new " . file_type($to_mode) . "$mode_chng]</span></td>\n" .
- "<td class=\"link\">" . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$to_id;hb=$hash;f=$file")}, "blob") . "</td>\n";
- } elsif ($status eq "D") {
- print "<td>" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$from_id;hb=$parent;f=$file"), -class => "list"}, esc_html($file)) . "</td>\n" .
- "<td><span class=\"file_status deleted\">[deleted " . file_type($from_mode). "]</span></td>\n" .
- "<td class=\"link\">" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$from_id;hb=$parent;f=$file")}, "blob") .
- " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=history;hb=$parent;f=$file")}, "history") .
- "</td>\n"
- } elsif ($status eq "M" || $status eq "T") {
- my $mode_chnge = "";
- if ($from_mode != $to_mode) {
- $mode_chnge = " <span class=\"file_status mode_chnge\">[changed";
- if (((oct $from_mode) & S_IFMT) != ((oct $to_mode) & S_IFMT)) {
- $mode_chnge .= " from " . file_type($from_mode) . " to " . file_type($to_mode);
- }
- if (((oct $from_mode) & 0777) != ((oct $to_mode) & 0777)) {
- if (S_ISREG($from_mode) && S_ISREG($to_mode)) {
- $mode_chnge .= sprintf(" mode: %04o->%04o", (oct $from_mode) & 0777, (oct $to_mode) & 0777);
- } elsif (S_ISREG($to_mode)) {
- $mode_chnge .= sprintf(" mode: %04o", (oct $to_mode) & 0777);
- }
- }
- $mode_chnge .= "]</span>\n";
- }
- print "<td>";
- if ($to_id ne $from_id) {
- print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blobdiff;h=$to_id;hp=$from_id;hb=$hash;f=$file"), -class => "list"}, esc_html($file));
- } else {
- print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$to_id;hb=$hash;f=$file"), -class => "list"}, esc_html($file));
- }
- print "</td>\n" .
- "<td>$mode_chnge</td>\n" .
- "<td class=\"link\">";
- print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$to_id;hb=$hash;f=$file")}, "blob");
- if ($to_id ne $from_id) {
- print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blobdiff;h=$to_id;hp=$from_id;hb=$hash;f=$file")}, "diff");
- }
- print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=history;hb=$hash;f=$file")}, "history") . "\n";
- print "</td>\n";
- } elsif ($status eq "R") {
- my ($from_file, $to_file) = split "\t", $file;
- my $mode_chng = "";
- if ($from_mode != $to_mode) {
- $mode_chng = sprintf(", mode: %04o", (oct $to_mode) & 0777);
- }
- print "<td>" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$to_id;hb=$hash;f=$to_file"), -class => "list"}, esc_html($to_file)) . "</td>\n" .
- "<td><span class=\"file_status moved\">[moved from " .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$from_id;hb=$parent;f=$from_file"), -class => "list"}, esc_html($from_file)) .
- " with " . (int $similarity) . "% similarity$mode_chng]</span></td>\n" .
- "<td class=\"link\">" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$to_id;hb=$hash;f=$to_file")}, "blob");
- if ($to_id ne $from_id) {
- print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blobdiff;h=$to_id;hp=$from_id;hb=$hash;f=$to_file")}, "diff");
- }
- print "</td>\n";
- }
- print "</tr>\n";
- }
- print "</table>\n";
+
+ git_difftree_body(\@difftree, $parent);
+
git_footer_html();
}
sub git_blobdiff {
mkdir($git_temp, 0700);
git_header_html();
- if (defined $hash_base && (my %co = git_read_commit($hash_base))) {
+ if (defined $hash_base && (my %co = parse_commit($hash_base))) {
my $formats_nav =
$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blobdiff_plain;h=$hash;hp=$hash_parent")}, "plain");
- git_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
- git_header_div('commit', esc_html($co{'title'}), $hash_base);
+ git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
+ git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
} else {
print "<div class=\"page_nav\">\n" .
"<br/><br/></div>\n" .
@@ -2109,7 +2318,7 @@ sub git_blobdiff_plain {
sub git_commitdiff {
mkdir($git_temp, 0700);
- my %co = git_read_commit($hash);
+ my %co = parse_commit($hash);
if (!%co) {
die_error(undef, "Unknown commit object");
}
@@ -2126,13 +2335,13 @@ sub git_commitdiff {
if ($hash =~ m/^[0-9a-fA-F]{40}$/) {
$expires = "+1d";
}
- my $refs = read_info_ref();
- my $ref = git_get_referencing($refs, $co{'id'});
+ my $refs = git_get_references();
+ my $ref = format_ref_marker($refs, $co{'id'});
my $formats_nav =
$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff_plain;h=$hash;hp=$hash_parent")}, "plain");
git_header_html(undef, $expires);
- git_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav);
- git_header_div('commit', esc_html($co{'title'}) . $ref, $hash);
+ git_print_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav);
+ git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash);
print "<div class=\"page_body\">\n";
my $comment = $co{'comment'};
my $empty = 0;
@@ -2200,7 +2409,7 @@ sub git_commitdiff {
sub git_commitdiff_plain {
mkdir($git_temp, 0700);
- my %co = git_read_commit($hash);
+ my %co = parse_commit($hash);
if (!%co) {
die_error(undef, "Unknown commit object");
}
@@ -2214,7 +2423,7 @@ sub git_commitdiff_plain {
# try to figure out the next tag after this commit
my $tagname;
- my $refs = read_info_ref("tags");
+ my $refs = git_get_references("tags");
open $fd, "-|", $GIT, "rev-list", "HEAD";
my @commits = map { chomp; $_ } <$fd>;
close $fd;
@@ -2228,7 +2437,7 @@ sub git_commitdiff_plain {
}
print $cgi->header(-type => "text/plain", -charset => 'utf-8', '-content-disposition' => "inline; filename=\"git-$hash.patch\"");
- my %ad = date_str($co{'author_epoch'}, $co{'author_tz'});
+ my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'});
my $comment = $co{'comment'};
print "From: $co{'author'}\n" .
"Date: $ad{'rfc2822'} ($ad{'tz_local'})\n".
@@ -2264,17 +2473,17 @@ sub git_commitdiff_plain {
sub git_history {
if (!defined $hash_base) {
- $hash_base = git_read_head($project);
+ $hash_base = git_get_head_hash($project);
}
my $ftype;
- my %co = git_read_commit($hash_base);
+ my %co = parse_commit($hash_base);
if (!%co) {
die_error(undef, "Unknown commit object");
}
- my $refs = read_info_ref();
+ my $refs = git_get_references();
git_header_html();
- git_page_nav('','', $hash_base,$co{'tree'},$hash_base);
- git_header_div('commit', esc_html($co{'title'}), $hash_base);
+ git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base);
+ git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
if (!defined $hash && defined $file_name) {
$hash = git_get_hash_by_path($hash_base, $file_name);
}
@@ -2285,42 +2494,8 @@ sub git_history {
open my $fd, "-|",
$GIT, "rev-list", "--full-history", $hash_base, "--", $file_name;
- print "<table cellspacing=\"0\">\n";
- my $alternate = 0;
- while (my $line = <$fd>) {
- if ($line =~ m/^([0-9a-fA-F]{40})/){
- my $commit = $1;
- my %co = git_read_commit($commit);
- if (!%co) {
- next;
- }
- my $ref = git_get_referencing($refs, $commit);
- if ($alternate) {
- print "<tr class=\"dark\">\n";
- } else {
- print "<tr class=\"light\">\n";
- }
- $alternate ^= 1;
- print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
- "<td><i>" . esc_html(chop_str($co{'author_name'}, 15, 3)) . "</i></td>\n" .
- "<td>" . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit"), -class => "list"}, "<b>" .
- esc_html(chop_str($co{'title'}, 50)) . "$ref</b>") . "</td>\n" .
- "<td class=\"link\">" .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit")}, "commit") .
- " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$commit")}, "commitdiff") .
- " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$ftype;hb=$commit;f=$file_name")}, $ftype);
- my $blob = git_get_hash_by_path($hash_base, $file_name);
- my $blob_parent = git_get_hash_by_path($commit, $file_name);
- if (defined $blob && defined $blob_parent && $blob ne $blob_parent) {
- print " | " .
- $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blobdiff;h=$blob;hp=$blob_parent;hb=$commit;f=$file_name")},
- "diff to current");
- }
- print "</td>\n" .
- "</tr>\n";
- }
- }
- print "</table>\n";
+ git_history_body($fd, $refs, $hash_base, $ftype);
+
close $fd;
git_footer_html();
}
@@ -2330,9 +2505,9 @@ sub git_search {
die_error(undef, "Text field empty");
}
if (!defined $hash) {
- $hash = git_read_head($project);
+ $hash = git_get_head_hash($project);
}
- my %co = git_read_commit($hash);
+ my %co = parse_commit($hash);
if (!%co) {
die_error(undef, "Unknown commit object");
}
@@ -2351,8 +2526,8 @@ sub git_search {
$pickaxe_search = 1;
}
git_header_html();
- git_page_nav('','', $hash,$co{'tree'},$hash);
- git_header_div('commit', esc_html($co{'title'}), $hash);
+ git_print_page_nav('','', $hash,$co{'tree'},$hash);
+ git_print_header_div('commit', esc_html($co{'title'}), $hash);
print "<table cellspacing=\"0\">\n";
my $alternate = 0;
@@ -2370,7 +2545,7 @@ sub git_search {
next;
}
my @commit_lines = split "\n", $commit_text;
- my %co = git_read_commit(undef, \@commit_lines);
+ my %co = parse_commit(undef, \@commit_lines);
if (!%co) {
next;
}
@@ -2451,7 +2626,7 @@ sub git_search {
print "</td>\n" .
"</tr>\n";
}
- %co = git_read_commit($1);
+ %co = parse_commit($1);
}
}
close $fd;
@@ -2461,14 +2636,14 @@ sub git_search {
}
sub git_shortlog {
- my $head = git_read_head($project);
+ my $head = git_get_head_hash($project);
if (!defined $hash) {
$hash = $head;
}
if (!defined $page) {
$page = 0;
}
- my $refs = read_info_ref();
+ my $refs = git_get_references();
my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
open my $fd, "-|", $GIT, "rev-list", $limit, $hash
@@ -2476,7 +2651,7 @@ sub git_shortlog {
my @revlist = map { chomp; $_ } <$fd>;
close $fd;
- my $paging_nav = git_get_paging_nav('shortlog', $hash, $head, $page, $#revlist);
+ my $paging_nav = format_paging_nav('shortlog', $hash, $head, $page, $#revlist);
my $next_link = '';
if ($#revlist >= (100 * ($page+1)-1)) {
$next_link =
@@ -2486,8 +2661,8 @@ sub git_shortlog {
git_header_html();
- git_page_nav('shortlog','', $hash,$hash,$hash, $paging_nav);
- git_header_div('summary', $project);
+ git_print_page_nav('shortlog','', $hash,$hash,$hash, $paging_nav);
+ git_print_header_div('summary', $project);
git_shortlog_body(\@revlist, ($page * 100), $#revlist, $refs, $next_link);
@@ -2499,7 +2674,7 @@ sub git_shortlog {
sub git_rss {
# http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ
- open my $fd, "-|", $GIT, "rev-list", "--max-count=150", git_read_head($project)
+ open my $fd, "-|", $GIT, "rev-list", "--max-count=150", git_get_head_hash($project)
or die_error(undef, "Open git-rev-list failed");
my @revlist = map { chomp; $_ } <$fd>;
close $fd or die_error(undef, "Reading git-rev-list failed");
@@ -2514,12 +2689,12 @@ sub git_rss {
for (my $i = 0; $i <= $#revlist; $i++) {
my $commit = $revlist[$i];
- my %co = git_read_commit($commit);
+ my %co = parse_commit($commit);
# we read 150, we always show 30 and the ones more recent than 48 hours
if (($i >= 20) && ((time - $co{'committer_epoch'}) > 48*60*60)) {
last;
}
- my %cd = date_str($co{'committer_epoch'});
+ my %cd = parse_date($co{'committer_epoch'});
open $fd, "-|", $GIT, "diff-tree", '-r', $co{'parent'}, $co{'id'} or next;
my @difftree = map { chomp; $_ } <$fd>;
close $fd or next;
@@ -2556,7 +2731,7 @@ sub git_rss {
}
sub git_opml {
- my @list = git_read_projects();
+ my @list = git_get_projects_list();
print $cgi->header(-type => 'text/xml', -charset => 'utf-8');
print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".
@@ -2569,12 +2744,12 @@ sub git_opml {
foreach my $pr (@list) {
my %proj = %$pr;
- my $head = git_read_head($proj{'path'});
+ my $head = git_get_head_hash($proj{'path'});
if (!defined $head) {
next;
}
$ENV{'GIT_DIR'} = "$projectroot/$proj{'path'}";
- my %co = git_read_commit($head);
+ my %co = parse_commit($head);
if (!%co) {
next;
}
diff --git a/help.c b/help.c
index 6484cb9df2..9ecdefdb03 100644
--- a/help.c
+++ b/help.c
@@ -14,7 +14,7 @@
static int term_columns(void)
{
char *col_string = getenv("COLUMNS");
- int n_cols = 0;
+ int n_cols;
if (col_string && (n_cols = atoi(col_string)) > 0)
return n_cols;
diff --git a/http-fetch.c b/http-fetch.c
index de5fc44e66..7f07d2a967 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -36,10 +36,10 @@ enum XML_Status {
#define PREV_BUF_SIZE 4096
#define RANGE_HEADER_SIZE 30
-static int commits_on_stdin = 0;
+static int commits_on_stdin;
static int got_alternates = -1;
-static int corrupt_object_found = 0;
+static int corrupt_object_found;
static struct curl_slist *no_pragma_header;
@@ -52,7 +52,7 @@ struct alt_base
struct alt_base *next;
};
-static struct alt_base *alt = NULL;
+static struct alt_base *alt;
enum object_request_state {
WAITING,
@@ -114,7 +114,7 @@ struct remote_ls_ctx
};
#endif
-static struct object_request *object_queue_head = NULL;
+static struct object_request *object_queue_head;
static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
void *data)
diff --git a/http-push.c b/http-push.c
index 0359ae5b6f..2bd9845765 100644
--- a/http-push.c
+++ b/http-push.c
@@ -70,18 +70,18 @@ enum XML_Status {
/* We allow "recursive" symbolic refs. Only within reason, though */
#define MAXDEPTH 5
-static int pushing = 0;
-static int aborted = 0;
+static int pushing;
+static int aborted;
static signed char remote_dir_exists[256];
static struct curl_slist *no_pragma_header;
static struct curl_slist *default_headers;
-static int push_verbosely = 0;
-static int push_all = 0;
-static int force_all = 0;
+static int push_verbosely;
+static int push_all;
+static int force_all;
-static struct object_list *objects = NULL;
+static struct object_list *objects;
struct repo
{
@@ -94,7 +94,7 @@ struct repo
struct remote_lock *locks;
};
-static struct repo *remote = NULL;
+static struct repo *remote;
enum transfer_state {
NEED_FETCH,
@@ -134,7 +134,7 @@ struct transfer_request
struct transfer_request *next;
};
-static struct transfer_request *request_queue_head = NULL;
+static struct transfer_request *request_queue_head;
struct xml_ctx
{
@@ -2186,10 +2186,7 @@ static int verify_merge_base(unsigned char *head_sha1, unsigned char *branch_sha
struct commit *branch = lookup_commit(branch_sha1);
struct commit_list *merge_bases = get_merge_bases(head, branch, 1);
- if (merge_bases && !merge_bases->next && merge_bases->item == branch)
- return 1;
-
- return 0;
+ return (merge_bases && !merge_bases->next && merge_bases->item == branch);
}
static int delete_remote_branch(char *pattern, int force)
diff --git a/local-fetch.c b/local-fetch.c
index 7d01845d39..7b6875cce6 100644
--- a/local-fetch.c
+++ b/local-fetch.c
@@ -5,10 +5,10 @@
#include "commit.h"
#include "fetch.h"
-static int use_link = 0;
-static int use_symlink = 0;
+static int use_link;
+static int use_symlink;
static int use_filecopy = 1;
-static int commits_on_stdin = 0;
+static int commits_on_stdin;
static const char *path; /* "Remote" git repository */
@@ -16,7 +16,7 @@ void prefetch(unsigned char *sha1)
{
}
-static struct packed_git *packs = NULL;
+static struct packed_git *packs;
static void setup_index(unsigned char *sha1)
{
diff --git a/merge-base.c b/merge-base.c
index 59f723f404..009caf804b 100644
--- a/merge-base.c
+++ b/merge-base.c
@@ -2,7 +2,7 @@
#include "cache.h"
#include "commit.h"
-static int show_all = 0;
+static int show_all;
static int merge_base(struct commit *rev1, struct commit *rev2)
{
diff --git a/merge-index.c b/merge-index.c
index 0498a6f45e..646d090c58 100644
--- a/merge-index.c
+++ b/merge-index.c
@@ -4,14 +4,15 @@
#include "cache.h"
-static const char *pgm = NULL;
+static const char *pgm;
static const char *arguments[8];
static int one_shot, quiet;
static int err;
static void run_program(void)
{
- int pid = fork(), status;
+ pid_t pid = fork();
+ int status;
if (pid < 0)
die("unable to fork");
diff --git a/mktree.c b/mktree.c
index 9a6f0d2f6b..93241385e4 100644
--- a/mktree.c
+++ b/mktree.c
@@ -49,7 +49,6 @@ static void write_tree(unsigned char *sha1)
int i;
qsort(entries, used, sizeof(*entries), ent_compare);
- size = 100;
for (size = i = 0; i < used; i++)
size += 32 + entries[i]->len;
buffer = xmalloc(size);
diff --git a/pack-redundant.c b/pack-redundant.c
index 41fb960569..92a09ed362 100644
--- a/pack-redundant.c
+++ b/pack-redundant.c
@@ -13,7 +13,7 @@
static const char pack_redundant_usage[] =
"git-pack-redundant [ --verbose ] [ --alt-odb ] < --all | <.pack filename> ...>";
-static int load_all_packs = 0, verbose = 0, alt_odb = 0;
+static int load_all_packs, verbose, alt_odb;
struct llist_item {
struct llist_item *next;
@@ -37,7 +37,7 @@ struct pll {
struct pack_list *pl;
};
-static struct llist_item *free_nodes = NULL;
+static struct llist_item *free_nodes;
static inline void llist_item_put(struct llist_item *item)
{
diff --git a/read-cache.c b/read-cache.c
index c923a32707..6bec833eec 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -5,7 +5,6 @@
*/
#include "cache.h"
#include "cache-tree.h"
-#include <time.h>
/* Index extensions.
*
@@ -19,16 +18,16 @@
#define CACHE_EXT(s) ( (s[0]<<24)|(s[1]<<16)|(s[2]<<8)|(s[3]) )
#define CACHE_EXT_TREE 0x54524545 /* "TREE" */
-struct cache_entry **active_cache = NULL;
+struct cache_entry **active_cache;
static time_t index_file_timestamp;
-unsigned int active_nr = 0, active_alloc = 0, active_cache_changed = 0;
+unsigned int active_nr, active_alloc, active_cache_changed;
-struct cache_tree *active_cache_tree = NULL;
+struct cache_tree *active_cache_tree;
-int cache_errno = 0;
+int cache_errno;
-static void *cache_mmap = NULL;
-static size_t cache_mmap_size = 0;
+static void *cache_mmap;
+static size_t cache_mmap_size;
/*
* This only updates the "non-critical" parts of the directory
@@ -170,9 +169,11 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
return changed;
}
-int ce_match_stat(struct cache_entry *ce, struct stat *st, int ignore_valid)
+int ce_match_stat(struct cache_entry *ce, struct stat *st, int options)
{
unsigned int changed;
+ int ignore_valid = options & 01;
+ int assume_racy_is_modified = options & 02;
/*
* If it's marked as always valid in the index, it's
@@ -201,8 +202,12 @@ int ce_match_stat(struct cache_entry *ce, struct stat *st, int ignore_valid)
*/
if (!changed &&
index_file_timestamp &&
- index_file_timestamp <= ntohl(ce->ce_mtime.sec))
- changed |= ce_modified_check_fs(ce, st);
+ index_file_timestamp <= ntohl(ce->ce_mtime.sec)) {
+ if (assume_racy_is_modified)
+ changed |= DATA_CHANGED;
+ else
+ changed |= ce_modified_check_fs(ce, st);
+ }
return changed;
}
@@ -880,10 +885,8 @@ static int write_index_ext_header(SHA_CTX *context, int fd,
{
ext = htonl(ext);
sz = htonl(sz);
- if ((ce_write(context, fd, &ext, 4) < 0) ||
- (ce_write(context, fd, &sz, 4) < 0))
- return -1;
- return 0;
+ return ((ce_write(context, fd, &ext, 4) < 0) ||
+ (ce_write(context, fd, &sz, 4) < 0)) ? -1 : 0;
}
static int ce_flush(SHA_CTX *context, int fd)
@@ -905,9 +908,7 @@ static int ce_flush(SHA_CTX *context, int fd)
/* Append the SHA1 signature at the end */
SHA1_Final(write_buffer + left, context);
left += 20;
- if (write(fd, write_buffer, left) != left)
- return -1;
- return 0;
+ return (write(fd, write_buffer, left) != left) ? -1 : 0;
}
static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
@@ -958,9 +959,7 @@ int write_cache(int newfd, struct cache_entry **cache, int entries)
{
SHA_CTX c;
struct cache_header hdr;
- int i, removed, recent;
- struct stat st;
- time_t now;
+ int i, removed;
for (i = removed = 0; i < entries; i++)
if (!cache[i]->ce_mode)
@@ -998,57 +997,5 @@ int write_cache(int newfd, struct cache_entry **cache, int entries)
return -1;
}
}
-
- /*
- * To prevent later ce_match_stat() from always falling into
- * check_fs(), if we have too many entries that can trigger
- * racily clean check, we are better off delaying the return.
- * We arbitrarily say if more than 20 paths or 25% of total
- * paths are very new, we delay the return until the index
- * file gets a new timestamp.
- *
- * NOTE! NOTE! NOTE!
- *
- * This assumes that nobody is touching the working tree while
- * we are updating the index.
- */
-
- /* Make sure that the new index file has st_mtime
- * that is current enough -- ce_write() batches the data
- * so it might not have written anything yet.
- */
- ce_write_flush(&c, newfd);
-
- now = fstat(newfd, &st) ? 0 : st.st_mtime;
- if (now) {
- recent = 0;
- for (i = 0; i < entries; i++) {
- struct cache_entry *ce = cache[i];
- time_t entry_time = (time_t) ntohl(ce->ce_mtime.sec);
- if (!ce->ce_mode)
- continue;
- if (now && now <= entry_time)
- recent++;
- }
- if (20 < recent && entries <= recent * 4) {
-#if 0
- fprintf(stderr, "entries %d\n", entries);
- fprintf(stderr, "recent %d\n", recent);
- fprintf(stderr, "now %lu\n", now);
-#endif
- while (!fstat(newfd, &st) && st.st_mtime <= now) {
- struct timespec rq, rm;
- off_t where = lseek(newfd, 0, SEEK_CUR);
- rq.tv_sec = 0;
- rq.tv_nsec = 250000000;
- nanosleep(&rq, &rm);
- if ((where == (off_t) -1) ||
- (write(newfd, "", 1) != 1) ||
- (lseek(newfd, -1, SEEK_CUR) != where) ||
- ftruncate(newfd, where))
- break;
- }
- }
- }
return ce_flush(&c, newfd);
}
diff --git a/receive-pack.c b/receive-pack.c
index 93929b5371..81e91909b8 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -8,10 +8,10 @@ static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
static const char *unpacker[] = { "unpack-objects", NULL };
-static int report_status = 0;
+static int report_status;
static char capabilities[] = "report-status";
-static int capabilities_sent = 0;
+static int capabilities_sent;
static int show_ref(const char *path, const unsigned char *sha1)
{
@@ -40,7 +40,7 @@ struct command {
char ref_name[FLEX_ARRAY]; /* more */
};
-static struct command *commands = NULL;
+static struct command *commands;
static int is_all_zeroes(const char *hex)
{
diff --git a/run-command.c b/run-command.c
index ca67ee9333..61908682b9 100644
--- a/run-command.c
+++ b/run-command.c
@@ -25,15 +25,15 @@ int run_command_v_opt(int argc, const char **argv, int flags)
}
for (;;) {
int status, code;
- int retval = waitpid(pid, &status, 0);
+ pid_t waiting = waitpid(pid, &status, 0);
- if (retval < 0) {
+ if (waiting < 0) {
if (errno == EINTR)
continue;
- error("waitpid failed (%s)", strerror(retval));
+ error("waitpid failed (%s)", strerror(errno));
return -ERR_RUN_COMMAND_WAITPID;
}
- if (retval != pid)
+ if (waiting != pid)
return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
if (WIFSIGNALED(status))
return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
diff --git a/send-pack.c b/send-pack.c
index 10bc8bc359..43e10b0a62 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -9,10 +9,10 @@ static const char send_pack_usage[] =
"git-send-pack [--all] [--exec=git-receive-pack] <remote> [<head>...]\n"
" --all and explicit <head> specification are mutually exclusive.";
static const char *exec = "git-receive-pack";
-static int verbose = 0;
-static int send_all = 0;
-static int force_update = 0;
-static int use_thin_pack = 0;
+static int verbose;
+static int send_all;
+static int force_update;
+static int use_thin_pack;
static int is_zero_sha1(const unsigned char *sha1)
{
@@ -111,7 +111,7 @@ static void rev_list(int fd, struct ref *refs)
exec_rev_list(refs);
}
-static int pack_objects(int fd, struct ref *refs)
+static void pack_objects(int fd, struct ref *refs)
{
pid_t rev_list_pid;
@@ -126,7 +126,6 @@ static int pack_objects(int fd, struct ref *refs)
* We don't wait for the rev-list pipeline in the parent:
* we end up waiting for the other end instead
*/
- return 0;
}
static void unmark_and_free(struct commit_list *list, unsigned int mark)
diff --git a/sha1_file.c b/sha1_file.c
index 842a6f3ae8..18dece46b1 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -22,7 +22,7 @@
#endif
#endif
-const unsigned char null_sha1[20] = { 0, };
+const unsigned char null_sha1[20];
static unsigned int sha1_file_open_flag = O_NOATIME;
diff --git a/sha1_name.c b/sha1_name.c
index c5a05faeb6..f567454d22 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -191,7 +191,7 @@ const char *find_unique_abbrev(const unsigned char *sha1, int len)
int status, is_null;
static char hex[41];
- is_null = !memcmp(sha1, null_sha1, 20);
+ is_null = is_null_sha1(sha1);
memcpy(hex, sha1_to_hex(sha1), 40);
if (len == 40 || !len)
return hex;
diff --git a/ssh-fetch.c b/ssh-fetch.c
index c7d8fa80e4..0b89df6dda 100644
--- a/ssh-fetch.c
+++ b/ssh-fetch.c
@@ -17,7 +17,7 @@
static int fd_in;
static int fd_out;
-static unsigned char remote_version = 0;
+static unsigned char remote_version;
static unsigned char local_version = 1;
static ssize_t force_write(int fd, void *buffer, size_t length)
@@ -36,9 +36,9 @@ static ssize_t force_write(int fd, void *buffer, size_t length)
return ret;
}
-static int prefetches = 0;
+static int prefetches;
-static struct object_list *in_transit = NULL;
+static struct object_list *in_transit;
static struct object_list **end_of_transit = &in_transit;
void prefetch(unsigned char *sha1)
@@ -59,7 +59,7 @@ void prefetch(unsigned char *sha1)
}
static char conn_buf[4096];
-static size_t conn_buf_posn = 0;
+static size_t conn_buf_posn;
int fetch(unsigned char *sha1)
{
diff --git a/ssh-upload.c b/ssh-upload.c
index 2da66618fc..20b15eab57 100644
--- a/ssh-upload.c
+++ b/ssh-upload.c
@@ -15,9 +15,9 @@
#include <string.h>
static unsigned char local_version = 1;
-static unsigned char remote_version = 0;
+static unsigned char remote_version;
-static int verbose = 0;
+static int verbose;
static int serve_object(int fd_in, int fd_out) {
ssize_t size;
diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh
new file mode 100755
index 0000000000..69aebe6005
--- /dev/null
+++ b/t/t4116-apply-reverse.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Junio C Hamano
+#
+
+test_description='git-apply in reverse
+
+'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+
+ for i in a b c d e f g h i j k l m n; do echo $i; done >file1 &&
+ tr "[ijk]" '\''[\0\1\2]'\'' <file1 >file2 &&
+
+ git add file1 file2 &&
+ git commit -m initial &&
+ git tag initial &&
+
+ for i in a b c g h i J K L m o n p q; do echo $i; done >file1 &&
+ tr "[mon]" '\''[\0\1\2]'\'' <file1 >file2 &&
+
+ git commit -a -m second &&
+
+ git diff --binary -R initial >patch
+
+'
+
+test_expect_success 'apply in forward' '
+
+ git apply --index --binary patch &&
+ git diff initial >diff &&
+ diff -u /dev/null diff
+
+'
+
+test_expect_success 'apply in reverse' '
+
+ git apply --reverse --binary --index patch &&
+ git diff >diff &&
+ diff -u /dev/null diff
+
+'
+
+test_done
diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh
index 900ca93cde..e5e0bb9d51 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -60,6 +60,10 @@ test_expect_success \
grep -E "^R100.+path0/README.+path2/README"'
test_expect_success \
+ 'succeed when source is a prefix of destination' \
+ 'git-mv path2/COPYING path2/COPYING-renamed'
+
+test_expect_success \
'moving whole subdirectory into subdirectory' \
'git-mv path2 path1'
diff --git a/tree-diff.c b/tree-diff.c
index 1cdf8aa908..916f489c5b 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -15,7 +15,8 @@ static char *malloc_base(const char *base, const char *path, int pathlen)
return newbase;
}
-static int show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base);
+static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc,
+ const char *base);
static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)
{
@@ -131,7 +132,8 @@ static void show_tree(struct diff_options *opt, const char *prefix, struct tree_
}
/* A file entry went away or appeared */
-static int show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base)
+static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc,
+ const char *base)
{
unsigned mode;
const char *path;
@@ -152,11 +154,9 @@ static int show_entry(struct diff_options *opt, const char *prefix, struct tree_
free(tree);
free(newbase);
- return 0;
+ } else {
+ opt->add_remove(opt, prefix[0], mode, sha1, base, path);
}
-
- opt->add_remove(opt, prefix[0], mode, sha1, base, path);
- return 0;
}
int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)
diff --git a/tree.c b/tree.c
index a6032e35ec..ef456be9dd 100644
--- a/tree.c
+++ b/tree.c
@@ -144,7 +144,7 @@ struct tree *lookup_tree(const unsigned char *sha1)
return (struct tree *) obj;
}
-static int track_tree_refs(struct tree *item)
+static void track_tree_refs(struct tree *item)
{
int n_refs = 0, i;
struct object_refs *refs;
@@ -174,7 +174,6 @@ static int track_tree_refs(struct tree *item)
refs->ref[i++] = obj;
}
set_object_refs(&item->object, refs);
- return 0;
}
int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
diff --git a/unpack-trees.c b/unpack-trees.c
index a20639be70..43ed12484f 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -278,7 +278,7 @@ static void unlink_entry(char *name)
}
}
-static volatile int progress_update = 0;
+static volatile sig_atomic_t progress_update;
static void progress_interval(int signum)
{
diff --git a/upload-pack.c b/upload-pack.c
index bbd6bd60b5..fcf279843a 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -14,12 +14,12 @@ static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=n
#define THEY_HAVE (1U << 0)
#define OUR_REF (1U << 1)
#define WANTED (1U << 2)
-static int multi_ack = 0, nr_our_refs = 0;
-static int use_thin_pack = 0;
+static int multi_ack, nr_our_refs;
+static int use_thin_pack;
static struct object_array have_obj;
static struct object_array want_obj;
-static unsigned int timeout = 0;
-static int use_sideband = 0;
+static unsigned int timeout;
+static int use_sideband;
static void reset_timeout(void)
{
@@ -459,18 +459,17 @@ static int send_ref(const char *refname, const unsigned char *sha1)
return 0;
}
-static int upload_pack(void)
+static void upload_pack(void)
{
reset_timeout();
head_ref(send_ref);
for_each_ref(send_ref);
packet_flush(1);
receive_needs();
- if (!want_obj.nr)
- return 0;
- get_common_commits();
- create_pack_file();
- return 0;
+ if (want_obj.nr) {
+ get_common_commits();
+ create_pack_file();
+ }
}
int main(int argc, char **argv)