Как найти хэш коммита

How do I get the hash of the current commit in Git?

Mateen Ulhaq's user avatar

Mateen Ulhaq

23.8k18 gold badges95 silver badges132 bronze badges

asked Jun 4, 2009 at 8:42

Sardaukar's user avatar

2

To turn any extended object reference into a hash, use git-rev-parse:

git rev-parse HEAD

or

git rev-parse --verify HEAD

To retrieve the short hash:

git rev-parse --short HEAD

To turn references (e.g. branches and tags) into hashes, use git show-ref and git for-each-ref.

Mateen Ulhaq's user avatar

Mateen Ulhaq

23.8k18 gold badges95 silver badges132 bronze badges

answered Jun 4, 2009 at 9:05

Jakub Narębski's user avatar

Jakub NarębskiJakub Narębski

306k65 gold badges214 silver badges230 bronze badges

20

To get the shortened commit hash, use the %h format specifier:

git log --pretty=format:'%h' -n 1

%H represents the long commit hash. Also, -1 can be used directly in place of -n 1.

Mateen Ulhaq's user avatar

Mateen Ulhaq

23.8k18 gold badges95 silver badges132 bronze badges

answered Sep 30, 2011 at 23:32

outofculture's user avatar

outofcultureoutofculture

5,9631 gold badge17 silver badges20 bronze badges

10

Another one, using git log:

git log -1 --format="%H"

It’s very similar to the of @outofculture though a bit shorter.

answered Nov 21, 2011 at 18:48

Paul Pladijs's user avatar

Paul PladijsPaul Pladijs

18.2k5 gold badges28 silver badges31 bronze badges

6

To get the full SHA:

$ git rev-parse HEAD
cbf1b9a1be984a9f61b79a05f23b19f66d533537

To get the shortened version:

$ git rev-parse --short HEAD
cbf1b9a

answered Jul 29, 2016 at 20:04

Alexander's user avatar

AlexanderAlexander

104k30 gold badges199 silver badges194 bronze badges

1

Commit hash

git show -s --format=%H

Abbreviated commit hash

git show -s --format=%h

The -s flag is same as --no-patch and stands for «Suppress diff output».

Click here for more git show examples.

Niko Pasanen's user avatar

Niko Pasanen

26.9k10 gold badges92 silver badges96 bronze badges

answered Mar 27, 2017 at 19:33

ecwpz91's user avatar

ecwpz91ecwpz91

1,50713 silver badges8 bronze badges

For completeness, since no one has suggested it yet. .git/refs/heads/master is a file that contains only one line: the hash of the latest commit on master. So you could just read it from there.

Or, as a command:

cat .git/refs/heads/master

Update:

Note that git now supports storing some head refs in the pack-ref file instead of as a file in the /refs/heads/ folder. https://www.kernel.org/pub/software/scm/git/docs/git-pack-refs.html

Pang's user avatar

Pang

9,481146 gold badges81 silver badges122 bronze badges

answered Oct 16, 2012 at 11:34

Deestan's user avatar

DeestanDeestan

16.7k4 gold badges32 silver badges48 bronze badges

11

There’s always git describe as well. By default it gives you —

john@eleanor:/dev/shm/mpd/ncmpc/pkg (master)$ git describe --always
release-0.19-11-g7a68a75

kayleeFrye_onDeck's user avatar

answered Aug 26, 2011 at 10:43

John Tyree's user avatar

John TyreeJohn Tyree

1,0607 silver badges14 bronze badges

4

Use git rev-list --max-count=1 HEAD

answered Jun 4, 2009 at 8:48

Robert Munteanu's user avatar

Robert MunteanuRobert Munteanu

66.7k35 gold badges205 silver badges277 bronze badges

1

If you need to store the hash in a variable during a script, you can use

last_commit=$(git rev-parse HEAD);

Or, if you only want the first 10 characters (like github.com does)

last_commit=$(git rev-parse --short=10 HEAD);

nik7's user avatar

nik7

8073 gold badges11 silver badges20 bronze badges

answered Jul 15, 2012 at 16:04

Henk's user avatar

HenkHenk

5464 silver badges5 bronze badges

1

If you want the super-hacky way to do it:

cat .git/`cat .git/HEAD | cut -d   -f 2`

Basically, git stores the location of HEAD in .git/HEAD, in the form ref: {path from .git}. This command reads that out, slices off the «ref: «, and reads out whatever file it pointed to.

This, of course, will fail in detached-head mode, as HEAD won’t be «ref:…», but the hash itself — but you know, I don’t think you expect that much smarts in your bash one-liners. If you don’t think semicolons are cheating, though…

HASH="ref: HEAD"; while [[ $HASH == ref:* ]]; do HASH="$(cat ".git/$(echo $HASH | cut -d   -f 2)")"; done; echo $HASH

dave1010's user avatar

dave1010

15.1k7 gold badges67 silver badges64 bronze badges

answered Oct 14, 2015 at 19:15

Fordi's user avatar

FordiFordi

2,74824 silver badges20 bronze badges

4

I needed something a little more different: display the full sha1 of the commit, but append an asterisk to the end if the working directory is not clean. Unless I wanted to use multiple commands, none of the options in the previous answers work.

Here is the one liner that does:
git describe --always --abbrev=0 --match "NOT A TAG" --dirty="*"
Result: f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe*

Explanation: describes (using annotated tags) the current commit, but only with tags containing «NOT A TAG». Since tags cannot have spaces, this never matches a tag and since we want to show a result --always, the command falls back displaying the full (--abbrev=0) sha1 of the commit and it appends an asterisk if the working directory is --dirty.

If you don’t want to append the asterisk, this works like all the other commands in the previous answers:
git describe --always --abbrev=0 --match "NOT A TAG"
Result: f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe

answered Feb 17, 2018 at 19:06

Rado's user avatar

RadoRado

8,5547 gold badges30 silver badges44 bronze badges

3

git rev-parse HEAD does the trick.

If you need to store it to checkout back later than saving actual branch if any may be preferable:

cat .git/HEAD

Example output:

ref: refs/heads/master

Parse it:

cat .git/HEAD | sed "s/^.+ (.+)$/1/g"

If you have Windows then you may consider using wsl.exe:

wsl cat .git/HEAD | wsl sed "s/^.+ (.+)$/1/g"

Output:

refs/heads/master

This value may be used to git checkout later but it becomes pointing to its SHA. To make it to point to the actual current branch by its name do:

wsl cat .git/HEAD | wsl sed "s/^.+ (.+)$/1/g" | wsl sed "s/^refs///g"  | wsl sed "s/^heads///g"

Output:

master

sdgfsdh's user avatar

sdgfsdh

32.8k26 gold badges128 silver badges235 bronze badges

answered Nov 4, 2019 at 16:12

Sergei Krivonos's user avatar

Sergei KrivonosSergei Krivonos

4,1513 gold badges39 silver badges54 bronze badges

The most succinct way I know:

git show --pretty=%h 

If you want a specific number of digits of the hash you can add:

--abbrev=n

answered Feb 7, 2014 at 6:43

Brian Peterson's user avatar

Brian PetersonBrian Peterson

3,0136 gold badges29 silver badges35 bronze badges

3

Perhaps you want an alias so you don’t have to remember all the nifty details. After doing one of the below steps, you will be able to simply type:

$ git lastcommit
49c03fc679ab11534e1b4b35687b1225c365c630

Following up on the accepted answer, here are two ways to set this up:

1) Teach git the explicit way by editing the global config (my original answer):

 # open the git config editor
 $ git config --global --edit
 # in the alias section, add
 ...
 [alias]
   lastcommit = rev-parse HEAD
 ...

2) Or if you like a shortcut to teach git a shortcut, as recently commented by Adrien:

$ git config --global alias.lastcommit "rev-parse HEAD"

From here on, use git lastcommit to show the last commit’s hash.

Community's user avatar

answered Oct 9, 2015 at 12:53

miraculixx's user avatar

miraculixxmiraculixx

9,9842 gold badges40 silver badges60 bronze badges

0

Here is one-liner in Bash shell using direct read from git files:

(head=($(<.git/HEAD)); cat .git/${head[1]})

You need to run above command in your git root folder.

This method can be useful when you’ve repository files, but git command has been not installed.

If won’t work, check in .git/refs/heads folder what kind of heads do you have present.

answered Oct 5, 2017 at 22:11

kenorb's user avatar

kenorbkenorb

153k85 gold badges674 silver badges738 bronze badges

git show-ref --head --hash head

If you’re going for speed though, the approach mentioned by Deestan

cat .git/refs/heads/<branch-name>

is significantly faster than any other method listed here so far.

Community's user avatar

answered Apr 30, 2015 at 7:06

Dennis's user avatar

DennisDennis

56.1k25 gold badges142 silver badges139 bronze badges

1

in your home-dir in file «.gitconfig» add the following

[alias]
sha = rev-parse HEAD

then you will have an easier command to remember:

$ git sha
59fbfdbadb43ad0b6154c982c997041e9e53b600

answered Feb 18, 2016 at 16:16

jo_'s user avatar

jo_jo_

7,8991 gold badge18 silver badges14 bronze badges

On git bash, simply run
$ git log -1

you will see, these lines following your command.

commit d25c95d88a5e8b7e15ba6c925a1631a5357095db .. (info about your head)

d25c95d88a5e8b7e15ba6c925a1631a5357095db, is your SHA for last commit.

answered Nov 26, 2019 at 12:40

Batty's user avatar

BattyBatty

1211 silver badge5 bronze badges

Pretty print of main git repo, and sub-modules:

echo "Main GIT repo:"
echo $(git show -s --format=%H) '(main)'
echo "Sub-modules:"
git submodule status | awk '{print $1,$2}'

Example output:

3a032b0992d7786b00a8822bbcbf192326160cf9 (main)
7de695d58f427c0887b094271ba1ae77a439084f sub-module-1
58f427c0887b01ba1ae77a439084947de695d27f sub-module-2
d58f427c0887de6957b09439084f4271ba1ae77a sub-module-3

answered Feb 27, 2022 at 8:52

leenremm's user avatar

leenremmleenremm

97312 silver badges17 bronze badges

How I would do it in python (based on @kenorb’s bash answer)

def get_git_sha():
    # Which branch are we on?
    branch = open(".git/HEAD", "r").read()

    # Parse output "ref: refs/heads/my_branch" -> my_branch
    branch = branch.strip().split("/")[-1]

    # What's the latest commit in this branch?
    return open(f".git/refs/heads/{branch}").read().strip()

answered Mar 22, 2022 at 15:24

ignorant's user avatar

ignorantignorant

1,3801 gold badge10 silver badges14 bronze badges

Here is another direct-access implementation:

head="$(cat ".git/HEAD")"
while [ "$head" != "${head#ref: }" ]; do
  head="$(cat ".git/${head#ref: }")"
done

This also works over http which is useful for local package archives (I know: for public web sites it’s not recommended to make the .git directory accessable):

head="$(curl -s "$baseurl/.git/HEAD")"
while [ "$head" != "${head#ref: }" ]; do
  head="$(curl -s "$baseurl/.git/${head#ref: }")"
done

answered Nov 4, 2016 at 13:20

Daniel Alder's user avatar

Daniel AlderDaniel Alder

4,9802 gold badges45 silver badges54 bronze badges

Here is another way of doing it with :)

git log | grep -o 'w{8,}' | head -n 1

answered Feb 10, 2017 at 15:14

Marcelo Lazaroni's user avatar

Marcelo LazaroniMarcelo Lazaroni

9,5993 gold badges34 silver badges41 bronze badges

echo «printing last commit id# for current branch:»;

 git reflog

Image to show actul results

answered Feb 23, 2022 at 10:53

Usman Ali Maan's user avatar

1

I wanted the newest commit on the origin/main branch so I use

git ls-remote origin | grep main$ | cut -f 1

answered Mar 15 at 19:49

mvndaai's user avatar

mvndaaimvndaai

3,3132 gold badges28 silver badges34 bronze badges

Viewing the Commit History

After you have created several commits, or if you have cloned a repository with an existing commit history, you’ll probably want to look back to see what has happened.
The most basic and powerful tool to do this is the git log command.

These examples use a very simple project called “simplegit”.
To get the project, run:

$ git clone https://github.com/schacon/simplegit-progit

When you run git log in this project, you should get output that looks something like this:

$ git log
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    Change version number

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    Remove unnecessary test

commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 10:31:28 2008 -0700

    Initial commit

By default, with no arguments, git log lists the commits made in that repository in reverse chronological order; that is, the most recent commits show up first.
As you can see, this command lists each commit with its SHA-1 checksum, the author’s name and email, the date written, and the commit message.

A huge number and variety of options to the git log command are available to show you exactly what you’re looking for.
Here, we’ll show you some of the most popular.

One of the more helpful options is -p or --patch, which shows the difference (the patch output) introduced in each commit.
You can also limit the number of log entries displayed, such as using -2 to show only the last two entries.

$ git log -p -2
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    Change version number

diff --git a/Rakefile b/Rakefile
index a874b73..8f94139 100644
--- a/Rakefile
+++ b/Rakefile
@@ -5,7 +5,7 @@ require 'rake/gempackagetask'
 spec = Gem::Specification.new do |s|
     s.platform  =   Gem::Platform::RUBY
     s.name      =   "simplegit"
-    s.version   =   "0.1.0"
+    s.version   =   "0.1.1"
     s.author    =   "Scott Chacon"
     s.email     =   "schacon@gee-mail.com"
     s.summary   =   "A simple gem for using Git in Ruby code."

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    Remove unnecessary test

diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index a0a60ae..47c6340 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -18,8 +18,3 @@ class SimpleGit
     end

 end
-
-if $0 == __FILE__
-  git = SimpleGit.new
-  puts git.show
-end

This option displays the same information but with a diff directly following each entry.
This is very helpful for code review or to quickly browse what happened during a series of commits that a collaborator has added.
You can also use a series of summarizing options with git log.
For example, if you want to see some abbreviated stats for each commit, you can use the --stat option:

$ git log --stat
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    Change version number

 Rakefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    Remove unnecessary test

 lib/simplegit.rb | 5 -----
 1 file changed, 5 deletions(-)

commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 10:31:28 2008 -0700

    Initial commit

 README           |  6 ++++++
 Rakefile         | 23 +++++++++++++++++++++++
 lib/simplegit.rb | 25 +++++++++++++++++++++++++
 3 files changed, 54 insertions(+)

As you can see, the --stat option prints below each commit entry a list of modified files, how many files were changed, and how many lines in those files were added and removed.
It also puts a summary of the information at the end.

Another really useful option is --pretty.
This option changes the log output to formats other than the default.
A few prebuilt option values are available for you to use.
The oneline value for this option prints each commit on a single line, which is useful if you’re looking at a lot of commits.
In addition, the short, full, and fuller values show the output in roughly the same format but with less or more information, respectively:

$ git log --pretty=oneline
ca82a6dff817ec66f44342007202690a93763949 Change version number
085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Remove unnecessary test
a11bef06a3f659402fe7563abf99ad00de2209e6 Initial commit

The most interesting option value is format, which allows you to specify your own log output format.
This is especially useful when you’re generating output for machine parsing — because you specify the format explicitly, you know it won’t change with updates to Git:

$ git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 6 years ago : Change version number
085bb3b - Scott Chacon, 6 years ago : Remove unnecessary test
a11bef0 - Scott Chacon, 6 years ago : Initial commit
Table 1. Useful specifiers for git log --pretty=format

Specifier Description of Output

%H

Commit hash

%h

Abbreviated commit hash

%T

Tree hash

%t

Abbreviated tree hash

%P

Parent hashes

%p

Abbreviated parent hashes

%an

Author name

%ae

Author email

%ad

Author date (format respects the --date=option)

%ar

Author date, relative

%cn

Committer name

%ce

Committer email

%cd

Committer date

%cr

Committer date, relative

%s

Subject

You may be wondering what the difference is between author and committer.
The author is the person who originally wrote the work, whereas the committer is the person who last applied the work.
So, if you send in a patch to a project and one of the core members applies the patch, both of you get credit — you as the author, and the core member as the committer.
We’ll cover this distinction a bit more in Distributed Git.

The oneline and format option values are particularly useful with another log option called --graph.
This option adds a nice little ASCII graph showing your branch and merge history:

$ git log --pretty=format:"%h %s" --graph
* 2d3acf9 Ignore errors from SIGCHLD on trap
*  5e3ee11 Merge branch 'master' of https://github.com/dustin/grit.git
|
| * 420eac9 Add method for getting the current branch
* | 30e367c Timeout code and tests
* | 5a09431 Add timeout protection to grit
* | e1193f8 Support for heads with slashes in them
|/
* d6016bc Require time for xmlschema
*  11d191e Merge branch 'defunkt' into local

This type of output will become more interesting as we go through branching and merging in the next chapter.

Those are only some simple output-formatting options to git log — there are many more.
Common options to git log lists the options we’ve covered so far, as well as some other common formatting options that may be useful, along with how they change the output of the log command.

Table 2. Common options to git log

Option Description

-p

Show the patch introduced with each commit.

--stat

Show statistics for files modified in each commit.

--shortstat

Display only the changed/insertions/deletions line from the --stat command.

--name-only

Show the list of files modified after the commit information.

--name-status

Show the list of files affected with added/modified/deleted information as well.

--abbrev-commit

Show only the first few characters of the SHA-1 checksum instead of all 40.

--relative-date

Display the date in a relative format (for example, “2 weeks ago”) instead of using the full date format.

--graph

Display an ASCII graph of the branch and merge history beside the log output.

--pretty

Show commits in an alternate format. Option values include oneline, short, full, fuller, and format (where you specify your own format).

--oneline

Shorthand for --pretty=oneline --abbrev-commit used together.

Limiting Log Output

In addition to output-formatting options, git log takes a number of useful limiting options; that is, options that let you show only a subset of commits.
You’ve seen one such option already — the -2 option, which displays only the last two commits.
In fact, you can do -<n>, where n is any integer to show the last n commits.
In reality, you’re unlikely to use that often, because Git by default pipes all output through a pager so you see only one page of log output at a time.

However, the time-limiting options such as --since and --until are very useful.
For example, this command gets the list of commits made in the last two weeks:

$ git log --since=2.weeks

This command works with lots of formats — you can specify a specific date like "2008-01-15", or a relative date such as "2 years 1 day 3 minutes ago".

You can also filter the list to commits that match some search criteria.
The --author option allows you to filter on a specific author, and the --grep option lets you search for keywords in the commit messages.

Note

You can specify more than one instance of both the --author and --grep search criteria, which will limit the commit output to commits that match any of the --author patterns and any of the --grep patterns; however, adding the --all-match option further limits the output to just those commits that match all --grep patterns.

Another really helpful filter is the -S option (colloquially referred to as Git’s “pickaxe” option), which takes a string and shows only those commits that changed the number of occurrences of that string.
For instance, if you wanted to find the last commit that added or removed a reference to a specific function, you could call:

$ git log -S function_name

The last really useful option to pass to git log as a filter is a path.
If you specify a directory or file name, you can limit the log output to commits that introduced a change to those files.
This is always the last option and is generally preceded by double dashes (--) to separate the paths from the options:

$ git log -- path/to/file
Table 3. Options to limit the output of git log

Option Description

-<n>

Show only the last n commits.

--since, --after

Limit the commits to those made after the specified date.

--until, --before

Limit the commits to those made before the specified date.

--author

Only show commits in which the author entry matches the specified string.

--committer

Only show commits in which the committer entry matches the specified string.

--grep

Only show commits with a commit message containing the string.

-S

Only show commits adding or removing code matching the string.

For example, if you want to see which commits modifying test files in the Git source code history were committed by Junio Hamano in the month of October 2008 and are not merge commits, you can run something like this:

$ git log --pretty="%h - %s" --author='Junio C Hamano' --since="2008-10-01" 
   --before="2008-11-01" --no-merges -- t/
5610e3b - Fix testcase failure when extended attributes are in use
acd3b9e - Enhance hold_lock_file_for_{update,append}() API
f563754 - demonstrate breakage of detached checkout with symbolic link HEAD
d1a43f2 - reset --hard/read-tree --reset -u: remove unmerged new paths
51a94af - Fix "checkout --track -b newbranch" on detached HEAD
b0ad11e - pull: allow "git pull origin $something:$current_branch" into an unborn branch

Of the nearly 40,000 commits in the Git source code history, this command shows the 6 that match those criteria.

Tip

Preventing the display of merge commits

Depending on the workflow used in your repository, it’s possible that a sizable percentage of the commits in your log history are just merge commits, which typically aren’t very informative.
To prevent the display of merge commits cluttering up your log history, simply add the log option --no-merges.

Урок, в котором мы подробнее рассмотрим историю коммитов и научимся путешествовать по истории

Видеоурок

Конспект урока

Краткое содержание урока, основные инструкции для командной строки, полезные ссылки и советы.

Для информации

Урок частично повторяет содержание предыдущего. Но в отличие от прошлого историю коммитов мы рассмотрим намного подробнее.

История коммитов

Сохранение истории изменений или история коммитов — одна из самых важных частей git. В истории сохраняются все коммиты, по которым можно посмотреть автора коммита, commit message, дату коммита и его хэш.
А также можно увидеть измененные файлы и изменения в каждом файле. То есть git хранит буквально все, от самого начала проекта.

Команда git log

За просмотр истории коммитов отвечает команда git log. В сочетании с различными параметрами эта команда выводит историю по-разному.
Есть много различных вариантов и комбинаций параметров, посмотрим некоторые из них

git log, просмотр истории по умолчанию


    $ git log

Показывает все коммиты от новых к старым. Для каждого коммита выводится

  • хэш
  • автор
  • дата
  • сообщение (commit message)

git log -p, расширенный вывод истории


    $ git log -p

Выводит то же, что и git log, но еще и с изменениями в файлах

git log —oneline, короткая запись


    $ git log --oneline

Вывод коммитов в одну строку. Показывает только хэш коммита и commit message

git log —stat —graph, история в виде дерева


    $ git log --stat --graph

Выводит коммиты в виде дерева, в командной строке псевдографикой. Плюс выводит список измененных файлов. К дереву коммитов мы вернемся, когда будем работать с ветками.

Сортировка и фильтрация истории

Есть множество команд, которые позволяют сортировать и фильтровать историю коммитов в командной строке. В том числе в сочетании с линуксовыми командами.
Рассмотрим некоторые из них

Поиск по коммитам

Команда grep — мощный инструмент, который помогает работать в том числе и с git. Например, искать по коммитам


    git log --oneline | grep revert # поиск упоминания revert
    git log --oneline | grep -i revert # независимо от регистра

Коммиты, затронувшие один файл


    git log index.html

Поиск по автору


    git log --author webdevkin

В опции —author можно указать имя или email, необязательно целиком, можно только часть.

Поиск по диапазону дат

Опции —after и —before задают начальную и конечную даты коммитов


     git log --after='2020-03-09 15:30' --before='2020-03-09 16:00'

Комбинация команд и опций

Команды и опции git можно комбинировать и дополнять их линуксовыми командами


    git log --author=webdevkin --oneline | grep footer # все коммиты от автора, в которых упоминается footer
    git log --oneline | wc -l # количество коммитов

Какие еще есть варианты

Мы рассмотрели базовые примеры, но в документации по git log есть много различных опций.
Все их рассматривать нет смысла, при необходимости изучайте документацию.


    git log --help

Просмотр отдельного коммита, git show

Чтобы просмотреть отдельный коммит, нужно узнать его хэш. Хэш коммита выводится в любой команде git log, с параметрами или без. Например,


    $ git log --oneline
    
    7b7d7fa Fixed footer
    26812f9 Revert "Fixed footer"
    0f90ae7 Revert "Fixed styles"
    ...
    a1f3c45 Added footer
    a65aa43 Added new block students to main page
    0b90433 Initial commit

Смотрим второй коммит


    $ git show 43f6afc

Выводится подробная информация о коммите:

  • хэш
  • автор
  • дата
  • commit message
  • список измененных файлов
  • изменения в каждом файле

Короткий хэш коммита

Хэш коммита 40-символьный, но можно использовать короткую запись — первые 7 символов хэша.
Команда git log —oneline выводит именно короткий хэш. Для других операций с коммитами достаточно использовать первые 4 символа.
Например, 3 команды ниже покажут содержимое одного и того же коммита


    $ git show 051f75475cb1dca3cd08c1c7367a3308671ccf7b
    $ git show 051f754
    $ git show 051f

История коммитов в PhpStorm

В окне Local Changes, на вкладке Log показывается вся история коммитов, в левой половине вкладки. В списке коммитов показываются их commit message, автор и дата.
Клик на нужный коммит откроет в правой части вкладки список измененных файлов. Клик на нужном файле и Ctrl/Cmd+D покажет все изменения в этом файле точно так же, как и git diff.

В тексте объяснить работу с историей в PhpStorm сложно, смотрите видеоурок.

Переключение на старый коммит, зачем это нужно

Нужно это обычно в двух случаях:

1. При неудачном деплое, когда вскрылась критичная бага.
Если бага сложная и пофиксить ее быстро не удается, можно откатиться на рабочий коммит, задеплоить рабочую версию и уже потом чинить багу.

2. При отладке. Когда в код закралась бага и мы постепенно продвигаемся «назад в прошлое» и ищем, в какой момент что-то сломалось

Как переключиться на коммит в терминале

Первое — узнать хэш нужного коммита. Например, имеем такую историю


    $ git log --oneline
    
    7b7d7fa Fixed footer
    26812f9 Revert "Fixed footer"
    0f90ae7 Revert "Fixed styles"
    ...
    a1f3c45 Added footer
    a65aa43 Added new block students to main page
    0b90433 Initial commit

Хотим переключиться на предпоследний коммит. Коммиты идут в порядке убывания, поэтому нам нужен второй сверху — 26812f9. Переключаемся на него командой


    $ git checkout 26812f9

Все, вернулись в прошлое. Проверим историю, теперь коммит, на который мы переключились — последний


    $ git log --oneline 
    
    26812f9 Revert "Fixed footer"
    0f90ae7 Revert "Fixed styles"
    ...
    a1f3c45 Added footer
    a65aa43 Added new block students to main page
    0b90433 Initial commit

Уйдем еще дальше, переключимся на первый коммит. Так как коммиты упорядочиваются по убыванию даты, то первый коммит — это последний в списке — 0b90433 Initial commit


    $ git checkout 0b90433

Проверяем историю


    $ git log --oneline 
    
    0b90433 Initial commit

Чтобы вернуться обрано, в исходное состояние, нужно набрать


    $ git checkout master

master — это ветка, в которой мы работаем по умолчанию. О ветках поговорим через пару уроков

Как переключаться между коммитами в PhpStrom

Вкладка Log, правый клик на нужном коммите и Checkout Revision. Все. История коммитов будет видна по-прежнему вся, но напротив текущего коммита будет стоять значок HEAD с символом «!»

Как вернуться обратно? В правом нижем угле PhpStorm есть пункт git:, кликаем на него, выбираем Local Branches — master — checkout. Значок «!» пропадет — мы вернулись в исходное состояние

Что могу посоветовать

  • как и git diff, историю коммитов git log удобнее смотреть в PhpStorm
  • в команде git log есть множество вариантов сортировки и фильтрации
  • сочетание git log с простыми линуксовыми командами дает хороший эффект. Обычный grep — очень хороший помощник
  • PhpStorm предоставляет удобные возможности по фильтрации коммитов. Можно искать коммиты по commit message, по автору, дате и по папкам, в которых происходили изменения
  • перемещайтесь по истории осторожно, не забывайте возвращаться в исходное состояние

На этом все. В следующем уроке мы поговорим о взаимодействии с сервером и познакомимся с командами git push и git pull.

Спасибо за внимание и до встречи!

Все уроки курса

  • Вводный урок
  • 1. Установка и базовая настройка git
  • 2. Создание и клонирование репозитория git
  • 3. Делаем первые изменения, git status и git diff
  • 4. Коммиты и история коммитов, git commit, git log и git show
  • 5. Подробнее об истории коммитов. Путешествие по истории
  • 6. Работа с сервером, git push и git pull
  • 7. Ветки — главная фишка git, git branch и git checkout
  • 8. Работа с ветками на сервере, git fetch
  • 9. Слияния или мерджи веток, git merge
  • 10. Конфликты и их разрешение
  • Платная часть курса. Презентация
  • * 11. Работа с gitignore и git exclude
  • * 12. Буфер обмена git, git stash
  • * 13. Копирование коммитов, git cherry-pick
  • * 14. Отмена и редактирование последнего коммита
  • * 15. Отмена произвольного коммита, git revert
  •    16. Склеивание коммитов, git rebase —interactive и git reflog
  • * 17. Зачем склеивать коммиты. Плюсы и минусы сквоша
  • * 18. Работа с git rebase. Отличия от merge
  • * 19. Что такое git push —force и как с ним работать
  • * 20. Ищем баги с помощью git, git bisect
  • * 21. Как и зачем работать с тегами git
  • * 22. Процессы: github flow и git flow
  • * 23. Псевдонимы в git
  •    24. Мердж-реквесты
  • * 25. Форки

* платные уроки

список обновляется…

The git log command is used for listing and filtering the project history and searching for particular changes. Let’s figure out how you can retrieve hash for commits below.

You can use git log -1 to show the information about the latest commit, and from that information, you can get the commit hash by using the --format option as shown below:

git log -1 --format=format:"%H"

# 2701112aee3d8a7ba13099b1aefec53e1fd3ca3a

Here, %H means commit hash.

As an alternative, you can use the git-rev-parse command, which will return the hash of the latest git commit:

git rev-parse HEAD

# 2701112aee3d8a7ba13099b1aefec53e1fd3ca3a

If you want to turn references (branches and tags) into hash, you can use git show-ref and git for-each-ref commands.

In case you want to get only the first 8 digits, you can use the cut -c 1-8 filter in the following way:

git rev-parse HEAD | cut -c 1-8

# 2701112a

Using the git reflog command is also used if you want to have the history on the head of your branches. With this command, you can find the line referring to the state you want to get back. After getting the hash of the commit you can restore it by using git cherry-pick.

The git log command displays the committed snapshots. It only works on the committed history, whereas git status controls the working directory and the staging area.

The git log command examines a repository’s history and finds a particular version of a project. Log output can be personalized differently, from filtering commits to displaying them in an entirely user-defined format.

The --format option pretty-prints the contents of the commit logs in a specified format, where <format> can be oneline, short, medium, eference, email, full, fuller, raw, format:<string> and tformat:<string>. When <format> is not specified and has %placeholder, it will act as if --pretty=tformat:<format> were specified.

I’m not going to edit your question since I cannot be sure that this is your intent, but it sounds like your real question comes down to this:

Suppose I have a directory full of source code. Suppose further that I believe this directory-of-source-code was created by running a series of git commands, such as:

git checkout [some hash ID]
git cherry-pick [another hash ID]

but Evil Spirits, or fluoridation, or some such, has lost the .git directory. So all I have now is this tree of code. Let’s call this «my lost tree».

Meanwhile, on some other machine or in some other directory, I do have a full Git repository. I am curious as to what commit or commits (there may be more than one) would, if I ran git checkout <hash>, get me a work-tree that is identical to my lost tree.

Now, it’s not clear what the point of all this is, but it is possible to do, with some caveats. The easy way to do it is to add the lost tree to the full Git repository—or, if you are concerned about precious bodily fluids :-) (see the «fluoridation» link above), to a git clone --mirror of it. (The clone is «as good as» the original, but can be thrown away after this process.)

Things to know before steps 1 and 2

In any normal Git repository, there are three things of interest while you are working on making a new commit:

  • the current commit, which is your HEAD;
  • the index, which is where you build the new commit; and
  • the work-tree, which is where you keep files in a form the rest of the computer can deal with, as the files stored in the current commit and in the index are in a form only Git can deal with.

As I mentioned in a comment, the repository database itself has four object types: blob (a file); tag (an annotated tag: a human-readable name for some commit object, plus some other metadata); commit (metadata including a log message, an author and committer, the parent commit(s) IDs of the commit—it’s these parent IDs that produce the history, when commits are viewed according to parent/child relationships); and tree. A tree object contains the names and hash-IDs of blobs and of additional sub-trees, and hence could represent a tree of files identical to your lost tree. Each commit has, as part of its metadata, the hash ID of the commit’s stored snapshot, i.e., the tree. So if your lost tree is in fact in the repository, its hash ID is stored in some commit(s).

We will make use of the fact that, once some object is in the repository, any attempt to put a bit-for-bit-identical new object into the repository simply re-uses the existing object. Making one grand assumption,1 this re-use is fundamentally safe: if the new object is bit-for-bit identical to the old object, why would you care which object—new or old—Git pulls out later when you ask Git to retrieve the object by its hash ID?


1The assumption is that no two different objects produce the same hash ID, ever. The pigeonhole principle tells us that this assumption is false in theory, but in practice, it’s actually true. It is possible, but currently very expensive, to break the assumption deliberately. A longer hash ID can—again, in theory at least—be less-breakable, although cryptography is always getting weirder. :-)

In fact, if two different Git objects do produce the same hash, Git breaks … well, sort of; it breaks, or should break, in a «safe» manner. The example PDFs that break SHA-1 do not actually break Git, though. Other files could—but meanwhile, some minor coding glitches in existing versions of Git apparently cause it to fail to alert the user to the fact that it will fail to store some new version in your repository.


Step 1: Finding the hash ID of your lost tree

The work-tree corresponds to your lost tree, but Git won’t make a tree object out of a work-tree. Git will only make a tree object out of the index. This means that in order to find the hash ID of your lost tree, you must copy it into the index.

The index already has stuff in it, so your first step is to remove all of it. In the top level of your Git repository, tell Git to remove everything, both from the work-tree and from the index:

git rm -rf .

You should now have an empty work-tree … unless—this is one of the caveats—there are untracked files.2 If there are some untracked files, you will have to find out (or guess) whether those are also in your lost tree, and whether they will also be untracked in the commit(s) in the full repository that use that same tree. I leave it to you to find solutions to this problem, should you actually have this problem. (It’s possible that even if there are untracked files in the repository, they were and are not present in your lost tree.)

In any case, you probably want to discard any untracked files at this point. If there are any, you can use git clean -fdx to discard them. (This can be a good reason to work on a fresh mirror clone: it won’t have any such untracked files in the first place, and removing such files from a real work-tree may force you to rebuild them later, which for a large project, might be many CPU-hours of computation.)

Now that your Git index and work-tree are empty, we will re-fill them from the lost tree:

(cd /path/to/lost/tree; tar cf - .) | tar xf -

or:

cp -R /path/to/lost/tree .

or whatever, so that the work-tree is now a copy of the lost tree.

(At this point, you must throw out, from the copy, any files that should be untracked. Since we removed everything, we also removed any .gitignore files that we had before, so files that would be ignored, if this were a normal setup, won’t be, unless those .gitignore files are in your lost tree. Again, how you do this, if you need to do it at all, is up to you.)

Second-to-last, we now want to populate our index from this work-tree. This part is simple:

git add .

does the trick. We now have a full index and can produce a tree object and find its hash.

The «normal» way to do this is to make a new commit. If we make a new commit now, it will have as its parent, our current (HEAD) commit. It will be added to our current branch. There’s nothing wrong with this, but that’s not our goal at this point, so we can use a lower-level Git command, one of the so-called plumbing commands:

git write-tree

What this does is turn the index into a series of tree objects, one for each sub-directory (and that sub-directory’s files) stored in the index, and one final top-level tree, for the files and sub-directories at the top level, i.e., for .. The output is the hash ID of the object just added to—or reused from—the existing Git object database:

$ git write-tree
b3bb4696cf8dcb93c1f09a447f6b7356bccb24d2

This tree hash is what we are looking for, but it’s not a commit hash. We simply believe that there may be one, two, or many existing commits that have this tree as their hash.3


2An untracked file is simply one that is not in the index. This simple definition is not a problem for us unless and until it becomes a very big problem: if your lost tree contains untracked files, you don’t know which ones are untracked because the index that made them untracked was part of the Git repository you lost when you acquired the lost tree in the first place!

3If we use git commit to make a new commit, the new commit we just made will have this hash as its tree object. That’s not the commit we’re looking for, of course—but if you use git commit instead of git write-tree, this is something to keep in mind.


Step 2: finding commits that have this tree

The remaining caveat, of course, is that it’s quite possible that no commit has the tree your just made; or it may be in two or more commits. The latter occurs from time to time due to git revert or trivial merges (merges that could be, but on purpose are not, fast-forwards). The way to deal with this is to find all such commits, then decide which one(s) you want.

To find these commits, our first sub-step is to enumerate every commit in the repository. We need their hash IDs, so that we can use another Git plumbing command to find their tree ID (remember, each commit has exactly one tree). The command to find every commit or other object reachable from some name is git rev-list; the option to use all names is --all; so:

git rev-list --all

does the trick. This prints each hash ID to its standard output stream, so we will now collect all those IDs and turn them into their corresponding tree hashes.

One slight wrinkle here is in the phrasing above: this finds all commits or other objects, including annotated tag objects. An annotated tag is a name for another Git object, usually a commit object. So if we find that annotated tag v1.3 and commit 1234567... both name your lost tree, we’ll see two hash IDs here. That’s probably actually what we want, but if not, you now know what to look for to change this.

In any case, to turn the rev-list ID into a tree, we will want to use git rev-parse. It’s possible that the ID cannot be turned into a tree: an annotated tag object, for instance, might tag a blob object rather than a commit. So for a fully robust solution we should check, using git rev-list --verify --quiet and checking its return value:

lookfor=...put in the hash ID you are searching for ...
git rev-list --all |
    while read hash; do
        tree=$(git rev-parse --verify --quiet ${hash}^{tree}) || continue
        if [ $tree = $lookfor ]; then
            echo "found: $hash (type $(git cat-file -t $hash)) names tree $lookfor"
        fi
    done

(the above is untested but it’s too simple to be wrong).

If this finds any objects that refer to your lost tree, you now have the hashes (of commits and/or tags) for it.

If this finds no objects, that means that either you put in the wrong tree—see the caveat about untracked files—or the tree you have does not have a corresponding commit. That does not mean it never had one: perhaps your lost tree was part of an experimental branch that was deleted and had all its commits thrown out during garbage collection, for instance. It just means that no commit has that tree now, in your full repository (or its mirror-clone).

Понравилась статья? Поделить с друзьями:
  • Как исправить вид экрана
  • Как договориться с домовым чтобы найти вещь
  • Как найти объем реализованной продукции в балансе
  • Как найти свой код любви
  • Как составить заявление в приказном порядке