2

Given you have a file with a version number which is increased in two branches, how to prevent Git from silently automerging the two lines changing lines defining the version?

*   Git automatically merges here, but shouldn't
|\
| * change same line to the same new text
* | change some line here
 \|
  * prior history/root commit

In our case we have a database schema with migration support. Our main schema file defines the current schema version. If two people change the schema, e.g. add a database column, in different tables and both increase the schema version by +1 Git will silently merge everything but the result will be broken.

I'd suggest having a special marker to add on any line which makes Git not automerge this particular line. Is there some feature like this I don't know or how could it be achieved?

Here's a list of shell commands to create an example Git history which illustrates the problem:

$ git init test
Initialized empty Git repository in $PWD/test/.git/
$ cd test/
$ echo "version 1" > file
$ git add file
$ git commit -m "add file v1"
[master (root-commit) 4ef6950] add file v1
 1 file changed, 1 insertion(+)
 create mode 100644 file
$ git checkout -b a
Switched to a new branch 'a'
$ echo "version 2" > file
$ git commit -a -m "bump to v2"
[a 85dba39] bump to v2
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git checkout -b b master
Switched to a new branch 'b'
$ echo "version 2" > file
$ git commit -a -m "bump to v2 in b"
[b b0fcf46] bump to v2 in b
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git merge a
Merge made by the 'recursive' strategy.          
$ git status                                # shouldn't be clean
On branch b
nothing to commit, working directory clean
Daniel Böhmer
  • 14,463
  • 5
  • 36
  • 46

2 Answers2

2

I don't think what you ask for is possible.
An identical change is an identical change is an identical change.

There are two things that come to mind how you could workaround your issue:

  1. Make the developers maintain a comment on the same line that bears something unique, e. g. the current time down to the second, the unix time, ... Something that is unlikely the same on both branches when the file is changed (don't use something user specific, one user could do both changes and forgot about them)

  2. Use a pre-commit hook. In the hook check whether the commit is a merge commit and then try to determine whether there is the situation you described, where both branches changed that line and abort the merge in this case.

Vampire
  • 35,631
  • 4
  • 76
  • 102
  • Your 1st suggestion is possible although I see no advantage. Humans tend to forget things which is the purpose of this question. Your 2nd suggestions sounds like a hook-based implementation of my proposed solution but I have no idea yet how to implement the check. I've not written such a complex hook yet. Can you elaborate? – Daniel Böhmer Jan 19 '17 at 17:40
  • **1.** Of course humans forget to do this eventually. But if he does not forget it, there will be a merge conflict. And it is very less likely that he forgets to change the comment that is directly after the version he changes than that it gets forgotten that the version was increased in two branches. You could also write a pre-commit hook that is installed for forgetting people that either checks that this conflict-producer is updated, or updates it automatically (if this is possible). **2.** I have no concrete idea. Something like "check if it is a merge", then compare the diffs for the ... – Vampire Jan 19 '17 at 18:12
  • ... parent commits against the merge base of the parent commits of the file in question and compare whether two of the merged branches did the same version change. Something like that. Of course this hook has to be installed at the mergers repository. Or alternatively / additionally you can make a similar check in the pre-receive hook of your central repo if you have one, then this is validated centrally on pushing. – Vampire Jan 19 '17 at 18:14
-1

This sounds like a process problem more than a problem with git. You should do everything you can to avoid making the exact same textual change in multiple commits. This will help avoid confusion in the commit history during later archaeological expeditions. You should find ways to make the changes to your database schema without such repetition in your version history.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
  • I don't agree that making identical changes in two branches is to be avoided. If you have a large distributed project (.e.g. popular FOSS) you can't always avoid these situations. Most of the time it's no problem, e.g. if people fix the same typo. Having a linear version number tracked in Git is a special case but I don't how to circumvent this. All RDBMS migrations systems I know use linear upgrades from *n* to *n+1* each. – Daniel Böhmer Jan 19 '17 at 17:46
  • Use Liquibase, it is the best of those tools I know and there each changeset is identified by the manual Id you give it (can be any string, e. g. a number that is counted up, for us it is the module the changeset is for plus the current date and time down to the second, so these IDs are unique usually already) **plus** the file in which it is kept **plus** the author that wrote the changeset. – Vampire Jan 19 '17 at 18:09