git multiple pull requests - github

I'm a git noob in a shared environment, but have used it for personal projects fine.
I'm trying to contribute to a project, so I did this:
Forked the project.
Made code changes.
Committed code changes to my local branch.
Pushed changes to my fork
Did a pull request.
That worked great. PR is still pending, but I had some other ideas.
So, I created a new local branch.
Made code changes
Committed code changes to local branch
Pushed changes to my forked copy
Did a PR
The code changes from my previous edits are obviously in place with this PR. I do not want that, since they haven't been committed to the main branch.
Likewise, I want to make additional changes and push them specifically without containing the code from my previous work.
How is this accomplished?

Since you already started a second pull request, you'll have to forego best practices:
rebase your local <PR-2-branch> to start of PR-1 (say 8 commits ago). use -i to start an interactive session.
git rebase -i HEAD~8
In the editor window that opens up, hit i and mark commits from PR-1 (5 commits) to be drop or d and pick or p commits from PR-2 (3 commits)
d 113456 <message>
d 223456 <message>
d 333456 <message>
d 443456 <message>
d 553456 <message>
p 663456 <message>
p 773456 <message>
p 883456 <message>
Press Esc > w > q to exit the editor and to proceed with the rebase.
The branch now contains only commits within the scope of current PR.
Update the remote branch with --force
git push origin <PR-2-branch> --force

Related

New Pull Request when a previous one is pending Merge

I made some changes to several files of the project on a new branch (let's call it branch_a), I commited them, created the Pull Request, and it was recently reviewed and approved. It's still pending Merge on the master branch.
Now, someone asked for another change. It's a small supplemental change in 1 of the files edited in the first Pull Request.
What's the best way of doing this? Should I ask for the first Pull request to be merged and then create a new branch (branch_b), make my change and create a new Pull Request, ask for review and merge again?
Or is there a "cleaner" way, when the first Pull Request is somehow merged with the second one and we don't have to make 2 different merges?
If another change requested is a part of the same feature as in ‘branch_a’, then you can simply make change in the same branch, your PR request will show up those changes, but PR approval will be required again.
If another change requested is outside the scope of feature ‘branch_a’ and it is just a file is same between two changes, then you can create a new branch out of master say ‘branch_b’, complete your changes and raise PR for the same. After ‘branch_a’ is merged into master, you can rebase your second branch ‘branch_b’ to include updated master codebase into branch_b, (or vice-versa if branch_b is merged first).
This is especially useful if the order of merge is not decided in advance.
Below are the steps, for rebase, here ‘feature_branch’ is the name of your branch for which you want to perform rebase:
git checkout master
git pull origin master
git checkout feature_branch
git rebase master
Here you might get some conflicts(if there are any) multiple times as per number of commits in your feature_branch. You can resolve the conflicts manually and proceed with further process of rebase with below command:
git rebase --continue
At any point if you think that things are not going well and you would like to cancel rebase process, then execute below command:
git rebase --abort
Finally when all conflicts are resolved and you get message as successfully merged, then execute below command to push changes to origin:
git push --force origin feature_branch
for more information on rebase process follow link:
https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase
Branch off the first pull request branch, edit, add, commit, push, and ask for a second PR merging to the first branch. When the first branch is merged the second PR will be reconfigured automatically (by GitHub) to be merged into the main branch.

How to change the owner of a PR on GitHub / How to commandeer an open GitHub PR

I find this missing feature in GitHub to be frustrating, so I'm documenting my work-around here to help the next person. Alternate, better work-arounds are welcome.
This question is not a duplicate of How to change the author of a commit in GitHub? ...because that question isn't clear if it is asking about how to rewrite the author of a few commits and the push those to github, or actually change the name under which the entire PR was created in the first place. And, the accepted answer to that question was a simple fix to the local .git/config file, which clearly will not solve the GitHub problem I'm talking about here.
At the top of a GitHub PR you'll see something like this:
username wants to merge 1 commit into base_branch from their_feature_branch
That username: how can we change that?
Example PR (chosen "at random" from GitHub, just to show the PR author line in the image below). Image:
Example use-cases:
The team-mate who opened this PR just left the company, and we'd like to commandeer (take over) and finish the PR for them.
Change of work-loads have necessitated you take over a partially-complete PR from another team-mate. How can you switch that PR to be in your name?
Assume that everyone has full push access to the whole repo, meaning that you can push/pull to/from each other's branches anyway.
Real-life example of why I want to know how to change the owner of an open PR
In 2020 a peer of mine opened a PR on a brand new branch that was intended to be worked on for 3 months until it had a ton of new features in it. Then, it would be merged. Peer reviews would occur on mini-PRs as they go into this separate, long-running, stand-alone branch.
The PR was initially opened with a "do not review" label, just to get the branch up so our CI (Continuous Integration) system would start to build it daily to ensure it wasn't broken. We would all then contribute to this branch with the understanding that the one person who opened it would be the "process owner" and walk the branch through all testing and processes until it gets merged back into the main branch.
My peer then left the company right after opening this PR. I immediately became the process owner and worked on the PR for 3 months and eventually merged it. That repo is set up by the maintainers to disable all types of merges except "squash merges" (see my comments under this question), so when it was merged, Github squashed all of the dozens of individual commits into one single huge commit and attached my peer's name (and keep in mind he hadn't been at the company for the last 3 months) to that commit, even though it was the commit that I had managed for nearly all of its 3 month lifetime.
git diff --shortstat 123456789abcd~..123456789abcd shows the following output:
164 files changed, 10360 insertions(+), 3013 deletions(-)
...meaning that commit had touched 164 files, added 10360 lines, and deleted 3013 lines. And guess what!? My peer's name is the name on all those changes, just because he opened the PR initially, instead of my name, even though a lot of that work was mine and I was the process owner of it. That's confusing, to say the least. I would have liked to have my name on all of those changed lines instead.
My answer here is therefore what I should have done, but didn't at the time, because I didn't know GitHub always uses the name of the person who opened the PR, and I didn't know how to change the owner of the PR. Now, I do know, and I have documented my workarounds in my answer.
What I actually did was option 1 from my answer, but what I should have done is option 2 from my answer.
Sometimes, an assignment gets passed off from one team member to another, or, a team member leaves a team. When this happens, it would be nice to "commandeer", or take over, their PR so that it becomes your PR. As far as I can tell, however, this isn't possible on GitHub yet.
On Phabricator (a paid alternative to GitHub, and originally an internal tool used at Facebook), this is as simple as clicking a button to "Commandeer Revision" (see old documentation here under "Take over another author's change"). This is known as "commandeering someone's diff", where "diff" here is the Phabricator-equivalent to a GitHub PR, or "Pull Request".
How to commandeer (take over) someone else's PR in GitHub
ie: how to change the owner of the open PR so it looks like you opened the PR, not them.
So, since GitHub doesn't allow commandeering a PR, here are some options:
Continue using their open PR, in which case their name, not yours, gets attached to the final, squashed-and-merged commit in the event you use the "Squash and merge" option to finish the PR. If they did the bulk of the work, that's fine. But, if you are taking over a PR and you are doing the bulk of the work, you'd probably like your name to be attached to the work. So, instead:
Just close their open PR and open your own.
To do option 1 above: just keep using their open PR, in which their name gets attached to the final, squashed merge commit:
Check out their branch locally
git fetch origin their_branch_name
git checkout their_branch_name
Optionally, rename your local copy of their branch to something you like
git branch -m new_branch_name
Set the upstream for this branch so that when you git push it will push to their remote branch name which is attached to their open PR:
git push --set-upstream origin new_branch_name:their_branch_name
Note: I learned the git push -u origin local_FROM_branch:remote_TO_branch syntax here: How can I push a local Git branch to a remote with a different name easily?
See also my own new answer to that question here.
Now, to push you can just call:
git push
And to pull from that branch, in case another team-mate pushes changes to it too, you can specify:
git pull origin their_branch_name
Now, whenever the PR is complete and reviewed, you can merge it via GitHub. If you choose the regular merge option you'll get credit for your commits. If you choose the "squash and merge" option, the original author, NOT you gets full credit for the entire merge. This is dumb and should be fixed by GitHub, but, that's how it is.
[My preference] Here's how to do option 2 above: just close their PR and open your own:
Go to the bottom of their PR and click "Close pull request": .
Check out their branch locally
git fetch origin their_branch_name
git checkout their_branch_name
Optionally, but recommended, rename your local copy of their branch to something you like.
git branch -m new_branch_name
Push this as a new branch to the remote origin on GitHub. This pushes to your remote branch and allows you to open a NEW PR under YOUR name on GitHub:
git push --set-upstream origin new_branch_name
# Note: if you didn't rename the branch to `new_branch_name` above,
# and it is therefore still called `their_branch_name` locally, just
# use `their_branch_name` here instead.
After pushing like that for the first time, GitHub will output a URL in the terminal where you pushed, which you can click on to open a new PR under your name. (If you don't have this feature, just go to Github.com and manually open up a PR there). Open a PR and voilá! It's now YOUR PR and you've just "commandeered" their PR!
Now, to push you can just call:
git push
And to pull from that branch, in case another team-mate pushes changes to it too, you can specify:
git pull origin new_branch_name
Now, when the PR is complete and reviewed, you can merge it on GitHub. If you choose the "squash and merge" option, your name will now be used for the final, single commit which gets merged to the base_branch.
See also:
How can I push a local Git branch to a remote with a different name easily?
[my own new answer I just added there] How can I push a local Git branch to a remote with a different name easily?
Just giving An example when this ability will be a necessary feature:
One of the PRs I Owned had state errors, that are not a part of the branch, but are localized to the PR:
>> git checkout -b new_name;
>> git push origin new_name;
>> opened new PR without errors.
The errors are not in GitHub per-se, but in some plugins and extensions we made for testing environment.
But I want the IT team to debug the state-corruption, so I would like to pass my PR onto them (the PR but not the code or the branch, obviously).

Eclipse Git - switch branch without merge

This is maybe a dumb question, but I could not find a way to solve my problem. I am working with Eclipse and Git.
When switching and pulling branches to work on different features, the local commits of the previous branch are added to the commit history of the new branch.
Let say I am working on a branch A, commit twice, then I create from master a branch B, switch to this branch B, pull, and perform one commit. Now my branch B contains the changes made on branch A + the commit made on branch B, making it difficult to create a pull request to merge the change of the only commit B to master.
I would like my local commits/changes to be erased when switching to another branch. How can I do that with Eclipse Git?
After playing around with eclipse, I noticed there was two possible pull actions:
The default one does Fetch + merge, resulting in the mess described in the question
The other option allow you to select Fetch + rebase, to rebase your working directory to the state of the remote branch.
Based on this answer https://stackoverflow.com/a/17324792/10631518 you can even make rebase the default behaviour by running
git config branch.autosetuprebase always

Mercurial: How to ignore multiple heads of a branch when used as ancestor on a closed branch

Another git user confused by Mercurial branches here. I've done something that I can't figure out how to undo and as a result I cannot push my totally unrelated changes. Any help would be appreciated.
Here's the story, I think:
I started working on something on default. I realized this was a mistake as it would become a PR, so the next commit I did on a branch feature1. I then submitted a PR on bitbucket.
I started working on something else, also off of default, this time I was certain to use a branch feature2, and I did purposely "hg up -r ..." with the revision number before my feature1 commit so as not to include that change.
At this point the history looks something like,
-- G (default) - H (feature1)
/
.. D - F (default)
\
-- I - J - K (feature2)
My PR was not accepted, so I close feature1.
There has been development on default in the parent repository, so I hg pull. Now it looks something like,
-- G (default) - H (feature1) [my repository, closed]
/
.. D - F (default)--- L (default) [parent repository]
\
-- I - J - K (feature2) [my repository]
.. plus lots of changes on other branches that I don't know anything about.
But I'm happy with feature2 and I want to make a PR for it, so I try to hg push --new-branch, but I get the message,
abort: push creates new remote head 7a341084eb8a!
Ok, so use hg glog and it appears the checksum corresponds with the parent work, i.e. L in the diagram above. Mercurial seems to be complaining that I have a commit on a closed branch with the branch default that has not been merged into default! But I don't want it to exist anymore! However, I don't want to strip it as then it would make reading the old, closed PR impossible.
If I try to push just my own branch, hg push --new-branch -b feature2, then I get:
abort: push creates new remote head 062efd5d0886!
i.e., same problem but with a different head. This one appears to correspond with the first patch of feature2! That is, I in my diagram.
This makes no sense.. a closed branch is stopping me from pushing the changes on an entirely other branch. Meanwhile I can't figure out what multiple heads it's even talking about when pushing my feature2 branch, since there is really only one feature2. The recommendation is to "merge" before pushing, but I can't even figure out here what to merge. I don't want to merge my rejected change on default, and when I do hg merge default on feature2, thinking maybe I need to take into account the latest upstream changes, this merges G, from my closed branch instead of the upstream head.
So, clearly, I just don't understand Mercurial branches. In git I would just delete the feature1 branch and that would be that. How do I resolve this?
But I'm happy with feature2 and I want to make a PR for it, so I try to hg push --new-branch, but I get the message,
abort: push creates new remote head 7a341084eb8a!
At this point, revision L is the head of branch default, and you are trying to send revision G. Revision G is in the default branch, so you will create another head. The branch feature1 was closed, but not the default branch in the revision G. You can update to revision G, and close the branch there, or merge it with revision L.
If I try to push just my own branch, hg push --new-branch -b feature2,
then I get:
abort: push creates new remote head 062efd5d0886!
If revision I is in the default branch, you have the same problem as above.
If not, try hg push -r <rev number of revision I>.

Is this a situation where I should "hg push -f"?

I have two machines, A and B that both access an external hg repository.
I did some development on A, wasn't ready to push changesets to the external, and needed to switch machines, so I pushed the changesets to B using hg serve. Changesets continued on B, were committed and then pushed to external repo.
I then pulled on A and updated to default/tip. This left the local changesets that had previously been pushed to B as a branch, but because of how I pushed things around, the changes in the local changesets are already in default/tip.
I've now continued to make changes and commit locally on A, but when I try to push hg asks me to merge or do push -f instead. I know push -f is almost never recommended.
This situation is close to one where I should use rebase, however the changesets that would be "rebased" I don't really need locally or in the external repository since they are already effectively in default/tip via the push to B.
Now, I know I could merge with the latest local changeset and just discard the changes, but then I would still have to commit the merge which gets me back into rebase territory.
Is this a case where I could do hg push -f?
Also, why would pushing from A create remote heads if I've updated to default/tip before I continued to commit changesets?
I would back up my A & B repositories and then try this:
rem Machine A
rem ---------
hg merge
hg commit -m"merge"
hg push
rem Machine B
rem ---------
hg pull
The merge should ensure that you have one instance of each changeset visible from the tip, plus an additional merge changeset with no file changes. It should be safe to push the committed merge - although I would check this before doing it.
One of the features of Mercurial is that it is good at merging, so you could try to take advantage of this. If you are nervous about the effect of a merge you could try:
hg merge --preview
to get a better idea of what it is about to do.
If you really want an unbranched history, then you could create a clean clone of the external repository [if it isn't too big] and apply your changes from A as patches.