Today I Learned Git Part 5
This is part 5 to my series of posts about learning
git. Most of the sections here are from various TILs I've found and hand picked ones I found useful.
Grep For a Pattern on Another Branch
Git has a built-in
grep command that works essentially the same as the standard
grep command that unix users are used to. The benefit of
git-grep is that it is tightly integrated with Git. You can search for occurrences of a pattern on another branch. For example, if you have a feature branch,
my-feature, on which you'd like to search for occurrences of
user.last_name, then your command would look like this:
git grep 'user.last_name' my-feature
If there are matching results, they follow this format:
my-feature:app/views/users/show.html.erb: <%= user.last_name %> ...
This formatting is handy because you can easily copy the branch and file directive for use with
man git-grep for more details.
Grep Over Commit Messages
git log command supports a
--grep flag that allows you to do a text search (using grep, obviously) over the commit messages for that repository. For the git user that writes descriptive commit messages, this can come in quite handy. In particular, this can be put to use in an environment where the standard process involves including ticket and bug numbers in the commit message. For example, finding bug
#123 can be accomplished with:
git log --grep="#123"
man git-log for more details.
Ignore Changes to a Tracked File
Files that should never be tracked are listed in your
.gitignore file. But what about if you want to ignore some local changes to a tracked file?
You can tell git to assume the file is unchanged
git update-index --assume-unchanged <some-file>
Reversing the process can be done with the
Intent to Add
Git commands like
git diff and
git add --patch are awesome, but their little caveat is that they only work on files that are currently tracked in the repository. That means that after working on that new feature for 30 minutes, a
git diff is only going to show you the changes to existing files and when you go to start making commits with
git add --patch you will again be provided with only part of the picture.
git add command has a flag,
-N, that is described in the git man pages:
Record only the fact that the path will be added later. An entry for the path is placed in the index with no content. This is useful for, among other things, showing the unstaged content of such files with git diff and committing them with git commit -a.
By adding untracked files with the
-N flag, you are stating your intent to add these files as tracked files. Once git knows that these files are meant to be tracked, it will know to include them when doing things like computing the diff, performing an interactive add, etc.
Interactively Unstage Changes
I often use
git add --patch to interactively stage changes for a commit. Git takes me through changes to tracked files piece by piece to check if I want to stage them. This same interactive staging of files can be used in reverse when removing changes from the index. Just add the
You can use it for a single file
git reset --patch README.md
or you can let it operate on the entire repository
git reset --patch
This is useful when you've staged part of a file for a commit and then realize that some of those changes shouldn't be committed.
Last Commit a File Appeared
In my project, I have a
README.md file that I haven't modified in a while. I'd like to take a look at the last commit that modified it. The
git log command can be used here with few arguments to narrow it down.
git log -1 -- README.md commit 6da76838549a43aa578604f8d0eee7f6dbf44168 Author: jbranchaud <email@example.com> Date: Sun May 17 12:08:02 2015 -0500 Add some documentation on configuring basic auth.
This same command will even work for files that have been deleted if you know the path and name of the file in question. For instance, I used to have an
ideas.md file and I'd like to find the commit that removed it.
git log -1 -- docs/ideas.md commit 0bb1d80ea8123dd12c305394e61ae27bdb706434 Author: jbranchaud <firstname.lastname@example.org> Date: Sat May 16 14:53:57 2015 -0500 Remove the ideas doc, it isn't needed anymore.
List All Files Changed Between Two Branches
git-diff command can help with finding all files that have changed between two branches. For instance, if you are at the
HEAD of your current feature branch and you'd like to see the list of files that have changed since being in sync with the
master branch, you'd formulate a command like the following:
git diff --name-only master
--name-only flag is important because it cuts out the rest of the non-essential output.
You'll want to list the older branch first and the current branch second as a way of showing what has changed from the original branch to get to the current branch.
Though the example shows the use of branches any git reference can be used to see what has changed between two commits.
man git-diff for more details.
List Different Commits Between Two Branches
There are times when I want to get a sense of the difference between two branches. I don't want to look at the actual diff though, I just want to see what commits are on one and the other.
I can do just this by using the
git-log command with a couple flags, most importantly the
To compare the
feature branch against the
master branch, I can run a command like the following:
git log --left-right --graph --cherry-pick --oneline feature...branch
This lists commits with the first line of their messages. It also includes either a
> arrow at the front of each commit indicating whether the commit is on the left (
feature) or right (
master) branch, respectively.
Note: you can use more than branches in a command like this. Any two references will work. You can just use two SHAs for instance.
List Filenames without the Diffs
git show command will list all changes for a given reference including the diffs. With diffs included, this can get rather verbose at times. If you just want to see the list of files involved (excluding the diffs), you can use the
--name-only flag. For instance,
git show HEAD --name-only commit c563bafb511bb984c4466763db7e8937e7c3a509 Author: jbranchaud <email@example.com> Date: Sat May 16 20:56:07 2015 -0500 This is my sweet commit message app/models/user.rb README.md spec/factories/user.rb
List Most Git Commands
You can list most git commands by using the
-a flag with
git help -a
List Untracked Files
ls-files command is a plumbing command that allows you to list different sets of files based on the state of the working directory. So, if you want to list all untracked files, you can do:
git ls-files --others
This includes files ignored by the
.gitignore file. If you want to exclude the ignored files and only see untracked and unignored files, then you can do:
git ls-files --exclude-standard --others
There are some other flags worth checking at at
git help ls-files.