pachanga
pachanga

Reputation: 3073

Mercurial "hg status" and relative paths

I'm using both mercurial and git for different projects and like them both. What I find a bit annoying about mercurial is that "hg status" shows paths relative to the repository root, not to the current directory(unlike git). Can this behaviour be tweaked somehow?

Upvotes: 31

Views: 8860

Answers (5)

muxator
muxator

Reputation: 357

The standard way that works since old mercurial versions (>= 1.1 from 2008) is:

hg status re:

which yields:

M ../contrib/buildrpm
M ../hg
M httprepo.py

Since mercurial 1.3 (2009) you can define an alias if you want:

[alias]
sst = status re:

This behaviour was finally documented in 3.4 (2015):

$ hg help status --verbose
[...]
- show changes in the working directory relative to the current directory
  (see 'hg help patterns' for more information):

    hg status re:

Since mercurial 4.2 (may 2017) you can tell the status command to always print relative paths putting this in your hgrc:

[commands]
status.relative = True

Testing directly on the command line (hg >= 4.2):

$ hg --config commands.status.relative=True status
M ../contrib/buildrpm
M ../hg
M httprepo.py

Finally, mercurial 4.3 introduced ui.tweakdefaults which, among other things, changes some defaults to more modern ones:

[ui]
# hg status prints relative paths
# hg diff produces patches in git format
tweakdefaults = True

If you are on a modern mercurial (>=4.3), this is the officially recommended way.

Upvotes: 7

Krazy Glew
Krazy Glew

Reputation: 7534

I am adding this answer not because it is better than the accepted answer, but because it clarifies the distinction between "hg status ." and "hg status $(hg root)". Which may have confused some commenters - worse, which may lead to forgetting to check in necessary stuff.

"hg status ." only reports status for the subtree underneath ., using relative paths.

"hg status $(hg root)" reports status for the entire repo, using paths relative to CWD.

Both are useful.

(In general, "hg status path" shows status for the subtree underneath path (the entire repo if path = $(hg root)", but relative to CWD. (I must admit that I find this confusing, because there are two things happening: subtree to get status on, and cwd to show paths relative to.))

This is shown by the example of a shell session embedded below.

$ bash [~/hack] 562 $> mcd hg-test
./hg-test
$ bash [~/hack/hg-test] 563 $> hg init .
$ bash [~/hack/hg-test] 564 $> mkdir subdir
$ bash [~/hack/hg-test] 565 $> touch foo
$ bash [~/hack/hg-test] 566 $> touch subdir/bar
$ bash [~/hack/hg-test] 567 $> hg status
? foo
? subdir/bar
$ bash [~/hack/hg-test] 552 $> hg status $(hg root)
? foo
? subdir/bar
$ bash [~/hack/hg-test] 552 $> cd subdir
./subdir
$ bash [~/hack/hg-test/subdir] 553 $> hg status
? foo
? subdir/bar
$ bash [~/hack/hg-test/subdir] 553 $> hg status .
? bar
$ bash [~/hack/hg-test/subdir] 513 $> hg status $(hg root)
? ../foo
? bar
$ bash [~/hack/hg-test/subdir] 523 $> hg status
? foo
? subdir/bar

Therefore, if you want do something like make a backup of files in the local subtree, without checking in, and then revert (I often need to do this when using "hg lock", because I am using FrameMaker files that cannot be diffed or merged within hg (or barely at all)):

$ bash [~/hack/hg-test/subdir] 523 $> mkdir bak; hg status -n . | xargs cp --target-directory bak
$ bash [~/hack/hg-test/subdir] 524 $> ls bak
bar

But if you want to back up all files in the tree that are reported by status

$ bash [~/hack/hg-test/subdir] 528 $> mkdir bak-root; hg status -n $(hg root) | xargs cp --target-directory bak-root
cp: will not overwrite just-created `bak-root/bar' with `bar'
$ bash [~/hack/hg-test/subdir] 529 $> ls bak-root
bar  foo

By the way, the warning shows the problems of colliding filenames. I usually use a little tool I have to add a .bak suffix, or xargs. But this example is sufficient.

BY the way^2, I usually do stuff like this with "hg status -nm", but the example above is sufficient.

Upvotes: 2

Louis Deflandre
Louis Deflandre

Reputation: 21

Hg is getting better with time : With hg 2.2.3, I can define st alias.

[alias]
st = !hg status $($HG root) $HG_ARGS

Consequently:

  • hg st will give you path relative to current directory
  • hg status will give you path relative to hg root directory

Upvotes: 2

richq
richq

Reputation: 56458

The usual workaround is to run:

hg status $(hg root)

For older versions of Mercurial, prior to 1.7, you could use this hack, adding to your repository's ".hg/hgrc" file:

[alias]
 sst = status /path/to/root

That needs the alias extension enabled, so you may have to add "alias=" to your ~/.hgrc file.

Starting with Mercurial 1.7, the alias extension learned about the "!" escape to use shell commands, so you can now have a global alias that does this:

[alias]
sst = !hg status $($HG root) $HG_ARGS

Don't use st = !hg status $(hg root), since that creates an infinite loop, running hg status over and over. It looks like a bug in the alias parsing - if you want to alias hg status to show the path from the root, then the following incantation works in the global $HOME/.hgrc:

[alias]
__mystatus = status
st = !hg __mystatus $($HG root) $HG_ARGS

Upvotes: 34

Giorgos Keramidas
Giorgos Keramidas

Reputation: 1848

To see workspace status relative to the current directory you can always use "." (a single dot) as the argument of "hg status", i.e.:

% hg root                   # root of the workspace
/work/foo

% pwd                       # current directory is <root>/src
/work/foo/src

% hg status                 # no argument, see all files
M etc/foo.conf              # all files are shown with paths
M src/foosetup.c            # relative to workspace root
%

The difference when you explicitly ask for the current working directory is that the relative filename paths use that as their starting point:

% hg status .               # see only files under current path
M foosetup.c
%

Upvotes: 36

Related Questions