是否可以检索最新推送的提交列表?例如,假设我正在执行10次本地提交但仅执行一次推送,是否有git命令仅显示这10次提交?
答案 0 :(得分:1)
你说
我正在执行10次本地提交
所以假设您做过其中之一
git clone whatever
git pull
在您这样做之前立即
# edit stuff
git commit -a
# repeat 9 more times
然后
git push
现在您可以使用命令查看这10次提交
git log origin/master@{1}..origin/master
但如果您这样做
git fetch
在两次提交之间的任何时间,您对origin/master
在您开始本地工作时的位置的惯用语都被宠坏了。您将必须记住origin/master
被git fetch
更改的频率,并将{1}
调整为{2}
(它要计算要更新的数量-而非修订版本)回去)。
答案 1 :(得分:1)
简而言之,就是您不能可靠地做自己想做的事情:Git本身不记录git push
的动作。但是您可以做一些事情。具体来说,在git push
的Git做( )或在git push
的Git接受 中,在推动自身时 strong>,您可以获取此信息。如何保存,处理和以后使用取决于您自己。
(我也认为这不是一个好主意:不要尝试按 push 对事物进行分组,以其他方式对其进行分组。例如,在CI系统中,对它们进行分组如果请求#30将提交A,B和C提交为“自创建请求以来是新的”,则由于先前的推送,提交请求的时间为5秒,但是现在有A ,B和D,而是对ABD而不是ABC之一进行CI检查,然后对remove-C-add-D进行一次CI检查。请仔细阅读本答案的其余部分以了解此处的情况。
正在发送提交的Git将运行一个预推钩子(如果存在)。发送git上的pre-push钩子每个会得到四个信息项,暂时,我们称其为“每件事情”:
假设您做了:
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
,远程哈希可能为全零,因为这大概是您要创建的新的轻量级标记。
如果您改为跑步:
git push origin master develop
您的钩子将得到两个东西。一个会两次提及refs/heads/master
,另一个会两次提及refs/heads/develop
:您要推送的本地和远程master
分支,以及本地和远程develop
分支一个大的git push
操作。哈希ID将是您的本地master
及其master
,本地develop
及其develop
的哈希ID。
使用这些哈希ID,您可以查看对它们而言是新的提交。如果它们的哈希ID在您的Git存储库中,您还可以查看是否要求他们删除任何提交,或更准确地说,是使它们 unreachable 。有关可达性的更多信息,请参见Think Like (a) Git。
其中一些哈希ID可能全为零。这样的哈希ID表示“没有这样的名称”。对于git push
,如果您要让他们的Git 删除引用,则 remote 哈希将为全零。如果没有引用, local 哈希将为全零(仅当您也要求删除它们时才有意义)。
1 TLA表示三字母缩写。与ETLA相比,后者是具有三个以上字母的扩展TLA。
正在接收提交并被要求更新其引用的Git将运行pre-receive钩和post-receive钩(如果存在)。这些将得到与更新请求一样多的“事物”。如果有的话,它还会运行一次更新挂钩(如果存在)。
预接收挂钩每个东西都会得到三个信息项:
current 哈希告诉您该名称当前代表的含义。例如,在我们的标签创建示例中,当前哈希为全零。提议的新哈希是推送Git要求您(接收Git)用作更新的引用的新哈希ID的对象ID。该参考当然是要更新的参考。
在我们的两个分支要更新的示例中,refs/heads/master
的两个哈希将是 current master
提交和提议的新master
提交。这些都可能是有效的散列,而不是全零,但是最多 可以是全零。如果您(接收方Git)还没有引用,则旧哈希为全零(即分支master
对您来说都是新的);如果要求您(接收方Git)删除引用,则新哈希为全零。
一个预推钩子的工作是通读 all 提议的更新,并验证这是否可以。如果是这样,则预推钩子应退出0(shell-exit-status-speak中为“ true”)。如果不是,则预推钩子可以打印输出,以通知运行git push
的用户为什么被拒绝推入操作-用户将看到带有单词remote:
的输出停留在它前面,然后退出非零值以拒绝整个推送。
在预接收钩子运行时,接收Git可以访问 all 个建议的对象。也就是说,如果执行推送的人运行了git push origin master develop
,并且这意味着发送了三个新的master
提交和一个新的develop
提交,则服务器上的pre-receive钩子将在之后运行服务器已经收集了所有四个新提交以及这些提交所需的任何其他对象。新的对象在隔离区的某个地方“隔离”。如果拒绝推送,则隔离区域将被丢弃,而不会将提交合并到主存储库中。 2 整个推送在此阶段被中止。
如果接收前钩子允许推送(或不存在),则推送继续进行到下一阶段,在该阶段接收Git实际上确实一次更新每个引用。此时,接收方Git为每个引用运行 update 钩子,为它(作为参数而不是stdin)提供引用,旧哈希和新哈希(请注意不同的顺序)。更新挂钩可以像以前一样检查项目,然后接受或拒绝此特定更新。无论更新是否被拒绝,接收都会继续进行下一个引用。因此,更新钩子只有一个局部视图(一次只能引用一个),但是具有更细粒度的接受/拒绝控件。
最后,在所有更新完成或被拒绝之后,如果任何引用已更新,则接收Git运行后接收钩子(如果存在)。这将获得与预接收钩相同的stdin行。挂钩应该退出零,因为推送已经完成。各种参考更新的锁定已被释放,因此该钩子不应在Git存储库中查找参考名称-由于另一次推送,它们可能已更改!
2 此“隔离区”是Git 2.13中的新增功能;在此之前,即使新对象最终没有被使用,它们仍会进入,只是后来需要丢弃。在真正的大型服务器(例如GitHub)上,这会造成很多痛苦。
给出一个旧的哈希ID和一个新的哈希ID,该命令:
git rev-list $old..$new
枚举$new
而非$old
可以到达的所有提交。例如,对于git push
,这些是刚刚添加的新提交。
它的对应物:
git rev-list $new..$old
枚举$old
可以到达的提交,而$new
不再可以到达的提交。例如,这些是通过推送删除的提交。
请注意,可以同时执行两个操作!更新可能会删除一次提交,并用新的和改进的变体替换它。
您可以使用以下方法一次完成两组提交:
git rev-list $old...$new
要使此输出有用,必须添加--left-right
来插入 markers ,关于哪些标记只能从$old
访问,哪些标记只能从{{1}访问}。
您可以使用$new
获得计数可达的提交。将git rev-list --count
添加到三点变量中可以得到两个计数:例如,--left-right
就是这样计算前后计数的。 (好吧,git status
已经编译了代码,因此比在脚本中更容易-但这使您可以在脚本中完成git status
的工作。)
可以进行推送枚举,但是只能使用信息,Git仅在推送事件期间保持 。一旦完成推送或拒绝推送,您将只有结果图。除了记录有关推送本身的消息外(例如,发送邮件通知某人推送事件添加了3个提交并删除了1个),这通常不是很有用,这就是Git不保留此消息的原因本身。
如果某些特定的提交分组有重要意义,则可以将此记录在图形本身中。例如,假设您具有一项功能,需要完成以下三个步骤:
在这种情况下,而不是从:
git status
收件人:
...--o--* <-- master
其中...--o--*--A--B--C <-- master
至A
是执行这三个步骤的新提交,请考虑将新图形推送为:
C
这里...--o--*---------M <-- master
\ /
A--B--C
是新的合并提交。将其合并消息设置为集成新功能(的一种更好的变体)。将A,B和C的提交消息设置为增强现有例程,添加新例程,并集成新旧例程以支持新功能。此合并气泡(M
链)隔离了功能,因此,如果确实很糟糕,则可以通过还原A-B-C
来还原整个合并,并且如果有轻微损坏,可以测试提交{分别从{1}}到M
找出原因。您可以执行上述任一操作或全部执行-是否还原整个合并;测试是否单独提交,因为所有信息都被永久保存在图中。
答案 2 :(得分:0)
感谢大家的支持,尤其是@torek的聪明有趣的回答,这就是我使用gitlab API和python做到的事情:
import json
import requests
def checkAsset(obj):
status=0
#status=0 modified, status=1 new file, status=2 deleted
if (obj['new_path']==obj['old_path'] and obj['new_file']==False):
status=0
elif (obj['new_path']==obj['old_path'] and obj['new_file']==True):
status=1
elif (obj['new_path']==obj['old_path'] and obj['deleted_file']==True):
status=2
else:
status=0
return status
headers = {'Private-Token': 'XXXXXXXXXXXXXX'}
#this API gives you all commits grouped by pushes
pushes= "https://gitlab.XXXXX/api/v4/projects/{{projectID}}/events??target_type=issue&action=pushed"
r = requests.get(pushes, headers=headers)
latestPushes=json.loads(r.content)
lastPush=latestPushes[0]
i=0
while lastPush['push_data']['ref']!= 'master':
i+=1
lastPush=latestPushes[i]
commitNumber=lastPush['push_data']['commit_count']
if (commitNumber > 30):
raise Exception("Could not compare, too many commits in one push")
initCommit=lastPush['push_data']['commit_from']
latestCommit=lastPush['push_data']['commit_to']
compareApi= "https://gitlab.XXXXXXXXXXX/api/v4/projects/{{projectID}}/repository/compare?from="+str(initCommit)+"&to="+str(latestCommit)
r = requests.get(compareApi, headers=headers)
compareJson=json.loads(r.content)
diffs=compareJson['diffs']
Mlist=[]
Alist=[]
Dlist=[]
for asset in diffs:
status=checkAsset(asset)
if status==0:
Mlist.append(asset['new_path'].encode('ascii','ignore'))
elif status==1:
Alist.append(asset['new_path'].encode('ascii','ignore'))
else:
Dlist.append(asset['new_path'].encode('ascii','ignore'))
答案 3 :(得分:-1)
您可以使用以下命令检查提交历史记录。
OnAuthorization