32

I forked a project on github, in order to send pull requests. The problem is that my way to do was very ... dirty.

I worked on a local copy of the fork, created a branch for my modifications and merge it on the master. Then I pushed the master on the github fork in order to create a pull request.

The problem is that recently, my pull request have been rejected. So now I am 5 commits ahead from the original master. What are the solutions in order to be even with the original repository?

Should I have to checkout the upstream master in a new-branch and make the new master with it (how to do this?)

Or is it better to delete my github fork (I have previous accepted commits) and recreate it (you can see the github repos here)https://github.com/cedlemo/ruby-gnome2

cedlemo
  • 3,205
  • 3
  • 32
  • 50

2 Answers2

78

First, you should always make your PR form a branch, not from master.
master is for mirroring upstream/master, with 'upstream' being the name of the original repository that you forked.

In your case, make sure that:

  • make sure that upstream exists (git remote -v),
  • make a branch in order to reference your current patches, and
  • reset master to upstream/master:

Before:

  z--z (upstream/master, with new commits)
 /
z--y--y--y (master with local patches, origin/master)

Memorize current work:

git checkout master
git checkout -b mybranch
# Or, With git 2.23+
git switch -c myBranch master

# if remote "upstream" does not yet exist
git remote add upstream /url/original/repo
git fetch upstream

# reset master to upstream/master
git checkout master
git reset --hard upstream/master
git push --force

  y--y--y (mybranch)
 /
z--z--z   (master, upstream/master, origin/master)

# replay the patches (even they are rejected for now) on top of master
git switch mybranch
git rebase master
git push -u origin mybranch

        y'--y'--y' (mybranch, origin/mybranch)
       /
z--z--z   (master, upstream/master, origin/master)

Here: git reset --hard upstream/master will reset master HEAD on the updated upstream/master, in order for master to reflect the exact same history as the one in the original repository.

But since some commits where previously done on master and pushed on the fork (origin/master), you would need to replace that history with the new master state. Hence the git push --force.

Rebasing mybranch allows for those current patches to be based on the most up-to-date commit of the original repository.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • I'm not sure what it means to 'make sure that `upstream` exists'. Does it mean verify that my fork knows it's a fork and tell it what the original fork is? If so is there a way to check if it's already set before going ahead and doing `git remote add upstream /url/original/repo`? – hippietrail Aug 22 '22 at 07:49
  • 1
    @hippietrail in the context in which this was written 7 years ago, I meant: "check the output of `git remote -v`", which should include an "`upstream`" entry with the URL of the original repository (that you later forked). The `git remote -v` is the way to "check if it's already set before going ahead and doing `git remote add upstream /url/original/repo`" – VonC Aug 22 '22 at 07:53
  • @VonC ah yes my old but newbie brain was confused and thought the `git branch -v` I'd read elsewhere didn't know about the original fork. Then I realized `git remote -v` is different and does tell me. It's hard for newbies because these helpful old answers don't line up perfectly with new answers that are up-to-date but assume reader already knows a lot. For example I think some newer commands split from `git clone` which can do many things. But I'm probably mixing things up still. – hippietrail Aug 22 '22 at 08:13
  • 1
    @hippietrail OK. I have edited the answer to clarify it. Let me know what can be improved. The main new commands I know of are [`git switch` / `git restore`](https://stackoverflow.com/a/57066202/6309) which are replacing the old, obsolete and confusing `git checkout` command. – VonC Aug 22 '22 at 08:22
1

I use this small shell script to reset a branch to it's origin

function git_branch_reset_origin() {
  branch_name="$(git symbolic-ref HEAD 2>/dev/null)"
  branch_name=${branch_name##refs/heads/}
  git checkout -b foo
  git branch -D ${branch_name}
  git checkout ${branch_name}
  git branch -D foo
}

Put simply it moves to a new 'foo' branch, deletes the branch you were on, and checks it out again. Checking out a branch you don't have locally makes a new local branch of that name at the position of the origin branch.

BookOfGreg
  • 3,550
  • 2
  • 42
  • 56