如何为自动备份设置Git分支

时间:2014-08-21 04:07:48

标签: git version-control merge backup

我意识到已经有关于如何备份存储库的问题(答案通常是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处于各种状态时,所有这些命令在不同点返回了错误的不同变化,因此很难总结它们。我说我的方法可能从根本上是错误的,所以列出的命令只是为了说明我到目前为止所尝试的内容。

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

3 个答案:

答案 0 :(得分: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. 复制到索引中
  5. 提交结果git commit -m "Backup of branchA"(不要使用-a!)
  6. 回到git checkout -f branchB; git stash pop来自的地方。您需要使用-f,因为工作副本会说它很脏。
  7. 这永远不会有任何合并冲突,因为你没有合并任何东西。备份中的每个提交都将完全代表您当时备份的分支。


    这是一个例子。

    $ 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-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"

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

答案 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。

请记住,分支只是提交的指针,因此使用术语“备份”确实具有误导性,您实际上并不是备份数据,您跟踪的最多是在给定时间检查到您的工作区的分支就是这样。