aboutsummaryrefslogtreecommitdiffstats
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c3
-rw-r--r--builtin/annotate.c23
-rw-r--r--builtin/archive.c5
-rw-r--r--builtin/checkout.c2
-rw-r--r--builtin/clone.c31
-rw-r--r--builtin/commit.c26
-rw-r--r--builtin/config.c4
-rw-r--r--builtin/credential-cache.c5
-rw-r--r--builtin/difftool.c2
-rw-r--r--builtin/fast-import.c6
-rw-r--r--builtin/fetch.c6
-rw-r--r--builtin/grep.c13
-rw-r--r--builtin/index-pack.c118
-rw-r--r--builtin/interpret-trailers.c25
-rw-r--r--builtin/ls-remote.c2
-rw-r--r--builtin/merge.c1
-rw-r--r--builtin/notes.c8
-rw-r--r--builtin/pack-objects.c32
-rw-r--r--builtin/pack-redundant.c45
-rw-r--r--builtin/pull.c4
-rw-r--r--builtin/push.c9
-rw-r--r--builtin/receive-pack.c5
-rw-r--r--builtin/rev-list.c7
-rw-r--r--builtin/revert.c17
-rw-r--r--builtin/send-pack.c1
-rw-r--r--builtin/shortlog.c12
-rw-r--r--builtin/stash.c4
-rw-r--r--builtin/tag.c2
-rw-r--r--builtin/worktree.c16
29 files changed, 347 insertions, 87 deletions
diff --git a/builtin/add.c b/builtin/add.c
index 773b7224a4..7d35307792 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -385,7 +385,8 @@ int cmd_add(int argc,
char *ps_matched = NULL;
struct lock_file lock_file = LOCK_INIT;
- repo_config(repo, add_config, NULL);
+ if (repo)
+ repo_config(repo, add_config, NULL);
argc = parse_options(argc, argv, prefix, builtin_add_options,
builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
diff --git a/builtin/annotate.c b/builtin/annotate.c
index a99179fe4d..7f754f2309 100644
--- a/builtin/annotate.c
+++ b/builtin/annotate.c
@@ -4,7 +4,6 @@
* Copyright (C) 2006 Ryan Anderson
*/
-#define USE_THE_REPOSITORY_VARIABLE
#include "git-compat-util.h"
#include "builtin.h"
#include "strvec.h"
@@ -12,16 +11,26 @@
int cmd_annotate(int argc,
const char **argv,
const char *prefix,
- struct repository *repo UNUSED)
+ struct repository *repo)
{
struct strvec args = STRVEC_INIT;
- int i;
+ const char **args_copy;
+ int ret;
strvec_pushl(&args, "annotate", "-c", NULL);
-
- for (i = 1; i < argc; i++) {
+ for (int i = 1; i < argc; i++)
strvec_push(&args, argv[i]);
- }
- return cmd_blame(args.nr, args.v, prefix, the_repository);
+ /*
+ * `cmd_blame()` ends up modifying the array, which causes memory leaks
+ * if we didn't copy the array here.
+ */
+ CALLOC_ARRAY(args_copy, args.nr + 1);
+ COPY_ARRAY(args_copy, args.v, args.nr);
+
+ ret = cmd_blame(args.nr, args_copy, prefix, repo);
+
+ strvec_clear(&args);
+ free(args_copy);
+ return ret;
}
diff --git a/builtin/archive.c b/builtin/archive.c
index dc926d1a3d..13ea7308c8 100644
--- a/builtin/archive.c
+++ b/builtin/archive.c
@@ -2,7 +2,6 @@
* Copyright (c) 2006 Franck Bui-Huu
* Copyright (c) 2006 Rene Scharfe
*/
-#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "archive.h"
#include "gettext.h"
@@ -79,7 +78,7 @@ static int run_remote_archiver(int argc, const char **argv,
int cmd_archive(int argc,
const char **argv,
const char *prefix,
- struct repository *repo UNUSED)
+ struct repository *repo)
{
const char *exec = "git-upload-archive";
char *output = NULL;
@@ -110,7 +109,7 @@ int cmd_archive(int argc,
setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
- ret = write_archive(argc, argv, prefix, the_repository, output, 0);
+ ret = write_archive(argc, argv, prefix, repo, output, 0);
out:
free(output);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 9c30000d3a..c449558e66 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1716,7 +1716,7 @@ static struct option *add_common_switch_branch_options(
N_("update ignored files (default)"),
PARSE_OPT_NOCOMPLETE),
OPT_BOOL(0, "ignore-other-worktrees", &opts->ignore_other_worktrees,
- N_("do not check if another worktree is holding the given ref")),
+ N_("do not check if another worktree is using this branch")),
OPT_END()
};
struct option *newopts = parse_options_concat(prevopts, options);
diff --git a/builtin/clone.c b/builtin/clone.c
index e77339c847..c0013c75cd 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -147,8 +147,8 @@ static struct option builtin_clone_options[] = {
N_("create a shallow clone of that depth")),
OPT_STRING(0, "shallow-since", &option_since, N_("time"),
N_("create a shallow clone since a specific time")),
- OPT_STRING_LIST(0, "shallow-exclude", &option_not, N_("revision"),
- N_("deepen history of shallow clone, excluding rev")),
+ OPT_STRING_LIST(0, "shallow-exclude", &option_not, N_("ref"),
+ N_("deepen history of shallow clone, excluding ref")),
OPT_BOOL(0, "single-branch", &option_single_branch,
N_("clone only one branch, HEAD or --branch")),
OPT_BOOL(0, "no-tags", &option_no_tags,
@@ -1403,8 +1403,17 @@ int cmd_clone(int argc,
* data from the --bundle-uri option.
*/
if (bundle_uri) {
+ struct remote_state *state;
int has_heuristic = 0;
+ /*
+ * We need to save the remote state as our remote's lifetime is
+ * tied to it.
+ */
+ state = the_repository->remote_state;
+ the_repository->remote_state = NULL;
+ repo_clear(the_repository);
+
/* At this point, we need the_repository to match the cloned repo. */
if (repo_init(the_repository, git_dir, work_tree))
warning(_("failed to initialize the repo, skipping bundle URI"));
@@ -1413,6 +1422,10 @@ int cmd_clone(int argc,
bundle_uri);
else if (has_heuristic)
git_config_set_gently("fetch.bundleuri", bundle_uri);
+
+ remote_state_clear(the_repository->remote_state);
+ free(the_repository->remote_state);
+ the_repository->remote_state = state;
} else {
/*
* Populate transport->got_remote_bundle_uri and
@@ -1422,12 +1435,26 @@ int cmd_clone(int argc,
if (transport->bundles &&
hashmap_get_size(&transport->bundles->bundles)) {
+ struct remote_state *state;
+
+ /*
+ * We need to save the remote state as our remote's
+ * lifetime is tied to it.
+ */
+ state = the_repository->remote_state;
+ the_repository->remote_state = NULL;
+ repo_clear(the_repository);
+
/* At this point, we need the_repository to match the cloned repo. */
if (repo_init(the_repository, git_dir, work_tree))
warning(_("failed to initialize the repo, skipping bundle URI"));
else if (fetch_bundle_list(the_repository,
transport->bundles))
warning(_("failed to fetch advertised bundles"));
+
+ remote_state_clear(the_repository->remote_state);
+ free(the_repository->remote_state);
+ the_repository->remote_state = state;
} else {
clear_bundle_list(transport->bundles);
FREE_AND_NULL(transport->bundles);
diff --git a/builtin/commit.c b/builtin/commit.c
index 8db4e9df0c..71d674138c 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -135,7 +135,7 @@ static struct strvec trailer_args = STRVEC_INIT;
* is specified explicitly.
*/
static enum commit_msg_cleanup_mode cleanup_mode;
-static char *cleanup_arg;
+static char *cleanup_config;
static enum commit_whence whence;
static int use_editor = 1, include_status = 1;
@@ -728,6 +728,13 @@ static void prepare_amend_commit(struct commit *commit, struct strbuf *sb,
repo_unuse_commit_buffer(the_repository, commit, buffer);
}
+static void change_data_free(void *util, const char *str UNUSED)
+{
+ struct wt_status_change_data *d = util;
+ free(d->rename_source);
+ free(d);
+}
+
static int prepare_to_commit(const char *index_file, const char *prefix,
struct commit *current_head,
struct wt_status *s,
@@ -991,7 +998,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
s->use_color = 0;
committable = run_status(s->fp, index_file, prefix, 1, s);
s->use_color = saved_color_setting;
- string_list_clear(&s->change, 1);
+ string_list_clear_func(&s->change, change_data_free);
} else {
struct object_id oid;
const char *parent = "HEAD";
@@ -1380,8 +1387,6 @@ static int parse_and_validate_options(int argc, const char *argv[],
if (0 <= edit_flag)
use_editor = edit_flag;
- cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
-
handle_untracked_files_arg(s);
if (all && argc > 0)
@@ -1629,8 +1634,10 @@ static int git_commit_config(const char *k, const char *v,
include_status = git_config_bool(k, v);
return 0;
}
- if (!strcmp(k, "commit.cleanup"))
- return git_config_string(&cleanup_arg, k, v);
+ if (!strcmp(k, "commit.cleanup")) {
+ FREE_AND_NULL(cleanup_config);
+ return git_config_string(&cleanup_config, k, v);
+ }
if (!strcmp(k, "commit.gpgsign")) {
sign_commit = git_config_bool(k, v) ? "" : NULL;
return 0;
@@ -1651,6 +1658,7 @@ int cmd_commit(int argc,
struct repository *repo UNUSED)
{
static struct wt_status s;
+ static const char *cleanup_arg = NULL;
static struct option builtin_commit_options[] = {
OPT__QUIET(&quiet, N_("suppress summary after successful commit")),
OPT__VERBOSE(&verbose, N_("show diff in commit message template")),
@@ -1750,6 +1758,12 @@ int cmd_commit(int argc,
if (verbose == -1)
verbose = (config_commit_verbose < 0) ? 0 : config_commit_verbose;
+ if (cleanup_arg) {
+ free(cleanup_config);
+ cleanup_config = xstrdup(cleanup_arg);
+ }
+ cleanup_mode = get_cleanup_mode(cleanup_config, use_editor);
+
if (dry_run)
return dry_run_commit(argv, prefix, current_head, &s);
index_file = prepare_index(argv, prefix, current_head, 0);
diff --git a/builtin/config.c b/builtin/config.c
index d8fd3def0e..cba7022108 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -19,7 +19,7 @@ static const char *const builtin_config_usage[] = {
N_("git config list [<file-option>] [<display-option>] [--includes]"),
N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"),
N_("git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
- N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
+ N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>"),
N_("git config rename-section [<file-option>] <old-name> <new-name>"),
N_("git config remove-section [<file-option>] <name>"),
N_("git config edit [<file-option>]"),
@@ -43,7 +43,7 @@ static const char *const builtin_config_set_usage[] = {
};
static const char *const builtin_config_unset_usage[] = {
- N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
+ N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>"),
NULL
};
diff --git a/builtin/credential-cache.c b/builtin/credential-cache.c
index 5de8b9123b..7f733cb756 100644
--- a/builtin/credential-cache.c
+++ b/builtin/credential-cache.c
@@ -30,7 +30,7 @@ static int connection_fatally_broken(int error)
static int connection_closed(int error)
{
- return (error == ECONNRESET);
+ return error == ECONNRESET || error == ECONNABORTED;
}
static int connection_fatally_broken(int error)
@@ -189,7 +189,8 @@ int cmd_credential_cache(int argc,
#else
-int cmd_credential_cache(int argc, const char **argv, const char *prefix)
+int cmd_credential_cache(int argc, const char **argv, const char *prefix,
+ struct repository *repo UNUSED)
{
const char * const usage[] = {
"git credential-cache [options] <action>",
diff --git a/builtin/difftool.c b/builtin/difftool.c
index 5772e82106..ca1b089065 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -340,7 +340,7 @@ static void write_file_in_directory(struct strbuf *dir, size_t dir_len,
/* Write the file contents for the left and right sides of the difftool
* dir-diff representation for submodules and symlinks. Symlinks and submodules
* are written as regular text files so that external diff tools can diff them
- * as text files, resulting in behavior that is analogous to to what "git diff"
+ * as text files, resulting in behavior that is analogous to what "git diff"
* displays for symlink and submodule diffs.
*/
static void write_standin_files(struct pair_entry *entry,
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index 1e7ab67f6e..76d5c20f14 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -966,8 +966,7 @@ static int store_object(
if (e->idx.offset) {
duplicate_count_by_type[type]++;
return 1;
- } else if (find_sha1_pack(oid.hash,
- get_all_packs(the_repository))) {
+ } else if (find_oid_pack(&oid, get_all_packs(the_repository))) {
e->type = type;
e->pack_id = MAX_PACK_ID;
e->idx.offset = 1; /* just not zero! */
@@ -1167,8 +1166,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
duplicate_count_by_type[OBJ_BLOB]++;
truncate_pack(&checkpoint);
- } else if (find_sha1_pack(oid.hash,
- get_all_packs(the_repository))) {
+ } else if (find_oid_pack(&oid, get_all_packs(the_repository))) {
e->type = OBJ_BLOB;
e->pack_id = MAX_PACK_ID;
e->idx.offset = 1; /* just not zero! */
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 80a64d0d26..18eff4e5fa 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1981,6 +1981,8 @@ static int fetch_multiple(struct string_list *list, int max_children,
strvec_pushl(&argv, "-c", "fetch.bundleURI=",
"fetch", "--append", "--no-auto-gc",
"--no-write-commit-graph", NULL);
+ for (i = 0; i < server_options.nr; i++)
+ strvec_pushf(&argv, "--server-option=%s", server_options.items[i].string);
add_options_to_argv(&argv, config);
if (max_children != 1 && list->nr != 1) {
@@ -2214,8 +2216,8 @@ int cmd_fetch(int argc,
N_("deepen history of shallow clone")),
OPT_STRING(0, "shallow-since", &deepen_since, N_("time"),
N_("deepen history of shallow repository based on time")),
- OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("revision"),
- N_("deepen history of shallow clone, excluding rev")),
+ OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("ref"),
+ N_("deepen history of shallow clone, excluding ref")),
OPT_INTEGER(0, "deepen", &deepen_relative,
N_("deepen history of shallow clone")),
OPT_SET_INT_F(0, "unshallow", &unshallow,
diff --git a/builtin/grep.c b/builtin/grep.c
index f17d46a06e..98b85c7fca 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -906,6 +906,7 @@ int cmd_grep(int argc,
int dummy;
int use_index = 1;
int allow_revs;
+ int ret;
struct option options[] = {
OPT_BOOL(0, "cached", &cached,
@@ -1172,8 +1173,10 @@ int cmd_grep(int argc,
* Optimize out the case where the amount of matches is limited to zero.
* We do this to keep results consistent with GNU grep(1).
*/
- if (opt.max_count == 0)
- return 1;
+ if (opt.max_count == 0) {
+ ret = 1;
+ goto out;
+ }
if (show_in_pager) {
if (num_threads > 1)
@@ -1267,10 +1270,14 @@ int cmd_grep(int argc,
hit |= wait_all();
if (hit && show_in_pager)
run_pager(&opt, prefix);
+
+ ret = !hit;
+
+out:
clear_pathspec(&pathspec);
string_list_clear(&path_list, 0);
free_grep_patterns(&opt);
object_array_clear(&list);
free_repos();
- return !hit;
+ return ret;
}
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index e228c56ff2..08b340552f 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -9,6 +9,7 @@
#include "csum-file.h"
#include "blob.h"
#include "commit.h"
+#include "tag.h"
#include "tree.h"
#include "progress.h"
#include "fsck.h"
@@ -20,9 +21,14 @@
#include "object-file.h"
#include "object-store-ll.h"
#include "oid-array.h"
+#include "oidset.h"
+#include "path.h"
#include "replace-object.h"
+#include "tree-walk.h"
#include "promisor-remote.h"
+#include "run-command.h"
#include "setup.h"
+#include "strvec.h"
static const char index_pack_usage[] =
"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--[no-]rev-index] [--verify] [--strict[=<msg-id>=<severity>...]] [--fsck-objects[=<msg-id>=<severity>...]] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
@@ -148,6 +154,13 @@ static uint32_t input_crc32;
static int input_fd, output_fd;
static const char *curr_pack;
+/*
+ * local_links is guarded by read_mutex, and record_local_links is read-only in
+ * a thread.
+ */
+static struct oidset local_links = OIDSET_INIT;
+static int record_local_links;
+
static struct thread_local *thread_data;
static int nr_dispatched;
static int threads_active;
@@ -799,6 +812,44 @@ static int check_collison(struct object_entry *entry)
return 0;
}
+static void record_if_local_object(const struct object_id *oid)
+{
+ struct object_info info = OBJECT_INFO_INIT;
+ if (oid_object_info_extended(the_repository, oid, &info, 0))
+ /* Missing; assume it is a promisor object */
+ return;
+ if (info.whence == OI_PACKED && info.u.packed.pack->pack_promisor)
+ return;
+ oidset_insert(&local_links, oid);
+}
+
+static void do_record_local_links(struct object *obj)
+{
+ if (obj->type == OBJ_TREE) {
+ struct tree *tree = (struct tree *)obj;
+ struct tree_desc desc;
+ struct name_entry entry;
+ if (init_tree_desc_gently(&desc, &tree->object.oid,
+ tree->buffer, tree->size, 0))
+ /*
+ * Error messages are given when packs are
+ * verified, so do not print any here.
+ */
+ return;
+ while (tree_entry_gently(&desc, &entry))
+ record_if_local_object(&entry.oid);
+ } else if (obj->type == OBJ_COMMIT) {
+ struct commit *commit = (struct commit *) obj;
+ struct commit_list *parents = commit->parents;
+
+ for (; parents; parents = parents->next)
+ record_if_local_object(&parents->item->object.oid);
+ } else if (obj->type == OBJ_TAG) {
+ struct tag *tag = (struct tag *) obj;
+ record_if_local_object(get_tagged_oid(tag));
+ }
+}
+
static void sha1_object(const void *data, struct object_entry *obj_entry,
unsigned long size, enum object_type type,
const struct object_id *oid)
@@ -845,7 +896,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
free(has_data);
}
- if (strict || do_fsck_object) {
+ if (strict || do_fsck_object || record_local_links) {
read_lock();
if (type == OBJ_BLOB) {
struct blob *blob = lookup_blob(the_repository, oid);
@@ -877,6 +928,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
die(_("fsck error in packed object"));
if (strict && fsck_walk(obj, NULL, &fsck_options))
die(_("Not all child objects of %s are reachable"), oid_to_hex(&obj->oid));
+ if (record_local_links)
+ do_record_local_links(obj);
if (obj->type == OBJ_TREE) {
struct tree *item = (struct tree *) obj;
@@ -1505,7 +1558,7 @@ static void rename_tmp_packfile(const char **final_name,
struct strbuf *name, unsigned char *hash,
const char *ext, int make_read_only_if_same)
{
- if (*final_name != curr_name) {
+ if (!*final_name || strcmp(*final_name, curr_name)) {
if (!*final_name)
*final_name = odb_pack_name(name, hash, ext);
if (finalize_object_file(curr_name, *final_name))
@@ -1719,6 +1772,58 @@ static void show_pack_info(int stat_only)
free(chain_histogram);
}
+static void repack_local_links(void)
+{
+ struct child_process cmd = CHILD_PROCESS_INIT;
+ FILE *out;
+ struct strbuf line = STRBUF_INIT;
+ struct oidset_iter iter;
+ struct object_id *oid;
+ char *base_name;
+
+ if (!oidset_size(&local_links))
+ return;
+
+ base_name = mkpathdup("%s/pack/pack", repo_get_object_directory(the_repository));
+
+ strvec_push(&cmd.args, "pack-objects");
+ strvec_push(&cmd.args, "--exclude-promisor-objects-best-effort");
+ strvec_push(&cmd.args, base_name);
+ cmd.git_cmd = 1;
+ cmd.in = -1;
+ cmd.out = -1;
+ if (start_command(&cmd))
+ die(_("could not start pack-objects to repack local links"));
+
+ oidset_iter_init(&local_links, &iter);
+ while ((oid = oidset_iter_next(&iter))) {
+ if (write_in_full(cmd.in, oid_to_hex(oid), the_hash_algo->hexsz) < 0 ||
+ write_in_full(cmd.in, "\n", 1) < 0)
+ die(_("failed to feed local object to pack-objects"));
+ }
+ close(cmd.in);
+
+ out = xfdopen(cmd.out, "r");
+ while (strbuf_getline_lf(&line, out) != EOF) {
+ unsigned char binary[GIT_MAX_RAWSZ];
+ if (line.len != the_hash_algo->hexsz ||
+ !hex_to_bytes(binary, line.buf, line.len))
+ die(_("index-pack: Expecting full hex object ID lines only from pack-objects."));
+
+ /*
+ * pack-objects creates the .pack and .idx files, but not the
+ * .promisor file. Create the .promisor file, which is empty.
+ */
+ write_special_file("promisor", "", NULL, binary, NULL);
+ }
+
+ fclose(out);
+ if (finish_command(&cmd))
+ die(_("could not finish pack-objects to repack local links"));
+ strbuf_release(&line);
+ free(base_name);
+}
+
int cmd_index_pack(int argc,
const char **argv,
const char *prefix,
@@ -1726,7 +1831,7 @@ int cmd_index_pack(int argc,
{
int i, fix_thin_pack = 0, verify = 0, stat_only = 0, rev_index;
const char *curr_index;
- const char *curr_rev_index = NULL;
+ char *curr_rev_index = NULL;
const char *index_name = NULL, *pack_name = NULL, *rev_index_name = NULL;
const char *keep_msg = NULL;
const char *promisor_msg = NULL;
@@ -1794,7 +1899,7 @@ int cmd_index_pack(int argc,
} else if (skip_to_optional_arg(arg, "--keep", &keep_msg)) {
; /* nothing to do */
} else if (skip_to_optional_arg(arg, "--promisor", &promisor_msg)) {
- ; /* already parsed */
+ record_local_links = 1;
} else if (starts_with(arg, "--threads=")) {
char *end;
nr_threads = strtoul(arg+10, &end, 0);
@@ -1968,8 +2073,9 @@ int cmd_index_pack(int argc,
free((void *) curr_pack);
if (!index_name)
free((void *) curr_index);
- if (!rev_index_name)
- free((void *) curr_rev_index);
+ free(curr_rev_index);
+
+ repack_local_links();
/*
* Let the caller know this pack is not self contained
diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
index c5e56e2cd3..44d8ccddc9 100644
--- a/builtin/interpret-trailers.c
+++ b/builtin/interpret-trailers.c
@@ -141,8 +141,8 @@ static void interpret_trailers(const struct process_trailer_options *opts,
{
LIST_HEAD(head);
struct strbuf sb = STRBUF_INIT;
- struct strbuf trailer_block = STRBUF_INIT;
- struct trailer_info *info;
+ struct strbuf trailer_block_sb = STRBUF_INIT;
+ struct trailer_block *trailer_block;
FILE *outfile = stdout;
trailer_config_init();
@@ -152,13 +152,13 @@ static void interpret_trailers(const struct process_trailer_options *opts,
if (opts->in_place)
outfile = create_in_place_tempfile(file);
- info = parse_trailers(opts, sb.buf, &head);
+ trailer_block = parse_trailers(opts, sb.buf, &head);
- /* Print the lines before the trailers */
+ /* Print the lines before the trailer block */
if (!opts->only_trailers)
- fwrite(sb.buf, 1, trailer_block_start(info), outfile);
+ fwrite(sb.buf, 1, trailer_block_start(trailer_block), outfile);
- if (!opts->only_trailers && !blank_line_before_trailer_block(info))
+ if (!opts->only_trailers && !blank_line_before_trailer_block(trailer_block))
fprintf(outfile, "\n");
@@ -172,15 +172,16 @@ static void interpret_trailers(const struct process_trailer_options *opts,
}
/* Print trailer block. */
- format_trailers(opts, &head, &trailer_block);
+ format_trailers(opts, &head, &trailer_block_sb);
free_trailers(&head);
- fwrite(trailer_block.buf, 1, trailer_block.len, outfile);
- strbuf_release(&trailer_block);
+ fwrite(trailer_block_sb.buf, 1, trailer_block_sb.len, outfile);
+ strbuf_release(&trailer_block_sb);
- /* Print the lines after the trailers as is */
+ /* Print the lines after the trailer block as is. */
if (!opts->only_trailers)
- fwrite(sb.buf + trailer_block_end(info), 1, sb.len - trailer_block_end(info), outfile);
- trailer_info_release(info);
+ fwrite(sb.buf + trailer_block_end(trailer_block), 1,
+ sb.len - trailer_block_end(trailer_block), outfile);
+ trailer_block_release(trailer_block);
if (opts->in_place)
if (rename_tempfile(&trailers_tempfile, file))
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index f723b3bf3b..42f34e1236 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -166,6 +166,7 @@ int cmd_ls_remote(int argc,
status = 0; /* we found something */
}
+ string_list_clear(&server_options, 0);
ref_sorting_release(sorting);
ref_array_clear(&ref_array);
if (transport_disconnect(transport))
@@ -173,5 +174,6 @@ int cmd_ls_remote(int argc,
transport_ls_refs_options_release(&transport_options);
strvec_clear(&pattern);
+ string_list_clear(&server_options, 0);
return status;
}
diff --git a/builtin/merge.c b/builtin/merge.c
index 84d0f3604b..51038eaca8 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -754,6 +754,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
clean = merge_recursive(&o, head, remoteheads->item,
reversed, &result);
free_commit_list(reversed);
+ strbuf_release(&o.obuf);
if (clean < 0) {
rollback_lock_file(&lock);
diff --git a/builtin/notes.c b/builtin/notes.c
index 8c26e45526..72c8a51cfa 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -32,9 +32,9 @@
static const char *separator = "\n";
static const char * const git_notes_usage[] = {
N_("git notes [--ref <notes-ref>] [list [<object>]]"),
- N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+ N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>] [-e]"),
N_("git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"),
- N_("git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+ N_("git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>] [-e]"),
N_("git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"),
N_("git notes [--ref <notes-ref>] show [<object>]"),
N_("git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>"),
@@ -489,6 +489,8 @@ static int add(int argc, const char **argv, const char *prefix)
OPT_CALLBACK_F('c', "reedit-message", &d, N_("object"),
N_("reuse and edit specified note object"), PARSE_OPT_NONEG,
parse_reedit_arg),
+ OPT_BOOL('e', "edit", &d.use_editor,
+ N_("edit note message in editor")),
OPT_CALLBACK_F('C', "reuse-message", &d, N_("object"),
N_("reuse specified note object"), PARSE_OPT_NONEG,
parse_reuse_arg),
@@ -667,6 +669,8 @@ static int append_edit(int argc, const char **argv, const char *prefix)
OPT_CALLBACK_F('C', "reuse-message", &d, N_("object"),
N_("reuse specified note object"), PARSE_OPT_NONEG,
parse_reuse_arg),
+ OPT_BOOL('e', "edit", &d.use_editor,
+ N_("edit note message in editor")),
OPT_BOOL(0, "allow-empty", &allow_empty,
N_("allow storing empty note")),
OPT_CALLBACK_F(0, "separator", &separator,
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 0fc0680b40..762949e4c8 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -239,6 +239,7 @@ static enum {
static uint16_t write_bitmap_options = BITMAP_OPT_HASH_CACHE;
static int exclude_promisor_objects;
+static int exclude_promisor_objects_best_effort;
static int use_delta_islands;
@@ -1556,7 +1557,7 @@ static int want_object_in_pack_one(struct packed_git *p,
if (p == *found_pack)
offset = *found_offset;
else
- offset = find_pack_entry_one(oid->hash, p);
+ offset = find_pack_entry_one(oid, p);
if (offset) {
if (!*found_pack) {
@@ -3984,7 +3985,7 @@ static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid)
while (p) {
if ((!p->pack_local || p->pack_keep ||
p->pack_keep_in_core) &&
- find_pack_entry_one(oid->hash, p)) {
+ find_pack_entry_one(oid, p)) {
last_found = p;
return 1;
}
@@ -4312,6 +4313,18 @@ static int option_parse_cruft_expiration(const struct option *opt UNUSED,
return 0;
}
+static int is_not_in_promisor_pack_obj(struct object *obj, void *data UNUSED)
+{
+ struct object_info info = OBJECT_INFO_INIT;
+ if (oid_object_info_extended(the_repository, &obj->oid, &info, 0))
+ BUG("should_include_obj should only be called on existing objects");
+ return info.whence != OI_PACKED || !info.u.packed.pack->pack_promisor;
+}
+
+static int is_not_in_promisor_pack(struct commit *commit, void *data) {
+ return is_not_in_promisor_pack_obj((struct object *) commit, data);
+}
+
int cmd_pack_objects(int argc,
const char **argv,
const char *prefix,
@@ -4424,6 +4437,9 @@ int cmd_pack_objects(int argc,
option_parse_missing_action),
OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects,
N_("do not pack objects in promisor packfiles")),
+ OPT_BOOL(0, "exclude-promisor-objects-best-effort",
+ &exclude_promisor_objects_best_effort,
+ N_("implies --missing=allow-any")),
OPT_BOOL(0, "delta-islands", &use_delta_islands,
N_("respect islands during delta compression")),
OPT_STRING_LIST(0, "uri-protocol", &uri_protocols,
@@ -4504,10 +4520,18 @@ int cmd_pack_objects(int argc,
strvec_push(&rp, "--unpacked");
}
+ if (exclude_promisor_objects && exclude_promisor_objects_best_effort)
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--exclude-promisor-objects", "--exclude-promisor-objects-best-effort");
if (exclude_promisor_objects) {
use_internal_rev_list = 1;
fetch_if_missing = 0;
strvec_push(&rp, "--exclude-promisor-objects");
+ } else if (exclude_promisor_objects_best_effort) {
+ use_internal_rev_list = 1;
+ fetch_if_missing = 0;
+ option_parse_missing_action(NULL, "allow-any", 0);
+ /* revs configured below */
}
if (unpack_unreachable || keep_unreachable || pack_loose_unreachable)
use_internal_rev_list = 1;
@@ -4627,6 +4651,10 @@ int cmd_pack_objects(int argc,
repo_init_revisions(the_repository, &revs, NULL);
list_objects_filter_copy(&revs.filter, &filter_options);
+ if (exclude_promisor_objects_best_effort) {
+ revs.include_check = is_not_in_promisor_pack;
+ revs.include_check_obj = is_not_in_promisor_pack_obj;
+ }
get_object_list(&revs, rp.nr, rp.v);
release_revisions(&revs);
}
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index 81f4494d46..d2c1c4e5ec 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -13,6 +13,7 @@
#include "packfile.h"
#include "object-store-ll.h"
+#include "strbuf.h"
#define BLKSIZE 512
@@ -69,6 +70,15 @@ static inline void llist_init(struct llist **list)
(*list)->size = 0;
}
+static void llist_free(struct llist *list)
+{
+ for (struct llist_item *i = list->front, *next; i; i = next) {
+ next = i->next;
+ llist_item_put(i);
+ }
+ free(list);
+}
+
static struct llist * llist_copy(struct llist *list)
{
struct llist *ret;
@@ -206,6 +216,14 @@ static inline struct pack_list * pack_list_insert(struct pack_list **pl,
return p;
}
+static void pack_list_free(struct pack_list *pl)
+{
+ for (struct pack_list *next; pl; pl = next) {
+ next = pl->next;
+ free(pl);
+ }
+}
+
static inline size_t pack_list_size(struct pack_list *pl)
{
size_t ret = 0;
@@ -419,7 +437,8 @@ static void minimize(struct pack_list **min)
/* return if there are no objects missing from the unique set */
if (missing->size == 0) {
- free(missing);
+ llist_free(missing);
+ pack_list_free(non_unique);
return;
}
@@ -434,6 +453,8 @@ static void minimize(struct pack_list **min)
}
while (non_unique) {
+ struct pack_list *next;
+
/* sort the non_unique packs, greater size of remaining_objects first */
sort_pack_list(&non_unique);
if (non_unique->remaining_objects->size == 0)
@@ -444,8 +465,14 @@ static void minimize(struct pack_list **min)
for (pl = non_unique->next; pl && pl->remaining_objects->size > 0; pl = pl->next)
llist_sorted_difference_inplace(pl->remaining_objects, non_unique->remaining_objects);
- non_unique = non_unique->next;
+ next = non_unique->next;
+ free(non_unique);
+ non_unique = next;
}
+
+ pack_list_free(non_unique);
+ llist_free(unique_pack_objects);
+ llist_free(missing);
}
static void load_all_objects(void)
@@ -565,7 +592,7 @@ static void load_all(void)
int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, struct repository *repo UNUSED) {
int i; int i_still_use_this = 0; struct pack_list *min = NULL, *red, *pl;
struct llist *ignore;
- struct object_id *oid;
+ struct strbuf idx_name = STRBUF_INIT;
char buf[GIT_MAX_HEXSZ + 2]; /* hex hash + \n + \0 */
if (argc == 2 && !strcmp(argv[1], "-h"))
@@ -625,11 +652,11 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, s
/* ignore objects given on stdin */
llist_init(&ignore);
if (!isatty(0)) {
+ struct object_id oid;
while (fgets(buf, sizeof(buf), stdin)) {
- oid = xmalloc(sizeof(*oid));
- if (get_oid_hex(buf, oid))
+ if (get_oid_hex(buf, &oid))
die("Bad object ID on stdin: %s", buf);
- llist_insert_sorted_unique(ignore, oid, NULL);
+ llist_insert_sorted_unique(ignore, &oid, NULL);
}
}
llist_sorted_difference_inplace(all_objects, ignore);
@@ -663,7 +690,7 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, s
pl = red = pack_list_difference(local_packs, min);
while (pl) {
printf("%s\n%s\n",
- sha1_pack_index_name(pl->pack->hash),
+ odb_pack_name(&idx_name, pl->pack->hash, "idx"),
pl->pack->pack_name);
pl = pl->next;
}
@@ -671,5 +698,9 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, s
fprintf(stderr, "%luMB of redundant packs in total.\n",
(unsigned long)pack_set_bytecount(red)/(1024*1024));
+ pack_list_free(red);
+ pack_list_free(min);
+ llist_free(ignore);
+ strbuf_release(&idx_name);
return 0;
}
diff --git a/builtin/pull.c b/builtin/pull.c
index 388ef3d130..edc56907aa 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -218,8 +218,8 @@ static struct option pull_options[] = {
OPT_PASSTHRU_ARGV(0, "shallow-since", &opt_fetch, N_("time"),
N_("deepen history of shallow repository based on time"),
0),
- OPT_PASSTHRU_ARGV(0, "shallow-exclude", &opt_fetch, N_("revision"),
- N_("deepen history of shallow clone, excluding rev"),
+ OPT_PASSTHRU_ARGV(0, "shallow-exclude", &opt_fetch, N_("ref"),
+ N_("deepen history of shallow clone, excluding ref"),
0),
OPT_PASSTHRU_ARGV(0, "deepen", &opt_fetch, N_("n"),
N_("deepen history of shallow clone"),
diff --git a/builtin/push.c b/builtin/push.c
index 59d4485603..51c609f208 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -519,14 +519,7 @@ static int git_push_config(const char *k, const char *v,
RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF;
recurse_submodules = val;
} else if (!strcmp(k, "push.pushoption")) {
- if (!v)
- return config_error_nonbool(k);
- else
- if (!*v)
- string_list_clear(&push_options_config, 0);
- else
- string_list_append(&push_options_config, v);
- return 0;
+ return parse_transport_option(k, v, &push_options_config);
} else if (!strcmp(k, "color.push")) {
push_use_color = git_config_colorbool(k, v);
return 0;
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 536d22761d..ab5b20e39c 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -374,6 +374,7 @@ static void write_head_info(void)
struct command {
struct command *next;
const char *error_string;
+ char *error_string_owned;
struct ref_push_report *report;
unsigned int skip_update:1,
did_not_exist:1,
@@ -1083,7 +1084,7 @@ static int read_proc_receive_report(struct packet_reader *reader,
hint->run_proc_receive |= RUN_PROC_RECEIVE_RETURNED;
if (!strcmp(head, "ng")) {
if (p)
- hint->error_string = xstrdup(p);
+ hint->error_string = hint->error_string_owned = xstrdup(p);
else
hint->error_string = "failed";
code = -1;
@@ -2054,6 +2055,8 @@ static void free_commands(struct command *commands)
while (commands) {
struct command *next = commands->next;
+ ref_push_report_free(commands->report);
+ free(commands->error_string_owned);
free(commands);
commands = next;
}
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index f62bcbf2b1..3078787115 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -485,6 +485,13 @@ static int try_bitmap_traversal(struct rev_info *revs,
if (revs->max_count >= 0)
return -1;
+ /*
+ * We can't know which commits were left/right in a single traversal,
+ * and we don't yet know how to traverse them separately.
+ */
+ if (revs->left_right)
+ return -1;
+
bitmap_git = prepare_bitmap_walk(revs, filter_provided_objects);
if (!bitmap_git)
return -1;
diff --git a/builtin/revert.c b/builtin/revert.c
index 55ba1092c5..b7917dddd3 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -110,6 +110,9 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
const char * const * usage_str = revert_or_cherry_pick_usage(opts);
const char *me = action_name(opts);
const char *cleanup_arg = NULL;
+ const char sentinel_value;
+ const char *strategy = &sentinel_value;
+ const char *gpg_sign = &sentinel_value;
enum empty_action empty_opt = EMPTY_COMMIT_UNSPECIFIED;
int cmd = 0;
struct option base_options[] = {
@@ -125,10 +128,10 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
OPT_CALLBACK('m', "mainline", opts, N_("parent-number"),
N_("select mainline parent"), option_parse_m),
OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto),
- OPT_STRING(0, "strategy", &opts->strategy, N_("strategy"), N_("merge strategy")),
+ OPT_STRING(0, "strategy", &strategy, N_("strategy"), N_("merge strategy")),
OPT_STRVEC('X', "strategy-option", &opts->xopts, N_("option"),
N_("option for merge strategy")),
- { OPTION_STRING, 'S', "gpg-sign", &opts->gpg_sign, N_("key-id"),
+ { OPTION_STRING, 'S', "gpg-sign", &gpg_sign, N_("key-id"),
N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
OPT_END()
};
@@ -240,8 +243,14 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
usage_with_options(usage_str, options);
/* These option values will be free()d */
- opts->gpg_sign = xstrdup_or_null(opts->gpg_sign);
- opts->strategy = xstrdup_or_null(opts->strategy);
+ if (gpg_sign != &sentinel_value) {
+ free(opts->gpg_sign);
+ opts->gpg_sign = xstrdup_or_null(gpg_sign);
+ }
+ if (strategy != &sentinel_value) {
+ free(opts->strategy);
+ opts->strategy = xstrdup_or_null(strategy);
+ }
if (!opts->strategy && getenv("GIT_TEST_MERGE_ALGORITHM"))
opts->strategy = xstrdup(getenv("GIT_TEST_MERGE_ALGORITHM"));
free(options);
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 8b1d46e79a..59b626aae8 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -340,6 +340,7 @@ int cmd_send_pack(int argc,
/* stable plumbing output; do not modify or localize */
fprintf(stderr, "Everything up-to-date\n");
+ string_list_clear(&push_options, 0);
free_refs(remote_refs);
free_refs(local_refs);
refspec_clear(&rs);
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 3ed5c46078..c86b75d981 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -407,6 +407,18 @@ int cmd_shortlog(int argc,
struct parse_opt_ctx_t ctx;
+ /*
+ * NEEDSWORK: Later on we'll call parse_revision_opt which relies on
+ * the hash algorithm being set but since we are operating outside of a
+ * Git repository we cannot determine one. This is only needed because
+ * parse_revision_opt expects hexsz for --abbrev which is irrelevant
+ * for shortlog outside of a git repository. For now explicitly set
+ * SHA1, but ideally the parsing machinery would be split between
+ * git/nongit so that we do not have to do this.
+ */
+ if (nongit && !the_hash_algo)
+ repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
git_config(git_default_config, NULL);
shortlog_init(&log);
repo_init_revisions(the_repository, &rev, prefix);
diff --git a/builtin/stash.c b/builtin/stash.c
index f1acc918d0..1399a1bbe2 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -1759,7 +1759,7 @@ static int push_stash(int argc, const char **argv, const char *prefix,
int quiet = 0;
int pathspec_file_nul = 0;
const char *stash_msg = NULL;
- const char *pathspec_from_file = NULL;
+ char *pathspec_from_file = NULL;
struct pathspec ps;
struct option options[] = {
OPT_BOOL('k', "keep-index", &keep_index,
@@ -1821,7 +1821,9 @@ static int push_stash(int argc, const char **argv, const char *prefix,
ret = do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode,
include_untracked, only_staged);
+
clear_pathspec(&ps);
+ free(pathspec_from_file);
return ret;
}
diff --git a/builtin/tag.c b/builtin/tag.c
index 93d10d5915..c37c0a68fd 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -164,7 +164,7 @@ static int do_sign(struct strbuf *buffer, struct object_id **compat_oid,
int ret = -1;
if (sign_buffer(buffer, &sig, keyid))
- return -1;
+ goto out;
if (compat) {
const struct git_hash_algo *algo = the_repository->hash_algo;
diff --git a/builtin/worktree.c b/builtin/worktree.c
index fc31d072a6..dae63dedf4 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -414,7 +414,8 @@ static int add_worktree(const char *path, const char *refname,
const struct add_opts *opts)
{
struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
- struct strbuf sb = STRBUF_INIT, realpath = STRBUF_INIT;
+ struct strbuf sb = STRBUF_INIT, sb_tmp = STRBUF_INIT;
+ struct strbuf sb_path_realpath = STRBUF_INIT, sb_repo_realpath = STRBUF_INIT;
const char *name;
struct strvec child_env = STRVEC_INIT;
unsigned int counter = 0;
@@ -490,11 +491,10 @@ static int add_worktree(const char *path, const char *refname,
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
- strbuf_realpath(&realpath, sb_git.buf, 1);
- write_file(sb.buf, "%s", realpath.buf);
- strbuf_realpath(&realpath, repo_get_common_dir(the_repository), 1);
- write_file(sb_git.buf, "gitdir: %s/worktrees/%s",
- realpath.buf, name);
+ strbuf_realpath(&sb_path_realpath, path, 1);
+ strbuf_realpath(&sb_repo_realpath, sb_repo.buf, 1);
+ write_file(sb.buf, "%s/.git", relative_path(sb_path_realpath.buf, sb_repo_realpath.buf, &sb_tmp));
+ write_file(sb_git.buf, "gitdir: %s", relative_path(sb_repo_realpath.buf, sb_path_realpath.buf, &sb_tmp));
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
write_file(sb.buf, "../..");
@@ -578,11 +578,13 @@ done:
strvec_clear(&child_env);
strbuf_release(&sb);
+ strbuf_release(&sb_tmp);
strbuf_release(&symref);
strbuf_release(&sb_repo);
+ strbuf_release(&sb_repo_realpath);
strbuf_release(&sb_git);
+ strbuf_release(&sb_path_realpath);
strbuf_release(&sb_name);
- strbuf_release(&realpath);
free_worktree(wt);
return ret;
}