ananthakumaran / monky

Magit for Hg
http://ananthakumaran.in/monky/index.html
GNU General Public License v3.0
154 stars 30 forks source link

Add some support for staging/unstaging individual hunks #104

Open ncalexan opened 4 years ago

ncalexan commented 4 years ago

Right now, Monky is file-centric: staging and unstaging works at the level of files. Historically, this is appropriate: most Mercurial commands filter by files. But newer Mercurial commands support "interactive" modes which operate at finer grains: hunk by hunk and line by line. What can we do to support this in Monky? I expect this to be very technically intricate, but worth discussing.

Under the hood, Mercurial's interactive operations are managing patch files. There's no magic here, other than that they apply the patches slightly different than hg patch does. Monky could, with effort, manage staged and unstaged hunks. It would be challenging to accommodate true git-style staging, but even that might be possible with a little Mercurial extension magic and in-memory diffing.

So suppose we aimed lower: could we teach Monky to handle staged and unstaged hunks and drop everything on the floor in the case that the status buffer is refreshed? (And ignore changes to the working directory behind Monky's back.) Right now staging a file refreshes the status buffer, but that's for convenience rather than a real requirement (and is bad for performance, especially in large repositories).

I'm also experimenting with work-flows that use, say, ediff to apply hunks in sequence before running hg patch, etc.

ncalexan commented 4 years ago

85 is related. #91 might be related, although that might look like applying a patch to the working directory rather than to the repository.

Wilfred commented 4 years ago

I'm massively in favour of this :)

I don't have the time to build this myself, but if you fancy putting up a PR, I will support you as best I can.

ncalexan commented 4 years ago

I'm massively in favour of this :)

Great! At least you're in favour.

I don't have the time to build this myself, but if you fancy putting up a PR, I will support you as best I can.

It's very difficult: for small repositories, a viable approach might be to create a transient git repository and use the index there!

I have been vaguely thinking about a Mercurial plugin that:

That's basically what the git index does (except that git accounts for the index in all of its commands). That would allow monky to "manage the index patch hunk-by-hunk", which feels possible, but still leverage Mercurial for hg status, etc. Committing the index patch is then equivalent to hg apply.

This is not something I can seriously pursue at this time, but I'll circle back to it occasionally as I can. Perhaps something will be possible.

Demosthenexx commented 4 years ago

I'm using 'hg commit --interactive' for now. Hunk commits would be very useful, even on a single file level.

ncalexan commented 2 years ago

This probably isn't interesting to many people, but: I just shelved a commit that started experimenting with this with the commit message:

It's pretty clear that this can be made to work on the `monky` side.
On the Mercurial side, I'm fairly convinced that it's not viable.
Mercurial assumes that changes are coming from the working directory
and various efforts to bring changes in "from the side", i.e., from
patches with `files` not a subset of `status.modified` in the working
directory ran into problems.

I conclude that it's likely to be more fruitful to support
`--interactive` selection out of the box.  I'm thinking that we can
pop to an Emacs mode that is `crecord`-like for `hg commit -i`, and
perhaps even have a `crecord`-like interface within `monky` that is
used at commit time.  There are hard questions about what to do when
the working directory and `monky` diverge (is it possible that `hg
commit -i` handles a hand-edited patch creating an entirely new file?
I don't know and it seems unlikely) but for normal use this might Just
Work.

I'll keep poking at my index hg extension -- I'm by no means a Mercurial expert -- but I really feel like this approach (having Mercurial manage the index as a patch) is swimming against the current.

melutovich commented 10 months ago

@ncalexan Did you ever discuss this with the mercurial developers/existing extension writers?

Mekk commented 9 months ago

It seems much more mercurial-ish to me to make commit and amend it (possibly many times) before pushing, not to work on defining what is staged before committing. Especially with evolve extension (which improves hg amend and hg commit --amend and makes those commands much safer as successive versions are kept as hidden changesets).

So instead of working on patch, I would simply commit straight away whatever user selected, then apply further actions by amending this commit.

Mekk commented 9 months ago

Regarding „selected changes commit”, it probably makes sense to look at how TortoiseHG does that. See here, especially fragments with partials: https://foss.heptapod.net/mercurial/tortoisehg/thg/-/blob/branch/stable/tortoisehg/hgqt/commit.py (the --partials option is some thg extension, also implemented there https://foss.heptapod.net/mercurial/tortoisehg/thg/-/blob/branch/stable/tortoisehg/util/partialcommit.py )

(mayhaps devs could be persuaded to move this or similar feature to core mercurial or to publish this extension as independent tool, looks like thing which various GUIs would use)

melutovich commented 9 months ago

@ncalexan @Wilfred

Besides the above comments by Mekk there is a related mercurial list thread https://lists.mercurial-scm.org/pipermail/mercurial/2023-September/106330.html