How can I find the SHA of a file on a branch (w/o search)?

I am trying to support a build tool.
The build tool currently:

  • creates a temporary branch
  • finds certain files on that branch
  • downloads those files
  • maybe updates and uploads those files (e.g. update the version number of a maven POM file)
  • creates a PR with the temporary branch
  • uses a secondary bot user to approve/merge the PR
  • deletes the temporary branch

I am specifically interested in fixing one particular step of the process which:

  • finds the latest copy of a sql script on the temporary branch (e.g. current_dev.sql)
  • download its contents
  • updates the contents with new version specific content
  • uploads the updated file to a new version specific filename (in the temporary branch)

Currently, the tool uses: get-repository-content - ie. https://developer.github.com/v3/repos/contents/#get-repository-content
This response includes the file’s SHA and its contents.

Unfortunately, if the file is larger than 1MB (as it sometimes is), this call will fail.
So, I need another way to find a particular file on a branch and its SHA.
I had just figured out how to use search, but apparently that doesn’t support searching any branch other than the default branch (e.g. master).

I need the SHA to download and upload the file:

I have observed that the github GUI find-file will find a file on a branch, so I assume it is supported by the REST API somehow.
So, please let me know your thoughts on how we might solve this problem.

:wave: hello there @cedoucette. Welcome to the GitHub Support Community, and thanks for asking this question!

Because a branch can have one or more commits, a file on that branch can have one or more revisions. Given that branch, it’s possible to list the branch’s commits and find the commit that has the revision of the file that you’re interested in. The API’s representation of a Git commit includes a tree field; you can get a tree and inspect the response’s tree field (an Array) that contains each of the files and their respective SHAs.

Example

Let’s use the octocat/Hello-world repository. It has a test branch and we can checkout the repository at that branch. In that revision, let’s say we wanted to obtain the SHA of the CONTRIBUTING.md file.

We can apply the aforementioned approach by first listing the branch’s commits:

curl -H "Authorization: token $TOKEN" "https://api.github.com/repos/octocat/Hello-World/commits?sha=test"
API response: commits
[
  {
    "sha": "b3cbd5bbd7e81436d2eee04537ea2b4c0cad4cdf",
    "node_id": "MDY6Q29tbWl0MTI5NjI2OTpiM2NiZDViYmQ3ZTgxNDM2ZDJlZWUwNDUzN2VhMmI0YzBjYWQ0Y2Rm",
    "commit": {
      "author": {
        "name": "The Octocat",
        "email": "octocat@nowhere.com",
        "date": "2014-06-10T22:22:26Z"
      },
      "committer": {
        "name": "The Octocat",
        "email": "octocat@nowhere.com",
        "date": "2014-06-10T22:22:26Z"
      },
      "message": "Create CONTRIBUTING.md",
      "tree": {
        "sha": "a99769c0f635bfd0610ee7a6c2f2b864fa23f3dc",
        "url": "https://api.github.com/repos/octocat/Hello-World/git/trees/a99769c0f635bfd0610ee7a6c2f2b864fa23f3dc"
      },
      "url": "https://api.github.com/repos/octocat/Hello-World/git/commits/b3cbd5bbd7e81436d2eee04537ea2b4c0cad4cdf",
      "comment_count": 2,
      "verification": {
        "verified": false,
        "reason": "unsigned",
        "signature": null,
        "payload": null
      }
    },
    "url": "https://api.github.com/repos/octocat/Hello-World/commits/b3cbd5bbd7e81436d2eee04537ea2b4c0cad4cdf",
    "html_url": "https://github.com/octocat/Hello-World/commit/b3cbd5bbd7e81436d2eee04537ea2b4c0cad4cdf",
    "comments_url": "https://api.github.com/repos/octocat/Hello-World/commits/b3cbd5bbd7e81436d2eee04537ea2b4c0cad4cdf/comments",
    "author": {
      "login": "octocat",
      "id": 583231,
      "node_id": "MDQ6VXNlcjU4MzIzMQ==",
      "avatar_url": "https://avatars3.githubusercontent.com/u/583231?v=4",
      "gravatar_id": "",
      "url": "https://api.github.com/users/octocat",
      "html_url": "https://github.com/octocat",
      "followers_url": "https://api.github.com/users/octocat/followers",
      "following_url": "https://api.github.com/users/octocat/following{/other_user}",
      "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
      "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
      "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
      "organizations_url": "https://api.github.com/users/octocat/orgs",
      "repos_url": "https://api.github.com/users/octocat/repos",
      "events_url": "https://api.github.com/users/octocat/events{/privacy}",
      "received_events_url": "https://api.github.com/users/octocat/received_events",
      "type": "User",
      "site_admin": false
    },
    "committer": {
      "login": "octocat",
      "id": 583231,
      "node_id": "MDQ6VXNlcjU4MzIzMQ==",
      "avatar_url": "https://avatars3.githubusercontent.com/u/583231?v=4",
      "gravatar_id": "",
      "url": "https://api.github.com/users/octocat",
      "html_url": "https://github.com/octocat",
      "followers_url": "https://api.github.com/users/octocat/followers",
      "following_url": "https://api.github.com/users/octocat/following{/other_user}",
      "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
      "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
      "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
      "organizations_url": "https://api.github.com/users/octocat/orgs",
      "repos_url": "https://api.github.com/users/octocat/repos",
      "events_url": "https://api.github.com/users/octocat/events{/privacy}",
      "received_events_url": "https://api.github.com/users/octocat/received_events",
      "type": "User",
      "site_admin": false
    },
    "parents": [
      {
        "sha": "7fd1a60b01f91b314f59955a4e4d4e80d8edf11d",
        "url": "https://api.github.com/repos/octocat/Hello-World/commits/7fd1a60b01f91b314f59955a4e4d4e80d8edf11d",
        "html_url": "https://github.com/octocat/Hello-World/commit/7fd1a60b01f91b314f59955a4e4d4e80d8edf11d"
      }
    ]
  },
  {
    "sha": "7fd1a60b01f91b314f59955a4e4d4e80d8edf11d",
    "node_id": "MDY6Q29tbWl0MTI5NjI2OTo3ZmQxYTYwYjAxZjkxYjMxNGY1OTk1NWE0ZTRkNGU4MGQ4ZWRmMTFk",
    "commit": {
      "author": {
        "name": "The Octocat",
        "email": "octocat@nowhere.com",
        "date": "2012-03-06T23:06:50Z"
      },
      "committer": {
        "name": "The Octocat",
        "email": "octocat@nowhere.com",
        "date": "2012-03-06T23:06:50Z"
      },
      "message": "Merge pull request #6 from Spaceghost/patch-1\n\nNew line at end of file.",
      "tree": {
        "sha": "b4eecafa9be2f2006ce1b709d6857b07069b4608",
        "url": "https://api.github.com/repos/octocat/Hello-World/git/trees/b4eecafa9be2f2006ce1b709d6857b07069b4608"
      },
      "url": "https://api.github.com/repos/octocat/Hello-World/git/commits/7fd1a60b01f91b314f59955a4e4d4e80d8edf11d",
      "comment_count": 57,
      "verification": {
        "verified": false,
        "reason": "unsigned",
        "signature": null,
        "payload": null
      }
    },
    "url": "https://api.github.com/repos/octocat/Hello-World/commits/7fd1a60b01f91b314f59955a4e4d4e80d8edf11d",
    "html_url": "https://github.com/octocat/Hello-World/commit/7fd1a60b01f91b314f59955a4e4d4e80d8edf11d",
    "comments_url": "https://api.github.com/repos/octocat/Hello-World/commits/7fd1a60b01f91b314f59955a4e4d4e80d8edf11d/comments",
    "author": {
      "login": "octocat",
      "id": 583231,
      "node_id": "MDQ6VXNlcjU4MzIzMQ==",
      "avatar_url": "https://avatars3.githubusercontent.com/u/583231?v=4",
      "gravatar_id": "",
      "url": "https://api.github.com/users/octocat",
      "html_url": "https://github.com/octocat",
      "followers_url": "https://api.github.com/users/octocat/followers",
      "following_url": "https://api.github.com/users/octocat/following{/other_user}",
      "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
      "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
      "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
      "organizations_url": "https://api.github.com/users/octocat/orgs",
      "repos_url": "https://api.github.com/users/octocat/repos",
      "events_url": "https://api.github.com/users/octocat/events{/privacy}",
      "received_events_url": "https://api.github.com/users/octocat/received_events",
      "type": "User",
      "site_admin": false
    },
    "committer": {
      "login": "octocat",
      "id": 583231,
      "node_id": "MDQ6VXNlcjU4MzIzMQ==",
      "avatar_url": "https://avatars3.githubusercontent.com/u/583231?v=4",
      "gravatar_id": "",
      "url": "https://api.github.com/users/octocat",
      "html_url": "https://github.com/octocat",
      "followers_url": "https://api.github.com/users/octocat/followers",
      "following_url": "https://api.github.com/users/octocat/following{/other_user}",
      "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
      "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
      "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
      "organizations_url": "https://api.github.com/users/octocat/orgs",
      "repos_url": "https://api.github.com/users/octocat/repos",
      "events_url": "https://api.github.com/users/octocat/events{/privacy}",
      "received_events_url": "https://api.github.com/users/octocat/received_events",
      "type": "User",
      "site_admin": false
    },
    "parents": [
      {
        "sha": "553c2077f0edc3d5dc5d17262f6aa498e69d6f8e",
        "url": "https://api.github.com/repos/octocat/Hello-World/commits/553c2077f0edc3d5dc5d17262f6aa498e69d6f8e",
        "html_url": "https://github.com/octocat/Hello-World/commit/553c2077f0edc3d5dc5d17262f6aa498e69d6f8e"
      },
      {
        "sha": "762941318ee16e59dabbacb1b4049eec22f0d303",
        "url": "https://api.github.com/repos/octocat/Hello-World/commits/762941318ee16e59dabbacb1b4049eec22f0d303",
        "html_url": "https://github.com/octocat/Hello-World/commit/762941318ee16e59dabbacb1b4049eec22f0d303"
      }
    ]
  },
  {
    "sha": "762941318ee16e59dabbacb1b4049eec22f0d303",
    "node_id": "MDY6Q29tbWl0MTI5NjI2OTo3NjI5NDEzMThlZTE2ZTU5ZGFiYmFjYjFiNDA0OWVlYzIyZjBkMzAz",
    "commit": {
      "author": {
        "name": "Johnneylee Jack Rollins",
        "email": "Johnneylee.rollins@gmail.com",
        "date": "2011-09-14T04:42:41Z"
      },
      "committer": {
        "name": "Johnneylee Jack Rollins",
        "email": "Johnneylee.rollins@gmail.com",
        "date": "2011-09-14T04:42:41Z"
      },
      "message": "New line at end of file. --Signed off by Spaceghost",
      "tree": {
        "sha": "b4eecafa9be2f2006ce1b709d6857b07069b4608",
        "url": "https://api.github.com/repos/octocat/Hello-World/git/trees/b4eecafa9be2f2006ce1b709d6857b07069b4608"
      },
      "url": "https://api.github.com/repos/octocat/Hello-World/git/commits/762941318ee16e59dabbacb1b4049eec22f0d303",
      "comment_count": 150,
      "verification": {
        "verified": false,
        "reason": "unsigned",
        "signature": null,
        "payload": null
      }
    },
    "url": "https://api.github.com/repos/octocat/Hello-World/commits/762941318ee16e59dabbacb1b4049eec22f0d303",
    "html_url": "https://github.com/octocat/Hello-World/commit/762941318ee16e59dabbacb1b4049eec22f0d303",
    "comments_url": "https://api.github.com/repos/octocat/Hello-World/commits/762941318ee16e59dabbacb1b4049eec22f0d303/comments",
    "author": {
      "login": "Spaceghost",
      "id": 251370,
      "node_id": "MDQ6VXNlcjI1MTM3MA==",
      "avatar_url": "https://avatars2.githubusercontent.com/u/251370?v=4",
      "gravatar_id": "",
      "url": "https://api.github.com/users/Spaceghost",
      "html_url": "https://github.com/Spaceghost",
      "followers_url": "https://api.github.com/users/Spaceghost/followers",
      "following_url": "https://api.github.com/users/Spaceghost/following{/other_user}",
      "gists_url": "https://api.github.com/users/Spaceghost/gists{/gist_id}",
      "starred_url": "https://api.github.com/users/Spaceghost/starred{/owner}{/repo}",
      "subscriptions_url": "https://api.github.com/users/Spaceghost/subscriptions",
      "organizations_url": "https://api.github.com/users/Spaceghost/orgs",
      "repos_url": "https://api.github.com/users/Spaceghost/repos",
      "events_url": "https://api.github.com/users/Spaceghost/events{/privacy}",
      "received_events_url": "https://api.github.com/users/Spaceghost/received_events",
      "type": "User",
      "site_admin": false
    },
    "committer": {
      "login": "Spaceghost",
      "id": 251370,
      "node_id": "MDQ6VXNlcjI1MTM3MA==",
      "avatar_url": "https://avatars2.githubusercontent.com/u/251370?v=4",
      "gravatar_id": "",
      "url": "https://api.github.com/users/Spaceghost",
      "html_url": "https://github.com/Spaceghost",
      "followers_url": "https://api.github.com/users/Spaceghost/followers",
      "following_url": "https://api.github.com/users/Spaceghost/following{/other_user}",
      "gists_url": "https://api.github.com/users/Spaceghost/gists{/gist_id}",
      "starred_url": "https://api.github.com/users/Spaceghost/starred{/owner}{/repo}",
      "subscriptions_url": "https://api.github.com/users/Spaceghost/subscriptions",
      "organizations_url": "https://api.github.com/users/Spaceghost/orgs",
      "repos_url": "https://api.github.com/users/Spaceghost/repos",
      "events_url": "https://api.github.com/users/Spaceghost/events{/privacy}",
      "received_events_url": "https://api.github.com/users/Spaceghost/received_events",
      "type": "User",
      "site_admin": false
    },
    "parents": [
      {
        "sha": "553c2077f0edc3d5dc5d17262f6aa498e69d6f8e",
        "url": "https://api.github.com/repos/octocat/Hello-World/commits/553c2077f0edc3d5dc5d17262f6aa498e69d6f8e",
        "html_url": "https://github.com/octocat/Hello-World/commit/553c2077f0edc3d5dc5d17262f6aa498e69d6f8e"
      }
    ]
  },
  {
    "sha": "553c2077f0edc3d5dc5d17262f6aa498e69d6f8e",
    "node_id": "MDY6Q29tbWl0MTI5NjI2OTo1NTNjMjA3N2YwZWRjM2Q1ZGM1ZDE3MjYyZjZhYTQ5OGU2OWQ2Zjhl",
    "commit": {
      "author": {
        "name": "cameronmcefee",
        "email": "cameron@github.com",
        "date": "2011-01-26T19:06:08Z"
      },
      "committer": {
        "name": "cameronmcefee",
        "email": "cameron@github.com",
        "date": "2011-01-26T19:06:08Z"
      },
      "message": "first commit",
      "tree": {
        "sha": "fcf4a9bba6857422971d67147517eb5edfdbf48d",
        "url": "https://api.github.com/repos/octocat/Hello-World/git/trees/fcf4a9bba6857422971d67147517eb5edfdbf48d"
      },
      "url": "https://api.github.com/repos/octocat/Hello-World/git/commits/553c2077f0edc3d5dc5d17262f6aa498e69d6f8e",
      "comment_count": 49,
      "verification": {
        "verified": false,
        "reason": "unsigned",
        "signature": null,
        "payload": null
      }
    },
    "url": "https://api.github.com/repos/octocat/Hello-World/commits/553c2077f0edc3d5dc5d17262f6aa498e69d6f8e",
    "html_url": "https://github.com/octocat/Hello-World/commit/553c2077f0edc3d5dc5d17262f6aa498e69d6f8e",
    "comments_url": "https://api.github.com/repos/octocat/Hello-World/commits/553c2077f0edc3d5dc5d17262f6aa498e69d6f8e/comments",
    "author": null,
    "committer": null,
    "parents": [

    ]
  }
]

The API response is a JSON array, where each element of the array represents a commit. Let’s say we chose the first element of the array representing the commit b3cbd5bbd7e81436d2eee04537ea2b4c0cad4cdf. Conveniently, this element has a commit object with a number of fields, including the tree. Making a request to the value of tree.url will get the associated tree:

curl -H "Authorization: token $TOKEN" "https://api.github.com/repos/octocat/Hello-World/git/trees/a99769c0f635bfd0610ee7a6c2f2b864fa23f3dc"
API Response: tree
{
  "sha": "a99769c0f635bfd0610ee7a6c2f2b864fa23f3dc",
  "url": "https://api.github.com/repos/octocat/Hello-World/git/trees/a99769c0f635bfd0610ee7a6c2f2b864fa23f3dc",
  "tree": [
    {
      "path": "CONTRIBUTING.md",
      "mode": "100644",
      "type": "blob",
      "sha": "340edab54ab5e07f0cab4f44808b3d2ee2622f02",
      "size": 16,
      "url": "https://api.github.com/repos/octocat/Hello-World/git/blobs/340edab54ab5e07f0cab4f44808b3d2ee2622f02"
    },
    {
      "path": "README",
      "mode": "100644",
      "type": "blob",
      "sha": "980a0d5f19a64b4b30a87d4206aade58726b60e3",
      "size": 13,
      "url": "https://api.github.com/repos/octocat/Hello-World/git/blobs/980a0d5f19a64b4b30a87d4206aade58726b60e3"
    }
  ],
  "truncated": false
}

This API response is also a JSON array with a tree field containing the files. I’ve extracted CONTRIBUTING.md's file here to showcase not only its file sha, but its url pointing to the API representation of its Git blob:

    {
      "path": "CONTRIBUTING.md",
      "mode": "100644",
      "type": "blob",
      "sha": "340edab54ab5e07f0cab4f44808b3d2ee2622f02",
      "size": 16,
      "url": "https://api.github.com/repos/octocat/Hello-World/git/blobs/340edab54ab5e07f0cab4f44808b3d2ee2622f02"
    }

What’s great about the Git Blobs API is that it’s possible to fetch a file up to 100 megabytes in size. This isn’t the only approach, and I’m sure there are alternatives that others can share here! :v: