我意识到已经有关于如何备份存储库的问题(答案通常是git bundle
),但我会针对特定的设置。
我会尝试定期将当前分支的“快照”提交到另一个分支以进行备份。我正在使用批处理文件,它看起来像这样(我尝试过的变化比我在这里列出的更多):
git stash
git checkout backup
git add .
git commit -m "Automatic Backup %Time%"
git push --all origin
git stash pop
git checkout -
我的目标是每次提交都应该是目录当前状态的精确快照,无论我在运行时检查了哪个分支。如果较新的提交更改了文件,我希望它在出现合并冲突时优先。
我实际上并没有尝试合并分支,我只是试图获取磁盘上快照时存在的文件。因此,如果分支A对文件A进行了更改,并且分支B对同一文件进行了更改,但是分支B被检出,则备份分支应该最终获得分支B的更改,这些更改当前位于磁盘上的文件中,忽略其他任何事情。
我正在尝试做的一个实际(?)示例: 假设分支A的“myfile.txt”为“Hello World”,分支B的“myfile.txt”为“Hello Dave”。
当我签出分支A并在文本编辑器中打开“myfile.txt”时,我希望它有“Hello World”。当我结账B时,我希望它有“Hello Dave”。
如果在一个分支内,提交1具有“Hello World”,而2个具有“Hello Dave”,则不存在冲突。我希望我的备份分支以包含“Hello World”的提交1结束,并且提交2包含“Hello Dave”,假设在我之前检出分支A时发生了提交1,而在提交2发生时分支B。
我相信 git stash是我正在做的事情的关键,但它根本不起作用。我尝试了这些命令的几种不同组合,并且当repo处于各种状态时,所有这些命令在不同点返回了错误的不同变化,因此很难总结它们。我说我的方法可能从根本上是错误的,所以列出的命令只是为了说明我到目前为止所尝试的内容。
但无论我做什么,我都会遇到合并冲突或者没有任何提交。我错过了什么? (如果我能提供任何其他信息,请告诉我们)
答案 0 :(得分:2)
为什么你需要这样做是超出我的。
您可以使用git config core.logAllRefUpdates true
。这将使git保持每个分支到处的完美历史。你甚至可以调整它永不过期,你将拥有每个分支的完美历史(而不仅仅是当你记得备份它时)。
如果你真的想这样做,你可以让索引包含你想要的树,然后提交它。
git stash; git checkout backup
git rm -fr --cached .
git ls-tree branchA | git update-index --index-info
git commit -m "Backup of branchA"
(不要使用-a
!)git checkout -f branchB; git stash pop
来自的地方。您需要使用-f
,因为工作副本会说它很脏。这永远不会有任何合并冲突,因为你没有合并任何东西。备份中的每个提交都将完全代表您当时备份的分支。
这是一个例子。
$ mkdir example
$ cd example
$ git init
Initialized empty Git repository in /tmp/example/.git/
$ echo "First change" > file1
$ git add file1
$ git commit -am "file1 first change"
[master (root-commit) f071d01] file1 first change
1 file changed, 1 insertion(+)
create mode 100644 file1
$ git branch master_two
$ git checkout master_two
Switched to branch 'master_two'
$ sed -i s/First/Two/g file1·
$ git commit -am "Two change"
[master_two b786d88] Two change
1 file changed, 1 insertion(+), 1 deletion(-)
$ git checkout master
Switched to branch 'master'
$ sed -i s/First/Second/g file1
$ git commit -am "Second change"
[master d88ca84] Second change
1 file changed, 1 insertion(+), 1 deletion(-)
$ git checkout --orphan backup
Switched to a new branch 'backup'
$ git rm -fr --cached .
rm 'file1'
$ git ls-tree master | git update-index --index-info
$ git commit -am "snapshot of master"
[backup (root-commit) 7af271d] snapshot of master
1 file changed, 1 insertion(+)
create mode 100644 file1
$ git rm -fr --cached .
rm 'file1'
$ git ls-tree master_two | git update-index --index-info
$ git commit -m "snapshot of master_two"
[backup a3ddfdd] snapshot of master_two
1 file changed, 1 insertion(+), 1 deletion(-)
$ git checkout -f master
Switched to branch 'master'
答案 1 :(得分:2)
在我看来,您希望自动将工作目录内容备份为backup
分支中的新提交,并将所有分支推送到origin
。< / p>
在这种情况下,您不希望checkout
backup
分支,因为这会更改您的工作目录内容。相反,您需要使用git read-tree
,git update-index
和git commit-tree
的某种组合来为您的backup
分支制作新的提交,然后使用git branch -f
来将新制作的提交添加到backup
分支。之后,您可以继续定期推送到origin
。
链接: http://alx.github.io/gitbook/7_raw_git.html
<强>更新强>
我认为最简单的方法就是这样(假设你已经有一个名为backup
的分支):
#!/bin/bash
BRANCH=backup
export GIT_INDEX_FILE=/tmp/git-backup-index.$$
git add .
git commit-tree $(git write-tree) -p $(git show-ref --hash --heads $BRANCH) -m "Automatic backup" | xargs git branch -f $BRANCH
rm -f "$GIT_INDEX_FILE"
(注意我还没有测试过上面的脚本......)
答案 2 :(得分:-1)
问题在于你试图让git假装所有分支都可以在一个分支中共存(你称之为备份)。所以实际上,你正在融合所有东西,你自然会发生冲突!
只是为了澄清,这是一个例子: 你有分支a,文件f包含文本“a”,分支b包含文件f包含“b”。您在分支a上工作,发生自动备份,并在备份分支中存储f =“a”。然后你出于任何原因在分支b上工作,并发生自动备份,现在你试图存储f =“b”。这是合并冲突,因为分支a和b之间没有关系(也许它们都从prod分支继承文件f,其中文件f包含“prod”,并且分别将其改为“a”和“b”)。
如果您想在给定时间拍摄目录中的内容的快照,您希望使用标记,并且您可能希望将标记作为标记名称的一部分放置,例如workdir-snapshot-20140818 -1432。
请记住,分支只是提交的指针,因此使用术语“备份”确实具有误导性,您实际上并不是备份数据,您跟踪的最多是在给定时间检查到您的工作区的分支就是这样。