How to detect a forced update

后端 未结 3 1867
不思量自难忘°
不思量自难忘° 2020-11-28 11:29

When a branch history is changed on the remote, you typically get

o git@git.server.com:XXXXX/Project.git
 + efe2e8b...cda0ee7 HEAD -> Ant_Config_processin         


        
相关标签:
3条回答
  • 2020-11-28 11:55

    You can use git-merge-base command, it finds nearest common ancestor for two commits.

    For fast-forward update, common ancestor for oldrev and newrev must point to oldrev. Sample code to be put into pre-receive hook to block non fast-forward:

    mergebase=`git merge-base $oldrev $newrev`
    if [ "$oldrev" != "$mergebase" ]; then
      echo "Non fast-forward update not allowed for $refname, from ${oldrev:0:16} to ${newrev:0:16} merge base ${mergebase:0:16}"
      exit 1
    fi
    
    0 讨论(0)
  • 2020-11-28 11:56

    One way to do it would be using git reflog, it keeps a record of the changes to the branch.

    With reflog, you can get where your branch pointed before the pull/fetch (i'd use a fetch if it is scripted, since it doesn't automatically merge) and check if that commit is reachable from the new remote's "tip" of the branch.

    Using bash you can try this:

    $ git rev-list remotename/branchname | grep $(git rev-parse remotename/branchname@{1})
    $ echo $?
    1
    

    If it returns a hash (or exit status 0) it means that it found our previous tip of the branch in the branch history, so it was a fast forward merge. If it returns nothing (or exit status 1), it was forced update.

    You can check the git reflog remotename/branchname output to see if branchname got a forced update.

    $ git reflog remotename/branchname
    dc2afab refs/remotes/remotename/branchname@{0}: fetch rewrite: forced-update
    4603c2c refs/remotes/remotename/branchname@{1}: fetch rewrite: forced-update
    
    0 讨论(0)
  • 2020-11-28 12:09

    I have a similar problem and I figured out it.

    I want to detect forced update within hook script in remote (bare) repository, So my answer might not be suitable for original question, but I hope to be useful my answer for future visitors.


    How to detect forced update or not from in Git hooks script

    https://github.com/kyanny/git-hooks-detect-force-update

    This is a sample git pre-receive hook script for learning about how to detect forced update.

    Conclusion

    $ git rev-list oldrev ^newrev
    

    How to test

    $ rake -T
    rake forced_push  # git hooks test detect forced update
    rake normal_push  # git hooks test
    

    Step-by-Step introduction

    Firstly, I describe a syntax of git-rev-list(1).

    In this case, we assume within a Git working repository that has this straight history.

    1 --- 2 --- O --- X --- 3 --- 4 --- N
    

    General usage of git-rev-list is below.

    $ git rev-list N
    

    This command will show all of commits reachable from commit N (note: git-rev-list shows commits reverse chronological order)

    git-rev-list accepts multiple arguments.

    $ git rev-list N O
    

    This command will show same output as git rev-list N, because commit O is an ancestor of commit N.

    Then, git-rev-list allows you to exclude commits from output.

    $ git rev-list N ^O
    

    ^O means that to exclude commits reachable from O, so this command will show N, 4, 3, X (note: O is excluded)


    Since we are learned about git-rev-list, I describe a case about forced update occured.

    In this case, we assume within a Git working repository that has this complex history.

    * --- B --- * --- O ($oldrev)
           \
            * --- X --- * --- N ($newrev)
    
    1. In old tree, we had 4 commits (*, B, *, O) and pushed them to remote.
    2. We checkout a new branch from commit B, it's new tree.
    3. In new tree, we had 4 commits (*, X, *, N) and pushed them to remote with --force option!

    When pushed, hook pre-receive script invoked with standard input. The format of stdin parameter is described at githooks(5).

    Typically, we extract two commit object sha1 from stdin - oldrev and newrev. oldrev is HEAD of old tree, newrev is HEAD of new tree.

    In this situation, we can detect forced push by git-rev-list output.

    git rev-list oldrev ^newrev shows the commits reachable from oldrev but not reachable from newrev. This shows the commits existed only old tree. If this command show any commits, old tree was replaced with new tree, so forced update was occured. This is what we want!

    If this command show none of commits, new tree was normally updated, so forced update was not occured. Simply.

    See Also

    • git-rev-list(1)
    • Git hook example: post-receive-email
    • git - How to detect a forced update - Stack Overflow
    • githooks - Git hook to detect push --mirror - Stack Overflow
    0 讨论(0)
提交回复
热议问题