Compare commits

...

8 Commits

  1. 6
      .gitmodules
  2. 3
      archetypes/default.md
  3. 292
      config.toml
  4. 236
      content/post/renames-in-git-explained.md
  5. 219
      content/posts/renames-in-git-explained.md
  6. 149
      static/publickey.asc
  7. 1
      themes/even
  8. 1
      themes/hermit

6
.gitmodules vendored

@ -1,3 +1,3 @@
[submodule "themes/hermit"]
path = themes/hermit
url = https://github.com/Track3/hermit.git
[submodule "themes/even"]
path = themes/even
url = git@github.com:Mithror/hugo-theme-even.git

@ -2,5 +2,8 @@
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
toc: true
tags: []
author: "Gaël Depreeuw"
---

@ -1,77 +1,229 @@
baseURL = "https://depreeuw.dev"
languageCode = "en-us"
languageCode = "en"
defaultContentLanguage = "en"
title = "Gaël Depreeuw"
theme = "hermit"
# enableGitInfo = true
pygmentsCodefences = true
pygmentsUseClasses = true
# hasCJKLanguage = true # If Chinese/Japanese/Korean is your main content language, enable this to make wordCount works right.
rssLimit = 10 # Maximum number of items in the RSS feed.
copyright = "This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License." # This message is only used by the RSS template.
enableEmoji = true # Shorthand emojis in content files - https://gohugo.io/functions/emojify/
# googleAnalytics = "UA-123-45"
# disqusShortname = "yourdiscussshortname"
[author]
preserveTaxonomyNames = true
enableRobotsTXT = true
enableEmoji = true
theme = "even"
enableGitInfo = true # use git commit log to generate lastmod record
# Syntax highlighting by Chroma. NOTE: Don't enable `highlightInClient` and `chroma` at the same time!
pygmentsOptions = "linenos=table"
pygmentsCodefences = true
pygmentsUseClasses = true
pygmentsCodefencesGuessSyntax = true
paginate = 5
copyright = "Gaël Depreeuw"
[author] # essential
name = "Gaël Depreeuw"
[blackfriday]
# hrefTargetBlank = true
# noreferrerLinks = true
# nofollowLinks = true
[taxonomies]
tag = "tags"
# Categories are disabled by default.
[sitemap] # essential
changefreq = "weekly"
priority = 0.5
filename = "sitemap.xml"
[[menu.main]] # config your menu # 配置目录
name = "Home"
weight = 10
identifier = "home"
url = "/"
[[menu.main]]
name = "Archives"
weight = 20
identifier = "archives"
url = "/post/"
[[menu.main]]
name = "Tags"
weight = 30
identifier = "tags"
url = "/tags/"
[[menu.main]]
name = "Categories"
weight = 40
identifier = "categories"
url = "/categories/"
[params]
dateform = "Jan 2, 2006"
dateformShort = "Jan 2"
dateformNum = "2006-01-02"
dateformNumTime = "2006-01-02 15:04 -0700"
# Metadata mostly used in document's head
# description = ""
# images = [""]
themeColor = "#494f5c"
homeSubtitle = "A website about my tips and general thoughts."
footerCopyright = ' &#183; <a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener">CC BY-NC 4.0</a>'
# bgImg = "" # Homepage background-image URL
# Prefix of link to the git commit detail page. GitInfo must be enabled.
# gitUrl = "https://github.com/username/repository/commit/"
# Toggling this option needs to rebuild SCSS, requires Hugo extended version
justifyContent = false # Set "text-align: justify" to `.content`.
relatedPosts = false # Add a related content section to all single posts page
code_copy_button = true # Turn on/off the code-copy-button for code-fields
# Add custom css
# customCSS = ["css/foo.css", "css/bar.css"]
# Social Icons
# Check https://github.com/Track3/hermit#social-icons for more info.
[[params.social]]
name = "github"
url = "https://github.com/mithror"
[[params.social]]
name = "nextcloud"
url = "https://nextcloud.depreeuw.dev/"
[menu]
[[menu.main]]
name = "Posts"
url = "posts/"
weight = 10
[[menu.main]]
name = "About"
url = "about-hugo/"
weight = 20
version = "4.x" # Used to give a friendly message when you have an incompatible update
debug = false # If true, load `eruda.min.js`. See https://github.com/liriliri/eruda
since = "2020"
# use public git repo url to link lastmod git commit, enableGitInfo should be true.
# 指定 git 仓库地址,可以生成指向最近更新的 git commit 的链接,需要将 enableGitInfo 设置成 true.
gitRepo = "https://gitea.depreeuw.dev/Mithror/main-site"
# site info (optional) # 站点信息(可选,不需要的可以直接注释掉)
logoTitle = "Gaël Depreeuw" # default: the title value # 默认值: 上面设置的title值
keywords = ["git", "blog","hugo", "even"]
description = "Gaël Depreeuw's personal site"
# paginate of archives, tags and categories # 归档、标签、分类每页显示的文章数目,建议修改为一个较大的值
archivePaginate = 50
# show 'xx Posts In Total' in archive page ? # 是否在归档页显示文章的总数
showArchiveCount = false
# The date format to use; for a list of valid formats, see https://gohugo.io/functions/format/
dateFormatToUse = "2006-01-02"
# show word count and read time ? # 是否显示字数统计与阅读时间
moreMeta = false
# Syntax highlighting by highlight.js
highlightInClient = false
# 一些全局开关,你也可以在每一篇内容的 front matter 中针对单篇内容关闭或开启某些功能,在 archetypes/default.md 查看更多信息。
# Some global options, you can also close or open something in front matter for a single post, see more information from `archetypes/default.md`.
toc = true # 是否开启目录
autoCollapseToc = false # Auto expand and collapse toc # 目录自动展开/折叠
fancybox = true # see https://github.com/fancyapps/fancybox # 是否启用fancybox(图片可点击)
# mathjax
mathjax = false # see https://www.mathjax.org/ # 是否使用mathjax(数学公式)
mathjaxEnableSingleDollar = false # 是否使用 $...$ 即可進行inline latex渲染
mathjaxEnableAutoNumber = false # 是否使用公式自动编号
mathjaxUseLocalFiles = false # You should install mathjax in `your-site/static/lib/mathjax`
postMetaInFooter = true # contain author, lastMod, markdown link, license # 包含作者,上次修改时间,markdown链接,许可信息
linkToMarkDown = false # Only effective when hugo will output .md files. # 链接到markdown原始文件(仅当允许hugo生成markdown文件时有效)
contentCopyright = '' # e.g. '<a rel="license noopener" href="https://creativecommons.org/licenses/by-nc-nd/4.0/" target="_blank">CC BY-NC-ND 4.0</a>'
changyanAppid = "" # Changyan app id # 畅言
changyanAppkey = "" # Changyan app key
livereUID = "" # LiveRe UID # 来必力
baiduPush = false # baidu push # 百度
baiduAnalytics = "" # Baidu Analytics
baiduVerification = "" # Baidu Verification
googleVerification = "" # Google Verification # 谷歌
# Link custom CSS and JS assets
# (relative to /static/css and /static/js respectively)
customCSS = []
customJS = []
uglyURLs = false # please keep same with uglyurls setting
[params.publicCDN] # load these files from public cdn # 启用公共CDN,需自行定义
enable = true
jquery = '<script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>'
slideout = '<script src="https://cdn.jsdelivr.net/npm/slideout@1.0.1/dist/slideout.min.js" integrity="sha256-t+zJ/g8/KXIJMjSVQdnibt4dlaDxc9zXr/9oNPeWqdg=" crossorigin="anonymous"></script>'
fancyboxJS = '<script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.js" integrity="sha256-XVLffZaxoWfGUEbdzuLi7pwaUJv1cecsQJQqGLe7axY=" crossorigin="anonymous"></script>'
fancyboxCSS = '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.css" integrity="sha256-7TyXnr2YU040zfSP+rEcz29ggW4j56/ujTPwjMzyqFY=" crossorigin="anonymous">'
timeagoJS = '<script src="https://cdn.jsdelivr.net/npm/timeago.js@3.0.2/dist/timeago.min.js" integrity="sha256-jwCP0NAdCBloaIWTWHmW4i3snUNMHUNO+jr9rYd2iOI=" crossorigin="anonymous"></script>'
timeagoLocalesJS = '<script src="https://cdn.jsdelivr.net/npm/timeago.js@3.0.2/dist/timeago.locales.min.js" integrity="sha256-ZwofwC1Lf/faQCzN7nZtfijVV6hSwxjQMwXL4gn9qU8=" crossorigin="anonymous"></script>'
flowchartDiagramsJS = '<script src="https://cdn.jsdelivr.net/npm/raphael@2.2.7/raphael.min.js" integrity="sha256-67By+NpOtm9ka1R6xpUefeGOY8kWWHHRAKlvaTJ7ONI=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/flowchart.js@1.8.0/release/flowchart.min.js" integrity="sha256-zNGWjubXoY6rb5MnmpBNefO0RgoVYfle9p0tvOQM+6k=" crossorigin="anonymous"></script>'
sequenceDiagramsCSS = '<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/bramp/js-sequence-diagrams@2.0.1/dist/sequence-diagram-min.css" integrity="sha384-6QbLKJMz5dS3adWSeINZe74uSydBGFbnzaAYmp+tKyq60S7H2p6V7g1TysM5lAaF" crossorigin="anonymous">'
sequenceDiagramsJS = '<script src="https://cdn.jsdelivr.net/npm/webfontloader@1.6.28/webfontloader.js" integrity="sha256-4O4pS1SH31ZqrSO2A/2QJTVjTPqVe+jnYgOWUVr7EEc=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/snapsvg@0.5.1/dist/snap.svg-min.js" integrity="sha256-oI+elz+sIm+jpn8F/qEspKoKveTc5uKeFHNNVexe6d8=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/underscore@1.8.3/underscore-min.js" integrity="sha256-obZACiHd7gkOk9iIL/pimWMTJ4W/pBsKu+oZnSeBIek=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/gh/bramp/js-sequence-diagrams@2.0.1/dist/sequence-diagram-min.js" integrity="sha384-8748Vn52gHJYJI0XEuPB2QlPVNUkJlJn9tHqKec6J3q2r9l8fvRxrgn/E5ZHV0sP" crossorigin="anonymous"></script>'
# Display a message at the beginning of an article to warn the readers that it's content may be outdated.
# 在文章开头显示提示信息,提醒读者文章内容可能过时。
[params.outdatedInfoWarning]
enable = false
hint = 30 # Display hint if the last modified time is more than these days ago. # 如果文章最后更新于这天数之前,显示提醒
warn = 180 # Display warning if the last modified time is more than these days ago. # 如果文章最后更新于这天数之前,显示警告
[params.gitment] # Gitment is a comment system based on GitHub issues. see https://github.com/imsun/gitment
owner = "" # Your GitHub ID
repo = "" # The repo to store comments
clientId = "" # Your client ID
clientSecret = "" # Your client secret
[params.utterances] # https://utteranc.es/
owner = "" # Your GitHub ID
repo = "" # The repo to store comments
[params.gitalk] # Gitalk is a comment system based on GitHub issues. see https://github.com/gitalk/gitalk
owner = "" # Your GitHub ID
repo = "" # The repo to store comments
clientId = "" # Your client ID
clientSecret = "" # Your client secret
# Valine.
# You can get your appid and appkey from https://leancloud.cn
# more info please open https://valine.js.org
[params.valine]
enable = false
appId = '你的appId'
appKey = '你的appKey'
notify = false # mail notifier , https://github.com/xCss/Valine/wiki
verify = false # Verification code
avatar = 'mm'
placeholder = '说点什么吧...'
visitor = false
[params.flowchartDiagrams]# see https://blog.olowolo.com/example-site/post/js-flowchart-diagrams/
enable = false
options = ""
[params.sequenceDiagrams] # see https://blog.olowolo.com/example-site/post/js-sequence-diagrams/
enable = false
options = "" # default: "{theme: 'simple'}"
[params.busuanzi] # count web traffic by busuanzi # 是否使用不蒜子统计站点访问量
enable = false
siteUV = true
sitePV = true
pagePV = true
[params.reward] # 文章打赏
enable = false
wechat = "/path/to/your/wechat-qr-code.png" # 微信二维码
alipay = "/path/to/your/alipay-qr-code.png" # 支付宝二维码
[params.social.asFont] # 社交链接
a-email = "mailto:gael@depreeuw.dev"
# b-stack-overflow = "http://localhost:1313"
# c-twitter = "http://localhost:1313"
# d-facebook = "http://localhost:1313"
# e-linkedin = "http://localhost:1313"
# f-google = "http://localhost:1313"
b-github = "https://github.com/Mithror"
# h-weibo = "http://localhost:1313"
# i-zhihu = "http://localhost:1313"
# j-douban = "http://localhost:1313"
# k-pocket = "http://localhost:1313"
# l-tumblr = "http://localhost:1313"
# m-instagram = "http://localhost:1313"
# n-gitlab = "http://localhost:1313"
# o-bilibili = "http://localhost:1313"
[params.social.asSVG]
a-gitea = "https://gitea.depreeuw.dev/Mithror"
b-nextcloud = "https://nextcloud.depreeuw.dev"
# See https://gohugo.io/about/hugo-and-gdpr/
[privacy]
[privacy.googleAnalytics]
anonymizeIP = true # 12.214.31.144 -> 12.214.31.0
[privacy.youtube]
privacyEnhanced = true
# see https://gohugo.io/getting-started/configuration-markup
[markup]
[markup.tableOfContents]
startLevel = 1
[markup.goldmark.renderer]
unsafe = true
# 将下面这段配置取消注释可以使 hugo 生成 .md 文件
# Uncomment these options to make hugo output .md files.
#[mediaTypes]
# [mediaTypes."text/plain"]
# suffixes = ["md"]
#
#[outputFormats.MarkDown]
# mediaType = "text/plain"
# isPlainText = true
# isHTML = false
#
#[outputs]
# home = ["HTML", "RSS"]
# page = ["HTML", "MarkDown"]
# section = ["HTML", "RSS"]
# taxonomy = ["HTML", "RSS"]
# taxonomyTerm = ["HTML"]

@ -0,0 +1,236 @@
---
title: "Renames in Git explained"
date: 2020-11-28T12:07:00Z
draft: false
toc: true
tags: ['tech', 'git', 'rename']
author: "Gaël Depreeuw"
---
## Introduction
One of the questions I'm often asked when teaching or explaining Git is how Git
handles file and/or directory renames. The short answer to this is: **It**
**doesn't**.
The slightly longer answer is: **It does, but probably not in the way you**
**envision it?**.
Let's first take a look at how Git works internally. If you don't quite
understand everything which follows, I can recommend reading chapter 10 of
the [Git Pro Book 2nd. Edition](https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain).
## Git stores content, not files
When you commit to a Git repository it basically does the following:
Create a **blob** object for every file in the index (a.k.a. the staging area).
A blob object is created by taking the content of the file, prepending a header
and compressing the result. A SHA-1 hash is then calculated for this object
which will be used to identify the object. The object is stored in the aptly
named object store (found in `.git/objects`). The first 2 characters of the
hash (in hex format) are used as a directory within this store, while the
remaining characters are the filename of the blob object.
Let's look at an example. Create a git repo somewhere and create a file.
```bash
git init foo
cd foo
echo "foo" >> foo.txt
```
If you look into your `.git/objects` directory, it will be empty, aside from
two empty subdirectories. Let's create a blob out of this file now.
```bash
$ git hash-object -w foo.txt
257cc5642cb1a054f08cc83f2d943e56fd3ebe99
```
You will now find an object in the store:
```bash
$ find .git/objects -type f
.git/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99
```
Here's an interesting exercise: what happens if you rename the file and create
the blob with the renamed file?
```bash
$ mv foo.txt bar.txt
$ git hash-object -w bar.txt
257cc5642cb1a054f08cc83f2d943e56fd3ebe99
```
That's right, nothing changed! This makes sense as we're only adding the content
to the object store! So how does Git remember the file names?
## Filenames are part of tree objects
Aside from **blob** objects, Git also creates **tree** objects. You can sort of
compare it to the directories in your worktree, i.e. for each directory in your
worktree, you will have a tree object. A tree object's content looks like:
```code
<mode> <type> <hash> <name>
...
<mode> <type> <hash> <name>
```
You can create a tree object yourself by doing:
```bash
$ git update-index --add --cacheinfo 100644 \
257cc5642cb1a054f08cc83f2d943e56fd3ebe99 foo.txt
$ git write-tree
fcf0be4d7e45f0ef9592682ad68e42270b0366b4
$ git cat-file -p fcf0be4d7e45f0ef9592682ad68e42270b0366b4
100644 blob 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 foo.txt
```
There are 3 different types (that I know of) which can be referred to in a tree
object: blob, tree, commit. Blobs represent file content, tree represent other
tree (i.e. subdirectories) and commits represent submodules (i.e the commit
at which they are included). A commit is a type of object which is also present
outside the tree objects. They contain the top tree object (representing the
top level of your repository), a link to one or more parent commits and some
meta data (author, commit msg, date, ...). Finally and for completion's sake,
there is also an object for annotated tags, which contain the commit it is
pointing too as well as some meta data.
## Renaming
Armed with the knowledge about trees and blobs, it should be fairly easy to
understand what happens if you rename a file. To make it easier to understand,
consider a simple example: we just rename a file at the top level.
> Note: more complex examples are just more time consuming to explain, but
> not to understand. The same principles apply.
In case of such a rename, when you commit this rename, your repository will
be impacted as follows:
- The blob representing the file remains unchanged.
- The top level tree object changes as well because the filename associated with
the blob is different.
- The commit object will point to the new tree. (Its parent will point to the
old tree.)
Nowhere is there any special mention of a rename occuring. Remember, we're just
storing content! As such Git is not aware of any name changes. This is why the
short answer was: Git doesn't handle file renames. The repository itself has no
notion of this action. It's just has content and a structure for that content.
However, that does not mean you lose your history when you rename a file.
### How to see history of a renamed file
Git might not store information on renames in the repository but it does come
packed with an algorithm that detects file renames. The way it works is that for
every add/delete pair added to the index, it tries to determine a rename
candidate for every deleted file. It does this by comparing how similar the
paired files are. If they are at least 50% similar, it considered the pair to
have been a rename. If there are multiple rename candidates for one file, it
takes the one with the highest similarity percentage. If multipe files have the
same percentage, it picks one depending on the implementation.
> **Note**: I believe, but am not sure, it basicaly takes the first
> alphabeticaly match in the last case.
By default `git log -- <file>` does not track accross renames. If you want to
do see the history across renames, you will need to add the `--follow` option.
You can also define the treshold percentage to be different from 50%. This is
done via the `-M<n>` or `--find-renames=<n>` option. See the git documentation
for the correct syntax.
You can also turn off rename detection by doing `--no-renames`
### Rename best practice
Because of the treshold and the cheapness of commits, it is recommended that
when you rename a file/directory, you commit those renames first, before you
continue working on the renamed file. This basically makes it so you can use
a treshold of 100% all the time.
### Why did Git do it this way
This is pure speculation, but here's my thoughts on it:
Filenames are actually part of the underlying file systems, so for a version
controls system to support multiple file system they have to handle filenames
in their own way. This includes renames. If you think about what this would
require for Git, it would not be very straightforward: Git could have chosen to
provide a command to store rename data, let's say: `git rename fileA fileB`, but
what should this command do? We can image it could create new '**rename**
object, which would hold the blob hash and the name of the previous file. Now,
every time you would walk through history, when you encounter this object type,
you would need to remember this redirections. There's probably a lot of little
nuances which are not immediately apparent though and it does not deal with one
of the major drawbacks of this new command: What happens if the user forgets it
and just does `mv fileA fileB`?
Well, we'd actually want to have some mechanism to detect this as a rename as
once this is commited it becomes more difficult to undo this change
(especially if we already pushed the commit!). So it sure would be nice if Git
could somehow figure out that it was a rename. Which is exactly what they did.
But now that we have this functionality, what actually is the point of the
new command we wanted to implement? This is probably highly subjective, but to
me it seems completely irrelevant now. Instead of having a command which can be
forgotten and for which we need contigency, just use the contigency as the
solution! It makes the behaviour a lot more consistent!
### Can I fix my commit if I did change a lot of content after renaming
First, to prevent this: always check using `git status` whether are not the
rename is being detected. Now, how to solve it?
It depends. If your commit is local only and it is the last commit, then you can
fix this easily. There are many ways to to it, but one option is:
```bash
git mv <newname> <oldname> # Undo the file rename
git commit --amend # Commit the changes to the file
git mv <oldname> <newname> # Rename the file
git commit # Commit the rename
```
If you want to rename first and the changes second you can also do this, but
it is a bit more complex:
```bash
git reset --soft HEAD~ # Go back one commit, but keep the changes
git restore --staged <oldname> <newname> # unstage the deletion and addition
git restore <oldname> # undelete the old file
mv <newname> <newname.tmp> # make a temp backup of the new file
git mv <oldname> <newname> # Rename the old file
git commit # commit the rename
cp <newname.tmp> <newname> # apply the new changes
git commit -a # Commit the changes
```
If the commit is already a couple of commits ago, you can do the same with an
interactive rebase and doing either of the above at the correct time.
If you already pushed your commits you will have to check with the team if you
can rewrite the history and push it. If this is not possible, you might need to
find the right treshold to have Git mark it as a rename.
## Summary
So in summary: no, Git does not store renames in its repository. Instead, for
every add/delete pair in a commit, Git will do an similarity analysis and
when they are X% alike (default 50%), it will assume a rename occured.
Some commands influenced by this are: `git log`, `git diff` and `git merge`.
Options related to renames are:
```txt
-M=<n>, --find-renames=<n> # where n is the treshold percentage.
--no-renames # don't do any rename detection
```
It is best practise to handle renames in their own commits. Try to avoid
renaming and modifying a file within the same commit.

@ -1,219 +0,0 @@
---
title: "Renames in Git explained"
date: 2020-11-28T12:07:00Z
draft: false
toc: true
tags: ['tech', 'git', 'rename']
---
## Introduction
One of the questions I'm often asked when teaching or explaining Git is how Git
handles file and/or directory renames. The short answer to this is: **It**
**doesn't**.
The slightly longer answer is: **It does, but probably not in the way you**
**envision it**.
To help you understand this topic a bit more, we first have to go back to the
basics: What actually is a file or directory name? The answer to this question
is highly dependent on the underlying file system, but in general it can be
boiled down to this:
> A file (or directory) name is an index used by the file system to look up the
> contents of the file. (Note: from now on I will only refer to file names, but
> the same applies to directory names as well.)
What you should note from this is that a filename is actually not a property of
the file content itself, but part of the meta-data regarding the content. In
Linux, for instance, the filename of a file is stored in the directory, which
is basically a associative array which maps filenames to inodes (the object
which stores the meta-data of a file).
When renaming a file, what you are actually doing is updating a look up table.
In Linux, this would be updating the associative array of the directory. If you
move a file, then you remove the element from one directory and add it to
another directory.
How this all works internally depends on the OS and the underlying file system,
but more importantly is seldom related to the content of a file. Which brings us
to the next chapter.
## Git stores content, not files
When you commit to a Git repository it basically does the following:
For each directory (including the top one), create a **tree** object. This is
done by looking at every file and directory to be commited and create **blob**
objects for the files and tree objects for the directories. The hash of each
such object is added to this tree object together with the filename if the
object type is blob and the directory name if the object type is tree. This is
then prepended with a header and compressed. The SHA-1 hash is calculated and
the object is stored in the object store (.git/objects), using the first two
characters as a directory and the rest as filename.
It then creates a commit object which points to the top level tree's hash.
> Note: it of course only really does this for files which were part of the
> staging area. That's the most efficient. Of course if the content of a file
> was changed, it hash will change and thus the tree object it was part of will
> change and its hash will also change and so on until the top level tree
> object.
As an example, suppose you have the following structure:
```bash
.
├── README.md
├── bar
   ├── bar.md
   └── baz
   └── baz.md
└── foo
└── foo.md
```
If you were to commit this structure to git, you will have (simplified):
- 4 blob objects (README.md, bar.md, foo.md, baz.md)
- 4 tree objects (., ./foo, ./bar and ./bar/baz)
- 1 commit object
In my case:
```bash
gael@Aviendha:~/git/tmp$ git commit -m "First commit"
[master (root-commit) 8be3cf0] First commit
4 files changed, 4 insertions(+)
create mode 100644 README.md
create mode 100644 bar/bar.md
create mode 100644 bar/baz/baz.md
create mode 100644 foo/foo.md
gael@Aviendha:~/git/tmp$ find .git/objects/ -type f
.git/objects/52/01cdd884658a103819d66f910ea25ba1dad2e0
.git/objects/be/e527307ae70706c20eb89f205f444c3bb385e9
.git/objects/6b/dd34e3e9ab26062ab881adb1024923923b5f8e
.git/objects/8b/e3cf05d01320a124991a8e7c10fe83ec9cd5e3
.git/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99
.git/objects/57/16ca5987cbf97d6bb54920bea6adde242d87e6
.git/objects/f9/07d059fcdc9b594c6e14dc0c3826f26ab47832
.git/objects/e8/45566c06f9bf557d35e8292c37cf05d97a9769
.git/objects/0c/7d27db1f575263efdcab3dc650f4502a2dbcbf
```
To get the top level tree object, just look at the commit:
```bash
gael@Aviendha:~/git/tmp$ git cat-file -p 8be3cf0
tree 5201cdd884658a103819d66f910ea25ba1dad2e0
author Gaël Depreeuw <gael@depreeuw.dev> 1606569688 +0100
committer Gaël Depreeuw <gael@depreeuw.dev> 1606569688 +0100
First commit
```
And if we look at the tree:
```bash
gael@Aviendha:~/git/tmp$ git cat-file -p 5201cdd
100644 blob e845566c06f9bf557d35e8292c37cf05d97a9769 README.md
040000 tree f907d059fcdc9b594c6e14dc0c3826f26ab47832 bar
040000 tree 0c7d27db1f575263efdcab3dc650f4502a2dbcbf foo
```
The contents of `README.md` is:
```bash
gael@Aviendha:~/git/tmp$ git cat-file -p e845566
README
```
So what does this all mean, when we rename a file?
## Renaming file
If we're just looking at renaming a file, then the contents of the file will
not change. This means the blob object representing the file does not change.
What does change is:
1. The old file's name is removed from the tree object it belong to.
2. The new file's name is added to the tree object it belongs to (with the same
hash in this case).
As such Git is not aware of any name changes. This is why the short answer is:
Git doesn't handle file renames. The repository itself has no notion of this
action. It's just has content and a structure for that content.
However, that does not mean you lose your history when you rename a file.
### How to see history of a renamed file
When you remove and add a file (which is what a rename is for Git), Git will
analyze this and when the files are X% alike (with X being defaulted to 50),
it will assume a rename occured. You can show the log of a file including
renames using:
```bash
git log --follow -- <file>
```
If you want to adjust the treshold you can use the `-MX%` option, where X is the
percentage you want (0-100).
Because there is a percentage treshold, the recommendation is that you do not
combine renaming a file, with modifying a file. If files are 100% identical when
adding/removing it makes it much easier to see them as renames. If on the other
hand, you rename a file and start modifying it heavily, Git might not detect
this as a rename, unless you lower the treshold.
You can also turn off rename detection by doing `--no-renames`
### Can I fix my commit if I did change a lot of content after renaming
First, to prevent this: always check using `git status` whether are not the
rename is being detected. Now, how to solve it?
It depends. If your commit is local only and it is the last commit, then you can
fix this easily. There are many ways to to it, but a couple options are:
```bash
git mv <newname> <oldname> # Undo the file rename
git commit --amend # Commit the changes to the file
git mv <oldname> <newname> # Rename the file
git commit # Commit the rename
```
If the commit is already a couple of commits ago, you can do the same with an
interactive rebase and amending the commit at the right time.
If you already pushed your commits you will have to check with the team if you
can rewrite the history and push it. If this is not possible, you might need to
find the right treshold to have Git mark it as a rename.
### Why did Git do it this way
This is pure speculation but dealing with renames is not as easy as it first
looks. For instance you could add a git command to do a rename (like subversion
has), which could create a new type of object a rename object which links two
objects (old and new). But what if the user forgets to do this and just uses
`mv fileA fileB` and commits this? Should Git automatically assume this is a
rename? It could use the same treshold discused earlier to determine so. That
would make it easier. But then what is the point of having a dedicated rename
command? I think for easy of use, they just decided not to add such a command,
because it is not a solution for all instances. Instead, the rename detection
works good enough for everything and they leave it up to the commiter to make
sure his renames are detected properly.
## Summary
So in summary: no, Git does not store renames in its repository. Instead, it
for every add/delete pair part of a commit, Git will do a likeness analysis and
when they are X% alike (default 50%), it will assume a rename occured.
Some commands influenced by this are: git log, git diff and git merge. Options
related to renames are:
```txt
-M=<n>, --find-renames=<n> # where n is the treshold percentage.
--no-renames # don't do any rename detection
```

@ -0,0 +1,149 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
FTZo62dWDvlkjXY0vE7Wsj0=
=4ORE
-----END PGP PUBLIC KEY BLOCK-----

@ -0,0 +1 @@
Subproject commit 39a8165aaa6b726ce0947abb31c0ce09aa30e9d9

@ -1 +0,0 @@
Subproject commit 2dc35c5c6a52168a3a7b35c5ad51209f40a851cf
Loading…
Cancel
Save