Pull requests, Squashed commits, Remote Merges

Because Stash doesn't allow users to edit the commit messages when merging pull requests, and because Stash uses the default commit message generated when squashing a branch onto another and thus the message is a sum total of all commit messages on that branch, we perform squashed merges manually.

However, if the source branch has more than one commit on it, the pull request is not marked as "remotely merged" when the Branch B is squashed onto Branch A and A is pushed to the remote. Even when I include the boilerplate text that Stash adds to pull request merge messages such as "Merge pull request #27 in FUBAR/adapter from feature/2.3-FUBAR-395-FuBar-FileMetrics-Payload to develop" or include a list of all of the shortened commit hashes ("git log --pretty=format:'%h'"), the pull request is still set to open after I push Branch A, now with a single squashed commit representing the merged pull request, to the remote.

I understand that Stash probably looks for the commit IDs on Branch A that are members of the pull request for Branch B, and if they appear in both places Stash will likely consider the pull request merged. The question is, what happens when those commit IDs disappear because you've squashed them? Clearly Stash can handle it internally since we have our pull request behavior set to ff-only-squash, and when we click the Merge button Stash knows it's merged the thing. But again, because of the noisy commit message generated, we merge by hand. We just need to know how to let Stash know it's been merged.


3 answers

1 accepted

1 vote

Hi Andrew,

When a push is received that updates either the source or target branch of a pull request, Stash updates the pull request. As part of this 'rescoping' logic, it checks:

  • Has either branch been deleted? --> pull request is declined automatically
  • Are there any commits on the source branch that are not on target branch? --> pull request is closed and marked as 'merged remotely'

In your case, I assume you're doing the following locally:

git checkout target-branch
git merge --ff-only --squash source-branch
git commit -m "Your custom message"
git push origin HEAD

This only updates the target branch; the source branch is unchanged and Stash will still see unmerged commits (the original commits prior to squashing) and keep the pull request open. It will rescope the pull request, which should result in an empty diff.

If you change your command a little bit, Stash will be able to recognize the fact that your pull request has been merged remotely:

git checkout target-branch
git merge --ff-only --squash source-branch
git commit -m "Your custom message"
git push origin HEAD
git checkout -B source-branch
git push --force origin HEAD

The last two lines will recreate source-branch at the squashed commit. You'll have to force-push that branch to update it on the server because it's not a fast-forward merge (even though the diff is empty).

I hope this explains the way Stash does 'remote merge' detection!



Hi Michael,

Thanks for the help! I think on line #5 of your suggested help you actually mean:

git checkout -B target-branch

The man page for git-checkout states "If -B is given, <new_branch> is created if it doesn't exist; otherwise, it is reset" whereas there is no -B option for git-branch.

Also, the last line of the suggested help might need to include the remote:

git push --force origin HEAD

However, when I do these things they don't actually work:

[0]akutz@pax:vcopsadapter$ git checkout -B develop
Reset branch 'develop'
Your branch is up-to-date with 'origin/develop'.

[0]akutz@pax:vcopsadapter$ git push --force origin HEAD
Everything up-to-date

No matter the variations I try, the last command always indicates everything is up to date.

Yeah, you're right about the checkout and providing a remote on the force push. I've edited my answer to reflect that.

I've just tested the steps and they work for me. Here's a script of what I've done:

# First create a new repo in Stash 
git init test-repo
git remote add origin http://localhost:7990/stash/scm/proj/test.git
echo test &gt; test
git add test
git commit -m "Initial commit"
git checkout -b develop
echo testing &gt;&gt; test &amp;&amp; git commit -am "Change"
echo testing &gt;&gt; test &amp;&amp; git commit -am "Change"
git push origin --all

# create pull request in Stash
git checkout master
git merge --ff-only --squash develop
git commit -m "Squashed changes"
git push origin HEAD

# verify pull request in Stash - still open, diff is empty
git checkout -B develop
git push --force origin HEAD  

# verify pull request in Stash - closed, marked as merged remotely

Hi Michael,

I'll try that as well. You know, I wonder if it was because the open pull request I tried it on only had a single commit on the source branch. It didn't need a squash, but I did it anyway just to see if the suggestion worked. I wonder if the scenario with squashing a single commit doesn't work. I mean, at that point I'm really just changing the commit ID of a single commit.

The other difference is that developers often rebase their feature branches from develop prior to opening a pull request or often after they open the pull request. However, the pull requests *do* update themselves when a developer rebases the branch for the pull request. For example, it will say 12 added, 12 deleted. Still, I don't know if that could cause issues.

Like I said, I'll create a new repo and try your steps on our set up. I do have the following configured in the stash propreties file:

# The default merge policy for the server is to only accept pull 
# requests if they are fast-foward only capable and then to process
# them as squashed commits.

Would that have an effect on how Stash resolve the pull request if it's merged remotely?

Re: only a single commit, it shouldn't matter. Perhaps you forgot to add the --squash option on the merge command?

Re: the plugin.stash-scm-git.pullrequest.merge.strategy=squash-ff-only option, that option only affects the merge Stash does when you merge the pull request through the UI. It should not matter for remotely merged pull requests.

Hi Michael,

No, it was definitely squashed. I know because I hard reset develop after that didn't work and merged it sans squash and pushed develop. That worked as expected since the same commit ID was now on develop that was on the source branch.

Hi Michael,

I also have the Workzone plug-in installed. I wonder if that affects the remote merge logic? For the repo in question the only setting I have enabled on Workzone are the automatic branch reviewers and to automatically withdraw any approvals for pull requests if a change is pushed to a branch with an open pull request.

Hi Michael,

That worked! I misunderstood your original instructions:

git checkout target-branch
git merge --ff-only --squash source-branch
git commit -m "Your custom message"
git push origin HEAD
git checkout -B target-branch
git push --force origin HEAD

Or rather I guess maybe they had an error. Line #5 should have actually been "git checkout -B source-branch"

In your last script you checked out and reset develop, and in your latest example that was the source branch. That's when I realized that the original instructions had me reset the target branch. So I tried the script and reset the source branch and force pushed it after I performed the squash and it worked perfectly!


Hi Michael,

May I suggest you edit your original answer to reflect the correct command? That way if people find this page they won't have to read the entire thread to find the correct method. Thanks again!

Done! Sorry about the confusion

Hi Michael,

One more nit to pick. I think "The last two lines will recreate target-branch at the squashed commit" should read "The last two lines will recreate source-branch at the squashed commit."

Thanks again!

I believe a squashed merge commit is different from a normal merge commit resulting from a non-fast-forward merge. I think a squashed merge commit does not reference the source branch as one of its parents.

From the Git docs: "Produce the working tree and index state as if a real merge happened (except for the merge information)"

So if instead of doing `git merge --squash` you were to instead do `git merge --no-ff --no-commit`, you would be able to edit your merge commit message and retain the merge metadata that would allow Stash to link things together.

Hi Gordon,

That's an idea, but since Stash does actually perform a squashed commit when you configure it to ff-only and squash, there has to be a way of doing that remotely.

And more specifically, I don't want all of the history from the feature branch, hence the squashed commit. When you perform a merge with --no-commit all you're doing is giving yourself the ability to edit the merge commit message. The merge still occurs as it normally would -- all of the commit IDs that existed on the source branch now exist on the destination branch.

I tried this solution, and it no longer works. It appears that the fix for Atlassian BSERV-4219 (https://jira.atlassian.com/browse/BSERV-4219) has caused the server to decline the pull -requests if you push the release/target branch before you push your feature branch.

In order for Bitbucket to recognize the request as merged, I had to push the feature branch before pushing the release branch:

git merge --ff-only --squash $FEATURE_BRANCH
git commit -m "B-$BLINUM: $MESSAGE" -m"    Delivery of $FEATURE_BRANCH"
git branch --force $FEATURE_BRANCH HEAD
git push --force origin $FEATURE_BRANCH
git push origin $RELEASE_BRANCH


See this SO discussion for more info:


Suggest an answer

Log in or Join to answer
Community showcase
Jason Wong
Published yesterday in Agility Beta

Welcome to agility

Every team in the world is unique, and so   Atlassian believes   that each and every team's best way of working  needs to  be molded to their unique circumstances  – ...

309 views 6 15
Read article

Atlassian User Groups

Connect with like-minded Atlassian users at free events near you!

Find a group

Connect with like-minded Atlassian users at free events near you!

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you
Atlassian Team Tour

Join us on the Team Tour

We're bringing product updates and pro tips on teamwork to ten cities around the world.

Save your spot