Mercurial: Multiple Change sets at once? - mercurial

Before, when I was using perforce, I could work on multiple bugs at once as long as the code did not affect the same files, by having multiple change sets open at once.
Changeset 1:
A.txt
B.txt
C.txt
Changeset 2:
D.txt
E.txt
F.txt
I could submit changeset 2 to the repository without submitting changeset 1 (because it's still in progress)
Is this possible with Mercurial? other than doing each file as a separate commit?

You can always just do: hg commit D.txt E.txt F.txt to commit just those files which will leave A.txt, B.txt, and C.txt uncommited. Using the -I option to commit lets you do those with patterns if they're, for example, in a common directory: hg commit -I 'dir1/**'

You can have two separate branches (working copies) and make one change in and the other in the other. That's one way.
Another is to use Mercurial Queues. You can use qpush --move to change the order of changesets if they have no dependencies on one another, so you can then use qfinish to 'commit' the first changeset that's ready.

You don't actually hold changesets "open" in Mercurial.
Either you've committed your changes, or you haven't.
You can, however, have multiple files with uncommitted changes, and only commit a few of them. It is even possible to commit parts of files, chunks, instead of the whole file.
If I was to do what you're asking I would simply make another clone locally from my first one, and work on the two different fixes in two different working folders. Then I have all the freedom I need to combine the two (push/pull locally), push to the server, etc.

In Mercurial, cloning is a cheap operation when done locally. Just clone the repository for each thing you are working on. Push back to the main repository as each thing is ready:
hg clone http://project project
hg clone project project-bugfix // uses hardlinks and is inexpensive.
hg clone project project-feature
<edit bugfix and feature as needed>
But remember that the default push location is the project cloned from, so you'll either need to edit .hg\hgrc's default push path for the "project" clones, or make sure to hg push http://project from "project-bugfix" and "project-feature" when complete.

Even if your modifications touches the same file you can select what to include (hunk by hunk). You just have to activate the record extension (it's installed by not activated by default).
To activate the record extension, put this in the [extensions] section of your .hgrc:
[extensions]
hgext.record=
Then to commit, replace hg commit by hg record. Let's assume your example change sets with a G.txt file that have changes for both change sets. Commit with:
hg record D.txt E.txt F.txt G.txt
Answer questions, for example:
2 hunks, 6 lines changed
examine changes to 'D.txt'? [Ynsfdaq?] f # f for full file (help with ?)
... skipped file E and F
6 hunks, 35 lines changed
examine changes to 'G.txt'? [Ynsfdaq?] y
## ... (patch hunk here)
record change 6/16 to 'G.txt'? [Ynsfdaq?] y # y to include the hunk, n to skip

Related

Mercurial - Pull changes after Clone

Say I cloned a remote repository and called it "A"
Then I cloned another remote repository and called it "B"
"B" has the .hg folder and src folder , and "A" only has the .hg folder.
If I pull changes from "B" to "A", should now "A" also contain the src folder? Because that's exactly what I did and it did not
You mix the concepts of 'repository' with the working directory, the actually checked-out changeset, which indicates the state of the repository at a particular revision.
If the two repositories A and B are pulled into one repository, all changesets are present there, but they are present in different changesets. If you want to bring them together, you have to merge two changesets; most likely you want to merge the two heads you have, the one from repository A and the one from repository B. For example:
# check heads:
hg heads --template="{rev}:{node|short} {desc}\n"
2332:d69c8aaf6db6 Doc: Changelog as it should have been
2128:6f38df710194 Added tag 0.2.5 for changeset 6d89bb9ad3f6
Update to one head and then merge the other. Make sure to use the actual revisions:
hg up -r2332
hg merge -r2128
Whether or not that works without any conflicts depends on how A and B look like.
Does src contain any files? You cannot add an empty directory to a mercurial repo. If you tried hg add src and src was empty, you won't get an error but nothing happens. If that's really what you want, there are ways, but it sounds like you're just experimenting.
More specifically: You can only add files, and the directories that contain them are added implicitly. After you create a file in src, add the file to the repo and commit the change (along with anything else you may want to bring along). Now you have a changeset you can push or pull to repository "B".
Once the changeset has become part of "B"'s history (check with hg log), you need to update to it (hg update); or, if you've ended up with a branch, merge it to your current branch.

Moving unstaged + uncommitted changes between Mercurial branches

I cloned a Mercurial repo and did a bunch of local work, and forgot to make a feature branch for said work.
The normal flow is:
Clone
Create a branch
Switch to that branch
Do your work in that branch
Push that branch
Code review
If code review passes, merge branch w/ default (locally)
Push merged changes to default
Close the feature branch
So I need to create a new branch, port all my unstaged/uncommitted code changes (made to default) over to this branch (so that default is now clean and the new branch contains my changes), and then push my feature branch.
I created the new branch via hg branch new_feature. But after pouring over the Merucrial docs, I can't figure out the next step.
So I ask: How do I move (not just copy) all my unstaged/uncommitted changes from default to my new_feature branch)?
You shouldn't have to do anything in particular.
Your uncommitted working folder changes are fluid, and you can set the branch name before you commit, without losing your changes.
If you're on the command line, simply do this:
hg branch feature-X
hg commit -m "Added feature X"
If you're using TortoiseHg simply click the "Branch: default" button just above the commit message input field and select "Open a new named branch" and give it a name, then click OK, then commit as normal.
Setting the branch name to use during commit does not in fact change your working folder, it doesn't do an update, it doesn't do anything, except record in metadata what the branch name is supposed to be.
Also note that this will only allow you to create a new branch to commit to. If you want to continue on an existing branch you first need to update to the head of that branch and this may cause changes to your working folder. You should not need to do this, however, if you want to create a new branch.

Mercurial will not let me push. Abort: push creates new remote head

I can't push using mercurial, it states I have to merge. If I do hg merge, will it merge my branch with the main trunk, I really want to avoid that.
I created and modified some files. I did hg add to add them all. I did some commits but it won't let me push them to my branch.
I posted my output of hg commands below:
C:\Users\kacalica\Desktop\Projects\hydroinformatics>hg incoming
comparing with https://stcalica#bitbucket.org/nickrsan/hydroinformatics
searching for changes
no changes found
C:\Users\kacalica\Desktop\Projects\hydroinformatics>hg status
M hydro\forms.py
? graph_test.py
? hydro\mlgraph\__init__.py
? hydro\mlgraph\test.py
? hydro\plugins\__init__.py.orig
? hydro\urls.py.orig
? hydro\views.py.orig
? public\Hydroinformatics\media\test.txt
? public\Hydroinformatics\media\test_EPALM1I.txt
? public\Hydroinformatics\media\test_OIWsXcC.txt
? public\Hydroinformatics\media\test_v5s6RmF.txt
C:\Users\kacalica\Desktop\Projects\hydroinformatics>hg add
adding graph_test.py
adding hydro\mlgraph\__init__.py
adding hydro\mlgraph\test.py
adding hydro\plugins\__init__.py.orig
adding hydro\urls.py.orig
adding hydro\views.py.orig
adding public\Hydroinformatics\media\test.txt
adding public\Hydroinformatics\media\test_EPALM1I.txt
adding public\Hydroinformatics\media\test_OIWsXcC.txt
adding public\Hydroinformatics\media\test_v5s6RmF.txt
C:\Users\kacalica\Desktop\Projects\hydroinformatics>hg push
pushing to https://stcalica#bitbucket.org/nickrsan/hydroinformatics
searching for changes
abort: push creates new remote head b54ae56acf07 on branch 'WITHOUTPLUGINSGRAPHS'!
(merge or see "hg help push" for details about pushing new heads)
C:\Users\kacalica\Desktop\Projects\hydroinformatics>hg commit -m "added files"
abort: last update was interrupted
(use 'hg update' to get a consistent checkout)
C:\Users\kacalica\Desktop\Projects\hydroinformatics>hg update
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
C:\Users\kacalica\Desktop\Projects\hydroinformatics>hg branch
WITHOUTPLUGINSGRAPHS
C:\Users\kacalica\Desktop\Projects\hydroinformatics>hg status
M hydro\forms.py
A graph_test.py
A hydro\mlgraph\__init__.py
A hydro\mlgraph\test.py
A hydro\plugins\__init__.py.orig
A hydro\urls.py.orig
A hydro\views.py.orig
A public\Hydroinformatics\media\test.txt
A public\Hydroinformatics\media\test_EPALM1I.txt
A public\Hydroinformatics\media\test_OIWsXcC.txt
A public\Hydroinformatics\media\test_v5s6RmF.txt
C:\Users\kacalica\Desktop\Projects\hydroinformatics>hg summary
parent: 36:b54ae56acf07 tip
actually added template
branch: WITHOUTPLUGINSGRAPHS
commit: 1 modified, 10 added
update: 10 new changesets, 2 branch heads (merge)
C:\Users\kacalica\Desktop\Projects\hydroinformatics>
OK, first of all, let's sort out our terminology here. In Mercurial, a "head" is a changeset with no child changesets (https://www.mercurial-scm.org/wiki/Head). Let's say you're working in default branch. If you're being told that pushing would create new remote heads, it means there's a different head revision in default on the remote repository (the one you're pushing to). If you pushed, default would have two head revisions!
How does this happen? Well, it might be another developer did a push in the meantime, or you pushed from another repository/computer by mistake. You don't want to push a branch with multiple heads, otherwise you end up with some crazy hydra with loads of heads, none of which has all the code.
First you need to pull from the remote repository. Next, you need to run "hg merge" - if you're using Hg-Workbench or similar, you might not see the other head immediately, so scroll down and find it. If you have conflicts, now's the time to resolve them. Make sure you commit your merge, and then you should be able to push.
If you're on a verison of Mercurial that's not more than a couple year's old do: hg push --new-branch which the hg help push shows lets you push a new branch:
--new-branch allow pushing a new branch
That'll only be necessary the first time you push a new branch -- it's just there to make sure you don't accidentally push something you didn't mean to share.

Detect creating of branches or bookmarks in HG

Is it possible to detect if a commit creates a new bookmark or branch via hooks in .hgrc?
I've tried to see if I can find out using hg log, but it just shows on what branch/bookmark the commit has been created: http://hgbook.red-bean.com/read/customizing-the-output-of-mercurial.html
There don't seem to be hooks for it: http://hgbook.red-bean.com/read/handling-repository-events-with-hooks.html
It would make sense I suppose that there isn't a hook for it, because it is also not possible to make a commit which is 'just' the creation of the branch indicating branches/bookmarks only exists when added to a specific commit.
I figured I could check hg branches and hg bookmarks before and after each commit and determine which are removed and added, but is there a cleaner way for detecting branch/bookmark adds/removes?
The pushkey and prepushkey hooks can detect the addition, deletion, and moves of bookmarks.
In hgrc:
[hooks]
prepushkey=echo %HG_NAMESPACE% %HG_KEY% %HG_OLD% %HG_NEW%\n >> out.txt
HG_NAMESPACE will contain "bookmark" and HG_KEY will contain the name of the bookmark.
HG_OLD will contain the hash of the commit the bookmark was before the operation. It won't be set if the bookmark is being created.
HG_NEW will contain the hash of the commit the bookmark will be after the operation. It won't be set if the bookmark is being deleted.
Bookmarks
Bookmarks-handling does not require commit
Bookmark can be created|modified for any changeset in history, not only for current
Bookmark(s) can appear as result of data-exchange (pull|push), not local user's actions
Only part of all possible cases can be covered by hook
Branches
Changing branch always reflected in commit
Branch in changeset may differ from parent's branch not only as result of hg branch (see "merge branches" and "mergesets") - and I haven't nice and easy and ready to use solution for this case
Common notes
You can use standard precommit hook (executed before commit and can enable|disable commit) for testing different conditions in commit or or pretxncommit
Mercurial template-engine has keywords for branch and bookmark for using in hg log -T
In pretxncommit hook commit already exist, but not finalized - it means you can manipulate with commit's data using -r tip and tip's parent in any Mercurial command
Dirty skeleton for hook's body
hg log -T "{KEYWORD}\n" -r "tip + tip^" | ....
where KEYWORD may be branch or bookmarks. Result of log is two-strings output, which can be identical of different (not sure for bookmark, TBT!!), which you have to compare (as you want and can)
PS: Idea inspired by EnsureCommitPolicy Wiki and Mercurial pre commit hook topic here

Can a Mercurial graft cope with renamed files

I want to use hg graft to copy a changeset from one branch to another.
However, a file that is modified in the changeset has been renamed (using hg rename) in the source branch -- before the changeset that I want to graft.
When I try I get:
scanning for duplicate grafts
grafting revision 3
searching for copies back to rev 2
unmatched files in local:
f1.txt
resolving manifests
overwrite: False, partial: False
ancestor: c06936303423, local: cfeaa3003c57+, remote: e3f2a201d1e2
remote changed f1a.txt which local deleted
use (c)hanged version or leave (d)eleted? c
Neither (c) nor (d) seem like the right option.
The file f1a.txt was renamed from f1.txt in the source branch. f1a.txt never even existed in the target branch.
Is this possible?
This is an excellent question. It looks like it is not possible. I replayed your scenario and also tried transplant and rebase -- with the same effect.
I guess the basic reason why this does not work is because a graft explicitly only picks the changes of one revision, i.e. past changes (including file renames) explicitly are not considered (update: could be a bug or missing feature as well, see #Soulman's answer).
You did not ask for, but here's a work around ..
Get a patch of the changeset you want to graft:
$ hg export --git -r <rev-to-graft> > my.patch
In this patch, replace f1a.txt with f1.txt, so you get:
...
diff --git a/f1.txt b/f1.txt
--- a/f1.txt
+++ b/f1.txt
## -1,1 +1,1 ##
...
Sed is your friend here: sed -i my.patch -e "s,\([ab]\)/f1a\.txt,\1/f1.txt,g"
Import the edited patch to the target revision:
$ hg up <target-rev>
$ hg import my.patch
I think this is simply a bug that will hopefully be fixed. There is a ticket: Graft fails when files have been moved in an ancestor revision.
A rename is a delete + add + a note saying to treat history of the old file as the history of the new file. When doing a graft (that is making a new changeset by duplicating the same changes without creating a relation as opposed to a merge), you have to incorporate the changes of the changeset some how. You can only graft an "add" operation in this case or decide not to add the file (leave it deleted). I am sorry to say, that it is fundamentally impossible to graft a rename in this case, because it is meaningless if the other branch did not have that file.
I am sorry, if I didn't understand correctly the situation you are in. If that is the case, then please provide an example. (Few commands to set up a dummy repo, which reproduces your case will do the trick).