Skip to content

Instantly share code, notes, and snippets.

@OleksiyRudenko
Last active May 21, 2022 22:20
Show Gist options
  • Save OleksiyRudenko/236c3046fbba028e0555fa847dae7001 to your computer and use it in GitHub Desktop.
Save OleksiyRudenko/236c3046fbba028e0555fa847dae7001 to your computer and use it in GitHub Desktop.
Contributing to a 3rd party repo for beginners

Contributing to a 3rd party repo for beginners

Table of Contents

Pre-requisites

You know and use basic git commands like init, clone, add, commit, branch, checkout, merge, pull, push.

You probably know and use git commands like fetch, pull --rebase, rebase, cherry-pick.

You want to contribute to a repo you do not have write access to.

You do not know how to or do not feel confident working with repos you do not have write access to.

You do not follow any firm workflow working with your own repos or repos you do not have write access.

What will you learn

  • How to keep your fork in sync with a source repo
  • How to minimize risks of conflicts
  • How to keep your repo history tree as clean as possible
  • How to contribute properly via pull requests

A good workflow to start with

Some definitions:

  • upstream is a repo you want to contribute to
  • origin or fork is your own fork of an upstream
  • local is a local clone of origin
  • master is a default branch (master for older repos or main for more recent repos)

Initialize things

  1. Fork an upstream: on GitHub navigate to the upstream and click Fork button.
  2. git clone <origin-url>.git <project-directory> on your machine to clone your fork
  3. cd <project-directory>
  4. git remote add <upstream-url>.git to enable upstream-related actions

Add your changes

It is important to have your fork in sync with upstream, employ branches and follow certain workflow to minimize conflicts risks and keep the project's git history tree as clean as possible.

Initialize a feature branch

  1. sync local and origin with upstream git checkout master && git pull upstream master && git push origin master
  2. create a feature branch with a meaningful name git checkout -b <feature-branch-name>

There are many branch naming conventions. Few to mention are:

  • start with author initials so other collaborators know who initialized the branch and also find branches per author, e.g. or-feature-portview
  • use slashes to denominate scopes, e.g. feature/api/rest, bugfix/sleep
  • use ticket/issue/epic/story id, e.g. feat/epic123/story128/search-people

Useful alias:

git config --global alias.sync-master '!git checkout master && git pull upstream master && git push origin master'

Usage: git sync-master

Feature development cycle

  1. do whatever you want on a dedicated feature branch
  2. commit often: git add . && git commit -m "Add REST api PATCH method"
  3. squash eventually grouping commits as appropriate: git rebase -i <REF> (Making use of git rebase)
  4. sync eventually local, origin, and feature branch with upstream
    • git checkout master && git pull upstream master && git push origin master
    • git checkout - && git merge master
    • resolve conflicts using your IDE or command line
    • when done git add . && git commit -m "Resolved merge conflict by incorporating both suggestions"
    • see also Resolving a merge conflict using the command line
  5. go to #1
  6. eventually push to origin: git push origin <feature-branch-name>

Useful alias:

git config --global alias.sync-branch '!git sync-master && git checkout - && git merge master'

Usage: git sync-branch (it also does sync-master as a part of the flow)

Commit message

There are numbers of commit message structure conventions. To mention a few:

  • start with commit scope, e.g. one of feat|fix|docs|style|refactor|test|chore
  • add feature/fix scope, e.g. (api)
  • use imperative mood in the subject line, e.g. one of Add|Change|Fix|Refactor|Remove|Bump version|Release version

If you resolve an issue (in upstream or fork) it is useful to have a note on issue resolution.

Your commit message may look like the following

fix(foo api): Fix ABC component render conditions

Resolves: #12
See also: #34, #78

Further reading:

DON'Ts

Do not squash or rebase what is already on remotes!

Do not overwrite hsitory on remotes!

NB

The above doesn't cover the case when you work on the same branch with someone else, when you will prefer git pull --rebase over git pull.

Contribute via pull request

Contributing is not necessarily required. You may develop your fork for your own purposes (adhering to upstream license conditions).

Otherwise stick to the following contribution workflow:

  1. git push origin <feature-branch-name> to push your feature branch to the origin.
  2. Navigate to the cloud git hub (e.g. GitHub)
  3. Use cloud UI to create the PR
  4. Pass through code review process until your changes are merged or declined

Once your feature branch gets merged you will find your commits in upon next sync with upstream. So, you don't need merging those to your master locally.

However, you will need to merge into master if you do not contribute to the upstream or your PR is declined and you want to keep those for yourself.

Cleaning up

Once your PR approved and merged you can get rid of your feature branch:

  • git branch -D feature-branch locally
  • git push --delete origin feature-branch on your remote

A better workflow

Work In Progress under the cut
  1. Keep things in sync
  2. When base branch (master) gets updated, rebase feature branch onto it
    • NB! If a feature branch is on remote already then after rebase push --force is required to get the remote updated; USE WITH CAUTION
    • an alternative solution: branch off from master (new branch) and cherry-pick from old branch or rebase from the old branch onto new branch; remove old branch both locally and on remote
  3. When ready to update master
    • cherry-pick or rebase onto master and squash (using e.g. PR)
    • remove feature branch

Workflow visualized

Basic git contribution workflow visualized

@realmariano
Copy link

Hello @OleksiyRudenko, great gist. I am attaching below a spanish version of it perhaps you find it useful to add it to your original.
Also I would like to ask you if I may use this spanish version for educational proposes (givin the proper credit to you of course).
Regards

Contribuir a un repositorio de terceros (para principiantes)

created by @OleksiyRudenko original english version
translated to Spanish @realmariano

Tabla de contenido

Requisitos previos

Conoces y usas comandos básicos de git como
init, clone, add, commit,
branch, checkout, merge, pull, push.

Probablemente conoces y usas comandos de git como
fetch, pull --rebase, rebase, cherry-pick.

Quiere contribuir a un repositorio al que no tiene acceso de escritura.

No sabes o no te sientes seguro trabajando
con repositorios a los que no tiene acceso de escritura.

No sigue ningún flujo de trabajo firme trabajando con el suyo propio.
repos o repos no tiene acceso de escritura.

Que aprenderás

  • Cómo mantener tu bifurcación sincronizada con un repositorio fuente
  • Cómo minimizar los riesgos de conflictos
  • Cómo mantener el árbol del historial de su repositorio lo más limpio posible
  • Cómo contribuir adecuadamente a través de solicitudes de extracción

Un buen flujo de trabajo para empezar

Algunas definiciones:

  • upstream es un repositorio al que desea contribuir
  • origin o fork es tu propia bifurcación de un upstream
  • local es un clon de origen local
  • master es una rama predeterminada (master para repositorios más antiguos o main para repositorios más recientes)

Inicializar cosas

  1. Bifurque un flujo ascendente : en GitHub, navegue hasta el flujo ascendente y haga clic en el botón Fork.
  2. git clone <origin-url>.git <project-directory>
    en su máquina para clonar su bifurcación on your machine to clone your fork
  3. cd <project-directory>
  4. git remote add <upstream-url>.git para habilitar acciones relacionadas con el flujo ascendente

Agregue sus cambios

Es importante tener su bifurcación sincronizada con upstream,
emplear sucursales y seguir cierto flujo de trabajo
para minimizar los riesgos de conflictos y mantener el árbol histórico de git del proyecto lo más limpio posible.

Inicializar una branch (rama) de características

  1. sincronización local y origen con upstream
    git checkout master && git pull upstream master && git push origin master
  2. crea una rama de características con un nombre significativo
    git checkout -b <feature-branch-name>

Hay muchas convenciones de nombres de sucursales. Algunos para mencionar son:

  • comenzar con las iniciales del autor para que otros colaboradores sepan quién
    inicializó la rama y también encontró ramas por autor, por ejemplo , or-feature- portview
  • use barras para denominar ámbitos, por ejemplo , feature/ api /rest, bugfix/sleep
  • use el ticket/número/epic/story id, por ejemplo , feat/epic123/story128/search-people

Alias útil:

git config --global alias.sync -master '!git checkout master && git pull upstream master && git push origin master'

Uso: git sync-master

Ciclo de desarrollo de características

  1. haz lo que quieras en una rama de funciones dedicada
  2. comete a menudo: git add. && git commit -m "Agregar método REST api PATCH"
  3. squash eventualmente agrupando confirmaciones según corresponda:
    git rebase - i <REF>
    (Haciendo uso de git rebase)
  4. sincronizar eventualmente la rama local, de origen y de funciones con upstream
  • git checkout master && git pull upstream master && git push origin master
  • git checkout - && git merge master
  • resuelve conflictos usando tu IDE o línea de comando
  • cuando termine git add. && git commit -m "Se resolvió el conflicto de fusión incorporando ambas sugerencias"
  • ver también
    Resolución de un conflicto de fusión mediante la línea de comandos
  1. ir a #1
  2. Eventualmente empujar al origen: git push origin <feature-branch-name>

Alias útil:

git config --global alias.sync -branch '!git sync-master && git checkout - && git merge master'

Uso: git sync-branch (también hace sync-master como parte del flujo)

Mensaje de Commit (confirmación)

Hay varias convenciones de estructura de mensajes de commit.
Por mencionar algunos:

  • comenzar con el entorno de commit, por ejemplo, uno de los siguientes feat|fix|docs|style|refactor|test| chore
  • agregar función/arreglar alcance, por ejemplo, ( api )
  • use modo imperativo en la línea de asunto, por ejemplo, uno de Add|Change|Fix|Refactor|Remove|Bump version|Release version

Si resuelve un problema (en upstream o bifurcación --fork--), es útil tener una nota sobre la resolución del problema.

Su mensaje de confirmación puede parecerse al siguiente

fix ( foo api ): Fix ABC component render conditions

Resolves: #12
See also: #34, #78

Otras lecturas:

NO HACER

¡No aplastes ni hagas rebase de lo que ya está en el remoto!

¡No sobrescriba la historia de los remotos!
NB

Lo anterior no cubre el caso cuando trabajas en la misma branch (rama)
con alguien más,
en ese caso es preferible git pull --rebase sobre git pull.

Contribuir a través de una solicitud de extracción (pull request)

Contribuir no es necesariamente obligatorio.
Puedes desarrollar tu tenedor para tus propios fines.
(cumpliendo con las condiciones de la licencia upstream).

De lo contrario, siga el siguiente flujo de trabajo de contribución:

  1. git push origin <feature-branch-name> para enviar la rama de funciones al origen.
  2. Navegue hasta el hub de git en la nube (p. ej., GitHub o Gitlab)
  3. Use la interfaz de usuario en la nube para crear el PR
  4. Pase por el proceso de revisión de código hasta que su
    los cambios se fusionan o rechazan

Una vez que su rama de funciones se fusione, encontrará sus confirmaciones
en la próxima sincronización con upstream. Por lo tanto, no necesita fusionar esos
a su master localmente.

Sin embargo, deberá fusionarse con master si no contribuye al upstream o su PR es rechazado y desea
guardarlos para usted.

Limpiar

Una vez que su PR sea aprobado y fusionado, puede deshacerse de su rama de características:

  • git branch -D feature-branch localmente
  • git push --delete origin feature-branch en tu control remoto

Un mejor flujo de trabajo

Trabajo en curso bajo el corte

  1. Mantén las cosas sincronizadas
  2. Cuando la rama base (maestro) se actualice, rebase (cree una nueva base) la rama de características en ella
    • ¡NB! Si una rama de función ya está en remoto, entonces después de la reorganización
      Se requiere push --force para actualizar el control remoto; USE CON PRECAUCIÓN
    • una solución alternativa: bifurcarse desde el maestro (nueva bifurcación) y
      elegir individualmente desde la rama vieja o cambiar la base de la rama vieja a la nueva rama;
      eliminar la rama antigua tanto de forma local como remota
  3. Cuando esté listo para actualizar master
    • selección idividual o rebase en maestro y squash (usando, por ejemplo, PR)
    • eliminar la rama de función

Flujo de trabajo visualizado

Flujo de trabajo básico de contribución de git visualizado

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment