0

I found two questions (asked by the same user) about whether it's possible to disable the staging area

None of the answers actually answered the question. They were all some flavour of

  • You should learn to love the staging area

  • Use commit -a instead

But what's the actual answer? Can I set a git option so that attempts to partially move changes to the staging area fail? I guess the answer is "no" because if it were "yes" someone would already have mentioned it on one of the above questions.

(For context, I commit with commit --patch and I see no need for the staging area.)

(EDIT: I want to know how to disable the staging area because I want my less experienced collaborators to be able to avoid interacting with this feature, in a tooling-enforced way. Git is already confusing enough for them. The staging area is an additional unnecessary complication.)

Tom Ellis
  • 9,224
  • 1
  • 29
  • 54
  • 1
    umm... yes, they already have an answer, which is rated at the top: https://stackoverflow.com/a/3834653/365237 - the answer is "No, there isn't". I don't think opening new questions on the same subject will change it. – eis Apr 11 '18 at 06:39
  • "Can I set a git option so that attempts to partially move changes to the staging area fail?" you could check in `pre-commit` hook that there are no unstaged changes, and fail to commit in case there are – max630 Apr 11 '18 at 06:42
  • @max630 that wouldn't prevent partially moving changes to the staging area, only committing such changes (like you probably know) – eis Apr 11 '18 at 06:43
  • @eis If that's really a definitive answer then fair enough, but given it's tied up with a moral exhortation to "learn to love it" it's rather ambiguous. – Tom Ellis Apr 11 '18 at 06:44
  • @max630 But I do want to be able to make commits whilst there are unstaged changes! – Tom Ellis Apr 11 '18 at 06:45
  • How exactly the staging area is preventing you from what you are dooing? – max630 Apr 11 '18 at 06:47
  • @TomEllis `git commit --only` skips the staging area, so might help you with that specific issue. – eis Apr 11 '18 at 06:49
  • @max630 I added an edit which hopefully explains my rationale – Tom Ellis Apr 11 '18 at 06:51
  • @eis I added an edit which explains my rationale. I want to disable a complex feature of the system to enable less experience users to have simpler interactions with in. – Tom Ellis Apr 11 '18 at 06:52
  • yes, and like explained, that is not supported by git. – eis Apr 11 '18 at 06:52
  • @eis Then it would be very helpful for someone to post that as an answer, preferably with an explanation for how they know that is the case. Then I can accept it. – Tom Ellis Apr 11 '18 at 06:55
  • 1
    I think you would be better off offering a bounty to existing thread if you want proof or further explanations, as they do ask the same thing. – eis Apr 11 '18 at 06:57
  • So do your collaborators also use `commit --patch`? And what exactly fails in that scenario? – max630 Apr 11 '18 at 07:01
  • @max630 I will suggest that they do. Nothing fails when they use `commit --patch`. What fails is when they use `add` and things go into the staging area. Then life is more confusing than necessary. – Tom Ellis Apr 11 '18 at 07:06

1 Answers1

4

No, this is not possible. Many people have made various attempts to hide or otherwise disguise Git's index aka cache aka staging area, and they all fail for one simple reason: Git actually makes new commits from whatever is in the index / staging-area.

This has several consequences, some of which are immediately all up in your grill and some of which hit you later, including these:

  1. The contents of your work-tree do not matter to Git, except as a place to go to get files to store into the index. You can mostly, but not entirely, work around this using git commit -a which has an effect that is very similar to running git add -u just before running git commit.

  2. A file is tracked if and only if it is present in the index. Tracked, untracked, and untracked-and-ignored status of files is literally impossible to explain without making note of the existence of the index, even if you otherwise mostly work around it using git commit -a.

  3. The git status command runs two comparisons: one from HEAD commit to the index, and one from the index to the work-tree. The only way to explain its output is to acknowledge the presence of the index.

  4. Eventually, if one chooses to do it, it's the index that stores partial changes using git add -p and the other patch-oriented operations (checkout -p and reset -p). Of course you can simply avoid these entirely; then you never see this aspect of the index.

  5. During a merge operation—a merge-as-a-verb, as I like to call it—that runs into a conflict, the conflicted state is recorded in the index. Git puts all three copies of the file-that-has-conflicts into the index. Each file in the index actually has four staging slots. At this point, the base version goes in slot 1, the HEAD or local or --ours version goes in slot 2, and the remote or other or --theirs version goes into slot 3. Resolving the conflict really means doing your own merge work, then copying the result into the normal staging-slot zero, wiping away the three higher-numbered staging entries.

Mercurial, which is otherwise very similar to Git, has no index / staging-area. This proves that the concept is possible. However, the way Mercurial achieves this is that it treats the work-tree as the proposed new commit, rather than having a separate index object that is the proposed new commit. Mercurial then has a second separate object called the manifest that determines which files are tracked. Merge state during conflicts is stored in a third location (the dircache). In one way this actually winds up being even more complicated, though it makes the usual case of working with Mercurial much simpler and more user-friendly.

To make Git work like Mercurial here, you would need to wrap every Git operation: hide the entire user interface and implementation from users, with some auxiliary state to keep track of why the index state is the way it is. Essentially, you would need to create your own manifest and dircache to remember which files to copy in and out of the index so as to make things look as though the work-tree were the proposed commit. You would need your own status wrapper, and you might even want to run in detached HEAD mode all the time (I have not thought enough about corner cases and, e.g., hg histedit equivalence here).

torek
  • 448,244
  • 59
  • 642
  • 775