dotnet / dotnet/sdk

Support Git-based tool management

Open
#52,169 2 comments 0 reactions 0 assignees View on GitHub
Area-Tools help wanted
Dominant language
C#
Stars
3.2k
Forks
1.3k
PR merge metrics
PR metrics pending

Description

# Problem

Currently, `dotnet tool` (.NET 10) only supports installing tools from NuGet packages via package identifiers. So, a way to have an easier and more convenient way to install these tools directly from repositories isn’t there, it supports ways to install local projects/tools via packaging and then reinstalling, but that’s it.

There are community tools like `dotnet-git-tool`, but: it's very basic, (outdated) lastly updated in 2019, and a first-class support for this use case scenario is somehow expected as other languages such as Rust’s Cargo, Go, Bun (JS), Deno (JS), and (the best implementation in my opinion) Python’s uv from Astral tooling, have it.

# Requirements

Overall, add Git repository tool management support to `dotnet tool` , similar to one uv’s implementation (as a reference point).

## Installation, removal, update and listing

Allow installation, listing, removal and update of these tools, some proposed syntax for installation URLs could be:

```bash
# Explicit
dotnet tool install --git URL
# Implicit
dotnet tool install URL.git
```

For NuGets, the syntax basically remains the same, just by IDs, as currently is.

## Handing subdirectories or multiple projects

Allow installation from subdirectories (in the case of uv, they have a *PEP 508* which standardizes the behavior such as `uv tool install git+#subdirectory=`)

For .NET’s case given that’s easier thanks to project files and solutions, at least is most defined, there could be the something like a project flag: `dotnet tool install --global --git --project `

## Git reference management with commits, branches and tags

Allow installation specifying the tag, branch or commit.

Such syntax could be:

- Flag-based (like Cargo’s), which could be specific, or generic:
- Generic: `dotnet tool install --git URL --git-ref `
- Specific: `dotnet tool install --git URL --`
- URL-based (like uv’s *but it depends on the PEP 508, so one specification would be needed to define this much better, considering that it also handles subdirectories/projects*): `dotnet tool install --git |url[tag]>`

## .NET tools schema

A way to extend it with Git support might be:

```jsonc
{
"version": 1,
"isRoot": true,
"tools": {
"my-tool": {
"version": "1.0.0",
"commands": ["my-tool"],
"source": "git",
"git": {
"url": "https://github.com/user/repo",
"ref": "v1.0.0",
"commit": "abc123",
"project": "src/MyTool/MyTool.csproj"
}
},
"nuget-tool": {
"version": "2.0.0",
"commands": ["nuget-tool"]
// existing nuget format remains unchanged
}
}
}
```

## Extensibility in sources

Considering a design that should allow for future source types:

- Local directories (partially covered)
- HTTP(S) direct downloads of .nupkg
- Private registry protocols
- Container registries (OCI artifacts)

Then a suggested source type identifier scheme should be:

- `nuget:PackageId` (default, implicit)
- `git+https://...` or `-git` flag
- `file:///path/to/project`
- Future: `oci://`, `http://`, etc.

# Behavioral requirements

## Git tooling: Shelling out vs. library

As for context with other tools:

- uv migrated from using a library
- Go uses the user shell
- GitKraken migrate to the CLI
- Cargo maintains usage of a library `libgit2` and the `gitoxide` for development.

Each obviously has its pros and cons, but I’m not quite sure whether .NET would find it more beneficial to add a Git library for these operations.

The main benefit I could think of CLI, is setup and auth depends on the user’s end, so it respects their credentials.

As a library, there is a deeper control but yeah, it’s a new bundled dependency.

## Packaging and build strategy: packing vs publishing

At first, I thought yeah maybe publishing makes more sense, but dotnet pack feels more correct for the main reason of the project metadata, the user is expected to set their project to be packaged as a tool, plus a special name for the tool, considering the conventional nature of Pascal Case projects.

There could be also alternative or hybrid approaches such as:

- Force the project to be packaged with a flag, plus an additional name if conventional.
- Using publishing it’s confusing for me as I find both building (release) and publishing similar, except the fact that publishing gathers dependencies and allows for self-contained apps, but in this scenario, the user is expected to have the respective .NET SDK (which I think it’s also an issue with .NET or maybe not, that it allows for example, the installation of such tool like Git tool, which requires the .NET 3, so it installs it fine, but the user at the end still needs to download the runtime/SDK to use it, I’m not sure if it would be better to not let the user install those tools unless it first has the respective version), so self-containing doesn’t feel useful, as well that using pack, bundles some extra metadata for later usage.

Therefore, the primary approach might be better using`dotnet pack`

- Projects MUST have `true` set (or use `-force-pack` flag)
- Respects project's target framework, dependencies, and build configuration
- Works with projects using MSBuild customizations
- No assumptions about Trimming, AOT, or other features

Rationale: `dotnet pack` is the standard way to create .NET tools and already handles project references, package references, and metadata

Build process: clone, pack, and install it via tool interface.

Caching is something confusing, uv caches it for the sake of easier and faster updates, while Cargo traditionally by default clones and builds it once, and when the user wants to update it, it needs to be cloned and built from scratch all over.

# Extra requirements

## Pinning to a commit

Allow un/pinning to a specific commit when one needs to upgrade all tools, so it gets ignored.

## Update to another git reference

Allow switching (updating) to a branch or tag

## Aliases for the installed tools

In cases where the projects remain with pascal case names.

## On-demand installation of respective SDKs

Automatically install the specific runtime or SDK based on the global JSON or target framework.

Since it basically requires building, for non-compatible versions with the user’s current tools, do version checks once cloned to with global JSON or project metadata to avoid failed builds.

## Local filesystem and repositories

Expecting the usual usage to be mostly with remote URLs, local usage could be done with:

```bash
dotnet tool install . # for current diretory/project
dotnet tool install
dotnet tool install file://
dotnet tool install , but these being git repos
```

- Alongside Git-based tool management, maybe allow direct installation of local repositories or directories easily, such as `dotnet tool install --global ./MyProject.csproj`, which is tracked for updates.

## Git LFS and submodules

- For submodules, it could default to using `git clone --recurse-submodules` for build safety.
- For LFS, I suppose/assume most projects don’t take LFS as part of build process, but in those cases, a Boolean flag could be used.

# Additional context and references

- The main reference to the tool would be Python's uv from Astral (https://github.com/astral-sh/uv) which does an amazing job at managing tool installations via git.
- .NET git tool: https://github.com/yaegaki/dotnet-git-tool
- https://github.com/astral-sh/uv/pull/3833
- https://github.com/golang/go/blob/master/src/cmd/go/internal/vcs/vcs.go
- https://www.gitkraken.com/blog/gitkraken-client-migrating-from-libgit2-to-git-executable
- https://github.com/rust-lang/cargo/blob/master/src/cargo/sources/git/
- https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-pack
- https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-publish
- https://learn.microsoft.com/en-us/visualstudio/msbuild/common-msbuild-project-properties
- https://learn.microsoft.com/en-us/nuget/create-packages/creating-a-package-msbuild
- https://learn.microsoft.com/en-us/dotnet/core/tools/troubleshoot-usage-issues
- https://peps.python.org/pep-0508/

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.