def revs(self, branch='master', limit=None, skip=None, num_datapoints=None):
        """
        Returns a dataframe of all revision tags and their timestamps for each project. It will have the columns:

         * date
         * repository
         * rev

        :param branch: (optional, default 'master') the branch to work in
        :param limit: (optional, default None), the maximum number of revisions to return, None for no limit
        :param skip: (optional, default None), the number of revisions to skip. Ex: skip=2 returns every other revision, None for no skipping.
        :param num_datapoints: (optional, default=None) if limit and skip are none, and this isn't, then num_datapoints evenly spaced revs will be used

        :return: DataFrame
        """

        if limit is not None:
            limit = math.floor(float(limit) / len(self.repos))

        if num_datapoints is not None:
            num_datapoints = math.floor(float(num_datapoints) / len(self.repos))

        df = pd.DataFrame(columns=['repository', 'rev'])

        if _has_joblib:
            ds = Parallel(n_jobs=-1, backend='threading', verbose=0)(
                delayed(_revs_func)
                (x, branch, limit, skip, num_datapoints) for x in self.repos
            )
            for d in ds:
                df = df.append(d)
        else:
            for repo in self.repos:
                try:
                    revs = repo.revs(branch=branch, limit=limit, skip=skip, num_datapoints=num_datapoints)
                    revs['repository'] = repo.repo_name
                    df = df.append(revs)
                except GitCommandError:
                    print('Warning! Repo: %s couldn\'t be inspected' % (repo, ))

        df.reset_index()

        return df