如何编辑旧标记中的文件而不删除当前更改

时间:2016-10-23 16:48:33

标签: git

我在主分公司的大学项目上工作了一段时间。

在每一步我们都应该添加TAG。但是我最近发现我必须在之前的标签中修改一些东西。

我搜索过,我找到了很多解决方案(基于重置 - 硬件或其他东西),但我不想失去我所做的一切,特别是我必须做的编辑非常小。

我知道我们不应该更改标签中的任何内容,但我必须进行的编辑是次要的。

那么在旧提交中编辑文件(制作标签)的最佳方法是什么,而不会在提交后丢失更改?

谢谢

1 个答案:

答案 0 :(得分:0)

你不能。你可以可以做一些事情(在线下),但你要求的几乎是不可能的。原因很简单,虽然它分为两部分:

  1. 标记只是提交的名称。 (它可能是"带注释的标记对象的名称"它反过来命名一个提交,但这最终都是相同的。)

    每个提交 - 实际上,每个Git对象 - 由其哈希ID唯一标识。命令git rev-parse将名称(例如分支和标记名称)转换为这些哈希ID:

    $ git rev-parse origin/master
    659889482ac63411daea38b2c3d127842ea04e4d
    $ git rev-parse v2.2.1
    7c56b20857837de401f79db236651a1bd886fbbb
    

    使用标记(例如v2.2.1)而不是哈希ID的主要原因是......嗯,谁能记住7c5b208-aw-the-heck-with-it,我们将如何将其与{{1}进行比较}}?我知道:电脑可以为我们记住这个!让我们让计算机记住哈希ID,并将其称为"标记"。

    标记名称和分支名称之间的区别在于标记假定永远保持不变,并且分支假定移动,在&中#34;前进一步"当你做出提交的时尚--Git会自动为你做这件事 - 或者有时会在很多提交中快速做到这一点"时尚(当你从其他地方获取新的更新时)。

  2. 提交的原始哈希ID是该提交内容的加密校验和。事实上,对于所有Git对象都是如此:哈希是SHA-1内容校验和。如果您在Git存储的任何内容中更改了一个位,您将获得一个新的不同的哈希ID。

    任何提交的内容都取决于该提交中的所有文件,以及导致该提交的所有历史记录。我发现查看实际提交是有益的:

    v2.5.2

    它实际上是$ git cat-file -p origin/master | sed 's/@/ /' tree 3424a8d14d91a3aaf7b9d5c962f5dd36ff90953c parent 720265749d905ab8da275f18abc42b2dac751dff parent 23415c26fef155f2fa9aebf8a48a6ae457b68c7b author Junio C Hamano <gitster pobox.com> 1476737546 -0700 committer Junio C Hamano <gitster pobox.com> 1476737546 -0700 Sync with maint * maint: l10n: de.po: translate 260 new messages l10n: de.po: fix translation of autostash l10n: ru.po: update Russian translation 行(指向Git&#34;树&#34;对象),它允许提交记录源的快照。如果更改源,tree对象及其ID将更改,这意味着新提交(使用新的和不同的tree对象的提交)与旧提交不同。

    因为ID是内容的加密校验和,所以没有Git对象可以永远更改。 Git通常只将 new 对象添加到存储库中;现有的物体永远保持不变,物体几乎不会被删除(我们稍后会看到更多)。

  3. 所有这一切 - 您无法编辑现有提交中的文件 - 您可以制作和不同的提交*,然后为它命名。如果删除标记的旧名称到ID映射,并安装这个新的,不同的名称到ID映射,该怎么办?这被称为&#34;重新标记&#34;和Linus Torvalds has advice for the re-tagger, right in the git tag documentation

      

    当您标记错误的提交并且想要重新标记时,您应该怎么做?

         

    如果您从未推过任何东西,只需重新标记即可。使用&#34; -f&#34;替换旧的。你已经完成了。

         

    但是如果你把事情搞砸了(或者其他人可以直接读取你的存储库),那么其他人就已经看到了旧的标签。在这种情况下,您可以执行以下两项操作之一:

         
        
    1. 理智的事情。只是承认你搞砸了,并使用不同的名字。其他人已经看过一个标签名称,如果你保持相同的名称,你可能会遇到两个人都拥有&#34;版本X&#34;但他们实际上有不同的 &#34; X&#34;&#39;第所以只需称它为&#34; X.1&#34;并完成它。

    2.   
    3. 疯狂的事。 ...

    4.   

    (点击链接阅读其余部分。)

    如果你想做一个像旧提交一样的新提交,但是有一些改变,你有一些选择。让我们从这开始:像往常一样,像往常一样在分支上进行新的提交。

    首先给自己一个指向原始提交的分支名称:

    tree

    (我们在这里所做的只是为before: ...--o--o--o--o--o--o <-- master ^ | tag: v2.5.2 $ git checkout -b newbranch v2.5.2 now: o--o--o <-- master / ...--o--o--o <-- newbranch ^ | tag: v2.5.2 推了一些链,然后添加一个新的分支标签master,指向与标签相同的提交 newbranch)。

    现在v2.5.2上的提交会像往常一样延长newbranch

    newbranch

    如果您使用了多少次提交来扩展 o--o--o <-- master / ...--o--o--o--o--o <-- newbranch ^ | tag: v2.5.2 ,则可以重新标记(强制newbranch指向新提示提交),或创建标记。使用Linus的建议知道哪些是明智的。

    除此之外,您可能已阅读v2.5.2。这个似乎来更改提交。这是一个谎言 - 在好的情况下是一个白色的谎言,在其他一些情况下是一种灰色或暗淡的谎言;如果你不知道它的真正作用,它会在恶劣的情况下恶毒地咬你。

    git commit --amend做的是修改进行新提交的正常过程。 正常进程是将新提交添加到当前分支:

    git commit --amend

    before: ...--A--B--C <-- branch $ git commit ... after: ...--A--B--C--D <-- branch 做的是将当前提交推到一边,以便&#34;&#34;之后&#34;这张照片的一部分看起来像这样:

    git commit --amend

    请注意,提交 C [abandoned] / ...--A--B--D <-- branch C的上一个提示)完全未修改。它存在于您的存储库内部,完整且未更改,直到稍后的垃圾收集&#34; pass(branch)发现它是否真的被抛弃了。默认情况下,名为 reflog 的东西会挂起至少30天,这样如果您发现自己需要它,就可以将其取回;如果有一些其他分支或标记名称,Git可以通过它找到提交git gc某些其他方式,那些挂起到提交&#34;永远&#34; (或直到那些分支和/或标签名称都被删除)。

    让我们来看看如果我们使用&#34;将提交推到一边会发生什么?&#34; &#34;&#34;之后的C方法看起来像这样的图片:

    newbranch

    如果需要,我们会 o--o--o <-- master / ...--o--o--o <-- newbranch ^ | tag: v2.5.2 ,以便我们对其进行处理。然后,我们会在工作树git checkout newbranchgit add中进行一些更改。这会将标记的提交推到一边,但git commit --amend仍然链接到它,并且标记仍然指向它。绘图会变得混乱,所以让我们在每次提交时都放置一个字母的名字,暂时停止在标签中绘图。这是&#34;在修改之前&#34;再次拍照,字母名称为:

    master

    现在我们进行&#34;修改&#34;,将C推到一边。但是, D--E--F <-- master / ...--A--B--C <-- newbranch 仍然指向D,因此我们在C所在的地方绘制了新的提交G,但将C移开了C指向它。请注意,D仍然指向C

    B

    现在我们可以再次绘制标记 - 它仍然指向提交 C--D--E--F <-- master / ...--A--B--G <-- newbranch ,所以让我们从上面绘制它:

    C

    事实上,完全以另一种方式绘制它可能会更好:

         tag: v2.5.2
              |
              v
              C--D--E--F    <-- master
             /
    ...--A--B--G            <-- newbranch
    

    现在很清楚 tag: v2.5.2 | v ...--A--B--C--D--E--F <-- master \ G <-- newbranch 怎么没有修改任何东西。它所做的是在--amend进行新的提交newbranch时将风G退回一步,以便G指回B,而不是指向C

    此时,您可以重新标记&#34;重新标记&#34;您的旧标记(如果这是一个理智的事情),或者只是创建一个指向提交G的新标记。