Another way to do the block above is to chain the futures - make sure then when you start another future you return its value. Something like this (though I don't know if this code compiles):

    getGitTestFileSystem().then((chrome_files.CrFileSystem fs) {
      return fs.root.createDirectory(projectName).then((chrome.DirectoryEntry dir) {
        GitOptions options = new GitOptions();
        options.root = dir;
        options.repoUrl = url;
        options.depth = 1;
        options.store = new ObjectStore(dir);
        Clone clone = new Clone(options);
        return options.store.init().then((_) {
          return clone.clone().then((_) {
            return spark.workspace.link(dir).then((folder) {
              spark._filesController.selectFile(folder);
              spark.workspace.save();
            });
          });
        });
      });
    }).whenComplete(() => completer.complete(this));