Yes, there is a difference. By default, the value of when: is on_success -- jobs only run if jobs in previous stages succeed. Using always will allow the job to run, even if jobs in the previous stage failed.
Per the docs these are the possible values for when:
on_success(default): Run the job only when all jobs in earlier stages succeed or have allow_failure: true.
manual: Run the job only when triggered manually.
always: Run the job regardless of the status of jobs in earlier stages. Can also be used in workflow:rules.
on_failure: Run the job only when at least one job in an earlier stage fails. A job with allow_failure: true is always considered successful.
delayed: Delay the execution of a job for a specified duration.
never: Don’t run the job. Can only be used in a rules section or workflow: rules.
But if you did the following, it would be effectively the same as the first example:
- if: "$CI_PIPELINE_SOURCE == "merge_request_event"
when: on_success
This also assumes when: is not used in the job body.
If you do have when: in the body AND in your rules, this changes a bit.
myjob:
when: always
rules:
- if: ...
when: on_success # this takes precedence if this rule matches
- if: ... # uses the default "when:" if this rule matches
In which case, adding the when: to the rules, the when: specified in the rules will take precedence over the when: set in the job body when the rule matches.
In older versions of GitLab, mixing job:when: and job:rules:when: is not allowed and results in an error.
I think that at the end of the rules block the line when: never tells that the pipeline should not be run in any other cases.
Because by default it runs after each commit in any created MR.
Like others have said, the - when: is how you do an 'else' condition. However, in this case it is redundant because - when: never is the default 'else' when rules are used.
As far as why this code is there... This may just be a personal preference or coding standard. Sometimes it's nice to make this explicit for clarity, even if redundant.