无需添加即可提交,以及如何查看远程分支日志 [英] Commit without add and how to see remote branch log

查看:131
本文介绍了无需添加即可提交,以及如何查看远程分支日志的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

<1>我对git很陌生,想知道如果我有一个修改过的文件(现在已经被修改过),会发生什么情况,我想用命令提交文件例如:

git commit -myada yada〜/ home / Dan / project / file_to_commit.py



这相当于做了什么:

a。 git add〜/ home / dan / project / file_to_commit.py >
b。 git commit -myada yada



如果没有请解释。 p>

2.如何在不执行git pull的情况下看到远程分支提交日志(推送)?



谢谢

解决方案

这可能会更好,因为两个不同的问题,第二个问题已经被正确回答了,但我会采取刺回答两者。然而,在我开始之前,我想说的是〜/ home / Dan / project / file_to_commit.py 的路径非常可疑:它表明你的git目录是 / .git ,这不是一个好主意。我将在下面假设 .git 目录更进一步缩减,并且您只需添加 project / file file (我将修剪问题中的路径)。



请注意,TL ; DR版本的第一个答案是它们几乎相同,并且只需要知道一些边缘情况的差异。 (因此, eleventhend的现有答案对于大多数用途来说可能已经够用了。)



Q1:添加并提交vs git commit 路径




...我已经修改了一个文件,并且已经在过去进行过(但现在又修改了),并且我想使用如下命令来提交文件:

  git commit -myada yadafile_to_commit.py 

这相当于做了什么:

  git add file_to_commit.py 
git commit -m yada yada

如果不是请解释。


不,它不是完全相同的。这有点棘手,如果我们定义了一些术语并让一些东西固定下来,这将有很大的帮助。



另外,你说已经上演在过去(但现在又被修改了),这留下了一些含糊之处:你在这些操作之间做了一个 git commit 吗?我会通过描述完整的一般情况来解决是和否的情况。



索引


$ b $首先,我们需要定义git的索引临时区域(它甚至有更多的名称,例如 cache git diff --cached ,但是index和staging area是两个最常用的术语)。 Git有一个(单一的)标准索引,我们称之为the索引,当我们想引用另一个不同的索引时,我们将阐明我们指的是另一个索引。当你运行大多数正常的git命令时,包括 git add ,git会更新这个索引。 1



接下来,我们需要对索引中实际的内容做一些说明。除了一些有趣的但并不相关的情况,比如合并,还有一件事我会故意忽略,实际上,索引每个文件都有一个条目,它们将在 next 提交中。 2 也就是说,假设你已经提交了一个提交,或者签出了一个分支,以便你的工作树中现在的当前提交有100个文件。 (您的工作树可能还有其他未被跟踪和/或被忽略文件,只要它也有这100个文件。)



使用 git add



运行 git add ,git存储了每个被添加到版本库中的文件的新副本,它调用了 blob对象。它会为每个blob计算一个散列值,因为它会将其添加到存储库中,然后将新散列放入索引中。



当您运行 git提交 - 至少,没有任何路径或 -a -git读取索引并使用它来形成新的提交。如果新提交与前一个提交具有相同的树,则 3 git要求添加 - 允许为空标志。 (这并不意味着索引是,而是索引匹配通过重新签出当前提交获得的索引,因此 - 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



这个区别是什么?



我上面声称 path (和 git commit -a )与 git add 然后<$ c完全不同 $ c> git commit 。让我们看一下精确的区别。



当您将路径名称(或 -a )赋给 git commit ,git使用一个新的不同的临时索引。它首先将临时索引拷贝到临时索引中,然后它添加要提交的每个文件,然后从临时索引进行提交。提交完成后,git返回使用普通的普通索引,并且更新索引。也就是说,在之后将内容添加到临时索引并提交后,它 也会添加到常规索引。



为了看到这是如何工作的,我们需要一些例子。假设我们有两个文件,并且 git add 对其中一个文件进行了更改:

 #假设file1和file2在HEAD commit中
echo将东西添加到file1>> file1
git add file1
echo add stuff to file2 too>> file2

此时, git status 会告诉我们,我们已经对 file1 进行了更改,并将其更改为



如果我们运行 git add file2; git commit ,我们将在新的提交中获得两个更新。一旦提交完成, git status 将显示没有任何提交。但是,如果我们这样做:

  git commit -m消息文件2 

然后运行 git status ,我们会看到 file1 仍处于暂存状态并准备提交。我们刚刚提交的提交改变为 file2



这是因为 git commit file2 命令通过使用 HEAD 提交创建一个临时索引来启动,并添加 file2 ,进行提交,然后使用新的 file2 更新普通索引。最后一点很重要:如果git没有将变化复制回(常规)索引,那么索引仍然会有旧版本 file2 ,并且下一次提交会撤销我们刚才提交的更改。

这个复制步骤有一个重要的副作用。假设我们对 foo.py 进行了复杂的更改。例如,假设我们去修复一个bug,并且一路上我们重构了一些函数。我们已经测试了这个修补程序并且它可以正常工作,所以我们做了 git add foo.py 并准备提交它:

  ... hack on foo.py ... 
...测试,hack more,测试,直到修正...
git add foo。 py
git commit -m'重构foo.py然后修复错误'^ C

现在我们意识到我们不应该同时提交两个更改:我们应该首先提交重构代码然后然后提交错误修复。 4

那么,我们已经 git add - 重构的和固定的

代码,所以它安全地隐藏在索引中,对吧? ( No,WRONG!Danger Will Robinson!但让我们继续,因为这是一个例子。)所以我们可以撤销修复部分,只保留重构,然后首先提交:

  ...编辑foo.py删除修正... 
git commit -m'重构代码以预备bug修复'foo.py

完成该提交后,我们可以提交暂存版本:

  git commit -m'修正错误#12345'foo.py 

唉,git现在告诉我们没有什么可以提交的。 foo.py



仔细分类的完整版本发生了什么?答案是, git commit foo.py 将其擦除。 Git首先将仅限重构的 foo.py 添加到临时索引并提交;但它然后将仅重构的 foo.py 复制回常规索引,失去了我们仔细分阶段的完整版本。我们可以重新创建它,或者在存储库中查找因此而留下的悬空斑点。



(这应该被认为是在git中有bug,但是不清楚如何处理stage但未提交的版本。)


$ b

git commit -a 和/或路径: - 仅 vs - 包含



在这里,我需要引用自己刚才的话。当使用 -a 或路径时, git commit 首先复制一些东西 - 确切地说有点复杂。如果仔细观察 git commit 文档,你会发现 -i 或者 --include >选项(和相应的,但默认情况下, -o / - 仅选项)。这些控制进入临时索引的内容。



当使用 - include 时, git commit 从当前索引创建其临时索引。当使用默认 - 仅模式时, git commit 会从头部创建其临时索引提交。



(由于最后的回退步骤,只能看到 命令实际上是使用临时索引来查看提交操作中间的索引,如果我们使用 --include 并在提交完成后检查,常规index会匹配新的 HEAD 提交,就好像 git commit 被添加到常规索引而不是临时索引幸运的是,通过不提供 -m 标志来查看常规索引在中间非常容易,因此 git commit 会触发编辑器,在这种情况下,可以在另一个窗口中运行 git status ,或者使用作业控制,例如:

 #此时我已经修改了a.py和mxgroup.py 
#但没有`git add``两个。

$ git add a.py
$ git status --short
M a.py
M mxgroup.py

#我们看到一个普通的git commit会提交a.py,
#但不是mxgroup.py。

$ git commit -i mxgroup.py
#现在在编辑器中等待

#现在,在另一个窗口中:
$ git status -s
M a.py
M mxgroup.py

这表明(常规)指数仍然是我们建立的方式。一旦我们写出消息并退出编辑器,提交过程将更新新的 mxgroup.py 条目的常规索引,并且现在提交的 a.py change也在新的 HEAD 提交中,所以 git status 会)



Q2:查看日志




我怎么看远程分支提交日志?(推)没有做git拉?


Git本身几乎完全在本地运行。您可以直接在网页浏览器中执行此操作,但通过首先运行 git fetch 即可在本地执行,非常方便。



git pull 命令实际上意味着方便。合并其他人的提交需要两个步骤:


  1. 获取这些提交,以便在本地提供它们;和
  2. 使用这些提交进行合并或重新绑定。

这两个步骤由不同的git命令: git fetch 执行步骤1,并且 git merge git rebase - 你必须选择其中的一个 - 做任何你想要的第二步的版本。



git pull 命令只是执行第1步,然后执行第2步。除非另有指示,否则它会选择 merge 。由于历史原因,它有多种方式选择在第2步中运行哪个操作。



我的建议是作为git的新手,避免 git pull 完全。这有两个原因,其中只有一个是今天有效的(除非你被困在旧版本的git中):


  1. 传统上, git pull 存在各种错误,其中一些甚至会失去工作。 (据我所知,这些都是固定的,因为git 2.0。)

  2. 尽管 方便, git pull 会遮挡正在发生的事情,并使您选择merge-vs-rebase过早。确实,rebase几乎总是正确的答案,但是 git pull 默认为合并,这意味着它对新用户的默认值是错误的。此外,当然,还有模糊了正在发生的事情的问题。如果你知道获取,然后重新分配作为单独的步骤,这个问题可能甚至不会出现。







1 索引只是一个文件,你可以在 .git / index 中找到它。您可以通过在环境中设置 GIT_INDEX_FILE 来让git使用不同的索引,但这主要是为像 git stash $ b

2 我要离开的情况是:


  • 冲突合并,每个路径使用非零阶段号码记录最多三个条目。一旦你解决了冲突和 git add 结果,非零阶段被清除,正常的阶段0结果被存储,而我们又回到了正常的阶段,准备提交的索引intry实例。

  • 删除当前提交中的文件( git rm ,有或没有 - cached )。这写入了一个特殊的stage-0条目,标记文件将被省略,而不是简单地删除条目。




3 如果你正在提交合并,git允许树匹配任何或所有父母的树,因为合并提交需要记录多个父母。 空测试因此仅适用于非合并单亲提交。这在现代git中比在旧版本的git中记录得好得多,但它仍然有错误的名称

4 这与git本身无关。这里的想法是提供小的,可读的,可理解的,最重要的是可测试的改变。每当你发现自己写一个提交为做A和B,修正C,并添加D和E,这表明你应该把它分成一个提交 - 在这种情况下,大约需要5次独立的提交。

1.I'm new to git and would like to know what happen if I've a file which was modified and already staged in the past(but now modified again), and I want to commit the file using a command such as :
git commit -m "yada yada" ~/home/Dan/project/file_to_commit.py

Is this equivalent to doing:
a.git add ~/home/dan/project/file_to_commit.py
b.git commit -m "yada yada"

If not please explain.

2.How can I see the remotes branch commits logs?(pushes) without doing git pull?

Thanks

解决方案

This might be better as two separate questions, and the second question is already answered correctly, but I'll take a stab at answering both. Before I start, though, I want to say that the path ~/home/Dan/project/file_to_commit.py is pretty suspect: it suggests that your git directory is /.git, which is not a good idea. I'm going to assume, below, that the .git directory is much further down and you're just adding project/file or file (and I'll trim the paths in the question).

Note that the TL;DR version of the first answer is that they're almost the same, and you only need to know about the difference in some edge cases. (Hence the existing answer from eleventhend is probably good enough for most purposes.)

Q1: Add and commit vs git commit path

... I've a file which was modified and already staged in the past (but now modified again), and I want to commit the file using a command such as:

git commit -m "yada yada" file_to_commit.py

Is this equivalent to doing:

git add file_to_commit.py
git commit -m "yada yada"

If not please explain.

No, it's not exactly equivalent. This is a little bit tricky and it will help a lot if we define some terms and get a few things pinned down a bit more.

Also, you say "already staged in the past (but now modified again)", which leaves a bit of ambiguity: did you do a git commit in between these operations? I'll address both the "yes" and "no" cases by describing the full, general case.

The index

First, we need to define git's index or staging area (it has even a few more names, e.g., cache as in git diff --cached, but "index" and "staging area" are the two most common terms). Git has a (one, single) standard index—let's call this "the" index, and when we want to refer to another, different index, we'll spell out which other one we mean. When you run most normal git commands, including git add, git updates this index.1

Next, we need to take some notes on what's actually in the index. Aside from some interesting but not relevant here cases like merges, and one thing I'm leaving out on purpose, in essence, the index has one entry per file that will be in the next commit.2 That is, suppose you've made a commit, or checked out some branch, so that your current commit, which is now in your work tree, has 100 files in it. (Your work tree may have additional untracked and/or ignored files, as long as it also has those 100 files.)

Using git add

When you run git add, git stores a new copy of each of the files being added into the repository, which it calls blob objects. It calculates a hash value for each blob as it adds it to the repository, then puts the new hash into the index.

When you run git commit—at least, without either paths or -a—git reads the index and uses that to form the new commit. If the new commit would have the same tree as the previous commit,3 git requires that you add the --allow-empty flag. (This doesn't mean that the index is empty, but rather that the index matches the index you'd get by re-checking-out the current commit. So --allow-empty might be the wrong name for this flag; it maybe should have been called --allow-same or allow-unchanged or some such.)

Hence, if you do git add path and then git commit -m message, you'll get a commit that uses the index as updated by the git add, which may have additional updates from before that git add. Since there's just the one entry per path, though, if you do:

... hack on foo.py ...
$ git add foo.py
$ echo '# add a final comment' >> foo.py
$ git add foo.py
$ git commit -m 'update foo'

there will only be one update to foo.py in the new commit.

So what's the difference?

I claimed above that git commit path (and git commit -a) is not exactly the same as doing the git add and then git commit. Let's look at the precise difference.

When you give path names (or -a) to git commit, git uses a new, different, temporary index. It starts by copying something—exactly what gets a bit complicated—to the temporary index, then it adds each file that is to be committed, then it makes a commit from the temporary index. Once the commit is done, git goes back to using the normal, ordinary index, and it updates the index. That is, after adding stuff to the temporary index and committing, it also adds to the regular index.

To see how this really works we need some examples. Suppose we have two files and we git add a change to one of them:

# 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

At this point, git status will tell us that we have changes to file1 that are staged to be committed, and changes to file2 that are not staged to be committed.

If we run git add file2; git commit, we'll get both updates in the new commit. Once the commit is done, git status will show there is nothing to commit. But if, instead, we do:

git commit -m message file2

and then run git status, we'll see that file1 is still staged and ready to commit. The commit we just made has only the change to file2.

This is because the git commit file2 command started by making a temporary index using the HEAD commit, adding file2, making the commit, and then updating the normal index with the new file2. This last bit is important: if git didn't copy the change back into the (regular) index, the index would still have the old version of file2, and the next commit would undo the change we just committed.

This copy-back step has an important side effect. Suppose that we have a complicated change to foo.py. For instance, suppose we went to fix a bug, and along the way we refactored a few functions. We've tested the fix and it works, so we did git add foo.py and were about to commit it:

... 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

At this point we realized that we shouldn't commit both changes together: we should commit the refactored code first, and then commit the bug fix.4

Well, we've already git add-ed the refactored and fixed code, so it's safely stashed away in the index, right? (No, WRONG! Danger Will Robinson! But let's proceed, since this is an example.) So we can just undo the fix part, leaving only the refactoring, and commit that first:

... edit foo.py to remove just the fix ...
git commit -m 'refactor code to prep for bug fix' foo.py

Once that commit is done, we can commit the staged version:

git commit -m 'fix bug #12345' foo.py

Alas, git now tells us that there's nothing to commit. What happened to the carefully staged full-fix version of foo.py?

The answer is, git commit foo.py wiped it out. Git first added the refactor-only foo.py to a temporary index and committed that; but then it copied the refactor-only foo.py back to the regular index, losing our carefully staged full-fix version. We can either re-create it, or fish around in the repository for the "dangling blob" that is left behind because of this.

(This should probably be considered a bug in git, although it's not clear what to do with the staged but uncommitted version.)

git commit -a and/or paths: --only vs --include

Here I need to quote myself from just a moment ago. When using -a or paths, git commit starts by copying something—exactly what gets a bit complicated. If you look closely at the git commit documentation, you will find the -i or --include option (and a corresponding, but default, -o / --only option). These control what goes into the temporary index.

When using --include, git commit creates its temporary index from the current index. When using the default --only mode, git commit creates its temporary index from the HEAD commit.

(Because of the copy-back step at the end, the only way to see that both commands are in fact using a temporary index is to view the index in the middle of the commit operation. If we use --include and check after the commit is done, the regular index will match the new HEAD commit, as if git commit were adding to the regular index rather than to the temporary index. Fortunately it's very easy to view the regular index "in the middle", by not supplying the -m flag, so that git commit fires up the editor. While that's going on, run git status in another window, or using job control. Here's an example:

# 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

This shows that the (regular) index is still set up the way we had it. Once we write the message out and exit the editor, the commit process will update the regular index for the new mxgroup.py entry, and the now-committed a.py change is also in the new HEAD commit, so git status will show neither file.)

Q2: Viewing logs

How can I see the remotes branch commits logs?(pushes) without doing git pull?

Git itself operates almost entirely locally. You may be able to do this directly with web viewers, but it's pretty convenient to just do locally, by first running git fetch.

The git pull command is actually meant as a convenience. There are two steps needed to incorporate other people's commits:

  1. obtain those commits so that you have them locally; and
  2. merge or rebase using those commits.

These two steps are handled by different git commands: git fetch does step 1, and git merge and git rebase—you must pick one of the two—does whichever version of step 2 you want.

The git pull command simply does step 1, then does step 2. It chooses merge unless you instruct it otherwise. For historical reasons, it has multiple ways of choosing which operation to run in step 2.

My recommendation is that as a newbie to git, you avoid git pull entirely. There are two reasons for this, only one of which is valid today (unless you're stuck with very old versions of git):

  1. Traditionally, git pull has had various bugs, some of which can even lose work. (As far as I know these are all fixed since git 2.0.)

  2. While it is convenient, git pull obscures what's happening and makes you choose merge-vs-rebase too early. It is true that rebase is almost always the right answer, but git pull defaults to doing merge, which means that its default is wrong for new users. Plus, of course, there's that "obscures what's happening" issue. If you knew about fetch and then rebase as separate steps, this question probably would not even have come up.


1The index is just a file, and you can find it in .git/index. You can make git use a different index by setting GIT_INDEX_FILE in the environment, but this is mainly meant for use by scripts like git stash.

2The cases I'm leaving out are:

  • Conflicted merges, which record up to three entries per path, using non-zero stage numbers. Once your resolve the conflict and git add the result, the nonzero stages are cleaned out and the normal stage-0 result is stored instead, and we're back to the normal, ready-to-commit case for that index intry.

  • Removing a file that is in the current commit (git rm, with or without --cached). This writes a special stage-0 entry marking the file as to-be-omitted, rather than simply removing the entry.

3If you're committing a merge, git allows the tree to match those of any or all parents, since the merge commit needs to record the multiple parents. The "empty" test is thus applied only to non-merge, single-parent commits. This is documented much better in modern git than it was in old versions of git, but it still has the wrong name.

4This has nothing to do with git itself. The idea here is to commit small, readable, understandable, and most importantly testable changes. Any time you find yourself writing up a commit as "do A and B, and fix C, and add D and E" it's an indication that you should probably split this into one commit per thing—in this case, about 5 separate commits.

这篇关于无需添加即可提交,以及如何查看远程分支日志的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆