get all commits in a Git tag through GitHub API return only the first commit

半世苍凉 提交于 2021-02-07 17:07:31

问题


I'm trying to get all commits in a git tag throw github api. I checked in this stack overflow issue but in this way, it asks me to compare between two tags and it returns me only the first commit. I want to get all commits of a specific tag. what I used is

https://api.github.com/repos/:org/:repo/compare/:tag_1...:tag_2

because I want to specific tag I added the same tag

https://api.github.com/repos/RapidAPI/ant-design/compare/3.13.2...3.13.2

it return me the only 2 commits but in the tag I have many commits as you can see here.


回答1:


It wasn't clear what the constraints were tech-wise so here is an example solution using Node that should illustrate what's possible.

I believe the tags returned by /repos/:owner/:name/tags are not sorted by date created, but instead alphabetically, so I had to filter out the tags that didn't match the version regex to catch some stray inputs. To ensure the order was correct I used the semver npm package to sort them based on version.

Then it was a matter of just using the Compare endpoint with the two latest tags in the repository.

// API client for working with GitHub data using promises
const { Octokit } = require("@octokit/rest");

// helper function to compare two version strings using semver
const semverGt = require('semver/functions/gt');

const owner =  "RapidAPI";
const repo = "ant-design";

const octokit = new Octokit();

octokit.repos
  .listTags({
    owner,
    repo,
  })
  .then(({ data: tags }) => {
    // filter out tags that don't look like releases
    const sortedTaggedVersions = tags.filter(t => t.name.match(/\d+.\d+.\d+/))
                                     .sort((a, b) => semverGt(a.name, b.name));

    // these are out inputs for locating the commits that are in the latest
    // release (aka "head") but are not in the previous release (aka "base")
    const head = sortedTaggedVersions[0].name;
    const base = sortedTaggedVersions[1].name;

    console.log(`Comparing base ${base} and head ${head}...`)

    return octokit.repos.compareCommits({
        owner,
        repo,
        base,
        head,
    });
  })
  .then(({ data }) => {
    console.log(`Found ${data.commits.length} commits:`);
    for (const c of data.commits) {
        let message = c.commit.message;

        // only show first line of commit message to keep output clean
        const newline = message.indexOf("\n");
        if (newline > -1) {
            message = message.substr(0, newline);
        }

        let author = c.author ? `@${c.author.login}` : null;
        if (author == null) {
          // use the name from the commit itself if we cannot find a GitHub committer
          author = c.commit.author.name;
        }

        console.log(` - ${c.sha} - ${author} - ${message}`)
    }
  })
  .catch(err => {
      console.error("Unable to find commits", err);
  });

This is the result:

$ node index.js
Comparing base 3.13.1 and head 3.13.2...
Found 19 commits:
 - 4b526bf251fde5d4b6f1fec6d1ec3eb8805b4c75 - @orzyyyy - docs: fix wrong comma
 - 736f5b9549a3de6d694786f63f835aa26c29d105 - @pine3ree - doc: handle invalid date in message.info() call
 - 0d65f0578de652d2b3f5231088eaeaab95d8a3be - dependabot[bot] - :arrow_up: Update @types/react requirement from ~16.7.13 to ~16.8.1
 - c895c809f91e7ce817d9a42c4e0fd3ea5311d198 - @gyh9457 - improve tabs demo (#14701)
 - 163140189f57c225dd49758f4ea2b8116f201dc9 - @ashearer - Fix quote rendering (#14708)
 - 31d55e43b358c148640a7991b444c56e1cf25456 - @ycjcl868 - upd: version
 - 976a6a5c5a2adb3c407e953b95df08f6810e0cd5 - @Josephus-P - Fixed typos and improved grammar
 - b6f81340baeec20caa8511693ea4ec7d7d0c0ba7 - @Josephus-P - small change
 - 777c56a515159a2eb7e809695def53d66aebfc10 - @zombieJ - mock test
 - 6f040b6c4090fbc060bf2a06a7a01b900f4fe890 - @ycjcl868 - fix: strict check input
 - 6cdc203a2fc58b5c89ea7bfe0ef361e7afdf95e6 - @ycjcl868 - Merge pull request #14725 from ant-design/fix-form-test
 - 99eeefc25d38a2e2060c23de0f8446fd90729911 - @imhele - correct type in Switch (#14727)
 - 2b558af9600c0d0fa56467b8de0522b2a4277232 - @zombieJ - update silder snapshot (#14732)
 - b3834e48b1e009adbd142a7e2c38a129729170de - @imhele - Table: fix showing only first page (#14724)
 - 991b47f421bc3c60d30a8ff1d689615e6b70dbe1 - @zombieJ - update antd-tools version to check (#14738)
 - dfc9b24c989c58ffe6a922b45286e09450f85579 - @GabeMedrash - Properly type onMouseEnter and onMouseLeave events
 - 5ad97a33d1d65f05a121796210e4fa15f2894c5c - @afc163 - :lipstick: improve home page style in mobile device
 - a9a6da47ed44d811e402822ec3933608405c27fb - @thilo-behnke - Input: Clear icon doesn't disappear if value is null (vs undefined or empy string) (#14733)
 - dab30ef2ccead39135ff6e4b215259344d812897 - @zombieJ - update changelog (#14746)

This is different to the provided URL from the screenshot https://api.github.com/repos/RapidAPI/ant-design/compare/3.13.2...3.13.2 because it uses the version 3.13.2 for both tags.




回答2:


yes, I would happy to know what is doing when the same tag..

To explain the /repos/:owner/:repo/compare/:base...:head API I first need to explain the corresponding API in Git itself - how to get a list of commits.

If you were to run git log 3.13.2 it would do a few things:

  1. figure out that 3.13.2 is a tag (a branch, commit ID, or other aliases could also be used here)
  2. find the commit that belongs to this tag
  3. list the details about this first commit
  4. check the first parent of this commit
  5. GOTO 3

It'll then continue to traverse the history of the repository until you decide to exit the process.

But what if we only want to go back to a certain point? This is where "commit ranges" comes into play.

If you were working on the command line to find the commits between two tags, you'd probably use this syntax:

$ git log 3.13.1...3.13.2 --oneline                                                                                   
dab30ef2cc (tag: 3.13.2) update changelog (#14746)
a9a6da47ed Input: Clear icon doesn't disappear if value is null (vs undefined or empy string) (#14733)
5ad97a33d1 :lipstick: improve home page style in mobile device
dfc9b24c98 Properly type onMouseEnter and onMouseLeave events
991b47f421 update antd-tools version to check (#14738)
b3834e48b1 Table: fix showing only first page (#14724)
2b558af960 update silder snapshot (#14732)
99eeefc25d correct type in Switch (#14727)
6cdc203a2f Merge pull request #14725 from ant-design/fix-form-test
6f040b6c40 fix: strict check input
777c56a515 mock test
b6f81340ba small change
976a6a5c5a Fixed typos and improved grammar
31d55e43b3 upd: version
163140189f Fix quote rendering (#14708)
c895c809f9 improve tabs demo (#14701)
0d65f0578d :arrow_up: Update @types/react requirement from ~16.7.13 to ~16.8.1
736f5b9549 doc: handle invalid date in message.info() call
4b526bf251 docs: fix wrong comma

This is what the design of the /repos/:owner/:repo/compare/:base...:head API is based upon - providing the commit range that you want to query on in the form of two tags. But what happens when you provide the same tag twice?

$ git log 3.13.2...3.13.2 --oneline

No commits are returned, because Git thinks you want to find the range of commits from the same tag - which is an empty set. This is what the GitHub API is doing with your initial API call.



来源:https://stackoverflow.com/questions/61359461/get-all-commits-in-a-git-tag-through-github-api-return-only-the-first-commit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!