14

I need a reliable way to clone a github repo and paste it into a local directory using node.js and any necessary npm packages.

This code is using the nodegit library and doesn't work to clone a github repo. it creates a single folder named .git and copies none of the files from the repo. I have tried several libraries most of which have extremely complicated code or don't work. This was working before but now isn't. (it goes on and off as it pleases). pls help, I need a reliable code that clones a github repo from url and pastes it into a local directory. Thank you.

var nodegit = require('nodegit'),
    path = require('path');

var url = "https://github.com/atomicptr/dauntless-builder", //also tried https://github.com/atomicptr/dauntless-builder.git
    local = "C:/data",
    cloneOpts = {};

nodegit.Clone(url, local, cloneOpts).then(function (repo) {
    console.log("cloning succesful!");
    console.log("Cloned " + path.basename(url) + " to " + repo.workdir());
}).catch(function (err) {
    console.log(err);
});

this code shows no errors, yet doesn't actually work to clone the repo.

2
  • if you do not care if user has git installed, you can resolve to using child_process and exec method to execute commands Commented Aug 27, 2019 at 6:54
  • have you tried using the GitHub API's? or nodegit. Commented Aug 27, 2019 at 7:31

4 Answers 4

21

You can use shelljs for this.

const shell = require('shelljs')
const path = 'absolute/path/to/folder'
shell.cd(path)
shell.exec('git clone https://github.com/atomicptr/dauntless-builder')
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you :) would there also be a way to upload files from local machine to my github repo? if so can u please tell me? I am finding it quite hard to get any code working.
yes. you can do any commands in terminal in shelljs. for this example, you can add shell.cd('dauntless-builder') then, shell.exec('git push')
to work with GitHub you don't need to go through git, surely not CLI commands. also, git push won't work without authorization. you need to set the configuration using git config first.
@AZ_ you're against using CLI for accessing git repos??
10

Assuming you have git installed on the machine you could simply run the clone command from node.

const path = require('path');
const{ execSync } = require('child_process');

execSync('git clone repolink', {
  stdio: [0, 1, 2], // we need this so node will print the command output
  cwd: path.resolve(__dirname, ''), // path to where you want to save the file
})

4 Comments

Thank you :) would there also be a way to upload files from local machine to my github repo? if so can u please tell me? I am finding it quite hard to get any code working.
if you clone the repo with ssh instead of https and you set your ssh key corectly it shoul work with git push
This is the ideal solution as it doesn't require an npm package. It's also useful in that it uses execSync, which seems to be the only way to git clone from node without the process hanging, async exec f.ex never triggers the callback.
@ShukriAdams Do you have any links to that problem with async exec?
7

Try the git-clone npm package

npm i git-clone
var clone = require('git-clone');

clone(repo, targetPath, [options], cb);

Supported options:

git: path to git binary; default: git (optional).

shallow: when true, clone with depth 1 (optional).

checkout: revision/branch/tag to check out (optional).

1 Comment

although it offers very limited options . but its good to use
1

I didn't have access to installing Git on a Linux machine I was developing on (running on a web server), so running into this issue enough, I wrote a script in Node to use the Git API and do just that. And it honestly isn't that crazy at <100 lines. Also, it should work with vanilla node (which happened to be installed).

P.S. I've tested it on both Windows and Linux.

const fs = require('fs');
const path = require('path');
const https = require('https');

// Parse command-line arguments
const [repoOwner, repoName, branch] = process.argv.slice(2);

if (!repoOwner || !repoName || !branch) {
    console.error('Usage: node clone-repo.js <repoOwner> <repoName> <branch>');
    process.exit(1);
}

const baseUrl = `https://api.github.com/repos/${repoOwner}/${repoName}/contents`;

function fetchRepoContents(url) {
    return new Promise((resolve, reject) => {
        https.get(url, { headers: { 'User-Agent': 'node.js' } }, (res) => {
            let data = '';
            res.on('data', (chunk) => {
                data += chunk;
            });
            res.on('end', () => {
                resolve(JSON.parse(data));
            });
        }).on('error', (err) => {
            reject(err);
        });
    });
}

async function downloadFile(url, filePath) {
    return new Promise((resolve, reject) => {
        https.get(url, { headers: { 'User-Agent': 'node.js' } }, (res) => {
            const fileStream = fs.createWriteStream(filePath);
            res.pipe(fileStream);
            fileStream.on('finish', () => {
                fileStream.close();
                resolve();
            });
        }).on('error', (err) => {
            fs.unlink(filePath, () => {}); // Delete the file async. (avoid using callback)
            reject(err);
        });
    });
}

async function processContents(contents, basePath) {
    for (const item of contents) {
        const fullPath = path.join(basePath, item.name);
        if (item.type === 'dir') {
            fs.mkdirSync(fullPath, { recursive: true });
            console.log(`Created directory: ${fullPath}`);
            const dirContents = await fetchRepoContents(item.url);
            await processContents(dirContents, fullPath);
        } else if (item.type === 'file') {
            try {
                // Ensure the directory exists before downloading the file
                const dirPath = path.dirname(fullPath);
                if (!fs.existsSync(dirPath)) {
                    fs.mkdirSync(dirPath, { recursive: true });
                    console.log(`Created directory: ${dirPath}`);
                }
                await downloadFile(item.download_url, fullPath);
                console.log(`Downloaded file: ${fullPath}`);
            } catch (err) {
                console.error(`Error downloading file ${fullPath}:`, err);
            }
        } else {
            console.warn(`Unknown type for ${fullPath}: ${item.type}`);
        }
    }
}

async function main() {
    try {
        const contents = await fetchRepoContents(`${baseUrl}?ref=${branch}`);
        await processContents(contents, repoName);
        console.log('Repository cloned successfully');
    } catch (err) {
        console.error('Error cloning repository:', err);
    }
}

main();

Usage:

node clone-repo.js repoOwner repoName branch

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.