Fossil Forum

Commit file in chunks
Login

Commit file in chunks

Commit file in chunks

(1.1) By Lifepillar (lifepillar) on 2018-12-31 15:31:19 edited from 1.0 [link] [source]

Coming from Git (cough cough), I got used to commit changes to a file in chunks. For instance, I may be editing a C function when I notice that a comment somewhere else in the file contains a typo, which I fix at once. Later on, I'd stage the change to the comment, commit, then stage the change to the function, and commit again.

AFAIK, Fossil's commit unit is a file. So, I am wondering how people deal with scenarios like the above. So far, I've come up with the following workflow:

  1. create a copy of the file containing the changes to be committed (e.g., cp foo.c foo.c~).

  2. Stash changes to foo.c (fossil stash save -m foo.c foo.c).

  3. Open both foo.c and foo.c~ with an editor and pick some changes from foo.c~ into foo.c (vimdiff works wonderfully for this). Commit foo.c.

  4. Iterate step 3 as long as there are changes to be committed.

  5. Unstash (fossil stash pop). This step may introduce conflicts, depending on which lines have been committed.

In the simple scenario described above, I could simplify the workflow by (1) stashing, (2) updating the comment, (3) committing, (4) unstashing, (5) keep editing the function. But the workflow addresses the more general situation (make changes and decide what to commit later).

Any better ideas? Any plan for Fossil to streamline this?

Edit: fix command syntax.

(2) By Florian Balmer (florian.balmer) on 2018-12-31 17:17:39 in reply to 1.1 [link] [source]

That's something I'd often find very handy. It also happens that the unrelated changes affect more than one simple typo in one single location.

I'm also using the fossil stash feature, but for more complex scenarios, I sometimes end up with manually splitting the (not yet committed) diff (copied to a text editor via clipboard with fossil diff | clip on Windows) into individual patches, and applying them one by one with the patch utility.

I haven't known about git stage, and my first thought was, that this might need some interactive mode, which indeed seems to be the case.

(3) By Stephan Beal (stephan) on 2018-12-31 17:37:24 in reply to 1.1 [link] [source]

i feel compelled to point out that the ability to commit a single part of a modified file encourages checking in code which cannot possibly have been tested for compilability. No compiler can have compiled just that change, without all others in the file, unless one blocks them all off using the C preprocessor or a similar tool.

(4) By Warren Young (wyoung) on 2018-12-31 18:30:30 in reply to 3 [link] [source]

A solution to both this problem and the OP's is fossil stash apply/pop --incremental:

  1. On first run, it presents each chunk of the diff and asks whether to apply it or not.

  2. Build, test, and check the cherrypicked diff chunks as you would with any other checkin.

  3. Run fossil stash pop --incremental again. On subsequent runs, it checks whether each chunk is already applied and silently skips past it if so. If the newest stash contained a 3-chunk diff and only one chunk was selected in step 1, it would only ask about the remaining two.

  4. When the last chunk is selected, if this is "pop," not "apply," actually pop the stash.

If the user edits a diff chunk, such as because step 2 showed that it doesn't apply cleanly or pass tests in isolation, the scheme above will cause it to be continually offered for selection, and if the user says "yes," it'll cause a merge conflict. That's fine for "version 1.0" of this feature, but we can refine it later. Fossil already knows how to detect merge conflicts, so it can offer more choices: remove chunk from stash, apply anyway creating merge-conflicted lines in target file, or apply to original baseline.

The value of the last option might not be clear. If the original three stashed chunks all work correctly together, but some subset needs to be modified to allow a clean checkin, when it comes time to do the final stash apply/pop step, we want the original stash to be applied to the baseline it was made against, not against the current checkout. It'll still get checked in against the current branch tip, but the diff will partially revert some of the earlier checkin work so that the whole stash applies cleanly.

All that's needed for all of this is someone to have this itch bad enough to scratch it.

That's not me, because I've taken the current situation as motivation to clarify my thinking, so that I now see situations like this developing in advance. I then do one of several tricks to work around the lack of such a feature:

  1. Stash the work I've got so far, do the tangential thing, then pop the stash and continue my original line of development.

  2. Check what I've got so far in as the start of a new short-lived feature branch, go back to trunk, do the tangential thing there, return to the branch, finish work on it, and merge it down to trunk. If the work on trunk affects the behavior of my temporary feature branch, I'll merge trunk up into the branch at one or more points along the path toward finishing the branch. My rule for short-lived branches is that only the final checkin before merge needs to actually work.

  3. I keep a scratch checkout directory alongside the trunk checkout. In the OP's example, I could cd ../scratch, fossil up trunk, fix the comment, check it in, cd -, fossil up, and continue work.

Because I've developed these tricks and work habits, I probably wouldn't actually use incremental stash application much if I had it!

If someone wants to do this, the UI can be arbitrarily spiffy. A sensible path would be to start with a portable ISO C interaction loop, then enhance it to make use of EDITOR/PAGER if available locally, much like is done in freebsd-update. Once that's done, someone can create a custom Curses UI when Fossil's built on a system where that's available and TERM is set.

(5) By Lifepillar (lifepillar) on 2018-12-31 18:57:32 in reply to 4 [source]

I see that there is also fossil stash gdiff. So, my workflow can be simplified as follows:

  1. fossil stash save -m foo foo.c

  2. fossil stash gdiff (this opens vimdiff in my environment), pick up changes, quit vimdiff, commit. Repeat.

  3. fossil stash pop.

It's a bit annoying that I have to quit the diff program to commit each chunk, but the database is locked as long as fossil stash gdiff is running. Compared to my original workflow, at least now I don't have to manually create and delete temporary files. Of course, if your diff program is just a viewer, the above is of no use. For me, this might be good enough, and it might help me getting out of the arguably bad habit of committing in chunks while still giving me the possibility of doing that when I really need to.

(6) By Florian Balmer (florian.balmer) on 2018-12-31 19:17:34 in reply to 4 [link] [source]

Thank you everybody for the interesting comments.

It seems that fossil stash gdiff with the WinMerge utility is the way to go, for me. Much better than manually splitting the patches.

The last good thing I've learned in 2018 ... Happy New Year!

(7) By MBL (RoboManni) on 2023-04-16 11:41:43 in reply to 4 [link] [source]

Hello Warren, you wrote about

fossil stash apply/pop --incremental

but when I looked for such an option I could not find any. Where can I find the description of such an option?

The --incremental option seems to exist in fossil only with the import command.

(8) By Warren Young (wyoung) on 2023-04-16 12:47:48 in reply to 7 [link] [source]

It’s merely an idea I’ve brought up multiple times. Someone should write it. :)

(10) By mark on 2023-05-03 03:32:32 in reply to 7 [link] [source]

fossil stash apply/pop --incremental but when I looked for such an option I could not find any. Where can I find the description of such an option?

There is no incremental/interactive stash like Git provides in Fossil proper. It is, however, available in third-party tools that can be found on Fossil's User Links page. I suspect there may be other such tools that work with Fossil and provide this feature. If you are aware of any, please let us know so we can add them to the page.

I think all the following provide interactive stash in some capacity:

This specific feature was one of the primary drivers behind developing fnc. As someone coming from git before git provided work trees, my workflow relied on this feature; it still does! I suspect it's a common pattern for other developers too. When I first wrote fnc, I proposed integrating it into Fossil, but as Stephan rightly replied, we don't want to introduce a curses dependency. I still have plans to add the interactive stash feature to fossil without the curses aspect, though, so hopefully when time permits developing a prototype, it might still be supported in Fossil sometime soon :)


As another workaround that I have not yet tried, if you keep a git mirror of your fossil projects, you could copy the changed files in your fossil work tree to your git work tree, run interactive stash as needed to split them into reasonable commits, then apply diffs of the git commits to the fossil repository. Then you can drop the commits from the git mirror before exporting the fossil repo again.

(9) By Alfred M. Szmidt (ams) on 2023-05-02 19:54:04 in reply to 1.1 [link] [source]

This should not be part of a VCS system (IMNSHO!); it can be entirely separate. Decades ago, I wrote diff-commit-hunk (https://tumbleweed.nu/r/ams/file?name=diff-commit-hunk.el&ci=tip), a small hack for GNU Emacs that basically addresses this though in Emacs specific terms. It works for anything from GIT to RCS to CVS to Mercurial, since it uses a agnostic VC interface .. that being said -- this could be modified easily to accommodate the case of "staged" commits in Fossil.