-3

Having to constantly re-stage files that are already staged after every edit is wasting my time. I already staged the file once. Forgetting to re-stage the file means changes necessary may not get committed.

Educational statements regarding how git works with changes and not files needs to also come with information on how to stage a change (without naming a file) that does not require a lengthy CLI instruction. AFAICT git add needs file names or the like.

EDIT: This is not a duplicate of the nominated question, as I dont want to have to do something (running any CLI command, clicking a button, etc.) after every already staged file edit, or even just once before commit. Im asking if there is a way to configure the behavior of git (.gitattribute, etc) in this regard so it always behaves the way I need it to. I want to deal with Files when it comes to commits, because Files are what I'm editing and what are depicted as the changelist in just about every common tool.

StingyJack
  • 19,041
  • 10
  • 63
  • 122
  • 1
    "git works with changes and not files" No, it works with files. – matt Dec 04 '20 at 15:31
  • `git add -u` re-adds every already staged file to take any new changes into account. No effect on non-staged files. – Romain Valeri Dec 04 '20 at 15:32
  • 1
    `git commit -a` picks up all staged changed files as if you had added them. – matt Dec 04 '20 at 15:33
  • 1
    Does this answer your question? [Refresh staged files](https://stackoverflow.com/questions/10006462/refresh-staged-files) – underscore_d Dec 04 '20 at 15:36
  • https://stackoverflow.com/a/6840337/7976758 – phd Dec 04 '20 at 17:48
  • @matt - if git worked with files and not changes (like TFVC for example), then i would not have the problem I'm having. – StingyJack Dec 04 '20 at 19:03
  • @phd - there are unstaged files with edits that I dont want to commit (like local dev configuration files, etc) – StingyJack Dec 04 '20 at 19:03
  • @underscore_d - i edited the question to include clarification – StingyJack Dec 04 '20 at 19:05
  • From https://stackoverflow.com/help/dont-ask — "avoid asking subjective questions where … your question is just a rant in disguise: “______ sucks, am I right?” That's this. I assure you that the way the staging area works does not suck. It _is_ Git. The rule is simple: _you_ are responsible for constructing the next commit. Absolutely nothing is going to be committed automatically or by any other sort of magic. It's as simple as that. It's not a bug, it's a feature — one of the _primary_ features of Git. – matt Dec 04 '20 at 23:14
  • 1
    There are plenty of ways around "I committed but then it turned out there were more changes in one file that I forgot to commit"; for instance, it is easy to amend the commit you just made, or squash a new commit with the previous one(s). There are ways to say "Please make sure you have incorporated into the staging area all changes to all stages files." There are even ways to commit without bothering to add first. But these are all things _you_ must do. Nothing will happen by itself. And that's _good._ – matt Dec 04 '20 at 23:16
  • @matt - if it was a rant against git, that would be clear. I didnt say anything about "suck" in the question or compare it to something else, i asked "this behavior is wasting time, is there a way to short circuit it?" What I dont want as answers is stuff like "Git is a beautiful wonderful thing and works like so..." which undoubtedly accompanies questions about tools that have very enthusiastic followings but are ultimately useless as answers. Despite that part of the request, it still happened with the first answer given. =/ – StingyJack Dec 07 '20 at 15:00
  • @matt - and I think you miss my point. I dont want to avoid staging files. I just dont want to have to stage a file that is already staged and has changes. Compilers and other tools work with the file as it sits on the disk, they dont inspect git status to just get the file changes that are staged and work on those. Git does not recognize that reality and makes me do additional work, bending me into a behavior pattern that creates risk of missed changes. – StingyJack Dec 07 '20 at 15:08
  • Perhaps it has already been brought up but.... why do you add stuff every single step of the way? _normally_ waiting until it's time to commit to add files works very well (there are some use cases where you might want to add before that time.... but certainly every time you edit a file is not a good use case... as you can attest, I'm sure). – eftshift0 Dec 07 '20 at 15:29
  • I dont after every edit, but I do appreciate a clear view of my changes and not a split list. Most of the time I have this problem when I'm looking over my changes before I commit them. I'll spot something that I missed or that needs to be done, make the change and retest (if necessary), then have to restage the file. When I have 20-30 files changed (fixing ill-named types or other larger refactorings), having to do this restage is onerous. Most recently another dev needed some of my changes so i had to commit and push a subset, and keeping stage/unstage correct was a real pain. – StingyJack Dec 07 '20 at 17:31

3 Answers3

2

If what you're asking is whether you can use git add to add a file and then have all subsequent changes made to that file automatically included in the next commit, then no, Git doesn't have that functionality built in.

However, you can write an alias to do this and use it instead of git commit:

[alias]
ci = "!f() { git status --porcelain | grep '^[AMD]' | cut -b4- | xargs git commit \"$@\" --; }; f"

You can then run git ci and it will automatically commit all the changes to any staged file.

But outside of an alias, this isn't possible without some external tool. The way this is working is intentional, even if it's not to your liking.

bk2204
  • 64,793
  • 6
  • 84
  • 100
  • Wouldn't it be simplier to build an alias over `commit -a` ? – Obsidian Dec 04 '20 at 22:23
  • 1
    But I don't believe that's what the OP is asking for. Otherwise, they could just use `git commit -a` without a problem. – bk2204 Dec 04 '20 at 22:32
  • Right but he believes from the beginning that `commit -a` should be the standard behavour (mostly because he didn't get the point of Git, imho) so he assumes there's forcibly a way to set up this once and for all. This is what used to exist on CVS or such but if we've migrated to something else, it was for a reason… – Obsidian Dec 04 '20 at 23:57
  • 1
    No, I believe what they're asking for is for _only the staged files_ to be picked up, not all files. I agree `git commit -a` is the way to pick up all files. – bk2204 Dec 05 '20 at 02:32
  • Not exactly (it's a trap): `git add -A` does pick up all the files, while `git commit -a` only picks staged ones, according to the man page, which makes it a shortcut for `git add -u ; git commit`. – Obsidian Dec 05 '20 at 03:15
  • @Obsidian No, `git commit -a` adds all _tracked_ files that have changed. The `man git commit` for me says `-a, --all Tell the command to automatically stage files that have been modified and deleted, but new files you have not told Git about are not affected.` – underscore_d Dec 05 '20 at 14:54
  • @underscore_d : this is exactly what I meant. Read again. – Obsidian Dec 05 '20 at 15:11
  • @Obsidian I still don't see it! `tracked != staged`. Tracked files are any that have been added on the file level in the history of the repo and not removed since. Staged files/hunks are those that have been added to the index since the previous commit. `git commit -a` adds all **tracked** files that have changes to the index and then commits. It does _not_ add only files that have previously been **staged** during current / since previous commit. – underscore_d Dec 07 '20 at 10:33
  • @bk2204 is correct. I just dont want to have to re-stage files. There are files (usually config files tailored for my working environment) that need to stay unstaged and not committed. Sometimes I will need to break an existing uncommitted set of changes into multiple commits if someone needs code I've finished but cant make a PR to main/master/dev trunk. This would also be where not having to re-stage would be useful. – StingyJack Dec 07 '20 at 14:48
2

Considering your asks and the comments and edits you made, it might be useful to pinpoint the fact that Git is a snapshot-oriented VCS. Each commit actually contains a tree object that leads to every file this commit references.

Each time you change one your file, would it be of a single byte, it's assumed as something new then recorded all again. Since all contents are indexed using their SHA1 sum, though, only different contents are saved separately. If you record multiple times the same file or revert to a previous version of it, it will be recorded only once. All this stuff is moreover compressed, so you'll never face any space issue because of this.

In this way, this behavour is introduced as being similar to the filesystem's snapshot mecanism, which makes it acceptable.

This answers your first question : files are always recorded, not changes. What you see when you browse a commit is actually an automatic "diff" operation between this commit and its parent one. This also enables you to easily make a "diff" between two arbitrary revisions without having to resolve anything first. It also guarantees yourself that once you can reach a commit, you'll have access to the entirety of its files, even if you can't see its history (useful with shadow clones or if your repository is corrupted).

If you now want to automatically embed all modified files each time you commit, you can use git add -u to mark all updated files, or git add -A to include all new files with updated ones, or even git commit -a to perform an add -u/commit in a single operation.

You can also easily define aliases commands, either from outside if you're using a shell, or in the [alias] section of your gitconfig file. For example, I personnaly use:

[alias]
    root = rev-parse --show-toplevel

… to have a git root command that finds the root directory of my repository.

But… you probably don't want to do this.

The reason why this is not automatic with Git is to incite the developer to prepare "cooked", unitary commits that focus on one purpose at a time, even if this task applies on multiple files at a time and if, on the other hand, a same file can be amended at different places for different purposes.

That's why, from this point of view, staging all modified files at once is generally pointless because unless you commit very frequently, it's very unlikely that all modified files concern a single topic at a time.

If you really don't care about it and you want is to save the state of your work, it remains easy to do so using the commands stated above but trust me, doing clean commits is AT LEAST as valuable as the code itself. It's really important when you work alone, it becomes critical in a teamwork.

As regards the index now: it's actually a very clever way to handle the whole thing. At first, the index is simply the list of files that are already tracked. It's a flat, binary file located under .git/index. But it won't stick to hold the names, it will also refer the content objects these files are associated to. This means that objects are created at add time and when you commit, Git simply needs to record the state of this index.

It's really interesting because this what enables Git to know if a file is unchanged, staged, unstaged or even both of it. Also, when you select hunks with git add -p, Git won't collect temporary bits of changes stored somewhere: it will directly amend the index, which then allows you to prepare exactly what you want or revert it to its initial state if you change you mind.

Git is not as cryptic as it seems. The only notions you need to master are the object concept, the way the index works and optionaly the reflog to easily recover when something go wrong. In particular, DON'T try to emulate the Mercurial behaviour: it looks easy at first but leads you pretty soon into a dead end.

You may be interested in this post: What is the use of Staging area in git

Obsidian
  • 3,719
  • 8
  • 17
  • 30
  • The commits are clean commits. All the changes are intended to be committed together, as that's what I developed and tested together. I'm having this pain mostly when looking over my changes prior to committing them. If I find something I have to address in a file, I will do so and test it... and then _have to stage the file again_. Ugh. Also I'm using visual studio, so the option to run an external CLI command is possible to make into an IDE command but I was looking for something built in first. – StingyJack Dec 07 '20 at 01:58
  • Git and other VCS workings are not cryptic to me in the general sense. Commit changes, merge, branch, tag/label, reparent, rollback, etc. They all do those basic things, just some are better or more efficient or safer or more team centric than others. I shouldn't have to care or worry about internal mechanics like the reflog, unless I'm one of the team that's making a VCS. – StingyJack Dec 07 '20 at 02:05
  • Hg is one that I have not used actually. I'd prefer TFVC because I can do all of the necessary usual activities with the least amount of actions, the visualization tools are good, managing a repo for a team doesn't require a ton of branch cleanup, I don't have to worry about anyone accidentally deleting a commit or losing changes, and it has shelvesets. Unfortunately for me, in it's zeal to pander to the FOSS community, MSFT has forgotten all about an awesome thing it made to the point where VC PM's are misinformed about it's features ("tfvc doesn't branch, etc"... Smh) – StingyJack Dec 07 '20 at 02:14
0

Well, that's part of the reason GIT is so useful, it allows you to make incremental changes and see the differences as you update the code. You can use git add -u to update changes automatically, it's counter intuitive to the purpose of GIT and source control to automatically update though, I don't think you can do that.

The benefit of seeing the differences of the changes in the file is the diff, which comes in handy while developing, it shows the new changes before staging:

git diff

One useful tool that might alleviate your frustration is the git add patch flag:

git add -p

It will look at the hunks of code that you changed in the files and let you pick and choose which to stage. You won't need to deal with files as much.

benjaminknox
  • 257
  • 4
  • 11
  • And I would add that if the hunk is to wide, one can split it using "s" and if it's still not enough, one can directly edit the patch with "e". – Obsidian Dec 04 '20 at 16:29
  • Yes, it is interactive and there is a set of options that you can choose for each hunk, "s" will only show up when git can split it. The options look like this when you are stepping through `Stage this hunk [y,n,q,a,d,K,j,J,g,/,e,?]?` and you can read more by answering "?" – benjaminknox Dec 04 '20 at 16:58
  • Every other VCS I've used does incremental updates like Git does. Its not special in that regard. I dont see the benefit of staged vs nonstaged differences when only the combination of the two is what exists on the filesystem and is used by programs/compilers/etc. The File is what I compiled with and tested locally and what should be committed. This is another one of those openings for mistakes that git allows under the guise of "powerful/useful" that just does not need to be there for the common uses of a VCS. – StingyJack Dec 04 '20 at 16:59
  • Some of us compile/test things in 1 go but then commit them in smaller chunks. Big shrug. – underscore_d Dec 04 '20 at 19:39
  • 1
    I think it's a matter of opinion which is better, but I don't think I've ever thought of smaller chunks as a bad thing. Interesting opinion that you have. – benjaminknox Dec 04 '20 at 21:40