Hacker News new | past | comments | ask | show | jobs | submit login

Please ask away if there's anything specific that's confusing and I'll do my best to explain.



My biggest problem is I work alone, am undisciplined, and do not work with mature software. So my commits are all over the place. If I've already started to stage one commit how can I stage a different commit without losing my current progress?

I actually like git but I haven't found a tutorial that demonstrates a workflow for non-ideal conditions.


Something to remember:

  working tree --[add]--> index --[commit]--> HEAD
                          index <--[reset]--- HEAD
           ^----[diff]----^   ^-[diff --cached]-^
• git add moves things from the working tree into the index

• git commit creates a new commit from the index and makes it your new tip commit, typically updating whatever branch is indicated by HEAD. (HEAD literally is just .git/HEAD and is normally the name of a branch, take a look)

• git diff shows you the difference between the index and the working tree, i.e. unstaged work

• git diff --cached shows you the difference between the index and HEAD, i.e., staged but uncommitted work

• git add /path/to/file will stage an entire file

• git add -p /path/to/file lets you stage individual hunks from a file

• git reset unstages everything

• git reset /path/to/file unstages that file

• git reset -p /path/to/file lets you unstage individual hunks from a file

Now you know how to stage/unstage individual bits of work, either a whole file at a time, or bit by bit. You also know how to commit what you've staged, and how to view what you're about to commit.

So if you've started to stage some work and you're ready to stage a different commit, just commit the stuff you've already staged. e.g., let's say (for simplicity) you've edited foo and bar and want to make those changes separate commits:

   $ git add foo
   $ git diff --cached (confirm it's what you expect to commit)
   $ git commit -m "add fn() to foo"
   $ git add bar
   $ git diff --cached (confirm it's what you expect to commit)
   $ git commit -m "fix bug in x()"
In between making those two commits, you may wish to test the first commit. You could do that like this:

   $ git add foo
   $ git diff --cached (confirm it's what you expect to commit)
   $ git commit -m "add fn() to foo"
   $ git stash save "temporarily set aside work so I can test foo"
 
At this point, your unstaged/uncommitted work has been set aside and your working tree matches (with respect to the files git is tracking) the commit you just made. Here's where you can perform testing, potentially amending foo (git add, git commit --amend). Okay, you're ready to continue:

   $ git stash pop
   $ git add bar
   $ git diff --cached (confirm it's what you expect to commit)
   $ git commit -m "fix bug in x()"

I hope this helps. The key thing (IMO) is really to understand what git is doing under-the-hood. The git UI and (especially the) documentation are all over the place. Don't be afraid to start with a test repo and peek inside .git to see what it's doing as you execute commands.

Good luck!


Thanks, this is really helpful.

git stash is exactly what I was looking for in order to save my index without having to make a random commit. And then the -p option is icing on the cake (ps, it also works for stash).

I ran into a tiny problem with git stash. Assume I have a file called README. If I do the following:

  $ git mv README README.markdown
  $ git stash save
  $ git stash pop
The index no longer knows that I did a 'git mv'. It turns out the --index option will try to reinstate the changes made to the index, but it might cause a merge conflict.

Also, the patch interactive mode documentation says "g - select a hunk to go to" yet it never gives that option. I thought it might not allow it if there are a small number of chunks, but I even tried it on an old repo I have with 7 modified files and 'g' was never an option.... Have you ever used g?


I didn't mention --index since I was trying to keep it simple.

-g works for me, but it's only an option if there's more than one hunk in a single file. You can use 's' to split a hunk up if its non-contiguous.


You may find this post interesting. Git means never having to say "you should have".

http://tomayko.com/writings/the-thing-about-git




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: