0

I come from a Subversion background where generally speaking the process is that you check in files individually with per-file commit messages/comments. My (possibly incorrect) observation with Git is that the workflow gears you towards committing all staged files together and with a single commit message, since the default syntax of git commit is to commit all staged files at once. Initially I wanted to think of things in the svn way, that is, per-file commits. But the more I think about the behavior Git is trying to achieve seems to make more sense to me because changes are changes, whatever and wherever they may be, rather than just thinking per file.

Am I correct that Git is going for this behavior in general? Obviously you can commit individual files but it seems that would be done less frequently in Git thinking.

Howiecamp
  • 2,981
  • 6
  • 38
  • 59
  • 1
    Rather than answering the question as posed, I'll just point out that when you do a "git commit" it captures what's in the index at that time *as a complete source tree*. When you later ask to get that commit back, you get, *as a complete tree*, whatever was in the index. (There are many tweaks available upon this formula but that's the general aim.) – torek Jul 13 '14 at 17:18
  • @torek - Can you elaborate on what 'complete source tree' means? – Howiecamp Jul 13 '14 at 21:10
  • 1
    Do: `git ls-tree -r --name-only HEAD`, and repeat for other revisions (like `HEAD~1` and so on to walk backwards in history). Each commit contains a complete copy of every file. These copies are very cleverly compressed so that even though a repo might have thousands of commits each containing thousands of files, the space needed for the entire repo is often less than that needed for whichever copy you ask git to check out! – torek Jul 13 '14 at 21:34
  • "generally speaking the process is that you check in files individually with per-file commit messages/comments" - This may be *your* process but this is not a conventional approach. In SVN you should also be committing logical change sets, as it makes reviewing & rolling back easier, and is far less likely to leave your build broken. – alroc Jul 14 '14 at 11:26

2 Answers2

4

The trick is to recognize that you are in complete control of which changes get staged. This might be all changes, it might be changes to one file, it might be some changes to some files. Basically, it can be whatever you want.

The interesting bit isn't really git commit, but git add. Here are some common secenarios:

  • Stage all changes to file foo.bar:

    git add foo.bar
    
  • Stage some changes from file foo.bar:

    git add --patch foo.bar
    

    This mode will "chunk" your changes and ask if each chunk should be committed.

  • Stage all changes to tracked files (i.e. ones that Git is already tracking):

    git add -u
    

    The documentation for this option explains what it does better than I can:

    Update the index just where it already has an entry matching <pathspec>. This removes as well as modifies index entries to match the working tree, but adds no new files.

    If no <pathspec> is given when -u option is used, all tracked files in the entire working tree are updated (old versions of Git used to limit the update to the current directory and its subdirectories).

  • Many people also like to use git add ., but I've never made that part of my workflow. You can read about the differences between git add . and git add -u in this question. Basically, git add . will also stage changes to untracked files, but does not stage file deletions, which -u does stage.

Of course, you can also stage changes from multiple files together. I tend not to break commits up by file but rather by logical change. If you're fixing a bug and that requires modifications to three files, those three sets of modifications go together. git add foo bar baz, git commit.

It is very useful to review your staged changes before committing.

  • git diff shows unstaged changes.
  • git diff --staged shows staged changes. These are the ones that will be committed when you run git commit.

I usually run both of these before committing, just to make sure that I know what I've got staged.

If you want to commit all modified files (ones that would be staged with git add -u) you can use the shortcut git commit -a:

by using the -a switch with the commit command to automatically "add" changes from all known files (i.e. all files that are already listed in the index) and to automatically "rm" files in the index that have been removed from the working tree, and then perform the actual commit;

Community
  • 1
  • 1
ChrisGPT was on strike
  • 127,765
  • 105
  • 273
  • 257
  • Your answer is great. FYI I corrected my question in the area that you quoted, to correct the the `git commit` default syntax is to commit all *staged* files as you said. Your comment about breaking up commits by logical change is much better stated than I put it. So just to clarify, should I then not make any interpretations about the thought process that Git may be trying to drive in this regard? I originally assumed this was the intent based on the default commit syntax. – Howiecamp Jul 13 '14 at 20:50
  • 1
    @Howiecamp, I would say that Git's default of committing what you've expressly staged puts you in full control. – ChrisGPT was on strike Jul 13 '14 at 22:10
1

Absolutely not. In fact, with git it is extremely common to commit only portions of changes to a single file, and that is one of git's greatest strengths. You can make two logically distinct changes in a single file and commit them individually. This is why it is said that git tracks content rather than files. Version control systems that require you to submit all changes to a single file feel clumsy and barbaric in comparison.

William Pursell
  • 204,365
  • 48
  • 270
  • 300
  • << In fact, with git it is extremely common to commit only portions of changes to a single file, and that is one of git's greatest strengths. You can make two logically distinct changes in a single file and commit them individually. >> Via `git add --patch`? – Howiecamp Jul 13 '14 at 20:53
  • 1
    Yes, `git add -p` is the usual way to stage hunks. – William Pursell Jul 13 '14 at 21:00