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

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

 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.

Once ref_transaction_begin() and ref_transaction_update() set err,
this will always have a reasonable message to print in die().

Reviewed-by: Jonathan Nieder jrnie...@gmail.com
--
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 17/44] fast-import.c: change update_branch to use ref transactions

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

 --- a/fast-import.c
 +++ b/fast-import.c
 @@ -1679,39 +1679,45 @@ 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);
   return error(Branch %s is missing commits., b-name);
   }

(style) Now that there's only one line in the if body, we can
drop the braces.

  
   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;

(not about this patch, feel free to ignore) This could
return warning(...)

   }
 - 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)) ||

Would be more idiomatic to drop a layer of parentheses:

if (!transaction ||
ref_transaction_update(...) ||

 + (ref_transaction_commit(transaction, msg, err) 
 +  !(transaction = NULL))) {

Would be clearer if ref_transaction_commit didn't take care of the
rollback (or in other words if patch 21 were earlier in the series).

 + ref_transaction_rollback(transaction);
 + error(Unable to update branch %s: %s, b-name, err.buf);
 + strbuf_release(err);
 + return -1;
 + }

Example old message:

error: Unable to lock refs/heads/master

New message:

error: Unable to update branch refs/heads/master: Cannot lock the ref 
'refs/heads/master'.

So 'error(%s, err.buf)' would probably work better.

The only call site is dump_branches:

for (i = 0; i  branch_table_sz; i++) {
for (b = branch_table[i]; b; b = b-table_next_branch)
failure |= update_branch(b);
}

Should these happen in a single transaction?  I haven't thought
through whether it would be a good idea, if it should be optional, or
what.

Anyway, that would be a bigger behavior change, but it's interesting
to think about.

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 v8 16/44] sequencer.c: use ref transactions for all ref updates

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

 --- a/sequencer.c
 +++ b/sequencer.c
 @@ -272,23 +272,31 @@ static int fast_forward_to(const unsigned char *to, 
 const unsigned char *from,
[...]
 + error(_(HEAD: Could not fast-forward: %s\n), err.buf);

As with 'git commit', since err.buf already mentions that HEAD was the
problematic ref I think it has enough information for the user to
diagnose the problem and figure out what to do next.

error(%s, err.buf);
--
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 18/44] branch.c: use ref transaction for all ref updates

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

 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.

Previously the ref lock was also held during setup_tracking, which
sets up configuration for the branch in .git/config.  So in principle
they were one transaction and this patch would change that.

The race:

checkout -B master origin/master

update-ref -d refs/heads/master
---
checkout -B master 
other/master

---
create ref
delete ref
create ref

configure tracking  configure tracking

Since setup_tracking is not a single transaction, if the two processes
are lucky enough to not try to write to .git/config at the same time
then the resulting configuration could have branch.master.merge set
by the first checkout -b and branch.master.remote set by the second.

But trying to checkout -b the same branch in two terminals
concurrently is a somewhat insane thing to do, so I don't mind
breaking it.

[...]
 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 existsing. I.e. one thread could end 
 up

s/existsing/existing/

 overwriting a branch even if the forcing flag is false.

Good catch.

 --- a/branch.c
 +++ b/branch.c
[...]
 @@ -301,13 +291,25 @@ void create_branch(const char *head,
[...]
 + if (!transaction ||
 + ref_transaction_update(transaction, ref.buf, sha1,
 +null_sha1, 0, !forcing) ||
 + ref_transaction_commit(transaction, msg, err))
 + die_errno(_(%s: failed to write ref: %s),
 +   ref.buf, err.buf);

errno is not guaranteed valid here.  The usual

die(%s, err.buf);

should do the trick.

With the changes mentioned above (commit message typofix, die()
message),
Reviewed-by: Jonathan Nieder jrnie...@gmail.com

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: [PATCH v8 19/44] refs.c: change update_ref to use a transaction

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

 Change the update_ref helper function to use a ref transaction internally.
 
 Signed-off-by: Ronnie Sahlberg sahlb...@google.com
 ---
  refs.c | 25 +
  1 file changed, 21 insertions(+), 4 deletions(-)
 
 diff --git a/refs.c b/refs.c
 index 6e5e940..0476892 100644
 --- a/refs.c
 +++ b/refs.c
 @@ -3416,11 +3416,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)) ||
 + (ref_transaction_commit(t, action, err)  !(t = NULL))) {
 + const char *str = update_ref failed for ref '%s': %s;
 +
 + ref_transaction_rollback(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;
 + }

The error string already contains the refname, so it would make sense to
do

case UPDATE_REFS_MSG_ON_ERR:
error(%s, err.buf); break;

etc here.

It occurs to me now that if ref_transaction_begin fails, presumably
the error string would not contain the refname.  I want to say that
the refname wouldn't help much in diagnosing or recovering from the
problem in that case so it would still be okay to just do error(%s,
err.buf).  What do you think?

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 v8 21/44] refs.c: ref_transaction_commit should not free the transaction

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

 Change ref_transaction_commit so that it does not free the transaction.
 Instead require that a caller will end a transaction by either calling
 ref_transaction_rollback or ref_transaction_free.

Can I always use ref_transaction_rollback instead of ref_transaction_free?
It would be convenient if my cleanup code could always call _rollback
instead of having to do something different for success and errors.

Another way to ask the question: what is it valid to do with a
transaction after commiting?

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 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: [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 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_unsafe(const char 

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 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 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 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/RFC] send-pack.c: Allow to disable side-band-64k

2014-05-19 Thread Jonathan Nieder
Hi,

Thomas Braun wrote:

 pushing over the dump git protocol with a windows git client.

I've never heard of the dump git protocol.  Do you mean the git
protocol that's used with git:// URLs?

[...]
 Alternative approaches considered but deemed too invasive:
 - Rewrite read/write wrappers in mingw.c in order to distinguish between
   a file descriptor which has a socket behind and a file descriptor
   which has a file behind.

I assume here too invasive means too much engineering effort?

It sounds like a clean fix, not too invasive at all.  But I can
understand wanting a stopgap in the meantime.

 - Turning the capability side-band-64k off completely. This would remove a 
 useful
   feature for users of non-affected transport protocols.

Would it make sense to turn off sideband unconditionally on Windows
when using the relevant protocols?

I assume someone on the list wouldn't mind writing such a patch, so I
don't think the engineering effort would be a problem for that.

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 00/19] convert test -a/-o to and || patch series

2014-05-20 Thread Jonathan Nieder
Hi,

Elia Pinto wrote:

 These patch series  convert test -a/-o to  and ||.

Should this come with a new check in t/check-non-portable-shell.pl so
we don't regress in the future?

 Elia Pinto (19):
[...]
  check_bindir|2 +-
  contrib/examples/git-clone.sh   |2 +-
  contrib/examples/git-commit.sh  |4 ++--
  contrib/examples/git-merge.sh   |4 ++--
  contrib/examples/git-repack.sh  |4 ++--
  contrib/examples/git-resolve.sh |2 +-
  git-bisect.sh   |2 +-
  git-mergetool.sh|4 ++--
  git-rebase--interactive.sh  |2 +-
  git-submodule.sh|   29 +
  t/t0025-crlf-auto.sh|6 +++---
  t/t0026-eol-config.sh   |8 
  t/t4102-apply-rename.sh |2 +-
  t/t5000-tar-tree.sh |2 +-
  t/t5403-post-checkout-hook.sh   |8 
  t/t5537-fetch-shallow.sh|2 +-
  t/t5538-push-shallow.sh |2 +-
  t/t9814-git-p4-rename.sh|4 ++--
  t/test-lib-functions.sh |4 ++--
  19 files changed, 49 insertions(+), 44 deletions(-)

I still think one patch per file is too many patches for this.  It would
be easier to read with, e.g., whichever ones were most complex as
separate patches and the rest (the easy ones) as a single patch.

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 v8 25/44] receive-pack.c: use a reference transaction for updating the refs

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

 Wrap all the ref updates inside a transaction to make the update atomic.

Interesting.

[...]
 --- 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;

I think it would be cleaner for err to be local.  It isn't used for
communication between functions.

[...]
 @@ -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;

The original used rp_error to send an error message immediately via
sideband.  This drops that --- intended?

The old error string shown on the push status line was was failed to
lock or failed to write which makes it clear that the cause is
contention or database problems or filesystem problems, respectively.
After this change it would say failed to update which is about as
clear as failed.

Would it be safe to send err.buf as-is over the wire, or does it
contain information or formatting that wouldn't be suitable for the
client?  (I haven't thought this through completely yet.)  Is there
some easy way to distinguish between failure to lock and failure to
write?  Or is there some one-size-fits-all error for this case?

When the transaction fails, we need to make sure that all ref updates
emit 'ng' and not 'ok' in receive-pack.c::report (see the example at
the end of Documentation/technical/pack-protocol.txt for what this
means).  What error string should they use?  Is there some way to make
it clear to the user which ref was the culprit?

What should happen when checks outside the ref transaction system
cause a ref update to fail?  I'm thinking of

 * per-ref 'update' hook (see githooks(5))
 * fast-forward check
 * ref creation/deletion checks
 * attempt to push to the currently checked out branch

I think the natural thing to do would be to put each ref update in its
own transaction to start so the semantics do not change right away.
If there are obvious answers to all these questions, then a separate
patch could combine all these into a single transaction; or if there
are no obvious answers, we could make the single-transaction-per-push
semantics optional (using a configuration variable or protocol
capability or something) to make it possible to experiment.

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 v8 26/44] fast-import.c: use a ref transaction when dumping tags

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

 [Subject: fast-import.c: use a ref transaction when dumping tags]

This seems like an odd thing to do: either it would make sense to have
a single transaction for all imported refs so all fail or succeed
together, or there would be separate transactions for each ref.

That said, I don't mind, particularly if it's a step on the way to
using a single transaction for everything being dumped.

[...]
 --- a/fast-import.c
 +++ b/fast-import.c
 @@ -1736,15 +1736,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);
 + sprintf(ref_name, refs/tags/%s, t-name);

Can this overflow the buffer?

 - 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);
 +
 + if (ref_transaction_update(transaction, ref_name, t-sha1,
 +NULL, 0, 0, err)) {
 + failure |= 1;
 + break;
 + }
   }
 + if (failure || ref_transaction_commit(transaction, msg, err))
 + failure |= error(Unable to update %s, err.buf);

This 'if (failure || ...) failure |=' idiom seems strange.
Is err.buf always set if failure is nonzero?

Elsewhere failure is 0 or -1 but this introduces the possibility for
it to be temporarily 1.

dump_branches could have caused failure to be -1 before dump_tags
is called.  I think the intent is

if (ref_transaction_update(...)) {
failure |= error(...);
goto out;
}
}
if (ref_transaction_commit(...))
failure |= error(...);
 out:
ref_transaction_free(transaction);
...

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/RFC] t0000-*.sh: Fix the GIT_SKIP_TESTS sub-tests

2014-05-20 Thread Jonathan Nieder
Ramsay Jones wrote:

 --- a/t/t-basic.sh
 +++ b/t/t-basic.sh
 @@ -296,8 +296,9 @@ test_expect_success 'test --verbose-only' '
  '
  
  test_expect_success 'GIT_SKIP_TESTS' 
 - GIT_SKIP_TESTS='git.2' \
 - run_sub_test_lib_test git-skip-tests-basic \
 + GIT_SKIP_TESTS='git.2'  export GIT_SKIP_TESTS 
 + test_when_finished sane_unset GIT_SKIP_TESTS 

Oof.  Good catch.

What should happen if I have set GIT_SKIP_TESTS explicitly to run
only some of the tests in t-basic?

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/RFC] t0000-*.sh: Fix the GIT_SKIP_TESTS sub-tests

2014-05-20 Thread Jonathan Nieder
Hi,

Ramsay Jones wrote:
 On 20/05/14 22:40, Jonathan Nieder wrote:

 What should happen if I have set GIT_SKIP_TESTS explicitly to run
 only some of the tests in t-basic?

 A quick test (with the above patch applied) shows that
 it works as I would expect:

   $  GIT_SKIP_TESTS=t.1[2-6] ./t-basic.sh
   ...
   ok 11 - test --verbose
   ok 12 # skip test --verbose-only (GIT_SKIP_TESTS)
   ok 13 # skip GIT_SKIP_TESTS (GIT_SKIP_TESTS)
   ok 14 # skip GIT_SKIP_TESTS several tests (GIT_SKIP_TESTS)
   ok 15 # skip GIT_SKIP_TESTS sh pattern (GIT_SKIP_TESTS)
   ok 16 # skip --run basic (GIT_SKIP_TESTS)
   ok 17 - --run with a range

Try GIT_SKIP_TESTS=t.17 ./t-basic.sh:

 ok 13 - GIT_SKIP_TESTS
 ok 14 - GIT_SKIP_TESTS several tests
 ok 15 - GIT_SKIP_TESTS sh pattern
 ok 16 - --run basic
 ok 17 - --run with a range

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 v8 27/44] walker.c: use ref transaction for ref updates

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

 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.

Sounds scary.  The usual approach is

old_sha1 = ...
... various checks ...

transaction = transaction_begin(err)
transaction_update(transaction, refname, new_sha1, old_sha1, ...);
transaction_commit(transaction, err);

which is not racy because _update checks against old_sha1.

If I understand correctly, you are saying 'have_old' is false here so
we don't have the usual protection.  If the ... various checks ...
section shown above is empty, that should be fine and there is no
actual change in semantics.  If the ... various checks ... section
shown above is nonempty then it could be a problem.

[...]
 --- 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];

We tend to prefer strbuf instead of fixed-size buffers in new code.

[...]
 - char *msg;
 + char *msg = NULL;

Needed?  The existing code seems to set msg = NULL in the
!write_ref_log_details case already.

[...]
 @@ -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));

Okay, so before this patch we do:

for each target in write_ref:
lock it (with no particular expectation about where it
points)

Then

unless http-fetch was passed --recover:
mark the objects pointed to by current refs as COMPLETE

Then we do HTTP GETs to grab the objects we need from a dumb HTTP
server.  The COMPLETE objects tell us about objects we don't have to
bother trying to get.

When we're done, we come up with a reflog entry and write out refs
pointing to the requested commits.

This code has two callers:

git-remote-http (aka remote-curl.c::fetch_dumb)
git-http-fetch (aka http-fetch.c)

The codepath in git-remote-http gets wide use, though it's diminishing
as more people switch to smart http.  It doesn't 't use the write
out some refs feature.  It just wants the objects and then takes care
of writing refs on its own.

Perhaps it's worth avoiding beginning a transaction in the first place
in the !write_ref case.

The git-http-fetch command is a piece of plumbing that used to be used
by 'git clone' and 'git fetch' in the olden days when they were shell
scripts.  I doubt anyone uses it.  As you noticed, it doesn't have any
way to specify anything about the expected old values of the refs it
writes to.  So this change doesn't introduce any race there.

 + sprintf(ref_name, refs/%s, write_ref[i]);
 + if (ref_transaction_update(transaction, ref_name,
 +sha1[20 * i], NULL,
 +0, 0))
 + goto rollback_and_fail;
 + }

Looks good.

 +
 + if (ref_transaction_commit(transaction, msg ? msg : fetch (unknown),
 +err)) {
 + error(%s, err.buf);
 + goto rollback_and_fail;
   }

Also looks good.

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 v8 28/44] refs.c: make write_ref_sha1 static

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

 No external users call write_ref_sha1 any more so lets declare it static.

Yay!

[...]
 +++ 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);

Is this forward declaration needed?

[...]
 --- 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);

(nit) Would be nice to keep the documentation comment.

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 v8 29/44] refs.c: make lock_ref_sha1 static

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

 No external callers reference lock_ref_sha1 any more so lets declare it 
 static.

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

Reviewed-by: Jonathan Nieder jrnie...@gmail.com
--
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 30/44] refs.c: add transaction.status and track OPEN/CLOSED/ERROR

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

 --- a/refs.c
 +++ b/refs.c
 @@ -3308,6 +3308,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,

What is the difference between _TRANSACTION_CLOSED and
_TRANSACTION_ERROR?

[...]
 @@ -3340,6 +3347,11 @@ void ref_transaction_free(struct ref_transaction 
 *transaction)
  
  void ref_transaction_rollback(struct ref_transaction *transaction)
  {
 + if (!transaction)
 + return;
 +
 + transaction-status = REF_TRANSACTION_ERROR;
 +
   ref_transaction_free(transaction);

Once the transaction is freed, transaction-status is not reachable any
more so no one can tell that you've set it to _ERROR.  What is the
intended effect?

[...]
 @@ -3366,6 +3378,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);

Ok.

[...]
 @@ -3538,6 +3564,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;

Nit: odd use of whitespace.

Overall thoughts: I like the idea of enforcing the API more strictly
(after an error, the only permitted operations are...).  The details
leave me a little confused because I don't think anything is
distinguishing between _CLOSED and _ERROR.  Maybe the enum only needs
two states.

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 v8 31/44] refs.c: remove the update_ref_lock function

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

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

Reviewed-by: Jonathan Nieder jrnie...@gmail.com
--
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 32/44] refs.c: remove the update_ref_write function

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

 +++ b/refs.c
[...]
 @@ -3518,14 +3499,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);
 + ret = write_ref_sha1(update-lock, update-new_sha1,
 +  msg);

This changes the return value on error from 1 to -1.  That seems like a
good change.  It's probably worth mentioning in the commit 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


Re: [PATCH] builtin/log.c: fix minor memory leak

2014-08-07 Thread Jonathan Nieder
Matthieu Moy wrote:

 Signed-off-by: Matthieu Moy matthieu@imag.fr
 ---
 Valgrind confirms, one less unreachable block ;-).

This belongs in the commit message.

[...]
 --- a/builtin/log.c
 +++ b/builtin/log.c
 @@ -857,20 +857,21 @@ static void add_branch_description(struct strbuf *buf, 
 const char *branch_name)
  {
   struct strbuf desc = STRBUF_INIT;
   if (!branch_name || !*branch_name)
   return;
   read_branch_desc(desc, branch_name);
   if (desc.len) {
   strbuf_addch(buf, '\n');
   strbuf_addbuf(buf, desc);
   strbuf_addch(buf, '\n');
   }
 + strbuf_release(desc);

This is an old one.  The leak was introduced by v1.7.9-rc1~1^2~12
(format-patch: use branch description in cover letter, 2011-09-21).

I was a little scared to see a leak in 'git log' code, since most of
what log does involves looping over many commits.  Luckily this one is
only used in make_cover_letter to create a cover letter describing the
single branch on the command line, making it is a small, one-time
leak.

Less noise from static and dynamic analysis tools is still worthwhile,
so for what it's worth,

Reviewed-by: Jonathan Nieder jrnie...@gmail.com

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: possibly a spurious conflict in a three way merge

2014-08-07 Thread Jonathan Nieder
Hi,

meanlo...@gmail.com wrote:

 2. commit test.txt to master:
 line1
 line1

 3. branch and checkout branch1
 4. make and commit the following change to branch1:
 #line1
 #line2

 5. checkout master
 6. make and commit the following change to master:
 line1
 #line2

 7. merge branch1, git sees a conflict:
  HEAD
 line1
 ===
 #line1
  branch1
 #line2

 Why?

Thanks for a clear example.  On branch1 you made the following change:

 (a) modify lines 1 and 2

On master, you made a different change:

 (b) just modify line 2

The changes touch the same chunk of lines and don't produce the same
result there.  Git is being conservative and letting you know that the
two branches didn't agree about what line 1 should say.

On the other hand, if you had a larger files and on branch1 made the
following change:

 (a) modify lines 1 and 101

and on master, you made a different change:

 (b) just modify line 101

then the changes are touching different parts of the code and are
merged independently.  The result would be a clean merge where lines 1
and 101 are both modified.

Git's conservatism can be helpful when working with code, where
adjacent lines are likely to be affecting a single behavior and the
conflict can help the operator to know to be extra careful.  It makes
less sense for line-oriented input where every line is independent.

If you are often making changes to a line-oriented file, it may make
sense to set up a custom merge driver to override git's merge behavior
for that file.  See 'Defining a custom merge driver' in
gitattributes(5) for details about how that works.

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


[PATCH] Update hard-coded header dependencies

2014-08-08 Thread Jonathan Nieder
The fall-back rules used when compilers don't support the -MMD switch
to generate makefile rules based on #includes have been out of date
since v1.7.12.1~22^2~8 (move git_version_string into version.c,
2012-06-02).

Checked with 'make CHECK_HEADER_DEPENDENCIES=yes'.

Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
Maybe it's worth switching to plain

LIB_H += $(wildcard *.h)

?  People using ancient compilers that never change headers wouldn't
be hurt, people using modern compilers that do change headers also
wouldn't be hurt, and we could stop pretending to maintain an
up-to-date list.

 Makefile | 8 
 1 file changed, 8 insertions(+)

diff --git a/Makefile b/Makefile
index 2320de5..18f0fad 100644
--- a/Makefile
+++ b/Makefile
@@ -646,15 +646,19 @@ LIB_H += cache.h
 LIB_H += color.h
 LIB_H += column.h
 LIB_H += commit.h
+LIB_H += commit-slab.h
+LIB_H += compat/apple-common-crypto.h
 LIB_H += compat/bswap.h
 LIB_H += compat/mingw.h
 LIB_H += compat/obstack.h
 LIB_H += compat/poll/poll.h
 LIB_H += compat/precompose_utf8.h
 LIB_H += compat/terminal.h
+LIB_H += compat/win32/alloca.h
 LIB_H += compat/win32/dirent.h
 LIB_H += compat/win32/pthread.h
 LIB_H += compat/win32/syslog.h
+LIB_H += connect.h
 LIB_H += connected.h
 LIB_H += convert.h
 LIB_H += credential.h
@@ -678,6 +682,7 @@ LIB_H += grep.h
 LIB_H += hashmap.h
 LIB_H += help.h
 LIB_H += http.h
+LIB_H += khash.h
 LIB_H += kwset.h
 LIB_H += levenshtein.h
 LIB_H += line-log.h
@@ -721,6 +726,7 @@ LIB_H += sha1-lookup.h
 LIB_H += shortlog.h
 LIB_H += sideband.h
 LIB_H += sigchain.h
+LIB_H += split-index.h
 LIB_H += strbuf.h
 LIB_H += streaming.h
 LIB_H += string-list.h
@@ -728,6 +734,7 @@ LIB_H += submodule.h
 LIB_H += tag.h
 LIB_H += tar.h
 LIB_H += thread-utils.h
+LIB_H += trace.h
 LIB_H += transport.h
 LIB_H += tree-walk.h
 LIB_H += tree.h
@@ -744,6 +751,7 @@ LIB_H += vcs-svn/repo_tree.h
 LIB_H += vcs-svn/sliding_window.h
 LIB_H += vcs-svn/svndiff.h
 LIB_H += vcs-svn/svndump.h
+LIB_H += version.h
 LIB_H += walker.h
 LIB_H += wildmatch.h
 LIB_H += wt-status.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] mailsplit.c: remove dead code

2014-08-12 Thread Jonathan Nieder
Stefan Beller wrote:

 This was found by coverity. (Id: 290001)
[...]
 Signed-off-by: Stefan Beller stefanbel...@gmail.com
 Helped-by: René Scharfe l@web.de
 ---
  builtin/mailsplit.c | 17 ++---
  1 file changed, 6 insertions(+), 11 deletions(-)

The idea is to simplify error handling (removing cleanup of the
'output' var) by making it more obvious that there is only one kind of
error, right?

For what it's worth, it looks good to me (and much clearer than the
last version).  It's always possible to reintroduce goto-based error
handling later if another kind of error is introduced, and in the
meantime this is simpler and does not change behavior.

Reviewed-by: Jonathan Nieder jrnie...@gmail.com

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


[PATCH 0/3] Re: [PATCH] unpack-tree.c: remove dead code

2014-08-12 Thread Jonathan Nieder
Stefan Beller wrote:

 In line 1763 of unpack-tree.c we have a condition on the current tree
[...]

The description is describing why the patch is *correct* (i.e., not
going to introduce a bug), while what the reader wants to know is why
the change is *desirable*.

Is this about making the code more readable, or robust, or suppressing
a static analysis error, or something else?  What did the user or
reader want to do that they couldn't do before and now can after this
patch?

[...]
 --- a/unpack-trees.c
 +++ b/unpack-trees.c
 @@ -1789,15 +1789,11 @@ int twoway_merge(const struct cache_entry * const 
 *src,
   /* 20 or 21 */
   return merged_entry(newtree, current, o);
   }
 + else if (o-gently) {
 + return  -1 ;
 + }

(not about this patch) Elsewhere git uses the 'cuddled else':

if (foo) {
...
} else if (bar) {
...
} else {
...
}

That stylefix would be a topic for a different patch, though.

   else {
 - /* all other failures */
 - if (oldtree)
 - return o-gently ? -1 : reject_merge(oldtree, 
 o);
 - if (current)
 - return o-gently ? -1 : reject_merge(current, 
 o);
 - if (newtree)
 - return o-gently ? -1 : reject_merge(newtree, 
 o);
 - return -1;

Does the static analysis tool support comments like

if (oldtree)
...
if (current)
...
...

/* not reached */
return -1;

?  That might be the simplest minimally invasive fix for what coverity
pointed out.

Now that we're looking there, though, it's worth understanding why we
do the 'if oldtree exists, use it, else fall back to, etc' thing.  Was
this meant as futureproofing in case commands like 'git checkout' want
to do rename detection some day?

Everywhere else in the file that reject_merge is used, it is as

return o-gently ? -1 : reject_merge(..., o);

The one exception is

!current 
oldtree 
newtree 
oldtree != newtree 
!initial_checkout

(#17), which seems like a bug (it should have the same check).  Would
it make sense to inline the o-gently check into reject_merge so callers
don't have to care?

In that spirit, I suspect the simplest fix would be

else
return o-gently ? -1 : reject_merge(current, o);

and then all calls could be replaced in a followup patch.

Sensible?

Thanks,

Jonathan Nieder (2):
  unpack-trees: use 'cuddled' style for if-else cascade
  checkout -m: attempt merge when deletion of path was staged

Stefan Beller (1):
  unpack-trees: simplify 'all other failures' case

 unpack-trees.c | 31 ++-
 1 file changed, 10 insertions(+), 21 deletions(-)
--
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 1/3] unpack-trees: simplify 'all other failures' case

2014-08-12 Thread Jonathan Nieder
From: Stefan Beller stefanbel...@gmail.com

In the 'if (current)' block of twoway_merge, we handle the boring
errors by checking if the entry from the old tree, current index, and
new tree are present, to get a pathname for the error message from one
of them:

if (oldtree)
return o-gently ? -1 : reject_merge(oldtree, o);
if (current)
return o-gently ? -1 : reject_merge(current, o);
if (newtree)
return o-gently ? -1 : reject_merge(newtree, o);
return -1;

Since this is guarded by 'if (current)', the second test is guaranteed
to succeed.  Moreover, any of the three entries, if present, would
have the same path because there is no rename detection in this code
path.   Even if some day in the future the entries' paths differ, the
'current' path used in the index and worktree would presumably be the
most recognizable for the end user.

Simplify by just using 'current'.

Noticed by coverity, Id:290002

Signed-off-by: Stefan Beller stefanbel...@gmail.com
Improved-by: Junio C Hamano gits...@pobox.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 unpack-trees.c | 12 ++--
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/unpack-trees.c b/unpack-trees.c
index ad3e9a0..f4a9aa9 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1791,16 +1791,8 @@ int twoway_merge(const struct cache_entry * const *src,
/* 20 or 21 */
return merged_entry(newtree, current, o);
}
-   else {
-   /* all other failures */
-   if (oldtree)
-   return o-gently ? -1 : reject_merge(oldtree, 
o);
-   if (current)
-   return o-gently ? -1 : reject_merge(current, 
o);
-   if (newtree)
-   return o-gently ? -1 : reject_merge(newtree, 
o);
-   return -1;
-   }
+   else
+   return o-gently ? -1 : reject_merge(current, o);
}
else if (newtree) {
if (oldtree  !o-initial_checkout) {
-- 
--
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 2/3] unpack-trees: use 'cuddled' style for if-else cascade

2014-08-12 Thread Jonathan Nieder
Match the predominant style in git by following KR style for if/else
cascades.  Documentation/CodingStyle from linux.git explains:

  Note that the closing brace is empty on a line of its own, _except_ in
  the cases where it is followed by a continuation of the same statement,
  ie a while in a do-statement or an else in an if-statement, like
  this:

if (x == y) {
..
} else if (x  y) {
...
} else {

}

  Rationale: KR.

  Also, note that this brace-placement also minimizes the number of empty
  (or almost empty) lines, without any loss of readability.

Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 unpack-trees.c | 12 
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/unpack-trees.c b/unpack-trees.c
index f4a9aa9..187b15b 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1771,8 +1771,7 @@ int twoway_merge(const struct cache_entry * const *src,
return merged_entry(newtree, current, 
o);
}
return o-gently ? -1 : reject_merge(current, o);
-   }
-   else if ((!oldtree  !newtree) || /* 4 and 5 */
+   } else if ((!oldtree  !newtree) || /* 4 and 5 */
 (!oldtree  newtree 
  same(current, newtree)) || /* 6 and 7 */
 (oldtree  newtree 
@@ -1781,17 +1780,14 @@ int twoway_merge(const struct cache_entry * const *src,
  !same(oldtree, newtree)  /* 18 and 19 */
  same(current, newtree))) {
return keep_entry(current, o);
-   }
-   else if (oldtree  !newtree  same(current, oldtree)) {
+   } else if (oldtree  !newtree  same(current, oldtree)) {
/* 10 or 11 */
return deleted_entry(oldtree, current, o);
-   }
-   else if (oldtree  newtree 
+   } else if (oldtree  newtree 
 same(current, oldtree)  !same(current, newtree)) {
/* 20 or 21 */
return merged_entry(newtree, current, o);
-   }
-   else
+   } else
return o-gently ? -1 : reject_merge(current, o);
}
else if (newtree) {
-- 
--
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 3/3] checkout -m: attempt merge when deletion of path was staged

2014-08-12 Thread Jonathan Nieder
twoway_merge() is missing an o-gently check in the case where a file
that needs to be modified is missing from the index but present in the
old and new trees.  As a result, in this case 'git checkout -m' errors
out instead of trying to perform a merge.

Fix it by checking o-gently.  While at it, inline the o-gently check
into reject_merge to prevent future call sites from making the same
mistake.

Noticed by code inspection.  The motivating case hasn't been tested.

Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
This is the most iffy of the three patches, mostly because I was too
lazy to write a test.  I believe it's safe as-is nonetheless.

Thanks for reading.

 unpack-trees.c | 11 ++-
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/unpack-trees.c b/unpack-trees.c
index 187b15b..6c45af7 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1178,7 +1178,8 @@ return_failed:
 static int reject_merge(const struct cache_entry *ce,
struct unpack_trees_options *o)
 {
-   return add_rejected_path(o, ERROR_WOULD_OVERWRITE, ce-name);
+   return o-gently ? -1 :
+   add_rejected_path(o, ERROR_WOULD_OVERWRITE, ce-name);
 }
 
 static int same(const struct cache_entry *a, const struct cache_entry *b)
@@ -1633,7 +1634,7 @@ int threeway_merge(const struct cache_entry * const 
*stages,
/* #14, #14ALT, #2ALT */
if (remote  !df_conflict_head  head_match  !remote_match) {
if (index  !same(index, remote)  !same(index, head))
-   return o-gently ? -1 : reject_merge(index, o);
+   return reject_merge(index, o);
return merged_entry(remote, index, o);
}
/*
@@ -1641,7 +1642,7 @@ int threeway_merge(const struct cache_entry * const 
*stages,
 * make sure that it matches head.
 */
if (index  !same(index, head))
-   return o-gently ? -1 : reject_merge(index, o);
+   return reject_merge(index, o);
 
if (head) {
/* #5ALT, #15 */
@@ -1770,7 +1771,7 @@ int twoway_merge(const struct cache_entry * const *src,
else
return merged_entry(newtree, current, 
o);
}
-   return o-gently ? -1 : reject_merge(current, o);
+   return reject_merge(current, o);
} else if ((!oldtree  !newtree) || /* 4 and 5 */
 (!oldtree  newtree 
  same(current, newtree)) || /* 6 and 7 */
@@ -1788,7 +1789,7 @@ int twoway_merge(const struct cache_entry * const *src,
/* 20 or 21 */
return merged_entry(newtree, current, o);
} else
-   return o-gently ? -1 : reject_merge(current, o);
+   return reject_merge(current, o);
}
else if (newtree) {
if (oldtree  !o-initial_checkout) {
-- 
--
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] git-imap-send: use libcurl for implementation

2014-08-12 Thread Jonathan Nieder
Bernhard Reiter wrote:

 Use libcurl's high-level API functions to implement git-imap-send
 instead of the previous low-level OpenSSL-based functions.

Wow!  This sounds lovely.  Thanks for working on this.

[...]
 Since version 7.30.0, libcurl's API has been able to communicate with
 IMAP servers. Using those high-level functions instead of the current
 ones reduces imap-send.c by some 1200 lines of code.

 As I don't have access to that many IMAP servers, I haven't been able to
 test a variety of parameter combinations. I did test both secure and
 insecure (imaps:// and imap://) connections -- this e-mail was generated
 that way -- but could e.g. neither test the authMethod nor the tunnel
 parameter.

The above two paragraphs belong in the commit message, too, since
they'll be just as useful for someone looking back through the history
as for someone reading the patch on-list today.

[...]
 --- a/INSTALL
 +++ b/INSTALL
[...]
 - - libcurl library is used by git-http-fetch and git-fetch.  You
 + - libcurl library is used by git-http-fetch, git-fetch, and
 +   git-impap-send.  You might also want the curl executable for

Typo: s/impap-send/imap-send/

 --- a/Makefile
 +++ b/Makefile
 @@ -2067,9 +2067,9 @@ endif
  git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
   $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) 
 $(LIBS)
  
 -git-imap-send$X: imap-send.o GIT-LDFLAGS $(GITLIBS)
 +git-imap-send$X: imap-send.o http.o GIT-LDFLAGS $(GITLIBS)
   $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 - $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)
 + $(LIBS) $(CURL_LIBCURL)

7.30.0 is only ~1 year old.  Does this mean users would need to update
curl in order to build imap-send?

For example, Debian 7.6 ships curl 7.26.0 and CentOS 7 has curl 7.29.0.

Ideally this could be done as an optional feature:

 1. Introduce a USE_CURL_FOR_IMAP_SEND makefile variable to take
advantage of the nice new API.

 2. (optional) Use the curl_check makefile variable to turn on
USE_CURL_FOR_IMAP_SEND automatically when appropriate.

 3. In a few years, when everyone has upgraded, we could simplify by
getting rid of the USE_OPENSSL_FOR_IMAP_SEND code path.

What do you think?

[...]
 --- a/imap-send.c
 +++ b/imap-send.c
 @@ -22,47 +22,13 @@
   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
  
 -#include cache.h

Usual style is to start with a #include of cache.h or
git-compat-util.h.  http.h including cache.h for itself was an
old mistake.  (I'll reply with a patch to fix that.)

[...]
 +#include curl/curl.h

http.h already #includes this.  Do you use other helpers from
http.h/http.c or do you use libcurl directly?  (Just curious.)

Some style nits:

[...]
 +static curl_socket_t opensocket(void *clientp, curlsocktype purpose,
 + struct 
 curl_sockaddr *address)

Long line.  Do you have ts=4?  (Git uses 8-space tabs.  There's some
emacs magic in Documentation/CodingGuidelines.  It should be possible
to add similar hints there for other editors if they don't do the
right thing by default.)

 +{
 + curl_socket_t sockfd;
 + (void)purpose;
 + (void)address;

Elsewhere git lets unused parameters be.  The unused parameter warning
is too noisy in callback-heavy code (e.g., for_each_ref) so we don't
turn it on.

 + sockfd = *(curl_socket_t *)clientp;
 + /* the actual externally set socket is passed in via the OPENSOCKETDATA
 +option */

(style nit) Comments in git look like this:

/*
 * The actual, externally set socket is passed in via the
 * OPENSOCKETDATA option.
 */
return sockfd;

[...]
 +static int sockopt_callback(void *clientp, curl_socket_t curlfd,
 + curlsocktype purpose)
 +{
 + /* This return code was added in libcurl 7.21.5 */
 + return CURL_SOCKOPT_ALREADY_CONNECTED;

I'd drop the comment, unless there's some subtlety involved.  (E.g.,
is there some other return code that would be more appropriate but was
introudced later or something?)

[...]
 @@ -1368,12 +218,14 @@ static int git_imap_config(const char *key, const char 
 *val, void *cb)
  int main(int argc, char **argv)
  {
   struct strbuf all_msgs = STRBUF_INIT;
 - struct strbuf msg = STRBUF_INIT;
 + struct buffer msg = { STRBUF_INIT, 0 };

Ah, ok --- we do use http.c stuff.

[...]
 + char path[8192];
 + int pathlen;

I realize the old code only had 8192 for the IMAP command buffer,
but could this be a strbuf now, or is there some underlying limit
somewhere else?

[...]
 @@ -1417,31 +269,89 @@ int main(int argc, char **argv)
   return 1;
   }
  
 + curl_global_init(CURL_GLOBAL_ALL);

http.c seems to make the same mistake, but should the return value
from this be checked?

 - /* write it to the imap server */
 - 

Re: Git on Mac OS X 10.4.10

2014-08-14 Thread Jonathan Nieder
Hi Markus,

 export NO_APPLE_COMMON_CRYPTO=yes
 make configure
 CFLAGS=-O2 ./configure --without-tcltk --prefix=/usr/global
 make all

 compiles fine on 10.4.10. Would a configure patch checking for the
 existence of CommonHMAC.h and, if not found, defining this variable, be
 acceptable?

Yes, that sounds useful.

Orthogonal to that: a patch to the Darwin section of config.mak.uname
so you can build without the 'make configure' would be even more
welcome. :)

See Documentation/SubmittingPatches for details about how to
contribute to git.  (Or if you're short on time, see section 5 of that
file, Sign your work, and then push your code somewhere and tell us
about it.)

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: Relative submodule URLs

2014-08-18 Thread Jonathan Nieder
Hi,

Robert Dailey wrote:

 The documentation wasn't 100% clear on this, but I'm assuming by
 remote origin, it says that the relative URL is relative to the
 actual remote *named* origin (and it is not using origin as just a
 general terminology).

Thanks for reporting.  The remote used is the default remote that git
fetch without further arguments would use:

get_default_remote () {
curr_branch=$(git symbolic-ref -q HEAD)
curr_branch=${curr_branch#refs/heads/}
origin=$(git config --get branch.$curr_branch.remote)
echo ${origin:-origin}
}

The documentation is wrong.  git-fetch(1) doesn't provide a name for
this thing.  Any ideas for wording?

 Is there a way to specify (on a per-clone basis) which named remote
 will be used to calculate the URL for submodules?

Currently there isn't, short of reconfiguring the remote used by
default by git fetch.

 Various co-workers use the remote named central instead of
 upstream and fork instead of origin (because that just makes
 more sense to them and it's perfectly valid).

 However if relative submodules require 'origin' to exist AND also
 represent the upstream repository (in triangle workflow), then this
 breaks on several levels.

Can you explain further?  In a triangle workflow, git fetch will
pull from the 'origin' remote by default and will push to the remote
named in the '[remote] pushdefault' setting (see remote.pushdefault
in git-config(1)).  So you can do

[remote]
pushDefault = whereishouldpush

and then 'git fetch' and 'git fetch --recurse-submodules' will fetch
from origin and 'git push' will push to the whereishouldpush remote.

It might make sense to introduce a new

[remote]
default = whereishouldfetch

setting to allow the name origin above to be replaced, too.  Is that
what you mean?

Meanwhile it is hard to fork a project that uses relative submodule
URLs without also forking the submodules (or, conversely, to fork some
of the submodules of a project that uses absolute submodule URLs).
That's a real and serious problem but I'm not sure how it relates to
the names of remotes.  My preferred fix involves teaching git to read
a refs/meta/git (or similarly named) ref when cloning a project with
submodules and let settings from .gitmodules in that ref override
.gitmodules in other branches.  Is that what you were referring to?

Curious,
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 v20 43/48] refs.c: move the check for valid refname to lock_ref_sha1_basic

2014-08-20 Thread Jonathan Nieder
Hi,

Ronnie Sahlberg wrote:
 On Wed, Aug 20, 2014 at 7:52 AM, Michael Haggerty mhag...@alum.mit.edu 
 wrote:

 I'm a little worried that abandoning *all* refname checks could open us
 up to somehow trying to delete a reference with a name like
 ../../../../etc/passwd.  Either such names have to be prohibited
 somehow, or we have to be very sure that they can only come from trusted
 sources.

 I only set this flag from builtin/branch.c so it should only be used
 when a user runs 'git branch -D' from the command line.
 All other places where we delete branches we should still be checking
 the rename for badness.

Right, this should be safe for 'git branch -D' and 'git update-ref -d'.

But if we wanted to open it up in the future for 'git push --delete',
too, then it would be a way to break out of the repository on hosts where
people use git-shell instead of relying on filesystem permissions.  And
that wouldn't be good.

I think elsewhere git has some checks for does this pathname fall in
this directory.  Could that be reused here, too, to make sure the
resolved path is under the resolved $GIT_DIR/refs directory?

Alternatively, when a ref being deleted doesn't meet the
'check-ref-format' checks, would it make sense to check that it is one
of the refs you can get by iteration?

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: Transaction patch series overview

2014-08-20 Thread Jonathan Nieder
Hi,

Ronnie Sahlberg wrote:

 List, please see here an overview and ordering of the ref transaction
 patch series.

Thanks much for this.

[...]
 rs/ref-transaction-0
[...]
 Has been merged into next.

This is even part of master now, so if people have review comments
then they can make them most easily by submitting new patches on top.

 ref-transaction-1 (2014-07-16) 20 commits
 -
 Second batch of ref transactions

  - refs.c: make delete_ref use a transaction
  - refs.c: make prune_ref use a transaction to delete the ref
  - refs.c: remove lock_ref_sha1
  - refs.c: remove the update_ref_write function
  - refs.c: remove the update_ref_lock function
  - refs.c: make lock_ref_sha1 static
  - walker.c: use ref transaction for ref updates
  - fast-import.c: use a ref transaction when dumping tags
  - receive-pack.c: use a reference transaction for updating the refs
  - refs.c: change update_ref to use a transaction
  - branch.c: use ref transaction for all ref updates
  - fast-import.c: change update_branch to use ref transactions
  - sequencer.c: use ref transactions for all ref updates
  - commit.c: use ref transactions for updates
  - replace.c: use the ref transaction functions for updates
  - tag.c: use ref transactions when doing updates
  - refs.c: add transaction.status and track OPEN/CLOSED/ERROR
  - refs.c: make ref_transaction_begin take an err argument
  - refs.c: update ref_transaction_delete to check for error and return status
  - refs.c: change ref_transaction_create to do error checking and return 
 status
  (this branch is used by rs/ref-transaction, rs/ref-transaction-multi,
 rs/ref-transaction-reflog and rs/ref-transaction-rename.)

  The second batch of the transactional ref update series.

 Has been merged into pu

Last reviewed at
http://thread.gmane.org/gmane.comp.version-control.git/252226, if
I am using gmane search correctly.

Are there any pending questions for this part?

I've having trouble keeping track of how patches change, which patches
have been reviewed and which haven't, unaddressed comments, and so on,
so as an experiment I've pushed this part of the series to the Gerrit
server at

 https://code-review.googlesource.com/#/q/topic:ref-transaction-1

It's running a copy of gerrit code review
(https://code.google.com/p/gerrit).

Maybe this can be useful as a way of keeping track of the state of
long and long-lived series like this one.  It works something like
this:

Preparation
---
Get a password from https://code-review.googlesource.com/new-password
and put it in netrc.

Install the hook from
https://code-review.googlesource.com/tools/hooks/commit-msg to
.git/hooks/commit-msg.  This automatically populates a Change-Id
line in the commit message if none is present so gerrit can
tell when you are uploading a new version of an existing patch.

(The commit-msg hook can be annoying when not working with gerrit
code review.  To turn it off, use 'git config gerrit.createChangeId false'.)

Uploading patches
-
Write a patch series against 'maint' or 'master' as usual, then push:

git push https://code.googlesource.com/git \
HEAD:refs/for/master; # or refs/for/maint

There can be a parameter '%topic=name' after the refs/for/branch
(e.g., refs/for/master%topic=ref-transaction-1) if the series should
be labelled with a topic name, or that can be set in the web UI or
using the HTTP API after the fact.

Commenting on patches
-
Visit https://code-review.googlesource.com.  Patches can be found
under All - Open.  Patches you're involved with somehow are
at My - Changes.

To prepare inline comments, choose a file, highlight the text to comment
on or click a line number, and comment.

To publish comments, go back up to the change overview screen (using
the up arrow button or by pressing u), click Reply, and say
something.

'?' brings up keyboard shortcuts.

Downloading patches
---
In the change overview screen, there's a 'Download' menu in the
top-right corner with commands to download the patch.

Revising patches

After modifying a patch locally using the usual tools such as rebase
--interactive, push again:

git push https://code.googlesource.com/git \
HEAD:refs/for/master; # or refs/for/maint

When a patch seems polished
---
Get rid of the Change-Id lines --- they shouldn't be needed any
more.  Send the patches or a request to pull from a public git
repository, as usual.  A link (in the top-left corner where it says
'Change 1000', the 1000 is a link to the change) can be helpful
for letting people on-list see how the patch got into the form it's
in today.

Maybe it can be useful.

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 1/2] Makefile: use find to determine static header dependencies

2014-08-21 Thread Jonathan Nieder
Hi,

Jeff King wrote:

 However, we do always define $(LIB_H) as a dependency of
 po/git.pot. Even though we do not actually try to build that
 target, make will still evaluate the dependencies when
 reading the Makefile, and expand the variable. This is not
 ideal

Would the following work?  The current dependencies for po/git.pot are
not correct anyway --- they include LOCALIZED_C but not LOCALIZED_SH
or LOCALIZED_PERL, so someone hacking on shell scripts and then trying
'make po/git.pot' could end up with the pot file not being
regenerated.

-- 8 --
Subject: i18n: treat make pot as an explicitly-invoked target

po/git.pot is normally used as-is and not regenerated by people
building git, so it is okay if an explicit make po/git.pot always
automatically regenerates it.  Depend on the magic FORCE target
instead of explicitly keeping track of dependencies.

This simplifies the makefile, in particular preparing for a moment
when $(LIB_H), which is part of $(LOCALIZED_C), can be computed on the
fly.

We still need a dependency on GENERATED_H, to force those files to be
built when regenerating git.pot.

Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 2320de5..cf0ccdf 100644
--- a/Makefile
+++ b/Makefile
@@ -2138,7 +2138,7 @@ LOCALIZED_SH += t/t0200/test.sh
 LOCALIZED_PERL += t/t0200/test.perl
 endif
 
-po/git.pot: $(LOCALIZED_C)
+po/git.pot: $(GENERATED_H) FORCE
$(QUIET_XGETTEXT)$(XGETTEXT) -o$@+ $(XGETTEXT_FLAGS_C) $(LOCALIZED_C)
$(QUIET_XGETTEXT)$(XGETTEXT) -o$@+ --join-existing $(XGETTEXT_FLAGS_SH) 
\
$(LOCALIZED_SH)
-- 
--
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: Hook post-merge does not get executed in case of confilicts

2014-08-21 Thread Jonathan Nieder
Hi,

Bertram Scharpf wrote:

 today I wrote a port-merge hook. Then I just detected that it only gets
 executed when the merge is immediately successful. In case there is a
 conflict, I have to finish the merge using the command git commit.
 This will not call the post-merge hook.

 I think the hook should be reliable to be executed on _every_ non-failed
 merge. Therefore I propose the below extension.

I agree that at first glance this sounds like a good thing.  A manual
conflict resolution is not so different from a very smart merge
strategy, after all.

Nits:

 Bertram

Sign-off?  (See Documentation/SubmittingPatches, section 5 Sign your
work for what this means.

 --- a/builtin/commit.c
 +++ b/builtin/commit.c
 @@ -1783,6 +1783,8 @@ int cmd_commit(int argc, const char **argv, const char 
 *prefix)
  
   rerere(0);
   run_commit_hook(use_editor, get_index_file(), post-commit, NULL);
 + if (whence == FROM_MERGE)
 + run_hook_le(NULL, post-merge, 0, NULL);

git merge doesn't run the post-commit hook, so there's a new
asymmetry being introduced here.  Should git merge run the
post-commit hook?  Should a git commit that means git merge
--continue avoid running it?

Also if doing this for real, the documentation should be updated
and tests introduced to make sure the behavior doesn't get broken
in the future.  Documentation/githooks.txt currently says

This hook cannot affect the outcome of git merge and is not
executed if the merge failed due to conflicts.

which would need to be updated to say that the hook will run later
in that case, when the merge is finally committed.

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


check-ref-format: include refs/ in the argument or to strip it?

2014-08-22 Thread Jonathan Nieder
Hi,

Michael Haggerty wrote[1]:
 Jonathan Nieder wrote:

 The check-ref-format documentation is pretty unclear, but the
 intent is that it would be used like

  git check-ref-format heads/master

 (see the surviving examples in contrib/examples/). That way, it can
 enforce the rule (from git-check-ref-format(1))

  2. They must contain at least one /. This enforces the presence
  of a category like heads/, tags/ etc. but the actual names
  are not restricted.
[...]
 Thanks for the explanation and the pointer.

 I suppose that was a usage that was more popular in the past than
 now. I can hardly remember anyone talking about references like
 heads/master or tags/v1. It seems to me that when somebody wants
 to be unambiguous they usually use the whole reference name
 refs/heads/master or refs/tags/v1. When they want to be succinct
 they usually use just master or v1.

 To me it seems incongruous to have the heads/master syntax
 supported at this deep level of plumbing. In most cases, the caller
 could get the same effect by prepending refs/ to the string and
 then calling check_refname_format with a new
 REFNAME_REQUIRE_CATEGORY option that requires both a refs/ prefix
 and a total of at least *three* levels.

I agree that this piece of UI is pretty weird.  Worse, it's
underdocumented.

I wonder if it would make sense to have the check-ref-format commandline
utility require two slashes when its argument begins with refs/ (still
requiring only one slash when it doesn't, for backward compatibility)
and to start encouraging people to pass refnames with refs/ to it.

The alternative would be something like the following, which doesn't
seem too appealing.

Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
[1] https://code-review.googlesource.com/1017

 Documentation/git-check-ref-format.txt | 18 +-
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/Documentation/git-check-ref-format.txt 
b/Documentation/git-check-ref-format.txt
index fc02959..447e9fb 100644
--- a/Documentation/git-check-ref-format.txt
+++ b/Documentation/git-check-ref-format.txt
@@ -15,8 +15,8 @@ SYNOPSIS
 
 DESCRIPTION
 ---
-Checks if a given 'refname' is acceptable, and exits with a non-zero
-status if it is not.
+Checks if refs/refname is an acceptable ref name, and exits
+with a non-zero status if it is not.
 
 A reference is used in Git to specify branches and tags.  A
 branch head is stored in the `refs/heads` hierarchy, while
@@ -91,14 +91,14 @@ OPTIONS
components).  The default is `--no-allow-onelevel`.
 
 --refspec-pattern::
-   Interpret refname as a reference name pattern for a refspec
-   (as used with remote repositories).  If this option is
-   enabled, refname is allowed to contain a single `*`
-   in place of a one full pathname component (e.g.,
-   `foo/*/bar` but not `foo/bar*`).
+   Interpret refs/refname as a reference name pattern
+   for a refspec (as used with remote repositories).
+   If this option is enabled, refname is allowed
+   to contain a single `*` in place of a one full pathname
+   component (e.g., `foo/*/bar` but not `foo/bar*`).
 
 --normalize::
-   Normalize 'refname' by removing any leading slash (`/`)
+   Normalize refname by removing any leading slash (`/`)
characters and collapsing runs of adjacent slashes between
name components into a single slash.  Iff the normalized
refname is valid then print it to standard output and exit
@@ -118,7 +118,7 @@ $ git check-ref-format --branch @{-1}
 * Determine the reference name to use for a new branch:
 +
 
-$ ref=$(git check-ref-format --normalize refs/heads/$newbranch) ||
+$ ref=$(git check-ref-format --normalize heads/$newbranch) ||
 die we do not like '$newbranch' as a branch name.
 
 
-- 
--
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: check-ref-format: include refs/ in the argument or to strip it?

2014-08-22 Thread Jonathan Nieder
Junio C Hamano wrote:

implication of which is that the 'at least one slash'
 rule was to expect things are 'refs/anything' so there will be at
 least one.  Even back then, that anything alone had at least one
 slash (e.g. heads/master), but the intention was *never* that we
 would forbid anything that does not have a slash by feeding
 anything part alone to check-ref-format, i.e. things like
 refs/stash were designed to be allowed.

Now I'm more confused.  Until 5f7b202a (2008-01-01), there was a
comment

if (level  2)
return -2; /* at least of form heads/blah */

and that behavior has been preserved since the beginning.

Why do most old callers pass a string that doesn't start with refs/
(e.g., see the callers in 03feddd6, 2005-10-13)?  Has the intent been
to relax the requirement since then?

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: check-ref-format: include refs/ in the argument or to strip it?

2014-08-22 Thread Jonathan Nieder
Junio C Hamano wrote:
 Michael Haggerty wrote[1]:
 Jonathan Nieder wrote:

 The check-ref-format documentation is pretty unclear, but the
 intent is that it would be used like

git check-ref-format heads/master

 (see the surviving examples in contrib/examples/). That way, it can
 enforce the rule (from git-check-ref-format(1))
[...]
 Thanks for the explanation and the pointer.

 I wanted to follow this discussion, especially the ellided [...]
 pointer, but had a hart time finding what pointer was.

I missed this question before.

The discussion happened at https://code-review.googlesource.com/1017.
It's easier to see after clicking the 'Expand All' button, but even
then it's hard to see the signal in the 'Patch Set n was rebased'
noise.

The pointer Michael mentioned was to the git-check-ref-format(1)
manpage and old 'check-ref-format' callers that can be found in
contrib/examples/.  Sorry for the lack of context.

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: check-ref-format: include refs/ in the argument or to strip it?

2014-08-25 Thread Jonathan Nieder
Ronnie Sahlberg wrote:
 On Fri, Aug 22, 2014 at 10:46 PM, Jeff King p...@peff.net wrote:

 Yeah, this weird do not allow refs/foo behavior has continually
 confused me. Coincidentally I just noticed a case today where
 pack-refs treats refs/foo specially for no good reason:

   http://thread.gmane.org/gmane.comp.version-control.git/255729

 After much head scratching over the years, I am of the opinion that
 nobody every really _meant_ to prevent refs/foo, and that code
 comments like the one you quote above were an attempt to document
 existing buggy behavior that was really trying to differentiate HEAD
 from refs/*. That's just my opinion, though. :)

It's still very puzzling to me.  The comment came at the same time as
the behavior, in v0.99.9~120 (git-check-ref-format: reject funny ref
names, 2005-10-13).  Before that, the behavior was even stranger ---
it checked that there was exactly one slash in the argument.

I'm willing to believe we might not want that check any more, though.

[...]
 There are also a lot of places where we assume that a refs will start
 with refs/heads/ and not just refs/
 for_each_branch_ref(), log_ref_setup() (so no reflogs) is_branch() to
 name a few.

for_each_branch_ref is for iterating over local branches, which are
defined as refs that start with refs/heads/*.  Likewise, the only
point of is_branch is to check whether a ref is under refs/heads/*.
That's not an assumption about all refs.

log_ref_setup implements the policy that there are only reflogs for:

 * refs where the reflog was explicitly created (git branch
   --create-reflog does this, but for some reason there's no
   corresponding git update-ref --create-reflog so people have
   to use mkdir directly for other refs), plus

 * if the '[core] logallrefupdates' configuration is enabled (and it
   is by default for non-bare repositories), then HEAD, refs/heads/*,
   refs/notes/*, and refs/remotes/*.

This is documented in git-config(1) --- see core.logAllRefUpdates.

That way, when tools internally use other refs (e.g., FETCH_HEAD),
git doesn't have to automatically incur the cost of maintaining the
reflog for those.  What other refs should there be reflogs for?  I
haven't thought carefully about this.

It definitely isn't an assumption that *all* refs will match that
pattern.  But it might be worth changing for other reasons.

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 2/3] Makefile: use `find` to determine static header dependencies

2014-08-25 Thread Jonathan Nieder
Jeff King wrote:

 -LOCALIZED_C := $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)
 +LOCALIZED_C = $(C_OBJ:o=c) $(GENERATED_H)

Why is LIB_H dropped here?  This would mean that po/git.pot stops
including strings from macros and static inline functions in headers
(e.g., in parse-options.h).

The rest looks good.

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 2/3] Makefile: use `find` to determine static header dependencies

2014-08-25 Thread Jonathan Nieder
Jeff King wrote:

 It is unfortunately easy for our static header list to grow
 stale, as none of the regular developers make use of it.
 Instead of trying to keep it up to date, let's invoke find
 to generate the list dynamically.

Yep, I like this.

It does mean that people who run make pot have to be a little more
vigilant about not keeping around extra .h files by mistake.  But I
trust them.

[...]
 +LIB_H = $(shell $(FIND) . \
 + -name .git -prune -o \
 + -name t -prune -o \
 + -name Documentation -prune -o \
 + -name '*.h' -print)

Tiny nit: I might use

$(shell $(FIND) * \
-name . -o
-name '.*' -prune -o \
-name t -prune -o \
-name Documentation -prune -o \
-name '*.h' -print)

or

$(shell $(FIND) * \
-name '.?*' -prune -o \
-name t -prune -o \
-name Documentation -prune -o \
-name '*.h' -print)

to avoid spending time looking in other dot-directories like .svn,
.hg, or .snapshot.

With or without such a change,
Reviewed-by: Jonathan Nieder jrnie...@gmail.com
--
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/3] Makefile: use `find` to determine static header dependencies

2014-08-25 Thread Jonathan Nieder
Junio C Hamano wrote:
 Jonathan Nieder jrnie...@gmail.com writes:

 Tiny nit: I might use

  $(shell $(FIND) * \
  -name . -o
  -name '.*' -prune -o \
  -name t -prune -o \
  -name Documentation -prune -o \
  -name '*.h' -print)

 or

  $(shell $(FIND) * \
  -name '.?*' -prune -o \
  -name t -prune -o \
  -name Documentation -prune -o \
  -name '*.h' -print)

 to avoid spending time looking in other dot-directories like .svn,
 .hg, or .snapshot.

 Wouldn't it be sufficient to start digging not from * but from
 ??*?

Gah, the * was supposed to be . in my examples (though it doesn't
hurt).

   find ??* \( -name Documentation -o -name .\?\* \) -prune -o -name \*.h

Heh.  Yeah, that would work. ;-)
--
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: Transaction patch series overview

2014-08-25 Thread Jonathan Nieder
Jonathan Nieder wrote:
 Ronnie Sahlberg wrote:

 ref-transaction-1 (2014-07-16) 20 commits
 -
 Second batch of ref transactions

  - refs.c: make delete_ref use a transaction
  - refs.c: make prune_ref use a transaction to delete the ref
  - refs.c: remove lock_ref_sha1
  - refs.c: remove the update_ref_write function
  - refs.c: remove the update_ref_lock function
  - refs.c: make lock_ref_sha1 static
  - walker.c: use ref transaction for ref updates
  - fast-import.c: use a ref transaction when dumping tags
  - receive-pack.c: use a reference transaction for updating the refs
  - refs.c: change update_ref to use a transaction
  - branch.c: use ref transaction for all ref updates
  - fast-import.c: change update_branch to use ref transactions
  - sequencer.c: use ref transactions for all ref updates
  - commit.c: use ref transactions for updates
  - replace.c: use the ref transaction functions for updates
  - tag.c: use ref transactions when doing updates
  - refs.c: add transaction.status and track OPEN/CLOSED/ERROR
  - refs.c: make ref_transaction_begin take an err argument
  - refs.c: update ref_transaction_delete to check for error and return status
  - refs.c: change ref_transaction_create to do error checking and return 
 status
  (this branch is used by rs/ref-transaction, rs/ref-transaction-multi,
 rs/ref-transaction-reflog and rs/ref-transaction-rename.)
[...]
 I've having trouble keeping track of how patches change, which patches
 have been reviewed and which haven't, unaddressed comments, and so on,
 so as an experiment I've pushed this part of the series to the Gerrit
 server at

  https://code-review.googlesource.com/#/q/topic:ref-transaction-1

Outcome of the experiment: patches gained some minor changes and then

 1-12
Reviewed-by: Jonathan Nieder jrnie...@gmail.com

 13
Reviewed-by: Michael Haggerty mhag...@alum.mit.edu
Reviewed-by: Jonathan Nieder jrnie...@gmail.com

 14
Reviewed-by: Jonathan Nieder jrnie...@gmail.com

 15-16
Reviewed-by: Michael Haggerty mhag...@alum.mit.edu
Reviewed-by: Jonathan Nieder jrnie...@gmail.com

 17
Reviewed-by: Michael Haggerty mhag...@alum.mit.edu

 18
Reviewed-by: Michael Haggerty mhag...@alum.mit.edu
Reviewed-by: Jonathan Nieder jrnie...@gmail.com

 19
Reviewed-by: Jonathan Nieder jrnie...@gmail.com

 20
Reviewed-by: Michael Haggerty mhag...@alum.mit.edu
Reviewed-by: Jonathan Nieder jrnie...@gmail.com

I found the web UI helpful in seeing how each patch evolved since I
last looked at it.  Interdiff relative to the version in pu is below.
I'm still hoping for a tweak in response to a minor comment and then I
can put up a copy of the updated series to pull.

The next series from Ronnie's collection is available at
https://code-review.googlesource.com/#/q/topic:ref-transaction in case
someone wants a fresh series to look at.

diff --git a/branch.c b/branch.c
index c1eae00..37ac555 100644
--- a/branch.c
+++ b/branch.c
@@ -305,6 +305,7 @@ void create_branch(const char *head,
ref_transaction_commit(transaction, msg, err))
die(%s, err.buf);
ref_transaction_free(transaction);
+   strbuf_release(err);
}
 
if (real_ref  track)
diff --git a/builtin/commit.c b/builtin/commit.c
index 668fa6a..9bf1003 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1765,8 +1765,8 @@ int cmd_commit(int argc, const char **argv, const char 
*prefix)
transaction = ref_transaction_begin(err);
if (!transaction ||
ref_transaction_update(transaction, HEAD, sha1,
-  current_head ?
-  current_head-object.sha1 : NULL,
+  current_head
+  ? current_head-object.sha1 : NULL,
   0, !!current_head, err) ||
ref_transaction_commit(transaction, sb.buf, err)) {
rollback_index_files();
@@ -1801,5 +1801,6 @@ int cmd_commit(int argc, const char **argv, const char 
*prefix)
if (!quiet)
print_summary(prefix, sha1, !current_head);
 
+   strbuf_release(err);
return 0;
 }
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 91099ad..224fadc 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -194,7 +194,7 @@ static void write_head_info(void)
 
 struct command {
struct command *next;
-   char *error_string;
+   const char *error_string;
unsigned int skip_update:1,
 did_not_exist:1;
int index;
@@ -468,7 +468,7 @@ static int update_shallow_ref(struct command *cmd, struct 
shallow_info *si)
return 0;
 }
 
-static char *update(struct command *cmd, struct shallow_info *si)
+static const char *update(struct command *cmd, struct

Re: Transaction patch series overview

2014-08-26 Thread Jonathan Nieder
Hi again,

Junio C Hamano wrote:

 It seems that I can hold the topic in 'pu' a bit longer and expect a
 reroll from this effort before merging it to 'next'?

Sorry for the delay.  The following changes on top of master
(refs.c: change ref_transaction_update() to do error checking and
return status, 2014-07-14) are available in the git repository at

  git://repo.or.cz/git/jrn.git tags/rs/ref-transaction-1

for you to fetch changes up to 432ad1f39fd773b37757dd8f10b3075dc3d0d0a2:

  refs.c: make delete_ref use a transaction (2014-08-26 14:22:53 -0700)


Use ref transactions, early part

Ronnie explains:

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

This series teaches the tag, replace, commit, cherry-pick,
fast-import, checkout -b, branch, receive-pack, and http-fetch
commands and all update_ref and delete_ref callers to use the ref
transaction API instead of lock_ref_sha1.

The main user-visible change should be some cosmetic changes to error
messages.  The series also combines multiple ref updates into a single
transaction in 'git http-fetch -w' and when writing tags in
fast-import but otherwise doesn't change the granularity of
transactions.

Reviewed at https://code-review.googlesource.com/#/q/topic:ref-transaction-1


Ronnie Sahlberg (20):
  refs.c: change ref_transaction_create to do error checking and return 
status
  refs.c: update ref_transaction_delete to check for error and return status
  refs.c: make ref_transaction_begin take an err argument
  refs.c: add transaction.status and track OPEN/CLOSED
  tag.c: use ref transactions when doing updates
  replace.c: use the ref transaction functions for updates
  commit.c: use ref transactions for updates
  sequencer.c: use ref transactions for all ref updates
  fast-import.c: change update_branch to use ref transactions
  branch.c: use ref transaction for all ref updates
  refs.c: change update_ref to use a transaction
  receive-pack.c: use a reference transaction for updating the refs
  fast-import.c: use a ref transaction when dumping tags
  walker.c: use ref transaction for ref updates
  refs.c: make lock_ref_sha1 static
  refs.c: remove the update_ref_lock function
  refs.c: remove the update_ref_write function
  refs.c: remove lock_ref_sha1
  refs.c: make prune_ref use a transaction to delete the ref
  refs.c: make delete_ref use a transaction

 branch.c   |  31 ---
 builtin/commit.c   |  25 +++--
 builtin/receive-pack.c |  25 +++--
 builtin/replace.c  |  14 +--
 builtin/tag.c  |  16 ++--
 builtin/update-ref.c   |  14 ++-
 fast-import.c  |  54 +++
 refs.c | 244 -
 refs.h |  77 
 sequencer.c|  26 --
 walker.c   |  70 --
 11 files changed, 367 insertions(+), 229 deletions(-)

[...]
 Jonathan Nieder jrnie...@gmail.com writes:

 --- a/builtin/receive-pack.c
 +++ b/builtin/receive-pack.c
 @@ -580,18 +580,18 @@ static char *update(struct command *cmd, struct 
 shallow_info *si)
[...]
  if (!transaction ||
  ref_transaction_update(transaction, namespaced_name,
 new_sha1, old_sha1, 0, 1, err) ||
  ref_transaction_commit(transaction, push, err)) {
 -char *str = strbuf_detach(err, NULL);
  ref_transaction_free(transaction);
  
 -rp_error(%s, str);
 -return str;
 +rp_error(%s, err.buf);
 +strbuf_release(err);
 +return failed to update ref;
  }

 I am guessing that the purpose of this change is to make sure that
 cmd-error_string is taken from a fixed set of strings, not an
 arbitrary collection of errors from the transaction subsystem, but
 what is the significance of doing so?  Do the other side i18n while
 running print_ref_status() or something?

It's about keeping the message in parentheses on the ! rejected
master - master line short and simple, since the more detailed
diagnosis is redundant next to the full message that is sent over
sideband earlier and gets a line to itself.

Side effects:

 * a less invasive patch --- no more need to change the calling
   convention to return a dynamically allocated string, with
   assertions throughout the file that check for leaks

 * using the same all lowercase and brief convention makes the
   message less jarring next to other statuses for ! rejected lines,
   like non

[PATCH 0/20] rs/ref-transaction-1 (Re: Transaction patch series overview)

2014-08-26 Thread Jonathan Nieder
Jonathan Nieder wrote:

 This series teaches the tag, replace, commit, cherry-pick,
 fast-import, checkout -b, branch, receive-pack, and http-fetch
 commands and all update_ref and delete_ref callers to use the ref
 transaction API instead of lock_ref_sha1.

 The main user-visible change should be some cosmetic changes to error
 messages.  The series also combines multiple ref updates into a single
 transaction in 'git http-fetch -w' and when writing tags in
 fast-import but otherwise doesn't change the granularity of
 transactions.

 Reviewed at https://code-review.googlesource.com/#/q/topic:ref-transaction-1

 
 Ronnie Sahlberg (20):
   refs.c: change ref_transaction_create to do error checking and return 
 status
   refs.c: update ref_transaction_delete to check for error and return 
 status
   refs.c: make ref_transaction_begin take an err argument
   refs.c: add transaction.status and track OPEN/CLOSED
   tag.c: use ref transactions when doing updates
   replace.c: use the ref transaction functions for updates
   commit.c: use ref transactions for updates
   sequencer.c: use ref transactions for all ref updates
   fast-import.c: change update_branch to use ref transactions
   branch.c: use ref transaction for all ref updates
   refs.c: change update_ref to use a transaction
   receive-pack.c: use a reference transaction for updating the refs
   fast-import.c: use a ref transaction when dumping tags
   walker.c: use ref transaction for ref updates
   refs.c: make lock_ref_sha1 static
   refs.c: remove the update_ref_lock function
   refs.c: remove the update_ref_write function
   refs.c: remove lock_ref_sha1
   refs.c: make prune_ref use a transaction to delete the ref
   refs.c: make delete_ref use a transaction

And here are the patches.
--
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 02/20] refs.c: update ref_transaction_delete to check for error and return status

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Wed, 16 Apr 2014 15:27:45 -0700

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 sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 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 41121fa..7c9c248 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, err))
+   die(%s, err.buf);
 
update_flags = 0;
free(refname);
diff --git a/refs.c b/refs.c
index c49f1c6..40f04f4 100644
--- a/refs.c
+++ b/refs.c
@@ -3469,19 +3469,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 b648819..71389a1 100644
--- a/refs.h
+++ b/refs.h
@@ -308,11 +308,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.
  */
-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.1.0.rc2.206.gedb03e5

--
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 01/20] refs.c: change ref_transaction_create to do error checking and return status

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Wed, 16 Apr 2014 15:26:44 -0700

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 sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 builtin/update-ref.c |  4 +++-
 refs.c   | 18 --
 refs.h   | 48 +---
 3 files changed, 56 insertions(+), 14 deletions(-)

diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 3067b11..41121fa 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, err))
+   die(%s, err.buf);
 
update_flags = 0;
free(refname);
diff --git a/refs.c b/refs.c
index 3f05e88..c49f1c6 100644
--- a/refs.c
+++ b/refs.c
@@ -3449,18 +3449,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 c5376ce..b648819 100644
--- a/refs.h
+++ b/refs.h
@@ -10,6 +10,38 @@ struct ref_lock {
int force_write;
 };
 
+/*
+ * A ref_transaction represents a collection of ref updates
+ * that should succeed or fail together.
+ *
+ * Calling sequence
+ * 
+ * - Allocate and initialize a `struct ref_transaction` by calling
+ *   `ref_transaction_begin()`.
+ *
+ * - List intended ref updates by calling functions like
+ *   `ref_transaction_update()` and `ref_transaction_create()`.
+ *
+ * - Call `ref_transaction_commit()` to execute the transaction.
+ *   If this succeeds, the ref updates will have taken place and
+ *   the transaction cannot be rolled back.
+ *
+ * - At any time call `ref_transaction_free()` to discard the
+ *   transaction and free associated resources.  In particular,
+ *   this rolls back the transaction if it has not been
+ *   successfully committed.
+ *
+ * Error handling
+ * --
+ *
+ * On error, transaction functions append a message about what
+ * went wrong to the 'err' argument.  The message mentions what
+ * ref was being updated (if any) when the error occurred so it
+ * can be passed to 'die' or 'error' as-is.
+ *
+ * The message is appended to err without first clearing err.
+ * err will not be '\n' terminated.
+ */
 struct ref_transaction;
 
 /*
@@ -248,7 +280,7 @@ struct ref_transaction *ref_transaction_begin(void);
  * 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.
+ * rolled back.
  */
 int ref_transaction_update(struct ref_transaction *transaction,
   const char *refname,
@@ -262,11 +294,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.
  */
-void ref_transaction_create(struct ref_transaction *transaction,
-   const char *refname,
-   const unsigned char *new_sha1,
-   int flags);
+int

[PATCH 03/20] refs.c: make ref_transaction_begin take an err argument

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Mon, 19 May 2014 10:42:34 -0700

Add an err argument to _begin so that on non-fatal failures in future ref
backends we can report a nice error back to the caller.
While _begin can currently never fail for other reasons than OOM, in which
case we die() anyway, we may add other types of backends in the future.
For example, a hypothetical MySQL backend could fail in _begin with
Can not connect to MySQL server. No route to host.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 builtin/update-ref.c | 5 -
 refs.c   | 2 +-
 refs.h   | 2 +-
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 7c9c248..96a53b9 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -365,7 +365,9 @@ int cmd_update_ref(int argc, const char **argv, const char 
*prefix)
die(Refusing to perform update with empty message.);
 
if (read_stdin) {
-   transaction = ref_transaction_begin();
+   transaction = ref_transaction_begin(err);
+   if (!transaction)
+   die(%s, err.buf);
if (delete || no_deref || argc  0)
usage_with_options(git_update_ref_usage, options);
if (end_null)
@@ -374,6 +376,7 @@ int cmd_update_ref(int argc, const char **argv, const char 
*prefix)
if (ref_transaction_commit(transaction, msg, err))
die(%s, err.buf);
ref_transaction_free(transaction);
+   strbuf_release(err);
return 0;
}
 
diff --git a/refs.c b/refs.c
index 40f04f4..9cb7908 100644
--- a/refs.c
+++ b/refs.c
@@ -3397,7 +3397,7 @@ struct ref_transaction {
size_t nr;
 };
 
-struct ref_transaction *ref_transaction_begin(void)
+struct ref_transaction *ref_transaction_begin(struct strbuf *err)
 {
return xcalloc(1, sizeof(struct ref_transaction));
 }
diff --git a/refs.h b/refs.h
index 71389a1..3f37c65 100644
--- a/refs.h
+++ b/refs.h
@@ -262,7 +262,7 @@ enum action_on_err {
  * Begin a reference transaction.  The reference transaction must
  * be freed by calling ref_transaction_free().
  */
-struct ref_transaction *ref_transaction_begin(void);
+struct ref_transaction *ref_transaction_begin(struct strbuf *err);
 
 /*
  * The following functions add a reference check or update to a
-- 
2.1.0.rc2.206.gedb03e5

--
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 04/20] refs.c: add transaction.status and track OPEN/CLOSED

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Tue, 29 Apr 2014 12:06:19 -0700

Track the state of a transaction in a new state field. Check the field for
sanity, i.e. that state must be OPEN when _commit/_create/_delete or
_update is called or else die(BUG:...)

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 refs.c | 34 +-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/refs.c b/refs.c
index 9cb7908..cc63056 100644
--- a/refs.c
+++ b/refs.c
@@ -3387,6 +3387,21 @@ struct ref_update {
 };
 
 /*
+ * Transaction states.
+ * OPEN:   The transaction is in a valid state and can accept new updates.
+ * An OPEN transaction can be committed.
+ * CLOSED: A closed transaction is no longer active and no other operations
+ * than free can be used on it in this state.
+ * A transaction can either become closed by successfully committing
+ * an active transaction or if there is a failure while building
+ * the transaction thus rendering it failed/inactive.
+ */
+enum ref_transaction_state {
+   REF_TRANSACTION_OPEN   = 0,
+   REF_TRANSACTION_CLOSED = 1
+};
+
+/*
  * Data structure for holding a reference transaction, which can
  * consist of checks and updates to multiple references, carried out
  * as atomically as possible.  This structure is opaque to callers.
@@ -3395,6 +3410,7 @@ struct ref_transaction {
struct ref_update **updates;
size_t alloc;
size_t nr;
+   enum ref_transaction_state state;
 };
 
 struct ref_transaction *ref_transaction_begin(struct strbuf *err)
@@ -3437,6 +3453,9 @@ int ref_transaction_update(struct ref_transaction 
*transaction,
 {
struct ref_update *update;
 
+   if (transaction-state != REF_TRANSACTION_OPEN)
+   die(BUG: update called for transaction that is not open);
+
if (have_old  !old_sha1)
die(BUG: have_old is true but old_sha1 is NULL);
 
@@ -3457,6 +3476,9 @@ int ref_transaction_create(struct ref_transaction 
*transaction,
 {
struct ref_update *update;
 
+   if (transaction-state != REF_TRANSACTION_OPEN)
+   die(BUG: create called for transaction that is not open);
+
if (!new_sha1 || is_null_sha1(new_sha1))
die(BUG: create ref with null new_sha1);
 
@@ -3477,6 +3499,9 @@ int ref_transaction_delete(struct ref_transaction 
*transaction,
 {
struct ref_update *update;
 
+   if (transaction-state != REF_TRANSACTION_OPEN)
+   die(BUG: delete called for transaction that is not open);
+
if (have_old  !old_sha1)
die(BUG: have_old is true but old_sha1 is NULL);
 
@@ -3532,8 +3557,13 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
int n = transaction-nr;
struct ref_update **updates = transaction-updates;
 
-   if (!n)
+   if (transaction-state != REF_TRANSACTION_OPEN)
+   die(BUG: commit called for transaction that is not open);
+
+   if (!n) {
+   transaction-state = REF_TRANSACTION_CLOSED;
return 0;
+   }
 
/* Allocate work space */
delnames = xmalloc(sizeof(*delnames) * n);
@@ -3595,6 +3625,8 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
clear_loose_ref_cache(ref_cache);
 
 cleanup:
+   transaction-state = REF_TRANSACTION_CLOSED;
+
for (i = 0; i  n; i++)
if (updates[i]-lock)
unlock_ref(updates[i]-lock);
-- 
2.1.0.rc2.206.gedb03e5

--
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 05/20] tag.c: use ref transactions when doing updates

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Wed, 16 Apr 2014 15:30:41 -0700

Change tag.c to use ref transactions for all ref updates.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 builtin/tag.c | 16 ++--
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/builtin/tag.c b/builtin/tag.c
index c6e8a71..f3f172f 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,14 +702,17 @@ 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(err);
+   if (!transaction ||
+   ref_transaction_update(transaction, ref.buf, object, prev,
+  0, 1, 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));
 
+   strbuf_release(err);
strbuf_release(buf);
strbuf_release(ref);
return 0;
-- 
2.1.0.rc2.206.gedb03e5

--
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 06/20] replace.c: use the ref transaction functions for updates

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Wed, 16 Apr 2014 15:32:29 -0700

Update replace.c to use ref transactions for updates.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 builtin/replace.c | 14 --
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/builtin/replace.c b/builtin/replace.c
index 1bb491d..1fcd06d 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -153,7 +153,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;
 
obj_type = sha1_object_info(object, NULL);
repl_type = sha1_object_info(repl, NULL);
@@ -166,12 +167,13 @@ static int replace_object_sha1(const char *object_ref,
 
check_ref_valid(object, prev, ref, sizeof(ref), force);
 
-   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(err);
+   if (!transaction ||
+   ref_transaction_update(transaction, ref, repl, prev, 0, 1, err) ||
+   ref_transaction_commit(transaction, NULL, err))
+   die(%s, err.buf);
 
+   ref_transaction_free(transaction);
return 0;
 }
 
-- 
2.1.0.rc2.206.gedb03e5

--
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 07/20] commit.c: use ref transactions for updates

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Wed, 16 Apr 2014 15:34:19 -0700

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.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 builtin/commit.c | 25 -
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 5e2221c..9bf1003 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1627,11 +1627,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);
@@ -1753,16 +1754,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);
@@ -1771,10 +1762,17 @@ 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(err);
+   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);
}
+   ref_transaction_free(transaction);
 
unlink(git_path(CHERRY_PICK_HEAD));
unlink(git_path(REVERT_HEAD));
@@ -1803,5 +1801,6 @@ int cmd_commit(int argc, const char **argv, const char 
*prefix)
if (!quiet)
print_summary(prefix, sha1, !current_head);
 
+   strbuf_release(err);
return 0;
 }
-- 
2.1.0.rc2.206.gedb03e5

--
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 08/20] sequencer.c: use ref transactions for all ref updates

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Wed, 16 Apr 2014 15:37:45 -0700

Change to use ref transactions for all updates to refs.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 sequencer.c | 26 ++
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index 0a80c58..5e93b6a 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -272,23 +272,33 @@ 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(err);
+   if (!transaction ||
+   ref_transaction_update(transaction, HEAD,
+  to, unborn ? null_sha1 : from,
+  0, 1, err) ||
+   ref_transaction_commit(transaction, sb.buf, err)) {
+   ref_transaction_free(transaction);
+   error(%s, err.buf);
+   strbuf_release(sb);
+   strbuf_release(err);
+   return -1;
+   }
 
strbuf_release(sb);
-   return ret;
+   strbuf_release(err);
+   ref_transaction_free(transaction);
+   return 0;
 }
 
 static int do_recursive_merge(struct commit *base, struct commit *next,
-- 
2.1.0.rc2.206.gedb03e5

--
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 10/20] branch.c: use ref transaction for all ref updates

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Wed, 16 Apr 2014 16:21:53 -0700

Change create_branch to use a ref transaction when creating the new branch.

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.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 branch.c | 31 +--
 1 file changed, 17 insertions(+), 14 deletions(-)

diff --git a/branch.c b/branch.c
index 660097b..37ac555 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,26 @@ 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(err);
+   if (!transaction ||
+   ref_transaction_update(transaction, ref.buf, sha1,
+  null_sha1, 0, !forcing, err) ||
+   ref_transaction_commit(transaction, msg, err))
+   die(%s, err.buf);
+   ref_transaction_free(transaction);
+   strbuf_release(err);
+   }
+
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.1.0.rc2.206.gedb03e5

--
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 09/20] fast-import.c: change update_branch to use ref transactions

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Wed, 16 Apr 2014 16:21:13 -0700

Change update_branch() to use ref transactions for updates.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 fast-import.c | 25 +++--
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/fast-import.c b/fast-import.c
index 6707a66..79160d5 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -1679,8 +1679,9 @@ 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);
@@ -1689,29 +1690,33 @@ static int update_branch(struct branch *b)
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(err);
+   if (!transaction ||
+   ref_transaction_update(transaction, b-name, b-sha1, old_sha1,
+  0, 1, err) ||
+   ref_transaction_commit(transaction, msg, err)) {
+   ref_transaction_free(transaction);
+   error(%s, err.buf);
+   strbuf_release(err);
+   return -1;
+   }
+   ref_transaction_free(transaction);
+   strbuf_release(err);
return 0;
 }
 
-- 
2.1.0.rc2.206.gedb03e5

--
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 11/20] refs.c: change update_ref to use a transaction

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Thu, 24 Apr 2014 16:36:55 -0700

Change the update_ref helper function to use a ref transaction internally.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 refs.c | 29 +
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/refs.c b/refs.c
index cc63056..dcc877b 100644
--- a/refs.c
+++ b/refs.c
@@ -3519,11 +3519,32 @@ 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(err);
+   if (!t ||
+   ref_transaction_update(t, refname, sha1, oldval, flags,
+  !!oldval, err) ||
+   ref_transaction_commit(t, action, err)) {
+   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);
+   }
+   strbuf_release(err);
+   return 0;
 }
 
 static int ref_update_compare(const void *r1, const void *r2)
-- 
2.1.0.rc2.206.gedb03e5

--
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 12/20] receive-pack.c: use a reference transaction for updating the refs

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Mon, 28 Apr 2014 14:36:15 -0700

Wrap all the ref updates inside a transaction.

In the new API there is no distinction between failure to lock and
failure to write a ref.  Both can be permanent (e.g., a ref
refs/heads/topic is blocking creation of the lock file
refs/heads/topic/1.lock) or transient (e.g., file system full) and
there's no clear difference in how the client should respond, so
replace the two statuses failed to lock and failed to write with
a single status failed to update ref.  In both cases a more
detailed message is sent by sideband to diagnose the problem.

Example, before:

 error: there are still refs under 'refs/heads/topic'
 remote: error: failed to lock refs/heads/topic
 To foo
  ! [remote rejected] HEAD - topic (failed to lock)

After:

 error: there are still refs under 'refs/heads/topic'
 remote: error: Cannot lock the ref 'refs/heads/topic'.
 To foo
  ! [remote rejected] HEAD - topic (failed to update ref)

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 builtin/receive-pack.c | 25 -
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index c323081..224fadc 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -475,7 +475,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)) {
@@ -576,19 +575,27 @@ static const char *update(struct command *cmd, struct 
shallow_info *si)
return NULL; /* good */
}
else {
+   struct strbuf err = STRBUF_INIT;
+   struct ref_transaction *transaction;
+
if (shallow_update  si-shallow_ref[cmd-index] 
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 */
+   transaction = ref_transaction_begin(err);
+   if (!transaction ||
+   ref_transaction_update(transaction, namespaced_name,
+  new_sha1, old_sha1, 0, 1, err) ||
+   ref_transaction_commit(transaction, push, err)) {
+   ref_transaction_free(transaction);
+
+   rp_error(%s, err.buf);
+   strbuf_release(err);
+   return failed to update ref;
}
+
+   ref_transaction_free(transaction);
+   strbuf_release(err);
return NULL; /* good */
}
 }
-- 
2.1.0.rc2.206.gedb03e5

--
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 13/20] fast-import.c: use a ref transaction when dumping tags

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Mon, 28 Apr 2014 15:23:58 -0700

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Reviewed-by: Michael Haggerty mhag...@alum.mit.edu
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 fast-import.c | 29 +++--
 1 file changed, 23 insertions(+), 6 deletions(-)

diff --git a/fast-import.c b/fast-import.c
index 79160d5..e7f6e37 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -1735,15 +1735,32 @@ 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 ref_name = STRBUF_INIT;
+   struct strbuf err = STRBUF_INIT;
+   struct ref_transaction *transaction;
 
+   transaction = ref_transaction_begin(err);
+   if (!transaction) {
+   failure |= error(%s, err.buf);
+   goto cleanup;
+   }
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);
+   strbuf_reset(ref_name);
+   strbuf_addf(ref_name, refs/tags/%s, t-name);
+
+   if (ref_transaction_update(transaction, ref_name.buf, t-sha1,
+  NULL, 0, 0, err)) {
+   failure |= error(%s, err.buf);
+   goto cleanup;
+   }
}
+   if (ref_transaction_commit(transaction, msg, err))
+   failure |= error(%s, err.buf);
+
+ cleanup:
+   ref_transaction_free(transaction);
+   strbuf_release(ref_name);
+   strbuf_release(err);
 }
 
 static void dump_marks_helper(FILE *f,
-- 
2.1.0.rc2.206.gedb03e5

--
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 15/20] refs.c: make lock_ref_sha1 static

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Mon, 28 Apr 2014 15:38:47 -0700

No external callers reference lock_ref_sha1 any more so let's declare it
static.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Reviewed-by: Michael Haggerty mhag...@alum.mit.edu
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 refs.c | 7 +--
 refs.h | 6 --
 2 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/refs.c b/refs.c
index dcc877b..0dc093c 100644
--- a/refs.c
+++ b/refs.c
@@ -2069,7 +2069,10 @@ int dwim_log(const char *str, int len, unsigned char 
*sha1, char **log)
return logs_found;
 }
 
-/* This function should make sure errno is meaningful on error */
+/*
+ * Locks a refs/ ref returning the lock on success and NULL on failure.
+ * On failure errno is set to something meaningful.
+ */
 static struct ref_lock *lock_ref_sha1_basic(const char *refname,
const unsigned char *old_sha1,
int flags, int *type_p)
@@ -2170,7 +2173,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 3f37c65..65dd593 100644
--- a/refs.h
+++ b/refs.h
@@ -170,12 +170,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.
- * On failure errno is set to something meaningful.
- */
-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
 /* errno is set to something meaningful on failure */
-- 
2.1.0.rc2.206.gedb03e5

--
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 14/20] walker.c: use ref transaction for ref updates

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Thu, 17 Apr 2014 11:31:06 -0700

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.

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 collisions that the previous locking would
protect against and cause the fetch to fail for are even more rare.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 walker.c | 72 
 1 file changed, 41 insertions(+), 31 deletions(-)

diff --git a/walker.c b/walker.c
index 1dd86b8..b8a5441 100644
--- a/walker.c
+++ b/walker.c
@@ -251,40 +251,40 @@ 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 *));
+   struct strbuf refname = STRBUF_INIT;
+   struct strbuf err = STRBUF_INIT;
+   struct ref_transaction *transaction = NULL;
unsigned char *sha1 = xmalloc(targets * 20);
-   char *msg;
-   int ret;
-   int i;
+   char *msg = NULL;
+   int i, ret = -1;
 
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;
+   if (write_ref) {
+   transaction = ref_transaction_begin(err);
+   if (!transaction) {
+   error(%s, err.buf);
+   goto done;
}
}
-
if (!walker-get_recover)
for_each_ref(mark_complete, NULL);
 
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 done;
}
if (process(walker, lookup_unknown_object(sha1[20 * i])))
-   goto unlock_and_fail;
+   goto done;
}
 
if (loop(walker))
-   goto unlock_and_fail;
-
+   goto done;
+   if (!write_ref) {
+   ret = 0;
+   goto done;
+   }
if (write_ref_log_details) {
msg = xmalloc(strlen(write_ref_log_details) + 12);
sprintf(msg, fetch from %s, write_ref_log_details);
@@ -292,23 +292,33 @@ int walker_fetch(struct walker *walker, int targets, char 
**target,
msg = NULL;
}
for (i = 0; i  targets; i++) {
-   if (!write_ref || !write_ref[i])
+   if (!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;
+   strbuf_reset(refname);
+   strbuf_addf(refname, refs/%s, write_ref[i]);
+   if (ref_transaction_update(transaction, refname.buf,
+  sha1[20 * i], NULL, 0, 0,
+  err)) {
+   error(%s, err.buf);
+   goto done;
+   }
}
+   if (ref_transaction_commit(transaction,
+  msg ? msg : fetch (unknown),
+  err)) {
+   error(%s, err.buf);
+   goto done;
+   }
+
+   ret = 0;
+
+done:
+   ref_transaction_free(transaction);
free(msg);
-
-   return 0;
-
-unlock_and_fail:
-   for (i = 0; i  targets; i++)
-   if (lock[i])
-   unlock_ref(lock[i]);
-
-   return -1;
+   free(sha1);
+   strbuf_release(err);
+   strbuf_release(refname);
+   return ret;
 }
 
 void walker_free(struct walker *walker)
-- 
2.1.0.rc2.206.gedb03e5

--
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 17/20] refs.c: remove the update_ref_write function

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Tue, 29 Apr 2014 13:42:07 -0700

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. This changes the return status for _commit from
1 to -1 on failures when writing to the ref. Eventually we will want
_commit to start returning more detailed error conditions than the current
simple success/failure.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 refs.c | 34 --
 1 file changed, 8 insertions(+), 26 deletions(-)

diff --git a/refs.c b/refs.c
index de07791..ef7660a 100644
--- a/refs.c
+++ b/refs.c
@@ -3336,25 +3336,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
@@ -3604,14 +3585,15 @@ 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) {
+   if (err)
+   strbuf_addf(err, Cannot update the ref 
'%s'.,
+   update-refname);
goto cleanup;
+   }
}
}
 
-- 
2.1.0.rc2.206.gedb03e5

--
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 16/20] refs.c: remove the update_ref_lock function

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Tue, 29 Apr 2014 12:14:47 -0700

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 sahlb...@google.com
Reviewed-by: Michael Haggerty mhag...@alum.mit.edu
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 refs.c | 30 ++
 1 file changed, 6 insertions(+), 24 deletions(-)

diff --git a/refs.c b/refs.c
index 0dc093c..de07791 100644
--- a/refs.c
+++ b/refs.c
@@ -3336,24 +3336,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)
@@ -3602,12 +3584,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.1.0.rc2.206.gedb03e5

--
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 18/20] refs.c: remove lock_ref_sha1

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Tue, 29 Apr 2014 15:45:52 -0700

lock_ref_sha1 was only called from one place in refs.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 sahlb...@google.com
Reviewed-by: Michael Haggerty mhag...@alum.mit.edu
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 refs.c | 15 +--
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/refs.c b/refs.c
index ef7660a..f0883d0 100644
--- a/refs.c
+++ b/refs.c
@@ -2173,15 +2173,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)
@@ -2391,8 +2382,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.1.0.rc2.206.gedb03e5

--
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 19/20] refs.c: make prune_ref use a transaction to delete the ref

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Wed, 30 Apr 2014 09:03:36 -0700

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 sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 refs.c | 28 +---
 refs.h | 13 +++--
 2 files changed, 32 insertions(+), 9 deletions(-)

diff --git a/refs.c b/refs.c
index f0883d0..5b2d335 100644
--- a/refs.c
+++ b/refs.c
@@ -25,6 +25,11 @@ static unsigned char refname_disposition[256] = {
 };
 
 /*
+ * 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 legal.  It is legal if it is something reasonable to have under
@@ -2382,17 +2387,25 @@ 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(err);
+   if (!transaction ||
+   ref_transaction_delete(transaction, r-name, r-sha1,
+  REF_ISPRUNING, 1, err) ||
+   ref_transaction_commit(transaction, NULL, err)) {
+   ref_transaction_free(transaction);
+   error(%s, err.buf);
+   strbuf_release(err);
+   return;
}
+   ref_transaction_free(transaction);
+   strbuf_release(err);
+   try_remove_empty_parents(r-name);
 }
 
 static void prune_refs(struct ref_to_prune *r)
@@ -3597,8 +3610,9 @@ 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);
+   if (!(update-flags  REF_ISPRUNING))
+   delnames[delnum++] = update-lock-ref_name;
}
}
 
diff --git a/refs.h b/refs.h
index 65dd593..69ef28c 100644
--- a/refs.h
+++ b/refs.h
@@ -170,9 +170,18 @@ extern int ref_exists(const char *);
  */
 extern int peel_ref(const char *refname, unsigned char *sha1);
 
-/** Locks any ref (for 'HEAD' type refs). */
+/*
+ * Flags controlling lock_any_ref_for_update(), ref_transaction_update(),
+ * ref_transaction_create(), etc.
+ * REF_NODEREF: act on the ref directly, instead of dereferencing
+ *  symbolic references.
+ *
+ * Flags = 0x100 are reserved for internal use.
+ */
 #define REF_NODEREF0x01
-/* errno is set to something meaningful on failure */
+/*
+ * This function sets errno to something meaningful on failure.
+ */
 extern struct ref_lock *lock_any_ref_for_update(const char *refname,
const unsigned char *old_sha1,
int flags, int *type_p);
-- 
2.1.0.rc2.206.gedb03e5

--
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 20/20] refs.c: make delete_ref use a transaction

2014-08-26 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Wed, 30 Apr 2014 09:22:45 -0700

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.

Change delete_ref to return 0 on success and 1 on failure instead of the
previous 0 on success either 1 or -1 on failure.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Reviewed-by: Michael Haggerty mhag...@alum.mit.edu
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
Thanks for reading.

 refs.c | 35 ++-
 1 file changed, 14 insertions(+), 21 deletions(-)

diff --git a/refs.c b/refs.c
index 5b2d335..7996be9 100644
--- a/refs.c
+++ b/refs.c
@@ -2548,11 +2548,6 @@ 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 delete_ref_loose(struct ref_lock *lock, int flag)
 {
if (!(flag  REF_ISPACKED) || flag  REF_ISSYMREF) {
@@ -2570,24 +2565,22 @@ static int delete_ref_loose(struct ref_lock *lock, int 
flag)
 
 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;
+   struct strbuf err = STRBUF_INIT;
 
-   lock = lock_ref_sha1_basic(refname, sha1, delopt, flag);
-   if (!lock)
+   transaction = ref_transaction_begin(err);
+   if (!transaction ||
+   ref_transaction_delete(transaction, refname, sha1, delopt,
+  sha1  !is_null_sha1(sha1), err) ||
+   ref_transaction_commit(transaction, NULL, err)) {
+   error(%s, err.buf);
+   ref_transaction_free(transaction);
+   strbuf_release(err);
return 1;
-   ret |= delete_ref_loose(lock, flag);
-
-   /* 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);
+   strbuf_release(err);
+   return 0;
 }
 
 /*
-- 
2.1.0.rc2.206.gedb03e5

--
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: problem with def of inet_ntop() in git-compat-util.h as well as other places

2014-08-27 Thread Jonathan Nieder
Hi,

dev wrote:

 CC credential-store.o
 git-compat-util.h, line 516: error: identifier redeclared: inet_ntop
   current : function(int, pointer to const void, pointer to char, 
 unsigned long) returning pointer to const char
   previous: function(int, pointer to const void, pointer to char, 
 unsigned int) returning pointer to const char :
   /usr/include/arpa/inet.h, line 68

Why is NO_INET_NTOP set?  What commands are you using to build?  If
you are using autoconf, what does your config.mak.autogen say?

Puzzled,
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] Document LF appearing in shallow command during send-pack/receive-pack

2014-08-27 Thread Jonathan Nieder
Shawn Pearce wrote:

 The implementation sends an LF, but the protocol documentation was
 missing this detail.

 Signed-off-by: Shawn Pearce spea...@spearce.org
 ---
  Documentation/technical/pack-protocol.txt | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
 
 diff --git a/Documentation/technical/pack-protocol.txt 
 b/Documentation/technical/pack-protocol.txt
 index 18dea8d..569c48a 100644
 --- a/Documentation/technical/pack-protocol.txt
 +++ b/Documentation/technical/pack-protocol.txt
 @@ -467,7 +467,7 @@ references.
  
update-request=  *shallow command-list [pack-file]
  
 -  shallow   =  PKT-LINE(shallow SP obj-id)
 +  shallow   =  PKT-LINE(shallow SP obj-id LF)

In git, the client sends LF and the server is happy with or
without LF.  JGit and libgit2 don't send 'shallow' lines.

Reviewed-by: Jonathan Nieder jrnie...@gmail.com

  
command-list  =  PKT-LINE(command NUL capability-list LF)
  *PKT-LINE(command LF)
 -- 
--
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: problem with def of inet_ntop() in git-compat-util.h as well as other places

2014-08-27 Thread Jonathan Nieder
Hi again,

dev wrote:

 So I guess I have to create a config.mak file from somewhere.

Sorry, let's take a step back.

What exact commands do you use to build, starting from a pristine
extracted tarball?  What output do you get back?

[...]
 Undefined   first referenced
  symbol in file
 libiconv_close  libgit.a(utf8.o)  (symbol belongs to 
 implicit dependency /usr/local/lib/libiconv.so.2)

Sounds like NEEDS_LIBICONV should be set on Solaris.  You can test
this by passing NEEDS_LIBICONV=YesPlease on the gmake command line and
seeing what happens.

But it seems odd --- was iconv once part of libc on Solaris and then
moved out or something?  There have been lots of people building git
on Solaris over the years (and writing patches to fix other build
problems) without needing to set that flag.

[...]
 You would potentially also need to turn off a few feature flags manually

The options for tweaking the build are described at the top of the
Makefile.

Thanks again,
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: revert top most commit

2014-08-27 Thread Jonathan Nieder
Keller, Jacob E wrote:
 On Wed, 2014-08-27 at 21:14 +, Keller, Jacob E wrote:

 I am having trouble using revert. If I attempt to

 $ git revert sha1id

 where sha1id is the same as the HEAD commit, I instead get the output of
 what looks like git status.
[...]
 It's actually not my repository, I was helping a co-worker, and thought
 I'd ask if anyone here knew if it was expected behavior or not.

More details about the output would help --- otherwise people have to
guess[*].  I'm guessing your co-worker's working tree is not clean.
Commiting or stashing their changes first might get things working.

Hope that helps,
Jonathan

[*] Another nice thing about quoting output is that it becomes more
obvious what about it wasn't helpful, which sometimes leads to patches
from kind people on the list to fix it.
--
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] merge, pull: stop advising 'commit -a' in case of conflict

2014-08-28 Thread Jonathan Nieder
Matthieu Moy wrote:

 Signed-off-by: Matthieu Moy matthieu@imag.fr
[...]
 ---
  advice.c| 3 +--
  git-pull.sh | 2 +-
  2 files changed, 2 insertions(+), 3 deletions(-)

Thanks for taking it on.

Reviewed-by: Jonathan Nieder jrnie...@gmail.com

[...]
 It was already on my todo-list, as a friend of mine semi-beginner with
 Git complained about the mis-advice the other day, and I had to agree.

That's a useful sort of thing to put in a commit message. :)

 Eventually, git could detect that conflicts have been resolved, but
 then that would be a different message, as not only use git commit
 -a could be resurected, but Fix them up in the work tree should be
 dropped when it is the case.

As is this --- when I wonder why code isn't a certain way, ideas for
future work found in the description for the blamed commit are often
helpful in explaining the current state and saving me from blind
alleys in changing it.

Anyway, this is already a very good change as-is.

Actually, I'd be nervous about suggesting use git commit -a without
at least also saying inspect the result or run tests in the
no-conflict-markers-found case.  Rerere sometimes makes mistakes, and
the result of picking one side when merging binary files can be even
worse.

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


[PATCH 01/22] refs.c: change ref_transaction_create to do error checking and return status

2014-09-02 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Wed, 16 Apr 2014 15:26:44 -0700

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 sahlb...@google.com
Reviewed-by: Michael Haggerty mhag...@alum.mit.edu
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 builtin/update-ref.c |  4 +++-
 refs.c   | 18 --
 refs.h   | 48 +---
 3 files changed, 56 insertions(+), 14 deletions(-)

diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 3067b11..41121fa 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, err))
+   die(%s, err.buf);
 
update_flags = 0;
free(refname);
diff --git a/refs.c b/refs.c
index 3f05e88..c49f1c6 100644
--- a/refs.c
+++ b/refs.c
@@ -3449,18 +3449,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 c5376ce..b648819 100644
--- a/refs.h
+++ b/refs.h
@@ -10,6 +10,38 @@ struct ref_lock {
int force_write;
 };
 
+/*
+ * A ref_transaction represents a collection of ref updates
+ * that should succeed or fail together.
+ *
+ * Calling sequence
+ * 
+ * - Allocate and initialize a `struct ref_transaction` by calling
+ *   `ref_transaction_begin()`.
+ *
+ * - List intended ref updates by calling functions like
+ *   `ref_transaction_update()` and `ref_transaction_create()`.
+ *
+ * - Call `ref_transaction_commit()` to execute the transaction.
+ *   If this succeeds, the ref updates will have taken place and
+ *   the transaction cannot be rolled back.
+ *
+ * - At any time call `ref_transaction_free()` to discard the
+ *   transaction and free associated resources.  In particular,
+ *   this rolls back the transaction if it has not been
+ *   successfully committed.
+ *
+ * Error handling
+ * --
+ *
+ * On error, transaction functions append a message about what
+ * went wrong to the 'err' argument.  The message mentions what
+ * ref was being updated (if any) when the error occurred so it
+ * can be passed to 'die' or 'error' as-is.
+ *
+ * The message is appended to err without first clearing err.
+ * err will not be '\n' terminated.
+ */
 struct ref_transaction;
 
 /*
@@ -248,7 +280,7 @@ struct ref_transaction *ref_transaction_begin(void);
  * 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.
+ * rolled back.
  */
 int ref_transaction_update(struct ref_transaction *transaction,
   const char *refname,
@@ -262,11 +294,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.
  */
-void ref_transaction_create(struct ref_transaction *transaction,
-   const char *refname,
-   const unsigned char *new_sha1

[PATCH 22/22] update-ref --stdin: pass transaction around explicitly

2014-09-02 Thread Jonathan Nieder
This makes it more obvious at a glance where the output of functions
parsing the --stdin stream goes.

No functional change intended.

Signed-off-by: Jonathan Nieder jrnie...@gmail.com
Reviewed-by: Michael Haggerty mhag...@alum.mit.edu
---
Thanks for reading.

 builtin/update-ref.c | 27 +++
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 866bbee..54a48c0 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -12,8 +12,6 @@ static const char * const git_update_ref_usage[] = {
NULL
 };
 
-static struct ref_transaction *transaction;
-
 static char line_termination = '\n';
 static int update_flags;
 
@@ -176,7 +174,8 @@ static int parse_next_sha1(struct strbuf *input, const char 
**next,
  * depending on how line_termination is set.
  */
 
-static const char *parse_cmd_update(struct strbuf *input, const char *next)
+static const char *parse_cmd_update(struct ref_transaction *transaction,
+   struct strbuf *input, const char *next)
 {
struct strbuf err = STRBUF_INIT;
char *refname;
@@ -209,7 +208,8 @@ static const char *parse_cmd_update(struct strbuf *input, 
const char *next)
return next;
 }
 
-static const char *parse_cmd_create(struct strbuf *input, const char *next)
+static const char *parse_cmd_create(struct ref_transaction *transaction,
+   struct strbuf *input, const char *next)
 {
struct strbuf err = STRBUF_INIT;
char *refname;
@@ -239,7 +239,8 @@ static const char *parse_cmd_create(struct strbuf *input, 
const char *next)
return next;
 }
 
-static const char *parse_cmd_delete(struct strbuf *input, const char *next)
+static const char *parse_cmd_delete(struct ref_transaction *transaction,
+   struct strbuf *input, const char *next)
 {
struct strbuf err = STRBUF_INIT;
char *refname;
@@ -273,7 +274,8 @@ static const char *parse_cmd_delete(struct strbuf *input, 
const char *next)
return next;
 }
 
-static const char *parse_cmd_verify(struct strbuf *input, const char *next)
+static const char *parse_cmd_verify(struct ref_transaction *transaction,
+   struct strbuf *input, const char *next)
 {
struct strbuf err = STRBUF_INIT;
char *refname;
@@ -317,7 +319,7 @@ static const char *parse_cmd_option(struct strbuf *input, 
const char *next)
return next + 8;
 }
 
-static void update_refs_stdin(void)
+static void update_refs_stdin(struct ref_transaction *transaction)
 {
struct strbuf input = STRBUF_INIT;
const char *next;
@@ -332,13 +334,13 @@ static void update_refs_stdin(void)
else if (isspace(*next))
die(whitespace before command: %s, next);
else if (starts_with(next, update ))
-   next = parse_cmd_update(input, next + 7);
+   next = parse_cmd_update(transaction, input, next + 7);
else if (starts_with(next, create ))
-   next = parse_cmd_create(input, next + 7);
+   next = parse_cmd_create(transaction, input, next + 7);
else if (starts_with(next, delete ))
-   next = parse_cmd_delete(input, next + 7);
+   next = parse_cmd_delete(transaction, input, next + 7);
else if (starts_with(next, verify ))
-   next = parse_cmd_verify(input, next + 7);
+   next = parse_cmd_verify(transaction, input, next + 7);
else if (starts_with(next, option ))
next = parse_cmd_option(input, next + 7);
else
@@ -373,6 +375,7 @@ int cmd_update_ref(int argc, const char **argv, const char 
*prefix)
 
if (read_stdin) {
struct strbuf err = STRBUF_INIT;
+   struct ref_transaction *transaction;
 
transaction = ref_transaction_begin(err);
if (!transaction)
@@ -381,7 +384,7 @@ int cmd_update_ref(int argc, const char **argv, const char 
*prefix)
usage_with_options(git_update_ref_usage, options);
if (end_null)
line_termination = '\0';
-   update_refs_stdin();
+   update_refs_stdin(transaction);
if (ref_transaction_commit(transaction, msg, err))
die(%s, err.buf);
ref_transaction_free(transaction);
-- 
2.1.0.rc2.206.gedb03e5

--
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: [RFC PATCH v2 1/2] Makefile: add check-headers target

2014-09-07 Thread Jonathan Nieder
Hi,

David Aguilar wrote:

 --- /dev/null
 +++ b/check-headers.sh
 @@ -0,0 +1,29 @@
[...]
 + $@ -Wno-unused -I$subdir -c -o $header.check -x c - $header 

All .c files in git are supposed to start by #include-ing
git-compat-util.h, cache.h, or builtin.h to set the appropriate
feature test macros and include system headers.

Headers rely on that for basic types like int32_t.  They don't need to
include git-compat-util.h because the .c file that included them would
have already, and .h files #include-ed by git-compat-util.h especially
*shouldn't* #include the compat header, so how about something like
the following for squashing in?

A side-thought: as long as we're building pre-compiled headers, could
we use them in the build?

Thanks,
Jonathan

diff --git a/check-headers.sh b/check-headers.sh
index bf85c41..08ca136 100755
--- a/check-headers.sh
+++ b/check-headers.sh
@@ -18,7 +18,7 @@ git ls-files *.h |
 while read header
 do
echo HEADER $header 
-   $@ -Wno-unused -x c -c -o $header.bin - $header 
+   $@ -Wno-unused -x c -include git-compat-util.h -c -o $header.bin - 
$header 
rm $header.bin ||
maybe_exit $?
 done
--
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: [RFC PATCH v2 2/2] headers: include dependent headers

2014-09-07 Thread Jonathan Nieder
David Aguilar wrote:

 Add dependent headers so that including a header does not
 require including additional headers.

I agree with this goal, modulo the compat-util.h caveat.  Thanks
for working on it.

[...]
 --- a/archive.h
 +++ b/archive.h
 @@ -1,6 +1,7 @@
  #ifndef ARCHIVE_H
  #define ARCHIVE_H
  
 +#include cache.h
  #include pathspec.h
  
  struct archiver_args {

I'm less happy about the way of achieving that goal.  Here's an
alternative.  Advantages:

 * (fully expanded) headers stay small

 * fewer other headers included as a side-effect of including one
   header, so callers are more likely to remember to #include the
   headers defining things they need (which makes later refactoring
   easier)

 * circular header dependencies are harder to produce

If this seems like a good direction to go in, I can finish the patch
later today (or I don't mind if someone else takes care of it).  This
is just to give the idea --- I stopped at dir.h.

Sensible?
Jonathan

diff --git i/archive.h w/archive.h
index 4a791e1..11f4d42 100644
--- i/archive.h
+++ w/archive.h
@@ -3,6 +3,9 @@
 
 #include pathspec.h
 
+enum object_type;
+
+
 struct archiver_args {
const char *base;
size_t baselen;
diff --git i/attr.h w/attr.h
index 8b08d33..c971ef2 100644
--- i/attr.h
+++ w/attr.h
@@ -1,6 +1,8 @@
 #ifndef ATTR_H
 #define ATTR_H
 
+struct index_state;
+
 /* An attribute is a pointer to this opaque structure */
 struct git_attr;
 
diff --git i/branch.h w/branch.h
index 64173ab..ed63209 100644
--- i/branch.h
+++ w/branch.h
@@ -1,6 +1,9 @@
 #ifndef BRANCH_H
 #define BRANCH_H
 
+enum branch_track;
+struct strbuf;
+
 /* Functions for acting on the information about branches. */
 
 /*
diff --git i/cache-tree.h w/cache-tree.h
index b47ccec..c22e2ec 100644
--- i/cache-tree.h
+++ w/cache-tree.h
@@ -1,8 +1,12 @@
 #ifndef CACHE_TREE_H
 #define CACHE_TREE_H
 
-#include tree.h
-#include tree-walk.h
+struct traverse_info;
+struct index_state;
+struct name_entry;
+struct tree;
+struct string_list;
+struct strbuf;
 
 struct cache_tree;
 struct cache_tree_sub {
diff --git i/column.h w/column.h
index 0a61917..8211386 100644
--- i/column.h
+++ w/column.h
@@ -1,6 +1,9 @@
 #ifndef COLUMN_H
 #define COLUMN_H
 
+struct option;
+struct string_list;
+
 #define COL_LAYOUT_MASK   0x000F
 #define COL_ENABLE_MASK   0x0030   /* always, never or auto */
 #define COL_PARSEOPT  0x0040   /* --column is given from cmdline */
@@ -26,7 +29,6 @@ struct column_options {
const char *nl;
 };
 
-struct option;
 extern int parseopt_column_callback(const struct option *, const char *, int);
 extern int git_column_config(const char *var, const char *value,
 const char *command, unsigned int *colopts);
diff --git i/commit.h w/commit.h
index aa8c3ca..d2fd182 100644
--- i/commit.h
+++ w/commit.h
@@ -1,13 +1,18 @@
 #ifndef COMMIT_H
 #define COMMIT_H
 
+#include cache.h
 #include object.h
-#include tree.h
-#include strbuf.h
-#include decorate.h
-#include gpg-interface.h
+#include trace.h
 #include string-list.h
 
+struct reflog_walk_info;
+struct rev_info;
+struct ref;
+struct signature_check;
+struct sha1_array;
+struct strbuf;
+
 struct commit_list {
struct commit *item;
struct commit_list *next;
@@ -151,7 +156,6 @@ struct userformat_want {
 };
 
 extern int has_non_ascii(const char *text);
-struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
 extern const char *logmsg_reencode(const struct commit *commit,
   char **commit_encoding,
   const char *output_encoding);
@@ -231,8 +235,6 @@ extern struct commit_list *get_octopus_merge_bases(struct 
commit_list *in);
 /* largest positive number a signed 32-bit integer can contain */
 #define INFINITE_DEPTH 0x7fff
 
-struct sha1_array;
-struct ref;
 extern int register_shallow(const unsigned char *sha1);
 extern int unregister_shallow(const unsigned char *sha1);
 extern int for_each_commit_graft(each_commit_graft_fn, void *);
diff --git i/convert.h w/convert.h
index 0c2143c..e623527 100644
--- i/convert.h
+++ w/convert.h
@@ -4,6 +4,8 @@
 #ifndef CONVERT_H
 #define CONVERT_H
 
+struct strbuf;
+
 enum safe_crlf {
SAFE_CRLF_FALSE = 0,
SAFE_CRLF_FAIL = 1,
diff --git i/csum-file.h w/csum-file.h
index bb543d5..9e29e35 100644
--- i/csum-file.h
+++ w/csum-file.h
@@ -1,6 +1,8 @@
 #ifndef CSUM_FILE_H
 #define CSUM_FILE_H
 
+#include cache.h
+
 struct progress;
 
 /* A SHA1-protected file */
diff --git i/diffcore.h w/diffcore.h
index c876dac..96fc827 100644
--- i/diffcore.h
+++ w/diffcore.h
@@ -4,6 +4,9 @@
 #ifndef DIFFCORE_H
 #define DIFFCORE_H
 
+struct userdiff_driver;
+struct diff_options;
+
 /* This header file is internal between diff.c and its diff transformers
  * (e.g. diffcore-rename, diffcore-pickaxe).  Never include this header
  * in anything else.
@@ -22,8 +25,6 @@
 
 #define MINIMUM_BREAK_SIZE 400 /* do not break a file smaller than this */
 

Re: [RFC PATCH v2 2/2] headers: include dependent headers

2014-09-07 Thread Jonathan Nieder
Johannes Sixt wrote:
 Am 07.09.2014 21:49, schrieb Jonathan Nieder:

 +enum object_type;

 Enum forward declarations are a relatively new C feature. They certainly
 don't exist pre-C99.

Good catch.  That makes

diff --git i/archive.h w/archive.h
index 4a791e1..b2ca5bf 100644
--- i/archive.h
+++ w/archive.h
@@ -1,6 +1,7 @@
 #ifndef ARCHIVE_H
 #define ARCHIVE_H
 
+#include cache.h
 #include pathspec.h
 
 struct archiver_args {
diff --git i/attr.h w/attr.h
index 8b08d33..c971ef2 100644
--- i/attr.h
+++ w/attr.h
@@ -1,6 +1,8 @@
 #ifndef ATTR_H
 #define ATTR_H
 
+struct index_state;
+
 /* An attribute is a pointer to this opaque structure */
 struct git_attr;
 
diff --git i/branch.h w/branch.h
index 64173ab..5ce6e21 100644
--- i/branch.h
+++ w/branch.h
@@ -1,6 +1,8 @@
 #ifndef BRANCH_H
 #define BRANCH_H
 
+#include cache.h
+
 /* Functions for acting on the information about branches. */
 
 /*
diff --git i/cache-tree.h w/cache-tree.h
index b47ccec..c22e2ec 100644
--- i/cache-tree.h
+++ w/cache-tree.h
@@ -1,8 +1,12 @@
 #ifndef CACHE_TREE_H
 #define CACHE_TREE_H
 
-#include tree.h
-#include tree-walk.h
+struct traverse_info;
+struct index_state;
+struct name_entry;
+struct tree;
+struct string_list;
+struct strbuf;
 
 struct cache_tree;
 struct cache_tree_sub {
diff --git i/column.h w/column.h
index 0a61917..8211386 100644
--- i/column.h
+++ w/column.h
@@ -1,6 +1,9 @@
 #ifndef COLUMN_H
 #define COLUMN_H
 
+struct option;
+struct string_list;
+
 #define COL_LAYOUT_MASK   0x000F
 #define COL_ENABLE_MASK   0x0030   /* always, never or auto */
 #define COL_PARSEOPT  0x0040   /* --column is given from cmdline */
@@ -26,7 +29,6 @@ struct column_options {
const char *nl;
 };
 
-struct option;
 extern int parseopt_column_callback(const struct option *, const char *, int);
 extern int git_column_config(const char *var, const char *value,
 const char *command, unsigned int *colopts);
diff --git i/commit.h w/commit.h
index aa8c3ca..097fc9e 100644
--- i/commit.h
+++ w/commit.h
@@ -1,13 +1,17 @@
 #ifndef COMMIT_H
 #define COMMIT_H
 
+#include cache.h
 #include object.h
-#include tree.h
-#include strbuf.h
-#include decorate.h
-#include gpg-interface.h
+#include trace.h
 #include string-list.h
 
+struct reflog_walk_info;
+struct rev_info;
+struct ref;
+struct signature_check;
+struct sha1_array;
+
 struct commit_list {
struct commit *item;
struct commit_list *next;
@@ -151,7 +155,6 @@ struct userformat_want {
 };
 
 extern int has_non_ascii(const char *text);
-struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
 extern const char *logmsg_reencode(const struct commit *commit,
   char **commit_encoding,
   const char *output_encoding);
@@ -231,8 +234,6 @@ extern struct commit_list *get_octopus_merge_bases(struct 
commit_list *in);
 /* largest positive number a signed 32-bit integer can contain */
 #define INFINITE_DEPTH 0x7fff
 
-struct sha1_array;
-struct ref;
 extern int register_shallow(const unsigned char *sha1);
 extern int unregister_shallow(const unsigned char *sha1);
 extern int for_each_commit_graft(each_commit_graft_fn, void *);
diff --git i/convert.h w/convert.h
index 0c2143c..e623527 100644
--- i/convert.h
+++ w/convert.h
@@ -4,6 +4,8 @@
 #ifndef CONVERT_H
 #define CONVERT_H
 
+struct strbuf;
+
 enum safe_crlf {
SAFE_CRLF_FALSE = 0,
SAFE_CRLF_FAIL = 1,
diff --git i/csum-file.h w/csum-file.h
index bb543d5..9e29e35 100644
--- i/csum-file.h
+++ w/csum-file.h
@@ -1,6 +1,8 @@
 #ifndef CSUM_FILE_H
 #define CSUM_FILE_H
 
+#include cache.h
+
 struct progress;
 
 /* A SHA1-protected file */
diff --git i/diffcore.h w/diffcore.h
index c876dac..96fc827 100644
--- i/diffcore.h
+++ w/diffcore.h
@@ -4,6 +4,9 @@
 #ifndef DIFFCORE_H
 #define DIFFCORE_H
 
+struct userdiff_driver;
+struct diff_options;
+
 /* This header file is internal between diff.c and its diff transformers
  * (e.g. diffcore-rename, diffcore-pickaxe).  Never include this header
  * in anything else.
@@ -22,8 +25,6 @@
 
 #define MINIMUM_BREAK_SIZE 400 /* do not break a file smaller than this */
 
-struct userdiff_driver;
-
 struct diff_filespec {
unsigned char sha1[20];
char *path;
diff --git i/object.h w/object.h
index 5e8d8ee..e61b290 100644
--- i/object.h
+++ w/object.h
@@ -1,6 +1,8 @@
 #ifndef OBJECT_H
 #define OBJECT_H
 
+#include cache.h
+
 struct object_list {
struct object *item;
struct object_list *next;
diff --git i/tree-walk.h w/tree-walk.h
index ae7fb3a..d7612cf 100644
--- i/tree-walk.h
+++ w/tree-walk.h
@@ -1,6 +1,8 @@
 #ifndef TREE_WALK_H
 #define TREE_WALK_H
 
+struct strbuf;
+
 struct name_entry {
const unsigned char *sha1;
const char *path;
diff --git i/tree.h w/tree.h
index d84ac63..ef84153 100644
--- i/tree.h
+++ w/tree.h
@@ -3,6 +3,9 @@
 
 #include object.h
 
+struct pathspec;
+
+
 extern const char *tree_type;
 
 struct tree

Re: [PATCH] fsck: exit with non-zero status upon error from fsck_obj()

2014-09-09 Thread Jonathan Nieder
Junio C Hamano wrote:

 By the way, Jonathan, with dbedf8bf (t1450 (fsck): remove dangling
 objects, 2010-09-06) you added a 'test_might_fail git fsck' to the
 1450 test that catches an object corruption.  Do you remember if
 there was some flakiness in this test that necessitated it, or is it
 merely I think this should fail, but it does not, and we may fix it
 some day but I am not doing that in this patch?

Thomas is the person to ask. :)  See v1.6.3-rc0~176^2~3 (Test fsck a
bit harder, 2009-02-19):

 + (git fsck 2out; true) 

which that cleanup tightened to test_might_fail.

But yes, I'm pretty sure it was for futureproofing, not for hiding
flakiness.  I think your patch does the right thing in changing it to
test_must_fail now that fsck exits nonzero.

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


[PATCH v21 0/19] rs/ref-transaction (Re: Transaction patch series overview)

2014-09-10 Thread Jonathan Nieder
Jonathan Nieder wrote:

 The next series from Ronnie's collection is available at
 https://code-review.googlesource.com/#/q/topic:ref-transaction in case
 someone wants a fresh series to look at.

Here is the outcome of that review.  It could use another set of eyes
(hint, hint) but should be mostly ready.  Interdiff below.  This is meant
to replace rs/ref-transaction in 'pu' and I'd prefer to wait a little
for more comments before merging to 'next'.

These patches are also available from the git repository at

  git://repo.or.cz/git/jrn.git tags/rs/ref-transaction

Use ref transactions, part 3

Ronnie explains:

This is the third and final part of the original 48 patch
series for basic transaction support.  This version implements
some changes suggested by mhagger for the warn_if_unremovable
changes.  It also adds a new patch fix handling of badly
named refs that repairs the handling of badly named refs.

This includes some improvements to the transaction API (in
particular allowing different reflog messages per ref update in
a transaction), some cleanups and consistency improvements, and
preparation for an implementation of ref renaming in terms of
the transaction API.

It also improves handling of refs with invalid names.  Today git
branch --list and git for-each-ref do not provide a way to discover
refs with invalid names and git branch -d and git update-ref -d
cannot delete them.  After this series, such bad refs will be
discoverable and deletable again as in olden times.

Jonathan Nieder (5):
  mv test: recreate mod/ directory instead of relying on stale copy
  branch -d: avoid repeated symref resolution
  refs.c: do not permit err == NULL
  lockfile: remove unable_to_lock_error
  ref_transaction_commit: bail out on failure to remove a ref

Ronnie Sahlberg (14):
  wrapper.c: remove/unlink_or_warn: simplify, treat ENOENT as success
  wrapper.c: add a new function unlink_or_msg
  refs.c: add an err argument to delete_ref_loose
  refs.c: pass the ref log message to _create/delete/update instead of
_commit
  rename_ref: don't ask read_ref_full where the ref came from
  refs.c: move the check for valid refname to lock_ref_sha1_basic
  refs.c: call lock_ref_sha1_basic directly from commit
  refs.c: pass a skip list to name_conflict_fn
  refs.c: ref_transaction_commit: distinguish name conflicts from other
errors
  fetch.c: change s_update_ref to use a ref transaction
  refs.c: make write_ref_sha1 static
  refs.c: change resolve_ref_unsafe reading argument to be a flags field
  refs.c: fix handling of badly named refs
  for-each-ref.c: improve message before aborting on broken ref

 branch.c|   6 +-
 builtin/blame.c |   2 +-
 builtin/branch.c|  19 ++-
 builtin/checkout.c  |   6 +-
 builtin/clone.c |   2 +-
 builtin/commit.c|   6 +-
 builtin/fetch.c |  34 +++--
 builtin/fmt-merge-msg.c |   2 +-
 builtin/for-each-ref.c  |  12 +-
 builtin/fsck.c  |   2 +-
 builtin/log.c   |   3 +-
 builtin/merge.c |   2 +-
 builtin/notes.c |   2 +-
 builtin/receive-pack.c  |   9 +-
 builtin/remote.c|   5 +-
 builtin/replace.c   |   5 +-
 builtin/show-branch.c   |   6 +-
 builtin/symbolic-ref.c  |   2 +-
 builtin/tag.c   |   4 +-
 builtin/update-ref.c|  16 ++-
 bundle.c|   2 +-
 cache.h |  31 +++--
 fast-import.c   |   8 +-
 git-compat-util.h   |  16 ++-
 http-backend.c  |   3 +-
 lockfile.c  |  10 --
 notes-merge.c   |   2 +-
 reflog-walk.c   |   5 +-
 refs.c  | 321 ++--
 refs.h  |  18 ++-
 remote.c|  10 +-
 sequencer.c |   8 +-
 t/t1400-update-ref.sh   |  16 +++
 t/t1402-check-ref-format.sh |  48 +++
 t/t3200-branch.sh   |   9 ++
 t/t7001-mv.sh   |  15 ++-
 transport-helper.c  |   4 +-
 transport.c |   5 +-
 upload-pack.c   |   2 +-
 walker.c|   5 +-
 wrapper.c   |  28 ++--
 wt-status.c |   2 +-
 42 files changed, 487 insertions(+), 226 deletions(-)
---
Changes since last appearance:

diff --git c/branch.c w/branch.c
index 76a8ec9..ba3e1c1 100644
--- c/branch.c
+++ w/branch.c
@@ -186,7 +186,7 @@ int validate_new_branchname(const char *name, struct strbuf 
*ref,
const char *head;
unsigned char sha1[20];
 
-   head = resolve_ref_unsafe(HEAD, sha1, 0, NULL);
+   head = resolve_ref_unsafe(HEAD, sha1, NULL, 0);
if (!is_bare_repository()  head  !strcmp(head, ref-buf))
die(_(Cannot force update the current branch.));
}
diff --git c/builtin/blame.c w

[PATCH 01/19] mv test: recreate mod/ directory instead of relying on stale copy

2014-09-10 Thread Jonathan Nieder
The tests for 'git mv moves a submodule' functionality often run
commands like

git mv sub mod/sub

to move a submodule into a subdirectory.  Just like plain /bin/mv,
this is supposed to succeed if the mod/ parent directory exists
and fail if it doesn't exist.

Usually these tests mkdir the parent directory beforehand, but some
instead rely on it being left behind by previous tests.

More precisely, when 'git reset --hard' tries to move to a state where
mod/sub is not present any more, it would perform the following
operations:

rmdir(mod/sub)
rmdir(mod)

The first fails with ENOENT because the test script removed mod/sub
with rm -rf already, so 'reset --hard' doesn't bother to move on to
the second, and the mod/ directory is kept around.

Better to explicitly remove and re-create the mod/ directory so later
tests don't have to depend on the directory left behind by the earlier
ones at all (making it easier to rearrange or skip some tests in the
file or to tweak 'reset --hard' behavior without breaking unrelated
tests).

Noticed while testing a patch that fixes the reset --hard behavior
described above.

Signed-off-by: Jonathan Nieder jrnie...@gmail.com
Reviewed-by: Ronnie Sahlberg sahlb...@google.com
---
 t/t7001-mv.sh | 15 ++-
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh
index 54d7807..69f11bd 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -350,10 +350,11 @@ test_expect_success 'git mv moves a submodule with a .git 
directory and .gitmodu
 '
 
 test_expect_success 'git mv moves a submodule with gitfile' '
-   rm -rf mod/sub 
+   rm -rf mod 
git reset --hard 
git submodule update 
entry=$(git ls-files --stage sub | cut -f 1) 
+   mkdir mod 
(
cd mod 
git mv ../sub/ .
@@ -372,11 +373,12 @@ test_expect_success 'git mv moves a submodule with 
gitfile' '
 '
 
 test_expect_success 'mv does not complain when no .gitmodules file is found' '
-   rm -rf mod/sub 
+   rm -rf mod 
git reset --hard 
git submodule update 
git rm .gitmodules 
entry=$(git ls-files --stage sub | cut -f 1) 
+   mkdir mod 
git mv sub mod/sub 2actual.err 
! test -s actual.err 
! test -e sub 
@@ -390,11 +392,12 @@ test_expect_success 'mv does not complain when no 
.gitmodules file is found' '
 '
 
 test_expect_success 'mv will error out on a modified .gitmodules file unless 
staged' '
-   rm -rf mod/sub 
+   rm -rf mod 
git reset --hard 
git submodule update 
git config -f .gitmodules foo.bar true 
entry=$(git ls-files --stage sub | cut -f 1) 
+   mkdir mod 
test_must_fail git mv sub mod/sub 2actual.err 
test -s actual.err 
test -e sub 
@@ -413,13 +416,14 @@ test_expect_success 'mv will error out on a modified 
.gitmodules file unless sta
 '
 
 test_expect_success 'mv issues a warning when section is not found in 
.gitmodules' '
-   rm -rf mod/sub 
+   rm -rf mod 
git reset --hard 
git submodule update 
git config -f .gitmodules --remove-section submodule.sub 
git add .gitmodules 
entry=$(git ls-files --stage sub | cut -f 1) 
echo warning: Could not find section in .gitmodules where path=sub 
expect.err 
+   mkdir mod 
git mv sub mod/sub 2actual.err 
test_i18ncmp expect.err actual.err 
! test -e sub 
@@ -433,9 +437,10 @@ test_expect_success 'mv issues a warning when section is 
not found in .gitmodule
 '
 
 test_expect_success 'mv --dry-run does not touch the submodule or .gitmodules' 
'
-   rm -rf mod/sub 
+   rm -rf mod 
git reset --hard 
git submodule update 
+   mkdir mod 
git mv -n sub mod/sub 2actual.err 
test -f sub/.git 
git diff-index --exit-code HEAD 
-- 
2.1.0.rc2.206.gedb03e5

--
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 02/19] wrapper.c: remove/unlink_or_warn: simplify, treat ENOENT as success

2014-09-10 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com

Simplify the function warn_if_unremovable slightly. Additionally, change
behaviour slightly. If we failed to remove the object because the object
does not exist, we can still return success back to the caller since none of
the callers depend on fail if the file did not exist.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 git-compat-util.h |  7 +--
 wrapper.c | 14 ++
 2 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/git-compat-util.h b/git-compat-util.h
index b6f03b3..611e77b 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -706,11 +706,14 @@ void git_qsort(void *base, size_t nmemb, size_t size,
 
 /*
  * Preserves errno, prints a message, but gives no warning for ENOENT.
- * Always returns the return value of unlink(2).
+ * Returns 0 on success which includes trying to unlink an object that does
+ * not exist.
  */
 int unlink_or_warn(const char *path);
 /*
- * Likewise for rmdir(2).
+ * Preserves errno, prints a message, but gives no warning for ENOENT.
+ * Returns 0 on success which includes trying to remove a directory that does
+ * not exist.
  */
 int rmdir_or_warn(const char *path);
 /*
diff --git a/wrapper.c b/wrapper.c
index bc1bfb8..c9605cd 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -429,14 +429,12 @@ int xmkstemp_mode(char *template, int mode)
 
 static int warn_if_unremovable(const char *op, const char *file, int rc)
 {
-   if (rc  0) {
-   int err = errno;
-   if (ENOENT != err) {
-   warning(unable to %s %s: %s,
-   op, file, strerror(errno));
-   errno = err;
-   }
-   }
+   int err;
+   if (!rc || errno == ENOENT)
+   return 0;
+   err = errno;
+   warning(unable to %s %s: %s, op, file, strerror(errno));
+   errno = err;
return rc;
 }
 
-- 
2.1.0.rc2.206.gedb03e5

--
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 03/19] wrapper.c: add a new function unlink_or_msg

2014-09-10 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Wed, 16 Jul 2014 11:20:36 -0700

This behaves like unlink_or_warn except that on failure it writes the message
to its 'err' argument, which the caller can display in an appropriate way or
ignore.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 git-compat-util.h |  9 +
 wrapper.c | 14 ++
 2 files changed, 23 insertions(+)

diff --git a/git-compat-util.h b/git-compat-util.h
index 611e77b..5ee140c 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -307,6 +307,8 @@ extern char *gitbasename(char *);
 
 #include wildmatch.h
 
+struct strbuf;
+
 /* General helper functions */
 extern void vreportf(const char *prefix, const char *err, va_list params);
 extern void vwritef(int fd, const char *prefix, const char *err, va_list 
params);
@@ -710,6 +712,13 @@ void git_qsort(void *base, size_t nmemb, size_t size,
  * not exist.
  */
 int unlink_or_warn(const char *path);
+ /*
+  * Tries to unlink file.  Returns 0 if unlink succeeded
+  * or the file already didn't exist.  Returns -1 and
+  * appends a message to err suitable for
+  * 'error(%s, err-buf)' on error.
+  */
+int unlink_or_msg(const char *file, struct strbuf *err);
 /*
  * Preserves errno, prints a message, but gives no warning for ENOENT.
  * Returns 0 on success which includes trying to remove a directory that does
diff --git a/wrapper.c b/wrapper.c
index c9605cd..ec7a08b 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -438,6 +438,20 @@ static int warn_if_unremovable(const char *op, const char 
*file, int rc)
return rc;
 }
 
+int unlink_or_msg(const char *file, struct strbuf *err)
+{
+   int rc = unlink(file);
+
+   assert(err);
+
+   if (!rc || errno == ENOENT)
+   return 0;
+
+   strbuf_addf(err, unable to unlink %s: %s,
+   file, strerror(errno));
+   return -1;
+}
+
 int unlink_or_warn(const char *file)
 {
return warn_if_unremovable(unlink, file, unlink(file));
-- 
2.1.0.rc2.206.gedb03e5

--
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 04/19] refs.c: add an err argument to delete_ref_loose

2014-09-10 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Thu, 15 May 2014 08:25:23 -0700

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.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 refs.c | 11 ++-
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/refs.c b/refs.c
index 7235574..5609622 100644
--- a/refs.c
+++ b/refs.c
@@ -2548,16 +2548,16 @@ int repack_without_refs(const char **refnames, int n, 
struct strbuf *err)
return ret;
 }
 
-static int delete_ref_loose(struct ref_lock *lock, int flag)
+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_msg(lock-lk-filename, err);
lock-lk-filename[i] = '.';
-   if (err  errno != ENOENT)
+   if (res)
return 1;
}
return 0;
@@ -3604,7 +3604,8 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
struct ref_update *update = updates[i];
 
if (update-lock) {
-   ret |= delete_ref_loose(update-lock, update-type);
+   ret |= delete_ref_loose(update-lock, update-type,
+   err);
if (!(update-flags  REF_ISPRUNING))
delnames[delnum++] = update-lock-ref_name;
}
-- 
2.1.0.rc2.206.gedb03e5

--
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 07/19] refs.c: move the check for valid refname to lock_ref_sha1_basic

2014-09-10 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Thu, 1 May 2014 10:40:10 -0700

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 has no visible impact to callers,
except for inability to lock badly named refs which is not possible today
anyway but for other reasons.

Keep lock_any_ref_for_update as a no-op wrapper --- it is the public facing
version of this interface and keeping it as a separate function will make
it easier to experiment with the internal lock_ref_sha1_basic signature.

Note that if lock_ref_sha1_basic now checks the refname format and fails to
lock the ref it will not be possible to delete such a ref since deletion
implies we first lock the ref. In fact, we currently fail even earlier than
that since these refs are not even recognized to exist.

Example:
$ cp .git/refs/heads/master .git/refs/heads/echo...\*\*
$ ./git branch -D .git/refs/heads/echo...\*\*
error: branch '.git/refs/heads/echo...**' not found.

This is not a new regression and this has been broken for a while.
Later patches in the series will start repairing the handling of badly
named refs, at which time we will need to modify lock_ref_sha1_basic once more
in order to allow locking these refs for certain use cases such as rename
and delete.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 refs.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/refs.c b/refs.c
index 39571f5..3c2ce57 100644
--- a/refs.c
+++ b/refs.c
@@ -2091,6 +2091,11 @@ 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)) {
+   errno = EINVAL;
+   return NULL;
+   }
+
lock = xcalloc(1, sizeof(struct ref_lock));
lock-lock_fd = -1;
 
@@ -2182,8 +2187,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.1.0.rc2.206.gedb03e5

--
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 06/19] rename_ref: don't ask read_ref_full where the ref came from

2014-09-10 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Wed, 30 Apr 2014 12:41:04 -0700

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 sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 refs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/refs.c b/refs.c
index 99a9b86..39571f5 100644
--- a/refs.c
+++ b/refs.c
@@ -2671,7 +2671,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.1.0.rc2.206.gedb03e5

--
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 05/19] refs.c: pass the ref log message to _create/delete/update instead of _commit

2014-09-10 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Wed, 30 Apr 2014 12:22:42 -0700

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 sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 branch.c   |  4 ++--
 builtin/commit.c   |  4 ++--
 builtin/receive-pack.c |  5 +++--
 builtin/replace.c  |  5 +++--
 builtin/tag.c  |  4 ++--
 builtin/update-ref.c   | 13 +++--
 fast-import.c  |  8 
 refs.c | 34 +-
 refs.h |  8 
 sequencer.c|  4 ++--
 walker.c   |  5 ++---
 11 files changed, 52 insertions(+), 42 deletions(-)

diff --git a/branch.c b/branch.c
index 37ac555..76a8ec9 100644
--- a/branch.c
+++ b/branch.c
@@ -301,8 +301,8 @@ void create_branch(const char *head,
transaction = ref_transaction_begin(err);
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);
strbuf_release(err);
diff --git a/builtin/commit.c b/builtin/commit.c
index 9bf1003..d23e876 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1767,8 +1767,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/receive-pack.c b/builtin/receive-pack.c
index 224fadc..d1f4cf7 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -585,8 +585,9 @@ static const char *update(struct command *cmd, struct 
shallow_info *si)
transaction = ref_transaction_begin(err);
if (!transaction ||
ref_transaction_update(transaction, namespaced_name,
-  new_sha1, old_sha1, 0, 1, err) ||
-   ref_transaction_commit(transaction, push, err)) {
+  new_sha1, old_sha1, 0, 1, push,
+  err) ||
+   ref_transaction_commit(transaction, err)) {
ref_transaction_free(transaction);
 
rp_error(%s, err.buf);
diff --git a/builtin/replace.c b/builtin/replace.c
index 1fcd06d..9d03b84 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -169,8 +169,9 @@ static int replace_object_sha1(const char *object_ref,
 
transaction = ref_transaction_begin(err);
if (!transaction ||
-   ref_transaction_update(transaction, ref, repl, prev, 0, 1, err) ||
-   ref_transaction_commit(transaction, NULL, err))
+   ref_transaction_update(transaction, ref, repl, prev,
+  0, 1, NULL, err) ||
+   ref_transaction_commit(transaction, err))
die(%s, err.buf);
 
ref_transaction_free(transaction);
diff --git a/builtin/tag.c b/builtin/tag.c
index f3f172f..70d28c5 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -705,8 +705,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
transaction = ref_transaction_begin(err);
if (!transaction ||
ref_transaction_update(transaction, ref.buf, object, prev,
-  0, 1, err) ||
-   ref_transaction_commit(transaction, NULL, err))
+  0, 1, NULL, err) ||
+   ref_transaction_commit(transaction, err))
die(%s, err.buf);
ref_transaction_free(transaction);
if (force  !is_null_sha1(prev)  hashcmp(prev, object))
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 54a48c0..6c9be05 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -14,6 +14,7 @@ static const char * const git_update_ref_usage[] = {
 
 static char line_termination = '\n';
 static int update_flags;
+static const char *msg;
 
 /*
  * Parse one whitespace- or NUL-terminated, possibly C-quoted argument
@@ -198,7 +199,7 @@ static const char

[PATCH 08/19] refs.c: call lock_ref_sha1_basic directly from commit

2014-09-10 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Thu, 1 May 2014 10:43:39 -0700

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 sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 refs.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/refs.c b/refs.c
index 3c2ce57..f124c2b 100644
--- a/refs.c
+++ b/refs.c
@@ -3578,12 +3578,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.1.0.rc2.206.gedb03e5

--
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 10/19] refs.c: ref_transaction_commit: distinguish name conflicts from other errors

2014-09-10 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Fri, 16 May 2014 14:14:38 -0700

In _commit, ENOTDIR can happen in the call to lock_ref_sha1_basic, either when
we lstat the new refname and it returns ENOTDIR or if the name checking
function reports that the same type of conflict happened. In both cases it
means that we can not create the new ref due to a name conflict.

Start defining specific return codes for _commit: assign -1 as a generic
error and UPDATE_REFS_NAME_CONFLICT (-2) as the error that refers to a name
conflict.

When git fetch is creating refs, name conflicts differ from other errors in
that they are likely to be resolved by running git remote prune remote.
git fetch currently inspects errno to decide whether to give that advice.
Once it switches to the transaction API, it can check for
UPDATE_REFS_NAME_CONFLICT instead.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 refs.c | 18 --
 refs.h |  5 +
 2 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/refs.c b/refs.c
index b63ab2f..86c708a 100644
--- a/refs.c
+++ b/refs.c
@@ -3584,9 +3584,10 @@ 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);
-   if (ret)
+   if (ref_update_reject_duplicates(updates, n, err)) {
+   ret = -1;
goto cleanup;
+   }
 
/* Acquire all locks while verifying old values */
for (i = 0; i  n; i++) {
@@ -3600,10 +3601,12 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
   update-flags,
   update-type);
if (!update-lock) {
+   int df_conflict = (errno == ENOTDIR);
+
if (err)
strbuf_addf(err, Cannot lock the ref '%s'.,
update-refname);
-   ret = 1;
+   ret = df_conflict ? UPDATE_REFS_NAME_CONFLICT : -1;
goto cleanup;
}
}
@@ -3620,6 +3623,7 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
if (err)
strbuf_addf(err, Cannot update the ref 
'%s'.,
update-refname);
+   ret = -1;
goto cleanup;
}
}
@@ -3630,14 +3634,16 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
struct ref_update *update = updates[i];
 
if (update-lock) {
-   ret |= delete_ref_loose(update-lock, update-type,
-   err);
+   if (delete_ref_loose(update-lock, update-type, err))
+   ret = -1;
+
if (!(update-flags  REF_ISPRUNING))
delnames[delnum++] = update-lock-ref_name;
}
}
 
-   ret |= repack_without_refs(delnames, delnum, err);
+   if (repack_without_refs(delnames, delnum, err))
+   ret = -1;
for (i = 0; i  delnum; i++)
unlink_or_warn(git_path(logs/%s, delnames[i]));
clear_loose_ref_cache(ref_cache);
diff --git a/refs.h b/refs.h
index 7c1bf95..e14aa31 100644
--- a/refs.h
+++ b/refs.h
@@ -325,7 +325,12 @@ int 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.
+ *
+ * Function returns 0 on success, -1 for generic failures and
+ * UPDATE_REFS_NAME_CONFLICT (-2) if the failure was due to a naming conflict.
+ * For example, the ref names A and A/B conflict.
  */
+#define UPDATE_REFS_NAME_CONFLICT -2
 int ref_transaction_commit(struct ref_transaction *transaction,
   struct strbuf *err);
 
-- 
2.1.0.rc2.206.gedb03e5

--
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 09/19] refs.c: pass a skip list to name_conflict_fn

2014-09-10 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Thu, 1 May 2014 11:16:07 -0700

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 sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 refs.c | 41 -
 1 file changed, 28 insertions(+), 13 deletions(-)

diff --git a/refs.c b/refs.c
index f124c2b..b63ab2f 100644
--- a/refs.c
+++ b/refs.c
@@ -801,14 +801,16 @@ static int names_conflict(const char *refname1, const 
char *refname2)
 
 struct name_conflict_cb {
const char *refname;
-   const char *oldrefname;
const char *conflicting_refname;
+   struct string_list *skiplist;
 };
 
 static int name_conflict_fn(struct ref_entry *entry, void *cb_data)
 {
struct name_conflict_cb *data = (struct name_conflict_cb *)cb_data;
-   if (data-oldrefname  !strcmp(data-oldrefname, entry-name))
+
+   if (data-skiplist 
+   string_list_has_string(data-skiplist, entry-name))
return 0;
if (names_conflict(data-refname, entry-name)) {
data-conflicting_refname = entry-name;
@@ -822,15 +824,17 @@ 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). skiplist contains a list of refs we want to skip checking for
+ * conflicts with. skiplist must be sorted.
  */
-static int is_refname_available(const char *refname, const char *oldrefname,
-   struct ref_dir *dir)
+static int is_refname_available(const char *refname,
+   struct ref_dir *dir,
+   struct string_list *skiplist)
 {
struct name_conflict_cb data;
data.refname = refname;
-   data.oldrefname = oldrefname;
data.conflicting_refname = NULL;
+   data.skiplist = skiplist;
 
sort_ref_dir(dir);
if (do_for_each_entry_in_dir(dir, 0, name_conflict_fn, data)) {
@@ -2080,6 +2084,7 @@ 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,
+   struct string_list *skiplist,
int flags, int *type_p)
 {
char *ref_file;
@@ -2129,7 +2134,8 @@ 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, get_packed_refs(ref_cache),
+  skiplist)) {
last_errno = ENOTDIR;
goto error_return;
}
@@ -2187,7 +2193,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, NULL, flags, type_p);
 }
 
 /*
@@ -2648,6 +2654,7 @@ int rename_ref(const char *oldrefname, const char 
*newrefname, const char *logms
struct stat loginfo;
int log = !lstat(git_path(logs/%s, oldrefname), loginfo);
const char *symref = NULL;
+   struct string_list skiplist = STRING_LIST_INIT_NODUP;
 
if (log  S_ISLNK(loginfo.st_mode))
return error(reflog for %s is a symlink, oldrefname);
@@ -2659,11 +2666,18 @@ 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)))
+   string_list_insert(skiplist, oldrefname);
+   if (!is_refname_available(newrefname, get_packed_refs(ref_cache),
+ skiplist)) {
+   string_list_clear(skiplist, 0);
return 1;
-
-   if (!is_refname_available(newrefname, oldrefname, 
get_loose_refs(ref_cache

[PATCH 11/19] fetch.c: change s_update_ref to use a ref transaction

2014-09-10 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Mon, 28 Apr 2014 13:49:07 -0700

Change s_update_ref to use a ref transaction for the ref update.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 builtin/fetch.c | 34 --
 1 file changed, 24 insertions(+), 10 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 55f457c..2e3bc73 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -375,23 +375,37 @@ 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;
+   struct strbuf err = STRBUF_INIT;
+   int ret, df_conflict = 0;
 
if (dry_run)
return 0;
if (!rla)
rla = default_rla.buf;
snprintf(msg, sizeof(msg), %s: %s, rla, action);
-   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)
-   return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
- STORE_REF_ERROR_OTHER;
+
+   transaction = ref_transaction_begin(err);
+   if (!transaction ||
+   ref_transaction_update(transaction, ref-name, ref-new_sha1,
+  ref-old_sha1, 0, check_old, msg, err))
+   goto fail;
+
+   ret = ref_transaction_commit(transaction, err);
+   if (ret == UPDATE_REFS_NAME_CONFLICT)
+   df_conflict = 1;
+   if (ret)
+   goto fail;
+
+   ref_transaction_free(transaction);
+   strbuf_release(err);
return 0;
+fail:
+   ref_transaction_free(transaction);
+   error(%s, err.buf);
+   strbuf_release(err);
+   return df_conflict ? STORE_REF_ERROR_DF_CONFLICT
+  : STORE_REF_ERROR_OTHER;
 }
 
 #define REFCOL_WIDTH  10
-- 
2.1.0.rc2.206.gedb03e5

--
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 12/19] refs.c: make write_ref_sha1 static

2014-09-10 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Mon, 28 Apr 2014 15:36:58 -0700

No external users call write_ref_sha1 any more so lets declare it static.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 refs.c | 10 --
 refs.h |  3 ---
 2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/refs.c b/refs.c
index 86c708a..c2dab4a 100644
--- a/refs.c
+++ b/refs.c
@@ -2646,6 +2646,9 @@ static int rename_tmp_log(const char *newrefname)
return 0;
 }
 
+static int write_ref_sha1(struct ref_lock *lock, const unsigned char *sha1,
+ const char *logmsg);
+
 int rename_ref(const char *oldrefname, const char *newrefname, const char 
*logmsg)
 {
unsigned char sha1[20], orig_sha1[20];
@@ -2901,8 +2904,11 @@ static int is_branch(const char *refname)
return !strcmp(refname, HEAD) || starts_with(refname, refs/heads/);
 }
 
-/* This function must return a meaningful errno */
-int write_ref_sha1(struct ref_lock *lock,
+/*
+ * Writes sha1 into the ref specified by the lock. Makes sure that errno
+ * is sane on error.
+ */
+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 e14aa31..fafa493 100644
--- a/refs.h
+++ b/refs.h
@@ -195,9 +195,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. Set errno to something meaningful on failure.
  */
-- 
2.1.0.rc2.206.gedb03e5

--
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 13/19] refs.c: change resolve_ref_unsafe reading argument to be a flags field

2014-09-10 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Tue, 15 Jul 2014 12:59:36 -0700

resolve_ref_unsafe takes a boolean argument for reading.
Change this to be a flags field instead and pass the new constant
RESOLVE_REF_READING when we want this behaviour.

Swap two of the arguments in the function to make sure that we capture any
instances where callers have not been updated/aware of the new api so that
they can be audited.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 branch.c|  2 +-
 builtin/blame.c |  2 +-
 builtin/branch.c|  9 +++---
 builtin/checkout.c  |  6 ++--
 builtin/clone.c |  2 +-
 builtin/commit.c|  2 +-
 builtin/fmt-merge-msg.c |  2 +-
 builtin/for-each-ref.c  |  6 ++--
 builtin/fsck.c  |  2 +-
 builtin/log.c   |  3 +-
 builtin/merge.c |  2 +-
 builtin/notes.c |  2 +-
 builtin/receive-pack.c  |  4 +--
 builtin/remote.c|  5 ++--
 builtin/show-branch.c   |  6 ++--
 builtin/symbolic-ref.c  |  2 +-
 bundle.c|  2 +-
 cache.h | 21 ++---
 http-backend.c  |  3 +-
 notes-merge.c   |  2 +-
 reflog-walk.c   |  5 ++--
 refs.c  | 79 -
 remote.c| 10 ---
 sequencer.c |  4 +--
 transport-helper.c  |  4 ++-
 transport.c |  5 ++--
 upload-pack.c   |  2 +-
 wt-status.c |  2 +-
 28 files changed, 111 insertions(+), 85 deletions(-)

diff --git a/branch.c b/branch.c
index 76a8ec9..ba3e1c1 100644
--- a/branch.c
+++ b/branch.c
@@ -186,7 +186,7 @@ int validate_new_branchname(const char *name, struct strbuf 
*ref,
const char *head;
unsigned char sha1[20];
 
-   head = resolve_ref_unsafe(HEAD, sha1, 0, NULL);
+   head = resolve_ref_unsafe(HEAD, sha1, NULL, 0);
if (!is_bare_repository()  head  !strcmp(head, ref-buf))
die(_(Cannot force update the current branch.));
}
diff --git a/builtin/blame.c b/builtin/blame.c
index a52a279..b8bec0a 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -2292,7 +2292,7 @@ static struct commit *fake_working_tree_commit(struct 
diff_options *opt,
commit-object.type = OBJ_COMMIT;
parent_tail = commit-parents;
 
-   if (!resolve_ref_unsafe(HEAD, head_sha1, 1, NULL))
+   if (!resolve_ref_unsafe(HEAD, head_sha1, NULL, RESOLVE_REF_READING))
die(no such ref: HEAD);
 
parent_tail = append_parent(parent_tail, head_sha1);
diff --git a/builtin/branch.c b/builtin/branch.c
index 652b1d2..f144808 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -129,7 +129,8 @@ static int branch_merged(int kind, const char *name,
branch-merge[0] 
branch-merge[0]-dst 
(reference_name = reference_name_to_free =
-resolve_refdup(branch-merge[0]-dst, sha1, 1, NULL)) != 
NULL)
+resolve_refdup(branch-merge[0]-dst, sha1,
+   NULL, RESOLVE_REF_READING)) != NULL)
reference_rev = lookup_commit_reference(sha1);
}
if (!reference_rev)
@@ -233,7 +234,7 @@ static int delete_branches(int argc, const char **argv, int 
force, int kinds,
free(name);
 
name = mkpathdup(fmt, bname.buf);
-   target = resolve_ref_unsafe(name, sha1, 0, flags);
+   target = resolve_ref_unsafe(name, sha1, flags, 0);
if (!target ||
(!(flags  REF_ISSYMREF)  is_null_sha1(sha1))) {
error(remote_branch
@@ -296,7 +297,7 @@ static char *resolve_symref(const char *src, const char 
*prefix)
int flag;
const char *dst, *cp;
 
-   dst = resolve_ref_unsafe(src, sha1, 0, flag);
+   dst = resolve_ref_unsafe(src, sha1, flag, 0);
if (!(dst  (flag  REF_ISSYMREF)))
return NULL;
if (prefix  (cp = skip_prefix(dst, prefix)))
@@ -862,7 +863,7 @@ int cmd_branch(int argc, const char **argv, const char 
*prefix)
 
track = git_branch_track;
 
-   head = resolve_refdup(HEAD, head_sha1, 0, NULL);
+   head = resolve_refdup(HEAD, head_sha1, NULL, 0);
if (!head)
die(_(Failed to resolve HEAD as a valid ref.));
if (!strcmp(head, HEAD)) {
diff --git a/builtin/checkout.c b/builtin/checkout.c
index f1dc56e..64af1f7 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -356,7 +356,7 @@ static int checkout_paths(const struct checkout_opts *opts,
commit_locked_index(lock_file))
die(_(unable to write new index file));
 
-   read_ref_full(HEAD, rev, 0, flag);
+   read_ref_full(HEAD, rev, flag, 0);
head = lookup_commit_reference_gently(rev, 1);
 
errs

[PATCH 17/19] refs.c: do not permit err == NULL

2014-09-10 Thread Jonathan Nieder
Some functions that take a strbuf argument to append an error to treat
!err as an indication that the message should be suppressed (e.g.,
ref_update_reject_duplicates).  Others write the message to stderr on
!err (e.g., repack_without_refs).  Others crash (e.g.,
ref_transaction_update).

Some of these behaviors are for historical reasons and others were
accidents.  Luckily no callers pass err == NULL any more.  Simplify
by consistently requiring the strbuf argument.

Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 refs.c | 46 +++---
 1 file changed, 27 insertions(+), 19 deletions(-)

diff --git a/refs.c b/refs.c
index 6faf0c8..550223c 100644
--- a/refs.c
+++ b/refs.c
@@ -2560,6 +2560,8 @@ int repack_without_refs(const char **refnames, int n, 
struct strbuf *err)
struct string_list_item *ref_to_delete;
int i, ret, removed = 0;
 
+   assert(err);
+
/* Look for a packed ref */
for (i = 0; i  n; i++)
if (get_packed_ref(refnames[i]))
@@ -2570,13 +2572,8 @@ int repack_without_refs(const char **refnames, int n, 
struct strbuf *err)
return 0; /* no refname exists in packed refs */
 
if (lock_packed_refs(0)) {
-   if (err) {
-   unable_to_lock_message(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]);
+   unable_to_lock_message(git_path(packed-refs), errno, err);
+   return -1;
}
packed = get_packed_refs(ref_cache);
 
@@ -2602,7 +2599,7 @@ int repack_without_refs(const char **refnames, int n, 
struct strbuf *err)
 
/* Write what remains */
ret = commit_packed_refs();
-   if (ret  err)
+   if (ret)
strbuf_addf(err, unable to overwrite old ref-pack file: %s,
strerror(errno));
return ret;
@@ -2610,6 +2607,8 @@ int repack_without_refs(const char **refnames, int n, 
struct strbuf *err)
 
 static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf 
*err)
 {
+   assert(err);
+
if (!(flag  REF_ISPACKED) || flag  REF_ISSYMREF) {
/* loose */
int res, i = strlen(lock-lk-filename) - 5; /* .lock */
@@ -3459,6 +3458,8 @@ struct ref_transaction {
 
 struct ref_transaction *ref_transaction_begin(struct strbuf *err)
 {
+   assert(err);
+
return xcalloc(1, sizeof(struct ref_transaction));
 }
 
@@ -3498,6 +3499,8 @@ int ref_transaction_update(struct ref_transaction 
*transaction,
 {
struct ref_update *update;
 
+   assert(err);
+
if (transaction-state != REF_TRANSACTION_OPEN)
die(BUG: update called for transaction that is not open);
 
@@ -3530,6 +3533,8 @@ int ref_transaction_create(struct ref_transaction 
*transaction,
 {
struct ref_update *update;
 
+   assert(err);
+
if (transaction-state != REF_TRANSACTION_OPEN)
die(BUG: create called for transaction that is not open);
 
@@ -3561,6 +3566,8 @@ int ref_transaction_delete(struct ref_transaction 
*transaction,
 {
struct ref_update *update;
 
+   assert(err);
+
if (transaction-state != REF_TRANSACTION_OPEN)
die(BUG: delete called for transaction that is not open);
 
@@ -3623,13 +3630,14 @@ static int ref_update_reject_duplicates(struct 
ref_update **updates, int n,
struct strbuf *err)
 {
int i;
+
+   assert(err);
+
for (i = 1; i  n; i++)
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);
-
+   strbuf_addf(err,
+   Multiple updates for ref '%s' not 
allowed.,
+   updates[i]-refname);
return 1;
}
return 0;
@@ -3643,6 +3651,8 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
int n = transaction-nr;
struct ref_update **updates = transaction-updates;
 
+   assert(err);
+
if (transaction-state != REF_TRANSACTION_OPEN)
die(BUG: commit called for transaction that is not open);
 
@@ -3675,9 +3685,8 @@ int ref_transaction_commit(struct ref_transaction 
*transaction,
if (!update-lock) {
int df_conflict = (errno == ENOTDIR);
 
-   if (err)
-   strbuf_addf(err, Cannot lock the ref '%s'.,
-   update

[PATCH 16/19] for-each-ref.c: improve message before aborting on broken ref

2014-09-10 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Fri, 5 Sep 2014 14:35:17 -0700

Print a warning message for any badly named refs we find in the repo.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 builtin/for-each-ref.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index e193073..090390c 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -853,6 +853,12 @@ static int grab_single_ref(const char *refname, const 
unsigned char *sha1, int f
struct refinfo *ref;
int cnt;
 
+   if ((flag  REF_ISBROKEN) 
+   check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
+ warning(ignoring ref with broken name %s, refname);
+ return 0;
+   }
+
if (*cb-grab_pattern) {
const char **pattern;
int namelen = strlen(refname);
-- 
2.1.0.rc2.206.gedb03e5

--
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 15/19] refs.c: fix handling of badly named refs

2014-09-10 Thread Jonathan Nieder
From: Ronnie Sahlberg sahlb...@google.com
Date: Wed, 3 Sep 2014 11:45:43 -0700

We currently do not handle badly named refs well:

  $ cp .git/refs/heads/master .git/refs/heads/master.@\*@\\.
  $ git branch
fatal: Reference has invalid format: 'refs/heads/master.@*@\.'
  $ git branch -D master.@\*@\\.
error: branch 'master.@*@\.' not found.

Currently we can not really recover from a badly named ref with less than
manually deleting the .git/refs/heads/refname file. This will also help
if change the naming rules in the future. For example if we decide to remove
`,  and such from the set of valid characters.

The purpose of this change is to allow git branch --list to show these refs
and to allow git branch -d/-D and update-ref -d to delete them.
Other functions will continue to not handle these refs but can be changed in
later patches.

Introduce two new internal flags: RESOLVE_REF_ALLOW_BAD_NAME and REF_BADNAMEOK.

In resolving functions, refuse to resolve badly named refs unless the new
RESOLVE_REF_ALLOW_BAD_NAME flag is passed. For these cases, if the badly named
ref exists then flag it as REF_ISBROKEN and resolve it to nullsha1.

In locking functions, refuse to act on badly named refs unless the new
REF_BADNAMEOK flag is passed. This is currently used only from branch.c and
update-ref.c when deleting a ref.

Change the internal functions that read loose and packed refs to allow
badly named refs but flag them as REF_ISBROKEN just like unresolvable refs
are.

During ref iteration only include these refs during for_each_rawref but
none of the other iterators. I.e. just like unresolvable refs, flag
inclusion of these refs based on DO_FOR_EACH_INCLUDE_BROKEN during
iteration.

In the transaction API, always refuse to create or update badly named refs
and refuse to delete them unless REF_BADNAMEOK flag is passed.

Signed-off-by: Ronnie Sahlberg sahlb...@google.com
Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 builtin/branch.c| 13 ++
 builtin/update-ref.c|  3 ++-
 cache.h |  8 +-
 refs.c  | 63 ++---
 refs.h  |  2 ++
 t/t1402-check-ref-format.sh | 48 ++
 6 files changed, 121 insertions(+), 16 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 7925660..5d5bc56 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -234,10 +234,13 @@ static int delete_branches(int argc, const char **argv, 
int force, int kinds,
free(name);
 
name = mkpathdup(fmt, bname.buf);
-   target = resolve_ref_unsafe(name, sha1,
-   flags, RESOLVE_REF_NODEREF);
+   target = resolve_ref_unsafe(name, sha1, flags,
+   RESOLVE_REF_READING
+   | RESOLVE_REF_NODEREF
+   | RESOLVE_REF_ALLOW_BAD_NAME);
if (!target ||
-   (!(flags  REF_ISSYMREF)  is_null_sha1(sha1))) {
+   (!(flags  (REF_ISSYMREF|REF_ISBROKEN)) 
+is_null_sha1(sha1))) {
error(remote_branch
  ? _(remote branch '%s' not found.)
  : _(branch '%s' not found.), bname.buf);
@@ -245,14 +248,14 @@ static int delete_branches(int argc, const char **argv, 
int force, int kinds,
continue;
}
 
-   if (!(flags  REF_ISSYMREF) 
+   if (!(flags  (REF_ISSYMREF|REF_ISBROKEN)) 
check_branch_commit(bname.buf, name, sha1, head_rev, kinds,
force)) {
ret = 1;
continue;
}
 
-   if (delete_ref(name, sha1, REF_NODEREF)) {
+   if (delete_ref(name, sha1, REF_NODEREF|REF_BADNAMEOK)) {
error(remote_branch
  ? _(Error deleting remote branch '%s')
  : _(Error deleting branch '%s'),
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 6c9be05..e379fdd 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -419,7 +419,8 @@ int cmd_update_ref(int argc, const char **argv, const char 
*prefix)
if (no_deref)
flags = REF_NODEREF;
if (delete)
-   return delete_ref(refname, oldval ? oldsha1 : NULL, flags);
+   return delete_ref(refname, oldval ? oldsha1 : NULL,
+ flags|REF_BADNAMEOK);
else
return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
  flags, UPDATE_REFS_DIE_ON_ERR);
diff --git a/cache.h b/cache.h
index 03ade12..03a6144 100644
--- a/cache.h
+++ b/cache.h
@@ -979,10 +979,16 @@ extern int

[PATCH 14/19] branch -d: avoid repeated symref resolution

2014-09-10 Thread Jonathan Nieder
If a repository gets in a broken state with too much symref nesting,
it cannot be repaired with git branch -d:

 $ git symbolic-ref refs/heads/nonsense refs/heads/nonsense
 $ git branch -d nonsense
 error: branch 'nonsense' not found.

Worse, git update-ref --no-deref -d doesn't work for such repairs
either:

 $ git update-ref -d refs/heads/nonsense
 error: unable to resolve reference refs/heads/nonsense: Too many levels of 
symbolic links

Fix both by teaching resolve_ref_unsafe a new RESOLVE_REF_NODEREF flag
and passing it when appropriate.

Callers can still read the value of a symref (for example to print a
message about it) with that flag set --- resolve_ref_unsafe will
resolve one level of symrefs and stop there.

Signed-off-by: Jonathan Nieder jrnie...@gmail.com
---
 builtin/branch.c  |  3 ++-
 cache.h   |  1 +
 refs.c| 10 ++
 t/t1400-update-ref.sh | 16 
 t/t3200-branch.sh |  9 +
 5 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index f144808..7925660 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -234,7 +234,8 @@ static int delete_branches(int argc, const char **argv, int 
force, int kinds,
free(name);
 
name = mkpathdup(fmt, bname.buf);
-   target = resolve_ref_unsafe(name, sha1, flags, 0);
+   target = resolve_ref_unsafe(name, sha1,
+   flags, RESOLVE_REF_NODEREF);
if (!target ||
(!(flags  REF_ISSYMREF)  is_null_sha1(sha1))) {
error(remote_branch
diff --git a/cache.h b/cache.h
index 2d3c5ed..03ade12 100644
--- a/cache.h
+++ b/cache.h
@@ -982,6 +982,7 @@ extern int read_ref(const char *refname, unsigned char 
*sha1);
  * errno is set to something meaningful on error.
  */
 #define RESOLVE_REF_READING 0x01
+#define RESOLVE_REF_NODEREF 0x02
 extern const char *resolve_ref_unsafe(const char *ref, unsigned char *sha1, 
int *flags, int resolve_flags);
 extern char *resolve_refdup(const char *ref, unsigned char *sha1, int *flags, 
int resolve_flags);
 
diff --git a/refs.c b/refs.c
index a5f9734..f11df33 100644
--- a/refs.c
+++ b/refs.c
@@ -1408,6 +1408,10 @@ const char *resolve_ref_unsafe(const char *refname, 
unsigned char *sha1, int *fl
refname = refname_buffer;
if (flags)
*flags |= REF_ISSYMREF;
+   if (resolve_flags  RESOLVE_REF_NODEREF) {
+   hashclr(sha1);
+   return refname;
+   }
continue;
}
}
@@ -1471,6 +1475,10 @@ const char *resolve_ref_unsafe(const char *refname, 
unsigned char *sha1, int *fl
return NULL;
}
refname = strcpy(refname_buffer, buf);
+   if (resolve_flags  RESOLVE_REF_NODEREF) {
+   hashclr(sha1);
+   return refname;
+   }
}
 }
 
@@ -2110,6 +2118,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char 
*refname,
 
if (mustexist)
resolve_flags |= RESOLVE_REF_READING;
+   if (flags  REF_NODEREF)
+   resolve_flags |= RESOLVE_REF_NODEREF;
 
refname = resolve_ref_unsafe(refname, lock-old_sha1, type,
 resolve_flags);
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 0218e96..ff4607b 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -110,6 +110,22 @@ test_expect_success delete symref without dereference 
when the referred ref is
 cp -f .git/HEAD.orig .git/HEAD
 git update-ref -d $m
 
+test_expect_success 'update-ref -d is not confused by self-reference' '
+   git symbolic-ref refs/heads/self refs/heads/self 
+   test_when_finished rm -f .git/refs/heads/self 
+   test_path_is_file .git/refs/heads/self 
+   test_must_fail git update-ref -d refs/heads/self 
+   test_path_is_file .git/refs/heads/self
+'
+
+test_expect_success 'update-ref --no-deref -d can delete self-reference' '
+   git symbolic-ref refs/heads/self refs/heads/self 
+   test_when_finished rm -f .git/refs/heads/self 
+   test_path_is_file .git/refs/heads/self 
+   git update-ref --no-deref -d refs/heads/self 
+   test_path_is_missing .git/refs/heads/self
+'
+
 test_expect_success '(not) create HEAD with old sha1' 
test_must_fail git update-ref HEAD $A $B
 
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index ac31b71..432921b 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -285,6 +285,15 @@ test_expect_success 'deleting a dangling symref' '
test_i18ncmp expect actual
 '
 
+test_expect_success 'deleting a self-referential symref

[PATCH 18/19] lockfile: remove unable_to_lock_error

2014-09-10 Thread Jonathan Nieder
The former caller uses unable_to_lock_message now.

Signed-off-by: Jonathan Nieder jrnie...@gmail.com
Reviewed-by: Ronnie Sahlberg sahlb...@google.com
---
 cache.h|  1 -
 lockfile.c | 10 --
 2 files changed, 11 deletions(-)

diff --git a/cache.h b/cache.h
index 03a6144..995729f 100644
--- a/cache.h
+++ b/cache.h
@@ -558,7 +558,6 @@ 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_message(const char *path, int err,
   struct strbuf *buf);
 extern NORETURN void unable_to_lock_index_die(const char *path, int err);
diff --git a/lockfile.c b/lockfile.c
index a921d77..dbd4101 100644
--- a/lockfile.c
+++ b/lockfile.c
@@ -176,16 +176,6 @@ void unable_to_lock_message(const char *path, int err, 
struct strbuf *buf)
absolute_path(path), strerror(err));
 }
 
-int unable_to_lock_error(const char *path, int err)
-{
-   struct strbuf buf = STRBUF_INIT;
-
-   unable_to_lock_message(path, err, buf);
-   error(%s, buf.buf);
-   strbuf_release(buf);
-   return -1;
-}
-
 NORETURN void unable_to_lock_index_die(const char *path, int err)
 {
struct strbuf buf = STRBUF_INIT;
-- 
2.1.0.rc2.206.gedb03e5

--
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   3   4   5   6   7   8   9   10   >