gitgithubgithub-actions

Is there a way to know how many commits a push in a github action contains?


this is my github action and i would like to know if is there a way to know how many commits are in my push?

Because in my operation i'm trying to run a pipeline of just the files that contains modifications.

name: SFDX-CLI DEV Deploy from Repository
on: 
  push:
    branches:
      - develop
    paths:
      - 'force-app/**'
jobs:
  SFDX-CLI-DEV-Deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
        with:
          # Fetch all history commit
          fetch-depth: 0
      - run: npm install sfdx-cli --location=global
      - run: echo 'y' | sfdx plugins:install sfdx-git-delta
      - run: sfdx force:auth:jwt:grant --clientid ${{ secrets.DEV_CLIENTID }} --jwtkeyfile=build/serverDev.key --username ${{ secrets.DEV_USERNAME }} --setdefaultdevhubusername --instanceurl=${{ secrets.DEV_INSTANCE_URL }} --setalias dev
      - run: git fetch origin "+refs/heads/*:refs/remotes/origin/*"
      - run: sfdx sgd:source:delta --to "HEAD" --from "HEAD^" --output .
      - run: sfdx force:source:deploy -x package/package.xml -u dev

I'm not found this information on the net.


Solution

  • First, let me note that you're using sfdx above, not git push; what sfdx does is a mystery black box to me. I'm answering the question you asked ("how many commits would git push push") rather than the one you probably should be asking, but that would probably belong under a different tag , or perhaps on https://salesforce.stackexchange.com.

    There is no completely reliable way to find out, because any test you perform will have a race condition. For instance, suppose we have two repositories, src and dst, and:

    git push dst refspec
    

    is currently going to send three commits from src, because those are the three commits that do not exist on dst at the moment.

    We use some process that finds this out:

    count-commits dst refspec
    

    where count-commits is our magic command that counts how many commits git push will send, and we get the answer: 3.

    Now that we have the answer—or just before we get the answer from the counting process—something else sneaks in and sends one of the commits to the dst repository, or sneaks in and removes one commit from the dst repository. We, resting assured that the count is 3, make use of this information in some way. Then we run the command for real:

    git push dst refspec
    

    and—whoa!—our git push sends two or four commits.1 What? How did that happen?

    The answer is right there above: someone snuck in after we counted, and changed things. We can't stop that from being a possibility. Race conditions like this usually mean you're doing something wrong.2 For instance, in this case, instead of counting in advance, then sending, we should reverse the process: send, and count upon receiving.

    If this is impossible for various reasons, and/or a "best effort" with possible race condition is sufficient albeit imperfect, we can go ahead with the counting. To do this counting, we:

    1. run git fetch dst to update any remote-tracking name;
    2. use git rev-list --count remote-tracking-name..local-name

    and the output of this git rev-list contains our count. For instance, if we're going to push to origin with git push origin foo and the upstream in question is origin/foo, a simple git rev-list origin/foo..foo gets us the right number (provided we've run git fetch origin to get origin/foo as close as we can, to keep the race as narrow as possible). If origin/foo is the upstream of foo, we can use foo@{upstream}:

    git rev-list --count foo@{upstream}..foo
    

    Note that this produces zero if our git push is meant to remove commits, though in this case we'll need git push --force or similar. To find out (racily) how many commits we'll remove, we can use:

    git rev-list --count foo..foo@{upstream}
    

    A forced push operation can both add and remove commits all at once; to get both counts, use git rev-list --count --left-right foo@{upstream}...foo (note three dots here, vs two in the others). You can reverse the order of the two names around the three dots: with upstream on the left and local on the right, we get the to-be-removed count on the left and the to-be-added count on the right, and if we swap the names, that swaps the counts.

    Last, we can close the race completely—at some cost—by using --force-with-lease here, given that foo has an upstream set. The push will simply fail if we lose a race. We'll then have to detect the failed push and do something about it, such as trying again (fetch, count, push) in a loop. This is not very efficient, but if it's rare enough, it might be OK.


    1Four shalt thou not count, neither thou count two, excepting that thou then proceed to three. Five is right out.

    2"What do we want?"      Now!
    "When do we want it?"    Fewer race conditions!