aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-init-db.txt91
-rw-r--r--Documentation/git-init.txt114
-rw-r--r--builtin-branch.c55
-rw-r--r--builtin-rm.c6
-rw-r--r--cache.h2
-rw-r--r--config.c43
-rw-r--r--fsck-objects.c2
-rwxr-xr-xgit-checkout.sh74
-rw-r--r--git-compat-util.h2
-rw-r--r--index-pack.c2
-rw-r--r--path.c26
-rw-r--r--read-cache.c2
-rw-r--r--setup.c5
-rw-r--r--sha1_file.c2
-rwxr-xr-xt/t3200-branch.sh2
-rw-r--r--write_or_die.c21
-rw-r--r--wt-status.c32
17 files changed, 316 insertions, 165 deletions
diff --git a/Documentation/git-init-db.txt b/Documentation/git-init-db.txt
index bc3ba1493..5412135d7 100644
--- a/Documentation/git-init-db.txt
+++ b/Documentation/git-init-db.txt
@@ -11,96 +11,9 @@ SYNOPSIS
'git-init-db' [--template=<template_directory>] [--shared[=<permissions>]]
-OPTIONS
--------
-
---
-
---template=<template_directory>::
-
-Provide the directory from which templates will be used. The default template
-directory is `/usr/share/git-core/templates`.
-
-When specified, `<template_directory>` is used as the source of the template
-files rather than the default. The template files include some directory
-structure, some suggested "exclude patterns", and copies of non-executing
-"hook" files. The suggested patterns and hook files are all modifiable and
-extensible.
-
---shared[={false|true|umask|group|all|world|everybody}]::
-
-Specify that the git repository is to be shared amongst several users. This
-allows users belonging to the same group to push into that
-repository. When specified, the config variable "core.sharedRepository" is
-set so that files and directories under `$GIT_DIR` are created with the
-requested permissions. When not specified, git will use permissions reported
-by umask(2).
-
-The option can have the following values, defaulting to 'group' if no value
-is given:
-
- - 'umask' (or 'false'): Use permissions reported by umask(2). The default,
- when `--shared` is not specified.
-
- - 'group' (or 'true'): Make the repository group-writable, (and g+sx, since
- the git group may be not the primary group of all users).
-
- - 'all' (or 'world' or 'everybody'): Same as 'group', but make the repository
- readable by all users.
-
-By default, the configuration flag receive.denyNonFastforward is enabled
-in shared repositories, so that you cannot force a non fast-forwarding push
-into it.
-
---
-
-
DESCRIPTION
-----------
-This command creates an empty git repository - basically a `.git` directory
-with subdirectories for `objects`, `refs/heads`, `refs/tags`, and
-template files.
-An initial `HEAD` file that references the HEAD of the master branch
-is also created.
-
-If the `$GIT_DIR` environment variable is set then it specifies a path
-to use instead of `./.git` for the base of the repository.
-
-If the object storage directory is specified via the `$GIT_OBJECT_DIRECTORY`
-environment variable then the sha1 directories are created underneath -
-otherwise the default `$GIT_DIR/objects` directory is used.
-
-Running `git-init-db` in an existing repository is safe. It will not overwrite
-things that are already there. The primary reason for rerunning `git-init-db`
-is to pick up newly added templates.
-
-Note that `git-init` is the same as `git-init-db`.
-
-
-EXAMPLES
---------
-
-Start a new git repository for an existing code base::
-+
-----------------
-$ cd /path/to/my/codebase
-$ git-init-db <1>
-$ git-add . <2>
-----------------
-+
-<1> prepare /path/to/my/codebase/.git directory
-<2> add all existing file to the index
-
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-GIT
----
-Part of the gitlink:git[7] suite
+This is a synonym for gitlink:git-init[1]. Please refer to the
+documentation of that command.
diff --git a/Documentation/git-init.txt b/Documentation/git-init.txt
index 36838c753..e1fd6884f 100644
--- a/Documentation/git-init.txt
+++ b/Documentation/git-init.txt
@@ -1 +1,113 @@
-include::git-init-db.txt[]
+git-init(1)
+===========
+
+NAME
+----
+git-init - Creates an empty git repository
+
+
+SYNOPSIS
+--------
+'git-init' [--template=<template_directory>] [--shared[=<permissions>]]
+
+
+OPTIONS
+-------
+
+--
+
+--template=<template_directory>::
+
+Provide the directory from which templates will be used. The default template
+directory is `/usr/share/git-core/templates`.
+
+When specified, `<template_directory>` is used as the source of the template
+files rather than the default. The template files include some directory
+structure, some suggested "exclude patterns", and copies of non-executing
+"hook" files. The suggested patterns and hook files are all modifiable and
+extensible.
+
+--shared[={false|true|umask|group|all|world|everybody}]::
+
+Specify that the git repository is to be shared amongst several users. This
+allows users belonging to the same group to push into that
+repository. When specified, the config variable "core.sharedRepository" is
+set so that files and directories under `$GIT_DIR` are created with the
+requested permissions. When not specified, git will use permissions reported
+by umask(2).
+
+The option can have the following values, defaulting to 'group' if no value
+is given:
+
+ - 'umask' (or 'false'): Use permissions reported by umask(2). The default,
+ when `--shared` is not specified.
+
+ - 'group' (or 'true'): Make the repository group-writable, (and g+sx, since
+ the git group may be not the primary group of all users).
+
+ - 'all' (or 'world' or 'everybody'): Same as 'group', but make the repository
+ readable by all users.
+
+By default, the configuration flag receive.denyNonFastforward is enabled
+in shared repositories, so that you cannot force a non fast-forwarding push
+into it.
+
+--
+
+
+DESCRIPTION
+-----------
+This command creates an empty git repository - basically a `.git` directory
+with subdirectories for `objects`, `refs/heads`, `refs/tags`, and
+template files.
+An initial `HEAD` file that references the HEAD of the master branch
+is also created.
+
+If the `$GIT_DIR` environment variable is set then it specifies a path
+to use instead of `./.git` for the base of the repository.
+
+If the object storage directory is specified via the `$GIT_OBJECT_DIRECTORY`
+environment variable then the sha1 directories are created underneath -
+otherwise the default `$GIT_DIR/objects` directory is used.
+
+Running `git-init` in an existing repository is safe. It will not overwrite
+things that are already there. The primary reason for rerunning `git-init`
+is to pick up newly added templates.
+
+Note that `git-init` is the same as `git-init-db`. The command
+was primarily meant to initialize the object database, but over
+time it has become responsible for setting up the other aspects
+of the repository, such as installing the default hooks and
+setting the configuration variables. The old name is retained
+because people are so used to it and many existing documents
+refer to it that way, and this will not change for some time to
+come.
+
+
+EXAMPLES
+--------
+
+Start a new git repository for an existing code base::
++
+----------------
+$ cd /path/to/my/codebase
+$ git-init <1>
+$ git-add . <2>
+----------------
++
+<1> prepare /path/to/my/codebase/.git directory
+<2> add all existing file to the index
+
+
+Author
+------
+Written by Linus Torvalds <torvalds@osdl.org>
+
+Documentation
+--------------
+Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the gitlink:git[7] suite
+
diff --git a/builtin-branch.c b/builtin-branch.c
index d3df5a57f..c760e188e 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -275,7 +275,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
}
}
-static void print_ref_list(int kinds, int verbose, int abbrev)
+static void print_ref_list(int kinds, int detached, int verbose, int abbrev)
{
int i;
struct ref_list ref_list;
@@ -286,8 +286,20 @@ static void print_ref_list(int kinds, int verbose, int abbrev)
qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);
+ detached = (detached && (kinds & REF_LOCAL_BRANCH));
+ if (detached) {
+ struct ref_item item;
+ item.name = "(no branch)";
+ item.kind = REF_LOCAL_BRANCH;
+ hashcpy(item.sha1, head_sha1);
+ if (strlen(item.name) > ref_list.maxwidth)
+ ref_list.maxwidth = strlen(item.name);
+ print_ref_item(&item, ref_list.maxwidth, verbose, abbrev, 1);
+ }
+
for (i = 0; i < ref_list.index; i++) {
- int current = (ref_list.list[i].kind == REF_LOCAL_BRANCH) &&
+ int current = !detached &&
+ (ref_list.list[i].kind == REF_LOCAL_BRANCH) &&
!strcmp(ref_list.list[i].name, head);
print_ref_item(&ref_list.list[i], ref_list.maxwidth, verbose,
abbrev, current);
@@ -296,7 +308,8 @@ static void print_ref_list(int kinds, int verbose, int abbrev)
free_ref_list(&ref_list);
}
-static void create_branch(const char *name, const char *start,
+static void create_branch(const char *name, const char *start_name,
+ unsigned char *start_sha1,
int force, int reflog)
{
struct ref_lock *lock;
@@ -315,9 +328,14 @@ static void create_branch(const char *name, const char *start,
die("Cannot force update the current branch.");
}
- if (get_sha1(start, sha1) ||
- (commit = lookup_commit_reference(sha1)) == NULL)
- die("Not a valid branch point: '%s'.", start);
+ if (start_sha1)
+ /* detached HEAD */
+ hashcpy(sha1, start_sha1);
+ else if (get_sha1(start_name, sha1))
+ die("Not a valid object name: '%s'.", start_name);
+
+ if ((commit = lookup_commit_reference(sha1)) == NULL)
+ die("Not a valid branch point: '%s'.", start_name);
hashcpy(sha1, commit->object.sha1);
lock = lock_any_ref_for_update(ref, NULL);
@@ -326,7 +344,8 @@ static void create_branch(const char *name, const char *start,
if (reflog) {
log_all_ref_updates = 1;
- snprintf(msg, sizeof msg, "branch: Created from %s", start);
+ snprintf(msg, sizeof msg, "branch: Created from %s",
+ start_name);
}
if (write_ref_sha1(lock, sha1, msg) < 0)
@@ -338,6 +357,9 @@ static void rename_branch(const char *oldname, const char *newname, int force)
char oldref[PATH_MAX], newref[PATH_MAX], logmsg[PATH_MAX*2 + 100];
unsigned char sha1[20];
+ if (!oldname)
+ die("cannot rename the curren branch while not on any.");
+
if (snprintf(oldref, sizeof(oldref), "refs/heads/%s", oldname) > sizeof(oldref))
die("Old branchname too long");
@@ -367,7 +389,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
{
int delete = 0, force_delete = 0, force_create = 0;
int rename = 0, force_rename = 0;
- int verbose = 0, abbrev = DEFAULT_ABBREV;
+ int verbose = 0, abbrev = DEFAULT_ABBREV, detached = 0;
int reflog = 0;
int kinds = REF_LOCAL_BRANCH;
int i;
@@ -444,22 +466,27 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
head = xstrdup(resolve_ref("HEAD", head_sha1, 0, NULL));
if (!head)
die("Failed to resolve HEAD as a valid ref.");
- if (strncmp(head, "refs/heads/", 11))
- die("HEAD not found below refs/heads!");
- head += 11;
+ if (!strcmp(head, "HEAD")) {
+ detached = 1;
+ }
+ else {
+ if (strncmp(head, "refs/heads/", 11))
+ die("HEAD not found below refs/heads!");
+ head += 11;
+ }
if (delete)
return delete_branches(argc - i, argv + i, force_delete, kinds);
else if (i == argc)
- print_ref_list(kinds, verbose, abbrev);
+ print_ref_list(kinds, detached, verbose, abbrev);
else if (rename && (i == argc - 1))
rename_branch(head, argv[i], force_rename);
else if (rename && (i == argc - 2))
rename_branch(argv[i], argv[i + 1], force_rename);
else if (i == argc - 1)
- create_branch(argv[i], head, force_create, reflog);
+ create_branch(argv[i], head, head_sha1, force_create, reflog);
else if (i == argc - 2)
- create_branch(argv[i], argv[i + 1], force_create, reflog);
+ create_branch(argv[i], argv[i+1], NULL, force_create, reflog);
else
usage(builtin_branch_usage);
diff --git a/builtin-rm.c b/builtin-rm.c
index 5b078c419..d81f289c3 100644
--- a/builtin-rm.c
+++ b/builtin-rm.c
@@ -32,6 +32,10 @@ static int remove_file(const char *name)
char *slash;
ret = unlink(name);
+ if (ret && errno == ENOENT)
+ /* The user has removed it from the filesystem by hand */
+ ret = errno = 0;
+
if (!ret && (slash = strrchr(name, '/'))) {
char *n = xstrdup(name);
do {
@@ -204,7 +208,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
return 0;
/*
- * Then, unless we used "--cache", remove the filenames from
+ * Then, unless we used "--cached", remove the filenames from
* the workspace. If we fail to remove the first one, we
* abort the "git rm" (but once we've successfully removed
* any file at all, we'll go ahead and commit to it all:
diff --git a/cache.h b/cache.h
index a9583ff18..cbe398d3b 100644
--- a/cache.h
+++ b/cache.h
@@ -299,7 +299,7 @@ extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
extern int read_ref(const char *filename, unsigned char *sha1);
extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);
extern int create_symref(const char *ref, const char *refs_heads_master);
-extern int validate_symref(const char *ref);
+extern int validate_headref(const char *ref);
extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
diff --git a/config.c b/config.c
index 2cd0263e1..733fb1a34 100644
--- a/config.c
+++ b/config.c
@@ -694,11 +694,9 @@ int git_config_set_multivar(const char* key, const char* value,
store.key = (char*)key;
if (!store_write_section(fd, key) ||
- !store_write_pair(fd, key, value)) {
- ret = write_error();
- goto out_free;
- }
- } else{
+ !store_write_pair(fd, key, value))
+ goto write_err_out;
+ } else {
struct stat st;
char* contents;
int i, copy_begin, copy_end, new_line = 0;
@@ -777,31 +775,33 @@ int git_config_set_multivar(const char* key, const char* value,
/* write the first part of the config */
if (copy_end > copy_begin) {
- write_in_full(fd, contents + copy_begin,
- copy_end - copy_begin);
- if (new_line)
- write_in_full(fd, "\n", 1);
+ if (write_in_full(fd, contents + copy_begin,
+ copy_end - copy_begin) <
+ copy_end - copy_begin)
+ goto write_err_out;
+ if (new_line &&
+ write_in_full(fd, "\n", 1) != 1)
+ goto write_err_out;
}
copy_begin = store.offset[i];
}
/* write the pair (value == NULL means unset) */
if (value != NULL) {
- if (store.state == START)
- if (!store_write_section(fd, key)) {
- ret = write_error();
- goto out_free;
- }
- if (!store_write_pair(fd, key, value)) {
- ret = write_error();
- goto out_free;
+ if (store.state == START) {
+ if (!store_write_section(fd, key))
+ goto write_err_out;
}
+ if (!store_write_pair(fd, key, value))
+ goto write_err_out;
}
/* write the rest of the config */
if (copy_begin < st.st_size)
- write_in_full(fd, contents + copy_begin,
- st.st_size - copy_begin);
+ if (write_in_full(fd, contents + copy_begin,
+ st.st_size - copy_begin) <
+ st.st_size - copy_begin)
+ goto write_err_out;
munmap(contents, st.st_size);
unlink(config_filename);
@@ -824,6 +824,11 @@ out_free:
free(lock_file);
}
return ret;
+
+write_err_out:
+ ret = write_error();
+ goto out_free;
+
}
int git_config_rename_section(const char *old_name, const char *new_name)
diff --git a/fsck-objects.c b/fsck-objects.c
index 0d8a8ebb4..81f00db90 100644
--- a/fsck-objects.c
+++ b/fsck-objects.c
@@ -290,7 +290,7 @@ static int fsck_sha1(unsigned char *sha1)
{
struct object *obj = parse_object(sha1);
if (!obj)
- return error("%s: object not found", sha1_to_hex(sha1));
+ return error("%s: object corrupt or missing", sha1_to_hex(sha1));
if (obj->flags & SEEN)
return 0;
obj->flags |= SEEN;
diff --git a/git-checkout.sh b/git-checkout.sh
index 92ec069a3..8f4356d49 100755
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -6,6 +6,7 @@ SUBDIRECTORY_OK=Sometimes
old_name=HEAD
old=$(git-rev-parse --verify $old_name 2>/dev/null)
+oldbranch=$(git-symbolic-ref $old_name 2>/dev/null)
new=
new_name=
force=
@@ -13,6 +14,8 @@ branch=
newbranch=
newbranch_log=
merge=
+LF='
+'
while [ "$#" != "0" ]; do
arg="$1"
shift
@@ -50,7 +53,7 @@ while [ "$#" != "0" ]; do
exit 1
fi
new="$rev"
- new_name="$arg^0"
+ new_name="$arg"
if git-show-ref --verify --quiet -- "refs/heads/$arg"
then
branch="$arg"
@@ -139,23 +142,49 @@ fi
[ -z "$new" ] && new=$old && new_name="$old_name"
-# If we don't have an old branch that we're switching to,
+# If we don't have an existing branch that we're switching to,
# and we don't have a new branch name for the target we
-# are switching to, then we'd better just be checking out
-# what we already had
+# are switching to, then we are detaching our HEAD from any
+# branch. However, if "git checkout HEAD" detaches the HEAD
+# from the current branch, even though that may be logically
+# correct, it feels somewhat funny. More importantly, we do not
+# want "git checkout" nor "git checkout -f" to detach HEAD.
-[ -z "$branch$newbranch" ] &&
- [ "$new" != "$old" ] &&
- die "git checkout: provided reference cannot be checked out directly
+detached=
+detach_warn=
- You need -b to associate a new branch with the wanted checkout. Example:
- git checkout -b <new_branch_name> $arg
-"
+if test -z "$branch$newbranch" && test "$new" != "$old"
+then
+ detached="$new"
+ if test -n "$oldbranch"
+ then
+ detach_warn="warning: you are not on ANY branch anymore.
+If you meant to create a new branch from the commit, you need -b to
+associate a new branch with the wanted checkout. Example:
+ git checkout -b <new_branch_name> $arg"
+ fi
+elif test -z "$oldbranch" && test -n "$branch"
+then
+ # Coming back...
+ if test -z "$force"
+ then
+ git show-ref -d -s | grep "$old" >/dev/null || {
+ echo >&2 \
+"You are not on any branch and switching to branch '$new_name'
+may lose your changes. At this point, you can do one of two things:
+ (1) Decide it is Ok and say 'git checkout -f $new_name';
+ (2) Start a new branch from the current commit, by saying
+ 'git checkout -b <branch-name>'.
+Leaving your HEAD detached; not switching to branch '$new_name'."
+ exit 1;
+ }
+ fi
+fi
if [ "X$old" = X ]
then
- echo "warning: You do not appear to currently be on a branch." >&2
- echo "warning: Forcing checkout of $new_name." >&2
+ echo >&2 "warning: You appear to be on a branch yet to be born."
+ echo >&2 "warning: Forcing checkout of $new_name."
force=1
fi
@@ -226,8 +255,25 @@ if [ "$?" -eq 0 ]; then
git-update-ref -m "checkout: Created from $new_name" "refs/heads/$newbranch" $new || exit
branch="$newbranch"
fi
- [ "$branch" ] &&
- GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD "refs/heads/$branch"
+ if test -n "$branch"
+ then
+ GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD "refs/heads/$branch"
+ elif test -n "$detached"
+ then
+ # NEEDSWORK: we would want a command to detach the HEAD
+ # atomically, instead of this handcrafted command sequence.
+ # Perhaps:
+ # git update-ref --detach HEAD $new
+ # or something like that...
+ #
+ echo "$detached" >"$GIT_DIR/HEAD.new" &&
+ mv "$GIT_DIR/HEAD.new" "$GIT_DIR/HEAD" ||
+ die "Cannot detach HEAD"
+ if test -n "$detach_warn"
+ then
+ echo >&2 "$detach_warn"
+ fi
+ fi
rm -f "$GIT_DIR/MERGE_HEAD"
else
exit 1
diff --git a/git-compat-util.h b/git-compat-util.h
index f8d46d587..8781e8e22 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -202,6 +202,8 @@ static inline void *xmmap(void *start, size_t length,
{
void *ret = mmap(start, length, prot, flags, fd, offset);
if (ret == MAP_FAILED) {
+ if (!length)
+ return NULL;
release_pack_memory(length);
ret = mmap(start, length, prot, flags, fd, offset);
if (ret == MAP_FAILED)
diff --git a/index-pack.c b/index-pack.c
index 8d10d6ba2..72e096241 100644
--- a/index-pack.c
+++ b/index-pack.c
@@ -814,7 +814,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
char buf[48];
int len = snprintf(buf, sizeof(buf), "%s\t%s\n",
report, sha1_to_hex(sha1));
- write_in_full(1, buf, len);
+ write_or_die(1, buf, len);
/*
* Let's just mimic git-unpack-objects here and write
diff --git a/path.c b/path.c
index bb5ee7bf9..c5d25a4b9 100644
--- a/path.c
+++ b/path.c
@@ -90,10 +90,11 @@ int git_mkstemp(char *path, size_t len, const char *template)
}
-int validate_symref(const char *path)
+int validate_headref(const char *path)
{
struct stat st;
char *buf, buffer[256];
+ unsigned char sha1[20];
int len, fd;
if (lstat(path, &st) < 0)
@@ -119,14 +120,23 @@ int validate_symref(const char *path)
/*
* Is it a symbolic ref?
*/
- if (len < 4 || memcmp("ref:", buffer, 4))
+ if (len < 4)
return -1;
- buf = buffer + 4;
- len -= 4;
- while (len && isspace(*buf))
- buf++, len--;
- if (len >= 5 && !memcmp("refs/", buf, 5))
+ if (!memcmp("ref:", buffer, 4)) {
+ buf = buffer + 4;
+ len -= 4;
+ while (len && isspace(*buf))
+ buf++, len--;
+ if (len >= 5 && !memcmp("refs/", buf, 5))
+ return 0;
+ }
+
+ /*
+ * Is this a detached HEAD?
+ */
+ if (!get_sha1_hex(buffer, sha1))
return 0;
+
return -1;
}
@@ -241,7 +251,7 @@ char *enter_repo(char *path, int strict)
return NULL;
if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
- validate_symref("HEAD") == 0) {
+ validate_headref("HEAD") == 0) {
putenv("GIT_DIR=.");
check_repository_format();
return path;
diff --git a/read-cache.c b/read-cache.c
index 8ecd826e9..c54a61187 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1010,7 +1010,7 @@ int write_cache(int newfd, struct cache_entry **cache, int entries)
if (data &&
!write_index_ext_header(&c, newfd, CACHE_EXT_TREE, sz) &&
!ce_write(&c, newfd, data, sz))
- ;
+ free(data);
else {
free(data);
return -1;
diff --git a/setup.c b/setup.c
index 2ae57f7c9..cc97f9f5c 100644
--- a/setup.c
+++ b/setup.c
@@ -138,7 +138,8 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
* GIT_OBJECT_DIRECTORY environment variable
* - a refs/ directory
* - either a HEAD symlink or a HEAD file that is formatted as
- * a proper "ref:".
+ * a proper "ref:", or a regular file HEAD that has a properly
+ * formatted sha1 object name.
*/
static int is_git_directory(const char *suspect)
{
@@ -161,7 +162,7 @@ static int is_git_directory(const char *suspect)
return 0;
strcpy(path + len, "/HEAD");
- if (validate_symref(path))
+ if (validate_headref(path))
return 0;
return 1;
diff --git a/sha1_file.c b/sha1_file.c
index 53e25f278..18dd89b50 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1620,6 +1620,8 @@ static int write_buffer(int fd, const void *buf, size_t len)
{
ssize_t size;
+ if (!len)
+ return 0;
size = write_in_full(fd, buf, len);
if (!size)
return error("file write: disk full");
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index a6ea0f6a1..bb80e4286 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -48,7 +48,7 @@ test_expect_success \
test ! -f .git/logs/refs/heads/d/e/f'
cat >expect <<EOF
-0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 checkout: Created from master^0
+0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 checkout: Created from master
EOF
test_expect_success \
'git checkout -b g/h/i -l should create a branch and a log' \
diff --git a/write_or_die.c b/write_or_die.c
index a119e1d20..488de721d 100644
--- a/write_or_die.c
+++ b/write_or_die.c
@@ -26,6 +26,8 @@ void read_or_die(int fd, void *buf, size_t count)
{
ssize_t loaded;
+ if (!count)
+ return;
loaded = read_in_full(fd, buf, count);
if (loaded == 0)
die("unexpected end of file");
@@ -37,15 +39,14 @@ int write_in_full(int fd, const void *buf, size_t count)
{
const char *p = buf;
ssize_t total = 0;
- ssize_t written = 0;
while (count > 0) {
- written = xwrite(fd, p, count);
- if (written <= 0) {
- if (total)
- return total;
- else
- return written;
+ size_t written = xwrite(fd, p, count);
+ if (written < 0)
+ return -1;
+ if (!written) {
+ errno = ENOSPC;
+ return -1;
}
count -= written;
p += written;
@@ -59,6 +60,8 @@ void write_or_die(int fd, const void *buf, size_t count)
{
ssize_t written;
+ if (!count)
+ return;
written = write_in_full(fd, buf, count);
if (written == 0)
die("disk full?");
@@ -73,6 +76,8 @@ int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg)
{
ssize_t written;
+ if (!count)
+ return 1;
written = write_in_full(fd, buf, count);
if (written == 0) {
fprintf(stderr, "%s: disk full?\n", msg);
@@ -93,6 +98,8 @@ int write_or_whine(int fd, const void *buf, size_t count, const char *msg)
{
ssize_t written;
+ if (!count)
+ return 1;
written = write_in_full(fd, buf, count);
if (written == 0) {
fprintf(stderr, "%s: disk full?\n", msg);
diff --git a/wt-status.c b/wt-status.c
index 1dc2fdc34..daba9a610 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -15,7 +15,13 @@ static char wt_status_colors[][COLOR_MAXLEN] = {
"\033[31m", /* WT_STATUS_CHANGED: red */
"\033[31m", /* WT_STATUS_UNTRACKED: red */
};
-static const char* use_add_msg = "use \"git add <file>...\" to incrementally add content to commit";
+
+static const char use_add_msg[] =
+"use \"git add <file>...\" to update what will be committed";
+static const char use_add_rm_msg[] =
+"use \"git add/rm <file>...\" to update what will be committed";
+static const char use_add_to_include_msg[] =
+"use \"git add <file>...\" to include in what will be committed";
static int parse_status_slot(const char *var, int offset)
{
@@ -177,8 +183,14 @@ static void wt_status_print_changed_cb(struct diff_queue_struct *q,
struct wt_status *s = data;
int i;
if (q->nr) {
+ const char *msg = use_add_msg;
s->workdir_dirty = 1;
- wt_status_print_header("Changed but not added", use_add_msg);
+ for (i = 0; i < q->nr; i++)
+ if (q->queue[i]->status == DIFF_STATUS_DELETED) {
+ msg = use_add_rm_msg;
+ break;
+ }
+ wt_status_print_header("Changed but not updated", msg);
}
for (i = 0; i < q->nr; i++)
wt_status_print_filepair(WT_STATUS_CHANGED, q->queue[i]);
@@ -265,7 +277,8 @@ static void wt_status_print_untracked(struct wt_status *s)
}
if (!shown_header) {
s->workdir_untracked = 1;
- wt_status_print_header("Untracked files", use_add_msg);
+ wt_status_print_header("Untracked files",
+ use_add_to_include_msg);
shown_header = 1;
}
color_printf(color(WT_STATUS_HEADER), "#\t");
@@ -289,9 +302,18 @@ void wt_status_print(struct wt_status *s)
unsigned char sha1[20];
s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0;
- if (s->branch)
+ if (s->branch) {
+ const char *on_what = "On branch ";
+ const char *branch_name = s->branch;
+ if (!strncmp(branch_name, "refs/heads/", 11))
+ branch_name += 11;
+ else if (!strcmp(branch_name, "HEAD")) {
+ branch_name = "";
+ on_what = "Not currently on any branch.";
+ }
color_printf_ln(color(WT_STATUS_HEADER),
- "# On branch %s", s->branch);
+ "# %s%s", on_what, branch_name);
+ }
if (s->is_initial) {
color_printf_ln(color(WT_STATUS_HEADER), "#");