William Vaughn

The git-add manual review

The git-add command is easy to overlook, I’ve used it thousands of times without ever thinking about reading the manual. I was excited to find out what what was in here, because I use this command so much that any learnings will probably payoff quickly. From using magit in emacs I knew it was possible to surgically add lines and blocks of code into the commit index, but using the CLI I’ve never bothered to try. I typically only add full files.

Basics

This command exists to prepare the content of the “index” to be used for the next commit.

git add ./path/to/file.txt
git add .
git add --all

These are the ways I typically use this command, and they’re perfectly valid! This is about all you need to know in order to take your working tree changes and prepare them for a commit. If you need more control you can get into using wildcards:

git add docs/\*.txt

Pick and Choose with --edit

Use this with some caution, but this option on git add will let you change the diff directly to be what you want to apply to the index. It will show you the + and - signs at the front of lines and you can delete the signs or completely remove the lines. When you save the edit, the things you kept will be added to the index and the things you left behind will still be in the working tree.

Here’s a diff with two simple chunks where I added and deleted some lines from a README. With the --edit option I’d like to only commit part of these. With the verbosity of git diffs even this small example can be a lot to read, you should go edit some files and try it yourself to get a feel.

diff --git a/README.md b/README.md
index eb107d0..fa359f8 100644
--- a/README.md
+++ b/README.md
@@ -52,10 +52,6 @@ https://stackoverflow.com/questions/44527452/cant-open-lib-odbc-driver-13-for-sq

 #### Installing MySQL

-##### macOS
-
-TODO: Probably something like `brew install mysql` or `brew install mariadb`.
-
 ##### amzn2

 ```bash
@@ -63,6 +59,13 @@ sudo yum install -y https://dev.mysql.com/get/mysql57-community-release-el7-11.n
 sudo yum install -y mysql-community-client
 ```

+How about add some more description here.
+Oh but this is toooooo much info, so let's take it out
+blah
+blah
+
+I want to leave this important bit in though!
+
 ### Installing Project Dependencies

 ```

So I’ll edit that:

git add --edit

This opens up my $EDITOR (vim) and then I can tweak this diff. Here’s my edit that leaves the macOS header in the first diff chunk and important bits of the second chunk.

 diff --git a/README.md b/README.md
 index eb107d0..fa359f8 100644
 --- a/README.md
 +++ b/README.md
 @@ -48,25 +48,28 @@ brew tap microsoft/mssql-release https://github.com/Microsoft/homebrew-mssql-rel
  brew update
  brew install msodbcsql mssql-tools
  ```
  https://stackoverflow.com/questions/44527452/cant-open-lib-odbc-driver-13-for-sql-server-sym-linking-issue

  #### Installing MySQL

 ##### macOS
 -
 -TODO: Probably something like `brew install mysql` or `brew install mariadb`.
 -
  ##### amzn2

  ```bash
  sudo yum install -y https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm
  sudo yum install -y mysql-community-client
  ```

 +How about add some more description here.
 +
 +I want to leave this important bit in though!
 +
  ### Installing Project Dependencies

  ```
  poetry install
  ```

  If you get a clang/ssl error during `poetry install`, it's possible your linker+brew+Apple aren't playing well together. Try pointing your linker to openssl directly, via:

Interactive additions with -p, --patch

Using the --interactive flag you get an interactive mode for exploring the state of your repo and what to add. The very useful bit of this to me was the patch subcommand, and you can go to interactive patch mode directly using the --patch option instead of --interactive.

In patch mode you are presented with hunks of your diff and a prompt to decide what to do with each hunk. Here are the possible decisions:

prompt description
y stage this hunk
n do not stage this hunk
q quit; do not stage this or any remaining
a stage this hunk and all remaining
d do not stage this hunk or any remaining
g select a hunk to go to
\/ search for a hunk matching regex
j leave this hunk undecided, see next undecided
J leave this hunk undecided, see next
k leave this hunk undecided, see previous undecided
K leave this hunk undecided, see previous
s split the current hunk into smaller hunks
e manually edit the current hunk

Pretty easy, answer the prompts and make your decisions. When you’re done the index will be updated with the hunks you selected. The ones you didn’t select are still unstaged.

Conclusion

I’ve been actively trying to make cleaner and smaller commits to simplify code review for my colleagues. I’m hopeful that what I learned here with git-add will help the next time I’m faced with a messy or complicated diff that could be split into simpler pieces. Thanks for reading!