Bitbucket: Pull PR and commit local changes to remote forks
Working in a large repo, with multiple forks, committing to a main repo
As a maintainer of a very large repo, we ask our developers to use the Forking Workflow
This has some challenges, especially when reviewing PRs and committing changes to those PRs on the respective, remote forks.
After many months and lots of blog reading, git-scm.org - The Refspec review and trial and error, I think I finally figured out the best way to work with this forking strategy.
First things first, set your refspecs to pull down all the PRs to the main repo. I picked this up from Atlassian's blog - Pull Request Proficiency.
I went about it slightly differently from their post but it works just as well and it was fewer steps.
Add a git config
for remote.origin.fetch
This adds a local namespace so you can eventually checkout a pr with shorthand
git config add remote.origin.fetch +refs/pull-requests/*:refs/remotes/origin/pr/*
git pull origin <main branch>
or whichever branch you are receiving the PRs
git pull origin develop
remote: Enumerating objects: 501, done.
remote: Counting objects: 100% (326/326), done.
remote: Compressing objects: 100% (229/229), done.
remote: Total 248 (delta 170), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (248/248), 54.99 KiB | 1.37 MiB/s, done.
Resolving deltas: 100% (170/170), completed with 42 local objects.
From ssh://bitbucket.<your-domain>.com:<port>/<project>/<repo>
* branch develop -> FETCH_HEAD
* [new ref] refs/pull-requests/1472/from -> origin/pr/1472/from
* [new ref] refs/pull-requests/1473/from -> origin/pr/1473/from
* [new ref] refs/pull-requests/1474/from -> origin/pr/1474/from
* [new ref] refs/pull-requests/1475/from -> origin/pr/1475/from
* [new ref] refs/pull-requests/1477/from -> origin/pr/1477/from
Now you can checkout the PR on your local machine with git checkout origin/pr/1474/from
git checkout origin/pr/1474/from
Note: switching to 'origin/pr/1474/from'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
Or undo this operation with:
git switch -
Turn off this advice by setting config variable advice.detachedHead to false
HEAD is now at <commit> fix spec validations
Now you're free to poke around, make changes, and commit changes to your local detached HEAD state
You'll notice here, git reminds you that you are in detached HEAD
state on commit.
git commit -m "<commit message title>" -m " <commit message body>[APIDESGN-1367]"
[detached HEAD <commit>] feat(api): update event-notifications schema
7 files changed, 32 insertions(+), 384 deletions(-)
delete mode 100644 <some-file-named-you-modified>
-- You ARE using <issue-keys> in your commit messages, RIGHT?!?!
Now comes the fun part, setting up the remote fork and pushing your local changes to the PR. Add a new remote
and name it whatever you want. This is the fork where the PR originated. I usually use the PR number as the remote to remind me of the PR number
git remote add 1474 ssh://git@bitbucket.<your-domain>.com:<port>/<project>/<repo>.git
You can run git remote -vv
to see all of your remote configs
git remote -vv
1474 ssh://git@bitbucket.<your-domain>:<port>/<fork-project>/<repo>.git (fetch)
1474 ssh://git@bitbucket.<your-domain>:<port>/<fork-project>/<repo>.git (push)
origin ssh://git@bitbucket.<your-domain>:<port>/<main-project>/<repo>.git (fetch)
origin ssh://git@bitbucket.<your-domain>:<port>/<main-project>/<repo>.git (push)
Now you can run git branch
and notice you have the HEAD detached
and your develop
branch. (you may have additional branches)
git branch
* (HEAD detached from origin/pr/1474/from)
develop
It's time to fetch
the upstream repo to pull down the actual branch name on the remote fork
git fetch 1474
remote: Enumerating objects: 54, done.
remote: Counting objects: 100% (54/54), done.
remote: Compressing objects: 100% (52/52), done.
remote: Total 60 (delta 28), reused 1 (delta 1), pack-reused 6
Unpacking objects: 100% (60/60), 16.54 KiB | 127.00 KiB/s, done.
From ssh://bitbucket.<your-domain>:<port>/<fork-project>/<repo>
* [new branch] develop -> 1474/develop
* [new branch] feature/APIDESGN-1367-<branch-name> -> 1474/feature/APIDESGN-1367-<branch-name>
Now we know the name of the original branch from the fork, we can checkout
and merge
our new commits. Since I've committed changes to the detached HEAD, I need to merge that commit into the branch. You can work in detached HEAD state or you can work on the actual branch, I just happened to make some changes while poking around in detached state. The beauty of checking out the branch in this fashion is git automatically sets the new branch to track the upstream branch, which is linked to the original PR
git checkout feature/APIDESGN-1367-<branch-name>
Warning: you are leaving 1 commit behind, not connected to
any of your branches:
<commit> feat(api): update event-notifications schema
If you want to keep it by creating a new branch, this may be a good time
to do so with:
git branch <new-branch-name> <commit>
Switched to a new branch 'feature/APIDESGN-1367-<branch-name>'
branch 'feature/APIDESGN-1367-<branch-name>' set up to track '1474/feature/APIDESGN-1367-<branch-name>'.
Checking git branch -vv
once more indicates the new branch is tracking the upstream we defined as 1474
git branch -vv
develop <commit> <commit-message>
* feature/APIDESGN-1367-<branch-name> <commit> [1474/feature/APIDESGN-1367-<branch-name>] fix spec validations
I opted not to create a new branch as suggested by the git cli but rather merge
my previous commit on the detached HEAD to the branch we just checked out
git merge <commit-from-detached-head>
Updating <commit>..<commit>
Fast-forward
...<some-modified-files> | 104 +---------
7 files changed, 32 insertions(+), 384 deletions(-)
Now we are ready to push our local changes to the upstream remote fork, but first let's check the status to see where we are. Oh look! Git recognizes we are now 1 commit ahead of our upstream remote fork branch
git status
On branch feature/APIDESGN-1367-<branch-name>
Your branch is ahead of '1474/feature/APIDESGN-1367-<branch-name>' by 1 commit.
(use "git push" to publish your local commits)
OK, let's push! We use the upstream remote name and the branch name to tell git where we want to go and where the changes were made
git push 1474 feature/APIDESGN-1367-<branch-name>
Enumerating objects: 24, done.
Counting objects: 100% (24/24), done.
Delta compression using up to 8 threads
Compressing objects: 100% (12/12), done.
Writing objects: 100% (13/13), 1.44 KiB | 491.00 KiB/s, done.
Total 13 (delta 8), reused 0 (delta 0), pack-reused 0
remote:
remote: View pull request for feature/APIDESGN-1367-<branch-name> => develop:
remote: https://bitbucket.<your-domain>.com/projects/<project>/repos/<repo>/pull-requests/1474
remote:
To ssh://bitbucket.<your-domain>.com:<port>/<project>/<repo>.git
<commit>..<commit> feature/APIDESGN-1367-<branch-name> -> feature/APIDESGN-1367-<branch-name>