在幕后发生了什么,在尝试git重置时,提交和头发生了什么——软的和撤销的?

在幕后发生了什么,在尝试git重置时,提交和头发生了什么——软的和撤销的?,git,github,git-reset,git-merge-conflict,Git,Github,Git Reset,Git Merge Conflict,我发布了git reset--soft HEAD~1,然后我决定不这样做,我想回到我以前的状态 所以,我在Stack Overflow中搜索,然后得到了以下答案: 现在我只想回到我发出重置之前的时间 如果您只想取消git重置,那么您可以在reflogs中查找以前的HEAD commit id $ git reflog $ git reset --soft formerCommit 如前所述,我发布了git reset--soft formerCommit。然后,我使用git reflog--

我发布了
git reset--soft HEAD~1
,然后我决定不这样做,我想回到我以前的状态

所以,我在Stack Overflow中搜索,然后得到了以下答案:

现在我只想回到我发出重置之前的时间

如果您只想取消git重置,那么您可以在reflogs中查找以前的HEAD commit id

$ git reflog
$ git reset --soft formerCommit
如前所述,我发布了git reset--soft formerCommit。然后,我使用
git reflog
--

正如您所看到的,它又创建了两个日志,但我的头处于所需的提交位置。所以,我想如果我做出新的改变并推动它,它会很好地工作

但是没有,我遇到了这个错误(在做了一个新的更改后被推送)--

尽管
git-log
不显示
git-reflog

那么,现在我的问题是---

  • 恢复某些文件(不是以前提交的所有文件)中的更改并再次推送的正确方法是什么

  • 如果必须强制推送,则在重置时使用我在问题中发出的命令有什么好处

  • 在发布了
    git reset--soft HEAD~1
    之后,我可以
    unstage
    the changes>made new changes>committed>强制推送

  • 为什么我总是需要强制更改?我知道
    的头
    已经分开了,但是没有其他方法可以优雅地做到这一点吗

  • 如何理解这些概念,我是git新手并自学。

    首先,直接(尽管不是那么有用)回答您的直接问题:

  • 恢复某些文件(不是以前提交的所有文件)中的更改并再次推送的正确方法是什么
  • 没有。也就是说,没有一种正确的方法可以做到这一点。有许多不同的正确方法可以做到这一点

  • 如果必须强制推送,使用[
    git reset--soft
    ]有什么好处
  • 如果这生成了您喜欢的提交图,那么这就是生成您喜欢的提交图的一种方法

  • 在发布了
    git reset--soft HEAD~1
    之后,我可以
    unstage
    the changes>made new changes>committed>强制推送
  • 这不是一个问题。这是一个陈述(也是一个真实的陈述)

  • 为什么我总是需要强制[推]
  • 你并不总是需要;您之所以这样做是因为您故意要求其他Git存储库丢弃一些提交

    关键概念 我如何理解这些概念

    这里的关键是Git实际上不是关于文件的,尽管它存储文件,也不是关于分支名称的,尽管它使用分支名称。Git实际上是关于提交的

    每次提交都存储文件。实际上,每次提交都会存储所有文件的完整快照。然而,这些快照中的文件是一种特殊的、只读的、压缩的和重复数据消除的格式,只有Git自己能够理解。系统上的其他软件都无法理解这些文件。(请注意,重复数据消除意味着每个提交都存储每个文件的一个副本是可以的,因为大多数提交只是重复使用其他提交的大部分文件,因此这些多个副本几乎不占用额外空间。)

    重要的是要记住,任何提交都不能在提交后更改。换句话说,所有提交都是完全、完全只读的。(这实际上是所有内部Git对象的通用属性,它与它们的对象哈希ID相关联。)

    但是如果提交是只读的,并且只有Git可以读取文件,那么我们如何使用它们呢?我们需要普通文件。我们需要能够阅读它们!我们需要能够给他们写信!所以要使用Git,我们必须从Git中取出文件。这就是
    git checkout
    ——或者在git 2.23或更高版本中,
    git switch
    ——的作用:定位某个特定的提交并提取它。请注意,Git将通过其哈希ID找到提交,即使我们使用分支名称,如
    master
    。我们一会儿再进一步讨论

    不过,在深入讨论之前,我们应该先了解一下提交对您的作用,因为每个提交都有两个部分:

    • 提交具有所有文件的完整快照。这是它的主要数据:你告诉Git保存的每个文件的完整副本,在你告诉Git保存它的时候,以它当时在Git中的形式

    • 提交还包含元数据,例如提交人的姓名。大部分元数据都是您在
      git log
      output中看到的内容:例如,某人的姓名和电子邮件地址、日期和时间戳以及日志消息。但有一段元数据对Git本身至关重要。每个提交存储其直接父提交的原始哈希ID,或者对于合并提交,存储其父提交的原始哈希ID(复数)

    大多数提交只有一个父级。如果我们有一系列这样的承诺,我们可以这样画:

    ... <-F <-G <-H
    
    A--B--C   <-- master
    
    A--B--C
           \
            D
    
              I   ???
             /
    ...--G--H   <-- master (HEAD)
    
    我在这里很懒(出于某种原因),不把提交箭头画成向后指向的箭头,但我们必须记住,它们只会向后。也就是说,如果我们有commit
    B
    ,我们不能很容易地前进到
    C
    ,但我们可以很容易地向后到
    A

    为了构建一个新的提交,我们首先让Git提取一个现有的提交。让我们使用名称
    master
    选择commit
    C
    。Git将commit
    C
    提取到某个地方,稍后我们将进一步讨论它,并让我们查看和处理它的所有文件。我们也需要阶段性和承诺性,我们也将在一段时间内进行更多的讨论。但无论如何,我们会做出一个新的承诺,得到一个新的uniq
    A--B--C
           \
            D   <-- master
    
    A--B--C   <-- dev, master
    
    A--B--C   <-- dev (HEAD), master
    
    A--B--C   <-- master
           \
            D   <-- dev (HEAD)
    
    A--B--C   <-- master (HEAD)
           \
            D   <-- dev
    
    git branch --force --delete dev
    
    git branch -D dev
    
    A--B--C   <-- master (HEAD)
           \
            D   ???
    
              I--J   <-- branch2
             /
    ...--G--H   <-- master
             \
              K   <-- branch3
    
    ...--G--H   <-- master (HEAD)
    
    ...--G--H--I   <-- master (HEAD)
    
              I   ???
             /
    ...--G--H   <-- master (HEAD)
    
    git reset --soft <hash>
    
    ...--G--H--I   <-- master (HEAD)
    
              I
             /
    ...--G--H   <-- master (HEAD)
    
              I
             /
    ...--G--H--J   <-- master (HEAD)
    
    ...--G--H--I   <-- master
    
              I
             /
    ...--G--H--J--K--L   <-- master (HEAD)
    
              I
             /
    ...--G--H--J--K--L   <-- master
    
    ...--G--H--I   <-- master
    
    ...--G--H--I   <-- master (HEAD)
    
    git restore --source=<hash-of-G> --staged --worktree path/to/file.ext
    
    git checkout <hash-of-G> -- path/to/file.ext
    
    ...--G--H--I--J   <-- master (HEAD)