##// END OF EJS Templates
merge with stable
Augie Fackler -
r44722:15eb9096 merge default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,193 +1,194 b''
1 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0 iD8DBQBEYmO2ywK+sNU5EO8RAnaYAKCO7x15xUn5mnhqWNXqk/ehlhRt2QCfRDfY0LrUq2q4oK/KypuJYPHgq1A=
1 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0 iD8DBQBEYmO2ywK+sNU5EO8RAnaYAKCO7x15xUn5mnhqWNXqk/ehlhRt2QCfRDfY0LrUq2q4oK/KypuJYPHgq1A=
2 2be3001847cb18a23c403439d9e7d0ace30804e9 0 iD8DBQBExUbjywK+sNU5EO8RAhzxAKCtyHAQUzcTSZTqlfJ0by6vhREwWQCghaQFHfkfN0l9/40EowNhuMOKnJk=
2 2be3001847cb18a23c403439d9e7d0ace30804e9 0 iD8DBQBExUbjywK+sNU5EO8RAhzxAKCtyHAQUzcTSZTqlfJ0by6vhREwWQCghaQFHfkfN0l9/40EowNhuMOKnJk=
3 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0 iD8DBQBFfL2QywK+sNU5EO8RAjYFAKCoGlaWRTeMsjdmxAjUYx6diZxOBwCfY6IpBYsKvPTwB3oktnPt5Rmrlys=
3 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0 iD8DBQBFfL2QywK+sNU5EO8RAjYFAKCoGlaWRTeMsjdmxAjUYx6diZxOBwCfY6IpBYsKvPTwB3oktnPt5Rmrlys=
4 27230c29bfec36d5540fbe1c976810aefecfd1d2 0 iD8DBQBFheweywK+sNU5EO8RAt7VAKCrqJQWT2/uo2RWf0ZI4bLp6v82jACgjrMdsaTbxRsypcmEsdPhlG6/8F4=
4 27230c29bfec36d5540fbe1c976810aefecfd1d2 0 iD8DBQBFheweywK+sNU5EO8RAt7VAKCrqJQWT2/uo2RWf0ZI4bLp6v82jACgjrMdsaTbxRsypcmEsdPhlG6/8F4=
5 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0 iD8DBQBGgHicywK+sNU5EO8RAgNxAJ0VG8ixAaeudx4sZbhngI1syu49HQCeNUJQfWBgA8bkJ2pvsFpNxwYaX3I=
5 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0 iD8DBQBGgHicywK+sNU5EO8RAgNxAJ0VG8ixAaeudx4sZbhngI1syu49HQCeNUJQfWBgA8bkJ2pvsFpNxwYaX3I=
6 23889160905a1b09fffe1c07378e9fc1827606eb 0 iD8DBQBHGTzoywK+sNU5EO8RAr/UAJ0Y8s4jQtzgS+G9vM8z6CWBThZ8fwCcCT5XDj2XwxKkz/0s6UELwjsO3LU=
6 23889160905a1b09fffe1c07378e9fc1827606eb 0 iD8DBQBHGTzoywK+sNU5EO8RAr/UAJ0Y8s4jQtzgS+G9vM8z6CWBThZ8fwCcCT5XDj2XwxKkz/0s6UELwjsO3LU=
7 bae2e9c838e90a393bae3973a7850280413e091a 0 iD8DBQBH6DO5ywK+sNU5EO8RAsfrAJ0e4r9c9GF/MJsM7Xjd3NesLRC3+ACffj6+6HXdZf8cswAoFPO+DY00oD0=
7 bae2e9c838e90a393bae3973a7850280413e091a 0 iD8DBQBH6DO5ywK+sNU5EO8RAsfrAJ0e4r9c9GF/MJsM7Xjd3NesLRC3+ACffj6+6HXdZf8cswAoFPO+DY00oD0=
8 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 0 iD8DBQBINdwsywK+sNU5EO8RAjIUAKCPmlFJSpsPAAUKF+iNHAwVnwmzeQCdEXrL27CWclXuUKdbQC8De7LICtE=
8 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 0 iD8DBQBINdwsywK+sNU5EO8RAjIUAKCPmlFJSpsPAAUKF+iNHAwVnwmzeQCdEXrL27CWclXuUKdbQC8De7LICtE=
9 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 0 iD8DBQBIo1wpywK+sNU5EO8RAmRNAJ94x3OFt6blbqu/yBoypm/AJ44fuACfUaldXcV5z9tht97hSp22DVTEPGc=
9 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 0 iD8DBQBIo1wpywK+sNU5EO8RAmRNAJ94x3OFt6blbqu/yBoypm/AJ44fuACfUaldXcV5z9tht97hSp22DVTEPGc=
10 2a67430f92f15ea5159c26b09ec4839a0c549a26 0 iEYEABECAAYFAkk1hykACgkQywK+sNU5EO85QACeNJNUanjc2tl4wUoPHNuv+lSj0ZMAoIm93wSTc/feyYnO2YCaQ1iyd9Nu
10 2a67430f92f15ea5159c26b09ec4839a0c549a26 0 iEYEABECAAYFAkk1hykACgkQywK+sNU5EO85QACeNJNUanjc2tl4wUoPHNuv+lSj0ZMAoIm93wSTc/feyYnO2YCaQ1iyd9Nu
11 3773e510d433969e277b1863c317b674cbee2065 0 iEYEABECAAYFAklNbbAACgkQywK+sNU5EO8o+gCfeb2/lfIJZMvyDA1m+G1CsBAxfFsAoIa6iAMG8SBY7hW1Q85Yf/LXEvaE
11 3773e510d433969e277b1863c317b674cbee2065 0 iEYEABECAAYFAklNbbAACgkQywK+sNU5EO8o+gCfeb2/lfIJZMvyDA1m+G1CsBAxfFsAoIa6iAMG8SBY7hW1Q85Yf/LXEvaE
12 11a4eb81fb4f4742451591489e2797dc47903277 0 iEYEABECAAYFAklcAnsACgkQywK+sNU5EO+uXwCbBVHNNsLy1g7BlAyQJwadYVyHOXoAoKvtAVO71+bv7EbVoukwTzT+P4Sx
12 11a4eb81fb4f4742451591489e2797dc47903277 0 iEYEABECAAYFAklcAnsACgkQywK+sNU5EO+uXwCbBVHNNsLy1g7BlAyQJwadYVyHOXoAoKvtAVO71+bv7EbVoukwTzT+P4Sx
13 11efa41037e280d08cfb07c09ad485df30fb0ea8 0 iEYEABECAAYFAkmvJRQACgkQywK+sNU5EO9XZwCeLMgDgPSMWMm6vgjL4lDs2pEc5+0AnRxfiFbpbBfuEFTqKz9nbzeyoBlx
13 11efa41037e280d08cfb07c09ad485df30fb0ea8 0 iEYEABECAAYFAkmvJRQACgkQywK+sNU5EO9XZwCeLMgDgPSMWMm6vgjL4lDs2pEc5+0AnRxfiFbpbBfuEFTqKz9nbzeyoBlx
14 02981000012e3adf40c4849bd7b3d5618f9ce82d 0 iEYEABECAAYFAknEH3wACgkQywK+sNU5EO+uXwCeI+LbLMmhjU1lKSfU3UWJHjjUC7oAoIZLvYDGOL/tNZFUuatc3RnZ2eje
14 02981000012e3adf40c4849bd7b3d5618f9ce82d 0 iEYEABECAAYFAknEH3wACgkQywK+sNU5EO+uXwCeI+LbLMmhjU1lKSfU3UWJHjjUC7oAoIZLvYDGOL/tNZFUuatc3RnZ2eje
15 196d40e7c885fa6e95f89134809b3ec7bdbca34b 0 iEYEABECAAYFAkpL2X4ACgkQywK+sNU5EO9FOwCfXJycjyKJXsvQqKkHrglwOQhEKS4An36GfKzptfN8b1qNc3+ya/5c2WOM
15 196d40e7c885fa6e95f89134809b3ec7bdbca34b 0 iEYEABECAAYFAkpL2X4ACgkQywK+sNU5EO9FOwCfXJycjyKJXsvQqKkHrglwOQhEKS4An36GfKzptfN8b1qNc3+ya/5c2WOM
16 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 0 iEYEABECAAYFAkpopLIACgkQywK+sNU5EO8QSgCfZ0ztsd071rOa2lhmp9Fyue/WoI0AoLTei80/xrhRlB8L/rZEf2KBl8dA
16 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 0 iEYEABECAAYFAkpopLIACgkQywK+sNU5EO8QSgCfZ0ztsd071rOa2lhmp9Fyue/WoI0AoLTei80/xrhRlB8L/rZEf2KBl8dA
17 31ec469f9b556f11819937cf68ee53f2be927ebf 0 iEYEABECAAYFAksBuxAACgkQywK+sNU5EO+mBwCfagB+A0txzWZ6dRpug3LEoK7Z1QsAoKpbk8vsLjv6/oRDicSk/qBu33+m
17 31ec469f9b556f11819937cf68ee53f2be927ebf 0 iEYEABECAAYFAksBuxAACgkQywK+sNU5EO+mBwCfagB+A0txzWZ6dRpug3LEoK7Z1QsAoKpbk8vsLjv6/oRDicSk/qBu33+m
18 439d7ea6fe3aa4ab9ec274a68846779153789de9 0 iEYEABECAAYFAksVw0kACgkQywK+sNU5EO/oZwCfdfBEkgp38xq6wN2F4nj+SzofrJIAnjmxt04vaJSeOOeHylHvk6lzuQsw
18 439d7ea6fe3aa4ab9ec274a68846779153789de9 0 iEYEABECAAYFAksVw0kACgkQywK+sNU5EO/oZwCfdfBEkgp38xq6wN2F4nj+SzofrJIAnjmxt04vaJSeOOeHylHvk6lzuQsw
19 296a0b14a68621f6990c54fdba0083f6f20935bf 0 iEYEABECAAYFAks+jCoACgkQywK+sNU5EO9J8wCeMUGF9E/gS2UBsqIz56WS4HMPRPUAoI5J95mwEIK8Clrl7qFRidNI6APq
19 296a0b14a68621f6990c54fdba0083f6f20935bf 0 iEYEABECAAYFAks+jCoACgkQywK+sNU5EO9J8wCeMUGF9E/gS2UBsqIz56WS4HMPRPUAoI5J95mwEIK8Clrl7qFRidNI6APq
20 4aa619c4c2c09907034d9824ebb1dd0e878206eb 0 iEYEABECAAYFAktm9IsACgkQywK+sNU5EO9XGgCgk4HclRQhexEtooPE5GcUCdB6M8EAn2ptOhMVbIoO+JncA+tNACPFXh0O
20 4aa619c4c2c09907034d9824ebb1dd0e878206eb 0 iEYEABECAAYFAktm9IsACgkQywK+sNU5EO9XGgCgk4HclRQhexEtooPE5GcUCdB6M8EAn2ptOhMVbIoO+JncA+tNACPFXh0O
21 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 0 iEYEABECAAYFAkuRoSQACgkQywK+sNU5EO//3QCeJDc5r2uFyFCtAlpSA27DEE5rrxAAn2FSwTy9fhrB3QAdDQlwkEZcQzDh
21 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 0 iEYEABECAAYFAkuRoSQACgkQywK+sNU5EO//3QCeJDc5r2uFyFCtAlpSA27DEE5rrxAAn2FSwTy9fhrB3QAdDQlwkEZcQzDh
22 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 0 iEYEABECAAYFAku1IwIACgkQywK+sNU5EO9MjgCdHLVwkTZlNHxhcznZKBL1rjN+J7cAoLLWi9LTL6f/TgBaPSKOy1ublbaW
22 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 0 iEYEABECAAYFAku1IwIACgkQywK+sNU5EO9MjgCdHLVwkTZlNHxhcznZKBL1rjN+J7cAoLLWi9LTL6f/TgBaPSKOy1ublbaW
23 39f725929f0c48c5fb3b90c071fc3066012456ca 0 iEYEABECAAYFAkvclvsACgkQywK+sNU5EO9FSwCeL9i5x8ALW/LE5+lCX6MFEAe4MhwAn1ev5o6SX6GrNdDfKweiemfO2VBk
23 39f725929f0c48c5fb3b90c071fc3066012456ca 0 iEYEABECAAYFAkvclvsACgkQywK+sNU5EO9FSwCeL9i5x8ALW/LE5+lCX6MFEAe4MhwAn1ev5o6SX6GrNdDfKweiemfO2VBk
24 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 0 iEYEABECAAYFAkvsKTkACgkQywK+sNU5EO9qEACgiSiRGvTG2vXGJ65tUSOIYihTuFAAnRzRIqEVSw8M8/RGeUXRps0IzaCO
24 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 0 iEYEABECAAYFAkvsKTkACgkQywK+sNU5EO9qEACgiSiRGvTG2vXGJ65tUSOIYihTuFAAnRzRIqEVSw8M8/RGeUXRps0IzaCO
25 24fe2629c6fd0c74c90bd066e77387c2b02e8437 0 iEYEABECAAYFAkwFLRsACgkQywK+sNU5EO+pJACgp13tPI+pbwKZV+LeMjcQ4H6tCZYAoJebzhd6a8yYx6qiwpJxA9BXZNXy
25 24fe2629c6fd0c74c90bd066e77387c2b02e8437 0 iEYEABECAAYFAkwFLRsACgkQywK+sNU5EO+pJACgp13tPI+pbwKZV+LeMjcQ4H6tCZYAoJebzhd6a8yYx6qiwpJxA9BXZNXy
26 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 0 iEYEABECAAYFAkwsyxcACgkQywK+sNU5EO+crACfUpNAF57PmClkSri9nJcBjb2goN4AniPCNaKvnki7TnUsi1u2oxltpKKL
26 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 0 iEYEABECAAYFAkwsyxcACgkQywK+sNU5EO+crACfUpNAF57PmClkSri9nJcBjb2goN4AniPCNaKvnki7TnUsi1u2oxltpKKL
27 bf1774d95bde614af3956d92b20e2a0c68c5fec7 0 iEYEABECAAYFAkxVwccACgkQywK+sNU5EO+oFQCeJzwZ+we1fIIyBGCddHceOUAN++cAnjvT6A8ZWW0zV21NXIFF1qQmjxJd
27 bf1774d95bde614af3956d92b20e2a0c68c5fec7 0 iEYEABECAAYFAkxVwccACgkQywK+sNU5EO+oFQCeJzwZ+we1fIIyBGCddHceOUAN++cAnjvT6A8ZWW0zV21NXIFF1qQmjxJd
28 c00f03a4982e467fb6b6bd45908767db6df4771d 0 iEYEABECAAYFAkxXDqsACgkQywK+sNU5EO/GJACfT9Rz4hZOxPQEs91JwtmfjevO84gAmwSmtfo5mmWSm8gtTUebCcdTv0Kf
28 c00f03a4982e467fb6b6bd45908767db6df4771d 0 iEYEABECAAYFAkxXDqsACgkQywK+sNU5EO/GJACfT9Rz4hZOxPQEs91JwtmfjevO84gAmwSmtfo5mmWSm8gtTUebCcdTv0Kf
29 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 0 iD8DBQBMdo+qywK+sNU5EO8RAqQpAJ975BL2CCAiWMz9SXthNQ9xG181IwCgp4O+KViHPkufZVFn2aTKMNvcr1A=
29 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 0 iD8DBQBMdo+qywK+sNU5EO8RAqQpAJ975BL2CCAiWMz9SXthNQ9xG181IwCgp4O+KViHPkufZVFn2aTKMNvcr1A=
30 93d8bff78c96fe7e33237b257558ee97290048a4 0 iD8DBQBMpfvdywK+sNU5EO8RAsxVAJ0UaL1XB51C76JUBhafc9GBefuMxwCdEWkTOzwvE0SarJBe9i008jhbqW4=
30 93d8bff78c96fe7e33237b257558ee97290048a4 0 iD8DBQBMpfvdywK+sNU5EO8RAsxVAJ0UaL1XB51C76JUBhafc9GBefuMxwCdEWkTOzwvE0SarJBe9i008jhbqW4=
31 333421b9e0f96c7bc788e5667c146a58a9440a55 0 iD8DBQBMz0HOywK+sNU5EO8RAlsEAJ0USh6yOG7OrWkADGunVt9QimBQnwCbBqeMnKgSbwEw8jZwE3Iz1mdrYlo=
31 333421b9e0f96c7bc788e5667c146a58a9440a55 0 iD8DBQBMz0HOywK+sNU5EO8RAlsEAJ0USh6yOG7OrWkADGunVt9QimBQnwCbBqeMnKgSbwEw8jZwE3Iz1mdrYlo=
32 4438875ec01bd0fc32be92b0872eb6daeed4d44f 0 iD8DBQBM4WYUywK+sNU5EO8RAhCVAJ0dJswachwFAHALmk1x0RJehxzqPQCbBNskP9n/X689jB+btNTZTyKU/fw=
32 4438875ec01bd0fc32be92b0872eb6daeed4d44f 0 iD8DBQBM4WYUywK+sNU5EO8RAhCVAJ0dJswachwFAHALmk1x0RJehxzqPQCbBNskP9n/X689jB+btNTZTyKU/fw=
33 6aff4f144ad356311318b0011df0bb21f2c97429 0 iD8DBQBM9uxXywK+sNU5EO8RAv+4AKCDj4qKP16GdPaq1tP6BUwpM/M1OACfRyzLPp/qiiN8xJTWoWYSe/XjJug=
33 6aff4f144ad356311318b0011df0bb21f2c97429 0 iD8DBQBM9uxXywK+sNU5EO8RAv+4AKCDj4qKP16GdPaq1tP6BUwpM/M1OACfRyzLPp/qiiN8xJTWoWYSe/XjJug=
34 e3bf16703e2601de99e563cdb3a5d50b64e6d320 0 iD8DBQBNH8WqywK+sNU5EO8RAiQTAJ9sBO+TeiGro4si77VVaQaA6jcRUgCfSA28dBbjj0oFoQwvPoZjANiZBH8=
34 e3bf16703e2601de99e563cdb3a5d50b64e6d320 0 iD8DBQBNH8WqywK+sNU5EO8RAiQTAJ9sBO+TeiGro4si77VVaQaA6jcRUgCfSA28dBbjj0oFoQwvPoZjANiZBH8=
35 a6c855c32ea081da3c3b8ff628f1847ff271482f 0 iD8DBQBNSJJ+ywK+sNU5EO8RAoJaAKCweDEF70fu+r1Zn7pYDXdlk5RuSgCeO9gK/eit8Lin/1n3pO7aYguFLok=
35 a6c855c32ea081da3c3b8ff628f1847ff271482f 0 iD8DBQBNSJJ+ywK+sNU5EO8RAoJaAKCweDEF70fu+r1Zn7pYDXdlk5RuSgCeO9gK/eit8Lin/1n3pO7aYguFLok=
36 2b2155623ee2559caf288fd333f30475966c4525 0 iD8DBQBNSJeBywK+sNU5EO8RAm1KAJ4hW9Cm9nHaaGJguchBaPLlAr+O3wCgqgmMok8bdAS06N6PL60PSTM//Gg=
36 2b2155623ee2559caf288fd333f30475966c4525 0 iD8DBQBNSJeBywK+sNU5EO8RAm1KAJ4hW9Cm9nHaaGJguchBaPLlAr+O3wCgqgmMok8bdAS06N6PL60PSTM//Gg=
37 2616325766e3504c8ae7c84bd15ee610901fe91d 0 iD8DBQBNbWy9ywK+sNU5EO8RAlWCAJ4mW8HbzjJj9GpK98muX7k+7EvEHwCfaTLbC/DH3QEsZBhEP+M8tzL6RU4=
37 2616325766e3504c8ae7c84bd15ee610901fe91d 0 iD8DBQBNbWy9ywK+sNU5EO8RAlWCAJ4mW8HbzjJj9GpK98muX7k+7EvEHwCfaTLbC/DH3QEsZBhEP+M8tzL6RU4=
38 aa1f3be38ab127280761889d2dca906ca465b5f4 0 iD8DBQBNeQq7ywK+sNU5EO8RAlEOAJ4tlEDdetE9lKfjGgjbkcR8PrC3egCfXCfF3qNVvU/2YYjpgvRwevjvDy0=
38 aa1f3be38ab127280761889d2dca906ca465b5f4 0 iD8DBQBNeQq7ywK+sNU5EO8RAlEOAJ4tlEDdetE9lKfjGgjbkcR8PrC3egCfXCfF3qNVvU/2YYjpgvRwevjvDy0=
39 b032bec2c0a651ca0ddecb65714bfe6770f67d70 0 iD8DBQBNlg5kywK+sNU5EO8RAnGEAJ9gmEx6MfaR4XcG2m/93vwtfyzs3gCgltzx8/YdHPwqDwRX/WbpYgi33is=
39 b032bec2c0a651ca0ddecb65714bfe6770f67d70 0 iD8DBQBNlg5kywK+sNU5EO8RAnGEAJ9gmEx6MfaR4XcG2m/93vwtfyzs3gCgltzx8/YdHPwqDwRX/WbpYgi33is=
40 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 0 iD8DBQBNvTy4ywK+sNU5EO8RAmp8AJ9QnxK4jTJ7G722MyeBxf0UXEdGwACgtlM7BKtNQfbEH/fOW5y+45W88VI=
40 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 0 iD8DBQBNvTy4ywK+sNU5EO8RAmp8AJ9QnxK4jTJ7G722MyeBxf0UXEdGwACgtlM7BKtNQfbEH/fOW5y+45W88VI=
41 733af5d9f6b22387913e1d11350fb8cb7c1487dd 0 iD8DBQBN5q/8ywK+sNU5EO8RArRGAKCNGT94GKIYtSuwZ57z1sQbcw6uLACfffpbMV4NAPMl8womAwg+7ZPKnIU=
41 733af5d9f6b22387913e1d11350fb8cb7c1487dd 0 iD8DBQBN5q/8ywK+sNU5EO8RArRGAKCNGT94GKIYtSuwZ57z1sQbcw6uLACfffpbMV4NAPMl8womAwg+7ZPKnIU=
42 de9eb6b1da4fc522b1cab16d86ca166204c24f25 0 iD8DBQBODhfhywK+sNU5EO8RAr2+AJ4ugbAj8ae8/K0bYZzx3sascIAg1QCeK3b+zbbVVqd3b7CDpwFnaX8kTd4=
42 de9eb6b1da4fc522b1cab16d86ca166204c24f25 0 iD8DBQBODhfhywK+sNU5EO8RAr2+AJ4ugbAj8ae8/K0bYZzx3sascIAg1QCeK3b+zbbVVqd3b7CDpwFnaX8kTd4=
43 4a43e23b8c55b4566b8200bf69fe2158485a2634 0 iD8DBQBONzIMywK+sNU5EO8RAj5SAJ0aPS3+JHnyI6bHB2Fl0LImbDmagwCdGbDLp1S7TFobxXudOH49bX45Iik=
43 4a43e23b8c55b4566b8200bf69fe2158485a2634 0 iD8DBQBONzIMywK+sNU5EO8RAj5SAJ0aPS3+JHnyI6bHB2Fl0LImbDmagwCdGbDLp1S7TFobxXudOH49bX45Iik=
44 d629f1e89021103f1753addcef6b310e4435b184 0 iD8DBQBOWAsBywK+sNU5EO8RAht4AJwJl9oNFopuGkj5m8aKuf7bqPkoAQCeNrEm7UhFsZKYT5iUOjnMV7s2LaM=
44 d629f1e89021103f1753addcef6b310e4435b184 0 iD8DBQBOWAsBywK+sNU5EO8RAht4AJwJl9oNFopuGkj5m8aKuf7bqPkoAQCeNrEm7UhFsZKYT5iUOjnMV7s2LaM=
45 351a9292e430e35766c552066ed3e87c557b803b 0 iD8DBQBOh3zUywK+sNU5EO8RApFMAKCD3Y/u3avDFndznwqfG5UeTHMlvACfUivPIVQZyDZnhZMq0UhC6zhCEQg=
45 351a9292e430e35766c552066ed3e87c557b803b 0 iD8DBQBOh3zUywK+sNU5EO8RApFMAKCD3Y/u3avDFndznwqfG5UeTHMlvACfUivPIVQZyDZnhZMq0UhC6zhCEQg=
46 384082750f2c51dc917d85a7145748330fa6ef4d 0 iD8DBQBOmd+OywK+sNU5EO8RAgDgAJ9V/X+G7VLwhTpHrZNiOHabzSyzYQCdE2kKfIevJUYB9QLAWCWP6DPwrwI=
46 384082750f2c51dc917d85a7145748330fa6ef4d 0 iD8DBQBOmd+OywK+sNU5EO8RAgDgAJ9V/X+G7VLwhTpHrZNiOHabzSyzYQCdE2kKfIevJUYB9QLAWCWP6DPwrwI=
47 41453d55b481ddfcc1dacb445179649e24ca861d 0 iD8DBQBOsFhpywK+sNU5EO8RAqM6AKCyfxUae3/zLuiLdQz+JR78690eMACfQ6JTBQib4AbE+rUDdkeFYg9K/+4=
47 41453d55b481ddfcc1dacb445179649e24ca861d 0 iD8DBQBOsFhpywK+sNU5EO8RAqM6AKCyfxUae3/zLuiLdQz+JR78690eMACfQ6JTBQib4AbE+rUDdkeFYg9K/+4=
48 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 0 iD8DBQBO1/fWywK+sNU5EO8RAmoPAKCR5lpv1D6JLURHD8KVLSV4GRVEBgCgnd0Sy78ligNfqAMafmACRDvj7vo=
48 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 0 iD8DBQBO1/fWywK+sNU5EO8RAmoPAKCR5lpv1D6JLURHD8KVLSV4GRVEBgCgnd0Sy78ligNfqAMafmACRDvj7vo=
49 6344043924497cd06d781d9014c66802285072e4 0 iD8DBQBPALgmywK+sNU5EO8RAlfhAJ9nYOdWnhfVDHYtDTJAyJtXBAQS9wCgnefoSQt7QABkbGxM+Q85UYEBuD0=
49 6344043924497cd06d781d9014c66802285072e4 0 iD8DBQBPALgmywK+sNU5EO8RAlfhAJ9nYOdWnhfVDHYtDTJAyJtXBAQS9wCgnefoSQt7QABkbGxM+Q85UYEBuD0=
50 db33555eafeaf9df1e18950e29439eaa706d399b 0 iD8DBQBPGdzxywK+sNU5EO8RAppkAJ9jOXhUVE/97CPgiMA0pMGiIYnesQCfengAszcBiSiKGugiI8Okc9ghU+Y=
50 db33555eafeaf9df1e18950e29439eaa706d399b 0 iD8DBQBPGdzxywK+sNU5EO8RAppkAJ9jOXhUVE/97CPgiMA0pMGiIYnesQCfengAszcBiSiKGugiI8Okc9ghU+Y=
51 2aa5b51f310fb3befd26bed99c02267f5c12c734 0 iD8DBQBPKZ9bywK+sNU5EO8RAt1TAJ45r1eJ0YqSkInzrrayg4TVCh0SnQCgm0GA/Ua74jnnDwVQ60lAwROuz1Q=
51 2aa5b51f310fb3befd26bed99c02267f5c12c734 0 iD8DBQBPKZ9bywK+sNU5EO8RAt1TAJ45r1eJ0YqSkInzrrayg4TVCh0SnQCgm0GA/Ua74jnnDwVQ60lAwROuz1Q=
52 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 0 iD8DBQBPT/fvywK+sNU5EO8RAnfYAKCn7d0vwqIb100YfWm1F7nFD5B+FACeM02YHpQLSNsztrBCObtqcnfod7Q=
52 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 0 iD8DBQBPT/fvywK+sNU5EO8RAnfYAKCn7d0vwqIb100YfWm1F7nFD5B+FACeM02YHpQLSNsztrBCObtqcnfod7Q=
53 b9bd95e61b49c221c4cca24e6da7c946fc02f992 0 iD8DBQBPeLsIywK+sNU5EO8RAvpNAKCtKe2gitz8dYn52IRF0hFOPCR7AQCfRJL/RWCFweu2T1vH/mUOCf8SXXc=
53 b9bd95e61b49c221c4cca24e6da7c946fc02f992 0 iD8DBQBPeLsIywK+sNU5EO8RAvpNAKCtKe2gitz8dYn52IRF0hFOPCR7AQCfRJL/RWCFweu2T1vH/mUOCf8SXXc=
54 d9e2f09d5488c395ae9ddbb320ceacd24757e055 0 iD8DBQBPju/dywK+sNU5EO8RArBYAJ9xtifdbk+hCOJO8OZa4JfHX8OYZQCeKPMBaBWiT8N/WHoOm1XU0q+iono=
54 d9e2f09d5488c395ae9ddbb320ceacd24757e055 0 iD8DBQBPju/dywK+sNU5EO8RArBYAJ9xtifdbk+hCOJO8OZa4JfHX8OYZQCeKPMBaBWiT8N/WHoOm1XU0q+iono=
55 00182b3d087909e3c3ae44761efecdde8f319ef3 0 iD8DBQBPoFhIywK+sNU5EO8RAhzhAKCBj1n2jxPTkZNJJ5pSp3soa+XHIgCgsZZpAQxOpXwCp0eCdNGe0+pmxmg=
55 00182b3d087909e3c3ae44761efecdde8f319ef3 0 iD8DBQBPoFhIywK+sNU5EO8RAhzhAKCBj1n2jxPTkZNJJ5pSp3soa+XHIgCgsZZpAQxOpXwCp0eCdNGe0+pmxmg=
56 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 0 iD8DBQBPovNWywK+sNU5EO8RAhgiAJ980T91FdPTRMmVONDhpkMsZwVIMACgg3bKvoWSeuCW28llUhAJtUjrMv0=
56 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 0 iD8DBQBPovNWywK+sNU5EO8RAhgiAJ980T91FdPTRMmVONDhpkMsZwVIMACgg3bKvoWSeuCW28llUhAJtUjrMv0=
57 85a358df5bbbe404ca25730c9c459b34263441dc 0 iD8DBQBPyZsWywK+sNU5EO8RAnpLAJ48qrGDJRT+pteS0mSQ11haqHstPwCdG4ccGbk+0JHb7aNy8/NRGAOqn9w=
57 85a358df5bbbe404ca25730c9c459b34263441dc 0 iD8DBQBPyZsWywK+sNU5EO8RAnpLAJ48qrGDJRT+pteS0mSQ11haqHstPwCdG4ccGbk+0JHb7aNy8/NRGAOqn9w=
58 b013baa3898e117959984fc64c29d8c784d2f28b 0 iD8DBQBP8QOPywK+sNU5EO8RAqimAKCFRSx0lvG6y8vne2IhNG062Hn0dACeMLI5/zhpWpHBIVeAAquYfx2XFeA=
58 b013baa3898e117959984fc64c29d8c784d2f28b 0 iD8DBQBP8QOPywK+sNU5EO8RAqimAKCFRSx0lvG6y8vne2IhNG062Hn0dACeMLI5/zhpWpHBIVeAAquYfx2XFeA=
59 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 0 iD8DBQBQGiL8ywK+sNU5EO8RAq5oAJ4rMMCPx6O+OuzNXVOexogedWz/QgCeIiIxLd76I4pXO48tdXhr0hQcBuM=
59 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 0 iD8DBQBQGiL8ywK+sNU5EO8RAq5oAJ4rMMCPx6O+OuzNXVOexogedWz/QgCeIiIxLd76I4pXO48tdXhr0hQcBuM=
60 072209ae4ddb654eb2d5fd35bff358c738414432 0 iD8DBQBQQkq0ywK+sNU5EO8RArDTAJ9nk5CySnNAjAXYvqvx4uWCw9ThZwCgqmFRehH/l+oTwj3f8nw8u8qTCdc=
60 072209ae4ddb654eb2d5fd35bff358c738414432 0 iD8DBQBQQkq0ywK+sNU5EO8RArDTAJ9nk5CySnNAjAXYvqvx4uWCw9ThZwCgqmFRehH/l+oTwj3f8nw8u8qTCdc=
61 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 0 iD8DBQBQamltywK+sNU5EO8RAlsqAJ4qF/m6aFu4mJCOKTiAP5RvZFK02ACfawYShUZO6OXEFfveU0aAxDR0M1k=
61 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 0 iD8DBQBQamltywK+sNU5EO8RAlsqAJ4qF/m6aFu4mJCOKTiAP5RvZFK02ACfawYShUZO6OXEFfveU0aAxDR0M1k=
62 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 0 iD8DBQBQgPV5ywK+sNU5EO8RArylAJ0abcx5NlDjyv3ZDWpAfRIHyRsJtQCgn4TMuEayqgxzrvadQZHdTEU2g38=
62 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 0 iD8DBQBQgPV5ywK+sNU5EO8RArylAJ0abcx5NlDjyv3ZDWpAfRIHyRsJtQCgn4TMuEayqgxzrvadQZHdTEU2g38=
63 195ad823b5d58c68903a6153a25e3fb4ed25239d 0 iD8DBQBQkuT9ywK+sNU5EO8RAhB4AKCeerItoK2Jipm2cVf4euGofAa/WACeJj3TVd4pFILpb+ogj7ebweFLJi0=
63 195ad823b5d58c68903a6153a25e3fb4ed25239d 0 iD8DBQBQkuT9ywK+sNU5EO8RAhB4AKCeerItoK2Jipm2cVf4euGofAa/WACeJj3TVd4pFILpb+ogj7ebweFLJi0=
64 0c10cf8191469e7c3c8844922e17e71a176cb7cb 0 iD8DBQBQvQWoywK+sNU5EO8RAnq3AJoCn98u4geFx5YaQaeh99gFhCd7bQCgjoBwBSUyOvGd0yBy60E3Vv3VZhM=
64 0c10cf8191469e7c3c8844922e17e71a176cb7cb 0 iD8DBQBQvQWoywK+sNU5EO8RAnq3AJoCn98u4geFx5YaQaeh99gFhCd7bQCgjoBwBSUyOvGd0yBy60E3Vv3VZhM=
65 a4765077b65e6ae29ba42bab7834717b5072d5ba 0 iD8DBQBQ486sywK+sNU5EO8RAhmJAJ90aLfLKZhmcZN7kqphigQJxiFOQACeJ5IUZxjGKH4xzi3MrgIcx9n+dB0=
65 a4765077b65e6ae29ba42bab7834717b5072d5ba 0 iD8DBQBQ486sywK+sNU5EO8RAhmJAJ90aLfLKZhmcZN7kqphigQJxiFOQACeJ5IUZxjGKH4xzi3MrgIcx9n+dB0=
66 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 0 iD8DBQBQ+yuYywK+sNU5EO8RAm9JAJoD/UciWvpGeKBcpGtZJBFJVcL/HACghDXSgQ+xQDjB+6uGrdgAQsRR1Lg=
66 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 0 iD8DBQBQ+yuYywK+sNU5EO8RAm9JAJoD/UciWvpGeKBcpGtZJBFJVcL/HACghDXSgQ+xQDjB+6uGrdgAQsRR1Lg=
67 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 0 iD8DBQBRDDROywK+sNU5EO8RAh75AJ9uJCGoCWnP0Lv/+XuYs4hvUl+sAgCcD36QgAnuw8IQXrvv684BAXAnHcA=
67 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 0 iD8DBQBRDDROywK+sNU5EO8RAh75AJ9uJCGoCWnP0Lv/+XuYs4hvUl+sAgCcD36QgAnuw8IQXrvv684BAXAnHcA=
68 7511d4df752e61fe7ae4f3682e0a0008573b0402 0 iD8DBQBRFYaoywK+sNU5EO8RAuErAJoDyhXn+lptU3+AevVdwAIeNFyR2gCdHzPHyWd+JDeWCUR+pSOBi8O2ppM=
68 7511d4df752e61fe7ae4f3682e0a0008573b0402 0 iD8DBQBRFYaoywK+sNU5EO8RAuErAJoDyhXn+lptU3+AevVdwAIeNFyR2gCdHzPHyWd+JDeWCUR+pSOBi8O2ppM=
69 5b7175377babacce80a6c1e12366d8032a6d4340 0 iD8DBQBRMCYgywK+sNU5EO8RAq1/AKCWKlt9ysibyQgYwoxxIOZv5J8rpwCcDSHQaaf1fFZUTnQsOePwcM2Y/Sg=
69 5b7175377babacce80a6c1e12366d8032a6d4340 0 iD8DBQBRMCYgywK+sNU5EO8RAq1/AKCWKlt9ysibyQgYwoxxIOZv5J8rpwCcDSHQaaf1fFZUTnQsOePwcM2Y/Sg=
70 50c922c1b5145dab8baefefb0437d363b6a6c21c 0 iD8DBQBRWnUnywK+sNU5EO8RAuQRAJwM42cJqJPeqJ0jVNdMqKMDqr4dSACeP0cRVGz1gitMuV0x8f3mrZrqc7I=
70 50c922c1b5145dab8baefefb0437d363b6a6c21c 0 iD8DBQBRWnUnywK+sNU5EO8RAuQRAJwM42cJqJPeqJ0jVNdMqKMDqr4dSACeP0cRVGz1gitMuV0x8f3mrZrqc7I=
71 8a7bd2dccd44ed571afe7424cd7f95594f27c092 0 iD8DBQBRXfBvywK+sNU5EO8RAn+LAKCsMmflbuXjYRxlzFwId5ptm8TZcwCdGkyLbZcASBOkzQUm/WW1qfknJHU=
71 8a7bd2dccd44ed571afe7424cd7f95594f27c092 0 iD8DBQBRXfBvywK+sNU5EO8RAn+LAKCsMmflbuXjYRxlzFwId5ptm8TZcwCdGkyLbZcASBOkzQUm/WW1qfknJHU=
72 292cd385856d98bacb2c3086f8897bc660c2beea 0 iD8DBQBRcM0BywK+sNU5EO8RAjp4AKCJBykQbvXhKuvLSMxKx3a2TBiXcACfbr/kLg5GlZTF/XDPmY+PyHgI/GM=
72 292cd385856d98bacb2c3086f8897bc660c2beea 0 iD8DBQBRcM0BywK+sNU5EO8RAjp4AKCJBykQbvXhKuvLSMxKx3a2TBiXcACfbr/kLg5GlZTF/XDPmY+PyHgI/GM=
73 23f785b38af38d2fca6b8f3db56b8007a84cd73a 0 iD8DBQBRgZwNywK+sNU5EO8RAmO4AJ4u2ILGuimRP6MJgE2t65LZ5dAdkACgiENEstIdrlFC80p+sWKD81kKIYI=
73 23f785b38af38d2fca6b8f3db56b8007a84cd73a 0 iD8DBQBRgZwNywK+sNU5EO8RAmO4AJ4u2ILGuimRP6MJgE2t65LZ5dAdkACgiENEstIdrlFC80p+sWKD81kKIYI=
74 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 0 iD8DBQBRkswvywK+sNU5EO8RAiYYAJsHTHyHbJeAgmGvBTmDrfcKu4doUgCeLm7eGBjx7yAPUvEtxef8rAkQmXI=
74 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 0 iD8DBQBRkswvywK+sNU5EO8RAiYYAJsHTHyHbJeAgmGvBTmDrfcKu4doUgCeLm7eGBjx7yAPUvEtxef8rAkQmXI=
75 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 0 iD8DBQBRqnFLywK+sNU5EO8RAsWNAJ9RR6t+y1DLFc2HeH0eN9VfZAKF9gCeJ8ezvhtKq/LMs0/nvcgKQc/d5jk=
75 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 0 iD8DBQBRqnFLywK+sNU5EO8RAsWNAJ9RR6t+y1DLFc2HeH0eN9VfZAKF9gCeJ8ezvhtKq/LMs0/nvcgKQc/d5jk=
76 009794acc6e37a650f0fae37872e733382ac1c0c 0 iD8DBQBR0guxywK+sNU5EO8RArNkAKCq9pMihVzP8Os5kCmgbWpe5C37wgCgqzuPZTHvAsXF5wTyaSTMVa9Ccq4=
76 009794acc6e37a650f0fae37872e733382ac1c0c 0 iD8DBQBR0guxywK+sNU5EO8RArNkAKCq9pMihVzP8Os5kCmgbWpe5C37wgCgqzuPZTHvAsXF5wTyaSTMVa9Ccq4=
77 f0d7721d7322dcfb5af33599c2543f27335334bb 0 iD8DBQBR8taaywK+sNU5EO8RAqeEAJ4idDhhDuEsgsUjeQgWNj498matHACfT67gSF5w0ylsrBx1Hb52HkGXDm0=
77 f0d7721d7322dcfb5af33599c2543f27335334bb 0 iD8DBQBR8taaywK+sNU5EO8RAqeEAJ4idDhhDuEsgsUjeQgWNj498matHACfT67gSF5w0ylsrBx1Hb52HkGXDm0=
78 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 0 iD8DBQBR+ymFywK+sNU5EO8RAuSdAJkBMcd9DAZ3rWE9WGKPm2YZ8LBoXACfXn/wbEsVy7ZgJoUwiWmHSnQaWCI=
78 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 0 iD8DBQBR+ymFywK+sNU5EO8RAuSdAJkBMcd9DAZ3rWE9WGKPm2YZ8LBoXACfXn/wbEsVy7ZgJoUwiWmHSnQaWCI=
79 335a558f81dc73afeab4d7be63617392b130117f 0 iQIVAwUAUiZrIyBXgaxoKi1yAQK2iw//cquNqqSkc8Re5/TZT9I6NH+lh6DbOKjJP0Xl1Wqq0K+KSIUgZG4G32ovaEb2l5X0uY+3unRPiZ0ebl0YSw4Fb2ZiPIADXLBTOYRrY2Wwd3tpJeGI6wEgZt3SfcITV/g7NJrCjT3FlYoSOIayrExM80InSdcEM0Q3Rx6HKzY2acyxzgZeAtAW5ohFvHilSvY6p5Gcm4+QptMxvw45GPdreUmjeXZxNXNXZ8P+MjMz/QJbai/N7PjmK8lqnhkBsT48Ng/KhhmOkGntNJ2/ImBWLFGcWngSvJ7sfWwnyhndvGhe0Hq1NcCf7I8TjNDxU5TR+m+uW7xjXdLoDbUjBdX4sKXnh8ZjbYiODKBOrrDq25cf8nA/tnpKyE/qsVy60kOk6loY4XKiYmn1V49Ta0emmDx0hqo3HgxHHsHX0NDnGdWGol7cPRET0RzVobKq1A0jnrhPooWidvLh9bPzLonrWDo+ib+DuySoRkuYUK4pgZJ2mbg6daFOBEZygkSyRB8bo1UQUP7EgQDrWe4khb/5GHEfDkrQz3qu/sXvc0Ir1mOUWBFPHC2DjjCn/oMJuUkG1SwM8l2Bfv7h67ssES6YQ2+RjOix4yid7EXS/Ogl45PzCIPSI5+BbNs10JhE0w5uErBHlF53EDTe/TSLc+GU6DB6PP6dH912Njdr3jpNSUQ=
79 335a558f81dc73afeab4d7be63617392b130117f 0 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
@@ -1,206 +1,207 b''
1 d40cc5aacc31ed673d9b5b24f98bee78c283062c 0.4f
1 d40cc5aacc31ed673d9b5b24f98bee78c283062c 0.4f
2 1c590d34bf61e2ea12c71738e5a746cd74586157 0.4e
2 1c590d34bf61e2ea12c71738e5a746cd74586157 0.4e
3 7eca4cfa8aad5fce9a04f7d8acadcd0452e2f34e 0.4d
3 7eca4cfa8aad5fce9a04f7d8acadcd0452e2f34e 0.4d
4 b4d0c3786ad3e47beacf8412157326a32b6d25a4 0.4c
4 b4d0c3786ad3e47beacf8412157326a32b6d25a4 0.4c
5 f40273b0ad7b3a6d3012fd37736d0611f41ecf54 0.5
5 f40273b0ad7b3a6d3012fd37736d0611f41ecf54 0.5
6 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b
6 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b
7 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6
7 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6
8 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
8 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
9 eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
9 eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
10 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7
10 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7
11 3a56574f329a368d645853e0f9e09472aee62349 0.8
11 3a56574f329a368d645853e0f9e09472aee62349 0.8
12 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1
12 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1
13 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9
13 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9
14 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1
14 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1
15 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2
15 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2
16 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3
16 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3
17 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4
17 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4
18 23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5
18 23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5
19 bae2e9c838e90a393bae3973a7850280413e091a 1.0
19 bae2e9c838e90a393bae3973a7850280413e091a 1.0
20 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 1.0.1
20 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 1.0.1
21 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 1.0.2
21 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 1.0.2
22 2a67430f92f15ea5159c26b09ec4839a0c549a26 1.1
22 2a67430f92f15ea5159c26b09ec4839a0c549a26 1.1
23 3773e510d433969e277b1863c317b674cbee2065 1.1.1
23 3773e510d433969e277b1863c317b674cbee2065 1.1.1
24 11a4eb81fb4f4742451591489e2797dc47903277 1.1.2
24 11a4eb81fb4f4742451591489e2797dc47903277 1.1.2
25 11efa41037e280d08cfb07c09ad485df30fb0ea8 1.2
25 11efa41037e280d08cfb07c09ad485df30fb0ea8 1.2
26 02981000012e3adf40c4849bd7b3d5618f9ce82d 1.2.1
26 02981000012e3adf40c4849bd7b3d5618f9ce82d 1.2.1
27 196d40e7c885fa6e95f89134809b3ec7bdbca34b 1.3
27 196d40e7c885fa6e95f89134809b3ec7bdbca34b 1.3
28 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 1.3.1
28 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 1.3.1
29 31ec469f9b556f11819937cf68ee53f2be927ebf 1.4
29 31ec469f9b556f11819937cf68ee53f2be927ebf 1.4
30 439d7ea6fe3aa4ab9ec274a68846779153789de9 1.4.1
30 439d7ea6fe3aa4ab9ec274a68846779153789de9 1.4.1
31 296a0b14a68621f6990c54fdba0083f6f20935bf 1.4.2
31 296a0b14a68621f6990c54fdba0083f6f20935bf 1.4.2
32 4aa619c4c2c09907034d9824ebb1dd0e878206eb 1.4.3
32 4aa619c4c2c09907034d9824ebb1dd0e878206eb 1.4.3
33 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 1.5
33 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 1.5
34 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 1.5.1
34 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 1.5.1
35 39f725929f0c48c5fb3b90c071fc3066012456ca 1.5.2
35 39f725929f0c48c5fb3b90c071fc3066012456ca 1.5.2
36 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 1.5.3
36 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 1.5.3
37 24fe2629c6fd0c74c90bd066e77387c2b02e8437 1.5.4
37 24fe2629c6fd0c74c90bd066e77387c2b02e8437 1.5.4
38 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 1.6
38 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 1.6
39 bf1774d95bde614af3956d92b20e2a0c68c5fec7 1.6.1
39 bf1774d95bde614af3956d92b20e2a0c68c5fec7 1.6.1
40 c00f03a4982e467fb6b6bd45908767db6df4771d 1.6.2
40 c00f03a4982e467fb6b6bd45908767db6df4771d 1.6.2
41 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 1.6.3
41 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 1.6.3
42 93d8bff78c96fe7e33237b257558ee97290048a4 1.6.4
42 93d8bff78c96fe7e33237b257558ee97290048a4 1.6.4
43 333421b9e0f96c7bc788e5667c146a58a9440a55 1.7
43 333421b9e0f96c7bc788e5667c146a58a9440a55 1.7
44 4438875ec01bd0fc32be92b0872eb6daeed4d44f 1.7.1
44 4438875ec01bd0fc32be92b0872eb6daeed4d44f 1.7.1
45 6aff4f144ad356311318b0011df0bb21f2c97429 1.7.2
45 6aff4f144ad356311318b0011df0bb21f2c97429 1.7.2
46 e3bf16703e2601de99e563cdb3a5d50b64e6d320 1.7.3
46 e3bf16703e2601de99e563cdb3a5d50b64e6d320 1.7.3
47 a6c855c32ea081da3c3b8ff628f1847ff271482f 1.7.4
47 a6c855c32ea081da3c3b8ff628f1847ff271482f 1.7.4
48 2b2155623ee2559caf288fd333f30475966c4525 1.7.5
48 2b2155623ee2559caf288fd333f30475966c4525 1.7.5
49 2616325766e3504c8ae7c84bd15ee610901fe91d 1.8
49 2616325766e3504c8ae7c84bd15ee610901fe91d 1.8
50 aa1f3be38ab127280761889d2dca906ca465b5f4 1.8.1
50 aa1f3be38ab127280761889d2dca906ca465b5f4 1.8.1
51 b032bec2c0a651ca0ddecb65714bfe6770f67d70 1.8.2
51 b032bec2c0a651ca0ddecb65714bfe6770f67d70 1.8.2
52 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3
52 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3
53 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4
53 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4
54 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9
54 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9
55 4a43e23b8c55b4566b8200bf69fe2158485a2634 1.9.1
55 4a43e23b8c55b4566b8200bf69fe2158485a2634 1.9.1
56 d629f1e89021103f1753addcef6b310e4435b184 1.9.2
56 d629f1e89021103f1753addcef6b310e4435b184 1.9.2
57 351a9292e430e35766c552066ed3e87c557b803b 1.9.3
57 351a9292e430e35766c552066ed3e87c557b803b 1.9.3
58 384082750f2c51dc917d85a7145748330fa6ef4d 2.0-rc
58 384082750f2c51dc917d85a7145748330fa6ef4d 2.0-rc
59 41453d55b481ddfcc1dacb445179649e24ca861d 2.0
59 41453d55b481ddfcc1dacb445179649e24ca861d 2.0
60 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 2.0.1
60 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 2.0.1
61 6344043924497cd06d781d9014c66802285072e4 2.0.2
61 6344043924497cd06d781d9014c66802285072e4 2.0.2
62 db33555eafeaf9df1e18950e29439eaa706d399b 2.1-rc
62 db33555eafeaf9df1e18950e29439eaa706d399b 2.1-rc
63 2aa5b51f310fb3befd26bed99c02267f5c12c734 2.1
63 2aa5b51f310fb3befd26bed99c02267f5c12c734 2.1
64 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 2.1.1
64 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 2.1.1
65 b9bd95e61b49c221c4cca24e6da7c946fc02f992 2.1.2
65 b9bd95e61b49c221c4cca24e6da7c946fc02f992 2.1.2
66 d9e2f09d5488c395ae9ddbb320ceacd24757e055 2.2-rc
66 d9e2f09d5488c395ae9ddbb320ceacd24757e055 2.2-rc
67 00182b3d087909e3c3ae44761efecdde8f319ef3 2.2
67 00182b3d087909e3c3ae44761efecdde8f319ef3 2.2
68 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 2.2.1
68 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 2.2.1
69 85a358df5bbbe404ca25730c9c459b34263441dc 2.2.2
69 85a358df5bbbe404ca25730c9c459b34263441dc 2.2.2
70 b013baa3898e117959984fc64c29d8c784d2f28b 2.2.3
70 b013baa3898e117959984fc64c29d8c784d2f28b 2.2.3
71 a06e2681dd1786e2354d84a5fa9c1c88dd4fa3e0 2.3-rc
71 a06e2681dd1786e2354d84a5fa9c1c88dd4fa3e0 2.3-rc
72 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 2.3
72 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 2.3
73 072209ae4ddb654eb2d5fd35bff358c738414432 2.3.1
73 072209ae4ddb654eb2d5fd35bff358c738414432 2.3.1
74 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 2.3.2
74 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 2.3.2
75 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 2.4-rc
75 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 2.4-rc
76 195ad823b5d58c68903a6153a25e3fb4ed25239d 2.4
76 195ad823b5d58c68903a6153a25e3fb4ed25239d 2.4
77 0c10cf8191469e7c3c8844922e17e71a176cb7cb 2.4.1
77 0c10cf8191469e7c3c8844922e17e71a176cb7cb 2.4.1
78 a4765077b65e6ae29ba42bab7834717b5072d5ba 2.4.2
78 a4765077b65e6ae29ba42bab7834717b5072d5ba 2.4.2
79 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 2.5-rc
79 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 2.5-rc
80 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 2.5
80 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 2.5
81 7511d4df752e61fe7ae4f3682e0a0008573b0402 2.5.1
81 7511d4df752e61fe7ae4f3682e0a0008573b0402 2.5.1
82 5b7175377babacce80a6c1e12366d8032a6d4340 2.5.2
82 5b7175377babacce80a6c1e12366d8032a6d4340 2.5.2
83 50c922c1b5145dab8baefefb0437d363b6a6c21c 2.5.3
83 50c922c1b5145dab8baefefb0437d363b6a6c21c 2.5.3
84 8a7bd2dccd44ed571afe7424cd7f95594f27c092 2.5.4
84 8a7bd2dccd44ed571afe7424cd7f95594f27c092 2.5.4
85 292cd385856d98bacb2c3086f8897bc660c2beea 2.6-rc
85 292cd385856d98bacb2c3086f8897bc660c2beea 2.6-rc
86 23f785b38af38d2fca6b8f3db56b8007a84cd73a 2.6
86 23f785b38af38d2fca6b8f3db56b8007a84cd73a 2.6
87 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 2.6.1
87 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 2.6.1
88 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 2.6.2
88 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 2.6.2
89 009794acc6e37a650f0fae37872e733382ac1c0c 2.6.3
89 009794acc6e37a650f0fae37872e733382ac1c0c 2.6.3
90 f0d7721d7322dcfb5af33599c2543f27335334bb 2.7-rc
90 f0d7721d7322dcfb5af33599c2543f27335334bb 2.7-rc
91 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 2.7
91 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 2.7
92 335a558f81dc73afeab4d7be63617392b130117f 2.7.1
92 335a558f81dc73afeab4d7be63617392b130117f 2.7.1
93 e7fa36d2ad3a7944a52dca126458d6f482db3524 2.7.2
93 e7fa36d2ad3a7944a52dca126458d6f482db3524 2.7.2
94 1596f2d8f2421314b1ddead8f7d0c91009358994 2.8-rc
94 1596f2d8f2421314b1ddead8f7d0c91009358994 2.8-rc
95 d825e4025e39d1c39db943cdc89818abd0a87c27 2.8
95 d825e4025e39d1c39db943cdc89818abd0a87c27 2.8
96 209e04a06467e2969c0cc6501335be0406d46ef0 2.8.1
96 209e04a06467e2969c0cc6501335be0406d46ef0 2.8.1
97 ca387377df7a3a67dbb90b6336b781cdadc3ef41 2.8.2
97 ca387377df7a3a67dbb90b6336b781cdadc3ef41 2.8.2
98 8862469e16f9236208581b20de5f96bd13cc039d 2.9-rc
98 8862469e16f9236208581b20de5f96bd13cc039d 2.9-rc
99 3cec5134e9c4bceab6a00c60f52a4f80677a78f2 2.9
99 3cec5134e9c4bceab6a00c60f52a4f80677a78f2 2.9
100 b96cb15ec9e04d8ac5ee08b34fcbbe4200588965 2.9.1
100 b96cb15ec9e04d8ac5ee08b34fcbbe4200588965 2.9.1
101 3f83fc5cfe715d292069ee8417c83804f6c6c1e4 2.9.2
101 3f83fc5cfe715d292069ee8417c83804f6c6c1e4 2.9.2
102 564f55b251224f16508dd1311452db7780dafe2b 3.0-rc
102 564f55b251224f16508dd1311452db7780dafe2b 3.0-rc
103 2195ac506c6ababe86985b932f4948837c0891b5 3.0
103 2195ac506c6ababe86985b932f4948837c0891b5 3.0
104 269c80ee5b3cb3684fa8edc61501b3506d02eb10 3.0.1
104 269c80ee5b3cb3684fa8edc61501b3506d02eb10 3.0.1
105 2d8cd3d0e83c7336c0cb45a9f88638363f993848 3.0.2
105 2d8cd3d0e83c7336c0cb45a9f88638363f993848 3.0.2
106 6c36dc6cd61a0e1b563f1d51e55bdf4dacf12162 3.1-rc
106 6c36dc6cd61a0e1b563f1d51e55bdf4dacf12162 3.1-rc
107 3178e49892020336491cdc6945885c4de26ffa8b 3.1
107 3178e49892020336491cdc6945885c4de26ffa8b 3.1
108 5dc91146f35369949ea56b40172308158b59063a 3.1.1
108 5dc91146f35369949ea56b40172308158b59063a 3.1.1
109 f768c888aaa68d12dd7f509dcc7f01c9584357d0 3.1.2
109 f768c888aaa68d12dd7f509dcc7f01c9584357d0 3.1.2
110 7f8d16af8cae246fa5a48e723d48d58b015aed94 3.2-rc
110 7f8d16af8cae246fa5a48e723d48d58b015aed94 3.2-rc
111 ced632394371a36953ce4d394f86278ae51a2aae 3.2
111 ced632394371a36953ce4d394f86278ae51a2aae 3.2
112 643c58303fb0ec020907af28b9e486be299ba043 3.2.1
112 643c58303fb0ec020907af28b9e486be299ba043 3.2.1
113 902554884335e5ca3661d63be9978eb4aec3f68a 3.2.2
113 902554884335e5ca3661d63be9978eb4aec3f68a 3.2.2
114 6dad422ecc5adb63d9fa649eeb8e05a5f9bc4900 3.2.3
114 6dad422ecc5adb63d9fa649eeb8e05a5f9bc4900 3.2.3
115 1265a3a71d75396f5d4cf6935ae7d9ba5407a547 3.2.4
115 1265a3a71d75396f5d4cf6935ae7d9ba5407a547 3.2.4
116 db8e3f7948b1fdeb9ad12d448fc3525759908b9f 3.3-rc
116 db8e3f7948b1fdeb9ad12d448fc3525759908b9f 3.3-rc
117 fbdd5195528fae4f41feebc1838215c110b25d6a 3.3
117 fbdd5195528fae4f41feebc1838215c110b25d6a 3.3
118 5b4ed033390bf6e2879c8f5c28c84e1ee3b87231 3.3.1
118 5b4ed033390bf6e2879c8f5c28c84e1ee3b87231 3.3.1
119 07a92bbd02e5e3a625e0820389b47786b02b2cea 3.3.2
119 07a92bbd02e5e3a625e0820389b47786b02b2cea 3.3.2
120 2e2e9a0750f91a6fe0ad88e4de34f8efefdcab08 3.3.3
120 2e2e9a0750f91a6fe0ad88e4de34f8efefdcab08 3.3.3
121 e89f909edffad558b56f4affa8239e4832f88de0 3.4-rc
121 e89f909edffad558b56f4affa8239e4832f88de0 3.4-rc
122 8cc6036bca532e06681c5a8fa37efaa812de67b5 3.4
122 8cc6036bca532e06681c5a8fa37efaa812de67b5 3.4
123 ed18f4acf435a2824c6f49fba40f42b9df5da7ad 3.4.1
123 ed18f4acf435a2824c6f49fba40f42b9df5da7ad 3.4.1
124 540cd0ddac49c1125b2e013aa2ff18ecbd4dd954 3.4.2
124 540cd0ddac49c1125b2e013aa2ff18ecbd4dd954 3.4.2
125 96a38d44ba093bd1d1ecfd34119e94056030278b 3.5-rc
125 96a38d44ba093bd1d1ecfd34119e94056030278b 3.5-rc
126 21aa1c313b05b1a85f8ffa1120d51579ddf6bf24 3.5
126 21aa1c313b05b1a85f8ffa1120d51579ddf6bf24 3.5
127 1a45e49a6bed023deb229102a8903234d18054d3 3.5.1
127 1a45e49a6bed023deb229102a8903234d18054d3 3.5.1
128 9a466b9f9792e3ad7ae3fc6c43c3ff2e136b718d 3.5.2
128 9a466b9f9792e3ad7ae3fc6c43c3ff2e136b718d 3.5.2
129 b66e3ca0b90c3095ea28dfd39aa24247bebf5c20 3.6-rc
129 b66e3ca0b90c3095ea28dfd39aa24247bebf5c20 3.6-rc
130 47dd34f2e7272be9e3b2a5a83cd0d20be44293f4 3.6
130 47dd34f2e7272be9e3b2a5a83cd0d20be44293f4 3.6
131 1aa5083cbebbe7575c88f3402ab377539b484897 3.6.1
131 1aa5083cbebbe7575c88f3402ab377539b484897 3.6.1
132 2d437a0f3355834a9485bbbeb30a52a052c98f19 3.6.2
132 2d437a0f3355834a9485bbbeb30a52a052c98f19 3.6.2
133 ea389970c08449440587712117f178d33bab3f1e 3.6.3
133 ea389970c08449440587712117f178d33bab3f1e 3.6.3
134 158bdc8965720ca4061f8f8d806563cfc7cdb62e 3.7-rc
134 158bdc8965720ca4061f8f8d806563cfc7cdb62e 3.7-rc
135 2408645de650d8a29a6ce9e7dce601d8dd0d1474 3.7
135 2408645de650d8a29a6ce9e7dce601d8dd0d1474 3.7
136 b698abf971e7377d9b7ec7fc8c52df45255b0329 3.7.1
136 b698abf971e7377d9b7ec7fc8c52df45255b0329 3.7.1
137 d493d64757eb45ada99fcb3693e479a51b7782da 3.7.2
137 d493d64757eb45ada99fcb3693e479a51b7782da 3.7.2
138 ae279d4a19e9683214cbd1fe8298cf0b50571432 3.7.3
138 ae279d4a19e9683214cbd1fe8298cf0b50571432 3.7.3
139 740156eedf2c450aee58b1a90b0e826f47c5da64 3.8-rc
139 740156eedf2c450aee58b1a90b0e826f47c5da64 3.8-rc
140 f85de28eae32e7d3064b1a1321309071bbaaa069 3.8
140 f85de28eae32e7d3064b1a1321309071bbaaa069 3.8
141 a56296f55a5e1038ea5016dace2076b693c28a56 3.8.1
141 a56296f55a5e1038ea5016dace2076b693c28a56 3.8.1
142 aaabed77791a75968a12b8c43ad263631a23ee81 3.8.2
142 aaabed77791a75968a12b8c43ad263631a23ee81 3.8.2
143 a9764ab80e11bcf6a37255db7dd079011f767c6c 3.8.3
143 a9764ab80e11bcf6a37255db7dd079011f767c6c 3.8.3
144 26a5d605b8683a292bb89aea11f37a81b06ac016 3.8.4
144 26a5d605b8683a292bb89aea11f37a81b06ac016 3.8.4
145 519bb4f9d3a47a6e83c2b414d58811ed38f503c2 3.9-rc
145 519bb4f9d3a47a6e83c2b414d58811ed38f503c2 3.9-rc
146 299546f84e68dbb9bd026f0f3a974ce4bdb93686 3.9
146 299546f84e68dbb9bd026f0f3a974ce4bdb93686 3.9
147 ccd436f7db6d5d7b9af89715179b911d031d44f1 3.9.1
147 ccd436f7db6d5d7b9af89715179b911d031d44f1 3.9.1
148 149433e68974eb5c63ccb03f794d8b57339a80c4 3.9.2
148 149433e68974eb5c63ccb03f794d8b57339a80c4 3.9.2
149 438173c415874f6ac653efc1099dec9c9150e90f 4.0-rc
149 438173c415874f6ac653efc1099dec9c9150e90f 4.0-rc
150 eab27446995210c334c3d06f1a659e3b9b5da769 4.0
150 eab27446995210c334c3d06f1a659e3b9b5da769 4.0
151 b3b1ae98f6a0e14c1e1ba806a6c18e193b6dae5c 4.0.1
151 b3b1ae98f6a0e14c1e1ba806a6c18e193b6dae5c 4.0.1
152 e69874dc1f4e142746ff3df91e678a09c6fc208c 4.0.2
152 e69874dc1f4e142746ff3df91e678a09c6fc208c 4.0.2
153 a1dd2c0c479e0550040542e392e87bc91262517e 4.1-rc
153 a1dd2c0c479e0550040542e392e87bc91262517e 4.1-rc
154 e1526da1e6d84e03146151c9b6e6950fe9a83d7d 4.1
154 e1526da1e6d84e03146151c9b6e6950fe9a83d7d 4.1
155 25703b624d27e3917d978af56d6ad59331e0464a 4.1.1
155 25703b624d27e3917d978af56d6ad59331e0464a 4.1.1
156 ed5b25874d998ababb181a939dd37a16ea644435 4.1.2
156 ed5b25874d998ababb181a939dd37a16ea644435 4.1.2
157 77eaf9539499a1b8be259ffe7ada787d07857f80 4.1.3
157 77eaf9539499a1b8be259ffe7ada787d07857f80 4.1.3
158 616e788321cc4ae9975b7f0c54c849f36d82182b 4.2-rc
158 616e788321cc4ae9975b7f0c54c849f36d82182b 4.2-rc
159 bb96d4a497432722623ae60d9bc734a1e360179e 4.2
159 bb96d4a497432722623ae60d9bc734a1e360179e 4.2
160 c850f0ed54c1d42f9aa079ad528f8127e5775217 4.2.1
160 c850f0ed54c1d42f9aa079ad528f8127e5775217 4.2.1
161 26c49ed51a698ec016d2b4c6b44ca3c3f73cc788 4.2.2
161 26c49ed51a698ec016d2b4c6b44ca3c3f73cc788 4.2.2
162 857876ebaed4e315f63157bd157d6ce553c7ab73 4.3-rc
162 857876ebaed4e315f63157bd157d6ce553c7ab73 4.3-rc
163 5544af8622863796a0027566f6b646e10d522c4c 4.3
163 5544af8622863796a0027566f6b646e10d522c4c 4.3
164 943c91326b23954e6e1c6960d0239511f9530258 4.2.3
164 943c91326b23954e6e1c6960d0239511f9530258 4.2.3
165 3fee7f7d2da04226914c2258cc2884dc27384fd7 4.3.1
165 3fee7f7d2da04226914c2258cc2884dc27384fd7 4.3.1
166 920977f72c7b70acfdaf56ab35360584d7845827 4.3.2
166 920977f72c7b70acfdaf56ab35360584d7845827 4.3.2
167 2f427b57bf9019c6dc3750baa539dc22c1be50f6 4.3.3
167 2f427b57bf9019c6dc3750baa539dc22c1be50f6 4.3.3
168 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc
168 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc
169 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4
169 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4
170 cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1
170 cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1
171 a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2
171 a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2
172 27b6df1b5adbdf647cf5c6675b40575e1b197c60 4.5-rc
172 27b6df1b5adbdf647cf5c6675b40575e1b197c60 4.5-rc
173 d334afc585e29577f271c5eda03378736a16ca6b 4.5
173 d334afc585e29577f271c5eda03378736a16ca6b 4.5
174 369aadf7a3264b03c8b09efce715bc41e6ab4a9b 4.5.1
174 369aadf7a3264b03c8b09efce715bc41e6ab4a9b 4.5.1
175 8bba684efde7f45add05f737952093bb2aa07155 4.5.2
175 8bba684efde7f45add05f737952093bb2aa07155 4.5.2
176 7de7bd407251af2bc98e5b809c8598ee95830daf 4.5.3
176 7de7bd407251af2bc98e5b809c8598ee95830daf 4.5.3
177 ed5448edcbfa747b9154099e18630e49024fd47b 4.6rc0
177 ed5448edcbfa747b9154099e18630e49024fd47b 4.6rc0
178 1ec874717d8a93b19e0d50628443e0ee5efab3a9 4.6rc1
178 1ec874717d8a93b19e0d50628443e0ee5efab3a9 4.6rc1
179 6614cac550aea66d19c601e45efd1b7bd08d7c40 4.6
179 6614cac550aea66d19c601e45efd1b7bd08d7c40 4.6
180 9c5ced5276d6e7d54f7c3dadf5247b7ee98ec79c 4.6.1
180 9c5ced5276d6e7d54f7c3dadf5247b7ee98ec79c 4.6.1
181 0b63a6743010dfdbf8a8154186e119949bdaa1cc 4.6.2
181 0b63a6743010dfdbf8a8154186e119949bdaa1cc 4.6.2
182 e90130af47ce8dd53a3109aed9d15876b3e7dee8 4.7rc0
182 e90130af47ce8dd53a3109aed9d15876b3e7dee8 4.7rc0
183 33ac6a72308a215e6086fbced347ec10aa963b0a 4.7
183 33ac6a72308a215e6086fbced347ec10aa963b0a 4.7
184 ede3bf31fe63677fdf5bd8db687977d4e3d792ed 4.7.1
184 ede3bf31fe63677fdf5bd8db687977d4e3d792ed 4.7.1
185 5405cb1a79010ac50c58cd84e6f50c4556bf2a4c 4.7.2
185 5405cb1a79010ac50c58cd84e6f50c4556bf2a4c 4.7.2
186 956ec6f1320df26f3133ec40f3de866ea0695fd7 4.8rc0
186 956ec6f1320df26f3133ec40f3de866ea0695fd7 4.8rc0
187 a91a2837150bdcb27ae76b3646e6c93cd6a15904 4.8
187 a91a2837150bdcb27ae76b3646e6c93cd6a15904 4.8
188 1c8c54cf97256f4468da2eb4dbee24f7f3888e71 4.8.1
188 1c8c54cf97256f4468da2eb4dbee24f7f3888e71 4.8.1
189 197f092b2cd9691e2a55d198f717b231af9be6f9 4.8.2
189 197f092b2cd9691e2a55d198f717b231af9be6f9 4.8.2
190 593718ff5844cad7a27ee3eb5adad89ac8550949 4.9rc0
190 593718ff5844cad7a27ee3eb5adad89ac8550949 4.9rc0
191 83377b4b4ae0e9a6b8e579f7b0a693b8cf5c3b10 4.9
191 83377b4b4ae0e9a6b8e579f7b0a693b8cf5c3b10 4.9
192 4ea21df312ec7159c5b3633096b6ecf68750b0dd 4.9.1
192 4ea21df312ec7159c5b3633096b6ecf68750b0dd 4.9.1
193 4a8d9ed864754837a185a642170cde24392f9abf 5.0rc0
193 4a8d9ed864754837a185a642170cde24392f9abf 5.0rc0
194 07e479ef7c9639be0029f00e6a722b96dcc05fee 5.0
194 07e479ef7c9639be0029f00e6a722b96dcc05fee 5.0
195 c3484ddbdb9621256d597ed86b90d229c59c2af9 5.0.1
195 c3484ddbdb9621256d597ed86b90d229c59c2af9 5.0.1
196 97ada9b8d51bef24c5cb4cdca4243f0db694ab6e 5.0.2
196 97ada9b8d51bef24c5cb4cdca4243f0db694ab6e 5.0.2
197 e386b5f4f8360dbb43a576dd9b1368e386fefa5b 5.1rc0
197 e386b5f4f8360dbb43a576dd9b1368e386fefa5b 5.1rc0
198 e91930d712e8507d1bc1b2dffd96c83edc4cbed3 5.1
198 e91930d712e8507d1bc1b2dffd96c83edc4cbed3 5.1
199 a4e32fd539ab41489a51b2aa88bda9a73b839562 5.1.1
199 a4e32fd539ab41489a51b2aa88bda9a73b839562 5.1.1
200 181e52f2b62f4768aa0d988936c929dc7c4a41a0 5.1.2
200 181e52f2b62f4768aa0d988936c929dc7c4a41a0 5.1.2
201 59338f9561099de77c684c00f76507f11e46ebe8 5.2rc0
201 59338f9561099de77c684c00f76507f11e46ebe8 5.2rc0
202 ca3dca416f8d5863ca6f5a4a6a6bb835dcd5feeb 5.2
202 ca3dca416f8d5863ca6f5a4a6a6bb835dcd5feeb 5.2
203 a50fecefa691c9b72a99e49aa6fe9dd13943c2bf 5.2.1
203 a50fecefa691c9b72a99e49aa6fe9dd13943c2bf 5.2.1
204 b4c82b70418022e67cc0e69b1aa3c3aa43aa1d29 5.2.2
204 b4c82b70418022e67cc0e69b1aa3c3aa43aa1d29 5.2.2
205 84a0102c05c7852c8215ef6cf21d809927586b69 5.3rc0
205 84a0102c05c7852c8215ef6cf21d809927586b69 5.3rc0
206 e4344e463c0c888a2f437b78b5982ecdf3f6650a 5.3rc1
206 e4344e463c0c888a2f437b78b5982ecdf3f6650a 5.3rc1
207 7f5410dfc8a64bb587d19637deb95d378fd1eb5c 5.3
@@ -1,27 +1,27 b''
1 Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
1 Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
2 Upstream-Name: mercurial
2 Upstream-Name: mercurial
3 Source: https://www.mercurial-scm.org/
3 Source: https://www.mercurial-scm.org/
4
4
5 Files: *
5 Files: *
6 Copyright: 2005-2019, Matt Mackall <mpm@selenic.com> and others.
6 Copyright: 2005-2020, Matt Mackall <mpm@selenic.com> and others.
7 License: GPL-2+
7 License: GPL-2+
8 This program is free software; you can redistribute it
8 This program is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public
9 and/or modify it under the terms of the GNU General Public
10 License as published by the Free Software Foundation; either
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later
11 version 2 of the License, or (at your option) any later
12 version.
12 version.
13 .
13 .
14 This program is distributed in the hope that it will be
14 This program is distributed in the hope that it will be
15 useful, but WITHOUT ANY WARRANTY; without even the implied
15 useful, but WITHOUT ANY WARRANTY; without even the implied
16 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
17 PURPOSE. See the GNU General Public License for more
17 PURPOSE. See the GNU General Public License for more
18 details.
18 details.
19 .
19 .
20 You should have received a copy of the GNU General Public
20 You should have received a copy of the GNU General Public
21 License along with this package; if not, write to the Free
21 License along with this package; if not, write to the Free
22 Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 Software Foundation, Inc., 51 Franklin St, Fifth Floor,
23 Boston, MA 02110-1301 USA
23 Boston, MA 02110-1301 USA
24 .
24 .
25 On Debian systems, the full text of the GNU General Public
25 On Debian systems, the full text of the GNU General Public
26 License version 2 can be found in the file
26 License version 2 can be found in the file
27 `/usr/share/common-licenses/GPL-2'.
27 `/usr/share/common-licenses/GPL-2'.
@@ -1,163 +1,173 b''
1 # inno.py - Inno Setup functionality.
1 # inno.py - Inno Setup functionality.
2 #
2 #
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 # no-check-code because Python 3 native.
8 # no-check-code because Python 3 native.
9
9
10 import os
10 import os
11 import pathlib
11 import pathlib
12 import shutil
12 import shutil
13 import subprocess
13 import subprocess
14
14
15 import jinja2
15 import jinja2
16
16
17 from .py2exe import (
17 from .py2exe import (
18 build_py2exe,
18 build_py2exe,
19 stage_install,
19 stage_install,
20 )
20 )
21 from .util import (
21 from .util import (
22 find_vc_runtime_files,
22 find_vc_runtime_files,
23 normalize_windows_version,
24 process_install_rules,
23 read_version_py,
25 read_version_py,
24 )
26 )
25
27
26 EXTRA_PACKAGES = {
28 EXTRA_PACKAGES = {
27 'dulwich',
29 'dulwich',
28 'keyring',
30 'keyring',
29 'pygments',
31 'pygments',
30 'win32ctypes',
32 'win32ctypes',
31 }
33 }
32
34
35 EXTRA_INSTALL_RULES = [
36 ('contrib/win32/mercurial.ini', 'defaultrc/mercurial.rc'),
37 ]
38
33 PACKAGE_FILES_METADATA = {
39 PACKAGE_FILES_METADATA = {
34 'ReadMe.html': 'Flags: isreadme',
40 'ReadMe.html': 'Flags: isreadme',
35 }
41 }
36
42
37
43
38 def build(
44 def build(
39 source_dir: pathlib.Path,
45 source_dir: pathlib.Path,
40 build_dir: pathlib.Path,
46 build_dir: pathlib.Path,
41 python_exe: pathlib.Path,
47 python_exe: pathlib.Path,
42 iscc_exe: pathlib.Path,
48 iscc_exe: pathlib.Path,
43 version=None,
49 version=None,
44 ):
50 ):
45 """Build the Inno installer.
51 """Build the Inno installer.
46
52
47 Build files will be placed in ``build_dir``.
53 Build files will be placed in ``build_dir``.
48
54
49 py2exe's setup.py doesn't use setuptools. It doesn't have modern logic
55 py2exe's setup.py doesn't use setuptools. It doesn't have modern logic
50 for finding the Python 2.7 toolchain. So, we require the environment
56 for finding the Python 2.7 toolchain. So, we require the environment
51 to already be configured with an active toolchain.
57 to already be configured with an active toolchain.
52 """
58 """
53 if not iscc_exe.exists():
59 if not iscc_exe.exists():
54 raise Exception('%s does not exist' % iscc_exe)
60 raise Exception('%s does not exist' % iscc_exe)
55
61
56 vc_x64 = r'\x64' in os.environ.get('LIB', '')
62 vc_x64 = r'\x64' in os.environ.get('LIB', '')
57 arch = 'x64' if vc_x64 else 'x86'
63 arch = 'x64' if vc_x64 else 'x86'
58 inno_source_dir = source_dir / 'contrib' / 'packaging' / 'inno'
64 inno_source_dir = source_dir / 'contrib' / 'packaging' / 'inno'
59 inno_build_dir = build_dir / ('inno-%s' % arch)
65 inno_build_dir = build_dir / ('inno-%s' % arch)
60 staging_dir = inno_build_dir / 'stage'
66 staging_dir = inno_build_dir / 'stage'
61
67
62 requirements_txt = (
68 requirements_txt = (
63 source_dir / 'contrib' / 'packaging' / 'inno' / 'requirements.txt'
69 source_dir / 'contrib' / 'packaging' / 'requirements_win32.txt'
64 )
70 )
65
71
66 inno_build_dir.mkdir(parents=True, exist_ok=True)
72 inno_build_dir.mkdir(parents=True, exist_ok=True)
67
73
68 build_py2exe(
74 build_py2exe(
69 source_dir,
75 source_dir,
70 build_dir,
76 build_dir,
71 python_exe,
77 python_exe,
72 'inno',
78 'inno',
73 requirements_txt,
79 requirements_txt,
74 extra_packages=EXTRA_PACKAGES,
80 extra_packages=EXTRA_PACKAGES,
75 )
81 )
76
82
77 # Purge the staging directory for every build so packaging is
83 # Purge the staging directory for every build so packaging is
78 # pristine.
84 # pristine.
79 if staging_dir.exists():
85 if staging_dir.exists():
80 print('purging %s' % staging_dir)
86 print('purging %s' % staging_dir)
81 shutil.rmtree(staging_dir)
87 shutil.rmtree(staging_dir)
82
88
83 # Now assemble all the packaged files into the staging directory.
89 # Now assemble all the packaged files into the staging directory.
84 stage_install(source_dir, staging_dir)
90 stage_install(source_dir, staging_dir)
85
91
92 # We also install some extra files.
93 process_install_rules(EXTRA_INSTALL_RULES, source_dir, staging_dir)
94
86 # hg.exe depends on VC9 runtime DLLs. Copy those into place.
95 # hg.exe depends on VC9 runtime DLLs. Copy those into place.
87 for f in find_vc_runtime_files(vc_x64):
96 for f in find_vc_runtime_files(vc_x64):
88 if f.name.endswith('.manifest'):
97 if f.name.endswith('.manifest'):
89 basename = 'Microsoft.VC90.CRT.manifest'
98 basename = 'Microsoft.VC90.CRT.manifest'
90 else:
99 else:
91 basename = f.name
100 basename = f.name
92
101
93 dest_path = staging_dir / basename
102 dest_path = staging_dir / basename
94
103
95 print('copying %s to %s' % (f, dest_path))
104 print('copying %s to %s' % (f, dest_path))
96 shutil.copyfile(f, dest_path)
105 shutil.copyfile(f, dest_path)
97
106
98 # The final package layout is simply a mirror of the staging directory.
107 # The final package layout is simply a mirror of the staging directory.
99 package_files = []
108 package_files = []
100 for root, dirs, files in os.walk(staging_dir):
109 for root, dirs, files in os.walk(staging_dir):
101 dirs.sort()
110 dirs.sort()
102
111
103 root = pathlib.Path(root)
112 root = pathlib.Path(root)
104
113
105 for f in sorted(files):
114 for f in sorted(files):
106 full = root / f
115 full = root / f
107 rel = full.relative_to(staging_dir)
116 rel = full.relative_to(staging_dir)
108 if str(rel.parent) == '.':
117 if str(rel.parent) == '.':
109 dest_dir = '{app}'
118 dest_dir = '{app}'
110 else:
119 else:
111 dest_dir = '{app}\\%s' % rel.parent
120 dest_dir = '{app}\\%s' % rel.parent
112
121
113 package_files.append(
122 package_files.append(
114 {
123 {
115 'source': rel,
124 'source': rel,
116 'dest_dir': dest_dir,
125 'dest_dir': dest_dir,
117 'metadata': PACKAGE_FILES_METADATA.get(str(rel), None),
126 'metadata': PACKAGE_FILES_METADATA.get(str(rel), None),
118 }
127 }
119 )
128 )
120
129
121 print('creating installer')
130 print('creating installer')
122
131
123 # Install Inno files by rendering a template.
132 # Install Inno files by rendering a template.
124 jinja_env = jinja2.Environment(
133 jinja_env = jinja2.Environment(
125 loader=jinja2.FileSystemLoader(str(inno_source_dir)),
134 loader=jinja2.FileSystemLoader(str(inno_source_dir)),
126 # Need to change these to prevent conflict with Inno Setup.
135 # Need to change these to prevent conflict with Inno Setup.
127 comment_start_string='{##',
136 comment_start_string='{##',
128 comment_end_string='##}',
137 comment_end_string='##}',
129 )
138 )
130
139
131 try:
140 try:
132 template = jinja_env.get_template('mercurial.iss')
141 template = jinja_env.get_template('mercurial.iss')
133 except jinja2.TemplateSyntaxError as e:
142 except jinja2.TemplateSyntaxError as e:
134 raise Exception(
143 raise Exception(
135 'template syntax error at %s:%d: %s'
144 'template syntax error at %s:%d: %s'
136 % (e.name, e.lineno, e.message,)
145 % (e.name, e.lineno, e.message,)
137 )
146 )
138
147
139 content = template.render(package_files=package_files)
148 content = template.render(package_files=package_files)
140
149
141 with (inno_build_dir / 'mercurial.iss').open('w', encoding='utf-8') as fh:
150 with (inno_build_dir / 'mercurial.iss').open('w', encoding='utf-8') as fh:
142 fh.write(content)
151 fh.write(content)
143
152
144 # Copy additional files used by Inno.
153 # Copy additional files used by Inno.
145 for p in ('mercurial.ico', 'postinstall.txt'):
154 for p in ('mercurial.ico', 'postinstall.txt'):
146 shutil.copyfile(
155 shutil.copyfile(
147 source_dir / 'contrib' / 'win32' / p, inno_build_dir / p
156 source_dir / 'contrib' / 'win32' / p, inno_build_dir / p
148 )
157 )
149
158
150 args = [str(iscc_exe)]
159 args = [str(iscc_exe)]
151
160
152 if vc_x64:
161 if vc_x64:
153 args.append('/dARCH=x64')
162 args.append('/dARCH=x64')
154
163
155 if not version:
164 if not version:
156 version = read_version_py(source_dir)
165 version = read_version_py(source_dir)
157
166
158 args.append('/dVERSION=%s' % version)
167 args.append('/dVERSION=%s' % version)
168 args.append('/dQUAD_VERSION=%s' % normalize_windows_version(version))
159
169
160 args.append('/Odist')
170 args.append('/Odist')
161 args.append(str(inno_build_dir / 'mercurial.iss'))
171 args.append(str(inno_build_dir / 'mercurial.iss'))
162
172
163 subprocess.run(args, cwd=str(source_dir), check=True)
173 subprocess.run(args, cwd=str(source_dir), check=True)
@@ -1,245 +1,245 b''
1 # py2exe.py - Functionality for performing py2exe builds.
1 # py2exe.py - Functionality for performing py2exe builds.
2 #
2 #
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 # no-check-code because Python 3 native.
8 # no-check-code because Python 3 native.
9
9
10 import os
10 import os
11 import pathlib
11 import pathlib
12 import subprocess
12 import subprocess
13
13
14 from .downloads import download_entry
14 from .downloads import download_entry
15 from .util import (
15 from .util import (
16 extract_tar_to_directory,
16 extract_tar_to_directory,
17 extract_zip_to_directory,
17 extract_zip_to_directory,
18 process_install_rules,
18 process_install_rules,
19 python_exe_info,
19 python_exe_info,
20 )
20 )
21
21
22
22
23 STAGING_RULES = [
23 STAGING_RULES = [
24 ('contrib/bash_completion', 'Contrib/'),
24 ('contrib/bash_completion', 'contrib/'),
25 ('contrib/hgk', 'Contrib/hgk.tcl'),
25 ('contrib/hgk', 'contrib/hgk.tcl'),
26 ('contrib/hgweb.fcgi', 'Contrib/'),
26 ('contrib/hgweb.fcgi', 'contrib/'),
27 ('contrib/hgweb.wsgi', 'Contrib/'),
27 ('contrib/hgweb.wsgi', 'contrib/'),
28 ('contrib/logo-droplets.svg', 'Contrib/'),
28 ('contrib/logo-droplets.svg', 'contrib/'),
29 ('contrib/mercurial.el', 'Contrib/'),
29 ('contrib/mercurial.el', 'contrib/'),
30 ('contrib/mq.el', 'Contrib/'),
30 ('contrib/mq.el', 'contrib/'),
31 ('contrib/tcsh_completion', 'Contrib/'),
31 ('contrib/tcsh_completion', 'contrib/'),
32 ('contrib/tcsh_completion_build.sh', 'Contrib/'),
32 ('contrib/tcsh_completion_build.sh', 'contrib/'),
33 ('contrib/vim/*', 'Contrib/Vim/'),
33 ('contrib/vim/*', 'contrib/vim/'),
34 ('contrib/win32/postinstall.txt', 'ReleaseNotes.txt'),
34 ('contrib/win32/postinstall.txt', 'ReleaseNotes.txt'),
35 ('contrib/win32/ReadMe.html', 'ReadMe.html'),
35 ('contrib/win32/ReadMe.html', 'ReadMe.html'),
36 ('contrib/xml.rnc', 'Contrib/'),
36 ('contrib/xml.rnc', 'contrib/'),
37 ('contrib/zsh_completion', 'Contrib/'),
37 ('contrib/zsh_completion', 'contrib/'),
38 ('dist/hg.exe', './'),
38 ('dist/hg.exe', './'),
39 ('dist/lib/*.dll', 'lib/'),
39 ('dist/lib/*.dll', 'lib/'),
40 ('dist/lib/*.pyd', 'lib/'),
40 ('dist/lib/*.pyd', 'lib/'),
41 ('dist/lib/library.zip', 'lib/'),
41 ('dist/lib/library.zip', 'lib/'),
42 ('dist/Microsoft.VC*.CRT.manifest', './'),
42 ('dist/Microsoft.VC*.CRT.manifest', './'),
43 ('dist/msvc*.dll', './'),
43 ('dist/msvc*.dll', './'),
44 ('dist/python*.dll', './'),
44 ('dist/python*.dll', './'),
45 ('doc/*.html', 'doc/'),
45 ('doc/*.html', 'doc/'),
46 ('doc/style.css', 'doc/'),
46 ('doc/style.css', 'doc/'),
47 ('mercurial/helptext/**/*.txt', 'helptext/'),
47 ('mercurial/helptext/**/*.txt', 'helptext/'),
48 ('mercurial/defaultrc/*.rc', 'defaultrc/'),
48 ('mercurial/defaultrc/*.rc', 'defaultrc/'),
49 ('mercurial/locale/**/*', 'locale/'),
49 ('mercurial/locale/**/*', 'locale/'),
50 ('mercurial/templates/**/*', 'Templates/'),
50 ('mercurial/templates/**/*', 'templates/'),
51 ('COPYING', 'Copying.txt'),
51 ('COPYING', 'Copying.txt'),
52 ]
52 ]
53
53
54 # List of paths to exclude from the staging area.
54 # List of paths to exclude from the staging area.
55 STAGING_EXCLUDES = [
55 STAGING_EXCLUDES = [
56 'doc/hg-ssh.8.html',
56 'doc/hg-ssh.8.html',
57 ]
57 ]
58
58
59
59
60 def build_py2exe(
60 def build_py2exe(
61 source_dir: pathlib.Path,
61 source_dir: pathlib.Path,
62 build_dir: pathlib.Path,
62 build_dir: pathlib.Path,
63 python_exe: pathlib.Path,
63 python_exe: pathlib.Path,
64 build_name: str,
64 build_name: str,
65 venv_requirements_txt: pathlib.Path,
65 venv_requirements_txt: pathlib.Path,
66 extra_packages=None,
66 extra_packages=None,
67 extra_excludes=None,
67 extra_excludes=None,
68 extra_dll_excludes=None,
68 extra_dll_excludes=None,
69 extra_packages_script=None,
69 extra_packages_script=None,
70 ):
70 ):
71 """Build Mercurial with py2exe.
71 """Build Mercurial with py2exe.
72
72
73 Build files will be placed in ``build_dir``.
73 Build files will be placed in ``build_dir``.
74
74
75 py2exe's setup.py doesn't use setuptools. It doesn't have modern logic
75 py2exe's setup.py doesn't use setuptools. It doesn't have modern logic
76 for finding the Python 2.7 toolchain. So, we require the environment
76 for finding the Python 2.7 toolchain. So, we require the environment
77 to already be configured with an active toolchain.
77 to already be configured with an active toolchain.
78 """
78 """
79 if 'VCINSTALLDIR' not in os.environ:
79 if 'VCINSTALLDIR' not in os.environ:
80 raise Exception(
80 raise Exception(
81 'not running from a Visual C++ build environment; '
81 'not running from a Visual C++ build environment; '
82 'execute the "Visual C++ <version> Command Prompt" '
82 'execute the "Visual C++ <version> Command Prompt" '
83 'application shortcut or a vcsvarsall.bat file'
83 'application shortcut or a vcsvarsall.bat file'
84 )
84 )
85
85
86 # Identity x86/x64 and validate the environment matches the Python
86 # Identity x86/x64 and validate the environment matches the Python
87 # architecture.
87 # architecture.
88 vc_x64 = r'\x64' in os.environ['LIB']
88 vc_x64 = r'\x64' in os.environ['LIB']
89
89
90 py_info = python_exe_info(python_exe)
90 py_info = python_exe_info(python_exe)
91
91
92 if vc_x64:
92 if vc_x64:
93 if py_info['arch'] != '64bit':
93 if py_info['arch'] != '64bit':
94 raise Exception(
94 raise Exception(
95 'architecture mismatch: Visual C++ environment '
95 'architecture mismatch: Visual C++ environment '
96 'is configured for 64-bit but Python is 32-bit'
96 'is configured for 64-bit but Python is 32-bit'
97 )
97 )
98 else:
98 else:
99 if py_info['arch'] != '32bit':
99 if py_info['arch'] != '32bit':
100 raise Exception(
100 raise Exception(
101 'architecture mismatch: Visual C++ environment '
101 'architecture mismatch: Visual C++ environment '
102 'is configured for 32-bit but Python is 64-bit'
102 'is configured for 32-bit but Python is 64-bit'
103 )
103 )
104
104
105 if py_info['py3']:
105 if py_info['py3']:
106 raise Exception('Only Python 2 is currently supported')
106 raise Exception('Only Python 2 is currently supported')
107
107
108 build_dir.mkdir(exist_ok=True)
108 build_dir.mkdir(exist_ok=True)
109
109
110 gettext_pkg, gettext_entry = download_entry('gettext', build_dir)
110 gettext_pkg, gettext_entry = download_entry('gettext', build_dir)
111 gettext_dep_pkg = download_entry('gettext-dep', build_dir)[0]
111 gettext_dep_pkg = download_entry('gettext-dep', build_dir)[0]
112 virtualenv_pkg, virtualenv_entry = download_entry('virtualenv', build_dir)
112 virtualenv_pkg, virtualenv_entry = download_entry('virtualenv', build_dir)
113 py2exe_pkg, py2exe_entry = download_entry('py2exe', build_dir)
113 py2exe_pkg, py2exe_entry = download_entry('py2exe', build_dir)
114
114
115 venv_path = build_dir / (
115 venv_path = build_dir / (
116 'venv-%s-%s' % (build_name, 'x64' if vc_x64 else 'x86')
116 'venv-%s-%s' % (build_name, 'x64' if vc_x64 else 'x86')
117 )
117 )
118
118
119 gettext_root = build_dir / ('gettext-win-%s' % gettext_entry['version'])
119 gettext_root = build_dir / ('gettext-win-%s' % gettext_entry['version'])
120
120
121 if not gettext_root.exists():
121 if not gettext_root.exists():
122 extract_zip_to_directory(gettext_pkg, gettext_root)
122 extract_zip_to_directory(gettext_pkg, gettext_root)
123 extract_zip_to_directory(gettext_dep_pkg, gettext_root)
123 extract_zip_to_directory(gettext_dep_pkg, gettext_root)
124
124
125 # This assumes Python 2. We don't need virtualenv on Python 3.
125 # This assumes Python 2. We don't need virtualenv on Python 3.
126 virtualenv_src_path = build_dir / (
126 virtualenv_src_path = build_dir / (
127 'virtualenv-%s' % virtualenv_entry['version']
127 'virtualenv-%s' % virtualenv_entry['version']
128 )
128 )
129 virtualenv_py = virtualenv_src_path / 'virtualenv.py'
129 virtualenv_py = virtualenv_src_path / 'virtualenv.py'
130
130
131 if not virtualenv_src_path.exists():
131 if not virtualenv_src_path.exists():
132 extract_tar_to_directory(virtualenv_pkg, build_dir)
132 extract_tar_to_directory(virtualenv_pkg, build_dir)
133
133
134 py2exe_source_path = build_dir / ('py2exe-%s' % py2exe_entry['version'])
134 py2exe_source_path = build_dir / ('py2exe-%s' % py2exe_entry['version'])
135
135
136 if not py2exe_source_path.exists():
136 if not py2exe_source_path.exists():
137 extract_zip_to_directory(py2exe_pkg, build_dir)
137 extract_zip_to_directory(py2exe_pkg, build_dir)
138
138
139 if not venv_path.exists():
139 if not venv_path.exists():
140 print('creating virtualenv with dependencies')
140 print('creating virtualenv with dependencies')
141 subprocess.run(
141 subprocess.run(
142 [str(python_exe), str(virtualenv_py), str(venv_path)], check=True
142 [str(python_exe), str(virtualenv_py), str(venv_path)], check=True
143 )
143 )
144
144
145 venv_python = venv_path / 'Scripts' / 'python.exe'
145 venv_python = venv_path / 'Scripts' / 'python.exe'
146 venv_pip = venv_path / 'Scripts' / 'pip.exe'
146 venv_pip = venv_path / 'Scripts' / 'pip.exe'
147
147
148 subprocess.run(
148 subprocess.run(
149 [str(venv_pip), 'install', '-r', str(venv_requirements_txt)], check=True
149 [str(venv_pip), 'install', '-r', str(venv_requirements_txt)], check=True
150 )
150 )
151
151
152 # Force distutils to use VC++ settings from environment, which was
152 # Force distutils to use VC++ settings from environment, which was
153 # validated above.
153 # validated above.
154 env = dict(os.environ)
154 env = dict(os.environ)
155 env['DISTUTILS_USE_SDK'] = '1'
155 env['DISTUTILS_USE_SDK'] = '1'
156 env['MSSdk'] = '1'
156 env['MSSdk'] = '1'
157
157
158 if extra_packages_script:
158 if extra_packages_script:
159 more_packages = set(
159 more_packages = set(
160 subprocess.check_output(extra_packages_script, cwd=build_dir)
160 subprocess.check_output(extra_packages_script, cwd=build_dir)
161 .split(b'\0')[-1]
161 .split(b'\0')[-1]
162 .strip()
162 .strip()
163 .decode('utf-8')
163 .decode('utf-8')
164 .splitlines()
164 .splitlines()
165 )
165 )
166 if more_packages:
166 if more_packages:
167 if not extra_packages:
167 if not extra_packages:
168 extra_packages = more_packages
168 extra_packages = more_packages
169 else:
169 else:
170 extra_packages |= more_packages
170 extra_packages |= more_packages
171
171
172 if extra_packages:
172 if extra_packages:
173 env['HG_PY2EXE_EXTRA_PACKAGES'] = ' '.join(sorted(extra_packages))
173 env['HG_PY2EXE_EXTRA_PACKAGES'] = ' '.join(sorted(extra_packages))
174 hgext3rd_extras = sorted(
174 hgext3rd_extras = sorted(
175 e for e in extra_packages if e.startswith('hgext3rd.')
175 e for e in extra_packages if e.startswith('hgext3rd.')
176 )
176 )
177 if hgext3rd_extras:
177 if hgext3rd_extras:
178 env['HG_PY2EXE_EXTRA_INSTALL_PACKAGES'] = ' '.join(hgext3rd_extras)
178 env['HG_PY2EXE_EXTRA_INSTALL_PACKAGES'] = ' '.join(hgext3rd_extras)
179 if extra_excludes:
179 if extra_excludes:
180 env['HG_PY2EXE_EXTRA_EXCLUDES'] = ' '.join(sorted(extra_excludes))
180 env['HG_PY2EXE_EXTRA_EXCLUDES'] = ' '.join(sorted(extra_excludes))
181 if extra_dll_excludes:
181 if extra_dll_excludes:
182 env['HG_PY2EXE_EXTRA_DLL_EXCLUDES'] = ' '.join(
182 env['HG_PY2EXE_EXTRA_DLL_EXCLUDES'] = ' '.join(
183 sorted(extra_dll_excludes)
183 sorted(extra_dll_excludes)
184 )
184 )
185
185
186 py2exe_py_path = venv_path / 'Lib' / 'site-packages' / 'py2exe'
186 py2exe_py_path = venv_path / 'Lib' / 'site-packages' / 'py2exe'
187 if not py2exe_py_path.exists():
187 if not py2exe_py_path.exists():
188 print('building py2exe')
188 print('building py2exe')
189 subprocess.run(
189 subprocess.run(
190 [str(venv_python), 'setup.py', 'install'],
190 [str(venv_python), 'setup.py', 'install'],
191 cwd=py2exe_source_path,
191 cwd=py2exe_source_path,
192 env=env,
192 env=env,
193 check=True,
193 check=True,
194 )
194 )
195
195
196 # Register location of msgfmt and other binaries.
196 # Register location of msgfmt and other binaries.
197 env['PATH'] = '%s%s%s' % (
197 env['PATH'] = '%s%s%s' % (
198 env['PATH'],
198 env['PATH'],
199 os.pathsep,
199 os.pathsep,
200 str(gettext_root / 'bin'),
200 str(gettext_root / 'bin'),
201 )
201 )
202
202
203 print('building Mercurial')
203 print('building Mercurial')
204 subprocess.run(
204 subprocess.run(
205 [str(venv_python), 'setup.py', 'py2exe', 'build_doc', '--html'],
205 [str(venv_python), 'setup.py', 'py2exe', 'build_doc', '--html'],
206 cwd=str(source_dir),
206 cwd=str(source_dir),
207 env=env,
207 env=env,
208 check=True,
208 check=True,
209 )
209 )
210
210
211
211
212 def stage_install(
212 def stage_install(
213 source_dir: pathlib.Path, staging_dir: pathlib.Path, lower_case=False
213 source_dir: pathlib.Path, staging_dir: pathlib.Path, lower_case=False
214 ):
214 ):
215 """Copy all files to be installed to a directory.
215 """Copy all files to be installed to a directory.
216
216
217 This allows packaging to simply walk a directory tree to find source
217 This allows packaging to simply walk a directory tree to find source
218 files.
218 files.
219 """
219 """
220 if lower_case:
220 if lower_case:
221 rules = []
221 rules = []
222 for source, dest in STAGING_RULES:
222 for source, dest in STAGING_RULES:
223 # Only lower directory names.
223 # Only lower directory names.
224 if '/' in dest:
224 if '/' in dest:
225 parent, leaf = dest.rsplit('/', 1)
225 parent, leaf = dest.rsplit('/', 1)
226 dest = '%s/%s' % (parent.lower(), leaf)
226 dest = '%s/%s' % (parent.lower(), leaf)
227 rules.append((source, dest))
227 rules.append((source, dest))
228 else:
228 else:
229 rules = STAGING_RULES
229 rules = STAGING_RULES
230
230
231 process_install_rules(rules, source_dir, staging_dir)
231 process_install_rules(rules, source_dir, staging_dir)
232
232
233 # Write out a default editor.rc file to configure notepad as the
233 # Write out a default editor.rc file to configure notepad as the
234 # default editor.
234 # default editor.
235 with (staging_dir / 'defaultrc' / 'editor.rc').open(
235 with (staging_dir / 'defaultrc' / 'editor.rc').open(
236 'w', encoding='utf-8'
236 'w', encoding='utf-8'
237 ) as fh:
237 ) as fh:
238 fh.write('[ui]\neditor = notepad\n')
238 fh.write('[ui]\neditor = notepad\n')
239
239
240 # Purge any files we don't want to be there.
240 # Purge any files we don't want to be there.
241 for f in STAGING_EXCLUDES:
241 for f in STAGING_EXCLUDES:
242 p = staging_dir / f
242 p = staging_dir / f
243 if p.exists():
243 if p.exists():
244 print('removing %s' % p)
244 print('removing %s' % p)
245 p.unlink()
245 p.unlink()
@@ -1,226 +1,286 b''
1 # util.py - Common packaging utility code.
1 # util.py - Common packaging utility code.
2 #
2 #
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 # no-check-code because Python 3 native.
8 # no-check-code because Python 3 native.
9
9
10 import distutils.version
10 import distutils.version
11 import getpass
11 import getpass
12 import glob
12 import glob
13 import os
13 import os
14 import pathlib
14 import pathlib
15 import re
15 import re
16 import shutil
16 import shutil
17 import subprocess
17 import subprocess
18 import tarfile
18 import tarfile
19 import zipfile
19 import zipfile
20
20
21
21
22 def extract_tar_to_directory(source: pathlib.Path, dest: pathlib.Path):
22 def extract_tar_to_directory(source: pathlib.Path, dest: pathlib.Path):
23 with tarfile.open(source, 'r') as tf:
23 with tarfile.open(source, 'r') as tf:
24 tf.extractall(dest)
24 tf.extractall(dest)
25
25
26
26
27 def extract_zip_to_directory(source: pathlib.Path, dest: pathlib.Path):
27 def extract_zip_to_directory(source: pathlib.Path, dest: pathlib.Path):
28 with zipfile.ZipFile(source, 'r') as zf:
28 with zipfile.ZipFile(source, 'r') as zf:
29 zf.extractall(dest)
29 zf.extractall(dest)
30
30
31
31
32 def find_vc_runtime_files(x64=False):
32 def find_vc_runtime_files(x64=False):
33 """Finds Visual C++ Runtime DLLs to include in distribution."""
33 """Finds Visual C++ Runtime DLLs to include in distribution."""
34 winsxs = pathlib.Path(os.environ['SYSTEMROOT']) / 'WinSxS'
34 winsxs = pathlib.Path(os.environ['SYSTEMROOT']) / 'WinSxS'
35
35
36 prefix = 'amd64' if x64 else 'x86'
36 prefix = 'amd64' if x64 else 'x86'
37
37
38 candidates = sorted(
38 candidates = sorted(
39 p
39 p
40 for p in os.listdir(winsxs)
40 for p in os.listdir(winsxs)
41 if p.lower().startswith('%s_microsoft.vc90.crt_' % prefix)
41 if p.lower().startswith('%s_microsoft.vc90.crt_' % prefix)
42 )
42 )
43
43
44 for p in candidates:
44 for p in candidates:
45 print('found candidate VC runtime: %s' % p)
45 print('found candidate VC runtime: %s' % p)
46
46
47 # Take the newest version.
47 # Take the newest version.
48 version = candidates[-1]
48 version = candidates[-1]
49
49
50 d = winsxs / version
50 d = winsxs / version
51
51
52 return [
52 return [
53 d / 'msvcm90.dll',
53 d / 'msvcm90.dll',
54 d / 'msvcp90.dll',
54 d / 'msvcp90.dll',
55 d / 'msvcr90.dll',
55 d / 'msvcr90.dll',
56 winsxs / 'Manifests' / ('%s.manifest' % version),
56 winsxs / 'Manifests' / ('%s.manifest' % version),
57 ]
57 ]
58
58
59
59
60 def windows_10_sdk_info():
60 def windows_10_sdk_info():
61 """Resolves information about the Windows 10 SDK."""
61 """Resolves information about the Windows 10 SDK."""
62
62
63 base = pathlib.Path(os.environ['ProgramFiles(x86)']) / 'Windows Kits' / '10'
63 base = pathlib.Path(os.environ['ProgramFiles(x86)']) / 'Windows Kits' / '10'
64
64
65 if not base.is_dir():
65 if not base.is_dir():
66 raise Exception('unable to find Windows 10 SDK at %s' % base)
66 raise Exception('unable to find Windows 10 SDK at %s' % base)
67
67
68 # Find the latest version.
68 # Find the latest version.
69 bin_base = base / 'bin'
69 bin_base = base / 'bin'
70
70
71 versions = [v for v in os.listdir(bin_base) if v.startswith('10.')]
71 versions = [v for v in os.listdir(bin_base) if v.startswith('10.')]
72 version = sorted(versions, reverse=True)[0]
72 version = sorted(versions, reverse=True)[0]
73
73
74 bin_version = bin_base / version
74 bin_version = bin_base / version
75
75
76 return {
76 return {
77 'root': base,
77 'root': base,
78 'version': version,
78 'version': version,
79 'bin_root': bin_version,
79 'bin_root': bin_version,
80 'bin_x86': bin_version / 'x86',
80 'bin_x86': bin_version / 'x86',
81 'bin_x64': bin_version / 'x64',
81 'bin_x64': bin_version / 'x64',
82 }
82 }
83
83
84
84
85 def normalize_windows_version(version):
86 """Normalize Mercurial version string so WiX/Inno accepts it.
87
88 Version strings have to be numeric ``A.B.C[.D]`` to conform with MSI's
89 requirements.
90
91 We normalize RC version or the commit count to a 4th version component.
92 We store this in the 4th component because ``A.B.C`` releases do occur
93 and we want an e.g. ``5.3rc0`` version to be semantically less than a
94 ``5.3.1rc2`` version. This requires always reserving the 3rd version
95 component for the point release and the ``X.YrcN`` release is always
96 point release 0.
97
98 In the case of an RC and presence of ``+`` suffix data, we can't use both
99 because the version format is limited to 4 components. We choose to use
100 RC and throw away the commit count in the suffix. This means we could
101 produce multiple installers with the same normalized version string.
102
103 >>> normalize_windows_version("5.3")
104 '5.3.0'
105
106 >>> normalize_windows_version("5.3rc0")
107 '5.3.0.0'
108
109 >>> normalize_windows_version("5.3rc1")
110 '5.3.0.1'
111
112 >>> normalize_windows_version("5.3rc1+2-abcdef")
113 '5.3.0.1'
114
115 >>> normalize_windows_version("5.3+2-abcdef")
116 '5.3.0.2'
117 """
118 if '+' in version:
119 version, extra = version.split('+', 1)
120 else:
121 extra = None
122
123 # 4.9rc0
124 if version[:-1].endswith('rc'):
125 rc = int(version[-1:])
126 version = version[:-3]
127 else:
128 rc = None
129
130 # Ensure we have at least X.Y version components.
131 versions = [int(v) for v in version.split('.')]
132 while len(versions) < 3:
133 versions.append(0)
134
135 if len(versions) < 4:
136 if rc is not None:
137 versions.append(rc)
138 elif extra:
139 # <commit count>-<hash>+<date>
140 versions.append(int(extra.split('-')[0]))
141
142 return '.'.join('%d' % x for x in versions[0:4])
143
144
85 def find_signtool():
145 def find_signtool():
86 """Find signtool.exe from the Windows SDK."""
146 """Find signtool.exe from the Windows SDK."""
87 sdk = windows_10_sdk_info()
147 sdk = windows_10_sdk_info()
88
148
89 for key in ('bin_x64', 'bin_x86'):
149 for key in ('bin_x64', 'bin_x86'):
90 p = sdk[key] / 'signtool.exe'
150 p = sdk[key] / 'signtool.exe'
91
151
92 if p.exists():
152 if p.exists():
93 return p
153 return p
94
154
95 raise Exception('could not find signtool.exe in Windows 10 SDK')
155 raise Exception('could not find signtool.exe in Windows 10 SDK')
96
156
97
157
98 def sign_with_signtool(
158 def sign_with_signtool(
99 file_path,
159 file_path,
100 description,
160 description,
101 subject_name=None,
161 subject_name=None,
102 cert_path=None,
162 cert_path=None,
103 cert_password=None,
163 cert_password=None,
104 timestamp_url=None,
164 timestamp_url=None,
105 ):
165 ):
106 """Digitally sign a file with signtool.exe.
166 """Digitally sign a file with signtool.exe.
107
167
108 ``file_path`` is file to sign.
168 ``file_path`` is file to sign.
109 ``description`` is text that goes in the signature.
169 ``description`` is text that goes in the signature.
110
170
111 The signing certificate can be specified by ``cert_path`` or
171 The signing certificate can be specified by ``cert_path`` or
112 ``subject_name``. These correspond to the ``/f`` and ``/n`` arguments
172 ``subject_name``. These correspond to the ``/f`` and ``/n`` arguments
113 to signtool.exe, respectively.
173 to signtool.exe, respectively.
114
174
115 The certificate password can be specified via ``cert_password``. If
175 The certificate password can be specified via ``cert_password``. If
116 not provided, you will be prompted for the password.
176 not provided, you will be prompted for the password.
117
177
118 ``timestamp_url`` is the URL of a RFC 3161 timestamp server (``/tr``
178 ``timestamp_url`` is the URL of a RFC 3161 timestamp server (``/tr``
119 argument to signtool.exe).
179 argument to signtool.exe).
120 """
180 """
121 if cert_path and subject_name:
181 if cert_path and subject_name:
122 raise ValueError('cannot specify both cert_path and subject_name')
182 raise ValueError('cannot specify both cert_path and subject_name')
123
183
124 while cert_path and not cert_password:
184 while cert_path and not cert_password:
125 cert_password = getpass.getpass('password for %s: ' % cert_path)
185 cert_password = getpass.getpass('password for %s: ' % cert_path)
126
186
127 args = [
187 args = [
128 str(find_signtool()),
188 str(find_signtool()),
129 'sign',
189 'sign',
130 '/v',
190 '/v',
131 '/fd',
191 '/fd',
132 'sha256',
192 'sha256',
133 '/d',
193 '/d',
134 description,
194 description,
135 ]
195 ]
136
196
137 if cert_path:
197 if cert_path:
138 args.extend(['/f', str(cert_path), '/p', cert_password])
198 args.extend(['/f', str(cert_path), '/p', cert_password])
139 elif subject_name:
199 elif subject_name:
140 args.extend(['/n', subject_name])
200 args.extend(['/n', subject_name])
141
201
142 if timestamp_url:
202 if timestamp_url:
143 args.extend(['/tr', timestamp_url, '/td', 'sha256'])
203 args.extend(['/tr', timestamp_url, '/td', 'sha256'])
144
204
145 args.append(str(file_path))
205 args.append(str(file_path))
146
206
147 print('signing %s' % file_path)
207 print('signing %s' % file_path)
148 subprocess.run(args, check=True)
208 subprocess.run(args, check=True)
149
209
150
210
151 PRINT_PYTHON_INFO = '''
211 PRINT_PYTHON_INFO = '''
152 import platform; print("%s:%s" % (platform.architecture()[0], platform.python_version()))
212 import platform; print("%s:%s" % (platform.architecture()[0], platform.python_version()))
153 '''.strip()
213 '''.strip()
154
214
155
215
156 def python_exe_info(python_exe: pathlib.Path):
216 def python_exe_info(python_exe: pathlib.Path):
157 """Obtain information about a Python executable."""
217 """Obtain information about a Python executable."""
158
218
159 res = subprocess.check_output([str(python_exe), '-c', PRINT_PYTHON_INFO])
219 res = subprocess.check_output([str(python_exe), '-c', PRINT_PYTHON_INFO])
160
220
161 arch, version = res.decode('utf-8').split(':')
221 arch, version = res.decode('utf-8').split(':')
162
222
163 version = distutils.version.LooseVersion(version)
223 version = distutils.version.LooseVersion(version)
164
224
165 return {
225 return {
166 'arch': arch,
226 'arch': arch,
167 'version': version,
227 'version': version,
168 'py3': version >= distutils.version.LooseVersion('3'),
228 'py3': version >= distutils.version.LooseVersion('3'),
169 }
229 }
170
230
171
231
172 def process_install_rules(
232 def process_install_rules(
173 rules: list, source_dir: pathlib.Path, dest_dir: pathlib.Path
233 rules: list, source_dir: pathlib.Path, dest_dir: pathlib.Path
174 ):
234 ):
175 for source, dest in rules:
235 for source, dest in rules:
176 if '*' in source:
236 if '*' in source:
177 if not dest.endswith('/'):
237 if not dest.endswith('/'):
178 raise ValueError('destination must end in / when globbing')
238 raise ValueError('destination must end in / when globbing')
179
239
180 # We strip off the source path component before the first glob
240 # We strip off the source path component before the first glob
181 # character to construct the relative install path.
241 # character to construct the relative install path.
182 prefix_end_index = source[: source.index('*')].rindex('/')
242 prefix_end_index = source[: source.index('*')].rindex('/')
183 relative_prefix = source_dir / source[0:prefix_end_index]
243 relative_prefix = source_dir / source[0:prefix_end_index]
184
244
185 for res in glob.glob(str(source_dir / source), recursive=True):
245 for res in glob.glob(str(source_dir / source), recursive=True):
186 source_path = pathlib.Path(res)
246 source_path = pathlib.Path(res)
187
247
188 if source_path.is_dir():
248 if source_path.is_dir():
189 continue
249 continue
190
250
191 rel_path = source_path.relative_to(relative_prefix)
251 rel_path = source_path.relative_to(relative_prefix)
192
252
193 dest_path = dest_dir / dest[:-1] / rel_path
253 dest_path = dest_dir / dest[:-1] / rel_path
194
254
195 dest_path.parent.mkdir(parents=True, exist_ok=True)
255 dest_path.parent.mkdir(parents=True, exist_ok=True)
196 print('copying %s to %s' % (source_path, dest_path))
256 print('copying %s to %s' % (source_path, dest_path))
197 shutil.copy(source_path, dest_path)
257 shutil.copy(source_path, dest_path)
198
258
199 # Simple file case.
259 # Simple file case.
200 else:
260 else:
201 source_path = pathlib.Path(source)
261 source_path = pathlib.Path(source)
202
262
203 if dest.endswith('/'):
263 if dest.endswith('/'):
204 dest_path = pathlib.Path(dest) / source_path.name
264 dest_path = pathlib.Path(dest) / source_path.name
205 else:
265 else:
206 dest_path = pathlib.Path(dest)
266 dest_path = pathlib.Path(dest)
207
267
208 full_source_path = source_dir / source_path
268 full_source_path = source_dir / source_path
209 full_dest_path = dest_dir / dest_path
269 full_dest_path = dest_dir / dest_path
210
270
211 full_dest_path.parent.mkdir(parents=True, exist_ok=True)
271 full_dest_path.parent.mkdir(parents=True, exist_ok=True)
212 shutil.copy(full_source_path, full_dest_path)
272 shutil.copy(full_source_path, full_dest_path)
213 print('copying %s to %s' % (full_source_path, full_dest_path))
273 print('copying %s to %s' % (full_source_path, full_dest_path))
214
274
215
275
216 def read_version_py(source_dir):
276 def read_version_py(source_dir):
217 """Read the mercurial/__version__.py file to resolve the version string."""
277 """Read the mercurial/__version__.py file to resolve the version string."""
218 p = source_dir / 'mercurial' / '__version__.py'
278 p = source_dir / 'mercurial' / '__version__.py'
219
279
220 with p.open('r', encoding='utf-8') as fh:
280 with p.open('r', encoding='utf-8') as fh:
221 m = re.search('version = b"([^"]+)"', fh.read(), re.MULTILINE)
281 m = re.search('version = b"([^"]+)"', fh.read(), re.MULTILINE)
222
282
223 if not m:
283 if not m:
224 raise Exception('could not parse %s' % p)
284 raise Exception('could not parse %s' % p)
225
285
226 return m.group(1)
286 return m.group(1)
@@ -1,518 +1,497 b''
1 # wix.py - WiX installer functionality
1 # wix.py - WiX installer functionality
2 #
2 #
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 # no-check-code because Python 3 native.
8 # no-check-code because Python 3 native.
9
9
10 import collections
10 import collections
11 import os
11 import os
12 import pathlib
12 import pathlib
13 import re
13 import re
14 import shutil
14 import shutil
15 import subprocess
15 import subprocess
16 import typing
16 import typing
17 import uuid
17 import uuid
18 import xml.dom.minidom
18 import xml.dom.minidom
19
19
20 from .downloads import download_entry
20 from .downloads import download_entry
21 from .py2exe import (
21 from .py2exe import (
22 build_py2exe,
22 build_py2exe,
23 stage_install,
23 stage_install,
24 )
24 )
25 from .util import (
25 from .util import (
26 extract_zip_to_directory,
26 extract_zip_to_directory,
27 normalize_windows_version,
27 process_install_rules,
28 process_install_rules,
28 sign_with_signtool,
29 sign_with_signtool,
29 )
30 )
30
31
31
32
32 EXTRA_PACKAGES = {
33 EXTRA_PACKAGES = {
34 'dulwich',
33 'distutils',
35 'distutils',
36 'keyring',
34 'pygments',
37 'pygments',
38 'win32ctypes',
35 }
39 }
36
40
37
41
38 EXTRA_INSTALL_RULES = [
42 EXTRA_INSTALL_RULES = [
39 ('contrib/packaging/wix/COPYING.rtf', 'COPYING.rtf'),
43 ('contrib/packaging/wix/COPYING.rtf', 'COPYING.rtf'),
40 ('contrib/win32/mercurial.ini', 'defaultrc/mercurial.rc'),
44 ('contrib/win32/mercurial.ini', 'defaultrc/mercurial.rc'),
41 ]
45 ]
42
46
43 STAGING_REMOVE_FILES = [
47 STAGING_REMOVE_FILES = [
44 # We use the RTF variant.
48 # We use the RTF variant.
45 'copying.txt',
49 'copying.txt',
46 ]
50 ]
47
51
48 SHORTCUTS = {
52 SHORTCUTS = {
49 # hg.1.html'
53 # hg.1.html'
50 'hg.file.5d3e441c_28d9_5542_afd0_cdd4234f12d5': {
54 'hg.file.5d3e441c_28d9_5542_afd0_cdd4234f12d5': {
51 'Name': 'Mercurial Command Reference',
55 'Name': 'Mercurial Command Reference',
52 },
56 },
53 # hgignore.5.html
57 # hgignore.5.html
54 'hg.file.5757d8e0_f207_5e10_a2ec_3ba0a062f431': {
58 'hg.file.5757d8e0_f207_5e10_a2ec_3ba0a062f431': {
55 'Name': 'Mercurial Ignore Files',
59 'Name': 'Mercurial Ignore Files',
56 },
60 },
57 # hgrc.5.html
61 # hgrc.5.html
58 'hg.file.92e605fd_1d1a_5dc6_9fc0_5d2998eb8f5e': {
62 'hg.file.92e605fd_1d1a_5dc6_9fc0_5d2998eb8f5e': {
59 'Name': 'Mercurial Configuration Files',
63 'Name': 'Mercurial Configuration Files',
60 },
64 },
61 }
65 }
62
66
63
67
64 def find_version(source_dir: pathlib.Path):
68 def find_version(source_dir: pathlib.Path):
65 version_py = source_dir / 'mercurial' / '__version__.py'
69 version_py = source_dir / 'mercurial' / '__version__.py'
66
70
67 with version_py.open('r', encoding='utf-8') as fh:
71 with version_py.open('r', encoding='utf-8') as fh:
68 source = fh.read().strip()
72 source = fh.read().strip()
69
73
70 m = re.search('version = b"(.*)"', source)
74 m = re.search('version = b"(.*)"', source)
71 return m.group(1)
75 return m.group(1)
72
76
73
77
74 def normalize_version(version):
75 """Normalize Mercurial version string so WiX accepts it.
76
77 Version strings have to be numeric X.Y.Z.
78 """
79
80 if '+' in version:
81 version, extra = version.split('+', 1)
82 else:
83 extra = None
84
85 # 4.9rc0
86 if version[:-1].endswith('rc'):
87 version = version[:-3]
88
89 versions = [int(v) for v in version.split('.')]
90 while len(versions) < 3:
91 versions.append(0)
92
93 major, minor, build = versions[:3]
94
95 if extra:
96 # <commit count>-<hash>+<date>
97 build = int(extra.split('-')[0])
98
99 return '.'.join('%d' % x for x in (major, minor, build))
100
101
102 def ensure_vc90_merge_modules(build_dir):
78 def ensure_vc90_merge_modules(build_dir):
103 x86 = (
79 x86 = (
104 download_entry(
80 download_entry(
105 'vc9-crt-x86-msm',
81 'vc9-crt-x86-msm',
106 build_dir,
82 build_dir,
107 local_name='microsoft.vcxx.crt.x86_msm.msm',
83 local_name='microsoft.vcxx.crt.x86_msm.msm',
108 )[0],
84 )[0],
109 download_entry(
85 download_entry(
110 'vc9-crt-x86-msm-policy',
86 'vc9-crt-x86-msm-policy',
111 build_dir,
87 build_dir,
112 local_name='policy.x.xx.microsoft.vcxx.crt.x86_msm.msm',
88 local_name='policy.x.xx.microsoft.vcxx.crt.x86_msm.msm',
113 )[0],
89 )[0],
114 )
90 )
115
91
116 x64 = (
92 x64 = (
117 download_entry(
93 download_entry(
118 'vc9-crt-x64-msm',
94 'vc9-crt-x64-msm',
119 build_dir,
95 build_dir,
120 local_name='microsoft.vcxx.crt.x64_msm.msm',
96 local_name='microsoft.vcxx.crt.x64_msm.msm',
121 )[0],
97 )[0],
122 download_entry(
98 download_entry(
123 'vc9-crt-x64-msm-policy',
99 'vc9-crt-x64-msm-policy',
124 build_dir,
100 build_dir,
125 local_name='policy.x.xx.microsoft.vcxx.crt.x64_msm.msm',
101 local_name='policy.x.xx.microsoft.vcxx.crt.x64_msm.msm',
126 )[0],
102 )[0],
127 )
103 )
128 return {
104 return {
129 'x86': x86,
105 'x86': x86,
130 'x64': x64,
106 'x64': x64,
131 }
107 }
132
108
133
109
134 def run_candle(wix, cwd, wxs, source_dir, defines=None):
110 def run_candle(wix, cwd, wxs, source_dir, defines=None):
135 args = [
111 args = [
136 str(wix / 'candle.exe'),
112 str(wix / 'candle.exe'),
137 '-nologo',
113 '-nologo',
138 str(wxs),
114 str(wxs),
139 '-dSourceDir=%s' % source_dir,
115 '-dSourceDir=%s' % source_dir,
140 ]
116 ]
141
117
142 if defines:
118 if defines:
143 args.extend('-d%s=%s' % define for define in sorted(defines.items()))
119 args.extend('-d%s=%s' % define for define in sorted(defines.items()))
144
120
145 subprocess.run(args, cwd=str(cwd), check=True)
121 subprocess.run(args, cwd=str(cwd), check=True)
146
122
147
123
148 def make_post_build_signing_fn(
124 def make_post_build_signing_fn(
149 name,
125 name,
150 subject_name=None,
126 subject_name=None,
151 cert_path=None,
127 cert_path=None,
152 cert_password=None,
128 cert_password=None,
153 timestamp_url=None,
129 timestamp_url=None,
154 ):
130 ):
155 """Create a callable that will use signtool to sign hg.exe."""
131 """Create a callable that will use signtool to sign hg.exe."""
156
132
157 def post_build_sign(source_dir, build_dir, dist_dir, version):
133 def post_build_sign(source_dir, build_dir, dist_dir, version):
158 description = '%s %s' % (name, version)
134 description = '%s %s' % (name, version)
159
135
160 sign_with_signtool(
136 sign_with_signtool(
161 dist_dir / 'hg.exe',
137 dist_dir / 'hg.exe',
162 description,
138 description,
163 subject_name=subject_name,
139 subject_name=subject_name,
164 cert_path=cert_path,
140 cert_path=cert_path,
165 cert_password=cert_password,
141 cert_password=cert_password,
166 timestamp_url=timestamp_url,
142 timestamp_url=timestamp_url,
167 )
143 )
168
144
169 return post_build_sign
145 return post_build_sign
170
146
171
147
172 def make_files_xml(staging_dir: pathlib.Path, is_x64) -> str:
148 def make_files_xml(staging_dir: pathlib.Path, is_x64) -> str:
173 """Create XML string listing every file to be installed."""
149 """Create XML string listing every file to be installed."""
174
150
175 # We derive GUIDs from a deterministic file path identifier.
151 # We derive GUIDs from a deterministic file path identifier.
176 # We shoehorn the name into something that looks like a URL because
152 # We shoehorn the name into something that looks like a URL because
177 # the UUID namespaces are supposed to work that way (even though
153 # the UUID namespaces are supposed to work that way (even though
178 # the input data probably is never validated).
154 # the input data probably is never validated).
179
155
180 doc = xml.dom.minidom.parseString(
156 doc = xml.dom.minidom.parseString(
181 '<?xml version="1.0" encoding="utf-8"?>'
157 '<?xml version="1.0" encoding="utf-8"?>'
182 '<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">'
158 '<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">'
183 '</Wix>'
159 '</Wix>'
184 )
160 )
185
161
186 # Assemble the install layout by directory. This makes it easier to
162 # Assemble the install layout by directory. This makes it easier to
187 # emit XML, since each directory has separate entities.
163 # emit XML, since each directory has separate entities.
188 manifest = collections.defaultdict(dict)
164 manifest = collections.defaultdict(dict)
189
165
190 for root, dirs, files in os.walk(staging_dir):
166 for root, dirs, files in os.walk(staging_dir):
191 dirs.sort()
167 dirs.sort()
192
168
193 root = pathlib.Path(root)
169 root = pathlib.Path(root)
194 rel_dir = root.relative_to(staging_dir)
170 rel_dir = root.relative_to(staging_dir)
195
171
196 for i in range(len(rel_dir.parts)):
172 for i in range(len(rel_dir.parts)):
197 parent = '/'.join(rel_dir.parts[0 : i + 1])
173 parent = '/'.join(rel_dir.parts[0 : i + 1])
198 manifest.setdefault(parent, {})
174 manifest.setdefault(parent, {})
199
175
200 for f in sorted(files):
176 for f in sorted(files):
201 full = root / f
177 full = root / f
202 manifest[str(rel_dir).replace('\\', '/')][full.name] = full
178 manifest[str(rel_dir).replace('\\', '/')][full.name] = full
203
179
204 component_groups = collections.defaultdict(list)
180 component_groups = collections.defaultdict(list)
205
181
206 # Now emit a <Fragment> for each directory.
182 # Now emit a <Fragment> for each directory.
207 # Each directory is composed of a <DirectoryRef> pointing to its parent
183 # Each directory is composed of a <DirectoryRef> pointing to its parent
208 # and defines child <Directory>'s and a <Component> with all the files.
184 # and defines child <Directory>'s and a <Component> with all the files.
209 for dir_name, entries in sorted(manifest.items()):
185 for dir_name, entries in sorted(manifest.items()):
210 # The directory id is derived from the path. But the root directory
186 # The directory id is derived from the path. But the root directory
211 # is special.
187 # is special.
212 if dir_name == '.':
188 if dir_name == '.':
213 parent_directory_id = 'INSTALLDIR'
189 parent_directory_id = 'INSTALLDIR'
214 else:
190 else:
215 parent_directory_id = 'hg.dir.%s' % dir_name.replace('/', '.')
191 parent_directory_id = 'hg.dir.%s' % dir_name.replace('/', '.')
216
192
217 fragment = doc.createElement('Fragment')
193 fragment = doc.createElement('Fragment')
218 directory_ref = doc.createElement('DirectoryRef')
194 directory_ref = doc.createElement('DirectoryRef')
219 directory_ref.setAttribute('Id', parent_directory_id)
195 directory_ref.setAttribute('Id', parent_directory_id)
220
196
221 # Add <Directory> entries for immediate children directories.
197 # Add <Directory> entries for immediate children directories.
222 for possible_child in sorted(manifest.keys()):
198 for possible_child in sorted(manifest.keys()):
223 if (
199 if (
224 dir_name == '.'
200 dir_name == '.'
225 and '/' not in possible_child
201 and '/' not in possible_child
226 and possible_child != '.'
202 and possible_child != '.'
227 ):
203 ):
228 child_directory_id = 'hg.dir.%s' % possible_child
204 child_directory_id = 'hg.dir.%s' % possible_child
229 name = possible_child
205 name = possible_child
230 else:
206 else:
231 if not possible_child.startswith('%s/' % dir_name):
207 if not possible_child.startswith('%s/' % dir_name):
232 continue
208 continue
233 name = possible_child[len(dir_name) + 1 :]
209 name = possible_child[len(dir_name) + 1 :]
234 if '/' in name:
210 if '/' in name:
235 continue
211 continue
236
212
237 child_directory_id = 'hg.dir.%s' % possible_child.replace(
213 child_directory_id = 'hg.dir.%s' % possible_child.replace(
238 '/', '.'
214 '/', '.'
239 )
215 )
240
216
241 directory = doc.createElement('Directory')
217 directory = doc.createElement('Directory')
242 directory.setAttribute('Id', child_directory_id)
218 directory.setAttribute('Id', child_directory_id)
243 directory.setAttribute('Name', name)
219 directory.setAttribute('Name', name)
244 directory_ref.appendChild(directory)
220 directory_ref.appendChild(directory)
245
221
246 # Add <Component>s for files in this directory.
222 # Add <Component>s for files in this directory.
247 for rel, source_path in sorted(entries.items()):
223 for rel, source_path in sorted(entries.items()):
248 if dir_name == '.':
224 if dir_name == '.':
249 full_rel = rel
225 full_rel = rel
250 else:
226 else:
251 full_rel = '%s/%s' % (dir_name, rel)
227 full_rel = '%s/%s' % (dir_name, rel)
252
228
253 component_unique_id = (
229 component_unique_id = (
254 'https://www.mercurial-scm.org/wix-installer/0/component/%s'
230 'https://www.mercurial-scm.org/wix-installer/0/component/%s'
255 % full_rel
231 % full_rel
256 )
232 )
257 component_guid = uuid.uuid5(uuid.NAMESPACE_URL, component_unique_id)
233 component_guid = uuid.uuid5(uuid.NAMESPACE_URL, component_unique_id)
258 component_id = 'hg.component.%s' % str(component_guid).replace(
234 component_id = 'hg.component.%s' % str(component_guid).replace(
259 '-', '_'
235 '-', '_'
260 )
236 )
261
237
262 component = doc.createElement('Component')
238 component = doc.createElement('Component')
263
239
264 component.setAttribute('Id', component_id)
240 component.setAttribute('Id', component_id)
265 component.setAttribute('Guid', str(component_guid).upper())
241 component.setAttribute('Guid', str(component_guid).upper())
266 component.setAttribute('Win64', 'yes' if is_x64 else 'no')
242 component.setAttribute('Win64', 'yes' if is_x64 else 'no')
267
243
268 # Assign this component to a top-level group.
244 # Assign this component to a top-level group.
269 if dir_name == '.':
245 if dir_name == '.':
270 component_groups['ROOT'].append(component_id)
246 component_groups['ROOT'].append(component_id)
271 elif '/' in dir_name:
247 elif '/' in dir_name:
272 component_groups[dir_name[0 : dir_name.index('/')]].append(
248 component_groups[dir_name[0 : dir_name.index('/')]].append(
273 component_id
249 component_id
274 )
250 )
275 else:
251 else:
276 component_groups[dir_name].append(component_id)
252 component_groups[dir_name].append(component_id)
277
253
278 unique_id = (
254 unique_id = (
279 'https://www.mercurial-scm.org/wix-installer/0/%s' % full_rel
255 'https://www.mercurial-scm.org/wix-installer/0/%s' % full_rel
280 )
256 )
281 file_guid = uuid.uuid5(uuid.NAMESPACE_URL, unique_id)
257 file_guid = uuid.uuid5(uuid.NAMESPACE_URL, unique_id)
282
258
283 # IDs have length limits. So use GUID to derive them.
259 # IDs have length limits. So use GUID to derive them.
284 file_guid_normalized = str(file_guid).replace('-', '_')
260 file_guid_normalized = str(file_guid).replace('-', '_')
285 file_id = 'hg.file.%s' % file_guid_normalized
261 file_id = 'hg.file.%s' % file_guid_normalized
286
262
287 file_element = doc.createElement('File')
263 file_element = doc.createElement('File')
288 file_element.setAttribute('Id', file_id)
264 file_element.setAttribute('Id', file_id)
289 file_element.setAttribute('Source', str(source_path))
265 file_element.setAttribute('Source', str(source_path))
290 file_element.setAttribute('KeyPath', 'yes')
266 file_element.setAttribute('KeyPath', 'yes')
291 file_element.setAttribute('ReadOnly', 'yes')
267 file_element.setAttribute('ReadOnly', 'yes')
292
268
293 component.appendChild(file_element)
269 component.appendChild(file_element)
294 directory_ref.appendChild(component)
270 directory_ref.appendChild(component)
295
271
296 fragment.appendChild(directory_ref)
272 fragment.appendChild(directory_ref)
297 doc.documentElement.appendChild(fragment)
273 doc.documentElement.appendChild(fragment)
298
274
299 for group, component_ids in sorted(component_groups.items()):
275 for group, component_ids in sorted(component_groups.items()):
300 fragment = doc.createElement('Fragment')
276 fragment = doc.createElement('Fragment')
301 component_group = doc.createElement('ComponentGroup')
277 component_group = doc.createElement('ComponentGroup')
302 component_group.setAttribute('Id', 'hg.group.%s' % group)
278 component_group.setAttribute('Id', 'hg.group.%s' % group)
303
279
304 for component_id in component_ids:
280 for component_id in component_ids:
305 component_ref = doc.createElement('ComponentRef')
281 component_ref = doc.createElement('ComponentRef')
306 component_ref.setAttribute('Id', component_id)
282 component_ref.setAttribute('Id', component_id)
307 component_group.appendChild(component_ref)
283 component_group.appendChild(component_ref)
308
284
309 fragment.appendChild(component_group)
285 fragment.appendChild(component_group)
310 doc.documentElement.appendChild(fragment)
286 doc.documentElement.appendChild(fragment)
311
287
312 # Add <Shortcut> to files that have it defined.
288 # Add <Shortcut> to files that have it defined.
313 for file_id, metadata in sorted(SHORTCUTS.items()):
289 for file_id, metadata in sorted(SHORTCUTS.items()):
314 els = doc.getElementsByTagName('File')
290 els = doc.getElementsByTagName('File')
315 els = [el for el in els if el.getAttribute('Id') == file_id]
291 els = [el for el in els if el.getAttribute('Id') == file_id]
316
292
317 if not els:
293 if not els:
318 raise Exception('could not find File[Id=%s]' % file_id)
294 raise Exception('could not find File[Id=%s]' % file_id)
319
295
320 for el in els:
296 for el in els:
321 shortcut = doc.createElement('Shortcut')
297 shortcut = doc.createElement('Shortcut')
322 shortcut.setAttribute('Id', 'hg.shortcut.%s' % file_id)
298 shortcut.setAttribute('Id', 'hg.shortcut.%s' % file_id)
323 shortcut.setAttribute('Directory', 'ProgramMenuDir')
299 shortcut.setAttribute('Directory', 'ProgramMenuDir')
324 shortcut.setAttribute('Icon', 'hgIcon.ico')
300 shortcut.setAttribute('Icon', 'hgIcon.ico')
325 shortcut.setAttribute('IconIndex', '0')
301 shortcut.setAttribute('IconIndex', '0')
326 shortcut.setAttribute('Advertise', 'yes')
302 shortcut.setAttribute('Advertise', 'yes')
327 for k, v in sorted(metadata.items()):
303 for k, v in sorted(metadata.items()):
328 shortcut.setAttribute(k, v)
304 shortcut.setAttribute(k, v)
329
305
330 el.appendChild(shortcut)
306 el.appendChild(shortcut)
331
307
332 return doc.toprettyxml()
308 return doc.toprettyxml()
333
309
334
310
335 def build_installer(
311 def build_installer(
336 source_dir: pathlib.Path,
312 source_dir: pathlib.Path,
337 python_exe: pathlib.Path,
313 python_exe: pathlib.Path,
338 msi_name='mercurial',
314 msi_name='mercurial',
339 version=None,
315 version=None,
340 post_build_fn=None,
316 post_build_fn=None,
341 extra_packages_script=None,
317 extra_packages_script=None,
342 extra_wxs: typing.Optional[typing.Dict[str, str]] = None,
318 extra_wxs: typing.Optional[typing.Dict[str, str]] = None,
343 extra_features: typing.Optional[typing.List[str]] = None,
319 extra_features: typing.Optional[typing.List[str]] = None,
344 ):
320 ):
345 """Build a WiX MSI installer.
321 """Build a WiX MSI installer.
346
322
347 ``source_dir`` is the path to the Mercurial source tree to use.
323 ``source_dir`` is the path to the Mercurial source tree to use.
348 ``arch`` is the target architecture. either ``x86`` or ``x64``.
324 ``arch`` is the target architecture. either ``x86`` or ``x64``.
349 ``python_exe`` is the path to the Python executable to use/bundle.
325 ``python_exe`` is the path to the Python executable to use/bundle.
350 ``version`` is the Mercurial version string. If not defined,
326 ``version`` is the Mercurial version string. If not defined,
351 ``mercurial/__version__.py`` will be consulted.
327 ``mercurial/__version__.py`` will be consulted.
352 ``post_build_fn`` is a callable that will be called after building
328 ``post_build_fn`` is a callable that will be called after building
353 Mercurial but before invoking WiX. It can be used to e.g. facilitate
329 Mercurial but before invoking WiX. It can be used to e.g. facilitate
354 signing. It is passed the paths to the Mercurial source, build, and
330 signing. It is passed the paths to the Mercurial source, build, and
355 dist directories and the resolved Mercurial version.
331 dist directories and the resolved Mercurial version.
356 ``extra_packages_script`` is a command to be run to inject extra packages
332 ``extra_packages_script`` is a command to be run to inject extra packages
357 into the py2exe binary. It should stage packages into the virtualenv and
333 into the py2exe binary. It should stage packages into the virtualenv and
358 print a null byte followed by a newline-separated list of packages that
334 print a null byte followed by a newline-separated list of packages that
359 should be included in the exe.
335 should be included in the exe.
360 ``extra_wxs`` is a dict of {wxs_name: working_dir_for_wxs_build}.
336 ``extra_wxs`` is a dict of {wxs_name: working_dir_for_wxs_build}.
361 ``extra_features`` is a list of additional named Features to include in
337 ``extra_features`` is a list of additional named Features to include in
362 the build. These must match Feature names in one of the wxs scripts.
338 the build. These must match Feature names in one of the wxs scripts.
363 """
339 """
364 arch = 'x64' if r'\x64' in os.environ.get('LIB', '') else 'x86'
340 arch = 'x64' if r'\x64' in os.environ.get('LIB', '') else 'x86'
365
341
366 hg_build_dir = source_dir / 'build'
342 hg_build_dir = source_dir / 'build'
367 dist_dir = source_dir / 'dist'
343 dist_dir = source_dir / 'dist'
368 wix_dir = source_dir / 'contrib' / 'packaging' / 'wix'
344 wix_dir = source_dir / 'contrib' / 'packaging' / 'wix'
369
345
370 requirements_txt = wix_dir / 'requirements.txt'
346 requirements_txt = 'requirements_win32.txt'
371
347
372 build_py2exe(
348 build_py2exe(
373 source_dir,
349 source_dir,
374 hg_build_dir,
350 hg_build_dir,
375 python_exe,
351 python_exe,
376 'wix',
352 'wix',
377 requirements_txt,
353 requirements_txt,
378 extra_packages=EXTRA_PACKAGES,
354 extra_packages=EXTRA_PACKAGES,
379 extra_packages_script=extra_packages_script,
355 extra_packages_script=extra_packages_script,
380 )
356 )
381
357
382 version = version or normalize_version(find_version(source_dir))
358 orig_version = version or find_version(source_dir)
359 version = normalize_windows_version(orig_version)
383 print('using version string: %s' % version)
360 print('using version string: %s' % version)
361 if version != orig_version:
362 print('(normalized from: %s)' % orig_version)
384
363
385 if post_build_fn:
364 if post_build_fn:
386 post_build_fn(source_dir, hg_build_dir, dist_dir, version)
365 post_build_fn(source_dir, hg_build_dir, dist_dir, version)
387
366
388 build_dir = hg_build_dir / ('wix-%s' % arch)
367 build_dir = hg_build_dir / ('wix-%s' % arch)
389 staging_dir = build_dir / 'stage'
368 staging_dir = build_dir / 'stage'
390
369
391 build_dir.mkdir(exist_ok=True)
370 build_dir.mkdir(exist_ok=True)
392
371
393 # Purge the staging directory for every build so packaging is pristine.
372 # Purge the staging directory for every build so packaging is pristine.
394 if staging_dir.exists():
373 if staging_dir.exists():
395 print('purging %s' % staging_dir)
374 print('purging %s' % staging_dir)
396 shutil.rmtree(staging_dir)
375 shutil.rmtree(staging_dir)
397
376
398 stage_install(source_dir, staging_dir, lower_case=True)
377 stage_install(source_dir, staging_dir, lower_case=True)
399
378
400 # We also install some extra files.
379 # We also install some extra files.
401 process_install_rules(EXTRA_INSTALL_RULES, source_dir, staging_dir)
380 process_install_rules(EXTRA_INSTALL_RULES, source_dir, staging_dir)
402
381
403 # And remove some files we don't want.
382 # And remove some files we don't want.
404 for f in STAGING_REMOVE_FILES:
383 for f in STAGING_REMOVE_FILES:
405 p = staging_dir / f
384 p = staging_dir / f
406 if p.exists():
385 if p.exists():
407 print('removing %s' % p)
386 print('removing %s' % p)
408 p.unlink()
387 p.unlink()
409
388
410 wix_pkg, wix_entry = download_entry('wix', hg_build_dir)
389 wix_pkg, wix_entry = download_entry('wix', hg_build_dir)
411 wix_path = hg_build_dir / ('wix-%s' % wix_entry['version'])
390 wix_path = hg_build_dir / ('wix-%s' % wix_entry['version'])
412
391
413 if not wix_path.exists():
392 if not wix_path.exists():
414 extract_zip_to_directory(wix_pkg, wix_path)
393 extract_zip_to_directory(wix_pkg, wix_path)
415
394
416 ensure_vc90_merge_modules(hg_build_dir)
395 ensure_vc90_merge_modules(hg_build_dir)
417
396
418 source_build_rel = pathlib.Path(os.path.relpath(source_dir, build_dir))
397 source_build_rel = pathlib.Path(os.path.relpath(source_dir, build_dir))
419
398
420 defines = {'Platform': arch}
399 defines = {'Platform': arch}
421
400
422 # Derive a .wxs file with the staged files.
401 # Derive a .wxs file with the staged files.
423 manifest_wxs = build_dir / 'stage.wxs'
402 manifest_wxs = build_dir / 'stage.wxs'
424 with manifest_wxs.open('w', encoding='utf-8') as fh:
403 with manifest_wxs.open('w', encoding='utf-8') as fh:
425 fh.write(make_files_xml(staging_dir, is_x64=arch == 'x64'))
404 fh.write(make_files_xml(staging_dir, is_x64=arch == 'x64'))
426
405
427 run_candle(wix_path, build_dir, manifest_wxs, staging_dir, defines=defines)
406 run_candle(wix_path, build_dir, manifest_wxs, staging_dir, defines=defines)
428
407
429 for source, rel_path in sorted((extra_wxs or {}).items()):
408 for source, rel_path in sorted((extra_wxs or {}).items()):
430 run_candle(wix_path, build_dir, source, rel_path, defines=defines)
409 run_candle(wix_path, build_dir, source, rel_path, defines=defines)
431
410
432 source = wix_dir / 'mercurial.wxs'
411 source = wix_dir / 'mercurial.wxs'
433 defines['Version'] = version
412 defines['Version'] = version
434 defines['Comments'] = 'Installs Mercurial version %s' % version
413 defines['Comments'] = 'Installs Mercurial version %s' % version
435 defines['VCRedistSrcDir'] = str(hg_build_dir)
414 defines['VCRedistSrcDir'] = str(hg_build_dir)
436 if extra_features:
415 if extra_features:
437 assert all(';' not in f for f in extra_features)
416 assert all(';' not in f for f in extra_features)
438 defines['MercurialExtraFeatures'] = ';'.join(extra_features)
417 defines['MercurialExtraFeatures'] = ';'.join(extra_features)
439
418
440 run_candle(wix_path, build_dir, source, source_build_rel, defines=defines)
419 run_candle(wix_path, build_dir, source, source_build_rel, defines=defines)
441
420
442 msi_path = (
421 msi_path = (
443 source_dir / 'dist' / ('%s-%s-%s.msi' % (msi_name, version, arch))
422 source_dir / 'dist' / ('%s-%s-%s.msi' % (msi_name, orig_version, arch))
444 )
423 )
445
424
446 args = [
425 args = [
447 str(wix_path / 'light.exe'),
426 str(wix_path / 'light.exe'),
448 '-nologo',
427 '-nologo',
449 '-ext',
428 '-ext',
450 'WixUIExtension',
429 'WixUIExtension',
451 '-sw1076',
430 '-sw1076',
452 '-spdb',
431 '-spdb',
453 '-o',
432 '-o',
454 str(msi_path),
433 str(msi_path),
455 ]
434 ]
456
435
457 for source, rel_path in sorted((extra_wxs or {}).items()):
436 for source, rel_path in sorted((extra_wxs or {}).items()):
458 assert source.endswith('.wxs')
437 assert source.endswith('.wxs')
459 source = os.path.basename(source)
438 source = os.path.basename(source)
460 args.append(str(build_dir / ('%s.wixobj' % source[:-4])))
439 args.append(str(build_dir / ('%s.wixobj' % source[:-4])))
461
440
462 args.extend(
441 args.extend(
463 [str(build_dir / 'stage.wixobj'), str(build_dir / 'mercurial.wixobj'),]
442 [str(build_dir / 'stage.wixobj'), str(build_dir / 'mercurial.wixobj'),]
464 )
443 )
465
444
466 subprocess.run(args, cwd=str(source_dir), check=True)
445 subprocess.run(args, cwd=str(source_dir), check=True)
467
446
468 print('%s created' % msi_path)
447 print('%s created' % msi_path)
469
448
470 return {
449 return {
471 'msi_path': msi_path,
450 'msi_path': msi_path,
472 }
451 }
473
452
474
453
475 def build_signed_installer(
454 def build_signed_installer(
476 source_dir: pathlib.Path,
455 source_dir: pathlib.Path,
477 python_exe: pathlib.Path,
456 python_exe: pathlib.Path,
478 name: str,
457 name: str,
479 version=None,
458 version=None,
480 subject_name=None,
459 subject_name=None,
481 cert_path=None,
460 cert_path=None,
482 cert_password=None,
461 cert_password=None,
483 timestamp_url=None,
462 timestamp_url=None,
484 extra_packages_script=None,
463 extra_packages_script=None,
485 extra_wxs=None,
464 extra_wxs=None,
486 extra_features=None,
465 extra_features=None,
487 ):
466 ):
488 """Build an installer with signed executables."""
467 """Build an installer with signed executables."""
489
468
490 post_build_fn = make_post_build_signing_fn(
469 post_build_fn = make_post_build_signing_fn(
491 name,
470 name,
492 subject_name=subject_name,
471 subject_name=subject_name,
493 cert_path=cert_path,
472 cert_path=cert_path,
494 cert_password=cert_password,
473 cert_password=cert_password,
495 timestamp_url=timestamp_url,
474 timestamp_url=timestamp_url,
496 )
475 )
497
476
498 info = build_installer(
477 info = build_installer(
499 source_dir,
478 source_dir,
500 python_exe=python_exe,
479 python_exe=python_exe,
501 msi_name=name.lower(),
480 msi_name=name.lower(),
502 version=version,
481 version=version,
503 post_build_fn=post_build_fn,
482 post_build_fn=post_build_fn,
504 extra_packages_script=extra_packages_script,
483 extra_packages_script=extra_packages_script,
505 extra_wxs=extra_wxs,
484 extra_wxs=extra_wxs,
506 extra_features=extra_features,
485 extra_features=extra_features,
507 )
486 )
508
487
509 description = '%s %s' % (name, version)
488 description = '%s %s' % (name, version)
510
489
511 sign_with_signtool(
490 sign_with_signtool(
512 info['msi_path'],
491 info['msi_path'],
513 description,
492 description,
514 subject_name=subject_name,
493 subject_name=subject_name,
515 cert_path=cert_path,
494 cert_path=cert_path,
516 cert_password=cert_password,
495 cert_password=cert_password,
517 timestamp_url=timestamp_url,
496 timestamp_url=timestamp_url,
518 )
497 )
@@ -1,82 +1,83 b''
1 ; Script generated by the Inno Setup Script Wizard.
1 ; Script generated by the Inno Setup Script Wizard.
2 ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
2 ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
3
3
4 #ifndef ARCH
4 #ifndef ARCH
5 #define ARCH = "x86"
5 #define ARCH = "x86"
6 #endif
6 #endif
7
7
8 [Setup]
8 [Setup]
9 AppCopyright=Copyright 2005-2019 Matt Mackall and others
9 AppCopyright=Copyright 2005-2020 Matt Mackall and others
10 AppName=Mercurial
10 AppName=Mercurial
11 AppVersion={#VERSION}
11 AppVersion={#VERSION}
12 #if ARCH == "x64"
12 #if ARCH == "x64"
13 AppVerName=Mercurial {#VERSION} (64-bit)
13 AppVerName=Mercurial {#VERSION} (64-bit)
14 OutputBaseFilename=Mercurial-{#VERSION}-x64
14 OutputBaseFilename=Mercurial-{#VERSION}-x64
15 ArchitecturesAllowed=x64
15 ArchitecturesAllowed=x64
16 ArchitecturesInstallIn64BitMode=x64
16 ArchitecturesInstallIn64BitMode=x64
17 #else
17 #else
18 AppVerName=Mercurial {#VERSION}
18 AppVerName=Mercurial {#VERSION}
19 OutputBaseFilename=Mercurial-{#VERSION}
19 OutputBaseFilename=Mercurial-{#VERSION}
20 #endif
20 #endif
21 InfoAfterFile=../postinstall.txt
21 InfoAfterFile=../postinstall.txt
22 LicenseFile=Copying.txt
22 LicenseFile=Copying.txt
23 ShowLanguageDialog=yes
23 ShowLanguageDialog=yes
24 AppPublisher=Matt Mackall and others
24 AppPublisher=Matt Mackall and others
25 AppPublisherURL=https://mercurial-scm.org/
25 AppPublisherURL=https://mercurial-scm.org/
26 AppSupportURL=https://mercurial-scm.org/
26 AppSupportURL=https://mercurial-scm.org/
27 AppUpdatesURL=https://mercurial-scm.org/
27 AppUpdatesURL=https://mercurial-scm.org/
28 {{ 'AppID={{4B95A5F1-EF59-4B08-BED8-C891C46121B3}' }}
28 {{ 'AppID={{4B95A5F1-EF59-4B08-BED8-C891C46121B3}' }}
29 AppContact=mercurial@mercurial-scm.org
29 AppContact=mercurial@mercurial-scm.org
30 DefaultDirName={pf}\Mercurial
30 DefaultDirName={pf}\Mercurial
31 SourceDir=stage
31 SourceDir=stage
32 VersionInfoDescription=Mercurial distributed SCM (version {#VERSION})
32 VersionInfoDescription=Mercurial distributed SCM (version {#VERSION})
33 VersionInfoCopyright=Copyright 2005-2019 Matt Mackall and others
33 VersionInfoCopyright=Copyright 2005-2020 Matt Mackall and others
34 VersionInfoCompany=Matt Mackall and others
34 VersionInfoCompany=Matt Mackall and others
35 VersionInfoVersion={#QUAD_VERSION}
35 InternalCompressLevel=max
36 InternalCompressLevel=max
36 SolidCompression=true
37 SolidCompression=true
37 SetupIconFile=../mercurial.ico
38 SetupIconFile=../mercurial.ico
38 AllowNoIcons=true
39 AllowNoIcons=true
39 DefaultGroupName=Mercurial
40 DefaultGroupName=Mercurial
40 PrivilegesRequired=none
41 PrivilegesRequired=none
41 ChangesEnvironment=true
42 ChangesEnvironment=true
42
43
43 [Files]
44 [Files]
44 {% for entry in package_files -%}
45 {% for entry in package_files -%}
45 Source: {{ entry.source }}; DestDir: {{ entry.dest_dir }}
46 Source: {{ entry.source }}; DestDir: {{ entry.dest_dir }}
46 {%- if entry.metadata %}; {{ entry.metadata }}{% endif %}
47 {%- if entry.metadata %}; {{ entry.metadata }}{% endif %}
47 {% endfor %}
48 {% endfor %}
48
49
49 [INI]
50 [INI]
50 Filename: {app}\Mercurial.url; Section: InternetShortcut; Key: URL; String: https://mercurial-scm.org/
51 Filename: {app}\Mercurial.url; Section: InternetShortcut; Key: URL; String: https://mercurial-scm.org/
51
52
52 [UninstallDelete]
53 [UninstallDelete]
53 Type: files; Name: {app}\Mercurial.url
54 Type: files; Name: {app}\Mercurial.url
54 Type: filesandordirs; Name: {app}\defaultrc
55 Type: filesandordirs; Name: {app}\defaultrc
55
56
56 [Icons]
57 [Icons]
57 Name: {group}\Uninstall Mercurial; Filename: {uninstallexe}
58 Name: {group}\Uninstall Mercurial; Filename: {uninstallexe}
58 Name: {group}\Mercurial Command Reference; Filename: {app}\Docs\hg.1.html
59 Name: {group}\Mercurial Command Reference; Filename: {app}\Docs\hg.1.html
59 Name: {group}\Mercurial Configuration Files; Filename: {app}\Docs\hgrc.5.html
60 Name: {group}\Mercurial Configuration Files; Filename: {app}\Docs\hgrc.5.html
60 Name: {group}\Mercurial Ignore Files; Filename: {app}\Docs\hgignore.5.html
61 Name: {group}\Mercurial Ignore Files; Filename: {app}\Docs\hgignore.5.html
61 Name: {group}\Mercurial Web Site; Filename: {app}\Mercurial.url
62 Name: {group}\Mercurial Web Site; Filename: {app}\Mercurial.url
62
63
63 [Tasks]
64 [Tasks]
64 Name: modifypath; Description: Add the installation path to the search path; Flags: unchecked
65 Name: modifypath; Description: Add the installation path to the search path; Flags: unchecked
65
66
66 [Code]
67 [Code]
67 procedure Touch(fn: String);
68 procedure Touch(fn: String);
68 begin
69 begin
69 SaveStringToFile(ExpandConstant(fn), '', False);
70 SaveStringToFile(ExpandConstant(fn), '', False);
70 end;
71 end;
71
72
72 const
73 const
73 ModPathName = 'modifypath';
74 ModPathName = 'modifypath';
74 ModPathType = 'user';
75 ModPathType = 'user';
75
76
76 function ModPathDir(): TArrayOfString;
77 function ModPathDir(): TArrayOfString;
77 begin
78 begin
78 setArrayLength(Result, 1)
79 setArrayLength(Result, 1)
79 Result[0] := ExpandConstant('{app}');
80 Result[0] := ExpandConstant('{app}');
80 end;
81 end;
81
82
82 {% include 'modpath.iss' %}
83 {% include 'modpath.iss' %}
@@ -1,13 +1,45 b''
1 #
1 #
2 # This file is autogenerated by pip-compile
2 # This file is autogenerated by pip-compile
3 # To update, run:
3 # To update, run:
4 #
4 #
5 # pip-compile --generate-hashes --output-file=contrib/packaging/wix/requirements.txt contrib/packaging/wix/requirements.txt.in
5 # pip-compile --generate-hashes --output-file=contrib/packaging/requirements_win32.txt contrib/packaging/requirements_win32.txt.in
6 #
6 #
7 certifi==2019.9.11 \
8 --hash=sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50 \
9 --hash=sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef \
10 # via dulwich
11 configparser==4.0.2 \
12 --hash=sha256:254c1d9c79f60c45dfde850850883d5aaa7f19a23f13561243a050d5a7c3fe4c \
13 --hash=sha256:c7d282687a5308319bf3d2e7706e575c635b0a470342641c93bea0ea3b5331df \
14 # via entrypoints
7 docutils==0.15.2 \
15 docutils==0.15.2 \
8 --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \
16 --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \
9 --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \
17 --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \
10 --hash=sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99
18 --hash=sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99
19 dulwich==0.19.13 \
20 --hash=sha256:0e442f6f96e6d97270a7cca4e75306b6b0228627bdf57dde3759e0e345a6b523 \
21 --hash=sha256:667f49536ccba09d3b90bac80d44048e45566f84b98a5e139cc8c70757a6ae60 \
22 --hash=sha256:82792a9d49b112fa2151fa0fb29b01667855a843ff99325b1c1578a4aec11b57 \
23 --hash=sha256:aa628449c5f594a9a282f4d9e5993fef65481ef5e3b9b6c52ff31200f8f5dc95 \
24 --hash=sha256:ab4668bc4e1996d12eb1910e123a09edcff8e166e7ec46db5aafb5c7e250b99f \
25 --hash=sha256:c35ed2cd5b263ce0d67758ffba590c0466ff13b048457ff060b7d2e6cb55a40e \
26 --hash=sha256:c8b48079a14850cbeb788b38e1061ae6db75061431c1c0f91382460be4c84bbe \
27 --hash=sha256:dfcd9943c69f963dd61a027f480d16f548ea5905c2485be8f4b8f130df2c32de \
28 --hash=sha256:e3693c3238c1a5fc1e4427281c4455d78549f4797f2a7107a5f4443b21efafb4
29 entrypoints==0.3 \
30 --hash=sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19 \
31 --hash=sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451 \
32 # via keyring
33 keyring==18.0.1 \
34 --hash=sha256:67d6cc0132bd77922725fae9f18366bb314fd8f95ff4d323a4df41890a96a838 \
35 --hash=sha256:7b29ebfcf8678c4da531b2478a912eea01e80007e5ddca9ee0c7038cb3489ec6
11 pygments==2.4.2 \
36 pygments==2.4.2 \
12 --hash=sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127 \
37 --hash=sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127 \
13 --hash=sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297
38 --hash=sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297
39 pywin32-ctypes==0.2.0 \
40 --hash=sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942 \
41 --hash=sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98
42 urllib3==1.25.6 \
43 --hash=sha256:3de946ffbed6e6746608990594d08faac602528ac7015ac28d33cee6a45b7398 \
44 --hash=sha256:9a107b99a5393caf59c7aa3c1249c16e6879447533d0887f4336dde834c7be86 \
45 # via dulwich
@@ -1,2 +1,7 b''
1 docutils
1 docutils
2 dulwich
3 keyring
2 pygments
4 pygments
5 # Need to list explicitly so dependency gets pulled in when
6 # not running on Windows.
7 pywin32-ctypes
1 NO CONTENT: modified file, binary diff hidden
NO CONTENT: modified file, binary diff hidden
@@ -1,161 +1,161 b''
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2 <html>
2 <html>
3 <head>
3 <head>
4 <title>Mercurial for Windows</title>
4 <title>Mercurial for Windows</title>
5 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
5 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
6 <style type="text/css">
6 <style type="text/css">
7 <!--
7 <!--
8 html {
8 html {
9 font-family: sans-serif;
9 font-family: sans-serif;
10 margin: 1em 2em;
10 margin: 1em 2em;
11 }
11 }
12
12
13 p {
13 p {
14 margin-top: 0.5em;
14 margin-top: 0.5em;
15 margin-bottom: 0.5em;
15 margin-bottom: 0.5em;
16 }
16 }
17
17
18 pre {
18 pre {
19 margin: 0.25em 0em;
19 margin: 0.25em 0em;
20 padding: 0.5em;
20 padding: 0.5em;
21 background-color: #EEE;
21 background-color: #EEE;
22 border: thin solid #CCC;
22 border: thin solid #CCC;
23 }
23 }
24
24
25 .indented {
25 .indented {
26 padding-left: 10pt;
26 padding-left: 10pt;
27 }
27 }
28 -->
28 -->
29 </style>
29 </style>
30 </head>
30 </head>
31
31
32 <body>
32 <body>
33 <h1>Mercurial for Windows</h1>
33 <h1>Mercurial for Windows</h1>
34
34
35 <p>Welcome to Mercurial for Windows!</p>
35 <p>Welcome to Mercurial for Windows!</p>
36
36
37 <p>
37 <p>
38 Mercurial is a command-line application. You must run it from
38 Mercurial is a command-line application. You must run it from
39 the Windows command prompt (or if you're hard core, a <a
39 the Windows command prompt (or if you're hard core, a <a
40 href="http://www.mingw.org/">MinGW</a> shell).
40 href="http://www.mingw.org/">MinGW</a> shell).
41 </p>
41 </p>
42
42
43 <p class="indented">
43 <p class="indented">
44 <i>Note: the standard <a href="http://www.mingw.org/">MinGW</a>
44 <i>Note: the standard <a href="http://www.mingw.org/">MinGW</a>
45 msys startup script uses rxvt which has problems setting up
45 msys startup script uses rxvt which has problems setting up
46 standard input and output. Running bash directly works
46 standard input and output. Running bash directly works
47 correctly.</i>
47 correctly.</i>
48 </p>
48 </p>
49
49
50 <p>
50 <p>
51 For documentation, please visit the <a
51 For documentation, please visit the <a
52 href="https://mercurial-scm.org/">Mercurial web site</a>.
52 href="https://mercurial-scm.org/">Mercurial web site</a>.
53 You can also download a free book, <a
53 You can also download a free book, <a
54 href="https://book.mercurial-scm.org/">Mercurial: The Definitive
54 href="https://book.mercurial-scm.org/">Mercurial: The Definitive
55 Guide</a>.
55 Guide</a>.
56 </p>
56 </p>
57
57
58 <p>
58 <p>
59 By default, Mercurial installs to <tt>C:\Program
59 By default, Mercurial installs to <tt>C:\Program
60 Files\Mercurial</tt>. The Mercurial command is called
60 Files\Mercurial</tt>. The Mercurial command is called
61 <tt>hg.exe</tt>.
61 <tt>hg.exe</tt>.
62 </p>
62 </p>
63
63
64 <h1>Testing Mercurial after you've installed it</h1>
64 <h1>Testing Mercurial after you've installed it</h1>
65
65
66 <p>
66 <p>
67 The easiest way to check that Mercurial is installed properly is
67 The easiest way to check that Mercurial is installed properly is
68 to just type the following at the command prompt:
68 to just type the following at the command prompt:
69 </p>
69 </p>
70
70
71 <pre>
71 <pre>
72 hg
72 hg
73 </pre>
73 </pre>
74
74
75 <p>
75 <p>
76 This command should print a useful help message. If it does,
76 This command should print a useful help message. If it does,
77 other Mercurial commands should work fine for you.
77 other Mercurial commands should work fine for you.
78 </p>
78 </p>
79
79
80 <h1>Configuration notes</h1>
80 <h1>Configuration notes</h1>
81 <h4>Default editor</h4>
81 <h4>Default editor</h4>
82 <p>
82 <p>
83 The default editor for commit messages is 'notepad'. You can set
83 The default editor for commit messages is 'notepad'. You can set
84 the <tt>EDITOR</tt> (or <tt>HGEDITOR</tt>) environment variable
84 the <tt>EDITOR</tt> (or <tt>HGEDITOR</tt>) environment variable
85 to specify your preference or set it in <tt>mercurial.ini</tt>:
85 to specify your preference or set it in <tt>mercurial.ini</tt>:
86 </p>
86 </p>
87 <pre>
87 <pre>
88 [ui]
88 [ui]
89 editor = whatever
89 editor = whatever
90 </pre>
90 </pre>
91
91
92 <h4>Configuring a Merge program</h4>
92 <h4>Configuring a Merge program</h4>
93 <p>
93 <p>
94 It should be emphasized that Mercurial by itself doesn't attempt
94 It should be emphasized that Mercurial by itself doesn't attempt
95 to do a Merge at the file level, neither does it make any
95 to do a Merge at the file level, neither does it make any
96 attempt to Resolve the conflicts.
96 attempt to Resolve the conflicts.
97 </p>
97 </p>
98
98
99 <p>
99 <p>
100 By default, Mercurial will use the merge program defined by the
100 By default, Mercurial will use the merge program defined by the
101 <tt>HGMERGE</tt> environment variable, or uses the one defined
101 <tt>HGMERGE</tt> environment variable, or uses the one defined
102 in the <tt>mercurial.ini</tt> file. (see <a
102 in the <tt>mercurial.ini</tt> file. (see <a
103 href="https://mercurial-scm.org/wiki/MergeProgram">MergeProgram</a>
103 href="https://mercurial-scm.org/wiki/MergeProgram">MergeProgram</a>
104 on the Mercurial Wiki for more information)
104 on the Mercurial Wiki for more information)
105 </p>
105 </p>
106
106
107 <h1>Reporting problems</h1>
107 <h1>Reporting problems</h1>
108
108
109 <p>
109 <p>
110 Before you report any problems, please consult the <a
110 Before you report any problems, please consult the <a
111 href="https://mercurial-scm.org/">Mercurial web site</a>
111 href="https://mercurial-scm.org/">Mercurial web site</a>
112 and see if your question is already in our list of <a
112 and see if your question is already in our list of <a
113 href="https://mercurial-scm.org/wiki/FAQ">Frequently
113 href="https://mercurial-scm.org/wiki/FAQ">Frequently
114 Answered Questions</a> (the "FAQ").
114 Answered Questions</a> (the "FAQ").
115 </p>
115 </p>
116
116
117 <p>
117 <p>
118 If you cannot find an answer to your question, please feel free
118 If you cannot find an answer to your question, please feel free
119 to send mail to the Mercurial mailing list, at <a
119 to send mail to the Mercurial mailing list, at <a
120 href="mailto:mercurial@mercurial-scm.org">mercurial@mercurial-scm.org</a>.
120 href="mailto:mercurial@mercurial-scm.org">mercurial@mercurial-scm.org</a>.
121 <b>Remember</b>, the more useful information you include in your
121 <b>Remember</b>, the more useful information you include in your
122 report, the easier it will be for us to help you!
122 report, the easier it will be for us to help you!
123 </p>
123 </p>
124
124
125 <p>
125 <p>
126 If you are IRC-savvy, that's usually the fastest way to get
126 If you are IRC-savvy, that's usually the fastest way to get
127 help. Go to <tt>#mercurial</tt> on <tt>irc.freenode.net</tt>.
127 help. Go to <tt>#mercurial</tt> on <tt>irc.freenode.net</tt>.
128 </p>
128 </p>
129
129
130 <h1>Author and copyright information</h1>
130 <h1>Author and copyright information</h1>
131
131
132 <p>
132 <p>
133 Mercurial was written by <a href="http://www.selenic.com">Matt
133 Mercurial was written by <a href="http://www.selenic.com">Matt
134 Mackall</a>, and is maintained by Matt and a team of volunteers.
134 Mackall</a>, and is maintained by Matt and a team of volunteers.
135 </p>
135 </p>
136
136
137 <p>
137 <p>
138 The Windows installer was written by <a
138 The Windows installer was written by <a
139 href="http://www.serpentine.com/blog">Bryan O'Sullivan</a>.
139 href="http://www.serpentine.com/blog">Bryan O'Sullivan</a>.
140 </p>
140 </p>
141
141
142 <p>
142 <p>
143 Mercurial is Copyright 2005-2019 Matt Mackall and others.
143 Mercurial is Copyright 2005-2020 Matt Mackall and others.
144 </p>
144 </p>
145
145
146 <p>
146 <p>
147 Mercurial is free software; you can redistribute it and/or
147 Mercurial is free software; you can redistribute it and/or
148 modify it under the terms of the <a
148 modify it under the terms of the <a
149 href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GNU
149 href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GNU
150 General Public License version 2</a> or any later version.
150 General Public License version 2</a> or any later version.
151 </p>
151 </p>
152
152
153 <p>
153 <p>
154 Mercurial is distributed in the hope that it will be useful, but
154 Mercurial is distributed in the hope that it will be useful, but
155 <b>without any warranty</b>; without even the implied warranty
155 <b>without any warranty</b>; without even the implied warranty
156 of <b>merchantability</b> or <b>fitness for a particular
156 of <b>merchantability</b> or <b>fitness for a particular
157 purpose</b>. See the GNU General Public License for more
157 purpose</b>. See the GNU General Public License for more
158 details.
158 details.
159 </p>
159 </p>
160 </body>
160 </body>
161 </html>
161 </html>
@@ -1,1797 +1,1797 b''
1 # phabricator.py - simple Phabricator integration
1 # phabricator.py - simple Phabricator integration
2 #
2 #
3 # Copyright 2017 Facebook, Inc.
3 # Copyright 2017 Facebook, Inc.
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7 """simple Phabricator integration (EXPERIMENTAL)
7 """simple Phabricator integration (EXPERIMENTAL)
8
8
9 This extension provides a ``phabsend`` command which sends a stack of
9 This extension provides a ``phabsend`` command which sends a stack of
10 changesets to Phabricator, and a ``phabread`` command which prints a stack of
10 changesets to Phabricator, and a ``phabread`` command which prints a stack of
11 revisions in a format suitable for :hg:`import`, and a ``phabupdate`` command
11 revisions in a format suitable for :hg:`import`, and a ``phabupdate`` command
12 to update statuses in batch.
12 to update statuses in batch.
13
13
14 A "phabstatus" view for :hg:`show` is also provided; it displays status
14 A "phabstatus" view for :hg:`show` is also provided; it displays status
15 information of Phabricator differentials associated with unfinished
15 information of Phabricator differentials associated with unfinished
16 changesets.
16 changesets.
17
17
18 By default, Phabricator requires ``Test Plan`` which might prevent some
18 By default, Phabricator requires ``Test Plan`` which might prevent some
19 changeset from being sent. The requirement could be disabled by changing
19 changeset from being sent. The requirement could be disabled by changing
20 ``differential.require-test-plan-field`` config server side.
20 ``differential.require-test-plan-field`` config server side.
21
21
22 Config::
22 Config::
23
23
24 [phabricator]
24 [phabricator]
25 # Phabricator URL
25 # Phabricator URL
26 url = https://phab.example.com/
26 url = https://phab.example.com/
27
27
28 # Repo callsign. If a repo has a URL https://$HOST/diffusion/FOO, then its
28 # Repo callsign. If a repo has a URL https://$HOST/diffusion/FOO, then its
29 # callsign is "FOO".
29 # callsign is "FOO".
30 callsign = FOO
30 callsign = FOO
31
31
32 # curl command to use. If not set (default), use builtin HTTP library to
32 # curl command to use. If not set (default), use builtin HTTP library to
33 # communicate. If set, use the specified curl command. This could be useful
33 # communicate. If set, use the specified curl command. This could be useful
34 # if you need to specify advanced options that is not easily supported by
34 # if you need to specify advanced options that is not easily supported by
35 # the internal library.
35 # the internal library.
36 curlcmd = curl --connect-timeout 2 --retry 3 --silent
36 curlcmd = curl --connect-timeout 2 --retry 3 --silent
37
37
38 [auth]
38 [auth]
39 example.schemes = https
39 example.schemes = https
40 example.prefix = phab.example.com
40 example.prefix = phab.example.com
41
41
42 # API token. Get it from https://$HOST/conduit/login/
42 # API token. Get it from https://$HOST/conduit/login/
43 example.phabtoken = cli-xxxxxxxxxxxxxxxxxxxxxxxxxxxx
43 example.phabtoken = cli-xxxxxxxxxxxxxxxxxxxxxxxxxxxx
44 """
44 """
45
45
46 from __future__ import absolute_import
46 from __future__ import absolute_import
47
47
48 import base64
48 import base64
49 import contextlib
49 import contextlib
50 import hashlib
50 import hashlib
51 import itertools
51 import itertools
52 import json
52 import json
53 import mimetypes
53 import mimetypes
54 import operator
54 import operator
55 import re
55 import re
56
56
57 from mercurial.node import bin, nullid
57 from mercurial.node import bin, nullid
58 from mercurial.i18n import _
58 from mercurial.i18n import _
59 from mercurial.pycompat import getattr
59 from mercurial.pycompat import getattr
60 from mercurial.thirdparty import attr
60 from mercurial.thirdparty import attr
61 from mercurial import (
61 from mercurial import (
62 cmdutil,
62 cmdutil,
63 context,
63 context,
64 encoding,
64 encoding,
65 error,
65 error,
66 exthelper,
66 exthelper,
67 graphmod,
67 graphmod,
68 httpconnection as httpconnectionmod,
68 httpconnection as httpconnectionmod,
69 localrepo,
69 localrepo,
70 logcmdutil,
70 logcmdutil,
71 match,
71 match,
72 mdiff,
72 mdiff,
73 obsutil,
73 obsutil,
74 parser,
74 parser,
75 patch,
75 patch,
76 phases,
76 phases,
77 pycompat,
77 pycompat,
78 scmutil,
78 scmutil,
79 smartset,
79 smartset,
80 tags,
80 tags,
81 templatefilters,
81 templatefilters,
82 templateutil,
82 templateutil,
83 url as urlmod,
83 url as urlmod,
84 util,
84 util,
85 )
85 )
86 from mercurial.utils import (
86 from mercurial.utils import (
87 procutil,
87 procutil,
88 stringutil,
88 stringutil,
89 )
89 )
90 from . import show
90 from . import show
91
91
92
92
93 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
93 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
94 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
94 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
95 # be specifying the version(s) of Mercurial they are tested with, or
95 # be specifying the version(s) of Mercurial they are tested with, or
96 # leave the attribute unspecified.
96 # leave the attribute unspecified.
97 testedwith = b'ships-with-hg-core'
97 testedwith = b'ships-with-hg-core'
98
98
99 eh = exthelper.exthelper()
99 eh = exthelper.exthelper()
100
100
101 cmdtable = eh.cmdtable
101 cmdtable = eh.cmdtable
102 command = eh.command
102 command = eh.command
103 configtable = eh.configtable
103 configtable = eh.configtable
104 templatekeyword = eh.templatekeyword
104 templatekeyword = eh.templatekeyword
105 uisetup = eh.finaluisetup
105 uisetup = eh.finaluisetup
106
106
107 # developer config: phabricator.batchsize
107 # developer config: phabricator.batchsize
108 eh.configitem(
108 eh.configitem(
109 b'phabricator', b'batchsize', default=12,
109 b'phabricator', b'batchsize', default=12,
110 )
110 )
111 eh.configitem(
111 eh.configitem(
112 b'phabricator', b'callsign', default=None,
112 b'phabricator', b'callsign', default=None,
113 )
113 )
114 eh.configitem(
114 eh.configitem(
115 b'phabricator', b'curlcmd', default=None,
115 b'phabricator', b'curlcmd', default=None,
116 )
116 )
117 # developer config: phabricator.repophid
117 # developer config: phabricator.repophid
118 eh.configitem(
118 eh.configitem(
119 b'phabricator', b'repophid', default=None,
119 b'phabricator', b'repophid', default=None,
120 )
120 )
121 eh.configitem(
121 eh.configitem(
122 b'phabricator', b'url', default=None,
122 b'phabricator', b'url', default=None,
123 )
123 )
124 eh.configitem(
124 eh.configitem(
125 b'phabsend', b'confirm', default=False,
125 b'phabsend', b'confirm', default=False,
126 )
126 )
127
127
128 colortable = {
128 colortable = {
129 b'phabricator.action.created': b'green',
129 b'phabricator.action.created': b'green',
130 b'phabricator.action.skipped': b'magenta',
130 b'phabricator.action.skipped': b'magenta',
131 b'phabricator.action.updated': b'magenta',
131 b'phabricator.action.updated': b'magenta',
132 b'phabricator.desc': b'',
132 b'phabricator.desc': b'',
133 b'phabricator.drev': b'bold',
133 b'phabricator.drev': b'bold',
134 b'phabricator.node': b'',
134 b'phabricator.node': b'',
135 b'phabricator.status.abandoned': b'magenta dim',
135 b'phabricator.status.abandoned': b'magenta dim',
136 b'phabricator.status.accepted': b'green bold',
136 b'phabricator.status.accepted': b'green bold',
137 b'phabricator.status.closed': b'green',
137 b'phabricator.status.closed': b'green',
138 b'phabricator.status.needsreview': b'yellow',
138 b'phabricator.status.needsreview': b'yellow',
139 b'phabricator.status.needsrevision': b'red',
139 b'phabricator.status.needsrevision': b'red',
140 b'phabricator.status.changesplanned': b'red',
140 b'phabricator.status.changesplanned': b'red',
141 }
141 }
142
142
143 _VCR_FLAGS = [
143 _VCR_FLAGS = [
144 (
144 (
145 b'',
145 b'',
146 b'test-vcr',
146 b'test-vcr',
147 b'',
147 b'',
148 _(
148 _(
149 b'Path to a vcr file. If nonexistent, will record a new vcr transcript'
149 b'Path to a vcr file. If nonexistent, will record a new vcr transcript'
150 b', otherwise will mock all http requests using the specified vcr file.'
150 b', otherwise will mock all http requests using the specified vcr file.'
151 b' (ADVANCED)'
151 b' (ADVANCED)'
152 ),
152 ),
153 ),
153 ),
154 ]
154 ]
155
155
156
156
157 @eh.wrapfunction(localrepo, "loadhgrc")
157 @eh.wrapfunction(localrepo, "loadhgrc")
158 def _loadhgrc(orig, ui, wdirvfs, hgvfs, requirements):
158 def _loadhgrc(orig, ui, wdirvfs, hgvfs, requirements):
159 """Load ``.arcconfig`` content into a ui instance on repository open.
159 """Load ``.arcconfig`` content into a ui instance on repository open.
160 """
160 """
161 result = False
161 result = False
162 arcconfig = {}
162 arcconfig = {}
163
163
164 try:
164 try:
165 # json.loads only accepts bytes from 3.6+
165 # json.loads only accepts bytes from 3.6+
166 rawparams = encoding.unifromlocal(wdirvfs.read(b".arcconfig"))
166 rawparams = encoding.unifromlocal(wdirvfs.read(b".arcconfig"))
167 # json.loads only returns unicode strings
167 # json.loads only returns unicode strings
168 arcconfig = pycompat.rapply(
168 arcconfig = pycompat.rapply(
169 lambda x: encoding.unitolocal(x)
169 lambda x: encoding.unitolocal(x)
170 if isinstance(x, pycompat.unicode)
170 if isinstance(x, pycompat.unicode)
171 else x,
171 else x,
172 pycompat.json_loads(rawparams),
172 pycompat.json_loads(rawparams),
173 )
173 )
174
174
175 result = True
175 result = True
176 except ValueError:
176 except ValueError:
177 ui.warn(_(b"invalid JSON in %s\n") % wdirvfs.join(b".arcconfig"))
177 ui.warn(_(b"invalid JSON in %s\n") % wdirvfs.join(b".arcconfig"))
178 except IOError:
178 except IOError:
179 pass
179 pass
180
180
181 cfg = util.sortdict()
181 cfg = util.sortdict()
182
182
183 if b"repository.callsign" in arcconfig:
183 if b"repository.callsign" in arcconfig:
184 cfg[(b"phabricator", b"callsign")] = arcconfig[b"repository.callsign"]
184 cfg[(b"phabricator", b"callsign")] = arcconfig[b"repository.callsign"]
185
185
186 if b"phabricator.uri" in arcconfig:
186 if b"phabricator.uri" in arcconfig:
187 cfg[(b"phabricator", b"url")] = arcconfig[b"phabricator.uri"]
187 cfg[(b"phabricator", b"url")] = arcconfig[b"phabricator.uri"]
188
188
189 if cfg:
189 if cfg:
190 ui.applyconfig(cfg, source=wdirvfs.join(b".arcconfig"))
190 ui.applyconfig(cfg, source=wdirvfs.join(b".arcconfig"))
191
191
192 return orig(ui, wdirvfs, hgvfs, requirements) or result # Load .hg/hgrc
192 return orig(ui, wdirvfs, hgvfs, requirements) or result # Load .hg/hgrc
193
193
194
194
195 def vcrcommand(name, flags, spec, helpcategory=None, optionalrepo=False):
195 def vcrcommand(name, flags, spec, helpcategory=None, optionalrepo=False):
196 fullflags = flags + _VCR_FLAGS
196 fullflags = flags + _VCR_FLAGS
197
197
198 def hgmatcher(r1, r2):
198 def hgmatcher(r1, r2):
199 if r1.uri != r2.uri or r1.method != r2.method:
199 if r1.uri != r2.uri or r1.method != r2.method:
200 return False
200 return False
201 r1params = util.urlreq.parseqs(r1.body)
201 r1params = util.urlreq.parseqs(r1.body)
202 r2params = util.urlreq.parseqs(r2.body)
202 r2params = util.urlreq.parseqs(r2.body)
203 for key in r1params:
203 for key in r1params:
204 if key not in r2params:
204 if key not in r2params:
205 return False
205 return False
206 value = r1params[key][0]
206 value = r1params[key][0]
207 # we want to compare json payloads without worrying about ordering
207 # we want to compare json payloads without worrying about ordering
208 if value.startswith(b'{') and value.endswith(b'}'):
208 if value.startswith(b'{') and value.endswith(b'}'):
209 r1json = pycompat.json_loads(value)
209 r1json = pycompat.json_loads(value)
210 r2json = pycompat.json_loads(r2params[key][0])
210 r2json = pycompat.json_loads(r2params[key][0])
211 if r1json != r2json:
211 if r1json != r2json:
212 return False
212 return False
213 elif r2params[key][0] != value:
213 elif r2params[key][0] != value:
214 return False
214 return False
215 return True
215 return True
216
216
217 def sanitiserequest(request):
217 def sanitiserequest(request):
218 request.body = re.sub(
218 request.body = re.sub(
219 br'cli-[a-z0-9]+', br'cli-hahayouwish', request.body
219 br'cli-[a-z0-9]+', br'cli-hahayouwish', request.body
220 )
220 )
221 return request
221 return request
222
222
223 def sanitiseresponse(response):
223 def sanitiseresponse(response):
224 if 'set-cookie' in response['headers']:
224 if 'set-cookie' in response['headers']:
225 del response['headers']['set-cookie']
225 del response['headers']['set-cookie']
226 return response
226 return response
227
227
228 def decorate(fn):
228 def decorate(fn):
229 def inner(*args, **kwargs):
229 def inner(*args, **kwargs):
230 cassette = pycompat.fsdecode(kwargs.pop('test_vcr', None))
230 cassette = pycompat.fsdecode(kwargs.pop('test_vcr', None))
231 if cassette:
231 if cassette:
232 import hgdemandimport
232 import hgdemandimport
233
233
234 with hgdemandimport.deactivated():
234 with hgdemandimport.deactivated():
235 import vcr as vcrmod
235 import vcr as vcrmod
236 import vcr.stubs as stubs
236 import vcr.stubs as stubs
237
237
238 vcr = vcrmod.VCR(
238 vcr = vcrmod.VCR(
239 serializer='json',
239 serializer='json',
240 before_record_request=sanitiserequest,
240 before_record_request=sanitiserequest,
241 before_record_response=sanitiseresponse,
241 before_record_response=sanitiseresponse,
242 custom_patches=[
242 custom_patches=[
243 (
243 (
244 urlmod,
244 urlmod,
245 'httpconnection',
245 'httpconnection',
246 stubs.VCRHTTPConnection,
246 stubs.VCRHTTPConnection,
247 ),
247 ),
248 (
248 (
249 urlmod,
249 urlmod,
250 'httpsconnection',
250 'httpsconnection',
251 stubs.VCRHTTPSConnection,
251 stubs.VCRHTTPSConnection,
252 ),
252 ),
253 ],
253 ],
254 )
254 )
255 vcr.register_matcher('hgmatcher', hgmatcher)
255 vcr.register_matcher('hgmatcher', hgmatcher)
256 with vcr.use_cassette(cassette, match_on=['hgmatcher']):
256 with vcr.use_cassette(cassette, match_on=['hgmatcher']):
257 return fn(*args, **kwargs)
257 return fn(*args, **kwargs)
258 return fn(*args, **kwargs)
258 return fn(*args, **kwargs)
259
259
260 inner.__name__ = fn.__name__
260 inner.__name__ = fn.__name__
261 inner.__doc__ = fn.__doc__
261 inner.__doc__ = fn.__doc__
262 return command(
262 return command(
263 name,
263 name,
264 fullflags,
264 fullflags,
265 spec,
265 spec,
266 helpcategory=helpcategory,
266 helpcategory=helpcategory,
267 optionalrepo=optionalrepo,
267 optionalrepo=optionalrepo,
268 )(inner)
268 )(inner)
269
269
270 return decorate
270 return decorate
271
271
272
272
273 def urlencodenested(params):
273 def urlencodenested(params):
274 """like urlencode, but works with nested parameters.
274 """like urlencode, but works with nested parameters.
275
275
276 For example, if params is {'a': ['b', 'c'], 'd': {'e': 'f'}}, it will be
276 For example, if params is {'a': ['b', 'c'], 'd': {'e': 'f'}}, it will be
277 flattened to {'a[0]': 'b', 'a[1]': 'c', 'd[e]': 'f'} and then passed to
277 flattened to {'a[0]': 'b', 'a[1]': 'c', 'd[e]': 'f'} and then passed to
278 urlencode. Note: the encoding is consistent with PHP's http_build_query.
278 urlencode. Note: the encoding is consistent with PHP's http_build_query.
279 """
279 """
280 flatparams = util.sortdict()
280 flatparams = util.sortdict()
281
281
282 def process(prefix, obj):
282 def process(prefix, obj):
283 if isinstance(obj, bool):
283 if isinstance(obj, bool):
284 obj = {True: b'true', False: b'false'}[obj] # Python -> PHP form
284 obj = {True: b'true', False: b'false'}[obj] # Python -> PHP form
285 lister = lambda l: [(b'%d' % k, v) for k, v in enumerate(l)]
285 lister = lambda l: [(b'%d' % k, v) for k, v in enumerate(l)]
286 items = {list: lister, dict: lambda x: x.items()}.get(type(obj))
286 items = {list: lister, dict: lambda x: x.items()}.get(type(obj))
287 if items is None:
287 if items is None:
288 flatparams[prefix] = obj
288 flatparams[prefix] = obj
289 else:
289 else:
290 for k, v in items(obj):
290 for k, v in items(obj):
291 if prefix:
291 if prefix:
292 process(b'%s[%s]' % (prefix, k), v)
292 process(b'%s[%s]' % (prefix, k), v)
293 else:
293 else:
294 process(k, v)
294 process(k, v)
295
295
296 process(b'', params)
296 process(b'', params)
297 return util.urlreq.urlencode(flatparams)
297 return util.urlreq.urlencode(flatparams)
298
298
299
299
300 def readurltoken(ui):
300 def readurltoken(ui):
301 """return conduit url, token and make sure they exist
301 """return conduit url, token and make sure they exist
302
302
303 Currently read from [auth] config section. In the future, it might
303 Currently read from [auth] config section. In the future, it might
304 make sense to read from .arcconfig and .arcrc as well.
304 make sense to read from .arcconfig and .arcrc as well.
305 """
305 """
306 url = ui.config(b'phabricator', b'url')
306 url = ui.config(b'phabricator', b'url')
307 if not url:
307 if not url:
308 raise error.Abort(
308 raise error.Abort(
309 _(b'config %s.%s is required') % (b'phabricator', b'url')
309 _(b'config %s.%s is required') % (b'phabricator', b'url')
310 )
310 )
311
311
312 res = httpconnectionmod.readauthforuri(ui, url, util.url(url).user)
312 res = httpconnectionmod.readauthforuri(ui, url, util.url(url).user)
313 token = None
313 token = None
314
314
315 if res:
315 if res:
316 group, auth = res
316 group, auth = res
317
317
318 ui.debug(b"using auth.%s.* for authentication\n" % group)
318 ui.debug(b"using auth.%s.* for authentication\n" % group)
319
319
320 token = auth.get(b'phabtoken')
320 token = auth.get(b'phabtoken')
321
321
322 if not token:
322 if not token:
323 raise error.Abort(
323 raise error.Abort(
324 _(b'Can\'t find conduit token associated to %s') % (url,)
324 _(b'Can\'t find conduit token associated to %s') % (url,)
325 )
325 )
326
326
327 return url, token
327 return url, token
328
328
329
329
330 def callconduit(ui, name, params):
330 def callconduit(ui, name, params):
331 """call Conduit API, params is a dict. return json.loads result, or None"""
331 """call Conduit API, params is a dict. return json.loads result, or None"""
332 host, token = readurltoken(ui)
332 host, token = readurltoken(ui)
333 url, authinfo = util.url(b'/'.join([host, b'api', name])).authinfo()
333 url, authinfo = util.url(b'/'.join([host, b'api', name])).authinfo()
334 ui.debug(b'Conduit Call: %s %s\n' % (url, pycompat.byterepr(params)))
334 ui.debug(b'Conduit Call: %s %s\n' % (url, pycompat.byterepr(params)))
335 params = params.copy()
335 params = params.copy()
336 params[b'__conduit__'] = {
336 params[b'__conduit__'] = {
337 b'token': token,
337 b'token': token,
338 }
338 }
339 rawdata = {
339 rawdata = {
340 b'params': templatefilters.json(params),
340 b'params': templatefilters.json(params),
341 b'output': b'json',
341 b'output': b'json',
342 b'__conduit__': 1,
342 b'__conduit__': 1,
343 }
343 }
344 data = urlencodenested(rawdata)
344 data = urlencodenested(rawdata)
345 curlcmd = ui.config(b'phabricator', b'curlcmd')
345 curlcmd = ui.config(b'phabricator', b'curlcmd')
346 if curlcmd:
346 if curlcmd:
347 sin, sout = procutil.popen2(
347 sin, sout = procutil.popen2(
348 b'%s -d @- %s' % (curlcmd, procutil.shellquote(url))
348 b'%s -d @- %s' % (curlcmd, procutil.shellquote(url))
349 )
349 )
350 sin.write(data)
350 sin.write(data)
351 sin.close()
351 sin.close()
352 body = sout.read()
352 body = sout.read()
353 else:
353 else:
354 urlopener = urlmod.opener(ui, authinfo)
354 urlopener = urlmod.opener(ui, authinfo)
355 request = util.urlreq.request(pycompat.strurl(url), data=data)
355 request = util.urlreq.request(pycompat.strurl(url), data=data)
356 with contextlib.closing(urlopener.open(request)) as rsp:
356 with contextlib.closing(urlopener.open(request)) as rsp:
357 body = rsp.read()
357 body = rsp.read()
358 ui.debug(b'Conduit Response: %s\n' % body)
358 ui.debug(b'Conduit Response: %s\n' % body)
359 parsed = pycompat.rapply(
359 parsed = pycompat.rapply(
360 lambda x: encoding.unitolocal(x)
360 lambda x: encoding.unitolocal(x)
361 if isinstance(x, pycompat.unicode)
361 if isinstance(x, pycompat.unicode)
362 else x,
362 else x,
363 # json.loads only accepts bytes from py3.6+
363 # json.loads only accepts bytes from py3.6+
364 pycompat.json_loads(encoding.unifromlocal(body)),
364 pycompat.json_loads(encoding.unifromlocal(body)),
365 )
365 )
366 if parsed.get(b'error_code'):
366 if parsed.get(b'error_code'):
367 msg = _(b'Conduit Error (%s): %s') % (
367 msg = _(b'Conduit Error (%s): %s') % (
368 parsed[b'error_code'],
368 parsed[b'error_code'],
369 parsed[b'error_info'],
369 parsed[b'error_info'],
370 )
370 )
371 raise error.Abort(msg)
371 raise error.Abort(msg)
372 return parsed[b'result']
372 return parsed[b'result']
373
373
374
374
375 @vcrcommand(b'debugcallconduit', [], _(b'METHOD'), optionalrepo=True)
375 @vcrcommand(b'debugcallconduit', [], _(b'METHOD'), optionalrepo=True)
376 def debugcallconduit(ui, repo, name):
376 def debugcallconduit(ui, repo, name):
377 """call Conduit API
377 """call Conduit API
378
378
379 Call parameters are read from stdin as a JSON blob. Result will be written
379 Call parameters are read from stdin as a JSON blob. Result will be written
380 to stdout as a JSON blob.
380 to stdout as a JSON blob.
381 """
381 """
382 # json.loads only accepts bytes from 3.6+
382 # json.loads only accepts bytes from 3.6+
383 rawparams = encoding.unifromlocal(ui.fin.read())
383 rawparams = encoding.unifromlocal(ui.fin.read())
384 # json.loads only returns unicode strings
384 # json.loads only returns unicode strings
385 params = pycompat.rapply(
385 params = pycompat.rapply(
386 lambda x: encoding.unitolocal(x)
386 lambda x: encoding.unitolocal(x)
387 if isinstance(x, pycompat.unicode)
387 if isinstance(x, pycompat.unicode)
388 else x,
388 else x,
389 pycompat.json_loads(rawparams),
389 pycompat.json_loads(rawparams),
390 )
390 )
391 # json.dumps only accepts unicode strings
391 # json.dumps only accepts unicode strings
392 result = pycompat.rapply(
392 result = pycompat.rapply(
393 lambda x: encoding.unifromlocal(x) if isinstance(x, bytes) else x,
393 lambda x: encoding.unifromlocal(x) if isinstance(x, bytes) else x,
394 callconduit(ui, name, params),
394 callconduit(ui, name, params),
395 )
395 )
396 s = json.dumps(result, sort_keys=True, indent=2, separators=(u',', u': '))
396 s = json.dumps(result, sort_keys=True, indent=2, separators=(u',', u': '))
397 ui.write(b'%s\n' % encoding.unitolocal(s))
397 ui.write(b'%s\n' % encoding.unitolocal(s))
398
398
399
399
400 def getrepophid(repo):
400 def getrepophid(repo):
401 """given callsign, return repository PHID or None"""
401 """given callsign, return repository PHID or None"""
402 # developer config: phabricator.repophid
402 # developer config: phabricator.repophid
403 repophid = repo.ui.config(b'phabricator', b'repophid')
403 repophid = repo.ui.config(b'phabricator', b'repophid')
404 if repophid:
404 if repophid:
405 return repophid
405 return repophid
406 callsign = repo.ui.config(b'phabricator', b'callsign')
406 callsign = repo.ui.config(b'phabricator', b'callsign')
407 if not callsign:
407 if not callsign:
408 return None
408 return None
409 query = callconduit(
409 query = callconduit(
410 repo.ui,
410 repo.ui,
411 b'diffusion.repository.search',
411 b'diffusion.repository.search',
412 {b'constraints': {b'callsigns': [callsign]}},
412 {b'constraints': {b'callsigns': [callsign]}},
413 )
413 )
414 if len(query[b'data']) == 0:
414 if len(query[b'data']) == 0:
415 return None
415 return None
416 repophid = query[b'data'][0][b'phid']
416 repophid = query[b'data'][0][b'phid']
417 repo.ui.setconfig(b'phabricator', b'repophid', repophid)
417 repo.ui.setconfig(b'phabricator', b'repophid', repophid)
418 return repophid
418 return repophid
419
419
420
420
421 _differentialrevisiontagre = re.compile(br'\AD([1-9][0-9]*)\Z')
421 _differentialrevisiontagre = re.compile(br'\AD([1-9][0-9]*)\Z')
422 _differentialrevisiondescre = re.compile(
422 _differentialrevisiondescre = re.compile(
423 br'^Differential Revision:\s*(?P<url>(?:.*)D(?P<id>[1-9][0-9]*))$', re.M
423 br'^Differential Revision:\s*(?P<url>(?:.*)D(?P<id>[1-9][0-9]*))$', re.M
424 )
424 )
425
425
426
426
427 def getoldnodedrevmap(repo, nodelist):
427 def getoldnodedrevmap(repo, nodelist):
428 """find previous nodes that has been sent to Phabricator
428 """find previous nodes that has been sent to Phabricator
429
429
430 return {node: (oldnode, Differential diff, Differential Revision ID)}
430 return {node: (oldnode, Differential diff, Differential Revision ID)}
431 for node in nodelist with known previous sent versions, or associated
431 for node in nodelist with known previous sent versions, or associated
432 Differential Revision IDs. ``oldnode`` and ``Differential diff`` could
432 Differential Revision IDs. ``oldnode`` and ``Differential diff`` could
433 be ``None``.
433 be ``None``.
434
434
435 Examines commit messages like "Differential Revision:" to get the
435 Examines commit messages like "Differential Revision:" to get the
436 association information.
436 association information.
437
437
438 If such commit message line is not found, examines all precursors and their
438 If such commit message line is not found, examines all precursors and their
439 tags. Tags with format like "D1234" are considered a match and the node
439 tags. Tags with format like "D1234" are considered a match and the node
440 with that tag, and the number after "D" (ex. 1234) will be returned.
440 with that tag, and the number after "D" (ex. 1234) will be returned.
441
441
442 The ``old node``, if not None, is guaranteed to be the last diff of
442 The ``old node``, if not None, is guaranteed to be the last diff of
443 corresponding Differential Revision, and exist in the repo.
443 corresponding Differential Revision, and exist in the repo.
444 """
444 """
445 unfi = repo.unfiltered()
445 unfi = repo.unfiltered()
446 has_node = unfi.changelog.index.has_node
446 has_node = unfi.changelog.index.has_node
447
447
448 result = {} # {node: (oldnode?, lastdiff?, drev)}
448 result = {} # {node: (oldnode?, lastdiff?, drev)}
449 toconfirm = {} # {node: (force, {precnode}, drev)}
449 toconfirm = {} # {node: (force, {precnode}, drev)}
450 for node in nodelist:
450 for node in nodelist:
451 ctx = unfi[node]
451 ctx = unfi[node]
452 # For tags like "D123", put them into "toconfirm" to verify later
452 # For tags like "D123", put them into "toconfirm" to verify later
453 precnodes = list(obsutil.allpredecessors(unfi.obsstore, [node]))
453 precnodes = list(obsutil.allpredecessors(unfi.obsstore, [node]))
454 for n in precnodes:
454 for n in precnodes:
455 if has_node(n):
455 if has_node(n):
456 for tag in unfi.nodetags(n):
456 for tag in unfi.nodetags(n):
457 m = _differentialrevisiontagre.match(tag)
457 m = _differentialrevisiontagre.match(tag)
458 if m:
458 if m:
459 toconfirm[node] = (0, set(precnodes), int(m.group(1)))
459 toconfirm[node] = (0, set(precnodes), int(m.group(1)))
460 break
460 break
461 else:
461 else:
462 continue # move to next predecessor
462 continue # move to next predecessor
463 break # found a tag, stop
463 break # found a tag, stop
464 else:
464 else:
465 # Check commit message
465 # Check commit message
466 m = _differentialrevisiondescre.search(ctx.description())
466 m = _differentialrevisiondescre.search(ctx.description())
467 if m:
467 if m:
468 toconfirm[node] = (1, set(precnodes), int(m.group('id')))
468 toconfirm[node] = (1, set(precnodes), int(m.group('id')))
469
469
470 # Double check if tags are genuine by collecting all old nodes from
470 # Double check if tags are genuine by collecting all old nodes from
471 # Phabricator, and expect precursors overlap with it.
471 # Phabricator, and expect precursors overlap with it.
472 if toconfirm:
472 if toconfirm:
473 drevs = [drev for force, precs, drev in toconfirm.values()]
473 drevs = [drev for force, precs, drev in toconfirm.values()]
474 alldiffs = callconduit(
474 alldiffs = callconduit(
475 unfi.ui, b'differential.querydiffs', {b'revisionIDs': drevs}
475 unfi.ui, b'differential.querydiffs', {b'revisionIDs': drevs}
476 )
476 )
477 getnode = lambda d: bin(getdiffmeta(d).get(b'node', b'')) or None
477 getnode = lambda d: bin(getdiffmeta(d).get(b'node', b'')) or None
478 for newnode, (force, precset, drev) in toconfirm.items():
478 for newnode, (force, precset, drev) in toconfirm.items():
479 diffs = [
479 diffs = [
480 d for d in alldiffs.values() if int(d[b'revisionID']) == drev
480 d for d in alldiffs.values() if int(d[b'revisionID']) == drev
481 ]
481 ]
482
482
483 # "precursors" as known by Phabricator
483 # "precursors" as known by Phabricator
484 phprecset = set(getnode(d) for d in diffs)
484 phprecset = set(getnode(d) for d in diffs)
485
485
486 # Ignore if precursors (Phabricator and local repo) do not overlap,
486 # Ignore if precursors (Phabricator and local repo) do not overlap,
487 # and force is not set (when commit message says nothing)
487 # and force is not set (when commit message says nothing)
488 if not force and not bool(phprecset & precset):
488 if not force and not bool(phprecset & precset):
489 tagname = b'D%d' % drev
489 tagname = b'D%d' % drev
490 tags.tag(
490 tags.tag(
491 repo,
491 repo,
492 tagname,
492 tagname,
493 nullid,
493 nullid,
494 message=None,
494 message=None,
495 user=None,
495 user=None,
496 date=None,
496 date=None,
497 local=True,
497 local=True,
498 )
498 )
499 unfi.ui.warn(
499 unfi.ui.warn(
500 _(
500 _(
501 b'D%d: local tag removed - does not match '
501 b'D%d: local tag removed - does not match '
502 b'Differential history\n'
502 b'Differential history\n'
503 )
503 )
504 % drev
504 % drev
505 )
505 )
506 continue
506 continue
507
507
508 # Find the last node using Phabricator metadata, and make sure it
508 # Find the last node using Phabricator metadata, and make sure it
509 # exists in the repo
509 # exists in the repo
510 oldnode = lastdiff = None
510 oldnode = lastdiff = None
511 if diffs:
511 if diffs:
512 lastdiff = max(diffs, key=lambda d: int(d[b'id']))
512 lastdiff = max(diffs, key=lambda d: int(d[b'id']))
513 oldnode = getnode(lastdiff)
513 oldnode = getnode(lastdiff)
514 if oldnode and not has_node(oldnode):
514 if oldnode and not has_node(oldnode):
515 oldnode = None
515 oldnode = None
516
516
517 result[newnode] = (oldnode, lastdiff, drev)
517 result[newnode] = (oldnode, lastdiff, drev)
518
518
519 return result
519 return result
520
520
521
521
522 def getdrevmap(repo, revs):
522 def getdrevmap(repo, revs):
523 """Return a dict mapping each rev in `revs` to their Differential Revision
523 """Return a dict mapping each rev in `revs` to their Differential Revision
524 ID or None.
524 ID or None.
525 """
525 """
526 result = {}
526 result = {}
527 for rev in revs:
527 for rev in revs:
528 result[rev] = None
528 result[rev] = None
529 ctx = repo[rev]
529 ctx = repo[rev]
530 # Check commit message
530 # Check commit message
531 m = _differentialrevisiondescre.search(ctx.description())
531 m = _differentialrevisiondescre.search(ctx.description())
532 if m:
532 if m:
533 result[rev] = int(m.group('id'))
533 result[rev] = int(m.group('id'))
534 continue
534 continue
535 # Check tags
535 # Check tags
536 for tag in repo.nodetags(ctx.node()):
536 for tag in repo.nodetags(ctx.node()):
537 m = _differentialrevisiontagre.match(tag)
537 m = _differentialrevisiontagre.match(tag)
538 if m:
538 if m:
539 result[rev] = int(m.group(1))
539 result[rev] = int(m.group(1))
540 break
540 break
541
541
542 return result
542 return result
543
543
544
544
545 def getdiff(ctx, diffopts):
545 def getdiff(ctx, diffopts):
546 """plain-text diff without header (user, commit message, etc)"""
546 """plain-text diff without header (user, commit message, etc)"""
547 output = util.stringio()
547 output = util.stringio()
548 for chunk, _label in patch.diffui(
548 for chunk, _label in patch.diffui(
549 ctx.repo(), ctx.p1().node(), ctx.node(), None, opts=diffopts
549 ctx.repo(), ctx.p1().node(), ctx.node(), None, opts=diffopts
550 ):
550 ):
551 output.write(chunk)
551 output.write(chunk)
552 return output.getvalue()
552 return output.getvalue()
553
553
554
554
555 class DiffChangeType(object):
555 class DiffChangeType(object):
556 ADD = 1
556 ADD = 1
557 CHANGE = 2
557 CHANGE = 2
558 DELETE = 3
558 DELETE = 3
559 MOVE_AWAY = 4
559 MOVE_AWAY = 4
560 COPY_AWAY = 5
560 COPY_AWAY = 5
561 MOVE_HERE = 6
561 MOVE_HERE = 6
562 COPY_HERE = 7
562 COPY_HERE = 7
563 MULTICOPY = 8
563 MULTICOPY = 8
564
564
565
565
566 class DiffFileType(object):
566 class DiffFileType(object):
567 TEXT = 1
567 TEXT = 1
568 IMAGE = 2
568 IMAGE = 2
569 BINARY = 3
569 BINARY = 3
570
570
571
571
572 @attr.s
572 @attr.s
573 class phabhunk(dict):
573 class phabhunk(dict):
574 """Represents a Differential hunk, which is owned by a Differential change
574 """Represents a Differential hunk, which is owned by a Differential change
575 """
575 """
576
576
577 oldOffset = attr.ib(default=0) # camelcase-required
577 oldOffset = attr.ib(default=0) # camelcase-required
578 oldLength = attr.ib(default=0) # camelcase-required
578 oldLength = attr.ib(default=0) # camelcase-required
579 newOffset = attr.ib(default=0) # camelcase-required
579 newOffset = attr.ib(default=0) # camelcase-required
580 newLength = attr.ib(default=0) # camelcase-required
580 newLength = attr.ib(default=0) # camelcase-required
581 corpus = attr.ib(default='')
581 corpus = attr.ib(default='')
582 # These get added to the phabchange's equivalents
582 # These get added to the phabchange's equivalents
583 addLines = attr.ib(default=0) # camelcase-required
583 addLines = attr.ib(default=0) # camelcase-required
584 delLines = attr.ib(default=0) # camelcase-required
584 delLines = attr.ib(default=0) # camelcase-required
585
585
586
586
587 @attr.s
587 @attr.s
588 class phabchange(object):
588 class phabchange(object):
589 """Represents a Differential change, owns Differential hunks and owned by a
589 """Represents a Differential change, owns Differential hunks and owned by a
590 Differential diff. Each one represents one file in a diff.
590 Differential diff. Each one represents one file in a diff.
591 """
591 """
592
592
593 currentPath = attr.ib(default=None) # camelcase-required
593 currentPath = attr.ib(default=None) # camelcase-required
594 oldPath = attr.ib(default=None) # camelcase-required
594 oldPath = attr.ib(default=None) # camelcase-required
595 awayPaths = attr.ib(default=attr.Factory(list)) # camelcase-required
595 awayPaths = attr.ib(default=attr.Factory(list)) # camelcase-required
596 metadata = attr.ib(default=attr.Factory(dict))
596 metadata = attr.ib(default=attr.Factory(dict))
597 oldProperties = attr.ib(default=attr.Factory(dict)) # camelcase-required
597 oldProperties = attr.ib(default=attr.Factory(dict)) # camelcase-required
598 newProperties = attr.ib(default=attr.Factory(dict)) # camelcase-required
598 newProperties = attr.ib(default=attr.Factory(dict)) # camelcase-required
599 type = attr.ib(default=DiffChangeType.CHANGE)
599 type = attr.ib(default=DiffChangeType.CHANGE)
600 fileType = attr.ib(default=DiffFileType.TEXT) # camelcase-required
600 fileType = attr.ib(default=DiffFileType.TEXT) # camelcase-required
601 commitHash = attr.ib(default=None) # camelcase-required
601 commitHash = attr.ib(default=None) # camelcase-required
602 addLines = attr.ib(default=0) # camelcase-required
602 addLines = attr.ib(default=0) # camelcase-required
603 delLines = attr.ib(default=0) # camelcase-required
603 delLines = attr.ib(default=0) # camelcase-required
604 hunks = attr.ib(default=attr.Factory(list))
604 hunks = attr.ib(default=attr.Factory(list))
605
605
606 def copynewmetadatatoold(self):
606 def copynewmetadatatoold(self):
607 for key in list(self.metadata.keys()):
607 for key in list(self.metadata.keys()):
608 newkey = key.replace(b'new:', b'old:')
608 newkey = key.replace(b'new:', b'old:')
609 self.metadata[newkey] = self.metadata[key]
609 self.metadata[newkey] = self.metadata[key]
610
610
611 def addoldmode(self, value):
611 def addoldmode(self, value):
612 self.oldProperties[b'unix:filemode'] = value
612 self.oldProperties[b'unix:filemode'] = value
613
613
614 def addnewmode(self, value):
614 def addnewmode(self, value):
615 self.newProperties[b'unix:filemode'] = value
615 self.newProperties[b'unix:filemode'] = value
616
616
617 def addhunk(self, hunk):
617 def addhunk(self, hunk):
618 if not isinstance(hunk, phabhunk):
618 if not isinstance(hunk, phabhunk):
619 raise error.Abort(b'phabchange.addhunk only takes phabhunks')
619 raise error.Abort(b'phabchange.addhunk only takes phabhunks')
620 self.hunks.append(pycompat.byteskwargs(attr.asdict(hunk)))
620 self.hunks.append(pycompat.byteskwargs(attr.asdict(hunk)))
621 # It's useful to include these stats since the Phab web UI shows them,
621 # It's useful to include these stats since the Phab web UI shows them,
622 # and uses them to estimate how large a change a Revision is. Also used
622 # and uses them to estimate how large a change a Revision is. Also used
623 # in email subjects for the [+++--] bit.
623 # in email subjects for the [+++--] bit.
624 self.addLines += hunk.addLines
624 self.addLines += hunk.addLines
625 self.delLines += hunk.delLines
625 self.delLines += hunk.delLines
626
626
627
627
628 @attr.s
628 @attr.s
629 class phabdiff(object):
629 class phabdiff(object):
630 """Represents a Differential diff, owns Differential changes. Corresponds
630 """Represents a Differential diff, owns Differential changes. Corresponds
631 to a commit.
631 to a commit.
632 """
632 """
633
633
634 # Doesn't seem to be any reason to send this (output of uname -n)
634 # Doesn't seem to be any reason to send this (output of uname -n)
635 sourceMachine = attr.ib(default=b'') # camelcase-required
635 sourceMachine = attr.ib(default=b'') # camelcase-required
636 sourcePath = attr.ib(default=b'/') # camelcase-required
636 sourcePath = attr.ib(default=b'/') # camelcase-required
637 sourceControlBaseRevision = attr.ib(default=b'0' * 40) # camelcase-required
637 sourceControlBaseRevision = attr.ib(default=b'0' * 40) # camelcase-required
638 sourceControlPath = attr.ib(default=b'/') # camelcase-required
638 sourceControlPath = attr.ib(default=b'/') # camelcase-required
639 sourceControlSystem = attr.ib(default=b'hg') # camelcase-required
639 sourceControlSystem = attr.ib(default=b'hg') # camelcase-required
640 branch = attr.ib(default=b'default')
640 branch = attr.ib(default=b'default')
641 bookmark = attr.ib(default=None)
641 bookmark = attr.ib(default=None)
642 creationMethod = attr.ib(default=b'phabsend') # camelcase-required
642 creationMethod = attr.ib(default=b'phabsend') # camelcase-required
643 lintStatus = attr.ib(default=b'none') # camelcase-required
643 lintStatus = attr.ib(default=b'none') # camelcase-required
644 unitStatus = attr.ib(default=b'none') # camelcase-required
644 unitStatus = attr.ib(default=b'none') # camelcase-required
645 changes = attr.ib(default=attr.Factory(dict))
645 changes = attr.ib(default=attr.Factory(dict))
646 repositoryPHID = attr.ib(default=None) # camelcase-required
646 repositoryPHID = attr.ib(default=None) # camelcase-required
647
647
648 def addchange(self, change):
648 def addchange(self, change):
649 if not isinstance(change, phabchange):
649 if not isinstance(change, phabchange):
650 raise error.Abort(b'phabdiff.addchange only takes phabchanges')
650 raise error.Abort(b'phabdiff.addchange only takes phabchanges')
651 self.changes[change.currentPath] = pycompat.byteskwargs(
651 self.changes[change.currentPath] = pycompat.byteskwargs(
652 attr.asdict(change)
652 attr.asdict(change)
653 )
653 )
654
654
655
655
656 def maketext(pchange, ctx, fname):
656 def maketext(pchange, ctx, fname):
657 """populate the phabchange for a text file"""
657 """populate the phabchange for a text file"""
658 repo = ctx.repo()
658 repo = ctx.repo()
659 fmatcher = match.exact([fname])
659 fmatcher = match.exact([fname])
660 diffopts = mdiff.diffopts(git=True, context=32767)
660 diffopts = mdiff.diffopts(git=True, context=32767)
661 _pfctx, _fctx, header, fhunks = next(
661 _pfctx, _fctx, header, fhunks = next(
662 patch.diffhunks(repo, ctx.p1(), ctx, fmatcher, opts=diffopts)
662 patch.diffhunks(repo, ctx.p1(), ctx, fmatcher, opts=diffopts)
663 )
663 )
664
664
665 for fhunk in fhunks:
665 for fhunk in fhunks:
666 (oldOffset, oldLength, newOffset, newLength), lines = fhunk
666 (oldOffset, oldLength, newOffset, newLength), lines = fhunk
667 corpus = b''.join(lines[1:])
667 corpus = b''.join(lines[1:])
668 shunk = list(header)
668 shunk = list(header)
669 shunk.extend(lines)
669 shunk.extend(lines)
670 _mf, _mt, addLines, delLines, _hb = patch.diffstatsum(
670 _mf, _mt, addLines, delLines, _hb = patch.diffstatsum(
671 patch.diffstatdata(util.iterlines(shunk))
671 patch.diffstatdata(util.iterlines(shunk))
672 )
672 )
673 pchange.addhunk(
673 pchange.addhunk(
674 phabhunk(
674 phabhunk(
675 oldOffset,
675 oldOffset,
676 oldLength,
676 oldLength,
677 newOffset,
677 newOffset,
678 newLength,
678 newLength,
679 corpus,
679 corpus,
680 addLines,
680 addLines,
681 delLines,
681 delLines,
682 )
682 )
683 )
683 )
684
684
685
685
686 def uploadchunks(fctx, fphid):
686 def uploadchunks(fctx, fphid):
687 """upload large binary files as separate chunks.
687 """upload large binary files as separate chunks.
688 Phab requests chunking over 8MiB, and splits into 4MiB chunks
688 Phab requests chunking over 8MiB, and splits into 4MiB chunks
689 """
689 """
690 ui = fctx.repo().ui
690 ui = fctx.repo().ui
691 chunks = callconduit(ui, b'file.querychunks', {b'filePHID': fphid})
691 chunks = callconduit(ui, b'file.querychunks', {b'filePHID': fphid})
692 with ui.makeprogress(
692 with ui.makeprogress(
693 _(b'uploading file chunks'), unit=_(b'chunks'), total=len(chunks)
693 _(b'uploading file chunks'), unit=_(b'chunks'), total=len(chunks)
694 ) as progress:
694 ) as progress:
695 for chunk in chunks:
695 for chunk in chunks:
696 progress.increment()
696 progress.increment()
697 if chunk[b'complete']:
697 if chunk[b'complete']:
698 continue
698 continue
699 bstart = int(chunk[b'byteStart'])
699 bstart = int(chunk[b'byteStart'])
700 bend = int(chunk[b'byteEnd'])
700 bend = int(chunk[b'byteEnd'])
701 callconduit(
701 callconduit(
702 ui,
702 ui,
703 b'file.uploadchunk',
703 b'file.uploadchunk',
704 {
704 {
705 b'filePHID': fphid,
705 b'filePHID': fphid,
706 b'byteStart': bstart,
706 b'byteStart': bstart,
707 b'data': base64.b64encode(fctx.data()[bstart:bend]),
707 b'data': base64.b64encode(fctx.data()[bstart:bend]),
708 b'dataEncoding': b'base64',
708 b'dataEncoding': b'base64',
709 },
709 },
710 )
710 )
711
711
712
712
713 def uploadfile(fctx):
713 def uploadfile(fctx):
714 """upload binary files to Phabricator"""
714 """upload binary files to Phabricator"""
715 repo = fctx.repo()
715 repo = fctx.repo()
716 ui = repo.ui
716 ui = repo.ui
717 fname = fctx.path()
717 fname = fctx.path()
718 size = fctx.size()
718 size = fctx.size()
719 fhash = pycompat.bytestr(hashlib.sha256(fctx.data()).hexdigest())
719 fhash = pycompat.bytestr(hashlib.sha256(fctx.data()).hexdigest())
720
720
721 # an allocate call is required first to see if an upload is even required
721 # an allocate call is required first to see if an upload is even required
722 # (Phab might already have it) and to determine if chunking is needed
722 # (Phab might already have it) and to determine if chunking is needed
723 allocateparams = {
723 allocateparams = {
724 b'name': fname,
724 b'name': fname,
725 b'contentLength': size,
725 b'contentLength': size,
726 b'contentHash': fhash,
726 b'contentHash': fhash,
727 }
727 }
728 filealloc = callconduit(ui, b'file.allocate', allocateparams)
728 filealloc = callconduit(ui, b'file.allocate', allocateparams)
729 fphid = filealloc[b'filePHID']
729 fphid = filealloc[b'filePHID']
730
730
731 if filealloc[b'upload']:
731 if filealloc[b'upload']:
732 ui.write(_(b'uploading %s\n') % bytes(fctx))
732 ui.write(_(b'uploading %s\n') % bytes(fctx))
733 if not fphid:
733 if not fphid:
734 uploadparams = {
734 uploadparams = {
735 b'name': fname,
735 b'name': fname,
736 b'data_base64': base64.b64encode(fctx.data()),
736 b'data_base64': base64.b64encode(fctx.data()),
737 }
737 }
738 fphid = callconduit(ui, b'file.upload', uploadparams)
738 fphid = callconduit(ui, b'file.upload', uploadparams)
739 else:
739 else:
740 uploadchunks(fctx, fphid)
740 uploadchunks(fctx, fphid)
741 else:
741 else:
742 ui.debug(b'server already has %s\n' % bytes(fctx))
742 ui.debug(b'server already has %s\n' % bytes(fctx))
743
743
744 if not fphid:
744 if not fphid:
745 raise error.Abort(b'Upload of %s failed.' % bytes(fctx))
745 raise error.Abort(b'Upload of %s failed.' % bytes(fctx))
746
746
747 return fphid
747 return fphid
748
748
749
749
750 def addoldbinary(pchange, fctx, originalfname):
750 def addoldbinary(pchange, fctx):
751 """add the metadata for the previous version of a binary file to the
751 """add the metadata for the previous version of a binary file to the
752 phabchange for the new version
752 phabchange for the new version
753 """
753 """
754 oldfctx = fctx.p1()[originalfname]
754 oldfctx = fctx.p1()
755 if fctx.cmp(oldfctx):
755 if fctx.cmp(oldfctx):
756 # Files differ, add the old one
756 # Files differ, add the old one
757 pchange.metadata[b'old:file:size'] = oldfctx.size()
757 pchange.metadata[b'old:file:size'] = oldfctx.size()
758 mimeguess, _enc = mimetypes.guess_type(
758 mimeguess, _enc = mimetypes.guess_type(
759 encoding.unifromlocal(oldfctx.path())
759 encoding.unifromlocal(oldfctx.path())
760 )
760 )
761 if mimeguess:
761 if mimeguess:
762 pchange.metadata[b'old:file:mime-type'] = pycompat.bytestr(
762 pchange.metadata[b'old:file:mime-type'] = pycompat.bytestr(
763 mimeguess
763 mimeguess
764 )
764 )
765 fphid = uploadfile(oldfctx)
765 fphid = uploadfile(oldfctx)
766 pchange.metadata[b'old:binary-phid'] = fphid
766 pchange.metadata[b'old:binary-phid'] = fphid
767 else:
767 else:
768 # If it's left as IMAGE/BINARY web UI might try to display it
768 # If it's left as IMAGE/BINARY web UI might try to display it
769 pchange.fileType = DiffFileType.TEXT
769 pchange.fileType = DiffFileType.TEXT
770 pchange.copynewmetadatatoold()
770 pchange.copynewmetadatatoold()
771
771
772
772
773 def makebinary(pchange, fctx):
773 def makebinary(pchange, fctx):
774 """populate the phabchange for a binary file"""
774 """populate the phabchange for a binary file"""
775 pchange.fileType = DiffFileType.BINARY
775 pchange.fileType = DiffFileType.BINARY
776 fphid = uploadfile(fctx)
776 fphid = uploadfile(fctx)
777 pchange.metadata[b'new:binary-phid'] = fphid
777 pchange.metadata[b'new:binary-phid'] = fphid
778 pchange.metadata[b'new:file:size'] = fctx.size()
778 pchange.metadata[b'new:file:size'] = fctx.size()
779 mimeguess, _enc = mimetypes.guess_type(encoding.unifromlocal(fctx.path()))
779 mimeguess, _enc = mimetypes.guess_type(encoding.unifromlocal(fctx.path()))
780 if mimeguess:
780 if mimeguess:
781 mimeguess = pycompat.bytestr(mimeguess)
781 mimeguess = pycompat.bytestr(mimeguess)
782 pchange.metadata[b'new:file:mime-type'] = mimeguess
782 pchange.metadata[b'new:file:mime-type'] = mimeguess
783 if mimeguess.startswith(b'image/'):
783 if mimeguess.startswith(b'image/'):
784 pchange.fileType = DiffFileType.IMAGE
784 pchange.fileType = DiffFileType.IMAGE
785
785
786
786
787 # Copied from mercurial/patch.py
787 # Copied from mercurial/patch.py
788 gitmode = {b'l': b'120000', b'x': b'100755', b'': b'100644'}
788 gitmode = {b'l': b'120000', b'x': b'100755', b'': b'100644'}
789
789
790
790
791 def notutf8(fctx):
791 def notutf8(fctx):
792 """detect non-UTF-8 text files since Phabricator requires them to be marked
792 """detect non-UTF-8 text files since Phabricator requires them to be marked
793 as binary
793 as binary
794 """
794 """
795 try:
795 try:
796 fctx.data().decode('utf-8')
796 fctx.data().decode('utf-8')
797 if fctx.parents():
797 if fctx.parents():
798 fctx.p1().data().decode('utf-8')
798 fctx.p1().data().decode('utf-8')
799 return False
799 return False
800 except UnicodeDecodeError:
800 except UnicodeDecodeError:
801 fctx.repo().ui.write(
801 fctx.repo().ui.write(
802 _(b'file %s detected as non-UTF-8, marked as binary\n')
802 _(b'file %s detected as non-UTF-8, marked as binary\n')
803 % fctx.path()
803 % fctx.path()
804 )
804 )
805 return True
805 return True
806
806
807
807
808 def addremoved(pdiff, ctx, removed):
808 def addremoved(pdiff, ctx, removed):
809 """add removed files to the phabdiff. Shouldn't include moves"""
809 """add removed files to the phabdiff. Shouldn't include moves"""
810 for fname in removed:
810 for fname in removed:
811 pchange = phabchange(
811 pchange = phabchange(
812 currentPath=fname, oldPath=fname, type=DiffChangeType.DELETE
812 currentPath=fname, oldPath=fname, type=DiffChangeType.DELETE
813 )
813 )
814 pchange.addoldmode(gitmode[ctx.p1()[fname].flags()])
814 pchange.addoldmode(gitmode[ctx.p1()[fname].flags()])
815 fctx = ctx.p1()[fname]
815 fctx = ctx.p1()[fname]
816 if not (fctx.isbinary() or notutf8(fctx)):
816 if not (fctx.isbinary() or notutf8(fctx)):
817 maketext(pchange, ctx, fname)
817 maketext(pchange, ctx, fname)
818
818
819 pdiff.addchange(pchange)
819 pdiff.addchange(pchange)
820
820
821
821
822 def addmodified(pdiff, ctx, modified):
822 def addmodified(pdiff, ctx, modified):
823 """add modified files to the phabdiff"""
823 """add modified files to the phabdiff"""
824 for fname in modified:
824 for fname in modified:
825 fctx = ctx[fname]
825 fctx = ctx[fname]
826 pchange = phabchange(currentPath=fname, oldPath=fname)
826 pchange = phabchange(currentPath=fname, oldPath=fname)
827 filemode = gitmode[ctx[fname].flags()]
827 filemode = gitmode[ctx[fname].flags()]
828 originalmode = gitmode[ctx.p1()[fname].flags()]
828 originalmode = gitmode[ctx.p1()[fname].flags()]
829 if filemode != originalmode:
829 if filemode != originalmode:
830 pchange.addoldmode(originalmode)
830 pchange.addoldmode(originalmode)
831 pchange.addnewmode(filemode)
831 pchange.addnewmode(filemode)
832
832
833 if fctx.isbinary() or notutf8(fctx):
833 if fctx.isbinary() or notutf8(fctx):
834 makebinary(pchange, fctx)
834 makebinary(pchange, fctx)
835 addoldbinary(pchange, fctx, fname)
835 addoldbinary(pchange, fctx)
836 else:
836 else:
837 maketext(pchange, ctx, fname)
837 maketext(pchange, ctx, fname)
838
838
839 pdiff.addchange(pchange)
839 pdiff.addchange(pchange)
840
840
841
841
842 def addadded(pdiff, ctx, added, removed):
842 def addadded(pdiff, ctx, added, removed):
843 """add file adds to the phabdiff, both new files and copies/moves"""
843 """add file adds to the phabdiff, both new files and copies/moves"""
844 # Keep track of files that've been recorded as moved/copied, so if there are
844 # Keep track of files that've been recorded as moved/copied, so if there are
845 # additional copies we can mark them (moves get removed from removed)
845 # additional copies we can mark them (moves get removed from removed)
846 copiedchanges = {}
846 copiedchanges = {}
847 movedchanges = {}
847 movedchanges = {}
848 for fname in added:
848 for fname in added:
849 fctx = ctx[fname]
849 fctx = ctx[fname]
850 pchange = phabchange(currentPath=fname)
850 pchange = phabchange(currentPath=fname)
851
851
852 filemode = gitmode[ctx[fname].flags()]
852 filemode = gitmode[ctx[fname].flags()]
853 renamed = fctx.renamed()
853 renamed = fctx.renamed()
854
854
855 if renamed:
855 if renamed:
856 originalfname = renamed[0]
856 originalfname = renamed[0]
857 originalmode = gitmode[ctx.p1()[originalfname].flags()]
857 originalmode = gitmode[ctx.p1()[originalfname].flags()]
858 pchange.oldPath = originalfname
858 pchange.oldPath = originalfname
859
859
860 if originalfname in removed:
860 if originalfname in removed:
861 origpchange = phabchange(
861 origpchange = phabchange(
862 currentPath=originalfname,
862 currentPath=originalfname,
863 oldPath=originalfname,
863 oldPath=originalfname,
864 type=DiffChangeType.MOVE_AWAY,
864 type=DiffChangeType.MOVE_AWAY,
865 awayPaths=[fname],
865 awayPaths=[fname],
866 )
866 )
867 movedchanges[originalfname] = origpchange
867 movedchanges[originalfname] = origpchange
868 removed.remove(originalfname)
868 removed.remove(originalfname)
869 pchange.type = DiffChangeType.MOVE_HERE
869 pchange.type = DiffChangeType.MOVE_HERE
870 elif originalfname in movedchanges:
870 elif originalfname in movedchanges:
871 movedchanges[originalfname].type = DiffChangeType.MULTICOPY
871 movedchanges[originalfname].type = DiffChangeType.MULTICOPY
872 movedchanges[originalfname].awayPaths.append(fname)
872 movedchanges[originalfname].awayPaths.append(fname)
873 pchange.type = DiffChangeType.COPY_HERE
873 pchange.type = DiffChangeType.COPY_HERE
874 else: # pure copy
874 else: # pure copy
875 if originalfname not in copiedchanges:
875 if originalfname not in copiedchanges:
876 origpchange = phabchange(
876 origpchange = phabchange(
877 currentPath=originalfname, type=DiffChangeType.COPY_AWAY
877 currentPath=originalfname, type=DiffChangeType.COPY_AWAY
878 )
878 )
879 copiedchanges[originalfname] = origpchange
879 copiedchanges[originalfname] = origpchange
880 else:
880 else:
881 origpchange = copiedchanges[originalfname]
881 origpchange = copiedchanges[originalfname]
882 origpchange.awayPaths.append(fname)
882 origpchange.awayPaths.append(fname)
883 pchange.type = DiffChangeType.COPY_HERE
883 pchange.type = DiffChangeType.COPY_HERE
884
884
885 if filemode != originalmode:
885 if filemode != originalmode:
886 pchange.addoldmode(originalmode)
886 pchange.addoldmode(originalmode)
887 pchange.addnewmode(filemode)
887 pchange.addnewmode(filemode)
888 else: # Brand-new file
888 else: # Brand-new file
889 pchange.addnewmode(gitmode[fctx.flags()])
889 pchange.addnewmode(gitmode[fctx.flags()])
890 pchange.type = DiffChangeType.ADD
890 pchange.type = DiffChangeType.ADD
891
891
892 if fctx.isbinary() or notutf8(fctx):
892 if fctx.isbinary() or notutf8(fctx):
893 makebinary(pchange, fctx)
893 makebinary(pchange, fctx)
894 if renamed:
894 if renamed:
895 addoldbinary(pchange, fctx, originalfname)
895 addoldbinary(pchange, fctx, originalfname)
896 else:
896 else:
897 maketext(pchange, ctx, fname)
897 maketext(pchange, ctx, fname)
898
898
899 pdiff.addchange(pchange)
899 pdiff.addchange(pchange)
900
900
901 for _path, copiedchange in copiedchanges.items():
901 for _path, copiedchange in copiedchanges.items():
902 pdiff.addchange(copiedchange)
902 pdiff.addchange(copiedchange)
903 for _path, movedchange in movedchanges.items():
903 for _path, movedchange in movedchanges.items():
904 pdiff.addchange(movedchange)
904 pdiff.addchange(movedchange)
905
905
906
906
907 def creatediff(ctx):
907 def creatediff(ctx):
908 """create a Differential Diff"""
908 """create a Differential Diff"""
909 repo = ctx.repo()
909 repo = ctx.repo()
910 repophid = getrepophid(repo)
910 repophid = getrepophid(repo)
911 # Create a "Differential Diff" via "differential.creatediff" API
911 # Create a "Differential Diff" via "differential.creatediff" API
912 pdiff = phabdiff(
912 pdiff = phabdiff(
913 sourceControlBaseRevision=b'%s' % ctx.p1().hex(),
913 sourceControlBaseRevision=b'%s' % ctx.p1().hex(),
914 branch=b'%s' % ctx.branch(),
914 branch=b'%s' % ctx.branch(),
915 )
915 )
916 modified, added, removed, _d, _u, _i, _c = ctx.p1().status(ctx)
916 modified, added, removed, _d, _u, _i, _c = ctx.p1().status(ctx)
917 # addadded will remove moved files from removed, so addremoved won't get
917 # addadded will remove moved files from removed, so addremoved won't get
918 # them
918 # them
919 addadded(pdiff, ctx, added, removed)
919 addadded(pdiff, ctx, added, removed)
920 addmodified(pdiff, ctx, modified)
920 addmodified(pdiff, ctx, modified)
921 addremoved(pdiff, ctx, removed)
921 addremoved(pdiff, ctx, removed)
922 if repophid:
922 if repophid:
923 pdiff.repositoryPHID = repophid
923 pdiff.repositoryPHID = repophid
924 diff = callconduit(
924 diff = callconduit(
925 repo.ui,
925 repo.ui,
926 b'differential.creatediff',
926 b'differential.creatediff',
927 pycompat.byteskwargs(attr.asdict(pdiff)),
927 pycompat.byteskwargs(attr.asdict(pdiff)),
928 )
928 )
929 if not diff:
929 if not diff:
930 raise error.Abort(_(b'cannot create diff for %s') % ctx)
930 raise error.Abort(_(b'cannot create diff for %s') % ctx)
931 return diff
931 return diff
932
932
933
933
934 def writediffproperties(ctx, diff):
934 def writediffproperties(ctx, diff):
935 """write metadata to diff so patches could be applied losslessly"""
935 """write metadata to diff so patches could be applied losslessly"""
936 # creatediff returns with a diffid but query returns with an id
936 # creatediff returns with a diffid but query returns with an id
937 diffid = diff.get(b'diffid', diff.get(b'id'))
937 diffid = diff.get(b'diffid', diff.get(b'id'))
938 params = {
938 params = {
939 b'diff_id': diffid,
939 b'diff_id': diffid,
940 b'name': b'hg:meta',
940 b'name': b'hg:meta',
941 b'data': templatefilters.json(
941 b'data': templatefilters.json(
942 {
942 {
943 b'user': ctx.user(),
943 b'user': ctx.user(),
944 b'date': b'%d %d' % ctx.date(),
944 b'date': b'%d %d' % ctx.date(),
945 b'branch': ctx.branch(),
945 b'branch': ctx.branch(),
946 b'node': ctx.hex(),
946 b'node': ctx.hex(),
947 b'parent': ctx.p1().hex(),
947 b'parent': ctx.p1().hex(),
948 }
948 }
949 ),
949 ),
950 }
950 }
951 callconduit(ctx.repo().ui, b'differential.setdiffproperty', params)
951 callconduit(ctx.repo().ui, b'differential.setdiffproperty', params)
952
952
953 params = {
953 params = {
954 b'diff_id': diffid,
954 b'diff_id': diffid,
955 b'name': b'local:commits',
955 b'name': b'local:commits',
956 b'data': templatefilters.json(
956 b'data': templatefilters.json(
957 {
957 {
958 ctx.hex(): {
958 ctx.hex(): {
959 b'author': stringutil.person(ctx.user()),
959 b'author': stringutil.person(ctx.user()),
960 b'authorEmail': stringutil.email(ctx.user()),
960 b'authorEmail': stringutil.email(ctx.user()),
961 b'time': int(ctx.date()[0]),
961 b'time': int(ctx.date()[0]),
962 b'commit': ctx.hex(),
962 b'commit': ctx.hex(),
963 b'parents': [ctx.p1().hex()],
963 b'parents': [ctx.p1().hex()],
964 b'branch': ctx.branch(),
964 b'branch': ctx.branch(),
965 },
965 },
966 }
966 }
967 ),
967 ),
968 }
968 }
969 callconduit(ctx.repo().ui, b'differential.setdiffproperty', params)
969 callconduit(ctx.repo().ui, b'differential.setdiffproperty', params)
970
970
971
971
972 def createdifferentialrevision(
972 def createdifferentialrevision(
973 ctx,
973 ctx,
974 revid=None,
974 revid=None,
975 parentrevphid=None,
975 parentrevphid=None,
976 oldnode=None,
976 oldnode=None,
977 olddiff=None,
977 olddiff=None,
978 actions=None,
978 actions=None,
979 comment=None,
979 comment=None,
980 ):
980 ):
981 """create or update a Differential Revision
981 """create or update a Differential Revision
982
982
983 If revid is None, create a new Differential Revision, otherwise update
983 If revid is None, create a new Differential Revision, otherwise update
984 revid. If parentrevphid is not None, set it as a dependency.
984 revid. If parentrevphid is not None, set it as a dependency.
985
985
986 If oldnode is not None, check if the patch content (without commit message
986 If oldnode is not None, check if the patch content (without commit message
987 and metadata) has changed before creating another diff.
987 and metadata) has changed before creating another diff.
988
988
989 If actions is not None, they will be appended to the transaction.
989 If actions is not None, they will be appended to the transaction.
990 """
990 """
991 repo = ctx.repo()
991 repo = ctx.repo()
992 if oldnode:
992 if oldnode:
993 diffopts = mdiff.diffopts(git=True, context=32767)
993 diffopts = mdiff.diffopts(git=True, context=32767)
994 oldctx = repo.unfiltered()[oldnode]
994 oldctx = repo.unfiltered()[oldnode]
995 neednewdiff = getdiff(ctx, diffopts) != getdiff(oldctx, diffopts)
995 neednewdiff = getdiff(ctx, diffopts) != getdiff(oldctx, diffopts)
996 else:
996 else:
997 neednewdiff = True
997 neednewdiff = True
998
998
999 transactions = []
999 transactions = []
1000 if neednewdiff:
1000 if neednewdiff:
1001 diff = creatediff(ctx)
1001 diff = creatediff(ctx)
1002 transactions.append({b'type': b'update', b'value': diff[b'phid']})
1002 transactions.append({b'type': b'update', b'value': diff[b'phid']})
1003 if comment:
1003 if comment:
1004 transactions.append({b'type': b'comment', b'value': comment})
1004 transactions.append({b'type': b'comment', b'value': comment})
1005 else:
1005 else:
1006 # Even if we don't need to upload a new diff because the patch content
1006 # Even if we don't need to upload a new diff because the patch content
1007 # does not change. We might still need to update its metadata so
1007 # does not change. We might still need to update its metadata so
1008 # pushers could know the correct node metadata.
1008 # pushers could know the correct node metadata.
1009 assert olddiff
1009 assert olddiff
1010 diff = olddiff
1010 diff = olddiff
1011 writediffproperties(ctx, diff)
1011 writediffproperties(ctx, diff)
1012
1012
1013 # Set the parent Revision every time, so commit re-ordering is picked-up
1013 # Set the parent Revision every time, so commit re-ordering is picked-up
1014 if parentrevphid:
1014 if parentrevphid:
1015 transactions.append(
1015 transactions.append(
1016 {b'type': b'parents.set', b'value': [parentrevphid]}
1016 {b'type': b'parents.set', b'value': [parentrevphid]}
1017 )
1017 )
1018
1018
1019 if actions:
1019 if actions:
1020 transactions += actions
1020 transactions += actions
1021
1021
1022 # Parse commit message and update related fields.
1022 # Parse commit message and update related fields.
1023 desc = ctx.description()
1023 desc = ctx.description()
1024 info = callconduit(
1024 info = callconduit(
1025 repo.ui, b'differential.parsecommitmessage', {b'corpus': desc}
1025 repo.ui, b'differential.parsecommitmessage', {b'corpus': desc}
1026 )
1026 )
1027 for k, v in info[b'fields'].items():
1027 for k, v in info[b'fields'].items():
1028 if k in [b'title', b'summary', b'testPlan']:
1028 if k in [b'title', b'summary', b'testPlan']:
1029 transactions.append({b'type': k, b'value': v})
1029 transactions.append({b'type': k, b'value': v})
1030
1030
1031 params = {b'transactions': transactions}
1031 params = {b'transactions': transactions}
1032 if revid is not None:
1032 if revid is not None:
1033 # Update an existing Differential Revision
1033 # Update an existing Differential Revision
1034 params[b'objectIdentifier'] = revid
1034 params[b'objectIdentifier'] = revid
1035
1035
1036 revision = callconduit(repo.ui, b'differential.revision.edit', params)
1036 revision = callconduit(repo.ui, b'differential.revision.edit', params)
1037 if not revision:
1037 if not revision:
1038 raise error.Abort(_(b'cannot create revision for %s') % ctx)
1038 raise error.Abort(_(b'cannot create revision for %s') % ctx)
1039
1039
1040 return revision, diff
1040 return revision, diff
1041
1041
1042
1042
1043 def userphids(repo, names):
1043 def userphids(repo, names):
1044 """convert user names to PHIDs"""
1044 """convert user names to PHIDs"""
1045 names = [name.lower() for name in names]
1045 names = [name.lower() for name in names]
1046 query = {b'constraints': {b'usernames': names}}
1046 query = {b'constraints': {b'usernames': names}}
1047 result = callconduit(repo.ui, b'user.search', query)
1047 result = callconduit(repo.ui, b'user.search', query)
1048 # username not found is not an error of the API. So check if we have missed
1048 # username not found is not an error of the API. So check if we have missed
1049 # some names here.
1049 # some names here.
1050 data = result[b'data']
1050 data = result[b'data']
1051 resolved = set(entry[b'fields'][b'username'].lower() for entry in data)
1051 resolved = set(entry[b'fields'][b'username'].lower() for entry in data)
1052 unresolved = set(names) - resolved
1052 unresolved = set(names) - resolved
1053 if unresolved:
1053 if unresolved:
1054 raise error.Abort(
1054 raise error.Abort(
1055 _(b'unknown username: %s') % b' '.join(sorted(unresolved))
1055 _(b'unknown username: %s') % b' '.join(sorted(unresolved))
1056 )
1056 )
1057 return [entry[b'phid'] for entry in data]
1057 return [entry[b'phid'] for entry in data]
1058
1058
1059
1059
1060 @vcrcommand(
1060 @vcrcommand(
1061 b'phabsend',
1061 b'phabsend',
1062 [
1062 [
1063 (b'r', b'rev', [], _(b'revisions to send'), _(b'REV')),
1063 (b'r', b'rev', [], _(b'revisions to send'), _(b'REV')),
1064 (b'', b'amend', True, _(b'update commit messages')),
1064 (b'', b'amend', True, _(b'update commit messages')),
1065 (b'', b'reviewer', [], _(b'specify reviewers')),
1065 (b'', b'reviewer', [], _(b'specify reviewers')),
1066 (b'', b'blocker', [], _(b'specify blocking reviewers')),
1066 (b'', b'blocker', [], _(b'specify blocking reviewers')),
1067 (
1067 (
1068 b'm',
1068 b'm',
1069 b'comment',
1069 b'comment',
1070 b'',
1070 b'',
1071 _(b'add a comment to Revisions with new/updated Diffs'),
1071 _(b'add a comment to Revisions with new/updated Diffs'),
1072 ),
1072 ),
1073 (b'', b'confirm', None, _(b'ask for confirmation before sending')),
1073 (b'', b'confirm', None, _(b'ask for confirmation before sending')),
1074 ],
1074 ],
1075 _(b'REV [OPTIONS]'),
1075 _(b'REV [OPTIONS]'),
1076 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1076 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1077 )
1077 )
1078 def phabsend(ui, repo, *revs, **opts):
1078 def phabsend(ui, repo, *revs, **opts):
1079 """upload changesets to Phabricator
1079 """upload changesets to Phabricator
1080
1080
1081 If there are multiple revisions specified, they will be send as a stack
1081 If there are multiple revisions specified, they will be send as a stack
1082 with a linear dependencies relationship using the order specified by the
1082 with a linear dependencies relationship using the order specified by the
1083 revset.
1083 revset.
1084
1084
1085 For the first time uploading changesets, local tags will be created to
1085 For the first time uploading changesets, local tags will be created to
1086 maintain the association. After the first time, phabsend will check
1086 maintain the association. After the first time, phabsend will check
1087 obsstore and tags information so it can figure out whether to update an
1087 obsstore and tags information so it can figure out whether to update an
1088 existing Differential Revision, or create a new one.
1088 existing Differential Revision, or create a new one.
1089
1089
1090 If --amend is set, update commit messages so they have the
1090 If --amend is set, update commit messages so they have the
1091 ``Differential Revision`` URL, remove related tags. This is similar to what
1091 ``Differential Revision`` URL, remove related tags. This is similar to what
1092 arcanist will do, and is more desired in author-push workflows. Otherwise,
1092 arcanist will do, and is more desired in author-push workflows. Otherwise,
1093 use local tags to record the ``Differential Revision`` association.
1093 use local tags to record the ``Differential Revision`` association.
1094
1094
1095 The --confirm option lets you confirm changesets before sending them. You
1095 The --confirm option lets you confirm changesets before sending them. You
1096 can also add following to your configuration file to make it default
1096 can also add following to your configuration file to make it default
1097 behaviour::
1097 behaviour::
1098
1098
1099 [phabsend]
1099 [phabsend]
1100 confirm = true
1100 confirm = true
1101
1101
1102 phabsend will check obsstore and the above association to decide whether to
1102 phabsend will check obsstore and the above association to decide whether to
1103 update an existing Differential Revision, or create a new one.
1103 update an existing Differential Revision, or create a new one.
1104 """
1104 """
1105 opts = pycompat.byteskwargs(opts)
1105 opts = pycompat.byteskwargs(opts)
1106 revs = list(revs) + opts.get(b'rev', [])
1106 revs = list(revs) + opts.get(b'rev', [])
1107 revs = scmutil.revrange(repo, revs)
1107 revs = scmutil.revrange(repo, revs)
1108 revs.sort() # ascending order to preserve topological parent/child in phab
1108 revs.sort() # ascending order to preserve topological parent/child in phab
1109
1109
1110 if not revs:
1110 if not revs:
1111 raise error.Abort(_(b'phabsend requires at least one changeset'))
1111 raise error.Abort(_(b'phabsend requires at least one changeset'))
1112 if opts.get(b'amend'):
1112 if opts.get(b'amend'):
1113 cmdutil.checkunfinished(repo)
1113 cmdutil.checkunfinished(repo)
1114
1114
1115 # {newnode: (oldnode, olddiff, olddrev}
1115 # {newnode: (oldnode, olddiff, olddrev}
1116 oldmap = getoldnodedrevmap(repo, [repo[r].node() for r in revs])
1116 oldmap = getoldnodedrevmap(repo, [repo[r].node() for r in revs])
1117
1117
1118 confirm = ui.configbool(b'phabsend', b'confirm')
1118 confirm = ui.configbool(b'phabsend', b'confirm')
1119 confirm |= bool(opts.get(b'confirm'))
1119 confirm |= bool(opts.get(b'confirm'))
1120 if confirm:
1120 if confirm:
1121 confirmed = _confirmbeforesend(repo, revs, oldmap)
1121 confirmed = _confirmbeforesend(repo, revs, oldmap)
1122 if not confirmed:
1122 if not confirmed:
1123 raise error.Abort(_(b'phabsend cancelled'))
1123 raise error.Abort(_(b'phabsend cancelled'))
1124
1124
1125 actions = []
1125 actions = []
1126 reviewers = opts.get(b'reviewer', [])
1126 reviewers = opts.get(b'reviewer', [])
1127 blockers = opts.get(b'blocker', [])
1127 blockers = opts.get(b'blocker', [])
1128 phids = []
1128 phids = []
1129 if reviewers:
1129 if reviewers:
1130 phids.extend(userphids(repo, reviewers))
1130 phids.extend(userphids(repo, reviewers))
1131 if blockers:
1131 if blockers:
1132 phids.extend(
1132 phids.extend(
1133 map(lambda phid: b'blocking(%s)' % phid, userphids(repo, blockers))
1133 map(lambda phid: b'blocking(%s)' % phid, userphids(repo, blockers))
1134 )
1134 )
1135 if phids:
1135 if phids:
1136 actions.append({b'type': b'reviewers.add', b'value': phids})
1136 actions.append({b'type': b'reviewers.add', b'value': phids})
1137
1137
1138 drevids = [] # [int]
1138 drevids = [] # [int]
1139 diffmap = {} # {newnode: diff}
1139 diffmap = {} # {newnode: diff}
1140
1140
1141 # Send patches one by one so we know their Differential Revision PHIDs and
1141 # Send patches one by one so we know their Differential Revision PHIDs and
1142 # can provide dependency relationship
1142 # can provide dependency relationship
1143 lastrevphid = None
1143 lastrevphid = None
1144 for rev in revs:
1144 for rev in revs:
1145 ui.debug(b'sending rev %d\n' % rev)
1145 ui.debug(b'sending rev %d\n' % rev)
1146 ctx = repo[rev]
1146 ctx = repo[rev]
1147
1147
1148 # Get Differential Revision ID
1148 # Get Differential Revision ID
1149 oldnode, olddiff, revid = oldmap.get(ctx.node(), (None, None, None))
1149 oldnode, olddiff, revid = oldmap.get(ctx.node(), (None, None, None))
1150 if oldnode != ctx.node() or opts.get(b'amend'):
1150 if oldnode != ctx.node() or opts.get(b'amend'):
1151 # Create or update Differential Revision
1151 # Create or update Differential Revision
1152 revision, diff = createdifferentialrevision(
1152 revision, diff = createdifferentialrevision(
1153 ctx,
1153 ctx,
1154 revid,
1154 revid,
1155 lastrevphid,
1155 lastrevphid,
1156 oldnode,
1156 oldnode,
1157 olddiff,
1157 olddiff,
1158 actions,
1158 actions,
1159 opts.get(b'comment'),
1159 opts.get(b'comment'),
1160 )
1160 )
1161 diffmap[ctx.node()] = diff
1161 diffmap[ctx.node()] = diff
1162 newrevid = int(revision[b'object'][b'id'])
1162 newrevid = int(revision[b'object'][b'id'])
1163 newrevphid = revision[b'object'][b'phid']
1163 newrevphid = revision[b'object'][b'phid']
1164 if revid:
1164 if revid:
1165 action = b'updated'
1165 action = b'updated'
1166 else:
1166 else:
1167 action = b'created'
1167 action = b'created'
1168
1168
1169 # Create a local tag to note the association, if commit message
1169 # Create a local tag to note the association, if commit message
1170 # does not have it already
1170 # does not have it already
1171 m = _differentialrevisiondescre.search(ctx.description())
1171 m = _differentialrevisiondescre.search(ctx.description())
1172 if not m or int(m.group('id')) != newrevid:
1172 if not m or int(m.group('id')) != newrevid:
1173 tagname = b'D%d' % newrevid
1173 tagname = b'D%d' % newrevid
1174 tags.tag(
1174 tags.tag(
1175 repo,
1175 repo,
1176 tagname,
1176 tagname,
1177 ctx.node(),
1177 ctx.node(),
1178 message=None,
1178 message=None,
1179 user=None,
1179 user=None,
1180 date=None,
1180 date=None,
1181 local=True,
1181 local=True,
1182 )
1182 )
1183 else:
1183 else:
1184 # Nothing changed. But still set "newrevphid" so the next revision
1184 # Nothing changed. But still set "newrevphid" so the next revision
1185 # could depend on this one and "newrevid" for the summary line.
1185 # could depend on this one and "newrevid" for the summary line.
1186 newrevphid = querydrev(repo, b'%d' % revid)[0][b'phid']
1186 newrevphid = querydrev(repo, b'%d' % revid)[0][b'phid']
1187 newrevid = revid
1187 newrevid = revid
1188 action = b'skipped'
1188 action = b'skipped'
1189
1189
1190 actiondesc = ui.label(
1190 actiondesc = ui.label(
1191 {
1191 {
1192 b'created': _(b'created'),
1192 b'created': _(b'created'),
1193 b'skipped': _(b'skipped'),
1193 b'skipped': _(b'skipped'),
1194 b'updated': _(b'updated'),
1194 b'updated': _(b'updated'),
1195 }[action],
1195 }[action],
1196 b'phabricator.action.%s' % action,
1196 b'phabricator.action.%s' % action,
1197 )
1197 )
1198 drevdesc = ui.label(b'D%d' % newrevid, b'phabricator.drev')
1198 drevdesc = ui.label(b'D%d' % newrevid, b'phabricator.drev')
1199 nodedesc = ui.label(bytes(ctx), b'phabricator.node')
1199 nodedesc = ui.label(bytes(ctx), b'phabricator.node')
1200 desc = ui.label(ctx.description().split(b'\n')[0], b'phabricator.desc')
1200 desc = ui.label(ctx.description().split(b'\n')[0], b'phabricator.desc')
1201 ui.write(
1201 ui.write(
1202 _(b'%s - %s - %s: %s\n') % (drevdesc, actiondesc, nodedesc, desc)
1202 _(b'%s - %s - %s: %s\n') % (drevdesc, actiondesc, nodedesc, desc)
1203 )
1203 )
1204 drevids.append(newrevid)
1204 drevids.append(newrevid)
1205 lastrevphid = newrevphid
1205 lastrevphid = newrevphid
1206
1206
1207 # Update commit messages and remove tags
1207 # Update commit messages and remove tags
1208 if opts.get(b'amend'):
1208 if opts.get(b'amend'):
1209 unfi = repo.unfiltered()
1209 unfi = repo.unfiltered()
1210 drevs = callconduit(ui, b'differential.query', {b'ids': drevids})
1210 drevs = callconduit(ui, b'differential.query', {b'ids': drevids})
1211 with repo.wlock(), repo.lock(), repo.transaction(b'phabsend'):
1211 with repo.wlock(), repo.lock(), repo.transaction(b'phabsend'):
1212 wnode = unfi[b'.'].node()
1212 wnode = unfi[b'.'].node()
1213 mapping = {} # {oldnode: [newnode]}
1213 mapping = {} # {oldnode: [newnode]}
1214 for i, rev in enumerate(revs):
1214 for i, rev in enumerate(revs):
1215 old = unfi[rev]
1215 old = unfi[rev]
1216 drevid = drevids[i]
1216 drevid = drevids[i]
1217 drev = [d for d in drevs if int(d[b'id']) == drevid][0]
1217 drev = [d for d in drevs if int(d[b'id']) == drevid][0]
1218 newdesc = getdescfromdrev(drev)
1218 newdesc = getdescfromdrev(drev)
1219 # Make sure commit message contain "Differential Revision"
1219 # Make sure commit message contain "Differential Revision"
1220 if old.description() != newdesc:
1220 if old.description() != newdesc:
1221 if old.phase() == phases.public:
1221 if old.phase() == phases.public:
1222 ui.warn(
1222 ui.warn(
1223 _(b"warning: not updating public commit %s\n")
1223 _(b"warning: not updating public commit %s\n")
1224 % scmutil.formatchangeid(old)
1224 % scmutil.formatchangeid(old)
1225 )
1225 )
1226 continue
1226 continue
1227 parents = [
1227 parents = [
1228 mapping.get(old.p1().node(), (old.p1(),))[0],
1228 mapping.get(old.p1().node(), (old.p1(),))[0],
1229 mapping.get(old.p2().node(), (old.p2(),))[0],
1229 mapping.get(old.p2().node(), (old.p2(),))[0],
1230 ]
1230 ]
1231 new = context.metadataonlyctx(
1231 new = context.metadataonlyctx(
1232 repo,
1232 repo,
1233 old,
1233 old,
1234 parents=parents,
1234 parents=parents,
1235 text=newdesc,
1235 text=newdesc,
1236 user=old.user(),
1236 user=old.user(),
1237 date=old.date(),
1237 date=old.date(),
1238 extra=old.extra(),
1238 extra=old.extra(),
1239 )
1239 )
1240
1240
1241 newnode = new.commit()
1241 newnode = new.commit()
1242
1242
1243 mapping[old.node()] = [newnode]
1243 mapping[old.node()] = [newnode]
1244 # Update diff property
1244 # Update diff property
1245 # If it fails just warn and keep going, otherwise the DREV
1245 # If it fails just warn and keep going, otherwise the DREV
1246 # associations will be lost
1246 # associations will be lost
1247 try:
1247 try:
1248 writediffproperties(unfi[newnode], diffmap[old.node()])
1248 writediffproperties(unfi[newnode], diffmap[old.node()])
1249 except util.urlerr.urlerror:
1249 except util.urlerr.urlerror:
1250 ui.warnnoi18n(
1250 ui.warnnoi18n(
1251 b'Failed to update metadata for D%d\n' % drevid
1251 b'Failed to update metadata for D%d\n' % drevid
1252 )
1252 )
1253 # Remove local tags since it's no longer necessary
1253 # Remove local tags since it's no longer necessary
1254 tagname = b'D%d' % drevid
1254 tagname = b'D%d' % drevid
1255 if tagname in repo.tags():
1255 if tagname in repo.tags():
1256 tags.tag(
1256 tags.tag(
1257 repo,
1257 repo,
1258 tagname,
1258 tagname,
1259 nullid,
1259 nullid,
1260 message=None,
1260 message=None,
1261 user=None,
1261 user=None,
1262 date=None,
1262 date=None,
1263 local=True,
1263 local=True,
1264 )
1264 )
1265 scmutil.cleanupnodes(repo, mapping, b'phabsend', fixphase=True)
1265 scmutil.cleanupnodes(repo, mapping, b'phabsend', fixphase=True)
1266 if wnode in mapping:
1266 if wnode in mapping:
1267 unfi.setparents(mapping[wnode][0])
1267 unfi.setparents(mapping[wnode][0])
1268
1268
1269
1269
1270 # Map from "hg:meta" keys to header understood by "hg import". The order is
1270 # Map from "hg:meta" keys to header understood by "hg import". The order is
1271 # consistent with "hg export" output.
1271 # consistent with "hg export" output.
1272 _metanamemap = util.sortdict(
1272 _metanamemap = util.sortdict(
1273 [
1273 [
1274 (b'user', b'User'),
1274 (b'user', b'User'),
1275 (b'date', b'Date'),
1275 (b'date', b'Date'),
1276 (b'branch', b'Branch'),
1276 (b'branch', b'Branch'),
1277 (b'node', b'Node ID'),
1277 (b'node', b'Node ID'),
1278 (b'parent', b'Parent '),
1278 (b'parent', b'Parent '),
1279 ]
1279 ]
1280 )
1280 )
1281
1281
1282
1282
1283 def _confirmbeforesend(repo, revs, oldmap):
1283 def _confirmbeforesend(repo, revs, oldmap):
1284 url, token = readurltoken(repo.ui)
1284 url, token = readurltoken(repo.ui)
1285 ui = repo.ui
1285 ui = repo.ui
1286 for rev in revs:
1286 for rev in revs:
1287 ctx = repo[rev]
1287 ctx = repo[rev]
1288 desc = ctx.description().splitlines()[0]
1288 desc = ctx.description().splitlines()[0]
1289 oldnode, olddiff, drevid = oldmap.get(ctx.node(), (None, None, None))
1289 oldnode, olddiff, drevid = oldmap.get(ctx.node(), (None, None, None))
1290 if drevid:
1290 if drevid:
1291 drevdesc = ui.label(b'D%d' % drevid, b'phabricator.drev')
1291 drevdesc = ui.label(b'D%d' % drevid, b'phabricator.drev')
1292 else:
1292 else:
1293 drevdesc = ui.label(_(b'NEW'), b'phabricator.drev')
1293 drevdesc = ui.label(_(b'NEW'), b'phabricator.drev')
1294
1294
1295 ui.write(
1295 ui.write(
1296 _(b'%s - %s: %s\n')
1296 _(b'%s - %s: %s\n')
1297 % (
1297 % (
1298 drevdesc,
1298 drevdesc,
1299 ui.label(bytes(ctx), b'phabricator.node'),
1299 ui.label(bytes(ctx), b'phabricator.node'),
1300 ui.label(desc, b'phabricator.desc'),
1300 ui.label(desc, b'phabricator.desc'),
1301 )
1301 )
1302 )
1302 )
1303
1303
1304 if ui.promptchoice(
1304 if ui.promptchoice(
1305 _(b'Send the above changes to %s (yn)?$$ &Yes $$ &No') % url
1305 _(b'Send the above changes to %s (yn)?$$ &Yes $$ &No') % url
1306 ):
1306 ):
1307 return False
1307 return False
1308
1308
1309 return True
1309 return True
1310
1310
1311
1311
1312 _knownstatusnames = {
1312 _knownstatusnames = {
1313 b'accepted',
1313 b'accepted',
1314 b'needsreview',
1314 b'needsreview',
1315 b'needsrevision',
1315 b'needsrevision',
1316 b'closed',
1316 b'closed',
1317 b'abandoned',
1317 b'abandoned',
1318 b'changesplanned',
1318 b'changesplanned',
1319 }
1319 }
1320
1320
1321
1321
1322 def _getstatusname(drev):
1322 def _getstatusname(drev):
1323 """get normalized status name from a Differential Revision"""
1323 """get normalized status name from a Differential Revision"""
1324 return drev[b'statusName'].replace(b' ', b'').lower()
1324 return drev[b'statusName'].replace(b' ', b'').lower()
1325
1325
1326
1326
1327 # Small language to specify differential revisions. Support symbols: (), :X,
1327 # Small language to specify differential revisions. Support symbols: (), :X,
1328 # +, and -.
1328 # +, and -.
1329
1329
1330 _elements = {
1330 _elements = {
1331 # token-type: binding-strength, primary, prefix, infix, suffix
1331 # token-type: binding-strength, primary, prefix, infix, suffix
1332 b'(': (12, None, (b'group', 1, b')'), None, None),
1332 b'(': (12, None, (b'group', 1, b')'), None, None),
1333 b':': (8, None, (b'ancestors', 8), None, None),
1333 b':': (8, None, (b'ancestors', 8), None, None),
1334 b'&': (5, None, None, (b'and_', 5), None),
1334 b'&': (5, None, None, (b'and_', 5), None),
1335 b'+': (4, None, None, (b'add', 4), None),
1335 b'+': (4, None, None, (b'add', 4), None),
1336 b'-': (4, None, None, (b'sub', 4), None),
1336 b'-': (4, None, None, (b'sub', 4), None),
1337 b')': (0, None, None, None, None),
1337 b')': (0, None, None, None, None),
1338 b'symbol': (0, b'symbol', None, None, None),
1338 b'symbol': (0, b'symbol', None, None, None),
1339 b'end': (0, None, None, None, None),
1339 b'end': (0, None, None, None, None),
1340 }
1340 }
1341
1341
1342
1342
1343 def _tokenize(text):
1343 def _tokenize(text):
1344 view = memoryview(text) # zero-copy slice
1344 view = memoryview(text) # zero-copy slice
1345 special = b'():+-& '
1345 special = b'():+-& '
1346 pos = 0
1346 pos = 0
1347 length = len(text)
1347 length = len(text)
1348 while pos < length:
1348 while pos < length:
1349 symbol = b''.join(
1349 symbol = b''.join(
1350 itertools.takewhile(
1350 itertools.takewhile(
1351 lambda ch: ch not in special, pycompat.iterbytestr(view[pos:])
1351 lambda ch: ch not in special, pycompat.iterbytestr(view[pos:])
1352 )
1352 )
1353 )
1353 )
1354 if symbol:
1354 if symbol:
1355 yield (b'symbol', symbol, pos)
1355 yield (b'symbol', symbol, pos)
1356 pos += len(symbol)
1356 pos += len(symbol)
1357 else: # special char, ignore space
1357 else: # special char, ignore space
1358 if text[pos : pos + 1] != b' ':
1358 if text[pos : pos + 1] != b' ':
1359 yield (text[pos : pos + 1], None, pos)
1359 yield (text[pos : pos + 1], None, pos)
1360 pos += 1
1360 pos += 1
1361 yield (b'end', None, pos)
1361 yield (b'end', None, pos)
1362
1362
1363
1363
1364 def _parse(text):
1364 def _parse(text):
1365 tree, pos = parser.parser(_elements).parse(_tokenize(text))
1365 tree, pos = parser.parser(_elements).parse(_tokenize(text))
1366 if pos != len(text):
1366 if pos != len(text):
1367 raise error.ParseError(b'invalid token', pos)
1367 raise error.ParseError(b'invalid token', pos)
1368 return tree
1368 return tree
1369
1369
1370
1370
1371 def _parsedrev(symbol):
1371 def _parsedrev(symbol):
1372 """str -> int or None, ex. 'D45' -> 45; '12' -> 12; 'x' -> None"""
1372 """str -> int or None, ex. 'D45' -> 45; '12' -> 12; 'x' -> None"""
1373 if symbol.startswith(b'D') and symbol[1:].isdigit():
1373 if symbol.startswith(b'D') and symbol[1:].isdigit():
1374 return int(symbol[1:])
1374 return int(symbol[1:])
1375 if symbol.isdigit():
1375 if symbol.isdigit():
1376 return int(symbol)
1376 return int(symbol)
1377
1377
1378
1378
1379 def _prefetchdrevs(tree):
1379 def _prefetchdrevs(tree):
1380 """return ({single-drev-id}, {ancestor-drev-id}) to prefetch"""
1380 """return ({single-drev-id}, {ancestor-drev-id}) to prefetch"""
1381 drevs = set()
1381 drevs = set()
1382 ancestordrevs = set()
1382 ancestordrevs = set()
1383 op = tree[0]
1383 op = tree[0]
1384 if op == b'symbol':
1384 if op == b'symbol':
1385 r = _parsedrev(tree[1])
1385 r = _parsedrev(tree[1])
1386 if r:
1386 if r:
1387 drevs.add(r)
1387 drevs.add(r)
1388 elif op == b'ancestors':
1388 elif op == b'ancestors':
1389 r, a = _prefetchdrevs(tree[1])
1389 r, a = _prefetchdrevs(tree[1])
1390 drevs.update(r)
1390 drevs.update(r)
1391 ancestordrevs.update(r)
1391 ancestordrevs.update(r)
1392 ancestordrevs.update(a)
1392 ancestordrevs.update(a)
1393 else:
1393 else:
1394 for t in tree[1:]:
1394 for t in tree[1:]:
1395 r, a = _prefetchdrevs(t)
1395 r, a = _prefetchdrevs(t)
1396 drevs.update(r)
1396 drevs.update(r)
1397 ancestordrevs.update(a)
1397 ancestordrevs.update(a)
1398 return drevs, ancestordrevs
1398 return drevs, ancestordrevs
1399
1399
1400
1400
1401 def querydrev(repo, spec):
1401 def querydrev(repo, spec):
1402 """return a list of "Differential Revision" dicts
1402 """return a list of "Differential Revision" dicts
1403
1403
1404 spec is a string using a simple query language, see docstring in phabread
1404 spec is a string using a simple query language, see docstring in phabread
1405 for details.
1405 for details.
1406
1406
1407 A "Differential Revision dict" looks like:
1407 A "Differential Revision dict" looks like:
1408
1408
1409 {
1409 {
1410 "id": "2",
1410 "id": "2",
1411 "phid": "PHID-DREV-672qvysjcczopag46qty",
1411 "phid": "PHID-DREV-672qvysjcczopag46qty",
1412 "title": "example",
1412 "title": "example",
1413 "uri": "https://phab.example.com/D2",
1413 "uri": "https://phab.example.com/D2",
1414 "dateCreated": "1499181406",
1414 "dateCreated": "1499181406",
1415 "dateModified": "1499182103",
1415 "dateModified": "1499182103",
1416 "authorPHID": "PHID-USER-tv3ohwc4v4jeu34otlye",
1416 "authorPHID": "PHID-USER-tv3ohwc4v4jeu34otlye",
1417 "status": "0",
1417 "status": "0",
1418 "statusName": "Needs Review",
1418 "statusName": "Needs Review",
1419 "properties": [],
1419 "properties": [],
1420 "branch": null,
1420 "branch": null,
1421 "summary": "",
1421 "summary": "",
1422 "testPlan": "",
1422 "testPlan": "",
1423 "lineCount": "2",
1423 "lineCount": "2",
1424 "activeDiffPHID": "PHID-DIFF-xoqnjkobbm6k4dk6hi72",
1424 "activeDiffPHID": "PHID-DIFF-xoqnjkobbm6k4dk6hi72",
1425 "diffs": [
1425 "diffs": [
1426 "3",
1426 "3",
1427 "4",
1427 "4",
1428 ],
1428 ],
1429 "commits": [],
1429 "commits": [],
1430 "reviewers": [],
1430 "reviewers": [],
1431 "ccs": [],
1431 "ccs": [],
1432 "hashes": [],
1432 "hashes": [],
1433 "auxiliary": {
1433 "auxiliary": {
1434 "phabricator:projects": [],
1434 "phabricator:projects": [],
1435 "phabricator:depends-on": [
1435 "phabricator:depends-on": [
1436 "PHID-DREV-gbapp366kutjebt7agcd"
1436 "PHID-DREV-gbapp366kutjebt7agcd"
1437 ]
1437 ]
1438 },
1438 },
1439 "repositoryPHID": "PHID-REPO-hub2hx62ieuqeheznasv",
1439 "repositoryPHID": "PHID-REPO-hub2hx62ieuqeheznasv",
1440 "sourcePath": null
1440 "sourcePath": null
1441 }
1441 }
1442 """
1442 """
1443
1443
1444 def fetch(params):
1444 def fetch(params):
1445 """params -> single drev or None"""
1445 """params -> single drev or None"""
1446 key = (params.get(b'ids') or params.get(b'phids') or [None])[0]
1446 key = (params.get(b'ids') or params.get(b'phids') or [None])[0]
1447 if key in prefetched:
1447 if key in prefetched:
1448 return prefetched[key]
1448 return prefetched[key]
1449 drevs = callconduit(repo.ui, b'differential.query', params)
1449 drevs = callconduit(repo.ui, b'differential.query', params)
1450 # Fill prefetched with the result
1450 # Fill prefetched with the result
1451 for drev in drevs:
1451 for drev in drevs:
1452 prefetched[drev[b'phid']] = drev
1452 prefetched[drev[b'phid']] = drev
1453 prefetched[int(drev[b'id'])] = drev
1453 prefetched[int(drev[b'id'])] = drev
1454 if key not in prefetched:
1454 if key not in prefetched:
1455 raise error.Abort(
1455 raise error.Abort(
1456 _(b'cannot get Differential Revision %r') % params
1456 _(b'cannot get Differential Revision %r') % params
1457 )
1457 )
1458 return prefetched[key]
1458 return prefetched[key]
1459
1459
1460 def getstack(topdrevids):
1460 def getstack(topdrevids):
1461 """given a top, get a stack from the bottom, [id] -> [id]"""
1461 """given a top, get a stack from the bottom, [id] -> [id]"""
1462 visited = set()
1462 visited = set()
1463 result = []
1463 result = []
1464 queue = [{b'ids': [i]} for i in topdrevids]
1464 queue = [{b'ids': [i]} for i in topdrevids]
1465 while queue:
1465 while queue:
1466 params = queue.pop()
1466 params = queue.pop()
1467 drev = fetch(params)
1467 drev = fetch(params)
1468 if drev[b'id'] in visited:
1468 if drev[b'id'] in visited:
1469 continue
1469 continue
1470 visited.add(drev[b'id'])
1470 visited.add(drev[b'id'])
1471 result.append(int(drev[b'id']))
1471 result.append(int(drev[b'id']))
1472 auxiliary = drev.get(b'auxiliary', {})
1472 auxiliary = drev.get(b'auxiliary', {})
1473 depends = auxiliary.get(b'phabricator:depends-on', [])
1473 depends = auxiliary.get(b'phabricator:depends-on', [])
1474 for phid in depends:
1474 for phid in depends:
1475 queue.append({b'phids': [phid]})
1475 queue.append({b'phids': [phid]})
1476 result.reverse()
1476 result.reverse()
1477 return smartset.baseset(result)
1477 return smartset.baseset(result)
1478
1478
1479 # Initialize prefetch cache
1479 # Initialize prefetch cache
1480 prefetched = {} # {id or phid: drev}
1480 prefetched = {} # {id or phid: drev}
1481
1481
1482 tree = _parse(spec)
1482 tree = _parse(spec)
1483 drevs, ancestordrevs = _prefetchdrevs(tree)
1483 drevs, ancestordrevs = _prefetchdrevs(tree)
1484
1484
1485 # developer config: phabricator.batchsize
1485 # developer config: phabricator.batchsize
1486 batchsize = repo.ui.configint(b'phabricator', b'batchsize')
1486 batchsize = repo.ui.configint(b'phabricator', b'batchsize')
1487
1487
1488 # Prefetch Differential Revisions in batch
1488 # Prefetch Differential Revisions in batch
1489 tofetch = set(drevs)
1489 tofetch = set(drevs)
1490 for r in ancestordrevs:
1490 for r in ancestordrevs:
1491 tofetch.update(range(max(1, r - batchsize), r + 1))
1491 tofetch.update(range(max(1, r - batchsize), r + 1))
1492 if drevs:
1492 if drevs:
1493 fetch({b'ids': list(tofetch)})
1493 fetch({b'ids': list(tofetch)})
1494 validids = sorted(set(getstack(list(ancestordrevs))) | set(drevs))
1494 validids = sorted(set(getstack(list(ancestordrevs))) | set(drevs))
1495
1495
1496 # Walk through the tree, return smartsets
1496 # Walk through the tree, return smartsets
1497 def walk(tree):
1497 def walk(tree):
1498 op = tree[0]
1498 op = tree[0]
1499 if op == b'symbol':
1499 if op == b'symbol':
1500 drev = _parsedrev(tree[1])
1500 drev = _parsedrev(tree[1])
1501 if drev:
1501 if drev:
1502 return smartset.baseset([drev])
1502 return smartset.baseset([drev])
1503 elif tree[1] in _knownstatusnames:
1503 elif tree[1] in _knownstatusnames:
1504 drevs = [
1504 drevs = [
1505 r
1505 r
1506 for r in validids
1506 for r in validids
1507 if _getstatusname(prefetched[r]) == tree[1]
1507 if _getstatusname(prefetched[r]) == tree[1]
1508 ]
1508 ]
1509 return smartset.baseset(drevs)
1509 return smartset.baseset(drevs)
1510 else:
1510 else:
1511 raise error.Abort(_(b'unknown symbol: %s') % tree[1])
1511 raise error.Abort(_(b'unknown symbol: %s') % tree[1])
1512 elif op in {b'and_', b'add', b'sub'}:
1512 elif op in {b'and_', b'add', b'sub'}:
1513 assert len(tree) == 3
1513 assert len(tree) == 3
1514 return getattr(operator, op)(walk(tree[1]), walk(tree[2]))
1514 return getattr(operator, op)(walk(tree[1]), walk(tree[2]))
1515 elif op == b'group':
1515 elif op == b'group':
1516 return walk(tree[1])
1516 return walk(tree[1])
1517 elif op == b'ancestors':
1517 elif op == b'ancestors':
1518 return getstack(walk(tree[1]))
1518 return getstack(walk(tree[1]))
1519 else:
1519 else:
1520 raise error.ProgrammingError(b'illegal tree: %r' % tree)
1520 raise error.ProgrammingError(b'illegal tree: %r' % tree)
1521
1521
1522 return [prefetched[r] for r in walk(tree)]
1522 return [prefetched[r] for r in walk(tree)]
1523
1523
1524
1524
1525 def getdescfromdrev(drev):
1525 def getdescfromdrev(drev):
1526 """get description (commit message) from "Differential Revision"
1526 """get description (commit message) from "Differential Revision"
1527
1527
1528 This is similar to differential.getcommitmessage API. But we only care
1528 This is similar to differential.getcommitmessage API. But we only care
1529 about limited fields: title, summary, test plan, and URL.
1529 about limited fields: title, summary, test plan, and URL.
1530 """
1530 """
1531 title = drev[b'title']
1531 title = drev[b'title']
1532 summary = drev[b'summary'].rstrip()
1532 summary = drev[b'summary'].rstrip()
1533 testplan = drev[b'testPlan'].rstrip()
1533 testplan = drev[b'testPlan'].rstrip()
1534 if testplan:
1534 if testplan:
1535 testplan = b'Test Plan:\n%s' % testplan
1535 testplan = b'Test Plan:\n%s' % testplan
1536 uri = b'Differential Revision: %s' % drev[b'uri']
1536 uri = b'Differential Revision: %s' % drev[b'uri']
1537 return b'\n\n'.join(filter(None, [title, summary, testplan, uri]))
1537 return b'\n\n'.join(filter(None, [title, summary, testplan, uri]))
1538
1538
1539
1539
1540 def getdiffmeta(diff):
1540 def getdiffmeta(diff):
1541 """get commit metadata (date, node, user, p1) from a diff object
1541 """get commit metadata (date, node, user, p1) from a diff object
1542
1542
1543 The metadata could be "hg:meta", sent by phabsend, like:
1543 The metadata could be "hg:meta", sent by phabsend, like:
1544
1544
1545 "properties": {
1545 "properties": {
1546 "hg:meta": {
1546 "hg:meta": {
1547 "date": "1499571514 25200",
1547 "date": "1499571514 25200",
1548 "node": "98c08acae292b2faf60a279b4189beb6cff1414d",
1548 "node": "98c08acae292b2faf60a279b4189beb6cff1414d",
1549 "user": "Foo Bar <foo@example.com>",
1549 "user": "Foo Bar <foo@example.com>",
1550 "parent": "6d0abad76b30e4724a37ab8721d630394070fe16"
1550 "parent": "6d0abad76b30e4724a37ab8721d630394070fe16"
1551 }
1551 }
1552 }
1552 }
1553
1553
1554 Or converted from "local:commits", sent by "arc", like:
1554 Or converted from "local:commits", sent by "arc", like:
1555
1555
1556 "properties": {
1556 "properties": {
1557 "local:commits": {
1557 "local:commits": {
1558 "98c08acae292b2faf60a279b4189beb6cff1414d": {
1558 "98c08acae292b2faf60a279b4189beb6cff1414d": {
1559 "author": "Foo Bar",
1559 "author": "Foo Bar",
1560 "time": 1499546314,
1560 "time": 1499546314,
1561 "branch": "default",
1561 "branch": "default",
1562 "tag": "",
1562 "tag": "",
1563 "commit": "98c08acae292b2faf60a279b4189beb6cff1414d",
1563 "commit": "98c08acae292b2faf60a279b4189beb6cff1414d",
1564 "rev": "98c08acae292b2faf60a279b4189beb6cff1414d",
1564 "rev": "98c08acae292b2faf60a279b4189beb6cff1414d",
1565 "local": "1000",
1565 "local": "1000",
1566 "parents": ["6d0abad76b30e4724a37ab8721d630394070fe16"],
1566 "parents": ["6d0abad76b30e4724a37ab8721d630394070fe16"],
1567 "summary": "...",
1567 "summary": "...",
1568 "message": "...",
1568 "message": "...",
1569 "authorEmail": "foo@example.com"
1569 "authorEmail": "foo@example.com"
1570 }
1570 }
1571 }
1571 }
1572 }
1572 }
1573
1573
1574 Note: metadata extracted from "local:commits" will lose time zone
1574 Note: metadata extracted from "local:commits" will lose time zone
1575 information.
1575 information.
1576 """
1576 """
1577 props = diff.get(b'properties') or {}
1577 props = diff.get(b'properties') or {}
1578 meta = props.get(b'hg:meta')
1578 meta = props.get(b'hg:meta')
1579 if not meta:
1579 if not meta:
1580 if props.get(b'local:commits'):
1580 if props.get(b'local:commits'):
1581 commit = sorted(props[b'local:commits'].values())[0]
1581 commit = sorted(props[b'local:commits'].values())[0]
1582 meta = {}
1582 meta = {}
1583 if b'author' in commit and b'authorEmail' in commit:
1583 if b'author' in commit and b'authorEmail' in commit:
1584 meta[b'user'] = b'%s <%s>' % (
1584 meta[b'user'] = b'%s <%s>' % (
1585 commit[b'author'],
1585 commit[b'author'],
1586 commit[b'authorEmail'],
1586 commit[b'authorEmail'],
1587 )
1587 )
1588 if b'time' in commit:
1588 if b'time' in commit:
1589 meta[b'date'] = b'%d 0' % int(commit[b'time'])
1589 meta[b'date'] = b'%d 0' % int(commit[b'time'])
1590 if b'branch' in commit:
1590 if b'branch' in commit:
1591 meta[b'branch'] = commit[b'branch']
1591 meta[b'branch'] = commit[b'branch']
1592 node = commit.get(b'commit', commit.get(b'rev'))
1592 node = commit.get(b'commit', commit.get(b'rev'))
1593 if node:
1593 if node:
1594 meta[b'node'] = node
1594 meta[b'node'] = node
1595 if len(commit.get(b'parents', ())) >= 1:
1595 if len(commit.get(b'parents', ())) >= 1:
1596 meta[b'parent'] = commit[b'parents'][0]
1596 meta[b'parent'] = commit[b'parents'][0]
1597 else:
1597 else:
1598 meta = {}
1598 meta = {}
1599 if b'date' not in meta and b'dateCreated' in diff:
1599 if b'date' not in meta and b'dateCreated' in diff:
1600 meta[b'date'] = b'%s 0' % diff[b'dateCreated']
1600 meta[b'date'] = b'%s 0' % diff[b'dateCreated']
1601 if b'branch' not in meta and diff.get(b'branch'):
1601 if b'branch' not in meta and diff.get(b'branch'):
1602 meta[b'branch'] = diff[b'branch']
1602 meta[b'branch'] = diff[b'branch']
1603 if b'parent' not in meta and diff.get(b'sourceControlBaseRevision'):
1603 if b'parent' not in meta and diff.get(b'sourceControlBaseRevision'):
1604 meta[b'parent'] = diff[b'sourceControlBaseRevision']
1604 meta[b'parent'] = diff[b'sourceControlBaseRevision']
1605 return meta
1605 return meta
1606
1606
1607
1607
1608 def readpatch(repo, drevs, write):
1608 def readpatch(repo, drevs, write):
1609 """generate plain-text patch readable by 'hg import'
1609 """generate plain-text patch readable by 'hg import'
1610
1610
1611 write is usually ui.write. drevs is what "querydrev" returns, results of
1611 write is usually ui.write. drevs is what "querydrev" returns, results of
1612 "differential.query".
1612 "differential.query".
1613 """
1613 """
1614 # Prefetch hg:meta property for all diffs
1614 # Prefetch hg:meta property for all diffs
1615 diffids = sorted(set(max(int(v) for v in drev[b'diffs']) for drev in drevs))
1615 diffids = sorted(set(max(int(v) for v in drev[b'diffs']) for drev in drevs))
1616 diffs = callconduit(repo.ui, b'differential.querydiffs', {b'ids': diffids})
1616 diffs = callconduit(repo.ui, b'differential.querydiffs', {b'ids': diffids})
1617
1617
1618 # Generate patch for each drev
1618 # Generate patch for each drev
1619 for drev in drevs:
1619 for drev in drevs:
1620 repo.ui.note(_(b'reading D%s\n') % drev[b'id'])
1620 repo.ui.note(_(b'reading D%s\n') % drev[b'id'])
1621
1621
1622 diffid = max(int(v) for v in drev[b'diffs'])
1622 diffid = max(int(v) for v in drev[b'diffs'])
1623 body = callconduit(
1623 body = callconduit(
1624 repo.ui, b'differential.getrawdiff', {b'diffID': diffid}
1624 repo.ui, b'differential.getrawdiff', {b'diffID': diffid}
1625 )
1625 )
1626 desc = getdescfromdrev(drev)
1626 desc = getdescfromdrev(drev)
1627 header = b'# HG changeset patch\n'
1627 header = b'# HG changeset patch\n'
1628
1628
1629 # Try to preserve metadata from hg:meta property. Write hg patch
1629 # Try to preserve metadata from hg:meta property. Write hg patch
1630 # headers that can be read by the "import" command. See patchheadermap
1630 # headers that can be read by the "import" command. See patchheadermap
1631 # and extract in mercurial/patch.py for supported headers.
1631 # and extract in mercurial/patch.py for supported headers.
1632 meta = getdiffmeta(diffs[b'%d' % diffid])
1632 meta = getdiffmeta(diffs[b'%d' % diffid])
1633 for k in _metanamemap.keys():
1633 for k in _metanamemap.keys():
1634 if k in meta:
1634 if k in meta:
1635 header += b'# %s %s\n' % (_metanamemap[k], meta[k])
1635 header += b'# %s %s\n' % (_metanamemap[k], meta[k])
1636
1636
1637 content = b'%s%s\n%s' % (header, desc, body)
1637 content = b'%s%s\n%s' % (header, desc, body)
1638 write(content)
1638 write(content)
1639
1639
1640
1640
1641 @vcrcommand(
1641 @vcrcommand(
1642 b'phabread',
1642 b'phabread',
1643 [(b'', b'stack', False, _(b'read dependencies'))],
1643 [(b'', b'stack', False, _(b'read dependencies'))],
1644 _(b'DREVSPEC [OPTIONS]'),
1644 _(b'DREVSPEC [OPTIONS]'),
1645 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1645 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1646 )
1646 )
1647 def phabread(ui, repo, spec, **opts):
1647 def phabread(ui, repo, spec, **opts):
1648 """print patches from Phabricator suitable for importing
1648 """print patches from Phabricator suitable for importing
1649
1649
1650 DREVSPEC could be a Differential Revision identity, like ``D123``, or just
1650 DREVSPEC could be a Differential Revision identity, like ``D123``, or just
1651 the number ``123``. It could also have common operators like ``+``, ``-``,
1651 the number ``123``. It could also have common operators like ``+``, ``-``,
1652 ``&``, ``(``, ``)`` for complex queries. Prefix ``:`` could be used to
1652 ``&``, ``(``, ``)`` for complex queries. Prefix ``:`` could be used to
1653 select a stack.
1653 select a stack.
1654
1654
1655 ``abandoned``, ``accepted``, ``closed``, ``needsreview``, ``needsrevision``
1655 ``abandoned``, ``accepted``, ``closed``, ``needsreview``, ``needsrevision``
1656 could be used to filter patches by status. For performance reason, they
1656 could be used to filter patches by status. For performance reason, they
1657 only represent a subset of non-status selections and cannot be used alone.
1657 only represent a subset of non-status selections and cannot be used alone.
1658
1658
1659 For example, ``:D6+8-(2+D4)`` selects a stack up to D6, plus D8 and exclude
1659 For example, ``:D6+8-(2+D4)`` selects a stack up to D6, plus D8 and exclude
1660 D2 and D4. ``:D9 & needsreview`` selects "Needs Review" revisions in a
1660 D2 and D4. ``:D9 & needsreview`` selects "Needs Review" revisions in a
1661 stack up to D9.
1661 stack up to D9.
1662
1662
1663 If --stack is given, follow dependencies information and read all patches.
1663 If --stack is given, follow dependencies information and read all patches.
1664 It is equivalent to the ``:`` operator.
1664 It is equivalent to the ``:`` operator.
1665 """
1665 """
1666 opts = pycompat.byteskwargs(opts)
1666 opts = pycompat.byteskwargs(opts)
1667 if opts.get(b'stack'):
1667 if opts.get(b'stack'):
1668 spec = b':(%s)' % spec
1668 spec = b':(%s)' % spec
1669 drevs = querydrev(repo, spec)
1669 drevs = querydrev(repo, spec)
1670 readpatch(repo, drevs, ui.write)
1670 readpatch(repo, drevs, ui.write)
1671
1671
1672
1672
1673 @vcrcommand(
1673 @vcrcommand(
1674 b'phabupdate',
1674 b'phabupdate',
1675 [
1675 [
1676 (b'', b'accept', False, _(b'accept revisions')),
1676 (b'', b'accept', False, _(b'accept revisions')),
1677 (b'', b'reject', False, _(b'reject revisions')),
1677 (b'', b'reject', False, _(b'reject revisions')),
1678 (b'', b'abandon', False, _(b'abandon revisions')),
1678 (b'', b'abandon', False, _(b'abandon revisions')),
1679 (b'', b'reclaim', False, _(b'reclaim revisions')),
1679 (b'', b'reclaim', False, _(b'reclaim revisions')),
1680 (b'm', b'comment', b'', _(b'comment on the last revision')),
1680 (b'm', b'comment', b'', _(b'comment on the last revision')),
1681 ],
1681 ],
1682 _(b'DREVSPEC [OPTIONS]'),
1682 _(b'DREVSPEC [OPTIONS]'),
1683 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1683 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1684 )
1684 )
1685 def phabupdate(ui, repo, spec, **opts):
1685 def phabupdate(ui, repo, spec, **opts):
1686 """update Differential Revision in batch
1686 """update Differential Revision in batch
1687
1687
1688 DREVSPEC selects revisions. See :hg:`help phabread` for its usage.
1688 DREVSPEC selects revisions. See :hg:`help phabread` for its usage.
1689 """
1689 """
1690 opts = pycompat.byteskwargs(opts)
1690 opts = pycompat.byteskwargs(opts)
1691 flags = [n for n in b'accept reject abandon reclaim'.split() if opts.get(n)]
1691 flags = [n for n in b'accept reject abandon reclaim'.split() if opts.get(n)]
1692 if len(flags) > 1:
1692 if len(flags) > 1:
1693 raise error.Abort(_(b'%s cannot be used together') % b', '.join(flags))
1693 raise error.Abort(_(b'%s cannot be used together') % b', '.join(flags))
1694
1694
1695 actions = []
1695 actions = []
1696 for f in flags:
1696 for f in flags:
1697 actions.append({b'type': f, b'value': True})
1697 actions.append({b'type': f, b'value': True})
1698
1698
1699 drevs = querydrev(repo, spec)
1699 drevs = querydrev(repo, spec)
1700 for i, drev in enumerate(drevs):
1700 for i, drev in enumerate(drevs):
1701 if i + 1 == len(drevs) and opts.get(b'comment'):
1701 if i + 1 == len(drevs) and opts.get(b'comment'):
1702 actions.append({b'type': b'comment', b'value': opts[b'comment']})
1702 actions.append({b'type': b'comment', b'value': opts[b'comment']})
1703 if actions:
1703 if actions:
1704 params = {
1704 params = {
1705 b'objectIdentifier': drev[b'phid'],
1705 b'objectIdentifier': drev[b'phid'],
1706 b'transactions': actions,
1706 b'transactions': actions,
1707 }
1707 }
1708 callconduit(ui, b'differential.revision.edit', params)
1708 callconduit(ui, b'differential.revision.edit', params)
1709
1709
1710
1710
1711 @eh.templatekeyword(b'phabreview', requires={b'ctx'})
1711 @eh.templatekeyword(b'phabreview', requires={b'ctx'})
1712 def template_review(context, mapping):
1712 def template_review(context, mapping):
1713 """:phabreview: Object describing the review for this changeset.
1713 """:phabreview: Object describing the review for this changeset.
1714 Has attributes `url` and `id`.
1714 Has attributes `url` and `id`.
1715 """
1715 """
1716 ctx = context.resource(mapping, b'ctx')
1716 ctx = context.resource(mapping, b'ctx')
1717 m = _differentialrevisiondescre.search(ctx.description())
1717 m = _differentialrevisiondescre.search(ctx.description())
1718 if m:
1718 if m:
1719 return templateutil.hybriddict(
1719 return templateutil.hybriddict(
1720 {b'url': m.group('url'), b'id': b"D%s" % m.group('id'),}
1720 {b'url': m.group('url'), b'id': b"D%s" % m.group('id'),}
1721 )
1721 )
1722 else:
1722 else:
1723 tags = ctx.repo().nodetags(ctx.node())
1723 tags = ctx.repo().nodetags(ctx.node())
1724 for t in tags:
1724 for t in tags:
1725 if _differentialrevisiontagre.match(t):
1725 if _differentialrevisiontagre.match(t):
1726 url = ctx.repo().ui.config(b'phabricator', b'url')
1726 url = ctx.repo().ui.config(b'phabricator', b'url')
1727 if not url.endswith(b'/'):
1727 if not url.endswith(b'/'):
1728 url += b'/'
1728 url += b'/'
1729 url += t
1729 url += t
1730
1730
1731 return templateutil.hybriddict({b'url': url, b'id': t,})
1731 return templateutil.hybriddict({b'url': url, b'id': t,})
1732 return None
1732 return None
1733
1733
1734
1734
1735 @eh.templatekeyword(b'phabstatus', requires={b'ctx', b'repo', b'ui'})
1735 @eh.templatekeyword(b'phabstatus', requires={b'ctx', b'repo', b'ui'})
1736 def template_status(context, mapping):
1736 def template_status(context, mapping):
1737 """:phabstatus: String. Status of Phabricator differential.
1737 """:phabstatus: String. Status of Phabricator differential.
1738 """
1738 """
1739 ctx = context.resource(mapping, b'ctx')
1739 ctx = context.resource(mapping, b'ctx')
1740 repo = context.resource(mapping, b'repo')
1740 repo = context.resource(mapping, b'repo')
1741 ui = context.resource(mapping, b'ui')
1741 ui = context.resource(mapping, b'ui')
1742
1742
1743 rev = ctx.rev()
1743 rev = ctx.rev()
1744 try:
1744 try:
1745 drevid = getdrevmap(repo, [rev])[rev]
1745 drevid = getdrevmap(repo, [rev])[rev]
1746 except KeyError:
1746 except KeyError:
1747 return None
1747 return None
1748 drevs = callconduit(ui, b'differential.query', {b'ids': [drevid]})
1748 drevs = callconduit(ui, b'differential.query', {b'ids': [drevid]})
1749 for drev in drevs:
1749 for drev in drevs:
1750 if int(drev[b'id']) == drevid:
1750 if int(drev[b'id']) == drevid:
1751 return templateutil.hybriddict(
1751 return templateutil.hybriddict(
1752 {b'url': drev[b'uri'], b'status': drev[b'statusName'],}
1752 {b'url': drev[b'uri'], b'status': drev[b'statusName'],}
1753 )
1753 )
1754 return None
1754 return None
1755
1755
1756
1756
1757 @show.showview(b'phabstatus', csettopic=b'work')
1757 @show.showview(b'phabstatus', csettopic=b'work')
1758 def phabstatusshowview(ui, repo, displayer):
1758 def phabstatusshowview(ui, repo, displayer):
1759 """Phabricator differiential status"""
1759 """Phabricator differiential status"""
1760 revs = repo.revs('sort(_underway(), topo)')
1760 revs = repo.revs('sort(_underway(), topo)')
1761 drevmap = getdrevmap(repo, revs)
1761 drevmap = getdrevmap(repo, revs)
1762 unknownrevs, drevids, revsbydrevid = [], set([]), {}
1762 unknownrevs, drevids, revsbydrevid = [], set([]), {}
1763 for rev, drevid in pycompat.iteritems(drevmap):
1763 for rev, drevid in pycompat.iteritems(drevmap):
1764 if drevid is not None:
1764 if drevid is not None:
1765 drevids.add(drevid)
1765 drevids.add(drevid)
1766 revsbydrevid.setdefault(drevid, set([])).add(rev)
1766 revsbydrevid.setdefault(drevid, set([])).add(rev)
1767 else:
1767 else:
1768 unknownrevs.append(rev)
1768 unknownrevs.append(rev)
1769
1769
1770 drevs = callconduit(ui, b'differential.query', {b'ids': list(drevids)})
1770 drevs = callconduit(ui, b'differential.query', {b'ids': list(drevids)})
1771 drevsbyrev = {}
1771 drevsbyrev = {}
1772 for drev in drevs:
1772 for drev in drevs:
1773 for rev in revsbydrevid[int(drev[b'id'])]:
1773 for rev in revsbydrevid[int(drev[b'id'])]:
1774 drevsbyrev[rev] = drev
1774 drevsbyrev[rev] = drev
1775
1775
1776 def phabstatus(ctx):
1776 def phabstatus(ctx):
1777 drev = drevsbyrev[ctx.rev()]
1777 drev = drevsbyrev[ctx.rev()]
1778 status = ui.label(
1778 status = ui.label(
1779 b'%(statusName)s' % drev,
1779 b'%(statusName)s' % drev,
1780 b'phabricator.status.%s' % _getstatusname(drev),
1780 b'phabricator.status.%s' % _getstatusname(drev),
1781 )
1781 )
1782 ui.write(b"\n%s %s\n" % (drev[b'uri'], status))
1782 ui.write(b"\n%s %s\n" % (drev[b'uri'], status))
1783
1783
1784 revs -= smartset.baseset(unknownrevs)
1784 revs -= smartset.baseset(unknownrevs)
1785 revdag = graphmod.dagwalker(repo, revs)
1785 revdag = graphmod.dagwalker(repo, revs)
1786
1786
1787 ui.setconfig(b'experimental', b'graphshorten', True)
1787 ui.setconfig(b'experimental', b'graphshorten', True)
1788 displayer._exthook = phabstatus
1788 displayer._exthook = phabstatus
1789 nodelen = show.longestshortest(repo, revs)
1789 nodelen = show.longestshortest(repo, revs)
1790 logcmdutil.displaygraph(
1790 logcmdutil.displaygraph(
1791 ui,
1791 ui,
1792 repo,
1792 repo,
1793 revdag,
1793 revdag,
1794 displayer,
1794 displayer,
1795 graphmod.asciiedges,
1795 graphmod.asciiedges,
1796 props={b'nodelen': nodelen},
1796 props={b'nodelen': nodelen},
1797 )
1797 )
@@ -1,7824 +1,7824 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import sys
14 import sys
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 short,
21 short,
22 wdirhex,
22 wdirhex,
23 wdirrev,
23 wdirrev,
24 )
24 )
25 from .pycompat import open
25 from .pycompat import open
26 from . import (
26 from . import (
27 archival,
27 archival,
28 bookmarks,
28 bookmarks,
29 bundle2,
29 bundle2,
30 changegroup,
30 changegroup,
31 cmdutil,
31 cmdutil,
32 copies,
32 copies,
33 debugcommands as debugcommandsmod,
33 debugcommands as debugcommandsmod,
34 destutil,
34 destutil,
35 dirstateguard,
35 dirstateguard,
36 discovery,
36 discovery,
37 encoding,
37 encoding,
38 error,
38 error,
39 exchange,
39 exchange,
40 extensions,
40 extensions,
41 filemerge,
41 filemerge,
42 formatter,
42 formatter,
43 graphmod,
43 graphmod,
44 hbisect,
44 hbisect,
45 help,
45 help,
46 hg,
46 hg,
47 logcmdutil,
47 logcmdutil,
48 merge as mergemod,
48 merge as mergemod,
49 narrowspec,
49 narrowspec,
50 obsolete,
50 obsolete,
51 obsutil,
51 obsutil,
52 patch,
52 patch,
53 phases,
53 phases,
54 pycompat,
54 pycompat,
55 rcutil,
55 rcutil,
56 registrar,
56 registrar,
57 revsetlang,
57 revsetlang,
58 rewriteutil,
58 rewriteutil,
59 scmutil,
59 scmutil,
60 server,
60 server,
61 shelve as shelvemod,
61 shelve as shelvemod,
62 state as statemod,
62 state as statemod,
63 streamclone,
63 streamclone,
64 tags as tagsmod,
64 tags as tagsmod,
65 ui as uimod,
65 ui as uimod,
66 util,
66 util,
67 verify as verifymod,
67 verify as verifymod,
68 wireprotoserver,
68 wireprotoserver,
69 )
69 )
70 from .utils import (
70 from .utils import (
71 dateutil,
71 dateutil,
72 stringutil,
72 stringutil,
73 )
73 )
74
74
75 table = {}
75 table = {}
76 table.update(debugcommandsmod.command._table)
76 table.update(debugcommandsmod.command._table)
77
77
78 command = registrar.command(table)
78 command = registrar.command(table)
79 INTENT_READONLY = registrar.INTENT_READONLY
79 INTENT_READONLY = registrar.INTENT_READONLY
80
80
81 # common command options
81 # common command options
82
82
83 globalopts = [
83 globalopts = [
84 (
84 (
85 b'R',
85 b'R',
86 b'repository',
86 b'repository',
87 b'',
87 b'',
88 _(b'repository root directory or name of overlay bundle file'),
88 _(b'repository root directory or name of overlay bundle file'),
89 _(b'REPO'),
89 _(b'REPO'),
90 ),
90 ),
91 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
91 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
92 (
92 (
93 b'y',
93 b'y',
94 b'noninteractive',
94 b'noninteractive',
95 None,
95 None,
96 _(
96 _(
97 b'do not prompt, automatically pick the first choice for all prompts'
97 b'do not prompt, automatically pick the first choice for all prompts'
98 ),
98 ),
99 ),
99 ),
100 (b'q', b'quiet', None, _(b'suppress output')),
100 (b'q', b'quiet', None, _(b'suppress output')),
101 (b'v', b'verbose', None, _(b'enable additional output')),
101 (b'v', b'verbose', None, _(b'enable additional output')),
102 (
102 (
103 b'',
103 b'',
104 b'color',
104 b'color',
105 b'',
105 b'',
106 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
106 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
107 # and should not be translated
107 # and should not be translated
108 _(b"when to colorize (boolean, always, auto, never, or debug)"),
108 _(b"when to colorize (boolean, always, auto, never, or debug)"),
109 _(b'TYPE'),
109 _(b'TYPE'),
110 ),
110 ),
111 (
111 (
112 b'',
112 b'',
113 b'config',
113 b'config',
114 [],
114 [],
115 _(b'set/override config option (use \'section.name=value\')'),
115 _(b'set/override config option (use \'section.name=value\')'),
116 _(b'CONFIG'),
116 _(b'CONFIG'),
117 ),
117 ),
118 (b'', b'debug', None, _(b'enable debugging output')),
118 (b'', b'debug', None, _(b'enable debugging output')),
119 (b'', b'debugger', None, _(b'start debugger')),
119 (b'', b'debugger', None, _(b'start debugger')),
120 (
120 (
121 b'',
121 b'',
122 b'encoding',
122 b'encoding',
123 encoding.encoding,
123 encoding.encoding,
124 _(b'set the charset encoding'),
124 _(b'set the charset encoding'),
125 _(b'ENCODE'),
125 _(b'ENCODE'),
126 ),
126 ),
127 (
127 (
128 b'',
128 b'',
129 b'encodingmode',
129 b'encodingmode',
130 encoding.encodingmode,
130 encoding.encodingmode,
131 _(b'set the charset encoding mode'),
131 _(b'set the charset encoding mode'),
132 _(b'MODE'),
132 _(b'MODE'),
133 ),
133 ),
134 (b'', b'traceback', None, _(b'always print a traceback on exception')),
134 (b'', b'traceback', None, _(b'always print a traceback on exception')),
135 (b'', b'time', None, _(b'time how long the command takes')),
135 (b'', b'time', None, _(b'time how long the command takes')),
136 (b'', b'profile', None, _(b'print command execution profile')),
136 (b'', b'profile', None, _(b'print command execution profile')),
137 (b'', b'version', None, _(b'output version information and exit')),
137 (b'', b'version', None, _(b'output version information and exit')),
138 (b'h', b'help', None, _(b'display help and exit')),
138 (b'h', b'help', None, _(b'display help and exit')),
139 (b'', b'hidden', False, _(b'consider hidden changesets')),
139 (b'', b'hidden', False, _(b'consider hidden changesets')),
140 (
140 (
141 b'',
141 b'',
142 b'pager',
142 b'pager',
143 b'auto',
143 b'auto',
144 _(b"when to paginate (boolean, always, auto, or never)"),
144 _(b"when to paginate (boolean, always, auto, or never)"),
145 _(b'TYPE'),
145 _(b'TYPE'),
146 ),
146 ),
147 ]
147 ]
148
148
149 dryrunopts = cmdutil.dryrunopts
149 dryrunopts = cmdutil.dryrunopts
150 remoteopts = cmdutil.remoteopts
150 remoteopts = cmdutil.remoteopts
151 walkopts = cmdutil.walkopts
151 walkopts = cmdutil.walkopts
152 commitopts = cmdutil.commitopts
152 commitopts = cmdutil.commitopts
153 commitopts2 = cmdutil.commitopts2
153 commitopts2 = cmdutil.commitopts2
154 commitopts3 = cmdutil.commitopts3
154 commitopts3 = cmdutil.commitopts3
155 formatteropts = cmdutil.formatteropts
155 formatteropts = cmdutil.formatteropts
156 templateopts = cmdutil.templateopts
156 templateopts = cmdutil.templateopts
157 logopts = cmdutil.logopts
157 logopts = cmdutil.logopts
158 diffopts = cmdutil.diffopts
158 diffopts = cmdutil.diffopts
159 diffwsopts = cmdutil.diffwsopts
159 diffwsopts = cmdutil.diffwsopts
160 diffopts2 = cmdutil.diffopts2
160 diffopts2 = cmdutil.diffopts2
161 mergetoolopts = cmdutil.mergetoolopts
161 mergetoolopts = cmdutil.mergetoolopts
162 similarityopts = cmdutil.similarityopts
162 similarityopts = cmdutil.similarityopts
163 subrepoopts = cmdutil.subrepoopts
163 subrepoopts = cmdutil.subrepoopts
164 debugrevlogopts = cmdutil.debugrevlogopts
164 debugrevlogopts = cmdutil.debugrevlogopts
165
165
166 # Commands start here, listed alphabetically
166 # Commands start here, listed alphabetically
167
167
168
168
169 @command(
169 @command(
170 b'abort',
170 b'abort',
171 dryrunopts,
171 dryrunopts,
172 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
172 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
173 helpbasic=True,
173 helpbasic=True,
174 )
174 )
175 def abort(ui, repo, **opts):
175 def abort(ui, repo, **opts):
176 """abort an unfinished operation (EXPERIMENTAL)
176 """abort an unfinished operation (EXPERIMENTAL)
177
177
178 Aborts a multistep operation like graft, histedit, rebase, merge,
178 Aborts a multistep operation like graft, histedit, rebase, merge,
179 and unshelve if they are in an unfinished state.
179 and unshelve if they are in an unfinished state.
180
180
181 use --dry-run/-n to dry run the command.
181 use --dry-run/-n to dry run the command.
182 """
182 """
183 dryrun = opts.get('dry_run')
183 dryrun = opts.get('dry_run')
184 abortstate = cmdutil.getunfinishedstate(repo)
184 abortstate = cmdutil.getunfinishedstate(repo)
185 if not abortstate:
185 if not abortstate:
186 raise error.Abort(_(b'no operation in progress'))
186 raise error.Abort(_(b'no operation in progress'))
187 if not abortstate.abortfunc:
187 if not abortstate.abortfunc:
188 raise error.Abort(
188 raise error.Abort(
189 (
189 (
190 _(b"%s in progress but does not support 'hg abort'")
190 _(b"%s in progress but does not support 'hg abort'")
191 % (abortstate._opname)
191 % (abortstate._opname)
192 ),
192 ),
193 hint=abortstate.hint(),
193 hint=abortstate.hint(),
194 )
194 )
195 if dryrun:
195 if dryrun:
196 ui.status(
196 ui.status(
197 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
197 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
198 )
198 )
199 return
199 return
200 return abortstate.abortfunc(ui, repo)
200 return abortstate.abortfunc(ui, repo)
201
201
202
202
203 @command(
203 @command(
204 b'add',
204 b'add',
205 walkopts + subrepoopts + dryrunopts,
205 walkopts + subrepoopts + dryrunopts,
206 _(b'[OPTION]... [FILE]...'),
206 _(b'[OPTION]... [FILE]...'),
207 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
207 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
208 helpbasic=True,
208 helpbasic=True,
209 inferrepo=True,
209 inferrepo=True,
210 )
210 )
211 def add(ui, repo, *pats, **opts):
211 def add(ui, repo, *pats, **opts):
212 """add the specified files on the next commit
212 """add the specified files on the next commit
213
213
214 Schedule files to be version controlled and added to the
214 Schedule files to be version controlled and added to the
215 repository.
215 repository.
216
216
217 The files will be added to the repository at the next commit. To
217 The files will be added to the repository at the next commit. To
218 undo an add before that, see :hg:`forget`.
218 undo an add before that, see :hg:`forget`.
219
219
220 If no names are given, add all files to the repository (except
220 If no names are given, add all files to the repository (except
221 files matching ``.hgignore``).
221 files matching ``.hgignore``).
222
222
223 .. container:: verbose
223 .. container:: verbose
224
224
225 Examples:
225 Examples:
226
226
227 - New (unknown) files are added
227 - New (unknown) files are added
228 automatically by :hg:`add`::
228 automatically by :hg:`add`::
229
229
230 $ ls
230 $ ls
231 foo.c
231 foo.c
232 $ hg status
232 $ hg status
233 ? foo.c
233 ? foo.c
234 $ hg add
234 $ hg add
235 adding foo.c
235 adding foo.c
236 $ hg status
236 $ hg status
237 A foo.c
237 A foo.c
238
238
239 - Specific files to be added can be specified::
239 - Specific files to be added can be specified::
240
240
241 $ ls
241 $ ls
242 bar.c foo.c
242 bar.c foo.c
243 $ hg status
243 $ hg status
244 ? bar.c
244 ? bar.c
245 ? foo.c
245 ? foo.c
246 $ hg add bar.c
246 $ hg add bar.c
247 $ hg status
247 $ hg status
248 A bar.c
248 A bar.c
249 ? foo.c
249 ? foo.c
250
250
251 Returns 0 if all files are successfully added.
251 Returns 0 if all files are successfully added.
252 """
252 """
253
253
254 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
254 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
255 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
255 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
256 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
256 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
257 return rejected and 1 or 0
257 return rejected and 1 or 0
258
258
259
259
260 @command(
260 @command(
261 b'addremove',
261 b'addremove',
262 similarityopts + subrepoopts + walkopts + dryrunopts,
262 similarityopts + subrepoopts + walkopts + dryrunopts,
263 _(b'[OPTION]... [FILE]...'),
263 _(b'[OPTION]... [FILE]...'),
264 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
264 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
265 inferrepo=True,
265 inferrepo=True,
266 )
266 )
267 def addremove(ui, repo, *pats, **opts):
267 def addremove(ui, repo, *pats, **opts):
268 """add all new files, delete all missing files
268 """add all new files, delete all missing files
269
269
270 Add all new files and remove all missing files from the
270 Add all new files and remove all missing files from the
271 repository.
271 repository.
272
272
273 Unless names are given, new files are ignored if they match any of
273 Unless names are given, new files are ignored if they match any of
274 the patterns in ``.hgignore``. As with add, these changes take
274 the patterns in ``.hgignore``. As with add, these changes take
275 effect at the next commit.
275 effect at the next commit.
276
276
277 Use the -s/--similarity option to detect renamed files. This
277 Use the -s/--similarity option to detect renamed files. This
278 option takes a percentage between 0 (disabled) and 100 (files must
278 option takes a percentage between 0 (disabled) and 100 (files must
279 be identical) as its parameter. With a parameter greater than 0,
279 be identical) as its parameter. With a parameter greater than 0,
280 this compares every removed file with every added file and records
280 this compares every removed file with every added file and records
281 those similar enough as renames. Detecting renamed files this way
281 those similar enough as renames. Detecting renamed files this way
282 can be expensive. After using this option, :hg:`status -C` can be
282 can be expensive. After using this option, :hg:`status -C` can be
283 used to check which files were identified as moved or renamed. If
283 used to check which files were identified as moved or renamed. If
284 not specified, -s/--similarity defaults to 100 and only renames of
284 not specified, -s/--similarity defaults to 100 and only renames of
285 identical files are detected.
285 identical files are detected.
286
286
287 .. container:: verbose
287 .. container:: verbose
288
288
289 Examples:
289 Examples:
290
290
291 - A number of files (bar.c and foo.c) are new,
291 - A number of files (bar.c and foo.c) are new,
292 while foobar.c has been removed (without using :hg:`remove`)
292 while foobar.c has been removed (without using :hg:`remove`)
293 from the repository::
293 from the repository::
294
294
295 $ ls
295 $ ls
296 bar.c foo.c
296 bar.c foo.c
297 $ hg status
297 $ hg status
298 ! foobar.c
298 ! foobar.c
299 ? bar.c
299 ? bar.c
300 ? foo.c
300 ? foo.c
301 $ hg addremove
301 $ hg addremove
302 adding bar.c
302 adding bar.c
303 adding foo.c
303 adding foo.c
304 removing foobar.c
304 removing foobar.c
305 $ hg status
305 $ hg status
306 A bar.c
306 A bar.c
307 A foo.c
307 A foo.c
308 R foobar.c
308 R foobar.c
309
309
310 - A file foobar.c was moved to foo.c without using :hg:`rename`.
310 - A file foobar.c was moved to foo.c without using :hg:`rename`.
311 Afterwards, it was edited slightly::
311 Afterwards, it was edited slightly::
312
312
313 $ ls
313 $ ls
314 foo.c
314 foo.c
315 $ hg status
315 $ hg status
316 ! foobar.c
316 ! foobar.c
317 ? foo.c
317 ? foo.c
318 $ hg addremove --similarity 90
318 $ hg addremove --similarity 90
319 removing foobar.c
319 removing foobar.c
320 adding foo.c
320 adding foo.c
321 recording removal of foobar.c as rename to foo.c (94% similar)
321 recording removal of foobar.c as rename to foo.c (94% similar)
322 $ hg status -C
322 $ hg status -C
323 A foo.c
323 A foo.c
324 foobar.c
324 foobar.c
325 R foobar.c
325 R foobar.c
326
326
327 Returns 0 if all files are successfully added.
327 Returns 0 if all files are successfully added.
328 """
328 """
329 opts = pycompat.byteskwargs(opts)
329 opts = pycompat.byteskwargs(opts)
330 if not opts.get(b'similarity'):
330 if not opts.get(b'similarity'):
331 opts[b'similarity'] = b'100'
331 opts[b'similarity'] = b'100'
332 matcher = scmutil.match(repo[None], pats, opts)
332 matcher = scmutil.match(repo[None], pats, opts)
333 relative = scmutil.anypats(pats, opts)
333 relative = scmutil.anypats(pats, opts)
334 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
334 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
335 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
335 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
336
336
337
337
338 @command(
338 @command(
339 b'annotate|blame',
339 b'annotate|blame',
340 [
340 [
341 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
341 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
342 (
342 (
343 b'',
343 b'',
344 b'follow',
344 b'follow',
345 None,
345 None,
346 _(b'follow copies/renames and list the filename (DEPRECATED)'),
346 _(b'follow copies/renames and list the filename (DEPRECATED)'),
347 ),
347 ),
348 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
348 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
349 (b'a', b'text', None, _(b'treat all files as text')),
349 (b'a', b'text', None, _(b'treat all files as text')),
350 (b'u', b'user', None, _(b'list the author (long with -v)')),
350 (b'u', b'user', None, _(b'list the author (long with -v)')),
351 (b'f', b'file', None, _(b'list the filename')),
351 (b'f', b'file', None, _(b'list the filename')),
352 (b'd', b'date', None, _(b'list the date (short with -q)')),
352 (b'd', b'date', None, _(b'list the date (short with -q)')),
353 (b'n', b'number', None, _(b'list the revision number (default)')),
353 (b'n', b'number', None, _(b'list the revision number (default)')),
354 (b'c', b'changeset', None, _(b'list the changeset')),
354 (b'c', b'changeset', None, _(b'list the changeset')),
355 (
355 (
356 b'l',
356 b'l',
357 b'line-number',
357 b'line-number',
358 None,
358 None,
359 _(b'show line number at the first appearance'),
359 _(b'show line number at the first appearance'),
360 ),
360 ),
361 (
361 (
362 b'',
362 b'',
363 b'skip',
363 b'skip',
364 [],
364 [],
365 _(b'revset to not display (EXPERIMENTAL)'),
365 _(b'revset to not display (EXPERIMENTAL)'),
366 _(b'REV'),
366 _(b'REV'),
367 ),
367 ),
368 ]
368 ]
369 + diffwsopts
369 + diffwsopts
370 + walkopts
370 + walkopts
371 + formatteropts,
371 + formatteropts,
372 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
372 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
373 helpcategory=command.CATEGORY_FILE_CONTENTS,
373 helpcategory=command.CATEGORY_FILE_CONTENTS,
374 helpbasic=True,
374 helpbasic=True,
375 inferrepo=True,
375 inferrepo=True,
376 )
376 )
377 def annotate(ui, repo, *pats, **opts):
377 def annotate(ui, repo, *pats, **opts):
378 """show changeset information by line for each file
378 """show changeset information by line for each file
379
379
380 List changes in files, showing the revision id responsible for
380 List changes in files, showing the revision id responsible for
381 each line.
381 each line.
382
382
383 This command is useful for discovering when a change was made and
383 This command is useful for discovering when a change was made and
384 by whom.
384 by whom.
385
385
386 If you include --file, --user, or --date, the revision number is
386 If you include --file, --user, or --date, the revision number is
387 suppressed unless you also include --number.
387 suppressed unless you also include --number.
388
388
389 Without the -a/--text option, annotate will avoid processing files
389 Without the -a/--text option, annotate will avoid processing files
390 it detects as binary. With -a, annotate will annotate the file
390 it detects as binary. With -a, annotate will annotate the file
391 anyway, although the results will probably be neither useful
391 anyway, although the results will probably be neither useful
392 nor desirable.
392 nor desirable.
393
393
394 .. container:: verbose
394 .. container:: verbose
395
395
396 Template:
396 Template:
397
397
398 The following keywords are supported in addition to the common template
398 The following keywords are supported in addition to the common template
399 keywords and functions. See also :hg:`help templates`.
399 keywords and functions. See also :hg:`help templates`.
400
400
401 :lines: List of lines with annotation data.
401 :lines: List of lines with annotation data.
402 :path: String. Repository-absolute path of the specified file.
402 :path: String. Repository-absolute path of the specified file.
403
403
404 And each entry of ``{lines}`` provides the following sub-keywords in
404 And each entry of ``{lines}`` provides the following sub-keywords in
405 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
405 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
406
406
407 :line: String. Line content.
407 :line: String. Line content.
408 :lineno: Integer. Line number at that revision.
408 :lineno: Integer. Line number at that revision.
409 :path: String. Repository-absolute path of the file at that revision.
409 :path: String. Repository-absolute path of the file at that revision.
410
410
411 See :hg:`help templates.operators` for the list expansion syntax.
411 See :hg:`help templates.operators` for the list expansion syntax.
412
412
413 Returns 0 on success.
413 Returns 0 on success.
414 """
414 """
415 opts = pycompat.byteskwargs(opts)
415 opts = pycompat.byteskwargs(opts)
416 if not pats:
416 if not pats:
417 raise error.Abort(_(b'at least one filename or pattern is required'))
417 raise error.Abort(_(b'at least one filename or pattern is required'))
418
418
419 if opts.get(b'follow'):
419 if opts.get(b'follow'):
420 # --follow is deprecated and now just an alias for -f/--file
420 # --follow is deprecated and now just an alias for -f/--file
421 # to mimic the behavior of Mercurial before version 1.5
421 # to mimic the behavior of Mercurial before version 1.5
422 opts[b'file'] = True
422 opts[b'file'] = True
423
423
424 if (
424 if (
425 not opts.get(b'user')
425 not opts.get(b'user')
426 and not opts.get(b'changeset')
426 and not opts.get(b'changeset')
427 and not opts.get(b'date')
427 and not opts.get(b'date')
428 and not opts.get(b'file')
428 and not opts.get(b'file')
429 ):
429 ):
430 opts[b'number'] = True
430 opts[b'number'] = True
431
431
432 linenumber = opts.get(b'line_number') is not None
432 linenumber = opts.get(b'line_number') is not None
433 if (
433 if (
434 linenumber
434 linenumber
435 and (not opts.get(b'changeset'))
435 and (not opts.get(b'changeset'))
436 and (not opts.get(b'number'))
436 and (not opts.get(b'number'))
437 ):
437 ):
438 raise error.Abort(_(b'at least one of -n/-c is required for -l'))
438 raise error.Abort(_(b'at least one of -n/-c is required for -l'))
439
439
440 rev = opts.get(b'rev')
440 rev = opts.get(b'rev')
441 if rev:
441 if rev:
442 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
442 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
443 ctx = scmutil.revsingle(repo, rev)
443 ctx = scmutil.revsingle(repo, rev)
444
444
445 ui.pager(b'annotate')
445 ui.pager(b'annotate')
446 rootfm = ui.formatter(b'annotate', opts)
446 rootfm = ui.formatter(b'annotate', opts)
447 if ui.debugflag:
447 if ui.debugflag:
448 shorthex = pycompat.identity
448 shorthex = pycompat.identity
449 else:
449 else:
450
450
451 def shorthex(h):
451 def shorthex(h):
452 return h[:12]
452 return h[:12]
453
453
454 if ui.quiet:
454 if ui.quiet:
455 datefunc = dateutil.shortdate
455 datefunc = dateutil.shortdate
456 else:
456 else:
457 datefunc = dateutil.datestr
457 datefunc = dateutil.datestr
458 if ctx.rev() is None:
458 if ctx.rev() is None:
459 if opts.get(b'changeset'):
459 if opts.get(b'changeset'):
460 # omit "+" suffix which is appended to node hex
460 # omit "+" suffix which is appended to node hex
461 def formatrev(rev):
461 def formatrev(rev):
462 if rev == wdirrev:
462 if rev == wdirrev:
463 return b'%d' % ctx.p1().rev()
463 return b'%d' % ctx.p1().rev()
464 else:
464 else:
465 return b'%d' % rev
465 return b'%d' % rev
466
466
467 else:
467 else:
468
468
469 def formatrev(rev):
469 def formatrev(rev):
470 if rev == wdirrev:
470 if rev == wdirrev:
471 return b'%d+' % ctx.p1().rev()
471 return b'%d+' % ctx.p1().rev()
472 else:
472 else:
473 return b'%d ' % rev
473 return b'%d ' % rev
474
474
475 def formathex(h):
475 def formathex(h):
476 if h == wdirhex:
476 if h == wdirhex:
477 return b'%s+' % shorthex(hex(ctx.p1().node()))
477 return b'%s+' % shorthex(hex(ctx.p1().node()))
478 else:
478 else:
479 return b'%s ' % shorthex(h)
479 return b'%s ' % shorthex(h)
480
480
481 else:
481 else:
482 formatrev = b'%d'.__mod__
482 formatrev = b'%d'.__mod__
483 formathex = shorthex
483 formathex = shorthex
484
484
485 opmap = [
485 opmap = [
486 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
486 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
487 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
487 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
488 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
488 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
489 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
489 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
490 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
490 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
491 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
491 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
492 ]
492 ]
493 opnamemap = {
493 opnamemap = {
494 b'rev': b'number',
494 b'rev': b'number',
495 b'node': b'changeset',
495 b'node': b'changeset',
496 b'path': b'file',
496 b'path': b'file',
497 b'lineno': b'line_number',
497 b'lineno': b'line_number',
498 }
498 }
499
499
500 if rootfm.isplain():
500 if rootfm.isplain():
501
501
502 def makefunc(get, fmt):
502 def makefunc(get, fmt):
503 return lambda x: fmt(get(x))
503 return lambda x: fmt(get(x))
504
504
505 else:
505 else:
506
506
507 def makefunc(get, fmt):
507 def makefunc(get, fmt):
508 return get
508 return get
509
509
510 datahint = rootfm.datahint()
510 datahint = rootfm.datahint()
511 funcmap = [
511 funcmap = [
512 (makefunc(get, fmt), sep)
512 (makefunc(get, fmt), sep)
513 for fn, sep, get, fmt in opmap
513 for fn, sep, get, fmt in opmap
514 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
514 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
515 ]
515 ]
516 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
516 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
517 fields = b' '.join(
517 fields = b' '.join(
518 fn
518 fn
519 for fn, sep, get, fmt in opmap
519 for fn, sep, get, fmt in opmap
520 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
520 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
521 )
521 )
522
522
523 def bad(x, y):
523 def bad(x, y):
524 raise error.Abort(b"%s: %s" % (x, y))
524 raise error.Abort(b"%s: %s" % (x, y))
525
525
526 m = scmutil.match(ctx, pats, opts, badfn=bad)
526 m = scmutil.match(ctx, pats, opts, badfn=bad)
527
527
528 follow = not opts.get(b'no_follow')
528 follow = not opts.get(b'no_follow')
529 diffopts = patch.difffeatureopts(
529 diffopts = patch.difffeatureopts(
530 ui, opts, section=b'annotate', whitespace=True
530 ui, opts, section=b'annotate', whitespace=True
531 )
531 )
532 skiprevs = opts.get(b'skip')
532 skiprevs = opts.get(b'skip')
533 if skiprevs:
533 if skiprevs:
534 skiprevs = scmutil.revrange(repo, skiprevs)
534 skiprevs = scmutil.revrange(repo, skiprevs)
535
535
536 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
536 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
537 for abs in ctx.walk(m):
537 for abs in ctx.walk(m):
538 fctx = ctx[abs]
538 fctx = ctx[abs]
539 rootfm.startitem()
539 rootfm.startitem()
540 rootfm.data(path=abs)
540 rootfm.data(path=abs)
541 if not opts.get(b'text') and fctx.isbinary():
541 if not opts.get(b'text') and fctx.isbinary():
542 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
542 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
543 continue
543 continue
544
544
545 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
545 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
546 lines = fctx.annotate(
546 lines = fctx.annotate(
547 follow=follow, skiprevs=skiprevs, diffopts=diffopts
547 follow=follow, skiprevs=skiprevs, diffopts=diffopts
548 )
548 )
549 if not lines:
549 if not lines:
550 fm.end()
550 fm.end()
551 continue
551 continue
552 formats = []
552 formats = []
553 pieces = []
553 pieces = []
554
554
555 for f, sep in funcmap:
555 for f, sep in funcmap:
556 l = [f(n) for n in lines]
556 l = [f(n) for n in lines]
557 if fm.isplain():
557 if fm.isplain():
558 sizes = [encoding.colwidth(x) for x in l]
558 sizes = [encoding.colwidth(x) for x in l]
559 ml = max(sizes)
559 ml = max(sizes)
560 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
560 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
561 else:
561 else:
562 formats.append([b'%s'] * len(l))
562 formats.append([b'%s'] * len(l))
563 pieces.append(l)
563 pieces.append(l)
564
564
565 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
565 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
566 fm.startitem()
566 fm.startitem()
567 fm.context(fctx=n.fctx)
567 fm.context(fctx=n.fctx)
568 fm.write(fields, b"".join(f), *p)
568 fm.write(fields, b"".join(f), *p)
569 if n.skip:
569 if n.skip:
570 fmt = b"* %s"
570 fmt = b"* %s"
571 else:
571 else:
572 fmt = b": %s"
572 fmt = b": %s"
573 fm.write(b'line', fmt, n.text)
573 fm.write(b'line', fmt, n.text)
574
574
575 if not lines[-1].text.endswith(b'\n'):
575 if not lines[-1].text.endswith(b'\n'):
576 fm.plain(b'\n')
576 fm.plain(b'\n')
577 fm.end()
577 fm.end()
578
578
579 rootfm.end()
579 rootfm.end()
580
580
581
581
582 @command(
582 @command(
583 b'archive',
583 b'archive',
584 [
584 [
585 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
585 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
586 (
586 (
587 b'p',
587 b'p',
588 b'prefix',
588 b'prefix',
589 b'',
589 b'',
590 _(b'directory prefix for files in archive'),
590 _(b'directory prefix for files in archive'),
591 _(b'PREFIX'),
591 _(b'PREFIX'),
592 ),
592 ),
593 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
593 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
594 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
594 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
595 ]
595 ]
596 + subrepoopts
596 + subrepoopts
597 + walkopts,
597 + walkopts,
598 _(b'[OPTION]... DEST'),
598 _(b'[OPTION]... DEST'),
599 helpcategory=command.CATEGORY_IMPORT_EXPORT,
599 helpcategory=command.CATEGORY_IMPORT_EXPORT,
600 )
600 )
601 def archive(ui, repo, dest, **opts):
601 def archive(ui, repo, dest, **opts):
602 '''create an unversioned archive of a repository revision
602 '''create an unversioned archive of a repository revision
603
603
604 By default, the revision used is the parent of the working
604 By default, the revision used is the parent of the working
605 directory; use -r/--rev to specify a different revision.
605 directory; use -r/--rev to specify a different revision.
606
606
607 The archive type is automatically detected based on file
607 The archive type is automatically detected based on file
608 extension (to override, use -t/--type).
608 extension (to override, use -t/--type).
609
609
610 .. container:: verbose
610 .. container:: verbose
611
611
612 Examples:
612 Examples:
613
613
614 - create a zip file containing the 1.0 release::
614 - create a zip file containing the 1.0 release::
615
615
616 hg archive -r 1.0 project-1.0.zip
616 hg archive -r 1.0 project-1.0.zip
617
617
618 - create a tarball excluding .hg files::
618 - create a tarball excluding .hg files::
619
619
620 hg archive project.tar.gz -X ".hg*"
620 hg archive project.tar.gz -X ".hg*"
621
621
622 Valid types are:
622 Valid types are:
623
623
624 :``files``: a directory full of files (default)
624 :``files``: a directory full of files (default)
625 :``tar``: tar archive, uncompressed
625 :``tar``: tar archive, uncompressed
626 :``tbz2``: tar archive, compressed using bzip2
626 :``tbz2``: tar archive, compressed using bzip2
627 :``tgz``: tar archive, compressed using gzip
627 :``tgz``: tar archive, compressed using gzip
628 :``txz``: tar archive, compressed using lzma (only in Python 3)
628 :``txz``: tar archive, compressed using lzma (only in Python 3)
629 :``uzip``: zip archive, uncompressed
629 :``uzip``: zip archive, uncompressed
630 :``zip``: zip archive, compressed using deflate
630 :``zip``: zip archive, compressed using deflate
631
631
632 The exact name of the destination archive or directory is given
632 The exact name of the destination archive or directory is given
633 using a format string; see :hg:`help export` for details.
633 using a format string; see :hg:`help export` for details.
634
634
635 Each member added to an archive file has a directory prefix
635 Each member added to an archive file has a directory prefix
636 prepended. Use -p/--prefix to specify a format string for the
636 prepended. Use -p/--prefix to specify a format string for the
637 prefix. The default is the basename of the archive, with suffixes
637 prefix. The default is the basename of the archive, with suffixes
638 removed.
638 removed.
639
639
640 Returns 0 on success.
640 Returns 0 on success.
641 '''
641 '''
642
642
643 opts = pycompat.byteskwargs(opts)
643 opts = pycompat.byteskwargs(opts)
644 rev = opts.get(b'rev')
644 rev = opts.get(b'rev')
645 if rev:
645 if rev:
646 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
646 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
647 ctx = scmutil.revsingle(repo, rev)
647 ctx = scmutil.revsingle(repo, rev)
648 if not ctx:
648 if not ctx:
649 raise error.Abort(_(b'no working directory: please specify a revision'))
649 raise error.Abort(_(b'no working directory: please specify a revision'))
650 node = ctx.node()
650 node = ctx.node()
651 dest = cmdutil.makefilename(ctx, dest)
651 dest = cmdutil.makefilename(ctx, dest)
652 if os.path.realpath(dest) == repo.root:
652 if os.path.realpath(dest) == repo.root:
653 raise error.Abort(_(b'repository root cannot be destination'))
653 raise error.Abort(_(b'repository root cannot be destination'))
654
654
655 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
655 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
656 prefix = opts.get(b'prefix')
656 prefix = opts.get(b'prefix')
657
657
658 if dest == b'-':
658 if dest == b'-':
659 if kind == b'files':
659 if kind == b'files':
660 raise error.Abort(_(b'cannot archive plain files to stdout'))
660 raise error.Abort(_(b'cannot archive plain files to stdout'))
661 dest = cmdutil.makefileobj(ctx, dest)
661 dest = cmdutil.makefileobj(ctx, dest)
662 if not prefix:
662 if not prefix:
663 prefix = os.path.basename(repo.root) + b'-%h'
663 prefix = os.path.basename(repo.root) + b'-%h'
664
664
665 prefix = cmdutil.makefilename(ctx, prefix)
665 prefix = cmdutil.makefilename(ctx, prefix)
666 match = scmutil.match(ctx, [], opts)
666 match = scmutil.match(ctx, [], opts)
667 archival.archive(
667 archival.archive(
668 repo,
668 repo,
669 dest,
669 dest,
670 node,
670 node,
671 kind,
671 kind,
672 not opts.get(b'no_decode'),
672 not opts.get(b'no_decode'),
673 match,
673 match,
674 prefix,
674 prefix,
675 subrepos=opts.get(b'subrepos'),
675 subrepos=opts.get(b'subrepos'),
676 )
676 )
677
677
678
678
679 @command(
679 @command(
680 b'backout',
680 b'backout',
681 [
681 [
682 (
682 (
683 b'',
683 b'',
684 b'merge',
684 b'merge',
685 None,
685 None,
686 _(b'merge with old dirstate parent after backout'),
686 _(b'merge with old dirstate parent after backout'),
687 ),
687 ),
688 (
688 (
689 b'',
689 b'',
690 b'commit',
690 b'commit',
691 None,
691 None,
692 _(b'commit if no conflicts were encountered (DEPRECATED)'),
692 _(b'commit if no conflicts were encountered (DEPRECATED)'),
693 ),
693 ),
694 (b'', b'no-commit', None, _(b'do not commit')),
694 (b'', b'no-commit', None, _(b'do not commit')),
695 (
695 (
696 b'',
696 b'',
697 b'parent',
697 b'parent',
698 b'',
698 b'',
699 _(b'parent to choose when backing out merge (DEPRECATED)'),
699 _(b'parent to choose when backing out merge (DEPRECATED)'),
700 _(b'REV'),
700 _(b'REV'),
701 ),
701 ),
702 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
702 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
703 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
703 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
704 ]
704 ]
705 + mergetoolopts
705 + mergetoolopts
706 + walkopts
706 + walkopts
707 + commitopts
707 + commitopts
708 + commitopts2,
708 + commitopts2,
709 _(b'[OPTION]... [-r] REV'),
709 _(b'[OPTION]... [-r] REV'),
710 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
710 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
711 )
711 )
712 def backout(ui, repo, node=None, rev=None, **opts):
712 def backout(ui, repo, node=None, rev=None, **opts):
713 '''reverse effect of earlier changeset
713 '''reverse effect of earlier changeset
714
714
715 Prepare a new changeset with the effect of REV undone in the
715 Prepare a new changeset with the effect of REV undone in the
716 current working directory. If no conflicts were encountered,
716 current working directory. If no conflicts were encountered,
717 it will be committed immediately.
717 it will be committed immediately.
718
718
719 If REV is the parent of the working directory, then this new changeset
719 If REV is the parent of the working directory, then this new changeset
720 is committed automatically (unless --no-commit is specified).
720 is committed automatically (unless --no-commit is specified).
721
721
722 .. note::
722 .. note::
723
723
724 :hg:`backout` cannot be used to fix either an unwanted or
724 :hg:`backout` cannot be used to fix either an unwanted or
725 incorrect merge.
725 incorrect merge.
726
726
727 .. container:: verbose
727 .. container:: verbose
728
728
729 Examples:
729 Examples:
730
730
731 - Reverse the effect of the parent of the working directory.
731 - Reverse the effect of the parent of the working directory.
732 This backout will be committed immediately::
732 This backout will be committed immediately::
733
733
734 hg backout -r .
734 hg backout -r .
735
735
736 - Reverse the effect of previous bad revision 23::
736 - Reverse the effect of previous bad revision 23::
737
737
738 hg backout -r 23
738 hg backout -r 23
739
739
740 - Reverse the effect of previous bad revision 23 and
740 - Reverse the effect of previous bad revision 23 and
741 leave changes uncommitted::
741 leave changes uncommitted::
742
742
743 hg backout -r 23 --no-commit
743 hg backout -r 23 --no-commit
744 hg commit -m "Backout revision 23"
744 hg commit -m "Backout revision 23"
745
745
746 By default, the pending changeset will have one parent,
746 By default, the pending changeset will have one parent,
747 maintaining a linear history. With --merge, the pending
747 maintaining a linear history. With --merge, the pending
748 changeset will instead have two parents: the old parent of the
748 changeset will instead have two parents: the old parent of the
749 working directory and a new child of REV that simply undoes REV.
749 working directory and a new child of REV that simply undoes REV.
750
750
751 Before version 1.7, the behavior without --merge was equivalent
751 Before version 1.7, the behavior without --merge was equivalent
752 to specifying --merge followed by :hg:`update --clean .` to
752 to specifying --merge followed by :hg:`update --clean .` to
753 cancel the merge and leave the child of REV as a head to be
753 cancel the merge and leave the child of REV as a head to be
754 merged separately.
754 merged separately.
755
755
756 See :hg:`help dates` for a list of formats valid for -d/--date.
756 See :hg:`help dates` for a list of formats valid for -d/--date.
757
757
758 See :hg:`help revert` for a way to restore files to the state
758 See :hg:`help revert` for a way to restore files to the state
759 of another revision.
759 of another revision.
760
760
761 Returns 0 on success, 1 if nothing to backout or there are unresolved
761 Returns 0 on success, 1 if nothing to backout or there are unresolved
762 files.
762 files.
763 '''
763 '''
764 with repo.wlock(), repo.lock():
764 with repo.wlock(), repo.lock():
765 return _dobackout(ui, repo, node, rev, **opts)
765 return _dobackout(ui, repo, node, rev, **opts)
766
766
767
767
768 def _dobackout(ui, repo, node=None, rev=None, **opts):
768 def _dobackout(ui, repo, node=None, rev=None, **opts):
769 opts = pycompat.byteskwargs(opts)
769 opts = pycompat.byteskwargs(opts)
770 if opts.get(b'commit') and opts.get(b'no_commit'):
770 if opts.get(b'commit') and opts.get(b'no_commit'):
771 raise error.Abort(_(b"cannot use --commit with --no-commit"))
771 raise error.Abort(_(b"cannot use --commit with --no-commit"))
772 if opts.get(b'merge') and opts.get(b'no_commit'):
772 if opts.get(b'merge') and opts.get(b'no_commit'):
773 raise error.Abort(_(b"cannot use --merge with --no-commit"))
773 raise error.Abort(_(b"cannot use --merge with --no-commit"))
774
774
775 if rev and node:
775 if rev and node:
776 raise error.Abort(_(b"please specify just one revision"))
776 raise error.Abort(_(b"please specify just one revision"))
777
777
778 if not rev:
778 if not rev:
779 rev = node
779 rev = node
780
780
781 if not rev:
781 if not rev:
782 raise error.Abort(_(b"please specify a revision to backout"))
782 raise error.Abort(_(b"please specify a revision to backout"))
783
783
784 date = opts.get(b'date')
784 date = opts.get(b'date')
785 if date:
785 if date:
786 opts[b'date'] = dateutil.parsedate(date)
786 opts[b'date'] = dateutil.parsedate(date)
787
787
788 cmdutil.checkunfinished(repo)
788 cmdutil.checkunfinished(repo)
789 cmdutil.bailifchanged(repo)
789 cmdutil.bailifchanged(repo)
790 node = scmutil.revsingle(repo, rev).node()
790 node = scmutil.revsingle(repo, rev).node()
791
791
792 op1, op2 = repo.dirstate.parents()
792 op1, op2 = repo.dirstate.parents()
793 if not repo.changelog.isancestor(node, op1):
793 if not repo.changelog.isancestor(node, op1):
794 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
794 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
795
795
796 p1, p2 = repo.changelog.parents(node)
796 p1, p2 = repo.changelog.parents(node)
797 if p1 == nullid:
797 if p1 == nullid:
798 raise error.Abort(_(b'cannot backout a change with no parents'))
798 raise error.Abort(_(b'cannot backout a change with no parents'))
799 if p2 != nullid:
799 if p2 != nullid:
800 if not opts.get(b'parent'):
800 if not opts.get(b'parent'):
801 raise error.Abort(_(b'cannot backout a merge changeset'))
801 raise error.Abort(_(b'cannot backout a merge changeset'))
802 p = repo.lookup(opts[b'parent'])
802 p = repo.lookup(opts[b'parent'])
803 if p not in (p1, p2):
803 if p not in (p1, p2):
804 raise error.Abort(
804 raise error.Abort(
805 _(b'%s is not a parent of %s') % (short(p), short(node))
805 _(b'%s is not a parent of %s') % (short(p), short(node))
806 )
806 )
807 parent = p
807 parent = p
808 else:
808 else:
809 if opts.get(b'parent'):
809 if opts.get(b'parent'):
810 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
810 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
811 parent = p1
811 parent = p1
812
812
813 # the backout should appear on the same branch
813 # the backout should appear on the same branch
814 branch = repo.dirstate.branch()
814 branch = repo.dirstate.branch()
815 bheads = repo.branchheads(branch)
815 bheads = repo.branchheads(branch)
816 rctx = scmutil.revsingle(repo, hex(parent))
816 rctx = scmutil.revsingle(repo, hex(parent))
817 if not opts.get(b'merge') and op1 != node:
817 if not opts.get(b'merge') and op1 != node:
818 with dirstateguard.dirstateguard(repo, b'backout'):
818 with dirstateguard.dirstateguard(repo, b'backout'):
819 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
819 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
820 with ui.configoverride(overrides, b'backout'):
820 with ui.configoverride(overrides, b'backout'):
821 stats = mergemod.update(
821 stats = mergemod.update(
822 repo,
822 repo,
823 parent,
823 parent,
824 branchmerge=True,
824 branchmerge=True,
825 force=True,
825 force=True,
826 ancestor=node,
826 ancestor=node,
827 mergeancestor=False,
827 mergeancestor=False,
828 )
828 )
829 repo.setparents(op1, op2)
829 repo.setparents(op1, op2)
830 hg._showstats(repo, stats)
830 hg._showstats(repo, stats)
831 if stats.unresolvedcount:
831 if stats.unresolvedcount:
832 repo.ui.status(
832 repo.ui.status(
833 _(b"use 'hg resolve' to retry unresolved file merges\n")
833 _(b"use 'hg resolve' to retry unresolved file merges\n")
834 )
834 )
835 return 1
835 return 1
836 else:
836 else:
837 hg.clean(repo, node, show_stats=False)
837 hg.clean(repo, node, show_stats=False)
838 repo.dirstate.setbranch(branch)
838 repo.dirstate.setbranch(branch)
839 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
839 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
840
840
841 if opts.get(b'no_commit'):
841 if opts.get(b'no_commit'):
842 msg = _(b"changeset %s backed out, don't forget to commit.\n")
842 msg = _(b"changeset %s backed out, don't forget to commit.\n")
843 ui.status(msg % short(node))
843 ui.status(msg % short(node))
844 return 0
844 return 0
845
845
846 def commitfunc(ui, repo, message, match, opts):
846 def commitfunc(ui, repo, message, match, opts):
847 editform = b'backout'
847 editform = b'backout'
848 e = cmdutil.getcommiteditor(
848 e = cmdutil.getcommiteditor(
849 editform=editform, **pycompat.strkwargs(opts)
849 editform=editform, **pycompat.strkwargs(opts)
850 )
850 )
851 if not message:
851 if not message:
852 # we don't translate commit messages
852 # we don't translate commit messages
853 message = b"Backed out changeset %s" % short(node)
853 message = b"Backed out changeset %s" % short(node)
854 e = cmdutil.getcommiteditor(edit=True, editform=editform)
854 e = cmdutil.getcommiteditor(edit=True, editform=editform)
855 return repo.commit(
855 return repo.commit(
856 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
856 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
857 )
857 )
858
858
859 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
859 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
860 if not newnode:
860 if not newnode:
861 ui.status(_(b"nothing changed\n"))
861 ui.status(_(b"nothing changed\n"))
862 return 1
862 return 1
863 cmdutil.commitstatus(repo, newnode, branch, bheads)
863 cmdutil.commitstatus(repo, newnode, branch, bheads)
864
864
865 def nice(node):
865 def nice(node):
866 return b'%d:%s' % (repo.changelog.rev(node), short(node))
866 return b'%d:%s' % (repo.changelog.rev(node), short(node))
867
867
868 ui.status(
868 ui.status(
869 _(b'changeset %s backs out changeset %s\n')
869 _(b'changeset %s backs out changeset %s\n')
870 % (nice(repo.changelog.tip()), nice(node))
870 % (nice(repo.changelog.tip()), nice(node))
871 )
871 )
872 if opts.get(b'merge') and op1 != node:
872 if opts.get(b'merge') and op1 != node:
873 hg.clean(repo, op1, show_stats=False)
873 hg.clean(repo, op1, show_stats=False)
874 ui.status(
874 ui.status(
875 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
875 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
876 )
876 )
877 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
877 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
878 with ui.configoverride(overrides, b'backout'):
878 with ui.configoverride(overrides, b'backout'):
879 return hg.merge(repo, hex(repo.changelog.tip()))
879 return hg.merge(repo, hex(repo.changelog.tip()))
880 return 0
880 return 0
881
881
882
882
883 @command(
883 @command(
884 b'bisect',
884 b'bisect',
885 [
885 [
886 (b'r', b'reset', False, _(b'reset bisect state')),
886 (b'r', b'reset', False, _(b'reset bisect state')),
887 (b'g', b'good', False, _(b'mark changeset good')),
887 (b'g', b'good', False, _(b'mark changeset good')),
888 (b'b', b'bad', False, _(b'mark changeset bad')),
888 (b'b', b'bad', False, _(b'mark changeset bad')),
889 (b's', b'skip', False, _(b'skip testing changeset')),
889 (b's', b'skip', False, _(b'skip testing changeset')),
890 (b'e', b'extend', False, _(b'extend the bisect range')),
890 (b'e', b'extend', False, _(b'extend the bisect range')),
891 (
891 (
892 b'c',
892 b'c',
893 b'command',
893 b'command',
894 b'',
894 b'',
895 _(b'use command to check changeset state'),
895 _(b'use command to check changeset state'),
896 _(b'CMD'),
896 _(b'CMD'),
897 ),
897 ),
898 (b'U', b'noupdate', False, _(b'do not update to target')),
898 (b'U', b'noupdate', False, _(b'do not update to target')),
899 ],
899 ],
900 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
900 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
901 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
901 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
902 )
902 )
903 def bisect(
903 def bisect(
904 ui,
904 ui,
905 repo,
905 repo,
906 rev=None,
906 rev=None,
907 extra=None,
907 extra=None,
908 command=None,
908 command=None,
909 reset=None,
909 reset=None,
910 good=None,
910 good=None,
911 bad=None,
911 bad=None,
912 skip=None,
912 skip=None,
913 extend=None,
913 extend=None,
914 noupdate=None,
914 noupdate=None,
915 ):
915 ):
916 """subdivision search of changesets
916 """subdivision search of changesets
917
917
918 This command helps to find changesets which introduce problems. To
918 This command helps to find changesets which introduce problems. To
919 use, mark the earliest changeset you know exhibits the problem as
919 use, mark the earliest changeset you know exhibits the problem as
920 bad, then mark the latest changeset which is free from the problem
920 bad, then mark the latest changeset which is free from the problem
921 as good. Bisect will update your working directory to a revision
921 as good. Bisect will update your working directory to a revision
922 for testing (unless the -U/--noupdate option is specified). Once
922 for testing (unless the -U/--noupdate option is specified). Once
923 you have performed tests, mark the working directory as good or
923 you have performed tests, mark the working directory as good or
924 bad, and bisect will either update to another candidate changeset
924 bad, and bisect will either update to another candidate changeset
925 or announce that it has found the bad revision.
925 or announce that it has found the bad revision.
926
926
927 As a shortcut, you can also use the revision argument to mark a
927 As a shortcut, you can also use the revision argument to mark a
928 revision as good or bad without checking it out first.
928 revision as good or bad without checking it out first.
929
929
930 If you supply a command, it will be used for automatic bisection.
930 If you supply a command, it will be used for automatic bisection.
931 The environment variable HG_NODE will contain the ID of the
931 The environment variable HG_NODE will contain the ID of the
932 changeset being tested. The exit status of the command will be
932 changeset being tested. The exit status of the command will be
933 used to mark revisions as good or bad: status 0 means good, 125
933 used to mark revisions as good or bad: status 0 means good, 125
934 means to skip the revision, 127 (command not found) will abort the
934 means to skip the revision, 127 (command not found) will abort the
935 bisection, and any other non-zero exit status means the revision
935 bisection, and any other non-zero exit status means the revision
936 is bad.
936 is bad.
937
937
938 .. container:: verbose
938 .. container:: verbose
939
939
940 Some examples:
940 Some examples:
941
941
942 - start a bisection with known bad revision 34, and good revision 12::
942 - start a bisection with known bad revision 34, and good revision 12::
943
943
944 hg bisect --bad 34
944 hg bisect --bad 34
945 hg bisect --good 12
945 hg bisect --good 12
946
946
947 - advance the current bisection by marking current revision as good or
947 - advance the current bisection by marking current revision as good or
948 bad::
948 bad::
949
949
950 hg bisect --good
950 hg bisect --good
951 hg bisect --bad
951 hg bisect --bad
952
952
953 - mark the current revision, or a known revision, to be skipped (e.g. if
953 - mark the current revision, or a known revision, to be skipped (e.g. if
954 that revision is not usable because of another issue)::
954 that revision is not usable because of another issue)::
955
955
956 hg bisect --skip
956 hg bisect --skip
957 hg bisect --skip 23
957 hg bisect --skip 23
958
958
959 - skip all revisions that do not touch directories ``foo`` or ``bar``::
959 - skip all revisions that do not touch directories ``foo`` or ``bar``::
960
960
961 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
961 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
962
962
963 - forget the current bisection::
963 - forget the current bisection::
964
964
965 hg bisect --reset
965 hg bisect --reset
966
966
967 - use 'make && make tests' to automatically find the first broken
967 - use 'make && make tests' to automatically find the first broken
968 revision::
968 revision::
969
969
970 hg bisect --reset
970 hg bisect --reset
971 hg bisect --bad 34
971 hg bisect --bad 34
972 hg bisect --good 12
972 hg bisect --good 12
973 hg bisect --command "make && make tests"
973 hg bisect --command "make && make tests"
974
974
975 - see all changesets whose states are already known in the current
975 - see all changesets whose states are already known in the current
976 bisection::
976 bisection::
977
977
978 hg log -r "bisect(pruned)"
978 hg log -r "bisect(pruned)"
979
979
980 - see the changeset currently being bisected (especially useful
980 - see the changeset currently being bisected (especially useful
981 if running with -U/--noupdate)::
981 if running with -U/--noupdate)::
982
982
983 hg log -r "bisect(current)"
983 hg log -r "bisect(current)"
984
984
985 - see all changesets that took part in the current bisection::
985 - see all changesets that took part in the current bisection::
986
986
987 hg log -r "bisect(range)"
987 hg log -r "bisect(range)"
988
988
989 - you can even get a nice graph::
989 - you can even get a nice graph::
990
990
991 hg log --graph -r "bisect(range)"
991 hg log --graph -r "bisect(range)"
992
992
993 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
993 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
994
994
995 Returns 0 on success.
995 Returns 0 on success.
996 """
996 """
997 # backward compatibility
997 # backward compatibility
998 if rev in b"good bad reset init".split():
998 if rev in b"good bad reset init".split():
999 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
999 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1000 cmd, rev, extra = rev, extra, None
1000 cmd, rev, extra = rev, extra, None
1001 if cmd == b"good":
1001 if cmd == b"good":
1002 good = True
1002 good = True
1003 elif cmd == b"bad":
1003 elif cmd == b"bad":
1004 bad = True
1004 bad = True
1005 else:
1005 else:
1006 reset = True
1006 reset = True
1007 elif extra:
1007 elif extra:
1008 raise error.Abort(_(b'incompatible arguments'))
1008 raise error.Abort(_(b'incompatible arguments'))
1009
1009
1010 incompatibles = {
1010 incompatibles = {
1011 b'--bad': bad,
1011 b'--bad': bad,
1012 b'--command': bool(command),
1012 b'--command': bool(command),
1013 b'--extend': extend,
1013 b'--extend': extend,
1014 b'--good': good,
1014 b'--good': good,
1015 b'--reset': reset,
1015 b'--reset': reset,
1016 b'--skip': skip,
1016 b'--skip': skip,
1017 }
1017 }
1018
1018
1019 enabled = [x for x in incompatibles if incompatibles[x]]
1019 enabled = [x for x in incompatibles if incompatibles[x]]
1020
1020
1021 if len(enabled) > 1:
1021 if len(enabled) > 1:
1022 raise error.Abort(
1022 raise error.Abort(
1023 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1023 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1024 )
1024 )
1025
1025
1026 if reset:
1026 if reset:
1027 hbisect.resetstate(repo)
1027 hbisect.resetstate(repo)
1028 return
1028 return
1029
1029
1030 state = hbisect.load_state(repo)
1030 state = hbisect.load_state(repo)
1031
1031
1032 # update state
1032 # update state
1033 if good or bad or skip:
1033 if good or bad or skip:
1034 if rev:
1034 if rev:
1035 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1035 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1036 else:
1036 else:
1037 nodes = [repo.lookup(b'.')]
1037 nodes = [repo.lookup(b'.')]
1038 if good:
1038 if good:
1039 state[b'good'] += nodes
1039 state[b'good'] += nodes
1040 elif bad:
1040 elif bad:
1041 state[b'bad'] += nodes
1041 state[b'bad'] += nodes
1042 elif skip:
1042 elif skip:
1043 state[b'skip'] += nodes
1043 state[b'skip'] += nodes
1044 hbisect.save_state(repo, state)
1044 hbisect.save_state(repo, state)
1045 if not (state[b'good'] and state[b'bad']):
1045 if not (state[b'good'] and state[b'bad']):
1046 return
1046 return
1047
1047
1048 def mayupdate(repo, node, show_stats=True):
1048 def mayupdate(repo, node, show_stats=True):
1049 """common used update sequence"""
1049 """common used update sequence"""
1050 if noupdate:
1050 if noupdate:
1051 return
1051 return
1052 cmdutil.checkunfinished(repo)
1052 cmdutil.checkunfinished(repo)
1053 cmdutil.bailifchanged(repo)
1053 cmdutil.bailifchanged(repo)
1054 return hg.clean(repo, node, show_stats=show_stats)
1054 return hg.clean(repo, node, show_stats=show_stats)
1055
1055
1056 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1056 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1057
1057
1058 if command:
1058 if command:
1059 changesets = 1
1059 changesets = 1
1060 if noupdate:
1060 if noupdate:
1061 try:
1061 try:
1062 node = state[b'current'][0]
1062 node = state[b'current'][0]
1063 except LookupError:
1063 except LookupError:
1064 raise error.Abort(
1064 raise error.Abort(
1065 _(
1065 _(
1066 b'current bisect revision is unknown - '
1066 b'current bisect revision is unknown - '
1067 b'start a new bisect to fix'
1067 b'start a new bisect to fix'
1068 )
1068 )
1069 )
1069 )
1070 else:
1070 else:
1071 node, p2 = repo.dirstate.parents()
1071 node, p2 = repo.dirstate.parents()
1072 if p2 != nullid:
1072 if p2 != nullid:
1073 raise error.Abort(_(b'current bisect revision is a merge'))
1073 raise error.Abort(_(b'current bisect revision is a merge'))
1074 if rev:
1074 if rev:
1075 node = repo[scmutil.revsingle(repo, rev, node)].node()
1075 node = repo[scmutil.revsingle(repo, rev, node)].node()
1076 with hbisect.restore_state(repo, state, node):
1076 with hbisect.restore_state(repo, state, node):
1077 while changesets:
1077 while changesets:
1078 # update state
1078 # update state
1079 state[b'current'] = [node]
1079 state[b'current'] = [node]
1080 hbisect.save_state(repo, state)
1080 hbisect.save_state(repo, state)
1081 status = ui.system(
1081 status = ui.system(
1082 command,
1082 command,
1083 environ={b'HG_NODE': hex(node)},
1083 environ={b'HG_NODE': hex(node)},
1084 blockedtag=b'bisect_check',
1084 blockedtag=b'bisect_check',
1085 )
1085 )
1086 if status == 125:
1086 if status == 125:
1087 transition = b"skip"
1087 transition = b"skip"
1088 elif status == 0:
1088 elif status == 0:
1089 transition = b"good"
1089 transition = b"good"
1090 # status < 0 means process was killed
1090 # status < 0 means process was killed
1091 elif status == 127:
1091 elif status == 127:
1092 raise error.Abort(_(b"failed to execute %s") % command)
1092 raise error.Abort(_(b"failed to execute %s") % command)
1093 elif status < 0:
1093 elif status < 0:
1094 raise error.Abort(_(b"%s killed") % command)
1094 raise error.Abort(_(b"%s killed") % command)
1095 else:
1095 else:
1096 transition = b"bad"
1096 transition = b"bad"
1097 state[transition].append(node)
1097 state[transition].append(node)
1098 ctx = repo[node]
1098 ctx = repo[node]
1099 ui.status(
1099 ui.status(
1100 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1100 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1101 )
1101 )
1102 hbisect.checkstate(state)
1102 hbisect.checkstate(state)
1103 # bisect
1103 # bisect
1104 nodes, changesets, bgood = hbisect.bisect(repo, state)
1104 nodes, changesets, bgood = hbisect.bisect(repo, state)
1105 # update to next check
1105 # update to next check
1106 node = nodes[0]
1106 node = nodes[0]
1107 mayupdate(repo, node, show_stats=False)
1107 mayupdate(repo, node, show_stats=False)
1108 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1108 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1109 return
1109 return
1110
1110
1111 hbisect.checkstate(state)
1111 hbisect.checkstate(state)
1112
1112
1113 # actually bisect
1113 # actually bisect
1114 nodes, changesets, good = hbisect.bisect(repo, state)
1114 nodes, changesets, good = hbisect.bisect(repo, state)
1115 if extend:
1115 if extend:
1116 if not changesets:
1116 if not changesets:
1117 extendnode = hbisect.extendrange(repo, state, nodes, good)
1117 extendnode = hbisect.extendrange(repo, state, nodes, good)
1118 if extendnode is not None:
1118 if extendnode is not None:
1119 ui.write(
1119 ui.write(
1120 _(b"Extending search to changeset %d:%s\n")
1120 _(b"Extending search to changeset %d:%s\n")
1121 % (extendnode.rev(), extendnode)
1121 % (extendnode.rev(), extendnode)
1122 )
1122 )
1123 state[b'current'] = [extendnode.node()]
1123 state[b'current'] = [extendnode.node()]
1124 hbisect.save_state(repo, state)
1124 hbisect.save_state(repo, state)
1125 return mayupdate(repo, extendnode.node())
1125 return mayupdate(repo, extendnode.node())
1126 raise error.Abort(_(b"nothing to extend"))
1126 raise error.Abort(_(b"nothing to extend"))
1127
1127
1128 if changesets == 0:
1128 if changesets == 0:
1129 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1129 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1130 else:
1130 else:
1131 assert len(nodes) == 1 # only a single node can be tested next
1131 assert len(nodes) == 1 # only a single node can be tested next
1132 node = nodes[0]
1132 node = nodes[0]
1133 # compute the approximate number of remaining tests
1133 # compute the approximate number of remaining tests
1134 tests, size = 0, 2
1134 tests, size = 0, 2
1135 while size <= changesets:
1135 while size <= changesets:
1136 tests, size = tests + 1, size * 2
1136 tests, size = tests + 1, size * 2
1137 rev = repo.changelog.rev(node)
1137 rev = repo.changelog.rev(node)
1138 ui.write(
1138 ui.write(
1139 _(
1139 _(
1140 b"Testing changeset %d:%s "
1140 b"Testing changeset %d:%s "
1141 b"(%d changesets remaining, ~%d tests)\n"
1141 b"(%d changesets remaining, ~%d tests)\n"
1142 )
1142 )
1143 % (rev, short(node), changesets, tests)
1143 % (rev, short(node), changesets, tests)
1144 )
1144 )
1145 state[b'current'] = [node]
1145 state[b'current'] = [node]
1146 hbisect.save_state(repo, state)
1146 hbisect.save_state(repo, state)
1147 return mayupdate(repo, node)
1147 return mayupdate(repo, node)
1148
1148
1149
1149
1150 @command(
1150 @command(
1151 b'bookmarks|bookmark',
1151 b'bookmarks|bookmark',
1152 [
1152 [
1153 (b'f', b'force', False, _(b'force')),
1153 (b'f', b'force', False, _(b'force')),
1154 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1154 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1155 (b'd', b'delete', False, _(b'delete a given bookmark')),
1155 (b'd', b'delete', False, _(b'delete a given bookmark')),
1156 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1156 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1157 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1157 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1158 (b'l', b'list', False, _(b'list existing bookmarks')),
1158 (b'l', b'list', False, _(b'list existing bookmarks')),
1159 ]
1159 ]
1160 + formatteropts,
1160 + formatteropts,
1161 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1161 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1162 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1162 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1163 )
1163 )
1164 def bookmark(ui, repo, *names, **opts):
1164 def bookmark(ui, repo, *names, **opts):
1165 '''create a new bookmark or list existing bookmarks
1165 '''create a new bookmark or list existing bookmarks
1166
1166
1167 Bookmarks are labels on changesets to help track lines of development.
1167 Bookmarks are labels on changesets to help track lines of development.
1168 Bookmarks are unversioned and can be moved, renamed and deleted.
1168 Bookmarks are unversioned and can be moved, renamed and deleted.
1169 Deleting or moving a bookmark has no effect on the associated changesets.
1169 Deleting or moving a bookmark has no effect on the associated changesets.
1170
1170
1171 Creating or updating to a bookmark causes it to be marked as 'active'.
1171 Creating or updating to a bookmark causes it to be marked as 'active'.
1172 The active bookmark is indicated with a '*'.
1172 The active bookmark is indicated with a '*'.
1173 When a commit is made, the active bookmark will advance to the new commit.
1173 When a commit is made, the active bookmark will advance to the new commit.
1174 A plain :hg:`update` will also advance an active bookmark, if possible.
1174 A plain :hg:`update` will also advance an active bookmark, if possible.
1175 Updating away from a bookmark will cause it to be deactivated.
1175 Updating away from a bookmark will cause it to be deactivated.
1176
1176
1177 Bookmarks can be pushed and pulled between repositories (see
1177 Bookmarks can be pushed and pulled between repositories (see
1178 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1178 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1179 diverged, a new 'divergent bookmark' of the form 'name@path' will
1179 diverged, a new 'divergent bookmark' of the form 'name@path' will
1180 be created. Using :hg:`merge` will resolve the divergence.
1180 be created. Using :hg:`merge` will resolve the divergence.
1181
1181
1182 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1182 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1183 the active bookmark's name.
1183 the active bookmark's name.
1184
1184
1185 A bookmark named '@' has the special property that :hg:`clone` will
1185 A bookmark named '@' has the special property that :hg:`clone` will
1186 check it out by default if it exists.
1186 check it out by default if it exists.
1187
1187
1188 .. container:: verbose
1188 .. container:: verbose
1189
1189
1190 Template:
1190 Template:
1191
1191
1192 The following keywords are supported in addition to the common template
1192 The following keywords are supported in addition to the common template
1193 keywords and functions such as ``{bookmark}``. See also
1193 keywords and functions such as ``{bookmark}``. See also
1194 :hg:`help templates`.
1194 :hg:`help templates`.
1195
1195
1196 :active: Boolean. True if the bookmark is active.
1196 :active: Boolean. True if the bookmark is active.
1197
1197
1198 Examples:
1198 Examples:
1199
1199
1200 - create an active bookmark for a new line of development::
1200 - create an active bookmark for a new line of development::
1201
1201
1202 hg book new-feature
1202 hg book new-feature
1203
1203
1204 - create an inactive bookmark as a place marker::
1204 - create an inactive bookmark as a place marker::
1205
1205
1206 hg book -i reviewed
1206 hg book -i reviewed
1207
1207
1208 - create an inactive bookmark on another changeset::
1208 - create an inactive bookmark on another changeset::
1209
1209
1210 hg book -r .^ tested
1210 hg book -r .^ tested
1211
1211
1212 - rename bookmark turkey to dinner::
1212 - rename bookmark turkey to dinner::
1213
1213
1214 hg book -m turkey dinner
1214 hg book -m turkey dinner
1215
1215
1216 - move the '@' bookmark from another branch::
1216 - move the '@' bookmark from another branch::
1217
1217
1218 hg book -f @
1218 hg book -f @
1219
1219
1220 - print only the active bookmark name::
1220 - print only the active bookmark name::
1221
1221
1222 hg book -ql .
1222 hg book -ql .
1223 '''
1223 '''
1224 opts = pycompat.byteskwargs(opts)
1224 opts = pycompat.byteskwargs(opts)
1225 force = opts.get(b'force')
1225 force = opts.get(b'force')
1226 rev = opts.get(b'rev')
1226 rev = opts.get(b'rev')
1227 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1227 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1228
1228
1229 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1229 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1230 if action:
1230 if action:
1231 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1231 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1232 elif names or rev:
1232 elif names or rev:
1233 action = b'add'
1233 action = b'add'
1234 elif inactive:
1234 elif inactive:
1235 action = b'inactive' # meaning deactivate
1235 action = b'inactive' # meaning deactivate
1236 else:
1236 else:
1237 action = b'list'
1237 action = b'list'
1238
1238
1239 cmdutil.check_incompatible_arguments(
1239 cmdutil.check_incompatible_arguments(
1240 opts, b'inactive', [b'delete', b'list']
1240 opts, b'inactive', [b'delete', b'list']
1241 )
1241 )
1242 if not names and action in {b'add', b'delete'}:
1242 if not names and action in {b'add', b'delete'}:
1243 raise error.Abort(_(b"bookmark name required"))
1243 raise error.Abort(_(b"bookmark name required"))
1244
1244
1245 if action in {b'add', b'delete', b'rename', b'inactive'}:
1245 if action in {b'add', b'delete', b'rename', b'inactive'}:
1246 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1246 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1247 if action == b'delete':
1247 if action == b'delete':
1248 names = pycompat.maplist(repo._bookmarks.expandname, names)
1248 names = pycompat.maplist(repo._bookmarks.expandname, names)
1249 bookmarks.delete(repo, tr, names)
1249 bookmarks.delete(repo, tr, names)
1250 elif action == b'rename':
1250 elif action == b'rename':
1251 if not names:
1251 if not names:
1252 raise error.Abort(_(b"new bookmark name required"))
1252 raise error.Abort(_(b"new bookmark name required"))
1253 elif len(names) > 1:
1253 elif len(names) > 1:
1254 raise error.Abort(_(b"only one new bookmark name allowed"))
1254 raise error.Abort(_(b"only one new bookmark name allowed"))
1255 oldname = repo._bookmarks.expandname(opts[b'rename'])
1255 oldname = repo._bookmarks.expandname(opts[b'rename'])
1256 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1256 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1257 elif action == b'add':
1257 elif action == b'add':
1258 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1258 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1259 elif action == b'inactive':
1259 elif action == b'inactive':
1260 if len(repo._bookmarks) == 0:
1260 if len(repo._bookmarks) == 0:
1261 ui.status(_(b"no bookmarks set\n"))
1261 ui.status(_(b"no bookmarks set\n"))
1262 elif not repo._activebookmark:
1262 elif not repo._activebookmark:
1263 ui.status(_(b"no active bookmark\n"))
1263 ui.status(_(b"no active bookmark\n"))
1264 else:
1264 else:
1265 bookmarks.deactivate(repo)
1265 bookmarks.deactivate(repo)
1266 elif action == b'list':
1266 elif action == b'list':
1267 names = pycompat.maplist(repo._bookmarks.expandname, names)
1267 names = pycompat.maplist(repo._bookmarks.expandname, names)
1268 with ui.formatter(b'bookmarks', opts) as fm:
1268 with ui.formatter(b'bookmarks', opts) as fm:
1269 bookmarks.printbookmarks(ui, repo, fm, names)
1269 bookmarks.printbookmarks(ui, repo, fm, names)
1270 else:
1270 else:
1271 raise error.ProgrammingError(b'invalid action: %s' % action)
1271 raise error.ProgrammingError(b'invalid action: %s' % action)
1272
1272
1273
1273
1274 @command(
1274 @command(
1275 b'branch',
1275 b'branch',
1276 [
1276 [
1277 (
1277 (
1278 b'f',
1278 b'f',
1279 b'force',
1279 b'force',
1280 None,
1280 None,
1281 _(b'set branch name even if it shadows an existing branch'),
1281 _(b'set branch name even if it shadows an existing branch'),
1282 ),
1282 ),
1283 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1283 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1284 (
1284 (
1285 b'r',
1285 b'r',
1286 b'rev',
1286 b'rev',
1287 [],
1287 [],
1288 _(b'change branches of the given revs (EXPERIMENTAL)'),
1288 _(b'change branches of the given revs (EXPERIMENTAL)'),
1289 ),
1289 ),
1290 ],
1290 ],
1291 _(b'[-fC] [NAME]'),
1291 _(b'[-fC] [NAME]'),
1292 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1292 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1293 )
1293 )
1294 def branch(ui, repo, label=None, **opts):
1294 def branch(ui, repo, label=None, **opts):
1295 """set or show the current branch name
1295 """set or show the current branch name
1296
1296
1297 .. note::
1297 .. note::
1298
1298
1299 Branch names are permanent and global. Use :hg:`bookmark` to create a
1299 Branch names are permanent and global. Use :hg:`bookmark` to create a
1300 light-weight bookmark instead. See :hg:`help glossary` for more
1300 light-weight bookmark instead. See :hg:`help glossary` for more
1301 information about named branches and bookmarks.
1301 information about named branches and bookmarks.
1302
1302
1303 With no argument, show the current branch name. With one argument,
1303 With no argument, show the current branch name. With one argument,
1304 set the working directory branch name (the branch will not exist
1304 set the working directory branch name (the branch will not exist
1305 in the repository until the next commit). Standard practice
1305 in the repository until the next commit). Standard practice
1306 recommends that primary development take place on the 'default'
1306 recommends that primary development take place on the 'default'
1307 branch.
1307 branch.
1308
1308
1309 Unless -f/--force is specified, branch will not let you set a
1309 Unless -f/--force is specified, branch will not let you set a
1310 branch name that already exists.
1310 branch name that already exists.
1311
1311
1312 Use -C/--clean to reset the working directory branch to that of
1312 Use -C/--clean to reset the working directory branch to that of
1313 the parent of the working directory, negating a previous branch
1313 the parent of the working directory, negating a previous branch
1314 change.
1314 change.
1315
1315
1316 Use the command :hg:`update` to switch to an existing branch. Use
1316 Use the command :hg:`update` to switch to an existing branch. Use
1317 :hg:`commit --close-branch` to mark this branch head as closed.
1317 :hg:`commit --close-branch` to mark this branch head as closed.
1318 When all heads of a branch are closed, the branch will be
1318 When all heads of a branch are closed, the branch will be
1319 considered closed.
1319 considered closed.
1320
1320
1321 Returns 0 on success.
1321 Returns 0 on success.
1322 """
1322 """
1323 opts = pycompat.byteskwargs(opts)
1323 opts = pycompat.byteskwargs(opts)
1324 revs = opts.get(b'rev')
1324 revs = opts.get(b'rev')
1325 if label:
1325 if label:
1326 label = label.strip()
1326 label = label.strip()
1327
1327
1328 if not opts.get(b'clean') and not label:
1328 if not opts.get(b'clean') and not label:
1329 if revs:
1329 if revs:
1330 raise error.Abort(_(b"no branch name specified for the revisions"))
1330 raise error.Abort(_(b"no branch name specified for the revisions"))
1331 ui.write(b"%s\n" % repo.dirstate.branch())
1331 ui.write(b"%s\n" % repo.dirstate.branch())
1332 return
1332 return
1333
1333
1334 with repo.wlock():
1334 with repo.wlock():
1335 if opts.get(b'clean'):
1335 if opts.get(b'clean'):
1336 label = repo[b'.'].branch()
1336 label = repo[b'.'].branch()
1337 repo.dirstate.setbranch(label)
1337 repo.dirstate.setbranch(label)
1338 ui.status(_(b'reset working directory to branch %s\n') % label)
1338 ui.status(_(b'reset working directory to branch %s\n') % label)
1339 elif label:
1339 elif label:
1340
1340
1341 scmutil.checknewlabel(repo, label, b'branch')
1341 scmutil.checknewlabel(repo, label, b'branch')
1342 if revs:
1342 if revs:
1343 return cmdutil.changebranch(ui, repo, revs, label)
1343 return cmdutil.changebranch(ui, repo, revs, label)
1344
1344
1345 if not opts.get(b'force') and label in repo.branchmap():
1345 if not opts.get(b'force') and label in repo.branchmap():
1346 if label not in [p.branch() for p in repo[None].parents()]:
1346 if label not in [p.branch() for p in repo[None].parents()]:
1347 raise error.Abort(
1347 raise error.Abort(
1348 _(b'a branch of the same name already exists'),
1348 _(b'a branch of the same name already exists'),
1349 # i18n: "it" refers to an existing branch
1349 # i18n: "it" refers to an existing branch
1350 hint=_(b"use 'hg update' to switch to it"),
1350 hint=_(b"use 'hg update' to switch to it"),
1351 )
1351 )
1352
1352
1353 repo.dirstate.setbranch(label)
1353 repo.dirstate.setbranch(label)
1354 ui.status(_(b'marked working directory as branch %s\n') % label)
1354 ui.status(_(b'marked working directory as branch %s\n') % label)
1355
1355
1356 # find any open named branches aside from default
1356 # find any open named branches aside from default
1357 for n, h, t, c in repo.branchmap().iterbranches():
1357 for n, h, t, c in repo.branchmap().iterbranches():
1358 if n != b"default" and not c:
1358 if n != b"default" and not c:
1359 return 0
1359 return 0
1360 ui.status(
1360 ui.status(
1361 _(
1361 _(
1362 b'(branches are permanent and global, '
1362 b'(branches are permanent and global, '
1363 b'did you want a bookmark?)\n'
1363 b'did you want a bookmark?)\n'
1364 )
1364 )
1365 )
1365 )
1366
1366
1367
1367
1368 @command(
1368 @command(
1369 b'branches',
1369 b'branches',
1370 [
1370 [
1371 (
1371 (
1372 b'a',
1372 b'a',
1373 b'active',
1373 b'active',
1374 False,
1374 False,
1375 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1375 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1376 ),
1376 ),
1377 (b'c', b'closed', False, _(b'show normal and closed branches')),
1377 (b'c', b'closed', False, _(b'show normal and closed branches')),
1378 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1378 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1379 ]
1379 ]
1380 + formatteropts,
1380 + formatteropts,
1381 _(b'[-c]'),
1381 _(b'[-c]'),
1382 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1382 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1383 intents={INTENT_READONLY},
1383 intents={INTENT_READONLY},
1384 )
1384 )
1385 def branches(ui, repo, active=False, closed=False, **opts):
1385 def branches(ui, repo, active=False, closed=False, **opts):
1386 """list repository named branches
1386 """list repository named branches
1387
1387
1388 List the repository's named branches, indicating which ones are
1388 List the repository's named branches, indicating which ones are
1389 inactive. If -c/--closed is specified, also list branches which have
1389 inactive. If -c/--closed is specified, also list branches which have
1390 been marked closed (see :hg:`commit --close-branch`).
1390 been marked closed (see :hg:`commit --close-branch`).
1391
1391
1392 Use the command :hg:`update` to switch to an existing branch.
1392 Use the command :hg:`update` to switch to an existing branch.
1393
1393
1394 .. container:: verbose
1394 .. container:: verbose
1395
1395
1396 Template:
1396 Template:
1397
1397
1398 The following keywords are supported in addition to the common template
1398 The following keywords are supported in addition to the common template
1399 keywords and functions such as ``{branch}``. See also
1399 keywords and functions such as ``{branch}``. See also
1400 :hg:`help templates`.
1400 :hg:`help templates`.
1401
1401
1402 :active: Boolean. True if the branch is active.
1402 :active: Boolean. True if the branch is active.
1403 :closed: Boolean. True if the branch is closed.
1403 :closed: Boolean. True if the branch is closed.
1404 :current: Boolean. True if it is the current branch.
1404 :current: Boolean. True if it is the current branch.
1405
1405
1406 Returns 0.
1406 Returns 0.
1407 """
1407 """
1408
1408
1409 opts = pycompat.byteskwargs(opts)
1409 opts = pycompat.byteskwargs(opts)
1410 revs = opts.get(b'rev')
1410 revs = opts.get(b'rev')
1411 selectedbranches = None
1411 selectedbranches = None
1412 if revs:
1412 if revs:
1413 revs = scmutil.revrange(repo, revs)
1413 revs = scmutil.revrange(repo, revs)
1414 getbi = repo.revbranchcache().branchinfo
1414 getbi = repo.revbranchcache().branchinfo
1415 selectedbranches = {getbi(r)[0] for r in revs}
1415 selectedbranches = {getbi(r)[0] for r in revs}
1416
1416
1417 ui.pager(b'branches')
1417 ui.pager(b'branches')
1418 fm = ui.formatter(b'branches', opts)
1418 fm = ui.formatter(b'branches', opts)
1419 hexfunc = fm.hexfunc
1419 hexfunc = fm.hexfunc
1420
1420
1421 allheads = set(repo.heads())
1421 allheads = set(repo.heads())
1422 branches = []
1422 branches = []
1423 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1423 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1424 if selectedbranches is not None and tag not in selectedbranches:
1424 if selectedbranches is not None and tag not in selectedbranches:
1425 continue
1425 continue
1426 isactive = False
1426 isactive = False
1427 if not isclosed:
1427 if not isclosed:
1428 openheads = set(repo.branchmap().iteropen(heads))
1428 openheads = set(repo.branchmap().iteropen(heads))
1429 isactive = bool(openheads & allheads)
1429 isactive = bool(openheads & allheads)
1430 branches.append((tag, repo[tip], isactive, not isclosed))
1430 branches.append((tag, repo[tip], isactive, not isclosed))
1431 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1431 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1432
1432
1433 for tag, ctx, isactive, isopen in branches:
1433 for tag, ctx, isactive, isopen in branches:
1434 if active and not isactive:
1434 if active and not isactive:
1435 continue
1435 continue
1436 if isactive:
1436 if isactive:
1437 label = b'branches.active'
1437 label = b'branches.active'
1438 notice = b''
1438 notice = b''
1439 elif not isopen:
1439 elif not isopen:
1440 if not closed:
1440 if not closed:
1441 continue
1441 continue
1442 label = b'branches.closed'
1442 label = b'branches.closed'
1443 notice = _(b' (closed)')
1443 notice = _(b' (closed)')
1444 else:
1444 else:
1445 label = b'branches.inactive'
1445 label = b'branches.inactive'
1446 notice = _(b' (inactive)')
1446 notice = _(b' (inactive)')
1447 current = tag == repo.dirstate.branch()
1447 current = tag == repo.dirstate.branch()
1448 if current:
1448 if current:
1449 label = b'branches.current'
1449 label = b'branches.current'
1450
1450
1451 fm.startitem()
1451 fm.startitem()
1452 fm.write(b'branch', b'%s', tag, label=label)
1452 fm.write(b'branch', b'%s', tag, label=label)
1453 rev = ctx.rev()
1453 rev = ctx.rev()
1454 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1454 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1455 fmt = b' ' * padsize + b' %d:%s'
1455 fmt = b' ' * padsize + b' %d:%s'
1456 fm.condwrite(
1456 fm.condwrite(
1457 not ui.quiet,
1457 not ui.quiet,
1458 b'rev node',
1458 b'rev node',
1459 fmt,
1459 fmt,
1460 rev,
1460 rev,
1461 hexfunc(ctx.node()),
1461 hexfunc(ctx.node()),
1462 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1462 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1463 )
1463 )
1464 fm.context(ctx=ctx)
1464 fm.context(ctx=ctx)
1465 fm.data(active=isactive, closed=not isopen, current=current)
1465 fm.data(active=isactive, closed=not isopen, current=current)
1466 if not ui.quiet:
1466 if not ui.quiet:
1467 fm.plain(notice)
1467 fm.plain(notice)
1468 fm.plain(b'\n')
1468 fm.plain(b'\n')
1469 fm.end()
1469 fm.end()
1470
1470
1471
1471
1472 @command(
1472 @command(
1473 b'bundle',
1473 b'bundle',
1474 [
1474 [
1475 (
1475 (
1476 b'f',
1476 b'f',
1477 b'force',
1477 b'force',
1478 None,
1478 None,
1479 _(b'run even when the destination is unrelated'),
1479 _(b'run even when the destination is unrelated'),
1480 ),
1480 ),
1481 (
1481 (
1482 b'r',
1482 b'r',
1483 b'rev',
1483 b'rev',
1484 [],
1484 [],
1485 _(b'a changeset intended to be added to the destination'),
1485 _(b'a changeset intended to be added to the destination'),
1486 _(b'REV'),
1486 _(b'REV'),
1487 ),
1487 ),
1488 (
1488 (
1489 b'b',
1489 b'b',
1490 b'branch',
1490 b'branch',
1491 [],
1491 [],
1492 _(b'a specific branch you would like to bundle'),
1492 _(b'a specific branch you would like to bundle'),
1493 _(b'BRANCH'),
1493 _(b'BRANCH'),
1494 ),
1494 ),
1495 (
1495 (
1496 b'',
1496 b'',
1497 b'base',
1497 b'base',
1498 [],
1498 [],
1499 _(b'a base changeset assumed to be available at the destination'),
1499 _(b'a base changeset assumed to be available at the destination'),
1500 _(b'REV'),
1500 _(b'REV'),
1501 ),
1501 ),
1502 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1502 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1503 (
1503 (
1504 b't',
1504 b't',
1505 b'type',
1505 b'type',
1506 b'bzip2',
1506 b'bzip2',
1507 _(b'bundle compression type to use'),
1507 _(b'bundle compression type to use'),
1508 _(b'TYPE'),
1508 _(b'TYPE'),
1509 ),
1509 ),
1510 ]
1510 ]
1511 + remoteopts,
1511 + remoteopts,
1512 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1512 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1513 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1513 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1514 )
1514 )
1515 def bundle(ui, repo, fname, dest=None, **opts):
1515 def bundle(ui, repo, fname, dest=None, **opts):
1516 """create a bundle file
1516 """create a bundle file
1517
1517
1518 Generate a bundle file containing data to be transferred to another
1518 Generate a bundle file containing data to be transferred to another
1519 repository.
1519 repository.
1520
1520
1521 To create a bundle containing all changesets, use -a/--all
1521 To create a bundle containing all changesets, use -a/--all
1522 (or --base null). Otherwise, hg assumes the destination will have
1522 (or --base null). Otherwise, hg assumes the destination will have
1523 all the nodes you specify with --base parameters. Otherwise, hg
1523 all the nodes you specify with --base parameters. Otherwise, hg
1524 will assume the repository has all the nodes in destination, or
1524 will assume the repository has all the nodes in destination, or
1525 default-push/default if no destination is specified, where destination
1525 default-push/default if no destination is specified, where destination
1526 is the repository you provide through DEST option.
1526 is the repository you provide through DEST option.
1527
1527
1528 You can change bundle format with the -t/--type option. See
1528 You can change bundle format with the -t/--type option. See
1529 :hg:`help bundlespec` for documentation on this format. By default,
1529 :hg:`help bundlespec` for documentation on this format. By default,
1530 the most appropriate format is used and compression defaults to
1530 the most appropriate format is used and compression defaults to
1531 bzip2.
1531 bzip2.
1532
1532
1533 The bundle file can then be transferred using conventional means
1533 The bundle file can then be transferred using conventional means
1534 and applied to another repository with the unbundle or pull
1534 and applied to another repository with the unbundle or pull
1535 command. This is useful when direct push and pull are not
1535 command. This is useful when direct push and pull are not
1536 available or when exporting an entire repository is undesirable.
1536 available or when exporting an entire repository is undesirable.
1537
1537
1538 Applying bundles preserves all changeset contents including
1538 Applying bundles preserves all changeset contents including
1539 permissions, copy/rename information, and revision history.
1539 permissions, copy/rename information, and revision history.
1540
1540
1541 Returns 0 on success, 1 if no changes found.
1541 Returns 0 on success, 1 if no changes found.
1542 """
1542 """
1543 opts = pycompat.byteskwargs(opts)
1543 opts = pycompat.byteskwargs(opts)
1544 revs = None
1544 revs = None
1545 if b'rev' in opts:
1545 if b'rev' in opts:
1546 revstrings = opts[b'rev']
1546 revstrings = opts[b'rev']
1547 revs = scmutil.revrange(repo, revstrings)
1547 revs = scmutil.revrange(repo, revstrings)
1548 if revstrings and not revs:
1548 if revstrings and not revs:
1549 raise error.Abort(_(b'no commits to bundle'))
1549 raise error.Abort(_(b'no commits to bundle'))
1550
1550
1551 bundletype = opts.get(b'type', b'bzip2').lower()
1551 bundletype = opts.get(b'type', b'bzip2').lower()
1552 try:
1552 try:
1553 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1553 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1554 except error.UnsupportedBundleSpecification as e:
1554 except error.UnsupportedBundleSpecification as e:
1555 raise error.Abort(
1555 raise error.Abort(
1556 pycompat.bytestr(e),
1556 pycompat.bytestr(e),
1557 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1557 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1558 )
1558 )
1559 cgversion = bundlespec.contentopts[b"cg.version"]
1559 cgversion = bundlespec.contentopts[b"cg.version"]
1560
1560
1561 # Packed bundles are a pseudo bundle format for now.
1561 # Packed bundles are a pseudo bundle format for now.
1562 if cgversion == b's1':
1562 if cgversion == b's1':
1563 raise error.Abort(
1563 raise error.Abort(
1564 _(b'packed bundles cannot be produced by "hg bundle"'),
1564 _(b'packed bundles cannot be produced by "hg bundle"'),
1565 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1565 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1566 )
1566 )
1567
1567
1568 if opts.get(b'all'):
1568 if opts.get(b'all'):
1569 if dest:
1569 if dest:
1570 raise error.Abort(
1570 raise error.Abort(
1571 _(b"--all is incompatible with specifying a destination")
1571 _(b"--all is incompatible with specifying a destination")
1572 )
1572 )
1573 if opts.get(b'base'):
1573 if opts.get(b'base'):
1574 ui.warn(_(b"ignoring --base because --all was specified\n"))
1574 ui.warn(_(b"ignoring --base because --all was specified\n"))
1575 base = [nullrev]
1575 base = [nullrev]
1576 else:
1576 else:
1577 base = scmutil.revrange(repo, opts.get(b'base'))
1577 base = scmutil.revrange(repo, opts.get(b'base'))
1578 if cgversion not in changegroup.supportedoutgoingversions(repo):
1578 if cgversion not in changegroup.supportedoutgoingversions(repo):
1579 raise error.Abort(
1579 raise error.Abort(
1580 _(b"repository does not support bundle version %s") % cgversion
1580 _(b"repository does not support bundle version %s") % cgversion
1581 )
1581 )
1582
1582
1583 if base:
1583 if base:
1584 if dest:
1584 if dest:
1585 raise error.Abort(
1585 raise error.Abort(
1586 _(b"--base is incompatible with specifying a destination")
1586 _(b"--base is incompatible with specifying a destination")
1587 )
1587 )
1588 common = [repo[rev].node() for rev in base]
1588 common = [repo[rev].node() for rev in base]
1589 heads = [repo[r].node() for r in revs] if revs else None
1589 heads = [repo[r].node() for r in revs] if revs else None
1590 outgoing = discovery.outgoing(repo, common, heads)
1590 outgoing = discovery.outgoing(repo, common, heads)
1591 else:
1591 else:
1592 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1592 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1593 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1593 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1594 other = hg.peer(repo, opts, dest)
1594 other = hg.peer(repo, opts, dest)
1595 revs = [repo[r].hex() for r in revs]
1595 revs = [repo[r].hex() for r in revs]
1596 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1596 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1597 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1597 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1598 outgoing = discovery.findcommonoutgoing(
1598 outgoing = discovery.findcommonoutgoing(
1599 repo,
1599 repo,
1600 other,
1600 other,
1601 onlyheads=heads,
1601 onlyheads=heads,
1602 force=opts.get(b'force'),
1602 force=opts.get(b'force'),
1603 portable=True,
1603 portable=True,
1604 )
1604 )
1605
1605
1606 if not outgoing.missing:
1606 if not outgoing.missing:
1607 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1607 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1608 return 1
1608 return 1
1609
1609
1610 if cgversion == b'01': # bundle1
1610 if cgversion == b'01': # bundle1
1611 bversion = b'HG10' + bundlespec.wirecompression
1611 bversion = b'HG10' + bundlespec.wirecompression
1612 bcompression = None
1612 bcompression = None
1613 elif cgversion in (b'02', b'03'):
1613 elif cgversion in (b'02', b'03'):
1614 bversion = b'HG20'
1614 bversion = b'HG20'
1615 bcompression = bundlespec.wirecompression
1615 bcompression = bundlespec.wirecompression
1616 else:
1616 else:
1617 raise error.ProgrammingError(
1617 raise error.ProgrammingError(
1618 b'bundle: unexpected changegroup version %s' % cgversion
1618 b'bundle: unexpected changegroup version %s' % cgversion
1619 )
1619 )
1620
1620
1621 # TODO compression options should be derived from bundlespec parsing.
1621 # TODO compression options should be derived from bundlespec parsing.
1622 # This is a temporary hack to allow adjusting bundle compression
1622 # This is a temporary hack to allow adjusting bundle compression
1623 # level without a) formalizing the bundlespec changes to declare it
1623 # level without a) formalizing the bundlespec changes to declare it
1624 # b) introducing a command flag.
1624 # b) introducing a command flag.
1625 compopts = {}
1625 compopts = {}
1626 complevel = ui.configint(
1626 complevel = ui.configint(
1627 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1627 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1628 )
1628 )
1629 if complevel is None:
1629 if complevel is None:
1630 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1630 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1631 if complevel is not None:
1631 if complevel is not None:
1632 compopts[b'level'] = complevel
1632 compopts[b'level'] = complevel
1633
1633
1634 # Allow overriding the bundling of obsmarker in phases through
1634 # Allow overriding the bundling of obsmarker in phases through
1635 # configuration while we don't have a bundle version that include them
1635 # configuration while we don't have a bundle version that include them
1636 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1636 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1637 bundlespec.contentopts[b'obsolescence'] = True
1637 bundlespec.contentopts[b'obsolescence'] = True
1638 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1638 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1639 bundlespec.contentopts[b'phases'] = True
1639 bundlespec.contentopts[b'phases'] = True
1640
1640
1641 bundle2.writenewbundle(
1641 bundle2.writenewbundle(
1642 ui,
1642 ui,
1643 repo,
1643 repo,
1644 b'bundle',
1644 b'bundle',
1645 fname,
1645 fname,
1646 bversion,
1646 bversion,
1647 outgoing,
1647 outgoing,
1648 bundlespec.contentopts,
1648 bundlespec.contentopts,
1649 compression=bcompression,
1649 compression=bcompression,
1650 compopts=compopts,
1650 compopts=compopts,
1651 )
1651 )
1652
1652
1653
1653
1654 @command(
1654 @command(
1655 b'cat',
1655 b'cat',
1656 [
1656 [
1657 (
1657 (
1658 b'o',
1658 b'o',
1659 b'output',
1659 b'output',
1660 b'',
1660 b'',
1661 _(b'print output to file with formatted name'),
1661 _(b'print output to file with formatted name'),
1662 _(b'FORMAT'),
1662 _(b'FORMAT'),
1663 ),
1663 ),
1664 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1664 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1665 (b'', b'decode', None, _(b'apply any matching decode filter')),
1665 (b'', b'decode', None, _(b'apply any matching decode filter')),
1666 ]
1666 ]
1667 + walkopts
1667 + walkopts
1668 + formatteropts,
1668 + formatteropts,
1669 _(b'[OPTION]... FILE...'),
1669 _(b'[OPTION]... FILE...'),
1670 helpcategory=command.CATEGORY_FILE_CONTENTS,
1670 helpcategory=command.CATEGORY_FILE_CONTENTS,
1671 inferrepo=True,
1671 inferrepo=True,
1672 intents={INTENT_READONLY},
1672 intents={INTENT_READONLY},
1673 )
1673 )
1674 def cat(ui, repo, file1, *pats, **opts):
1674 def cat(ui, repo, file1, *pats, **opts):
1675 """output the current or given revision of files
1675 """output the current or given revision of files
1676
1676
1677 Print the specified files as they were at the given revision. If
1677 Print the specified files as they were at the given revision. If
1678 no revision is given, the parent of the working directory is used.
1678 no revision is given, the parent of the working directory is used.
1679
1679
1680 Output may be to a file, in which case the name of the file is
1680 Output may be to a file, in which case the name of the file is
1681 given using a template string. See :hg:`help templates`. In addition
1681 given using a template string. See :hg:`help templates`. In addition
1682 to the common template keywords, the following formatting rules are
1682 to the common template keywords, the following formatting rules are
1683 supported:
1683 supported:
1684
1684
1685 :``%%``: literal "%" character
1685 :``%%``: literal "%" character
1686 :``%s``: basename of file being printed
1686 :``%s``: basename of file being printed
1687 :``%d``: dirname of file being printed, or '.' if in repository root
1687 :``%d``: dirname of file being printed, or '.' if in repository root
1688 :``%p``: root-relative path name of file being printed
1688 :``%p``: root-relative path name of file being printed
1689 :``%H``: changeset hash (40 hexadecimal digits)
1689 :``%H``: changeset hash (40 hexadecimal digits)
1690 :``%R``: changeset revision number
1690 :``%R``: changeset revision number
1691 :``%h``: short-form changeset hash (12 hexadecimal digits)
1691 :``%h``: short-form changeset hash (12 hexadecimal digits)
1692 :``%r``: zero-padded changeset revision number
1692 :``%r``: zero-padded changeset revision number
1693 :``%b``: basename of the exporting repository
1693 :``%b``: basename of the exporting repository
1694 :``\\``: literal "\\" character
1694 :``\\``: literal "\\" character
1695
1695
1696 .. container:: verbose
1696 .. container:: verbose
1697
1697
1698 Template:
1698 Template:
1699
1699
1700 The following keywords are supported in addition to the common template
1700 The following keywords are supported in addition to the common template
1701 keywords and functions. See also :hg:`help templates`.
1701 keywords and functions. See also :hg:`help templates`.
1702
1702
1703 :data: String. File content.
1703 :data: String. File content.
1704 :path: String. Repository-absolute path of the file.
1704 :path: String. Repository-absolute path of the file.
1705
1705
1706 Returns 0 on success.
1706 Returns 0 on success.
1707 """
1707 """
1708 opts = pycompat.byteskwargs(opts)
1708 opts = pycompat.byteskwargs(opts)
1709 rev = opts.get(b'rev')
1709 rev = opts.get(b'rev')
1710 if rev:
1710 if rev:
1711 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1711 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1712 ctx = scmutil.revsingle(repo, rev)
1712 ctx = scmutil.revsingle(repo, rev)
1713 m = scmutil.match(ctx, (file1,) + pats, opts)
1713 m = scmutil.match(ctx, (file1,) + pats, opts)
1714 fntemplate = opts.pop(b'output', b'')
1714 fntemplate = opts.pop(b'output', b'')
1715 if cmdutil.isstdiofilename(fntemplate):
1715 if cmdutil.isstdiofilename(fntemplate):
1716 fntemplate = b''
1716 fntemplate = b''
1717
1717
1718 if fntemplate:
1718 if fntemplate:
1719 fm = formatter.nullformatter(ui, b'cat', opts)
1719 fm = formatter.nullformatter(ui, b'cat', opts)
1720 else:
1720 else:
1721 ui.pager(b'cat')
1721 ui.pager(b'cat')
1722 fm = ui.formatter(b'cat', opts)
1722 fm = ui.formatter(b'cat', opts)
1723 with fm:
1723 with fm:
1724 return cmdutil.cat(
1724 return cmdutil.cat(
1725 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1725 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1726 )
1726 )
1727
1727
1728
1728
1729 @command(
1729 @command(
1730 b'clone',
1730 b'clone',
1731 [
1731 [
1732 (
1732 (
1733 b'U',
1733 b'U',
1734 b'noupdate',
1734 b'noupdate',
1735 None,
1735 None,
1736 _(
1736 _(
1737 b'the clone will include an empty working '
1737 b'the clone will include an empty working '
1738 b'directory (only a repository)'
1738 b'directory (only a repository)'
1739 ),
1739 ),
1740 ),
1740 ),
1741 (
1741 (
1742 b'u',
1742 b'u',
1743 b'updaterev',
1743 b'updaterev',
1744 b'',
1744 b'',
1745 _(b'revision, tag, or branch to check out'),
1745 _(b'revision, tag, or branch to check out'),
1746 _(b'REV'),
1746 _(b'REV'),
1747 ),
1747 ),
1748 (
1748 (
1749 b'r',
1749 b'r',
1750 b'rev',
1750 b'rev',
1751 [],
1751 [],
1752 _(
1752 _(
1753 b'do not clone everything, but include this changeset'
1753 b'do not clone everything, but include this changeset'
1754 b' and its ancestors'
1754 b' and its ancestors'
1755 ),
1755 ),
1756 _(b'REV'),
1756 _(b'REV'),
1757 ),
1757 ),
1758 (
1758 (
1759 b'b',
1759 b'b',
1760 b'branch',
1760 b'branch',
1761 [],
1761 [],
1762 _(
1762 _(
1763 b'do not clone everything, but include this branch\'s'
1763 b'do not clone everything, but include this branch\'s'
1764 b' changesets and their ancestors'
1764 b' changesets and their ancestors'
1765 ),
1765 ),
1766 _(b'BRANCH'),
1766 _(b'BRANCH'),
1767 ),
1767 ),
1768 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1768 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1769 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1769 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1770 (b'', b'stream', None, _(b'clone with minimal data processing')),
1770 (b'', b'stream', None, _(b'clone with minimal data processing')),
1771 ]
1771 ]
1772 + remoteopts,
1772 + remoteopts,
1773 _(b'[OPTION]... SOURCE [DEST]'),
1773 _(b'[OPTION]... SOURCE [DEST]'),
1774 helpcategory=command.CATEGORY_REPO_CREATION,
1774 helpcategory=command.CATEGORY_REPO_CREATION,
1775 helpbasic=True,
1775 helpbasic=True,
1776 norepo=True,
1776 norepo=True,
1777 )
1777 )
1778 def clone(ui, source, dest=None, **opts):
1778 def clone(ui, source, dest=None, **opts):
1779 """make a copy of an existing repository
1779 """make a copy of an existing repository
1780
1780
1781 Create a copy of an existing repository in a new directory.
1781 Create a copy of an existing repository in a new directory.
1782
1782
1783 If no destination directory name is specified, it defaults to the
1783 If no destination directory name is specified, it defaults to the
1784 basename of the source.
1784 basename of the source.
1785
1785
1786 The location of the source is added to the new repository's
1786 The location of the source is added to the new repository's
1787 ``.hg/hgrc`` file, as the default to be used for future pulls.
1787 ``.hg/hgrc`` file, as the default to be used for future pulls.
1788
1788
1789 Only local paths and ``ssh://`` URLs are supported as
1789 Only local paths and ``ssh://`` URLs are supported as
1790 destinations. For ``ssh://`` destinations, no working directory or
1790 destinations. For ``ssh://`` destinations, no working directory or
1791 ``.hg/hgrc`` will be created on the remote side.
1791 ``.hg/hgrc`` will be created on the remote side.
1792
1792
1793 If the source repository has a bookmark called '@' set, that
1793 If the source repository has a bookmark called '@' set, that
1794 revision will be checked out in the new repository by default.
1794 revision will be checked out in the new repository by default.
1795
1795
1796 To check out a particular version, use -u/--update, or
1796 To check out a particular version, use -u/--update, or
1797 -U/--noupdate to create a clone with no working directory.
1797 -U/--noupdate to create a clone with no working directory.
1798
1798
1799 To pull only a subset of changesets, specify one or more revisions
1799 To pull only a subset of changesets, specify one or more revisions
1800 identifiers with -r/--rev or branches with -b/--branch. The
1800 identifiers with -r/--rev or branches with -b/--branch. The
1801 resulting clone will contain only the specified changesets and
1801 resulting clone will contain only the specified changesets and
1802 their ancestors. These options (or 'clone src#rev dest') imply
1802 their ancestors. These options (or 'clone src#rev dest') imply
1803 --pull, even for local source repositories.
1803 --pull, even for local source repositories.
1804
1804
1805 In normal clone mode, the remote normalizes repository data into a common
1805 In normal clone mode, the remote normalizes repository data into a common
1806 exchange format and the receiving end translates this data into its local
1806 exchange format and the receiving end translates this data into its local
1807 storage format. --stream activates a different clone mode that essentially
1807 storage format. --stream activates a different clone mode that essentially
1808 copies repository files from the remote with minimal data processing. This
1808 copies repository files from the remote with minimal data processing. This
1809 significantly reduces the CPU cost of a clone both remotely and locally.
1809 significantly reduces the CPU cost of a clone both remotely and locally.
1810 However, it often increases the transferred data size by 30-40%. This can
1810 However, it often increases the transferred data size by 30-40%. This can
1811 result in substantially faster clones where I/O throughput is plentiful,
1811 result in substantially faster clones where I/O throughput is plentiful,
1812 especially for larger repositories. A side-effect of --stream clones is
1812 especially for larger repositories. A side-effect of --stream clones is
1813 that storage settings and requirements on the remote are applied locally:
1813 that storage settings and requirements on the remote are applied locally:
1814 a modern client may inherit legacy or inefficient storage used by the
1814 a modern client may inherit legacy or inefficient storage used by the
1815 remote or a legacy Mercurial client may not be able to clone from a
1815 remote or a legacy Mercurial client may not be able to clone from a
1816 modern Mercurial remote.
1816 modern Mercurial remote.
1817
1817
1818 .. note::
1818 .. note::
1819
1819
1820 Specifying a tag will include the tagged changeset but not the
1820 Specifying a tag will include the tagged changeset but not the
1821 changeset containing the tag.
1821 changeset containing the tag.
1822
1822
1823 .. container:: verbose
1823 .. container:: verbose
1824
1824
1825 For efficiency, hardlinks are used for cloning whenever the
1825 For efficiency, hardlinks are used for cloning whenever the
1826 source and destination are on the same filesystem (note this
1826 source and destination are on the same filesystem (note this
1827 applies only to the repository data, not to the working
1827 applies only to the repository data, not to the working
1828 directory). Some filesystems, such as AFS, implement hardlinking
1828 directory). Some filesystems, such as AFS, implement hardlinking
1829 incorrectly, but do not report errors. In these cases, use the
1829 incorrectly, but do not report errors. In these cases, use the
1830 --pull option to avoid hardlinking.
1830 --pull option to avoid hardlinking.
1831
1831
1832 Mercurial will update the working directory to the first applicable
1832 Mercurial will update the working directory to the first applicable
1833 revision from this list:
1833 revision from this list:
1834
1834
1835 a) null if -U or the source repository has no changesets
1835 a) null if -U or the source repository has no changesets
1836 b) if -u . and the source repository is local, the first parent of
1836 b) if -u . and the source repository is local, the first parent of
1837 the source repository's working directory
1837 the source repository's working directory
1838 c) the changeset specified with -u (if a branch name, this means the
1838 c) the changeset specified with -u (if a branch name, this means the
1839 latest head of that branch)
1839 latest head of that branch)
1840 d) the changeset specified with -r
1840 d) the changeset specified with -r
1841 e) the tipmost head specified with -b
1841 e) the tipmost head specified with -b
1842 f) the tipmost head specified with the url#branch source syntax
1842 f) the tipmost head specified with the url#branch source syntax
1843 g) the revision marked with the '@' bookmark, if present
1843 g) the revision marked with the '@' bookmark, if present
1844 h) the tipmost head of the default branch
1844 h) the tipmost head of the default branch
1845 i) tip
1845 i) tip
1846
1846
1847 When cloning from servers that support it, Mercurial may fetch
1847 When cloning from servers that support it, Mercurial may fetch
1848 pre-generated data from a server-advertised URL or inline from the
1848 pre-generated data from a server-advertised URL or inline from the
1849 same stream. When this is done, hooks operating on incoming changesets
1849 same stream. When this is done, hooks operating on incoming changesets
1850 and changegroups may fire more than once, once for each pre-generated
1850 and changegroups may fire more than once, once for each pre-generated
1851 bundle and as well as for any additional remaining data. In addition,
1851 bundle and as well as for any additional remaining data. In addition,
1852 if an error occurs, the repository may be rolled back to a partial
1852 if an error occurs, the repository may be rolled back to a partial
1853 clone. This behavior may change in future releases.
1853 clone. This behavior may change in future releases.
1854 See :hg:`help -e clonebundles` for more.
1854 See :hg:`help -e clonebundles` for more.
1855
1855
1856 Examples:
1856 Examples:
1857
1857
1858 - clone a remote repository to a new directory named hg/::
1858 - clone a remote repository to a new directory named hg/::
1859
1859
1860 hg clone https://www.mercurial-scm.org/repo/hg/
1860 hg clone https://www.mercurial-scm.org/repo/hg/
1861
1861
1862 - create a lightweight local clone::
1862 - create a lightweight local clone::
1863
1863
1864 hg clone project/ project-feature/
1864 hg clone project/ project-feature/
1865
1865
1866 - clone from an absolute path on an ssh server (note double-slash)::
1866 - clone from an absolute path on an ssh server (note double-slash)::
1867
1867
1868 hg clone ssh://user@server//home/projects/alpha/
1868 hg clone ssh://user@server//home/projects/alpha/
1869
1869
1870 - do a streaming clone while checking out a specified version::
1870 - do a streaming clone while checking out a specified version::
1871
1871
1872 hg clone --stream http://server/repo -u 1.5
1872 hg clone --stream http://server/repo -u 1.5
1873
1873
1874 - create a repository without changesets after a particular revision::
1874 - create a repository without changesets after a particular revision::
1875
1875
1876 hg clone -r 04e544 experimental/ good/
1876 hg clone -r 04e544 experimental/ good/
1877
1877
1878 - clone (and track) a particular named branch::
1878 - clone (and track) a particular named branch::
1879
1879
1880 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1880 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1881
1881
1882 See :hg:`help urls` for details on specifying URLs.
1882 See :hg:`help urls` for details on specifying URLs.
1883
1883
1884 Returns 0 on success.
1884 Returns 0 on success.
1885 """
1885 """
1886 opts = pycompat.byteskwargs(opts)
1886 opts = pycompat.byteskwargs(opts)
1887 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1887 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1888
1888
1889 # --include/--exclude can come from narrow or sparse.
1889 # --include/--exclude can come from narrow or sparse.
1890 includepats, excludepats = None, None
1890 includepats, excludepats = None, None
1891
1891
1892 # hg.clone() differentiates between None and an empty set. So make sure
1892 # hg.clone() differentiates between None and an empty set. So make sure
1893 # patterns are sets if narrow is requested without patterns.
1893 # patterns are sets if narrow is requested without patterns.
1894 if opts.get(b'narrow'):
1894 if opts.get(b'narrow'):
1895 includepats = set()
1895 includepats = set()
1896 excludepats = set()
1896 excludepats = set()
1897
1897
1898 if opts.get(b'include'):
1898 if opts.get(b'include'):
1899 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1899 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1900 if opts.get(b'exclude'):
1900 if opts.get(b'exclude'):
1901 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1901 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1902
1902
1903 r = hg.clone(
1903 r = hg.clone(
1904 ui,
1904 ui,
1905 opts,
1905 opts,
1906 source,
1906 source,
1907 dest,
1907 dest,
1908 pull=opts.get(b'pull'),
1908 pull=opts.get(b'pull'),
1909 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1909 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1910 revs=opts.get(b'rev'),
1910 revs=opts.get(b'rev'),
1911 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1911 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1912 branch=opts.get(b'branch'),
1912 branch=opts.get(b'branch'),
1913 shareopts=opts.get(b'shareopts'),
1913 shareopts=opts.get(b'shareopts'),
1914 storeincludepats=includepats,
1914 storeincludepats=includepats,
1915 storeexcludepats=excludepats,
1915 storeexcludepats=excludepats,
1916 depth=opts.get(b'depth') or None,
1916 depth=opts.get(b'depth') or None,
1917 )
1917 )
1918
1918
1919 return r is None
1919 return r is None
1920
1920
1921
1921
1922 @command(
1922 @command(
1923 b'commit|ci',
1923 b'commit|ci',
1924 [
1924 [
1925 (
1925 (
1926 b'A',
1926 b'A',
1927 b'addremove',
1927 b'addremove',
1928 None,
1928 None,
1929 _(b'mark new/missing files as added/removed before committing'),
1929 _(b'mark new/missing files as added/removed before committing'),
1930 ),
1930 ),
1931 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1931 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1932 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1932 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1933 (b's', b'secret', None, _(b'use the secret phase for committing')),
1933 (b's', b'secret', None, _(b'use the secret phase for committing')),
1934 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1934 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1935 (
1935 (
1936 b'',
1936 b'',
1937 b'force-close-branch',
1937 b'force-close-branch',
1938 None,
1938 None,
1939 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1939 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1940 ),
1940 ),
1941 (b'i', b'interactive', None, _(b'use interactive mode')),
1941 (b'i', b'interactive', None, _(b'use interactive mode')),
1942 ]
1942 ]
1943 + walkopts
1943 + walkopts
1944 + commitopts
1944 + commitopts
1945 + commitopts2
1945 + commitopts2
1946 + subrepoopts,
1946 + subrepoopts,
1947 _(b'[OPTION]... [FILE]...'),
1947 _(b'[OPTION]... [FILE]...'),
1948 helpcategory=command.CATEGORY_COMMITTING,
1948 helpcategory=command.CATEGORY_COMMITTING,
1949 helpbasic=True,
1949 helpbasic=True,
1950 inferrepo=True,
1950 inferrepo=True,
1951 )
1951 )
1952 def commit(ui, repo, *pats, **opts):
1952 def commit(ui, repo, *pats, **opts):
1953 """commit the specified files or all outstanding changes
1953 """commit the specified files or all outstanding changes
1954
1954
1955 Commit changes to the given files into the repository. Unlike a
1955 Commit changes to the given files into the repository. Unlike a
1956 centralized SCM, this operation is a local operation. See
1956 centralized SCM, this operation is a local operation. See
1957 :hg:`push` for a way to actively distribute your changes.
1957 :hg:`push` for a way to actively distribute your changes.
1958
1958
1959 If a list of files is omitted, all changes reported by :hg:`status`
1959 If a list of files is omitted, all changes reported by :hg:`status`
1960 will be committed.
1960 will be committed.
1961
1961
1962 If you are committing the result of a merge, do not provide any
1962 If you are committing the result of a merge, do not provide any
1963 filenames or -I/-X filters.
1963 filenames or -I/-X filters.
1964
1964
1965 If no commit message is specified, Mercurial starts your
1965 If no commit message is specified, Mercurial starts your
1966 configured editor where you can enter a message. In case your
1966 configured editor where you can enter a message. In case your
1967 commit fails, you will find a backup of your message in
1967 commit fails, you will find a backup of your message in
1968 ``.hg/last-message.txt``.
1968 ``.hg/last-message.txt``.
1969
1969
1970 The --close-branch flag can be used to mark the current branch
1970 The --close-branch flag can be used to mark the current branch
1971 head closed. When all heads of a branch are closed, the branch
1971 head closed. When all heads of a branch are closed, the branch
1972 will be considered closed and no longer listed.
1972 will be considered closed and no longer listed.
1973
1973
1974 The --amend flag can be used to amend the parent of the
1974 The --amend flag can be used to amend the parent of the
1975 working directory with a new commit that contains the changes
1975 working directory with a new commit that contains the changes
1976 in the parent in addition to those currently reported by :hg:`status`,
1976 in the parent in addition to those currently reported by :hg:`status`,
1977 if there are any. The old commit is stored in a backup bundle in
1977 if there are any. The old commit is stored in a backup bundle in
1978 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1978 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1979 on how to restore it).
1979 on how to restore it).
1980
1980
1981 Message, user and date are taken from the amended commit unless
1981 Message, user and date are taken from the amended commit unless
1982 specified. When a message isn't specified on the command line,
1982 specified. When a message isn't specified on the command line,
1983 the editor will open with the message of the amended commit.
1983 the editor will open with the message of the amended commit.
1984
1984
1985 It is not possible to amend public changesets (see :hg:`help phases`)
1985 It is not possible to amend public changesets (see :hg:`help phases`)
1986 or changesets that have children.
1986 or changesets that have children.
1987
1987
1988 See :hg:`help dates` for a list of formats valid for -d/--date.
1988 See :hg:`help dates` for a list of formats valid for -d/--date.
1989
1989
1990 Returns 0 on success, 1 if nothing changed.
1990 Returns 0 on success, 1 if nothing changed.
1991
1991
1992 .. container:: verbose
1992 .. container:: verbose
1993
1993
1994 Examples:
1994 Examples:
1995
1995
1996 - commit all files ending in .py::
1996 - commit all files ending in .py::
1997
1997
1998 hg commit --include "set:**.py"
1998 hg commit --include "set:**.py"
1999
1999
2000 - commit all non-binary files::
2000 - commit all non-binary files::
2001
2001
2002 hg commit --exclude "set:binary()"
2002 hg commit --exclude "set:binary()"
2003
2003
2004 - amend the current commit and set the date to now::
2004 - amend the current commit and set the date to now::
2005
2005
2006 hg commit --amend --date now
2006 hg commit --amend --date now
2007 """
2007 """
2008 with repo.wlock(), repo.lock():
2008 with repo.wlock(), repo.lock():
2009 return _docommit(ui, repo, *pats, **opts)
2009 return _docommit(ui, repo, *pats, **opts)
2010
2010
2011
2011
2012 def _docommit(ui, repo, *pats, **opts):
2012 def _docommit(ui, repo, *pats, **opts):
2013 if opts.get('interactive'):
2013 if opts.get('interactive'):
2014 opts.pop('interactive')
2014 opts.pop('interactive')
2015 ret = cmdutil.dorecord(
2015 ret = cmdutil.dorecord(
2016 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2016 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2017 )
2017 )
2018 # ret can be 0 (no changes to record) or the value returned by
2018 # ret can be 0 (no changes to record) or the value returned by
2019 # commit(), 1 if nothing changed or None on success.
2019 # commit(), 1 if nothing changed or None on success.
2020 return 1 if ret == 0 else ret
2020 return 1 if ret == 0 else ret
2021
2021
2022 opts = pycompat.byteskwargs(opts)
2022 opts = pycompat.byteskwargs(opts)
2023 if opts.get(b'subrepos'):
2023 if opts.get(b'subrepos'):
2024 if opts.get(b'amend'):
2024 if opts.get(b'amend'):
2025 raise error.Abort(_(b'cannot amend with --subrepos'))
2025 raise error.Abort(_(b'cannot amend with --subrepos'))
2026 # Let --subrepos on the command line override config setting.
2026 # Let --subrepos on the command line override config setting.
2027 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2027 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2028
2028
2029 cmdutil.checkunfinished(repo, commit=True)
2029 cmdutil.checkunfinished(repo, commit=True)
2030
2030
2031 branch = repo[None].branch()
2031 branch = repo[None].branch()
2032 bheads = repo.branchheads(branch)
2032 bheads = repo.branchheads(branch)
2033
2033
2034 extra = {}
2034 extra = {}
2035 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2035 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2036 extra[b'close'] = b'1'
2036 extra[b'close'] = b'1'
2037
2037
2038 if repo[b'.'].closesbranch():
2038 if repo[b'.'].closesbranch():
2039 raise error.Abort(
2039 raise error.Abort(
2040 _(b'current revision is already a branch closing head')
2040 _(b'current revision is already a branch closing head')
2041 )
2041 )
2042 elif not bheads:
2042 elif not bheads:
2043 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2043 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2044 elif (
2044 elif (
2045 branch == repo[b'.'].branch()
2045 branch == repo[b'.'].branch()
2046 and repo[b'.'].node() not in bheads
2046 and repo[b'.'].node() not in bheads
2047 and not opts.get(b'force_close_branch')
2047 and not opts.get(b'force_close_branch')
2048 ):
2048 ):
2049 hint = _(
2049 hint = _(
2050 b'use --force-close-branch to close branch from a non-head'
2050 b'use --force-close-branch to close branch from a non-head'
2051 b' changeset'
2051 b' changeset'
2052 )
2052 )
2053 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2053 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2054 elif opts.get(b'amend'):
2054 elif opts.get(b'amend'):
2055 if (
2055 if (
2056 repo[b'.'].p1().branch() != branch
2056 repo[b'.'].p1().branch() != branch
2057 and repo[b'.'].p2().branch() != branch
2057 and repo[b'.'].p2().branch() != branch
2058 ):
2058 ):
2059 raise error.Abort(_(b'can only close branch heads'))
2059 raise error.Abort(_(b'can only close branch heads'))
2060
2060
2061 if opts.get(b'amend'):
2061 if opts.get(b'amend'):
2062 if ui.configbool(b'ui', b'commitsubrepos'):
2062 if ui.configbool(b'ui', b'commitsubrepos'):
2063 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2063 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2064
2064
2065 old = repo[b'.']
2065 old = repo[b'.']
2066 rewriteutil.precheck(repo, [old.rev()], b'amend')
2066 rewriteutil.precheck(repo, [old.rev()], b'amend')
2067
2067
2068 # Currently histedit gets confused if an amend happens while histedit
2068 # Currently histedit gets confused if an amend happens while histedit
2069 # is in progress. Since we have a checkunfinished command, we are
2069 # is in progress. Since we have a checkunfinished command, we are
2070 # temporarily honoring it.
2070 # temporarily honoring it.
2071 #
2071 #
2072 # Note: eventually this guard will be removed. Please do not expect
2072 # Note: eventually this guard will be removed. Please do not expect
2073 # this behavior to remain.
2073 # this behavior to remain.
2074 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2074 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2075 cmdutil.checkunfinished(repo)
2075 cmdutil.checkunfinished(repo)
2076
2076
2077 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2077 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2078 if node == old.node():
2078 if node == old.node():
2079 ui.status(_(b"nothing changed\n"))
2079 ui.status(_(b"nothing changed\n"))
2080 return 1
2080 return 1
2081 else:
2081 else:
2082
2082
2083 def commitfunc(ui, repo, message, match, opts):
2083 def commitfunc(ui, repo, message, match, opts):
2084 overrides = {}
2084 overrides = {}
2085 if opts.get(b'secret'):
2085 if opts.get(b'secret'):
2086 overrides[(b'phases', b'new-commit')] = b'secret'
2086 overrides[(b'phases', b'new-commit')] = b'secret'
2087
2087
2088 baseui = repo.baseui
2088 baseui = repo.baseui
2089 with baseui.configoverride(overrides, b'commit'):
2089 with baseui.configoverride(overrides, b'commit'):
2090 with ui.configoverride(overrides, b'commit'):
2090 with ui.configoverride(overrides, b'commit'):
2091 editform = cmdutil.mergeeditform(
2091 editform = cmdutil.mergeeditform(
2092 repo[None], b'commit.normal'
2092 repo[None], b'commit.normal'
2093 )
2093 )
2094 editor = cmdutil.getcommiteditor(
2094 editor = cmdutil.getcommiteditor(
2095 editform=editform, **pycompat.strkwargs(opts)
2095 editform=editform, **pycompat.strkwargs(opts)
2096 )
2096 )
2097 return repo.commit(
2097 return repo.commit(
2098 message,
2098 message,
2099 opts.get(b'user'),
2099 opts.get(b'user'),
2100 opts.get(b'date'),
2100 opts.get(b'date'),
2101 match,
2101 match,
2102 editor=editor,
2102 editor=editor,
2103 extra=extra,
2103 extra=extra,
2104 )
2104 )
2105
2105
2106 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2106 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2107
2107
2108 if not node:
2108 if not node:
2109 stat = cmdutil.postcommitstatus(repo, pats, opts)
2109 stat = cmdutil.postcommitstatus(repo, pats, opts)
2110 if stat.deleted:
2110 if stat.deleted:
2111 ui.status(
2111 ui.status(
2112 _(
2112 _(
2113 b"nothing changed (%d missing files, see "
2113 b"nothing changed (%d missing files, see "
2114 b"'hg status')\n"
2114 b"'hg status')\n"
2115 )
2115 )
2116 % len(stat.deleted)
2116 % len(stat.deleted)
2117 )
2117 )
2118 else:
2118 else:
2119 ui.status(_(b"nothing changed\n"))
2119 ui.status(_(b"nothing changed\n"))
2120 return 1
2120 return 1
2121
2121
2122 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2122 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2123
2123
2124 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2124 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2125 status(
2125 status(
2126 ui,
2126 ui,
2127 repo,
2127 repo,
2128 modified=True,
2128 modified=True,
2129 added=True,
2129 added=True,
2130 removed=True,
2130 removed=True,
2131 deleted=True,
2131 deleted=True,
2132 unknown=True,
2132 unknown=True,
2133 subrepos=opts.get(b'subrepos'),
2133 subrepos=opts.get(b'subrepos'),
2134 )
2134 )
2135
2135
2136
2136
2137 @command(
2137 @command(
2138 b'config|showconfig|debugconfig',
2138 b'config|showconfig|debugconfig',
2139 [
2139 [
2140 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2140 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2141 (b'e', b'edit', None, _(b'edit user config')),
2141 (b'e', b'edit', None, _(b'edit user config')),
2142 (b'l', b'local', None, _(b'edit repository config')),
2142 (b'l', b'local', None, _(b'edit repository config')),
2143 (b'g', b'global', None, _(b'edit global config')),
2143 (b'g', b'global', None, _(b'edit global config')),
2144 ]
2144 ]
2145 + formatteropts,
2145 + formatteropts,
2146 _(b'[-u] [NAME]...'),
2146 _(b'[-u] [NAME]...'),
2147 helpcategory=command.CATEGORY_HELP,
2147 helpcategory=command.CATEGORY_HELP,
2148 optionalrepo=True,
2148 optionalrepo=True,
2149 intents={INTENT_READONLY},
2149 intents={INTENT_READONLY},
2150 )
2150 )
2151 def config(ui, repo, *values, **opts):
2151 def config(ui, repo, *values, **opts):
2152 """show combined config settings from all hgrc files
2152 """show combined config settings from all hgrc files
2153
2153
2154 With no arguments, print names and values of all config items.
2154 With no arguments, print names and values of all config items.
2155
2155
2156 With one argument of the form section.name, print just the value
2156 With one argument of the form section.name, print just the value
2157 of that config item.
2157 of that config item.
2158
2158
2159 With multiple arguments, print names and values of all config
2159 With multiple arguments, print names and values of all config
2160 items with matching section names or section.names.
2160 items with matching section names or section.names.
2161
2161
2162 With --edit, start an editor on the user-level config file. With
2162 With --edit, start an editor on the user-level config file. With
2163 --global, edit the system-wide config file. With --local, edit the
2163 --global, edit the system-wide config file. With --local, edit the
2164 repository-level config file.
2164 repository-level config file.
2165
2165
2166 With --debug, the source (filename and line number) is printed
2166 With --debug, the source (filename and line number) is printed
2167 for each config item.
2167 for each config item.
2168
2168
2169 See :hg:`help config` for more information about config files.
2169 See :hg:`help config` for more information about config files.
2170
2170
2171 .. container:: verbose
2171 .. container:: verbose
2172
2172
2173 Template:
2173 Template:
2174
2174
2175 The following keywords are supported. See also :hg:`help templates`.
2175 The following keywords are supported. See also :hg:`help templates`.
2176
2176
2177 :name: String. Config name.
2177 :name: String. Config name.
2178 :source: String. Filename and line number where the item is defined.
2178 :source: String. Filename and line number where the item is defined.
2179 :value: String. Config value.
2179 :value: String. Config value.
2180
2180
2181 Returns 0 on success, 1 if NAME does not exist.
2181 Returns 0 on success, 1 if NAME does not exist.
2182
2182
2183 """
2183 """
2184
2184
2185 opts = pycompat.byteskwargs(opts)
2185 opts = pycompat.byteskwargs(opts)
2186 if opts.get(b'edit') or opts.get(b'local') or opts.get(b'global'):
2186 if opts.get(b'edit') or opts.get(b'local') or opts.get(b'global'):
2187 if opts.get(b'local') and opts.get(b'global'):
2187 if opts.get(b'local') and opts.get(b'global'):
2188 raise error.Abort(_(b"can't use --local and --global together"))
2188 raise error.Abort(_(b"can't use --local and --global together"))
2189
2189
2190 if opts.get(b'local'):
2190 if opts.get(b'local'):
2191 if not repo:
2191 if not repo:
2192 raise error.Abort(_(b"can't use --local outside a repository"))
2192 raise error.Abort(_(b"can't use --local outside a repository"))
2193 paths = [repo.vfs.join(b'hgrc')]
2193 paths = [repo.vfs.join(b'hgrc')]
2194 elif opts.get(b'global'):
2194 elif opts.get(b'global'):
2195 paths = rcutil.systemrcpath()
2195 paths = rcutil.systemrcpath()
2196 else:
2196 else:
2197 paths = rcutil.userrcpath()
2197 paths = rcutil.userrcpath()
2198
2198
2199 for f in paths:
2199 for f in paths:
2200 if os.path.exists(f):
2200 if os.path.exists(f):
2201 break
2201 break
2202 else:
2202 else:
2203 if opts.get(b'global'):
2203 if opts.get(b'global'):
2204 samplehgrc = uimod.samplehgrcs[b'global']
2204 samplehgrc = uimod.samplehgrcs[b'global']
2205 elif opts.get(b'local'):
2205 elif opts.get(b'local'):
2206 samplehgrc = uimod.samplehgrcs[b'local']
2206 samplehgrc = uimod.samplehgrcs[b'local']
2207 else:
2207 else:
2208 samplehgrc = uimod.samplehgrcs[b'user']
2208 samplehgrc = uimod.samplehgrcs[b'user']
2209
2209
2210 f = paths[0]
2210 f = paths[0]
2211 fp = open(f, b"wb")
2211 fp = open(f, b"wb")
2212 fp.write(util.tonativeeol(samplehgrc))
2212 fp.write(util.tonativeeol(samplehgrc))
2213 fp.close()
2213 fp.close()
2214
2214
2215 editor = ui.geteditor()
2215 editor = ui.geteditor()
2216 ui.system(
2216 ui.system(
2217 b"%s \"%s\"" % (editor, f),
2217 b"%s \"%s\"" % (editor, f),
2218 onerr=error.Abort,
2218 onerr=error.Abort,
2219 errprefix=_(b"edit failed"),
2219 errprefix=_(b"edit failed"),
2220 blockedtag=b'config_edit',
2220 blockedtag=b'config_edit',
2221 )
2221 )
2222 return
2222 return
2223 ui.pager(b'config')
2223 ui.pager(b'config')
2224 fm = ui.formatter(b'config', opts)
2224 fm = ui.formatter(b'config', opts)
2225 for t, f in rcutil.rccomponents():
2225 for t, f in rcutil.rccomponents():
2226 if t == b'path':
2226 if t == b'path':
2227 ui.debug(b'read config from: %s\n' % f)
2227 ui.debug(b'read config from: %s\n' % f)
2228 elif t == b'resource':
2228 elif t == b'resource':
2229 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2229 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2230 elif t == b'items':
2230 elif t == b'items':
2231 # Don't print anything for 'items'.
2231 # Don't print anything for 'items'.
2232 pass
2232 pass
2233 else:
2233 else:
2234 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2234 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2235 untrusted = bool(opts.get(b'untrusted'))
2235 untrusted = bool(opts.get(b'untrusted'))
2236
2236
2237 selsections = selentries = []
2237 selsections = selentries = []
2238 if values:
2238 if values:
2239 selsections = [v for v in values if b'.' not in v]
2239 selsections = [v for v in values if b'.' not in v]
2240 selentries = [v for v in values if b'.' in v]
2240 selentries = [v for v in values if b'.' in v]
2241 uniquesel = len(selentries) == 1 and not selsections
2241 uniquesel = len(selentries) == 1 and not selsections
2242 selsections = set(selsections)
2242 selsections = set(selsections)
2243 selentries = set(selentries)
2243 selentries = set(selentries)
2244
2244
2245 matched = False
2245 matched = False
2246 for section, name, value in ui.walkconfig(untrusted=untrusted):
2246 for section, name, value in ui.walkconfig(untrusted=untrusted):
2247 source = ui.configsource(section, name, untrusted)
2247 source = ui.configsource(section, name, untrusted)
2248 value = pycompat.bytestr(value)
2248 value = pycompat.bytestr(value)
2249 defaultvalue = ui.configdefault(section, name)
2249 defaultvalue = ui.configdefault(section, name)
2250 if fm.isplain():
2250 if fm.isplain():
2251 source = source or b'none'
2251 source = source or b'none'
2252 value = value.replace(b'\n', b'\\n')
2252 value = value.replace(b'\n', b'\\n')
2253 entryname = section + b'.' + name
2253 entryname = section + b'.' + name
2254 if values and not (section in selsections or entryname in selentries):
2254 if values and not (section in selsections or entryname in selentries):
2255 continue
2255 continue
2256 fm.startitem()
2256 fm.startitem()
2257 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2257 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2258 if uniquesel:
2258 if uniquesel:
2259 fm.data(name=entryname)
2259 fm.data(name=entryname)
2260 fm.write(b'value', b'%s\n', value)
2260 fm.write(b'value', b'%s\n', value)
2261 else:
2261 else:
2262 fm.write(b'name value', b'%s=%s\n', entryname, value)
2262 fm.write(b'name value', b'%s=%s\n', entryname, value)
2263 if formatter.isprintable(defaultvalue):
2263 if formatter.isprintable(defaultvalue):
2264 fm.data(defaultvalue=defaultvalue)
2264 fm.data(defaultvalue=defaultvalue)
2265 elif isinstance(defaultvalue, list) and all(
2265 elif isinstance(defaultvalue, list) and all(
2266 formatter.isprintable(e) for e in defaultvalue
2266 formatter.isprintable(e) for e in defaultvalue
2267 ):
2267 ):
2268 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2268 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2269 # TODO: no idea how to process unsupported defaultvalue types
2269 # TODO: no idea how to process unsupported defaultvalue types
2270 matched = True
2270 matched = True
2271 fm.end()
2271 fm.end()
2272 if matched:
2272 if matched:
2273 return 0
2273 return 0
2274 return 1
2274 return 1
2275
2275
2276
2276
2277 @command(
2277 @command(
2278 b'continue',
2278 b'continue',
2279 dryrunopts,
2279 dryrunopts,
2280 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2280 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2281 helpbasic=True,
2281 helpbasic=True,
2282 )
2282 )
2283 def continuecmd(ui, repo, **opts):
2283 def continuecmd(ui, repo, **opts):
2284 """resumes an interrupted operation (EXPERIMENTAL)
2284 """resumes an interrupted operation (EXPERIMENTAL)
2285
2285
2286 Finishes a multistep operation like graft, histedit, rebase, merge,
2286 Finishes a multistep operation like graft, histedit, rebase, merge,
2287 and unshelve if they are in an interrupted state.
2287 and unshelve if they are in an interrupted state.
2288
2288
2289 use --dry-run/-n to dry run the command.
2289 use --dry-run/-n to dry run the command.
2290 """
2290 """
2291 dryrun = opts.get('dry_run')
2291 dryrun = opts.get('dry_run')
2292 contstate = cmdutil.getunfinishedstate(repo)
2292 contstate = cmdutil.getunfinishedstate(repo)
2293 if not contstate:
2293 if not contstate:
2294 raise error.Abort(_(b'no operation in progress'))
2294 raise error.Abort(_(b'no operation in progress'))
2295 if not contstate.continuefunc:
2295 if not contstate.continuefunc:
2296 raise error.Abort(
2296 raise error.Abort(
2297 (
2297 (
2298 _(b"%s in progress but does not support 'hg continue'")
2298 _(b"%s in progress but does not support 'hg continue'")
2299 % (contstate._opname)
2299 % (contstate._opname)
2300 ),
2300 ),
2301 hint=contstate.continuemsg(),
2301 hint=contstate.continuemsg(),
2302 )
2302 )
2303 if dryrun:
2303 if dryrun:
2304 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2304 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2305 return
2305 return
2306 return contstate.continuefunc(ui, repo)
2306 return contstate.continuefunc(ui, repo)
2307
2307
2308
2308
2309 @command(
2309 @command(
2310 b'copy|cp',
2310 b'copy|cp',
2311 [
2311 [
2312 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2312 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2313 (
2313 (
2314 b'f',
2314 b'f',
2315 b'force',
2315 b'force',
2316 None,
2316 None,
2317 _(b'forcibly copy over an existing managed file'),
2317 _(b'forcibly copy over an existing managed file'),
2318 ),
2318 ),
2319 ]
2319 ]
2320 + walkopts
2320 + walkopts
2321 + dryrunopts,
2321 + dryrunopts,
2322 _(b'[OPTION]... SOURCE... DEST'),
2322 _(b'[OPTION]... SOURCE... DEST'),
2323 helpcategory=command.CATEGORY_FILE_CONTENTS,
2323 helpcategory=command.CATEGORY_FILE_CONTENTS,
2324 )
2324 )
2325 def copy(ui, repo, *pats, **opts):
2325 def copy(ui, repo, *pats, **opts):
2326 """mark files as copied for the next commit
2326 """mark files as copied for the next commit
2327
2327
2328 Mark dest as having copies of source files. If dest is a
2328 Mark dest as having copies of source files. If dest is a
2329 directory, copies are put in that directory. If dest is a file,
2329 directory, copies are put in that directory. If dest is a file,
2330 the source must be a single file.
2330 the source must be a single file.
2331
2331
2332 By default, this command copies the contents of files as they
2332 By default, this command copies the contents of files as they
2333 exist in the working directory. If invoked with -A/--after, the
2333 exist in the working directory. If invoked with -A/--after, the
2334 operation is recorded, but no copying is performed.
2334 operation is recorded, but no copying is performed.
2335
2335
2336 This command takes effect with the next commit. To undo a copy
2336 This command takes effect with the next commit. To undo a copy
2337 before that, see :hg:`revert`.
2337 before that, see :hg:`revert`.
2338
2338
2339 Returns 0 on success, 1 if errors are encountered.
2339 Returns 0 on success, 1 if errors are encountered.
2340 """
2340 """
2341 opts = pycompat.byteskwargs(opts)
2341 opts = pycompat.byteskwargs(opts)
2342 with repo.wlock(False):
2342 with repo.wlock(False):
2343 return cmdutil.copy(ui, repo, pats, opts)
2343 return cmdutil.copy(ui, repo, pats, opts)
2344
2344
2345
2345
2346 @command(
2346 @command(
2347 b'debugcommands',
2347 b'debugcommands',
2348 [],
2348 [],
2349 _(b'[COMMAND]'),
2349 _(b'[COMMAND]'),
2350 helpcategory=command.CATEGORY_HELP,
2350 helpcategory=command.CATEGORY_HELP,
2351 norepo=True,
2351 norepo=True,
2352 )
2352 )
2353 def debugcommands(ui, cmd=b'', *args):
2353 def debugcommands(ui, cmd=b'', *args):
2354 """list all available commands and options"""
2354 """list all available commands and options"""
2355 for cmd, vals in sorted(pycompat.iteritems(table)):
2355 for cmd, vals in sorted(pycompat.iteritems(table)):
2356 cmd = cmd.split(b'|')[0]
2356 cmd = cmd.split(b'|')[0]
2357 opts = b', '.join([i[1] for i in vals[1]])
2357 opts = b', '.join([i[1] for i in vals[1]])
2358 ui.write(b'%s: %s\n' % (cmd, opts))
2358 ui.write(b'%s: %s\n' % (cmd, opts))
2359
2359
2360
2360
2361 @command(
2361 @command(
2362 b'debugcomplete',
2362 b'debugcomplete',
2363 [(b'o', b'options', None, _(b'show the command options'))],
2363 [(b'o', b'options', None, _(b'show the command options'))],
2364 _(b'[-o] CMD'),
2364 _(b'[-o] CMD'),
2365 helpcategory=command.CATEGORY_HELP,
2365 helpcategory=command.CATEGORY_HELP,
2366 norepo=True,
2366 norepo=True,
2367 )
2367 )
2368 def debugcomplete(ui, cmd=b'', **opts):
2368 def debugcomplete(ui, cmd=b'', **opts):
2369 """returns the completion list associated with the given command"""
2369 """returns the completion list associated with the given command"""
2370
2370
2371 if opts.get('options'):
2371 if opts.get('options'):
2372 options = []
2372 options = []
2373 otables = [globalopts]
2373 otables = [globalopts]
2374 if cmd:
2374 if cmd:
2375 aliases, entry = cmdutil.findcmd(cmd, table, False)
2375 aliases, entry = cmdutil.findcmd(cmd, table, False)
2376 otables.append(entry[1])
2376 otables.append(entry[1])
2377 for t in otables:
2377 for t in otables:
2378 for o in t:
2378 for o in t:
2379 if b"(DEPRECATED)" in o[3]:
2379 if b"(DEPRECATED)" in o[3]:
2380 continue
2380 continue
2381 if o[0]:
2381 if o[0]:
2382 options.append(b'-%s' % o[0])
2382 options.append(b'-%s' % o[0])
2383 options.append(b'--%s' % o[1])
2383 options.append(b'--%s' % o[1])
2384 ui.write(b"%s\n" % b"\n".join(options))
2384 ui.write(b"%s\n" % b"\n".join(options))
2385 return
2385 return
2386
2386
2387 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2387 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2388 if ui.verbose:
2388 if ui.verbose:
2389 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2389 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2390 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2390 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2391
2391
2392
2392
2393 @command(
2393 @command(
2394 b'diff',
2394 b'diff',
2395 [
2395 [
2396 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2396 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2397 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2397 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2398 ]
2398 ]
2399 + diffopts
2399 + diffopts
2400 + diffopts2
2400 + diffopts2
2401 + walkopts
2401 + walkopts
2402 + subrepoopts,
2402 + subrepoopts,
2403 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2403 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2404 helpcategory=command.CATEGORY_FILE_CONTENTS,
2404 helpcategory=command.CATEGORY_FILE_CONTENTS,
2405 helpbasic=True,
2405 helpbasic=True,
2406 inferrepo=True,
2406 inferrepo=True,
2407 intents={INTENT_READONLY},
2407 intents={INTENT_READONLY},
2408 )
2408 )
2409 def diff(ui, repo, *pats, **opts):
2409 def diff(ui, repo, *pats, **opts):
2410 """diff repository (or selected files)
2410 """diff repository (or selected files)
2411
2411
2412 Show differences between revisions for the specified files.
2412 Show differences between revisions for the specified files.
2413
2413
2414 Differences between files are shown using the unified diff format.
2414 Differences between files are shown using the unified diff format.
2415
2415
2416 .. note::
2416 .. note::
2417
2417
2418 :hg:`diff` may generate unexpected results for merges, as it will
2418 :hg:`diff` may generate unexpected results for merges, as it will
2419 default to comparing against the working directory's first
2419 default to comparing against the working directory's first
2420 parent changeset if no revisions are specified.
2420 parent changeset if no revisions are specified.
2421
2421
2422 When two revision arguments are given, then changes are shown
2422 When two revision arguments are given, then changes are shown
2423 between those revisions. If only one revision is specified then
2423 between those revisions. If only one revision is specified then
2424 that revision is compared to the working directory, and, when no
2424 that revision is compared to the working directory, and, when no
2425 revisions are specified, the working directory files are compared
2425 revisions are specified, the working directory files are compared
2426 to its first parent.
2426 to its first parent.
2427
2427
2428 Alternatively you can specify -c/--change with a revision to see
2428 Alternatively you can specify -c/--change with a revision to see
2429 the changes in that changeset relative to its first parent.
2429 the changes in that changeset relative to its first parent.
2430
2430
2431 Without the -a/--text option, diff will avoid generating diffs of
2431 Without the -a/--text option, diff will avoid generating diffs of
2432 files it detects as binary. With -a, diff will generate a diff
2432 files it detects as binary. With -a, diff will generate a diff
2433 anyway, probably with undesirable results.
2433 anyway, probably with undesirable results.
2434
2434
2435 Use the -g/--git option to generate diffs in the git extended diff
2435 Use the -g/--git option to generate diffs in the git extended diff
2436 format. For more information, read :hg:`help diffs`.
2436 format. For more information, read :hg:`help diffs`.
2437
2437
2438 .. container:: verbose
2438 .. container:: verbose
2439
2439
2440 Examples:
2440 Examples:
2441
2441
2442 - compare a file in the current working directory to its parent::
2442 - compare a file in the current working directory to its parent::
2443
2443
2444 hg diff foo.c
2444 hg diff foo.c
2445
2445
2446 - compare two historical versions of a directory, with rename info::
2446 - compare two historical versions of a directory, with rename info::
2447
2447
2448 hg diff --git -r 1.0:1.2 lib/
2448 hg diff --git -r 1.0:1.2 lib/
2449
2449
2450 - get change stats relative to the last change on some date::
2450 - get change stats relative to the last change on some date::
2451
2451
2452 hg diff --stat -r "date('may 2')"
2452 hg diff --stat -r "date('may 2')"
2453
2453
2454 - diff all newly-added files that contain a keyword::
2454 - diff all newly-added files that contain a keyword::
2455
2455
2456 hg diff "set:added() and grep(GNU)"
2456 hg diff "set:added() and grep(GNU)"
2457
2457
2458 - compare a revision and its parents::
2458 - compare a revision and its parents::
2459
2459
2460 hg diff -c 9353 # compare against first parent
2460 hg diff -c 9353 # compare against first parent
2461 hg diff -r 9353^:9353 # same using revset syntax
2461 hg diff -r 9353^:9353 # same using revset syntax
2462 hg diff -r 9353^2:9353 # compare against the second parent
2462 hg diff -r 9353^2:9353 # compare against the second parent
2463
2463
2464 Returns 0 on success.
2464 Returns 0 on success.
2465 """
2465 """
2466
2466
2467 opts = pycompat.byteskwargs(opts)
2467 opts = pycompat.byteskwargs(opts)
2468 revs = opts.get(b'rev')
2468 revs = opts.get(b'rev')
2469 change = opts.get(b'change')
2469 change = opts.get(b'change')
2470 stat = opts.get(b'stat')
2470 stat = opts.get(b'stat')
2471 reverse = opts.get(b'reverse')
2471 reverse = opts.get(b'reverse')
2472
2472
2473 if revs and change:
2473 if revs and change:
2474 msg = _(b'cannot specify --rev and --change at the same time')
2474 msg = _(b'cannot specify --rev and --change at the same time')
2475 raise error.Abort(msg)
2475 raise error.Abort(msg)
2476 elif change:
2476 elif change:
2477 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2477 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2478 ctx2 = scmutil.revsingle(repo, change, None)
2478 ctx2 = scmutil.revsingle(repo, change, None)
2479 ctx1 = ctx2.p1()
2479 ctx1 = ctx2.p1()
2480 else:
2480 else:
2481 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2481 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2482 ctx1, ctx2 = scmutil.revpair(repo, revs)
2482 ctx1, ctx2 = scmutil.revpair(repo, revs)
2483 node1, node2 = ctx1.node(), ctx2.node()
2483 node1, node2 = ctx1.node(), ctx2.node()
2484
2484
2485 if reverse:
2485 if reverse:
2486 node1, node2 = node2, node1
2486 node1, node2 = node2, node1
2487
2487
2488 diffopts = patch.diffallopts(ui, opts)
2488 diffopts = patch.diffallopts(ui, opts)
2489 m = scmutil.match(ctx2, pats, opts)
2489 m = scmutil.match(ctx2, pats, opts)
2490 m = repo.narrowmatch(m)
2490 m = repo.narrowmatch(m)
2491 ui.pager(b'diff')
2491 ui.pager(b'diff')
2492 logcmdutil.diffordiffstat(
2492 logcmdutil.diffordiffstat(
2493 ui,
2493 ui,
2494 repo,
2494 repo,
2495 diffopts,
2495 diffopts,
2496 node1,
2496 node1,
2497 node2,
2497 node2,
2498 m,
2498 m,
2499 stat=stat,
2499 stat=stat,
2500 listsubrepos=opts.get(b'subrepos'),
2500 listsubrepos=opts.get(b'subrepos'),
2501 root=opts.get(b'root'),
2501 root=opts.get(b'root'),
2502 )
2502 )
2503
2503
2504
2504
2505 @command(
2505 @command(
2506 b'export',
2506 b'export',
2507 [
2507 [
2508 (
2508 (
2509 b'B',
2509 b'B',
2510 b'bookmark',
2510 b'bookmark',
2511 b'',
2511 b'',
2512 _(b'export changes only reachable by given bookmark'),
2512 _(b'export changes only reachable by given bookmark'),
2513 _(b'BOOKMARK'),
2513 _(b'BOOKMARK'),
2514 ),
2514 ),
2515 (
2515 (
2516 b'o',
2516 b'o',
2517 b'output',
2517 b'output',
2518 b'',
2518 b'',
2519 _(b'print output to file with formatted name'),
2519 _(b'print output to file with formatted name'),
2520 _(b'FORMAT'),
2520 _(b'FORMAT'),
2521 ),
2521 ),
2522 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2522 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2523 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2523 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2524 ]
2524 ]
2525 + diffopts
2525 + diffopts
2526 + formatteropts,
2526 + formatteropts,
2527 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2527 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2528 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2528 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2529 helpbasic=True,
2529 helpbasic=True,
2530 intents={INTENT_READONLY},
2530 intents={INTENT_READONLY},
2531 )
2531 )
2532 def export(ui, repo, *changesets, **opts):
2532 def export(ui, repo, *changesets, **opts):
2533 """dump the header and diffs for one or more changesets
2533 """dump the header and diffs for one or more changesets
2534
2534
2535 Print the changeset header and diffs for one or more revisions.
2535 Print the changeset header and diffs for one or more revisions.
2536 If no revision is given, the parent of the working directory is used.
2536 If no revision is given, the parent of the working directory is used.
2537
2537
2538 The information shown in the changeset header is: author, date,
2538 The information shown in the changeset header is: author, date,
2539 branch name (if non-default), changeset hash, parent(s) and commit
2539 branch name (if non-default), changeset hash, parent(s) and commit
2540 comment.
2540 comment.
2541
2541
2542 .. note::
2542 .. note::
2543
2543
2544 :hg:`export` may generate unexpected diff output for merge
2544 :hg:`export` may generate unexpected diff output for merge
2545 changesets, as it will compare the merge changeset against its
2545 changesets, as it will compare the merge changeset against its
2546 first parent only.
2546 first parent only.
2547
2547
2548 Output may be to a file, in which case the name of the file is
2548 Output may be to a file, in which case the name of the file is
2549 given using a template string. See :hg:`help templates`. In addition
2549 given using a template string. See :hg:`help templates`. In addition
2550 to the common template keywords, the following formatting rules are
2550 to the common template keywords, the following formatting rules are
2551 supported:
2551 supported:
2552
2552
2553 :``%%``: literal "%" character
2553 :``%%``: literal "%" character
2554 :``%H``: changeset hash (40 hexadecimal digits)
2554 :``%H``: changeset hash (40 hexadecimal digits)
2555 :``%N``: number of patches being generated
2555 :``%N``: number of patches being generated
2556 :``%R``: changeset revision number
2556 :``%R``: changeset revision number
2557 :``%b``: basename of the exporting repository
2557 :``%b``: basename of the exporting repository
2558 :``%h``: short-form changeset hash (12 hexadecimal digits)
2558 :``%h``: short-form changeset hash (12 hexadecimal digits)
2559 :``%m``: first line of the commit message (only alphanumeric characters)
2559 :``%m``: first line of the commit message (only alphanumeric characters)
2560 :``%n``: zero-padded sequence number, starting at 1
2560 :``%n``: zero-padded sequence number, starting at 1
2561 :``%r``: zero-padded changeset revision number
2561 :``%r``: zero-padded changeset revision number
2562 :``\\``: literal "\\" character
2562 :``\\``: literal "\\" character
2563
2563
2564 Without the -a/--text option, export will avoid generating diffs
2564 Without the -a/--text option, export will avoid generating diffs
2565 of files it detects as binary. With -a, export will generate a
2565 of files it detects as binary. With -a, export will generate a
2566 diff anyway, probably with undesirable results.
2566 diff anyway, probably with undesirable results.
2567
2567
2568 With -B/--bookmark changesets reachable by the given bookmark are
2568 With -B/--bookmark changesets reachable by the given bookmark are
2569 selected.
2569 selected.
2570
2570
2571 Use the -g/--git option to generate diffs in the git extended diff
2571 Use the -g/--git option to generate diffs in the git extended diff
2572 format. See :hg:`help diffs` for more information.
2572 format. See :hg:`help diffs` for more information.
2573
2573
2574 With the --switch-parent option, the diff will be against the
2574 With the --switch-parent option, the diff will be against the
2575 second parent. It can be useful to review a merge.
2575 second parent. It can be useful to review a merge.
2576
2576
2577 .. container:: verbose
2577 .. container:: verbose
2578
2578
2579 Template:
2579 Template:
2580
2580
2581 The following keywords are supported in addition to the common template
2581 The following keywords are supported in addition to the common template
2582 keywords and functions. See also :hg:`help templates`.
2582 keywords and functions. See also :hg:`help templates`.
2583
2583
2584 :diff: String. Diff content.
2584 :diff: String. Diff content.
2585 :parents: List of strings. Parent nodes of the changeset.
2585 :parents: List of strings. Parent nodes of the changeset.
2586
2586
2587 Examples:
2587 Examples:
2588
2588
2589 - use export and import to transplant a bugfix to the current
2589 - use export and import to transplant a bugfix to the current
2590 branch::
2590 branch::
2591
2591
2592 hg export -r 9353 | hg import -
2592 hg export -r 9353 | hg import -
2593
2593
2594 - export all the changesets between two revisions to a file with
2594 - export all the changesets between two revisions to a file with
2595 rename information::
2595 rename information::
2596
2596
2597 hg export --git -r 123:150 > changes.txt
2597 hg export --git -r 123:150 > changes.txt
2598
2598
2599 - split outgoing changes into a series of patches with
2599 - split outgoing changes into a series of patches with
2600 descriptive names::
2600 descriptive names::
2601
2601
2602 hg export -r "outgoing()" -o "%n-%m.patch"
2602 hg export -r "outgoing()" -o "%n-%m.patch"
2603
2603
2604 Returns 0 on success.
2604 Returns 0 on success.
2605 """
2605 """
2606 opts = pycompat.byteskwargs(opts)
2606 opts = pycompat.byteskwargs(opts)
2607 bookmark = opts.get(b'bookmark')
2607 bookmark = opts.get(b'bookmark')
2608 changesets += tuple(opts.get(b'rev', []))
2608 changesets += tuple(opts.get(b'rev', []))
2609
2609
2610 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2610 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2611
2611
2612 if bookmark:
2612 if bookmark:
2613 if bookmark not in repo._bookmarks:
2613 if bookmark not in repo._bookmarks:
2614 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2614 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2615
2615
2616 revs = scmutil.bookmarkrevs(repo, bookmark)
2616 revs = scmutil.bookmarkrevs(repo, bookmark)
2617 else:
2617 else:
2618 if not changesets:
2618 if not changesets:
2619 changesets = [b'.']
2619 changesets = [b'.']
2620
2620
2621 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2621 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2622 revs = scmutil.revrange(repo, changesets)
2622 revs = scmutil.revrange(repo, changesets)
2623
2623
2624 if not revs:
2624 if not revs:
2625 raise error.Abort(_(b"export requires at least one changeset"))
2625 raise error.Abort(_(b"export requires at least one changeset"))
2626 if len(revs) > 1:
2626 if len(revs) > 1:
2627 ui.note(_(b'exporting patches:\n'))
2627 ui.note(_(b'exporting patches:\n'))
2628 else:
2628 else:
2629 ui.note(_(b'exporting patch:\n'))
2629 ui.note(_(b'exporting patch:\n'))
2630
2630
2631 fntemplate = opts.get(b'output')
2631 fntemplate = opts.get(b'output')
2632 if cmdutil.isstdiofilename(fntemplate):
2632 if cmdutil.isstdiofilename(fntemplate):
2633 fntemplate = b''
2633 fntemplate = b''
2634
2634
2635 if fntemplate:
2635 if fntemplate:
2636 fm = formatter.nullformatter(ui, b'export', opts)
2636 fm = formatter.nullformatter(ui, b'export', opts)
2637 else:
2637 else:
2638 ui.pager(b'export')
2638 ui.pager(b'export')
2639 fm = ui.formatter(b'export', opts)
2639 fm = ui.formatter(b'export', opts)
2640 with fm:
2640 with fm:
2641 cmdutil.export(
2641 cmdutil.export(
2642 repo,
2642 repo,
2643 revs,
2643 revs,
2644 fm,
2644 fm,
2645 fntemplate=fntemplate,
2645 fntemplate=fntemplate,
2646 switch_parent=opts.get(b'switch_parent'),
2646 switch_parent=opts.get(b'switch_parent'),
2647 opts=patch.diffallopts(ui, opts),
2647 opts=patch.diffallopts(ui, opts),
2648 )
2648 )
2649
2649
2650
2650
2651 @command(
2651 @command(
2652 b'files',
2652 b'files',
2653 [
2653 [
2654 (
2654 (
2655 b'r',
2655 b'r',
2656 b'rev',
2656 b'rev',
2657 b'',
2657 b'',
2658 _(b'search the repository as it is in REV'),
2658 _(b'search the repository as it is in REV'),
2659 _(b'REV'),
2659 _(b'REV'),
2660 ),
2660 ),
2661 (
2661 (
2662 b'0',
2662 b'0',
2663 b'print0',
2663 b'print0',
2664 None,
2664 None,
2665 _(b'end filenames with NUL, for use with xargs'),
2665 _(b'end filenames with NUL, for use with xargs'),
2666 ),
2666 ),
2667 ]
2667 ]
2668 + walkopts
2668 + walkopts
2669 + formatteropts
2669 + formatteropts
2670 + subrepoopts,
2670 + subrepoopts,
2671 _(b'[OPTION]... [FILE]...'),
2671 _(b'[OPTION]... [FILE]...'),
2672 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2672 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2673 intents={INTENT_READONLY},
2673 intents={INTENT_READONLY},
2674 )
2674 )
2675 def files(ui, repo, *pats, **opts):
2675 def files(ui, repo, *pats, **opts):
2676 """list tracked files
2676 """list tracked files
2677
2677
2678 Print files under Mercurial control in the working directory or
2678 Print files under Mercurial control in the working directory or
2679 specified revision for given files (excluding removed files).
2679 specified revision for given files (excluding removed files).
2680 Files can be specified as filenames or filesets.
2680 Files can be specified as filenames or filesets.
2681
2681
2682 If no files are given to match, this command prints the names
2682 If no files are given to match, this command prints the names
2683 of all files under Mercurial control.
2683 of all files under Mercurial control.
2684
2684
2685 .. container:: verbose
2685 .. container:: verbose
2686
2686
2687 Template:
2687 Template:
2688
2688
2689 The following keywords are supported in addition to the common template
2689 The following keywords are supported in addition to the common template
2690 keywords and functions. See also :hg:`help templates`.
2690 keywords and functions. See also :hg:`help templates`.
2691
2691
2692 :flags: String. Character denoting file's symlink and executable bits.
2692 :flags: String. Character denoting file's symlink and executable bits.
2693 :path: String. Repository-absolute path of the file.
2693 :path: String. Repository-absolute path of the file.
2694 :size: Integer. Size of the file in bytes.
2694 :size: Integer. Size of the file in bytes.
2695
2695
2696 Examples:
2696 Examples:
2697
2697
2698 - list all files under the current directory::
2698 - list all files under the current directory::
2699
2699
2700 hg files .
2700 hg files .
2701
2701
2702 - shows sizes and flags for current revision::
2702 - shows sizes and flags for current revision::
2703
2703
2704 hg files -vr .
2704 hg files -vr .
2705
2705
2706 - list all files named README::
2706 - list all files named README::
2707
2707
2708 hg files -I "**/README"
2708 hg files -I "**/README"
2709
2709
2710 - list all binary files::
2710 - list all binary files::
2711
2711
2712 hg files "set:binary()"
2712 hg files "set:binary()"
2713
2713
2714 - find files containing a regular expression::
2714 - find files containing a regular expression::
2715
2715
2716 hg files "set:grep('bob')"
2716 hg files "set:grep('bob')"
2717
2717
2718 - search tracked file contents with xargs and grep::
2718 - search tracked file contents with xargs and grep::
2719
2719
2720 hg files -0 | xargs -0 grep foo
2720 hg files -0 | xargs -0 grep foo
2721
2721
2722 See :hg:`help patterns` and :hg:`help filesets` for more information
2722 See :hg:`help patterns` and :hg:`help filesets` for more information
2723 on specifying file patterns.
2723 on specifying file patterns.
2724
2724
2725 Returns 0 if a match is found, 1 otherwise.
2725 Returns 0 if a match is found, 1 otherwise.
2726
2726
2727 """
2727 """
2728
2728
2729 opts = pycompat.byteskwargs(opts)
2729 opts = pycompat.byteskwargs(opts)
2730 rev = opts.get(b'rev')
2730 rev = opts.get(b'rev')
2731 if rev:
2731 if rev:
2732 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2732 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2733 ctx = scmutil.revsingle(repo, rev, None)
2733 ctx = scmutil.revsingle(repo, rev, None)
2734
2734
2735 end = b'\n'
2735 end = b'\n'
2736 if opts.get(b'print0'):
2736 if opts.get(b'print0'):
2737 end = b'\0'
2737 end = b'\0'
2738 fmt = b'%s' + end
2738 fmt = b'%s' + end
2739
2739
2740 m = scmutil.match(ctx, pats, opts)
2740 m = scmutil.match(ctx, pats, opts)
2741 ui.pager(b'files')
2741 ui.pager(b'files')
2742 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2742 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2743 with ui.formatter(b'files', opts) as fm:
2743 with ui.formatter(b'files', opts) as fm:
2744 return cmdutil.files(
2744 return cmdutil.files(
2745 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2745 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2746 )
2746 )
2747
2747
2748
2748
2749 @command(
2749 @command(
2750 b'forget',
2750 b'forget',
2751 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2751 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2752 + walkopts
2752 + walkopts
2753 + dryrunopts,
2753 + dryrunopts,
2754 _(b'[OPTION]... FILE...'),
2754 _(b'[OPTION]... FILE...'),
2755 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2755 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2756 helpbasic=True,
2756 helpbasic=True,
2757 inferrepo=True,
2757 inferrepo=True,
2758 )
2758 )
2759 def forget(ui, repo, *pats, **opts):
2759 def forget(ui, repo, *pats, **opts):
2760 """forget the specified files on the next commit
2760 """forget the specified files on the next commit
2761
2761
2762 Mark the specified files so they will no longer be tracked
2762 Mark the specified files so they will no longer be tracked
2763 after the next commit.
2763 after the next commit.
2764
2764
2765 This only removes files from the current branch, not from the
2765 This only removes files from the current branch, not from the
2766 entire project history, and it does not delete them from the
2766 entire project history, and it does not delete them from the
2767 working directory.
2767 working directory.
2768
2768
2769 To delete the file from the working directory, see :hg:`remove`.
2769 To delete the file from the working directory, see :hg:`remove`.
2770
2770
2771 To undo a forget before the next commit, see :hg:`add`.
2771 To undo a forget before the next commit, see :hg:`add`.
2772
2772
2773 .. container:: verbose
2773 .. container:: verbose
2774
2774
2775 Examples:
2775 Examples:
2776
2776
2777 - forget newly-added binary files::
2777 - forget newly-added binary files::
2778
2778
2779 hg forget "set:added() and binary()"
2779 hg forget "set:added() and binary()"
2780
2780
2781 - forget files that would be excluded by .hgignore::
2781 - forget files that would be excluded by .hgignore::
2782
2782
2783 hg forget "set:hgignore()"
2783 hg forget "set:hgignore()"
2784
2784
2785 Returns 0 on success.
2785 Returns 0 on success.
2786 """
2786 """
2787
2787
2788 opts = pycompat.byteskwargs(opts)
2788 opts = pycompat.byteskwargs(opts)
2789 if not pats:
2789 if not pats:
2790 raise error.Abort(_(b'no files specified'))
2790 raise error.Abort(_(b'no files specified'))
2791
2791
2792 m = scmutil.match(repo[None], pats, opts)
2792 m = scmutil.match(repo[None], pats, opts)
2793 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2793 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2794 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2794 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2795 rejected = cmdutil.forget(
2795 rejected = cmdutil.forget(
2796 ui,
2796 ui,
2797 repo,
2797 repo,
2798 m,
2798 m,
2799 prefix=b"",
2799 prefix=b"",
2800 uipathfn=uipathfn,
2800 uipathfn=uipathfn,
2801 explicitonly=False,
2801 explicitonly=False,
2802 dryrun=dryrun,
2802 dryrun=dryrun,
2803 interactive=interactive,
2803 interactive=interactive,
2804 )[0]
2804 )[0]
2805 return rejected and 1 or 0
2805 return rejected and 1 or 0
2806
2806
2807
2807
2808 @command(
2808 @command(
2809 b'graft',
2809 b'graft',
2810 [
2810 [
2811 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2811 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2812 (
2812 (
2813 b'',
2813 b'',
2814 b'base',
2814 b'base',
2815 b'',
2815 b'',
2816 _(b'base revision when doing the graft merge (ADVANCED)'),
2816 _(b'base revision when doing the graft merge (ADVANCED)'),
2817 _(b'REV'),
2817 _(b'REV'),
2818 ),
2818 ),
2819 (b'c', b'continue', False, _(b'resume interrupted graft')),
2819 (b'c', b'continue', False, _(b'resume interrupted graft')),
2820 (b'', b'stop', False, _(b'stop interrupted graft')),
2820 (b'', b'stop', False, _(b'stop interrupted graft')),
2821 (b'', b'abort', False, _(b'abort interrupted graft')),
2821 (b'', b'abort', False, _(b'abort interrupted graft')),
2822 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2822 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2823 (b'', b'log', None, _(b'append graft info to log message')),
2823 (b'', b'log', None, _(b'append graft info to log message')),
2824 (
2824 (
2825 b'',
2825 b'',
2826 b'no-commit',
2826 b'no-commit',
2827 None,
2827 None,
2828 _(b"don't commit, just apply the changes in working directory"),
2828 _(b"don't commit, just apply the changes in working directory"),
2829 ),
2829 ),
2830 (b'f', b'force', False, _(b'force graft')),
2830 (b'f', b'force', False, _(b'force graft')),
2831 (
2831 (
2832 b'D',
2832 b'D',
2833 b'currentdate',
2833 b'currentdate',
2834 False,
2834 False,
2835 _(b'record the current date as commit date'),
2835 _(b'record the current date as commit date'),
2836 ),
2836 ),
2837 (
2837 (
2838 b'U',
2838 b'U',
2839 b'currentuser',
2839 b'currentuser',
2840 False,
2840 False,
2841 _(b'record the current user as committer'),
2841 _(b'record the current user as committer'),
2842 ),
2842 ),
2843 ]
2843 ]
2844 + commitopts2
2844 + commitopts2
2845 + mergetoolopts
2845 + mergetoolopts
2846 + dryrunopts,
2846 + dryrunopts,
2847 _(b'[OPTION]... [-r REV]... REV...'),
2847 _(b'[OPTION]... [-r REV]... REV...'),
2848 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2848 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2849 )
2849 )
2850 def graft(ui, repo, *revs, **opts):
2850 def graft(ui, repo, *revs, **opts):
2851 '''copy changes from other branches onto the current branch
2851 '''copy changes from other branches onto the current branch
2852
2852
2853 This command uses Mercurial's merge logic to copy individual
2853 This command uses Mercurial's merge logic to copy individual
2854 changes from other branches without merging branches in the
2854 changes from other branches without merging branches in the
2855 history graph. This is sometimes known as 'backporting' or
2855 history graph. This is sometimes known as 'backporting' or
2856 'cherry-picking'. By default, graft will copy user, date, and
2856 'cherry-picking'. By default, graft will copy user, date, and
2857 description from the source changesets.
2857 description from the source changesets.
2858
2858
2859 Changesets that are ancestors of the current revision, that have
2859 Changesets that are ancestors of the current revision, that have
2860 already been grafted, or that are merges will be skipped.
2860 already been grafted, or that are merges will be skipped.
2861
2861
2862 If --log is specified, log messages will have a comment appended
2862 If --log is specified, log messages will have a comment appended
2863 of the form::
2863 of the form::
2864
2864
2865 (grafted from CHANGESETHASH)
2865 (grafted from CHANGESETHASH)
2866
2866
2867 If --force is specified, revisions will be grafted even if they
2867 If --force is specified, revisions will be grafted even if they
2868 are already ancestors of, or have been grafted to, the destination.
2868 are already ancestors of, or have been grafted to, the destination.
2869 This is useful when the revisions have since been backed out.
2869 This is useful when the revisions have since been backed out.
2870
2870
2871 If a graft merge results in conflicts, the graft process is
2871 If a graft merge results in conflicts, the graft process is
2872 interrupted so that the current merge can be manually resolved.
2872 interrupted so that the current merge can be manually resolved.
2873 Once all conflicts are addressed, the graft process can be
2873 Once all conflicts are addressed, the graft process can be
2874 continued with the -c/--continue option.
2874 continued with the -c/--continue option.
2875
2875
2876 The -c/--continue option reapplies all the earlier options.
2876 The -c/--continue option reapplies all the earlier options.
2877
2877
2878 .. container:: verbose
2878 .. container:: verbose
2879
2879
2880 The --base option exposes more of how graft internally uses merge with a
2880 The --base option exposes more of how graft internally uses merge with a
2881 custom base revision. --base can be used to specify another ancestor than
2881 custom base revision. --base can be used to specify another ancestor than
2882 the first and only parent.
2882 the first and only parent.
2883
2883
2884 The command::
2884 The command::
2885
2885
2886 hg graft -r 345 --base 234
2886 hg graft -r 345 --base 234
2887
2887
2888 is thus pretty much the same as::
2888 is thus pretty much the same as::
2889
2889
2890 hg diff -r 234 -r 345 | hg import
2890 hg diff -r 234 -r 345 | hg import
2891
2891
2892 but using merge to resolve conflicts and track moved files.
2892 but using merge to resolve conflicts and track moved files.
2893
2893
2894 The result of a merge can thus be backported as a single commit by
2894 The result of a merge can thus be backported as a single commit by
2895 specifying one of the merge parents as base, and thus effectively
2895 specifying one of the merge parents as base, and thus effectively
2896 grafting the changes from the other side.
2896 grafting the changes from the other side.
2897
2897
2898 It is also possible to collapse multiple changesets and clean up history
2898 It is also possible to collapse multiple changesets and clean up history
2899 by specifying another ancestor as base, much like rebase --collapse
2899 by specifying another ancestor as base, much like rebase --collapse
2900 --keep.
2900 --keep.
2901
2901
2902 The commit message can be tweaked after the fact using commit --amend .
2902 The commit message can be tweaked after the fact using commit --amend .
2903
2903
2904 For using non-ancestors as the base to backout changes, see the backout
2904 For using non-ancestors as the base to backout changes, see the backout
2905 command and the hidden --parent option.
2905 command and the hidden --parent option.
2906
2906
2907 .. container:: verbose
2907 .. container:: verbose
2908
2908
2909 Examples:
2909 Examples:
2910
2910
2911 - copy a single change to the stable branch and edit its description::
2911 - copy a single change to the stable branch and edit its description::
2912
2912
2913 hg update stable
2913 hg update stable
2914 hg graft --edit 9393
2914 hg graft --edit 9393
2915
2915
2916 - graft a range of changesets with one exception, updating dates::
2916 - graft a range of changesets with one exception, updating dates::
2917
2917
2918 hg graft -D "2085::2093 and not 2091"
2918 hg graft -D "2085::2093 and not 2091"
2919
2919
2920 - continue a graft after resolving conflicts::
2920 - continue a graft after resolving conflicts::
2921
2921
2922 hg graft -c
2922 hg graft -c
2923
2923
2924 - show the source of a grafted changeset::
2924 - show the source of a grafted changeset::
2925
2925
2926 hg log --debug -r .
2926 hg log --debug -r .
2927
2927
2928 - show revisions sorted by date::
2928 - show revisions sorted by date::
2929
2929
2930 hg log -r "sort(all(), date)"
2930 hg log -r "sort(all(), date)"
2931
2931
2932 - backport the result of a merge as a single commit::
2932 - backport the result of a merge as a single commit::
2933
2933
2934 hg graft -r 123 --base 123^
2934 hg graft -r 123 --base 123^
2935
2935
2936 - land a feature branch as one changeset::
2936 - land a feature branch as one changeset::
2937
2937
2938 hg up -cr default
2938 hg up -cr default
2939 hg graft -r featureX --base "ancestor('featureX', 'default')"
2939 hg graft -r featureX --base "ancestor('featureX', 'default')"
2940
2940
2941 See :hg:`help revisions` for more about specifying revisions.
2941 See :hg:`help revisions` for more about specifying revisions.
2942
2942
2943 Returns 0 on successful completion.
2943 Returns 0 on successful completion.
2944 '''
2944 '''
2945 with repo.wlock():
2945 with repo.wlock():
2946 return _dograft(ui, repo, *revs, **opts)
2946 return _dograft(ui, repo, *revs, **opts)
2947
2947
2948
2948
2949 def _dograft(ui, repo, *revs, **opts):
2949 def _dograft(ui, repo, *revs, **opts):
2950 opts = pycompat.byteskwargs(opts)
2950 opts = pycompat.byteskwargs(opts)
2951 if revs and opts.get(b'rev'):
2951 if revs and opts.get(b'rev'):
2952 ui.warn(
2952 ui.warn(
2953 _(
2953 _(
2954 b'warning: inconsistent use of --rev might give unexpected '
2954 b'warning: inconsistent use of --rev might give unexpected '
2955 b'revision ordering!\n'
2955 b'revision ordering!\n'
2956 )
2956 )
2957 )
2957 )
2958
2958
2959 revs = list(revs)
2959 revs = list(revs)
2960 revs.extend(opts.get(b'rev'))
2960 revs.extend(opts.get(b'rev'))
2961 basectx = None
2961 basectx = None
2962 if opts.get(b'base'):
2962 if opts.get(b'base'):
2963 basectx = scmutil.revsingle(repo, opts[b'base'], None)
2963 basectx = scmutil.revsingle(repo, opts[b'base'], None)
2964 # a dict of data to be stored in state file
2964 # a dict of data to be stored in state file
2965 statedata = {}
2965 statedata = {}
2966 # list of new nodes created by ongoing graft
2966 # list of new nodes created by ongoing graft
2967 statedata[b'newnodes'] = []
2967 statedata[b'newnodes'] = []
2968
2968
2969 cmdutil.resolvecommitoptions(ui, opts)
2969 cmdutil.resolvecommitoptions(ui, opts)
2970
2970
2971 editor = cmdutil.getcommiteditor(
2971 editor = cmdutil.getcommiteditor(
2972 editform=b'graft', **pycompat.strkwargs(opts)
2972 editform=b'graft', **pycompat.strkwargs(opts)
2973 )
2973 )
2974
2974
2975 cont = False
2975 cont = False
2976 if opts.get(b'no_commit'):
2976 if opts.get(b'no_commit'):
2977 if opts.get(b'edit'):
2977 if opts.get(b'edit'):
2978 raise error.Abort(
2978 raise error.Abort(
2979 _(b"cannot specify --no-commit and --edit together")
2979 _(b"cannot specify --no-commit and --edit together")
2980 )
2980 )
2981 if opts.get(b'currentuser'):
2981 if opts.get(b'currentuser'):
2982 raise error.Abort(
2982 raise error.Abort(
2983 _(b"cannot specify --no-commit and --currentuser together")
2983 _(b"cannot specify --no-commit and --currentuser together")
2984 )
2984 )
2985 if opts.get(b'currentdate'):
2985 if opts.get(b'currentdate'):
2986 raise error.Abort(
2986 raise error.Abort(
2987 _(b"cannot specify --no-commit and --currentdate together")
2987 _(b"cannot specify --no-commit and --currentdate together")
2988 )
2988 )
2989 if opts.get(b'log'):
2989 if opts.get(b'log'):
2990 raise error.Abort(
2990 raise error.Abort(
2991 _(b"cannot specify --no-commit and --log together")
2991 _(b"cannot specify --no-commit and --log together")
2992 )
2992 )
2993
2993
2994 graftstate = statemod.cmdstate(repo, b'graftstate')
2994 graftstate = statemod.cmdstate(repo, b'graftstate')
2995
2995
2996 if opts.get(b'stop'):
2996 if opts.get(b'stop'):
2997 if opts.get(b'continue'):
2997 if opts.get(b'continue'):
2998 raise error.Abort(
2998 raise error.Abort(
2999 _(b"cannot use '--continue' and '--stop' together")
2999 _(b"cannot use '--continue' and '--stop' together")
3000 )
3000 )
3001 if opts.get(b'abort'):
3001 if opts.get(b'abort'):
3002 raise error.Abort(_(b"cannot use '--abort' and '--stop' together"))
3002 raise error.Abort(_(b"cannot use '--abort' and '--stop' together"))
3003
3003
3004 if any(
3004 if any(
3005 (
3005 (
3006 opts.get(b'edit'),
3006 opts.get(b'edit'),
3007 opts.get(b'log'),
3007 opts.get(b'log'),
3008 opts.get(b'user'),
3008 opts.get(b'user'),
3009 opts.get(b'date'),
3009 opts.get(b'date'),
3010 opts.get(b'currentdate'),
3010 opts.get(b'currentdate'),
3011 opts.get(b'currentuser'),
3011 opts.get(b'currentuser'),
3012 opts.get(b'rev'),
3012 opts.get(b'rev'),
3013 )
3013 )
3014 ):
3014 ):
3015 raise error.Abort(_(b"cannot specify any other flag with '--stop'"))
3015 raise error.Abort(_(b"cannot specify any other flag with '--stop'"))
3016 return _stopgraft(ui, repo, graftstate)
3016 return _stopgraft(ui, repo, graftstate)
3017 elif opts.get(b'abort'):
3017 elif opts.get(b'abort'):
3018 if opts.get(b'continue'):
3018 if opts.get(b'continue'):
3019 raise error.Abort(
3019 raise error.Abort(
3020 _(b"cannot use '--continue' and '--abort' together")
3020 _(b"cannot use '--continue' and '--abort' together")
3021 )
3021 )
3022 if any(
3022 if any(
3023 (
3023 (
3024 opts.get(b'edit'),
3024 opts.get(b'edit'),
3025 opts.get(b'log'),
3025 opts.get(b'log'),
3026 opts.get(b'user'),
3026 opts.get(b'user'),
3027 opts.get(b'date'),
3027 opts.get(b'date'),
3028 opts.get(b'currentdate'),
3028 opts.get(b'currentdate'),
3029 opts.get(b'currentuser'),
3029 opts.get(b'currentuser'),
3030 opts.get(b'rev'),
3030 opts.get(b'rev'),
3031 )
3031 )
3032 ):
3032 ):
3033 raise error.Abort(
3033 raise error.Abort(
3034 _(b"cannot specify any other flag with '--abort'")
3034 _(b"cannot specify any other flag with '--abort'")
3035 )
3035 )
3036
3036
3037 return cmdutil.abortgraft(ui, repo, graftstate)
3037 return cmdutil.abortgraft(ui, repo, graftstate)
3038 elif opts.get(b'continue'):
3038 elif opts.get(b'continue'):
3039 cont = True
3039 cont = True
3040 if revs:
3040 if revs:
3041 raise error.Abort(_(b"can't specify --continue and revisions"))
3041 raise error.Abort(_(b"can't specify --continue and revisions"))
3042 # read in unfinished revisions
3042 # read in unfinished revisions
3043 if graftstate.exists():
3043 if graftstate.exists():
3044 statedata = cmdutil.readgraftstate(repo, graftstate)
3044 statedata = cmdutil.readgraftstate(repo, graftstate)
3045 if statedata.get(b'date'):
3045 if statedata.get(b'date'):
3046 opts[b'date'] = statedata[b'date']
3046 opts[b'date'] = statedata[b'date']
3047 if statedata.get(b'user'):
3047 if statedata.get(b'user'):
3048 opts[b'user'] = statedata[b'user']
3048 opts[b'user'] = statedata[b'user']
3049 if statedata.get(b'log'):
3049 if statedata.get(b'log'):
3050 opts[b'log'] = True
3050 opts[b'log'] = True
3051 if statedata.get(b'no_commit'):
3051 if statedata.get(b'no_commit'):
3052 opts[b'no_commit'] = statedata.get(b'no_commit')
3052 opts[b'no_commit'] = statedata.get(b'no_commit')
3053 nodes = statedata[b'nodes']
3053 nodes = statedata[b'nodes']
3054 revs = [repo[node].rev() for node in nodes]
3054 revs = [repo[node].rev() for node in nodes]
3055 else:
3055 else:
3056 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3056 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3057 else:
3057 else:
3058 if not revs:
3058 if not revs:
3059 raise error.Abort(_(b'no revisions specified'))
3059 raise error.Abort(_(b'no revisions specified'))
3060 cmdutil.checkunfinished(repo)
3060 cmdutil.checkunfinished(repo)
3061 cmdutil.bailifchanged(repo)
3061 cmdutil.bailifchanged(repo)
3062 revs = scmutil.revrange(repo, revs)
3062 revs = scmutil.revrange(repo, revs)
3063
3063
3064 skipped = set()
3064 skipped = set()
3065 if basectx is None:
3065 if basectx is None:
3066 # check for merges
3066 # check for merges
3067 for rev in repo.revs(b'%ld and merge()', revs):
3067 for rev in repo.revs(b'%ld and merge()', revs):
3068 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3068 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3069 skipped.add(rev)
3069 skipped.add(rev)
3070 revs = [r for r in revs if r not in skipped]
3070 revs = [r for r in revs if r not in skipped]
3071 if not revs:
3071 if not revs:
3072 return -1
3072 return -1
3073 if basectx is not None and len(revs) != 1:
3073 if basectx is not None and len(revs) != 1:
3074 raise error.Abort(_(b'only one revision allowed with --base '))
3074 raise error.Abort(_(b'only one revision allowed with --base '))
3075
3075
3076 # Don't check in the --continue case, in effect retaining --force across
3076 # Don't check in the --continue case, in effect retaining --force across
3077 # --continues. That's because without --force, any revisions we decided to
3077 # --continues. That's because without --force, any revisions we decided to
3078 # skip would have been filtered out here, so they wouldn't have made their
3078 # skip would have been filtered out here, so they wouldn't have made their
3079 # way to the graftstate. With --force, any revisions we would have otherwise
3079 # way to the graftstate. With --force, any revisions we would have otherwise
3080 # skipped would not have been filtered out, and if they hadn't been applied
3080 # skipped would not have been filtered out, and if they hadn't been applied
3081 # already, they'd have been in the graftstate.
3081 # already, they'd have been in the graftstate.
3082 if not (cont or opts.get(b'force')) and basectx is None:
3082 if not (cont or opts.get(b'force')) and basectx is None:
3083 # check for ancestors of dest branch
3083 # check for ancestors of dest branch
3084 ancestors = repo.revs(b'%ld & (::.)', revs)
3084 ancestors = repo.revs(b'%ld & (::.)', revs)
3085 for rev in ancestors:
3085 for rev in ancestors:
3086 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3086 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3087
3087
3088 revs = [r for r in revs if r not in ancestors]
3088 revs = [r for r in revs if r not in ancestors]
3089
3089
3090 if not revs:
3090 if not revs:
3091 return -1
3091 return -1
3092
3092
3093 # analyze revs for earlier grafts
3093 # analyze revs for earlier grafts
3094 ids = {}
3094 ids = {}
3095 for ctx in repo.set(b"%ld", revs):
3095 for ctx in repo.set(b"%ld", revs):
3096 ids[ctx.hex()] = ctx.rev()
3096 ids[ctx.hex()] = ctx.rev()
3097 n = ctx.extra().get(b'source')
3097 n = ctx.extra().get(b'source')
3098 if n:
3098 if n:
3099 ids[n] = ctx.rev()
3099 ids[n] = ctx.rev()
3100
3100
3101 # check ancestors for earlier grafts
3101 # check ancestors for earlier grafts
3102 ui.debug(b'scanning for duplicate grafts\n')
3102 ui.debug(b'scanning for duplicate grafts\n')
3103
3103
3104 # The only changesets we can be sure doesn't contain grafts of any
3104 # The only changesets we can be sure doesn't contain grafts of any
3105 # revs, are the ones that are common ancestors of *all* revs:
3105 # revs, are the ones that are common ancestors of *all* revs:
3106 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3106 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3107 ctx = repo[rev]
3107 ctx = repo[rev]
3108 n = ctx.extra().get(b'source')
3108 n = ctx.extra().get(b'source')
3109 if n in ids:
3109 if n in ids:
3110 try:
3110 try:
3111 r = repo[n].rev()
3111 r = repo[n].rev()
3112 except error.RepoLookupError:
3112 except error.RepoLookupError:
3113 r = None
3113 r = None
3114 if r in revs:
3114 if r in revs:
3115 ui.warn(
3115 ui.warn(
3116 _(
3116 _(
3117 b'skipping revision %d:%s '
3117 b'skipping revision %d:%s '
3118 b'(already grafted to %d:%s)\n'
3118 b'(already grafted to %d:%s)\n'
3119 )
3119 )
3120 % (r, repo[r], rev, ctx)
3120 % (r, repo[r], rev, ctx)
3121 )
3121 )
3122 revs.remove(r)
3122 revs.remove(r)
3123 elif ids[n] in revs:
3123 elif ids[n] in revs:
3124 if r is None:
3124 if r is None:
3125 ui.warn(
3125 ui.warn(
3126 _(
3126 _(
3127 b'skipping already grafted revision %d:%s '
3127 b'skipping already grafted revision %d:%s '
3128 b'(%d:%s also has unknown origin %s)\n'
3128 b'(%d:%s also has unknown origin %s)\n'
3129 )
3129 )
3130 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3130 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3131 )
3131 )
3132 else:
3132 else:
3133 ui.warn(
3133 ui.warn(
3134 _(
3134 _(
3135 b'skipping already grafted revision %d:%s '
3135 b'skipping already grafted revision %d:%s '
3136 b'(%d:%s also has origin %d:%s)\n'
3136 b'(%d:%s also has origin %d:%s)\n'
3137 )
3137 )
3138 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3138 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3139 )
3139 )
3140 revs.remove(ids[n])
3140 revs.remove(ids[n])
3141 elif ctx.hex() in ids:
3141 elif ctx.hex() in ids:
3142 r = ids[ctx.hex()]
3142 r = ids[ctx.hex()]
3143 if r in revs:
3143 if r in revs:
3144 ui.warn(
3144 ui.warn(
3145 _(
3145 _(
3146 b'skipping already grafted revision %d:%s '
3146 b'skipping already grafted revision %d:%s '
3147 b'(was grafted from %d:%s)\n'
3147 b'(was grafted from %d:%s)\n'
3148 )
3148 )
3149 % (r, repo[r], rev, ctx)
3149 % (r, repo[r], rev, ctx)
3150 )
3150 )
3151 revs.remove(r)
3151 revs.remove(r)
3152 if not revs:
3152 if not revs:
3153 return -1
3153 return -1
3154
3154
3155 if opts.get(b'no_commit'):
3155 if opts.get(b'no_commit'):
3156 statedata[b'no_commit'] = True
3156 statedata[b'no_commit'] = True
3157 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3157 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3158 desc = b'%d:%s "%s"' % (
3158 desc = b'%d:%s "%s"' % (
3159 ctx.rev(),
3159 ctx.rev(),
3160 ctx,
3160 ctx,
3161 ctx.description().split(b'\n', 1)[0],
3161 ctx.description().split(b'\n', 1)[0],
3162 )
3162 )
3163 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3163 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3164 if names:
3164 if names:
3165 desc += b' (%s)' % b' '.join(names)
3165 desc += b' (%s)' % b' '.join(names)
3166 ui.status(_(b'grafting %s\n') % desc)
3166 ui.status(_(b'grafting %s\n') % desc)
3167 if opts.get(b'dry_run'):
3167 if opts.get(b'dry_run'):
3168 continue
3168 continue
3169
3169
3170 source = ctx.extra().get(b'source')
3170 source = ctx.extra().get(b'source')
3171 extra = {}
3171 extra = {}
3172 if source:
3172 if source:
3173 extra[b'source'] = source
3173 extra[b'source'] = source
3174 extra[b'intermediate-source'] = ctx.hex()
3174 extra[b'intermediate-source'] = ctx.hex()
3175 else:
3175 else:
3176 extra[b'source'] = ctx.hex()
3176 extra[b'source'] = ctx.hex()
3177 user = ctx.user()
3177 user = ctx.user()
3178 if opts.get(b'user'):
3178 if opts.get(b'user'):
3179 user = opts[b'user']
3179 user = opts[b'user']
3180 statedata[b'user'] = user
3180 statedata[b'user'] = user
3181 date = ctx.date()
3181 date = ctx.date()
3182 if opts.get(b'date'):
3182 if opts.get(b'date'):
3183 date = opts[b'date']
3183 date = opts[b'date']
3184 statedata[b'date'] = date
3184 statedata[b'date'] = date
3185 message = ctx.description()
3185 message = ctx.description()
3186 if opts.get(b'log'):
3186 if opts.get(b'log'):
3187 message += b'\n(grafted from %s)' % ctx.hex()
3187 message += b'\n(grafted from %s)' % ctx.hex()
3188 statedata[b'log'] = True
3188 statedata[b'log'] = True
3189
3189
3190 # we don't merge the first commit when continuing
3190 # we don't merge the first commit when continuing
3191 if not cont:
3191 if not cont:
3192 # perform the graft merge with p1(rev) as 'ancestor'
3192 # perform the graft merge with p1(rev) as 'ancestor'
3193 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3193 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3194 base = ctx.p1() if basectx is None else basectx
3194 base = ctx.p1() if basectx is None else basectx
3195 with ui.configoverride(overrides, b'graft'):
3195 with ui.configoverride(overrides, b'graft'):
3196 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3196 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3197 # report any conflicts
3197 # report any conflicts
3198 if stats.unresolvedcount > 0:
3198 if stats.unresolvedcount > 0:
3199 # write out state for --continue
3199 # write out state for --continue
3200 nodes = [repo[rev].hex() for rev in revs[pos:]]
3200 nodes = [repo[rev].hex() for rev in revs[pos:]]
3201 statedata[b'nodes'] = nodes
3201 statedata[b'nodes'] = nodes
3202 stateversion = 1
3202 stateversion = 1
3203 graftstate.save(stateversion, statedata)
3203 graftstate.save(stateversion, statedata)
3204 hint = _(b"use 'hg resolve' and 'hg graft --continue'")
3204 hint = _(b"use 'hg resolve' and 'hg graft --continue'")
3205 raise error.Abort(
3205 raise error.Abort(
3206 _(b"unresolved conflicts, can't continue"), hint=hint
3206 _(b"unresolved conflicts, can't continue"), hint=hint
3207 )
3207 )
3208 else:
3208 else:
3209 cont = False
3209 cont = False
3210
3210
3211 # commit if --no-commit is false
3211 # commit if --no-commit is false
3212 if not opts.get(b'no_commit'):
3212 if not opts.get(b'no_commit'):
3213 node = repo.commit(
3213 node = repo.commit(
3214 text=message, user=user, date=date, extra=extra, editor=editor
3214 text=message, user=user, date=date, extra=extra, editor=editor
3215 )
3215 )
3216 if node is None:
3216 if node is None:
3217 ui.warn(
3217 ui.warn(
3218 _(b'note: graft of %d:%s created no changes to commit\n')
3218 _(b'note: graft of %d:%s created no changes to commit\n')
3219 % (ctx.rev(), ctx)
3219 % (ctx.rev(), ctx)
3220 )
3220 )
3221 # checking that newnodes exist because old state files won't have it
3221 # checking that newnodes exist because old state files won't have it
3222 elif statedata.get(b'newnodes') is not None:
3222 elif statedata.get(b'newnodes') is not None:
3223 statedata[b'newnodes'].append(node)
3223 statedata[b'newnodes'].append(node)
3224
3224
3225 # remove state when we complete successfully
3225 # remove state when we complete successfully
3226 if not opts.get(b'dry_run'):
3226 if not opts.get(b'dry_run'):
3227 graftstate.delete()
3227 graftstate.delete()
3228
3228
3229 return 0
3229 return 0
3230
3230
3231
3231
3232 def _stopgraft(ui, repo, graftstate):
3232 def _stopgraft(ui, repo, graftstate):
3233 """stop the interrupted graft"""
3233 """stop the interrupted graft"""
3234 if not graftstate.exists():
3234 if not graftstate.exists():
3235 raise error.Abort(_(b"no interrupted graft found"))
3235 raise error.Abort(_(b"no interrupted graft found"))
3236 pctx = repo[b'.']
3236 pctx = repo[b'.']
3237 hg.updaterepo(repo, pctx.node(), overwrite=True)
3237 hg.updaterepo(repo, pctx.node(), overwrite=True)
3238 graftstate.delete()
3238 graftstate.delete()
3239 ui.status(_(b"stopped the interrupted graft\n"))
3239 ui.status(_(b"stopped the interrupted graft\n"))
3240 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3240 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3241 return 0
3241 return 0
3242
3242
3243
3243
3244 statemod.addunfinished(
3244 statemod.addunfinished(
3245 b'graft',
3245 b'graft',
3246 fname=b'graftstate',
3246 fname=b'graftstate',
3247 clearable=True,
3247 clearable=True,
3248 stopflag=True,
3248 stopflag=True,
3249 continueflag=True,
3249 continueflag=True,
3250 abortfunc=cmdutil.hgabortgraft,
3250 abortfunc=cmdutil.hgabortgraft,
3251 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3251 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3252 )
3252 )
3253
3253
3254
3254
3255 @command(
3255 @command(
3256 b'grep',
3256 b'grep',
3257 [
3257 [
3258 (b'0', b'print0', None, _(b'end fields with NUL')),
3258 (b'0', b'print0', None, _(b'end fields with NUL')),
3259 (b'', b'all', None, _(b'print all revisions that match (DEPRECATED) ')),
3259 (b'', b'all', None, _(b'print all revisions that match (DEPRECATED) ')),
3260 (
3260 (
3261 b'',
3261 b'',
3262 b'diff',
3262 b'diff',
3263 None,
3263 None,
3264 _(
3264 _(
3265 b'search revision differences for when the pattern was added '
3265 b'search revision differences for when the pattern was added '
3266 b'or removed'
3266 b'or removed'
3267 ),
3267 ),
3268 ),
3268 ),
3269 (b'a', b'text', None, _(b'treat all files as text')),
3269 (b'a', b'text', None, _(b'treat all files as text')),
3270 (
3270 (
3271 b'f',
3271 b'f',
3272 b'follow',
3272 b'follow',
3273 None,
3273 None,
3274 _(
3274 _(
3275 b'follow changeset history,'
3275 b'follow changeset history,'
3276 b' or file history across copies and renames'
3276 b' or file history across copies and renames'
3277 ),
3277 ),
3278 ),
3278 ),
3279 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3279 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3280 (
3280 (
3281 b'l',
3281 b'l',
3282 b'files-with-matches',
3282 b'files-with-matches',
3283 None,
3283 None,
3284 _(b'print only filenames and revisions that match'),
3284 _(b'print only filenames and revisions that match'),
3285 ),
3285 ),
3286 (b'n', b'line-number', None, _(b'print matching line numbers')),
3286 (b'n', b'line-number', None, _(b'print matching line numbers')),
3287 (
3287 (
3288 b'r',
3288 b'r',
3289 b'rev',
3289 b'rev',
3290 [],
3290 [],
3291 _(b'search files changed within revision range'),
3291 _(b'search files changed within revision range'),
3292 _(b'REV'),
3292 _(b'REV'),
3293 ),
3293 ),
3294 (
3294 (
3295 b'',
3295 b'',
3296 b'all-files',
3296 b'all-files',
3297 None,
3297 None,
3298 _(
3298 _(
3299 b'include all files in the changeset while grepping (DEPRECATED)'
3299 b'include all files in the changeset while grepping (DEPRECATED)'
3300 ),
3300 ),
3301 ),
3301 ),
3302 (b'u', b'user', None, _(b'list the author (long with -v)')),
3302 (b'u', b'user', None, _(b'list the author (long with -v)')),
3303 (b'd', b'date', None, _(b'list the date (short with -q)')),
3303 (b'd', b'date', None, _(b'list the date (short with -q)')),
3304 ]
3304 ]
3305 + formatteropts
3305 + formatteropts
3306 + walkopts,
3306 + walkopts,
3307 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3307 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3308 helpcategory=command.CATEGORY_FILE_CONTENTS,
3308 helpcategory=command.CATEGORY_FILE_CONTENTS,
3309 inferrepo=True,
3309 inferrepo=True,
3310 intents={INTENT_READONLY},
3310 intents={INTENT_READONLY},
3311 )
3311 )
3312 def grep(ui, repo, pattern, *pats, **opts):
3312 def grep(ui, repo, pattern, *pats, **opts):
3313 """search for a pattern in specified files
3313 """search for a pattern in specified files
3314
3314
3315 Search the working directory or revision history for a regular
3315 Search the working directory or revision history for a regular
3316 expression in the specified files for the entire repository.
3316 expression in the specified files for the entire repository.
3317
3317
3318 By default, grep searches the repository files in the working
3318 By default, grep searches the repository files in the working
3319 directory and prints the files where it finds a match. To specify
3319 directory and prints the files where it finds a match. To specify
3320 historical revisions instead of the working directory, use the
3320 historical revisions instead of the working directory, use the
3321 --rev flag.
3321 --rev flag.
3322
3322
3323 To search instead historical revision differences that contains a
3323 To search instead historical revision differences that contains a
3324 change in match status ("-" for a match that becomes a non-match,
3324 change in match status ("-" for a match that becomes a non-match,
3325 or "+" for a non-match that becomes a match), use the --diff flag.
3325 or "+" for a non-match that becomes a match), use the --diff flag.
3326
3326
3327 PATTERN can be any Python (roughly Perl-compatible) regular
3327 PATTERN can be any Python (roughly Perl-compatible) regular
3328 expression.
3328 expression.
3329
3329
3330 If no FILEs are specified and the --rev flag isn't supplied, all
3330 If no FILEs are specified and the --rev flag isn't supplied, all
3331 files in the working directory are searched. When using the --rev
3331 files in the working directory are searched. When using the --rev
3332 flag and specifying FILEs, use the --follow argument to also
3332 flag and specifying FILEs, use the --follow argument to also
3333 follow the specified FILEs across renames and copies.
3333 follow the specified FILEs across renames and copies.
3334
3334
3335 .. container:: verbose
3335 .. container:: verbose
3336
3336
3337 Template:
3337 Template:
3338
3338
3339 The following keywords are supported in addition to the common template
3339 The following keywords are supported in addition to the common template
3340 keywords and functions. See also :hg:`help templates`.
3340 keywords and functions. See also :hg:`help templates`.
3341
3341
3342 :change: String. Character denoting insertion ``+`` or removal ``-``.
3342 :change: String. Character denoting insertion ``+`` or removal ``-``.
3343 Available if ``--diff`` is specified.
3343 Available if ``--diff`` is specified.
3344 :lineno: Integer. Line number of the match.
3344 :lineno: Integer. Line number of the match.
3345 :path: String. Repository-absolute path of the file.
3345 :path: String. Repository-absolute path of the file.
3346 :texts: List of text chunks.
3346 :texts: List of text chunks.
3347
3347
3348 And each entry of ``{texts}`` provides the following sub-keywords.
3348 And each entry of ``{texts}`` provides the following sub-keywords.
3349
3349
3350 :matched: Boolean. True if the chunk matches the specified pattern.
3350 :matched: Boolean. True if the chunk matches the specified pattern.
3351 :text: String. Chunk content.
3351 :text: String. Chunk content.
3352
3352
3353 See :hg:`help templates.operators` for the list expansion syntax.
3353 See :hg:`help templates.operators` for the list expansion syntax.
3354
3354
3355 Returns 0 if a match is found, 1 otherwise.
3355 Returns 0 if a match is found, 1 otherwise.
3356
3356
3357 """
3357 """
3358 opts = pycompat.byteskwargs(opts)
3358 opts = pycompat.byteskwargs(opts)
3359 diff = opts.get(b'all') or opts.get(b'diff')
3359 diff = opts.get(b'all') or opts.get(b'diff')
3360 if diff and opts.get(b'all_files'):
3360 if diff and opts.get(b'all_files'):
3361 raise error.Abort(_(b'--diff and --all-files are mutually exclusive'))
3361 raise error.Abort(_(b'--diff and --all-files are mutually exclusive'))
3362 if opts.get(b'all_files') is None and not diff:
3362 if opts.get(b'all_files') is None and not diff:
3363 opts[b'all_files'] = True
3363 opts[b'all_files'] = True
3364 plaingrep = opts.get(b'all_files') and not opts.get(b'rev')
3364 plaingrep = opts.get(b'all_files') and not opts.get(b'rev')
3365 all_files = opts.get(b'all_files')
3365 all_files = opts.get(b'all_files')
3366 if plaingrep:
3366 if plaingrep:
3367 opts[b'rev'] = [b'wdir()']
3367 opts[b'rev'] = [b'wdir()']
3368
3368
3369 reflags = re.M
3369 reflags = re.M
3370 if opts.get(b'ignore_case'):
3370 if opts.get(b'ignore_case'):
3371 reflags |= re.I
3371 reflags |= re.I
3372 try:
3372 try:
3373 regexp = util.re.compile(pattern, reflags)
3373 regexp = util.re.compile(pattern, reflags)
3374 except re.error as inst:
3374 except re.error as inst:
3375 ui.warn(
3375 ui.warn(
3376 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3376 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3377 )
3377 )
3378 return 1
3378 return 1
3379 sep, eol = b':', b'\n'
3379 sep, eol = b':', b'\n'
3380 if opts.get(b'print0'):
3380 if opts.get(b'print0'):
3381 sep = eol = b'\0'
3381 sep = eol = b'\0'
3382
3382
3383 getfile = util.lrucachefunc(repo.file)
3383 getfile = util.lrucachefunc(repo.file)
3384
3384
3385 def matchlines(body):
3385 def matchlines(body):
3386 begin = 0
3386 begin = 0
3387 linenum = 0
3387 linenum = 0
3388 while begin < len(body):
3388 while begin < len(body):
3389 match = regexp.search(body, begin)
3389 match = regexp.search(body, begin)
3390 if not match:
3390 if not match:
3391 break
3391 break
3392 mstart, mend = match.span()
3392 mstart, mend = match.span()
3393 linenum += body.count(b'\n', begin, mstart) + 1
3393 linenum += body.count(b'\n', begin, mstart) + 1
3394 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
3394 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
3395 begin = body.find(b'\n', mend) + 1 or len(body) + 1
3395 begin = body.find(b'\n', mend) + 1 or len(body) + 1
3396 lend = begin - 1
3396 lend = begin - 1
3397 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3397 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3398
3398
3399 class linestate(object):
3399 class linestate(object):
3400 def __init__(self, line, linenum, colstart, colend):
3400 def __init__(self, line, linenum, colstart, colend):
3401 self.line = line
3401 self.line = line
3402 self.linenum = linenum
3402 self.linenum = linenum
3403 self.colstart = colstart
3403 self.colstart = colstart
3404 self.colend = colend
3404 self.colend = colend
3405
3405
3406 def __hash__(self):
3406 def __hash__(self):
3407 return hash((self.linenum, self.line))
3407 return hash((self.linenum, self.line))
3408
3408
3409 def __eq__(self, other):
3409 def __eq__(self, other):
3410 return self.line == other.line
3410 return self.line == other.line
3411
3411
3412 def findpos(self):
3412 def findpos(self):
3413 """Iterate all (start, end) indices of matches"""
3413 """Iterate all (start, end) indices of matches"""
3414 yield self.colstart, self.colend
3414 yield self.colstart, self.colend
3415 p = self.colend
3415 p = self.colend
3416 while p < len(self.line):
3416 while p < len(self.line):
3417 m = regexp.search(self.line, p)
3417 m = regexp.search(self.line, p)
3418 if not m:
3418 if not m:
3419 break
3419 break
3420 yield m.span()
3420 yield m.span()
3421 p = m.end()
3421 p = m.end()
3422
3422
3423 matches = {}
3423 matches = {}
3424 copies = {}
3424 copies = {}
3425
3425
3426 def grepbody(fn, rev, body):
3426 def grepbody(fn, rev, body):
3427 matches[rev].setdefault(fn, [])
3427 matches[rev].setdefault(fn, [])
3428 m = matches[rev][fn]
3428 m = matches[rev][fn]
3429 if body is None:
3429 if body is None:
3430 return
3430 return
3431
3431
3432 for lnum, cstart, cend, line in matchlines(body):
3432 for lnum, cstart, cend, line in matchlines(body):
3433 s = linestate(line, lnum, cstart, cend)
3433 s = linestate(line, lnum, cstart, cend)
3434 m.append(s)
3434 m.append(s)
3435
3435
3436 def difflinestates(a, b):
3436 def difflinestates(a, b):
3437 sm = difflib.SequenceMatcher(None, a, b)
3437 sm = difflib.SequenceMatcher(None, a, b)
3438 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3438 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3439 if tag == 'insert':
3439 if tag == 'insert':
3440 for i in pycompat.xrange(blo, bhi):
3440 for i in pycompat.xrange(blo, bhi):
3441 yield (b'+', b[i])
3441 yield (b'+', b[i])
3442 elif tag == 'delete':
3442 elif tag == 'delete':
3443 for i in pycompat.xrange(alo, ahi):
3443 for i in pycompat.xrange(alo, ahi):
3444 yield (b'-', a[i])
3444 yield (b'-', a[i])
3445 elif tag == 'replace':
3445 elif tag == 'replace':
3446 for i in pycompat.xrange(alo, ahi):
3446 for i in pycompat.xrange(alo, ahi):
3447 yield (b'-', a[i])
3447 yield (b'-', a[i])
3448 for i in pycompat.xrange(blo, bhi):
3448 for i in pycompat.xrange(blo, bhi):
3449 yield (b'+', b[i])
3449 yield (b'+', b[i])
3450
3450
3451 uipathfn = scmutil.getuipathfn(repo)
3451 uipathfn = scmutil.getuipathfn(repo)
3452
3452
3453 def display(fm, fn, ctx, pstates, states):
3453 def display(fm, fn, ctx, pstates, states):
3454 rev = scmutil.intrev(ctx)
3454 rev = scmutil.intrev(ctx)
3455 if fm.isplain():
3455 if fm.isplain():
3456 formatuser = ui.shortuser
3456 formatuser = ui.shortuser
3457 else:
3457 else:
3458 formatuser = pycompat.bytestr
3458 formatuser = pycompat.bytestr
3459 if ui.quiet:
3459 if ui.quiet:
3460 datefmt = b'%Y-%m-%d'
3460 datefmt = b'%Y-%m-%d'
3461 else:
3461 else:
3462 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3462 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3463 found = False
3463 found = False
3464
3464
3465 @util.cachefunc
3465 @util.cachefunc
3466 def binary():
3466 def binary():
3467 flog = getfile(fn)
3467 flog = getfile(fn)
3468 try:
3468 try:
3469 return stringutil.binary(flog.read(ctx.filenode(fn)))
3469 return stringutil.binary(flog.read(ctx.filenode(fn)))
3470 except error.WdirUnsupported:
3470 except error.WdirUnsupported:
3471 return ctx[fn].isbinary()
3471 return ctx[fn].isbinary()
3472
3472
3473 fieldnamemap = {b'linenumber': b'lineno'}
3473 fieldnamemap = {b'linenumber': b'lineno'}
3474 if diff:
3474 if diff:
3475 iter = difflinestates(pstates, states)
3475 iter = difflinestates(pstates, states)
3476 else:
3476 else:
3477 iter = [(b'', l) for l in states]
3477 iter = [(b'', l) for l in states]
3478 for change, l in iter:
3478 for change, l in iter:
3479 fm.startitem()
3479 fm.startitem()
3480 fm.context(ctx=ctx)
3480 fm.context(ctx=ctx)
3481 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3481 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3482 fm.plain(uipathfn(fn), label=b'grep.filename')
3482 fm.plain(uipathfn(fn), label=b'grep.filename')
3483
3483
3484 cols = [
3484 cols = [
3485 (b'rev', b'%d', rev, not plaingrep, b''),
3485 (b'rev', b'%d', rev, not plaingrep, b''),
3486 (
3486 (
3487 b'linenumber',
3487 b'linenumber',
3488 b'%d',
3488 b'%d',
3489 l.linenum,
3489 l.linenum,
3490 opts.get(b'line_number'),
3490 opts.get(b'line_number'),
3491 b'',
3491 b'',
3492 ),
3492 ),
3493 ]
3493 ]
3494 if diff:
3494 if diff:
3495 cols.append(
3495 cols.append(
3496 (
3496 (
3497 b'change',
3497 b'change',
3498 b'%s',
3498 b'%s',
3499 change,
3499 change,
3500 True,
3500 True,
3501 b'grep.inserted '
3501 b'grep.inserted '
3502 if change == b'+'
3502 if change == b'+'
3503 else b'grep.deleted ',
3503 else b'grep.deleted ',
3504 )
3504 )
3505 )
3505 )
3506 cols.extend(
3506 cols.extend(
3507 [
3507 [
3508 (
3508 (
3509 b'user',
3509 b'user',
3510 b'%s',
3510 b'%s',
3511 formatuser(ctx.user()),
3511 formatuser(ctx.user()),
3512 opts.get(b'user'),
3512 opts.get(b'user'),
3513 b'',
3513 b'',
3514 ),
3514 ),
3515 (
3515 (
3516 b'date',
3516 b'date',
3517 b'%s',
3517 b'%s',
3518 fm.formatdate(ctx.date(), datefmt),
3518 fm.formatdate(ctx.date(), datefmt),
3519 opts.get(b'date'),
3519 opts.get(b'date'),
3520 b'',
3520 b'',
3521 ),
3521 ),
3522 ]
3522 ]
3523 )
3523 )
3524 for name, fmt, data, cond, extra_label in cols:
3524 for name, fmt, data, cond, extra_label in cols:
3525 if cond:
3525 if cond:
3526 fm.plain(sep, label=b'grep.sep')
3526 fm.plain(sep, label=b'grep.sep')
3527 field = fieldnamemap.get(name, name)
3527 field = fieldnamemap.get(name, name)
3528 label = extra_label + (b'grep.%s' % name)
3528 label = extra_label + (b'grep.%s' % name)
3529 fm.condwrite(cond, field, fmt, data, label=label)
3529 fm.condwrite(cond, field, fmt, data, label=label)
3530 if not opts.get(b'files_with_matches'):
3530 if not opts.get(b'files_with_matches'):
3531 fm.plain(sep, label=b'grep.sep')
3531 fm.plain(sep, label=b'grep.sep')
3532 if not opts.get(b'text') and binary():
3532 if not opts.get(b'text') and binary():
3533 fm.plain(_(b" Binary file matches"))
3533 fm.plain(_(b" Binary file matches"))
3534 else:
3534 else:
3535 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3535 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3536 fm.plain(eol)
3536 fm.plain(eol)
3537 found = True
3537 found = True
3538 if opts.get(b'files_with_matches'):
3538 if opts.get(b'files_with_matches'):
3539 break
3539 break
3540 return found
3540 return found
3541
3541
3542 def displaymatches(fm, l):
3542 def displaymatches(fm, l):
3543 p = 0
3543 p = 0
3544 for s, e in l.findpos():
3544 for s, e in l.findpos():
3545 if p < s:
3545 if p < s:
3546 fm.startitem()
3546 fm.startitem()
3547 fm.write(b'text', b'%s', l.line[p:s])
3547 fm.write(b'text', b'%s', l.line[p:s])
3548 fm.data(matched=False)
3548 fm.data(matched=False)
3549 fm.startitem()
3549 fm.startitem()
3550 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3550 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3551 fm.data(matched=True)
3551 fm.data(matched=True)
3552 p = e
3552 p = e
3553 if p < len(l.line):
3553 if p < len(l.line):
3554 fm.startitem()
3554 fm.startitem()
3555 fm.write(b'text', b'%s', l.line[p:])
3555 fm.write(b'text', b'%s', l.line[p:])
3556 fm.data(matched=False)
3556 fm.data(matched=False)
3557 fm.end()
3557 fm.end()
3558
3558
3559 skip = set()
3559 skip = set()
3560 revfiles = {}
3560 revfiles = {}
3561 match = scmutil.match(repo[None], pats, opts)
3561 match = scmutil.match(repo[None], pats, opts)
3562 found = False
3562 found = False
3563 follow = opts.get(b'follow')
3563 follow = opts.get(b'follow')
3564
3564
3565 getrenamed = scmutil.getrenamedfn(repo)
3565 getrenamed = scmutil.getrenamedfn(repo)
3566
3566
3567 def get_file_content(filename, filelog, filenode, context, revision):
3567 def get_file_content(filename, filelog, filenode, context, revision):
3568 try:
3568 try:
3569 content = filelog.read(filenode)
3569 content = filelog.read(filenode)
3570 except error.WdirUnsupported:
3570 except error.WdirUnsupported:
3571 content = context[filename].data()
3571 content = context[filename].data()
3572 except error.CensoredNodeError:
3572 except error.CensoredNodeError:
3573 content = None
3573 content = None
3574 ui.warn(
3574 ui.warn(
3575 _(b'cannot search in censored file: %(filename)s:%(revnum)s\n')
3575 _(b'cannot search in censored file: %(filename)s:%(revnum)s\n')
3576 % {b'filename': filename, b'revnum': pycompat.bytestr(revision)}
3576 % {b'filename': filename, b'revnum': pycompat.bytestr(revision)}
3577 )
3577 )
3578 return content
3578 return content
3579
3579
3580 def prep(ctx, fns):
3580 def prep(ctx, fns):
3581 rev = ctx.rev()
3581 rev = ctx.rev()
3582 pctx = ctx.p1()
3582 pctx = ctx.p1()
3583 parent = pctx.rev()
3583 parent = pctx.rev()
3584 matches.setdefault(rev, {})
3584 matches.setdefault(rev, {})
3585 matches.setdefault(parent, {})
3585 matches.setdefault(parent, {})
3586 files = revfiles.setdefault(rev, [])
3586 files = revfiles.setdefault(rev, [])
3587 for fn in fns:
3587 for fn in fns:
3588 flog = getfile(fn)
3588 flog = getfile(fn)
3589 try:
3589 try:
3590 fnode = ctx.filenode(fn)
3590 fnode = ctx.filenode(fn)
3591 except error.LookupError:
3591 except error.LookupError:
3592 continue
3592 continue
3593
3593
3594 copy = None
3594 copy = None
3595 if follow:
3595 if follow:
3596 copy = getrenamed(fn, rev)
3596 copy = getrenamed(fn, rev)
3597 if copy:
3597 if copy:
3598 copies.setdefault(rev, {})[fn] = copy
3598 copies.setdefault(rev, {})[fn] = copy
3599 if fn in skip:
3599 if fn in skip:
3600 skip.add(copy)
3600 skip.add(copy)
3601 if fn in skip:
3601 if fn in skip:
3602 continue
3602 continue
3603 files.append(fn)
3603 files.append(fn)
3604
3604
3605 if fn not in matches[rev]:
3605 if fn not in matches[rev]:
3606 content = get_file_content(fn, flog, fnode, ctx, rev)
3606 content = get_file_content(fn, flog, fnode, ctx, rev)
3607 grepbody(fn, rev, content)
3607 grepbody(fn, rev, content)
3608
3608
3609 pfn = copy or fn
3609 pfn = copy or fn
3610 if pfn not in matches[parent]:
3610 if pfn not in matches[parent]:
3611 try:
3611 try:
3612 pfnode = pctx.filenode(pfn)
3612 pfnode = pctx.filenode(pfn)
3613 pcontent = get_file_content(pfn, flog, pfnode, pctx, parent)
3613 pcontent = get_file_content(pfn, flog, pfnode, pctx, parent)
3614 grepbody(pfn, parent, pcontent)
3614 grepbody(pfn, parent, pcontent)
3615 except error.LookupError:
3615 except error.LookupError:
3616 pass
3616 pass
3617
3617
3618 ui.pager(b'grep')
3618 ui.pager(b'grep')
3619 fm = ui.formatter(b'grep', opts)
3619 fm = ui.formatter(b'grep', opts)
3620 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
3620 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
3621 rev = ctx.rev()
3621 rev = ctx.rev()
3622 parent = ctx.p1().rev()
3622 parent = ctx.p1().rev()
3623 for fn in sorted(revfiles.get(rev, [])):
3623 for fn in sorted(revfiles.get(rev, [])):
3624 states = matches[rev][fn]
3624 states = matches[rev][fn]
3625 copy = copies.get(rev, {}).get(fn)
3625 copy = copies.get(rev, {}).get(fn)
3626 if fn in skip:
3626 if fn in skip:
3627 if copy:
3627 if copy:
3628 skip.add(copy)
3628 skip.add(copy)
3629 continue
3629 continue
3630 pstates = matches.get(parent, {}).get(copy or fn, [])
3630 pstates = matches.get(parent, {}).get(copy or fn, [])
3631 if pstates or states:
3631 if pstates or states:
3632 r = display(fm, fn, ctx, pstates, states)
3632 r = display(fm, fn, ctx, pstates, states)
3633 found = found or r
3633 found = found or r
3634 if r and not diff and not all_files:
3634 if r and not diff and not all_files:
3635 skip.add(fn)
3635 skip.add(fn)
3636 if copy:
3636 if copy:
3637 skip.add(copy)
3637 skip.add(copy)
3638 del revfiles[rev]
3638 del revfiles[rev]
3639 # We will keep the matches dict for the duration of the window
3639 # We will keep the matches dict for the duration of the window
3640 # clear the matches dict once the window is over
3640 # clear the matches dict once the window is over
3641 if not revfiles:
3641 if not revfiles:
3642 matches.clear()
3642 matches.clear()
3643 fm.end()
3643 fm.end()
3644
3644
3645 return not found
3645 return not found
3646
3646
3647
3647
3648 @command(
3648 @command(
3649 b'heads',
3649 b'heads',
3650 [
3650 [
3651 (
3651 (
3652 b'r',
3652 b'r',
3653 b'rev',
3653 b'rev',
3654 b'',
3654 b'',
3655 _(b'show only heads which are descendants of STARTREV'),
3655 _(b'show only heads which are descendants of STARTREV'),
3656 _(b'STARTREV'),
3656 _(b'STARTREV'),
3657 ),
3657 ),
3658 (b't', b'topo', False, _(b'show topological heads only')),
3658 (b't', b'topo', False, _(b'show topological heads only')),
3659 (
3659 (
3660 b'a',
3660 b'a',
3661 b'active',
3661 b'active',
3662 False,
3662 False,
3663 _(b'show active branchheads only (DEPRECATED)'),
3663 _(b'show active branchheads only (DEPRECATED)'),
3664 ),
3664 ),
3665 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3665 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3666 ]
3666 ]
3667 + templateopts,
3667 + templateopts,
3668 _(b'[-ct] [-r STARTREV] [REV]...'),
3668 _(b'[-ct] [-r STARTREV] [REV]...'),
3669 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3669 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3670 intents={INTENT_READONLY},
3670 intents={INTENT_READONLY},
3671 )
3671 )
3672 def heads(ui, repo, *branchrevs, **opts):
3672 def heads(ui, repo, *branchrevs, **opts):
3673 """show branch heads
3673 """show branch heads
3674
3674
3675 With no arguments, show all open branch heads in the repository.
3675 With no arguments, show all open branch heads in the repository.
3676 Branch heads are changesets that have no descendants on the
3676 Branch heads are changesets that have no descendants on the
3677 same branch. They are where development generally takes place and
3677 same branch. They are where development generally takes place and
3678 are the usual targets for update and merge operations.
3678 are the usual targets for update and merge operations.
3679
3679
3680 If one or more REVs are given, only open branch heads on the
3680 If one or more REVs are given, only open branch heads on the
3681 branches associated with the specified changesets are shown. This
3681 branches associated with the specified changesets are shown. This
3682 means that you can use :hg:`heads .` to see the heads on the
3682 means that you can use :hg:`heads .` to see the heads on the
3683 currently checked-out branch.
3683 currently checked-out branch.
3684
3684
3685 If -c/--closed is specified, also show branch heads marked closed
3685 If -c/--closed is specified, also show branch heads marked closed
3686 (see :hg:`commit --close-branch`).
3686 (see :hg:`commit --close-branch`).
3687
3687
3688 If STARTREV is specified, only those heads that are descendants of
3688 If STARTREV is specified, only those heads that are descendants of
3689 STARTREV will be displayed.
3689 STARTREV will be displayed.
3690
3690
3691 If -t/--topo is specified, named branch mechanics will be ignored and only
3691 If -t/--topo is specified, named branch mechanics will be ignored and only
3692 topological heads (changesets with no children) will be shown.
3692 topological heads (changesets with no children) will be shown.
3693
3693
3694 Returns 0 if matching heads are found, 1 if not.
3694 Returns 0 if matching heads are found, 1 if not.
3695 """
3695 """
3696
3696
3697 opts = pycompat.byteskwargs(opts)
3697 opts = pycompat.byteskwargs(opts)
3698 start = None
3698 start = None
3699 rev = opts.get(b'rev')
3699 rev = opts.get(b'rev')
3700 if rev:
3700 if rev:
3701 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3701 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3702 start = scmutil.revsingle(repo, rev, None).node()
3702 start = scmutil.revsingle(repo, rev, None).node()
3703
3703
3704 if opts.get(b'topo'):
3704 if opts.get(b'topo'):
3705 heads = [repo[h] for h in repo.heads(start)]
3705 heads = [repo[h] for h in repo.heads(start)]
3706 else:
3706 else:
3707 heads = []
3707 heads = []
3708 for branch in repo.branchmap():
3708 for branch in repo.branchmap():
3709 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3709 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3710 heads = [repo[h] for h in heads]
3710 heads = [repo[h] for h in heads]
3711
3711
3712 if branchrevs:
3712 if branchrevs:
3713 branches = set(
3713 branches = set(
3714 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3714 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3715 )
3715 )
3716 heads = [h for h in heads if h.branch() in branches]
3716 heads = [h for h in heads if h.branch() in branches]
3717
3717
3718 if opts.get(b'active') and branchrevs:
3718 if opts.get(b'active') and branchrevs:
3719 dagheads = repo.heads(start)
3719 dagheads = repo.heads(start)
3720 heads = [h for h in heads if h.node() in dagheads]
3720 heads = [h for h in heads if h.node() in dagheads]
3721
3721
3722 if branchrevs:
3722 if branchrevs:
3723 haveheads = set(h.branch() for h in heads)
3723 haveheads = set(h.branch() for h in heads)
3724 if branches - haveheads:
3724 if branches - haveheads:
3725 headless = b', '.join(b for b in branches - haveheads)
3725 headless = b', '.join(b for b in branches - haveheads)
3726 msg = _(b'no open branch heads found on branches %s')
3726 msg = _(b'no open branch heads found on branches %s')
3727 if opts.get(b'rev'):
3727 if opts.get(b'rev'):
3728 msg += _(b' (started at %s)') % opts[b'rev']
3728 msg += _(b' (started at %s)') % opts[b'rev']
3729 ui.warn((msg + b'\n') % headless)
3729 ui.warn((msg + b'\n') % headless)
3730
3730
3731 if not heads:
3731 if not heads:
3732 return 1
3732 return 1
3733
3733
3734 ui.pager(b'heads')
3734 ui.pager(b'heads')
3735 heads = sorted(heads, key=lambda x: -(x.rev()))
3735 heads = sorted(heads, key=lambda x: -(x.rev()))
3736 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3736 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3737 for ctx in heads:
3737 for ctx in heads:
3738 displayer.show(ctx)
3738 displayer.show(ctx)
3739 displayer.close()
3739 displayer.close()
3740
3740
3741
3741
3742 @command(
3742 @command(
3743 b'help',
3743 b'help',
3744 [
3744 [
3745 (b'e', b'extension', None, _(b'show only help for extensions')),
3745 (b'e', b'extension', None, _(b'show only help for extensions')),
3746 (b'c', b'command', None, _(b'show only help for commands')),
3746 (b'c', b'command', None, _(b'show only help for commands')),
3747 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3747 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3748 (
3748 (
3749 b's',
3749 b's',
3750 b'system',
3750 b'system',
3751 [],
3751 [],
3752 _(b'show help for specific platform(s)'),
3752 _(b'show help for specific platform(s)'),
3753 _(b'PLATFORM'),
3753 _(b'PLATFORM'),
3754 ),
3754 ),
3755 ],
3755 ],
3756 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3756 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3757 helpcategory=command.CATEGORY_HELP,
3757 helpcategory=command.CATEGORY_HELP,
3758 norepo=True,
3758 norepo=True,
3759 intents={INTENT_READONLY},
3759 intents={INTENT_READONLY},
3760 )
3760 )
3761 def help_(ui, name=None, **opts):
3761 def help_(ui, name=None, **opts):
3762 """show help for a given topic or a help overview
3762 """show help for a given topic or a help overview
3763
3763
3764 With no arguments, print a list of commands with short help messages.
3764 With no arguments, print a list of commands with short help messages.
3765
3765
3766 Given a topic, extension, or command name, print help for that
3766 Given a topic, extension, or command name, print help for that
3767 topic.
3767 topic.
3768
3768
3769 Returns 0 if successful.
3769 Returns 0 if successful.
3770 """
3770 """
3771
3771
3772 keep = opts.get('system') or []
3772 keep = opts.get('system') or []
3773 if len(keep) == 0:
3773 if len(keep) == 0:
3774 if pycompat.sysplatform.startswith(b'win'):
3774 if pycompat.sysplatform.startswith(b'win'):
3775 keep.append(b'windows')
3775 keep.append(b'windows')
3776 elif pycompat.sysplatform == b'OpenVMS':
3776 elif pycompat.sysplatform == b'OpenVMS':
3777 keep.append(b'vms')
3777 keep.append(b'vms')
3778 elif pycompat.sysplatform == b'plan9':
3778 elif pycompat.sysplatform == b'plan9':
3779 keep.append(b'plan9')
3779 keep.append(b'plan9')
3780 else:
3780 else:
3781 keep.append(b'unix')
3781 keep.append(b'unix')
3782 keep.append(pycompat.sysplatform.lower())
3782 keep.append(pycompat.sysplatform.lower())
3783 if ui.verbose:
3783 if ui.verbose:
3784 keep.append(b'verbose')
3784 keep.append(b'verbose')
3785
3785
3786 commands = sys.modules[__name__]
3786 commands = sys.modules[__name__]
3787 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3787 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3788 ui.pager(b'help')
3788 ui.pager(b'help')
3789 ui.write(formatted)
3789 ui.write(formatted)
3790
3790
3791
3791
3792 @command(
3792 @command(
3793 b'identify|id',
3793 b'identify|id',
3794 [
3794 [
3795 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3795 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3796 (b'n', b'num', None, _(b'show local revision number')),
3796 (b'n', b'num', None, _(b'show local revision number')),
3797 (b'i', b'id', None, _(b'show global revision id')),
3797 (b'i', b'id', None, _(b'show global revision id')),
3798 (b'b', b'branch', None, _(b'show branch')),
3798 (b'b', b'branch', None, _(b'show branch')),
3799 (b't', b'tags', None, _(b'show tags')),
3799 (b't', b'tags', None, _(b'show tags')),
3800 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3800 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3801 ]
3801 ]
3802 + remoteopts
3802 + remoteopts
3803 + formatteropts,
3803 + formatteropts,
3804 _(b'[-nibtB] [-r REV] [SOURCE]'),
3804 _(b'[-nibtB] [-r REV] [SOURCE]'),
3805 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3805 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3806 optionalrepo=True,
3806 optionalrepo=True,
3807 intents={INTENT_READONLY},
3807 intents={INTENT_READONLY},
3808 )
3808 )
3809 def identify(
3809 def identify(
3810 ui,
3810 ui,
3811 repo,
3811 repo,
3812 source=None,
3812 source=None,
3813 rev=None,
3813 rev=None,
3814 num=None,
3814 num=None,
3815 id=None,
3815 id=None,
3816 branch=None,
3816 branch=None,
3817 tags=None,
3817 tags=None,
3818 bookmarks=None,
3818 bookmarks=None,
3819 **opts
3819 **opts
3820 ):
3820 ):
3821 """identify the working directory or specified revision
3821 """identify the working directory or specified revision
3822
3822
3823 Print a summary identifying the repository state at REV using one or
3823 Print a summary identifying the repository state at REV using one or
3824 two parent hash identifiers, followed by a "+" if the working
3824 two parent hash identifiers, followed by a "+" if the working
3825 directory has uncommitted changes, the branch name (if not default),
3825 directory has uncommitted changes, the branch name (if not default),
3826 a list of tags, and a list of bookmarks.
3826 a list of tags, and a list of bookmarks.
3827
3827
3828 When REV is not given, print a summary of the current state of the
3828 When REV is not given, print a summary of the current state of the
3829 repository including the working directory. Specify -r. to get information
3829 repository including the working directory. Specify -r. to get information
3830 of the working directory parent without scanning uncommitted changes.
3830 of the working directory parent without scanning uncommitted changes.
3831
3831
3832 Specifying a path to a repository root or Mercurial bundle will
3832 Specifying a path to a repository root or Mercurial bundle will
3833 cause lookup to operate on that repository/bundle.
3833 cause lookup to operate on that repository/bundle.
3834
3834
3835 .. container:: verbose
3835 .. container:: verbose
3836
3836
3837 Template:
3837 Template:
3838
3838
3839 The following keywords are supported in addition to the common template
3839 The following keywords are supported in addition to the common template
3840 keywords and functions. See also :hg:`help templates`.
3840 keywords and functions. See also :hg:`help templates`.
3841
3841
3842 :dirty: String. Character ``+`` denoting if the working directory has
3842 :dirty: String. Character ``+`` denoting if the working directory has
3843 uncommitted changes.
3843 uncommitted changes.
3844 :id: String. One or two nodes, optionally followed by ``+``.
3844 :id: String. One or two nodes, optionally followed by ``+``.
3845 :parents: List of strings. Parent nodes of the changeset.
3845 :parents: List of strings. Parent nodes of the changeset.
3846
3846
3847 Examples:
3847 Examples:
3848
3848
3849 - generate a build identifier for the working directory::
3849 - generate a build identifier for the working directory::
3850
3850
3851 hg id --id > build-id.dat
3851 hg id --id > build-id.dat
3852
3852
3853 - find the revision corresponding to a tag::
3853 - find the revision corresponding to a tag::
3854
3854
3855 hg id -n -r 1.3
3855 hg id -n -r 1.3
3856
3856
3857 - check the most recent revision of a remote repository::
3857 - check the most recent revision of a remote repository::
3858
3858
3859 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3859 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3860
3860
3861 See :hg:`log` for generating more information about specific revisions,
3861 See :hg:`log` for generating more information about specific revisions,
3862 including full hash identifiers.
3862 including full hash identifiers.
3863
3863
3864 Returns 0 if successful.
3864 Returns 0 if successful.
3865 """
3865 """
3866
3866
3867 opts = pycompat.byteskwargs(opts)
3867 opts = pycompat.byteskwargs(opts)
3868 if not repo and not source:
3868 if not repo and not source:
3869 raise error.Abort(
3869 raise error.Abort(
3870 _(b"there is no Mercurial repository here (.hg not found)")
3870 _(b"there is no Mercurial repository here (.hg not found)")
3871 )
3871 )
3872
3872
3873 default = not (num or id or branch or tags or bookmarks)
3873 default = not (num or id or branch or tags or bookmarks)
3874 output = []
3874 output = []
3875 revs = []
3875 revs = []
3876
3876
3877 if source:
3877 if source:
3878 source, branches = hg.parseurl(ui.expandpath(source))
3878 source, branches = hg.parseurl(ui.expandpath(source))
3879 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3879 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3880 repo = peer.local()
3880 repo = peer.local()
3881 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3881 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3882
3882
3883 fm = ui.formatter(b'identify', opts)
3883 fm = ui.formatter(b'identify', opts)
3884 fm.startitem()
3884 fm.startitem()
3885
3885
3886 if not repo:
3886 if not repo:
3887 if num or branch or tags:
3887 if num or branch or tags:
3888 raise error.Abort(
3888 raise error.Abort(
3889 _(b"can't query remote revision number, branch, or tags")
3889 _(b"can't query remote revision number, branch, or tags")
3890 )
3890 )
3891 if not rev and revs:
3891 if not rev and revs:
3892 rev = revs[0]
3892 rev = revs[0]
3893 if not rev:
3893 if not rev:
3894 rev = b"tip"
3894 rev = b"tip"
3895
3895
3896 remoterev = peer.lookup(rev)
3896 remoterev = peer.lookup(rev)
3897 hexrev = fm.hexfunc(remoterev)
3897 hexrev = fm.hexfunc(remoterev)
3898 if default or id:
3898 if default or id:
3899 output = [hexrev]
3899 output = [hexrev]
3900 fm.data(id=hexrev)
3900 fm.data(id=hexrev)
3901
3901
3902 @util.cachefunc
3902 @util.cachefunc
3903 def getbms():
3903 def getbms():
3904 bms = []
3904 bms = []
3905
3905
3906 if b'bookmarks' in peer.listkeys(b'namespaces'):
3906 if b'bookmarks' in peer.listkeys(b'namespaces'):
3907 hexremoterev = hex(remoterev)
3907 hexremoterev = hex(remoterev)
3908 bms = [
3908 bms = [
3909 bm
3909 bm
3910 for bm, bmr in pycompat.iteritems(
3910 for bm, bmr in pycompat.iteritems(
3911 peer.listkeys(b'bookmarks')
3911 peer.listkeys(b'bookmarks')
3912 )
3912 )
3913 if bmr == hexremoterev
3913 if bmr == hexremoterev
3914 ]
3914 ]
3915
3915
3916 return sorted(bms)
3916 return sorted(bms)
3917
3917
3918 if fm.isplain():
3918 if fm.isplain():
3919 if bookmarks:
3919 if bookmarks:
3920 output.extend(getbms())
3920 output.extend(getbms())
3921 elif default and not ui.quiet:
3921 elif default and not ui.quiet:
3922 # multiple bookmarks for a single parent separated by '/'
3922 # multiple bookmarks for a single parent separated by '/'
3923 bm = b'/'.join(getbms())
3923 bm = b'/'.join(getbms())
3924 if bm:
3924 if bm:
3925 output.append(bm)
3925 output.append(bm)
3926 else:
3926 else:
3927 fm.data(node=hex(remoterev))
3927 fm.data(node=hex(remoterev))
3928 if bookmarks or b'bookmarks' in fm.datahint():
3928 if bookmarks or b'bookmarks' in fm.datahint():
3929 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3929 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3930 else:
3930 else:
3931 if rev:
3931 if rev:
3932 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3932 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3933 ctx = scmutil.revsingle(repo, rev, None)
3933 ctx = scmutil.revsingle(repo, rev, None)
3934
3934
3935 if ctx.rev() is None:
3935 if ctx.rev() is None:
3936 ctx = repo[None]
3936 ctx = repo[None]
3937 parents = ctx.parents()
3937 parents = ctx.parents()
3938 taglist = []
3938 taglist = []
3939 for p in parents:
3939 for p in parents:
3940 taglist.extend(p.tags())
3940 taglist.extend(p.tags())
3941
3941
3942 dirty = b""
3942 dirty = b""
3943 if ctx.dirty(missing=True, merge=False, branch=False):
3943 if ctx.dirty(missing=True, merge=False, branch=False):
3944 dirty = b'+'
3944 dirty = b'+'
3945 fm.data(dirty=dirty)
3945 fm.data(dirty=dirty)
3946
3946
3947 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3947 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3948 if default or id:
3948 if default or id:
3949 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3949 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3950 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3950 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3951
3951
3952 if num:
3952 if num:
3953 numoutput = [b"%d" % p.rev() for p in parents]
3953 numoutput = [b"%d" % p.rev() for p in parents]
3954 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3954 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3955
3955
3956 fm.data(
3956 fm.data(
3957 parents=fm.formatlist(
3957 parents=fm.formatlist(
3958 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3958 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3959 )
3959 )
3960 )
3960 )
3961 else:
3961 else:
3962 hexoutput = fm.hexfunc(ctx.node())
3962 hexoutput = fm.hexfunc(ctx.node())
3963 if default or id:
3963 if default or id:
3964 output = [hexoutput]
3964 output = [hexoutput]
3965 fm.data(id=hexoutput)
3965 fm.data(id=hexoutput)
3966
3966
3967 if num:
3967 if num:
3968 output.append(pycompat.bytestr(ctx.rev()))
3968 output.append(pycompat.bytestr(ctx.rev()))
3969 taglist = ctx.tags()
3969 taglist = ctx.tags()
3970
3970
3971 if default and not ui.quiet:
3971 if default and not ui.quiet:
3972 b = ctx.branch()
3972 b = ctx.branch()
3973 if b != b'default':
3973 if b != b'default':
3974 output.append(b"(%s)" % b)
3974 output.append(b"(%s)" % b)
3975
3975
3976 # multiple tags for a single parent separated by '/'
3976 # multiple tags for a single parent separated by '/'
3977 t = b'/'.join(taglist)
3977 t = b'/'.join(taglist)
3978 if t:
3978 if t:
3979 output.append(t)
3979 output.append(t)
3980
3980
3981 # multiple bookmarks for a single parent separated by '/'
3981 # multiple bookmarks for a single parent separated by '/'
3982 bm = b'/'.join(ctx.bookmarks())
3982 bm = b'/'.join(ctx.bookmarks())
3983 if bm:
3983 if bm:
3984 output.append(bm)
3984 output.append(bm)
3985 else:
3985 else:
3986 if branch:
3986 if branch:
3987 output.append(ctx.branch())
3987 output.append(ctx.branch())
3988
3988
3989 if tags:
3989 if tags:
3990 output.extend(taglist)
3990 output.extend(taglist)
3991
3991
3992 if bookmarks:
3992 if bookmarks:
3993 output.extend(ctx.bookmarks())
3993 output.extend(ctx.bookmarks())
3994
3994
3995 fm.data(node=ctx.hex())
3995 fm.data(node=ctx.hex())
3996 fm.data(branch=ctx.branch())
3996 fm.data(branch=ctx.branch())
3997 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3997 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3998 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3998 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3999 fm.context(ctx=ctx)
3999 fm.context(ctx=ctx)
4000
4000
4001 fm.plain(b"%s\n" % b' '.join(output))
4001 fm.plain(b"%s\n" % b' '.join(output))
4002 fm.end()
4002 fm.end()
4003
4003
4004
4004
4005 @command(
4005 @command(
4006 b'import|patch',
4006 b'import|patch',
4007 [
4007 [
4008 (
4008 (
4009 b'p',
4009 b'p',
4010 b'strip',
4010 b'strip',
4011 1,
4011 1,
4012 _(
4012 _(
4013 b'directory strip option for patch. This has the same '
4013 b'directory strip option for patch. This has the same '
4014 b'meaning as the corresponding patch option'
4014 b'meaning as the corresponding patch option'
4015 ),
4015 ),
4016 _(b'NUM'),
4016 _(b'NUM'),
4017 ),
4017 ),
4018 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4018 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4019 (b'', b'secret', None, _(b'use the secret phase for committing')),
4019 (b'', b'secret', None, _(b'use the secret phase for committing')),
4020 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4020 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4021 (
4021 (
4022 b'f',
4022 b'f',
4023 b'force',
4023 b'force',
4024 None,
4024 None,
4025 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4025 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4026 ),
4026 ),
4027 (
4027 (
4028 b'',
4028 b'',
4029 b'no-commit',
4029 b'no-commit',
4030 None,
4030 None,
4031 _(b"don't commit, just update the working directory"),
4031 _(b"don't commit, just update the working directory"),
4032 ),
4032 ),
4033 (
4033 (
4034 b'',
4034 b'',
4035 b'bypass',
4035 b'bypass',
4036 None,
4036 None,
4037 _(b"apply patch without touching the working directory"),
4037 _(b"apply patch without touching the working directory"),
4038 ),
4038 ),
4039 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4039 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4040 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4040 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4041 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4041 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4042 (
4042 (
4043 b'',
4043 b'',
4044 b'import-branch',
4044 b'import-branch',
4045 None,
4045 None,
4046 _(b'use any branch information in patch (implied by --exact)'),
4046 _(b'use any branch information in patch (implied by --exact)'),
4047 ),
4047 ),
4048 ]
4048 ]
4049 + commitopts
4049 + commitopts
4050 + commitopts2
4050 + commitopts2
4051 + similarityopts,
4051 + similarityopts,
4052 _(b'[OPTION]... PATCH...'),
4052 _(b'[OPTION]... PATCH...'),
4053 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4053 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4054 )
4054 )
4055 def import_(ui, repo, patch1=None, *patches, **opts):
4055 def import_(ui, repo, patch1=None, *patches, **opts):
4056 """import an ordered set of patches
4056 """import an ordered set of patches
4057
4057
4058 Import a list of patches and commit them individually (unless
4058 Import a list of patches and commit them individually (unless
4059 --no-commit is specified).
4059 --no-commit is specified).
4060
4060
4061 To read a patch from standard input (stdin), use "-" as the patch
4061 To read a patch from standard input (stdin), use "-" as the patch
4062 name. If a URL is specified, the patch will be downloaded from
4062 name. If a URL is specified, the patch will be downloaded from
4063 there.
4063 there.
4064
4064
4065 Import first applies changes to the working directory (unless
4065 Import first applies changes to the working directory (unless
4066 --bypass is specified), import will abort if there are outstanding
4066 --bypass is specified), import will abort if there are outstanding
4067 changes.
4067 changes.
4068
4068
4069 Use --bypass to apply and commit patches directly to the
4069 Use --bypass to apply and commit patches directly to the
4070 repository, without affecting the working directory. Without
4070 repository, without affecting the working directory. Without
4071 --exact, patches will be applied on top of the working directory
4071 --exact, patches will be applied on top of the working directory
4072 parent revision.
4072 parent revision.
4073
4073
4074 You can import a patch straight from a mail message. Even patches
4074 You can import a patch straight from a mail message. Even patches
4075 as attachments work (to use the body part, it must have type
4075 as attachments work (to use the body part, it must have type
4076 text/plain or text/x-patch). From and Subject headers of email
4076 text/plain or text/x-patch). From and Subject headers of email
4077 message are used as default committer and commit message. All
4077 message are used as default committer and commit message. All
4078 text/plain body parts before first diff are added to the commit
4078 text/plain body parts before first diff are added to the commit
4079 message.
4079 message.
4080
4080
4081 If the imported patch was generated by :hg:`export`, user and
4081 If the imported patch was generated by :hg:`export`, user and
4082 description from patch override values from message headers and
4082 description from patch override values from message headers and
4083 body. Values given on command line with -m/--message and -u/--user
4083 body. Values given on command line with -m/--message and -u/--user
4084 override these.
4084 override these.
4085
4085
4086 If --exact is specified, import will set the working directory to
4086 If --exact is specified, import will set the working directory to
4087 the parent of each patch before applying it, and will abort if the
4087 the parent of each patch before applying it, and will abort if the
4088 resulting changeset has a different ID than the one recorded in
4088 resulting changeset has a different ID than the one recorded in
4089 the patch. This will guard against various ways that portable
4089 the patch. This will guard against various ways that portable
4090 patch formats and mail systems might fail to transfer Mercurial
4090 patch formats and mail systems might fail to transfer Mercurial
4091 data or metadata. See :hg:`bundle` for lossless transmission.
4091 data or metadata. See :hg:`bundle` for lossless transmission.
4092
4092
4093 Use --partial to ensure a changeset will be created from the patch
4093 Use --partial to ensure a changeset will be created from the patch
4094 even if some hunks fail to apply. Hunks that fail to apply will be
4094 even if some hunks fail to apply. Hunks that fail to apply will be
4095 written to a <target-file>.rej file. Conflicts can then be resolved
4095 written to a <target-file>.rej file. Conflicts can then be resolved
4096 by hand before :hg:`commit --amend` is run to update the created
4096 by hand before :hg:`commit --amend` is run to update the created
4097 changeset. This flag exists to let people import patches that
4097 changeset. This flag exists to let people import patches that
4098 partially apply without losing the associated metadata (author,
4098 partially apply without losing the associated metadata (author,
4099 date, description, ...).
4099 date, description, ...).
4100
4100
4101 .. note::
4101 .. note::
4102
4102
4103 When no hunks apply cleanly, :hg:`import --partial` will create
4103 When no hunks apply cleanly, :hg:`import --partial` will create
4104 an empty changeset, importing only the patch metadata.
4104 an empty changeset, importing only the patch metadata.
4105
4105
4106 With -s/--similarity, hg will attempt to discover renames and
4106 With -s/--similarity, hg will attempt to discover renames and
4107 copies in the patch in the same way as :hg:`addremove`.
4107 copies in the patch in the same way as :hg:`addremove`.
4108
4108
4109 It is possible to use external patch programs to perform the patch
4109 It is possible to use external patch programs to perform the patch
4110 by setting the ``ui.patch`` configuration option. For the default
4110 by setting the ``ui.patch`` configuration option. For the default
4111 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4111 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4112 See :hg:`help config` for more information about configuration
4112 See :hg:`help config` for more information about configuration
4113 files and how to use these options.
4113 files and how to use these options.
4114
4114
4115 See :hg:`help dates` for a list of formats valid for -d/--date.
4115 See :hg:`help dates` for a list of formats valid for -d/--date.
4116
4116
4117 .. container:: verbose
4117 .. container:: verbose
4118
4118
4119 Examples:
4119 Examples:
4120
4120
4121 - import a traditional patch from a website and detect renames::
4121 - import a traditional patch from a website and detect renames::
4122
4122
4123 hg import -s 80 http://example.com/bugfix.patch
4123 hg import -s 80 http://example.com/bugfix.patch
4124
4124
4125 - import a changeset from an hgweb server::
4125 - import a changeset from an hgweb server::
4126
4126
4127 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4127 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4128
4128
4129 - import all the patches in an Unix-style mbox::
4129 - import all the patches in an Unix-style mbox::
4130
4130
4131 hg import incoming-patches.mbox
4131 hg import incoming-patches.mbox
4132
4132
4133 - import patches from stdin::
4133 - import patches from stdin::
4134
4134
4135 hg import -
4135 hg import -
4136
4136
4137 - attempt to exactly restore an exported changeset (not always
4137 - attempt to exactly restore an exported changeset (not always
4138 possible)::
4138 possible)::
4139
4139
4140 hg import --exact proposed-fix.patch
4140 hg import --exact proposed-fix.patch
4141
4141
4142 - use an external tool to apply a patch which is too fuzzy for
4142 - use an external tool to apply a patch which is too fuzzy for
4143 the default internal tool.
4143 the default internal tool.
4144
4144
4145 hg import --config ui.patch="patch --merge" fuzzy.patch
4145 hg import --config ui.patch="patch --merge" fuzzy.patch
4146
4146
4147 - change the default fuzzing from 2 to a less strict 7
4147 - change the default fuzzing from 2 to a less strict 7
4148
4148
4149 hg import --config ui.fuzz=7 fuzz.patch
4149 hg import --config ui.fuzz=7 fuzz.patch
4150
4150
4151 Returns 0 on success, 1 on partial success (see --partial).
4151 Returns 0 on success, 1 on partial success (see --partial).
4152 """
4152 """
4153
4153
4154 opts = pycompat.byteskwargs(opts)
4154 opts = pycompat.byteskwargs(opts)
4155 if not patch1:
4155 if not patch1:
4156 raise error.Abort(_(b'need at least one patch to import'))
4156 raise error.Abort(_(b'need at least one patch to import'))
4157
4157
4158 patches = (patch1,) + patches
4158 patches = (patch1,) + patches
4159
4159
4160 date = opts.get(b'date')
4160 date = opts.get(b'date')
4161 if date:
4161 if date:
4162 opts[b'date'] = dateutil.parsedate(date)
4162 opts[b'date'] = dateutil.parsedate(date)
4163
4163
4164 exact = opts.get(b'exact')
4164 exact = opts.get(b'exact')
4165 update = not opts.get(b'bypass')
4165 update = not opts.get(b'bypass')
4166 if not update and opts.get(b'no_commit'):
4166 if not update and opts.get(b'no_commit'):
4167 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4167 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4168 if opts.get(b'secret') and opts.get(b'no_commit'):
4168 if opts.get(b'secret') and opts.get(b'no_commit'):
4169 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4169 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4170 try:
4170 try:
4171 sim = float(opts.get(b'similarity') or 0)
4171 sim = float(opts.get(b'similarity') or 0)
4172 except ValueError:
4172 except ValueError:
4173 raise error.Abort(_(b'similarity must be a number'))
4173 raise error.Abort(_(b'similarity must be a number'))
4174 if sim < 0 or sim > 100:
4174 if sim < 0 or sim > 100:
4175 raise error.Abort(_(b'similarity must be between 0 and 100'))
4175 raise error.Abort(_(b'similarity must be between 0 and 100'))
4176 if sim and not update:
4176 if sim and not update:
4177 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4177 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4178 if exact:
4178 if exact:
4179 if opts.get(b'edit'):
4179 if opts.get(b'edit'):
4180 raise error.Abort(_(b'cannot use --exact with --edit'))
4180 raise error.Abort(_(b'cannot use --exact with --edit'))
4181 if opts.get(b'prefix'):
4181 if opts.get(b'prefix'):
4182 raise error.Abort(_(b'cannot use --exact with --prefix'))
4182 raise error.Abort(_(b'cannot use --exact with --prefix'))
4183
4183
4184 base = opts[b"base"]
4184 base = opts[b"base"]
4185 msgs = []
4185 msgs = []
4186 ret = 0
4186 ret = 0
4187
4187
4188 with repo.wlock():
4188 with repo.wlock():
4189 if update:
4189 if update:
4190 cmdutil.checkunfinished(repo)
4190 cmdutil.checkunfinished(repo)
4191 if exact or not opts.get(b'force'):
4191 if exact or not opts.get(b'force'):
4192 cmdutil.bailifchanged(repo)
4192 cmdutil.bailifchanged(repo)
4193
4193
4194 if not opts.get(b'no_commit'):
4194 if not opts.get(b'no_commit'):
4195 lock = repo.lock
4195 lock = repo.lock
4196 tr = lambda: repo.transaction(b'import')
4196 tr = lambda: repo.transaction(b'import')
4197 dsguard = util.nullcontextmanager
4197 dsguard = util.nullcontextmanager
4198 else:
4198 else:
4199 lock = util.nullcontextmanager
4199 lock = util.nullcontextmanager
4200 tr = util.nullcontextmanager
4200 tr = util.nullcontextmanager
4201 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4201 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4202 with lock(), tr(), dsguard():
4202 with lock(), tr(), dsguard():
4203 parents = repo[None].parents()
4203 parents = repo[None].parents()
4204 for patchurl in patches:
4204 for patchurl in patches:
4205 if patchurl == b'-':
4205 if patchurl == b'-':
4206 ui.status(_(b'applying patch from stdin\n'))
4206 ui.status(_(b'applying patch from stdin\n'))
4207 patchfile = ui.fin
4207 patchfile = ui.fin
4208 patchurl = b'stdin' # for error message
4208 patchurl = b'stdin' # for error message
4209 else:
4209 else:
4210 patchurl = os.path.join(base, patchurl)
4210 patchurl = os.path.join(base, patchurl)
4211 ui.status(_(b'applying %s\n') % patchurl)
4211 ui.status(_(b'applying %s\n') % patchurl)
4212 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4212 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4213
4213
4214 haspatch = False
4214 haspatch = False
4215 for hunk in patch.split(patchfile):
4215 for hunk in patch.split(patchfile):
4216 with patch.extract(ui, hunk) as patchdata:
4216 with patch.extract(ui, hunk) as patchdata:
4217 msg, node, rej = cmdutil.tryimportone(
4217 msg, node, rej = cmdutil.tryimportone(
4218 ui, repo, patchdata, parents, opts, msgs, hg.clean
4218 ui, repo, patchdata, parents, opts, msgs, hg.clean
4219 )
4219 )
4220 if msg:
4220 if msg:
4221 haspatch = True
4221 haspatch = True
4222 ui.note(msg + b'\n')
4222 ui.note(msg + b'\n')
4223 if update or exact:
4223 if update or exact:
4224 parents = repo[None].parents()
4224 parents = repo[None].parents()
4225 else:
4225 else:
4226 parents = [repo[node]]
4226 parents = [repo[node]]
4227 if rej:
4227 if rej:
4228 ui.write_err(_(b"patch applied partially\n"))
4228 ui.write_err(_(b"patch applied partially\n"))
4229 ui.write_err(
4229 ui.write_err(
4230 _(
4230 _(
4231 b"(fix the .rej files and run "
4231 b"(fix the .rej files and run "
4232 b"`hg commit --amend`)\n"
4232 b"`hg commit --amend`)\n"
4233 )
4233 )
4234 )
4234 )
4235 ret = 1
4235 ret = 1
4236 break
4236 break
4237
4237
4238 if not haspatch:
4238 if not haspatch:
4239 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4239 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4240
4240
4241 if msgs:
4241 if msgs:
4242 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4242 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4243 return ret
4243 return ret
4244
4244
4245
4245
4246 @command(
4246 @command(
4247 b'incoming|in',
4247 b'incoming|in',
4248 [
4248 [
4249 (
4249 (
4250 b'f',
4250 b'f',
4251 b'force',
4251 b'force',
4252 None,
4252 None,
4253 _(b'run even if remote repository is unrelated'),
4253 _(b'run even if remote repository is unrelated'),
4254 ),
4254 ),
4255 (b'n', b'newest-first', None, _(b'show newest record first')),
4255 (b'n', b'newest-first', None, _(b'show newest record first')),
4256 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4256 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4257 (
4257 (
4258 b'r',
4258 b'r',
4259 b'rev',
4259 b'rev',
4260 [],
4260 [],
4261 _(b'a remote changeset intended to be added'),
4261 _(b'a remote changeset intended to be added'),
4262 _(b'REV'),
4262 _(b'REV'),
4263 ),
4263 ),
4264 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4264 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4265 (
4265 (
4266 b'b',
4266 b'b',
4267 b'branch',
4267 b'branch',
4268 [],
4268 [],
4269 _(b'a specific branch you would like to pull'),
4269 _(b'a specific branch you would like to pull'),
4270 _(b'BRANCH'),
4270 _(b'BRANCH'),
4271 ),
4271 ),
4272 ]
4272 ]
4273 + logopts
4273 + logopts
4274 + remoteopts
4274 + remoteopts
4275 + subrepoopts,
4275 + subrepoopts,
4276 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4276 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4277 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4277 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4278 )
4278 )
4279 def incoming(ui, repo, source=b"default", **opts):
4279 def incoming(ui, repo, source=b"default", **opts):
4280 """show new changesets found in source
4280 """show new changesets found in source
4281
4281
4282 Show new changesets found in the specified path/URL or the default
4282 Show new changesets found in the specified path/URL or the default
4283 pull location. These are the changesets that would have been pulled
4283 pull location. These are the changesets that would have been pulled
4284 by :hg:`pull` at the time you issued this command.
4284 by :hg:`pull` at the time you issued this command.
4285
4285
4286 See pull for valid source format details.
4286 See pull for valid source format details.
4287
4287
4288 .. container:: verbose
4288 .. container:: verbose
4289
4289
4290 With -B/--bookmarks, the result of bookmark comparison between
4290 With -B/--bookmarks, the result of bookmark comparison between
4291 local and remote repositories is displayed. With -v/--verbose,
4291 local and remote repositories is displayed. With -v/--verbose,
4292 status is also displayed for each bookmark like below::
4292 status is also displayed for each bookmark like below::
4293
4293
4294 BM1 01234567890a added
4294 BM1 01234567890a added
4295 BM2 1234567890ab advanced
4295 BM2 1234567890ab advanced
4296 BM3 234567890abc diverged
4296 BM3 234567890abc diverged
4297 BM4 34567890abcd changed
4297 BM4 34567890abcd changed
4298
4298
4299 The action taken locally when pulling depends on the
4299 The action taken locally when pulling depends on the
4300 status of each bookmark:
4300 status of each bookmark:
4301
4301
4302 :``added``: pull will create it
4302 :``added``: pull will create it
4303 :``advanced``: pull will update it
4303 :``advanced``: pull will update it
4304 :``diverged``: pull will create a divergent bookmark
4304 :``diverged``: pull will create a divergent bookmark
4305 :``changed``: result depends on remote changesets
4305 :``changed``: result depends on remote changesets
4306
4306
4307 From the point of view of pulling behavior, bookmark
4307 From the point of view of pulling behavior, bookmark
4308 existing only in the remote repository are treated as ``added``,
4308 existing only in the remote repository are treated as ``added``,
4309 even if it is in fact locally deleted.
4309 even if it is in fact locally deleted.
4310
4310
4311 .. container:: verbose
4311 .. container:: verbose
4312
4312
4313 For remote repository, using --bundle avoids downloading the
4313 For remote repository, using --bundle avoids downloading the
4314 changesets twice if the incoming is followed by a pull.
4314 changesets twice if the incoming is followed by a pull.
4315
4315
4316 Examples:
4316 Examples:
4317
4317
4318 - show incoming changes with patches and full description::
4318 - show incoming changes with patches and full description::
4319
4319
4320 hg incoming -vp
4320 hg incoming -vp
4321
4321
4322 - show incoming changes excluding merges, store a bundle::
4322 - show incoming changes excluding merges, store a bundle::
4323
4323
4324 hg in -vpM --bundle incoming.hg
4324 hg in -vpM --bundle incoming.hg
4325 hg pull incoming.hg
4325 hg pull incoming.hg
4326
4326
4327 - briefly list changes inside a bundle::
4327 - briefly list changes inside a bundle::
4328
4328
4329 hg in changes.hg -T "{desc|firstline}\\n"
4329 hg in changes.hg -T "{desc|firstline}\\n"
4330
4330
4331 Returns 0 if there are incoming changes, 1 otherwise.
4331 Returns 0 if there are incoming changes, 1 otherwise.
4332 """
4332 """
4333 opts = pycompat.byteskwargs(opts)
4333 opts = pycompat.byteskwargs(opts)
4334 if opts.get(b'graph'):
4334 if opts.get(b'graph'):
4335 logcmdutil.checkunsupportedgraphflags([], opts)
4335 logcmdutil.checkunsupportedgraphflags([], opts)
4336
4336
4337 def display(other, chlist, displayer):
4337 def display(other, chlist, displayer):
4338 revdag = logcmdutil.graphrevs(other, chlist, opts)
4338 revdag = logcmdutil.graphrevs(other, chlist, opts)
4339 logcmdutil.displaygraph(
4339 logcmdutil.displaygraph(
4340 ui, repo, revdag, displayer, graphmod.asciiedges
4340 ui, repo, revdag, displayer, graphmod.asciiedges
4341 )
4341 )
4342
4342
4343 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4343 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4344 return 0
4344 return 0
4345
4345
4346 if opts.get(b'bundle') and opts.get(b'subrepos'):
4346 if opts.get(b'bundle') and opts.get(b'subrepos'):
4347 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4347 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4348
4348
4349 if opts.get(b'bookmarks'):
4349 if opts.get(b'bookmarks'):
4350 source, branches = hg.parseurl(
4350 source, branches = hg.parseurl(
4351 ui.expandpath(source), opts.get(b'branch')
4351 ui.expandpath(source), opts.get(b'branch')
4352 )
4352 )
4353 other = hg.peer(repo, opts, source)
4353 other = hg.peer(repo, opts, source)
4354 if b'bookmarks' not in other.listkeys(b'namespaces'):
4354 if b'bookmarks' not in other.listkeys(b'namespaces'):
4355 ui.warn(_(b"remote doesn't support bookmarks\n"))
4355 ui.warn(_(b"remote doesn't support bookmarks\n"))
4356 return 0
4356 return 0
4357 ui.pager(b'incoming')
4357 ui.pager(b'incoming')
4358 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4358 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4359 return bookmarks.incoming(ui, repo, other)
4359 return bookmarks.incoming(ui, repo, other)
4360
4360
4361 repo._subtoppath = ui.expandpath(source)
4361 repo._subtoppath = ui.expandpath(source)
4362 try:
4362 try:
4363 return hg.incoming(ui, repo, source, opts)
4363 return hg.incoming(ui, repo, source, opts)
4364 finally:
4364 finally:
4365 del repo._subtoppath
4365 del repo._subtoppath
4366
4366
4367
4367
4368 @command(
4368 @command(
4369 b'init',
4369 b'init',
4370 remoteopts,
4370 remoteopts,
4371 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4371 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4372 helpcategory=command.CATEGORY_REPO_CREATION,
4372 helpcategory=command.CATEGORY_REPO_CREATION,
4373 helpbasic=True,
4373 helpbasic=True,
4374 norepo=True,
4374 norepo=True,
4375 )
4375 )
4376 def init(ui, dest=b".", **opts):
4376 def init(ui, dest=b".", **opts):
4377 """create a new repository in the given directory
4377 """create a new repository in the given directory
4378
4378
4379 Initialize a new repository in the given directory. If the given
4379 Initialize a new repository in the given directory. If the given
4380 directory does not exist, it will be created.
4380 directory does not exist, it will be created.
4381
4381
4382 If no directory is given, the current directory is used.
4382 If no directory is given, the current directory is used.
4383
4383
4384 It is possible to specify an ``ssh://`` URL as the destination.
4384 It is possible to specify an ``ssh://`` URL as the destination.
4385 See :hg:`help urls` for more information.
4385 See :hg:`help urls` for more information.
4386
4386
4387 Returns 0 on success.
4387 Returns 0 on success.
4388 """
4388 """
4389 opts = pycompat.byteskwargs(opts)
4389 opts = pycompat.byteskwargs(opts)
4390 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4390 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4391
4391
4392
4392
4393 @command(
4393 @command(
4394 b'locate',
4394 b'locate',
4395 [
4395 [
4396 (
4396 (
4397 b'r',
4397 b'r',
4398 b'rev',
4398 b'rev',
4399 b'',
4399 b'',
4400 _(b'search the repository as it is in REV'),
4400 _(b'search the repository as it is in REV'),
4401 _(b'REV'),
4401 _(b'REV'),
4402 ),
4402 ),
4403 (
4403 (
4404 b'0',
4404 b'0',
4405 b'print0',
4405 b'print0',
4406 None,
4406 None,
4407 _(b'end filenames with NUL, for use with xargs'),
4407 _(b'end filenames with NUL, for use with xargs'),
4408 ),
4408 ),
4409 (
4409 (
4410 b'f',
4410 b'f',
4411 b'fullpath',
4411 b'fullpath',
4412 None,
4412 None,
4413 _(b'print complete paths from the filesystem root'),
4413 _(b'print complete paths from the filesystem root'),
4414 ),
4414 ),
4415 ]
4415 ]
4416 + walkopts,
4416 + walkopts,
4417 _(b'[OPTION]... [PATTERN]...'),
4417 _(b'[OPTION]... [PATTERN]...'),
4418 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4418 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4419 )
4419 )
4420 def locate(ui, repo, *pats, **opts):
4420 def locate(ui, repo, *pats, **opts):
4421 """locate files matching specific patterns (DEPRECATED)
4421 """locate files matching specific patterns (DEPRECATED)
4422
4422
4423 Print files under Mercurial control in the working directory whose
4423 Print files under Mercurial control in the working directory whose
4424 names match the given patterns.
4424 names match the given patterns.
4425
4425
4426 By default, this command searches all directories in the working
4426 By default, this command searches all directories in the working
4427 directory. To search just the current directory and its
4427 directory. To search just the current directory and its
4428 subdirectories, use "--include .".
4428 subdirectories, use "--include .".
4429
4429
4430 If no patterns are given to match, this command prints the names
4430 If no patterns are given to match, this command prints the names
4431 of all files under Mercurial control in the working directory.
4431 of all files under Mercurial control in the working directory.
4432
4432
4433 If you want to feed the output of this command into the "xargs"
4433 If you want to feed the output of this command into the "xargs"
4434 command, use the -0 option to both this command and "xargs". This
4434 command, use the -0 option to both this command and "xargs". This
4435 will avoid the problem of "xargs" treating single filenames that
4435 will avoid the problem of "xargs" treating single filenames that
4436 contain whitespace as multiple filenames.
4436 contain whitespace as multiple filenames.
4437
4437
4438 See :hg:`help files` for a more versatile command.
4438 See :hg:`help files` for a more versatile command.
4439
4439
4440 Returns 0 if a match is found, 1 otherwise.
4440 Returns 0 if a match is found, 1 otherwise.
4441 """
4441 """
4442 opts = pycompat.byteskwargs(opts)
4442 opts = pycompat.byteskwargs(opts)
4443 if opts.get(b'print0'):
4443 if opts.get(b'print0'):
4444 end = b'\0'
4444 end = b'\0'
4445 else:
4445 else:
4446 end = b'\n'
4446 end = b'\n'
4447 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4447 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4448
4448
4449 ret = 1
4449 ret = 1
4450 m = scmutil.match(
4450 m = scmutil.match(
4451 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4451 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4452 )
4452 )
4453
4453
4454 ui.pager(b'locate')
4454 ui.pager(b'locate')
4455 if ctx.rev() is None:
4455 if ctx.rev() is None:
4456 # When run on the working copy, "locate" includes removed files, so
4456 # When run on the working copy, "locate" includes removed files, so
4457 # we get the list of files from the dirstate.
4457 # we get the list of files from the dirstate.
4458 filesgen = sorted(repo.dirstate.matches(m))
4458 filesgen = sorted(repo.dirstate.matches(m))
4459 else:
4459 else:
4460 filesgen = ctx.matches(m)
4460 filesgen = ctx.matches(m)
4461 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4461 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4462 for abs in filesgen:
4462 for abs in filesgen:
4463 if opts.get(b'fullpath'):
4463 if opts.get(b'fullpath'):
4464 ui.write(repo.wjoin(abs), end)
4464 ui.write(repo.wjoin(abs), end)
4465 else:
4465 else:
4466 ui.write(uipathfn(abs), end)
4466 ui.write(uipathfn(abs), end)
4467 ret = 0
4467 ret = 0
4468
4468
4469 return ret
4469 return ret
4470
4470
4471
4471
4472 @command(
4472 @command(
4473 b'log|history',
4473 b'log|history',
4474 [
4474 [
4475 (
4475 (
4476 b'f',
4476 b'f',
4477 b'follow',
4477 b'follow',
4478 None,
4478 None,
4479 _(
4479 _(
4480 b'follow changeset history, or file history across copies and renames'
4480 b'follow changeset history, or file history across copies and renames'
4481 ),
4481 ),
4482 ),
4482 ),
4483 (
4483 (
4484 b'',
4484 b'',
4485 b'follow-first',
4485 b'follow-first',
4486 None,
4486 None,
4487 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4487 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4488 ),
4488 ),
4489 (
4489 (
4490 b'd',
4490 b'd',
4491 b'date',
4491 b'date',
4492 b'',
4492 b'',
4493 _(b'show revisions matching date spec'),
4493 _(b'show revisions matching date spec'),
4494 _(b'DATE'),
4494 _(b'DATE'),
4495 ),
4495 ),
4496 (b'C', b'copies', None, _(b'show copied files')),
4496 (b'C', b'copies', None, _(b'show copied files')),
4497 (
4497 (
4498 b'k',
4498 b'k',
4499 b'keyword',
4499 b'keyword',
4500 [],
4500 [],
4501 _(b'do case-insensitive search for a given text'),
4501 _(b'do case-insensitive search for a given text'),
4502 _(b'TEXT'),
4502 _(b'TEXT'),
4503 ),
4503 ),
4504 (
4504 (
4505 b'r',
4505 b'r',
4506 b'rev',
4506 b'rev',
4507 [],
4507 [],
4508 _(b'show the specified revision or revset'),
4508 _(b'show the specified revision or revset'),
4509 _(b'REV'),
4509 _(b'REV'),
4510 ),
4510 ),
4511 (
4511 (
4512 b'L',
4512 b'L',
4513 b'line-range',
4513 b'line-range',
4514 [],
4514 [],
4515 _(b'follow line range of specified file (EXPERIMENTAL)'),
4515 _(b'follow line range of specified file (EXPERIMENTAL)'),
4516 _(b'FILE,RANGE'),
4516 _(b'FILE,RANGE'),
4517 ),
4517 ),
4518 (
4518 (
4519 b'',
4519 b'',
4520 b'removed',
4520 b'removed',
4521 None,
4521 None,
4522 _(b'include revisions where files were removed'),
4522 _(b'include revisions where files were removed'),
4523 ),
4523 ),
4524 (
4524 (
4525 b'm',
4525 b'm',
4526 b'only-merges',
4526 b'only-merges',
4527 None,
4527 None,
4528 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4528 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4529 ),
4529 ),
4530 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4530 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4531 (
4531 (
4532 b'',
4532 b'',
4533 b'only-branch',
4533 b'only-branch',
4534 [],
4534 [],
4535 _(
4535 _(
4536 b'show only changesets within the given named branch (DEPRECATED)'
4536 b'show only changesets within the given named branch (DEPRECATED)'
4537 ),
4537 ),
4538 _(b'BRANCH'),
4538 _(b'BRANCH'),
4539 ),
4539 ),
4540 (
4540 (
4541 b'b',
4541 b'b',
4542 b'branch',
4542 b'branch',
4543 [],
4543 [],
4544 _(b'show changesets within the given named branch'),
4544 _(b'show changesets within the given named branch'),
4545 _(b'BRANCH'),
4545 _(b'BRANCH'),
4546 ),
4546 ),
4547 (
4547 (
4548 b'P',
4548 b'P',
4549 b'prune',
4549 b'prune',
4550 [],
4550 [],
4551 _(b'do not display revision or any of its ancestors'),
4551 _(b'do not display revision or any of its ancestors'),
4552 _(b'REV'),
4552 _(b'REV'),
4553 ),
4553 ),
4554 ]
4554 ]
4555 + logopts
4555 + logopts
4556 + walkopts,
4556 + walkopts,
4557 _(b'[OPTION]... [FILE]'),
4557 _(b'[OPTION]... [FILE]'),
4558 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4558 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4559 helpbasic=True,
4559 helpbasic=True,
4560 inferrepo=True,
4560 inferrepo=True,
4561 intents={INTENT_READONLY},
4561 intents={INTENT_READONLY},
4562 )
4562 )
4563 def log(ui, repo, *pats, **opts):
4563 def log(ui, repo, *pats, **opts):
4564 """show revision history of entire repository or files
4564 """show revision history of entire repository or files
4565
4565
4566 Print the revision history of the specified files or the entire
4566 Print the revision history of the specified files or the entire
4567 project.
4567 project.
4568
4568
4569 If no revision range is specified, the default is ``tip:0`` unless
4569 If no revision range is specified, the default is ``tip:0`` unless
4570 --follow is set, in which case the working directory parent is
4570 --follow is set, in which case the working directory parent is
4571 used as the starting revision.
4571 used as the starting revision.
4572
4572
4573 File history is shown without following rename or copy history of
4573 File history is shown without following rename or copy history of
4574 files. Use -f/--follow with a filename to follow history across
4574 files. Use -f/--follow with a filename to follow history across
4575 renames and copies. --follow without a filename will only show
4575 renames and copies. --follow without a filename will only show
4576 ancestors of the starting revision.
4576 ancestors of the starting revision.
4577
4577
4578 By default this command prints revision number and changeset id,
4578 By default this command prints revision number and changeset id,
4579 tags, non-trivial parents, user, date and time, and a summary for
4579 tags, non-trivial parents, user, date and time, and a summary for
4580 each commit. When the -v/--verbose switch is used, the list of
4580 each commit. When the -v/--verbose switch is used, the list of
4581 changed files and full commit message are shown.
4581 changed files and full commit message are shown.
4582
4582
4583 With --graph the revisions are shown as an ASCII art DAG with the most
4583 With --graph the revisions are shown as an ASCII art DAG with the most
4584 recent changeset at the top.
4584 recent changeset at the top.
4585 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
4585 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
4586 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4586 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4587 changeset from the lines below is a parent of the 'o' merge on the same
4587 changeset from the lines below is a parent of the 'o' merge on the same
4588 line.
4588 line.
4589 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4589 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4590 of a '|' indicates one or more revisions in a path are omitted.
4590 of a '|' indicates one or more revisions in a path are omitted.
4591
4591
4592 .. container:: verbose
4592 .. container:: verbose
4593
4593
4594 Use -L/--line-range FILE,M:N options to follow the history of lines
4594 Use -L/--line-range FILE,M:N options to follow the history of lines
4595 from M to N in FILE. With -p/--patch only diff hunks affecting
4595 from M to N in FILE. With -p/--patch only diff hunks affecting
4596 specified line range will be shown. This option requires --follow;
4596 specified line range will be shown. This option requires --follow;
4597 it can be specified multiple times. Currently, this option is not
4597 it can be specified multiple times. Currently, this option is not
4598 compatible with --graph. This option is experimental.
4598 compatible with --graph. This option is experimental.
4599
4599
4600 .. note::
4600 .. note::
4601
4601
4602 :hg:`log --patch` may generate unexpected diff output for merge
4602 :hg:`log --patch` may generate unexpected diff output for merge
4603 changesets, as it will only compare the merge changeset against
4603 changesets, as it will only compare the merge changeset against
4604 its first parent. Also, only files different from BOTH parents
4604 its first parent. Also, only files different from BOTH parents
4605 will appear in files:.
4605 will appear in files:.
4606
4606
4607 .. note::
4607 .. note::
4608
4608
4609 For performance reasons, :hg:`log FILE` may omit duplicate changes
4609 For performance reasons, :hg:`log FILE` may omit duplicate changes
4610 made on branches and will not show removals or mode changes. To
4610 made on branches and will not show removals or mode changes. To
4611 see all such changes, use the --removed switch.
4611 see all such changes, use the --removed switch.
4612
4612
4613 .. container:: verbose
4613 .. container:: verbose
4614
4614
4615 .. note::
4615 .. note::
4616
4616
4617 The history resulting from -L/--line-range options depends on diff
4617 The history resulting from -L/--line-range options depends on diff
4618 options; for instance if white-spaces are ignored, respective changes
4618 options; for instance if white-spaces are ignored, respective changes
4619 with only white-spaces in specified line range will not be listed.
4619 with only white-spaces in specified line range will not be listed.
4620
4620
4621 .. container:: verbose
4621 .. container:: verbose
4622
4622
4623 Some examples:
4623 Some examples:
4624
4624
4625 - changesets with full descriptions and file lists::
4625 - changesets with full descriptions and file lists::
4626
4626
4627 hg log -v
4627 hg log -v
4628
4628
4629 - changesets ancestral to the working directory::
4629 - changesets ancestral to the working directory::
4630
4630
4631 hg log -f
4631 hg log -f
4632
4632
4633 - last 10 commits on the current branch::
4633 - last 10 commits on the current branch::
4634
4634
4635 hg log -l 10 -b .
4635 hg log -l 10 -b .
4636
4636
4637 - changesets showing all modifications of a file, including removals::
4637 - changesets showing all modifications of a file, including removals::
4638
4638
4639 hg log --removed file.c
4639 hg log --removed file.c
4640
4640
4641 - all changesets that touch a directory, with diffs, excluding merges::
4641 - all changesets that touch a directory, with diffs, excluding merges::
4642
4642
4643 hg log -Mp lib/
4643 hg log -Mp lib/
4644
4644
4645 - all revision numbers that match a keyword::
4645 - all revision numbers that match a keyword::
4646
4646
4647 hg log -k bug --template "{rev}\\n"
4647 hg log -k bug --template "{rev}\\n"
4648
4648
4649 - the full hash identifier of the working directory parent::
4649 - the full hash identifier of the working directory parent::
4650
4650
4651 hg log -r . --template "{node}\\n"
4651 hg log -r . --template "{node}\\n"
4652
4652
4653 - list available log templates::
4653 - list available log templates::
4654
4654
4655 hg log -T list
4655 hg log -T list
4656
4656
4657 - check if a given changeset is included in a tagged release::
4657 - check if a given changeset is included in a tagged release::
4658
4658
4659 hg log -r "a21ccf and ancestor(1.9)"
4659 hg log -r "a21ccf and ancestor(1.9)"
4660
4660
4661 - find all changesets by some user in a date range::
4661 - find all changesets by some user in a date range::
4662
4662
4663 hg log -k alice -d "may 2008 to jul 2008"
4663 hg log -k alice -d "may 2008 to jul 2008"
4664
4664
4665 - summary of all changesets after the last tag::
4665 - summary of all changesets after the last tag::
4666
4666
4667 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4667 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4668
4668
4669 - changesets touching lines 13 to 23 for file.c::
4669 - changesets touching lines 13 to 23 for file.c::
4670
4670
4671 hg log -L file.c,13:23
4671 hg log -L file.c,13:23
4672
4672
4673 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4673 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4674 main.c with patch::
4674 main.c with patch::
4675
4675
4676 hg log -L file.c,13:23 -L main.c,2:6 -p
4676 hg log -L file.c,13:23 -L main.c,2:6 -p
4677
4677
4678 See :hg:`help dates` for a list of formats valid for -d/--date.
4678 See :hg:`help dates` for a list of formats valid for -d/--date.
4679
4679
4680 See :hg:`help revisions` for more about specifying and ordering
4680 See :hg:`help revisions` for more about specifying and ordering
4681 revisions.
4681 revisions.
4682
4682
4683 See :hg:`help templates` for more about pre-packaged styles and
4683 See :hg:`help templates` for more about pre-packaged styles and
4684 specifying custom templates. The default template used by the log
4684 specifying custom templates. The default template used by the log
4685 command can be customized via the ``ui.logtemplate`` configuration
4685 command can be customized via the ``ui.logtemplate`` configuration
4686 setting.
4686 setting.
4687
4687
4688 Returns 0 on success.
4688 Returns 0 on success.
4689
4689
4690 """
4690 """
4691 opts = pycompat.byteskwargs(opts)
4691 opts = pycompat.byteskwargs(opts)
4692 linerange = opts.get(b'line_range')
4692 linerange = opts.get(b'line_range')
4693
4693
4694 if linerange and not opts.get(b'follow'):
4694 if linerange and not opts.get(b'follow'):
4695 raise error.Abort(_(b'--line-range requires --follow'))
4695 raise error.Abort(_(b'--line-range requires --follow'))
4696
4696
4697 if linerange and pats:
4697 if linerange and pats:
4698 # TODO: take pats as patterns with no line-range filter
4698 # TODO: take pats as patterns with no line-range filter
4699 raise error.Abort(
4699 raise error.Abort(
4700 _(b'FILE arguments are not compatible with --line-range option')
4700 _(b'FILE arguments are not compatible with --line-range option')
4701 )
4701 )
4702
4702
4703 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4703 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4704 revs, differ = logcmdutil.getrevs(repo, pats, opts)
4704 revs, differ = logcmdutil.getrevs(repo, pats, opts)
4705 if linerange:
4705 if linerange:
4706 # TODO: should follow file history from logcmdutil._initialrevs(),
4706 # TODO: should follow file history from logcmdutil._initialrevs(),
4707 # then filter the result by logcmdutil._makerevset() and --limit
4707 # then filter the result by logcmdutil._makerevset() and --limit
4708 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4708 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4709
4709
4710 getcopies = None
4710 getcopies = None
4711 if opts.get(b'copies'):
4711 if opts.get(b'copies'):
4712 endrev = None
4712 endrev = None
4713 if revs:
4713 if revs:
4714 endrev = revs.max() + 1
4714 endrev = revs.max() + 1
4715 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4715 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4716
4716
4717 ui.pager(b'log')
4717 ui.pager(b'log')
4718 displayer = logcmdutil.changesetdisplayer(
4718 displayer = logcmdutil.changesetdisplayer(
4719 ui, repo, opts, differ, buffered=True
4719 ui, repo, opts, differ, buffered=True
4720 )
4720 )
4721 if opts.get(b'graph'):
4721 if opts.get(b'graph'):
4722 displayfn = logcmdutil.displaygraphrevs
4722 displayfn = logcmdutil.displaygraphrevs
4723 else:
4723 else:
4724 displayfn = logcmdutil.displayrevs
4724 displayfn = logcmdutil.displayrevs
4725 displayfn(ui, repo, revs, displayer, getcopies)
4725 displayfn(ui, repo, revs, displayer, getcopies)
4726
4726
4727
4727
4728 @command(
4728 @command(
4729 b'manifest',
4729 b'manifest',
4730 [
4730 [
4731 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4731 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4732 (b'', b'all', False, _(b"list files from all revisions")),
4732 (b'', b'all', False, _(b"list files from all revisions")),
4733 ]
4733 ]
4734 + formatteropts,
4734 + formatteropts,
4735 _(b'[-r REV]'),
4735 _(b'[-r REV]'),
4736 helpcategory=command.CATEGORY_MAINTENANCE,
4736 helpcategory=command.CATEGORY_MAINTENANCE,
4737 intents={INTENT_READONLY},
4737 intents={INTENT_READONLY},
4738 )
4738 )
4739 def manifest(ui, repo, node=None, rev=None, **opts):
4739 def manifest(ui, repo, node=None, rev=None, **opts):
4740 """output the current or given revision of the project manifest
4740 """output the current or given revision of the project manifest
4741
4741
4742 Print a list of version controlled files for the given revision.
4742 Print a list of version controlled files for the given revision.
4743 If no revision is given, the first parent of the working directory
4743 If no revision is given, the first parent of the working directory
4744 is used, or the null revision if no revision is checked out.
4744 is used, or the null revision if no revision is checked out.
4745
4745
4746 With -v, print file permissions, symlink and executable bits.
4746 With -v, print file permissions, symlink and executable bits.
4747 With --debug, print file revision hashes.
4747 With --debug, print file revision hashes.
4748
4748
4749 If option --all is specified, the list of all files from all revisions
4749 If option --all is specified, the list of all files from all revisions
4750 is printed. This includes deleted and renamed files.
4750 is printed. This includes deleted and renamed files.
4751
4751
4752 Returns 0 on success.
4752 Returns 0 on success.
4753 """
4753 """
4754 opts = pycompat.byteskwargs(opts)
4754 opts = pycompat.byteskwargs(opts)
4755 fm = ui.formatter(b'manifest', opts)
4755 fm = ui.formatter(b'manifest', opts)
4756
4756
4757 if opts.get(b'all'):
4757 if opts.get(b'all'):
4758 if rev or node:
4758 if rev or node:
4759 raise error.Abort(_(b"can't specify a revision with --all"))
4759 raise error.Abort(_(b"can't specify a revision with --all"))
4760
4760
4761 res = set()
4761 res = set()
4762 for rev in repo:
4762 for rev in repo:
4763 ctx = repo[rev]
4763 ctx = repo[rev]
4764 res |= set(ctx.files())
4764 res |= set(ctx.files())
4765
4765
4766 ui.pager(b'manifest')
4766 ui.pager(b'manifest')
4767 for f in sorted(res):
4767 for f in sorted(res):
4768 fm.startitem()
4768 fm.startitem()
4769 fm.write(b"path", b'%s\n', f)
4769 fm.write(b"path", b'%s\n', f)
4770 fm.end()
4770 fm.end()
4771 return
4771 return
4772
4772
4773 if rev and node:
4773 if rev and node:
4774 raise error.Abort(_(b"please specify just one revision"))
4774 raise error.Abort(_(b"please specify just one revision"))
4775
4775
4776 if not node:
4776 if not node:
4777 node = rev
4777 node = rev
4778
4778
4779 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4779 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4780 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4780 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4781 if node:
4781 if node:
4782 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4782 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4783 ctx = scmutil.revsingle(repo, node)
4783 ctx = scmutil.revsingle(repo, node)
4784 mf = ctx.manifest()
4784 mf = ctx.manifest()
4785 ui.pager(b'manifest')
4785 ui.pager(b'manifest')
4786 for f in ctx:
4786 for f in ctx:
4787 fm.startitem()
4787 fm.startitem()
4788 fm.context(ctx=ctx)
4788 fm.context(ctx=ctx)
4789 fl = ctx[f].flags()
4789 fl = ctx[f].flags()
4790 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4790 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4791 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4791 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4792 fm.write(b'path', b'%s\n', f)
4792 fm.write(b'path', b'%s\n', f)
4793 fm.end()
4793 fm.end()
4794
4794
4795
4795
4796 @command(
4796 @command(
4797 b'merge',
4797 b'merge',
4798 [
4798 [
4799 (
4799 (
4800 b'f',
4800 b'f',
4801 b'force',
4801 b'force',
4802 None,
4802 None,
4803 _(b'force a merge including outstanding changes (DEPRECATED)'),
4803 _(b'force a merge including outstanding changes (DEPRECATED)'),
4804 ),
4804 ),
4805 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4805 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4806 (
4806 (
4807 b'P',
4807 b'P',
4808 b'preview',
4808 b'preview',
4809 None,
4809 None,
4810 _(b'review revisions to merge (no merge is performed)'),
4810 _(b'review revisions to merge (no merge is performed)'),
4811 ),
4811 ),
4812 (b'', b'abort', None, _(b'abort the ongoing merge')),
4812 (b'', b'abort', None, _(b'abort the ongoing merge')),
4813 ]
4813 ]
4814 + mergetoolopts,
4814 + mergetoolopts,
4815 _(b'[-P] [[-r] REV]'),
4815 _(b'[-P] [[-r] REV]'),
4816 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4816 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4817 helpbasic=True,
4817 helpbasic=True,
4818 )
4818 )
4819 def merge(ui, repo, node=None, **opts):
4819 def merge(ui, repo, node=None, **opts):
4820 """merge another revision into working directory
4820 """merge another revision into working directory
4821
4821
4822 The current working directory is updated with all changes made in
4822 The current working directory is updated with all changes made in
4823 the requested revision since the last common predecessor revision.
4823 the requested revision since the last common predecessor revision.
4824
4824
4825 Files that changed between either parent are marked as changed for
4825 Files that changed between either parent are marked as changed for
4826 the next commit and a commit must be performed before any further
4826 the next commit and a commit must be performed before any further
4827 updates to the repository are allowed. The next commit will have
4827 updates to the repository are allowed. The next commit will have
4828 two parents.
4828 two parents.
4829
4829
4830 ``--tool`` can be used to specify the merge tool used for file
4830 ``--tool`` can be used to specify the merge tool used for file
4831 merges. It overrides the HGMERGE environment variable and your
4831 merges. It overrides the HGMERGE environment variable and your
4832 configuration files. See :hg:`help merge-tools` for options.
4832 configuration files. See :hg:`help merge-tools` for options.
4833
4833
4834 If no revision is specified, the working directory's parent is a
4834 If no revision is specified, the working directory's parent is a
4835 head revision, and the current branch contains exactly one other
4835 head revision, and the current branch contains exactly one other
4836 head, the other head is merged with by default. Otherwise, an
4836 head, the other head is merged with by default. Otherwise, an
4837 explicit revision with which to merge must be provided.
4837 explicit revision with which to merge must be provided.
4838
4838
4839 See :hg:`help resolve` for information on handling file conflicts.
4839 See :hg:`help resolve` for information on handling file conflicts.
4840
4840
4841 To undo an uncommitted merge, use :hg:`merge --abort` which
4841 To undo an uncommitted merge, use :hg:`merge --abort` which
4842 will check out a clean copy of the original merge parent, losing
4842 will check out a clean copy of the original merge parent, losing
4843 all changes.
4843 all changes.
4844
4844
4845 Returns 0 on success, 1 if there are unresolved files.
4845 Returns 0 on success, 1 if there are unresolved files.
4846 """
4846 """
4847
4847
4848 opts = pycompat.byteskwargs(opts)
4848 opts = pycompat.byteskwargs(opts)
4849 abort = opts.get(b'abort')
4849 abort = opts.get(b'abort')
4850 if abort and repo.dirstate.p2() == nullid:
4850 if abort and repo.dirstate.p2() == nullid:
4851 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4851 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4852 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4852 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4853 if abort:
4853 if abort:
4854 state = cmdutil.getunfinishedstate(repo)
4854 state = cmdutil.getunfinishedstate(repo)
4855 if state and state._opname != b'merge':
4855 if state and state._opname != b'merge':
4856 raise error.Abort(
4856 raise error.Abort(
4857 _(b'cannot abort merge with %s in progress') % (state._opname),
4857 _(b'cannot abort merge with %s in progress') % (state._opname),
4858 hint=state.hint(),
4858 hint=state.hint(),
4859 )
4859 )
4860 if node:
4860 if node:
4861 raise error.Abort(_(b"cannot specify a node with --abort"))
4861 raise error.Abort(_(b"cannot specify a node with --abort"))
4862 return hg.abortmerge(repo.ui, repo)
4862 return hg.abortmerge(repo.ui, repo)
4863
4863
4864 if opts.get(b'rev') and node:
4864 if opts.get(b'rev') and node:
4865 raise error.Abort(_(b"please specify just one revision"))
4865 raise error.Abort(_(b"please specify just one revision"))
4866 if not node:
4866 if not node:
4867 node = opts.get(b'rev')
4867 node = opts.get(b'rev')
4868
4868
4869 if node:
4869 if node:
4870 node = scmutil.revsingle(repo, node).node()
4870 node = scmutil.revsingle(repo, node).node()
4871 else:
4871 else:
4872 if ui.configbool(b'commands', b'merge.require-rev'):
4872 if ui.configbool(b'commands', b'merge.require-rev'):
4873 raise error.Abort(
4873 raise error.Abort(
4874 _(
4874 _(
4875 b'configuration requires specifying revision to merge '
4875 b'configuration requires specifying revision to merge '
4876 b'with'
4876 b'with'
4877 )
4877 )
4878 )
4878 )
4879 node = repo[destutil.destmerge(repo)].node()
4879 node = repo[destutil.destmerge(repo)].node()
4880
4880
4881 if node is None:
4881 if node is None:
4882 raise error.Abort(_(b'merging with the working copy has no effect'))
4882 raise error.Abort(_(b'merging with the working copy has no effect'))
4883
4883
4884 if opts.get(b'preview'):
4884 if opts.get(b'preview'):
4885 # find nodes that are ancestors of p2 but not of p1
4885 # find nodes that are ancestors of p2 but not of p1
4886 p1 = repo[b'.'].node()
4886 p1 = repo[b'.'].node()
4887 p2 = node
4887 p2 = node
4888 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4888 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4889
4889
4890 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4890 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4891 for node in nodes:
4891 for node in nodes:
4892 displayer.show(repo[node])
4892 displayer.show(repo[node])
4893 displayer.close()
4893 displayer.close()
4894 return 0
4894 return 0
4895
4895
4896 # ui.forcemerge is an internal variable, do not document
4896 # ui.forcemerge is an internal variable, do not document
4897 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4897 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4898 with ui.configoverride(overrides, b'merge'):
4898 with ui.configoverride(overrides, b'merge'):
4899 force = opts.get(b'force')
4899 force = opts.get(b'force')
4900 labels = [b'working copy', b'merge rev']
4900 labels = [b'working copy', b'merge rev']
4901 return hg.merge(
4901 return hg.merge(
4902 repo, node, force=force, mergeforce=force, labels=labels
4902 repo, node, force=force, mergeforce=force, labels=labels
4903 )
4903 )
4904
4904
4905
4905
4906 statemod.addunfinished(
4906 statemod.addunfinished(
4907 b'merge',
4907 b'merge',
4908 fname=None,
4908 fname=None,
4909 clearable=True,
4909 clearable=True,
4910 allowcommit=True,
4910 allowcommit=True,
4911 cmdmsg=_(b'outstanding uncommitted merge'),
4911 cmdmsg=_(b'outstanding uncommitted merge'),
4912 abortfunc=hg.abortmerge,
4912 abortfunc=hg.abortmerge,
4913 statushint=_(
4913 statushint=_(
4914 b'To continue: hg commit\nTo abort: hg merge --abort'
4914 b'To continue: hg commit\nTo abort: hg merge --abort'
4915 ),
4915 ),
4916 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4916 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4917 )
4917 )
4918
4918
4919
4919
4920 @command(
4920 @command(
4921 b'outgoing|out',
4921 b'outgoing|out',
4922 [
4922 [
4923 (
4923 (
4924 b'f',
4924 b'f',
4925 b'force',
4925 b'force',
4926 None,
4926 None,
4927 _(b'run even when the destination is unrelated'),
4927 _(b'run even when the destination is unrelated'),
4928 ),
4928 ),
4929 (
4929 (
4930 b'r',
4930 b'r',
4931 b'rev',
4931 b'rev',
4932 [],
4932 [],
4933 _(b'a changeset intended to be included in the destination'),
4933 _(b'a changeset intended to be included in the destination'),
4934 _(b'REV'),
4934 _(b'REV'),
4935 ),
4935 ),
4936 (b'n', b'newest-first', None, _(b'show newest record first')),
4936 (b'n', b'newest-first', None, _(b'show newest record first')),
4937 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4937 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4938 (
4938 (
4939 b'b',
4939 b'b',
4940 b'branch',
4940 b'branch',
4941 [],
4941 [],
4942 _(b'a specific branch you would like to push'),
4942 _(b'a specific branch you would like to push'),
4943 _(b'BRANCH'),
4943 _(b'BRANCH'),
4944 ),
4944 ),
4945 ]
4945 ]
4946 + logopts
4946 + logopts
4947 + remoteopts
4947 + remoteopts
4948 + subrepoopts,
4948 + subrepoopts,
4949 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4949 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4950 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4950 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4951 )
4951 )
4952 def outgoing(ui, repo, dest=None, **opts):
4952 def outgoing(ui, repo, dest=None, **opts):
4953 """show changesets not found in the destination
4953 """show changesets not found in the destination
4954
4954
4955 Show changesets not found in the specified destination repository
4955 Show changesets not found in the specified destination repository
4956 or the default push location. These are the changesets that would
4956 or the default push location. These are the changesets that would
4957 be pushed if a push was requested.
4957 be pushed if a push was requested.
4958
4958
4959 See pull for details of valid destination formats.
4959 See pull for details of valid destination formats.
4960
4960
4961 .. container:: verbose
4961 .. container:: verbose
4962
4962
4963 With -B/--bookmarks, the result of bookmark comparison between
4963 With -B/--bookmarks, the result of bookmark comparison between
4964 local and remote repositories is displayed. With -v/--verbose,
4964 local and remote repositories is displayed. With -v/--verbose,
4965 status is also displayed for each bookmark like below::
4965 status is also displayed for each bookmark like below::
4966
4966
4967 BM1 01234567890a added
4967 BM1 01234567890a added
4968 BM2 deleted
4968 BM2 deleted
4969 BM3 234567890abc advanced
4969 BM3 234567890abc advanced
4970 BM4 34567890abcd diverged
4970 BM4 34567890abcd diverged
4971 BM5 4567890abcde changed
4971 BM5 4567890abcde changed
4972
4972
4973 The action taken when pushing depends on the
4973 The action taken when pushing depends on the
4974 status of each bookmark:
4974 status of each bookmark:
4975
4975
4976 :``added``: push with ``-B`` will create it
4976 :``added``: push with ``-B`` will create it
4977 :``deleted``: push with ``-B`` will delete it
4977 :``deleted``: push with ``-B`` will delete it
4978 :``advanced``: push will update it
4978 :``advanced``: push will update it
4979 :``diverged``: push with ``-B`` will update it
4979 :``diverged``: push with ``-B`` will update it
4980 :``changed``: push with ``-B`` will update it
4980 :``changed``: push with ``-B`` will update it
4981
4981
4982 From the point of view of pushing behavior, bookmarks
4982 From the point of view of pushing behavior, bookmarks
4983 existing only in the remote repository are treated as
4983 existing only in the remote repository are treated as
4984 ``deleted``, even if it is in fact added remotely.
4984 ``deleted``, even if it is in fact added remotely.
4985
4985
4986 Returns 0 if there are outgoing changes, 1 otherwise.
4986 Returns 0 if there are outgoing changes, 1 otherwise.
4987 """
4987 """
4988 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4988 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4989 # style URLs, so don't overwrite dest.
4989 # style URLs, so don't overwrite dest.
4990 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4990 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4991 if not path:
4991 if not path:
4992 raise error.Abort(
4992 raise error.Abort(
4993 _(b'default repository not configured!'),
4993 _(b'default repository not configured!'),
4994 hint=_(b"see 'hg help config.paths'"),
4994 hint=_(b"see 'hg help config.paths'"),
4995 )
4995 )
4996
4996
4997 opts = pycompat.byteskwargs(opts)
4997 opts = pycompat.byteskwargs(opts)
4998 if opts.get(b'graph'):
4998 if opts.get(b'graph'):
4999 logcmdutil.checkunsupportedgraphflags([], opts)
4999 logcmdutil.checkunsupportedgraphflags([], opts)
5000 o, other = hg._outgoing(ui, repo, dest, opts)
5000 o, other = hg._outgoing(ui, repo, dest, opts)
5001 if not o:
5001 if not o:
5002 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5002 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5003 return
5003 return
5004
5004
5005 revdag = logcmdutil.graphrevs(repo, o, opts)
5005 revdag = logcmdutil.graphrevs(repo, o, opts)
5006 ui.pager(b'outgoing')
5006 ui.pager(b'outgoing')
5007 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
5007 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
5008 logcmdutil.displaygraph(
5008 logcmdutil.displaygraph(
5009 ui, repo, revdag, displayer, graphmod.asciiedges
5009 ui, repo, revdag, displayer, graphmod.asciiedges
5010 )
5010 )
5011 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5011 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5012 return 0
5012 return 0
5013
5013
5014 if opts.get(b'bookmarks'):
5014 if opts.get(b'bookmarks'):
5015 dest = path.pushloc or path.loc
5015 dest = path.pushloc or path.loc
5016 other = hg.peer(repo, opts, dest)
5016 other = hg.peer(repo, opts, dest)
5017 if b'bookmarks' not in other.listkeys(b'namespaces'):
5017 if b'bookmarks' not in other.listkeys(b'namespaces'):
5018 ui.warn(_(b"remote doesn't support bookmarks\n"))
5018 ui.warn(_(b"remote doesn't support bookmarks\n"))
5019 return 0
5019 return 0
5020 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5020 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5021 ui.pager(b'outgoing')
5021 ui.pager(b'outgoing')
5022 return bookmarks.outgoing(ui, repo, other)
5022 return bookmarks.outgoing(ui, repo, other)
5023
5023
5024 repo._subtoppath = path.pushloc or path.loc
5024 repo._subtoppath = path.pushloc or path.loc
5025 try:
5025 try:
5026 return hg.outgoing(ui, repo, dest, opts)
5026 return hg.outgoing(ui, repo, dest, opts)
5027 finally:
5027 finally:
5028 del repo._subtoppath
5028 del repo._subtoppath
5029
5029
5030
5030
5031 @command(
5031 @command(
5032 b'parents',
5032 b'parents',
5033 [
5033 [
5034 (
5034 (
5035 b'r',
5035 b'r',
5036 b'rev',
5036 b'rev',
5037 b'',
5037 b'',
5038 _(b'show parents of the specified revision'),
5038 _(b'show parents of the specified revision'),
5039 _(b'REV'),
5039 _(b'REV'),
5040 ),
5040 ),
5041 ]
5041 ]
5042 + templateopts,
5042 + templateopts,
5043 _(b'[-r REV] [FILE]'),
5043 _(b'[-r REV] [FILE]'),
5044 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5044 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5045 inferrepo=True,
5045 inferrepo=True,
5046 )
5046 )
5047 def parents(ui, repo, file_=None, **opts):
5047 def parents(ui, repo, file_=None, **opts):
5048 """show the parents of the working directory or revision (DEPRECATED)
5048 """show the parents of the working directory or revision (DEPRECATED)
5049
5049
5050 Print the working directory's parent revisions. If a revision is
5050 Print the working directory's parent revisions. If a revision is
5051 given via -r/--rev, the parent of that revision will be printed.
5051 given via -r/--rev, the parent of that revision will be printed.
5052 If a file argument is given, the revision in which the file was
5052 If a file argument is given, the revision in which the file was
5053 last changed (before the working directory revision or the
5053 last changed (before the working directory revision or the
5054 argument to --rev if given) is printed.
5054 argument to --rev if given) is printed.
5055
5055
5056 This command is equivalent to::
5056 This command is equivalent to::
5057
5057
5058 hg log -r "p1()+p2()" or
5058 hg log -r "p1()+p2()" or
5059 hg log -r "p1(REV)+p2(REV)" or
5059 hg log -r "p1(REV)+p2(REV)" or
5060 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5060 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5061 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5061 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5062
5062
5063 See :hg:`summary` and :hg:`help revsets` for related information.
5063 See :hg:`summary` and :hg:`help revsets` for related information.
5064
5064
5065 Returns 0 on success.
5065 Returns 0 on success.
5066 """
5066 """
5067
5067
5068 opts = pycompat.byteskwargs(opts)
5068 opts = pycompat.byteskwargs(opts)
5069 rev = opts.get(b'rev')
5069 rev = opts.get(b'rev')
5070 if rev:
5070 if rev:
5071 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5071 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5072 ctx = scmutil.revsingle(repo, rev, None)
5072 ctx = scmutil.revsingle(repo, rev, None)
5073
5073
5074 if file_:
5074 if file_:
5075 m = scmutil.match(ctx, (file_,), opts)
5075 m = scmutil.match(ctx, (file_,), opts)
5076 if m.anypats() or len(m.files()) != 1:
5076 if m.anypats() or len(m.files()) != 1:
5077 raise error.Abort(_(b'can only specify an explicit filename'))
5077 raise error.Abort(_(b'can only specify an explicit filename'))
5078 file_ = m.files()[0]
5078 file_ = m.files()[0]
5079 filenodes = []
5079 filenodes = []
5080 for cp in ctx.parents():
5080 for cp in ctx.parents():
5081 if not cp:
5081 if not cp:
5082 continue
5082 continue
5083 try:
5083 try:
5084 filenodes.append(cp.filenode(file_))
5084 filenodes.append(cp.filenode(file_))
5085 except error.LookupError:
5085 except error.LookupError:
5086 pass
5086 pass
5087 if not filenodes:
5087 if not filenodes:
5088 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5088 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5089 p = []
5089 p = []
5090 for fn in filenodes:
5090 for fn in filenodes:
5091 fctx = repo.filectx(file_, fileid=fn)
5091 fctx = repo.filectx(file_, fileid=fn)
5092 p.append(fctx.node())
5092 p.append(fctx.node())
5093 else:
5093 else:
5094 p = [cp.node() for cp in ctx.parents()]
5094 p = [cp.node() for cp in ctx.parents()]
5095
5095
5096 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5096 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5097 for n in p:
5097 for n in p:
5098 if n != nullid:
5098 if n != nullid:
5099 displayer.show(repo[n])
5099 displayer.show(repo[n])
5100 displayer.close()
5100 displayer.close()
5101
5101
5102
5102
5103 @command(
5103 @command(
5104 b'paths',
5104 b'paths',
5105 formatteropts,
5105 formatteropts,
5106 _(b'[NAME]'),
5106 _(b'[NAME]'),
5107 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5107 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5108 optionalrepo=True,
5108 optionalrepo=True,
5109 intents={INTENT_READONLY},
5109 intents={INTENT_READONLY},
5110 )
5110 )
5111 def paths(ui, repo, search=None, **opts):
5111 def paths(ui, repo, search=None, **opts):
5112 """show aliases for remote repositories
5112 """show aliases for remote repositories
5113
5113
5114 Show definition of symbolic path name NAME. If no name is given,
5114 Show definition of symbolic path name NAME. If no name is given,
5115 show definition of all available names.
5115 show definition of all available names.
5116
5116
5117 Option -q/--quiet suppresses all output when searching for NAME
5117 Option -q/--quiet suppresses all output when searching for NAME
5118 and shows only the path names when listing all definitions.
5118 and shows only the path names when listing all definitions.
5119
5119
5120 Path names are defined in the [paths] section of your
5120 Path names are defined in the [paths] section of your
5121 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5121 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5122 repository, ``.hg/hgrc`` is used, too.
5122 repository, ``.hg/hgrc`` is used, too.
5123
5123
5124 The path names ``default`` and ``default-push`` have a special
5124 The path names ``default`` and ``default-push`` have a special
5125 meaning. When performing a push or pull operation, they are used
5125 meaning. When performing a push or pull operation, they are used
5126 as fallbacks if no location is specified on the command-line.
5126 as fallbacks if no location is specified on the command-line.
5127 When ``default-push`` is set, it will be used for push and
5127 When ``default-push`` is set, it will be used for push and
5128 ``default`` will be used for pull; otherwise ``default`` is used
5128 ``default`` will be used for pull; otherwise ``default`` is used
5129 as the fallback for both. When cloning a repository, the clone
5129 as the fallback for both. When cloning a repository, the clone
5130 source is written as ``default`` in ``.hg/hgrc``.
5130 source is written as ``default`` in ``.hg/hgrc``.
5131
5131
5132 .. note::
5132 .. note::
5133
5133
5134 ``default`` and ``default-push`` apply to all inbound (e.g.
5134 ``default`` and ``default-push`` apply to all inbound (e.g.
5135 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5135 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5136 and :hg:`bundle`) operations.
5136 and :hg:`bundle`) operations.
5137
5137
5138 See :hg:`help urls` for more information.
5138 See :hg:`help urls` for more information.
5139
5139
5140 .. container:: verbose
5140 .. container:: verbose
5141
5141
5142 Template:
5142 Template:
5143
5143
5144 The following keywords are supported. See also :hg:`help templates`.
5144 The following keywords are supported. See also :hg:`help templates`.
5145
5145
5146 :name: String. Symbolic name of the path alias.
5146 :name: String. Symbolic name of the path alias.
5147 :pushurl: String. URL for push operations.
5147 :pushurl: String. URL for push operations.
5148 :url: String. URL or directory path for the other operations.
5148 :url: String. URL or directory path for the other operations.
5149
5149
5150 Returns 0 on success.
5150 Returns 0 on success.
5151 """
5151 """
5152
5152
5153 opts = pycompat.byteskwargs(opts)
5153 opts = pycompat.byteskwargs(opts)
5154 ui.pager(b'paths')
5154 ui.pager(b'paths')
5155 if search:
5155 if search:
5156 pathitems = [
5156 pathitems = [
5157 (name, path)
5157 (name, path)
5158 for name, path in pycompat.iteritems(ui.paths)
5158 for name, path in pycompat.iteritems(ui.paths)
5159 if name == search
5159 if name == search
5160 ]
5160 ]
5161 else:
5161 else:
5162 pathitems = sorted(pycompat.iteritems(ui.paths))
5162 pathitems = sorted(pycompat.iteritems(ui.paths))
5163
5163
5164 fm = ui.formatter(b'paths', opts)
5164 fm = ui.formatter(b'paths', opts)
5165 if fm.isplain():
5165 if fm.isplain():
5166 hidepassword = util.hidepassword
5166 hidepassword = util.hidepassword
5167 else:
5167 else:
5168 hidepassword = bytes
5168 hidepassword = bytes
5169 if ui.quiet:
5169 if ui.quiet:
5170 namefmt = b'%s\n'
5170 namefmt = b'%s\n'
5171 else:
5171 else:
5172 namefmt = b'%s = '
5172 namefmt = b'%s = '
5173 showsubopts = not search and not ui.quiet
5173 showsubopts = not search and not ui.quiet
5174
5174
5175 for name, path in pathitems:
5175 for name, path in pathitems:
5176 fm.startitem()
5176 fm.startitem()
5177 fm.condwrite(not search, b'name', namefmt, name)
5177 fm.condwrite(not search, b'name', namefmt, name)
5178 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5178 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5179 for subopt, value in sorted(path.suboptions.items()):
5179 for subopt, value in sorted(path.suboptions.items()):
5180 assert subopt not in (b'name', b'url')
5180 assert subopt not in (b'name', b'url')
5181 if showsubopts:
5181 if showsubopts:
5182 fm.plain(b'%s:%s = ' % (name, subopt))
5182 fm.plain(b'%s:%s = ' % (name, subopt))
5183 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5183 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5184
5184
5185 fm.end()
5185 fm.end()
5186
5186
5187 if search and not pathitems:
5187 if search and not pathitems:
5188 if not ui.quiet:
5188 if not ui.quiet:
5189 ui.warn(_(b"not found!\n"))
5189 ui.warn(_(b"not found!\n"))
5190 return 1
5190 return 1
5191 else:
5191 else:
5192 return 0
5192 return 0
5193
5193
5194
5194
5195 @command(
5195 @command(
5196 b'phase',
5196 b'phase',
5197 [
5197 [
5198 (b'p', b'public', False, _(b'set changeset phase to public')),
5198 (b'p', b'public', False, _(b'set changeset phase to public')),
5199 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5199 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5200 (b's', b'secret', False, _(b'set changeset phase to secret')),
5200 (b's', b'secret', False, _(b'set changeset phase to secret')),
5201 (b'f', b'force', False, _(b'allow to move boundary backward')),
5201 (b'f', b'force', False, _(b'allow to move boundary backward')),
5202 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5202 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5203 ],
5203 ],
5204 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5204 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5205 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5205 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5206 )
5206 )
5207 def phase(ui, repo, *revs, **opts):
5207 def phase(ui, repo, *revs, **opts):
5208 """set or show the current phase name
5208 """set or show the current phase name
5209
5209
5210 With no argument, show the phase name of the current revision(s).
5210 With no argument, show the phase name of the current revision(s).
5211
5211
5212 With one of -p/--public, -d/--draft or -s/--secret, change the
5212 With one of -p/--public, -d/--draft or -s/--secret, change the
5213 phase value of the specified revisions.
5213 phase value of the specified revisions.
5214
5214
5215 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5215 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5216 lower phase to a higher phase. Phases are ordered as follows::
5216 lower phase to a higher phase. Phases are ordered as follows::
5217
5217
5218 public < draft < secret
5218 public < draft < secret
5219
5219
5220 Returns 0 on success, 1 if some phases could not be changed.
5220 Returns 0 on success, 1 if some phases could not be changed.
5221
5221
5222 (For more information about the phases concept, see :hg:`help phases`.)
5222 (For more information about the phases concept, see :hg:`help phases`.)
5223 """
5223 """
5224 opts = pycompat.byteskwargs(opts)
5224 opts = pycompat.byteskwargs(opts)
5225 # search for a unique phase argument
5225 # search for a unique phase argument
5226 targetphase = None
5226 targetphase = None
5227 for idx, name in enumerate(phases.cmdphasenames):
5227 for idx, name in enumerate(phases.cmdphasenames):
5228 if opts[name]:
5228 if opts[name]:
5229 if targetphase is not None:
5229 if targetphase is not None:
5230 raise error.Abort(_(b'only one phase can be specified'))
5230 raise error.Abort(_(b'only one phase can be specified'))
5231 targetphase = idx
5231 targetphase = idx
5232
5232
5233 # look for specified revision
5233 # look for specified revision
5234 revs = list(revs)
5234 revs = list(revs)
5235 revs.extend(opts[b'rev'])
5235 revs.extend(opts[b'rev'])
5236 if not revs:
5236 if not revs:
5237 # display both parents as the second parent phase can influence
5237 # display both parents as the second parent phase can influence
5238 # the phase of a merge commit
5238 # the phase of a merge commit
5239 revs = [c.rev() for c in repo[None].parents()]
5239 revs = [c.rev() for c in repo[None].parents()]
5240
5240
5241 revs = scmutil.revrange(repo, revs)
5241 revs = scmutil.revrange(repo, revs)
5242
5242
5243 ret = 0
5243 ret = 0
5244 if targetphase is None:
5244 if targetphase is None:
5245 # display
5245 # display
5246 for r in revs:
5246 for r in revs:
5247 ctx = repo[r]
5247 ctx = repo[r]
5248 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5248 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5249 else:
5249 else:
5250 with repo.lock(), repo.transaction(b"phase") as tr:
5250 with repo.lock(), repo.transaction(b"phase") as tr:
5251 # set phase
5251 # set phase
5252 if not revs:
5252 if not revs:
5253 raise error.Abort(_(b'empty revision set'))
5253 raise error.Abort(_(b'empty revision set'))
5254 nodes = [repo[r].node() for r in revs]
5254 nodes = [repo[r].node() for r in revs]
5255 # moving revision from public to draft may hide them
5255 # moving revision from public to draft may hide them
5256 # We have to check result on an unfiltered repository
5256 # We have to check result on an unfiltered repository
5257 unfi = repo.unfiltered()
5257 unfi = repo.unfiltered()
5258 getphase = unfi._phasecache.phase
5258 getphase = unfi._phasecache.phase
5259 olddata = [getphase(unfi, r) for r in unfi]
5259 olddata = [getphase(unfi, r) for r in unfi]
5260 phases.advanceboundary(repo, tr, targetphase, nodes)
5260 phases.advanceboundary(repo, tr, targetphase, nodes)
5261 if opts[b'force']:
5261 if opts[b'force']:
5262 phases.retractboundary(repo, tr, targetphase, nodes)
5262 phases.retractboundary(repo, tr, targetphase, nodes)
5263 getphase = unfi._phasecache.phase
5263 getphase = unfi._phasecache.phase
5264 newdata = [getphase(unfi, r) for r in unfi]
5264 newdata = [getphase(unfi, r) for r in unfi]
5265 changes = sum(newdata[r] != olddata[r] for r in unfi)
5265 changes = sum(newdata[r] != olddata[r] for r in unfi)
5266 cl = unfi.changelog
5266 cl = unfi.changelog
5267 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5267 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5268 if rejected:
5268 if rejected:
5269 ui.warn(
5269 ui.warn(
5270 _(
5270 _(
5271 b'cannot move %i changesets to a higher '
5271 b'cannot move %i changesets to a higher '
5272 b'phase, use --force\n'
5272 b'phase, use --force\n'
5273 )
5273 )
5274 % len(rejected)
5274 % len(rejected)
5275 )
5275 )
5276 ret = 1
5276 ret = 1
5277 if changes:
5277 if changes:
5278 msg = _(b'phase changed for %i changesets\n') % changes
5278 msg = _(b'phase changed for %i changesets\n') % changes
5279 if ret:
5279 if ret:
5280 ui.status(msg)
5280 ui.status(msg)
5281 else:
5281 else:
5282 ui.note(msg)
5282 ui.note(msg)
5283 else:
5283 else:
5284 ui.warn(_(b'no phases changed\n'))
5284 ui.warn(_(b'no phases changed\n'))
5285 return ret
5285 return ret
5286
5286
5287
5287
5288 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5288 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5289 """Run after a changegroup has been added via pull/unbundle
5289 """Run after a changegroup has been added via pull/unbundle
5290
5290
5291 This takes arguments below:
5291 This takes arguments below:
5292
5292
5293 :modheads: change of heads by pull/unbundle
5293 :modheads: change of heads by pull/unbundle
5294 :optupdate: updating working directory is needed or not
5294 :optupdate: updating working directory is needed or not
5295 :checkout: update destination revision (or None to default destination)
5295 :checkout: update destination revision (or None to default destination)
5296 :brev: a name, which might be a bookmark to be activated after updating
5296 :brev: a name, which might be a bookmark to be activated after updating
5297 """
5297 """
5298 if modheads == 0:
5298 if modheads == 0:
5299 return
5299 return
5300 if optupdate:
5300 if optupdate:
5301 try:
5301 try:
5302 return hg.updatetotally(ui, repo, checkout, brev)
5302 return hg.updatetotally(ui, repo, checkout, brev)
5303 except error.UpdateAbort as inst:
5303 except error.UpdateAbort as inst:
5304 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5304 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5305 hint = inst.hint
5305 hint = inst.hint
5306 raise error.UpdateAbort(msg, hint=hint)
5306 raise error.UpdateAbort(msg, hint=hint)
5307 if modheads is not None and modheads > 1:
5307 if modheads is not None and modheads > 1:
5308 currentbranchheads = len(repo.branchheads())
5308 currentbranchheads = len(repo.branchheads())
5309 if currentbranchheads == modheads:
5309 if currentbranchheads == modheads:
5310 ui.status(
5310 ui.status(
5311 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5311 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5312 )
5312 )
5313 elif currentbranchheads > 1:
5313 elif currentbranchheads > 1:
5314 ui.status(
5314 ui.status(
5315 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5315 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5316 )
5316 )
5317 else:
5317 else:
5318 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5318 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5319 elif not ui.configbool(b'commands', b'update.requiredest'):
5319 elif not ui.configbool(b'commands', b'update.requiredest'):
5320 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5320 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5321
5321
5322
5322
5323 @command(
5323 @command(
5324 b'pull',
5324 b'pull',
5325 [
5325 [
5326 (
5326 (
5327 b'u',
5327 b'u',
5328 b'update',
5328 b'update',
5329 None,
5329 None,
5330 _(b'update to new branch head if new descendants were pulled'),
5330 _(b'update to new branch head if new descendants were pulled'),
5331 ),
5331 ),
5332 (
5332 (
5333 b'f',
5333 b'f',
5334 b'force',
5334 b'force',
5335 None,
5335 None,
5336 _(b'run even when remote repository is unrelated'),
5336 _(b'run even when remote repository is unrelated'),
5337 ),
5337 ),
5338 (
5338 (
5339 b'r',
5339 b'r',
5340 b'rev',
5340 b'rev',
5341 [],
5341 [],
5342 _(b'a remote changeset intended to be added'),
5342 _(b'a remote changeset intended to be added'),
5343 _(b'REV'),
5343 _(b'REV'),
5344 ),
5344 ),
5345 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5345 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5346 (
5346 (
5347 b'b',
5347 b'b',
5348 b'branch',
5348 b'branch',
5349 [],
5349 [],
5350 _(b'a specific branch you would like to pull'),
5350 _(b'a specific branch you would like to pull'),
5351 _(b'BRANCH'),
5351 _(b'BRANCH'),
5352 ),
5352 ),
5353 ]
5353 ]
5354 + remoteopts,
5354 + remoteopts,
5355 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5355 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5356 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5356 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5357 helpbasic=True,
5357 helpbasic=True,
5358 )
5358 )
5359 def pull(ui, repo, source=b"default", **opts):
5359 def pull(ui, repo, source=b"default", **opts):
5360 """pull changes from the specified source
5360 """pull changes from the specified source
5361
5361
5362 Pull changes from a remote repository to a local one.
5362 Pull changes from a remote repository to a local one.
5363
5363
5364 This finds all changes from the repository at the specified path
5364 This finds all changes from the repository at the specified path
5365 or URL and adds them to a local repository (the current one unless
5365 or URL and adds them to a local repository (the current one unless
5366 -R is specified). By default, this does not update the copy of the
5366 -R is specified). By default, this does not update the copy of the
5367 project in the working directory.
5367 project in the working directory.
5368
5368
5369 When cloning from servers that support it, Mercurial may fetch
5369 When cloning from servers that support it, Mercurial may fetch
5370 pre-generated data. When this is done, hooks operating on incoming
5370 pre-generated data. When this is done, hooks operating on incoming
5371 changesets and changegroups may fire more than once, once for each
5371 changesets and changegroups may fire more than once, once for each
5372 pre-generated bundle and as well as for any additional remaining
5372 pre-generated bundle and as well as for any additional remaining
5373 data. See :hg:`help -e clonebundles` for more.
5373 data. See :hg:`help -e clonebundles` for more.
5374
5374
5375 Use :hg:`incoming` if you want to see what would have been added
5375 Use :hg:`incoming` if you want to see what would have been added
5376 by a pull at the time you issued this command. If you then decide
5376 by a pull at the time you issued this command. If you then decide
5377 to add those changes to the repository, you should use :hg:`pull
5377 to add those changes to the repository, you should use :hg:`pull
5378 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5378 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5379
5379
5380 If SOURCE is omitted, the 'default' path will be used.
5380 If SOURCE is omitted, the 'default' path will be used.
5381 See :hg:`help urls` for more information.
5381 See :hg:`help urls` for more information.
5382
5382
5383 Specifying bookmark as ``.`` is equivalent to specifying the active
5383 Specifying bookmark as ``.`` is equivalent to specifying the active
5384 bookmark's name.
5384 bookmark's name.
5385
5385
5386 Returns 0 on success, 1 if an update had unresolved files.
5386 Returns 0 on success, 1 if an update had unresolved files.
5387 """
5387 """
5388
5388
5389 opts = pycompat.byteskwargs(opts)
5389 opts = pycompat.byteskwargs(opts)
5390 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5390 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5391 b'update'
5391 b'update'
5392 ):
5392 ):
5393 msg = _(b'update destination required by configuration')
5393 msg = _(b'update destination required by configuration')
5394 hint = _(b'use hg pull followed by hg update DEST')
5394 hint = _(b'use hg pull followed by hg update DEST')
5395 raise error.Abort(msg, hint=hint)
5395 raise error.Abort(msg, hint=hint)
5396
5396
5397 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5397 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5398 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5398 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5399 other = hg.peer(repo, opts, source)
5399 other = hg.peer(repo, opts, source)
5400 try:
5400 try:
5401 revs, checkout = hg.addbranchrevs(
5401 revs, checkout = hg.addbranchrevs(
5402 repo, other, branches, opts.get(b'rev')
5402 repo, other, branches, opts.get(b'rev')
5403 )
5403 )
5404
5404
5405 pullopargs = {}
5405 pullopargs = {}
5406
5406
5407 nodes = None
5407 nodes = None
5408 if opts.get(b'bookmark') or revs:
5408 if opts.get(b'bookmark') or revs:
5409 # The list of bookmark used here is the same used to actually update
5409 # The list of bookmark used here is the same used to actually update
5410 # the bookmark names, to avoid the race from issue 4689 and we do
5410 # the bookmark names, to avoid the race from issue 4689 and we do
5411 # all lookup and bookmark queries in one go so they see the same
5411 # all lookup and bookmark queries in one go so they see the same
5412 # version of the server state (issue 4700).
5412 # version of the server state (issue 4700).
5413 nodes = []
5413 nodes = []
5414 fnodes = []
5414 fnodes = []
5415 revs = revs or []
5415 revs = revs or []
5416 if revs and not other.capable(b'lookup'):
5416 if revs and not other.capable(b'lookup'):
5417 err = _(
5417 err = _(
5418 b"other repository doesn't support revision lookup, "
5418 b"other repository doesn't support revision lookup, "
5419 b"so a rev cannot be specified."
5419 b"so a rev cannot be specified."
5420 )
5420 )
5421 raise error.Abort(err)
5421 raise error.Abort(err)
5422 with other.commandexecutor() as e:
5422 with other.commandexecutor() as e:
5423 fremotebookmarks = e.callcommand(
5423 fremotebookmarks = e.callcommand(
5424 b'listkeys', {b'namespace': b'bookmarks'}
5424 b'listkeys', {b'namespace': b'bookmarks'}
5425 )
5425 )
5426 for r in revs:
5426 for r in revs:
5427 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5427 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5428 remotebookmarks = fremotebookmarks.result()
5428 remotebookmarks = fremotebookmarks.result()
5429 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5429 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5430 pullopargs[b'remotebookmarks'] = remotebookmarks
5430 pullopargs[b'remotebookmarks'] = remotebookmarks
5431 for b in opts.get(b'bookmark', []):
5431 for b in opts.get(b'bookmark', []):
5432 b = repo._bookmarks.expandname(b)
5432 b = repo._bookmarks.expandname(b)
5433 if b not in remotebookmarks:
5433 if b not in remotebookmarks:
5434 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5434 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5435 nodes.append(remotebookmarks[b])
5435 nodes.append(remotebookmarks[b])
5436 for i, rev in enumerate(revs):
5436 for i, rev in enumerate(revs):
5437 node = fnodes[i].result()
5437 node = fnodes[i].result()
5438 nodes.append(node)
5438 nodes.append(node)
5439 if rev == checkout:
5439 if rev == checkout:
5440 checkout = node
5440 checkout = node
5441
5441
5442 wlock = util.nullcontextmanager()
5442 wlock = util.nullcontextmanager()
5443 if opts.get(b'update'):
5443 if opts.get(b'update'):
5444 wlock = repo.wlock()
5444 wlock = repo.wlock()
5445 with wlock:
5445 with wlock:
5446 pullopargs.update(opts.get(b'opargs', {}))
5446 pullopargs.update(opts.get(b'opargs', {}))
5447 modheads = exchange.pull(
5447 modheads = exchange.pull(
5448 repo,
5448 repo,
5449 other,
5449 other,
5450 heads=nodes,
5450 heads=nodes,
5451 force=opts.get(b'force'),
5451 force=opts.get(b'force'),
5452 bookmarks=opts.get(b'bookmark', ()),
5452 bookmarks=opts.get(b'bookmark', ()),
5453 opargs=pullopargs,
5453 opargs=pullopargs,
5454 ).cgresult
5454 ).cgresult
5455
5455
5456 # brev is a name, which might be a bookmark to be activated at
5456 # brev is a name, which might be a bookmark to be activated at
5457 # the end of the update. In other words, it is an explicit
5457 # the end of the update. In other words, it is an explicit
5458 # destination of the update
5458 # destination of the update
5459 brev = None
5459 brev = None
5460
5460
5461 if checkout:
5461 if checkout:
5462 checkout = repo.unfiltered().changelog.rev(checkout)
5462 checkout = repo.unfiltered().changelog.rev(checkout)
5463
5463
5464 # order below depends on implementation of
5464 # order below depends on implementation of
5465 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5465 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5466 # because 'checkout' is determined without it.
5466 # because 'checkout' is determined without it.
5467 if opts.get(b'rev'):
5467 if opts.get(b'rev'):
5468 brev = opts[b'rev'][0]
5468 brev = opts[b'rev'][0]
5469 elif opts.get(b'branch'):
5469 elif opts.get(b'branch'):
5470 brev = opts[b'branch'][0]
5470 brev = opts[b'branch'][0]
5471 else:
5471 else:
5472 brev = branches[0]
5472 brev = branches[0]
5473 repo._subtoppath = source
5473 repo._subtoppath = source
5474 try:
5474 try:
5475 ret = postincoming(
5475 ret = postincoming(
5476 ui, repo, modheads, opts.get(b'update'), checkout, brev
5476 ui, repo, modheads, opts.get(b'update'), checkout, brev
5477 )
5477 )
5478 except error.FilteredRepoLookupError as exc:
5478 except error.FilteredRepoLookupError as exc:
5479 msg = _(b'cannot update to target: %s') % exc.args[0]
5479 msg = _(b'cannot update to target: %s') % exc.args[0]
5480 exc.args = (msg,) + exc.args[1:]
5480 exc.args = (msg,) + exc.args[1:]
5481 raise
5481 raise
5482 finally:
5482 finally:
5483 del repo._subtoppath
5483 del repo._subtoppath
5484
5484
5485 finally:
5485 finally:
5486 other.close()
5486 other.close()
5487 return ret
5487 return ret
5488
5488
5489
5489
5490 @command(
5490 @command(
5491 b'push',
5491 b'push',
5492 [
5492 [
5493 (b'f', b'force', None, _(b'force push')),
5493 (b'f', b'force', None, _(b'force push')),
5494 (
5494 (
5495 b'r',
5495 b'r',
5496 b'rev',
5496 b'rev',
5497 [],
5497 [],
5498 _(b'a changeset intended to be included in the destination'),
5498 _(b'a changeset intended to be included in the destination'),
5499 _(b'REV'),
5499 _(b'REV'),
5500 ),
5500 ),
5501 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5501 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5502 (
5502 (
5503 b'b',
5503 b'b',
5504 b'branch',
5504 b'branch',
5505 [],
5505 [],
5506 _(b'a specific branch you would like to push'),
5506 _(b'a specific branch you would like to push'),
5507 _(b'BRANCH'),
5507 _(b'BRANCH'),
5508 ),
5508 ),
5509 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5509 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5510 (
5510 (
5511 b'',
5511 b'',
5512 b'pushvars',
5512 b'pushvars',
5513 [],
5513 [],
5514 _(b'variables that can be sent to server (ADVANCED)'),
5514 _(b'variables that can be sent to server (ADVANCED)'),
5515 ),
5515 ),
5516 (
5516 (
5517 b'',
5517 b'',
5518 b'publish',
5518 b'publish',
5519 False,
5519 False,
5520 _(b'push the changeset as public (EXPERIMENTAL)'),
5520 _(b'push the changeset as public (EXPERIMENTAL)'),
5521 ),
5521 ),
5522 ]
5522 ]
5523 + remoteopts,
5523 + remoteopts,
5524 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5524 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5525 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5525 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5526 helpbasic=True,
5526 helpbasic=True,
5527 )
5527 )
5528 def push(ui, repo, dest=None, **opts):
5528 def push(ui, repo, dest=None, **opts):
5529 """push changes to the specified destination
5529 """push changes to the specified destination
5530
5530
5531 Push changesets from the local repository to the specified
5531 Push changesets from the local repository to the specified
5532 destination.
5532 destination.
5533
5533
5534 This operation is symmetrical to pull: it is identical to a pull
5534 This operation is symmetrical to pull: it is identical to a pull
5535 in the destination repository from the current one.
5535 in the destination repository from the current one.
5536
5536
5537 By default, push will not allow creation of new heads at the
5537 By default, push will not allow creation of new heads at the
5538 destination, since multiple heads would make it unclear which head
5538 destination, since multiple heads would make it unclear which head
5539 to use. In this situation, it is recommended to pull and merge
5539 to use. In this situation, it is recommended to pull and merge
5540 before pushing.
5540 before pushing.
5541
5541
5542 Use --new-branch if you want to allow push to create a new named
5542 Use --new-branch if you want to allow push to create a new named
5543 branch that is not present at the destination. This allows you to
5543 branch that is not present at the destination. This allows you to
5544 only create a new branch without forcing other changes.
5544 only create a new branch without forcing other changes.
5545
5545
5546 .. note::
5546 .. note::
5547
5547
5548 Extra care should be taken with the -f/--force option,
5548 Extra care should be taken with the -f/--force option,
5549 which will push all new heads on all branches, an action which will
5549 which will push all new heads on all branches, an action which will
5550 almost always cause confusion for collaborators.
5550 almost always cause confusion for collaborators.
5551
5551
5552 If -r/--rev is used, the specified revision and all its ancestors
5552 If -r/--rev is used, the specified revision and all its ancestors
5553 will be pushed to the remote repository.
5553 will be pushed to the remote repository.
5554
5554
5555 If -B/--bookmark is used, the specified bookmarked revision, its
5555 If -B/--bookmark is used, the specified bookmarked revision, its
5556 ancestors, and the bookmark will be pushed to the remote
5556 ancestors, and the bookmark will be pushed to the remote
5557 repository. Specifying ``.`` is equivalent to specifying the active
5557 repository. Specifying ``.`` is equivalent to specifying the active
5558 bookmark's name.
5558 bookmark's name.
5559
5559
5560 Please see :hg:`help urls` for important details about ``ssh://``
5560 Please see :hg:`help urls` for important details about ``ssh://``
5561 URLs. If DESTINATION is omitted, a default path will be used.
5561 URLs. If DESTINATION is omitted, a default path will be used.
5562
5562
5563 .. container:: verbose
5563 .. container:: verbose
5564
5564
5565 The --pushvars option sends strings to the server that become
5565 The --pushvars option sends strings to the server that become
5566 environment variables prepended with ``HG_USERVAR_``. For example,
5566 environment variables prepended with ``HG_USERVAR_``. For example,
5567 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5567 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5568 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5568 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5569
5569
5570 pushvars can provide for user-overridable hooks as well as set debug
5570 pushvars can provide for user-overridable hooks as well as set debug
5571 levels. One example is having a hook that blocks commits containing
5571 levels. One example is having a hook that blocks commits containing
5572 conflict markers, but enables the user to override the hook if the file
5572 conflict markers, but enables the user to override the hook if the file
5573 is using conflict markers for testing purposes or the file format has
5573 is using conflict markers for testing purposes or the file format has
5574 strings that look like conflict markers.
5574 strings that look like conflict markers.
5575
5575
5576 By default, servers will ignore `--pushvars`. To enable it add the
5576 By default, servers will ignore `--pushvars`. To enable it add the
5577 following to your configuration file::
5577 following to your configuration file::
5578
5578
5579 [push]
5579 [push]
5580 pushvars.server = true
5580 pushvars.server = true
5581
5581
5582 Returns 0 if push was successful, 1 if nothing to push.
5582 Returns 0 if push was successful, 1 if nothing to push.
5583 """
5583 """
5584
5584
5585 opts = pycompat.byteskwargs(opts)
5585 opts = pycompat.byteskwargs(opts)
5586 if opts.get(b'bookmark'):
5586 if opts.get(b'bookmark'):
5587 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5587 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5588 for b in opts[b'bookmark']:
5588 for b in opts[b'bookmark']:
5589 # translate -B options to -r so changesets get pushed
5589 # translate -B options to -r so changesets get pushed
5590 b = repo._bookmarks.expandname(b)
5590 b = repo._bookmarks.expandname(b)
5591 if b in repo._bookmarks:
5591 if b in repo._bookmarks:
5592 opts.setdefault(b'rev', []).append(b)
5592 opts.setdefault(b'rev', []).append(b)
5593 else:
5593 else:
5594 # if we try to push a deleted bookmark, translate it to null
5594 # if we try to push a deleted bookmark, translate it to null
5595 # this lets simultaneous -r, -b options continue working
5595 # this lets simultaneous -r, -b options continue working
5596 opts.setdefault(b'rev', []).append(b"null")
5596 opts.setdefault(b'rev', []).append(b"null")
5597
5597
5598 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5598 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5599 if not path:
5599 if not path:
5600 raise error.Abort(
5600 raise error.Abort(
5601 _(b'default repository not configured!'),
5601 _(b'default repository not configured!'),
5602 hint=_(b"see 'hg help config.paths'"),
5602 hint=_(b"see 'hg help config.paths'"),
5603 )
5603 )
5604 dest = path.pushloc or path.loc
5604 dest = path.pushloc or path.loc
5605 branches = (path.branch, opts.get(b'branch') or [])
5605 branches = (path.branch, opts.get(b'branch') or [])
5606 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5606 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5607 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5607 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5608 other = hg.peer(repo, opts, dest)
5608 other = hg.peer(repo, opts, dest)
5609
5609
5610 if revs:
5610 if revs:
5611 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5611 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5612 if not revs:
5612 if not revs:
5613 raise error.Abort(
5613 raise error.Abort(
5614 _(b"specified revisions evaluate to an empty set"),
5614 _(b"specified revisions evaluate to an empty set"),
5615 hint=_(b"use different revision arguments"),
5615 hint=_(b"use different revision arguments"),
5616 )
5616 )
5617 elif path.pushrev:
5617 elif path.pushrev:
5618 # It doesn't make any sense to specify ancestor revisions. So limit
5618 # It doesn't make any sense to specify ancestor revisions. So limit
5619 # to DAG heads to make discovery simpler.
5619 # to DAG heads to make discovery simpler.
5620 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5620 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5621 revs = scmutil.revrange(repo, [expr])
5621 revs = scmutil.revrange(repo, [expr])
5622 revs = [repo[rev].node() for rev in revs]
5622 revs = [repo[rev].node() for rev in revs]
5623 if not revs:
5623 if not revs:
5624 raise error.Abort(
5624 raise error.Abort(
5625 _(b'default push revset for path evaluates to an empty set')
5625 _(b'default push revset for path evaluates to an empty set')
5626 )
5626 )
5627 elif ui.configbool(b'commands', b'push.require-revs'):
5627 elif ui.configbool(b'commands', b'push.require-revs'):
5628 raise error.Abort(
5628 raise error.Abort(
5629 _(b'no revisions specified to push'),
5629 _(b'no revisions specified to push'),
5630 hint=_(b'did you mean "hg push -r ."?'),
5630 hint=_(b'did you mean "hg push -r ."?'),
5631 )
5631 )
5632
5632
5633 repo._subtoppath = dest
5633 repo._subtoppath = dest
5634 try:
5634 try:
5635 # push subrepos depth-first for coherent ordering
5635 # push subrepos depth-first for coherent ordering
5636 c = repo[b'.']
5636 c = repo[b'.']
5637 subs = c.substate # only repos that are committed
5637 subs = c.substate # only repos that are committed
5638 for s in sorted(subs):
5638 for s in sorted(subs):
5639 result = c.sub(s).push(opts)
5639 result = c.sub(s).push(opts)
5640 if result == 0:
5640 if result == 0:
5641 return not result
5641 return not result
5642 finally:
5642 finally:
5643 del repo._subtoppath
5643 del repo._subtoppath
5644
5644
5645 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5645 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5646 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5646 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5647
5647
5648 pushop = exchange.push(
5648 pushop = exchange.push(
5649 repo,
5649 repo,
5650 other,
5650 other,
5651 opts.get(b'force'),
5651 opts.get(b'force'),
5652 revs=revs,
5652 revs=revs,
5653 newbranch=opts.get(b'new_branch'),
5653 newbranch=opts.get(b'new_branch'),
5654 bookmarks=opts.get(b'bookmark', ()),
5654 bookmarks=opts.get(b'bookmark', ()),
5655 publish=opts.get(b'publish'),
5655 publish=opts.get(b'publish'),
5656 opargs=opargs,
5656 opargs=opargs,
5657 )
5657 )
5658
5658
5659 result = not pushop.cgresult
5659 result = not pushop.cgresult
5660
5660
5661 if pushop.bkresult is not None:
5661 if pushop.bkresult is not None:
5662 if pushop.bkresult == 2:
5662 if pushop.bkresult == 2:
5663 result = 2
5663 result = 2
5664 elif not result and pushop.bkresult:
5664 elif not result and pushop.bkresult:
5665 result = 2
5665 result = 2
5666
5666
5667 return result
5667 return result
5668
5668
5669
5669
5670 @command(
5670 @command(
5671 b'recover',
5671 b'recover',
5672 [(b'', b'verify', True, b"run `hg verify` after successful recover"),],
5672 [(b'', b'verify', True, b"run `hg verify` after successful recover"),],
5673 helpcategory=command.CATEGORY_MAINTENANCE,
5673 helpcategory=command.CATEGORY_MAINTENANCE,
5674 )
5674 )
5675 def recover(ui, repo, **opts):
5675 def recover(ui, repo, **opts):
5676 """roll back an interrupted transaction
5676 """roll back an interrupted transaction
5677
5677
5678 Recover from an interrupted commit or pull.
5678 Recover from an interrupted commit or pull.
5679
5679
5680 This command tries to fix the repository status after an
5680 This command tries to fix the repository status after an
5681 interrupted operation. It should only be necessary when Mercurial
5681 interrupted operation. It should only be necessary when Mercurial
5682 suggests it.
5682 suggests it.
5683
5683
5684 Returns 0 if successful, 1 if nothing to recover or verify fails.
5684 Returns 0 if successful, 1 if nothing to recover or verify fails.
5685 """
5685 """
5686 ret = repo.recover()
5686 ret = repo.recover()
5687 if ret:
5687 if ret:
5688 if opts['verify']:
5688 if opts['verify']:
5689 return hg.verify(repo)
5689 return hg.verify(repo)
5690 else:
5690 else:
5691 msg = _(
5691 msg = _(
5692 b"(verify step skipped, run `hg verify` to check your "
5692 b"(verify step skipped, run `hg verify` to check your "
5693 b"repository content)\n"
5693 b"repository content)\n"
5694 )
5694 )
5695 ui.warn(msg)
5695 ui.warn(msg)
5696 return 0
5696 return 0
5697 return 1
5697 return 1
5698
5698
5699
5699
5700 @command(
5700 @command(
5701 b'remove|rm',
5701 b'remove|rm',
5702 [
5702 [
5703 (b'A', b'after', None, _(b'record delete for missing files')),
5703 (b'A', b'after', None, _(b'record delete for missing files')),
5704 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5704 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5705 ]
5705 ]
5706 + subrepoopts
5706 + subrepoopts
5707 + walkopts
5707 + walkopts
5708 + dryrunopts,
5708 + dryrunopts,
5709 _(b'[OPTION]... FILE...'),
5709 _(b'[OPTION]... FILE...'),
5710 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5710 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5711 helpbasic=True,
5711 helpbasic=True,
5712 inferrepo=True,
5712 inferrepo=True,
5713 )
5713 )
5714 def remove(ui, repo, *pats, **opts):
5714 def remove(ui, repo, *pats, **opts):
5715 """remove the specified files on the next commit
5715 """remove the specified files on the next commit
5716
5716
5717 Schedule the indicated files for removal from the current branch.
5717 Schedule the indicated files for removal from the current branch.
5718
5718
5719 This command schedules the files to be removed at the next commit.
5719 This command schedules the files to be removed at the next commit.
5720 To undo a remove before that, see :hg:`revert`. To undo added
5720 To undo a remove before that, see :hg:`revert`. To undo added
5721 files, see :hg:`forget`.
5721 files, see :hg:`forget`.
5722
5722
5723 .. container:: verbose
5723 .. container:: verbose
5724
5724
5725 -A/--after can be used to remove only files that have already
5725 -A/--after can be used to remove only files that have already
5726 been deleted, -f/--force can be used to force deletion, and -Af
5726 been deleted, -f/--force can be used to force deletion, and -Af
5727 can be used to remove files from the next revision without
5727 can be used to remove files from the next revision without
5728 deleting them from the working directory.
5728 deleting them from the working directory.
5729
5729
5730 The following table details the behavior of remove for different
5730 The following table details the behavior of remove for different
5731 file states (columns) and option combinations (rows). The file
5731 file states (columns) and option combinations (rows). The file
5732 states are Added [A], Clean [C], Modified [M] and Missing [!]
5732 states are Added [A], Clean [C], Modified [M] and Missing [!]
5733 (as reported by :hg:`status`). The actions are Warn, Remove
5733 (as reported by :hg:`status`). The actions are Warn, Remove
5734 (from branch) and Delete (from disk):
5734 (from branch) and Delete (from disk):
5735
5735
5736 ========= == == == ==
5736 ========= == == == ==
5737 opt/state A C M !
5737 opt/state A C M !
5738 ========= == == == ==
5738 ========= == == == ==
5739 none W RD W R
5739 none W RD W R
5740 -f R RD RD R
5740 -f R RD RD R
5741 -A W W W R
5741 -A W W W R
5742 -Af R R R R
5742 -Af R R R R
5743 ========= == == == ==
5743 ========= == == == ==
5744
5744
5745 .. note::
5745 .. note::
5746
5746
5747 :hg:`remove` never deletes files in Added [A] state from the
5747 :hg:`remove` never deletes files in Added [A] state from the
5748 working directory, not even if ``--force`` is specified.
5748 working directory, not even if ``--force`` is specified.
5749
5749
5750 Returns 0 on success, 1 if any warnings encountered.
5750 Returns 0 on success, 1 if any warnings encountered.
5751 """
5751 """
5752
5752
5753 opts = pycompat.byteskwargs(opts)
5753 opts = pycompat.byteskwargs(opts)
5754 after, force = opts.get(b'after'), opts.get(b'force')
5754 after, force = opts.get(b'after'), opts.get(b'force')
5755 dryrun = opts.get(b'dry_run')
5755 dryrun = opts.get(b'dry_run')
5756 if not pats and not after:
5756 if not pats and not after:
5757 raise error.Abort(_(b'no files specified'))
5757 raise error.Abort(_(b'no files specified'))
5758
5758
5759 m = scmutil.match(repo[None], pats, opts)
5759 m = scmutil.match(repo[None], pats, opts)
5760 subrepos = opts.get(b'subrepos')
5760 subrepos = opts.get(b'subrepos')
5761 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5761 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5762 return cmdutil.remove(
5762 return cmdutil.remove(
5763 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5763 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5764 )
5764 )
5765
5765
5766
5766
5767 @command(
5767 @command(
5768 b'rename|move|mv',
5768 b'rename|move|mv',
5769 [
5769 [
5770 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5770 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5771 (
5771 (
5772 b'f',
5772 b'f',
5773 b'force',
5773 b'force',
5774 None,
5774 None,
5775 _(b'forcibly move over an existing managed file'),
5775 _(b'forcibly move over an existing managed file'),
5776 ),
5776 ),
5777 ]
5777 ]
5778 + walkopts
5778 + walkopts
5779 + dryrunopts,
5779 + dryrunopts,
5780 _(b'[OPTION]... SOURCE... DEST'),
5780 _(b'[OPTION]... SOURCE... DEST'),
5781 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5781 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5782 )
5782 )
5783 def rename(ui, repo, *pats, **opts):
5783 def rename(ui, repo, *pats, **opts):
5784 """rename files; equivalent of copy + remove
5784 """rename files; equivalent of copy + remove
5785
5785
5786 Mark dest as copies of sources; mark sources for deletion. If dest
5786 Mark dest as copies of sources; mark sources for deletion. If dest
5787 is a directory, copies are put in that directory. If dest is a
5787 is a directory, copies are put in that directory. If dest is a
5788 file, there can only be one source.
5788 file, there can only be one source.
5789
5789
5790 By default, this command copies the contents of files as they
5790 By default, this command copies the contents of files as they
5791 exist in the working directory. If invoked with -A/--after, the
5791 exist in the working directory. If invoked with -A/--after, the
5792 operation is recorded, but no copying is performed.
5792 operation is recorded, but no copying is performed.
5793
5793
5794 This command takes effect at the next commit. To undo a rename
5794 This command takes effect at the next commit. To undo a rename
5795 before that, see :hg:`revert`.
5795 before that, see :hg:`revert`.
5796
5796
5797 Returns 0 on success, 1 if errors are encountered.
5797 Returns 0 on success, 1 if errors are encountered.
5798 """
5798 """
5799 opts = pycompat.byteskwargs(opts)
5799 opts = pycompat.byteskwargs(opts)
5800 with repo.wlock(False):
5800 with repo.wlock(False):
5801 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5801 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5802
5802
5803
5803
5804 @command(
5804 @command(
5805 b'resolve',
5805 b'resolve',
5806 [
5806 [
5807 (b'a', b'all', None, _(b'select all unresolved files')),
5807 (b'a', b'all', None, _(b'select all unresolved files')),
5808 (b'l', b'list', None, _(b'list state of files needing merge')),
5808 (b'l', b'list', None, _(b'list state of files needing merge')),
5809 (b'm', b'mark', None, _(b'mark files as resolved')),
5809 (b'm', b'mark', None, _(b'mark files as resolved')),
5810 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5810 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5811 (b'n', b'no-status', None, _(b'hide status prefix')),
5811 (b'n', b'no-status', None, _(b'hide status prefix')),
5812 (b'', b're-merge', None, _(b're-merge files')),
5812 (b'', b're-merge', None, _(b're-merge files')),
5813 ]
5813 ]
5814 + mergetoolopts
5814 + mergetoolopts
5815 + walkopts
5815 + walkopts
5816 + formatteropts,
5816 + formatteropts,
5817 _(b'[OPTION]... [FILE]...'),
5817 _(b'[OPTION]... [FILE]...'),
5818 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5818 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5819 inferrepo=True,
5819 inferrepo=True,
5820 )
5820 )
5821 def resolve(ui, repo, *pats, **opts):
5821 def resolve(ui, repo, *pats, **opts):
5822 """redo merges or set/view the merge status of files
5822 """redo merges or set/view the merge status of files
5823
5823
5824 Merges with unresolved conflicts are often the result of
5824 Merges with unresolved conflicts are often the result of
5825 non-interactive merging using the ``internal:merge`` configuration
5825 non-interactive merging using the ``internal:merge`` configuration
5826 setting, or a command-line merge tool like ``diff3``. The resolve
5826 setting, or a command-line merge tool like ``diff3``. The resolve
5827 command is used to manage the files involved in a merge, after
5827 command is used to manage the files involved in a merge, after
5828 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5828 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5829 working directory must have two parents). See :hg:`help
5829 working directory must have two parents). See :hg:`help
5830 merge-tools` for information on configuring merge tools.
5830 merge-tools` for information on configuring merge tools.
5831
5831
5832 The resolve command can be used in the following ways:
5832 The resolve command can be used in the following ways:
5833
5833
5834 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5834 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5835 the specified files, discarding any previous merge attempts. Re-merging
5835 the specified files, discarding any previous merge attempts. Re-merging
5836 is not performed for files already marked as resolved. Use ``--all/-a``
5836 is not performed for files already marked as resolved. Use ``--all/-a``
5837 to select all unresolved files. ``--tool`` can be used to specify
5837 to select all unresolved files. ``--tool`` can be used to specify
5838 the merge tool used for the given files. It overrides the HGMERGE
5838 the merge tool used for the given files. It overrides the HGMERGE
5839 environment variable and your configuration files. Previous file
5839 environment variable and your configuration files. Previous file
5840 contents are saved with a ``.orig`` suffix.
5840 contents are saved with a ``.orig`` suffix.
5841
5841
5842 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5842 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5843 (e.g. after having manually fixed-up the files). The default is
5843 (e.g. after having manually fixed-up the files). The default is
5844 to mark all unresolved files.
5844 to mark all unresolved files.
5845
5845
5846 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5846 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5847 default is to mark all resolved files.
5847 default is to mark all resolved files.
5848
5848
5849 - :hg:`resolve -l`: list files which had or still have conflicts.
5849 - :hg:`resolve -l`: list files which had or still have conflicts.
5850 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5850 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5851 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5851 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5852 the list. See :hg:`help filesets` for details.
5852 the list. See :hg:`help filesets` for details.
5853
5853
5854 .. note::
5854 .. note::
5855
5855
5856 Mercurial will not let you commit files with unresolved merge
5856 Mercurial will not let you commit files with unresolved merge
5857 conflicts. You must use :hg:`resolve -m ...` before you can
5857 conflicts. You must use :hg:`resolve -m ...` before you can
5858 commit after a conflicting merge.
5858 commit after a conflicting merge.
5859
5859
5860 .. container:: verbose
5860 .. container:: verbose
5861
5861
5862 Template:
5862 Template:
5863
5863
5864 The following keywords are supported in addition to the common template
5864 The following keywords are supported in addition to the common template
5865 keywords and functions. See also :hg:`help templates`.
5865 keywords and functions. See also :hg:`help templates`.
5866
5866
5867 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5867 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5868 :path: String. Repository-absolute path of the file.
5868 :path: String. Repository-absolute path of the file.
5869
5869
5870 Returns 0 on success, 1 if any files fail a resolve attempt.
5870 Returns 0 on success, 1 if any files fail a resolve attempt.
5871 """
5871 """
5872
5872
5873 opts = pycompat.byteskwargs(opts)
5873 opts = pycompat.byteskwargs(opts)
5874 confirm = ui.configbool(b'commands', b'resolve.confirm')
5874 confirm = ui.configbool(b'commands', b'resolve.confirm')
5875 flaglist = b'all mark unmark list no_status re_merge'.split()
5875 flaglist = b'all mark unmark list no_status re_merge'.split()
5876 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5876 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5877
5877
5878 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5878 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5879 if actioncount > 1:
5879 if actioncount > 1:
5880 raise error.Abort(_(b"too many actions specified"))
5880 raise error.Abort(_(b"too many actions specified"))
5881 elif actioncount == 0 and ui.configbool(
5881 elif actioncount == 0 and ui.configbool(
5882 b'commands', b'resolve.explicit-re-merge'
5882 b'commands', b'resolve.explicit-re-merge'
5883 ):
5883 ):
5884 hint = _(b'use --mark, --unmark, --list or --re-merge')
5884 hint = _(b'use --mark, --unmark, --list or --re-merge')
5885 raise error.Abort(_(b'no action specified'), hint=hint)
5885 raise error.Abort(_(b'no action specified'), hint=hint)
5886 if pats and all:
5886 if pats and all:
5887 raise error.Abort(_(b"can't specify --all and patterns"))
5887 raise error.Abort(_(b"can't specify --all and patterns"))
5888 if not (all or pats or show or mark or unmark):
5888 if not (all or pats or show or mark or unmark):
5889 raise error.Abort(
5889 raise error.Abort(
5890 _(b'no files or directories specified'),
5890 _(b'no files or directories specified'),
5891 hint=b'use --all to re-merge all unresolved files',
5891 hint=b'use --all to re-merge all unresolved files',
5892 )
5892 )
5893
5893
5894 if confirm:
5894 if confirm:
5895 if all:
5895 if all:
5896 if ui.promptchoice(
5896 if ui.promptchoice(
5897 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5897 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5898 ):
5898 ):
5899 raise error.Abort(_(b'user quit'))
5899 raise error.Abort(_(b'user quit'))
5900 if mark and not pats:
5900 if mark and not pats:
5901 if ui.promptchoice(
5901 if ui.promptchoice(
5902 _(
5902 _(
5903 b'mark all unresolved files as resolved (yn)?'
5903 b'mark all unresolved files as resolved (yn)?'
5904 b'$$ &Yes $$ &No'
5904 b'$$ &Yes $$ &No'
5905 )
5905 )
5906 ):
5906 ):
5907 raise error.Abort(_(b'user quit'))
5907 raise error.Abort(_(b'user quit'))
5908 if unmark and not pats:
5908 if unmark and not pats:
5909 if ui.promptchoice(
5909 if ui.promptchoice(
5910 _(
5910 _(
5911 b'mark all resolved files as unresolved (yn)?'
5911 b'mark all resolved files as unresolved (yn)?'
5912 b'$$ &Yes $$ &No'
5912 b'$$ &Yes $$ &No'
5913 )
5913 )
5914 ):
5914 ):
5915 raise error.Abort(_(b'user quit'))
5915 raise error.Abort(_(b'user quit'))
5916
5916
5917 uipathfn = scmutil.getuipathfn(repo)
5917 uipathfn = scmutil.getuipathfn(repo)
5918
5918
5919 if show:
5919 if show:
5920 ui.pager(b'resolve')
5920 ui.pager(b'resolve')
5921 fm = ui.formatter(b'resolve', opts)
5921 fm = ui.formatter(b'resolve', opts)
5922 ms = mergemod.mergestate.read(repo)
5922 ms = mergemod.mergestate.read(repo)
5923 wctx = repo[None]
5923 wctx = repo[None]
5924 m = scmutil.match(wctx, pats, opts)
5924 m = scmutil.match(wctx, pats, opts)
5925
5925
5926 # Labels and keys based on merge state. Unresolved path conflicts show
5926 # Labels and keys based on merge state. Unresolved path conflicts show
5927 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5927 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5928 # resolved conflicts.
5928 # resolved conflicts.
5929 mergestateinfo = {
5929 mergestateinfo = {
5930 mergemod.MERGE_RECORD_UNRESOLVED: (b'resolve.unresolved', b'U'),
5930 mergemod.MERGE_RECORD_UNRESOLVED: (b'resolve.unresolved', b'U'),
5931 mergemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5931 mergemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5932 mergemod.MERGE_RECORD_UNRESOLVED_PATH: (
5932 mergemod.MERGE_RECORD_UNRESOLVED_PATH: (
5933 b'resolve.unresolved',
5933 b'resolve.unresolved',
5934 b'P',
5934 b'P',
5935 ),
5935 ),
5936 mergemod.MERGE_RECORD_RESOLVED_PATH: (b'resolve.resolved', b'R'),
5936 mergemod.MERGE_RECORD_RESOLVED_PATH: (b'resolve.resolved', b'R'),
5937 mergemod.MERGE_RECORD_DRIVER_RESOLVED: (
5937 mergemod.MERGE_RECORD_DRIVER_RESOLVED: (
5938 b'resolve.driverresolved',
5938 b'resolve.driverresolved',
5939 b'D',
5939 b'D',
5940 ),
5940 ),
5941 }
5941 }
5942
5942
5943 for f in ms:
5943 for f in ms:
5944 if not m(f):
5944 if not m(f):
5945 continue
5945 continue
5946
5946
5947 label, key = mergestateinfo[ms[f]]
5947 label, key = mergestateinfo[ms[f]]
5948 fm.startitem()
5948 fm.startitem()
5949 fm.context(ctx=wctx)
5949 fm.context(ctx=wctx)
5950 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5950 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5951 fm.data(path=f)
5951 fm.data(path=f)
5952 fm.plain(b'%s\n' % uipathfn(f), label=label)
5952 fm.plain(b'%s\n' % uipathfn(f), label=label)
5953 fm.end()
5953 fm.end()
5954 return 0
5954 return 0
5955
5955
5956 with repo.wlock():
5956 with repo.wlock():
5957 ms = mergemod.mergestate.read(repo)
5957 ms = mergemod.mergestate.read(repo)
5958
5958
5959 if not (ms.active() or repo.dirstate.p2() != nullid):
5959 if not (ms.active() or repo.dirstate.p2() != nullid):
5960 raise error.Abort(
5960 raise error.Abort(
5961 _(b'resolve command not applicable when not merging')
5961 _(b'resolve command not applicable when not merging')
5962 )
5962 )
5963
5963
5964 wctx = repo[None]
5964 wctx = repo[None]
5965
5965
5966 if (
5966 if (
5967 ms.mergedriver
5967 ms.mergedriver
5968 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED
5968 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED
5969 ):
5969 ):
5970 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5970 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5971 ms.commit()
5971 ms.commit()
5972 # allow mark and unmark to go through
5972 # allow mark and unmark to go through
5973 if not mark and not unmark and not proceed:
5973 if not mark and not unmark and not proceed:
5974 return 1
5974 return 1
5975
5975
5976 m = scmutil.match(wctx, pats, opts)
5976 m = scmutil.match(wctx, pats, opts)
5977 ret = 0
5977 ret = 0
5978 didwork = False
5978 didwork = False
5979 runconclude = False
5979 runconclude = False
5980
5980
5981 tocomplete = []
5981 tocomplete = []
5982 hasconflictmarkers = []
5982 hasconflictmarkers = []
5983 if mark:
5983 if mark:
5984 markcheck = ui.config(b'commands', b'resolve.mark-check')
5984 markcheck = ui.config(b'commands', b'resolve.mark-check')
5985 if markcheck not in [b'warn', b'abort']:
5985 if markcheck not in [b'warn', b'abort']:
5986 # Treat all invalid / unrecognized values as 'none'.
5986 # Treat all invalid / unrecognized values as 'none'.
5987 markcheck = False
5987 markcheck = False
5988 for f in ms:
5988 for f in ms:
5989 if not m(f):
5989 if not m(f):
5990 continue
5990 continue
5991
5991
5992 didwork = True
5992 didwork = True
5993
5993
5994 # don't let driver-resolved files be marked, and run the conclude
5994 # don't let driver-resolved files be marked, and run the conclude
5995 # step if asked to resolve
5995 # step if asked to resolve
5996 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
5996 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
5997 exact = m.exact(f)
5997 exact = m.exact(f)
5998 if mark:
5998 if mark:
5999 if exact:
5999 if exact:
6000 ui.warn(
6000 ui.warn(
6001 _(b'not marking %s as it is driver-resolved\n')
6001 _(b'not marking %s as it is driver-resolved\n')
6002 % uipathfn(f)
6002 % uipathfn(f)
6003 )
6003 )
6004 elif unmark:
6004 elif unmark:
6005 if exact:
6005 if exact:
6006 ui.warn(
6006 ui.warn(
6007 _(b'not unmarking %s as it is driver-resolved\n')
6007 _(b'not unmarking %s as it is driver-resolved\n')
6008 % uipathfn(f)
6008 % uipathfn(f)
6009 )
6009 )
6010 else:
6010 else:
6011 runconclude = True
6011 runconclude = True
6012 continue
6012 continue
6013
6013
6014 # path conflicts must be resolved manually
6014 # path conflicts must be resolved manually
6015 if ms[f] in (
6015 if ms[f] in (
6016 mergemod.MERGE_RECORD_UNRESOLVED_PATH,
6016 mergemod.MERGE_RECORD_UNRESOLVED_PATH,
6017 mergemod.MERGE_RECORD_RESOLVED_PATH,
6017 mergemod.MERGE_RECORD_RESOLVED_PATH,
6018 ):
6018 ):
6019 if mark:
6019 if mark:
6020 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
6020 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
6021 elif unmark:
6021 elif unmark:
6022 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
6022 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
6023 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
6023 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
6024 ui.warn(
6024 ui.warn(
6025 _(b'%s: path conflict must be resolved manually\n')
6025 _(b'%s: path conflict must be resolved manually\n')
6026 % uipathfn(f)
6026 % uipathfn(f)
6027 )
6027 )
6028 continue
6028 continue
6029
6029
6030 if mark:
6030 if mark:
6031 if markcheck:
6031 if markcheck:
6032 fdata = repo.wvfs.tryread(f)
6032 fdata = repo.wvfs.tryread(f)
6033 if (
6033 if (
6034 filemerge.hasconflictmarkers(fdata)
6034 filemerge.hasconflictmarkers(fdata)
6035 and ms[f] != mergemod.MERGE_RECORD_RESOLVED
6035 and ms[f] != mergemod.MERGE_RECORD_RESOLVED
6036 ):
6036 ):
6037 hasconflictmarkers.append(f)
6037 hasconflictmarkers.append(f)
6038 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
6038 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
6039 elif unmark:
6039 elif unmark:
6040 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
6040 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
6041 else:
6041 else:
6042 # backup pre-resolve (merge uses .orig for its own purposes)
6042 # backup pre-resolve (merge uses .orig for its own purposes)
6043 a = repo.wjoin(f)
6043 a = repo.wjoin(f)
6044 try:
6044 try:
6045 util.copyfile(a, a + b".resolve")
6045 util.copyfile(a, a + b".resolve")
6046 except (IOError, OSError) as inst:
6046 except (IOError, OSError) as inst:
6047 if inst.errno != errno.ENOENT:
6047 if inst.errno != errno.ENOENT:
6048 raise
6048 raise
6049
6049
6050 try:
6050 try:
6051 # preresolve file
6051 # preresolve file
6052 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6052 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6053 with ui.configoverride(overrides, b'resolve'):
6053 with ui.configoverride(overrides, b'resolve'):
6054 complete, r = ms.preresolve(f, wctx)
6054 complete, r = ms.preresolve(f, wctx)
6055 if not complete:
6055 if not complete:
6056 tocomplete.append(f)
6056 tocomplete.append(f)
6057 elif r:
6057 elif r:
6058 ret = 1
6058 ret = 1
6059 finally:
6059 finally:
6060 ms.commit()
6060 ms.commit()
6061
6061
6062 # replace filemerge's .orig file with our resolve file, but only
6062 # replace filemerge's .orig file with our resolve file, but only
6063 # for merges that are complete
6063 # for merges that are complete
6064 if complete:
6064 if complete:
6065 try:
6065 try:
6066 util.rename(
6066 util.rename(
6067 a + b".resolve", scmutil.backuppath(ui, repo, f)
6067 a + b".resolve", scmutil.backuppath(ui, repo, f)
6068 )
6068 )
6069 except OSError as inst:
6069 except OSError as inst:
6070 if inst.errno != errno.ENOENT:
6070 if inst.errno != errno.ENOENT:
6071 raise
6071 raise
6072
6072
6073 if hasconflictmarkers:
6073 if hasconflictmarkers:
6074 ui.warn(
6074 ui.warn(
6075 _(
6075 _(
6076 b'warning: the following files still have conflict '
6076 b'warning: the following files still have conflict '
6077 b'markers:\n'
6077 b'markers:\n'
6078 )
6078 )
6079 + b''.join(
6079 + b''.join(
6080 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6080 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6081 )
6081 )
6082 )
6082 )
6083 if markcheck == b'abort' and not all and not pats:
6083 if markcheck == b'abort' and not all and not pats:
6084 raise error.Abort(
6084 raise error.Abort(
6085 _(b'conflict markers detected'),
6085 _(b'conflict markers detected'),
6086 hint=_(b'use --all to mark anyway'),
6086 hint=_(b'use --all to mark anyway'),
6087 )
6087 )
6088
6088
6089 for f in tocomplete:
6089 for f in tocomplete:
6090 try:
6090 try:
6091 # resolve file
6091 # resolve file
6092 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6092 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6093 with ui.configoverride(overrides, b'resolve'):
6093 with ui.configoverride(overrides, b'resolve'):
6094 r = ms.resolve(f, wctx)
6094 r = ms.resolve(f, wctx)
6095 if r:
6095 if r:
6096 ret = 1
6096 ret = 1
6097 finally:
6097 finally:
6098 ms.commit()
6098 ms.commit()
6099
6099
6100 # replace filemerge's .orig file with our resolve file
6100 # replace filemerge's .orig file with our resolve file
6101 a = repo.wjoin(f)
6101 a = repo.wjoin(f)
6102 try:
6102 try:
6103 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6103 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6104 except OSError as inst:
6104 except OSError as inst:
6105 if inst.errno != errno.ENOENT:
6105 if inst.errno != errno.ENOENT:
6106 raise
6106 raise
6107
6107
6108 ms.commit()
6108 ms.commit()
6109 ms.recordactions()
6109 ms.recordactions()
6110
6110
6111 if not didwork and pats:
6111 if not didwork and pats:
6112 hint = None
6112 hint = None
6113 if not any([p for p in pats if p.find(b':') >= 0]):
6113 if not any([p for p in pats if p.find(b':') >= 0]):
6114 pats = [b'path:%s' % p for p in pats]
6114 pats = [b'path:%s' % p for p in pats]
6115 m = scmutil.match(wctx, pats, opts)
6115 m = scmutil.match(wctx, pats, opts)
6116 for f in ms:
6116 for f in ms:
6117 if not m(f):
6117 if not m(f):
6118 continue
6118 continue
6119
6119
6120 def flag(o):
6120 def flag(o):
6121 if o == b're_merge':
6121 if o == b're_merge':
6122 return b'--re-merge '
6122 return b'--re-merge '
6123 return b'-%s ' % o[0:1]
6123 return b'-%s ' % o[0:1]
6124
6124
6125 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6125 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6126 hint = _(b"(try: hg resolve %s%s)\n") % (
6126 hint = _(b"(try: hg resolve %s%s)\n") % (
6127 flags,
6127 flags,
6128 b' '.join(pats),
6128 b' '.join(pats),
6129 )
6129 )
6130 break
6130 break
6131 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6131 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6132 if hint:
6132 if hint:
6133 ui.warn(hint)
6133 ui.warn(hint)
6134 elif ms.mergedriver and ms.mdstate() != b's':
6134 elif ms.mergedriver and ms.mdstate() != b's':
6135 # run conclude step when either a driver-resolved file is requested
6135 # run conclude step when either a driver-resolved file is requested
6136 # or there are no driver-resolved files
6136 # or there are no driver-resolved files
6137 # we can't use 'ret' to determine whether any files are unresolved
6137 # we can't use 'ret' to determine whether any files are unresolved
6138 # because we might not have tried to resolve some
6138 # because we might not have tried to resolve some
6139 if (runconclude or not list(ms.driverresolved())) and not list(
6139 if (runconclude or not list(ms.driverresolved())) and not list(
6140 ms.unresolved()
6140 ms.unresolved()
6141 ):
6141 ):
6142 proceed = mergemod.driverconclude(repo, ms, wctx)
6142 proceed = mergemod.driverconclude(repo, ms, wctx)
6143 ms.commit()
6143 ms.commit()
6144 if not proceed:
6144 if not proceed:
6145 return 1
6145 return 1
6146
6146
6147 # Nudge users into finishing an unfinished operation
6147 # Nudge users into finishing an unfinished operation
6148 unresolvedf = list(ms.unresolved())
6148 unresolvedf = list(ms.unresolved())
6149 driverresolvedf = list(ms.driverresolved())
6149 driverresolvedf = list(ms.driverresolved())
6150 if not unresolvedf and not driverresolvedf:
6150 if not unresolvedf and not driverresolvedf:
6151 ui.status(_(b'(no more unresolved files)\n'))
6151 ui.status(_(b'(no more unresolved files)\n'))
6152 cmdutil.checkafterresolved(repo)
6152 cmdutil.checkafterresolved(repo)
6153 elif not unresolvedf:
6153 elif not unresolvedf:
6154 ui.status(
6154 ui.status(
6155 _(
6155 _(
6156 b'(no more unresolved files -- '
6156 b'(no more unresolved files -- '
6157 b'run "hg resolve --all" to conclude)\n'
6157 b'run "hg resolve --all" to conclude)\n'
6158 )
6158 )
6159 )
6159 )
6160
6160
6161 return ret
6161 return ret
6162
6162
6163
6163
6164 @command(
6164 @command(
6165 b'revert',
6165 b'revert',
6166 [
6166 [
6167 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6167 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6168 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6168 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6169 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6169 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6170 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6170 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6171 (b'i', b'interactive', None, _(b'interactively select the changes')),
6171 (b'i', b'interactive', None, _(b'interactively select the changes')),
6172 ]
6172 ]
6173 + walkopts
6173 + walkopts
6174 + dryrunopts,
6174 + dryrunopts,
6175 _(b'[OPTION]... [-r REV] [NAME]...'),
6175 _(b'[OPTION]... [-r REV] [NAME]...'),
6176 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6176 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6177 )
6177 )
6178 def revert(ui, repo, *pats, **opts):
6178 def revert(ui, repo, *pats, **opts):
6179 """restore files to their checkout state
6179 """restore files to their checkout state
6180
6180
6181 .. note::
6181 .. note::
6182
6182
6183 To check out earlier revisions, you should use :hg:`update REV`.
6183 To check out earlier revisions, you should use :hg:`update REV`.
6184 To cancel an uncommitted merge (and lose your changes),
6184 To cancel an uncommitted merge (and lose your changes),
6185 use :hg:`merge --abort`.
6185 use :hg:`merge --abort`.
6186
6186
6187 With no revision specified, revert the specified files or directories
6187 With no revision specified, revert the specified files or directories
6188 to the contents they had in the parent of the working directory.
6188 to the contents they had in the parent of the working directory.
6189 This restores the contents of files to an unmodified
6189 This restores the contents of files to an unmodified
6190 state and unschedules adds, removes, copies, and renames. If the
6190 state and unschedules adds, removes, copies, and renames. If the
6191 working directory has two parents, you must explicitly specify a
6191 working directory has two parents, you must explicitly specify a
6192 revision.
6192 revision.
6193
6193
6194 Using the -r/--rev or -d/--date options, revert the given files or
6194 Using the -r/--rev or -d/--date options, revert the given files or
6195 directories to their states as of a specific revision. Because
6195 directories to their states as of a specific revision. Because
6196 revert does not change the working directory parents, this will
6196 revert does not change the working directory parents, this will
6197 cause these files to appear modified. This can be helpful to "back
6197 cause these files to appear modified. This can be helpful to "back
6198 out" some or all of an earlier change. See :hg:`backout` for a
6198 out" some or all of an earlier change. See :hg:`backout` for a
6199 related method.
6199 related method.
6200
6200
6201 Modified files are saved with a .orig suffix before reverting.
6201 Modified files are saved with a .orig suffix before reverting.
6202 To disable these backups, use --no-backup. It is possible to store
6202 To disable these backups, use --no-backup. It is possible to store
6203 the backup files in a custom directory relative to the root of the
6203 the backup files in a custom directory relative to the root of the
6204 repository by setting the ``ui.origbackuppath`` configuration
6204 repository by setting the ``ui.origbackuppath`` configuration
6205 option.
6205 option.
6206
6206
6207 See :hg:`help dates` for a list of formats valid for -d/--date.
6207 See :hg:`help dates` for a list of formats valid for -d/--date.
6208
6208
6209 See :hg:`help backout` for a way to reverse the effect of an
6209 See :hg:`help backout` for a way to reverse the effect of an
6210 earlier changeset.
6210 earlier changeset.
6211
6211
6212 Returns 0 on success.
6212 Returns 0 on success.
6213 """
6213 """
6214
6214
6215 opts = pycompat.byteskwargs(opts)
6215 opts = pycompat.byteskwargs(opts)
6216 if opts.get(b"date"):
6216 if opts.get(b"date"):
6217 if opts.get(b"rev"):
6217 if opts.get(b"rev"):
6218 raise error.Abort(_(b"you can't specify a revision and a date"))
6218 raise error.Abort(_(b"you can't specify a revision and a date"))
6219 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6219 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6220
6220
6221 parent, p2 = repo.dirstate.parents()
6221 parent, p2 = repo.dirstate.parents()
6222 if not opts.get(b'rev') and p2 != nullid:
6222 if not opts.get(b'rev') and p2 != nullid:
6223 # revert after merge is a trap for new users (issue2915)
6223 # revert after merge is a trap for new users (issue2915)
6224 raise error.Abort(
6224 raise error.Abort(
6225 _(b'uncommitted merge with no revision specified'),
6225 _(b'uncommitted merge with no revision specified'),
6226 hint=_(b"use 'hg update' or see 'hg help revert'"),
6226 hint=_(b"use 'hg update' or see 'hg help revert'"),
6227 )
6227 )
6228
6228
6229 rev = opts.get(b'rev')
6229 rev = opts.get(b'rev')
6230 if rev:
6230 if rev:
6231 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6231 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6232 ctx = scmutil.revsingle(repo, rev)
6232 ctx = scmutil.revsingle(repo, rev)
6233
6233
6234 if not (
6234 if not (
6235 pats
6235 pats
6236 or opts.get(b'include')
6236 or opts.get(b'include')
6237 or opts.get(b'exclude')
6237 or opts.get(b'exclude')
6238 or opts.get(b'all')
6238 or opts.get(b'all')
6239 or opts.get(b'interactive')
6239 or opts.get(b'interactive')
6240 ):
6240 ):
6241 msg = _(b"no files or directories specified")
6241 msg = _(b"no files or directories specified")
6242 if p2 != nullid:
6242 if p2 != nullid:
6243 hint = _(
6243 hint = _(
6244 b"uncommitted merge, use --all to discard all changes,"
6244 b"uncommitted merge, use --all to discard all changes,"
6245 b" or 'hg update -C .' to abort the merge"
6245 b" or 'hg update -C .' to abort the merge"
6246 )
6246 )
6247 raise error.Abort(msg, hint=hint)
6247 raise error.Abort(msg, hint=hint)
6248 dirty = any(repo.status())
6248 dirty = any(repo.status())
6249 node = ctx.node()
6249 node = ctx.node()
6250 if node != parent:
6250 if node != parent:
6251 if dirty:
6251 if dirty:
6252 hint = (
6252 hint = (
6253 _(
6253 _(
6254 b"uncommitted changes, use --all to discard all"
6254 b"uncommitted changes, use --all to discard all"
6255 b" changes, or 'hg update %d' to update"
6255 b" changes, or 'hg update %d' to update"
6256 )
6256 )
6257 % ctx.rev()
6257 % ctx.rev()
6258 )
6258 )
6259 else:
6259 else:
6260 hint = (
6260 hint = (
6261 _(
6261 _(
6262 b"use --all to revert all files,"
6262 b"use --all to revert all files,"
6263 b" or 'hg update %d' to update"
6263 b" or 'hg update %d' to update"
6264 )
6264 )
6265 % ctx.rev()
6265 % ctx.rev()
6266 )
6266 )
6267 elif dirty:
6267 elif dirty:
6268 hint = _(b"uncommitted changes, use --all to discard all changes")
6268 hint = _(b"uncommitted changes, use --all to discard all changes")
6269 else:
6269 else:
6270 hint = _(b"use --all to revert all files")
6270 hint = _(b"use --all to revert all files")
6271 raise error.Abort(msg, hint=hint)
6271 raise error.Abort(msg, hint=hint)
6272
6272
6273 return cmdutil.revert(
6273 return cmdutil.revert(
6274 ui, repo, ctx, (parent, p2), *pats, **pycompat.strkwargs(opts)
6274 ui, repo, ctx, (parent, p2), *pats, **pycompat.strkwargs(opts)
6275 )
6275 )
6276
6276
6277
6277
6278 @command(
6278 @command(
6279 b'rollback',
6279 b'rollback',
6280 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6280 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6281 helpcategory=command.CATEGORY_MAINTENANCE,
6281 helpcategory=command.CATEGORY_MAINTENANCE,
6282 )
6282 )
6283 def rollback(ui, repo, **opts):
6283 def rollback(ui, repo, **opts):
6284 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6284 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6285
6285
6286 Please use :hg:`commit --amend` instead of rollback to correct
6286 Please use :hg:`commit --amend` instead of rollback to correct
6287 mistakes in the last commit.
6287 mistakes in the last commit.
6288
6288
6289 This command should be used with care. There is only one level of
6289 This command should be used with care. There is only one level of
6290 rollback, and there is no way to undo a rollback. It will also
6290 rollback, and there is no way to undo a rollback. It will also
6291 restore the dirstate at the time of the last transaction, losing
6291 restore the dirstate at the time of the last transaction, losing
6292 any dirstate changes since that time. This command does not alter
6292 any dirstate changes since that time. This command does not alter
6293 the working directory.
6293 the working directory.
6294
6294
6295 Transactions are used to encapsulate the effects of all commands
6295 Transactions are used to encapsulate the effects of all commands
6296 that create new changesets or propagate existing changesets into a
6296 that create new changesets or propagate existing changesets into a
6297 repository.
6297 repository.
6298
6298
6299 .. container:: verbose
6299 .. container:: verbose
6300
6300
6301 For example, the following commands are transactional, and their
6301 For example, the following commands are transactional, and their
6302 effects can be rolled back:
6302 effects can be rolled back:
6303
6303
6304 - commit
6304 - commit
6305 - import
6305 - import
6306 - pull
6306 - pull
6307 - push (with this repository as the destination)
6307 - push (with this repository as the destination)
6308 - unbundle
6308 - unbundle
6309
6309
6310 To avoid permanent data loss, rollback will refuse to rollback a
6310 To avoid permanent data loss, rollback will refuse to rollback a
6311 commit transaction if it isn't checked out. Use --force to
6311 commit transaction if it isn't checked out. Use --force to
6312 override this protection.
6312 override this protection.
6313
6313
6314 The rollback command can be entirely disabled by setting the
6314 The rollback command can be entirely disabled by setting the
6315 ``ui.rollback`` configuration setting to false. If you're here
6315 ``ui.rollback`` configuration setting to false. If you're here
6316 because you want to use rollback and it's disabled, you can
6316 because you want to use rollback and it's disabled, you can
6317 re-enable the command by setting ``ui.rollback`` to true.
6317 re-enable the command by setting ``ui.rollback`` to true.
6318
6318
6319 This command is not intended for use on public repositories. Once
6319 This command is not intended for use on public repositories. Once
6320 changes are visible for pull by other users, rolling a transaction
6320 changes are visible for pull by other users, rolling a transaction
6321 back locally is ineffective (someone else may already have pulled
6321 back locally is ineffective (someone else may already have pulled
6322 the changes). Furthermore, a race is possible with readers of the
6322 the changes). Furthermore, a race is possible with readers of the
6323 repository; for example an in-progress pull from the repository
6323 repository; for example an in-progress pull from the repository
6324 may fail if a rollback is performed.
6324 may fail if a rollback is performed.
6325
6325
6326 Returns 0 on success, 1 if no rollback data is available.
6326 Returns 0 on success, 1 if no rollback data is available.
6327 """
6327 """
6328 if not ui.configbool(b'ui', b'rollback'):
6328 if not ui.configbool(b'ui', b'rollback'):
6329 raise error.Abort(
6329 raise error.Abort(
6330 _(b'rollback is disabled because it is unsafe'),
6330 _(b'rollback is disabled because it is unsafe'),
6331 hint=b'see `hg help -v rollback` for information',
6331 hint=b'see `hg help -v rollback` for information',
6332 )
6332 )
6333 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6333 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6334
6334
6335
6335
6336 @command(
6336 @command(
6337 b'root',
6337 b'root',
6338 [] + formatteropts,
6338 [] + formatteropts,
6339 intents={INTENT_READONLY},
6339 intents={INTENT_READONLY},
6340 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6340 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6341 )
6341 )
6342 def root(ui, repo, **opts):
6342 def root(ui, repo, **opts):
6343 """print the root (top) of the current working directory
6343 """print the root (top) of the current working directory
6344
6344
6345 Print the root directory of the current repository.
6345 Print the root directory of the current repository.
6346
6346
6347 .. container:: verbose
6347 .. container:: verbose
6348
6348
6349 Template:
6349 Template:
6350
6350
6351 The following keywords are supported in addition to the common template
6351 The following keywords are supported in addition to the common template
6352 keywords and functions. See also :hg:`help templates`.
6352 keywords and functions. See also :hg:`help templates`.
6353
6353
6354 :hgpath: String. Path to the .hg directory.
6354 :hgpath: String. Path to the .hg directory.
6355 :storepath: String. Path to the directory holding versioned data.
6355 :storepath: String. Path to the directory holding versioned data.
6356
6356
6357 Returns 0 on success.
6357 Returns 0 on success.
6358 """
6358 """
6359 opts = pycompat.byteskwargs(opts)
6359 opts = pycompat.byteskwargs(opts)
6360 with ui.formatter(b'root', opts) as fm:
6360 with ui.formatter(b'root', opts) as fm:
6361 fm.startitem()
6361 fm.startitem()
6362 fm.write(b'reporoot', b'%s\n', repo.root)
6362 fm.write(b'reporoot', b'%s\n', repo.root)
6363 fm.data(hgpath=repo.path, storepath=repo.spath)
6363 fm.data(hgpath=repo.path, storepath=repo.spath)
6364
6364
6365
6365
6366 @command(
6366 @command(
6367 b'serve',
6367 b'serve',
6368 [
6368 [
6369 (
6369 (
6370 b'A',
6370 b'A',
6371 b'accesslog',
6371 b'accesslog',
6372 b'',
6372 b'',
6373 _(b'name of access log file to write to'),
6373 _(b'name of access log file to write to'),
6374 _(b'FILE'),
6374 _(b'FILE'),
6375 ),
6375 ),
6376 (b'd', b'daemon', None, _(b'run server in background')),
6376 (b'd', b'daemon', None, _(b'run server in background')),
6377 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6377 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6378 (
6378 (
6379 b'E',
6379 b'E',
6380 b'errorlog',
6380 b'errorlog',
6381 b'',
6381 b'',
6382 _(b'name of error log file to write to'),
6382 _(b'name of error log file to write to'),
6383 _(b'FILE'),
6383 _(b'FILE'),
6384 ),
6384 ),
6385 # use string type, then we can check if something was passed
6385 # use string type, then we can check if something was passed
6386 (
6386 (
6387 b'p',
6387 b'p',
6388 b'port',
6388 b'port',
6389 b'',
6389 b'',
6390 _(b'port to listen on (default: 8000)'),
6390 _(b'port to listen on (default: 8000)'),
6391 _(b'PORT'),
6391 _(b'PORT'),
6392 ),
6392 ),
6393 (
6393 (
6394 b'a',
6394 b'a',
6395 b'address',
6395 b'address',
6396 b'',
6396 b'',
6397 _(b'address to listen on (default: all interfaces)'),
6397 _(b'address to listen on (default: all interfaces)'),
6398 _(b'ADDR'),
6398 _(b'ADDR'),
6399 ),
6399 ),
6400 (
6400 (
6401 b'',
6401 b'',
6402 b'prefix',
6402 b'prefix',
6403 b'',
6403 b'',
6404 _(b'prefix path to serve from (default: server root)'),
6404 _(b'prefix path to serve from (default: server root)'),
6405 _(b'PREFIX'),
6405 _(b'PREFIX'),
6406 ),
6406 ),
6407 (
6407 (
6408 b'n',
6408 b'n',
6409 b'name',
6409 b'name',
6410 b'',
6410 b'',
6411 _(b'name to show in web pages (default: working directory)'),
6411 _(b'name to show in web pages (default: working directory)'),
6412 _(b'NAME'),
6412 _(b'NAME'),
6413 ),
6413 ),
6414 (
6414 (
6415 b'',
6415 b'',
6416 b'web-conf',
6416 b'web-conf',
6417 b'',
6417 b'',
6418 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6418 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6419 _(b'FILE'),
6419 _(b'FILE'),
6420 ),
6420 ),
6421 (
6421 (
6422 b'',
6422 b'',
6423 b'webdir-conf',
6423 b'webdir-conf',
6424 b'',
6424 b'',
6425 _(b'name of the hgweb config file (DEPRECATED)'),
6425 _(b'name of the hgweb config file (DEPRECATED)'),
6426 _(b'FILE'),
6426 _(b'FILE'),
6427 ),
6427 ),
6428 (
6428 (
6429 b'',
6429 b'',
6430 b'pid-file',
6430 b'pid-file',
6431 b'',
6431 b'',
6432 _(b'name of file to write process ID to'),
6432 _(b'name of file to write process ID to'),
6433 _(b'FILE'),
6433 _(b'FILE'),
6434 ),
6434 ),
6435 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6435 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6436 (
6436 (
6437 b'',
6437 b'',
6438 b'cmdserver',
6438 b'cmdserver',
6439 b'',
6439 b'',
6440 _(b'for remote clients (ADVANCED)'),
6440 _(b'for remote clients (ADVANCED)'),
6441 _(b'MODE'),
6441 _(b'MODE'),
6442 ),
6442 ),
6443 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6443 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6444 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6444 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6445 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6445 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6446 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6446 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6447 (b'', b'print-url', None, _(b'start and print only the URL')),
6447 (b'', b'print-url', None, _(b'start and print only the URL')),
6448 ]
6448 ]
6449 + subrepoopts,
6449 + subrepoopts,
6450 _(b'[OPTION]...'),
6450 _(b'[OPTION]...'),
6451 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6451 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6452 helpbasic=True,
6452 helpbasic=True,
6453 optionalrepo=True,
6453 optionalrepo=True,
6454 )
6454 )
6455 def serve(ui, repo, **opts):
6455 def serve(ui, repo, **opts):
6456 """start stand-alone webserver
6456 """start stand-alone webserver
6457
6457
6458 Start a local HTTP repository browser and pull server. You can use
6458 Start a local HTTP repository browser and pull server. You can use
6459 this for ad-hoc sharing and browsing of repositories. It is
6459 this for ad-hoc sharing and browsing of repositories. It is
6460 recommended to use a real web server to serve a repository for
6460 recommended to use a real web server to serve a repository for
6461 longer periods of time.
6461 longer periods of time.
6462
6462
6463 Please note that the server does not implement access control.
6463 Please note that the server does not implement access control.
6464 This means that, by default, anybody can read from the server and
6464 This means that, by default, anybody can read from the server and
6465 nobody can write to it by default. Set the ``web.allow-push``
6465 nobody can write to it by default. Set the ``web.allow-push``
6466 option to ``*`` to allow everybody to push to the server. You
6466 option to ``*`` to allow everybody to push to the server. You
6467 should use a real web server if you need to authenticate users.
6467 should use a real web server if you need to authenticate users.
6468
6468
6469 By default, the server logs accesses to stdout and errors to
6469 By default, the server logs accesses to stdout and errors to
6470 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6470 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6471 files.
6471 files.
6472
6472
6473 To have the server choose a free port number to listen on, specify
6473 To have the server choose a free port number to listen on, specify
6474 a port number of 0; in this case, the server will print the port
6474 a port number of 0; in this case, the server will print the port
6475 number it uses.
6475 number it uses.
6476
6476
6477 Returns 0 on success.
6477 Returns 0 on success.
6478 """
6478 """
6479
6479
6480 opts = pycompat.byteskwargs(opts)
6480 opts = pycompat.byteskwargs(opts)
6481 if opts[b"stdio"] and opts[b"cmdserver"]:
6481 if opts[b"stdio"] and opts[b"cmdserver"]:
6482 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6482 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6483 if opts[b"print_url"] and ui.verbose:
6483 if opts[b"print_url"] and ui.verbose:
6484 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6484 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6485
6485
6486 if opts[b"stdio"]:
6486 if opts[b"stdio"]:
6487 if repo is None:
6487 if repo is None:
6488 raise error.RepoError(
6488 raise error.RepoError(
6489 _(b"there is no Mercurial repository here (.hg not found)")
6489 _(b"there is no Mercurial repository here (.hg not found)")
6490 )
6490 )
6491 s = wireprotoserver.sshserver(ui, repo)
6491 s = wireprotoserver.sshserver(ui, repo)
6492 s.serve_forever()
6492 s.serve_forever()
6493
6493
6494 service = server.createservice(ui, repo, opts)
6494 service = server.createservice(ui, repo, opts)
6495 return server.runservice(opts, initfn=service.init, runfn=service.run)
6495 return server.runservice(opts, initfn=service.init, runfn=service.run)
6496
6496
6497
6497
6498 @command(
6498 @command(
6499 b'shelve',
6499 b'shelve',
6500 [
6500 [
6501 (
6501 (
6502 b'A',
6502 b'A',
6503 b'addremove',
6503 b'addremove',
6504 None,
6504 None,
6505 _(b'mark new/missing files as added/removed before shelving'),
6505 _(b'mark new/missing files as added/removed before shelving'),
6506 ),
6506 ),
6507 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6507 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6508 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6508 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6509 (
6509 (
6510 b'',
6510 b'',
6511 b'date',
6511 b'date',
6512 b'',
6512 b'',
6513 _(b'shelve with the specified commit date'),
6513 _(b'shelve with the specified commit date'),
6514 _(b'DATE'),
6514 _(b'DATE'),
6515 ),
6515 ),
6516 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6516 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6517 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6517 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6518 (
6518 (
6519 b'k',
6519 b'k',
6520 b'keep',
6520 b'keep',
6521 False,
6521 False,
6522 _(b'shelve, but keep changes in the working directory'),
6522 _(b'shelve, but keep changes in the working directory'),
6523 ),
6523 ),
6524 (b'l', b'list', None, _(b'list current shelves')),
6524 (b'l', b'list', None, _(b'list current shelves')),
6525 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6525 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6526 (
6526 (
6527 b'n',
6527 b'n',
6528 b'name',
6528 b'name',
6529 b'',
6529 b'',
6530 _(b'use the given name for the shelved commit'),
6530 _(b'use the given name for the shelved commit'),
6531 _(b'NAME'),
6531 _(b'NAME'),
6532 ),
6532 ),
6533 (
6533 (
6534 b'p',
6534 b'p',
6535 b'patch',
6535 b'patch',
6536 None,
6536 None,
6537 _(
6537 _(
6538 b'output patches for changes (provide the names of the shelved '
6538 b'output patches for changes (provide the names of the shelved '
6539 b'changes as positional arguments)'
6539 b'changes as positional arguments)'
6540 ),
6540 ),
6541 ),
6541 ),
6542 (b'i', b'interactive', None, _(b'interactive mode')),
6542 (b'i', b'interactive', None, _(b'interactive mode')),
6543 (
6543 (
6544 b'',
6544 b'',
6545 b'stat',
6545 b'stat',
6546 None,
6546 None,
6547 _(
6547 _(
6548 b'output diffstat-style summary of changes (provide the names of '
6548 b'output diffstat-style summary of changes (provide the names of '
6549 b'the shelved changes as positional arguments)'
6549 b'the shelved changes as positional arguments)'
6550 ),
6550 ),
6551 ),
6551 ),
6552 ]
6552 ]
6553 + cmdutil.walkopts,
6553 + cmdutil.walkopts,
6554 _(b'hg shelve [OPTION]... [FILE]...'),
6554 _(b'hg shelve [OPTION]... [FILE]...'),
6555 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6555 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6556 )
6556 )
6557 def shelve(ui, repo, *pats, **opts):
6557 def shelve(ui, repo, *pats, **opts):
6558 '''save and set aside changes from the working directory
6558 '''save and set aside changes from the working directory
6559
6559
6560 Shelving takes files that "hg status" reports as not clean, saves
6560 Shelving takes files that "hg status" reports as not clean, saves
6561 the modifications to a bundle (a shelved change), and reverts the
6561 the modifications to a bundle (a shelved change), and reverts the
6562 files so that their state in the working directory becomes clean.
6562 files so that their state in the working directory becomes clean.
6563
6563
6564 To restore these changes to the working directory, using "hg
6564 To restore these changes to the working directory, using "hg
6565 unshelve"; this will work even if you switch to a different
6565 unshelve"; this will work even if you switch to a different
6566 commit.
6566 commit.
6567
6567
6568 When no files are specified, "hg shelve" saves all not-clean
6568 When no files are specified, "hg shelve" saves all not-clean
6569 files. If specific files or directories are named, only changes to
6569 files. If specific files or directories are named, only changes to
6570 those files are shelved.
6570 those files are shelved.
6571
6571
6572 In bare shelve (when no files are specified, without interactive,
6572 In bare shelve (when no files are specified, without interactive,
6573 include and exclude option), shelving remembers information if the
6573 include and exclude option), shelving remembers information if the
6574 working directory was on newly created branch, in other words working
6574 working directory was on newly created branch, in other words working
6575 directory was on different branch than its first parent. In this
6575 directory was on different branch than its first parent. In this
6576 situation unshelving restores branch information to the working directory.
6576 situation unshelving restores branch information to the working directory.
6577
6577
6578 Each shelved change has a name that makes it easier to find later.
6578 Each shelved change has a name that makes it easier to find later.
6579 The name of a shelved change defaults to being based on the active
6579 The name of a shelved change defaults to being based on the active
6580 bookmark, or if there is no active bookmark, the current named
6580 bookmark, or if there is no active bookmark, the current named
6581 branch. To specify a different name, use ``--name``.
6581 branch. To specify a different name, use ``--name``.
6582
6582
6583 To see a list of existing shelved changes, use the ``--list``
6583 To see a list of existing shelved changes, use the ``--list``
6584 option. For each shelved change, this will print its name, age,
6584 option. For each shelved change, this will print its name, age,
6585 and description; use ``--patch`` or ``--stat`` for more details.
6585 and description; use ``--patch`` or ``--stat`` for more details.
6586
6586
6587 To delete specific shelved changes, use ``--delete``. To delete
6587 To delete specific shelved changes, use ``--delete``. To delete
6588 all shelved changes, use ``--cleanup``.
6588 all shelved changes, use ``--cleanup``.
6589 '''
6589 '''
6590 opts = pycompat.byteskwargs(opts)
6590 opts = pycompat.byteskwargs(opts)
6591 allowables = [
6591 allowables = [
6592 (b'addremove', {b'create'}), # 'create' is pseudo action
6592 (b'addremove', {b'create'}), # 'create' is pseudo action
6593 (b'unknown', {b'create'}),
6593 (b'unknown', {b'create'}),
6594 (b'cleanup', {b'cleanup'}),
6594 (b'cleanup', {b'cleanup'}),
6595 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6595 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6596 (b'delete', {b'delete'}),
6596 (b'delete', {b'delete'}),
6597 (b'edit', {b'create'}),
6597 (b'edit', {b'create'}),
6598 (b'keep', {b'create'}),
6598 (b'keep', {b'create'}),
6599 (b'list', {b'list'}),
6599 (b'list', {b'list'}),
6600 (b'message', {b'create'}),
6600 (b'message', {b'create'}),
6601 (b'name', {b'create'}),
6601 (b'name', {b'create'}),
6602 (b'patch', {b'patch', b'list'}),
6602 (b'patch', {b'patch', b'list'}),
6603 (b'stat', {b'stat', b'list'}),
6603 (b'stat', {b'stat', b'list'}),
6604 ]
6604 ]
6605
6605
6606 def checkopt(opt):
6606 def checkopt(opt):
6607 if opts.get(opt):
6607 if opts.get(opt):
6608 for i, allowable in allowables:
6608 for i, allowable in allowables:
6609 if opts[i] and opt not in allowable:
6609 if opts[i] and opt not in allowable:
6610 raise error.Abort(
6610 raise error.Abort(
6611 _(
6611 _(
6612 b"options '--%s' and '--%s' may not be "
6612 b"options '--%s' and '--%s' may not be "
6613 b"used together"
6613 b"used together"
6614 )
6614 )
6615 % (opt, i)
6615 % (opt, i)
6616 )
6616 )
6617 return True
6617 return True
6618
6618
6619 if checkopt(b'cleanup'):
6619 if checkopt(b'cleanup'):
6620 if pats:
6620 if pats:
6621 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6621 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6622 return shelvemod.cleanupcmd(ui, repo)
6622 return shelvemod.cleanupcmd(ui, repo)
6623 elif checkopt(b'delete'):
6623 elif checkopt(b'delete'):
6624 return shelvemod.deletecmd(ui, repo, pats)
6624 return shelvemod.deletecmd(ui, repo, pats)
6625 elif checkopt(b'list'):
6625 elif checkopt(b'list'):
6626 return shelvemod.listcmd(ui, repo, pats, opts)
6626 return shelvemod.listcmd(ui, repo, pats, opts)
6627 elif checkopt(b'patch') or checkopt(b'stat'):
6627 elif checkopt(b'patch') or checkopt(b'stat'):
6628 return shelvemod.patchcmds(ui, repo, pats, opts)
6628 return shelvemod.patchcmds(ui, repo, pats, opts)
6629 else:
6629 else:
6630 return shelvemod.createcmd(ui, repo, pats, opts)
6630 return shelvemod.createcmd(ui, repo, pats, opts)
6631
6631
6632
6632
6633 _NOTTERSE = b'nothing'
6633 _NOTTERSE = b'nothing'
6634
6634
6635
6635
6636 @command(
6636 @command(
6637 b'status|st',
6637 b'status|st',
6638 [
6638 [
6639 (b'A', b'all', None, _(b'show status of all files')),
6639 (b'A', b'all', None, _(b'show status of all files')),
6640 (b'm', b'modified', None, _(b'show only modified files')),
6640 (b'm', b'modified', None, _(b'show only modified files')),
6641 (b'a', b'added', None, _(b'show only added files')),
6641 (b'a', b'added', None, _(b'show only added files')),
6642 (b'r', b'removed', None, _(b'show only removed files')),
6642 (b'r', b'removed', None, _(b'show only removed files')),
6643 (b'd', b'deleted', None, _(b'show only deleted (but tracked) files')),
6643 (b'd', b'deleted', None, _(b'show only deleted (but tracked) files')),
6644 (b'c', b'clean', None, _(b'show only files without changes')),
6644 (b'c', b'clean', None, _(b'show only files without changes')),
6645 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6645 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6646 (b'i', b'ignored', None, _(b'show only ignored files')),
6646 (b'i', b'ignored', None, _(b'show only ignored files')),
6647 (b'n', b'no-status', None, _(b'hide status prefix')),
6647 (b'n', b'no-status', None, _(b'hide status prefix')),
6648 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6648 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6649 (b'C', b'copies', None, _(b'show source of copied files')),
6649 (b'C', b'copies', None, _(b'show source of copied files')),
6650 (
6650 (
6651 b'0',
6651 b'0',
6652 b'print0',
6652 b'print0',
6653 None,
6653 None,
6654 _(b'end filenames with NUL, for use with xargs'),
6654 _(b'end filenames with NUL, for use with xargs'),
6655 ),
6655 ),
6656 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6656 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6657 (
6657 (
6658 b'',
6658 b'',
6659 b'change',
6659 b'change',
6660 b'',
6660 b'',
6661 _(b'list the changed files of a revision'),
6661 _(b'list the changed files of a revision'),
6662 _(b'REV'),
6662 _(b'REV'),
6663 ),
6663 ),
6664 ]
6664 ]
6665 + walkopts
6665 + walkopts
6666 + subrepoopts
6666 + subrepoopts
6667 + formatteropts,
6667 + formatteropts,
6668 _(b'[OPTION]... [FILE]...'),
6668 _(b'[OPTION]... [FILE]...'),
6669 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6669 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6670 helpbasic=True,
6670 helpbasic=True,
6671 inferrepo=True,
6671 inferrepo=True,
6672 intents={INTENT_READONLY},
6672 intents={INTENT_READONLY},
6673 )
6673 )
6674 def status(ui, repo, *pats, **opts):
6674 def status(ui, repo, *pats, **opts):
6675 """show changed files in the working directory
6675 """show changed files in the working directory
6676
6676
6677 Show status of files in the repository. If names are given, only
6677 Show status of files in the repository. If names are given, only
6678 files that match are shown. Files that are clean or ignored or
6678 files that match are shown. Files that are clean or ignored or
6679 the source of a copy/move operation, are not listed unless
6679 the source of a copy/move operation, are not listed unless
6680 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6680 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6681 Unless options described with "show only ..." are given, the
6681 Unless options described with "show only ..." are given, the
6682 options -mardu are used.
6682 options -mardu are used.
6683
6683
6684 Option -q/--quiet hides untracked (unknown and ignored) files
6684 Option -q/--quiet hides untracked (unknown and ignored) files
6685 unless explicitly requested with -u/--unknown or -i/--ignored.
6685 unless explicitly requested with -u/--unknown or -i/--ignored.
6686
6686
6687 .. note::
6687 .. note::
6688
6688
6689 :hg:`status` may appear to disagree with diff if permissions have
6689 :hg:`status` may appear to disagree with diff if permissions have
6690 changed or a merge has occurred. The standard diff format does
6690 changed or a merge has occurred. The standard diff format does
6691 not report permission changes and diff only reports changes
6691 not report permission changes and diff only reports changes
6692 relative to one merge parent.
6692 relative to one merge parent.
6693
6693
6694 If one revision is given, it is used as the base revision.
6694 If one revision is given, it is used as the base revision.
6695 If two revisions are given, the differences between them are
6695 If two revisions are given, the differences between them are
6696 shown. The --change option can also be used as a shortcut to list
6696 shown. The --change option can also be used as a shortcut to list
6697 the changed files of a revision from its first parent.
6697 the changed files of a revision from its first parent.
6698
6698
6699 The codes used to show the status of files are::
6699 The codes used to show the status of files are::
6700
6700
6701 M = modified
6701 M = modified
6702 A = added
6702 A = added
6703 R = removed
6703 R = removed
6704 C = clean
6704 C = clean
6705 ! = missing (deleted by non-hg command, but still tracked)
6705 ! = missing (deleted by non-hg command, but still tracked)
6706 ? = not tracked
6706 ? = not tracked
6707 I = ignored
6707 I = ignored
6708 = origin of the previous file (with --copies)
6708 = origin of the previous file (with --copies)
6709
6709
6710 .. container:: verbose
6710 .. container:: verbose
6711
6711
6712 The -t/--terse option abbreviates the output by showing only the directory
6712 The -t/--terse option abbreviates the output by showing only the directory
6713 name if all the files in it share the same status. The option takes an
6713 name if all the files in it share the same status. The option takes an
6714 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6714 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6715 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6715 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6716 for 'ignored' and 'c' for clean.
6716 for 'ignored' and 'c' for clean.
6717
6717
6718 It abbreviates only those statuses which are passed. Note that clean and
6718 It abbreviates only those statuses which are passed. Note that clean and
6719 ignored files are not displayed with '--terse ic' unless the -c/--clean
6719 ignored files are not displayed with '--terse ic' unless the -c/--clean
6720 and -i/--ignored options are also used.
6720 and -i/--ignored options are also used.
6721
6721
6722 The -v/--verbose option shows information when the repository is in an
6722 The -v/--verbose option shows information when the repository is in an
6723 unfinished merge, shelve, rebase state etc. You can have this behavior
6723 unfinished merge, shelve, rebase state etc. You can have this behavior
6724 turned on by default by enabling the ``commands.status.verbose`` option.
6724 turned on by default by enabling the ``commands.status.verbose`` option.
6725
6725
6726 You can skip displaying some of these states by setting
6726 You can skip displaying some of these states by setting
6727 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6727 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6728 'histedit', 'merge', 'rebase', or 'unshelve'.
6728 'histedit', 'merge', 'rebase', or 'unshelve'.
6729
6729
6730 Template:
6730 Template:
6731
6731
6732 The following keywords are supported in addition to the common template
6732 The following keywords are supported in addition to the common template
6733 keywords and functions. See also :hg:`help templates`.
6733 keywords and functions. See also :hg:`help templates`.
6734
6734
6735 :path: String. Repository-absolute path of the file.
6735 :path: String. Repository-absolute path of the file.
6736 :source: String. Repository-absolute path of the file originated from.
6736 :source: String. Repository-absolute path of the file originated from.
6737 Available if ``--copies`` is specified.
6737 Available if ``--copies`` is specified.
6738 :status: String. Character denoting file's status.
6738 :status: String. Character denoting file's status.
6739
6739
6740 Examples:
6740 Examples:
6741
6741
6742 - show changes in the working directory relative to a
6742 - show changes in the working directory relative to a
6743 changeset::
6743 changeset::
6744
6744
6745 hg status --rev 9353
6745 hg status --rev 9353
6746
6746
6747 - show changes in the working directory relative to the
6747 - show changes in the working directory relative to the
6748 current directory (see :hg:`help patterns` for more information)::
6748 current directory (see :hg:`help patterns` for more information)::
6749
6749
6750 hg status re:
6750 hg status re:
6751
6751
6752 - show all changes including copies in an existing changeset::
6752 - show all changes including copies in an existing changeset::
6753
6753
6754 hg status --copies --change 9353
6754 hg status --copies --change 9353
6755
6755
6756 - get a NUL separated list of added files, suitable for xargs::
6756 - get a NUL separated list of added files, suitable for xargs::
6757
6757
6758 hg status -an0
6758 hg status -an0
6759
6759
6760 - show more information about the repository status, abbreviating
6760 - show more information about the repository status, abbreviating
6761 added, removed, modified, deleted, and untracked paths::
6761 added, removed, modified, deleted, and untracked paths::
6762
6762
6763 hg status -v -t mardu
6763 hg status -v -t mardu
6764
6764
6765 Returns 0 on success.
6765 Returns 0 on success.
6766
6766
6767 """
6767 """
6768
6768
6769 opts = pycompat.byteskwargs(opts)
6769 opts = pycompat.byteskwargs(opts)
6770 revs = opts.get(b'rev')
6770 revs = opts.get(b'rev')
6771 change = opts.get(b'change')
6771 change = opts.get(b'change')
6772 terse = opts.get(b'terse')
6772 terse = opts.get(b'terse')
6773 if terse is _NOTTERSE:
6773 if terse is _NOTTERSE:
6774 if revs:
6774 if revs:
6775 terse = b''
6775 terse = b''
6776 else:
6776 else:
6777 terse = ui.config(b'commands', b'status.terse')
6777 terse = ui.config(b'commands', b'status.terse')
6778
6778
6779 if revs and change:
6779 if revs and change:
6780 msg = _(b'cannot specify --rev and --change at the same time')
6780 msg = _(b'cannot specify --rev and --change at the same time')
6781 raise error.Abort(msg)
6781 raise error.Abort(msg)
6782 elif revs and terse:
6782 elif revs and terse:
6783 msg = _(b'cannot use --terse with --rev')
6783 msg = _(b'cannot use --terse with --rev')
6784 raise error.Abort(msg)
6784 raise error.Abort(msg)
6785 elif change:
6785 elif change:
6786 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6786 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6787 ctx2 = scmutil.revsingle(repo, change, None)
6787 ctx2 = scmutil.revsingle(repo, change, None)
6788 ctx1 = ctx2.p1()
6788 ctx1 = ctx2.p1()
6789 else:
6789 else:
6790 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6790 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6791 ctx1, ctx2 = scmutil.revpair(repo, revs)
6791 ctx1, ctx2 = scmutil.revpair(repo, revs)
6792
6792
6793 forcerelativevalue = None
6793 forcerelativevalue = None
6794 if ui.hasconfig(b'commands', b'status.relative'):
6794 if ui.hasconfig(b'commands', b'status.relative'):
6795 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6795 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6796 uipathfn = scmutil.getuipathfn(
6796 uipathfn = scmutil.getuipathfn(
6797 repo,
6797 repo,
6798 legacyrelativevalue=bool(pats),
6798 legacyrelativevalue=bool(pats),
6799 forcerelativevalue=forcerelativevalue,
6799 forcerelativevalue=forcerelativevalue,
6800 )
6800 )
6801
6801
6802 if opts.get(b'print0'):
6802 if opts.get(b'print0'):
6803 end = b'\0'
6803 end = b'\0'
6804 else:
6804 else:
6805 end = b'\n'
6805 end = b'\n'
6806 states = b'modified added removed deleted unknown ignored clean'.split()
6806 states = b'modified added removed deleted unknown ignored clean'.split()
6807 show = [k for k in states if opts.get(k)]
6807 show = [k for k in states if opts.get(k)]
6808 if opts.get(b'all'):
6808 if opts.get(b'all'):
6809 show += ui.quiet and (states[:4] + [b'clean']) or states
6809 show += ui.quiet and (states[:4] + [b'clean']) or states
6810
6810
6811 if not show:
6811 if not show:
6812 if ui.quiet:
6812 if ui.quiet:
6813 show = states[:4]
6813 show = states[:4]
6814 else:
6814 else:
6815 show = states[:5]
6815 show = states[:5]
6816
6816
6817 m = scmutil.match(ctx2, pats, opts)
6817 m = scmutil.match(ctx2, pats, opts)
6818 if terse:
6818 if terse:
6819 # we need to compute clean and unknown to terse
6819 # we need to compute clean and unknown to terse
6820 stat = repo.status(
6820 stat = repo.status(
6821 ctx1.node(),
6821 ctx1.node(),
6822 ctx2.node(),
6822 ctx2.node(),
6823 m,
6823 m,
6824 b'ignored' in show or b'i' in terse,
6824 b'ignored' in show or b'i' in terse,
6825 clean=True,
6825 clean=True,
6826 unknown=True,
6826 unknown=True,
6827 listsubrepos=opts.get(b'subrepos'),
6827 listsubrepos=opts.get(b'subrepos'),
6828 )
6828 )
6829
6829
6830 stat = cmdutil.tersedir(stat, terse)
6830 stat = cmdutil.tersedir(stat, terse)
6831 else:
6831 else:
6832 stat = repo.status(
6832 stat = repo.status(
6833 ctx1.node(),
6833 ctx1.node(),
6834 ctx2.node(),
6834 ctx2.node(),
6835 m,
6835 m,
6836 b'ignored' in show,
6836 b'ignored' in show,
6837 b'clean' in show,
6837 b'clean' in show,
6838 b'unknown' in show,
6838 b'unknown' in show,
6839 opts.get(b'subrepos'),
6839 opts.get(b'subrepos'),
6840 )
6840 )
6841
6841
6842 changestates = zip(
6842 changestates = zip(
6843 states,
6843 states,
6844 pycompat.iterbytestr(b'MAR!?IC'),
6844 pycompat.iterbytestr(b'MAR!?IC'),
6845 [getattr(stat, s.decode('utf8')) for s in states],
6845 [getattr(stat, s.decode('utf8')) for s in states],
6846 )
6846 )
6847
6847
6848 copy = {}
6848 copy = {}
6849 if (
6849 if (
6850 opts.get(b'all')
6850 opts.get(b'all')
6851 or opts.get(b'copies')
6851 or opts.get(b'copies')
6852 or ui.configbool(b'ui', b'statuscopies')
6852 or ui.configbool(b'ui', b'statuscopies')
6853 ) and not opts.get(b'no_status'):
6853 ) and not opts.get(b'no_status'):
6854 copy = copies.pathcopies(ctx1, ctx2, m)
6854 copy = copies.pathcopies(ctx1, ctx2, m)
6855
6855
6856 morestatus = None
6856 morestatus = None
6857 if (
6857 if (
6858 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6858 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6859 ) and not ui.plain():
6859 ) and not ui.plain():
6860 morestatus = cmdutil.readmorestatus(repo)
6860 morestatus = cmdutil.readmorestatus(repo)
6861
6861
6862 ui.pager(b'status')
6862 ui.pager(b'status')
6863 fm = ui.formatter(b'status', opts)
6863 fm = ui.formatter(b'status', opts)
6864 fmt = b'%s' + end
6864 fmt = b'%s' + end
6865 showchar = not opts.get(b'no_status')
6865 showchar = not opts.get(b'no_status')
6866
6866
6867 for state, char, files in changestates:
6867 for state, char, files in changestates:
6868 if state in show:
6868 if state in show:
6869 label = b'status.' + state
6869 label = b'status.' + state
6870 for f in files:
6870 for f in files:
6871 fm.startitem()
6871 fm.startitem()
6872 fm.context(ctx=ctx2)
6872 fm.context(ctx=ctx2)
6873 fm.data(itemtype=b'file', path=f)
6873 fm.data(itemtype=b'file', path=f)
6874 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6874 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6875 fm.plain(fmt % uipathfn(f), label=label)
6875 fm.plain(fmt % uipathfn(f), label=label)
6876 if f in copy:
6876 if f in copy:
6877 fm.data(source=copy[f])
6877 fm.data(source=copy[f])
6878 fm.plain(
6878 fm.plain(
6879 (b' %s' + end) % uipathfn(copy[f]),
6879 (b' %s' + end) % uipathfn(copy[f]),
6880 label=b'status.copied',
6880 label=b'status.copied',
6881 )
6881 )
6882 if morestatus:
6882 if morestatus:
6883 morestatus.formatfile(f, fm)
6883 morestatus.formatfile(f, fm)
6884
6884
6885 if morestatus:
6885 if morestatus:
6886 morestatus.formatfooter(fm)
6886 morestatus.formatfooter(fm)
6887 fm.end()
6887 fm.end()
6888
6888
6889
6889
6890 @command(
6890 @command(
6891 b'summary|sum',
6891 b'summary|sum',
6892 [(b'', b'remote', None, _(b'check for push and pull'))],
6892 [(b'', b'remote', None, _(b'check for push and pull'))],
6893 b'[--remote]',
6893 b'[--remote]',
6894 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6894 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6895 helpbasic=True,
6895 helpbasic=True,
6896 intents={INTENT_READONLY},
6896 intents={INTENT_READONLY},
6897 )
6897 )
6898 def summary(ui, repo, **opts):
6898 def summary(ui, repo, **opts):
6899 """summarize working directory state
6899 """summarize working directory state
6900
6900
6901 This generates a brief summary of the working directory state,
6901 This generates a brief summary of the working directory state,
6902 including parents, branch, commit status, phase and available updates.
6902 including parents, branch, commit status, phase and available updates.
6903
6903
6904 With the --remote option, this will check the default paths for
6904 With the --remote option, this will check the default paths for
6905 incoming and outgoing changes. This can be time-consuming.
6905 incoming and outgoing changes. This can be time-consuming.
6906
6906
6907 Returns 0 on success.
6907 Returns 0 on success.
6908 """
6908 """
6909
6909
6910 opts = pycompat.byteskwargs(opts)
6910 opts = pycompat.byteskwargs(opts)
6911 ui.pager(b'summary')
6911 ui.pager(b'summary')
6912 ctx = repo[None]
6912 ctx = repo[None]
6913 parents = ctx.parents()
6913 parents = ctx.parents()
6914 pnode = parents[0].node()
6914 pnode = parents[0].node()
6915 marks = []
6915 marks = []
6916
6916
6917 try:
6917 try:
6918 ms = mergemod.mergestate.read(repo)
6918 ms = mergemod.mergestate.read(repo)
6919 except error.UnsupportedMergeRecords as e:
6919 except error.UnsupportedMergeRecords as e:
6920 s = b' '.join(e.recordtypes)
6920 s = b' '.join(e.recordtypes)
6921 ui.warn(
6921 ui.warn(
6922 _(b'warning: merge state has unsupported record types: %s\n') % s
6922 _(b'warning: merge state has unsupported record types: %s\n') % s
6923 )
6923 )
6924 unresolved = []
6924 unresolved = []
6925 else:
6925 else:
6926 unresolved = list(ms.unresolved())
6926 unresolved = list(ms.unresolved())
6927
6927
6928 for p in parents:
6928 for p in parents:
6929 # label with log.changeset (instead of log.parent) since this
6929 # label with log.changeset (instead of log.parent) since this
6930 # shows a working directory parent *changeset*:
6930 # shows a working directory parent *changeset*:
6931 # i18n: column positioning for "hg summary"
6931 # i18n: column positioning for "hg summary"
6932 ui.write(
6932 ui.write(
6933 _(b'parent: %d:%s ') % (p.rev(), p),
6933 _(b'parent: %d:%s ') % (p.rev(), p),
6934 label=logcmdutil.changesetlabels(p),
6934 label=logcmdutil.changesetlabels(p),
6935 )
6935 )
6936 ui.write(b' '.join(p.tags()), label=b'log.tag')
6936 ui.write(b' '.join(p.tags()), label=b'log.tag')
6937 if p.bookmarks():
6937 if p.bookmarks():
6938 marks.extend(p.bookmarks())
6938 marks.extend(p.bookmarks())
6939 if p.rev() == -1:
6939 if p.rev() == -1:
6940 if not len(repo):
6940 if not len(repo):
6941 ui.write(_(b' (empty repository)'))
6941 ui.write(_(b' (empty repository)'))
6942 else:
6942 else:
6943 ui.write(_(b' (no revision checked out)'))
6943 ui.write(_(b' (no revision checked out)'))
6944 if p.obsolete():
6944 if p.obsolete():
6945 ui.write(_(b' (obsolete)'))
6945 ui.write(_(b' (obsolete)'))
6946 if p.isunstable():
6946 if p.isunstable():
6947 instabilities = (
6947 instabilities = (
6948 ui.label(instability, b'trouble.%s' % instability)
6948 ui.label(instability, b'trouble.%s' % instability)
6949 for instability in p.instabilities()
6949 for instability in p.instabilities()
6950 )
6950 )
6951 ui.write(b' (' + b', '.join(instabilities) + b')')
6951 ui.write(b' (' + b', '.join(instabilities) + b')')
6952 ui.write(b'\n')
6952 ui.write(b'\n')
6953 if p.description():
6953 if p.description():
6954 ui.status(
6954 ui.status(
6955 b' ' + p.description().splitlines()[0].strip() + b'\n',
6955 b' ' + p.description().splitlines()[0].strip() + b'\n',
6956 label=b'log.summary',
6956 label=b'log.summary',
6957 )
6957 )
6958
6958
6959 branch = ctx.branch()
6959 branch = ctx.branch()
6960 bheads = repo.branchheads(branch)
6960 bheads = repo.branchheads(branch)
6961 # i18n: column positioning for "hg summary"
6961 # i18n: column positioning for "hg summary"
6962 m = _(b'branch: %s\n') % branch
6962 m = _(b'branch: %s\n') % branch
6963 if branch != b'default':
6963 if branch != b'default':
6964 ui.write(m, label=b'log.branch')
6964 ui.write(m, label=b'log.branch')
6965 else:
6965 else:
6966 ui.status(m, label=b'log.branch')
6966 ui.status(m, label=b'log.branch')
6967
6967
6968 if marks:
6968 if marks:
6969 active = repo._activebookmark
6969 active = repo._activebookmark
6970 # i18n: column positioning for "hg summary"
6970 # i18n: column positioning for "hg summary"
6971 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6971 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6972 if active is not None:
6972 if active is not None:
6973 if active in marks:
6973 if active in marks:
6974 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6974 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6975 marks.remove(active)
6975 marks.remove(active)
6976 else:
6976 else:
6977 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6977 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6978 for m in marks:
6978 for m in marks:
6979 ui.write(b' ' + m, label=b'log.bookmark')
6979 ui.write(b' ' + m, label=b'log.bookmark')
6980 ui.write(b'\n', label=b'log.bookmark')
6980 ui.write(b'\n', label=b'log.bookmark')
6981
6981
6982 status = repo.status(unknown=True)
6982 status = repo.status(unknown=True)
6983
6983
6984 c = repo.dirstate.copies()
6984 c = repo.dirstate.copies()
6985 copied, renamed = [], []
6985 copied, renamed = [], []
6986 for d, s in pycompat.iteritems(c):
6986 for d, s in pycompat.iteritems(c):
6987 if s in status.removed:
6987 if s in status.removed:
6988 status.removed.remove(s)
6988 status.removed.remove(s)
6989 renamed.append(d)
6989 renamed.append(d)
6990 else:
6990 else:
6991 copied.append(d)
6991 copied.append(d)
6992 if d in status.added:
6992 if d in status.added:
6993 status.added.remove(d)
6993 status.added.remove(d)
6994
6994
6995 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6995 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6996
6996
6997 labels = [
6997 labels = [
6998 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6998 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6999 (ui.label(_(b'%d added'), b'status.added'), status.added),
6999 (ui.label(_(b'%d added'), b'status.added'), status.added),
7000 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7000 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7001 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7001 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7002 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7002 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7003 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7003 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7004 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7004 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7005 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7005 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7006 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7006 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7007 ]
7007 ]
7008 t = []
7008 t = []
7009 for l, s in labels:
7009 for l, s in labels:
7010 if s:
7010 if s:
7011 t.append(l % len(s))
7011 t.append(l % len(s))
7012
7012
7013 t = b', '.join(t)
7013 t = b', '.join(t)
7014 cleanworkdir = False
7014 cleanworkdir = False
7015
7015
7016 if repo.vfs.exists(b'graftstate'):
7016 if repo.vfs.exists(b'graftstate'):
7017 t += _(b' (graft in progress)')
7017 t += _(b' (graft in progress)')
7018 if repo.vfs.exists(b'updatestate'):
7018 if repo.vfs.exists(b'updatestate'):
7019 t += _(b' (interrupted update)')
7019 t += _(b' (interrupted update)')
7020 elif len(parents) > 1:
7020 elif len(parents) > 1:
7021 t += _(b' (merge)')
7021 t += _(b' (merge)')
7022 elif branch != parents[0].branch():
7022 elif branch != parents[0].branch():
7023 t += _(b' (new branch)')
7023 t += _(b' (new branch)')
7024 elif parents[0].closesbranch() and pnode in repo.branchheads(
7024 elif parents[0].closesbranch() and pnode in repo.branchheads(
7025 branch, closed=True
7025 branch, closed=True
7026 ):
7026 ):
7027 t += _(b' (head closed)')
7027 t += _(b' (head closed)')
7028 elif not (
7028 elif not (
7029 status.modified
7029 status.modified
7030 or status.added
7030 or status.added
7031 or status.removed
7031 or status.removed
7032 or renamed
7032 or renamed
7033 or copied
7033 or copied
7034 or subs
7034 or subs
7035 ):
7035 ):
7036 t += _(b' (clean)')
7036 t += _(b' (clean)')
7037 cleanworkdir = True
7037 cleanworkdir = True
7038 elif pnode not in bheads:
7038 elif pnode not in bheads:
7039 t += _(b' (new branch head)')
7039 t += _(b' (new branch head)')
7040
7040
7041 if parents:
7041 if parents:
7042 pendingphase = max(p.phase() for p in parents)
7042 pendingphase = max(p.phase() for p in parents)
7043 else:
7043 else:
7044 pendingphase = phases.public
7044 pendingphase = phases.public
7045
7045
7046 if pendingphase > phases.newcommitphase(ui):
7046 if pendingphase > phases.newcommitphase(ui):
7047 t += b' (%s)' % phases.phasenames[pendingphase]
7047 t += b' (%s)' % phases.phasenames[pendingphase]
7048
7048
7049 if cleanworkdir:
7049 if cleanworkdir:
7050 # i18n: column positioning for "hg summary"
7050 # i18n: column positioning for "hg summary"
7051 ui.status(_(b'commit: %s\n') % t.strip())
7051 ui.status(_(b'commit: %s\n') % t.strip())
7052 else:
7052 else:
7053 # i18n: column positioning for "hg summary"
7053 # i18n: column positioning for "hg summary"
7054 ui.write(_(b'commit: %s\n') % t.strip())
7054 ui.write(_(b'commit: %s\n') % t.strip())
7055
7055
7056 # all ancestors of branch heads - all ancestors of parent = new csets
7056 # all ancestors of branch heads - all ancestors of parent = new csets
7057 new = len(
7057 new = len(
7058 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7058 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7059 )
7059 )
7060
7060
7061 if new == 0:
7061 if new == 0:
7062 # i18n: column positioning for "hg summary"
7062 # i18n: column positioning for "hg summary"
7063 ui.status(_(b'update: (current)\n'))
7063 ui.status(_(b'update: (current)\n'))
7064 elif pnode not in bheads:
7064 elif pnode not in bheads:
7065 # i18n: column positioning for "hg summary"
7065 # i18n: column positioning for "hg summary"
7066 ui.write(_(b'update: %d new changesets (update)\n') % new)
7066 ui.write(_(b'update: %d new changesets (update)\n') % new)
7067 else:
7067 else:
7068 # i18n: column positioning for "hg summary"
7068 # i18n: column positioning for "hg summary"
7069 ui.write(
7069 ui.write(
7070 _(b'update: %d new changesets, %d branch heads (merge)\n')
7070 _(b'update: %d new changesets, %d branch heads (merge)\n')
7071 % (new, len(bheads))
7071 % (new, len(bheads))
7072 )
7072 )
7073
7073
7074 t = []
7074 t = []
7075 draft = len(repo.revs(b'draft()'))
7075 draft = len(repo.revs(b'draft()'))
7076 if draft:
7076 if draft:
7077 t.append(_(b'%d draft') % draft)
7077 t.append(_(b'%d draft') % draft)
7078 secret = len(repo.revs(b'secret()'))
7078 secret = len(repo.revs(b'secret()'))
7079 if secret:
7079 if secret:
7080 t.append(_(b'%d secret') % secret)
7080 t.append(_(b'%d secret') % secret)
7081
7081
7082 if draft or secret:
7082 if draft or secret:
7083 ui.status(_(b'phases: %s\n') % b', '.join(t))
7083 ui.status(_(b'phases: %s\n') % b', '.join(t))
7084
7084
7085 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7085 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7086 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7086 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7087 numtrouble = len(repo.revs(trouble + b"()"))
7087 numtrouble = len(repo.revs(trouble + b"()"))
7088 # We write all the possibilities to ease translation
7088 # We write all the possibilities to ease translation
7089 troublemsg = {
7089 troublemsg = {
7090 b"orphan": _(b"orphan: %d changesets"),
7090 b"orphan": _(b"orphan: %d changesets"),
7091 b"contentdivergent": _(b"content-divergent: %d changesets"),
7091 b"contentdivergent": _(b"content-divergent: %d changesets"),
7092 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7092 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7093 }
7093 }
7094 if numtrouble > 0:
7094 if numtrouble > 0:
7095 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7095 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7096
7096
7097 cmdutil.summaryhooks(ui, repo)
7097 cmdutil.summaryhooks(ui, repo)
7098
7098
7099 if opts.get(b'remote'):
7099 if opts.get(b'remote'):
7100 needsincoming, needsoutgoing = True, True
7100 needsincoming, needsoutgoing = True, True
7101 else:
7101 else:
7102 needsincoming, needsoutgoing = False, False
7102 needsincoming, needsoutgoing = False, False
7103 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7103 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7104 if i:
7104 if i:
7105 needsincoming = True
7105 needsincoming = True
7106 if o:
7106 if o:
7107 needsoutgoing = True
7107 needsoutgoing = True
7108 if not needsincoming and not needsoutgoing:
7108 if not needsincoming and not needsoutgoing:
7109 return
7109 return
7110
7110
7111 def getincoming():
7111 def getincoming():
7112 source, branches = hg.parseurl(ui.expandpath(b'default'))
7112 source, branches = hg.parseurl(ui.expandpath(b'default'))
7113 sbranch = branches[0]
7113 sbranch = branches[0]
7114 try:
7114 try:
7115 other = hg.peer(repo, {}, source)
7115 other = hg.peer(repo, {}, source)
7116 except error.RepoError:
7116 except error.RepoError:
7117 if opts.get(b'remote'):
7117 if opts.get(b'remote'):
7118 raise
7118 raise
7119 return source, sbranch, None, None, None
7119 return source, sbranch, None, None, None
7120 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7120 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7121 if revs:
7121 if revs:
7122 revs = [other.lookup(rev) for rev in revs]
7122 revs = [other.lookup(rev) for rev in revs]
7123 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7123 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7124 repo.ui.pushbuffer()
7124 repo.ui.pushbuffer()
7125 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7125 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7126 repo.ui.popbuffer()
7126 repo.ui.popbuffer()
7127 return source, sbranch, other, commoninc, commoninc[1]
7127 return source, sbranch, other, commoninc, commoninc[1]
7128
7128
7129 if needsincoming:
7129 if needsincoming:
7130 source, sbranch, sother, commoninc, incoming = getincoming()
7130 source, sbranch, sother, commoninc, incoming = getincoming()
7131 else:
7131 else:
7132 source = sbranch = sother = commoninc = incoming = None
7132 source = sbranch = sother = commoninc = incoming = None
7133
7133
7134 def getoutgoing():
7134 def getoutgoing():
7135 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7135 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7136 dbranch = branches[0]
7136 dbranch = branches[0]
7137 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7137 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7138 if source != dest:
7138 if source != dest:
7139 try:
7139 try:
7140 dother = hg.peer(repo, {}, dest)
7140 dother = hg.peer(repo, {}, dest)
7141 except error.RepoError:
7141 except error.RepoError:
7142 if opts.get(b'remote'):
7142 if opts.get(b'remote'):
7143 raise
7143 raise
7144 return dest, dbranch, None, None
7144 return dest, dbranch, None, None
7145 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7145 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7146 elif sother is None:
7146 elif sother is None:
7147 # there is no explicit destination peer, but source one is invalid
7147 # there is no explicit destination peer, but source one is invalid
7148 return dest, dbranch, None, None
7148 return dest, dbranch, None, None
7149 else:
7149 else:
7150 dother = sother
7150 dother = sother
7151 if source != dest or (sbranch is not None and sbranch != dbranch):
7151 if source != dest or (sbranch is not None and sbranch != dbranch):
7152 common = None
7152 common = None
7153 else:
7153 else:
7154 common = commoninc
7154 common = commoninc
7155 if revs:
7155 if revs:
7156 revs = [repo.lookup(rev) for rev in revs]
7156 revs = [repo.lookup(rev) for rev in revs]
7157 repo.ui.pushbuffer()
7157 repo.ui.pushbuffer()
7158 outgoing = discovery.findcommonoutgoing(
7158 outgoing = discovery.findcommonoutgoing(
7159 repo, dother, onlyheads=revs, commoninc=common
7159 repo, dother, onlyheads=revs, commoninc=common
7160 )
7160 )
7161 repo.ui.popbuffer()
7161 repo.ui.popbuffer()
7162 return dest, dbranch, dother, outgoing
7162 return dest, dbranch, dother, outgoing
7163
7163
7164 if needsoutgoing:
7164 if needsoutgoing:
7165 dest, dbranch, dother, outgoing = getoutgoing()
7165 dest, dbranch, dother, outgoing = getoutgoing()
7166 else:
7166 else:
7167 dest = dbranch = dother = outgoing = None
7167 dest = dbranch = dother = outgoing = None
7168
7168
7169 if opts.get(b'remote'):
7169 if opts.get(b'remote'):
7170 t = []
7170 t = []
7171 if incoming:
7171 if incoming:
7172 t.append(_(b'1 or more incoming'))
7172 t.append(_(b'1 or more incoming'))
7173 o = outgoing.missing
7173 o = outgoing.missing
7174 if o:
7174 if o:
7175 t.append(_(b'%d outgoing') % len(o))
7175 t.append(_(b'%d outgoing') % len(o))
7176 other = dother or sother
7176 other = dother or sother
7177 if b'bookmarks' in other.listkeys(b'namespaces'):
7177 if b'bookmarks' in other.listkeys(b'namespaces'):
7178 counts = bookmarks.summary(repo, other)
7178 counts = bookmarks.summary(repo, other)
7179 if counts[0] > 0:
7179 if counts[0] > 0:
7180 t.append(_(b'%d incoming bookmarks') % counts[0])
7180 t.append(_(b'%d incoming bookmarks') % counts[0])
7181 if counts[1] > 0:
7181 if counts[1] > 0:
7182 t.append(_(b'%d outgoing bookmarks') % counts[1])
7182 t.append(_(b'%d outgoing bookmarks') % counts[1])
7183
7183
7184 if t:
7184 if t:
7185 # i18n: column positioning for "hg summary"
7185 # i18n: column positioning for "hg summary"
7186 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7186 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7187 else:
7187 else:
7188 # i18n: column positioning for "hg summary"
7188 # i18n: column positioning for "hg summary"
7189 ui.status(_(b'remote: (synced)\n'))
7189 ui.status(_(b'remote: (synced)\n'))
7190
7190
7191 cmdutil.summaryremotehooks(
7191 cmdutil.summaryremotehooks(
7192 ui,
7192 ui,
7193 repo,
7193 repo,
7194 opts,
7194 opts,
7195 (
7195 (
7196 (source, sbranch, sother, commoninc),
7196 (source, sbranch, sother, commoninc),
7197 (dest, dbranch, dother, outgoing),
7197 (dest, dbranch, dother, outgoing),
7198 ),
7198 ),
7199 )
7199 )
7200
7200
7201
7201
7202 @command(
7202 @command(
7203 b'tag',
7203 b'tag',
7204 [
7204 [
7205 (b'f', b'force', None, _(b'force tag')),
7205 (b'f', b'force', None, _(b'force tag')),
7206 (b'l', b'local', None, _(b'make the tag local')),
7206 (b'l', b'local', None, _(b'make the tag local')),
7207 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7207 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7208 (b'', b'remove', None, _(b'remove a tag')),
7208 (b'', b'remove', None, _(b'remove a tag')),
7209 # -l/--local is already there, commitopts cannot be used
7209 # -l/--local is already there, commitopts cannot be used
7210 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7210 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7211 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7211 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7212 ]
7212 ]
7213 + commitopts2,
7213 + commitopts2,
7214 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7214 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7215 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7215 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7216 )
7216 )
7217 def tag(ui, repo, name1, *names, **opts):
7217 def tag(ui, repo, name1, *names, **opts):
7218 """add one or more tags for the current or given revision
7218 """add one or more tags for the current or given revision
7219
7219
7220 Name a particular revision using <name>.
7220 Name a particular revision using <name>.
7221
7221
7222 Tags are used to name particular revisions of the repository and are
7222 Tags are used to name particular revisions of the repository and are
7223 very useful to compare different revisions, to go back to significant
7223 very useful to compare different revisions, to go back to significant
7224 earlier versions or to mark branch points as releases, etc. Changing
7224 earlier versions or to mark branch points as releases, etc. Changing
7225 an existing tag is normally disallowed; use -f/--force to override.
7225 an existing tag is normally disallowed; use -f/--force to override.
7226
7226
7227 If no revision is given, the parent of the working directory is
7227 If no revision is given, the parent of the working directory is
7228 used.
7228 used.
7229
7229
7230 To facilitate version control, distribution, and merging of tags,
7230 To facilitate version control, distribution, and merging of tags,
7231 they are stored as a file named ".hgtags" which is managed similarly
7231 they are stored as a file named ".hgtags" which is managed similarly
7232 to other project files and can be hand-edited if necessary. This
7232 to other project files and can be hand-edited if necessary. This
7233 also means that tagging creates a new commit. The file
7233 also means that tagging creates a new commit. The file
7234 ".hg/localtags" is used for local tags (not shared among
7234 ".hg/localtags" is used for local tags (not shared among
7235 repositories).
7235 repositories).
7236
7236
7237 Tag commits are usually made at the head of a branch. If the parent
7237 Tag commits are usually made at the head of a branch. If the parent
7238 of the working directory is not a branch head, :hg:`tag` aborts; use
7238 of the working directory is not a branch head, :hg:`tag` aborts; use
7239 -f/--force to force the tag commit to be based on a non-head
7239 -f/--force to force the tag commit to be based on a non-head
7240 changeset.
7240 changeset.
7241
7241
7242 See :hg:`help dates` for a list of formats valid for -d/--date.
7242 See :hg:`help dates` for a list of formats valid for -d/--date.
7243
7243
7244 Since tag names have priority over branch names during revision
7244 Since tag names have priority over branch names during revision
7245 lookup, using an existing branch name as a tag name is discouraged.
7245 lookup, using an existing branch name as a tag name is discouraged.
7246
7246
7247 Returns 0 on success.
7247 Returns 0 on success.
7248 """
7248 """
7249 opts = pycompat.byteskwargs(opts)
7249 opts = pycompat.byteskwargs(opts)
7250 with repo.wlock(), repo.lock():
7250 with repo.wlock(), repo.lock():
7251 rev_ = b"."
7251 rev_ = b"."
7252 names = [t.strip() for t in (name1,) + names]
7252 names = [t.strip() for t in (name1,) + names]
7253 if len(names) != len(set(names)):
7253 if len(names) != len(set(names)):
7254 raise error.Abort(_(b'tag names must be unique'))
7254 raise error.Abort(_(b'tag names must be unique'))
7255 for n in names:
7255 for n in names:
7256 scmutil.checknewlabel(repo, n, b'tag')
7256 scmutil.checknewlabel(repo, n, b'tag')
7257 if not n:
7257 if not n:
7258 raise error.Abort(
7258 raise error.Abort(
7259 _(b'tag names cannot consist entirely of whitespace')
7259 _(b'tag names cannot consist entirely of whitespace')
7260 )
7260 )
7261 if opts.get(b'rev') and opts.get(b'remove'):
7261 if opts.get(b'rev') and opts.get(b'remove'):
7262 raise error.Abort(_(b"--rev and --remove are incompatible"))
7262 raise error.Abort(_(b"--rev and --remove are incompatible"))
7263 if opts.get(b'rev'):
7263 if opts.get(b'rev'):
7264 rev_ = opts[b'rev']
7264 rev_ = opts[b'rev']
7265 message = opts.get(b'message')
7265 message = opts.get(b'message')
7266 if opts.get(b'remove'):
7266 if opts.get(b'remove'):
7267 if opts.get(b'local'):
7267 if opts.get(b'local'):
7268 expectedtype = b'local'
7268 expectedtype = b'local'
7269 else:
7269 else:
7270 expectedtype = b'global'
7270 expectedtype = b'global'
7271
7271
7272 for n in names:
7272 for n in names:
7273 if repo.tagtype(n) == b'global':
7273 if repo.tagtype(n) == b'global':
7274 alltags = tagsmod.findglobaltags(ui, repo)
7274 alltags = tagsmod.findglobaltags(ui, repo)
7275 if alltags[n][0] == nullid:
7275 if alltags[n][0] == nullid:
7276 raise error.Abort(_(b"tag '%s' is already removed") % n)
7276 raise error.Abort(_(b"tag '%s' is already removed") % n)
7277 if not repo.tagtype(n):
7277 if not repo.tagtype(n):
7278 raise error.Abort(_(b"tag '%s' does not exist") % n)
7278 raise error.Abort(_(b"tag '%s' does not exist") % n)
7279 if repo.tagtype(n) != expectedtype:
7279 if repo.tagtype(n) != expectedtype:
7280 if expectedtype == b'global':
7280 if expectedtype == b'global':
7281 raise error.Abort(
7281 raise error.Abort(
7282 _(b"tag '%s' is not a global tag") % n
7282 _(b"tag '%s' is not a global tag") % n
7283 )
7283 )
7284 else:
7284 else:
7285 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7285 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7286 rev_ = b'null'
7286 rev_ = b'null'
7287 if not message:
7287 if not message:
7288 # we don't translate commit messages
7288 # we don't translate commit messages
7289 message = b'Removed tag %s' % b', '.join(names)
7289 message = b'Removed tag %s' % b', '.join(names)
7290 elif not opts.get(b'force'):
7290 elif not opts.get(b'force'):
7291 for n in names:
7291 for n in names:
7292 if n in repo.tags():
7292 if n in repo.tags():
7293 raise error.Abort(
7293 raise error.Abort(
7294 _(b"tag '%s' already exists (use -f to force)") % n
7294 _(b"tag '%s' already exists (use -f to force)") % n
7295 )
7295 )
7296 if not opts.get(b'local'):
7296 if not opts.get(b'local'):
7297 p1, p2 = repo.dirstate.parents()
7297 p1, p2 = repo.dirstate.parents()
7298 if p2 != nullid:
7298 if p2 != nullid:
7299 raise error.Abort(_(b'uncommitted merge'))
7299 raise error.Abort(_(b'uncommitted merge'))
7300 bheads = repo.branchheads()
7300 bheads = repo.branchheads()
7301 if not opts.get(b'force') and bheads and p1 not in bheads:
7301 if not opts.get(b'force') and bheads and p1 not in bheads:
7302 raise error.Abort(
7302 raise error.Abort(
7303 _(
7303 _(
7304 b'working directory is not at a branch head '
7304 b'working directory is not at a branch head '
7305 b'(use -f to force)'
7305 b'(use -f to force)'
7306 )
7306 )
7307 )
7307 )
7308 node = scmutil.revsingle(repo, rev_).node()
7308 node = scmutil.revsingle(repo, rev_).node()
7309
7309
7310 if not message:
7310 if not message:
7311 # we don't translate commit messages
7311 # we don't translate commit messages
7312 message = b'Added tag %s for changeset %s' % (
7312 message = b'Added tag %s for changeset %s' % (
7313 b', '.join(names),
7313 b', '.join(names),
7314 short(node),
7314 short(node),
7315 )
7315 )
7316
7316
7317 date = opts.get(b'date')
7317 date = opts.get(b'date')
7318 if date:
7318 if date:
7319 date = dateutil.parsedate(date)
7319 date = dateutil.parsedate(date)
7320
7320
7321 if opts.get(b'remove'):
7321 if opts.get(b'remove'):
7322 editform = b'tag.remove'
7322 editform = b'tag.remove'
7323 else:
7323 else:
7324 editform = b'tag.add'
7324 editform = b'tag.add'
7325 editor = cmdutil.getcommiteditor(
7325 editor = cmdutil.getcommiteditor(
7326 editform=editform, **pycompat.strkwargs(opts)
7326 editform=editform, **pycompat.strkwargs(opts)
7327 )
7327 )
7328
7328
7329 # don't allow tagging the null rev
7329 # don't allow tagging the null rev
7330 if (
7330 if (
7331 not opts.get(b'remove')
7331 not opts.get(b'remove')
7332 and scmutil.revsingle(repo, rev_).rev() == nullrev
7332 and scmutil.revsingle(repo, rev_).rev() == nullrev
7333 ):
7333 ):
7334 raise error.Abort(_(b"cannot tag null revision"))
7334 raise error.Abort(_(b"cannot tag null revision"))
7335
7335
7336 tagsmod.tag(
7336 tagsmod.tag(
7337 repo,
7337 repo,
7338 names,
7338 names,
7339 node,
7339 node,
7340 message,
7340 message,
7341 opts.get(b'local'),
7341 opts.get(b'local'),
7342 opts.get(b'user'),
7342 opts.get(b'user'),
7343 date,
7343 date,
7344 editor=editor,
7344 editor=editor,
7345 )
7345 )
7346
7346
7347
7347
7348 @command(
7348 @command(
7349 b'tags',
7349 b'tags',
7350 formatteropts,
7350 formatteropts,
7351 b'',
7351 b'',
7352 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7352 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7353 intents={INTENT_READONLY},
7353 intents={INTENT_READONLY},
7354 )
7354 )
7355 def tags(ui, repo, **opts):
7355 def tags(ui, repo, **opts):
7356 """list repository tags
7356 """list repository tags
7357
7357
7358 This lists both regular and local tags. When the -v/--verbose
7358 This lists both regular and local tags. When the -v/--verbose
7359 switch is used, a third column "local" is printed for local tags.
7359 switch is used, a third column "local" is printed for local tags.
7360 When the -q/--quiet switch is used, only the tag name is printed.
7360 When the -q/--quiet switch is used, only the tag name is printed.
7361
7361
7362 .. container:: verbose
7362 .. container:: verbose
7363
7363
7364 Template:
7364 Template:
7365
7365
7366 The following keywords are supported in addition to the common template
7366 The following keywords are supported in addition to the common template
7367 keywords and functions such as ``{tag}``. See also
7367 keywords and functions such as ``{tag}``. See also
7368 :hg:`help templates`.
7368 :hg:`help templates`.
7369
7369
7370 :type: String. ``local`` for local tags.
7370 :type: String. ``local`` for local tags.
7371
7371
7372 Returns 0 on success.
7372 Returns 0 on success.
7373 """
7373 """
7374
7374
7375 opts = pycompat.byteskwargs(opts)
7375 opts = pycompat.byteskwargs(opts)
7376 ui.pager(b'tags')
7376 ui.pager(b'tags')
7377 fm = ui.formatter(b'tags', opts)
7377 fm = ui.formatter(b'tags', opts)
7378 hexfunc = fm.hexfunc
7378 hexfunc = fm.hexfunc
7379
7379
7380 for t, n in reversed(repo.tagslist()):
7380 for t, n in reversed(repo.tagslist()):
7381 hn = hexfunc(n)
7381 hn = hexfunc(n)
7382 label = b'tags.normal'
7382 label = b'tags.normal'
7383 tagtype = b''
7383 tagtype = b''
7384 if repo.tagtype(t) == b'local':
7384 if repo.tagtype(t) == b'local':
7385 label = b'tags.local'
7385 label = b'tags.local'
7386 tagtype = b'local'
7386 tagtype = b'local'
7387
7387
7388 fm.startitem()
7388 fm.startitem()
7389 fm.context(repo=repo)
7389 fm.context(repo=repo)
7390 fm.write(b'tag', b'%s', t, label=label)
7390 fm.write(b'tag', b'%s', t, label=label)
7391 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7391 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7392 fm.condwrite(
7392 fm.condwrite(
7393 not ui.quiet,
7393 not ui.quiet,
7394 b'rev node',
7394 b'rev node',
7395 fmt,
7395 fmt,
7396 repo.changelog.rev(n),
7396 repo.changelog.rev(n),
7397 hn,
7397 hn,
7398 label=label,
7398 label=label,
7399 )
7399 )
7400 fm.condwrite(
7400 fm.condwrite(
7401 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7401 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7402 )
7402 )
7403 fm.plain(b'\n')
7403 fm.plain(b'\n')
7404 fm.end()
7404 fm.end()
7405
7405
7406
7406
7407 @command(
7407 @command(
7408 b'tip',
7408 b'tip',
7409 [
7409 [
7410 (b'p', b'patch', None, _(b'show patch')),
7410 (b'p', b'patch', None, _(b'show patch')),
7411 (b'g', b'git', None, _(b'use git extended diff format')),
7411 (b'g', b'git', None, _(b'use git extended diff format')),
7412 ]
7412 ]
7413 + templateopts,
7413 + templateopts,
7414 _(b'[-p] [-g]'),
7414 _(b'[-p] [-g]'),
7415 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7415 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7416 )
7416 )
7417 def tip(ui, repo, **opts):
7417 def tip(ui, repo, **opts):
7418 """show the tip revision (DEPRECATED)
7418 """show the tip revision (DEPRECATED)
7419
7419
7420 The tip revision (usually just called the tip) is the changeset
7420 The tip revision (usually just called the tip) is the changeset
7421 most recently added to the repository (and therefore the most
7421 most recently added to the repository (and therefore the most
7422 recently changed head).
7422 recently changed head).
7423
7423
7424 If you have just made a commit, that commit will be the tip. If
7424 If you have just made a commit, that commit will be the tip. If
7425 you have just pulled changes from another repository, the tip of
7425 you have just pulled changes from another repository, the tip of
7426 that repository becomes the current tip. The "tip" tag is special
7426 that repository becomes the current tip. The "tip" tag is special
7427 and cannot be renamed or assigned to a different changeset.
7427 and cannot be renamed or assigned to a different changeset.
7428
7428
7429 This command is deprecated, please use :hg:`heads` instead.
7429 This command is deprecated, please use :hg:`heads` instead.
7430
7430
7431 Returns 0 on success.
7431 Returns 0 on success.
7432 """
7432 """
7433 opts = pycompat.byteskwargs(opts)
7433 opts = pycompat.byteskwargs(opts)
7434 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7434 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7435 displayer.show(repo[b'tip'])
7435 displayer.show(repo[b'tip'])
7436 displayer.close()
7436 displayer.close()
7437
7437
7438
7438
7439 @command(
7439 @command(
7440 b'unbundle',
7440 b'unbundle',
7441 [
7441 [
7442 (
7442 (
7443 b'u',
7443 b'u',
7444 b'update',
7444 b'update',
7445 None,
7445 None,
7446 _(b'update to new branch head if changesets were unbundled'),
7446 _(b'update to new branch head if changesets were unbundled'),
7447 )
7447 )
7448 ],
7448 ],
7449 _(b'[-u] FILE...'),
7449 _(b'[-u] FILE...'),
7450 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7450 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7451 )
7451 )
7452 def unbundle(ui, repo, fname1, *fnames, **opts):
7452 def unbundle(ui, repo, fname1, *fnames, **opts):
7453 """apply one or more bundle files
7453 """apply one or more bundle files
7454
7454
7455 Apply one or more bundle files generated by :hg:`bundle`.
7455 Apply one or more bundle files generated by :hg:`bundle`.
7456
7456
7457 Returns 0 on success, 1 if an update has unresolved files.
7457 Returns 0 on success, 1 if an update has unresolved files.
7458 """
7458 """
7459 fnames = (fname1,) + fnames
7459 fnames = (fname1,) + fnames
7460
7460
7461 with repo.lock():
7461 with repo.lock():
7462 for fname in fnames:
7462 for fname in fnames:
7463 f = hg.openpath(ui, fname)
7463 f = hg.openpath(ui, fname)
7464 gen = exchange.readbundle(ui, f, fname)
7464 gen = exchange.readbundle(ui, f, fname)
7465 if isinstance(gen, streamclone.streamcloneapplier):
7465 if isinstance(gen, streamclone.streamcloneapplier):
7466 raise error.Abort(
7466 raise error.Abort(
7467 _(
7467 _(
7468 b'packed bundles cannot be applied with '
7468 b'packed bundles cannot be applied with '
7469 b'"hg unbundle"'
7469 b'"hg unbundle"'
7470 ),
7470 ),
7471 hint=_(b'use "hg debugapplystreamclonebundle"'),
7471 hint=_(b'use "hg debugapplystreamclonebundle"'),
7472 )
7472 )
7473 url = b'bundle:' + fname
7473 url = b'bundle:' + fname
7474 try:
7474 try:
7475 txnname = b'unbundle'
7475 txnname = b'unbundle'
7476 if not isinstance(gen, bundle2.unbundle20):
7476 if not isinstance(gen, bundle2.unbundle20):
7477 txnname = b'unbundle\n%s' % util.hidepassword(url)
7477 txnname = b'unbundle\n%s' % util.hidepassword(url)
7478 with repo.transaction(txnname) as tr:
7478 with repo.transaction(txnname) as tr:
7479 op = bundle2.applybundle(
7479 op = bundle2.applybundle(
7480 repo, gen, tr, source=b'unbundle', url=url
7480 repo, gen, tr, source=b'unbundle', url=url
7481 )
7481 )
7482 except error.BundleUnknownFeatureError as exc:
7482 except error.BundleUnknownFeatureError as exc:
7483 raise error.Abort(
7483 raise error.Abort(
7484 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7484 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7485 hint=_(
7485 hint=_(
7486 b"see https://mercurial-scm.org/"
7486 b"see https://mercurial-scm.org/"
7487 b"wiki/BundleFeature for more "
7487 b"wiki/BundleFeature for more "
7488 b"information"
7488 b"information"
7489 ),
7489 ),
7490 )
7490 )
7491 modheads = bundle2.combinechangegroupresults(op)
7491 modheads = bundle2.combinechangegroupresults(op)
7492
7492
7493 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7493 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7494
7494
7495
7495
7496 @command(
7496 @command(
7497 b'unshelve',
7497 b'unshelve',
7498 [
7498 [
7499 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7499 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7500 (
7500 (
7501 b'c',
7501 b'c',
7502 b'continue',
7502 b'continue',
7503 None,
7503 None,
7504 _(b'continue an incomplete unshelve operation'),
7504 _(b'continue an incomplete unshelve operation'),
7505 ),
7505 ),
7506 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7506 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7507 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7507 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7508 (
7508 (
7509 b'n',
7509 b'n',
7510 b'name',
7510 b'name',
7511 b'',
7511 b'',
7512 _(b'restore shelved change with given name'),
7512 _(b'restore shelved change with given name'),
7513 _(b'NAME'),
7513 _(b'NAME'),
7514 ),
7514 ),
7515 (b't', b'tool', b'', _(b'specify merge tool')),
7515 (b't', b'tool', b'', _(b'specify merge tool')),
7516 (
7516 (
7517 b'',
7517 b'',
7518 b'date',
7518 b'date',
7519 b'',
7519 b'',
7520 _(b'set date for temporary commits (DEPRECATED)'),
7520 _(b'set date for temporary commits (DEPRECATED)'),
7521 _(b'DATE'),
7521 _(b'DATE'),
7522 ),
7522 ),
7523 ],
7523 ],
7524 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7524 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7525 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7525 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7526 )
7526 )
7527 def unshelve(ui, repo, *shelved, **opts):
7527 def unshelve(ui, repo, *shelved, **opts):
7528 """restore a shelved change to the working directory
7528 """restore a shelved change to the working directory
7529
7529
7530 This command accepts an optional name of a shelved change to
7530 This command accepts an optional name of a shelved change to
7531 restore. If none is given, the most recent shelved change is used.
7531 restore. If none is given, the most recent shelved change is used.
7532
7532
7533 If a shelved change is applied successfully, the bundle that
7533 If a shelved change is applied successfully, the bundle that
7534 contains the shelved changes is moved to a backup location
7534 contains the shelved changes is moved to a backup location
7535 (.hg/shelve-backup).
7535 (.hg/shelve-backup).
7536
7536
7537 Since you can restore a shelved change on top of an arbitrary
7537 Since you can restore a shelved change on top of an arbitrary
7538 commit, it is possible that unshelving will result in a conflict
7538 commit, it is possible that unshelving will result in a conflict
7539 between your changes and the commits you are unshelving onto. If
7539 between your changes and the commits you are unshelving onto. If
7540 this occurs, you must resolve the conflict, then use
7540 this occurs, you must resolve the conflict, then use
7541 ``--continue`` to complete the unshelve operation. (The bundle
7541 ``--continue`` to complete the unshelve operation. (The bundle
7542 will not be moved until you successfully complete the unshelve.)
7542 will not be moved until you successfully complete the unshelve.)
7543
7543
7544 (Alternatively, you can use ``--abort`` to abandon an unshelve
7544 (Alternatively, you can use ``--abort`` to abandon an unshelve
7545 that causes a conflict. This reverts the unshelved changes, and
7545 that causes a conflict. This reverts the unshelved changes, and
7546 leaves the bundle in place.)
7546 leaves the bundle in place.)
7547
7547
7548 If bare shelved change (without interactive, include and exclude
7548 If bare shelved change (without interactive, include and exclude
7549 option) was done on newly created branch it would restore branch
7549 option) was done on newly created branch it would restore branch
7550 information to the working directory.
7550 information to the working directory.
7551
7551
7552 After a successful unshelve, the shelved changes are stored in a
7552 After a successful unshelve, the shelved changes are stored in a
7553 backup directory. Only the N most recent backups are kept. N
7553 backup directory. Only the N most recent backups are kept. N
7554 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7554 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7555 configuration option.
7555 configuration option.
7556
7556
7557 .. container:: verbose
7557 .. container:: verbose
7558
7558
7559 Timestamp in seconds is used to decide order of backups. More
7559 Timestamp in seconds is used to decide order of backups. More
7560 than ``maxbackups`` backups are kept, if same timestamp
7560 than ``maxbackups`` backups are kept, if same timestamp
7561 prevents from deciding exact order of them, for safety.
7561 prevents from deciding exact order of them, for safety.
7562
7562
7563 Selected changes can be unshelved with ``--interactive`` flag.
7563 Selected changes can be unshelved with ``--interactive`` flag.
7564 The working directory is updated with the selected changes, and
7564 The working directory is updated with the selected changes, and
7565 only the unselected changes remain shelved.
7565 only the unselected changes remain shelved.
7566 Note: The whole shelve is applied to working directory first before
7566 Note: The whole shelve is applied to working directory first before
7567 running interactively. So, this will bring up all the conflicts between
7567 running interactively. So, this will bring up all the conflicts between
7568 working directory and the shelve, irrespective of which changes will be
7568 working directory and the shelve, irrespective of which changes will be
7569 unshelved.
7569 unshelved.
7570 """
7570 """
7571 with repo.wlock():
7571 with repo.wlock():
7572 return shelvemod.dounshelve(ui, repo, *shelved, **opts)
7572 return shelvemod.dounshelve(ui, repo, *shelved, **opts)
7573
7573
7574
7574
7575 statemod.addunfinished(
7575 statemod.addunfinished(
7576 b'unshelve',
7576 b'unshelve',
7577 fname=b'shelvedstate',
7577 fname=b'shelvedstate',
7578 continueflag=True,
7578 continueflag=True,
7579 abortfunc=shelvemod.hgabortunshelve,
7579 abortfunc=shelvemod.hgabortunshelve,
7580 continuefunc=shelvemod.hgcontinueunshelve,
7580 continuefunc=shelvemod.hgcontinueunshelve,
7581 cmdmsg=_(b'unshelve already in progress'),
7581 cmdmsg=_(b'unshelve already in progress'),
7582 )
7582 )
7583
7583
7584
7584
7585 @command(
7585 @command(
7586 b'update|up|checkout|co',
7586 b'update|up|checkout|co',
7587 [
7587 [
7588 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7588 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7589 (b'c', b'check', None, _(b'require clean working directory')),
7589 (b'c', b'check', None, _(b'require clean working directory')),
7590 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7590 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7591 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7591 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7592 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7592 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7593 ]
7593 ]
7594 + mergetoolopts,
7594 + mergetoolopts,
7595 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7595 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7596 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7596 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7597 helpbasic=True,
7597 helpbasic=True,
7598 )
7598 )
7599 def update(ui, repo, node=None, **opts):
7599 def update(ui, repo, node=None, **opts):
7600 """update working directory (or switch revisions)
7600 """update working directory (or switch revisions)
7601
7601
7602 Update the repository's working directory to the specified
7602 Update the repository's working directory to the specified
7603 changeset. If no changeset is specified, update to the tip of the
7603 changeset. If no changeset is specified, update to the tip of the
7604 current named branch and move the active bookmark (see :hg:`help
7604 current named branch and move the active bookmark (see :hg:`help
7605 bookmarks`).
7605 bookmarks`).
7606
7606
7607 Update sets the working directory's parent revision to the specified
7607 Update sets the working directory's parent revision to the specified
7608 changeset (see :hg:`help parents`).
7608 changeset (see :hg:`help parents`).
7609
7609
7610 If the changeset is not a descendant or ancestor of the working
7610 If the changeset is not a descendant or ancestor of the working
7611 directory's parent and there are uncommitted changes, the update is
7611 directory's parent and there are uncommitted changes, the update is
7612 aborted. With the -c/--check option, the working directory is checked
7612 aborted. With the -c/--check option, the working directory is checked
7613 for uncommitted changes; if none are found, the working directory is
7613 for uncommitted changes; if none are found, the working directory is
7614 updated to the specified changeset.
7614 updated to the specified changeset.
7615
7615
7616 .. container:: verbose
7616 .. container:: verbose
7617
7617
7618 The -C/--clean, -c/--check, and -m/--merge options control what
7618 The -C/--clean, -c/--check, and -m/--merge options control what
7619 happens if the working directory contains uncommitted changes.
7619 happens if the working directory contains uncommitted changes.
7620 At most of one of them can be specified.
7620 At most of one of them can be specified.
7621
7621
7622 1. If no option is specified, and if
7622 1. If no option is specified, and if
7623 the requested changeset is an ancestor or descendant of
7623 the requested changeset is an ancestor or descendant of
7624 the working directory's parent, the uncommitted changes
7624 the working directory's parent, the uncommitted changes
7625 are merged into the requested changeset and the merged
7625 are merged into the requested changeset and the merged
7626 result is left uncommitted. If the requested changeset is
7626 result is left uncommitted. If the requested changeset is
7627 not an ancestor or descendant (that is, it is on another
7627 not an ancestor or descendant (that is, it is on another
7628 branch), the update is aborted and the uncommitted changes
7628 branch), the update is aborted and the uncommitted changes
7629 are preserved.
7629 are preserved.
7630
7630
7631 2. With the -m/--merge option, the update is allowed even if the
7631 2. With the -m/--merge option, the update is allowed even if the
7632 requested changeset is not an ancestor or descendant of
7632 requested changeset is not an ancestor or descendant of
7633 the working directory's parent.
7633 the working directory's parent.
7634
7634
7635 3. With the -c/--check option, the update is aborted and the
7635 3. With the -c/--check option, the update is aborted and the
7636 uncommitted changes are preserved.
7636 uncommitted changes are preserved.
7637
7637
7638 4. With the -C/--clean option, uncommitted changes are discarded and
7638 4. With the -C/--clean option, uncommitted changes are discarded and
7639 the working directory is updated to the requested changeset.
7639 the working directory is updated to the requested changeset.
7640
7640
7641 To cancel an uncommitted merge (and lose your changes), use
7641 To cancel an uncommitted merge (and lose your changes), use
7642 :hg:`merge --abort`.
7642 :hg:`merge --abort`.
7643
7643
7644 Use null as the changeset to remove the working directory (like
7644 Use null as the changeset to remove the working directory (like
7645 :hg:`clone -U`).
7645 :hg:`clone -U`).
7646
7646
7647 If you want to revert just one file to an older revision, use
7647 If you want to revert just one file to an older revision, use
7648 :hg:`revert [-r REV] NAME`.
7648 :hg:`revert [-r REV] NAME`.
7649
7649
7650 See :hg:`help dates` for a list of formats valid for -d/--date.
7650 See :hg:`help dates` for a list of formats valid for -d/--date.
7651
7651
7652 Returns 0 on success, 1 if there are unresolved files.
7652 Returns 0 on success, 1 if there are unresolved files.
7653 """
7653 """
7654 rev = opts.get('rev')
7654 rev = opts.get('rev')
7655 date = opts.get('date')
7655 date = opts.get('date')
7656 clean = opts.get('clean')
7656 clean = opts.get('clean')
7657 check = opts.get('check')
7657 check = opts.get('check')
7658 merge = opts.get('merge')
7658 merge = opts.get('merge')
7659 if rev and node:
7659 if rev and node:
7660 raise error.Abort(_(b"please specify just one revision"))
7660 raise error.Abort(_(b"please specify just one revision"))
7661
7661
7662 if ui.configbool(b'commands', b'update.requiredest'):
7662 if ui.configbool(b'commands', b'update.requiredest'):
7663 if not node and not rev and not date:
7663 if not node and not rev and not date:
7664 raise error.Abort(
7664 raise error.Abort(
7665 _(b'you must specify a destination'),
7665 _(b'you must specify a destination'),
7666 hint=_(b'for example: hg update ".::"'),
7666 hint=_(b'for example: hg update ".::"'),
7667 )
7667 )
7668
7668
7669 if rev is None or rev == b'':
7669 if rev is None or rev == b'':
7670 rev = node
7670 rev = node
7671
7671
7672 if date and rev is not None:
7672 if date and rev is not None:
7673 raise error.Abort(_(b"you can't specify a revision and a date"))
7673 raise error.Abort(_(b"you can't specify a revision and a date"))
7674
7674
7675 if len([x for x in (clean, check, merge) if x]) > 1:
7675 if len([x for x in (clean, check, merge) if x]) > 1:
7676 raise error.Abort(
7676 raise error.Abort(
7677 _(
7677 _(
7678 b"can only specify one of -C/--clean, -c/--check, "
7678 b"can only specify one of -C/--clean, -c/--check, "
7679 b"or -m/--merge"
7679 b"or -m/--merge"
7680 )
7680 )
7681 )
7681 )
7682
7682
7683 updatecheck = None
7683 updatecheck = None
7684 if check:
7684 if check:
7685 updatecheck = b'abort'
7685 updatecheck = b'abort'
7686 elif merge:
7686 elif merge:
7687 updatecheck = b'none'
7687 updatecheck = b'none'
7688
7688
7689 with repo.wlock():
7689 with repo.wlock():
7690 cmdutil.clearunfinished(repo)
7690 cmdutil.clearunfinished(repo)
7691 if date:
7691 if date:
7692 rev = cmdutil.finddate(ui, repo, date)
7692 rev = cmdutil.finddate(ui, repo, date)
7693
7693
7694 # if we defined a bookmark, we have to remember the original name
7694 # if we defined a bookmark, we have to remember the original name
7695 brev = rev
7695 brev = rev
7696 if rev:
7696 if rev:
7697 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7697 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7698 ctx = scmutil.revsingle(repo, rev, default=None)
7698 ctx = scmutil.revsingle(repo, rev, default=None)
7699 rev = ctx.rev()
7699 rev = ctx.rev()
7700 hidden = ctx.hidden()
7700 hidden = ctx.hidden()
7701 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7701 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7702 with ui.configoverride(overrides, b'update'):
7702 with ui.configoverride(overrides, b'update'):
7703 ret = hg.updatetotally(
7703 ret = hg.updatetotally(
7704 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7704 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7705 )
7705 )
7706 if hidden:
7706 if hidden:
7707 ctxstr = ctx.hex()[:12]
7707 ctxstr = ctx.hex()[:12]
7708 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7708 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7709
7709
7710 if ctx.obsolete():
7710 if ctx.obsolete():
7711 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7711 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7712 ui.warn(b"(%s)\n" % obsfatemsg)
7712 ui.warn(b"(%s)\n" % obsfatemsg)
7713 return ret
7713 return ret
7714
7714
7715
7715
7716 @command(
7716 @command(
7717 b'verify',
7717 b'verify',
7718 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7718 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7719 helpcategory=command.CATEGORY_MAINTENANCE,
7719 helpcategory=command.CATEGORY_MAINTENANCE,
7720 )
7720 )
7721 def verify(ui, repo, **opts):
7721 def verify(ui, repo, **opts):
7722 """verify the integrity of the repository
7722 """verify the integrity of the repository
7723
7723
7724 Verify the integrity of the current repository.
7724 Verify the integrity of the current repository.
7725
7725
7726 This will perform an extensive check of the repository's
7726 This will perform an extensive check of the repository's
7727 integrity, validating the hashes and checksums of each entry in
7727 integrity, validating the hashes and checksums of each entry in
7728 the changelog, manifest, and tracked files, as well as the
7728 the changelog, manifest, and tracked files, as well as the
7729 integrity of their crosslinks and indices.
7729 integrity of their crosslinks and indices.
7730
7730
7731 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7731 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7732 for more information about recovery from corruption of the
7732 for more information about recovery from corruption of the
7733 repository.
7733 repository.
7734
7734
7735 Returns 0 on success, 1 if errors are encountered.
7735 Returns 0 on success, 1 if errors are encountered.
7736 """
7736 """
7737 opts = pycompat.byteskwargs(opts)
7737 opts = pycompat.byteskwargs(opts)
7738
7738
7739 level = None
7739 level = None
7740 if opts[b'full']:
7740 if opts[b'full']:
7741 level = verifymod.VERIFY_FULL
7741 level = verifymod.VERIFY_FULL
7742 return hg.verify(repo, level)
7742 return hg.verify(repo, level)
7743
7743
7744
7744
7745 @command(
7745 @command(
7746 b'version',
7746 b'version',
7747 [] + formatteropts,
7747 [] + formatteropts,
7748 helpcategory=command.CATEGORY_HELP,
7748 helpcategory=command.CATEGORY_HELP,
7749 norepo=True,
7749 norepo=True,
7750 intents={INTENT_READONLY},
7750 intents={INTENT_READONLY},
7751 )
7751 )
7752 def version_(ui, **opts):
7752 def version_(ui, **opts):
7753 """output version and copyright information
7753 """output version and copyright information
7754
7754
7755 .. container:: verbose
7755 .. container:: verbose
7756
7756
7757 Template:
7757 Template:
7758
7758
7759 The following keywords are supported. See also :hg:`help templates`.
7759 The following keywords are supported. See also :hg:`help templates`.
7760
7760
7761 :extensions: List of extensions.
7761 :extensions: List of extensions.
7762 :ver: String. Version number.
7762 :ver: String. Version number.
7763
7763
7764 And each entry of ``{extensions}`` provides the following sub-keywords
7764 And each entry of ``{extensions}`` provides the following sub-keywords
7765 in addition to ``{ver}``.
7765 in addition to ``{ver}``.
7766
7766
7767 :bundled: Boolean. True if included in the release.
7767 :bundled: Boolean. True if included in the release.
7768 :name: String. Extension name.
7768 :name: String. Extension name.
7769 """
7769 """
7770 opts = pycompat.byteskwargs(opts)
7770 opts = pycompat.byteskwargs(opts)
7771 if ui.verbose:
7771 if ui.verbose:
7772 ui.pager(b'version')
7772 ui.pager(b'version')
7773 fm = ui.formatter(b"version", opts)
7773 fm = ui.formatter(b"version", opts)
7774 fm.startitem()
7774 fm.startitem()
7775 fm.write(
7775 fm.write(
7776 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7776 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7777 )
7777 )
7778 license = _(
7778 license = _(
7779 b"(see https://mercurial-scm.org for more information)\n"
7779 b"(see https://mercurial-scm.org for more information)\n"
7780 b"\nCopyright (C) 2005-2019 Matt Mackall and others\n"
7780 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7781 b"This is free software; see the source for copying conditions. "
7781 b"This is free software; see the source for copying conditions. "
7782 b"There is NO\nwarranty; "
7782 b"There is NO\nwarranty; "
7783 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7783 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7784 )
7784 )
7785 if not ui.quiet:
7785 if not ui.quiet:
7786 fm.plain(license)
7786 fm.plain(license)
7787
7787
7788 if ui.verbose:
7788 if ui.verbose:
7789 fm.plain(_(b"\nEnabled extensions:\n\n"))
7789 fm.plain(_(b"\nEnabled extensions:\n\n"))
7790 # format names and versions into columns
7790 # format names and versions into columns
7791 names = []
7791 names = []
7792 vers = []
7792 vers = []
7793 isinternals = []
7793 isinternals = []
7794 for name, module in extensions.extensions():
7794 for name, module in extensions.extensions():
7795 names.append(name)
7795 names.append(name)
7796 vers.append(extensions.moduleversion(module) or None)
7796 vers.append(extensions.moduleversion(module) or None)
7797 isinternals.append(extensions.ismoduleinternal(module))
7797 isinternals.append(extensions.ismoduleinternal(module))
7798 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7798 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7799 if names:
7799 if names:
7800 namefmt = b" %%-%ds " % max(len(n) for n in names)
7800 namefmt = b" %%-%ds " % max(len(n) for n in names)
7801 places = [_(b"external"), _(b"internal")]
7801 places = [_(b"external"), _(b"internal")]
7802 for n, v, p in zip(names, vers, isinternals):
7802 for n, v, p in zip(names, vers, isinternals):
7803 fn.startitem()
7803 fn.startitem()
7804 fn.condwrite(ui.verbose, b"name", namefmt, n)
7804 fn.condwrite(ui.verbose, b"name", namefmt, n)
7805 if ui.verbose:
7805 if ui.verbose:
7806 fn.plain(b"%s " % places[p])
7806 fn.plain(b"%s " % places[p])
7807 fn.data(bundled=p)
7807 fn.data(bundled=p)
7808 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7808 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7809 if ui.verbose:
7809 if ui.verbose:
7810 fn.plain(b"\n")
7810 fn.plain(b"\n")
7811 fn.end()
7811 fn.end()
7812 fm.end()
7812 fm.end()
7813
7813
7814
7814
7815 def loadcmdtable(ui, name, cmdtable):
7815 def loadcmdtable(ui, name, cmdtable):
7816 """Load command functions from specified cmdtable
7816 """Load command functions from specified cmdtable
7817 """
7817 """
7818 overrides = [cmd for cmd in cmdtable if cmd in table]
7818 overrides = [cmd for cmd in cmdtable if cmd in table]
7819 if overrides:
7819 if overrides:
7820 ui.warn(
7820 ui.warn(
7821 _(b"extension '%s' overrides commands: %s\n")
7821 _(b"extension '%s' overrides commands: %s\n")
7822 % (name, b" ".join(overrides))
7822 % (name, b" ".join(overrides))
7823 )
7823 )
7824 table.update(cmdtable)
7824 table.update(cmdtable)
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now