官术网_书友最值得收藏!

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.

主站蜘蛛池模板: 龙山县| 清新县| 伊宁县| 故城县| 龙南县| 全南县| 南华县| 西乌珠穆沁旗| 昭通市| 辽阳县| 雅安市| 昌邑市| 旬邑县| 富平县| 迭部县| 都匀市| 义乌市| 桐庐县| 唐河县| 望奎县| 五莲县| 达日县| 西平县| 沧源| 大余县| 酒泉市| 灌云县| 湘阴县| 特克斯县| 南康市| 甘肃省| 达拉特旗| 扎囊县| 鄂伦春自治旗| 皋兰县| 山东省| 玉田县| 阳谷县| 临夏市| 阿巴嘎旗| 汝城县|