Mercurial delete file during merge - mercurial

I have a branch called "developing" with a certain status o files with a release number 500 with a.java and b.java inside.
STEP
- a.java has been deleted from developing and then pushed (501).
- a branch is created from 501 called (my_branch);
- in my_branch I have added a new version of a.java and a new file c.java;
PROBLEM
When I try to merge my_branch with developing, mercurial delete a.java. The result is my_branch with b.java and c.java;
What I think is that mercurial is aware of previusly deleting of a.java and, without prompting a warning, delete the file even if I have added again in my_branch.
How can I force my_branch's file to be merged?

I just tried the described scenario. The mercurial doesn't delete new version of previously deleted file.
Steps to reproduce:
Create new hg repository
Create new file a.txt, commit changes - version 1
Delete file a.txt, commit changes - version 2
Create file b.txt, commit changes - version 3
Update to version 2, by hg update -C 2
Create again new file a.txt, commit changes ( creates new head)
Merging two heads results in files a.txt and b.txt

I'm with #bbaja42 that there's some detail missing in your description -- this doesn't happen in normal usage.
That said, it's easy to work around -- just put the file you want in place before you commit the merge -- merges are always manually committed in Mercurial.
hg update my_branch
hg merge developing
hg revert -r my_branch a.java
hg add a.java # might be unnecessary, but it can't hurt
hg commit -m 'committed the merge with a.java from my_branch in place'

Related

Mercurial: Move a modified file between commits

Let's say I have the following commit history:
A - newest
B
C - oldest
I have changed a file foo in B, but I want to move the change from B to A.
How can I do that with hg?
There are several different ways that I can think of. Both have some moderate user requirements (please make sure you have backed up or pushed to a non-publishing repository first).
1 ) Use histedit and amend (requires that each extensions be enabled).
- copy file you wish to move to a safe location
- run hg histedit and edit changeset b and restore file to its original state
- run hg histedit --continue to commit changes.
- copy file from safe location to repository
- run hg amend to append file to changeset A
2 ) Use split and histedit.
- run hg split -r b
- split out all but the file you wish to move into a new changeset
- create a new changeset onto of that containing the fie (give it a temporary description)
- run hg histedit
- move the temp change above A
- roll the temp change into A
3 ) Use hg-evolve uncommit / amend. While this is a somewhat advanced method, I much prefer this one myself.
- run hg update B
- run hg uncommit and select the file you wish to move.
- run hg evolve to correct the stack
- run hg update A
Note: if you get a warning about needing to use --clean use hg shelve before
running the update followed by hg unshelve afterwords.
- run hg amend to add file to change A
4 ) Use hg uncommit all contents of changesets A and B and then recommit using hg commit -i to reassemble the changesets with the desired content.
There are likely a number of other ways, but this is what came to me.
Here's a simplistic but functional approach, maybe for people not very experienced with some of the more advanced HG commands:
Make sure your working directory is clean (no changes).
hg update -r C
hg revert -r B
hg commit ... as needed, but leave out the change destined for A. This creates B'.
hg shelve ... store away the uncommitted changes
hg revert -r A
hg unshelve ... restore uncommitted changes, merging them into the workding directory
hg commit ... creates C'.
hg strip -r B ... (optional!)
(where it says -r A that means use the revision # corresponding to A)
Explanation: we just create two (or more) entirely new changesets and then delete the originals (which is optional).
We're using revert basically to mean "copy from some changeset to the working directory" which I find is very handy in many circumstances.
After these operations -- but prior to using strip -- the history would look like:
*
|
A A'
| |
B B'
|/
C
and strip will just delete A, B.

Purging old directories and files from a remote hg repo

I initially committed my project to a hg repo with the following structure:
myapp/
fizz/
buzz.txt
foobar.cfg
whistlefeather/
vroom-vroom-party-starter.xml
I did so using the following commands:
hg add
hg commit -m "Initial commit."
hg push
I then changed my directory structure locally to look like this:
myapp/
buzz/
fizz.txt
config.foobar
whistlefeather/
vroom-vroom-party-starter.xml
I then ran the same following commands:
hg add
hg commit -m "Changing some things."
hg push
When I go to the remote repo, I see it has the following structure (?!?):
myapp/
fizz/
buzz.txt
buzz/
fizz.txt
foobar.cfg
config.foobar
whistlefeather/
vroom-vroom-party-starter.xml
What commands can I run to push/purge the old directories/files from the remote repo (and so that it reflect the directory struture on my local machine)?
The hg add command you issued prior to your second commit did not actually remove files from under version control, but only added new ones. Now your repository is actually a melange of old and new files.
To add new files and remove missing ones, use hg addremove command or hg commit -A
It's actually simple to remember:
hg add adds files to the repo
hg remove removes files
hg move moves or renames files
hg addremove looks at current working dir and adds and removes files from the repo such that only the files still being present will continue to be tracked.
Each of these operation can be done in any sequence. And only a commit will actually create a changeset

how to backout to an older version ignoring all versions after that

I have 3 commits which I pushed to the public repository accidentally. I want to revert to an older version (a version before these 3 commits happened) and make it the current code in our public repository.
I am using TortoiseHg,version 2.11.1
Option 1
You can use the strip option as mentioned in the command
hg strip is the command
This extension has to be enabled
Enable the extension by adding the following lines to your .hgrc or Mercurial.ini:
[extensions]
strip =
This option is only suitable if you have access to the central repository where your code is hosted and you have a small group in which you would know if someone have already pulled your changes.
Option 2
Another option would be to backout these 3 commits, Since you are using UI,I will attach a screen shot
Step 1: Right click the unwanted commit and you will see a backout option click that and the wizard wll guide you.
if its a merge that you are trying to backout then you have to select which branch to backout to.
Do the same for the 3 unwanted commits
Option 3
if you have many commits and if its in a named branch following these steps will provide a solution
1) Close the branch and update to the last good commit you want.
2) Reopen the barch from there by new commit (Named branch can have multiple heads)
3) use hg revert -r and commit
This will make the working directory exactly as the last good commit you need and ignore the inwanted commits. This will only work if the commits are in a named branch.
You can do it like this:
hg backout -r <rev>
hg push
This will backout to the <rev> revision (which should be the last correct commit). In other words, it will set your working directory into the same state as it was on the last correct commit and create a new commit with an explanatory message. Then you'll push it to the public repository so it's the current code again.

Mercurial suprepositories

I have got a question regarding suprepositories. Our project is set up like this:
+ projectA
+ some files
+ dependencyA
+ some files
dependencyA is a subrepository. It was created this way:
cd projectA
mkdir dependencyA
cd dependencyA
hg init
hg pull ssh://hg#somerandomiphere/dependencyA
cd ..
echo dependencyA = ssh://hg#somerandomiphere/dependencyA > .hgsub
hg add
hg commit
hg push
If I make changes to the suprepository, then commit and push them from main project. Both of them will be pushed to the server since its recursive. Now my colleague wants to pull changes from the server. But since nothing was changed in the main project, it wont work. But if I change something in the main project and push it to server. Upon hg pull he will get the newest changeset and if he does hg update then, it will update the subrepository as well. This is expected behaviour.
Now my question would be, if there is a way to pull changes, but only for subrepository without making a new clone of it or what would be the best way to do it.
Subrepository in Mercurial wiki, p. 2.5 "Pull"
The 'pull' command is by default not recursive. This is because
Mercurial won't know which subrepos are required until an update to a
specific changeset is requested. The update will pull the requested
subrepositories and changesets on demand. To get pull and update in
one step, use 'pull --update'.
Note that this matches exactly how 'pull' works without
subrepositories, considering that subrepositories lives in the working
directory:
'hg pull' gives you the upstream changesets but doesn't affect your working directory.
'hg update' updates the contents of your working directory (both in the top repo and in all subrepos)
It might be a good idea to always pull with --update if you have any
subrepositories. That will generally ensure that updates not will miss
any changesets and that update thus not will cause any pulls. If the
pull with update fails due to crossing branches then 'hg update' must
be used to get all the subrepository updates.
What was suggested above works like I thought it would. The real problem was my way of creating a subrepository.
Instead of:
cd projectA
mkdir
dependencyA
cd dependencyA
hg init
hg pull ssh://hg#somerandomiphere/dependencyA
It should have been a simple:
hg clone ssh://hg#somerandomiphere/dependencyA dependencyA
As we know .hgsusbtate will lock the subrepo on specific revision after commit. This is what happened, but (!) doing hg pull in subrepository ended with an error
paths cannot contain dot file components
So this means my subrepo was locked on the revision it was updated after commit and it could not pull changes from its repository due to the error shown above. Why this happened is explained pretty well in this accepted answer.
Solution:
cloning is the way to go

Someone committed in our central repository. How do we revert it?

We're using a local central repository where everyone pushes to and pulls from. Until recently this repository only contained the .hg folder. Then someone went ahead and committed directly in the central repository creating an "island" changeset with no parent (parent = -1) nor child. The correct way would have been to add it in a local repository and push the changes.
Is there any way to get the working copy of the central repository to get back to the state where it only contain .hg and not be associated with a specific changeset?
The command:
hg update null
Updates a repository's working directory to the point before the first commit, so there are no files in the working directory and hg parents shows -1.
You'll still need to remove the commit if you don't want it, but that's a separate question/issue.
Since this is your local central repository and these are commands that edit history, please take every precaution, like trying things out on a copy of the repository first.
hg rollback (to remove the last repository change)
https://www.mercurial-scm.org/wiki/Rollback
Roll back the last transaction in a repository.
hg strip (to remove specific revisions)
https://www.mercurial-scm.org/wiki/Strip
hg strip rev removes the rev revision and all its descendants from a repository.
Also see:
https://www.mercurial-scm.org/wiki/EditingHistory
If you catch your mistake immediately (or reasonably soon), you can just use hg strip REV to roll back the latest (one or more) changes. ...
Edit: This answers the question in its original form. The OP has since edited the question.
Just delete everything except the .hg folder.
If I understand correctly what happened, someone changed into the repository directory and committed a single file as an 'added file' without first checking out any changeset from the active directory.
What you ended up with is something like the following history graph:
0:a43f 1:2843 2:bc81 3:2947
o ------ o ------ o ------ o
4:228f
o
where changeset 4:228f has the "null id" as its parent changeset.
Depending on whether you want to keep changeset 4:228f or not, you can follow one of the following strategies:
Option 1: Clone the repository without the offending change
You can create a new clone of the repository, specifying revision 3:2947 as the target revision. This will pull change 3:2947 and all its ancestor changesets into the new repository. Since the offending changeset is not linked into the ancestry of changeset 3:2947, it will not be part of the new clone.
I recommend saving the old repository first, and then moving everything over to a new clone, e.g. any repository-specific setup files you keep in its .hg/ directory.
If your current repository lives in /work/repo/foo, one way to do this would be:
$ cd /work/repo
$ mv foo foo.bak
$ hg clone -r 2947 foo.bak newfoo
Now copy over any .hg/ setup files, e.g. your original .hg/hgrc file:
$ cp foo.bak/.hg/hgrc newfoo/.hg/hgrc
Finally move the new foo repository in place:
$ mv newfoo foo
Option 2: Clone the repository and keep but rebase the change
Do the same as before, but before you move the newfoo repository in place, use the "hg export" command to extract a copy of the offending change from the old repository. Then check out a working copy of the tip-most changeset in the newfoo tree and import the file changes of the offending change as a normal changeset of your current history graph.
So, right before mv newfoo foo, save the patch of the offending change by typing:
$ cd /work/repo/foo.bak
$ hg export -r 228f --git > /tmp/patchfile.diff
then you can check-out the latest revision of the new repository, and re-import the patch on top of your current history:
$ cd /work/repo/newfoo
$ hg update --clean tip
$ hg import /tmp/patchfile.diff
If the offending changeset merely adds a new file, this should work fine and you are ready to move the new repository in place!
Before doing the final rename though, it may be a good idea to remove the working-copy files of the new repository:
$ cd /work/repo/newfoo
$ hg update --clean null