I have a master repo, which has some changes I do not want to commit.
I have a subrepo, which has changes that have already been committed.
I want to commit the changes subrepo revision in my master repo, without committing the changes to the files in the master repo.
I cannot seem to do this. I can't commit .hgsubstate, and making a trivial change to a file to commit that does not commit the subrepo changes to the master repo.
Pass the name of the subrepo itself to commit and Mercurial will update .hgsubstate and commit it.
ry4an#four:~$ hg init main
ry4an#four:~$ cd main
ry4an#four:~/main$ hg init sub
ry4an#four:~/main$ echo sub = sub > .hgsub
ry4an#four:~/main$ hg add .hgsub
ry4an#four:~/main$ hg commit
ry4an#four:~/main$ cd sub
ry4an#four:~/main/sub$ echo text > afile
ry4an#four:~/main/sub$ hg commit -Am first-in-sub
adding afile
ry4an#four:~/main/sub$ cd ..
ry4an#four:~/main$ hg status
ry4an#four:~/main$ echo text > dont-commit-me
ry4an#four:~/main$ hg add dont-commit-me
ry4an#four:~/main$ hg status
A dont-commit-me
ry4an#four:~/main$ cat .hgsubstate
0000000000000000000000000000000000000000 sub
ry4an#four:~/main$ hg commit -m 'subrepo only' sub
ry4an#four:~/main$ hg status
A dont-commit-me
ry4an#four:~/main$ cat .hgsubstate
dec5eaa9e22cd0a05cbba3ba02fdb0e1f243e07e sub
Note that the file in main dont-commit-me never got committed, but the .hgsubstate was updated.
Related
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
I have $HG_NODE referencing the changeset from which I wish to start:
[vcs#Quake /tmp/test/advanced]$ hg log -r $HG_NODE: --template '{node|short}:{files}\n'
c5eefea063fd:1.txt backup.cmd notes.txt
370f9ef91471:1.txt backup.cmd notes.txt
5eac12f79df6:advanced/Program.cs advanced/a advanced/b advanced/notes.txt lab6/scratch2/Fiobonacci.sln lab6/scratch2/Program.cs lab6/scratch2/xxx lab6/scratch2/yyy
4be96f43f327:advanced/1.txt
c724950dd2a6:advanced/Fiobonacci.csproj advanced/aaa.kuku
Now, I also have a directory, which is of a particular interest to me. So, I wish to get all the changesets from the starting one affecting the files in this directory.
First, I tried to check if I can get it for a specific file:
[vcs#Quake /tmp/test/advanced]$ hg log -r "$HG_NODE: and file('path:advanced/1.txt')" --template '{node|short}\n'
4be96f43f327
Then, for all the files in that directory. But I seem to be missing something:
[vcs#Quake /tmp/test/advanced]$ hg log -r "$HG_NODE: and file('path:advanced/**')" --template '{node|short}\n'
[vcs#Quake /tmp/test/advanced]$ hg log -r "$HG_NODE: and file('set:advanced/**')" --template '{node|short}\n'
abort: fileset expression with no context
[vcs#Quake /tmp/test/advanced]$ hg log -r "$HG_NODE: and file('glob:advanced/**')" --template '{node|short}\n'
[vcs#Quake /tmp/test/advanced]$ hg log -r "$HG_NODE: and file('advanced/**')" --template '{node|short}\n'
[vcs#Quake /tmp/test/advanced]$ hg log -r "$HG_NODE: and file('re:^advanced/.*')" --template '{node|short}\n'
5eac12f79df6
4be96f43f327
c724950dd2a6
Only the re: prefix works for me, but this is something that should work with glob: as well.
How can I make it work with glob: and ** ?
After a little playing, I think it's because you are already in the advanced directory. Try one of the following options (assuming this is the case):
1) Specify only that you want to match the files in this directory:
$ hg log -r "$HG_NODE: and file('glob:**')" --template '{node|short}\n'
5eac12f79df6
4be96f43f327
c724950dd2a6
2) Go to the parent directory:
$ cd ..
$ hg log -r "$HG_NODE: and file('glob:advanced/**')" --template '{node|short}\n'
5eac12f79df6
4be96f43f327
c724950dd2a6
3) Use the path option, but don't specify the /**:
$ hg log -r "$HG_NODE: and file('path:advanced')" --template '{node|short}\n'
5eac12f79df6
4be96f43f327
c724950dd2a6
These options all seem to work in my small test repo.
working directory
Did a
hg commit (resulted in rev3)
Copied some directories inside ... changed some files. Did
hg add
hg commit (resulted in rev4 - tip)
How to get back exactly to the state of rev3. hg update 3 will change the files to the state they were in rev3, but it will also leave all the copied directories inside. I want to get the working directory without the copied directories and files, which were added after rev3.
That doesn't happen for me:
> hg init
> mkdir first
> jed first/foo.txt
> hg add
adding first/foo.txt
> hg commit -m asd
> mkdir second
> jed second/foo.txt
> hg add
adding second/foo.txt
> hg commit -m asd
> hg update 0
Now first exists, but second doesn't...
Are you sure you added everything in the new directories before your commit?
Like Jon writes, Mercurial will normally try to clean up after itself. So when you hg update you should get back exactly what you committed. What I guess you're seeing is the following behavior:
$ hg init repo
$ cd repo
$ echo "# some C program" > foo.c
$ hg add foo.c
$ hg commit -m first
$ mkdir dir
$ echo "$ other C program" > dir/bar.c
$ hg add dir/bar.c
$ hg commit -m second
$ echo "object file" > dir/bar.o
$ hg update 0
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ ls
foo.c dir
$ ls dir
bar.o
So the untracked dir/bar.o file has been left behind, but the tracked dir/bar.c file has been correctly removed. That is: Mercurial wont delete untracked files since it doesn't know if they contain valuable data. This applies even if the files are ignored by a pattern in .hgignore. If the directory had only contained the tracked dir/bar.c file, then the directory would have been completely removed when you update to a revision where it isn't needed.
The normal way to clean up untracked files is to use the purge extension.
Turns out there is no hg qfold -a.
I tried hg qfold $(hg qunapp) and hg qunapp | xargs hg qfold but couldn't get it to work. Any ideas?
With your xargs approach, did you remember that qfold only folds unapplied patches into an applied patch? This worked for me (Windows) to fold all patches into the first patch:
hg qpop -a # remove all patches
hg qpush # apply first one
for /f %i in ('hg qunapplied') do hg qfold %i # fold remaining patches
Hmm... we could add a -a flag... But until we do, I would use the histedit or collapse extensions or maybe just do it myself:
$ hg update qparent
$ hg revert --all --rev qtip
$ hg commit -m 'Everything in one commit'
$ hg qpop -a
You then need to remove the patches -- perhaps you can just remove .hg/patches entirely, or you can delete some of them and edit .hg/patches/series to match.
hg qunapp | xargs -I'{}' hg qfold '{}'
In Mercurial it's possible to hg status only the modified/added/removed files by doing:
hg st -m
hg st -a
hg st -r
Is it possible to obtain the same behaviour for the diff command? From the man page, it seems not.
One option would be to use something like this:
hg status -mar --no-status | xargs hg diff
The --no-status flag insures that just the file name is sent to STDOUT.