How can I keep some modifications from propagating in mercurial?

冷暖自知 提交于 2019-12-06 11:41:19

From your comments, it looks like you are already familiar with the best practice for dealing with this: version a configuration template, and keep the actual configuration unversioned.

But since you aren't happy with that solution, here is another one you can try:

Mercurial 2.1 introduced the concept of Phases. The phase is changeset metadata marking it as "secret", "draft" or "public". Normally this metadata is used and manipulated automatically by mercurial and its extensions without the user needing to be aware of it.

However, if you made a changeset 1234 which you never want to push to other repositories, you can enforce this by manually marking it as secret like this:

hg phase --force --secret -r 1234

If you then try to push to another repository, it will be ignored with this warning:

pushing to http://example.com/some/other/repository
searching for changes
no changes found (ignored 1 secret changesets)

This solution allows you to

  1. version the local configuration changes
  2. prevent those changes from being pushed accidentally
  3. merge your local changes with other changes which you pull in

The big downside is of course that you cannot push changes which you made on top of this secret changeset (because that would push the secret changeset along). You'll have to rebase any such changes before you can push them.

If the problem with a versioned template and an unversioned local copy is that changes to the template don't make it into the local copies, how about modifying your app to use an unversioned localconfig.ini and fallback to a versioned config.ini for missing parameters. This way new default parameters can be added to config.ini and be propagated into your app.

Having followed up on the suggestions here, I came to the conclusion that named branches plus rebase provide a simple and reliable solution. I've been using the following method for some time now and it works very well. Basically, the history around the local changes is separated into named branches which can be easily rearranged with rebase.

I use a branch local for configuration information. When all my repos support Phases, I'll mark the local branch secret; but the method works without it. local depends on default, but default does not depend on local so it can be pushed independently (with hg push -r default). Here's how it works:

  1. Suppose the main line of development is in the default branch. (You could have more branches; this is for concreteness). There is a master (stable) repo that does not contain passwords etc.:

    ---o--o--o   (default)
    
  2. In each deployed (non-development) clone, I create a branch local and commit all local state to it.

    ...o--o--o   (default)
              \
               L--L    (local)
    
  3. Updates from upstream will always be in default. Whenever I pull updates, I merge them into local (n is a sequence of new updates):

    ...o--o--o--n--n    (default)
              \     \
               L--L--N     (local)
    

    The local branch tracks the evolution of default, and I can still return to old configurations if something goes wrong.

  4. On the development server, I start with the same set-up: a local branch with config settings as above. This will never be pushed. But at the tip of local I create a third branch, dev. This is where new development happens.

    ...o--o   (default)
           \
            L--L    (local)
                \
                 d--d--d     (dev)
    
  5. When I am ready to publish some features to the main repository, I first rebase the entire dev branch onto the tip of default:

    hg rebase --source "min(branch('dev'))" --dest default --detach
    

    The previous tree becomes:

    ...o--o--d--d--d   (default)
           \
            L--L    (local)
    

    The rebased changesets now belong to branch default. (With feature branches, add --keepbranches to the rebase command to retain the branch name). The new features no longer have any ancestors in local, and I can publish them with push -r default without dragging along the local revisions. (Never merge from local into default; only the other way around). If you forget to say -r default when pushing, no problem: Your push gets rejected since it would add a new head.

  6. On the development server, I merge the rebased revs into local as if I'd just pulled them:

    ...o--o--d--d--d   (default)
           \        \
            L--L-----N    (local)
    
  7. I can now create a new dev branch on top of local, and continue development.

This has the benefits that I can develop on a version-controlled, configured setup; that I don't need to mess with patches; that previous configuration stages remain in the history (if my webserver stops working after an update, I can update back to a configured version); and that I only rebase once, when I'm ready to publish changes. The rebasing and subsequent merge might lead to conflicts if a revision conflicts with local configuration changes; but if that's going to happen, it's better if they occur when merge facilities can help resolve them.

1 Mercurial have (follow-up to comments) selective (string-based) commit - see Record Extension

2 Local changes inside versioned public files can be easy received with MQ Extension (I do it for site-configs all time). Your headache with MQ

Every time I want to commit a regular changeset to the local repo, I need to pop all patches, commit the modifications, and re-apply the patches. When I'm ready to push to the master repo, I must again pop the patches, push, and re-apply them.

is a result of not polished workflow and (some) misinterpretation. If you want commit without MQ-patches - don't do it by hand. Add alias for commit, which qop -all + commit and use this new command only. And when you push, you may don't worry about MQ-state - you push changesets from repo, not WC state. Local repo can also be protected without alias by pre-commit hook checking content.

3 You can try LocalBranches extension, where your local changes stored inside local branches (and merge branches on changes) - I found this way more troublesome, compared to MQ

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!