Join two Mercurial repositories into one line of revisions - mercurial

Two "unrelated" Mercurial repositories are created:
user#SERVER ~/mercurialtest
$ cd jointest/
user#SERVER ~/mercurialtest/jointest
$ hg init beginning
user#SERVER ~/mercurialtest/jointest
$ hg init end
user#SERVER ~/mercurialtest/jointest
$ cd beginning/
user#SERVER ~/mercurialtest/jointest/beginning
$ echo "something old..." >> data.txt
user#SERVER ~/mercurialtest/jointest/beginning
$ hg add data.txt
user#SERVER ~/mercurialtest/jointest/beginning
$ hg commit -m "Nr 1 in beginning"
user#SERVER ~/mercurialtest/jointest/beginning
$ echo "something old..." >> data.txt
user#SERVER ~/mercurialtest/jointest/beginning
$ hg commit -m "Nr 2 in beginning"
user#SERVER ~/mercurialtest/jointest/beginning
$ echo "something old..." >> data.txt
user#SERVER ~/mercurialtest/jointest/beginning
$ hg commit -m "Nr 3 in beginning"
user#SERVER ~/mercurialtest/jointest/beginning
$ cp -v data.txt ../end/
`data.txt' -> `../end/data.txt'
user#SERVER ~/mercurialtest/jointest/beginning
$ cd ../end
user#SERVER ~/mercurialtest/jointest/end
$ hg add data.txt # No shared changeset
user#SERVER ~/mercurialtest/jointest/end
$ hg commit -m "Nr 1 in end"
user#SERVER ~/mercurialtest/jointest/end
$ echo "new stuff..." >> data.txt
user#SERVER ~/mercurialtest/jointest/end
$ hg commit -m "Nr 2 in end"
user#SERVER ~/mercurialtest/jointest/end
$ echo "new stuff..." >> data.txt
user#SERVER ~/mercurialtest/jointest/end
$ hg commit -m "Nr 3 in end"
Is it possible and how do I join them together into one repository? I want to go from two separate repositories beginning="o-o-O", end="O-o-o" (with a total of six commits) where they have exactly the same content in O to one repository joined="o-o-O-o-o" (with a total of five commits).
My reason is that I have converted two branches into their own repositories, but I really want them in one instead. I havenĀ“t gotten the convert to work except this way, as separate repositories.

The convert extension can do that, using --splicemap.

Related

Amending a commit with the effects of hg cp --after

I have a file before.txt, which I want to split into two smaller files. What I should have done was
$ hg cp before.txt part1.txt # Then edit part1.txt
$ hg mv before.txt part2.txt # Then edit part2.txt
$ hg commit
Then, both part1.txt and part2.txt will have before.txt as part of their history, so the diff will show as deleting parts of a larger file, rather than deleting one file and creating a new one with some of its contents.
However, what I actually did was
$ cp before.txt part1.txt # Then edit part1.txt
$ hg mv before.txt part2.txt # Then edit part2.txt
$ hg commit
So before.txt is only present in the history of one of my two files. If I hadn't run hg commit, it seems clear to me that I could solve my problem with
$ hg cp --after before.txt part1.txt
or something similar to that. And I haven't pushed this commit upstream, so I should be able to edit it however I like. But I can't figure out how to do it. When I run that hg cp, I see:
$ hg cp --after before.txt part1.txt
before.txt: No such file or directory
before.txt: No such file or directory
abort: no files to copy
This makes sense: it can't record that edit as part of a new commit, because the source file doesn't exist. I want to record it as part of the previous commit, but I don't know how to do that except by recording it as part of a new commit and then amending it into the previous commit.
Here's one way to fix that situation:
$ hg shelve # get any miscellaneous, unrelated changes out of the way
$ hg up <parent of revision with the mistake in it>
$ hg cp before.txt part1.txt
$ hg mv before.txt part2.txt
$ hg revert -r <revision with the mistake in it> --all
$ hg commit
$ hg strip <revision with the mistake in it>
(I didn't actually try all these commands, hopefully no typos!)
The first step is optional depending on the state of your working directories.
Now part1.txt and part2.txt should have the correct contents. The use of revert was just to save having to manually re-edit the file changes. But you could also just redo it manually if that seems easier.
The use of revert to pull into the working folder the effects of another changeset is a trick I use a lot. Its like a manual way of amending which gives you total flexibility. But it only works well when the revision you are reverting your working copy to is closely related to the revision which is the parent of the working copy. Otherwise it will create numerous nuisance changes.
based on #DaveInCaz answer, here is a MCVE
mkdir tmpdir
cd tmpdir
hg init
echo line1 > before.txt
echo line2 >> before.txt
hg add before.txt
hg commit -m "my before"
cp before.txt part1.txt
hg add part1.txt
hg mv before.txt part2.txt
echo line1 > part1.txt
echo line2 > part2.txt
hg commit -m "my bad"
hg shelve
hg up -r -2
hg cp before.txt part1.txt
hg cp before.txt part2.txt
hg revert -r -1 --all
hg commit -m "my good"
hg strip -r -2
some remarks:
twice hg cp, because the later revert will delete the file before.txt for us, otherwise it would complain about missing it
revert --all at least in my version it requires to specify what is being reverted
the hg shelve is to be safe, before switching over to a different revision
the hg up -r -2 could have -C since previous shelve made us safe, that way you can retry final steps with different approaches and see what suits you better

Create a Mercurial alias that runs two commands and takes one paramater

I'm trying to create an alias and allows me to commit my changes and push all changesets for the current branch.
I'm running this from a Windows command prompt.
I've read this question and this question and so far have this:
ci-push = !hg ci -m $1 && hg push -b .
When I try this i get the error:
abort: Commit: The system cannot find the file specified
If I try:
ci-push = !hg ci -m %1 && hg push -b .
then it appears to work (prompts for auth and pushes the commit), but my commit message is:
%1
Is this even possible from a Windows cmd prompt?
On Windows, %USERPROFILE%\mercurial.ini:
[alias]
ll = log -l$1
Testing:
>hg ll
abort: too few arguments for command alias
> hg ll 5
changeset:...
Shell alias (%USERPROFILE%\mercurial.ini):
[alias]
ld = !hg log -r $1 && hg diff -r $1
Testing:
>hg ld 154
changeset: 154:5bb3aba44eab
....
diff -r 5bb3aba44eab ....
P.S.
When using $N with spaces you should use quotes (!hg ci -m "$1" ... in aliases).

How to work on multiple patches at the same time using Mercurial Queues?

Lets say, I have 2 bugs to fix : bug1 and bug2.
I start with bug1 and in the midst of fixing it, I go to bug2 and half fix it.
I return to bug1 and again partially fix it and again go to bug2.
Like this, after much switching, I finish fixing both the bugs.
The people who are to review both these bugs are different and want nothing to do with the bug they aren't concerned with. So, I need to provide them with different patches.
If I were using plain hg diff, I would have done :
hg diff -U 7 -p file1 -r OLD_REVISION_NUMBER > patch1 for bug1, and
hg diff -U 7 -p file2 -r OLD_REVISION_NUMBER > patch2 for bug2
How do I do the same with Mercurial Queues?
Please suggest a basic workflow.
Here is a very simplified workflow assuming two non-overlapping patches, that is, the two patches do not modify the same files.
$ hg init myrepo
$ cd myrepo
$ echo "This is file1" >file1
$ echo "This is file2" >file2
$ hg add
adding file1
adding file2
$ hg commit -m 'initial files'
# Initialize and work on patch1
$ hg qnew -m 'Fix for bug1' patch1
$ echo "a second line" >>file1
$ hg diff
diff --git a/file1 b/file1
--- a/file1
+++ b/file1
## -1,1 +1,1 ##
-This is file1
+a second line
$ hg qdiff
diff --git a/file1 b/file1
--- a/file1
+++ b/file1
## -1,1 +1,1 ##
-This is file1
+a second line
# Update the current patch (patch1)
$ hg qrefresh
$ hg diff
$ hg qdiff
diff --git a/file1 b/file1
--- a/file1
+++ b/file1
## -1,1 +1,1 ##
-This is file1
+a second line
# Initialize and work on patch2
$ hg qnew -m 'Fix for bug2' patch2
$ hg qseries
patch1
patch2
$ hg qtop
patch2
$ hg diff
$ echo 'another line for file2' >>file2
$ hg diff
diff --git a/file2 b/file2
--- a/file2
+++ b/file2
## -1,1 +1,2 ##
This is file2
+another line for file2
$ hg qrefresh
$ hg diff
$ hg qdiff
diff --git a/file2 b/file2
--- a/file2
+++ b/file2
## -1,1 +1,2 ##
This is file2
+another line for file2
# Export patch2
$ hg export qtip
# HG changeset patch
# User My Name <myemail>
# Date 1362771912 28800
# Node ID 2baa2bf81b000d4d720f9c4151242458b90bcd80
# Parent ccd75363c8f459bec4a8d6b94dfb4150fb9e3014
Fix for bug2
diff --git a/file2 b/file2
--- a/file2
+++ b/file2
## -1,1 +1,2 ##
This is file2
+another line for file2
# Pop back to and export patch1
$ hg qpop
popping patch2
now at: patch1
$ hg export qtip
# HG changeset patch
# User My Name <myemail>
# Date 1362771745 28800
# Node ID ccd75363c8f459bec4a8d6b94dfb4150fb9e3014
# Parent a227e9c42f2d17fb28082ad2451a03d4926505ba
Fix for bug1
diff --git a/file1 b/file1
--- a/file1
+++ b/file1
## -1,1 +1,1 ##
-This is file1
+a second line
# Resume working on patch2
$ hg qpush
applying patch2
now at: patch2
...
# Apply patch1 to repo
$ hg qpop
popping patch2
now at: patch1
$ hg qfinish -a
$ hg qseries
patch2
$ hg summary
parent: 1:ccd75363c8f4 tip
Fix for bug1
branch: default
commit: (clean)
update: (current)
mq: 1 unapplied
$ hg qpush
applying patch2
now at: patch2
Keep in mind that the Mercurial Queues is designed to manage an ordered list of patches where a later patch in a series may modify changes made by an earlier patch. If the projects you are working on involve parallel development on the same sets of files, MQ may not be the best tool to use. In that case, consider using Mercurial branches or Mercurial anonymous heads with or without bookmarks.

How do you check if a mercurial repo is in a clean state?

As a user, I usually use hg st to check the status of a repo, and verify that it is in a clean state, with no modified files.
Here I would like to do this programmatically. I know I can also use hg st for that, but the output is less than ideal for consumption by a computer program. Is there a better way to check whether a mercurial repo is in a clean state?
If you issue the hg identify --id command, it will suffix the ID with a + character when the repository has modified files. (Note: this flag does not report untracked files.)
If you grep the output of this command for the + character, you can use the exit status to determine whether there are modifications or no:
$ hg init
$ hg identify --id | grep --quiet + ; echo $?
1
$ touch a
$ hg identify --id | grep --quiet + ; echo $?
1
$ hg add a
$ hg identify --id | grep --quiet + ; echo $?
0
You should use hg summary:
$ hg init
$ echo blablabla > test.txt
$ hg summary
parent: -1:000000000000 tip (empty repository)
branch: default
commit: 1 unknown (clean)
update: (current)
Most major programming languages have HG APIs you can access.
This answer might be useful for other people searching this topic:
I agree to #SteveKayes comment above that hg status is a good command for programmatic consumption.
Here is an example how to use it in a bash script:
#!/bin/bash
set -e
cd /path/to/hg-repo
repo_status=`hg status | wc -l`
if [ $repo_status -ne 0 ]; then
echo "Repo is not clean"
else
echo "Repo is clean"
fi

logging mercurial transactions

this is a small addition to the previous script, and this time I would like to log details for the backup.
script /tmp/commit-push-log
# add all files to the repository
for REPOSITORY in $#
do
cd $REPOSITORY
# commit the changes
hg commit -A -m "Commit changes `date`"
# push the changes to the remote repository
if hg push
then
logger hg push completed without failure
else
logger hg push fails
fi
done
exit
cat /tmp/commit-push-log | logger
rm /tmp/commit-push-log
the problem is that i don't see any mercurial messages in the log. What can go wrong in my script?
You should not use static tmp filenames. Use mktemp, it's far safer.
You should cd "$REPOSITORY" instead of "cd $REPOSITORY" or things will get funny when REPOSITORY will contain any spaces or special characters.
You should not write automated commit comments. See here for the great article on this topic.
hg probably outputs errors to stderr. Use hg commit -A -m "$comment" 2>&1 and hg push 2>&1
my current version
for REPOSITORY in $#
do
# new temp file
OUTPUT_LOG=`tempfile`
echo -n > $OUTPUT_LOG
# checks whether $REPO is a repo
if [ ! -d $REPOSITORY/.hg ]; then
echo "Not a repository: $REPOSITORY"
exit 1;
fi
# change to that dir
cd "$REPOSITORY"
logger "Repository: $REPOSITORY"
# commit the changes
hg commit -A -m "Commit changes `date`" 2>&1 >> $OUTPUT_LOG
# push the changes to the remote repository
if hg push 2>&1 >> $OUTPUT_LOG
then
logger hg push completed without failure
else
logger hg push fails
exit 1;
fi
# log the contents and delete the tempfile
cat $OUTPUT_LOG | logger
rm -f $OUTLOG_LOG
done
exit 0