- Mastering Git
- Jakub Nar?bski
- 1641字
- 2021-07-09 19:37:28
Searching history
A huge number and variety of useful options to the git log
command are limiting options—that is, options that let you show only a subset of commits. This complements selecting commits to view by passing the appropriate revision range, and allows us to search the history for the specific versions, utilizing information other than the shape of the DAG of revisions.
Limiting the number of revisions
The most basic way of limiting the git log
output, the simplest limiting option, is to show only then most recent commits. This is done using the -<n>
option (where n
is any integer); this can be also written as -n <n>
, or in long form as --max-count=<n>
. For example, git log -2
would show the two last (most recent) commits in the current line of development, starting from the implicit HEAD
revision.
You can skip the first few commits shown with --skip=<n>
.
Matching revision metadata
History limiting options can be pided into those that check information stored in the commit object itself (the revision metadata), and those that filter commits based on changeset (on changes from parent commit(s)).
Time-limiting options
If you are interested in commits created within some date range that you're interested in, you can use a number of options such as --since
and --until
, or --before
and --after
. For example, the following command gets the list of commits made in the last two weeks:
$ git log --since=2.weeks
These options work with lots of formats. You can specify a specific date such as "2008-04-21" or a relative date such as "2 years, 3 months, and 3 days ago"; you can use a dot in place of a space.
When using a specific date, one must remember that these dates are interpreted to be in the local time zone, if the date does not include the time zone. It is important because, in such a situation, Git will not yield identical results when run by different colleagues, who may be situated in other time zones around the world. For example, --since="2014-04-29 12:00:00"
would catch an additional 6 hours, worth of commits when issued in Birmingham, England, United Kingdom (where it means 2014-04-29Z11:00:00 universal time) than when issued in Birmingham, Alabama, USA. (where it means 2014-04-29Z17:00:00). To have everyone get the same results, you need to include the time zone in the time limit, for example, --after="2013-04-29T17:07:22+0200"
.
Note that Git stores not one but two dates describing the version: author date and committer date. Time-limiting options described here examine the committer date, which means the date and time when the revision object was created. This might be different from author date, which means the date and time when a changeset was created (the change was made).
The date of authorship can be different from the date of committership in a few cases. One is when the commit was created in one repository, converted to e-mail, and then applied by other person in an other repository. Another way to have these two dates differ is to have the commit recreated while rebasing; by default, it keeps the author date and gets a new committer date (refer to Chapter 8, Keeping History Clean).
Matching commit contents
If you want to filter your commit history to only show those done by a specific author or committer, you can use the --author
or --committer
options, respectively. For example, let's say you're looking for all the commits in the Git source code authored by Linus. You could use something like git log --author=Linus
. The search is, by default, case-sensitive, and uses regular expressions. Git will search both the name and the e-mail address of the commit author; to match first name only use --author=^Linus
.
The --grep
option lets you search commit messages (which should contain descriptions of the changes). Let's say that you want to find all the security bug fixes that mention the Common Vulnerabilities and Exposures (CVE) identifier in the commit message. You could generate a list of such commits with git log --grep=CVE
.
If you specify both --author
and --grep
options, or more than one --author
or --grep
option, Git will show commits that match either query. In other words, Git will logically OR all the commit matching options. If you want to find commits that match all the queries, with matching options logically AND, you need to use the --all-match
option.
There is also a set of options to modify the meaning of matching patterns, similar to the ones used by the grep
program. To make the search case-insensitive, use the -i
/ --regexp-ignore-case
option. If you want to match simply a substring, you can use -F
/ --fixed-strings
(you might want to do it to avoid having to escape regular expression metacharacters such as ".
" and "?
"). To write more powerful search terms, you can use --extended-regexp
or --perl-regexp
(use the last one only if Git was compiled linked with the PCRE library).
Commit parents
Git, by default, will follow all the parents of each merge commit, when walking down the ancestry chain. To make it follow only the first parent, you can use the aptly named --first-parent
option. This will show you the main line of the history (sometimes called the trunk), assuming that you follow the specific practices with respect to merging changes; you will learn more about this in Chapter 7, Merging Changes Together.
Compare (this example uses the very nice --graph
option that makes an ASCII-art diagram of the history) the following code...
$ git log -5 --graph --oneline * 50f84e3 Update draft release notes to 2.1 * 07768e0 Merge branch 'jc/shortlog-ref-exclude' |\ | * eb07774 shortlog: allow --exclude=<glob> to be passed * | 251cb96 Merge branch 'mn/sideband-no-ansi' |\ \ | * | 38de156 sideband.c: do not use ANSI control sequence
...with this:
$ git log -5 --graph --oneline --first-parent * 50f84e3 Update draft release notes to 2.1 * 07768e0 Merge branch 'jc/shortlog-ref-exclude' * 251cb96 Merge branch 'mn/sideband-no-ansi' * d37e8c5 Merge branch 'rs/mailinfo-header-cmp' * 53b4d83 Merge branch 'pb/trim-trailing-spaces'
You can filter the list to show only the merge commits, or show only the non-merge commits, with the --merges
and --no-merges
options, respectively. These options can be considered just a shortcut for a more generic options: --min-parents=<number>
(--merges
is --min-parents=2
) and --max-parents=<number>
(--no-merges
is --max-parents=1
).
Let's say that you want to find the starting point(s) of your project. You can do this with the help of --max-parents=0
, which would give you all the root commits:
$ git log --max-parents=0 --oneline 0ca71b3 basic options parsing and whatnot. 16d6b8a Initial import of a python script… cb07fc2 git-gui: Initial revision. 161332a first working version 1db95b0 Add initial version of gitk to the CVS repository 2744b23 Start of early patch applicator tools for git. e83c516 Initial revision of "git", the information manager from hell
Searching changes in revisions
Sometimes, searching through commit messages and other revision metadata is not enough. Perhaps, descriptions of the changes were not detailed enough. Or, what if you are looking for a revision when a function was introduced, or where variables started to be used?
Git allows you to look through the changes that each revision brought (the difference between commit and its parent). The faster option is called a pickaxe
search.
With the -S<string>
option, Git will look for differences that introduce or remove an instance of a given string. Note that this is different from the string simply appearing in diff output. (You can do a match using a regular expression with the --pickaxe-regex
option.) Git checks for each revision if there are files whose current side and whose parent side have a different number of specified strings, and shows the revisions that match.
As a side effect, git log
with the -S
option would also show the changes that each revision made (as if the --patch
option were used), but only those differences that match the query. To show differences for all the files, and not only those diffs where the change in number occurred, you need to use the --pickaxe-all
option:
$ git log -S'sub href' commit 06a9d86b49b826562e2b12b5c7e831e20b8f7dce Author: Martin Waitz <tali@admingilde.org> Date: Wed Aug 16 00:23:50 2006 +0200 gitweb: provide function to format the URL for an action link. Provide a new function which can be used to generate an URL for the CGI. This makes it possible to consolidate the URL generation in order to make it easier to change the encoding of actions into URLs. Signed-off-by: Martin Waitz <tali@admingilde.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
With -G<regex>
, Git will literally look for differences whose added or removed line matches the given regular expression. Note that the unified diff format (that Git uses) considers changing line as removing the old version and adding a new one; refer to Chapter 3, Developing with Git for an explanation of how Git describes changes.
To illustrate the difference between -S<regex> --pickaxe-regex
and -G<regex>
, consider a commit with the following diff
in the same file:
if (lstat(path, &st)) - return error("cannot stat '%s': %s", path, + ret = error("cannot stat '%s': %s", path, strerror(errno));
While git log -G"error\("
will show this commit (because the query matches both changed lines), git log -S"error\(" --pickaxe-regex
will not (because the number of occurrences of that string did not change).
Note
If we are interested in a single file, it is easier to use git blame
(perhaps in a graphical blame browser, like with git gui blame
) to check when the given change was introduced. However, git blame
can't be used to find a commit that deleted a line—you need a pickaxe
search for that.
Selecting types of change
Sometimes, you might want to see only those changes that added or renamed files. With Git, you can do this with git log --diff-filter=AM
. You can select any combination of types of changes; see the git-log(1)
manpage for details.
- 數據庫系統教程(第2版)
- Microsoft Dynamics 365 Extensions Cookbook
- Mastering Scientific Computing with R
- 基于Struts、Hibernate、Spring架構的Web應用開發
- Visual Basic程序設計
- Go語言入門經典
- Python Web自動化測試設計與實現
- 深度學習程序設計實戰
- Greenplum構建實時數據倉庫實踐
- Java與Android移動應用開發:技術、方法與實踐
- BackTrack 5 Cookbook
- 網絡工程方案設計與實施(第二版)
- 自然語言處理NLP從入門到項目實戰:Python語言實現
- VB語言程序設計實驗教程
- Jupyter入門與實戰