Skip to content

Worktree implementation#3436

Merged
ethomson merged 31 commits into
libgit2:masterfrom
pks-t:libgit2-worktree
Feb 13, 2017
Merged

Worktree implementation#3436
ethomson merged 31 commits into
libgit2:masterfrom
pks-t:libgit2-worktree

Conversation

@pks-t
Copy link
Copy Markdown
Member

@pks-t pks-t commented Sep 23, 2015

These patches introduce initial support for work trees, which have been introduced with git v.2.5.

Criticism and proposals welcome.

Things that need to be tackled in order to work with $COMMONDIR:

  • ref lookup
  • loose lookup
  • packed lookup
  • config
  • logs/

The following directories are not really used by us but would require to be made aware of $COMMONDIR:

  • shallow/
  • info/
  • remotes/ (legacy)
  • branches/ directory (legacy)
  • hooks/

Additional things that need to be cared about:

  • creating new working trees
  • restrictions on ability to check out refs that are being linked to
  • restrictions on ability to delete refs that are being linked to (only enforced for git_branch_delete function)
  • pruning (abandoned) working trees
  • renaming references?

Comment thread src/refdb_fs.c Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect that we should give this a more meaningful name. (And the is_symbolic_ref function, also, below.) You could have a symbolic ref refs/heads/foo -> refs/heads/bar, which would be in the commondir not the gitdir.

I don't have any brilliant ideas though. Special refs? Local refs? Workdir refs?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something like uncommon_refs, as those would not be stored in the common directory. Not exactly happy with this name, though, but I'd prefer either this or workdir_refs.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that these are often referred to as pseudorefs in git, or per-worktree refs, as they exist at the top level and exist for each worktree.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed this array altogether as there is currently only one per-worktree ref that needs to be handled this way, which is HEAD. I've also renamed is_symbolic_ref to is_per_worktree_ref.

@ethomson
Copy link
Copy Markdown
Member

Nice! I'm happy to see that you decided to tackle this, and it looks like this is going to be a nice and clean implementation.

I made a couple of minor comments, but I like where this is going.

@pks-t
Copy link
Copy Markdown
Member Author

pks-t commented Sep 23, 2015

Eh. I've already fixed some issues you mention, especially the link-path being relative. Seems I've got an out of date branch on this computer.

Comment thread src/refdb_fs.c Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this seems to be missing MERGE_HEAD and FETCH_HEAD, or are those handled differently? Is there really a list of these or should we perform the {_,}HEAD suffix check like we do to determine if we want to allow writing to a particular ref?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, those aren't really refs, per se, they're sort of ref-like but in a non-ref irregular format and should be outside the scope of the refdb.

Though to be completely honest, I would have expected the same was true for ORIG_HEAD. Do we really use the refdb infrastructure for ORIG_HEAD?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are pseudorefs, as @carlosmn previously pointed out (see gmane).
The list was not complete yet, wanted to come back to it later. Should've left a TODO in there, I guess. I don't exactly know how pseudorefs are handled yet, I'll have to figure that out.

@pks-t
Copy link
Copy Markdown
Member Author

pks-t commented Sep 24, 2015

Rebase onto master and fixed the absolute gitdir path. No changes yet besides that.

@pks-t pks-t force-pushed the libgit2-worktree branch 2 times, most recently from 6e9b4aa to 71f82df Compare October 21, 2015 10:14
@pks-t
Copy link
Copy Markdown
Member Author

pks-t commented Oct 21, 2015

I've done some bugfixing, cleanup and further implementation now. As far as opening and acting on worktree-repositories goes I'm currently not aware of any gaping holes, at least it seems to work fine now. Object store, packed refs, loose refs, reflog and configs are all accessible and seem to work, even though I did not yet do any major testing (will do that when I consider this feature ready).

In addition to git_repository_open support for working trees I've now started a new interface that acts on working trees for a given repository. I want it to make available the same functionality as the upstream git worktree command does, that is listing worktrees, creating new worktrees and pruning old ones. Currently I've only implemented listing worktrees and opening them, everything else will follow soon-ish.

One more missing thing is preventing the user from checking out branches that are already checked out by any worktree, as upstream git does. Guess I'll add a ref-field to struct git_worktree that will show which reference is currently checked out and use that in the checkout codepath.

I think the current state (excluding items that are still todo and the WIP-commit) is somewhat sane and cleaned up, so I'd appreciate some feedback.

@Therzok
Copy link
Copy Markdown
Member

Therzok commented Oct 21, 2015

@pks-t
Copy link
Copy Markdown
Member Author

pks-t commented Oct 21, 2015

Meh... will fix some time later this week.

@pks-t
Copy link
Copy Markdown
Member Author

pks-t commented Oct 23, 2015

sigh No luck for me, I guess. Seems as if AppVeyor is having a hiccup right now.

@pks-t pks-t force-pushed the libgit2-worktree branch 7 times, most recently from 7a3cf8d to aa5a48b Compare November 2, 2015 15:48
@pks-t pks-t force-pushed the libgit2-worktree branch 2 times, most recently from f60a3fb to b69d987 Compare November 6, 2015 11:42
@pks-t pks-t changed the title [WIP,RFC] worktree implementation Worktree implementation Nov 6, 2015
@pks-t
Copy link
Copy Markdown
Member Author

pks-t commented Nov 6, 2015

I consider this branch feature complete now. Some points that remain:

  • The test suite on AppVeyor fails somehow. I cannot explain why and am not able to reproduce this error with either Visual Studio 2015 or the Cygwin toolchain. I'll try to get my hands on the compilers/runtimes used by AppVeyor and debug it some times soon.
  • Restrictions on references are currently only enforced for the branch API, that is only for git_branch_delete. This is based on the fact that the current refs API does not do any protection of checked out branches, not even for the current HEAD branch in a normal repository.

@ethomson @carlosmn I'd appreciate if you could review the changes as soon as you find the time to do so.

pks-t added 20 commits February 13, 2017 10:28
A repository's configuartion file can always be found in the
GIT_COMMON_DIR, which has been newly introduced. For normal
repositories this does change nothing, but for working trees this
change allows to access the shared configuration file.
Expose the function `repo_init_create_head` as
`git_repository_create_head`.
Add new module for working trees with the `git_worktree_list`
function. The function lists names for all working trees of a
certain repository.
Introduce a new `struct git_worktree`, which holds information
about a possible working tree connected to a repository.
Introduce functions to allow opening working trees for a
repository.
Add function `git_repository_open_from_worktree`, which allows to open a
`git_worktree` as repository.
Add a new function that checks wether a given `struct
git_worktree` is valid. The validation includes checking if the
gitdir, parent directory and common directory are present.
Implement the `git_worktree_add` function which can be used to create
new working trees for a given repository.
Working trees support locking by creating a file `locked` inside
the tree's gitdir with an optional reason inside. Support this
feature by adding functions to get and set the locking status.
Implement the `git_worktree_prune` function. This function can be
used to delete working trees from a repository. According to the
flags passed to it, it can either delete the working tree's
gitdir only or both gitdir and the working directory.
Implement `git_repository_head_for_worktree` and
`git_repository_head_detached_for_worktree` for directly accessing a
worktree's HEAD without opening it as a `git_repository` first.
Implement a new function that is able to determine if a branch is
checked out in any repository connected to the current
repository. In particular, this is required to check if for a
given repository and branch, there exists any working tree
connected to that repository that is referencing this branch.
Restrict the ability to delete branches that are checked out in
any linked repository.
If a branch is already checked out in a working tree we are not
allowed to check out that branch in another repository. Introduce
this restriction when setting a repository's HEAD.
The `path_repository` variable is actually confusing to think
about, as it is not always clear what the repository actually is.
It may either be the path to the folder containing worktree and
.git directory, the path to .git itself, a worktree or something
entirely different. Actually, the intent of the variable is to
hold the path to the gitdir, which is either the .git directory
or the bare repository.

Rename the variable to `gitdir` to avoid confusion. While at it,
also rename `path_gitlink` to `gitlink` to improve consistency.
When opening a worktree via the gitdir of its parent repository
we fail to correctly set up the worktree's working directory. The
problem here is two-fold: we first fail to see that the gitdir
actually is a gitdir of a working tree and then subsequently
fail to determine the working tree location from the gitdir.

The first problem of not noticing a gitdir belongs to a worktree
can be solved by checking for the existence of a `gitdir` file in
the gitdir. This file points back to the gitlink file located in
the working tree's working directory. As this file only exists
for worktrees, it should be sufficient indication of the gitdir
belonging to a worktree.

The second problem, that is determining the location of the
worktree's working directory, can then be solved by reading the
`gitdir` file in the working directory's gitdir. When we now
resolve relative paths and strip the final `.git` component, we
have the actual worktree's working directory location.
@ethomson ethomson merged commit 4f9f8e0 into libgit2:master Feb 13, 2017
@ethomson
Copy link
Copy Markdown
Member

🎉

Thanks again @pks-t !!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants