Git Product home page Git Product logo

git's Introduction

@npmcli/git

A utility for spawning git from npm CLI contexts.

This is not an implementation of git itself, it's just a thing that spawns child processes to tell the system git CLI implementation to do stuff.

USAGE

const git = require('@npmcli/git')
git.clone('git://foo/bar.git', 'some-branch', 'some-path', opts) // clone a repo
  .then(() => git.spawn(['checkout', 'some-branch'], {cwd: 'bar'}))
  .then(() => git.spawn(['you get the idea']))

API

Most methods take an options object. Options are described below.

git.spawn(args, opts = {})

Launch a git subprocess with the arguments specified.

All the other functions call this one at some point.

Processes are launched using @npmcli/promise-spawn, with the stdioString: true option enabled by default, since git output is generally in readable string format.

Return value is a Promise that resolves to a result object with {cmd, args, code, signal, stdout, stderr} members, or rejects with an error with the same fields, passed back from @npmcli/promise-spawn.

git.clone(repo, ref = 'HEAD', target = null, opts = {}) -> Promise<sha String>

Clone the repository into target path (or the default path for the name of the repository), checking out ref.

Return value is the sha of the current HEAD in the locally cloned repository.

In lieu of a specific ref, you may also pass in a spec option, which is a npm-package-arg object for a git package dependency reference. In this way, you can select SemVer tags within a range, or any git committish value. For example:

const npa = require('npm-package-arg')
git.clone('[email protected]:npm/git.git', '', null, {
  spec: npa('github:npm/git#semver:1.x'),
})

// only gitRange and gitCommittish are relevant, so this works, too
git.clone('[email protected]:npm/git.git', null, null, {
  spec: { gitRange: '1.x' }
})

This will automatically do a shallow --depth=1 clone on any hosts that are known to support it. To force a shallow or deep clone, you can set the gitShallow option to true or false respectively.

git.revs(repo, opts = {}) -> Promise<rev doc Object>

Fetch a representation of all of the named references in a given repository. The resulting doc is intentionally somewhat packument-like, so that git semver ranges can be applied using the same npm-pick-manifest logic.

The resulting object looks like:

revs = {
  versions: {
    // all semver-looking tags go in here...
    // version: { sha, ref, rawRef, type }
    '1.0.0': {
      sha: '1bc5fba3353f8e1b56493b266bc459276ab23139',
      ref: 'v1.0.0',
      rawRef: 'refs/tags/v1.0.0',
      type: 'tag',
    },
  },
  'dist-tags': {
    HEAD: '1.0.0',
    latest: '1.0.0',
  },
  refs: {
    // all the advertised refs that can be cloned down remotely
    HEAD: { sha, ref, rawRef, type: 'head' },
    master: { ... },
    'v1.0.0': { ... },
    'refs/tags/v1.0.0': { ... },
  },
  shas: {
    // all named shas referenced above
    // sha: [list, of, refs]
    '6b2501f9183a1753027a9bf89a184b7d3d4602c7': [
      'HEAD',
      'master',
      'refs/heads/master',
    ],
    '1bc5fba3353f8e1b56493b266bc459276ab23139': [ 'v1.0.0', 'refs/tags/v1.0.0' ],
  },
}

git.is(opts) -> Promise<Boolean>

Resolve to true if the path argument refers to the root of a git repository.

It does this by looking for a file in ${path}/.git/index, which is not an airtight indicator, but at least avoids being fooled by an empty directory or a file named .git.

git.find(opts) -> Promise<String | null>

Given a path, walk up the file system tree until a git repo working directory is found. Since this calls stat a bunch of times, it's probably best to only call it if you're reasonably sure you're likely to be in a git project somewhere. Pass in opts.root to stop checking at that directory.

Resolves to null if not in a git project.

git.isClean(opts = {}) -> Promise<Boolean>

Return true if in a git dir, and that git dir is free of changes. This will resolve true if the git working dir is clean, or false if not, and reject if the path is not within a git directory or some other error occurs.

OPTIONS

  • retry An object to configure retry behavior for transient network errors with exponential backoff.
    • retries: Defaults to opts.fetchRetries or 2
    • factor: Defaults to opts.fetchRetryFactor or 10
    • maxTimeout: Defaults to opts.fetchRetryMaxtimeout or 60000
    • minTimeout: Defaults to opts.fetchRetryMintimeout or 1000
  • git Path to the git binary to use. Will look up the first git in the PATH if not specified.
  • spec The npm-package-arg specifier object for the thing being fetched (if relevant).
  • fakePlatform set to a fake value of process.platform to use. (Just for testing win32 behavior on Unix, and vice versa.)
  • cwd The current working dir for the git command. Particularly for find and is and isClean, it's good to know that this defaults to process.cwd(), as one might expect.
  • Any other options that can be passed to @npmcli/promise-spawn, or child_process.spawn().

git's People

Contributors

commanderroot avatar dependabot[bot] avatar ferdinando-ferreira avatar github-actions[bot] avatar isaacs avatar lukekarrys avatar nlf avatar regevbr avatar ruyadorno avatar thecodrr avatar wraithgar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

git's Issues

[BUG] yarn 2 pnp issues

The library requires the lru-cache and semver packages but they are not declared as dependencies.
This is done at

const LRU = require('lru-cache')
and
const semver = require('semver')

Because yarn 2 uses PlugNPlay, it is not allowed to use non declared dependencies, causing my CI tools to fail

Temp fix is to add to .yarnrc.yml

packageExtensions:
  "@npmcli/git@*":
    dependencies:
      lru-cache: "*"
      semver: "*"

[BUG] npm run test fails for all git versions below 2.28.0

What / Why

npm run test for this package fails (for instance) on the latest release of Ubuntu (20.10 groovy) fully upgraded. It happens due the latest stable version of the git command line being 2.27.0 on that distro.

When

Fails for every attempt with a git version below 2.28.0

Where

  • n/a

How

Current Behavior

Git cloning the repository on any machine with a version of git installed below 2.28.0 and running npm run test fails

Steps to Reproduce

On any machine with git below 2.28.0 installed (for instance, a fully upgraded Ubuntu 20.10 machine) execute the following commands:

mkdir tests
cd tests
git clone https://github.com/npm/git.git git
cd git/
npm install
npm run test

The expected result would be all tests passing. The obtained result is:

> @npmcli/[email protected] test /home/user/tests/git
> tap

 PASS  test/env.js 4 OK 111.436ms
 PASS  test/find.js 3 OK 130.919ms
 PASS  test/index.js 1 OK 55.775ms
 PASS  test/is-clean.js 6 OK 894.282ms
 PASS  test/is.js 5 OK 115.166ms
 PASS  test/lines-to-revs.js 22 OK 99.539ms
 PASS  test/opts.js 2 OK 77.576ms
 FAIL  test/revs.js
 ✖ command failed

      if (code || signal)
        rej(Object.assign(new Error('command failed'), result))
--------------------------^
      else
        res(result)

  test: setup
  stack: |
    ChildProcess.<anonymous> (node_modules/@npmcli/promise-spawn/index.js:63:27)
  at:
    line: 63
    column: 27
    file: node_modules/@npmcli/promise-spawn/index.js
    function: ChildProcess.<anonymous>
  cmd: /usr/bin/git
  args:
    - init
    - -b
    - main
  code: 129
  signal: null
  stdout: ""
  stderr: >+
    error: unknown switch `b'

    usage: git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [<directory>]

        --template <template-directory>
                              directory from which templates will be used
        --bare                create a bare repository
        --shared[=<permissions>]
                              specify that the git repository is to be shared amongst several users
        -q, --quiet           be quiet
        --separate-git-dir <gitdir>
                              separate git dir from working tree
        --object-format <hash>
                              specify the hash algorithm to use

  tapCaught: returnedPromiseRejection

 FAIL  test/revs.js
 ✖ command failed

      if (code || signal)
        rej(Object.assign(new Error('command failed'), result))
--------------------------^
      else
        res(result)

  test: point latest at HEAD
  stack: |
    ChildProcess.<anonymous> (node_modules/@npmcli/promise-spawn/index.js:63:27)
  at:
    line: 63
    column: 27
    file: node_modules/@npmcli/promise-spawn/index.js
    function: ChildProcess.<anonymous>
  cmd: /usr/bin/git
  args:
    - ls-remote
    - /home/user/tests/git/test/revs
  code: 128
  signal: null
  stdout: ""
  stderr: |
    fatal: '/home/user/tests/git/test/revs' does not appear to be a git repository
    fatal: Could not read from remote repository.

    Please make sure you have the correct access rights
    and the repository exists.
  tapCaught: returnedPromiseRejection

 FAIL  test/revs.js
 ✖ command failed

      if (code || signal)
        rej(Object.assign(new Error('command failed'), result))
--------------------------^
      else
        res(result)

  test: add a latest branch, point to 1.2.3 version
  stack: |
    ChildProcess.<anonymous> (node_modules/@npmcli/promise-spawn/index.js:63:27)
  at:
    line: 63
    column: 27
    file: node_modules/@npmcli/promise-spawn/index.js
    function: ChildProcess.<anonymous>
  cmd: /usr/bin/git
  args:
    - reset
    - --hard
    - version-1.2.3
  code: 128
  signal: null
  stdout: ""
  stderr: >
    fatal: ambiguous argument 'version-1.2.3': unknown revision or path not in the
    working tree.

    Use '--' to separate paths from revisions, like this:

    'git <command> [<revision>...] -- [<file>...]'
  tapCaught: returnedPromiseRejection

 FAIL  test/revs.js
 ✖ command failed

      if (code || signal)
        rej(Object.assign(new Error('command failed'), result))
--------------------------^
      else
        res(result)

  test: check the revs
  stack: |
    ChildProcess.<anonymous> (node_modules/@npmcli/promise-spawn/index.js:63:27)
  at:
    line: 63
    column: 27
    file: node_modules/@npmcli/promise-spawn/index.js
    function: ChildProcess.<anonymous>
  cmd: /usr/bin/git
  args:
    - ls-remote
    - /home/user/tests/git/test/revs
  code: 128
  signal: null
  stdout: ""
  stderr: |
    fatal: '/home/user/tests/git/test/revs' does not appear to be a git repository
    fatal: Could not read from remote repository.

    Please make sure you have the correct access rights
    and the repository exists.
  tapCaught: returnedPromiseRejection

 FAIL  test/revs.js 4 failed of 4 921.343ms
 ✖ command failed
 ✖ command failed
 ✖ command failed
 ✖ command failed

 PASS  test/should-retry.js 3 OK 90.277ms
 PASS  test/clone.js 115 OK 22s
 PASS  test/which.js 5 OK 1s
 PASS  test/spawn.js 6 OK 4s


  🌈 SUMMARY RESULTS 🌈


 FAIL  test/revs.js 4 failed of 4 921.343ms
 ✖ command failed
 ✖ command failed
 ✖ command failed
 ✖ command failed

Suites:   1 failed, 11 passed, 12 of 12 completed
Asserts:  4 failed, 172 passed, of 176
Time:     33s

Expected Behavior

npm run test should succeed in an unchanged repository

[BUG] git worktree support

When running npm version ... a commit/tag isn't created when you run within a git worktree. We should be able to detect when there's a ref to follow (ie. gitdir) inside a relative .git file. Need to update lib/is.js to understand this scenario....

feat: implement caching

currently every operation performed through this module has to maintain its own cache. pacote half implements some form of caching, but now that we don't keep integrity values for locally built tarballs (i.e. git repositories) pacote will never actually use the cache.

in order to resolve this, i propose that we implement git specific caching semantics in this module.

these are just some thoughts i had about how this could work, that may or may not be useful when we implement.

ideally, we use cacache so that we maintain consistency in our caching locations. this gives us a tiny bit of a challenge, however, in that we would need to cache specific entities in different ways

  1. package.json (including corgis, so this is really two entities in one key similar to how make-fetch-happen handles different accept headers and content-types
  2. npm-shrinkwrap.json if the package has one present, we need it accessible
  3. a built tarball, meaning we've cloned the repo, checked out the appropriate reference, installed dependencies and run prepare scripts (if necessary), and run npm pack

where we start to venture into uncharted waters is with regards to how we identify and correctly handle stale repositories. to this end, i think one approach we could take is to also store a tarball comprising of the raw git repository in the cache. this tarball would be used as a means of determining if the requested reference has changed or not. the flow would look something like this:

  • request the raw git repository from cacache or clone it
  • extract the raw git repository (if we just cloned it, skip this)
  • update the raw git repository (git fetch, again skip if we just cloned)
  • resolve the requested git ref to a commit hash
  • attempt to read the requested file from the cache, use the commit hash as an etag of sorts
  • if the file does not exist, do what is necessary to retrieve it and store it

this would mean that every installation of a git repository will require us to extract a tarball of the repository, and do a git fetch before retrieving anything but that's a very considerably better state than we have today where we clone the entire repository from scratch every time we need something from it.

[BUG] npm run test leaves a test/is-clean folder behind, on Windows, after running

What / Why

npm run test leaves a test/is-clean folder behind, on Windows, after running

When

  • n/a

Where

  • n/a

How

  • n/a

Current Behavior

Git cloning the repository on Windows and running npm run test leaves a test/is-clean folder behind even when the test is successful.

Steps to Reproduce

On a Windows machine execute the following commands:

mkdir tests
cd tests
git clone [email protected]:npm/git.git git
cd git
npm install
npm run test

Expected Behavior

npm run test should leave no temporary folder after a successful run

[BUG] npm run test fails on machines where the tests take more than 30 seconds

What / Why

npm run test fails on machines where the tests take more than 30 seconds

When

  • n/a

Where

  • n/a

How

  • n/a

Current Behavior

Git cloning the repository on Windows and running npm run test fails

Steps to Reproduce

On a Windows machine execute the following commands:

mkdir tests
cd tests
git clone [email protected]:npm/git.git git
cd git
npm install
npm run test

The expected result would be all tests passing. The obtained result is:

> @npmcli/[email protected] test
> tap

 PASS  test/find.js 3 OK 185.154ms
 PASS  test/is.js 5 OK 184.057ms
 PASS  test/opts.js 2 OK 134.044ms
 PASS  test/env.js 4 OK 15.652ms
 PASS  test/index.js 1 OK 16.549ms
 PASS  test/lines-to-revs.js 22 OK 91.419ms
 PASS  test/is-clean.js 6 OK 2s
 PASS  test/should-retry.js 3 OK 15.07ms
 FAIL  test/spawn.js
 ✖ expect resolving Promise

  --- expected
  +++ actual
  @@ -1,3 +1,3 @@
   Object {
  -  "stdout": "Initialized empty Git repository in c:/tests/git/test/spawn",
  +  "stdout": "Initialized empty Git repository in C:/tests/git/test/spawn/.git/\n",
   }

  test: test/spawn.js setup repo
  at:
    line: 22
    column: 12
    file: test/spawn.js
    type: Test

 PASS  test/which.js 5 OK 1s
 PASS  test/revs.js 20 OK 2s
 FAIL  test/spawn.js 1 failed of 6 4s
 ✖ expect resolving Promise

 FAIL  test/clone.js
 ✖ timeout!

  test: test/clone.js again, with a submodule
  expired: test/clone.js

 FAIL  test/clone.js
 ✖ timeout!

 FAIL  test/clone.js 2 failed of 33 31s
 ✖ timeout!
 ✖ timeout!

  🌈 SUMMARY RESULTS 🌈

 FAIL  test/clone.js 2 failed of 33 31s
 ✖ timeout!
 ✖ timeout!

 FAIL  test/spawn.js 1 failed of 6 4s
 ✖ expect resolving Promise

Suites:   2 failed, 10 passed, 12 of 12 completed
Asserts:  3 failed, 107 passed, of 110
Time:     31s

Expected Behavior

npm run test should succeed in an unchanged repository

[BUG] npm run test fails on Windows

What / Why

npm run test for this package fails on windows

When

Always

Where

  • n/a

How

Current Behavior

Git cloning the repository on Windows and running npm run test fails

Steps to Reproduce

On a Windows machine execute the following commands:

mkdir tests
cd tests
git clone [email protected]:npm/git.git git
cd git
npm install
npm run test

The expected result would be all tests passing. The obtained result is:

> @npmcli/[email protected] test
> tap

 PASS  test/find.js 3 OK 185.154ms
 PASS  test/is.js 5 OK 184.057ms
 PASS  test/opts.js 2 OK 134.044ms
 PASS  test/env.js 4 OK 15.652ms
 PASS  test/index.js 1 OK 16.549ms
 PASS  test/lines-to-revs.js 22 OK 91.419ms
 PASS  test/is-clean.js 6 OK 2s
 PASS  test/should-retry.js 3 OK 15.07ms
 FAIL  test/spawn.js
 ✖ expect resolving Promise

  --- expected
  +++ actual
  @@ -1,3 +1,3 @@
   Object {
  -  "stdout": "Initialized empty Git repository in c:/tests/git/test/spawn",
  +  "stdout": "Initialized empty Git repository in C:/tests/git/test/spawn/.git/\n",
   }

  test: test/spawn.js setup repo
  at:
    line: 22
    column: 12
    file: test/spawn.js
    type: Test

 PASS  test/which.js 5 OK 1s
 PASS  test/revs.js 20 OK 2s
 FAIL  test/spawn.js 1 failed of 6 4s
 ✖ expect resolving Promise

 FAIL  test/clone.js
 ✖ timeout!

  test: test/clone.js again, with a submodule
  expired: test/clone.js

 FAIL  test/clone.js
 ✖ timeout!

 FAIL  test/clone.js 2 failed of 33 31s
 ✖ timeout!
 ✖ timeout!

  🌈 SUMMARY RESULTS 🌈

 FAIL  test/clone.js 2 failed of 33 31s
 ✖ timeout!
 ✖ timeout!

 FAIL  test/spawn.js 1 failed of 6 4s
 ✖ expect resolving Promise

Suites:   2 failed, 10 passed, 12 of 12 completed
Asserts:  3 failed, 107 passed, of 110
Time:     31s

Expected Behavior

npm run test should succeed in an unchanged repository

Reporting a vulnerability

Hello!

I hope you are doing well!

We are a security research team. Our tool automatically detected a vulnerability in this repository. We want to disclose it responsibly. GitHub has a feature called Private vulnerability reporting, which enables security research to privately disclose a vulnerability. Unfortunately, it is not enabled for this repository.

Can you enable it, so that we can report it?

Thanks in advance!

PS: you can read about how to enable private vulnerability reporting here: https://docs.github.com/en/code-security/security-advisories/repository-security-advisories/configuring-private-vulnerability-reporting-for-a-repository

Remove mkdirp with fs.mkdir recursive ?

What / Why

Hi, would you be ok for a pull-request to replace mkdirp with the new native fs.mkdir recursive method ?

This is a Node.js 10.12.0 addition and Node.js 8 is EOL now so i guess the timing is ok.

Best Regards,
Thomas

[BUG] StrictHostKeyChecking=accept-new causes install failure on OpenSSH <7.6

As seen in the comments on npm/cli#3233 and #7, trying to install a git repository with the current npm CLI fails
when using OpenSSH <7.6 with the following:

npm ERR! command git --no-replace-objects ls-remote ssh://[email protected]/foo/bar.git
npm ERR! command-line line 0: unsupported option "accept-new".
npm ERR! fatal: Could not read from remote repository.

While the change is in theory a good one (I was caught off guard with the old behavior when cloning a repository failed due to a missing host key), it creates issues in practice.

  • OpenSSH >= 7.6 probably can't be expected - at the very least in my case, on an up-to-date Amazon Linux, I'm stuck with 7.4p1 from the repositories, and I'd rather not compile from source.
  • This implementation overrides .git/config and ~/.gitconfig, contrary to the PR (and ~/.ssh/config as well, as someone pointed out)

Proposals I've seen include:

  • Verifying the current ssh version (ssh -V) before attempting to use accept-new
  • Wholesale reversion of #7

[BUG] Cannot install git package without HEAD ref

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

npm install fails to clone branch, commit hash or tag when the repo does not have a HEAD reference.

Error Message:
`npm ERR! Cannot read properties of undefined (reading 'sha')

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\user\AppData\Local\npm-cache_logs\2023-01-26T12_33_01_788Z-debug-0.log`

Expected Behavior

It should still be able to clone the specified reference.

Steps To Reproduce

  1. Run npm install ssh+git://git@private/private_repo#reference
  2. Wait for the error to show up.
    `npm ERR! Cannot read properties of undefined (reading 'sha')

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\user\AppData\Local\npm-cache_logs\2023-01-26T12_33_01_788Z-debug-0.log`

Environment

  • npm: 9.3.1
  • Node: v16.14.2
  • OS: Windows 11 Pro 21H2 22000.1455 Windows Feature Experience Pack 1000.22000.1455.0
  • platform:

[BUG] GIT_SSH_COMMAND should honor GIT_SSH

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

Currently GIT_SSH_COMMAND has hardcoded ssh path in https://github.com/npm/git/blob/v4.0.4/lib/opts.js#L5

But there is also GIT_SSH env. var honored by standard git. The GIT_SSH_COMMAND should use GIT_SSH (and quoted) instead of ssh when GIT_SSH is non-empty.

Will fix npm/cli#2891 as I can confirm npm/cli#2891 (comment) fixes the problem.

image

Expected Behavior

GIT_SSH other than ssh/empty is honored.

[BUG] Packages installed from git+https on Windows when the tmp directory contains spaces

What / Why

There is already a description at length of this bug on npm/cli#2414 but a minimal use case can be provided if necessary

When

Whenever npm install is run on a Windows system containing spaces in the path of the temporary folder when a git+https package is in package.json

Where

npm/cli

How

Current Behavior

npm install fails with the following error:

npm ERR! code 129
npm ERR! command failed
npm ERR! command git clone <repo> <target containing spaces> --recurse-submodules --depth=1 --config core

Steps to Reproduce

A minimal reproducible usecase can be provided if necessary for this issue to be solved but, as #9 is a very straightforward fix, it may not be necessary

Expected Behavior

npm install installs the package

Who

  • n/a

References

Related to npm/cli#2414

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.