const shadower = co.wrap(function *(repos, mapping) { // If a meta commit was made, map it to "m" and create a branch // named "m" pointing to it. For each submodule commit made, // map the commit to one with that submodule's name, and make a // branch in the submodule with that name. const repo = repos.x; const message = c.message || "message\n"; const meta = c.includeMeta; const includeUntracked = undefined === c.includeUntracked || c.includeUntracked; const incrementTimestamp = (undefined === c.incrementTimestamp) ? false : c.incrementTimestamp; const result = yield StashUtil.makeShadowCommit( repo, message, incrementTimestamp, meta, includeUntracked, false); const commitMap = {}; if (null !== result) { const metaSha = result.metaCommit; const commit = yield repo.getCommit(metaSha); const head = yield repo.getHeadCommit(); if (incrementTimestamp) { assert.equal(commit.time(), head.time() + 1); } commitMap[metaSha] = "m"; yield NodeGit.Branch.create(repo, "m", commit, 1); for (let path in result.subCommits) { const subSha = result.subCommits[path]; const subRepo = yield SubmoduleUtil.getRepo(repo, path); const subCommit = yield subRepo.getCommit(subSha); if (!(subSha in mapping.commitMap)) { commitMap[subSha] = path; yield NodeGit.Branch.create(subRepo, path, subCommit, 1); } } } return { commitMap: commitMap, }; });
.then(function(ref) { if (git.Branch.delete(ref) === 0) { res.status(200).end(); } else { writeError(403, res); } })
.then(function(commit) { theCommit = commit; if (branch) { return git.Branch.create(theRepo, branch, commit, 0).then(function() { return theRepo.checkoutBranch("refs/heads/" + branch, checkOptions); }); } return git.Checkout.tree(theRepo, commit, checkOptions).then(function() { return theRepo.setHeadDetached(theCommit); }); });
repo.getBranchCommit(ref.shorthand()).then(function (commit) { nodegit.Branch.create(repo, thisHook.context.params.name, commit, 0).then(function (reference) { data.messages.push({ "message": "Branch created" }); thisHook.pass(data); }); });
exports.executeCheckout = co.wrap(function *(repo, commit, newBranch, switchBranch, force) { assert.instanceOf(repo, NodeGit.Repository); if (null !== commit) { assert.instanceOf(commit, NodeGit.Commit); } if (null !== newBranch) { assert.isObject(newBranch); assert.isString(newBranch.name); if (null !== newBranch.tracking) { assert.isObject(newBranch.tracking); if (null !== newBranch.tracking.remoteName) { assert.isString(newBranch.tracking.remoteName); } assert.isString(newBranch.tracking.branchName); } } if (null !== switchBranch) { assert.isString(switchBranch); } assert.isBoolean(force); // attempt the checkout first. if (null !== commit) { yield exports.checkoutCommit(repo, commit, force); } if (null !== newBranch) { const name = newBranch.name; const branch = yield GitUtil.createBranchFromHead(repo, name); const tracking = newBranch.tracking; if (null !== tracking) { const trackingName = tracking.branchName; const remote = tracking.remoteName; let trackingBranchName; if (null !== remote) { trackingBranchName = `${remote}/${trackingName}`; } else { trackingBranchName = trackingName; } yield NodeGit.Branch.setUpstream(branch, trackingBranchName); } } if (null !== switchBranch) { yield repo.setHead(`refs/heads/${switchBranch}`); } });
const commitAndBranch = co.wrap(function *(treeId, type) { const tree = yield NodeGit.Tree.lookup(repo, treeId); const commitId = yield NodeGit.Commit.create(repo, null, sig, sig, null, type, tree, 0, []); const commit = yield repo.getCommit(commitId); yield NodeGit.Branch.create(repo, type, commit, 1); commitMap[commitId.tostrS()] = type; });
return Promise.all(branches.map(function(branch) { return git.Branch.lookup(repo, api.join(remote.name(), branch.Name), git.Branch.BRANCH.REMOTE).then(function(remoteBranch) { return repo.getBranchCommit(remoteBranch).then(function(commit) { var rJson = mRemotes.remoteJSON(remote, fileDir, [mRemotes.remoteBranchJSON(remoteBranch, commit, remote, fileDir)]); var trackingRemote = config.branch && config.branch[branch.Name] && config.branch[branch.Name].remote; if (trackingRemote === remote.name() || !trackingRemote) { branch["RemoteLocation"].splice(0, 0, rJson); } else { branch["RemoteLocation"].push(rJson); } }); }).catch(function() { //No remote tracking branch branch["RemoteLocation"].push(mRemotes.remoteJSON(remote, fileDir, [mRemotes.remoteBranchJSON(null, null, remote, fileDir, branch)])); }); }));
const writeRepo = co.wrap(function *(repo, ast) { assert.instanceOf(ast, RepoAST); // Now we should have all the commits from `commitRepo` so delete it // and all associated refs. We have to detach the head or it keeps // around the current branch. repo.detachHead(); const refs = yield repo.getReferences(NodeGit.Reference.TYPE.LISTALL); for (let i = 0; i < refs.length; ++i) { NodeGit.Branch.delete(refs[i]); } yield NodeGit.Remote.delete(repo, "origin"); // Then set up the rest of the repository. yield configureRepo(repo, ast, commitMaps.oldToNew, treeCache); const cleanupString = `\ git -C '${repo.path()}' -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 \ -c gc.rerereresolved=0 -c gc.rerereunresolved=0 \ -c gc.pruneExpire=now gc`; yield exec(cleanupString); });
}).then((branch) => { currentBranch = branch return Branch.upstream(currentBranch) }).then((currentOrigin) => {
.then(function(commit) { var branch = "master"; return git.Branch.create(subrepo, branch, commit, 0).then(function() { return subrepo.checkoutBranch(branch, {}); }); })
.then(function(repo) { return git.Branch.lookup(repo, branchName, git.Branch.BRANCH.LOCAL); })
.then(function(commit) { if (!branchName) { branchName = theRef.shorthand().split("/").slice(1).join("/"); } return git.Branch.create(theRepo, branchName, commit, 0); })
.then(function(repo) { theRepo = repo; fileDir = clone.getfileDir(repo,req); return git.Branch.lookup(repo, branchName, git.Branch.BRANCH.LOCAL); })
const configureRepo = co.wrap(function *(repo, ast, commitMap, treeCache) { const makeConflictEntry = co.wrap(function *(data) { assert.instanceOf(repo, NodeGit.Repository); if (null === data) { return null; } if (data instanceof RepoAST.Submodule) { //TODO: some day support putting conflicts in the .gitmodules file. assert.equal("", data.url, "submodule conflicts must have empty URL"); const sha = commitMap[data.sha]; return new ConflictUtil.ConflictEntry(FILEMODE.COMMIT, sha); } const id = yield GitUtil.hashObject(repo, data.contents); const mode = data.isExecutable ? FILEMODE.EXECUTABLE : FILEMODE.BLOB; return new ConflictUtil.ConflictEntry(mode, id.tostrS()); }); const makeRef = co.wrap(function *(name, commit) { const newSha = commitMap[commit]; const newId = NodeGit.Oid.fromString(newSha); return yield NodeGit.Reference.create(repo, name, newId, 0, "made ref"); }); let newHeadSha = null; if (null !== ast.head) { newHeadSha = commitMap[ast.head]; } // Then create the refs for (let ref in ast.refs) { yield makeRef("refs/" + ref, ast.refs[ref]); } // Handle remotes. for (let remoteName in ast.remotes) { const remote = ast.remotes[remoteName]; yield NodeGit.Remote.create(repo, remoteName, remote.url); // Explicitly create the desired refs for the remote. for (let branchName in remote.branches) { yield makeRef(`refs/remotes/${remoteName}/${branchName}`, remote.branches[branchName]); } } // Then create the branches we want. for (let branch in ast.branches) { const astBranch = ast.branches[branch]; const ref = yield makeRef("refs/heads/" + branch, astBranch.sha); if (null !== astBranch.tracking) { yield NodeGit.Branch.setUpstream(ref, astBranch.tracking); } } // Deal with bare repos. if (ast.bare) { if (null !== ast.currentBranchName) { yield repo.setHead("refs/heads/" + ast.currentBranchName); } else { repo.setHeadDetached(newHeadSha); } } else if (null !== ast.currentBranchName || null !== ast.head) { // If we use NodeGit to checkout, it will not respect the // sparse-checkout settings. if (null === ast.currentBranchName) { repo.detachHead(); } const toCheckout = ast.currentBranchName || newHeadSha; const checkoutStr = `\ git -C '${repo.workdir()}' checkout ${toCheckout} `; try { yield exec(checkoutStr); } catch (e) { // This can fail if there is no .gitmodules file to checkout and // it's sparse. Git will complain that it cannot do the checkout // because the worktree is empty. } } const notes = ast.notes; const sig = repo.defaultSignature(); for (let notesRef in notes) { const commits = notes[notesRef]; for (let commit in commits) { const message = commits[commit]; yield NodeGit.Note.create(repo, notesRef, sig, sig, commitMap[commit], message, 0); } } if (!ast.bare) { let indexHead = ast.head; // Set up a rebase if there is one, this has to come right before // setting up the workdir, otherwise the rebase won't be allowed to // start. if (null !== ast.rebase) { const rebase = ast.rebase; const originalSha = commitMap[rebase.originalHead]; const ontoSha = commitMap[rebase.onto]; const original = yield NodeGit.AnnotatedCommit.lookup(repo, originalSha); const onto = yield NodeGit.AnnotatedCommit.lookup(repo, ontoSha); // `init` creates the rebase, but it's not actually started (some // files are not made) until the first call to `next`. const rb = yield NodeGit.Rebase.init(repo, original, onto, null, null); yield rb.next(); const gitDir = repo.path(); const rbDir = yield RebaseFileUtil.findRebasingDir(gitDir); const headNamePath = path.join(gitDir, rbDir, RebaseFileUtil.headFileName); yield fs.writeFile(headNamePath, rebase.headName + "\n"); // Starting a rebase will change the HEAD If we render the index // against `ast.head`, it will be incorrect; we must adjust so that // we render against the new head, `onto`. indexHead = rebase.onto; } // Write out sequencer state if there is one. const sequencer = ast.sequencerState; if (null !== sequencer) { const mapped = SequencerStateUtil.mapCommits(sequencer, commitMap); yield SequencerStateUtil.writeSequencerState(repo.path(), mapped); } // Set up the index. We render the current commit and apply the index // on top of it. let indexParent; if (null !== indexHead) { indexParent = treeCache[indexHead]; } const trees = yield writeTree(repo, commitMap, ast.index, indexParent); const index = yield repo.index(); const treeObj = trees.tree; yield index.readTree(treeObj); for (let filename in ast.index) { const data = ast.index[filename]; if (data instanceof RepoAST.Conflict) { const ancestor = yield makeConflictEntry(data.ancestor); const our = yield makeConflictEntry(data.our); const their = yield makeConflictEntry(data.their); const conflict = new ConflictUtil.Conflict(ancestor, our, their); yield ConflictUtil.addConflict(index, filename, conflict); } } yield index.write(); // TODO: Firgure out if this can be done with NodeGit; extend if // not. I didn't see anything about `clean` and `Checkout.index` // didn't seem to work.. const filesStr = ast.sparse ? "-- .gitmodules" : "-a"; const checkoutIndexStr = `\ git -C '${repo.workdir()}' checkout -- git -C '${repo.workdir()}' clean -f -d git -C '${repo.workdir()}' checkout-index -f ${filesStr} `; yield exec(checkoutIndexStr); // Now apply changes to the workdir. const workdir = ast.workdir; for (let filePath in workdir) { const change = workdir[filePath]; const absPath = path.join(repo.workdir(), filePath); if (null === change) { yield fs.unlink(absPath); } else { const dirname = path.dirname(absPath); mkdirp.sync(dirname); yield fs.writeFile(absPath, change.contents); if (change.isExecutable) { yield fs.chmod(absPath, "755"); } } } } return repo; });
exports.stitch = co.wrap(function *(repoPath, commitish, targetBranchName, options) { assert.isString(repoPath); assert.isString(commitish); assert.isString(targetBranchName); assert.isObject(options); let fetch = false; let url = null; if ("fetch" in options) { assert.isBoolean(options.fetch); fetch = options.fetch; assert.isString(options.url, "url required with fetch"); url = options.url; } assert.isFunction(options.keepAsSubmodule); let joinRoot = null; if ("joinRoot" in options) { assert.isString(options.joinRoot); joinRoot = options.joinRoot; } assert.isNumber(options.numParallel); let skipEmpty = false; if ("skipEmpty" in options) { assert.isBoolean(options.skipEmpty); skipEmpty = options.skipEmpty; } const repo = yield NodeGit.Repository.open(repoPath); const annotated = yield GitUtil.resolveCommitish(repo, commitish); if (null === annotated) { throw new Error(`Could not resolve ${commitish}.`); } const commit = yield repo.getCommit(annotated.id()); console.log("Listing previously converted commits."); let convertedCommits = {}; if (options.preloadCache) { convertedCommits = yield exports.readConvertedCommits(repo); } const getConverted = exports.makeGetConvertedCommit(repo, convertedCommits); console.log("listing unconverted ancestors of", commit.id().tostrS()); const commitsToStitch = yield exports.listCommitsToStitch(repo, commit, getConverted); console.log("listing submodule changes"); const changes = yield exports.listSubmoduleChanges(repo, commitsToStitch); const adjustPath = exports.makeAdjustPathFunction(joinRoot); console.log(commitsToStitch.length, "to stitch"); if (fetch) { console.log("listing fetches"); const fetches = yield exports.listFetches(repo, commitsToStitch, changes, options.keepAsSubmodule, adjustPath, options.numParallel); console.log("Found", Object.keys(fetches).length, "subs to fetch."); const subNames = Object.keys(fetches); const doFetch = co.wrap(function *(name, i) { const subFetches = fetches[name]; const fetchTimeMessage = `\ (${i + 1}/${subNames.length}) -- fetched ${subFetches.length} SHAs for \ ${name}`; console.time(fetchTimeMessage); yield exports.fetchSubCommits(repo, url, subFetches); console.timeEnd(fetchTimeMessage); }); yield DoWorkQueue.doInParallel(subNames, doFetch, options.numParallel); } console.log("Now stitching"); let lastCommit = null; let records = {}; const writeNotes = co.wrap(function *() { console.log( `Writing notes for ${Object.keys(records).length} commits.`); const convertedNotes = {}; const referenceNotes = {}; for (let sha in records) { const record = records[sha]; const stitchedCommit = record.stitchedCommit; const stitchedSha = null === stitchedCommit ? null : stitchedCommit.id().tostrS(); convertedNotes[sha] = exports.makeConvertedNoteContent(stitchedSha); if (null !== stitchedSha) { referenceNotes[stitchedSha] = exports.makeReferenceNoteContent(sha, record.subCommits); } } yield BulkNotesUtil.writeNotes(repo, exports.referenceNoteRef, referenceNotes); yield BulkNotesUtil.writeNotes(repo, exports.convertedNoteRef, convertedNotes); records = {}; }); const whitelist = yield exports.readWhitelist(repo); for (let i = 0; i < commitsToStitch.length; ++i) { const next = commitsToStitch[i]; const nextSha = next.id().tostrS(); const parents = yield next.getParents(); const newParents = []; for (const parent of parents) { const newParentSha = yield getConverted(parent.id().tostrS()); if (null !== newParentSha && undefined !== newParentSha) { const newParent = yield repo.getCommit(newParentSha); newParents.push(newParent); } } const result = yield exports.writeStitchedCommit( repo, next, changes[nextSha], newParents, options.keepAsSubmodule, adjustPath, skipEmpty, whitelist); records[nextSha] = result; const newCommit = result.stitchedCommit; const newSha = null === newCommit ? null : newCommit.id().tostrS(); convertedCommits[nextSha] = newSha; const desc = null === newCommit ? "skipped" : newCommit.id().tostrS(); const log = `\ Of [${commitsToStitch.length}] done [${i + 1}] : ${nextSha} -> ${desc}`; console.log(log); if (10000 <= Object.keys(records).length) { yield writeNotes(); } // If `writeStitchedCommit` returned null to indicate that it did not // make a commit (because it would have been empty), leave `lastCommit` // unchanged. lastCommit = newCommit || lastCommit; } yield writeNotes(); // Delete submodule change cache if we succeeded; we won't need these // submodules again. if (0 !== Object.keys(changes)) { NodeGit.Reference.remove(repo, exports.changeCacheRef); } if (null !== lastCommit) { console.log( `Updating ${targetBranchName} to ${lastCommit.id().tostrS()}.`); yield NodeGit.Branch.create(repo, targetBranchName, lastCommit, 1); } });
.then(([repo, local]) => { const upstream = Git.Branch.upstream(local) return Promise.all([repo, local, upstream]) })
const deleteBranch = co.wrap(function *(repo) { const branch = yield GitUtil.findBranch(repo, branchName); if (null !== branch) { NodeGit.Branch.delete(branch); } });
.then(branch => Git.Branch.upstream(branch))
.then(function (commit) { console.log("3.0"); return Git.Branch.create(repos, bn, commit, 0); })