Git每次推送都会提交 [英] Git commits for each push

查看:92
本文介绍了Git每次推送都会提交的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有一种方法可以检索最新推送的提交列表?例如,假设我正在执行10次本地提交但仅执行一次推送,是否有git命令仅显示这10次提交?

Is there a way to retrieve a list of commits for the latest push? For example let's assume i'm doing 10 local commits but a single push, is there a git command showing just these 10 commits?

推荐答案

简而言之,就是您不能可靠地做自己想做的事情:Git本身不记录git push动作.但是您可以做一些事情.具体来说,在Git 执行 git push或Git 接收 git push时,在推送本身时,您可以获取此信息.如何保存,处理和以后使用取决于您自己.

The short answer is that you can't do what you want reliably: Git itself does not record git push actions. But there are some things you can do. Specifically, in the Git doing the git push or in the Git receiving the git push, at the time of the push itself, you can get this information. How to save it, deal with it, and use it later is up to you.

(我也认为这不是一个好主意:不要尝试按 push 对事物进行分组,以其他方式对其进行分组.例如,在CI系统中,对它们进行分组如果构建请求#30将A,B和C提交为自创建请求以来的新内容",则由于先前的推送,提交请求的时间为5秒,但现在有了A ,B和D,而是对ABD而不是ABC进行CI检验,然后对remove-C-add-D进行CI检验.请仔细阅读本答案的其余部分,以了解此处的情况.

(I'd also argue that this is not a good idea: don't try to group things by push, group them some other way. For instance, in a CI system, group them by request, with requests being updated dynamically. If build request #30 had commits A, B, and C as "new since request was created" five seconds go due to a previous push, but now has A, B, and D instead, do a CI check of A-B-D, not one of A-B-C, then one of remove-C-add-D. Read through the rest of this answer to understand what's going on here.)

正在发送提交的Git将运行一个预推钩子(如果存在).发送git上的pre-push挂钩每个会得到四个信息项,暂时,我们称其为每件事情":

The Git that is sending commits will run a pre-push hook, if it's present. The pre-push hook on the sending Git gets four informational items per, um, let's call it "per thingy" for the moment:

  • 本地参考
  • 本地OID/SHA-1/哈希
  • 远程引用
  • 远程OID/SHA-1/哈希

假设您做到了:

git push origin refs/heads/master:refs/tags/v1.1

因此,本地引用为refs/heads/master.哈希ID(今天是SHA-1哈希),但是当Git切换到SHA-256时,Git内部现在将其称为"OID"(意为对象ID)以用于将来的验证,但是您可以将其称为哈希"以避免TLA综合症 1 -是您的refs/heads/master标识的提交哈希ID.远程引用将为refs/tags/v1.1,远程哈希可能为全零,因为这大概是您要创建的新的轻量级标记.

Here the local ref is thus refs/heads/master. The hash ID—which is a SHA-1 hash today, but internals of Git now call "OID" (meaning object ID) for future-proofing when Git switches to SHA-256, but you can just call it "hash" to avoid TLA syndrome1—is whatever commit hash ID your refs/heads/master identifies. The remote ref will be refs/tags/v1.1, and the remote hash will probably be all-zeros, since this is presumably a new lightweight tag you'd like to create.

如果您改为跑步:

git push origin master develop

您的钩子将得到两个东西.一个会两次提到refs/heads/master,另一个会两次提及refs/heads/develop:本地和远程master分支,以及本地和远程develop分支,这是您要进行的大git push操作.哈希ID将是您的本地master及其master,本地develop及其develop的哈希ID.

your hook would get two thingies. One would mention refs/heads/master twice and the other would mention refs/heads/develop twice: the local and remote master branch, and the local and remote develop branch, that you're pushing in one big git push operation. The hash IDs would be those for your local master and for their master, and for your local develop and for their develop.

使用这些哈希ID,您可以查看对它们来说是新的提交.如果它们的哈希ID在您的Git存储库中,您还可以查看是否要求他们删除任何提交,或更准确地说,是使它们 unreachable .有关可达性的更多信息,请参见像(a)Git一样.

Using these hash IDs, you can see which commit(s) are new to them. If their hash ID is in your Git repository, you can also see whether you're asking them to remove any commits—or more precisely, make them unreachable. For much more about reachability, see Think Like (a) Git.

其中一些哈希ID可能为全零.这样的哈希ID表示没有这样的名称".对于git push,如果您要让他们的Git 删除引用,则 remote 哈希将为全零.如果没有引用, local 哈希将为全零(仅当您也要求删除它们时才有意义).

Some of these hash IDs may be all-zeros. Such a hash ID means "there is no such name". For git push, the remote hash will be all-zeros if you're asking their Git to delete the reference. The local hash will be all-zeros if you don't have the reference (which is meaningful only if you're asking them to delete too).

1 TLA表示三字母缩写.与ETLA相比,ETLA是具有三个以上字母的扩展TLA.

1TLA stands for Three Letter Acronym. Compare with ETLA, which is an Extended TLA with more than three letters.

正在接收提交的Git,并被要求更新其引用,它将运行pre-receive钩子和post-receive钩子(如果存在).这些将得到与更新请求一样多的事物".如果有的话,它还会运行一次更新挂钩(如果存在).

The Git that is receiving commits, and being asked to update its references, will run the pre-receive hook and post-receive hooks if they exist. These will get as many "thingies" as there are update requests. It will also run the update hook, if it exists, once per thingy.

预接收挂钩每个东西都会得到三个信息项:

The pre-receive hook gets three informational items per thingy:

  • 当前(旧的)OID/哈希
  • 建议的新OID/哈希
  • 参考

current 哈希告诉您该名称当前代表的含义.例如,在我们的标签创建示例中,当前哈希为全零.建议的新哈希是推送Git要求您(接收Git)用作更新的引用的新哈希ID的对象ID.该参考当然是要更新的参考.

The current hash tells you what the name currently represents. For instance, with our tag-creation example, the current hash would be all-zeros. The proposed new hash is the object ID that the pushing Git is asking you, the receiving Git, to use as the new hash ID for the updated reference. The reference is of course the reference to be updated.

在我们的两个分支要更新的示例中,refs/heads/master的两个哈希是 current master提交和建议的新master提交.这些都可能是有效的散列,而不是全零,但是最多 可以是全零.如果接收方Git还没有引用,则旧哈希为全零(即分支master对您来说都是新的);如果要求您(接收方Git)删除引用,则new-hash为全零.

With our two-branches-to-update example, the two hashes for refs/heads/master would be the current master commit and the proposed new master commit. These are both likely to be valid hashes, rather than all-zeros, but at most one can be all-zeros. The old-hash is all-zero if you, the receiving Git, don't have the reference yet (i.e., the branch master is all new to you); the new-hash is all-zero if you, the receiving Git, are being asked to delete the reference.

一个预推钩子的工作是通读 all 提议的更新,并验证这是否可以.如果是这样,则预推挂钩应退出0(shell-exit-status-speak中为"true").如果不是,则预推钩子可以打印输出,以通知运行git push 为什么的用户被拒绝推入操作-用户将看到此输出,并且在remote:前面插入单词remote:它-然后退出非零值,以拒绝整个推送.

A pre-push hook's job is to read through all the proposed updates and verify whether this is OK. If so, the pre-push hook should exit 0 ("true" in shell-exit-status-speak). If not, the pre-push hook can print output intended to inform the user running git push why the push is being rejected—that user will see this output with the word remote: stuck in front of it—and then exit nonzero, to reject the entire push.

在预接收钩子运行时,接收Git可以访问 all 个提议的对象.也就是说,如果执行推送的人运行了git push origin master develop,这意味着发送了三个新的master提交和一个新的develop提交,则服务器上的pre-receive钩子将在之后运行已经收集了所有四个新提交以及这些提交所需的任何其他对象.新的对象在隔离区中的某个地方隔离".如果拒绝推送,则隔离区域将被丢弃,而不会将提交合并到主存储库中. 2 整个推送在此阶段中止.

At the time the pre-receive hook runs, the receiving Git has access to all the objects proposed. That is, if the guy doing the push ran git push origin master develop and this meant sending three new master commits and one new develop commit, the pre-receive hook on the server runs after the server has collected all four new commits, and any other objects required by those commits. The new objects are "in quarantine", in a holding area somewhere. If the push is rejected, the quarantine area is thrown away without incorporating the commits into the main repository.2 The entire push is aborted at this stage.

如果接收前钩子允许推送(或不存在),则推送继续进行到下一个阶段,在该阶段接收Git实际上确实一次更新每个引用.这时,接收方Git为每个引用运行 update 钩子,为它(作为参数而不是stdin)提供引用,旧哈希和新哈希(请注意不同的顺序).更新挂钩可以像以前一样检查项目,然后接受或拒绝此特定更新.无论更新是否被拒绝,接收都会继续进行下一个引用.因此,更新钩子只有一个局部视图(一次只能引用一个),但是具有更细粒度的接受/拒绝控件.

If the pre-receive hook allows the push—or does not exist—the push goes on to its next stage, where the receiving Git actually does update each reference, one at a time. At this time the receiving Git runs the update hook for each reference, giving it (as arguments, rather than as stdin) the reference, the old hash, and the new hash (note the different order). The update hook can inspect items as before, and then either accept or reject this particular update. Whether or not the update is rejected, the receiving continues with the next reference. So the update hook has only a local view—one reference at a time—but finer-grained accept/reject control.

最后,在所有更新完成或被拒绝之后,如果任何引用已更新,则接收Git运行后接收钩子(如果存在).这将获得与预接收钩相同的stdin行.挂钩应该退出零,因为推送已经完成.各种参考更新的锁定已被释放,因此该钩子不应在Git存储库中查找参考名称-由于另一次推送,它们可能已更改!

Finally, after all the updates have been done or rejected, if any references were updated, the receiving Git runs the post-receive hook, if it exists. This gets the same kind of stdin lines as the pre-receive hook. The hook should exit zero, because the push is already done. The locks on the various reference updates have been released so the hook should not look up the reference names in the Git repository—they might have changed already due to another push!

2 此隔离区"是Git 2.13中的新增功能;在此之前,即使新对象最终没有被使用,它们仍会进入,只是以后需要扔掉.在真正的大型服务器(例如GitHub)上,这会造成很多麻烦.

2This "quarantine area" was new in Git 2.13; before that, the new objects went in even if they ended up being unused, only to have to be thrown out later. On really big servers (e.g., GitHub) this caused a lot of pain.

给出一个旧的哈希ID和一个新的哈希ID,该命令:

Given an old hash ID and a new hash ID, the command:

git rev-list $old..$new

枚举从$new可访问的所有提交,但不能从$old进行访问.例如,对于git push,这些是刚刚添加的新提交.

enumerates all the commits that are reachable from $new but not from $old. For a git push, these are the new commits just added, for instance.

它的对应物:

git rev-list $new..$old

枚举从$old可以到达的提交,而从$new不再可以到达的提交.例如,这些是通过推送删除的提交.

enumerates the commits reachable from $old that are no longer reachable from $new. These are the commits removed by a push, for instance.

请注意,可以同时执行两个操作!更新可能会删除一个提交,并用新的和改进的变体替换它.

Note that it's possible to do both at the same time! An update might remove one commit and replace it with a new-and-improved variant.

您可以使用以下方法一次完成两组提交:

You can get both sets of commits in one shot using:

git rev-list $old...$new

要使此输出有用,必须添加--left-right插入 markers ,其中仅可从$old访问的提交,以及仅可从$new访问的提交.

To make this output useful, you must add --left-right to insert markers about which commits are reachable only from $old and which ones are reachable only from $new.

您可以使用git rev-list --count获得计数可达的提交.在三点变量中添加--left-right可以得到两个计数:例如,这就是git status如何计算前后计数. (好吧,git status已编译了代码,因此比在脚本中要容易得多,但这可以让您在脚本中执行git status的操作.)

You can get counts of reachable commits using git rev-list --count. Adding --left-right to the three-dot variant gives you two counts: this is how git status computes the ahead-and-behind counts, for instance. (Well, git status has the code compiled in, so it's easier than it would be in a script—but this lets you do what git status does, in a script.)

可以进行推送枚举,但是仅通过使用信息,Git仅在推送事件期间保持 .一旦完成推送或拒绝推送,您将只有结果图.除了记录有关推送本身的信息外(例如,发送邮件通知某人推送事件添加了3个提交并删除了1个),这通常不是很有用,这就是Git不保留此信息的原因本身.

A push enumeration is possible, but only by using information Git keeps only during the push event. Once the push is done, or rejected, you have only the resulting graph. Other than recording something about the push itself—e.g., sending mail informing someone that a push event added 3 commits and removed 1—this isn't generally very useful, which is why Git doesn't keep this itself.

如果某些特定的提交分组有重要意义,则可以在图形本身中记录该 .例如,假设您具有一项功能,需要完成以下三个步骤:

If there's something important about some particular commit grouping, you can record this in the graph itself. For instance, suppose you have a feature that requires three steps to achieve:

  • 升级无法使用的现有例程,以使其更有能力
  • 添加新例程来做新事情
  • 添加以新方式使用新旧例程的顶级集成

在这种情况下,而不是从:

In this case, instead of going from:

...--o--*   <-- master

收件人:

...--o--*--A--B--C   <-- master

其中AC是执行这三个步骤的新提交,请考虑将新图形推送为:

where A through C are the new commits that do these three steps, consider pushing the new graph as:

...--o--*---------M   <-- master
         \       /
          A--B--C

此处M是新的合并提交.将其合并消息设置为集成新功能(的一种更好的变体).将A,B和C的提交消息设置为增强现有例程添加新例程,并集成新旧例程以支持新功能.该合并气泡-A-B-C链-隔离了功能,因此,如果确实很糟糕,则可以通过还原M来还原整个合并,并且如果某些内容有些破损,则可以测试AA的提交. c39>单独弄清楚是什么.您可以执行上述任一操作或全部执行-还原整个合并,或不还原整个合并;测试是否单独提交,因为所有信息都被永久保存在图中.

Here M is a new merge commit. Set its merge message to (a better variant of) integrate new feature. Set the commit messages for A, B, and C to augment existing routines, add new routines, and integrate old and new routines to support new feature. This merge bubble—the A-B-C chain—isolates the feature, so that if something is really terrible, you can revert the entire merge by reverting M, and if something is slightly broken, you can test commits A through C individually to figure out what. You can do either or both of these—revert entire merge, or not; test commits individually, or not—because all the information is saved forever, in the graph.

这篇关于Git每次推送都会提交的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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