I have an old mercurial repository for a project that has the changes before a certain date, and I have another repository for the same project with all the changes after that date.
I want to merge these two repositories so the history reflects that the first commit in the latter repository is the child of the last commit in the former repository.
Is this possible? Or do I just have to merge both heads?
Reading here:
http://blog.experimentalworks.net/2009/03/merge-vs-rebase-a-deep-dive-into-the-mysteries-of-revision-control/
and here:
https://www.mercurial-scm.org/wiki/RebaseExtension
I looks like what I am wanting to accomplish can be done with a rebase, with some caveats.
I pull the changes from the newer repo into the older repo. This results in two heads since both repos only have the 'default' branch. In the older repo folder, I ran:
hg pull -f ../newer-repo
Then I have to use hg phases to make the pulled changes malleable. Normally, this is a bad idea, but since I know I am the only developer on this project, I can do this safely.
hg phase -f -d -r 15 16 ...
Finally, I can now rebase because the history pulled in from the newer repo begins with the same state as the last changelist in the old repo.
hg rebase -s 15 -d 14
I have a single history and no conflicts.
This probably wont work for everyone, but in this narrow circumstance, this was exactly what was needed.
Related
I have a mercurial repository in which I had created a branch 7-8 months back. And now this branch is the one in which I do most of the development and I don't have anything fruitful in default branch and other branches that I have.
I want to create a new repository that represent only this branch. i.e. I want to move this branch to a new repository with history.
I tried to use HG convert tool with following syntax:
hg convert --filemap ~filemap.txt --branchmap branchmap.txt --source-type hg --dest-type hg "E:\MyStuff\Dev\MyOldRepo" "E:\NewRepo"
File map I have defined all my file that I want to include. In branchmap file i had defined
MyOldNamedBranch default
Convert tool do rename MyOldNamedBranch to default but it also brings the changesets from other branch that I don't need.
I also tried to set the following in setting file but no results:
[convert]
hg.usebranchnames=0
hg.startrev=5262
Please suggest how I can move a branch to new repository with history and leaving other branches behind.
I have set the start revision number in command only and it worked.
hg convert --config convert.hg.startrev=5262 --branchmap branchmap.txt "E:\MyStuff\Dev\MyOldRepo" "E:\NewRepo"
And it worked like a charm.
Try this:
Clone only the branch you need:
hg clone E:\MyStuff\Dev\MyOldRepo -b MyOldNamedBranch .\NewRepo
Then inside the NewRepo, convert all the changesets to the draft phase:
hg phase -r 0 -d -f
Then update to the patent of MyOldBranch (I assume, that the parent is in the default branch)
hg update -r "parents(min(branch(MyOldBranch)))"
Then rebase MyOldBranch on the exactly the same changeset.
hg rebase -s "min(branch(MyOldBranch))" -d .
Do exactly the same with the rest of the branches.
To be honest I'm not sure if this is the best method but it worked for me.
We just moved over to Git from SVN. In trying to clean up some unused files. I saved before deleting one folder that I thought we weren't using. I did not push this to the origin. I realized we are using one of the files in the folder after all, and would like to revert to my last commit. This is on my own branch from the master. I can't find a way to do that in Xcode. Am I missing something? Thanks.
You can see here for rsanchezsaez answer: Xcode 4 git integration
Xcode 4 won't let you to checkout older commits within the user interface, unless you created a new branch for that commit. Nevertheless, you can do it from the command line. For that, use the following command from your project folder
$ git log --format=oneline
to get the hash code of the commit you want to go to, and then use:
$ git checkout desired-hash-code
to checkout that particular version. Once there, you can make tests, changes, and possibly create a new branch. If you do a commit without creating a new branch, you will lose the newer commits in your current branch. If you want to go back to the newest commit after having performed some tests on your older version use:
$ git checkout master
note again that this won't work if you do a new commit from your old code version without creating a new branch, because newer commits in the current branch get dereferenced.
Also, please consider searching SO before asking. Many questions had already been asked and answered.
From the command line, run a program called gitk - this will allow you to visualize the commits you currently have. Find the ID of the commit you want (e.g. the previous commit) and do the following on your branch:
git tag JustInCase
git reset --hard <commit ID>
Refresh gitk, and if you're happy with the results then delete the tag using:
git tag -d JustInCase
If you're not happy with it, just do:
git reset --hard JustInCase
git tag -d JustInCase
To visualize this for you:
1) Start
2) After tagging and resetting your branch to the previous commit.
3) After deleting the tag and doing Reload in gitk.
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.
I'm using Mercurial and I've got into a terrible mess locally, with three heads. I can't push, and I just want to delete all my local changes and commits and start again with totally clean code and a clean history.
In other words, I want to end up with (a) exactly the same code locally as exists in the tip of the remote branch and (b) no history of any local commits.
I know hg update -C overwrites any local changes. But how do I delete any local commits?
To be clear, I have no interest in preserving any of the work I've done locally. I just want the simplest way to revert back to a totally clean local checkout.
When the simplest way (a new hg clone) isn't practical, I use hg strip:
% hg outgoing -l 1
% hg strip $rev # replace $rev with the revision number from outgoing
Repeat until hg outgoing stays quiet. Note that hg strip $rev obliterates $rev and all its descendants.
Note that you may have to first enable strip in your Mercurial settings.
PS: an even smarter approach is to use the revset language, and do:
% hg strip 'roots(outgoing())'
You'll want to make a local clone where you preserve only the changesets that are also present in the remote repository. Use TortoiseHg, hg log or similar to figure out which of your revisions is that lastest revision you didn't make (the one before the mess started). Using hg outgoing can help here -- it will list all the changesets you made -- pick a revision number earlier than any of those.
If the target revision is called good and your clone is called foo, then do:
hg clone -r good foo foo-clean
This will be a fast, local operation -- there is no reason to download everything again. The foo-clean clone will only contain changesets up to revision good. You can now replace foo-clean/.hg/hgrc with foo/.hg/hgrc in order to preserve your repository-local settings such as the default push/pull path.
When you are satisfied that foo-clean has everything you need from foo, then simply delete foo and rename foo-clean to foo. Do a hg pull to get any new changesets from the remote repository into your clone and continue like normal.
If nobody has pushed new changesets to the remote repository, then it is very simple to determine which revision you want to use as good above: hg id default will tell you the ID of the tip in the remote repository.
Ok. So just delete all the local stuff, hg init the new local repository and hg pull the latest tip you have. Don't forget to hg update after this.
You may use
hg strip revision
to kill any revision and its subtree in your local repository.
https://www.mercurial-scm.org/wiki/Strip
But don't try to use it for anything that has been already pushed.
Just delete everything you have on your local system and re-clone the remote repo.
hg strip `hg out --template "{rev} {author}\n" | grep YOUR_AUTHOR_NAME | cut -d " " -f 1`
does the trick for me.
It strips all revisions that aren't pushed to the default repository which are created with your author name.
You can also use this style to make it not checking with the default repository but with another Repository
hg strip `hg out OTHER_REPO_ALIAS --template "{rev} {author}\n" | grep YOUR_AUTHOR_NAME | cut -d " " -f 1`
If you are using TortoiseHg, one simple way to get out of a (small) mess is to first update to the latest revision, then select your changesets and initiate "merge with local". When the merge dialogue appears, simply click the little '+' icon to reveal some extra options, one of which is "discard changesets from merge target (other) revision". Doing this will mean your changesets will still be in the repo and get pushed, but will have no effect, because they will be discarded in the merge. If you have a lot of changesets spanning many heads, you might not want to pollute the repo this way, but it's a simple fix and worth considering if the changesets you are discarding contain data that you may later want to reference.
How do I get a patch from a commit in order to send it to another developer? And how do I best avoid a merge conflict with this patch when merging our trees at a later date?
If you know how please explain how to do this in your VCS of choice such as subversion, git, Mercurial, bzr or etc.
In git you can pipe the output of git-diff between two commits like this:
git diff fa1afe1 deadbeef > patch.diff
Send the patch.diff to the developer and let him git-apply it to his workspace like this:
git apply patch.diff
If the other developer already has the commits available in his repository he could always pipe it in himself without merging like this:
git apply < git diff fa1afe1 deadbeef
You can then add and commit the changes in the diff the usual way.
Now here comes the interesting part when you have to merge the patch back to the master branch (that is public). Consider the following revision tree where C* is the applied patch from C in the master branch:
A---B---C---D master, public/master
\
E---C*---F feature_foo
You can use git-rebase to update the topic branch (in this example named feature_foo) with it's upstream head. What that means is when you type in the following:
git rebase master feature_foo
Git will rearrange the revision tree like this and will also apply the patch itself:
A---B---C---D master, public/master
\
E*---F* feature_foo
Merging to the upstream branch will now be an easy fast-forward merge. Also check that the new commits E* and F* work as the previous E and F respectively.
You can do the same thing against another developer's branch using the same steps but instead of doing it on a public repo, you'll be fetching revisions from the developer's repository. This way you won't have to ask the other developer for a patch if it is already available from what he published at his repo.
Please note to never rebase a public branch because the command will rewrite git history which is something you don't want to do on branches that people depend on and will create a mess when merging to remote repositories. Also never forget to integrate often so others in your team can take part of your changes.
In SVN you can simply make your changes then before commiting, pipe the output of the svn diff to a file as such
svn diff > mypatch.diff
you can then revert your changes and apply the patch at a later date using
patch -p0 -i mypatch.diff
As always don't blindly apply patches to your code and always inspect them first.
You may also find that the patch will break your source code if the source files have changed significantly enough since the patch was taken.
You also can not guarantee that there will not be merge conflicts when you attempt to check in the code.
Bzr handles sending a "merge directive", meaning it sends the patch for you so that the other party can simply click "OK" to merge and there's less futzing around with patch/apply etc.
just:
$ bzr send -o mycode.patch
In Subversion there is no nice way of doing this. Yes, you can use svn diff + patch but this will only postpone your problems until you are going to merge and by then chances are that you've forgotten about it.
The way you would do it in Subversion would be to create a branch, do the commit on the branch and ask the recipient of the patch to switch to the branch. Then you can merge the branch back to trunk in the usual way.