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