flowchart TD
subgraph gh["<b>GitHub</b>"]
subgraph project["<b>Project</b>"]
upstream/main["<b>upstream/main</b>"]
upstream/dev["<b>upstream/dev</b>"]
end
subgraph fork["<b>Your fork</b>"]
origin/main["<b>origin/main</b>"]
origin/dev["<b>origin/dev</b>"]
end
end
subgraph local["<b>Your machine</b>"]
subgraph clone["<b>Your clone</b>"]
main["<b>main</b>"]
dev["<b>dev</b>"]
end
end
classDef location fill:#bfbfbf, color:#000;
class gh location;
class local location;
classDef repo fill:#85adad, color:#000;
class project repo;
class fork repo;
class clone repo;
upstream/main == GitHub Fork ==> origin/main
origin/main == git clone ==> main
upstream/main == git pull upstream main ==> main
main -- git push origin main --> origin/main
main == git switch -c dev ==> dev
dev == git push origin dev ==> origin/dev
origin/dev == GitHub PR ==> upstream/dev
upstream/dev -. PR merged by maintainer .-> upstream/main
linkStyle 0 stroke:YellowGreen;
linkStyle 1 stroke:YellowGreen, color:magenta;
linkStyle 2 stroke:goldenrod, color:magenta;
linkStyle 3 stroke:sienna, color:magenta;
linkStyle 4 stroke:goldenrod, color:magenta;
linkStyle 5 stroke:goldenrod, color:magenta;
linkStyle 6 stroke:goldenrod;
linkStyle 7 stroke:CornflowerBlue, stroke-width:4px;
Working without write access
There are two situations in which you do not have write access to projects:
- you are an outsider (i.e. you are contributing to open source projects you are using, but you are not part of the team),
- you are part of the team, but the person in charge wants a workflow via pull requests (PRs)—this is often the case in large teams with a more top-down organization.
This section shows you how you can contribute to such projects.
Opening issues
The easiest thing to do is to open an issue.
This is a way to bring the attention of the maintainer(s) of the project to a particular question without attempting to directly address the problem.
You might open an issue for instance if:
- you are having problems with an open source tool you are using,
- you found a bug,
- you want to suggest a new feature,
- (more applicable to the research collaboration framework) you want your team to address some question relevant to the project—an issue is a way to keep something in the mind of everyone involved until it is resolved and closed.
If enabled by the maintainer of a project, the Discussions tab is the place where you want to ask for help or discuss topics less directly pertinent to improving the project.
Submitting changes
If you want to actually edit the content of a project you don’t have write-access to, you have to create a pull request (PR).
In GitLab, pull requests are called merge requests (MR), but the concepts are exactly the same.
Workflow summary
This is a multi-step process. Here is a summary that we will break down step by step below:
flowchart LR
subgraph legend["<b>Legend</b>"]
direction LR
start1[ ] ===>|To do before first PR| stop1[ ]
style start1 height:0px;
style stop1 height:0px;
start2[ ] ===>|To do for each PR| stop2[ ]
style start2 height:0px;
style stop2 height:0px;
start3[ ] --->|"(Optional) If you want to keep your fork up to date"| stop3[ ]
style start3 height:0px;
style stop3 height:0px;
style legend fill:#fff, color:grey;
linkStyle 0 stroke:YellowGreen, color:grey;
linkStyle 1 stroke:goldenrod, color:grey;
linkStyle 2 stroke:sienna, color:grey;
end
“Project” = the project you want to contribute to
“Your fork” = your fork of the project
“Your clone” = your local clone of the project (cloned from origin)
“dev” = a new branch you create and switch to before committing changes
“upstream” = the name of the remote corresponding to the original project
“origin” = the name of the remote you can push to (your fork)
Workflow step by step
Setup
Before you can submit PRs, there are two steps that you need to do to set things up.
Fork the project
First, create a fork of the project. This will make a copy of the repository into your GitHub account: go to GitHub and fork the project by clicking on the Fork button in the top right corner:
flowchart TD
subgraph gh["<b>GitHub</b>"]
subgraph project["<b>Project</b>"]
upstream/main["<b>upstream/main</b>"]
upstream/dev["<b>upstream/dev</b>"]
end
subgraph fork["<b>Your fork</b>"]
origin/main["<b>origin/main</b>"]
origin/dev["<b>origin/dev</b>"]
end
end
subgraph local["<b>Your machine</b>"]
subgraph clone["<b>Your clone</b>"]
main["<b>main</b>"]
dev["<b>dev</b>"]
end
end
classDef location fill:#bfbfbf, color:#000;
class gh location;
class local location;
classDef repo fill:#85adad, color:#000;
class project repo;
class fork repo;
class clone repo;
upstream/main == GitHub Fork ==> origin/main
origin/main ~~~ main
upstream/main ~~~ main
main ~~~ origin/main
main ~~~ dev
dev ~~~ origin/dev
origin/dev ~~~ upstream/dev
upstream/dev ~~~ upstream/main
linkStyle 0 stroke:YellowGreen;
linkStyle 1 stroke:YellowGreen, color:magenta;
linkStyle 2 stroke:goldenrod, color:magenta;
linkStyle 3 stroke:sienna, color:magenta;
linkStyle 4 stroke:goldenrod, color:magenta;
linkStyle 5 stroke:goldenrod, color:magenta;
linkStyle 6 stroke:goldenrod;
If you want to develop your own version of the project, you can keep working on your fork and develop it in a direction different from that of the initial project. You have all privileges on the forked project: your fork is your repo. This means that you can make any changes you want. You can clone it to your machine, create commits and push them back to your fork.
Here however, we want to submit changes to the original project.
Clone your fork
Then clone your fork to your machine to have a local copy of the project. This will automatically set your fork on GitHub as a remote called origin.
Since origin is your fork, you can freely pull from and push to it.
# If you have set SSH for your GitHub account
git clone git@github.com:<user>/<repo>.git <name>
# If you haven't set SSH
git clone https://github.com/<user>/<repo>.git <name>flowchart TD
subgraph gh["<b>GitHub</b>"]
subgraph project["<b>Project</b>"]
upstream/main["<b>upstream/main</b>"]
upstream/dev["<b>upstream/dev</b>"]
end
subgraph fork["<b>Your fork</b>"]
origin/main["<b>origin/main</b>"]
origin/dev["<b>origin/dev</b>"]
end
end
subgraph local["<b>Your machine</b>"]
subgraph clone["<b>Your clone</b>"]
main["<b>main</b>"]
dev["<b>dev</b>"]
end
end
classDef location fill:#bfbfbf, color:#000;
class gh location;
class local location;
classDef repo fill:#85adad, color:#000;
class project repo;
class fork repo;
class clone repo;
upstream/main ~~~ origin/main
origin/main == git clone ==> main
upstream/main ~~~ main
main ~~~ origin/main
main ~~~ dev
dev ~~~ origin/dev
origin/dev ~~~ upstream/dev
upstream/dev ~~~ upstream/main
linkStyle 0 stroke:YellowGreen;
linkStyle 1 stroke:YellowGreen, color:magenta;
linkStyle 2 stroke:goldenrod, color:magenta;
linkStyle 3 stroke:sienna, color:magenta;
linkStyle 4 stroke:goldenrod, color:magenta;
linkStyle 5 stroke:goldenrod, color:magenta;
linkStyle 6 stroke:goldenrod;
Create a PR
Creating a PR is a four-step process.
1. Update your local repo
You need to make sure that your local copy of the repo is up to date by pulling from upstream.
Add upstream
Add a second remote, this one pointing to the initial project. It is usual to call this remote upstream:
# If you have set SSH for your GitHub account
git remote add upstream git@github.com:<user>/<repo>.git
# If you haven't set SSH
git remote add upstream https://github.com/<user>/<repo>.gitPull from upstream
You can now pull from upstream to keep your local repo up to date:
git pull upstream mainflowchart TD
subgraph gh["<b>GitHub</b>"]
subgraph project["<b>Project</b>"]
upstream/main["<b>upstream/main</b>"]
upstream/dev["<b>upstream/dev</b>"]
end
subgraph fork["<b>Your fork</b>"]
origin/main["<b>origin/main</b>"]
origin/dev["<b>origin/dev</b>"]
end
end
subgraph local["<b>Your machine</b>"]
subgraph clone["<b>Your clone</b>"]
main["<b>main</b>"]
dev["<b>dev</b>"]
end
end
classDef location fill:#bfbfbf, color:#000;
class gh location;
class local location;
classDef repo fill:#85adad, color:#000;
class project repo;
class fork repo;
class clone repo;
upstream/main ~~~ origin/main
origin/main ~~~ main
upstream/main == git pull upstream main ==> main
main ~~~ origin/main
main ~~~ dev
dev ~~~ origin/dev
origin/dev ~~~ upstream/dev
upstream/dev ~~~ upstream/main
linkStyle 0 stroke:YellowGreen;
linkStyle 1 stroke:YellowGreen, color:magenta;
linkStyle 2 stroke:goldenrod, color:magenta;
linkStyle 3 stroke:sienna, color:magenta;
linkStyle 4 stroke:goldenrod, color:magenta;
linkStyle 5 stroke:goldenrod, color:magenta;
linkStyle 6 stroke:goldenrod;
Of course, if your local copy and the initial project have diverged in places, this will lead to conflicts that you will have to resolve as you merge the pulls from upstream.
Note that, while you can pull freely from upstream, you can’t push changes back to it directly since you don’t have write access to the initial project (if anybody could push to any project, that would be utter chaos).
2. Switch to new branch
You don’t want to create the changes for your PR on main: if the PR is rejected by the maintainer of the project or if they are taking time to accept it, you would then be stuck not knowing how to add new changes to your project.
It is much better to create a new branch for the changes you want to submit to the project as a PR (don’t forget to switch to that branch before committing the changes):
flowchart TD
subgraph gh["<b>GitHub</b>"]
subgraph project["<b>Project</b>"]
upstream/main["<b>upstream/main</b>"]
upstream/dev["<b>upstream/dev</b>"]
end
subgraph fork["<b>Your fork</b>"]
origin/main["<b>origin/main</b>"]
origin/dev["<b>origin/dev</b>"]
end
end
subgraph local["<b>Your machine</b>"]
subgraph clone["<b>Your clone</b>"]
main["<b>main</b>"]
dev["<b>dev</b>"]
end
end
classDef location fill:#bfbfbf, color:#000;
class gh location;
class local location;
classDef repo fill:#85adad, color:#000;
class project repo;
class fork repo;
class clone repo;
upstream/main ~~~ origin/main
origin/main ~~~ main
upstream/main ~~~ main
main ~~~ origin/main
main == git switch -c dev ==> dev
dev ~~~ origin/dev
origin/dev ~~~ upstream/dev
upstream/dev ~~~ upstream/main
linkStyle 0 stroke:YellowGreen;
linkStyle 1 stroke:YellowGreen, color:magenta;
linkStyle 2 stroke:goldenrod, color:magenta;
linkStyle 3 stroke:sienna, color:magenta;
linkStyle 4 stroke:goldenrod, color:magenta;
linkStyle 5 stroke:goldenrod, color:magenta;
linkStyle 6 stroke:goldenrod;
3. Push changes to origin
Make your changes, commit, then push your branch to origin:
flowchart TD
subgraph gh["<b>GitHub</b>"]
subgraph project["<b>Project</b>"]
upstream/main["<b>upstream/main</b>"]
upstream/dev["<b>upstream/dev</b>"]
end
subgraph fork["<b>Your fork</b>"]
origin/main["<b>origin/main</b>"]
origin/dev["<b>origin/dev</b>"]
end
end
subgraph local["<b>Your machine</b>"]
subgraph clone["<b>Your clone</b>"]
main["<b>main</b>"]
dev["<b>dev</b>"]
end
end
classDef location fill:#bfbfbf, color:#000;
class gh location;
class local location;
classDef repo fill:#85adad, color:#000;
class project repo;
class fork repo;
class clone repo;
upstream/main ~~~ origin/main
origin/main ~~~ main
upstream/main ~~~ main
main ~~~ origin/main
main ~~~ dev
dev == git push origin dev ==> origin/dev
origin/dev ~~~ upstream/dev
upstream/dev ~~~ upstream/main
linkStyle 0 stroke:YellowGreen;
linkStyle 1 stroke:YellowGreen, color:magenta;
linkStyle 2 stroke:goldenrod, color:magenta;
linkStyle 3 stroke:sienna, color:magenta;
linkStyle 4 stroke:goldenrod, color:magenta;
linkStyle 5 stroke:goldenrod, color:magenta;
linkStyle 6 stroke:goldenrod;
4. Submit a PR
After you have pushed your branch to origin, go to your fork on GitHub: GitHub will automatically offer to submit a PR in a pop-up and you can just follow the instructions:
flowchart TD
subgraph gh["<b>GitHub</b>"]
subgraph project["<b>Project</b>"]
upstream/main["<b>upstream/main</b>"]
upstream/dev["<b>upstream/dev</b>"]
end
subgraph fork["<b>Your fork</b>"]
origin/main["<b>origin/main</b>"]
origin/dev["<b>origin/dev</b>"]
end
end
subgraph local["<b>Your machine</b>"]
subgraph clone["<b>Your clone</b>"]
main["<b>main</b>"]
dev["<b>dev</b>"]
end
end
classDef location fill:#bfbfbf, color:#000;
class gh location;
class local location;
classDef repo fill:#85adad, color:#000;
class project repo;
class fork repo;
class clone repo;
upstream/main ~~~ origin/main
origin/main ~~~ main
upstream/main ~~~ main
main ~~~ origin/main
main ~~~ dev
dev ~~~ origin/dev
origin/dev == GitHub PR ==> upstream/dev
upstream/dev ~~~ upstream/main
linkStyle 0 stroke:YellowGreen;
linkStyle 1 stroke:YellowGreen, color:magenta;
linkStyle 2 stroke:goldenrod, color:magenta;
linkStyle 3 stroke:sienna, color:magenta;
linkStyle 4 stroke:goldenrod, color:magenta;
linkStyle 5 stroke:goldenrod, color:magenta;
linkStyle 6 stroke:goldenrod;
The maintainer of the initial project may accept or decline the PR. They may also make comments and ask you to make changes. If so, make new changes and push additional commits to that branch until they are happy with the change.
Once/if the maintainer accepts the PR, they merge it to the main branch in the project:
flowchart TD
subgraph gh["<b>GitHub</b>"]
subgraph project["<b>Project</b>"]
upstream/main["<b>upstream/main</b>"]
upstream/dev["<b>upstream/dev</b>"]
end
subgraph fork["<b>Your fork</b>"]
origin/main["<b>origin/main</b>"]
origin/dev["<b>origin/dev</b>"]
end
end
subgraph local["<b>Your machine</b>"]
subgraph clone["<b>Your clone</b>"]
main["<b>main</b>"]
dev["<b>dev</b>"]
end
end
classDef location fill:#bfbfbf, color:#000;
class gh location;
class local location;
classDef repo fill:#85adad, color:#000;
class project repo;
class fork repo;
class clone repo;
upstream/main ~~~ origin/main
origin/main ~~~ main
upstream/main ~~~ main
main ~~~ origin/main
main ~~~ dev
dev ~~~ origin/dev
origin/dev ~~~ upstream/dev
upstream/dev -. PR merged by maintainer .-> upstream/main
linkStyle 0 stroke:YellowGreen;
linkStyle 1 stroke:YellowGreen, color:magenta;
linkStyle 2 stroke:goldenrod, color:magenta;
linkStyle 3 stroke:sienna, color:magenta;
linkStyle 4 stroke:goldenrod, color:magenta;
linkStyle 5 stroke:goldenrod, color:magenta;
linkStyle 6 stroke:goldenrod;
linkStyle 7 stroke:CornflowerBlue, stroke-width:4px;
Congratulations: you have successfully contributed changes to the project. 🙂
You can now delete the branch you created for this PR (GitHub will offer you to do so on your fork with a pop-up). You can also delete it on your local repo with:
git branch -d dev # use the name you chose for your branch(Optional) Update your fork
Optionally, if you want to keep your fork up to date, you should pull from upstream to integrate the new changes to your local repo:
flowchart TD
subgraph gh["<b>GitHub</b>"]
subgraph project["<b>Project</b>"]
upstream/main["<b>upstream/main</b>"]
upstream/dev["<b>upstream/dev</b>"]
end
subgraph fork["<b>Your fork</b>"]
origin/main["<b>origin/main</b>"]
origin/dev["<b>origin/dev</b>"]
end
end
subgraph local["<b>Your machine</b>"]
subgraph clone["<b>Your clone</b>"]
main["<b>main</b>"]
dev["<b>dev</b>"]
end
end
classDef location fill:#bfbfbf, color:#000;
class gh location;
class local location;
classDef repo fill:#85adad, color:#000;
class project repo;
class fork repo;
class clone repo;
upstream/main ~~~ origin/main
origin/main ~~~ main
upstream/main -- git pull upstream main --> main
main ~~~ origin/main
main ~~~ dev
dev ~~~ origin/dev
origin/dev ~~~ upstream/dev
upstream/dev ~~~ upstream/main
linkStyle 0 stroke:YellowGreen;
linkStyle 1 stroke:YellowGreen, color:magenta;
linkStyle 2 stroke:sienna, color:magenta;
linkStyle 3 stroke:sienna, color:magenta;
linkStyle 4 stroke:goldenrod, color:magenta;
linkStyle 5 stroke:goldenrod, color:magenta;
linkStyle 6 stroke:goldenrod;
Then you should push those changes back to your fork:
flowchart TD
subgraph gh["<b>GitHub</b>"]
subgraph project["<b>Project</b>"]
upstream/main["<b>upstream/main</b>"]
upstream/dev["<b>upstream/dev</b>"]
end
subgraph fork["<b>Your fork</b>"]
origin/main["<b>origin/main</b>"]
origin/dev["<b>origin/dev</b>"]
end
end
subgraph local["<b>Your machine</b>"]
subgraph clone["<b>Your clone</b>"]
main["<b>main</b>"]
dev["<b>dev</b>"]
end
end
classDef location fill:#bfbfbf, color:#000;
class gh location;
class local location;
classDef repo fill:#85adad, color:#000;
class project repo;
class fork repo;
class clone repo;
upstream/main ~~~ origin/main
origin/main ~~~ main
upstream/main ~~~ main
main -- git push origin main --> origin/main
main ~~~ dev
dev ~~~ origin/dev
origin/dev ~~~ upstream/dev
upstream/dev ~~~ upstream/main
linkStyle 0 stroke:YellowGreen;
linkStyle 1 stroke:YellowGreen, color:magenta;
linkStyle 2 stroke:goldenrod, color:magenta;
linkStyle 3 stroke:sienna, color:magenta;
linkStyle 4 stroke:goldenrod, color:magenta;
linkStyle 5 stroke:goldenrod, color:magenta;
linkStyle 6 stroke:goldenrod;