重复一个分支,具有相同但不与原始分支相同的分支

发布于 2025-02-12 14:01:02 字数 549 浏览 0 评论 0 原文

我将这个项目添加到了一个由主要分支组成的git存储库中。

      A--->B--->C--->D--->E

当我对b tht b进行一些实验修改时,我想在其他分支中保留 main 分支的副本 main-copy ,以防万一错误的原因是在Main Branch上玩提交,我不想进行还原,我仍然有一个完整的主分支副本。 如果我创建 main_copy 在提交e之上的分支,当前我实际上不会制作 main 分支的副本。 因此,我需要在提交A之上创建一个分支,并在此分支中进行相同的提交。最后的存储库将是这样的。

     A--->B--->C--->D--->E
     |
     `--->B'--->C'--->D'--->E'

我不知道如何做到这一点,而不必重新犯下另一个分支,然后再次通过e逐一进行b。 在git上有没有忠实的命令?

I have this project added to a git repository with the main branch consisting of a number of commits.

      A--->B--->C--->D--->E

as i'm doing some experimental modifications on commits A through B i want to keep a copy of the commits of main branch inside a different branch main-copy in case anything went wrong due to play with commits in main branch and i wouldn't want to go through restoring, i still have an intact copy of main branch.
if i create main_copy branch on top of commit E where Head is currently at i will not actually make a copy of main branch because commits A to B are common between the two branches.
so i need to create a branch on top of commit A and do the same commits in this branch. the final repository would be something like this.

     A--->B--->C--->D--->E
     |
     `--->B'--->C'--->D'--->E'

I have no idea how to do this without going back to commit A making another branch and doing commits B through E again one by one.
is there any devoted command to do this on git?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

同尘 2025-02-19 14:01:02

TL; DR

所需要做的就是在开始实验之前创建一个分支名称。

长期

...我正在进行一些实验修改,以通过...

我不是说您不是尝试尝试这样做。我的意思是从字面上看,这是不可能的,所以无论您尝试什么,这实际上都没有发生。

这里的诀窍是:提交是不可变的,但是我们没有通过它们不可变的真实名称找到它们。任何给定提交的真实名称是其哈希ID,使用该哈希ID会找到commit 的。无论您尝试多么努力,该提交都永远不会改变。稍后再次使用该名称会找到comport (有一个警告:请参见下文)。

A 分支名称在git中是一个数据库条目,但是您可以将其视为一个小文件,因为有时将其实现为一个小文件。此“文件”(或实际文件)包含一个字符串,条目提供的一个字符串是我们要声明的 last commit的 hash id 分支”。

也就是说,给定的一连串的提交:

... <-F <-G <-H

如果我们创建一个分支名称输入并塞入提交 h 该名称,我们得到:

...--F--G--H   <-- somebranch

运行 git log tomeBranch 显示我们提交 h ,然后提交commit g ,然后提交 f ,等等。

如果我们尝试更改其中一些提交(例如 g ),而发生的事情是,我们立即获得了 new commit,a g' ,其父<代码> f 。新提交 g'没有孩子,并且要查找 g'我们将使用一个名称,例如分支名称,因为人类是如此不擅长使用哈希ID:

...--F--G--H   <-- somebranch
      \
       G'  <-- newbranch

如果进行“修改”提交 g'的目的是仅编辑 g 中的提交消息的文本 ,新提交 g'将保持由于它的快照是 g 保留的相同快照(两个快照将是100%被删除的,因此 g'没有额外的空间)。然后,我们必须制作一个新的 h' h 的副本,其中我们在 h'中更改的一件事是它保存的父母哈希ID:commit h'必须向后指向我们的新 g'

...--F--G--H   <-- somebranch
      \
       G'-H'  <-- newbranch

一旦我们处于这种情况下,如果我们 stuff h ' s Hash ID中的名称 someBranch ,我们得到:

...--F--G--H   ???
      \
       G'-H'  <-- somebranch, newbranch

如果现在删除临时名称 newBranch 似乎我们已经编辑了Commit commit > g'以某种方式:

       G--H   ???
      /
...--F--G'-H'  <-- somebranch

我们从字面上看,除非我们在某处记住了它的哈希ID,否则找不到 commit commit 。

当然,记住其哈希ID的地方很明显:我们只是创建一个新的分支名称在做任何事情之前,我们要做“修改” g 以制作 g'。然后,一旦名称 someBranch 找到 h'而不是 h ,我们创建的我们的分支是 h

       G--H   <-- original-somebranch
      /
...--F--G'-H'  <-- somebranch

git日志原始单行向我们展示了仍然存在的原始提交。

如果我们忘记创建名称怎么办?

如果我们忘记了创建一个名称,例如 ointer-somebranch ,我们必须 找到旧提交的哈希ID h 。我们有一些时间来做到这一点:git存储库也不会丢弃旧提交,即使是通过普通方式无法理解的,因为“一段时间”。那“一段时间”多长时间?好吧,这取决于许多事情。一些托管系统(例如,github)从不丢弃旧提交。默认情况下,git设置了三个到期时间:14天,30天和90天。在这三次中之一之后, 名称都无法找到的旧提交可以消失。

当然,如果您先制作新名称,那么您最安全, git rebase -i 或您正在做的任何事情。但是大多数操作将提交哈希ID的副本放入另一个名称或a reflog条目,在这里30或90天默认启动。要安全起见,我们应该考虑较短的到期:30 几天后能够找到 h ,如果我们不费心为其创建名称,则git May 可以删除它。 Git的过程是有点懒惰的,因此它可能会持续多个月或几年,但是在回流条目到期30天之后,它已经“变得脆弱”。

您可以使用 git reflog 查看回流条目,这实际上是运行 git log -g 的前端。请参阅 git reflog 的文档。请注意,在一个随机的哈希ID和提交信息的海洋中,很难从另一个旧提交中告诉一个旧提交。这是在您开始工作之前制作名称​​的另一个原因。

如果通过“垃圾收集器” git gc 删除提交,并且您将git命名其真实姓名(哈希ID),则git会说它不识别该哈希ID。如果您只是构成哈希ID,尽管您“缩短”了一个缩短的情况,但也会发生同样的事情ID。如果您使用 branch名称(或标签名称或其他名称)来保存哈希ID,这也停止 git gc 删除它,因为现在可以找到提示能够以一些可读的名称。这也保护所有提交的所有提交(比此提交更早),因为这些提交也可以发现。

TL;DR

All you need to do is create a branch name before you start experimenting.

Long-ish

... I'm doing some experimental modifications on commits A through ...

No, you're not.

I don't mean you aren't trying to do that. I mean it's literally impossible to do that, so no matter what you try, that doesn't actually happen.

The trick here is this: commits are immutable, but we don't find them by their immutable true names. The true name of any given commit is its hash ID, and using that hash ID will find that commit. That commit can never be changed, no matter how hard you try; using that name again later will find that commit (with one caveat: see below).

A branch name, in Git, is a database entry, but you can think of it as a small file, because it's sometimes implemented as a small file. This "file" (or actual file) contains one string, and that one string the entry provides is the hash ID of the last commit we want to claim is "in the branch".

That is, given a string of commits:

... <-F <-G <-H

which ends at commit H, if we create a branch name entry and stuff the raw hash ID of commit H into that name, we get:

...--F--G--H   <-- somebranch

Running git log somebranch shows us commit H, then commit G, then commit F, and so on.

If we attempt to change some of these commits—such as G—what happens instead is that we immediately get a new commit, a G', whose parent is F. New commit G' has no child, and to find G' we will use a name, such as a branch name, because humans are so bad at using hash IDs:

...--F--G--H   <-- somebranch
      \
       G'  <-- newbranch

If the purpose of making "modified" commit G' was to edit just the text of the commit message in G, new commit G' will hold as its snapshot the same snapshot that G holds (and the two snapshots will be 100% de-duplicated and thus the one for G' takes no extra space). We then have to make a new H' copy of H where the one thing we change in H' is its saved parent hash ID: commit H' must point backwards to our new G':

...--F--G--H   <-- somebranch
      \
       G'-H'  <-- newbranch

Once we're in this situation, if we stuff H's hash ID into the name somebranch, we get:

...--F--G--H   ???
      \
       G'-H'  <-- somebranch, newbranch

If we now delete the temporary name newbranch, it seems as though we've edited commit G' somehow:

       G--H   ???
      /
...--F--G'-H'  <-- somebranch

We literally can't find commit H unless we've memorized its hash ID somewhere.

Of course, the place to memorize its hash ID is obvious: we just create a new branch name before we do whatever it is that we do that "modifies" G to make G'. Then, once the name somebranch locates H' instead of H, our branch we created earlier locates H:

       G--H   <-- original-somebranch
      /
...--F--G'-H'  <-- somebranch

and git log original-somebranch shows us the original commits, which still exist.

What if we forget to create the name?

If we forget to create a name like original-somebranch, we must find the hash ID of old commit H. We have some time to do this: a Git repository will not discard an old commit, even if it's unfindable by ordinary means, for "some time". How long is that "some time"? Well, that depends on many things. Some hosting systems (e.g., GitHub) never discard old commits. Git by default sets three expiration times though: 14 days, 30 days, and 90 days. After one of these three times, old commits that can't be found by any name can go away.

You're safest, of course, if you make the new name first, before doing git rebase -i or whatever it is that you are doing. But most actions place a copy of a commit hash ID into another name, or a reflog entry, and here the 30 or 90 day default kicks in. To be safe we should just consider the shorter expiration: 30 days after we were able to find H, if we haven't bothered to create a name for it, Git may get around to removing it. Git's process for doing this is kind of lazy so it could stick around for many more months or years, but it has "become vulnerable" after the 30 day expiry of the reflog entry.

You can view reflog entries with git reflog, which is actually a front end that runs git log -g. See the documentation for git reflog for details. Note that in a sea of random-looking hash IDs and commit messages, it can be hard to tell one old commit from another. That's the other reason to make the name before you start working.

If a commit is removed via the "garbage collector" git gc, and you give Git its true name (hash ID), Git will say that it doesn't recognize that hash ID. The same thing happens if you just make up a hash ID—although if you "make up" a shortened one, there's a good chance that this is the valid prefix of some existing commit, so you want to make sure you remember the full hash ID. If you use a branch name (or tag name or other name) to hold the hash ID, that also stops git gc from removing it, since the commit is now find-able by some human-readable name. This also protects all commits "behind" (earlier than) this commit, since those too are find-able.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文