.gitignore 根本不忽略

.gitignore not ignoring at all

我创建了一个名为 Exploratory Data Analysis/Course Project 1/ 的目录,其中包含文件 household_power_consumption.txt。我试图将它推送到我的这个项目的 git 存储库并收到关于 household_power_consumption.txt 大小的警告,所以我添加了一个 .gitignore 文件,其中包含以下行:

Exploratory\ Data\ Analysis/Course\ Project\ 1/household_power_consumption.txt

我尝试遵循 posted here, here and here 的解决方案,但 none 这些对我有用。我总是收到同样的错误:

 git push origin master
Counting objects: 31, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (28/28), done.
Writing objects: 100% (31/31), 20.48 MiB | 221.00 KiB/s, done.
Total 31 (delta 6), reused 0 (delta 0)
remote: error: GH001: Large files detected.
remote: error: Trace: 491a8219bf1d3de4fd08a8e3ea253faa
remote: error: See http://git.io/iEPt8g for more information.
remote: error: File Exploratory Data Analysis/Course Project 1/household_power_consumption.txt is 126.80 MB; this exceeds GitHub's file size limit of 100.00 MB
To https://github.com/jd901215/DataScience_CourseraSpecialization.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://github.com/jd901215/DataScience_CourseraSpecialization.git'

这是我项目的本地目录树:

├── Exploratory Data Analysis
│   └── Course Project 1
│       └── household_power_consumption.txt
├── .git
│   ├── branches
│   ├── COMMIT_EDITMSG
│   ├── config
│   ├── description
│   ├── FETCH_HEAD
│   ├── HEAD
│   ├── hooks
│   │   ├── applypatch-msg.sample
│   │   ├── commit-msg.sample
│   │   ├── post-update.sample
│   │   ├── pre-applypatch.sample
│   │   ├── pre-commit.sample
│   │   ├── prepare-commit-msg.sample
│   │   ├── pre-push.sample
│   │   ├── pre-rebase.sample
│   │   └── update.sample
│   ├── index
│   ├── info
│   │   └── exclude
│   ├── logs
│   │   ├── HEAD
│   │   └── refs
│   │       ├── heads
│   │       │   └── master
│   │       └── remotes
│   │           └── origin
│   │               └── master
│   ├── objects
|   |   ├── (Bunch of SHA-1 checksums I guess )
│   │   ├── info
│   │   └── pack
│   ├── ORIG_HEAD
│   └── refs
│       ├── heads
│       │   └── master
│       ├── remotes
│       │   └── origin
│       │       └── master
│       └── tags
├── .gitignore
├── LICENSE
├── README.md
└── R programming 
    ├── README.md
    ├── Week 1 Programming assignment
    │   ├── complete7.R
    │   ├── complete.R
    │   ├── corr.R
    │   ├── pollutantmean.R
    │   ├── .RData
    │   ├── .Rhistory
    │   └── specdata
    ├── Week 2 Programming assignment
    │   ├── cachematrix.R
    │   └── README.md
    └── Week 4 Programming assignment
        ├── best.R
        ├── hospital-data.csv
        ├── Hospital_Revised_Flatfiles.pdf
        ├── outcome-of-care-measures.csv
        ├── .Rhistory
        └── rprog-doc-ProgAssignment3.pdf

抱歉这么久 post 但我正在尝试提供必要的信息。提前致谢

当我添加行时为我工作

Exploratory\ Data\ Analysis/Course\ Project\ 1/household_power_consumption.txt

到 .gitignore

我怀疑您因为之前的提交而无法推送。虽然您是在本地删除它,但我认为之前使用该文件创建了一个提交。 检查'git log',看看你在txt文件中检查的提交是否存在。

如果是,执行

git reset --soft HEAD^

删除该提交(如果它是最新的提交)。

重置提交后, 在 'git status' 中,如果您在以下位置看到文件:

    "Changes to be committed:" area, execute "git reset HEAD <file>".
    "Changes not staged for commit:" area, execute "git checkout -- <file>".

执行'git status'并检查文件是否在"Untracked files:"区域。

然后,将文件添加到.gitignore。会成功的。

首先,值得注意的是 .gitignore 条目起初并不代表人们通常认为的意思。我稍后会回到这个(很多)。

很明显1 这个输出行:

remote: error: Trace: 491a8219bf1d3de4fd08a8e3ea253faa

告诉您在您尝试推送的提交集中哪个提交包含过大的文件。

不过,要到达这里,您必须了解很多关于 git 的事情,而这些事情在各种文档中通常解释得很少。 (有关 good 的解释,请参阅 Git Book。)在这种特殊情况下,需要知道的一件事是 git push 调用了 "remote",另一台计算机上有自己单独的 git 存储库,然后你的 git 要求其他 git 接受你的任何新提交并将它们添加到它自己的存储库中。


在这种情况下,您和您的 git 调用遥控器 "origin",这是 "the place I cloned from originally" 的标准名称。

为了便于说明,以下是在分支 master:

上克隆只有三个提交的原点的简单情况。

their git: C1 <- C2 <- C3 <-- master

you: $ git clone <url>

your git: (uses Internet-phone to call their git) "Here's a URL, what do you have?"

their git: "I have master which points to commit C3"

your git: "OK, gimme, and oh, I see I also need C2 and C1"

their git: (gives your git a bundle of everything)

your git: "kthxbye!" (unpacks everything, creates new repo that's the same as what you got from their git, plus the remote-name "origin" and the url)

现在您已经有了克隆,您可以做一些工作并进行一些提交。我们称它们为 C4C5。这些 C<digit> 中的每一个都代表那些丑陋的 40 字符 SHA-1 中的一个,例如 491a8219bf1d3de4fd08a8e3ea253faa。每个提交 "points back" 在其父提交中,因此 C3 指向 C2C2 指向 C1。 (由于 C1 是第一个提交,它没有出站箭头:一个提交指向零个或多个父项,而初始提交是零个。)让我们绘制 C4C5现在:

C1 <- C2 <- C3 <- C4 <- C5   <-- master

请注意,分支标签 master 现在指向提交 C5,不再指向 C3

(您的 git 将创建一个额外的标签,origin/master,指向 C3。这就是您的 git 可以判断您是 "ahead 2" 提交。由于您的 git 并不总是在 Internet 上-phone 与他们的 git 保持同步,因此此信息可能会过时。但是我们将忽略它现在。)

最终,您决定:

$ git push origin master

这会告诉您的 git 重新连接到 Internet-phone 到他们的 git。现在的对话有点不一样了:

your git: "I have some stuff for you."

their git: "Hm, well, gimme the stuff and I'll see. I have master and it's commit C3."

your git: "OK, since you're on C3, here's my C4 and C5."

their git: (starts doing checking, in this case, running a "pre-receive hook")

"pre-receive hook" 是他们(无论他们是谁)编写的任意代码。它可以做任何他们想让它做的事,但在这种情况下,它显然(又是那个词:-))检查你移交的新提交。这两个提交中至少有一个在其关联的源代码树中显然有一个大文件。

这个任意代码 可以 只是说 "no",但它正在打印关于 为什么 它说 "no" 的细节.明智的做法是打印具有大文件的提交的标识,因为 提交 ID 是唯一的 ,即使在 Internet 上也是如此 - phone,所以你将拥有相同的ID 在您的存储库中,可以使用它来查看哪里出了问题。

在这个例子中,要么提交 C4 要么提交 C5。 (大文件可能在两次提交中;远程可能会在找到第一个找到的那个之后停止,而不是告诉你第二个。但无论如何它只告诉你一个提交。)

查看特定提交:

$ git log 491a8219bf1d3de4fd08a8e3ea253faa

或:

$ git show 491a8219bf1d3de4fd08a8e3ea253faa

其他可能有助于使其更易于查看的方法是使用:

$ git log --name-status

显示添加、删除或更改的文件(通过将每个提交与其父提交进行比较)。


现在,真正的问题是如何处理这个问题。在这种特殊情况下,使用交互式变基可能是最简单的,如 Rewriting History section of the Git Book 中所示。您需要在这里做的是用 "good" 提交替换原来的 "bad" 提交。

(Git 实际上从来没有 replace 提交,它只会添加 new 提交,但是一旦你有了新的,你和你的 git 可以假装旧的不存在。最终——默认情况下,在 30 天左右——旧的被遗忘的提交 "expire" 并将被删除,但它们'保留到那时。这种保留意味着您始终可以从交互式变基过程中犯的任何错误中恢复。)

为了说明起见,假设错误发生在提交 C4 中(如果它发生在 C5 中,则更容易修复,并且不需要整个交互变基的事情,尽管它仍然有效)。我们进一步要说——这似乎是合理的,因为你的 git push 失败了——你还没有将 C4C5 推到其他任何地方。 (如果你有,那么得到你当前 C4C5 承诺的人的生活会变得更加痛苦。)

你从运行宁git rebase -i开始。由于您在 master 上并且它的 "upstream" 分支(如 git 所称)是 origin/master,这意味着 "rebase master onto origin/master":即复制提交 C4C5origin/master 的顶端以创建新的、复制但略有更改的提交 C4'C5':

                 C4 <- C5  <-- [master, before rebase]
               /
C1 <- C2 <- C3             <-- origin/master
               \
                 C4' ...   <-- temporary rebase branch

当你的编辑器中出现 rebase 命令时,将提交 C4pick 行更改为 edit 行。写出指令并退出编辑器。 (您不需要为 C5 做任何事情,因为一旦变基完成,它将成为最尖端的提交。如果您需要更改它,您可以简单地 git commit --amend 它。)

交互式变基将挑选原始提交,但随后停止,此时提交 C4' 实际上与 C4 相同(除了某些时间戳和其他 author/committer元数据)。您现在可以 "amend" 提交。

由于提交添加了一个你不想要的文件,你需要先 git rm 它,也许 git rm --cached 将文件留在你的工作树中:

$ git rm --cached Exploratory\ Data\ Analysis/Course\ Project\ 1/household_power_consumption.txt

如果有必要或合适,您还可以将该路径添加到 .gitignore 文件,并且 git add 添加 .gitignore。这个文件只是给你带来一点方便,所以是否这样做取决于你。

现在您可以使用 git commit --amend 使修改后的提交 C4' 永久化,然后再继续变基:

$ git commit --amend --no-edit
[master d106870] blah blah ...
$ git rebase --continue

--no-edit 标志跳过在提交消息上打开编辑器。如果您也想对提交消息进行更改,请将其保留。)

continue 步骤简单地通过复制提交 C5 完成变基,将其添加到临时分支的顶端:

                 C4 <- C5  <-- [master, before rebase]
               /
C1 <- C2 <- C3             <-- origin/master
               \
                 C4' - C5' <-- temporary rebase branch

然后——像所有 rebase 一样——擦除标签 master 并将其粘贴到临时分支:

C1 <- C2 <- C3             <-- origin/master
               \
                 C4' - C5' <-- master

现在您有一组提交 添加大文件,您可以重新运行 git push origin master。你的 git 和他们的 git 将重新进行他们的对话,但这一次,你的 git 将移交提交 C4'C5',这省略了大文件。然后你的 git 会要求他们的 git 将 C5' 标记为分支 master,大概这次就可以了。


回到 .gitignore 文件:我有时认为这个文件命名有误,因为这些文件不是 git 忽略 的文件。特别是,如果文件已经被跟踪——在索引中——git 将不会忽略它。因此,如果您 git add 错误地编辑了一个文件,提交了该文件,然后将其放入 .gitignore,它仍处于较早的提交中。即使您从那时起 git rm-ed 也是如此。

.gitignore 中的条目做两件事,通常更重要的是 "keep git from griping about this file being untracked",因此更好的名称可能是 [=99= 而不是 .gitignore ], 或类似的东西。但是此文件中的条目 also 阻止 git add 将文件添加到索引中,如果它尚未 in 索引,所以它还需要名称 .git-dont-add-files 或类似的名称。因此,我们只使用 .gitignore 并且必须理解它并不真正意味着 "ignore"。)


1"Obvious" 意思是 "not obvious at all, except after you've written some pre-receive hooks."