2 """Performs a 3-way merge for GIT files
6 Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License version 2 as
10 published by the Free Software Foundation.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 # Try to detect where it is run from and set prefix and the search path.
25 # It is assumed that the user installed StGIT using the --prefix= option
26 prefix
, bin
= os
.path
.split(sys
.path
[0])
28 if bin
== 'bin' and prefix
!= sys
.prefix
:
29 major
, minor
= sys
.version_info
[0:2]
30 local_path
= [os
.path
.join(prefix
, 'lib', 'python'),
31 os
.path
.join(prefix
, 'lib', 'python%s.%s' %
(major
, minor
)),
32 os
.path
.join(prefix
, 'lib', 'python%s.%s' %
(major
, minor
),
34 sys
.path
= local_path
+ sys
.path
36 from stgit
.config
import config
37 from stgit
.utils
import append_string
44 merger
= config
.get('gitmergeonefile', 'merger')
45 except Exception, err
:
46 print >> sys
.stderr
, 'Configuration error: %s' % err
49 if config
.has_option('gitmergeonefile', 'keeporig'):
50 keeporig
= config
.get('gitmergeonefile', 'keeporig')
58 if 'GIT_DIR' in os
.environ
:
59 base_dir
= os
.environ
['GIT_DIR']
74 f
= os
.popen(cmd
, 'r')
75 string
= f
.readline().strip()
77 print >> sys
.stderr
, 'Error: failed to execute "%s"' % cmd
81 def __checkout_files():
82 """Check out the files passed as arguments
84 global orig
, src1
, src2
87 orig
= '%s.older' % path
88 tmp
= __output('git-unpack-file %s' % orig_hash
)
89 os
.chmod(tmp
, int(orig_mode
, 8))
92 src1
= '%s.local' % path
93 tmp
= __output('git-unpack-file %s' % file
1_hash
)
94 os
.chmod(tmp
, int(file1_mode
, 8))
97 src2
= '%s.remote' % path
98 tmp
= __output('git-unpack-file %s' % file
2_hash
)
99 os
.chmod(tmp
, int(file2_mode
, 8))
100 os
.renames(tmp
, src2
)
102 def __remove_files():
103 """Remove any temporary files
114 """Write the conflict file for the 'path' variable and exit
116 append_string(os
.path
.join(base_dir
, 'conflicts'), path
)
120 # $1 - original file SHA1 (or empty)
121 # $2 - file in branch1 SHA1 (or empty)
122 # $3 - file in branch2 SHA1 (or empty)
123 # $4 - pathname in repository
124 # $5 - orignal file mode (or empty)
125 # $6 - file in branch1 mode (or empty)
126 # $7 - file in branch2 mode (or empty)
128 #print 'gitmergeonefile.py "%s" "%s" "%s" "%s" "%s" "%s" "%s"' \
129 # % tuple(sys.argv[1:8])
130 orig_hash
, file1_hash
, file2_hash
, path
, orig_mode
, file1_mode
, file2_mode
= \
131 [__str2none(x
) for x
in sys
.argv
[1:8]]
139 # file exists in origin
142 if file1_hash
and file2_hash
:
143 # if modes are the same (git-read-tree probably dealed with it)
144 if file1_hash
== file2_hash
:
145 if os
.system('git-update-cache --cacheinfo %s %s %s'
146 %
(file1_mode
, file1_hash
, path
)) != 0:
147 print >> sys
.stderr
, 'Error: git-update-cache failed'
149 if os
.system('git-checkout-cache -u -f -- %s' % path
):
150 print >> sys
.stderr
, 'Error: git-checkout-cache failed'
152 if file1_mode
!= file2_mode
:
153 print >> sys
.stderr
, \
154 'Error: File added in both, permissions conflict'
158 merge_ok
= os
.system(merger %
{'branch1': src1
,
161 'output': path
}) == 0
164 os
.system('git-update-cache -- %s' % path
)
168 print >> sys
.stderr
, \
169 'Error: three-way merge tool failed for file "%s"' % path
170 # reset the cache to the first branch
171 os
.system('git-update-cache --cacheinfo %s %s %s'
172 %
(file1_mode
, file1_hash
, path
))
173 if keeporig
!= 'yes':
176 # file deleted in both or deleted in one and unchanged in the other
177 elif not (file1_hash
or file2_hash
) \
178 or file1_hash
== orig_hash
or file2_hash
== orig_hash
:
179 if os
.path
.exists(path
):
182 sys
.exit(os
.system('git-update-cache --remove -- %s' % path
))
183 # file does not exist in origin
186 if file1_hash
and file2_hash
:
188 if file1_hash
== file2_hash
:
189 if os
.system('git-update-cache --add --cacheinfo %s %s %s'
190 %
(file1_mode
, file1_hash
, path
)) != 0:
191 print >> sys
.stderr
, 'Error: git-update-cache failed'
193 if os
.system('git-checkout-cache -u -f -- %s' % path
):
194 print >> sys
.stderr
, 'Error: git-checkout-cache failed'
196 if file1_mode
!= file2_mode
:
197 print >> sys
.stderr
, \
198 'Error: File "s" added in both, permissions conflict' \
201 # files are different
203 print >> sys
.stderr
, \
204 'Error: File "%s" added in branches but different' % path
207 elif file1_hash
or file2_hash
:
214 if os
.system('git-update-cache --add --cacheinfo %s %s %s'
215 %
(mode
, obj
, path
)) != 0:
216 print >> sys
.stderr
, 'Error: git-update-cache failed'
219 sys
.exit(os
.system('git-checkout-cache -u -f -- %s' % path
))
222 print >> sys
.stderr
, 'Error: Un-handled merge conflict'
223 print >> sys
.stderr
, 'gitmergeonefile.py "%s" "%s" "%s" "%s" "%s" "%s" "%s"' \
224 %
tuple(sys
.argv
[1:8])