Fossil Forum

"staging area"
Login

"staging area"

"staging area"

(1) By TomaszDrozdz on 2021-05-12 12:03:53 [link] [source]

In GIT I can put files into "staging area" before commit.
I found this particular feature useful especially when having a lots of changes in many files to commit.
Can we somehow imitate that feature in Fossil ?

(2) By Stephan Beal (stephan) on 2021-05-12 12:21:31 in reply to 1 [link] [source]

Can we somehow imitate that feature in Fossil ?

Not without significant changes to how fossil processes checkins. While we don't mind borrowing ideas from git when it makes sense (like the stash), i think it's fair to say that most of the active devs aren't impressed enough by git's staging area concept to feel compelled to overhaul fossil to be able to handle such a feature.

(4) By TomaszDrozdz on 2021-05-12 14:14:58 in reply to 2 [link] [source]

I even did not think for a second to ask for it :)
Just wandering how You deal with a lots of changed files that should be (but it is a mater of taste) checked-in in a few commits, not one.
Perhaps I could group files by adding them to "stash commit A", "stash commit B", and then unstash one "group", simply commit all files, then unstash another "group", ...

(5) By Andy Bradford (andybradford) on 2021-05-12 14:30:18 in reply to 4 [link] [source]

> Just wandering how  You deal with a lots of  changed files that should
> be (but it is a mater of taste) checked-in in a few commits, not one.

One person mentioned using separate checkout directories. I find that to
be great when working on separate  branches of code. But there's nothing
from  preventing  you  from  committing  a  subset  of  files,  or  even
committing one file  at a time. This doesn't really  make much sense for
compiled code,  or even  interpreted code,  but for  other repositories,
where  the files  may not  necessarily  share any  kind of  relationship
except being in the same repository, it might make sense.

If you  are working with  code that is  untested, it's probably  best to
make such commits on a branch.

In ten years of using Git, I've never onced use the staging area.

Andy

(13) By Warren Young (wyoung) on 2021-05-13 00:45:48 in reply to 5 [link] [source]

I frequently commit a subset of files by name or by subdirectory in several cases:

  • My ~/bin is version-controlled by Fossil. Each file in that directory is generally a standalone script, so I can safely commit changes to each one independently.

    Usually when I have multiple uncommitted changes to my ~/bin repo it's because I've forgotten to commit after each change. When I get around to doing a commit, Fossil informs me that the one file I thought I was committing a change to actually collects changes to, say, 3 files, so I abort the commit comment editor and go back and diff the repo, then commit each changed file separately having refreshed my memory of what I changed previously, so the commit messages talk about only one thing each.

  • Several of my Fossil-controlled projects have a support library shared by multiple programs within that project. If I've made a change to both the support library and one or more of the programs that use that library, it is often both safe and sensible to commit the change to the library separately from the commits to the programs using that library.

    This is especially the case when the change to the library is to either add a wholly new feature or to fix an obvious bug. Changes to pre-existing features generally have to be tested and committed as part of the change to the non-library code, since both change sets go hand-in-hand. A good razor for telling when this is the case is that the library code change also changes the library's test suite output, since that tells you that outside users of the library can tell that the library has changed behavior.

  • The project has multiple cooperating but independent programs, so if I change multiple programs in a single work session, I can safely commit each change set separately as fossil ci src/program1/ and such, since the changes effectively have been tested independently.

    (But just as true, if the work on two separate programs affects the interface between those programs, rather than internals within each so that one program's change can't work without the other, I will commit them together.)

(6) By Richard Hipp (drh) on 2021-05-12 14:36:06 in reply to 4 [link] [source]

Just wandering how You deal with a lots of changed files that should be (but it is a mater of taste) checked-in in a few commits, not one.

  1. If you have made changes to 10 files and you only check-in 4 of them, that probably means you have not tested your project with just those 4 changes and without the other 6. So you would be checking in untested code. Many projects consider that a big no-no.

  2. You can do check-in a subset of the changed file simply by naming the files you want to commit on the "fossil commit" command line.

  3. The staging area is a misfeature and interface design bug in Git. Fossil will not be replicating Git bugs.

(3) By ravbc on 2021-05-12 12:57:07 in reply to 1 [link] [source]

You could do it by yourself - just open a new checkout on the same commit and copy there files which you want to commit.

PS. git's staging area is IMHO a misfeature created probably as a workaround for its inability to open multiple checkouts from the same clone.

(7) By John Rouillard (rouilj) on 2021-05-12 15:59:44 in reply to 1 [link] [source]

I agree with all the above. I think the staging area is a misfeature that is useful only when you have multiple unrelated changes in your working directory. Committing partial untested code can come back to bite you when bisecting for example.

Having said that, have you looked at the fsl fossil wrapper? I think you can use it to create a new stage subcommand with options:

  stage add <files>
  stage remove <files>
  stage list <files>
  stage diff - diff staged files against the base commit
  stage empty (same as stage remove for all files)
Add .fossil-settings/fsl-stage to .fossil-settings/ignore-glob.

Store the paths to the staged files in fsl-stage.

Wrap the fossil commit command so that it uses the contents of fsl-stage if it exists. Then it commits using the file paths in fsl-stage to limit the commit to those files. If the commit succeeds, delete fsl-stage.

You could also wrap fossil status to report/mark files that are staged.

Then alias fossil to fsl and I think it could work.

Implementing interactive git stash would be very difficult. But check out the record and rstash commands in fsl. They allow you commit or stash parts of files. I find rstash useful if I have multiple changes in a file. I can rstash parts that aren't ready to commit, test/commit the rest and then stash pop the saved changes.

This allows me to untangle code and generate tested changesets to commit.

(8) By TomaszDrozdz on 2021-05-12 19:20:07 in reply to 7 [link] [source]

Thank you all for words of wisdom.
But "sometimes" writing code looks like this :-)

(10) By Marcelo Huerta (richieadler) on 2021-05-12 20:37:47 in reply to 8 [link] [source]

But "sometimes" writing code looks like this :-)

I'd say that's probably your problem and not Fossil's, would you not?

(12.3) By Warren Young (wyoung) on 2021-05-13 00:27:29 edited from 12.2 in reply to 8 [link] [source]

If you have to fix the car, take the fixed car to the store to get lubricant, lube the drawer slides, and repair the drawer support before you can change a light bulb, to take your analogy, then either:

  1. You've mismanaged yourself into a mess that you should probably fix before looking to Fossil for help; or

  2. You've got a weird one-off collection of independent problems that Fossil already provides plenty of mechanisms for handling.

For the second case:

Branches

The situation: you've found that the drawer squeaks when you're in the middle of working on the "light bulb" problem. Then:

$ fossil ci --branch light-bulb-feature \
            --comment 'initial work on light bulb feature'
$ fossil up trunk
$ vi src/drawer.c
$ fossil ci -m 'fixed squeaky drawer'
$ fossil up light-bulb-feature
$ fossil merge trunk
$ fossil ci -m 'merged trunk'
$ vi src/light-bulb.c

...and then you proceed to fix the drawer support, fix the car, and drive to the store to buy lubricant in the same fashion, merging each into the light-bulb-feature branch as each is completed so that when that branch is merged down to trunk, the diff for the merge commit shows only the light bulb feature work.

Stash

Similar to above, but using the stash:

$ fossil stash save -m 'light bulb change feature in progress'
$ vi src/drawer.c
$ fossil ci -m 'fixed squeaky drawer'
$ fossil stash pop
$ vi src/light-bulb.c

...and then you continue working on the "light bulb" feature until it's time to stash again because you've gotten distracted again.

Selective Commits

If you're certain your partial changes can be committed without being fully tested independently, then starting from the state where src/light-bulb.c has uncommitted changes at the time you get distracted:

$ vi src/drawer.c
$ fossil ci -m 'fixed squeaky drawer' src/drawer.c
$ vi src/light-bulb.c

Combo Plate

You can combine the previous two methods:

$ vi src/light-bulb.c src/workbench/*.c src/car/engine.c
$ fossil stash save src/light-bulb.c
$ fossil stash save src/workbench/drawer.c
$ fossil stash save src/workbench/carcass.c
...leaving only src/car/engine.c changed; test independently...
$ fossil ci -m 'repaired car engine'
$ fossil stash pop
...test workbench drawer support fix independently...
$ fossil ci -m 'repaired drawer support'

...and so on for the following 2 stash slots.

Tickets

If the problems you discover along the way toward replacing the light bulb are not blockers, then you can just file a Fossil ticket on each of them as you discover them, returning to each once you finish work on the light bulb.

To take the TV show clip's analogy, it is not actually necessary that you fix the workbench's drawer support, buy lubricant, lube the drawer slide, and fix the car engine before you can replace the light bulb. Only if you were also out of light bulbs and had no other way to get to the store than by driving would you be in such a sorry state, at which point you have a local resource management problem, not a software feature problem.

Selective Patching

If you've got a situation where individual parts of a changed file have to be committed separately, then install Patchouli and:

$ vi src/garage.c
$ fossil diff -i > my-life-is-a-mess.patch
$ patchouli my-life-is-a-mess.patch

$ patch -p0 < car-fix.patch
...test it separately...
$ fossil ci -m 'fixed car engine'

$ patch -p0 < drawer-support.patch
...test it separately...
$ fossil ci -m 'repaired broken drawer support'

$ patch -p0 < lubricant.patch
...test it separately...
$ fossil ci -m 'applied household lubricant to drawer slide'

$ patch -p0 < light-bulb.patch
...test it separately...
$ fossil ci -m 'replaced burned-out lightbulb'

...and then ask yourself why you have your "drawer" and "light bulb" material in a single garage.c file even though they clearly have little to do with each other, as exemplified by the very fact that you evidently can have multiple projects in progress within this single file independently. The existence of "garage" files in a project is generally a bad sign when either:

  1. It is the only file in the project, meaning that every change has to be made to that one file, making use of any of the other methods above needlessly difficult.

  2. It is not the one-and-only miscellaneous junk-drawer module that's rarely touched, since almost all code lives somewhere else that's better scoped.

(22) By anonymous on 2021-05-13 19:37:26 in reply to 12.3 [link] [source]

Thanks for the detailed reply Warren. I learned a thing or two.

For what it's worth the video seems to be describing a situation that git users would most likely recommend interactive patching to solve. Assuming that once you fixed the car you'd just want to commit that fix and begin "unwinding" git add -p would let you select just those changes and commit them leaving everything else uncommitted (and this doesn't even need the staging area). Patchouli seems like the most git-like solution (and a neat project I was unaware of).

As others have mentioned separate checkout directories is another option. Each task Hal starts is done in a different area completely. He isn't holding the lightbulb, drawer, etc when fixing the car.

mkdir -p myproject/trunk
cd myproject/lightbulb && fossil open ~/museum/myproject.fossil
vi src/lightbulb.c 
... notice the drawer needs fixed ...

mkdir ../drawer && cd ../drawer
fossil open ~/museum/myproject.fossil
vi src/drawer.c

I've found this method works well when supporting bug fixes in released versions while still working on new features. If I'm adding a feature and notice the light bulb needs to be fixed, my release probably needs the fix too. With multiple checkout directories I can quickly switch to that workspace and fix it there.

(9) By kak (kkugler) on 2021-05-12 20:33:43 in reply to 1 [link] [source]

Been a long time since I commented on anything here...

A couple years ago I made a VS Code Fossil extension that does have a "staging" area. There are notes in the extension that this is purely an artifact of the extension and only exists for the current VS Code session, and basically does what drh identifies in his response bullet point #2

Though I think git functionality you are actually looking to replicate is git add -p, which allows for staging specific changesets within a specified file? Does Fossil have something like that?

Since my company has moved to git I've noticed there is a huge emphasis on the "clean commit history" being engrained in the developers which I think is the reason why you have these staging areas and patch adds in git. Admittedly it does make code review easier for projects I am not as familiar with, but is definitely more time consuming.

(11) By sean (jungleboogie) on 2021-05-12 22:34:03 in reply to 9 [link] [source]

I was going to recommend this extension to the OP as a possible solution!

I don't mind your staging area, since it's just a button click away. And I usually just click it again to add it into what I want to commit. Thanks for creating the extension.

For the OP on using only Fossil, I think committing a single file or a group of files together is perfectly acceptable. I've actually done this very recently. Not because my changes were untested, but because they were unrelated to one other. I wanted my commit messages to make sense for the change I was committing and not be a list of unrelated changes just so I could get it in one commit.

I think there's a project that I'm using now that relies on the staging thing...or at least a similar functionality of git. I first have to commit the change, then push the change. It was quite confusing at first and I still don't understand the benefit of this model.

Please no staging in Fossil!

(14) By Andy Bradford (andybradford) on 2021-05-13 14:29:08 in reply to 11 [link] [source]

> Not because my changes were  untested, but because they were unrelated
> to one other.

Whenever I  have unrelated changes  I prefer  to keep them  separated by
using different  fossil checkout directories.  In this way, I  don't run
the risk of accidentally committing code. As an individual with flaws, I
don't always  follow my  own advice rigorously,  and have,  on occasion,
accidentally committed more than I wanted. :-)

Andy

(31.1) By Lifepillar (lifepillar) on 2021-05-14 07:40:02 edited from 31.0 in reply to 9 [link] [source]

Does Fossil have anything like [git add -p]?

No, but with the right tooling (basically, a good diffing tool), you can easily commit in chunks. See: Commit file in chunks

(15) By anonymous on 2021-05-13 16:38:38 in reply to 1 [link] [source]

Can we somehow imitate [Git staging] feature in Fossil ?

Misfeature, bug - it's strange to see here such harsh labels for clearly a productivity feature which arises from the workflow needs. Oh, well... a right tool for the right job.

As for emulating the staging with Fossil. The firstmost idea is to use private branch partial commits, then backout to base and merge (or cherrypick in order) from the private. You may scrub afterwards to remove the private branch for cleanliness.

Another way is patch-based - 'fossil diff -v' for the partial list of the files into a patch-file, then apply the patches in the needed order with 'patch -p 0'.

Also an idea to possibly consider is Fossil bundle, but I'm not very familiar with its use.

Stashing also could be of help, but it reverts the files, so it needs some adjustment.

Finally, oh sacriledge, use local Git just for the purpose. Create a temporary Git repo with only modified/deleted base files, redo adds, do the staging as needed. Once done, commit the whole tree in Fossil, or sequentially redo the Git partial commits in Fossil. Obviously, this gets very cumbersome without automation.

(16) By Stephan Beal (stephan) on 2021-05-13 16:52:50 in reply to 15 [link] [source]

Also an idea to possibly consider is Fossil bundle, but I'm not very familiar with its use.

A bundle is basically a way to move a branch or commit from one repository to another. i recently realized that a bundle can be used to "pop" the tip commit off of a repository (noting that the new tip can then be popped (noting that the new new tip can then be popped... ad nauseum)), via repeated application of the bundle export and bundle purge commands.

Stashing also could be of help, but it reverts the files, so it needs some adjustment.

See the difference between stash "save" vs "snapshot": fossil:/help/stash

Finally, oh sacriledge, use local Git just for the purpose. Create a temporary Git repo with only modified/deleted base files, redo adds, do the staging as needed. Once done, commit the whole tree in Fossil, or sequentially redo the Git partial commits in Fossil. Obviously, this gets very cumbersome without automation.

That's just crazy talk!

(17) By MBL (RoboManni) on 2021-05-13 18:18:48 in reply to 16 [link] [source]

fossil stash apply ID FILENAME...

That would probably help...but taking individual files out of stash is not yet possible

(18) By Richard Hipp (drh) on 2021-05-13 18:36:53 in reply to 15 [link] [source]

The staging area is a misfeature and bug because it forces you to think about it and increases the risk of errors even if you never use the staging area.

The staging area of Git does not provide any new capabilities. You can do a partial commit in Fossil, just as you can in Git, by specifying the names of those files or directories that you want to include in the commit on the commit command line. The default "fossil commit" commits everything. A "fossil commit FILE1 FILE2 ..." commits just the files or directories named.

But, a Git user does need to be aware of the Git staging area regardless of whether or not he or she ever uses the staging area. For the majority of people who never use the staging area, the staging area just becomes a stumbling block that increases the chance of errors and causes the user to have to think harder and be more cautious to avoid problems.

"no new capabilities" + "increased workload and error potential" = "misfeature"

(19) By anonymous on 2021-05-13 19:16:27 in reply to 18 [link] [source]

While I agree that the staging area is a misfeature and stumbling block it's use case is a bit different than specifying files to commit in that it can be used to track changes in the same file.

Consider a milestone on a feature that you don't quite want to commit to record for some reason:

vi file.c          # hack until a milestone has been reached
git add file.c     # save changes from the milestone in the staging area

# go out for a night on the town come back and hack some more
vi file.c

# sleep off the hangover

git diff --staged  # what did I do in the haze of last night?

In my humble opinion if the staging area is a must have feature then just use git otherwise OP can modify their workflow to fit fossil's paradigm (and probably learn workflow tweaks that they can adapt to git).

(The above scenario could probably solved with private branches fossil:/doc/trunk/www/private.wiki)

(20) By Warren Young (wyoung) on 2021-05-13 19:23:25 in reply to 19 [link] [source]

That looks a lot like

vi file.c
fossil stash snapshot         # not save!
# sleep it off
vi file.c
fossil stash diff

(21.1) By Richard Hipp (drh) on 2021-05-13 19:28:04 edited from 21.0 in reply to 20 [link] [source]

I was just about to say what Warren said. Except I was going to point out that you can (if you choose) stash just "file.c" and not all your changes. So the equivalent workflow would be:

vi file.c
fossil stash snapshot file.c
# night on the town
vi file.c
# sleep it off
fossil stash diff --tk

So, once again, the staging area provides no new capabilities, only a stumbling block.

(23) By anonymous on 2021-05-13 19:40:00 in reply to 21.1 [link] [source]

So, once again, the staging area provides no new capabilities, only a stumbling block.

Agreed. This shows there are multiple solutions. One only has to select their preferred method.

(25) By Scott Robison (sdr) on 2021-05-13 20:50:31 in reply to 21.1 [link] [source]

As I understand it, the one thing the git staging area does that isn't native to fossil is the ability to add just hunks of changes from a file. So if five lines have been changed, you can choose to add one, several, or all the modifications.

I do not like this feature and agree with the fossil philosophy that it is a misfeature in git. However, based on my understanding, it is a feature that isn't easily emulated by native fossil functionality.

(26) By Warren Young (wyoung) on 2021-05-13 21:47:46 in reply to 25 [link] [source]

My Patchouli solution up-thread provides this with minimal externalities, assuming you have Python installed already.

(27) By anonymous on 2021-05-13 21:49:59 in reply to 25 [link] [source]

I don't think the staging area is what's allowing you to add change hunks necessarily.

Couldn't git, in theory, allow you to select the hunks and then commit directly skipping the staging area?

(28) By Scott Robison (sdr) on 2021-05-14 01:49:21 in reply to 27 [link] [source]

It certainly could, but that's the model git uses. Regardless, I believe it is true that fossil doesn't natively support building a commit at the diff hunk level.

(29) By John Rouillard (rouilj) on 2021-05-14 01:58:07 in reply to 28 [link] [source]

Regardless, I believe it is true that fossil doesn't natively support building a commit at the diff hunk level.

For that you need to use fsl and record (to commit sections/diff hunks) or rstash (to stash sections/diff hunks).

(24) By anonymous on 2021-05-13 20:28:32 in reply to 18 [link] [source]

The staging area of Git does not provide any new capabilities.

I respect your opinion very much. However it has to be supplied with "...for the common workflow" qualifier.

Git from the beginning is practically fitted for intensive patch management, which involves often juggling diffs from similar or interrelated patches. The goal is to craft a commit out of several patches, sometimes multiple commits which could then be further resequenced, again into a trackable patch.

Staging area is helping in such patch management, as one can diff against the index, amend the staged changes. Basically, crafting the commit. Stash and rebase fit into that purpose too.

Additionally, the index helps with interactive patching (on an individual diff hunk level) and during merge progress, when dealing with conflicts.

All in all, Git is able to cater to a much more involved SCM workflow. As for the "interface bug", the minimal difference is the "commit -am" vs "commit -m" with Fossil.

Git index concept may be confusing for those who does not need it, does not want to learn about it or does not want to use it at all. So is the SCM concept as whole...

I still cannot convince quite knowledgeable and professional business folks to incorporate an SCM (either flavor) into their routine operations. Neither Git nor Fossil practically help managing Office files.

(30) By Andy Bradford (andybradford) on 2021-05-14 03:28:31 in reply to 18 [link] [source]

> a Git user does need to be aware of the Git staging area regardless of
> whether or not he or she ever uses the staging area.

Fortunately, or unfortunately  as the case may be, I  don't seem to have
felt the  need to  be aware of  the Git  staging area, or  if I  am, I'm
blissfully unaware. :-)

I always use:

"git commit -a"

or

"git commit <filename>"

I have  yet to use  "git add <filename>" except  when adding a  new file
into a Git  repository (because I don't  know of any other way  to get a
new file into Git). In this way, I think I've avoided the "staging area"
altogether, and any complications that might derive from it.

Andy

(32) By patmaddox on 2023-04-15 21:22:40 in reply to 1 [source]

I have done partial commits in git for years... it used to be one of my favorite features. But there was always something that bothered me about it - I was checking in a version of the code that I never thoroughly tested.

When I started using fossil, I tried the approach of multiple branches. I like that for parallel development, but not for staging commits.

It turns out there is a super simple VCS-agnostic approach to doing this.

  1. Copy your working files to ones with .final extension
  2. Edit working files to the desired state for your next commit
  3. Test; Commit
  4. Copy the .final back over the working files
  5. GOTO 2. You're done when the working file has the same contents as the .final

I never thought of this approach until I asked myself "how would I do this with fossil?"

It's a way simpler model than git's staging area, and allows for testing each stage.