git - 使用 git 在各种提交中将文件移动到不同的文件夹
问题描述
这可能是一个菜鸟问题;使用 Android Studio 我进行了多次提交,在每次提交中创建新文件。
在最后三个提交中,新文件被放置在错误的目录中。我可以去那些提交并将它们放在正确的文件夹中并创建新的提交吗?
- 提交 4 --> 将 /file3 移动到 /sample/file3
- 提交 3 --> 将 /file2 移动到 /sample/file2
- 提交 2 --> 将 /file1 移动到 /sample/file1
- 提交 1 --> 一切正常
解决方案
您不能更改任何现有的提交。但是您可以停止使用现有的提交。
因为提交保存了所有内容的完整状态(嗯,所有提交的内容),实际上您还可以通过检查较旧的提交来“及时返回”。
如果你给每个提交一个唯一的 ID,并按照它们的顺序绘制它们,你会得到这样的结果:
A <-B <-C <-D <--master
也就是说,最新的提交 会D
记住其先前提交或父提交的ID C
。同时C
记住它的父母,B
,它记住它的父母A
。(如果A
是存储库中的第一个提交,则它没有父级,因为它没有父级。否则A
记住之前的任何提交A
。)
Git找到这些的方式是名称 master
记录了最后一次提交的哈希 ID。既然是这样D
,就master
发现D
。既然是D
recordsC
的 ID,那么 finds 就是它D
自己,finds 就是C
它自己,B
以此类推。
因此,鉴于所有这些,假设您:
签出提交
A
。现在A
是当前提交,您拥有所有文件,就像您制作A
.继续从复制所有文件
B
,然后移动其中一个。然后你做出一个新的提交,除了B
文件被移动(并且内部保存的新改进日期B
是“现在”而不是“那时”)。你会得到一个新的提交,我们可以称之为B'
:A--B--C--D \ B'
B'
is的父级A
:Git 用来从每个提交向后工作到前一个提交的向后箭头,指向 commitA
,就像B
'points to commit一样A
。B
和之间的区别在于B'
您移动了文件(当然,它B'
具有不同的 Git 哈希 ID——我们这里的字母代表 Git 为每个新提交弥补的实际又大又丑的哈希 ID)。但是,此图中缺少一些内容:名称指向
B'
什么?好吧,我们先别担心。相反,让我们继续...现在,复制
C
到C'
,沿途重命名一个文件,就像制作B'
. 的父母C'
将是B'
:A--B--C--D \ B'-C'
重复
D
制作D'
:A--B--C--D \ B'-C'-D'
让 Git 将 的哈希 ID 写入
D'
namemaster
中。这是特别偷偷摸摸的部分:你现在有:A--B--C--D [abandoned] \ B'-C'-D' <-- master (HEAD)
也就是说,现在这个名称
master
标识了这个新的和改进D'
的而不是旧的D
。
这样做的唯一问题是,如果任何其他Git 用户拥有包含提交序列的存储库副本A-B-C-D
。他们可能会D
在您的新D'
. 如果他们没有准备好,这种过程将使他们的生活变得困难。因此,如果您确实有其他人使用此存储库的克隆,并且他们确实有这三个提交,请考虑不要这样做。但是,如果没有其他人拥有该B-C-D
链条,您可以自由地将它们替换为新的和改进的B'-C'-D'
链。或者,如果参与该项目的其他人都期望这种重写,你仍然可以自由地去做。(如果没有其他人参与,很容易看到所有其他参与的人,他们都不会反对。)
好的,那么,我们如何才能实现这种重写呢?
简单的方法是使用git rebase -i
. 这种交互式变基可让您在实际提交之前停止并更改将进入每个新提交的内容。您只需找到要保留的提交的实际哈希 ID ——在本例中为 commit A
——然后在 branchmaster
上运行:
git rebase -i <hash>
这会调出你最喜欢的编辑器——或者至少,你告诉 Git 的那个是你最喜欢的,通过设置core.editor
——在一个包含三个pick
命令的文件上。将每个更改为edit
,保存指令文件,然后退出编辑器。
Git 现在将继续开始制作B'
atop A
,然后停止并让您编辑提交。跑:
git mv file1 sample/file1
(如果需要,首先制作目录sample
),然后:
git commit --amend --no-edit
建立B'
为期望的结果,然后:
git rebase --continue
这将松散地B'
固定并开始复制过程C
,然后停止,所以现在你git mv file2 sample/file2
和git commit --amend --no-edit
移动git rebase --continue
到复制-D步骤。像以前一样重复。
一旦更新的提交都完成并到位,git rebase
将执行最后一步,将分支名称拉到master
指向D'
而不是D
.
仅出于完整性考虑:这是中间提交的工作方式
当 Git 构建这个新的替换B'-C'-D'
链时,找到每个提交的名称就是HEAD
它本身。这使用了 Git 称为分离的 HEAD的模式。虽然这听起来很吓人,但这只是意味着HEAD
Git 始终需要的特殊名称根本没有附加到任何分支名称。
例如,在变基的中间,你有:
A--B--C--D <-- master
\
B' <-- HEAD
随着更多提交的添加,您将获得:
A--B--C--D <-- master
\
B'-C' <-- HEAD
等等。当git rebase -i
指令用完时——pick
你更改为edit
s 的 s 是指令——rebase 完成,Git 将名称拉到适当的master
位置,重新附加HEAD
到它并为我们提供步骤 5 中显示的图表。
推荐阅读
- python - 使用 cv2.Writevideo 从 ipcam 保存视频 10 秒的最佳实践?
- python - 如何在 CSV 文件中查找特定列的累积总和
- sas - 错误:BY 变量未在数据集 TEST.NOTSORTEDTEST 上正确排序
- python - 在python中,是否可以通过给出坐标和函数值来绘制颜色图?
- docker - 尝试使用内置 kibana 用户登录 Kibana Web 界面时出现 403/Forbidden
- powershell - Powershell 测量与网站的连接时间
- go - 如何让 go fasthttp 服务器在文件上传时更快地触发处理程序?
- numpy - Numpy - 线性代数
- c++ - 'operator<<' C++ 不匹配
- c - C程序中一些数组元素从函数内部更改为main函数内部