将工作文件添加到暂存后将对其进行修改。然后将文件提交到git,而不添加。该怎么办?
我注意到,在git中将一个修改过的文件添加到staging中,并且再次更改该文件,然后在没有添加的情况下进行提交之后,既没有错误也没有警告。提交工作文件中的最新更改。最初添加到登台的内容是否被丢弃将工作文件添加到暂存后将对其进行修改。然后将文件提交到git,而不添加。该怎么办?,git,staging,Git,Staging,我注意到,在git中将一个修改过的文件添加到staging中,并且再次更改该文件,然后在没有添加的情况下进行提交之后,既没有错误也没有警告。提交工作文件中的最新更改。最初添加到登台的内容是否被丢弃 $ git init Initialized empty Git repository in /tmp/test/.git/ /tmp/test (master) $ git config --global user.name "Your Name" /tmp/test (ma
$ git init
Initialized empty Git repository in /tmp/test/.git/
/tmp/test (master)
$ git config --global user.name "Your Name"
/tmp/test (master)
$ git config --global user.email "you@example.com"
/tmp/test (master)
$ echo A > my.txt
/tmp/test (master)
$ git add my.txt
/tmp/test (master)
$ git commit -m '1st' my.txt
[master (root-commit) c804a96] 1st
1 file changed, 1 insertion(+)
create mode 100644 my.txt
此时,my.txt被提交为“A”
/tmp/test (master)
$ echo B >> my.txt
/tmp/test (master)
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: my.txt
no changes added to commit (use "git add" and/or "git commit -a")
/tmp/test (master)
$ git diff
The file will have its original line endings in your working directory
diff --git a/my.txt b/my.txt
index f70f10e..35d242b 100644
--- a/my.txt
+++ b/my.txt
@@ -1 +1,2 @@
A
+B
/tmp/test (master)
$ git add my.txt
从以下文档:
通过将文件列为commit命令的参数,而不使用-interactive或-patch开关,在这种情况下,commit将忽略索引中进行的更改,而是记录所列文件的当前内容,这些内容必须是Git已知的;
强调我的观点——博士是正确的,但值得扩展
如果您注意到它随着时间的推移而发展,它应该包括-include和-only选项:
-包括
在提交到目前为止的暂存内容之前,还要暂存命令行上给定的路径的内容。这通常不是您想要的,除非您正在结束冲突合并
-o-only
通过获取命令行上指定路径的更新工作树内容来进行提交,而不考虑为其他路径暂存的任何内容。如果命令行上给出了任何路径,这是git commit的默认操作模式,在这种情况下,可以忽略此选项。[剪报]
正如最后引用的那句话所说,在向git commit命令添加路径名时,默认操作是作为git commit-only。这个特定的操作是以一种非常复杂的方式实现的,这可能会混淆一些预提交钩子
-include行为更容易描述,尽管这个简单/简单的描述有点缺陷,请参见下面的详细和正确的描述。使用git提交-包括:
$git add file1.txt
$git提交-包含file2.txt
例如,基本上等同于做:
$git add file1.txt
$git add file2.txt
$git提交
也就是说,-include只是为您运行git add,但如果提交失败,这些文件就会神奇地被取消添加,这一点很复杂
然而,唯一的选择要复杂得多。没有简单的方法来描述它,这也是完全正确的。为了正确地描述这两种情况,我们需要更详细地了解Git的索引
技术细节:索引
当Git进行新的提交时,它总是1从索引、暂存区域或缓存进行提交。这是同一件事的三个词。索引/暂存区/缓存是Git跟踪您希望提交的内容的方式。除了冲突合并的特殊情况外,2索引保存建议的下一次提交。当您第一次使用git签出或git切换到某个提交时,git将填充该提交的索引。因此,建议的下一次提交与当前提交匹配
您可能已经注意到,我有时会说索引,或Git的索引,好像只有一个索引,但我有时也会说一个索引,好像可以有多个索引。这里比较棘手的一点是两者都是正确的:有一个特定的可区分索引,即索引,但可以有多个
从技术上讲,可分辨索引是每个工作树的:如果使用git worktree add,那么不仅可以为特定的工作树添加另一个工作树,还可以添加另一个可分辨索引。您可以通过以下方式找到可分辨索引的文件名:
git rev-parse --git-path index
它通常打印.git/index,但在添加的工作树中,打印其他内容。如果在环境中设置了$GIT_INDEX_文件,它将打印此变量的值。这就是Git交换到某个备用索引文件的方式,或者更准确地说,这是一种外部可用的机制,您可以使用它将Git指向某个备用索引文件,例如,预提交钩子可以检测Git仅提交的调用
运行git add时,git会在索引中找到要git add的文件的现有条目:
如果没有现有条目如果这是一个新文件Git将文件复制到Git的索引中,现在有了一个现有条目:与当前提交相比,您建议的新提交有一个新添加的文件
否则,Git的索引中存在一些现有文件。Git将该文件从其索引中引导出来,并将该文件的工作树版本复制到其索引中。如果该文件的副本与当前提交中的副本不同,git状态现在将显示该文件已暂存以进行提交
因此,git add只需更新您建议的下一次提交,该提交在任何时候都会保存git将快照的每个文件的副本,但请参见脚注2。索引中的副本是git commit将使用的副本
现在我们知道了索引是如何工作的,Git可以使用我们可以创建的一些额外的临时索引文件,现在我们可以真正了解Git commit-include和Git commit是如何工作的
-只有工作
1这对于git提交是正确的,但如果使用git提交树,则可以绕过对索引的需要。必须向git提交树提供树的哈希ID。你从哪里弄到那棵树?如果使用git write tree,则使用索引。但是您可以从其他地方获得一棵树,例如,只使用一些现有的树,或者使用git mktree。但是,请注意,使用git mktree可以构建不正确的树;由此产生的提交将无法签出
2在发生冲突的合并过程中,Git会扩展索引。无法写出此扩展索引:git写入树发出抱怨并中止。使用git-add或git-rm,可以将扩展的索引项替换为普通项,或者完全删除某些项。一旦没有扩展的、非零的stage条目,冲突就会全部解决,因为git write tree现在可以写出索引:提交再次成为可能
技术细节:-仅包括和
为了实现git commit-include,git或多或少会这样做:
将索引复制到临时索引或索引;
在临时索引上运行git add,其中包含正在加载的文件;
尝试提交。
尝试的提交可以成功创建新的提交并更新当前分支名称,也可以失败。例如,如果git commit运行编辑器,然后您选择删除整个提交消息,则提交失败。也许你正在看一些东西,并且意识到你还不应该做出承诺,所以你就这么做了。或者,如果预提交挂钩确定此提交尚未就绪,则提交失败。注意,预提交钩子应该在这里查看临时索引!它不应该查看工作树中的文件。这不一定是提交中的内容。建议的下一次提交现在是临时索引中的内容
如果提交失败,Git只会删除临时索引。原始索引索引未被更改,因此现在所有内容都恢复原状。第2步中的git添加被神奇地撤消
如果提交成功,Git只需用临时索引替换索引。现在,索引和当前提交(我们刚刚进行了匹配)匹配,因此没有为提交准备任何内容。这就是我们喜欢的
仅实现git提交更加困难。仍然有两种情况:提交可能失败,或者提交可能成功。对于失败的情况,我们希望发生与git commit相同的事情-包括:索引,主要的区别之一,是不受干扰的,就好像我们甚至没有尝试运行git commit一样。但是,对于成功的案例来说,git-commit-only是一个棘手的问题,而且我认为文档有点不足
假设我们这样做:
$git checkout somebranch提取包含文件的提交
$echo new file>newfile.txt创建一个全新文件
$git add newfile.txt将全新文件副本转移到索引中
$echo mod 1>>file.txt在现有文件中追加一行
$git add file.txt将更新的文件副本转移到索引中
$echo mod 2>>file.txt在文件中附加*另一*行
$git commit-only file.txt-m test
如果成功,我们希望得到什么样的结果?我们告诉Git提交两行添加。该文件的工作树副本是两个添加行版本。在我们的测试提交之后,建议进行下一次提交的暂存文件是否应该只添加一行?还是应该同时添加两行
Git对这个问题的回答是,它应该同时添加两行。也就是说,如果git提交工作正常,git状态现在应该不说file.txt;应该只说newfile.txt是一个新文件。因此,此时,文件的两个添加行版本必须是建议的下一次提交中的版本。您可能同意Git,也可能不同意Git,但这正是Git作者选择的结果
这意味着我们在git提交时需要三个版本的索引-仅尝试进行提交:3
一个是原始索引中的新文件,另一个是添加的行。
一个是git commit用于进行新提交的索引中不会包含新文件,但会在file.txt中添加两行。
最后一个将包含新文件,并在其中添加了两行到file.txt。
这三者中的中间一个是git提交在尝试进行新提交时将使用的一个。这增加了两行,但没有新文件:这是git仅提交操作,正在执行
如果提交失败,git commit只会删除两个临时索引文件,使原始索引和索引不受干扰。我们现在在建议的下一次提交的file.txt版本中添加了一行,并且在建议的下一次提交中也添加了新添加的文件,就好像我们根本没有运行过git-commit-only file.txt一样
如果提交成功,gitcommit将生成最后一个同时具有这两个属性的索引
新添加的文件和file.txt的两行版本成为主/区分索引。用于执行提交的原始索引和临时索引都将被删除
这就是git提交的原因——只是这么复杂而已。假设您自己正在编写一个预提交钩子,在这个预提交钩子中,您计划做两件事:
使用一个linter来确保将要提交的任何代码中没有明显的bug,比如pylint、pep8、govet等等。。
使用格式化程序确保代码符合项目的标准black、go fmt等。。
在我看来,第二步是一个错误:不要这样做。但其他人喜欢这个想法
我们现在有三个案例:
您正在执行正常的git提交$未设置GIT_索引_文件。只有一个指标值得担心。您将文件从普通的、日常的、标准的索引中读取到一个临时目录中,并将它们挂在那里。如果linting失败,则停止并拒绝提交。如果linting成功,则格式化文件并将其添加回单个索引,然后让提交发生
这里仍然存在一个大问题,因为刚刚提交的文件是暂存的文件,而不是用户工作树中的文件。在git添加任何格式更新之前,您可能可以对照索引中预更新、尚未格式化的文件检查工作树文件。如果工作树文件与索引副本匹配,则在此处重新格式化工作树副本也可能是安全的
您正在执行git提交-包括。有两个索引文件需要担心,但出于linting的目的,您只需从Git现在用于此提交的索引文件中读取这些文件,它位于$Git_index_文件中,此时通常命名为.Git/index.lock。4
您可以像以前一样对待这一点,因为您所做的任何格式化都将进入建议的提交中,并且破坏用户的工作树文件与上次一样安全。您已经拒绝了提交,并且没有进行任何格式化,假设您要拒绝提交;如果提交成功,正如您所认为的那样,用户的包含文件也应该格式化。成功后,对临时索引所做的任何更新都将在实际索引中,因为临时索引将成为实际索引
您正在执行git提交操作。现在有三个索引文件需要担心。其中一个git提交将要使用的是$git_INDEX_文件。其中一个git commit计划用来替换主/可分辨索引的文件位于您不知道其名称的文件中。第三个是标准的主索引,Git将在失败时返回到该索引
您可以像往常一样进行检查:lint/vet$GIT_INDEX_文件中的文件。毕竟,这是用户打算做出的承诺
但现在,如果您格式化这些文件并将它们添加到$GIT_INDEX_文件中。。。嗯,格式化的文件就是要提交的文件。那很好。但是您还需要git将这些格式化文件添加到您不知道其名称的临时索引文件中!而且,在检查工作树文件与某些索引副本时,您可能应该使用不知道其名称的临时索引文件中的副本
如果您不更改任何文件,只需对所有文件进行lint/vet并检查所需的格式,这些问题就会消失。所以最好只是检查一下东西。如果用户希望根据项目规则格式化工作树文件,请为其提供工作树文件格式化程序。让他们运行它,然后让他们在更新的文件上运行git add,或者,如果您真的必须,提供在格式化脚本中添加回格式化文件
我曾经参与过一个项目,在这个项目中,pre-commit钩子进行了检查,然后,如果格式错误,检查$GIT_INDEX_文件,在遇到困难的情况时会停止并不做任何事情,或者提供给GIT添加重新格式化的文件。这也是一种选择,但有点冒险,因为Git可能会改变某些行为,导致$Git_INDEX_文件测试以某种方式失败
3毫无疑问,还有其他方法可以达到预期的效果,但考虑到索引文件实际上至少在最初是一个文件,再加上一堆现有的Git代码,这三个索引文件的技巧就是要使用的
4上次我测试这一切时就是这样,但那是在git worktree add出现之前的一段时间,它显然会影响这一点,至少对于添加的工作树来说是如此。感谢torek提供了足够的上下文来消除混淆。这本书还有更多内容 这个故事的寓意是- 提交时不要指定文件,除非您知道自己在做什么 典型动作:
git commit -m "commit everything that is currently staged"
git commit -m "commit only my.txt working file, ignore what is staged" my.txt
非典型行动:
git commit -m "commit everything that is currently staged"
git commit -m "commit only my.txt working file, ignore what is staged" my.txt
在上述提交中指定文件意味着一个-only选项
这个-only选项表示只提交spe文件
在commit命令中指定,并忽略当前正在暂存的内容。提交后,阶段文件将保持原样,等待提交。我想这种“插队”行为是有用例的。但允许隐式使用纯选项是鲁莽的。这是一场等待发生的事故
这里有一个类比可以帮助你记住这一点。
你和你的朋友来到一家餐馆,等着一起坐在一张大桌子旁。领班d意识到你的12人小组中的2人实际上不是你小组的一部分,并对他们进行了特别的优先排序——只是先坐在桌旁2人。领班没有说“下一个入座的人跟我来”,而是说“你们两个跟我来”
正如已经指出的那样,-include commit选项始终是显式的,表示还要将命令中指定的工作文件添加到当前已暂存的任何其他文件中
git commit -m "add almostforgot.txt to what is staged " --include almostforgot.txt
相当于:
git add almostforgot.txt
git commit -m "now have everything"
git commit -m "add almostforgot.txt to what is staged " --include almostforgot.txt
git add almostforgot.txt
git commit -m "now have everything"