Hg: Find out if a branch has been merged in to default? - merge

So I've got a long and detailed Mercurial Repository which has been worked on by several times over a long period of time with lots of branches, in that time no one knew that you can close a branch.
Recently I've closed nearly 1200 abandoned heads and it runs a lot better. However we have a number of branches which we want to preserve. Some I think may have already been merged back in to default but I'm not sure.
I can see if I run hg branches that they are marked as (inactive) meaning that it has been merged in to another branch but on checking its not merged directly back in to default. Is there a way I can check if somewhere these branches have been merged back in to default even if its via another branch ?

I believe you can accomplish that with revsets, in particular:
hg log -r "not ancestors(heads(default)) and head() and not closed()"
That should get you all heads of named branches that have not been closed and are not ancestors of (i.e. have not been merged into) the default branch.

Related

Do squashed pull requests show up in the contributions graph as a single commit?

I'm working on feature branches that can have over a hundred commits over the course of a week or two. I've expected to get daily marks on my contribution graph for these daily commits once my pull request is accepted, but when that pull request gets "Squashed and merged", it looks like it just shows up as a single commit on the contribution graph.
Is this the intended behavior, or are my commits missing for a different reason?
Yes, this is the intended behavior. You only got one commit merged. That's the point of squash and merge.
I do not recommend squash merges. It takes all the carefully considered commit history about how the branch was developed and mashes it into a convenient but homogeneous paste.
I'm working on feature branches that can have over a hundred commits over the course of a week or two.
I would say this is the real problem. Feature branches should not regularly have over a hundred commits. Your features are too
big, or you're making a lot of commits to fix previous commits, or you have a lot of incidental merge commits from updating your branch, or all of the above.
Update your branch using rebase instead of merge. git rebase main rewrites your branch as if it were written on top of the latest version of main all along. This removes merge commits which say nothing but "I updated my branch" and makes it easier to see what work has been done on the branch. You can change git pull to do a rebase instead of a merge with git pull --rebase and by default by setting pull.rebase. See git-config and Git Branching - Rebasing.
Break up large features into a series of smaller features. This is a skill beyond the scope of this answer, but often a big change can be broken down into a series of smaller refactorings.
Eliminate incidental fixup commits. If you need to fix something in the previous commit, instead of making a new commit "amend" your changes to the previous one with git commit --amend.
For a general cleanup, do an interactive rebase and squash your incidental commits individually. Use fixup.
$ git rebase -i master
pick abcd1234 feature: do that thing
fixup 1234dcba whoops, had a typo in that thing
fixup b33fdead docs: document that thing
fixup afdcefff test: test that thing
fixup deadb33f fix that thing
pick efga1389 feature: did another thing
You had six commits, but you only really did two things. Now you will have just two commits for doing two things.
Using these techniques you can bring your PRs down to a handful of well thought out commits, each conveying important information to the reviewer and future developers wondering why the code was written that way.
See Rewriting History for more.
Yes, they show up as a single commit. That's because GitHub only counts commits that end up on the default branch, and when you squash a PR, you end up with one commit on the default branch.
I personally don't worry about my contribution graph, so this doesn't matter to me. However, I also don't use squash and merge, since I write nice, bisectable commits with good commit messages, and squash and merge destroys that. If it's important to you not to reduce the work that a contributor has made down to a single commit, then you would need a merge strategy whose goal isn't explicitly to destroy history.

Switch branches and take only specific changes with you

I’m still fairly new to the Git way of thinking, and I use it almost exclusively through the VSCode GUI and the Github desktop application, so bear with me if my thinking or terminology is backwards or sideways.
I frequently find myself in the situation that I do some work, then realise some of the work I’ve just done should have been done in a different branch than I’m in and need to move those changes to another branch. But this only applies to some of the changes in the current branch – the rest of the changes in the branch do belong where they are and should stay put. Usually it’ll be just a small handful of files I want to move, while perhaps 40 or 50 files should stay where they are.
There are lots of questions and tutorials on how to change branches and move all your uncommitted changes to another branch; I can also find questions on how to cherry-pick from an existing commit (like this one – but Google as I might, I cannot find any descriptions of how to move only specific, selected, uncommitted changes to a different branch. That is,
the changes are not committed in the current branch (and I don’t want to commit them there, because they don’t belong in that branch)
the changes to move are only a subset of the total number of changes in the current branch
after the move, the changes should disappear from the current branch and be added to existing changes in the other branch so that I can commit them in that branch
I can cherry-pick the files manually (file by file) or I can stage or unstage the particular changes I want to move or not move; either way is fine with me (or if there’s another way, that’d be fine too).
Theoretically, I would imagine I should be able to stash the changes in current branch excluding the files I want to move, and then switch to the other branch. I’ve found a description of how to stash specific files, but not a way to do the opposite, stashing everything except specific files.
Is there some relatively simple way to accomplish this?
Of course, as always happens, a solution occurred to me right after posting here… Very possibly not the best or easiest way of doing it, but it works.
It can be done in a few, relatively simple steps combining staging and stashing:
Stage the changes you want to bring over to the other branch
Stash your unstaged changes with git stash -ku (k for keep-index, which limits it to unstaged changes, u for including untracked files)
Switch to the branch you want and commit the changes there
Switch back to the branch you were in and apply/pop your stash with git stash apply git stash pop
For reasons I don’t really understand, the staged changes also reappeared when I applied my stash, but since they were now committed in the other branch, I could just unstage and discard them in the current branch.

Github repo squash commits on master

I'm working with a github repo where a lot of commits historically have been "bugfix", "bugfix for real this time", "ok final bugfix", "finally fixed".
These were committed directly to master. How can I squash them?
Fromt his post a year ago - it basically sounds like this is bad, want to squash multiple commits in github. Has anything changed in the past year?
The answer today is basically the same: Squashing these commits is possible, but rewriting shared history is something to be strongly avoided in Git.
Imagine that you and I each have a copy of some repository that also exists on GitHub:
A---B---C
You notice that commits B and C should really have been committed together, so you squash these commits in your local copy. You now have
A---D
where D is a combination of B and C, while GitHub and I still have
A---B---C
At this point, even though the file content is the same everywhere, our commit IDs have diverged. Now you can't push to GitHub without --force, because GitHub's master branch contains two commits that are no longer present in your history.
If you do use --force you can make GitHub accept your changes, but now my repository contains commit objects that are no longer present upstream. I can't push to GitHub without using --force (which will invalidate your changes) or without doing a relatively funky merge to bring your changes in, probably rebasing my work, etc. And that's only possible if you communicate with me outside of Git to tell me what you've done.
This gets even messier with more developers (imaging doing this on the Linux kernel repository!) and with more work being done concurrently.
Really, any time you're tempted to git push --force, sit back and think for a moment. You're probably doing something that should only be done with an extremely good reason.
My recommendation is to accept that your history is a bit messy, but to try to improve things going forward. These commits can be cleaned up locally, before you push to GitHub (or share with other developers). Work in feature branches, use cherry-pick, rebase, etc. to clean up the commit history if necessary, then push.
Squashing is something which is used to merge a lot of commits into one. If you want to clean up last serval commit's check your last git log's by using
git log
this will look something like this
* df71a27 - (HEAD feature_x) Updated CSS for new elements (4 minutes ago)
* ba9dd9a - Added new elements to page design (15 minutes ago)
* f392171 - Added new feature X (1 day ago)
* d7322aa - (origin/feature_x) Proof of concept for feature X (3 days ago)
now if you want to squash last three commit's then
git rebase -i HEAD~3
by doing this you'll get into editor like this
pick f392171 Added new feature X
pick ba9dd9a Added new elements to page design
pick df71a27 Updated CSS for new elements
Edit the one who you want to squash like this
pick f392171 Added new feature X
squash ba9dd9a Added new elements to page design
squash df71a27 Updated CSS for new elements
When done, save and quit your editor. Git will now squash the commits into one. All done!

Gerrit: working with multiple branches & propagating changes

I'm trying to identify the proper way of working with multiple branches on Gerrit that would match our workflow.
The way we work with branches right now is: we have master & feature branch. Master is the branch we want to polish and make it ready for release, while feature is obviously a field of intensive work. Now, in our particular case whenever somebody works on a bug fix, they:
create a change targeted for master branch
cherry pick it to the feature branch targeted change
once gerrit code review completes, submit both changes.
now the way i understand cherry-pick, it selects individual commit and merges it to the current change. if that is the case, i would expect to have no merge conflicts in the end, and indeed this workflow works perfectly with just GIT. Gerrit, however, most likely due to its nature (branches are not merged remotely the way these are locally and get a different sha tag) lists a tremendous number of conflicting files in the end.
Now, I resolved all these issues by applying merge strategy (ours on feature, theirs on master), but it does not feel right: if anything was not propagated, it just got discarded.
My question is: is there a safe workflow, similar to the above one, that would in the end produce a clean merge with gerrit?
I would say that it's better, in this case, to merge than to cherry pick.
A cherry pick adds the same changes but not the same commit. So while the source is the same on a cherry pick and merge the git tree is different. When the tree is different and you later do a merge git will think that the commit you previously cherry picked is missing and try to merge that change as well, even if the actual code is already there. That's probably why you get a lot of conflicts.
I would propose another way of working.
When you do normal work you develop on feature and push to Gerrit as normal.
When you do a patch (ie bug fix) on the stable production environment you do that directly on master (or local branches if you like but not on feature)
When the patch as been approved in Gerrit it get's merged into the real master and you can make a pull request to get that change to your local copy. Your version of master is now the same as Gerrits master
Now you would merge all new changes on master into feature. Make sure you do a rebase so that the patch ends up before anything you've already done on feature
Once it's time to deploy all new features you can merge feature into master, push to Gerrit (if you have permissions you can by pass gerrit by pushing directly to master instead of refs/for/master as these changes are already reviewed)
Once all changes are on Gerrits master you do a pull on your master and a merge into feature with rebase making feature a clean branch to work on. It's of course totally valid to have a new feature each release. Both work fine.
I'm a little confused, as this flow should work just fine. If other users submit changes before your bug fix is reviewed/verified/submitted, that could result in merge conflicts, but that should be rare.
If you:
Fix a bug on master
Push to review (creating change A in gerrit)
cherry-pick change A on top of the feature branch (resolving any conflicts from master to feature)
Push the cherry-picked change to review (creating change B)
Review/verify/submit changes A & B
Everything will work fine. The only way for merge conflicts to occur is if other users upload and submit changes between steps 1 and 5. Are you seeing different behavior? Can you provide more details?

Merging of branch to trunk in SVN using Eclipse

I am looking forward to merge my code which I developed in a branch of SVN to the trunk. I am using Eclipse and I have been using Team->Commit to commit my updates to the SVN. But I haven't done a merge before. Please help me with this.
First of all make sure you are up to date. Update your working copy of the target branch, ie. where you are merging into. In this example we're working on the trunk of "core" and we want to grab the changes that have happened in the maintenance branch and merge them.
Resolve any conflicts. There should be no conflicts at this stage between the working copy and the repository.
Select the SVN merge option on the working copy. In Eclipse this is going to be found under the "Team" menu and called "Merge Branch".
SVN: Merging in Eclipse
Change the From URL to the specific branch you want to be merged into your working copy. In this example we're looking for the p400 maintenance branch (./core/branches/p400).
Change the From Revision to the last revision that was merged into the target branch. Essentially you don't want to keep merging the whole branch history, you just want to include those changes since the last time you merged. There is no easy way to determine the last merge point at this time in Subversion. You have to review your message log and look for the last commit that talks about merging. If you are disciplined about the commit messages you use for merging this should be easy (see below). Make a note of what that revision is -- you'll need this later when you commit your changes.
SVN: Merge with Eclipse
Change the To Revision to the latest (i.e. head). Make a note of what that revision is -- you'll need this later when you commit your changes.
Click Merge and wait. Depending on how big the differences are this may be quick or Eclipse my just fall over. If you have such an enormous change that you can't get it done in Eclipse you may need to make the range of revisions you are merging smaller. Or you may even have to skip certain revisions and do them manually if they are massive. We've had this problem from time to time when updating large third-party libraries. The vast majority of the time you will be fine.
Review changes and resolve conflicts. Once the merge is complete, look through the changes made to your working copy and make sure you address any conflicts you find.
Once all the changes have been resolved in the target working copy, check them in with a single commit. The reason you're not doing lots of commits is that these are changes that should have been documented in the branch from which you merged. The commit message needs to be in a specific format that details the merge and is easy to find in the future. We use the following format, but you can use anything that works for you -- as long as you stick to it.
Merging [source] to [target]; [repository]. Merge rev [start]:[end]
Enjoy!
In eclipse we have an option to merge. Right click the project , you will see "Team" option and on clicking it you will see merge option. There are three different options you can see in the merge.
To successfully merge the changes from the branch to the trunk, we need to switch the local workspace to the trunk (but make sure all the changes are committed to the branch before that). Once we do that we can use merge option and select "2 URLs" option. I put url for trunk as url 1 and the branch I wanted to merge as url 2. I could see all the incoming changes I selected "OK". All the changes are in my local now (at this point my workspace is linked to the trunk). Then I committed my changes to the trunk and hence merge from branch to the trunk was successful.
I would like to add for Point 8 .Review changes and resolve conflicts. ---
When working on conflicts manually- when you do copy from right to left on chunks of code - Be careful
Sometimes chunk of code gets added, sometimes it properly replaces the chunk.
Make sure there is no duplicate chunk of code.
Also, this is helpful-- What is the proper way to do a Subversion merge in Eclipse?