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?
相关问题
- Why does recursive submodule update from github fa
- Extended message for commit via Visual Studio Code
- Emacs shell: save commit message
- Can I organize Git submodules in a flat hierarchy?
- Upload file > 25 MB on Github
相关文章
- 请教Git如何克隆本地库?
- GitHub:Enterprise post-receive hook
- Git Clone Fails: Server Certificate Verification F
- SSIS solution on GIT?
- Is there a version control system abstraction for
- ssh: Could not resolve hostname git: Name or servi
- Cannot commit changes with gitextensions
- git: retry if http request failed
You say
so let's assume you did one of
immediately before you did
and then
Now you can see these 10 commits with the command
But if you did
anytime between your commits, you have spoiled your reflog of where
origin/master
was when you began your local work. You will have to remember how oftenorigin/master
was changed bygit fetch
and adjust{1}
to{2}
(it counts how many updates---not revisions---you want to go back).You can check your commit history by using below command.
Thanks for the support everyone especially @torek for his smart and interesting answer, this is how I did it with gitlab API and python:
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 thegit push
or in the Git receiving thegit 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.(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.)
The pre-push hook
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:
Let's say you did:
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 yourrefs/heads/master
identifies. The remote ref will berefs/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.If you ran instead:
your hook would get two thingies. One would mention
refs/heads/master
twice and the other would mentionrefs/heads/develop
twice: the local and remotemaster
branch, and the local and remotedevelop
branch, that you're pushing in one biggit push
operation. The hash IDs would be those for your localmaster
and for theirmaster
, and for your localdevelop
and for theirdevelop
.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.
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).1TLA stands for Three Letter Acronym. Compare with ETLA, which is an Extended TLA with more than three letters.
The pre-receive, update, and post-receive hooks
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:
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.
With our two-branches-to-update example, the two hashes for
refs/heads/master
would be the currentmaster
commit and the proposed newmaster
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 branchmaster
is all new to you); the new-hash is all-zero if you, the receiving Git, are being asked to delete the reference.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 wordremote:
stuck in front of it—and then exit nonzero, to reject the entire push.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 newmaster
commits and one newdevelop
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.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.
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!
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.
Enumerating commits
Given an old hash ID and a new hash ID, the command:
enumerates all the commits that are reachable from
$new
but not from$old
. For agit push
, these are the new commits just added, for instance.Its counterpart:
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:
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
.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 howgit 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 whatgit status
does, in a script.)Conclusion
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:
to:
where
A
throughC
are the new commits that do these three steps, consider pushing the new graph as: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—theA-B-C
chain—isolates the feature, so that if something is really terrible, you can revert the entire merge by revertingM
, and if something is slightly broken, you can test commitsA
throughC
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.