# Bitbucket: Pull PR and commit local changes to remote forks

As a maintainer of a very large repo, we ask our developers to use the [Forking Workflow](https://www.atlassian.com/git/tutorials/comparing-workflows/forking-workflow#:~:text=Forking%20is%20a%20git%20clone,org%2FuserA%2Fopen%2Dproject)

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](https://git-scm.com/book/en/v2/Git-Internals-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](https://www.atlassian.com/git/articles/pull-request-proficiency-fetching-abilities-unlocked).

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
    

```bash
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
    

```bash
 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`
    

```bash
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.
    

```bash
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 &lt;issue-keys&gt; 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
    

```bash
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
    

```bash
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)
    

```bash
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
    

```bash
 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
    

```bash
 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`
    

```bash
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
    

```bash
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
    

```bash
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
    

```bash
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>
```
