From: Felipe Contreras <hidden> Date: 2016-06-15 22:59:06
Hi,
Here are the patches that allow transport helpers to be completely transparent;
renaming branches, deleting them, custom refspecs, --force, --dry-run,
reporting forced update, everything works.
Some of these were were sent before and rejected without a reason, but here
they are again in case anybody is interested.
This time rebased on top of the latest master, plus a few fixes.
Diff from v3:
@@ -836,9 +836,6 @@ static int push_refs_with_export(struct transport *transport,char*private;unsignedcharsha1[20];-if(ref->deletion)-die("remote-helpers do not support ref deletion");-private=apply_refspecs(data->refspecs,data->refspec_nr,ref->name);if(private&&!get_sha1(private,sha1)){strbuf_addf(&buf,"^%s",private);
Felipe Contreras (10):
transport-helper: add 'force' to 'export' helpers
transport-helper: fix extra lines
transport-helper: check for 'forced update' message
fast-export: improve argument parsing
fast-export: add new --refspec option
transport-helper: add support for old:new refspec
fast-import: add support to delete refs
fast-export: add support to delete refs
transport-helper: add support to delete branches
transport-helper: don't update refs in dry-run
Documentation/git-fast-export.txt | 4 ++++
Documentation/git-fast-import.txt | 3 +++
builtin/fast-export.c | 47 ++++++++++++++++++++++++++++++++++++++-
fast-import.c | 13 ++++++++---
t/t5801-remote-helpers.sh | 10 ++++++++-
t/t9300-fast-import.sh | 18 +++++++++++++++
t/t9350-fast-export.sh | 18 +++++++++++++++
transport-helper.c | 47 ++++++++++++++++++++++++++-------------
8 files changed, 140 insertions(+), 20 deletions(-)
--
1.8.4-fc
From: Felipe Contreras <hidden> Date: 2016-06-15 22:59:06
So the remote-helpers can tell us when a forced push was needed.
Signed-off-by: Felipe Contreras <redacted>
---
transport-helper.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
@@ -105,6 +105,10 @@ marks the same across runs. in the commit (as opposed to just listing the files which are different from the commit's first parent).+--refspec::+ Apply the specified refspec to each ref exported. Multiple of them can+ be specified.+ [<git-rev-list-args>...]:: A list of arguments, acceptable to 'git rev-parse' and 'git rev-list', that specifies the specific objects and references
@@ -31,6 +32,8 @@ static int use_done_feature;staticintno_data;staticintfull_tree;staticstructstring_listextra_refs=STRING_LIST_INIT_NODUP;+staticstructrefspec*refspecs;+staticintrefspecs_nr;staticintparse_opt_signed_tag_mode(conststructoption*opt,constchar*arg,intunset)
@@ -525,6 +528,15 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)if(dwim_ref(e->name,strlen(e->name),sha1,&full_name)!=1)continue;+if(refspecs){+char*private;+private=apply_refspecs(refspecs,refspecs_nr,full_name);+if(private){+free(full_name);+full_name=private;+}+}+commit=get_commit(e,full_name);if(!commit){warning("%s: Unexpected object of type %s, skipping.",
@@ -668,6 +680,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)structcommit*commit;char*export_filename=NULL,*import_filename=NULL;uint32_tlastimportid;+structstring_listrefspecs_list=STRING_LIST_INIT_NODUP;structoptionoptions[]={OPT_INTEGER(0,"progress",&progress,N_("show progress after <n> objects")),
@@ -688,6 +701,8 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)OPT_BOOL(0,"use-done-feature",&use_done_feature,N_("Use the done feature to terminate the stream")),OPT_BOOL(0,"no-data",&no_data,N_("Skip output of blob data")),+OPT_STRING_LIST(0,"refspec",&refspecs_list,N_("refspec"),+N_("Apply refspec to exported refs")),OPT_END()};
@@ -504,4 +504,11 @@ test_expect_success 'refs are updated even if no commits need to be exported' 'test_cmpexpectedactual'+test_expect_success'use refspec''+gitfast-export--refspecrefs/heads/master:refs/heads/foobarmaster|\+grep"^commit "|sort|uniq>actual&&+echo"commit refs/heads/foobar">expected&&+test_cmpexpectedactual+'+ test_done
@@ -874,9 +874,6 @@ static int push_refs_with_export(struct transport *transport,char*private;unsignedcharsha1[20];-if(ref->deletion)-die("remote-helpers do not support ref deletion");-private=apply_refspecs(data->refspecs,data->refspec_nr,ref->name);if(private&&!get_sha1(private,sha1)){strbuf_addf(&buf,"^%s",private);
@@ -888,12 +885,16 @@ static int push_refs_with_export(struct transport *transport,if(ref->peer_ref){if(strcmp(ref->name,ref->peer_ref->name)){structstrbufbuf=STRBUF_INIT;-strbuf_addf(&buf,"%s:%s",ref->peer_ref->name,ref->name);+if(!ref->deletion)+strbuf_addf(&buf,"%s:%s",ref->peer_ref->name,ref->name);+else+strbuf_addf(&buf,":%s",ref->name);string_list_append(&revlist_args,"--refspec");string_list_append(&revlist_args,buf.buf);strbuf_release(&buf);}-string_list_append(&revlist_args,ref->peer_ref->name);+if(!ref->deletion)+string_list_append(&revlist_args,ref->peer_ref->name);}}
@@ -87,7 +87,7 @@ test_expect_success 'push new branch by name' 'compare_refslocalHEADserverrefs/heads/new-name'-test_expect_failure'push new branch with old:new refspec''+test_expect_success'push new branch with old:new refspec''(cdlocal&&gitpushoriginnew-name:new-refspec)&&
@@ -848,7 +848,7 @@ static int push_refs_with_export(struct transport *transport,structref*ref;structchild_process*helper,exporter;structhelper_data*data=transport->data;-structstring_listrevlist_args=STRING_LIST_INIT_NODUP;+structstring_listrevlist_args=STRING_LIST_INIT_DUP;structstrbufbuf=STRBUF_INIT;if(!data->refspecs)
@@ -886,8 +886,13 @@ static int push_refs_with_export(struct transport *transport,free(private);if(ref->peer_ref){-if(strcmp(ref->peer_ref->name,ref->name))-die("remote-helpers do not support old:new syntax");+if(strcmp(ref->name,ref->peer_ref->name)){+structstrbufbuf=STRBUF_INIT;+strbuf_addf(&buf,"%s:%s",ref->peer_ref->name,ref->name);+string_list_append(&revlist_args,"--refspec");+string_list_append(&revlist_args,buf.buf);+strbuf_release(&buf);+}string_list_append(&revlist_args,ref->peer_ref->name);}}
@@ -895,6 +900,8 @@ static int push_refs_with_export(struct transport *transport,if(get_exporter(transport,&exporter,&revlist_args))die("Couldn't run fast-export");+string_list_clear(&revlist_args,1);+if(finish_command(&exporter))die("Error while running fast-export");push_update_refs_status(data,remote_refs);
@@ -879,9 +879,6 @@ static int push_refs_with_export(struct transport *transport,}free(private);-if(ref->deletion)-die("remote-helpers do not support ref deletion");-if(ref->peer_ref){if(strcmp(ref->peer_ref->name,ref->name))die("remote-helpers do not support old:new syntax");
From: Felipe Contreras <hidden> Date: 2016-06-15 22:59:06
The remote helper namespace should not be updated.
Signed-off-by: Felipe Contreras <redacted>
---
transport-helper.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
@@ -733,7 +733,8 @@ static int push_update_ref_status(struct strbuf *buf,}staticvoidpush_update_refs_status(structhelper_data*data,-structref*remote_refs)+structref*remote_refs,+intflags){structstrbufbuf=STRBUF_INIT;structref*ref=remote_refs;
@@ -747,7 +748,7 @@ static void push_update_refs_status(struct helper_data *data,if(push_update_ref_status(&buf,&ref,remote_refs))continue;-if(!data->refspecs||data->no_private_update)+if(flags&TRANSPORT_PUSH_DRY_RUN||!data->refspecs||data->no_private_update)continue;/* propagate back the update to the remote namespace */
@@ -838,7 +839,7 @@ static int push_refs_with_push(struct transport *transport,sendline(data,&buf);strbuf_release(&buf);-push_update_refs_status(data,remote_refs);+push_update_refs_status(data,remote_refs,flags);return0;}
@@ -905,7 +906,7 @@ static int push_refs_with_export(struct transport *transport,if(finish_command(&exporter))die("Error while running fast-export");-push_update_refs_status(data,remote_refs);+push_update_refs_status(data,remote_refs,flags);return0;}
@@ -483,6 +483,9 @@ Marks must be declared (via `mark`) before they can be used. * Any valid Git SHA-1 expression that resolves to a commit. See ``SPECIFYING REVISIONS'' in linkgit:gitrevisions[7] for details.+* The special null SHA-1 (40 zeros) specifices that the branch is to be+ removed.+ The special case of restarting an incremental import from the current branch value should be written as: ----
@@ -1690,10 +1691,13 @@ static int update_branch(struct branch *b)structref_lock*lock;unsignedcharold_sha1[20];-if(is_null_sha1(b->sha1))-return0;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);+return0;+}lock=lock_any_ref_for_update(b->name,old_sha1,0,NULL);if(!lock)returnerror("Unable to lock %s",b->name);
@@ -2620,8 +2624,11 @@ static int parse_from(struct branch *b)free(buf);}elseparse_from_existing(b);-}elseif(!get_sha1(from,b->sha1))+}elseif(!get_sha1(from,b->sha1)){parse_from_existing(b);+if(is_null_sha1(b->sha1))+b->delete=1;+}elsedie("Invalid ref name or SHA1 expression: %s",from);
From: Felipe Contreras <hidden> Date: 2016-06-15 22:59:06
Otherwise they cannot know when to force the push or not (other than
hacks).
Signed-off-by: Felipe Contreras <redacted>
---
transport-helper.c | 5 +++++
1 file changed, 5 insertions(+)
@@ -853,6 +853,11 @@ static int push_refs_with_export(struct transport *transport,die("helper %s does not support dry-run",data->name);}+if(flags&TRANSPORT_PUSH_FORCE){+if(set_helper_option(transport,"force","true")!=0)+die("helper %s does not support 'force'",data->name);+}+helper=get_helper(transport);write_constant(helper->in,"export\n");
From: Felipe Contreras <hidden> Date: 2016-06-15 22:59:06
We don't want to pass arguments specific to fast-export to
setup_revisions.
Signed-off-by: Felipe Contreras <redacted>
---
builtin/fast-export.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
@@ -483,6 +483,9 @@ Marks must be declared (via `mark`) before they can be used. * Any valid Git SHA-1 expression that resolves to a commit. See ``SPECIFYING REVISIONS'' in linkgit:gitrevisions[7] for details.+* The special null SHA-1 (40 zeros) specifices that the branch is to be
s/specifices/specifies/
+ removed.
+
The special case of restarting an incremental import from the
current branch value should be written as:
----
@@ -437,6 +437,10 @@ set by Git if the remote helper has the 'option' capability. 'option check-connectivity' \{'true'|'false'\}:: Request the helper to check connectivity of a clone.+'option force' \{'true'|'false'\}::+ Request the helper to perform a force update. Defaults to+ 'false'.+ SEE ALSO -------- linkgit:git-remote[1]
We can do <<-EOF to align this properly.
Also, I don't see why all the variables are ${foo} instead of $foo.
+ case ${opt} in
+ force)
I think the convention is to align these:
case $opt in
force)
+ case ${val} in
+ true) forcearg=--force; echo 'ok';;
+ false) forcearg=; echo 'ok';;
+ *) printf %s\\n "error '${val}'\
+ is not a valid value for option ${opt}";;
I think this is packing a lot of stuff and it's not that readable.
Moreover, this is not for production purposes, it's for testing purposes and a
guideline, I think this suffices.
option\ *)
read cmd opt val <<-EOF
$line
EOF
case $opt in
force)
test $val = "true" && force="true" || force=
echo "ok"
;;
*)
echo "unsupported"
;;
esac
;;
But this is definetly good to have, will merge.
--
Felipe Contreras
Good point. I personally avoid tabs whenever possible, and <<- only
works with tabs, so I'm in the habit of doing <<EOF.
Also, I don't see why all the variables are ${foo} instead of $foo.
I'm in the habit of doing ${foo} because I like the consistency --
sometimes you need them to disambiguate, and sometimes you need special
expansions like ${foo##bar} or ${foo:-bar}.
In this case it's actually less consistent to do ${foo} because the rest
of the file doesn't use {} when not needed, so I agree with your change.
quoted
+ case ${opt} in
+ force)
I think the convention is to align these:
case $opt in
force)
The existing case statement in this file indents the patterns the same
amount as the case statement, so this should be aligned to match.
In general I rarely see the case patterns indented at the same level as
the case statement, possibly because Emacs shell-mode indents the
patterns more than the case statement (by default). The POSIX spec
contains a mix of styles:
* the normative text documenting the format of a 'case' construct
indents the patterns more than the 'case' statement
* two of the four non-normative examples indent the patterns
more than the 'case' statements; the other two do not
quoted
+ case ${val} in
+ true) forcearg=--force; echo 'ok';;
+ false) forcearg=; echo 'ok';;
+ *) printf %s\\n "error '${val}'\
+ is not a valid value for option ${opt}";;
I think this is packing a lot of stuff and it's not that readable.
Moreover, this is not for production purposes, it's for testing purposes and a
guideline, I think this suffices.
option\ *)
read cmd opt val <<-EOF
$line
EOF
case $opt in
force)
test $val = "true" && force="true" || force=
echo "ok"
;;
*)
echo "unsupported"
;;
esac
;;
Good point. I personally avoid tabs whenever possible, and <<- only
works with tabs, so I'm in the habit of doing <<EOF.
That looks very weird to me, plus <<-EOF is often used already in git tests.
quoted
Also, I don't see why all the variables are ${foo} instead of $foo.
I'm in the habit of doing ${foo} because I like the consistency --
Sure, but with the price of less readibility. If consistency was the
priority, we would be doing the follwoing in C:
if (foo) {
# single line
}
Since the if might contain multiple lines, but we don't do that,
because readibility is more important than consistency. So sometimes
it's with braces, sometimes without.
quoted
quoted
+ case ${opt} in
+ force)
I think the convention is to align these:
case $opt in
force)
The existing case statement in this file indents the patterns the same
amount as the case statement, so this should be aligned to match.
In general I rarely see the case patterns indented at the same level as
the case statement, possibly because Emacs shell-mode indents the
patterns more than the case statement (by default). The POSIX spec
contains a mix of styles:
* the normative text documenting the format of a 'case' construct
indents the patterns more than the 'case' statement
* two of the four non-normative examples indent the patterns
more than the 'case' statements; the other two do not
The style in C has the cases at the same level, so I think it makes
sense to do the same in shell, but I'm not sure if that's followed
already.
quoted
quoted
+ case ${val} in
+ true) forcearg=--force; echo 'ok';;
+ false) forcearg=; echo 'ok';;
+ *) printf %s\\n "error '${val}'\
+ is not a valid value for option ${opt}";;
I think this is packing a lot of stuff and it's not that readable.
Moreover, this is not for production purposes, it's for testing purposes and a
guideline, I think this suffices.
option\ *)
read cmd opt val <<-EOF
$line
EOF
case $opt in
force)
test $val = "true" && force="true" || force=
echo "ok"
;;
echo "unsupported"
;;
esac
;;
Works for me.
Good, the final code style can be decided later on, and perhaps update
Documentation/CodingGuidelines, but it's good the rest is more or less
settled.
Cheers.
--
Felipe Contreras