|
| 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 <[email protected]> 1749697268 +0800 |
| 83 | +committer sharpchen <[email protected]> 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 | + |
0 commit comments