简体   繁体   English

我可以将一个本地 git 存储库与两个远程存储库一起使用吗?

[英]Can I use one local git repo with two remote repo?

New to git and want to be sure I understand what I'm doing. git 新手,想确保我明白我在做什么。

Currently, I have a local repo pushing to a public remote repo.目前,我有一个本地仓库推送到公共远程仓库。 There are certain files and dir that I want to separate from the public remote repo and add to a private remote repo.我想将某些文件和目录与公共远程存储库分开并添加到私有远程存储库中。

My plan is to add these files and dir to .gitignore , create a new branch named privateRepo , then link it to the private remote repo.我的计划是将这些文件和目录添加到.gitignore ,创建一个名为privateRepo的新分支,然后将其链接到私有远程privateRepo Afterwards, switch to the branch, privateRepo and add/commit/push the local contents.之后,切换到分支, privateRepo并添加/提交/推送本地内容。

git checkout -b privateRepo
git remote add privateRepo <url>
git switch privateRepo
git add <files & dir>
git commit -m "message"
git push

After this, I can use git switch main to return to my main branch and push without influencing privateRepo .之后,我可以使用git switch main返回到我的主分支并推送,而不会影响privateRepo

Is this correct?这样对吗?

Will this pose any problems if I want to pull from privateRepo to my local repo?如果我想从privateRepo我的本地privateRepo ,这会带来什么问题吗?

You can do what you're proposing.可以做你提议的事情。 I would advise against it because:我建议不要这样做,因为:

  • it doesn't work the way I think you think it does;它不像我认为的那样工作; and
  • it's far too easy to accidentally send the wrong commits to the wrong "other Git repository", thereby publishing forever your private files.很容易不小心将错误的提交发送到错误的“其他 Git 存储库”,从而永久发布您的私人文件。

To understand this, we need to cover the basics of what a repository is and does for you.要理解这一点,我们需要介绍存储库是什么以及为您做什么的基础知识。 A repository is, primarily, a collection of two databases:存储库主要是两个数据库的集合:

  • One database holds commits and other supporting Git objects.一个数据库保存提交和其他支持 Git 对象。 This is the "object database".这是“对象数据库”。 It is a simple key-value store in which the keys are hash IDs —commit hash IDs, and other supporting object hash IDs—and the values are the objects (the commits and the stuff commits use to store files forever).它是一个简单的键值存储,其中键是散列ID——提交散列 ID 和其他支持的对象散列 ID——而值是对象(提交和提交用于永久存储文件的东西)。

  • The other database holds names .另一个数据库保存名称 The keys in the object database—the hash IDs—are too big and ugly for humans to deal with.对象数据库中的键——哈希 ID——对于人类来说太大而难看。 So we don't: we use names.所以我们不:我们使用名称。 Git keeps the second database around so that it can translate from name to hash ID, to find the commits (and other internal objects). Git 保留第二个数据库,以便它可以从名称转换为哈希 ID,以查找提交(和其他内部对象)。 Humans can deal with names, like master or main as a branch name, for instance.例如,人类可以处理名称,例如mastermain作为分支名称。

When you use more than one Git repository and cross-connect them with git fetch or git push (note that git pull is a convenience command that means run git fetch , then run a second Git command , so it's really git fetch in disguise), what you're doing is transferring the commits between the repositories.当您使用多个 Git 存储库并将它们与git fetchgit push交叉连接时(请注意, git pull是一个方便的命令,这意味着运行git fetch ,然后运行第二个 Git 命令,因此它实际上是伪装的git fetch ),您正在做的是在存储库之间传输提交 You have few options here: you either send a whole commit, or none of it.您在这里有几个选择:要么发送整个提交,要么不发送。 You either receive a whole commit, or none of it.你要么收到一个完整的提交,要么没有。 1 If you do send, or receive, a commit, you also send or receive all its predecessor (ancestor) commits that you or they don't have. 1如果您确实发送或接收了一个提交,那么您也会发送或接收您或他们没有的所有前辈(祖先)提交 2 2

The upshot of this is that if you accidentally send one commit to the wrong (ie, public) repository, you'll likely send all of them.这样做的结果是,如果您不小心将一个提交发送到错误的(即公共)存储库,您可能会发送所有提交。 Now they have every version of every private file you ever committed.现在他们拥有您提交的每个私人文件的每个版本。 You can try to take this back—GitHub make this somewhat difficult as you must contact GitHub support—but during the window where these commits are visible, anyone and everyone can copy them from the public repository.可以尝试收回这个——GitHub 使这有点困难,因为你必须联系 GitHub 支持——但是在这些提交可见的窗口期间,任何人和每个人都可以从公共存储库中复制它们。

If you, instead, split the files into "public availability files"—which you put in one repository and then share that repository with GitHub as a public repository there—and "private files" that go into a different repository , and then share that one with GitHub only as a private repository, the whole thing is much more manageable.相反,如果您将文件拆分为“公共可用性文件”(您将其放在一个存储库中,然后与 GitHub 作为公共存储库在那里共享该存储库)和进入另一个存储库的“私有文件”,然后共享该存储库一个 GitHub 仅作为私有存储库,整个事情更易于管理。

You can coordinate the two repositories with Git's submodules , as Ôrel mentioned in a comment .您可以使用 Git 的子模块来协调这两个存储库,如评论中提到的 Ôrel Submodules have their own headaches and drawbacks, enough so that people sometimes call them sob -modules, but they do achieve a proper public/private split.子模块有它们自己的头疼和缺点,以至于人们有时称它们为sob模块,但它们确实实现了适当的公共/私有拆分。


1 Git is growing a new facility called partial clones where this general all-or-nothing principle is carefully pulled apart, like a Jenga tower . 1 Git 正在开发一种称为部分克隆的新工具,在该工具中,这种通用的全有或全无原则被小心地拆分开来,就像叠层塔一样 Pull the wrong part and the whole thing collapses, though.但是,拉错了部分,整个事情就会崩溃。 This is not—at least currently—meant for the kind of thing you're talking about and I would not advise using it for that, unless you plan to work on Git itself to add that.这不是 - 至少目前 - 意味着你正在谈论的那种事情,我不建议使用它,除非你计划在 Git 本身上添加它。 (It could in theory be used for this sort of purpose.) (理论上它可以用于这种目的。)

2 This rule, too, can be carefully violated with shallow clones . 2浅克隆也可以小心地违反此规则。 Shallow clones are more mature than the partial clone code, but they still don't do the kind of thing you want.浅层克隆比部分克隆代码更成熟,但它们仍然没有做你想要的那种事情。


Some more words about repositories关于存储库的更多词

Many people think Git is about files.许多人认为 Git 是关于文件的。 It's not: it's really about commits .这不是:它真的是关于commits The commits do, however, hold files.但是,提交确实会保留文件。 Or they'll think that Git is about branches.或者他们会认为 Git 是关于分支的。 It's not: it's about commits.这不是:这是关于提交。 The branch names, however, do help you (and Git) find the commits.但是,分支名称确实可以帮助您(和 Git)找到提交。 So branch names, and files, are important.所以分支名称和文件很重要。 But it's really all about the commits.但这真的是关于提交的。

Because commits are stored in the object database, they're numbered , with those big ugly hash IDs.因为提交存储在对象数据库中,所以它们被编号,并带有那些大而难看的哈希 ID。 Every unique object gets a unique number.每个唯一的对象都有一个唯一的编号。 The commit numbers in particular must be unique across every Git repository in the universe , which means the numbers must be huge (currently there are 2 160 possible numbers, and this will probably become 2 256 in the relatively near future as it turns out 2 160 is too small).特别是提交编号在Universe 中的每个 Git 存储库中必须是唯一,这意味着数字必须很大(目前有 2 160 个可能的数字,并且在相对不久的将来这可能会变成 2 256 ,因为结果是 2 160太小)。 That's why they are so big and ugly and random-looking, though actually they're entirely non-random: they are outputs from a cryptographic hash function (currently SHA-1; SHA-256 is the planned future).这就是为什么它们如此巨大、丑陋和随机的原因,尽管实际上它们完全是非随机的:它们是加密哈希函数的输出(目前是 SHA-1;SHA-256 是计划的未来)。

Each commit, though, stores two things:但是,每次提交都会存储件事:

  • Every commit stores a full snapshot of every file, as of the form the file had at the time you (or whoever) made the commit.每次提交都存储每个文件的完整快照,按照您(或任何人)提交时文件的形式。 These are stored in a special, read-only, Git-only, compressed and de-duplicated format (as objects in the database), not as ordinary computer files.它们以特殊的、只读的、仅限 Git 的、压缩和重复数据删除的格式存储(作为数据库中的对象),而不是普通的计算机文件。

  • Every commit stores some metadata , or information about the commit itself: who made it, when, and why (a log message) for instance.每个提交都存储一些元数据,或关于提交本身的信息:例如,谁提交,何时提交,以及为什么(一条日志消息)。 This metadata is as read-only as everything in the objects database.此元数据与对象数据库中的所有内容一样只读。 (The read-only quality comes from Git's hashing tricks, and is necessary to allow the file de-duplication as well.) (只读质量来自 Git 的散列技巧,也是允许文件重复数据删除所必需的。)

In the metadata for any one given commit, Git stores the raw hash ID(s) of a list of previous commit(s).在任何给定提交的元数据中,Git 存储先前提交列表的原始哈希 ID。 Usually this list is just one element long.通常这个列表只有一个元素长。 We call this single previous commit the parent of the commit.我们将这个单一的先前提交称为提交的父级 These parent IDs form backwards-looking chains:这些父 ID 形成后向链:

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

Here H stands in for the hash ID of the last commit in the chain.这里H代表链中最后一次提交的哈希 ID。 Commit H has, inside it, a full snapshot of all of your files, plus some metadata. Commit H在其中包含所有文件的完整快照,以及一些元数据。 The metadata in H show you that you (or whoever) made the commit. H的元数据显示您(或任何人)进行了提交。 They keep data such as your log message.他们保留诸如您的日志消息之类的数据。 And, they show that commit H has one parent, whatever hash ID G stands in for.而且,他们表明提交H有一个父级,无论哈希 ID G代表什么。

Commit G , of course, also has a snapshot and metadata.当然,Commit G也有快照和元数据。 Using H , Git can find G , and extract both snapshots and compare them.使用H ,Git 可以找到G ,并提取两个快照并进行比较。 Whatever is the same did not change (and this is easy for Git to see because of the de-duplication via hashing).无论是相同的都没有改变(这对于 Git 来说很容易看到,因为通过散列进行了重复数据删除)。 Whatever is different, here Git will need to run git diff to figure out what changed .无论有什么不同,这里 Git 都需要运行git diff来找出发生了什么变化 Git will do this if and when you ask for it, and you'll see what changed going from G to H , when you view commit H . Git 会在您要求时执行此操作,并且当您查看提交H时,您将看到从GH更改

Having viewed commit H , a command like git log now moves back one hop to commit G .查看提交H ,像git log这样的命令现在向后移动一跳以提交G Commit G has metadata, including the hash ID of earlier commit F .提交G具有元数据,包括较早提交F的哈希 ID。 Commit F has a snapshot, so Git can compare F -vs- G to see what changed, and hence show you G as changes, even though G is a snapshot.提交F有一个快照,因此 Git 可以比较F -vs- G以查看发生了什么变化,从而将G显示为更改,即使G一个快照。 Then git log can move back one hop to F , and repeat.然后git log可以向后移动一跳到F ,并重复。 The process ends only when Git has gone back to the very first commit ever, which—being the first commit—has no parent, or when you get tired of reading git log output and make it quit.只有当 Git 回到有史以来的第一次提交时,这个过程才会结束,这是第一次提交,没有父提交,或者当你厌倦了阅读git log输出并让它退出时。

Using commits: the work-tree and the index / staging-area使用提交:工作树和索引/暂存区

But there's a big problem here.但是这里有一个大问题。 If the content in a snapshot, the saved-for-all-time files, is read-only —and, worse, in a format that only Git itself can read in the first place—how will we ever use it?如果快照中的内容,即所有时间保存的文件,是只读的——更糟糕的是,它的格式只有 Git 本身才能读取——我们将如何使用它?

The answer to this problem is simple enough.这个问题的答案很简单。 In a non-bare repository (which is to say, most of them), Git adds a working area , called a working tree or work-tree .在一个非裸仓库(也就是说,大部分)中,Git 添加了一个工作区,称为工作树工作树 To use a commit, Git simply copies all the files out of the commit , into your working tree.若要使用承诺,简直混帐将所有文件复制出来的承诺,到你的工作树。 Now you can see your files and do your work.现在您可以查看您的文件并完成您的工作。

It's important to realize that these files are not in Git .重要的是要意识到这些文件不在 Git 中 These are ordinary computer files, that all your ordinary computer programs can read and write and generally work with.这些是普通的计算机文件,您的所有普通计算机程序都可以读写并且通常可以使用这些文件。 They may have come out of Git.他们可能已经来临Git出来 But at this point, they're not in Git any more.但在这一点上,他们不再Git 中了。 They're just files.它们只是文件。

As you work with them, they may drift away from what's in Git.当你与他们的工作,他们可能会从什么是Git渐行渐远。 Their contents change.它们的内容发生了变化。 At some point, you might wish to take all the updated files and store them forever, in a new commit.在某些时候,您可能希望获取所有更新的文件并将它们永久存储在新的提交中。 In other, non-Git, version control systems, this is pretty easy: you run, eg, hg commit and Mercurial figures out what you changed and makes a new commit.在其他非 Git 版本控制系统中,这非常简单:您运行,例如hg commit ,Mercurial 会找出您更改的内容并进行新的提交。 In Git, this is not so easy.在 Git 中,这不是那么容易。

Instead, Git adds a hidden extra "copy" of each file.相反,Git 为每个文件添加了一个隐藏的额外“副本” I say "copy" in quotes here because this extra "copy" of each file is pre-Git-ified: it is stored in the compressed, de-duplicated format that Git uses internally.我在这里用引号说“复制”是因为每个文件的这个额外“副本”是预先 Git 化的:它以 Git 内部使用的压缩、重复数据删除格式存储。 Since all these files initially came out of some commit, they're all duplicates, and therefore none of them take any space.由于所有这些文件最初出来的一些承诺,他们都是重复的,因此他们没有采取任何空间。 3 3

When you tell Git make a new commit now , Git looks only at these hidden extra copies.当你告诉 Git make a new commit now 时,Git 只查看这些隐藏的额外副本。 So, before you make a new commit, you must run git add .所以,你才能建立新的提交,你必须运行git add What git add does is: git add作用是:

  • read through the working tree copy of some file;通读某个文件的工作树副本;
  • compress and generally Git-ify it, coming up with an internal object hash ID;压缩并一般 Git-ify 它,提出一个内部对象哈希 ID;
  • if that's a duplicate of some existing file, throw out the temporary stuff built up now and use the duplicate;如果这是某个现有文件的副本,则丢弃现在建立的临时文件并使用副本;
  • otherwise, prep it for future committing and store it.否则,为将来的提交做好准备并存储它。

Either way, the git add step takes the updated file and makes it ready to go into the next commit.无论哪种方式, git add步骤都会获取更新的文件并使其准备好进入下一次提交。 This replaces the copy that was there , ready to go into the next commit.替换那里的副本,准备进入下一次提交。 Or, if the file is all-new—if there was no file with this name before—then git add has nothing to replace, and instead adds a new file, and now there is a copy, ready to go into the next commit.或者,如果文件是全新的——如果之前没有这个名字的文件——那么git add没有什么可以替换的,而是添加一个新文件,现在有一个副本,准备进入下一次提交。

In all cases, then, before git add , Git had all the files ready to go into the new commit.在所有情况下,git add之前,Git 已准备好所有文件以进入新提交。 After git add , Git has all the files ready to go into the new commit.git add ,Git 已准备好所有文件以进入新的提交。 So Git always has all the files ready to go.所以 Git总是准备好所有文件。 What git add does is replace one, or two, or many, of those ready-to-go "copies" with updated files (new copies if needed, or re-used old "copies" if possible) and add any new files. git add所做的是用更新的文件(如果需要,新的副本,或者如果可能,重新使用旧的“副本”)替换一个、两个或多个现成的“副本”,并添加任何新文件。

The area in which this extra ready-to-go not-quite-a-commit-yet thing lives has three names in Git.这个额外的现成的尚未完全提交的东西所在的区域在 Git 中有三个名称。 This may be because the primary name, the index , is meaningless.这可能是因为主名称index没有意义。 The other main name, the staging area , refers to how you use the index.另一个主要名称,暂存区,指的是您如何使用索引。 The third name, the cache , is mostly defunct, but still shows up in flags like git rm --cached .第三个名字,缓存,大部分已经不复存在,但仍然出现在像git rm --cached这样的标志中。 I tend to use the name "index", but "staging area" has probably become the most common, and it's definitely how you use it: you "stage" the files by arranging them on/in a "staging area", ready to be "photographed" into a commit where they will live forever.我倾向于使用名称“索引”,但“暂存区”可能已成为最常见的名称,这绝对是您使用它的方式:您通过将文件安排在“暂存区”上/在“暂存区”中来“暂存”文件,准备好被“拍到”成为他们将永远生活的承诺。

This staging area, or index, sits between the current commit and your working tree.这个暂存区或索引位于当前提交和您的工作树之间。 Git's index is a lot like a commit, and is initially set up from a commit and later becomes a new commit , but the key difference between an actual commit and Git's index is that you can replace files in, add files to, and remove files from Git's index. Git 的索引很像一次提交,最初是一次提交设置的,后来变成了新的提交,但实际提交和 Git 的索引之间的主要区别在于您可以替换文件、添加文件和删除文件来自Git 的索引。 You can't do that to a commit: the commit, once made, is set in stone.你不能对提交这样做:提交一旦完成,就一成不变。

When you do finally run git commit , Git simply packages up the files that are in the index right then .当你最后运行git commit ,Git的简单包起来是在指数权然后将文件。 Those become the snapshot for the new commit.这些成为新提交的快照。 So you must update the index .所以你必须更新索引 People are often tempted by git commit -a , but there are some flaws with this and I advise users to avoid it (see below).人们经常受到git commit -a诱惑,但是这有一些缺陷,我建议用户避免使用它(见下文)。

In any case, I find that it helps, to think of the index as being between commit and working tree, like this:无论如何,我发现将索引视为位于提交树和工作树之间是有帮助的,如下所示:

  HEAD         index      work-tree
---------    ---------    ---------
README.md    README.md    README.md
main.py      main.py      main.py
                          new.txt

Here, we checked out some commit that had two files in it, so HEAD —the current commit—has those two files, and Git's index has those two files, and our working tree has those two files.在这里,我们检查了一些承诺是有两个文件,所以HEAD -the当前提交-有这两个文件,和Git的指数有这两个文件,我们的工作树有这两个文件。 Unlike the HEAD and index copies, we can actually see and use the working tree copies, but all three exist.与 HEAD 和索引副本不同,我们实际上可以看到和使用工作树副本,但是这三个副本都存在。

Then we made a new file , new.txt , in the working tree.然后我们在工作树中new.txt了一个新文件new.txt It doesn't exist in HEAD , and it doesn't exist in Git's index.它不存在于HEAD ,也不存在于 Git 的索引中。 Now we come to an interesting special case.现在我们来看一个有趣的特例。


3 They take some space for name, hash ID, and a bunch of cache data that Git uses internally. 3它们占用一些空间用于名称、哈希 ID 和 Git 内部使用的一堆缓存数据。 The amount of space needed depends on the name lengths and the index format (there are multiple index format numbers) but it's generally pretty tiny, on the order of 100 bytes per file.所需的空间量取决于名称长度和索引格式(有多个索引格式编号),但通常非常小,每个文件大约 100 个字节。


Tracked, untracked, and ignored files跟踪、未跟踪和忽略的文件

The new file we made in the working tree is not in Git .我们在工作树中创建的新文件不在 Git 中 Neither are the two other files we can see, but those two do have copies that are in Git, in the HEAD commit, and a proposed new commit prepared in the index.也不是我们可以看到两个其他文件,但是这两个确实Git的副本,在HEAD承诺和所提出的新的提交索引编制。 But new.txt is not in the index: it's not even in the proposed next commit.但是new.txt不在索引中:它甚至不在提议的下一次提交中。

At this point, new.txt is what Git calls an untracked file .此时, new.txt就是 Git 所说的未跟踪文件 An untracked file is defined as any file that is not in Git's index right now .未跟踪文件定义为目前不在 Git 索引中的任何文件

Suppose, for instance, that we now run:例如,假设我们现在运行:

git rm --cached main.py

to produce this:产生这个:

  HEAD         index      work-tree
---------    ---------    ---------
README.md    README.md    README.md
main.py                   main.py
                          new.txt

We didn't change the commit (we can't change its contents), but now main.py is not in Git's index right now .我们没有改变提交(我们不能改变它的内容),但现在main.py不在 Git 的索引中 The main.py in our working tree has gone from tracked to untracked .我们工作树中的main.py已经从tracked变为untracked

If we run git add main.py new.txt right now, Git will:如果我们现在运行git add main.py new.txt ,Git 将:

  • read the contents of main.py , compress them, and discover it's a duplicate and re-use the old main.py in the index;读取main.py的内容,压缩它们,发现它是重复的并在索引中重新使用旧的main.py
  • read the contents of new.txt , compress them, and probably discover it's new and make a new Git-ified copy prepared for commit, and put that in the index;读取new.txt的内容,压缩它们,可能会发现它是新的,并制作一个新的 Git 化副本准备提交,并将其放入索引中;

and now we will have:现在我们将拥有:

  HEAD         index      work-tree
---------    ---------    ---------
README.md    README.md    README.md
main.py      main.py      main.py
             new.txt      new.txt

Now we have no untracked files.现在我们没有未跟踪的文件。

The tracked-ness of a file is changeable.文件的跟踪性是可变的。 All we have to do is create or remove index entries and/or working tree files.我们所要做的就是创建或删除索引条目和/或工作树文件。 Those files that are in both are tracked files;两者中的那些文件都是跟踪文件; those files that are only in the working tree are untracked files .那些仅在工作树中的文件未跟踪的文件 And that's all there is to that— almost .这就是全部——几乎

Why .gitignore does not mean what people think it means为什么.gitignore并不意味着人们认为它意味着什么

A file that is in Git's index is never ignored . Git 索引中的文件永远不会被忽略

An entry in .gitignore , listing a file's name, tells Git, in part, if this file is untracked, don't complain about it. .gitignore一个条目,列出了一个文件的名称,部分地告诉 Git,如果这个文件没有被跟踪,不要抱怨它。 The git status command is very useful, as it will tell us about what's in the index and what's not in the index, in terms of stuff we have forgotten to git add for instance. git status命令非常有用,因为它会告诉我们什么在索引中,什么不在索引中,例如我们忘记git add的内容。 That includes any file that's in the working tree, but not in the index.这包括工作树中的任何文件,但不在索引中。

But some things—like Python 2.x—generate a lot of working tree files that should never be committed .但是有些东西——比如 Python 2.x——会生成很多不应该提交的工作树文件。 If git status complained about all your *.pyc files all the time, git status could become unusable: the useful nuggets of "oh I forgot to git add this one thing" would be buried in the useless "here are 5000 *.pyc files you could add" messages.如果git status抱怨你所有的*.pyc文件,那么git status可能变得无法使用:“哦,我忘了git add this one thing”的有用信息将被埋没在无用的“here are 5000 *.pyc files”中你可以添加”消息。

To prevent this, we list the *.pyc glob pattern in a .gitignore file.为了防止这种情况,我们在.gitignore文件中列出了*.pyc glob 模式 This makes git status shut up about these files.这使得git status关闭这些文件。

It has one other effect as well.它还有另一种效果。 We can run git add .我们可以运行git add . or git add --all or similar to do an en-masse "add everything".git add --all或类似的来做一个整体“添加所有内容”。 When we do use this, Git will skip any existing untracked file that's also listed in .gitignore .当我们确实使用它时,Git 将跳过也在.gitignore列出的任何现有的未跟踪文件。 But Git only skips the untracked files, not the tracked ones.但是 Git 只跳过未跟踪的文件,而不是跟踪的文件。 The tracked files—the ones that are in Git's index—get updated.被跟踪的文件,该在Git的指数,获得更新的。 (This is actually usually what people want.) (这实际上通常是人们想要的。)

So, .gitignore is the wrong name.因此, .gitignore是错误的名称。 The file should be named something like .git-do-not-complain-about-these-files-when-they-are-untracked-and-also-if-they-are-untracked-and-I-use-an-en-masse-git-add-command-do-not-add-them-to-the-index-after-all .该文件应命名为.git-do-not-complain-about-these-files-when-they-are-untracked-and-also-if-they-are-untracked-and-I-use-an-en-masse-git-add-command-do-not-add-them-to-the-index-after-all But this name is ridiculous, as are several slightly shorter versions.但是这个名字很荒谬,几个略短的版本也是如此。 So it's just called .gitignore .所以它只是被称为.gitignore

The key here is that it won't ignore files that are in the index.这里的关键是,它不会忽略索引文件。 For a file to go into a commit, it has to be in Git's index .对于要提交的文件,它必须在 Git 的 index 中 If it was in a commit and we checked the commit out, the file is now in Git's index .如果它在提交中并且我们检查了提交,则该文件现在在 Git 的 index 中 So once a file gets committed, it tends to sneak back into the index, even if we take it out now and then: any time we check out a commit that has the file, it's back in the index.所以一旦一个文件被提交,它往往会偷偷溜回索引,即使我们时不时地把它取出来:每当我们检出一个包含文件的提交时,它就会回到索引中。 And then its listing in .gitignore has no effect.然后它在.gitignore中的列表无效。

Why (and when) to avoid git commit -a为什么(以及何时)避免git commit -a

What git commit -a does is use a shortcut. git commit -a所做的是使用快捷方式。 It:它:

  • runs git add for you , and then为你运行git add ,然后
  • does the git commit step.执行git commit步骤。

You can also do things like:您还可以执行以下操作:

git commit --only main.py

and:和:

git commit --include main.py

These all manipulate the index, then do the commit.这些都操作索引,然后进行提交。 However, they're quite tricky: they make Git make one or two extra and temporary index files for the duration of the commit.然而,它们非常棘手:它们使 Git 在提交期间生成一两个额外的临时索引文件。 These extra index files can mess with pre-commit hooks.这些额外的索引文件可能会干扰预提交钩子。 Whether, and when, and how much, they do mess with such hooks depends on several things, including how carefully the hook writer wrote their hook, whether they were even aware of this Git trick, and whether you use the --only or --include form of git commit .是否,以及何时,多少,他们乱用这种挂钩取决于几个因素,包括挂钩作家如何认真地写下自己的钩,无论他们甚至知道这个混帐招,以及是否使用--only--include形式的git commit 4 4

That said, git commit -a usually works fine (see footnote 4).也就是说, git commit -a通常可以正常工作(参见脚注 4)。 But it is roughly equivalent to running git add -u first, and then running git commit .但大致相当于先运行git add -u ,然后运行git commit The -u option to git add will only update known files , not add new ones . git add-u选项只会更新已知文件,不会添加新文件 When we use git add .当我们使用git add . to en-masse add everything we've updated, this includes adding new files.批量添加我们更新的所有内容,这包括添加新文件。 The -a option to git commit can't add a new file. git commit-a选项不能添加文件。

Besides this, git commit -a is just plain lazy.除此之外, git commit -a只是懒惰。 Sometimes laziness is a virtue, so this doesn't mean never use it.有时懒惰是一种美德,所以这并不意味着永远不要使用它。 But git status , followed by careful git add operations—perhaps even git add -p operations—followed by another git status , followed by git diff --cached (or git diff --staged —these do exactly the same thing), will help you arrange to commit only the changes you want .但是git status ,然后是仔细的git add操作——甚至可能是git add -p操作——接着是另一个git status ,然后是git diff --cached (或git diff --staged ——这些做完全相同的事情),会有所帮助您安排提交您想要的更改 Reading through the diff lets you compose a good commit message, or take notes at least, in another window, which you can then paste into the commit.通读 diff 可以让你在另一个窗口中编写一个好的提交消息,或者至少做笔记,然后你可以将其粘贴到提交中。 This lets you make good, careful commits .这可以让你做出好的、谨慎的提交 To do this, you must generally avoid git commit -a .为此,您通常必须避免git commit -a So it's at least a bad habit , even if laziness is occasionally a virtue.所以这至少是一个坏习惯,即使懒惰偶尔是一种美德。


4 git commit -a uses the --include mode internally. 4 git commit -a在内部使用--include模式。 This is less disruptive than the --only form, because --include needs only two index files, not three, and the one used during the commit is the one that becomes the new index after the commit if the commit succeeds.这是用不到的破坏性--only形式,因为--include只需要两个索引文件,而不是三个,并在提交中使用的是后,如果提交成功提交即成为新的指数之一。 The extra file is used only for the rollback case.额外文件仅用于回滚情况。 The --only form needs three: one for the commit, one for rollback, and one for success; --only形式需要三种:一种用于提交,一种用于回滚,一种用于成功; all three have—at least potentially—different content.这三者都有——至少可能是——不同的内容。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM