简体   繁体   English

从合并的主分支恢复 git 个文件

[英]recover git files from merged master branches

I have a scenario in which I believe I have accidentally deleted all history and files from my local repository and am looking to see if this is in fact the case (and if any file recovery is possible) I initially cloned a repo from a remote repo and never created a new branch locally.我有一个场景,我认为我不小心从我的本地存储库中删除了所有历史记录和文件,并且正在查看是否确实如此(以及是否可以恢复任何文件)我最初从远程存储库克隆了一个存储库并且从未在本地创建新分支。 I created several files in one of the local directories.我在其中一个本地目录中创建了几个文件。 I then accidentally merged the master branch from the remote repo back to local, causing those files to be deleted.然后我不小心将远程仓库的 master 分支合并回本地,导致这些文件被删除。 I have no means to revert back to a different branch (as is the case on the other SO questions I have seen).我没有办法恢复到另一个分支(就像我看到的其他 SO 问题一样)。 There is no means to revert back to the 'pre-merge' local version is there?没有办法恢复到“合并前”的本地版本吗?

edit: I also should note that the files in my local repo were never committed at any point.编辑:我还应该注意,我本地存储库中的文件从未在任何时候提交过。 They were just saved within the folder that git init was run on.它们只是保存在运行git init的文件夹中。

edit: I also should note that the files in my local repo were never committed at any point.编辑:我还应该注意,我本地存储库中的文件从未在任何时候提交过。 They were just saved within the folder that git init was run on.它们只是保存在运行git init的文件夹中。

That's the key information, and it means that Git cannot help you get the files back, once they're gone.这是关键信息,这意味着一旦文件丢失,Git 将无法帮助您找回文件。 If you have some sort of OS-level file backup (such as macOS Time Machine), that's the way to recover them.如果您有某种操作系统级别的文件备份(例如 macOS Time Machine),这就是恢复它们的方法。

What to know before using Git使用 Git 前须知

When using Git, it's important to understand the underlying model by which Git works.使用 Git 时,了解 Git 工作的底层 model 很重要。 The details get very complicated, but an overall description is pretty simple: Git stores commits , and that's basically it.细节变得非常复杂,但总体描述非常简单: Git stores commits ,基本上就是这样。 If it's committed, it's in Git. If it's not committed, it's not in Git .如果已提交,则在 Git 中。如果未提交,则不在 Git 中 1 1个

The repository proper consists mainly of two databases.适当的存储库主要由两个数据库组成。 One database holds Git's objects —commits and other supporting objects.一个数据库保存 Git 的对象——提交和其他支持对象。 The other holds names such as branch and tag names.另一个保存名称,例如分支和标签名称。 Both databases are simple key-value stores , with the names database storing hash ID values using the names as the keys, and the objects database storing the objects using hash IDs as the keys.两个数据库都是简单的键值存储,名称数据库存储 hash 个 ID 值,使用名称作为键,对象数据库使用 hash 个 ID 作为键存储对象。 There are also a bunch of auxiliary files in the .git directory, but it's the object database that is copied, more or less wholesale, by git clone . .git目录中还有一堆辅助文件,但它是由git clone复制的object数据库,或多或少是批发的。 The names database is used to seed a new, independent names database in the new clone, with the clone holding different names but the same hash IDs .名称数据库用于在新克隆中播种一个新的独立名称数据库,该克隆具有不同的名称具有相同的 hash ID The hash IDs are universal—shared among all Git repositories everywhere via a hashing algorithm—but the names are unique to each Git repository. hash ID 是通用的——通过散列算法在所有Git 存储库之间共享——但每个 Git 存储库的名称是唯一的。 2 2个

So, the repository consists of these two databases, as stored inside the hidden .git directory.因此,存储库由这两个数据库组成,存储在隐藏的.git目录中。 Git also stores a lot of extra data in the .git directory, which have varying amounts of importance to Git itself while you're using Git, but relatively less importance to you as a user of Git. That means that you can either say that the repository "is" the .git directory and its contents, or that the repository "is" the two databases: either claim is okay, especially if you qualify it as necessary. Git 还在.git目录中存储了大量额外数据,当您使用 Git 时,这些数据对 Git 本身具有不同程度的重要性,但对您作为 Git 的用户来说相对不太重要。这意味着您可以说存储库“是” .git目录及其内容,或者存储库“是”两个数据库:任何一种说法都可以,特别是如果您根据需要对其进行限定。

But what about your working tree files?但是你的工作树文件呢? Well, before we get there, let's note one other feature of the objects database.好吧,在我们到达那里之前,让我们注意对象数据库的另一个特性。 The hash ID system that Git uses requires that objects never change . Git 使用的 hash ID 系统要求对象永不更改 The hash ID of some object is simply a cryptographic checksum of the object's content: that's how Git manages, algorithmically, the trick of having the same ID everywhere.一些 object 的 hash ID 只是对象内容的加密校验和:这就是 Git 在算法上管理到处具有相同 ID 的技巧的方式。 But it depends on this "never change" property.但这取决于这个“永不改变”的属性。

What this means is that the committed copies of files literally can't change.这意味着文件的已提交副本实际上无法更改。 Git therefore stores, in each commit, a full snapshot of every file, in a compressed, Git-ified, de-duplicated, and read-only fashion.因此,Git 在每次提交中以压缩、Git 化、去重和只读方式存储每个文件的完整快照。 The de-duplication handles the fact that most commits mostly have the same files as some previous commits.重复数据删除处理这样一个事实,即大多数提交大多具有与之前的一些提交相同的文件。 Since they are the same, they are de-duplicated and use no space at all.因为它们相同的,所以它们被删除重复并且根本不使用空间。 The read-only nature of the objects makes this possible, and the full-snapshot nature of each commit makes it necessary, in a sort of Ouroboros fashion.对象的只读特性使这成为可能,而每次提交的完整快照特性使其成为一种必要,以一种Ouroboros的方式。

But—this means you literally cannot use the committed files at all .但是——这意味着您根本无法使用提交的文件。 Only Git can read them, and literally nothing, not even Git itself, can write to them.只有Git可以读取它们,实际上没有任何东西,甚至 Git 本身也不能写入它们。 So what good are they?那他们有什么好处呢? Well, like any archive, the snapshot in any given commit can be extracted .好吧,就像任何存档一样,可以提取任何给定提交中的快照。 This is where your working tree comes in. When you select some particular commit—with git checkout or git switch for instance: you pick out some branch name, and the branch name picks out the latest commit that is currently "on" that branch—Git will extract the committed files.这就是你的工作树进来的地方。当你 select 一些特定的提交时 - 例如git checkoutgit switch :你选择一些分支名称,分支名称选择当前“在”该分支上的最新提交 - Git 将提取提交的文件。 The files come out of the archive, and go into your working tree.文件从存档中出来,然后 go 进入您的工作树。

The working tree in a standard Git repository is the directory in which you ran git init , if you created the repository that way, or the directory where git clone put the new clone, if you created the repository that way.标准 Git 存储库中的工作树是您运行git init的目录,如果您以这种方式创建存储库,或者git clone放置新克隆的目录,如果您以这种方式创建存储库。 The hidden .git folder is stored inside that working tree, in the top level.隐藏的.git文件夹存储在该工作树中的顶层。 The repository is in the .git directory but the files you use are in the working tree.存储库位于.git目录中,但您使用的文件位于工作树中。 This means that the files you use are not in Git!这意味着你使用的文件不在 Git 中! They're only in the working tree.他们只在工作树中。 Until you save them in a commit, these files aren't in Git. Some of them came out of Git, if you have existing commits and are using one of those;在您将它们保存在提交中之前,这些文件不在Git 中。其中一些来自Git,如果您有现有的提交并且正在使用其中之一; you can get those back because they are in a commit, and came out of Git. But any file you've modified in the working tree is just a file on your computer.您可以取回它们,因为它们处于提交状态,并且来自 Git。但是您在工作树中修改的任何文件都只是您计算机上的一个文件。 It's not in Git. Git can't get it back for you, if you destroy it.它不在 Git。Git 无法为您取回,如果您销毁它。

The bottom line is that files that are not committed are not in Git .底线是未提交的文件不在 Git 中 That's why you should commit early and often.这就是为什么您应该尽早并经常做出承诺。 Git can get you those files back; Git 可以为您取回那些文件; it can't get back the ones you never committed.它无法取回您从未承诺过的那些。

(Note that it's also crucial that you not destroy the .git directory, through action or inaction. Don't put the .git folder in a cloud-shared / cloud-managed location as cloud-sharing software tends to damage Git's internal files. Cloud-syncers assume that humans are dealing with each file, and that humans know what to do with files named README.txt.cloudified-version-2 and so on. Git has no idea what to do if the cloud software renames its precious database files, and will think—correctly, at this point—that the repository is damaged.) (请注意,无论是作为还是不作为,都不要破坏.git目录也很重要。不要将.git文件夹放在云共享/云管理的位置,因为云共享软件往往会损坏 Git 的内部文件。 Cloud-syncers 假设人类正在处理每个文件,并且人类知道如何处理名为README.txt.cloudified-version-2等的文件。Git 不知道如果云软件重命名其珍贵的数据库该怎么办文件,并且会认为——在这一点上是正确的——存储库已损坏。)


1 There's a technical niggle here. 1这里有一个技术问题。 If you have used git add on a file, this causes the file's content —but not the file's name —to be stored in the Git objects database.如果您在文件上使用了git add ,这会导致文件的内容(而不是文件的名称)存储在 Git 对象数据库中。 So sometimes this kind of content is recoverable.所以有时这种内容是可以恢复的。 The name gets stored in Git's index , which is in an important sense less solid or more ephemeral than an object-database entry.名称存储在 Git 的索引中,在重要的意义上,它比对象数据库条目更不可靠或更短暂。 Entities in the objects database persist for at least 14 days by default, regardless of other actions.对象数据库中的实体默认至少保留 14 天,无论其他操作如何。 Meanwhile, the index is constantly being updated every time you update the proposed next commit, or run git merge , or run git checkout or git switch or whatever.同时,每次更新建议的下一次提交、运行git merge或运行git checkoutgit switch或其他任何操作时,索引都会不断更新。 Entities in the object database are read-only; object数据库中的实体是只读的; but the index is regularly overwritten, and an index entry that's lost this way is lost forever.但是索引会定期被覆盖,以这种方式丢失的索引条目将永远丢失。

In any case, aside from the occasional ability to use git fsck --lost-found to recover the content of a file that was git add -ed but never committed, there's not a lot Git can do about files that did not make it into a commit.在任何情况下,除了偶尔能够使用git fsck --lost-found来恢复git add但从未提交的文件的内容之外,Git 对未进入的文件无能为力一个承诺。

2 There's a sort of standard mapping, where if I clone your Git repository, my clone's names database stores your branch names as my remote-tracking names. 2有一种标准映射,如果我克隆您的 Git 存储库,我克隆的名称数据库会将您的分支名称存储为我的远程跟踪名称。 My branch names, which are independent of your branch names, then become another third person's remote-tracking names when the third person clones my clone of your clone.我的分支名称,独立于你的分支名称,然后当第三人克隆的克隆你的克隆时,成为另一个第三方的远程跟踪名称。 Tag names, however, are by default copied as-is, so that the tag names are universal across all these clones.然而,标签名称默认按原样复制,因此标签名称在所有这些克隆中都是通用的。 You, as the person running git clone and then additional Git commands, are in charge of this kind of mapping, so this is just a default standard.你,作为运行git clone然后附加 Git 命令的人,负责这种映射,所以这只是默认标准。 The fact that the hash IDs are universal is not under your control, but the way the names map is . hash ID 是通用的这一事实不受您的控制,但名称 map 的方式.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在主分支和分支中的Git修改文件 - Git modified files in master and branches 如何仅将过去分支中的更改文件合并到GIT中的主文件中? - How to merged only changed files from a past branch into the master in GIT? Git:如何列出从特定日期合并到主控的所有远程分支/按日期排序 - Git : how to list all remote branches which ve been merged to master from a specific date / sorted by date 如何删除在 git 中以编程方式合并到 master 的超过 1 个月的分支? - How to delete branches older than 1 month that was merged to master programmatically in git? Linux内核的稳定git分支是否合并回主服务器? - Are the Linux kernel's stable git branches merged back into master? 如何以编程方式找到已使用git合并到master的分支? - How to programmatically find branches that were merged into master with git? Git:如何删除所有本地分支(合并与否),除了master和develop - Git : How to delete all local branches (merged or not), except master and develop 从 master 更新 Git 分支 - Update Git branches from master Git:如何找到所有从未合并回master的分支 - Git: How to find all branches that were never merged back into master Git:列出合并到Master的分支数量,但不在Release分支上 - Git: List the number of branches merged to Master but not on Release branch
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM