Git: Get list if all commits in the latest push in a branch

1.1k views Asked by At

I am trying to create an automatic pipeline in gitlab-runner that will apply all the changes in the most recent git push. It is picking up the latest commit in the push (using $CI_COMMIT_SHA variable in gitlab-runner). However, if a push had multiple commits, it ignores the older ones. Thus, all the changes are not applied in the application.

I have the following queries:

  1. Is there any Id assigned to each git push? Basically given a git push Id, is there a way to find all the underlying commits?
  2. Is there a way in gitlab-runner to find all the files committed in the latest git push? Also, I would prefer to maintain the order in which they were committed.
  3. I saw that git cherry can give me the list of unpushed commits. Is there a way, I can pass the info to gitlab-runner via variables?

Thanks in advance

1

There are 1 answers

0
panta82 On

I solved this by getting the latest push event through GitLab API, getting the latest commits by spawning the git CLI tool locally, and then cross-checking them.

Push event will have push_data property, which will tell you which commit range was in the push. https://docs.gitlab.com/ee/api/events.html#list-a-projects-visible-events

My shortened node.js code:

require('isomorphic-fetch');
const exec = require('util').promisify(require('child_process').exec);

const lastPush = await getLastPushEvent();
const commits = await listLatestCommits();

const commitsInLatestPush = [];
for (const commit of commits) {
  if (lastPush.push_data.commit_from === commit.commit) {
    break;
  }
  commitsInLatestPush.push(commit);
}

console.log(commitsInLatestPush);

async function getLastPushEvent() {
  const events = await fetch(`https://gitlab.example.com/api/v4/projects/${process.env.CI_PROJECT_ID}/events?action=pushed`, {
    headers: {
      'PRIVATE-TOKEN': process.env.PRIVATE_GITLAB_TOKEN,
    },
  });
  return events[0] || null;
}

async function listLatestCommits(count = 10) {
  const { stdout, stderr } = await exec(`git log --pretty=format:'{%n  ^^^^commit^^^^: ^^^^%H^^^^,%n  ^^^^abbreviated_commit^^^^: ^^^^%h^^^^,%n  ^^^^tree^^^^: ^^^^%T^^^^,%n  ^^^^abbreviated_tree^^^^: ^^^^%t^^^^,%n  ^^^^parent^^^^: ^^^^%P^^^^,%n  ^^^^abbreviated_parent^^^^: ^^^^%p^^^^,%n  ^^^^refs^^^^: ^^^^%D^^^^,%n  ^^^^encoding^^^^: ^^^^%e^^^^,%n  ^^^^subject^^^^: ^^^^%s^^^^,%n  ^^^^sanitized_subject_line^^^^: ^^^^%f^^^^,%n  ^^^^commit_notes^^^^: ^^^^%N^^^^,%n  ^^^^verification_flag^^^^: ^^^^%G?^^^^,%n  ^^^^signer^^^^: ^^^^%GS^^^^,%n  ^^^^signer_key^^^^: ^^^^%GK^^^^,%n  ^^^^author^^^^: {%n    ^^^^name^^^^: ^^^^%aN^^^^,%n    ^^^^email^^^^: ^^^^%aE^^^^,%n    ^^^^date^^^^: ^^^^%aD^^^^%n  },%n  ^^^^committer^^^^: {%n    ^^^^name^^^^: ^^^^%cN^^^^,%n    ^^^^email^^^^: ^^^^%cE^^^^,%n    ^^^^date^^^^: ^^^^%cD^^^^%n  }%n},' -n ${count} | sed 's/"/\\\\"/g' | sed 's/\\^^^^/"/g' | sed "$ s/,$//" | sed -e ':a' -e 'N' -e '$!ba' -e 's/\\n/ /g'  | awk 'BEGIN { print("[") } { print($0) } END { print("]") }'`);
  if (stderr) {
    throw new Error(`Git command failed: ${stderr}`);
  }
  const data = JSON.parse(stdout);
  return data;
}