external = "/usr/local/bin/gnu-diff -u"
renames = true
+ [branch "devel"]
+ remote = origin
+ merge = refs/heads/devel
+
+
Variables
~~~~~~~~~
[verse]
'git-clone' [--template=<template_directory>] [-l [-s]] [-q] [-n] [--bare]
[-o <name>] [-u <upload-pack>] [--reference <repository>]
- [--use-separate-remote | --no-separate-remote] <repository>
- [<directory>]
+ <repository> [<directory>]
DESCRIPTION
-----------
if unset the templates are taken from the installation
defined default, typically `/usr/share/git-core/templates`.
---use-separate-remote::
- Save remotes heads under `$GIT_DIR/refs/remotes/origin/` instead
- of `$GIT_DIR/refs/heads/`. Only the local master branch is
- saved in the latter. This is the default.
-
---no-separate-remote::
- Save remotes heads in the same namespace as the local
- heads, `$GIT_DIR/refs/heads/'. In regular repositories,
- this is a legacy setup git-clone created by default in
- older Git versions, and will be removed before the next
- major release.
-
<repository>::
The (possibly remote) repository to clone from. It can
be any URL git-fetch supports.
[verse]
'git-show-branch' [--all] [--heads] [--tags] [--topo-order] [--current]
[--more=<n> | --list | --independent | --merge-base]
- [--no-name | --sha1-name] [<rev> | <glob>]...
+ [--no-name | --sha1-name] [--topics] [<rev> | <glob>]...
DESCRIPTION
-----------
of "master"), name them with the unique prefix of their
object names.
+--topics::
+ Shows only commits that are NOT on the first branch given.
+ This helps track topic branches by hiding any commit that
+ is already in the main line of development. When given
+ "git show-branch --topics master topic1 topic2", this
+ will show the revisions given by "git rev-list {caret}master
+ topic1 topic2"
+
Note that --more, --list, --independent and --merge-base options
are mutually exclusive.
Background
----------
-The index is one of the most important data structure in git.
+The index is one of the most important data structures 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
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
+if the files in the working tree are different from what are
recorded in the index to avoid stomping on local changes in them
during patch application, switching branches, and merging.
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
+git first runs `lstat(2)` on the files and compares 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()` function, but the current code does it 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.
There is one slight problem with the optimization based on the
cached stat information. Consider this sequence:
+ : modify 'foo'
$ git update-index 'foo'
- : modify 'foo' in-place without changing its size
+ : modify 'foo' again, 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`
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.
+would see in the filesystem, even though the file `foo` is now
+different.
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
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
+`st_mtime` timestamp on `foo` cannot get a value 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.
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
+checks by `ce_match_stat_basic()` would report that the index entry
does not match the file and git does not have to fall back on more
expensive `ce_modified_check_fs()`.
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
+In order to avoid the above runtime penalty, post 1.4.2 git used
+to have a code that made sure the index file
+got 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:
+I suspected that in practice the situation where many paths in the
+index are all racily clean was quite rare. The only code paths
+that can record recent timestamp for large number of paths are:
. Initial `git add .` of a large project.
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.
+Based on this discussion, the current code does not use the
+"workaround" to avoid the runtime penalty that does not exist in
+practice anymore. This was done with commit 0fc82cff on Aug 15,
+2006.
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.4.4.1.GIT
+DEF_VER=v1.4.4.GIT
LF='
'
# Define NO_ACCURATE_DIFF if your diff program at least sometimes misses
# a missing newline at the end of the file.
#
-# Define COLLISION_CHECK below if you believe that SHA1's
-# 1461501637330902918203684832716283019655932542976 hashes do not give you
-# sufficient guarantee that no collisions between objects will ever happen.
-#
# Define USE_NSEC below if you want git to care about sub-second file mtimes
# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
test-date$X: test-date.c date.o ctype.o
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) test-date.c date.o ctype.o
-test-delta$X: test-delta.c diff-delta.o patch-delta.o
- $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $^
+test-delta$X: test-delta.o diff-delta.o patch-delta.o $(GITLIBS)
+ $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
test-dump-cache-tree$X: dump-cache-tree.o $(GITLIBS)
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
/*
* Copyright (c) 2005, 2006 Rene Scharfe
*/
-#include <time.h>
#include "cache.h"
#include "commit.h"
#include "strbuf.h"
/*
* Copyright (c) 2006 Rene Scharfe
*/
-#include <time.h>
#include "cache.h"
#include "commit.h"
#include "blob.h"
#include "cache.h"
#include "blob.h"
-#include <stdlib.h>
const char *blob_type = "blob";
*
* Copyright (C) 2006 Linus Torvalds
*/
-#include <fnmatch.h>
-
#include "cache.h"
#include "builtin.h"
#include "dir.h"
}
usage(builtin_add_usage);
}
+ if (argc <= i) {
+ fprintf(stderr, "Nothing specified, nothing added.\n");
+ fprintf(stderr, "Maybe you wanted to say 'git add .'?\n");
+ return 0;
+ }
pathspec = get_pathspec(prefix, argv + i);
fill_directory(&dir, pathspec);
* This applies patches on top of some (arbitrary) version of the SCM.
*
*/
-#include <fnmatch.h>
#include "cache.h"
#include "cache-tree.h"
#include "quote.h"
* Copyright (c) 2006 Franck Bui-Huu
* Copyright (c) 2006 Rene Scharfe
*/
-#include <time.h>
#include "cache.h"
#include "builtin.h"
#include "archive.h"
#include "revision.h"
#include "xdiff-interface.h"
-#include <time.h>
-#include <sys/time.h>
-#include <regex.h>
-
static char blame_usage[] =
"git-blame [-c] [-l] [-t] [-f] [-n] [-p] [-L n,m] [-S <revs-file>] [-M] [-C] [-C] [commit] [--] file\n"
" -c, --compatibility Use the same output mode as git-annotate (Default: off)\n"
+" -b Show blank SHA-1 for boundary commits (Default: off)\n"
" -l, --long Show long commit SHA1 (Default: off)\n"
+" --root Do not treat root commits as boundaries (Default: off)\n"
" -t, --time Show raw timestamp (Default: off)\n"
" -f, --show-name Show original filename (Default: auto)\n"
" -n, --show-number Show original linenumber (Default: off)\n"
static int max_orig_digits;
static int max_digits;
static int max_score_digits;
+static int show_root;
+static int blank_boundary;
#ifndef DEBUG
#define DEBUG 0
if (!(commit->object.flags & UNINTERESTING) &&
!(revs->max_age != -1 && commit->date < revs->max_age))
pass_blame(sb, suspect, opt);
+ else {
+ commit->object.flags |= UNINTERESTING;
+ if (commit->object.parsed)
+ mark_parents_uninteresting(commit);
+ }
+ /* treat root commit as boundary */
+ if (!commit->parents && !show_root)
+ commit->object.flags |= UNINTERESTING;
/* Take responsibility for the remaining entries */
for (ent = sb->ent; ent; ent = ent->next)
printf("committer-tz %s\n", ci.committer_tz);
printf("filename %s\n", suspect->path);
printf("summary %s\n", ci.summary);
+ if (suspect->commit->object.flags & UNINTERESTING)
+ printf("boundary\n");
}
else if (suspect->commit->object.flags & MORE_THAN_ONE_PATH)
printf("filename %s\n", suspect->path);
cp = nth_line(sb, ent->lno);
for (cnt = 0; cnt < ent->num_lines; cnt++) {
char ch;
+ int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? 40 : 8;
+
+ if (suspect->commit->object.flags & UNINTERESTING) {
+ if (!blank_boundary) {
+ length--;
+ putchar('^');
+ }
+ else
+ memset(hex, ' ', length);
+ }
- printf("%.*s", (opt & OUTPUT_LONG_OBJECT_NAME) ? 40 : 8, hex);
+ printf("%.*s", length, hex);
if (opt & OUTPUT_ANNOTATE_COMPAT)
printf("\t(%10s\t%10s\t%d)", ci.author,
format_time(ci.author_time, ci.author_tz,
usage(blame_usage);
}
+static int git_blame_config(const char *var, const char *value)
+{
+ if (!strcmp(var, "blame.showroot")) {
+ show_root = git_config_bool(var, value);
+ return 0;
+ }
+ if (!strcmp(var, "blame.blankboundary")) {
+ blank_boundary = git_config_bool(var, value);
+ return 0;
+ }
+ return git_default_config(var, value);
+}
+
int cmd_blame(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
char type[10];
const char *bottomtop = NULL;
+ git_config(git_blame_config);
save_commit_buffer = 0;
opt = 0;
const char *arg = argv[i];
if (*arg != '-')
break;
+ else if (!strcmp("-b", arg))
+ blank_boundary = 1;
+ else if (!strcmp("--root", arg))
+ show_root = 1;
else if (!strcmp("-c", arg))
output_option |= OUTPUT_ANNOTATE_COMPAT;
else if (!strcmp("-t", arg))
* Based on git-branch.sh by Junio C Hamano.
*/
-#include "color.h"
#include "cache.h"
+#include "color.h"
#include "refs.h"
#include "commit.h"
#include "builtin.h"
static const char builtin_branch_usage[] =
- "git-branch (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [-r | -a] [-v [--abbrev=<length>]]";
+ "git-branch [-r] (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [-r | -a] [-v [--abbrev=<length>]]";
+#define REF_UNKNOWN_TYPE 0x00
+#define REF_LOCAL_BRANCH 0x01
+#define REF_REMOTE_BRANCH 0x02
+#define REF_TAG 0x04
static const char *head;
static unsigned char head_sha1[20];
return ret;
}
-static void delete_branches(int argc, const char **argv, int force)
+static int delete_branches(int argc, const char **argv, int force, int kinds)
{
struct commit *rev, *head_rev = head_rev;
unsigned char sha1[20];
- char *name;
+ char *name = NULL;
+ const char *fmt, *remote;
int i;
+ int ret = 0;
+
+ switch (kinds) {
+ case REF_REMOTE_BRANCH:
+ fmt = "refs/remotes/%s";
+ remote = "remote ";
+ force = 1;
+ break;
+ case REF_LOCAL_BRANCH:
+ fmt = "refs/heads/%s";
+ remote = "";
+ break;
+ default:
+ die("cannot use -a with -d");
+ }
if (!force) {
head_rev = lookup_commit_reference(head_sha1);
die("Couldn't look up commit object for HEAD");
}
for (i = 0; i < argc; i++) {
- if (!strcmp(head, argv[i]))
- die("Cannot delete the branch you are currently on.");
+ if (kinds == REF_LOCAL_BRANCH && !strcmp(head, argv[i])) {
+ error("Cannot delete the branch '%s' "
+ "which you are currently on.", argv[i]);
+ ret = 1;
+ continue;
+ }
- name = xstrdup(mkpath("refs/heads/%s", argv[i]));
- if (!resolve_ref(name, sha1, 1, NULL))
- die("Branch '%s' not found.", argv[i]);
+ if (name)
+ free(name);
+
+ name = xstrdup(mkpath(fmt, argv[i]));
+ if (!resolve_ref(name, sha1, 1, NULL)) {
+ error("%sbranch '%s' not found.",
+ remote, argv[i]);
+ ret = 1;
+ continue;
+ }
rev = lookup_commit_reference(sha1);
- if (!rev)
- die("Couldn't look up commit object for '%s'", name);
+ if (!rev) {
+ error("Couldn't look up commit object for '%s'", name);
+ ret = 1;
+ continue;
+ }
/* This checks whether the merge bases of branch and
* HEAD contains branch -- which means that the HEAD
if (!force &&
!in_merge_bases(sha1, rev, head_rev)) {
- fprintf(stderr,
- "The branch '%s' is not a strict subset of your current HEAD.\n"
- "If you are sure you want to delete it, run 'git branch -D %s'.\n",
- argv[i], argv[i]);
- exit(1);
+ error("The branch '%s' is not a strict subset of "
+ "your current HEAD.\n"
+ "If you are sure you want to delete it, "
+ "run 'git branch -D %s'.", argv[i], argv[i]);
+ ret = 1;
+ continue;
}
- if (delete_ref(name, sha1))
- printf("Error deleting branch '%s'\n", argv[i]);
- else
- printf("Deleted branch %s.\n", argv[i]);
+ if (delete_ref(name, sha1)) {
+ error("Error deleting %sbranch '%s'", remote,
+ argv[i]);
+ ret = 1;
+ } else
+ printf("Deleted %sbranch %s.\n", remote, argv[i]);
- free(name);
}
-}
-#define REF_UNKNOWN_TYPE 0x00
-#define REF_LOCAL_BRANCH 0x01
-#define REF_REMOTE_BRANCH 0x02
-#define REF_TAG 0x04
+ if (name)
+ free(name);
+
+ return(ret);
+}
struct ref_item {
char *name;
head += 11;
if (delete)
- delete_branches(argc - i, argv + i, force_delete);
+ return delete_branches(argc - i, argv + i, force_delete, kinds);
else if (i == argc)
print_ref_list(kinds, verbose, abbrev);
else if (rename && (i == argc - 1))
#include "tree.h"
#include "blob.h"
#include "quote.h"
-#include <fnmatch.h>
/* Quoting styles */
#define QUOTE_NONE 0
#include "tag.h"
#include "tree-walk.h"
#include "builtin.h"
-#include <regex.h>
#include "grep.h"
-#include <fnmatch.h>
-#include <sys/wait.h>
/*
* git grep pathspecs are somewhat different from diff-tree pathspecs;
int template_len;
DIR *dir;
- if (!template_dir)
- template_dir = DEFAULT_GIT_TEMPLATE_DIR;
+ if (!template_dir) {
+ template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT);
+ if (!template_dir)
+ template_dir = DEFAULT_GIT_TEMPLATE_DIR;
+ }
strcpy(template_path, template_dir);
template_len = strlen(template_path);
if (template_path[template_len-1] != '/') {
#include "log-tree.h"
#include "builtin.h"
#include "tag.h"
-#include <time.h>
-#include <sys/time.h>
static int default_show_root = 1;
*
* Copyright (C) Linus Torvalds, 2005
*/
-#include <fnmatch.h>
-
#include "cache.h"
#include "quote.h"
#include "dir.h"
* Another stupid program, this one parsing the headers of an
* email to figure out authorship and subject
*/
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#ifndef NO_ICONV
-#include <iconv.h>
-#endif
-#include "git-compat-util.h"
#include "cache.h"
#include "builtin.h"
* It just splits a mbox into a list of files: "0001" "0002" ..
* so you can process them further from there.
*/
-#include <unistd.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <stdio.h>
#include "cache.h"
#include "builtin.h"
*
* Copyright (C) 2006 Johannes Schindelin
*/
-#include <fnmatch.h>
-
#include "cache.h"
#include "builtin.h"
#include "dir.h"
-#include <stdlib.h>
#include "builtin.h"
#include "cache.h"
#include "commit.h"
#include "diff.h"
#include "revision.h"
#include "list-objects.h"
-#include <sys/time.h>
-#include <signal.h>
static const char pack_usage[] = "\
git-pack-objects [{ -q | --progress | --all-progress }] \n\
#include "builtin.h"
#include "cache.h"
-#include <regex.h>
static const char git_config_set_usage[] =
-"git-repo-config [ --global ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --list";
+"git-repo-config [ --global ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --list";
static char *key;
static regex_t *key_regexp;
char *global = NULL, *repo_config = NULL;
const char *local;
- local = getenv("GIT_CONFIG");
+ local = getenv(CONFIG_ENVIRONMENT);
if (!local) {
const char *home = getenv("HOME");
- local = getenv("GIT_CONFIG_LOCAL");
+ local = getenv(CONFIG_LOCAL_ENVIRONMENT);
if (!local)
local = repo_config = xstrdup(git_path("config"));
if (home)
} else {
die("$HOME not set");
}
+ } else if (!strcmp(argv[1], "--rename-section")) {
+ int ret;
+ if (argc != 4)
+ usage(git_config_set_usage);
+ ret = git_config_rename_section(argv[2], argv[3]);
+ if (ret < 0)
+ return ret;
+ if (ret == 0) {
+ fprintf(stderr, "No such section!\n");
+ return 1;
+ }
+ return 0;
} else
break;
argc--;
-#include "wt-status.h"
#include "cache.h"
+#include "wt-status.h"
extern int wt_status_use_color;
#include "diff.h"
#include "path-list.h"
#include "revision.h"
-#include <string.h>
static const char shortlog_usage[] =
"git-shortlog [-n] [-s] [<commit-id>... ]";
-#include <stdlib.h>
-#include <fnmatch.h>
#include "cache.h"
#include "commit.h"
#include "refs.h"
#include "builtin.h"
static const char show_branch_usage[] =
-"git-show-branch [--sparse] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...]";
+"git-show-branch [--sparse] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...] | --reflog[=n] <branch>";
static int default_num;
static int default_alloc;
#define REV_SHIFT 2
#define MAX_REVS (FLAG_BITS - REV_SHIFT) /* should not exceed bits_per_int - REV_SHIFT */
+#define DEFAULT_REFLOG 4
+
static struct commit *interesting(struct commit_list *list)
{
while (list) {
int head_at = -1;
int topics = 0;
int dense = 1;
+ int reflog = 0;
git_config(git_show_branch_config);
dense = 0;
else if (!strcmp(arg, "--date-order"))
lifo = 0;
+ else if (!strcmp(arg, "--reflog")) {
+ reflog = DEFAULT_REFLOG;
+ }
+ else if (!strncmp(arg, "--reflog=", 9)) {
+ char *end;
+ reflog = strtoul(arg + 9, &end, 10);
+ if (*end != '\0')
+ die("unrecognized reflog count '%s'", arg + 9);
+ }
else
usage(show_branch_usage);
ac--; av++;
ac--; av++;
/* Only one of these is allowed */
- if (1 < independent + merge_base + (extra != 0))
+ if (1 < independent + merge_base + (extra != 0) + (!!reflog))
usage(show_branch_usage);
/* If nothing is specified, show all branches by default */
if (all_heads + all_tags)
snarf_refs(all_heads, all_tags);
- while (0 < ac) {
- append_one_rev(*av);
- ac--; av++;
+ if (reflog) {
+ int reflen;
+ if (!ac)
+ die("--reflog option needs one branch name");
+ reflen = strlen(*av);
+ for (i = 0; i < reflog; i++) {
+ char *name = xmalloc(reflen + 20);
+ sprintf(name, "%s@{%d}", *av, i);
+ append_one_rev(name);
+ }
+ }
+ else {
+ while (0 < ac) {
+ append_one_rev(*av);
+ ac--; av++;
+ }
}
head_p = resolve_ref("HEAD", head_sha1, 1, NULL);
#include "refs.h"
#include "object.h"
#include "tag.h"
+#include "path-list.h"
-static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--dereference] [-s|--hash[=<length>]] [--abbrev[=<length>]] [--tags] [--heads] [--] [pattern*]";
+static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--dereference] [-s|--hash[=<length>]] [--abbrev[=<length>]] [--tags] [--heads] [--] [pattern*] < ref-list";
static int deref_tags = 0, show_head = 0, tags_only = 0, heads_only = 0,
found_match = 0, verify = 0, quiet = 0, hash_only = 0, abbrev = 0;
static const char **pattern;
+static void show_one(const char *refname, const unsigned char *sha1)
+{
+ const char *hex = find_unique_abbrev(sha1, abbrev);
+ if (hash_only)
+ printf("%s\n", hex);
+ else
+ printf("%s %s\n", hex, refname);
+}
+
static int show_ref(const char *refname, const unsigned char *sha1, int flag, void *cbdata)
{
struct object *obj;
if (quiet)
return 0;
- hex = find_unique_abbrev(sha1, abbrev);
- if (hash_only)
- printf("%s\n", hex);
- else
- printf("%s %s\n", hex, refname);
+ show_one(refname, sha1);
if (!deref_tags)
return 0;
return 0;
}
+static int add_existing(const char *refname, const unsigned char *sha1, int flag, void *cbdata)
+{
+ struct path_list *list = (struct path_list *)cbdata;
+ path_list_insert(refname, list);
+ return 0;
+}
+
+/*
+ * read "^(?:<anything>\s)?<refname>(?:\^\{\})?$" from the standard input,
+ * and
+ * (1) strip "^{}" at the end of line if any;
+ * (2) ignore if match is provided and does not head-match refname;
+ * (3) warn if refname is not a well-formed refname and skip;
+ * (4) ignore if refname is a ref that exists in the local repository;
+ * (5) otherwise output the line.
+ */
+static int exclude_existing(const char *match)
+{
+ static struct path_list existing_refs = { NULL, 0, 0, 0 };
+ char buf[1024];
+ int matchlen = match ? strlen(match) : 0;
+
+ for_each_ref(add_existing, &existing_refs);
+ while (fgets(buf, sizeof(buf), stdin)) {
+ char *ref;
+ int len = strlen(buf);
+
+ if (len > 0 && buf[len - 1] == '\n')
+ buf[--len] = '\0';
+ if (3 <= len && !strcmp(buf + len - 3, "^{}")) {
+ len -= 3;
+ buf[len] = '\0';
+ }
+ for (ref = buf + len; buf < ref; ref--)
+ if (isspace(ref[-1]))
+ break;
+ if (match) {
+ int reflen = buf + len - ref;
+ if (reflen < matchlen)
+ continue;
+ if (strncmp(ref, match, matchlen))
+ continue;
+ }
+ if (check_ref_format(ref)) {
+ fprintf(stderr, "warning: ref '%s' ignored\n", ref);
+ continue;
+ }
+ if (!path_list_has_path(&existing_refs, ref)) {
+ printf("%s\n", buf);
+ }
+ }
+ return 0;
+}
+
int cmd_show_ref(int argc, const char **argv, const char *prefix)
{
int i;
if (!strncmp(arg, "--hash=", 7) ||
(!strncmp(arg, "--abbrev", 8) &&
(arg[8] == '=' || arg[8] == '\0'))) {
- if (arg[3] != 'h' && !arg[8])
+ if (arg[2] != 'h' && !arg[8])
/* --abbrev only */
abbrev = DEFAULT_ABBREV;
else {
/* --hash= or --abbrev= */
char *end;
- if (arg[3] == 'h') {
+ if (arg[2] == 'h') {
hash_only = 1;
arg += 7;
}
heads_only = 1;
continue;
}
+ if (!strcmp(arg, "--exclude-existing"))
+ return exclude_existing(NULL);
+ if (!strncmp(arg, "--exclude-existing=", 19))
+ return exclude_existing(arg + 19);
usage(show_ref_usage);
}
+
+ if (verify) {
+ unsigned char sha1[20];
+
+ while (*pattern) {
+ if (!strncmp(*pattern, "refs/", 5) &&
+ resolve_ref(*pattern, sha1, 1, NULL)) {
+ if (!quiet)
+ show_one(*pattern, sha1);
+ }
+ else if (!quiet)
+ die("'%s' - not a valid ref", *pattern);
+ else
+ return 1;
+ pattern++;
+ }
+ return 0;
+ }
+
if (show_head)
head_ref(show_ref, NULL);
for_each_ref(show_ref, NULL);
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
#include "builtin.h"
/*
/*
* Copyright (c) 2005, 2006 Rene Scharfe
*/
-#include <time.h>
#include "cache.h"
#include "commit.h"
#include "tar.h"
#include "tag.h"
#include "tree.h"
-#include <sys/time.h>
-
static int dry_run, quiet, recover, has_errors;
static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] < pack-file";
/*
* Copyright (c) 2006 Franck Bui-Huu
*/
-#include <time.h>
-#include <sys/wait.h>
-#include <sys/poll.h>
#include "cache.h"
#include "builtin.h"
#include "archive.h"
#define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
#define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
#define GRAFT_ENVIRONMENT "GIT_GRAFT_FILE"
+#define TEMPLATE_DIR_ENVIRONMENT "GIT_TEMPLATE_DIR"
+#define CONFIG_ENVIRONMENT "GIT_CONFIG"
+#define CONFIG_LOCAL_ENVIRONMENT "GIT_CONFIG_LOCAL"
+#define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH"
extern int is_bare_git_dir(const char *dir);
extern const char *get_git_dir(void);
extern int git_config_bool(const char *, const char *);
extern int git_config_set(const char *, const char *);
extern int git_config_set_multivar(const char *, const char *, const char *, int);
+extern int git_config_rename_section(const char *, const char *);
extern int check_repository_format_version(const char *var, const char *value);
#define MAX_GITNAME (1000)
-#include "color.h"
#include "cache.h"
-#include "git-compat-util.h"
-
-#include <stdarg.h>
+#include "color.h"
#define COLOR_RESET "\033[m"
*/
char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
struct { int base, len; } best, cur;
- u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
+ unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
int i;
/*
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
#include "../git-compat-util.h"
void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset)
-#include <stdlib.h>
-#include <string.h>
+#include "../git-compat-util.h"
int gitsetenv(const char *name, const char *value, int replace)
{
-#include <string.h>
+#include "../git-compat-util.h"
size_t gitstrlcpy(char *dest, const char *src, size_t size)
{
-#include <stdlib.h>
-#include <string.h>
+#include "../git-compat-util.h"
void gitunsetenv (const char *name)
{
*
*/
#include "cache.h"
-#include <regex.h>
#define MAXNAME (256)
* $GIT_CONFIG_LOCAL will make it process it in addition to the
* global config file, the same way it would the per-repository
* config file otherwise. */
- filename = getenv("GIT_CONFIG");
+ filename = getenv(CONFIG_ENVIRONMENT);
if (!filename) {
home = getenv("HOME");
- filename = getenv("GIT_CONFIG_LOCAL");
+ filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
if (!filename)
filename = repo_config = xstrdup(git_path("config"));
}
char* lock_file;
const char* last_dot = strrchr(key, '.');
- config_filename = getenv("GIT_CONFIG");
+ config_filename = getenv(CONFIG_ENVIRONMENT);
if (!config_filename) {
- config_filename = getenv("GIT_CONFIG_LOCAL");
+ config_filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
if (!config_filename)
config_filename = git_path("config");
}
return ret;
}
+int git_config_rename_section(const char *old_name, const char *new_name)
+{
+ int ret = 0;
+ char *config_filename;
+ struct lock_file *lock = xcalloc(sizeof(struct lock_file), 1);
+ int out_fd;
+ char buf[1024];
+
+ config_filename = getenv(CONFIG_ENVIRONMENT);
+ if (!config_filename) {
+ config_filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
+ if (!config_filename)
+ config_filename = git_path("config");
+ }
+ config_filename = xstrdup(config_filename);
+ out_fd = hold_lock_file_for_update(lock, config_filename, 0);
+ if (out_fd < 0) {
+ ret = error("Could not lock config file!");
+ goto out;
+ }
+
+ if (!(config_file = fopen(config_filename, "rb"))) {
+ ret = error("Could not open config file!");
+ goto out;
+ }
+
+ while (fgets(buf, sizeof(buf), config_file)) {
+ int i;
+ for (i = 0; buf[i] && isspace(buf[i]); i++)
+ ; /* do nothing */
+ if (buf[i] == '[') {
+ /* it's a section */
+ int j = 0, dot = 0;
+ for (i++; buf[i] && buf[i] != ']'; i++) {
+ if (!dot && isspace(buf[i])) {
+ dot = 1;
+ if (old_name[j++] != '.')
+ break;
+ for (i++; isspace(buf[i]); i++)
+ ; /* do nothing */
+ if (buf[i] != '"')
+ break;
+ continue;
+ }
+ if (buf[i] == '\\' && dot)
+ i++;
+ else if (buf[i] == '"' && dot) {
+ for (i++; isspace(buf[i]); i++)
+ ; /* do_nothing */
+ break;
+ }
+ if (buf[i] != old_name[j++])
+ break;
+ }
+ if (buf[i] == ']') {
+ /* old_name matches */
+ ret++;
+ store.baselen = strlen(new_name);
+ store_write_section(out_fd, new_name);
+ continue;
+ }
+ }
+ write(out_fd, buf, strlen(buf));
+ }
+ fclose(config_file);
+ if (close(out_fd) || commit_lock_file(lock) < 0)
+ ret = error("Cannot commit config file!");
+ out:
+ free(config_filename);
+ return ret;
+}
## --enable-FEATURE[=ARG] and --disable-FEATURE
#
-# Define COLLISION_CHECK below if you believe that SHA1's
-# 1461501637330902918203684832716283019655932542976 hashes do not give you
-# sufficient guarantee that no collisions between objects will ever happen.
-#
# Define USE_NSEC below if you want git to care about sub-second file mtimes
# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
#include "pkt-line.h"
#include "quote.h"
#include "refs.h"
-#include <sys/wait.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <signal.h>
static char *server_capabilities;
syn region gitLine start=/^#/ end=/$/
-syn region gitCommit start=/^# Updated but not checked in:$/ end=/^#$/ contains=gitHead,gitCommitFile
+syn region gitCommit start=/^# Added but not yet committed:$/ end=/^#$/ contains=gitHead,gitCommitFile
syn region gitHead contained start=/^# (.*)/ end=/^#$/
-syn region gitChanged start=/^# Changed but not updated:/ end=/^#$/ contains=gitHead,gitChangedFile
+syn region gitChanged start=/^# Changed but not added:/ end=/^#$/ contains=gitHead,gitChangedFile
syn region gitUntracked start=/^# Untracked files:/ end=/^#$/ contains=gitHead,gitUntrackedFile
syn match gitCommitFile contained /^#\t.*/hs=s+2
-#define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
-#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
-#define _GNU_SOURCE
-#include <time.h>
#include "cache.h"
#include "blob.h"
#include "commit.h"
-#include <signal.h>
-#include <sys/wait.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <sys/poll.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <syslog.h>
-#include <pwd.h>
-#include <grp.h>
-#include <limits.h>
-#include "pkt-line.h"
#include "cache.h"
+#include "pkt-line.h"
#include "exec_cmd.h"
#include "interpolate.h"
+#include <syslog.h>
+
#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 256
#endif
* Copyright (C) Linus Torvalds, 2005
*/
-#include <time.h>
-#include <sys/time.h>
-
#include "cache.h"
static time_t my_mktime(struct tm *tm)
* licensing gets turned into GPLv2 within this project.
*/
-#include <stdlib.h>
-#include <string.h>
-#include "delta.h"
-
#include "git-compat-util.h"
+#include "delta.h"
/* maximum hash entry list for the same hash bucket */
#define HASH_LIMIT 64
/*
* Copyright (C) 2005 Junio C Hamano
*/
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
#include "cache.h"
#include "quote.h"
#include "diff.h"
* objects however would tend to be slower as they need
* to be individually opened and inflated.
*/
- if (FAST_WORKING_DIRECTORY && !want_file && has_sha1_pack(sha1, NULL))
+ if (!FAST_WORKING_DIRECTORY && !want_file && has_sha1_pack(sha1, NULL))
return 0;
len = strlen(name);
#include "cache.h"
#include "diff.h"
#include "diffcore.h"
-#include <fnmatch.h>
static char **order;
static int order_cnt;
#include "diff.h"
#include "diffcore.h"
-#include <regex.h>
-
static unsigned int contains(struct diff_filespec *one,
const char *needle, unsigned long len,
regex_t *regexp)
* Copyright (C) Linus Torvalds, 2005-2006
* Junio Hamano, 2005-2006
*/
-#include <dirent.h>
-#include <fnmatch.h>
-
#include "cache.h"
#include "dir.h"
-#include <sys/types.h>
-#include <dirent.h>
#include "cache.h"
#include "blob.h"
if (current_exec_path)
return current_exec_path;
- env = getenv("GIT_EXEC_PATH");
+ env = getenv(EXEC_PATH_ENVIRONMENT);
if (env && *env) {
return env;
}
char git_command[PATH_MAX + 1];
int i;
const char *paths[] = { current_exec_path,
- getenv("GIT_EXEC_PATH"),
+ getenv(EXEC_PATH_ENVIRONMENT),
builtin_exec_path };
for (i = 0; i < ARRAY_SIZE(paths); ++i) {
#include "tag.h"
#include "exec_cmd.h"
#include "sideband.h"
-#include <sys/wait.h>
static int keep_pack;
static int quiet;
-#include "fetch.h"
-
#include "cache.h"
+#include "fetch.h"
#include "commit.h"
#include "tree.h"
#include "tree-walk.h"
-#include <sys/types.h>
-#include <dirent.h>
-
#include "cache.h"
#include "commit.h"
#include "tree.h"
}
usage() {
- die "Usage: $0 [--template=<template_directory>] [--no-separate-remote] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [-n] <repo> [<dir>]"
+ die "Usage: $0 [--template=<template_directory>] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [-n] <repo> [<dir>]"
}
get_repo_base() {
*,--template=*)
template="$1" ;;
*,-q|*,--quiet) quiet=-q ;;
- *,--use-separate-remote)
- # default
- use_separate_remote=t ;;
+ *,--use-separate-remote) ;;
*,--no-separate-remote)
- use_separate_remote= ;;
+ die "clones are always made with separate-remote layout" ;;
1,--reference) usage ;;
*,--reference)
shift; reference="$1" ;;
if test -z "$bare" && test -f "$GIT_DIR/REMOTE_HEAD"
then
- # Figure out which remote branch HEAD points at.
- case "$use_separate_remote" in
- '') remote_top=refs/heads ;;
- *) remote_top="refs/remotes/$origin" ;;
- esac
-
+ # a non-bare repository is always in separate-remote layout
+ remote_top="refs/remotes/$origin"
head_sha1=`cat "$GIT_DIR/REMOTE_HEAD"`
case "$head_sha1" in
'ref: refs/'*)
)
)
- # Write out remotes/$origin file, and update our "$head_points_at".
+ # Write out remote.$origin config, and update our "$head_points_at".
case "$head_points_at" in
?*)
- mkdir -p "$GIT_DIR/remotes" &&
+ # Local default branch
git-symbolic-ref HEAD "refs/heads/$head_points_at" &&
- case "$use_separate_remote" in
- t) origin_track="$remote_top/$head_points_at"
- git-update-ref HEAD "$head_sha1" ;;
- *) origin_track="$remote_top/$origin"
- git-update-ref "refs/heads/$origin" "$head_sha1" ;;
- esac &&
+
+ # Tracking branch for the primary branch at the remote.
+ origin_track="$remote_top/$head_points_at" &&
+ git-update-ref HEAD "$head_sha1" &&
+
+ # Upstream URL
git-repo-config remote."$origin".url "$repo" &&
+
+ # Set up the mappings to track the remote branches.
git-repo-config remote."$origin".fetch \
- "refs/heads/$head_points_at:$origin_track" &&
- (cd "$GIT_DIR/$remote_top" && find . -type f -print) |
- while read dotslref
- do
- name=`expr "$dotslref" : './\(.*\)'`
- if test "z$head_points_at" = "z$name"
- then
- continue
- fi
- if test "$use_separate_remote" = '' &&
- test "z$origin" = "z$name"
- then
- continue
- fi
- git-repo-config remote."$origin".fetch "refs/heads/${name}:$remote_top/${name}" '^$'
- done &&
- case "$use_separate_remote" in
- t)
- rm -f "refs/remotes/$origin/HEAD"
- git-symbolic-ref "refs/remotes/$origin/HEAD" \
- "refs/remotes/$origin/$head_points_at"
- esac &&
+ "refs/heads/*:$remote_top/*" '^$' &&
+ rm -f "refs/remotes/$origin/HEAD"
+ git-symbolic-ref "refs/remotes/$origin/HEAD" \
+ "refs/remotes/$origin/$head_points_at" &&
+
git-repo-config branch."$head_points_at".remote "$origin" &&
git-repo-config branch."$head_points_at".merge "refs/heads/$head_points_at"
esac
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
+#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
+#define _GNU_SOURCE
+#define _BSD_SOURCE
+
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#include <sys/param.h>
-#include <netinet/in.h>
#include <sys/types.h>
#include <dirent.h>
+#include <sys/time.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <fnmatch.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <assert.h>
+#include <regex.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <grp.h>
+
+#ifndef NO_ICONV
+#include <iconv.h>
+#endif
/* On most systems <limits.h> would have given us this, but
* not on some systems (e.g. GNU/Hurd).
$log->debug("Temporary directory for merge is $dir");
- my $return = system("git merge-file", $file_local, $file_old, $file_new);
+ my $return = system("git", "merge-file", $file_local, $file_old, $file_new);
$return >>= 8;
if ( $return == 0 )
# Global that is reused later
ls_remote_result=$(git ls-remote $upload_pack "$remote") ||
- die "Cannot find the reflist at $remote"
+ die "Cannot get the repository state from $remote"
append_fetch_head () {
head_="$1"
reflist=$(get_remote_refs_for_fetch "$@")
if test "$tags"
then
- taglist=`IFS=" " &&
+ taglist=`IFS=' ' &&
echo "$ls_remote_result" |
while read sha1 name
do
*:refs/*)
# effective only when we are following remote branch
# using local tracking branch.
- taglist=$(IFS=" " &&
+ taglist=$(IFS=' ' &&
echo "$ls_remote_result" |
- sed -n -e 's|^\('"$_x40"'\) \(refs/tags/.*\)^{}$|\1 \2|p' \
- -e 's|^\('"$_x40"'\) \(refs/tags/.*\)$|\1 \2|p' |
+ git-show-ref --exclude-existing=refs/tags/ |
while read sha1 name
do
- git-show-ref --verify --quiet -- "$name" && continue
- git-check-ref-format "$name" || {
- echo >&2 "warning: tag ${name} ignored"
- continue
- }
git-cat-file -t "$sha1" >/dev/null 2>&1 || continue
echo >&2 "Auto-following $name"
echo ".${name}:${name}"
do
case "$sha1" in
failed)
- die "Failed to find remote refs"
+ exit 1 ;;
esac
case "$path" in
refs/heads/*)
local_force=
test "z$lref" = "z$ref" || local_force='+'
echo "$ls_remote_result" |
+ sed -e '/\^{}$/d' |
(
IFS=' '
while read sha1 name
do
+ # ignore the ones that do not start with $from
mapped=${name#"$from"}
- if test "z$name" != "z${name%'^{}'}" ||
- test "z$name" = "z$mapped"
- then
- continue
- fi
+ test "z$name" = "z$mapped" && continue
echo "${local_force}${name}:${to}${mapped}"
done
)
# or the first one otherwise; add prefix . to the rest
# to prevent the secondary branches to be merged by default.
merge_branches=
- found_mergeref=
curr_branch=
if test "$1" = "-d"
then
curr_branch=$(git-symbolic-ref HEAD | \
sed -e 's|^refs/heads/||')
merge_branches=$(git-repo-config \
- --get-all "branch.${curr_branch}.merge")
+ --get-all "branch.${curr_branch}.merge") ||
+ merge_branches=.this.would.never.match.any.ref.
fi
set x $(expand_refs_wildcard "$@")
shift
dot_prefix= && break
done
fi
- if test -z $dot_prefix
- then
- found_mergeref=true
- fi
case "$remote" in
'') remote=HEAD ;;
refs/heads/* | refs/tags/* | refs/remotes/*) ;;
fi
echo "${dot_prefix}${force}${remote}:${local}"
done
- if test -z "$found_mergeref" -a "$curr_branch"
- then
- echo >&2 "Warning: No merge candidate found because value of config option
- \"branch.${curr_branch}.merge\" does not match any remote branch fetched."
- fi
}
# Returns list of src: (no store), or src:dst (store)
case "$merge_head" in
'')
+ curr_branch=$(git-symbolic-ref HEAD | \
+ sed -e 's|^refs/heads/||')
+ echo >&2 "Warning: No merge candidate found because value of config option
+ \"branch.${curr_branch}.merge\" does not match any remote branch fetched."
echo >&2 "No changes."
exit 0
;;
sub merge {
my ($name, $path) = @_;
record_preimage($path, "$rr_dir/$name/thisimage");
- unless (system('git merge-file', map { "$rr_dir/$name/${_}image" }
+ unless (system('git', 'merge-file', map { "$rr_dir/$name/${_}image" }
qw(this pre post))) {
my $in;
open $in, "<$rr_dir/$name/thisimage" or
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdarg.h>
-#include "git-compat-util.h"
+#include "builtin.h"
#include "exec_cmd.h"
#include "cache.h"
#include "quote.h"
-#include "builtin.h"
-
const char git_usage_string[] =
"git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate] [--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]";
"tags" => \&git_tags,
"tree" => \&git_tree,
"snapshot" => \&git_snapshot,
+ "object" => \&git_object,
# those below don't need $project
"opml" => \&git_opml,
"project_list" => \&git_project_list,
my $line = shift;
$line = esc_html($line, -nbsp=>1);
- if ($line =~ m/([0-9a-fA-F]{40})/) {
+ if ($line =~ m/([0-9a-fA-F]{8,40})/) {
my $hash_text = $1;
- if (git_get_type($hash_text) eq "commit") {
- my $link =
- $cgi->a({-href => href(action=>"commit", hash=>$hash_text),
- -class => "text"}, $hash_text);
- $line =~ s/$hash_text/$link/;
- }
+ my $link =
+ $cgi->a({-href => href(action=>"object", hash=>$hash_text),
+ -class => "text"}, $hash_text);
+ $line =~ s/$hash_text/$link/;
}
return $line;
}
$name = $ref;
}
- $markers .= " <span class=\"$type\">" . esc_html($name) . "</span>";
+ $markers .= " <span class=\"$type\" title=\"$ref\">" .
+ esc_html($name) . "</span>";
}
}
}
}
+# return link target (what link points to)
+sub git_get_link_target {
+ my $hash = shift;
+ my $link_target;
+
+ # read link
+ open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
+ or return;
+ {
+ local $/;
+ $link_target = <$fd>;
+ }
+ close $fd
+ or return;
+
+ return $link_target;
+}
+
+# given link target, and the directory (basedir) the link is in,
+# return target of link relative to top directory (top tree);
+# return undef if it is not possible (including absolute links).
+sub normalize_link_target {
+ my ($link_target, $basedir, $hash_base) = @_;
+
+ # we can normalize symlink target only if $hash_base is provided
+ return unless $hash_base;
+
+ # absolute symlinks (beginning with '/') cannot be normalized
+ return if (substr($link_target, 0, 1) eq '/');
+
+ # normalize link target to path from top (root) tree (dir)
+ my $path;
+ if ($basedir) {
+ $path = $basedir . '/' . $link_target;
+ } else {
+ # we are in top (root) tree (dir)
+ $path = $link_target;
+ }
+
+ # remove //, /./, and /../
+ my @path_parts;
+ foreach my $part (split('/', $path)) {
+ # discard '.' and ''
+ next if (!$part || $part eq '.');
+ # handle '..'
+ if ($part eq '..') {
+ if (@path_parts) {
+ pop @path_parts;
+ } else {
+ # link leads outside repository (outside top dir)
+ return;
+ }
+ } else {
+ push @path_parts, $part;
+ }
+ }
+ $path = join('/', @path_parts);
+
+ return $path;
+}
+
# print tree entry (row of git_tree), but without encompassing <tr> element
sub git_print_tree_entry {
my ($t, $basedir, $hash_base, $have_blame) = @_;
my %base_key = ();
- $base_key{hash_base} = $hash_base if defined $hash_base;
+ $base_key{'hash_base'} = $hash_base if defined $hash_base;
# The format of a table row is: mode list link. Where mode is
# the mode of the entry, list is the name of the entry, an href,
print "<td class=\"list\">" .
$cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
file_name=>"$basedir$t->{'name'}", %base_key),
- -class => "list"}, esc_path($t->{'name'})) . "</td>\n";
+ -class => "list"}, esc_path($t->{'name'}));
+ if (S_ISLNK(oct $t->{'mode'})) {
+ my $link_target = git_get_link_target($t->{'hash'});
+ if ($link_target) {
+ my $norm_target = normalize_link_target($link_target, $basedir, $hash_base);
+ if (defined $norm_target) {
+ print " -> " .
+ $cgi->a({-href => href(action=>"object", hash_base=>$hash_base,
+ file_name=>$norm_target),
+ -title => $norm_target}, esc_path($link_target));
+ } else {
+ print " -> " . esc_path($link_target);
+ }
+ }
+ }
+ print "</td>\n";
print "<td class=\"link\">";
print $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
- file_name=>"$basedir$t->{'name'}", %base_key)},
- "blob");
+ file_name=>"$basedir$t->{'name'}", %base_key)},
+ "blob");
if ($have_blame) {
print " | " .
$cgi->a({-href => href(action=>"blame", hash=>$t->{'hash'},
- file_name=>"$basedir$t->{'name'}", %base_key)},
- "blame");
+ file_name=>"$basedir$t->{'name'}", %base_key)},
+ "blame");
}
if (defined $hash_base) {
print " | " .
print "</td>\n";
print "<td class=\"link\">";
print $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'},
- file_name=>"$basedir$t->{'name'}", %base_key)},
- "tree");
+ file_name=>"$basedir$t->{'name'}", %base_key)},
+ "tree");
if (defined $hash_base) {
print " | " .
$cgi->a({-href => href(action=>"history", hash_base=>$hash_base,
my $owner = git_get_project_owner($project);
my $refs = git_get_references();
- my @taglist = git_get_tags_list(15);
- my @headlist = git_get_heads_list(15);
+ # These get_*_list functions return one more to allow us to see if
+ # there are more ...
+ my @taglist = git_get_tags_list(16);
+ my @headlist = git_get_heads_list(16);
my @forklist;
my ($check_forks) = gitweb_check_feature('forks');
}
}
+ # we need to request one more than 16 (0..15) to check if
+ # those 16 are all
open my $fd, "-|", git_cmd(), "rev-list", "--max-count=17",
git_get_head_hash($project), "--"
or die_error(undef, "Open git-rev-list failed");
close $fd;
git_print_header_div('shortlog');
git_shortlog_body(\@revlist, 0, 15, $refs,
+ $#revlist <= 15 ? undef :
$cgi->a({-href => href(action=>"shortlog")}, "..."));
if (@taglist) {
git_print_header_div('tags');
git_tags_body(\@taglist, 0, 15,
+ $#taglist <= 15 ? undef :
$cgi->a({-href => href(action=>"tags")}, "..."));
}
if (@headlist) {
git_print_header_div('heads');
git_heads_body(\@headlist, $head, 0, 15,
+ $#headlist <= 15 ? undef :
$cgi->a({-href => href(action=>"heads")}, "..."));
}
my $filename = basename($project) . "-$hash.tar.$suffix";
print $cgi->header(
- -type => 'application/x-tar',
- -content_encoding => $ctype,
+ -type => "application/$ctype",
-content_disposition => 'inline; filename="' . "$filename" . '"',
-status => '200 OK');
my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'});
my %cd = parse_date($co{'committer_epoch'}, $co{'committer_tz'});
- my $parent = $co{'parent'};
+ my $parent = $co{'parent'};
+ my $parents = $co{'parents'}; # listref
+
+ # we need to prepare $formats_nav before any parameter munging
+ my $formats_nav;
+ if (!defined $parent) {
+ # --root commitdiff
+ $formats_nav .= '(initial)';
+ } elsif (@$parents == 1) {
+ # single parent commit
+ $formats_nav .=
+ '(parent: ' .
+ $cgi->a({-href => href(action=>"commit",
+ hash=>$parent)},
+ esc_html(substr($parent, 0, 7))) .
+ ')';
+ } else {
+ # merge commit
+ $formats_nav .=
+ '(merge: ' .
+ join(' ', map {
+ $cgi->a({-href => href(action=>"commitdiff",
+ hash=>$_)},
+ esc_html(substr($_, 0, 7)));
+ } @$parents ) .
+ ')';
+ }
+
if (!defined $parent) {
$parent = "--root";
}
- open my $fd, "-|", git_cmd(), "diff-tree", '-r', "--no-commit-id",
- @diff_opts, $parent, $hash, "--"
- or die_error(undef, "Open git-diff-tree failed");
- my @difftree = map { chomp; $_ } <$fd>;
- close $fd or die_error(undef, "Reading git-diff-tree failed");
+ my @difftree;
+ if (@$parents <= 1) {
+ # difftree output is not printed for merges
+ open my $fd, "-|", git_cmd(), "diff-tree", '-r', "--no-commit-id",
+ @diff_opts, $parent, $hash, "--"
+ or die_error(undef, "Open git-diff-tree failed");
+ @difftree = map { chomp; $_ } <$fd>;
+ close $fd or die_error(undef, "Reading git-diff-tree failed");
+ }
# non-textual hash id's can be cached
my $expires;
my $have_snapshot = gitweb_have_snapshot();
- my @views_nav = ();
- if (defined $file_name && defined $co{'parent'}) {
- push @views_nav,
- $cgi->a({-href => href(action=>"blame", hash_parent=>$parent, file_name=>$file_name)},
- "blame");
- }
git_header_html(undef, $expires);
git_print_page_nav('commit', '',
$hash, $co{'tree'}, $hash,
- join (' | ', @views_nav));
+ $formats_nav);
if (defined $co{'parent'}) {
git_print_header_div('commitdiff', esc_html($co{'title'}) . $ref, $hash);
}
print "</td>" .
"</tr>\n";
- my $parents = $co{'parents'};
+
foreach my $par (@$parents) {
print "<tr>" .
"<td>parent</td>" .
git_print_log($co{'comment'});
print "</div>\n";
- git_difftree_body(\@difftree, $hash, $parent);
+ if (@$parents <= 1) {
+ # do not output difftree/whatchanged for merges
+ git_difftree_body(\@difftree, $hash, $parent);
+ }
git_footer_html();
}
+sub git_object {
+ # object is defined by:
+ # - hash or hash_base alone
+ # - hash_base and file_name
+ my $type;
+
+ # - hash or hash_base alone
+ if ($hash || ($hash_base && !defined $file_name)) {
+ my $object_id = $hash || $hash_base;
+
+ my $git_command = git_cmd_str();
+ open my $fd, "-|", "$git_command cat-file -t $object_id 2>/dev/null"
+ or die_error('404 Not Found', "Object does not exist");
+ $type = <$fd>;
+ chomp $type;
+ close $fd
+ or die_error('404 Not Found', "Object does not exist");
+
+ # - hash_base and file_name
+ } elsif ($hash_base && defined $file_name) {
+ $file_name =~ s,/+$,,;
+
+ system(git_cmd(), "cat-file", '-e', $hash_base) == 0
+ or die_error('404 Not Found', "Base object does not exist");
+
+ # here errors should not hapen
+ open my $fd, "-|", git_cmd(), "ls-tree", $hash_base, "--", $file_name
+ or die_error(undef, "Open git-ls-tree failed");
+ my $line = <$fd>;
+ close $fd;
+
+ #'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c'
+ unless ($line && $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t/) {
+ die_error('404 Not Found', "File or directory for given base does not exist");
+ }
+ $type = $2;
+ $hash = $3;
+ } else {
+ die_error('404 Not Found', "Not enough information to find object");
+ }
+
+ print $cgi->redirect(-uri => href(action=>$type, -full=>1,
+ hash=>$hash, hash_base=>$hash_base,
+ file_name=>$file_name),
+ -status => '302 Found');
+}
+
sub git_blobdiff {
my $format = shift || 'html';
#include "cache.h"
-#include <regex.h>
#include "grep.h"
void append_grep_pattern(struct grep_opt *opt, const char *pat,
*
* Builtin help-related commands (help, usage, version)
*/
-#include <sys/ioctl.h>
#include "cache.h"
#include "builtin.h"
#include "exec_cmd.h"
#include "common-cmds.h"
-
+#include <sys/ioctl.h>
/* most GUI terminals set COLUMNS (although some don't export it) */
static int term_columns(void)
*/
#include "cache.h"
-#include <pwd.h>
-#include <netdb.h>
-
static char git_default_date[50];
static void copy_gecos(struct passwd *w, char *name, int sz)
#include "cache.h"
-#include <assert.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <netdb.h>
-
typedef struct store_conf {
char *name;
const char *path; /* should this be here? its interpretation is driver-specific */
#include "commit.h"
#include "tag.h"
#include "tree.h"
-#include <sys/time.h>
-#include <signal.h>
static const char index_pack_usage[] =
"git-index-pack [-v] [-o <index-file>] [{ ---keep | --keep=<msg> }] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
static unsigned char input_buffer[4096];
static unsigned long input_offset, input_len, consumed_bytes;
static SHA_CTX input_ctx;
-static int input_fd, output_fd, mmap_fd;
+static int input_fd, output_fd, pack_fd;
/* Discard current buffer used content. */
static void flush(void)
output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600);
if (output_fd < 0)
die("unable to create %s: %s\n", pack_name, strerror(errno));
- mmap_fd = output_fd;
+ pack_fd = output_fd;
} else {
input_fd = open(pack_name, O_RDONLY);
if (input_fd < 0)
die("cannot open packfile '%s': %s",
pack_name, strerror(errno));
output_fd = -1;
- mmap_fd = input_fd;
+ pack_fd = input_fd;
}
SHA1_Init(&input_ctx);
return pack_name;
case OBJ_TAG:
break;
default:
- bad_object(obj->offset, "bad object type %d", obj->type);
+ bad_object(obj->offset, "unknown object type %d", obj->type);
}
obj->hdr_size = consumed_bytes - obj->offset;
{
unsigned long from = obj[0].offset + obj[0].hdr_size;
unsigned long len = obj[1].offset - from;
- unsigned pg_offset = from % getpagesize();
- unsigned char *map, *data;
+ unsigned char *src, *data;
z_stream stream;
int st;
- map = mmap(NULL, len + pg_offset, PROT_READ, MAP_PRIVATE,
- mmap_fd, from - pg_offset);
- if (map == MAP_FAILED)
- die("cannot mmap pack file: %s", strerror(errno));
+ src = xmalloc(len);
+ if (pread(pack_fd, src, len, from) != len)
+ die("cannot pread pack file: %s", strerror(errno));
data = xmalloc(obj->size);
memset(&stream, 0, sizeof(stream));
stream.next_out = data;
stream.avail_out = obj->size;
- stream.next_in = map + pg_offset;
+ stream.next_in = src;
stream.avail_in = len;
inflateInit(&stream);
while ((st = inflate(&stream, Z_FINISH)) == Z_OK);
inflateEnd(&stream);
if (st != Z_STREAM_END || stream.total_out != obj->size)
die("serious inflate inconsistency");
- munmap(map, len + pg_offset);
+ free(src);
return data;
}
* Copyright 2006 Jon Loeliger
*/
-#include <string.h>
-
#include "git-compat-util.h"
#include "interpolate.h"
/*
* Copyright (c) 2005, Junio C Hamano
*/
-#include <signal.h>
#include "cache.h"
static struct lock_file *lock_file_list;
-#include <stdlib.h>
#include "cache.h"
#include "commit.h"
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-
#include "cache.h"
static const char *pgm;
* Fredrik Kuivinen.
* The thieves were Alex Riesen and Johannes Schindelin, in June/July 2006
*/
-#include <stdarg.h>
-#include <string.h>
-#include <assert.h>
-#include <sys/wait.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <time.h>
#include "cache.h"
#include "cache-tree.h"
#include "commit.h"
struct commit *result, *h1, *h2;
git_config(git_default_config); /* core.filemode */
- original_index_file = getenv("GIT_INDEX_FILE");
+ original_index_file = getenv(INDEX_ENVIRONMENT);
if (!original_index_file)
original_index_file = xstrdup(git_path("index"));
* published by the Free Software Foundation.
*/
-#include <stdlib.h>
-#include <string.h>
+#include "git-compat-util.h"
#include "delta.h"
void *patch_delta(const void *src_buf, unsigned long src_size,
/* now the result size */
size = get_delta_hdr_size(&data, top);
- dst_buf = malloc(size + 1);
- if (!dst_buf)
- return NULL;
+ dst_buf = xmalloc(size + 1);
dst_buf[size] = 0;
out = dst_buf;
if (cp_off + cp_size < cp_size ||
cp_off + cp_size > src_size ||
cp_size > size)
- goto bad;
+ break;
memcpy(out, (char *) src_buf + cp_off, cp_size);
out += cp_size;
size -= cp_size;
} else if (cmd) {
if (cmd > size)
- goto bad;
+ break;
memcpy(out, data, cmd);
out += cmd;
data += cmd;
* extensions. In the mean time we must fail when
* encountering them (might be data corruption).
*/
+ error("unexpected delta opcode 0");
goto bad;
}
}
/* sanity check */
if (data != top || size != 0) {
+ error("delta replay has gone wild");
bad:
free(dst_buf);
return NULL;
-#include <stdio.h>
#include "cache.h"
#include "path-list.h"
* which is what it's designed for.
*/
#include "cache.h"
-#include <pwd.h>
static char bad_path[] = "/bad-path/";
if (ret < 0)
die("read error (%s)", strerror(errno));
if (!ret)
- die("unexpected EOF");
+ die("The remote end hung up unexpectedly");
n += ret;
}
}
#include "exec_cmd.h"
#include "commit.h"
#include "object.h"
-#include <sys/wait.h>
static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
-#include "refs.h"
#include "cache.h"
+#include "refs.h"
#include "object.h"
#include "tag.h"
-#include <errno.h>
-
/* ISSYMREF=01 and ISPACKED=02 are public interfaces */
#define REF_KNOWS_PEELED 04
goto rollback;
}
+ if (!strncmp(oldref, "refs/heads/", 11) &&
+ !strncmp(newref, "refs/heads/", 11)) {
+ char oldsection[1024], newsection[1024];
+
+ snprintf(oldsection, 1024, "branch.%s", oldref + 11);
+ snprintf(newsection, 1024, "branch.%s", newref + 11);
+ if (git_config_rename_section(oldsection, newsection) < 0)
+ return 1;
+ }
+
return 0;
rollback:
#include "diff.h"
#include "refs.h"
#include "revision.h"
-#include <regex.h>
#include "grep.h"
static char *path_name(struct name_path *path, const char *name)
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
+#include "cache.h"
#include "rsh.h"
#include "quote.h"
-#include "cache.h"
#define COMMAND_SIZE 4096
#include "cache.h"
#include "run-command.h"
-#include <sys/wait.h>
#include "exec_cmd.h"
int run_command_v_opt(int argc, const char **argv, int flags)
for (;;) {
switch (kind) {
default:
- die("corrupted pack file %s containing object of kind %d",
+ die("pack %s contains unknown object type %d",
p->pack_name, kind);
case OBJ_COMMIT:
case OBJ_TREE:
strcpy(type, type_names[kind]);
break;
default:
- die("corrupted pack file %s containing object of kind %d",
+ die("pack %s contains unknown object type %d",
p->pack_name, kind);
}
if (sizep)
#include "rsh.h"
#include "refs.h"
-#include <string.h>
-
static unsigned char local_version = 1;
static unsigned char remote_version;
-#include <stdio.h>
-#include <stdlib.h>
-#include "strbuf.h"
#include "cache.h"
+#include "strbuf.h"
void strbuf_init(struct strbuf *sb) {
sb->buf = NULL;
test_expect_success '--set in alternative GIT_CONFIG' 'cmp other-config expect'
+cat > .git/config << EOF
+# Hallo
+ #Bello
+[branch "eins"]
+ x = 1
+[branch.eins]
+ y = 1
+ [branch "1 234 blabl/a"]
+weird
+EOF
+
+test_expect_success "rename section" \
+ "git-repo-config --rename-section branch.eins branch.zwei"
+
+cat > expect << EOF
+# Hallo
+ #Bello
+[branch "zwei"]
+ x = 1
+[branch "zwei"]
+ y = 1
+ [branch "1 234 blabl/a"]
+weird
+EOF
+
+test_expect_success "rename succeeded" "diff -u expect .git/config"
+
+test_expect_failure "rename non-existing section" \
+ 'git-repo-config --rename-section branch."world domination" branch.drei'
+
+test_expect_success "rename succeeded" "diff -u expect .git/config"
+
+test_expect_success "rename another section" \
+ 'git-repo-config --rename-section branch."1 234 blabl/a" branch.drei'
+
+cat > expect << EOF
+# Hallo
+ #Bello
+[branch "zwei"]
+ x = 1
+[branch "zwei"]
+ y = 1
+[branch "drei"]
+weird
+EOF
+
+test_expect_success "rename succeeded" "diff -u expect .git/config"
+
test_done
git-branch r &&
git-branch -m q r/q'
+git-repo-config branch.s/s.dummy Hello
+
test_expect_success \
'git branch -m s/s s should work when s/t is deleted' \
'git-branch -l s/s &&
git-branch -m s/s s &&
test -f .git/logs/refs/heads/s'
+test_expect_success 'config information was renamed, too' \
+ "test $(git-repo-config branch.s.dummy) = Hello &&
+ ! git-repo-config branch.s/s/dummy"
+
test_expect_failure \
'git-branch -m u v should fail when the reflog for u is a symlink' \
'git-branch -l u &&
git clone . two &&
cd two &&
git repo-config branch.master.remote one &&
- {
- echo "URL: ../one/.git/"
- echo "Pull: refs/heads/master:refs/heads/one"
- } >.git/remotes/one
+ git repo-config remote.one.url ../one/.git/ &&
+ git repo-config remote.one.fetch refs/heads/master:refs/heads/one &&
cd .. &&
git clone . three &&
cd three &&
git repo-config branch.master.remote two &&
git repo-config branch.master.merge refs/heads/one &&
+ mkdir -p .git/remotes &&
{
echo "URL: ../two/.git/"
echo "Pull: refs/heads/master:refs/heads/two"
# t/ subdirectory and are run in trash subdirectory.
PATH=$(pwd)/..:$PATH
GIT_EXEC_PATH=$(pwd)/..
+GIT_TEMPLATE_DIR=$(pwd)/../templates/blt
HOME=$(pwd)/trash
-export PATH GIT_EXEC_PATH HOME
+export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR HOME
GITPERLLIB=$(pwd)/../perl/blib/lib:$(pwd)/../perl/blib/arch/auto/Git
export GITPERLLIB
+++ /dev/null
-: this is just to ensure the directory exists.
-#include <stdio.h>
-#include <time.h>
-
#include "cache.h"
int main(int argc, char **argv)
* published by the Free Software Foundation.
*/
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
+#include "git-compat-util.h"
#include "delta.h"
static const char usage[] =
#include "commit.h"
#include "tag.h"
#include "tree-walk.h"
-#include <stdlib.h>
const char *tree_type = "tree";
-#include <signal.h>
-#include <sys/time.h>
#include "cache.h"
#include "dir.h"
#include "tree.h"
-#include <signal.h>
-#include <sys/wait.h>
-#include <sys/poll.h>
#include "cache.h"
#include "refs.h"
#include "pkt-line.h"
* Copyright (C) Eric Biederman, 2005
*/
#include "cache.h"
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
static const char var_usage[] = "git-var [-l | <variable>]";
+#include "cache.h"
#include "wt-status.h"
#include "color.h"
-#include "cache.h"
#include "object.h"
#include "dir.h"
#include "commit.h"