mercurial clone branches before merge changeset - mercurial

Is there a way to clone a part of a mercurial repo (i.e. clone -r xxx), but keep all changesets prior to the specified revision i.e. not just the ancestors?
For example, given a repo that looks like this:
-- 2 (branch default) -- 5 -- 8 (merge) -- 9 (merge) --
/ / /
0 -- 1 -- 3 (branch foo) ------ 6 -- /
\ /
-- 4 (branch bar) ------ 7 -------------
I would like to clone only the commits prior to the merge, i.e. so the resulting repo looks something like this:
-- 2 (branch default) -- 5
/
0 -- 1 -- 3 (branch foo) ------ 6
\
-- 4 (branch bar) ------ 7
but running
hg clone -r 7 repo repo2
will only give me commits 1, 4, and 7 (branch bar). It appears the only way to get what I'm after is something like this:
hg clone -r 5 repo repo2
cd repo2
hg pull -r 6
hg pull -r 7
Is that correct, or does someone know of a quicker way to do this?

You have to read hg help clone and remember options, which can be used more than once in one clone (-r and -b namely).
You want, in plain words "clone all in default to 5 inclusive and FOO branch and BAR branch"
Translate it into clone
hg clone -r 5 -b foo -b bar <SRC REPO> <DST-REPO>

hg help clone says
-r --rev REV [+] include the specified changeset
This is different than hg help log, for example, which says
-r --rev REV [+] show the specified revision or range
The best you'll be able to do is use -r more than once:
hg clone -r 5 -r 6 -r 7 repo repo2
You can use log and revision sets to determine which other revisions you need to include.

Related

Mercurial: "undoing" two or more commits

In How do I do a pristine checkout with mercurial? Martin Geisler discuss how to remove already Mercurial commit'ed files using:
hg strip "outgoing()"
But what if I I want to keep my added files which went into "outgoing()" - example:
Two users a and b — starting on the same changeset
User a:
echo "A" > A.txt; hg ci -M -m ""; hg push
User b (forgets to run hg pull -u):
echo "B" > B.txt; hg ci -M -m "" B.txt;
echo "C" > C.txt; hg ci -M -m "" C.txt;
If user b run hg strip "outgoing()" then B.txt and C.txt are lost. hg rollback is not an option since there are two commits.
Can user b revert his files as "locally added - nontracked", then do hg pull -u, which gets A.txt, then handle the add/commit/push for B.txt and C.txt later?
Martin Geisler answered this earlier in the mentioned thread (a comment which I deleted and moved here:
hg update "p1(min(outgoing()))"
hg revert --all --rev tip
hg strip "outgoing()"
hg pull -u
Now user c can finalize his work in the new files B.txt and C.txt and commit+push those.
Other ways to do this?
You could but, by doing so, you are working against one of the biggest features of a DVCS like mercurial, that is, to easily and reliably handle the merging of multiple lines of development as in your case. If user b's goal is to have a line of development with all three changes applied, then the standard way to do that in hg would be to just go ahead and do an hg pull -u which will create a new head containing the change(s) from user a (and any other changes pushed to repo used for pulling) and then use hg merge to merge the two heads, the head containing user b's two change sets and the other containing user a's change set (as pulled). In a simple case like this one with no overlapping changes, hg should do all the right things by default.
$ hg pull -u
[...]
added 1 changesets with 1 changes to 1 files (+1 heads)
not updating: crosses branches (merge branches or update --check to force update)
$ hg merge
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg ci -m "merge"
If there were conflicts between the two heads (i.e. both users committed changes to the same files), there might need to be conflict resolution editing as part of the merge; hg will tell you if that is the case.
Another option is the rebase extension. With your scenario:
A and B start with the same history.
A commits and pushs a change.
B commits two changes, but can't push because of A's commit.
B pulls A's change.
B runs hg rebase and pushes.
Before rebase:
Common ---------------------------- A (tip)
\
B1 - B2 (working parent)
After:
Common - A - B1 - B2 (tip, working parent)

How do I diff one branch with my default branch

I switched to a branch on my local repo and noticed it gave me message showing x files updated. This surprised me as I didn't know there were any differences on that branch. How do I compare that branch with the default branch to see what has changed?
Use hg diff -r BRANCH1:BRANCH2, where BRANCH1 and BRANCH2 are the names of the branches. This will show you the differences between the heads of the two branches.
You got the message about "x files updated" because there were files changed on the original branch, not necessarily because there were files changed on the other branch. Mercurial shows you the union of the sets of changed files from both branches.
To just list the files with differences, add the --stat option:
hg diff --stat -r BRANCH1:BRANCH2
This gives output like this:
mypath/file1.cpp | 1 -
mypath/file2.cpp | 143 ++++++++++
mypath/file3.cpp | 18 +-
3 files changed, 160 insertions(+), 2 deletions(-)
Or to clean up the output a bit, pipe it through sed to remove everything after the pipe symbols:
hg diff --stat -r BRANCH1:BRANCH2 | sed "s/|.*$//g"
This gives you just a list of the changed files and the summary line at the end:
mypath/file1.cpp
mypath/file2.cpp
mypath/file3.cpp
3 files changed, 160 insertions(+), 2 deletions(-)
To view a diff of branch otherbranch with the current branch:
hg diff -r otherbranch

Create a new branch, made a lot of changes, how to view list of files changed?

So there was a new branch created where we made some breaking changes to the codebase.
Now we are going to merge, but before that I want to get a list of all the files that were changed in the branch.
How can I get a list of files? I tried:
hg status --change REV
But i'm not sure if that is what I want, since I want all files changed in this branch and not a specific revision in the branch.
BTW, how can I view the revision numbers?
Try with
$ hg status --rev "branch('your-branch')"
to get the changes between the first and the last changeset on the branch (hg status will implicitly use min(branch('your-branch')) and max(branch('your-branch')) when you give it a range of revisions like this).
Since you'll be merging, you should really look at
$ hg status --rev default:your-branch
to see what is changed between the default branch and your-branch. This shows you the modifications done, and filters out any modifications done on the branch due to merges with default.
This is necessary in case your history looks like this:
your-branch: x --- o --- o --- o --- o --- o --- y
/ / /
default: o --- a --- o --- b --- o --- c --- o --- o --- d
where you've already merged default into your branch a couple of times. Merging default into your branch is normal since you want to regularly integrate the latest stuff from that branch to avoid the branches drifting too far away from each other.
But if a new file was introduced on default and later merged up into B, then you don't really want to see that in the hg status output. You will see it if you do
$ hg status --rev a:y
since the file was not present in a, but is present in y. If you do
$ hg status --rev d:y
then you wont see the file in the output, assuming that it's present in both heads.
You write in a comment that you're working Kiln repository. They mean "clone" when they say "branch", but the above can still be adapted for your case. All changesets will be on the default named branch, but that's okay.
Run the following command in your local clone of the "branch" repository:
$ hg bookmark -r tip mybranch
This marks the current tip as the head of mybranch. Then pull all the changesets from the main repository:
$ hg pull https://you.kilnhg.com/Repo/public/Group/Main
You then mark the new tip as the tip of the main repository:
$ hg bookmark -r tip main
You can now run
$ hg status --rev main:mybranch
to see the changes between main and my-branch. If you want to see what you did on the branch itself, the use
$ hg status --rev "::mybranch - ::main"
The ::mybranch part will select changesets that are ancestors of mybranch — this is all your new work, plus old history from before you branched. We remove the old history with - ::main. In older versions of Mercurial, you would use hg log -r -r mybranch:0 -P main.
In cases like this, I prefer to do a test merge from a newly checked-out copy of the repo. This has the advantage that I can see how many conflicts the merge will produce, and I can keep the merge result because I did it in its own copy.
To view the revision numbers, enable the graphlog extension and run:
$ hg log -b your-branch -G
This gives you a nice ASCII graph. This can be handy to quickly look at the graph, but I recommend using TortoiseHg for a cross-platform log viewer:
I had to merge the default branch into my branch to get some fixes, now the commands above shows also files changed because of merges (this files changed after the merge again in the default branch).
Therefore, to get only the correct files I use something like this:
hg log --rev "branch('my-branch') and not merge()" --template '{files}\n' | sed -e 's/ /\n/g' | sort -u
if you have spaces in file names, you can do it this way:
hg log --rev "branch('my-branch') and not merge()" --template '{rev}\0' | xargs -0 -I # hg status -n --change # | sort -u
And to answer your last question, revisions can be shown this way:
hg log --rev "branch('my-branch') and not merge()" --template '{rev}\n'
TIP: I use a hg-alias for this:
[alias]
_lf = ! $HG log --rev "branch(\"$1\") and not merge()" --template '{rev}\0' | xargs -0 -I # hg status -n --change # | sort -u
With mercurial, if you want to get the list of all the files changed in your current branch (changes done of your changeset) you can use these commands: :
hg log --branch $(hg branch) --stat | grep '|' | awk -F\ '{printf ("%s\n", $1)}' | sort -u
Example result:
api/tests/test_my_app.py
docker/run.sh
api/my_app.py
Explanation of the commands:
hg log --branch $(hg branch) --stat
Show revision history of entire repository or files and output diffstat-style summary of changes
hg branch
Show the current branch name
grep '|'
Search for a text pattern, in this case, it is "|"
awk -F\ '{printf ("%s\n", $1)}'
Space separator denotes each field in a record and prints each one in a new line
sort -u
Sort all the printed lines and delete duplicates

Mercurial - see list of files that need to be manually merged?

Is there a Mercurial command you can use after an hg pull to see a list of all files that will be need to be manually merged (ie: that have conflicts) when doing an hg merge?
hg resolve --list
From the documentation:
Merges with unresolved conflicts are often the result of non-interactive merging using the internal:merge configuration setting, or a command-line merge tool like diff3. The resolve command is used to manage the files involved in a merge, after hg merge has been run, and before hg commit is run (i.e. the working directory must have two parents).
Edit 5 January 2012:
(I received an up vote for this answer today so I revisited it. I discovered that I misunderstood the question.)
The question is "I have performed a pull from a remote repository and have not yet performed a merge. Can I see what conflicts will be created upon performing the merge?"
My answer above is clearly wrong. After reading through the linked documentation, I do not think there is a built-in method for doing this. However, there is a way to do it without ruining your working source tree.
Let's assume you have cloned repository A from some remote source to repository B on your local system, i.e. hg clone http://hg.example.com/A B. After doing so, you make changes to your local repository, B, that involve at least one commit. In the meantime, changes have been made to repository A so that when you do a pull you get a message indicated new changesets have been added and heads have been created.
At this point, you can do hg heads to list the two changesets that will be involved in a merge. From this information, you can issue a status command to list the differences between the heads. Assuming the revision numbers in your repository B, according to the heads list, are "1" and "2", then you can do hg status --rev 1:2 to see a list of the changes.
Of course, this doesn't really tell you if conflicts will occur when you do a merge. Since there isn't a command that will show you this, you will have to "preview" the merge by cloning to a new repository and doing the merge there. So, hg clone B C && cd C && hg merge. If you are satisfied with the result of this merge you can do hg com -m 'Merging complete' && hg push && cd ../ && rm -rf C.
It's a bit of a process, but it keeps your current source tree clean if the merge turns out to be a disaster. You might also find this description of working with public repositories helpful.
Unless I'm misreading it myself, the answers above don't seem to address the question that I think is being asked: I have two branches in my repository that I'd like to merge, and I want to know what conflicts will come up (e.g., before stepping through the conflict resolutions one-by-one.)
To do this, I would merge with the :merge3 tool (which tries to merge automatically, but leaves conflicts unresolved) and then use hg resolve --list — or just look at the output of merge command — to see the conflicts.
hg merge <otherbranch> --tool :merge3
hg resolve -l
If you didn't actually want to merge in the end (if you just want to see what would conflict) you can run hg update -C afterwards to undo the merge.
If you do want to finish the merge, you can run hg resolve <filepath> for each file, or just hg resolve --all to step through all that remain with conflicts, before you hg commit the merge changeset.
You can use the --rev option of hg stat with a pair of revisions to see what file differences exist between the two. See below for a slightly verbose but detailed example:
First we start by making a new repository:
[gkeramidas /tmp]$ hg init foo
[gkeramidas /tmp]$ cd foo
Then add a single file called foo.txt to the new repository:
[gkeramidas /tmp/foo]$ echo foo > foo.txt
[gkeramidas /tmp/foo]$ hg commit -Am 'add foo'
adding foo.txt
[gkeramidas /tmp/foo]$ hg glog
# 0[tip] b7ac7bd864b7 2011-01-30 18:11 -0800 gkeramidas
add foo
Now add a second file, called bar.txt as revision 1:
[gkeramidas /tmp/foo]$ echo bar > bar.txt
[gkeramidas /tmp/foo]$ hg commit -Am 'add bar'
adding bar.txt
Go back to revision 0, and add a third file, on a different head. This is done to simulate a pull from someone else who had cloned the same repository at its starting revision:
[gkeramidas /tmp/foo]$ hg up -C 0
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
[gkeramidas /tmp/foo]$ echo koko > koko.txt
[gkeramidas /tmp/foo]$ hg commit -Am 'add koko'
adding koko.txt
created new head
[gkeramidas /tmp/foo]$ hg glog
# 2[tip]:0 e5d80abdcb06 2011-01-30 18:12 -0800 gkeramidas
| add koko
|
| o 1 a2d0d0e66ce4 2011-01-30 18:12 -0800 gkeramidas
|/ add bar
|
o 0 b7ac7bd864b7 2011-01-30 18:11 -0800 gkeramidas
add foo
Now you can use hg stat to see what file differences exist between any pair of revisions, e.g. the changes from rev 0 to rev 1 added 'bar.txt' to the file list:
[gkeramidas /tmp/foo]$ hg stat --rev 0:1
A bar.txt
The changes from rev 0 to rev2 added 'koko.txt' to the file list:
[gkeramidas /tmp/foo]$ hg stat --rev 0:2
A koko.txt
But more interestingly, the changes from rev 1 to rev 2 involve two file manifest changes. (1) 'koko.txt' was added in rev 2, and (2) 'bar.txt' exists in rev 1 but is missing from rev 2, so it shows as a 'removed' file:
[gkeramidas /tmp/foo]$ hg stat --rev 1:2
A koko.txt
R bar.txt
I think hg status is what you are looking for.
You may want to read this chapter from Mercurial: The Definitive Guide
http://hgbook.red-bean.com/read/mercurial-in-daily-use.html

Mercurial Rebase Scenario

I've read the RebaseProject page and tried a non-trivial example
(not rebasing a complete branch). It's similar to the case rebase D on
I of the scenario B.
Here's the situation before the rebase:
default : 0 ----- 2
\
feature : 1 ----- 3
Now I'd like to rebase 3 on 2, giving:
default : 0 ----- 2 ----- 3
\
feature : 1
Unfortunately the exact commands aren't given in the RebaseProject
page, but from my understanding of the usage synopsis it should be:
hg rebase --source 3 --dest 2
But somehow my understanding must be flawed, because I get a rebase combined with a merge:
default : 0 ----- 2 ----- 3
\ /
feature : 1 -------
Why is that?
Commands to reproduce the scenario:
hg init
touch a
hg add a
hg commit -m "added a"
hg branch feature
touch b
hg add b
hg commit -m "added b on feature"
hg up -C default
touch c
hg add c
hg commit -m "added c on default"
hg up -C feature
echo "feature" >> a
hg commit -m "changed a on feature"
hg rebase --source 3 --dest 2
Your scenario looks very similar to part rebase G onto I of scenario B of the Rebase Project Scenarios:
Scenario B
...
...
rebase G onto I
In your scenario, D == 1, I == 2 and G == 3. After rebasing, 3 maintains its relationship to 1 just like G' maintained its relationship to D. This is because D is not an ancestor of I and:
Note: Rebase drops a parent relationship only if the parent is an ancestor of target.
You really want to remove that relationship, then, according to the docs, you need a development version to get the --detach option:
Using a development version is available the new --detach option that drops this relationship.