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.
Related
I want a simple command to get the list of files which differ after pushing to a mercurial repository on a server,
that is the differences between the previous push and the current push.
On the server, I have a hook on the changegroup event which calls a bash script.
$HG_NODE is the revision for the first commit in the changegroup.
My attempts:
hg status --rev $HG_NODE::
Exclude changes made in the first commit
hg status --rev $HG_NODE^1::
Includes changes that affected the parent revision through others pushes.
hg log -v --rev $HG_NODE:: | grep ^files
Include committed then reverted changes, still has 'files:' and files are not one per line
hg status --rev $HG_NODE:: && hg status change --rev $HG_NODE
Does not give exactly what I want, rather the change between the parent to the first commit in the changegroup + the change between this one (instead of the two changesets merged)
hg status --rev some_tag ; hg tag --remove some_tag ; hg tag --local some_tag
(Have not tried, is it a good idea?) Uses a local tag to keep track of the head for the last push, updates it each time.
Also I want to only monitor the default branch, so I assume I will use something like --rev "revision and branch(default)" or the branch option for hg log.
As to why, I need to go through the changes to determine parameters for an automated build.
hg stat -r is to list the removed files. To get the list of files which differ, you should use hg st --rev as follows.
hg st -m --rev tip^:tip
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).
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
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
I need to know what files have been added/modified/removed between two revisions. What I do:
hg status --rev 10:11
It looks okay. But when I have only one revision (initial = 0) it doesn't work.
# not work
hg status --rev 0:0
# also not work as I want
hg status --rev 0
There is no revision -1.
The special revision null is used to indicate the parent of revision 0. You can use
hg status --rev null:0
to see the changes in the first revision.
hg status --change [rev]
ie,
hg status --change 0
and
hg log -v
You might want to look at the output of hg log -v. For each changeset, it should list the files modified in that changeset. If you had a particular changeset in mind, add the -r switch to specify it.