I am working on a large project, with a main repository and multiple subrepos, organized like this:
main-repo
sub-a
sub-b
sub-c
Each person working has one or more named branches of their own. I am working in a branch that we will call shastings-dev and a co-worker has a branch that we will call coworker-dev. (Both of these branches exist in main-repo, sub-a, and sub-b; neither exists in sub-c and we are both using someone else's branch for that one.)
My problem is that I can no longer merge changes from coworker-dev without creating a new head somehow. This sequence of commands has the unexpected effect:
hg pull
hg branch # prints: shastings-dev
hg merge --tool internal:other coworker-dev
hg commit -m "merge coworker-dev" --subrepos
hg push
The hg push prints this message:
abort: push creates new remote head 945a60694252 on branch 'shastings-dev'! (in subrepo sub-a)
EDIT -- I am breaking the question here and putting the answer. The rest of the question will be left intact below for anyone who is really interested in all the details.
The solution: for each subrepo that needed a merge, change directory to the subrepo and follow these steps:
hg update --clean shastings-dev
hg merge --tool internal:other coworker-dev
hg commit -m "merge coworker-dev"
hg push
(I did this for subrepos sub-a and sub-b. For sub-c I just ran hg update correct_branch_name to make sure that it was at the head as well.)
Then, once each subrepo has been properly updated, return to the containing repo, and:
hg commit -m "commit .hgsubstate after merging in subrepos"
hg push
As a result of this experience, I am going to adopt a new rule:
If you have problems with subrepos, always retry the commands in the individual subrepos.
What confused me was that hg update --clean switched all the subrepos, but didn't actually update them. The heads for the subrepos belonged to a different branch than the one showing with hg branch. As a result, #zerkms's comment was correct: the subrepos actually were not on the head and the merge really was creating a new head.
In other words, even if hg id shows that the main repo is at the head, that doesn't mean the subrepos updated properly and are also at their respective heads. Check the subrepos individually to figure out the real state of things.
EDIT -- rest of original question is below.
My first thought was that my local copy of the repo was somehow scrambled. So I cloned an absolutely fresh copy of the repo, verified that hg pull didn't bring anything new in and tried the merge/commit/push again. Same problem.
I have tried doing the merge/commit/push in the subrepo then doing commit in the main repo (to update .hgsubstate) and then doing merge/commit/push in the main repo. No joy.
I have tried using TortoiseHg on Windows to clone the repo, update to branch shastings-dev, and then merge/commit/push. Same problem.
So now my questions:
Why is a new head being created? Am I doing something wrong, is there something wrong with my branch, or is this expected behavior?
What should I do? Can I eliminate this multiple heads problem, or should I push with -f and then close the older of the two heads with hg commit --close-branch?
What bad things might happen if I use hg push -f? My personal rule is "don't do that unless you are a Mercurial expert" and I'm not a Mercurial expert. (So my actual personal rule is "never use hg push -f.")
By the way, I am not working on any files that coworker is working on. At this time I have only minor differences from coworker-dev and I would be willing to totally lose all history on branch shastings-dev, as long as I can get a working up-to-date branch with the same name. (If I lose my changes I am willing to copy the changed files over again. I just want Mercurial to work as expected again.)
EDIT: I am on a branch head when I do the above.
$ hg heads
changeset: 1515:803ea844dc8a
branch: coworker2-dev
tag: tip
user: coworker2
date: Tue Oct 08 17:33:31 2013 -0700
files: .hgsubstate
description:
Fixed some stuff in the foo bar.
changeset: 1513:1e76e6a43d83
branch: coworker-dev
parent: 1509:5e5392aded0a
user: coworker#place_where_i_work.com
date: Tue Oct 08 16:44:04 2013 -0700
files: foo.java bar.java baz.java quux.java
description:
Added more support to the foo bar for release.
changeset: 1422:8705d62db8f2
branch: shastings-dev
user: shastings#place_where_i_work.com
date: Wed Oct 02 21:08:39 2013 -0700
files: .hgsubstate
description:
Finish adding files
...many others not copied here...
$ hg id
8705d62db8f2 (shastings-dev)
$ hg update --clean shastings-dev
resolving manifests
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg id
8705d62db8f2 (shastings-dev)
$ hg merge --tool internal:other coworker-dev
...much output not copied here...
$ hg commit -m "merge coworker-dev" --subrepos
...much output not copied here...
$ hg push
pushing to https://path/to/repo/dir/main-repo
pushing subrepo sub-a to https://path/to/repo/dir/sub-a
searching for changes
new remote heads on branch 'shastings-dev'
new remote head 85d8faada6c4
new remote head 90ce145db695
abort: push creates new remote head 85d8faada6c4 on branch 'shastings-dev'! (in subrepo sub-a)
(you should pull and merge or use push -f to force)
As I said, when I had problems, I re-cloned everything. So the status is clean: I have no modified files.
Also, I have one other branch, and I tried the above sequence with the other branch. It happened again just as described. So, if anything is wrong, I figure it must be wrong in branch coworker-dev and not in my own branches.
Why is a new head being created? Am I doing something wrong, is there something wrong with my branch, or is this expected behavior?
You're not on the branch head, so merge creates another one
-- A (you're here) --- B --- C (head #1)
\
D (merge, head #2)
So you need to make sure you're on the head using hg id and hg heads. And if no - hg up
What should I do? Can I eliminate this multiple heads problem, or should I push with -f and then close the older of the two heads with hg commit --close-branch?
You should solve the real issue. See the advice above
What bad things might happen if I use hg push -f? My personal rule is "don't do that unless you are a Mercurial expert" and I'm not a Mercurial expert. (So my actual personal rule is "never use hg push -f.")
My personal rule is - to never use -f. After 4 years of experience with mercurial I don't see any good reason to use it at all. What may happen - as soon as there are 2 heads, what would hg up branchname do? What would hg up do?
Related
Is there any way of simulating a git merge between two branches, the current working branch and the master, but without making any changes?
I often have conflicts when I have to make a git merge. Is there any way of simulating the merge first?
You can use git merge --no-commit to prevent the merge from actually being committed, and if you don't like how the merge works out, just reset to the original head.
If you definitely don't want to finalize the merge, even if it's a fast-forward (and thus has no conflicts, by definition), you could add --no-ff as well.
I don't think there is a way of simulating what will happen until you try the merge. However, if you make sure that the output of git status is empty before you do the merge, it is quite safe to just go ahead and try it. If you get conflicts, you can immediately get back to the state you were at before with:
git reset --merge
Since git 1.7.4, you can also abort the merge by doing:
git merge --abort
(As the commit message that added that option explains, this was added for consistency with git rebase --abort and so on.)
If I want to compare changes on a topic branch to master, I find it easiest and safest to do the following:
git checkout master
git checkout -b trial_merge
git merge topic_branch
After completing the merge, it is easy to see the consolidated change from master
git diff master
When done, simply delete the trial_merge branch
git checkout master
git branch -D trial_merge
This way, the master branch never changes.
Here is the solution that I have found: git merge-tree does merging "in memory" and prints the diff without touching your working directory. You can even test a branch without checking it out.
Get the merge diff
First, do this to make sure your repository knows about all the remote branches:
$ git fetch --all
Now use this bash snippet to see how branch $branch would merge into $master:
$ branch='feature'
$ git merge-tree $(git merge-base $branch master) master $branch
No changes are made to your workdir or index. It's a dry-run merge.
Pick information from the output
The output is a diff.
In case the branch has been merged, it will be empty.
To find whether there are conflicts, grep it for <<<:
$ git merge-tree $(git merge-base $branch master) master $branch | fgrep '<<<'
To extract conflict diffs, use sed to extract lines between <<< and >>>:
$ git merge-tree $(git merge-base $branch master) master $branch | \
sed -ne '/^\+<<</,/^\+>>>/ p'
Features
The diff will be empty if a branch is already merged
Use grep/sed to extract conflicts information
Use origin/feature to test branches you've never worked with
Can be used to see how 2 branches have diverged
Add it to your favorites
Get the diff of the merge:
git config --global alias.mergediff '!f(){ branch="$1" ; into="$2" ; git merge-tree $(git merge-base "$branch" "$into") "$into" "$branch" ; };f '
Usage:
$ git mergediff <feature-branch> <merge-into>
$ git mergediff feature master
Get merge conflicts:
git config --global alias.mergetest '!f(){ git mergediff $# | sed -ne "/^+<<</,/^+>>>/ p" ; };f '
Usage:
$ git mergetest <feature-branch> <merge-into>
$ git mergetest feature master
Why not just create a throwaway branch (git checkout -b), and do a test merge there?
I use :
git merge --ff-only
according to documentation:
Refuse to merge and exit with a non-zero status unless the current HEAD is already up-to-date or the merge can be resolved as a fast-forward.
It's not really a simulation because there will be a fast-forward merge in case of no conflicts between the two branches. But in case of conflicts, you will be informed and nothing will happens.
I've been able to use git merge --abort, recently. However, this can only be used if there is a merge conflict. If you are sure that you will not want to commit, then use the other mentioned methods above.
I don't know exactly if it is your case, but your question remember me that sometimes I start a feature, I commit over the days and I merge the develop on it many times.
On this point I lose the control over the exact files I changed and I will only know it when my feature were closed and my code go to develop.
In this case, a good way to know what modifications you did (not other from the merges) is using Sourcetree.
You must click with the right button on the base branch and select Diff Against Current:
Then sourcetree will show you all the modifications that will be merged if you merge your branch into base branch.
Of course, it will not show you the conflicts, but it is a useful tool in merges.
I'm new to Bazaar, coming to it from a background of Subversion and git. I thought I had a working grasp of some basic concepts, but have already hit a stumbling block in my first major commit.
The project is hosted on Launchpad. I created a local branch ("working") with bzr branch. I made changes, added new files, renamed others. In the interim another person on the team committed and pushed their changes. At this point the commit history looked something like this:
3. Team Member A
2. Me (trivial commit of .bzrignore)
1. Original commit
This morning I bzr commit my changes locally. The commit number was reported as 3, which I assumed (wrongly) would be reconciled when I sync'd with the server. When I did a bzr pull I got this message:
Using saved parent location: bzr+ssh://bazaar.launchpad.net/...
bzr: ERROR: These branches have diverged. Use the missing command to see how.
Use the merge command to reconcile them.
I did bzr merge. No conflicts were discovered but three files were left as modified in my local branch. I inspected and committed those with a comment, which was reported to me as commit 4. Then I did a bzr push, which reported no errors.
Now the commit history (bzr log --include-merges) looks like this:
4. My merge commit
2.1.1 Team Member A
3. My commit this morning
2. My .bzrignore commit
1. Original commit
There's a high desire here to keep the trunk line serialized and avoid these merge bubbles. (Annoyingly, Launchpad doesn't display the 2.1.1 commit, making it look like I overwrote it.) What is the best workflow in this situation to avoid these bubbles? Should I have pulled first? I'm wary of having to merge other people's code into my local uncommitted changes.
In addition, although rebase is commonly used in git, it appears it's not generally approved of in the Bazaar world. If we can avoid using the bzr-rebase plugin, that would be great.
One way to have a cleaner mainline history would be to do your work in a separate feature branch, while maintaining a mirror of the mainline branch. I'm assuming branches with working trees here, but you could use treeless branches and a checkout to save disk space.
// setup the mirror branch
cd <mirror directory>
bzr pull <mainline>
// setup a feature branch
cd <feature directory>
bzr branch <mirror directory> .
// work on your feature branch
bzr commit -m "Did some work"
...
bzr commit -m "Did some more work"
// ready to commit your feature
cd <mirror directory>
bzr pull
bzr merge <feature directory>
// your integration testing is done
bzr commit -m "My shiny feature"
bzr push
I have a git branch "dev". Branch "master" is reachable from dev. While on branch "dev", if I type "git log master..dev --pretty=oneline" it clearly shows that master is reachable (104 commits earlier). But if I type "git rebase master", it will stop with conflicts. Why is that? Shouldn't rebase have nothing to do in this case, since dev is already based on master?
The reason I am asking this is because I really want to do an interactive rebase with squashes and rewords to clean up a lengthy history. But I am put off by having to resolve all the conflicts that should have already been resolved once I start the rebase.
The following are some related questions that I've already looked at:
Why does git-rebase give me merge conflicts when all I'm doing is squashing commits?
Conflicts with `git rebase`
git rebase master rebases your branch to be based off the latest commit in master. If you want to base it off something earlier, you need to specify the exact commit, i.e.
git rebase `git merge-base master HEAD`
rebase != merge
If you just want to fast forward, use
git pull --ff-only ...
git merge --ff-only ...
If you want to 'automatically rebase/fastforward' depending on the current context and relationship of your branches, I suppose this would work:
git pull --rebase ...
You may want to read the man page on what it does, precisely
http://gitready.com/advanced/2009/02/11/pull-with-rebase.html
http://longair.net/blog/2009/04/16/git-fetch-and-merge/
We are in the process of converting from CVS to Mercurial hg.
Our infrastructure is Windows 2003/IIS6
Each developer develop on their machine
1xDevelopement server
1xStaging server
Production environment
Here's what I have done so far:
Installed Mercurial on my machine, on the development server and on the staging server.
Created a repository on the dev. server.
Imported our CVS repository in there.
Cloned that repository to my local machine.
Cloned that repository to our staging server.
For development in the past we always shared 1 branch, not ideal but merging was such a pain that we never bothered and dealt with it.
Now if I understand correctly, we should be doing this:
Local:
hg branch myfeature1 //Start work on feature1
Urgent bugfix required, using the affecting the SAME files as our feature
hg update default
hg branch bugfix1 //fix bug
hg commit --rev bugfix1 //done fixing bug we commit
hg push --rev bugfix1 -f //-f seems odd here, forcing to create a new branch
hg update feature1 //we return to work on feature1
hg commit --rev feature1 //done work commit
hg push --rev feature1
DEV
hg branches //we see the bugfix and feature1
hg merge --rev bugfix1
hg commit //commiting bugfix1
hg merge --rev feature1
hg commit //commiting feature1 //Dev master is now our main trunk ready for a new developer containing the feature1 and bugfix1.
Staging (The QA needs to signoff on that important bugfix before testing feature1
hg incoming //we see the new stuff
hg pull --rev bugfix1
hg merge --rev bugfix1
hg commit
//QA test and signoff bugfix1 we clone to a production repo and sync.
//QA can now test feature1 which we finished some days after bugfix1
hg pull --rev feature1
hg merge --rev feature1
hg commit //commiting merge feature1
//QA test feature1 and signoff
We clone to a production repo and sync.
Does this way make sense? Am I complicating things and will it bite me in the ass later?
It looks like you've got the concepts down great, but you've got some oddities and some questions in there, I'll hit them as a list below:
commit doesn't take a --rev option. It commits the current working directory as a new changeset whose parent (or parents if it's a merge) is whatever hg parents returns, which is always whatever you last hg updateed to.
your hg push --rev bugfix1 -f won't require a -f in very new (1.5+) versions of mercurial. Historically the warning "you're creating a new head" usually meant you forgot to merge, but now if the new head is a new named branch the warning is suppressed.
If I were your person doing the emergency bug fix on my local machine I'd just create a new clone and do the branch and fix in there. If you set up your webserver/webapp config to support that you can allow new instances at new path locations easily/automatically
In your staging environment, I recognize the desire to have them test the bugfix independent of the feature and that's a good idea, your QA team shouldn't be merging. Make/let the developers merge and have the QA team pull the merge revisions into their working area. For example, the developer changeset created in DEV step 3 already provides the proper integration of the bugfix and what-used-to-be, so have the QA team pull that revision, which will be on the 'default' branch. Similarly, after QA has approved the bugfix and is ready to move on to the feature, have them pull from dev the changeset created in dev step 5.
Remember, merging is coding too -- the person doing the merge is making choices about what should and shouldn't be. The QA people might be capable of it, but it's the developer's job. Also, why do it twice? The usual handoff for this is something like "QA, pull revision 897a9d9f9a7 and test please -- the developers". If you want to get fancy you can have a tag like 'readyforQA' that the developers move along the 'default' branch as they go (in this example they'd hg tag after their steps 3 and 5 and let QA know there's new stuff to pull.
The one piece of advice I'd give you is don't try to over-engineer the process. DVCSs lead to a sort-of haphazard way of working, that's a little scary at first, but tends to work out. YOu'll find sub-teams and pairs of folks have clones you never knew about and in the end so long as you have a few firm rules like "nothing goes to production without first passing through QA" the rest sort of works itself out.
I would like to do some experimental work in a hg project. So I would like to create branch, commit to it. And if the experiment works, I can merge it back to main branch.
In git, I can do
$ git branch experimental
$ git checkout experimental
(edit file)
$ git commit -a
$ git checkout master
I've read A Guide to Branching in Mercurial. It said hg branch feature. But what is next?
I don't follow.
$ hg branch experimental
(edit file)
$ hg commit
$ hg update default
First note that git branch is different from hg branch. Branches created with hg branch are permanent and live in a global name space, whereas branches made with git branch are transient. The nearest equivalent of git branch is hg bookmark: bookmarks can be renamed and deleted and behave more like Git-branches.
I've recently written a guide for Mercurial bookmarks. Compare this with the named branch guide. Both guides contain worked examples of how to use (named) branches in Mercurial for keeping track of the development. It shows how to merge branches and how to close them or delete the bookmark when you are done.
If it's not a big feature (i.e. the branch doesn't have to have a name), it's quite simple.
Let's say your repository is at changeset X. You work on the feature as much as you like, commit, commit, commit and if you're happy with the result, continue as if you knew it would work all along. ;) If you aren't happy, do a hg update X and continue development from there. All the work you did on your experiment will become an anonymous branch.
Strangely enough, it appears that Git doesn't provide such a way to work with anonymous branches which is what might be confusing you.