1

I work with git repos hosted in Azure Devops (AzDO). Usually the master branch has AzDO policy that you can't push directly to it, and must use pull requests. However, some folks accidentally commit locally to master, and then their master branch gets out of sync with the origin, and they need to reset it with git reset --hard origin. I want to avoid this.

I know I can prevent commits to master using pre-commit hooks, with scripts or utils that will block (See answers to this question, and also this answer to a similar question). The richest util for this - https://pre-commit.com/hooks.html - only has a manually-configured no-commit-to-branch list.

Is there a solution that will block commits to any branch with policies in AzDO?

Edit in response to comments:

  • I disagree it's a training issue. A tool should do its best to guard users from mistake (just like saws have hand guard/etc.). IMO git fails at it, and git/AzDO could do better.
    • That said, maybe the git checkout master/git checkout -b mybranch is at fault here. So git fetch/git checkout -b mybranch origin/master would be safer.
  • I know one can reset/rebase, and that's the workaround for folks that got into this situation. However, I'd like to avoid that, especially for people with lower git skills.
Jonathan
  • 6,939
  • 4
  • 44
  • 61
  • Just FYI, the [general consensus](https://stackoverflow.com/q/58029322/184546) seems to be that AzureDevOps should not be abbreviated, but if it is, it shouldn't be abbreviated as "ADO". Perhaps the leading contender is "AzDO", which happens to be my personal preference. – TTT Feb 08 '22 at 16:29
  • 1
    I think training would go farther than trying to stop devs from committing locally to certain branches (which you can't really enforce anyway, though you can try to help by asking them to use pre-commit hooks like you're investigating). Some of the devs at my company used to have a similar issue, and the best advice I found for them was: "Stop checking out `master`. Just `fetch` often, and use `origin/master` anytime you would have previously used `master`." This seems to have worked for most people. – TTT Feb 08 '22 at 16:38
  • 1
    Yeah, this is a people problem. I occasionally commit to the wrong branch on occasion, and a quick rebase/reset solves the problem and I go about my day. – Daniel Mann Feb 08 '22 at 17:16
  • Git itself has no such option (and cannot provide anything enforceable here because branch names are *private* up until someone "says them out loud" as it were). Web hosting sites often provide protection because "push my commits to other repository and have them set their branch name" is the "saying out loud" part that makes a name *public* in the first place. – torek Feb 08 '22 at 23:20
  • 1
    @TTT: `ADO` was common inside Microsoft. I never liked it in there too... I've edited to `AzDO` – Jonathan Feb 09 '22 at 09:11
  • @TTT: If you write an answer about fetch/etc., I'll accept it. – Jonathan Feb 09 '22 at 09:24
  • @Jonathan do you mean MS employees commonly referred to AzureDevOps as "ADO"? And no one cared about the older MS technology called "ADO"? – TTT Feb 09 '22 at 21:38
  • 1
    @TTT: Yes, in some Microsoft circles they would refer to AzureDevOps as "ADO". It was never confused with ActiveX Data Objects. – Jonathan Feb 10 '22 at 11:21
  • @Jonathan Hehe. I wouldn't expect anyone to ever *confuse* it with the old ADO, but I'm a little surprised they used it since it seems the MS official position is to not abbreviate it. :) – TTT Feb 10 '22 at 15:36

2 Answers2

1

tl;dr: One possible solution is to sidestep the issue. Instruct your users (that are not super comfortable with Git yet) to delete their local copy of master and never checkout the master branch again. Instead they can update their copy of the remote branches often with git fetch, and they can use origin/master when making new branches or rebasing/merging to update their branches with the latest origin/master. I don't know that I would go so far as to prevent users from checking out master though, since more advanced users of Git might still wish to do so for some reason, and they would be perfectly comfortable resetting or renaming that local branch as needed.

I have recommended this approach to my co-workers and anecdotal evidence (of approximately 50 developers over the last few years) shows it seems to work fairly well. I also eat my own dog food most of the time; I still occasionally checkout out shared branches when I need to commit to one directly (and either bypass policies to push, or on very rare occasions, force push).

Additional Notes:

When you use remote tracking branches (such as origin/master) to create new branches, by default the new local branch will track that remote branch, which you normally don't want. So, when creating branches this way you'll probably want to use --no-track. In general, to make pushing for the first time slightly easier I recommend using the config setting of push.default to current. More info here.

Here are some recommended conventions for using origin/master:

# Update your local copy of the remote branches often,
#   especially before creating or updating branches
git fetch

# Create a new branch (newer syntax)
git switch -c my-branch origin/master --no-track
# Create a new branch (old syntax)
git checkout -b my-branch origin/master --no-track

# Pushing out changes for the first time
git push -u origin my-branch
# Pushing out changes for the first time with config set to current
git push -u
# Subsequent pushes
git push

# Update your feature branch using rebase
git switch my-branch
git fetch
git rebase origin/master
git push --force-with-lease

# Update your feature branch using merge
git switch my-branch
git fetch
git merge origin/master
git push

Also, you mentioned:

A tool should do its best to guard users from mistake...

I generally agree, though you do need to make sure your solution works for everyone. Ideally there would be a way to enable using training wheels for those that want/need them, without forcing them on those who can ride effectively without them. As I mentioned above I wouldn't want to be prevented from checking out (or committing to) a shared branch, since I sometimes actually need to. That being said, since using pre-commit hooks are at the user's discretion, I could simply not use the hook, or perhaps disable it temporarily when I need to bypass it, so I would not be too bothered by that sort of hook.

On the other hand, here's a really silly example that would bother me. In one of the Git repos I work out of we have a (strongly urged but not yet enforced) policy that all commit titles should begin with a capital letter. I recently demoed a pre-commit hook that warns you when you create a commit starting with a lowercase letter. Someone asked me if that hook could be changed to prevent from creating commits that don't begin with a capital letter, and I told them that I didn't want that, because I happen to purposefully make lots of local commits beginning with a lowercase letter. I'm referring to my WIP temporary commits, for which I use a lowercase letter as a note-to-self that I need to rewrite the commit before PR'ing it into a shared branch. If others wish to use the same mnemonic, they too would need that hook to be only a warning rather than a block. I would however support a block on the server side to prevent merging in commits that don't begin with a capital letter, as long as someone had the capability to override it, to cover the case where certain commits cannot (or should not) be re-written.

TTT
  • 22,611
  • 8
  • 63
  • 69
1

However, some folks accidentally commit locally to master, and then their master branch gets out of sync with the origin, and they need to reset it with git reset --hard origin. I want to avoid this.

They don't need to do that. In Git, all ref names are local and completely, utterly arbitrary. Just rename the local branch.

git branch -M master whatIshouldhavecalledit

is all they need, rename their branch.

jthill
  • 55,082
  • 5
  • 77
  • 137
  • isn't "whatIshouldhavecalledit" still tracked to origin\master? (which could be confusing with pull and push) – Julian Feb 10 '22 at 09:47