{"thread":{"id":"62946","subject":"Get the commits to be pushed accurately in pre-push hook","startedAt":"2025-02-13T02:06:01Z","lastAt":"2025-02-13T02:49:41Z","messageCount":2,"participants":["Jayce Cao","brian m. carlson"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"512336","messageId":"CAGwx5_8wNzE51Z7pYA_skimZZ29b8C_Bxk_58kPOqcWAmSQpHw@mail.gmail.com","threadId":"62946","inReplyTo":null,"subject":"Get the commits to be pushed accurately in pre-push hook","fromName":"Jayce Cao","fromEmail":"jaycecao520@gmail.com","sentAt":"2025-02-13T02:05:47Z","receivedAt":"2025-02-13T02:06:01Z","isPatch":false,"sender":{"key":"jaycecao520@gmail.com","avatar":null},"body":"My goal is to check the commits to be pushed in pre-push hook to see\nif they contain sensitive data or not.\nI have an assumption that those commits which already exist in remote\nrepos have no need to check.\n\nSo I read the Git doc and pre-push.sample file, I know that if we push\nto a new branch that the remote does not have,\n$remote_oid weil be zero, so we need to examine all commits in this\nbranch. We can run `git rev-list $local_oid` to\nget all commits to be examined.\n\nBut consider this case, if I'm developing a huge project which has\nmillions of commits.\nI create a new branch (we call it feat/awesome-feat) based on the\nmaster branch on my local repo, and create three commits.\nThen I run the `git push --set-upstream origin feat/awesome-feat`\ncommand to push the three commits to the remote.\nBut when the pre-push hook is called, `git rev-list $local_oid` will\nprint millions of commits. The commits except the new three\nalready exist in the remote repo. And the `git push` command will send\ndata only in the new commits to the remote, instead of all\nhistory commits.\n\nSo I mean we've no idea which commits will be sent to the remote\nindeed in the pre-push hook when pushing to a new branch\nthat the remote doesn't have. I found a workaround:\n* Run `git ls-remote -q -h` command to get the commits the remote has.\n* Run `git rev-list $local_oid ^$haves` command to get the commits to\nbe pushed.($haves are the commits obtained from the previous step).\n\nBut this workaround seems to be stupid when the remote has many\nbranches. I wonder if there is any better way to get the commits\nto be pushed accurately in the pre-push hook.\n"},{"id":"512337","messageId":"Z61dw-pzJKgs7U-v@tapette.crustytoothpaste.net","threadId":"62946","inReplyTo":"CAGwx5_8wNzE51Z7pYA_skimZZ29b8C_Bxk_58kPOqcWAmSQpHw@mail.gmail.com","subject":"Re: Get the commits to be pushed accurately in pre-push hook","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2025-02-13T02:49:39Z","receivedAt":"2025-02-13T02:49:41Z","isPatch":false,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On 2025-02-13 at 02:05:47, Jayce Cao wrote:\n> My goal is to check the commits to be pushed in pre-push hook to see\n> if they contain sensitive data or not.\n> I have an assumption that those commits which already exist in remote\n> repos have no need to check.\n\nYou will probably want to read\nhttps://git-scm.com/docs/gitfaq#restrict-with-hooks.  It's very easy to\nbypass the `pre-push` hook locally by using `--no-verify` without any\nway to detect that, so assuming you want to have an effective control,\nyou'll want a different approach.   Note also that I don't believe\nlibgit2 or other library-based Git engines invoke hooks at all, which is\nalso going to lend itself to probably adopting a different approach.\n\n> So I read the Git doc and pre-push.sample file, I know that if we push\n> to a new branch that the remote does not have,\n> $remote_oid weil be zero, so we need to examine all commits in this\n> branch. We can run `git rev-list $local_oid` to\n> get all commits to be examined.\n> \n> But consider this case, if I'm developing a huge project which has\n> millions of commits.\n> I create a new branch (we call it feat/awesome-feat) based on the\n> master branch on my local repo, and create three commits.\n> Then I run the `git push --set-upstream origin feat/awesome-feat`\n> command to push the three commits to the remote.\n> But when the pre-push hook is called, `git rev-list $local_oid` will\n> print millions of commits. The commits except the new three\n> already exist in the remote repo. And the `git push` command will send\n> data only in the new commits to the remote, instead of all\n> history commits.\n> \n> So I mean we've no idea which commits will be sent to the remote\n> indeed in the pre-push hook when pushing to a new branch\n> that the remote doesn't have. I found a workaround:\n> * Run `git ls-remote -q -h` command to get the commits the remote has.\n> * Run `git rev-list $local_oid ^$haves` command to get the commits to\n> be pushed.($haves are the commits obtained from the previous step).\n> \n> But this workaround seems to be stupid when the remote has many\n> branches. I wonder if there is any better way to get the commits\n> to be pushed accurately in the pre-push hook.\n\nGit LFS has an optimization where it uses `git rev-list --not\n--remotes=origin` (or whatever the remote is).  This excludes objects\nreachable from remote-tracking refs for the origin in question.\n\nHowever, this has some limitations.  For instance, if the remote is\nspecified as a URL and not a remote name, then there will never be any\nremote-tracking branches, and this optimization cannot be used.\nNotably, I believe EGit (and maybe JGit) _always_ specify the remote as\na URL and never as a remote name, so this will not work there.\n\nYou may wish to inspect that project's source code for more details.\n\nI am not aware of a better way to do this, but as I mentioned above, you\nmay not want to do this at all.\n-- \nbrian m. carlson (they/them or he/him)\nToronto, Ontario, CA\n"}]}