DEV Community

Jean-Michel 🕵🏻‍♂️ Fayard
Jean-Michel 🕵🏻‍♂️ Fayard

Posted on • Updated on

Pull Requests: a simple workflow

Disclaimer: I’m not a git ninja, and I’m pretty sure a lot of people have written more sophisticated things on this topic. My only qualification is having made a lot of mistakes in the past.

So in the hope of being useful, here is my take on how to contribute simply and effectively a pull request:

  • I git clone the original repo. origin/master should point to the latest and greatest, not to my soon un-maintened fork
  • I hit “fork” on github and add my fork as a remote
  • I contribute a failing test that showcase what you have in mind
  • I open a pull-request to start the discussion

The discussion can have many outcomes: I may have requested something already possible, or outside of the scope of the project, or it’s a bad idea, or it’s good idea that the maintainers will implement ASAP, or it’s a good idea that I am ready to implement myself. 

Let’s assume the later case. I do the diligent work locally. Days or weeks later, I’m back in the pull request. I have some feedback, very good, I improve my code. 
What then happens especially well-maintained fast-moving projects is that I’m at this point way behind the commit I forked on. At this point I have been stuck in the past by having to do too heavy git gymnastics. (Looking at you git rebase!)

Here is a 4 steps workflow that gets the job done:

  • Pull and merge origin/master (reminder: origin is the project’s repo,)
  • Resolve conflicts, update things then commit
  • git reset --soft origin/master then commit again.
  • Force push to my repo

The commits at steps 2 and 3 will have the same content, the git history will be clean from the perspective of the maintainers of the project, and the whole thing has the nice feature to be idiot proof.

TL;DR

Here is my idiot-proof solution for having a clean PR that is one commit above origin/main

git fetch
git merge origin/main

# if conflicts
echo "resolve conflicts in your IDE"
git commit -a -m "resolve conflicts"
# end if

git reset --soft origin/main
git commit -a -m "⚡️ implement xxx"
git push --force
Enter fullscreen mode Exit fullscreen mode

Top comments (4)

Collapse
 
ben profile image
Ben Halpern

Really well described. Will reference this in the future.

Collapse
 
jmfayard profile image
Jean-Michel 🕵🏻‍♂️ Fayard
Collapse
 
krishselvaraj profile image
Radhakrishnan • Edited

How does this help?

git reset --soft origin/master

Can you explain?

Collapse
 
jmfayard profile image
Jean-Michel 🕵🏻‍♂️ Fayard • Edited

Sure!

  • origin is the original project and not your fork.
  • since you have pulled origin/master, that commit represents the latest and greatest that the project has.
  • since you have merged origin/master so that you are not behind the project's latest and greatest. The commit that you did after merging contains the right working tree that you want to submit.
  • after git reset --soft origin/master, when you commit again, you have the exact same right working working tree BUT its direct parent will be origin/master. (1)
  • from the perspective of the maintainer, the git history is clean : exactly one new commit above his master branch.

(1) As the friendly manual says,

  git reset --soft <commit> # here <commit> = origin/master
    Does not touch the index file or the working tree at all 
    (but resets the head to <commit>, just like all modes do). 
    This leaves all your changed files "Changes to be committed", 
    as git status would put it.
Enter fullscreen mode Exit fullscreen mode

Hope that helps :)