Mercurial: How to keep some files unchanged after merge? - mercurial

I need to pull changes from one branch to another, but keep some files unchanged.
For example:
> hg up -C production
...
> hg merge feature-branch
...
> hg st
M file1
M file2
M file3
R file4
...
Is there a way to keep file2 unchanged and file4 not deleted, and then commit?
Using hg transplant is inappropriate in my case because there're too many commits to find what exactly to transplant.

$ hg revert -r . file2 file4
This reverts both files to how they were in the first parent of your working directory (.).

Related

How can I list all (new) added files between two change sets in mercurial?

How can I list all (new) added files between two change sets in mercurial?
I can use hg status --rev x:y to get all changes between two revisions, but what if I only want to get the new files?
hg help revsets + hg help templates for hg log -r … -T … command
"x::y"
A DAG range, meaning all changesets that are descendants of x and ancestors of y,
including x and y themselves.
Good correct range
file_adds
List of strings. Files added by this changeset
Keyword for template
>hg log -T {file_adds}\n
file3.txt file4.txt
file2.txt
file1.txt
(last changeset added 2 files)
>hg log -T "{file_adds % '{file}\n'}"
file3.txt
file4.txt
file2.txt
file1.txt
with just added formatting of list

Hg: how to get diff of two different files?

I'm sorry if it's odd question. I have a mercurial repository. Is it possible to get a diff of two different files from some revision by hg? For example, there is a revision
revision xxx
- file1
- file2
How I can get a diff of file1 and file2 by standard hg command or any extensions?
Thank you.
UPD
I would like something like this:
hg diff -r xxx file1 file2
Than I will have all changes between two files of same revision.
Initially I read your question differently, but your comment made clear that you are asking about the differences between two files of the same revision. That's nothing where the VCS has any stakes in.
You simply can use (on *nix systems) the diff command:
diff FILE1 FILE2
If you need the difference of the files at particular revisions, of course you can use mercurial before that in order to get to that:
hg update -rXXX
or even to see the difference of FILE1 at revision XXX compared to FILE2 at revision YYY (but beware, it changes the working dir content; make sure to undo the revert afterwards):
hg revert -rXXX FILE1
hg revert -rYYY FILE2
diff FILE1 FILE2

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: "undoing" two or more commits

In How do I do a pristine checkout with mercurial? Martin Geisler discuss how to remove already Mercurial commit'ed files using:
hg strip "outgoing()"
But what if I I want to keep my added files which went into "outgoing()" - example:
Two users a and b — starting on the same changeset
User a:
echo "A" > A.txt; hg ci -M -m ""; hg push
User b (forgets to run hg pull -u):
echo "B" > B.txt; hg ci -M -m "" B.txt;
echo "C" > C.txt; hg ci -M -m "" C.txt;
If user b run hg strip "outgoing()" then B.txt and C.txt are lost. hg rollback is not an option since there are two commits.
Can user b revert his files as "locally added - nontracked", then do hg pull -u, which gets A.txt, then handle the add/commit/push for B.txt and C.txt later?
Martin Geisler answered this earlier in the mentioned thread (a comment which I deleted and moved here:
hg update "p1(min(outgoing()))"
hg revert --all --rev tip
hg strip "outgoing()"
hg pull -u
Now user c can finalize his work in the new files B.txt and C.txt and commit+push those.
Other ways to do this?
You could but, by doing so, you are working against one of the biggest features of a DVCS like mercurial, that is, to easily and reliably handle the merging of multiple lines of development as in your case. If user b's goal is to have a line of development with all three changes applied, then the standard way to do that in hg would be to just go ahead and do an hg pull -u which will create a new head containing the change(s) from user a (and any other changes pushed to repo used for pulling) and then use hg merge to merge the two heads, the head containing user b's two change sets and the other containing user a's change set (as pulled). In a simple case like this one with no overlapping changes, hg should do all the right things by default.
$ hg pull -u
[...]
added 1 changesets with 1 changes to 1 files (+1 heads)
not updating: crosses branches (merge branches or update --check to force update)
$ hg merge
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg ci -m "merge"
If there were conflicts between the two heads (i.e. both users committed changes to the same files), there might need to be conflict resolution editing as part of the merge; hg will tell you if that is the case.
Another option is the rebase extension. With your scenario:
A and B start with the same history.
A commits and pushs a change.
B commits two changes, but can't push because of A's commit.
B pulls A's change.
B runs hg rebase and pushes.
Before rebase:
Common ---------------------------- A (tip)
\
B1 - B2 (working parent)
After:
Common - A - B1 - B2 (tip, working parent)

TortoiseHg not deleting files on update + clean

I performed these steps:
Commited my project
Added a couple class files to my project
Decided I wanted to completely abandon what I had just done
Used TortoiseHg Repository Explorer to Update to last changeset with "Discard local changes, no backup (-C/--clean)" checked/turned on
The two class files I added did not get deleted as I would have expected. They appear in the folder without shell icons.
Questions
Is this correct behavior or a bug?
If this is correct, is there a feature that will allow me to go back to a previous changeset without ending up with a bunch of junk files in my working copy?
Even if you hg add the files, if you haven't committed them, when you update it leaves the files as unknown files. Example:
C:\> md test
C:\> cd test
C:\test> hg init
C:\test> echo >file1
C:\test> hg ci -Am file1
adding file1
C:\test> echo >file2
C:\test> echo >file3
C:\test> hg add
adding file2
adding file3
C:\test> hg st
A file2
A file3
C:\test> hg update -C
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
C:\test> hg st
? file2
? file3
If you enable the purge extension, then hg purge will delete files with ? status. Be careful because files you meant to add to your project but haven't yet will be deleted:
C:\test> hg add file2
C:\test> hg status
A file2
? file3
C:\test> hg purge
C:\test> hg status
A file2
If you don't have added the files to you repository, I think they are not at all under version control. That will also mean they are left alone by the version control system, and you'll have to delete them yourself if you want them to be deleted.
Only if you have actually put them under version control (added them to the repository), you will have to revert your changes, or explicitly delete them from you repository.
The reason for this is of course that you may need some files in your project directory that you don't want to be in your version control repository at all.
Use hg update null on your working folder. Check the docs.