问个 Git 基操:怎么样复制一个文件,能保持历史记录?

123 天前
 xiangyuecn
git cp:没这号命令😂
git mv:这是改名

比如已有 a.txt ,我现在要个 b.txt 。 如何复制出 b.txt 这个文件,并且复制前的历史和 a.txt 保持一致?

还是说 和空文件夹 一样,git 不在乎你死活?

操作尽量简单,要是涉及的非基础知识点太多,还是算了,这历史不要也罢😂

8035 次点击
所在节点    git
99 条回复
codehz
123 天前
@dfkjgklfdjg 这个 diff 完全是根据两个状态对比实时计算出来的,git 并没有记录任何 diff 信息
rb6221
123 天前
git 原生的概念是基于行操作的,甚至没有整个源文件 mv 的识别。
mv 的识别都是各大 git 第三方客户端自己实现的,为了用户的交互友好。
我曾经就遇到过,同一个提交,在某个客户端上被识别为 mv ,在另一个客户端上被识别为 del+add 。没有任何理由。
整个原理基本上是基于识别同名文件,对比文件中的内容。
你这样,文件名变了,内容也变了,那鬼才知道你的意图。
geelaw
123 天前
@dfkjgklfdjg #30 git mv 和删除文件再新建没有任何区别。你在 #38 也说了,Git 是猜的,但

>但是如果猜到了,那么提交历史里面是会有标注是 rename

这是错误的,commits 里不会标注为 rename ,只有计算 diff/blame 的时候 Git 才会去(根据 commits 的内容)识别重命名关系。
codehz
123 天前
@janus77 并没有基于行,是单纯整个文件对比,之所以可以提交 hunk ,也是前端的处理方式,内部生成虚拟文件提交到树里,这个意义上二进制文件和文本文件的唯一区别只在前端展示方面(后端影响的只有可压缩性,二进制一般不太容易压缩)
dcsuibian
123 天前
啊?这个很简单啊
首先你复制一下文件,复制以后立马就 add 并 commit (这其中不能修改,否则 git 会认为是另一个文件)
然后就只要
git log --follow -- 对应的文件
就好了呀
TsubasaHanekaw
123 天前
git mv 重命名文件 ,提交之后,回滚,到上一条记录,再重新添加旧的文件, merge 两个分支
mercury233
123 天前
GIT_AUTHOR_DATE=$(date -d'2012-12-12 01:00:01') GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" git commit -m '2012 init'

git 本身倒是确实支持随意设置提交时间(和提交人),但 git log 的顺序还是按实际顺序的,除非 merge
LRainner
123 天前
ykrank
123 天前
@xiangyuecn #29 并不会因为你不在乎重力,你就可以直接飞起来。现在的问题是其他人推荐让你可以飞的工具,你说我一定要靠肉身,然后别人说重力是这个世界的规则,你说我不需要“规则”,只需要飞起来。
那别人就只能建议你睡一觉或者去天台了
skiy
123 天前
跟修改邮箱一个样。历史记录是不变,但是,所有的 commit id 都变了。
yinheli
123 天前
你需要 `git subtree` 具体来说你要把一个文件的 commit 历史都拿出来,`git subtree split`, https://tldr.inbrowser.app/pages/common/git-subtree
mangoDB
123 天前
@xiangyuecn #29 非常震惊你会以这种傲慢的态度进行回复。我后悔自己浪费时间码字来回复你(包括这条)。
B1ankCat
123 天前
个人朴素的看法,如果没有固定的命令的话,那么 commit 也是一个 git 对象,它的第一行是 tree ,第二行是 parent ,tree 就是这个文件在目录树中的内容,因为每次 commit 都和 a 一样,所以只需要复制每次 commit 里用到 tree 改下名字,sha1 都一样就行,然后把复制这个 commit ,把第一行改成复制出来的 tree 的 sha1 ,然后把 parent 也这样递归操作,就伪造好一个一模一样的历史了,浅见哈,有错请指出
gesse
123 天前
@xiangyuecn #29 非常震惊你会以这种傲慢的态度进行回复。我后悔自己浪费时间码字来回复你(包括这条)。
passive
123 天前
git 的优点就是能改历史。但是楼主这题有地触碰到 git 的短板了。

(爬了楼,什么狗屁哲学和理念,就是 Torvalds 随手写的一个工具)
moudy
123 天前
@mangoDB 旁观者说一句,你们上来的用词才是傲慢。又是理念 又是伪造的,好像 lz 要对 git 下黑手一样。lz 只不过是问如何看历史的时候能知道 b 文件是在某个时候从 a copy 出来的,这不是一个很清楚也完全可以理解的需求么,怎么就跟伪造历史扯上了。
94
123 天前
@geelaw #43 ,好的,修正了认知上的错误。
所以实际上 git 只会存储变更的文件快照,而不会额外存储变更信息。每次在拉取 log 或者分析的时候实时去对比计算。
一直以为 git log 输出的内容是直接输出的 commit 中的记录,而不是实时算的。怪不得要加上 --stat 。
mangoDB
123 天前
@moudy 你甚至都没有理解楼主的需求,就在这里大言不惭的教育别人。楼主需要让「文件 b 」具备和「文件 a 」一样的历史记录,并不是关注「文件 b 」是什么时间点被“拷贝”出来的。
evada
123 天前
说 git blame 的意思就是,你使用 git mv a.txt b.txt 然后 commit 。
然后可以通过 git log --graph --decorate --oneline --name-status --follow b.txt 查看包括 a.txt 的详细记录。
或者 git blame -C -C -w b.txt 查看每一行的变更记录(包括来自 a.txt)的
j869716
123 天前
谢谢, 已 block

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1133693

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX