【问题标题】:How can I set up Git branch for automatic backups如何设置 Git 分支以进行自动备份
【发布时间】:2014-10-14 14:24:37
【问题描述】:

我意识到已经存在关于如何备份存储库的问题(答案通常是 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 和包含“Hello Dave”的提交 2 结束,假设提交 1 在我之前签出分支 A 时发生,而在提交 2 发生时分支 B。

相信 git stash 是我正在做的事情的关键,但它根本不起作用。我尝试了这些命令的几种不同组合,并且它们都在 repo 处于各种状态时在不同的时间点返回了不同的错误变化,因此很难总结它们。我想说我的方法可能从根本上是错误的,所以列出的命令只是为了说明我到目前为止所尝试的内容。

但无论我做什么,我都会遇到合并冲突,或者什么都没有提交。我错过了什么? (如果我可以提供任何其他信息,请告诉我)

【问题讨论】:

  • 它必须在 git 中还是可以像 git archive 一样是存档,甚至可能是增量 rsync 备份?
  • 真的喜欢为此使用 Git
  • 我能想到的唯一方法是每次备份都使用单独的分支,因为就像莱昂内尔所说,如果你上次备份分支,现在尝试将分支 b 提交到同一个分支,并且 a 和 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”,那不会有冲突吗?
  • 是的,您正确理解了这个问题。你有没有一一运行命令,看看哪里出错了?

标签: git version-control merge backup


【解决方案1】:

在我看来,您想自动备份工作目录内容作为backup 分支中的新提交,并将所有分支推送到origin

在这种情况下,您不希望 checkout backup 分支,因为这会改变您的工作目录内容。相反,您需要使用git read-treegit update-indexgit 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"

(注意上面的脚本我没有测试过……)

【讨论】:

  • 我几乎放弃了希望,但脚本运行良好!我没有考虑到检查backup 分支会出于某种原因更改我的工作目录,而且我不知道操作树的命令的用法,您的链接非常有帮助,谢谢。跨度>
【解决方案2】:

我为什么需要这样做。

您可以使用git config core.logAllRefUpdates true。这将使 git 保留每个分支的完美历史记录。您甚至可以将其调整为永不过期,并且您将拥有每个分支的完美历史记录(而不仅仅是在您记得备份它时)。


如果你真的想这样做,你可以让索引包含你想要的树,然后提交它。

  1. 切换到备份分支git stash; git checkout backup
  2. 清空索引git rm -fr --cached .
  3. 将要备份的提交的树复制到索引中
    git ls-tree branchA | git update-index --index-info
  4. 提交结果git commit -m "Backup of branchA"(不要使用-a!)
  5. 回到你来自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'

【讨论】:

  • 这个答案给了我另一件需要研究的东西,(git checkout --orphan),但它做的事情与我所要求的不同。它正在对备份分支中的特定分支进行快照,这与我的想法有些相反(忽略其他分支的存在)
  • 那么您能否为您的问题添加更多信息?我又去读了一遍,我还是不知道你在找什么。也许绘制提交和分支的树会有所帮助。
  • 我不确定要添加什么。您还可以在答案的上下文中添加对git checkout --orphan 的解释吗?
  • 带着搜索来到这里,看到了一个很好的答案,我想我会回答“为什么”,从我的角度来看——自动备份可以使它更不容易出错在两台(或多台)机器之间并具有相同的工作文件——无需将您的 git 签出到诸如保管箱同步目录之类的东西中。不过,git 内部的环境同步有点复杂……它只是节省了一个额外的工具。
【解决方案3】:

问题是你试图让 git 假装你的所有分支都可以共存于一个分支中(你称之为备份)。所以实际上,您正在合并所有内容,很自然会产生冲突!

为了澄清,这里有一个例子: 您有分支 a,文件 f 包含文本“a”,分支 b 的文件 f 包含“b”。您在分支 a 上工作,发生自动备份,并将 f="a" 存储在备份分支中。然后,无论出于何种原因,您都在分支 b 上工作,并发生自动备份,现在您正在尝试存储 f="b"。这是一个合并冲突,因为分支 a 和 b 之间没有关系(可能它们都继承了文件 f 包含“prod”的 prod 分支的文件 f,并将其分别更改为“a”和“b”)。

如果您想在给定时间拍摄目录中的内容的快照,您想使用标签,并且您可能希望将拍摄标签的时间作为标签名称的一部分,例如 workdir-snapshot-20140818 -1432。

请记住,分支只是指向提交的指针,因此使用“备份”一词确实具有误导性,您实际上并没有备份数据,您要跟踪的最多的是在给定时间将哪个分支签出到您的工作目录,就是这样。

【讨论】:

  • 如果需要,我可以澄清这个问题,但我实际上并没有尝试合并分支,我只是想获取在快照时存在的文件磁盘。因此,如果分支 A 对文件 A 进行了更改,而分支 B 在同一文件上进行了冲突更改,但分支 B 已签出,则备份分支最终应该得到分支 B 的更改,这些更改当前位于磁盘上的文件中,忽略其他任何内容。
  • 我刚刚在问题中添加了一些来自 cmets 的信息
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-26
  • 2012-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多