How is the SCM Command generated by Jenkins - mercurial

I have mercurial repository, and by providing the URL to Jenkins, i get the following in stdout:
Started by an SCM change
[workspace] $ hg incoming --quiet --bundle hg.bundle --template "{desc|xmlescape}{file_adds|stringify|xmlescape}{file_dels|stringify|xmlescape}{files|stringify|xmlescape}{parents}\n" --rev default
[workspace] $ hg unbundle hg.bundle
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
(run 'hg update' to get a working copy)
[workspace] $ hg update --clean --rev default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
[workspace] $ hg log --rev . --template {node}
No emails were triggered.
Question is HOW are these commands generated and can they be modified ?

Those commands are part of the Mercurial Jenkins plugin, with the source code available at GitHub.
You can find the incoming command used in the hudson.plugins.mercurial.MercurialSCM.java class in the update() method.
os.write("<changesets>\n".getBytes());
ArgumentListBuilder args = findHgExe(build, listener, false);
args.add(forest ? "fincoming" : "incoming", "--quiet");
if (!forest) {
args.add("--bundle", "hg.bundle");
}
args.add("--template", MercurialChangeSet.CHANGELOG_TEMPLATE);
args.add("--rev", getBranch(env));

Related

Mercurial commands equivalency

I am trying to find out if the following Mercurial commands are equivalent (beside the additional + in id -i output if the directory is has modified files): hg id -i and hg log -l1 --template "{node|short}". Are they or are they not?
The purpose is to potentially speed up some automation not needing to execute the id -i and use {node|short} in the log template instead. They seem equivalent but I'd rather if somebody else took a look as well before I proceed.
They're equivalent under certain conditions. log -l 1 gives you the first revision when all revisions are ordered from tip ("newest") to 0. hg id tells you what you currently have checked out. So if you've not checked out tip (say you've checked out a branch org a specific revision) you'll get entirely different output:
ry4an#four:~/projects/mercurial-crew$ hg log -l1 --template "{node|short}\n"
7eda5bb9ec8f
ry4an#four:~/projects/mercurial-crew$ hg id -i
824f7b3545c1
If, however, you've checked out tip (and you have no modified files) then they're identical (except for log not providing a newline without \n):
ry4an#four:~/projects/mercurial-crew$ hg checkout tip
4 files updated, 0 files merged, 0 files removed, 0 files unresolved
ry4an#four:~/projects/mercurial-crew$ hg id -i
7eda5bb9ec8f
ry4an#four:~/projects/mercurial-crew$ hg log -l1 --template "{node|short}\n"
7eda5bb9ec8f
They're not the same, because hg id defaults to examining the work-tree, and:
$ hg merge side
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg id -i
eb51a3480d0c+62e318575165+
if you're in the middle of merging, the work-tree has two parents and hg id prints both of them.
Meanwhile, hg log defaults to looking at the current (oops, thanks to Ry4an Brase) tip commit (rather than the work-tree); {node | short} prints its ID:
$ hg log -l1 --template '{node|short}'
eb51a3480d0c
On the other hand, if you're not in the middle of a merge, the work-tree has only one parent. You can also specify the revision ., which is the current commit ... so in that case, they are effectively the same.

How to add a hook for post bookmark activation

I use a bookmark based development approach and have various scripts written to help me do this. I'd like to run one of these scripts after updating to a new bookmark. I've added an update hook, but this seems to run before the bookmark has been changed:
$ hg update new-bookmark
$ <SCRIPT RUNS>
$ (activating bookmark new-bookmark)
How do I add a hook which will run after the current bookmark has been updated?
Your testing just wrong. update-hooks performed after new changeset become active
Test-case
>hg log -T "{rev}:{node|short}\n"
2:e37c7be131f2
1:ef24a87ada3d
0:a8219c43c17e
Hooks section of repo's .hgrc
[hooks]
update.UpHook = echo Update hook: && hg id -in
preupdate.preUpHook = echo PreUpdate hook: && hg id -in
Testing
>hg id -in
a8219c43c17e 0
>hg up 2
PreUpdate hook:
a8219c43c17e 0
Update hook:
e37c7be131f2 2
1 files updated, 0 files merged, 0 files removed, 0 files unresolved

Mercurial: roll back an "hg commit --amend".

I accidentally did a "hg commit --amend" instead of just a commit. How can I roll back the commit to before the amend?
You can use hg reflog (from the journal extension) and hg reset <hash>.
hg reflog -v
should give something like:
<old-hash> -> <new-hash> <user> <timestamp> commit --amend <some-path>
if that is the amend you want to revert, just use:
hg reset <old-hash>
The commit will be reverted to what is previously was and the changes that were amended should now be uncommitted changes (check using hg status and hg diff).
If your version of Mercurial is new enough, I believe you should be able to use the hg unamend command from the uncommit extension that ships with Mercurial. This may require that obsolescence markers are enabled, I'm not sure.
Enable the uncommit extension, add this to your ~/.hgrc:
[extensions]
uncommit =
Actually run the unamend:
hg unamend
Find the latest saved backup in .hg/strip-backup directory
hg unbundle .hg/strip-backup/<latest backup>
Now you should have two heads - one with the amended commit, other one with two commits (first one - old commit before amending, second one caled: "temporary amend commit for (old commit hash)".
if you have histedit extension, you can do hg histedit on it in order to change it (e.g. select edit in order to achieve a state just before the commit, i.e. when you can see all changes using hg diff).
Don't forget to strip the old head.
It's 2022, and my attempts to use hg unamend have not worked. histedit is too clunky for my purposes, but the solution proposed by mariu52 elsewhere on this page can easily be adapted to work without histedit. It relies on the -k option of the strip subcommand.
In a nutshell:
Find the latest saved backup in the .hg/strip-backup/ directory
Run hg unbundle .hg/strip-backup/<latest backup> where <latest backup> signifies the full filename.
Run hg heads and note the rev number corresponding to the amendment.
Let's call this $AMENDREV; this is the rev number we will strip in the next step.
Run hg strip -k --rev $AMENDREV
Using the -k option in the strip command is critical.
WARNING: this procedure will in effect erase the memory of any add or remove commands
that were pending when the amend command was executed.
For example, in the transcript below, the hg add file2 command is effectively
forgotten after the strip command is executed.
For clarity, here's a transcript based on the above recipe.
$ mkdir tmp ; cd tmp
$ ls
$ echo 1 > file1
$ echo 2 > file2
$ hg init
$ ls
file1 file2
$ hg add file1
$ hg commit -m 'one file'
$ hg add file2
$ hg amend -m 'amendment'
saved backup bundle to /tmp/tmp/.hg/strip-backup/d332ee829c21-5a5f23b0-amend.hg
$ hg unbundle -u .hg/strip-backup/d332ee829c21-5a5f23b0-amend.hg
adding changesets
adding manifests
adding file changes
added 1 changesets with 0 changes to 1 files (+1 heads)
new changesets d332ee829c21 (1 drafts)
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
updated to "1a445f3252eb: amendment"
1 other heads for branch "default"
$ hg heads
1[tip]:-1 d332ee829c21 2022-11-09 01:55 -0500 peak
one file
0 1a445f3252eb 2022-11-09 01:55 -0500 peak
amendment
$ ls
file1 file2
$ hg strip -k -r 0
saved backup bundle to /tmp/tmp/.hg/strip-backup/1a445f3252eb-bfaab5ec-backup.hg
$ ls
file1 file2
$ hg list
r0: peak tip 2022-11-09 01:55 -0500
one file
file1
$
hg unamend part of Mercurial 4.5 (2018-02-01).
NOTE: This answer is now deprecated. See the answer from #Sorina Sandu instead.
See hg help commit, where it says:
The --amend flag can be used to amend the parent of the working
directory with a new commit that contains the changes in the parent in
addition to those currently reported by "hg status", if there are any.
The old commit is stored in a backup bundle in ".hg/strip-backup" (see
"hg help bundle" and "hg help unbundle" on how to restore it).

Mercurial deleted a untracked file

In our repository we have initial version of database (binary file).
I have executed hg pull and I saw that someone committed another version of this file.
As I won't to loose my changes in dev db, I did make a copy of it (copy file.db my_file.db) in same directory.
When I runned hg up, mercurial overwrited file.db with new version and deleted my_file.db!
I'm on windows 7 x64, and tried various software that recover deleted files, but with no success.
How can I get back my version of file.db or recover my_file.db? I didn't commit it.
I really don't think mercurial deleted your untracked file. Here's the sequence you've described as I understand it:
ry4an#four:~$ mkdir zote
ry4an#four:~$ cd zote
ry4an#four:~/zote$ hg init orig
ry4an#four:~/zote$ echo text > orig/file.db
ry4an#four:~/zote$ hg -R orig commit -A -m 'initial'
adding file.db
ry4an#four:~/zote$ hg clone orig clone
updating to branch default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
ry4an#four:~/zote$ mv clone/file.db clone/my_file.db
ry4an#four:~/zote$ echo more text >> orig/file.db
ry4an#four:~/zote$ hg -R orig commit -m 'new line'
ry4an#four:~/zote$ hg -R clone pull
pulling from /home/ry4an/zote/orig
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
(run 'hg update' to get a working copy)
ry4an#four:~/zote$ hg -R clone update
remote changed file.db which local deleted
use (c)hanged version or leave (d)eleted? c
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
ry4an#four:~/zote$ ls clone/
file.db my_file.db
ry4an#four:~/zote$ cat clone/my_file.db
text
ry4an#four:~/zote$ hg -R clone status
? my_file.db
You can see that afterward my_file.db is still there. Even with --clean as Mikezx6r mentiones the file is still there:
pulling from /home/ry4an/zote/orig
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
(run 'hg update' to get a working copy)
ry4an#four:~/zote/clone$ hg update --clean
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
ry4an#four:~/zote/clone$ ls -l
total 8
-rw-r--r-- 1 ry4an ry4an 15 2011-02-08 14:31 file.db
-rw-r--r-- 1 ry4an ry4an 5 2011-02-08 14:28 my_file.db
ry4an#four:~/zote/clone$ hg stat
? my_file.db
ry4an#four:~/zote/clone$
It's not what you want to hear, but it's much more likely you accidentally botched the 'mv' and only thought you created the copy or somehow externally deleted it. Or your antivirus app saw a pattern it didn't like a refused to create it, or some other horrible, accidental thing.
It's also not helpful now, but this is a great example of why you should commit early and often, and especially before updating -- it's just too easy to make mistakes, but once something in in the repo there's nothing you can do to accidentally remove it.

Making mercurial subrepositories behave like subversion externals

The FAQ, and hginit.com have been really useful for helping me make the transition from svn to hg.
However, when it comes to using Hg's subrepository feature in the manner of subversion's externals, I've tried everythign and cannot replicate the nice behavior of svn externals.
Here's the simplest example of what I want to do:
Init "lib" repository
This repository is never to be used as a standalone; it's always included by main
repositories, as a sub-repository.
Init one or more including repositories
To keep the example simple, I'll "init" a repository called "main"
Have "main" include "lib" as a subrepository
Importantly -- AND HERE'S WHAT I CAN'T GET TO WORK:
When I modify a file inside of "main/lib", and I push the modification,
then that change gets pushed to the "lib" repository -- NOT to a copy
inside of "main".
Command lines speak louder than words. I've tried so many variations on this theme, but here's the gist. If someone can reply, in command lines, I'll be forever grateful!
1. Init "lib" repository
$ cd /home/moi/hgrepos ## Where I'm storing my hg repositories, on my main server
$ hg init lib
$ echo "foo" > lib/lib.txt
$ hg add lib
$ hg ci -A -m "Init lib" lib
2. Init "main" repository, and include "lib" as a subrepos
$ cd /home/moi/hgrepos
$ hg init main
$ echo "foo" > main/main.txt
$ hg add main
$ cd main
$ hg clone ../lib lib
$ echo "lib=lib" > .hgsub
$ hg ci -A -m "Init main" .
This all works fine, but when I make a clone of the "main" repository, and make local
modifications to files in "main/lib", and push them, the changes get pushed to "main/lib",
NOT to "lib".
IN COMMAND-LINE-ESE, THIS IS THE PROBLEM:
$ /home/moi/hg-test
$ hg clone ssh://moi#www.moi.com/hgrepos/lib lib
$ hg clone ssh://moi#www.moi.com/hgrepos/main main
$ cd main
$ echo foo >> lib/lib.txt
$ hg st
M lib.txt
$ hg com -m "Modified lib.txt, from inside the main repos" lib.txt
$ hg push
pushing to ssh://moi#www.moi.com/hgrepos/main/lib
That last line of output from hg shows the problem.
It shows that I've made a modification to a COPY of a file in lib, NOT to a file in the lib repository. If this were working as I'd like it to work, the push would be to hgrepos/lib, NOT to hgrepos/main/lib. I.e., I would see:
$ hg push
pushing to ssh://moi#www.moi.com/hgrepos/lib
IF YOU CAN ANSWER THIS IN TERMS
OF COMMAND LINES RATHER THAN IN ENGLISH,
I WILL BE ETERNALLY GRATEFUL!
Thank you in advance!
Emily in Portland
The problem is with your .hgsub file. It points to where the lib repo is, so if lib is a sibling to main it should be:
lib=../lib
Also your hg add lib and hg add main lines don't make sense. To what repo outside of main and lib are those being added? You're running them while in in /home/moi/hgrepos.
Here's your script with some tweaks:
+ cd /home/ry4an/hgtest
+ hg init lib
+ echo foo
+ cd lib
+ hg commit -A -m Init lib
adding lib.txt
+ cd /home/ry4an/hgtest
+ hg init main
+ echo foo
+ cd main
+ echo lib=../lib
+ hg clone ../lib
destination directory: lib
updating to branch default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ hg add .hgsub main.txt
+ hg commit -m Init main: initial file and a .hgsub
committing subrepository lib
+ cd /home/ry4an/hgtest
+ hg clone main main-clone
updating to branch default
pulling subrepo lib
requesting all changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ cd main-clone
+ echo foo
+ hg commit -m Modified lib.txt, from inside the main repos
committing subrepository lib
+ hg push
pushing to /home/ry4an/hgtest/main
pushing subrepo lib
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
To do that over ssh:// you need only make a single change. When cloning the main repo change hg clone main main-clone to hg clone ssh://host/hgtest/main main-clone -- cloning the main automatically clones the lib -- that's the subrepo benefit.
Here's a log of that working:
+ cd /home/ry4an/hgtest
+ hg init lib
+ echo foo
+ cd lib
+ hg commit -A -m Init lib
adding lib.txt
+ cd /home/ry4an/hgtest
+ hg init main
+ echo foo
+ cd main
+ echo lib=../lib
+ hg clone ../lib
destination directory: lib
updating to branch default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ hg add .hgsub main.txt
+ hg commit -m Init main: initial file and a .hgsub
committing subrepository lib
+ cd /home/ry4an/hgtest
+ hg clone ssh://localhost/hgtest/main main-clone
The authenticity of host 'localhost (::1)' can't be established.
RSA key fingerprint is 0c:58:d6:d3:d3:16:14:ee:3b:be:01:bc:c7:3c:92:0b.
Are you sure you want to continue connecting (yes/no)? yes
ry4an#localhost's password:
requesting all changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 3 changes to 3 files
updating to branch default
pulling subrepo lib
ry4an#localhost's password:
requesting all changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
remote: Warning: Permanently added 'localhost' (RSA) to the list of known hosts.
+ cd main-clone
+ echo foo
+ hg commit -m Modified lib.txt, from inside the main repos
committing subrepository lib
+ hg push
ry4an#localhost's password:
pushing to ssh://localhost/hgtest/main
pushing subrepo lib
ry4an#localhost's password:
searching for changes
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 1 changes to 1 files
searching for changes
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 1 changes to 1 files
Oops, sorry for the formatting in previous answer. Here it is again, formatted!
So, here are the two scenarios most folks will be faced with:
A) Using subrepositories in a completely local situation.
This is Ryan's solution, essentially.
I imagine only developers working solo will be in this boat.
cd /home/moi/hgrepos
hg init lib
cd lib
echo foo > lib.txt
hg ci -A -m Init
cd /home/moi/hgrepos
hg init main
cd main
echo foo > main.txt
echo lib = ../lib > .hgsub
hg clone ../lib
hg add .hgsub main.txt
hg ci -m Init
cd /home/moi/hgrepos
hg clone main main-clone
cd main-clone/lib
echo "Modified while on main trunk" >>lib.txt
hg commit -m "Modified lib.txt, while on main trunk"
hg push
cd /home/moi/hgrepos/lib
hg update
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
cat lib.txt
foo
Modified while on main trunk
-----------------------------------------------------------------
B) Using subrepositories over ssh.
I imagine most developers working on teams will be in this boat.
1) Set up lib
cd /home/moi/hgrepos
hg init lib
cd lib
echo foo > lib.txt
hg ci -A -m Init
2) Set up main
cd /home/moi/hgrepos
hg init main
cd main
echo foo > main.txt
echo lib=ssh://moi#www.moi.com/hgrepos/lib > .hgsub
hg clone ssh://moi#www.moi.com/hgrepos/lib lib
hg add .hgsub main.txt
hg ci -m Init
3) Clone lib to hgtest dir
cd /home/moi/hgtest
hg clone ssh://moi#www.moi.com/hgrepos/lib lib
4) Clone main to hgtest dir
cd /home/moi/hgtest
hg clone ssh://moi#www.moi.com/hgrepos/main main
5) Modify lib.txt while on main trunk
cd /home/moi/hgtest/main/lib
echo "Modified while on main trunk" >>lib.txt
hg commit -m "Modified lib.txt, while on main trunk"
hg push
6) Verify that lib.txt got changed in the lib repository
cd /home/moi/hgtest/lib
hg pull
hg update
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
cat lib.txt
foo
Modified while on main trunk