在我的本地倉庫中,我有不希望提交或上傳到遠程倉庫的大檔案。如果我將這些檔案添加到 .gitignore,它們是否仍會通過git push命令上傳到遠程倉庫?
uj5u.com熱心網友回復:
該git push命令發送提交,而不是檔案。然后每個提交包含每個檔案(它包含;見下文)。因此,要回答您提出的問題——是否git push上傳列出的任何檔案.gitignore——您必須檢查提交以查看它們是否包含這些檔案。
這個名字.gitignore本質上是錯誤的:它不會讓 Git忽略檔案。問題是,一個正確的名稱會非常笨拙以至于無法使用:它可能類似于.git-do-not-auto-add-these-files-if-they-are-untracked-and-if-they-are-untracked-do-not-complain-about-them-being-untracked-when-I-run-git-status. 它還有一個效果,雖然很少見,但也很重要:它允許 Git在特定情況下破壞這些檔案。所以一個完全正確的名字會更糟。但這兩個都是關于未跟蹤檔案的,是兩個常見的。
那么:首先,關于未跟蹤檔案的所有這些東西是什么?是什么讓檔案“未被跟蹤”?要回答這個問題,我們必須從 Git 存在的原因開始,那就是提交。
Git 是關于提交的
那些剛接觸 Git 的人通常認為它與檔案有關。它不是:它是關于提交的。提交確實包含檔案,但 Git 通常一次處理整個提交。或者,如果他們不認為 Git 是關于檔案的,那么初學者通常會認為 Git 是關于分支的,但事實并非如此:它仍然是關于提交的。分支——或者更準確地說,分支名稱——很重要,因為它們幫助我們(和 Git)找到提交。但真正重要的是提交。 如果您打算使用 Git,您必須了解提交是什么以及為您做什么。
每個提交:
有編號。提交的“數量”很大、丑陋且看起來很隨機。它實際上是一個以十六進制表示的通用唯一 ID ,例如
dcc0cd074f0c639a0df20461a301af6d45bd582e. 該數字一旦分配給該提交,就意味著該提交,而不是任何其他提交。這就是兩個不同的 Git 存盤庫如何決定它們是否具有相同的提交:它們要么有編號,在這種情況下他們有那個提交,要么一個有,一個沒有,然后一個沒有它的需要從那個做的人那里得到提交。完全只讀。所有 Git 內部物件都是這樣的——使編號方案起作用是必要的。
存盤 Git 在您或任何人進行提交時“知道”的每個檔案的完整存檔。提交中的檔案以特殊的、只讀的、僅 Git 的、壓縮的和去重的形式間接存盤,以便兩個不同的檔案具有相同的內容,或者兩個提交具有相同的檔案具有相同的內容,只存盤一次檔案。因此,雖然每個提交都有每個檔案的完整存檔,但所有提交也共享所有檔案,因此存盤庫不會變得非常臃腫。
還存盤一些元資料,或有關提交本身的資訊。這包括提交人的姓名和電子郵件地址。它包括一些日期和時間戳。它包括您想要放入的任何提交日志訊息。而且,對于 Git 自己的內部操作而言至關重要的是,每個提交都存盤了一個先前提交哈希 ID的串列。這個串列通常只有一個條目:這意味著這個提交緊跟在它列出的父提交之后。
正是這個父級串列,將向后提交的字串組合在一起,形成了存盤庫中的真正分支資訊。舉例來說,假設我們有提交該串兩端用哈希在一個我們稱之為H(用于H灰)。CommitH存盤一些較早提交的哈希 ID。我們說這H 指向這個較早的提交:
<-H
如果我們呼叫較早的 commitG并將其繪制進去,我們有:
<-G <-H
當然G也指向一個更早的提交,它再次指向后,依此類推:
... <-F <-G <-H
那是一個“分支”。要找到這個分支,Git 需要知道 commit 的實際哈希 ID H,我們將其粘貼在分支名稱中,并說該名稱指向 H:
...--F--G--H <-- main
如果我們有多個分支名稱,每個名稱只指向一個提交:
I--J <-- feature-1
/
...--G--H <-- main
\
K--L <-- feature-2
現在有三個“最后”提交:H是最后提交上main和以前一樣,但是J是最后一次提交的feature-1,并且L是最后一次提交的feature-2。請注意,提交H都在所有三個分支上(這是 Git 特有的;大多數版本控制系統都不是這樣作業的)。
如果提交中的檔案是只讀的且僅限 Git,我們如何使用它們?
The fact is that each commit is read-only, and the files inside the commit can only be read by Git itself. So before we can use a commit, we have to have Git extract the commit. We do this with git checkout or git switch: we pick some commit, by hash ID like H or by name like main which provides Git with hash ID H, and say extract that commit:
git switch main
Git will read all the files from commit H and expand them into ordinary everyday files. Git puts these files in a work area, which Git calls our working tree or work-tree.
That, then, answers the question about how we get work done: we use the working tree copies of the files. These files are not in Git! They came out of Git—at least, the initial ones did—but they are not in Git at this point.
Git's index or staging area
After we work on some file in the working tree, we might want Git to use that file—plus all the other files that we didn't change—to make a new commit. In other version control systems, we would generally run their "make commit" verb:
hg commit
for instance. They would figure out which files we changed and make the new commit. Git, alas, does not make it this easy. Instead, Git demands that we run:
git add updated-file
git commit
The first command—the git add step—tells Git: Read the working tree file, compress it into your internal Gitty format with de-duplication, and insert that into your index / staging-area, ready to be committed.
The secret here—it's not really a secret, but it's not always advertised or taught correctly—is that Git already has every existing checked-out file in its index / staging-area. This thing—the thing Git calls either the index or the staging area, depending on which bit of Git documentation is doing this calling—holds in it your proposed next commit.
When you first switch to some particular commit, Git removes from your working tree all the checked-out files that came out of whatever commit you were using, as recorded in its index. It also removes all the checked-out files from its index. Then it installs, into its index and into your working tree, all the files that go with the new commit you want to use. That is, if we did:
git switch main
we had all the files from H, but if we then decided to look at feature-1 instead and ran:
git switch feature-1
Git removed all the files from H and replaced them with the files from J, which is the commit to which the name feature-1 points.
There are a couple of important things to know about this remove-and-replace step:
First, Git only removes-and-replaces any files it has to. Git is already de-duplicating files, so it knows which files in
Hare the same inJ. For any file that's the same in both commits, it can skip the R(emove)-and-R(eplace) job. For files that are inHbut not inJ, it has to do the first R—the remove—without a replace, and for files that are inJbut notH, it has to just replace.Second, Git only does an R-and-R for the files it knows about. But what are those files? That's where the index comes in.
Because your working tree is a regular directory (or folder, if you prefer that term) with regular everyday files in it, you can create files that Git doesn't know about. These are your untracked files. That gives us the definition of an "untracked" file: an untracked file is one that is not in Git's index right now. This is extremely important, so let's repeat it.
An untracked file is a file that is not in Git's index right now
This is the key to making new commits, and also the key to .gitignore. Files that are in Git's index right now are tracked. Files that are not in Git's index right now are untracked. The "right now" part is important, because:
git switchandgit checkoutfill in the index; butgit addreads a working tree file and copies it into the index; andgit rmremoves a file from both the working tree and the index.
This gives you several ways to change what's in the index / staging-area. (There are more ways, such as git restore, but we'll just cover these three for now.) Using git rm --cached, you can remove a file from Git's index without removing it from the working tree, too, so it's easy to take a file from tracked to untracked with git rm --cached, or from untracked to tracked with git add.
Git builds new commits from whatever is in the index right now
When you run:
git commit
Git makes a snapshot of all the files that are in the index right then, as of the form they have in the index at that time. So if you:
git switch main
<modify one file - say, README.txt>
git add file
<modify the file again>
you currently have three versions of README.txt: there's one unchangeable one in the current commit, a second one in Git's index, and a third one in your working tree. If you run git commit, it's that second one—the one in Git's index—that goes in the new commit.
(Note that git commit -a is roughly equivalent to git add -u && git commit. That is, the -a option merely does an update-add of all the files that are already in Git's index. So truly-new files require a separate git add step.)
This is where .gitignore comes in
You can explicitly run:
git add some-file
or, if you like, you can run an en-masse "add everything here" with:
git add .
Both operations tell Git to add a file; the second one tells Git to add all the files from the current directory. But some files should not be put in new commits, and it would be painful to force you to git add individual files instead of letting you use git add . to just make Git figure things out.
Besides this, the git status command will run two diffs:
The first diff compares the
HEAD(current) commit to Git's index. For each file that is the same, Git says nothing at all. For each file that is different—including newly added or removed—Git tells you about it, sayingstaged for commit. That's because whatever is in the index will be in the next commit, and if it's different, that's interesting. If you have a big project, with thousands of files, you probably don't care thatdull/1throughdull/999are all unchanged; what you care about is thatimportant.codeis changed. Thisgit statusdiff will tell you that.The second diff compares the index to your working tree. For each file that is the same, Git says nothing. For files that are different, Git tells you about them, saying
not staged for commit. But new files—files that aren't in Git's index, but are in your working tree—are separated out. Git tells you about them not as "new" but rather asuntracked.
To prevent git status from being uselessly noisy about 10,000 untracked files that should be untracked, and to make git add . useful by not adding the 10,000 files, Git will read the poorly-named file .gitignore. These are the files that Git will (a) shut up about, and (b) not add even though you said git add ..
This has no effect on files that are already in Git's index. If the file is in Git's index, it is tracked and it will be in the next commit. Listing a file in .gitignore doesn't make it untracked and does not make Git ignore it: it just means that if it is untracked, Git won't complain about it and won't auto-add it.1
1In fact, if you explicitly try to add it with git add listed-ignored-file, Git will tell you that it's both currently untracked and listed in .gitignore, but—if you haven't disabled the hint—that you can override this with git add -f. Some people like to use this trick to ignore "everything" (with * in a .gitignore, for instance), and then force-add the few files that they don't want to ignore. I personally don't like to do this, but it does work. Just note that if you do use this trick, git rm --cached -r . && git add . will do bad things.
Diagnosing whether a file is "ignored"
Suppose you have some repository in which someone, at some point, said to ignore *.zorg files. Maybe that was the right thing to do at that time, even. But now you do need to commit some or all of the files in which you store your bad guys, so you don't want *.zorg ignored.
You run ls and you see:
jean-baptiste.emanuel.zorg
You run git status and it doesn't list jean-baptiste.emanuel.zorg.
Is the file unchanged, or is it changed-but-ignored, and not present in Git's index right now?
You can run:
git add jean-baptiste.emanuel.zorg
If it says nothing, the file was added; git status will now tell you whether it's changed. If it says that the file is explicitly ignored but you can use -f to override, you can git add -f jean-baptiste.emanuel.zorg to get it added.
您還可以運行:
git ls-files jean-baptiste.emanuel.zorg
如果這什么都沒說,則忽略該檔案。或者你可以運行:
git check-ignore jean-baptiste.emanuel.zorg
(也考慮添加-v)。如果這沒有說明,則不會忽略該檔案,可能是因為它已被強制添加。
uj5u.com熱心網友回復:
如果在 中添加正確的檔案路徑,.gitignore則使用時不會添加檔案git add .,鍵入時不會推送git push。
這么簡短的回答,不
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/405105.html
標籤:
