Re: Empty bundles are not useless

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Rodrigo,

On Tue, 14 Jul 2020, R. Lemos wrote:

> When working disconnected (sending bundles back and forth) it is
> useful to make bundles like this:
>
> $ git bundle create /tmp/my.bundle master ^disconnected/master
>
> This way I pack all new commits since the last updated from
> `disconnected` remote.
>
> But if my local copy is up-to-date, git bundle refuses to create an
> empty bundle, since there are no commits to send.
>
> However it would be nice to at least send the information that my
> local branch `master` is up-to-date. That is, the bundle would just
> convey that my local `master` points to a given commit (even though
> this commit is already on the remote site). This way, when I upload
> this bundle to the remote site, then bring back changes made there,
> the remote site will know which commits I already have.

I am sympathetic to your use case (I certainly had wished for something
like this in the past), but it is not quite as trivial as you might think:
any bundle lists its "wants" and "haves" first, i.e. the commits that it
expects to be present and the tip commits it provides, respectively. And
herein lies the rub: in your case, the tip commit would technically belong
to both "wants" and "haves", and that cannot be represented by the simple
`git rev-list --boundary --pretty=oneline <rev-list-args>` call that
`compute_and_write_prerequisites()` in `bundle.c` performs in order to
generate that wants/haves list.

You could of course implement something in `write_bundle_refs()` that
(guarded by a new option, so as to maintain backwards-compatibility) would
list commits marked as `UNINTERESTING` both as "wants" and "haves", but
that might become a bit tricky e.g. handling commit ranges like
`HEAD~2..HEAD` (where `HEAD~2` would be marked `UNINTERESTING`).

Side note: if it is not clear to you what I mean by `UNINTERESTING`,
please read the excellent tutorial at:
https://github.com/git/git/blob/v2.28.0-rc0/Documentation/MyFirstObjectWalk.txt

Once you worked out how to write out such commits both as prerequisites as
well as refs in the bundle, the rest should be relatively easy: a new test
case in `t/t5607-clone-bundle.sh` to verify that empty bundles can be
created (using a new command-line option that allows precisely that) and
something like this (plus the corresponding docs in
`Documentation/git-bundle.txt`):

-- snip --
diff --git a/bundle.c b/bundle.c
index 99439e07a106..74f2759a2068 100644
--- a/bundle.c
+++ b/bundle.c
@@ -11,6 +11,7 @@
 #include "run-command.h"
 #include "refs.h"
 #include "argv-array.h"
+#include "parse-options.h"

 static const char bundle_signature[] = "# v2 git bundle\n";

@@ -436,6 +437,21 @@ int create_bundle(struct repository *r, const char *path,
 	int bundle_to_stdout;
 	int ref_count = 0;
 	struct rev_info revs;
+	int allow_empty_bundle = 0;
+	struct option options[] = {
+		OPT_BOOL(0, "allow-empty-bundle",
+			 &allow_empty_bundle,
+			 N_("allow an empty bundle to be created")),
+		OPT_END()
+	};
+	const char * const create_usage[] = {
+		N_("git bundle create [<options>] <file> <git-rev-list args>"),
+		NULL
+	};
+
+	argc = parse_options(argc, argv, NULL, options, create_usage,
+			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0 |
+			     PARSE_OPT_KEEP_UNKNOWN);

 	bundle_to_stdout = !strcmp(path, "-");
 	if (bundle_to_stdout)
@@ -465,7 +481,7 @@ int create_bundle(struct repository *r, const char *path,
 	object_array_remove_duplicates(&revs.pending);

 	ref_count = write_bundle_refs(bundle_fd, &revs);
-	if (!ref_count)
+	if (!ref_count && !allow_empty_bundle)
 		die(_("Refusing to create empty bundle."));
 	else if (ref_count < 0)
 		goto err;
-- snap --

Hopefully this gets you started with "scratching your own itch".

Ciao,
Johannes




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux