1.我是git的新手,想知道如果我修改过一个已经过去的文件(但现在再次修改)会发生什么,我想提交文件使用如下命令:
git commit -m "yada yada" ~/home/Dan/project/file_to_commit.py
这相当于做:
一个。git add ~/home/dan/project/file_to_commit.py
湾git commit -m "yada yada"
如果没有请解释。
2.如何在不执行git pull的情况下看到远程分支提交日志?(推送)?
由于
答案 0 :(得分:2)
这可能更好,因为两个单独的问题,第二个问题已经正确回答,但我会采取措施来回答这两个问题。不过,在我开始之前,我想说路径~/home/Dan/project/file_to_commit.py
非常可疑:它表明你的git目录是/.git
,这不是一个好主意。我将在下面假设.git
目录进一步缩小,您只需添加project/file
或file
(并且我会修剪问题中的路径。)
请注意,TL; DR版本的第一个答案是他们几乎相同,你只需知道某些边缘情况的差异。 (因此the existing answer from eleventhend对于大多数用途来说可能已经足够了。)
git commit path
...我已经修改了一个文件并且过去已经暂存(但现在再次修改),我想使用如下命令提交文件:
git commit -m "yada yada" file_to_commit.py
这相当于:
git add file_to_commit.py git commit -m "yada yada"
如果没有请解释。
不,它不是完全等同于。这有点棘手,如果我们定义一些术语并将一些东西固定下来,它将会有很大的帮助。
另外,你说"已经过去了(但现在再次修改)",这留下了一些含糊之处:你在这些操作之间做了git commit
吗?我将同时解答"是"和"不"案例通过描述完整的一般案例。
首先,我们需要定义git的索引或暂存区域(它甚至还有一些名称,例如 cache 如同git diff --cached
,但"索引"和"暂存区"是两个最常见的术语)。 Git有一个(一个,单个)标准索引 - 让我们称之为"""当我们想要引用另一个不同的索引时,我们将说明我们所指的另一个索引。当你运行大多数普通的git命令,包括git add
时,git会更新这个索引。 1
接下来,我们需要记录索引中 的内容。除了一些有趣但不相关的情况,比如合并,以及我故意遗漏的一件事,实质上,索引每个文件都有一个条目,将在 next 提交中。 2 也就是说,假设您已提交或检出某个分支,那么您的当前提交(现在位于工作树中)已有100个其中的文件。 (您的工作树可能还有其他未跟踪的和/或忽略的文件,只要它还包含这100个文件。)
git add
当您运行git add
时,git会将每个要添加到存储库中的文件的新副本存储到其中,并将其称为 blob对象。它会在将每个blob添加到存储库时计算每个blob的哈希值,然后将新哈希值放入索引中。
当你运行git commit
时 - 至少没有路径或-a
- git读取索引并使用它来形成新的提交。如果新提交与先前提交具有相同的树,则 3 git要求您添加--allow-empty
标志。 (这并不意味着索引为空,而是索引与您通过重新检出当前获得的索引相匹配因此,--allow-empty
可能是此标志的错误名称;它可能应该被称为--allow-same
或allow-unchanged
或其他一些。)
因此,如果您执行git add path
然后git commit -m message
,您将获得使用由git add
更新的索引的提交,该提交可能包含之前的其他更新git add
。但是,如果您执行以下操作,那么每个路径只有一个条目:
... hack on foo.py ...
$ git add foo.py
$ echo '# add a final comment' >> foo.py
$ git add foo.py
$ git commit -m 'update foo'
新提交中只有foo.py
的一次更新。
我在上面声明,git commit path
(和git commit -a
) 与<{1}}然后git add
完全相同。让我们来看看确切的差异。
当您将路径名称(或git commit
)提供给-a
时,git会使用新的,不同的临时索引。它首先复制一些东西 - 确切地说有点复杂 - 到临时索引,然后它添加要提交的每个文件,然后它从临时索引进行提交。提交完成后,git返回使用普通的普通索引,更新索引。也就是说,在将内容添加到临时索引并提交后,也会添加到常规索引中。
要了解这是如何运作的,我们需要一些例子。假设我们有两个文件,我们git commit
对其中一个文件进行了更改:
git add
此时,# assume file1 and file2 are in the HEAD commit
echo add stuff to file1 >> file1
git add file1
echo add stuff to file2 too >> file2
会告诉我们,我们对已提交的git status
进行了更改,并且更改为不的file1
上演了承诺。
如果我们运行file2
,我们将在新提交中获得两个更新。提交完成后,git add file2; git commit
将显示没有任何提交。但是,如果我们这样做:
git status
然后运行git commit -m message file2
,我们会看到git status
仍在上演并准备提交。我们刚刚提交的提交仅对file1
的更改。
这是因为file2
命令通过使用git commit file2
提交创建临时索引,添加HEAD
,进行提交,然后使用新的{{更新普通索引来启动1}}。最后一点很重要:如果git没有将更改复制回(常规)索引,那么索引仍然会有旧版本的file2
,并且下一次提交将取消我们刚刚提交的更改。
此复制步骤具有重要的副作用。假设我们对file2
进行了复杂的更改。例如,假设我们去修复一个bug,并且在整个过程中我们重构了一些函数。我们已经测试了该修复程序并且它可以正常运行,因此我们执行了file2
并且即将提交它:
foo.py
此时我们意识到我们不应该同时提交两个更改:我们应该首先提交重构的代码 ,然后然后提交错误修复。< SUP> 4
好吧,我们已经git add foo.py
编了重构的和修复的代码,所以它安全地隐藏在索引中,对吗? (不,错!危险Will Robinson!但是让我们继续,因为这是一个例子。)所以我们可以撤消修复部分,只留下重构,并先提交:
... hack on foo.py ...
... test, hack more, test, until fixed ...
git add foo.py
git commit -m 'refactor foo.py and then fix a bug'^C
完成提交后,我们可以提交暂存版本:
git add
唉,git现在告诉我们没有什么可以承诺的。精心上演的... edit foo.py to remove just the fix ...
git commit -m 'refactor code to prep for bug fix' foo.py
完全修复版本发生了什么?
答案是,git commit -m 'fix bug #12345' foo.py
消灭了它。 Git首先将仅重构foo.py
添加到临时索引并提交;但随后它将仅重构git commit foo.py
复制回常规索引,失去了我们精心上演的完整修复版本。我们可以重新创建它,也可以在存储库中钓鱼,以便悬空&#34;悬挂blob&#34;因为这个原因而被遗忘。
(这应该被认为是git中的一个错误,虽然它不清楚如何处理已暂存但未提交的版本。)
foo.py
和/或路径:foo.py
vs git commit -a
我需要在刚才引用自己。使用--only
或路径时,--include
首先复制某些内容 - 但实际上有点复杂。如果仔细查看the git commit
documentation,您会看到-a
或git commit
选项(以及相应的,但默认的-i
/ --include
选项)。这些控制了临时索引的内容。
使用-o
时,--only
会从当前索引创建临时索引。使用默认的--include
模式时,git commit
会从--only
提交中创建其临时索引。
(由于最后的复制步骤,看到两个命令实际上使用临时索引的唯一方法是在提交操作的中间查看索引。如果我们使用git commit
并在提交完成后进行检查,则常规索引将匹配新的HEAD
提交,就好像--include
正在添加到常规索引而不是临时索引。幸运的是,通过不提供HEAD
标志来查看常规索引&#34;非常容易,因此git commit
会激活编辑器。同时#&} 39;继续,在另一个窗口中运行-m
,或使用工作控制。这是一个例子:
git commit
这表明(常规)索引仍然按照我们的方式设置。一旦我们将消息写出并退出编辑器,提交过程将更新新git status
条目的常规索引,并且现在提交的# At this point I've modified both a.py and mxgroup.py
# but have not `git add`ed either one.
$ git add a.py
$ git status --short
M a.py
M mxgroup.py
# We see that a plain "git commit" would commit a.py,
# but not mxgroup.py.
$ git commit -i mxgroup.py
# now waiting in the editor
# Now, in another window:
$ git status -s
M a.py
M mxgroup.py
更改也在新mxgroup.py
中提交,因此a.py
将不显示任何文件。)
如何在不执行git pull的情况下看到远程分支提交日志?(推送)?
Git本身几乎完全在本地运营。您可以直接通过网络浏览器执行此操作,但只需首先运行HEAD
即可在本地执行此操作非常方便。
git status
命令实际上是为了方便起见。合并其他人的提交需要两个步骤:
这两个步骤由不同的git命令处理:git fetch
执行第1步,git pull
和git fetch
- 您必须选择其中一个 - 执行第2步中的任何一个版本想。
git merge
命令只执行步骤1,然后执行步骤2.它会选择git rebase
,除非您另有指示。由于历史原因,它有多种方法可以选择在步骤2中运行哪个操作。
我的建议是,作为git的新手,你完全避免使用git pull
。这有两个原因,今天只有一个是有效的(除非你已经坚持使用非常旧版本的git):
传统上,merge
有各种各样的错误,其中一些甚至可能会失去工作。 (据我所知,这些都是自git 2.0以来都已修复。)
虽然 方便,git pull
会模糊发生的事情并让您过早选择merge-vs-rebase。确实,rebase几乎总是正确答案,但git pull
默认为合并,这意味着新用户的默认设置是错误的。当然,还有那些&#34;掩盖了正在发生的事情&#34;问题。如果你知道fetch,然后将rebase作为单独的步骤,那么这个问题可能就不会出现了。
1 索引只是一个文件,您可以在git pull
中找到它。您可以通过在环境中设置git pull
来使git使用不同的索引,但这主要是供.git/index
等脚本使用。
2 我遗漏的案例是:
冲突合并,使用非零阶段编号,每条路径最多记录三个条目。一旦你解决了冲突和GIT_INDEX_FILE
结果,就会清除非零阶段,而是存储正常的阶段0结果,然后我们回到正常的,准备提交的情况下index intry。
删除当前提交中的文件(git stash
,有或没有git add
)。这会写一个特殊的stage-0条目,将文件标记为要省略,而不是简单地删除条目。
3 如果您正在提交合并,git允许树匹配任何或所有父项的树,因为合并提交需要记录多个父项。 &#34;空&#34;因此,test仅适用于非合并的单父提交。这在现代git中比在旧版本的git中记录得更好,但它仍然有错误的名称。
4 这与git本身无关。这里的想法是提交小的,可读的,可理解的,最重要的可测试的更改。任何时候你发现自己写了一个提交作为&#34;做A和B,并修复C,并添加D和E&#34;它表明你应该将每个东西分成一个提交 - 在这种情况下,大约5个单独的提交。
答案 1 :(得分:1)
实际上是等同的。当您使用git commit <filepath>
直接提交文件时,它会在提交之前暂存当前文件。您必须在提交文件之前第一次添加文件时暂存文件(告诉存储库开始跟踪文件),使用git add <file>
。
示例工作流程:
git add <file>
git commit -m "yada yada" <file>
git commit -m "blah blah" <file>
2
要查看远程git存储库的提交日志,首先在存储库中使用git fetch
,然后运行git log <path/branch>
以查看日志。
见这里:https://github.com/abhikp/git-test/wiki/View-the-commit-log-of-a-remote-branch