Re: GIT, libcurl and GSS-Negotiate

2014-05-16 Thread Jeff King
On Fri, May 16, 2014 at 10:34:10PM +, brian m. carlson wrote:

> > The tricky part is figuring out when to return HTTP_NOAUTH ("do not try
> > again, we failed") versus HTTP_REAUTH ("get credentials and try again")
> > in handle_curl_result. Right now the decision is based on "did we have a
> > username and password for this request?" I'm not clear on what extra
> > bits would be needed to decide to continue in the case you guys are
> > discussing.
> 
> I'm honestly not sure, either.  That's why I said, "how to do that is
> unknown".
> 
> However, if you base64-decode the two Negotiate replies in the
> successful attempt with WinHTTP and pass it through od -tc, you'll see
> that the second reply contains some form of user ID that the first one
> does not.  The curl binary sends an identical reply for the first pass,
> but then gives up and does not try a second pass.  I don't know if
> libcurl is able to provide the data required in the second pass.
> 
> All of this is way outside my knowledge, since my Kerberos/GSSAPI
> Negotiate requests look very different than the NTLM ones.

Mine too. I think a good place to start would be somebody who has a
setup to replicate the problem dumping the curl data (either from
GIT_CURL_VERBOSE, or instrumenting git with some curl_easy_getinfo
calls), and seeing what is interesting.

> > Yeah, we just set CURLAUTH_ANY now, but it would be fairly trivial to
> > add "http.authtype" and "http.proxyauthtype" to map to CURLOPT_HTTPAUTH
> > and CURLOPT_PROXYAUTH.
> 
> This might be the easiest option.

I can help with working up a patch, but I don't have any meaningful way
to test it.

The patch below might help somebody get started. I don't know if
CURLAUTH_ONLY would be useful to be able to set, too.

diff --git a/http.c b/http.c
index 94e1afd..ba56f7e 100644
--- a/http.c
+++ b/http.c
@@ -51,6 +51,9 @@ struct credential http_auth = CREDENTIAL_INIT;
 static int http_proactive_auth;
 static const char *user_agent;
 
+static long curl_http_authtype;
+static long curl_proxy_authtype;
+
 #if LIBCURL_VERSION_NUM >= 0x071700
 /* Use CURLOPT_KEYPASSWD as is */
 #elif LIBCURL_VERSION_NUM >= 0x070903
@@ -143,6 +146,37 @@ static void process_curl_messages(void)
 }
 #endif
 
+static int parse_auth_type(const char *var, const char *value, long *type)
+{
+   static struct {
+   const char *name;
+   long value;
+   } types[] = {
+{ "basic", CURLAUTH_BASIC },
+{ "digest", CURLAUTH_DIGEST },
+#if CURL_VERSION >= 0x071303
+{ "digest-ie", CURLAUTH_DIGEST_IE },
+#endif
+{ "negotiate", CURLAUTH_GSSNEGOTIATE },
+#if CURL_VERSION >= 0x071600
+{ "ntlm-wb", CURLAUTH_NTLM_WB },
+#endif
+{ "ntlm", CURLAUTH_NTLM }
+   };
+   int i;
+
+   if (!value)
+   return config_error_nonbool(var);
+
+   for (i = 0; i < ARRAY_SIZE(types); i++)
+   if (!strcmp(value, types[i].name))
+   *type |= types[i].value;
+
+   if (i == ARRAY_SIZE(types))
+   return error("unknown auth type for '%s': %s", var, value);
+   return 0;
+}
+
 static int http_options(const char *var, const char *value, void *cb)
 {
if (!strcmp("http.sslverify", var)) {
@@ -216,6 +250,11 @@ static int http_options(const char *var, const char 
*value, void *cb)
if (!strcmp("http.useragent", var))
return git_config_string(&user_agent, var, value);
 
+   if (!strcmp("http.authtype", var))
+   return parse_auth_type(var, value, &curl_http_authtype);
+   if (!strcmp("http.proxyauthtype", var))
+   return parse_auth_type(var, value, &curl_proxy_authtype);
+
/* Fall back on the default ones */
return git_default_config(var, value, cb);
 }
@@ -296,6 +335,17 @@ static void set_curl_keepalive(CURL *c)
 }
 #endif
 
+static void set_curl_authtype(CURL *c, CURLoption option, long value)
+{
+   if (value)
+   curl_easy_setopt(c, option, value);
+   else {
+#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
+   curl_easy_setopt(c, option, CURLAUTH_ANY);
+#endif
+   }
+}
+
 static CURL *get_curl_handle(void)
 {
CURL *result = curl_easy_init();
@@ -313,8 +363,13 @@ static CURL *get_curl_handle(void)
 #if LIBCURL_VERSION_NUM >= 0x070907
curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
 #endif
-#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
-   curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
+
+#if LIBCURL_VERSION_NUM >= 0x070a06
+   set_curl_authtype(result, CURLOPT_HTTPAUTH, curl_http_authtype);
+#endif
+
+#if LIBCURL_VERSION_NUM >= 0x070a07
+   set_curl_authtype(result, CURLOPT_PROXYAUTH, curl_proxy_authtype);
 #endif
 
if (http_proactive_auth)
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/major

[PATCH v2 09/10] replace: add --edit to usage string

2014-05-16 Thread Christian Couder
Signed-off-by: Christian Couder 
---
 builtin/replace.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/builtin/replace.c b/builtin/replace.c
index 4ee3d92..1bb491d 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -16,6 +16,7 @@
 
 static const char * const git_replace_usage[] = {
N_("git replace [-f]  "),
+   N_("git replace [-f] --edit "),
N_("git replace -d ..."),
N_("git replace [--format=] [-l []]"),
NULL
-- 
1.9.rc0.17.g651113e


--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 10/10] Documentation: replace: describe new --edit option

2014-05-16 Thread Christian Couder
Signed-off-by: Christian Couder 
---
 Documentation/git-replace.txt | 15 ++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/Documentation/git-replace.txt b/Documentation/git-replace.txt
index 0a02f70..37d872d 100644
--- a/Documentation/git-replace.txt
+++ b/Documentation/git-replace.txt
@@ -9,6 +9,7 @@ SYNOPSIS
 
 [verse]
 'git replace' [-f]  
+'git replace' [-f] --edit 
 'git replace' -d ...
 'git replace' [--format=] [-l []]
 
@@ -63,6 +64,14 @@ OPTIONS
 --delete::
Delete existing replace refs for the given objects.
 
+--edit ::
+   Launch an editor to let the user change the content of
+   , then create a new object of the same type with the
+   changed content, and create a replace ref to replace 
+   with the new object. See linkgit:git-commit[1] and
+   linkgit:git-var[1] for details about how the editor will be
+   chosen.
+
 -l ::
 --list ::
List replace refs for objects that match the given pattern (or
@@ -92,7 +101,9 @@ CREATING REPLACEMENT OBJECTS
 
 linkgit:git-filter-branch[1], linkgit:git-hash-object[1] and
 linkgit:git-rebase[1], among other git commands, can be used to create
-replacement objects from existing objects.
+replacement objects from existing objects. The `--edit` option can
+also be used with 'git replace' to create a replacement object by
+editing an existing object.
 
 If you want to replace many blobs, trees or commits that are part of a
 string of commits, you may just want to create a replacement string of
@@ -117,6 +128,8 @@ linkgit:git-filter-branch[1]
 linkgit:git-rebase[1]
 linkgit:git-tag[1]
 linkgit:git-branch[1]
+linkgit:git-commit[1]
+linkgit:git-var[1]
 linkgit:git[1]
 
 GIT
-- 
1.9.rc0.17.g651113e

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 02/10] replace: use OPT_CMDMODE to handle modes

2014-05-16 Thread Christian Couder
From: Jeff King 

By using OPT_CMDMODE, the mutual exclusion between modes is
taken care of for us. It also makes it easy for us to
maintain a single variable with the mode, which makes its
intent more clear. We can use a single switch() to make sure
we have covered all of the modes.

This ends up breaking even in code size, but the win will be
much bigger when we start adding more modes.

Signed-off-by: Jeff King 
Signed-off-by: Christian Couder 
---
 builtin/replace.c | 49 +
 1 file changed, 25 insertions(+), 24 deletions(-)

diff --git a/builtin/replace.c b/builtin/replace.c
index 28db96f..29cf699 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -168,11 +168,17 @@ static int replace_object(const char *object_ref, const 
char *replace_ref,
 
 int cmd_replace(int argc, const char **argv, const char *prefix)
 {
-   int list = 0, delete = 0, force = 0;
+   int force = 0;
const char *format = NULL;
+   enum {
+   MODE_UNSPECIFIED = 0,
+   MODE_LIST,
+   MODE_DELETE,
+   MODE_REPLACE
+   } cmdmode = MODE_UNSPECIFIED;
struct option options[] = {
-   OPT_BOOL('l', "list", &list, N_("list replace refs")),
-   OPT_BOOL('d', "delete", &delete, N_("delete replace refs")),
+   OPT_CMDMODE('l', "list", &cmdmode, N_("list replace refs"), 
MODE_LIST),
+   OPT_CMDMODE('d', "delete", &cmdmode, N_("delete replace refs"), 
MODE_DELETE),
OPT_BOOL('f', "force", &force, N_("replace the ref if it 
exists")),
OPT_STRING(0, "format", &format, N_("format"), N_("use this 
format")),
OPT_END()
@@ -182,42 +188,37 @@ int cmd_replace(int argc, const char **argv, const char 
*prefix)
 
argc = parse_options(argc, argv, prefix, options, git_replace_usage, 0);
 
-   if (!list && !delete)
-   if (!argc)
-   list = 1;
+   if (!cmdmode)
+   cmdmode = argc ? MODE_REPLACE : MODE_LIST;
 
-   if (list && delete)
-   usage_msg_opt("-l and -d cannot be used together",
- git_replace_usage, options);
-
-   if (format && !list)
+   if (format && cmdmode != MODE_LIST)
usage_msg_opt("--format cannot be used when not listing",
  git_replace_usage, options);
 
-   if (force && (list || delete))
-   usage_msg_opt("-f cannot be used with -d or -l",
+   if (force && cmdmode != MODE_REPLACE)
+   usage_msg_opt("-f only makes sense when writing a replacement",
  git_replace_usage, options);
 
-   /* Delete refs */
-   if (delete) {
+   switch (cmdmode) {
+   case MODE_DELETE:
if (argc < 1)
usage_msg_opt("-d needs at least one argument",
  git_replace_usage, options);
return for_each_replace_name(argv, delete_replace_ref);
-   }
 
-   /* Replace object */
-   if (!list && argc) {
+   case MODE_REPLACE:
if (argc != 2)
usage_msg_opt("bad number of arguments",
  git_replace_usage, options);
return replace_object(argv[0], argv[1], force);
-   }
 
-   /* List refs, even if "list" is not set */
-   if (argc > 1)
-   usage_msg_opt("only one pattern can be given with -l",
- git_replace_usage, options);
+   case MODE_LIST:
+   if (argc > 1)
+   usage_msg_opt("only one pattern can be given with -l",
+ git_replace_usage, options);
+   return list_replace_refs(argv[0], format);
 
-   return list_replace_refs(argv[0], format);
+   default:
+   die("BUG: invalid cmdmode %d", (int)cmdmode);
+   }
 }
-- 
1.9.rc0.17.g651113e


--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 01/10] replace: refactor command-mode determination

2014-05-16 Thread Christian Couder
From: Jeff King 

The git-replace command has three modes: listing, deleting,
and replacing. The first two are selected explicitly. If
none is selected, we fallback to listing when there are no
arguments, and replacing otherwise.

Let's figure out up front which operation we are going to
do, before getting into the application logic. That lets us
simplify our option checks (e.g., we currently have to check
whether a useless "--force" is given both along with an
explicit list, as well as with an implicit one).

This saves some lines, makes the logic easier to follow, and
will facilitate further cleanups.

Signed-off-by: Jeff King 
Signed-off-by: Christian Couder 
---
 builtin/replace.c | 14 ++
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/builtin/replace.c b/builtin/replace.c
index b62420a..28db96f 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -182,12 +182,16 @@ int cmd_replace(int argc, const char **argv, const char 
*prefix)
 
argc = parse_options(argc, argv, prefix, options, git_replace_usage, 0);
 
+   if (!list && !delete)
+   if (!argc)
+   list = 1;
+
if (list && delete)
usage_msg_opt("-l and -d cannot be used together",
  git_replace_usage, options);
 
-   if (format && delete)
-   usage_msg_opt("--format and -d cannot be used together",
+   if (format && !list)
+   usage_msg_opt("--format cannot be used when not listing",
  git_replace_usage, options);
 
if (force && (list || delete))
@@ -207,9 +211,6 @@ int cmd_replace(int argc, const char **argv, const char 
*prefix)
if (argc != 2)
usage_msg_opt("bad number of arguments",
  git_replace_usage, options);
-   if (format)
-   usage_msg_opt("--format cannot be used when not 
listing",
- git_replace_usage, options);
return replace_object(argv[0], argv[1], force);
}
 
@@ -217,9 +218,6 @@ int cmd_replace(int argc, const char **argv, const char 
*prefix)
if (argc > 1)
usage_msg_opt("only one pattern can be given with -l",
  git_replace_usage, options);
-   if (force)
-   usage_msg_opt("-f needs some arguments",
- git_replace_usage, options);
 
return list_replace_refs(argv[0], format);
 }
-- 
1.9.rc0.17.g651113e


--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 08/10] replace: add tests for --edit

2014-05-16 Thread Christian Couder
Signed-off-by: Christian Couder 
---
 t/t6050-replace.sh | 29 +
 1 file changed, 29 insertions(+)

diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh
index 719a116..7609174 100755
--- a/t/t6050-replace.sh
+++ b/t/t6050-replace.sh
@@ -318,6 +318,35 @@ test_expect_success 'test --format long' '
test_cmp expected actual
 '
 
+test_expect_success 'setup a fake editor' '
+   cat >fakeeditor <<-\EOF &&
+   #!/bin/sh
+   sed -e "s/A U Thor/A fake Thor/" "$1" >"$1.new"
+   mv "$1.new" "$1"
+   EOF
+   chmod +x fakeeditor
+'
+
+test_expect_success '--edit with and without already replaced object' '
+   GIT_EDITOR=./fakeeditor test_must_fail git replace --edit "$PARA3" &&
+   GIT_EDITOR=./fakeeditor git replace --force --edit "$PARA3" &&
+   git replace -l | grep "$PARA3" &&
+   git cat-file commit "$PARA3" | grep "A fake Thor" &&
+   git replace -d "$PARA3" &&
+   GIT_EDITOR=./fakeeditor git replace --edit "$PARA3" &&
+   git replace -l | grep "$PARA3" &&
+   git cat-file commit "$PARA3" | grep "A fake Thor"
+'
+
+test_expect_success '--edit and change nothing or command failed' '
+   git replace -d "$PARA3" &&
+   GIT_EDITOR=true test_must_fail git replace --edit "$PARA3" &&
+   GIT_EDITOR="./fakeeditor;false" test_must_fail git replace --edit 
"$PARA3" &&
+   GIT_EDITOR=./fakeeditor git replace --edit "$PARA3" &&
+   git replace -l | grep "$PARA3" &&
+   git cat-file commit "$PARA3" | grep "A fake Thor"
+'
+
 test_expect_success 'replace ref cleanup' '
test -n "$(git replace)" &&
git replace -d $(git replace) &&
-- 
1.9.rc0.17.g651113e


--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 00/10] replace: add option to edit a Git object

2014-05-16 Thread Christian Couder
This patch series comes from what Peff sent in the following thread:

http://thread.gmane.org/gmane.comp.version-control.git/243361/focus=243528

The first 4 patches (1/4, 2/4, 3/4 and 4/4) didn't change since v1.
I added 6 more small patches to add tests, documentation and a few
small improvements. 

Christian Couder (6):
  replace: make sure --edit results in a different object
  replace: refactor checking ref validity
  replace: die early if replace ref already exists
  replace: add tests for --edit
  replace: add --edit to usage string
  Documentation: replace: describe new --edit option

Jeff King (4):
  replace: refactor command-mode determination
  replace: use OPT_CMDMODE to handle modes
  replace: factor object resolution out of replace_object
  replace: add --edit option

 Documentation/git-replace.txt |  15 ++-
 builtin/replace.c | 225 +-
 t/t6050-replace.sh|  29 ++
 3 files changed, 223 insertions(+), 46 deletions(-)

-- 
1.9.rc0.17.g651113e

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 05/10] replace: make sure --edit results in a different object

2014-05-16 Thread Christian Couder
It's a bad idea to create a replace ref for an object
that points to the original object itself.

That's why we have to check if the result from editing
the original object is a different object and error out
if it isn't.

Signed-off-by: Christian Couder 
---
 builtin/replace.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/replace.c b/builtin/replace.c
index 3da1bae..0751804 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -275,6 +275,9 @@ static int edit_and_replace(const char *object_ref, int 
force)
 
free(tmpfile);
 
+   if (!hashcmp(old, new))
+   return error("new object is the same as the old one: '%s'", 
sha1_to_hex(old));
+
return replace_object_sha1(object_ref, old, "replacement", new, force);
 }
 
-- 
1.9.rc0.17.g651113e


--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 03/10] replace: factor object resolution out of replace_object

2014-05-16 Thread Christian Couder
From: Jeff King 

As we add new options that operate on objects before
replacing them, we'll want to be able to feed raw sha1s
straight into replace_object. Split replace_object into the
object-resolution part and the actual replacement.

Signed-off-by: Jeff King 
Signed-off-by: Christian Couder 
---
 builtin/replace.c | 26 ++
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/builtin/replace.c b/builtin/replace.c
index 29cf699..af40129 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -123,19 +123,17 @@ static int delete_replace_ref(const char *name, const 
char *ref,
return 0;
 }
 
-static int replace_object(const char *object_ref, const char *replace_ref,
- int force)
+static int replace_object_sha1(const char *object_ref,
+  unsigned char object[20],
+  const char *replace_ref,
+  unsigned char repl[20],
+  int force)
 {
-   unsigned char object[20], prev[20], repl[20];
+   unsigned char prev[20];
enum object_type obj_type, repl_type;
char ref[PATH_MAX];
struct ref_lock *lock;
 
-   if (get_sha1(object_ref, object))
-   die("Failed to resolve '%s' as a valid ref.", object_ref);
-   if (get_sha1(replace_ref, repl))
-   die("Failed to resolve '%s' as a valid ref.", replace_ref);
-
if (snprintf(ref, sizeof(ref),
 "refs/replace/%s",
 sha1_to_hex(object)) > sizeof(ref) - 1)
@@ -166,6 +164,18 @@ static int replace_object(const char *object_ref, const 
char *replace_ref,
return 0;
 }
 
+static int replace_object(const char *object_ref, const char *replace_ref, int 
force)
+{
+   unsigned char object[20], repl[20];
+
+   if (get_sha1(object_ref, object))
+   die("Failed to resolve '%s' as a valid ref.", object_ref);
+   if (get_sha1(replace_ref, repl))
+   die("Failed to resolve '%s' as a valid ref.", replace_ref);
+
+   return replace_object_sha1(object_ref, object, replace_ref, repl, 
force);
+}
+
 int cmd_replace(int argc, const char **argv, const char *prefix)
 {
int force = 0;
-- 
1.9.rc0.17.g651113e


--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 04/10] replace: add --edit option

2014-05-16 Thread Christian Couder
From: Jeff King 

This allows you to run:

git replace --edit SHA1

to get dumped in an editor with the contents of the object
for SHA1. The result is then read back in and used as a
"replace" object for SHA1. The writing/reading is
type-aware, so you get to edit "ls-tree" output rather than
the binary tree format.

Missing documentation and tests.

Signed-off-by: Jeff King 
Signed-off-by: Christian Couder 
---
 builtin/replace.c | 112 +-
 1 file changed, 111 insertions(+), 1 deletion(-)

diff --git a/builtin/replace.c b/builtin/replace.c
index af40129..3da1bae 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -12,6 +12,7 @@
 #include "builtin.h"
 #include "refs.h"
 #include "parse-options.h"
+#include "run-command.h"
 
 static const char * const git_replace_usage[] = {
N_("git replace [-f]  "),
@@ -176,6 +177,107 @@ static int replace_object(const char *object_ref, const 
char *replace_ref, int f
return replace_object_sha1(object_ref, object, replace_ref, repl, 
force);
 }
 
+/*
+ * Write the contents of the object named by "sha1" to the file "filename",
+ * pretty-printed for human editing based on its type.
+ */
+static void export_object(const unsigned char *sha1, const char *filename)
+{
+   const char *argv[] = { "--no-replace-objects", "cat-file", "-p", NULL, 
NULL };
+   struct child_process cmd = { argv };
+   int fd;
+
+   fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+   if (fd < 0)
+   die_errno("unable to open %s for writing", filename);
+
+   argv[3] = sha1_to_hex(sha1);
+   cmd.git_cmd = 1;
+   cmd.out = fd;
+
+   if (run_command(&cmd))
+   die("cat-file reported failure");
+
+   close(fd);
+}
+
+/*
+ * Read a previously-exported (and possibly edited) object back from 
"filename",
+ * interpreting it as "type", and writing the result to the object database.
+ * The sha1 of the written object is returned via sha1.
+ */
+static void import_object(unsigned char *sha1, enum object_type type,
+ const char *filename)
+{
+   int fd;
+
+   fd = open(filename, O_RDONLY);
+   if (fd < 0)
+   die_errno("unable to open %s for reading", filename);
+
+   if (type == OBJ_TREE) {
+   const char *argv[] = { "mktree", NULL };
+   struct child_process cmd = { argv };
+   struct strbuf result = STRBUF_INIT;
+
+   cmd.argv = argv;
+   cmd.git_cmd = 1;
+   cmd.in = fd;
+   cmd.out = -1;
+
+   if (start_command(&cmd))
+   die("unable to spawn mktree");
+
+   if (strbuf_read(&result, cmd.out, 41) < 0)
+   die_errno("unable to read from mktree");
+   close(cmd.out);
+
+   if (finish_command(&cmd))
+   die("mktree reported failure");
+   if (get_sha1_hex(result.buf, sha1) < 0)
+   die("mktree did not return an object name");
+
+   strbuf_release(&result);
+   } else {
+   struct stat st;
+   int flags = HASH_FORMAT_CHECK | HASH_WRITE_OBJECT;
+
+   if (fstat(fd, &st) < 0)
+   die_errno("unable to fstat %s", filename);
+   if (index_fd(sha1, fd, &st, type, NULL, flags) < 0)
+   die("unable to write object to database");
+   /* index_fd close()s fd for us */
+   }
+
+   /*
+* No need to close(fd) here; both run-command and index-fd
+* will have done it for us.
+*/
+}
+
+static int edit_and_replace(const char *object_ref, int force)
+{
+   char *tmpfile = git_pathdup("REPLACE_EDITOBJ");
+   enum object_type type;
+   unsigned char old[20], new[20];
+
+   if (get_sha1(object_ref, old) < 0)
+   die("Not a valid object name: '%s'", object_ref);
+
+   type = sha1_object_info(old, NULL);
+   if (type < 0)
+   die("unable to get object type for %s", sha1_to_hex(old));
+
+   export_object(old, tmpfile);
+   if (launch_editor(tmpfile, NULL, NULL) < 0)
+   die("editing object file failed");
+   import_object(new, type, tmpfile);
+
+   free(tmpfile);
+
+   return replace_object_sha1(object_ref, old, "replacement", new, force);
+}
+
 int cmd_replace(int argc, const char **argv, const char *prefix)
 {
int force = 0;
@@ -184,11 +286,13 @@ int cmd_replace(int argc, const char **argv, const char 
*prefix)
MODE_UNSPECIFIED = 0,
MODE_LIST,
MODE_DELETE,
+   MODE_EDIT,
MODE_REPLACE
} cmdmode = MODE_UNSPECIFIED;
struct option options[] = {
OPT_CMDMODE('l', "list", &cmdmode, N_("list replace refs"), 
MODE_LIST),
OPT_CMDMODE('d', "delete", &cmdmode, N_("delete replac

[PATCH v2 06/10] replace: refactor checking ref validity

2014-05-16 Thread Christian Couder
This will be useful in a following commit when we will
want to check if the ref already exists before we let the
user edit an object.

Signed-off-by: Christian Couder 
---
 builtin/replace.c | 31 ---
 1 file changed, 20 insertions(+), 11 deletions(-)

diff --git a/builtin/replace.c b/builtin/replace.c
index 0751804..3d6edaf 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -124,6 +124,25 @@ static int delete_replace_ref(const char *name, const char 
*ref,
return 0;
 }
 
+static void check_ref_valid(unsigned char object[20],
+   unsigned char prev[20],
+   char *ref,
+   int ref_size,
+   int force)
+{
+   if (snprintf(ref, ref_size,
+"refs/replace/%s",
+sha1_to_hex(object)) > ref_size - 1)
+   die("replace ref name too long: %.*s...", 50, ref);
+   if (check_refname_format(ref, 0))
+   die("'%s' is not a valid ref name.", ref);
+
+   if (read_ref(ref, prev))
+   hashclr(prev);
+   else if (!force)
+   die("replace ref '%s' already exists", ref);
+}
+
 static int replace_object_sha1(const char *object_ref,
   unsigned char object[20],
   const char *replace_ref,
@@ -135,13 +154,6 @@ static int replace_object_sha1(const char *object_ref,
char ref[PATH_MAX];
struct ref_lock *lock;
 
-   if (snprintf(ref, sizeof(ref),
-"refs/replace/%s",
-sha1_to_hex(object)) > sizeof(ref) - 1)
-   die("replace ref name too long: %.*s...", 50, ref);
-   if (check_refname_format(ref, 0))
-   die("'%s' is not a valid ref name.", ref);
-
obj_type = sha1_object_info(object, NULL);
repl_type = sha1_object_info(repl, NULL);
if (!force && obj_type != repl_type)
@@ -151,10 +163,7 @@ static int replace_object_sha1(const char *object_ref,
object_ref, typename(obj_type),
replace_ref, typename(repl_type));
 
-   if (read_ref(ref, prev))
-   hashclr(prev);
-   else if (!force)
-   die("replace ref '%s' already exists", ref);
+   check_ref_valid(object, prev, ref, sizeof(ref), force);
 
lock = lock_any_ref_for_update(ref, prev, 0, NULL);
if (!lock)
-- 
1.9.rc0.17.g651113e


--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 07/10] replace: die early if replace ref already exists

2014-05-16 Thread Christian Couder
If a replace ref already exists for an object, it is
much better for the user if we error out before we
let the user edit the object, rather than after.

Signed-off-by: Christian Couder 
---
 builtin/replace.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/builtin/replace.c b/builtin/replace.c
index 3d6edaf..4ee3d92 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -268,7 +268,8 @@ static int edit_and_replace(const char *object_ref, int 
force)
 {
char *tmpfile = git_pathdup("REPLACE_EDITOBJ");
enum object_type type;
-   unsigned char old[20], new[20];
+   unsigned char old[20], new[20], prev[20];
+   char ref[PATH_MAX];
 
if (get_sha1(object_ref, old) < 0)
die("Not a valid object name: '%s'", object_ref);
@@ -277,6 +278,8 @@ static int edit_and_replace(const char *object_ref, int 
force)
if (type < 0)
die("unable to get object type for %s", sha1_to_hex(old));
 
+   check_ref_valid(old, prev, ref, sizeof(ref), force);
+
export_object(old, tmpfile);
if (launch_editor(tmpfile, NULL, NULL) < 0)
die("editing object file failed");
-- 
1.9.rc0.17.g651113e


--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] remote-helpers: point at their upstream repositories

2014-05-16 Thread Jeff King
On Sat, May 17, 2014 at 12:25:30AM -0500, Felipe Contreras wrote:

> > I agree with the line of reasoning you laid out in your email,
> > especially:
> 
> What a shock.

Please stop with these unproductive and rude comments.

> > I hadn't thought of the rename idea, and it would address the concerns I
> > brought up. I do think "obsolete" is the wrong word, as it sends the
> > wrong message. The helpers are not obsolete; it is our _copy_ of them
> > that is.
> 
> Originally you said you would respect if I wanted the code out
> for v2.0, I said I would like it out at some point, not necessarily in
> v2.0. Junio said he was fine with that, but the proposals above don't do
> that.
> 
> Now it seems you are changing your mind and you are OK with the code
> remaining in.

My concerns were with people not noticing the README. Removing the code
entirely is the way I thought of to address that. Junio suggested
another way, which I would also be fine with. And it seems like a
friendlier way than removal to handle it for v2.0, if we are going to
remove the code entirely post-v2.0.

As before, if your desire is to have the code out for v2.0, then say so.
I think we should respect such a request.

-Peff
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] remote-helpers: point at their upstream repositories

2014-05-16 Thread Felipe Contreras
Jeff King wrote:

> I agree with the line of reasoning you laid out in your email,
> especially:

What a shock.

> > I would say that the options I see are these three, and I would rank
> > the "warn every time" as less helpful to end-users:
> > 
> >  - rename contrib/remote-helpers to contrib/obsolete-remote-helpers
> >and add README to point at the upstream.
> > 
> >  - remove contrib/remote-helpers scripts and add README.
> > 
> >  - warn every time the user runs the scripts.
> 
> I hadn't thought of the rename idea, and it would address the concerns I
> brought up. I do think "obsolete" is the wrong word, as it sends the
> wrong message. The helpers are not obsolete; it is our _copy_ of them
> that is.

Originally you said you would respect if I wanted the code out
for v2.0, I said I would like it out at some point, not necessarily in
v2.0. Junio said he was fine with that, but the proposals above don't do
that.

Now it seems you are changing your mind and you are OK with the code
remaining in.

Do what you will, but I already told you what I will do in response.

-- 
Felipe Contreras
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] remote-helpers: point at their upstream repositories

2014-05-16 Thread Felipe Contreras
James Denholm wrote:
> On Fri, May 16, 2014 at 05:39:42PM -0500, Felipe Contreras wrote:
> > (...) I would venture to say you have never made a package in your
> > life.
> 
> And you have, Felipe? Let us see the years of experience you surely have
> in the field.

As a matter of fact, yes I've written many packages, for Debian, Fedora,
ArchLinux, and others. Even Windows installers.

But that's a red herring. Even if was the worst packager in history,
that doesn't make Junio's decision any more correct.

> > The fact that you think packagers of git would simply package
> > git-remote-hg/bzr as well is pretty appalling.
> 
> It's not an outlandish thought, in fact, I'd suggest it as probable -
> provided that they find the projects to be stable and of high quality.

Do you want to bet?

> You, or someone else, might have to tap them on the shoulder and play
> nice to _ensure_ they know about them (after all, we all know that
> packagers _never_ read READMEs, do they), but you're capable of that,
> I'm sure.

In my experience packagers scratch their own itches, and if
git-remote-hg/bzr are not their itch, I don't see why any amount of
nice poking would make them package them. Some other packager would have
to do it, not the Git packagers.

-- 
Felipe Contreras
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] RelNotes/2.0.0.txt: Fix several grammar issues, notably a lack of hyphens, double quotes, or articles

2014-05-16 Thread Jason St. John
Signed-off-by: Jason St. John 
---
 Documentation/RelNotes/2.0.0.txt | 75 
 1 file changed, 38 insertions(+), 37 deletions(-)

diff --git a/Documentation/RelNotes/2.0.0.txt b/Documentation/RelNotes/2.0.0.txt
index 6e628d4..e6bf9d6 100644
--- a/Documentation/RelNotes/2.0.0.txt
+++ b/Documentation/RelNotes/2.0.0.txt
@@ -44,7 +44,7 @@ with "git diff-files --diff-filter=d").
 The default prefix for "git svn" has changed in Git 2.0.  For a long
 time, "git svn" created its remote-tracking branches directly under
 refs/remotes, but it now places them under refs/remotes/origin/ unless
-it is told otherwise with its --prefix option.
+it is told otherwise with its "--prefix" option.
 
 
 Updates since v1.9 series
@@ -53,7 +53,7 @@ Updates since v1.9 series
 UI, Workflows & Features
 
  * The "multi-mail" post-receive hook (in contrib/) has been updated
-   to a more recent version from the upstream.
+   to a more recent version from upstream.
 
  * "git gc --aggressive" learned "--depth" option and
"gc.aggressiveDepth" configuration variable to allow use of a less
@@ -63,12 +63,13 @@ UI, Workflows & Features
single strand-of-pearls is broken in its output.
 
  * The "rev-parse --parseopt" mechanism used by scripted Porcelains to
-   parse command line options and to give help text learned to take
+   parse command-line options and to give help text learned to take
the argv-help (the placeholder string for an option parameter,
e.g. "key-id" in "--gpg-sign=").
 
  * The pattern to find where the function begins in C/C++ used in
-   "diff" and "grep -p" has been updated to help C++ source better.
+   "diff" and "grep -p" has been updated to improve viewing C++
+   sources.
 
  * "git rebase" learned to interpret a lone "-" as "@{-1}", the
branch that we were previously on.
@@ -79,7 +80,7 @@ UI, Workflows & Features
"--sort=version:refname".
 
  * Discard the accumulated "heuristics" to guess from which branch the
-   result wants to be pulled from and make sure what the end user
+   result wants to be pulled from and make sure that what the end user
specified is not second-guessed by "git request-pull", to avoid
mistakes.  When you pushed out your 'master' branch to your public
repository as 'for-linus', use the new "master:for-linus" syntax to
@@ -88,7 +89,7 @@ UI, Workflows & Features
  * "git grep" learned to behave in a way similar to native grep when
"-h" (no header) and "-c" (count) options are given.
 
- * "git push" via transport-helper interface (e.g. remote-hg) has
+ * "git push" via transport-helper interfaces (e.g. remote-hg) has
been updated to allow forced ref updates in a way similar to the
natively supported transports.
 
@@ -114,28 +115,28 @@ UI, Workflows & Features
  * The progress indicators from various time-consuming commands have
been marked for i18n/l10n.
 
- * "git notes -C " diagnoses an attempt to use an object that
-   is not a blob as an error.
+ * "git notes -C " diagnoses as an error an attempt to use an
+   object that is not a blob.
 
  * "git config" learned to read from the standard input when "-" is
given as the value to its "--file" parameter (attempting an
-   operation to update the configuration in the standard input of
-   course is rejected).
+   operation to update the configuration in the standard input is
+   rejected, of course).
 
  * Trailing whitespaces in .gitignore files, unless they are quoted
for fnmatch(3), e.g. "path\ ", are warned and ignored.  Strictly
-   speaking, this is a backward incompatible change, but very unlikely
+   speaking, this is a backward-incompatible change, but very unlikely
to bite any sane user and adjusting should be obvious and easy.
 
- * Many commands that create commits, e.g. "pull", "rebase",
-   learned to take the --gpg-sign option on the command line.
+ * Many commands that create commits, e.g. "pull" and "rebase",
+   learned to take the "--gpg-sign" option on the command line.
 
  * "git commit" can be told to always GPG sign the resulting commit
-   by setting "commit.gpgsign" configuration variable to true (the
-   command line option --no-gpg-sign should override it).
+   by setting the "commit.gpgsign" configuration variable to "true"
+   (the command-line option "--no-gpg-sign" should override it).
 
  * "git pull" can be told to only accept fast-forward by setting the
-   new "pull.ff" configuration.
+   new "pull.ff" configuration variable.
 
  * "git reset" learned the "-N" option, which does not reset the index
fully for paths the index knows about but the tree-ish the command
@@ -152,7 +153,7 @@ Performance, Internal Implementation, etc.
 
  * Uses of curl's "multi" interface and "easy" interface do not mix
well when we attempt to reuse outgoing connections.  Teach the RPC
-   over http code, used in the smart HTTP transport, not to use the
+   over HTTP code, used in the smart HTTP transport, not to use the
  

Re: [PATCH] remote-helpers: point at their upstream repositories

2014-05-16 Thread James Denholm
On Fri, May 16, 2014 at 05:39:42PM -0500, Felipe Contreras wrote:
> (...) I would venture to say you have never made a package in your
> life.

And you have, Felipe? Let us see the years of experience you surely have
in the field.

> The fact that you think packagers of git would simply package
> git-remote-hg/bzr as well is pretty appalling.

It's not an outlandish thought, in fact, I'd suggest it as probable -
provided that they find the projects to be stable and of high quality.
You, or someone else, might have to tap them on the shoulder and play
nice to _ensure_ they know about them (after all, we all know that
packagers _never_ read READMEs, do they), but you're capable of that,
I'm sure.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [git-users] worlds slowest git repo- what to do?

2014-05-16 Thread Duy Nguyen
On Sat, May 17, 2014 at 4:22 AM, John Fisher  wrote:
>> Probably known issues. But some elaboration would be nice (e.g. what 
>> operation is slow, how slow, some more detail
>> characteristics of the repo..) in case new problems pop up.
>
> so far I have done add, commit, status, clone - commit and status are slow; 
> add seems to depend on the files involved,
> clone seems to run at network speed.
> I can provide metrics later, see above. email me offline with what you want.

OK "commit -a" should be just as slow as "add", but as-is commit and
status should be fast unless there are lots of files (how many in your
worktree?) or we hit something that makes us look into (large) file
content anyway.
-- 
Duy
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 2/2] commit: allow core.commentChar=auto for character auto selection

2014-05-16 Thread Nguyễn Thái Ngọc Duy
When core.commentChar is "auto", the comment char starts with '#' as
in default but if it's already in the prepared message, find another
char in a small subset. This should stop surprises because git strips
some lines unexpectedly.

Note that git is not smart enough to recognize '#' as the comment char
in custom templates and convert it if the final comment char is
different. It thinks '#' lines in custom templates as part of the
commit message. So don't use this with custom templates.

Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 Documentation/config.txt |  3 +++
 builtin/commit.c | 32 
 cache.h  |  1 +
 config.c |  3 +++
 environment.c|  1 +
 t/t7502-commit.sh| 26 ++
 6 files changed, 66 insertions(+)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 1932e9b..9f3ce06 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -544,6 +544,9 @@ core.commentchar::
messages consider a line that begins with this character
commented, and removes them after the editor returns
(default '#').
++
+If set to "auto", `git-commit` would select a character that is not
+the beginning character of any line in existing commit messages.
 
 sequence.editor::
Text editor used by `git rebase -i` for editing the rebase instruction 
file.
diff --git a/builtin/commit.c b/builtin/commit.c
index 9cfef6c..515c4c4 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -594,6 +594,36 @@ static char *cut_ident_timestamp_part(char *string)
return ket;
 }
 
+static void adjust_comment_line_char(const struct strbuf *sb)
+{
+   char candidates[] = "#;@!$%^&|:";
+   char *candidate;
+   const char *p;
+
+   comment_line_char = candidates[0];
+   if (!memchr(sb->buf, comment_line_char, sb->len))
+   return;
+
+   p = sb->buf;
+   candidate = strchr(candidates, *p);
+   if (candidate)
+   *candidate = ' ';
+   for (p = sb->buf; *p; p++) {
+   if ((p[0] == '\n' || p[0] == '\r') && p[1]) {
+   candidate = strchr(candidates, p[1]);
+   if (candidate)
+   *candidate = ' ';
+   }
+   }
+
+   for (p = candidates; *p == ' '; p++)
+   ;
+   if (!*p)
+   die(_("unable to select a comment character that is not used\n"
+ "in the current commit message"));
+   comment_line_char = *p;
+}
+
 static int prepare_to_commit(const char *index_file, const char *prefix,
 struct commit *current_head,
 struct wt_status *s,
@@ -748,6 +778,8 @@ static int prepare_to_commit(const char *index_file, const 
char *prefix,
if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
die_errno(_("could not write commit template"));
 
+   if (auto_comment_line_char)
+   adjust_comment_line_char(&sb);
strbuf_release(&sb);
 
/* This checks if committer ident is explicitly given */
diff --git a/cache.h b/cache.h
index 107ac61..646fb81 100644
--- a/cache.h
+++ b/cache.h
@@ -602,6 +602,7 @@ extern int precomposed_unicode;
  * that is subject to stripspace.
  */
 extern char comment_line_char;
+extern int auto_comment_line_char;
 
 enum branch_track {
BRANCH_TRACK_UNSPECIFIED = -1,
diff --git a/config.c b/config.c
index 491a905..d29c733 100644
--- a/config.c
+++ b/config.c
@@ -828,8 +828,11 @@ static int git_default_core_config(const char *var, const 
char *value)
int ret = git_config_string(&comment, var, value);
if (ret)
return ret;
+   else if (!strcasecmp(comment, "auto"))
+   auto_comment_line_char = 1;
else if (comment[0] && !comment[1]) {
comment_line_char = comment[0];
+   auto_comment_line_char = 0;
} else
return error("core.commentChar should only be one 
character");
return 0;
diff --git a/environment.c b/environment.c
index 5c4815d..f2de1ee 100644
--- a/environment.c
+++ b/environment.c
@@ -69,6 +69,7 @@ unsigned long pack_size_limit_cfg;
  * that is subject to stripspace.
  */
 char comment_line_char = '#';
+int auto_comment_line_char;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh
index 9a3f3a1..30e4688 100755
--- a/t/t7502-commit.sh
+++ b/t/t7502-commit.sh
@@ -563,4 +563,30 @@ test_expect_success 'commit --status with custom comment 
character' '
test_i18ngrep "^; Changes to be committed:" .git/COMMIT_EDITMSG
 '
 
+test_expect_success 'switch core.commentchar' '
+   test_commit "#foo" foo &&
+   GIT_EDITOR=.git/FAKE_EDITOR git -c core.commentChar=auto commit --amend 
&&
+ 

[PATCH v2 1/2] config: be strict on core.commentChar

2014-05-16 Thread Nguyễn Thái Ngọc Duy
We don't support comment _strings_ (at least not yet). And multi-byte
character encoding could also be misinterpreted.

The test with two commas is updated because it violates this. It's
added with the patch that introduces core.commentChar in eff80a9
(Allow custom "comment char" - 2013-01-16). It's not clear to me _why_
that behavior is wanted.

Signed-off-by: Nguyễn Thái Ngọc Duy 
---
 config.c  | 8 ++--
 t/t7508-status.sh | 3 +--
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/config.c b/config.c
index a30cb5c..491a905 100644
--- a/config.c
+++ b/config.c
@@ -826,9 +826,13 @@ static int git_default_core_config(const char *var, const 
char *value)
if (!strcmp(var, "core.commentchar")) {
const char *comment;
int ret = git_config_string(&comment, var, value);
-   if (!ret)
+   if (ret)
+   return ret;
+   else if (comment[0] && !comment[1]) {
comment_line_char = comment[0];
-   return ret;
+   } else
+   return error("core.commentChar should only be one 
character");
+   return 0;
}
 
if (!strcmp(var, "core.askpass"))
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index c987b5e..148ab9e 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1350,8 +1350,7 @@ test_expect_success "status (core.commentchar with 
submodule summary)" '
 
 test_expect_success "status (core.commentchar with two chars with submodule 
summary)" '
test_config core.commentchar ";;" &&
-   git -c status.displayCommentPrefix=true status >output &&
-   test_i18ncmp expect output
+   test_must_fail git -c status.displayCommentPrefix=true status
 '
 
 test_expect_success "--ignore-submodules=all suppresses submodule summary" '
-- 
1.9.1.346.ga2b5940

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 2/2] commit: allow core.commentChar=auto for character auto selection

2014-05-16 Thread Duy Nguyen
On Fri, May 16, 2014 at 11:40 PM, Jonathan Nieder  wrote:
> Nguyễn Thái Ngọc Duy wrote:
>
>> core.commentChar starts with '#' as in default but if it's already in
>> the prepared message, find another one among a small subset. This
>> should stop surprises because git strips some lines unexpectedly.
>
> Probably worth mentioning this only kicks in if someone explicitly
> configures [core] commentchar = auto.
>
> Would it be a goal to make 'auto' the default eventually if people
> turn out to like it?

No. I started this with a patch that does this automatically without a
config knob. It broke git-commit with custom templates. It broke
--cleanup=strip -e -F.. So people may want to put this in ~/.gitconfig
but it's their decision.

>> --- a/builtin/commit.c
>> +++ b/builtin/commit.c
>> @@ -594,6 +594,40 @@ static char *cut_ident_timestamp_part(char *string)
>>   return ket;
>>  }
>>
>> +static void adjust_comment_line_char(const struct strbuf *sb)
>> +{
>> + char candidates[] = " @!#$%^&|:;~";
>
> This prefers '@' over '#'.  Intended?

It used to be the order of keys 1, 2, 3... on qwerty keyboard, but I
was afraid ! may become history expansion in bash so I made @
preferred over !. Will make # and ; higher priority.

>> + char *candidate;
>> + const char *p;
>> +
>> + if (!sb->len)
>> + return;
>> +
>> + if (!strchr(candidates, comment_line_char))
>> + candidates[0] = comment_line_char;
>
> Could do
>
> if (!memchr(sb->buf, comment_line_char, sb->len))
> return;
>
> to solve the precedence problem.  The comment_line_char not appearing
> in the message is the usual case and handling it separately means it
> gets handled faster.

Now that we use "auto" to turn this on, the placeholder candidates[0]
could probably be removed, we know comment_line_char is '#' at this
point.

>> --- a/config.c
>> +++ b/config.c
>> @@ -829,6 +829,8 @@ static int git_default_core_config(const char *var, 
>> const char *value)
>>   if (!ret) {
>>   if (comment[0] && !comment[1])
>>   comment_line_char = comment[0];
>> + else if (!strcasecmp(comment, "auto"))
>> + auto_comment_line_char = 1;
>
> Is there a way to disable 'auto' if 'auto' is already set?
>
> comment_line_char still can be set and matters when 'auto' is set.
> Should they be separate settings?

I think the next core.commentChar should override the old one, so
auto_comment_line_char should be clear when we set new value to
comment_line_char.
-- 
Duy
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v8 22/44] fetch.c: clear errno before calling functions that might set it

2014-05-16 Thread Jeff King
On Fri, May 16, 2014 at 11:33:48AM -0700, Jonathan Nieder wrote:

> (cc-ing peff, who may remember this STORE_REF_ERROR_DF_CONFLICT case
>  from long ago)

No, but I have very good tools for searching the list archive. ;)

> > In s_update_ref there are two calls that when they fail we return an error
> > based on the errno value. In particular we want to return a specific error
> > if ENOTDIR happened. Both these functions do have failure modes where they
> > may return an error without updating errno
> 
> That's a bug.  Any function for which errno is supposed to be
> meaningful when it returns an error should always set errno.
> Otherwise errno may be set to ENOTDIR within the function by an
> unrelated system call.

I'd agree. It's OK for a function not to set errno if it is
_successful_. But if setting errno on error is part of the interface for
lock_any_ref_for_update, it should do so consistently.

We have not been very good about documenting which functions use errno,
or using it consistently (e.g., in my original patch, we are explicitly
converting errno into a numeric return value!), so I can definitely see
how it is confusing.

> That should cover the cases affecting the code path in fetch.c you
> mentioned (I haven't checked the others).
> 
> How about something like this?
> [...]

Yeah, I think this is a better direction.

> diff --git i/refs.c w/refs.c
> index 82a8d4e..f98acf0 100644
> --- i/refs.c
> +++ w/refs.c
> @@ -1333,8 +1333,10 @@ const char *resolve_ref_unsafe(const char *refname, 
> unsigned char *sha1, int rea
>   if (flag)
>   *flag = 0;
>  
> - if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
> + if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
> + errno = EINVAL;
>   return NULL;
> + }

check_refname_format comes up in a few places. I wonder if it should set
EINVAL itself.

Other than that, I just skimmed through your list. All looked
reasonable to me, though I was not thorough enough to be sure we got
call cases (OTOH, we can add them later on top).

-Peff
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Returning error message from custom smart http server

2014-05-16 Thread brian m. carlson
On Tue, May 13, 2014 at 09:39:59AM +0200, "Ákos, Tajti" wrote:
> Dear List,
> 
> we implemented our own git smart http server to be able to check permissions
> and other thing before pushes. It works fine, however, the error messages we
> generate on the server side are not displayed by the command line client. On
> the server we generate error messages like this:
> 
> response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
> response.getWriter().write(msg);
> 
> On the command line we get this:
> 
> Total 0 (delta 0), reused 0 (delta 0)
> POST git-receive-pack (290 bytes)
> efrror: RPC failed; result=22, HTTP code = 401
> atal: The remote end hung up unexpectedly
> fatal: The remote end hung up unexpectedly
> 
> The server message is completely missing. Is there a solution for this?

It does look that way.  Does the following patch work for you?

-- >8 --
Subject: [PATCH] http: provide server's error message on RPC failure

The server might provide a custom error message that is useful to the user.
Provide this message to the user if HTTP RPC fails.

Signed-off-by: brian m. carlson 
---
 remote-curl.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/remote-curl.c b/remote-curl.c
index 52c2d96..5984d35 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -426,8 +426,8 @@ static int run_slot(struct active_request_slot *slot,
err = run_one_slot(slot, results);
 
if (err != HTTP_OK && err != HTTP_REAUTH) {
-   error("RPC failed; result=%d, HTTP code = %ld",
- results->curl_result, results->http_code);
+   error("RPC failed; result=%d, HTTP code = %ld (%s)",
+ results->curl_result, results->http_code, curl_errorstr);
}
 
return err;
-- >8 --

-- 
brian m. carlson / brian with sandals: Houston, Texas, US
+1 832 623 2791 | http://www.crustytoothpaste.net/~bmc | My opinion only
OpenPGP: RSA v4 4096b: 88AC E9B2 9196 305B A994 7552 F1BA 225C 0223 B187


signature.asc
Description: Digital signature


Re: [PATCH v8 23/44] fetch.c: change s_update_ref to use a ref transaction

2014-05-16 Thread Jonathan Nieder
Ronnie Sahlberg wrote:

> --- a/builtin/fetch.c
> +++ b/builtin/fetch.c
[...]
> @@ -384,15 +384,16 @@ static int s_update_ref(const char *action,
>   snprintf(msg, sizeof(msg), "%s: %s", rla, action);
>  
>   errno = 0;
> - lock = lock_any_ref_for_update(ref->name,
> -check_old ? ref->old_sha1 : NULL,
> -0, NULL);
> - if (!lock)
> - return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
> -   STORE_REF_ERROR_OTHER;
> - if (write_ref_sha1(lock, ref->new_sha1, msg) < 0)
> + transaction = ref_transaction_begin();
> + if (!transaction ||
> + ref_transaction_update(transaction, ref->name, ref->new_sha1,
> +ref->old_sha1, 0, check_old) ||
> + ref_transaction_commit(transaction, msg, NULL)) {

Since 'err' is NULL, does that mean there's no message shown to the
user on error?
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v8 24/44] fetch.c: use a single ref transaction for all ref updates

2014-05-16 Thread Jonathan Nieder
Ronnie Sahlberg wrote:

> Change store_updated_refs to use a single ref transaction for all refs that
> are updated during the fetch. This makes the fetch more atomic when update
> failures occur.

Fun.

[...]
> --- a/builtin/fetch.c
> +++ b/builtin/fetch.c
[...]
> @@ -373,27 +374,13 @@ static int s_update_ref(const char *action,
>   struct ref *ref,
>   int check_old)
>  {
> - char msg[1024];
> - char *rla = getenv("GIT_REFLOG_ACTION");
> - struct ref_transaction *transaction;

Previously fetch respected GIT_REFLOG_ACTION, and this is dropping
that support.  Intended?

[...]
> + if (ref_transaction_update(transaction, ref->name, ref->new_sha1,
> +ref->old_sha1, 0, check_old))
> + return STORE_REF_ERROR_OTHER;

Should pass a strbuf in to get a message back.

[...]
> +
>   return 0;
>  }
>  
> @@ -565,6 +552,13 @@ static int store_updated_refs(const char *raw_url, const 
> char *remote_name,
>   goto abort;
>   }
>  
> + errno = 0;
> + transaction = ref_transaction_begin();
> + if (!transaction) {
> + rc = error(_("cannot start ref transaction\n"));
> + goto abort;

error() appends a newline on its own, so the message shouldn't
end with newline.

More importantly, this message isn't helpful without more detail about
why _transaction_begin() failed.  The user doesn't know what

error: cannot start ref transaction

means.

error: cannot connect to mysqld for ref storage: [etc]

would tell what they need to know.  That is:

transaction = ref_transaction_begin(err);
if (!transaction) {
rc = error("%s", err.buf);
goto abort;
}

errno is not used here, so no need to set errno = 0.

[...]
> @@ -676,6 +670,10 @@ static int store_updated_refs(const char *raw_url, const 
> char *remote_name,
>   }
>   }
>   }
> + if ((ret = ref_transaction_commit(transaction, NULL)))
> + rc |= ret == -2 ? STORE_REF_ERROR_DF_CONFLICT :
> + STORE_REF_ERROR_OTHER;

(I cheated and stole the newer code from your repo.)

Yay!  Style nit: git avoids assignments in "if" conditionals.

ret = ref_tr...
if (ret == -2)
rc |= ...
else if (ret)
rc |= ...

Does _update need the too as futureproofing for backends that can
detect the name conflict sooner?

Thanks,
Jonathan
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] remote-helpers: point at their upstream repositories

2014-05-16 Thread Jeff King
On Fri, May 16, 2014 at 09:52:15AM -0700, Junio C Hamano wrote:

> Or am I reacting to a typo and you meant to say "I would prefer not
> to instrument"?  Your "shipping the warnings to end users who did
> not package the software will not help" was unclear if you meant the
> README that has warning or warning message they have to see every
> time from the instrumented code.

Argh, yes, it is a typo. I had written "I would prefer _not_ to
instrument the code with warnings...". While reading it back to myself,
I thought "using underlining there is too argumentative", but somehow
managed to delete the whole word rather than simply the "_" characters.
I'm very sorry to have wasted people's time by accidentally making the
opposite point.

I agree with the line of reasoning you laid out in your email,
especially:

> I would say that the options I see are these three, and I would rank
> the "warn every time" as less helpful to end-users:
> 
>  - rename contrib/remote-helpers to contrib/obsolete-remote-helpers
>and add README to point at the upstream.
> 
>  - remove contrib/remote-helpers scripts and add README.
> 
>  - warn every time the user runs the scripts.

I hadn't thought of the rename idea, and it would address the concerns I
brought up. I do think "obsolete" is the wrong word, as it sends the
wrong message. The helpers are not obsolete; it is our _copy_ of them
that is.

-Peff
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] remote-helpers: point at their upstream repositories

2014-05-16 Thread Felipe Contreras
Junio C Hamano wrote:
> Jeff King  writes:
> 
> > On Thu, May 15, 2014 at 03:56:29PM -0700, Junio C Hamano wrote:
> >
> >> Two announcements for their version 0.2 on the list archive are not
> >> quite enough to advertise them to their users.
> >
> > I do not think this README nor a mention in the release notes will get
> > their attention either, and many people (and packagers) will continue to
> > use the stale versions forever until those versions go away.
> >
> > I would much rather _replace_ them with a README in the long run, and
> > people will notice that they are gone, and then use the README to update
> > their install procedure.
> >
> > For 2.0, I am hesitant to do that, though I do not have a problem with a
> > README like this as a heads-up to prepare packagers for the future. I
> > say hesitant because people may have been test-packaging 2.0.0-rc3 in
> > preparation for release, and it will be annoying to them to suddenly
> > switch.
> 
> I share the latter two of the above three.  I was giving distro
> packagers a bit more credit for their diligence in knowing what they
> are packaging than you seem to be in your first point, but I admit
> that it is a blind faith.

I don't see why anybody would think otherwise. There are dozens of tools
in contrib/ many without documentation, or even a description of that
whey do. I bet most Git developers don't know what half of them do (even
a quarter), how are package maintainers supposed to know?

All the packages I've seen stash everything into /usr/share/git, with a
few exceptions, like shell completions.

> > But that being said, this is Felipe's code. While we have a legal right
> > to distribute it in v2.0, if he would really prefer it out for v2.0, I
> > would respect that.
> 
> I am fine with that.

Are you? Because in two of the three options you list below you wouldn't
be doing that.

> > I would prefer to instrument the code with warnings, as that is the sort
> > of thing a packager moving from -rc3 to -final might not notice, and
> > shipping the warnings to end users who did not package the software in
> > the first place will not help them. It is the attention of the packagers
> > (and source-builders) you want to get.
> 
> I do agree that a new warning every time it is run will be a more
> likely to grab users' attention.  The conclusion I draw from that
> shared observation is that the user will be annoyed all the time,

That's exactly what we do when anything gets deprecated. Try running Git
with an empty configuration for a day and you'll see tons of warnings,
often huge ones every time the user does common operations, like
`git push`.

Why is it OK to warn about minor behavior changes, but not when the
whole code the user is exercising might be broken?

At least the warning I proposed for the remote-helpers is small and to
the point, unlike the warning of `git push` without refspec.

> without having a power to do anything about the annoyance, until the
> report s/he (or other users) Throw at the packager, even when the
> version that was packaged hasn't diverged that much yet, which does
> not help end users.

What do you expect the packagers are going to do? They will simply
ignore the report as it's not related to their package (git).

I suspect this will continue for quite some time, and very likely these
will not be packaged as part of the official distribution, but some
user-based repository. In some distributions they might end up being
unpackaged completely.

Take git-imerge as an example, a very popular tool you yourself are very
fond of. I don't see it packaged either in ArchLinux, Debian, or Fedora,
and I don't think it will ever be packaged.

So, yes, this will hurt our users, that's what every user of an
out-of-tree tool must suffer, and that's what you unilaterally decided
users of git-remote-hg/bzr should suffer.

> I guess the ideal we want is to make sure their build break.

We cannot make 'cp -r contrib /usr/share/git' fail, that's all packagers
do.

I already pointed to the fact that most of the tools in contrib
shouldn't even be there, and that most of them should have tests. If
there was a standardized way to tests contrib, we could make the build
break. But you ignored my call of attention.

> What if we do the README in addition to rename contrib/remote-helpers
> to contrib/obsolete-remote-helpers (or s/obsolete/graduated/)?  It
> will give the packagers three choices and I think it hurts people much
> less.
> 
>  * The packagers that dump the entirety of contrib/ to somewhere
>without doing anything to expose the scripts to user's PATH do
>not have to do anything.  The users who chose to pick them up
>from there notice the missing contrib/remote-helpers, notice
>"obsolete" (or "graduated"), and read README.

This is wrong. Users will not notice the missing contrib/remote-helpers.
At least not initially. If they setup links to /usr/share, they'll just
see:

  fatal: Unable to find remote helper fo

Delaying 2.0 final

2014-05-16 Thread Junio C Hamano
As we seem to have a few regressions we may want to fix, I will not
be cutting the 2.0 final today (https://tinyurl.com/gitCal).

I queued the following near the bottom of 'pu' (these are also
merged to 'next' to keep pu^{/match.next} in sync with next), and
plan to cut 2.0.0-rc4 early next week.

 * git-gui has a show-stopper bug that wants to see if it is used
   with a version of git that "vsatisfies" 1.7.0; because 2.x is
   considered significantly different, it incorrectly decides to use
   the codepath for ancient versions that compares older than 1.7.0
   when working inside a submodule working tree.  A fix by Jens
   Lehmann is queued as an emergency patch to use vcompare instead.

 * There was a vague admission of having broken git-remote-hg/bzr by
   its author that hinted one topic branch is the culprit, without
   much detail.  As a precautionary measure, the merge of the topic
   has been reverted.

 * git-remote-hg/bzr are maintained outside our tree, our copy will
   become stale and will eventually go away.  A warning message to
   its standard error output has been added to each of them to tell
   the users where to find the latest of these tools.

 * git-request-pull has a minor regression and lost a useful DWIM
   that was designed to be friendly to users of Git older than
   1.7.10.  "git request-pull $base $URL for-linus" used to say
   "Please pull tags/for-linus" if that is what the user meant, but
   the version in 2.0.0-rc3 requires the command line to be "git
   request-pull $base $URL tags/for-linus".  It is simple enough to
   special case this use case, and a patch is included to fix it
   with a band-aid.

If you fetch tonight's 'pu' branch, you will find all of the above
at f608b83.  Hopefully 2.0.0-rc4 and 2.0.0-final will be the same
tree as that commit, with updated release notes.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: GIT, libcurl and GSS-Negotiate

2014-05-16 Thread brian m. carlson
On Mon, May 12, 2014 at 04:21:53PM -0400, Jeff King wrote:
> On Sat, May 10, 2014 at 09:01:32PM +, brian m. carlson wrote:
> > * Make git understand that it really needs to try again with different
> >   credentials in this case (how to do that is unknown).
> 
> It should be pretty straightforward to loop again; http_request_reauth
> just needs to turn into a for-loop on getting HTTP_REAUTH, rather than a
> static two-tries (I even had a patch for this a while ago, but the
> function has changed a bit in the interim).
> 
> The tricky part is figuring out when to return HTTP_NOAUTH ("do not try
> again, we failed") versus HTTP_REAUTH ("get credentials and try again")
> in handle_curl_result. Right now the decision is based on "did we have a
> username and password for this request?" I'm not clear on what extra
> bits would be needed to decide to continue in the case you guys are
> discussing.

I'm honestly not sure, either.  That's why I said, "how to do that is
unknown".

However, if you base64-decode the two Negotiate replies in the
successful attempt with WinHTTP and pass it through od -tc, you'll see
that the second reply contains some form of user ID that the first one
does not.  The curl binary sends an identical reply for the first pass,
but then gives up and does not try a second pass.  I don't know if
libcurl is able to provide the data required in the second pass.

All of this is way outside my knowledge, since my Kerberos/GSSAPI
Negotiate requests look very different than the NTLM ones.

> > * Provide some way of forcing git to use a particular authentication
> >   protocol.
> 
> Yeah, we just set CURLAUTH_ANY now, but it would be fairly trivial to
> add "http.authtype" and "http.proxyauthtype" to map to CURLOPT_HTTPAUTH
> and CURLOPT_PROXYAUTH.

This might be the easiest option.

-- 
brian m. carlson / brian with sandals: Houston, Texas, US
+1 832 623 2791 | http://www.crustytoothpaste.net/~bmc | My opinion only
OpenPGP: RSA v4 4096b: 88AC E9B2 9196 305B A994 7552 F1BA 225C 0223 B187


signature.asc
Description: Digital signature


Re: [PATCH v8 23/44] fetch.c: change s_update_ref to use a ref transaction

2014-05-16 Thread Ronnie Sahlberg
On Fri, May 16, 2014 at 12:12 PM, Jonathan Nieder  wrote:
> (+cc: peff for STORE_REF_ERROR_DF_CONFLICT expertise)
> Ronnie Sahlberg wrote:
>
>> --- a/builtin/fetch.c
>> +++ b/builtin/fetch.c
>> @@ -375,7 +375,7 @@ static int s_update_ref(const char *action,
> [...]
>> + transaction = ref_transaction_begin();
>> + if (!transaction ||
>> + ref_transaction_update(transaction, ref->name, ref->new_sha1,
>> +ref->old_sha1, 0, check_old) ||
>> + ref_transaction_commit(transaction, msg, NULL)) {
>> + ref_transaction_rollback(transaction);
>>   return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
>> STORE_REF_ERROR_OTHER;
>> + }
>
> I'd rather not rely on errno here (see the previous patch for why).
> Is there some other way to distinguish the case where a ref couldn't
> be created because there was a prefix of that ref in the way?
>
> For example, maybe ref_transaction_commit could return a different
> negative integer in this case.

I have changed it to make transaction_commit will return a special
error if there is a name conflict
and fetch.c now uses that instead of looking at errno to decide if to
print the "try pruning" message.


>
> Thanks,
> Jonathan
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 09/31] refs.c: allow multiple reflog updates during a single transaction

2014-05-16 Thread Eric Sunshine
On Fri, May 16, 2014 at 5:35 PM, Junio C Hamano  wrote:
> Ronnie Sahlberg  writes:
>
>> Allow to make multiple reflog updates to the same ref during a transaction.
>> This means we only need to lock the reflog once, during the first update that
>> touches the reflog, and that all further updates can just write the reflog
>> entry since the reflog is already locked.
>>
>> This allows us to write code such as:
>>
>> t = transaction_begin()
>> transaction_reflog_update(t, "foo", REFLOG_TRUNCATE, NULL);
>> loop-over-somehting...
>>transaction_reflog_update(t, "foo", 0, );
>> transaction_commit(t)
>
> OK, so you are now doing not just "refs" but also "reflogs", you
> felt that "ref_transaction()" does not cover the latter.  Is that
> the reason for the rename in the earlier step?
>
> I am sort-of on the fence.
>
> Calling the begin "ref_transaction_begin" and then calling the new
> function "ref_transaction_log_update" would still allow us to
> differentiate transactions on refs and reflogs, while allowing other
> kinds of transactions that are not related to refs at all to employ
> a mechanism that is different from the one that is used to implement
> the transactions on refs and reflogs you are building here.
>
> But I think I am OK with the generic "transaction-begin" now.
> Having one mechanism for refs and reflogs, and then having another
> completely different mechanism for other things, will not let us
> coordinate between the two easily, so "allow transactions that are
> not related to refs at all to be built on a different mechanism" may
> not be a worthwhile goal to pursue in the first place.  Please
> consider the question on the naming in the earlier one dropped.
>
>>
>> where we first truncate the reflog and then build the new content one line 
>> at a
>> time.
>>
>> Signed-off-by: Ronnie Sahlberg 
>> ---
>>  refs.c | 58 +-
>>  1 file changed, 49 insertions(+), 9 deletions(-)
>>
>> diff --git a/refs.c b/refs.c
>> index a3f60ad..e7ede03 100644
>> --- a/refs.c
>> +++ b/refs.c
>> @@ -37,6 +37,10 @@ static inline int bad_ref_char(int ch)
>>   *  need to lock the loose ref during the transaction.
>>   */
>>  #define REF_ISPACKONLY   0x0200
>> +/** Only the first reflog update needs to lock the reflog file. Further 
>> updates
>> + *  just use the lock taken by the first update.
>> + */
>
> Style.
>
>> @@ -3349,8 +3355,23 @@ int transaction_update_reflog(struct ref_transaction 
>> *transaction,
>> int flags)
>>  {
>>   struct ref_update *update;
>> + int i;
>>
>>   update = add_update(transaction, refname, UPDATE_LOG);
>> + update->flags = flags;
>> + for (i = 0; i < transaction->nr - 1; i++) {
>> + if (transaction->updates[i]->update_type != UPDATE_LOG)
>> + continue;
>> + if (!strcmp(transaction->updates[i]->refname,
>> + update->refname)) {
>> + update->flags |= UPDATE_REFLOG_NOLOCK;
>> + update->orig_update = transaction->updates[i];
>> + break;
>> + }
>> + }
>> + if (!(update->flags & UPDATE_REFLOG_NOLOCK))
>> +   update->reflog_lock = xcalloc(1, sizeof(struct lock_file));
>
> So with two calls to transaction-update-reflog, we make two calls to
> add-update, and each holds a separate lock?  If we write two entries
> to record two updates of the same ref, would we still want to do so?

Also, indent with tabs rather than spaces (the line following the 'if').

>> + /* Rollback any reflog files that are still open */
>> + for (i = 0; i < n; i++) {
>> + struct ref_update *update = updates[i];
>> +
>> + if (update->update_type != UPDATE_LOG)
>> + continue;
>> + if (update->flags & UPDATE_REFLOG_NOLOCK)
>> + continue;
>> + if (update->reflog_fd == -1)
>> + continue;
>> + rollback_lock_file(update->reflog_lock);
>> + }
>>   transaction->status = ret ? REF_TRANSACTION_ERROR
>> : REF_TRANSACTION_CLOSED;

Indent with tabs.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 09/31] refs.c: allow multiple reflog updates during a single transaction

2014-05-16 Thread Junio C Hamano
Ronnie Sahlberg  writes:

> Allow to make multiple reflog updates to the same ref during a transaction.
> This means we only need to lock the reflog once, during the first update that
> touches the reflog, and that all further updates can just write the reflog
> entry since the reflog is already locked.
>
> This allows us to write code such as:
>
> t = transaction_begin()
> transaction_reflog_update(t, "foo", REFLOG_TRUNCATE, NULL);
> loop-over-somehting...
>transaction_reflog_update(t, "foo", 0, );
> transaction_commit(t)

OK, so you are now doing not just "refs" but also "reflogs", you
felt that "ref_transaction()" does not cover the latter.  Is that
the reason for the rename in the earlier step?

I am sort-of on the fence.

Calling the begin "ref_transaction_begin" and then calling the new
function "ref_transaction_log_update" would still allow us to
differentiate transactions on refs and reflogs, while allowing other
kinds of transactions that are not related to refs at all to employ
a mechanism that is different from the one that is used to implement
the transactions on refs and reflogs you are building here.

But I think I am OK with the generic "transaction-begin" now.
Having one mechanism for refs and reflogs, and then having another
completely different mechanism for other things, will not let us
coordinate between the two easily, so "allow transactions that are
not related to refs at all to be built on a different mechanism" may
not be a worthwhile goal to pursue in the first place.  Please
consider the question on the naming in the earlier one dropped.

>
> where we first truncate the reflog and then build the new content one line at 
> a
> time.
>
> Signed-off-by: Ronnie Sahlberg 
> ---
>  refs.c | 58 +-
>  1 file changed, 49 insertions(+), 9 deletions(-)
>
> diff --git a/refs.c b/refs.c
> index a3f60ad..e7ede03 100644
> --- a/refs.c
> +++ b/refs.c
> @@ -37,6 +37,10 @@ static inline int bad_ref_char(int ch)
>   *  need to lock the loose ref during the transaction.
>   */
>  #define REF_ISPACKONLY   0x0200
> +/** Only the first reflog update needs to lock the reflog file. Further 
> updates
> + *  just use the lock taken by the first update.
> + */

Style.

> @@ -3349,8 +3355,23 @@ int transaction_update_reflog(struct ref_transaction 
> *transaction,
> int flags)
>  {
>   struct ref_update *update;
> + int i;
>  
>   update = add_update(transaction, refname, UPDATE_LOG);
> + update->flags = flags;
> + for (i = 0; i < transaction->nr - 1; i++) {
> + if (transaction->updates[i]->update_type != UPDATE_LOG)
> + continue;
> + if (!strcmp(transaction->updates[i]->refname,
> + update->refname)) {
> + update->flags |= UPDATE_REFLOG_NOLOCK;
> + update->orig_update = transaction->updates[i];
> + break;
> + }
> + }
> + if (!(update->flags & UPDATE_REFLOG_NOLOCK))
> +   update->reflog_lock = xcalloc(1, sizeof(struct lock_file));

So with two calls to transaction-update-reflog, we make two calls to
add-update, and each holds a separate lock?  If we write two entries
to record two updates of the same ref, would we still want to do so?

> + /* Rollback any reflog files that are still open */
> + for (i = 0; i < n; i++) {
> + struct ref_update *update = updates[i];
> +
> + if (update->update_type != UPDATE_LOG)
> + continue;
> + if (update->flags & UPDATE_REFLOG_NOLOCK)
> + continue;
> + if (update->reflog_fd == -1)
> + continue;
> + rollback_lock_file(update->reflog_lock);
> + }
>   transaction->status = ret ? REF_TRANSACTION_ERROR
> : REF_TRANSACTION_CLOSED;
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 08/31] refs.c: only write reflog update if msg is non-NULL

2014-05-16 Thread Junio C Hamano
Ronnie Sahlberg  writes:

> When performing a reflog transaction update, only write to the reflog iff
> msg is non-NULL. This can then be combined with REFLOG_TRUNCATE to perform
> an update that only truncates but does not write.
>
> Signed-off-by: Ronnie Sahlberg 
> ---
>  refs.c | 8 +---
>  refs.h | 1 +
>  2 files changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/refs.c b/refs.c
> index a8b583a..a3f60ad 100644
> --- a/refs.c
> +++ b/refs.c
> @@ -3625,9 +3625,11 @@ int transaction_commit(struct ref_transaction 
> *transaction,
>   ftruncate(update->reflog_fd, 0)) {
>   error("Could not truncate reflog");
>   }
> - if (log_ref_write_fd(update->reflog_fd, update->old_sha1,
> -  update->new_sha1,
> -  update->committer, update->msg)) {
> + if (update->msg && log_ref_write_fd(update->reflog_fd,
> + update->old_sha1,
> + update->new_sha1,
> + update->committer,
> + update->msg)) {

Wouldn't it make it easier to read if you chopped immediately after
the &&, i.e. chopping at a gap at a higher-level in the parse tree?

if (update->msg &&
log_ref_write_fd(update->reflog_fd,
 update->old_sha1, update->old_sha1,
 update->committer, update->msg)) {
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [git-users] worlds slowest git repo- what to do?

2014-05-16 Thread John Fisher

On 05/16/2014 03:13 AM, Duy Nguyen wrote:
> On Fri, May 16, 2014 at 2:06 AM, Philip Oakley  wrote:
>> From: "John Fisher" 
>>> I assert based on one piece of evidence ( a post from a facebook dev) that
>>> I now have the worlds biggest and slowest git
>>> repository, and I am not a happy guy. I used to have the worlds biggest
>>> CVS repository, but CVS can't handle multi-G
>>> sized files. So I moved the repo to git, because we are using that for our
>>> new projects.
>>>
>>> goal:
>>> keep 150 G of files (mostly binary) from tiny sized to over 8G in a
>>> version-control system.
> I think your best bet so far is git-annex 

good, I am  looking at that

> (or maybe bup) for dealing
> with huge files. I plan on resurrecting Junio's split-blob series to
> make core git handle huge files better, but there's no eta on that.
> The problem here is about file size, not the number of files, or
> history depth, right?

When things here calm down, I could easily test the repo without the giant 
files, leaving 99% of files in the repo.
There is hardly any history depth because these are releases, version 
controlled by directory name. As has been
suggested I could be forced to abandon the version-control, even to the point 
of just using rsync.  But I've been doing
this with CVS for 10 years now and I hate to change or in any way move away 
fron KISS. Moving it to Git may not have
been one of my better ideas...


> Probably known issues. But some elaboration would be nice (e.g. what 
> operation is slow, how slow, some more detail
> characteristics of the repo..) in case new problems pop up. 

so far I have done add, commit, status, clone - commit and status are slow; add 
seems to depend on the files involved,
clone seems to run at network speed.
I can provide metrics later, see above. email me offline with what you want.

John
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 07/31] refs.c: add a flag to allow reflog updates to truncate the log

2014-05-16 Thread Junio C Hamano
Ronnie Sahlberg  writes:

> Add a flag that allows us to truncate the reflog before we write the update.
>
> Signed-off-by: Ronnie Sahlberg 
> ---

Until we read the callers it is hard to see how such a feature is
useful, though.

(style) The two multi-line comments are formatted differently.

>  refs.c | 12 ++--
>  refs.h |  4 +++-
>  2 files changed, 13 insertions(+), 3 deletions(-)
>
> diff --git a/refs.c b/refs.c
> index d8a1568..a8b583a 100644
> --- a/refs.c
> +++ b/refs.c
> @@ -3608,7 +3608,11 @@ int transaction_commit(struct ref_transaction 
> *transaction,
>   }
>   }
>  
> - /* Update all reflog files */
> + /* Update all reflog files
> +We have already done all ref updates and deletes.
> +There is not much we can do here if there are any reflog
> +update errors, other than complain.
> + */
>   for (i = 0; i < n; i++) {
>   struct ref_update *update = updates[i];
>  
> @@ -3616,7 +3620,11 @@ int transaction_commit(struct ref_transaction 
> *transaction,
>   continue;
>   if (update->reflog_fd == -1)
>   continue;
> -
> + if (update->flags & REFLOG_TRUNCATE)
> + if (lseek(update->reflog_fd, 0, SEEK_SET) < 0 ||
> + ftruncate(update->reflog_fd, 0)) {
> + error("Could not truncate reflog");
> + }

The {} looks somewhat curious here.  If you seeked to the beginning,
and failed to truncate, do you still want to go on without "return"
in front of the error()?  Would that overwrite existing entries?

>   if (log_ref_write_fd(update->reflog_fd, update->old_sha1,
>update->new_sha1,
>update->committer, update->msg)) {
> diff --git a/refs.h b/refs.h
> index 2e22a26..b1b97e7 100644
> --- a/refs.h
> +++ b/refs.h
> @@ -269,8 +269,10 @@ int transaction_delete_sha1(struct ref_transaction 
> *transaction,
>   const unsigned char *old_sha1,
>   int flags, int have_old, const char *msg);
>  
> +#define REFLOG_TRUNCATE 0x01
>  /*
> - * Append a reflog entry for refname.
> + * Append a reflog entry for refname. If the REFLOG_TRUNCATE flag is set
> + * this update will first truncate the reflog before writing the entry.
>   */
>  int transaction_update_reflog(struct ref_transaction *transaction,
> const char *refname,
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 03/31] refs.c: rename the transaction functions

2014-05-16 Thread Junio C Hamano
Ronnie Sahlberg  writes:

> Rename the transaction functions. Remove the leading ref_ from the names
> and append _sha1 to the names for functions that create/delete/update sha1
> refs.
> ...
> - transaction = ref_transaction_begin();
> + transaction = transaction_begin();

Why?  Do we forsee that there will never be other kinds of
transaction, and whenever we say a "transaction" that will be always
about updating the refs and nothing else?
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v8 22/44] fetch.c: clear errno before calling functions that might set it

2014-05-16 Thread Ronnie Sahlberg
errno is hairy :-(


You probably also want something like this :
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 4603cb6..55e7dd8 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -426,7 +426,7 @@ static int update_local_ref(struct ref *ref,
_("! %-*s %-*s -> %s  (can't fetch in current branch
TRANSPORT_SUMMARY(_("[rejected]")),
REFCOL_WIDTH, remote, pretty_ref);
-   return 1;
+   return STORE_REF_ERROR_OTHER;
}

if (!is_null_sha1(ref->old_sha1) &&
@@ -513,7 +513,7 @@ static int update_local_ref(struct ref *ref,
TRANSPORT_SUMMARY(_("[rejected]")),
REFCOL_WIDTH, remote, pretty_ref,
_("(non-fast-forward)"));
-   return 1;
+   return STORE_REF_ERROR_OTHER;
}
 }


To make it more clear that this function returns a specific error and
not just a generic not-zero.


On Fri, May 16, 2014 at 11:33 AM, Jonathan Nieder  wrote:
> (cc-ing peff, who may remember this STORE_REF_ERROR_DF_CONFLICT case
>  from long ago)
> Ronnie Sahlberg wrote:
>
>> In s_update_ref there are two calls that when they fail we return an error
>> based on the errno value. In particular we want to return a specific error
>> if ENOTDIR happened. Both these functions do have failure modes where they
>> may return an error without updating errno
>
> That's a bug.  Any function for which errno is supposed to be
> meaningful when it returns an error should always set errno.
> Otherwise errno may be set to ENOTDIR within the function by an
> unrelated system call.
>
> Functions that fail and lead callers to check errno, based on a quick
> search with 'git grep -e 'errno *[!=]=':
>
>  fopen
>  lstat
>  builtin/apply.c::try_create_file (= mkdir, symlink, or open)
>  rmdir
>  open
>  mkdir
>  unlink
>  lock_any_ref_for_update
>  write_ref_sha1
>  strtol
>  kill
>  odb_pack_keep
>  opendir
>  fgets
>  read
>  poll
>  pread
>  strtoimax
>  strtoumax
>  git_parse_int
>  git_parse_int64
>  git_parse_ulong
>  write_in_full
>  credential-cache.c::send_request
>  fstat
>  run_command_v_opt
>  git.c::run_argv
>  readlink
>  resolve_ref_unsafe
>  hold_lock_file_for_update
>  unlink_or_warn
>  rename
>  execvp
>  waitpid
>  execv_git_cmd
>  execv_shell_cmd
>  sane_execvp
>  stat
>  read_object
>  git_mkstemp_mode
>  create_tmpfile
>  start_command
>  xwrite
>  iconv
>  fast_export_ls
>  fast_export_ls_rev
>  delete_ref
>
> lock_any_ref_for_update has failure paths
>  * check_ref_format [!]
>  * lock_ref_sha1_basic
>
> lock_ref_sha1_basic has failure paths
>  * remove_empty_directories
>  * resolve_ref_unsafe
>  * safe_create_leading_directories
>  * verify_lock
>
> remove_empty_directories has one failure path
>  * remove_dir_recursively
> but could be more explicit about the need to preserve errno.
>
> errno from remove_dir_recursively is meaningful.
>
> resolve_ref_unsafe has failure paths
>  * check_refname_format [!]
>  * too much recursion [!]
>  * lstat, readlink, open
>  * handle_missing_loose_ref
>  * read_in_full, but errno gets clobbered
>  * invalid ref [!]
>  * invalid symref [!]
>
> verify_lock has failure paths
>  * read_ref_full, but errno gets clobbered
>  * old_sha1 didn't match [!]
>
> write_ref_sha1 has failure paths
>  * !lock [!]
>  * missing object [!]
>  * non-commit object [!]
>  * write_in_full, close_ref, but errno gets clobbered
>  * log_ref_write
>  * commit_ref
>
> log_ref_write has failure paths
>  * log_ref_setup
>  * write_in_full, close.  errno gets clobbered
>
> commit_ref just calls commit_lock_file.
>
> log_ref_setup has failure paths
>  * safe_create_leading_directories, but errno gets clobbered
>  * remove_empty_directories, but errno gets clobbered
>  * open, but errno gets clobbered
>
> safe_create_leading_directories doesn't set errno for SCLD_EXISTS
> but otherwise its errno is useful.
>
> That should cover the cases affecting the code path in fetch.c you
> mentioned (I haven't checked the others).
>
> How about something like this?
>
> It's also tempting to teach vreportf and vwritef to save errno, which
> would handle some of these cases automatically.
>
> diff --git i/refs.c w/refs.c
> index 82a8d4e..f98acf0 100644
> --- i/refs.c
> +++ w/refs.c
> @@ -1333,8 +1333,10 @@ const char *resolve_ref_unsafe(const char *refname, 
> unsigned char *sha1, int rea
> if (flag)
> *flag = 0;
>
> -   if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
> +   if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
> +   errno = EINVAL;
> return NULL;
> +   }
>
> for (;;) {
> char path[PATH_MAX];
> @@ -1342,8 +1344,10 @@ const char *resolve_ref_unsafe(const char *refname, 
> unsigned char *sha1, int rea
> char *buf;
> int fd;
>
> -   if (--depth < 0)
>

Re: [PATCH v8 23/44] fetch.c: change s_update_ref to use a ref transaction

2014-05-16 Thread Jonathan Nieder
(+cc: peff for STORE_REF_ERROR_DF_CONFLICT expertise)
Ronnie Sahlberg wrote:

> --- a/builtin/fetch.c
> +++ b/builtin/fetch.c
> @@ -375,7 +375,7 @@ static int s_update_ref(const char *action,
[...]
> + transaction = ref_transaction_begin();
> + if (!transaction ||
> + ref_transaction_update(transaction, ref->name, ref->new_sha1,
> +ref->old_sha1, 0, check_old) ||
> + ref_transaction_commit(transaction, msg, NULL)) {
> + ref_transaction_rollback(transaction);
>   return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
> STORE_REF_ERROR_OTHER;
> + }

I'd rather not rely on errno here (see the previous patch for why).
Is there some other way to distinguish the case where a ref couldn't
be created because there was a prefix of that ref in the way?

For example, maybe ref_transaction_commit could return a different
negative integer in this case.

Thanks,
Jonathan
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 10/10] git-submodule.sh: don't use the -a or -b option with the test command

2014-05-16 Thread Junio C Hamano
Jonathan Nieder  writes:

> Perhaps something like the following would work?
>
>   tree-wide: convert test -a/-o to && and ||
>
>   The interaction with unary operators and operator precedence
>   for && and || are better known than -a and -o, and for that
>   reason we prefer them.  Replace all existing instances in git
>   of -a and -o to save readers from the burden of thinking
>   about such things.
>
>   Add a check-non-portable-shell.pl to avoid more instances of
>   test -a and -o arising in the future.

Yeah, the title is certainly better than "-a or -b option" I see
above ;-) and a single tree-wide fix may be OK while the tree is
quiescent.

I however do think "better known" is much less of an issue than that
"-a/-o" is more error prone e.g. 'test -n "$x" -a a = b' is buggy
because it does not consider that $x could be "=".



> [...]
>> -test $status = D -o $status = T && echo "$sm_path" && 
>> continue
>> + ( test $status = D || test $status = T ) && echo 
>> "$sm_path" && continue
>
> There's no need for a subshell for this.  Better to use a block:
>
>   {
>   test "$status" = D ||
>   test "$status" = T
>   } &&
>   echo "$sm_path" &&
>   continue

Yes.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] commit: switch core.commentChar if it's found in existing commit

2014-05-16 Thread Junio C Hamano
Junio C Hamano  writes:

> Nguyễn Thái Ngọc Duy   writes:
>
>> If we need to use core.commentChar and it's already in the prepared
>> message, find another char among a small subset. This should stop
>> surprises because git strips some lines unexpectedly. Of course if
>> candicate characters happen to be all out, this change does not help.
>>
>> Signed-off-by: Nguyễn Thái Ngọc Duy 
>> ---
>>  On Fri, May 16, 2014 at 5:28 PM, Duy Nguyen  wrote:
>>  > But maybe git should detect that the
>>  > current commit message has leading '#' and automatically switch to
>>  > another character..
>>
>>  Something like this. Lightly tested.. I know there's a small bug..
>>
>>  builtin/commit.c | 29 +
>>  1 file changed, 29 insertions(+)
>>
>> diff --git a/builtin/commit.c b/builtin/commit.c
>> index 6ab4605..70ceb61 100644
>> --- a/builtin/commit.c
>> +++ b/builtin/commit.c
>> @@ -593,6 +593,32 @@ static char *cut_ident_timestamp_part(char *string)
>>  return ket;
>>  }
>>  
>> +static void adjust_comment_line_char(const struct strbuf *sb)
>> +{
>> +char candidates[] = " !@#$%^&|:;~";
>
> Did you really mean to add a SP to the candidates?

Please ignore this noise.  I realized that the SP is there only to
be overwritten in the meantime, and this is an old message sent out
before that realization, just emerging from my mail provider's
outbox.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2 1/2] t4205, t6006: Add failing tests for the case when i18n.logOutputEncoding is set

2014-05-16 Thread Junio C Hamano
Alexey Shumkin  writes:

> Pretty format string %<(N,[ml]trunc)>%s truncates subject to a given
> length with an appropriate padding. This works for non-ASCII texts when
> i18n.logOutputEncoding is UTF-8 only (independently of a printed commit
> message encoding) but does not work when i18n.logOutputEncoding is NOT
> UTF-8.
>
> There were no breakages as far as were no tests for the case
> when both a commit message and logOutputEncoding are not UTF-8.
>
> Add failing tests for that which will be fixed in the next patch.
>
> Signed-off-by: Alexey Shumkin 
> Reviewed-by: Nguyễn Thái Ngọc Duy 
> ---
>  t/t4205-log-pretty-formats.sh | 169 
> ++
>  t/t6006-rev-list-format.sh|  75 ++-
>  2 files changed, 242 insertions(+), 2 deletions(-)
>
> diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
> index 2a6278b..6791e0d 100755
> --- a/t/t4205-log-pretty-formats.sh
> +++ b/t/t4205-log-pretty-formats.sh
> @@ -153,6 +153,19 @@ EOF
>   test_cmp expected actual
>  '
>  
> +test_expect_success 'left alignment formatting. i18n.logOutputEncoding' '
> + git -c i18n.logOutputEncoding=iso8859-1 log --pretty="format:%<(40)%s" 
> >actual &&
> + # complete the incomplete line at the end
> + echo >>actual &&

Would it change the meaning of the test if you used tformat: instead
of format: (or --format="%<(40)%s")?  If it doesn't, it would make
it unnecessary to append an extra LF and explain why you do so.

> + qz_to_tab_space  + git -c i18n.logOutputEncoding=iso8859-1 log --pretty="format:%<(1)%s" 
> >actual &&
> + # complete the incomplete line at the end
> + echo >>actual &&

Likewise for all the other "--pretty=format:" followed by an echo.

Thanks.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re* regression: request-pull with signed tag lacks tags/ in master

2014-05-16 Thread Junio C Hamano
Junio C Hamano  writes:

> "Michael S. Tsirkin"  writes:
>
>>> My reading of the earlier parts of the series is that Linus wanted
>>> us never dwim "for-upstream" to "tags/for-upstream" or any other ref
>>> that happens to point at the same commit as for-upstream you have.
>>> The changes done for that purpose covered various cases a bit too
>>> widely, and "request-pull ... tags/for_upstream" were incorrectly
>>> stripped to a request to pull "for_upstream", which was fixed by
>>> 5aae66bd (request-pull: resurrect "pretty refname" feature,
>>> 2014-02-25).
>>> 
>>> But that fix does not resurrect the dwimming forbid by the earlier
>>> parts of the series to turn "for_upstream" into "tags/for_upstream".
>>> 
>>> What would you get if you do this?
>>> 
>>> $ git request-pull origin/master \
>>>   git://git.kernel.org/pub/scm/virt/kvm/mst/qemu.git \
>>>   tags/for_upstream | grep git.kernel.org
>>
>>
>> I get
>>  git://git.kernel.org/pub/scm/virt/kvm/mst/qemu.git tags/for_upstream
>
> Thanks for double-checking.  Let's close this as working as
> intended, then.
>
> I personally feel that the "intention" tightened the logic a bit too
> much [*1*], and with the updates mentioned in [*2*], existing users
> may find it still too tight, but that is what we have today.
>
>
> [References]
>
> *1* http://thread.gmane.org/gmane.comp.version-control.git/240860
> *2* http://thread.gmane.org/gmane.comp.version-control.git/240886

An update.

In the ideal world, I think it would be nice to make

$ git request-pull $mine $URL for_upstream

explicitly say "Please pull tags/for_upstream" rather than without
"tags/" prefix to accomodate older Git, where

$ git pull $URL for_upstream

did not DWIM to fetch and merge tags/for_upstream and the user had
to say "tags/for_upstream" instead.

That "older Git" refers to those without 47d84b6a (fetch: allow "git
fetch $there v1.0" to fetch a tag, 2011-11-04).  v1.7.10 (tagged on
April 6th, 2012) and later versions of Git will notice that the name
refers to the tags/for_upstream just fine, so I think it is fair to
label this as a minor cosmetic regression whose fix can wait for a
future maintenance release, rather than a blocker for the upcoming
release.

I _think_ the fix, without breaking the spirit of Linus's "I do not
want the thing DWIM based on what the remote end has" original,
would be as simple as this patch.  We can queue it as a regression
fix and do another round of -rc4 if those who depend on request-pull
heavily feel strongly about it.

Comments?


 git-request-pull.sh | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/git-request-pull.sh b/git-request-pull.sh
index 5c15997..d5500fd 100755
--- a/git-request-pull.sh
+++ b/git-request-pull.sh
@@ -119,6 +119,12 @@ then
status=1
 fi
 
+# Special case: turn "for_linus" to "tags/for_linus" when it is correct
+if test "$ref" = "refs/tags/$pretty_remote"
+then
+   pretty_remote=tags/$pretty_remote
+fi
+
 url=$(git ls-remote --get-url "$url")
 
 git show -s --format='The following changes since commit %H:


--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] commit: switch core.commentChar if it's found in existing commit

2014-05-16 Thread Junio C Hamano
Nguyễn Thái Ngọc Duy   writes:

> If we need to use core.commentChar and it's already in the prepared
> message, find another char among a small subset. This should stop
> surprises because git strips some lines unexpectedly. Of course if
> candicate characters happen to be all out, this change does not help.
>
> Signed-off-by: Nguyễn Thái Ngọc Duy 
> ---
>  On Fri, May 16, 2014 at 5:28 PM, Duy Nguyen  wrote:
>  > But maybe git should detect that the
>  > current commit message has leading '#' and automatically switch to
>  > another character..
>
>  Something like this. Lightly tested.. I know there's a small bug..
>
>  builtin/commit.c | 29 +
>  1 file changed, 29 insertions(+)
>
> diff --git a/builtin/commit.c b/builtin/commit.c
> index 6ab4605..70ceb61 100644
> --- a/builtin/commit.c
> +++ b/builtin/commit.c
> @@ -593,6 +593,32 @@ static char *cut_ident_timestamp_part(char *string)
>   return ket;
>  }
>  
> +static void adjust_comment_line_char(const struct strbuf *sb)
> +{
> + char candidates[] = " !@#$%^&|:;~";

Did you really mean to add a SP to the candidates?

> + char *candidate;
> + const char *p;
> + if (!sb->len)
> + return;
> + candidates[0] = comment_line_char;
> + p = sb->buf;
> + do {
> + candidate = strchr(candidates, *p);
> + if (candidate)
> + *candidate = ' ';
> + p = strchrnul(p, '\n');
> + if (*p)
> + p++;
> + } while (*p);
> + if (strchr(candidates, comment_line_char)) {
> + p = candidates;
> + while (*p && *p == ' ')
> + p++;
> + if (*p)
> + comment_line_char = *p;
> + }
> +}
> +
>  static int prepare_to_commit(const char *index_file, const char *prefix,
>struct commit *current_head,
>struct wt_status *s,
> @@ -748,6 +774,9 @@ static int prepare_to_commit(const char *index_file, 
> const char *prefix,
>   if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
>   die_errno(_("could not write commit template"));
>  
> + if (use_editor && include_status)
> + adjust_comment_line_char(&sb);
> +
>   strbuf_release(&sb);
>  
>   /* This checks if committer ident is explicitly given */
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH/RFC] Gitweb: Convert UTF-8 encoded file names

2014-05-16 Thread Junio C Hamano
Jakub Narębski  writes:

>> Correct, but is "where does it appear" the question we are
>> primarily interested in, wrt this breakage and its fix?
>
> That of course depends on how we want to test gitweb output.
> The simplest solution, comparing with known output with perhaps
> fragile / variable elements masked out could be done quickly...
> but changes in output (even if they don't change functionality,
> or don't change visible output) require regenerating test cases
> (expected output) to test against - which might be source of
> errors in test suite.

I agree with your "to test it fully, we need extra dependencies",
but my point is that it does not have to be a full "HTML-validating,
picking the expected attribute via XPATH matching" kind of test if
what we want is only to add a new test to protect this particular
fix from future breakages.

For example, I think it is sufficient to grep for 'href="...%xx%xx"'
in the output after preparing a sample tree with one entry to show.
The expected substring either exists (in which case we got it
right), or it doesn't (in which case we are showing garbage).  Of
course that depends on the assumption that its output is not too
heavily contaminated with volatile parts outside our control, as I
already mentioned in the message you are responding to.

But it all depends on "if" we wanted to add a new test ;-)
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v10 00/44] Use ref transactions for all ref updates

2014-05-16 Thread Jonathan Nieder
Ronnie Sahlberg wrote:

> This patch series can also be found at
> https://github.com/rsahlberg/git/tree/ref-transactions

I think the rerolls are coming too fast.  I've been using your
repository on github to check if I should not send any particular
comment because you've already fixed it, so the extra mail is not
needed for that purpose, at least.

In general, I think it's best to stick with one version of a series,
gather review comments on it, comment inline to solicit feedback about
approaches to particular problems, point reviewers to an up-to-date
branch which is more in flux, etc, and then only resend when reviewers
have had a chance to get through it to make it easier to keep track of
the review without getting lost.

Thanks for the quick work so far, by the way.  It's been fun watching
the API evolve.

My two cents,
Jonathan
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v8 22/44] fetch.c: clear errno before calling functions that might set it

2014-05-16 Thread Jonathan Nieder
(cc-ing peff, who may remember this STORE_REF_ERROR_DF_CONFLICT case
 from long ago)
Ronnie Sahlberg wrote:

> In s_update_ref there are two calls that when they fail we return an error
> based on the errno value. In particular we want to return a specific error
> if ENOTDIR happened. Both these functions do have failure modes where they
> may return an error without updating errno

That's a bug.  Any function for which errno is supposed to be
meaningful when it returns an error should always set errno.
Otherwise errno may be set to ENOTDIR within the function by an
unrelated system call.

Functions that fail and lead callers to check errno, based on a quick
search with 'git grep -e 'errno *[!=]=':

 fopen
 lstat
 builtin/apply.c::try_create_file (= mkdir, symlink, or open)
 rmdir
 open
 mkdir
 unlink
 lock_any_ref_for_update 
 write_ref_sha1
 strtol
 kill
 odb_pack_keep
 opendir
 fgets
 read
 poll
 pread
 strtoimax
 strtoumax
 git_parse_int
 git_parse_int64
 git_parse_ulong
 write_in_full
 credential-cache.c::send_request
 fstat
 run_command_v_opt
 git.c::run_argv
 readlink
 resolve_ref_unsafe
 hold_lock_file_for_update
 unlink_or_warn
 rename
 execvp
 waitpid
 execv_git_cmd
 execv_shell_cmd
 sane_execvp
 stat
 read_object
 git_mkstemp_mode
 create_tmpfile
 start_command
 xwrite
 iconv
 fast_export_ls
 fast_export_ls_rev
 delete_ref

lock_any_ref_for_update has failure paths
 * check_ref_format [!]
 * lock_ref_sha1_basic

lock_ref_sha1_basic has failure paths
 * remove_empty_directories
 * resolve_ref_unsafe
 * safe_create_leading_directories
 * verify_lock

remove_empty_directories has one failure path
 * remove_dir_recursively
but could be more explicit about the need to preserve errno.

errno from remove_dir_recursively is meaningful.

resolve_ref_unsafe has failure paths
 * check_refname_format [!]
 * too much recursion [!]
 * lstat, readlink, open
 * handle_missing_loose_ref
 * read_in_full, but errno gets clobbered
 * invalid ref [!]
 * invalid symref [!]

verify_lock has failure paths
 * read_ref_full, but errno gets clobbered
 * old_sha1 didn't match [!]
 
write_ref_sha1 has failure paths
 * !lock [!]
 * missing object [!]
 * non-commit object [!]
 * write_in_full, close_ref, but errno gets clobbered
 * log_ref_write
 * commit_ref

log_ref_write has failure paths
 * log_ref_setup
 * write_in_full, close.  errno gets clobbered

commit_ref just calls commit_lock_file.

log_ref_setup has failure paths
 * safe_create_leading_directories, but errno gets clobbered
 * remove_empty_directories, but errno gets clobbered
 * open, but errno gets clobbered

safe_create_leading_directories doesn't set errno for SCLD_EXISTS
but otherwise its errno is useful.

That should cover the cases affecting the code path in fetch.c you
mentioned (I haven't checked the others).

How about something like this?

It's also tempting to teach vreportf and vwritef to save errno, which
would handle some of these cases automatically.

diff --git i/refs.c w/refs.c
index 82a8d4e..f98acf0 100644
--- i/refs.c
+++ w/refs.c
@@ -1333,8 +1333,10 @@ const char *resolve_ref_unsafe(const char *refname, 
unsigned char *sha1, int rea
if (flag)
*flag = 0;
 
-   if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
+   if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
+   errno = EINVAL;
return NULL;
+   }
 
for (;;) {
char path[PATH_MAX];
@@ -1342,8 +1344,10 @@ const char *resolve_ref_unsafe(const char *refname, 
unsigned char *sha1, int rea
char *buf;
int fd;
 
-   if (--depth < 0)
+   if (--depth < 0) {
+   errno = ELOOP;
return NULL;
+   }
 
git_snpath(path, sizeof(path), "%s", refname);
 
@@ -1405,9 +1409,13 @@ const char *resolve_ref_unsafe(const char *refname, 
unsigned char *sha1, int rea
return NULL;
}
len = read_in_full(fd, buffer, sizeof(buffer)-1);
-   close(fd);
-   if (len < 0)
+   if (len < 0) {
+   int save_errno = errno;
+   close(fd);
+   errno = save_errno;
return NULL;
+   }
+   close(fd);
while (len && isspace(buffer[len-1]))
len--;
buffer[len] = '\0';
@@ -1424,6 +1432,7 @@ const char *resolve_ref_unsafe(const char *refname, 
unsigned char *sha1, int rea
(buffer[40] != '\0' && !isspace(buffer[40]))) {
if (flag)
*flag |= REF_ISBROKEN;
+   errno = EINVAL;
return NULL;
}
return refname;
@@ -1436,6 +1445,7 @@ const char *resolve_ref_unsaf

Re: [PATCH 2/2] commit: allow core.commentChar=auto for character auto selection

2014-05-16 Thread Junio C Hamano
Jonathan Nieder  writes:

> Nguyễn Thái Ngọc Duy wrote:
>
>> core.commentChar starts with '#' as in default but if it's already in
>> the prepared message, find another one among a small subset. This
>> should stop surprises because git strips some lines unexpectedly.
>
> Probably worth mentioning this only kicks in if someone explicitly
> configures [core] commentchar = auto.
>
> Would it be a goal to make 'auto' the default eventually if people
> turn out to like it?
>
> [...]
>> --- a/builtin/commit.c
>> +++ b/builtin/commit.c
>> @@ -594,6 +594,40 @@ static char *cut_ident_timestamp_part(char *string)
>>  return ket;
>>  }
>>  
>> +static void adjust_comment_line_char(const struct strbuf *sb)
>> +{
>> +char candidates[] = " @!#$%^&|:;~";
>
> This prefers '@' over '#'.  Intended?

I think the candidates[0] will almost always be overridden with "#"
so it probably does not matter in practice, but I tend to agree that
"#" (and probably ";") should come before all others.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/2] config: be strict on core.commentChar

2014-05-16 Thread Junio C Hamano
Jonathan Nieder  writes:

> Nguyễn Thái Ngọc Duy wrote:
>
>> --- a/config.c
>> +++ b/config.c
>> @@ -826,8 +826,12 @@ static int git_default_core_config(const char *var, 
>> const char *value)
>>  if (!strcmp(var, "core.commentchar")) {
>>  const char *comment;
>>  int ret = git_config_string(&comment, var, value);
>> -if (!ret)
>> -comment_line_char = comment[0];
>> +if (!ret) {
>> +if (comment[0] && !comment[1])
>> +comment_line_char = comment[0];
>> +else
>> +return error("core.commentChar should only be 
>> one character");
>> +}
>
> Perhaps, to decrease indentation a little:
>
>   if (ret)
>   return ret;
>   if (comment[0] && !comment[1])
>   comment_line_char = comment[0];
>   else
>   return error(...);
>   return 0;
>
> [...]
>> --- a/t/t7508-status.sh
>> +++ b/t/t7508-status.sh
>> @@ -1348,12 +1348,6 @@ test_expect_success "status (core.commentchar with 
>> submodule summary)" '
>>  test_i18ncmp expect output
>>  '
>>  
>> -test_expect_success "status (core.commentchar with two chars with submodule 
>> summary)" '
>> -test_config core.commentchar ";;" &&
>> -git -c status.displayCommentPrefix=true status >output &&
>> -test_i18ncmp expect output
>
> Could keep the test to avoid regressions:
>
>   test_config core.commentchar ";;" &&
>   test_must_fail git -c status.displayCommentPrefix=true status

All good points, including your other review message.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] request-pull: resurrect for-linus -> tags/for-linus DWIM

2014-05-16 Thread Junio C Hamano
Older versions of Git before v1.7.10 did not DWIM

$ git pull $URL for-linus

to the tag "tags/for-linus" and the users were required to say

$ git pull $URL tags/for-linus

instead.  Because newer versions of Git works either way,
request-pull used to show tags/for-linus when asked

$ git request-pull origin/master $URL for-linus

The recent updates broke this and in the output we see "for-linus"
without the "tags/" prefix.

As v1.7.10 is more than 2 years old, this should matter very little
in practice, but resurrecting it is very simple.

Signed-off-by: Junio C Hamano 
---

 * I _think_ the fix, without breaking the spirit of Linus's "I do
   not want the thing DWIM based on what the remote end has"
   original, would be as simple as this patch.  We can queue it as a
   regression fix and do another round of -rc4 if those who depend
   on request-pull heavily feel strongly about it.

 git-request-pull.sh | 6 ++
 t/t5150-request-pull.sh | 8 +++-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/git-request-pull.sh b/git-request-pull.sh
index b67513a..d6648b2 100755
--- a/git-request-pull.sh
+++ b/git-request-pull.sh
@@ -118,6 +118,12 @@ then
status=1
 fi
 
+# Special case: turn "for_linus" to "tags/for_linus" when it is correct
+if test "$ref" = "refs/tags/$pretty_remote"
+then
+   pretty_remote=tags/$pretty_remote
+fi
+
 url=$(git ls-remote --get-url "$url")
 
 git show -s --format='The following changes since commit %H:
diff --git a/t/t5150-request-pull.sh b/t/t5150-request-pull.sh
index 75d6b38..93e2c65 100755
--- a/t/t5150-request-pull.sh
+++ b/t/t5150-request-pull.sh
@@ -223,7 +223,13 @@ test_expect_success 'pull request format' '
git request-pull initial "$downstream_url" 
tags/full:refs/tags/full
) >request &&
sed -nf fuzz.sed request.fuzzy &&
-   test_i18ncmp expect request.fuzzy
+   test_i18ncmp expect request.fuzzy &&
+
+   (
+   cd local &&
+   git request-pull initial "$downstream_url" full
+   ) >request &&
+   grep ' tags/full$'
 '
 
 test_expect_success 'request-pull ignores OPTIONS_KEEPDASHDASH poison' '
-- 
2.0.0-rc3-434-g1ba2fe8

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH/RFC] Gitweb: Convert UTF-8 encoded file names

2014-05-16 Thread Junio C Hamano
(sorry if you receive a dup; pobox.com seems to be constipated right now)

Jakub Narębski  writes:

>> Correct, but is "where does it appear" the question we are
>> primarily interested in, wrt this breakage and its fix?
>
> That of course depends on how we want to test gitweb output.
> The simplest solution, comparing with known output with perhaps
> fragile / variable elements masked out could be done quickly...
> but changes in output (even if they don't change functionality,
> or don't change visible output) require regenerating test cases
> (expected output) to test against - which might be source of
> errors in test suite.

I agree with your "to test it fully, we need extra dependencies",
but my point is that it does not have to be a full "HTML-validating,
picking the expected attribute via XPATH matching" kind of test if
what we want is only to add a new test to protect this particular
fix from future breakages.

For example, I think it is sufficient to grep for 'href="...%xx%xx"'
in the output after preparing a sample tree with one entry to show.
The expected substring either exists (in which case we got it
right), or it doesn't (in which case we are showing garbage).  Of
course that depends on the assumption that its output is not too
heavily contaminated with volatile parts outside our control, as I
already mentioned in the message you are responding to.

But it all depends on "if" we wanted to add a new test ;-)
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] remote-helpers: point at their upstream repositories

2014-05-16 Thread Junio C Hamano
Jeff King  writes:

> On Thu, May 15, 2014 at 03:56:29PM -0700, Junio C Hamano wrote:
>
>> Two announcements for their version 0.2 on the list archive are not
>> quite enough to advertise them to their users.
>
> I do not think this README nor a mention in the release notes will get
> their attention either, and many people (and packagers) will continue to
> use the stale versions forever until those versions go away.
>
> I would much rather _replace_ them with a README in the long run, and
> people will notice that they are gone, and then use the README to update
> their install procedure.
>
> For 2.0, I am hesitant to do that, though I do not have a problem with a
> README like this as a heads-up to prepare packagers for the future. I
> say hesitant because people may have been test-packaging 2.0.0-rc3 in
> preparation for release, and it will be annoying to them to suddenly
> switch.

I share the latter two of the above three.  I was giving distro
packagers a bit more credit for their diligence in knowing what they
are packaging than you seem to be in your first point, but I admit
that it is a blind faith.

> But that being said, this is Felipe's code. While we have a legal right
> to distribute it in v2.0, if he would really prefer it out for v2.0, I
> would respect that.

I am fine with that.

> I would prefer to instrument the code with warnings, as that is the sort
> of thing a packager moving from -rc3 to -final might not notice, and
> shipping the warnings to end users who did not package the software in
> the first place will not help them. It is the attention of the packagers
> (and source-builders) you want to get.

I do agree that a new warning every time it is run will be a more
likely to grab users' attention.  The conclusion I draw from that
shared observation is that the user will be annoyed all the time,
without having a power to do anything about the annoyance, until the
report s/he (or other users) Throw at the packager, even when the
version that was packaged hasn't diverged that much yet, which does
not help end users.

I guess the ideal we want is to make sure their build break.  What
if we do the README in addition to rename contrib/remote-helpers to
contrib/obsolete-remote-helpers (or s/obsolete/graduated/)?  It will
give the packagers three choices and I think it hurts people much
less.

 * The packagers that dump the entirety of contrib/ to somewhere
   without doing anything to expose the scripts to user's PATH do
   not have to do anything.  The users who chose to pick them up
   from there notice the missing contrib/remote-helpers, notice
   "obsolete" (or "graduated"), and read README.

 * The packagers that pick up from contrib/remote-helpers and
   arrange the scripts to be on user's PATH will find their build
   broken, because they are no longer where they expect them to be.
   They will notice "obsolete"(or "graduated"), and read README.

   - They can choose to pick them up from "obsolete", perhaps for
 expediency, perhaps for their change aversion, but that will
 not last once we grabbed their attention, and they will switch
 their upstream in some later release once such a choice makes
 them feel dirty enough.

   - They can choose to switch their upstream right now in response
 to the breakage.

I would say that the options I see are these three, and I would rank
the "warn every time" as less helpful to end-users:

 - rename contrib/remote-helpers to contrib/obsolete-remote-helpers
   and add README to point at the upstream.

 - remove contrib/remote-helpers scripts and add README.

 - warn every time the user runs the scripts.

Or am I reacting to a typo and you meant to say "I would prefer not
to instrument"?  Your "shipping the warnings to end users who did
not package the software will not help" was unclear if you meant the
README that has warning or warning message they have to see every
time from the instrumented code.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] remote-helpers: point at their upstream repositories

2014-05-16 Thread Junio C Hamano
(Sorry if you receive a dup; pobox.com seems to be constipated right now).

Jeff King  writes:

> On Thu, May 15, 2014 at 03:56:29PM -0700, Junio C Hamano wrote:
>
>> Two announcements for their version 0.2 on the list archive are not
>> quite enough to advertise them to their users.
>
> I do not think this README nor a mention in the release notes will get
> their attention either, and many people (and packagers) will continue to
> use the stale versions forever until those versions go away.
>
> I would much rather _replace_ them with a README in the long run, and
> people will notice that they are gone, and then use the README to update
> their install procedure.
>
> For 2.0, I am hesitant to do that, though I do not have a problem with a
> README like this as a heads-up to prepare packagers for the future. I
> say hesitant because people may have been test-packaging 2.0.0-rc3 in
> preparation for release, and it will be annoying to them to suddenly
> switch.

I share the latter two of the above three.  I was giving distro
packagers a bit more credit for their diligence in knowing what they
are packaging than you seem to be in your first point, but I admit
that it is a blind faith.

> But that being said, this is Felipe's code. While we have a legal right
> to distribute it in v2.0, if he would really prefer it out for v2.0, I
> would respect that.

I am fine with that.

> I would prefer to instrument the code with warnings, as that is the sort
> of thing a packager moving from -rc3 to -final might not notice, and
> shipping the warnings to end users who did not package the software in
> the first place will not help them. It is the attention of the packagers
> (and source-builders) you want to get.

I do agree that a new warning every time it is run will be a more
likely to grab users' attention.  The conclusion I draw from that
shared observation is that the user will be annoyed all the time,
without having a power to do anything about the annoyance, until the
report s/he (or other users) Throw at the packager, even when the
version that was packaged hasn't diverged that much yet, which does
not help end users.

I guess the ideal we want is to make sure their build break.  What
if we do the README in addition to rename contrib/remote-helpers to
contrib/obsolete-remote-helpers (or s/obsolete/graduated/)?  It will
give the packagers three choices and I think it hurts people much
less.

 * The packagers that dump the entirety of contrib/ to somewhere
   without doing anything to expose the scripts to user's PATH do
   not have to do anything.  The users who chose to pick them up
   from there notice the missing contrib/remote-helpers, notice
   "obsolete" (or "graduated"), and read README.

 * The packagers that pick up from contrib/remote-helpers and
   arrange the scripts to be on user's PATH will find their build
   broken, because they are no longer where they expect them to be.
   They will notice "obsolete"(or "graduated"), and read README.

   - They can choose to pick them up from "obsolete", perhaps for
 expediency, perhaps for their change aversion, but that will
 not last once we grabbed their attention, and they will switch
 their upstream in some later release once such a choice makes
 them feel dirty enough.

   - They can choose to switch their upstream right now in response
 to the breakage.

I would say that the options I see are these three, and I would rank
the "warn every time" as less helpful to end-users:

 - rename contrib/remote-helpers to contrib/obsolete-remote-helpers
   and add README to point at the upstream.

 - remove contrib/remote-helpers scripts and add README.

 - warn every time the user runs the scripts.

Or am I reacting to a typo and you meant to say "I would prefer not
to instrument"?  Your "shipping the warnings to end users who did
not package the software will not help" was unclear if you meant the
README that has warning or warning message they have to see every
time from the instrumented code.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 01/44] refs.c: constify the sha arguments for ref_transaction_create|delete|update

2014-05-16 Thread Ronnie Sahlberg
ref_transaction_create|delete|update has no need to modify the sha1
arguments passed to it so it should use const unsigned char* instead
of unsigned char*.

Some functions, such as fast_forward_to(), already have its old/new
sha1 arguments as consts. This function will at some point need to
use ref_transaction_update() in which case this change is required.

Reviewed-by: Jonathan Nieder 
Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 7 ---
 refs.h | 7 ---
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/refs.c b/refs.c
index 48573e3..3b7e604 100644
--- a/refs.c
+++ b/refs.c
@@ -,7 +,8 @@ static struct ref_update *add_update(struct 
ref_transaction *transaction,
 
 void ref_transaction_update(struct ref_transaction *transaction,
const char *refname,
-   unsigned char *new_sha1, unsigned char *old_sha1,
+   const unsigned char *new_sha1,
+   const unsigned char *old_sha1,
int flags, int have_old)
 {
struct ref_update *update = add_update(transaction, refname);
@@ -3347,7 +3348,7 @@ void ref_transaction_update(struct ref_transaction 
*transaction,
 
 void ref_transaction_create(struct ref_transaction *transaction,
const char *refname,
-   unsigned char *new_sha1,
+   const unsigned char *new_sha1,
int flags)
 {
struct ref_update *update = add_update(transaction, refname);
@@ -3361,7 +3362,7 @@ void ref_transaction_create(struct ref_transaction 
*transaction,
 
 void ref_transaction_delete(struct ref_transaction *transaction,
const char *refname,
-   unsigned char *old_sha1,
+   const unsigned char *old_sha1,
int flags, int have_old)
 {
struct ref_update *update = add_update(transaction, refname);
diff --git a/refs.h b/refs.h
index a07a5d0..50ca06a 100644
--- a/refs.h
+++ b/refs.h
@@ -238,7 +238,8 @@ struct ref_transaction *ref_transaction_begin(void);
  */
 void ref_transaction_update(struct ref_transaction *transaction,
const char *refname,
-   unsigned char *new_sha1, unsigned char *old_sha1,
+   const unsigned char *new_sha1,
+   const unsigned char *old_sha1,
int flags, int have_old);
 
 /*
@@ -249,7 +250,7 @@ void ref_transaction_update(struct ref_transaction 
*transaction,
  */
 void ref_transaction_create(struct ref_transaction *transaction,
const char *refname,
-   unsigned char *new_sha1,
+   const unsigned char *new_sha1,
int flags);
 
 /*
@@ -259,7 +260,7 @@ void ref_transaction_create(struct ref_transaction 
*transaction,
  */
 void ref_transaction_delete(struct ref_transaction *transaction,
const char *refname,
-   unsigned char *old_sha1,
+   const unsigned char *old_sha1,
int flags, int have_old);
 
 /*
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 11/44] refs.c: change ref_transaction_create to do error checking and return status

2014-05-16 Thread Ronnie Sahlberg
Do basic error checking in ref_transaction_create() and make it return
non-zero on error. Update all callers to check the result of
ref_transaction_create(). There are currently no conditions in _create that
will return error but there will be in the future. Add an err argument that
will be updated on failure.

Signed-off-by: Ronnie Sahlberg 
---
 builtin/update-ref.c |  4 +++-
 refs.c   | 18 --
 refs.h   | 12 
 3 files changed, 23 insertions(+), 11 deletions(-)

diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 9f328b2..e9c216e 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -226,7 +226,9 @@ static const char *parse_cmd_create(struct strbuf *input, 
const char *next)
if (*next != line_termination)
die("create %s: extra input: %s", refname, next);
 
-   ref_transaction_create(transaction, refname, new_sha1, update_flags);
+   if (ref_transaction_create(transaction, refname, new_sha1,
+  update_flags, NULL))
+   die("cannot create ref '%s'", refname);
 
update_flags = 0;
free(refname);
diff --git a/refs.c b/refs.c
index a4fdfc7..06a4fed 100644
--- a/refs.c
+++ b/refs.c
@@ -3397,18 +3397,24 @@ int ref_transaction_update(struct ref_transaction 
*transaction,
return 0;
 }
 
-void ref_transaction_create(struct ref_transaction *transaction,
-   const char *refname,
-   const unsigned char *new_sha1,
-   int flags)
+int ref_transaction_create(struct ref_transaction *transaction,
+  const char *refname,
+  const unsigned char *new_sha1,
+  int flags,
+  struct strbuf *err)
 {
-   struct ref_update *update = add_update(transaction, refname);
+   struct ref_update *update;
+
+   if (!new_sha1 || is_null_sha1(new_sha1))
+   die("BUG: create ref with null new_sha1");
+
+   update = add_update(transaction, refname);
 
-   assert(!is_null_sha1(new_sha1));
hashcpy(update->new_sha1, new_sha1);
hashclr(update->old_sha1);
update->flags = flags;
update->have_old = 1;
+   return 0;
 }
 
 void ref_transaction_delete(struct ref_transaction *transaction,
diff --git a/refs.h b/refs.h
index 454871a..bcae348 100644
--- a/refs.h
+++ b/refs.h
@@ -251,11 +251,15 @@ int ref_transaction_update(struct ref_transaction 
*transaction,
  * that the reference should have after the update; it must not be the
  * null SHA-1.  It is verified that the reference does not exist
  * already.
+ * Function returns 0 on success and non-zero on failure. A failure to create
+ * means that the transaction as a whole has failed and will need to be
+ * rolled back. On failure the err buffer will be updated.
  */
-void ref_transaction_create(struct ref_transaction *transaction,
-   const char *refname,
-   const unsigned char *new_sha1,
-   int flags);
+int ref_transaction_create(struct ref_transaction *transaction,
+  const char *refname,
+  const unsigned char *new_sha1,
+  int flags,
+  struct strbuf *err);
 
 /*
  * Add a reference deletion to transaction.  If have_old is true, then
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 37/44] refs.c: pass NULL as *flags to read_ref_full

2014-05-16 Thread Ronnie Sahlberg
We call read_ref_full with a pointer to flags from rename_ref but since
we never actually use the returned flags we can just pass NULL here instead.

Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/refs.c b/refs.c
index 98f3c85..1210345 100644
--- a/refs.c
+++ b/refs.c
@@ -2640,7 +2640,7 @@ int rename_ref(const char *oldrefname, const char 
*newrefname, const char *logms
goto rollback;
}
 
-   if (!read_ref_full(newrefname, sha1, 1, &flag) &&
+   if (!read_ref_full(newrefname, sha1, 1, NULL) &&
delete_ref(newrefname, sha1, REF_NODEREF)) {
if (errno==EISDIR) {
if (remove_empty_directories(git_path("%s", 
newrefname))) {
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 30/44] refs.c: add transaction.status and track OPEN/CLOSED/ERROR

2014-05-16 Thread Ronnie Sahlberg
Track the status of a transaction in a new status field. Check the field for
sanity, i.e. that status must be OPEN when _commit/_create/_delete or
_update is called or else die(BUG:...)

Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 26 +-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/refs.c b/refs.c
index 2d9789f..4f7ae92 100644
--- a/refs.c
+++ b/refs.c
@@ -3336,6 +3336,12 @@ struct ref_update {
const char refname[FLEX_ARRAY];
 };
 
+enum ref_transaction_status {
+   REF_TRANSACTION_OPEN   = 0,
+   REF_TRANSACTION_CLOSED = 1,
+   REF_TRANSACTION_ERROR  = 2,
+};
+
 /*
  * Data structure for holding a reference transaction, which can
  * consist of checks and updates to multiple references, carried out
@@ -3345,6 +3351,7 @@ struct ref_transaction {
struct ref_update **updates;
size_t alloc;
size_t nr;
+   enum ref_transaction_status status;
 };
 
 struct ref_transaction *ref_transaction_begin(void)
@@ -3390,6 +3397,9 @@ int ref_transaction_update(struct ref_transaction 
*transaction,
if (have_old && !old_sha1)
die("BUG: have_old is true but old_sha1 is NULL");
 
+   if (transaction->status != REF_TRANSACTION_OPEN)
+   die("BUG: update on transaction that is not open");
+
update = add_update(transaction, refname);
hashcpy(update->new_sha1, new_sha1);
update->flags = flags;
@@ -3410,6 +3420,9 @@ int ref_transaction_create(struct ref_transaction 
*transaction,
if (!new_sha1 || is_null_sha1(new_sha1))
die("BUG: create ref with null new_sha1");
 
+   if (transaction->status != REF_TRANSACTION_OPEN)
+   die("BUG: create on transaction that is not open");
+
update = add_update(transaction, refname);
 
hashcpy(update->new_sha1, new_sha1);
@@ -3430,6 +3443,9 @@ int ref_transaction_delete(struct ref_transaction 
*transaction,
if (have_old && !old_sha1)
die("BUG: have_old is true but old_sha1 is NULL");
 
+   if (transaction->status != REF_TRANSACTION_OPEN)
+   die("BUG: delete on transaction that is not open");
+
update = add_update(transaction, refname);
update->flags = flags;
update->have_old = have_old;
@@ -3500,8 +3516,13 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
int n = transaction->nr;
struct ref_update **updates = transaction->updates;
 
-   if (!n)
+   if (transaction->status != REF_TRANSACTION_OPEN)
+   die("BUG: commit on transaction that is not open");
+
+   if (!n) {
+   transaction->status = REF_TRANSACTION_CLOSED;
return 0;
+   }
 
/* Allocate work space */
delnames = xmalloc(sizeof(*delnames) * n);
@@ -3564,6 +3585,9 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
clear_loose_ref_cache(&ref_cache);
 
 cleanup:
+   transaction->status = ret ? REF_TRANSACTION_ERROR
+ : REF_TRANSACTION_CLOSED;
+
for (i = 0; i < n; i++)
if (updates[i]->lock)
unlock_ref(updates[i]->lock);
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 14/44] replace.c: use the ref transaction functions for updates

2014-05-16 Thread Ronnie Sahlberg
Update replace.c to use ref transactions for updates.

Signed-off-by: Ronnie Sahlberg 
---
 builtin/replace.c | 14 --
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/builtin/replace.c b/builtin/replace.c
index 3da1bae..e8932cd 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -133,7 +133,8 @@ static int replace_object_sha1(const char *object_ref,
unsigned char prev[20];
enum object_type obj_type, repl_type;
char ref[PATH_MAX];
-   struct ref_lock *lock;
+   struct ref_transaction *transaction;
+   struct strbuf err = STRBUF_INIT;
 
if (snprintf(ref, sizeof(ref),
 "refs/replace/%s",
@@ -156,11 +157,12 @@ static int replace_object_sha1(const char *object_ref,
else if (!force)
die("replace ref '%s' already exists", ref);
 
-   lock = lock_any_ref_for_update(ref, prev, 0, NULL);
-   if (!lock)
-   die("%s: cannot lock the ref", ref);
-   if (write_ref_sha1(lock, repl, NULL) < 0)
-   die("%s: cannot update the ref", ref);
+   transaction = ref_transaction_begin();
+   if (!transaction ||
+   ref_transaction_update(transaction, ref, repl, prev,
+  0, !is_null_sha1(prev), &err) ||
+   ref_transaction_commit(transaction, NULL, &err))
+   die("%s", err.buf);
 
return 0;
 }
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 22/44] fetch.c: clear errno before calling functions that might set it

2014-05-16 Thread Ronnie Sahlberg
In s_update_ref there are two calls that when they fail we return an error
based on the errno value. In particular we want to return a specific error
if ENOTDIR happened. Both these functions do have failure modes where they
may return an error without updating errno, in which case a previous and
unrelated ENOTDIR may cause us to return the wrong error. Clear errno before
calling any functions if we check errno afterwards.

Also skip initializing a static variable to 0. Statics live in .bss and
are all automatically initialized to 0.

Signed-off-by: Ronnie Sahlberg 
---
 builtin/fetch.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 55f457c..a93c893 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -44,7 +44,7 @@ static struct transport *gtransport;
 static struct transport *gsecondary;
 static const char *submodule_prefix = "";
 static const char *recurse_submodules_default;
-static int shown_url = 0;
+static int shown_url;
 
 static int option_parse_recurse_submodules(const struct option *opt,
   const char *arg, int unset)
@@ -382,6 +382,8 @@ static int s_update_ref(const char *action,
if (!rla)
rla = default_rla.buf;
snprintf(msg, sizeof(msg), "%s: %s", rla, action);
+
+   errno = 0;
lock = lock_any_ref_for_update(ref->name,
   check_old ? ref->old_sha1 : NULL,
   0, NULL);
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 03/44] refs.c: add a strbuf argument to ref_transaction_commit for error logging

2014-05-16 Thread Ronnie Sahlberg
Add a strbuf argument to _commit so that we can pass an error string back to
the caller. So that we can do error logging from the caller instead of from
_commit.

Longer term plan is to first convert all callers to use onerr==QUIET_ON_ERR
and craft any log messages from the callers themselves and finally remove the
onerr argument completely.

Reviewed-by: Jonathan Nieder 
Signed-off-by: Ronnie Sahlberg 
---
 builtin/update-ref.c | 2 +-
 refs.c   | 6 +-
 refs.h   | 5 -
 3 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 405267f..aaa06aa 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -367,7 +367,7 @@ int cmd_update_ref(int argc, const char **argv, const char 
*prefix)
if (end_null)
line_termination = '\0';
update_refs_stdin();
-   ret = ref_transaction_commit(transaction, msg,
+   ret = ref_transaction_commit(transaction, msg, NULL,
 UPDATE_REFS_DIE_ON_ERR);
return ret;
}
diff --git a/refs.c b/refs.c
index 6357089..686b802 100644
--- a/refs.c
+++ b/refs.c
@@ -3418,7 +3418,8 @@ static int ref_update_reject_duplicates(struct ref_update 
**updates, int n,
 }
 
 int ref_transaction_commit(struct ref_transaction *transaction,
-  const char *msg, enum action_on_err onerr)
+  const char *msg, struct strbuf *err,
+  enum action_on_err onerr)
 {
int ret = 0, delnum = 0, i;
const char **delnames;
@@ -3447,6 +3448,9 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
   update->flags,
   &update->type, onerr);
if (!update->lock) {
+   if (err)
+   strbuf_addf(err, "Cannot lock the ref '%s'.",
+   update->refname);
ret = 1;
goto cleanup;
}
diff --git a/refs.h b/refs.h
index 50ca06a..8669fc9 100644
--- a/refs.h
+++ b/refs.h
@@ -267,9 +267,12 @@ void ref_transaction_delete(struct ref_transaction 
*transaction,
  * Commit all of the changes that have been queued in transaction, as
  * atomically as possible.  Return a nonzero value if there is a
  * problem.  The ref_transaction is freed by this function.
+ * If err is non-NULL we will add an error string to it to explain why
+ * the transaction failed. The string does not end in newline.
  */
 int ref_transaction_commit(struct ref_transaction *transaction,
-  const char *msg, enum action_on_err onerr);
+  const char *msg, struct strbuf *err,
+  enum action_on_err onerr);
 
 /*
  * Free an existing transaction and all associated data.
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 02/44] refs.c: allow passing NULL to ref_transaction_free

2014-05-16 Thread Ronnie Sahlberg
Allow ref_transaction_free(NULL) and hence ref_transaction_rollback(NULL)
as no-ops. This makes ref_transaction_rollback easier to use and more similar
to plain 'free'.

In particular, it lets us rollback unconditionally as part of cleanup code
after setting 'transaction = NULL' if a transaction has been committed or
rolled back already.

This allows us to write code like
  if ( (!transaction ||
ref_transaction_update(...))  ||
  (ref_transaction_commit(...) && !(transaction = NULL)) {
  ref_transaction_rollback(transaction);
  ...
  }

Reviewed-by: Jonathan Nieder 
Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/refs.c b/refs.c
index 3b7e604..6357089 100644
--- a/refs.c
+++ b/refs.c
@@ -3312,6 +3312,9 @@ void ref_transaction_free(struct ref_transaction 
*transaction)
 {
int i;
 
+   if (!transaction)
+   return;
+
for (i = 0; i < transaction->nr; i++)
free(transaction->updates[i]);
 
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 34/44] refs.c: make prune_ref use a transaction to delete the ref

2014-05-16 Thread Ronnie Sahlberg
Change prune_ref to delete the ref using a ref transaction. To do this we also
need to add a new flag REF_ISPRUNING that will tell the transaction that we
do not want to delete this ref from the packed refs. This flag is private to
refs.c and not exposed to external callers.

Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 27 ---
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/refs.c b/refs.c
index 69623e4..3a5f1e5 100644
--- a/refs.c
+++ b/refs.c
@@ -29,6 +29,11 @@ static inline int bad_ref_char(int ch)
return 0;
 }
 
+/** Used as a flag to ref_transaction_delete when a loose ref is being
+ *  pruned.
+ */
+#define REF_ISPRUNING  0x0100
+
 /*
  * Try to read one refname component from the front of refname.  Return
  * the length of the component found, or -1 if the component is not
@@ -2330,17 +2335,24 @@ static void try_remove_empty_parents(char *name)
 /* make sure nobody touched the ref, and unlink */
 static void prune_ref(struct ref_to_prune *r)
 {
-   struct ref_lock *lock;
+   struct ref_transaction *transaction;
+   struct strbuf err = STRBUF_INIT;
 
if (check_refname_format(r->name + 5, 0))
return;
 
-   lock = lock_ref_sha1_basic(r->name, r->sha1, 0, NULL);
-   if (lock) {
-   unlink_or_warn(git_path("%s", r->name));
-   unlock_ref(lock);
-   try_remove_empty_parents(r->name);
+   transaction = ref_transaction_begin();
+   if (!transaction ||
+   ref_transaction_delete(transaction, r->name, r->sha1,
+  REF_ISPRUNING, 1, &err) ||
+   ref_transaction_commit(transaction, NULL, &err)) {
+   ref_transaction_free(transaction);
+   warning("prune_ref: %s", err.buf);
+   strbuf_release(&err);
+   return;
}
+   ref_transaction_free(transaction);
+   try_remove_empty_parents(r->name);
 }
 
 static void prune_refs(struct ref_to_prune *r)
@@ -3533,9 +3545,10 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
struct ref_update *update = updates[i];
 
if (update->lock) {
-   delnames[delnum++] = update->lock->ref_name;
ret |= delete_ref_loose(update->lock, update->type,
err);
+   if (!(update->flags & REF_ISPRUNING))
+   delnames[delnum++] = update->lock->ref_name;
}
}
 
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 20/44] refs.c: free the transaction before returning when number of updates is 0

2014-05-16 Thread Ronnie Sahlberg
We have to free the transaction before returning in the early check for
'return early if number of updates == 0' or else the following code would
create a memory leak with the transaction never being freed :
   t = ref_transaction_begin()
   ref_transaction_commit(t)

Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/refs.c b/refs.c
index 78312b5..2c3f070 100644
--- a/refs.c
+++ b/refs.c
@@ -3497,8 +3497,10 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
int n = transaction->nr;
struct ref_update **updates = transaction->updates;
 
-   if (!n)
+   if (!n) {
+   ref_transaction_free(transaction);
return 0;
+   }
 
/* Allocate work space */
delnames = xmalloc(sizeof(*delnames) * n);
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 05/44] refs.c: make ref_update_reject_duplicates take a strbuf argument for errors

2014-05-16 Thread Ronnie Sahlberg
Make ref_update_reject_duplicates return any error that occurs through a
new strbuf argument. This means that when a transaction commit fails in
this function we will now be able to pass a helpful error message back to the
caller.

Reviewed-by: Jonathan Nieder 
Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/refs.c b/refs.c
index a470e51..57ec72a 100644
--- a/refs.c
+++ b/refs.c
@@ -3410,6 +3410,7 @@ static int ref_update_compare(const void *r1, const void 
*r2)
 }
 
 static int ref_update_reject_duplicates(struct ref_update **updates, int n,
+   struct strbuf *err,
enum action_on_err onerr)
 {
int i;
@@ -3417,6 +3418,9 @@ static int ref_update_reject_duplicates(struct ref_update 
**updates, int n,
if (!strcmp(updates[i - 1]->refname, updates[i]->refname)) {
const char *str =
"Multiple updates for ref '%s' not allowed.";
+   if (err)
+   strbuf_addf(err, str, updates[i]->refname);
+
switch (onerr) {
case UPDATE_REFS_MSG_ON_ERR:
error(str, updates[i]->refname); break;
@@ -3447,7 +3451,7 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
 
/* Copy, sort, and reject duplicate refs */
qsort(updates, n, sizeof(*updates), ref_update_compare);
-   ret = ref_update_reject_duplicates(updates, n, onerr);
+   ret = ref_update_reject_duplicates(updates, n, err, onerr);
if (ret)
goto cleanup;
 
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 28/44] refs.c: make write_ref_sha1 static

2014-05-16 Thread Ronnie Sahlberg
No external users call write_ref_sha1 any more so lets declare it static.

Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 4 +++-
 refs.h | 3 ---
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/refs.c b/refs.c
index 266a792..93e2cd2 100644
--- a/refs.c
+++ b/refs.c
@@ -251,6 +251,8 @@ struct ref_entry {
 };
 
 static void read_loose_refs(const char *dirname, struct ref_dir *dir);
+static int write_ref_sha1(struct ref_lock *lock,
+ const unsigned char *sha1, const char *logmsg);
 
 static struct ref_dir *get_ref_dir(struct ref_entry *entry)
 {
@@ -2833,7 +2835,7 @@ static int is_branch(const char *refname)
return !strcmp(refname, "HEAD") || starts_with(refname, "refs/heads/");
 }
 
-int write_ref_sha1(struct ref_lock *lock,
+static int write_ref_sha1(struct ref_lock *lock,
const unsigned char *sha1, const char *logmsg)
 {
static char term = '\n';
diff --git a/refs.h b/refs.h
index e0f5f67..0c4d043 100644
--- a/refs.h
+++ b/refs.h
@@ -150,9 +150,6 @@ extern int commit_ref(struct ref_lock *lock);
 /** Release any lock taken but not written. **/
 extern void unlock_ref(struct ref_lock *lock);
 
-/** Writes sha1 into the ref specified by the lock. **/
-extern int write_ref_sha1(struct ref_lock *lock, const unsigned char *sha1, 
const char *msg);
-
 /** Setup reflog before using. **/
 int log_ref_setup(const char *refname, char *logfile, int bufsize);
 
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 12/44] refs.c: ref_transaction_delete to check for error and return status

2014-05-16 Thread Ronnie Sahlberg
Change ref_transaction_delete() to do basic error checking and return
non-zero of error. Update all callers to check the return for
ref_transaction_delete(). There are currently no conditions in _delete that
will return error but there will be in the future. Add an err argument that
will be updated on failure.

Signed-off-by: Ronnie Sahlberg 
---
 builtin/update-ref.c |  5 +++--
 refs.c   | 16 +++-
 refs.h   | 12 
 3 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index e9c216e..cdb71a8 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -258,8 +258,9 @@ static const char *parse_cmd_delete(struct strbuf *input, 
const char *next)
if (*next != line_termination)
die("delete %s: extra input: %s", refname, next);
 
-   ref_transaction_delete(transaction, refname, old_sha1,
-  update_flags, have_old);
+   if (ref_transaction_delete(transaction, refname, old_sha1,
+  update_flags, have_old, NULL))
+   die("failed transaction delete for %s", refname);
 
update_flags = 0;
free(refname);
diff --git a/refs.c b/refs.c
index 06a4fed..a588194 100644
--- a/refs.c
+++ b/refs.c
@@ -3417,19 +3417,25 @@ int ref_transaction_create(struct ref_transaction 
*transaction,
return 0;
 }
 
-void ref_transaction_delete(struct ref_transaction *transaction,
-   const char *refname,
-   const unsigned char *old_sha1,
-   int flags, int have_old)
+int ref_transaction_delete(struct ref_transaction *transaction,
+  const char *refname,
+  const unsigned char *old_sha1,
+  int flags, int have_old,
+  struct strbuf *err)
 {
-   struct ref_update *update = add_update(transaction, refname);
+   struct ref_update *update;
 
+   if (have_old && !old_sha1)
+   die("BUG: have_old is true but old_sha1 is NULL");
+
+   update = add_update(transaction, refname);
update->flags = flags;
update->have_old = have_old;
if (have_old) {
assert(!is_null_sha1(old_sha1));
hashcpy(update->old_sha1, old_sha1);
}
+   return 0;
 }
 
 int update_ref(const char *action, const char *refname,
diff --git a/refs.h b/refs.h
index bcae348..9b978da 100644
--- a/refs.h
+++ b/refs.h
@@ -265,11 +265,15 @@ int ref_transaction_create(struct ref_transaction 
*transaction,
  * Add a reference deletion to transaction.  If have_old is true, then
  * old_sha1 holds the value that the reference should have had before
  * the update (which must not be the null SHA-1).
+ * Function returns 0 on success and non-zero on failure. A failure to delete
+ * means that the transaction as a whole has failed and will need to be
+ * rolled back. On failure the err buffer will be updated.
  */
-void ref_transaction_delete(struct ref_transaction *transaction,
-   const char *refname,
-   const unsigned char *old_sha1,
-   int flags, int have_old);
+int ref_transaction_delete(struct ref_transaction *transaction,
+  const char *refname,
+  const unsigned char *old_sha1,
+  int flags, int have_old,
+  struct strbuf *err);
 
 /*
  * Commit all of the changes that have been queued in transaction, as
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 10/44] refs.c: change ref_transaction_update() to do error checking and return status

2014-05-16 Thread Ronnie Sahlberg
Update ref_transaction_update() do some basic error checking and return
non-zero on error. Update all callers to check ref_transaction_update() for
error. There are currently no conditions in _update that will return error but
there will be in the future. Add an err argument that will be updated on
failure.

Also check for BUGs during update and die(BUG:...) if we are calling
_update with have_old but the old_sha1 pointer is NULL.

Signed-off-by: Ronnie Sahlberg 
---
 builtin/update-ref.c | 12 +++-
 refs.c   | 18 --
 refs.h   | 14 +-
 3 files changed, 28 insertions(+), 16 deletions(-)

diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 2bef2a0..9f328b2 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -16,6 +16,7 @@ static struct ref_transaction *transaction;
 
 static char line_termination = '\n';
 static int update_flags;
+static struct strbuf err = STRBUF_INIT;
 
 /*
  * Parse one whitespace- or NUL-terminated, possibly C-quoted argument
@@ -197,8 +198,9 @@ static const char *parse_cmd_update(struct strbuf *input, 
const char *next)
if (*next != line_termination)
die("update %s: extra input: %s", refname, next);
 
-   ref_transaction_update(transaction, refname, new_sha1, old_sha1,
-  update_flags, have_old);
+   if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
+  update_flags, have_old, &err))
+   die("update %s: failed: %s", refname, err.buf);
 
update_flags = 0;
free(refname);
@@ -286,8 +288,9 @@ static const char *parse_cmd_verify(struct strbuf *input, 
const char *next)
if (*next != line_termination)
die("verify %s: extra input: %s", refname, next);
 
-   ref_transaction_update(transaction, refname, new_sha1, old_sha1,
-  update_flags, have_old);
+   if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
+  update_flags, have_old, &err))
+   die("verify %s: %s", refname, err.buf);
 
update_flags = 0;
free(refname);
@@ -342,7 +345,6 @@ int cmd_update_ref(int argc, const char **argv, const char 
*prefix)
const char *refname, *oldval, *msg = NULL;
unsigned char sha1[20], oldsha1[20];
int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0, flags = 0;
-   struct strbuf err = STRBUF_INIT;
struct option options[] = {
OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the 
update")),
OPT_BOOL('d', NULL, &delete, N_("delete the reference")),
diff --git a/refs.c b/refs.c
index 29cfe78..a4fdfc7 100644
--- a/refs.c
+++ b/refs.c
@@ -3376,19 +3376,25 @@ static struct ref_update *add_update(struct 
ref_transaction *transaction,
return update;
 }
 
-void ref_transaction_update(struct ref_transaction *transaction,
-   const char *refname,
-   const unsigned char *new_sha1,
-   const unsigned char *old_sha1,
-   int flags, int have_old)
+int ref_transaction_update(struct ref_transaction *transaction,
+  const char *refname,
+  const unsigned char *new_sha1,
+  const unsigned char *old_sha1,
+  int flags, int have_old,
+  struct strbuf *err)
 {
-   struct ref_update *update = add_update(transaction, refname);
+   struct ref_update *update;
+
+   if (have_old && !old_sha1)
+   die("BUG: have_old is true but old_sha1 is NULL");
 
+   update = add_update(transaction, refname);
hashcpy(update->new_sha1, new_sha1);
update->flags = flags;
update->have_old = have_old;
if (have_old)
hashcpy(update->old_sha1, old_sha1);
+   return 0;
 }
 
 void ref_transaction_create(struct ref_transaction *transaction,
diff --git a/refs.h b/refs.h
index 05e65fa..454871a 100644
--- a/refs.h
+++ b/refs.h
@@ -235,12 +235,16 @@ struct ref_transaction *ref_transaction_begin(void);
  * be deleted.  If have_old is true, then old_sha1 holds the value
  * that the reference should have had before the update, or zeros if
  * it must not have existed beforehand.
+ * Function returns 0 on success and non-zero on failure. A failure to update
+ * means that the transaction as a whole has failed and will need to be
+ * rolled back. On failure the err buffer will be updated.
  */
-void ref_transaction_update(struct ref_transaction *transaction,
-   const char *refname,
-   const unsigned char *new_sha1,
-   const unsigned char *old_sha1,
-   int flags, int have_old);
+int ref_transaction_update(struct ref_transaction *transaction,
+   

[PATCH v10 24/44] fetch.c: use a single ref transaction for all ref updates

2014-05-16 Thread Ronnie Sahlberg
Change store_updated_refs to use a single ref transaction for all refs that
are updated during the fetch. This makes the fetch more atomic when update
failures occur.

Since ref update failures will now no longer occur in the code path for
updating a single ref in s_update_ref, we no longer have as detailed error
message logging the exact reference and the ref log action as in the old cod
Instead since we fail the entire transaction we log a much more generic
message. But since we commit the transaction using MSG_ON_ERR we will log
an error containing the ref name if either locking of writing the ref would
so the regression in the log message is minor.

This will also change the order in which errors are checked for and logged
which may alter which error will be logged if there are multiple errors
occuring during a fetch.

For example, assume we have a fetch for two refs that both would fail.
Where the first ref would fail with ENOTDIR due to a directory in the ref
path not existing, and the second ref in the fetch would fail due to
the check in update_logical_ref():
if (current_branch &&
!strcmp(ref->name, current_branch->name) &&
!(update_head_ok || is_bare_repository()) &&
!is_null_sha1(ref->old_sha1)) {
/*
 * If this is the head, and it's not okay to update
 * the head, and the old value of the head isn't empty...
 */

In the old code since we would update the refs one ref at a time we would
first fail the ENOTDIR and then fail the second update of HEAD as well.
But since the first ref failed with ENOTDIR we would eventually fail the who
fetch with STORE_REF_ERROR_DF_CONFLICT

In the new code, since we defer committing the transaction until all refs
have been processed, we would now detect that the second ref was bad and
rollback the transaction before we would even try start writing the update t
disk and thus we would not return STORE_REF_ERROR_DF_CONFLICT for this case.

I think this new behaviour is more correct, since if there was a problem
we would not even try to commit the transaction but need to highlight this
change in how/what errors are reported.
This change in what error is returned only occurs if there are multiple
refs that fail to update and only some, but not all, of them fail due to
ENOTDIR.

Signed-off-by: Ronnie Sahlberg 
---
 builtin/fetch.c | 34 --
 1 file changed, 16 insertions(+), 18 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 8cf70cd..5b0cc31 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -45,6 +45,7 @@ static struct transport *gsecondary;
 static const char *submodule_prefix = "";
 static const char *recurse_submodules_default;
 static int shown_url;
+static struct ref_transaction *transaction;
 
 static int option_parse_recurse_submodules(const struct option *opt,
   const char *arg, int unset)
@@ -373,27 +374,13 @@ static int s_update_ref(const char *action,
struct ref *ref,
int check_old)
 {
-   char msg[1024];
-   char *rla = getenv("GIT_REFLOG_ACTION");
-   struct ref_transaction *transaction;
-
if (dry_run)
return 0;
-   if (!rla)
-   rla = default_rla.buf;
-   snprintf(msg, sizeof(msg), "%s: %s", rla, action);
 
-   errno = 0;
-   transaction = ref_transaction_begin();
-   if (!transaction ||
-   ref_transaction_update(transaction, ref->name, ref->new_sha1,
-  ref->old_sha1, 0, check_old, NULL) ||
-   ref_transaction_commit(transaction, msg, NULL)) {
-   ref_transaction_free(transaction);
-   return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
- STORE_REF_ERROR_OTHER;
-   }
-   ref_transaction_free(transaction);
+   if (ref_transaction_update(transaction, ref->name, ref->new_sha1,
+  ref->old_sha1, 0, check_old, NULL))
+   return STORE_REF_ERROR_OTHER;
+
return 0;
 }
 
@@ -565,6 +552,13 @@ static int store_updated_refs(const char *raw_url, const 
char *remote_name,
goto abort;
}
 
+   errno = 0;
+   transaction = ref_transaction_begin();
+   if (!transaction) {
+   rc = error(_("cannot start ref transaction\n"));
+   goto abort;
+   }
+
/*
 * We do a pass for each fetch_head_status type in their enum order, so
 * merged entries are written before not-for-merge. That lets readers
@@ -676,6 +670,10 @@ static int store_updated_refs(const char *raw_url, const 
char *remote_name,
}
}
}
+   if (ref_transaction_commit(transaction, "fetch_ref transaction", NULL))
+   rc |= errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
+ ST

[PATCH v10 08/44] update-ref.c: log transaction error from the update_ref

2014-05-16 Thread Ronnie Sahlberg
Call ref_transaction_commit with QUIET_ON_ERR and use the strbuf that is
returned to print a log message if/after the transaction fails.

Reviewed-by: Jonathan Nieder 
Signed-off-by: Ronnie Sahlberg 
---
 builtin/update-ref.c | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index aaa06aa..207e24d 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -342,6 +342,7 @@ int cmd_update_ref(int argc, const char **argv, const char 
*prefix)
const char *refname, *oldval, *msg = NULL;
unsigned char sha1[20], oldsha1[20];
int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0, flags = 0;
+   struct strbuf err = STRBUF_INIT;
struct option options[] = {
OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the 
update")),
OPT_BOOL('d', NULL, &delete, N_("delete the reference")),
@@ -359,17 +360,16 @@ int cmd_update_ref(int argc, const char **argv, const 
char *prefix)
die("Refusing to perform update with empty message.");
 
if (read_stdin) {
-   int ret;
transaction = ref_transaction_begin();
-
if (delete || no_deref || argc > 0)
usage_with_options(git_update_ref_usage, options);
if (end_null)
line_termination = '\0';
update_refs_stdin();
-   ret = ref_transaction_commit(transaction, msg, NULL,
-UPDATE_REFS_DIE_ON_ERR);
-   return ret;
+   if (ref_transaction_commit(transaction, msg, &err,
+  UPDATE_REFS_QUIET_ON_ERR))
+   die("%s", err.buf);
+   return 0;
}
 
if (end_null)
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 07/44] refs.c: make update_ref_write update a strbuf on failure

2014-05-16 Thread Ronnie Sahlberg
Change update_ref_write to also update an error strbuf on failure.
This makes the error available to ref_transaction_commit callers if the
transaction failed due to update_ref_sha1/write_ref_sha1 failures.

Reviewed-by: Jonathan Nieder 
Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/refs.c b/refs.c
index bc444c7..582c74b 100644
--- a/refs.c
+++ b/refs.c
@@ -3301,10 +3301,13 @@ static struct ref_lock *update_ref_lock(const char 
*refname,
 
 static int update_ref_write(const char *action, const char *refname,
const unsigned char *sha1, struct ref_lock *lock,
-   enum action_on_err onerr)
+   struct strbuf *err, enum action_on_err onerr)
 {
if (write_ref_sha1(lock, sha1, action) < 0) {
const char *str = "Cannot update the ref '%s'.";
+   if (err)
+   strbuf_addf(err, str, refname);
+
switch (onerr) {
case UPDATE_REFS_MSG_ON_ERR: error(str, refname); break;
case UPDATE_REFS_DIE_ON_ERR: die(str, refname); break;
@@ -3425,7 +3428,7 @@ int update_ref(const char *action, const char *refname,
lock = update_ref_lock(refname, oldval, flags, NULL, onerr);
if (!lock)
return 1;
-   return update_ref_write(action, refname, sha1, lock, onerr);
+   return update_ref_write(action, refname, sha1, lock, NULL, onerr);
 }
 
 static int ref_update_compare(const void *r1, const void *r2)
@@ -3507,7 +3510,7 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
ret = update_ref_write(msg,
   update->refname,
   update->new_sha1,
-  update->lock, onerr);
+  update->lock, err, onerr);
update->lock = NULL; /* freed by update_ref_write */
if (ret)
goto cleanup;
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 15/44] commit.c: use ref transactions for updates

2014-05-16 Thread Ronnie Sahlberg
Change commit.c to use ref transactions for all ref updates.
Make sure we pass a NULL pointer to ref_transaction_update if have_old
is false.

Reviewed-by: Jonathan Nieder 
Signed-off-by: Ronnie Sahlberg 
---
 builtin/commit.c | 23 ++-
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index d28505a..c429216 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1581,11 +1581,12 @@ int cmd_commit(int argc, const char **argv, const char 
*prefix)
const char *index_file, *reflog_msg;
char *nl;
unsigned char sha1[20];
-   struct ref_lock *ref_lock;
struct commit_list *parents = NULL, **pptr = &parents;
struct stat statbuf;
struct commit *current_head = NULL;
struct commit_extra_header *extra = NULL;
+   struct ref_transaction *transaction;
+   struct strbuf err = STRBUF_INIT;
 
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(builtin_commit_usage, 
builtin_commit_options);
@@ -1707,16 +1708,6 @@ int cmd_commit(int argc, const char **argv, const char 
*prefix)
strbuf_release(&author_ident);
free_commit_extra_headers(extra);
 
-   ref_lock = lock_any_ref_for_update("HEAD",
-  !current_head
-  ? NULL
-  : current_head->object.sha1,
-  0, NULL);
-   if (!ref_lock) {
-   rollback_index_files();
-   die(_("cannot lock HEAD ref"));
-   }
-
nl = strchr(sb.buf, '\n');
if (nl)
strbuf_setlen(&sb, nl + 1 - sb.buf);
@@ -1725,9 +1716,15 @@ int cmd_commit(int argc, const char **argv, const char 
*prefix)
strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg));
strbuf_insert(&sb, strlen(reflog_msg), ": ", 2);
 
-   if (write_ref_sha1(ref_lock, sha1, sb.buf) < 0) {
+   transaction = ref_transaction_begin();
+   if (!transaction ||
+   ref_transaction_update(transaction, "HEAD", sha1,
+  current_head ?
+  current_head->object.sha1 : NULL,
+  0, !!current_head, &err) ||
+   ref_transaction_commit(transaction, sb.buf, &err)) {
rollback_index_files();
-   die(_("cannot update HEAD ref"));
+   die("%s", err.buf);
}
 
unlink(git_path("CHERRY_PICK_HEAD"));
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 36/44] refs.c: pass the ref log message to _create/delete/update instead of _commit

2014-05-16 Thread Ronnie Sahlberg
Change the reference transactions so that we pass the reflog message
through to the create/delete/update function instead of the commit message.
This allows for individual messages for each change in a multi ref
transaction.

Signed-off-by: Ronnie Sahlberg 
---
 branch.c   |  4 ++--
 builtin/commit.c   |  4 ++--
 builtin/fetch.c| 10 --
 builtin/receive-pack.c |  5 +++--
 builtin/replace.c  |  4 ++--
 builtin/tag.c  |  4 ++--
 builtin/update-ref.c   | 13 +++--
 fast-import.c  |  8 
 refs.c | 31 +--
 refs.h |  5 -
 sequencer.c|  4 ++--
 walker.c   |  6 +++---
 12 files changed, 60 insertions(+), 38 deletions(-)

diff --git a/branch.c b/branch.c
index f78a28b..6dfdc2e 100644
--- a/branch.c
+++ b/branch.c
@@ -301,8 +301,8 @@ void create_branch(const char *head,
transaction = ref_transaction_begin();
if (!transaction ||
ref_transaction_update(transaction, ref.buf, sha1,
-  null_sha1, 0, !forcing, &err) ||
-   ref_transaction_commit(transaction, msg, &err))
+  null_sha1, 0, !forcing, msg, &err) ||
+   ref_transaction_commit(transaction, &err))
die("%s", err.buf);
ref_transaction_free(transaction);
}
diff --git a/builtin/commit.c b/builtin/commit.c
index 6b888f2..b361a13 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1721,8 +1721,8 @@ int cmd_commit(int argc, const char **argv, const char 
*prefix)
ref_transaction_update(transaction, "HEAD", sha1,
   current_head ?
   current_head->object.sha1 : NULL,
-  0, !!current_head, &err) ||
-   ref_transaction_commit(transaction, sb.buf, &err)) {
+  0, !!current_head, sb.buf, &err) ||
+   ref_transaction_commit(transaction, &err)) {
rollback_index_files();
die("%s", err.buf);
}
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 5b0cc31..4603cb6 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -374,11 +374,17 @@ static int s_update_ref(const char *action,
struct ref *ref,
int check_old)
 {
+   char msg[1024];
+   char *rla = getenv("GIT_REFLOG_ACTION");
+
if (dry_run)
return 0;
+   if (!rla)
+   rla = default_rla.buf;
+   snprintf(msg, sizeof(msg), "%s: %s", rla, action);
 
if (ref_transaction_update(transaction, ref->name, ref->new_sha1,
-  ref->old_sha1, 0, check_old, NULL))
+  ref->old_sha1, 0, check_old, msg, NULL))
return STORE_REF_ERROR_OTHER;
 
return 0;
@@ -670,7 +676,7 @@ static int store_updated_refs(const char *raw_url, const 
char *remote_name,
}
}
}
-   if (ref_transaction_commit(transaction, "fetch_ref transaction", NULL))
+   if (ref_transaction_commit(transaction, NULL))
rc |= errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
  STORE_REF_ERROR_OTHER;
ref_transaction_free(transaction);
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 5534138..324a220 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -582,7 +582,8 @@ static const char *update(struct command *cmd, struct 
shallow_info *si)
return "shallow error";
 
if (ref_transaction_update(transaction, namespaced_name,
-  new_sha1, old_sha1, 0, 1, &err))
+  new_sha1, old_sha1, 0, 1, "push",
+  &err))
return "failed to update";
return NULL; /* good */
}
@@ -823,7 +824,7 @@ static void execute_commands(struct command *commands,
checked_connectivity = 0;
}
}
-   if (ref_transaction_commit(transaction, "push", &err))
+   if (ref_transaction_commit(transaction, &err))
error("%s", err.buf);
ref_transaction_free(transaction);
strbuf_release(&err);
diff --git a/builtin/replace.c b/builtin/replace.c
index af7f72d..4fa74c1 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -160,8 +160,8 @@ static int replace_object_sha1(const char *object_ref,
transaction = ref_transaction_begin();
if (!transaction ||
ref_transaction_update(transaction, ref, repl, prev,
-  0, !is_null_sha1(prev), &err) ||
-   ref_transaction_commit(transaction, NULL, &err))
+  

[PATCH v10 29/44] refs.c: make lock_ref_sha1 static

2014-05-16 Thread Ronnie Sahlberg
No external callers reference lock_ref_sha1 any more so lets declare it static.

Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 2 +-
 refs.h | 3 ---
 2 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/refs.c b/refs.c
index 93e2cd2..2d9789f 100644
--- a/refs.c
+++ b/refs.c
@@ -2126,7 +2126,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char 
*refname,
return NULL;
 }
 
-struct ref_lock *lock_ref_sha1(const char *refname, const unsigned char 
*old_sha1)
+static struct ref_lock *lock_ref_sha1(const char *refname, const unsigned char 
*old_sha1)
 {
char refpath[PATH_MAX];
if (check_refname_format(refname, 0))
diff --git a/refs.h b/refs.h
index 0c4d043..90c7fb4 100644
--- a/refs.h
+++ b/refs.h
@@ -132,9 +132,6 @@ extern int ref_exists(const char *);
  */
 extern int peel_ref(const char *refname, unsigned char *sha1);
 
-/** Locks a "refs/" ref returning the lock on success and NULL on failure. **/
-extern struct ref_lock *lock_ref_sha1(const char *refname, const unsigned char 
*old_sha1);
-
 /** Locks any ref (for 'HEAD' type refs). */
 #define REF_NODEREF0x01
 extern struct ref_lock *lock_any_ref_for_update(const char *refname,
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 09/44] refs.c: remove the onerr argument to ref_transaction_commit

2014-05-16 Thread Ronnie Sahlberg
Since all callers now use QUIET_ON_ERR we no longer need to provide an onerr
argument any more. Remove the onerr argument from the ref_transaction_commit
signature.

Reviewed-by: Jonathan Nieder 
Signed-off-by: Ronnie Sahlberg 
---
 builtin/update-ref.c |  3 +--
 refs.c   | 22 +++---
 refs.h   |  3 +--
 3 files changed, 9 insertions(+), 19 deletions(-)

diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 207e24d..2bef2a0 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -366,8 +366,7 @@ int cmd_update_ref(int argc, const char **argv, const char 
*prefix)
if (end_null)
line_termination = '\0';
update_refs_stdin();
-   if (ref_transaction_commit(transaction, msg, &err,
-  UPDATE_REFS_QUIET_ON_ERR))
+   if (ref_transaction_commit(transaction, msg, &err))
die("%s", err.buf);
return 0;
}
diff --git a/refs.c b/refs.c
index 582c74b..29cfe78 100644
--- a/refs.c
+++ b/refs.c
@@ -3439,8 +3439,7 @@ static int ref_update_compare(const void *r1, const void 
*r2)
 }
 
 static int ref_update_reject_duplicates(struct ref_update **updates, int n,
-   struct strbuf *err,
-   enum action_on_err onerr)
+   struct strbuf *err)
 {
int i;
for (i = 1; i < n; i++)
@@ -3450,22 +3449,13 @@ static int ref_update_reject_duplicates(struct 
ref_update **updates, int n,
if (err)
strbuf_addf(err, str, updates[i]->refname);
 
-   switch (onerr) {
-   case UPDATE_REFS_MSG_ON_ERR:
-   error(str, updates[i]->refname); break;
-   case UPDATE_REFS_DIE_ON_ERR:
-   die(str, updates[i]->refname); break;
-   case UPDATE_REFS_QUIET_ON_ERR:
-   break;
-   }
return 1;
}
return 0;
 }
 
 int ref_transaction_commit(struct ref_transaction *transaction,
-  const char *msg, struct strbuf *err,
-  enum action_on_err onerr)
+  const char *msg, struct strbuf *err)
 {
int ret = 0, delnum = 0, i;
const char **delnames;
@@ -3480,7 +3470,7 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
 
/* Copy, sort, and reject duplicate refs */
qsort(updates, n, sizeof(*updates), ref_update_compare);
-   ret = ref_update_reject_duplicates(updates, n, err, onerr);
+   ret = ref_update_reject_duplicates(updates, n, err);
if (ret)
goto cleanup;
 
@@ -3492,7 +3482,8 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
   (update->have_old ?
update->old_sha1 : NULL),
   update->flags,
-  &update->type, onerr);
+  &update->type,
+  UPDATE_REFS_QUIET_ON_ERR);
if (!update->lock) {
if (err)
strbuf_addf(err, "Cannot lock the ref '%s'.",
@@ -3510,7 +3501,8 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
ret = update_ref_write(msg,
   update->refname,
   update->new_sha1,
-  update->lock, err, onerr);
+  update->lock, err,
+  UPDATE_REFS_QUIET_ON_ERR);
update->lock = NULL; /* freed by update_ref_write */
if (ret)
goto cleanup;
diff --git a/refs.h b/refs.h
index 8669fc9..05e65fa 100644
--- a/refs.h
+++ b/refs.h
@@ -271,8 +271,7 @@ void ref_transaction_delete(struct ref_transaction 
*transaction,
  * the transaction failed. The string does not end in newline.
  */
 int ref_transaction_commit(struct ref_transaction *transaction,
-  const char *msg, struct strbuf *err,
-  enum action_on_err onerr);
+  const char *msg, struct strbuf *err);
 
 /*
  * Free an existing transaction and all associated data.
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 04/44] refs.c: add an err argument to repack_without_refs

2014-05-16 Thread Ronnie Sahlberg
Update repack_without_refs to take an err argument and update it if there
is a failure. Pass the err variable from ref_transaction_commit to this
function so that callers can print a meaningful error message if _commit
fails due to a problem in repack_without_refs.

Signed-off-by: Ronnie Sahlberg 
---
 cache.h|  2 ++
 lockfile.c | 21 -
 refs.c | 25 +++--
 3 files changed, 33 insertions(+), 15 deletions(-)

diff --git a/cache.h b/cache.h
index 8c6cdc2..48548d6 100644
--- a/cache.h
+++ b/cache.h
@@ -559,6 +559,8 @@ struct lock_file {
 #define LOCK_DIE_ON_ERROR 1
 #define LOCK_NODEREF 2
 extern int unable_to_lock_error(const char *path, int err);
+extern void unable_to_lock_strbuf(const char *path, int err,
+ struct strbuf *buf);
 extern NORETURN void unable_to_lock_index_die(const char *path, int err);
 extern int hold_lock_file_for_update(struct lock_file *, const char *path, 
int);
 extern int hold_lock_file_for_append(struct lock_file *, const char *path, 
int);
diff --git a/lockfile.c b/lockfile.c
index 8fbcb6a..9e04b43 100644
--- a/lockfile.c
+++ b/lockfile.c
@@ -157,33 +157,36 @@ static int lock_file(struct lock_file *lk, const char 
*path, int flags)
return lk->fd;
 }
 
-static char *unable_to_lock_message(const char *path, int err)
+void unable_to_lock_strbuf(const char *path, int err, struct strbuf *buf)
 {
-   struct strbuf buf = STRBUF_INIT;
 
if (err == EEXIST) {
-   strbuf_addf(&buf, "Unable to create '%s.lock': %s.\n\n"
+   strbuf_addf(buf, "Unable to create '%s.lock': %s.\n\n"
"If no other git process is currently running, this 
probably means a\n"
"git process crashed in this repository earlier. Make sure 
no other git\n"
"process is running and remove the file manually to 
continue.",
absolute_path(path), strerror(err));
} else
-   strbuf_addf(&buf, "Unable to create '%s.lock': %s",
+   strbuf_addf(buf, "Unable to create '%s.lock': %s",
absolute_path(path), strerror(err));
-   return strbuf_detach(&buf, NULL);
 }
 
 int unable_to_lock_error(const char *path, int err)
 {
-   char *msg = unable_to_lock_message(path, err);
-   error("%s", msg);
-   free(msg);
+   struct strbuf buf = STRBUF_INIT;
+
+   unable_to_lock_strbuf(path, err, &buf);
+   error("%s", buf.buf);
+   strbuf_release(&buf);
return -1;
 }
 
 NORETURN void unable_to_lock_index_die(const char *path, int err)
 {
-   die("%s", unable_to_lock_message(path, err));
+   struct strbuf buf = STRBUF_INIT;
+
+   unable_to_lock_strbuf(path, err, &buf);
+   die("%s", buf.buf);
 }
 
 int hold_lock_file_for_update(struct lock_file *lk, const char *path, int 
flags)
diff --git a/refs.c b/refs.c
index 686b802..a470e51 100644
--- a/refs.c
+++ b/refs.c
@@ -2208,6 +2208,7 @@ int commit_packed_refs(void)
struct packed_ref_cache *packed_ref_cache =
get_packed_ref_cache(&ref_cache);
int error = 0;
+   int save_errno;
 
if (!packed_ref_cache->lock)
die("internal error: packed-refs not locked");
@@ -2217,10 +2218,13 @@ int commit_packed_refs(void)
do_for_each_entry_in_dir(get_packed_ref_dir(packed_ref_cache),
 0, write_packed_entry_fn,
 &packed_ref_cache->lock->fd);
-   if (commit_lock_file(packed_ref_cache->lock))
+   if (commit_lock_file(packed_ref_cache->lock)) {
+   save_errno = errno;
error = -1;
+   }
packed_ref_cache->lock = NULL;
release_packed_ref_cache(packed_ref_cache);
+   errno = save_errno;
return error;
 }
 
@@ -2427,12 +2431,12 @@ static int curate_packed_ref_fn(struct ref_entry 
*entry, void *cb_data)
return 0;
 }
 
-static int repack_without_refs(const char **refnames, int n)
+static int repack_without_refs(const char **refnames, int n, struct strbuf 
*err)
 {
struct ref_dir *packed;
struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
struct string_list_item *ref_to_delete;
-   int i, removed = 0;
+   int i, ret, removed = 0;
 
/* Look for a packed ref */
for (i = 0; i < n; i++)
@@ -2444,6 +2448,11 @@ static int repack_without_refs(const char **refnames, 
int n)
return 0; /* no refname exists in packed refs */
 
if (lock_packed_refs(0)) {
+   if (err) {
+   unable_to_lock_strbuf(git_path("packed-refs"), errno,
+ err);
+   return 1;
+   }
unable_to_lock_error(git_path("packed-refs"), errno);
return error("cannot delete '%s' from packed refs", 
refnames[i]);
}
@@ -2470,12 +2479,16 @@ static

[PATCH v10 25/44] receive-pack.c: use a reference transaction for updating the refs

2014-05-16 Thread Ronnie Sahlberg
Wrap all the ref updates inside a transaction to make the update atomic.

Signed-off-by: Ronnie Sahlberg 
---
 builtin/receive-pack.c | 20 ++--
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index c323081..5534138 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -46,6 +46,8 @@ static void *head_name_to_free;
 static int sent_capabilities;
 static int shallow_update;
 static const char *alt_shallow_file;
+static struct strbuf err = STRBUF_INIT;
+static struct ref_transaction *transaction;
 
 static enum deny_action parse_deny_action(const char *var, const char *value)
 {
@@ -475,7 +477,6 @@ static const char *update(struct command *cmd, struct 
shallow_info *si)
const char *namespaced_name;
unsigned char *old_sha1 = cmd->old_sha1;
unsigned char *new_sha1 = cmd->new_sha1;
-   struct ref_lock *lock;
 
/* only refs/... are allowed */
if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) {
@@ -580,15 +581,9 @@ static const char *update(struct command *cmd, struct 
shallow_info *si)
update_shallow_ref(cmd, si))
return "shallow error";
 
-   lock = lock_any_ref_for_update(namespaced_name, old_sha1,
-  0, NULL);
-   if (!lock) {
-   rp_error("failed to lock %s", name);
-   return "failed to lock";
-   }
-   if (write_ref_sha1(lock, new_sha1, "push")) {
-   return "failed to write"; /* error() already called */
-   }
+   if (ref_transaction_update(transaction, namespaced_name,
+  new_sha1, old_sha1, 0, 1, &err))
+   return "failed to update";
return NULL; /* good */
}
 }
@@ -812,6 +807,7 @@ static void execute_commands(struct command *commands,
head_name = head_name_to_free = resolve_refdup("HEAD", sha1, 0, NULL);
 
checked_connectivity = 1;
+   transaction = ref_transaction_begin();
for (cmd = commands; cmd; cmd = cmd->next) {
if (cmd->error_string)
continue;
@@ -827,6 +823,10 @@ static void execute_commands(struct command *commands,
checked_connectivity = 0;
}
}
+   if (ref_transaction_commit(transaction, "push", &err))
+   error("%s", err.buf);
+   ref_transaction_free(transaction);
+   strbuf_release(&err);
 
if (shallow_update && !checked_connectivity)
error("BUG: run 'git fsck' for safety.\n"
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 42/44] refs.c: pass a skip list to name_conflict_fn

2014-05-16 Thread Ronnie Sahlberg
Allow passing a list of refs to skip checking to name_conflict_fn.
There are some conditions where we want to allow a temporary conflict and skip
checking those refs. For example if we have a transaction that
1, guarantees that m is a packed refs and there is no loose ref for m
2, the transaction will delete m from the packed ref
3, the transaction will create conflicting m/m

For this case we want to be able to lock and create m/m since we know that the
conflict is only transient. I.e. the conflict will be automatically resolved
by the transaction when it deletes m.

Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 43 +--
 1 file changed, 33 insertions(+), 10 deletions(-)

diff --git a/refs.c b/refs.c
index c5d41bb..3967333 100644
--- a/refs.c
+++ b/refs.c
@@ -798,11 +798,19 @@ struct name_conflict_cb {
const char *refname;
const char *oldrefname;
const char *conflicting_refname;
+   const char **skip;
+   int skipnum;
 };
 
 static int name_conflict_fn(struct ref_entry *entry, void *cb_data)
 {
struct name_conflict_cb *data = (struct name_conflict_cb *)cb_data;
+   int i;
+   for(i = 0; i < data->skipnum; i++) {
+   if (!strcmp(entry->name, data->skip[i])) {
+   return 0;
+   }
+   }
if (data->oldrefname && !strcmp(data->oldrefname, entry->name))
return 0;
if (names_conflict(data->refname, entry->name)) {
@@ -817,15 +825,21 @@ static int name_conflict_fn(struct ref_entry *entry, void 
*cb_data)
  * conflicting with the name of an existing reference in dir.  If
  * oldrefname is non-NULL, ignore potential conflicts with oldrefname
  * (e.g., because oldrefname is scheduled for deletion in the same
- * operation).
+ * operation). skip contains a list of refs we want to skip checking for
+ * conflicts with. Refs may be skipped due to us knowing that it will
+ * be deleted later during a transaction that deletes one reference and then
+ * creates a new conflicting reference. For example a rename from m to m/m.
  */
 static int is_refname_available(const char *refname, const char *oldrefname,
-   struct ref_dir *dir)
+   struct ref_dir *dir,
+   const char **skip, int skipnum)
 {
struct name_conflict_cb data;
data.refname = refname;
data.oldrefname = oldrefname;
data.conflicting_refname = NULL;
+   data.skip = skip;
+   data.skipnum = skipnum;
 
sort_ref_dir(dir);
if (do_for_each_entry_in_dir(dir, 0, name_conflict_fn, &data)) {
@@ -2037,7 +2051,8 @@ int dwim_log(const char *str, int len, unsigned char 
*sha1, char **log)
 
 static struct ref_lock *lock_ref_sha1_basic(const char *refname,
const unsigned char *old_sha1,
-   int flags, int *type_p)
+   int flags, int *type_p,
+   const char **skip, int skipnum)
 {
char *ref_file;
const char *orig_refname = refname;
@@ -2084,7 +2099,9 @@ static struct ref_lock *lock_ref_sha1_basic(const char 
*refname,
 * name is a proper prefix of our refname.
 */
if (missing &&
-!is_refname_available(refname, NULL, get_packed_refs(&ref_cache))) 
{
+!is_refname_available(refname, NULL,
+  get_packed_refs(&ref_cache),
+  skip, skipnum)) {
last_errno = ENOTDIR;
goto error_return;
}
@@ -2142,7 +2159,7 @@ struct ref_lock *lock_any_ref_for_update(const char 
*refname,
 const unsigned char *old_sha1,
 int flags, int *type_p)
 {
-   return lock_ref_sha1_basic(refname, old_sha1, flags, type_p);
+   return lock_ref_sha1_basic(refname, old_sha1, flags, type_p, NULL, 0);
 }
 
 /*
@@ -2620,6 +2637,9 @@ int rename_ref(const char *oldrefname, const char 
*newrefname, const char *logms
int log = !lstat(git_path("logs/%s", oldrefname), &loginfo);
const char *symref = NULL;
 
+   if (!strcmp(oldrefname, newrefname))
+   return 0;
+
if (log && S_ISLNK(loginfo.st_mode))
return error("reflog for %s is a symlink", oldrefname);
 
@@ -2630,10 +2650,12 @@ int rename_ref(const char *oldrefname, const char 
*newrefname, const char *logms
if (!symref)
return error("refname %s not found", oldrefname);
 
-   if (!is_refname_available(newrefname, oldrefname, 
get_packed_refs(&ref_cache)))
+   if (!is_refname_available(newrefname, oldrefname,
+ get_packed_refs(&ref_cache), NULL, 0))
return 1;
 
-   if (!is_refname_available(newrefname, oldrefname, 
get_loose_re

[PATCH v10 32/44] refs.c: remove the update_ref_write function

2014-05-16 Thread Ronnie Sahlberg
Since we only call update_ref_write from a single place and we only call it
with onerr==QUIET_ON_ERR we can just as well get rid of it and just call
write_ref_sha1 directly.

Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 35 +--
 1 file changed, 9 insertions(+), 26 deletions(-)

diff --git a/refs.c b/refs.c
index 04de777..b1acf51 100644
--- a/refs.c
+++ b/refs.c
@@ -3283,25 +3283,6 @@ int for_each_reflog(each_ref_fn fn, void *cb_data)
return retval;
 }
 
-static int update_ref_write(const char *action, const char *refname,
-   const unsigned char *sha1, struct ref_lock *lock,
-   struct strbuf *err, enum action_on_err onerr)
-{
-   if (write_ref_sha1(lock, sha1, action) < 0) {
-   const char *str = "Cannot update the ref '%s'.";
-   if (err)
-   strbuf_addf(err, str, refname);
-
-   switch (onerr) {
-   case UPDATE_REFS_MSG_ON_ERR: error(str, refname); break;
-   case UPDATE_REFS_DIE_ON_ERR: die(str, refname); break;
-   case UPDATE_REFS_QUIET_ON_ERR: break;
-   }
-   return 1;
-   }
-   return 0;
-}
-
 /**
  * Information needed for a single ref update.  Set new_sha1 to the
  * new value or to zero to delete the ref.  To check the old value
@@ -3539,14 +3520,16 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
struct ref_update *update = updates[i];
 
if (!is_null_sha1(update->new_sha1)) {
-   ret = update_ref_write(msg,
-  update->refname,
-  update->new_sha1,
-  update->lock, err,
-  UPDATE_REFS_QUIET_ON_ERR);
-   update->lock = NULL; /* freed by update_ref_write */
-   if (ret)
+   ret = write_ref_sha1(update->lock, update->new_sha1,
+msg);
+   update->lock = NULL; /* freed by write_ref_sha1 */
+   if (ret) {
+   const char *str = "Cannot update the ref '%s'.";
+
+   if (err)
+   strbuf_addf(err, str, update->refname);
goto cleanup;
+   }
}
}
 
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 43/44] refs.c: make rename_ref use a transaction

2014-05-16 Thread Ronnie Sahlberg
Change rename_ref to use a single transaction to perform the ref rename.

Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 73 ++
 1 file changed, 20 insertions(+), 53 deletions(-)

diff --git a/refs.c b/refs.c
index 3967333..71e3059 100644
--- a/refs.c
+++ b/refs.c
@@ -2630,9 +2630,10 @@ static int rename_tmp_log(const char *newrefname)
 
 int rename_ref(const char *oldrefname, const char *newrefname, const char 
*logmsg)
 {
-   unsigned char sha1[20], orig_sha1[20];
-   int flag = 0, logmoved = 0;
-   struct ref_lock *lock;
+   unsigned char sha1[20];
+   int flag = 0;
+   struct ref_transaction *transaction;
+   struct strbuf err = STRBUF_INIT;
struct stat loginfo;
int log = !lstat(git_path("logs/%s", oldrefname), &loginfo);
const char *symref = NULL;
@@ -2643,7 +2644,7 @@ int rename_ref(const char *oldrefname, const char 
*newrefname, const char *logms
if (log && S_ISLNK(loginfo.st_mode))
return error("reflog for %s is a symlink", oldrefname);
 
-   symref = resolve_ref_unsafe(oldrefname, orig_sha1, 1, &flag);
+   symref = resolve_ref_unsafe(oldrefname, sha1, 1, &flag);
if (flag & REF_ISSYMREF)
return error("refname %s is a symbolic ref, renaming it is not 
supported",
oldrefname);
@@ -2665,62 +2666,28 @@ int rename_ref(const char *oldrefname, const char 
*newrefname, const char *logms
if (pack_refs(PACK_REFS_ALL | PACK_REFS_PRUNE))
return error("unable to pack refs");
 
-   if (delete_ref(oldrefname, orig_sha1, REF_NODEREF)) {
-   error("unable to delete old %s", oldrefname);
-   goto rollback;
-   }
-
-   if (!read_ref_full(newrefname, sha1, 1, NULL) &&
-   delete_ref(newrefname, sha1, REF_NODEREF)) {
-   if (errno==EISDIR) {
-   if (remove_empty_directories(git_path("%s", 
newrefname))) {
-   error("Directory not empty: %s", newrefname);
-   goto rollback;
-   }
-   } else {
-   error("unable to delete existing %s", newrefname);
-   goto rollback;
-   }
+   transaction = ref_transaction_begin();
+   if (!transaction ||
+   ref_transaction_delete(transaction, oldrefname, sha1,
+  REF_NODEREF | REF_ISPACKONLY,
+  1, NULL, &err) ||
+   ref_transaction_update(transaction, newrefname, sha1,
+  NULL, 0, 0, logmsg, &err) ||
+   ref_transaction_commit(transaction, &err)) {
+   ref_transaction_free(transaction);
+   error("rename_ref failed: %s", err.buf);
+   strbuf_release(&err);
+   goto rollbacklog;
}
+   ref_transaction_free(transaction);
 
if (log && rename_tmp_log(newrefname))
-   goto rollback;
-
-   logmoved = log;
-
-   lock = lock_ref_sha1_basic(newrefname, NULL, 0, NULL, NULL, 0);
-   if (!lock) {
-   error("unable to lock %s for update", newrefname);
-   goto rollback;
-   }
-   lock->force_write = 1;
-   hashcpy(lock->old_sha1, orig_sha1);
-   if (write_ref_sha1(lock, orig_sha1, logmsg)) {
-   error("unable to write current sha1 into %s", newrefname);
-   goto rollback;
-   }
-
-   return 0;
-
- rollback:
-   lock = lock_ref_sha1_basic(oldrefname, NULL, 0, NULL, NULL, 0);
-   if (!lock) {
-   error("unable to lock %s for rollback", oldrefname);
goto rollbacklog;
-   }
 
-   lock->force_write = 1;
-   flag = log_all_ref_updates;
-   log_all_ref_updates = 0;
-   if (write_ref_sha1(lock, orig_sha1, NULL))
-   error("unable to write current sha1 into %s", oldrefname);
-   log_all_ref_updates = flag;
+   return 0;
 
  rollbacklog:
-   if (logmoved && rename(git_path("logs/%s", newrefname), 
git_path("logs/%s", oldrefname)))
-   error("unable to restore logfile %s from %s: %s",
-   oldrefname, newrefname, strerror(errno));
-   if (!logmoved && log &&
+   if (log &&
rename(git_path(TMP_RENAMED_LOG), git_path("logs/%s", oldrefname)))
error("unable to restore logfile %s from "TMP_RENAMED_LOG": %s",
oldrefname, strerror(errno));
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 38/44] refs.c: pack all refs before we start to rename a ref

2014-05-16 Thread Ronnie Sahlberg
This means that most loose refs will no longer be present after the rename
which triggered a test failure since it assumes the file for an unrelated
ref would still be present after the rename.

Signed-off-by: Ronnie Sahlberg 
---
 refs.c| 3 +++
 t/t3200-branch.sh | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/refs.c b/refs.c
index 1210345..f4899e0 100644
--- a/refs.c
+++ b/refs.c
@@ -2635,6 +2635,9 @@ int rename_ref(const char *oldrefname, const char 
*newrefname, const char *logms
return error("unable to move logfile logs/%s to 
"TMP_RENAMED_LOG": %s",
oldrefname, strerror(errno));
 
+   if (pack_refs(PACK_REFS_ALL | PACK_REFS_PRUNE))
+   return error("unable to pack refs");
+
if (delete_ref(oldrefname, orig_sha1, REF_NODEREF)) {
error("unable to delete old %s", oldrefname);
goto rollback;
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index ac31b71..fafd38a 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -289,7 +289,7 @@ test_expect_success 'renaming a symref is not allowed' '
git symbolic-ref refs/heads/master2 refs/heads/master &&
test_must_fail git branch -m master2 master3 &&
git symbolic-ref refs/heads/master2 &&
-   test_path_is_file .git/refs/heads/master &&
+   test_path_is_missing .git/refs/heads/master &&
test_path_is_missing .git/refs/heads/master3
 '
 
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 33/44] refs.c: remove lock_ref_sha1

2014-05-16 Thread Ronnie Sahlberg
lock_ref_sha1 was only called from one place in refc.c and only provided
a check that the refname was sane before adding back the initial "refs/"
part of the ref path name, the initial "refs/" that this caller had already
stripped off before calling lock_ref_sha1.

Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 15 +--
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/refs.c b/refs.c
index b1acf51..69623e4 100644
--- a/refs.c
+++ b/refs.c
@@ -2126,15 +2126,6 @@ static struct ref_lock *lock_ref_sha1_basic(const char 
*refname,
return NULL;
 }
 
-static struct ref_lock *lock_ref_sha1(const char *refname, const unsigned char 
*old_sha1)
-{
-   char refpath[PATH_MAX];
-   if (check_refname_format(refname, 0))
-   return NULL;
-   strcpy(refpath, mkpath("refs/%s", refname));
-   return lock_ref_sha1_basic(refpath, old_sha1, 0, NULL);
-}
-
 struct ref_lock *lock_any_ref_for_update(const char *refname,
 const unsigned char *old_sha1,
 int flags, int *type_p)
@@ -2339,8 +2330,12 @@ static void try_remove_empty_parents(char *name)
 /* make sure nobody touched the ref, and unlink */
 static void prune_ref(struct ref_to_prune *r)
 {
-   struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1);
+   struct ref_lock *lock;
+
+   if (check_refname_format(r->name + 5, 0))
+   return;
 
+   lock = lock_ref_sha1_basic(r->name, r->sha1, 0, NULL);
if (lock) {
unlink_or_warn(git_path("%s", r->name));
unlock_ref(lock);
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 39/44] refs.c: move the check for valid refname to lock_ref_sha1_basic

2014-05-16 Thread Ronnie Sahlberg
Move the check for check_refname_format from lock_any_ref_for_update
to lock_ref_sha1_basic. At some later stage we will get rid of
lock_any_ref_for_update completely.

This leaves lock_any_ref_for_updates as a no-op wrapper which could be removed.
But this wrapper is also called from an external caller and we will soon
make changes to the signature to lock_ref_sha1_basic that we do not want to
expose to that caller.

Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/refs.c b/refs.c
index f4899e0..f63a356 100644
--- a/refs.c
+++ b/refs.c
@@ -2044,6 +2044,9 @@ static struct ref_lock *lock_ref_sha1_basic(const char 
*refname,
int missing = 0;
int attempts_remaining = 3;
 
+   if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
+   return NULL;
+
lock = xcalloc(1, sizeof(struct ref_lock));
lock->lock_fd = -1;
 
@@ -2135,8 +2138,6 @@ struct ref_lock *lock_any_ref_for_update(const char 
*refname,
 const unsigned char *old_sha1,
 int flags, int *type_p)
 {
-   if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
-   return NULL;
return lock_ref_sha1_basic(refname, old_sha1, flags, type_p);
 }
 
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 31/44] refs.c: remove the update_ref_lock function

2014-05-16 Thread Ronnie Sahlberg
Since we now only call update_ref_lock with onerr==QUIET_ON_ERR we no longer
need this function and can replace it with just calling lock_any_ref_for_update
directly.

Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 30 ++
 1 file changed, 6 insertions(+), 24 deletions(-)

diff --git a/refs.c b/refs.c
index 4f7ae92..04de777 100644
--- a/refs.c
+++ b/refs.c
@@ -3283,24 +3283,6 @@ int for_each_reflog(each_ref_fn fn, void *cb_data)
return retval;
 }
 
-static struct ref_lock *update_ref_lock(const char *refname,
-   const unsigned char *oldval,
-   int flags, int *type_p,
-   enum action_on_err onerr)
-{
-   struct ref_lock *lock;
-   lock = lock_any_ref_for_update(refname, oldval, flags, type_p);
-   if (!lock) {
-   const char *str = "Cannot lock the ref '%s'.";
-   switch (onerr) {
-   case UPDATE_REFS_MSG_ON_ERR: error(str, refname); break;
-   case UPDATE_REFS_DIE_ON_ERR: die(str, refname); break;
-   case UPDATE_REFS_QUIET_ON_ERR: break;
-   }
-   }
-   return lock;
-}
-
 static int update_ref_write(const char *action, const char *refname,
const unsigned char *sha1, struct ref_lock *lock,
struct strbuf *err, enum action_on_err onerr)
@@ -3537,12 +3519,12 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
for (i = 0; i < n; i++) {
struct ref_update *update = updates[i];
 
-   update->lock = update_ref_lock(update->refname,
-  (update->have_old ?
-   update->old_sha1 : NULL),
-  update->flags,
-  &update->type,
-  UPDATE_REFS_QUIET_ON_ERR);
+   update->lock = lock_any_ref_for_update(update->refname,
+  (update->have_old ?
+   update->old_sha1 :
+   NULL),
+  update->flags,
+  &update->type);
if (!update->lock) {
if (err)
strbuf_addf(err, "Cannot lock the ref '%s'.",
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 40/44] refs.c: call lock_ref_sha1_basic directly from commit

2014-05-16 Thread Ronnie Sahlberg
Skip using the lock_any_ref_for_update wrapper and call lock_ref_sha1_basic
directly from the commit function.

Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/refs.c b/refs.c
index f63a356..564feb6 100644
--- a/refs.c
+++ b/refs.c
@@ -3511,12 +3511,12 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
for (i = 0; i < n; i++) {
struct ref_update *update = updates[i];
 
-   update->lock = lock_any_ref_for_update(update->refname,
-  (update->have_old ?
-   update->old_sha1 :
-   NULL),
-  update->flags,
-  &update->type);
+   update->lock = lock_ref_sha1_basic(update->refname,
+  (update->have_old ?
+   update->old_sha1 :
+   NULL),
+  update->flags,
+  &update->type);
if (!update->lock) {
if (err)
strbuf_addf(err, "Cannot lock the ref '%s'.",
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 41/44] refs.c: add a new flag for transaction delete for refs we know are packed only

2014-05-16 Thread Ronnie Sahlberg
Add a new flag REF_ISPACKONLY that we can use in ref_transaction_delete.
This flag indicates that the ref does not exist as a loose ref andf only as
a packed ref. If this is the case we then change the commit code so that
we skip taking out a lock file and we skip calling delete_ref_loose.
Check for this flag and die(BUG:...) if used with _update or _create.

At the start of the transaction, before we even start locking any refs,
we add all such REF_ISPACKONLY refs to delnames so that we have a list of
all pack only refs that we will be deleting during this transaction.

Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 23 +++
 1 file changed, 23 insertions(+)

diff --git a/refs.c b/refs.c
index 564feb6..c5d41bb 100644
--- a/refs.c
+++ b/refs.c
@@ -33,6 +33,10 @@ static inline int bad_ref_char(int ch)
  *  pruned.
  */
 #define REF_ISPRUNING  0x0100
+/** Deletion of a ref that only exists as a packed ref in which case we do not
+ *  need to lock the loose ref during the transaction.
+ */
+#define REF_ISPACKONLY 0x0200
 
 /*
  * Try to read one refname component from the front of refname.  Return
@@ -3366,6 +3370,9 @@ int ref_transaction_update(struct ref_transaction 
*transaction,
if (transaction->status != REF_TRANSACTION_OPEN)
die("BUG: update on transaction that is not open");
 
+   if (flags & REF_ISPACKONLY)
+   die("BUG: REF_ISPACKONLY can not be used with updates");
+
update = add_update(transaction, refname);
hashcpy(update->new_sha1, new_sha1);
update->flags = flags;
@@ -3392,6 +3399,9 @@ int ref_transaction_create(struct ref_transaction 
*transaction,
if (transaction->status != REF_TRANSACTION_OPEN)
die("BUG: create on transaction that is not open");
 
+   if (flags & REF_ISPACKONLY)
+   die("BUG: REF_ISPACKONLY can not be used with creates");
+
update = add_update(transaction, refname);
 
hashcpy(update->new_sha1, new_sha1);
@@ -3507,10 +3517,20 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
if (ret)
goto cleanup;
 
+   for (i = 0; i < n; i++) {
+   struct ref_update *update = updates[i];
+
+   if (update->flags & REF_ISPACKONLY)
+   delnames[delnum++] = update->refname;
+   }
+
/* Acquire all locks while verifying old values */
for (i = 0; i < n; i++) {
struct ref_update *update = updates[i];
 
+   if (update->flags & REF_ISPACKONLY)
+   continue;
+
update->lock = lock_ref_sha1_basic(update->refname,
   (update->have_old ?
update->old_sha1 :
@@ -3548,6 +3568,9 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
for (i = 0; i < n; i++) {
struct ref_update *update = updates[i];
 
+   if (update->flags & REF_ISPACKONLY)
+   continue;
+
if (update->lock) {
ret |= delete_ref_loose(update->lock, update->type,
err);
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 23/44] fetch.c: change s_update_ref to use a ref transaction

2014-05-16 Thread Ronnie Sahlberg
Change s_update_ref to use a ref transaction for the ref update.

Signed-off-by: Ronnie Sahlberg 
---
 builtin/fetch.c | 17 +
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index a93c893..8cf70cd 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -375,7 +375,7 @@ static int s_update_ref(const char *action,
 {
char msg[1024];
char *rla = getenv("GIT_REFLOG_ACTION");
-   static struct ref_lock *lock;
+   struct ref_transaction *transaction;
 
if (dry_run)
return 0;
@@ -384,15 +384,16 @@ static int s_update_ref(const char *action,
snprintf(msg, sizeof(msg), "%s: %s", rla, action);
 
errno = 0;
-   lock = lock_any_ref_for_update(ref->name,
-  check_old ? ref->old_sha1 : NULL,
-  0, NULL);
-   if (!lock)
-   return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
- STORE_REF_ERROR_OTHER;
-   if (write_ref_sha1(lock, ref->new_sha1, msg) < 0)
+   transaction = ref_transaction_begin();
+   if (!transaction ||
+   ref_transaction_update(transaction, ref->name, ref->new_sha1,
+  ref->old_sha1, 0, check_old, NULL) ||
+   ref_transaction_commit(transaction, msg, NULL)) {
+   ref_transaction_free(transaction);
return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
  STORE_REF_ERROR_OTHER;
+   }
+   ref_transaction_free(transaction);
return 0;
 }
 
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 26/44] fast-import.c: use a ref transaction when dumping tags

2014-05-16 Thread Ronnie Sahlberg
Signed-off-by: Ronnie Sahlberg 
---
 fast-import.c | 17 -
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/fast-import.c b/fast-import.c
index cb3f5af..9c76c73 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -1735,15 +1735,22 @@ static void dump_tags(void)
 {
static const char *msg = "fast-import";
struct tag *t;
-   struct ref_lock *lock;
char ref_name[PATH_MAX];
+   struct strbuf err = STRBUF_INIT;
+   struct ref_transaction *transaction;
 
+   transaction = ref_transaction_begin();
for (t = first_tag; t; t = t->next_tag) {
-   sprintf(ref_name, "tags/%s", t->name);
-   lock = lock_ref_sha1(ref_name, NULL);
-   if (!lock || write_ref_sha1(lock, t->sha1, msg) < 0)
-   failure |= error("Unable to update %s", ref_name);
+   sprintf(ref_name, "refs/tags/%s", t->name);
+
+   if (ref_transaction_update(transaction, ref_name, t->sha1,
+  NULL, 0, 0, &err))
+   failure |= error("%s", err.buf);
}
+   if (failure || ref_transaction_commit(transaction, msg, &err))
+   failure |= error("%s", err.buf);
+   ref_transaction_free(transaction);
+   strbuf_release(&err);
 }
 
 static void dump_marks_helper(FILE *f,
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 27/44] walker.c: use ref transaction for ref updates

2014-05-16 Thread Ronnie Sahlberg
Switch to using ref transactions in walker_fetch(). As part of the refactoring
to use ref transactions we also fix a potential memory leak where in the
original code if write_ref_sha1() would fail we would end up returning from
the function without free()ing the msg string.

This changes the locking slightly for walker_fetch. Previously the code would
lock all refs before writing them but now we do not lock the refs until the
commit stage. There is thus a very short window where changes could be done
locally during the fetch which would be overwritten when the fetch completes
and commits its transaction. But this window should be reasonably short.
Even if this race does trigger, since both the old code and the new code
just overwrites the refs to the new values without checking or comparing
them with the previous value, this is not too dissimilar to a similar scenario
where you first do a ref change locally and then later do a fetch that
overwrites the local change. With this in mind I do not see the change in
locking semantics to be critical.

Note that this function is only called when fetching from a remote HTTP
repository onto the local (most of the time single-user) repository which
likely means that the type of collissions that the previous locking would
protect against and cause the fetch to fail for to be even more rare.

Signed-off-by: Ronnie Sahlberg 
---
 walker.c | 51 ++-
 1 file changed, 26 insertions(+), 25 deletions(-)

diff --git a/walker.c b/walker.c
index 1dd86b8..cbe5686 100644
--- a/walker.c
+++ b/walker.c
@@ -251,24 +251,18 @@ void walker_targets_free(int targets, char **target, 
const char **write_ref)
 int walker_fetch(struct walker *walker, int targets, char **target,
 const char **write_ref, const char *write_ref_log_details)
 {
-   struct ref_lock **lock = xcalloc(targets, sizeof(struct ref_lock *));
+   char ref_name[PATH_MAX];
+   struct strbuf err = STRBUF_INIT;
+   struct ref_transaction *transaction;
unsigned char *sha1 = xmalloc(targets * 20);
-   char *msg;
-   int ret;
+   char *msg = NULL;
int i;
 
save_commit_buffer = 0;
 
-   for (i = 0; i < targets; i++) {
-   if (!write_ref || !write_ref[i])
-   continue;
-
-   lock[i] = lock_ref_sha1(write_ref[i], NULL);
-   if (!lock[i]) {
-   error("Can't lock ref %s", write_ref[i]);
-   goto unlock_and_fail;
-   }
-   }
+   transaction = ref_transaction_begin();
+   if (!transaction)
+   return -1;
 
if (!walker->get_recover)
for_each_ref(mark_complete, NULL);
@@ -276,14 +270,14 @@ int walker_fetch(struct walker *walker, int targets, char 
**target,
for (i = 0; i < targets; i++) {
if (interpret_target(walker, target[i], &sha1[20 * i])) {
error("Could not interpret response from server '%s' as 
something to pull", target[i]);
-   goto unlock_and_fail;
+   goto rollback_and_fail;
}
if (process(walker, lookup_unknown_object(&sha1[20 * i])))
-   goto unlock_and_fail;
+   goto rollback_and_fail;
}
 
if (loop(walker))
-   goto unlock_and_fail;
+   goto rollback_and_fail;
 
if (write_ref_log_details) {
msg = xmalloc(strlen(write_ref_log_details) + 12);
@@ -294,19 +288,26 @@ int walker_fetch(struct walker *walker, int targets, char 
**target,
for (i = 0; i < targets; i++) {
if (!write_ref || !write_ref[i])
continue;
-   ret = write_ref_sha1(lock[i], &sha1[20 * i], msg ? msg : "fetch 
(unknown)");
-   lock[i] = NULL;
-   if (ret)
-   goto unlock_and_fail;
+   sprintf(ref_name, "refs/%s", write_ref[i]);
+   if (ref_transaction_update(transaction, ref_name,
+  &sha1[20 * i], NULL,
+  0, 0, &err))
+   goto rollback_and_fail;
+   }
+
+   if (ref_transaction_commit(transaction, msg ? msg : "fetch (unknown)",
+  &err)) {
+   error("%s", err.buf);
+   goto rollback_and_fail;
}
-   free(msg);
 
+   free(msg);
return 0;
 
-unlock_and_fail:
-   for (i = 0; i < targets; i++)
-   if (lock[i])
-   unlock_ref(lock[i]);
+rollback_and_fail:
+   free(msg);
+   strbuf_release(&err);
+   ref_transaction_free(transaction);
 
return -1;
 }
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info 

[PATCH v10 44/44] refs.c: remove forward declaration of write_ref_sha1

2014-05-16 Thread Ronnie Sahlberg
Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/refs.c b/refs.c
index 71e3059..bf84306 100644
--- a/refs.c
+++ b/refs.c
@@ -260,8 +260,6 @@ struct ref_entry {
 };
 
 static void read_loose_refs(const char *dirname, struct ref_dir *dir);
-static int write_ref_sha1(struct ref_lock *lock,
- const unsigned char *sha1, const char *logmsg);
 
 static struct ref_dir *get_ref_dir(struct ref_entry *entry)
 {
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 21/44] refs.c: ref_transaction_commit should not free the transaction

2014-05-16 Thread Ronnie Sahlberg
Change ref_transaction_commit so that it does not free the transaction.
Instead require that a caller will end a transaction by calling
ref_transaction_free.

By having the transaction object remaining valid after _commit returns allows
us to write much nicer code and still be able to call ref_transaction_free
safely. Instead of this horribleness
t = ref_transaction_begin();
if ((!t ||
ref_transaction_update(t, refname, sha1, oldval, flags,
   !!oldval)) ||
(ref_transaction_commit(t, action, &err) && !(t = NULL))) {
ref_transaction_free(t);

we can now just do the much nicer
t = ref_transaction_begin();
if (!t ||
ref_transaction_update(t, refname, sha1, oldval, flags,
   !!oldval) ||
ref_transaction_commit(&t, action, &err)) {
ref_transaction_free(t);
... die/return ...

ref_transaction_free(transaction);

Signed-off-by: Ronnie Sahlberg 
---
 branch.c |  1 +
 builtin/commit.c |  1 +
 builtin/replace.c|  1 +
 builtin/tag.c|  1 +
 builtin/update-ref.c |  1 +
 fast-import.c|  4 ++--
 refs.c   | 12 +---
 refs.h   |  8 +++-
 sequencer.c  |  4 ++--
 9 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/branch.c b/branch.c
index 8bf7588..f78a28b 100644
--- a/branch.c
+++ b/branch.c
@@ -304,6 +304,7 @@ void create_branch(const char *head,
   null_sha1, 0, !forcing, &err) ||
ref_transaction_commit(transaction, msg, &err))
die("%s", err.buf);
+   ref_transaction_free(transaction);
}
 
if (real_ref && track)
diff --git a/builtin/commit.c b/builtin/commit.c
index c429216..6b888f2 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1726,6 +1726,7 @@ int cmd_commit(int argc, const char **argv, const char 
*prefix)
rollback_index_files();
die("%s", err.buf);
}
+   ref_transaction_free(transaction);
 
unlink(git_path("CHERRY_PICK_HEAD"));
unlink(git_path("REVERT_HEAD"));
diff --git a/builtin/replace.c b/builtin/replace.c
index e8932cd..af7f72d 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -164,6 +164,7 @@ static int replace_object_sha1(const char *object_ref,
ref_transaction_commit(transaction, NULL, &err))
die("%s", err.buf);
 
+   ref_transaction_free(transaction);
return 0;
 }
 
diff --git a/builtin/tag.c b/builtin/tag.c
index b05f9a5..30b471c 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -708,6 +708,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
   0, !is_null_sha1(prev), &err) ||
ref_transaction_commit(transaction, NULL, &err))
die("%s", err.buf);
+   ref_transaction_free(transaction);
if (force && !is_null_sha1(prev) && hashcmp(prev, object))
printf(_("Updated tag '%s' (was %s)\n"), tag, 
find_unique_abbrev(prev, DEFAULT_ABBREV));
 
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index cdb71a8..4c2145e 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -373,6 +373,7 @@ int cmd_update_ref(int argc, const char **argv, const char 
*prefix)
update_refs_stdin();
if (ref_transaction_commit(transaction, msg, &err))
die("%s", err.buf);
+   ref_transaction_free(transaction);
return 0;
}
 
diff --git a/fast-import.c b/fast-import.c
index 60d4538..cb3f5af 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -1710,13 +1710,13 @@ static int update_branch(struct branch *b)
if (!transaction ||
ref_transaction_update(transaction, b->name, b->sha1, old_sha1,
   0, 1, &err) ||
-   (ref_transaction_commit(transaction, msg, &err) &&
-!(transaction = NULL))) {
+   ref_transaction_commit(transaction, msg, &err)) {
ref_transaction_free(transaction);
error("%s", err.buf);
strbuf_release(&err);
return -1;
}
+   ref_transaction_free(transaction);
return 0;
 }
 
diff --git a/refs.c b/refs.c
index 2c3f070..266a792 100644
--- a/refs.c
+++ b/refs.c
@@ -3446,10 +3446,10 @@ int update_ref(const char *action, const char *refname,
struct strbuf err = STRBUF_INIT;
 
t = ref_transaction_begin();
-   if ((!t ||
+   if (!t ||
ref_transaction_update(t, refname, sha1, oldval, flags,
-  !!oldval, &err)) ||
-   (ref_transaction_commit(t, action, &err) && !(t = NULL))) {
+  !!oldval, &err) ||
+   ref_transaction_commit(t, action, &err)) {
c

[PATCH v10 19/44] refs.c: change update_ref to use a transaction

2014-05-16 Thread Ronnie Sahlberg
Change the update_ref helper function to use a ref transaction internally.

Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 25 +
 1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/refs.c b/refs.c
index a588194..78312b5 100644
--- a/refs.c
+++ b/refs.c
@@ -3442,11 +3442,28 @@ int update_ref(const char *action, const char *refname,
   const unsigned char *sha1, const unsigned char *oldval,
   int flags, enum action_on_err onerr)
 {
-   struct ref_lock *lock;
-   lock = update_ref_lock(refname, oldval, flags, NULL, onerr);
-   if (!lock)
+   struct ref_transaction *t;
+   struct strbuf err = STRBUF_INIT;
+
+   t = ref_transaction_begin();
+   if ((!t ||
+   ref_transaction_update(t, refname, sha1, oldval, flags,
+  !!oldval, &err)) ||
+   (ref_transaction_commit(t, action, &err) && !(t = NULL))) {
+   const char *str = "update_ref failed for ref '%s': %s";
+
+   ref_transaction_free(t);
+   switch (onerr) {
+   case UPDATE_REFS_MSG_ON_ERR:
+   error(str, refname, err.buf); break;
+   case UPDATE_REFS_DIE_ON_ERR:
+   die(str, refname, err.buf); break;
+   case UPDATE_REFS_QUIET_ON_ERR: break;
+   }
+   strbuf_release(&err);
return 1;
-   return update_ref_write(action, refname, sha1, lock, NULL, onerr);
+   }
+   return 0;
 }
 
 static int ref_update_compare(const void *r1, const void *r2)
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 17/44] fast-import.c: change update_branch to use ref transactions

2014-05-16 Thread Ronnie Sahlberg
Change update_branch() to use ref transactions for updates.

Signed-off-by: Ronnie Sahlberg 
---
 fast-import.c | 25 +++--
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/fast-import.c b/fast-import.c
index 6707a66..60d4538 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -1679,39 +1679,44 @@ found_entry:
 static int update_branch(struct branch *b)
 {
static const char *msg = "fast-import";
-   struct ref_lock *lock;
+   struct ref_transaction *transaction;
unsigned char old_sha1[20];
+   struct strbuf err = STRBUF_INIT;
 
if (read_ref(b->name, old_sha1))
hashclr(old_sha1);
+
if (is_null_sha1(b->sha1)) {
if (b->delete)
delete_ref(b->name, old_sha1, 0);
return 0;
}
-   lock = lock_any_ref_for_update(b->name, old_sha1, 0, NULL);
-   if (!lock)
-   return error("Unable to lock %s", b->name);
if (!force_update && !is_null_sha1(old_sha1)) {
struct commit *old_cmit, *new_cmit;
 
old_cmit = lookup_commit_reference_gently(old_sha1, 0);
new_cmit = lookup_commit_reference_gently(b->sha1, 0);
-   if (!old_cmit || !new_cmit) {
-   unlock_ref(lock);
+   if (!old_cmit || !new_cmit)
return error("Branch %s is missing commits.", b->name);
-   }
 
if (!in_merge_bases(old_cmit, new_cmit)) {
-   unlock_ref(lock);
warning("Not updating %s"
" (new tip %s does not contain %s)",
b->name, sha1_to_hex(b->sha1), 
sha1_to_hex(old_sha1));
return -1;
}
}
-   if (write_ref_sha1(lock, b->sha1, msg) < 0)
-   return error("Unable to update %s", b->name);
+   transaction = ref_transaction_begin();
+   if (!transaction ||
+   ref_transaction_update(transaction, b->name, b->sha1, old_sha1,
+  0, 1, &err) ||
+   (ref_transaction_commit(transaction, msg, &err) &&
+!(transaction = NULL))) {
+   ref_transaction_free(transaction);
+   error("%s", err.buf);
+   strbuf_release(&err);
+   return -1;
+   }
return 0;
 }
 
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 35/44] refs.c: make delete_ref use a transaction

2014-05-16 Thread Ronnie Sahlberg
Change delete_ref to use a ref transaction for the deletion. At the same time
since we no longer have any callers of repack_without_ref we can now delete
this function.

Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 31 ++-
 1 file changed, 10 insertions(+), 21 deletions(-)

diff --git a/refs.c b/refs.c
index 3a5f1e5..b16cf4c 100644
--- a/refs.c
+++ b/refs.c
@@ -2495,11 +2495,6 @@ static int repack_without_refs(const char **refnames, 
int n, struct strbuf *err)
return ret;
 }
 
-static int repack_without_ref(const char *refname)
-{
-   return repack_without_refs(&refname, 1, NULL);
-}
-
 static int add_err_if_unremovable(const char *op, const char *file,
  struct strbuf *e, int rc)
 {
@@ -2543,24 +2538,18 @@ static int delete_ref_loose(struct ref_lock *lock, int 
flag, struct strbuf *err)
 
 int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
 {
-   struct ref_lock *lock;
-   int ret = 0, flag = 0;
+   struct ref_transaction *transaction;
 
-   lock = lock_ref_sha1_basic(refname, sha1, delopt, &flag);
-   if (!lock)
+   transaction = ref_transaction_begin();
+   if (!transaction ||
+   ref_transaction_delete(transaction, refname, sha1, delopt,
+  sha1 && !is_null_sha1(sha1), NULL) ||
+   ref_transaction_commit(transaction, NULL, NULL)) {
+   ref_transaction_free(transaction);
return 1;
-   ret |= delete_ref_loose(lock, flag, NULL);
-
-   /* removing the loose one could have resurrected an earlier
-* packed one.  Also, if it was not loose we need to repack
-* without it.
-*/
-   ret |= repack_without_ref(lock->ref_name);
-
-   unlink_or_warn(git_path("logs/%s", lock->ref_name));
-   clear_loose_ref_cache(&ref_cache);
-   unlock_ref(lock);
-   return ret;
+   }
+   ref_transaction_free(transaction);
+   return 0;
 }
 
 /*
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 13/44] tag.c: use ref transactions when doing updates

2014-05-16 Thread Ronnie Sahlberg
Change tag.c to use ref transactions for all ref updates.

Signed-off-by: Ronnie Sahlberg 
---
 builtin/tag.c | 14 --
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/builtin/tag.c b/builtin/tag.c
index c6e8a71..b05f9a5 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -548,7 +548,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
struct strbuf ref = STRBUF_INIT;
unsigned char object[20], prev[20];
const char *object_ref, *tag;
-   struct ref_lock *lock;
struct create_tag_options opt;
char *cleanup_arg = NULL;
int annotate = 0, force = 0, lines = -1;
@@ -556,6 +555,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
const char *msgfile = NULL, *keyid = NULL;
struct msg_arg msg = { 0, STRBUF_INIT };
struct commit_list *with_commit = NULL;
+   struct ref_transaction *transaction;
+   struct strbuf err = STRBUF_INIT;
struct option options[] = {
OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'),
{ OPTION_INTEGER, 'n', NULL, &lines, N_("n"),
@@ -701,11 +702,12 @@ int cmd_tag(int argc, const char **argv, const char 
*prefix)
if (annotate)
create_tag(object, tag, &buf, &opt, prev, object);
 
-   lock = lock_any_ref_for_update(ref.buf, prev, 0, NULL);
-   if (!lock)
-   die(_("%s: cannot lock the ref"), ref.buf);
-   if (write_ref_sha1(lock, object, NULL) < 0)
-   die(_("%s: cannot update the ref"), ref.buf);
+   transaction = ref_transaction_begin();
+   if (!transaction ||
+   ref_transaction_update(transaction, ref.buf, object, prev,
+  0, !is_null_sha1(prev), &err) ||
+   ref_transaction_commit(transaction, NULL, &err))
+   die("%s", err.buf);
if (force && !is_null_sha1(prev) && hashcmp(prev, object))
printf(_("Updated tag '%s' (was %s)\n"), tag, 
find_unique_abbrev(prev, DEFAULT_ABBREV));
 
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 16/44] sequencer.c: use ref transactions for all ref updates

2014-05-16 Thread Ronnie Sahlberg
Change to use ref transactions for all updates to refs.

Signed-off-by: Ronnie Sahlberg 
---
 sequencer.c | 24 
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index 0a80c58..b047fb8 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -272,23 +272,31 @@ static int error_dirty_index(struct replay_opts *opts)
 static int fast_forward_to(const unsigned char *to, const unsigned char *from,
int unborn, struct replay_opts *opts)
 {
-   struct ref_lock *ref_lock;
+   struct ref_transaction *transaction;
struct strbuf sb = STRBUF_INIT;
-   int ret;
+   struct strbuf err = STRBUF_INIT;
 
read_cache();
if (checkout_fast_forward(from, to, 1))
exit(1); /* the callee should have complained already */
-   ref_lock = lock_any_ref_for_update("HEAD", unborn ? null_sha1 : from,
-  0, NULL);
-   if (!ref_lock)
-   return error(_("Failed to lock HEAD during fast_forward_to"));
 
strbuf_addf(&sb, "%s: fast-forward", action_name(opts));
-   ret = write_ref_sha1(ref_lock, to, sb.buf);
+
+   transaction = ref_transaction_begin();
+   if (!transaction ||
+   ref_transaction_update(transaction, "HEAD", to, from,
+  0, !unborn, &err) ||
+   (ref_transaction_commit(transaction, sb.buf, &err) &&
+!(transaction = NULL))) {
+   ref_transaction_free(transaction);
+   error("%s", err.buf);
+   strbuf_release(&sb);
+   strbuf_release(&err);
+   return -1;
+   }
 
strbuf_release(&sb);
-   return ret;
+   return 0;
 }
 
 static int do_recursive_merge(struct commit *base, struct commit *next,
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 18/44] branch.c: use ref transaction for all ref updates

2014-05-16 Thread Ronnie Sahlberg
Change create_branch to use a ref transaction when creating the new branch.
ref_transaction_create will check that the ref does not already exist and fail
otherwise meaning that we no longer need to keep a lock on the ref during the
setup_tracking. This simplifies the code since we can now do the transaction
in one single step.

If the forcing flag is false then use ref_transaction_create since this will
fail if the ref already exist. Otherwise use ref_transaction_update.

This also fixes a race condition in the old code where two concurrent
create_branch could race since the lock_any_ref_for_update/write_ref_sha1
did not protect against the ref already existing. I.e. one thread could end up
overwriting a branch even if the forcing flag is false.

Reviewed-by: Jonathan Nieder 
Signed-off-by: Ronnie Sahlberg 
---
 branch.c | 29 +++--
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/branch.c b/branch.c
index 660097b..8bf7588 100644
--- a/branch.c
+++ b/branch.c
@@ -226,7 +226,6 @@ void create_branch(const char *head,
   int force, int reflog, int clobber_head,
   int quiet, enum branch_track track)
 {
-   struct ref_lock *lock = NULL;
struct commit *commit;
unsigned char sha1[20];
char *real_ref, msg[PATH_MAX + 20];
@@ -285,15 +284,6 @@ void create_branch(const char *head,
die(_("Not a valid branch point: '%s'."), start_name);
hashcpy(sha1, commit->object.sha1);
 
-   if (!dont_change_ref) {
-   lock = lock_any_ref_for_update(ref.buf, NULL, 0, NULL);
-   if (!lock)
-   die_errno(_("Failed to lock ref for update"));
-   }
-
-   if (reflog)
-   log_all_ref_updates = 1;
-
if (forcing)
snprintf(msg, sizeof msg, "branch: Reset to %s",
 start_name);
@@ -301,13 +291,24 @@ void create_branch(const char *head,
snprintf(msg, sizeof msg, "branch: Created from %s",
 start_name);
 
+   if (reflog)
+   log_all_ref_updates = 1;
+
+   if (!dont_change_ref) {
+   struct ref_transaction *transaction;
+   struct strbuf err = STRBUF_INIT;
+
+   transaction = ref_transaction_begin();
+   if (!transaction ||
+   ref_transaction_update(transaction, ref.buf, sha1,
+  null_sha1, 0, !forcing, &err) ||
+   ref_transaction_commit(transaction, msg, &err))
+   die("%s", err.buf);
+   }
+
if (real_ref && track)
setup_tracking(ref.buf + 11, real_ref, track, quiet);
 
-   if (!dont_change_ref)
-   if (write_ref_sha1(lock, sha1, msg) < 0)
-   die_errno(_("Failed to write ref"));
-
strbuf_release(&ref);
free(real_ref);
 }
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 06/44] refs.c: add an err argument to delete_ref_loose

2014-05-16 Thread Ronnie Sahlberg
Add an err argument to delete_loose_ref so that we can pass a descriptive
error string back to the caller. Pass the err argument from transaction
commit to this function so that transaction users will have a nice error
string if the transaction failed due to delete_loose_ref.

Add a new function unlink_or_err that we can call from delete_ref_loose. This
function is similar to unlink_or_warn except that we can pass it an err
argument. If err is non-NULL the function will populate err instead of
printing a warning().

Signed-off-by: Ronnie Sahlberg 
---
 refs.c | 39 +--
 1 file changed, 33 insertions(+), 6 deletions(-)

diff --git a/refs.c b/refs.c
index 57ec72a..bc444c7 100644
--- a/refs.c
+++ b/refs.c
@@ -2491,17 +2491,43 @@ static int repack_without_ref(const char *refname)
return repack_without_refs(&refname, 1, NULL);
 }
 
-static int delete_ref_loose(struct ref_lock *lock, int flag)
+static int add_err_if_unremovable(const char *op, const char *file,
+ struct strbuf *e, int rc)
+{
+   int err = errno;
+   if (rc < 0 && err != ENOENT) {
+   strbuf_addf(e, "unable to %s %s: %s",
+   op, file, strerror(errno));
+   errno = err;
+   }
+   return rc;
+}
+
+static int unlink_or_err(const char *file, struct strbuf *err)
+{
+   if (err)
+   return add_err_if_unremovable("unlink", file, err,
+ unlink(file));
+   else
+   return unlink_or_warn(file);
+}
+
+static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf 
*err)
 {
if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
/* loose */
-   int err, i = strlen(lock->lk->filename) - 5; /* .lock */
+   int res, i = strlen(lock->lk->filename) - 5; /* .lock */
 
lock->lk->filename[i] = 0;
-   err = unlink_or_warn(lock->lk->filename);
+   res = unlink_or_err(lock->lk->filename, err);
lock->lk->filename[i] = '.';
-   if (err && errno != ENOENT)
+   if (res && errno != ENOENT) {
+   if (err)
+   strbuf_addf(err,
+   "failed to delete loose ref '%s'",
+   lock->lk->filename);
return 1;
+   }
}
return 0;
 }
@@ -2514,7 +2540,7 @@ int delete_ref(const char *refname, const unsigned char 
*sha1, int delopt)
lock = lock_ref_sha1_basic(refname, sha1, delopt, &flag);
if (!lock)
return 1;
-   ret |= delete_ref_loose(lock, flag);
+   ret |= delete_ref_loose(lock, flag, NULL);
 
/* removing the loose one could have resurrected an earlier
 * packed one.  Also, if it was not loose we need to repack
@@ -3494,7 +3520,8 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
 
if (update->lock) {
delnames[delnum++] = update->lock->ref_name;
-   ret |= delete_ref_loose(update->lock, update->type);
+   ret |= delete_ref_loose(update->lock, update->type,
+   err);
}
}
 
-- 
2.0.0.rc3.510.g20c254b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v10 00/44] Use ref transactions for all ref updates

2014-05-16 Thread Ronnie Sahlberg
This patch series can also be found at
https://github.com/rsahlberg/git/tree/ref-transactions


This patch series is based on next and expands on the transaction API. It
converts all ref updates, inside refs.c as well as external, to use the
transaction API for updates. This makes most of the ref updates to become
atomic when there are failures locking or writing to a ref.

This version completes the work to convert all ref updates to use transactions.
Now that all updates are through transactions I will start working on
cleaning up the reading of refs and to create an api for managing reflogs but
all that will go in a different patch series.

Version 10:
 - Add err argument to _update/_delete/_create
 - Remove the ref_transaction_rollback function
 - Other changes based on JN's reviews.

Version 9:
 - Lots of updates to error messages based on JN's review.

Version 8:
 - Updates after review by JN
 - Improve commit messages
 - Add a patch that adds an err argument to repack_without_refs
 - Add a patch that adds an err argument to delete_loose_ref
 - Better document that a _update/_delete/_create failure means the whole
   transaction has failed and needs rollback.

Version 7:
 - Updated commit messages per JNs review comments.
 - Changed REF_ISPRUNING and REF_ISPACKONLY to be private flags and not
   exposed through refs.h

Version 6:
 - Convert all updates in refs.c to use transactions too.

Version 5:
 - Reword commit messages for having _create/_delete/_update returning
   success/failure. There are no conditions yet that return an error from
   these failures but there will be in the future. So we still check the
   return from these functions in the callers in preparation for this.
 - Don't leak memory by just passing a strbuf_detach() pointer to functions.
   Use .buf and explicitely strbuf_release the data afterwards.
 - Remove the function update_ref_lock.
 - Remove the function update_ref_write.
 - Track transaction status and die(BUG:) if we call _create/_delete/_update/
   _commit for a transaction that is not OPEN.

Version 4:
 - Rename patch series from "Use ref transactions from most callers" to
   "Use ref transactions for all ref updates".
 - Convert all external ref writes to use transactions and make write_ref_sha1
   and lock_ref_sha1 static functions.
 - Change the ref commit and free handling so we no longer pass pointer to
   pointer to _commit. _commit no longer frees the transaction. The caller
   MUST call _free itself.
 - Change _commit to take a strbuf pointer instead of a char* for error
   reporting back to the caller.
 - Re-add the walker patch after fixing it.

Version 3:
 - Remove the walker patch for now. Walker needs more complex solution
   so defer it until the basics are done.
 - Remove the onerr argument to ref_transaction_commit(). All callers
   that need to die() on error now have to do this explicitely.
 - Pass an error string from ref_transaction_commit() back to the callers
   so that they can craft a nice error message upon failures.
 - Make ref_transaction_rollback() accept NULL as argument.
 - Change ref_transaction_commit() to take a pointer to pointer argument for
   the transaction and have it clear the callers pointer to NULL when
   invoked. This allows for much nicer handling of transaction rollback on
   failure.

Version 2:
 - Add a patch to ref_transaction_commit to make it honor onerr even if the
   error triggered in ref_Transaction_commit itself rather than in a call
   to other functions (that already honor onerr).
 - Add a patch to make the update_ref() helper function use transactions
   internally.
 - Change ref_transaction_update to die() instead of error() if we pass
   if a NULL old_sha1 but have have_old == true.
 - Change ref_transaction_create to die() instead of error() if new_sha1
   is false but we pass it a null_sha1.
 - Change ref_transaction_delete die() instead of error() if we pass
   if a NULL old_sha1 but have have_old == true.
 - Change several places to do  if(!transaction || ref_transaction_update()
   || ref_Transaction_commit()) die(generic-message) instead of checking each
   step separately and having a different message for each failure.
   Most users are likely not interested in what step of the transaction
   failed and only whether it failed or not.
 - Change commit.c to only pass a pointer to ref_transaction_update
   iff current_head is non-NULL.
   The previous patch used to compute a garbage pointer for
   current_head->object.sha1 and relied on the fact that ref_transaction_update
   would not try to dereference this pointer if !!current_head was 0.
 - Updated commit message for the walker_fetch change to try to justify why
   the change in locking semantics should not be harmful.



Ronnie Sahlberg (44):
  refs.c: constify the sha arguments for
ref_transaction_create|delete|update
  refs.c: allow passing NULL to ref_transaction_free
  refs.c: add a strbuf argument to ref_transaction_commit for error
log

Re: [PATCH 2/2] commit: allow core.commentChar=auto for character auto selection

2014-05-16 Thread Jonathan Nieder
Nguyễn Thái Ngọc Duy wrote:

> core.commentChar starts with '#' as in default but if it's already in
> the prepared message, find another one among a small subset. This
> should stop surprises because git strips some lines unexpectedly.

Probably worth mentioning this only kicks in if someone explicitly
configures [core] commentchar = auto.

Would it be a goal to make 'auto' the default eventually if people
turn out to like it?

[...]
> --- a/builtin/commit.c
> +++ b/builtin/commit.c
> @@ -594,6 +594,40 @@ static char *cut_ident_timestamp_part(char *string)
>   return ket;
>  }
>  
> +static void adjust_comment_line_char(const struct strbuf *sb)
> +{
> + char candidates[] = " @!#$%^&|:;~";

This prefers '@' over '#'.  Intended?

[...]
> + char *candidate;
> + const char *p;
> +
> + if (!sb->len)
> + return;
> +
> + if (!strchr(candidates, comment_line_char))
> + candidates[0] = comment_line_char;

Could do

if (!memchr(sb->buf, comment_line_char, sb->len))
return;

to solve the precedence problem.  The comment_line_char not appearing
in the message is the usual case and handling it separately means it
gets handled faster.

[...]
> --- a/config.c
> +++ b/config.c
> @@ -829,6 +829,8 @@ static int git_default_core_config(const char *var, const 
> char *value)
>   if (!ret) {
>   if (comment[0] && !comment[1])
>   comment_line_char = comment[0];
> + else if (!strcasecmp(comment, "auto"))
> + auto_comment_line_char = 1;

Is there a way to disable 'auto' if 'auto' is already set?

comment_line_char still can be set and matters when 'auto' is set.
Should they be separate settings?

> --- a/t/t7502-commit.sh
> +++ b/t/t7502-commit.sh
> @@ -563,4 +563,29 @@ test_expect_success 'commit --status with custom comment 
> character' '
[...]
> + GIT_EDITOR=.git/FAKE_EDITOR test_must_fail \

Shells make it obnoxiously hard to set a one-shot envvar while
calling a function without the setting leaking into later commands.

(
test_set_editor .git/FAKE_EDITOR &&
test_must_fail ...
)

or

test_must_fail env GIT_EDITOR=.git/FAKE_EDITOR ...

should do the trick.

Thanks and hope that helps,
Jonathan
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/2] config: be strict on core.commentChar

2014-05-16 Thread Jonathan Nieder
Nguyễn Thái Ngọc Duy wrote:

> --- a/config.c
> +++ b/config.c
> @@ -826,8 +826,12 @@ static int git_default_core_config(const char *var, 
> const char *value)
>   if (!strcmp(var, "core.commentchar")) {
>   const char *comment;
>   int ret = git_config_string(&comment, var, value);
> - if (!ret)
> - comment_line_char = comment[0];
> + if (!ret) {
> + if (comment[0] && !comment[1])
> + comment_line_char = comment[0];
> + else
> + return error("core.commentChar should only be 
> one character");
> + }

Perhaps, to decrease indentation a little:

if (ret)
return ret;
if (comment[0] && !comment[1])
comment_line_char = comment[0];
else
return error(...);
return 0;

[...]
> --- a/t/t7508-status.sh
> +++ b/t/t7508-status.sh
> @@ -1348,12 +1348,6 @@ test_expect_success "status (core.commentchar with 
> submodule summary)" '
>   test_i18ncmp expect output
>  '
>  
> -test_expect_success "status (core.commentchar with two chars with submodule 
> summary)" '
> - test_config core.commentchar ";;" &&
> - git -c status.displayCommentPrefix=true status >output &&
> - test_i18ncmp expect output

Could keep the test to avoid regressions:

test_config core.commentchar ";;" &&
test_must_fail git -c status.displayCommentPrefix=true status

Thanks,
Jonathan
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [GUILT v3 09/31] Test suite: properly check the exit status of commands.

2014-05-16 Thread Jeff Sipek
On Fri, May 16, 2014 at 04:45:56PM +0200, Per Cederqvist wrote:
> The "cmd" and "shouldfail" functions checked the exit status of the
> replace_path function instead of the actual command that was running.
> (The $? construct checks the exit status of the last command in a
> pipeline, not the first command.)
> 
> Updated t-032.sh, which used "shouldfail" instead of "cmd" in one
> place.  (The comment in the script makes it clear that the command is
> expected to succeed.)
> 
> Signed-off-by: Per Cederqvist 
> ---
>  regression/scaffold | 17 +++--
>  regression/t-032.sh |  2 +-
>  2 files changed, 12 insertions(+), 7 deletions(-)
> 
> diff --git a/regression/scaffold b/regression/scaffold
> index 5c8b73e..e4d7487 100644
> --- a/regression/scaffold
> +++ b/regression/scaffold
> @@ -51,18 +51,23 @@ function filter_dd
>  function cmd
>  {
>   echo "% $@"
> - "$@" 2>&1 | replace_path && return 0
> - return 1
> + (
> + exec 3>&1
> + rv=`(("$@" 2>&1; echo $? >&4) | replace_path >&3 ) 4>&1`

Wow.  This took a while to decipher :)

Signed-off-by: Josef 'Jeff' Sipek 


> + exit $rv
> + )
> + return $?
>  }
>  
>  # usage: shouldfail ..
>  function shouldfail
>  {
>   echo "% $@"
> - (
> - "$@" 2>&1 || return 0
> - return 1
> - ) | replace_path
> + ! (
> + exec 3>&1
> + rv=`(("$@" 2>&1; echo $? >&4) | replace_path >&3 ) 4>&1`
> + exit $rv
> + )
>   return $?
>  }
>  
> diff --git a/regression/t-032.sh b/regression/t-032.sh
> index b1d5f19..bba401e 100755
> --- a/regression/t-032.sh
> +++ b/regression/t-032.sh
> @@ -28,7 +28,7 @@ shouldfail guilt import -P foo3 foo
>  cmd guilt import -P foo2 foo
>  
>  # ok
> -shouldfail guilt import foo
> +cmd guilt import foo
>  
>  # duplicate patch name (implicit)
>  shouldfail guilt import foo
> -- 
> 1.8.3.1
> 

-- 
Fact: 28.1% of all statistics are generated randomly.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


  1   2   >