Perform an empty commit with mercurial
Asked Answered
O

5

21

With with Mercurial queues extension, I can make an empty commit with some commit message like so:

hg qnew patch_name -m "message"

Is there a way to do this without Mercurial queues? I tried simply:

hg commit -m "message"

but hg just says "nothing changed" and doesn't do the commit, and I don't see any "force" option that would override that.

If you're wondering about my motivation for doing this: we have testing infrastructure where you push to a special repository and it will trigger automated tests to run. You need to put a special string into the commit message of the tipmost commit that says which tests to run. Obviously, I don't want this string in there when I push to the actual repository. Rather than amending the commit twice (once to add the special string, and a second time to remove it), I would find it cleaner to just add an empty commit, and then roll it back -- and I can do this with mq, but I'd like to find a way to do it without mq.

Orthogonal answered 30/8, 2013 at 21:23 Comment(0)
I
19

You can use hg commit --amend to create empty commits.

Just create an arbitrary commit and backout the change. Afterwards fold both commits together.

Example:

touch tmp                               # create dummy file
hg add tmp                              # add file and...
hg commit -m "tmp"                      # ... commit
hg rm tmp                               # remove the file again and ...
hg commit --amend -m "empty commit"     # ... commit
Infante answered 12/11, 2014 at 17:18 Comment(8)
Similar to hg commit --close-branch, this will not create a truly empty commit — it will still leave a marker in the changeset and create an amend backup bundle. However, I think it's better in that it doesn't have the potentially confusing effect of marking a branch as closed when it's intended to remain open.Transilient
This won't work if you have already pushed to a remote repositoryLance
@Lance Why not? As long as you don't push in between the two hg commit commands you are fine.Infante
That's what I said: if you have already pushed after the first commit you can't amend it.Lance
Oh I see, I hadn't understood the example. I thought you were suggesting to use an ammend alone.Lance
Ugly (should be in the interface), but it works. I needed this to mark the roleback point when I closed branch, on a linear set of commits, and had no real changes for now.Madelon
@richard agreed! But you can create an alias if you really need this more often by putting the following into your .hgrc file: [alias] emptycommit = !touch tmp ; $HG add tmp ; $HG commit -m "<enter commit message>" ; $HG rm tmp ; $HG commit --amend "$@"Infante
Improvement of @JosefEisl alias [alias] emptycommit = !touch tmp ; $HG add tmp ; $HG commit tmp -m "<enter commit message>" ; $HG rm tmp ; $HG commit tmp --amend "$@" Commits should target our tmp file, so that we do not commit changes (so it is always an empty commit).Madelon
P
8

In 2015 a patch to the mercurial-devel mailing list suggested adding an option to the commit command, called --allow-empty (much like the similar git option). However, it was decided to go with a configuration option instead.

This ended up being added in Mercurial 3.5 in 2015 July, by the name ui.allowemptycommit. One doesn't have to specify it in a user's or repo's configuration file however, it is sufficient to add a --config switch to a single command, like this:

hg ci -m "empty commit" --config ui.allowemptycommit=1

Additionally, in 2020 it was suggested for the hg rebase extension command to consider the value of another, experimental configuration option. It is named rewrite.empty-successor, and can be set to either skip (the default) or keep. The configuration option itself was introduced with Mercurial 5.5 in 2020 August, although I am not sure when the rebase extension started to consider it.

How it works seems to be that rebase reads the new option and then locally overrides the older ui.allowemptycommit option depending on whether rewrite.empty-successor is configured to skip or keep. The result is that the rebase extension of older Mercurial versions directly observes the ui.allowemptycommit=1 option (version 4.8.2 tested), while the newer versions' extension observes rewrite.empty-successor=keep instead (version 6.1 tested). The newer versions ignore the external state of the ui.allowemptycommit configuration.

Therefore to get hg rebase to keep empty changesets somewhat portably, both options can be set so as to keep them, like in this example:

hg rebase --config rewrite.empty-successor=keep --config ui.allowemptycommit=1 ...

My use case for all of this is to use hg convert on an svn repo, then use an empty hg commit to become the initial commit (local changeset number 0). Then I will use hg rebase first to make the soon-to-be changeset 0 the parent of the first imported svn revision (so it will become local changeset number 1, matching the svn revision number), and second to fix a certain problematic commit that hg convert doesn't parse correctly. It is crucial to me that the hg rebase commands should keep empty commits, such as those based on svn revisions which only changed directories. (Directories are never tracked by Mercurial on their own, only files.)

Preliminary answered 10/3, 2022 at 18:9 Comment(1)
If anyone is interested, here is the finished script. I actually have to fix the broken changeset first, as it would interfere with the rebase onto my changeset 0. I reported the broken changeset created by hg convert to the Mercurial bug tracker.Preliminary
B
5

You can make commit that's closing the branch:

hg commit --close-branch -m "message"

Update:

You can close branch once, but it can be reopened with another commit. Simplest way to reopen branch without changing files is to tag some revision. So you can use hg commit --close-branch for empty commit and then hg tag for reopening.

Update v2

Actually you can create new empty commits with just hg tag command. It has -m parameter for setting a commit message. If you don't really care about correctness of this tags, you can use just one tag name by calling hg tag with -f parameter:

hg tag t1 -f -m "message"
Buzzell answered 30/8, 2013 at 21:44 Comment(4)
Won't these operations pollute the history with branch closing and tag creation events?Orthogonal
Closing the branch won't pollute history. It will just add new changeset. Tag creation adds new changeset with specific commit message, but you can override it with -m parameter.Buzzell
Hey, you can actually just create new tags without closing the branch. If you don't care about tags but just a commit messages, you can even use just one tag and set it with -f flag. So, you can create empty commit with hg tag t1 -f -m "message".Buzzell
closing the branch or adding a tag is not a true empty commit.Rhynchocephalian
R
4

You can now create empty commits by just doing hg ci -m "empty commit"

e.g.

hg branch my-next-branch
hg ci -m "empty commit"

Will create a my-next-branch with a single empty commit that you can push to the remote repo.

Rhyne answered 11/10, 2018 at 3:27 Comment(1)
I've always been able to have an "empty" commit that does nothing more than make a branch. Suppose that I have made seven commits to the branch and then want to just add a new commit message without file changes. Should hg ci -m "empty commit" work in that case? I tried it and it didn't work. I don't know if I just have an older version or if it's because this sample makes a branch first, which I'm not doing in the scenario I described.Prate
M
1

I just found that hg graft . --force --edit works fine for that purpose.

This will force-graft the current checked-out commit, so it'll be empty, and it'll open an editor to enter a commit message.

Mayemayeda answered 14/4, 2022 at 12:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.