|
| 1 | +#Commit |
| 2 | + |
| 3 | +Commits are snapshots for each phase of the repository, which allowing you to rollback to any instance of that commit. |
| 4 | +Git is able to compare base on two commits(usually the current and last commit), which is the diff. |
| 5 | + |
| 6 | +- Each commit stores a snapshot of current repository with a unique hash to be identified. |
| 7 | +- A commit can have**one or more** parent from which it was derived. |
| 8 | +- Each snapshot file or folder has a unique hash, and can inspect their content in some way. |
| 9 | +- the folder snapshot is called`tree` |
| 10 | +- the file snapshot is`blob` |
| 11 | +- a commit always shows the snapshot of root of the repository as entry of a commit |
| 12 | + |
| 13 | +>[!NOTE] |
| 14 | +>*Revision* is another synonym of*Commit* in git. |
| 15 | +
|
| 16 | +>[!IMPORTANT] |
| 17 | +>**Commit** is the atomic identifier of how git manage the versions, it's the*true* and*real* concept while*branch* and*merge* are just*fake* concepts upon it. |
| 18 | +
|
| 19 | +##Commit Identifier |
| 20 | + |
| 21 | +Each commit is identified by the uniquely generated SHA hash, you can reference the commit using the full hash or the leading 7 digit hash on git commands. |
| 22 | +Each snapshot instance of that particular commit could be found on`.git/objects/<first-2digits-of-hash>/<restof-hash>` |
| 23 | + |
| 24 | +>[!NOTE] |
| 25 | +>Those*identifier* of commits are called*refs* in git, you could find their representations in`.git/refs` |
| 26 | +
|
| 27 | +1.**commit hash**: the most explicit identification of a commit. |
| 28 | +2.**branch name**: points to**latest** commit of the branch. |
| 29 | +3.**tag name**: points to the commit of that tag. |
| 30 | +4.`HEAD` or`@`: points to the**current** commit you're at. |
| 31 | +- for some other special identifier names, see documentation. |
| 32 | +5.`-` or`@{-1}`: previous commit you're at. |
| 33 | +-`-` is not a valid identifier in some scenarios, but you can use it in like`git checkout -` or`git merge -`. |
| 34 | +6.**commit expression**: see next section. |
| 35 | + |
| 36 | +###Commit Expression |
| 37 | + |
| 38 | +Commit expression is special syntax to reference commits backward from a given point. |
| 39 | +Three special symbols for traversing back in git: |
| 40 | + |
| 41 | +1.`@`: reference backward through***reflog***, you can see such symbol like`HEAD@{1}` in`git reflog` output. |
| 42 | +-`@{-<n>}`: go to nth previously checked out commit by`git checkout` |
| 43 | +-`<commit_identifier>@{<n>}`: go to previous nth commit |
| 44 | +-`@{<n>}` is equivalent to`<current_branch>@{<n>}`, this is only valid when you're on a branch. |
| 45 | +2.`~`: trace back to previous commits through**the first parent** only. |
| 46 | +-`<identifier>~3`: points to previous 3 commit from current branch. |
| 47 | +3.`^`: trace back to previous commits through a specified parent by its index. |
| 48 | +-`<identifier>^2`: points to previous commit through**second** parent of`<identifier>`. |
| 49 | +-`<identifier>^101`: if you're wild enough to merge from 100 branches, you might need to point to previous commit through the 101-th parent. |
| 50 | + |
| 51 | +>[!TIP] |
| 52 | +>`~1` and`^1` are always equivalent since they would pick the same first parent of the commit. |
| 53 | +
|
| 54 | +>[!NOTE] |
| 55 | +>See`git help revisions` for more details |
| 56 | +
|
| 57 | +>[!TIP] |
| 58 | +>You can expand the commit hash by special identifier using`git rev-parse <identifier>` |
| 59 | +>```console |
| 60 | +>$ git rev-parse @~1 |
| 61 | +>42804017200559f28d12757e729f95dbd18f4998 |
| 62 | +>$ git rev-parse main |
| 63 | +>e7bbe687097f56d152c2291190b67d91eed4cd57 |
| 64 | +>``` |
| 65 | +
|
| 66 | +## Commit Inspection |
| 67 | +
|
| 68 | +Commit inspection generally requires `git cat-file -p <hash>`, see `git help cat-file`. |
| 69 | +
|
| 70 | +A commit can contain elements: |
| 71 | +- `tree`: the structure of current snapshot, including files and folders. |
| 72 | +- `parent`: the parent commit it was derived from, a commit can have multiple parents. |
| 73 | +- `author`: who did the changes. |
| 74 | +- `committer`: who made the commit, may differ from `author` when rebasing. |
| 75 | +- and more... |
| 76 | +
|
| 77 | +```console |
| 78 | +$git cat-file -p 5eb5a747cfd9b17603b79d7ab64fc4ecee1751e3 |
| 79 | +
|
| 80 | +tree e060913d1a04d39082981dc116c5a5cd35ba8e52 |
| 81 | +parent 02348ec70c2c901e9ecc4be5860330e6dcf911ff |
| 82 | +author sharpchen <rui.chen.sharp@gmail.com> 1749697268 +0800 |
| 83 | +committer sharpchen <rui.chen.sharp@gmail.com> 1749697268 +0800 |
| 84 | +``` |
| 85 | +
|
| 86 | +>[!TIP] |
| 87 | +>It's more general to use`git show <commit_identifier>` to inspect a commit. |
| 88 | +
|
| 89 | +###Tree & Blob Inspection |
| 90 | + |
| 91 | +Tree in the inspected commit is a**recursive** structure and also has a hash that can be inspected by`git cat-file -p <hash>`. |
| 92 | +A`blob` represents a real file, a`tree` represents a folder as a container. |
| 93 | +So the tree printed from the commit is actually**the root folder of your repository**. |
| 94 | + |
| 95 | +```console |
| 96 | +$git cat-file -p e060913d1a04d39082981dc116c5a5cd35ba8e52 |
| 97 | + |
| 98 | +100644 blob 397b4a7624e35fa60563a9c03b1213d93f7b6546 .gitignore |
| 99 | +100644 blob 67f24d19be001eebf7bcdde488d8ab594bcd969d PSScriptAnalyzerSettings.psd1 |
| 100 | +100644 blob 4bd5bb6fcff0b514d0160f3cb8ff01b5de46eeb4 README.md |
| 101 | +100644 blob 207846dc4b8f93edd892df9b6058ded48f5355b8 dotfiles.ps1 |
| 102 | +100755 blob fa9fe71978d17992a3f27eaf78f2619a25a1966d dotfiles.sh |
| 103 | +040000 tree 0199c6476a45a6dadadaf7baf70a136d7f8f217f dotfiles |
| 104 | +100644 blob b6e1531298fed5dc7a019f6c01018b5c1add3c99 flake.lock |
| 105 | +100644 blob 92d9549668557adb021f959f8b898ad96ee84efb flake.nix |
| 106 | +100644 blob bb166d071cb8541aac7df35b7c1f5dbf420dd70c home.nix |
| 107 | +100644 blob baa979aff962214ddb5e23502acdb211d8d32064 install.ps1 |
| 108 | +040000 tree c1aef838a425cd6f209ecc01f28bef2208fd2d26 packages |
| 109 | +``` |
| 110 | + |
| 111 | +You can either go deeper to the nested`tree` or inspect the snapshot content of a`blob` using the same way. |
| 112 | + |
| 113 | +```console |
| 114 | +$git cat-file -p 67f24d19be001eebf7bcdde488d8ab594bcd969d |
| 115 | + |
| 116 | +@{ |
| 117 | + IncludeRules = @('PSAvoidTrailingWhitespace') |
| 118 | +} |
| 119 | +``` |
| 120 | + |
| 121 | +##Checkout Commit |
| 122 | + |
| 123 | + |