Example #1
0
	.then(function(_commit) {
		commit = _commit;
		var work;
		switch (rebaseOperation) {
			case "ABORT":
				work = git.Rebase.open(repo, {}).then(function(rebase){
					return rebase.abort();
				});
				break;
				
			case "CONTINUE":
				work = repo.continueRebase();
				break;
				
			case "SKIP":
				return git.Checkout.head(repo, {
					checkoutStrategy:
						git.Checkout.STRATEGY.FORCE |
						git.Checkout.STRATEGY.RECREATE_MISSING |
						git.Checkout.STRATEGY.REMOVE_UNTRACKED
				})
				.then(function() {
					return git.Rebase.open(repo, {});
				}).then(function(rebase) {
					if (rebase.operationCurrent() === rebase.operationEntrycount() - 1) {
						// if skipping the last operation, then we're done here
						rebase.finish(repo.defaultSignature());
						// return the commit that we're currently on
						return head;
					}
					// move to the next one and continue
					return rebase.next().then(function(rebaseOperation) {
						return repo.continueRebase();
					});
				});
				
			default:
				work = repo.rebaseBranches("HEAD", commitToRebase, null, null, null);
		}
		return work
		.then(function(_oid) {
			oid = _oid;
		})
		.catch(function(index) {
			if (rebaseOperation === "ABORT" || !index.entries) {
				throw index;
			}
			paths = {};
			index.entries().forEach(function(entry) {
				if (git.Index.entryIsConflict(entry)) {
					paths[entry.path] = "";
				}
			});
			return git.Checkout.index(repo, index, {
				checkoutStrategy: git.Checkout.STRATEGY.ALLOW_CONFLICTS,
				ourLabel: "HEAD",
				theirLabel: commit.sha()
			});
		});
	})
Example #2
0
	.then(function(_commit) {
		commit = _commit;
		var work;
		switch (rebaseOperation) {
			case "ABORT":
				work = git.Rebase.open(repo, {}).then(function(rebase){
					return rebase.abort();
				});
				break;
				
			case "CONTINUE":
				work = repo.continueRebase();
				break;
				
			case "SKIP":
				throw new Error("Not implemented yet");
				
			default:
				work = repo.rebaseBranches("HEAD", commitToRebase, null, null, null);
		}
		return work
		.then(function(_oid) {
			oid = _oid;
		})
		.catch(function(index) {
			if (rebaseOperation === "ABORT" || !index.entries) {
				throw index;
			}
			paths = {};
			index.entries().forEach(function(entry) {
				if (git.Index.entryIsConflict(entry)) {
					paths[entry.path] = "";
				}
			});
			return git.Checkout.index(repo, index, {
				checkoutStrategy: git.Checkout.STRATEGY.ALLOW_CONFLICTS,
				ourLabel: "HEAD",
				theirLabel: commit.sha()
			});
		});
	})
it("callNext", co.wrap(function *() {
    const init = "S:C2-1;Bmaster=2;C3-1;Bfoo=3";
    const written = yield RepoASTTestUtil.createRepo(init);
    const repo = written.repo;
    const ontoSha = written.oldCommitMap["3"];
    const fromId = NodeGit.Oid.fromString(ontoSha);
    const fromAnnotated =
                        yield NodeGit.AnnotatedCommit.lookup(repo, fromId);
    const head = yield repo.head();
    const ontoAnnotated = yield NodeGit.AnnotatedCommit.fromRef(repo,
                                                                head);
    const rebase = yield NodeGit.Rebase.init(repo,
                                             fromAnnotated,
                                             ontoAnnotated,
                                             null,
                                             null);
    const first = yield SubmoduleRebaseUtil.callNext(rebase);
    assert.equal(first.id().tostrS(), ontoSha);
    const second = yield SubmoduleRebaseUtil.callNext(rebase);
    assert.isNull(second);
}));
 const op = co.wrap(function *(repos, maps) {
     const repo = repos.x;
     const headCommit = yield repo.getHeadCommit();
     const AnnotatedCommit = NodeGit.AnnotatedCommit;
     const headAnnotated = yield AnnotatedCommit.lookup(
                                               repo,
                                               headCommit.id());
     const targetCommitSha = maps.reverseCommitMap.r;
     const targetCommit = yield repo.getCommit(targetCommitSha);
     const targetAnnotated = yield AnnotatedCommit.lookup(
                                             repo,
                                             targetCommit.id());
     const rebase = yield NodeGit.Rebase.init(repo,
                                              targetAnnotated,
                                              headAnnotated,
                                              null,
                                              null);
     const op = yield SubmoduleRebaseUtil.callNext(rebase);
     const result = yield SubmoduleRebaseUtil.processRebase(repo,
                                                            rebase,
                                                            op);
     if (null === c.conflictedCommit) {
         assert.isNull(result.conflictedCommit);
     } else {
         assert.equal(
                     result.conflictedCommit,
                     maps.reverseCommitMap[c.conflictedCommit]);
     }
     const commitMap = {};
     Object.keys(result.commits).forEach(newSha => {
         const oldSha = result.commits[newSha];
         const oldLogicalCommit = maps.commitMap[oldSha];
         commitMap[newSha] = oldLogicalCommit + "r";
     });
     return {
         commitMap: commitMap,
     };
 });
Example #5
0
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;
});
Example #6
0
				.then(function() {
					return git.Rebase.open(repo, {});
				}).then(function(rebase) {