global: introduce `USE_THE_REPOSITORY_VARIABLE` macro
Use of the `the_repository` variable is deprecated nowadays, and we
slowly but steadily convert the codebase to not use it anymore. Instead,
callers should be passing down the repository to work on via parameters.
It is hard though to prove that a given code unit does not use this
variable anymore. The most trivial case, merely demonstrating that there
is no direct use of `the_repository`, is already a bit of a pain during
code reviews as the reviewer needs to manually verify claims made by the
patch author. The bigger problem though is that we have many interfaces
that implicitly rely on `the_repository`.
Introduce a new `USE_THE_REPOSITORY_VARIABLE` macro that allows code
units to opt into usage of `the_repository`. The intent of this macro is
to demonstrate that a certain code unit does not use this variable
anymore, and to keep it from new dependencies on it in future changes,
be it explicit or implicit
For now, the macro only guards `the_repository` itself as well as
`the_hash_algo`. There are many more known interfaces where we have an
implicit dependency on `the_repository`, but those are not guarded at
the current point in time. Over time though, we should start to add
guards as required (or even better, just remove them).
Define the macro as required in our code units. As expected, most of our
code still relies on the global variable. Nearly all of our builtins
rely on the variable as there is no way yet to pass `the_repository` to
their entry point. For now, declare the macro in "biultin.h" to keep the
required changes at least a little bit more contained.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-06-14 14:50:23 +08:00
|
|
|
#define USE_THE_REPOSITORY_VARIABLE
|
|
|
|
|
2023-03-21 14:26:06 +08:00
|
|
|
#include "git-compat-util.h"
|
2023-03-21 14:25:58 +08:00
|
|
|
#include "abspath.h"
|
2023-03-21 14:26:03 +08:00
|
|
|
#include "environment.h"
|
2023-03-21 14:25:54 +08:00
|
|
|
#include "gettext.h"
|
2023-05-16 14:33:59 +08:00
|
|
|
#include "path.h"
|
2017-06-23 02:43:37 +08:00
|
|
|
#include "repository.h"
|
2015-10-02 19:55:31 +08:00
|
|
|
#include "refs.h"
|
2023-03-21 14:26:05 +08:00
|
|
|
#include "setup.h"
|
2015-10-02 19:55:31 +08:00
|
|
|
#include "strbuf.h"
|
|
|
|
#include "worktree.h"
|
2016-04-22 21:01:28 +08:00
|
|
|
#include "dir.h"
|
2016-04-22 21:01:33 +08:00
|
|
|
#include "wt-status.h"
|
2022-02-08 05:32:59 +08:00
|
|
|
#include "config.h"
|
2015-10-02 19:55:31 +08:00
|
|
|
|
2024-01-08 18:05:43 +08:00
|
|
|
void free_worktree(struct worktree *worktree)
|
|
|
|
{
|
|
|
|
if (!worktree)
|
|
|
|
return;
|
|
|
|
free(worktree->path);
|
|
|
|
free(worktree->id);
|
|
|
|
free(worktree->head_ref);
|
|
|
|
free(worktree->lock_reason);
|
|
|
|
free(worktree->prune_reason);
|
|
|
|
free(worktree);
|
|
|
|
}
|
|
|
|
|
2015-10-09 01:01:03 +08:00
|
|
|
void free_worktrees(struct worktree **worktrees)
|
|
|
|
{
|
|
|
|
int i = 0;
|
2024-01-08 18:05:43 +08:00
|
|
|
for (i = 0; worktrees[i]; i++)
|
|
|
|
free_worktree(worktrees[i]);
|
2015-10-09 01:01:03 +08:00
|
|
|
free (worktrees);
|
|
|
|
}
|
|
|
|
|
2015-10-09 01:01:04 +08:00
|
|
|
/**
|
2020-09-27 21:15:45 +08:00
|
|
|
* Update head_oid, head_ref and is_detached of the given worktree
|
2015-10-09 01:01:04 +08:00
|
|
|
*/
|
2017-04-24 18:01:23 +08:00
|
|
|
static void add_head_info(struct worktree *wt)
|
2015-10-09 01:01:04 +08:00
|
|
|
{
|
2017-04-24 18:01:23 +08:00
|
|
|
int flags;
|
|
|
|
const char *target;
|
|
|
|
|
2021-10-16 17:39:27 +08:00
|
|
|
target = refs_resolve_ref_unsafe(get_worktree_ref_store(wt),
|
2017-04-24 18:01:23 +08:00
|
|
|
"HEAD",
|
branch: fix branch renaming not updating HEADs correctly
There are two bugs that sort of work together and cause
problems. Let's start with one in replace_each_worktree_head_symref.
Before fa099d2322 (worktree.c: kill parse_ref() in favor of
refs_resolve_ref_unsafe() - 2017-04-24), this code looks like this:
if (strcmp(oldref, worktrees[i]->head_ref))
continue;
set_worktree_head_symref(...);
After fa099d2322, it is possible that head_ref can be NULL. However,
the updated code takes the wrong exit. In the error case (NULL
head_ref), we should "continue;" to the next worktree. The updated
code makes us _skip_ "continue;" and update HEAD anyway.
The NULL head_ref is triggered by the second bug in add_head_info (in
the same commit). With the flag RESOLVE_REF_READING, resolve_ref_unsafe()
will abort if it cannot resolve the target ref. For orphan checkouts,
HEAD always points to an unborned branch, resolving target ref will
always fail. Now we have NULL head_ref. Now we always update HEAD.
Correct the logic in replace_ function so that we don't accidentally
update HEAD on error. As it turns out, correcting the logic bug above
breaks branch renaming completely, thanks to the second bug.
"git branch -[Mm]" does two steps (on a normal checkout, no orphan!):
- rename the branch on disk (e.g. refs/heads/abc to refs/heads/def)
- update HEAD if it points to the branch being renamed.
At the second step, since the branch pointed to by HEAD (e.g. "abc") no
longer exists on disk, we run into a temporary orphan checkout situation
that has been just corrected to _not_ update HEAD. But we need to update
HEAD since it's not actually an orphan checkout. We need to update HEAD
to move out of that orphan state.
Correct add_head_info(), remove RESOLVE_REF_READING flag. With the flag
gone, we should always return good "head_ref" in orphan checkouts (either
temporary or permanent). With good head_ref, things start to work again.
Noticed-by: Nish Aravamudan <nish.aravamudan@canonical.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-08-24 18:41:24 +08:00
|
|
|
0,
|
2022-01-26 22:37:01 +08:00
|
|
|
&wt->head_oid, &flags);
|
2017-04-24 18:01:23 +08:00
|
|
|
if (!target)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (flags & REF_ISSYMREF)
|
|
|
|
wt->head_ref = xstrdup(target);
|
|
|
|
else
|
|
|
|
wt->is_detached = 1;
|
2015-10-09 01:01:04 +08:00
|
|
|
}
|
|
|
|
|
2024-06-06 13:29:34 +08:00
|
|
|
static int is_current_worktree(struct worktree *wt)
|
|
|
|
{
|
2024-09-12 19:29:24 +08:00
|
|
|
char *git_dir = absolute_pathdup(repo_get_git_dir(the_repository));
|
2024-06-06 13:29:34 +08:00
|
|
|
const char *wt_git_dir = get_worktree_git_dir(wt);
|
|
|
|
int is_current = !fspathcmp(git_dir, absolute_path(wt_git_dir));
|
|
|
|
free(git_dir);
|
|
|
|
return is_current;
|
|
|
|
}
|
|
|
|
|
2015-10-09 01:01:03 +08:00
|
|
|
/**
|
|
|
|
* get the main worktree
|
|
|
|
*/
|
2023-12-29 15:26:30 +08:00
|
|
|
static struct worktree *get_main_worktree(int skip_reading_head)
|
2015-10-09 01:01:02 +08:00
|
|
|
{
|
2015-10-09 01:01:03 +08:00
|
|
|
struct worktree *worktree = NULL;
|
|
|
|
struct strbuf worktree_path = STRBUF_INIT;
|
2015-10-09 01:01:02 +08:00
|
|
|
|
2024-09-12 19:29:27 +08:00
|
|
|
strbuf_add_real_path(&worktree_path, repo_get_common_dir(the_repository));
|
worktree: retire special-case normalization of main worktree path
In order for "git-worktree list" to present consistent results,
get_main_worktree() performs manual normalization on the repository
path (returned by get_common_dir()) after passing it through
strbuf_add_absolute_path(). In particular, it cleans up the path for
three distinct cases when the current working directory is (1) the main
worktree, (2) the .git/ subdirectory, or (3) a bare repository.
The need for such special-cases is a direct consequence of employing
strbuf_add_absolute_path() which, for the sake of efficiency, doesn't
bother normalizing the path (such as folding out redundant path
components) after making it absolute. Lack of normalization is not
typically a problem since redundant path elements make no difference
when working with paths at the filesystem level. However, when preparing
paths for presentation, possible redundant path components make it
difficult to ensure consistency.
Eliminate the need for these special cases by instead making the path
absolute via strbuf_add_real_path() which normalizes the path for us.
Once normalized, the only case we need to handle manually is converting
it to the path of the main worktree by stripping the "/.git" suffix.
This stripping of the "/.git" suffix is a regular idiom in
worktree-related code; for instance, it is employed by
get_linked_worktree(), as well.
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-08-01 07:32:14 +08:00
|
|
|
strbuf_strip_suffix(&worktree_path, "/.git");
|
2015-10-09 01:01:03 +08:00
|
|
|
|
2021-03-14 00:17:22 +08:00
|
|
|
CALLOC_ARRAY(worktree, 1);
|
2024-05-17 16:18:44 +08:00
|
|
|
worktree->repo = the_repository;
|
2015-10-09 01:01:04 +08:00
|
|
|
worktree->path = strbuf_detach(&worktree_path, NULL);
|
worktree: update is_bare heuristics
When "git branch -D <name>" is run, Git usually first checks if that
branch is currently checked out. But this check is not performed if the
Git directory of that repository is not at "<repo>/.git", which is the
case if that repository is a submodule that has its Git directory stored
as "super/.git/modules/<repo>", for example. This results in the branch
being deleted even though it is checked out.
This is because get_main_worktree() in worktree.c sets is_bare on a
worktree only using the heuristic that a repo is bare if the worktree's
path does not end in "/.git", and not bare otherwise. This is_bare code
was introduced in 92718b7438 ("worktree: add details to the worktree
struct", 2015-10-08), following a pre-core.bare heuristic. This patch
does 2 things:
- Teach get_main_worktree() to use is_bare_repository() instead,
introduced in 7d1864ce67 ("Introduce is_bare_repository() and
core.bare configuration variable", 2007-01-07) and updated in
e90fdc39b6 ("Clean up work-tree handling", 2007-08-01). This solves
the "git branch -D <name>" problem described above. However...
- If a repository has core.bare=1 but the "git" command is being run
from one of its secondary worktrees, is_bare_repository() returns
false (which is fine, since there is a worktree available). However,
treating the main worktree as non-bare when it is bare causes issues:
for example, failure to delete a branch from a secondary worktree
that is referred to by a main worktree's HEAD, even if that main
worktree is bare.
In order to avoid that, also check core.bare when setting is_bare. If
core.bare=1, trust it, and otherwise, use is_bare_repository().
Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-20 01:21:28 +08:00
|
|
|
/*
|
|
|
|
* NEEDSWORK: If this function is called from a secondary worktree and
|
|
|
|
* config.worktree is present, is_bare_repository_cfg will reflect the
|
|
|
|
* contents of config.worktree, not the contents of the main worktree.
|
|
|
|
* This means that worktree->is_bare may be set to 0 even if the main
|
|
|
|
* worktree is configured to be bare.
|
|
|
|
*/
|
|
|
|
worktree->is_bare = (is_bare_repository_cfg == 1) ||
|
|
|
|
is_bare_repository();
|
2024-06-06 13:29:34 +08:00
|
|
|
worktree->is_current = is_current_worktree(worktree);
|
2023-12-29 15:26:30 +08:00
|
|
|
if (!skip_reading_head)
|
|
|
|
add_head_info(worktree);
|
2015-10-09 01:01:03 +08:00
|
|
|
return worktree;
|
2015-10-09 01:01:02 +08:00
|
|
|
}
|
|
|
|
|
2024-01-08 18:05:43 +08:00
|
|
|
struct worktree *get_linked_worktree(const char *id,
|
|
|
|
int skip_reading_head)
|
2015-10-02 19:55:31 +08:00
|
|
|
{
|
2015-10-09 01:01:03 +08:00
|
|
|
struct worktree *worktree = NULL;
|
2015-10-02 19:55:31 +08:00
|
|
|
struct strbuf path = STRBUF_INIT;
|
2015-10-09 01:01:03 +08:00
|
|
|
struct strbuf worktree_path = STRBUF_INIT;
|
2015-10-02 19:55:31 +08:00
|
|
|
|
2015-10-09 01:01:02 +08:00
|
|
|
if (!id)
|
|
|
|
die("Missing linked worktree name");
|
2015-10-02 19:55:31 +08:00
|
|
|
|
2017-06-23 02:43:37 +08:00
|
|
|
strbuf_git_common_path(&path, the_repository, "worktrees/%s/gitdir", id);
|
2015-10-09 01:01:03 +08:00
|
|
|
if (strbuf_read_file(&worktree_path, path.buf, 0) <= 0)
|
|
|
|
/* invalid gitdir file */
|
2015-10-02 19:55:31 +08:00
|
|
|
goto done;
|
2015-10-09 01:01:03 +08:00
|
|
|
strbuf_rtrim(&worktree_path);
|
worktree: drop bogus and unnecessary path munging
The content of .git/worktrees/<id>/gitdir must be a path of the form
"/path/to/worktree/.git". Any other content would be indicative of a
corrupt "gitdir" file. To determine the path of the worktree itself one
merely strips the "/.git" suffix, and this is indeed how the worktree
path was determined from inception.
However, 5193490442 (worktree: add a function to get worktree details,
2015-10-08) extended the path manipulation in a mysterious way. If it is
unable to strip "/.git" from the path, then it instead reports the
current working directory as the linked worktree's path:
if (!strbuf_strip_suffix(&worktree_path, "/.git")) {
strbuf_reset(&worktree_path);
strbuf_add_absolute_path(&worktree_path, ".");
strbuf_strip_suffix(&worktree_path, "/.");
}
This logic is clearly bogus; it can never be generally correct behavior.
It materialized out of thin air in 5193490442 with neither explanation
nor tests to illustrate a case in which it would be desirable.
It's possible that this logic was introduced to somehow deal with a
corrupt "gitdir" file, so that it returns _some_ sort of meaningful
value, but returning the current working directory is not helpful. In
fact, it is quite misleading (except in the one specific case when the
current directory is the worktree whose "gitdir" entry is corrupt).
Moreover, reporting the corrupt value to the user, rather than fibbing
about it and hiding it outright, is more helpful since it may aid in
diagnosing the problem.
Therefore, drop this bogus path munging and restore the logic to the
original behavior of merely stripping "/.git".
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-08-01 07:32:13 +08:00
|
|
|
strbuf_strip_suffix(&worktree_path, "/.git");
|
2015-10-09 01:01:03 +08:00
|
|
|
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
if (!is_absolute_path(worktree_path.buf)) {
|
|
|
|
strbuf_strip_suffix(&path, "gitdir");
|
|
|
|
strbuf_addbuf(&path, &worktree_path);
|
|
|
|
strbuf_realpath_forgiving(&worktree_path, path.buf, 0);
|
|
|
|
}
|
|
|
|
|
2021-03-14 00:17:22 +08:00
|
|
|
CALLOC_ARRAY(worktree, 1);
|
2024-05-17 16:18:44 +08:00
|
|
|
worktree->repo = the_repository;
|
2015-10-09 01:01:04 +08:00
|
|
|
worktree->path = strbuf_detach(&worktree_path, NULL);
|
2016-04-22 21:01:26 +08:00
|
|
|
worktree->id = xstrdup(id);
|
2024-06-06 13:29:34 +08:00
|
|
|
worktree->is_current = is_current_worktree(worktree);
|
2023-12-29 15:26:30 +08:00
|
|
|
if (!skip_reading_head)
|
|
|
|
add_head_info(worktree);
|
2015-10-02 19:55:31 +08:00
|
|
|
|
|
|
|
done:
|
|
|
|
strbuf_release(&path);
|
2015-10-09 01:01:03 +08:00
|
|
|
strbuf_release(&worktree_path);
|
|
|
|
return worktree;
|
2015-10-02 19:55:31 +08:00
|
|
|
}
|
|
|
|
|
2023-12-29 15:26:30 +08:00
|
|
|
/*
|
|
|
|
* NEEDSWORK: This function exists so that we can look up metadata of a
|
|
|
|
* worktree without trying to access any of its internals like the refdb. It
|
|
|
|
* would be preferable to instead have a corruption-tolerant function for
|
|
|
|
* retrieving worktree metadata that could be used when the worktree is known
|
|
|
|
* to not be in a healthy state, e.g. when creating or repairing it.
|
|
|
|
*/
|
|
|
|
static struct worktree **get_worktrees_internal(int skip_reading_head)
|
2015-10-02 19:55:31 +08:00
|
|
|
{
|
2015-10-09 01:01:03 +08:00
|
|
|
struct worktree **list = NULL;
|
2015-10-02 19:55:31 +08:00
|
|
|
struct strbuf path = STRBUF_INIT;
|
|
|
|
DIR *dir;
|
|
|
|
struct dirent *d;
|
2015-10-09 01:01:03 +08:00
|
|
|
int counter = 0, alloc = 2;
|
|
|
|
|
2017-02-25 18:30:03 +08:00
|
|
|
ALLOC_ARRAY(list, alloc);
|
2015-10-02 19:55:31 +08:00
|
|
|
|
2023-12-29 15:26:30 +08:00
|
|
|
list[counter++] = get_main_worktree(skip_reading_head);
|
2015-10-02 19:55:31 +08:00
|
|
|
|
2024-09-12 19:29:27 +08:00
|
|
|
strbuf_addf(&path, "%s/worktrees", repo_get_common_dir(the_repository));
|
2015-10-02 19:55:31 +08:00
|
|
|
dir = opendir(path.buf);
|
|
|
|
strbuf_release(&path);
|
2015-10-09 01:01:03 +08:00
|
|
|
if (dir) {
|
2021-05-13 01:28:22 +08:00
|
|
|
while ((d = readdir_skip_dot_and_dotdot(dir)) != NULL) {
|
2015-10-09 01:01:03 +08:00
|
|
|
struct worktree *linked = NULL;
|
2015-10-02 19:55:31 +08:00
|
|
|
|
2023-12-29 15:26:30 +08:00
|
|
|
if ((linked = get_linked_worktree(d->d_name, skip_reading_head))) {
|
2016-01-18 19:21:29 +08:00
|
|
|
ALLOC_GROW(list, counter + 1, alloc);
|
|
|
|
list[counter++] = linked;
|
|
|
|
}
|
2015-10-09 01:01:03 +08:00
|
|
|
}
|
|
|
|
closedir(dir);
|
|
|
|
}
|
|
|
|
ALLOC_GROW(list, counter + 1, alloc);
|
|
|
|
list[counter] = NULL;
|
2016-04-22 21:01:28 +08:00
|
|
|
|
2015-10-09 01:01:03 +08:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2023-12-29 15:26:30 +08:00
|
|
|
struct worktree **get_worktrees(void)
|
|
|
|
{
|
|
|
|
return get_worktrees_internal(0);
|
|
|
|
}
|
|
|
|
|
2016-04-22 21:01:26 +08:00
|
|
|
const char *get_worktree_git_dir(const struct worktree *wt)
|
|
|
|
{
|
|
|
|
if (!wt)
|
2024-09-12 19:29:24 +08:00
|
|
|
return repo_get_git_dir(the_repository);
|
2016-04-22 21:01:26 +08:00
|
|
|
else if (!wt->id)
|
2024-09-12 19:29:27 +08:00
|
|
|
return repo_get_common_dir(the_repository);
|
2016-04-22 21:01:26 +08:00
|
|
|
else
|
|
|
|
return git_common_path("worktrees/%s", wt->id);
|
|
|
|
}
|
|
|
|
|
2016-06-13 20:18:26 +08:00
|
|
|
static struct worktree *find_worktree_by_suffix(struct worktree **list,
|
|
|
|
const char *suffix)
|
|
|
|
{
|
|
|
|
struct worktree *found = NULL;
|
|
|
|
int nr_found = 0, suffixlen;
|
|
|
|
|
|
|
|
suffixlen = strlen(suffix);
|
|
|
|
if (!suffixlen)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (; *list && nr_found < 2; list++) {
|
|
|
|
const char *path = (*list)->path;
|
|
|
|
int pathlen = strlen(path);
|
|
|
|
int start = pathlen - suffixlen;
|
|
|
|
|
|
|
|
/* suffix must start at directory boundary */
|
|
|
|
if ((!start || (start > 0 && is_dir_sep(path[start - 1]))) &&
|
|
|
|
!fspathcmp(suffix, path + start)) {
|
|
|
|
found = *list;
|
|
|
|
nr_found++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nr_found == 1 ? found : NULL;
|
|
|
|
}
|
|
|
|
|
2016-06-03 20:19:39 +08:00
|
|
|
struct worktree *find_worktree(struct worktree **list,
|
|
|
|
const char *prefix,
|
|
|
|
const char *arg)
|
|
|
|
{
|
2016-06-13 20:18:26 +08:00
|
|
|
struct worktree *wt;
|
2017-03-21 09:28:49 +08:00
|
|
|
char *to_free = NULL;
|
2016-06-03 20:19:39 +08:00
|
|
|
|
2016-06-13 20:18:26 +08:00
|
|
|
if ((wt = find_worktree_by_suffix(list, arg)))
|
|
|
|
return wt;
|
|
|
|
|
2017-03-21 09:28:49 +08:00
|
|
|
if (prefix)
|
|
|
|
arg = to_free = prefix_filename(prefix, arg);
|
2020-02-24 17:08:47 +08:00
|
|
|
wt = find_worktree_by_path(list, arg);
|
|
|
|
free(to_free);
|
|
|
|
return wt;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct worktree *find_worktree_by_path(struct worktree **list, const char *p)
|
|
|
|
{
|
2020-03-10 21:11:23 +08:00
|
|
|
struct strbuf wt_path = STRBUF_INIT;
|
2020-02-24 17:08:47 +08:00
|
|
|
char *path = real_pathdup(p, 0);
|
|
|
|
|
|
|
|
if (!path)
|
2018-08-29 05:20:18 +08:00
|
|
|
return NULL;
|
2019-05-13 18:49:44 +08:00
|
|
|
for (; *list; list++) {
|
2020-03-10 21:11:23 +08:00
|
|
|
if (!strbuf_realpath(&wt_path, (*list)->path, 0))
|
|
|
|
continue;
|
2019-05-13 18:49:44 +08:00
|
|
|
|
2020-03-10 21:11:23 +08:00
|
|
|
if (!fspathcmp(path, wt_path.buf))
|
2016-06-03 20:19:39 +08:00
|
|
|
break;
|
2019-05-13 18:49:44 +08:00
|
|
|
}
|
2016-06-03 20:19:39 +08:00
|
|
|
free(path);
|
2020-03-10 21:11:23 +08:00
|
|
|
strbuf_release(&wt_path);
|
2016-06-03 20:19:39 +08:00
|
|
|
return *list;
|
|
|
|
}
|
|
|
|
|
2016-06-03 20:19:40 +08:00
|
|
|
int is_main_worktree(const struct worktree *wt)
|
|
|
|
{
|
|
|
|
return !wt->id;
|
|
|
|
}
|
|
|
|
|
2018-10-30 14:24:09 +08:00
|
|
|
const char *worktree_lock_reason(struct worktree *wt)
|
2016-06-13 20:18:23 +08:00
|
|
|
{
|
2021-01-20 05:27:35 +08:00
|
|
|
if (is_main_worktree(wt))
|
|
|
|
return NULL;
|
2016-06-13 20:18:23 +08:00
|
|
|
|
|
|
|
if (!wt->lock_reason_valid) {
|
|
|
|
struct strbuf path = STRBUF_INIT;
|
|
|
|
|
2024-08-13 17:13:37 +08:00
|
|
|
strbuf_addstr(&path, worktree_git_path(the_repository, wt, "locked"));
|
2016-06-13 20:18:23 +08:00
|
|
|
if (file_exists(path.buf)) {
|
|
|
|
struct strbuf lock_reason = STRBUF_INIT;
|
|
|
|
if (strbuf_read_file(&lock_reason, path.buf, 0) < 0)
|
|
|
|
die_errno(_("failed to read '%s'"), path.buf);
|
|
|
|
strbuf_trim(&lock_reason);
|
|
|
|
wt->lock_reason = strbuf_detach(&lock_reason, NULL);
|
|
|
|
} else
|
|
|
|
wt->lock_reason = NULL;
|
|
|
|
wt->lock_reason_valid = 1;
|
|
|
|
strbuf_release(&path);
|
|
|
|
}
|
|
|
|
|
|
|
|
return wt->lock_reason;
|
|
|
|
}
|
|
|
|
|
2021-01-20 05:27:34 +08:00
|
|
|
const char *worktree_prune_reason(struct worktree *wt, timestamp_t expire)
|
|
|
|
{
|
|
|
|
struct strbuf reason = STRBUF_INIT;
|
|
|
|
char *path = NULL;
|
|
|
|
|
|
|
|
if (is_main_worktree(wt))
|
|
|
|
return NULL;
|
|
|
|
if (wt->prune_reason_valid)
|
|
|
|
return wt->prune_reason;
|
|
|
|
|
|
|
|
if (should_prune_worktree(wt->id, &reason, &path, expire))
|
|
|
|
wt->prune_reason = strbuf_detach(&reason, NULL);
|
|
|
|
wt->prune_reason_valid = 1;
|
|
|
|
|
|
|
|
strbuf_release(&reason);
|
|
|
|
free(path);
|
|
|
|
return wt->prune_reason;
|
|
|
|
}
|
|
|
|
|
2018-01-24 17:53:51 +08:00
|
|
|
/* convenient wrapper to deal with NULL strbuf */
|
2021-07-13 16:05:18 +08:00
|
|
|
__attribute__((format (printf, 2, 3)))
|
2018-01-24 17:53:51 +08:00
|
|
|
static void strbuf_addf_gently(struct strbuf *buf, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list params;
|
|
|
|
|
|
|
|
if (!buf)
|
|
|
|
return;
|
|
|
|
|
|
|
|
va_start(params, fmt);
|
|
|
|
strbuf_vaddf(buf, fmt, params);
|
|
|
|
va_end(params);
|
|
|
|
}
|
|
|
|
|
2018-02-12 17:49:40 +08:00
|
|
|
int validate_worktree(const struct worktree *wt, struct strbuf *errmsg,
|
|
|
|
unsigned flags)
|
2018-01-24 17:53:51 +08:00
|
|
|
{
|
|
|
|
struct strbuf wt_path = STRBUF_INIT;
|
2020-03-10 21:11:22 +08:00
|
|
|
struct strbuf realpath = STRBUF_INIT;
|
2018-01-24 17:53:51 +08:00
|
|
|
char *path = NULL;
|
|
|
|
int err, ret = -1;
|
|
|
|
|
|
|
|
strbuf_addf(&wt_path, "%s/.git", wt->path);
|
|
|
|
|
|
|
|
if (is_main_worktree(wt)) {
|
|
|
|
if (is_directory(wt_path.buf)) {
|
|
|
|
ret = 0;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Main worktree using .git file to point to the
|
|
|
|
* repository would make it impossible to know where
|
|
|
|
* the actual worktree is if this function is executed
|
|
|
|
* from another worktree. No .git file support for now.
|
|
|
|
*/
|
|
|
|
strbuf_addf_gently(errmsg,
|
|
|
|
_("'%s' at main working tree is not the repository directory"),
|
|
|
|
wt_path.buf);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure "gitdir" file points to a real .git file and that
|
|
|
|
* file points back here.
|
|
|
|
*/
|
|
|
|
if (!is_absolute_path(wt->path)) {
|
|
|
|
strbuf_addf_gently(errmsg,
|
|
|
|
_("'%s' file does not contain absolute path to the working tree location"),
|
|
|
|
git_common_path("worktrees/%s/gitdir", wt->id));
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2018-02-12 17:49:40 +08:00
|
|
|
if (flags & WT_VALIDATE_WORKTREE_MISSING_OK &&
|
|
|
|
!file_exists(wt->path)) {
|
|
|
|
ret = 0;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2018-01-24 17:53:51 +08:00
|
|
|
if (!file_exists(wt_path.buf)) {
|
|
|
|
strbuf_addf_gently(errmsg, _("'%s' does not exist"), wt_path.buf);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
path = xstrdup_or_null(read_gitfile_gently(wt_path.buf, &err));
|
|
|
|
if (!path) {
|
|
|
|
strbuf_addf_gently(errmsg, _("'%s' is not a .git file, error code %d"),
|
|
|
|
wt_path.buf, err);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2020-03-10 21:11:22 +08:00
|
|
|
strbuf_realpath(&realpath, git_common_path("worktrees/%s", wt->id), 1);
|
|
|
|
ret = fspathcmp(path, realpath.buf);
|
2018-01-24 17:53:51 +08:00
|
|
|
|
|
|
|
if (ret)
|
|
|
|
strbuf_addf_gently(errmsg, _("'%s' does not point back to '%s'"),
|
|
|
|
wt->path, git_common_path("worktrees/%s", wt->id));
|
|
|
|
done:
|
|
|
|
free(path);
|
|
|
|
strbuf_release(&wt_path);
|
2020-03-10 21:11:22 +08:00
|
|
|
strbuf_release(&realpath);
|
2018-01-24 17:53:51 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-02-12 17:49:35 +08:00
|
|
|
void update_worktree_location(struct worktree *wt, const char *path_)
|
|
|
|
{
|
|
|
|
struct strbuf path = STRBUF_INIT;
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
struct strbuf repo = STRBUF_INIT;
|
|
|
|
struct strbuf file = STRBUF_INIT;
|
|
|
|
struct strbuf tmp = STRBUF_INIT;
|
2018-02-12 17:49:35 +08:00
|
|
|
|
|
|
|
if (is_main_worktree(wt))
|
2018-05-02 17:38:39 +08:00
|
|
|
BUG("can't relocate main worktree");
|
2018-02-12 17:49:35 +08:00
|
|
|
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
|
2018-02-12 17:49:35 +08:00
|
|
|
strbuf_realpath(&path, path_, 1);
|
|
|
|
if (fspathcmp(wt->path, path.buf)) {
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
strbuf_addf(&file, "%s/gitdir", repo.buf);
|
|
|
|
write_file(file.buf, "%s/.git", relative_path(path.buf, repo.buf, &tmp));
|
|
|
|
strbuf_reset(&file);
|
|
|
|
strbuf_addf(&file, "%s/.git", path.buf);
|
|
|
|
write_file(file.buf, "gitdir: %s", relative_path(repo.buf, path.buf, &tmp));
|
|
|
|
|
2018-02-12 17:49:35 +08:00
|
|
|
free(wt->path);
|
|
|
|
wt->path = strbuf_detach(&path, NULL);
|
|
|
|
}
|
|
|
|
strbuf_release(&path);
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
strbuf_release(&repo);
|
|
|
|
strbuf_release(&file);
|
|
|
|
strbuf_release(&tmp);
|
2018-02-12 17:49:35 +08:00
|
|
|
}
|
|
|
|
|
2016-04-22 21:01:36 +08:00
|
|
|
int is_worktree_being_rebased(const struct worktree *wt,
|
|
|
|
const char *target)
|
2016-04-22 21:01:33 +08:00
|
|
|
{
|
|
|
|
struct wt_status_state state;
|
|
|
|
int found_rebase;
|
|
|
|
|
|
|
|
memset(&state, 0, sizeof(state));
|
|
|
|
found_rebase = wt_status_check_rebase(wt, &state) &&
|
2020-09-27 21:15:47 +08:00
|
|
|
(state.rebase_in_progress ||
|
|
|
|
state.rebase_interactive_in_progress) &&
|
|
|
|
state.branch &&
|
|
|
|
skip_prefix(target, "refs/heads/", &target) &&
|
|
|
|
!strcmp(state.branch, target);
|
wt-status: introduce wt_status_state_free_buffers()
When we have a `struct wt_status_state`, we manually free its `branch`,
`onto` and `detached_from`, or sometimes just one or two of them.
Provide a function `wt_status_state_free_buffers()` which does the
freeing.
The callers are still aware of these fields, e.g., they check whether
`branch` was populated or not. But this way, they don't need to know
about *all* of them, and if `struct wt_status_state` gets more fields,
they will not need to learn to free them.
Users of `struct wt_status` (which contains a `wt_status_state`) already
have `wt_status_collect_free_buffers()` (corresponding to
`wt_status_collect()`) which we can also teach to use this new helper.
Finally, note that we're currently leaving dangling pointers behind.
Some callers work on a stack-allocated struct, where this is obviously
ok. But for the users of `run_status()` in builtin/commit.c, there are
ample opportunities for someone to mistakenly use those dangling
pointers. We seem to be ok for now, but it's a use-after-free waiting to
happen. Let's leave NULL-pointers behind instead.
Signed-off-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-09-27 21:15:43 +08:00
|
|
|
wt_status_state_free_buffers(&state);
|
2016-04-22 21:01:33 +08:00
|
|
|
return found_rebase;
|
|
|
|
}
|
|
|
|
|
2016-04-22 21:01:36 +08:00
|
|
|
int is_worktree_being_bisected(const struct worktree *wt,
|
|
|
|
const char *target)
|
2015-10-09 01:01:03 +08:00
|
|
|
{
|
2016-04-22 21:01:35 +08:00
|
|
|
struct wt_status_state state;
|
2020-09-27 21:15:46 +08:00
|
|
|
int found_bisect;
|
2016-04-22 21:01:35 +08:00
|
|
|
|
|
|
|
memset(&state, 0, sizeof(state));
|
2020-09-27 21:15:46 +08:00
|
|
|
found_bisect = wt_status_check_bisect(wt, &state) &&
|
status: fix branch shown when not only bisecting
In 83c750acde (wt-status.*: better advice for git status added,
2012-06-05), git-status received new informative messages to describe
the ongoing work in a worktree.
These messages were enhanced in 0722c805d6 (status: show the branch name
if possible in in-progress info, 2013-02-03), to show, if possible, the
branch where the operation was initiated.
Since then, we show incorrect information when several operations are in
progress and one of them is bisect:
$ git checkout -b foo
$ GIT_SEQUENCE_EDITOR='echo break >' git rebase -i HEAD~
$ git checkout -b bar
$ git bisect start
$ git status
...
You are currently editing a commit while rebasing branch 'bar' on '...'.
You are currently bisecting, started from branch 'bar'.
...
Note that we erroneously say "while rebasing branch 'bar'" when we
should be referring to "foo".
This must have gone unnoticed for so long because it must be unusual to
start a bisection while another operation is in progress. And even less
usual to involve different branches.
It caught my attention reviewing a leak introduced in 8b87cfd000
(wt-status: move strbuf into read_and_strip_branch(), 2013-03-16).
A simple change to deal with this situation can be to record in struct
wt_status_state, the branch where the bisect starts separately from the
branch related to other operations.
Let's do it and so we'll be able to display correct information and
we'll avoid the leak as well.
Signed-off-by: Rubén Justo <rjusto@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-09-10 04:12:47 +08:00
|
|
|
state.bisecting_from &&
|
2020-09-27 21:15:47 +08:00
|
|
|
skip_prefix(target, "refs/heads/", &target) &&
|
status: fix branch shown when not only bisecting
In 83c750acde (wt-status.*: better advice for git status added,
2012-06-05), git-status received new informative messages to describe
the ongoing work in a worktree.
These messages were enhanced in 0722c805d6 (status: show the branch name
if possible in in-progress info, 2013-02-03), to show, if possible, the
branch where the operation was initiated.
Since then, we show incorrect information when several operations are in
progress and one of them is bisect:
$ git checkout -b foo
$ GIT_SEQUENCE_EDITOR='echo break >' git rebase -i HEAD~
$ git checkout -b bar
$ git bisect start
$ git status
...
You are currently editing a commit while rebasing branch 'bar' on '...'.
You are currently bisecting, started from branch 'bar'.
...
Note that we erroneously say "while rebasing branch 'bar'" when we
should be referring to "foo".
This must have gone unnoticed for so long because it must be unusual to
start a bisection while another operation is in progress. And even less
usual to involve different branches.
It caught my attention reviewing a leak introduced in 8b87cfd000
(wt-status: move strbuf into read_and_strip_branch(), 2013-03-16).
A simple change to deal with this situation can be to record in struct
wt_status_state, the branch where the bisect starts separately from the
branch related to other operations.
Let's do it and so we'll be able to display correct information and
we'll avoid the leak as well.
Signed-off-by: Rubén Justo <rjusto@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-09-10 04:12:47 +08:00
|
|
|
!strcmp(state.bisecting_from, target);
|
wt-status: introduce wt_status_state_free_buffers()
When we have a `struct wt_status_state`, we manually free its `branch`,
`onto` and `detached_from`, or sometimes just one or two of them.
Provide a function `wt_status_state_free_buffers()` which does the
freeing.
The callers are still aware of these fields, e.g., they check whether
`branch` was populated or not. But this way, they don't need to know
about *all* of them, and if `struct wt_status_state` gets more fields,
they will not need to learn to free them.
Users of `struct wt_status` (which contains a `wt_status_state`) already
have `wt_status_collect_free_buffers()` (corresponding to
`wt_status_collect()`) which we can also teach to use this new helper.
Finally, note that we're currently leaving dangling pointers behind.
Some callers work on a stack-allocated struct, where this is obviously
ok. But for the users of `run_status()` in builtin/commit.c, there are
ample opportunities for someone to mistakenly use those dangling
pointers. We seem to be ok for now, but it's a use-after-free waiting to
happen. Let's leave NULL-pointers behind instead.
Signed-off-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-09-27 21:15:43 +08:00
|
|
|
wt_status_state_free_buffers(&state);
|
2020-09-27 21:15:46 +08:00
|
|
|
return found_bisect;
|
2016-04-22 21:01:35 +08:00
|
|
|
}
|
|
|
|
|
2016-04-22 21:01:33 +08:00
|
|
|
/*
|
|
|
|
* note: this function should be able to detect shared symref even if
|
|
|
|
* HEAD is temporarily detached (e.g. in the middle of rebase or
|
|
|
|
* bisect). New commands that do similar things should update this
|
|
|
|
* function as well.
|
|
|
|
*/
|
2023-02-25 22:21:51 +08:00
|
|
|
int is_shared_symref(const struct worktree *wt, const char *symref,
|
|
|
|
const char *target)
|
2015-10-09 01:01:03 +08:00
|
|
|
{
|
2023-02-25 22:21:51 +08:00
|
|
|
const char *symref_target;
|
|
|
|
struct ref_store *refs;
|
|
|
|
int flags;
|
2015-10-09 01:01:03 +08:00
|
|
|
|
2023-02-25 22:21:51 +08:00
|
|
|
if (wt->is_bare)
|
|
|
|
return 0;
|
2017-04-24 18:01:23 +08:00
|
|
|
|
2023-02-25 22:21:51 +08:00
|
|
|
if (wt->is_detached && !strcmp(symref, "HEAD")) {
|
|
|
|
if (is_worktree_being_rebased(wt, target))
|
|
|
|
return 1;
|
|
|
|
if (is_worktree_being_bisected(wt, target))
|
|
|
|
return 1;
|
|
|
|
}
|
2016-04-22 21:01:32 +08:00
|
|
|
|
2023-02-25 22:21:51 +08:00
|
|
|
refs = get_worktree_ref_store(wt);
|
|
|
|
symref_target = refs_resolve_ref_unsafe(refs, symref, 0,
|
|
|
|
NULL, &flags);
|
|
|
|
if ((flags & REF_ISSYMREF) &&
|
|
|
|
symref_target && !strcmp(symref_target, target))
|
|
|
|
return 1;
|
2016-04-22 21:01:33 +08:00
|
|
|
|
2023-02-25 22:21:51 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct worktree *find_shared_symref(struct worktree **worktrees,
|
|
|
|
const char *symref,
|
|
|
|
const char *target)
|
|
|
|
{
|
|
|
|
|
2023-02-25 22:22:02 +08:00
|
|
|
for (int i = 0; worktrees[i]; i++)
|
2023-02-25 22:21:51 +08:00
|
|
|
if (is_shared_symref(worktrees[i], symref, target))
|
|
|
|
return worktrees[i];
|
2015-10-09 01:01:03 +08:00
|
|
|
|
2023-02-25 22:21:51 +08:00
|
|
|
return NULL;
|
2015-10-02 19:55:31 +08:00
|
|
|
}
|
2016-12-13 03:04:33 +08:00
|
|
|
|
|
|
|
int submodule_uses_worktrees(const char *path)
|
|
|
|
{
|
|
|
|
char *submodule_gitdir;
|
2020-02-23 04:17:41 +08:00
|
|
|
struct strbuf sb = STRBUF_INIT, err = STRBUF_INIT;
|
2016-12-13 03:04:33 +08:00
|
|
|
DIR *dir;
|
|
|
|
struct dirent *d;
|
2016-12-28 01:50:13 +08:00
|
|
|
int ret = 0;
|
setup: fix memory leaks with `struct repository_format`
After we set up a `struct repository_format`, it owns various pieces of
allocated memory. We then either use those members, because we decide we
want to use the "candidate" repository format, or we discard the
candidate / scratch space. In the first case, we transfer ownership of
the memory to a few global variables. In the latter case, we just
silently drop the struct and end up leaking memory.
Introduce an initialization macro `REPOSITORY_FORMAT_INIT` and a
function `clear_repository_format()`, to be used on each side of
`read_repository_format()`. To have a clear and simple memory ownership,
let all users of `struct repository_format` duplicate the strings that
they take from it, rather than stealing the pointers.
Call `clear_...()` at the start of `read_...()` instead of just zeroing
the struct, since we sometimes enter the function multiple times. Thus,
it is important to initialize the struct before calling `read_...()`, so
document that. It's also important because we might not even call
`read_...()` before we call `clear_...()`, see, e.g., builtin/init-db.c.
Teach `read_...()` to clear the struct on error, so that it is reset to
a safe state, and document this. (In `setup_git_directory_gently()`, we
look at `repo_fmt.hash_algo` even if `repo_fmt.version` is -1, which we
weren't actually supposed to do per the API. After this commit, that's
ok.)
We inherit the existing code's combining "error" and "no version found".
Both are signalled through `version == -1` and now both cause us to
clear any partial configuration we have picked up. For "extensions.*",
that's fine, since they require a positive version number. For
"core.bare" and "core.worktree", we're already verifying that we have a
non-negative version number before using them.
Signed-off-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-03-01 04:36:28 +08:00
|
|
|
struct repository_format format = REPOSITORY_FORMAT_INIT;
|
2016-12-13 03:04:33 +08:00
|
|
|
|
|
|
|
submodule_gitdir = git_pathdup_submodule(path, "%s", "");
|
|
|
|
if (!submodule_gitdir)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* The env would be set for the superproject. */
|
|
|
|
get_common_dir_noenv(&sb, submodule_gitdir);
|
2017-05-04 21:59:19 +08:00
|
|
|
free(submodule_gitdir);
|
2016-12-13 03:04:33 +08:00
|
|
|
|
|
|
|
strbuf_addstr(&sb, "/config");
|
|
|
|
read_repository_format(&format, sb.buf);
|
2020-02-23 04:17:41 +08:00
|
|
|
if (verify_repository_format(&format, &err)) {
|
|
|
|
strbuf_release(&err);
|
2016-12-13 03:04:33 +08:00
|
|
|
strbuf_release(&sb);
|
setup: fix memory leaks with `struct repository_format`
After we set up a `struct repository_format`, it owns various pieces of
allocated memory. We then either use those members, because we decide we
want to use the "candidate" repository format, or we discard the
candidate / scratch space. In the first case, we transfer ownership of
the memory to a few global variables. In the latter case, we just
silently drop the struct and end up leaking memory.
Introduce an initialization macro `REPOSITORY_FORMAT_INIT` and a
function `clear_repository_format()`, to be used on each side of
`read_repository_format()`. To have a clear and simple memory ownership,
let all users of `struct repository_format` duplicate the strings that
they take from it, rather than stealing the pointers.
Call `clear_...()` at the start of `read_...()` instead of just zeroing
the struct, since we sometimes enter the function multiple times. Thus,
it is important to initialize the struct before calling `read_...()`, so
document that. It's also important because we might not even call
`read_...()` before we call `clear_...()`, see, e.g., builtin/init-db.c.
Teach `read_...()` to clear the struct on error, so that it is reset to
a safe state, and document this. (In `setup_git_directory_gently()`, we
look at `repo_fmt.hash_algo` even if `repo_fmt.version` is -1, which we
weren't actually supposed to do per the API. After this commit, that's
ok.)
We inherit the existing code's combining "error" and "no version found".
Both are signalled through `version == -1` and now both cause us to
clear any partial configuration we have picked up. For "extensions.*",
that's fine, since they require a positive version number. For
"core.bare" and "core.worktree", we're already verifying that we have a
non-negative version number before using them.
Signed-off-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-03-01 04:36:28 +08:00
|
|
|
clear_repository_format(&format);
|
2016-12-13 03:04:33 +08:00
|
|
|
return 1;
|
|
|
|
}
|
setup: fix memory leaks with `struct repository_format`
After we set up a `struct repository_format`, it owns various pieces of
allocated memory. We then either use those members, because we decide we
want to use the "candidate" repository format, or we discard the
candidate / scratch space. In the first case, we transfer ownership of
the memory to a few global variables. In the latter case, we just
silently drop the struct and end up leaking memory.
Introduce an initialization macro `REPOSITORY_FORMAT_INIT` and a
function `clear_repository_format()`, to be used on each side of
`read_repository_format()`. To have a clear and simple memory ownership,
let all users of `struct repository_format` duplicate the strings that
they take from it, rather than stealing the pointers.
Call `clear_...()` at the start of `read_...()` instead of just zeroing
the struct, since we sometimes enter the function multiple times. Thus,
it is important to initialize the struct before calling `read_...()`, so
document that. It's also important because we might not even call
`read_...()` before we call `clear_...()`, see, e.g., builtin/init-db.c.
Teach `read_...()` to clear the struct on error, so that it is reset to
a safe state, and document this. (In `setup_git_directory_gently()`, we
look at `repo_fmt.hash_algo` even if `repo_fmt.version` is -1, which we
weren't actually supposed to do per the API. After this commit, that's
ok.)
We inherit the existing code's combining "error" and "no version found".
Both are signalled through `version == -1` and now both cause us to
clear any partial configuration we have picked up. For "extensions.*",
that's fine, since they require a positive version number. For
"core.bare" and "core.worktree", we're already verifying that we have a
non-negative version number before using them.
Signed-off-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-03-01 04:36:28 +08:00
|
|
|
clear_repository_format(&format);
|
2020-02-23 04:17:41 +08:00
|
|
|
strbuf_release(&err);
|
2016-12-13 03:04:33 +08:00
|
|
|
|
|
|
|
/* Replace config by worktrees. */
|
|
|
|
strbuf_setlen(&sb, sb.len - strlen("config"));
|
|
|
|
strbuf_addstr(&sb, "worktrees");
|
|
|
|
|
|
|
|
/* See if there is any file inside the worktrees directory. */
|
|
|
|
dir = opendir(sb.buf);
|
|
|
|
strbuf_release(&sb);
|
|
|
|
|
|
|
|
if (!dir)
|
|
|
|
return 0;
|
|
|
|
|
2021-05-13 01:28:22 +08:00
|
|
|
d = readdir_skip_dot_and_dotdot(dir);
|
2022-05-03 00:50:37 +08:00
|
|
|
if (d)
|
2016-12-13 03:04:33 +08:00
|
|
|
ret = 1;
|
|
|
|
closedir(dir);
|
|
|
|
return ret;
|
|
|
|
}
|
2017-08-23 20:36:59 +08:00
|
|
|
|
2018-10-21 16:08:56 +08:00
|
|
|
void strbuf_worktree_ref(const struct worktree *wt,
|
|
|
|
struct strbuf *sb,
|
|
|
|
const char *refname)
|
|
|
|
{
|
2022-09-20 00:34:50 +08:00
|
|
|
if (parse_worktree_ref(refname, NULL, NULL, NULL) ==
|
|
|
|
REF_WORKTREE_CURRENT &&
|
|
|
|
wt && !wt->is_current) {
|
|
|
|
if (is_main_worktree(wt))
|
|
|
|
strbuf_addstr(sb, "main-worktree/");
|
|
|
|
else
|
|
|
|
strbuf_addf(sb, "worktrees/%s/", wt->id);
|
2018-10-21 16:08:56 +08:00
|
|
|
}
|
|
|
|
strbuf_addstr(sb, refname);
|
|
|
|
}
|
|
|
|
|
2017-08-23 20:36:59 +08:00
|
|
|
int other_head_refs(each_ref_fn fn, void *cb_data)
|
|
|
|
{
|
|
|
|
struct worktree **worktrees, **p;
|
2020-09-27 21:15:44 +08:00
|
|
|
struct strbuf refname = STRBUF_INIT;
|
2017-08-23 20:36:59 +08:00
|
|
|
int ret = 0;
|
|
|
|
|
2020-06-20 07:35:44 +08:00
|
|
|
worktrees = get_worktrees();
|
2017-08-23 20:36:59 +08:00
|
|
|
for (p = worktrees; *p; p++) {
|
|
|
|
struct worktree *wt = *p;
|
2018-10-21 16:08:56 +08:00
|
|
|
struct object_id oid;
|
|
|
|
int flag;
|
2017-08-23 20:36:59 +08:00
|
|
|
|
|
|
|
if (wt->is_current)
|
|
|
|
continue;
|
|
|
|
|
2020-09-27 21:15:44 +08:00
|
|
|
strbuf_reset(&refname);
|
|
|
|
strbuf_worktree_ref(wt, &refname, "HEAD");
|
2021-10-16 17:39:27 +08:00
|
|
|
if (refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
|
2021-10-16 17:39:14 +08:00
|
|
|
refname.buf,
|
|
|
|
RESOLVE_REF_READING,
|
2022-01-26 22:37:01 +08:00
|
|
|
&oid, &flag))
|
2024-08-09 23:37:50 +08:00
|
|
|
ret = fn(refname.buf, NULL, &oid, flag, cb_data);
|
2017-08-23 20:36:59 +08:00
|
|
|
if (ret)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
free_worktrees(worktrees);
|
2020-09-27 21:15:44 +08:00
|
|
|
strbuf_release(&refname);
|
2017-08-23 20:36:59 +08:00
|
|
|
return ret;
|
|
|
|
}
|
2020-08-31 14:57:57 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Repair worktree's /path/to/worktree/.git file if missing, corrupt, or not
|
|
|
|
* pointing at <repo>/worktrees/<id>.
|
|
|
|
*/
|
|
|
|
static void repair_gitfile(struct worktree *wt,
|
|
|
|
worktree_repair_fn fn, void *cb_data)
|
|
|
|
{
|
|
|
|
struct strbuf dotgit = STRBUF_INIT;
|
|
|
|
struct strbuf repo = STRBUF_INIT;
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
struct strbuf backlink = STRBUF_INIT;
|
|
|
|
struct strbuf tmp = STRBUF_INIT;
|
|
|
|
char *dotgit_contents = NULL;
|
2020-08-31 14:57:57 +08:00
|
|
|
const char *repair = NULL;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/* missing worktree can't be repaired */
|
|
|
|
if (!file_exists(wt->path))
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
goto done;
|
2020-08-31 14:57:57 +08:00
|
|
|
|
|
|
|
if (!is_directory(wt->path)) {
|
|
|
|
fn(1, wt->path, _("not a directory"), cb_data);
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
goto done;
|
2020-08-31 14:57:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
|
|
|
|
strbuf_addf(&dotgit, "%s/.git", wt->path);
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
dotgit_contents = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err));
|
|
|
|
|
|
|
|
if (dotgit_contents) {
|
|
|
|
if (is_absolute_path(dotgit_contents)) {
|
|
|
|
strbuf_addstr(&backlink, dotgit_contents);
|
|
|
|
} else {
|
|
|
|
strbuf_addf(&backlink, "%s/%s", wt->path, dotgit_contents);
|
|
|
|
strbuf_realpath_forgiving(&backlink, backlink.buf, 0);
|
|
|
|
}
|
|
|
|
}
|
2020-08-31 14:57:57 +08:00
|
|
|
|
|
|
|
if (err == READ_GITFILE_ERR_NOT_A_FILE)
|
|
|
|
fn(1, wt->path, _(".git is not a file"), cb_data);
|
|
|
|
else if (err)
|
|
|
|
repair = _(".git file broken");
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
else if (fspathcmp(backlink.buf, repo.buf))
|
2020-08-31 14:57:57 +08:00
|
|
|
repair = _(".git file incorrect");
|
|
|
|
|
|
|
|
if (repair) {
|
|
|
|
fn(0, wt->path, repair, cb_data);
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
write_file(dotgit.buf, "gitdir: %s", relative_path(repo.buf, wt->path, &tmp));
|
2020-08-31 14:57:57 +08:00
|
|
|
}
|
|
|
|
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
done:
|
|
|
|
free(dotgit_contents);
|
2020-08-31 14:57:57 +08:00
|
|
|
strbuf_release(&repo);
|
|
|
|
strbuf_release(&dotgit);
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
strbuf_release(&backlink);
|
|
|
|
strbuf_release(&tmp);
|
2020-08-31 14:57:57 +08:00
|
|
|
}
|
|
|
|
|
2023-08-30 07:45:31 +08:00
|
|
|
static void repair_noop(int iserr UNUSED,
|
|
|
|
const char *path UNUSED,
|
|
|
|
const char *msg UNUSED,
|
|
|
|
void *cb_data UNUSED)
|
2020-08-31 14:57:57 +08:00
|
|
|
{
|
|
|
|
/* nothing */
|
|
|
|
}
|
|
|
|
|
|
|
|
void repair_worktrees(worktree_repair_fn fn, void *cb_data)
|
|
|
|
{
|
2023-12-29 15:26:30 +08:00
|
|
|
struct worktree **worktrees = get_worktrees_internal(1);
|
2020-08-31 14:57:57 +08:00
|
|
|
struct worktree **wt = worktrees + 1; /* +1 skips main worktree */
|
|
|
|
|
|
|
|
if (!fn)
|
|
|
|
fn = repair_noop;
|
|
|
|
for (; *wt; wt++)
|
|
|
|
repair_gitfile(*wt, fn, cb_data);
|
|
|
|
free_worktrees(worktrees);
|
|
|
|
}
|
2020-08-31 14:57:58 +08:00
|
|
|
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
void repair_worktree_after_gitdir_move(struct worktree *wt, const char *old_path)
|
|
|
|
{
|
|
|
|
struct strbuf path = STRBUF_INIT;
|
|
|
|
struct strbuf repo = STRBUF_INIT;
|
|
|
|
struct strbuf gitdir = STRBUF_INIT;
|
|
|
|
struct strbuf dotgit = STRBUF_INIT;
|
|
|
|
struct strbuf olddotgit = STRBUF_INIT;
|
|
|
|
struct strbuf tmp = STRBUF_INIT;
|
|
|
|
|
|
|
|
if (is_main_worktree(wt))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
|
|
|
|
strbuf_addf(&gitdir, "%s/gitdir", repo.buf);
|
|
|
|
|
|
|
|
if (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
strbuf_rtrim(&olddotgit);
|
|
|
|
if (is_absolute_path(olddotgit.buf)) {
|
|
|
|
strbuf_addbuf(&dotgit, &olddotgit);
|
|
|
|
} else {
|
|
|
|
strbuf_addf(&dotgit, "%s/worktrees/%s/%s", old_path, wt->id, olddotgit.buf);
|
|
|
|
strbuf_realpath_forgiving(&dotgit, dotgit.buf, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!file_exists(dotgit.buf))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
strbuf_addbuf(&path, &dotgit);
|
|
|
|
strbuf_strip_suffix(&path, "/.git");
|
|
|
|
|
|
|
|
write_file(dotgit.buf, "gitdir: %s", relative_path(repo.buf, path.buf, &tmp));
|
|
|
|
write_file(gitdir.buf, "%s", relative_path(dotgit.buf, repo.buf, &tmp));
|
|
|
|
done:
|
|
|
|
strbuf_release(&path);
|
|
|
|
strbuf_release(&repo);
|
|
|
|
strbuf_release(&gitdir);
|
|
|
|
strbuf_release(&dotgit);
|
|
|
|
strbuf_release(&olddotgit);
|
|
|
|
strbuf_release(&tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void repair_worktrees_after_gitdir_move(const char *old_path)
|
|
|
|
{
|
|
|
|
struct worktree **worktrees = get_worktrees_internal(1);
|
|
|
|
struct worktree **wt = worktrees + 1; /* +1 skips main worktree */
|
|
|
|
|
|
|
|
for (; *wt; wt++)
|
|
|
|
repair_worktree_after_gitdir_move(*wt, old_path);
|
|
|
|
free_worktrees(worktrees);
|
|
|
|
}
|
|
|
|
|
2020-08-31 14:57:58 +08:00
|
|
|
static int is_main_worktree_path(const char *path)
|
|
|
|
{
|
|
|
|
struct strbuf target = STRBUF_INIT;
|
|
|
|
struct strbuf maindir = STRBUF_INIT;
|
|
|
|
int cmp;
|
|
|
|
|
|
|
|
strbuf_add_real_path(&target, path);
|
|
|
|
strbuf_strip_suffix(&target, "/.git");
|
2024-09-12 19:29:27 +08:00
|
|
|
strbuf_add_real_path(&maindir, repo_get_common_dir(the_repository));
|
2020-08-31 14:57:58 +08:00
|
|
|
strbuf_strip_suffix(&maindir, "/.git");
|
|
|
|
cmp = fspathcmp(maindir.buf, target.buf);
|
|
|
|
|
|
|
|
strbuf_release(&maindir);
|
|
|
|
strbuf_release(&target);
|
|
|
|
return !cmp;
|
|
|
|
}
|
|
|
|
|
worktree: teach `repair` to fix multi-directional breakage
`git worktree repair` knows how to repair the two-way links between the
repository and a worktree as long as a link in one or the other
direction is sound. For instance, if a linked worktree is moved (without
using `git worktree move`), repair is possible because the worktree
still knows the location of the repository even though the repository no
longer knows where the worktree is. Similarly, if the repository is
moved, repair is possible since the repository still knows the locations
of the worktrees even though the worktrees no longer know where the
repository is.
However, if both the repository and the worktrees are moved, then links
are severed in both directions, and no repair is possible. This is the
case even when the new worktree locations are specified as arguments to
`git worktree repair`. The reason for this limitation is twofold. First,
when `repair` consults the worktree's gitfile (/path/to/worktree/.git)
to determine the corresponding <repo>/worktrees/<id>/gitdir file to fix,
<repo> is the old path to the repository, thus it is unable to fix the
`gitdir` file at its new location since it doesn't know where it is.
Second, when `repair` consults <repo>/worktrees/<id>/gitdir to find the
location of the worktree's gitfile (/path/to/worktree/.git), the path
recorded in `gitdir` is the old location of the worktree's gitfile, thus
it is unable to repair the gitfile since it doesn't know where it is.
Fix these shortcomings by teaching `repair` to attempt to infer the new
location of the <repo>/worktrees/<id>/gitdir file when the location
recorded in the worktree's gitfile has become stale but the file is
otherwise well-formed. The inference is intentionally simple-minded.
For each worktree path specified as an argument, `git worktree repair`
manually reads the ".git" gitfile at that location and, if it is
well-formed, extracts the <id>. It then searches for a corresponding
<id> in <repo>/worktrees/ and, if found, concludes that there is a
reasonable match and updates <repo>/worktrees/<id>/gitdir to point at
the specified worktree path. In order for <repo> to be known, `git
worktree repair` must be run in the main worktree or bare repository.
`git worktree repair` first attempts to repair each incoming
/path/to/worktree/.git gitfile to point at the repository, and then
attempts to repair outgoing <repo>/worktrees/<id>/gitdir files to point
at the worktrees. This sequence was chosen arbitrarily when originally
implemented since the order of fixes is immaterial as long as one side
of the two-way link between the repository and a worktree is sound.
However, for this new repair technique to work, the order must be
reversed. This is because the new inference mechanism, when it is
successful, allows the outgoing <repo>/worktrees/<id>/gitdir file to be
repaired, thus fixing one side of the two-way link. Once that side is
fixed, the other side can be fixed by the existing repair mechanism,
hence the order of repairs is now significant.
Two safeguards are employed to avoid hijacking a worktree from a
different repository if the user accidentally specifies a foreign
worktree as an argument. The first, as described above, is that it
requires an <id> match between the repository and the worktree. That
itself is not foolproof for preventing hijack, so the second safeguard
is that the inference will only kick in if the worktree's
/path/to/worktree/.git gitfile does not point at a repository.
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-21 16:16:01 +08:00
|
|
|
/*
|
|
|
|
* If both the main worktree and linked worktree have been moved, then the
|
|
|
|
* gitfile /path/to/worktree/.git won't point into the repository, thus we
|
|
|
|
* won't know which <repo>/worktrees/<id>/gitdir to repair. However, we may
|
|
|
|
* be able to infer the gitdir by manually reading /path/to/worktree/.git,
|
|
|
|
* extracting the <id>, and checking if <repo>/worktrees/<id> exists.
|
|
|
|
*/
|
2024-10-08 11:12:30 +08:00
|
|
|
static int infer_backlink(const char *gitfile, struct strbuf *inferred)
|
worktree: teach `repair` to fix multi-directional breakage
`git worktree repair` knows how to repair the two-way links between the
repository and a worktree as long as a link in one or the other
direction is sound. For instance, if a linked worktree is moved (without
using `git worktree move`), repair is possible because the worktree
still knows the location of the repository even though the repository no
longer knows where the worktree is. Similarly, if the repository is
moved, repair is possible since the repository still knows the locations
of the worktrees even though the worktrees no longer know where the
repository is.
However, if both the repository and the worktrees are moved, then links
are severed in both directions, and no repair is possible. This is the
case even when the new worktree locations are specified as arguments to
`git worktree repair`. The reason for this limitation is twofold. First,
when `repair` consults the worktree's gitfile (/path/to/worktree/.git)
to determine the corresponding <repo>/worktrees/<id>/gitdir file to fix,
<repo> is the old path to the repository, thus it is unable to fix the
`gitdir` file at its new location since it doesn't know where it is.
Second, when `repair` consults <repo>/worktrees/<id>/gitdir to find the
location of the worktree's gitfile (/path/to/worktree/.git), the path
recorded in `gitdir` is the old location of the worktree's gitfile, thus
it is unable to repair the gitfile since it doesn't know where it is.
Fix these shortcomings by teaching `repair` to attempt to infer the new
location of the <repo>/worktrees/<id>/gitdir file when the location
recorded in the worktree's gitfile has become stale but the file is
otherwise well-formed. The inference is intentionally simple-minded.
For each worktree path specified as an argument, `git worktree repair`
manually reads the ".git" gitfile at that location and, if it is
well-formed, extracts the <id>. It then searches for a corresponding
<id> in <repo>/worktrees/ and, if found, concludes that there is a
reasonable match and updates <repo>/worktrees/<id>/gitdir to point at
the specified worktree path. In order for <repo> to be known, `git
worktree repair` must be run in the main worktree or bare repository.
`git worktree repair` first attempts to repair each incoming
/path/to/worktree/.git gitfile to point at the repository, and then
attempts to repair outgoing <repo>/worktrees/<id>/gitdir files to point
at the worktrees. This sequence was chosen arbitrarily when originally
implemented since the order of fixes is immaterial as long as one side
of the two-way link between the repository and a worktree is sound.
However, for this new repair technique to work, the order must be
reversed. This is because the new inference mechanism, when it is
successful, allows the outgoing <repo>/worktrees/<id>/gitdir file to be
repaired, thus fixing one side of the two-way link. Once that side is
fixed, the other side can be fixed by the existing repair mechanism,
hence the order of repairs is now significant.
Two safeguards are employed to avoid hijacking a worktree from a
different repository if the user accidentally specifies a foreign
worktree as an argument. The first, as described above, is that it
requires an <id> match between the repository and the worktree. That
itself is not foolproof for preventing hijack, so the second safeguard
is that the inference will only kick in if the worktree's
/path/to/worktree/.git gitfile does not point at a repository.
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-21 16:16:01 +08:00
|
|
|
{
|
|
|
|
struct strbuf actual = STRBUF_INIT;
|
|
|
|
const char *id;
|
|
|
|
|
|
|
|
if (strbuf_read_file(&actual, gitfile, 0) < 0)
|
|
|
|
goto error;
|
|
|
|
if (!starts_with(actual.buf, "gitdir:"))
|
|
|
|
goto error;
|
|
|
|
if (!(id = find_last_dir_sep(actual.buf)))
|
|
|
|
goto error;
|
|
|
|
strbuf_trim(&actual);
|
|
|
|
id++; /* advance past '/' to point at <id> */
|
|
|
|
if (!*id)
|
|
|
|
goto error;
|
2024-10-08 11:12:30 +08:00
|
|
|
strbuf_reset(inferred);
|
|
|
|
strbuf_git_common_path(inferred, the_repository, "worktrees/%s", id);
|
|
|
|
if (!is_directory(inferred->buf))
|
worktree: teach `repair` to fix multi-directional breakage
`git worktree repair` knows how to repair the two-way links between the
repository and a worktree as long as a link in one or the other
direction is sound. For instance, if a linked worktree is moved (without
using `git worktree move`), repair is possible because the worktree
still knows the location of the repository even though the repository no
longer knows where the worktree is. Similarly, if the repository is
moved, repair is possible since the repository still knows the locations
of the worktrees even though the worktrees no longer know where the
repository is.
However, if both the repository and the worktrees are moved, then links
are severed in both directions, and no repair is possible. This is the
case even when the new worktree locations are specified as arguments to
`git worktree repair`. The reason for this limitation is twofold. First,
when `repair` consults the worktree's gitfile (/path/to/worktree/.git)
to determine the corresponding <repo>/worktrees/<id>/gitdir file to fix,
<repo> is the old path to the repository, thus it is unable to fix the
`gitdir` file at its new location since it doesn't know where it is.
Second, when `repair` consults <repo>/worktrees/<id>/gitdir to find the
location of the worktree's gitfile (/path/to/worktree/.git), the path
recorded in `gitdir` is the old location of the worktree's gitfile, thus
it is unable to repair the gitfile since it doesn't know where it is.
Fix these shortcomings by teaching `repair` to attempt to infer the new
location of the <repo>/worktrees/<id>/gitdir file when the location
recorded in the worktree's gitfile has become stale but the file is
otherwise well-formed. The inference is intentionally simple-minded.
For each worktree path specified as an argument, `git worktree repair`
manually reads the ".git" gitfile at that location and, if it is
well-formed, extracts the <id>. It then searches for a corresponding
<id> in <repo>/worktrees/ and, if found, concludes that there is a
reasonable match and updates <repo>/worktrees/<id>/gitdir to point at
the specified worktree path. In order for <repo> to be known, `git
worktree repair` must be run in the main worktree or bare repository.
`git worktree repair` first attempts to repair each incoming
/path/to/worktree/.git gitfile to point at the repository, and then
attempts to repair outgoing <repo>/worktrees/<id>/gitdir files to point
at the worktrees. This sequence was chosen arbitrarily when originally
implemented since the order of fixes is immaterial as long as one side
of the two-way link between the repository and a worktree is sound.
However, for this new repair technique to work, the order must be
reversed. This is because the new inference mechanism, when it is
successful, allows the outgoing <repo>/worktrees/<id>/gitdir file to be
repaired, thus fixing one side of the two-way link. Once that side is
fixed, the other side can be fixed by the existing repair mechanism,
hence the order of repairs is now significant.
Two safeguards are employed to avoid hijacking a worktree from a
different repository if the user accidentally specifies a foreign
worktree as an argument. The first, as described above, is that it
requires an <id> match between the repository and the worktree. That
itself is not foolproof for preventing hijack, so the second safeguard
is that the inference will only kick in if the worktree's
/path/to/worktree/.git gitfile does not point at a repository.
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-21 16:16:01 +08:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
strbuf_release(&actual);
|
2024-10-08 11:12:30 +08:00
|
|
|
return 1;
|
worktree: teach `repair` to fix multi-directional breakage
`git worktree repair` knows how to repair the two-way links between the
repository and a worktree as long as a link in one or the other
direction is sound. For instance, if a linked worktree is moved (without
using `git worktree move`), repair is possible because the worktree
still knows the location of the repository even though the repository no
longer knows where the worktree is. Similarly, if the repository is
moved, repair is possible since the repository still knows the locations
of the worktrees even though the worktrees no longer know where the
repository is.
However, if both the repository and the worktrees are moved, then links
are severed in both directions, and no repair is possible. This is the
case even when the new worktree locations are specified as arguments to
`git worktree repair`. The reason for this limitation is twofold. First,
when `repair` consults the worktree's gitfile (/path/to/worktree/.git)
to determine the corresponding <repo>/worktrees/<id>/gitdir file to fix,
<repo> is the old path to the repository, thus it is unable to fix the
`gitdir` file at its new location since it doesn't know where it is.
Second, when `repair` consults <repo>/worktrees/<id>/gitdir to find the
location of the worktree's gitfile (/path/to/worktree/.git), the path
recorded in `gitdir` is the old location of the worktree's gitfile, thus
it is unable to repair the gitfile since it doesn't know where it is.
Fix these shortcomings by teaching `repair` to attempt to infer the new
location of the <repo>/worktrees/<id>/gitdir file when the location
recorded in the worktree's gitfile has become stale but the file is
otherwise well-formed. The inference is intentionally simple-minded.
For each worktree path specified as an argument, `git worktree repair`
manually reads the ".git" gitfile at that location and, if it is
well-formed, extracts the <id>. It then searches for a corresponding
<id> in <repo>/worktrees/ and, if found, concludes that there is a
reasonable match and updates <repo>/worktrees/<id>/gitdir to point at
the specified worktree path. In order for <repo> to be known, `git
worktree repair` must be run in the main worktree or bare repository.
`git worktree repair` first attempts to repair each incoming
/path/to/worktree/.git gitfile to point at the repository, and then
attempts to repair outgoing <repo>/worktrees/<id>/gitdir files to point
at the worktrees. This sequence was chosen arbitrarily when originally
implemented since the order of fixes is immaterial as long as one side
of the two-way link between the repository and a worktree is sound.
However, for this new repair technique to work, the order must be
reversed. This is because the new inference mechanism, when it is
successful, allows the outgoing <repo>/worktrees/<id>/gitdir file to be
repaired, thus fixing one side of the two-way link. Once that side is
fixed, the other side can be fixed by the existing repair mechanism,
hence the order of repairs is now significant.
Two safeguards are employed to avoid hijacking a worktree from a
different repository if the user accidentally specifies a foreign
worktree as an argument. The first, as described above, is that it
requires an <id> match between the repository and the worktree. That
itself is not foolproof for preventing hijack, so the second safeguard
is that the inference will only kick in if the worktree's
/path/to/worktree/.git gitfile does not point at a repository.
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-21 16:16:01 +08:00
|
|
|
|
|
|
|
error:
|
|
|
|
strbuf_release(&actual);
|
2024-10-08 11:12:30 +08:00
|
|
|
strbuf_reset(inferred); /* clear invalid path */
|
|
|
|
return 0;
|
worktree: teach `repair` to fix multi-directional breakage
`git worktree repair` knows how to repair the two-way links between the
repository and a worktree as long as a link in one or the other
direction is sound. For instance, if a linked worktree is moved (without
using `git worktree move`), repair is possible because the worktree
still knows the location of the repository even though the repository no
longer knows where the worktree is. Similarly, if the repository is
moved, repair is possible since the repository still knows the locations
of the worktrees even though the worktrees no longer know where the
repository is.
However, if both the repository and the worktrees are moved, then links
are severed in both directions, and no repair is possible. This is the
case even when the new worktree locations are specified as arguments to
`git worktree repair`. The reason for this limitation is twofold. First,
when `repair` consults the worktree's gitfile (/path/to/worktree/.git)
to determine the corresponding <repo>/worktrees/<id>/gitdir file to fix,
<repo> is the old path to the repository, thus it is unable to fix the
`gitdir` file at its new location since it doesn't know where it is.
Second, when `repair` consults <repo>/worktrees/<id>/gitdir to find the
location of the worktree's gitfile (/path/to/worktree/.git), the path
recorded in `gitdir` is the old location of the worktree's gitfile, thus
it is unable to repair the gitfile since it doesn't know where it is.
Fix these shortcomings by teaching `repair` to attempt to infer the new
location of the <repo>/worktrees/<id>/gitdir file when the location
recorded in the worktree's gitfile has become stale but the file is
otherwise well-formed. The inference is intentionally simple-minded.
For each worktree path specified as an argument, `git worktree repair`
manually reads the ".git" gitfile at that location and, if it is
well-formed, extracts the <id>. It then searches for a corresponding
<id> in <repo>/worktrees/ and, if found, concludes that there is a
reasonable match and updates <repo>/worktrees/<id>/gitdir to point at
the specified worktree path. In order for <repo> to be known, `git
worktree repair` must be run in the main worktree or bare repository.
`git worktree repair` first attempts to repair each incoming
/path/to/worktree/.git gitfile to point at the repository, and then
attempts to repair outgoing <repo>/worktrees/<id>/gitdir files to point
at the worktrees. This sequence was chosen arbitrarily when originally
implemented since the order of fixes is immaterial as long as one side
of the two-way link between the repository and a worktree is sound.
However, for this new repair technique to work, the order must be
reversed. This is because the new inference mechanism, when it is
successful, allows the outgoing <repo>/worktrees/<id>/gitdir file to be
repaired, thus fixing one side of the two-way link. Once that side is
fixed, the other side can be fixed by the existing repair mechanism,
hence the order of repairs is now significant.
Two safeguards are employed to avoid hijacking a worktree from a
different repository if the user accidentally specifies a foreign
worktree as an argument. The first, as described above, is that it
requires an <id> match between the repository and the worktree. That
itself is not foolproof for preventing hijack, so the second safeguard
is that the inference will only kick in if the worktree's
/path/to/worktree/.git gitfile does not point at a repository.
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-21 16:16:01 +08:00
|
|
|
}
|
|
|
|
|
2020-08-31 14:57:58 +08:00
|
|
|
/*
|
|
|
|
* Repair <repo>/worktrees/<id>/gitdir if missing, corrupt, or not pointing at
|
|
|
|
* the worktree's path.
|
|
|
|
*/
|
|
|
|
void repair_worktree_at_path(const char *path,
|
|
|
|
worktree_repair_fn fn, void *cb_data)
|
|
|
|
{
|
|
|
|
struct strbuf dotgit = STRBUF_INIT;
|
|
|
|
struct strbuf realdotgit = STRBUF_INIT;
|
2024-10-08 11:12:30 +08:00
|
|
|
struct strbuf backlink = STRBUF_INIT;
|
|
|
|
struct strbuf inferred_backlink = STRBUF_INIT;
|
2020-08-31 14:57:58 +08:00
|
|
|
struct strbuf gitdir = STRBUF_INIT;
|
|
|
|
struct strbuf olddotgit = STRBUF_INIT;
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
struct strbuf realolddotgit = STRBUF_INIT;
|
|
|
|
struct strbuf tmp = STRBUF_INIT;
|
2024-10-08 11:12:30 +08:00
|
|
|
char *dotgit_contents = NULL;
|
2020-08-31 14:57:58 +08:00
|
|
|
const char *repair = NULL;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!fn)
|
|
|
|
fn = repair_noop;
|
|
|
|
|
|
|
|
if (is_main_worktree_path(path))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
strbuf_addf(&dotgit, "%s/.git", path);
|
|
|
|
if (!strbuf_realpath(&realdotgit, dotgit.buf, 0)) {
|
|
|
|
fn(1, path, _("not a valid path"), cb_data);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2024-10-08 11:12:30 +08:00
|
|
|
infer_backlink(realdotgit.buf, &inferred_backlink);
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
strbuf_realpath_forgiving(&inferred_backlink, inferred_backlink.buf, 0);
|
2024-10-08 11:12:30 +08:00
|
|
|
dotgit_contents = xstrdup_or_null(read_gitfile_gently(realdotgit.buf, &err));
|
|
|
|
if (dotgit_contents) {
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
if (is_absolute_path(dotgit_contents)) {
|
|
|
|
strbuf_addstr(&backlink, dotgit_contents);
|
|
|
|
} else {
|
|
|
|
strbuf_addbuf(&backlink, &realdotgit);
|
|
|
|
strbuf_strip_suffix(&backlink, ".git");
|
|
|
|
strbuf_addstr(&backlink, dotgit_contents);
|
|
|
|
strbuf_realpath_forgiving(&backlink, backlink.buf, 0);
|
|
|
|
}
|
2024-10-08 11:12:30 +08:00
|
|
|
} else if (err == READ_GITFILE_ERR_NOT_A_FILE) {
|
2020-08-31 14:57:58 +08:00
|
|
|
fn(1, realdotgit.buf, _("unable to locate repository; .git is not a file"), cb_data);
|
|
|
|
goto done;
|
worktree: teach `repair` to fix multi-directional breakage
`git worktree repair` knows how to repair the two-way links between the
repository and a worktree as long as a link in one or the other
direction is sound. For instance, if a linked worktree is moved (without
using `git worktree move`), repair is possible because the worktree
still knows the location of the repository even though the repository no
longer knows where the worktree is. Similarly, if the repository is
moved, repair is possible since the repository still knows the locations
of the worktrees even though the worktrees no longer know where the
repository is.
However, if both the repository and the worktrees are moved, then links
are severed in both directions, and no repair is possible. This is the
case even when the new worktree locations are specified as arguments to
`git worktree repair`. The reason for this limitation is twofold. First,
when `repair` consults the worktree's gitfile (/path/to/worktree/.git)
to determine the corresponding <repo>/worktrees/<id>/gitdir file to fix,
<repo> is the old path to the repository, thus it is unable to fix the
`gitdir` file at its new location since it doesn't know where it is.
Second, when `repair` consults <repo>/worktrees/<id>/gitdir to find the
location of the worktree's gitfile (/path/to/worktree/.git), the path
recorded in `gitdir` is the old location of the worktree's gitfile, thus
it is unable to repair the gitfile since it doesn't know where it is.
Fix these shortcomings by teaching `repair` to attempt to infer the new
location of the <repo>/worktrees/<id>/gitdir file when the location
recorded in the worktree's gitfile has become stale but the file is
otherwise well-formed. The inference is intentionally simple-minded.
For each worktree path specified as an argument, `git worktree repair`
manually reads the ".git" gitfile at that location and, if it is
well-formed, extracts the <id>. It then searches for a corresponding
<id> in <repo>/worktrees/ and, if found, concludes that there is a
reasonable match and updates <repo>/worktrees/<id>/gitdir to point at
the specified worktree path. In order for <repo> to be known, `git
worktree repair` must be run in the main worktree or bare repository.
`git worktree repair` first attempts to repair each incoming
/path/to/worktree/.git gitfile to point at the repository, and then
attempts to repair outgoing <repo>/worktrees/<id>/gitdir files to point
at the worktrees. This sequence was chosen arbitrarily when originally
implemented since the order of fixes is immaterial as long as one side
of the two-way link between the repository and a worktree is sound.
However, for this new repair technique to work, the order must be
reversed. This is because the new inference mechanism, when it is
successful, allows the outgoing <repo>/worktrees/<id>/gitdir file to be
repaired, thus fixing one side of the two-way link. Once that side is
fixed, the other side can be fixed by the existing repair mechanism,
hence the order of repairs is now significant.
Two safeguards are employed to avoid hijacking a worktree from a
different repository if the user accidentally specifies a foreign
worktree as an argument. The first, as described above, is that it
requires an <id> match between the repository and the worktree. That
itself is not foolproof for preventing hijack, so the second safeguard
is that the inference will only kick in if the worktree's
/path/to/worktree/.git gitfile does not point at a repository.
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-21 16:16:01 +08:00
|
|
|
} else if (err == READ_GITFILE_ERR_NOT_A_REPO) {
|
2024-10-08 11:12:30 +08:00
|
|
|
if (inferred_backlink.len) {
|
worktree: repair copied repository and linked worktrees
For each linked worktree, Git maintains two pointers: (1)
<repo>/worktrees/<id>/gitdir which points at the linked worktree, and
(2) <worktree>/.git which points back at <repo>/worktrees/<id>. Both
pointers are absolute pathnames.
Aside from manually manipulating those raw files, it is possible to
easily "break" one or both pointers by ignoring the "git worktree move"
command and instead manually moving a linked worktree, moving the
repository, or moving both. The "git worktree repair" command was
invented to handle this case by restoring these pointers to sane values.
For the "repair" command, the "git worktree" manual page states:
Repair worktree administrative files, if possible, if they have
become corrupted or outdated due to external factors.
The "if possible" clause was chosen deliberately to convey that the
existing implementation may not be able to fix every possible breakage,
and to imply that improvements may be made to handle other types of
breakage.
A recent problem report[*] illustrates a case in which "git worktree
repair" not only fails to fix breakage, but actually causes breakage.
Specifically, if a repository / main-worktree and linked worktrees are
*copied* as a unit (rather than *moved*), then "git worktree repair" run
in the copy leaves the copy untouched but botches the pointers in the
original repository and the original worktrees.
For instance, given this directory structure:
orig/
main/ (main-worktree)
linked/ (linked worktree)
if "orig" is copied (not moved) to "dup", then immediately after the
manual copy operation:
* orig/main/.git/worktrees/linked/gitdir points at orig/linked/.git
* orig/linked/.git points at orig/main/.git/worktrees/linked
* dup/main/.git/worktrees/linked/gitdir points at orig/linked/.git
* dup/linked/.git points at orig/main/.git/worktrees/linked
So, dup/main thinks its linked worktree is orig/linked, and worktree
dup/linked thinks its repository / main-worktree is orig/main.
"git worktree repair" is reasonably simple-minded; it wants to trust
valid-looking pointers, hence doesn't try to second-guess them. In this
case, when validating dup/linked/.git, it finds a legitimate repository
pointer, orig/main/.git/worktrees/linked, thus trusts that is correct,
but does notice that gitdir in that directory doesn't point at
dup/linked/.git, so it (incorrectly) _fixes_
orig/main/.git/worktrees/linked/gitdir to point at dup/linked/.git.
Similarly, when validating dup/main/.git/worktrees/linked/gitdir, it
finds a legitimate worktree pointer, orig/linked/.git, but notices that
its .git file doesn't point back at dup/main, thus (incorrectly) _fixes_
orig/linked/.git to point at dup/main/.git/worktrees/linked. Hence, it
has modified and broken the linkage between orig/main and orig/linked
rather than fixing dup/main and dup/linked as expected.
Fix this problem by also checking if a plausible .git/worktrees/<id>
exists in the *current* repository -- not just in the repository pointed
at by the worktree's .git file -- and comparing whether they are the
same. If not, then it is likely because the repository / main-worktree
and linked worktrees were copied, so prefer the discovered plausible
pointer rather than the one from the existing .git file.
[*]: https://lore.kernel.org/git/E1sr5iF-0007zV-2k@binarylane-bailey.stuart.id.au/
Reported-by: Russell Stuart <russell+git.vger.kernel.org@stuart.id.au>
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-09-23 15:54:16 +08:00
|
|
|
/*
|
|
|
|
* Worktree's .git file does not point at a repository
|
|
|
|
* but we found a .git/worktrees/<id> in this
|
|
|
|
* repository with the same <id> as recorded in the
|
|
|
|
* worktree's .git file so make the worktree point at
|
2024-10-08 11:12:30 +08:00
|
|
|
* the discovered .git/worktrees/<id>.
|
worktree: repair copied repository and linked worktrees
For each linked worktree, Git maintains two pointers: (1)
<repo>/worktrees/<id>/gitdir which points at the linked worktree, and
(2) <worktree>/.git which points back at <repo>/worktrees/<id>. Both
pointers are absolute pathnames.
Aside from manually manipulating those raw files, it is possible to
easily "break" one or both pointers by ignoring the "git worktree move"
command and instead manually moving a linked worktree, moving the
repository, or moving both. The "git worktree repair" command was
invented to handle this case by restoring these pointers to sane values.
For the "repair" command, the "git worktree" manual page states:
Repair worktree administrative files, if possible, if they have
become corrupted or outdated due to external factors.
The "if possible" clause was chosen deliberately to convey that the
existing implementation may not be able to fix every possible breakage,
and to imply that improvements may be made to handle other types of
breakage.
A recent problem report[*] illustrates a case in which "git worktree
repair" not only fails to fix breakage, but actually causes breakage.
Specifically, if a repository / main-worktree and linked worktrees are
*copied* as a unit (rather than *moved*), then "git worktree repair" run
in the copy leaves the copy untouched but botches the pointers in the
original repository and the original worktrees.
For instance, given this directory structure:
orig/
main/ (main-worktree)
linked/ (linked worktree)
if "orig" is copied (not moved) to "dup", then immediately after the
manual copy operation:
* orig/main/.git/worktrees/linked/gitdir points at orig/linked/.git
* orig/linked/.git points at orig/main/.git/worktrees/linked
* dup/main/.git/worktrees/linked/gitdir points at orig/linked/.git
* dup/linked/.git points at orig/main/.git/worktrees/linked
So, dup/main thinks its linked worktree is orig/linked, and worktree
dup/linked thinks its repository / main-worktree is orig/main.
"git worktree repair" is reasonably simple-minded; it wants to trust
valid-looking pointers, hence doesn't try to second-guess them. In this
case, when validating dup/linked/.git, it finds a legitimate repository
pointer, orig/main/.git/worktrees/linked, thus trusts that is correct,
but does notice that gitdir in that directory doesn't point at
dup/linked/.git, so it (incorrectly) _fixes_
orig/main/.git/worktrees/linked/gitdir to point at dup/linked/.git.
Similarly, when validating dup/main/.git/worktrees/linked/gitdir, it
finds a legitimate worktree pointer, orig/linked/.git, but notices that
its .git file doesn't point back at dup/main, thus (incorrectly) _fixes_
orig/linked/.git to point at dup/main/.git/worktrees/linked. Hence, it
has modified and broken the linkage between orig/main and orig/linked
rather than fixing dup/main and dup/linked as expected.
Fix this problem by also checking if a plausible .git/worktrees/<id>
exists in the *current* repository -- not just in the repository pointed
at by the worktree's .git file -- and comparing whether they are the
same. If not, then it is likely because the repository / main-worktree
and linked worktrees were copied, so prefer the discovered plausible
pointer rather than the one from the existing .git file.
[*]: https://lore.kernel.org/git/E1sr5iF-0007zV-2k@binarylane-bailey.stuart.id.au/
Reported-by: Russell Stuart <russell+git.vger.kernel.org@stuart.id.au>
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-09-23 15:54:16 +08:00
|
|
|
*/
|
2024-10-08 11:12:30 +08:00
|
|
|
strbuf_swap(&backlink, &inferred_backlink);
|
worktree: repair copied repository and linked worktrees
For each linked worktree, Git maintains two pointers: (1)
<repo>/worktrees/<id>/gitdir which points at the linked worktree, and
(2) <worktree>/.git which points back at <repo>/worktrees/<id>. Both
pointers are absolute pathnames.
Aside from manually manipulating those raw files, it is possible to
easily "break" one or both pointers by ignoring the "git worktree move"
command and instead manually moving a linked worktree, moving the
repository, or moving both. The "git worktree repair" command was
invented to handle this case by restoring these pointers to sane values.
For the "repair" command, the "git worktree" manual page states:
Repair worktree administrative files, if possible, if they have
become corrupted or outdated due to external factors.
The "if possible" clause was chosen deliberately to convey that the
existing implementation may not be able to fix every possible breakage,
and to imply that improvements may be made to handle other types of
breakage.
A recent problem report[*] illustrates a case in which "git worktree
repair" not only fails to fix breakage, but actually causes breakage.
Specifically, if a repository / main-worktree and linked worktrees are
*copied* as a unit (rather than *moved*), then "git worktree repair" run
in the copy leaves the copy untouched but botches the pointers in the
original repository and the original worktrees.
For instance, given this directory structure:
orig/
main/ (main-worktree)
linked/ (linked worktree)
if "orig" is copied (not moved) to "dup", then immediately after the
manual copy operation:
* orig/main/.git/worktrees/linked/gitdir points at orig/linked/.git
* orig/linked/.git points at orig/main/.git/worktrees/linked
* dup/main/.git/worktrees/linked/gitdir points at orig/linked/.git
* dup/linked/.git points at orig/main/.git/worktrees/linked
So, dup/main thinks its linked worktree is orig/linked, and worktree
dup/linked thinks its repository / main-worktree is orig/main.
"git worktree repair" is reasonably simple-minded; it wants to trust
valid-looking pointers, hence doesn't try to second-guess them. In this
case, when validating dup/linked/.git, it finds a legitimate repository
pointer, orig/main/.git/worktrees/linked, thus trusts that is correct,
but does notice that gitdir in that directory doesn't point at
dup/linked/.git, so it (incorrectly) _fixes_
orig/main/.git/worktrees/linked/gitdir to point at dup/linked/.git.
Similarly, when validating dup/main/.git/worktrees/linked/gitdir, it
finds a legitimate worktree pointer, orig/linked/.git, but notices that
its .git file doesn't point back at dup/main, thus (incorrectly) _fixes_
orig/linked/.git to point at dup/main/.git/worktrees/linked. Hence, it
has modified and broken the linkage between orig/main and orig/linked
rather than fixing dup/main and dup/linked as expected.
Fix this problem by also checking if a plausible .git/worktrees/<id>
exists in the *current* repository -- not just in the repository pointed
at by the worktree's .git file -- and comparing whether they are the
same. If not, then it is likely because the repository / main-worktree
and linked worktrees were copied, so prefer the discovered plausible
pointer rather than the one from the existing .git file.
[*]: https://lore.kernel.org/git/E1sr5iF-0007zV-2k@binarylane-bailey.stuart.id.au/
Reported-by: Russell Stuart <russell+git.vger.kernel.org@stuart.id.au>
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-09-23 15:54:16 +08:00
|
|
|
} else {
|
worktree: teach `repair` to fix multi-directional breakage
`git worktree repair` knows how to repair the two-way links between the
repository and a worktree as long as a link in one or the other
direction is sound. For instance, if a linked worktree is moved (without
using `git worktree move`), repair is possible because the worktree
still knows the location of the repository even though the repository no
longer knows where the worktree is. Similarly, if the repository is
moved, repair is possible since the repository still knows the locations
of the worktrees even though the worktrees no longer know where the
repository is.
However, if both the repository and the worktrees are moved, then links
are severed in both directions, and no repair is possible. This is the
case even when the new worktree locations are specified as arguments to
`git worktree repair`. The reason for this limitation is twofold. First,
when `repair` consults the worktree's gitfile (/path/to/worktree/.git)
to determine the corresponding <repo>/worktrees/<id>/gitdir file to fix,
<repo> is the old path to the repository, thus it is unable to fix the
`gitdir` file at its new location since it doesn't know where it is.
Second, when `repair` consults <repo>/worktrees/<id>/gitdir to find the
location of the worktree's gitfile (/path/to/worktree/.git), the path
recorded in `gitdir` is the old location of the worktree's gitfile, thus
it is unable to repair the gitfile since it doesn't know where it is.
Fix these shortcomings by teaching `repair` to attempt to infer the new
location of the <repo>/worktrees/<id>/gitdir file when the location
recorded in the worktree's gitfile has become stale but the file is
otherwise well-formed. The inference is intentionally simple-minded.
For each worktree path specified as an argument, `git worktree repair`
manually reads the ".git" gitfile at that location and, if it is
well-formed, extracts the <id>. It then searches for a corresponding
<id> in <repo>/worktrees/ and, if found, concludes that there is a
reasonable match and updates <repo>/worktrees/<id>/gitdir to point at
the specified worktree path. In order for <repo> to be known, `git
worktree repair` must be run in the main worktree or bare repository.
`git worktree repair` first attempts to repair each incoming
/path/to/worktree/.git gitfile to point at the repository, and then
attempts to repair outgoing <repo>/worktrees/<id>/gitdir files to point
at the worktrees. This sequence was chosen arbitrarily when originally
implemented since the order of fixes is immaterial as long as one side
of the two-way link between the repository and a worktree is sound.
However, for this new repair technique to work, the order must be
reversed. This is because the new inference mechanism, when it is
successful, allows the outgoing <repo>/worktrees/<id>/gitdir file to be
repaired, thus fixing one side of the two-way link. Once that side is
fixed, the other side can be fixed by the existing repair mechanism,
hence the order of repairs is now significant.
Two safeguards are employed to avoid hijacking a worktree from a
different repository if the user accidentally specifies a foreign
worktree as an argument. The first, as described above, is that it
requires an <id> match between the repository and the worktree. That
itself is not foolproof for preventing hijack, so the second safeguard
is that the inference will only kick in if the worktree's
/path/to/worktree/.git gitfile does not point at a repository.
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-21 16:16:01 +08:00
|
|
|
fn(1, realdotgit.buf, _("unable to locate repository; .git file does not reference a repository"), cb_data);
|
|
|
|
goto done;
|
|
|
|
}
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
} else {
|
2020-08-31 14:57:58 +08:00
|
|
|
fn(1, realdotgit.buf, _("unable to locate repository; .git file broken"), cb_data);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
worktree: repair copied repository and linked worktrees
For each linked worktree, Git maintains two pointers: (1)
<repo>/worktrees/<id>/gitdir which points at the linked worktree, and
(2) <worktree>/.git which points back at <repo>/worktrees/<id>. Both
pointers are absolute pathnames.
Aside from manually manipulating those raw files, it is possible to
easily "break" one or both pointers by ignoring the "git worktree move"
command and instead manually moving a linked worktree, moving the
repository, or moving both. The "git worktree repair" command was
invented to handle this case by restoring these pointers to sane values.
For the "repair" command, the "git worktree" manual page states:
Repair worktree administrative files, if possible, if they have
become corrupted or outdated due to external factors.
The "if possible" clause was chosen deliberately to convey that the
existing implementation may not be able to fix every possible breakage,
and to imply that improvements may be made to handle other types of
breakage.
A recent problem report[*] illustrates a case in which "git worktree
repair" not only fails to fix breakage, but actually causes breakage.
Specifically, if a repository / main-worktree and linked worktrees are
*copied* as a unit (rather than *moved*), then "git worktree repair" run
in the copy leaves the copy untouched but botches the pointers in the
original repository and the original worktrees.
For instance, given this directory structure:
orig/
main/ (main-worktree)
linked/ (linked worktree)
if "orig" is copied (not moved) to "dup", then immediately after the
manual copy operation:
* orig/main/.git/worktrees/linked/gitdir points at orig/linked/.git
* orig/linked/.git points at orig/main/.git/worktrees/linked
* dup/main/.git/worktrees/linked/gitdir points at orig/linked/.git
* dup/linked/.git points at orig/main/.git/worktrees/linked
So, dup/main thinks its linked worktree is orig/linked, and worktree
dup/linked thinks its repository / main-worktree is orig/main.
"git worktree repair" is reasonably simple-minded; it wants to trust
valid-looking pointers, hence doesn't try to second-guess them. In this
case, when validating dup/linked/.git, it finds a legitimate repository
pointer, orig/main/.git/worktrees/linked, thus trusts that is correct,
but does notice that gitdir in that directory doesn't point at
dup/linked/.git, so it (incorrectly) _fixes_
orig/main/.git/worktrees/linked/gitdir to point at dup/linked/.git.
Similarly, when validating dup/main/.git/worktrees/linked/gitdir, it
finds a legitimate worktree pointer, orig/linked/.git, but notices that
its .git file doesn't point back at dup/main, thus (incorrectly) _fixes_
orig/linked/.git to point at dup/main/.git/worktrees/linked. Hence, it
has modified and broken the linkage between orig/main and orig/linked
rather than fixing dup/main and dup/linked as expected.
Fix this problem by also checking if a plausible .git/worktrees/<id>
exists in the *current* repository -- not just in the repository pointed
at by the worktree's .git file -- and comparing whether they are the
same. If not, then it is likely because the repository / main-worktree
and linked worktrees were copied, so prefer the discovered plausible
pointer rather than the one from the existing .git file.
[*]: https://lore.kernel.org/git/E1sr5iF-0007zV-2k@binarylane-bailey.stuart.id.au/
Reported-by: Russell Stuart <russell+git.vger.kernel.org@stuart.id.au>
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-09-23 15:54:16 +08:00
|
|
|
/*
|
|
|
|
* If we got this far, either the worktree's .git file pointed at a
|
|
|
|
* valid repository (i.e. read_gitfile_gently() returned success) or
|
|
|
|
* the .git file did not point at a repository but we were able to
|
|
|
|
* infer a suitable new value for the .git file by locating a
|
|
|
|
* .git/worktrees/<id> in *this* repository corresponding to the <id>
|
|
|
|
* recorded in the worktree's .git file.
|
|
|
|
*
|
|
|
|
* However, if, at this point, inferred_backlink is non-NULL (i.e. we
|
|
|
|
* found a suitable .git/worktrees/<id> in *this* repository) *and* the
|
|
|
|
* worktree's .git file points at a valid repository *and* those two
|
|
|
|
* paths differ, then that indicates that the user probably *copied*
|
|
|
|
* the main and linked worktrees to a new location as a unit rather
|
|
|
|
* than *moving* them. Thus, the copied worktree's .git file actually
|
|
|
|
* points at the .git/worktrees/<id> in the *original* repository, not
|
|
|
|
* in the "copy" repository. In this case, point the "copy" worktree's
|
|
|
|
* .git file at the "copy" repository.
|
|
|
|
*/
|
2024-10-08 11:12:30 +08:00
|
|
|
if (inferred_backlink.len && fspathcmp(backlink.buf, inferred_backlink.buf)) {
|
|
|
|
strbuf_swap(&backlink, &inferred_backlink);
|
worktree: repair copied repository and linked worktrees
For each linked worktree, Git maintains two pointers: (1)
<repo>/worktrees/<id>/gitdir which points at the linked worktree, and
(2) <worktree>/.git which points back at <repo>/worktrees/<id>. Both
pointers are absolute pathnames.
Aside from manually manipulating those raw files, it is possible to
easily "break" one or both pointers by ignoring the "git worktree move"
command and instead manually moving a linked worktree, moving the
repository, or moving both. The "git worktree repair" command was
invented to handle this case by restoring these pointers to sane values.
For the "repair" command, the "git worktree" manual page states:
Repair worktree administrative files, if possible, if they have
become corrupted or outdated due to external factors.
The "if possible" clause was chosen deliberately to convey that the
existing implementation may not be able to fix every possible breakage,
and to imply that improvements may be made to handle other types of
breakage.
A recent problem report[*] illustrates a case in which "git worktree
repair" not only fails to fix breakage, but actually causes breakage.
Specifically, if a repository / main-worktree and linked worktrees are
*copied* as a unit (rather than *moved*), then "git worktree repair" run
in the copy leaves the copy untouched but botches the pointers in the
original repository and the original worktrees.
For instance, given this directory structure:
orig/
main/ (main-worktree)
linked/ (linked worktree)
if "orig" is copied (not moved) to "dup", then immediately after the
manual copy operation:
* orig/main/.git/worktrees/linked/gitdir points at orig/linked/.git
* orig/linked/.git points at orig/main/.git/worktrees/linked
* dup/main/.git/worktrees/linked/gitdir points at orig/linked/.git
* dup/linked/.git points at orig/main/.git/worktrees/linked
So, dup/main thinks its linked worktree is orig/linked, and worktree
dup/linked thinks its repository / main-worktree is orig/main.
"git worktree repair" is reasonably simple-minded; it wants to trust
valid-looking pointers, hence doesn't try to second-guess them. In this
case, when validating dup/linked/.git, it finds a legitimate repository
pointer, orig/main/.git/worktrees/linked, thus trusts that is correct,
but does notice that gitdir in that directory doesn't point at
dup/linked/.git, so it (incorrectly) _fixes_
orig/main/.git/worktrees/linked/gitdir to point at dup/linked/.git.
Similarly, when validating dup/main/.git/worktrees/linked/gitdir, it
finds a legitimate worktree pointer, orig/linked/.git, but notices that
its .git file doesn't point back at dup/main, thus (incorrectly) _fixes_
orig/linked/.git to point at dup/main/.git/worktrees/linked. Hence, it
has modified and broken the linkage between orig/main and orig/linked
rather than fixing dup/main and dup/linked as expected.
Fix this problem by also checking if a plausible .git/worktrees/<id>
exists in the *current* repository -- not just in the repository pointed
at by the worktree's .git file -- and comparing whether they are the
same. If not, then it is likely because the repository / main-worktree
and linked worktrees were copied, so prefer the discovered plausible
pointer rather than the one from the existing .git file.
[*]: https://lore.kernel.org/git/E1sr5iF-0007zV-2k@binarylane-bailey.stuart.id.au/
Reported-by: Russell Stuart <russell+git.vger.kernel.org@stuart.id.au>
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-09-23 15:54:16 +08:00
|
|
|
}
|
|
|
|
|
2024-10-08 11:12:30 +08:00
|
|
|
strbuf_addf(&gitdir, "%s/gitdir", backlink.buf);
|
2020-08-31 14:57:58 +08:00
|
|
|
if (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0)
|
|
|
|
repair = _("gitdir unreadable");
|
|
|
|
else {
|
|
|
|
strbuf_rtrim(&olddotgit);
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
if (is_absolute_path(olddotgit.buf)) {
|
|
|
|
strbuf_addbuf(&realolddotgit, &olddotgit);
|
|
|
|
} else {
|
|
|
|
strbuf_addf(&realolddotgit, "%s/%s", backlink.buf, olddotgit.buf);
|
|
|
|
strbuf_realpath_forgiving(&realolddotgit, realolddotgit.buf, 0);
|
|
|
|
}
|
|
|
|
if (fspathcmp(realolddotgit.buf, realdotgit.buf))
|
2020-08-31 14:57:58 +08:00
|
|
|
repair = _("gitdir incorrect");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (repair) {
|
|
|
|
fn(0, gitdir.buf, repair, cb_data);
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
write_file(gitdir.buf, "%s", relative_path(realdotgit.buf, backlink.buf, &tmp));
|
2020-08-31 14:57:58 +08:00
|
|
|
}
|
|
|
|
done:
|
2024-10-08 11:12:30 +08:00
|
|
|
free(dotgit_contents);
|
2020-08-31 14:57:58 +08:00
|
|
|
strbuf_release(&olddotgit);
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
strbuf_release(&realolddotgit);
|
2024-10-08 11:12:30 +08:00
|
|
|
strbuf_release(&backlink);
|
|
|
|
strbuf_release(&inferred_backlink);
|
2020-08-31 14:57:58 +08:00
|
|
|
strbuf_release(&gitdir);
|
|
|
|
strbuf_release(&realdotgit);
|
|
|
|
strbuf_release(&dotgit);
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
strbuf_release(&tmp);
|
2020-08-31 14:57:58 +08:00
|
|
|
}
|
2021-01-20 05:27:33 +08:00
|
|
|
|
|
|
|
int should_prune_worktree(const char *id, struct strbuf *reason, char **wtpath, timestamp_t expire)
|
|
|
|
{
|
|
|
|
struct stat st;
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
struct strbuf dotgit = STRBUF_INIT;
|
|
|
|
struct strbuf gitdir = STRBUF_INIT;
|
|
|
|
struct strbuf repo = STRBUF_INIT;
|
|
|
|
struct strbuf file = STRBUF_INIT;
|
|
|
|
char *path = NULL;
|
|
|
|
int rc = 0;
|
2021-01-20 05:27:33 +08:00
|
|
|
int fd;
|
|
|
|
size_t len;
|
|
|
|
ssize_t read_result;
|
|
|
|
|
|
|
|
*wtpath = NULL;
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
strbuf_realpath(&repo, git_common_path("worktrees/%s", id), 1);
|
|
|
|
strbuf_addf(&gitdir, "%s/gitdir", repo.buf);
|
|
|
|
if (!is_directory(repo.buf)) {
|
2021-01-20 05:27:33 +08:00
|
|
|
strbuf_addstr(reason, _("not a valid directory"));
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
rc = 1;
|
|
|
|
goto done;
|
2021-01-20 05:27:33 +08:00
|
|
|
}
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
strbuf_addf(&file, "%s/locked", repo.buf);
|
|
|
|
if (file_exists(file.buf)) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
if (stat(gitdir.buf, &st)) {
|
2021-01-20 05:27:33 +08:00
|
|
|
strbuf_addstr(reason, _("gitdir file does not exist"));
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
rc = 1;
|
|
|
|
goto done;
|
2021-01-20 05:27:33 +08:00
|
|
|
}
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
fd = open(gitdir.buf, O_RDONLY);
|
2021-01-20 05:27:33 +08:00
|
|
|
if (fd < 0) {
|
|
|
|
strbuf_addf(reason, _("unable to read gitdir file (%s)"),
|
|
|
|
strerror(errno));
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
rc = 1;
|
|
|
|
goto done;
|
2021-01-20 05:27:33 +08:00
|
|
|
}
|
|
|
|
len = xsize_t(st.st_size);
|
|
|
|
path = xmallocz(len);
|
|
|
|
|
|
|
|
read_result = read_in_full(fd, path, len);
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
close(fd);
|
2021-01-20 05:27:33 +08:00
|
|
|
if (read_result < 0) {
|
|
|
|
strbuf_addf(reason, _("unable to read gitdir file (%s)"),
|
|
|
|
strerror(errno));
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
rc = 1;
|
|
|
|
goto done;
|
|
|
|
} else if (read_result != len) {
|
2021-01-20 05:27:33 +08:00
|
|
|
strbuf_addf(reason,
|
|
|
|
_("short read (expected %"PRIuMAX" bytes, read %"PRIuMAX")"),
|
|
|
|
(uintmax_t)len, (uintmax_t)read_result);
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
rc = 1;
|
|
|
|
goto done;
|
2021-01-20 05:27:33 +08:00
|
|
|
}
|
|
|
|
while (len && (path[len - 1] == '\n' || path[len - 1] == '\r'))
|
|
|
|
len--;
|
|
|
|
if (!len) {
|
|
|
|
strbuf_addstr(reason, _("invalid gitdir file"));
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
rc = 1;
|
|
|
|
goto done;
|
2021-01-20 05:27:33 +08:00
|
|
|
}
|
|
|
|
path[len] = '\0';
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
if (is_absolute_path(path)) {
|
|
|
|
strbuf_addstr(&dotgit, path);
|
|
|
|
} else {
|
|
|
|
strbuf_addf(&dotgit, "%s/%s", repo.buf, path);
|
|
|
|
strbuf_realpath_forgiving(&dotgit, dotgit.buf, 0);
|
|
|
|
}
|
|
|
|
if (!file_exists(dotgit.buf)) {
|
|
|
|
strbuf_reset(&file);
|
|
|
|
strbuf_addf(&file, "%s/index", repo.buf);
|
|
|
|
if (stat(file.buf, &st) || st.st_mtime <= expire) {
|
2021-01-20 05:27:33 +08:00
|
|
|
strbuf_addstr(reason, _("gitdir file points to non-existent location"));
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
rc = 1;
|
|
|
|
goto done;
|
2021-01-20 05:27:33 +08:00
|
|
|
}
|
|
|
|
}
|
worktree: link worktrees with relative paths
Git currently stores absolute paths to both the main repository and
linked worktrees. However, this causes problems when moving repositories
or working in containerized environments where absolute paths differ
between systems. The worktree links break, and users are required to
manually execute `worktree repair` to repair them, leading to workflow
disruptions. Additionally, mapping repositories inside of containerized
environments renders the repository unusable inside the containers, and
this is not repairable as repairing the worktrees inside the containers
will result in them being broken outside the containers.
To address this, this patch makes Git always write relative paths when
linking worktrees. Relative paths increase the resilience of the
worktree links across various systems and environments, particularly
when the worktrees are self-contained inside the main repository (such
as when using a bare repository with worktrees). This improves
portability, workflow efficiency, and reduces overall breakages.
Although Git now writes relative paths, existing repositories with
absolute paths are still supported. There are no breaking changes
to workflows based on absolute paths, ensuring backward compatibility.
At a low level, the changes involve modifying functions in `worktree.c`
and `builtin/worktree.c` to use `relative_path()` when writing the
worktree’s `.git` file and the main repository’s `gitdir` reference.
Instead of hardcoding absolute paths, Git now computes the relative path
between the worktree and the repository, ensuring that these links are
portable. Locations where these respective file are read have also been
updated to properly handle both absolute and relative paths. Generally,
relative paths are always resolved into absolute paths before any
operations or comparisons are performed.
Additionally, `repair_worktrees_after_gitdir_move()` has been introduced
to address the case where both the `<worktree>/.git` and
`<repo>/worktrees/<id>/gitdir` links are broken after the gitdir is
moved (such as during a re-initialization). This function repairs both
sides of the worktree link using the old gitdir path to reestablish the
correct paths after a move.
The `worktree.path` struct member has also been updated to always store
the absolute path of a worktree. This ensures that worktree consumers
never have to worry about trying to resolve the absolute path themselves.
Signed-off-by: Caleb White <cdwhite3@pm.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-10-08 11:12:31 +08:00
|
|
|
*wtpath = strbuf_detach(&dotgit, NULL);
|
|
|
|
done:
|
|
|
|
free(path);
|
|
|
|
strbuf_release(&dotgit);
|
|
|
|
strbuf_release(&gitdir);
|
|
|
|
strbuf_release(&repo);
|
|
|
|
strbuf_release(&file);
|
|
|
|
return rc;
|
2021-01-20 05:27:33 +08:00
|
|
|
}
|
2022-02-08 05:32:59 +08:00
|
|
|
|
|
|
|
static int move_config_setting(const char *key, const char *value,
|
|
|
|
const char *from_file, const char *to_file)
|
|
|
|
{
|
2024-03-13 05:47:00 +08:00
|
|
|
if (git_config_set_in_file_gently(to_file, key, NULL, value))
|
2022-02-08 05:32:59 +08:00
|
|
|
return error(_("unable to set %s in '%s'"), key, to_file);
|
2024-03-13 05:47:00 +08:00
|
|
|
if (git_config_set_in_file_gently(from_file, key, NULL, NULL))
|
2022-02-08 05:32:59 +08:00
|
|
|
return error(_("unable to unset %s in '%s'"), key, from_file);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int init_worktree_config(struct repository *r)
|
|
|
|
{
|
|
|
|
int res = 0;
|
|
|
|
int bare = 0;
|
|
|
|
struct config_set cs = { { 0 } };
|
|
|
|
const char *core_worktree;
|
|
|
|
char *common_config_file;
|
|
|
|
char *main_worktree_file;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the extension is already enabled, then we can skip the
|
|
|
|
* upgrade process.
|
|
|
|
*/
|
2023-05-26 09:33:00 +08:00
|
|
|
if (r->repository_format_worktree_config)
|
2022-02-08 05:32:59 +08:00
|
|
|
return 0;
|
|
|
|
if ((res = git_config_set_gently("extensions.worktreeConfig", "true")))
|
|
|
|
return error(_("failed to set extensions.worktreeConfig setting"));
|
|
|
|
|
|
|
|
common_config_file = xstrfmt("%s/config", r->commondir);
|
|
|
|
main_worktree_file = xstrfmt("%s/config.worktree", r->commondir);
|
|
|
|
|
|
|
|
git_configset_init(&cs);
|
|
|
|
git_configset_add_file(&cs, common_config_file);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If core.bare is true in the common config file, then we need to
|
|
|
|
* move it to the main worktree's config file or it will break all
|
|
|
|
* worktrees. If it is false, then leave it in place because it
|
|
|
|
* _could_ be negating a global core.bare=true.
|
|
|
|
*/
|
|
|
|
if (!git_configset_get_bool(&cs, "core.bare", &bare) && bare) {
|
|
|
|
if ((res = move_config_setting("core.bare", "true",
|
|
|
|
common_config_file,
|
|
|
|
main_worktree_file)))
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If core.worktree is set, then the main worktree is located
|
|
|
|
* somewhere different than the parent of the common Git dir.
|
|
|
|
* Relocate that value to avoid breaking all worktrees with this
|
|
|
|
* upgrade to worktree config.
|
|
|
|
*/
|
config: pass kvi to die_bad_number()
Plumb "struct key_value_info" through all code paths that end in
die_bad_number(), which lets us remove the helper functions that read
analogous values from "struct config_reader". As a result, nothing reads
config_reader.config_kvi any more, so remove that too.
In config.c, this requires changing the signature of
git_configset_get_value() to 'return' "kvi" in an out parameter so that
git_configset_get_<type>() can pass it to git_config_<type>(). Only
numeric types will use "kvi", so for non-numeric types (e.g.
git_configset_get_string()), pass NULL to indicate that the out
parameter isn't needed.
Outside of config.c, config callbacks now need to pass "ctx->kvi" to any
of the git_config_<type>() functions that parse a config string into a
number type. Included is a .cocci patch to make that refactor.
The only exceptional case is builtin/config.c, where git_config_<type>()
is called outside of a config callback (namely, on user-provided input),
so config source information has never been available. In this case,
die_bad_number() defaults to a generic, but perfectly descriptive
message. Let's provide a safe, non-NULL for "kvi" anyway, but make sure
not to change the message.
Signed-off-by: Glen Choo <chooglen@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-06-29 03:26:27 +08:00
|
|
|
if (!git_configset_get_value(&cs, "core.worktree", &core_worktree, NULL)) {
|
2022-02-08 05:32:59 +08:00
|
|
|
if ((res = move_config_setting("core.worktree", core_worktree,
|
|
|
|
common_config_file,
|
|
|
|
main_worktree_file)))
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ensure that we use worktree config for the remaining lifetime
|
|
|
|
* of the current process.
|
|
|
|
*/
|
2023-05-26 09:33:00 +08:00
|
|
|
r->repository_format_worktree_config = 1;
|
2022-02-08 05:32:59 +08:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
git_configset_clear(&cs);
|
|
|
|
free(common_config_file);
|
|
|
|
free(main_worktree_file);
|
|
|
|
return res;
|
|
|
|
}
|