Git: Simulate PR merge and test it

We have a PR, it is working ok, however the PR has a very old version of the origin branch, the origin branch has been updated a lot since the PR branch was created.

So How can I "simulate" the merge and run tests before actually merge to the origin branch?


ANSWERS:


You can replicate your branch pointer by just doing the following from your development branch:

git checkout -b test-branch

Now you are in test-branch, which is identical to your development branch. Go ahead and merge (or better yet, rebase) onto the current master branch:

git merge master

OR

git rebase master

You may have to resolve some conflicts along the way. Git will print clear instructions on how to do so if that happens. Now test-branch is merged on top of master, starting where your development branch first diverged. Your development and master branches are untouched by this operation.

If you are happy with the merge, you can delete test-branch or move the development branch to the merge point using git branch:

git branch -f development test-branch

Keep in mind that if your original master branch has changed, you should probably update it before you try to merge or rebase:

git fetch origin
git checkout master
git merge --ff-only origin/master

Alternatively, you can just do git pull if you don't mind potentially pulling in changes from other branches.


  1. Create a branch from master (or the branch you want to test on)

  2. Merge your pull request in this way: Merge pull request to a different branch than default, in Github

  3. test your stuff

  4. if your tests are successful, merge to master and delete your testing branch


Mad Physicist's answer is correct (and upvoted), but a diagram might help.

The key to understanding this is that for most purposes in Git, branch names are almost entirely irrelevant. What matters is the commit graph (and the snapshots attached to each participating commit in that graph).

Let's say you have the following graph:

...--A--B--C         <-- mainline
         \
          D--E--F    <-- feature

and you are proposing to git merge the feature branch into the main-line branch. Normally you would do this with:

git checkout mainline && git merge feature

which would direct Git to perform the merge ("merge" as a verb) using commits B and C as "what we did", and commits B and F as "what they did". If all goes well Git automatically makes a new commit, which adjusts the label mainline to point to the new commit. If things do not go well, Git forces us to fix up the mess (edit things in the work-tree, and git add the result) and make the new commit ourselves. This also makes a new commit, which also adjusts the label mainline to point to the new commit. In any case the new commit has two parents: commits C and F (in that order). In other words, the new commit is a merge ("merge" as a noun). So let's draw this:

...--A--B--C------G   <-- mainline
         \       /
          D--E--F     <-- feature

Now, note that this graph is identical to this graph:

          C
         / \
...--A--B   \-----G   <-- mainline
         \       /
          D--E--F     <-- feature

But imagine for a moment that we can make Git not move the label mainline after we make the commit, so that we get this graph instead:

          C           <-- mainline
         / \
...--A--B   \-----G   <-- ??? (HEAD)
         \       /
          D--E--F     <-- feature

Except for leaving the branch name mainline alone, the effect is exactly the same: we do the same merge-as-a-verb work and make the same merge-as-a-noun commit object G.

This is what happens if you make a new branch name (which fills in the ??? part). The "before the new merge" picture is:

          C           <-- mainline, test-branch (HEAD)
         /
...--A--B
         \
          D--E--F     <-- feature

and the after-merge picture is the one with merge commit G added.

Git knows which branch name to update based on HEAD.

Note that you can even make the merge using Git's "detached HEAD" mode. In this mode, the name HEAD points directly to a commit ID, instead of having the HEAD file store the branch name. The rest of Git works as usual, but when making a new commit, instead of updating the branch-name stored in HEAD—there isn't one—Git simply updates HEAD itself.

Once you decide that the merge is good, you can then ask Git to "slide the name mainline forward" in a fast-forward operation:

          C           <-- (old mainline)
         / \
...--A--B   \-----G   <-- HEAD, (new mainline if slide-forward works)
         \       /
          D--E--F     <-- feature

This "slide forward" operation fails, on purpose, if it's not possible to just slide forward. For instance, suppose that our work to do the merge, resolving conflicts or whatever it is we had to do, and then running our tests, took a relatively long time ... and during that time, someone else snuck in and updated mainline, adding some new commit of their own:

          C---------H   <-- mainline
         / \
...--A--B   \-----G     <-- HEAD
         \       /
          D--E--F       <-- feature

It's no longer possible to "slide forward" to G: the name mainline would first have to "slide back" to C, losing H. The fast-forward operation will fail, letting us know that our temporary merge G cannot become a permanent member of branch mainline after all.

(I've drawn the new commit H as an ordinary commit, but it doesn't matter whether it's a simple commit, or a merge commit: the point is that it comes after C, but not after G. These fast-forward operations must move only "forward"—rightward, in these graph drawings.)



 MORE:


 ? Git ignoring gitconfig?
 ? Random 'concerns' folders and '.keep' files
 ? How do I require a private ruby gem from another private ruby gem?
 ? Github, file too large already deleted.
 ? What's the difference between `git diff --patience` and `git diff --histogram`?
 ? Creating an array with "hidden" extra indices
 ? What are the pros and cons of using a trunk-based Vs feature-based workflow in Git?
 ? GitPython How to clone all branches?
 ? Git take their or my file while merging
 ? How to obtain the effective git-config values and their source?