Mercurial: Easy way to see changes from last commit - mercurial

In Mercurial, I can see my current (uncommitted) changes by running
$ hg diff
Fine. But after commit, I sometimes want to see this diff again (i.e., the diff of the last changeset). I know I can achieve this by
$ hg log -l 1
changeset: 1234
tag ...
$ hg diff -c 1234
I'm looking for a way to do this in one line.

Use hg diff -c tip, or hg tip -p (shorter, but works only for tip).
This will work until you pull something, since tip is an alias for the most recent revision to appear in the repo, either by local commit or
pull/push from remote repositories.

You can use relative revision numbers for the --change option:
hg diff -c -1
See https://stackoverflow.com/a/3547662/239247 for more info.

An alternative is to use: hg diff --rev -2:-1
This form has the advantage that it can be used with the status command (e.g. hg st --rev -2:-1), and using it makes it easy to remember what to do when one needs to determine differences between other revision pairs (e.g. hg diff --rev 0:tip).

The answer from Macke is quite helpful, but in my case I didn't want to diff tip.
Thankfully you can also just diff the currently selected comment:
hg diff -c .

Related

Diff after committing locally

I just cloned a repo from their remote.
I built the software, changed about 4 files, committed them locally and now want to create a patch that I can show them.
When I run :
hg diff -U8p abc efg pqr > patch_file
I don't see the changes I made. Does hg diff only compare the current files with the last committed files?
How do I get this to work?
To diff the working directory against a particular revision REV, use
hg diff -r REV
To compare two revisions against each other, use
hg diff -r REV1 -r REV2
To figure out which revisions to compare, examine the output of hg log. If you'll be doing this a lot and the base revision is fixed, give it a name (e.g., whatipulled) with
hg tag -r REV whatipulled
You can then specify whatipulled as the revision, instead of a numeric rev id (or a hash).
To export your diffs in a richer format, including commit comments etc., you can also use the following which is designed for this purpose:
hg export -r REV
There's also hg bundle -r REV, which produces a binary file with similar information.
But if you're sending changes back to the parent repo, the best method is to use hg push. It communicates your changesets directly to the parent; you don't even need to know which changesets need pushing. Of course, you must have the right to push to the parent repo.
hg push [ parent_repo_url ]
(If you pulled from it, mercurial should already know the path and you can leave it out).
If the parent repo is on bitbucket and you don't have pu, you can set up your own account on bitbucket, pull/push to that from your local repo, and then issue a "pull request" to the project repo, asking them to pull from you.
All of the above have options to control their behavior, which see.
From hg help diff
If only one revision is specified then that revision is compared to the working directory
In your diff for -r you must to use old tip (latest "not your" changeset) and update to tip (your latest changeset) before diffing.
If some binary data was modified in your changesets, don't forget to use -g option
hg up & hg diff -r <CSET> -g > some.patch
Improved diff for any active changeset and without hand-work for detecting base changeset (for linear history == in single branch)
hg diff -r "parent(min(outgoing()))" -r tip
By default, hg diff compares the currently checked out file with the last commit. You can change this by adding options:
-r REV compares the currently checked out files with a specific revision REV.
-c REV shows the changes made by revision REV
So in your case hg diff -c 123 ... would give you the diff for commit 123.
My guess is that hg outgoing is exactly what you want -- it compares what you've committed locally with what is at the default remote server and shows you a list of those changesets or with -p the commits.
That does, however, shows each changeset separately. If you want to see all the changes combined, you'd have to do hg diff -r HERE -r THERE or since -r HERE is a default, hg diff -r THERE
I see you've asked in a comment "How do I know what THERE is", where THERE is the last changeset remote has, and you can get that answer by doing hg outgoing. If hg outgoing shows it would send changesets 66, 67, and 68, then you want to do hg diff -r 65 to compare what's already there (65) with what's local (68).

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

Generating patches in Mercurial

I've looked for that in the manual, but I can't generate a patch for the last commit.
I tried
hg qnew patch_name
but it does only file with
# HG changeset patch
# Parent a6a8e225d16ff5970a8926ee8d24272a1c099f9c
I also tried
hg export tip
but it doesn't do anything. I committed the changes exactly.
How to generate a patch file with the last commit in?
The command to do this is export:
$ hg export -o FILE -r REV
It doesn't require redirection and will thus work correctly on any platform/shell.
Your hg export tip is the best way to do it, and the hg diff and hg log based answers are just lesser versions of the same. What exactly do you see/get when you type hg export tip? What does the output of hg log -p -r tip show?
The changeset tip is just means "the changeset that most recently arrived in my repository" which isn't as useful a concept as you might think, since hg pull and hg tag all create changesets too. If you really want the last thing you committed you'll need a more precise revspec.
Like so:
hg diff -r tip > tip.patch
You can use this command:
hg log -r tip -p > tip.patch
this will generate a patch for just that revision.
If you want to convert the latest commit to a patch file, use
hg qimport -r tip
This will replace the topmost regular commit with an applied MQ patch file.
To generate patches using "mq extensions" in mercurial, you can follow the below given steps. This will create a patch using mercurial:
1) Enabling mq extensions: Add the following lines to your hgrc file and save it.
[extensions]
mq =
2) Creating a patch using mq extensions: To create a patch using mq extensions you can do the following.
hg qnew -e -m "comment you want to enter" bug_name.patch
In the above command, -e flag is for editing the patch and -m flag is for adding a message to the patch.
3) Updating the patch: For updating the patch, you can use the following command when a patch is already applied.
hg qrefresh

In Mercurial how do I extract a single file's changes from a Changeset to apply to another branch?

I have a large commit of many files on one branch, I need to transfer the modifications of a single file in that changeset to another branch. How can I do this? I am mostly using TortoiseHg but commandline solutions are also fine.
If I go to the changeset in TortoiseHg and select the file I can see the diffs I want to transfer, but not a way to actually apply them.
You can get the patch for just that file using:
hg log -r THEREVISIONWITHLOTSOFCHANGES -p -I path/to/justthatfile > justthatfile.patch
which you can then import on whatever branch you want by doing:
hg update anotherbranch
hg import --no-commit justthatfile.patch
hg commit
The most basic solution is to dump the patch of the file, apply it to the current working revision, and commit it (assuming you're at the root of the repository):
$ hg up <revision-to-apply-the-patch-to>
$ hg diff -c <revision-containing-the-patch> <files-to-include> | patch -p0
$ hg ci -m "Transplanting selected changes from <revision-contain...>"
The drawback of this method is that it isn't very obvious what you've done from a revision history perspective. A good commit message helps here, but the history graph gives no hint about the process of transplanting some changes. In that case merging and reverting may be a better solution:
$ hg up <revision-to-apply-the-patch-to>
$ hg merge -r <revision-containing-the-patch>
$ hg revert --no-backup <files-to-exclude>
$ hg ci -m "Merge in changes of <files-to-include>"
Probably there are more solutions to do this -- these two came to my mind first.

Using Mercurial, how to diff with a fixed revision if commit intermediate states often?

Using Mercurial, say if I do an hg pull and hg up and now the local repo and working directory are both up to date.
What if I commit often, say 1 day later, and then 2 days later, and want to diff with the revision as of right now?
Otherwise, the diff is always comparing to the previous committed version.
I can use pencil and paper and write down the revision number right now, say, 4117, and then 1 day later, 2 days later, and any time before I am sure and push to the remote central repo, do an
hg vdiff -r 4117
(either using vdiff or diff). But instead of remembering this "magic number" 4117, is there a way to make Mercurial somehow remember this number? That way, hg vdiff is to see the difference between minor changes against committed code, but there is a diff that shows all changes before pushing to the remote repo.
(or, if there is command that shows the revision number since your last pull, which should also show 4117, so on bash we can do something like hg vdiff -r `hg --what-is-last-pull` )
Update: does hg out --patch show the diff of what would be pushed to the remote repo? If so, maybe it serves the purpose without caring the "magic number". But how to show the patch diff using kdiff3 or any other diff tools? Also, it seems we can do hg out and if we see 4118, 4119, 4120, then we know if we do hg vdiff -r ___ we should use (4118 - 1) which is 4117.
Update 2: actually, hg out --patch shows the diff between local repo and the remote repo, so it is close, but not exactly the same as the diff between working directory and the local or remote repo.
If you want to mark a revision you can use bookmarks extensions. It is shipped with mercurial. Documentationis available here
In your case,
hg pull -u
hg bookmarks lastpull
..hack..hack..
hg ci -m new-hack
hg diff -r lastpull:tip
hg bookmarks -d lastpull
Do it with multiple clones. When you clone from the remote repo initially use clone -U to create a clone that has no working directory files at all. Then clone again locally, for example:
$ hg clone my-local-clone-with-no-working-files my-working-clone
Do your commits and work in my-working-clone and then at any time you can check the tip in my-local-clone-with-no-working-files to see what the last thing you pulled from the server was. If you want to get fancy you could create a shell alias for:
hg diff -r $(hg -R $(hg root)/../my-local-clone-with-no-working-files id -i -r tip)
which will compare the working directory of the repo in which you run it (my-working-clone) with the tip of whatever you last pulled from the server.
It's worth nothing that this takes no extra disk space because local clones use hardlinks under the covers the the my-local-clone-with-no-working-files has no working directory files.
You can replace pen and paper with a local tag: hg tag -l -r <revision number on paper> tagname. Notice the -l, which makes the tag local, which means it does not get transferred by push and pull. You can also remove this tag by hg tag -l --remove tagname.