18

The normal GitHub flow to contribute to a repo is to create a fork of the upstream, clone a local copy where you make changes, then push back up to your fork and then create a PR to have your changes merged into upstream.

But if upstream changes after that, how do you update your fork without creating a merge commit (and also without using the git CLI)?

I already know how to do this in a way that will create a merge commit or which depend on the git command line interface. This question is specifically about using the GitHub.com website or GitHub Desktop application only (no CLI).

Since this is a very common workflow it seems like there should be some simple way to do it using the GitHub GUI.

To reiterate: any answers that use the CLI or create a merge commit (e.g. this way) will not be answering this question since I'm explicitly looking for a non-CLI solution.

brentonstrine
  • 17,958
  • 23
  • 61
  • 112
  • I know it will be very tempting to answer this with an answer that uses the CLI. The reason this has a bounty is because I am explicitly NOT looking for an answer that uses the CLI tool. See how `git` is not tagged: that's intentional. Also, I am aware that with many steps you can use the GitHub.com website to pull from upstream, but this creates a merge commit, which is the other thing I am explicitly NOT looking for. – brentonstrine Jun 04 '19 at 01:22

3 Answers3

13

without a merge commit or using CLI?

Not directly with GitHub web UI alone, since it would involve rebasing your PR branch on top of upstream/master

So in short: no.
But in less short... maybe, if you really want to try it.

Rebasing through GitHub web UI is actually possible, since Sept. 2016, ...

  • if you are the maintainer of the original repo, wanting to integrate a PR branch
  • if none of the replayed commit introduces a conflict

https://github.blog/wp-content/uploads/2016/09/a03fa9b6-7f35-11e6-8fa0-e16b2fede8ca.gif?resize=788%2C423

(This differs from GitHub Desktop, which, since June 5th 2019 does support rebasing. But that is a frontend to Git CLI, like other tools provide. For example GitKraken and interactive rebase)

So a convoluted workaround would be:

  • to fetch, then push upstream/master to the master branch of your own fork (a CLI operation, but more on that below)
  • change the base branch of your current PR to master (so a PR within the same repository: your own fork), provided you haven't pushed to master.
    Meaning: master in your fork represents the updated upstream/master, with upstream being the original repository that you have forked.
  • Since you are the owner of that repository (your fork), GitHub can then show you if you can rebase said branch to the base branch of the PR (master), but only if there is no conflict.
  • finally, change the base branch again, to <originalRepo>/master (which is the intended target of your PR)

The very first step is typically done through command line, but... there might be a trick to do it (update upstream master in your fork) through web UI: see "Quick Tip: Sync a Fork with the Original via GitHub’s Web UI" by Bruno Skvorc

In short, it involves:

  • creating a new branch from your current master (which would be at upstream/master at the time you forked the original repository)

https://help.github.com/assets/images/help/branch/branch-creation-text-box.png

  • Making a PR with that new branch and <originalRepo/master>
  • doing a base switch before creating the PR

https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2016/02/1454845571Screenshot-2016-02-07-12.41.28-1024x411.png

https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2016/02/1454964017Screenshot-2016-02-07-12.41.42.png

That is the step which artificially forces upstream/master to be refreshed

You can the create and merge it with the “Merge Pull Request” button (and “Confirm Merge” afterwards): the merge will be trivial: no merge commit.

The end result is: your own master branch (in your fork) updated with upstream/master (the master branch of the original repository)!

You can then resume the steps I describe above, and change the base of your current PR to your own (now refreshed) master branch, and see if you can rebase it!

VonC
  • 1,042,979
  • 435
  • 3,649
  • 4,283
  • If I'm reading this right, the fork doesn't ever get updated this way, so over time the fork would become more and more out of date to the point that a rebase merge would be insane. – brentonstrine Jun 04 '19 at 16:49
  • This is super clever, btw, thanks for thinking through how to do this. – brentonstrine Jun 04 '19 at 16:51
  • @brentonstrine No, the fork is updated: more precisely, the master branch of the fork (which represents the original state of the upstream/master branch) is updated first, then you rebase your PR branch. – VonC Jun 04 '19 at 19:21
  • It doesn't work. It's still the three possibilities: two that create a merge commit and "Rebase and merge" which says that there are conflicts even though I didn't change anything in forked master. – int_ua Dec 24 '20 at 21:49
  • @int_ua The rebase won't remove any conflict. If the forked master has concurrent changes compared to your branch, there would still be conflict, in case of merge or rebase. – VonC Dec 24 '20 at 21:53
  • Created a new question about GitHub web with a bit more details https://webapps.stackexchange.com/q/149537/37431 – int_ua Dec 24 '20 at 22:05
  • 1
    @int_ua OK, let me know if you find a solution there, I don't monitor webapps, only Stack Overflow (where there are 40000+ GitHub questions, compared to 371 on webapps) – VonC Dec 25 '20 at 02:06
12

This is feasible with GitHub Desktop since version 1.0.7 considering the following:

  • If the current branch does not have any commits ahead upstream (the original repo of the fork), the new commits can be pulled without creating a new merge commit

    In GitHub Desktop:

    1. Clone your repository from File > Clone Repository

    2. Fetch origin, which will automatically fetch the upstream as well

    3. Go to Branches by clicking on where it says Current Branch

    4. Click on Choose a branch to merge into <branch> at the bottom

    5. Search for upstream/<branch>, then click Merge upstream/<branch> into <branch>

    6. Push to origin, et voilà!

  • Otherwise, ff the current branch has commits ahead of the fork, then of course one has to create a merge commit or rebase and force push. For rebasing which might be more preferable, do the following:

    1. In GItHub Desktop, go to Branch from menu, then Rebase Current Branch

    2. Search for upstream/<branch>, then click Start Rebase

    3. Solve any conflicts that have occurred from the rebase

    4. Force push to origin. You will get a warning for this for obvious reasons.

For avoiding force-pushing to your work when your current branch is both ahead and behind its upstream counterpart, either create a new merge commit or:

  • Make a new branch based with all your changes

  • If needed, reset the original branch to its original state (before it diverged from the original repo)

  • Perform the steps from the first scenario and merge your changes into your branch.

And yes, it seems that pulling via the GitHub website from the original repo without creating a pull request and merge commit is not possible at this moment.


Demo GIF for first scenario: https://imgur.com/a/8wci2yf

Some GitHub issues related to this:

Siavas
  • 4,634
  • 2
  • 18
  • 29
  • Have you been able to try this approach? Any questions or observations? It might seem a long process by the instructions but it actually takes about 30 seconds to complete. – Siavas Jun 11 '19 at 13:09
  • Have you clicked on Fetch first @brentonstrine? There is a linked GIF that shows you how to do it from there. Do you have the most recent version of GitHub Desktop? – Siavas Jun 11 '19 at 18:14
  • Yes, that was the problem, just realized that and deleted my comment. – brentonstrine Jun 11 '19 at 18:15
  • No problem @brentonstrine. Let me know if there is anything I can do to clarify the steps. – Siavas Jun 11 '19 at 18:16
  • Was the rebasing feature really available since 1.0.7? I know with 2.0 (which came out days after this question was asked) there was an overhaul to help with rebasing--before 2.0 I was not aware of the ability to rebase. – brentonstrine Jun 11 '19 at 18:17
  • From [this GitHub pull request](https://github.com/desktop/desktop/pull/3199), dated in 2 Nov 2017, it seems they added the feature of fetching from upstream which allows the rebase via the `merge with upstream/` feature. The rebase feature per-se I think was indeed added lately. – Siavas Jun 11 '19 at 18:19
4

Update Note: Non-CLI based approach that might help: Is there a way to make GitHub Desktop rebase a branch against master?

The only key here is doing a rebase, so the above answer should help.


CLI way (which is easier and using git, so it should be more comprehensive by default)

There are some practices that you should use to avoid this.

  • Don't work on the master branch in your fork.
$ git clone <your fork>
$ git checkout -b feature_branch

You can work in your feature_branch and then raise a Pull Request.

  • Once your changes are merged in the upstream master, you can pull from upstream to your origin. Since the master on upstream will have your commits sitting neatly on top of it, there won't be a merge commit.
$ git checkout master
$ git pull upstream master
$ git push origin master
  • In the case, where the maintainer has diverged from the master that you have in your fork, that is, it's not linear any more, you need to pull a fresh copy of it. That should not be a problem as your changes are already in the upstream.

  • If the master in upstream has moved ahead while you were working on your PR, then you can rebase on you feature_branch.

$ git checkout master
$ git pull upstream master
$ git push origin master
$ git checkout feature_branch
$ git rebase master

Please refer to this document for detailed reference: Fork and pull request workflow

pikaynu
  • 625
  • 4
  • 11
  • 2
    CLI means Command Line Interface. So all of the lines in your answer that start with `$` would be CLI. I tried to make my question very clear that I'm not looking for a CLI solution. Can you give me some advice on how I could make my question more clear that I'm not looking for a CLI solution? – brentonstrine Jun 03 '19 at 17:36
  • There is a way to rebase using Github Desktop, so that might help. I usually refrain from using UI since it makes things a little complicated. the only reason I use UI is to partially select lines while committing and breaking existing commit into smaller ones because it's a bit difficult in the CLI. – pikaynu Jun 03 '19 at 18:15
  • 1
    @brentonstrine It's clear. The reason why this particular answer came about is most likely due to the bounty. The highest upvoted answer, if there are at least 2 upvotes, gets half the bounty rep if no answer is chosen after the period ends, so if this answer is the highest voted one.... (Reference: https://meta.stackexchange.com/questions/16065/how-does-the-bounty-system-work). Best thing to do in this case is if this answer doesn't address your concerns, downvote and move on. – rayryeng Jun 04 '19 at 01:22
  • 1
    In pikaynu's defense, they posted their answer before I created the bounty. – brentonstrine Jun 11 '19 at 20:34
  • In my defense, yes, I did not see the bounty and I did not post for the bounty. Thanks @brentonstrine. :) – pikaynu Jun 12 '19 at 09:30
  • i appreciate this answer, since i was searching the web for solutions with CLI and @brentonstrine didn't provide it. thanks pika- dude! (if i don't comment anymore, it also means this worked) – cregox Mar 31 '21 at 03:37